We need to handle device addition in preorder (so we add a new device before any children), but device removal in postorder (so we remove any children before removing the parent). The callback from AcpiWalkNamespace() is done in preorder. This patch adds a new AcpiWalkNamespace2() that takes both preorder and a postorder callbacks. This patch may be used under either the GPL v2 or the BSD-style license used for the Intel ACPICA. Signed-off-by: Bjorn Helgaas <bjorn.helgaas@xxxxxx> --- drivers/acpi/acpica/acnamesp.h | 9 +++ drivers/acpi/acpica/nswalk.c | 106 ++++++++++++++++++++++++++++++++++++---- drivers/acpi/acpica/nsxfeval.c | 41 +++++++++++---- include/acpi/acpixf.h | 8 +++ 4 files changed, 141 insertions(+), 23 deletions(-) diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 94cdc2b..cb3a34f 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -99,6 +99,15 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_walk_callback user_function, void *context, void **return_value); +acpi_status +acpi_ns_walk_namespace2(acpi_object_type type, + acpi_handle start_object, + u32 max_depth, + u32 flags, + acpi_walk_callback pre_user_function, + acpi_walk_callback post_user_function, + void *context, void **return_value); + struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node *parent, struct acpi_namespace_node diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 572a181..4b01550 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -168,6 +168,10 @@ acpi_call_user_function(acpi_object_type type, acpi_status status; acpi_status mutex_status; + if (!user_function) { + return (AE_OK); + } + /* * Ignore all temporary namespace nodes (created during control * method execution) unless told otherwise. These temporary nodes @@ -219,8 +223,11 @@ acpi_call_user_function(acpi_object_type type, * max_depth - Depth to which search is to reach * Flags - Whether to unlock the NS before invoking * the callback routine - * user_function - Called when an object of "Type" is found - * Context - Passed to user function + * pre_user_function - Called in preorder when an object of + * "Type" is found + * post_user_function - Called in postorder when an object of + * "Type" is found + * Context - Passed to user functions * return_value - from the user_function if terminated early. * Otherwise, returns NULL. * RETURNS: Status @@ -241,12 +248,13 @@ acpi_call_user_function(acpi_object_type type, ******************************************************************************/ acpi_status -acpi_ns_walk_namespace(acpi_object_type type, - acpi_handle start_node, - u32 max_depth, - u32 flags, - acpi_walk_callback user_function, - void *context, void **return_value) +acpi_ns_walk_namespace2(acpi_object_type type, + acpi_handle start_node, + u32 max_depth, + u32 flags, + acpi_walk_callback pre_user_function, + acpi_walk_callback post_user_function, + void *context, void **return_value) { acpi_status status; struct acpi_namespace_node *child_node; @@ -283,7 +291,7 @@ acpi_ns_walk_namespace(acpi_object_type type, if (child_node) { status = acpi_call_user_function(type, flags, - user_function, child_node, level, + pre_user_function, child_node, level, context, return_value); switch (status) { @@ -320,16 +328,79 @@ acpi_ns_walk_namespace(acpi_object_type type, level++; parent_node = child_node; child_node = NULL; + } else { + + /* + * This node has no children, so visit + * it in postorder before going back + * upwards. + */ + + status = acpi_call_user_function(type, flags, + post_user_function, child_node, level, + context, return_value); + + switch (status) { + case AE_OK: + case AE_CTRL_DEPTH: + + /* Just keep going */ + break; + + case AE_CTRL_TERMINATE: + + /* Exit now, with OK status */ + + return_ACPI_STATUS(AE_OK); + + default: + + /* All others are valid exceptions */ + + return_ACPI_STATUS(status); + } } } } else { /* - * No more children of this node (acpi_ns_get_next_node failed), go - * back upwards in the namespace tree to the node's parent. + * No more children of this node (acpi_ns_get_next_node failed), + * call the postorder user function and go back upwards in the + * namespace tree to the node's parent. */ level--; child_node = parent_node; parent_node = acpi_ns_get_parent_node(parent_node); + + /* + * We don't visit the starting node in preorder, so + * don't visit it in postorder either. + */ + + if (level > 0) { + status = acpi_call_user_function(type, flags, + post_user_function, child_node, level, + context, return_value); + + switch (status) { + case AE_OK: + case AE_CTRL_DEPTH: + + /* Just keep going */ + break; + + case AE_CTRL_TERMINATE: + + /* Exit now, with OK status */ + + return_ACPI_STATUS(AE_OK); + + default: + + /* All others are valid exceptions */ + + return_ACPI_STATUS(status); + } + } } } @@ -337,3 +408,16 @@ acpi_ns_walk_namespace(acpi_object_type type, return_ACPI_STATUS(AE_OK); } + +acpi_status +acpi_ns_walk_namespace(acpi_object_type type, + acpi_handle start_node, + u32 max_depth, + u32 flags, + acpi_walk_callback user_function, + void *context, void **return_value) +{ + return acpi_ns_walk_namespace2(type, start_node, max_depth, flags, + user_function, NULL, + context, return_value); +} diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index daf4ad3..2cc5ce4 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -428,13 +428,16 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info) /******************************************************************************* * - * FUNCTION: acpi_walk_namespace + * FUNCTION: acpi_walk_namespace2 * * PARAMETERS: Type - acpi_object_type to search for * start_object - Handle in namespace where search begins * max_depth - Depth to which search is to reach - * user_function - Called when an object of "Type" is found - * Context - Passed to user function + * pre_user_function - Called in preorder when an object of + * "Type" is found + * post_user_function - Called in postorder when an object of + * "Type" is found + * Context - Passed to user functions * return_value - Location where return value of * user_function is put if terminated early * @@ -457,11 +460,12 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info) ******************************************************************************/ acpi_status -acpi_walk_namespace(acpi_object_type type, - acpi_handle start_object, - u32 max_depth, - acpi_walk_callback user_function, - void *context, void **return_value) +acpi_walk_namespace2(acpi_object_type type, + acpi_handle start_object, + u32 max_depth, + acpi_walk_callback pre_user_function, + acpi_walk_callback post_user_function, + void *context, void **return_value) { acpi_status status; @@ -469,7 +473,8 @@ acpi_walk_namespace(acpi_object_type type, /* Parameter validation */ - if ((type > ACPI_TYPE_LOCAL_MAX) || (!max_depth) || (!user_function)) { + if ((type > ACPI_TYPE_LOCAL_MAX) || (!max_depth) || + ((!pre_user_function) && (!post_user_function))) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -500,9 +505,10 @@ acpi_walk_namespace(acpi_object_type type, goto unlock_and_exit; } - status = acpi_ns_walk_namespace(type, start_object, max_depth, - ACPI_NS_WALK_UNLOCK, user_function, - context, return_value); + status = acpi_ns_walk_namespace2(type, start_object, max_depth, + ACPI_NS_WALK_UNLOCK, pre_user_function, + post_user_function, + context, return_value); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); @@ -511,6 +517,17 @@ acpi_walk_namespace(acpi_object_type type, return_ACPI_STATUS(status); } +acpi_status +acpi_walk_namespace(acpi_object_type type, + acpi_handle start_object, + u32 max_depth, + acpi_walk_callback user_function, + void *context, void **return_value) +{ + return acpi_walk_namespace2(type, start_object, max_depth, + user_function, NULL, context, return_value); +} + ACPI_EXPORT_SYMBOL(acpi_walk_namespace) /******************************************************************************* diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 82ec6a3..8404879 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -157,6 +157,14 @@ acpi_walk_namespace(acpi_object_type type, void *context, void **return_value); acpi_status +acpi_walk_namespace2(acpi_object_type type, + acpi_handle start_object, + u32 max_depth, + acpi_walk_callback pre_user_function, + acpi_walk_callback post_user_function, + void *context, void **return_value); + +acpi_status acpi_get_devices(const char *HID, acpi_walk_callback user_function, void *context, void **return_value); -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html