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> 45e2f7a777SLen Brown #include "accommon.h" 46e2f7a777SLen 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 * 558c725bf9SBob Moore * PARAMETERS: parent_node - Parent node whose children we are 568c725bf9SBob Moore * getting 578c725bf9SBob Moore * child_node - Previous child that was found. 588c725bf9SBob Moore * The NEXT child will be returned 598c725bf9SBob Moore * 608c725bf9SBob Moore * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if 618c725bf9SBob Moore * none is found. 628c725bf9SBob Moore * 638c725bf9SBob Moore * DESCRIPTION: Return the next peer node within the namespace. If Handle 648c725bf9SBob Moore * is valid, Scope is ignored. Otherwise, the first node 658c725bf9SBob Moore * within Scope is returned. 668c725bf9SBob Moore * 678c725bf9SBob Moore ******************************************************************************/ 688c725bf9SBob Moore struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node 698c725bf9SBob Moore *parent_node, 708c725bf9SBob Moore struct acpi_namespace_node 718c725bf9SBob Moore *child_node) 728c725bf9SBob Moore { 738c725bf9SBob Moore ACPI_FUNCTION_ENTRY(); 748c725bf9SBob Moore 758c725bf9SBob Moore if (!child_node) { 768c725bf9SBob Moore 778c725bf9SBob Moore /* It's really the parent's _scope_ that we want */ 788c725bf9SBob Moore 798c725bf9SBob Moore return parent_node->child; 808c725bf9SBob Moore } 818c725bf9SBob Moore 828c725bf9SBob Moore /* 838c725bf9SBob Moore * Get the next node. 848c725bf9SBob Moore * 858c725bf9SBob Moore * If we are at the end of this peer list, return NULL 868c725bf9SBob Moore */ 878c725bf9SBob Moore if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { 888c725bf9SBob Moore return NULL; 898c725bf9SBob Moore } 908c725bf9SBob Moore 918c725bf9SBob Moore /* Otherwise just return the next peer */ 928c725bf9SBob Moore 938c725bf9SBob Moore return child_node->peer; 948c725bf9SBob Moore } 958c725bf9SBob Moore 968c725bf9SBob Moore /******************************************************************************* 978c725bf9SBob Moore * 988c725bf9SBob Moore * FUNCTION: acpi_ns_get_next_node_typed 998c725bf9SBob Moore * 10095b482a8SLen Brown * PARAMETERS: Type - Type of node to be searched for 10195b482a8SLen Brown * parent_node - Parent node whose children we are 10295b482a8SLen Brown * getting 10395b482a8SLen Brown * child_node - Previous child that was found. 10495b482a8SLen Brown * The NEXT child will be returned 10595b482a8SLen Brown * 10695b482a8SLen Brown * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if 10795b482a8SLen Brown * none is found. 10895b482a8SLen Brown * 10995b482a8SLen Brown * DESCRIPTION: Return the next peer node within the namespace. If Handle 11095b482a8SLen Brown * is valid, Scope is ignored. Otherwise, the first node 11195b482a8SLen Brown * within Scope is returned. 11295b482a8SLen Brown * 11395b482a8SLen Brown ******************************************************************************/ 1148c725bf9SBob Moore 1158c725bf9SBob Moore struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, 1168c725bf9SBob Moore struct 1178c725bf9SBob Moore acpi_namespace_node 1188c725bf9SBob Moore *parent_node, 1198c725bf9SBob Moore struct 1208c725bf9SBob Moore acpi_namespace_node 12195b482a8SLen Brown *child_node) 12295b482a8SLen Brown { 12395b482a8SLen Brown struct acpi_namespace_node *next_node = NULL; 12495b482a8SLen Brown 12595b482a8SLen Brown ACPI_FUNCTION_ENTRY(); 12695b482a8SLen Brown 1278c725bf9SBob Moore next_node = acpi_ns_get_next_node(parent_node, child_node); 12895b482a8SLen Brown 12995b482a8SLen Brown 13095b482a8SLen Brown /* If any type is OK, we are done */ 13195b482a8SLen Brown 13295b482a8SLen Brown if (type == ACPI_TYPE_ANY) { 13395b482a8SLen Brown 13495b482a8SLen Brown /* next_node is NULL if we are at the end-of-list */ 13595b482a8SLen Brown 13695b482a8SLen Brown return (next_node); 13795b482a8SLen Brown } 13895b482a8SLen Brown 13995b482a8SLen Brown /* Must search for the node -- but within this scope only */ 14095b482a8SLen Brown 14195b482a8SLen Brown while (next_node) { 14295b482a8SLen Brown 14395b482a8SLen Brown /* If type matches, we are done */ 14495b482a8SLen Brown 14595b482a8SLen Brown if (next_node->type == type) { 14695b482a8SLen Brown return (next_node); 14795b482a8SLen Brown } 14895b482a8SLen Brown 14995b482a8SLen Brown /* Otherwise, move on to the next node */ 15095b482a8SLen Brown 15195b482a8SLen Brown next_node = acpi_ns_get_next_valid_node(next_node); 15295b482a8SLen Brown } 15395b482a8SLen Brown 15495b482a8SLen Brown /* Not found */ 15595b482a8SLen Brown 15695b482a8SLen Brown return (NULL); 15795b482a8SLen Brown } 15895b482a8SLen Brown 15995b482a8SLen Brown /******************************************************************************* 16095b482a8SLen Brown * 16195b482a8SLen Brown * FUNCTION: acpi_ns_walk_namespace 16295b482a8SLen Brown * 16395b482a8SLen Brown * PARAMETERS: Type - acpi_object_type to search for 16495b482a8SLen Brown * start_node - Handle in namespace where search begins 16595b482a8SLen Brown * max_depth - Depth to which search is to reach 16695b482a8SLen Brown * Flags - Whether to unlock the NS before invoking 16795b482a8SLen Brown * the callback routine 168*2263576cSLin Ming * pre_order_visit - Called during tree pre-order visit 169*2263576cSLin Ming * when an object of "Type" is found 170*2263576cSLin Ming * post_order_visit - Called during tree post-order visit 171*2263576cSLin Ming * when an object of "Type" is found 172*2263576cSLin Ming * Context - Passed to user function(s) above 173*2263576cSLin Ming * return_value - from the user_function if terminated 174*2263576cSLin Ming * early. Otherwise, returns NULL. 17595b482a8SLen Brown * RETURNS: Status 17695b482a8SLen Brown * 17795b482a8SLen Brown * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 17895b482a8SLen Brown * starting (and ending) at the node specified by start_handle. 179*2263576cSLin Ming * The callback function is called whenever a node that matches 180*2263576cSLin Ming * the type parameter is found. If the callback function returns 181d4913dc6SBob Moore * a non-zero value, the search is terminated immediately and 182d4913dc6SBob Moore * this value is returned to the caller. 18395b482a8SLen Brown * 18495b482a8SLen Brown * The point of this procedure is to provide a generic namespace 18595b482a8SLen Brown * walk routine that can be called from multiple places to 186*2263576cSLin Ming * provide multiple services; the callback function(s) can be 187*2263576cSLin Ming * tailored to each task, whether it is a print function, 188*2263576cSLin Ming * a compare function, etc. 18995b482a8SLen Brown * 19095b482a8SLen Brown ******************************************************************************/ 19195b482a8SLen Brown 19295b482a8SLen Brown acpi_status 19395b482a8SLen Brown acpi_ns_walk_namespace(acpi_object_type type, 19495b482a8SLen Brown acpi_handle start_node, 19595b482a8SLen Brown u32 max_depth, 19695b482a8SLen Brown u32 flags, 197*2263576cSLin Ming acpi_walk_callback pre_order_visit, 198*2263576cSLin Ming acpi_walk_callback post_order_visit, 19995b482a8SLen Brown void *context, void **return_value) 20095b482a8SLen Brown { 20195b482a8SLen Brown acpi_status status; 20295b482a8SLen Brown acpi_status mutex_status; 20395b482a8SLen Brown struct acpi_namespace_node *child_node; 20495b482a8SLen Brown struct acpi_namespace_node *parent_node; 20595b482a8SLen Brown acpi_object_type child_type; 20695b482a8SLen Brown u32 level; 207*2263576cSLin Ming u8 node_previously_visited = FALSE; 20895b482a8SLen Brown 20995b482a8SLen Brown ACPI_FUNCTION_TRACE(ns_walk_namespace); 21095b482a8SLen Brown 21195b482a8SLen Brown /* Special case for the namespace Root Node */ 21295b482a8SLen Brown 21395b482a8SLen Brown if (start_node == ACPI_ROOT_OBJECT) { 21495b482a8SLen Brown start_node = acpi_gbl_root_node; 21595b482a8SLen Brown } 21695b482a8SLen Brown 21795b482a8SLen Brown /* Null child means "get first node" */ 21895b482a8SLen Brown 21995b482a8SLen Brown parent_node = start_node; 220*2263576cSLin Ming child_node = acpi_ns_get_next_node(parent_node, NULL); 22195b482a8SLen Brown child_type = ACPI_TYPE_ANY; 22295b482a8SLen Brown level = 1; 22395b482a8SLen Brown 22495b482a8SLen Brown /* 22595b482a8SLen Brown * Traverse the tree of nodes until we bubble back up to where we 22695b482a8SLen Brown * started. When Level is zero, the loop is done because we have 22795b482a8SLen Brown * bubbled up to (and passed) the original parent handle (start_entry) 22895b482a8SLen Brown */ 229*2263576cSLin Ming while (level > 0 && child_node) { 23095b482a8SLen Brown status = AE_OK; 23195b482a8SLen Brown 23295b482a8SLen Brown /* Found next child, get the type if we are not searching for ANY */ 23395b482a8SLen Brown 23495b482a8SLen Brown if (type != ACPI_TYPE_ANY) { 23595b482a8SLen Brown child_type = child_node->type; 23695b482a8SLen Brown } 23795b482a8SLen Brown 23895b482a8SLen Brown /* 23995b482a8SLen Brown * Ignore all temporary namespace nodes (created during control 24095b482a8SLen Brown * method execution) unless told otherwise. These temporary nodes 241d4913dc6SBob Moore * can cause a race condition because they can be deleted during 242d4913dc6SBob Moore * the execution of the user function (if the namespace is 243d4913dc6SBob Moore * unlocked before invocation of the user function.) Only the 244d4913dc6SBob Moore * debugger namespace dump will examine the temporary nodes. 24595b482a8SLen Brown */ 24695b482a8SLen Brown if ((child_node->flags & ANOBJ_TEMPORARY) && 24795b482a8SLen Brown !(flags & ACPI_NS_WALK_TEMP_NODES)) { 24895b482a8SLen Brown status = AE_CTRL_DEPTH; 24995b482a8SLen Brown } 25095b482a8SLen Brown 25195b482a8SLen Brown /* Type must match requested type */ 25295b482a8SLen Brown 25395b482a8SLen Brown else if (child_type == type) { 25495b482a8SLen Brown /* 25595b482a8SLen Brown * Found a matching node, invoke the user callback function. 25695b482a8SLen Brown * Unlock the namespace if flag is set. 25795b482a8SLen Brown */ 25895b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 25995b482a8SLen Brown mutex_status = 260*2263576cSLin Ming acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 26195b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 262*2263576cSLin Ming return_ACPI_STATUS(mutex_status); 26395b482a8SLen Brown } 26495b482a8SLen Brown } 26595b482a8SLen Brown 266*2263576cSLin Ming /* 267*2263576cSLin Ming * Invoke the user function, either pre-order or post-order 268*2263576cSLin Ming * or both. 269*2263576cSLin Ming */ 270*2263576cSLin Ming if (!node_previously_visited) { 271*2263576cSLin Ming if (pre_order_visit) { 27295b482a8SLen Brown status = 273*2263576cSLin Ming pre_order_visit(child_node, level, 274*2263576cSLin Ming context, 27595b482a8SLen Brown return_value); 276*2263576cSLin Ming } 277*2263576cSLin Ming } else { 278*2263576cSLin Ming if (post_order_visit) { 279*2263576cSLin Ming status = 280*2263576cSLin Ming post_order_visit(child_node, level, 281*2263576cSLin Ming context, 282*2263576cSLin Ming return_value); 283*2263576cSLin Ming } 284*2263576cSLin Ming } 28595b482a8SLen Brown 28695b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 28795b482a8SLen Brown mutex_status = 288*2263576cSLin Ming acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 28995b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 290*2263576cSLin Ming return_ACPI_STATUS(mutex_status); 29195b482a8SLen Brown } 29295b482a8SLen Brown } 29395b482a8SLen Brown 29495b482a8SLen Brown switch (status) { 29595b482a8SLen Brown case AE_OK: 29695b482a8SLen Brown case AE_CTRL_DEPTH: 29795b482a8SLen Brown 29895b482a8SLen Brown /* Just keep going */ 29995b482a8SLen Brown break; 30095b482a8SLen Brown 30195b482a8SLen Brown case AE_CTRL_TERMINATE: 30295b482a8SLen Brown 30395b482a8SLen Brown /* Exit now, with OK status */ 30495b482a8SLen Brown 30595b482a8SLen Brown return_ACPI_STATUS(AE_OK); 30695b482a8SLen Brown 30795b482a8SLen Brown default: 30895b482a8SLen Brown 30995b482a8SLen Brown /* All others are valid exceptions */ 31095b482a8SLen Brown 31195b482a8SLen Brown return_ACPI_STATUS(status); 31295b482a8SLen Brown } 31395b482a8SLen Brown } 31495b482a8SLen Brown 31595b482a8SLen Brown /* 31695b482a8SLen Brown * Depth first search: Attempt to go down another level in the 31795b482a8SLen Brown * namespace if we are allowed to. Don't go any further if we have 31895b482a8SLen Brown * reached the caller specified maximum depth or if the user 31995b482a8SLen Brown * function has specified that the maximum depth has been reached. 32095b482a8SLen Brown */ 321*2263576cSLin Ming if (!node_previously_visited && 322*2263576cSLin Ming (level < max_depth) && (status != AE_CTRL_DEPTH)) { 3238c725bf9SBob Moore if (child_node->child) { 32495b482a8SLen Brown 32595b482a8SLen Brown /* There is at least one child of this node, visit it */ 32695b482a8SLen Brown 32795b482a8SLen Brown level++; 32895b482a8SLen Brown parent_node = child_node; 329*2263576cSLin Ming child_node = 330*2263576cSLin Ming acpi_ns_get_next_node(parent_node, NULL); 331*2263576cSLin Ming continue; 33295b482a8SLen Brown } 33395b482a8SLen Brown } 334*2263576cSLin Ming 335*2263576cSLin Ming /* No more children, re-visit this node */ 336*2263576cSLin Ming 337*2263576cSLin Ming if (!node_previously_visited) { 338*2263576cSLin Ming node_previously_visited = TRUE; 339*2263576cSLin Ming continue; 340*2263576cSLin Ming } 341*2263576cSLin Ming 342*2263576cSLin Ming /* No more children, visit peers */ 343*2263576cSLin Ming 344*2263576cSLin Ming child_node = acpi_ns_get_next_node(parent_node, child_node); 345*2263576cSLin Ming if (child_node) { 346*2263576cSLin Ming node_previously_visited = FALSE; 347*2263576cSLin Ming } 348*2263576cSLin Ming 349*2263576cSLin Ming /* No peers, re-visit parent */ 350*2263576cSLin Ming 351*2263576cSLin Ming else { 35295b482a8SLen Brown /* 35395b482a8SLen Brown * No more children of this node (acpi_ns_get_next_node failed), go 35495b482a8SLen Brown * back upwards in the namespace tree to the node's parent. 35595b482a8SLen Brown */ 35695b482a8SLen Brown level--; 35795b482a8SLen Brown child_node = parent_node; 35895b482a8SLen Brown parent_node = acpi_ns_get_parent_node(parent_node); 359*2263576cSLin Ming 360*2263576cSLin Ming node_previously_visited = TRUE; 36195b482a8SLen Brown } 36295b482a8SLen Brown } 36395b482a8SLen Brown 36495b482a8SLen Brown /* Complete walk, not terminated by user function */ 36595b482a8SLen Brown 36695b482a8SLen Brown return_ACPI_STATUS(AE_OK); 36795b482a8SLen Brown } 368