linux/drivers/acpi/acpica/nswalk.c
<<
>>
Prefs
   1/******************************************************************************
   2 *
   3 * Module Name: nswalk - Functions for walking the ACPI namespace
   4 *
   5 *****************************************************************************/
   6
   7/*
   8 * Copyright (C) 2000 - 2011, 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
  49ACPI_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 ******************************************************************************/
  68struct 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
 106struct 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 *              pre_order_visit     - Called during tree pre-order visit
 160 *                                    when an object of "Type" is found
 161 *              post_order_visit    - Called during tree post-order visit
 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
 183acpi_status
 184acpi_ns_walk_namespace(acpi_object_type type,
 185                       acpi_handle start_node,
 186                       u32 max_depth,
 187                       u32 flags,
 188                       acpi_walk_callback pre_order_visit,
 189                       acpi_walk_callback post_order_visit,
 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 pre-order or post-order
 259                         * or both.
 260                         */
 261                        if (!node_previously_visited) {
 262                                if (pre_order_visit) {
 263                                        status =
 264                                            pre_order_visit(child_node, level,
 265                                                            context,
 266                                                            return_value);
 267                                }
 268                        } else {
 269                                if (post_order_visit) {
 270                                        status =
 271                                            post_order_visit(child_node, level,
 272                                                             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