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
48acpi_parse_object *
49acpi_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
102void
103acpi_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
177acpi_parse_object *
178acpi_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
242acpi_parse_object *
243acpi_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
302