import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / acpi / parser / pstree.c
1 /******************************************************************************
2  *
3  * Module Name: pstree - Parser op tree manipulation/traversal/search
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 "acparser.h"
29 #include "amlcode.h"
30
31 #define _COMPONENT          ACPI_PARSER
32          MODULE_NAME         ("pstree")
33
34
35 /*******************************************************************************
36  *
37  * FUNCTION:    Acpi_ps_get_arg
38  *
39  * PARAMETERS:  Op              - Get an argument for this op
40  *              Argn            - Nth argument to get
41  *
42  * RETURN:      The argument (as an Op object).  NULL if argument does not exist
43  *
44  * DESCRIPTION: Get the specified op's argument.
45  *
46  ******************************************************************************/
47
48 acpi_parse_object *
49 acpi_ps_get_arg (
50         acpi_parse_object       *op,
51         u32                     argn)
52 {
53         acpi_parse_object       *arg = NULL;
54         const acpi_opcode_info  *op_info;
55
56
57         FUNCTION_ENTRY ();
58
59
60         /* Get the info structure for this opcode */
61
62         op_info = acpi_ps_get_opcode_info (op->opcode);
63         if (op_info->class == AML_CLASS_UNKNOWN) {
64                 /* Invalid opcode or ASCII character */
65
66                 return (NULL);
67         }
68
69         /* Check if this opcode requires argument sub-objects */
70
71         if (!(op_info->flags & AML_HAS_ARGS)) {
72                 /* Has no linked argument objects */
73
74                 return (NULL);
75         }
76
77         /* Get the requested argument object */
78
79         arg = op->value.arg;
80         while (arg && argn) {
81                 argn--;
82                 arg = arg->next;
83         }
84
85         return (arg);
86 }
87
88
89 /*******************************************************************************
90  *
91  * FUNCTION:    Acpi_ps_append_arg
92  *
93  * PARAMETERS:  Op              - Append an argument to this Op.
94  *              Arg             - Argument Op to append
95  *
96  * RETURN:      None.
97  *
98  * DESCRIPTION: Append an argument to an op's argument list (a NULL arg is OK)
99  *
100  ******************************************************************************/
101
102 void
103 acpi_ps_append_arg (
104         acpi_parse_object       *op,
105         acpi_parse_object       *arg)
106 {
107         acpi_parse_object       *prev_arg;
108         const acpi_opcode_info  *op_info;
109
110
111         FUNCTION_ENTRY ();
112
113
114         if (!op) {
115                 return;
116         }
117
118         /* Get the info structure for this opcode */
119
120         op_info = acpi_ps_get_opcode_info (op->opcode);
121         if (op_info->class == AML_CLASS_UNKNOWN) {
122                 /* Invalid opcode */
123
124                 REPORT_ERROR (("Ps_append_arg: Invalid AML Opcode: 0x%2.2X\n", op->opcode));
125                 return;
126         }
127
128         /* Check if this opcode requires argument sub-objects */
129
130         if (!(op_info->flags & AML_HAS_ARGS)) {
131                 /* Has no linked argument objects */
132
133                 return;
134         }
135
136
137         /* Append the argument to the linked argument list */
138
139         if (op->value.arg) {
140                 /* Append to existing argument list */
141
142                 prev_arg = op->value.arg;
143                 while (prev_arg->next) {
144                         prev_arg = prev_arg->next;
145                 }
146                 prev_arg->next = arg;
147         }
148
149         else {
150                 /* No argument list, this will be the first argument */
151
152                 op->value.arg = arg;
153         }
154
155
156         /* Set the parent in this arg and any args linked after it */
157
158         while (arg) {
159                 arg->parent = op;
160                 arg = arg->next;
161         }
162 }
163
164
165 /*******************************************************************************
166  *
167  * FUNCTION:    Acpi_ps_get_child
168  *
169  * PARAMETERS:  Op              - Get the child of this Op
170  *
171  * RETURN:      Child Op, Null if none is found.
172  *
173  * DESCRIPTION: Get op's children or NULL if none
174  *
175  ******************************************************************************/
176
177 acpi_parse_object *
178 acpi_ps_get_child (
179         acpi_parse_object       *op)
180 {
181         acpi_parse_object       *child = NULL;
182
183
184         FUNCTION_ENTRY ();
185
186
187         switch (op->opcode) {
188         case AML_SCOPE_OP:
189         case AML_ELSE_OP:
190         case AML_DEVICE_OP:
191         case AML_THERMAL_ZONE_OP:
192         case AML_INT_METHODCALL_OP:
193
194                 child = acpi_ps_get_arg (op, 0);
195                 break;
196
197
198         case AML_BUFFER_OP:
199         case AML_PACKAGE_OP:
200         case AML_METHOD_OP:
201         case AML_IF_OP:
202         case AML_WHILE_OP:
203         case AML_FIELD_OP:
204
205                 child = acpi_ps_get_arg (op, 1);
206                 break;
207
208
209         case AML_POWER_RES_OP:
210         case AML_INDEX_FIELD_OP:
211
212                 child = acpi_ps_get_arg (op, 2);
213                 break;
214
215
216         case AML_PROCESSOR_OP:
217         case AML_BANK_FIELD_OP:
218
219                 child = acpi_ps_get_arg (op, 3);
220                 break;
221
222         }
223
224         return (child);
225 }
226
227
228 /*******************************************************************************
229  *
230  * FUNCTION:    Acpi_ps_get_depth_next
231  *
232  * PARAMETERS:  Origin          - Root of subtree to search
233  *              Op              - Last (previous) Op that was found
234  *
235  * RETURN:      Next Op found in the search.
236  *
237  * DESCRIPTION: Get next op in tree (walking the tree in depth-first order)
238  *              Return NULL when reaching "origin" or when walking up from root
239  *
240  ******************************************************************************/
241
242 acpi_parse_object *
243 acpi_ps_get_depth_next (
244         acpi_parse_object       *origin,
245         acpi_parse_object       *op)
246 {
247         acpi_parse_object       *next = NULL;
248         acpi_parse_object       *parent;
249         acpi_parse_object       *arg;
250
251
252         FUNCTION_ENTRY ();
253
254
255         if (!op) {
256                 return (NULL);
257         }
258
259         /* look for an argument or child */
260
261         next = acpi_ps_get_arg (op, 0);
262         if (next) {
263                 return (next);
264         }
265
266         /* look for a sibling */
267
268         next = op->next;
269         if (next) {
270                 return (next);
271         }
272
273         /* look for a sibling of parent */
274
275         parent = op->parent;
276
277         while (parent) {
278                 arg = acpi_ps_get_arg (parent, 0);
279                 while (arg && (arg != origin) && (arg != op)) {
280                         arg = arg->next;
281                 }
282
283                 if (arg == origin) {
284                         /* reached parent of origin, end search */
285
286                         return (NULL);
287                 }
288
289                 if (parent->next) {
290                         /* found sibling of parent */
291                         return (parent->next);
292                 }
293
294                 op = parent;
295                 parent = parent->parent;
296         }
297
298         return (next);
299 }
300
301