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