1 /****************************************************************************** 2 * 3 * Module Name: nswalk - Functions for walking the ACPI namespace 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, 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 /* Otherwise just return the next peer */ 83 84 return (child_node->peer); 85 } 86 87 /******************************************************************************* 88 * 89 * FUNCTION: acpi_ns_get_next_node_typed 90 * 91 * PARAMETERS: type - Type of node to be searched for 92 * parent_node - Parent node whose children we are 93 * getting 94 * child_node - Previous child that was found. 95 * The NEXT child will be returned 96 * 97 * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if 98 * none is found. 99 * 100 * DESCRIPTION: Return the next peer node within the namespace. If Handle 101 * is valid, Scope is ignored. Otherwise, the first node 102 * within Scope is returned. 103 * 104 ******************************************************************************/ 105 106 struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, 107 struct 108 acpi_namespace_node 109 *parent_node, 110 struct 111 acpi_namespace_node 112 *child_node) 113 { 114 struct acpi_namespace_node *next_node = NULL; 115 116 ACPI_FUNCTION_ENTRY(); 117 118 next_node = acpi_ns_get_next_node(parent_node, child_node); 119 120 121 /* If any type is OK, we are done */ 122 123 if (type == ACPI_TYPE_ANY) { 124 125 /* next_node is NULL if we are at the end-of-list */ 126 127 return (next_node); 128 } 129 130 /* Must search for the node -- but within this scope only */ 131 132 while (next_node) { 133 134 /* If type matches, we are done */ 135 136 if (next_node->type == type) { 137 return (next_node); 138 } 139 140 /* Otherwise, move on to the next peer node */ 141 142 next_node = next_node->peer; 143 } 144 145 /* Not found */ 146 147 return (NULL); 148 } 149 150 /******************************************************************************* 151 * 152 * FUNCTION: acpi_ns_walk_namespace 153 * 154 * PARAMETERS: type - acpi_object_type to search for 155 * start_node - Handle in namespace where search begins 156 * max_depth - Depth to which search is to reach 157 * flags - Whether to unlock the NS before invoking 158 * the callback routine 159 * descending_callback - Called during tree descent 160 * when an object of "Type" is found 161 * ascending_callback - Called during tree ascent 162 * when an object of "Type" is found 163 * context - Passed to user function(s) above 164 * return_value - from the user_function if terminated 165 * early. Otherwise, returns NULL. 166 * RETURNS: Status 167 * 168 * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, 169 * starting (and ending) at the node specified by start_handle. 170 * The callback function is called whenever a node that matches 171 * the type parameter is found. If the callback function returns 172 * a non-zero value, the search is terminated immediately and 173 * this value is returned to the caller. 174 * 175 * The point of this procedure is to provide a generic namespace 176 * walk routine that can be called from multiple places to 177 * provide multiple services; the callback function(s) can be 178 * tailored to each task, whether it is a print function, 179 * a compare function, etc. 180 * 181 ******************************************************************************/ 182 183 acpi_status 184 acpi_ns_walk_namespace(acpi_object_type type, 185 acpi_handle start_node, 186 u32 max_depth, 187 u32 flags, 188 acpi_walk_callback descending_callback, 189 acpi_walk_callback ascending_callback, 190 void *context, void **return_value) 191 { 192 acpi_status status; 193 acpi_status mutex_status; 194 struct acpi_namespace_node *child_node; 195 struct acpi_namespace_node *parent_node; 196 acpi_object_type child_type; 197 u32 level; 198 u8 node_previously_visited = FALSE; 199 200 ACPI_FUNCTION_TRACE(ns_walk_namespace); 201 202 /* Special case for the namespace Root Node */ 203 204 if (start_node == ACPI_ROOT_OBJECT) { 205 start_node = acpi_gbl_root_node; 206 } 207 208 /* Null child means "get first node" */ 209 210 parent_node = start_node; 211 child_node = acpi_ns_get_next_node(parent_node, NULL); 212 child_type = ACPI_TYPE_ANY; 213 level = 1; 214 215 /* 216 * Traverse the tree of nodes until we bubble back up to where we 217 * started. When Level is zero, the loop is done because we have 218 * bubbled up to (and passed) the original parent handle (start_entry) 219 */ 220 while (level > 0 && child_node) { 221 status = AE_OK; 222 223 /* Found next child, get the type if we are not searching for ANY */ 224 225 if (type != ACPI_TYPE_ANY) { 226 child_type = child_node->type; 227 } 228 229 /* 230 * Ignore all temporary namespace nodes (created during control 231 * method execution) unless told otherwise. These temporary nodes 232 * can cause a race condition because they can be deleted during 233 * the execution of the user function (if the namespace is 234 * unlocked before invocation of the user function.) Only the 235 * debugger namespace dump will examine the temporary nodes. 236 */ 237 if ((child_node->flags & ANOBJ_TEMPORARY) && 238 !(flags & ACPI_NS_WALK_TEMP_NODES)) { 239 status = AE_CTRL_DEPTH; 240 } 241 242 /* Type must match requested type */ 243 244 else if (child_type == type) { 245 /* 246 * Found a matching node, invoke the user callback function. 247 * Unlock the namespace if flag is set. 248 */ 249 if (flags & ACPI_NS_WALK_UNLOCK) { 250 mutex_status = 251 acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 252 if (ACPI_FAILURE(mutex_status)) { 253 return_ACPI_STATUS(mutex_status); 254 } 255 } 256 257 /* 258 * Invoke the user function, either descending, ascending, 259 * or both. 260 */ 261 if (!node_previously_visited) { 262 if (descending_callback) { 263 status = 264 descending_callback(child_node, 265 level, context, 266 return_value); 267 } 268 } else { 269 if (ascending_callback) { 270 status = 271 ascending_callback(child_node, 272 level, context, 273 return_value); 274 } 275 } 276 277 if (flags & ACPI_NS_WALK_UNLOCK) { 278 mutex_status = 279 acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 280 if (ACPI_FAILURE(mutex_status)) { 281 return_ACPI_STATUS(mutex_status); 282 } 283 } 284 285 switch (status) { 286 case AE_OK: 287 case AE_CTRL_DEPTH: 288 289 /* Just keep going */ 290 break; 291 292 case AE_CTRL_TERMINATE: 293 294 /* Exit now, with OK status */ 295 296 return_ACPI_STATUS(AE_OK); 297 298 default: 299 300 /* All others are valid exceptions */ 301 302 return_ACPI_STATUS(status); 303 } 304 } 305 306 /* 307 * Depth first search: Attempt to go down another level in the 308 * namespace if we are allowed to. Don't go any further if we have 309 * reached the caller specified maximum depth or if the user 310 * function has specified that the maximum depth has been reached. 311 */ 312 if (!node_previously_visited && 313 (level < max_depth) && (status != AE_CTRL_DEPTH)) { 314 if (child_node->child) { 315 316 /* There is at least one child of this node, visit it */ 317 318 level++; 319 parent_node = child_node; 320 child_node = 321 acpi_ns_get_next_node(parent_node, NULL); 322 continue; 323 } 324 } 325 326 /* No more children, re-visit this node */ 327 328 if (!node_previously_visited) { 329 node_previously_visited = TRUE; 330 continue; 331 } 332 333 /* No more children, visit peers */ 334 335 child_node = acpi_ns_get_next_node(parent_node, child_node); 336 if (child_node) { 337 node_previously_visited = FALSE; 338 } 339 340 /* No peers, re-visit parent */ 341 342 else { 343 /* 344 * No more children of this node (acpi_ns_get_next_node failed), go 345 * back upwards in the namespace tree to the node's parent. 346 */ 347 level--; 348 child_node = parent_node; 349 parent_node = parent_node->parent; 350 351 node_previously_visited = TRUE; 352 } 353 } 354 355 /* Complete walk, not terminated by user function */ 356 357 return_ACPI_STATUS(AE_OK); 358 } 359