Merge /spare/repo/linux-2.6/
[linux-2.6] / drivers / acpi / parser / pstree.c
1 /******************************************************************************
2  *
3  * Module Name: pstree - Parser op tree manipulation/traversal/search
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2005, R. Byron Moore
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43
44 #include <acpi/acpi.h>
45 #include <acpi/acparser.h>
46 #include <acpi/amlcode.h>
47
48 #define _COMPONENT          ACPI_PARSER
49 ACPI_MODULE_NAME("pstree")
50
51 /* Local prototypes */
52 #ifdef ACPI_OBSOLETE_FUNCTIONS
53 union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op);
54 #endif
55
56 /*******************************************************************************
57  *
58  * FUNCTION:    acpi_ps_get_arg
59  *
60  * PARAMETERS:  Op              - Get an argument for this op
61  *              Argn            - Nth argument to get
62  *
63  * RETURN:      The argument (as an Op object). NULL if argument does not exist
64  *
65  * DESCRIPTION: Get the specified op's argument.
66  *
67  ******************************************************************************/
68
69 union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn)
70 {
71         union acpi_parse_object *arg = NULL;
72         const struct acpi_opcode_info *op_info;
73
74         ACPI_FUNCTION_ENTRY();
75
76         /* Get the info structure for this opcode */
77
78         op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
79         if (op_info->class == AML_CLASS_UNKNOWN) {
80                 /* Invalid opcode or ASCII character */
81
82                 return (NULL);
83         }
84
85         /* Check if this opcode requires argument sub-objects */
86
87         if (!(op_info->flags & AML_HAS_ARGS)) {
88                 /* Has no linked argument objects */
89
90                 return (NULL);
91         }
92
93         /* Get the requested argument object */
94
95         arg = op->common.value.arg;
96         while (arg && argn) {
97                 argn--;
98                 arg = arg->common.next;
99         }
100
101         return (arg);
102 }
103
104 /*******************************************************************************
105  *
106  * FUNCTION:    acpi_ps_append_arg
107  *
108  * PARAMETERS:  Op              - Append an argument to this Op.
109  *              Arg             - Argument Op to append
110  *
111  * RETURN:      None.
112  *
113  * DESCRIPTION: Append an argument to an op's argument list (a NULL arg is OK)
114  *
115  ******************************************************************************/
116
117 void
118 acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
119 {
120         union acpi_parse_object *prev_arg;
121         const struct acpi_opcode_info *op_info;
122
123         ACPI_FUNCTION_ENTRY();
124
125         if (!op) {
126                 return;
127         }
128
129         /* Get the info structure for this opcode */
130
131         op_info = acpi_ps_get_opcode_info(op->common.aml_opcode);
132         if (op_info->class == AML_CLASS_UNKNOWN) {
133                 /* Invalid opcode */
134
135                 ACPI_REPORT_ERROR(("ps_append_arg: Invalid AML Opcode: 0x%2.2X\n", op->common.aml_opcode));
136                 return;
137         }
138
139         /* Check if this opcode requires argument sub-objects */
140
141         if (!(op_info->flags & AML_HAS_ARGS)) {
142                 /* Has no linked argument objects */
143
144                 return;
145         }
146
147         /* Append the argument to the linked argument list */
148
149         if (op->common.value.arg) {
150                 /* Append to existing argument list */
151
152                 prev_arg = op->common.value.arg;
153                 while (prev_arg->common.next) {
154                         prev_arg = prev_arg->common.next;
155                 }
156                 prev_arg->common.next = arg;
157         } else {
158                 /* No argument list, this will be the first argument */
159
160                 op->common.value.arg = arg;
161         }
162
163         /* Set the parent in this arg and any args linked after it */
164
165         while (arg) {
166                 arg->common.parent = op;
167                 arg = arg->common.next;
168         }
169 }
170
171 #ifdef ACPI_FUTURE_USAGE
172 /*******************************************************************************
173  *
174  * FUNCTION:    acpi_ps_get_depth_next
175  *
176  * PARAMETERS:  Origin          - Root of subtree to search
177  *              Op              - Last (previous) Op that was found
178  *
179  * RETURN:      Next Op found in the search.
180  *
181  * DESCRIPTION: Get next op in tree (walking the tree in depth-first order)
182  *              Return NULL when reaching "origin" or when walking up from root
183  *
184  ******************************************************************************/
185
186 union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin,
187                                                 union acpi_parse_object *op)
188 {
189         union acpi_parse_object *next = NULL;
190         union acpi_parse_object *parent;
191         union acpi_parse_object *arg;
192
193         ACPI_FUNCTION_ENTRY();
194
195         if (!op) {
196                 return (NULL);
197         }
198
199         /* Look for an argument or child */
200
201         next = acpi_ps_get_arg(op, 0);
202         if (next) {
203                 return (next);
204         }
205
206         /* Look for a sibling */
207
208         next = op->common.next;
209         if (next) {
210                 return (next);
211         }
212
213         /* Look for a sibling of parent */
214
215         parent = op->common.parent;
216
217         while (parent) {
218                 arg = acpi_ps_get_arg(parent, 0);
219                 while (arg && (arg != origin) && (arg != op)) {
220                         arg = arg->common.next;
221                 }
222
223                 if (arg == origin) {
224                         /* Reached parent of origin, end search */
225
226                         return (NULL);
227                 }
228
229                 if (parent->common.next) {
230                         /* Found sibling of parent */
231
232                         return (parent->common.next);
233                 }
234
235                 op = parent;
236                 parent = parent->common.parent;
237         }
238
239         return (next);
240 }
241
242 #ifdef ACPI_OBSOLETE_FUNCTIONS
243 /*******************************************************************************
244  *
245  * FUNCTION:    acpi_ps_get_child
246  *
247  * PARAMETERS:  Op              - Get the child of this Op
248  *
249  * RETURN:      Child Op, Null if none is found.
250  *
251  * DESCRIPTION: Get op's children or NULL if none
252  *
253  ******************************************************************************/
254
255 union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op)
256 {
257         union acpi_parse_object *child = NULL;
258
259         ACPI_FUNCTION_ENTRY();
260
261         switch (op->common.aml_opcode) {
262         case AML_SCOPE_OP:
263         case AML_ELSE_OP:
264         case AML_DEVICE_OP:
265         case AML_THERMAL_ZONE_OP:
266         case AML_INT_METHODCALL_OP:
267
268                 child = acpi_ps_get_arg(op, 0);
269                 break;
270
271         case AML_BUFFER_OP:
272         case AML_PACKAGE_OP:
273         case AML_METHOD_OP:
274         case AML_IF_OP:
275         case AML_WHILE_OP:
276         case AML_FIELD_OP:
277
278                 child = acpi_ps_get_arg(op, 1);
279                 break;
280
281         case AML_POWER_RES_OP:
282         case AML_INDEX_FIELD_OP:
283
284                 child = acpi_ps_get_arg(op, 2);
285                 break;
286
287         case AML_PROCESSOR_OP:
288         case AML_BANK_FIELD_OP:
289
290                 child = acpi_ps_get_arg(op, 3);
291                 break;
292
293         default:
294                 /* All others have no children */
295                 break;
296         }
297
298         return (child);
299 }
300 #endif
301
302 #endif                          /*  ACPI_FUTURE_USAGE  */