:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / bus / acpi / parser / pswalk.c
1 /******************************************************************************
2  *
3  * Module Name: pswalk - Parser routines to walk parsed op tree(s)
4  *              $Revision$
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 "amlcode.h"
29 #include "acparser.h"
30 #include "acdispat.h"
31 #include "acnamesp.h"
32 #include "acinterp.h"
33
34 #define _COMPONENT          ACPI_PARSER
35          MODULE_NAME         ("pswalk")
36
37
38 /*******************************************************************************
39  *
40  * FUNCTION:    Acpi_ps_get_next_walk_op
41  *
42  * PARAMETERS:  Walk_state          - Current state of the walk
43  *              Op                  - Current Op to be walked
44  *              Ascending_callback  - Procedure called when Op is complete
45  *
46  * RETURN:      Status
47  *
48  * DESCRIPTION: Get the next Op in a walk of the parse tree.
49  *
50  ******************************************************************************/
51
52 ACPI_STATUS
53 acpi_ps_get_next_walk_op (
54         ACPI_WALK_STATE         *walk_state,
55         ACPI_PARSE_OBJECT       *op,
56         ACPI_PARSE_UPWARDS      ascending_callback)
57 {
58         ACPI_PARSE_OBJECT       *next;
59         ACPI_PARSE_OBJECT       *parent;
60         ACPI_PARSE_OBJECT       *grand_parent;
61         ACPI_STATUS             status;
62
63
64         /* Check for a argument only if we are descending in the tree */
65
66         if (walk_state->next_op_info != NEXT_OP_UPWARD) {
67                 /* Look for an argument or child of the current op */
68
69                 next = acpi_ps_get_arg (op, 0);
70                 if (next) {
71                         /* Still going downward in tree (Op is not completed yet) */
72
73                         walk_state->prev_op     = op;
74                         walk_state->next_op     = next;
75                         walk_state->next_op_info = NEXT_OP_DOWNWARD;
76
77                         return (AE_OK);
78                 }
79
80
81                 /*
82                  * No more children, this Op is complete.  Save Next and Parent
83                  * in case the Op object gets deleted by the callback routine
84                  */
85
86                 next    = op->next;
87                 parent  = op->parent;
88
89                 status = ascending_callback (walk_state, op);
90
91                 /*
92                  * If we are back to the starting point, the walk is complete.
93                  */
94                 if (op == walk_state->origin) {
95                         /* Reached the point of origin, the walk is complete */
96
97                         walk_state->prev_op     = op;
98                         walk_state->next_op     = NULL;
99
100                         return (status);
101                 }
102
103                 /*
104                  * Check for a sibling to the current op.  A sibling means
105                  * we are still going "downward" in the tree.
106                  */
107
108                 if (next) {
109                         /* There is a sibling, it will be next */
110
111                         walk_state->prev_op     = op;
112                         walk_state->next_op     = next;
113                         walk_state->next_op_info = NEXT_OP_DOWNWARD;
114
115                         /* Continue downward */
116
117                         return (status);
118                 }
119
120
121                 /*
122                  * Drop into the loop below because we are moving upwards in
123                  * the tree
124                  */
125         }
126
127         else {
128                 /*
129                  * We are resuming a walk, and we were (are) going upward in the tree.
130                  * So, we want to drop into the parent loop below.
131                  */
132
133                 parent = op;
134         }
135
136
137         /*
138          * Look for a sibling of the current Op's parent
139          * Continue moving up the tree until we find a node that has not been
140          * visited, or we get back to where we started.
141          */
142         while (parent) {
143                 /* We are moving up the tree, therefore this parent Op is complete */
144
145                 grand_parent = parent->parent;
146                 next        = parent->next;
147
148                 status = ascending_callback (walk_state, parent);
149
150                 /*
151                  * If we are back to the starting point, the walk is complete.
152                  */
153                 if (parent == walk_state->origin) {
154                         /* Reached the point of origin, the walk is complete */
155
156                         walk_state->prev_op     = parent;
157                         walk_state->next_op     = NULL;
158
159                         return (status);
160                 }
161
162                 /*
163                  * If there is a sibling to this parent (it is not the starting point
164                  * Op), then we will visit it.
165                  */
166                 if (next) {
167                         /* found sibling of parent */
168
169                         walk_state->prev_op     = parent;
170                         walk_state->next_op     = next;
171                         walk_state->next_op_info = NEXT_OP_DOWNWARD;
172
173                         return (status);
174                 }
175
176                 /* No siblings, no errors, just move up one more level in the tree */
177
178                 op                  = parent;
179                 parent              = grand_parent;
180                 walk_state->prev_op = op;
181         }
182
183
184         /* Got all the way to the top of the tree, we must be done! */
185         /* However, the code should have terminated in the loop above */
186
187         walk_state->next_op     = NULL;
188
189         return (AE_OK);
190 }
191
192
193 /*******************************************************************************
194  *
195  * FUNCTION:    Acpi_ps_delete_completed_op
196  *
197  * PARAMETERS:  State           - Walk state
198  *              Op              - Completed op
199  *
200  * RETURN:      AE_OK
201  *
202  * DESCRIPTION: Callback function for Acpi_ps_get_next_walk_op(). Used during
203  *              Acpi_ps_delete_parse tree to delete Op objects when all sub-objects
204  *              have been visited (and deleted.)
205  *
206  ******************************************************************************/
207
208 static ACPI_STATUS
209 acpi_ps_delete_completed_op (
210         ACPI_WALK_STATE         *state,
211         ACPI_PARSE_OBJECT       *op)
212 {
213
214         acpi_ps_free_op (op);
215         return (AE_OK);
216 }
217
218
219 /*******************************************************************************
220  *
221  * FUNCTION:    Acpi_ps_delete_parse_tree
222  *
223  * PARAMETERS:  Subtree_root        - Root of tree (or subtree) to delete
224  *
225  * RETURN:      None
226  *
227  * DESCRIPTION: Delete a portion of or an entire parse tree.
228  *
229  ******************************************************************************/
230
231 void
232 acpi_ps_delete_parse_tree (
233         ACPI_PARSE_OBJECT       *subtree_root)
234 {
235         ACPI_WALK_STATE         *walk_state;
236         ACPI_WALK_LIST          walk_list;
237
238
239         if (!subtree_root) {
240                 return;
241         }
242
243         /* Create and initialize a new walk list */
244
245         walk_list.walk_state = NULL;
246         walk_list.acquired_mutex_list.prev = NULL;
247         walk_list.acquired_mutex_list.next = NULL;
248
249         walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, &walk_list);
250         if (!walk_state) {
251                 return;
252         }
253
254         walk_state->parser_state        = NULL;
255         walk_state->parse_flags         = 0;
256         walk_state->descending_callback = NULL;
257         walk_state->ascending_callback  = NULL;
258
259
260         walk_state->origin = subtree_root;
261         walk_state->next_op = subtree_root;
262
263
264         /* Head downward in the tree */
265
266         walk_state->next_op_info = NEXT_OP_DOWNWARD;
267
268         /* Visit all nodes in the subtree */
269
270         while (walk_state->next_op) {
271                 acpi_ps_get_next_walk_op (walk_state, walk_state->next_op,
272                                  acpi_ps_delete_completed_op);
273         }
274
275         /* We are done with this walk */
276
277         acpi_aml_release_all_mutexes ((ACPI_OPERAND_OBJECT *) &walk_list.acquired_mutex_list);
278         acpi_ds_delete_walk_state (walk_state);
279
280         return;
281 }
282
283