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