Commit 9cb32acf authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

ACPI / scan: Add bind/unbind callbacks to struct acpi_scan_handler

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: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 2d984ad1
...@@ -287,6 +287,7 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one); ...@@ -287,6 +287,7 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one);
static int acpi_platform_notify(struct device *dev) static int acpi_platform_notify(struct device *dev)
{ {
struct acpi_bus_type *type = acpi_get_bus_type(dev); struct acpi_bus_type *type = acpi_get_bus_type(dev);
struct acpi_device *adev;
int ret; int ret;
ret = acpi_bind_one(dev, NULL); ret = acpi_bind_one(dev, NULL);
...@@ -303,9 +304,14 @@ static int acpi_platform_notify(struct device *dev) ...@@ -303,9 +304,14 @@ static int acpi_platform_notify(struct device *dev)
if (ret) if (ret)
goto out; goto out;
} }
adev = ACPI_COMPANION(dev);
if (!adev)
goto out;
if (type && type->setup) if (type && type->setup)
type->setup(dev); type->setup(dev);
else if (adev->handler && adev->handler->bind)
adev->handler->bind(dev);
out: out:
#if ACPI_GLUE_DEBUG #if ACPI_GLUE_DEBUG
...@@ -324,11 +330,17 @@ static int acpi_platform_notify(struct device *dev) ...@@ -324,11 +330,17 @@ static int acpi_platform_notify(struct device *dev)
static int acpi_platform_notify_remove(struct device *dev) static int acpi_platform_notify_remove(struct device *dev)
{ {
struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_bus_type *type; struct acpi_bus_type *type;
if (!adev)
return 0;
type = acpi_get_bus_type(dev); type = acpi_get_bus_type(dev);
if (type && type->cleanup) if (type && type->cleanup)
type->cleanup(dev); type->cleanup(dev);
else if (adev->handler && adev->handler->unbind)
adev->handler->unbind(dev);
acpi_unbind_one(dev); acpi_unbind_one(dev);
return 0; return 0;
......
...@@ -2015,15 +2015,16 @@ static int acpi_scan_attach_handler(struct acpi_device *device) ...@@ -2015,15 +2015,16 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
handler = acpi_scan_match_handler(hwid->id, &devid); handler = acpi_scan_match_handler(hwid->id, &devid);
if (handler) { if (handler) {
ret = handler->attach(device, devid);
if (ret > 0) {
device->handler = handler; device->handler = handler;
ret = handler->attach(device, devid);
if (ret > 0)
break; break;
} else if (ret < 0) {
device->handler = NULL;
if (ret < 0)
break; break;
} }
} }
}
return ret; return ret;
} }
......
...@@ -133,6 +133,8 @@ struct acpi_scan_handler { ...@@ -133,6 +133,8 @@ struct acpi_scan_handler {
struct list_head list_node; struct list_head list_node;
int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id); int (*attach)(struct acpi_device *dev, const struct acpi_device_id *id);
void (*detach)(struct acpi_device *dev); void (*detach)(struct acpi_device *dev);
void (*bind)(struct device *phys_dev);
void (*unbind)(struct device *phys_dev);
struct acpi_hotplug_profile hotplug; struct acpi_hotplug_profile hotplug;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment