summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/dispatcher
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/dispatcher')
-rw-r--r--drivers/acpi/dispatcher/Makefile9
-rw-r--r--drivers/acpi/dispatcher/dsfield.c649
-rw-r--r--drivers/acpi/dispatcher/dsinit.c204
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c623
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c717
-rw-r--r--drivers/acpi/dispatcher/dsobject.c812
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c1429
-rw-r--r--drivers/acpi/dispatcher/dsutils.c868
-rw-r--r--drivers/acpi/dispatcher/dswexec.c745
-rw-r--r--drivers/acpi/dispatcher/dswload.c1202
-rw-r--r--drivers/acpi/dispatcher/dswscope.c213
-rw-r--r--drivers/acpi/dispatcher/dswstate.c752
12 files changed, 8223 insertions, 0 deletions
diff --git a/drivers/acpi/dispatcher/Makefile b/drivers/acpi/dispatcher/Makefile
new file mode 100644
index 0000000..eb7e602
--- /dev/null
+++ b/drivers/acpi/dispatcher/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \
+ dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \
+ dsinit.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
new file mode 100644
index 0000000..f988a5e
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -0,0 +1,649 @@
+/******************************************************************************
+ *
+ * Module Name: dsfield - Dispatcher field routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dsfield")
+
+/* Local prototypes */
+static acpi_status
+acpi_ds_get_field_names(struct acpi_create_field_info *info,
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *arg);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_buffer_field
+ *
+ * PARAMETERS: Op - Current parse op (create_xXField)
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute the create_field operators:
+ * create_bit_field_op,
+ * create_byte_field_op,
+ * create_word_field_op,
+ * create_dword_field_op,
+ * create_qword_field_op,
+ * create_field_op (all of which define a field in a buffer)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_buffer_field(union acpi_parse_object *op,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_parse_object *arg;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *second_desc = NULL;
+ u32 flags;
+
+ ACPI_FUNCTION_TRACE(ds_create_buffer_field);
+
+ /*
+ * Get the name_string argument (name of the new buffer_field)
+ */
+ if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
+
+ /* For create_field, name is the 4th argument */
+
+ arg = acpi_ps_get_arg(op, 3);
+ } else {
+ /* For all other create_xXXField operators, name is the 3rd argument */
+
+ arg = acpi_ps_get_arg(op, 2);
+ }
+
+ if (!arg) {
+ return_ACPI_STATUS(AE_AML_NO_OPERAND);
+ }
+
+ if (walk_state->deferred_node) {
+ node = walk_state->deferred_node;
+ status = AE_OK;
+ } else {
+ /* Execute flag should always be set when this function is entered */
+
+ if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
+ /* Creating new namespace node, should not already exist */
+
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND;
+
+ /* Mark node temporary if we are executing a method */
+
+ if (walk_state->method_node) {
+ flags |= ACPI_NS_TEMPORARY;
+ }
+
+ /* Enter the name_string into the namespace */
+
+ status =
+ acpi_ns_lookup(walk_state->scope_info,
+ arg->common.value.string, ACPI_TYPE_ANY,
+ ACPI_IMODE_LOAD_PASS1, flags, walk_state,
+ &node);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ /*
+ * We could put the returned object (Node) on the object stack for later,
+ * but for now, we will put it in the "op" object that the parser uses,
+ * so we can get it again at the end of this scope.
+ */
+ op->common.node = node;
+
+ /*
+ * If there is no object attached to the node, this node was just created
+ * and we need to create the field object. Otherwise, this was a lookup
+ * of an existing node and we don't want to create the field object again.
+ */
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (obj_desc) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /*
+ * The Field definition is not fully parsed at this time.
+ * (We must save the address of the AML for the buffer and index operands)
+ */
+
+ /* Create the buffer field object */
+
+ obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER_FIELD);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Remember location in AML stream of the field unit opcode and operands --
+ * since the buffer and index operands must be evaluated.
+ */
+ second_desc = obj_desc->common.next_object;
+ second_desc->extra.aml_start = op->named.data;
+ second_desc->extra.aml_length = op->named.length;
+ obj_desc->buffer_field.node = node;
+
+ /* Attach constructed field descriptors to parent node */
+
+ status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_BUFFER_FIELD);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ cleanup:
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_field_names
+ *
+ * PARAMETERS: Info - create_field info structure
+ * ` walk_state - Current method state
+ * Arg - First parser arg for the field name list
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Process all named fields in a field declaration. Names are
+ * entered into the namespace.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_get_field_names(struct acpi_create_field_info *info,
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *arg)
+{
+ acpi_status status;
+ acpi_integer position;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info);
+
+ /* First field starts at bit zero */
+
+ info->field_bit_position = 0;
+
+ /* Process all elements in the field list (of parse nodes) */
+
+ while (arg) {
+ /*
+ * Three types of field elements are handled:
+ * 1) Offset - specifies a bit offset
+ * 2) access_as - changes the access mode
+ * 3) Name - Enters a new named field into the namespace
+ */
+ switch (arg->common.aml_opcode) {
+ case AML_INT_RESERVEDFIELD_OP:
+
+ position = (acpi_integer) info->field_bit_position
+ + (acpi_integer) arg->common.value.size;
+
+ if (position > ACPI_UINT32_MAX) {
+ ACPI_ERROR((AE_INFO,
+ "Bit offset within field too large (> 0xFFFFFFFF)"));
+ return_ACPI_STATUS(AE_SUPPORT);
+ }
+
+ info->field_bit_position = (u32) position;
+ break;
+
+ case AML_INT_ACCESSFIELD_OP:
+
+ /*
+ * Get a new access_type and access_attribute -- to be used for all
+ * field units that follow, until field end or another access_as
+ * keyword.
+ *
+ * In field_flags, preserve the flag bits other than the
+ * ACCESS_TYPE bits
+ */
+ info->field_flags = (u8)
+ ((info->
+ field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) |
+ ((u8) ((u32) arg->common.value.integer >> 8)));
+
+ info->attribute = (u8) (arg->common.value.integer);
+ break;
+
+ case AML_INT_NAMEDFIELD_OP:
+
+ /* Lookup the name, it should already exist */
+
+ status = acpi_ns_lookup(walk_state->scope_info,
+ (char *)&arg->named.name,
+ info->field_type,
+ ACPI_IMODE_EXECUTE,
+ ACPI_NS_DONT_OPEN_SCOPE,
+ walk_state, &info->field_node);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
+ status);
+ return_ACPI_STATUS(status);
+ } else {
+ arg->common.node = info->field_node;
+ info->field_bit_length = arg->common.value.size;
+
+ /*
+ * If there is no object attached to the node, this node was
+ * just created and we need to create the field object.
+ * Otherwise, this was a lookup of an existing node and we
+ * don't want to create the field object again.
+ */
+ if (!acpi_ns_get_attached_object
+ (info->field_node)) {
+ status = acpi_ex_prep_field_value(info);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+ }
+
+ /* Keep track of bit position for the next field */
+
+ position = (acpi_integer) info->field_bit_position
+ + (acpi_integer) arg->common.value.size;
+
+ if (position > ACPI_UINT32_MAX) {
+ ACPI_ERROR((AE_INFO,
+ "Field [%4.4s] bit offset too large (> 0xFFFFFFFF)",
+ ACPI_CAST_PTR(char,
+ &info->field_node->
+ name)));
+ return_ACPI_STATUS(AE_SUPPORT);
+ }
+
+ info->field_bit_position += info->field_bit_length;
+ break;
+
+ default:
+
+ ACPI_ERROR((AE_INFO,
+ "Invalid opcode in field list: %X",
+ arg->common.aml_opcode));
+ return_ACPI_STATUS(AE_AML_BAD_OPCODE);
+ }
+
+ arg = arg->common.next;
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * region_node - Object for the containing Operation Region
+ * ` walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new field in the specified operation region
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_field(union acpi_parse_object *op,
+ struct acpi_namespace_node *region_node,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_parse_object *arg;
+ struct acpi_create_field_info info;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_create_field, op);
+
+ /* First arg is the name of the parent op_region (must already exist) */
+
+ arg = op->common.value.arg;
+ if (!region_node) {
+ status =
+ acpi_ns_lookup(walk_state->scope_info,
+ arg->common.value.name, ACPI_TYPE_REGION,
+ ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
+ walk_state, &region_node);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(arg->common.value.name, status);
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ /* Second arg is the field flags */
+
+ arg = arg->common.next;
+ info.field_flags = (u8) arg->common.value.integer;
+ info.attribute = 0;
+
+ /* Each remaining arg is a Named Field */
+
+ info.field_type = ACPI_TYPE_LOCAL_REGION_FIELD;
+ info.region_node = region_node;
+
+ status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_field_objects
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * ` walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: For each "Field Unit" name in the argument list that is
+ * part of the field declaration, enter the name into the
+ * namespace.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_init_field_objects(union acpi_parse_object *op,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_parse_object *arg = NULL;
+ struct acpi_namespace_node *node;
+ u8 type = 0;
+ u32 flags;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op);
+
+ /* Execute flag should always be set when this function is entered */
+
+ if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
+ if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) {
+
+ /* bank_field Op is deferred, just return OK */
+
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
+ /*
+ * Get the field_list argument for this opcode. This is the start of the
+ * list of field elements.
+ */
+ switch (walk_state->opcode) {
+ case AML_FIELD_OP:
+ arg = acpi_ps_get_arg(op, 2);
+ type = ACPI_TYPE_LOCAL_REGION_FIELD;
+ break;
+
+ case AML_BANK_FIELD_OP:
+ arg = acpi_ps_get_arg(op, 4);
+ type = ACPI_TYPE_LOCAL_BANK_FIELD;
+ break;
+
+ case AML_INDEX_FIELD_OP:
+ arg = acpi_ps_get_arg(op, 3);
+ type = ACPI_TYPE_LOCAL_INDEX_FIELD;
+ break;
+
+ default:
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Creating new namespace node(s), should not already exist */
+
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND;
+
+ /* Mark node(s) temporary if we are executing a method */
+
+ if (walk_state->method_node) {
+ flags |= ACPI_NS_TEMPORARY;
+ }
+
+ /*
+ * Walk the list of entries in the field_list
+ * Note: field_list can be of zero length. In this case, Arg will be NULL.
+ */
+ while (arg) {
+ /*
+ * Ignore OFFSET and ACCESSAS terms here; we are only interested in the
+ * field names in order to enter them into the namespace.
+ */
+ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
+ status = acpi_ns_lookup(walk_state->scope_info,
+ (char *)&arg->named.name, type,
+ ACPI_IMODE_LOAD_PASS1, flags,
+ walk_state, &node);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
+ status);
+ if (status != AE_ALREADY_EXISTS) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Name already exists, just ignore this error */
+
+ status = AE_OK;
+ }
+
+ arg->common.node = node;
+ }
+
+ /* Get the next field element in the list */
+
+ arg = arg->common.next;
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_bank_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * region_node - Object for the containing Operation Region
+ * walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new bank field in the specified operation region
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_bank_field(union acpi_parse_object *op,
+ struct acpi_namespace_node *region_node,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_parse_object *arg;
+ struct acpi_create_field_info info;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_create_bank_field, op);
+
+ /* First arg is the name of the parent op_region (must already exist) */
+
+ arg = op->common.value.arg;
+ if (!region_node) {
+ status =
+ acpi_ns_lookup(walk_state->scope_info,
+ arg->common.value.name, ACPI_TYPE_REGION,
+ ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
+ walk_state, &region_node);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(arg->common.value.name, status);
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ /* Second arg is the Bank Register (Field) (must already exist) */
+
+ arg = arg->common.next;
+ status =
+ acpi_ns_lookup(walk_state->scope_info, arg->common.value.string,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state,
+ &info.register_node);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Third arg is the bank_value
+ * This arg is a term_arg, not a constant
+ * It will be evaluated later, by acpi_ds_eval_bank_field_operands
+ */
+ arg = arg->common.next;
+
+ /* Fourth arg is the field flags */
+
+ arg = arg->common.next;
+ info.field_flags = (u8) arg->common.value.integer;
+
+ /* Each remaining arg is a Named Field */
+
+ info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD;
+ info.region_node = region_node;
+
+ /*
+ * Use Info.data_register_node to store bank_field Op
+ * It's safe because data_register_node will never be used when create bank field
+ * We store aml_start and aml_length in the bank_field Op for late evaluation
+ * Used in acpi_ex_prep_field_value(Info)
+ *
+ * TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"?
+ */
+ info.data_register_node = (struct acpi_namespace_node *)op;
+
+ status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_index_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * region_node - Object for the containing Operation Region
+ * ` walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new index field in the specified operation region
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_index_field(union acpi_parse_object *op,
+ struct acpi_namespace_node *region_node,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_parse_object *arg;
+ struct acpi_create_field_info info;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_create_index_field, op);
+
+ /* First arg is the name of the Index register (must already exist) */
+
+ arg = op->common.value.arg;
+ status =
+ acpi_ns_lookup(walk_state->scope_info, arg->common.value.string,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state,
+ &info.register_node);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
+ return_ACPI_STATUS(status);
+ }
+
+ /* Second arg is the data register (must already exist) */
+
+ arg = arg->common.next;
+ status =
+ acpi_ns_lookup(walk_state->scope_info, arg->common.value.string,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state,
+ &info.data_register_node);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
+ return_ACPI_STATUS(status);
+ }
+
+ /* Next arg is the field flags */
+
+ arg = arg->common.next;
+ info.field_flags = (u8) arg->common.value.integer;
+
+ /* Each remaining arg is a Named Field */
+
+ info.field_type = ACPI_TYPE_LOCAL_INDEX_FIELD;
+ info.region_node = region_node;
+
+ status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
+
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
new file mode 100644
index 0000000..949f7c7
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -0,0 +1,204 @@
+/******************************************************************************
+ *
+ * Module Name: dsinit - Object initialization namespace walk
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acdispat.h>
+#include <acpi/acnamesp.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dsinit")
+
+/* Local prototypes */
+static acpi_status
+acpi_ds_init_one_object(acpi_handle obj_handle,
+ u32 level, void *context, void **return_value);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_one_object
+ *
+ * PARAMETERS: obj_handle - Node for the object
+ * Level - Current nesting level
+ * Context - Points to a init info struct
+ * return_value - Not used
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object
+ * within the namespace.
+ *
+ * Currently, the only objects that require initialization are:
+ * 1) Methods
+ * 2) Operation Regions
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_init_one_object(acpi_handle obj_handle,
+ u32 level, void *context, void **return_value)
+{
+ struct acpi_init_walk_info *info =
+ (struct acpi_init_walk_info *)context;
+ struct acpi_namespace_node *node =
+ (struct acpi_namespace_node *)obj_handle;
+ acpi_object_type type;
+ acpi_status status;
+
+ ACPI_FUNCTION_ENTRY();
+
+ /*
+ * We are only interested in NS nodes owned by the table that
+ * was just loaded
+ */
+ if (node->owner_id != info->owner_id) {
+ return (AE_OK);
+ }
+
+ info->object_count++;
+
+ /* And even then, we are only interested in a few object types */
+
+ type = acpi_ns_get_type(obj_handle);
+
+ switch (type) {
+ case ACPI_TYPE_REGION:
+
+ status = acpi_ds_initialize_region(obj_handle);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During Region initialization %p [%4.4s]",
+ obj_handle,
+ acpi_ut_get_node_name(obj_handle)));
+ }
+
+ info->op_region_count++;
+ break;
+
+ case ACPI_TYPE_METHOD:
+
+ info->method_count++;
+ break;
+
+ case ACPI_TYPE_DEVICE:
+
+ info->device_count++;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * We ignore errors from above, and always return OK, since
+ * we don't want to abort the walk on a single error.
+ */
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_initialize_objects
+ *
+ * PARAMETERS: table_desc - Descriptor for parent ACPI table
+ * start_node - Root of subtree to be initialized.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Walk the namespace starting at "StartNode" and perform any
+ * necessary initialization on the objects found therein
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_initialize_objects(u32 table_index,
+ struct acpi_namespace_node * start_node)
+{
+ acpi_status status;
+ struct acpi_init_walk_info info;
+ struct acpi_table_header *table;
+ acpi_owner_id owner_id;
+
+ ACPI_FUNCTION_TRACE(ds_initialize_objects);
+
+ status = acpi_tb_get_owner_id(table_index, &owner_id);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "**** Starting initialization of namespace objects ****\n"));
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
+
+ info.method_count = 0;
+ info.op_region_count = 0;
+ info.object_count = 0;
+ info.device_count = 0;
+ info.table_index = table_index;
+ info.owner_id = owner_id;
+
+ /* Walk entire namespace from the supplied root */
+
+ status = acpi_walk_namespace(ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX,
+ acpi_ds_init_one_object, &info, NULL);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
+ }
+
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
+ "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
+ table->signature, owner_id, info.object_count,
+ info.device_count, info.method_count,
+ info.op_region_count));
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "%hd Methods, %hd Regions\n", info.method_count,
+ info.op_region_count));
+
+ return_ACPI_STATUS(AE_OK);
+}
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
new file mode 100644
index 0000000..279a5a6
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -0,0 +1,623 @@
+/******************************************************************************
+ *
+ * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acdisasm.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dsmethod")
+
+/* Local prototypes */
+static acpi_status
+acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_error
+ *
+ * PARAMETERS: Status - Execution status
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Called on method error. Invoke the global exception handler if
+ * present, dump the method data if the disassembler is configured
+ *
+ * Note: Allows the exception handler to change the status code
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
+{
+ ACPI_FUNCTION_ENTRY();
+
+ /* Ignore AE_OK and control exception codes */
+
+ if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) {
+ return (status);
+ }
+
+ /* Invoke the global exception handler */
+
+ if (acpi_gbl_exception_handler) {
+
+ /* Exit the interpreter, allow handler to execute methods */
+
+ acpi_ex_exit_interpreter();
+
+ /*
+ * Handler can map the exception code to anything it wants, including
+ * AE_OK, in which case the executing method will not be aborted.
+ */
+ status = acpi_gbl_exception_handler(status,
+ walk_state->method_node ?
+ walk_state->method_node->
+ name.integer : 0,
+ walk_state->opcode,
+ walk_state->aml_offset,
+ NULL);
+ acpi_ex_enter_interpreter();
+ }
+
+ acpi_ds_clear_implicit_return(walk_state);
+
+#ifdef ACPI_DISASSEMBLER
+ if (ACPI_FAILURE(status)) {
+
+ /* Display method locals/args if disassembler is present */
+
+ acpi_dm_dump_method_info(status, walk_state, walk_state->op);
+ }
+#endif
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_method_mutex
+ *
+ * PARAMETERS: obj_desc - The method object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a mutex object for a serialized control method
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_create_method_mutex(union acpi_operand_object *method_desc)
+{
+ union acpi_operand_object *mutex_desc;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ds_create_method_mutex);
+
+ /* Create the new mutex object */
+
+ mutex_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX);
+ if (!mutex_desc) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Create the actual OS Mutex */
+
+ status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ mutex_desc->mutex.sync_level = method_desc->method.sync_level;
+ method_desc->method.mutex = mutex_desc;
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_begin_method_execution
+ *
+ * PARAMETERS: method_node - Node of the method
+ * obj_desc - The method object
+ * walk_state - current state, NULL if not yet executing
+ * a method.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
+ * increments the thread count, and waits at the method semaphore
+ * for clearance to execute.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
+ union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);
+
+ if (!method_node) {
+ return_ACPI_STATUS(AE_NULL_ENTRY);
+ }
+
+ /* Prevent wraparound of thread count */
+
+ if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
+ ACPI_ERROR((AE_INFO,
+ "Method reached maximum reentrancy limit (255)"));
+ return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
+ }
+
+ /*
+ * If this method is serialized, we need to acquire the method mutex.
+ */
+ if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) {
+ /*
+ * Create a mutex for the method if it is defined to be Serialized
+ * and a mutex has not already been created. We defer the mutex creation
+ * until a method is actually executed, to minimize the object count
+ */
+ if (!obj_desc->method.mutex) {
+ status = acpi_ds_create_method_mutex(obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ /*
+ * The current_sync_level (per-thread) must be less than or equal to
+ * the sync level of the method. This mechanism provides some
+ * deadlock prevention
+ *
+ * Top-level method invocation has no walk state at this point
+ */
+ if (walk_state &&
+ (walk_state->thread->current_sync_level >
+ obj_desc->method.mutex->mutex.sync_level)) {
+ ACPI_ERROR((AE_INFO,
+ "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%d)",
+ acpi_ut_get_node_name(method_node),
+ walk_state->thread->current_sync_level));
+
+ return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
+ }
+
+ /*
+ * Obtain the method mutex if necessary. Do not acquire mutex for a
+ * recursive call.
+ */
+ if (!walk_state ||
+ !obj_desc->method.mutex->mutex.thread_id ||
+ (walk_state->thread->thread_id !=
+ obj_desc->method.mutex->mutex.thread_id)) {
+ /*
+ * Acquire the method mutex. This releases the interpreter if we
+ * block (and reacquires it before it returns)
+ */
+ status =
+ acpi_ex_system_wait_mutex(obj_desc->method.mutex->
+ mutex.os_mutex,
+ ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Update the mutex and walk info and save the original sync_level */
+
+ if (walk_state) {
+ obj_desc->method.mutex->mutex.
+ original_sync_level =
+ walk_state->thread->current_sync_level;
+
+ obj_desc->method.mutex->mutex.thread_id =
+ walk_state->thread->thread_id;
+ walk_state->thread->current_sync_level =
+ obj_desc->method.sync_level;
+ } else {
+ obj_desc->method.mutex->mutex.
+ original_sync_level =
+ obj_desc->method.mutex->mutex.sync_level;
+ }
+ }
+
+ /* Always increase acquisition depth */
+
+ obj_desc->method.mutex->mutex.acquisition_depth++;
+ }
+
+ /*
+ * Allocate an Owner ID for this method, only if this is the first thread
+ * to begin concurrent execution. We only need one owner_id, even if the
+ * method is invoked recursively.
+ */
+ if (!obj_desc->method.owner_id) {
+ status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Increment the method parse tree thread count since it has been
+ * reentered one more time (even if it is the same thread)
+ */
+ obj_desc->method.thread_count++;
+ return_ACPI_STATUS(status);
+
+ cleanup:
+ /* On error, must release the method mutex (if present) */
+
+ if (obj_desc->method.mutex) {
+ acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex);
+ }
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_call_control_method
+ *
+ * PARAMETERS: Thread - Info for this thread
+ * this_walk_state - Current walk state
+ * Op - Current Op to be walked
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Transfer execution to a called control method
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_call_control_method(struct acpi_thread_state *thread,
+ struct acpi_walk_state *this_walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ struct acpi_namespace_node *method_node;
+ struct acpi_walk_state *next_walk_state = NULL;
+ union acpi_operand_object *obj_desc;
+ struct acpi_evaluate_info *info;
+ u32 i;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Calling method %p, currentstate=%p\n",
+ this_walk_state->prev_op, this_walk_state));
+
+ /*
+ * Get the namespace entry for the control method we are about to call
+ */
+ method_node = this_walk_state->method_call_node;
+ if (!method_node) {
+ return_ACPI_STATUS(AE_NULL_ENTRY);
+ }
+
+ obj_desc = acpi_ns_get_attached_object(method_node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NULL_OBJECT);
+ }
+
+ /* Init for new method, possibly wait on method mutex */
+
+ status = acpi_ds_begin_method_execution(method_node, obj_desc,
+ this_walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Begin method parse/execution. Create a new walk state */
+
+ next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
+ NULL, obj_desc, thread);
+ if (!next_walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * The resolved arguments were put on the previous walk state's operand
+ * stack. Operands on the previous walk state stack always
+ * start at index 0. Also, null terminate the list of arguments
+ */
+ this_walk_state->operands[this_walk_state->num_operands] = NULL;
+
+ /*
+ * Allocate and initialize the evaluation information block
+ * TBD: this is somewhat inefficient, should change interface to
+ * ds_init_aml_walk. For now, keeps this struct off the CPU stack
+ */
+ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
+ if (!info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ info->parameters = &this_walk_state->operands[0];
+
+ status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
+ obj_desc->method.aml_start,
+ obj_desc->method.aml_length, info,
+ ACPI_IMODE_EXECUTE);
+
+ ACPI_FREE(info);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ /*
+ * Delete the operands on the previous walkstate operand stack
+ * (they were copied to new objects)
+ */
+ for (i = 0; i < obj_desc->method.param_count; i++) {
+ acpi_ut_remove_reference(this_walk_state->operands[i]);
+ this_walk_state->operands[i] = NULL;
+ }
+
+ /* Clear the operand stack */
+
+ this_walk_state->num_operands = 0;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
+ method_node->name.ascii, next_walk_state));
+
+ /* Invoke an internal method if necessary */
+
+ if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
+ status = obj_desc->method.implementation(next_walk_state);
+ }
+
+ return_ACPI_STATUS(status);
+
+ cleanup:
+
+ /* On error, we must terminate the method properly */
+
+ acpi_ds_terminate_control_method(obj_desc, next_walk_state);
+ if (next_walk_state) {
+ acpi_ds_delete_walk_state(next_walk_state);
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_restart_control_method
+ *
+ * PARAMETERS: walk_state - State for preempted method (caller)
+ * return_desc - Return value from the called method
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Restart a method that was preempted by another (nested) method
+ * invocation. Handle the return value (if any) from the callee.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
+ union acpi_operand_object *return_desc)
+{
+ acpi_status status;
+ int same_as_implicit_return;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
+ acpi_ut_get_node_name(walk_state->method_node),
+ walk_state->method_call_op, return_desc));
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
+ walk_state->return_used,
+ walk_state->results, walk_state));
+
+ /* Did the called method return a value? */
+
+ if (return_desc) {
+
+ /* Is the implicit return object the same as the return desc? */
+
+ same_as_implicit_return =
+ (walk_state->implicit_return_obj == return_desc);
+
+ /* Are we actually going to use the return value? */
+
+ if (walk_state->return_used) {
+
+ /* Save the return value from the previous method */
+
+ status = acpi_ds_result_push(return_desc, walk_state);
+ if (ACPI_FAILURE(status)) {
+ acpi_ut_remove_reference(return_desc);
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Save as THIS method's return value in case it is returned
+ * immediately to yet another method
+ */
+ walk_state->return_desc = return_desc;
+ }
+
+ /*
+ * The following code is the optional support for the so-called
+ * "implicit return". Some AML code assumes that the last value of the
+ * method is "implicitly" returned to the caller, in the absence of an
+ * explicit return value.
+ *
+ * Just save the last result of the method as the return value.
+ *
+ * NOTE: this is optional because the ASL language does not actually
+ * support this behavior.
+ */
+ else if (!acpi_ds_do_implicit_return
+ (return_desc, walk_state, FALSE)
+ || same_as_implicit_return) {
+ /*
+ * Delete the return value if it will not be used by the
+ * calling method or remove one reference if the explicit return
+ * is the same as the implicit return value.
+ */
+ acpi_ut_remove_reference(return_desc);
+ }
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_terminate_control_method
+ *
+ * PARAMETERS: method_desc - Method object
+ * walk_state - State associated with the method
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Terminate a control method. Delete everything that the method
+ * created, delete all locals and arguments, and delete the parse
+ * tree if requested.
+ *
+ * MUTEX: Interpreter is locked
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
+ struct acpi_walk_state *walk_state)
+{
+
+ ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
+
+ /* method_desc is required, walk_state is optional */
+
+ if (!method_desc) {
+ return_VOID;
+ }
+
+ if (walk_state) {
+
+ /* Delete all arguments and locals */
+
+ acpi_ds_method_data_delete_all(walk_state);
+
+ /*
+ * If method is serialized, release the mutex and restore the
+ * current sync level for this thread
+ */
+ if (method_desc->method.mutex) {
+
+ /* Acquisition Depth handles recursive calls */
+
+ method_desc->method.mutex->mutex.acquisition_depth--;
+ if (!method_desc->method.mutex->mutex.acquisition_depth) {
+ walk_state->thread->current_sync_level =
+ method_desc->method.mutex->mutex.
+ original_sync_level;
+
+ acpi_os_release_mutex(method_desc->method.
+ mutex->mutex.os_mutex);
+ method_desc->method.mutex->mutex.thread_id = NULL;
+ }
+ }
+
+ /*
+ * Delete any namespace objects created anywhere within
+ * the namespace by the execution of this method
+ */
+ acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
+ }
+
+ /* Decrement the thread count on the method */
+
+ if (method_desc->method.thread_count) {
+ method_desc->method.thread_count--;
+ } else {
+ ACPI_ERROR((AE_INFO, "Invalid zero thread count in method"));
+ }
+
+ /* Are there any other threads currently executing this method? */
+
+ if (method_desc->method.thread_count) {
+ /*
+ * Additional threads. Do not release the owner_id in this case,
+ * we immediately reuse it for the next thread executing this method
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "*** Completed execution of one thread, %d threads remaining\n",
+ method_desc->method.thread_count));
+ } else {
+ /* This is the only executing thread for this method */
+
+ /*
+ * Support to dynamically change a method from not_serialized to
+ * Serialized if it appears that the method is incorrectly written and
+ * does not support multiple thread execution. The best example of this
+ * is if such a method creates namespace objects and blocks. A second
+ * thread will fail with an AE_ALREADY_EXISTS exception
+ *
+ * This code is here because we must wait until the last thread exits
+ * before creating the synchronization semaphore.
+ */
+ if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
+ && (!method_desc->method.mutex)) {
+ (void)acpi_ds_create_method_mutex(method_desc);
+ }
+
+ /* No more threads, we can free the owner_id */
+
+ acpi_ut_release_owner_id(&method_desc->method.owner_id);
+ }
+
+ return_VOID;
+}
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
new file mode 100644
index 0000000..d03f81b
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -0,0 +1,717 @@
+/*******************************************************************************
+ *
+ * Module Name: dsmthdat - control method arguments and local variables
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acdispat.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dsmthdat")
+
+/* Local prototypes */
+static void
+acpi_ds_method_data_delete_value(u8 type,
+ u32 index, struct acpi_walk_state *walk_state);
+
+static acpi_status
+acpi_ds_method_data_set_value(u8 type,
+ u32 index,
+ union acpi_operand_object *object,
+ struct acpi_walk_state *walk_state);
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+acpi_object_type
+acpi_ds_method_data_get_type(u16 opcode,
+ u32 index, struct acpi_walk_state *walk_state);
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_init
+ *
+ * PARAMETERS: walk_state - Current walk state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the data structures that hold the method's arguments
+ * and locals. The data struct is an array of namespace nodes for
+ * each - this allows ref_of and de_ref_of to work properly for these
+ * special data types.
+ *
+ * NOTES: walk_state fields are initialized to zero by the
+ * ACPI_ALLOCATE_ZEROED().
+ *
+ * A pseudo-Namespace Node is assigned to each argument and local
+ * so that ref_of() can return a pointer to the Node.
+ *
+ ******************************************************************************/
+
+void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
+{
+ u32 i;
+
+ ACPI_FUNCTION_TRACE(ds_method_data_init);
+
+ /* Init the method arguments */
+
+ for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
+ ACPI_MOVE_32_TO_32(&walk_state->arguments[i].name,
+ NAMEOF_ARG_NTE);
+ walk_state->arguments[i].name.integer |= (i << 24);
+ walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;
+ walk_state->arguments[i].type = ACPI_TYPE_ANY;
+ walk_state->arguments[i].flags =
+ ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
+ }
+
+ /* Init the method locals */
+
+ for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
+ ACPI_MOVE_32_TO_32(&walk_state->local_variables[i].name,
+ NAMEOF_LOCAL_NTE);
+
+ walk_state->local_variables[i].name.integer |= (i << 24);
+ walk_state->local_variables[i].descriptor_type =
+ ACPI_DESC_TYPE_NAMED;
+ walk_state->local_variables[i].type = ACPI_TYPE_ANY;
+ walk_state->local_variables[i].flags =
+ ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_delete_all
+ *
+ * PARAMETERS: walk_state - Current walk state object
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete method locals and arguments. Arguments are only
+ * deleted if this method was called from another method.
+ *
+ ******************************************************************************/
+
+void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)
+{
+ u32 index;
+
+ ACPI_FUNCTION_TRACE(ds_method_data_delete_all);
+
+ /* Detach the locals */
+
+ for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) {
+ if (walk_state->local_variables[index].object) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%d=%p\n",
+ index,
+ walk_state->local_variables[index].
+ object));
+
+ /* Detach object (if present) and remove a reference */
+
+ acpi_ns_detach_object(&walk_state->
+ local_variables[index]);
+ }
+ }
+
+ /* Detach the arguments */
+
+ for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) {
+ if (walk_state->arguments[index].object) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%d=%p\n",
+ index,
+ walk_state->arguments[index].object));
+
+ /* Detach object (if present) and remove a reference */
+
+ acpi_ns_detach_object(&walk_state->arguments[index]);
+ }
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_init_args
+ *
+ * PARAMETERS: *Params - Pointer to a parameter list for the method
+ * max_param_count - The arg count for this method
+ * walk_state - Current walk state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize arguments for a method. The parameter list is a list
+ * of ACPI operand objects, either null terminated or whose length
+ * is defined by max_param_count.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_method_data_init_args(union acpi_operand_object **params,
+ u32 max_param_count,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ u32 index = 0;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_method_data_init_args, params);
+
+ if (!params) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "No param list passed to method\n"));
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Copy passed parameters into the new method stack frame */
+
+ while ((index < ACPI_METHOD_NUM_ARGS) &&
+ (index < max_param_count) && params[index]) {
+ /*
+ * A valid parameter.
+ * Store the argument in the method/walk descriptor.
+ * Do not copy the arg in order to implement call by reference
+ */
+ status = acpi_ds_method_data_set_value(ACPI_REFCLASS_ARG, index,
+ params[index],
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ index++;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%d args passed to method\n", index));
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_get_node
+ *
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
+ * Index - Which Local or Arg whose type to get
+ * walk_state - Current walk state object
+ * Node - Where the node is returned.
+ *
+ * RETURN: Status and node
+ *
+ * DESCRIPTION: Get the Node associated with a local or arg.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_method_data_get_node(u8 type,
+ u32 index,
+ struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node **node)
+{
+ ACPI_FUNCTION_TRACE(ds_method_data_get_node);
+
+ /*
+ * Method Locals and Arguments are supported
+ */
+ switch (type) {
+ case ACPI_REFCLASS_LOCAL:
+
+ if (index > ACPI_METHOD_MAX_LOCAL) {
+ ACPI_ERROR((AE_INFO,
+ "Local index %d is invalid (max %d)",
+ index, ACPI_METHOD_MAX_LOCAL));
+ return_ACPI_STATUS(AE_AML_INVALID_INDEX);
+ }
+
+ /* Return a pointer to the pseudo-node */
+
+ *node = &walk_state->local_variables[index];
+ break;
+
+ case ACPI_REFCLASS_ARG:
+
+ if (index > ACPI_METHOD_MAX_ARG) {
+ ACPI_ERROR((AE_INFO,
+ "Arg index %d is invalid (max %d)",
+ index, ACPI_METHOD_MAX_ARG));
+ return_ACPI_STATUS(AE_AML_INVALID_INDEX);
+ }
+
+ /* Return a pointer to the pseudo-node */
+
+ *node = &walk_state->arguments[index];
+ break;
+
+ default:
+ ACPI_ERROR((AE_INFO, "Type %d is invalid", type));
+ return_ACPI_STATUS(AE_TYPE);
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_set_value
+ *
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
+ * Index - Which Local or Arg to get
+ * Object - Object to be inserted into the stack entry
+ * walk_state - Current walk state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index.
+ * Note: There is no "implicit conversion" for locals.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_method_data_set_value(u8 type,
+ u32 index,
+ union acpi_operand_object *object,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+
+ ACPI_FUNCTION_TRACE(ds_method_data_set_value);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "NewObj %p Type %2.2X, Refs=%d [%s]\n", object,
+ type, object->common.reference_count,
+ acpi_ut_get_type_name(object->common.type)));
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Increment ref count so object can't be deleted while installed.
+ * NOTE: We do not copy the object in order to preserve the call by
+ * reference semantics of ACPI Control Method invocation.
+ * (See ACPI Specification 2.0_c)
+ */
+ acpi_ut_add_reference(object);
+
+ /* Install the object */
+
+ node->object = object;
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_get_value
+ *
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
+ * Index - Which local_var or argument to get
+ * walk_state - Current walk state object
+ * dest_desc - Where Arg or Local value is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve value of selected Arg or Local for this method
+ * Used only in acpi_ex_resolve_to_value().
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_method_data_get_value(u8 type,
+ u32 index,
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object **dest_desc)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *object;
+
+ ACPI_FUNCTION_TRACE(ds_method_data_get_value);
+
+ /* Validate the object descriptor */
+
+ if (!dest_desc) {
+ ACPI_ERROR((AE_INFO, "Null object descriptor pointer"));
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Get the object from the node */
+
+ object = node->object;
+
+ /* Examine the returned object, it must be valid. */
+
+ if (!object) {
+ /*
+ * Index points to uninitialized object.
+ * This means that either 1) The expected argument was
+ * not passed to the method, or 2) A local variable
+ * was referenced by the method (via the ASL)
+ * before it was initialized. Either case is an error.
+ */
+
+ /* If slack enabled, init the local_x/arg_x to an Integer of value zero */
+
+ if (acpi_gbl_enable_interpreter_slack) {
+ object =
+ acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
+ if (!object) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ object->integer.value = 0;
+ node->object = object;
+ }
+
+ /* Otherwise, return the error */
+
+ else
+ switch (type) {
+ case ACPI_REFCLASS_ARG:
+
+ ACPI_ERROR((AE_INFO,
+ "Uninitialized Arg[%d] at node %p",
+ index, node));
+
+ return_ACPI_STATUS(AE_AML_UNINITIALIZED_ARG);
+
+ case ACPI_REFCLASS_LOCAL:
+
+ ACPI_ERROR((AE_INFO,
+ "Uninitialized Local[%d] at node %p",
+ index, node));
+
+ return_ACPI_STATUS(AE_AML_UNINITIALIZED_LOCAL);
+
+ default:
+
+ ACPI_ERROR((AE_INFO,
+ "Not a Arg/Local opcode: %X",
+ type));
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+ }
+
+ /*
+ * The Index points to an initialized and valid object.
+ * Return an additional reference to the object
+ */
+ *dest_desc = object;
+ acpi_ut_add_reference(object);
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_delete_value
+ *
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
+ * Index - Which local_var or argument to delete
+ * walk_state - Current walk state object
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete the entry at Opcode:Index. Inserts
+ * a null into the stack slot after the object is deleted.
+ *
+ ******************************************************************************/
+
+static void
+acpi_ds_method_data_delete_value(u8 type,
+ u32 index, struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *object;
+
+ ACPI_FUNCTION_TRACE(ds_method_data_delete_value);
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
+ if (ACPI_FAILURE(status)) {
+ return_VOID;
+ }
+
+ /* Get the associated object */
+
+ object = acpi_ns_get_attached_object(node);
+
+ /*
+ * Undefine the Arg or Local by setting its descriptor
+ * pointer to NULL. Locals/Args can contain both
+ * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs
+ */
+ node->object = NULL;
+
+ if ((object) &&
+ (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_OPERAND)) {
+ /*
+ * There is a valid object.
+ * Decrement the reference count by one to balance the
+ * increment when the object was stored.
+ */
+ acpi_ut_remove_reference(object);
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_store_object_to_local
+ *
+ * PARAMETERS: Type - Either ACPI_REFCLASS_LOCAL or
+ * ACPI_REFCLASS_ARG
+ * Index - Which Local or Arg to set
+ * obj_desc - Value to be stored
+ * walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed
+ * as the new value for the Arg or Local and the reference count
+ * for obj_desc is incremented.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_store_object_to_local(u8 type,
+ u32 index,
+ union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *current_obj_desc;
+ union acpi_operand_object *new_obj_desc;
+
+ ACPI_FUNCTION_TRACE(ds_store_object_to_local);
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%d Obj=%p\n",
+ type, index, obj_desc));
+
+ /* Parameter validation */
+
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node(type, index, walk_state, &node);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ current_obj_desc = acpi_ns_get_attached_object(node);
+ if (current_obj_desc == obj_desc) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p already installed!\n",
+ obj_desc));
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * If the reference count on the object is more than one, we must
+ * take a copy of the object before we store. A reference count
+ * of exactly 1 means that the object was just created during the
+ * evaluation of an expression, and we can safely use it since it
+ * is not used anywhere else.
+ */
+ new_obj_desc = obj_desc;
+ if (obj_desc->common.reference_count > 1) {
+ status =
+ acpi_ut_copy_iobject_to_iobject(obj_desc, &new_obj_desc,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ /*
+ * If there is an object already in this slot, we either
+ * have to delete it, or if this is an argument and there
+ * is an object reference stored there, we have to do
+ * an indirect store!
+ */
+ if (current_obj_desc) {
+ /*
+ * Check for an indirect store if an argument
+ * contains an object reference (stored as an Node).
+ * We don't allow this automatic dereferencing for
+ * locals, since a store to a local should overwrite
+ * anything there, including an object reference.
+ *
+ * If both Arg0 and Local0 contain ref_of (Local4):
+ *
+ * Store (1, Arg0) - Causes indirect store to local4
+ * Store (1, Local0) - Stores 1 in local0, overwriting
+ * the reference to local4
+ * Store (1, de_refof (Local0)) - Causes indirect store to local4
+ *
+ * Weird, but true.
+ */
+ if (type == ACPI_REFCLASS_ARG) {
+ /*
+ * If we have a valid reference object that came from ref_of(),
+ * do the indirect store
+ */
+ if ((ACPI_GET_DESCRIPTOR_TYPE(current_obj_desc) ==
+ ACPI_DESC_TYPE_OPERAND)
+ && (current_obj_desc->common.type ==
+ ACPI_TYPE_LOCAL_REFERENCE)
+ && (current_obj_desc->reference.class ==
+ ACPI_REFCLASS_REFOF)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Arg (%p) is an ObjRef(Node), storing in node %p\n",
+ new_obj_desc,
+ current_obj_desc));
+
+ /*
+ * Store this object to the Node (perform the indirect store)
+ * NOTE: No implicit conversion is performed, as per the ACPI
+ * specification rules on storing to Locals/Args.
+ */
+ status =
+ acpi_ex_store_object_to_node(new_obj_desc,
+ current_obj_desc->
+ reference.
+ object,
+ walk_state,
+ ACPI_NO_IMPLICIT_CONVERSION);
+
+ /* Remove local reference if we copied the object above */
+
+ if (new_obj_desc != obj_desc) {
+ acpi_ut_remove_reference(new_obj_desc);
+ }
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ /* Delete the existing object before storing the new one */
+
+ acpi_ds_method_data_delete_value(type, index, walk_state);
+ }
+
+ /*
+ * Install the Obj descriptor (*new_obj_desc) into
+ * the descriptor for the Arg or Local.
+ * (increments the object reference count by one)
+ */
+ status =
+ acpi_ds_method_data_set_value(type, index, new_obj_desc,
+ walk_state);
+
+ /* Remove local reference if we copied the object above */
+
+ if (new_obj_desc != obj_desc) {
+ acpi_ut_remove_reference(new_obj_desc);
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_get_type
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - Which Local or Arg whose type to get
+ * walk_state - Current walk state object
+ *
+ * RETURN: Data type of current value of the selected Arg or Local
+ *
+ * DESCRIPTION: Get the type of the object stored in the Local or Arg
+ *
+ ******************************************************************************/
+
+acpi_object_type
+acpi_ds_method_data_get_type(u16 opcode,
+ u32 index, struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *object;
+
+ ACPI_FUNCTION_TRACE(ds_method_data_get_type);
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node(opcode, index, walk_state, &node);
+ if (ACPI_FAILURE(status)) {
+ return_VALUE((ACPI_TYPE_NOT_FOUND));
+ }
+
+ /* Get the object */
+
+ object = acpi_ns_get_attached_object(node);
+ if (!object) {
+
+ /* Uninitialized local/arg, return TYPE_ANY */
+
+ return_VALUE(ACPI_TYPE_ANY);
+ }
+
+ /* Get the object type */
+
+ return_VALUE(ACPI_GET_OBJECT_TYPE(object));
+}
+#endif
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
new file mode 100644
index 0000000..4f08e59
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -0,0 +1,812 @@
+/******************************************************************************
+ *
+ * Module Name: dsobject - Dispatcher object management routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dsobject")
+
+/* Local prototypes */
+static acpi_status
+acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ union acpi_operand_object **obj_desc_ptr);
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_build_internal_object
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Op - Parser object to be translated
+ * obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parser Op object to the equivalent namespace object
+ * Simple objects are any objects other than a package object!
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_build_internal_object(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ union acpi_operand_object **obj_desc_ptr)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ds_build_internal_object);
+
+ *obj_desc_ptr = NULL;
+ if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ /*
+ * This is a named object reference. If this name was
+ * previously looked up in the namespace, it was stored in this op.
+ * Otherwise, go ahead and look it up now
+ */
+ if (!op->common.node) {
+ status = acpi_ns_lookup(walk_state->scope_info,
+ op->common.value.string,
+ ACPI_TYPE_ANY,
+ ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT |
+ ACPI_NS_DONT_OPEN_SCOPE, NULL,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_namespace_node,
+ &(op->
+ common.
+ node)));
+ if (ACPI_FAILURE(status)) {
+
+ /* Check if we are resolving a named reference within a package */
+
+ if ((status == AE_NOT_FOUND)
+ && (acpi_gbl_enable_interpreter_slack)
+ &&
+ ((op->common.parent->common.aml_opcode ==
+ AML_PACKAGE_OP)
+ || (op->common.parent->common.aml_opcode ==
+ AML_VAR_PACKAGE_OP))) {
+ /*
+ * We didn't find the target and we are populating elements
+ * of a package - ignore if slack enabled. Some ASL code
+ * contains dangling invalid references in packages and
+ * expects that no exception will be issued. Leave the
+ * element as a null element. It cannot be used, but it
+ * can be overwritten by subsequent ASL code - this is
+ * typically the case.
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Ignoring unresolved reference in package [%4.4s]\n",
+ walk_state->
+ scope_info->scope.
+ node->name.ascii));
+
+ return_ACPI_STATUS(AE_OK);
+ } else {
+ ACPI_ERROR_NAMESPACE(op->common.value.
+ string, status);
+ }
+
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ /* Special object resolution for elements of a package */
+
+ if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode ==
+ AML_VAR_PACKAGE_OP)) {
+ /*
+ * Attempt to resolve the node to a value before we insert it into
+ * the package. If this is a reference to a common data type,
+ * resolve it immediately. According to the ACPI spec, package
+ * elements can only be "data objects" or method references.
+ * Attempt to resolve to an Integer, Buffer, String or Package.
+ * If cannot, return the named reference (for things like Devices,
+ * Methods, etc.) Buffer Fields and Fields will resolve to simple
+ * objects (int/buf/str/pkg).
+ *
+ * NOTE: References to things like Devices, Methods, Mutexes, etc.
+ * will remain as named references. This behavior is not described
+ * in the ACPI spec, but it appears to be an oversight.
+ */
+ obj_desc =
+ ACPI_CAST_PTR(union acpi_operand_object,
+ op->common.node);
+
+ status =
+ acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
+ (struct
+ acpi_namespace_node,
+ &obj_desc),
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ switch (op->common.node->type) {
+ /*
+ * For these types, we need the actual node, not the subobject.
+ * However, the subobject did not get an extra reference count above.
+ *
+ * TBD: should ex_resolve_node_to_value be changed to fix this?
+ */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_THERMAL:
+
+ acpi_ut_add_reference(op->common.node->object);
+
+ /*lint -fallthrough */
+ /*
+ * For these types, we need the actual node, not the subobject.
+ * The subobject got an extra reference count in ex_resolve_node_to_value.
+ */
+ case ACPI_TYPE_MUTEX:
+ case ACPI_TYPE_METHOD:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_EVENT:
+ case ACPI_TYPE_REGION:
+
+ /* We will create a reference object for these types below */
+ break;
+
+ default:
+ /*
+ * All other types - the node was resolved to an actual
+ * object, we are done.
+ */
+ goto exit;
+ }
+ }
+ }
+
+ /* Create and init a new internal ACPI object */
+
+ obj_desc = acpi_ut_create_internal_object((acpi_ps_get_opcode_info
+ (op->common.aml_opcode))->
+ object_type);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ status =
+ acpi_ds_init_object_from_op(walk_state, op, op->common.aml_opcode,
+ &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+ }
+
+ exit:
+ *obj_desc_ptr = obj_desc;
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_build_internal_buffer_obj
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Op - Parser object to be translated
+ * buffer_length - Length of the buffer
+ * obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parser Op package object to the equivalent
+ * namespace object
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ u32 buffer_length,
+ union acpi_operand_object **obj_desc_ptr)
+{
+ union acpi_parse_object *arg;
+ union acpi_operand_object *obj_desc;
+ union acpi_parse_object *byte_list;
+ u32 byte_list_length = 0;
+
+ ACPI_FUNCTION_TRACE(ds_build_internal_buffer_obj);
+
+ /*
+ * If we are evaluating a Named buffer object "Name (xxxx, Buffer)".
+ * The buffer object already exists (from the NS node), otherwise it must
+ * be created.
+ */
+ obj_desc = *obj_desc_ptr;
+ if (!obj_desc) {
+
+ /* Create a new buffer object */
+
+ obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_BUFFER);
+ *obj_desc_ptr = obj_desc;
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+ }
+
+ /*
+ * Second arg is the buffer data (optional) byte_list can be either
+ * individual bytes or a string initializer. In either case, a
+ * byte_list appears in the AML.
+ */
+ arg = op->common.value.arg; /* skip first arg */
+
+ byte_list = arg->named.next;
+ if (byte_list) {
+ if (byte_list->common.aml_opcode != AML_INT_BYTELIST_OP) {
+ ACPI_ERROR((AE_INFO,
+ "Expecting bytelist, got AML opcode %X in op %p",
+ byte_list->common.aml_opcode, byte_list));
+
+ acpi_ut_remove_reference(obj_desc);
+ return (AE_TYPE);
+ }
+
+ byte_list_length = (u32) byte_list->common.value.integer;
+ }
+
+ /*
+ * The buffer length (number of bytes) will be the larger of:
+ * 1) The specified buffer length and
+ * 2) The length of the initializer byte list
+ */
+ obj_desc->buffer.length = buffer_length;
+ if (byte_list_length > buffer_length) {
+ obj_desc->buffer.length = byte_list_length;
+ }
+
+ /* Allocate the buffer */
+
+ if (obj_desc->buffer.length == 0) {
+ obj_desc->buffer.pointer = NULL;
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Buffer defined with zero length in AML, creating\n"));
+ } else {
+ obj_desc->buffer.pointer =
+ ACPI_ALLOCATE_ZEROED(obj_desc->buffer.length);
+ if (!obj_desc->buffer.pointer) {
+ acpi_ut_delete_object_desc(obj_desc);
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Initialize buffer from the byte_list (if present) */
+
+ if (byte_list) {
+ ACPI_MEMCPY(obj_desc->buffer.pointer,
+ byte_list->named.data, byte_list_length);
+ }
+ }
+
+ obj_desc->buffer.flags |= AOPOBJ_DATA_VALID;
+ op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_build_internal_package_obj
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Op - Parser object to be translated
+ * element_count - Number of elements in the package - this is
+ * the num_elements argument to Package()
+ * obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parser Op package object to the equivalent
+ * namespace object
+ *
+ * NOTE: The number of elements in the package will be always be the num_elements
+ * count, regardless of the number of elements in the package list. If
+ * num_elements is smaller, only that many package list elements are used.
+ * if num_elements is larger, the Package object is padded out with
+ * objects of type Uninitialized (as per ACPI spec.)
+ *
+ * Even though the ASL compilers do not allow num_elements to be smaller
+ * than the Package list length (for the fixed length package opcode), some
+ * BIOS code modifies the AML on the fly to adjust the num_elements, and
+ * this code compensates for that. This also provides compatibility with
+ * other AML interpreters.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ u32 element_count,
+ union acpi_operand_object **obj_desc_ptr)
+{
+ union acpi_parse_object *arg;
+ union acpi_parse_object *parent;
+ union acpi_operand_object *obj_desc = NULL;
+ acpi_status status = AE_OK;
+ unsigned i;
+ u16 index;
+ u16 reference_count;
+
+ ACPI_FUNCTION_TRACE(ds_build_internal_package_obj);
+
+ /* Find the parent of a possibly nested package */
+
+ parent = op->common.parent;
+ while ((parent->common.aml_opcode == AML_PACKAGE_OP) ||
+ (parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
+ parent = parent->common.parent;
+ }
+
+ /*
+ * If we are evaluating a Named package object "Name (xxxx, Package)",
+ * the package object already exists, otherwise it must be created.
+ */
+ obj_desc = *obj_desc_ptr;
+ if (!obj_desc) {
+ obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PACKAGE);
+ *obj_desc_ptr = obj_desc;
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ obj_desc->package.node = parent->common.node;
+ }
+
+ /*
+ * Allocate the element array (array of pointers to the individual
+ * objects) based on the num_elements parameter. Add an extra pointer slot
+ * so that the list is always null terminated.
+ */
+ obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)
+ element_count +
+ 1) * sizeof(void *));
+
+ if (!obj_desc->package.elements) {
+ acpi_ut_delete_object_desc(obj_desc);
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ obj_desc->package.count = element_count;
+
+ /*
+ * Initialize the elements of the package, up to the num_elements count.
+ * Package is automatically padded with uninitialized (NULL) elements
+ * if num_elements is greater than the package list length. Likewise,
+ * Package is truncated if num_elements is less than the list length.
+ */
+ arg = op->common.value.arg;
+ arg = arg->common.next;
+ for (i = 0; arg && (i < element_count); i++) {
+ if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
+ if (arg->common.node->type == ACPI_TYPE_METHOD) {
+ /*
+ * A method reference "looks" to the parser to be a method
+ * invocation, so we special case it here
+ */
+ arg->common.aml_opcode = AML_INT_NAMEPATH_OP;
+ status =
+ acpi_ds_build_internal_object(walk_state,
+ arg,
+ &obj_desc->
+ package.
+ elements[i]);
+ } else {
+ /* This package element is already built, just get it */
+
+ obj_desc->package.elements[i] =
+ ACPI_CAST_PTR(union acpi_operand_object,
+ arg->common.node);
+ }
+ } else {
+ status = acpi_ds_build_internal_object(walk_state, arg,
+ &obj_desc->
+ package.
+ elements[i]);
+ }
+
+ if (*obj_desc_ptr) {
+
+ /* Existing package, get existing reference count */
+
+ reference_count =
+ (*obj_desc_ptr)->common.reference_count;
+ if (reference_count > 1) {
+
+ /* Make new element ref count match original ref count */
+
+ for (index = 0; index < (reference_count - 1);
+ index++) {
+ acpi_ut_add_reference((obj_desc->
+ package.
+ elements[i]));
+ }
+ }
+ }
+
+ arg = arg->common.next;
+ }
+
+ /* Check for match between num_elements and actual length of package_list */
+
+ if (arg) {
+ /*
+ * num_elements was exhausted, but there are remaining elements in the
+ * package_list.
+ *
+ * Note: technically, this is an error, from ACPI spec: "It is an error
+ * for NumElements to be less than the number of elements in the
+ * PackageList". However, for now, we just print an error message and
+ * no exception is returned.
+ */
+ while (arg) {
+
+ /* Find out how many elements there really are */
+
+ i++;
+ arg = arg->common.next;
+ }
+
+ ACPI_WARNING((AE_INFO,
+ "Package List length (%X) larger than NumElements count (%X), truncated\n",
+ i, element_count));
+ } else if (i < element_count) {
+ /*
+ * Arg list (elements) was exhausted, but we did not reach num_elements count.
+ * Note: this is not an error, the package is padded out with NULLs.
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Package List length (%X) smaller than NumElements count (%X), padded with null elements\n",
+ i, element_count));
+ }
+
+ obj_desc->package.flags |= AOPOBJ_DATA_VALID;
+ op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_node
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Node - NS Node to be initialized
+ * Op - Parser object to be translated
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create the object to be associated with a namespace node
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_node(struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node *node,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_create_node, op);
+
+ /*
+ * Because of the execution pass through the non-control-method
+ * parts of the table, we can arrive here twice. Only init
+ * the named object node the first time through
+ */
+ if (acpi_ns_get_attached_object(node)) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ if (!op->common.value.arg) {
+
+ /* No arguments, there is nothing to do */
+
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Build an internal object for the argument(s) */
+
+ status = acpi_ds_build_internal_object(walk_state, op->common.value.arg,
+ &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Re-type the object according to its argument */
+
+ node->type = ACPI_GET_OBJECT_TYPE(obj_desc);
+
+ /* Attach obj to node */
+
+ status = acpi_ns_attach_object(node, obj_desc, node->type);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference(obj_desc);
+ return_ACPI_STATUS(status);
+}
+
+#endif /* ACPI_NO_METHOD_EXECUTION */
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_object_from_op
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Op - Parser op used to init the internal object
+ * Opcode - AML opcode associated with the object
+ * ret_obj_desc - Namespace object to be initialized
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize a namespace object from a parser Op and its
+ * associated arguments. The namespace object is a more compact
+ * representation of the Op and its arguments.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ u16 opcode,
+ union acpi_operand_object **ret_obj_desc)
+{
+ const struct acpi_opcode_info *op_info;
+ union acpi_operand_object *obj_desc;
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(ds_init_object_from_op);
+
+ obj_desc = *ret_obj_desc;
+ op_info = acpi_ps_get_opcode_info(opcode);
+ if (op_info->class == AML_CLASS_UNKNOWN) {
+
+ /* Unknown opcode */
+
+ return_ACPI_STATUS(AE_TYPE);
+ }
+
+ /* Perform per-object initialization */
+
+ switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * Defer evaluation of Buffer term_arg operand
+ */
+ obj_desc->buffer.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node,
+ walk_state->operands[0]);
+ obj_desc->buffer.aml_start = op->named.data;
+ obj_desc->buffer.aml_length = op->named.length;
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * Defer evaluation of Package term_arg operand
+ */
+ obj_desc->package.node =
+ ACPI_CAST_PTR(struct acpi_namespace_node,
+ walk_state->operands[0]);
+ obj_desc->package.aml_start = op->named.data;
+ obj_desc->package.aml_length = op->named.length;
+ break;
+
+ case ACPI_TYPE_INTEGER:
+
+ switch (op_info->type) {
+ case AML_TYPE_CONSTANT:
+ /*
+ * Resolve AML Constants here - AND ONLY HERE!
+ * All constants are integers.
+ * We mark the integer with a flag that indicates that it started
+ * life as a constant -- so that stores to constants will perform
+ * as expected (noop). zero_op is used as a placeholder for optional
+ * target operands.
+ */
+ obj_desc->common.flags = AOPOBJ_AML_CONSTANT;
+
+ switch (opcode) {
+ case AML_ZERO_OP:
+
+ obj_desc->integer.value = 0;
+ break;
+
+ case AML_ONE_OP:
+
+ obj_desc->integer.value = 1;
+ break;
+
+ case AML_ONES_OP:
+
+ obj_desc->integer.value = ACPI_INTEGER_MAX;
+
+ /* Truncate value if we are executing from a 32-bit ACPI table */
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+ acpi_ex_truncate_for32bit_table(obj_desc);
+#endif
+ break;
+
+ case AML_REVISION_OP:
+
+ obj_desc->integer.value = ACPI_CA_VERSION;
+ break;
+
+ default:
+
+ ACPI_ERROR((AE_INFO,
+ "Unknown constant opcode %X",
+ opcode));
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+ break;
+
+ case AML_TYPE_LITERAL:
+
+ obj_desc->integer.value = op->common.value.integer;
+#ifndef ACPI_NO_METHOD_EXECUTION
+ acpi_ex_truncate_for32bit_table(obj_desc);
+#endif
+ break;
+
+ default:
+ ACPI_ERROR((AE_INFO, "Unknown Integer type %X",
+ op_info->type));
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+ break;
+
+ case ACPI_TYPE_STRING:
+
+ obj_desc->string.pointer = op->common.value.string;
+ obj_desc->string.length =
+ (u32) ACPI_STRLEN(op->common.value.string);
+
+ /*
+ * The string is contained in the ACPI table, don't ever try
+ * to delete it
+ */
+ obj_desc->common.flags |= AOPOBJ_STATIC_POINTER;
+ break;
+
+ case ACPI_TYPE_METHOD:
+ break;
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ switch (op_info->type) {
+ case AML_TYPE_LOCAL_VARIABLE:
+
+ /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */
+
+ obj_desc->reference.value = opcode - AML_LOCAL_OP;
+ obj_desc->reference.class = ACPI_REFCLASS_LOCAL;
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+ status =
+ acpi_ds_method_data_get_node(ACPI_REFCLASS_LOCAL,
+ obj_desc->reference.
+ value, walk_state,
+ ACPI_CAST_INDIRECT_PTR
+ (struct
+ acpi_namespace_node,
+ &obj_desc->reference.
+ object));
+#endif
+ break;
+
+ case AML_TYPE_METHOD_ARGUMENT:
+
+ /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */
+
+ obj_desc->reference.value = opcode - AML_ARG_OP;
+ obj_desc->reference.class = ACPI_REFCLASS_ARG;
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+ status = acpi_ds_method_data_get_node(ACPI_REFCLASS_ARG,
+ obj_desc->
+ reference.value,
+ walk_state,
+ ACPI_CAST_INDIRECT_PTR
+ (struct
+ acpi_namespace_node,
+ &obj_desc->
+ reference.
+ object));
+#endif
+ break;
+
+ default: /* Object name or Debug object */
+
+ switch (op->common.aml_opcode) {
+ case AML_INT_NAMEPATH_OP:
+
+ /* Node was saved in Op */
+
+ obj_desc->reference.node = op->common.node;
+ obj_desc->reference.object =
+ op->common.node->object;
+ obj_desc->reference.class = ACPI_REFCLASS_NAME;
+ break;
+
+ case AML_DEBUG_OP:
+
+ obj_desc->reference.class = ACPI_REFCLASS_DEBUG;
+ break;
+
+ default:
+
+ ACPI_ERROR((AE_INFO,
+ "Unimplemented reference type for AML opcode: %4.4X",
+ opcode));
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
+ break;
+ }
+ break;
+
+ default:
+
+ ACPI_ERROR((AE_INFO, "Unimplemented data type: %X",
+ ACPI_GET_OBJECT_TYPE(obj_desc)));
+
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
new file mode 100644
index 0000000..69fae59
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -0,0 +1,1429 @@
+/******************************************************************************
+ *
+ * Module Name: dsopcode - Dispatcher Op Region support and handling of
+ * "control" opcodes
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dsopcode")
+
+/* Local prototypes */
+static acpi_status
+acpi_ds_execute_arguments(struct acpi_namespace_node *node,
+ struct acpi_namespace_node *scope_node,
+ u32 aml_length, u8 * aml_start);
+
+static acpi_status
+acpi_ds_init_buffer_field(u16 aml_opcode,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object *buffer_desc,
+ union acpi_operand_object *offset_desc,
+ union acpi_operand_object *length_desc,
+ union acpi_operand_object *result_desc);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_execute_arguments
+ *
+ * PARAMETERS: Node - Object NS node
+ * scope_node - Parent NS node
+ * aml_length - Length of executable AML
+ * aml_start - Pointer to the AML
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Late (deferred) execution of region or field arguments
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_execute_arguments(struct acpi_namespace_node *node,
+ struct acpi_namespace_node *scope_node,
+ u32 aml_length, u8 * aml_start)
+{
+ acpi_status status;
+ union acpi_parse_object *op;
+ struct acpi_walk_state *walk_state;
+
+ ACPI_FUNCTION_TRACE(ds_execute_arguments);
+
+ /*
+ * Allocate a new parser op to be the root of the parsed tree
+ */
+ op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Save the Node for use in acpi_ps_parse_aml */
+
+ op->common.node = scope_node;
+
+ /* Create and initialize a new parser state */
+
+ walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL);
+ if (!walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
+ aml_length, NULL, ACPI_IMODE_LOAD_PASS1);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ goto cleanup;
+ }
+
+ /* Mark this parse as a deferred opcode */
+
+ walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP;
+ walk_state->deferred_node = node;
+
+ /* Pass1: Parse the entire declaration */
+
+ status = acpi_ps_parse_aml(walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ /* Get and init the Op created above */
+
+ op->common.node = node;
+ acpi_ps_delete_parse_tree(op);
+
+ /* Evaluate the deferred arguments */
+
+ op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ op->common.node = scope_node;
+
+ /* Create and initialize a new parser state */
+
+ walk_state = acpi_ds_create_walk_state(0, NULL, NULL, NULL);
+ if (!walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Execute the opcode and arguments */
+
+ status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
+ aml_length, NULL, ACPI_IMODE_EXECUTE);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ goto cleanup;
+ }
+
+ /* Mark this execution as a deferred opcode */
+
+ walk_state->deferred_node = node;
+ status = acpi_ps_parse_aml(walk_state);
+
+ cleanup:
+ acpi_ps_delete_parse_tree(op);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_buffer_field_arguments
+ *
+ * PARAMETERS: obj_desc - A valid buffer_field object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late
+ * evaluation of these field attributes.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
+{
+ union acpi_operand_object *extra_desc;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_field_arguments, obj_desc);
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Get the AML pointer (method object) and buffer_field node */
+
+ extra_desc = acpi_ns_get_secondary_object(obj_desc);
+ node = obj_desc->buffer_field.node;
+
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+ (ACPI_TYPE_BUFFER_FIELD, node, NULL));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BufferField Arg Init\n",
+ acpi_ut_get_node_name(node)));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ extra_desc->extra.aml_length,
+ extra_desc->extra.aml_start);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_bank_field_arguments
+ *
+ * PARAMETERS: obj_desc - A valid bank_field object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get bank_field bank_value. This implements the late
+ * evaluation of these field attributes.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
+{
+ union acpi_operand_object *extra_desc;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc);
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Get the AML pointer (method object) and bank_field node */
+
+ extra_desc = acpi_ns_get_secondary_object(obj_desc);
+ node = obj_desc->bank_field.node;
+
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+ (ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n",
+ acpi_ut_get_node_name(node)));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ extra_desc->extra.aml_length,
+ extra_desc->extra.aml_start);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_buffer_arguments
+ *
+ * PARAMETERS: obj_desc - A valid Buffer object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get Buffer length and initializer byte list. This implements
+ * the late evaluation of these attributes.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_buffer_arguments, obj_desc);
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Get the Buffer node */
+
+ node = obj_desc->buffer.node;
+ if (!node) {
+ ACPI_ERROR((AE_INFO,
+ "No pointer back to NS node in buffer obj %p",
+ obj_desc));
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Buffer Arg Init\n"));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments(node, node,
+ obj_desc->buffer.aml_length,
+ obj_desc->buffer.aml_start);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_package_arguments
+ *
+ * PARAMETERS: obj_desc - A valid Package object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get Package length and initializer byte list. This implements
+ * the late evaluation of these attributes.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_package_arguments, obj_desc);
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Get the Package node */
+
+ node = obj_desc->package.node;
+ if (!node) {
+ ACPI_ERROR((AE_INFO,
+ "No pointer back to NS node in package %p",
+ obj_desc));
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Package Arg Init\n"));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments(node, node,
+ obj_desc->package.aml_length,
+ obj_desc->package.aml_start);
+ return_ACPI_STATUS(status);
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_region_arguments
+ *
+ * PARAMETERS: obj_desc - A valid region object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get region address and length. This implements the late
+ * evaluation of these region attributes.
+ *
+ ****************************************************************************/
+
+acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ union acpi_operand_object *extra_desc;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_region_arguments, obj_desc);
+
+ if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ extra_desc = acpi_ns_get_secondary_object(obj_desc);
+ if (!extra_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ /* Get the Region node */
+
+ node = obj_desc->region.node;
+
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+ (ACPI_TYPE_REGION, node, NULL));
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] OpRegion Arg Init at AML %p\n",
+ acpi_ut_get_node_name(node),
+ extra_desc->extra.aml_start));
+
+ /* Execute the argument AML */
+
+ status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ extra_desc->extra.aml_length,
+ extra_desc->extra.aml_start);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Validate the region address/length via the host OS */
+
+ status = acpi_os_validate_address(obj_desc->region.space_id,
+ obj_desc->region.address,
+ (acpi_size) obj_desc->region.length,
+ acpi_ut_get_node_name(node));
+
+ if (ACPI_FAILURE(status)) {
+ /*
+ * Invalid address/length. We will emit an error message and mark
+ * the region as invalid, so that it will cause an additional error if
+ * it is ever used. Then return AE_OK.
+ */
+ ACPI_EXCEPTION((AE_INFO, status,
+ "During address validation of OpRegion [%4.4s]",
+ node->name.ascii));
+ obj_desc->common.flags |= AOPOBJ_INVALID;
+ status = AE_OK;
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_initialize_region
+ *
+ * PARAMETERS: obj_handle - Region namespace node
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Front end to ev_initialize_region
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_initialize_region(acpi_handle obj_handle)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+ obj_desc = acpi_ns_get_attached_object(obj_handle);
+
+ /* Namespace is NOT locked */
+
+ status = acpi_ev_initialize_region(obj_desc, FALSE);
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_buffer_field
+ *
+ * PARAMETERS: aml_opcode - create_xxx_field
+ * obj_desc - buffer_field object
+ * buffer_desc - Host Buffer
+ * offset_desc - Offset into buffer
+ * length_desc - Length of field (CREATE_FIELD_OP only)
+ * result_desc - Where to store the result
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Perform actual initialization of a buffer field
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_init_buffer_field(u16 aml_opcode,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object *buffer_desc,
+ union acpi_operand_object *offset_desc,
+ union acpi_operand_object *length_desc,
+ union acpi_operand_object *result_desc)
+{
+ u32 offset;
+ u32 bit_offset;
+ u32 bit_count;
+ u8 field_flags;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_init_buffer_field, obj_desc);
+
+ /* Host object must be a Buffer */
+
+ if (ACPI_GET_OBJECT_TYPE(buffer_desc) != ACPI_TYPE_BUFFER) {
+ ACPI_ERROR((AE_INFO,
+ "Target of Create Field is not a Buffer object - %s",
+ acpi_ut_get_object_type_name(buffer_desc)));
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /*
+ * The last parameter to all of these opcodes (result_desc) started
+ * out as a name_string, and should therefore now be a NS node
+ * after resolution in acpi_ex_resolve_operands().
+ */
+ if (ACPI_GET_DESCRIPTOR_TYPE(result_desc) != ACPI_DESC_TYPE_NAMED) {
+ ACPI_ERROR((AE_INFO,
+ "(%s) destination not a NS Node [%s]",
+ acpi_ps_get_opcode_name(aml_opcode),
+ acpi_ut_get_descriptor_name(result_desc)));
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ offset = (u32) offset_desc->integer.value;
+
+ /*
+ * Setup the Bit offsets and counts, according to the opcode
+ */
+ switch (aml_opcode) {
+ case AML_CREATE_FIELD_OP:
+
+ /* Offset is in bits, count is in bits */
+
+ field_flags = AML_FIELD_ACCESS_BYTE;
+ bit_offset = offset;
+ bit_count = (u32) length_desc->integer.value;
+
+ /* Must have a valid (>0) bit count */
+
+ if (bit_count == 0) {
+ ACPI_ERROR((AE_INFO,
+ "Attempt to CreateField of length zero"));
+ status = AE_AML_OPERAND_VALUE;
+ goto cleanup;
+ }
+ break;
+
+ case AML_CREATE_BIT_FIELD_OP:
+
+ /* Offset is in bits, Field is one bit */
+
+ bit_offset = offset;
+ bit_count = 1;
+ field_flags = AML_FIELD_ACCESS_BYTE;
+ break;
+
+ case AML_CREATE_BYTE_FIELD_OP:
+
+ /* Offset is in bytes, field is one byte */
+
+ bit_offset = 8 * offset;
+ bit_count = 8;
+ field_flags = AML_FIELD_ACCESS_BYTE;
+ break;
+
+ case AML_CREATE_WORD_FIELD_OP:
+
+ /* Offset is in bytes, field is one word */
+
+ bit_offset = 8 * offset;
+ bit_count = 16;
+ field_flags = AML_FIELD_ACCESS_WORD;
+ break;
+
+ case AML_CREATE_DWORD_FIELD_OP:
+
+ /* Offset is in bytes, field is one dword */
+
+ bit_offset = 8 * offset;
+ bit_count = 32;
+ field_flags = AML_FIELD_ACCESS_DWORD;
+ break;
+
+ case AML_CREATE_QWORD_FIELD_OP:
+
+ /* Offset is in bytes, field is one qword */
+
+ bit_offset = 8 * offset;
+ bit_count = 64;
+ field_flags = AML_FIELD_ACCESS_QWORD;
+ break;
+
+ default:
+
+ ACPI_ERROR((AE_INFO,
+ "Unknown field creation opcode %02x", aml_opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+ /* Entire field must fit within the current length of the buffer */
+
+ if ((bit_offset + bit_count) > (8 * (u32) buffer_desc->buffer.length)) {
+ ACPI_ERROR((AE_INFO,
+ "Field [%4.4s] at %d exceeds Buffer [%4.4s] size %d (bits)",
+ acpi_ut_get_node_name(result_desc),
+ bit_offset + bit_count,
+ acpi_ut_get_node_name(buffer_desc->buffer.node),
+ 8 * (u32) buffer_desc->buffer.length));
+ status = AE_AML_BUFFER_LIMIT;
+ goto cleanup;
+ }
+
+ /*
+ * Initialize areas of the field object that are common to all fields
+ * For field_flags, use LOCK_RULE = 0 (NO_LOCK),
+ * UPDATE_RULE = 0 (UPDATE_PRESERVE)
+ */
+ status = acpi_ex_prep_common_field_object(obj_desc, field_flags, 0,
+ bit_offset, bit_count);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ obj_desc->buffer_field.buffer_obj = buffer_desc;
+
+ /* Reference count for buffer_desc inherits obj_desc count */
+
+ buffer_desc->common.reference_count = (u16)
+ (buffer_desc->common.reference_count +
+ obj_desc->common.reference_count);
+
+ cleanup:
+
+ /* Always delete the operands */
+
+ acpi_ut_remove_reference(offset_desc);
+ acpi_ut_remove_reference(buffer_desc);
+
+ if (aml_opcode == AML_CREATE_FIELD_OP) {
+ acpi_ut_remove_reference(length_desc);
+ }
+
+ /* On failure, delete the result descriptor */
+
+ if (ACPI_FAILURE(status)) {
+ acpi_ut_remove_reference(result_desc); /* Result descriptor */
+ } else {
+ /* Now the address and length are valid for this buffer_field */
+
+ obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID;
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_buffer_field_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid buffer_field Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get buffer_field Buffer and Index
+ * Called from acpi_ds_exec_end_op during buffer_field parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_buffer_field_operands, op);
+
+ /*
+ * This is where we evaluate the address and length fields of the
+ * create_xxx_field declaration
+ */
+ node = op->common.node;
+
+ /* next_op points to the op that holds the Buffer */
+
+ next_op = op->common.value.arg;
+
+ /* Evaluate/create the address and length operands */
+
+ status = acpi_ds_create_operands(walk_state, next_op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ /* Resolve the operands */
+
+ status = acpi_ex_resolve_operands(op->common.aml_opcode,
+ ACPI_WALK_OPERANDS, walk_state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO, "(%s) bad operand(s) (%X)",
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ status));
+
+ return_ACPI_STATUS(status);
+ }
+
+ /* Initialize the Buffer Field */
+
+ if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
+
+ /* NOTE: Slightly different operands for this opcode */
+
+ status =
+ acpi_ds_init_buffer_field(op->common.aml_opcode, obj_desc,
+ walk_state->operands[0],
+ walk_state->operands[1],
+ walk_state->operands[2],
+ walk_state->operands[3]);
+ } else {
+ /* All other, create_xxx_field opcodes */
+
+ status =
+ acpi_ds_init_buffer_field(op->common.aml_opcode, obj_desc,
+ walk_state->operands[0],
+ walk_state->operands[1], NULL,
+ walk_state->operands[2]);
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_region_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get region address and length
+ * Called from acpi_ds_exec_end_op during op_region parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *operand_desc;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_region_operands, op);
+
+ /*
+ * This is where we evaluate the address and length fields of the
+ * op_region declaration
+ */
+ node = op->common.node;
+
+ /* next_op points to the op that holds the space_iD */
+
+ next_op = op->common.value.arg;
+
+ /* next_op points to address op */
+
+ next_op = next_op->common.next;
+
+ /* Evaluate/create the address and length operands */
+
+ status = acpi_ds_create_operands(walk_state, next_op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Resolve the length and address operands to numbers */
+
+ status = acpi_ex_resolve_operands(op->common.aml_opcode,
+ ACPI_WALK_OPERANDS, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ /*
+ * Get the length operand and save it
+ * (at Top of stack)
+ */
+ operand_desc = walk_state->operands[walk_state->num_operands - 1];
+
+ obj_desc->region.length = (u32) operand_desc->integer.value;
+ acpi_ut_remove_reference(operand_desc);
+
+ /*
+ * Get the address and save it
+ * (at top of stack - 1)
+ */
+ operand_desc = walk_state->operands[walk_state->num_operands - 2];
+
+ obj_desc->region.address = (acpi_physical_address)
+ operand_desc->integer.value;
+ acpi_ut_remove_reference(operand_desc);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
+ obj_desc,
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address),
+ obj_desc->region.length));
+
+ /* Now the address and length are valid for this opregion */
+
+ obj_desc->region.flags |= AOPOBJ_DATA_VALID;
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_table_region_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get region address and length
+ * Called from acpi_ds_exec_end_op during data_table_region parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object **operand;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+ u32 table_index;
+ struct acpi_table_header *table;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op);
+
+ /*
+ * This is where we evaluate the signature_string and oem_iDString
+ * and oem_table_iDString of the data_table_region declaration
+ */
+ node = op->common.node;
+
+ /* next_op points to signature_string op */
+
+ next_op = op->common.value.arg;
+
+ /*
+ * Evaluate/create the signature_string and oem_iDString
+ * and oem_table_iDString operands
+ */
+ status = acpi_ds_create_operands(walk_state, next_op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Resolve the signature_string and oem_iDString
+ * and oem_table_iDString operands
+ */
+ status = acpi_ex_resolve_operands(op->common.aml_opcode,
+ ACPI_WALK_OPERANDS, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ operand = &walk_state->operands[0];
+
+ /* Find the ACPI table */
+
+ status = acpi_tb_find_table(operand[0]->string.pointer,
+ operand[1]->string.pointer,
+ operand[2]->string.pointer, &table_index);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ut_remove_reference(operand[0]);
+ acpi_ut_remove_reference(operand[1]);
+ acpi_ut_remove_reference(operand[2]);
+
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ obj_desc->region.address =
+ (acpi_physical_address) ACPI_TO_INTEGER(table);
+ obj_desc->region.length = table->length;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
+ obj_desc,
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address),
+ obj_desc->region.length));
+
+ /* Now the address and length are valid for this opregion */
+
+ obj_desc->region.flags |= AOPOBJ_DATA_VALID;
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_data_object_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid data_object Op object
+ * obj_desc - data_object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the operands and complete the following data object types:
+ * Buffer, Package.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status;
+ union acpi_operand_object *arg_desc;
+ u32 length;
+
+ ACPI_FUNCTION_TRACE(ds_eval_data_object_operands);
+
+ /* The first operand (for all of these data objects) is the length */
+
+ /*
+ * Set proper index into operand stack for acpi_ds_obj_stack_push
+ * invoked inside acpi_ds_create_operand.
+ */
+ walk_state->operand_index = walk_state->num_operands;
+
+ status = acpi_ds_create_operand(walk_state, op->common.value.arg, 1);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_ex_resolve_operands(walk_state->opcode,
+ &(walk_state->
+ operands[walk_state->num_operands -
+ 1]), walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Extract length operand */
+
+ arg_desc = walk_state->operands[walk_state->num_operands - 1];
+ length = (u32) arg_desc->integer.value;
+
+ /* Cleanup for length operand */
+
+ status = acpi_ds_obj_stack_pop(1, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ut_remove_reference(arg_desc);
+
+ /*
+ * Create the actual data object
+ */
+ switch (op->common.aml_opcode) {
+ case AML_BUFFER_OP:
+
+ status =
+ acpi_ds_build_internal_buffer_obj(walk_state, op, length,
+ &obj_desc);
+ break;
+
+ case AML_PACKAGE_OP:
+ case AML_VAR_PACKAGE_OP:
+
+ status =
+ acpi_ds_build_internal_package_obj(walk_state, op, length,
+ &obj_desc);
+ break;
+
+ default:
+ return_ACPI_STATUS(AE_AML_BAD_OPCODE);
+ }
+
+ if (ACPI_SUCCESS(status)) {
+ /*
+ * Return the object in the walk_state, unless the parent is a package -
+ * in this case, the return object will be stored in the parse tree
+ * for the package.
+ */
+ if ((!op->common.parent) ||
+ ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) &&
+ (op->common.parent->common.aml_opcode !=
+ AML_VAR_PACKAGE_OP)
+ && (op->common.parent->common.aml_opcode != AML_NAME_OP))) {
+ walk_state->result_obj = obj_desc;
+ }
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_bank_field_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid bank_field Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get bank_field bank_value
+ * Called from acpi_ds_exec_end_op during bank_field parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *operand_desc;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+ union acpi_parse_object *arg;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_bank_field_operands, op);
+
+ /*
+ * This is where we evaluate the bank_value field of the
+ * bank_field declaration
+ */
+
+ /* next_op points to the op that holds the Region */
+
+ next_op = op->common.value.arg;
+
+ /* next_op points to the op that holds the Bank Register */
+
+ next_op = next_op->common.next;
+
+ /* next_op points to the op that holds the Bank Value */
+
+ next_op = next_op->common.next;
+
+ /*
+ * Set proper index into operand stack for acpi_ds_obj_stack_push
+ * invoked inside acpi_ds_create_operand.
+ *
+ * We use walk_state->Operands[0] to store the evaluated bank_value
+ */
+ walk_state->operand_index = 0;
+
+ status = acpi_ds_create_operand(walk_state, next_op, 0);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_ex_resolve_to_value(&walk_state->operands[0], walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS,
+ acpi_ps_get_opcode_name(op->common.aml_opcode), 1);
+ /*
+ * Get the bank_value operand and save it
+ * (at Top of stack)
+ */
+ operand_desc = walk_state->operands[0];
+
+ /* Arg points to the start Bank Field */
+
+ arg = acpi_ps_get_arg(op, 4);
+ while (arg) {
+
+ /* Ignore OFFSET and ACCESSAS terms here */
+
+ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
+ node = arg->common.node;
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ obj_desc->bank_field.value =
+ (u32) operand_desc->integer.value;
+ }
+
+ /* Move to next field in the list */
+
+ arg = arg->common.next;
+ }
+
+ acpi_ut_remove_reference(operand_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_exec_begin_control_op
+ *
+ * PARAMETERS: walk_list - The list that owns the walk stack
+ * Op - The control Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handles all control ops encountered during control method
+ * execution.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status = AE_OK;
+ union acpi_generic_state *control_state;
+
+ ACPI_FUNCTION_NAME(ds_exec_begin_control_op);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", op,
+ op->common.aml_opcode, walk_state));
+
+ switch (op->common.aml_opcode) {
+ case AML_IF_OP:
+ case AML_WHILE_OP:
+
+ /*
+ * IF/WHILE: Create a new control state to manage these
+ * constructs. We need to manage these as a stack, in order
+ * to handle nesting.
+ */
+ control_state = acpi_ut_create_control_state();
+ if (!control_state) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+ /*
+ * Save a pointer to the predicate for multiple executions
+ * of a loop
+ */
+ control_state->control.aml_predicate_start =
+ walk_state->parser_state.aml - 1;
+ control_state->control.package_end =
+ walk_state->parser_state.pkg_end;
+ control_state->control.opcode = op->common.aml_opcode;
+
+ /* Push the control state on this walk's control stack */
+
+ acpi_ut_push_generic_state(&walk_state->control_state,
+ control_state);
+ break;
+
+ case AML_ELSE_OP:
+
+ /* Predicate is in the state object */
+ /* If predicate is true, the IF was executed, ignore ELSE part */
+
+ if (walk_state->last_predicate) {
+ status = AE_CTRL_TRUE;
+ }
+
+ break;
+
+ case AML_RETURN_OP:
+
+ break;
+
+ default:
+ break;
+ }
+
+ return (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_exec_end_control_op
+ *
+ * PARAMETERS: walk_list - The list that owns the walk stack
+ * Op - The control Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handles all control ops encountered during control method
+ * execution.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
+ union acpi_parse_object * op)
+{
+ acpi_status status = AE_OK;
+ union acpi_generic_state *control_state;
+
+ ACPI_FUNCTION_NAME(ds_exec_end_control_op);
+
+ switch (op->common.aml_opcode) {
+ case AML_IF_OP:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op));
+
+ /*
+ * Save the result of the predicate in case there is an
+ * ELSE to come
+ */
+ walk_state->last_predicate =
+ (u8) walk_state->control_state->common.value;
+
+ /*
+ * Pop the control state that was created at the start
+ * of the IF and free it
+ */
+ control_state =
+ acpi_ut_pop_generic_state(&walk_state->control_state);
+ acpi_ut_delete_generic_state(control_state);
+ break;
+
+ case AML_ELSE_OP:
+
+ break;
+
+ case AML_WHILE_OP:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
+
+ if (walk_state->control_state->common.value) {
+
+ /* Predicate was true, go back and evaluate it again! */
+
+ status = AE_CTRL_PENDING;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "[WHILE_OP] termination! Op=%p\n", op));
+
+ /* Pop this control state and free it */
+
+ control_state =
+ acpi_ut_pop_generic_state(&walk_state->control_state);
+
+ walk_state->aml_last_while =
+ control_state->control.aml_predicate_start;
+ acpi_ut_delete_generic_state(control_state);
+ break;
+
+ case AML_RETURN_OP:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "[RETURN_OP] Op=%p Arg=%p\n", op,
+ op->common.value.arg));
+
+ /*
+ * One optional operand -- the return value
+ * It can be either an immediate operand or a result that
+ * has been bubbled up the tree
+ */
+ if (op->common.value.arg) {
+
+ /* Since we have a real Return(), delete any implicit return */
+
+ acpi_ds_clear_implicit_return(walk_state);
+
+ /* Return statement has an immediate operand */
+
+ status =
+ acpi_ds_create_operands(walk_state,
+ op->common.value.arg);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /*
+ * If value being returned is a Reference (such as
+ * an arg or local), resolve it now because it may
+ * cease to exist at the end of the method.
+ */
+ status =
+ acpi_ex_resolve_to_value(&walk_state->operands[0],
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+
+ /*
+ * Get the return value and save as the last result
+ * value. This is the only place where walk_state->return_desc
+ * is set to anything other than zero!
+ */
+ walk_state->return_desc = walk_state->operands[0];
+ } else if (walk_state->result_count) {
+
+ /* Since we have a real Return(), delete any implicit return */
+
+ acpi_ds_clear_implicit_return(walk_state);
+
+ /*
+ * The return value has come from a previous calculation.
+ *
+ * If value being returned is a Reference (such as
+ * an arg or local), resolve it now because it may
+ * cease to exist at the end of the method.
+ *
+ * Allow references created by the Index operator to return unchanged.
+ */
+ if ((ACPI_GET_DESCRIPTOR_TYPE
+ (walk_state->results->results.obj_desc[0]) ==
+ ACPI_DESC_TYPE_OPERAND)
+ &&
+ (ACPI_GET_OBJECT_TYPE
+ (walk_state->results->results.obj_desc[0]) ==
+ ACPI_TYPE_LOCAL_REFERENCE)
+ && ((walk_state->results->results.obj_desc[0])->
+ reference.class != ACPI_REFCLASS_INDEX)) {
+ status =
+ acpi_ex_resolve_to_value(&walk_state->
+ results->results.
+ obj_desc[0],
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+
+ walk_state->return_desc =
+ walk_state->results->results.obj_desc[0];
+ } else {
+ /* No return operand */
+
+ if (walk_state->num_operands) {
+ acpi_ut_remove_reference(walk_state->
+ operands[0]);
+ }
+
+ walk_state->operands[0] = NULL;
+ walk_state->num_operands = 0;
+ walk_state->return_desc = NULL;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Completed RETURN_OP State=%p, RetVal=%p\n",
+ walk_state, walk_state->return_desc));
+
+ /* End the control method execution right now */
+
+ status = AE_CTRL_TERMINATE;
+ break;
+
+ case AML_NOOP_OP:
+
+ /* Just do nothing! */
+ break;
+
+ case AML_BREAK_POINT_OP:
+
+ /* Call up to the OS service layer to handle this */
+
+ status =
+ acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
+ "Executed AML Breakpoint opcode");
+
+ /* If and when it returns, all done. */
+
+ break;
+
+ case AML_BREAK_OP:
+ case AML_CONTINUE_OP: /* ACPI 2.0 */
+
+ /* Pop and delete control states until we find a while */
+
+ while (walk_state->control_state &&
+ (walk_state->control_state->control.opcode !=
+ AML_WHILE_OP)) {
+ control_state =
+ acpi_ut_pop_generic_state(&walk_state->
+ control_state);
+ acpi_ut_delete_generic_state(control_state);
+ }
+
+ /* No while found? */
+
+ if (!walk_state->control_state) {
+ return (AE_AML_NO_WHILE);
+ }
+
+ /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */
+
+ walk_state->aml_last_while =
+ walk_state->control_state->control.package_end;
+
+ /* Return status depending on opcode */
+
+ if (op->common.aml_opcode == AML_BREAK_OP) {
+ status = AE_CTRL_BREAK;
+ } else {
+ status = AE_CTRL_CONTINUE;
+ }
+ break;
+
+ default:
+
+ ACPI_ERROR((AE_INFO, "Unknown control opcode=%X Op=%p",
+ op->common.aml_opcode, op));
+
+ status = AE_AML_BAD_OPCODE;
+ break;
+ }
+
+ return (status);
+}
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
new file mode 100644
index 0000000..b398982
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -0,0 +1,868 @@
+/*******************************************************************************
+ *
+ * Module Name: dsutils - Dispatcher utilities
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acdebug.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dsutils")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_clear_implicit_return
+ *
+ * PARAMETERS: walk_state - Current State
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Clear and remove a reference on an implicit return value. Used
+ * to delete "stale" return values (if enabled, the return value
+ * from every operator is saved at least momentarily, in case the
+ * parent method exits.)
+ *
+ ******************************************************************************/
+void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state)
+{
+ ACPI_FUNCTION_NAME(ds_clear_implicit_return);
+
+ /*
+ * Slack must be enabled for this feature
+ */
+ if (!acpi_gbl_enable_interpreter_slack) {
+ return;
+ }
+
+ if (walk_state->implicit_return_obj) {
+ /*
+ * Delete any "stale" implicit return. However, in
+ * complex statements, the implicit return value can be
+ * bubbled up several levels.
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Removing reference on stale implicit return obj %p\n",
+ walk_state->implicit_return_obj));
+
+ acpi_ut_remove_reference(walk_state->implicit_return_obj);
+ walk_state->implicit_return_obj = NULL;
+ }
+}
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_do_implicit_return
+ *
+ * PARAMETERS: return_desc - The return value
+ * walk_state - Current State
+ * add_reference - True if a reference should be added to the
+ * return object
+ *
+ * RETURN: TRUE if implicit return enabled, FALSE otherwise
+ *
+ * DESCRIPTION: Implements the optional "implicit return". We save the result
+ * of every ASL operator and control method invocation in case the
+ * parent method exit. Before storing a new return value, we
+ * delete the previous return value.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ds_do_implicit_return(union acpi_operand_object *return_desc,
+ struct acpi_walk_state *walk_state, u8 add_reference)
+{
+ ACPI_FUNCTION_NAME(ds_do_implicit_return);
+
+ /*
+ * Slack must be enabled for this feature, and we must
+ * have a valid return object
+ */
+ if ((!acpi_gbl_enable_interpreter_slack) || (!return_desc)) {
+ return (FALSE);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Result %p will be implicitly returned; Prev=%p\n",
+ return_desc, walk_state->implicit_return_obj));
+
+ /*
+ * Delete any "stale" implicit return value first. However, in
+ * complex statements, the implicit return value can be
+ * bubbled up several levels, so we don't clear the value if it
+ * is the same as the return_desc.
+ */
+ if (walk_state->implicit_return_obj) {
+ if (walk_state->implicit_return_obj == return_desc) {
+ return (TRUE);
+ }
+ acpi_ds_clear_implicit_return(walk_state);
+ }
+
+ /* Save the implicit return value, add a reference if requested */
+
+ walk_state->implicit_return_obj = return_desc;
+ if (add_reference) {
+ acpi_ut_add_reference(return_desc);
+ }
+
+ return (TRUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_is_result_used
+ *
+ * PARAMETERS: Op - Current Op
+ * walk_state - Current State
+ *
+ * RETURN: TRUE if result is used, FALSE otherwise
+ *
+ * DESCRIPTION: Check if a result object will be used by the parent
+ *
+ ******************************************************************************/
+
+u8
+acpi_ds_is_result_used(union acpi_parse_object * op,
+ struct acpi_walk_state * walk_state)
+{
+ const struct acpi_opcode_info *parent_info;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_is_result_used, op);
+
+ /* Must have both an Op and a Result Object */
+
+ if (!op) {
+ ACPI_ERROR((AE_INFO, "Null Op"));
+ return_UINT8(TRUE);
+ }
+
+ /*
+ * We know that this operator is not a
+ * Return() operator (would not come here.) The following code is the
+ * optional support for a so-called "implicit return". Some AML code
+ * assumes that the last value of the method is "implicitly" returned
+ * to the caller. Just save the last result as the return value.
+ * NOTE: this is optional because the ASL language does not actually
+ * support this behavior.
+ */
+ (void)acpi_ds_do_implicit_return(walk_state->result_obj, walk_state,
+ TRUE);
+
+ /*
+ * Now determine if the parent will use the result
+ *
+ * If there is no parent, or the parent is a scope_op, we are executing
+ * at the method level. An executing method typically has no parent,
+ * since each method is parsed separately. A method invoked externally
+ * via execute_control_method has a scope_op as the parent.
+ */
+ if ((!op->common.parent) ||
+ (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) {
+
+ /* No parent, the return value cannot possibly be used */
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "At Method level, result of [%s] not used\n",
+ acpi_ps_get_opcode_name(op->common.
+ aml_opcode)));
+ return_UINT8(FALSE);
+ }
+
+ /* Get info on the parent. The root_op is AML_SCOPE */
+
+ parent_info =
+ acpi_ps_get_opcode_info(op->common.parent->common.aml_opcode);
+ if (parent_info->class == AML_CLASS_UNKNOWN) {
+ ACPI_ERROR((AE_INFO, "Unknown parent opcode Op=%p", op));
+ return_UINT8(FALSE);
+ }
+
+ /*
+ * Decide what to do with the result based on the parent. If
+ * the parent opcode will not use the result, delete the object.
+ * Otherwise leave it as is, it will be deleted when it is used
+ * as an operand later.
+ */
+ switch (parent_info->class) {
+ case AML_CLASS_CONTROL:
+
+ switch (op->common.parent->common.aml_opcode) {
+ case AML_RETURN_OP:
+
+ /* Never delete the return value associated with a return opcode */
+
+ goto result_used;
+
+ case AML_IF_OP:
+ case AML_WHILE_OP:
+
+ /*
+ * If we are executing the predicate AND this is the predicate op,
+ * we will use the return value
+ */
+ if ((walk_state->control_state->common.state ==
+ ACPI_CONTROL_PREDICATE_EXECUTING)
+ && (walk_state->control_state->control.
+ predicate_op == op)) {
+ goto result_used;
+ }
+ break;
+
+ default:
+ /* Ignore other control opcodes */
+ break;
+ }
+
+ /* The general control opcode returns no result */
+
+ goto result_not_used;
+
+ case AML_CLASS_CREATE:
+
+ /*
+ * These opcodes allow term_arg(s) as operands and therefore
+ * the operands can be method calls. The result is used.
+ */
+ goto result_used;
+
+ case AML_CLASS_NAMED_OBJECT:
+
+ if ((op->common.parent->common.aml_opcode == AML_REGION_OP) ||
+ (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP)
+ || (op->common.parent->common.aml_opcode == AML_PACKAGE_OP)
+ || (op->common.parent->common.aml_opcode ==
+ AML_VAR_PACKAGE_OP)
+ || (op->common.parent->common.aml_opcode == AML_BUFFER_OP)
+ || (op->common.parent->common.aml_opcode ==
+ AML_INT_EVAL_SUBTREE_OP)
+ || (op->common.parent->common.aml_opcode ==
+ AML_BANK_FIELD_OP)) {
+ /*
+ * These opcodes allow term_arg(s) as operands and therefore
+ * the operands can be method calls. The result is used.
+ */
+ goto result_used;
+ }
+
+ goto result_not_used;
+
+ default:
+
+ /*
+ * In all other cases. the parent will actually use the return
+ * object, so keep it.
+ */
+ goto result_used;
+ }
+
+ result_used:
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Result of [%s] used by Parent [%s] Op=%p\n",
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ acpi_ps_get_opcode_name(op->common.parent->common.
+ aml_opcode), op));
+
+ return_UINT8(TRUE);
+
+ result_not_used:
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Result of [%s] not used by Parent [%s] Op=%p\n",
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ acpi_ps_get_opcode_name(op->common.parent->common.
+ aml_opcode), op));
+
+ return_UINT8(FALSE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_delete_result_if_not_used
+ *
+ * PARAMETERS: Op - Current parse Op
+ * result_obj - Result of the operation
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Used after interpretation of an opcode. If there is an internal
+ * result descriptor, check if the parent opcode will actually use
+ * this result. If not, delete the result now so that it will
+ * not become orphaned.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_delete_result_if_not_used(union acpi_parse_object *op,
+ union acpi_operand_object *result_obj,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_delete_result_if_not_used, result_obj);
+
+ if (!op) {
+ ACPI_ERROR((AE_INFO, "Null Op"));
+ return_VOID;
+ }
+
+ if (!result_obj) {
+ return_VOID;
+ }
+
+ if (!acpi_ds_is_result_used(op, walk_state)) {
+
+ /* Must pop the result stack (obj_desc should be equal to result_obj) */
+
+ status = acpi_ds_result_pop(&obj_desc, walk_state);
+ if (ACPI_SUCCESS(status)) {
+ acpi_ut_remove_reference(result_obj);
+ }
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_resolve_operands
+ *
+ * PARAMETERS: walk_state - Current walk state with operands on stack
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Resolve all operands to their values. Used to prepare
+ * arguments to a control method invocation (a call from one
+ * method to another.)
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state)
+{
+ u32 i;
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_resolve_operands, walk_state);
+
+ /*
+ * Attempt to resolve each of the valid operands
+ * Method arguments are passed by reference, not by value. This means
+ * that the actual objects are passed, not copies of the objects.
+ */
+ for (i = 0; i < walk_state->num_operands; i++) {
+ status =
+ acpi_ex_resolve_to_value(&walk_state->operands[i],
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_clear_operands
+ *
+ * PARAMETERS: walk_state - Current walk state with operands on stack
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Clear all operands on the current walk state operand stack.
+ *
+ ******************************************************************************/
+
+void acpi_ds_clear_operands(struct acpi_walk_state *walk_state)
+{
+ u32 i;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_clear_operands, walk_state);
+
+ /* Remove a reference on each operand on the stack */
+
+ for (i = 0; i < walk_state->num_operands; i++) {
+ /*
+ * Remove a reference to all operands, including both
+ * "Arguments" and "Targets".
+ */
+ acpi_ut_remove_reference(walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
+ }
+
+ walk_state->num_operands = 0;
+ return_VOID;
+}
+#endif
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_operand
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Arg - Parse object for the argument
+ * arg_index - Which argument (zero based)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parse tree object that is an argument to an AML
+ * opcode to the equivalent interpreter object. This may include
+ * looking up a name or entering a new name into the internal
+ * namespace.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_operand(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *arg, u32 arg_index)
+{
+ acpi_status status = AE_OK;
+ char *name_string;
+ u32 name_length;
+ union acpi_operand_object *obj_desc;
+ union acpi_parse_object *parent_op;
+ u16 opcode;
+ acpi_interpreter_mode interpreter_mode;
+ const struct acpi_opcode_info *op_info;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_create_operand, arg);
+
+ /* A valid name must be looked up in the namespace */
+
+ if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
+ (arg->common.value.string) &&
+ !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n",
+ arg));
+
+ /* Get the entire name string from the AML stream */
+
+ status =
+ acpi_ex_get_name_string(ACPI_TYPE_ANY,
+ arg->common.value.buffer,
+ &name_string, &name_length);
+
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* All prefixes have been handled, and the name is in name_string */
+
+ /*
+ * Special handling for buffer_field declarations. This is a deferred
+ * opcode that unfortunately defines the field name as the last
+ * parameter instead of the first. We get here when we are performing
+ * the deferred execution, so the actual name of the field is already
+ * in the namespace. We don't want to attempt to look it up again
+ * because we may be executing in a different scope than where the
+ * actual opcode exists.
+ */
+ if ((walk_state->deferred_node) &&
+ (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD)
+ && (arg_index ==
+ (u32) ((walk_state->opcode ==
+ AML_CREATE_FIELD_OP) ? 3 : 2))) {
+ obj_desc =
+ ACPI_CAST_PTR(union acpi_operand_object,
+ walk_state->deferred_node);
+ status = AE_OK;
+ } else { /* All other opcodes */
+
+ /*
+ * Differentiate between a namespace "create" operation
+ * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
+ * IMODE_EXECUTE) in order to support the creation of
+ * namespace objects during the execution of control methods.
+ */
+ parent_op = arg->common.parent;
+ op_info =
+ acpi_ps_get_opcode_info(parent_op->common.
+ aml_opcode);
+ if ((op_info->flags & AML_NSNODE)
+ && (parent_op->common.aml_opcode !=
+ AML_INT_METHODCALL_OP)
+ && (parent_op->common.aml_opcode != AML_REGION_OP)
+ && (parent_op->common.aml_opcode !=
+ AML_INT_NAMEPATH_OP)) {
+
+ /* Enter name into namespace if not found */
+
+ interpreter_mode = ACPI_IMODE_LOAD_PASS2;
+ } else {
+ /* Return a failure if name not found */
+
+ interpreter_mode = ACPI_IMODE_EXECUTE;
+ }
+
+ status =
+ acpi_ns_lookup(walk_state->scope_info, name_string,
+ ACPI_TYPE_ANY, interpreter_mode,
+ ACPI_NS_SEARCH_PARENT |
+ ACPI_NS_DONT_OPEN_SCOPE, walk_state,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_namespace_node,
+ &obj_desc));
+ /*
+ * The only case where we pass through (ignore) a NOT_FOUND
+ * error is for the cond_ref_of opcode.
+ */
+ if (status == AE_NOT_FOUND) {
+ if (parent_op->common.aml_opcode ==
+ AML_COND_REF_OF_OP) {
+ /*
+ * For the Conditional Reference op, it's OK if
+ * the name is not found; We just need a way to
+ * indicate this to the interpreter, set the
+ * object to the root
+ */
+ obj_desc = ACPI_CAST_PTR(union
+ acpi_operand_object,
+ acpi_gbl_root_node);
+ status = AE_OK;
+ } else {
+ /*
+ * We just plain didn't find it -- which is a
+ * very serious error at this point
+ */
+ status = AE_AML_NAME_NOT_FOUND;
+ }
+ }
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(name_string, status);
+ }
+ }
+
+ /* Free the namestring created above */
+
+ ACPI_FREE(name_string);
+
+ /* Check status from the lookup */
+
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Put the resulting object onto the current object stack */
+
+ status = acpi_ds_obj_stack_push(obj_desc, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object
+ (obj_desc, walk_state));
+ } else {
+ /* Check for null name case */
+
+ if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
+ !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
+ /*
+ * If the name is null, this means that this is an
+ * optional result parameter that was not specified
+ * in the original ASL. Create a Zero Constant for a
+ * placeholder. (Store to a constant is a Noop.)
+ */
+ opcode = AML_ZERO_OP; /* Has no arguments! */
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Null namepath: Arg=%p\n", arg));
+ } else {
+ opcode = arg->common.aml_opcode;
+ }
+
+ /* Get the object type of the argument */
+
+ op_info = acpi_ps_get_opcode_info(opcode);
+ if (op_info->object_type == ACPI_TYPE_INVALID) {
+ return_ACPI_STATUS(AE_NOT_IMPLEMENTED);
+ }
+
+ if ((op_info->flags & AML_HAS_RETVAL)
+ || (arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Argument previously created, already stacked\n"));
+
+ ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object
+ (walk_state->
+ operands[walk_state->num_operands -
+ 1], walk_state));
+
+ /*
+ * Use value that was already previously returned
+ * by the evaluation of this argument
+ */
+ status = acpi_ds_result_pop(&obj_desc, walk_state);
+ if (ACPI_FAILURE(status)) {
+ /*
+ * Only error is underflow, and this indicates
+ * a missing or null operand!
+ */
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Missing or null operand"));
+ return_ACPI_STATUS(status);
+ }
+ } else {
+ /* Create an ACPI_INTERNAL_OBJECT for the argument */
+
+ obj_desc =
+ acpi_ut_create_internal_object(op_info->
+ object_type);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Initialize the new object */
+
+ status =
+ acpi_ds_init_object_from_op(walk_state, arg, opcode,
+ &obj_desc);
+ if (ACPI_FAILURE(status)) {
+ acpi_ut_delete_object_desc(obj_desc);
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ /* Put the operand object on the object stack */
+
+ status = acpi_ds_obj_stack_push(obj_desc, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DEBUGGER_EXEC(acpi_db_display_argument_object
+ (obj_desc, walk_state));
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_operands
+ *
+ * PARAMETERS: walk_state - Current state
+ * first_arg - First argument of a parser argument tree
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert an operator's arguments from a parse tree format to
+ * namespace objects and place those argument object on the object
+ * stack in preparation for evaluation by the interpreter.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *first_arg)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *arg;
+ union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS];
+ u32 arg_count = 0;
+ u32 index = walk_state->num_operands;
+ u32 i;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
+
+ /* Get all arguments in the list */
+
+ arg = first_arg;
+ while (arg) {
+ if (index >= ACPI_OBJ_NUM_OPERANDS) {
+ return_ACPI_STATUS(AE_BAD_DATA);
+ }
+
+ arguments[index] = arg;
+ walk_state->operands[index] = NULL;
+
+ /* Move on to next argument, if any */
+
+ arg = arg->common.next;
+ arg_count++;
+ index++;
+ }
+
+ index--;
+
+ /* It is the appropriate order to get objects from the Result stack */
+
+ for (i = 0; i < arg_count; i++) {
+ arg = arguments[index];
+
+ /* Force the filling of the operand stack in inverse order */
+
+ walk_state->operand_index = (u8) index;
+
+ status = acpi_ds_create_operand(walk_state, arg, index);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ index--;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Arg #%d (%p) done, Arg1=%p\n", index, arg,
+ first_arg));
+ }
+
+ return_ACPI_STATUS(status);
+
+ cleanup:
+ /*
+ * We must undo everything done above; meaning that we must
+ * pop everything off of the operand stack and delete those
+ * objects
+ */
+ acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
+
+ ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", index));
+ return_ACPI_STATUS(status);
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_evaluate_name_path
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk,
+ * the opcode of current operation should be
+ * AML_INT_NAMEPATH_OP
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate the -name_path- parse tree object to the equivalent
+ * interpreter object, convert it to value, if needed, duplicate
+ * it, if needed, and push it onto the current result stack.
+ *
+ ****************************************************************************/
+
+acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op = walk_state->op;
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *new_obj_desc;
+ u8 type;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state);
+
+ if (!op->common.parent) {
+
+ /* This happens after certain exception processing */
+
+ goto exit;
+ }
+
+ if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_REF_OF_OP)) {
+
+ /* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */
+
+ goto exit;
+ }
+
+ status = acpi_ds_create_operand(walk_state, op, 0);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ if (op->common.flags & ACPI_PARSEOP_TARGET) {
+ new_obj_desc = *operand;
+ goto push_result;
+ }
+
+ type = ACPI_GET_OBJECT_TYPE(*operand);
+
+ status = acpi_ex_resolve_to_value(operand, walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ if (type == ACPI_TYPE_INTEGER) {
+
+ /* It was incremented by acpi_ex_resolve_to_value */
+
+ acpi_ut_remove_reference(*operand);
+
+ status =
+ acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+ } else {
+ /*
+ * The object either was anew created or is
+ * a Namespace node - don't decrement it.
+ */
+ new_obj_desc = *operand;
+ }
+
+ /* Cleanup for name-path operand */
+
+ status = acpi_ds_obj_stack_pop(1, walk_state);
+ if (ACPI_FAILURE(status)) {
+ walk_state->result_obj = new_obj_desc;
+ goto exit;
+ }
+
+ push_result:
+
+ walk_state->result_obj = new_obj_desc;
+
+ status = acpi_ds_result_push(walk_state->result_obj, walk_state);
+ if (ACPI_SUCCESS(status)) {
+
+ /* Force to take it from stack */
+
+ op->common.flags |= ACPI_PARSEOP_IN_STACK;
+ }
+
+ exit:
+
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
new file mode 100644
index 0000000..396fe12
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -0,0 +1,745 @@
+/******************************************************************************
+ *
+ * Module Name: dswexec - Dispatcher method execution callbacks;
+ * dispatch to interpreter.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acdebug.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dswexec")
+
+/*
+ * Dispatch table for opcode classes
+ */
+static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch[] = {
+ acpi_ex_opcode_0A_0T_1R,
+ acpi_ex_opcode_1A_0T_0R,
+ acpi_ex_opcode_1A_0T_1R,
+ acpi_ex_opcode_1A_1T_0R,
+ acpi_ex_opcode_1A_1T_1R,
+ acpi_ex_opcode_2A_0T_0R,
+ acpi_ex_opcode_2A_0T_1R,
+ acpi_ex_opcode_2A_1T_1R,
+ acpi_ex_opcode_2A_2T_1R,
+ acpi_ex_opcode_3A_0T_0R,
+ acpi_ex_opcode_3A_1T_1R,
+ acpi_ex_opcode_6A_0T_1R
+};
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_predicate_value
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * result_obj - if non-zero, pop result from result stack
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the result of a predicate evaluation
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state,
+ union acpi_operand_object *result_obj)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *local_obj_desc = NULL;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_predicate_value, walk_state);
+
+ walk_state->control_state->common.state = 0;
+
+ if (result_obj) {
+ status = acpi_ds_result_pop(&obj_desc, walk_state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not get result from predicate evaluation"));
+
+ return_ACPI_STATUS(status);
+ }
+ } else {
+ status = acpi_ds_create_operand(walk_state, walk_state->op, 0);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status =
+ acpi_ex_resolve_to_value(&walk_state->operands[0],
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ obj_desc = walk_state->operands[0];
+ }
+
+ if (!obj_desc) {
+ ACPI_ERROR((AE_INFO,
+ "No predicate ObjDesc=%p State=%p",
+ obj_desc, walk_state));
+
+ return_ACPI_STATUS(AE_AML_NO_OPERAND);
+ }
+
+ /*
+ * Result of predicate evaluation must be an Integer
+ * object. Implicitly convert the argument if necessary.
+ */
+ status = acpi_ex_convert_to_integer(obj_desc, &local_obj_desc, 16);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ if (ACPI_GET_OBJECT_TYPE(local_obj_desc) != ACPI_TYPE_INTEGER) {
+ ACPI_ERROR((AE_INFO,
+ "Bad predicate (not an integer) ObjDesc=%p State=%p Type=%X",
+ obj_desc, walk_state,
+ ACPI_GET_OBJECT_TYPE(obj_desc)));
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /* Truncate the predicate to 32-bits if necessary */
+
+ acpi_ex_truncate_for32bit_table(local_obj_desc);
+
+ /*
+ * Save the result of the predicate evaluation on
+ * the control stack
+ */
+ if (local_obj_desc->integer.value) {
+ walk_state->control_state->common.value = TRUE;
+ } else {
+ /*
+ * Predicate is FALSE, we will just toss the
+ * rest of the package
+ */
+ walk_state->control_state->common.value = FALSE;
+ status = AE_CTRL_FALSE;
+ }
+
+ /* Predicate can be used for an implicit return value */
+
+ (void)acpi_ds_do_implicit_return(local_obj_desc, walk_state, TRUE);
+
+ cleanup:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n",
+ walk_state->control_state->common.value,
+ walk_state->op));
+
+ /* Break to debugger to display result */
+
+ ACPI_DEBUGGER_EXEC(acpi_db_display_result_object
+ (local_obj_desc, walk_state));
+
+ /*
+ * Delete the predicate result object (we know that
+ * we don't need it anymore)
+ */
+ if (local_obj_desc != obj_desc) {
+ acpi_ut_remove_reference(local_obj_desc);
+ }
+ acpi_ut_remove_reference(obj_desc);
+
+ walk_state->control_state->common.state = ACPI_CONTROL_NORMAL;
+ return_ACPI_STATUS(status);
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_exec_begin_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * out_op - Where to return op if a new one is created
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the execution of control
+ * methods. This is where most operators and operands are
+ * dispatched to the interpreter.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op)
+{
+ union acpi_parse_object *op;
+ acpi_status status = AE_OK;
+ u32 opcode_class;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_exec_begin_op, walk_state);
+
+ op = walk_state->op;
+ if (!op) {
+ status = acpi_ds_load2_begin_op(walk_state, out_op);
+ if (ACPI_FAILURE(status)) {
+ goto error_exit;
+ }
+
+ op = *out_op;
+ walk_state->op = op;
+ walk_state->opcode = op->common.aml_opcode;
+ walk_state->op_info =
+ acpi_ps_get_opcode_info(op->common.aml_opcode);
+
+ if (acpi_ns_opens_scope(walk_state->op_info->object_type)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "(%s) Popping scope for Op %p\n",
+ acpi_ut_get_type_name(walk_state->
+ op_info->
+ object_type),
+ op));
+
+ status = acpi_ds_scope_stack_pop(walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto error_exit;
+ }
+ }
+ }
+
+ if (op == walk_state->origin) {
+ if (out_op) {
+ *out_op = op;
+ }
+
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /*
+ * If the previous opcode was a conditional, this opcode
+ * must be the beginning of the associated predicate.
+ * Save this knowledge in the current scope descriptor
+ */
+ if ((walk_state->control_state) &&
+ (walk_state->control_state->common.state ==
+ ACPI_CONTROL_CONDITIONAL_EXECUTING)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Exec predicate Op=%p State=%p\n", op,
+ walk_state));
+
+ walk_state->control_state->common.state =
+ ACPI_CONTROL_PREDICATE_EXECUTING;
+
+ /* Save start of predicate */
+
+ walk_state->control_state->control.predicate_op = op;
+ }
+
+ opcode_class = walk_state->op_info->class;
+
+ /* We want to send namepaths to the load code */
+
+ if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ opcode_class = AML_CLASS_NAMED_OBJECT;
+ }
+
+ /*
+ * Handle the opcode based upon the opcode type
+ */
+ switch (opcode_class) {
+ case AML_CLASS_CONTROL:
+
+ status = acpi_ds_exec_begin_control_op(walk_state, op);
+ break;
+
+ case AML_CLASS_NAMED_OBJECT:
+
+ if (walk_state->walk_type & ACPI_WALK_METHOD) {
+ /*
+ * Found a named object declaration during method execution;
+ * we must enter this object into the namespace. The created
+ * object is temporary and will be deleted upon completion of
+ * the execution of this method.
+ */
+ status = acpi_ds_load2_begin_op(walk_state, NULL);
+ }
+
+ break;
+
+ case AML_CLASS_EXECUTE:
+ case AML_CLASS_CREATE:
+
+ break;
+
+ default:
+ break;
+ }
+
+ /* Nothing to do here during method execution */
+
+ return_ACPI_STATUS(status);
+
+ error_exit:
+ status = acpi_ds_method_error(status, walk_state);
+ return_ACPI_STATUS(status);
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_exec_end_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback used during the execution of control
+ * methods. The only thing we really need to do here is to
+ * notice the beginning of IF, ELSE, and WHILE blocks.
+ *
+ ****************************************************************************/
+
+acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
+{
+ union acpi_parse_object *op;
+ acpi_status status = AE_OK;
+ u32 op_type;
+ u32 op_class;
+ union acpi_parse_object *next_op;
+ union acpi_parse_object *first_arg;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_exec_end_op, walk_state);
+
+ op = walk_state->op;
+ op_type = walk_state->op_info->type;
+ op_class = walk_state->op_info->class;
+
+ if (op_class == AML_CLASS_UNKNOWN) {
+ ACPI_ERROR((AE_INFO, "Unknown opcode %X",
+ op->common.aml_opcode));
+ return_ACPI_STATUS(AE_NOT_IMPLEMENTED);
+ }
+
+ first_arg = op->common.value.arg;
+
+ /* Init the walk state */
+
+ walk_state->num_operands = 0;
+ walk_state->operand_index = 0;
+ walk_state->return_desc = NULL;
+ walk_state->result_obj = NULL;
+
+ /* Call debugger for single step support (DEBUG build only) */
+
+ ACPI_DEBUGGER_EXEC(status =
+ acpi_db_single_step(walk_state, op, op_class));
+ ACPI_DEBUGGER_EXEC(if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);}
+ ) ;
+
+ /* Decode the Opcode Class */
+
+ switch (op_class) {
+ case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */
+
+ if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
+ status = acpi_ds_evaluate_name_path(walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
+ break;
+
+ case AML_CLASS_EXECUTE: /* Most operators with arguments */
+
+ /* Build resolved operand stack */
+
+ status = acpi_ds_create_operands(walk_state, first_arg);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ /*
+ * All opcodes require operand resolution, with the only exceptions
+ * being the object_type and size_of operators.
+ */
+ if (!(walk_state->op_info->flags & AML_NO_OPERAND_RESOLVE)) {
+
+ /* Resolve all operands */
+
+ status = acpi_ex_resolve_operands(walk_state->opcode,
+ &(walk_state->
+ operands
+ [walk_state->
+ num_operands - 1]),
+ walk_state);
+ }
+
+ if (ACPI_SUCCESS(status)) {
+ /*
+ * Dispatch the request to the appropriate interpreter handler
+ * routine. There is one routine per opcode "type" based upon the
+ * number of opcode arguments and return type.
+ */
+ status =
+ acpi_gbl_op_type_dispatch[op_type] (walk_state);
+ } else {
+ /*
+ * Treat constructs of the form "Store(LocalX,LocalX)" as noops when the
+ * Local is uninitialized.
+ */
+ if ((status == AE_AML_UNINITIALIZED_LOCAL) &&
+ (walk_state->opcode == AML_STORE_OP) &&
+ (walk_state->operands[0]->common.type ==
+ ACPI_TYPE_LOCAL_REFERENCE)
+ && (walk_state->operands[1]->common.type ==
+ ACPI_TYPE_LOCAL_REFERENCE)
+ && (walk_state->operands[0]->reference.class ==
+ walk_state->operands[1]->reference.class)
+ && (walk_state->operands[0]->reference.value ==
+ walk_state->operands[1]->reference.value)) {
+ status = AE_OK;
+ } else {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "While resolving operands for [%s]",
+ acpi_ps_get_opcode_name
+ (walk_state->opcode)));
+ }
+ }
+
+ /* Always delete the argument objects and clear the operand stack */
+
+ acpi_ds_clear_operands(walk_state);
+
+ /*
+ * If a result object was returned from above, push it on the
+ * current result stack
+ */
+ if (ACPI_SUCCESS(status) && walk_state->result_obj) {
+ status =
+ acpi_ds_result_push(walk_state->result_obj,
+ walk_state);
+ }
+ break;
+
+ default:
+
+ switch (op_type) {
+ case AML_TYPE_CONTROL: /* Type 1 opcode, IF/ELSE/WHILE/NOOP */
+
+ /* 1 Operand, 0 external_result, 0 internal_result */
+
+ status = acpi_ds_exec_end_control_op(walk_state, op);
+
+ break;
+
+ case AML_TYPE_METHOD_CALL:
+
+ /*
+ * If the method is referenced from within a package
+ * declaration, it is not a invocation of the method, just
+ * a reference to it.
+ */
+ if ((op->asl.parent) &&
+ ((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP)
+ || (op->asl.parent->asl.aml_opcode ==
+ AML_VAR_PACKAGE_OP))) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Method Reference in a Package, Op=%p\n",
+ op));
+
+ op->common.node =
+ (struct acpi_namespace_node *)op->asl.value.
+ arg->asl.node;
+ acpi_ut_add_reference(op->asl.value.arg->asl.
+ node->object);
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Method invocation, Op=%p\n", op));
+
+ /*
+ * (AML_METHODCALL) Op->Asl.Value.Arg->Asl.Node contains
+ * the method Node pointer
+ */
+ /* next_op points to the op that holds the method name */
+
+ next_op = first_arg;
+
+ /* next_op points to first argument op */
+
+ next_op = next_op->common.next;
+
+ /*
+ * Get the method's arguments and put them on the operand stack
+ */
+ status = acpi_ds_create_operands(walk_state, next_op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+
+ /*
+ * Since the operands will be passed to another control method,
+ * we must resolve all local references here (Local variables,
+ * arguments to *this* method, etc.)
+ */
+ status = acpi_ds_resolve_operands(walk_state);
+ if (ACPI_FAILURE(status)) {
+
+ /* On error, clear all resolved operands */
+
+ acpi_ds_clear_operands(walk_state);
+ break;
+ }
+
+ /*
+ * Tell the walk loop to preempt this running method and
+ * execute the new method
+ */
+ status = AE_CTRL_TRANSFER;
+
+ /*
+ * Return now; we don't want to disturb anything,
+ * especially the operand count!
+ */
+ return_ACPI_STATUS(status);
+
+ case AML_TYPE_CREATE_FIELD:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing CreateField Buffer/Index Op=%p\n",
+ op));
+
+ status = acpi_ds_load2_end_op(walk_state);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+
+ status =
+ acpi_ds_eval_buffer_field_operands(walk_state, op);
+ break;
+
+ case AML_TYPE_CREATE_OBJECT:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing CreateObject (Buffer/Package) Op=%p\n",
+ op));
+
+ switch (op->common.parent->common.aml_opcode) {
+ case AML_NAME_OP:
+
+ /*
+ * Put the Node on the object stack (Contains the ACPI Name
+ * of this object)
+ */
+ walk_state->operands[0] =
+ (void *)op->common.parent->common.node;
+ walk_state->num_operands = 1;
+
+ status = acpi_ds_create_node(walk_state,
+ op->common.parent->
+ common.node,
+ op->common.parent);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+
+ /* Fall through */
+ /*lint -fallthrough */
+
+ case AML_INT_EVAL_SUBTREE_OP:
+
+ status =
+ acpi_ds_eval_data_object_operands
+ (walk_state, op,
+ acpi_ns_get_attached_object(op->common.
+ parent->common.
+ node));
+ break;
+
+ default:
+
+ status =
+ acpi_ds_eval_data_object_operands
+ (walk_state, op, NULL);
+ break;
+ }
+
+ /*
+ * If a result object was returned from above, push it on the
+ * current result stack
+ */
+ if (walk_state->result_obj) {
+ status =
+ acpi_ds_result_push(walk_state->result_obj,
+ walk_state);
+ }
+ break;
+
+ case AML_TYPE_NAMED_FIELD:
+ case AML_TYPE_NAMED_COMPLEX:
+ case AML_TYPE_NAMED_SIMPLE:
+ case AML_TYPE_NAMED_NO_OBJ:
+
+ status = acpi_ds_load2_end_op(walk_state);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing OpRegion Address/Length Op=%p\n",
+ op));
+
+ status =
+ acpi_ds_eval_region_operands(walk_state,
+ op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+ } else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing DataTableRegion Strings Op=%p\n",
+ op));
+
+ status =
+ acpi_ds_eval_table_region_operands
+ (walk_state, op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+ } else if (op->common.aml_opcode == AML_BANK_FIELD_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing BankField Op=%p\n",
+ op));
+
+ status =
+ acpi_ds_eval_bank_field_operands(walk_state,
+ op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+ }
+ break;
+
+ case AML_TYPE_UNDEFINED:
+
+ ACPI_ERROR((AE_INFO,
+ "Undefined opcode type Op=%p", op));
+ return_ACPI_STATUS(AE_NOT_IMPLEMENTED);
+
+ case AML_TYPE_BOGUS:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Internal opcode=%X type Op=%p\n",
+ walk_state->opcode, op));
+ break;
+
+ default:
+
+ ACPI_ERROR((AE_INFO,
+ "Unimplemented opcode, class=%X type=%X Opcode=%X Op=%p",
+ op_class, op_type, op->common.aml_opcode,
+ op));
+
+ status = AE_NOT_IMPLEMENTED;
+ break;
+ }
+ }
+
+ /*
+ * ACPI 2.0 support for 64-bit integers: Truncate numeric
+ * result value if we are executing from a 32-bit ACPI table
+ */
+ acpi_ex_truncate_for32bit_table(walk_state->result_obj);
+
+ /*
+ * Check if we just completed the evaluation of a
+ * conditional predicate
+ */
+ if ((ACPI_SUCCESS(status)) &&
+ (walk_state->control_state) &&
+ (walk_state->control_state->common.state ==
+ ACPI_CONTROL_PREDICATE_EXECUTING) &&
+ (walk_state->control_state->control.predicate_op == op)) {
+ status =
+ acpi_ds_get_predicate_value(walk_state,
+ walk_state->result_obj);
+ walk_state->result_obj = NULL;
+ }
+
+ cleanup:
+
+ if (walk_state->result_obj) {
+
+ /* Break to debugger to display result */
+
+ ACPI_DEBUGGER_EXEC(acpi_db_display_result_object
+ (walk_state->result_obj, walk_state));
+
+ /*
+ * Delete the result op if and only if:
+ * Parent will not use the result -- such as any
+ * non-nested type2 op in a method (parent will be method)
+ */
+ acpi_ds_delete_result_if_not_used(op, walk_state->result_obj,
+ walk_state);
+ }
+#ifdef _UNDER_DEVELOPMENT
+
+ if (walk_state->parser_state.aml == walk_state->parser_state.aml_end) {
+ acpi_db_method_end(walk_state);
+ }
+#endif
+
+ /* Invoke exception handler on error */
+
+ if (ACPI_FAILURE(status)) {
+ status = acpi_ds_method_error(status, walk_state);
+ }
+
+ /* Always clear the object stack */
+
+ walk_state->num_operands = 0;
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
new file mode 100644
index 0000000..dff7a3e
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -0,0 +1,1202 @@
+/******************************************************************************
+ *
+ * Module Name: dswload - Dispatcher namespace load callbacks
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+
+#ifdef ACPI_ASL_COMPILER
+#include <acpi/acdisasm.h>
+#endif
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dswload")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_callbacks
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * pass_number - 1, 2, or 3
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Init walk state callbacks
+ *
+ ******************************************************************************/
+acpi_status
+acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number)
+{
+
+ switch (pass_number) {
+ case 1:
+ walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
+ ACPI_PARSE_DELETE_TREE;
+ walk_state->descending_callback = acpi_ds_load1_begin_op;
+ walk_state->ascending_callback = acpi_ds_load1_end_op;
+ break;
+
+ case 2:
+ walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
+ ACPI_PARSE_DELETE_TREE;
+ walk_state->descending_callback = acpi_ds_load2_begin_op;
+ walk_state->ascending_callback = acpi_ds_load2_end_op;
+ break;
+
+ case 3:
+#ifndef ACPI_NO_METHOD_EXECUTION
+ walk_state->parse_flags |= ACPI_PARSE_EXECUTE |
+ ACPI_PARSE_DELETE_TREE;
+ walk_state->descending_callback = acpi_ds_exec_begin_op;
+ walk_state->ascending_callback = acpi_ds_exec_end_op;
+#endif
+ break;
+
+ default:
+ return (AE_BAD_PARAMETER);
+ }
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_load1_begin_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * out_op - Where to return op if a new one is created
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
+ union acpi_parse_object ** out_op)
+{
+ union acpi_parse_object *op;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ acpi_object_type object_type;
+ char *path;
+ u32 flags;
+
+ ACPI_FUNCTION_TRACE(ds_load1_begin_op);
+
+ op = walk_state->op;
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
+ walk_state));
+
+ /* We are only interested in opcodes that have an associated name */
+
+ if (op) {
+ if (!(walk_state->op_info->flags & AML_NAMED)) {
+ *out_op = op;
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Check if this object has already been installed in the namespace */
+
+ if (op->common.node) {
+ *out_op = op;
+ return_ACPI_STATUS(AE_OK);
+ }
+ }
+
+ path = acpi_ps_get_next_namestring(&walk_state->parser_state);
+
+ /* Map the raw opcode into an internal object type */
+
+ object_type = walk_state->op_info->object_type;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "State=%p Op=%p [%s]\n", walk_state, op,
+ acpi_ut_get_type_name(object_type)));
+
+ switch (walk_state->opcode) {
+ case AML_SCOPE_OP:
+
+ /*
+ * The target name of the Scope() operator must exist at this point so
+ * that we can actually open the scope to enter new names underneath it.
+ * Allow search-to-root for single namesegs.
+ */
+ status =
+ acpi_ns_lookup(walk_state->scope_info, path, object_type,
+ ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
+ walk_state, &(node));
+#ifdef ACPI_ASL_COMPILER
+ if (status == AE_NOT_FOUND) {
+ /*
+ * Table disassembly:
+ * Target of Scope() not found. Generate an External for it, and
+ * insert the name into the namespace.
+ */
+ acpi_dm_add_to_external_list(path, ACPI_TYPE_DEVICE, 0);
+ status =
+ acpi_ns_lookup(walk_state->scope_info, path,
+ object_type, ACPI_IMODE_LOAD_PASS1,
+ ACPI_NS_SEARCH_PARENT, walk_state,
+ &node);
+ }
+#endif
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(path, status);
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Check to make sure that the target is
+ * one of the opcodes that actually opens a scope
+ */
+ switch (node->type) {
+ case ACPI_TYPE_ANY:
+ case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+
+ /* These are acceptable types */
+ break;
+
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * These types we will allow, but we will change the type. This
+ * enables some existing code of the form:
+ *
+ * Name (DEB, 0)
+ * Scope (DEB) { ... }
+ *
+ * Note: silently change the type here. On the second pass, we will report
+ * a warning
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
+ path,
+ acpi_ut_get_type_name(node->type)));
+
+ node->type = ACPI_TYPE_ANY;
+ walk_state->scope_info->common.value = ACPI_TYPE_ANY;
+ break;
+
+ default:
+
+ /* All other types are an error */
+
+ ACPI_ERROR((AE_INFO,
+ "Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)",
+ acpi_ut_get_type_name(node->type), path));
+
+ return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+ }
+ break;
+
+ default:
+ /*
+ * For all other named opcodes, we will enter the name into
+ * the namespace.
+ *
+ * Setup the search flags.
+ * Since we are entering a name into the namespace, we do not want to
+ * enable the search-to-root upsearch.
+ *
+ * There are only two conditions where it is acceptable that the name
+ * already exists:
+ * 1) the Scope() operator can reopen a scoping object that was
+ * previously defined (Scope, Method, Device, etc.)
+ * 2) Whenever we are parsing a deferred opcode (op_region, Buffer,
+ * buffer_field, or Package), the name of the object is already
+ * in the namespace.
+ */
+ if (walk_state->deferred_node) {
+
+ /* This name is already in the namespace, get the node */
+
+ node = walk_state->deferred_node;
+ status = AE_OK;
+ break;
+ }
+
+ /*
+ * If we are executing a method, do not create any namespace objects
+ * during the load phase, only during execution.
+ */
+ if (walk_state->method_node) {
+ node = NULL;
+ status = AE_OK;
+ break;
+ }
+
+ flags = ACPI_NS_NO_UPSEARCH;
+ if ((walk_state->opcode != AML_SCOPE_OP) &&
+ (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) {
+ flags |= ACPI_NS_ERROR_IF_FOUND;
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "[%s] Cannot already exist\n",
+ acpi_ut_get_type_name(object_type)));
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "[%s] Both Find or Create allowed\n",
+ acpi_ut_get_type_name(object_type)));
+ }
+
+ /*
+ * Enter the named type into the internal namespace. We enter the name
+ * as we go downward in the parse tree. Any necessary subobjects that
+ * involve arguments to the opcode must be created as we go back up the
+ * parse tree later.
+ */
+ status =
+ acpi_ns_lookup(walk_state->scope_info, path, object_type,
+ ACPI_IMODE_LOAD_PASS1, flags, walk_state,
+ &node);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_ALREADY_EXISTS) {
+
+ /* The name already exists in this scope */
+
+ if (node->flags & ANOBJ_IS_EXTERNAL) {
+ /*
+ * Allow one create on an object or segment that was
+ * previously declared External
+ */
+ node->flags &= ~ANOBJ_IS_EXTERNAL;
+ node->type = (u8) object_type;
+
+ /* Just retyped a node, probably will need to open a scope */
+
+ if (acpi_ns_opens_scope(object_type)) {
+ status =
+ acpi_ds_scope_stack_push
+ (node, object_type,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS
+ (status);
+ }
+ }
+
+ status = AE_OK;
+ }
+ }
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(path, status);
+ return_ACPI_STATUS(status);
+ }
+ }
+ break;
+ }
+
+ /* Common exit */
+
+ if (!op) {
+
+ /* Create a new op */
+
+ op = acpi_ps_alloc_op(walk_state->opcode);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+ }
+
+ /* Initialize the op */
+
+#if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY))
+ op->named.path = ACPI_CAST_PTR(u8, path);
+#endif
+
+ if (node) {
+ /*
+ * Put the Node in the "op" object that the parser uses, so we
+ * can get it again quickly when this scope is closed
+ */
+ op->common.node = node;
+ op->named.name = node->name.integer;
+ }
+
+ acpi_ps_append_arg(acpi_ps_get_parent_scope(&walk_state->parser_state),
+ op);
+ *out_op = op;
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_load1_end_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback used during the loading of the namespace,
+ * both control methods and everything else.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
+{
+ union acpi_parse_object *op;
+ acpi_object_type object_type;
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(ds_load1_end_op);
+
+ op = walk_state->op;
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
+ walk_state));
+
+ /* We are only interested in opcodes that have an associated name */
+
+ if (!(walk_state->op_info->flags & (AML_NAMED | AML_FIELD))) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Get the object type to determine if we should pop the scope */
+
+ object_type = walk_state->op_info->object_type;
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+ if (walk_state->op_info->flags & AML_FIELD) {
+ /*
+ * If we are executing a method, do not create any namespace objects
+ * during the load phase, only during execution.
+ */
+ if (!walk_state->method_node) {
+ if (walk_state->opcode == AML_FIELD_OP ||
+ walk_state->opcode == AML_BANK_FIELD_OP ||
+ walk_state->opcode == AML_INDEX_FIELD_OP) {
+ status =
+ acpi_ds_init_field_objects(op, walk_state);
+ }
+ }
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * If we are executing a method, do not create any namespace objects
+ * during the load phase, only during execution.
+ */
+ if (!walk_state->method_node) {
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ status =
+ acpi_ex_create_region(op->named.data,
+ op->named.length,
+ (acpi_adr_space_type) ((op->
+ common.
+ value.
+ arg)->
+ common.
+ value.
+ integer),
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ } else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+ status =
+ acpi_ex_create_region(op->named.data,
+ op->named.length,
+ REGION_DATA_TABLE,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+ }
+#endif
+
+ if (op->common.aml_opcode == AML_NAME_OP) {
+
+ /* For Name opcode, get the object type from the argument */
+
+ if (op->common.value.arg) {
+ object_type = (acpi_ps_get_opcode_info((op->common.
+ value.arg)->
+ common.
+ aml_opcode))->
+ object_type;
+
+ /* Set node type if we have a namespace node */
+
+ if (op->common.node) {
+ op->common.node->type = (u8) object_type;
+ }
+ }
+ }
+
+ /*
+ * If we are executing a method, do not create any namespace objects
+ * during the load phase, only during execution.
+ */
+ if (!walk_state->method_node) {
+ if (op->common.aml_opcode == AML_METHOD_OP) {
+ /*
+ * method_op pkg_length name_string method_flags term_list
+ *
+ * Note: We must create the method node/object pair as soon as we
+ * see the method declaration. This allows later pass1 parsing
+ * of invocations of the method (need to know the number of
+ * arguments.)
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "LOADING-Method: State=%p Op=%p NamedObj=%p\n",
+ walk_state, op, op->named.node));
+
+ if (!acpi_ns_get_attached_object(op->named.node)) {
+ walk_state->operands[0] =
+ ACPI_CAST_PTR(void, op->named.node);
+ walk_state->num_operands = 1;
+
+ status =
+ acpi_ds_create_operands(walk_state,
+ op->common.value.
+ arg);
+ if (ACPI_SUCCESS(status)) {
+ status =
+ acpi_ex_create_method(op->named.
+ data,
+ op->named.
+ length,
+ walk_state);
+ }
+
+ walk_state->operands[0] = NULL;
+ walk_state->num_operands = 0;
+
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+ }
+ }
+
+ /* Pop the scope stack (only if loading a table) */
+
+ if (!walk_state->method_node && acpi_ns_opens_scope(object_type)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "(%s): Popping scope for Op %p\n",
+ acpi_ut_get_type_name(object_type), op));
+
+ status = acpi_ds_scope_stack_pop(walk_state);
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_load2_begin_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * out_op - Wher to return op if a new one is created
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op)
+{
+ union acpi_parse_object *op;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ acpi_object_type object_type;
+ char *buffer_ptr;
+ u32 flags;
+
+ ACPI_FUNCTION_TRACE(ds_load2_begin_op);
+
+ op = walk_state->op;
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op,
+ walk_state));
+
+ if (op) {
+ if ((walk_state->control_state) &&
+ (walk_state->control_state->common.state ==
+ ACPI_CONTROL_CONDITIONAL_EXECUTING)) {
+
+ /* We are executing a while loop outside of a method */
+
+ status = acpi_ds_exec_begin_op(walk_state, out_op);
+ return_ACPI_STATUS(status);
+ }
+
+ /* We only care about Namespace opcodes here */
+
+ if ((!(walk_state->op_info->flags & AML_NSOPCODE) &&
+ (walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
+ (!(walk_state->op_info->flags & AML_NAMED))) {
+#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
+ if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
+ (walk_state->op_info->class == AML_CLASS_CONTROL)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Begin/EXEC: %s (fl %8.8X)\n",
+ walk_state->op_info->name,
+ walk_state->op_info->flags));
+
+ /* Executing a type1 or type2 opcode outside of a method */
+
+ status =
+ acpi_ds_exec_begin_op(walk_state, out_op);
+ return_ACPI_STATUS(status);
+ }
+#endif
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Get the name we are going to enter or lookup in the namespace */
+
+ if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
+
+ /* For Namepath op, get the path string */
+
+ buffer_ptr = op->common.value.string;
+ if (!buffer_ptr) {
+
+ /* No name, just exit */
+
+ return_ACPI_STATUS(AE_OK);
+ }
+ } else {
+ /* Get name from the op */
+
+ buffer_ptr = ACPI_CAST_PTR(char, &op->named.name);
+ }
+ } else {
+ /* Get the namestring from the raw AML */
+
+ buffer_ptr =
+ acpi_ps_get_next_namestring(&walk_state->parser_state);
+ }
+
+ /* Map the opcode into an internal object type */
+
+ object_type = walk_state->op_info->object_type;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "State=%p Op=%p Type=%X\n", walk_state, op,
+ object_type));
+
+ switch (walk_state->opcode) {
+ case AML_FIELD_OP:
+ case AML_BANK_FIELD_OP:
+ case AML_INDEX_FIELD_OP:
+
+ node = NULL;
+ status = AE_OK;
+ break;
+
+ case AML_INT_NAMEPATH_OP:
+ /*
+ * The name_path is an object reference to an existing object.
+ * Don't enter the name into the namespace, but look it up
+ * for use later.
+ */
+ status =
+ acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
+ object_type, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+ break;
+
+ case AML_SCOPE_OP:
+ /*
+ * The Path is an object reference to an existing object.
+ * Don't enter the name into the namespace, but look it up
+ * for use later.
+ */
+ status =
+ acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
+ object_type, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+ if (ACPI_FAILURE(status)) {
+#ifdef ACPI_ASL_COMPILER
+ if (status == AE_NOT_FOUND) {
+ status = AE_OK;
+ } else {
+ ACPI_ERROR_NAMESPACE(buffer_ptr, status);
+ }
+#else
+ ACPI_ERROR_NAMESPACE(buffer_ptr, status);
+#endif
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * We must check to make sure that the target is
+ * one of the opcodes that actually opens a scope
+ */
+ switch (node->type) {
+ case ACPI_TYPE_ANY:
+ case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+
+ /* These are acceptable types */
+ break;
+
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * These types we will allow, but we will change the type. This
+ * enables some existing code of the form:
+ *
+ * Name (DEB, 0)
+ * Scope (DEB) { ... }
+ */
+ ACPI_WARNING((AE_INFO,
+ "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)",
+ buffer_ptr,
+ acpi_ut_get_type_name(node->type)));
+
+ node->type = ACPI_TYPE_ANY;
+ walk_state->scope_info->common.value = ACPI_TYPE_ANY;
+ break;
+
+ default:
+
+ /* All other types are an error */
+
+ ACPI_ERROR((AE_INFO,
+ "Invalid type (%s) for target of Scope operator [%4.4s]",
+ acpi_ut_get_type_name(node->type),
+ buffer_ptr));
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+ break;
+
+ default:
+
+ /* All other opcodes */
+
+ if (op && op->common.node) {
+
+ /* This op/node was previously entered into the namespace */
+
+ node = op->common.node;
+
+ if (acpi_ns_opens_scope(object_type)) {
+ status =
+ acpi_ds_scope_stack_push(node, object_type,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /*
+ * Enter the named type into the internal namespace. We enter the name
+ * as we go downward in the parse tree. Any necessary subobjects that
+ * involve arguments to the opcode must be created as we go back up the
+ * parse tree later.
+ *
+ * Note: Name may already exist if we are executing a deferred opcode.
+ */
+ if (walk_state->deferred_node) {
+
+ /* This name is already in the namespace, get the node */
+
+ node = walk_state->deferred_node;
+ status = AE_OK;
+ break;
+ }
+
+ flags = ACPI_NS_NO_UPSEARCH;
+ if (walk_state->pass_number == ACPI_IMODE_EXECUTE) {
+
+ /* Execution mode, node cannot already exist, node is temporary */
+
+ flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY);
+ }
+
+ /* Add new entry or lookup existing entry */
+
+ status =
+ acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
+ object_type, ACPI_IMODE_LOAD_PASS2, flags,
+ walk_state, &node);
+
+ if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "***New Node [%4.4s] %p is temporary\n",
+ acpi_ut_get_node_name(node), node));
+ }
+ break;
+ }
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR_NAMESPACE(buffer_ptr, status);
+ return_ACPI_STATUS(status);
+ }
+
+ if (!op) {
+
+ /* Create a new op */
+
+ op = acpi_ps_alloc_op(walk_state->opcode);
+ if (!op) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Initialize the new op */
+
+ if (node) {
+ op->named.name = node->name.integer;
+ }
+ *out_op = op;
+ }
+
+ /*
+ * Put the Node in the "op" object that the parser uses, so we
+ * can get it again quickly when this scope is closed
+ */
+ op->common.node = node;
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_load2_end_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback used during the loading of the namespace,
+ * both control methods and everything else.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
+{
+ union acpi_parse_object *op;
+ acpi_status status = AE_OK;
+ acpi_object_type object_type;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *arg;
+ struct acpi_namespace_node *new_node;
+#ifndef ACPI_NO_METHOD_EXECUTION
+ u32 i;
+ u8 region_space;
+#endif
+
+ ACPI_FUNCTION_TRACE(ds_load2_end_op);
+
+ op = walk_state->op;
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n",
+ walk_state->op_info->name, op, walk_state));
+
+ /* Check if opcode had an associated namespace object */
+
+ if (!(walk_state->op_info->flags & AML_NSOBJECT)) {
+#ifndef ACPI_NO_METHOD_EXECUTION
+#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
+ /* No namespace object. Executable opcode? */
+
+ if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
+ (walk_state->op_info->class == AML_CLASS_CONTROL)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "End/EXEC: %s (fl %8.8X)\n",
+ walk_state->op_info->name,
+ walk_state->op_info->flags));
+
+ /* Executing a type1 or type2 opcode outside of a method */
+
+ status = acpi_ds_exec_end_op(walk_state);
+ return_ACPI_STATUS(status);
+ }
+#endif
+#endif
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ if (op->common.aml_opcode == AML_SCOPE_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Ending scope Op=%p State=%p\n", op,
+ walk_state));
+ }
+
+ object_type = walk_state->op_info->object_type;
+
+ /*
+ * Get the Node/name from the earlier lookup
+ * (It was saved in the *op structure)
+ */
+ node = op->common.node;
+
+ /*
+ * Put the Node on the object stack (Contains the ACPI Name of
+ * this object)
+ */
+ walk_state->operands[0] = (void *)node;
+ walk_state->num_operands = 1;
+
+ /* Pop the scope stack */
+
+ if (acpi_ns_opens_scope(object_type) &&
+ (op->common.aml_opcode != AML_INT_METHODCALL_OP)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "(%s) Popping scope for Op %p\n",
+ acpi_ut_get_type_name(object_type), op));
+
+ status = acpi_ds_scope_stack_pop(walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Named operations are as follows:
+ *
+ * AML_ALIAS
+ * AML_BANKFIELD
+ * AML_CREATEBITFIELD
+ * AML_CREATEBYTEFIELD
+ * AML_CREATEDWORDFIELD
+ * AML_CREATEFIELD
+ * AML_CREATEQWORDFIELD
+ * AML_CREATEWORDFIELD
+ * AML_DATA_REGION
+ * AML_DEVICE
+ * AML_EVENT
+ * AML_FIELD
+ * AML_INDEXFIELD
+ * AML_METHOD
+ * AML_METHODCALL
+ * AML_MUTEX
+ * AML_NAME
+ * AML_NAMEDFIELD
+ * AML_OPREGION
+ * AML_POWERRES
+ * AML_PROCESSOR
+ * AML_SCOPE
+ * AML_THERMALZONE
+ */
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Create-Load [%s] State=%p Op=%p NamedObj=%p\n",
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ walk_state, op, node));
+
+ /* Decode the opcode */
+
+ arg = op->common.value.arg;
+
+ switch (walk_state->op_info->type) {
+#ifndef ACPI_NO_METHOD_EXECUTION
+
+ case AML_TYPE_CREATE_FIELD:
+ /*
+ * Create the field object, but the field buffer and index must
+ * be evaluated later during the execution phase
+ */
+ status = acpi_ds_create_buffer_field(op, walk_state);
+ break;
+
+ case AML_TYPE_NAMED_FIELD:
+ /*
+ * If we are executing a method, initialize the field
+ */
+ if (walk_state->method_node) {
+ status = acpi_ds_init_field_objects(op, walk_state);
+ }
+
+ switch (op->common.aml_opcode) {
+ case AML_INDEX_FIELD_OP:
+
+ status =
+ acpi_ds_create_index_field(op,
+ (acpi_handle) arg->
+ common.node, walk_state);
+ break;
+
+ case AML_BANK_FIELD_OP:
+
+ status =
+ acpi_ds_create_bank_field(op, arg->common.node,
+ walk_state);
+ break;
+
+ case AML_FIELD_OP:
+
+ status =
+ acpi_ds_create_field(op, arg->common.node,
+ walk_state);
+ break;
+
+ default:
+ /* All NAMED_FIELD opcodes must be handled above */
+ break;
+ }
+ break;
+
+ case AML_TYPE_NAMED_SIMPLE:
+
+ status = acpi_ds_create_operands(walk_state, arg);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ switch (op->common.aml_opcode) {
+ case AML_PROCESSOR_OP:
+
+ status = acpi_ex_create_processor(walk_state);
+ break;
+
+ case AML_POWER_RES_OP:
+
+ status = acpi_ex_create_power_resource(walk_state);
+ break;
+
+ case AML_MUTEX_OP:
+
+ status = acpi_ex_create_mutex(walk_state);
+ break;
+
+ case AML_EVENT_OP:
+
+ status = acpi_ex_create_event(walk_state);
+ break;
+
+ case AML_ALIAS_OP:
+
+ status = acpi_ex_create_alias(walk_state);
+ break;
+
+ default:
+ /* Unknown opcode */
+
+ status = AE_OK;
+ goto cleanup;
+ }
+
+ /* Delete operands */
+
+ for (i = 1; i < walk_state->num_operands; i++) {
+ acpi_ut_remove_reference(walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
+ }
+
+ break;
+#endif /* ACPI_NO_METHOD_EXECUTION */
+
+ case AML_TYPE_NAMED_COMPLEX:
+
+ switch (op->common.aml_opcode) {
+#ifndef ACPI_NO_METHOD_EXECUTION
+ case AML_REGION_OP:
+ case AML_DATA_REGION_OP:
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ region_space = (acpi_adr_space_type)
+ ((op->common.value.arg)->common.value.
+ integer);
+ } else {
+ region_space = REGION_DATA_TABLE;
+ }
+
+ /*
+ * If we are executing a method, initialize the region
+ */
+ if (walk_state->method_node) {
+ status =
+ acpi_ex_create_region(op->named.data,
+ op->named.length,
+ region_space,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+
+ /*
+ * The op_region is not fully parsed at this time. Only valid
+ * argument is the space_id. (We must save the address of the
+ * AML of the address and length operands)
+ */
+
+ /*
+ * If we have a valid region, initialize it
+ * Namespace is NOT locked at this point.
+ */
+ status =
+ acpi_ev_initialize_region
+ (acpi_ns_get_attached_object(node), FALSE);
+ if (ACPI_FAILURE(status)) {
+ /*
+ * If AE_NOT_EXIST is returned, it is not fatal
+ * because many regions get created before a handler
+ * is installed for said region.
+ */
+ if (AE_NOT_EXIST == status) {
+ status = AE_OK;
+ }
+ }
+ break;
+
+ case AML_NAME_OP:
+
+ status = acpi_ds_create_node(walk_state, node, op);
+ break;
+
+ case AML_METHOD_OP:
+ /*
+ * method_op pkg_length name_string method_flags term_list
+ *
+ * Note: We must create the method node/object pair as soon as we
+ * see the method declaration. This allows later pass1 parsing
+ * of invocations of the method (need to know the number of
+ * arguments.)
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "LOADING-Method: State=%p Op=%p NamedObj=%p\n",
+ walk_state, op, op->named.node));
+
+ if (!acpi_ns_get_attached_object(op->named.node)) {
+ walk_state->operands[0] =
+ ACPI_CAST_PTR(void, op->named.node);
+ walk_state->num_operands = 1;
+
+ status =
+ acpi_ds_create_operands(walk_state,
+ op->common.value.
+ arg);
+ if (ACPI_SUCCESS(status)) {
+ status =
+ acpi_ex_create_method(op->named.
+ data,
+ op->named.
+ length,
+ walk_state);
+ }
+ walk_state->operands[0] = NULL;
+ walk_state->num_operands = 0;
+
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+ break;
+
+#endif /* ACPI_NO_METHOD_EXECUTION */
+
+ default:
+ /* All NAMED_COMPLEX opcodes must be handled above */
+ break;
+ }
+ break;
+
+ case AML_CLASS_INTERNAL:
+
+ /* case AML_INT_NAMEPATH_OP: */
+ break;
+
+ case AML_CLASS_METHOD_CALL:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "RESOLVING-MethodCall: State=%p Op=%p NamedObj=%p\n",
+ walk_state, op, node));
+
+ /*
+ * Lookup the method name and save the Node
+ */
+ status =
+ acpi_ns_lookup(walk_state->scope_info,
+ arg->common.value.string, ACPI_TYPE_ANY,
+ ACPI_IMODE_LOAD_PASS2,
+ ACPI_NS_SEARCH_PARENT |
+ ACPI_NS_DONT_OPEN_SCOPE, walk_state,
+ &(new_node));
+ if (ACPI_SUCCESS(status)) {
+ /*
+ * Make sure that what we found is indeed a method
+ * We didn't search for a method on purpose, to see if the name
+ * would resolve
+ */
+ if (new_node->type != ACPI_TYPE_METHOD) {
+ status = AE_AML_OPERAND_TYPE;
+ }
+
+ /* We could put the returned object (Node) on the object stack for
+ * later, but for now, we will put it in the "op" object that the
+ * parser uses, so we can get it again at the end of this scope
+ */
+ op->common.node = new_node;
+ } else {
+ ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ cleanup:
+
+ /* Remove the Node pushed at the very beginning */
+
+ walk_state->operands[0] = NULL;
+ walk_state->num_operands = 0;
+ return_ACPI_STATUS(status);
+}
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
new file mode 100644
index 0000000..9e60732
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -0,0 +1,213 @@
+/******************************************************************************
+ *
+ * Module Name: dswscope - Scope stack manipulation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acdispat.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dswscope")
+
+/****************************************************************************
+ *
+ * FUNCTION: acpi_ds_scope_stack_clear
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Pop (and free) everything on the scope stack except the
+ * root scope object (which remains at the stack top.)
+ *
+ ***************************************************************************/
+void acpi_ds_scope_stack_clear(struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *scope_info;
+
+ ACPI_FUNCTION_NAME(ds_scope_stack_clear);
+
+ while (walk_state->scope_info) {
+
+ /* Pop a scope off the stack */
+
+ scope_info = walk_state->scope_info;
+ walk_state->scope_info = scope_info->scope.next;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Popped object type (%s)\n",
+ acpi_ut_get_type_name(scope_info->common.
+ value)));
+ acpi_ut_delete_generic_state(scope_info);
+ }
+}
+
+/****************************************************************************
+ *
+ * FUNCTION: acpi_ds_scope_stack_push
+ *
+ * PARAMETERS: Node - Name to be made current
+ * Type - Type of frame being pushed
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push the current scope on the scope stack, and make the
+ * passed Node current.
+ *
+ ***************************************************************************/
+
+acpi_status
+acpi_ds_scope_stack_push(struct acpi_namespace_node *node,
+ acpi_object_type type,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *scope_info;
+ union acpi_generic_state *old_scope_info;
+
+ ACPI_FUNCTION_TRACE(ds_scope_stack_push);
+
+ if (!node) {
+
+ /* Invalid scope */
+
+ ACPI_ERROR((AE_INFO, "Null scope parameter"));
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Make sure object type is valid */
+
+ if (!acpi_ut_valid_object_type(type)) {
+ ACPI_WARNING((AE_INFO, "Invalid object type: 0x%X", type));
+ }
+
+ /* Allocate a new scope object */
+
+ scope_info = acpi_ut_create_generic_state();
+ if (!scope_info) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Init new scope object */
+
+ scope_info->common.descriptor_type = ACPI_DESC_TYPE_STATE_WSCOPE;
+ scope_info->scope.node = node;
+ scope_info->common.value = (u16) type;
+
+ walk_state->scope_depth++;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "[%.2d] Pushed scope ",
+ (u32) walk_state->scope_depth));
+
+ old_scope_info = walk_state->scope_info;
+ if (old_scope_info) {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC,
+ "[%4.4s] (%s)",
+ acpi_ut_get_node_name(old_scope_info->
+ scope.node),
+ acpi_ut_get_type_name(old_scope_info->
+ common.value)));
+ } else {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[\\___] (%s)", "ROOT"));
+ }
+
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC,
+ ", New scope -> [%4.4s] (%s)\n",
+ acpi_ut_get_node_name(scope_info->scope.node),
+ acpi_ut_get_type_name(scope_info->common.value)));
+
+ /* Push new scope object onto stack */
+
+ acpi_ut_push_generic_state(&walk_state->scope_info, scope_info);
+ return_ACPI_STATUS(AE_OK);
+}
+
+/****************************************************************************
+ *
+ * FUNCTION: acpi_ds_scope_stack_pop
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop the scope stack once.
+ *
+ ***************************************************************************/
+
+acpi_status acpi_ds_scope_stack_pop(struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *scope_info;
+ union acpi_generic_state *new_scope_info;
+
+ ACPI_FUNCTION_TRACE(ds_scope_stack_pop);
+
+ /*
+ * Pop scope info object off the stack.
+ */
+ scope_info = acpi_ut_pop_generic_state(&walk_state->scope_info);
+ if (!scope_info) {
+ return_ACPI_STATUS(AE_STACK_UNDERFLOW);
+ }
+
+ walk_state->scope_depth--;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "[%.2d] Popped scope [%4.4s] (%s), New scope -> ",
+ (u32) walk_state->scope_depth,
+ acpi_ut_get_node_name(scope_info->scope.node),
+ acpi_ut_get_type_name(scope_info->common.value)));
+
+ new_scope_info = walk_state->scope_info;
+ if (new_scope_info) {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC,
+ "[%4.4s] (%s)\n",
+ acpi_ut_get_node_name(new_scope_info->
+ scope.node),
+ acpi_ut_get_type_name(new_scope_info->
+ common.value)));
+ } else {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_EXEC, "[\\___] (ROOT)\n"));
+ }
+
+ acpi_ut_delete_generic_state(scope_info);
+ return_ACPI_STATUS(AE_OK);
+}
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
new file mode 100644
index 0000000..b00d4af
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -0,0 +1,752 @@
+/******************************************************************************
+ *
+ * Module Name: dswstate - Dispatcher parse tree walk management routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2008, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acparser.h>
+#include <acpi/acdispat.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ACPI_MODULE_NAME("dswstate")
+
+ /* Local prototypes */
+static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *ws);
+static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *ws);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_pop
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop an object off the top of this walk's result stack
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_pop(union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state)
+{
+ u32 index;
+ union acpi_generic_state *state;
+ acpi_status status;
+
+ ACPI_FUNCTION_NAME(ds_result_pop);
+
+ state = walk_state->results;
+
+ /* Incorrect state of result stack */
+
+ if (state && !walk_state->result_count) {
+ ACPI_ERROR((AE_INFO, "No results on result stack"));
+ return (AE_AML_INTERNAL);
+ }
+
+ if (!state && walk_state->result_count) {
+ ACPI_ERROR((AE_INFO, "No result state for result stack"));
+ return (AE_AML_INTERNAL);
+ }
+
+ /* Empty result stack */
+
+ if (!state) {
+ ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p",
+ walk_state));
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+ /* Return object of the top element and clean that top element result stack */
+
+ walk_state->result_count--;
+ index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+
+ *object = state->results.obj_desc[index];
+ if (!*object) {
+ ACPI_ERROR((AE_INFO,
+ "No result objects on result stack, State=%p",
+ walk_state));
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+ state->results.obj_desc[index] = NULL;
+ if (index == 0) {
+ status = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Obj=%p [%s] Index=%X State=%p Num=%X\n", *object,
+ acpi_ut_get_object_type_name(*object),
+ index, walk_state, walk_state->result_count));
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_push
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push an object onto the current result stack
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_push(union acpi_operand_object * object,
+ struct acpi_walk_state * walk_state)
+{
+ union acpi_generic_state *state;
+ acpi_status status;
+ u32 index;
+
+ ACPI_FUNCTION_NAME(ds_result_push);
+
+ if (walk_state->result_count > walk_state->result_size) {
+ ACPI_ERROR((AE_INFO, "Result stack is full"));
+ return (AE_AML_INTERNAL);
+ } else if (walk_state->result_count == walk_state->result_size) {
+
+ /* Extend the result stack */
+
+ status = acpi_ds_result_stack_push(walk_state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Failed to extend the result stack"));
+ return (status);
+ }
+ }
+
+ if (!(walk_state->result_count < walk_state->result_size)) {
+ ACPI_ERROR((AE_INFO, "No free elements in result stack"));
+ return (AE_AML_INTERNAL);
+ }
+
+ state = walk_state->results;
+ if (!state) {
+ ACPI_ERROR((AE_INFO, "No result stack frame during push"));
+ return (AE_AML_INTERNAL);
+ }
+
+ if (!object) {
+ ACPI_ERROR((AE_INFO,
+ "Null Object! Obj=%p State=%p Num=%X",
+ object, walk_state, walk_state->result_count));
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Assign the address of object to the top free element of result stack */
+
+ index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+ state->results.obj_desc[index] = object;
+ walk_state->result_count++;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
+ object,
+ acpi_ut_get_object_type_name((union
+ acpi_operand_object *)
+ object), walk_state,
+ walk_state->result_count,
+ walk_state->current_result));
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_stack_push
+ *
+ * PARAMETERS: walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push an object onto the walk_state result stack
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+ ACPI_FUNCTION_NAME(ds_result_stack_push);
+
+ /* Check for stack overflow */
+
+ if (((u32) walk_state->result_size + ACPI_RESULTS_FRAME_OBJ_NUM) >
+ ACPI_RESULTS_OBJ_NUM_MAX) {
+ ACPI_ERROR((AE_INFO, "Result stack overflow: State=%p Num=%X",
+ walk_state, walk_state->result_size));
+ return (AE_STACK_OVERFLOW);
+ }
+
+ state = acpi_ut_create_generic_state();
+ if (!state) {
+ return (AE_NO_MEMORY);
+ }
+
+ state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT;
+ acpi_ut_push_generic_state(&walk_state->results, state);
+
+ /* Increase the length of the result stack by the length of frame */
+
+ walk_state->result_size += ACPI_RESULTS_FRAME_OBJ_NUM;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n",
+ state, walk_state));
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_stack_pop
+ *
+ * PARAMETERS: walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop an object off of the walk_state result stack
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+ ACPI_FUNCTION_NAME(ds_result_stack_pop);
+
+ /* Check for stack underflow */
+
+ if (walk_state->results == NULL) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Result stack underflow - State=%p\n",
+ walk_state));
+ return (AE_AML_NO_OPERAND);
+ }
+
+ if (walk_state->result_size < ACPI_RESULTS_FRAME_OBJ_NUM) {
+ ACPI_ERROR((AE_INFO, "Insufficient result stack size"));
+ return (AE_AML_INTERNAL);
+ }
+
+ state = acpi_ut_pop_generic_state(&walk_state->results);
+ acpi_ut_delete_generic_state(state);
+
+ /* Decrease the length of result stack by the length of frame */
+
+ walk_state->result_size -= ACPI_RESULTS_FRAME_OBJ_NUM;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Result=%p RemainingResults=%X State=%p\n",
+ state, walk_state->result_count, walk_state));
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_push
+ *
+ * PARAMETERS: Object - Object to push
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push an object onto this walk's object/operand stack
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_obj_stack_push(void *object, struct acpi_walk_state * walk_state)
+{
+ ACPI_FUNCTION_NAME(ds_obj_stack_push);
+
+ /* Check for stack overflow */
+
+ if (walk_state->num_operands >= ACPI_OBJ_NUM_OPERANDS) {
+ ACPI_ERROR((AE_INFO,
+ "Object stack overflow! Obj=%p State=%p #Ops=%X",
+ object, walk_state, walk_state->num_operands));
+ return (AE_STACK_OVERFLOW);
+ }
+
+ /* Put the object onto the stack */
+
+ walk_state->operands[walk_state->operand_index] = object;
+ walk_state->num_operands++;
+
+ /* For the usual order of filling the operand stack */
+
+ walk_state->operand_index++;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
+ object,
+ acpi_ut_get_object_type_name((union
+ acpi_operand_object *)
+ object), walk_state,
+ walk_state->num_operands));
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_pop
+ *
+ * PARAMETERS: pop_count - Number of objects/entries to pop
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
+ * deleted by this routine.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state * walk_state)
+{
+ u32 i;
+
+ ACPI_FUNCTION_NAME(ds_obj_stack_pop);
+
+ for (i = 0; i < pop_count; i++) {
+
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ ACPI_ERROR((AE_INFO,
+ "Object stack underflow! Count=%X State=%p #Ops=%X",
+ pop_count, walk_state,
+ walk_state->num_operands));
+ return (AE_STACK_UNDERFLOW);
+ }
+
+ /* Just set the stack entry to null */
+
+ walk_state->num_operands--;
+ walk_state->operands[walk_state->num_operands] = NULL;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n",
+ pop_count, walk_state, walk_state->num_operands));
+
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_pop_and_delete
+ *
+ * PARAMETERS: pop_count - Number of objects/entries to pop
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop this walk's object stack and delete each object that is
+ * popped off.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
+ struct acpi_walk_state *walk_state)
+{
+ s32 i;
+ union acpi_operand_object *obj_desc;
+
+ ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete);
+
+ if (pop_count == 0) {
+ return;
+ }
+
+ for (i = (s32) pop_count - 1; i >= 0; i--) {
+ if (walk_state->num_operands == 0) {
+ return;
+ }
+
+ /* Pop the stack and delete an object if present in this stack entry */
+
+ walk_state->num_operands--;
+ obj_desc = walk_state->operands[i];
+ if (obj_desc) {
+ acpi_ut_remove_reference(walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
+ }
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n",
+ pop_count, walk_state, walk_state->num_operands));
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_current_walk_state
+ *
+ * PARAMETERS: Thread - Get current active state for this Thread
+ *
+ * RETURN: Pointer to the current walk state
+ *
+ * DESCRIPTION: Get the walk state that is at the head of the list (the "current"
+ * walk state.)
+ *
+ ******************************************************************************/
+
+struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state
+ *thread)
+{
+ ACPI_FUNCTION_NAME(ds_get_current_walk_state);
+
+ if (!thread) {
+ return (NULL);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Current WalkState %p\n",
+ thread->walk_state_list));
+
+ return (thread->walk_state_list);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_push_walk_state
+ *
+ * PARAMETERS: walk_state - State to push
+ * Thread - Thread state object
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Place the Thread state at the head of the state list
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_push_walk_state(struct acpi_walk_state *walk_state,
+ struct acpi_thread_state *thread)
+{
+ ACPI_FUNCTION_TRACE(ds_push_walk_state);
+
+ walk_state->next = thread->walk_state_list;
+ thread->walk_state_list = walk_state;
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_pop_walk_state
+ *
+ * PARAMETERS: Thread - Current thread state
+ *
+ * RETURN: A walk_state object popped from the thread's stack
+ *
+ * DESCRIPTION: Remove and return the walkstate object that is at the head of
+ * the walk stack for the given walk list. NULL indicates that
+ * the list is empty.
+ *
+ ******************************************************************************/
+
+struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread)
+{
+ struct acpi_walk_state *walk_state;
+
+ ACPI_FUNCTION_TRACE(ds_pop_walk_state);
+
+ walk_state = thread->walk_state_list;
+
+ if (walk_state) {
+
+ /* Next walk state becomes the current walk state */
+
+ thread->walk_state_list = walk_state->next;
+
+ /*
+ * Don't clear the NEXT field, this serves as an indicator
+ * that there is a parent WALK STATE
+ * Do Not: walk_state->Next = NULL;
+ */
+ }
+
+ return_PTR(walk_state);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_walk_state
+ *
+ * PARAMETERS: owner_id - ID for object creation
+ * Origin - Starting point for this walk
+ * method_desc - Method object
+ * Thread - Current thread state
+ *
+ * RETURN: Pointer to the new walk state.
+ *
+ * DESCRIPTION: Allocate and initialize a new walk state. The current walk
+ * state is set to this new state.
+ *
+ ******************************************************************************/
+
+struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object
+ *origin, union acpi_operand_object
+ *method_desc, struct acpi_thread_state
+ *thread)
+{
+ struct acpi_walk_state *walk_state;
+
+ ACPI_FUNCTION_TRACE(ds_create_walk_state);
+
+ walk_state = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_walk_state));
+ if (!walk_state) {
+ return_PTR(NULL);
+ }
+
+ walk_state->descriptor_type = ACPI_DESC_TYPE_WALK;
+ walk_state->method_desc = method_desc;
+ walk_state->owner_id = owner_id;
+ walk_state->origin = origin;
+ walk_state->thread = thread;
+
+ walk_state->parser_state.start_op = origin;
+
+ /* Init the method args/local */
+
+#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+ acpi_ds_method_data_init(walk_state);
+#endif
+
+ /* Put the new state at the head of the walk list */
+
+ if (thread) {
+ acpi_ds_push_walk_state(walk_state, thread);
+ }
+
+ return_PTR(walk_state);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_aml_walk
+ *
+ * PARAMETERS: walk_state - New state to be initialized
+ * Op - Current parse op
+ * method_node - Control method NS node, if any
+ * aml_start - Start of AML
+ * aml_length - Length of AML
+ * Info - Method info block (params, etc.)
+ * pass_number - 1, 2, or 3
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ struct acpi_namespace_node *method_node,
+ u8 * aml_start,
+ u32 aml_length,
+ struct acpi_evaluate_info *info, u8 pass_number)
+{
+ acpi_status status;
+ struct acpi_parse_state *parser_state = &walk_state->parser_state;
+ union acpi_parse_object *extra_op;
+
+ ACPI_FUNCTION_TRACE(ds_init_aml_walk);
+
+ walk_state->parser_state.aml =
+ walk_state->parser_state.aml_start = aml_start;
+ walk_state->parser_state.aml_end =
+ walk_state->parser_state.pkg_end = aml_start + aml_length;
+
+ /* The next_op of the next_walk will be the beginning of the method */
+
+ walk_state->next_op = NULL;
+ walk_state->pass_number = pass_number;
+
+ if (info) {
+ walk_state->params = info->parameters;
+ walk_state->caller_return_desc = &info->return_object;
+ }
+
+ status = acpi_ps_init_scope(&walk_state->parser_state, op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (method_node) {
+ walk_state->parser_state.start_node = method_node;
+ walk_state->walk_type = ACPI_WALK_METHOD;
+ walk_state->method_node = method_node;
+ walk_state->method_desc =
+ acpi_ns_get_attached_object(method_node);
+
+ /* Push start scope on scope stack and make it current */
+
+ status =
+ acpi_ds_scope_stack_push(method_node, ACPI_TYPE_METHOD,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Init the method arguments */
+
+ status = acpi_ds_method_data_init_args(walk_state->params,
+ ACPI_METHOD_NUM_ARGS,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ } else {
+ /*
+ * Setup the current scope.
+ * Find a Named Op that has a namespace node associated with it.
+ * search upwards from this Op. Current scope is the first
+ * Op with a namespace node.
+ */
+ extra_op = parser_state->start_op;
+ while (extra_op && !extra_op->common.node) {
+ extra_op = extra_op->common.parent;
+ }
+
+ if (!extra_op) {
+ parser_state->start_node = NULL;
+ } else {
+ parser_state->start_node = extra_op->common.node;
+ }
+
+ if (parser_state->start_node) {
+
+ /* Push start scope on scope stack and make it current */
+
+ status =
+ acpi_ds_scope_stack_push(parser_state->start_node,
+ parser_state->start_node->
+ type, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+ }
+ }
+
+ status = acpi_ds_init_callbacks(walk_state, pass_number);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_delete_walk_state
+ *
+ * PARAMETERS: walk_state - State to delete
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete a walk state including all internal data structures
+ *
+ ******************************************************************************/
+
+void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_delete_walk_state, walk_state);
+
+ if (!walk_state) {
+ return;
+ }
+
+ if (walk_state->descriptor_type != ACPI_DESC_TYPE_WALK) {
+ ACPI_ERROR((AE_INFO, "%p is not a valid walk state",
+ walk_state));
+ return;
+ }
+
+ /* There should not be any open scopes */
+
+ if (walk_state->parser_state.scope) {
+ ACPI_ERROR((AE_INFO, "%p walk still has a scope list",
+ walk_state));
+ acpi_ps_cleanup_scope(&walk_state->parser_state);
+ }
+
+ /* Always must free any linked control states */
+
+ while (walk_state->control_state) {
+ state = walk_state->control_state;
+ walk_state->control_state = state->common.next;
+
+ acpi_ut_delete_generic_state(state);
+ }
+
+ /* Always must free any linked parse states */
+
+ while (walk_state->scope_info) {
+ state = walk_state->scope_info;
+ walk_state->scope_info = state->common.next;
+
+ acpi_ut_delete_generic_state(state);
+ }
+
+ /* Always must free any stacked result states */
+
+ while (walk_state->results) {
+ state = walk_state->results;
+ walk_state->results = state->common.next;
+
+ acpi_ut_delete_generic_state(state);
+ }
+
+ ACPI_FREE(walk_state);
+ return_VOID;
+}
OpenPOWER on IntegriCloud