ACPI / scan: Change the implementation of acpi_bus_trim()

The current acpi_bus_trim() implementation is not really
straightforward and may be simplified significantly by using
acpi_walk_namespace() with acpi_bus_remove() as a post-order
callback.

Observe that acpi_bus_remove(), as called by acpi_bus_trim(), cannot
actually fail, because its first argument is guaranteed not to be
NULL thanks to the acpi_bus_get_device() check in acpi_bus_trim(),
so simply move the acpi_bus_get_device() check to acpi_bus_remove()
and use acpi_walk_namespace() to execute it for every device under
start->handle as a post-order callback.  The, run it directly for
start->handle itself.

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>
This commit is contained in:
Rafael J. Wysocki 2013-01-15 13:24:02 +01:00
parent ae281795ec
commit cecdb193c8

View file

@ -1374,17 +1374,20 @@ static int acpi_device_set_context(struct acpi_device *device)
return -ENODEV;
}
static int acpi_bus_remove(struct acpi_device *dev)
static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **ret_not_used)
{
if (!dev)
return -EINVAL;
struct acpi_device *dev = NULL;
if (acpi_bus_get_device(handle, &dev))
return AE_OK;
dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
device_release_driver(&dev->dev);
acpi_device_unregister(dev);
return 0;
return AE_OK;
}
static int acpi_add_single_object(struct acpi_device **child,
@ -1641,51 +1644,14 @@ EXPORT_SYMBOL(acpi_bus_add);
int acpi_bus_trim(struct acpi_device *start)
{
acpi_status status;
struct acpi_device *parent, *child;
acpi_handle phandle, chandle;
acpi_object_type type;
u32 level = 1;
int err = 0;
parent = start;
phandle = start->handle;
child = chandle = NULL;
while ((level > 0) && parent && (!err)) {
status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
chandle, &chandle);
/*
* If this scope is exhausted then move our way back up.
*/
if (ACPI_FAILURE(status)) {
level--;
chandle = phandle;
acpi_get_parent(phandle, &phandle);
child = parent;
parent = parent->parent;
err = acpi_bus_remove(child);
continue;
}
status = acpi_get_type(chandle, &type);
if (ACPI_FAILURE(status)) {
continue;
}
/*
* If there is a device corresponding to chandle then
* parse it (depth-first).
*/
if (acpi_bus_get_device(chandle, &child) == 0) {
level++;
phandle = chandle;
chandle = NULL;
parent = child;
}
continue;
}
return err;
/*
* Execute acpi_bus_remove() as a post-order callback to remove device
* nodes in the given namespace scope.
*/
acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
acpi_bus_remove, NULL, NULL);
acpi_bus_remove(start->handle, 0, NULL, NULL);
return 0;
}
EXPORT_SYMBOL_GPL(acpi_bus_trim);