From b24715027aab5e586c4ab1d035f3e543307dea69 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:28:49 +0000 Subject: [PATCH 01/25] ACPICA: fixup after acpi_get_object_info() change Commit 15b8dd53f5ffa changed info->hardware_id from a static array to a pointer. If hardware_id is non-NULL, it points to a NULL-terminated string, so we don't need to terminate it explicitly. However, it may be NULL; in that case, we *can't* add a NULL terminator. This causes a NULL pointer dereference oops for devices without _HID. Signed-off-by: Bjorn Helgaas CC: Lin Ming CC: Bob Moore CC: Gary Hade Signed-off-by: Len Brown --- drivers/pci/hotplug/acpiphp_ibm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index a9d926b7d805..e7be66dbac21 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -406,7 +406,6 @@ static acpi_status __init ibm_find_acpi_device(acpi_handle handle, __func__, status); return retval; } - info->hardware_id.string[sizeof(info->hardware_id.length) - 1] = '\0'; if (info->current_status && (info->valid & ACPI_VALID_HID) && (!strcmp(info->hardware_id.string, IBM_HARDWARE_ID1) || From 29aaefa68f933110e577fbf3ca360c88331e5ff5 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:28:54 +0000 Subject: [PATCH 02/25] ACPI: add debug for device addition Add debug output for adding an ACPI device. Enable this with "acpi.debug_layer=0x00010000" (ACPI_BUS_COMPONENT). Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 408ebde18986..75b7c572ef45 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1230,6 +1230,7 @@ acpi_add_single_object(struct acpi_device **child, { int result = 0; struct acpi_device *device = NULL; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; if (!child) @@ -1355,9 +1356,16 @@ acpi_add_single_object(struct acpi_device **child, } end: - if (!result) + if (!result) { + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Adding %s [%s] parent %s\n", dev_name(&device->dev), + (char *) buffer.pointer, + device->parent ? dev_name(&device->parent->dev) : + "(null)")); + kfree(buffer.pointer); *child = device; - else + } else acpi_device_release(&device->dev); return result; From e8b945c9c155d06e1d1ea594f8e18e01aa36f612 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:28:59 +0000 Subject: [PATCH 03/25] ACPI: remove unused acpi_bus_scan_fixed() argument We never use the "root" argument, so just remove it. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 75b7c572ef45..0302dd454e17 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1580,15 +1580,12 @@ int acpi_bus_trim(struct acpi_device *start, int rmdevice) } EXPORT_SYMBOL_GPL(acpi_bus_trim); -static int acpi_bus_scan_fixed(struct acpi_device *root) +static int acpi_bus_scan_fixed(void) { int result = 0; struct acpi_device *device = NULL; struct acpi_bus_ops ops; - if (!root) - return -ENODEV; - memset(&ops, 0, sizeof(ops)); ops.acpi_op_add = 1; ops.acpi_op_start = 1; @@ -1639,7 +1636,7 @@ int __init acpi_scan_init(void) /* * Enumerate devices in the ACPI namespace. */ - result = acpi_bus_scan_fixed(acpi_root); + result = acpi_bus_scan_fixed(); if (!result) result = acpi_bus_scan(acpi_root, &ops); From 66b7ed40aaf153d634aabff409a0dda675f37f45 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:05 +0000 Subject: [PATCH 04/25] ACPI: remove redundant "handle" and "parent" arguments In several cases, functions take handle and parent device pointers in addition to acpi_device pointers. But the acpi_device structure contains both the handle and the parent pointer, so it's pointless and error-prone to pass them all. This patch removes the unnecessary "handle" and "parent" arguments. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 0302dd454e17..ab5a26469707 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -474,12 +474,12 @@ struct bus_type acpi_bus_type = { .uevent = acpi_device_uevent, }; -static int acpi_device_register(struct acpi_device *device, - struct acpi_device *parent) +static int acpi_device_register(struct acpi_device *device) { int result; struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; int found = 0; + /* * Linkage * ------- @@ -524,7 +524,7 @@ static int acpi_device_register(struct acpi_device *device, mutex_unlock(&acpi_device_lock); if (device->parent) - device->dev.parent = &parent->dev; + device->dev.parent = &device->parent->dev; device->dev.bus = &acpi_bus_type; device->dev.release = &acpi_device_release; result = device_register(&device->dev); @@ -918,8 +918,7 @@ static int acpi_bus_get_flags(struct acpi_device *device) return 0; } -static void acpi_device_get_busid(struct acpi_device *device, - acpi_handle handle, int type) +static void acpi_device_get_busid(struct acpi_device *device, int type) { char bus_id[5] = { '?', 0 }; struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; @@ -942,7 +941,7 @@ static void acpi_device_get_busid(struct acpi_device *device, strcpy(device->pnp.bus_id, "SLPF"); break; default: - acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + acpi_get_name(device->handle, ACPI_SINGLE_NAME, &buffer); /* Clean up trailing underscores (if any) */ for (i = 3; i > 1; i--) { if (bus_id[i] == '_') @@ -1058,9 +1057,7 @@ acpi_add_cid( return cid; } -static void acpi_device_set_id(struct acpi_device *device, - struct acpi_device *parent, acpi_handle handle, - int type) +static void acpi_device_set_id(struct acpi_device *device, int type) { struct acpi_device_info *info = NULL; char *hid = NULL; @@ -1071,7 +1068,7 @@ static void acpi_device_set_id(struct acpi_device *device, switch (type) { case ACPI_BUS_TYPE_DEVICE: - status = acpi_get_object_info(handle, &info); + status = acpi_get_object_info(device->handle, &info); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); return; @@ -1126,7 +1123,8 @@ static void acpi_device_set_id(struct acpi_device *device, * ---- * Fix for the system root bus device -- the only root-level device. */ - if (((acpi_handle)parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) { + if (((acpi_handle)device->parent == ACPI_ROOT_OBJECT) && + (type == ACPI_BUS_TYPE_DEVICE)) { hid = ACPI_BUS_HID; strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); strcpy(device->pnp.device_class, ACPI_BUS_CLASS); @@ -1246,8 +1244,7 @@ acpi_add_single_object(struct acpi_device **child, device->parent = parent; device->bus_ops = *ops; /* workround for not call .start */ - - acpi_device_get_busid(device, handle, type); + acpi_device_get_busid(device, type); /* * Flags @@ -1310,7 +1307,7 @@ acpi_add_single_object(struct acpi_device **child, * Hardware ID, Unique ID, & Bus Address * ------------------------------------- */ - acpi_device_set_id(device, parent, handle, type); + acpi_device_set_id(device, type); /* * Power Management @@ -1345,7 +1342,7 @@ acpi_add_single_object(struct acpi_device **child, if ((result = acpi_device_set_context(device, type))) goto end; - result = acpi_device_register(device, parent); + result = acpi_device_register(device); /* * Bind _ADR-Based Devices when hot add From caaa6efb3d82d0102db9e7094ca5773c46e6780c Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:10 +0000 Subject: [PATCH 05/25] ACPI: save device_type in acpi_device Most uses of the ACPI bus device_type (ACPI_BUS_TYPE_DEVICE, ACPI_BUS_TYPE_POWER, etc) are during device initialization, but we do need it later for notify handler installation, since that is different for fixed hardware devices vs. namespace devices. This patch saves the device_type in the acpi_device structure, so we can check that rather than comparing against the _HID string. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 1 + include/acpi/acpi_bus.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ab5a26469707..c73681b7e69e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1240,6 +1240,7 @@ acpi_add_single_object(struct acpi_device **child, return -ENOMEM; } + device->device_type = type; device->handle = handle; device->parent = parent; device->bus_ops = *ops; /* workround for not call .start */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 1cef1398e358..8456e8cbf9fd 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -262,7 +262,8 @@ struct acpi_device_wakeup { /* Device */ struct acpi_device { - acpi_handle handle; + int device_type; + acpi_handle handle; /* no handle for fixed hardware */ struct acpi_device *parent; struct list_head children; struct list_head node; From ccba2a36d74a9da815e597ac727cfd096fa8e750 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:15 +0000 Subject: [PATCH 06/25] ACPI: use device_type rather than comparing HID Check the acpi_device device_type rather than the HID. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c73681b7e69e..c8e867b4a842 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -378,15 +378,13 @@ static acpi_status acpi_device_notify_fixed(void *data) static int acpi_device_install_notify_handler(struct acpi_device *device) { acpi_status status; - char *hid; - hid = acpi_device_hid(device); - if (!strcmp(hid, ACPI_BUTTON_HID_POWERF)) + if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, acpi_device_notify_fixed, device); - else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) + else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) status = acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, acpi_device_notify_fixed, @@ -404,10 +402,10 @@ static int acpi_device_install_notify_handler(struct acpi_device *device) static void acpi_device_remove_notify_handler(struct acpi_device *device) { - if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) + if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, acpi_device_notify_fixed); - else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) + else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, acpi_device_notify_fixed); else From bc3b07726aa288e2a5e60d9a1dd8188b3faa7385 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:20 +0000 Subject: [PATCH 07/25] ACPI: remove acpi_device_set_context() "type" argument We only pass the "type" to acpi_device_set_context() so we know whether the device has a handle to which we can attach the acpi_device pointer. But it's safer to just check for the handle directly, since it's in the acpi_device already. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c8e867b4a842..44383fe35082 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1171,29 +1171,27 @@ static void acpi_device_set_id(struct acpi_device *device, int type) kfree(info); } -static int acpi_device_set_context(struct acpi_device *device, int type) +static int acpi_device_set_context(struct acpi_device *device) { - acpi_status status = AE_OK; - int result = 0; + acpi_status status; + /* * Context * ------- * Attach this 'struct acpi_device' to the ACPI object. This makes - * resolutions from handle->device very efficient. Note that we need - * to be careful with fixed-feature devices as they all attach to the - * root object. + * resolutions from handle->device very efficient. Fixed hardware + * devices have no handles, so we skip them. */ - if (type != ACPI_BUS_TYPE_POWER_BUTTON && - type != ACPI_BUS_TYPE_SLEEP_BUTTON) { - status = acpi_attach_data(device->handle, - acpi_bus_data_handler, device); + if (!device->handle) + return 0; - if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Error attaching device data\n"); - result = -ENODEV; - } - } - return result; + status = acpi_attach_data(device->handle, + acpi_bus_data_handler, device); + if (ACPI_SUCCESS(status)) + return 0; + + printk(KERN_ERR PREFIX "Error attaching device data\n"); + return -ENODEV; } static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) @@ -1338,7 +1336,7 @@ acpi_add_single_object(struct acpi_device **child, goto end; } - if ((result = acpi_device_set_context(device, type))) + if ((result = acpi_device_set_context(device))) goto end; result = acpi_device_register(device); From c7bcb4e98aca348f6f8ab432496ff35ba7a49a1d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:25 +0000 Subject: [PATCH 08/25] ACPI: remove redundant "type" arguments We now save the ACPI bus "device_type" in the acpi_device structure, so we don't need to pass it around explicitly anymore. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 44383fe35082..6c83342d13d5 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -916,7 +916,7 @@ static int acpi_bus_get_flags(struct acpi_device *device) return 0; } -static void acpi_device_get_busid(struct acpi_device *device, int type) +static void acpi_device_get_busid(struct acpi_device *device) { char bus_id[5] = { '?', 0 }; struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; @@ -928,7 +928,7 @@ static void acpi_device_get_busid(struct acpi_device *device, int type) * The device's Bus ID is simply the object name. * TBD: Shouldn't this value be unique (within the ACPI namespace)? */ - switch (type) { + switch (device->device_type) { case ACPI_BUS_TYPE_SYSTEM: strcpy(device->pnp.bus_id, "ACPI"); break; @@ -1055,7 +1055,7 @@ acpi_add_cid( return cid; } -static void acpi_device_set_id(struct acpi_device *device, int type) +static void acpi_device_set_id(struct acpi_device *device) { struct acpi_device_info *info = NULL; char *hid = NULL; @@ -1064,7 +1064,7 @@ static void acpi_device_set_id(struct acpi_device *device, int type) char *cid_add = NULL; acpi_status status; - switch (type) { + switch (device->device_type) { case ACPI_BUS_TYPE_DEVICE: status = acpi_get_object_info(device->handle, &info); if (ACPI_FAILURE(status)) { @@ -1122,7 +1122,7 @@ static void acpi_device_set_id(struct acpi_device *device, int type) * Fix for the system root bus device -- the only root-level device. */ if (((acpi_handle)device->parent == ACPI_ROOT_OBJECT) && - (type == ACPI_BUS_TYPE_DEVICE)) { + (device->device_type == ACPI_BUS_TYPE_DEVICE)) { hid = ACPI_BUS_HID; strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); strcpy(device->pnp.device_class, ACPI_BUS_CLASS); @@ -1241,7 +1241,7 @@ acpi_add_single_object(struct acpi_device **child, device->parent = parent; device->bus_ops = *ops; /* workround for not call .start */ - acpi_device_get_busid(device, type); + acpi_device_get_busid(device); /* * Flags @@ -1304,7 +1304,7 @@ acpi_add_single_object(struct acpi_device **child, * Hardware ID, Unique ID, & Bus Address * ------------------------------------- */ - acpi_device_set_id(device, type); + acpi_device_set_id(device); /* * Power Management From 77c24888b7693eecee904308e0ee51f7f1f564df Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:30 +0000 Subject: [PATCH 09/25] ACPI: remove unnecessary argument checking acpi_add_single_object() is static, and all callers supply a valid "child" argument, so we don't need to check it. This patch also remove some unnecessary initializations. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 6c83342d13d5..f2e283426be9 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1222,14 +1222,10 @@ acpi_add_single_object(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type, struct acpi_bus_ops *ops) { - int result = 0; - struct acpi_device *device = NULL; + int result; + struct acpi_device *device; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - - if (!child) - return -EINVAL; - device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); if (!device) { printk(KERN_ERR PREFIX "Memory allocation error\n"); From 5c478f499c9e6a3ac542c940f7b434686f4967a5 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:35 +0000 Subject: [PATCH 10/25] ACPI: add acpi_bus_get_parent() and remove "parent" arguments This patch adds acpi_bus_get_parent(), which ascends the namespace until it finds a parent with an acpi_device. Then we use acpi_bus_get_parent() in acpi_add_single_object(), so callers don't have to figure out or keep track of the parent acpi_device. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 50 +++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index f2e283426be9..f205b368894b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -662,6 +662,33 @@ EXPORT_SYMBOL(acpi_bus_unregister_driver); /* -------------------------------------------------------------------------- Device Enumeration -------------------------------------------------------------------------- */ +static struct acpi_device *acpi_bus_get_parent(acpi_handle handle) +{ + acpi_status status; + int ret; + struct acpi_device *device; + + /* + * Fixed hardware devices do not appear in the namespace and do not + * have handles, but we fabricate acpi_devices for them, so we have + * to deal with them specially. + */ + if (handle == NULL) + return acpi_root; + + do { + status = acpi_get_parent(handle, &handle); + if (status == AE_NULL_ENTRY) + return NULL; + if (ACPI_FAILURE(status)) + return acpi_root; + + ret = acpi_bus_get_device(handle, &device); + if (ret == 0) + return device; + } while (1); +} + acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) { @@ -1217,10 +1244,9 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) return 0; } -static int -acpi_add_single_object(struct acpi_device **child, - struct acpi_device *parent, acpi_handle handle, int type, - struct acpi_bus_ops *ops) +static int acpi_add_single_object(struct acpi_device **child, + acpi_handle handle, int type, + struct acpi_bus_ops *ops) { int result; struct acpi_device *device; @@ -1234,7 +1260,7 @@ acpi_add_single_object(struct acpi_device **child, device->device_type = type; device->handle = handle; - device->parent = parent; + device->parent = acpi_bus_get_parent(handle); device->bus_ops = *ops; /* workround for not call .start */ acpi_device_get_busid(device); @@ -1434,8 +1460,8 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops) } if (ops->acpi_op_add) - status = acpi_add_single_object(&child, parent, - chandle, type, ops); + status = acpi_add_single_object(&child, chandle, type, + ops); else status = acpi_bus_get_device(chandle, &child); @@ -1488,7 +1514,7 @@ acpi_bus_add(struct acpi_device **child, memset(&ops, 0, sizeof(ops)); ops.acpi_op_add = 1; - result = acpi_add_single_object(child, parent, handle, type, &ops); + result = acpi_add_single_object(child, handle, type, &ops); if (!result) result = acpi_bus_scan(*child, &ops); @@ -1584,15 +1610,13 @@ static int acpi_bus_scan_fixed(void) * Enumerate all fixed-feature devices. */ if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) { - result = acpi_add_single_object(&device, acpi_root, - NULL, + result = acpi_add_single_object(&device, NULL, ACPI_BUS_TYPE_POWER_BUTTON, &ops); } if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { - result = acpi_add_single_object(&device, acpi_root, - NULL, + result = acpi_add_single_object(&device, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON, &ops); } @@ -1618,7 +1642,7 @@ int __init acpi_scan_init(void) /* * Create the root device in the bus's device tree */ - result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, + result = acpi_add_single_object(&acpi_root, ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SYSTEM, &ops); if (result) goto Done; From 8e029bf0a611ea3995bd1fae0285cbaf6eed7f16 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:40 +0000 Subject: [PATCH 11/25] ACPI: convert acpi_bus_scan() to operate on an acpi_handle This patch changes acpi_bus_scan() to take an acpi_handle rather than an acpi_device pointer. I plan to use acpi_bus_scan() in the hotplug path, and I'd rather not assume that notifications only go to nodes that already have acpi_devices. This will also help remove the special case for adding the root node. We currently add the root by hand before acpi_bus_scan(), but using a handle here means we can start the acpi_bus_scan() directly with the root even though it doesn't have an acpi_device yet. Note that acpi_bus_scan() currently adds and/or starts the *children* of its device argument. It doesn't do anything with the device itself. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index f205b368894b..4fe73596c5d3 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1387,7 +1387,7 @@ static int acpi_add_single_object(struct acpi_device **child, return result; } -static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops) +static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops) { acpi_status status = AE_OK; struct acpi_device *parent = NULL; @@ -1396,13 +1396,16 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops) acpi_handle chandle = NULL; acpi_object_type type = 0; u32 level = 1; + int ret; - - if (!start) - return -EINVAL; - - parent = start; - phandle = start->handle; + /* + * We must have an acpi_device for the starting node already, and + * we scan its children. + */ + phandle = handle; + ret = acpi_bus_get_device(phandle, &parent); + if (ret) + return ret; /* * Parse through the ACPI namespace, identify all 'devices', and @@ -1516,7 +1519,7 @@ acpi_bus_add(struct acpi_device **child, result = acpi_add_single_object(child, handle, type, &ops); if (!result) - result = acpi_bus_scan(*child, &ops); + result = acpi_bus_scan((*child)->handle, &ops); return result; } @@ -1527,16 +1530,13 @@ int acpi_bus_start(struct acpi_device *device) int result; struct acpi_bus_ops ops; - - if (!device) - return -EINVAL; + memset(&ops, 0, sizeof(ops)); + ops.acpi_op_start = 1; result = acpi_start_single_object(device); - if (!result) { - memset(&ops, 0, sizeof(ops)); - ops.acpi_op_start = 1; - result = acpi_bus_scan(device, &ops); - } + if (!result) + result = acpi_bus_scan(device->handle, &ops); + return result; } EXPORT_SYMBOL(acpi_bus_start); @@ -1653,7 +1653,7 @@ int __init acpi_scan_init(void) result = acpi_bus_scan_fixed(); if (!result) - result = acpi_bus_scan(acpi_root, &ops); + result = acpi_bus_scan(acpi_root->handle, &ops); if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); From adc08e2035f1859d4b129f42b2c2305ef090d226 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:45 +0000 Subject: [PATCH 12/25] ACPI: enumerate namespace before adding functional fixed hardware devices This patch changes the order so we enumerate in the "root, namespace, functional fixed" order instead of the "root, functional fixed, namespace" order. When I change acpi_bus_scan() to use acpi_walk_namespace(), it will use the former order, so this patch isolates the order change for bisectability. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 4fe73596c5d3..27d2dec55c6c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1650,10 +1650,10 @@ int __init acpi_scan_init(void) /* * Enumerate devices in the ACPI namespace. */ - result = acpi_bus_scan_fixed(); + result = acpi_bus_scan(acpi_root->handle, &ops); if (!result) - result = acpi_bus_scan(acpi_root->handle, &ops); + result = acpi_bus_scan_fixed(); if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); From 859ac9a4be0c753cece0e30a2e4a65fd2cdcaeee Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:50 +0000 Subject: [PATCH 13/25] ACPI: identify device tree root by null parent pointer, not ACPI_BUS_TYPE We can identify the root of the ACPI device tree by the fact that it has no parent. This is simpler than passing around ACPI_BUS_TYPE_SYSTEM and will help remove special treatment of the device tree root. Currently, we add the root by hand with ACPI_BUS_TYPE_SYSTEM. If we traverse the tree treating the root as just another device and use acpi_get_type(), the root shows up as ACPI_TYPE_DEVICE. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 20 +++++++++++++------- include/acpi/acpi_bus.h | 1 - 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 27d2dec55c6c..0b5aaf059c9b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -22,6 +22,8 @@ extern struct acpi_device *acpi_root; #define ACPI_BUS_HID "LNXSYBUS" #define ACPI_BUS_DEVICE_NAME "System Bus" +#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) + static LIST_HEAD(acpi_device_list); static LIST_HEAD(acpi_bus_id_list); DEFINE_MUTEX(acpi_device_lock); @@ -955,10 +957,12 @@ static void acpi_device_get_busid(struct acpi_device *device) * The device's Bus ID is simply the object name. * TBD: Shouldn't this value be unique (within the ACPI namespace)? */ - switch (device->device_type) { - case ACPI_BUS_TYPE_SYSTEM: + if (ACPI_IS_ROOT_DEVICE(device)) { strcpy(device->pnp.bus_id, "ACPI"); - break; + return; + } + + switch (device->device_type) { case ACPI_BUS_TYPE_POWER_BUTTON: strcpy(device->pnp.bus_id, "PWRF"); break; @@ -1093,6 +1097,11 @@ static void acpi_device_set_id(struct acpi_device *device) switch (device->device_type) { case ACPI_BUS_TYPE_DEVICE: + if (ACPI_IS_ROOT_DEVICE(device)) { + hid = ACPI_SYSTEM_HID; + break; + } + status = acpi_get_object_info(device->handle, &info); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "%s: Error reading device info\n", __func__); @@ -1129,9 +1138,6 @@ static void acpi_device_set_id(struct acpi_device *device) case ACPI_BUS_TYPE_PROCESSOR: hid = ACPI_PROCESSOR_OBJECT_HID; break; - case ACPI_BUS_TYPE_SYSTEM: - hid = ACPI_SYSTEM_HID; - break; case ACPI_BUS_TYPE_THERMAL: hid = ACPI_THERMAL_HID; break; @@ -1643,7 +1649,7 @@ int __init acpi_scan_init(void) * Create the root device in the bus's device tree */ result = acpi_add_single_object(&acpi_root, ACPI_ROOT_OBJECT, - ACPI_BUS_TYPE_SYSTEM, &ops); + ACPI_BUS_TYPE_DEVICE, &ops); if (result) goto Done; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 8456e8cbf9fd..bc7a69516dce 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -70,7 +70,6 @@ enum acpi_bus_device_type { ACPI_BUS_TYPE_POWER, ACPI_BUS_TYPE_PROCESSOR, ACPI_BUS_TYPE_THERMAL, - ACPI_BUS_TYPE_SYSTEM, ACPI_BUS_TYPE_POWER_BUTTON, ACPI_BUS_TYPE_SLEEP_BUTTON, ACPI_BUS_DEVICE_TYPE_COUNT From 51a85faf2d4ffecd8384b3f501f9f7ee2b05ee53 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:29:56 +0000 Subject: [PATCH 14/25] ACPI: use acpi_walk_namespace() to enumerate devices acpi_bus_scan() currently walks the namespace manually. This patch changes it to use acpi_walk_namespace() instead. Besides removing some complicated code, this means we take advantage of the namespace locking done by acpi_walk_namespace(). The locking isn't so important at boot-time, but I hope to eventually use this same path to handle hot-addition of devices, when it will be important. Note that acpi_walk_namespace() does not actually visit the starting node first, so we need to do that by hand first. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 214 +++++++++++++++++--------------------------- 1 file changed, 83 insertions(+), 131 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 0b5aaf059c9b..ed2b5f9a9815 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1393,123 +1393,92 @@ static int acpi_add_single_object(struct acpi_device **child, return result; } -static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops) +static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, + void *context, void **return_value) { acpi_status status = AE_OK; - struct acpi_device *parent = NULL; - struct acpi_device *child = NULL; - acpi_handle phandle = NULL; - acpi_handle chandle = NULL; + struct acpi_device *device = NULL; acpi_object_type type = 0; - u32 level = 1; - int ret; + struct acpi_bus_ops *ops = context; + + status = acpi_get_type(handle, &type); + if (ACPI_FAILURE(status)) + return AE_OK; /* - * We must have an acpi_device for the starting node already, and - * we scan its children. + * We're only interested in objects that we consider 'devices'. */ - phandle = handle; - ret = acpi_bus_get_device(phandle, &parent); - if (ret) - return ret; - - /* - * Parse through the ACPI namespace, identify all 'devices', and - * create a new 'struct acpi_device' for each. - */ - while ((level > 0) && parent) { - - status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, - chandle, &chandle); - - /* - * If this scope is exhausted then move our way back up. - */ - if (ACPI_FAILURE(status)) { - level--; - chandle = phandle; - acpi_get_parent(phandle, &phandle); - if (parent->parent) - parent = parent->parent; - continue; - } - - status = acpi_get_type(chandle, &type); - if (ACPI_FAILURE(status)) - continue; - - /* - * If this is a scope object then parse it (depth-first). - */ - if (type == ACPI_TYPE_LOCAL_SCOPE) { - level++; - phandle = chandle; - chandle = NULL; - continue; - } - - /* - * We're only interested in objects that we consider 'devices'. - */ - switch (type) { - case ACPI_TYPE_DEVICE: - type = ACPI_BUS_TYPE_DEVICE; - break; - case ACPI_TYPE_PROCESSOR: - type = ACPI_BUS_TYPE_PROCESSOR; - break; - case ACPI_TYPE_THERMAL: - type = ACPI_BUS_TYPE_THERMAL; - break; - case ACPI_TYPE_POWER: - type = ACPI_BUS_TYPE_POWER; - break; - default: - continue; - } - - if (ops->acpi_op_add) - status = acpi_add_single_object(&child, chandle, type, - ops); - else - status = acpi_bus_get_device(chandle, &child); - - if (ACPI_FAILURE(status)) - continue; - - if (ops->acpi_op_start && !(ops->acpi_op_add)) { - status = acpi_start_single_object(child); - if (ACPI_FAILURE(status)) - continue; - } - - /* - * If the device is present, enabled, and functioning then - * parse its scope (depth-first). Note that we need to - * represent absent devices to facilitate PnP notifications - * -- but only the subtree head (not all of its children, - * which will be enumerated when the parent is inserted). - * - * TBD: Need notifications and other detection mechanisms - * in place before we can fully implement this. - */ - /* - * When the device is not present but functional, it is also - * necessary to scan the children of this device. - */ - if (child->status.present || (!child->status.present && - child->status.functional)) { - status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, - NULL, NULL); - if (ACPI_SUCCESS(status)) { - level++; - phandle = chandle; - chandle = NULL; - parent = child; - } - } + switch (type) { + case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ + case ACPI_TYPE_DEVICE: + type = ACPI_BUS_TYPE_DEVICE; + break; + case ACPI_TYPE_PROCESSOR: + type = ACPI_BUS_TYPE_PROCESSOR; + break; + case ACPI_TYPE_THERMAL: + type = ACPI_BUS_TYPE_THERMAL; + break; + case ACPI_TYPE_POWER: + type = ACPI_BUS_TYPE_POWER; + break; + default: + return AE_OK; } + if (ops->acpi_op_add) + status = acpi_add_single_object(&device, handle, type, ops); + else + status = acpi_bus_get_device(handle, &device); + + if (ACPI_FAILURE(status)) + return AE_CTRL_DEPTH; + + if (ops->acpi_op_start && !(ops->acpi_op_add)) { + status = acpi_start_single_object(device); + if (ACPI_FAILURE(status)) + return AE_CTRL_DEPTH; + } + + /* + * If the device is present, enabled, and functioning then + * parse its scope (depth-first). Note that we need to + * represent absent devices to facilitate PnP notifications + * -- but only the subtree head (not all of its children, + * which will be enumerated when the parent is inserted). + * + * TBD: Need notifications and other detection mechanisms + * in place before we can fully implement this. + * + * When the device is not present but functional, it is also + * necessary to scan the children of this device. + */ + if (!device->status.present && !device->status.functional) + return AE_CTRL_DEPTH; + + if (!*return_value) + *return_value = device; + return AE_OK; +} + +static int acpi_bus_scan(acpi_handle handle, struct acpi_bus_ops *ops, + struct acpi_device **child) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + void *device = NULL; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + printk(KERN_INFO PREFIX "Enumerating devices from [%s]\n", + (char *) buffer.pointer); + + status = acpi_bus_check_add(handle, 0, ops, &device); + if (ACPI_SUCCESS(status)) + acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, + acpi_bus_check_add, ops, &device); + + if (child) + *child = device; return 0; } @@ -1517,33 +1486,25 @@ int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type) { - int result; struct acpi_bus_ops ops; memset(&ops, 0, sizeof(ops)); ops.acpi_op_add = 1; - result = acpi_add_single_object(child, handle, type, &ops); - if (!result) - result = acpi_bus_scan((*child)->handle, &ops); - - return result; + acpi_bus_scan(handle, &ops, child); + return 0; } EXPORT_SYMBOL(acpi_bus_add); int acpi_bus_start(struct acpi_device *device) { - int result; struct acpi_bus_ops ops; memset(&ops, 0, sizeof(ops)); ops.acpi_op_start = 1; - result = acpi_start_single_object(device); - if (!result) - result = acpi_bus_scan(device->handle, &ops); - - return result; + acpi_bus_scan(device->handle, &ops, NULL); + return 0; } EXPORT_SYMBOL(acpi_bus_start); @@ -1645,18 +1606,10 @@ int __init acpi_scan_init(void) printk(KERN_ERR PREFIX "Could not register bus type\n"); } - /* - * Create the root device in the bus's device tree - */ - result = acpi_add_single_object(&acpi_root, ACPI_ROOT_OBJECT, - ACPI_BUS_TYPE_DEVICE, &ops); - if (result) - goto Done; - /* * Enumerate devices in the ACPI namespace. */ - result = acpi_bus_scan(acpi_root->handle, &ops); + result = acpi_bus_scan(ACPI_ROOT_OBJECT, &ops, &acpi_root); if (!result) result = acpi_bus_scan_fixed(); @@ -1664,6 +1617,5 @@ int __init acpi_scan_init(void) if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); -Done: return result; } From 402ac53614bce0c273c73a80339556bf56dd3d39 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:30:01 +0000 Subject: [PATCH 15/25] ACPI: add acpi_bus_get_status_handle() Add acpi_bus_get_status_handle() so we can get the status of a namespace object before building a struct acpi_device. This removes a use of "device->flags.dynamic_status", a cached indicator of whether _STA exists. It seems simpler and more reliable to just evaluate _STA and catch AE_NOT_FOUND errors. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/bus.c | 51 +++++++++++++++++++---------------------- include/acpi/acpi_bus.h | 2 ++ 2 files changed, 25 insertions(+), 28 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 135fbfe1825c..741191524353 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -94,36 +94,33 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) EXPORT_SYMBOL(acpi_bus_get_device); +acpi_status acpi_bus_get_status_handle(acpi_handle handle, + unsigned long long *sta) +{ + acpi_status status; + + status = acpi_evaluate_integer(handle, "_STA", NULL, sta); + if (ACPI_SUCCESS(status)) + return AE_OK; + + if (status == AE_NOT_FOUND) { + *sta = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | + ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; + return AE_OK; + } + return status; +} + int acpi_bus_get_status(struct acpi_device *device) { - acpi_status status = AE_OK; - unsigned long long sta = 0; + acpi_status status; + unsigned long long sta; + status = acpi_bus_get_status_handle(device->handle, &sta); + if (ACPI_FAILURE(status)) + return -ENODEV; - if (!device) - return -EINVAL; - - /* - * Evaluate _STA if present. - */ - if (device->flags.dynamic_status) { - status = - acpi_evaluate_integer(device->handle, "_STA", NULL, &sta); - if (ACPI_FAILURE(status)) - return -ENODEV; - STRUCT_TO_INT(device->status) = (int)sta; - } - - /* - * According to ACPI spec some device can be present and functional - * even if the parent is not present but functional. - * In such conditions the child device should not inherit the status - * from the parent. - */ - else - STRUCT_TO_INT(device->status) = - ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | - ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; + STRUCT_TO_INT(device->status) = (int) sta; if (device->status.functional && !device->status.present) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: " @@ -135,10 +132,8 @@ int acpi_bus_get_status(struct acpi_device *device) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status))); - return 0; } - EXPORT_SYMBOL(acpi_bus_get_status); void acpi_bus_private_data_handler(acpi_handle handle, diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index bc7a69516dce..670f7f33837e 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -322,6 +322,8 @@ extern void unregister_acpi_bus_notifier(struct notifier_block *nb); int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); void acpi_bus_data_handler(acpi_handle handle, void *context); +acpi_status acpi_bus_get_status_handle(acpi_handle handle, + unsigned long long *sta); int acpi_bus_get_status(struct acpi_device *device); int acpi_bus_get_power(acpi_handle handle, int *state); int acpi_bus_set_power(acpi_handle handle, int state); From 778cbc1d3abd434b6d882714630235e3711bb15b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:30:06 +0000 Subject: [PATCH 16/25] ACPI: factor out device type and status checking This patch adds acpi_bus_type_and_status(), which determines the type of the object and whether we want to build an acpi_device for it. If it is acpi_device-worthy, it returns the type and the device's current status. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 145 ++++++++++++++++++-------------------------- 1 file changed, 60 insertions(+), 85 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ed2b5f9a9815..954bd01f295a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1252,6 +1252,7 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) static int acpi_add_single_object(struct acpi_device **child, acpi_handle handle, int type, + unsigned long long sta, struct acpi_bus_ops *ops) { int result; @@ -1268,60 +1269,20 @@ static int acpi_add_single_object(struct acpi_device **child, device->handle = handle; device->parent = acpi_bus_get_parent(handle); device->bus_ops = *ops; /* workround for not call .start */ + STRUCT_TO_INT(device->status) = sta; acpi_device_get_busid(device); /* * Flags * ----- - * Get prior to calling acpi_bus_get_status() so we know whether - * or not _STA is present. Note that we only look for object - * handles -- cannot evaluate objects until we know the device is - * present and properly initialized. + * Note that we only look for object handles -- cannot evaluate objects + * until we know the device is present and properly initialized. */ result = acpi_bus_get_flags(device); if (result) goto end; - /* - * Status - * ------ - * See if the device is present. We always assume that non-Device - * and non-Processor objects (e.g. thermal zones, power resources, - * etc.) are present, functioning, etc. (at least when parent object - * is present). Note that _STA has a different meaning for some - * objects (e.g. power resources) so we need to be careful how we use - * it. - */ - switch (type) { - case ACPI_BUS_TYPE_PROCESSOR: - case ACPI_BUS_TYPE_DEVICE: - result = acpi_bus_get_status(device); - if (ACPI_FAILURE(result)) { - result = -ENODEV; - goto end; - } - /* - * When the device is neither present nor functional, the - * device should not be added to Linux ACPI device tree. - * When the status of the device is not present but functinal, - * it should be added to Linux ACPI tree. For example : bay - * device , dock device. - * In such conditions it is unncessary to check whether it is - * bay device or dock device. - */ - if (!device->status.present && !device->status.functional) { - result = -ENODEV; - goto end; - } - break; - default: - STRUCT_TO_INT(device->status) = - ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | - ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; - break; - } - /* * Initialize Device * ----------------- @@ -1393,41 +1354,69 @@ static int acpi_add_single_object(struct acpi_device **child, return result; } +#define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ + ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) + +static int acpi_bus_type_and_status(acpi_handle handle, int *type, + unsigned long long *sta) +{ + acpi_status status; + acpi_object_type acpi_type; + + status = acpi_get_type(handle, &acpi_type); + if (ACPI_FAILURE(status)) + return -ENODEV; + + switch (acpi_type) { + case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ + case ACPI_TYPE_DEVICE: + *type = ACPI_BUS_TYPE_DEVICE; + status = acpi_bus_get_status_handle(handle, sta); + if (ACPI_FAILURE(status)) + return -ENODEV; + break; + case ACPI_TYPE_PROCESSOR: + *type = ACPI_BUS_TYPE_PROCESSOR; + status = acpi_bus_get_status_handle(handle, sta); + if (ACPI_FAILURE(status)) + return -ENODEV; + break; + case ACPI_TYPE_THERMAL: + *type = ACPI_BUS_TYPE_THERMAL; + *sta = ACPI_STA_DEFAULT; + break; + case ACPI_TYPE_POWER: + *type = ACPI_BUS_TYPE_POWER; + *sta = ACPI_STA_DEFAULT; + break; + default: + return -ENODEV; + } + + return 0; +} + static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, void *context, void **return_value) { - acpi_status status = AE_OK; - struct acpi_device *device = NULL; - acpi_object_type type = 0; struct acpi_bus_ops *ops = context; + struct acpi_device *device = NULL; + acpi_status status; + int type; + unsigned long long sta; + int result; - status = acpi_get_type(handle, &type); - if (ACPI_FAILURE(status)) + result = acpi_bus_type_and_status(handle, &type, &sta); + if (result) return AE_OK; - /* - * We're only interested in objects that we consider 'devices'. - */ - switch (type) { - case ACPI_TYPE_ANY: /* for ACPI_ROOT_OBJECT */ - case ACPI_TYPE_DEVICE: - type = ACPI_BUS_TYPE_DEVICE; - break; - case ACPI_TYPE_PROCESSOR: - type = ACPI_BUS_TYPE_PROCESSOR; - break; - case ACPI_TYPE_THERMAL: - type = ACPI_BUS_TYPE_THERMAL; - break; - case ACPI_TYPE_POWER: - type = ACPI_BUS_TYPE_POWER; - break; - default: - return AE_OK; - } + if (!(sta & ACPI_STA_DEVICE_PRESENT) && + !(sta & ACPI_STA_DEVICE_FUNCTIONING)) + return AE_CTRL_DEPTH; if (ops->acpi_op_add) - status = acpi_add_single_object(&device, handle, type, ops); + status = acpi_add_single_object(&device, handle, type, sta, + ops); else status = acpi_bus_get_device(handle, &device); @@ -1440,22 +1429,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, return AE_CTRL_DEPTH; } - /* - * If the device is present, enabled, and functioning then - * parse its scope (depth-first). Note that we need to - * represent absent devices to facilitate PnP notifications - * -- but only the subtree head (not all of its children, - * which will be enumerated when the parent is inserted). - * - * TBD: Need notifications and other detection mechanisms - * in place before we can fully implement this. - * - * When the device is not present but functional, it is also - * necessary to scan the children of this device. - */ - if (!device->status.present && !device->status.functional) - return AE_CTRL_DEPTH; - if (!*return_value) *return_value = device; return AE_OK; @@ -1579,12 +1552,14 @@ static int acpi_bus_scan_fixed(void) if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) { result = acpi_add_single_object(&device, NULL, ACPI_BUS_TYPE_POWER_BUTTON, + ACPI_STA_DEFAULT, &ops); } if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { result = acpi_add_single_object(&device, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON, + ACPI_STA_DEFAULT, &ops); } From e3b87f8a9d5a61f6367c66d1bb0a4e19d251194d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 19:30:11 +0000 Subject: [PATCH 17/25] ACPI: handle re-enumeration, when acpi_devices might already exist acpi_bus_scan() traverses the namespace to enumerate devices and uses acpi_add_single_object() to create acpi_devices. When the platform notifies us of a hot-plug event, we need to traverse part of the namespace again to figure out what appeared or disappeared. (We don't yet call acpi_bus_scan() during hot-plug, but I plan to do that in the future.) This patch makes acpi_add_single_object() notice when we already have an acpi_device, so we don't need to make a new one. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 954bd01f295a..2c4cac576a7e 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1400,10 +1400,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, void *context, void **return_value) { struct acpi_bus_ops *ops = context; - struct acpi_device *device = NULL; - acpi_status status; int type; unsigned long long sta; + struct acpi_device *device; + acpi_status status; int result; result = acpi_bus_type_and_status(handle, &type, &sta); @@ -1414,13 +1414,16 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, !(sta & ACPI_STA_DEVICE_FUNCTIONING)) return AE_CTRL_DEPTH; - if (ops->acpi_op_add) - status = acpi_add_single_object(&device, handle, type, sta, - ops); - else - status = acpi_bus_get_device(handle, &device); + /* + * We may already have an acpi_device from a previous enumeration. If + * so, we needn't add it again, but we may still have to start it. + */ + device = NULL; + acpi_bus_get_device(handle, &device); + if (ops->acpi_op_add && !device) + acpi_add_single_object(&device, handle, type, sta, ops); - if (ACPI_FAILURE(status)) + if (!device) return AE_CTRL_DEPTH; if (ops->acpi_op_start && !(ops->acpi_op_add)) { From 78b8e141f8458ba0b8ac53c45bc327112c53887e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 13:35:04 -0600 Subject: [PATCH 18/25] ACPI: fix synthetic HID for \_SB_ This makes \_SB_ show up as /sys/devices/LNXSYSTM:00/LNXSYBUS:00 rather than "device:00". This has been broken for a loooong time (at least since 2.6.13) because device->parent is an acpi_device pointer, not a handle. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2c4cac576a7e..e9227ea2cb2f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1100,6 +1100,12 @@ static void acpi_device_set_id(struct acpi_device *device) if (ACPI_IS_ROOT_DEVICE(device)) { hid = ACPI_SYSTEM_HID; break; + } else if (ACPI_IS_ROOT_DEVICE(device->parent)) { + /* \_SB_, the only root-level namespace device */ + hid = ACPI_BUS_HID; + strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); + strcpy(device->pnp.device_class, ACPI_BUS_CLASS); + break; } status = acpi_get_object_info(device->handle, &info); @@ -1149,18 +1155,6 @@ static void acpi_device_set_id(struct acpi_device *device) break; } - /* - * \_SB - * ---- - * Fix for the system root bus device -- the only root-level device. - */ - if (((acpi_handle)device->parent == ACPI_ROOT_OBJECT) && - (device->device_type == ACPI_BUS_TYPE_DEVICE)) { - hid = ACPI_BUS_HID; - strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); - strcpy(device->pnp.device_class, ACPI_BUS_CLASS); - } - if (hid) { device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1); if (device->pnp.hardware_id) { From ea8d82fd316208bd0ffe6f64823d04bcb8c57158 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 13:35:09 -0600 Subject: [PATCH 19/25] ACPI: use acpi_device_hid() when possible Use acpi_device_hid() rather than accessing acpi_device.pnp.hardware_id directly. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 6 +++--- drivers/pnp/pnpacpi/core.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index e9227ea2cb2f..269c0aae4bed 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -185,7 +185,7 @@ static ssize_t acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct acpi_device *acpi_dev = to_acpi_device(dev); - return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id); + return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev)); } static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); @@ -501,7 +501,7 @@ static int acpi_device_register(struct acpi_device *device) * If failed, create one and link it into acpi_bus_id_list */ list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) { - if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) { + if (!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id ? acpi_device_hid(device) : "device")) { acpi_device_bus_id->instance_no ++; found = 1; kfree(new_bus_id); @@ -510,7 +510,7 @@ static int acpi_device_register(struct acpi_device *device) } if (!found) { acpi_device_bus_id = new_bus_id; - strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device"); + strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? acpi_device_hid(device) : "device"); acpi_device_bus_id->instance_no = 0; list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); } diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index c07fdb94d665..ff963d4dab46 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -234,7 +234,7 @@ static int __init acpi_pnp_match(struct device *dev, void *_pnp) /* true means it matched */ return acpi->flags.hardware_id && !acpi_get_physical_device(acpi->handle) - && compare_pnp_id(pnp->id, acpi->pnp.hardware_id); + && compare_pnp_id(pnp->id, acpi_device_hid(acpi)); } static int __init acpi_pnp_find_device(struct device *dev, acpi_handle * handle) From b1fbfb2ae8f2f0e04219218da6f52f7313466899 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 13:35:14 -0600 Subject: [PATCH 20/25] ACPI: make sure every acpi_device has an ID This makes sure every acpi_device has at least one ID. If we build an acpi_device for a namespace node with no _HID or _CID, we sometimes synthesize an ID like "LNXCPU" or "LNXVIDEO". If we don't even have that, give it a default "device" ID. Note that this means things like: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/HWP0001:00/HWP0002:04/device:00 (a PCI slot SxFy device) will have "hid" and "modprobe" entries, where they didn't before. These aren't very useful (a HID of "device" doesn't tell you what *kind* of device it is, so it doesn't help find a driver), but I don't think they're harmful. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 269c0aae4bed..53b96e7a64ab 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1155,6 +1155,16 @@ static void acpi_device_set_id(struct acpi_device *device) break; } + /* + * We build acpi_devices for some objects that don't have _HID or _CID, + * e.g., PCI bridges and slots. Drivers can't bind to these objects, + * but we do use them indirectly by traversing the acpi_device tree. + * This generic ID isn't useful for driver binding, but it provides + * the useful property that "every acpi_device has an ID." + */ + if (!hid && !cid_list && !cid_add) + hid = "device"; + if (hid) { device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1); if (device->pnp.hardware_id) { From 7f47fa6c2ff15f5e59cdbb350f86faef6829294a Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 13:35:19 -0600 Subject: [PATCH 21/25] ACPI: maintain a single list of _HID and _CID IDs There's no need to treat _HID and _CID differently. Keeping them in a single list makes code that uses the IDs a little simpler because it can just traverse the list rather than checking "do we have a HID?", "do we have any CIDs?" Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Chiang Signed-off-by: Len Brown --- drivers/acpi/scan.c | 166 ++++++++++--------------------------- drivers/pnp/pnpacpi/core.c | 16 ++-- include/acpi/acpi_bus.h | 10 ++- 3 files changed, 60 insertions(+), 132 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 53b96e7a64ab..2e8889f62666 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -45,6 +45,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, { int len; int count; + struct acpi_hardware_id *id; if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids) return -ENODEV; @@ -52,33 +53,14 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, len = snprintf(modalias, size, "acpi:"); size -= len; - if (acpi_dev->flags.hardware_id) { - count = snprintf(&modalias[len], size, "%s:", - acpi_dev->pnp.hardware_id); + list_for_each_entry(id, &acpi_dev->pnp.ids, list) { + count = snprintf(&modalias[len], size, "%s:", id->id); if (count < 0 || count >= size) return -EINVAL; len += count; size -= count; } - if (acpi_dev->flags.compatible_ids) { - struct acpica_device_id_list *cid_list; - int i; - - cid_list = acpi_dev->pnp.cid_list; - for (i = 0; i < cid_list->count; i++) { - count = snprintf(&modalias[len], size, "%s:", - cid_list->ids[i].string); - if (count < 0 || count >= size) { - printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size", - acpi_dev->pnp.device_name, i); - break; - } - len += count; - size -= count; - } - } - modalias[len] = '\0'; return len; } @@ -273,6 +255,7 @@ int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids) { const struct acpi_device_id *id; + struct acpi_hardware_id *hwid; /* * If the device is not present, it is unnecessary to load device @@ -281,40 +264,30 @@ int acpi_match_device_ids(struct acpi_device *device, if (!device->status.present) return -ENODEV; - if (device->flags.hardware_id) { - for (id = ids; id->id[0]; id++) { - if (!strcmp((char*)id->id, device->pnp.hardware_id)) + for (id = ids; id->id[0]; id++) + list_for_each_entry(hwid, &device->pnp.ids, list) + if (!strcmp((char *) id->id, hwid->id)) return 0; - } - } - - if (device->flags.compatible_ids) { - struct acpica_device_id_list *cid_list = device->pnp.cid_list; - int i; - - for (id = ids; id->id[0]; id++) { - /* compare multiple _CID entries against driver ids */ - for (i = 0; i < cid_list->count; i++) { - if (!strcmp((char*)id->id, - cid_list->ids[i].string)) - return 0; - } - } - } return -ENOENT; } EXPORT_SYMBOL(acpi_match_device_ids); +static void acpi_free_ids(struct acpi_device *device) +{ + struct acpi_hardware_id *id, *tmp; + + list_for_each_entry_safe(id, tmp, &device->pnp.ids, list) { + kfree(id->id); + kfree(id); + } +} + static void acpi_device_release(struct device *dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); - kfree(acpi_dev->pnp.cid_list); - if (acpi_dev->flags.hardware_id) - kfree(acpi_dev->pnp.hardware_id); - if (acpi_dev->flags.unique_id) - kfree(acpi_dev->pnp.unique_id); + acpi_free_ids(acpi_dev); kfree(acpi_dev); } @@ -1028,62 +1001,31 @@ static int acpi_dock_match(struct acpi_device *device) return acpi_get_handle(device->handle, "_DCK", &tmp); } -static struct acpica_device_id_list* -acpi_add_cid( - struct acpi_device_info *info, - struct acpica_device_id *new_cid) +char *acpi_device_hid(struct acpi_device *device) { - struct acpica_device_id_list *cid; - char *next_id_string; - acpi_size cid_length; - acpi_size new_cid_length; - u32 i; + struct acpi_hardware_id *hid; + hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list); + return hid->id; +} +EXPORT_SYMBOL(acpi_device_hid); - /* Allocate new CID list with room for the new CID */ +static void acpi_add_id(struct acpi_device *device, const char *dev_id) +{ + struct acpi_hardware_id *id; - if (!new_cid) - new_cid_length = info->compatible_id_list.list_size; - else if (info->compatible_id_list.list_size) - new_cid_length = info->compatible_id_list.list_size + - new_cid->length + sizeof(struct acpica_device_id); - else - new_cid_length = sizeof(struct acpica_device_id_list) + new_cid->length; + id = kmalloc(sizeof(*id), GFP_KERNEL); + if (!id) + return; - cid = ACPI_ALLOCATE_ZEROED(new_cid_length); - if (!cid) { - return NULL; + id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL); + if (!id->id) { + kfree(id); + return; } - cid->list_size = new_cid_length; - cid->count = info->compatible_id_list.count; - if (new_cid) - cid->count++; - next_id_string = (char *) cid->ids + (cid->count * sizeof(struct acpica_device_id)); - - /* Copy all existing CIDs */ - - for (i = 0; i < info->compatible_id_list.count; i++) { - cid_length = info->compatible_id_list.ids[i].length; - cid->ids[i].string = next_id_string; - cid->ids[i].length = cid_length; - - ACPI_MEMCPY(next_id_string, info->compatible_id_list.ids[i].string, - cid_length); - - next_id_string += cid_length; - } - - /* Append the new CID */ - - if (new_cid) { - cid->ids[i].string = next_id_string; - cid->ids[i].length = new_cid->length; - - ACPI_MEMCPY(next_id_string, new_cid->string, new_cid->length); - } - - return cid; + strcpy(id->id, dev_id); + list_add_tail(&id->list, &device->pnp.ids); } static void acpi_device_set_id(struct acpi_device *device) @@ -1094,6 +1036,7 @@ static void acpi_device_set_id(struct acpi_device *device) struct acpica_device_id_list *cid_list = NULL; char *cid_add = NULL; acpi_status status; + int i; switch (device->device_type) { case ACPI_BUS_TYPE_DEVICE: @@ -1166,15 +1109,9 @@ static void acpi_device_set_id(struct acpi_device *device) hid = "device"; if (hid) { - device->pnp.hardware_id = ACPI_ALLOCATE_ZEROED(strlen (hid) + 1); - if (device->pnp.hardware_id) { - strcpy(device->pnp.hardware_id, hid); - device->flags.hardware_id = 1; - } + acpi_add_id(device, hid); + device->flags.hardware_id = 1; } - if (!device->flags.hardware_id) - device->pnp.hardware_id = ""; - if (uid) { device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); if (device->pnp.unique_id) { @@ -1185,24 +1122,12 @@ static void acpi_device_set_id(struct acpi_device *device) if (!device->flags.unique_id) device->pnp.unique_id = ""; - if (cid_list || cid_add) { - struct acpica_device_id_list *list; - - if (cid_add) { - struct acpica_device_id cid; - cid.length = strlen (cid_add) + 1; - cid.string = cid_add; - - list = acpi_add_cid(info, &cid); - } else { - list = acpi_add_cid(info, NULL); - } - - if (list) { - device->pnp.cid_list = list; - if (cid_add) - device->flags.compatible_ids = 1; - } + if (cid_list) + for (i = 0; i < cid_list->count; i++) + acpi_add_id(device, cid_list->ids[i].string); + if (cid_add) { + acpi_add_id(device, cid_add); + device->flags.compatible_ids = 1; } kfree(info); @@ -1269,6 +1194,7 @@ static int acpi_add_single_object(struct acpi_device **child, return -ENOMEM; } + INIT_LIST_HEAD(&device->pnp.ids); device->device_type = type; device->handle = handle; device->parent = acpi_bus_get_parent(handle); diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index ff963d4dab46..3a4478f1fc72 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -153,6 +153,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) acpi_handle temp = NULL; acpi_status status; struct pnp_dev *dev; + struct acpi_hardware_id *id; /* * If a PnPacpi device is not present , the device @@ -193,15 +194,12 @@ static int __init pnpacpi_add_device(struct acpi_device *device) if (dev->capabilities & PNP_CONFIGURABLE) pnpacpi_parse_resource_option_data(dev); - if (device->flags.compatible_ids) { - struct acpica_device_id_list *cid_list = device->pnp.cid_list; - int i; - - for (i = 0; i < cid_list->count; i++) { - if (!ispnpidacpi(cid_list->ids[i].string)) - continue; - pnp_add_id(dev, cid_list->ids[i].string); - } + list_for_each_entry(id, &device->pnp.ids, list) { + if (!strcmp(id->id, acpi_device_hid(device))) + continue; + if (!ispnpidacpi(id->id)) + continue; + pnp_add_id(dev, id->id); } /* clear out the damaged flags */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 670f7f33837e..c2c434626edc 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -171,19 +171,23 @@ typedef unsigned long acpi_bus_address; typedef char acpi_device_name[40]; typedef char acpi_device_class[20]; +struct acpi_hardware_id { + struct list_head list; + char *id; +}; + struct acpi_device_pnp { acpi_bus_id bus_id; /* Object name */ acpi_bus_address bus_address; /* _ADR */ - char *hardware_id; /* _HID */ - struct acpica_device_id_list *cid_list; /* _CIDs */ char *unique_id; /* _UID */ + struct list_head ids; /* _HID and _CIDs */ acpi_device_name device_name; /* Driver-determined */ acpi_device_class device_class; /* " */ }; #define acpi_device_bid(d) ((d)->pnp.bus_id) #define acpi_device_adr(d) ((d)->pnp.bus_address) -#define acpi_device_hid(d) ((d)->pnp.hardware_id) +char *acpi_device_hid(struct acpi_device *device); #define acpi_device_uid(d) ((d)->pnp.unique_id) #define acpi_device_name(d) ((d)->pnp.device_name) #define acpi_device_class(d) ((d)->pnp.device_class) From b2972f87508a21db7584d11fdb5c97cb7101a788 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 13:35:24 -0600 Subject: [PATCH 22/25] ACPI: remove acpi_device.flags.compatible_ids We now keep a single list of IDs that includes both the _HID and any _CIDs. We no longer need to keep track of whether the device has a _CID. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 15 ++++----------- include/acpi/acpi_bus.h | 3 +-- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2e8889f62666..395ae129aae0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -47,7 +47,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, int count; struct acpi_hardware_id *id; - if (!acpi_dev->flags.hardware_id && !acpi_dev->flags.compatible_ids) + if (!acpi_dev->flags.hardware_id) return -ENODEV; len = snprintf(modalias, size, "acpi:"); @@ -209,7 +209,7 @@ static int acpi_device_setup_files(struct acpi_device *dev) goto end; } - if (dev->flags.hardware_id || dev->flags.compatible_ids) { + if (dev->flags.hardware_id) { result = device_create_file(&dev->dev, &dev_attr_modalias); if (result) goto end; @@ -239,7 +239,7 @@ static void acpi_device_remove_files(struct acpi_device *dev) if (ACPI_SUCCESS(status)) device_remove_file(&dev->dev, &dev_attr_eject); - if (dev->flags.hardware_id || dev->flags.compatible_ids) + if (dev->flags.hardware_id) device_remove_file(&dev->dev, &dev_attr_modalias); if (dev->flags.hardware_id) @@ -876,11 +876,6 @@ static int acpi_bus_get_flags(struct acpi_device *device) if (ACPI_SUCCESS(status)) device->flags.dynamic_status = 1; - /* Presence of _CID indicates 'compatible_ids' */ - status = acpi_get_handle(device->handle, "_CID", &temp); - if (ACPI_SUCCESS(status)) - device->flags.compatible_ids = 1; - /* Presence of _RMV indicates 'removable' */ status = acpi_get_handle(device->handle, "_RMV", &temp); if (ACPI_SUCCESS(status)) @@ -1125,10 +1120,8 @@ static void acpi_device_set_id(struct acpi_device *device) if (cid_list) for (i = 0; i < cid_list->count; i++) acpi_add_id(device, cid_list->ids[i].string); - if (cid_add) { + if (cid_add) acpi_add_id(device, cid_add); - device->flags.compatible_ids = 1; - } kfree(info); } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c2c434626edc..0a970e4ade6f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -142,7 +142,6 @@ struct acpi_device_status { struct acpi_device_flags { u32 dynamic_status:1; u32 hardware_id:1; - u32 compatible_ids:1; u32 bus_address:1; u32 unique_id:1; u32 removable:1; @@ -153,7 +152,7 @@ struct acpi_device_flags { u32 performance_manageable:1; u32 wake_capable:1; /* Wakeup(_PRW) supported? */ u32 force_power_state:1; - u32 reserved:19; + u32 reserved:20; }; /* File System */ From 1131b938f0757350f569f8ad5bee737cd02b8e58 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 13:35:29 -0600 Subject: [PATCH 23/25] ACPI: remove acpi_device.flags.hardware_id Every acpi_device has at least one ID (if there's no _HID or _CID, we give it a synthetic or default ID). So there's no longer a need to check whether an ID exists; we can just use it. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 37 +++++++++++++------------------------ drivers/pnp/pnpacpi/core.c | 3 +-- include/acpi/acpi_bus.h | 3 +-- 3 files changed, 15 insertions(+), 28 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 395ae129aae0..7e031b90c09c 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -47,9 +47,6 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, int count; struct acpi_hardware_id *id; - if (!acpi_dev->flags.hardware_id) - return -ENODEV; - len = snprintf(modalias, size, "acpi:"); size -= len; @@ -203,17 +200,13 @@ static int acpi_device_setup_files(struct acpi_device *dev) goto end; } - if (dev->flags.hardware_id) { - result = device_create_file(&dev->dev, &dev_attr_hid); - if (result) - goto end; - } + result = device_create_file(&dev->dev, &dev_attr_hid); + if (result) + goto end; - if (dev->flags.hardware_id) { - result = device_create_file(&dev->dev, &dev_attr_modalias); - if (result) - goto end; - } + result = device_create_file(&dev->dev, &dev_attr_modalias); + if (result) + goto end; /* * If device has _EJ0, 'eject' file is created that is used to trigger @@ -239,11 +232,8 @@ static void acpi_device_remove_files(struct acpi_device *dev) if (ACPI_SUCCESS(status)) device_remove_file(&dev->dev, &dev_attr_eject); - if (dev->flags.hardware_id) - device_remove_file(&dev->dev, &dev_attr_modalias); - - if (dev->flags.hardware_id) - device_remove_file(&dev->dev, &dev_attr_hid); + device_remove_file(&dev->dev, &dev_attr_modalias); + device_remove_file(&dev->dev, &dev_attr_hid); if (dev->handle) device_remove_file(&dev->dev, &dev_attr_path); } @@ -474,8 +464,9 @@ static int acpi_device_register(struct acpi_device *device) * If failed, create one and link it into acpi_bus_id_list */ list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) { - if (!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id ? acpi_device_hid(device) : "device")) { - acpi_device_bus_id->instance_no ++; + if (!strcmp(acpi_device_bus_id->bus_id, + acpi_device_hid(device))) { + acpi_device_bus_id->instance_no++; found = 1; kfree(new_bus_id); break; @@ -483,7 +474,7 @@ static int acpi_device_register(struct acpi_device *device) } if (!found) { acpi_device_bus_id = new_bus_id; - strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? acpi_device_hid(device) : "device"); + strcpy(acpi_device_bus_id->bus_id, acpi_device_hid(device)); acpi_device_bus_id->instance_no = 0; list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); } @@ -1103,10 +1094,8 @@ static void acpi_device_set_id(struct acpi_device *device) if (!hid && !cid_list && !cid_add) hid = "device"; - if (hid) { + if (hid) acpi_add_id(device, hid); - device->flags.hardware_id = 1; - } if (uid) { device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); if (device->pnp.unique_id) { diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 3a4478f1fc72..83b8b5ac49c9 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -230,8 +230,7 @@ static int __init acpi_pnp_match(struct device *dev, void *_pnp) struct pnp_dev *pnp = _pnp; /* true means it matched */ - return acpi->flags.hardware_id - && !acpi_get_physical_device(acpi->handle) + return !acpi_get_physical_device(acpi->handle) && compare_pnp_id(pnp->id, acpi_device_hid(acpi)); } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 0a970e4ade6f..6599b8cab45a 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -141,7 +141,6 @@ struct acpi_device_status { struct acpi_device_flags { u32 dynamic_status:1; - u32 hardware_id:1; u32 bus_address:1; u32 unique_id:1; u32 removable:1; @@ -152,7 +151,7 @@ struct acpi_device_flags { u32 performance_manageable:1; u32 wake_capable:1; /* Wakeup(_PRW) supported? */ u32 force_power_state:1; - u32 reserved:20; + u32 reserved:21; }; /* File System */ From 6622d8cee73a26bce958484065c8f0e704911a62 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 13:35:35 -0600 Subject: [PATCH 24/25] ACPI: remove acpi_device_uid() and related stuff Nobody uses acpi_device_uid(), so this patch removes it. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 18 ------------------ include/acpi/acpi_bus.h | 4 +--- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7e031b90c09c..da11b5379dc8 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1018,7 +1018,6 @@ static void acpi_device_set_id(struct acpi_device *device) { struct acpi_device_info *info = NULL; char *hid = NULL; - char *uid = NULL; struct acpica_device_id_list *cid_list = NULL; char *cid_add = NULL; acpi_status status; @@ -1045,8 +1044,6 @@ static void acpi_device_set_id(struct acpi_device *device) if (info->valid & ACPI_VALID_HID) hid = info->hardware_id.string; - if (info->valid & ACPI_VALID_UID) - uid = info->unique_id.string; if (info->valid & ACPI_VALID_CID) cid_list = &info->compatible_id_list; if (info->valid & ACPI_VALID_ADR) { @@ -1096,16 +1093,6 @@ static void acpi_device_set_id(struct acpi_device *device) if (hid) acpi_add_id(device, hid); - if (uid) { - device->pnp.unique_id = ACPI_ALLOCATE_ZEROED(strlen (uid) + 1); - if (device->pnp.unique_id) { - strcpy(device->pnp.unique_id, uid); - device->flags.unique_id = 1; - } - } - if (!device->flags.unique_id) - device->pnp.unique_id = ""; - if (cid_list) for (i = 0; i < cid_list->count; i++) acpi_add_id(device, cid_list->ids[i].string); @@ -1200,11 +1187,6 @@ static int acpi_add_single_object(struct acpi_device **child, * ----------------- * TBD: Synch with Core's enumeration/initialization process. */ - - /* - * Hardware ID, Unique ID, & Bus Address - * ------------------------------------- - */ acpi_device_set_id(device); /* diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 6599b8cab45a..3cd9ccdcbd8f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -142,7 +142,6 @@ struct acpi_device_status { struct acpi_device_flags { u32 dynamic_status:1; u32 bus_address:1; - u32 unique_id:1; u32 removable:1; u32 ejectable:1; u32 lockable:1; @@ -151,7 +150,7 @@ struct acpi_device_flags { u32 performance_manageable:1; u32 wake_capable:1; /* Wakeup(_PRW) supported? */ u32 force_power_state:1; - u32 reserved:21; + u32 reserved:22; }; /* File System */ @@ -186,7 +185,6 @@ struct acpi_device_pnp { #define acpi_device_bid(d) ((d)->pnp.bus_id) #define acpi_device_adr(d) ((d)->pnp.bus_address) char *acpi_device_hid(struct acpi_device *device); -#define acpi_device_uid(d) ((d)->pnp.unique_id) #define acpi_device_name(d) ((d)->pnp.device_name) #define acpi_device_class(d) ((d)->pnp.device_class) From 57f3674f5e9c7b1102ae62fc2920d2fa09fce1ea Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Sep 2009 13:35:40 -0600 Subject: [PATCH 25/25] ACPI: simplify building device HID/CID list Minor code cleanup, no functional change. Instead of remembering what HIDs & CIDs to add later, just add them immediately. Signed-off-by: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 56 +++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index da11b5379dc8..468921bed22f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1016,21 +1016,19 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id) static void acpi_device_set_id(struct acpi_device *device) { - struct acpi_device_info *info = NULL; - char *hid = NULL; - struct acpica_device_id_list *cid_list = NULL; - char *cid_add = NULL; acpi_status status; + struct acpi_device_info *info; + struct acpica_device_id_list *cid_list; int i; switch (device->device_type) { case ACPI_BUS_TYPE_DEVICE: if (ACPI_IS_ROOT_DEVICE(device)) { - hid = ACPI_SYSTEM_HID; + acpi_add_id(device, ACPI_SYSTEM_HID); break; } else if (ACPI_IS_ROOT_DEVICE(device->parent)) { /* \_SB_, the only root-level namespace device */ - hid = ACPI_BUS_HID; + acpi_add_id(device, ACPI_BUS_HID); strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); strcpy(device->pnp.device_class, ACPI_BUS_CLASS); break; @@ -1043,41 +1041,43 @@ static void acpi_device_set_id(struct acpi_device *device) } if (info->valid & ACPI_VALID_HID) - hid = info->hardware_id.string; - if (info->valid & ACPI_VALID_CID) + acpi_add_id(device, info->hardware_id.string); + if (info->valid & ACPI_VALID_CID) { cid_list = &info->compatible_id_list; + for (i = 0; i < cid_list->count; i++) + acpi_add_id(device, cid_list->ids[i].string); + } if (info->valid & ACPI_VALID_ADR) { device->pnp.bus_address = info->address; device->flags.bus_address = 1; } - /* If we have a video/bay/dock device, add our selfdefined - HID to the CID list. Like that the video/bay/dock drivers - will get autoloaded and the device might still match - against another driver. - */ + /* + * Some devices don't reliably have _HIDs & _CIDs, so add + * synthetic HIDs to make sure drivers can find them. + */ if (acpi_is_video_device(device)) - cid_add = ACPI_VIDEO_HID; + acpi_add_id(device, ACPI_VIDEO_HID); else if (ACPI_SUCCESS(acpi_bay_match(device))) - cid_add = ACPI_BAY_HID; + acpi_add_id(device, ACPI_BAY_HID); else if (ACPI_SUCCESS(acpi_dock_match(device))) - cid_add = ACPI_DOCK_HID; + acpi_add_id(device, ACPI_DOCK_HID); break; case ACPI_BUS_TYPE_POWER: - hid = ACPI_POWER_HID; + acpi_add_id(device, ACPI_POWER_HID); break; case ACPI_BUS_TYPE_PROCESSOR: - hid = ACPI_PROCESSOR_OBJECT_HID; + acpi_add_id(device, ACPI_PROCESSOR_OBJECT_HID); break; case ACPI_BUS_TYPE_THERMAL: - hid = ACPI_THERMAL_HID; + acpi_add_id(device, ACPI_THERMAL_HID); break; case ACPI_BUS_TYPE_POWER_BUTTON: - hid = ACPI_BUTTON_HID_POWERF; + acpi_add_id(device, ACPI_BUTTON_HID_POWERF); break; case ACPI_BUS_TYPE_SLEEP_BUTTON: - hid = ACPI_BUTTON_HID_SLEEPF; + acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF); break; } @@ -1088,18 +1088,8 @@ static void acpi_device_set_id(struct acpi_device *device) * This generic ID isn't useful for driver binding, but it provides * the useful property that "every acpi_device has an ID." */ - if (!hid && !cid_list && !cid_add) - hid = "device"; - - if (hid) - acpi_add_id(device, hid); - if (cid_list) - for (i = 0; i < cid_list->count; i++) - acpi_add_id(device, cid_list->ids[i].string); - if (cid_add) - acpi_add_id(device, cid_add); - - kfree(info); + if (list_empty(&device->pnp.ids)) + acpi_add_id(device, "device"); } static int acpi_device_set_context(struct acpi_device *device)