Merge branch 'origin'
[pandora-kernel.git] / 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 - 2006, 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_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X",
136                             op->common.aml_opcode));
137                 return;
138         }
139
140         /* Check if this opcode requires argument sub-objects */
141
142         if (!(op_info->flags & AML_HAS_ARGS)) {
143                 /* Has no linked argument objects */
144
145                 return;
146         }
147
148         /* Append the argument to the linked argument list */
149
150         if (op->common.value.arg) {
151                 /* Append to existing argument list */
152
153                 prev_arg = op->common.value.arg;
154                 while (prev_arg->common.next) {
155                         prev_arg = prev_arg->common.next;
156                 }
157                 prev_arg->common.next = arg;
158         } else {
159                 /* No argument list, this will be the first argument */
160
161                 op->common.value.arg = arg;
162         }
163
164         /* Set the parent in this arg and any args linked after it */
165
166         while (arg) {
167                 arg->common.parent = op;
168                 arg = arg->common.next;
169         }
170 }
171
172 #ifdef ACPI_FUTURE_USAGE
173 /*******************************************************************************
174  *
175  * FUNCTION:    acpi_ps_get_depth_next
176  *
177  * PARAMETERS:  Origin          - Root of subtree to search
178  *              Op              - Last (previous) Op that was found
179  *
180  * RETURN:      Next Op found in the search.
181  *
182  * DESCRIPTION: Get next op in tree (walking the tree in depth-first order)
183  *              Return NULL when reaching "origin" or when walking up from root
184  *
185  ******************************************************************************/
186
187 union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin,
188                                                 union acpi_parse_object *op)
189 {
190         union acpi_parse_object *next = NULL;
191         union acpi_parse_object *parent;
192         union acpi_parse_object *arg;
193
194         ACPI_FUNCTION_ENTRY();
195
196         if (!op) {
197                 return (NULL);
198         }
199
200         /* Look for an argument or child */
201
202         next = acpi_ps_get_arg(op, 0);
203         if (next) {
204                 return (next);
205         }
206
207         /* Look for a sibling */
208
209         next = op->common.next;
210         if (next) {
211                 return (next);
212         }
213
214         /* Look for a sibling of parent */
215
216         parent = op->common.parent;
217
218         while (parent) {
219                 arg = acpi_ps_get_arg(parent, 0);
220                 while (arg && (arg != origin) && (arg != op)) {
221                         arg = arg->common.next;
222                 }
223
224                 if (arg == origin) {
225                         /* Reached parent of origin, end search */
226
227                         return (NULL);
228                 }
229
230                 if (parent->common.next) {
231                         /* Found sibling of parent */
232
233                         return (parent->common.next);
234                 }
235
236                 op = parent;
237                 parent = parent->common.parent;
238         }
239
240         return (next);
241 }
242
243 #ifdef ACPI_OBSOLETE_FUNCTIONS
244 /*******************************************************************************
245  *
246  * FUNCTION:    acpi_ps_get_child
247  *
248  * PARAMETERS:  Op              - Get the child of this Op
249  *
250  * RETURN:      Child Op, Null if none is found.
251  *
252  * DESCRIPTION: Get op's children or NULL if none
253  *
254  ******************************************************************************/
255
256 union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op)
257 {
258         union acpi_parse_object *child = NULL;
259
260         ACPI_FUNCTION_ENTRY();
261
262         switch (op->common.aml_opcode) {
263         case AML_SCOPE_OP:
264         case AML_ELSE_OP:
265         case AML_DEVICE_OP:
266         case AML_THERMAL_ZONE_OP:
267         case AML_INT_METHODCALL_OP:
268
269                 child = acpi_ps_get_arg(op, 0);
270                 break;
271
272         case AML_BUFFER_OP:
273         case AML_PACKAGE_OP:
274         case AML_METHOD_OP:
275         case AML_IF_OP:
276         case AML_WHILE_OP:
277         case AML_FIELD_OP:
278
279                 child = acpi_ps_get_arg(op, 1);
280                 break;
281
282         case AML_POWER_RES_OP:
283         case AML_INDEX_FIELD_OP:
284
285                 child = acpi_ps_get_arg(op, 2);
286                 break;
287
288         case AML_PROCESSOR_OP:
289         case AML_BANK_FIELD_OP:
290
291                 child = acpi_ps_get_arg(op, 3);
292                 break;
293
294         default:
295                 /* All others have no children */
296                 break;
297         }
298
299         return (child);
300 }
301 #endif
302
303 #endif                          /*  ACPI_FUTURE_USAGE  */