nswalk.c revision 231844
138032Speter/******************************************************************************
298125Sgshapiro *
364565Sgshapiro * Module Name: nswalk - Functions for walking the ACPI namespace
438032Speter *
538032Speter *****************************************************************************/
638032Speter
738032Speter/*
838032Speter * Copyright (C) 2000 - 2012, Intel Corp.
938032Speter * All rights reserved.
1038032Speter *
1138032Speter * Redistribution and use in source and binary forms, with or without
12102533Sgshapiro * modification, are permitted provided that the following conditions
13102533Sgshapiro * are met:
1438032Speter * 1. Redistributions of source code must retain the above copyright
1538032Speter *    notice, this list of conditions, and the following disclaimer,
1690795Sgshapiro *    without modification.
1790795Sgshapiro * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1890795Sgshapiro *    substantially similar to the "NO WARRANTY" disclaimer below
1973191Sgshapiro *    ("Disclaimer") and any redistribution must be conditioned upon
2064565Sgshapiro *    including a substantially similar Disclaimer requirement for further
2164565Sgshapiro *    binary redistribution.
2264565Sgshapiro * 3. Neither the names of the above-listed copyright holders nor the names
2390795Sgshapiro *    of any contributors may be used to endorse or promote products derived
2438032Speter *    from this software without specific prior written permission.
2598125Sgshapiro *
2664565Sgshapiro * Alternatively, this software may be distributed under the terms of the
2738032Speter * GNU General Public License ("GPL") version 2 as published by the Free
2838032Speter * Software Foundation.
2938032Speter *
3038032Speter * NO WARRANTY
3138032Speter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3238032Speter * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3338032Speter * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3438032Speter * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3538032Speter * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3638032Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3738032Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3838032Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3938032Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4038032Speter * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4138032Speter * POSSIBILITY OF SUCH DAMAGES.
4238081Speter */
4338032Speter
4438032Speter
4564565Sgshapiro#define __NSWALK_C__
4664565Sgshapiro
4764565Sgshapiro#include <contrib/dev/acpica/include/acpi.h>
4838032Speter#include <contrib/dev/acpica/include/accommon.h>
4938032Speter#include <contrib/dev/acpica/include/acnamesp.h>
5064565Sgshapiro
5138032Speter
5238032Speter#define _COMPONENT          ACPI_NAMESPACE
5338032Speter        ACPI_MODULE_NAME    ("nswalk")
5438032Speter
5538032Speter
5638032Speter/*******************************************************************************
5738032Speter *
5890795Sgshapiro * FUNCTION:    AcpiNsGetNextNode
5998125Sgshapiro *
6090795Sgshapiro * PARAMETERS:  ParentNode          - Parent node whose children we are
6138032Speter *                                    getting
62105016Sgshapiro *              ChildNode           - Previous child that was found.
63105016Sgshapiro *                                    The NEXT child will be returned
6438032Speter *
6538032Speter * RETURN:      ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if
6664565Sgshapiro *                                    none is found.
6738032Speter *
6838032Speter * DESCRIPTION: Return the next peer node within the namespace.  If Handle
6964565Sgshapiro *              is valid, Scope is ignored.  Otherwise, the first node
7038032Speter *              within Scope is returned.
7138032Speter *
7238032Speter ******************************************************************************/
7338032Speter
7490795SgshapiroACPI_NAMESPACE_NODE *
7590795SgshapiroAcpiNsGetNextNode (
7664565Sgshapiro    ACPI_NAMESPACE_NODE     *ParentNode,
7738032Speter    ACPI_NAMESPACE_NODE     *ChildNode)
7838032Speter{
7990795Sgshapiro    ACPI_FUNCTION_ENTRY ();
8090795Sgshapiro
8190795Sgshapiro
8290795Sgshapiro    if (!ChildNode)
8390795Sgshapiro    {
8464565Sgshapiro        /* It's really the parent's _scope_ that we want */
8538032Speter
8638032Speter        return (ParentNode->Child);
8738032Speter    }
8838032Speter
8938032Speter    /* Otherwise just return the next peer */
9038032Speter
9190795Sgshapiro    return (ChildNode->Peer);
9290795Sgshapiro}
9390795Sgshapiro
9490795Sgshapiro
9590795Sgshapiro/*******************************************************************************
9664565Sgshapiro *
9738032Speter * FUNCTION:    AcpiNsGetNextNodeTyped
9864565Sgshapiro *
9964565Sgshapiro * PARAMETERS:  Type                - Type of node to be searched for
10064565Sgshapiro *              ParentNode          - Parent node whose children we are
10164565Sgshapiro *                                    getting
10264565Sgshapiro *              ChildNode           - Previous child that was found.
10364565Sgshapiro *                                    The NEXT child will be returned
10464565Sgshapiro *
10564565Sgshapiro * RETURN:      ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if
10664565Sgshapiro *                                    none is found.
10764565Sgshapiro *
10864565Sgshapiro * DESCRIPTION: Return the next peer node within the namespace.  If Handle
10964565Sgshapiro *              is valid, Scope is ignored.  Otherwise, the first node
11064565Sgshapiro *              within Scope is returned.
11164565Sgshapiro *
11264565Sgshapiro ******************************************************************************/
11364565Sgshapiro
11464565SgshapiroACPI_NAMESPACE_NODE *
11564565SgshapiroAcpiNsGetNextNodeTyped (
11664565Sgshapiro    ACPI_OBJECT_TYPE        Type,
11790795Sgshapiro    ACPI_NAMESPACE_NODE     *ParentNode,
11890795Sgshapiro    ACPI_NAMESPACE_NODE     *ChildNode)
11964565Sgshapiro{
12064565Sgshapiro    ACPI_NAMESPACE_NODE     *NextNode = NULL;
12164565Sgshapiro
12264565Sgshapiro
12364565Sgshapiro    ACPI_FUNCTION_ENTRY ();
12464565Sgshapiro
12564565Sgshapiro
12690795Sgshapiro    NextNode = AcpiNsGetNextNode (ParentNode, ChildNode);
12790795Sgshapiro
12864565Sgshapiro    /* If any type is OK, we are done */
12964565Sgshapiro
13064565Sgshapiro    if (Type == ACPI_TYPE_ANY)
13164565Sgshapiro    {
13264565Sgshapiro        /* NextNode is NULL if we are at the end-of-list */
13364565Sgshapiro
13498125Sgshapiro        return (NextNode);
13590795Sgshapiro    }
13664565Sgshapiro
13764565Sgshapiro    /* Must search for the node -- but within this scope only */
13838032Speter
13938032Speter    while (NextNode)
14038032Speter    {
14138032Speter        /* If type matches, we are done */
14238032Speter
14338032Speter        if (NextNode->Type == Type)
14438032Speter        {
14564565Sgshapiro            return (NextNode);
14638032Speter        }
14764565Sgshapiro
14864565Sgshapiro        /* Otherwise, move on to the next peer node */
14938032Speter
15038032Speter        NextNode = NextNode->Peer;
15164565Sgshapiro    }
152105016Sgshapiro
15338032Speter    /* Not found */
15464565Sgshapiro
15564565Sgshapiro    return (NULL);
15638032Speter}
15764565Sgshapiro
15838032Speter
15964565Sgshapiro/*******************************************************************************
16064565Sgshapiro *
16138032Speter * FUNCTION:    AcpiNsWalkNamespace
16298125Sgshapiro *
16338032Speter * PARAMETERS:  Type                - ACPI_OBJECT_TYPE to search for
16438032Speter *              StartNode           - Handle in namespace where search begins
16538032Speter *              MaxDepth            - Depth to which search is to reach
16638032Speter *              Flags               - Whether to unlock the NS before invoking
16738032Speter *                                    the callback routine
16838032Speter *              PreOrderVisit       - Called during tree pre-order visit
16938032Speter *                                    when an object of "Type" is found
17064565Sgshapiro *              PostOrderVisit      - Called during tree post-order visit
17164565Sgshapiro *                                    when an object of "Type" is found
17238032Speter *              Context             - Passed to user function(s) above
17338032Speter *              ReturnValue         - from the UserFunction if terminated
17490795Sgshapiro *                                    early. Otherwise, returns NULL.
17590795Sgshapiro * RETURNS:     Status
17664565Sgshapiro *
17738032Speter * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
17864565Sgshapiro *              starting (and ending) at the node specified by StartHandle.
17938032Speter *              The callback function is called whenever a node that matches
18038032Speter *              the type parameter is found. If the callback function returns
18138032Speter *              a non-zero value, the search is terminated immediately and
18277352Sgshapiro *              this value is returned to the caller.
18377352Sgshapiro *
18438032Speter *              The point of this procedure is to provide a generic namespace
18538032Speter *              walk routine that can be called from multiple places to
18638032Speter *              provide multiple services; the callback function(s) can be
18738032Speter *              tailored to each task, whether it is a print function,
18838032Speter *              a compare function, etc.
18938032Speter *
19038032Speter ******************************************************************************/
19164565Sgshapiro
19238032SpeterACPI_STATUS
19364565SgshapiroAcpiNsWalkNamespace (
19464565Sgshapiro    ACPI_OBJECT_TYPE        Type,
19564565Sgshapiro    ACPI_HANDLE             StartNode,
19638032Speter    UINT32                  MaxDepth,
19738032Speter    UINT32                  Flags,
19890795Sgshapiro    ACPI_WALK_CALLBACK      PreOrderVisit,
19964565Sgshapiro    ACPI_WALK_CALLBACK      PostOrderVisit,
20064565Sgshapiro    void                    *Context,
20190795Sgshapiro    void                    **ReturnValue)
20238032Speter{
20338032Speter    ACPI_STATUS             Status;
20438032Speter    ACPI_STATUS             MutexStatus;
20538032Speter    ACPI_NAMESPACE_NODE     *ChildNode;
20638032Speter    ACPI_NAMESPACE_NODE     *ParentNode;
20790795Sgshapiro    ACPI_OBJECT_TYPE        ChildType;
20838032Speter    UINT32                  Level;
20990795Sgshapiro    BOOLEAN                 NodePreviouslyVisited = FALSE;
21090795Sgshapiro
21164565Sgshapiro
21264565Sgshapiro    ACPI_FUNCTION_TRACE (NsWalkNamespace);
21364565Sgshapiro
21438032Speter
21538032Speter    /* Special case for the namespace Root Node */
21638032Speter
21764565Sgshapiro    if (StartNode == ACPI_ROOT_OBJECT)
21864565Sgshapiro    {
21990795Sgshapiro        StartNode = AcpiGbl_RootNode;
22038032Speter    }
22198125Sgshapiro
22238032Speter    /* Null child means "get first node" */
22364565Sgshapiro
22464565Sgshapiro    ParentNode  = StartNode;
22564565Sgshapiro    ChildNode   = AcpiNsGetNextNode (ParentNode, NULL);
22664565Sgshapiro    ChildType   = ACPI_TYPE_ANY;
22738032Speter    Level       = 1;
22864565Sgshapiro
22964565Sgshapiro    /*
23064565Sgshapiro     * Traverse the tree of nodes until we bubble back up to where we
23164565Sgshapiro     * started. When Level is zero, the loop is done because we have
23238032Speter     * bubbled up to (and passed) the original parent handle (StartEntry)
23364565Sgshapiro     */
23464565Sgshapiro    while (Level > 0 && ChildNode)
23590795Sgshapiro    {
23690795Sgshapiro        Status = AE_OK;
23790795Sgshapiro
23864565Sgshapiro        /* Found next child, get the type if we are not searching for ANY */
23990795Sgshapiro
24064565Sgshapiro        if (Type != ACPI_TYPE_ANY)
24164565Sgshapiro        {
24264565Sgshapiro            ChildType = ChildNode->Type;
24338032Speter        }
24438032Speter
24538032Speter        /*
24664565Sgshapiro         * Ignore all temporary namespace nodes (created during control
24764565Sgshapiro         * method execution) unless told otherwise. These temporary nodes
24864565Sgshapiro         * can cause a race condition because they can be deleted during
24964565Sgshapiro         * the execution of the user function (if the namespace is
25064565Sgshapiro         * unlocked before invocation of the user function.) Only the
25164565Sgshapiro         * debugger namespace dump will examine the temporary nodes.
25264565Sgshapiro         */
25364565Sgshapiro        if ((ChildNode->Flags & ANOBJ_TEMPORARY) &&
25464565Sgshapiro            !(Flags & ACPI_NS_WALK_TEMP_NODES))
25564565Sgshapiro        {
25664565Sgshapiro            Status = AE_CTRL_DEPTH;
25764565Sgshapiro        }
25864565Sgshapiro
25964565Sgshapiro        /* Type must match requested type */
26064565Sgshapiro
26164565Sgshapiro        else if (ChildType == Type)
26264565Sgshapiro        {
26364565Sgshapiro            /*
26464565Sgshapiro             * Found a matching node, invoke the user callback function.
26538032Speter             * Unlock the namespace if flag is set.
26664565Sgshapiro             */
26764565Sgshapiro            if (Flags & ACPI_NS_WALK_UNLOCK)
26864565Sgshapiro            {
26990795Sgshapiro                MutexStatus = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
27098125Sgshapiro                if (ACPI_FAILURE (MutexStatus))
27164565Sgshapiro                {
27264565Sgshapiro                    return_ACPI_STATUS (MutexStatus);
27390795Sgshapiro                }
27464565Sgshapiro            }
27564565Sgshapiro
27664565Sgshapiro            /*
27764565Sgshapiro             * Invoke the user function, either pre-order or post-order
27890795Sgshapiro             * or both.
27998125Sgshapiro             */
28064565Sgshapiro            if (!NodePreviouslyVisited)
28164565Sgshapiro            {
28264565Sgshapiro                if (PreOrderVisit)
28364565Sgshapiro                {
28498125Sgshapiro                    Status = PreOrderVisit (ChildNode, Level,
28598125Sgshapiro                                Context, ReturnValue);
28664565Sgshapiro                }
28764565Sgshapiro            }
28864565Sgshapiro            else
28998125Sgshapiro            {
29098125Sgshapiro                if (PostOrderVisit)
29198125Sgshapiro                {
29298125Sgshapiro                    Status = PostOrderVisit (ChildNode, Level,
29398125Sgshapiro                                Context, ReturnValue);
29498125Sgshapiro                }
29598125Sgshapiro            }
29698125Sgshapiro
29798125Sgshapiro            if (Flags & ACPI_NS_WALK_UNLOCK)
29898125Sgshapiro            {
29998125Sgshapiro                MutexStatus = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
30098125Sgshapiro                if (ACPI_FAILURE (MutexStatus))
30198125Sgshapiro                {
30298125Sgshapiro                    return_ACPI_STATUS (MutexStatus);
30398125Sgshapiro                }
30498125Sgshapiro            }
30598125Sgshapiro
30664565Sgshapiro            switch (Status)
30790795Sgshapiro            {
30890795Sgshapiro            case AE_OK:
30964565Sgshapiro            case AE_CTRL_DEPTH:
310105016Sgshapiro
311105016Sgshapiro                /* Just keep going */
312105016Sgshapiro                break;
313105016Sgshapiro
314105016Sgshapiro            case AE_CTRL_TERMINATE:
315105016Sgshapiro
316105016Sgshapiro                /* Exit now, with OK status */
317105016Sgshapiro
318105016Sgshapiro                return_ACPI_STATUS (AE_OK);
319105016Sgshapiro
320105016Sgshapiro            default:
321105016Sgshapiro
322105016Sgshapiro                /* All others are valid exceptions */
323105016Sgshapiro
324105016Sgshapiro                return_ACPI_STATUS (Status);
325105016Sgshapiro            }
326105016Sgshapiro        }
327105016Sgshapiro
328105016Sgshapiro        /*
329105016Sgshapiro         * Depth first search: Attempt to go down another level in the
330105016Sgshapiro         * namespace if we are allowed to.  Don't go any further if we have
331105016Sgshapiro         * reached the caller specified maximum depth or if the user
332105016Sgshapiro         * function has specified that the maximum depth has been reached.
333105016Sgshapiro         */
334105016Sgshapiro        if (!NodePreviouslyVisited &&
335105016Sgshapiro            (Level < MaxDepth) &&
336105016Sgshapiro            (Status != AE_CTRL_DEPTH))
337105016Sgshapiro        {
338105016Sgshapiro            if (ChildNode->Child)
339105016Sgshapiro            {
340105016Sgshapiro                /* There is at least one child of this node, visit it */
341105016Sgshapiro
34264565Sgshapiro                Level++;
34364565Sgshapiro                ParentNode = ChildNode;
34464565Sgshapiro                ChildNode = AcpiNsGetNextNode (ParentNode, NULL);
34590795Sgshapiro                continue;
34690795Sgshapiro            }
34790795Sgshapiro        }
34864565Sgshapiro
34964565Sgshapiro        /* No more children, re-visit this node */
35064565Sgshapiro
35164565Sgshapiro        if (!NodePreviouslyVisited)
35290795Sgshapiro        {
35364565Sgshapiro            NodePreviouslyVisited = TRUE;
35464565Sgshapiro            continue;
35564565Sgshapiro        }
35638032Speter
35764565Sgshapiro        /* No more children, visit peers */
35864565Sgshapiro
35964565Sgshapiro        ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode);
36064565Sgshapiro        if (ChildNode)
36190795Sgshapiro        {
36264565Sgshapiro            NodePreviouslyVisited = FALSE;
36390795Sgshapiro        }
36464565Sgshapiro
36538032Speter        /* No peers, re-visit parent */
36638032Speter
36764565Sgshapiro        else
36864565Sgshapiro        {
36964565Sgshapiro            /*
37064565Sgshapiro             * No more children of this node (AcpiNsGetNextNode failed), go
37190795Sgshapiro             * back upwards in the namespace tree to the node's parent.
37290795Sgshapiro             */
37390795Sgshapiro            Level--;
37464565Sgshapiro            ChildNode = ParentNode;
37564565Sgshapiro            ParentNode = ParentNode->Parent;
37664565Sgshapiro
37790795Sgshapiro            NodePreviouslyVisited = TRUE;
37890795Sgshapiro        }
37990795Sgshapiro    }
38064565Sgshapiro
38164565Sgshapiro    /* Complete walk, not terminated by user function */
38264565Sgshapiro
38364565Sgshapiro    return_ACPI_STATUS (AE_OK);
38464565Sgshapiro}
38564565Sgshapiro
38664565Sgshapiro
38790795Sgshapiro