9ff403c3f5bd52c2df8e660a3ebcf128cf2eca1f
[reactos.git] / reactos / drivers / bus / acpi / namespace / nswalk.c
1 /******************************************************************************
2 *
3 * Module Name: nswalk - Functions for walking the APCI namespace
4 * $Revision: 1.1 $
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 R. Byron Moore
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include "acpi.h"
28 #include "acinterp.h"
29 #include "acnamesp.h"
30
31
32 #define _COMPONENT ACPI_NAMESPACE
33 MODULE_NAME ("nswalk")
34
35
36 /****************************************************************************
37 *
38 * FUNCTION: Acpi_get_next_object
39 *
40 * PARAMETERS: Type - Type of object to be searched for
41 * Parent - Parent object whose children we are
42 * getting
43 * Last_child - Previous child that was found.
44 * The NEXT child will be returned
45 *
46 * RETURN: ACPI_NAMESPACE_NODE - Pointer to the NEXT child or NULL if
47 * none is found.
48 *
49 * DESCRIPTION: Return the next peer object within the namespace. If Handle
50 * is valid, Scope is ignored. Otherwise, the first object
51 * within Scope is returned.
52 *
53 ****************************************************************************/
54
55 ACPI_NAMESPACE_NODE *
56 acpi_ns_get_next_object (
57 OBJECT_TYPE_INTERNAL type,
58 ACPI_NAMESPACE_NODE *parent_node,
59 ACPI_NAMESPACE_NODE *child_node)
60 {
61 ACPI_NAMESPACE_NODE *next_node = NULL;
62
63
64 if (!child_node) {
65
66 /* It's really the parent's _scope_ that we want */
67
68 if (parent_node->child) {
69 next_node = parent_node->child;
70 }
71 }
72
73 else {
74 /* Start search at the NEXT object */
75
76 next_node = acpi_ns_get_next_valid_object (child_node);
77 }
78
79
80 /* If any type is OK, we are done */
81
82 if (type == ACPI_TYPE_ANY) {
83 /* Next_node is NULL if we are at the end-of-list */
84
85 return (next_node);
86 }
87
88
89 /* Must search for the object -- but within this scope only */
90
91 while (next_node) {
92 /* If type matches, we are done */
93
94 if (next_node->type == type) {
95 return (next_node);
96 }
97
98 /* Otherwise, move on to the next object */
99
100 next_node = acpi_ns_get_next_valid_object (next_node);
101 }
102
103
104 /* Not found */
105
106 return (NULL);
107 }
108
109
110 /******************************************************************************
111 *
112 * FUNCTION: Acpi_ns_walk_namespace
113 *
114 * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for
115 * Start_node - Handle in namespace where search begins
116 * Max_depth - Depth to which search is to reach
117 * Unlock_before_callback- Whether to unlock the NS before invoking
118 * the callback routine
119 * User_function - Called when an object of "Type" is found
120 * Context - Passed to user function
121 *
122 * RETURNS Return value from the User_function if terminated early.
123 * Otherwise, returns NULL.
124 *
125 * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
126 * starting (and ending) at the object specified by Start_handle.
127 * The User_function is called whenever an object that matches
128 * the type parameter is found. If the user function returns
129 * a non-zero value, the search is terminated immediately and this
130 * value is returned to the caller.
131 *
132 * The point of this procedure is to provide a generic namespace
133 * walk routine that can be called from multiple places to
134 * provide multiple services; the User Function can be tailored
135 * to each task, whether it is a print function, a compare
136 * function, etc.
137 *
138 ******************************************************************************/
139
140 ACPI_STATUS
141 acpi_ns_walk_namespace (
142 OBJECT_TYPE_INTERNAL type,
143 ACPI_HANDLE start_node,
144 u32 max_depth,
145 u8 unlock_before_callback,
146 WALK_CALLBACK user_function,
147 void *context,
148 void **return_value)
149 {
150 ACPI_STATUS status;
151 ACPI_NAMESPACE_NODE *child_node;
152 ACPI_NAMESPACE_NODE *parent_node;
153 OBJECT_TYPE_INTERNAL child_type;
154 u32 level;
155
156
157 /* Special case for the namespace Root Node */
158
159 if (start_node == ACPI_ROOT_OBJECT) {
160 start_node = acpi_gbl_root_node;
161 }
162
163
164 /* Null child means "get first object" */
165
166 parent_node = start_node;
167 child_node = 0;
168 child_type = ACPI_TYPE_ANY;
169 level = 1;
170
171 /*
172 * Traverse the tree of objects until we bubble back up to where we
173 * started. When Level is zero, the loop is done because we have
174 * bubbled up to (and passed) the original parent handle (Start_entry)
175 */
176
177 while (level > 0) {
178 /*
179 * Get the next typed object in this scope. Null returned
180 * if not found
181 */
182
183 status = AE_OK;
184 child_node = acpi_ns_get_next_object (ACPI_TYPE_ANY,
185 parent_node,
186 child_node);
187
188 if (child_node) {
189 /*
190 * Found an object, Get the type if we are not
191 * searching for ANY
192 */
193
194 if (type != ACPI_TYPE_ANY) {
195 child_type = child_node->type;
196 }
197
198 if (child_type == type) {
199 /*
200 * Found a matching object, invoke the user
201 * callback function
202 */
203
204 if (unlock_before_callback) {
205 acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
206 }
207
208 status = user_function (child_node, level,
209 context, return_value);
210
211 if (unlock_before_callback) {
212 acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
213 }
214
215 switch (status) {
216 case AE_OK:
217 case AE_CTRL_DEPTH:
218 /* Just keep going */
219 break;
220
221 case AE_CTRL_TERMINATE:
222 /* Exit now, with OK status */
223 return (AE_OK);
224 break;
225
226 default:
227 /* All others are valid exceptions */
228 return (status);
229 break;
230 }
231 }
232
233 /*
234 * Depth first search:
235 * Attempt to go down another level in the namespace
236 * if we are allowed to. Don't go any further if we
237 * have reached the caller specified maximum depth
238 * or if the user function has specified that the
239 * maximum depth has been reached.
240 */
241
242 if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
243 if (acpi_ns_get_next_object (ACPI_TYPE_ANY,
244 child_node, 0)) {
245 /*
246 * There is at least one child of this
247 * object, visit the object
248 */
249 level++;
250 parent_node = child_node;
251 child_node = 0;
252 }
253 }
254 }
255
256 else {
257 /*
258 * No more children in this object (Acpi_ns_get_next_object
259 * failed), go back upwards in the namespace tree to
260 * the object's parent.
261 */
262 level--;
263 child_node = parent_node;
264 parent_node = acpi_ns_get_parent_object (parent_node);
265 }
266 }
267
268 /* Complete walk, not terminated by user function */
269 return (AE_OK);
270 }
271
272