diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2012-12-22 18:02:13 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-01-03 07:09:40 -0500 |
commit | 11909ca1cf614f9396b17d366f9e3cfcba7b4a99 (patch) | |
tree | 64ac9e3885d22043acd7a29169104126d602ce31 /drivers/acpi/glue.c | |
parent | 0cd6ac52b333f66ee64e50ed216ec99231092dcd (diff) |
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>
Diffstat (limited to 'drivers/acpi/glue.c')
-rw-r--r-- | drivers/acpi/glue.c | 50 |
1 files changed, 35 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) | |||
63 | { | 63 | { |
64 | struct acpi_bus_type *tmp, *ret = NULL; | 64 | struct acpi_bus_type *tmp, *ret = NULL; |
65 | 65 | ||
66 | if (!type) | ||
67 | return NULL; | ||
68 | |||
66 | down_read(&bus_type_sem); | 69 | down_read(&bus_type_sem); |
67 | list_for_each_entry(tmp, &bus_type_list, list) { | 70 | list_for_each_entry(tmp, &bus_type_list, list) { |
68 | if (tmp->bus == type) { | 71 | if (tmp->bus == type) { |
@@ -264,28 +267,39 @@ static int acpi_platform_notify(struct device *dev) | |||
264 | { | 267 | { |
265 | struct acpi_bus_type *type; | 268 | struct acpi_bus_type *type; |
266 | acpi_handle handle; | 269 | acpi_handle handle; |
267 | int ret = -EINVAL; | 270 | int ret; |
268 | 271 | ||
269 | ret = acpi_bind_one(dev, NULL); | 272 | ret = acpi_bind_one(dev, NULL); |
270 | if (!ret) | 273 | if (ret && (!dev->bus || !dev->parent)) { |
271 | goto out; | ||
272 | |||
273 | if (!dev->bus || !dev->parent) { | ||
274 | /* bridge devices genernally haven't bus or parent */ | 274 | /* bridge devices genernally haven't bus or parent */ |
275 | ret = acpi_find_bridge_device(dev, &handle); | 275 | ret = acpi_find_bridge_device(dev, &handle); |
276 | goto end; | 276 | if (!ret) { |
277 | ret = acpi_bind_one(dev, handle); | ||
278 | if (ret) | ||
279 | goto out; | ||
280 | } | ||
277 | } | 281 | } |
282 | |||
278 | type = acpi_get_bus_type(dev->bus); | 283 | type = acpi_get_bus_type(dev->bus); |
279 | if (!type) { | 284 | if (ret) { |
280 | DBG("No ACPI bus support for %s\n", dev_name(dev)); | 285 | if (!type || !type->find_device) { |
281 | ret = -EINVAL; | 286 | DBG("No ACPI bus support for %s\n", dev_name(dev)); |
282 | goto end; | 287 | ret = -EINVAL; |
288 | goto out; | ||
289 | } | ||
290 | |||
291 | ret = type->find_device(dev, &handle); | ||
292 | if (ret) { | ||
293 | DBG("Unable to get handle for %s\n", dev_name(dev)); | ||
294 | goto out; | ||
295 | } | ||
296 | ret = acpi_bind_one(dev, handle); | ||
297 | if (ret) | ||
298 | goto out; | ||
283 | } | 299 | } |
284 | if ((ret = type->find_device(dev, &handle)) != 0) | 300 | |
285 | DBG("Can't get handler for %s\n", dev_name(dev)); | 301 | if (type && type->setup) |
286 | end: | 302 | type->setup(dev); |
287 | if (!ret) | ||
288 | acpi_bind_one(dev, handle); | ||
289 | 303 | ||
290 | out: | 304 | out: |
291 | #if ACPI_GLUE_DEBUG | 305 | #if ACPI_GLUE_DEBUG |
@@ -304,6 +318,12 @@ static int acpi_platform_notify(struct device *dev) | |||
304 | 318 | ||
305 | static int acpi_platform_notify_remove(struct device *dev) | 319 | static int acpi_platform_notify_remove(struct device *dev) |
306 | { | 320 | { |
321 | struct acpi_bus_type *type; | ||
322 | |||
323 | type = acpi_get_bus_type(dev->bus); | ||
324 | if (type && type->cleanup) | ||
325 | type->cleanup(dev); | ||
326 | |||
307 | acpi_unbind_one(dev); | 327 | acpi_unbind_one(dev); |
308 | return 0; | 328 | return 0; |
309 | } | 329 | } |