root/drivers/acpi/acpica/nswalk.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ACPI_MODULE_NAME
  2. acpi_ns_get_next_node_typed
  3. acpi_ns_walk_namespace

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /******************************************************************************
   3  *
   4  * Module Name: nswalk - Functions for walking the ACPI namespace
   5  *
   6  * Copyright (C) 2000 - 2019, Intel Corp.
   7  *
   8  *****************************************************************************/
   9 
  10 #include <acpi/acpi.h>
  11 #include "accommon.h"
  12 #include "acnamesp.h"
  13 
  14 #define _COMPONENT          ACPI_NAMESPACE
  15 ACPI_MODULE_NAME("nswalk")
  16 
  17 /*******************************************************************************
  18  *
  19  * FUNCTION:    acpi_ns_get_next_node
  20  *
  21  * PARAMETERS:  parent_node         - Parent node whose children we are
  22  *                                    getting
  23  *              child_node          - Previous child that was found.
  24  *                                    The NEXT child will be returned
  25  *
  26  * RETURN:      struct acpi_namespace_node - Pointer to the NEXT child or NULL if
  27  *                                    none is found.
  28  *
  29  * DESCRIPTION: Return the next peer node within the namespace. If Handle
  30  *              is valid, Scope is ignored. Otherwise, the first node
  31  *              within Scope is returned.
  32  *
  33  ******************************************************************************/
  34 struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
  35                                                   *parent_node,
  36                                                   struct acpi_namespace_node
  37                                                   *child_node)
  38 {
  39         ACPI_FUNCTION_ENTRY();
  40 
  41         if (!child_node) {
  42 
  43                 /* It's really the parent's _scope_ that we want */
  44 
  45                 return (parent_node->child);
  46         }
  47 
  48         /* Otherwise just return the next peer */
  49 
  50         return (child_node->peer);
  51 }
  52 
  53 /*******************************************************************************
  54  *
  55  * FUNCTION:    acpi_ns_get_next_node_typed
  56  *
  57  * PARAMETERS:  type                - Type of node to be searched for
  58  *              parent_node         - Parent node whose children we are
  59  *                                    getting
  60  *              child_node          - Previous child that was found.
  61  *                                    The NEXT child will be returned
  62  *
  63  * RETURN:      struct acpi_namespace_node - Pointer to the NEXT child or NULL if
  64  *                                    none is found.
  65  *
  66  * DESCRIPTION: Return the next peer node within the namespace. If Handle
  67  *              is valid, Scope is ignored. Otherwise, the first node
  68  *              within Scope is returned.
  69  *
  70  ******************************************************************************/
  71 
  72 struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
  73                                                         struct
  74                                                         acpi_namespace_node
  75                                                         *parent_node,
  76                                                         struct
  77                                                         acpi_namespace_node
  78                                                         *child_node)
  79 {
  80         struct acpi_namespace_node *next_node = NULL;
  81 
  82         ACPI_FUNCTION_ENTRY();
  83 
  84         next_node = acpi_ns_get_next_node(parent_node, child_node);
  85 
  86 
  87         /* If any type is OK, we are done */
  88 
  89         if (type == ACPI_TYPE_ANY) {
  90 
  91                 /* next_node is NULL if we are at the end-of-list */
  92 
  93                 return (next_node);
  94         }
  95 
  96         /* Must search for the node -- but within this scope only */
  97 
  98         while (next_node) {
  99 
 100                 /* If type matches, we are done */
 101 
 102                 if (next_node->type == type) {
 103                         return (next_node);
 104                 }
 105 
 106                 /* Otherwise, move on to the next peer node */
 107 
 108                 next_node = next_node->peer;
 109         }
 110 
 111         /* Not found */
 112 
 113         return (NULL);
 114 }
 115 
 116 /*******************************************************************************
 117  *
 118  * FUNCTION:    acpi_ns_walk_namespace
 119  *
 120  * PARAMETERS:  type                - acpi_object_type to search for
 121  *              start_node          - Handle in namespace where search begins
 122  *              max_depth           - Depth to which search is to reach
 123  *              flags               - Whether to unlock the NS before invoking
 124  *                                    the callback routine
 125  *              descending_callback - Called during tree descent
 126  *                                    when an object of "Type" is found
 127  *              ascending_callback  - Called during tree ascent
 128  *                                    when an object of "Type" is found
 129  *              context             - Passed to user function(s) above
 130  *              return_value        - from the user_function if terminated
 131  *                                    early. 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 callback function is called whenever a node that matches
 137  *              the type parameter is found. If the callback 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 callback function(s) can be
 144  *              tailored to each task, whether it is a print function,
 145  *              a compare 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 descending_callback,
 155                        acpi_walk_callback ascending_callback,
 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         u8 node_previously_visited = FALSE;
 165 
 166         ACPI_FUNCTION_TRACE(ns_walk_namespace);
 167 
 168         /* Special case for the namespace Root Node */
 169 
 170         if (start_node == ACPI_ROOT_OBJECT) {
 171                 start_node = acpi_gbl_root_node;
 172         }
 173 
 174         /* Null child means "get first node" */
 175 
 176         parent_node = start_node;
 177         child_node = acpi_ns_get_next_node(parent_node, NULL);
 178         child_type = ACPI_TYPE_ANY;
 179         level = 1;
 180 
 181         /*
 182          * Traverse the tree of nodes until we bubble back up to where we
 183          * started. When Level is zero, the loop is done because we have
 184          * bubbled up to (and passed) the original parent handle (start_entry)
 185          */
 186         while (level > 0 && child_node) {
 187                 status = AE_OK;
 188 
 189                 /* Found next child, get the type if we are not searching for ANY */
 190 
 191                 if (type != ACPI_TYPE_ANY) {
 192                         child_type = child_node->type;
 193                 }
 194 
 195                 /*
 196                  * Ignore all temporary namespace nodes (created during control
 197                  * method execution) unless told otherwise. These temporary nodes
 198                  * can cause a race condition because they can be deleted during
 199                  * the execution of the user function (if the namespace is
 200                  * unlocked before invocation of the user function.) Only the
 201                  * debugger namespace dump will examine the temporary nodes.
 202                  */
 203                 if ((child_node->flags & ANOBJ_TEMPORARY) &&
 204                     !(flags & ACPI_NS_WALK_TEMP_NODES)) {
 205                         status = AE_CTRL_DEPTH;
 206                 }
 207 
 208                 /* Type must match requested type */
 209 
 210                 else if (child_type == type) {
 211                         /*
 212                          * Found a matching node, invoke the user callback function.
 213                          * Unlock the namespace if flag is set.
 214                          */
 215                         if (flags & ACPI_NS_WALK_UNLOCK) {
 216                                 mutex_status =
 217                                     acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 218                                 if (ACPI_FAILURE(mutex_status)) {
 219                                         return_ACPI_STATUS(mutex_status);
 220                                 }
 221                         }
 222 
 223                         /*
 224                          * Invoke the user function, either descending, ascending,
 225                          * or both.
 226                          */
 227                         if (!node_previously_visited) {
 228                                 if (descending_callback) {
 229                                         status =
 230                                             descending_callback(child_node,
 231                                                                 level, context,
 232                                                                 return_value);
 233                                 }
 234                         } else {
 235                                 if (ascending_callback) {
 236                                         status =
 237                                             ascending_callback(child_node,
 238                                                                level, context,
 239                                                                return_value);
 240                                 }
 241                         }
 242 
 243                         if (flags & ACPI_NS_WALK_UNLOCK) {
 244                                 mutex_status =
 245                                     acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
 246                                 if (ACPI_FAILURE(mutex_status)) {
 247                                         return_ACPI_STATUS(mutex_status);
 248                                 }
 249                         }
 250 
 251                         switch (status) {
 252                         case AE_OK:
 253                         case AE_CTRL_DEPTH:
 254 
 255                                 /* Just keep going */
 256                                 break;
 257 
 258                         case AE_CTRL_TERMINATE:
 259 
 260                                 /* Exit now, with OK status */
 261 
 262                                 return_ACPI_STATUS(AE_OK);
 263 
 264                         default:
 265 
 266                                 /* All others are valid exceptions */
 267 
 268                                 return_ACPI_STATUS(status);
 269                         }
 270                 }
 271 
 272                 /*
 273                  * Depth first search: Attempt to go down another level in the
 274                  * namespace if we are allowed to. Don't go any further if we have
 275                  * reached the caller specified maximum depth or if the user
 276                  * function has specified that the maximum depth has been reached.
 277                  */
 278                 if (!node_previously_visited &&
 279                     (level < max_depth) && (status != AE_CTRL_DEPTH)) {
 280                         if (child_node->child) {
 281 
 282                                 /* There is at least one child of this node, visit it */
 283 
 284                                 level++;
 285                                 parent_node = child_node;
 286                                 child_node =
 287                                     acpi_ns_get_next_node(parent_node, NULL);
 288                                 continue;
 289                         }
 290                 }
 291 
 292                 /* No more children, re-visit this node */
 293 
 294                 if (!node_previously_visited) {
 295                         node_previously_visited = TRUE;
 296                         continue;
 297                 }
 298 
 299                 /* No more children, visit peers */
 300 
 301                 child_node = acpi_ns_get_next_node(parent_node, child_node);
 302                 if (child_node) {
 303                         node_previously_visited = FALSE;
 304                 }
 305 
 306                 /* No peers, re-visit parent */
 307 
 308                 else {
 309                         /*
 310                          * No more children of this node (acpi_ns_get_next_node failed), go
 311                          * back upwards in the namespace tree to the node's parent.
 312                          */
 313                         level--;
 314                         child_node = parent_node;
 315                         parent_node = parent_node->parent;
 316 
 317                         node_previously_visited = TRUE;
 318                 }
 319         }
 320 
 321         /* Complete walk, not terminated by user function */
 322 
 323         return_ACPI_STATUS(AE_OK);
 324 }

/* [<][>][^][v][top][bottom][index][help] */