aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/scan.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-15 07:24:13 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-15 07:24:13 -0500
commit05404d8f7b5c831e1a2c24bb782f0fe8ea02354c (patch)
tree907c9119308d98ed919b21339bf399ade8dbf591 /drivers/acpi/scan.c
parentcecdb193c8d91a42d9489d00618cc3dfff92e55a (diff)
ACPI / scan: Add second pass to acpi_bus_trim()
Make acpi_bus_trim() work in analogy with acpi_bus_scan() and carry out two passes such that ACPI drivers will be detached from device nodes being removed in the first pass and the device nodes themselves will be removed in the second pass. For this purpose split the driver unregistration out of acpi_bus_remove() into a new routine, acpi_bus_device_detach(), that will be executed by acpi_bus_trim() in the additional first pass as a post-order callback. This is necessary, because some ACPI drivers' .remove() routines unregister struct device objects associated with the ACPI device nodes being removed and that needs to happen while the ACPI device nodes are still around (for example, in case they need to be used for power management or similar things at that time). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Toshi Kani <toshi.kani@hp.com> Acked-by: Yinghai Lu <yinghai@kernel.org> Acked-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r--drivers/acpi/scan.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1ee62bd25828..d04d0b33656c 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1374,22 +1374,6 @@ static int acpi_device_set_context(struct acpi_device *device)
1374 return -ENODEV; 1374 return -ENODEV;
1375} 1375}
1376 1376
1377static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
1378 void *not_used, void **ret_not_used)
1379{
1380 struct acpi_device *dev = NULL;
1381
1382 if (acpi_bus_get_device(handle, &dev))
1383 return AE_OK;
1384
1385 dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
1386 device_release_driver(&dev->dev);
1387
1388 acpi_device_unregister(dev);
1389
1390 return AE_OK;
1391}
1392
1393static int acpi_add_single_object(struct acpi_device **child, 1377static int acpi_add_single_object(struct acpi_device **child,
1394 acpi_handle handle, int type, 1378 acpi_handle handle, int type,
1395 unsigned long long sta, bool match_driver) 1379 unsigned long long sta, bool match_driver)
@@ -1642,9 +1626,39 @@ int acpi_bus_add(acpi_handle handle)
1642} 1626}
1643EXPORT_SYMBOL(acpi_bus_add); 1627EXPORT_SYMBOL(acpi_bus_add);
1644 1628
1629static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
1630 void *not_used, void **ret_not_used)
1631{
1632 struct acpi_device *device = NULL;
1633
1634 if (!acpi_bus_get_device(handle, &device)) {
1635 device->removal_type = ACPI_BUS_REMOVAL_EJECT;
1636 device_release_driver(&device->dev);
1637 }
1638 return AE_OK;
1639}
1640
1641static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
1642 void *not_used, void **ret_not_used)
1643{
1644 struct acpi_device *device = NULL;
1645
1646 if (!acpi_bus_get_device(handle, &device))
1647 acpi_device_unregister(device);
1648
1649 return AE_OK;
1650}
1651
1645int acpi_bus_trim(struct acpi_device *start) 1652int acpi_bus_trim(struct acpi_device *start)
1646{ 1653{
1647 /* 1654 /*
1655 * Execute acpi_bus_device_detach() as a post-order callback to detach
1656 * all ACPI drivers from the device nodes being removed.
1657 */
1658 acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
1659 acpi_bus_device_detach, NULL, NULL);
1660 acpi_bus_device_detach(start->handle, 0, NULL, NULL);
1661 /*
1648 * Execute acpi_bus_remove() as a post-order callback to remove device 1662 * Execute acpi_bus_remove() as a post-order callback to remove device
1649 * nodes in the given namespace scope. 1663 * nodes in the given namespace scope.
1650 */ 1664 */