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