File: /usr/src/linux/drivers/acpi/parser/pswalk.c

1     /******************************************************************************
2      *
3      * Module Name: pswalk - Parser routines to walk parsed op tree(s)
4      *              $Revision: 56 $
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     		status = ascending_callback (walk_state, op);
92     
93     		/*
94     		 * If we are back to the starting point, the walk is complete.
95     		 */
96     		if (op == walk_state->origin) {
97     			/* Reached the point of origin, the walk is complete */
98     
99     			walk_state->prev_op     = op;
100     			walk_state->next_op     = NULL;
101     
102     			return_ACPI_STATUS (status);
103     		}
104     
105     		/*
106     		 * Check for a sibling to the current op.  A sibling means
107     		 * we are still going "downward" in the tree.
108     		 */
109     		if (next) {
110     			/* There is a sibling, it will be next */
111     
112     			walk_state->prev_op     = op;
113     			walk_state->next_op     = next;
114     			walk_state->next_op_info = NEXT_OP_DOWNWARD;
115     
116     			/* Continue downward */
117     
118     			return_ACPI_STATUS (status);
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     		parent = op;
133     	}
134     
135     
136     	/*
137     	 * Look for a sibling of the current Op's parent
138     	 * Continue moving up the tree until we find a node that has not been
139     	 * visited, or we get back to where we started.
140     	 */
141     	while (parent) {
142     		/* We are moving up the tree, therefore this parent Op is complete */
143     
144     		grand_parent = parent->parent;
145     		next        = parent->next;
146     
147     		status = ascending_callback (walk_state, parent);
148     
149     		/*
150     		 * If we are back to the starting point, the walk is complete.
151     		 */
152     		if (parent == walk_state->origin) {
153     			/* Reached the point of origin, the walk is complete */
154     
155     			walk_state->prev_op     = parent;
156     			walk_state->next_op     = NULL;
157     
158     			return_ACPI_STATUS (status);
159     		}
160     
161     		/*
162     		 * If there is a sibling to this parent (it is not the starting point
163     		 * Op), then we will visit it.
164     		 */
165     		if (next) {
166     			/* found sibling of parent */
167     
168     			walk_state->prev_op     = parent;
169     			walk_state->next_op     = next;
170     			walk_state->next_op_info = NEXT_OP_DOWNWARD;
171     
172     			return_ACPI_STATUS (status);
173     		}
174     
175     		/* No siblings, no errors, just move up one more level in the tree */
176     
177     		op                  = parent;
178     		parent              = grand_parent;
179     		walk_state->prev_op = op;
180     	}
181     
182     
183     	/* Got all the way to the top of the tree, we must be done! */
184     	/* However, the code should have terminated in the loop above */
185     
186     	walk_state->next_op     = NULL;
187     
188     	return_ACPI_STATUS (AE_OK);
189     }
190     
191     
192     /*******************************************************************************
193      *
194      * FUNCTION:    Acpi_ps_delete_completed_op
195      *
196      * PARAMETERS:  State           - Walk state
197      *              Op              - Completed op
198      *
199      * RETURN:      AE_OK
200      *
201      * DESCRIPTION: Callback function for Acpi_ps_get_next_walk_op(). Used during
202      *              Acpi_ps_delete_parse tree to delete Op objects when all sub-objects
203      *              have been visited (and deleted.)
204      *
205      ******************************************************************************/
206     
207     static acpi_status
208     acpi_ps_delete_completed_op (
209     	acpi_walk_state         *state,
210     	acpi_parse_object       *op)
211     {
212     
213     	acpi_ps_free_op (op);
214     	return (AE_OK);
215     }
216     
217     
218     /*******************************************************************************
219      *
220      * FUNCTION:    Acpi_ps_delete_parse_tree
221      *
222      * PARAMETERS:  Subtree_root        - Root of tree (or subtree) to delete
223      *
224      * RETURN:      None
225      *
226      * DESCRIPTION: Delete a portion of or an entire parse tree.
227      *
228      ******************************************************************************/
229     
230     void
231     acpi_ps_delete_parse_tree (
232     	acpi_parse_object       *subtree_root)
233     {
234     	acpi_walk_state         *walk_state;
235     	acpi_walk_list          walk_list;
236     
237     
238     	FUNCTION_TRACE_PTR ("Ps_delete_parse_tree", subtree_root);
239     
240     
241     	if (!subtree_root) {
242     		return_VOID;
243     	}
244     
245     	/* Create and initialize a new walk list */
246     
247     	walk_list.walk_state = NULL;
248     	walk_list.acquired_mutex_list.prev = NULL;
249     	walk_list.acquired_mutex_list.next = NULL;
250     
251     	walk_state = acpi_ds_create_walk_state (TABLE_ID_DSDT, NULL, NULL, &walk_list);
252     	if (!walk_state) {
253     		return_VOID;
254     	}
255     
256     	walk_state->parser_state        = NULL;
257     	walk_state->parse_flags         = 0;
258     	walk_state->descending_callback = NULL;
259     	walk_state->ascending_callback  = NULL;
260     
261     
262     	walk_state->origin = subtree_root;
263     	walk_state->next_op = subtree_root;
264     
265     
266     	/* Head downward in the tree */
267     
268     	walk_state->next_op_info = NEXT_OP_DOWNWARD;
269     
270     	/* Visit all nodes in the subtree */
271     
272     	while (walk_state->next_op) {
273     		acpi_ps_get_next_walk_op (walk_state, walk_state->next_op,
274     				 acpi_ps_delete_completed_op);
275     	}
276     
277     	/* We are done with this walk */
278     
279     	acpi_ex_release_all_mutexes ((acpi_operand_object *) &walk_list.acquired_mutex_list);
280     	acpi_ds_delete_walk_state (walk_state);
281     
282     	return_VOID;
283     }
284     
285     
286