ACPI: Fix autloading of dock, video, bay and all linux specific HID drivers
References: https://bugzilla.novell.com/show_bug.cgi?id=302482 Due to the new autloading of acpi drivers, the dock driver wasn't loaded anymore as there is no HID to identify it with (dock is needed if ACPI has a _DCK method). This patch is a workaround for this, original by Thomas Renninger, revised first by Kay Sievers and last by Frank Seidel. V2 of this patch fixed problems on systems without a defined _CID for the docking devices. Signed-off-by: Thomas Renninger <trenn@novell.com> Signed-off-by: Kay Sievers <kasievers@novell.com> Signed-off-by: Frank Seidel <fseidel@suse.de> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
f194d132e4
commit
3620f2f2f3
1 changed files with 85 additions and 15 deletions
|
@ -941,6 +941,15 @@ static int acpi_bay_match(struct acpi_device *device){
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* acpi_dock_match - see if a device has a _DCK method
|
||||||
|
*/
|
||||||
|
static int acpi_dock_match(struct acpi_device *device)
|
||||||
|
{
|
||||||
|
acpi_handle tmp;
|
||||||
|
return acpi_get_handle(device->handle, "_DCK", &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
static void acpi_device_set_id(struct acpi_device *device,
|
static void acpi_device_set_id(struct acpi_device *device,
|
||||||
struct acpi_device *parent, acpi_handle handle,
|
struct acpi_device *parent, acpi_handle handle,
|
||||||
int type)
|
int type)
|
||||||
|
@ -950,6 +959,7 @@ static void acpi_device_set_id(struct acpi_device *device,
|
||||||
char *hid = NULL;
|
char *hid = NULL;
|
||||||
char *uid = NULL;
|
char *uid = NULL;
|
||||||
struct acpi_compatible_id_list *cid_list = NULL;
|
struct acpi_compatible_id_list *cid_list = NULL;
|
||||||
|
const char *cid_add = NULL;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -972,15 +982,18 @@ static void acpi_device_set_id(struct acpi_device *device,
|
||||||
device->flags.bus_address = 1;
|
device->flags.bus_address = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
|
/* If we have a video/bay/dock device, add our selfdefined
|
||||||
status = acpi_video_bus_match(device);
|
HID to the CID list. Like that the video/bay/dock drivers
|
||||||
if(ACPI_SUCCESS(status))
|
will get autoloaded and the device might still match
|
||||||
hid = ACPI_VIDEO_HID;
|
against another driver.
|
||||||
|
*/
|
||||||
|
if (ACPI_SUCCESS(acpi_video_bus_match(device)))
|
||||||
|
cid_add = ACPI_VIDEO_HID;
|
||||||
|
else if (ACPI_SUCCESS(acpi_bay_match(device)))
|
||||||
|
cid_add = ACPI_BAY_HID;
|
||||||
|
else if (ACPI_SUCCESS(acpi_dock_match(device)))
|
||||||
|
cid_add = ACPI_DOCK_HID;
|
||||||
|
|
||||||
status = acpi_bay_match(device);
|
|
||||||
if (ACPI_SUCCESS(status))
|
|
||||||
hid = ACPI_BAY_HID;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ACPI_BUS_TYPE_POWER:
|
case ACPI_BUS_TYPE_POWER:
|
||||||
hid = ACPI_POWER_HID;
|
hid = ACPI_POWER_HID;
|
||||||
|
@ -1021,11 +1034,44 @@ static void acpi_device_set_id(struct acpi_device *device,
|
||||||
strcpy(device->pnp.unique_id, uid);
|
strcpy(device->pnp.unique_id, uid);
|
||||||
device->flags.unique_id = 1;
|
device->flags.unique_id = 1;
|
||||||
}
|
}
|
||||||
if (cid_list) {
|
if (cid_list || cid_add) {
|
||||||
device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL);
|
struct acpi_compatible_id_list *list;
|
||||||
if (device->pnp.cid_list)
|
int size = 0;
|
||||||
memcpy(device->pnp.cid_list, cid_list, cid_list->size);
|
int count = 0;
|
||||||
else
|
|
||||||
|
if (cid_list) {
|
||||||
|
size = cid_list->size;
|
||||||
|
} else if (cid_add) {
|
||||||
|
size = sizeof(struct acpi_compatible_id_list);
|
||||||
|
cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
|
||||||
|
if (!cid_list) {
|
||||||
|
printk(KERN_ERR "Memory allocation error\n");
|
||||||
|
kfree(buffer.pointer);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
cid_list->count = 0;
|
||||||
|
cid_list->size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cid_add)
|
||||||
|
size += sizeof(struct acpi_compatible_id);
|
||||||
|
list = kmalloc(size, GFP_KERNEL);
|
||||||
|
|
||||||
|
if (list) {
|
||||||
|
if (cid_list) {
|
||||||
|
memcpy(list, cid_list, cid_list->size);
|
||||||
|
count = cid_list->count;
|
||||||
|
}
|
||||||
|
if (cid_add) {
|
||||||
|
strncpy(list->id[count].value, cid_add,
|
||||||
|
ACPI_MAX_CID_LENGTH);
|
||||||
|
count++;
|
||||||
|
device->flags.compatible_ids = 1;
|
||||||
|
}
|
||||||
|
list->size = size;
|
||||||
|
list->count = count;
|
||||||
|
device->pnp.cid_list = list;
|
||||||
|
} else
|
||||||
printk(KERN_ERR "Memory allocation error\n");
|
printk(KERN_ERR "Memory allocation error\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1080,6 +1126,20 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
acpi_is_child_device(struct acpi_device *device,
|
||||||
|
int (*matcher)(struct acpi_device *))
|
||||||
|
{
|
||||||
|
int result = -ENODEV;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (ACPI_SUCCESS(matcher(device)))
|
||||||
|
return AE_OK;
|
||||||
|
} while ((device = device->parent));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
acpi_add_single_object(struct acpi_device **child,
|
acpi_add_single_object(struct acpi_device **child,
|
||||||
struct acpi_device *parent, acpi_handle handle, int type,
|
struct acpi_device *parent, acpi_handle handle, int type,
|
||||||
|
@ -1131,10 +1191,20 @@ acpi_add_single_object(struct acpi_device **child,
|
||||||
case ACPI_BUS_TYPE_PROCESSOR:
|
case ACPI_BUS_TYPE_PROCESSOR:
|
||||||
case ACPI_BUS_TYPE_DEVICE:
|
case ACPI_BUS_TYPE_DEVICE:
|
||||||
result = acpi_bus_get_status(device);
|
result = acpi_bus_get_status(device);
|
||||||
if (ACPI_FAILURE(result) || !device->status.present) {
|
if (ACPI_FAILURE(result)) {
|
||||||
result = -ENOENT;
|
result = -ENODEV;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
if (!device->status.present) {
|
||||||
|
/* Bay and dock should be handled even if absent */
|
||||||
|
if (!ACPI_SUCCESS(
|
||||||
|
acpi_is_child_device(device, acpi_bay_match)) &&
|
||||||
|
!ACPI_SUCCESS(
|
||||||
|
acpi_is_child_device(device, acpi_dock_match))) {
|
||||||
|
result = -ENODEV;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
STRUCT_TO_INT(device->status) =
|
STRUCT_TO_INT(device->status) =
|
||||||
|
|
Loading…
Add table
Reference in a new issue