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