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: Type - Type of node to be searched for 56 * parent_node - Parent node whose children we are 57 * getting 58 * child_node - Previous child that was found. 59 * The NEXT child will be returned 60 * 61 * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if 62 * none is found. 63 * 64 * DESCRIPTION: Return the next peer node within the namespace. If Handle 65 * is valid, Scope is ignored. Otherwise, the first node 66 * within Scope is returned. 67 * 68 ******************************************************************************/ 69 struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node 70 *parent_node, struct acpi_namespace_node 71 *child_node) 72 { 73 struct acpi_namespace_node *next_node = NULL; 74 75 ACPI_FUNCTION_ENTRY(); 76 77 if (!child_node) { 78 79 /* It's really the parent's _scope_ that we want */ 80 81 next_node = parent_node->child; 82 } 83 84 else { 85 /* Start search at the NEXT node */ 86 87 next_node = acpi_ns_get_next_valid_node(child_node); 88 } 89 90 /* If any type is OK, we are done */ 91 92 if (type == ACPI_TYPE_ANY) { 93 94 /* next_node is NULL if we are at the end-of-list */ 95 96 return (next_node); 97 } 98 99 /* Must search for the node -- but within this scope only */ 100 101 while (next_node) { 102 103 /* If type matches, we are done */ 104 105 if (next_node->type == type) { 106 return (next_node); 107 } 108 109 /* Otherwise, move on to the next node */ 110 111 next_node = acpi_ns_get_next_valid_node(next_node); 112 } 113 114 /* Not found */ 115 116 return (NULL); 117 } 118 119 /******************************************************************************* 120 * 121 * FUNCTION: acpi_ns_walk_namespace 122 * 123 * PARAMETERS: Type - acpi_object_type to search for 124 * start_node - Handle in namespace where search begins 125 * max_depth - Depth to which search is to reach 126 * Flags - Whether to unlock the NS before invoking 127 * the callback routine 128 * user_function - Called when an object of "Type" is found 129 * Context - Passed to user function 130 * return_value - from the user_function if terminated early. 131 * Otherwise, returns NULL. 132 * RETURNS: Status 133 * 134 * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 135 * starting (and ending) at the node specified by start_handle. 136 * The user_function is called whenever a node that matches 137 * the type parameter is found. If the user function returns 138 * a non-zero value, the search is terminated immediately and 139 * this value is returned to the caller. 140 * 141 * The point of this procedure is to provide a generic namespace 142 * walk routine that can be called from multiple places to 143 * provide multiple services; the User Function can be tailored 144 * to each task, whether it is a print function, a compare 145 * function, etc. 146 * 147 ******************************************************************************/ 148 149 acpi_status 150 acpi_ns_walk_namespace(acpi_object_type type, 151 acpi_handle start_node, 152 u32 max_depth, 153 u32 flags, 154 acpi_walk_callback user_function, 155 void *context, void **return_value) 156 { 157 acpi_status status; 158 acpi_status mutex_status; 159 struct acpi_namespace_node *child_node; 160 struct acpi_namespace_node *parent_node; 161 acpi_object_type child_type; 162 u32 level; 163 164 ACPI_FUNCTION_TRACE(ns_walk_namespace); 165 166 /* Special case for the namespace Root Node */ 167 168 if (start_node == ACPI_ROOT_OBJECT) { 169 start_node = acpi_gbl_root_node; 170 } 171 172 /* Null child means "get first node" */ 173 174 parent_node = start_node; 175 child_node = NULL; 176 child_type = ACPI_TYPE_ANY; 177 level = 1; 178 179 /* 180 * Traverse the tree of nodes until we bubble back up to where we 181 * started. When Level is zero, the loop is done because we have 182 * bubbled up to (and passed) the original parent handle (start_entry) 183 */ 184 while (level > 0) { 185 186 /* Get the next node in this scope. Null if not found */ 187 188 status = AE_OK; 189 child_node = 190 acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, 191 child_node); 192 if (child_node) { 193 194 /* Found next child, get the type if we are not searching for ANY */ 195 196 if (type != ACPI_TYPE_ANY) { 197 child_type = child_node->type; 198 } 199 200 /* 201 * Ignore all temporary namespace nodes (created during control 202 * method execution) unless told otherwise. These temporary nodes 203 * can cause a race condition because they can be deleted during 204 * the execution of the user function (if the namespace is 205 * unlocked before invocation of the user function.) Only the 206 * debugger namespace dump will examine the temporary nodes. 207 */ 208 if ((child_node->flags & ANOBJ_TEMPORARY) && 209 !(flags & ACPI_NS_WALK_TEMP_NODES)) { 210 status = AE_CTRL_DEPTH; 211 } 212 213 /* Type must match requested type */ 214 215 else if (child_type == type) { 216 /* 217 * Found a matching node, invoke the user callback function. 218 * Unlock the namespace if flag is set. 219 */ 220 if (flags & ACPI_NS_WALK_UNLOCK) { 221 mutex_status = 222 acpi_ut_release_mutex 223 (ACPI_MTX_NAMESPACE); 224 if (ACPI_FAILURE(mutex_status)) { 225 return_ACPI_STATUS 226 (mutex_status); 227 } 228 } 229 230 status = 231 user_function(child_node, level, context, 232 return_value); 233 234 if (flags & ACPI_NS_WALK_UNLOCK) { 235 mutex_status = 236 acpi_ut_acquire_mutex 237 (ACPI_MTX_NAMESPACE); 238 if (ACPI_FAILURE(mutex_status)) { 239 return_ACPI_STATUS 240 (mutex_status); 241 } 242 } 243 244 switch (status) { 245 case AE_OK: 246 case AE_CTRL_DEPTH: 247 248 /* Just keep going */ 249 break; 250 251 case AE_CTRL_TERMINATE: 252 253 /* Exit now, with OK status */ 254 255 return_ACPI_STATUS(AE_OK); 256 257 default: 258 259 /* All others are valid exceptions */ 260 261 return_ACPI_STATUS(status); 262 } 263 } 264 265 /* 266 * Depth first search: Attempt to go down another level in the 267 * namespace if we are allowed to. Don't go any further if we have 268 * reached the caller specified maximum depth or if the user 269 * function has specified that the maximum depth has been reached. 270 */ 271 if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { 272 if (acpi_ns_get_next_node 273 (ACPI_TYPE_ANY, child_node, NULL)) { 274 275 /* There is at least one child of this node, visit it */ 276 277 level++; 278 parent_node = child_node; 279 child_node = NULL; 280 } 281 } 282 } else { 283 /* 284 * No more children of this node (acpi_ns_get_next_node failed), go 285 * back upwards in the namespace tree to the node's parent. 286 */ 287 level--; 288 child_node = parent_node; 289 parent_node = acpi_ns_get_parent_node(parent_node); 290 } 291 } 292 293 /* Complete walk, not terminated by user function */ 294 295 return_ACPI_STATUS(AE_OK); 296 } 297