1*95b482a8SLen Brown /****************************************************************************** 2*95b482a8SLen Brown * 3*95b482a8SLen Brown * Module Name: nswalk - Functions for walking the ACPI namespace 4*95b482a8SLen Brown * 5*95b482a8SLen Brown *****************************************************************************/ 6*95b482a8SLen Brown 7*95b482a8SLen Brown /* 8*95b482a8SLen Brown * Copyright (C) 2000 - 2008, Intel Corp. 9*95b482a8SLen Brown * All rights reserved. 10*95b482a8SLen Brown * 11*95b482a8SLen Brown * Redistribution and use in source and binary forms, with or without 12*95b482a8SLen Brown * modification, are permitted provided that the following conditions 13*95b482a8SLen Brown * are met: 14*95b482a8SLen Brown * 1. Redistributions of source code must retain the above copyright 15*95b482a8SLen Brown * notice, this list of conditions, and the following disclaimer, 16*95b482a8SLen Brown * without modification. 17*95b482a8SLen Brown * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18*95b482a8SLen Brown * substantially similar to the "NO WARRANTY" disclaimer below 19*95b482a8SLen Brown * ("Disclaimer") and any redistribution must be conditioned upon 20*95b482a8SLen Brown * including a substantially similar Disclaimer requirement for further 21*95b482a8SLen Brown * binary redistribution. 22*95b482a8SLen Brown * 3. Neither the names of the above-listed copyright holders nor the names 23*95b482a8SLen Brown * of any contributors may be used to endorse or promote products derived 24*95b482a8SLen Brown * from this software without specific prior written permission. 25*95b482a8SLen Brown * 26*95b482a8SLen Brown * Alternatively, this software may be distributed under the terms of the 27*95b482a8SLen Brown * GNU General Public License ("GPL") version 2 as published by the Free 28*95b482a8SLen Brown * Software Foundation. 29*95b482a8SLen Brown * 30*95b482a8SLen Brown * NO WARRANTY 31*95b482a8SLen Brown * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32*95b482a8SLen Brown * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33*95b482a8SLen Brown * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34*95b482a8SLen Brown * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35*95b482a8SLen Brown * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36*95b482a8SLen Brown * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37*95b482a8SLen Brown * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38*95b482a8SLen Brown * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39*95b482a8SLen Brown * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40*95b482a8SLen Brown * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41*95b482a8SLen Brown * POSSIBILITY OF SUCH DAMAGES. 42*95b482a8SLen Brown */ 43*95b482a8SLen Brown 44*95b482a8SLen Brown #include <acpi/acpi.h> 45*95b482a8SLen Brown #include <acpi/accommon.h> 46*95b482a8SLen Brown #include <acpi/acnamesp.h> 47*95b482a8SLen Brown 48*95b482a8SLen Brown #define _COMPONENT ACPI_NAMESPACE 49*95b482a8SLen Brown ACPI_MODULE_NAME("nswalk") 50*95b482a8SLen Brown 51*95b482a8SLen Brown /******************************************************************************* 52*95b482a8SLen Brown * 53*95b482a8SLen Brown * FUNCTION: acpi_ns_get_next_node 54*95b482a8SLen Brown * 55*95b482a8SLen Brown * PARAMETERS: Type - Type of node to be searched for 56*95b482a8SLen Brown * parent_node - Parent node whose children we are 57*95b482a8SLen Brown * getting 58*95b482a8SLen Brown * child_node - Previous child that was found. 59*95b482a8SLen Brown * The NEXT child will be returned 60*95b482a8SLen Brown * 61*95b482a8SLen Brown * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if 62*95b482a8SLen Brown * none is found. 63*95b482a8SLen Brown * 64*95b482a8SLen Brown * DESCRIPTION: Return the next peer node within the namespace. If Handle 65*95b482a8SLen Brown * is valid, Scope is ignored. Otherwise, the first node 66*95b482a8SLen Brown * within Scope is returned. 67*95b482a8SLen Brown * 68*95b482a8SLen Brown ******************************************************************************/ 69*95b482a8SLen Brown struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node 70*95b482a8SLen Brown *parent_node, struct acpi_namespace_node 71*95b482a8SLen Brown *child_node) 72*95b482a8SLen Brown { 73*95b482a8SLen Brown struct acpi_namespace_node *next_node = NULL; 74*95b482a8SLen Brown 75*95b482a8SLen Brown ACPI_FUNCTION_ENTRY(); 76*95b482a8SLen Brown 77*95b482a8SLen Brown if (!child_node) { 78*95b482a8SLen Brown 79*95b482a8SLen Brown /* It's really the parent's _scope_ that we want */ 80*95b482a8SLen Brown 81*95b482a8SLen Brown next_node = parent_node->child; 82*95b482a8SLen Brown } 83*95b482a8SLen Brown 84*95b482a8SLen Brown else { 85*95b482a8SLen Brown /* Start search at the NEXT node */ 86*95b482a8SLen Brown 87*95b482a8SLen Brown next_node = acpi_ns_get_next_valid_node(child_node); 88*95b482a8SLen Brown } 89*95b482a8SLen Brown 90*95b482a8SLen Brown /* If any type is OK, we are done */ 91*95b482a8SLen Brown 92*95b482a8SLen Brown if (type == ACPI_TYPE_ANY) { 93*95b482a8SLen Brown 94*95b482a8SLen Brown /* next_node is NULL if we are at the end-of-list */ 95*95b482a8SLen Brown 96*95b482a8SLen Brown return (next_node); 97*95b482a8SLen Brown } 98*95b482a8SLen Brown 99*95b482a8SLen Brown /* Must search for the node -- but within this scope only */ 100*95b482a8SLen Brown 101*95b482a8SLen Brown while (next_node) { 102*95b482a8SLen Brown 103*95b482a8SLen Brown /* If type matches, we are done */ 104*95b482a8SLen Brown 105*95b482a8SLen Brown if (next_node->type == type) { 106*95b482a8SLen Brown return (next_node); 107*95b482a8SLen Brown } 108*95b482a8SLen Brown 109*95b482a8SLen Brown /* Otherwise, move on to the next node */ 110*95b482a8SLen Brown 111*95b482a8SLen Brown next_node = acpi_ns_get_next_valid_node(next_node); 112*95b482a8SLen Brown } 113*95b482a8SLen Brown 114*95b482a8SLen Brown /* Not found */ 115*95b482a8SLen Brown 116*95b482a8SLen Brown return (NULL); 117*95b482a8SLen Brown } 118*95b482a8SLen Brown 119*95b482a8SLen Brown /******************************************************************************* 120*95b482a8SLen Brown * 121*95b482a8SLen Brown * FUNCTION: acpi_ns_walk_namespace 122*95b482a8SLen Brown * 123*95b482a8SLen Brown * PARAMETERS: Type - acpi_object_type to search for 124*95b482a8SLen Brown * start_node - Handle in namespace where search begins 125*95b482a8SLen Brown * max_depth - Depth to which search is to reach 126*95b482a8SLen Brown * Flags - Whether to unlock the NS before invoking 127*95b482a8SLen Brown * the callback routine 128*95b482a8SLen Brown * user_function - Called when an object of "Type" is found 129*95b482a8SLen Brown * Context - Passed to user function 130*95b482a8SLen Brown * return_value - from the user_function if terminated early. 131*95b482a8SLen Brown * Otherwise, returns NULL. 132*95b482a8SLen Brown * RETURNS: Status 133*95b482a8SLen Brown * 134*95b482a8SLen Brown * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 135*95b482a8SLen Brown * starting (and ending) at the node specified by start_handle. 136*95b482a8SLen Brown * The user_function is called whenever a node that matches 137*95b482a8SLen Brown * the type parameter is found. If the user function returns 138*95b482a8SLen Brown * a non-zero value, the search is terminated immediately and this 139*95b482a8SLen Brown * value is returned to the caller. 140*95b482a8SLen Brown * 141*95b482a8SLen Brown * The point of this procedure is to provide a generic namespace 142*95b482a8SLen Brown * walk routine that can be called from multiple places to 143*95b482a8SLen Brown * provide multiple services; the User Function can be tailored 144*95b482a8SLen Brown * to each task, whether it is a print function, a compare 145*95b482a8SLen Brown * function, etc. 146*95b482a8SLen Brown * 147*95b482a8SLen Brown ******************************************************************************/ 148*95b482a8SLen Brown 149*95b482a8SLen Brown acpi_status 150*95b482a8SLen Brown acpi_ns_walk_namespace(acpi_object_type type, 151*95b482a8SLen Brown acpi_handle start_node, 152*95b482a8SLen Brown u32 max_depth, 153*95b482a8SLen Brown u32 flags, 154*95b482a8SLen Brown acpi_walk_callback user_function, 155*95b482a8SLen Brown void *context, void **return_value) 156*95b482a8SLen Brown { 157*95b482a8SLen Brown acpi_status status; 158*95b482a8SLen Brown acpi_status mutex_status; 159*95b482a8SLen Brown struct acpi_namespace_node *child_node; 160*95b482a8SLen Brown struct acpi_namespace_node *parent_node; 161*95b482a8SLen Brown acpi_object_type child_type; 162*95b482a8SLen Brown u32 level; 163*95b482a8SLen Brown 164*95b482a8SLen Brown ACPI_FUNCTION_TRACE(ns_walk_namespace); 165*95b482a8SLen Brown 166*95b482a8SLen Brown /* Special case for the namespace Root Node */ 167*95b482a8SLen Brown 168*95b482a8SLen Brown if (start_node == ACPI_ROOT_OBJECT) { 169*95b482a8SLen Brown start_node = acpi_gbl_root_node; 170*95b482a8SLen Brown } 171*95b482a8SLen Brown 172*95b482a8SLen Brown /* Null child means "get first node" */ 173*95b482a8SLen Brown 174*95b482a8SLen Brown parent_node = start_node; 175*95b482a8SLen Brown child_node = NULL; 176*95b482a8SLen Brown child_type = ACPI_TYPE_ANY; 177*95b482a8SLen Brown level = 1; 178*95b482a8SLen Brown 179*95b482a8SLen Brown /* 180*95b482a8SLen Brown * Traverse the tree of nodes until we bubble back up to where we 181*95b482a8SLen Brown * started. When Level is zero, the loop is done because we have 182*95b482a8SLen Brown * bubbled up to (and passed) the original parent handle (start_entry) 183*95b482a8SLen Brown */ 184*95b482a8SLen Brown while (level > 0) { 185*95b482a8SLen Brown 186*95b482a8SLen Brown /* Get the next node in this scope. Null if not found */ 187*95b482a8SLen Brown 188*95b482a8SLen Brown status = AE_OK; 189*95b482a8SLen Brown child_node = 190*95b482a8SLen Brown acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, 191*95b482a8SLen Brown child_node); 192*95b482a8SLen Brown if (child_node) { 193*95b482a8SLen Brown 194*95b482a8SLen Brown /* Found next child, get the type if we are not searching for ANY */ 195*95b482a8SLen Brown 196*95b482a8SLen Brown if (type != ACPI_TYPE_ANY) { 197*95b482a8SLen Brown child_type = child_node->type; 198*95b482a8SLen Brown } 199*95b482a8SLen Brown 200*95b482a8SLen Brown /* 201*95b482a8SLen Brown * Ignore all temporary namespace nodes (created during control 202*95b482a8SLen Brown * method execution) unless told otherwise. These temporary nodes 203*95b482a8SLen Brown * can cause a race condition because they can be deleted during the 204*95b482a8SLen Brown * execution of the user function (if the namespace is unlocked before 205*95b482a8SLen Brown * invocation of the user function.) Only the debugger namespace dump 206*95b482a8SLen Brown * will examine the temporary nodes. 207*95b482a8SLen Brown */ 208*95b482a8SLen Brown if ((child_node->flags & ANOBJ_TEMPORARY) && 209*95b482a8SLen Brown !(flags & ACPI_NS_WALK_TEMP_NODES)) { 210*95b482a8SLen Brown status = AE_CTRL_DEPTH; 211*95b482a8SLen Brown } 212*95b482a8SLen Brown 213*95b482a8SLen Brown /* Type must match requested type */ 214*95b482a8SLen Brown 215*95b482a8SLen Brown else if (child_type == type) { 216*95b482a8SLen Brown /* 217*95b482a8SLen Brown * Found a matching node, invoke the user callback function. 218*95b482a8SLen Brown * Unlock the namespace if flag is set. 219*95b482a8SLen Brown */ 220*95b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 221*95b482a8SLen Brown mutex_status = 222*95b482a8SLen Brown acpi_ut_release_mutex 223*95b482a8SLen Brown (ACPI_MTX_NAMESPACE); 224*95b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 225*95b482a8SLen Brown return_ACPI_STATUS 226*95b482a8SLen Brown (mutex_status); 227*95b482a8SLen Brown } 228*95b482a8SLen Brown } 229*95b482a8SLen Brown 230*95b482a8SLen Brown status = 231*95b482a8SLen Brown user_function(child_node, level, context, 232*95b482a8SLen Brown return_value); 233*95b482a8SLen Brown 234*95b482a8SLen Brown if (flags & ACPI_NS_WALK_UNLOCK) { 235*95b482a8SLen Brown mutex_status = 236*95b482a8SLen Brown acpi_ut_acquire_mutex 237*95b482a8SLen Brown (ACPI_MTX_NAMESPACE); 238*95b482a8SLen Brown if (ACPI_FAILURE(mutex_status)) { 239*95b482a8SLen Brown return_ACPI_STATUS 240*95b482a8SLen Brown (mutex_status); 241*95b482a8SLen Brown } 242*95b482a8SLen Brown } 243*95b482a8SLen Brown 244*95b482a8SLen Brown switch (status) { 245*95b482a8SLen Brown case AE_OK: 246*95b482a8SLen Brown case AE_CTRL_DEPTH: 247*95b482a8SLen Brown 248*95b482a8SLen Brown /* Just keep going */ 249*95b482a8SLen Brown break; 250*95b482a8SLen Brown 251*95b482a8SLen Brown case AE_CTRL_TERMINATE: 252*95b482a8SLen Brown 253*95b482a8SLen Brown /* Exit now, with OK status */ 254*95b482a8SLen Brown 255*95b482a8SLen Brown return_ACPI_STATUS(AE_OK); 256*95b482a8SLen Brown 257*95b482a8SLen Brown default: 258*95b482a8SLen Brown 259*95b482a8SLen Brown /* All others are valid exceptions */ 260*95b482a8SLen Brown 261*95b482a8SLen Brown return_ACPI_STATUS(status); 262*95b482a8SLen Brown } 263*95b482a8SLen Brown } 264*95b482a8SLen Brown 265*95b482a8SLen Brown /* 266*95b482a8SLen Brown * Depth first search: Attempt to go down another level in the 267*95b482a8SLen Brown * namespace if we are allowed to. Don't go any further if we have 268*95b482a8SLen Brown * reached the caller specified maximum depth or if the user 269*95b482a8SLen Brown * function has specified that the maximum depth has been reached. 270*95b482a8SLen Brown */ 271*95b482a8SLen Brown if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { 272*95b482a8SLen Brown if (acpi_ns_get_next_node 273*95b482a8SLen Brown (ACPI_TYPE_ANY, child_node, NULL)) { 274*95b482a8SLen Brown 275*95b482a8SLen Brown /* There is at least one child of this node, visit it */ 276*95b482a8SLen Brown 277*95b482a8SLen Brown level++; 278*95b482a8SLen Brown parent_node = child_node; 279*95b482a8SLen Brown child_node = NULL; 280*95b482a8SLen Brown } 281*95b482a8SLen Brown } 282*95b482a8SLen Brown } else { 283*95b482a8SLen Brown /* 284*95b482a8SLen Brown * No more children of this node (acpi_ns_get_next_node failed), go 285*95b482a8SLen Brown * back upwards in the namespace tree to the node's parent. 286*95b482a8SLen Brown */ 287*95b482a8SLen Brown level--; 288*95b482a8SLen Brown child_node = parent_node; 289*95b482a8SLen Brown parent_node = acpi_ns_get_parent_node(parent_node); 290*95b482a8SLen Brown } 291*95b482a8SLen Brown } 292*95b482a8SLen Brown 293*95b482a8SLen Brown /* Complete walk, not terminated by user function */ 294*95b482a8SLen Brown 295*95b482a8SLen Brown return_ACPI_STATUS(AE_OK); 296*95b482a8SLen Brown } 297