195b482a8SLen Brown /****************************************************************************** 295b482a8SLen Brown * 395b482a8SLen Brown * Module Name: nswalk - Functions for walking the ACPI namespace 495b482a8SLen Brown * 595b482a8SLen Brown *****************************************************************************/ 695b482a8SLen Brown 795b482a8SLen Brown /* 895b482a8SLen Brown * Copyright (C) 2000 - 2008, Intel Corp. 995b482a8SLen Brown * All rights reserved. 1095b482a8SLen Brown * 1195b482a8SLen Brown * Redistribution and use in source and binary forms, with or without 1295b482a8SLen Brown * modification, are permitted provided that the following conditions 1395b482a8SLen Brown * are met: 1495b482a8SLen Brown * 1. Redistributions of source code must retain the above copyright 1595b482a8SLen Brown * notice, this list of conditions, and the following disclaimer, 1695b482a8SLen Brown * without modification. 1795b482a8SLen Brown * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1895b482a8SLen Brown * substantially similar to the "NO WARRANTY" disclaimer below 1995b482a8SLen Brown * ("Disclaimer") and any redistribution must be conditioned upon 2095b482a8SLen Brown * including a substantially similar Disclaimer requirement for further 2195b482a8SLen Brown * binary redistribution. 2295b482a8SLen Brown * 3. Neither the names of the above-listed copyright holders nor the names 2395b482a8SLen Brown * of any contributors may be used to endorse or promote products derived 2495b482a8SLen Brown * from this software without specific prior written permission. 2595b482a8SLen Brown * 2695b482a8SLen Brown * Alternatively, this software may be distributed under the terms of the 2795b482a8SLen Brown * GNU General Public License ("GPL") version 2 as published by the Free 2895b482a8SLen Brown * Software Foundation. 2995b482a8SLen Brown * 3095b482a8SLen Brown * NO WARRANTY 3195b482a8SLen Brown * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3295b482a8SLen Brown * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3395b482a8SLen Brown * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3495b482a8SLen Brown * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3595b482a8SLen Brown * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3695b482a8SLen Brown * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3795b482a8SLen Brown * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3895b482a8SLen Brown * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3995b482a8SLen Brown * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4095b482a8SLen Brown * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4195b482a8SLen Brown * POSSIBILITY OF SUCH DAMAGES. 4295b482a8SLen Brown */ 4395b482a8SLen Brown 4495b482a8SLen Brown #include <acpi/acpi.h> 45*e2f7a777SLen Brown #include "accommon.h" 46*e2f7a777SLen Brown #include "acnamesp.h" 4795b482a8SLen Brown 4895b482a8SLen Brown #define _COMPONENT ACPI_NAMESPACE 4995b482a8SLen Brown ACPI_MODULE_NAME("nswalk") 5095b482a8SLen Brown 5195b482a8SLen Brown /******************************************************************************* 5295b482a8SLen Brown * 5395b482a8SLen Brown * FUNCTION: acpi_ns_get_next_node 5495b482a8SLen Brown * 5595b482a8SLen Brown * PARAMETERS: Type - Type of node to be searched for 5695b482a8SLen Brown * parent_node - Parent node whose children we are 5795b482a8SLen Brown * getting 5895b482a8SLen Brown * child_node - Previous child that was found. 5995b482a8SLen Brown * The NEXT child will be returned 6095b482a8SLen Brown * 6195b482a8SLen Brown * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if 6295b482a8SLen Brown * none is found. 6395b482a8SLen Brown * 6495b482a8SLen Brown * DESCRIPTION: Return the next peer node within the namespace. If Handle 6595b482a8SLen Brown * is valid, Scope is ignored. Otherwise, the first node 6695b482a8SLen Brown * within Scope is returned. 6795b482a8SLen Brown * 6895b482a8SLen Brown ******************************************************************************/ 6995b482a8SLen Brown struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node 7095b482a8SLen Brown *parent_node, struct acpi_namespace_node 7195b482a8SLen Brown *child_node) 7295b482a8SLen Brown { 7395b482a8SLen Brown struct acpi_namespace_node *next_node = NULL; 7495b482a8SLen Brown 7595b482a8SLen Brown ACPI_FUNCTION_ENTRY(); 7695b482a8SLen Brown 7795b482a8SLen Brown if (!child_node) { 7895b482a8SLen Brown 7995b482a8SLen Brown /* It's really the parent's _scope_ that we want */ 8095b482a8SLen Brown 8195b482a8SLen Brown next_node = parent_node->child; 8295b482a8SLen Brown } 8395b482a8SLen Brown 8495b482a8SLen Brown else { 8595b482a8SLen Brown /* Start search at the NEXT node */ 8695b482a8SLen Brown 8795b482a8SLen Brown next_node = acpi_ns_get_next_valid_node(child_node); 8895b482a8SLen Brown } 8995b482a8SLen Brown 9095b482a8SLen Brown /* If any type is OK, we are done */ 9195b482a8SLen Brown 9295b482a8SLen Brown if (type == ACPI_TYPE_ANY) { 9395b482a8SLen Brown 9495b482a8SLen Brown /* next_node is NULL if we are at the end-of-list */ 9595b482a8SLen Brown 9695b482a8SLen Brown return (next_node); 9795b482a8SLen Brown } 9895b482a8SLen Brown 9995b482a8SLen Brown /* Must search for the node -- but within this scope only */ 10095b482a8SLen Brown 10195b482a8SLen Brown while (next_node) { 10295b482a8SLen Brown 10395b482a8SLen Brown /* If type matches, we are done */ 10495b482a8SLen Brown 10595b482a8SLen Brown if (next_node->type == type) { 10695b482a8SLen Brown return (next_node); 10795b482a8SLen Brown } 10895b482a8SLen Brown 10995b482a8SLen Brown /* Otherwise, move on to the next node */ 11095b482a8SLen Brown 11195b482a8SLen Brown next_node = acpi_ns_get_next_valid_node(next_node); 11295b482a8SLen Brown } 11395b482a8SLen Brown 11495b482a8SLen Brown /* Not found */ 11595b482a8SLen Brown 11695b482a8SLen Brown return (NULL); 11795b482a8SLen Brown } 11895b482a8SLen Brown 11995b482a8SLen Brown /******************************************************************************* 12095b482a8SLen Brown * 12195b482a8SLen Brown * FUNCTION: acpi_ns_walk_namespace 12295b482a8SLen Brown * 12395b482a8SLen Brown * PARAMETERS: Type - acpi_object_type to search for 12495b482a8SLen Brown * start_node - Handle in namespace where search begins 12595b482a8SLen Brown * max_depth - Depth to which search is to reach 12695b482a8SLen Brown * Flags - Whether to unlock the NS before invoking 12795b482a8SLen Brown * the callback routine 12895b482a8SLen Brown * user_function - Called when an object of "Type" is found 12995b482a8SLen Brown * Context - Passed to user function 13095b482a8SLen Brown * return_value - from the user_function if terminated early. 13195b482a8SLen Brown * Otherwise, returns NULL. 13295b482a8SLen Brown * RETURNS: Status 13395b482a8SLen Brown * 13495b482a8SLen Brown * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 13595b482a8SLen Brown * starting (and ending) at the node specified by start_handle. 13695b482a8SLen Brown * The user_function is called whenever a node that matches 13795b482a8SLen Brown * the type parameter is found. If the user function returns 13895b482a8SLen Brown * a non-zero value, the search is terminated immediately and this 13995b482a8SLen Brown * value is returned to the caller. 14095b482a8SLen Brown * 14195b482a8SLen Brown * The point of this procedure is to provide a generic namespace 14295b482a8SLen Brown * walk routine that can be called from multiple places to 14395b482a8SLen Brown * provide multiple services; the User Function can be tailored 14495b482a8SLen Brown * to each task, whether it is a print function, a compare 14595b482a8SLen Brown * function, etc. 14695b482a8SLen Brown * 14795b482a8SLen Brown ******************************************************************************/ 14895b482a8SLen Brown 14995b482a8SLen Brown acpi_status 15095b482a8SLen Brown acpi_ns_walk_namespace(acpi_object_type type, 15195b482a8SLen Brown acpi_handle start_node, 15295b482a8SLen Brown u32 max_depth, 15395b482a8SLen Brown u32 flags, 15495b482a8SLen Brown acpi_walk_callback user_function, 15595b482a8SLen Brown void *context, void **return_value) 15695b482a8SLen Brown { 15795b482a8SLen Brown acpi_status status; 15895b482a8SLen Brown acpi_status mutex_status; 15995b482a8SLen Brown struct acpi_namespace_node *child_node; 16095b482a8SLen Brown struct acpi_namespace_node *parent_node; 16195b482a8SLen Brown acpi_object_type child_type; 16295b482a8SLen Brown u32 level; 16395b482a8SLen Brown 16495b482a8SLen Brown ACPI_FUNCTION_TRACE(ns_walk_namespace); 16595b482a8SLen Brown 16695b482a8SLen Brown /* Special case for the namespace Root Node */ 16795b482a8SLen Brown 16895b482a8SLen Brown if (start_node == ACPI_ROOT_OBJECT) { 16995b482a8SLen Brown start_node = acpi_gbl_root_node; 17095b482a8SLen Brown } 17195b482a8SLen Brown 17295b482a8SLen Brown /* Null child means "get first node" */ 17395b482a8SLen Brown 17495b482a8SLen Brown parent_node = start_node; 17595b482a8SLen Brown child_node = NULL; 17695b482a8SLen Brown child_type = ACPI_TYPE_ANY; 17795b482a8SLen Brown level = 1; 17895b482a8SLen Brown 17995b482a8SLen Brown /* 18095b482a8SLen Brown * Traverse the tree of nodes until we bubble back up to where we 18195b482a8SLen Brown * started. When Level is zero, the loop is done because we have 18295b482a8SLen Brown * bubbled up to (and passed) the original parent handle (start_entry) 18395b482a8SLen Brown */ 18495b482a8SLen Brown while (level > 0) { 18595b482a8SLen Brown 18695b482a8SLen Brown /* Get the next node in this scope. Null if not found */ 18795b482a8SLen Brown 18895b482a8SLen Brown status = AE_OK; 18995b482a8SLen Brown child_node = 19095b482a8SLen Brown acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, 19195b482a8SLen Brown child_node); 19295b482a8SLen Brown if (child_node) { 19395b482a8SLen Brown 19495b482a8SLen Brown /* Found next child, get the type if we are not searching for ANY */ 19595b482a8SLen Brown 19695b482a8SLen Brown if (type != ACPI_TYPE_ANY) { 19795b482a8SLen Brown child_type = child_node->type; 19895b482a8SLen Brown } 19995b482a8SLen Brown 20095b482a8SLen Brown /* 20195b482a8SLen Brown * Ignore all temporary namespace nodes (created during control 20295b482a8SLen Brown * method execution) unless told otherwise. These temporary nodes 20395b482a8SLen Brown * can cause a race condition because they can be deleted during the 20495b482a8SLen Brown * execution of the user function (if the namespace is unlocked before 20595b482a8SLen Brown * invocation of the user function.) Only the debugger namespace dump 20695b482a8SLen Brown * will examine the temporary nodes. 20795b482a8SLen Brown */ 20895b482a8SLen Brown if ((child_node->flags & ANOBJ_TEMPORARY) && 20995b482a8SLen Brown !(flags & ACPI_NS_WALK_TEMP_NODES)) { 21095b482a8SLen Brown status = AE_CTRL_DEPTH; 21195b482a8SLen Brown } 21295b482a8SLen Brown 21395b482a8SLen Brown /* Type must match requested type */ 21495b482a8SLen Brown 21595b482a8SLen Brown else if (child_type == type) { 21695b482a8SLen Brown /* 21795b482a8SLen Brown * Found a matching node, invoke the user callback function. 21895b482a8SLen Brown * Unlock the namespace if flag is set. 21995b482a8SLen Brown */ 22095b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 22195b482a8SLen Brown mutex_status = 22295b482a8SLen Brown acpi_ut_release_mutex 22395b482a8SLen Brown (ACPI_MTX_NAMESPACE); 22495b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 22595b482a8SLen Brown return_ACPI_STATUS 22695b482a8SLen Brown (mutex_status); 22795b482a8SLen Brown } 22895b482a8SLen Brown } 22995b482a8SLen Brown 23095b482a8SLen Brown status = 23195b482a8SLen Brown user_function(child_node, level, context, 23295b482a8SLen Brown return_value); 23395b482a8SLen Brown 23495b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 23595b482a8SLen Brown mutex_status = 23695b482a8SLen Brown acpi_ut_acquire_mutex 23795b482a8SLen Brown (ACPI_MTX_NAMESPACE); 23895b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 23995b482a8SLen Brown return_ACPI_STATUS 24095b482a8SLen Brown (mutex_status); 24195b482a8SLen Brown } 24295b482a8SLen Brown } 24395b482a8SLen Brown 24495b482a8SLen Brown switch (status) { 24595b482a8SLen Brown case AE_OK: 24695b482a8SLen Brown case AE_CTRL_DEPTH: 24795b482a8SLen Brown 24895b482a8SLen Brown /* Just keep going */ 24995b482a8SLen Brown break; 25095b482a8SLen Brown 25195b482a8SLen Brown case AE_CTRL_TERMINATE: 25295b482a8SLen Brown 25395b482a8SLen Brown /* Exit now, with OK status */ 25495b482a8SLen Brown 25595b482a8SLen Brown return_ACPI_STATUS(AE_OK); 25695b482a8SLen Brown 25795b482a8SLen Brown default: 25895b482a8SLen Brown 25995b482a8SLen Brown /* All others are valid exceptions */ 26095b482a8SLen Brown 26195b482a8SLen Brown return_ACPI_STATUS(status); 26295b482a8SLen Brown } 26395b482a8SLen Brown } 26495b482a8SLen Brown 26595b482a8SLen Brown /* 26695b482a8SLen Brown * Depth first search: Attempt to go down another level in the 26795b482a8SLen Brown * namespace if we are allowed to. Don't go any further if we have 26895b482a8SLen Brown * reached the caller specified maximum depth or if the user 26995b482a8SLen Brown * function has specified that the maximum depth has been reached. 27095b482a8SLen Brown */ 27195b482a8SLen Brown if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { 27295b482a8SLen Brown if (acpi_ns_get_next_node 27395b482a8SLen Brown (ACPI_TYPE_ANY, child_node, NULL)) { 27495b482a8SLen Brown 27595b482a8SLen Brown /* There is at least one child of this node, visit it */ 27695b482a8SLen Brown 27795b482a8SLen Brown level++; 27895b482a8SLen Brown parent_node = child_node; 27995b482a8SLen Brown child_node = NULL; 28095b482a8SLen Brown } 28195b482a8SLen Brown } 28295b482a8SLen Brown } else { 28395b482a8SLen Brown /* 28495b482a8SLen Brown * No more children of this node (acpi_ns_get_next_node failed), go 28595b482a8SLen Brown * back upwards in the namespace tree to the node's parent. 28695b482a8SLen Brown */ 28795b482a8SLen Brown level--; 28895b482a8SLen Brown child_node = parent_node; 28995b482a8SLen Brown parent_node = acpi_ns_get_parent_node(parent_node); 29095b482a8SLen Brown } 29195b482a8SLen Brown } 29295b482a8SLen Brown 29395b482a8SLen Brown /* Complete walk, not terminated by user function */ 29495b482a8SLen Brown 29595b482a8SLen Brown return_ACPI_STATUS(AE_OK); 29695b482a8SLen Brown } 297