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