195b482a8SLen Brown /****************************************************************************** 295b482a8SLen Brown * 395b482a8SLen Brown * Module Name: nswalk - Functions for walking the ACPI namespace 495b482a8SLen Brown * 595b482a8SLen Brown *****************************************************************************/ 695b482a8SLen Brown 795b482a8SLen Brown /* 877848130SBob Moore * Copyright (C) 2000 - 2012, 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 79*9c0d7939SLv Zheng return (parent_node->child); 808c725bf9SBob Moore } 818c725bf9SBob Moore 828c725bf9SBob Moore /* Otherwise just return the next peer */ 838c725bf9SBob Moore 84*9c0d7939SLv Zheng return (child_node->peer); 858c725bf9SBob Moore } 868c725bf9SBob Moore 878c725bf9SBob Moore /******************************************************************************* 888c725bf9SBob Moore * 898c725bf9SBob Moore * FUNCTION: acpi_ns_get_next_node_typed 908c725bf9SBob Moore * 91ba494beeSBob Moore * PARAMETERS: type - Type of node to be searched for 9295b482a8SLen Brown * parent_node - Parent node whose children we are 9395b482a8SLen Brown * getting 9495b482a8SLen Brown * child_node - Previous child that was found. 9595b482a8SLen Brown * The NEXT child will be returned 9695b482a8SLen Brown * 9795b482a8SLen Brown * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if 9895b482a8SLen Brown * none is found. 9995b482a8SLen Brown * 10095b482a8SLen Brown * DESCRIPTION: Return the next peer node within the namespace. If Handle 10195b482a8SLen Brown * is valid, Scope is ignored. Otherwise, the first node 10295b482a8SLen Brown * within Scope is returned. 10395b482a8SLen Brown * 10495b482a8SLen Brown ******************************************************************************/ 1058c725bf9SBob Moore 1068c725bf9SBob Moore struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, 1078c725bf9SBob Moore struct 1088c725bf9SBob Moore acpi_namespace_node 1098c725bf9SBob Moore *parent_node, 1108c725bf9SBob Moore struct 1118c725bf9SBob Moore acpi_namespace_node 11295b482a8SLen Brown *child_node) 11395b482a8SLen Brown { 11495b482a8SLen Brown struct acpi_namespace_node *next_node = NULL; 11595b482a8SLen Brown 11695b482a8SLen Brown ACPI_FUNCTION_ENTRY(); 11795b482a8SLen Brown 1188c725bf9SBob Moore next_node = acpi_ns_get_next_node(parent_node, child_node); 11995b482a8SLen Brown 12095b482a8SLen Brown 12195b482a8SLen Brown /* If any type is OK, we are done */ 12295b482a8SLen Brown 12395b482a8SLen Brown if (type == ACPI_TYPE_ANY) { 12495b482a8SLen Brown 12595b482a8SLen Brown /* next_node is NULL if we are at the end-of-list */ 12695b482a8SLen Brown 12795b482a8SLen Brown return (next_node); 12895b482a8SLen Brown } 12995b482a8SLen Brown 13095b482a8SLen Brown /* Must search for the node -- but within this scope only */ 13195b482a8SLen Brown 13295b482a8SLen Brown while (next_node) { 13395b482a8SLen Brown 13495b482a8SLen Brown /* If type matches, we are done */ 13595b482a8SLen Brown 13695b482a8SLen Brown if (next_node->type == type) { 13795b482a8SLen Brown return (next_node); 13895b482a8SLen Brown } 13995b482a8SLen Brown 140c45b5c09SAlexey Starikovskiy /* Otherwise, move on to the next peer node */ 14195b482a8SLen Brown 142c45b5c09SAlexey Starikovskiy next_node = next_node->peer; 14395b482a8SLen Brown } 14495b482a8SLen Brown 14595b482a8SLen Brown /* Not found */ 14695b482a8SLen Brown 14795b482a8SLen Brown return (NULL); 14895b482a8SLen Brown } 14995b482a8SLen Brown 15095b482a8SLen Brown /******************************************************************************* 15195b482a8SLen Brown * 15295b482a8SLen Brown * FUNCTION: acpi_ns_walk_namespace 15395b482a8SLen Brown * 154ba494beeSBob Moore * PARAMETERS: type - acpi_object_type to search for 15595b482a8SLen Brown * start_node - Handle in namespace where search begins 15695b482a8SLen Brown * max_depth - Depth to which search is to reach 157ba494beeSBob Moore * flags - Whether to unlock the NS before invoking 15895b482a8SLen Brown * the callback routine 1592263576cSLin Ming * pre_order_visit - Called during tree pre-order visit 1602263576cSLin Ming * when an object of "Type" is found 1612263576cSLin Ming * post_order_visit - Called during tree post-order visit 1622263576cSLin Ming * when an object of "Type" is found 163ba494beeSBob Moore * context - Passed to user function(s) above 1642263576cSLin Ming * return_value - from the user_function if terminated 1652263576cSLin Ming * early. Otherwise, returns NULL. 16695b482a8SLen Brown * RETURNS: Status 16795b482a8SLen Brown * 16895b482a8SLen Brown * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 16995b482a8SLen Brown * starting (and ending) at the node specified by start_handle. 1702263576cSLin Ming * The callback function is called whenever a node that matches 1712263576cSLin Ming * the type parameter is found. If the callback function returns 172d4913dc6SBob Moore * a non-zero value, the search is terminated immediately and 173d4913dc6SBob Moore * this value is returned to the caller. 17495b482a8SLen Brown * 17595b482a8SLen Brown * The point of this procedure is to provide a generic namespace 17695b482a8SLen Brown * walk routine that can be called from multiple places to 1772263576cSLin Ming * provide multiple services; the callback function(s) can be 1782263576cSLin Ming * tailored to each task, whether it is a print function, 1792263576cSLin Ming * a compare function, etc. 18095b482a8SLen Brown * 18195b482a8SLen Brown ******************************************************************************/ 18295b482a8SLen Brown 18395b482a8SLen Brown acpi_status 18495b482a8SLen Brown acpi_ns_walk_namespace(acpi_object_type type, 18595b482a8SLen Brown acpi_handle start_node, 18695b482a8SLen Brown u32 max_depth, 18795b482a8SLen Brown u32 flags, 1882263576cSLin Ming acpi_walk_callback pre_order_visit, 1892263576cSLin Ming acpi_walk_callback post_order_visit, 19095b482a8SLen Brown void *context, void **return_value) 19195b482a8SLen Brown { 19295b482a8SLen Brown acpi_status status; 19395b482a8SLen Brown acpi_status mutex_status; 19495b482a8SLen Brown struct acpi_namespace_node *child_node; 19595b482a8SLen Brown struct acpi_namespace_node *parent_node; 19695b482a8SLen Brown acpi_object_type child_type; 19795b482a8SLen Brown u32 level; 1982263576cSLin Ming u8 node_previously_visited = FALSE; 19995b482a8SLen Brown 20095b482a8SLen Brown ACPI_FUNCTION_TRACE(ns_walk_namespace); 20195b482a8SLen Brown 20295b482a8SLen Brown /* Special case for the namespace Root Node */ 20395b482a8SLen Brown 20495b482a8SLen Brown if (start_node == ACPI_ROOT_OBJECT) { 20595b482a8SLen Brown start_node = acpi_gbl_root_node; 20695b482a8SLen Brown } 20795b482a8SLen Brown 20895b482a8SLen Brown /* Null child means "get first node" */ 20995b482a8SLen Brown 21095b482a8SLen Brown parent_node = start_node; 2112263576cSLin Ming child_node = acpi_ns_get_next_node(parent_node, NULL); 21295b482a8SLen Brown child_type = ACPI_TYPE_ANY; 21395b482a8SLen Brown level = 1; 21495b482a8SLen Brown 21595b482a8SLen Brown /* 21695b482a8SLen Brown * Traverse the tree of nodes until we bubble back up to where we 21795b482a8SLen Brown * started. When Level is zero, the loop is done because we have 21895b482a8SLen Brown * bubbled up to (and passed) the original parent handle (start_entry) 21995b482a8SLen Brown */ 2202263576cSLin Ming while (level > 0 && child_node) { 22195b482a8SLen Brown status = AE_OK; 22295b482a8SLen Brown 22395b482a8SLen Brown /* Found next child, get the type if we are not searching for ANY */ 22495b482a8SLen Brown 22595b482a8SLen Brown if (type != ACPI_TYPE_ANY) { 22695b482a8SLen Brown child_type = child_node->type; 22795b482a8SLen Brown } 22895b482a8SLen Brown 22995b482a8SLen Brown /* 23095b482a8SLen Brown * Ignore all temporary namespace nodes (created during control 23195b482a8SLen Brown * method execution) unless told otherwise. These temporary nodes 232d4913dc6SBob Moore * can cause a race condition because they can be deleted during 233d4913dc6SBob Moore * the execution of the user function (if the namespace is 234d4913dc6SBob Moore * unlocked before invocation of the user function.) Only the 235d4913dc6SBob Moore * debugger namespace dump will examine the temporary nodes. 23695b482a8SLen Brown */ 23795b482a8SLen Brown if ((child_node->flags & ANOBJ_TEMPORARY) && 23895b482a8SLen Brown !(flags & ACPI_NS_WALK_TEMP_NODES)) { 23995b482a8SLen Brown status = AE_CTRL_DEPTH; 24095b482a8SLen Brown } 24195b482a8SLen Brown 24295b482a8SLen Brown /* Type must match requested type */ 24395b482a8SLen Brown 24495b482a8SLen Brown else if (child_type == type) { 24595b482a8SLen Brown /* 24695b482a8SLen Brown * Found a matching node, invoke the user callback function. 24795b482a8SLen Brown * Unlock the namespace if flag is set. 24895b482a8SLen Brown */ 24995b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 25095b482a8SLen Brown mutex_status = 2512263576cSLin Ming acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 25295b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 2532263576cSLin Ming return_ACPI_STATUS(mutex_status); 25495b482a8SLen Brown } 25595b482a8SLen Brown } 25695b482a8SLen Brown 2572263576cSLin Ming /* 2582263576cSLin Ming * Invoke the user function, either pre-order or post-order 2592263576cSLin Ming * or both. 2602263576cSLin Ming */ 2612263576cSLin Ming if (!node_previously_visited) { 2622263576cSLin Ming if (pre_order_visit) { 26395b482a8SLen Brown status = 2642263576cSLin Ming pre_order_visit(child_node, level, 2652263576cSLin Ming context, 26695b482a8SLen Brown return_value); 2672263576cSLin Ming } 2682263576cSLin Ming } else { 2692263576cSLin Ming if (post_order_visit) { 2702263576cSLin Ming status = 2712263576cSLin Ming post_order_visit(child_node, level, 2722263576cSLin Ming context, 2732263576cSLin Ming return_value); 2742263576cSLin Ming } 2752263576cSLin Ming } 27695b482a8SLen Brown 27795b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 27895b482a8SLen Brown mutex_status = 2792263576cSLin Ming acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 28095b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 2812263576cSLin Ming return_ACPI_STATUS(mutex_status); 28295b482a8SLen Brown } 28395b482a8SLen Brown } 28495b482a8SLen Brown 28595b482a8SLen Brown switch (status) { 28695b482a8SLen Brown case AE_OK: 28795b482a8SLen Brown case AE_CTRL_DEPTH: 28895b482a8SLen Brown 28995b482a8SLen Brown /* Just keep going */ 29095b482a8SLen Brown break; 29195b482a8SLen Brown 29295b482a8SLen Brown case AE_CTRL_TERMINATE: 29395b482a8SLen Brown 29495b482a8SLen Brown /* Exit now, with OK status */ 29595b482a8SLen Brown 29695b482a8SLen Brown return_ACPI_STATUS(AE_OK); 29795b482a8SLen Brown 29895b482a8SLen Brown default: 29995b482a8SLen Brown 30095b482a8SLen Brown /* All others are valid exceptions */ 30195b482a8SLen Brown 30295b482a8SLen Brown return_ACPI_STATUS(status); 30395b482a8SLen Brown } 30495b482a8SLen Brown } 30595b482a8SLen Brown 30695b482a8SLen Brown /* 30795b482a8SLen Brown * Depth first search: Attempt to go down another level in the 30895b482a8SLen Brown * namespace if we are allowed to. Don't go any further if we have 30995b482a8SLen Brown * reached the caller specified maximum depth or if the user 31095b482a8SLen Brown * function has specified that the maximum depth has been reached. 31195b482a8SLen Brown */ 3122263576cSLin Ming if (!node_previously_visited && 3132263576cSLin Ming (level < max_depth) && (status != AE_CTRL_DEPTH)) { 3148c725bf9SBob Moore if (child_node->child) { 31595b482a8SLen Brown 31695b482a8SLen Brown /* There is at least one child of this node, visit it */ 31795b482a8SLen Brown 31895b482a8SLen Brown level++; 31995b482a8SLen Brown parent_node = child_node; 3202263576cSLin Ming child_node = 3212263576cSLin Ming acpi_ns_get_next_node(parent_node, NULL); 3222263576cSLin Ming continue; 32395b482a8SLen Brown } 32495b482a8SLen Brown } 3252263576cSLin Ming 3262263576cSLin Ming /* No more children, re-visit this node */ 3272263576cSLin Ming 3282263576cSLin Ming if (!node_previously_visited) { 3292263576cSLin Ming node_previously_visited = TRUE; 3302263576cSLin Ming continue; 3312263576cSLin Ming } 3322263576cSLin Ming 3332263576cSLin Ming /* No more children, visit peers */ 3342263576cSLin Ming 3352263576cSLin Ming child_node = acpi_ns_get_next_node(parent_node, child_node); 3362263576cSLin Ming if (child_node) { 3372263576cSLin Ming node_previously_visited = FALSE; 3382263576cSLin Ming } 3392263576cSLin Ming 3402263576cSLin Ming /* No peers, re-visit parent */ 3412263576cSLin Ming 3422263576cSLin Ming else { 34395b482a8SLen Brown /* 34495b482a8SLen Brown * No more children of this node (acpi_ns_get_next_node failed), go 34595b482a8SLen Brown * back upwards in the namespace tree to the node's parent. 34695b482a8SLen Brown */ 34795b482a8SLen Brown level--; 34895b482a8SLen Brown child_node = parent_node; 349c45b5c09SAlexey Starikovskiy parent_node = parent_node->parent; 3502263576cSLin Ming 3512263576cSLin Ming node_previously_visited = TRUE; 35295b482a8SLen Brown } 35395b482a8SLen Brown } 35495b482a8SLen Brown 35595b482a8SLen Brown /* Complete walk, not terminated by user function */ 35695b482a8SLen Brown 35795b482a8SLen Brown return_ACPI_STATUS(AE_OK); 35895b482a8SLen Brown } 359