Started on ISA PnP bus driver.
svn path=/trunk/; revision=1850
--- /dev/null
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+ PRODUCTVERSION RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", RES_STR_COMPANY_NAME
+ VALUE "FileDescription", "ReactOS ACPI Driver\0"
+ VALUE "FileVersion", RES_STR_FILE_VERSION
+ VALUE "InternalName", "acpi\0"
+ VALUE "LegalCopyright", RES_STR_LEGAL_COPYRIGHT
+ VALUE "OriginalFilename", "acpi.sys\0"
+ VALUE "ProductName", RES_STR_PRODUCT_NAME
+ VALUE "ProductVersion", RES_STR_PRODUCT_VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
--- /dev/null
+Changes to ACPI CA
+------------------
+
++ = Added
+- = Removed
+* = Altered
+
++ include/platform/acwin.h
++ include/platform/types.h
+- ospm/*
\ No newline at end of file
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: dsfield - Dispatcher field routines
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dsfield")
+
+
+/*
+ * Field flags: Bits 00 - 03 : Access_type (Any_acc, Byte_acc, etc.)
+ * 04 : Lock_rule (1 == Lock)
+ * 05 - 06 : Update_rule
+ */
+
+#define FIELD_ACCESS_TYPE_MASK 0x0F
+#define FIELD_LOCK_RULE_MASK 0x10
+#define FIELD_UPDATE_RULE_MASK 0x60
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * Region_node - Object for the containing Operation Region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new field in the specified operation region
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_field (
+ ACPI_PARSE_OBJECT *op,
+ ACPI_NAMESPACE_NODE *region_node,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status = AE_AML_ERROR;
+ ACPI_PARSE_OBJECT *arg;
+ ACPI_NAMESPACE_NODE *node;
+ u8 field_flags;
+ u8 access_attribute = 0;
+ u32 field_bit_position = 0;
+
+
+ /* First arg is the name of the parent Op_region */
+
+ arg = op->value.arg;
+ if (!region_node) {
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.name,
+ ACPI_TYPE_REGION, IMODE_EXECUTE,
+ NS_SEARCH_PARENT, walk_state,
+ ®ion_node);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ /* Second arg is the field flags */
+
+ arg = arg->next;
+ field_flags = (u8) arg->value.integer;
+
+ /* Each remaining arg is a Named Field */
+
+ arg = arg->next;
+ while (arg) {
+ switch (arg->opcode) {
+ case AML_RESERVEDFIELD_OP:
+
+ field_bit_position += arg->value.size;
+ break;
+
+
+ case AML_ACCESSFIELD_OP:
+
+ /*
+ * Get a new Access_type and Access_attribute for all
+ * entries (until end or another Access_as keyword)
+ */
+
+ access_attribute = (u8) arg->value.integer;
+ field_flags = (u8)
+ ((field_flags & FIELD_ACCESS_TYPE_MASK) ||
+ ((u8) (arg->value.integer >> 8)));
+ break;
+
+
+ case AML_NAMEDFIELD_OP:
+
+ status = acpi_ns_lookup (walk_state->scope_info,
+ (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name,
+ INTERNAL_TYPE_DEF_FIELD,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &node);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Initialize an object for the new Node that is on
+ * the object stack
+ */
+
+ status = acpi_aml_prep_def_field_value (node, region_node, field_flags,
+ access_attribute, field_bit_position, arg->value.size);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Keep track of bit position for *next* field */
+
+ field_bit_position += arg->value.size;
+ break;
+ }
+
+ arg = arg->next;
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_bank_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * Region_node - Object for the containing Operation Region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new bank field in the specified operation region
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_bank_field (
+ ACPI_PARSE_OBJECT *op,
+ ACPI_NAMESPACE_NODE *region_node,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status = AE_AML_ERROR;
+ ACPI_PARSE_OBJECT *arg;
+ ACPI_NAMESPACE_NODE *register_node;
+ ACPI_NAMESPACE_NODE *node;
+ u32 bank_value;
+ u8 field_flags;
+ u8 access_attribute = 0;
+ u32 field_bit_position = 0;
+
+
+ /* First arg is the name of the parent Op_region */
+
+ arg = op->value.arg;
+ if (!region_node) {
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.name,
+ ACPI_TYPE_REGION, IMODE_EXECUTE,
+ NS_SEARCH_PARENT, walk_state,
+ ®ion_node);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ /* Second arg is the Bank Register */
+
+ arg = arg->next;
+
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string,
+ INTERNAL_TYPE_BANK_FIELD_DEFN,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, ®ister_node);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Third arg is the Bank_value */
+
+ arg = arg->next;
+ bank_value = arg->value.integer;
+
+
+ /* Next arg is the field flags */
+
+ arg = arg->next;
+ field_flags = (u8) arg->value.integer;
+
+ /* Each remaining arg is a Named Field */
+
+ arg = arg->next;
+ while (arg) {
+ switch (arg->opcode) {
+ case AML_RESERVEDFIELD_OP:
+
+ field_bit_position += arg->value.size;
+ break;
+
+
+ case AML_ACCESSFIELD_OP:
+
+ /*
+ * Get a new Access_type and Access_attribute for
+ * all entries (until end or another Access_as keyword)
+ */
+
+ access_attribute = (u8) arg->value.integer;
+ field_flags = (u8)
+ ((field_flags & FIELD_ACCESS_TYPE_MASK) ||
+ ((u8) (arg->value.integer >> 8)));
+ break;
+
+
+ case AML_NAMEDFIELD_OP:
+
+ status = acpi_ns_lookup (walk_state->scope_info,
+ (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name,
+ INTERNAL_TYPE_DEF_FIELD,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &node);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Initialize an object for the new Node that is on
+ * the object stack
+ */
+
+ status = acpi_aml_prep_bank_field_value (node, region_node, register_node,
+ bank_value, field_flags, access_attribute,
+ field_bit_position, arg->value.size);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Keep track of bit position for the *next* field */
+
+ field_bit_position += arg->value.size;
+ break;
+
+ }
+
+ arg = arg->next;
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_index_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * Region_node - Object for the containing Operation Region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new index field in the specified operation region
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_index_field (
+ ACPI_PARSE_OBJECT *op,
+ ACPI_HANDLE region_node,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_PARSE_OBJECT *arg;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_NAMESPACE_NODE *index_register_node;
+ ACPI_NAMESPACE_NODE *data_register_node;
+ u8 field_flags;
+ u8 access_attribute = 0;
+ u32 field_bit_position = 0;
+
+
+ arg = op->value.arg;
+
+ /* First arg is the name of the Index register */
+
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string,
+ ACPI_TYPE_ANY, IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &index_register_node);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Second arg is the data register */
+
+ arg = arg->next;
+
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string,
+ INTERNAL_TYPE_INDEX_FIELD_DEFN,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &data_register_node);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+ /* Next arg is the field flags */
+
+ arg = arg->next;
+ field_flags = (u8) arg->value.integer;
+
+
+ /* Each remaining arg is a Named Field */
+
+ arg = arg->next;
+ while (arg) {
+ switch (arg->opcode) {
+ case AML_RESERVEDFIELD_OP:
+
+ field_bit_position += arg->value.size;
+ break;
+
+
+ case AML_ACCESSFIELD_OP:
+
+ /*
+ * Get a new Access_type and Access_attribute for all
+ * entries (until end or another Access_as keyword)
+ */
+
+ access_attribute = (u8) arg->value.integer;
+ field_flags = (u8)
+ ((field_flags & FIELD_ACCESS_TYPE_MASK) ||
+ ((u8) (arg->value.integer >> 8)));
+ break;
+
+
+ case AML_NAMEDFIELD_OP:
+
+ status = acpi_ns_lookup (walk_state->scope_info,
+ (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)arg)->name,
+ INTERNAL_TYPE_INDEX_FIELD,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ NULL, &node);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Initialize an object for the new Node that is on
+ * the object stack
+ */
+
+ status = acpi_aml_prep_index_field_value (node, index_register_node, data_register_node,
+ field_flags, access_attribute,
+ field_bit_position, arg->value.size);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Keep track of bit position for the *next* field */
+
+ field_bit_position += arg->value.size;
+ break;
+
+
+ default:
+
+ status = AE_AML_ERROR;
+ break;
+ }
+
+ arg = arg->next;
+ }
+
+ return (status);
+}
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "actables.h"
+#include "acdebug.h"
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dsmethod")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_parse_method
+ *
+ * PARAMETERS: Obj_handle - Node of the method
+ * Level - Current nesting level
+ * Context - Points to a method counter
+ * Return_value - Not used
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Call the parser and parse the AML that is
+ * associated with the method.
+ *
+ * MUTEX: Assumes parser is locked
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_parse_method (
+ ACPI_HANDLE obj_handle)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_PARSE_OBJECT *op;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_OWNER_ID owner_id;
+
+
+ /* Parameter Validation */
+
+ if (!obj_handle) {
+ return (AE_NULL_ENTRY);
+ }
+
+
+ /* Extract the method object from the method Node */
+
+ node = (ACPI_NAMESPACE_NODE *) obj_handle;
+ obj_desc = node->object;
+ if (!obj_desc) {
+ return (AE_NULL_OBJECT);
+ }
+
+ /* Create a mutex for the method if there is a concurrency limit */
+
+ if ((obj_desc->method.concurrency != INFINITE_CONCURRENCY) &&
+ (!obj_desc->method.semaphore)) {
+ status = acpi_os_create_semaphore (obj_desc->method.concurrency,
+ obj_desc->method.concurrency,
+ &obj_desc->method.semaphore);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ /*
+ * Allocate a new parser op to be the root of the parsed
+ * method tree
+ */
+ op = acpi_ps_alloc_op (AML_METHOD_OP);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Init new op with the method name and pointer back to the Node */
+
+ acpi_ps_set_name (op, node->name);
+ op->node = node;
+
+
+ /*
+ * Parse the method, first pass
+ *
+ * The first pass load is
+ * where newly declared named objects are
+ * added into the namespace. Actual evaluation of
+ * the named objects (what would be called a "second
+ * pass") happens during the actual execution of the
+ * method so that operands to the named objects can
+ * take on dynamic run-time values.
+ */
+ status = acpi_ps_parse_aml (op, obj_desc->method.pcode,
+ obj_desc->method.pcode_length,
+ ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE,
+ node, NULL, NULL,
+ acpi_ds_load1_begin_op, acpi_ds_load1_end_op);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Get a new Owner_id for objects created by this method */
+
+ owner_id = acpi_cm_allocate_owner_id (OWNER_TYPE_METHOD);
+ obj_desc->method.owning_id = owner_id;
+
+ /* Install the parsed tree in the method object */
+ /* TBD: [Restructure] Obsolete field? */
+
+ acpi_ps_delete_parse_tree (op);
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_begin_method_execution
+ *
+ * PARAMETERS: Method_node - Node of the method
+ * Obj_desc - The method object
+ * Calling_method_node - Caller of this method (if non-null)
+ *
+ * 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.
+ *
+ * MUTEX: Locks/unlocks parser.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_begin_method_execution (
+ ACPI_NAMESPACE_NODE *method_node,
+ ACPI_OPERAND_OBJECT *obj_desc,
+ ACPI_NAMESPACE_NODE *calling_method_node)
+{
+ ACPI_STATUS status = AE_OK;
+
+
+ if (!method_node) {
+ return (AE_NULL_ENTRY);
+ }
+
+
+ /*
+ * If there is a concurrency limit on this method, we need to
+ * obtain a unit from the method semaphore.
+ */
+ if (obj_desc->method.semaphore) {
+ /*
+ * Allow recursive method calls, up to the reentrancy/concurrency
+ * limit imposed by the SERIALIZED rule and the Sync_level method
+ * parameter.
+ *
+ * The point of this code is to avoid permanently blocking a
+ * thread that is making recursive method calls.
+ */
+ if (method_node == calling_method_node) {
+ if (obj_desc->method.thread_count >= obj_desc->method.concurrency) {
+ return (AE_AML_METHOD_LIMIT);
+ }
+ }
+
+ /*
+ * Get a unit from the method semaphore. This releases the
+ * interpreter if we block
+ */
+ status = acpi_aml_system_wait_semaphore (obj_desc->method.semaphore,
+ WAIT_FOREVER);
+ }
+
+
+ /*
+ * 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 (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_call_control_method
+ *
+ * PARAMETERS: Walk_state - Current state of the walk
+ * Op - Current Op to be walked
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Transfer execution to a called control method
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_call_control_method (
+ ACPI_WALK_LIST *walk_list,
+ ACPI_WALK_STATE *this_walk_state,
+ ACPI_PARSE_OBJECT *op)
+{
+ ACPI_STATUS status;
+ ACPI_NAMESPACE_NODE *method_node;
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_WALK_STATE *next_walk_state;
+ ACPI_PARSE_STATE *parser_state;
+ u32 i;
+
+
+ /*
+ * 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 (AE_NULL_ENTRY);
+ }
+
+ obj_desc = acpi_ns_get_attached_object (method_node);
+ if (!obj_desc) {
+ return (AE_NULL_OBJECT);
+ }
+
+
+ /* Init for new method, wait on concurrency semaphore */
+
+ status = acpi_ds_begin_method_execution (method_node, obj_desc,
+ this_walk_state->method_node);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Create and initialize a new parser state */
+
+ parser_state = acpi_ps_create_state (obj_desc->method.pcode,
+ obj_desc->method.pcode_length);
+ if (!parser_state) {
+ return (AE_NO_MEMORY);
+ }
+
+ acpi_ps_init_scope (parser_state, NULL);
+ parser_state->start_node = method_node;
+
+
+ /* Create a new state for the preempting walk */
+
+ next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
+ NULL, obj_desc, walk_list);
+ if (!next_walk_state) {
+ /* TBD: delete parser state */
+
+ return (AE_NO_MEMORY);
+ }
+
+ next_walk_state->walk_type = WALK_METHOD;
+ next_walk_state->method_node = method_node;
+ next_walk_state->parser_state = parser_state;
+ next_walk_state->parse_flags = this_walk_state->parse_flags;
+ next_walk_state->descending_callback = this_walk_state->descending_callback;
+ next_walk_state->ascending_callback = this_walk_state->ascending_callback;
+
+ /* The Next_op of the Next_walk will be the beginning of the method */
+ /* TBD: [Restructure] -- obsolete? */
+
+ next_walk_state->next_op = NULL;
+
+ /* Open a new scope */
+
+ status = acpi_ds_scope_stack_push (method_node,
+ ACPI_TYPE_METHOD, next_walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+
+ /*
+ * Initialize the arguments for the method. 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.
+ */
+ status = acpi_ds_method_data_init_args (&this_walk_state->operands[0],
+ this_walk_state->num_operands,
+ next_walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+
+ /* Create and init a Root Node */
+
+ op = acpi_ps_alloc_op (AML_SCOPE_OP);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ status = acpi_ps_parse_aml (op, obj_desc->method.pcode,
+ obj_desc->method.pcode_length,
+ ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE,
+ method_node, NULL, NULL,
+ acpi_ds_load1_begin_op, acpi_ds_load1_end_op);
+ acpi_ps_delete_parse_tree (op);
+
+
+ /*
+ * 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_cm_remove_reference (this_walk_state->operands [i]);
+ this_walk_state->operands [i] = NULL;
+ }
+
+ /* Clear the operand stack */
+
+ this_walk_state->num_operands = 0;
+
+
+ return (AE_OK);
+
+
+ /* On error, we must delete the new walk state */
+
+cleanup:
+ acpi_ds_terminate_control_method (next_walk_state);
+ acpi_ds_delete_walk_state (next_walk_state);
+ return (status);
+
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_restart_control_method
+ *
+ * PARAMETERS: Walk_state - State of the method when it was preempted
+ * Op - Pointer to new current op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Restart a method that was preempted
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_restart_control_method (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OPERAND_OBJECT *return_desc)
+{
+ ACPI_STATUS status;
+
+
+ if (return_desc) {
+ if (walk_state->return_used) {
+ /*
+ * Get the return value (if any) from the previous method.
+ * NULL if no return value
+ */
+ status = acpi_ds_result_push (return_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (return_desc);
+ return (status);
+ }
+ }
+
+ else {
+ /*
+ * Delete the return value if it will not be used by the
+ * calling method
+ */
+ acpi_cm_remove_reference (return_desc);
+ }
+
+ }
+
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_terminate_control_method
+ *
+ * PARAMETERS: Walk_state - State of the method
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Terminate a control method. Delete everything that the method
+ * created, delete all locals and arguments, and delete the parse
+ * tree if requested.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_terminate_control_method (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_NAMESPACE_NODE *method_node;
+
+
+ /* The method object should be stored in the walk state */
+
+ obj_desc = walk_state->method_desc;
+ if (!obj_desc) {
+ return (AE_OK);
+ }
+
+ /* Delete all arguments and locals */
+
+ acpi_ds_method_data_delete_all (walk_state);
+
+ /*
+ * Lock the parser while we terminate this method.
+ * If this is the last thread executing the method,
+ * we have additional cleanup to perform
+ */
+ acpi_cm_acquire_mutex (ACPI_MTX_PARSER);
+
+
+ /* Signal completion of the execution of this method if necessary */
+
+ if (walk_state->method_desc->method.semaphore) {
+ status = acpi_os_signal_semaphore (
+ walk_state->method_desc->method.semaphore, 1);
+ }
+
+ /* Decrement the thread count on the method parse tree */
+
+ walk_state->method_desc->method.thread_count--;
+ if (!walk_state->method_desc->method.thread_count) {
+ /*
+ * There are no more threads executing this method. Perform
+ * additional cleanup.
+ *
+ * The method Node is stored in the walk state
+ */
+ method_node = walk_state->method_node;
+
+ /*
+ * Delete any namespace entries created immediately underneath
+ * the method
+ */
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (method_node->child) {
+ acpi_ns_delete_namespace_subtree (method_node);
+ }
+
+ /*
+ * Delete any namespace entries created anywhere else within
+ * the namespace
+ */
+ acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owning_id);
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ acpi_cm_release_mutex (ACPI_MTX_PARSER);
+ return (AE_OK);
+}
+
+
--- /dev/null
+/*******************************************************************************
+ *
+ * Module Name: dsmthdat - control method arguments and local variables
+ * $Revision: 1.1 $
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acparser.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "amlcode.h"
+#include "acnamesp.h"
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dsmthdat")
+
+
+/*******************************************************************************
+ *
+ * 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 NTEs for each.
+ * This allows Ref_of and De_ref_of to work properly for these
+ * special data types.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_init (
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 i;
+
+
+ /*
+ * Walk_state fields are initialized to zero by the
+ * Acpi_cm_callocate().
+ *
+ * An Node is assigned to each argument and local so
+ * that Ref_of() can return a pointer to the Node.
+ */
+
+ /* Init the method arguments */
+
+ for (i = 0; i < MTH_NUM_ARGS; i++) {
+ MOVE_UNALIGNED32_TO_32 (&walk_state->arguments[i].name,
+ NAMEOF_ARG_NTE);
+ walk_state->arguments[i].name |= (i << 24);
+ walk_state->arguments[i].data_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 < MTH_NUM_LOCALS; i++) {
+ MOVE_UNALIGNED32_TO_32 (&walk_state->local_variables[i].name,
+ NAMEOF_LOCAL_NTE);
+
+ walk_state->local_variables[i].name |= (i << 24);
+ walk_state->local_variables[i].data_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 (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_delete_all
+ *
+ * PARAMETERS: Walk_state - Current walk state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete method locals and arguments. Arguments are only
+ * deleted if this method was called from another method.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_delete_all (
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 index;
+ ACPI_OPERAND_OBJECT *object;
+
+
+ /* Delete the locals */
+
+ for (index = 0; index < MTH_NUM_LOCALS; index++) {
+ object = walk_state->local_variables[index].object;
+ if (object) {
+ /* Remove first */
+
+ walk_state->local_variables[index].object = NULL;
+
+ /* Was given a ref when stored */
+
+ acpi_cm_remove_reference (object);
+ }
+ }
+
+
+ /* Delete the arguments */
+
+ for (index = 0; index < MTH_NUM_ARGS; index++) {
+ object = walk_state->arguments[index].object;
+ if (object) {
+ /* Remove first */
+
+ walk_state->arguments[index].object = NULL;
+
+ /* Was given a ref when stored */
+
+ acpi_cm_remove_reference (object);
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * 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
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_init_args (
+ ACPI_OPERAND_OBJECT **params,
+ u32 max_param_count,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ u32 mindex;
+ u32 pindex;
+
+
+ if (!params) {
+ return (AE_OK);
+ }
+
+ /* Copy passed parameters into the new method stack frame */
+
+ for (pindex = mindex = 0;
+ (mindex < MTH_NUM_ARGS) && (pindex < max_param_count);
+ mindex++) {
+ if (params[pindex]) {
+ /*
+ * A valid parameter.
+ * Set the current method argument to the
+ * Params[Pindex++] argument object descriptor
+ */
+ status = acpi_ds_store_object_to_local (AML_ARG_OP, mindex,
+ params[pindex], walk_state);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ pindex++;
+ }
+
+ else {
+ break;
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_get_entry
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - Which local_var or argument to get
+ * Entry - Pointer to where a pointer to the stack
+ * entry is returned.
+ * Walk_state - Current walk state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the address of the object entry given by Opcode:Index
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_get_entry (
+ u16 opcode,
+ u32 index,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OPERAND_OBJECT ***entry)
+{
+
+
+ /*
+ * Get the requested object.
+ * The stack "Opcode" is either a Local_variable or an Argument
+ */
+
+ switch (opcode) {
+
+ case AML_LOCAL_OP:
+
+ if (index > MTH_MAX_LOCAL) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ *entry = (ACPI_OPERAND_OBJECT **)
+ &walk_state->local_variables[index].object;
+ break;
+
+
+ case AML_ARG_OP:
+
+ if (index > MTH_MAX_ARG) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ *entry = (ACPI_OPERAND_OBJECT **)
+ &walk_state->arguments[index].object;
+ break;
+
+
+ default:
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_set_entry
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - Which local_var or argument 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.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_set_entry (
+ u16 opcode,
+ u32 index,
+ ACPI_OPERAND_OBJECT *object,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT **entry;
+
+
+ /* Get a pointer to the stack entry to set */
+
+ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Increment ref count so object can't be deleted while installed */
+
+ acpi_cm_add_reference (object);
+
+ /* Install the object into the stack entry */
+
+ *entry = object;
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_get_type
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - Which local_var or argument whose type
+ * to get
+ * Walk_state - Current walk state object
+ *
+ * RETURN: Data type of selected Arg or Local
+ * Used only in Exec_monadic2()/Type_op.
+ *
+ ******************************************************************************/
+
+OBJECT_TYPE_INTERNAL
+acpi_ds_method_data_get_type (
+ u16 opcode,
+ u32 index,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT **entry;
+ ACPI_OPERAND_OBJECT *object;
+
+
+ /* Get a pointer to the requested stack entry */
+
+ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
+ if (ACPI_FAILURE (status)) {
+ return ((ACPI_TYPE_NOT_FOUND));
+ }
+
+ /* Get the object from the method stack */
+
+ object = *entry;
+
+ /* Get the object type */
+
+ if (!object) {
+ /* Any == 0 => "uninitialized" -- see spec 15.2.3.5.2.28 */
+ return (ACPI_TYPE_ANY);
+ }
+
+ return (object->common.type);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_get_node
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - Which local_var or argument whose type
+ * to get
+ * Walk_state - Current walk state object
+ *
+ * RETURN: Get the Node associated with a local or arg.
+ *
+ ******************************************************************************/
+
+ACPI_NAMESPACE_NODE *
+acpi_ds_method_data_get_node (
+ u16 opcode,
+ u32 index,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_NAMESPACE_NODE *node = NULL;
+
+
+ switch (opcode) {
+
+ case AML_LOCAL_OP:
+
+ if (index > MTH_MAX_LOCAL) {
+ return (node);
+ }
+
+ node = &walk_state->local_variables[index];
+ break;
+
+
+ case AML_ARG_OP:
+
+ if (index > MTH_MAX_ARG) {
+ return (node);
+ }
+
+ node = &walk_state->arguments[index];
+ break;
+
+
+ default:
+ break;
+ }
+
+
+ return (node);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_get_value
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - Which local_var or argument to get
+ * Walk_state - Current walk state object
+ * *Dest_desc - Ptr to Descriptor into which selected Arg
+ * or Local value should be copied
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame
+ * at the current top of the method stack.
+ * Used only in Acpi_aml_resolve_to_value().
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_get_value (
+ u16 opcode,
+ u32 index,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_OPERAND_OBJECT **dest_desc)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT **entry;
+ ACPI_OPERAND_OBJECT *object;
+
+
+ /* Validate the object descriptor */
+
+ if (!dest_desc) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Get a pointer to the requested method stack entry */
+
+ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Get the object from the method stack */
+
+ object = *entry;
+
+
+ /* Examine the returned object, it must be valid. */
+
+ if (!object) {
+ /*
+ * Index points to uninitialized object stack value.
+ * 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.
+ */
+
+ switch (opcode) {
+ case AML_ARG_OP:
+
+ return (AE_AML_UNINITIALIZED_ARG);
+ break;
+
+ case AML_LOCAL_OP:
+
+ return (AE_AML_UNINITIALIZED_LOCAL);
+ break;
+ }
+ }
+
+
+ /*
+ * Index points to initialized and valid object stack value.
+ * Return an additional reference to the object
+ */
+
+ *dest_desc = object;
+ acpi_cm_add_reference (object);
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_method_data_delete_value
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - Which local_var or argument to delete
+ * Walk_state - Current walk state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts
+ * a null into the stack slot after the object is deleted.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_method_data_delete_value (
+ u16 opcode,
+ u32 index,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT **entry;
+ ACPI_OPERAND_OBJECT *object;
+
+
+ /* Get a pointer to the requested entry */
+
+ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Get the current entry in this slot k */
+
+ object = *entry;
+
+ /*
+ * Undefine the Arg or Local by setting its descriptor
+ * pointer to NULL. Locals/Args can contain both
+ * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs
+ */
+ *entry = NULL;
+
+
+ if ((object) &&
+ (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_INTERNAL))) {
+ /*
+ * There is a valid object in this slot
+ * Decrement the reference count by one to balance the
+ * increment when the object was stored in the slot.
+ */
+ acpi_cm_remove_reference (object);
+ }
+
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_store_object_to_local
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - Which local_var or argument to set
+ * Src_desc - Value to be stored
+ * Walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store a value in an Arg or Local. The Src_desc is installed
+ * as the new value for the Arg or Local and the reference count
+ * for Src_desc is incremented.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_store_object_to_local (
+ u16 opcode,
+ u32 index,
+ ACPI_OPERAND_OBJECT *src_desc,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT **entry;
+
+
+ /* Parameter validation */
+
+ if (!src_desc) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ /* Get a pointer to the requested method stack entry */
+
+ status = acpi_ds_method_data_get_entry (opcode, index, walk_state, &entry);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ if (*entry == src_desc) {
+ goto cleanup;
+ }
+
+
+ /*
+ * 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 (*entry) {
+ /*
+ * 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 ((opcode == AML_ARG_OP) &&
+ (VALID_DESCRIPTOR_TYPE (*entry, ACPI_DESC_TYPE_NAMED))) {
+ /* Detach an existing object from the Node */
+
+ acpi_ns_detach_object ((ACPI_NAMESPACE_NODE *) *entry);
+
+ /*
+ * Store this object into the Node
+ * (do the indirect store)
+ */
+ status = acpi_ns_attach_object ((ACPI_NAMESPACE_NODE *) *entry, src_desc,
+ src_desc->common.type);
+ return (status);
+ }
+
+
+#ifdef ACPI_ENABLE_IMPLICIT_CONVERSION
+ /*
+ * Perform "Implicit conversion" of the new object to the type of the
+ * existing object
+ */
+ status = acpi_aml_convert_to_target_type ((*entry)->common.type, &src_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+#endif
+
+ /*
+ * Delete the existing object
+ * before storing the new one
+ */
+ acpi_ds_method_data_delete_value (opcode, index, walk_state);
+ }
+
+
+ /*
+ * Install the Obj_stack descriptor (*Src_desc) into
+ * the descriptor for the Arg or Local.
+ * Install the new object in the stack entry
+ * (increments the object reference count by one)
+ */
+ status = acpi_ds_method_data_set_entry (opcode, index, src_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Normal exit */
+
+ return (AE_OK);
+
+
+ /* Error exit */
+
+cleanup:
+
+ return (status);
+}
+
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: dsobject - Dispatcher object management routines
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dsobject")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_init_one_object
+ *
+ * PARAMETERS: Obj_handle - Node
+ * 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) Op Regions
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_init_one_object (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ OBJECT_TYPE_INTERNAL type;
+ ACPI_STATUS status;
+ ACPI_INIT_WALK_INFO *info = (ACPI_INIT_WALK_INFO *) context;
+ u8 table_revision;
+
+
+ info->object_count++;
+ table_revision = info->table_desc->pointer->revision;
+
+ /*
+ * We are only interested in objects owned by the table that
+ * was just loaded
+ */
+
+ if (((ACPI_NAMESPACE_NODE *) obj_handle)->owner_id !=
+ info->table_desc->table_id) {
+ return (AE_OK);
+ }
+
+
+ /* 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:
+
+ acpi_ds_initialize_region (obj_handle);
+
+ info->op_region_count++;
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+
+ info->method_count++;
+
+
+ /*
+ * Set the execution data width (32 or 64) based upon the
+ * revision number of the parent ACPI table.
+ */
+
+ if (table_revision == 1) {
+ ((ACPI_NAMESPACE_NODE *)obj_handle)->flags |= ANOBJ_DATA_WIDTH_32;
+ }
+
+ /*
+ * Always parse methods to detect errors, we may delete
+ * the parse tree below
+ */
+
+ status = acpi_ds_parse_method (obj_handle);
+
+ /* TBD: [Errors] what do we do with an error? */
+
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ /*
+ * Delete the parse tree. We simple re-parse the method
+ * for every execution since there isn't much overhead
+ */
+ acpi_ns_delete_namespace_subtree (obj_handle);
+ 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: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Walk the entire namespace and perform any necessary
+ * initialization on the objects found therein
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_initialize_objects (
+ ACPI_TABLE_DESC *table_desc,
+ ACPI_NAMESPACE_NODE *start_node)
+{
+ ACPI_STATUS status;
+ ACPI_INIT_WALK_INFO info;
+
+
+ info.method_count = 0;
+ info.op_region_count = 0;
+ info.object_count = 0;
+ info.table_desc = table_desc;
+
+
+ /* 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);
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_init_object_from_op
+ *
+ * PARAMETERS: Op - Parser op used to init the internal object
+ * Opcode - AML opcode associated with the object
+ * 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 (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op,
+ u16 opcode,
+ ACPI_OPERAND_OBJECT **obj_desc)
+{
+ ACPI_STATUS status;
+ ACPI_PARSE_OBJECT *arg;
+ ACPI_PARSE2_OBJECT *byte_list;
+ ACPI_OPERAND_OBJECT *arg_desc;
+ ACPI_OPCODE_INFO *op_info;
+
+
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) {
+ /* Unknown opcode */
+
+ return (AE_TYPE);
+ }
+
+
+ /* Get and prepare the first argument */
+
+ switch ((*obj_desc)->common.type) {
+ case ACPI_TYPE_BUFFER:
+
+ /* First arg is a number */
+
+ acpi_ds_create_operand (walk_state, op->value.arg, 0);
+ arg_desc = walk_state->operands [walk_state->num_operands - 1];
+ acpi_ds_obj_stack_pop (1, walk_state);
+
+ /* Resolve the object (could be an arg or local) */
+
+ status = acpi_aml_resolve_to_value (&arg_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (arg_desc);
+ return (status);
+ }
+
+ /* We are expecting a number */
+
+ if (arg_desc->common.type != ACPI_TYPE_INTEGER) {
+ acpi_cm_remove_reference (arg_desc);
+ return (AE_TYPE);
+ }
+
+ /* Get the value, delete the internal object */
+
+ (*obj_desc)->buffer.length = (u32) arg_desc->integer.value;
+ acpi_cm_remove_reference (arg_desc);
+
+ /* Allocate the buffer */
+
+ if ((*obj_desc)->buffer.length == 0) {
+ (*obj_desc)->buffer.pointer = NULL;
+ REPORT_WARNING (("Buffer created with zero length in AML\n"));
+ break;
+ }
+
+ else {
+ (*obj_desc)->buffer.pointer =
+ acpi_cm_callocate ((*obj_desc)->buffer.length);
+
+ if (!(*obj_desc)->buffer.pointer) {
+ return (AE_NO_MEMORY);
+ }
+ }
+
+ /*
+ * Second arg is the buffer data (optional)
+ * Byte_list can be either individual bytes or a
+ * string initializer!
+ */
+
+ /* skip first arg */
+ arg = op->value.arg;
+ byte_list = (ACPI_PARSE2_OBJECT *) arg->next;
+ if (byte_list) {
+ if (byte_list->opcode != AML_BYTELIST_OP) {
+ return (AE_TYPE);
+ }
+
+ MEMCPY ((*obj_desc)->buffer.pointer, byte_list->data,
+ (*obj_desc)->buffer.length);
+ }
+
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * When called, an internal package object has already
+ * been built and is pointed to by *Obj_desc.
+ * Acpi_ds_build_internal_object build another internal
+ * package object, so remove reference to the original
+ * so that it is deleted. Error checking is done
+ * within the remove reference function.
+ */
+ acpi_cm_remove_reference(*obj_desc);
+
+ status = acpi_ds_build_internal_object (walk_state, op, obj_desc);
+ break;
+
+ case ACPI_TYPE_INTEGER:
+ (*obj_desc)->integer.value = op->value.integer;
+ break;
+
+
+ case ACPI_TYPE_STRING:
+ (*obj_desc)->string.pointer = op->value.string;
+ (*obj_desc)->string.length = STRLEN (op->value.string);
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+ break;
+
+
+ case INTERNAL_TYPE_REFERENCE:
+
+ switch (ACPI_GET_OP_CLASS (op_info)) {
+ case OPTYPE_LOCAL_VARIABLE:
+
+ /* Split the opcode into a base opcode + offset */
+
+ (*obj_desc)->reference.opcode = AML_LOCAL_OP;
+ (*obj_desc)->reference.offset = opcode - AML_LOCAL_OP;
+ break;
+
+ case OPTYPE_METHOD_ARGUMENT:
+
+ /* Split the opcode into a base opcode + offset */
+
+ (*obj_desc)->reference.opcode = AML_ARG_OP;
+ (*obj_desc)->reference.offset = opcode - AML_ARG_OP;
+ break;
+
+ default: /* Constants, Literals, etc.. */
+
+ if (op->opcode == AML_NAMEPATH_OP) {
+ /* Node was saved in Op */
+
+ (*obj_desc)->reference.node = op->node;
+ }
+
+ (*obj_desc)->reference.opcode = opcode;
+ break;
+ }
+
+ break;
+
+
+ default:
+
+ break;
+ }
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_build_internal_simple_obj
+ *
+ * PARAMETERS: 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_simple_obj (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op,
+ ACPI_OPERAND_OBJECT **obj_desc_ptr)
+{
+ ACPI_OPERAND_OBJECT *obj_desc;
+ OBJECT_TYPE_INTERNAL type;
+ ACPI_STATUS status;
+ u32 length;
+ char *name;
+
+
+ if (op->opcode == AML_NAMEPATH_OP) {
+ /*
+ * This is an object reference. If The name was
+ * previously looked up in the NS, it is stored in this op.
+ * Otherwise, go ahead and look it up now
+ */
+
+ if (!op->node) {
+ status = acpi_ns_lookup (walk_state->scope_info,
+ op->value.string, ACPI_TYPE_ANY,
+ IMODE_EXECUTE,
+ NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE,
+ NULL,
+ (ACPI_NAMESPACE_NODE **)&(op->node));
+
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_NOT_FOUND) {
+ name = NULL;
+ acpi_ns_externalize_name (ACPI_UINT32_MAX, op->value.string, &length, &name);
+
+ if (name) {
+ REPORT_WARNING (("Reference %s at AML %X not found\n",
+ name, op->aml_offset));
+ acpi_cm_free (name);
+ }
+ else {
+ REPORT_WARNING (("Reference %s at AML %X not found\n",
+ op->value.string, op->aml_offset));
+ }
+ *obj_desc_ptr = NULL;
+ }
+
+ else {
+ return (status);
+ }
+ }
+ }
+
+ /*
+ * The reference will be a Reference
+ * TBD: [Restructure] unless we really need a separate
+ * type of INTERNAL_TYPE_REFERENCE change
+ * Acpi_ds_map_opcode_to_data_type to handle this case
+ */
+ type = INTERNAL_TYPE_REFERENCE;
+ }
+ else {
+ type = acpi_ds_map_opcode_to_data_type (op->opcode, NULL);
+ }
+
+
+ /* Create and init the internal ACPI object */
+
+ obj_desc = acpi_cm_create_internal_object (type);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ status = acpi_ds_init_object_from_op (walk_state, op,
+ op->opcode, &obj_desc);
+
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (obj_desc);
+ return (status);
+ }
+
+ *obj_desc_ptr = obj_desc;
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_build_internal_package_obj
+ *
+ * PARAMETERS: Op - Parser object to be translated
+ * 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_package_obj (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op,
+ ACPI_OPERAND_OBJECT **obj_desc_ptr)
+{
+ ACPI_PARSE_OBJECT *arg;
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_STATUS status = AE_OK;
+
+
+ obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_PACKAGE);
+ if (!obj_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* The first argument must be the package length */
+
+ arg = op->value.arg;
+ obj_desc->package.count = arg->value.integer;
+
+ /*
+ * Allocate the array of pointers (ptrs to the
+ * individual objects) Add an extra pointer slot so
+ * that the list is always null terminated.
+ */
+
+ obj_desc->package.elements =
+ acpi_cm_callocate ((obj_desc->package.count + 1) *
+ sizeof (void *));
+
+ if (!obj_desc->package.elements) {
+ /* Package vector allocation failure */
+
+ REPORT_ERROR (("Ds_build_internal_package_obj: Package vector allocation failure\n"));
+
+ acpi_cm_delete_object_desc (obj_desc);
+ return (AE_NO_MEMORY);
+ }
+
+ obj_desc->package.next_element = obj_desc->package.elements;
+
+ /*
+ * Now init the elements of the package
+ */
+
+ arg = arg->next;
+ while (arg) {
+ if (arg->opcode == AML_PACKAGE_OP) {
+ status = acpi_ds_build_internal_package_obj (walk_state, arg,
+ obj_desc->package.next_element);
+ }
+
+ else {
+ status = acpi_ds_build_internal_simple_obj (walk_state, arg,
+ obj_desc->package.next_element);
+ }
+
+ obj_desc->package.next_element++;
+ arg = arg->next;
+ }
+
+ *obj_desc_ptr = obj_desc;
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_build_internal_object
+ *
+ * PARAMETERS: 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
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_build_internal_object (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op,
+ ACPI_OPERAND_OBJECT **obj_desc_ptr)
+{
+ ACPI_STATUS status;
+
+
+ if (op->opcode == AML_PACKAGE_OP) {
+ status = acpi_ds_build_internal_package_obj (walk_state, op,
+ obj_desc_ptr);
+ }
+
+ else {
+ status = acpi_ds_build_internal_simple_obj (walk_state, op,
+ obj_desc_ptr);
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_node
+ *
+ * PARAMETERS: Op - Parser object to be translated
+ * Obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_create_node (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_NAMESPACE_NODE *node,
+ ACPI_PARSE_OBJECT *op)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT *obj_desc;
+
+
+ if (!op->value.arg) {
+ /* No arguments, there is nothing to do */
+
+ return (AE_OK);
+ }
+
+
+ /* Build an internal object for the argument(s) */
+
+ status = acpi_ds_build_internal_object (walk_state,
+ op->value.arg, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+ /* Re-type the object according to it's argument */
+
+ node->type = obj_desc->common.type;
+
+ /* Init obj */
+
+ status = acpi_ns_attach_object ((ACPI_HANDLE) node, obj_desc,
+ (u8) node->type);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ return (status);
+
+
+cleanup:
+
+ acpi_cm_remove_reference (obj_desc);
+
+ return (status);
+}
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: dsopcode - Dispatcher Op Region support and handling of
+ * "control" opcodes
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acevents.h"
+#include "actables.h"
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dsopcode")
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_get_field_unit_arguments
+ *
+ * PARAMETERS: Obj_desc - A valid Field_unit object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get Field_unit Buffer and Index. This implements the late
+ * evaluation of these field attributes.
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_get_field_unit_arguments (
+ ACPI_OPERAND_OBJECT *obj_desc)
+{
+ ACPI_OPERAND_OBJECT *extra_desc;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_PARSE_OBJECT *op;
+ ACPI_PARSE_OBJECT *field_op;
+ ACPI_STATUS status;
+ ACPI_TABLE_DESC *table_desc;
+
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return (AE_OK);
+ }
+
+
+ /* Get the AML pointer (method object) and Field_unit node */
+
+ extra_desc = obj_desc->field_unit.extra;
+ node = obj_desc->field_unit.node;
+
+ /*
+ * Allocate a new parser op to be the root of the parsed
+ * Op_region tree
+ */
+
+ op = acpi_ps_alloc_op (AML_SCOPE_OP);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Save the Node for use in Acpi_ps_parse_aml */
+
+ op->node = acpi_ns_get_parent_object (node);
+
+ /* Get a handle to the parent ACPI table */
+
+ status = acpi_tb_handle_to_object (node->owner_id, &table_desc);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Pass1: Parse the entire Field_unit declaration */
+
+ status = acpi_ps_parse_aml (op, extra_desc->extra.pcode,
+ extra_desc->extra.pcode_length, 0,
+ NULL, NULL, NULL, acpi_ds_load1_begin_op, acpi_ds_load1_end_op);
+ if (ACPI_FAILURE (status)) {
+ acpi_ps_delete_parse_tree (op);
+ return (status);
+ }
+
+
+ /* Get and init the actual Fiel_unit_op created above */
+
+ field_op = op->value.arg;
+ op->node = node;
+
+
+ field_op = op->value.arg;
+ field_op->node = node;
+ acpi_ps_delete_parse_tree (op);
+
+ /* Acpi_evaluate the address and length arguments for the Op_region */
+
+ op = acpi_ps_alloc_op (AML_SCOPE_OP);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ op->node = acpi_ns_get_parent_object (node);
+
+ status = acpi_ps_parse_aml (op, extra_desc->extra.pcode,
+ extra_desc->extra.pcode_length,
+ ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE,
+ NULL /*Method_desc*/, NULL, NULL,
+ acpi_ds_exec_begin_op, acpi_ds_exec_end_op);
+ /* All done with the parse tree, delete it */
+
+ acpi_ps_delete_parse_tree (op);
+
+
+ /*
+ * The pseudo-method object is no longer needed since the region is
+ * now initialized
+ */
+ acpi_cm_remove_reference (obj_desc->field_unit.extra);
+ obj_desc->field_unit.extra = NULL;
+
+ return (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 (
+ ACPI_OPERAND_OBJECT *obj_desc)
+{
+ ACPI_OPERAND_OBJECT *extra_desc = NULL;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_PARSE_OBJECT *op;
+ ACPI_PARSE_OBJECT *region_op;
+ ACPI_STATUS status;
+ ACPI_TABLE_DESC *table_desc;
+
+
+ if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
+ return (AE_OK);
+ }
+
+
+ /* Get the AML pointer (method object) and region node */
+
+ extra_desc = obj_desc->region.extra;
+ node = obj_desc->region.node;
+
+ /*
+ * Allocate a new parser op to be the root of the parsed
+ * Op_region tree
+ */
+
+ op = acpi_ps_alloc_op (AML_SCOPE_OP);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Save the Node for use in Acpi_ps_parse_aml */
+
+ op->node = acpi_ns_get_parent_object (node);
+
+ /* Get a handle to the parent ACPI table */
+
+ status = acpi_tb_handle_to_object (node->owner_id, &table_desc);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Parse the entire Op_region declaration, creating a parse tree */
+
+ status = acpi_ps_parse_aml (op, extra_desc->extra.pcode,
+ extra_desc->extra.pcode_length, 0,
+ NULL, NULL, NULL, acpi_ds_load1_begin_op, acpi_ds_load1_end_op);
+
+ if (ACPI_FAILURE (status)) {
+ acpi_ps_delete_parse_tree (op);
+ return (status);
+ }
+
+
+ /* Get and init the actual Region_op created above */
+
+ region_op = op->value.arg;
+ op->node = node;
+
+
+ region_op = op->value.arg;
+ region_op->node = node;
+ acpi_ps_delete_parse_tree (op);
+
+ /* Acpi_evaluate the address and length arguments for the Op_region */
+
+ op = acpi_ps_alloc_op (AML_SCOPE_OP);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ op->node = acpi_ns_get_parent_object (node);
+
+ status = acpi_ps_parse_aml (op, extra_desc->extra.pcode,
+ extra_desc->extra.pcode_length,
+ ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE,
+ NULL /*Method_desc*/, NULL, NULL,
+ acpi_ds_exec_begin_op, acpi_ds_exec_end_op);
+
+ /* All done with the parse tree, delete it */
+
+ acpi_ps_delete_parse_tree (op);
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_initialize_region
+ *
+ * PARAMETERS: Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_initialize_region (
+ ACPI_HANDLE obj_handle)
+{
+ 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_eval_field_unit_operands
+ *
+ * PARAMETERS: Op - A valid Field_unit Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get Field_unit Buffer and Index
+ * Called from Acpi_ds_exec_end_op during Field_unit parse tree walk
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_eval_field_unit_operands (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT *field_desc;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_PARSE_OBJECT *next_op;
+ u32 offset;
+ u32 bit_offset;
+ u16 bit_count;
+
+
+ ACPI_OPERAND_OBJECT *res_desc = NULL;
+ ACPI_OPERAND_OBJECT *cnt_desc = NULL;
+ ACPI_OPERAND_OBJECT *off_desc = NULL;
+ ACPI_OPERAND_OBJECT *src_desc = NULL;
+ u32 num_operands = 3;
+
+
+ /*
+ * This is where we evaluate the address and length fields of the Op_field_unit declaration
+ */
+
+ node = op->node;
+
+ /* Next_op points to the op that holds the Buffer */
+ next_op = op->value.arg;
+
+ /* Acpi_evaluate/create the address and length operands */
+
+ status = acpi_ds_create_operands (walk_state, next_op);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ field_desc = acpi_ns_get_attached_object (node);
+ if (!field_desc) {
+ return (AE_NOT_EXIST);
+ }
+
+
+ /* Resolve the operands */
+
+ status = acpi_aml_resolve_operands (op->opcode, WALK_OPERANDS, walk_state);
+
+ /* Get the operands */
+
+ status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state);
+ if (AML_CREATE_FIELD_OP == op->opcode) {
+ num_operands = 4;
+ status |= acpi_ds_obj_stack_pop_object (&cnt_desc, walk_state);
+ }
+
+ status |= acpi_ds_obj_stack_pop_object (&off_desc, walk_state);
+ status |= acpi_ds_obj_stack_pop_object (&src_desc, walk_state);
+
+ if (ACPI_FAILURE (status)) {
+ /* Invalid parameters on object stack */
+
+ goto cleanup;
+ }
+
+
+ offset = (u32) off_desc->integer.value;
+
+
+ /*
+ * If Res_desc is a Name, it will be a direct name pointer after
+ * Acpi_aml_resolve_operands()
+ */
+
+ if (!VALID_DESCRIPTOR_TYPE (res_desc, ACPI_DESC_TYPE_NAMED)) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+
+ /*
+ * Setup the Bit offsets and counts, according to the opcode
+ */
+
+ switch (op->opcode) {
+
+ /* Def_create_bit_field */
+
+ case AML_BIT_FIELD_OP:
+
+ /* Offset is in bits, Field is a bit */
+
+ bit_offset = offset;
+ bit_count = 1;
+ break;
+
+
+ /* Def_create_byte_field */
+
+ case AML_BYTE_FIELD_OP:
+
+ /* Offset is in bytes, field is a byte */
+
+ bit_offset = 8 * offset;
+ bit_count = 8;
+ break;
+
+
+ /* Def_create_word_field */
+
+ case AML_WORD_FIELD_OP:
+
+ /* Offset is in bytes, field is a word */
+
+ bit_offset = 8 * offset;
+ bit_count = 16;
+ break;
+
+
+ /* Def_create_dWord_field */
+
+ case AML_DWORD_FIELD_OP:
+
+ /* Offset is in bytes, field is a dword */
+
+ bit_offset = 8 * offset;
+ bit_count = 32;
+ break;
+
+
+ /* Def_create_field */
+
+ case AML_CREATE_FIELD_OP:
+
+ /* Offset is in bits, count is in bits */
+
+ bit_offset = offset;
+ bit_count = (u16) cnt_desc->integer.value;
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+ /*
+ * Setup field according to the object type
+ */
+
+ switch (src_desc->common.type) {
+
+ /* Source_buff := Term_arg=>Buffer */
+
+ case ACPI_TYPE_BUFFER:
+
+ if (bit_offset + (u32) bit_count >
+ (8 * (u32) src_desc->buffer.length)) {
+ status = AE_AML_BUFFER_LIMIT;
+ goto cleanup;
+ }
+
+
+ /* Construct the remainder of the field object */
+
+ field_desc->field_unit.access = (u8) ACCESS_ANY_ACC;
+ field_desc->field_unit.lock_rule = (u8) GLOCK_NEVER_LOCK;
+ field_desc->field_unit.update_rule = (u8) UPDATE_PRESERVE;
+ field_desc->field_unit.length = bit_count;
+ field_desc->field_unit.bit_offset = (u8) (bit_offset % 8);
+ field_desc->field_unit.offset = DIV_8 (bit_offset);
+ field_desc->field_unit.container = src_desc;
+
+ /* Reference count for Src_desc inherits Field_desc count */
+
+ src_desc->common.reference_count = (u16) (src_desc->common.reference_count +
+ field_desc->common.reference_count);
+
+ break;
+
+
+ /* Improper object type */
+
+ default:
+
+
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+
+ if (AML_CREATE_FIELD_OP == op->opcode) {
+ /* Delete object descriptor unique to Create_field */
+
+ acpi_cm_remove_reference (cnt_desc);
+ cnt_desc = NULL;
+ }
+
+
+cleanup:
+
+ /* Always delete the operands */
+
+ acpi_cm_remove_reference (off_desc);
+ acpi_cm_remove_reference (src_desc);
+
+ if (AML_CREATE_FIELD_OP == op->opcode) {
+ acpi_cm_remove_reference (cnt_desc);
+ }
+
+ /* On failure, delete the result descriptor */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_remove_reference (res_desc); /* Result descriptor */
+ }
+
+ else {
+ /* Now the address and length are valid for this op_field_unit */
+
+ field_desc->field_unit.flags |= AOPOBJ_DATA_VALID;
+ }
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_eval_region_operands
+ *
+ * PARAMETERS: 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 (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op)
+{
+ ACPI_STATUS status;
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_OPERAND_OBJECT *operand_desc;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_PARSE_OBJECT *next_op;
+
+
+ /*
+ * This is where we evaluate the address and length fields of the Op_region declaration
+ */
+
+ node = op->node;
+
+ /* Next_op points to the op that holds the Space_iD */
+ next_op = op->value.arg;
+
+ /* Next_op points to address op */
+ next_op = next_op->next;
+
+ /* Acpi_evaluate/create the address and length operands */
+
+ status = acpi_ds_create_operands (walk_state, next_op);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Resolve the length and address operands to numbers */
+
+ status = acpi_aml_resolve_operands (op->opcode, WALK_OPERANDS, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ return (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_cm_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_cm_remove_reference (operand_desc);
+
+
+ /* Now the address and length are valid for this opregion */
+
+ obj_desc->region.flags |= AOPOBJ_DATA_VALID;
+
+ return (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 (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_GENERIC_STATE *control_state;
+
+
+ switch (op->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_cm_create_control_state ();
+ if (!control_state) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ acpi_cm_push_generic_state (&walk_state->control_state, control_state);
+
+ /*
+ * Save a pointer to the predicate for multiple executions
+ * of a loop
+ */
+ walk_state->control_state->control.aml_predicate_start =
+ walk_state->parser_state->aml - 1;
+ /* TBD: can this be removed? */
+ /*Acpi_ps_pkg_length_encoding_size (GET8 (Walk_state->Parser_state->Aml));*/
+ 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 (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_GENERIC_STATE *control_state;
+
+
+ switch (op->opcode) {
+ case AML_IF_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_cm_pop_generic_state (&walk_state->control_state);
+
+ acpi_cm_delete_generic_state (control_state);
+
+ break;
+
+
+ case AML_ELSE_OP:
+
+ break;
+
+
+ case AML_WHILE_OP:
+
+ if (walk_state->control_state->common.value) {
+ /* Predicate was true, go back and evaluate it again! */
+
+ status = AE_CTRL_PENDING;
+ }
+
+
+ /* Pop this control state and free it */
+
+ control_state =
+ acpi_cm_pop_generic_state (&walk_state->control_state);
+
+ walk_state->aml_last_while = control_state->control.aml_predicate_start;
+ acpi_cm_delete_generic_state (control_state);
+
+ break;
+
+
+ case AML_RETURN_OP:
+
+
+ /*
+ * 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->value.arg) {
+ /* Return statement has an immediate operand */
+
+ status = acpi_ds_create_operands (walk_state, op->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_aml_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->results) &&
+ (walk_state->results->results.num_results > 0)) {
+ /*
+ * 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 (VALID_DESCRIPTOR_TYPE (walk_state->results->results.obj_desc [0], ACPI_DESC_TYPE_INTERNAL) &&
+ ((walk_state->results->results.obj_desc [0])->common.type == INTERNAL_TYPE_REFERENCE) &&
+ ((walk_state->results->results.obj_desc [0])->reference.opcode != AML_INDEX_OP)) {
+ status = acpi_aml_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_cm_remove_reference (walk_state->operands [0]);
+ }
+
+ walk_state->operands [0] = NULL;
+ walk_state->num_operands = 0;
+ walk_state->return_desc = NULL;
+ }
+
+
+ /* 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 dependent layer to handle this */
+
+ acpi_os_breakpoint (NULL);
+
+ /* If it returns, we are done! */
+
+ break;
+
+
+ case AML_BREAK_OP:
+
+ /*
+ * As per the ACPI specification:
+ * "The break operation causes the current package
+ * execution to complete"
+ * "Break -- Stop executing the current code package
+ * at this point"
+ *
+ * Returning AE_FALSE here will cause termination of
+ * the current package, and execution will continue one
+ * level up, starting with the completion of the parent Op.
+ */
+
+ status = AE_CTRL_FALSE;
+ break;
+
+
+ default:
+
+ status = AE_AML_BAD_OPCODE;
+ break;
+ }
+
+
+ return (status);
+}
+
--- /dev/null
+/*******************************************************************************
+ *
+ * Module Name: dsutils - Dispatcher utilities
+ * $Revision: 1.1 $
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dsutils")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_is_result_used
+ *
+ * PARAMETERS: Op
+ * Result_obj
+ * Walk_state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check if a result object will be used by the parent
+ *
+ ******************************************************************************/
+
+u8
+acpi_ds_is_result_used (
+ ACPI_PARSE_OBJECT *op,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_OPCODE_INFO *parent_info;
+
+
+ /* Must have both an Op and a Result Object */
+
+ if (!op) {
+ return (TRUE);
+ }
+
+
+ /*
+ * If there is no parent, the result can't possibly be used!
+ * (An executing method typically has no parent, since each
+ * method is parsed separately) However, a method that is
+ * invoked from another method has a parent.
+ */
+ if (!op->parent) {
+ return (FALSE);
+ }
+
+
+ /*
+ * Get info on the parent. The root Op is AML_SCOPE
+ */
+
+ parent_info = acpi_ps_get_opcode_info (op->parent->opcode);
+ if (ACPI_GET_OP_TYPE (parent_info) != ACPI_OP_TYPE_OPCODE) {
+ return (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 (ACPI_GET_OP_CLASS (parent_info)) {
+ /*
+ * In these cases, the parent will never use the return object
+ */
+ case OPTYPE_CONTROL: /* IF, ELSE, WHILE only */
+
+ switch (op->parent->opcode) {
+ case AML_RETURN_OP:
+
+ /* Never delete the return value associated with a return opcode */
+
+ return (TRUE);
+ break;
+
+ 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 == CONTROL_PREDICATE_EXECUTING) &&
+ (walk_state->control_state->control.predicate_op == op)) {
+ return (TRUE);
+ }
+
+ break;
+ }
+
+
+ /* Fall through to not used case below */
+
+
+ case OPTYPE_NAMED_OBJECT: /* Scope, method, etc. */
+
+ /*
+ * These opcodes allow Term_arg(s) as operands and therefore
+ * method calls. The result is used.
+ */
+ if ((op->parent->opcode == AML_REGION_OP) ||
+ (op->parent->opcode == AML_CREATE_FIELD_OP) ||
+ (op->parent->opcode == AML_BIT_FIELD_OP) ||
+ (op->parent->opcode == AML_BYTE_FIELD_OP) ||
+ (op->parent->opcode == AML_WORD_FIELD_OP) ||
+ (op->parent->opcode == AML_DWORD_FIELD_OP) ||
+ (op->parent->opcode == AML_QWORD_FIELD_OP)) {
+ return (TRUE);
+ }
+
+ return (FALSE);
+ break;
+
+ /*
+ * In all other cases. the parent will actually use the return
+ * object, so keep it.
+ */
+ default:
+ break;
+ }
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_delete_result_if_not_used
+ *
+ * PARAMETERS: Op
+ * Result_obj
+ * Walk_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 (
+ ACPI_PARSE_OBJECT *op,
+ ACPI_OPERAND_OBJECT *result_obj,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_STATUS status;
+
+
+ if (!op) {
+ return;
+ }
+
+ if (!result_obj) {
+ return;
+ }
+
+
+ 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_cm_remove_reference (result_obj);
+ }
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_operand
+ *
+ * PARAMETERS: Walk_state
+ * Arg
+ *
+ * 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 (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *arg,
+ u32 arg_index)
+{
+ ACPI_STATUS status = AE_OK;
+ NATIVE_CHAR *name_string;
+ u32 name_length;
+ OBJECT_TYPE_INTERNAL data_type;
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_PARSE_OBJECT *parent_op;
+ u16 opcode;
+ u32 flags;
+ OPERATING_MODE interpreter_mode;
+
+
+ /* A valid name must be looked up in the namespace */
+
+ if ((arg->opcode == AML_NAMEPATH_OP) &&
+ (arg->value.string)) {
+ /* Get the entire name string from the AML stream */
+
+ status = acpi_aml_get_name_string (ACPI_TYPE_ANY,
+ arg->value.buffer,
+ &name_string,
+ &name_length);
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * All prefixes have been handled, and the name is
+ * in Name_string
+ */
+
+ /*
+ * 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->parent;
+ if ((acpi_ps_is_node_op (parent_op->opcode)) &&
+ (parent_op->opcode != AML_METHODCALL_OP) &&
+ (parent_op->opcode != AML_REGION_OP) &&
+ (parent_op->opcode != AML_NAMEPATH_OP)) {
+ /* Enter name into namespace if not found */
+
+ interpreter_mode = IMODE_LOAD_PASS2;
+ }
+
+ else {
+ /* Return a failure if name not found */
+
+ interpreter_mode = IMODE_EXECUTE;
+ }
+
+ status = acpi_ns_lookup (walk_state->scope_info, name_string,
+ ACPI_TYPE_ANY, interpreter_mode,
+ NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE,
+ walk_state,
+ (ACPI_NAMESPACE_NODE **) &obj_desc);
+
+ /* Free the namestring created above */
+
+ acpi_cm_free (name_string);
+
+ /*
+ * 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->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_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;
+ }
+ }
+
+ /* Check status from the lookup */
+
+ if (ACPI_FAILURE (status)) {
+ return (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 (status);
+ }
+ DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state));
+ }
+
+
+ else {
+ /* Check for null name case */
+
+ if (arg->opcode == AML_NAMEPATH_OP) {
+ /*
+ * If the name is null, this means that this is an
+ * optional result parameter that was not specified
+ * in the original ASL. Create an Reference for a
+ * placeholder
+ */
+ opcode = AML_ZERO_OP; /* Has no arguments! */
+
+ /*
+ * TBD: [Investigate] anything else needed for the
+ * zero op lvalue?
+ */
+ }
+
+ else {
+ opcode = arg->opcode;
+ }
+
+
+ /* Get the data type of the argument */
+
+ data_type = acpi_ds_map_opcode_to_data_type (opcode, &flags);
+ if (data_type == INTERNAL_TYPE_INVALID) {
+ return (AE_NOT_IMPLEMENTED);
+ }
+
+ if (flags & OP_HAS_RETURN_VALUE) {
+ 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_from_bottom (&obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ /*
+ * Only error is underflow, and this indicates
+ * a missing or null operand!
+ */
+ return (status);
+ }
+
+ }
+
+ else {
+ /* Create an ACPI_INTERNAL_OBJECT for the argument */
+
+ obj_desc = acpi_cm_create_internal_object (data_type);
+ if (!obj_desc) {
+ return (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_cm_delete_object_desc (obj_desc);
+ return (status);
+ }
+ }
+
+ /* Put the operand object on the object stack */
+
+ status = acpi_ds_obj_stack_push (obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state));
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_operands
+ *
+ * PARAMETERS: 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 (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *first_arg)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_PARSE_OBJECT *arg;
+ u32 arg_count = 0;
+
+
+ /* For all arguments in the list... */
+
+ arg = first_arg;
+ while (arg) {
+ status = acpi_ds_create_operand (walk_state, arg, arg_count);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Move on to next argument, if any */
+
+ arg = arg->next;
+ arg_count++;
+ }
+
+ return (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);
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * 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 (
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 i;
+ ACPI_STATUS status = AE_OK;
+
+
+ /*
+ * Attempt to resolve each of the valid operands
+ * Method arguments are passed by value, not by reference
+ */
+
+ /*
+ * TBD: [Investigate] Note from previous parser:
+ * Ref_of problem with Acpi_aml_resolve_to_value() conversion.
+ */
+
+ for (i = 0; i < walk_state->num_operands; i++) {
+ status = acpi_aml_resolve_to_value (&walk_state->operands[i], walk_state);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_map_opcode_to_data_type
+ *
+ * PARAMETERS: Opcode - AML opcode to map
+ * Out_flags - Additional info about the opcode
+ *
+ * RETURN: The ACPI type associated with the opcode
+ *
+ * DESCRIPTION: Convert a raw AML opcode to the associated ACPI data type,
+ * if any. If the opcode returns a value as part of the
+ * intepreter execution, a flag is returned in Out_flags.
+ *
+ ******************************************************************************/
+
+OBJECT_TYPE_INTERNAL
+acpi_ds_map_opcode_to_data_type (
+ u16 opcode,
+ u32 *out_flags)
+{
+ OBJECT_TYPE_INTERNAL data_type = INTERNAL_TYPE_INVALID;
+ ACPI_OPCODE_INFO *op_info;
+ u32 flags = 0;
+
+
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) {
+ /* Unknown opcode */
+
+ return (data_type);
+ }
+
+ switch (ACPI_GET_OP_CLASS (op_info)) {
+
+ case OPTYPE_LITERAL:
+
+ switch (opcode) {
+ case AML_BYTE_OP:
+ case AML_WORD_OP:
+ case AML_DWORD_OP:
+
+ data_type = ACPI_TYPE_INTEGER;
+ break;
+
+
+ case AML_STRING_OP:
+
+ data_type = ACPI_TYPE_STRING;
+ break;
+
+ case AML_NAMEPATH_OP:
+ data_type = INTERNAL_TYPE_REFERENCE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+
+ case OPTYPE_DATA_TERM:
+
+ switch (opcode) {
+ case AML_BUFFER_OP:
+
+ data_type = ACPI_TYPE_BUFFER;
+ break;
+
+ case AML_PACKAGE_OP:
+
+ data_type = ACPI_TYPE_PACKAGE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+
+ case OPTYPE_CONSTANT:
+ case OPTYPE_METHOD_ARGUMENT:
+ case OPTYPE_LOCAL_VARIABLE:
+
+ data_type = INTERNAL_TYPE_REFERENCE;
+ break;
+
+
+ case OPTYPE_MONADIC2:
+ case OPTYPE_MONADIC2_r:
+ case OPTYPE_DYADIC2:
+ case OPTYPE_DYADIC2_r:
+ case OPTYPE_DYADIC2_s:
+ case OPTYPE_INDEX:
+ case OPTYPE_MATCH:
+ case OPTYPE_RETURN:
+
+ flags = OP_HAS_RETURN_VALUE;
+ data_type = ACPI_TYPE_ANY;
+ break;
+
+ case OPTYPE_METHOD_CALL:
+
+ flags = OP_HAS_RETURN_VALUE;
+ data_type = ACPI_TYPE_METHOD;
+ break;
+
+
+ case OPTYPE_NAMED_OBJECT:
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (opcode);
+ break;
+
+
+ case OPTYPE_DYADIC1:
+ case OPTYPE_CONTROL:
+
+ /* No mapping needed at this time */
+
+ break;
+
+
+ default:
+
+ break;
+ }
+
+ /* Return flags to caller if requested */
+
+ if (out_flags) {
+ *out_flags = flags;
+ }
+
+ return (data_type);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_map_named_opcode_to_data_type
+ *
+ * PARAMETERS: Opcode - The Named AML opcode to map
+ *
+ * RETURN: The ACPI type associated with the named opcode
+ *
+ * DESCRIPTION: Convert a raw Named AML opcode to the associated data type.
+ * Named opcodes are a subsystem of the AML opcodes.
+ *
+ ******************************************************************************/
+
+OBJECT_TYPE_INTERNAL
+acpi_ds_map_named_opcode_to_data_type (
+ u16 opcode)
+{
+ OBJECT_TYPE_INTERNAL data_type;
+
+
+ /* Decode Opcode */
+
+ switch (opcode) {
+ case AML_SCOPE_OP:
+ data_type = INTERNAL_TYPE_SCOPE;
+ break;
+
+ case AML_DEVICE_OP:
+ data_type = ACPI_TYPE_DEVICE;
+ break;
+
+ case AML_THERMAL_ZONE_OP:
+ data_type = ACPI_TYPE_THERMAL;
+ break;
+
+ case AML_METHOD_OP:
+ data_type = ACPI_TYPE_METHOD;
+ break;
+
+ case AML_POWER_RES_OP:
+ data_type = ACPI_TYPE_POWER;
+ break;
+
+ case AML_PROCESSOR_OP:
+ data_type = ACPI_TYPE_PROCESSOR;
+ break;
+
+ case AML_DEF_FIELD_OP: /* Def_field_op */
+ data_type = INTERNAL_TYPE_DEF_FIELD_DEFN;
+ break;
+
+ case AML_INDEX_FIELD_OP: /* Index_field_op */
+ data_type = INTERNAL_TYPE_INDEX_FIELD_DEFN;
+ break;
+
+ case AML_BANK_FIELD_OP: /* Bank_field_op */
+ data_type = INTERNAL_TYPE_BANK_FIELD_DEFN;
+ break;
+
+ case AML_NAMEDFIELD_OP: /* NO CASE IN ORIGINAL */
+ data_type = ACPI_TYPE_ANY;
+ break;
+
+ case AML_NAME_OP: /* Name_op - special code in original */
+ case AML_NAMEPATH_OP:
+ data_type = ACPI_TYPE_ANY;
+ break;
+
+ case AML_ALIAS_OP:
+ data_type = INTERNAL_TYPE_ALIAS;
+ break;
+
+ case AML_MUTEX_OP:
+ data_type = ACPI_TYPE_MUTEX;
+ break;
+
+ case AML_EVENT_OP:
+ data_type = ACPI_TYPE_EVENT;
+ break;
+
+ case AML_REGION_OP:
+ data_type = ACPI_TYPE_REGION;
+ break;
+
+
+ default:
+ data_type = ACPI_TYPE_ANY;
+ break;
+
+ }
+
+ return (data_type);
+}
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: dswexec - Dispatcher method execution callbacks;
+ * dispatch to interpreter.
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acdebug.h"
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dswexec")
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_get_predicate_value
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the result of a predicate evaluation
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ds_get_predicate_value (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op,
+ u32 has_result_obj)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_OPERAND_OBJECT *obj_desc;
+
+
+ walk_state->control_state->common.state = 0;
+
+ if (has_result_obj) {
+ status = acpi_ds_result_pop (&obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ else {
+ status = acpi_ds_create_operand (walk_state, op, 0);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ status = acpi_aml_resolve_to_value (&walk_state->operands [0], walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ obj_desc = walk_state->operands [0];
+ }
+
+ if (!obj_desc) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+
+ /*
+ * Result of predicate evaluation currently must
+ * be a number
+ */
+
+ if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+
+ /* Truncate the predicate to 32-bits if necessary */
+
+ acpi_aml_truncate_for32bit_table (obj_desc, walk_state);
+
+ /*
+ * Save the result of the predicate evaluation on
+ * the control stack
+ */
+
+ if (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;
+ }
+
+
+cleanup:
+
+ /* Break to debugger to display result */
+
+ DEBUGGER_EXEC (acpi_db_display_result_object (obj_desc, walk_state));
+
+ /*
+ * Delete the predicate result object (we know that
+ * we don't need it anymore)
+ */
+
+ acpi_cm_remove_reference (obj_desc);
+
+ walk_state->control_state->common.state = CONTROL_NORMAL;
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_exec_begin_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been reached in the
+ * walk; Arguments have not been evaluated yet.
+ *
+ * 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 (
+ u16 opcode,
+ ACPI_PARSE_OBJECT *op,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT **out_op)
+{
+ ACPI_OPCODE_INFO *op_info;
+ ACPI_STATUS status = AE_OK;
+
+
+ if (!op) {
+ status = acpi_ds_load2_begin_op (opcode, NULL, walk_state, out_op);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ op = *out_op;
+ }
+
+ if (op == walk_state->origin) {
+ if (out_op) {
+ *out_op = op;
+ }
+
+ return (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 ==
+ CONTROL_CONDITIONAL_EXECUTING)) {
+ walk_state->control_state->common.state = CONTROL_PREDICATE_EXECUTING;
+
+ /* Save start of predicate */
+
+ walk_state->control_state->control.predicate_op = op;
+ }
+
+
+ op_info = acpi_ps_get_opcode_info (op->opcode);
+
+ /* We want to send namepaths to the load code */
+
+ if (op->opcode == AML_NAMEPATH_OP) {
+ op_info->flags = OPTYPE_NAMED_OBJECT;
+ }
+
+
+ /*
+ * Handle the opcode based upon the opcode type
+ */
+
+ switch (ACPI_GET_OP_CLASS (op_info)) {
+ case OPTYPE_CONTROL:
+
+ status = acpi_ds_result_stack_push (walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ status = acpi_ds_exec_begin_control_op (walk_state, op);
+ break;
+
+
+ case OPTYPE_NAMED_OBJECT:
+
+ if (walk_state->walk_type == 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 (op->opcode, op, walk_state, NULL);
+ }
+
+
+ if (op->opcode == AML_REGION_OP) {
+ status = acpi_ds_result_stack_push (walk_state);
+ }
+
+ break;
+
+
+ /* most operators with arguments */
+
+ case OPTYPE_MONADIC1:
+ case OPTYPE_DYADIC1:
+ case OPTYPE_MONADIC2:
+ case OPTYPE_MONADIC2_r:
+ case OPTYPE_DYADIC2:
+ case OPTYPE_DYADIC2_r:
+ case OPTYPE_DYADIC2_s:
+ case OPTYPE_RECONFIGURATION:
+ case OPTYPE_INDEX:
+ case OPTYPE_MATCH:
+ case OPTYPE_FATAL:
+ case OPTYPE_CREATE_FIELD:
+
+ /* Start a new result/operand state */
+
+ status = acpi_ds_result_stack_push (walk_state);
+ break;
+
+
+ default:
+ break;
+ }
+
+ /* Nothing to do here during method execution */
+
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_exec_end_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been completed in the
+ * walk; Arguments have now been evaluated.
+ *
+ * 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 (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op)
+{
+ ACPI_STATUS status = AE_OK;
+ u16 opcode;
+ u8 optype;
+ ACPI_PARSE_OBJECT *next_op;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_PARSE_OBJECT *first_arg;
+ ACPI_OPERAND_OBJECT *result_obj = NULL;
+ ACPI_OPCODE_INFO *op_info;
+ u32 operand_index;
+
+
+ opcode = (u16) op->opcode;
+
+
+ op_info = acpi_ps_get_opcode_info (op->opcode);
+ if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) {
+ return (AE_NOT_IMPLEMENTED);
+ }
+
+ optype = (u8) ACPI_GET_OP_CLASS (op_info);
+ first_arg = op->value.arg;
+
+ /* Init the walk state */
+
+ walk_state->num_operands = 0;
+ walk_state->return_desc = NULL;
+ walk_state->op_info = op_info;
+ walk_state->opcode = opcode;
+
+
+ /* Call debugger for single step support (DEBUG build only) */
+
+ DEBUGGER_EXEC (status = acpi_db_single_step (walk_state, op, optype));
+ DEBUGGER_EXEC (if (ACPI_FAILURE (status)) {return (status);});
+
+
+ /* Decode the opcode */
+
+ switch (optype) {
+ case OPTYPE_UNDEFINED:
+
+ return (AE_NOT_IMPLEMENTED);
+ break;
+
+
+ case OPTYPE_BOGUS:
+ break;
+
+ case OPTYPE_CONSTANT: /* argument type only */
+ case OPTYPE_LITERAL: /* argument type only */
+ case OPTYPE_DATA_TERM: /* argument type only */
+ case OPTYPE_LOCAL_VARIABLE: /* argument type only */
+ case OPTYPE_METHOD_ARGUMENT: /* argument type only */
+ break;
+
+
+ /* most operators with arguments */
+
+ case OPTYPE_MONADIC1:
+ case OPTYPE_DYADIC1:
+ case OPTYPE_MONADIC2:
+ case OPTYPE_MONADIC2_r:
+ case OPTYPE_DYADIC2:
+ case OPTYPE_DYADIC2_r:
+ case OPTYPE_DYADIC2_s:
+ case OPTYPE_RECONFIGURATION:
+ case OPTYPE_INDEX:
+ case OPTYPE_MATCH:
+ case OPTYPE_FATAL:
+
+
+ /* Build resolved operand stack */
+
+ status = acpi_ds_create_operands (walk_state, first_arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ operand_index = walk_state->num_operands - 1;
+
+
+ /* Done with this result state (Now that operand stack is built) */
+
+ status = acpi_ds_result_stack_pop (walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ switch (optype) {
+ case OPTYPE_MONADIC1:
+
+ /* 1 Operand, 0 External_result, 0 Internal_result */
+
+ status = acpi_aml_exec_monadic1 (opcode, walk_state);
+ break;
+
+
+ case OPTYPE_MONADIC2:
+
+ /* 1 Operand, 0 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_monadic2 (opcode, walk_state, &result_obj);
+ break;
+
+
+ case OPTYPE_MONADIC2_r:
+
+ /* 1 Operand, 1 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_monadic2_r (opcode, walk_state, &result_obj);
+ break;
+
+
+ case OPTYPE_DYADIC1:
+
+ /* 2 Operands, 0 External_result, 0 Internal_result */
+
+ status = acpi_aml_exec_dyadic1 (opcode, walk_state);
+ break;
+
+
+ case OPTYPE_DYADIC2:
+
+ /* 2 Operands, 0 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_dyadic2 (opcode, walk_state, &result_obj);
+ break;
+
+
+ case OPTYPE_DYADIC2_r:
+
+ /* 2 Operands, 1 or 2 External_results, 1 Internal_result */
+
+ status = acpi_aml_exec_dyadic2_r (opcode, walk_state, &result_obj);
+ break;
+
+
+ case OPTYPE_DYADIC2_s: /* Synchronization Operator */
+
+ /* 2 Operands, 0 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_dyadic2_s (opcode, walk_state, &result_obj);
+ break;
+
+
+ case OPTYPE_INDEX: /* Type 2 opcode with 3 operands */
+
+ /* 3 Operands, 1 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_index (walk_state, &result_obj);
+ break;
+
+
+ case OPTYPE_MATCH: /* Type 2 opcode with 6 operands */
+
+ /* 6 Operands, 0 External_result, 1 Internal_result */
+
+ status = acpi_aml_exec_match (walk_state, &result_obj);
+ break;
+
+
+ case OPTYPE_RECONFIGURATION:
+
+ /* 1 or 2 operands, 0 Internal Result */
+
+ status = acpi_aml_exec_reconfiguration (opcode, walk_state);
+ break;
+
+
+ case OPTYPE_FATAL:
+
+ /* 3 Operands, 0 External_result, 0 Internal_result */
+
+ status = acpi_aml_exec_fatal (walk_state);
+ break;
+ }
+
+ /*
+ * If a result object was returned from above, push it on the
+ * current result stack
+ */
+ if (ACPI_SUCCESS (status) &&
+ result_obj) {
+ status = acpi_ds_result_push (result_obj, walk_state);
+ }
+
+ break;
+
+
+ case OPTYPE_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);
+
+ acpi_ds_result_stack_pop (walk_state);
+ break;
+
+
+ case OPTYPE_METHOD_CALL:
+
+ /*
+ * (AML_METHODCALL) Op->Value->Arg->Node contains
+ * the method Node pointer
+ */
+ /* Next_op points to the op that holds the method name */
+
+ next_op = first_arg;
+ node = next_op->node;
+
+ /* Next_op points to first argument op */
+
+ next_op = next_op->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)) {
+ 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 (status);
+ break;
+
+
+ case OPTYPE_CREATE_FIELD:
+
+ status = acpi_ds_load2_end_op (walk_state, op);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ status = acpi_ds_eval_field_unit_operands (walk_state, op);
+ break;
+
+
+ case OPTYPE_NAMED_OBJECT:
+
+ status = acpi_ds_load2_end_op (walk_state, op);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ switch (op->opcode) {
+ case AML_REGION_OP:
+
+ status = acpi_ds_eval_region_operands (walk_state, op);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ status = acpi_ds_result_stack_pop (walk_state);
+ break;
+
+
+ case AML_METHOD_OP:
+ break;
+
+
+ case AML_ALIAS_OP:
+
+ /* Alias creation was already handled by call
+ to psxload above */
+ break;
+
+
+ default:
+ /* Nothing needs to be done */
+
+ status = AE_OK;
+ break;
+ }
+
+ break;
+
+ default:
+
+ 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_aml_truncate_for32bit_table (result_obj, walk_state);
+
+ /*
+ * Check if we just completed the evaluation of a
+ * conditional predicate
+ */
+
+ if ((walk_state->control_state) &&
+ (walk_state->control_state->common.state ==
+ CONTROL_PREDICATE_EXECUTING) &&
+ (walk_state->control_state->control.predicate_op == op)) {
+ status = acpi_ds_get_predicate_value (walk_state, op, (u32) result_obj);
+ result_obj = NULL;
+ }
+
+
+cleanup:
+ if (result_obj) {
+ /* Break to debugger to display result */
+
+ DEBUGGER_EXEC (acpi_db_display_result_object (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, result_obj, walk_state);
+ }
+
+ /* Always clear the object stack */
+
+ /* TBD: [Investigate] Clear stack of return value,
+ but don't delete it */
+ walk_state->num_operands = 0;
+
+ return (status);
+}
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: dswload - Dispatcher namespace load callbacks
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acparser.h"
+#include "amlcode.h"
+#include "acdispat.h"
+#include "acinterp.h"
+#include "acnamesp.h"
+#include "acevents.h"
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dswload")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_load1_begin_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been reached in the
+ * walk; Arguments have not been evaluated yet.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_load1_begin_op (
+ u16 opcode,
+ ACPI_PARSE_OBJECT *op,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT **out_op)
+{
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_STATUS status;
+ OBJECT_TYPE_INTERNAL data_type;
+ NATIVE_CHAR *path;
+
+
+ /* We are only interested in opcodes that have an associated name */
+
+ if (!acpi_ps_is_named_op (opcode)) {
+ *out_op = op;
+ return (AE_OK);
+ }
+
+
+ /* Check if this object has already been installed in the namespace */
+
+ if (op && op->node) {
+ *out_op = op;
+ return (AE_OK);
+ }
+
+ path = acpi_ps_get_next_namestring (walk_state->parser_state);
+
+ /* Map the raw opcode into an internal object type */
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (opcode);
+
+
+
+ /*
+ * 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,
+ data_type, IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH, walk_state, &(node));
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ if (!op) {
+ /* Create a new op */
+
+ op = acpi_ps_alloc_op (opcode);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+ }
+
+ /* Initialize */
+
+ ((ACPI_PARSE2_OBJECT *)op)->name = node->name;
+
+ /*
+ * Put the Node in the "op" object that the parser uses, so we
+ * can get it again quickly when this scope is closed
+ */
+ op->node = node;
+
+
+ acpi_ps_append_arg (acpi_ps_get_parent_scope (walk_state->parser_state), op);
+
+ *out_op = op;
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_load1_end_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been completed in the
+ * walk; Arguments have now been evaluated.
+ *
+ * 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 (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op)
+{
+ OBJECT_TYPE_INTERNAL data_type;
+
+
+ /* We are only interested in opcodes that have an associated name */
+
+ if (!acpi_ps_is_named_op (op->opcode)) {
+ return (AE_OK);
+ }
+
+
+ /* Get the type to determine if we should pop the scope */
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode);
+
+ if (op->opcode == AML_NAME_OP) {
+ /* For Name opcode, check the argument */
+
+ if (op->value.arg) {
+ data_type = acpi_ds_map_opcode_to_data_type (
+ (op->value.arg)->opcode, NULL);
+ ((ACPI_NAMESPACE_NODE *)op->node)->type =
+ (u8) data_type;
+ }
+ }
+
+
+ /* Pop the scope stack */
+
+ if (acpi_ns_opens_scope (data_type)) {
+
+ acpi_ds_scope_stack_pop (walk_state);
+ }
+
+ return (AE_OK);
+
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_load2_begin_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been reached in the
+ * walk; Arguments have not been evaluated yet.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_load2_begin_op (
+ u16 opcode,
+ ACPI_PARSE_OBJECT *op,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT **out_op)
+{
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_STATUS status;
+ OBJECT_TYPE_INTERNAL data_type;
+ NATIVE_CHAR *buffer_ptr;
+ void *original = NULL;
+
+
+ /* We only care about Namespace opcodes here */
+
+ if (!acpi_ps_is_namespace_op (opcode) &&
+ opcode != AML_NAMEPATH_OP) {
+ return (AE_OK);
+ }
+
+
+ /* Temp! same code as in psparse */
+
+ if (!acpi_ps_is_named_op (opcode)) {
+ return (AE_OK);
+ }
+
+ if (op) {
+ /*
+ * Get the name we are going to enter or lookup in the namespace
+ */
+ if (opcode == AML_NAMEPATH_OP) {
+ /* For Namepath op, get the path string */
+
+ buffer_ptr = op->value.string;
+ if (!buffer_ptr) {
+ /* No name, just exit */
+
+ return (AE_OK);
+ }
+ }
+
+ else {
+ /* Get name from the op */
+
+ buffer_ptr = (NATIVE_CHAR *) &((ACPI_PARSE2_OBJECT *)op)->name;
+ }
+ }
+
+ else {
+ buffer_ptr = acpi_ps_get_next_namestring (walk_state->parser_state);
+ }
+
+
+ /* Map the raw opcode into an internal object type */
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (opcode);
+
+
+ if (opcode == AML_DEF_FIELD_OP ||
+ opcode == AML_BANK_FIELD_OP ||
+ opcode == AML_INDEX_FIELD_OP) {
+ node = NULL;
+ status = AE_OK;
+ }
+
+ else if (opcode == AML_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,
+ data_type, IMODE_EXECUTE,
+ NS_SEARCH_PARENT, walk_state,
+ &(node));
+ }
+
+ else {
+ if (op && op->node) {
+ original = op->node;
+ node = op->node;
+
+ if (acpi_ns_opens_scope (data_type)) {
+ status = acpi_ds_scope_stack_push (node,
+ data_type,
+ walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ }
+ return (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.
+ */
+ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr,
+ data_type, IMODE_EXECUTE,
+ NS_NO_UPSEARCH, walk_state,
+ &(node));
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ if (!op) {
+ /* Create a new op */
+
+ op = acpi_ps_alloc_op (opcode);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Initialize */
+
+ ((ACPI_PARSE2_OBJECT *)op)->name = node->name;
+ *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->node = node;
+
+ }
+
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_load2_end_op
+ *
+ * PARAMETERS: Walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been completed in the
+ * walk; Arguments have now been evaluated.
+ *
+ * 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 (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_PARSE_OBJECT *op)
+{
+ ACPI_STATUS status = AE_OK;
+ OBJECT_TYPE_INTERNAL data_type;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_PARSE_OBJECT *arg;
+ ACPI_NAMESPACE_NODE *new_node;
+
+
+ if (!acpi_ps_is_namespace_object_op (op->opcode)) {
+ return (AE_OK);
+ }
+
+ if (op->opcode == AML_SCOPE_OP) {
+ if (((ACPI_PARSE2_OBJECT *)op)->name == -1) {
+ return (AE_OK);
+ }
+ }
+
+
+ data_type = acpi_ds_map_named_opcode_to_data_type (op->opcode);
+
+ /*
+ * Get the Node/name from the earlier lookup
+ * (It was saved in the *op structure)
+ */
+ node = op->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 (data_type)) {
+
+ acpi_ds_scope_stack_pop (walk_state);
+ }
+
+
+ /*
+ * Named operations are as follows:
+ *
+ * AML_SCOPE
+ * AML_DEVICE
+ * AML_THERMALZONE
+ * AML_METHOD
+ * AML_POWERRES
+ * AML_PROCESSOR
+ * AML_FIELD
+ * AML_INDEXFIELD
+ * AML_BANKFIELD
+ * AML_NAMEDFIELD
+ * AML_NAME
+ * AML_ALIAS
+ * AML_MUTEX
+ * AML_EVENT
+ * AML_OPREGION
+ * AML_CREATEFIELD
+ * AML_CREATEBITFIELD
+ * AML_CREATEBYTEFIELD
+ * AML_CREATEWORDFIELD
+ * AML_CREATEDWORDFIELD
+ * AML_METHODCALL
+ */
+
+
+ /* Decode the opcode */
+
+ arg = op->value.arg;
+
+ switch (op->opcode) {
+
+ case AML_CREATE_FIELD_OP:
+ case AML_BIT_FIELD_OP:
+ case AML_BYTE_FIELD_OP:
+ case AML_WORD_FIELD_OP:
+ case AML_DWORD_FIELD_OP:
+
+ /*
+ * Create the field object, but the field buffer and index must
+ * be evaluated later during the execution phase
+ */
+
+ /* Get the Name_string argument */
+
+ if (op->opcode == AML_CREATE_FIELD_OP) {
+ arg = acpi_ps_get_arg (op, 3);
+ }
+ else {
+ /* Create Bit/Byte/Word/Dword field */
+
+ arg = acpi_ps_get_arg (op, 2);
+ }
+
+ /*
+ * Enter the Name_string into the namespace
+ */
+
+ status = acpi_ns_lookup (walk_state->scope_info,
+ arg->value.string,
+ INTERNAL_TYPE_DEF_ANY,
+ IMODE_LOAD_PASS1,
+ NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE,
+ walk_state, &(new_node));
+
+ if (ACPI_SUCCESS (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->node = new_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.
+ */
+ if (!new_node->object) {
+ /*
+ * The Field definition is not fully parsed at this time.
+ * (We must save the address of the AML for the buffer and index operands)
+ */
+ status = acpi_aml_exec_create_field (((ACPI_PARSE2_OBJECT *) op)->data,
+ ((ACPI_PARSE2_OBJECT *) op)->length,
+ new_node, walk_state);
+ }
+ }
+
+
+ break;
+
+
+ case AML_METHODCALL_OP:
+
+ /*
+ * Lookup the method name and save the Node
+ */
+
+ status = acpi_ns_lookup (walk_state->scope_info, arg->value.string,
+ ACPI_TYPE_ANY, IMODE_LOAD_PASS2,
+ NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE,
+ walk_state, &(new_node));
+
+ if (ACPI_SUCCESS (status)) {
+
+/* has name already been resolved by here ??*/
+
+ /* TBD: [Restructure] 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! */
+
+ /* 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->node = new_node;
+ }
+
+
+ break;
+
+
+ case AML_PROCESSOR_OP:
+
+ /* Nothing to do other than enter object into namespace */
+
+ status = acpi_aml_exec_create_processor (op, (ACPI_HANDLE) node);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ break;
+
+
+ case AML_POWER_RES_OP:
+
+ /* Nothing to do other than enter object into namespace */
+
+ status = acpi_aml_exec_create_power_resource (op, (ACPI_HANDLE) node);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ break;
+
+
+ case AML_THERMAL_ZONE_OP:
+
+ /* Nothing to do other than enter object into namespace */
+
+ break;
+
+
+ case AML_DEF_FIELD_OP:
+
+ arg = op->value.arg;
+
+ status = acpi_ds_create_field (op, arg->node, walk_state);
+ break;
+
+
+ case AML_INDEX_FIELD_OP:
+
+ arg = op->value.arg;
+
+ status = acpi_ds_create_index_field (op, (ACPI_HANDLE) arg->node,
+ walk_state);
+ break;
+
+
+ case AML_BANK_FIELD_OP:
+
+ arg = op->value.arg;
+ status = acpi_ds_create_bank_field (op, arg->node, walk_state);
+ break;
+
+
+ /*
+ * Method_op Pkg_length Names_string Method_flags Term_list
+ */
+ case AML_METHOD_OP:
+
+ if (!node->object) {
+ status = acpi_aml_exec_create_method (((ACPI_PARSE2_OBJECT *) op)->data,
+ ((ACPI_PARSE2_OBJECT *) op)->length,
+ arg->value.integer, (ACPI_HANDLE) node);
+ }
+
+ break;
+
+
+ case AML_MUTEX_OP:
+
+ status = acpi_ds_create_operands (walk_state, arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_aml_exec_create_mutex (walk_state);
+ break;
+
+
+ case AML_EVENT_OP:
+
+ status = acpi_ds_create_operands (walk_state, arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_aml_exec_create_event (walk_state);
+ break;
+
+
+ case AML_REGION_OP:
+
+ if (node->object) {
+ break;
+ }
+
+
+ /*
+ * 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)
+ */
+
+ status = acpi_aml_exec_create_region (((ACPI_PARSE2_OBJECT *) op)->data,
+ ((ACPI_PARSE2_OBJECT *) op)->length,
+ (ACPI_ADDRESS_SPACE_TYPE) arg->value.integer,
+ walk_state);
+
+ break;
+
+
+ /* Namespace Modifier Opcodes */
+
+ case AML_ALIAS_OP:
+
+ status = acpi_ds_create_operands (walk_state, arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_aml_exec_create_alias (walk_state);
+ break;
+
+
+ case AML_NAME_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 (!node->object) {
+ status = acpi_ds_create_node (walk_state, node, op);
+ }
+
+ break;
+
+
+ case AML_NAMEPATH_OP:
+
+ break;
+
+
+ default:
+ break;
+ }
+
+
+cleanup:
+
+ /* Remove the Node pushed at the very beginning */
+
+ acpi_ds_obj_stack_pop (1, walk_state);
+ return (status);
+}
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: dswscope - Scope stack manipulation
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acinterp.h"
+#include "acdispat.h"
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dswscope")
+
+
+#define STACK_POP(head) head
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_scope_stack_clear
+ *
+ * PARAMETERS: 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 (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *scope_info;
+
+
+ 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_cm_delete_generic_state (scope_info);
+ }
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_scope_stack_push
+ *
+ * PARAMETERS: *Node, - Name to be made current
+ * Type, - Type of frame being pushed
+ *
+ * DESCRIPTION: Push the current scope on the scope stack, and make the
+ * passed Node current.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ds_scope_stack_push (
+ ACPI_NAMESPACE_NODE *node,
+ OBJECT_TYPE_INTERNAL type,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *scope_info;
+
+
+ if (!node) {
+ /* invalid scope */
+
+ REPORT_ERROR (("Ds_scope_stack_push: null scope passed\n"));
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Make sure object type is valid */
+
+ if (!acpi_aml_validate_object_type (type)) {
+ REPORT_WARNING (("Ds_scope_stack_push: type code out of range\n"));
+ }
+
+
+ /* Allocate a new scope object */
+
+ scope_info = acpi_cm_create_generic_state ();
+ if (!scope_info) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Init new scope object */
+
+ scope_info->scope.node = node;
+ scope_info->common.value = (u16) type;
+
+ /* Push new scope object onto stack */
+
+ acpi_cm_push_generic_state (&walk_state->scope_info, scope_info);
+
+ return (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ds_scope_stack_pop
+ *
+ * PARAMETERS: Type - The type of frame to be found
+ *
+ * DESCRIPTION: Pop the scope stack until a frame of the requested type
+ * is found.
+ *
+ * RETURN: Count of frames popped. If no frame of the requested type
+ * was found, the count is returned as a negative number and
+ * the scope stack is emptied (which sets the current scope
+ * to the root). If the scope stack was empty at entry, the
+ * function is a no-op and returns 0.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ds_scope_stack_pop (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *scope_info;
+
+
+ /*
+ * Pop scope info object off the stack.
+ */
+
+ scope_info = acpi_cm_pop_generic_state (&walk_state->scope_info);
+ if (!scope_info) {
+ return (AE_STACK_UNDERFLOW);
+ }
+
+ acpi_cm_delete_generic_state (scope_info);
+
+ return (AE_OK);
+}
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: dswstate - Dispatcher parse tree walk management routines
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "amlcode.h"
+#include "acparser.h"
+#include "acdispat.h"
+#include "acnamesp.h"
+#include "acinterp.h"
+
+#define _COMPONENT ACPI_DISPATCHER
+ MODULE_NAME ("dswstate")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_result_insert
+ *
+ * PARAMETERS: Object - Object to push
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push an object onto this walk's result stack
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_result_insert (
+ void *object,
+ u32 index,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ state = walk_state->results;
+ if (!state) {
+ return (AE_NOT_EXIST);
+ }
+
+ if (index >= OBJ_NUM_OPERANDS) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (!object) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ state->results.obj_desc [index] = object;
+ state->results.num_results++;
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_result_remove
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
+ * other words, this is a FIFO.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_result_remove (
+ ACPI_OPERAND_OBJECT **object,
+ u32 index,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ state = walk_state->results;
+ if (!state) {
+ return (AE_NOT_EXIST);
+ }
+
+
+
+ /* Check for a valid result object */
+
+ if (!state->results.obj_desc [index]) {
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+ /* Remove the object */
+
+ state->results.num_results--;
+
+ *object = state->results.obj_desc [index];
+ state->results.obj_desc [index] = NULL;
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * 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 bottom of this walk's result stack. In
+ * other words, this is a FIFO.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_result_pop (
+ ACPI_OPERAND_OBJECT **object,
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 index;
+ ACPI_GENERIC_STATE *state;
+
+
+ state = walk_state->results;
+ if (!state) {
+ return (AE_OK);
+ }
+
+
+ if (!state->results.num_results) {
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+ /* Remove top element */
+
+ state->results.num_results--;
+
+ for (index = OBJ_NUM_OPERANDS; index; index--) {
+ /* Check for a valid result object */
+
+ if (state->results.obj_desc [index -1]) {
+ *object = state->results.obj_desc [index -1];
+ state->results.obj_desc [index -1] = NULL;
+
+ return (AE_OK);
+ }
+ }
+
+
+ return (AE_AML_NO_RETURN_VALUE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_result_pop_from_bottom
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
+ * other words, this is a FIFO.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_result_pop_from_bottom (
+ ACPI_OPERAND_OBJECT **object,
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 index;
+ ACPI_GENERIC_STATE *state;
+
+
+ state = walk_state->results;
+ if (!state) {
+ return (AE_NOT_EXIST);
+ }
+
+
+ if (!state->results.num_results) {
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+ /* Remove Bottom element */
+
+ *object = state->results.obj_desc [0];
+
+
+ /* Push entire stack down one element */
+
+ for (index = 0; index < state->results.num_results; index++) {
+ state->results.obj_desc [index] = state->results.obj_desc [index + 1];
+ }
+
+ state->results.num_results--;
+
+ /* Check for a valid result object */
+
+ if (!*object) {
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+
+ 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 (
+ ACPI_OPERAND_OBJECT *object,
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ state = walk_state->results;
+ if (!state) {
+ return (AE_AML_INTERNAL);
+ }
+
+ if (state->results.num_results == OBJ_NUM_OPERANDS) {
+ return (AE_STACK_OVERFLOW);
+ }
+
+ if (!object) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ state->results.obj_desc [state->results.num_results] = object;
+ state->results.num_results++;
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_result_stack_push
+ *
+ * PARAMETERS: Object - Object to push
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION:
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_result_stack_push (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ state = acpi_cm_create_generic_state ();
+ if (!state) {
+ return (AE_NO_MEMORY);
+ }
+
+ acpi_cm_push_generic_state (&walk_state->results, state);
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_result_stack_pop
+ *
+ * PARAMETERS: Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION:
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_result_stack_pop (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ /* Check for stack underflow */
+
+ if (walk_state->results == NULL) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+
+ state = acpi_cm_pop_generic_state (&walk_state->results);
+
+ acpi_cm_delete_generic_state (state);
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_obj_stack_delete_all
+ *
+ * PARAMETERS: Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear the object stack by deleting all objects that are on it.
+ * Should be used with great care, if at all!
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_obj_stack_delete_all (
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 i;
+
+
+ /* The stack size is configurable, but fixed */
+
+ for (i = 0; i < OBJ_NUM_OPERANDS; i++) {
+ if (walk_state->operands[i]) {
+ acpi_cm_remove_reference (walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
+ }
+ }
+
+ 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,
+ ACPI_WALK_STATE *walk_state)
+{
+
+
+ /* Check for stack overflow */
+
+ if (walk_state->num_operands >= OBJ_NUM_OPERANDS) {
+ return (AE_STACK_OVERFLOW);
+ }
+
+ /* Put the object onto the stack */
+
+ walk_state->operands [walk_state->num_operands] = object;
+ walk_state->num_operands++;
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_obj_stack_pop_object
+ *
+ * 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_object (
+ ACPI_OPERAND_OBJECT **object,
+ ACPI_WALK_STATE *walk_state)
+{
+
+
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+
+ /* Pop the stack */
+
+ walk_state->num_operands--;
+
+ /* Check for a valid operand */
+
+ if (!walk_state->operands [walk_state->num_operands]) {
+ return (AE_AML_NO_OPERAND);
+ }
+
+ /* Get operand and set stack entry to null */
+
+ *object = walk_state->operands [walk_state->num_operands];
+ walk_state->operands [walk_state->num_operands] = NULL;
+
+ 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,
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 i;
+
+
+ for (i = 0; i < pop_count; i++) {
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ return (AE_STACK_UNDERFLOW);
+ }
+
+ /* Just set the stack entry to null */
+
+ walk_state->num_operands--;
+ walk_state->operands [walk_state->num_operands] = NULL;
+ }
+
+ 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.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ds_obj_stack_pop_and_delete (
+ u32 pop_count,
+ ACPI_WALK_STATE *walk_state)
+{
+ u32 i;
+ ACPI_OPERAND_OBJECT *obj_desc;
+
+
+ for (i = 0; i < pop_count; i++) {
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ return (AE_STACK_UNDERFLOW);
+ }
+
+ /* Pop the stack and delete an object if present in this stack entry */
+
+ walk_state->num_operands--;
+ obj_desc = walk_state->operands [walk_state->num_operands];
+ if (obj_desc) {
+ acpi_cm_remove_reference (walk_state->operands [walk_state->num_operands]);
+ walk_state->operands [walk_state->num_operands] = NULL;
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_obj_stack_get_value
+ *
+ * PARAMETERS: Index - Stack index whose value is desired. Based
+ * on the top of the stack (index=0 == top)
+ * Walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve an object from this walk's object stack. Index must
+ * be within the range of the current stack pointer.
+ *
+ ******************************************************************************/
+
+void *
+acpi_ds_obj_stack_get_value (
+ u32 index,
+ ACPI_WALK_STATE *walk_state)
+{
+
+
+ /* Can't do it if the stack is empty */
+
+ if (walk_state->num_operands == 0) {
+ return (NULL);
+ }
+
+ /* or if the index is past the top of the stack */
+
+ if (index > (walk_state->num_operands - (u32) 1)) {
+ return (NULL);
+ }
+
+
+ return (walk_state->operands[(NATIVE_UINT)(walk_state->num_operands - 1) -
+ index]);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_get_current_walk_state
+ *
+ * PARAMETERS: Walk_list - Get current active state for this walk list
+ *
+ * RETURN: Pointer to the current walk state
+ *
+ * DESCRIPTION: Get the walk state that is at the head of the list (the "current"
+ * walk state.
+ *
+ ******************************************************************************/
+
+ACPI_WALK_STATE *
+acpi_ds_get_current_walk_state (
+ ACPI_WALK_LIST *walk_list)
+
+{
+
+ if (!walk_list) {
+ return (NULL);
+ }
+
+ return (walk_list->walk_state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_push_walk_state
+ *
+ * PARAMETERS: Walk_state - State to push
+ * Walk_list - The list that owns the walk stack
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Place the Walk_state at the head of the state list.
+ *
+ ******************************************************************************/
+
+static void
+acpi_ds_push_walk_state (
+ ACPI_WALK_STATE *walk_state,
+ ACPI_WALK_LIST *walk_list)
+{
+
+
+ walk_state->next = walk_list->walk_state;
+ walk_list->walk_state = walk_state;
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_pop_walk_state
+ *
+ * PARAMETERS: Walk_list - The list that owns the walk stack
+ *
+ * RETURN: A Walk_state object popped from the 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.
+ *
+ ******************************************************************************/
+
+ACPI_WALK_STATE *
+acpi_ds_pop_walk_state (
+ ACPI_WALK_LIST *walk_list)
+{
+ ACPI_WALK_STATE *walk_state;
+
+
+ walk_state = walk_list->walk_state;
+
+ if (walk_state) {
+ /* Next walk state becomes the current walk state */
+
+ walk_list->walk_state = walk_state->next;
+
+ /*
+ * Don't clear the NEXT field, this serves as an indicator
+ * that there is a parent WALK STATE
+ * Walk_state->Next = NULL;
+ */
+ }
+
+ return (walk_state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_create_walk_state
+ *
+ * PARAMETERS: Origin - Starting point for this walk
+ * Walk_list - Owning walk list
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+ACPI_WALK_STATE *
+acpi_ds_create_walk_state (
+ ACPI_OWNER_ID owner_id,
+ ACPI_PARSE_OBJECT *origin,
+ ACPI_OPERAND_OBJECT *mth_desc,
+ ACPI_WALK_LIST *walk_list)
+{
+ ACPI_WALK_STATE *walk_state;
+ ACPI_STATUS status;
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+ acpi_gbl_walk_state_cache_requests++;
+
+ /* Check the cache first */
+
+ if (acpi_gbl_walk_state_cache) {
+ /* There is an object available, use it */
+
+ walk_state = acpi_gbl_walk_state_cache;
+ acpi_gbl_walk_state_cache = walk_state->next;
+
+ acpi_gbl_walk_state_cache_hits++;
+ acpi_gbl_walk_state_cache_depth--;
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+ }
+
+ else {
+ /* The cache is empty, create a new object */
+
+ /* Avoid deadlock with Acpi_cm_callocate */
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+
+ walk_state = acpi_cm_callocate (sizeof (ACPI_WALK_STATE));
+ if (!walk_state) {
+ return (NULL);
+ }
+ }
+
+ walk_state->data_type = ACPI_DESC_TYPE_WALK;
+ walk_state->owner_id = owner_id;
+ walk_state->origin = origin;
+ walk_state->method_desc = mth_desc;
+ walk_state->walk_list = walk_list;
+
+ /* Init the method args/local */
+
+#ifndef _ACPI_ASL_COMPILER
+ acpi_ds_method_data_init (walk_state);
+#endif
+
+ /* Create an initial result stack entry */
+
+ status = acpi_ds_result_stack_push (walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (NULL);
+ }
+
+
+ /* Put the new state at the head of the walk list */
+
+ acpi_ds_push_walk_state (walk_state, walk_list);
+
+ return (walk_state);
+}
+
+
+/*******************************************************************************
+ *
+ * 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 (
+ ACPI_WALK_STATE *walk_state)
+{
+ ACPI_GENERIC_STATE *state;
+
+
+ if (!walk_state) {
+ return;
+ }
+
+ if (walk_state->data_type != ACPI_DESC_TYPE_WALK) {
+ return;
+ }
+
+
+ /* 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_cm_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_cm_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_cm_delete_generic_state (state);
+ }
+
+
+ /* If walk cache is full, just free this wallkstate object */
+
+ if (acpi_gbl_walk_state_cache_depth >= MAX_WALK_CACHE_DEPTH) {
+ acpi_cm_free (walk_state);
+ }
+
+ /* Otherwise put this object back into the cache */
+
+ else {
+ acpi_cm_acquire_mutex (ACPI_MTX_CACHES);
+
+ /* Clear the state */
+
+ MEMSET (walk_state, 0, sizeof (ACPI_WALK_STATE));
+ walk_state->data_type = ACPI_DESC_TYPE_WALK;
+
+ /* Put the object at the head of the global cache list */
+
+ walk_state->next = acpi_gbl_walk_state_cache;
+ acpi_gbl_walk_state_cache = walk_state;
+ acpi_gbl_walk_state_cache_depth++;
+
+
+ acpi_cm_release_mutex (ACPI_MTX_CACHES);
+ }
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ds_delete_walk_state_cache
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Purge the global state object cache. Used during subsystem
+ * termination.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_delete_walk_state_cache (
+ void)
+{
+ ACPI_WALK_STATE *next;
+
+
+ /* Traverse the global cache list */
+
+ while (acpi_gbl_walk_state_cache) {
+ /* Delete one cached state object */
+
+ next = acpi_gbl_walk_state_cache->next;
+ acpi_cm_free (acpi_gbl_walk_state_cache);
+ acpi_gbl_walk_state_cache = next;
+ acpi_gbl_walk_state_cache_depth--;
+ }
+
+ return;
+}
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: evevent - Fixed and General Purpose Acpi_event
+ * handling and dispatch
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "acpi.h"
+#include "achware.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "accommon.h"
+
+#define _COMPONENT ACPI_EVENTS
+ MODULE_NAME ("evevent")
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ensures that the system control interrupt (SCI) is properly
+ * configured, disables SCI event sources, installs the SCI
+ * handler
+ *
+ *************************************************************************/
+
+ACPI_STATUS
+acpi_ev_initialize (
+ void)
+{
+ ACPI_STATUS status;
+
+
+ /* Make sure we have ACPI tables */
+
+ if (!acpi_gbl_DSDT) {
+ return (AE_NO_ACPI_TABLES);
+ }
+
+
+ /* Make sure the BIOS supports ACPI mode */
+
+ if (SYS_MODE_LEGACY == acpi_hw_get_mode_capabilities()) {
+ return (AE_ERROR);
+ }
+
+
+ acpi_gbl_original_mode = acpi_hw_get_mode();
+
+ /*
+ * Initialize the Fixed and General Purpose Acpi_events prior. This is
+ * done prior to enabling SCIs to prevent interrupts from occuring
+ * before handers are installed.
+ */
+
+ status = acpi_ev_fixed_event_initialize ();
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ status = acpi_ev_gpe_initialize ();
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Install the SCI handler */
+
+ status = acpi_ev_install_sci_handler ();
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+ /* Install handlers for control method GPE handlers (_Lxx, _Exx) */
+
+ status = acpi_ev_init_gpe_control_methods ();
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Install the handler for the Global Lock */
+
+ status = acpi_ev_init_global_lock_handler ();
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_fixed_event_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the Fixed Acpi_event data structures
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_fixed_event_initialize(void)
+{
+ int i = 0;
+
+ /* Initialize the structure that keeps track of fixed event handlers */
+
+ for (i = 0; i < NUM_FIXED_EVENTS; i++) {
+ acpi_gbl_fixed_event_handlers[i].handler = NULL;
+ acpi_gbl_fixed_event_handlers[i].context = NULL;
+ }
+
+ acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, TMR_EN, 0);
+ acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, GBL_EN, 0);
+ acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, PWRBTN_EN, 0);
+ acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, SLPBTN_EN, 0);
+ acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK, RTC_EN, 0);
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_fixed_event_detect
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Checks the PM status register for fixed events
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_fixed_event_detect(void)
+{
+ u32 int_status = INTERRUPT_NOT_HANDLED;
+ u32 status_register;
+ u32 enable_register;
+
+ /*
+ * Read the fixed feature status and enable registers, as all the cases
+ * depend on their values.
+ */
+
+ status_register = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_STS);
+ enable_register = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, PM1_EN);
+
+
+ /* power management timer roll over */
+
+ if ((status_register & ACPI_STATUS_PMTIMER) &&
+ (enable_register & ACPI_ENABLE_PMTIMER)) {
+ int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_PMTIMER);
+ }
+
+ /* global event (BIOS want's the global lock) */
+
+ if ((status_register & ACPI_STATUS_GLOBAL) &&
+ (enable_register & ACPI_ENABLE_GLOBAL)) {
+ int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_GLOBAL);
+ }
+
+ /* power button event */
+
+ if ((status_register & ACPI_STATUS_POWER_BUTTON) &&
+ (enable_register & ACPI_ENABLE_POWER_BUTTON)) {
+ int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_POWER_BUTTON);
+ }
+
+ /* sleep button event */
+
+ if ((status_register & ACPI_STATUS_SLEEP_BUTTON) &&
+ (enable_register & ACPI_ENABLE_SLEEP_BUTTON)) {
+ int_status |= acpi_ev_fixed_event_dispatch (ACPI_EVENT_SLEEP_BUTTON);
+ }
+
+ return (int_status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_fixed_event_dispatch
+ *
+ * PARAMETERS: Event - Event type
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Clears the status bit for the requested event, calls the
+ * handler that previously registered for the event.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_fixed_event_dispatch (
+ u32 event)
+{
+ u32 register_id;
+
+ /* Clear the status bit */
+
+ switch (event) {
+ case ACPI_EVENT_PMTIMER:
+ register_id = TMR_STS;
+ break;
+
+ case ACPI_EVENT_GLOBAL:
+ register_id = GBL_STS;
+ break;
+
+ case ACPI_EVENT_POWER_BUTTON:
+ register_id = PWRBTN_STS;
+ break;
+
+ case ACPI_EVENT_SLEEP_BUTTON:
+ register_id = SLPBTN_STS;
+ break;
+
+ case ACPI_EVENT_RTC:
+ register_id = RTC_STS;
+ break;
+
+ default:
+ return 0;
+ break;
+ }
+
+ acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK, register_id, 1);
+
+ /*
+ * Make sure we've got a handler. If not, report an error.
+ * The event is disabled to prevent further interrupts.
+ */
+ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
+ register_id = (PM1_EN | REGISTER_BIT_ID(register_id));
+
+ acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_DO_NOT_LOCK,
+ register_id, 0);
+
+ REPORT_ERROR (
+ ("Ev_gpe_dispatch: No installed handler for fixed event [%08X]\n",
+ event));
+
+ return (INTERRUPT_NOT_HANDLED);
+ }
+
+ /* Invoke the handler */
+
+ return ((acpi_gbl_fixed_event_handlers[event].handler)(
+ acpi_gbl_fixed_event_handlers[event].context));
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_gpe_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the GPE data structures
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_gpe_initialize (void)
+{
+ u32 i;
+ u32 j;
+ u32 register_index;
+ u32 gpe_number;
+ u16 gpe0register_count;
+ u16 gpe1_register_count;
+
+
+ /*
+ * Set up various GPE counts
+ *
+ * You may ask,why are the GPE register block lengths divided by 2?
+ * From the ACPI 2.0 Spec, section, 4.7.1.6 General-Purpose Event
+ * Registers, we have,
+ *
+ * "Each register block contains two registers of equal length
+ * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the
+ * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN
+ * The length of the GPE1_STS and GPE1_EN registers is equal to
+ * half the GPE1_LEN. If a generic register block is not supported
+ * then its respective block pointer and block length values in the
+ * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need
+ * to be the same size."
+ */
+
+ gpe0register_count = (u16) DIV_2 (acpi_gbl_FADT->gpe0blk_len);
+ gpe1_register_count = (u16) DIV_2 (acpi_gbl_FADT->gpe1_blk_len);
+ acpi_gbl_gpe_register_count = gpe0register_count + gpe1_register_count;
+
+ if (!acpi_gbl_gpe_register_count) {
+ REPORT_WARNING (("Zero GPEs are defined in the FADT\n"));
+ return (AE_OK);
+ }
+
+ /*
+ * Allocate the Gpe information block
+ */
+
+ acpi_gbl_gpe_registers = acpi_cm_callocate (acpi_gbl_gpe_register_count *
+ sizeof (ACPI_GPE_REGISTERS));
+ if (!acpi_gbl_gpe_registers) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Allocate the Gpe dispatch handler block
+ * There are eight distinct GP events per register.
+ * Initialization to zeros is sufficient
+ */
+
+ acpi_gbl_gpe_info = acpi_cm_callocate (MUL_8 (acpi_gbl_gpe_register_count) *
+ sizeof (ACPI_GPE_LEVEL_INFO));
+ if (!acpi_gbl_gpe_info) {
+ acpi_cm_free (acpi_gbl_gpe_registers);
+ return (AE_NO_MEMORY);
+ }
+
+ /* Set the Gpe validation table to GPE_INVALID */
+
+ MEMSET (acpi_gbl_gpe_valid, (int) ACPI_GPE_INVALID, NUM_GPE);
+
+ /*
+ * Initialize the Gpe information and validation blocks. A goal of these
+ * blocks is to hide the fact that there are two separate GPE register sets
+ * In a given block, the status registers occupy the first half, and
+ * the enable registers occupy the second half.
+ */
+
+ /* GPE Block 0 */
+
+ register_index = 0;
+
+ for (i = 0; i < gpe0register_count; i++) {
+ acpi_gbl_gpe_registers[register_index].status_addr =
+ (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + i);
+
+ acpi_gbl_gpe_registers[register_index].enable_addr =
+ (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe0blk.address) + i + gpe0register_count);
+
+ acpi_gbl_gpe_registers[register_index].gpe_base = (u8) MUL_8 (i);
+
+ for (j = 0; j < 8; j++) {
+ gpe_number = acpi_gbl_gpe_registers[register_index].gpe_base + j;
+ acpi_gbl_gpe_valid[gpe_number] = (u8) register_index;
+ }
+
+ /*
+ * Clear the status/enable registers. Note that status registers
+ * are cleared by writing a '1', while enable registers are cleared
+ * by writing a '0'.
+ */
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].enable_addr, 0x00);
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].status_addr, 0xFF);
+
+ register_index++;
+ }
+
+ /* GPE Block 1 */
+
+ for (i = 0; i < gpe1_register_count; i++) {
+ acpi_gbl_gpe_registers[register_index].status_addr =
+ (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + i);
+
+ acpi_gbl_gpe_registers[register_index].enable_addr =
+ (u16) (ACPI_GET_ADDRESS (acpi_gbl_FADT->Xgpe1_blk.address) + i + gpe1_register_count);
+
+ acpi_gbl_gpe_registers[register_index].gpe_base =
+ (u8) (acpi_gbl_FADT->gpe1_base + MUL_8 (i));
+
+ for (j = 0; j < 8; j++) {
+ gpe_number = acpi_gbl_gpe_registers[register_index].gpe_base + j;
+ acpi_gbl_gpe_valid[gpe_number] = (u8) register_index;
+ }
+
+ /*
+ * Clear the status/enable registers. Note that status registers
+ * are cleared by writing a '1', while enable registers are cleared
+ * by writing a '0'.
+ */
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].enable_addr, 0x00);
+ acpi_os_out8 (acpi_gbl_gpe_registers[register_index].status_addr, 0xFF);
+
+ register_index++;
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_save_method_info
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Called from Acpi_walk_namespace. Expects each object to be a
+ * control method under the _GPE portion of the namespace.
+ * Extract the name and GPE type from the object, saving this
+ * information for quick lookup during GPE dispatch
+ *
+ * The name of each GPE control method is of the form:
+ * "_Lnn" or "_Enn"
+ * Where:
+ * L - means that the GPE is level triggered
+ * E - means that the GPE is edge triggered
+ * nn - is the GPE number
+ *
+ ******************************************************************************/
+
+static ACPI_STATUS
+acpi_ev_save_method_info (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *obj_desc,
+ void **return_value)
+{
+ u32 gpe_number;
+ NATIVE_CHAR name[ACPI_NAME_SIZE + 1];
+ u8 type;
+
+
+ /* Extract the name from the object and convert to a string */
+
+ MOVE_UNALIGNED32_TO_32 (name, &((ACPI_NAMESPACE_NODE *) obj_handle)->name);
+ name[ACPI_NAME_SIZE] = 0;
+
+ /*
+ * Edge/Level determination is based on the 2nd s8 of the method name
+ */
+ if (name[1] == 'L') {
+ type = ACPI_EVENT_LEVEL_TRIGGERED;
+ }
+ else if (name[1] == 'E') {
+ type = ACPI_EVENT_EDGE_TRIGGERED;
+ }
+ else {
+ /* Unknown method type, just ignore it! */
+
+ return (AE_OK);
+ }
+
+ /* Convert the last two characters of the name to the Gpe Number */
+
+ gpe_number = STRTOUL (&name[2], NULL, 16);
+ if (gpe_number == ACPI_UINT32_MAX) {
+ /* Conversion failed; invalid method, just ignore it */
+
+ return (AE_OK);
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
+ /* Not valid, all we can do here is ignore it */
+
+ return (AE_OK);
+ }
+
+ /*
+ * Now we can add this information to the Gpe_info block
+ * for use during dispatch of this GPE.
+ */
+
+ acpi_gbl_gpe_info [gpe_number].type = type;
+ acpi_gbl_gpe_info [gpe_number].method_handle = obj_handle;
+
+
+ /*
+ * Enable the GPE (SCIs should be disabled at this point)
+ */
+
+ acpi_hw_enable_gpe (gpe_number);
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_init_gpe_control_methods
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Obtain the control methods associated with the GPEs.
+ *
+ * NOTE: Must be called AFTER namespace initialization!
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_init_gpe_control_methods (void)
+{
+ ACPI_STATUS status;
+
+
+ /* Get a permanent handle to the _GPE object */
+
+ status = acpi_get_handle (NULL, "\\_GPE", &acpi_gbl_gpe_obj_handle);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Traverse the namespace under \_GPE to find all methods there */
+
+ status = acpi_walk_namespace (ACPI_TYPE_METHOD, acpi_gbl_gpe_obj_handle,
+ ACPI_UINT32_MAX, acpi_ev_save_method_info,
+ NULL, NULL);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_gpe_detect
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Detect if any GP events have occurred
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_gpe_detect (void)
+{
+ u32 int_status = INTERRUPT_NOT_HANDLED;
+ u32 i;
+ u32 j;
+ u8 enabled_status_byte;
+ u8 bit_mask;
+
+
+ /*
+ * Read all of the 8-bit GPE status and enable registers
+ * in both of the register blocks, saving all of it.
+ * Find all currently active GP events.
+ */
+
+ for (i = 0; i < acpi_gbl_gpe_register_count; i++) {
+ acpi_gbl_gpe_registers[i].status =
+ acpi_os_in8 (acpi_gbl_gpe_registers[i].status_addr);
+
+ acpi_gbl_gpe_registers[i].enable =
+ acpi_os_in8 (acpi_gbl_gpe_registers[i].enable_addr);
+
+ /* First check if there is anything active at all in this register */
+
+ enabled_status_byte = (u8) (acpi_gbl_gpe_registers[i].status &
+ acpi_gbl_gpe_registers[i].enable);
+
+ if (!enabled_status_byte) {
+ /* No active GPEs in this register, move on */
+
+ continue;
+ }
+
+ /* Now look at the individual GPEs in this byte register */
+
+ for (j = 0, bit_mask = 1; j < 8; j++, bit_mask <<= 1) {
+ /* Examine one GPE bit */
+
+ if (enabled_status_byte & bit_mask) {
+ /*
+ * Found an active GPE. Dispatch the event to a handler
+ * or method.
+ */
+ int_status |=
+ acpi_ev_gpe_dispatch (acpi_gbl_gpe_registers[i].gpe_base + j);
+ }
+ }
+ }
+
+ return (int_status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_asynch_execute_gpe_method
+ *
+ * PARAMETERS: Gpe_number - The 0-based Gpe number
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Perform the actual execution of a GPE control method. This
+ * function is called from an invocation of Acpi_os_queue_for_execution
+ * (and therefore does NOT execute at interrupt level) so that
+ * the control method itself is not executed in the context of
+ * the SCI interrupt handler.
+ *
+ ******************************************************************************/
+
+static void
+acpi_ev_asynch_execute_gpe_method (
+ void *context)
+{
+ u32 gpe_number = (u32) context;
+ ACPI_GPE_LEVEL_INFO gpe_info;
+
+
+ /*
+ * Take a snapshot of the GPE info for this level
+ */
+ acpi_cm_acquire_mutex (ACPI_MTX_EVENTS);
+ gpe_info = acpi_gbl_gpe_info [gpe_number];
+ acpi_cm_release_mutex (ACPI_MTX_EVENTS);
+
+ /*
+ * Method Handler (_Lxx, _Exx):
+ * ----------------------------
+ * Evaluate the _Lxx/_Exx control method that corresponds to this GPE.
+ */
+ if (gpe_info.method_handle) {
+ acpi_ns_evaluate_by_handle (gpe_info.method_handle, NULL, NULL);
+ }
+
+ /*
+ * Level-Triggered?
+ * ----------------
+ * If level-triggered we clear the GPE status bit after handling the event.
+ */
+ if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) {
+ acpi_hw_clear_gpe (gpe_number);
+ }
+
+ /*
+ * Enable the GPE.
+ */
+ acpi_hw_enable_gpe (gpe_number);
+
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_gpe_dispatch
+ *
+ * PARAMETERS: Gpe_number - The 0-based Gpe number
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Handle and dispatch a General Purpose Acpi_event.
+ * Clears the status bit for the requested event.
+ *
+ * TBD: [Investigate] is this still valid or necessary:
+ * The Gpe handler differs from the fixed events in that it clears the enable
+ * bit rather than the status bit to clear the interrupt. This allows
+ * software outside of interrupt context to determine what caused the SCI and
+ * dispatch the correct AML.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_gpe_dispatch (
+ u32 gpe_number)
+{
+ ACPI_GPE_LEVEL_INFO gpe_info;
+
+ /*
+ * Valid GPE number?
+ */
+ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) {
+ return (INTERRUPT_NOT_HANDLED);
+ }
+
+ /*
+ * Disable the GPE.
+ */
+ acpi_hw_disable_gpe (gpe_number);
+
+ gpe_info = acpi_gbl_gpe_info [gpe_number];
+
+ /*
+ * Edge-Triggered?
+ * ---------------
+ * If edge-triggered, clear the GPE status bit now. Note that
+ * level-triggered events are cleared after the GPE is serviced.
+ */
+ if (gpe_info.type & ACPI_EVENT_EDGE_TRIGGERED) {
+ acpi_hw_clear_gpe (gpe_number);
+ }
+ /*
+ * Function Handler (e.g. EC)?
+ */
+ if (gpe_info.handler) {
+ /* Invoke function handler (at interrupt level). */
+ gpe_info.handler (gpe_info.context);
+
+ /* Level-Triggered? */
+ if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) {
+ acpi_hw_clear_gpe (gpe_number);
+ }
+
+ /* Enable GPE */
+ acpi_hw_enable_gpe (gpe_number);
+ }
+ /*
+ * Method Handler (e.g. _Exx/_Lxx)?
+ */
+ else if (gpe_info.method_handle) {
+ if (ACPI_FAILURE(acpi_os_queue_for_execution (OSD_PRIORITY_GPE,
+ acpi_ev_asynch_execute_gpe_method, (void*)(NATIVE_UINT)gpe_number))) {
+ /*
+ * Shoudn't occur, but if it does report an error. Note that
+ * the GPE will remain disabled until the ACPI Core Subsystem
+ * is restarted, or the handler is removed/reinstalled.
+ */
+ REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to queue handler for GPE bit [%X]\n", gpe_number));
+ }
+ }
+ /*
+ * No Handler? Report an error and leave the GPE disabled.
+ */
+ else {
+ REPORT_ERROR (("Acpi_ev_gpe_dispatch: No installed handler for GPE [%X]\n", gpe_number));
+
+ /* Level-Triggered? */
+ if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) {
+ acpi_hw_clear_gpe (gpe_number);
+ }
+ }
+
+ return (INTERRUPT_HANDLED);
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: evmisc - ACPI device notification handler dispatch
+ * and ACPI Global Lock support
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "acpi.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "acinterp.h"
+#include "achware.h"
+
+#define _COMPONENT ACPI_EVENTS
+ MODULE_NAME ("evmisc")
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_queue_notify_request
+ *
+ * PARAMETERS:
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Dispatch a device notification event to a previously
+ * installed handler.
+ *
+ *************************************************************************/
+
+ACPI_STATUS
+acpi_ev_queue_notify_request (
+ ACPI_NAMESPACE_NODE *node,
+ u32 notify_value)
+{
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_OPERAND_OBJECT *handler_obj = NULL;
+ ACPI_GENERIC_STATE *notify_info;
+ ACPI_STATUS status = AE_OK;
+
+
+ /*
+ * For value 1 (Ejection Request), some device method may need to be run.
+ * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run.
+ * For value 0x80 (Status Change) on the power button or sleep button,
+ * initiate soft-off or sleep operation?
+ */
+
+ switch (notify_value) {
+ case 0:
+ break;
+
+ case 1:
+ break;
+
+ case 2:
+ break;
+
+ case 0x80:
+ break;
+
+ default:
+ break;
+ }
+
+
+ /*
+ * Get the notify object attached to the device Node
+ */
+
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
+ if (obj_desc) {
+
+ /* We have the notify object, Get the right handler */
+
+ switch (node->type) {
+ case ACPI_TYPE_DEVICE:
+ if (notify_value <= MAX_SYS_NOTIFY) {
+ handler_obj = obj_desc->device.sys_handler;
+ }
+ else {
+ handler_obj = obj_desc->device.drv_handler;
+ }
+ break;
+
+ case ACPI_TYPE_THERMAL:
+ if (notify_value <= MAX_SYS_NOTIFY) {
+ handler_obj = obj_desc->thermal_zone.sys_handler;
+ }
+ else {
+ handler_obj = obj_desc->thermal_zone.drv_handler;
+ }
+ break;
+ }
+ }
+
+
+ /* If there is any handler to run, schedule the dispatcher */
+
+ if ((acpi_gbl_sys_notify.handler && (notify_value <= MAX_SYS_NOTIFY)) ||
+ (acpi_gbl_drv_notify.handler && (notify_value > MAX_SYS_NOTIFY)) ||
+ handler_obj) {
+
+ notify_info = acpi_cm_create_generic_state ();
+ if (!notify_info) {
+ return (AE_NO_MEMORY);
+ }
+
+ notify_info->notify.node = node;
+ notify_info->notify.value = (u16) notify_value;
+ notify_info->notify.handler_obj = handler_obj;
+
+ status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH,
+ acpi_ev_notify_dispatch, notify_info);
+ if (ACPI_FAILURE (status)) {
+ acpi_cm_delete_generic_state (notify_info);
+ }
+ }
+
+ if (!handler_obj) {
+ /* There is no per-device notify handler for this device */
+
+ }
+
+
+ return (status);
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_notify_dispatch
+ *
+ * PARAMETERS:
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Dispatch a device notification event to a previously
+ * installed handler.
+ *
+ *************************************************************************/
+
+void
+acpi_ev_notify_dispatch (
+ void *context)
+{
+ ACPI_GENERIC_STATE *notify_info = (ACPI_GENERIC_STATE *) context;
+ NOTIFY_HANDLER global_handler = NULL;
+ void *global_context = NULL;
+ ACPI_OPERAND_OBJECT *handler_obj;
+
+
+ /*
+ * We will invoke a global notify handler if installed.
+ * This is done _before_ we invoke the per-device handler attached to the device.
+ */
+
+ if (notify_info->notify.value <= MAX_SYS_NOTIFY) {
+ /* Global system notification handler */
+
+ if (acpi_gbl_sys_notify.handler) {
+ global_handler = acpi_gbl_sys_notify.handler;
+ global_context = acpi_gbl_sys_notify.context;
+ }
+ }
+
+ else {
+ /* Global driver notification handler */
+
+ if (acpi_gbl_drv_notify.handler) {
+ global_handler = acpi_gbl_drv_notify.handler;
+ global_context = acpi_gbl_drv_notify.context;
+ }
+ }
+
+
+ /* Invoke the system handler first, if present */
+
+ if (global_handler) {
+ global_handler (notify_info->notify.node, notify_info->notify.value, global_context);
+ }
+
+ /* Now invoke the per-device handler, if present */
+
+ handler_obj = notify_info->notify.handler_obj;
+ if (handler_obj) {
+ handler_obj->notify_handler.handler (notify_info->notify.node, notify_info->notify.value,
+ handler_obj->notify_handler.context);
+ }
+
+
+ /* All done with the info object */
+
+ acpi_cm_delete_generic_state (notify_info);
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_global_lock_thread
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
+ * Global Lock. Simply signal all threads that are waiting
+ * for the lock.
+ *
+ **************************************************************************/
+
+static void
+acpi_ev_global_lock_thread (
+ void *context)
+{
+
+ /* Signal threads that are waiting for the lock */
+
+ if (acpi_gbl_global_lock_thread_count) {
+ /* Send sufficient units to the semaphore */
+
+ acpi_os_signal_semaphore (acpi_gbl_global_lock_semaphore,
+ acpi_gbl_global_lock_thread_count);
+ }
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_global_lock_handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Invoked directly from the SCI handler when a global lock
+ * release interrupt occurs. Grab the global lock and queue
+ * the global lock thread for execution
+ *
+ **************************************************************************/
+
+static u32
+acpi_ev_global_lock_handler (
+ void *context)
+{
+ u8 acquired = FALSE;
+ void *global_lock;
+
+
+ /*
+ * Attempt to get the lock
+ * If we don't get it now, it will be marked pending and we will
+ * take another interrupt when it becomes free.
+ */
+
+ global_lock = acpi_gbl_FACS->global_lock;
+ ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired);
+ if (acquired) {
+ /* Got the lock, now wake all threads waiting for it */
+
+ acpi_gbl_global_lock_acquired = TRUE;
+
+ /* Run the Global Lock thread which will signal all waiting threads */
+
+ acpi_os_queue_for_execution (OSD_PRIORITY_HIGH, acpi_ev_global_lock_thread,
+ context);
+ }
+
+ return (INTERRUPT_HANDLED);
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_init_global_lock_handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for the global lock release event
+ *
+ **************************************************************************/
+
+ACPI_STATUS
+acpi_ev_init_global_lock_handler (void)
+{
+ ACPI_STATUS status;
+
+
+ acpi_gbl_global_lock_present = TRUE;
+ status = acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL,
+ acpi_ev_global_lock_handler, NULL);
+
+ /*
+ * If the global lock does not exist on this platform, the attempt
+ * to enable GBL_STS will fail (the GBL_EN bit will not stick)
+ * Map to AE_OK, but mark global lock as not present.
+ * Any attempt to actually use the global lock will be flagged
+ * with an error.
+ */
+ if (status == AE_NO_HARDWARE_RESPONSE) {
+ acpi_gbl_global_lock_present = FALSE;
+ status = AE_OK;
+ }
+
+ return (status);
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_acquire_global_lock
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Attempt to gain ownership of the Global Lock.
+ *
+ **************************************************************************/
+
+ACPI_STATUS
+acpi_ev_acquire_global_lock(void)
+{
+ ACPI_STATUS status = AE_OK;
+ u8 acquired = FALSE;
+ void *global_lock;
+
+
+ /* Make sure that we actually have a global lock */
+
+ if (!acpi_gbl_global_lock_present) {
+ return (AE_NO_GLOBAL_LOCK);
+ }
+
+ /* One more thread wants the global lock */
+
+ acpi_gbl_global_lock_thread_count++;
+
+
+ /* If we (OS side) have the hardware lock already, we are done */
+
+ if (acpi_gbl_global_lock_acquired) {
+ return (AE_OK);
+ }
+
+ /* Only if the FACS is valid */
+
+ if (!acpi_gbl_FACS) {
+ return (AE_OK);
+ }
+
+
+ /* We must acquire the actual hardware lock */
+
+ global_lock = acpi_gbl_FACS->global_lock;
+ ACPI_ACQUIRE_GLOBAL_LOCK (global_lock, acquired);
+ if (acquired) {
+ /* We got the lock */
+
+ acpi_gbl_global_lock_acquired = TRUE;
+
+ return (AE_OK);
+ }
+
+
+ /*
+ * Did not get the lock. The pending bit was set above, and we must now
+ * wait until we get the global lock released interrupt.
+ */
+
+ /*
+ * Acquire the global lock semaphore first.
+ * Since this wait will block, we must release the interpreter
+ */
+
+ status = acpi_aml_system_wait_semaphore (acpi_gbl_global_lock_semaphore,
+ ACPI_UINT32_MAX);
+
+ return (status);
+}
+
+
+/***************************************************************************
+ *
+ * FUNCTION: Acpi_ev_release_global_lock
+ *
+ * DESCRIPTION: Releases ownership of the Global Lock.
+ *
+ **************************************************************************/
+
+void
+acpi_ev_release_global_lock (void)
+{
+ u8 pending = FALSE;
+ void *global_lock;
+
+
+ if (!acpi_gbl_global_lock_thread_count) {
+ REPORT_WARNING(("Global Lock has not be acquired, cannot release\n"));
+ return;
+ }
+
+ /* One fewer thread has the global lock */
+
+ acpi_gbl_global_lock_thread_count--;
+
+ /* Have all threads released the lock? */
+
+ if (!acpi_gbl_global_lock_thread_count) {
+ /*
+ * No more threads holding lock, we can do the actual hardware
+ * release
+ */
+
+ global_lock = acpi_gbl_FACS->global_lock;
+ ACPI_RELEASE_GLOBAL_LOCK (global_lock, pending);
+ acpi_gbl_global_lock_acquired = FALSE;
+
+ /*
+ * If the pending bit was set, we must write GBL_RLS to the control
+ * register
+ */
+ if (pending) {
+ acpi_hw_register_bit_access (ACPI_WRITE, ACPI_MTX_LOCK,
+ GBL_RLS, 1);
+ }
+ }
+
+ return;
+}
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: evregion - ACPI Address_space (Op_region) handler dispatch
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "acinterp.h"
+#include "amlcode.h"
+
+#define _COMPONENT ACPI_EVENTS
+ MODULE_NAME ("evregion")
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_install_default_address_space_handlers
+ *
+ * PARAMETERS:
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Installs the core subsystem address space handlers.
+ *
+ *************************************************************************/
+
+ACPI_STATUS
+acpi_ev_install_default_address_space_handlers (
+ void)
+{
+ ACPI_STATUS status;
+
+
+ /*
+ * All address spaces (PCI Config, EC, SMBus) are scope dependent
+ * and registration must occur for a specific device. In the case
+ * system memory and IO address spaces there is currently no device
+ * associated with the address space. For these we use the root.
+ * We install the default PCI config space handler at the root so
+ * that this space is immediately available even though the we have
+ * not enumerated all the PCI Root Buses yet. This is to conform
+ * to the ACPI specification which states that the PCI config
+ * space must be always available -- even though we are nowhere
+ * near ready to find the PCI root buses at this point.
+ *
+ * NOTE: We ignore AE_EXIST because this means that a handler has
+ * already been installed (via Acpi_install_address_space_handler)
+ */
+
+ status = acpi_install_address_space_handler (acpi_gbl_root_node,
+ ADDRESS_SPACE_SYSTEM_MEMORY,
+ ACPI_DEFAULT_HANDLER, NULL, NULL);
+ if ((ACPI_FAILURE (status)) &&
+ (status != AE_EXIST)) {
+ return (status);
+ }
+
+ status = acpi_install_address_space_handler (acpi_gbl_root_node,
+ ADDRESS_SPACE_SYSTEM_IO,
+ ACPI_DEFAULT_HANDLER, NULL, NULL);
+ if ((ACPI_FAILURE (status)) &&
+ (status != AE_EXIST)) {
+ return (status);
+ }
+
+ status = acpi_install_address_space_handler (acpi_gbl_root_node,
+ ADDRESS_SPACE_PCI_CONFIG,
+ ACPI_DEFAULT_HANDLER, NULL, NULL);
+ if ((ACPI_FAILURE (status)) &&
+ (status != AE_EXIST)) {
+ return (status);
+ }
+
+
+ return (AE_OK);
+}
+
+
+/* TBD: [Restructure] Move elsewhere */
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_execute_reg_method
+ *
+ * PARAMETERS: Region_obj - Object structure
+ * Function - On (1) or Off (0)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute _REG method for a region
+ *
+ *************************************************************************/
+
+static ACPI_STATUS
+acpi_ev_execute_reg_method (
+ ACPI_OPERAND_OBJECT *region_obj,
+ u32 function)
+{
+ ACPI_OPERAND_OBJECT *params[3];
+ ACPI_OPERAND_OBJECT space_id_desc;
+ ACPI_OPERAND_OBJECT function_desc;
+ ACPI_STATUS status;
+
+
+ if (region_obj->region.extra->extra.method_REG == NULL) {
+ return (AE_OK);
+ }
+
+ /*
+ * _REG method has two arguments
+ * Arg0: Integer: Operation region space ID
+ * Same value as Region_obj->Region.Space_id
+ * Arg1: Integer: connection status
+ * 1 for connecting the handler,
+ * 0 for disconnecting the handler
+ * Passed as a parameter
+ */
+
+ acpi_cm_init_static_object (&space_id_desc);
+ acpi_cm_init_static_object (&function_desc);
+
+ /*
+ * Method requires two parameters.
+ */
+ params [0] = &space_id_desc;
+ params [1] = &function_desc;
+ params [2] = NULL;
+
+ /*
+ * Set up the parameter objects
+ */
+ space_id_desc.common.type = ACPI_TYPE_INTEGER;
+ space_id_desc.integer.value = region_obj->region.space_id;
+
+ function_desc.common.type = ACPI_TYPE_INTEGER;
+ function_desc.integer.value = function;
+
+ /*
+ * Execute the method, no return value
+ */
+ status = acpi_ns_evaluate_by_handle (region_obj->region.extra->extra.method_REG, params, NULL);
+ return (status);
+}
+
+
+/**************************************************************************
+ *
+ * FUNCTION: Acpi_ev_address_space_dispatch
+ *
+ * PARAMETERS: Region_obj - internal region object
+ * Space_id - ID of the address space (0-255)
+ * Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * Bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Dispatch an address space or operation region access to
+ * a previously installed handler.
+ *
+ *************************************************************************/
+
+ACPI_STATUS
+acpi_ev_address_space_dispatch (
+ ACPI_OPERAND_OBJECT *region_obj,
+ u32 function,
+ ACPI_PHYSICAL_ADDRESS address,
+ u32 bit_width,
+ u32 *value)
+{
+ ACPI_STATUS status;
+ ADDRESS_SPACE_HANDLER handler;
+ ADDRESS_SPACE_SETUP region_setup;
+ ACPI_OPERAND_OBJECT *handler_desc;
+ void *region_context = NULL;
+
+
+ /*
+ * Ensure that there is a handler associated with this region
+ */
+ handler_desc = region_obj->region.addr_handler;
+ if (!handler_desc) {
+ return(AE_NOT_EXIST);
+ }
+
+ /*
+ * It may be the case that the region has never been initialized
+ * Some types of regions require special init code
+ */
+ if (!(region_obj->region.flags & AOPOBJ_INITIALIZED)) {
+ /*
+ * This region has not been initialized yet, do it
+ */
+ region_setup = handler_desc->addr_handler.setup;
+ if (!region_setup) {
+ /*
+ * Bad news, no init routine and not init'd
+ */
+ return (AE_UNKNOWN_STATUS);
+ }
+
+ /*
+ * We must exit the interpreter because the region setup will potentially
+ * execute control methods
+ */
+ acpi_aml_exit_interpreter ();
+
+ status = region_setup (region_obj, ACPI_REGION_ACTIVATE,
+ handler_desc->addr_handler.context,
+ ®ion_context);
+
+ /* Re-enter the interpreter */
+
+ acpi_aml_enter_interpreter ();
+
+ /*
+ * Init routine may fail
+ */
+ if (ACPI_FAILURE (status)) {
+ return(status);
+ }
+
+ region_obj->region.flags |= AOPOBJ_INITIALIZED;
+
+ /*
+ * Save the returned context for use in all accesses to
+ * this particular region.
+ */
+ region_obj->region.extra->extra.region_context = region_context;
+ }
+
+ /*
+ * We have everything we need, begin the process
+ */
+ handler = handler_desc->addr_handler.handler;
+
+ if (!(handler_desc->addr_handler.flags & ADDR_HANDLER_DEFAULT_INSTALLED)) {
+ /*
+ * For handlers other than the default (supplied) handlers, we must
+ * exit the interpreter because the handler *might* block -- we don't
+ * know what it will do, so we can't hold the lock on the intepreter.
+ */
+ acpi_aml_exit_interpreter();
+ }
+
+ /*
+ * Invoke the handler.
+ */
+ status = handler (function, address, bit_width, value,
+ handler_desc->addr_handler.context,
+ region_obj->region.extra->extra.region_context);
+
+
+ if (!(handler_desc->addr_handler.flags & ADDR_HANDLER_DEFAULT_INSTALLED)) {
+ /* We just returned from a non-default handler, we must re-enter the
+ interpreter */
+
+ acpi_aml_enter_interpreter ();
+ }
+
+ return (status);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_disassociate_region_from_handler
+ *
+ * PARAMETERS: Region_obj - Region Object
+ * Acpi_ns_is_locked - Namespace Region Already Locked?
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Break the association between the handler and the region
+ * this is a two way association.
+ *
+ ******************************************************************************/
+
+void
+acpi_ev_disassociate_region_from_handler(
+ ACPI_OPERAND_OBJECT *region_obj,
+ u8 acpi_ns_is_locked)
+{
+ ACPI_OPERAND_OBJECT *handler_obj;
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_OPERAND_OBJECT **last_obj_ptr;
+ ADDRESS_SPACE_SETUP region_setup;
+ void *region_context;
+ ACPI_STATUS status;
+
+
+ region_context = region_obj->region.extra->extra.region_context;
+
+ /*
+ * Get the address handler from the region object
+ */
+
+ handler_obj = region_obj->region.addr_handler;
+ if (!handler_obj) {
+ /*
+ * This region has no handler, all done
+ */
+ return;
+ }
+
+
+ /*
+ * Find this region in the handler's list
+ */
+
+ obj_desc = handler_obj->addr_handler.region_list;
+ last_obj_ptr = &handler_obj->addr_handler.region_list;
+
+ while (obj_desc) {
+ /*
+ * See if this is the one
+ */
+ if (obj_desc == region_obj) {
+ /*
+ * This is it, remove it from the handler's list
+ */
+ *last_obj_ptr = obj_desc->region.next;
+ obj_desc->region.next = NULL; /* Must clear field */
+
+ if (acpi_ns_is_locked) {
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ /*
+ * Now stop region accesses by executing the _REG method
+ */
+ acpi_ev_execute_reg_method (region_obj, 0);
+
+ if (acpi_ns_is_locked) {
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ /*
+ * Call the setup handler with the deactivate notification
+ */
+ region_setup = handler_obj->addr_handler.setup;
+ status = region_setup (region_obj, ACPI_REGION_DEACTIVATE,
+ handler_obj->addr_handler.context,
+ ®ion_context);
+
+ /*
+ * Init routine may fail, Just ignore errors
+ */
+
+ region_obj->region.flags &= ~(AOPOBJ_INITIALIZED);
+
+ /*
+ * Remove handler reference in the region
+ *
+ * NOTE: this doesn't mean that the region goes away
+ * The region is just inaccessible as indicated to
+ * the _REG method
+ *
+ * If the region is on the handler's list
+ * this better be the region's handler
+ */
+ ACPI_ASSERT (region_obj->region.addr_handler == handler_obj);
+
+ region_obj->region.addr_handler = NULL;
+
+ return;
+
+ } /* found the right handler */
+
+ /*
+ * Move through the linked list of handlers
+ */
+ last_obj_ptr = &obj_desc->region.next;
+ obj_desc = obj_desc->region.next;
+ }
+
+ /*
+ * If we get here, the region was not in the handler's region list
+ */
+ return;
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_associate_region_and_handler
+ *
+ * PARAMETERS: Handler_obj - Handler Object
+ * Region_obj - Region Object
+ * Acpi_ns_is_locked - Namespace Region Already Locked?
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Create the association between the handler and the region
+ * this is a two way association.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_associate_region_and_handler (
+ ACPI_OPERAND_OBJECT *handler_obj,
+ ACPI_OPERAND_OBJECT *region_obj,
+ u8 acpi_ns_is_locked)
+{
+ ACPI_STATUS status;
+
+
+ ACPI_ASSERT (region_obj->region.space_id == handler_obj->addr_handler.space_id);
+ ACPI_ASSERT (region_obj->region.addr_handler == 0);
+
+ /*
+ * Link this region to the front of the handler's list
+ */
+
+ region_obj->region.next = handler_obj->addr_handler.region_list;
+ handler_obj->addr_handler.region_list = region_obj;
+
+ /*
+ * set the region's handler
+ */
+
+/*
+ Handler_obj->Common.Reference_count =
+ (u16) (Handler_obj->Common.Reference_count +
+ Region_obj->Common.Reference_count - 1);
+*/
+ region_obj->region.addr_handler = handler_obj;
+
+ /*
+ * Last thing, tell all users that this region is usable
+ */
+ if (acpi_ns_is_locked) {
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ status = acpi_ev_execute_reg_method (region_obj, 1);
+
+ if (acpi_ns_is_locked) {
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+ }
+
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_addr_handler_helper
+ *
+ * PARAMETERS: Handle - Node to be dumped
+ * Level - Nesting level of the handle
+ * Context - Passed into Acpi_ns_walk_namespace
+ *
+ * DESCRIPTION: This routine checks to see if the object is a Region if it
+ * is then the address handler is installed in it.
+ *
+ * If the Object is a Device, and the device has a handler of
+ * the same type then the search is terminated in that branch.
+ *
+ * This is because the existing handler is closer in proximity
+ * to any more regions than the one we are trying to install.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ev_addr_handler_helper (
+ ACPI_HANDLE obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ ACPI_OPERAND_OBJECT *handler_obj;
+ ACPI_OPERAND_OBJECT *tmp_obj;
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_STATUS status;
+
+
+ handler_obj = (ACPI_OPERAND_OBJECT *) context;
+
+ /* Parameter validation */
+
+ if (!handler_obj) {
+ return (AE_OK);
+ }
+
+ /* Convert and validate the device handle */
+
+ node = acpi_ns_convert_handle_to_entry (obj_handle);
+ if (!node) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * We only care about regions.and objects
+ * that can have address handlers
+ */
+
+ if ((node->type != ACPI_TYPE_DEVICE) &&
+ (node->type != ACPI_TYPE_REGION) &&
+ (node != acpi_gbl_root_node)) {
+ return (AE_OK);
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) node);
+ if (!obj_desc) {
+ /*
+ * The object DNE, we don't care about it
+ */
+ return (AE_OK);
+ }
+
+ /*
+ * Devices are handled different than regions
+ */
+ if (IS_THIS_OBJECT_TYPE (obj_desc, ACPI_TYPE_DEVICE)) {
+ /*
+ * See if this guy has any handlers
+ */
+ tmp_obj = obj_desc->device.addr_handler;
+ while (tmp_obj) {
+ /*
+ * Now let's see if it's for the same address space.
+ */
+ if (tmp_obj->addr_handler.space_id == handler_obj->addr_handler.space_id) {
+ /*
+ * It's for the same address space
+ */
+ /*
+ * Since the object we found it on was a device, then it
+ * means that someone has already installed a handler for
+ * the branch of the namespace from this device on. Just
+ * bail out telling the walk routine to not traverse this
+ * branch. This preserves the scoping rule for handlers.
+ */
+ return (AE_CTRL_DEPTH);
+ }
+
+ /*
+ * Move through the linked list of handlers
+ */
+ tmp_obj = tmp_obj->addr_handler.next;
+ }
+
+ /*
+ * As long as the device didn't have a handler for this
+ * space we don't care about it. We just ignore it and
+ * proceed.
+ */
+ return (AE_OK);
+ }
+
+ /*
+ * Only here if it was a region
+ */
+ ACPI_ASSERT (obj_desc->common.type == ACPI_TYPE_REGION);
+
+ if (obj_desc->region.space_id != handler_obj->addr_handler.space_id) {
+ /*
+ * This region is for a different address space
+ * ignore it
+ */
+ return (AE_OK);
+ }
+
+ /*
+ * Now we have a region and it is for the handler's address
+ * space type.
+ *
+ * First disconnect region for any previous handler (if any)
+ */
+ acpi_ev_disassociate_region_from_handler (obj_desc, FALSE);
+
+ /*
+ * Then connect the region to the new handler
+ */
+ status = acpi_ev_associate_region_and_handler (handler_obj, obj_desc, FALSE);
+
+ return (status);
+}
+
+
--- /dev/null
+/******************************************************************************
+ *
+ * Module Name: evrgnini- ACPI Address_space (Op_region) init
+ * $Revision: 1.1 $
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000, 2001 R. Byron Moore
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include "acpi.h"
+#include "acevents.h"
+#include "acnamesp.h"
+#include "acinterp.h"
+#include "amlcode.h"
+
+#define _COMPONENT ACPI_EVENTS
+ MODULE_NAME ("evrgnini")
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_system_memory_region_setup
+ *
+ * PARAMETERS: Region_obj - region we are interested in
+ * Function - start or stop
+ * Handler_context - Address space handler context
+ * Region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling, a nop for now
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_system_memory_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+
+ if (function == ACPI_REGION_DEACTIVATE) {
+ if (*region_context) {
+ acpi_cm_free (*region_context);
+ *region_context = NULL;
+ }
+ return (AE_OK);
+ }
+
+
+ /* Activate. Create a new context */
+
+ *region_context = acpi_cm_callocate (sizeof (MEM_HANDLER_CONTEXT));
+ if (!(*region_context)) {
+ return (AE_NO_MEMORY);
+ }
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_io_space_region_setup
+ *
+ * PARAMETERS: Region_obj - region we are interested in
+ * Function - start or stop
+ * Handler_context - Address space handler context
+ * Region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_io_space_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+ if (function == ACPI_REGION_DEACTIVATE) {
+ *region_context = NULL;
+ }
+ else {
+ *region_context = handler_context;
+ }
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_pci_config_region_setup
+ *
+ * PARAMETERS: Region_obj - region we are interested in
+ * Function - start or stop
+ * Handler_context - Address space handler context
+ * Region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ * MUTEX: Assumes namespace is not locked
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_pci_config_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+ ACPI_STATUS status = AE_OK;
+ ACPI_INTEGER temp;
+ PCI_HANDLER_CONTEXT *pci_context = *region_context;
+ ACPI_OPERAND_OBJECT *handler_obj;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_OPERAND_OBJECT *region_obj = (ACPI_OPERAND_OBJECT *) handle;
+ DEVICE_ID object_hID;
+
+ handler_obj = region_obj->region.addr_handler;
+
+ if (!handler_obj) {
+ /*
+ * No installed handler. This shouldn't happen because the dispatch
+ * routine checks before we get here, but we check again just in case.
+ */
+ return(AE_NOT_EXIST);
+ }
+
+ if (function == ACPI_REGION_DEACTIVATE) {
+ if (pci_context) {
+ acpi_cm_free (pci_context);
+ *region_context = NULL;
+ }
+
+ return (status);
+ }
+
+
+ /* Create a new context */
+
+ pci_context = acpi_cm_callocate (sizeof(PCI_HANDLER_CONTEXT));
+ if (!pci_context) {
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * For PCI Config space access, we have to pass the segment, bus,
+ * device and function numbers. This routine must acquire those.
+ */
+
+ /*
+ * First get device and function numbers from the _ADR object
+ * in the parent's scope.
+ */
+ ACPI_ASSERT(region_obj->region.node);
+
+ node = acpi_ns_get_parent_object (region_obj->region.node);
+
+
+ /* Acpi_evaluate the _ADR object */
+
+ status = acpi_cm_evaluate_numeric_object (METHOD_NAME__ADR, node, &temp);
+ /*
+ * The default is zero, since the allocation above zeroed the data, just
+ * do nothing on failures.
+ */
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Got it..
+ */
+ pci_context->dev_func = (u32) temp;
+ }
+
+ /*
+ * Get the _SEG and _BBN values from the device upon which the handler
+ * is installed.
+ *
+ * We need to get the _SEG and _BBN objects relative to the PCI BUS device.
+ * This is the device the handler has been registered to handle.
+ */
+
+ /*
+ * If the Addr_handler.Node is still pointing to the root, we need
+ * to scan upward for a PCI Root bridge and re-associate the Op_region
+ * handlers with that device.
+ */
+ if (handler_obj->addr_handler.node == acpi_gbl_root_node) {
+ /*
+ * Node is currently the parent object
+ */
+ while (node != acpi_gbl_root_node) {
+ status = acpi_cm_execute_HID(node, &object_hID);
+
+ if (ACPI_SUCCESS (status)) {
+ if (!(STRNCMP(object_hID.buffer, PCI_ROOT_HID_STRING,
+ sizeof (PCI_ROOT_HID_STRING)))) {
+ acpi_install_address_space_handler(node,
+ ADDRESS_SPACE_PCI_CONFIG,
+ ACPI_DEFAULT_HANDLER, NULL, NULL);
+
+ break;
+ }
+ }
+
+ node = acpi_ns_get_parent_object(node);
+ }
+ }
+ else {
+ node = handler_obj->addr_handler.node;
+ }
+
+ status = acpi_cm_evaluate_numeric_object (METHOD_NAME__SEG, node, &temp);
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Got it..
+ */
+ pci_context->seg = (u32) temp;
+ }
+
+ status = acpi_cm_evaluate_numeric_object (METHOD_NAME__BBN, node, &temp);
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Got it..
+ */
+ pci_context->bus = (u32) temp;
+ }
+
+ *region_context = pci_context;
+
+ return (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: Acpi_ev_default_region_setup
+ *
+ * PARAMETERS: Region_obj - region we are interested in
+ * Function - start or stop
+ * Handler_context - Address space handler context
+ * Region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+acpi_ev_default_region_setup (
+ ACPI_HANDLE handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+ if (function == ACPI_REGION_DEACTIVATE) {
+ *region_context = NULL;
+ }
+ else {
+ *region_context = handler_context;
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: Acpi_ev_initialize_region
+ *
+ * PARAMETERS: Region_obj - Region we are initializing
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initializes the region, finds any _REG methods and saves them
+ * for execution at a later time
+ *
+ * Get the appropriate address space handler for a newly
+ * created region.
+ *
+ * This also performs address space specific intialization. For
+ * example, PCI regions must have an _ADR object that contains
+ * a PCI address in the scope of the defintion. This address is
+ * required to perform an access to PCI config space.
+ *
+ ******************************************************************************/
+
+ACPI_STATUS
+acpi_ev_initialize_region (
+ ACPI_OPERAND_OBJECT *region_obj,
+ u8 acpi_ns_locked)
+{
+ ACPI_OPERAND_OBJECT *handler_obj;
+ ACPI_OPERAND_OBJECT *obj_desc;
+ ACPI_ADDRESS_SPACE_TYPE space_id;
+ ACPI_NAMESPACE_NODE *node;
+ ACPI_STATUS status;
+ ACPI_NAMESPACE_NODE *method_node;
+ ACPI_NAME *reg_name_ptr = (ACPI_NAME *) METHOD_NAME__REG;
+
+
+ if (!region_obj) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ ACPI_ASSERT(region_obj->region.node);
+
+ node = acpi_ns_get_parent_object (region_obj->region.node);
+ space_id = region_obj->region.space_id;
+
+ region_obj->region.addr_handler = NULL;
+ region_obj->region.extra->extra.method_REG = NULL;
+ region_obj->region.flags &= ~(AOPOBJ_INITIALIZED);
+
+ /*
+ * Find any "_REG" associated with this region definition