167754Smsmith/******************************************************************************
267754Smsmith *
382367Smsmith * Module Name: nswalk - Functions for walking the ACPI namespace
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
970243Smsmith * All rights reserved.
1067754Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2567754Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2967754Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4367754Smsmith
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
46193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
4767754Smsmith
4867754Smsmith
4977424Smsmith#define _COMPONENT          ACPI_NAMESPACE
5091116Smsmith        ACPI_MODULE_NAME    ("nswalk")
5167754Smsmith
5267754Smsmith
5385756Smsmith/*******************************************************************************
5467754Smsmith *
5585756Smsmith * FUNCTION:    AcpiNsGetNextNode
5667754Smsmith *
57193267Sjkim * PARAMETERS:  ParentNode          - Parent node whose children we are
58151937Sjkim *                                    getting
5985756Smsmith *              ChildNode           - Previous child that was found.
6067754Smsmith *                                    The NEXT child will be returned
6167754Smsmith *
6267754Smsmith * RETURN:      ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if
6385756Smsmith *                                    none is found.
6467754Smsmith *
65241973Sjkim * DESCRIPTION: Return the next peer node within the namespace. If Handle
66241973Sjkim *              is valid, Scope is ignored. Otherwise, the first node
6767754Smsmith *              within Scope is returned.
6867754Smsmith *
6985756Smsmith ******************************************************************************/
7067754Smsmith
7167754SmsmithACPI_NAMESPACE_NODE *
7285756SmsmithAcpiNsGetNextNode (
7367754Smsmith    ACPI_NAMESPACE_NODE     *ParentNode,
7467754Smsmith    ACPI_NAMESPACE_NODE     *ChildNode)
7567754Smsmith{
7691116Smsmith    ACPI_FUNCTION_ENTRY ();
7783174Smsmith
7883174Smsmith
7967754Smsmith    if (!ChildNode)
8067754Smsmith    {
8167754Smsmith        /* It's really the parent's _scope_ that we want */
8267754Smsmith
83193267Sjkim        return (ParentNode->Child);
8467754Smsmith    }
8567754Smsmith
86193267Sjkim    /* Otherwise just return the next peer */
87193267Sjkim
88193267Sjkim    return (ChildNode->Peer);
89193267Sjkim}
90193267Sjkim
91193267Sjkim
92193267Sjkim/*******************************************************************************
93193267Sjkim *
94193267Sjkim * FUNCTION:    AcpiNsGetNextNodeTyped
95193267Sjkim *
96193267Sjkim * PARAMETERS:  Type                - Type of node to be searched for
97193267Sjkim *              ParentNode          - Parent node whose children we are
98193267Sjkim *                                    getting
99193267Sjkim *              ChildNode           - Previous child that was found.
100193267Sjkim *                                    The NEXT child will be returned
101193267Sjkim *
102193267Sjkim * RETURN:      ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if
103193267Sjkim *                                    none is found.
104193267Sjkim *
105241973Sjkim * DESCRIPTION: Return the next peer node within the namespace. If Handle
106241973Sjkim *              is valid, Scope is ignored. Otherwise, the first node
107193267Sjkim *              within Scope is returned.
108193267Sjkim *
109193267Sjkim ******************************************************************************/
110193267Sjkim
111193267SjkimACPI_NAMESPACE_NODE *
112193267SjkimAcpiNsGetNextNodeTyped (
113193267Sjkim    ACPI_OBJECT_TYPE        Type,
114193267Sjkim    ACPI_NAMESPACE_NODE     *ParentNode,
115193267Sjkim    ACPI_NAMESPACE_NODE     *ChildNode)
116193267Sjkim{
117193267Sjkim    ACPI_NAMESPACE_NODE     *NextNode = NULL;
118193267Sjkim
119193267Sjkim
120193267Sjkim    ACPI_FUNCTION_ENTRY ();
121193267Sjkim
122193267Sjkim
123193267Sjkim    NextNode = AcpiNsGetNextNode (ParentNode, ChildNode);
124193267Sjkim
12567754Smsmith    /* If any type is OK, we are done */
12667754Smsmith
12767754Smsmith    if (Type == ACPI_TYPE_ANY)
12867754Smsmith    {
12967754Smsmith        /* NextNode is NULL if we are at the end-of-list */
13067754Smsmith
13167754Smsmith        return (NextNode);
13267754Smsmith    }
13367754Smsmith
13485756Smsmith    /* Must search for the node -- but within this scope only */
13567754Smsmith
13667754Smsmith    while (NextNode)
13767754Smsmith    {
13867754Smsmith        /* If type matches, we are done */
13967754Smsmith
14067754Smsmith        if (NextNode->Type == Type)
14167754Smsmith        {
14267754Smsmith            return (NextNode);
14367754Smsmith        }
14467754Smsmith
145209746Sjkim        /* Otherwise, move on to the next peer node */
14667754Smsmith
147209746Sjkim        NextNode = NextNode->Peer;
14867754Smsmith    }
14967754Smsmith
15067754Smsmith    /* Not found */
15167754Smsmith
15267754Smsmith    return (NULL);
15367754Smsmith}
15467754Smsmith
15567754Smsmith
15685756Smsmith/*******************************************************************************
15767754Smsmith *
15867754Smsmith * FUNCTION:    AcpiNsWalkNamespace
15967754Smsmith *
16067754Smsmith * PARAMETERS:  Type                - ACPI_OBJECT_TYPE to search for
16167754Smsmith *              StartNode           - Handle in namespace where search begins
16267754Smsmith *              MaxDepth            - Depth to which search is to reach
163167802Sjkim *              Flags               - Whether to unlock the NS before invoking
16467754Smsmith *                                    the callback routine
165253690Sjkim *              DescendingCallback  - Called during tree descent
166199337Sjkim *                                    when an object of "Type" is found
167253690Sjkim *              AscendingCallback   - Called during tree ascent
168199337Sjkim *                                    when an object of "Type" is found
169199337Sjkim *              Context             - Passed to user function(s) above
170199337Sjkim *              ReturnValue         - from the UserFunction if terminated
171199337Sjkim *                                    early. Otherwise, returns NULL.
17285756Smsmith * RETURNS:     Status
17367754Smsmith *
17467754Smsmith * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
17585756Smsmith *              starting (and ending) at the node specified by StartHandle.
176199337Sjkim *              The callback function is called whenever a node that matches
177199337Sjkim *              the type parameter is found. If the callback function returns
178193267Sjkim *              a non-zero value, the search is terminated immediately and
179193267Sjkim *              this value is returned to the caller.
18067754Smsmith *
18167754Smsmith *              The point of this procedure is to provide a generic namespace
18267754Smsmith *              walk routine that can be called from multiple places to
183199337Sjkim *              provide multiple services; the callback function(s) can be
184199337Sjkim *              tailored to each task, whether it is a print function,
185199337Sjkim *              a compare function, etc.
18667754Smsmith *
18767754Smsmith ******************************************************************************/
18867754Smsmith
18967754SmsmithACPI_STATUS
19067754SmsmithAcpiNsWalkNamespace (
19191116Smsmith    ACPI_OBJECT_TYPE        Type,
19267754Smsmith    ACPI_HANDLE             StartNode,
19367754Smsmith    UINT32                  MaxDepth,
194167802Sjkim    UINT32                  Flags,
195253690Sjkim    ACPI_WALK_CALLBACK      DescendingCallback,
196253690Sjkim    ACPI_WALK_CALLBACK      AscendingCallback,
19767754Smsmith    void                    *Context,
19867754Smsmith    void                    **ReturnValue)
19967754Smsmith{
20067754Smsmith    ACPI_STATUS             Status;
201117521Snjl    ACPI_STATUS             MutexStatus;
20267754Smsmith    ACPI_NAMESPACE_NODE     *ChildNode;
20367754Smsmith    ACPI_NAMESPACE_NODE     *ParentNode;
20491116Smsmith    ACPI_OBJECT_TYPE        ChildType;
20567754Smsmith    UINT32                  Level;
206199337Sjkim    BOOLEAN                 NodePreviouslyVisited = FALSE;
20767754Smsmith
20867754Smsmith
209167802Sjkim    ACPI_FUNCTION_TRACE (NsWalkNamespace);
21067754Smsmith
21183174Smsmith
21267754Smsmith    /* Special case for the namespace Root Node */
21367754Smsmith
21467754Smsmith    if (StartNode == ACPI_ROOT_OBJECT)
21567754Smsmith    {
21667754Smsmith        StartNode = AcpiGbl_RootNode;
21767754Smsmith    }
21867754Smsmith
21985756Smsmith    /* Null child means "get first node" */
22067754Smsmith
221306536Sjkim    ParentNode = StartNode;
222306536Sjkim    ChildNode = AcpiNsGetNextNode (ParentNode, NULL);
223306536Sjkim    ChildType = ACPI_TYPE_ANY;
224306536Sjkim    Level = 1;
22567754Smsmith
22667754Smsmith    /*
22785756Smsmith     * Traverse the tree of nodes until we bubble back up to where we
22867754Smsmith     * started. When Level is zero, the loop is done because we have
22967754Smsmith     * bubbled up to (and passed) the original parent handle (StartEntry)
23067754Smsmith     */
231199337Sjkim    while (Level > 0 && ChildNode)
23267754Smsmith    {
233199337Sjkim        Status = AE_OK;
23485756Smsmith
235199337Sjkim        /* Found next child, get the type if we are not searching for ANY */
236199337Sjkim
237199337Sjkim        if (Type != ACPI_TYPE_ANY)
23867754Smsmith        {
239199337Sjkim            ChildType = ChildNode->Type;
240199337Sjkim        }
241167802Sjkim
242199337Sjkim        /*
243199337Sjkim         * Ignore all temporary namespace nodes (created during control
244199337Sjkim         * method execution) unless told otherwise. These temporary nodes
245199337Sjkim         * can cause a race condition because they can be deleted during
246199337Sjkim         * the execution of the user function (if the namespace is
247199337Sjkim         * unlocked before invocation of the user function.) Only the
248199337Sjkim         * debugger namespace dump will examine the temporary nodes.
249199337Sjkim         */
250199337Sjkim        if ((ChildNode->Flags & ANOBJ_TEMPORARY) &&
251199337Sjkim            !(Flags & ACPI_NS_WALK_TEMP_NODES))
252199337Sjkim        {
253199337Sjkim            Status = AE_CTRL_DEPTH;
254199337Sjkim        }
255199337Sjkim
256199337Sjkim        /* Type must match requested type */
257199337Sjkim
258199337Sjkim        else if (ChildType == Type)
259199337Sjkim        {
260199337Sjkim            /*
261199337Sjkim             * Found a matching node, invoke the user callback function.
262199337Sjkim             * Unlock the namespace if flag is set.
263199337Sjkim             */
264199337Sjkim            if (Flags & ACPI_NS_WALK_UNLOCK)
26567754Smsmith            {
266199337Sjkim                MutexStatus = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
267199337Sjkim                if (ACPI_FAILURE (MutexStatus))
268199337Sjkim                {
269199337Sjkim                    return_ACPI_STATUS (MutexStatus);
270199337Sjkim                }
27167754Smsmith            }
27267754Smsmith
273167802Sjkim            /*
274253690Sjkim             * Invoke the user function, either descending, ascending,
275199337Sjkim             * or both.
276167802Sjkim             */
277199337Sjkim            if (!NodePreviouslyVisited)
27867754Smsmith            {
279253690Sjkim                if (DescendingCallback)
280199337Sjkim                {
281253690Sjkim                    Status = DescendingCallback (ChildNode, Level,
282306536Sjkim                        Context, ReturnValue);
283199337Sjkim                }
284167802Sjkim            }
285199337Sjkim            else
286167802Sjkim            {
287253690Sjkim                if (AscendingCallback)
28867754Smsmith                {
289253690Sjkim                    Status = AscendingCallback (ChildNode, Level,
290306536Sjkim                        Context, ReturnValue);
29167754Smsmith                }
292199337Sjkim            }
29367754Smsmith
294199337Sjkim            if (Flags & ACPI_NS_WALK_UNLOCK)
295199337Sjkim            {
296199337Sjkim                MutexStatus = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
297199337Sjkim                if (ACPI_FAILURE (MutexStatus))
29867754Smsmith                {
299199337Sjkim                    return_ACPI_STATUS (MutexStatus);
30067754Smsmith                }
301199337Sjkim            }
30267754Smsmith
303199337Sjkim            switch (Status)
304199337Sjkim            {
305199337Sjkim            case AE_OK:
306199337Sjkim            case AE_CTRL_DEPTH:
30783174Smsmith
308199337Sjkim                /* Just keep going */
309199337Sjkim                break;
31067754Smsmith
311199337Sjkim            case AE_CTRL_TERMINATE:
31283174Smsmith
313199337Sjkim                /* Exit now, with OK status */
31483174Smsmith
315199337Sjkim                return_ACPI_STATUS (AE_OK);
31667754Smsmith
317199337Sjkim            default:
31883174Smsmith
319199337Sjkim                /* All others are valid exceptions */
32083174Smsmith
321199337Sjkim                return_ACPI_STATUS (Status);
32267754Smsmith            }
323199337Sjkim        }
32467754Smsmith
325199337Sjkim        /*
326199337Sjkim         * Depth first search: Attempt to go down another level in the
327241973Sjkim         * namespace if we are allowed to. Don't go any further if we have
328199337Sjkim         * reached the caller specified maximum depth or if the user
329199337Sjkim         * function has specified that the maximum depth has been reached.
330199337Sjkim         */
331199337Sjkim        if (!NodePreviouslyVisited &&
332199337Sjkim            (Level < MaxDepth) &&
333199337Sjkim            (Status != AE_CTRL_DEPTH))
334199337Sjkim        {
335199337Sjkim            if (ChildNode->Child)
33667754Smsmith            {
337199337Sjkim                /* There is at least one child of this node, visit it */
338167802Sjkim
339199337Sjkim                Level++;
340199337Sjkim                ParentNode = ChildNode;
341199337Sjkim                ChildNode = AcpiNsGetNextNode (ParentNode, NULL);
342199337Sjkim                continue;
34367754Smsmith            }
34467754Smsmith        }
345199337Sjkim
346199337Sjkim        /* No more children, re-visit this node */
347199337Sjkim
348199337Sjkim        if (!NodePreviouslyVisited)
349199337Sjkim        {
350199337Sjkim            NodePreviouslyVisited = TRUE;
351199337Sjkim            continue;
352199337Sjkim        }
353199337Sjkim
354199337Sjkim        /* No more children, visit peers */
355199337Sjkim
356199337Sjkim        ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode);
357199337Sjkim        if (ChildNode)
358199337Sjkim        {
359199337Sjkim            NodePreviouslyVisited = FALSE;
360199337Sjkim        }
361199337Sjkim
362199337Sjkim        /* No peers, re-visit parent */
363199337Sjkim
36467754Smsmith        else
36567754Smsmith        {
36667754Smsmith            /*
367167802Sjkim             * No more children of this node (AcpiNsGetNextNode failed), go
368167802Sjkim             * back upwards in the namespace tree to the node's parent.
36967754Smsmith             */
37067754Smsmith            Level--;
37167754Smsmith            ChildNode = ParentNode;
372209746Sjkim            ParentNode = ParentNode->Parent;
373199337Sjkim
374199337Sjkim            NodePreviouslyVisited = TRUE;
37567754Smsmith        }
37667754Smsmith    }
37767754Smsmith
37867754Smsmith    /* Complete walk, not terminated by user function */
37983174Smsmith
38067754Smsmith    return_ACPI_STATUS (AE_OK);
38167754Smsmith}
382