ACPI / scan: Add bind/unbind callbacks to struct acpi_scan_handler
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 10 Feb 2014 23:35:46 +0000 (00:35 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 10 Feb 2014 23:35:46 +0000 (00:35 +0100)
In some cases it may be necessary to perform certain setup/cleanup
operations on a device object representing a physical device after
it has been associated with an ACPI companion by acpi_bind_one() or
before disassociating it from that companion by acpi_unbind_one(),
respectively.  If there is a struct acpi_bus_type object for the
given device's bus type, the .setup()/.cleanup() callbacks from there
are executed for these purposes.  However, an analogous mechanism will
be necessary for devices whose bus types don't have corresponding
struct acpi_bus_type objects and that have specific ACPI scan handlers.

For those devices, add new .bind() and .unbind() callbacks to struct
acpi_scan_handler that will be executed by acpi_platform_notify()
right after the given device has been associated with an ACPI
comapnion and by acpi_platform_notify_remove() right before calling
acpi_unbind_one() for that device, respectively.

To make that work for scan handlers registering new devices in their
.attach() callbacks, modify acpi_scan_attach_handler() to set the
ACPI device object's handler field before calling .attach() from the
scan handler at hand.

This changeset includes a fix from Mika Westerberg.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/glue.c
drivers/acpi/scan.c
include/acpi/acpi_bus.h

index 0c789224d40d4da34aa3c7f1a9314bb12ba7b459..f774c65ecb8bb03065ba406e658710aead5d02c0 100644 (file)
@@ -287,6 +287,7 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one);
 static int acpi_platform_notify(struct device *dev)
 {
        struct acpi_bus_type *type = acpi_get_bus_type(dev);
+       struct acpi_device *adev;
        int ret;
 
        ret = acpi_bind_one(dev, NULL);
@@ -303,9 +304,14 @@ static int acpi_platform_notify(struct device *dev)
                if (ret)
                        goto out;
        }
+       adev = ACPI_COMPANION(dev);
+       if (!adev)
+               goto out;
 
        if (type && type->setup)
                type->setup(dev);
+       else if (adev->handler && adev->handler->bind)
+               adev->handler->bind(dev);
 
  out:
 #if ACPI_GLUE_DEBUG
@@ -324,11 +330,17 @@ static int acpi_platform_notify(struct device *dev)
 
 static int acpi_platform_notify_remove(struct device *dev)
 {
+       struct acpi_device *adev = ACPI_COMPANION(dev);
        struct acpi_bus_type *type;
 
+       if (!adev)
+               return 0;
+
        type = acpi_get_bus_type(dev);
        if (type && type->cleanup)
                type->cleanup(dev);
+       else if (adev->handler && adev->handler->unbind)
+               adev->handler->unbind(dev);
 
        acpi_unbind_one(dev);
        return 0;
index 57b053f424d13e23ef2dd4b43a191c0d9dda09da..9c4581fd5827afdc3925abc153ab4a239955414c 100644 (file)
@@ -2015,13 +2015,14 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
 
                handler = acpi_scan_match_handler(hwid->id, &devid);
                if (handler) {
+                       device->handler = handler;
                        ret = handler->attach(device, devid);
-                       if (ret > 0) {
-                               device->handler = handler;
+                       if (ret > 0)
                                break;
-                       } else if (ret < 0) {
+
+                       device->handler = NULL;
+                       if (ret < 0)
                                break;
-                       }
                }
        }
        return ret;
index 8256eb4ad0579be822efd37e22193fa4fdffefdb..c93bce469492d7c9f5f0b4474ec9cfd749a85b5f 100644 (file)
@@ -133,6 +133,8 @@ struct acpi_scan_handler {
        struct list_head list_node;
        int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
        void (*detach)(struct acpi_device *dev);
+       void (*bind)(struct device *phys_dev);
+       void (*unbind)(struct device *phys_dev);
        struct acpi_hotplug_profile hotplug;
 };
 
This page took 0.035488 seconds and 5 git commands to generate.