diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-07-08 00:53:00 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-07-08 00:53:00 +0000 |
commit | b8553086288629b4efb77e97f5582e08bc50ad65 (patch) | |
tree | 0a19bd1c21e148f35c7a0f76baa4f7a056b966b0 /drivers/acpi/namespace | |
parent | 75b6d92f2dd5112b02f4e78cf9f35f9825946ef0 (diff) |
Merge with 2.4.0-test3-pre4.
Diffstat (limited to 'drivers/acpi/namespace')
-rw-r--r-- | drivers/acpi/namespace/nsaccess.c | 647 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsalloc.c | 411 | ||||
-rw-r--r-- | drivers/acpi/namespace/nseval.c | 507 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsload.c | 488 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsnames.c | 503 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsobject.c | 556 | ||||
-rw-r--r-- | drivers/acpi/namespace/nssearch.c | 646 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsutils.c | 886 | ||||
-rw-r--r-- | drivers/acpi/namespace/nswalk.c | 279 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsxfname.c | 372 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsxfobj.c | 554 |
11 files changed, 5849 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); +} + diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c new file mode 100644 index 000000000..414f3791a --- /dev/null +++ b/drivers/acpi/namespace/nsalloc.c @@ -0,0 +1,411 @@ + +/****************************************************************************** + * + * Module Name: nsalloc - Namespace allocation and deletion utilities + * + *****************************************************************************/ + +/* + * 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 "namesp.h" +#include "interp.h" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nsalloc"); + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_allocate_name_table + * + * PARAMETERS: Nte_count - Count of NTEs to allocate + * + * RETURN: The address of the first nte in the array, or NULL + * + * DESCRIPTION: Allocate an array of nte, including prepended link space + * Array is set to all zeros via Acpi_os_callcate(). + * + ***************************************************************************/ + +ACPI_NAME_TABLE * +acpi_ns_allocate_name_table ( + u32 num_entries) +{ + ACPI_NAME_TABLE *name_table = NULL; + ACPI_SIZE alloc_size; + + + alloc_size = sizeof (ACPI_NAME_TABLE) + ((num_entries - 1) * + sizeof (ACPI_NAMED_OBJECT)); + + name_table = acpi_cm_callocate (alloc_size); + + + return (name_table); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_delete_namespace_subtree + * + * PARAMETERS: None. + * + * RETURN: None. + * + * DESCRIPTION: Delete a subtree of the namespace. This includes all objects stored + * within the subtree. Scope tables are deleted also + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_delete_namespace_subtree ( + ACPI_NAMED_OBJECT *parent_entry) +{ + ACPI_NAMED_OBJECT *child_entry; + u32 level; + ACPI_OBJECT_INTERNAL *obj_desc; + + + child_entry = 0; + level = 1; + + /* + * Traverse the tree of objects until we bubble back up + * to where we started. + */ + + while (level > 0) { + /* + * Get the next typed object in this scope. + * Null returned if not found + */ + + child_entry = acpi_ns_get_next_object (ACPI_TYPE_ANY, + parent_entry, + child_entry); + + if (child_entry) { + /* + * Found an object - delete the object within + * the Value field + */ + + obj_desc = acpi_ns_get_attached_object (child_entry); + if (obj_desc) { + acpi_ns_detach_object (child_entry); + acpi_cm_remove_reference (obj_desc); + } + + + /* + * Clear the NTE in case this scope is reused + * (e.g., a control method scope) + */ + + child_entry->type = ACPI_TYPE_ANY; + child_entry->name = 0; + + /* Check if this object has any children */ + + if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_entry, 0)) { + /* + * There is at least one child of this object, + * visit the object + */ + + level++; + parent_entry = child_entry; + child_entry = 0; + } + + else { + /* + * There may be a name table even if there are + * no children + */ + + acpi_ns_delete_name_table (child_entry->child_table); + child_entry->child_table = NULL; + + } + } + + else { + /* + * No more children in this object. + * We will move up to the grandparent. + */ + level--; + + /* + * Delete the scope (Name Table) associated with + * the parent object + */ + /* Don't delete the top level scope, this allows + * the dynamic deletion of objects created underneath + * control methods! + */ + + if (level != 0) { + acpi_ns_delete_name_table (parent_entry->child_table); + parent_entry->child_table = NULL; + } + + /* New "last child" is this parent object */ + + child_entry = parent_entry; + + /* Now we can move up the tree to the grandparent */ + + parent_entry = acpi_ns_get_parent_entry (parent_entry); + } + } + + + return (AE_OK); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_remove_reference + * + * PARAMETERS: Entry - NTE whose reference count is to be decremented + * + * RETURN: None. + * + * DESCRIPTION: Remove an NTE reference. Decrements the reference count of + * all parent NTEs up to the root. Any NTE along the way that + * reaches zero references is freed. + * + ***************************************************************************/ + +void +acpi_ns_remove_reference ( + ACPI_NAMED_OBJECT *entry) +{ + ACPI_NAMED_OBJECT *this_entry; + + + /* There may be a name table even if there are no children */ + + acpi_ns_delete_name_table (entry->child_table); + entry->child_table = NULL; + + + /* + * Decrement the reference count(s) of all parents up to the root, + * And delete anything with zero remaining references. + */ + this_entry = entry; + while (this_entry) { + /* Decrement the reference */ + + this_entry->reference_count--; + + /* Delete entry if no more references */ + + if (!this_entry->reference_count) { + /* Delete the scope if present */ + + if (this_entry->child_table) { + acpi_ns_delete_name_table (this_entry->child_table); + this_entry->child_table = NULL; + } + + /* + * Mark the entry free + * (This doesn't deallocate anything) + */ + + acpi_ns_free_table_entry (this_entry); + + } + + /* Move up to parent */ + + this_entry = acpi_ns_get_parent_entry (this_entry); + } +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_delete_namespace_by_owner + * + * PARAMETERS: None. + * + * RETURN: None. + * + * DESCRIPTION: Delete entries within the namespace that are owned by a + * specific ID. Used to delete entire ACPI tables. All + * reference counts are updated. + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_delete_namespace_by_owner ( + u16 owner_id) +{ + ACPI_NAMED_OBJECT *child_entry; + u32 level; + ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_NAMED_OBJECT *parent_entry; + + + parent_entry = acpi_gbl_root_object; + child_entry = 0; + level = 1; + + /* + * Traverse the tree of objects until we bubble back up + * to where we started. + */ + + while (level > 0) { + /* + * Get the next typed object in this scope. + * Null returned if not found + */ + + child_entry = acpi_ns_get_next_object (ACPI_TYPE_ANY, + parent_entry, + child_entry); + + if (child_entry) { + if (child_entry->owner_id == owner_id) { + /* + * Found an object - delete the object within + * the Value field + */ + + obj_desc = acpi_ns_get_attached_object (child_entry); + if (obj_desc) { + acpi_ns_detach_object (child_entry); + acpi_cm_remove_reference (obj_desc); + } + } + + /* Check if this object has any children */ + + if (acpi_ns_get_next_object (ACPI_TYPE_ANY, child_entry, 0)) { + /* + * There is at least one child of this object, + * visit the object + */ + + level++; + parent_entry = child_entry; + child_entry = 0; + } + + else if (child_entry->owner_id == owner_id) { + acpi_ns_remove_reference (child_entry); + } + } + + else { + /* + * No more children in this object. + * We will move up to the grandparent. + */ + level--; + + /* + * Delete the scope (Name Table) associated with + * the parent object + */ + /* Don't delete the top level scope, this allows + * the dynamic deletion of objects created underneath + * control methods! + */ + + + if (level != 0) { + if (parent_entry->owner_id == owner_id) { + acpi_ns_remove_reference (parent_entry); + } + } + + + /* New "last child" is this parent object */ + + child_entry = parent_entry; + + /* Now we can move up the tree to the grandparent */ + + parent_entry = acpi_ns_get_parent_entry (parent_entry); + } + } + + + return (AE_OK); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_delete_name_table + * + * PARAMETERS: Scope - A handle to the scope to be deleted + * + * RETURN: None. + * + * DESCRIPTION: Delete a namespace Name Table with zero or + * more appendages. The table and all appendages are deleted. + * + ***************************************************************************/ + +void +acpi_ns_delete_name_table ( + ACPI_NAME_TABLE *name_table) +{ + ACPI_NAME_TABLE *this_table; + ACPI_NAME_TABLE *next_table; + + + if (!name_table) { + return; + } + + this_table = name_table; + + + /* + * Deallocate the name table and all appendages + */ + do + { + next_table = this_table->next_table; + + /* Now we can free the table */ + + acpi_cm_free (this_table); + this_table = next_table; + + } while (this_table); + + return; +} + + diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c new file mode 100644 index 000000000..ea3e15621 --- /dev/null +++ b/drivers/acpi/namespace/nseval.c @@ -0,0 +1,507 @@ + +/****************************************************************************** + * + * Module Name: nseval - Object evaluation interfaces -- includes control + * method lookup and execution. + * + *****************************************************************************/ + +/* + * 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 "parser.h" +#include "interp.h" +#include "namesp.h" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nseval"); + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_evaluate_relative + * + * PARAMETERS: Rel_obj_entry - NTE of the relative containing object + * *Pathname - Name of method to execute, If NULL, the + * handle is the object to execute + * **Params - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. + * *Return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * + * RETURN: Status + * + * DESCRIPTION: Find and execute the requested method using the handle as a + * scope + * + * MUTEX: Locks Namespace + * + ****************************************************************************/ + +ACPI_STATUS +acpi_ns_evaluate_relative ( + ACPI_NAMED_OBJECT *handle, + char *pathname, + ACPI_OBJECT_INTERNAL **params, + ACPI_OBJECT_INTERNAL **return_object) +{ + ACPI_NAMED_OBJECT *rel_obj_entry; + ACPI_STATUS status; + ACPI_NAMED_OBJECT *obj_entry = NULL; + char *internal_path = NULL; + ACPI_GENERIC_STATE scope_info; + + + /* + * Must have a valid object handle + */ + if (!handle) { + return (AE_BAD_PARAMETER); + } + + /* Build an internal name string for the method */ + + status = acpi_ns_internalize_name (pathname, &internal_path); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Get the prefix handle and NTE */ + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + rel_obj_entry = acpi_ns_convert_handle_to_entry (handle); + if (!rel_obj_entry) { + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + status = AE_BAD_PARAMETER; + goto cleanup; + } + + /* Lookup the name in the namespace */ + + scope_info.scope.name_table = rel_obj_entry->child_table; + status = acpi_ns_lookup (&scope_info, internal_path, ACPI_TYPE_ANY, + IMODE_EXECUTE, + NS_NO_UPSEARCH, NULL, + &obj_entry); + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + + if (status != AE_OK) { + goto cleanup; + } + + /* + * Now that we have a handle to the object, we can attempt + * to evaluate it. + */ + + status = acpi_ns_evaluate_by_handle (obj_entry, params, return_object); + +cleanup: + + /* Cleanup */ + + acpi_cm_free (internal_path); + + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_evaluate_by_name + * + * PARAMETERS: Pathname - Fully qualified pathname to the object + * *Return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * **Params - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. + * + * RETURN: Status + * + * DESCRIPTION: Find and execute the requested method passing the given + * parameters + * + * MUTEX: Locks Namespace + * + ****************************************************************************/ + +ACPI_STATUS +acpi_ns_evaluate_by_name ( + char *pathname, + ACPI_OBJECT_INTERNAL **params, + ACPI_OBJECT_INTERNAL **return_object) +{ + ACPI_STATUS status; + ACPI_NAMED_OBJECT *obj_entry = NULL; + char *internal_path = NULL; + + + /* Build an internal name string for the method */ + + if (pathname[0] != '\\' || pathname[1] != '/') { + status = acpi_ns_internalize_name (pathname, &internal_path); + if (ACPI_FAILURE (status)) { + return (status); + } + } + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + /* Lookup the name in the namespace */ + + status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, + IMODE_EXECUTE, + NS_NO_UPSEARCH, NULL, + &obj_entry); + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + + if (status != AE_OK) { + goto cleanup; + } + + /* + * Now that we have a handle to the object, we can attempt + * to evaluate it. + */ + + status = acpi_ns_evaluate_by_handle (obj_entry, params, return_object); + + +cleanup: + + /* Cleanup */ + + if (internal_path) { + acpi_cm_free (internal_path); + } + + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_evaluate_by_handle + * + * PARAMETERS: Obj_entry - NTE of method to execute + * *Return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * **Params - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. + * + * RETURN: Status + * + * DESCRIPTION: Execute the requested method passing the given parameters + * + * MUTEX: Locks Namespace + * + ****************************************************************************/ + +ACPI_STATUS +acpi_ns_evaluate_by_handle ( + ACPI_NAMED_OBJECT *handle, + ACPI_OBJECT_INTERNAL **params, + ACPI_OBJECT_INTERNAL **return_object) +{ + ACPI_NAMED_OBJECT *obj_entry; + ACPI_STATUS status; + ACPI_OBJECT_INTERNAL *local_return_object; + + + /* Check if namespace has been initialized */ + + if (!acpi_gbl_root_object->child_table) { + return (AE_NO_NAMESPACE); + } + + /* Parameter Validation */ + + if (!handle) { + return (AE_BAD_PARAMETER); + } + + if (return_object) { + /* Initialize the return value to an invalid object */ + + *return_object = NULL; + } + + /* Get the prefix handle and NTE */ + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + obj_entry = acpi_ns_convert_handle_to_entry (handle); + if (!obj_entry) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + + /* + * Two major cases here: + * 1) The object is an actual control method -- execute it. + * 2) The object is not a method -- just return it's current + * value + * + * In both cases, the namespace is unlocked by the + * Acpi_ns* procedure + */ + + if (acpi_ns_get_type (obj_entry) == ACPI_TYPE_METHOD) { + /* + * Case 1) We have an actual control method to execute + */ + + status = acpi_ns_execute_control_method (obj_entry, + params, + &local_return_object); + } + + else { + /* + * Case 2) Object is NOT a method, just return its + * current value + */ + + status = acpi_ns_get_object_value (obj_entry, + &local_return_object); + } + + + /* + * Check if there is a return value on the stack that must + * be dealt with + */ + + if (status == AE_CTRL_RETURN_VALUE) { + /* + * If the Method returned a value and the caller + * provided a place to store a returned value, Copy + * the returned value to the object descriptor provided + * by the caller. + */ + + if (return_object) { + /* + * Valid return object, copy the pointer to + * the returned object + */ + + *return_object = local_return_object; + } + + + /* Map AE_RETURN_VALUE to AE_OK, we are done with it */ + + if (status == AE_CTRL_RETURN_VALUE) { + status = AE_OK; + } + } + + /* + * Namespace was unlocked by the handling Acpi_ns* function, + * so we just return + */ + + return (status); + + +unlock_and_exit: + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_execute_control_method + * + * PARAMETERS: Method_entry - The Nte of the object/method + * **Params - List of parameters to pass to the method, + * terminated by NULL. Params itself may be + * NULL if no parameters are being passed. + * + * RETURN: Status + * + * DESCRIPTION: Execute the requested method passing the given parameters + * + * MUTEX: Assumes namespace is locked + * + ****************************************************************************/ + +ACPI_STATUS +acpi_ns_execute_control_method ( + ACPI_NAMED_OBJECT *method_entry, + ACPI_OBJECT_INTERNAL **params, + ACPI_OBJECT_INTERNAL **return_obj_desc) +{ + ACPI_STATUS status; + ACPI_OBJECT_INTERNAL *obj_desc; + + + /* Verify that there is a method associated with this object */ + + obj_desc = acpi_ns_get_attached_object ((ACPI_HANDLE) method_entry); + if (!obj_desc) { + return (AE_ERROR); + } + + /* + * Valid method, Set the current scope to that of the Method, + * and execute it. + */ + + + /* + * Unlock the namespace before execution. This allows namespace access + * via the external Acpi* interfaces while a method is being executed. + * However, any namespace deletion must acquire both the namespace and + * interpter locks to ensure that no thread is using the portion of the + * namespace that is being deleted. + */ + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + + /* + * Excecute the method via the interpreter + */ + status = acpi_aml_execute_method (method_entry, params, return_obj_desc); + + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_get_object_value + * + * PARAMETERS: Object_entry - The Nte of the object + * + * RETURN: Status + * + * DESCRIPTION: Return the current value of the object + * + * MUTEX: Assumes namespace is locked + * + ****************************************************************************/ + +ACPI_STATUS +acpi_ns_get_object_value ( + ACPI_NAMED_OBJECT *object_entry, + ACPI_OBJECT_INTERNAL **return_obj_desc) +{ + ACPI_STATUS status = AE_OK; + ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OBJECT_INTERNAL *val_desc; + + + /* + * We take the value from certain objects directly + */ + + if ((object_entry->type == ACPI_TYPE_PROCESSOR) || + (object_entry->type == ACPI_TYPE_POWER)) + { + + /* + * Create a Reference object to contain the object + */ + obj_desc = acpi_cm_create_internal_object (object_entry->type); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + /* + * Get the attached object + */ + + val_desc = acpi_ns_get_attached_object (object_entry); + if (!val_desc) { + status = AE_NULL_OBJECT; + goto unlock_and_exit; + } + + /* + * Just copy from the original to the return object + */ + + MEMCPY (&obj_desc->common.first_non_common_byte, + &val_desc->common.first_non_common_byte, + (sizeof(ACPI_OBJECT_COMMON) - + sizeof(obj_desc->common.first_non_common_byte))); + } + + + /* + * Other objects require a reference object wrapper which we + * then attempt to resolve. + */ + else { + /* Create an Reference object to contain the object */ + + obj_desc = acpi_cm_create_internal_object (INTERNAL_TYPE_REFERENCE); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + /* Construct a descriptor pointing to the name */ + + obj_desc->reference.op_code = (u8) AML_NAME_OP; + obj_desc->reference.object = (void *) object_entry; + + /* + * Use Acpi_aml_resolve_to_value() to get the associated value. + * The call to Acpi_aml_resolve_to_value causes + * Obj_desc (allocated above) to always be deleted. + */ + + status = acpi_aml_resolve_to_value (&obj_desc); + } + + /* + * If Acpi_aml_resolve_to_value() succeeded, the return value was + * placed in Obj_desc. + */ + + if (status == AE_OK) { + status = AE_CTRL_RETURN_VALUE; + + *return_obj_desc = obj_desc; + } + + +unlock_and_exit: + + /* Unlock the namespace */ + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c new file mode 100644 index 000000000..4b6b3f309 --- /dev/null +++ b/drivers/acpi/namespace/nsload.c @@ -0,0 +1,488 @@ + +/****************************************************************************** + * + * Module Name: nsload - namespace loading/expanding/contracting procedures + * + *****************************************************************************/ + +/* + * 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 "interp.h" +#include "namesp.h" +#include "amlcode.h" +#include "parser.h" +#include "dispatch.h" +#include "debugger.h" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nsload"); + + +/******************************************************************************* + * + * FUNCTION: Acpi_ns_parse_table + * + * PARAMETERS: Table_desc - An ACPI table descriptor for table to parse + * Scope - Where to enter the table into the namespace + * + * RETURN: Status + * + * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops + * + ******************************************************************************/ + +ACPI_STATUS +acpi_ns_parse_table ( + ACPI_TABLE_DESC *table_desc, + ACPI_NAME_TABLE *scope) +{ + ACPI_STATUS status; + + + /* Create the root object */ + + acpi_gbl_parsed_namespace_root = acpi_ps_alloc_op (AML_SCOPE_OP); + if (!acpi_gbl_parsed_namespace_root) { + return (AE_NO_MEMORY); + } + + /* Initialize the root object */ + + ((ACPI_NAMED_OP *) acpi_gbl_parsed_namespace_root)->name = ACPI_ROOT_NAME; + + /* Pass 1: Parse everything except control method bodies */ + + status = acpi_ps_parse_aml (acpi_gbl_parsed_namespace_root, + table_desc->aml_pointer, + table_desc->aml_length, 0); + + if (ACPI_FAILURE (status)) { + return (status); + } + + +#ifndef PARSER_ONLY + status = acpi_ps_walk_parsed_aml (acpi_ps_get_child (acpi_gbl_parsed_namespace_root), + acpi_gbl_parsed_namespace_root, NULL, + scope, NULL, NULL, + table_desc->table_id, + acpi_ds_load2_begin_op, + acpi_ds_load2_end_op); + + + /* + * Now that the internal namespace has been constructed, we can delete the + * parsed namespace, since it is no longer needed + */ + + acpi_ps_delete_parse_tree (acpi_gbl_parsed_namespace_root); + acpi_gbl_parsed_namespace_root = NULL; +#endif + + + return (status); +} + + +/***************************************************************************** + * + * FUNCTION: Acpi_ns_load_table + * + * PARAMETERS: *Pcode_addr - Address of pcode block + * Pcode_length - Length of pcode block + * + * RETURN: Status + * + * DESCRIPTION: Mainline of the AML load/dump subsystem. Sets up the + * input engine, calls handler for outermost object type. + * + ****************************************************************************/ + +ACPI_STATUS +acpi_ns_load_table ( + ACPI_TABLE_DESC *table_desc, + ACPI_NAMED_OBJECT *entry) +{ + ACPI_STATUS status; + + + if (!table_desc->aml_pointer) { + return (AE_BAD_PARAMETER); + } + + + if (!table_desc->aml_length) { + return (AE_BAD_PARAMETER); + } + + + /* + * Parse the table and load the namespace with all named + * objects found within. Control methods are NOT parsed + * at this time. In fact, the control methods cannot be + * parsed until the entire namespace is loaded, because + * if a control method makes a forward reference (call) + * to another control method, we can't continue parsing + * because we don't know how many arguments to parse next! + */ + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ns_parse_table (table_desc, entry->child_table); + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE (status)) { + return (status); + } + + /* + * Now we can parse the control methods. We always parse + * them here for a sanity check, and if configured for + * just-in-time parsing, we delete the control method + * parse trees. + */ + + status = acpi_ds_initialize_objects (table_desc, entry); + + return (status); +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_ns_load_table_by_type + * + * PARAMETERS: Table_type - Id of the table type to load + * + * RETURN: Status + * + * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables + * of the given type are loaded. The mechanism allows this + * routine to be called repeatedly. + * + *****************************************************************************/ + +ACPI_STATUS +acpi_ns_load_table_by_type ( + ACPI_TABLE_TYPE table_type) +{ + u32 i; + ACPI_STATUS status = AE_OK; + ACPI_TABLE_HEADER *table_ptr; + ACPI_TABLE_DESC *table_desc; + + + acpi_cm_acquire_mutex (ACPI_MTX_TABLES); + + + /* + * Table types supported are: + * DSDT (one), SSDT/PSDT (multiple) + */ + + switch (table_type) + { + + case ACPI_TABLE_DSDT: + + table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_DSDT]; + + /* If table already loaded into namespace, just return */ + + if (table_desc->loaded_into_namespace) { + goto unlock_and_exit; + } + + table_desc->table_id = TABLE_ID_DSDT; + + /* Initialize the root of the namespace tree */ + + status = acpi_ns_root_initialize (); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + + /* Now load the single DSDT */ + + status = acpi_ns_load_table (table_desc, acpi_gbl_root_object); + if (ACPI_SUCCESS (status)) { + table_desc->loaded_into_namespace = TRUE; + } + + break; + + + case ACPI_TABLE_SSDT: + + /* + * Traverse list of SSDT tables + */ + + table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_SSDT]; + for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_SSDT].count; i++) { + table_ptr = table_desc->pointer; + + /* + * Only attempt to load table if it is not + * already loaded! + */ + + if (!table_desc->loaded_into_namespace) { + status = acpi_ns_load_table (table_desc, + acpi_gbl_root_object); + if (ACPI_FAILURE (status)) { + break; + } + + table_desc->loaded_into_namespace = TRUE; + } + + table_desc = table_desc->next; + } + + break; + + + case ACPI_TABLE_PSDT: + + /* + * Traverse list of PSDT tables + */ + + table_desc = &acpi_gbl_acpi_tables[ACPI_TABLE_PSDT]; + + for (i = 0; i < acpi_gbl_acpi_tables[ACPI_TABLE_PSDT].count; i++) { + table_ptr = table_desc->pointer; + + /* Only attempt to load table if it is not already loaded! */ + + if (!table_desc->loaded_into_namespace) { + status = acpi_ns_load_table (table_desc, + acpi_gbl_root_object); + if (ACPI_FAILURE (status)) { + break; + } + + table_desc->loaded_into_namespace = TRUE; + } + + table_desc = table_desc->next; + } + + break; + + + default: + status = AE_SUPPORT; + } + + +unlock_and_exit: + + acpi_cm_release_mutex (ACPI_MTX_TABLES); + + return (status); + +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_ns_free_table_entry + * + * PARAMETERS: Entry - The entry to be deleted + * + * RETURNS None + * + * DESCRIPTION: Free an entry in a namespace table. Delete any objects contained + * in the entry, unlink the entry, then mark it unused. + * + ******************************************************************************/ + +void +acpi_ns_free_table_entry ( + ACPI_NAMED_OBJECT *entry) +{ + + if (!entry) { + return; + } + + /* + * Need to delete + * 1) The scope, if any + * 2) An attached object, if any + */ + + if (entry->child_table) { + acpi_cm_free (entry->child_table); + entry->child_table = NULL; + } + + if (entry->object) { + acpi_ns_detach_object (entry->object); + entry->object = NULL; + } + + /* Mark the entry unallocated */ + + entry->name = 0; + + return; +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_ns_delete_subtree + * + * PARAMETERS: Start_handle - Handle in namespace where search begins + * + * RETURNS Status + * + * DESCRIPTION: Walks the namespace starting at the given handle and deletes + * all objects, entries, and scopes in the entire subtree. + * + * TBD: [Investigate] What if any part of this subtree is in use? + * (i.e. on one of the object stacks?) + * + ******************************************************************************/ + +ACPI_STATUS +acpi_ns_delete_subtree ( + ACPI_HANDLE start_handle) +{ + ACPI_STATUS status; + ACPI_HANDLE child_handle; + ACPI_HANDLE parent_handle; + ACPI_HANDLE next_child_handle; + ACPI_HANDLE dummy; + u32 level; + + + parent_handle = start_handle; + child_handle = 0; + level = 1; + + /* + * Traverse the tree of objects until we bubble back up + * to where we started. + */ + + while (level > 0) { + /* Attempt to get the next object in this scope */ + + status = acpi_get_next_object (ACPI_TYPE_ANY, parent_handle, + child_handle, + &next_child_handle); + + /* + * Regardless of the success or failure of the + * previous operation, we are done with the previous + * object (if there was one), and any children it + * may have had. So we can now safely delete it (and + * its scope, if any) + */ + + acpi_ns_free_table_entry (child_handle); + child_handle = next_child_handle; + + + /* Did we get a new object? */ + + if (ACPI_SUCCESS (status)) { + /* Check if this object has any children */ + + if (ACPI_SUCCESS (acpi_get_next_object (ACPI_TYPE_ANY, + child_handle, 0, + &dummy))) + { + /* + * There is at least one child of this object, + * visit the object + */ + + level++; + parent_handle = child_handle; + child_handle = 0; + } + } + + else { + /* + * No more children in this object, go back up to + * the object's parent + */ + level--; + child_handle = parent_handle; + acpi_get_parent (parent_handle, &parent_handle); + } + } + + /* Now delete the starting object, and we are done */ + + acpi_ns_free_table_entry ((ACPI_NAMED_OBJECT*) child_handle); + + + return (AE_OK); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_unload_name_space + * + * PARAMETERS: Handle - Root of namespace subtree to be deleted + * + * RETURN: Status + * + * DESCRIPTION: Shrinks the namespace, typically in response to an undocking + * event. Deletes an entire subtree starting from (and + * including) the given handle. + * + ****************************************************************************/ + +ACPI_STATUS +acpi_ns_unload_namespace ( + ACPI_HANDLE handle) +{ + ACPI_STATUS status; + + + /* Parameter validation */ + + if (!acpi_gbl_root_object->child_table) { + return (AE_NO_NAMESPACE); + } + + if (!handle) { + return (AE_BAD_PARAMETER); + } + + + /* This function does the real work */ + + status = acpi_ns_delete_subtree (handle); + + return (status); +} + + diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c new file mode 100644 index 000000000..1c4ab7c0b --- /dev/null +++ b/drivers/acpi/namespace/nsnames.c @@ -0,0 +1,503 @@ + +/****************************************************************************** + * + * Module Name: nsnames - Name manipulation and search + * + *****************************************************************************/ + +/* + * 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" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nsnames"); + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_name_of_scope + * + * PARAMETERS: Scope - Scope whose name is needed + * + * RETURN: Pointer to storage containing the fully qualified name of + * the scope, in Label format (all segments strung together + * with no separators) + * + * DESCRIPTION: Used via Acpi_ns_name_of_current_scope() and Acpi_ns_last_fQN() + * for label generation in the interpreter, and for debug + * printing in Acpi_ns_search_table(). + * + ***************************************************************************/ + +char * +acpi_ns_name_of_scope ( + ACPI_NAME_TABLE *scope) +{ + char *name_buffer; + ACPI_SIZE size; + ACPI_NAME name; + ACPI_NAMED_OBJECT *entry_to_search; + ACPI_NAMED_OBJECT *parent_entry; + + + if (!acpi_gbl_root_object->child_table || !scope) { + /* + * If the name space has not been initialized, + * this function should not have been called. + */ + return (NULL); + } + + entry_to_search = scope->entries; + + + /* Calculate required buffer size based on depth below root NT */ + + size = 1; + parent_entry = entry_to_search; + while (parent_entry) { + parent_entry = acpi_ns_get_parent_entry (parent_entry); + if (parent_entry) { + size += ACPI_NAME_SIZE; + } + } + + + /* Allocate the buffer */ + + name_buffer = acpi_cm_callocate (size + 1); + if (!name_buffer) { + REPORT_ERROR ("Ns_name_of_scope: allocation failure"); + return (NULL); + } + + + /* Store terminator byte, then build name backwards */ + + name_buffer[size] = '\0'; + while ((size > ACPI_NAME_SIZE) && + acpi_ns_get_parent_entry (entry_to_search)) + { + size -= ACPI_NAME_SIZE; + name = acpi_ns_find_parent_name (entry_to_search); + + /* Put the name into the buffer */ + + MOVE_UNALIGNED32_TO_32 ((name_buffer + size), &name); + entry_to_search = acpi_ns_get_parent_entry (entry_to_search); + } + + name_buffer[--size] = AML_ROOT_PREFIX; + + + return (name_buffer); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_name_of_current_scope + * + * PARAMETERS: none + * + * RETURN: pointer to storage containing the name of the current scope + * + ***************************************************************************/ + +char * +acpi_ns_name_of_current_scope ( + ACPI_WALK_STATE *walk_state) +{ + char *scope_name; + + + if (walk_state && walk_state->scope_info) { + scope_name = + acpi_ns_name_of_scope (walk_state->scope_info->scope.name_table); + + return (scope_name); + } + + REPORT_ERROR ("Current scope pointer is invalid"); + + return (NULL); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_handle_to_pathname + * + * PARAMETERS: Target_handle - Handle of nte whose name is to be found + * Buf_size - Size of the buffer provided + * User_buffer - Where the pathname is returned + * + * RETURN: Status, Buffer is filled with pathname if status == AE_OK + * + * DESCRIPTION: Build and return a full namespace pathname + * + * MUTEX: Locks Namespace + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_handle_to_pathname ( + ACPI_HANDLE target_handle, + u32 *buf_size, + char *user_buffer) +{ + ACPI_STATUS status = AE_OK; + ACPI_NAMED_OBJECT *entry_to_search = NULL; + ACPI_NAMED_OBJECT *temp = NULL; + ACPI_SIZE path_length = 0; + ACPI_SIZE size; + u32 user_buf_size; + ACPI_NAME name; + u8 namespace_was_locked; + + + if (!acpi_gbl_root_object->child_table || !target_handle) { + /* + * If the name space has not been initialized, + * this function should not have been called. + */ + + return (AE_NO_NAMESPACE); + } + + namespace_was_locked = acpi_gbl_acpi_mutex_info[ACPI_MTX_NAMESPACE].locked; + if (!namespace_was_locked) { + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + } + + entry_to_search = acpi_ns_convert_handle_to_entry (target_handle); + if (!entry_to_search) { + return (AE_BAD_PARAMETER); + } + + /* + * Compute length of pathname as 5 * number of name segments. + * Go back up the parent tree to the root + */ + for (size = 0, temp = entry_to_search; + acpi_ns_get_parent_entry (temp); + temp = acpi_ns_get_parent_entry (temp)) + { + size += PATH_SEGMENT_LENGTH; + } + + /* Set return length to the required path length */ + + path_length = size + 1; + user_buf_size = *buf_size; + *buf_size = path_length; + + /* Check if the user buffer is sufficiently large */ + + if (path_length > user_buf_size) { + status = AE_BUFFER_OVERFLOW; + goto unlock_and_exit; + } + + /* Store null terminator */ + + user_buffer[size] = 0; + size -= ACPI_NAME_SIZE; + + /* Put the original ACPI name at the end of the path */ + + MOVE_UNALIGNED32_TO_32 ((user_buffer + size), + &entry_to_search->name); + + user_buffer[--size] = PATH_SEPARATOR; + + /* Build name backwards, putting "." between segments */ + + while ((size > ACPI_NAME_SIZE) && entry_to_search) { + size -= ACPI_NAME_SIZE; + name = acpi_ns_find_parent_name (entry_to_search); + MOVE_UNALIGNED32_TO_32 ((user_buffer + size), &name); + + user_buffer[--size] = PATH_SEPARATOR; + entry_to_search = acpi_ns_get_parent_entry (entry_to_search); + } + + /* + * Overlay the "." preceding the first segment with + * the root name "\" + */ + + user_buffer[size] = '\\'; + + +unlock_and_exit: + + if (!namespace_was_locked) { + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + } + + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_pattern_match + * + * PARAMETERS: Obj_entry - A namespace entry + * Search_for - Wildcard pattern string + * + * DESCRIPTION: Matches a namespace name against a wildcard pattern. Only + * a very simple pattern - 4 chars, either a valid char or a "?" + * to match any. + * + ***************************************************************************/ + +u8 +acpi_ns_pattern_match ( + ACPI_NAMED_OBJECT *obj_entry, + char *search_for) +{ + s32 i; + + + for (i = 0; i < ACPI_NAME_SIZE; i++) { + if (search_for[i] != '?' && + search_for[i] != ((char *) &obj_entry->name)[i]) + { + /* No match */ + + return FALSE; + } + } + + /* name matches pattern */ + + return TRUE; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_name_compare + * + * PARAMETERS: Obj_handle - A namespace entry + * Level - Current nesting level + * Context - A FIND_CONTEXT structure + * + * DESCRIPTION: A User_function called by Acpi_ns_walk_namespace(). It performs + * a pattern match for Acpi_ns_low_find_names(), and updates the list + * and count as required. + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_name_compare ( + ACPI_HANDLE obj_handle, + u32 level, + void *context, + void **return_value) +{ + FIND_CONTEXT *find = context; + + + /* Match, yes or no? */ + + if (acpi_ns_pattern_match ((ACPI_NAMED_OBJECT*) obj_handle, + find->search_for)) + { + /* Name matches pattern */ + + if (find->list) { + find->list[*(find->count)] = obj_handle; + } + + ++*(find->count); + } + + /* Don't terminate the walk */ + return AE_OK; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_low_find_names + * + * PARAMETERS: *This_entry - Table to be searched + * *Search_for - Pattern to be found. + * 4 bytes, ? matches any character. + * *Count - Output count of matches found. + * Outermost caller should preset to 0 + * List[] - Output array of handles. If + * null, only the count is obtained. + * Max_depth - Maximum depth of search. Use + * INT_MAX for an effectively + * unlimited depth. + * + * DESCRIPTION: Low-level find name. + * Traverse the name space finding names which match a search + * pattern, and return an array of handles in List[]. + * + ***************************************************************************/ + +void +acpi_ns_low_find_names ( + ACPI_NAMED_OBJECT *this_entry, + char *search_for, + s32 *count, + ACPI_HANDLE list[], + s32 max_depth) +{ + FIND_CONTEXT find; + + + if (0 == max_depth || !this_entry || !search_for || !count) { + /* + * Zero requested depth, nothing to search, + * nothing to search for, or count pointer bad + */ + + return; + } + + /* Init the context structure used by compare routine */ + + find.list = list; + find.count = count; + find.search_for = search_for; + + /* Walk the namespace and find all matches */ + + acpi_ns_walk_namespace (ACPI_TYPE_ANY, (ACPI_HANDLE) this_entry, + max_depth, NS_WALK_NO_UNLOCK, + acpi_ns_name_compare, &find, NULL); + + if (list) { + /* null-terminate the output array */ + + list[*count] = (ACPI_HANDLE) 0; + } + + return; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_find_names + + * + * PARAMETERS: *Search_for - pattern to be found. + * 4 bytes, ? matches any character. + * If NULL, "????" will be used. + * Start_handle - Root of subtree to be searched, or + * NS_ALL to search the entire namespace + * Max_depth - Maximum depth of search. Use INT_MAX + * for an effectively unlimited depth. + * + * DESCRIPTION: Traverse the name space finding names which match a search + * pattern, and return an array of handles. The end of the + * array is marked by the value (ACPI_HANDLE)0. A return value + * of (ACPI_HANDLE *)0 indicates that no matching names were + * found or that space for the list could not be allocated. + * if Start_handle is NS_ALL (null) search from the root, + * else it is a handle whose children are to be searched. + * + ***************************************************************************/ + +ACPI_HANDLE * +acpi_ns_find_names ( + char *search_for, + ACPI_HANDLE start_handle, + s32 max_depth) +{ + ACPI_HANDLE *list = NULL; + s32 count; + + + if (!acpi_gbl_root_object->child_table) { + /* + * If the name space has not been initialized, + * there surely are no matching names. + */ + return (NULL); + } + + if (NS_ALL == start_handle) { + /* base is root */ + + start_handle = acpi_gbl_root_object; + } + + else if (((ACPI_NAMED_OBJECT *) start_handle)->child_table) { + /* base has children to search */ + + start_handle = + ((ACPI_NAMED_OBJECT *) start_handle)->child_table->entries; + } + + else { + /* + * If base is not the root and has no children, + * there is nothing to search. + */ + return (NULL); + } + + if (!search_for) { + /* Search name not specified */ + + search_for = "????"; + } + + + /* Pass 1. Get required buffer size, don't try to build list */ + + count = 0; + acpi_ns_low_find_names (start_handle, search_for, &count, + NULL, max_depth); + + if (0 == count) { + return (NULL); + } + + /* Allow for trailing null */ + count++; + + list = acpi_cm_callocate (count * sizeof(ACPI_HANDLE)); + if (!list) { + REPORT_ERROR ("Ns_find_names: allocation failure"); + return (NULL); + } + + /* Pass 2. Fill buffer */ + + count = 0; + acpi_ns_low_find_names (start_handle, search_for, &count, list, max_depth); + + return (list); +} + + diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c new file mode 100644 index 000000000..56e497bb0 --- /dev/null +++ b/drivers/acpi/namespace/nsobject.c @@ -0,0 +1,556 @@ + +/****************************************************************************** + * + * Module Name: nsobject - Utilities for objects attached to namespace + * table entries + * + *****************************************************************************/ + +/* + * 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 "namesp.h" +#include "interp.h" +#include "tables.h" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nsobject"); + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_attach_object + * + * PARAMETERS: Handle - Handle of nte + * Object - Object to be attached + * Type - Type of object, or ACPI_TYPE_ANY if not + * known + * + * DESCRIPTION: Record the given object as the value associated with the + * name whose ACPI_HANDLE is passed. If Object is NULL + * and Type is ACPI_TYPE_ANY, set the name as having no value. + * + * MUTEX: Assumes namespace is locked + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_attach_object ( + ACPI_HANDLE handle, + ACPI_HANDLE object, + OBJECT_TYPE_INTERNAL type) +{ + ACPI_NAMED_OBJECT *this_entry = (ACPI_NAMED_OBJECT*) handle; + ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OBJECT_INTERNAL *previous_obj_desc; + OBJECT_TYPE_INTERNAL obj_type = ACPI_TYPE_ANY; + u8 flags; + u16 opcode; + + + /* + * Parameter validation + */ + + if (!acpi_gbl_root_object->child_table) { + /* Name space not initialized */ + + REPORT_ERROR ("Ns_attach_object: Name space not initialized"); + return (AE_NO_NAMESPACE); + } + + if (!handle) { + /* Invalid handle */ + + REPORT_ERROR ("Ns_attach_object: Null name handle"); + return (AE_BAD_PARAMETER); + } + + if (!object && (ACPI_TYPE_ANY != type)) { + /* Null object */ + + REPORT_ERROR ("Ns_attach_object: Null object, but type" + "not ACPI_TYPE_ANY"); + return (AE_BAD_PARAMETER); + } + + if (!VALID_DESCRIPTOR_TYPE (handle, ACPI_DESC_TYPE_NAMED)) { + /* Not a name handle */ + + REPORT_ERROR ("Ns_attach_object: Invalid handle"); + return (AE_BAD_PARAMETER); + } + + /* Check if this object is already attached */ + + if (this_entry->object == object) { + return (AE_OK); + } + + + /* Get the current flags field of the NTE */ + + flags = this_entry->flags; + flags &= ~NTE_AML_ATTACHMENT; + + + /* If null object, we will just install it */ + + if (!object) { + obj_desc = NULL; + obj_type = ACPI_TYPE_ANY; + } + + /* + * If the object is an NTE with an attached object, + * we will use that (attached) object + */ + + else if (VALID_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_NAMED) && + ((ACPI_NAMED_OBJECT*) object)->object) + { + /* + * Value passed is a name handle and that name has a + * non-null value. Use that name's value and type. + */ + + obj_desc = ((ACPI_NAMED_OBJECT*) object)->object; + obj_type = ((ACPI_NAMED_OBJECT*) object)->type; + + /* + * Copy appropriate flags + */ + + if (((ACPI_NAMED_OBJECT*) object)->flags & NTE_AML_ATTACHMENT) { + flags |= NTE_AML_ATTACHMENT; + } + } + + + /* + * Otherwise, we will use the parameter object, but we must type + * it first + */ + + else { + obj_desc = (ACPI_OBJECT_INTERNAL *) object; + + + /* If a valid type (non-ANY) was given, just use it */ + + if (ACPI_TYPE_ANY != type) { + obj_type = type; + } + + + /* + * Type is TYPE_Any, we must try to determinte the + * actual type of the object + */ + + /* + * Check if value points into the AML code + */ + else if (acpi_tb_system_table_pointer (object)) { + /* + * Object points into the AML stream. + * Set a flag bit in the NTE to indicate this + */ + + flags |= NTE_AML_ATTACHMENT; + + /* + * The next byte (perhaps the next two bytes) + * will be the AML opcode + */ + + MOVE_UNALIGNED16_TO_16 (&opcode, object); + + /* Check for a recognized Op_code */ + + switch ((u8) opcode) + { + + case AML_OP_PREFIX: + + if (opcode != AML_REVISION_OP) { + /* + * Op_prefix is unrecognized unless part + * of Revision_op + */ + + break; + } + + /* Else fall through to set type as Number */ + + + case AML_ZERO_OP: case AML_ONES_OP: case AML_ONE_OP: + case AML_BYTE_OP: case AML_WORD_OP: case AML_DWORD_OP: + + obj_type = ACPI_TYPE_NUMBER; + break; + + + case AML_STRING_OP: + + obj_type = ACPI_TYPE_STRING; + break; + + + case AML_BUFFER_OP: + + obj_type = ACPI_TYPE_BUFFER; + break; + + + case AML_MUTEX_OP: + + obj_type = ACPI_TYPE_MUTEX; + break; + + + case AML_PACKAGE_OP: + + obj_type = ACPI_TYPE_PACKAGE; + break; + + + default: + + return (AE_TYPE); + break; + } + } + + else { + /* + * Cannot figure out the type -- set to Def_any which + * will print as an error in the name table dump + */ + + + obj_type = INTERNAL_TYPE_DEF_ANY; + } + } + + + /* + * Must increment the new value's reference count + * (if it is an internal object) + */ + + acpi_cm_add_reference (obj_desc); + + /* Save the existing object (if any) for deletion later */ + + previous_obj_desc = this_entry->object; + + /* Install the object and set the type, flags */ + + this_entry->object = obj_desc; + this_entry->type = (u8) obj_type; + this_entry->flags = flags; + + + /* + * Delete an existing attached object. + */ + + if (previous_obj_desc) { + /* One for the attach to the NTE */ + acpi_cm_remove_reference (previous_obj_desc); + /* Now delete */ + acpi_cm_remove_reference (previous_obj_desc); + } + + return (AE_OK); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_attach_method + * + * PARAMETERS: Handle - Handle of nte to be set + * Offset - Value to be set + * Length - Length associated with value + * + * DESCRIPTION: Record the given offset and p-code length of the method + * whose handle is passed + * + * MUTEX: Assumes namespace is locked + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_attach_method ( + ACPI_HANDLE handle, + u8 *pcode_addr, + u32 pcode_length) +{ + ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_OBJECT_INTERNAL *previous_obj_desc; + ACPI_NAMED_OBJECT *this_entry = (ACPI_NAMED_OBJECT*) handle; + + + /* Parameter validation */ + + if (!acpi_gbl_root_object->child_table) { + /* Name space uninitialized */ + + REPORT_ERROR ("Ns_attach_method: name space uninitialized"); + return (AE_NO_NAMESPACE); + } + + if (!handle) { + /* Null name handle */ + + REPORT_ERROR ("Ns_attach_method: null name handle"); + return (AE_BAD_PARAMETER); + } + + + /* Allocate a method descriptor */ + + obj_desc = acpi_cm_create_internal_object (ACPI_TYPE_METHOD); + if (!obj_desc) { + /* Method allocation failure */ + + REPORT_ERROR ("Ns_attach_method: allocation failure"); + return (AE_NO_MEMORY); + } + + /* Init the method info */ + + obj_desc->method.pcode = pcode_addr; + obj_desc->method.pcode_length = pcode_length; + + /* Update reference count and install */ + + acpi_cm_add_reference (obj_desc); + + previous_obj_desc = this_entry->object; + this_entry->object = obj_desc; + + + /* + * Delete an existing object. Don't try to re-use in case it is shared + */ + if (previous_obj_desc) { + acpi_cm_remove_reference (previous_obj_desc); + } + + return (AE_OK); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_detach_object + * + * PARAMETERS: Object - An object whose Value will be deleted + * + * RETURN: None. + * + * DESCRIPTION: Delete the Value associated with a namespace object. If the + * Value is an allocated object, it is freed. Otherwise, the + * field is simply cleared. + * + ***************************************************************************/ + +void +acpi_ns_detach_object ( + ACPI_HANDLE object) +{ + ACPI_NAMED_OBJECT *entry = object; + ACPI_OBJECT_INTERNAL *obj_desc; + + + obj_desc = entry->object; + if (!obj_desc) { + return; + } + + /* Clear the entry in all cases */ + + entry->object = NULL; + + /* Found a valid value */ + + /* + * Not every value is an object allocated via Acpi_cm_callocate, + * - must check + */ + + if (!acpi_tb_system_table_pointer (obj_desc)) { + /* Attempt to delete the object (and all subobjects) */ + + acpi_cm_remove_reference (obj_desc); + } + + return; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_get_attached_object + * + * PARAMETERS: Handle - Handle of nte to be examined + * + * RETURN: Current value of the object field from nte whose handle is + * passed + * + ***************************************************************************/ + +void * +acpi_ns_get_attached_object ( + ACPI_HANDLE handle) +{ + + if (!handle) { + /* handle invalid */ + + REPORT_WARNING ("Ns_get_attached_object: Null handle"); + return (NULL); + } + + return (((ACPI_NAMED_OBJECT*) handle)->object); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_compare_object + * + * PARAMETERS: Obj_handle - A namespace entry + * Level - Current nesting level + * Obj_desc - The value to be compared + * + * DESCRIPTION: A User_function called by Acpi_ns_walk_namespace(). It performs + * a comparison for Acpi_ns_find_attached_object(). The comparison is against + * the value in the value field of the Obj_handle (an NTE). + * If a match is found, the handle is returned, which aborts + * Acpi_ns_walk_namespace. + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_compare_object ( + ACPI_HANDLE obj_handle, + u32 level, + void *obj_desc, + void **return_value) +{ + + if (((ACPI_NAMED_OBJECT*) obj_handle)->object == obj_desc) { + if (return_value) { + *return_value = obj_handle; + } + + /* Stop the walk */ + return AE_CTRL_TERMINATE; + } + + /* Not found, continue the walk */ + return AE_OK; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_find_attached_object + * + * PARAMETERS: *Obj_desc - Value to be found in ptr_val field. + * Start_handle - Root of subtree to be searched, or + * NS_ALL to search the entire namespace + * Max_depth - Maximum depth of search. Use INT_MAX + * for an effectively unlimited depth. + * + * DESCRIPTION: Traverse the name space until finding a name whose Value field + * matches the Obj_desc parameter, and return a handle to that + * name, or (ACPI_HANDLE)0 if none exists. + * if Start_handle is NS_ALL (null) search from the root, + * else it is a handle whose children are to be searched. + * + ***************************************************************************/ + +ACPI_HANDLE +acpi_ns_find_attached_object ( + ACPI_OBJECT_INTERNAL *obj_desc, + ACPI_HANDLE start_handle, + s32 max_depth) +{ + ACPI_HANDLE ret_object; + ACPI_STATUS status; + + + /* Parameter validation */ + + if (!obj_desc) { + return (NULL); + } + + if (0 == max_depth) { + return (NULL); + } + + if (!acpi_gbl_root_object->child_table) { + /* + * If the name space has not been initialized, + * there surely are no matching values. + */ + return (NULL); + } + + if (NS_ALL == start_handle) { + start_handle = acpi_gbl_root_object; + } + + else { + /* + * If base is not the root and has no children, + * there is nothing to search. + */ + return (NULL); + } + + + /* + * Walk namespace until a match is found. + * Either the matching object is returned, or NULL in case + * of no match. + */ + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, start_handle, + max_depth, NS_WALK_NO_UNLOCK, + acpi_ns_compare_object, + obj_desc, &ret_object); + + if (ACPI_FAILURE (status)) { + ret_object = NULL; + } + + return (ret_object); +} + + diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c new file mode 100644 index 000000000..19fad8ad6 --- /dev/null +++ b/drivers/acpi/namespace/nssearch.c @@ -0,0 +1,646 @@ + +/****************************************************************************** + * + * Module Name: nssearch - Namespace search + * + *****************************************************************************/ + +/* + * 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" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nssearch"); + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_search_one_scope + * + * PARAMETERS: *Entry_name - Ascii ACPI name to search for + * *Name_table - Starting table where search will begin + * Type - Object type to match + * **Ret_entry - Where the matched NTE is returned + * *Ret_info - Where info about the search is returned + * + * RETURN: Status and return information via NS_SEARCH_DATA + * + * DESCRIPTION: Search a single namespace table. Performs a simple search, + * does not add entries or search parents. + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_search_one_scope ( + u32 entry_name, + ACPI_NAME_TABLE *name_table, + OBJECT_TYPE_INTERNAL type, + ACPI_NAMED_OBJECT **ret_entry, + NS_SEARCH_DATA *ret_info) +{ + u32 position; + ACPI_NAME_TABLE *this_table; + ACPI_NAME_TABLE *previous_table = name_table; + ACPI_NAMED_OBJECT *entries; + u8 table_full = TRUE; + ACPI_NAME_TABLE *table_with_empty_slots = NULL; + u32 empty_slot_position = 0; + + + + /* + * Name tables are built (and subsequently dumped) in the + * order in which the names are encountered during the namespace load; + * + * All namespace searching will be linear; If a table overflows an + * additional segment will be allocated and added (chained). + * + * Start linear search at top of table + */ + position = 0; + this_table = name_table; + entries = this_table->entries; + + + /* Init return data */ + + if (ret_info) { + ret_info->name_table = this_table; + } + + + /* + * Search entire name table, including all linked appendages + */ + + while (this_table) { + /* + * Search for name in table, starting at Position. Stop + * searching upon examining all entries in the table. + * + */ + + entries = this_table->entries; + while (position < NS_TABLE_SIZE) { + /* Check for a valid entry */ + + if (!entries[position].name) { + if (table_full) { + /* + * There is room in the table for more + * entries, if necessary + */ + + table_full = FALSE; + table_with_empty_slots = this_table; + empty_slot_position = position; + } + } + + /* Search for name in table */ + + else if (entries[position].name == entry_name) { + /* + * Found matching entry. Capture type if + * appropriate before returning the entry. + */ + + /* + * The Def_field_defn and Bank_field_defn cases + * are actually looking up the Region in which + * the field will be defined + */ + + if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) || + (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) + { + type = ACPI_TYPE_REGION; + } + + /* + * Scope, Def_any, and Index_field_defn are bogus + * "types" which do not actually have anything + * to do with the type of the name being looked + * up. For any other value of Type, if the type + * stored in the entry is Any (i.e. unknown), + * save the actual type. + */ + + if (type != INTERNAL_TYPE_SCOPE && + type != INTERNAL_TYPE_DEF_ANY && + type != INTERNAL_TYPE_INDEX_FIELD_DEFN && + entries[position].type == ACPI_TYPE_ANY) + { + entries[position].type = (u8) type; + } + + *ret_entry = &entries[position]; + return (AE_OK); + } + + + /* Didn't match name, move on to the next entry */ + + position++; + } + + + /* + * Just examined last slot in this table, move on + * to next appendate. + * All appendages, even to the root NT, contain + * NS_TABLE_SIZE entries. + */ + + previous_table = this_table; + this_table = this_table->next_table; + + position = 0; + } + + + /* Searched entire table, not found */ + + + if (ret_info) { + /* + * Save info on if/where a slot is available + * (name was not found) + */ + + ret_info->table_full = table_full; + if (table_full) { + ret_info->name_table = previous_table; + } + + else { + ret_info->position = empty_slot_position; + ret_info->name_table = table_with_empty_slots; + } + } + + return (AE_NOT_FOUND); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_search_parent_tree + * + * PARAMETERS: *Entry_name - Ascii ACPI name to search for + * *Name_table - Starting table where search will begin + * Type - Object type to match + * **Ret_entry - Where the matched NTE is returned + * + * RETURN: Status + * + * DESCRIPTION: Called when a name has not been found in the current namespace + * table. Before adding it or giving up, ACPI scope rules require + * searching enclosing scopes in cases identified by Acpi_ns_local(). + * + * "A name is located by finding the matching name in the current + * name space, and then in the parent name space. If the parent + * name space does not contain the name, the search continues + * recursively until either the name is found or the name space + * does not have a parent (the root of the name space). This + * indicates that the name is not found" (From ACPI Specification, + * section 5.3) + * + ***************************************************************************/ + + +ACPI_STATUS +acpi_ns_search_parent_tree ( + u32 entry_name, + ACPI_NAME_TABLE *name_table, + OBJECT_TYPE_INTERNAL type, + ACPI_NAMED_OBJECT **ret_entry) +{ + ACPI_STATUS status; + ACPI_NAMED_OBJECT *parent_entry; + ACPI_NAMED_OBJECT *entries; + + + entries = name_table->entries; + + /* + * If no parent or type is "local", we won't be searching the + * parent tree. + */ + + if (!acpi_ns_local (type) && + name_table->parent_entry) + { + parent_entry = name_table->parent_entry; + /* + * Search parents until found or we have backed up to + * the root + */ + + while (parent_entry) { + /* Search parent scope */ + /* TBD: [Investigate] Why ACPI_TYPE_ANY? */ + + status = acpi_ns_search_one_scope (entry_name, + parent_entry->child_table, + ACPI_TYPE_ANY, + ret_entry, NULL); + + if (status == AE_OK) { + return (status); + } + + /* + * Not found here, go up another level + * (until we reach the root) + */ + + parent_entry = acpi_ns_get_parent_entry (parent_entry); + } + + /* Not found in parent tree */ + } + + + return (AE_NOT_FOUND); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_create_and_link_new_table + * + * PARAMETERS: *Name_table - The table that is to be "extended" by + * the creation of an appendage table. + * + * RETURN: Status + * + * DESCRIPTION: Allocate a new namespace table, initialize it, and link it + * into the parent table. + * + * NOTE: We are in the first or second pass load mode, want to + * add a new table entry, and the current table is full. + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_create_and_link_new_table ( + ACPI_NAME_TABLE *name_table) +{ + ACPI_NAME_TABLE *new_table; + ACPI_NAMED_OBJECT *parent_entry; + ACPI_STATUS status = AE_OK; + + + /* Sanity check on the data structure */ + + if (name_table->next_table) { + /* We should never get here (an appendage already allocated) */ + + return (AE_AML_INTERNAL); + } + + + /* + * We can use the parent entries from the current table + * Since the parent information remains the same. + */ + parent_entry = name_table->parent_entry; + + + /* Allocate and chain an appendage to the filled table */ + + new_table = acpi_ns_allocate_name_table (NS_TABLE_SIZE); + if (!new_table) { + REPORT_ERROR ("Name Table appendage allocation failure"); + return (AE_NO_MEMORY); + } + + /* + * Allocation successful. Init the new table. + */ + name_table->next_table = new_table; + acpi_ns_initialize_table (new_table, parent_entry->child_table, + parent_entry); + + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_initialize_table + * + * PARAMETERS: New_table - The new table to be initialized + * Parent_table - The parent (owner) scope + * Parent_entry - The NTE for the parent + * + * RETURN: None + * + * DESCRIPTION: Initialize a new namespace table. Simple, but called + * from several places -- code should be kept in one place. + * + ***************************************************************************/ + +void +acpi_ns_initialize_table ( + ACPI_NAME_TABLE *new_table, + ACPI_NAME_TABLE *parent_table, + ACPI_NAMED_OBJECT *parent_entry) +{ + u8 i; + + + new_table->parent_entry = parent_entry; + new_table->parent_table = parent_table; + + + /* Init each named object entry in the table */ + + for (i = 0; i < NS_TABLE_SIZE; i++) { + new_table->entries[i].this_index = i; + new_table->entries[i].data_type = ACPI_DESC_TYPE_NAMED; + } + +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_initialize_entry + * + * PARAMETERS: Name_table - The containing table for the new NTE + * Position - Position (index) of the new NTE in the table + * Entry_name - ACPI name of the new entry + * Type - ACPI object type of the new entry + * Previous_entry - Link back to the previous entry (can span + * multiple tables) + * + * RETURN: None + * + * DESCRIPTION: Initialize a new entry within a namespace table. + * + ***************************************************************************/ + +void +acpi_ns_initialize_entry ( + ACPI_WALK_STATE *walk_state, + ACPI_NAME_TABLE *name_table, + u32 position, + u32 entry_name, + OBJECT_TYPE_INTERNAL type) +{ + ACPI_NAMED_OBJECT *new_entry; + u16 owner_id = TABLE_ID_DSDT; + ACPI_NAMED_OBJECT *entries; + + + /* + * Get the owner ID from the Walk state + * The owner ID is used to track table deletion and + * deletion of objects created by methods + */ + if (walk_state) { + owner_id = walk_state->owner_id; + } + + /* The new entry is given by two parameters */ + + entries = name_table->entries; + new_entry = &entries[position]; + + /* Init the new entry */ + + new_entry->data_type = ACPI_DESC_TYPE_NAMED; + new_entry->name = entry_name; + new_entry->owner_id = owner_id; + new_entry->reference_count = 1; + + + /* + * If adding a name with unknown type, or having to + * add the region in order to define fields in it, we + * have a forward reference. + */ + + if ((ACPI_TYPE_ANY == type) || + (INTERNAL_TYPE_DEF_FIELD_DEFN == type) || + (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) + { + /* + * We don't want to abort here, however! + * We will fill in the actual type when the + * real definition is found later. + */ + + } + + /* + * The Def_field_defn and Bank_field_defn cases are actually + * looking up the Region in which the field will be defined + */ + + if ((INTERNAL_TYPE_DEF_FIELD_DEFN == type) || + (INTERNAL_TYPE_BANK_FIELD_DEFN == type)) + { + type = ACPI_TYPE_REGION; + } + + /* + * Scope, Def_any, and Index_field_defn are bogus "types" which do + * not actually have anything to do with the type of the name + * being looked up. Save any other value of Type as the type of + * the entry. + */ + + if ((type != INTERNAL_TYPE_SCOPE) && + (type != INTERNAL_TYPE_DEF_ANY) && + (type != INTERNAL_TYPE_INDEX_FIELD_DEFN)) + { + new_entry->type = (u8) type; + } + + return; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_search_and_enter + * + * PARAMETERS: Entry_name - Ascii ACPI name to search for (4 chars) + * *Name_table - Starting table where search will begin + * Interpreter_mode - Add names only in MODE_Load_pass_x. Otherwise, + * search only. + * Type - Object type to match + * **Ret_entry - Where the matched NTE is returned + * + * RETURN: Status + * + * DESCRIPTION: Search for a name segment in a single name table, + * optionally adding it if it is not found. If the passed + * Type is not Any and the type previously stored in the + * entry was Any (i.e. unknown), update the stored type. + * + * In IMODE_EXECUTE, search only. + * In other modes, search and add if not found. + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_search_and_enter ( + u32 entry_name, + ACPI_WALK_STATE *walk_state, + ACPI_NAME_TABLE *name_table, + OPERATING_MODE interpreter_mode, + OBJECT_TYPE_INTERNAL type, + u32 flags, + ACPI_NAMED_OBJECT **ret_entry) +{ + u32 position; /* position in table */ + ACPI_STATUS status; + NS_SEARCH_DATA search_info; + ACPI_NAMED_OBJECT *entry; + ACPI_NAMED_OBJECT *entries; + + + /* Parameter validation */ + + if (!name_table || !entry_name || !ret_entry) { + REPORT_ERROR ("Ns_search_and_enter: bad parameter"); + return (AE_BAD_PARAMETER); + } + + + /* Name must consist of printable characters */ + + if (!acpi_cm_valid_acpi_name (entry_name)) { + return (AE_BAD_CHARACTER); + } + + + /* Try to find the name in the table specified by the caller */ + + *ret_entry = ENTRY_NOT_FOUND; + status = acpi_ns_search_one_scope (entry_name, name_table, + type, ret_entry, &search_info); + if (status != AE_NOT_FOUND) { + /* + * Either found it or there was an error + * -- finished either way + */ + + return (status); + } + + + /* + * Not found in the table. If we are NOT performing the + * first pass (name entry) of loading the namespace, search + * the parent tree (all the way to the root if necessary.) + * We don't want to perform the parent search when the + * namespace is actually being loaded. We want to perform + * the search when namespace references are being resolved + * (load pass 2) and during the execution phase. + */ + + if ((interpreter_mode != IMODE_LOAD_PASS1) && + (flags & NS_SEARCH_PARENT)) + { + /* + * Not found in table - search parent tree according + * to ACPI specification + */ + + status = acpi_ns_search_parent_tree (entry_name, name_table, + type, ret_entry); + + if (status == AE_OK) { + return (status); + } + } + + + /* + * In execute mode, just search, never add names. Exit now. + */ + + if (interpreter_mode == IMODE_EXECUTE) { + return (AE_NOT_FOUND); + } + + + /* + * Extract the pertinent info from the search result struct. + * Name_table and position might now point to an appendage + */ + name_table = search_info.name_table; + position = search_info.position; + + + /* + * This block handles the case where the existing table is full. + * we must allocate a new table before we can initialize a new entry + */ + + if (search_info.table_full) { + status = acpi_ns_create_and_link_new_table (name_table); + if (status != AE_OK) { + return (status); + } + + /* Point to the first slot in the new table */ + + name_table = name_table->next_table; + position = 0; + } + + + /* + * There is room in the table (or we have just allocated a new one.) + * Initialize the new entry + */ + + acpi_ns_initialize_entry (walk_state, name_table, position, + entry_name, type); + + + entries = name_table->entries; + *ret_entry = &entries[position]; + entry = &entries[position]; + + /* + * Increment the reference count(s) of all parents up to + * the root! + */ + + while (acpi_ns_get_parent_entry (entry)) { + entry = acpi_ns_get_parent_entry (entry); + entry->reference_count++; + } + + + return (AE_OK); +} + diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c new file mode 100644 index 000000000..c938ede93 --- /dev/null +++ b/drivers/acpi/namespace/nsutils.c @@ -0,0 +1,886 @@ + +/****************************************************************************** + * + * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing + * parents and siblings and Scope manipulation + * + *****************************************************************************/ + +/* + * 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 "namesp.h" +#include "interp.h" +#include "amlcode.h" +#include "tables.h" + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nsutils"); + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_valid_root_prefix + * + * PARAMETERS: Prefix - Character to be checked + * + * RETURN: TRUE if a valid prefix + * + * DESCRIPTION: Check if a character is a valid ACPI Root prefix + * + ***************************************************************************/ + +u8 +acpi_ns_valid_root_prefix ( + char prefix) +{ + + return ((u8) (prefix == '\\')); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_valid_path_separator + * + * PARAMETERS: Sep - Character to be checked + * + * RETURN: TRUE if a valid path separator + * + * DESCRIPTION: Check if a character is a valid ACPI path separator + * + ***************************************************************************/ + +u8 +acpi_ns_valid_path_separator ( + char sep) +{ + + return ((u8) (sep == '.')); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_get_type + * + * PARAMETERS: Handle - Handle of nte to be examined + * + * RETURN: Type field from nte whose handle is passed + * + ***************************************************************************/ + +OBJECT_TYPE_INTERNAL +acpi_ns_get_type ( + ACPI_HANDLE handle) +{ + + if (!handle) { + /* Handle invalid */ + + REPORT_WARNING ("Ns_get_type: Null handle"); + return (ACPI_TYPE_ANY); + } + + return (((ACPI_NAMED_OBJECT*) handle)->type); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_local + * + * PARAMETERS: Type - A namespace object type + * + * RETURN: LOCAL if names must be found locally in objects of the + * passed type, 0 if enclosing scopes should be searched + * + ***************************************************************************/ + +s32 +acpi_ns_local ( + OBJECT_TYPE_INTERNAL type) +{ + + if (!acpi_cm_valid_object_type (type)) { + /* type code out of range */ + + REPORT_WARNING ("Ns_local: Invalid Object Type"); + return (NSP_NORMAL); + } + + return ((s32) acpi_gbl_ns_properties[type] & NSP_LOCAL); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_internalize_name + * + * PARAMETERS: *External_name - External representation of name + * **Converted Name - Where to return the resulting + * internal represention of the name + * + * RETURN: Status + * + * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0") + * to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) + * + ****************************************************************************/ + +ACPI_STATUS +acpi_ns_internalize_name ( + char *external_name, + char **converted_name) +{ + char *result = NULL; + char *internal_name; + ACPI_SIZE num_segments; + u8 fully_qualified = FALSE; + u32 i; + + + if ((!external_name) || + (*external_name == 0) || + (!converted_name)) + { + return (AE_BAD_PARAMETER); + } + + + /* + * For the internal name, the required length is 4 bytes + * per segment, plus 1 each for Root_prefix, Multi_name_prefix_op, + * segment count, trailing null (which is not really needed, + * but no there's harm in putting it there) + * + * strlen() + 1 covers the first Name_seg, which has no + * path separator + */ + + if (acpi_ns_valid_root_prefix (external_name[0])) { + fully_qualified = TRUE; + external_name++; + } + + + /* + * Determine the number of ACPI name "segments" by counting + * the number of path separators within the string. Start + * with one segment since the segment count is (# separators) + * + 1, and zero separators is ok. + */ + + num_segments = 1; + for (i = 0; external_name[i]; i++) { + if (acpi_ns_valid_path_separator (external_name[i])) { + num_segments++; + } + } + + + /* We need a segment to store the internal version of the name */ + + internal_name = acpi_cm_callocate ((ACPI_NAME_SIZE * num_segments) + 4); + if (!internal_name) { + return (AE_NO_MEMORY); + } + + + /* Setup the correct prefixes, counts, and pointers */ + + if (fully_qualified) { + internal_name[0] = '\\'; + internal_name[1] = AML_MULTI_NAME_PREFIX_OP; + internal_name[2] = (char) num_segments; + result = &internal_name[3]; + } + else { + internal_name[0] = AML_MULTI_NAME_PREFIX_OP; + internal_name[1] = (char) num_segments; + result = &internal_name[2]; + } + + + /* Build the name (minus path separators) */ + + for (; num_segments; num_segments--) { + for (i = 0; i < ACPI_NAME_SIZE; i++) { + if (acpi_ns_valid_path_separator (*external_name) || + (*external_name == 0)) + { + /* + * Pad the segment with underscore(s) if + * segment is short + */ + + result[i] = '_'; + } + + else { + /* Convert char to uppercase and save it */ + + result[i] = (char) TOUPPER (*external_name); + external_name++; + } + + } + + /* Now we must have a path separator, or the pathname is bad */ + + if (!acpi_ns_valid_path_separator (*external_name) && + (*external_name != 0)) + { + acpi_cm_free (internal_name); + return (AE_BAD_PARAMETER); + } + + /* Move on the next segment */ + + external_name++; + result += ACPI_NAME_SIZE; + } + + + /* Return the completed name */ + + /* Terminate the string! */ + *result = 0; + *converted_name = internal_name; + + + + return (AE_OK); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_externalize_name + * + * PARAMETERS: *Internal_name - Internal representation of name + * **Converted_name - Where to return the resulting + * external representation of name + * + * RETURN: Status + * + * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) + * to its external form (e.g. "\_PR_.CPU0") + * + ****************************************************************************/ + +ACPI_STATUS +acpi_ns_externalize_name ( + u32 internal_name_length, + char *internal_name, + u32 *converted_name_length, + char **converted_name) +{ + u32 prefix_length = 0; + u32 names_index = 0; + u32 names_count = 0; + u32 i = 0; + u32 j = 0; + + if (internal_name_length < 0 || + !internal_name || + !converted_name_length || + !converted_name) + { + return (AE_BAD_PARAMETER); + } + + /* + * Check for a prefix (one '\' | one or more '^'). + */ + switch (internal_name[0]) + { + case '\\': + prefix_length = 1; + break; + + case '^': + for (i = 0; i < internal_name_length; i++) { + if (internal_name[i] != '^') { + prefix_length = i + 1; + } + } + + if (i == internal_name_length) { + prefix_length = i; + } + + break; + } + + /* + * Check for object names. Note that there could be 0-255 of these + * 4-byte elements. + */ + if (prefix_length < internal_name_length) { + switch (internal_name[prefix_length]) + { + + /* <count> 4-byte names */ + + case AML_MULTI_NAME_PREFIX_OP: + names_index = prefix_length + 2; + names_count = (u32) internal_name[prefix_length + 1]; + break; + + + /* two 4-byte names */ + + case AML_DUAL_NAME_PREFIX: + names_index = prefix_length + 1; + names_count = 2; + break; + + + /* Null_name */ + + case 0: + names_index = 0; + names_count = 0; + break; + + + /* one 4-byte name */ + + default: + names_index = prefix_length; + names_count = 1; + break; + } + } + + /* + * Calculate the length of Converted_name, which equals the length + * of the prefix, length of all object names, length of any required + * punctuation ('.') between object names, plus the NULL terminator. + */ + *converted_name_length = prefix_length + (4 * names_count) + + ((names_count > 0) ? (names_count - 1) : 0) + 1; + + /* + * Check to see if we're still in bounds. If not, there's a problem + * with Internal_name (invalid format). + */ + if (*converted_name_length > internal_name_length) { + REPORT_ERROR ("Ns_externalize_name: Invalid internal name.\n"); + return (AE_BAD_PATHNAME); + } + + /* + * Build Converted_name... + */ + + (*converted_name) = acpi_cm_callocate (*converted_name_length); + if (!(*converted_name)) { + return (AE_NO_MEMORY); + } + + j = 0; + + for (i = 0; i < prefix_length; i++) { + (*converted_name)[j++] = internal_name[i]; + } + + if (names_count > 0) { + for (i = 0; i < names_count; i++) { + if (i > 0) { + (*converted_name)[j++] = '.'; + } + + (*converted_name)[j++] = internal_name[names_index++]; + (*converted_name)[j++] = internal_name[names_index++]; + (*converted_name)[j++] = internal_name[names_index++]; + (*converted_name)[j++] = internal_name[names_index++]; + } + } + + return (AE_OK); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_convert_handle_to_entry + * + * PARAMETERS: Handle - Handle to be converted to an NTE + * + * RETURN: A Name table entry pointer + * + * DESCRIPTION: Convert a namespace handle to a real NTE + * + ****************************************************************************/ + +ACPI_NAMED_OBJECT* +acpi_ns_convert_handle_to_entry ( + ACPI_HANDLE handle) +{ + + /* + * Simple implementation for now; + * TBD: [Future] Real integer handles allow for more verification + * and keep all pointers within this subsystem! + */ + + if (!handle) { + return NULL; + } + + if (handle == ACPI_ROOT_OBJECT) { + return acpi_gbl_root_object; + } + + + /* We can at least attempt to verify the handle */ + + if (!VALID_DESCRIPTOR_TYPE (handle, ACPI_DESC_TYPE_NAMED)) { + return NULL; + } + + return (ACPI_NAMED_OBJECT*) handle; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_convert_entry_to_handle + * + * PARAMETERS: Nte - NTE to be converted to a Handle + * + * RETURN: An USER ACPI_HANDLE + * + * DESCRIPTION: Convert a real NTE to a namespace handle + * + ****************************************************************************/ + +ACPI_HANDLE +acpi_ns_convert_entry_to_handle(ACPI_NAMED_OBJECT*nte) +{ + + + /* + * Simple implementation for now; + * TBD: [Future] Real integer handles allow for more verification + * and keep all pointers within this subsystem! + */ + + return (ACPI_HANDLE) nte; + + +/* --------------------------------------------------- + + if (!Nte) { + return NULL; + } + + if (Nte == Acpi_gbl_Root_object) { + return ACPI_ROOT_OBJECT; + } + + + return (ACPI_HANDLE) Nte; +------------------------------------------------------*/ +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_ns_terminate + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: free memory allocated for table storage. + * + ******************************************************************************/ + +void +acpi_ns_terminate (void) +{ + ACPI_OBJECT_INTERNAL *obj_desc; + ACPI_NAMED_OBJECT *entry; + + + entry = acpi_gbl_root_object; + + /* + * 1) Free the entire namespace -- all objects, tables, and stacks + */ + /* + * Delete all objects linked to the root + * (additional table descriptors) + */ + + acpi_ns_delete_namespace_subtree (entry); + + /* Detach any object(s) attached to the root */ + + obj_desc = acpi_ns_get_attached_object (entry); + if (obj_desc) { + acpi_ns_detach_object (entry); + acpi_cm_remove_reference (obj_desc); + } + + acpi_ns_delete_name_table (entry->child_table); + entry->child_table = NULL; + + + REPORT_SUCCESS ("Entire namespace and objects deleted"); + + /* + * 2) Now we can delete the ACPI tables + */ + + acpi_tb_delete_acpi_tables (); + + return; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_opens_scope + * + * PARAMETERS: Type - A valid namespace type + * + * RETURN: NEWSCOPE if the passed type "opens a name scope" according + * to the ACPI specification, else 0 + * + ***************************************************************************/ + +s32 +acpi_ns_opens_scope ( + OBJECT_TYPE_INTERNAL type) +{ + + if (!acpi_cm_valid_object_type (type)) { + /* type code out of range */ + + REPORT_WARNING ("Ns_opens_scope: Invalid Object Type"); + return (NSP_NORMAL); + } + + return (((s32) acpi_gbl_ns_properties[type]) & NSP_NEWSCOPE); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_get_named_object + * + * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The + * \ (backslash) and ^ (carat) prefixes, and the + * . (period) to separate segments are supported. + * In_scope - Root of subtree to be searched, or NS_ALL for the + * root of the name space. If Name is fully + * qualified (first char is '\'), the passed value + * of Scope will not be accessed. + * Out_nte - Where the Nte is returned + * + * DESCRIPTION: Look up a name relative to a given scope and return the + * corresponding NTE. NOTE: Scope can be null. + * + * MUTEX: Locks namespace + * + ***************************************************************************/ + +ACPI_STATUS +acpi_ns_get_named_object ( + char *pathname, + ACPI_NAME_TABLE *in_scope, + ACPI_NAMED_OBJECT **out_nte) +{ + ACPI_GENERIC_STATE scope_info; + ACPI_STATUS status; + ACPI_NAMED_OBJECT *obj_entry = NULL; + char *internal_path = NULL; + + + scope_info.scope.name_table = in_scope; + + /* Ensure that the namespace has been initialized */ + + if (!acpi_gbl_root_object->child_table) { + return (AE_NO_NAMESPACE); + } + + if (!pathname) { + return (AE_BAD_PARAMETER); + } + + + /* Convert path to internal representation */ + + status = acpi_ns_internalize_name (pathname, &internal_path); + if (ACPI_FAILURE (status)) { + return (status); + } + + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + /* NS_ALL means start from the root */ + + if (NS_ALL == scope_info.scope.name_table) { + scope_info.scope.name_table = acpi_gbl_root_object->child_table; + } + + else { + scope_info.scope.name_table = in_scope; + if (!scope_info.scope.name_table) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + } + + /* Lookup the name in the namespace */ + + status = acpi_ns_lookup (&scope_info, internal_path, + ACPI_TYPE_ANY, IMODE_EXECUTE, + NS_NO_UPSEARCH | NS_DONT_OPEN_SCOPE, + NULL, &obj_entry); + + + /* Return what was wanted - the NTE that matches the name */ + + *out_nte = obj_entry; + + +unlock_and_exit: + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + + /* Cleanup */ + + acpi_cm_free (internal_path); + + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_find_parent_name + * + * PARAMETERS: *Child_entry - nte whose name is to be found + * + * RETURN: The ACPI name + * + * DESCRIPTION: Search for the given nte in its parent scope and return the + * name segment, or "????" if the parent name can't be found + * (which "should not happen"). + * + ***************************************************************************/ + +ACPI_NAME +acpi_ns_find_parent_name ( + ACPI_NAMED_OBJECT *child_entry) +{ + ACPI_NAMED_OBJECT *parent_entry; + + + if (child_entry) { + /* Valid entry. Get the parent Nte */ + + parent_entry = acpi_ns_get_parent_entry (child_entry); + if (parent_entry) { + if (parent_entry->name) { + return (parent_entry->name); + } + } + + } + + + return (ACPI_UNKNOWN_NAME); +} + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_exist_downstream_sibling + * + * PARAMETERS: *This_entry - pointer to first nte to examine + * + * RETURN: TRUE if sibling is found, FALSE otherwise + * + * DESCRIPTION: Searches remainder of scope being processed to determine + * whether there is a downstream sibling to the current + * object. This function is used to determine what type of + * line drawing character to use when displaying namespace + * trees. + * + ***************************************************************************/ + +u8 +acpi_ns_exist_downstream_sibling ( + ACPI_NAMED_OBJECT *this_entry) +{ + + if (!this_entry) { + return FALSE; + } + + if (this_entry->name) { + return TRUE; + } + + +/* TBD: what did this really do? + if (This_entry->Next_entry) { + return TRUE; + } +*/ + return FALSE; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_get_owner_table + * + * PARAMETERS: + * + * RETURN: + * + * DESCRIPTION: + * + ***************************************************************************/ + + +ACPI_NAME_TABLE * +acpi_ns_get_owner_table ( + ACPI_NAMED_OBJECT *this_entry) +{ + + /* + * Given an entry in the Name_table->Entries field of a name table, + * we can create a pointer to the beginning of the table as follows: + * + * 1) Starting with the the pointer to the entry, + * 2) Subtract the entry index * size of each entry to get a + * pointer to Entries[0] + * 3) Subtract the size of NAME_TABLE structure to get a pointer + * to the start. + * + * This saves having to put a pointer in every entry that points + * back to the beginning of the table and/or a pointer back to + * the parent. + */ + + return (ACPI_NAME_TABLE *) ((char *) this_entry - + (this_entry->this_index * + sizeof (ACPI_NAMED_OBJECT)) - + (sizeof (ACPI_NAME_TABLE) - + sizeof (ACPI_NAMED_OBJECT))); + +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_get_parent_entry + * + * PARAMETERS: This_entry - Current table entry + * + * RETURN: Parent entry of the given entry + * + * DESCRIPTION: Obtain the parent entry for a given entry in the namespace. + * + ***************************************************************************/ + + +ACPI_NAMED_OBJECT * +acpi_ns_get_parent_entry ( + ACPI_NAMED_OBJECT *this_entry) +{ + ACPI_NAME_TABLE *name_table; + + + name_table = acpi_ns_get_owner_table (this_entry); + + /* + * Now that we have a pointer to the name table, we can just pluck + * the parent + */ + + return (name_table->parent_entry); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_ns_get_next_valid_entry + * + * PARAMETERS: This_entry - Current table entry + * + * RETURN: Next valid object in the table. NULL if no more valid + * objects + * + * DESCRIPTION: Find the next valid object within a name table. + * + ***************************************************************************/ + + +ACPI_NAMED_OBJECT * +acpi_ns_get_next_valid_entry ( + ACPI_NAMED_OBJECT *this_entry) +{ + ACPI_NAME_TABLE *name_table; + u32 index; + + + index = this_entry->this_index + 1; + name_table = acpi_ns_get_owner_table (this_entry); + + + while (name_table) { + if (index >= NS_TABLE_SIZE) { + /* We are at the end of this table */ + + name_table = name_table->next_table; + index = 0; + continue; + } + + + /* Is this a valid (occupied) slot? */ + + if (name_table->entries[index].name) { + /* Found a valid entry, all done */ + + return (&name_table->entries[index]); + } + + /* Go to the next slot */ + + index++; + } + + /* No more valid entries in this name table */ + + return NULL; +} + + diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c new file mode 100644 index 000000000..6fcb14b76 --- /dev/null +++ b/drivers/acpi/namespace/nswalk.c @@ -0,0 +1,279 @@ + +/****************************************************************************** + * + * Module Name: nswalk - Functions for walking the APCI 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 "interp.h" +#include "namesp.h" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nswalk"); + + +/**************************************************************************** + * + * FUNCTION: Acpi_get_next_object + * + * PARAMETERS: Type - Type of object to be searched for + * Parent - Parent object whose children we are getting + * Last_child - Previous child that was found. + * The NEXT child will be returned + * Ret_handle - Where handle to the next object is placed + * + * RETURN: Status + * + * DESCRIPTION: Return the next peer object within the namespace. If Handle is + * valid, Scope is ignored. Otherwise, the first object within + * Scope is returned. + * + ******************************************************************************/ + +ACPI_NAMED_OBJECT* +acpi_ns_get_next_object ( + OBJECT_TYPE_INTERNAL type, + ACPI_NAMED_OBJECT *parent, + ACPI_NAMED_OBJECT *child) +{ + ACPI_NAMED_OBJECT *this_entry = NULL; + + + if (!child) { + + /* It's really the parent's _scope_ that we want */ + + if (parent->child_table) { + this_entry = parent->child_table->entries; + } + } + + else { + /* Start search at the NEXT object */ + + this_entry = acpi_ns_get_next_valid_entry (child); + } + + + /* If any type is OK, we are done */ + + if (type == ACPI_TYPE_ANY) { + /* Make sure this is valid entry first */ + + if ((!this_entry) || + (!this_entry->name)) + { + return NULL; + } + + return (this_entry); + } + + + /* Must search for the object -- but within this scope only */ + + while (this_entry) { + /* If type matches, we are done */ + + if (this_entry->type == type) { + return (this_entry); + } + + /* Otherwise, move on to the next object */ + + this_entry = acpi_ns_get_next_valid_entry (this_entry); + } + + + /* Not found */ + + return NULL; +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_ns_walk_namespace + * + * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for + * Start_object - Handle in namespace where search begins + * Max_depth - Depth to which search is to reach + * Unlock_before_callback- Whether to unlock the NS before invoking + * the callback routine + * User_function - Called when an object of "Type" is found + * Context - Passed to user function + * + * RETURNS Return value from the User_function if terminated early. + * Otherwise, returns NULL. + * + * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, + * starting (and ending) at the object specified by Start_handle. + * The User_function is called whenever an object that matches + * the type parameter is found. If the user function returns + * a non-zero value, the search is terminated immediately and this + * value is returned to the caller. + * + * The point of this procedure is to provide a generic namespace + * walk routine that can be called from multiple places to + * provide multiple services; the User Function can be tailored + * to each task, whether it is a print function, a compare + * function, etc. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_ns_walk_namespace ( + OBJECT_TYPE_INTERNAL type, + ACPI_HANDLE start_object, + u32 max_depth, + u8 unlock_before_callback, + WALK_CALLBACK user_function, + void *context, + void **return_value) +{ + ACPI_STATUS status; + ACPI_NAMED_OBJECT *child_entry; + ACPI_NAMED_OBJECT *parent_entry; + OBJECT_TYPE_INTERNAL child_type; + u32 level; + + + /* Special case for the namespace root object */ + + if (start_object == ACPI_ROOT_OBJECT) { + start_object = acpi_gbl_root_object; + } + + + /* Null child means "get first object" */ + + parent_entry = start_object; + child_entry = 0; + child_type = ACPI_TYPE_ANY; + level = 1; + + /* + * Traverse the tree of objects until we bubble back up to where we + * started. When Level is zero, the loop is done because we have + * bubbled up to (and passed) the original parent handle (Start_entry) + */ + + while (level > 0) { + /* + * Get the next typed object in this scope. Null returned + * if not found + */ + + status = AE_OK; + child_entry = acpi_ns_get_next_object (ACPI_TYPE_ANY, + parent_entry, + child_entry); + + if (child_entry) { + /* + * Found an object, Get the type if we are not + * searching for ANY + */ + + if (type != ACPI_TYPE_ANY) { + child_type = child_entry->type; + } + + if (child_type == type) { + /* + * Found a matching object, invoke the user + * callback function + */ + + if (unlock_before_callback) { + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + } + + status = user_function (child_entry, level, + context, return_value); + + if (unlock_before_callback) { + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + } + + switch (status) + { + case AE_OK: + case AE_CTRL_DEPTH: + /* Just keep going */ + break; + + case AE_CTRL_TERMINATE: + /* Exit now, with OK status */ + return (AE_OK); + break; + + default: + /* All others are valid exceptions */ + return (status); + break; + } + } + + /* + * Depth first search: + * Attempt to go down another level in the namespace + * if we are allowed to. Don't go any further if we + * have reached the caller specified maximum depth + * or if the user function has specified that the + * maximum depth has been reached. + */ + + if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { + if (acpi_ns_get_next_object (ACPI_TYPE_ANY, + child_entry, 0)) + { + /* + * There is at least one child of this + * object, visit the object + */ + level++; + parent_entry = child_entry; + child_entry = 0; + } + } + } + + else { + /* + * No more children in this object (Acpi_ns_get_next_object + * failed), go back upwards in the namespace tree to + * the object's parent. + */ + level--; + child_entry = parent_entry; + parent_entry = acpi_ns_get_parent_entry (parent_entry); + } + } + + /* Complete walk, not terminated by user function */ + return (AE_OK); +} + + diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c new file mode 100644 index 000000000..2622a9be8 --- /dev/null +++ b/drivers/acpi/namespace/nsxfname.c @@ -0,0 +1,372 @@ +/****************************************************************************** + * + * Module Name: nsxfname - Public interfaces to the ACPI subsystem + * ACPI Namespace oriented interfaces + * + *****************************************************************************/ + +/* + * 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 "interp.h" +#include "namesp.h" +#include "amlcode.h" +#include "parser.h" +#include "dispatch.h" +#include "events.h" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nsxfname"); + + +/****************************************************************************** + * + * FUNCTION: Acpi_load_namespace + * + * PARAMETERS: Display_aml_during_load + * + * RETURN: Status + * + * DESCRIPTION: Load the name space from what ever is pointed to by DSDT. + * (DSDT points to either the BIOS or a buffer.) + * + ******************************************************************************/ + +ACPI_STATUS +acpi_load_namespace ( + void) +{ + ACPI_STATUS status; + + + /* There must be at least a DSDT installed */ + + if (acpi_gbl_DSDT == NULL) { + return (AE_NO_ACPI_TABLES); + } + + + /* Init the hardware */ + + /* + * TBD: [Restructure] Should this should be moved elsewhere, + * like Acpi_enable! ?? + */ + + /* we need to be able to call this interface repeatedly! */ + /* Does H/W require init before loading the namespace? */ + + status = acpi_cm_hardware_initialize (); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* + * Load the namespace. The DSDT is required, + * but the SSDT and PSDT tables are optional. + */ + + status = acpi_ns_load_table_by_type (ACPI_TABLE_DSDT); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Ignore exceptions from these */ + + acpi_ns_load_table_by_type (ACPI_TABLE_SSDT); + acpi_ns_load_table_by_type (ACPI_TABLE_PSDT); + + + /* + * Install the default Op_region handlers, ignore the return + * code right now. + */ + + acpi_ev_install_default_address_space_handlers (); + + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_get_handle + * + * PARAMETERS: Parent - Object to search under (search scope). + * Path_name - Pointer to an asciiz string containing the + * name + * Ret_handle - Where the return handle is placed + * + * RETURN: Status + * + * DESCRIPTION: This routine will search for a caller specified name in the + * name space. The caller can restrict the search region by + * specifying a non NULL parent. The parent value is itself a + * namespace handle. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_handle ( + ACPI_HANDLE parent, + ACPI_STRING pathname, + ACPI_HANDLE *ret_handle) +{ + ACPI_STATUS status; + ACPI_NAMED_OBJECT *this_entry; + ACPI_NAME_TABLE *scope = NULL; + + + if (!ret_handle || !pathname) { + return AE_BAD_PARAMETER; + } + + if (parent) { + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + this_entry = acpi_ns_convert_handle_to_entry (parent); + if (!this_entry) { + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + return AE_BAD_PARAMETER; + } + + scope = this_entry->child_table; + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + } + + /* Special case for root, since we can't search for it */ + /* TBD: [Investigate] Check for both forward and backslash?? */ + + if (STRCMP (pathname, NS_ROOT_PATH) == 0) { + *ret_handle = acpi_ns_convert_entry_to_handle (acpi_gbl_root_object); + return AE_OK; + } + + /* + * Find the Nte and convert to the user format + */ + this_entry = NULL; + status = acpi_ns_get_named_object (pathname, scope, &this_entry); + + *ret_handle = acpi_ns_convert_entry_to_handle (this_entry); + + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_get_pathname + * + * PARAMETERS: Handle - Handle to be converted to a pathname + * Name_type - Full pathname or single segment + * Ret_path_ptr - Buffer for returned path + * + * RETURN: Pointer to a string containing the fully qualified Name. + * + * DESCRIPTION: This routine returns the fully qualified name associated with + * the Handle parameter. This and the Acpi_pathname_to_handle are + * complementary functions. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_name ( + ACPI_HANDLE handle, + u32 name_type, + ACPI_BUFFER *ret_path_ptr) +{ + ACPI_STATUS status; + ACPI_NAMED_OBJECT *obj_entry; + + + /* Buffer pointer must be valid always */ + + if (!ret_path_ptr || (name_type > ACPI_NAME_TYPE_MAX)) { + return AE_BAD_PARAMETER; + } + + /* Allow length to be zero and ignore the pointer */ + + if ((ret_path_ptr->length) && + (!ret_path_ptr->pointer)) + { + return AE_BAD_PARAMETER; + } + + if (name_type == ACPI_FULL_PATHNAME) { + /* Get the full pathname (From the namespace root) */ + + status = acpi_ns_handle_to_pathname (handle, &ret_path_ptr->length, + ret_path_ptr->pointer); + return status; + } + + /* + * Wants the single segment ACPI name. + * Validate handle and convert to an NTE + */ + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + obj_entry = acpi_ns_convert_handle_to_entry (handle); + if (!obj_entry) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Check if name will fit in buffer */ + + if (ret_path_ptr->length < PATH_SEGMENT_LENGTH) { + ret_path_ptr->length = PATH_SEGMENT_LENGTH; + status = AE_BUFFER_OVERFLOW; + goto unlock_and_exit; + } + + /* Just copy the ACPI name from the NTE and zero terminate it */ + + STRNCPY (ret_path_ptr->pointer, (char *) &obj_entry->name, + ACPI_NAME_SIZE); + ((char *) ret_path_ptr->pointer) [ACPI_NAME_SIZE] = 0; + status = AE_OK; + + +unlock_and_exit: + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + return status; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_get_object_info + * + * PARAMETERS: Handle - Object Handle + * Info - Where the info is returned + * + * RETURN: Status + * + * DESCRIPTION: Returns information about an object as gleaned from running + * several standard control methods. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_object_info ( + ACPI_HANDLE device, + ACPI_DEVICE_INFO *info) +{ + DEVICE_ID hid; + DEVICE_ID uid; + ACPI_STATUS status; + u32 device_status = 0; + u32 address = 0; + ACPI_NAMED_OBJECT *device_entry; + + + /* Parameter validation */ + + if (!device || !info) { + return AE_BAD_PARAMETER; + } + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + device_entry = acpi_ns_convert_handle_to_entry (device); + if (!device_entry) { + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + return AE_BAD_PARAMETER; + } + + info->type = device_entry->type; + info->name = device_entry->name; + info->parent = + acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_entry (device_entry)); + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + + /* + * If not a device, we are all done. + */ + if (info->type != ACPI_TYPE_DEVICE) { + return AE_OK; + } + + + /* Get extra info for ACPI devices */ + + info->valid = 0; + + /* Execute the _HID method and save the result */ + + status = acpi_cm_execute_HID (device_entry, &hid); + if (ACPI_SUCCESS (status)) { + if (hid.type == STRING_PTR_DEVICE_ID) { + STRCPY (info->hardware_id, hid.data.string_ptr); + } + else { + STRCPY (info->hardware_id, hid.data.buffer); + } + + info->valid |= ACPI_VALID_HID; + } + + /* Execute the _UID method and save the result */ + + status = acpi_cm_execute_UID (device_entry, &uid); + if (ACPI_SUCCESS (status)) { + if (hid.type == STRING_PTR_DEVICE_ID) { + STRCPY (info->unique_id, uid.data.string_ptr); + } + else { + STRCPY (info->unique_id, uid.data.buffer); + } + + info->valid |= ACPI_VALID_UID; + } + + /* + * Execute the _STA method and save the result + * _STA is not always present + */ + + status = acpi_cm_execute_STA (device_entry, &device_status); + if (ACPI_SUCCESS (status)) { + info->current_status = device_status; + info->valid |= ACPI_VALID_STA; + } + + /* + * Execute the _ADR method and save result if successful + * _ADR is not always present + */ + + status = acpi_cm_evaluate_numeric_object (METHOD_NAME__ADR, + device_entry, &address); + + if (ACPI_SUCCESS (status)) { + info->address = address; + info->valid |= ACPI_VALID_ADR; + } + + return AE_OK; +} + diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c new file mode 100644 index 000000000..09c5e4e3d --- /dev/null +++ b/drivers/acpi/namespace/nsxfobj.c @@ -0,0 +1,554 @@ + +/****************************************************************************** + * + * Module Name: nsxfobj - Public interfaces to the ACPI subsystem + * ACPI Object oriented interfaces + * + *****************************************************************************/ + +/* + * 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 "interp.h" +#include "namesp.h" + + +#define _COMPONENT NAMESPACE + MODULE_NAME ("nsxfobj"); + + +/**************************************************************************** + * + * FUNCTION: Acpi_evaluate_object + * + * PARAMETERS: Handle - Object handle (optional) + * *Pathname - Object pathname (optional) + * **Params - List of parameters to pass to + * method, terminated by NULL. + * Params itself may be NULL + * if no parameters are being + * passed. + * *Return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * + * RETURN: Status + * + * DESCRIPTION: Find and evaluate the given object, passing the given + * parameters if necessary. One of "Handle" or "Pathname" must + * be valid (non-null) + * + ****************************************************************************/ + +ACPI_STATUS +acpi_evaluate_object ( + ACPI_HANDLE handle, + ACPI_STRING pathname, + ACPI_OBJECT_LIST *param_objects, + ACPI_BUFFER *return_buffer) +{ + ACPI_STATUS status; + ACPI_OBJECT_INTERNAL **param_ptr = NULL; + ACPI_OBJECT_INTERNAL *return_obj = NULL; + ACPI_OBJECT_INTERNAL *object_ptr = NULL; + u32 buffer_space_needed; + u32 user_buffer_length; + u32 count; + u32 i; + u32 param_length; + u32 object_length; + + + /* + * If there are parameters to be passed to the object + * (which must be a control method), the external objects + * must be converted to internal objects + */ + + if (param_objects && param_objects->count) { + /* + * Allocate a new parameter block for the internal objects + * Add 1 to count to allow for null terminated internal list + * TBD: [Restructure] merge into single allocation! + */ + + count = param_objects->count; + param_length = (count + 1) * sizeof (void *); + object_length = count * sizeof (ACPI_OBJECT_INTERNAL); + + param_ptr = acpi_cm_callocate (param_length + /* Parameter List part */ + object_length); /* Actual objects */ + if (!param_ptr) { + return (AE_NO_MEMORY); + } + + object_ptr = (ACPI_OBJECT_INTERNAL *) ((u8 *) param_ptr + + param_length); + + /* + * Init the param array of pointers and NULL terminate + * the list + */ + + for (i = 0; i < count; i++) { + param_ptr[i] = &object_ptr[i]; + acpi_cm_init_static_object (&object_ptr[i]); + } + param_ptr[count] = NULL; + + /* + * Convert each external object in the list to an + * internal object + */ + for (i = 0; i < count; i++) { + status = + acpi_cm_build_internal_object (¶m_objects->pointer[i], + param_ptr[i]); + + if (ACPI_FAILURE (status)) { + acpi_cm_delete_internal_object_list (param_ptr); + return (status); + } + } + } + + + /* + * Three major cases: + * 1) Fully qualified pathname + * 2) No handle, not fully qualified pathname (error) + * 3) Valid handle + */ + + if ((pathname) && + (acpi_ns_valid_root_prefix (pathname[0]))) + { + /* + * The path is fully qualified, just evaluate by name + */ + status = acpi_ns_evaluate_by_name (pathname, param_ptr, &return_obj); + } + + else if (!handle) { + /* + * A handle is optional iff a fully qualified pathname + * is specified. Since we've already handled fully + * qualified names above, this is an error + */ + + + + status = AE_BAD_PARAMETER; + } + + else { + /* + * We get here if we have a handle -- and if we have a + * pathname it is relative. The handle will be validated + * in the lower procedures + */ + + if (!pathname) { + /* + * The null pathname case means the handle is for + * the actual object to be evaluated + */ + status = acpi_ns_evaluate_by_handle (handle, + param_ptr, + &return_obj); + } + + else { + /* + * Both a Handle and a relative Pathname + */ + status = acpi_ns_evaluate_relative (handle, pathname, + param_ptr, + &return_obj); + } + } + + + /* + * If we are expecting a return value, and all went well above, + * copy the return value to an external object. + */ + + if (return_buffer) { + user_buffer_length = return_buffer->length; + return_buffer->length = 0; + + if (return_obj) { + if (VALID_DESCRIPTOR_TYPE (return_obj, + ACPI_DESC_TYPE_NAMED)) + { + /* + * If we got an NTE as a return object, + * this means the object we are evaluating + * has nothing interesting to return (such + * as a mutex, etc.) We return an error + * because these types are essentially + * unsupported by this interface. We + * don't check up front because this makes + * it easier to add support for various + * types at a later date if necessary. + */ + status = AE_TYPE; + return_obj = NULL; /* No need to delete an NTE */ + } + + if (ACPI_SUCCESS (status)) { + /* + * Find out how large a buffer is needed + * to contain the returned object + */ + status = acpi_cm_get_object_size (return_obj, + &buffer_space_needed); + if (ACPI_SUCCESS (status)) { + /* + * Check if there is enough room in the + * caller's buffer + */ + + if (user_buffer_length < buffer_space_needed) { + /* + * Caller's buffer is too small, can't + * give him partial results fail the call + * but return the buffer size needed + */ + + return_buffer->length = buffer_space_needed; + status = AE_BUFFER_OVERFLOW; + } + + else { + /* + * We have enough space for the object, build it + */ + status = + acpi_cm_build_external_object (return_obj, + return_buffer); + return_buffer->length = buffer_space_needed; + } + } + } + } + } + + + /* Delete the return and parameter objects */ + + if (return_obj) { + /* + * Delete the internal return object. (Or at least + * decrement the reference count by one) + */ + acpi_cm_remove_reference (return_obj); + } + + /* + * Free the input parameter list (if we created one), + */ + + if (param_ptr) { + /* Free the allocated parameter block */ + + acpi_cm_delete_internal_object_list (param_ptr); + } + + return (status); +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_get_next_object + * + * PARAMETERS: Type - Type of object to be searched for + * Parent - Parent object whose children we are getting + * Last_child - Previous child that was found. + * The NEXT child will be returned + * Ret_handle - Where handle to the next object is placed + * + * RETURN: Status + * + * DESCRIPTION: Return the next peer object within the namespace. If Handle is + * valid, Scope is ignored. Otherwise, the first object within + * Scope is returned. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_next_object ( + ACPI_OBJECT_TYPE type, + ACPI_HANDLE parent, + ACPI_HANDLE child, + ACPI_HANDLE *ret_handle) +{ + ACPI_STATUS status = AE_OK; + ACPI_NAMED_OBJECT *entry; + ACPI_NAMED_OBJECT *parent_entry = NULL; + ACPI_NAMED_OBJECT *child_entry = NULL; + + + /* Parameter validation */ + + if (type > ACPI_TYPE_MAX) { + return AE_BAD_PARAMETER; + } + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + /* If null handle, use the parent */ + + if (!child) { + /* Start search at the beginning of the specified scope */ + + parent_entry = acpi_ns_convert_handle_to_entry (parent); + if (!parent_entry) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + } + + /* Non-null handle, ignore the parent */ + + else { + /* Convert and validate the handle */ + + child_entry = acpi_ns_convert_handle_to_entry (child); + if (!child_entry) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + } + + + /* Internal function does the real work */ + + entry = acpi_ns_get_next_object ((OBJECT_TYPE_INTERNAL) type, + parent_entry, child_entry); + if (!entry) { + status = AE_NOT_FOUND; + goto unlock_and_exit; + } + + if (ret_handle) { + *ret_handle = acpi_ns_convert_entry_to_handle (entry); + } + + +unlock_and_exit: + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + return status; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_get_type + * + * PARAMETERS: Handle - Handle of object whose type is desired + * *Ret_type - Where the type will be placed + * + * RETURN: Status + * + * DESCRIPTION: This routine returns the type associatd with a particular handle + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_type ( + ACPI_HANDLE handle, + ACPI_OBJECT_TYPE *ret_type) +{ + ACPI_NAMED_OBJECT *object; + + + /* Parameter Validation */ + + if (!ret_type) { + return AE_BAD_PARAMETER; + } + + /* + * Special case for the predefined Root Object + * (return type ANY) + */ + + if (handle == ACPI_ROOT_OBJECT) { + *ret_type = ACPI_TYPE_ANY; + return AE_OK; + } + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + /* Convert and validate the handle */ + + object = acpi_ns_convert_handle_to_entry (handle); + if (!object) { + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + return AE_BAD_PARAMETER; + } + + *ret_type = object->type; + + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + return AE_OK; +} + + +/**************************************************************************** + * + * FUNCTION: Acpi_get_parent + * + * PARAMETERS: Handle - Handle of object whose parent is desired + * Ret_handle - Where the parent handle will be placed + * + * RETURN: Status + * + * DESCRIPTION: Returns a handle to the parent of the object represented by + * Handle. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_get_parent ( + ACPI_HANDLE handle, + ACPI_HANDLE *ret_handle) +{ + ACPI_NAMED_OBJECT *object; + ACPI_STATUS status = AE_OK; + + + /* No trace macro, too verbose */ + + + if (!ret_handle) { + return AE_BAD_PARAMETER; + } + + /* Special case for the predefined Root Object (no parent) */ + + if (handle == ACPI_ROOT_OBJECT) { + return AE_NULL_ENTRY; + } + + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + + /* Convert and validate the handle */ + + object = acpi_ns_convert_handle_to_entry (handle); + if (!object) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + + /* Get the parent entry */ + + *ret_handle = + acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_entry (object)); + + /* Return exeption if parent is null */ + + if (!acpi_ns_get_parent_entry (object)) { + status = AE_NULL_ENTRY; + } + + +unlock_and_exit: + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + return AE_OK; +} + + +/****************************************************************************** + * + * FUNCTION: Acpi_walk_namespace + * + * PARAMETERS: Type - ACPI_OBJECT_TYPE to search for + * Start_object - Handle in namespace where search begins + * Max_depth - Depth to which search is to reach + * User_function - Called when an object of "Type" is found + * Context - Passed to user function + * + * RETURNS Return value from the User_function if terminated early. + * Otherwise, returns NULL. + * + * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, + * starting (and ending) at the object specified by Start_handle. + * The User_function is called whenever an object that matches + * the type parameter is found. If the user function returns + * a non-zero value, the search is terminated immediately and this + * value is returned to the caller. + * + * The point of this procedure is to provide a generic namespace + * walk routine that can be called from multiple places to + * provide multiple services; the User Function can be tailored + * to each task, whether it is a print function, a compare + * function, etc. + * + ******************************************************************************/ + +ACPI_STATUS +acpi_walk_namespace ( + ACPI_OBJECT_TYPE type, + ACPI_HANDLE start_object, + u32 max_depth, + WALK_CALLBACK user_function, + void *context, + void **return_value) +{ + ACPI_STATUS status; + + + /* Parameter validation */ + + if ((type > ACPI_TYPE_MAX) || + (!max_depth) || + (!user_function)) + { + return (AE_BAD_PARAMETER); + } + + /* + * Lock the namespace around the walk. + * The namespace will be unlocked/locked around each call + * to the user function - since this function + * must be allowed to make Acpi calls itself. + */ + + acpi_cm_acquire_mutex (ACPI_MTX_NAMESPACE); + status = acpi_ns_walk_namespace ((OBJECT_TYPE_INTERNAL) type, + start_object, max_depth, + NS_WALK_UNLOCK, + user_function, context, + return_value); + + acpi_cm_release_mutex (ACPI_MTX_NAMESPACE); + + return (status); +} + + |