Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /******************************************************************************
  2.  *
  3.  * Module Name: nswalk - Functions for walking the ACPI namespace
  4.  *
  5.  *****************************************************************************/
  6.  
  7. /*
  8.  * Copyright (C) 2000 - 2015, 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.