ACPI: Add .setup() and .cleanup() callbacks to struct acpi_bus_type
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Sat, 22 Dec 2012 23:02:13 +0000 (00:02 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 3 Jan 2013 12:09:40 +0000 (13:09 +0100)
Add two new callbacks,.setup() and .cleanup(), struct acpi_bus_type
and modify acpi_platform_notify() to call .setup() after executing
acpi_bind_one() successfully and acpi_platform_notify_remove() to
call .cleanup() before running acpi_unbind_one().  This will allow
the users of struct acpi_bus_type, PCI in particular, to specify
operations to be executed right after the given device has been
associated with a companion struct acpi_device and right before
it's going to be detached from that companion, respectively.

The main motivation is to be able to get rid of acpi_pci_bind()
and acpi_pci_unbind(), which are horrible horrible stuff.  [In short,
there are three problems with them: The way they populate the .bind()
and .unbind() callbacks of ACPI devices is rather less than
straightforward, they require special hotplug-specific paths to be
present in the ACPI namespace scanning code and by the time
acpi_pci_unbind() is called the PCI device object in question may
not exist any more.]

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Yinghai Lu <yinghai@kernel.org>
Acked-by: Toshi Kani <toshi.kani@hp.com>
drivers/acpi/glue.c
include/acpi/acpi_bus.h

index 01551840d2365389ae8e0ea3c67054bc8655452f..ac00b882e75def36b030cc4458f8010cbb3e8f24 100644 (file)
@@ -63,6 +63,9 @@ static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
 {
        struct acpi_bus_type *tmp, *ret = NULL;
 
+       if (!type)
+               return NULL;
+
        down_read(&bus_type_sem);
        list_for_each_entry(tmp, &bus_type_list, list) {
                if (tmp->bus == type) {
@@ -264,28 +267,39 @@ static int acpi_platform_notify(struct device *dev)
 {
        struct acpi_bus_type *type;
        acpi_handle handle;
-       int ret = -EINVAL;
+       int ret;
 
        ret = acpi_bind_one(dev, NULL);
-       if (!ret)
-               goto out;
-
-       if (!dev->bus || !dev->parent) {
+       if (ret && (!dev->bus || !dev->parent)) {
                /* bridge devices genernally haven't bus or parent */
                ret = acpi_find_bridge_device(dev, &handle);
-               goto end;
+               if (!ret) {
+                       ret = acpi_bind_one(dev, handle);
+                       if (ret)
+                               goto out;
+               }
        }
+
        type = acpi_get_bus_type(dev->bus);
-       if (!type) {
-               DBG("No ACPI bus support for %s\n", dev_name(dev));
-               ret = -EINVAL;
-               goto end;
+       if (ret) {
+               if (!type || !type->find_device) {
+                       DBG("No ACPI bus support for %s\n", dev_name(dev));
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               ret = type->find_device(dev, &handle);
+               if (ret) {
+                       DBG("Unable to get handle for %s\n", dev_name(dev));
+                       goto out;
+               }
+               ret = acpi_bind_one(dev, handle);
+               if (ret)
+                       goto out;
        }
-       if ((ret = type->find_device(dev, &handle)) != 0)
-               DBG("Can't get handler for %s\n", dev_name(dev));
- end:
-       if (!ret)
-               acpi_bind_one(dev, handle);
+
+       if (type && type->setup)
+               type->setup(dev);
 
  out:
 #if ACPI_GLUE_DEBUG
@@ -304,6 +318,12 @@ static int acpi_platform_notify(struct device *dev)
 
 static int acpi_platform_notify_remove(struct device *dev)
 {
+       struct acpi_bus_type *type;
+
+       type = acpi_get_bus_type(dev->bus);
+       if (type && type->cleanup)
+               type->cleanup(dev);
+
        acpi_unbind_one(dev);
        return 0;
 }
index 5e1d5a1b477fbc4ed0dbee699846a6586bb0bf00..70647313a9bcf7b6e7cdc4fdd4e7f6bc50b76d58 100644 (file)
@@ -383,6 +383,8 @@ struct acpi_bus_type {
        int (*find_device) (struct device *, acpi_handle *);
        /* For bridges, such as PCI root bridge, IDE controller */
        int (*find_bridge) (struct device *, acpi_handle *);
+       void (*setup)(struct device *);
+       void (*cleanup)(struct device *);
 };
 int register_acpi_bus_type(struct acpi_bus_type *);
 int unregister_acpi_bus_type(struct acpi_bus_type *);