diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2012-12-23 03:02:13 +0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-01-03 16:09:40 +0400 |
commit | 11909ca1cf614f9396b17d366f9e3cfcba7b4a99 (patch) | |
tree | 64ac9e3885d22043acd7a29169104126d602ce31 | |
parent | 0cd6ac52b333f66ee64e50ed216ec99231092dcd (diff) | |
download | linux-11909ca1cf614f9396b17d366f9e3cfcba7b4a99.tar.xz |
ACPI: Add .setup() and .cleanup() callbacks to struct acpi_bus_type
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>
-rw-r--r-- | drivers/acpi/glue.c | 50 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 2 |
2 files changed, 37 insertions, 15 deletions
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 01551840d236..ac00b882e75d 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -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; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 5e1d5a1b477f..70647313a9bc 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -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 *); |