ACPI: use acpi_walk_namespace() to enumerate devices
authorBjorn Helgaas <bjorn.helgaas@hp.com>
Mon, 21 Sep 2009 19:29:56 +0000 (19:29 +0000)
committerLen Brown <len.brown@intel.com>
Fri, 25 Sep 2009 18:24:30 +0000 (14:24 -0400)
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 <bjorn.helgaas@hp.com>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/acpi/scan.c

index 0b5aaf059c9b4b14a85f0fe784499063cabc584c..ed2b5f9a9815688779ac6b3bf73b86d4b066da3f 100644 (file)
@@ -1393,123 +1393,92 @@ end:
        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;
 
-       /*
-        * 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;
+       status = acpi_get_type(handle, &type);
+       if (ACPI_FAILURE(status))
+               return AE_OK;
 
        /*
-        * Parse through the ACPI namespace, identify all 'devices', and
-        * create a new 'struct acpi_device' for each.
+        * We're only interested in objects that we consider 'devices'.
         */
-       while ((level > 0) && parent) {
+       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;
+       }
 
-               status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
-                                             chandle, &chandle);
+       if (ops->acpi_op_add)
+               status = acpi_add_single_object(&device, handle, type, ops);
+       else
+               status = acpi_bus_get_device(handle, &device);
 
-               /*
-                * 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;
-               }
+       if (ACPI_FAILURE(status))
+               return AE_CTRL_DEPTH;
 
-               status = acpi_get_type(chandle, &type);
+       if (ops->acpi_op_start && !(ops->acpi_op_add)) {
+               status = acpi_start_single_object(device);
                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;
-               }
+                       return AE_CTRL_DEPTH;
+       }
 
-               /*
-                * 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 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 (ops->acpi_op_add)
-                       status = acpi_add_single_object(&child, chandle, type,
-                                                       ops);
-               else
-                       status = acpi_bus_get_device(chandle, &child);
+       if (!*return_value)
+               *return_value = device;
+       return AE_OK;
+}
 
-               if (ACPI_FAILURE(status))
-                       continue;
+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;
 
-               if (ops->acpi_op_start && !(ops->acpi_op_add)) {
-                       status = acpi_start_single_object(child);
-                       if (ACPI_FAILURE(status))
-                               continue;
-               }
+       acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+       printk(KERN_INFO PREFIX "Enumerating devices from [%s]\n",
+              (char *) buffer.pointer);
 
-               /*
-                * 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;
-                       }
-               }
-       }
+       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;
 }