summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/namespace/nsaccess.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/namespace/nsaccess.c')
-rw-r--r--drivers/acpi/namespace/nsaccess.c647
1 files changed, 647 insertions, 0 deletions
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
new file mode 100644
index 000000000..7cb9ac409
--- /dev/null
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -0,0 +1,647 @@
+
+/******************************************************************************
+ *
+ * Module Name: nsaccess - Top-level functions for accessing ACPI namespace
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 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 "interp.h"
+#include "namesp.h"
+#include "dispatch.h"
+
+
+#define _COMPONENT NAMESPACE
+ MODULE_NAME ("nsaccess");
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_root_create_scope
+ *
+ * PARAMETERS: Entry - NTE for which a scope will be created
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a scope table for the given name table entry
+ *
+ * MUTEX: Expects namespace to be locked
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_root_create_scope (
+ ACPI_NAMED_OBJECT *entry)
+{
+
+ /* Allocate a scope table */
+
+ if (entry->child_table) {
+ return (AE_EXIST);
+ }
+
+ entry->child_table = acpi_ns_allocate_name_table (NS_TABLE_SIZE);
+ if (!entry->child_table) {
+ /* root name table allocation failure */
+
+ REPORT_ERROR ("Root name table allocation failure");
+ return (AE_NO_MEMORY);
+ }
+
+ /*
+ * Init the scope first entry -- since it is the exemplar of
+ * the scope (Some fields are duplicated to new entries!)
+ */
+ acpi_ns_initialize_table (entry->child_table, NULL, entry);
+ return (AE_OK);
+
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_root_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocate and initialize the root name table
+ *
+ * MUTEX: Locks namespace for entire execution
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_root_initialize (void)
+{
+ ACPI_STATUS status = AE_OK;
+ PREDEFINED_NAMES *init_val = NULL;
+ ACPI_NAMED_OBJECT *new_entry;
+ ACPI_OBJECT_INTERNAL *obj_desc;
+
+
+ acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE);
+
+ /*
+ * Root is initially NULL, so a non-NULL value indicates
+ * that Acpi_ns_root_initialize() has already been called; just return.
+ */
+
+ if (acpi_gbl_root_object->child_table) {
+ status = AE_OK;
+ goto unlock_and_exit;
+ }
+
+
+ /* Create the root scope */
+
+ status = acpi_ns_root_create_scope (acpi_gbl_root_object);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Enter the pre-defined names in the name table */
+
+ for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {
+ status = acpi_ns_lookup (NULL, init_val->name,
+ (OBJECT_TYPE_INTERNAL) init_val->type,
+ IMODE_LOAD_PASS2, NS_NO_UPSEARCH,
+ NULL, &new_entry);
+
+ /*
+ * if name entered successfully
+ * && its entry in Pre_defined_names[] specifies an
+ * initial value
+ */
+
+ if ((status == AE_OK) &&
+ new_entry && init_val->val)
+ {
+ /*
+ * Entry requests an initial value, allocate a
+ * descriptor for it.
+ */
+
+ obj_desc =
+ acpi_cm_create_internal_object (
+ (OBJECT_TYPE_INTERNAL) init_val->type);
+
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Convert value string from table entry to
+ * internal representation. Only types actually
+ * used for initial values are implemented here.
+ */
+
+ switch (init_val->type)
+ {
+
+ case ACPI_TYPE_NUMBER:
+
+ obj_desc->number.value =
+ (u32) STRTOUL (init_val->val, NULL, 10);
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ obj_desc->string.length =
+ (u16) STRLEN (init_val->val);
+
+ /*
+ * Allocate a buffer for the string. All
+ * String.Pointers must be allocated buffers!
+ * (makes deletion simpler)
+ */
+ obj_desc->string.pointer =
+ acpi_cm_allocate ((ACPI_SIZE)
+ (obj_desc->string.length + 1));
+
+ if (!obj_desc->string.pointer) {
+ REPORT_ERROR ("Initial value string"
+ "allocation failure");
+
+ acpi_cm_remove_reference (obj_desc);
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ STRCPY ((char *) obj_desc->string.pointer,
+ init_val->val);
+ break;
+
+
+ case ACPI_TYPE_MUTEX:
+
+ obj_desc->mutex.sync_level =
+ (u16) STRTOUL (init_val->val, NULL, 10);
+
+ if (STRCMP (init_val->name, "_GL_") == 0) {
+ /*
+ * Create a counting semaphore for the
+ * global lock
+ */
+ status =
+ acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT,
+ 1, &obj_desc->mutex.semaphore);
+
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ /*
+ * We just created the mutex for the
+ * global lock, save it
+ */
+
+ acpi_gbl_global_lock_semaphore =
+ obj_desc->mutex.semaphore;
+ }
+
+ else {
+ /* Create a mutex */
+
+ status = acpi_os_create_semaphore (1, 1,
+ &obj_desc->mutex.semaphore);
+
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ /* TBD: [Restructure] These fields may be obsolete */
+
+ obj_desc->mutex.lock_count = 0;
+ obj_desc->mutex.thread_id = 0;
+ break;
+
+
+ default:
+ REPORT_ERROR ("Unsupported initial type value");
+ acpi_cm_remove_reference (obj_desc);
+ obj_desc = NULL;
+ continue;
+ }
+
+ /* Store pointer to value descriptor in nte */
+
+ acpi_ns_attach_object (new_entry, obj_desc,
+ obj_desc->common.type);
+ }
+ }
+
+
+unlock_and_exit:
+ acpi_cm_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: Acpi_ns_lookup
+ *
+ * PARAMETERS: Prefix_scope - Search scope if name is not fully qualified
+ * Pathname - Search pathname, in internal format
+ * (as represented in the AML stream)
+ * Type - Type associated with name
+ * Interpreter_mode - IMODE_LOAD_PASS2 => add name if not found
+ * Ret_entry - Where the new entry (NTE) is placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find or enter the passed name in the name space.
+ * Log an error if name not found in Exec mode.
+ *
+ * MUTEX: Assumes namespace is locked.
+ *
+ ***************************************************************************/
+
+ACPI_STATUS
+acpi_ns_lookup (
+ ACPI_GENERIC_STATE *scope_info,
+ char *pathname,
+ OBJECT_TYPE_INTERNAL type,
+ OPERATING_MODE interpreter_mode,
+ u32 flags,
+ ACPI_WALK_STATE *walk_state,
+ ACPI_NAMED_OBJECT **ret_entry)
+{
+ ACPI_STATUS status;
+ ACPI_NAME_TABLE *prefix_scope;
+ ACPI_NAME_TABLE *table_to_search = NULL;
+ ACPI_NAME_TABLE *scope_to_push = NULL;
+ ACPI_NAMED_OBJECT *this_entry = NULL;
+ u32 num_segments;
+ ACPI_NAME simple_name;
+ u8 null_name_path = FALSE;
+ OBJECT_TYPE_INTERNAL type_to_check_for;
+ OBJECT_TYPE_INTERNAL this_search_type;
+
+ if (!ret_entry) {
+ return (AE_BAD_PARAMETER);
+ }
+
+
+ acpi_gbl_ns_lookup_count++;
+
+ *ret_entry = ENTRY_NOT_FOUND;
+ if (!acpi_gbl_root_object->child_table) {
+ /*
+ * If the name space has not been initialized:
+ * - In Pass1 of Load mode, we need to initialize it
+ * before trying to define a name.
+ * - In Exec mode, there are no names to be found.
+ */
+
+ if (IMODE_LOAD_PASS1 == interpreter_mode) {
+ if ((status = acpi_ns_root_initialize ()) != AE_OK) {
+ return (status);
+ }
+ }
+ else {
+ return (AE_NOT_FOUND);
+ }
+ }
+
+
+ /*
+ * Get the prefix scope.
+ * A null scope means use the root scope
+ */
+
+ if ((!scope_info) ||
+ (!scope_info->scope.name_table))
+ {
+ prefix_scope = acpi_gbl_root_object->child_table;
+ }
+ else {
+ prefix_scope = scope_info->scope.name_table;
+ }
+
+
+ /*
+ * This check is explicitly split provide relax the Type_to_check_for
+ * conditions for Bank_field_defn. Originally, both Bank_field_defn and
+ * Def_field_defn caused Type_to_check_for to be set to ACPI_TYPE_REGION,
+ * but the Bank_field_defn may also check for a Field definition as well
+ * as an Operation_region.
+ */
+
+ if (INTERNAL_TYPE_DEF_FIELD_DEFN == type) {
+ /* Def_field_defn defines fields in a Region */
+
+ type_to_check_for = ACPI_TYPE_REGION;
+ }
+
+ else if (INTERNAL_TYPE_BANK_FIELD_DEFN == type) {
+ /* Bank_field_defn defines data fields in a Field Object */
+
+ type_to_check_for = ACPI_TYPE_ANY;
+ }
+
+ else {
+ type_to_check_for = type;
+ }
+
+
+ /* Examine the name pointer */
+
+ if (!pathname) {
+ /* 8-12-98 ASL Grammar Update supports null Name_path */
+
+ null_name_path = TRUE;
+ num_segments = 0;
+ this_entry = acpi_gbl_root_object;
+
+ }
+
+ else {
+ /*
+ * Valid name pointer (Internal name format)
+ *
+ * Check for prefixes. As represented in the AML stream, a
+ * Pathname consists of an optional scope prefix followed by
+ * a segment part.
+ *
+ * If present, the scope prefix is either a Root_prefix (in
+ * which case the name is fully qualified), or zero or more
+ * Parent_prefixes (in which case the name's scope is relative
+ * to the current scope).
+ *
+ * The segment part consists of either:
+ * - A single 4-byte name segment, or
+ * - A Dual_name_prefix followed by two 4-byte name segments, or
+ * - A Multi_name_prefix_op, followed by a byte indicating the
+ * number of segments and the segments themselves.
+ */
+
+ if (*pathname == AML_ROOT_PREFIX) {
+ /* Pathname is fully qualified, look in root name table */
+
+ table_to_search = acpi_gbl_root_object->child_table;
+ /* point to segment part */
+ pathname++;
+
+ /* Direct reference to root, "\" */
+
+ if (!(*pathname)) {
+ this_entry = acpi_gbl_root_object;
+ goto check_for_new_scope_and_exit;
+ }
+ }
+
+ else {
+ /* Pathname is relative to current scope, start there */
+
+ table_to_search = prefix_scope;
+
+ /*
+ * Handle up-prefix (carat). More than one prefix
+ * is supported
+ */
+
+ while (*pathname == AML_PARENT_PREFIX) {
+
+ /* Point to segment part or next Parent_prefix */
+
+ pathname++;
+
+ /* Backup to the parent's scope */
+
+ table_to_search = table_to_search->parent_table;
+ if (!table_to_search) {
+ /* Current scope has no parent scope */
+
+ REPORT_ERROR ("Ns_lookup: Too many parent"
+ "prefixes or scope has no parent");
+
+
+ return (AE_NOT_FOUND);
+ }
+ }
+ }
+
+
+ /*
+ * Examine the name prefix opcode, if any,
+ * to determine the number of segments
+ */
+
+ if (*pathname == AML_DUAL_NAME_PREFIX) {
+ num_segments = 2;
+ /* point to first segment */
+ pathname++;
+
+ }
+
+ else if (*pathname == AML_MULTI_NAME_PREFIX_OP) {
+ num_segments = (s32)* (u8 *) ++pathname;
+ /* point to first segment */
+ pathname++;
+
+ }
+
+ else {
+ /*
+ * No Dual or Multi prefix, hence there is only one
+ * segment and Pathname is already pointing to it.
+ */
+ num_segments = 1;
+
+ }
+
+ }
+
+
+ /*
+ * Search namespace for each segment of the name.
+ * Loop through and verify/add each name segment.
+ */
+
+
+ while (num_segments-- && table_to_search) {
+ /*
+ * Search for the current segment in the table where
+ * it should be.
+ * Type is significant only at the last (topmost) level.
+ */
+ this_search_type = ACPI_TYPE_ANY;
+ if (!num_segments) {
+ this_search_type = type;
+ }
+
+ MOVE_UNALIGNED32_TO_32 (&simple_name, pathname);
+ status = acpi_ns_search_and_enter (simple_name, walk_state,
+ table_to_search, interpreter_mode,
+ this_search_type, flags,
+ &this_entry);
+
+ if (status != AE_OK) {
+ if (status == AE_NOT_FOUND) {
+ /* Name not in ACPI namespace */
+
+ if (IMODE_LOAD_PASS1 == interpreter_mode ||
+ IMODE_LOAD_PASS2 == interpreter_mode)
+ {
+ REPORT_ERROR ("Name table overflow");
+ }
+
+ }
+
+ return (status);
+ }
+
+
+ /*
+ * If 1) last segment (Num_segments == 0)
+ * 2) and looking for a specific type
+ * (Not checking for TYPE_ANY)
+ * 3) which is not a local type (TYPE_DEF_ANY)
+ * 4) which is not a local type (TYPE_SCOPE)
+ * 5) which is not a local type (TYPE_INDEX_FIELD_DEFN)
+ * 6) and type of entry is known (not TYPE_ANY)
+ * 7) and entry does not match request
+ *
+ * Then we have a type mismatch. Just warn and ignore it.
+ */
+ if ((num_segments == 0) &&
+ (type_to_check_for != ACPI_TYPE_ANY) &&
+ (type_to_check_for != INTERNAL_TYPE_DEF_ANY) &&
+ (type_to_check_for != INTERNAL_TYPE_SCOPE) &&
+ (type_to_check_for != INTERNAL_TYPE_INDEX_FIELD_DEFN) &&
+ (this_entry->type != ACPI_TYPE_ANY) &&
+ (this_entry->type != type_to_check_for))
+ {
+ /* Complain about type mismatch */
+
+ REPORT_WARNING ("Type mismatch");
+ }
+
+ /*
+ * If last segment and not looking for a specific type, but type of
+ * found entry is known, use that type to see if it opens a scope.
+ */
+
+ if ((0 == num_segments) && (ACPI_TYPE_ANY == type)) {
+ type = this_entry->type;
+ }
+
+ if ((num_segments || acpi_ns_opens_scope (type)) &&
+ (this_entry->child_table == NULL))
+ {
+ /*
+ * More segments or the type implies enclosed scope,
+ * and the next scope has not been allocated.
+ */
+
+ if ((IMODE_LOAD_PASS1 == interpreter_mode) ||
+ (IMODE_LOAD_PASS2 == interpreter_mode))
+ {
+ /*
+ * First or second pass load mode
+ * ==> locate the next scope
+ */
+
+ this_entry->child_table =
+ acpi_ns_allocate_name_table (NS_TABLE_SIZE);
+
+ if (!this_entry->child_table) {
+ return (AE_NO_MEMORY);
+ }
+ }
+
+ /* Now complain if there is no next scope */
+
+ if (this_entry->child_table == NULL) {
+ if (IMODE_LOAD_PASS1 == interpreter_mode ||
+ IMODE_LOAD_PASS2 == interpreter_mode)
+ {
+ REPORT_ERROR ("Name Table allocation failure");
+ return (AE_NOT_FOUND);
+ }
+
+ return (AE_NOT_FOUND);
+ }
+
+
+ /* Scope table initialization */
+
+ if (IMODE_LOAD_PASS1 == interpreter_mode ||
+ IMODE_LOAD_PASS2 == interpreter_mode)
+ {
+ /* Initialize the new table */
+
+ acpi_ns_initialize_table (this_entry->child_table,
+ table_to_search,
+ this_entry);
+ }
+ }
+
+ table_to_search = this_entry->child_table;
+ /* point to next name segment */
+ pathname += ACPI_NAME_SIZE;
+ }
+
+
+ /*
+ * Always check if we need to open a new scope
+ */
+
+check_for_new_scope_and_exit:
+
+ if (!(flags & NS_DONT_OPEN_SCOPE) && (walk_state)) {
+ /*
+ * If entry is a type which opens a scope,
+ * push the new scope on the scope stack.
+ */
+
+ if (acpi_ns_opens_scope (type_to_check_for)) {
+ /* 8-12-98 ASL Grammar Update supports null Name_path */
+
+ if (null_name_path) {
+ /* TBD: [Investigate] - is this the correct thing to do? */
+
+ scope_to_push = NULL;
+ }
+ else {
+ scope_to_push = this_entry->child_table;
+ }
+
+ status = acpi_ds_scope_stack_push (scope_to_push, type,
+ walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ }
+ }
+
+ *ret_entry = this_entry;
+ return (AE_OK);
+}
+