diff options
Diffstat (limited to 'drivers/acpi/acpica/pstree.c')
-rw-r--r-- | drivers/acpi/acpica/pstree.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c new file mode 100644 index 0000000000..7f7f5ecd40 --- /dev/null +++ b/drivers/acpi/acpica/pstree.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 +/****************************************************************************** + * + * Module Name: pstree - Parser op tree manipulation/traversal/search + * + * Copyright (C) 2000 - 2023, Intel Corp. + * + *****************************************************************************/ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acconvert.h" + +#define _COMPONENT ACPI_PARSER +ACPI_MODULE_NAME("pstree") + +/* Local prototypes */ +#ifdef ACPI_OBSOLETE_FUNCTIONS +union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op); +#endif + +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_arg + * + * PARAMETERS: op - Get an argument for this op + * argn - Nth argument to get + * + * RETURN: The argument (as an Op object). NULL if argument does not exist + * + * DESCRIPTION: Get the specified op's argument. + * + ******************************************************************************/ + +union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn) +{ + union acpi_parse_object *arg = NULL; + const struct acpi_opcode_info *op_info; + + ACPI_FUNCTION_ENTRY(); + +/* + if (Op->Common.aml_opcode == AML_INT_CONNECTION_OP) + { + return (Op->Common.Value.Arg); + } +*/ + /* Get the info structure for this opcode */ + + op_info = acpi_ps_get_opcode_info(op->common.aml_opcode); + if (op_info->class == AML_CLASS_UNKNOWN) { + + /* Invalid opcode or ASCII character */ + + return (NULL); + } + + /* Check if this opcode requires argument sub-objects */ + + if (!(op_info->flags & AML_HAS_ARGS)) { + + /* Has no linked argument objects */ + + return (NULL); + } + + /* Get the requested argument object */ + + arg = op->common.value.arg; + while (arg && argn) { + argn--; + arg = arg->common.next; + } + + return (arg); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ps_append_arg + * + * PARAMETERS: op - Append an argument to this Op. + * arg - Argument Op to append + * + * RETURN: None. + * + * DESCRIPTION: Append an argument to an op's argument list (a NULL arg is OK) + * + ******************************************************************************/ + +void +acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) +{ + union acpi_parse_object *prev_arg; + const struct acpi_opcode_info *op_info; + + ACPI_FUNCTION_TRACE(ps_append_arg); + + if (!op) { + return_VOID; + } + + /* Get the info structure for this opcode */ + + op_info = acpi_ps_get_opcode_info(op->common.aml_opcode); + if (op_info->class == AML_CLASS_UNKNOWN) { + + /* Invalid opcode */ + + ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X", + op->common.aml_opcode)); + return_VOID; + } + + /* Check if this opcode requires argument sub-objects */ + + if (!(op_info->flags & AML_HAS_ARGS)) { + + /* Has no linked argument objects */ + + return_VOID; + } + + /* Append the argument to the linked argument list */ + + if (op->common.value.arg) { + + /* Append to existing argument list */ + + prev_arg = op->common.value.arg; + while (prev_arg->common.next) { + prev_arg = prev_arg->common.next; + } + prev_arg->common.next = arg; + } else { + /* No argument list, this will be the first argument */ + + op->common.value.arg = arg; + } + + /* Set the parent in this arg and any args linked after it */ + + while (arg) { + arg->common.parent = op; + arg = arg->common.next; + + op->common.arg_list_length++; + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_depth_next + * + * PARAMETERS: origin - Root of subtree to search + * op - Last (previous) Op that was found + * + * RETURN: Next Op found in the search. + * + * DESCRIPTION: Get next op in tree (walking the tree in depth-first order) + * Return NULL when reaching "origin" or when walking up from root + * + ******************************************************************************/ + +union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, + union acpi_parse_object *op) +{ + union acpi_parse_object *next = NULL; + union acpi_parse_object *parent; + union acpi_parse_object *arg; + + ACPI_FUNCTION_ENTRY(); + + if (!op) { + return (NULL); + } + + /* Look for an argument or child */ + + next = acpi_ps_get_arg(op, 0); + if (next) { + ASL_CV_LABEL_FILENODE(next); + return (next); + } + + /* Look for a sibling */ + + next = op->common.next; + if (next) { + ASL_CV_LABEL_FILENODE(next); + return (next); + } + + /* Look for a sibling of parent */ + + parent = op->common.parent; + + while (parent) { + arg = acpi_ps_get_arg(parent, 0); + while (arg && (arg != origin) && (arg != op)) { + + ASL_CV_LABEL_FILENODE(arg); + arg = arg->common.next; + } + + if (arg == origin) { + + /* Reached parent of origin, end search */ + + return (NULL); + } + + if (parent->common.next) { + + /* Found sibling of parent */ + + ASL_CV_LABEL_FILENODE(parent->common.next); + return (parent->common.next); + } + + op = parent; + parent = parent->common.parent; + } + + ASL_CV_LABEL_FILENODE(next); + return (next); +} + +#ifdef ACPI_OBSOLETE_FUNCTIONS +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_child + * + * PARAMETERS: op - Get the child of this Op + * + * RETURN: Child Op, Null if none is found. + * + * DESCRIPTION: Get op's children or NULL if none + * + ******************************************************************************/ + +union acpi_parse_object *acpi_ps_get_child(union acpi_parse_object *op) +{ + union acpi_parse_object *child = NULL; + + ACPI_FUNCTION_ENTRY(); + + switch (op->common.aml_opcode) { + case AML_SCOPE_OP: + case AML_ELSE_OP: + case AML_DEVICE_OP: + case AML_THERMAL_ZONE_OP: + case AML_INT_METHODCALL_OP: + + child = acpi_ps_get_arg(op, 0); + break; + + case AML_BUFFER_OP: + case AML_PACKAGE_OP: + case AML_VARIABLE_PACKAGE_OP: + case AML_METHOD_OP: + case AML_IF_OP: + case AML_WHILE_OP: + case AML_FIELD_OP: + + child = acpi_ps_get_arg(op, 1); + break; + + case AML_POWER_RESOURCE_OP: + case AML_INDEX_FIELD_OP: + + child = acpi_ps_get_arg(op, 2); + break; + + case AML_PROCESSOR_OP: + case AML_BANK_FIELD_OP: + + child = acpi_ps_get_arg(op, 3); + break; + + default: + + /* All others have no children */ + + break; + } + + return (child); +} +#endif |