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