diff options
Diffstat (limited to 'drivers/acpi/acpica/nswalk.c')
| -rw-r--r-- | drivers/acpi/acpica/nswalk.c | 272 |
1 files changed, 167 insertions, 105 deletions
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 83e3aa6d4b9..4758a1f2ce2 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2008, Intel Corp. + * Copyright (C) 2000 - 2014, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,8 +52,7 @@ ACPI_MODULE_NAME("nswalk") * * FUNCTION: acpi_ns_get_next_node * - * PARAMETERS: Type - Type of node to be searched for - * parent_node - Parent node whose children we are + * PARAMETERS: parent_node - Parent node whose children we are * getting * child_node - Previous child that was found. * The NEXT child will be returned @@ -61,31 +60,63 @@ ACPI_MODULE_NAME("nswalk") * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if * none is found. * - * DESCRIPTION: Return the next peer node within the namespace. If Handle - * is valid, Scope is ignored. Otherwise, the first node + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node * within Scope is returned. * ******************************************************************************/ -struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node - *parent_node, struct acpi_namespace_node +struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node + *parent_node, + struct acpi_namespace_node *child_node) { - struct acpi_namespace_node *next_node = NULL; - ACPI_FUNCTION_ENTRY(); if (!child_node) { /* It's really the parent's _scope_ that we want */ - next_node = parent_node->child; + return (parent_node->child); } - else { - /* Start search at the NEXT node */ + /* Otherwise just return the next peer */ + + return (child_node->peer); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_next_node_typed + * + * PARAMETERS: type - Type of node to be searched for + * parent_node - Parent node whose children we are + * getting + * child_node - Previous child that was found. + * The NEXT child will be returned + * + * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if + * none is found. + * + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node + * within Scope is returned. + * + ******************************************************************************/ + +struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, + struct + acpi_namespace_node + *parent_node, + struct + acpi_namespace_node + *child_node) +{ + struct acpi_namespace_node *next_node = NULL; + + ACPI_FUNCTION_ENTRY(); + + next_node = acpi_ns_get_next_node(parent_node, child_node); - next_node = acpi_ns_get_next_valid_node(child_node); - } /* If any type is OK, we are done */ @@ -106,9 +137,9 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct return (next_node); } - /* Otherwise, move on to the next node */ + /* Otherwise, move on to the next peer node */ - next_node = acpi_ns_get_next_valid_node(next_node); + next_node = next_node->peer; } /* Not found */ @@ -120,29 +151,32 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct * * FUNCTION: acpi_ns_walk_namespace * - * PARAMETERS: Type - acpi_object_type to search for + * PARAMETERS: type - acpi_object_type to search for * start_node - Handle in namespace where search begins * max_depth - Depth to which search is to reach - * Flags - Whether to unlock the NS before invoking + * 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 - * return_value - from the user_function if terminated early. - * Otherwise, returns NULL. + * descending_callback - Called during tree descent + * when an object of "Type" is found + * ascending_callback - Called during tree ascent + * when an object of "Type" is found + * context - Passed to user function(s) above + * return_value - from the user_function if terminated + * early. Otherwise, returns NULL. * RETURNS: Status * * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, * starting (and ending) at the node specified by start_handle. - * The user_function is called whenever a node that matches - * the type parameter is found. If the user function returns + * The callback function is called whenever a node that matches + * the type parameter is found. If the callback function returns * a non-zero value, the search is terminated immediately and * this value is returned to the caller. * * The point of this procedure is to provide a generic namespace * walk routine that can be called from multiple places to - * provide multiple services; the User Function can be tailored - * to each task, whether it is a print function, a compare - * function, etc. + * provide multiple services; the callback function(s) can be + * tailored to each task, whether it is a print function, + * a compare function, etc. * ******************************************************************************/ @@ -151,7 +185,8 @@ acpi_ns_walk_namespace(acpi_object_type type, acpi_handle start_node, u32 max_depth, u32 flags, - acpi_walk_callback user_function, + acpi_walk_callback descending_callback, + acpi_walk_callback ascending_callback, void *context, void **return_value) { acpi_status status; @@ -160,6 +195,7 @@ acpi_ns_walk_namespace(acpi_object_type type, struct acpi_namespace_node *parent_node; acpi_object_type child_type; u32 level; + u8 node_previously_visited = FALSE; ACPI_FUNCTION_TRACE(ns_walk_namespace); @@ -172,7 +208,7 @@ acpi_ns_walk_namespace(acpi_object_type type, /* Null child means "get first node" */ parent_node = start_node; - child_node = NULL; + child_node = acpi_ns_get_next_node(parent_node, NULL); child_type = ACPI_TYPE_ANY; level = 1; @@ -181,112 +217,138 @@ acpi_ns_walk_namespace(acpi_object_type type, * started. When Level is zero, the loop is done because we have * bubbled up to (and passed) the original parent handle (start_entry) */ - while (level > 0) { + while (level > 0 && child_node) { + status = AE_OK; - /* Get the next node in this scope. Null if not found */ + /* Found next child, get the type if we are not searching for ANY */ - status = AE_OK; - child_node = - acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, - child_node); - if (child_node) { + if (type != ACPI_TYPE_ANY) { + child_type = child_node->type; + } - /* Found next child, get the type if we are not searching for ANY */ + /* + * Ignore all temporary namespace nodes (created during control + * method execution) unless told otherwise. These temporary nodes + * can cause a race condition because they can be deleted during + * the execution of the user function (if the namespace is + * unlocked before invocation of the user function.) Only the + * debugger namespace dump will examine the temporary nodes. + */ + if ((child_node->flags & ANOBJ_TEMPORARY) && + !(flags & ACPI_NS_WALK_TEMP_NODES)) { + status = AE_CTRL_DEPTH; + } - if (type != ACPI_TYPE_ANY) { - child_type = child_node->type; - } + /* Type must match requested type */ + else if (child_type == type) { /* - * Ignore all temporary namespace nodes (created during control - * method execution) unless told otherwise. These temporary nodes - * can cause a race condition because they can be deleted during - * the execution of the user function (if the namespace is - * unlocked before invocation of the user function.) Only the - * debugger namespace dump will examine the temporary nodes. + * Found a matching node, invoke the user callback function. + * Unlock the namespace if flag is set. */ - if ((child_node->flags & ANOBJ_TEMPORARY) && - !(flags & ACPI_NS_WALK_TEMP_NODES)) { - status = AE_CTRL_DEPTH; + if (flags & ACPI_NS_WALK_UNLOCK) { + mutex_status = + acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(mutex_status)) { + return_ACPI_STATUS(mutex_status); + } } - /* Type must match requested type */ - - else if (child_type == type) { - /* - * Found a matching node, invoke the user callback function. - * Unlock the namespace if flag is set. - */ - if (flags & ACPI_NS_WALK_UNLOCK) { - mutex_status = - acpi_ut_release_mutex - (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(mutex_status)) { - return_ACPI_STATUS - (mutex_status); - } + /* + * Invoke the user function, either descending, ascending, + * or both. + */ + if (!node_previously_visited) { + if (descending_callback) { + status = + descending_callback(child_node, + level, context, + return_value); + } + } else { + if (ascending_callback) { + status = + ascending_callback(child_node, + level, context, + return_value); } + } - status = - user_function(child_node, level, context, - return_value); - - if (flags & ACPI_NS_WALK_UNLOCK) { - mutex_status = - acpi_ut_acquire_mutex - (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(mutex_status)) { - return_ACPI_STATUS - (mutex_status); - } + if (flags & ACPI_NS_WALK_UNLOCK) { + mutex_status = + acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(mutex_status)) { + return_ACPI_STATUS(mutex_status); } + } - switch (status) { - case AE_OK: - case AE_CTRL_DEPTH: + switch (status) { + case AE_OK: + case AE_CTRL_DEPTH: - /* Just keep going */ - break; + /* Just keep going */ + break; - case AE_CTRL_TERMINATE: + case AE_CTRL_TERMINATE: - /* Exit now, with OK status */ + /* Exit now, with OK status */ - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(AE_OK); - default: + default: - /* All others are valid exceptions */ + /* All others are valid exceptions */ - return_ACPI_STATUS(status); - } + return_ACPI_STATUS(status); } + } - /* - * Depth first search: Attempt to go down another level in the - * namespace if we are allowed to. Don't go any further if we have - * reached the caller specified maximum depth or if the user - * function has specified that the maximum depth has been reached. - */ - if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { - if (acpi_ns_get_next_node - (ACPI_TYPE_ANY, child_node, NULL)) { + /* + * Depth first search: Attempt to go down another level in the + * namespace if we are allowed to. Don't go any further if we have + * reached the caller specified maximum depth or if the user + * function has specified that the maximum depth has been reached. + */ + if (!node_previously_visited && + (level < max_depth) && (status != AE_CTRL_DEPTH)) { + if (child_node->child) { + + /* There is at least one child of this node, visit it */ + + level++; + parent_node = child_node; + child_node = + acpi_ns_get_next_node(parent_node, NULL); + continue; + } + } - /* There is at least one child of this node, visit it */ + /* No more children, re-visit this node */ - level++; - parent_node = child_node; - child_node = NULL; - } - } - } else { + if (!node_previously_visited) { + node_previously_visited = TRUE; + continue; + } + + /* No more children, visit peers */ + + child_node = acpi_ns_get_next_node(parent_node, child_node); + if (child_node) { + node_previously_visited = FALSE; + } + + /* No peers, re-visit parent */ + + 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. */ level--; child_node = parent_node; - parent_node = acpi_ns_get_parent_node(parent_node); + parent_node = parent_node->parent; + + node_previously_visited = TRUE; } } |
