Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[sfrench/cifs-2.6.git] / drivers / acpi / acpica / pstree.c
1 /******************************************************************************
2  *
3  * Module Name: pstree - Parser op tree manipulation/traversal/search
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2017, 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