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: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
2d984ad132
commit
9cb32acf09
3 changed files with 19 additions and 4 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue