1ae115bc7Smrj /******************************************************************************
2ae115bc7Smrj *
3ae115bc7Smrj * Module Name: nswalk - Functions for walking the ACPI namespace
4ae115bc7Smrj *
5ae115bc7Smrj *****************************************************************************/
6ae115bc7Smrj
726f3cdf0SGordon Ross /*
8*385cc6b4SJerry Jelinek * Copyright (C) 2000 - 2016, Intel Corp.
9ae115bc7Smrj * All rights reserved.
10ae115bc7Smrj *
1126f3cdf0SGordon Ross * Redistribution and use in source and binary forms, with or without
1226f3cdf0SGordon Ross * modification, are permitted provided that the following conditions
1326f3cdf0SGordon Ross * are met:
1426f3cdf0SGordon Ross * 1. Redistributions of source code must retain the above copyright
1526f3cdf0SGordon Ross * notice, this list of conditions, and the following disclaimer,
1626f3cdf0SGordon Ross * without modification.
1726f3cdf0SGordon Ross * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1826f3cdf0SGordon Ross * substantially similar to the "NO WARRANTY" disclaimer below
1926f3cdf0SGordon Ross * ("Disclaimer") and any redistribution must be conditioned upon
2026f3cdf0SGordon Ross * including a substantially similar Disclaimer requirement for further
2126f3cdf0SGordon Ross * binary redistribution.
2226f3cdf0SGordon Ross * 3. Neither the names of the above-listed copyright holders nor the names
2326f3cdf0SGordon Ross * of any contributors may be used to endorse or promote products derived
2426f3cdf0SGordon Ross * from this software without specific prior written permission.
25ae115bc7Smrj *
2626f3cdf0SGordon Ross * Alternatively, this software may be distributed under the terms of the
2726f3cdf0SGordon Ross * GNU General Public License ("GPL") version 2 as published by the Free
2826f3cdf0SGordon Ross * Software Foundation.
29ae115bc7Smrj *
3026f3cdf0SGordon Ross * NO WARRANTY
3126f3cdf0SGordon Ross * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3226f3cdf0SGordon Ross * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3326f3cdf0SGordon Ross * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3426f3cdf0SGordon Ross * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3526f3cdf0SGordon Ross * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3626f3cdf0SGordon Ross * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3726f3cdf0SGordon Ross * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3826f3cdf0SGordon Ross * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3926f3cdf0SGordon Ross * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
4026f3cdf0SGordon Ross * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
4126f3cdf0SGordon Ross * POSSIBILITY OF SUCH DAMAGES.
4226f3cdf0SGordon Ross */
43ae115bc7Smrj
44ae115bc7Smrj #include "acpi.h"
45aa2aa9a6SDana Myers #include "accommon.h"
46ae115bc7Smrj #include "acnamesp.h"
47ae115bc7Smrj
48ae115bc7Smrj
49ae115bc7Smrj #define _COMPONENT ACPI_NAMESPACE
50ae115bc7Smrj ACPI_MODULE_NAME ("nswalk")
51ae115bc7Smrj
52ae115bc7Smrj
53ae115bc7Smrj /*******************************************************************************
54ae115bc7Smrj *
55ae115bc7Smrj * FUNCTION: AcpiNsGetNextNode
56ae115bc7Smrj *
57aa2aa9a6SDana Myers * PARAMETERS: ParentNode - Parent node whose children we are
58aa2aa9a6SDana Myers * getting
59aa2aa9a6SDana Myers * ChildNode - Previous child that was found.
60aa2aa9a6SDana Myers * The NEXT child will be returned
61aa2aa9a6SDana Myers *
62aa2aa9a6SDana Myers * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if
63aa2aa9a6SDana Myers * none is found.
64aa2aa9a6SDana Myers *
65aa2aa9a6SDana Myers * DESCRIPTION: Return the next peer node within the namespace. If Handle
66aa2aa9a6SDana Myers * is valid, Scope is ignored. Otherwise, the first node
67aa2aa9a6SDana Myers * within Scope is returned.
68aa2aa9a6SDana Myers *
69aa2aa9a6SDana Myers ******************************************************************************/
70aa2aa9a6SDana Myers
71aa2aa9a6SDana Myers ACPI_NAMESPACE_NODE *
AcpiNsGetNextNode(ACPI_NAMESPACE_NODE * ParentNode,ACPI_NAMESPACE_NODE * ChildNode)72aa2aa9a6SDana Myers AcpiNsGetNextNode (
73aa2aa9a6SDana Myers ACPI_NAMESPACE_NODE *ParentNode,
74aa2aa9a6SDana Myers ACPI_NAMESPACE_NODE *ChildNode)
75aa2aa9a6SDana Myers {
76aa2aa9a6SDana Myers ACPI_FUNCTION_ENTRY ();
77aa2aa9a6SDana Myers
78aa2aa9a6SDana Myers
79aa2aa9a6SDana Myers if (!ChildNode)
80aa2aa9a6SDana Myers {
81aa2aa9a6SDana Myers /* It's really the parent's _scope_ that we want */
82aa2aa9a6SDana Myers
83aa2aa9a6SDana Myers return (ParentNode->Child);
84aa2aa9a6SDana Myers }
85aa2aa9a6SDana Myers
86aa2aa9a6SDana Myers /* Otherwise just return the next peer */
87aa2aa9a6SDana Myers
88aa2aa9a6SDana Myers return (ChildNode->Peer);
89aa2aa9a6SDana Myers }
90aa2aa9a6SDana Myers
91aa2aa9a6SDana Myers
92aa2aa9a6SDana Myers /*******************************************************************************
93aa2aa9a6SDana Myers *
94aa2aa9a6SDana Myers * FUNCTION: AcpiNsGetNextNodeTyped
95aa2aa9a6SDana Myers *
96ae115bc7Smrj * PARAMETERS: Type - Type of node to be searched for
97ae115bc7Smrj * ParentNode - Parent node whose children we are
98ae115bc7Smrj * getting
99ae115bc7Smrj * ChildNode - Previous child that was found.
100ae115bc7Smrj * The NEXT child will be returned
101ae115bc7Smrj *
102ae115bc7Smrj * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if
103ae115bc7Smrj * none is found.
104ae115bc7Smrj *
105ae115bc7Smrj * DESCRIPTION: Return the next peer node within the namespace. If Handle
106ae115bc7Smrj * is valid, Scope is ignored. Otherwise, the first node
107ae115bc7Smrj * within Scope is returned.
108ae115bc7Smrj *
109ae115bc7Smrj ******************************************************************************/
110ae115bc7Smrj
111ae115bc7Smrj ACPI_NAMESPACE_NODE *
AcpiNsGetNextNodeTyped(ACPI_OBJECT_TYPE Type,ACPI_NAMESPACE_NODE * ParentNode,ACPI_NAMESPACE_NODE * ChildNode)112aa2aa9a6SDana Myers AcpiNsGetNextNodeTyped (
113ae115bc7Smrj ACPI_OBJECT_TYPE Type,
114ae115bc7Smrj ACPI_NAMESPACE_NODE *ParentNode,
115ae115bc7Smrj ACPI_NAMESPACE_NODE *ChildNode)
116ae115bc7Smrj {
117ae115bc7Smrj ACPI_NAMESPACE_NODE *NextNode = NULL;
118ae115bc7Smrj
119ae115bc7Smrj
120ae115bc7Smrj ACPI_FUNCTION_ENTRY ();
121ae115bc7Smrj
122ae115bc7Smrj
123aa2aa9a6SDana Myers NextNode = AcpiNsGetNextNode (ParentNode, ChildNode);
124ae115bc7Smrj
125ae115bc7Smrj /* If any type is OK, we are done */
126ae115bc7Smrj
127ae115bc7Smrj if (Type == ACPI_TYPE_ANY)
128ae115bc7Smrj {
129ae115bc7Smrj /* NextNode is NULL if we are at the end-of-list */
130ae115bc7Smrj
131ae115bc7Smrj return (NextNode);
132ae115bc7Smrj }
133ae115bc7Smrj
134ae115bc7Smrj /* Must search for the node -- but within this scope only */
135ae115bc7Smrj
136ae115bc7Smrj while (NextNode)
137ae115bc7Smrj {
138ae115bc7Smrj /* If type matches, we are done */
139ae115bc7Smrj
140ae115bc7Smrj if (NextNode->Type == Type)
141ae115bc7Smrj {
142ae115bc7Smrj return (NextNode);
143ae115bc7Smrj }
144ae115bc7Smrj
14526f3cdf0SGordon Ross /* Otherwise, move on to the next peer node */
146ae115bc7Smrj
14726f3cdf0SGordon Ross NextNode = NextNode->Peer;
148ae115bc7Smrj }
149ae115bc7Smrj
150ae115bc7Smrj /* Not found */
151ae115bc7Smrj
152ae115bc7Smrj return (NULL);
153ae115bc7Smrj }
154ae115bc7Smrj
155ae115bc7Smrj
156ae115bc7Smrj /*******************************************************************************
157ae115bc7Smrj *
158ae115bc7Smrj * FUNCTION: AcpiNsWalkNamespace
159ae115bc7Smrj *
160ae115bc7Smrj * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for
161ae115bc7Smrj * StartNode - Handle in namespace where search begins
162ae115bc7Smrj * MaxDepth - Depth to which search is to reach
163db2bae30SDana Myers * Flags - Whether to unlock the NS before invoking
164ae115bc7Smrj * the callback routine
165*385cc6b4SJerry Jelinek * DescendingCallback - Called during tree descent
16657190917SDana Myers * when an object of "Type" is found
167*385cc6b4SJerry Jelinek * AscendingCallback - Called during tree ascent
16857190917SDana Myers * when an object of "Type" is found
16957190917SDana Myers * Context - Passed to user function(s) above
17057190917SDana Myers * ReturnValue - from the UserFunction if terminated
17157190917SDana Myers * early. Otherwise, returns NULL.
172ae115bc7Smrj * RETURNS: Status
173ae115bc7Smrj *
174ae115bc7Smrj * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
175ae115bc7Smrj * starting (and ending) at the node specified by StartHandle.
17657190917SDana Myers * The callback function is called whenever a node that matches
17757190917SDana Myers * the type parameter is found. If the callback function returns
178aa2aa9a6SDana Myers * a non-zero value, the search is terminated immediately and
179aa2aa9a6SDana Myers * this value is returned to the caller.
180ae115bc7Smrj *
181ae115bc7Smrj * The point of this procedure is to provide a generic namespace
182ae115bc7Smrj * walk routine that can be called from multiple places to
18357190917SDana Myers * provide multiple services; the callback function(s) can be
18457190917SDana Myers * tailored to each task, whether it is a print function,
18557190917SDana Myers * a compare function, etc.
186ae115bc7Smrj *
187ae115bc7Smrj ******************************************************************************/
188ae115bc7Smrj
189ae115bc7Smrj ACPI_STATUS
AcpiNsWalkNamespace(ACPI_OBJECT_TYPE Type,ACPI_HANDLE StartNode,UINT32 MaxDepth,UINT32 Flags,ACPI_WALK_CALLBACK DescendingCallback,ACPI_WALK_CALLBACK AscendingCallback,void * Context,void ** ReturnValue)190ae115bc7Smrj AcpiNsWalkNamespace (
191ae115bc7Smrj ACPI_OBJECT_TYPE Type,
192ae115bc7Smrj ACPI_HANDLE StartNode,
193ae115bc7Smrj UINT32 MaxDepth,
194db2bae30SDana Myers UINT32 Flags,
195*385cc6b4SJerry Jelinek ACPI_WALK_CALLBACK DescendingCallback,
196*385cc6b4SJerry Jelinek ACPI_WALK_CALLBACK AscendingCallback,
197ae115bc7Smrj void *Context,
198ae115bc7Smrj void **ReturnValue)
199ae115bc7Smrj {
200ae115bc7Smrj ACPI_STATUS Status;
201ae115bc7Smrj ACPI_STATUS MutexStatus;
202ae115bc7Smrj ACPI_NAMESPACE_NODE *ChildNode;
203ae115bc7Smrj ACPI_NAMESPACE_NODE *ParentNode;
204ae115bc7Smrj ACPI_OBJECT_TYPE ChildType;
205ae115bc7Smrj UINT32 Level;
20657190917SDana Myers BOOLEAN NodePreviouslyVisited = FALSE;
207ae115bc7Smrj
208ae115bc7Smrj
209ae115bc7Smrj ACPI_FUNCTION_TRACE (NsWalkNamespace);
210ae115bc7Smrj
211ae115bc7Smrj
212ae115bc7Smrj /* Special case for the namespace Root Node */
213ae115bc7Smrj
214ae115bc7Smrj if (StartNode == ACPI_ROOT_OBJECT)
215ae115bc7Smrj {
216ae115bc7Smrj StartNode = AcpiGbl_RootNode;
217ae115bc7Smrj }
218ae115bc7Smrj
219ae115bc7Smrj /* Null child means "get first node" */
220ae115bc7Smrj
221ae115bc7Smrj ParentNode = StartNode;
22257190917SDana Myers ChildNode = AcpiNsGetNextNode (ParentNode, NULL);
223ae115bc7Smrj ChildType = ACPI_TYPE_ANY;
224ae115bc7Smrj Level = 1;
225ae115bc7Smrj
226ae115bc7Smrj /*
227ae115bc7Smrj * Traverse the tree of nodes until we bubble back up to where we
228ae115bc7Smrj * started. When Level is zero, the loop is done because we have
229ae115bc7Smrj * bubbled up to (and passed) the original parent handle (StartEntry)
230ae115bc7Smrj */
23157190917SDana Myers while (Level > 0 && ChildNode)
232ae115bc7Smrj {
233ae115bc7Smrj Status = AE_OK;
23457190917SDana Myers
235db2bae30SDana Myers /* Found next child, get the type if we are not searching for ANY */
236db2bae30SDana Myers
237ae115bc7Smrj if (Type != ACPI_TYPE_ANY)
238ae115bc7Smrj {
239ae115bc7Smrj ChildType = ChildNode->Type;
240ae115bc7Smrj }
241ae115bc7Smrj
242db2bae30SDana Myers /*
243db2bae30SDana Myers * Ignore all temporary namespace nodes (created during control
244db2bae30SDana Myers * method execution) unless told otherwise. These temporary nodes
245aa2aa9a6SDana Myers * can cause a race condition because they can be deleted during
246aa2aa9a6SDana Myers * the execution of the user function (if the namespace is
247aa2aa9a6SDana Myers * unlocked before invocation of the user function.) Only the
248aa2aa9a6SDana Myers * debugger namespace dump will examine the temporary nodes.
249db2bae30SDana Myers */
250db2bae30SDana Myers if ((ChildNode->Flags & ANOBJ_TEMPORARY) &&
251db2bae30SDana Myers !(Flags & ACPI_NS_WALK_TEMP_NODES))
252db2bae30SDana Myers {
253db2bae30SDana Myers Status = AE_CTRL_DEPTH;
254db2bae30SDana Myers }
255db2bae30SDana Myers
256db2bae30SDana Myers /* Type must match requested type */
257db2bae30SDana Myers
258db2bae30SDana Myers else if (ChildType == Type)
259ae115bc7Smrj {
260ae115bc7Smrj /*
261db2bae30SDana Myers * Found a matching node, invoke the user callback function.
262db2bae30SDana Myers * Unlock the namespace if flag is set.
263ae115bc7Smrj */
264db2bae30SDana Myers if (Flags & ACPI_NS_WALK_UNLOCK)
265ae115bc7Smrj {
266ae115bc7Smrj MutexStatus = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE);
267ae115bc7Smrj if (ACPI_FAILURE (MutexStatus))
268ae115bc7Smrj {
269ae115bc7Smrj return_ACPI_STATUS (MutexStatus);
270ae115bc7Smrj }
271ae115bc7Smrj }
272ae115bc7Smrj
27357190917SDana Myers /*
274*385cc6b4SJerry Jelinek * Invoke the user function, either descending, ascending,
27557190917SDana Myers * or both.
27657190917SDana Myers */
27757190917SDana Myers if (!NodePreviouslyVisited)
27857190917SDana Myers {
279*385cc6b4SJerry Jelinek if (DescendingCallback)
28057190917SDana Myers {
281*385cc6b4SJerry Jelinek Status = DescendingCallback (ChildNode, Level,
28257190917SDana Myers Context, ReturnValue);
28357190917SDana Myers }
28457190917SDana Myers }
28557190917SDana Myers else
28657190917SDana Myers {
287*385cc6b4SJerry Jelinek if (AscendingCallback)
28857190917SDana Myers {
289*385cc6b4SJerry Jelinek Status = AscendingCallback (ChildNode, Level,
29057190917SDana Myers Context, ReturnValue);
29157190917SDana Myers }
29257190917SDana Myers }
293ae115bc7Smrj
294db2bae30SDana Myers if (Flags & ACPI_NS_WALK_UNLOCK)
295ae115bc7Smrj {
296ae115bc7Smrj MutexStatus = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE);
297ae115bc7Smrj if (ACPI_FAILURE (MutexStatus))
298ae115bc7Smrj {
299ae115bc7Smrj return_ACPI_STATUS (MutexStatus);
300ae115bc7Smrj }
301ae115bc7Smrj }
302ae115bc7Smrj
303ae115bc7Smrj switch (Status)
304ae115bc7Smrj {
305ae115bc7Smrj case AE_OK:
306ae115bc7Smrj case AE_CTRL_DEPTH:
307ae115bc7Smrj
308ae115bc7Smrj /* Just keep going */
309ae115bc7Smrj break;
310ae115bc7Smrj
311ae115bc7Smrj case AE_CTRL_TERMINATE:
312ae115bc7Smrj
313ae115bc7Smrj /* Exit now, with OK status */
314ae115bc7Smrj
315ae115bc7Smrj return_ACPI_STATUS (AE_OK);
316ae115bc7Smrj
317ae115bc7Smrj default:
318ae115bc7Smrj
319ae115bc7Smrj /* All others are valid exceptions */
320ae115bc7Smrj
321ae115bc7Smrj return_ACPI_STATUS (Status);
322ae115bc7Smrj }
323ae115bc7Smrj }
324ae115bc7Smrj
325ae115bc7Smrj /*
326db2bae30SDana Myers * Depth first search: Attempt to go down another level in the
327db2bae30SDana Myers * namespace if we are allowed to. Don't go any further if we have
328db2bae30SDana Myers * reached the caller specified maximum depth or if the user
329db2bae30SDana Myers * function has specified that the maximum depth has been reached.
330ae115bc7Smrj */
33157190917SDana Myers if (!NodePreviouslyVisited &&
33257190917SDana Myers (Level < MaxDepth) &&
33357190917SDana Myers (Status != AE_CTRL_DEPTH))
334ae115bc7Smrj {
335aa2aa9a6SDana Myers if (ChildNode->Child)
336ae115bc7Smrj {
337db2bae30SDana Myers /* There is at least one child of this node, visit it */
338db2bae30SDana Myers
339ae115bc7Smrj Level++;
340ae115bc7Smrj ParentNode = ChildNode;
34157190917SDana Myers ChildNode = AcpiNsGetNextNode (ParentNode, NULL);
34257190917SDana Myers continue;
343ae115bc7Smrj }
344ae115bc7Smrj }
34557190917SDana Myers
34657190917SDana Myers /* No more children, re-visit this node */
34757190917SDana Myers
34857190917SDana Myers if (!NodePreviouslyVisited)
34957190917SDana Myers {
35057190917SDana Myers NodePreviouslyVisited = TRUE;
35157190917SDana Myers continue;
352ae115bc7Smrj }
35357190917SDana Myers
35457190917SDana Myers /* No more children, visit peers */
35557190917SDana Myers
35657190917SDana Myers ChildNode = AcpiNsGetNextNode (ParentNode, ChildNode);
35757190917SDana Myers if (ChildNode)
35857190917SDana Myers {
35957190917SDana Myers NodePreviouslyVisited = FALSE;
36057190917SDana Myers }
36157190917SDana Myers
36257190917SDana Myers /* No peers, re-visit parent */
36357190917SDana Myers
364ae115bc7Smrj else
365ae115bc7Smrj {
366ae115bc7Smrj /*
367db2bae30SDana Myers * No more children of this node (AcpiNsGetNextNode failed), go
368db2bae30SDana Myers * back upwards in the namespace tree to the node's parent.
369ae115bc7Smrj */
370ae115bc7Smrj Level--;
371ae115bc7Smrj ChildNode = ParentNode;
37226f3cdf0SGordon Ross ParentNode = ParentNode->Parent;
37357190917SDana Myers
37457190917SDana Myers NodePreviouslyVisited = TRUE;
375ae115bc7Smrj }
376ae115bc7Smrj }
377ae115bc7Smrj
378ae115bc7Smrj /* Complete walk, not terminated by user function */
379ae115bc7Smrj
380ae115bc7Smrj return_ACPI_STATUS (AE_OK);
381ae115bc7Smrj }
382