aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-12-22 18:02:13 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-03 07:09:40 -0500
commit11909ca1cf614f9396b17d366f9e3cfcba7b4a99 (patch)
tree64ac9e3885d22043acd7a29169104126d602ce31
parent0cd6ac52b333f66ee64e50ed216ec99231092dcd (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>
-rw-r--r--drivers/acpi/glue.c50
-rw-r--r--include/acpi/acpi_bus.h2
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)
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
305static int acpi_platform_notify_remove(struct device *dev) 319static 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}
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 {
383 int (*find_device) (struct device *, acpi_handle *); 383 int (*find_device) (struct device *, acpi_handle *);
384 /* For bridges, such as PCI root bridge, IDE controller */ 384 /* For bridges, such as PCI root bridge, IDE controller */
385 int (*find_bridge) (struct device *, acpi_handle *); 385 int (*find_bridge) (struct device *, acpi_handle *);
386 void (*setup)(struct device *);
387 void (*cleanup)(struct device *);
386}; 388};
387int register_acpi_bus_type(struct acpi_bus_type *); 389int register_acpi_bus_type(struct acpi_bus_type *);
388int unregister_acpi_bus_type(struct acpi_bus_type *); 390int unregister_acpi_bus_type(struct acpi_bus_type *);