diff options
Diffstat (limited to 'drivers/acpi/namespace')
-rw-r--r-- | drivers/acpi/namespace/Makefile | 12 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsaccess.c | 637 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsalloc.c | 685 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsdump.c | 673 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsdumpdv.c | 146 | ||||
-rw-r--r-- | drivers/acpi/namespace/nseval.c | 487 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsinit.c | 441 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsload.c | 460 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsnames.c | 265 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsobject.c | 461 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsparse.c | 171 | ||||
-rw-r--r-- | drivers/acpi/namespace/nssearch.c | 381 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsutils.c | 1069 | ||||
-rw-r--r-- | drivers/acpi/namespace/nswalk.c | 289 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsxfeval.c | 764 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsxfname.c | 369 | ||||
-rw-r--r-- | drivers/acpi/namespace/nsxfobj.c | 262 |
17 files changed, 7572 insertions, 0 deletions
diff --git a/drivers/acpi/namespace/Makefile b/drivers/acpi/namespace/Makefile new file mode 100644 index 000000000000..3f63d3640696 --- /dev/null +++ b/drivers/acpi/namespace/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for all Linux ACPI interpreter subdirectories +# + +obj-y := nsaccess.o nsload.o nssearch.o nsxfeval.o \ + nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \ + nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \ + nsparse.o + +obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o + +EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c new file mode 100644 index 000000000000..1c0c12336c57 --- /dev/null +++ b/drivers/acpi/namespace/nsaccess.c @@ -0,0 +1,637 @@ +/******************************************************************************* + * + * Module Name: nsaccess - Top-level functions for accessing ACPI namespace + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/amlcode.h> +#include <acpi/acnamesp.h> +#include <acpi/acdispat.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsaccess") + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_root_initialize + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Allocate and initialize the default root named objects + * + * MUTEX: Locks namespace for entire execution + * + ******************************************************************************/ + +acpi_status +acpi_ns_root_initialize (void) +{ + acpi_status status; + const struct acpi_predefined_names *init_val = NULL; + struct acpi_namespace_node *new_node; + union acpi_operand_object *obj_desc; + acpi_string val = NULL; + + + ACPI_FUNCTION_TRACE ("ns_root_initialize"); + + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * The global root ptr is initially NULL, so a non-NULL value indicates + * that acpi_ns_root_initialize() has already been called; just return. + */ + if (acpi_gbl_root_node) { + status = AE_OK; + goto unlock_and_exit; + } + + /* + * Tell the rest of the subsystem that the root is initialized + * (This is OK because the namespace is locked) + */ + acpi_gbl_root_node = &acpi_gbl_root_node_struct; + + /* Enter the pre-defined names in the name table */ + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Entering predefined entries into namespace\n")); + + for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { + /* _OSI is optional for now, will be permanent later */ + + if (!ACPI_STRCMP (init_val->name, "_OSI") && !acpi_gbl_create_osi_method) { + continue; + } + + status = acpi_ns_lookup (NULL, init_val->name, init_val->type, + ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, + NULL, &new_node); + + if (ACPI_FAILURE (status) || (!new_node)) /* Must be on same line for code converter */ { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not create predefined name %s, %s\n", + init_val->name, acpi_format_exception (status))); + } + + /* + * Name entered successfully. + * If entry in pre_defined_names[] specifies an + * initial value, create the initial value. + */ + if (init_val->val) { + status = acpi_os_predefined_override (init_val, &val); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not override predefined %s\n", + init_val->name)); + } + + if (!val) { + val = init_val->val; + } + + /* + * Entry requests an initial value, allocate a + * descriptor for it. + */ + obj_desc = acpi_ut_create_internal_object (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_METHOD: + obj_desc->method.param_count = (u8) ACPI_TO_INTEGER (val); + obj_desc->common.flags |= AOPOBJ_DATA_VALID; + +#if defined (_ACPI_ASL_COMPILER) || defined (_ACPI_DUMP_App) + + /* + * i_aSL Compiler cheats by putting parameter count + * in the owner_iD + */ + new_node->owner_id = obj_desc->method.param_count; +#else + /* Mark this as a very SPECIAL method */ + + obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY; + obj_desc->method.implementation = acpi_ut_osi_implementation; +#endif + break; + + case ACPI_TYPE_INTEGER: + + obj_desc->integer.value = ACPI_TO_INTEGER (val); + break; + + + case ACPI_TYPE_STRING: + + /* + * Build an object around the static string + */ + obj_desc->string.length = (u32) ACPI_STRLEN (val); + obj_desc->string.pointer = val; + obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; + break; + + + case ACPI_TYPE_MUTEX: + + obj_desc->mutex.node = new_node; + obj_desc->mutex.sync_level = (u8) (ACPI_TO_INTEGER (val) - 1); + + if (ACPI_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)) { + acpi_ut_remove_reference (obj_desc); + 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)) { + acpi_ut_remove_reference (obj_desc); + goto unlock_and_exit; + } + } + break; + + + default: + + ACPI_REPORT_ERROR (("Unsupported initial type value %X\n", + init_val->type)); + acpi_ut_remove_reference (obj_desc); + obj_desc = NULL; + continue; + } + + /* Store pointer to value descriptor in the Node */ + + status = acpi_ns_attach_object (new_node, obj_desc, + ACPI_GET_OBJECT_TYPE (obj_desc)); + + /* Remove local reference to the object */ + + acpi_ut_remove_reference (obj_desc); + } + } + + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + + /* Save a handle to "_GPE", it is always present */ + + if (ACPI_SUCCESS (status)) { + status = acpi_ns_get_node_by_path ("\\_GPE", NULL, ACPI_NS_NO_UPSEARCH, + &acpi_gbl_fadt_gpe_device); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_lookup + * + * PARAMETERS: prefix_node - 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 + * Flags - Flags describing the search restrictions + * walk_state - Current state of the walk + * return_node - Where the Node is placed (if found + * or created successfully) + * + * 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 ( + union acpi_generic_state *scope_info, + char *pathname, + acpi_object_type type, + acpi_interpreter_mode interpreter_mode, + u32 flags, + struct acpi_walk_state *walk_state, + struct acpi_namespace_node **return_node) +{ + acpi_status status; + char *path = pathname; + struct acpi_namespace_node *prefix_node; + struct acpi_namespace_node *current_node = NULL; + struct acpi_namespace_node *this_node = NULL; + u32 num_segments; + u32 num_carats; + acpi_name simple_name; + acpi_object_type type_to_check_for; + acpi_object_type this_search_type; + u32 search_parent_flag = ACPI_NS_SEARCH_PARENT; + u32 local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND | + ACPI_NS_SEARCH_PARENT); + + + ACPI_FUNCTION_TRACE ("ns_lookup"); + + + if (!return_node) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + acpi_gbl_ns_lookup_count++; + *return_node = ACPI_ENTRY_NOT_FOUND; + + if (!acpi_gbl_root_node) { + return_ACPI_STATUS (AE_NO_NAMESPACE); + } + + /* + * Get the prefix scope. + * A null scope means use the root scope + */ + if ((!scope_info) || + (!scope_info->scope.node)) { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Null scope prefix, using root node (%p)\n", + acpi_gbl_root_node)); + + prefix_node = acpi_gbl_root_node; + } + else { + prefix_node = scope_info->scope.node; + if (ACPI_GET_DESCRIPTOR_TYPE (prefix_node) != ACPI_DESC_TYPE_NAMED) { + ACPI_REPORT_ERROR (("ns_lookup: %p is not a namespace node [%s]\n", + prefix_node, acpi_ut_get_descriptor_name (prefix_node))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + + /* + * This node might not be a actual "scope" node (such as a + * Device/Method, etc.) It could be a Package or other object node. + * Backup up the tree to find the containing scope node. + */ + while (!acpi_ns_opens_scope (prefix_node->type) && + prefix_node->type != ACPI_TYPE_ANY) { + prefix_node = acpi_ns_get_parent_node (prefix_node); + } + } + + /* Save type TBD: may be no longer necessary */ + + type_to_check_for = type; + + /* + * Begin examination of the actual pathname + */ + if (!pathname) { + /* A Null name_path is allowed and refers to the root */ + + num_segments = 0; + this_node = acpi_gbl_root_node; + path = ""; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Null Pathname (Zero segments), Flags=%X\n", flags)); + } + else { + /* + * Name pointer is valid (and must be in internal name format) + * + * Check for scope prefixes: + * + * As represented in the AML stream, a namepath consists of an + * optional scope prefix followed by a name segment part. + * + * If present, the scope prefix is either a Root Prefix (in + * which case the name is fully qualified), or one or more + * Parent Prefixes (in which case the name's scope is relative + * to the current scope). + */ + if (*path == (u8) AML_ROOT_PREFIX) { + /* Pathname is fully qualified, start from the root */ + + this_node = acpi_gbl_root_node; + search_parent_flag = ACPI_NS_NO_UPSEARCH; + + /* Point to name segment part */ + + path++; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Path is absolute from root [%p]\n", this_node)); + } + else { + /* Pathname is relative to current scope, start there */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Searching relative to prefix scope [%4.4s] (%p)\n", + acpi_ut_get_node_name (prefix_node), prefix_node)); + + /* + * Handle multiple Parent Prefixes (carat) by just getting + * the parent node for each prefix instance. + */ + this_node = prefix_node; + num_carats = 0; + while (*path == (u8) AML_PARENT_PREFIX) { + /* Name is fully qualified, no search rules apply */ + + search_parent_flag = ACPI_NS_NO_UPSEARCH; + /* + * Point past this prefix to the name segment + * part or the next Parent Prefix + */ + path++; + + /* Backup to the parent node */ + + num_carats++; + this_node = acpi_ns_get_parent_node (this_node); + if (!this_node) { + /* Current scope has no parent scope */ + + ACPI_REPORT_ERROR ( + ("ACPI path has too many parent prefixes (^) - reached beyond root node\n")); + return_ACPI_STATUS (AE_NOT_FOUND); + } + } + + if (search_parent_flag == ACPI_NS_NO_UPSEARCH) { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Search scope is [%4.4s], path has %d carat(s)\n", + acpi_ut_get_node_name (this_node), num_carats)); + } + } + + /* + * Determine the number of ACPI name segments in this pathname. + * + * The segment part consists of either: + * - A Null name segment (0) + * - A dual_name_prefix followed by two 4-byte name segments + * - A multi_name_prefix followed by a byte indicating the + * number of segments and the segments themselves. + * - A single 4-byte name segment + * + * Examine the name prefix opcode, if any, to determine the number of + * segments. + */ + switch (*path) { + case 0: + /* + * Null name after a root or parent prefixes. We already + * have the correct target node and there are no name segments. + */ + num_segments = 0; + type = this_node->type; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Prefix-only Pathname (Zero name segments), Flags=%X\n", + flags)); + break; + + case AML_DUAL_NAME_PREFIX: + + /* More than one name_seg, search rules do not apply */ + + search_parent_flag = ACPI_NS_NO_UPSEARCH; + + /* Two segments, point to first name segment */ + + num_segments = 2; + path++; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Dual Pathname (2 segments, Flags=%X)\n", flags)); + break; + + case AML_MULTI_NAME_PREFIX_OP: + + /* More than one name_seg, search rules do not apply */ + + search_parent_flag = ACPI_NS_NO_UPSEARCH; + + /* Extract segment count, point to first name segment */ + + path++; + num_segments = (u32) (u8) *path; + path++; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Multi Pathname (%d Segments, Flags=%X) \n", + num_segments, flags)); + break; + + default: + /* + * Not a Null name, no Dual or Multi prefix, hence there is + * only one name segment and Pathname is already pointing to it. + */ + num_segments = 1; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Simple Pathname (1 segment, Flags=%X)\n", flags)); + break; + } + + ACPI_DEBUG_EXEC (acpi_ns_print_pathname (num_segments, path)); + } + + + /* + * Search namespace for each segment of the name. Loop through and + * verify (or add to the namespace) each name segment. + * + * The object type is significant only at the last name + * segment. (We don't care about the types along the path, only + * the type of the final target object.) + */ + this_search_type = ACPI_TYPE_ANY; + current_node = this_node; + while (num_segments && current_node) { + num_segments--; + if (!num_segments) { + /* + * This is the last segment, enable typechecking + */ + this_search_type = type; + + /* + * Only allow automatic parent search (search rules) if the caller + * requested it AND we have a single, non-fully-qualified name_seg + */ + if ((search_parent_flag != ACPI_NS_NO_UPSEARCH) && + (flags & ACPI_NS_SEARCH_PARENT)) { + local_flags |= ACPI_NS_SEARCH_PARENT; + } + + /* Set error flag according to caller */ + + if (flags & ACPI_NS_ERROR_IF_FOUND) { + local_flags |= ACPI_NS_ERROR_IF_FOUND; + } + } + + /* Extract one ACPI name from the front of the pathname */ + + ACPI_MOVE_32_TO_32 (&simple_name, path); + + /* Try to find the single (4 character) ACPI name */ + + status = acpi_ns_search_and_enter (simple_name, walk_state, current_node, + interpreter_mode, this_search_type, local_flags, &this_node); + if (ACPI_FAILURE (status)) { + if (status == AE_NOT_FOUND) { + /* Name not found in ACPI namespace */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Name [%4.4s] not found in scope [%4.4s] %p\n", + (char *) &simple_name, (char *) ¤t_node->name, + current_node)); + } + + *return_node = this_node; + return_ACPI_STATUS (status); + } + + /* + * Sanity typecheck of the target object: + * + * If 1) This is the last segment (num_segments == 0) + * 2) And we are looking for a specific type + * (Not checking for TYPE_ANY) + * 3) Which is not an alias + * 4) Which is not a local type (TYPE_SCOPE) + * 5) And the type of target object is known (not TYPE_ANY) + * 6) And target object does not match what we are looking for + * + * 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 != ACPI_TYPE_LOCAL_ALIAS) && + (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) && + (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) && + (this_node->type != ACPI_TYPE_ANY) && + (this_node->type != type_to_check_for)) { + /* Complain about a type mismatch */ + + ACPI_REPORT_WARNING ( + ("ns_lookup: Type mismatch on %4.4s (%s), searching for (%s)\n", + (char *) &simple_name, acpi_ut_get_type_name (this_node->type), + acpi_ut_get_type_name (type_to_check_for))); + } + + /* + * If this is the last name segment and we are not looking for a + * specific type, but the type of found object is known, use that type + * to see if it opens a scope. + */ + if ((num_segments == 0) && (type == ACPI_TYPE_ANY)) { + type = this_node->type; + } + + /* Point to next name segment and make this node current */ + + path += ACPI_NAME_SIZE; + current_node = this_node; + } + + /* + * Always check if we need to open a new scope + */ + if (!(flags & ACPI_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)) { + status = acpi_ds_scope_stack_push (this_node, type, walk_state); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + } + + *return_node = this_node; + return_ACPI_STATUS (AE_OK); +} + diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c new file mode 100644 index 000000000000..bfd922c5c7d1 --- /dev/null +++ b/drivers/acpi/namespace/nsalloc.c @@ -0,0 +1,685 @@ +/******************************************************************************* + * + * Module Name: nsalloc - Namespace allocation and deletion utilities + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsalloc") + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_create_node + * + * PARAMETERS: acpi_name - Name of the new node + * + * RETURN: None + * + * DESCRIPTION: Create a namespace node + * + ******************************************************************************/ + +struct acpi_namespace_node * +acpi_ns_create_node ( + u32 name) +{ + struct acpi_namespace_node *node; + + + ACPI_FUNCTION_TRACE ("ns_create_node"); + + + node = ACPI_MEM_CALLOCATE (sizeof (struct acpi_namespace_node)); + if (!node) { + return_PTR (NULL); + } + + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_allocated++); + + node->name.integer = name; + node->reference_count = 1; + ACPI_SET_DESCRIPTOR_TYPE (node, ACPI_DESC_TYPE_NAMED); + + return_PTR (node); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_delete_node + * + * PARAMETERS: Node - Node to be deleted + * + * RETURN: None + * + * DESCRIPTION: Delete a namespace node + * + ******************************************************************************/ + +void +acpi_ns_delete_node ( + struct acpi_namespace_node *node) +{ + struct acpi_namespace_node *parent_node; + struct acpi_namespace_node *prev_node; + struct acpi_namespace_node *next_node; + + + ACPI_FUNCTION_TRACE_PTR ("ns_delete_node", node); + + + parent_node = acpi_ns_get_parent_node (node); + + prev_node = NULL; + next_node = parent_node->child; + + /* Find the node that is the previous peer in the parent's child list */ + + while (next_node != node) { + prev_node = next_node; + next_node = prev_node->peer; + } + + if (prev_node) { + /* Node is not first child, unlink it */ + + prev_node->peer = next_node->peer; + if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { + prev_node->flags |= ANOBJ_END_OF_PEER_LIST; + } + } + else { + /* Node is first child (has no previous peer) */ + + if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { + /* No peers at all */ + + parent_node->child = NULL; + } + else { /* Link peer list to parent */ + + parent_node->child = next_node->peer; + } + } + + + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++); + + /* + * Detach an object if there is one then delete the node + */ + acpi_ns_detach_object (node); + ACPI_MEM_FREE (node); + return_VOID; +} + + +#ifdef ACPI_ALPHABETIC_NAMESPACE +/******************************************************************************* + * + * FUNCTION: acpi_ns_compare_names + * + * PARAMETERS: Name1 - First name to compare + * Name2 - Second name to compare + * + * RETURN: value from strncmp + * + * DESCRIPTION: Compare two ACPI names. Names that are prefixed with an + * underscore are forced to be alphabetically first. + * + ******************************************************************************/ + +int +acpi_ns_compare_names ( + char *name1, + char *name2) +{ + char reversed_name1[ACPI_NAME_SIZE]; + char reversed_name2[ACPI_NAME_SIZE]; + u32 i; + u32 j; + + + /* + * Replace all instances of "underscore" with a value that is smaller so + * that all names that are prefixed with underscore(s) are alphabetically + * first. + * + * Reverse the name bytewise so we can just do a 32-bit compare instead + * of a strncmp. + */ + for (i = 0, j= (ACPI_NAME_SIZE - 1); i < ACPI_NAME_SIZE; i++, j--) { + reversed_name1[j] = name1[i]; + if (name1[i] == '_') { + reversed_name1[j] = '*'; + } + + reversed_name2[j] = name2[i]; + if (name2[i] == '_') { + reversed_name2[j] = '*'; + } + } + + return (*(int *) reversed_name1 - *(int *) reversed_name2); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_install_node + * + * PARAMETERS: walk_state - Current state of the walk + * parent_node - The parent of the new Node + * Node - The new Node to install + * Type - ACPI object type of the new Node + * + * RETURN: None + * + * DESCRIPTION: Initialize a new namespace node and install it amongst + * its peers. + * + * Note: Current namespace lookup is linear search. However, the + * nodes are linked in alphabetical order to 1) put all reserved + * names (start with underscore) first, and to 2) make a readable + * namespace dump. + * + ******************************************************************************/ + +void +acpi_ns_install_node ( + struct acpi_walk_state *walk_state, + struct acpi_namespace_node *parent_node, /* Parent */ + struct acpi_namespace_node *node, /* New Child*/ + acpi_object_type type) +{ + u16 owner_id = 0; + struct acpi_namespace_node *child_node; +#ifdef ACPI_ALPHABETIC_NAMESPACE + + struct acpi_namespace_node *previous_child_node; +#endif + + + ACPI_FUNCTION_TRACE ("ns_install_node"); + + + /* + * 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; + } + + /* Link the new entry into the parent and existing children */ + + child_node = parent_node->child; + if (!child_node) { + parent_node->child = node; + node->flags |= ANOBJ_END_OF_PEER_LIST; + node->peer = parent_node; + } + else { +#ifdef ACPI_ALPHABETIC_NAMESPACE + /* + * Walk the list whilst searching for the correct + * alphabetic placement. + */ + previous_child_node = NULL; + while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), acpi_ut_get_node_name (node)) < 0) { + if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { + /* Last peer; Clear end-of-list flag */ + + child_node->flags &= ~ANOBJ_END_OF_PEER_LIST; + + /* This node is the new peer to the child node */ + + child_node->peer = node; + + /* This node is the new end-of-list */ + + node->flags |= ANOBJ_END_OF_PEER_LIST; + node->peer = parent_node; + break; + } + + /* Get next peer */ + + previous_child_node = child_node; + child_node = child_node->peer; + } + + /* Did the node get inserted at the end-of-list? */ + + if (!(node->flags & ANOBJ_END_OF_PEER_LIST)) { + /* + * Loop above terminated without reaching the end-of-list. + * Insert the new node at the current location + */ + if (previous_child_node) { + /* Insert node alphabetically */ + + node->peer = child_node; + previous_child_node->peer = node; + } + else { + /* Insert node alphabetically at start of list */ + + node->peer = child_node; + parent_node->child = node; + } + } +#else + while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) { + child_node = child_node->peer; + } + + child_node->peer = node; + + /* Clear end-of-list flag */ + + child_node->flags &= ~ANOBJ_END_OF_PEER_LIST; + node->flags |= ANOBJ_END_OF_PEER_LIST; + node->peer = parent_node; +#endif + } + + /* Init the new entry */ + + node->owner_id = owner_id; + node->type = (u8) type; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", + acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type), node, owner_id, + acpi_ut_get_node_name (parent_node), acpi_ut_get_type_name (parent_node->type), + parent_node)); + + /* + * Increment the reference count(s) of all parents up to + * the root! + */ + while ((node = acpi_ns_get_parent_node (node)) != NULL) { + node->reference_count++; + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_delete_children + * + * PARAMETERS: parent_node - Delete this objects children + * + * RETURN: None. + * + * DESCRIPTION: Delete all children of the parent object. In other words, + * deletes a "scope". + * + ******************************************************************************/ + +void +acpi_ns_delete_children ( + struct acpi_namespace_node *parent_node) +{ + struct acpi_namespace_node *child_node; + struct acpi_namespace_node *next_node; + struct acpi_namespace_node *node; + u8 flags; + + + ACPI_FUNCTION_TRACE_PTR ("ns_delete_children", parent_node); + + + if (!parent_node) { + return_VOID; + } + + /* If no children, all done! */ + + child_node = parent_node->child; + if (!child_node) { + return_VOID; + } + + /* + * Deallocate all children at this level + */ + do { + /* Get the things we need */ + + next_node = child_node->peer; + flags = child_node->flags; + + /* Grandchildren should have all been deleted already */ + + if (child_node->child) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Found a grandchild! P=%p C=%p\n", + parent_node, child_node)); + } + + /* Now we can free this child object */ + + ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++); + + ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p, Remaining %X\n", + child_node, acpi_gbl_current_node_count)); + + /* + * Detach an object if there is one, then free the child node + */ + acpi_ns_detach_object (child_node); + + /* + * Decrement the reference count(s) of all parents up to + * the root! (counts were incremented when the node was created) + */ + node = child_node; + while ((node = acpi_ns_get_parent_node (node)) != NULL) { + node->reference_count--; + } + + /* There should be only one reference remaining on this node */ + + if (child_node->reference_count != 1) { + ACPI_REPORT_WARNING (("Existing references (%d) on node being deleted (%p)\n", + child_node->reference_count, child_node)); + } + + /* Now we can delete the node */ + + ACPI_MEM_FREE (child_node); + + /* And move on to the next child in the list */ + + child_node = next_node; + + } while (!(flags & ANOBJ_END_OF_PEER_LIST)); + + + /* Clear the parent's child pointer */ + + parent_node->child = NULL; + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_delete_namespace_subtree + * + * PARAMETERS: parent_node - Root of the subtree to be deleted + * + * RETURN: None. + * + * DESCRIPTION: Delete a subtree of the namespace. This includes all objects + * stored within the subtree. + * + ******************************************************************************/ + +void +acpi_ns_delete_namespace_subtree ( + struct acpi_namespace_node *parent_node) +{ + struct acpi_namespace_node *child_node = NULL; + u32 level = 1; + + + ACPI_FUNCTION_TRACE ("ns_delete_namespace_subtree"); + + + if (!parent_node) { + return_VOID; + } + + /* + * Traverse the tree of objects until we bubble back up + * to where we started. + */ + while (level > 0) { + /* Get the next node in this scope (NULL if none) */ + + child_node = acpi_ns_get_next_node (ACPI_TYPE_ANY, parent_node, + child_node); + if (child_node) { + /* Found a child node - detach any attached object */ + + acpi_ns_detach_object (child_node); + + /* Check if this node has any children */ + + if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) { + /* + * There is at least one child of this node, + * visit the node + */ + level++; + parent_node = child_node; + child_node = NULL; + } + } + else { + /* + * No more children of this parent node. + * Move up to the grandparent. + */ + level--; + + /* + * Now delete all of the children of this parent + * all at the same time. + */ + acpi_ns_delete_children (parent_node); + + /* New "last child" is this parent node */ + + child_node = parent_node; + + /* Move up the tree to the grandparent */ + + parent_node = acpi_ns_get_parent_node (parent_node); + } + } + + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_remove_reference + * + * PARAMETERS: Node - Named node whose reference count is to be + * decremented + * + * RETURN: None. + * + * DESCRIPTION: Remove a Node reference. Decrements the reference count + * of all parent Nodes up to the root. Any node along + * the way that reaches zero references is freed. + * + ******************************************************************************/ + +void +acpi_ns_remove_reference ( + struct acpi_namespace_node *node) +{ + struct acpi_namespace_node *parent_node; + struct acpi_namespace_node *this_node; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * Decrement the reference count(s) of this node and all + * nodes up to the root, Delete anything with zero remaining references. + */ + this_node = node; + while (this_node) { + /* Prepare to move up to parent */ + + parent_node = acpi_ns_get_parent_node (this_node); + + /* Decrement the reference count on this node */ + + this_node->reference_count--; + + /* Delete the node if no more references */ + + if (!this_node->reference_count) { + /* Delete all children and delete the node */ + + acpi_ns_delete_children (this_node); + acpi_ns_delete_node (this_node); + } + + this_node = parent_node; + } +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_delete_namespace_by_owner + * + * PARAMETERS: owner_id - All nodes with this owner will be deleted + * + * RETURN: Status + * + * DESCRIPTION: Delete entries within the namespace that are owned by a + * specific ID. Used to delete entire ACPI tables. All + * reference counts are updated. + * + ******************************************************************************/ + +void +acpi_ns_delete_namespace_by_owner ( + u16 owner_id) +{ + struct acpi_namespace_node *child_node; + struct acpi_namespace_node *deletion_node; + u32 level; + struct acpi_namespace_node *parent_node; + + + ACPI_FUNCTION_TRACE_U32 ("ns_delete_namespace_by_owner", owner_id); + + + parent_node = acpi_gbl_root_node; + child_node = NULL; + deletion_node = NULL; + level = 1; + + /* + * Traverse the tree of nodes until we bubble back up + * to where we started. + */ + while (level > 0) { + /* + * Get the next child of this parent node. When child_node is NULL, + * the first child of the parent is returned + */ + child_node = acpi_ns_get_next_node (ACPI_TYPE_ANY, parent_node, child_node); + + if (deletion_node) { + acpi_ns_remove_reference (deletion_node); + deletion_node = NULL; + } + + if (child_node) { + if (child_node->owner_id == owner_id) { + /* Found a matching child node - detach any attached object */ + + acpi_ns_detach_object (child_node); + } + + /* Check if this node has any children */ + + if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) { + /* + * There is at least one child of this node, + * visit the node + */ + level++; + parent_node = child_node; + child_node = NULL; + } + else if (child_node->owner_id == owner_id) { + deletion_node = child_node; + } + } + else { + /* + * No more children of this parent node. + * Move up to the grandparent. + */ + level--; + if (level != 0) { + if (parent_node->owner_id == owner_id) { + deletion_node = parent_node; + } + } + + /* New "last child" is this parent node */ + + child_node = parent_node; + + /* Move up the tree to the grandparent */ + + parent_node = acpi_ns_get_parent_node (parent_node); + } + } + + return_VOID; +} + + diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c new file mode 100644 index 000000000000..1f6af3eb6c91 --- /dev/null +++ b/drivers/acpi/namespace/nsdump.c @@ -0,0 +1,673 @@ +/****************************************************************************** + * + * Module Name: nsdump - table dumping routines for debug + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/acparser.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsdump") + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +/******************************************************************************* + * + * FUNCTION: acpi_ns_print_pathname + * + * PARAMETERS: num_segment - Number of ACPI name segments + * Pathname - The compressed (internal) path + * + * DESCRIPTION: Print an object's full namespace pathname + * + ******************************************************************************/ + +void +acpi_ns_print_pathname ( + u32 num_segments, + char *pathname) +{ + ACPI_FUNCTION_NAME ("ns_print_pathname"); + + + if (!(acpi_dbg_level & ACPI_LV_NAMES) || !(acpi_dbg_layer & ACPI_NAMESPACE)) { + return; + } + + /* Print the entire name */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[")); + + while (num_segments) { + acpi_os_printf ("%4.4s", pathname); + pathname += ACPI_NAME_SIZE; + + num_segments--; + if (num_segments) { + acpi_os_printf ("."); + } + } + + acpi_os_printf ("]\n"); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_dump_pathname + * + * PARAMETERS: Handle - Object + * Msg - Prefix message + * Level - Desired debug level + * Component - Caller's component ID + * + * DESCRIPTION: Print an object's full namespace pathname + * Manages allocation/freeing of a pathname buffer + * + ******************************************************************************/ + +void +acpi_ns_dump_pathname ( + acpi_handle handle, + char *msg, + u32 level, + u32 component) +{ + + ACPI_FUNCTION_TRACE ("ns_dump_pathname"); + + + /* Do this only if the requested debug level and component are enabled */ + + if (!(acpi_dbg_level & level) || !(acpi_dbg_layer & component)) { + return_VOID; + } + + /* Convert handle to a full pathname and print it (with supplied message) */ + + acpi_ns_print_node_pathname (handle, msg); + acpi_os_printf ("\n"); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_dump_one_object + * + * PARAMETERS: Handle - Node to be dumped + * Level - Nesting level of the handle + * Context - Passed into walk_namespace + * + * DESCRIPTION: Dump a single Node + * This procedure is a user_function called by acpi_ns_walk_namespace. + * + ******************************************************************************/ + +acpi_status +acpi_ns_dump_one_object ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value) +{ + struct acpi_walk_info *info = (struct acpi_walk_info *) context; + struct acpi_namespace_node *this_node; + union acpi_operand_object *obj_desc = NULL; + acpi_object_type obj_type; + acpi_object_type type; + u32 bytes_to_dump; + u32 dbg_level; + u32 i; + + + ACPI_FUNCTION_NAME ("ns_dump_one_object"); + + + /* Is output enabled? */ + + if (!(acpi_dbg_level & info->debug_level)) { + return (AE_OK); + } + + if (!obj_handle) { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Null object handle\n")); + return (AE_OK); + } + + this_node = acpi_ns_map_handle_to_node (obj_handle); + type = this_node->type; + + /* Check if the owner matches */ + + if ((info->owner_id != ACPI_UINT32_MAX) && + (info->owner_id != this_node->owner_id)) { + return (AE_OK); + } + + /* Indent the object according to the level */ + + acpi_os_printf ("%2d%*s", (u32) level - 1, (int) level * 2, " "); + + /* Check the node type and name */ + + if (type > ACPI_TYPE_LOCAL_MAX) { + ACPI_REPORT_WARNING (("Invalid ACPI Type %08X\n", type)); + } + + if (!acpi_ut_valid_acpi_name (this_node->name.integer)) { + ACPI_REPORT_WARNING (("Invalid ACPI Name %08X\n", + this_node->name.integer)); + } + + /* + * Now we can print out the pertinent information + */ + acpi_os_printf ("%4.4s %-12s %p ", + acpi_ut_get_node_name (this_node), acpi_ut_get_type_name (type), this_node); + + dbg_level = acpi_dbg_level; + acpi_dbg_level = 0; + obj_desc = acpi_ns_get_attached_object (this_node); + acpi_dbg_level = dbg_level; + + switch (info->display_type) { + case ACPI_DISPLAY_SUMMARY: + + if (!obj_desc) { + /* No attached object, we are done */ + + acpi_os_printf ("\n"); + return (AE_OK); + } + + switch (type) { + case ACPI_TYPE_PROCESSOR: + + acpi_os_printf ("ID %X Len %.4X Addr %p\n", + obj_desc->processor.proc_id, obj_desc->processor.length, + (char *) obj_desc->processor.address); + break; + + + case ACPI_TYPE_DEVICE: + + acpi_os_printf ("Notify Object: %p\n", obj_desc); + break; + + + case ACPI_TYPE_METHOD: + + acpi_os_printf ("Args %X Len %.4X Aml %p\n", + (u32) obj_desc->method.param_count, + obj_desc->method.aml_length, obj_desc->method.aml_start); + break; + + + case ACPI_TYPE_INTEGER: + + acpi_os_printf ("= %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); + break; + + + case ACPI_TYPE_PACKAGE: + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + acpi_os_printf ("Elements %.2X\n", + obj_desc->package.count); + } + else { + acpi_os_printf ("[Length not yet evaluated]\n"); + } + break; + + + case ACPI_TYPE_BUFFER: + + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + acpi_os_printf ("Len %.2X", + obj_desc->buffer.length); + + /* Dump some of the buffer */ + + if (obj_desc->buffer.length > 0) { + acpi_os_printf (" ="); + for (i = 0; (i < obj_desc->buffer.length && i < 12); i++) { + acpi_os_printf (" %.2hX", obj_desc->buffer.pointer[i]); + } + } + acpi_os_printf ("\n"); + } + else { + acpi_os_printf ("[Length not yet evaluated]\n"); + } + break; + + + case ACPI_TYPE_STRING: + + acpi_os_printf ("Len %.2X ", obj_desc->string.length); + acpi_ut_print_string (obj_desc->string.pointer, 32); + acpi_os_printf ("\n"); + break; + + + case ACPI_TYPE_REGION: + + acpi_os_printf ("[%s]", + acpi_ut_get_region_name (obj_desc->region.space_id)); + if (obj_desc->region.flags & AOPOBJ_DATA_VALID) { + acpi_os_printf (" Addr %8.8X%8.8X Len %.4X\n", + ACPI_FORMAT_UINT64 (obj_desc->region.address), + obj_desc->region.length); + } + else { + acpi_os_printf (" [Address/Length not yet evaluated]\n"); + } + break; + + + case ACPI_TYPE_LOCAL_REFERENCE: + + acpi_os_printf ("[%s]\n", + acpi_ps_get_opcode_name (obj_desc->reference.opcode)); + break; + + + case ACPI_TYPE_BUFFER_FIELD: + + if (obj_desc->buffer_field.buffer_obj && + obj_desc->buffer_field.buffer_obj->buffer.node) { + acpi_os_printf ("Buf [%4.4s]", + acpi_ut_get_node_name (obj_desc->buffer_field.buffer_obj->buffer.node)); + } + break; + + + case ACPI_TYPE_LOCAL_REGION_FIELD: + + acpi_os_printf ("Rgn [%4.4s]", + acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node)); + break; + + + case ACPI_TYPE_LOCAL_BANK_FIELD: + + acpi_os_printf ("Rgn [%4.4s] Bnk [%4.4s]", + acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node), + acpi_ut_get_node_name (obj_desc->bank_field.bank_obj->common_field.node)); + break; + + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + acpi_os_printf ("Idx [%4.4s] Dat [%4.4s]", + acpi_ut_get_node_name (obj_desc->index_field.index_obj->common_field.node), + acpi_ut_get_node_name (obj_desc->index_field.data_obj->common_field.node)); + break; + + + case ACPI_TYPE_LOCAL_ALIAS: + case ACPI_TYPE_LOCAL_METHOD_ALIAS: + + acpi_os_printf ("Target %4.4s (%p)\n", + acpi_ut_get_node_name (obj_desc), obj_desc); + break; + + default: + + acpi_os_printf ("Object %p\n", obj_desc); + break; + } + + /* Common field handling */ + + switch (type) { + case ACPI_TYPE_BUFFER_FIELD: + case ACPI_TYPE_LOCAL_REGION_FIELD: + case ACPI_TYPE_LOCAL_BANK_FIELD: + case ACPI_TYPE_LOCAL_INDEX_FIELD: + + acpi_os_printf (" Off %.3X Len %.2X Acc %.2hd\n", + (obj_desc->common_field.base_byte_offset * 8) + + obj_desc->common_field.start_field_bit_offset, + obj_desc->common_field.bit_length, + obj_desc->common_field.access_byte_width); + break; + + default: + break; + } + break; + + + case ACPI_DISPLAY_OBJECTS: + + acpi_os_printf ("O:%p", obj_desc); + if (!obj_desc) { + /* No attached object, we are done */ + + acpi_os_printf ("\n"); + return (AE_OK); + } + + acpi_os_printf ("(R%d)", + obj_desc->common.reference_count); + + switch (type) { + case ACPI_TYPE_METHOD: + + /* Name is a Method and its AML offset/length are set */ + + acpi_os_printf (" M:%p-%X\n", obj_desc->method.aml_start, + obj_desc->method.aml_length); + break; + + case ACPI_TYPE_INTEGER: + + acpi_os_printf (" I:%8.8X8.8%X\n", + ACPI_FORMAT_UINT64 (obj_desc->integer.value)); + break; + + case ACPI_TYPE_STRING: + + acpi_os_printf (" S:%p-%X\n", obj_desc->string.pointer, + obj_desc->string.length); + break; + + case ACPI_TYPE_BUFFER: + + acpi_os_printf (" B:%p-%X\n", obj_desc->buffer.pointer, + obj_desc->buffer.length); + break; + + default: + + acpi_os_printf ("\n"); + break; + } + break; + + + default: + acpi_os_printf ("\n"); + break; + } + + /* If debug turned off, done */ + + if (!(acpi_dbg_level & ACPI_LV_VALUES)) { + return (AE_OK); + } + + + /* If there is an attached object, display it */ + + dbg_level = acpi_dbg_level; + acpi_dbg_level = 0; + obj_desc = acpi_ns_get_attached_object (this_node); + acpi_dbg_level = dbg_level; + + /* Dump attached objects */ + + while (obj_desc) { + obj_type = ACPI_TYPE_INVALID; + acpi_os_printf (" Attached Object %p: ", obj_desc); + + /* Decode the type of attached object and dump the contents */ + + switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) { + case ACPI_DESC_TYPE_NAMED: + + acpi_os_printf ("(Ptr to Node)\n"); + bytes_to_dump = sizeof (struct acpi_namespace_node); + break; + + + case ACPI_DESC_TYPE_OPERAND: + + obj_type = ACPI_GET_OBJECT_TYPE (obj_desc); + + if (obj_type > ACPI_TYPE_LOCAL_MAX) { + acpi_os_printf ("(Ptr to ACPI Object type %X [UNKNOWN])\n", + obj_type); + bytes_to_dump = 32; + } + else { + acpi_os_printf ("(Ptr to ACPI Object type %s, %X)\n", + acpi_ut_get_type_name (obj_type), obj_type); + bytes_to_dump = sizeof (union acpi_operand_object); + } + break; + + + default: + + acpi_os_printf ( + "(String or Buffer ptr - not an object descriptor) [%s]\n", + acpi_ut_get_descriptor_name (obj_desc)); + bytes_to_dump = 16; + break; + } + + ACPI_DUMP_BUFFER (obj_desc, bytes_to_dump); + + /* If value is NOT an internal object, we are done */ + + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) { + goto cleanup; + } + + /* + * Valid object, get the pointer to next level, if any + */ + switch (obj_type) { + case ACPI_TYPE_STRING: + obj_desc = (void *) obj_desc->string.pointer; + break; + + case ACPI_TYPE_BUFFER: + obj_desc = (void *) obj_desc->buffer.pointer; + break; + + case ACPI_TYPE_BUFFER_FIELD: + obj_desc = (union acpi_operand_object *) obj_desc->buffer_field.buffer_obj; + break; + + case ACPI_TYPE_PACKAGE: + obj_desc = (void *) obj_desc->package.elements; + break; + + case ACPI_TYPE_METHOD: + obj_desc = (void *) obj_desc->method.aml_start; + break; + + case ACPI_TYPE_LOCAL_REGION_FIELD: + obj_desc = (void *) obj_desc->field.region_obj; + break; + + case ACPI_TYPE_LOCAL_BANK_FIELD: + obj_desc = (void *) obj_desc->bank_field.region_obj; + break; + + case ACPI_TYPE_LOCAL_INDEX_FIELD: + obj_desc = (void *) obj_desc->index_field.index_obj; + break; + + default: + goto cleanup; + } + + obj_type = ACPI_TYPE_INVALID; /* Terminate loop after next pass */ + } + +cleanup: + acpi_os_printf ("\n"); + return (AE_OK); +} + + +#ifdef ACPI_FUTURE_USAGE + +/******************************************************************************* + * + * FUNCTION: acpi_ns_dump_objects + * + * PARAMETERS: Type - Object type to be dumped + * max_depth - Maximum depth of dump. Use ACPI_UINT32_MAX + * for an effectively unlimited depth. + * owner_id - Dump only objects owned by this ID. Use + * ACPI_UINT32_MAX to match all owners. + * start_handle - Where in namespace to start/end search + * + * DESCRIPTION: Dump typed objects within the loaded namespace. + * Uses acpi_ns_walk_namespace in conjunction with acpi_ns_dump_one_object. + * + ******************************************************************************/ + +void +acpi_ns_dump_objects ( + acpi_object_type type, + u8 display_type, + u32 max_depth, + u32 owner_id, + acpi_handle start_handle) +{ + struct acpi_walk_info info; + + + ACPI_FUNCTION_ENTRY (); + + + info.debug_level = ACPI_LV_TABLES; + info.owner_id = owner_id; + info.display_type = display_type; + + (void) acpi_ns_walk_namespace (type, start_handle, max_depth, + ACPI_NS_WALK_NO_UNLOCK, acpi_ns_dump_one_object, + (void *) &info, NULL); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_dump_tables + * + * PARAMETERS: search_base - Root of subtree to be dumped, or + * NS_ALL to dump the entire namespace + * max_depth - Maximum depth of dump. Use INT_MAX + * for an effectively unlimited depth. + * + * DESCRIPTION: Dump the name space, or a portion of it. + * + ******************************************************************************/ + +void +acpi_ns_dump_tables ( + acpi_handle search_base, + u32 max_depth) +{ + acpi_handle search_handle = search_base; + + + ACPI_FUNCTION_TRACE ("ns_dump_tables"); + + + if (!acpi_gbl_root_node) { + /* + * If the name space has not been initialized, + * there is nothing to dump. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "namespace not initialized!\n")); + return_VOID; + } + + if (ACPI_NS_ALL == search_base) { + /* entire namespace */ + + search_handle = acpi_gbl_root_node; + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "\\\n")); + } + + acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_OBJECTS, max_depth, + ACPI_UINT32_MAX, search_handle); + return_VOID; +} + +#endif /* ACPI_FUTURE_USAGE */ + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_dump_entry + * + * PARAMETERS: Handle - Node to be dumped + * debug_level - Output level + * + * DESCRIPTION: Dump a single Node + * + ******************************************************************************/ + +void +acpi_ns_dump_entry ( + acpi_handle handle, + u32 debug_level) +{ + struct acpi_walk_info info; + + + ACPI_FUNCTION_ENTRY (); + + + info.debug_level = debug_level; + info.owner_id = ACPI_UINT32_MAX; + info.display_type = ACPI_DISPLAY_SUMMARY; + + (void) acpi_ns_dump_one_object (handle, 1, &info, NULL); +} + +#endif + diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c new file mode 100644 index 000000000000..d30a59e6b07d --- /dev/null +++ b/drivers/acpi/namespace/nsdumpdv.c @@ -0,0 +1,146 @@ +/****************************************************************************** + * + * Module Name: nsdump - table dumping routines for debug + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsdumpdv") + + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +/******************************************************************************* + * + * FUNCTION: acpi_ns_dump_one_device + * + * PARAMETERS: Handle - Node to be dumped + * Level - Nesting level of the handle + * Context - Passed into walk_namespace + * + * DESCRIPTION: Dump a single Node that represents a device + * This procedure is a user_function called by acpi_ns_walk_namespace. + * + ******************************************************************************/ + +acpi_status +acpi_ns_dump_one_device ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value) +{ + struct acpi_buffer buffer; + struct acpi_device_info *info; + acpi_status status; + u32 i; + + + ACPI_FUNCTION_NAME ("ns_dump_one_device"); + + + status = acpi_ns_dump_one_object (obj_handle, level, context, return_value); + + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + status = acpi_get_object_info (obj_handle, &buffer); + if (ACPI_SUCCESS (status)) { + info = buffer.pointer; + for (i = 0; i < level; i++) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " ")); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, + " HID: %s, ADR: %8.8X%8.8X, Status: %X\n", + info->hardware_id.value, ACPI_FORMAT_UINT64 (info->address), + info->current_status)); + ACPI_MEM_FREE (info); + } + + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_dump_root_devices + * + * PARAMETERS: None + * + * DESCRIPTION: Dump all objects of type "device" + * + ******************************************************************************/ + +void +acpi_ns_dump_root_devices (void) +{ + acpi_handle sys_bus_handle; + acpi_status status; + + + ACPI_FUNCTION_NAME ("ns_dump_root_devices"); + + + /* Only dump the table if tracing is enabled */ + + if (!(ACPI_LV_TABLES & acpi_dbg_level)) { + return; + } + + status = acpi_get_handle(NULL, ACPI_NS_SYSTEM_BUS, &sys_bus_handle); + if (ACPI_FAILURE (status)) { + return; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, + "Display of all devices in the namespace:\n")); + + status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, sys_bus_handle, + ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, + acpi_ns_dump_one_device, NULL, NULL); +} + +#endif + + diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c new file mode 100644 index 000000000000..0d008d53657e --- /dev/null +++ b/drivers/acpi/namespace/nseval.c @@ -0,0 +1,487 @@ +/******************************************************************************* + * + * Module Name: nseval - Object evaluation interfaces -- includes control + * method lookup and execution. + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acparser.h> +#include <acpi/acinterp.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nseval") + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_evaluate_relative + * + * PARAMETERS: Pathname - Name of method to execute, If NULL, the + * handle is the object to execute + * Info - Method info block + * + * RETURN: Status + * + * DESCRIPTION: Find and execute the requested method using the handle as a + * scope + * + * MUTEX: Locks Namespace + * + ******************************************************************************/ + +acpi_status +acpi_ns_evaluate_relative ( + char *pathname, + struct acpi_parameter_info *info) +{ + acpi_status status; + struct acpi_namespace_node *node = NULL; + union acpi_generic_state *scope_info; + char *internal_path = NULL; + + + ACPI_FUNCTION_TRACE ("ns_evaluate_relative"); + + + /* + * Must have a valid object handle + */ + if (!info || !info->node) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Build an internal name string for the method */ + + status = acpi_ns_internalize_name (pathname, &internal_path); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + scope_info = acpi_ut_create_generic_state (); + if (!scope_info) { + goto cleanup1; + } + + /* Get the prefix handle and Node */ + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + info->node = acpi_ns_map_handle_to_node (info->node); + if (!info->node) { + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + status = AE_BAD_PARAMETER; + goto cleanup; + } + + /* Lookup the name in the namespace */ + + scope_info->scope.node = info->node; + status = acpi_ns_lookup (scope_info, internal_path, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, + &node); + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Object [%s] not found [%s]\n", + pathname, acpi_format_exception (status))); + goto cleanup; + } + + /* + * Now that we have a handle to the object, we can attempt to evaluate it. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", + pathname, node, acpi_ns_get_attached_object (node))); + + info->node = node; + status = acpi_ns_evaluate_by_handle (info); + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", + pathname)); + +cleanup: + acpi_ut_delete_generic_state (scope_info); + +cleanup1: + ACPI_MEM_FREE (internal_path); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_evaluate_by_name + * + * PARAMETERS: Pathname - Fully qualified pathname to the object + * Info - Contains: + * 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, + struct acpi_parameter_info *info) +{ + acpi_status status; + char *internal_path = NULL; + + + ACPI_FUNCTION_TRACE ("ns_evaluate_by_name"); + + + /* Build an internal name string for the method */ + + status = acpi_ns_internalize_name (pathname, &internal_path); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Lookup the name in the namespace */ + + status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, + &info->node); + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Object at [%s] was not found, status=%.4X\n", + pathname, status)); + goto cleanup; + } + + /* + * Now that we have a handle to the object, we can attempt to evaluate it. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n", + pathname, info->node, acpi_ns_get_attached_object (info->node))); + + status = acpi_ns_evaluate_by_handle (info); + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n", + pathname)); + + +cleanup: + + /* Cleanup */ + + if (internal_path) { + ACPI_MEM_FREE (internal_path); + } + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_evaluate_by_handle + * + * PARAMETERS: Handle - Method Node 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. + * param_type - Type of Parameter list + * return_object - Where to put method's return value (if + * any). If NULL, no value is returned. + * + * RETURN: Status + * + * DESCRIPTION: Execute the requested method passing the given parameters + * + * MUTEX: Locks Namespace + * + ******************************************************************************/ + +acpi_status +acpi_ns_evaluate_by_handle ( + struct acpi_parameter_info *info) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ns_evaluate_by_handle"); + + + /* Check if namespace has been initialized */ + + if (!acpi_gbl_root_node) { + return_ACPI_STATUS (AE_NO_NAMESPACE); + } + + /* Parameter Validation */ + + if (!info) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Initialize the return value to an invalid object */ + + info->return_object = NULL; + + /* Get the prefix handle and Node */ + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + info->node = acpi_ns_map_handle_to_node (info->node); + if (!info->node) { + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * For a method alias, we must grab the actual method node so that proper + * scoping context will be established before execution. + */ + if (acpi_ns_get_type (info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { + info->node = ACPI_CAST_PTR (struct acpi_namespace_node, info->node->object); + } + + /* + * 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 (info->node) == ACPI_TYPE_METHOD) { + /* + * Case 1) We have an actual control method to execute + */ + status = acpi_ns_execute_control_method (info); + } + else { + /* + * Case 2) Object is NOT a method, just return its current value + */ + status = acpi_ns_get_object_value (info); + } + + /* + * Check if there is a return value on the stack that must be dealt with + */ + if (status == AE_CTRL_RETURN_VALUE) { + /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */ + + status = AE_OK; + } + + /* + * Namespace was unlocked by the handling acpi_ns* function, so we + * just return + */ + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_execute_control_method + * + * PARAMETERS: Info - Method info block (w/params) + * + * RETURN: Status + * + * DESCRIPTION: Execute the requested method passing the given parameters + * + * MUTEX: Assumes namespace is locked + * + ******************************************************************************/ + +acpi_status +acpi_ns_execute_control_method ( + struct acpi_parameter_info *info) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_TRACE ("ns_execute_control_method"); + + + /* Verify that there is a method associated with this object */ + + obj_desc = acpi_ns_get_attached_object (info->node); + if (!obj_desc) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No attached method object\n")); + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + ACPI_DUMP_PATHNAME (info->node, "Execute Method:", + ACPI_LV_INFO, _COMPONENT); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Method at AML address %p Length %X\n", + obj_desc->method.aml_start + 1, obj_desc->method.aml_length - 1)); + + /* + * 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 + * interpreter locks to ensure that no thread is using the portion of the + * namespace that is being deleted. + */ + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Execute the method via the interpreter. The interpreter is locked + * here before calling into the AML parser + */ + status = acpi_ex_enter_interpreter (); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_psx_execute (info); + acpi_ex_exit_interpreter (); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_object_value + * + * PARAMETERS: Info - Method info block (w/params) + * + * RETURN: Status + * + * DESCRIPTION: Return the current value of the object + * + * MUTEX: Assumes namespace is locked, leaves namespace unlocked + * + ******************************************************************************/ + +acpi_status +acpi_ns_get_object_value ( + struct acpi_parameter_info *info) +{ + acpi_status status = AE_OK; + struct acpi_namespace_node *resolved_node = info->node; + + + ACPI_FUNCTION_TRACE ("ns_get_object_value"); + + + /* + * Objects require additional resolution steps (e.g., the Node may be a + * field that must be read, etc.) -- we can't just grab the object out of + * the node. + */ + + /* + * Use resolve_node_to_value() to get the associated value. This call always + * deletes obj_desc (allocated above). + * + * NOTE: we can get away with passing in NULL for a walk state because + * obj_desc is guaranteed to not be a reference to either a method local or + * a method argument (because this interface can only be called from the + * acpi_evaluate external interface, never called from a running method.) + * + * Even though we do not directly invoke the interpreter for this, we must + * enter it because we could access an opregion. The opregion access code + * assumes that the interpreter is locked. + * + * We must release the namespace lock before entering the intepreter. + */ + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ex_enter_interpreter (); + if (ACPI_SUCCESS (status)) { + status = acpi_ex_resolve_node_to_value (&resolved_node, NULL); + /* + * If acpi_ex_resolve_node_to_value() succeeded, the return value was placed + * in resolved_node. + */ + acpi_ex_exit_interpreter (); + + if (ACPI_SUCCESS (status)) { + status = AE_CTRL_RETURN_VALUE; + info->return_object = ACPI_CAST_PTR + (union acpi_operand_object, resolved_node); + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n", + info->return_object, + acpi_ut_get_object_type_name (info->return_object))); + } + } + + /* Namespace is unlocked */ + + return_ACPI_STATUS (status); +} + diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c new file mode 100644 index 000000000000..4a46b380605b --- /dev/null +++ b/drivers/acpi/namespace/nsinit.c @@ -0,0 +1,441 @@ +/****************************************************************************** + * + * Module Name: nsinit - namespace initialization + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/acdispat.h> +#include <acpi/acinterp.h> + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsinit") + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_initialize_objects + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Walk the entire namespace and perform any necessary + * initialization on the objects found therein + * + ******************************************************************************/ + +acpi_status +acpi_ns_initialize_objects ( + void) +{ + acpi_status status; + struct acpi_init_walk_info info; + + + ACPI_FUNCTION_TRACE ("ns_initialize_objects"); + + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "**** Starting initialization of namespace objects ****\n")); + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "Completing Region/Field/Buffer/Package initialization:")); + + /* Set all init info to zero */ + + ACPI_MEMSET (&info, 0, sizeof (struct acpi_init_walk_info)); + + /* Walk entire namespace from the supplied root */ + + status = acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, acpi_ns_init_one_object, + &info, NULL); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed! %s\n", + acpi_format_exception (status))); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "\nInitialized %hd/%hd Regions %hd/%hd Fields %hd/%hd Buffers %hd/%hd Packages (%hd nodes)\n", + info.op_region_init, info.op_region_count, + info.field_init, info.field_count, + info.buffer_init, info.buffer_count, + info.package_init, info.package_count, info.object_count)); + + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "%hd Control Methods found\n", info.method_count)); + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "%hd Op Regions found\n", info.op_region_count)); + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_initialize_devices + * + * PARAMETERS: None + * + * RETURN: acpi_status + * + * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices. + * This means running _INI on all present devices. + * + * Note: We install PCI config space handler on region access, + * not here. + * + ******************************************************************************/ + +acpi_status +acpi_ns_initialize_devices ( + void) +{ + acpi_status status; + struct acpi_device_walk_info info; + + + ACPI_FUNCTION_TRACE ("ns_initialize_devices"); + + + /* Init counters */ + + info.device_count = 0; + info.num_STA = 0; + info.num_INI = 0; + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "Executing all Device _STA and_INI methods:")); + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Walk namespace for all objects */ + + status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, TRUE, acpi_ns_init_one_device, &info, NULL); + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed! %s\n", + acpi_format_exception (status))); + } + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "\n%hd Devices found containing: %hd _STA, %hd _INI methods\n", + info.device_count, info.num_STA, info.num_INI)); + + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_init_one_object + * + * PARAMETERS: obj_handle - Node + * Level - Current nesting level + * Context - Points to a init info struct + * return_value - Not used + * + * RETURN: Status + * + * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object + * within the namespace. + * + * Currently, the only objects that require initialization are: + * 1) Methods + * 2) Op Regions + * + ******************************************************************************/ + +acpi_status +acpi_ns_init_one_object ( + acpi_handle obj_handle, + u32 level, + void *context, + void **return_value) +{ + acpi_object_type type; + acpi_status status; + struct acpi_init_walk_info *info = (struct acpi_init_walk_info *) context; + struct acpi_namespace_node *node = (struct acpi_namespace_node *) obj_handle; + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_NAME ("ns_init_one_object"); + + + info->object_count++; + + /* And even then, we are only interested in a few object types */ + + type = acpi_ns_get_type (obj_handle); + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + return (AE_OK); + } + + /* Increment counters for object types we are looking for */ + + switch (type) { + case ACPI_TYPE_REGION: + info->op_region_count++; + break; + + case ACPI_TYPE_BUFFER_FIELD: + info->field_count++; + break; + + case ACPI_TYPE_BUFFER: + info->buffer_count++; + break; + + case ACPI_TYPE_PACKAGE: + info->package_count++; + break; + + default: + + /* No init required, just exit now */ + return (AE_OK); + } + + /* + * If the object is already initialized, nothing else to do + */ + if (obj_desc->common.flags & AOPOBJ_DATA_VALID) { + return (AE_OK); + } + + /* + * Must lock the interpreter before executing AML code + */ + status = acpi_ex_enter_interpreter (); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* + * Each of these types can contain executable AML code within the + * declaration. + */ + switch (type) { + case ACPI_TYPE_REGION: + + info->op_region_init++; + status = acpi_ds_get_region_arguments (obj_desc); + break; + + case ACPI_TYPE_BUFFER_FIELD: + + info->field_init++; + status = acpi_ds_get_buffer_field_arguments (obj_desc); + break; + + case ACPI_TYPE_BUFFER: + + info->buffer_init++; + status = acpi_ds_get_buffer_arguments (obj_desc); + break; + + case ACPI_TYPE_PACKAGE: + + info->package_init++; + status = acpi_ds_get_package_arguments (obj_desc); + break; + + default: + /* No other types can get here */ + break; + } + + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not execute arguments for [%4.4s] (%s), %s\n", + acpi_ut_get_node_name (node), acpi_ut_get_type_name (type), + acpi_format_exception (status))); + } + + /* + * Print a dot for each object unless we are going to print the entire + * pathname + */ + if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); + } + + /* + * We ignore errors from above, and always return OK, since we don't want + * to abort the walk on any single error. + */ + acpi_ex_exit_interpreter (); + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_init_one_device + * + * PARAMETERS: acpi_walk_callback + * + * RETURN: acpi_status + * + * DESCRIPTION: This is called once per device soon after ACPI is enabled + * to initialize each device. It determines if the device is + * present, and if so, calls _INI. + * + ******************************************************************************/ + +acpi_status +acpi_ns_init_one_device ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value) +{ + struct acpi_device_walk_info *info = (struct acpi_device_walk_info *) context; + struct acpi_parameter_info pinfo; + u32 flags; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ns_init_one_device"); + + + pinfo.parameters = NULL; + pinfo.parameter_type = ACPI_PARAM_ARGS; + + pinfo.node = acpi_ns_map_handle_to_node (obj_handle); + if (!pinfo.node) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * We will run _STA/_INI on Devices, Processors and thermal_zones only + */ + if ((pinfo.node->type != ACPI_TYPE_DEVICE) && + (pinfo.node->type != ACPI_TYPE_PROCESSOR) && + (pinfo.node->type != ACPI_TYPE_THERMAL)) { + return_ACPI_STATUS (AE_OK); + } + + if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) && + (!(acpi_dbg_level & ACPI_LV_INFO))) { + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, ".")); + } + + info->device_count++; + + /* + * Run _STA to determine if we can run _INI on the device. + */ + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_STA")); + status = acpi_ut_execute_STA (pinfo.node, &flags); + + if (ACPI_FAILURE (status)) { + if (pinfo.node->type == ACPI_TYPE_DEVICE) { + /* Ignore error and move on to next device */ + + return_ACPI_STATUS (AE_OK); + } + + /* _STA is not required for Processor or thermal_zone objects */ + } + else { + info->num_STA++; + + if (!(flags & 0x01)) { + /* Don't look at children of a not present device */ + + return_ACPI_STATUS(AE_CTRL_DEPTH); + } + } + + /* + * The device is present. Run _INI. + */ + ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI")); + status = acpi_ns_evaluate_relative ("_INI", &pinfo); + if (ACPI_FAILURE (status)) { + /* No _INI (AE_NOT_FOUND) means device requires no initialization */ + + if (status != AE_NOT_FOUND) { + /* Ignore error and move on to next device */ + +#ifdef ACPI_DEBUG_OUTPUT + char *scope_name = acpi_ns_get_external_pathname (pinfo.node); + + ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n", + scope_name, acpi_format_exception (status))); + + ACPI_MEM_FREE (scope_name); +#endif + } + + status = AE_OK; + } + else { + /* Delete any return object (especially if implicit_return is enabled) */ + + if (pinfo.return_object) { + acpi_ut_remove_reference (pinfo.return_object); + } + + /* Count of successful INIs */ + + info->num_INI++; + } + + if (acpi_gbl_init_handler) { + /* External initialization handler is present, call it */ + + status = acpi_gbl_init_handler (pinfo.node, ACPI_INIT_DEVICE_INI); + } + + return_ACPI_STATUS (status); +} diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c new file mode 100644 index 000000000000..1d7aedf68a77 --- /dev/null +++ b/drivers/acpi/namespace/nsload.c @@ -0,0 +1,460 @@ +/****************************************************************************** + * + * Module Name: nsload - namespace loading/expanding/contracting procedures + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/acdispat.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsload") + + +#ifndef ACPI_NO_METHOD_EXECUTION + +/******************************************************************************* + * + * FUNCTION: acpi_ns_load_table + * + * PARAMETERS: table_desc - Descriptor for table to be loaded + * Node - Owning NS node + * + * RETURN: Status + * + * DESCRIPTION: Load one ACPI table into the namespace + * + ******************************************************************************/ + +acpi_status +acpi_ns_load_table ( + struct acpi_table_desc *table_desc, + struct acpi_namespace_node *node) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ns_load_table"); + + + /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */ + + if (!(acpi_gbl_table_data[table_desc->type].flags & ACPI_TABLE_EXECUTABLE)) { + /* Just ignore this table */ + + return_ACPI_STATUS (AE_OK); + } + + /* Check validity of the AML start and length */ + + if (!table_desc->aml_start) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null AML pointer\n")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "AML block at %p\n", + table_desc->aml_start)); + + /* Ignore table if there is no AML contained within */ + + if (!table_desc->aml_length) { + ACPI_REPORT_WARNING (("Zero-length AML block in table [%4.4s]\n", + table_desc->pointer->signature)); + return_ACPI_STATUS (AE_OK); + } + + /* + * 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_DEBUG_PRINT ((ACPI_DB_INFO, + "**** Loading table into namespace ****\n")); + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ns_parse_table (table_desc, node->child); + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (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. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "**** Begin Table Method Parsing and Object Initialization ****\n")); + + status = acpi_ds_initialize_objects (table_desc, node); + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "**** Completed Table Method Parsing and Object Initialization ****\n")); + + return_ACPI_STATUS (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; + struct acpi_table_desc *table_desc; + + + ACPI_FUNCTION_TRACE ("ns_load_table_by_type"); + + + status = acpi_ut_acquire_mutex (ACPI_MTX_TABLES); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * Table types supported are: + * DSDT (one), SSDT/PSDT (multiple) + */ + switch (table_type) { + case ACPI_TABLE_DSDT: + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading DSDT\n")); + + table_desc = acpi_gbl_table_lists[ACPI_TABLE_DSDT].next; + + /* If table already loaded into namespace, just return */ + + if (table_desc->loaded_into_namespace) { + goto unlock_and_exit; + } + + /* Now load the single DSDT */ + + status = acpi_ns_load_table (table_desc, acpi_gbl_root_node); + if (ACPI_SUCCESS (status)) { + table_desc->loaded_into_namespace = TRUE; + } + break; + + + case ACPI_TABLE_SSDT: + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading %d SSDTs\n", + acpi_gbl_table_lists[ACPI_TABLE_SSDT].count)); + + /* + * Traverse list of SSDT tables + */ + table_desc = acpi_gbl_table_lists[ACPI_TABLE_SSDT].next; + for (i = 0; i < acpi_gbl_table_lists[ACPI_TABLE_SSDT].count; i++) { + /* + * 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_node); + if (ACPI_FAILURE (status)) { + break; + } + + table_desc->loaded_into_namespace = TRUE; + } + + table_desc = table_desc->next; + } + break; + + + case ACPI_TABLE_PSDT: + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading %d PSDTs\n", + acpi_gbl_table_lists[ACPI_TABLE_PSDT].count)); + + /* + * Traverse list of PSDT tables + */ + table_desc = acpi_gbl_table_lists[ACPI_TABLE_PSDT].next; + + for (i = 0; i < acpi_gbl_table_lists[ACPI_TABLE_PSDT].count; i++) { + /* 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_node); + if (ACPI_FAILURE (status)) { + break; + } + + table_desc->loaded_into_namespace = TRUE; + } + + table_desc = table_desc->next; + } + break; + + + default: + status = AE_SUPPORT; + break; + } + + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_TABLES); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_load_namespace + * + * PARAMETERS: None + * + * 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_ns_load_namespace ( + void) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("acpi_load_name_space"); + + + /* There must be at least a DSDT installed */ + + if (acpi_gbl_DSDT == NULL) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "DSDT is not in memory\n")); + return_ACPI_STATUS (AE_NO_ACPI_TABLES); + } + + /* + * 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_ACPI_STATUS (status); + } + + /* Ignore exceptions from these */ + + (void) acpi_ns_load_table_by_type (ACPI_TABLE_SSDT); + (void) acpi_ns_load_table_by_type (ACPI_TABLE_PSDT); + + ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, + "ACPI Namespace successfully loaded at root %p\n", + acpi_gbl_root_node)); + + return_ACPI_STATUS (status); +} + + +#ifdef ACPI_FUTURE_USAGE + +/******************************************************************************* + * + * 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. + * + * Namespace/Interpreter should be locked or the subsystem should + * be in shutdown before this routine is called. + * + ******************************************************************************/ + +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; + + + ACPI_FUNCTION_TRACE ("ns_delete_subtree"); + + + parent_handle = start_handle; + child_handle = NULL; + 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); + + 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, + NULL, &dummy))) { + /* + * There is at least one child of this object, + * visit the object + */ + level++; + parent_handle = child_handle; + child_handle = NULL; + } + } + else { + /* + * No more children in this object, go back up to + * the object's parent + */ + level--; + + /* Delete all children now */ + + acpi_ns_delete_children (child_handle); + + child_handle = parent_handle; + status = acpi_get_parent (parent_handle, &parent_handle); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + } + + /* Now delete the starting object, and we are done */ + + acpi_ns_delete_node (child_handle); + + return_ACPI_STATUS (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; + + + ACPI_FUNCTION_TRACE ("ns_unload_name_space"); + + + /* Parameter validation */ + + if (!acpi_gbl_root_node) { + return_ACPI_STATUS (AE_NO_NAMESPACE); + } + + if (!handle) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* This function does the real work */ + + status = acpi_ns_delete_subtree (handle); + + return_ACPI_STATUS (status); +} + +#endif /* ACPI_FUTURE_USAGE */ + +#endif + diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c new file mode 100644 index 000000000000..b6f8f910eff0 --- /dev/null +++ b/drivers/acpi/namespace/nsnames.c @@ -0,0 +1,265 @@ +/******************************************************************************* + * + * Module Name: nsnames - Name manipulation and search + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/amlcode.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsnames") + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_build_external_path + * + * PARAMETERS: Node - NS node whose pathname is needed + * Size - Size of the pathname + * *name_buffer - Where to return the pathname + * + * RETURN: Places the pathname into the name_buffer, in external format + * (name segments separated by path separators) + * + * DESCRIPTION: Generate a full pathaname + * + ******************************************************************************/ + +void +acpi_ns_build_external_path ( + struct acpi_namespace_node *node, + acpi_size size, + char *name_buffer) +{ + acpi_size index; + struct acpi_namespace_node *parent_node; + + + ACPI_FUNCTION_NAME ("ns_build_external_path"); + + + /* Special case for root */ + + index = size - 1; + if (index < ACPI_NAME_SIZE) { + name_buffer[0] = AML_ROOT_PREFIX; + name_buffer[1] = 0; + return; + } + + /* Store terminator byte, then build name backwards */ + + parent_node = node; + name_buffer[index] = 0; + + while ((index > ACPI_NAME_SIZE) && (parent_node != acpi_gbl_root_node)) { + index -= ACPI_NAME_SIZE; + + /* Put the name into the buffer */ + + ACPI_MOVE_32_TO_32 ((name_buffer + index), &parent_node->name); + parent_node = acpi_ns_get_parent_node (parent_node); + + /* Prefix name with the path separator */ + + index--; + name_buffer[index] = ACPI_PATH_SEPARATOR; + } + + /* Overwrite final separator with the root prefix character */ + + name_buffer[index] = AML_ROOT_PREFIX; + + if (index != 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not construct pathname; index=%X, size=%X, Path=%s\n", + (u32) index, (u32) size, &name_buffer[size])); + } + + return; +} + + +#ifdef ACPI_DEBUG_OUTPUT +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_external_pathname + * + * PARAMETERS: Node - NS node whose pathname is needed + * + * RETURN: Pointer to storage containing the fully qualified name of + * the node, In external format (name segments separated by path + * separators.) + * + * DESCRIPTION: Used for debug printing in acpi_ns_search_table(). + * + ******************************************************************************/ + +char * +acpi_ns_get_external_pathname ( + struct acpi_namespace_node *node) +{ + char *name_buffer; + acpi_size size; + + + ACPI_FUNCTION_TRACE_PTR ("ns_get_external_pathname", node); + + + /* Calculate required buffer size based on depth below root */ + + size = acpi_ns_get_pathname_length (node); + + /* Allocate a buffer to be returned to caller */ + + name_buffer = ACPI_MEM_CALLOCATE (size); + if (!name_buffer) { + ACPI_REPORT_ERROR (("ns_get_table_pathname: allocation failure\n")); + return_PTR (NULL); + } + + /* Build the path in the allocated buffer */ + + acpi_ns_build_external_path (node, size, name_buffer); + return_PTR (name_buffer); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_pathname_length + * + * PARAMETERS: Node - Namespace node + * + * RETURN: Length of path, including prefix + * + * DESCRIPTION: Get the length of the pathname string for this node + * + ******************************************************************************/ + +acpi_size +acpi_ns_get_pathname_length ( + struct acpi_namespace_node *node) +{ + acpi_size size; + struct acpi_namespace_node *next_node; + + + ACPI_FUNCTION_ENTRY (); + + + /* + * Compute length of pathname as 5 * number of name segments. + * Go back up the parent tree to the root + */ + size = 0; + next_node = node; + + while (next_node && (next_node != acpi_gbl_root_node)) { + size += ACPI_PATH_SEGMENT_LENGTH; + next_node = acpi_ns_get_parent_node (next_node); + } + + if (!size) { + size = 1; /* Root node case */ + } + + return (size + 1); /* +1 for null string terminator */ +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_handle_to_pathname + * + * PARAMETERS: target_handle - Handle of named object whose name is + * to be found + * Buffer - Where the pathname is returned + * + * RETURN: Status, Buffer is filled with pathname if status is AE_OK + * + * DESCRIPTION: Build and return a full namespace pathname + * + ******************************************************************************/ + +acpi_status +acpi_ns_handle_to_pathname ( + acpi_handle target_handle, + struct acpi_buffer *buffer) +{ + acpi_status status; + struct acpi_namespace_node *node; + acpi_size required_size; + + + ACPI_FUNCTION_TRACE_PTR ("ns_handle_to_pathname", target_handle); + + + node = acpi_ns_map_handle_to_node (target_handle); + if (!node) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Determine size required for the caller buffer */ + + required_size = acpi_ns_get_pathname_length (node); + + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer (buffer, required_size); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Build the path in the caller buffer */ + + acpi_ns_build_external_path (node, required_size, buffer->pointer); + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s [%X] \n", + (char *) buffer->pointer, (u32) required_size)); + return_ACPI_STATUS (AE_OK); +} + + diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c new file mode 100644 index 000000000000..4e41e66db61f --- /dev/null +++ b/drivers/acpi/namespace/nsobject.c @@ -0,0 +1,461 @@ +/******************************************************************************* + * + * Module Name: nsobject - Utilities for objects attached to namespace + * table entries + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsobject") + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_attach_object + * + * PARAMETERS: Node - Parent Node + * 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. + * Note: Future may require that the Node->Flags field be passed + * as a parameter. + * + * MUTEX: Assumes namespace is locked + * + ******************************************************************************/ + +acpi_status +acpi_ns_attach_object ( + struct acpi_namespace_node *node, + union acpi_operand_object *object, + acpi_object_type type) +{ + union acpi_operand_object *obj_desc; + union acpi_operand_object *last_obj_desc; + acpi_object_type object_type = ACPI_TYPE_ANY; + + + ACPI_FUNCTION_TRACE ("ns_attach_object"); + + + /* + * Parameter validation + */ + if (!node) { + /* Invalid handle */ + + ACPI_REPORT_ERROR (("ns_attach_object: Null named_obj handle\n")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (!object && (ACPI_TYPE_ANY != type)) { + /* Null object */ + + ACPI_REPORT_ERROR (("ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) { + /* Not a name handle */ + + ACPI_REPORT_ERROR (("ns_attach_object: Invalid handle %p [%s]\n", + node, acpi_ut_get_descriptor_name (node))); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Check if this object is already attached */ + + if (node->object == object) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj %p already installed in name_obj %p\n", + object, node)); + + return_ACPI_STATUS (AE_OK); + } + + /* If null object, we will just install it */ + + if (!object) { + obj_desc = NULL; + object_type = ACPI_TYPE_ANY; + } + + /* + * If the source object is a namespace Node with an attached object, + * we will use that (attached) object + */ + else if ((ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) && + ((struct acpi_namespace_node *) 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 = ((struct acpi_namespace_node *) object)->object; + object_type = ((struct acpi_namespace_node *) object)->type; + } + + /* + * Otherwise, we will use the parameter object, but we must type + * it first + */ + else { + obj_desc = (union acpi_operand_object *) object; + + /* Use the given type */ + + object_type = type; + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Installing %p into Node %p [%4.4s]\n", + obj_desc, node, acpi_ut_get_node_name (node))); + + /* Detach an existing attached object if present */ + + if (node->object) { + acpi_ns_detach_object (node); + } + + if (obj_desc) { + /* + * Must increment the new value's reference count + * (if it is an internal object) + */ + acpi_ut_add_reference (obj_desc); + + /* + * Handle objects with multiple descriptors - walk + * to the end of the descriptor list + */ + last_obj_desc = obj_desc; + while (last_obj_desc->common.next_object) { + last_obj_desc = last_obj_desc->common.next_object; + } + + /* Install the object at the front of the object list */ + + last_obj_desc->common.next_object = node->object; + } + + node->type = (u8) object_type; + node->object = obj_desc; + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_detach_object + * + * PARAMETERS: Node - An node whose object will be detached + * + * RETURN: None. + * + * DESCRIPTION: Detach/delete an object associated with a namespace node. + * if the object is an allocated object, it is freed. + * Otherwise, the field is simply cleared. + * + ******************************************************************************/ + +void +acpi_ns_detach_object ( + struct acpi_namespace_node *node) +{ + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_TRACE ("ns_detach_object"); + + + obj_desc = node->object; + + if (!obj_desc || + (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA)) { + return_VOID; + } + + /* Clear the entry in all cases */ + + node->object = NULL; + if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_OPERAND) { + node->object = obj_desc->common.next_object; + if (node->object && + (ACPI_GET_OBJECT_TYPE (node->object) != ACPI_TYPE_LOCAL_DATA)) { + node->object = node->object->common.next_object; + } + } + + /* Reset the node type to untyped */ + + node->type = ACPI_TYPE_ANY; + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n", + node, acpi_ut_get_node_name (node), obj_desc)); + + /* Remove one reference on the object (and all subobjects) */ + + acpi_ut_remove_reference (obj_desc); + return_VOID; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_attached_object + * + * PARAMETERS: Node - Parent Node to be examined + * + * RETURN: Current value of the object field from the Node whose + * handle is passed + * + * DESCRIPTION: Obtain the object attached to a namespace node. + * + ******************************************************************************/ + +union acpi_operand_object * +acpi_ns_get_attached_object ( + struct acpi_namespace_node *node) +{ + ACPI_FUNCTION_TRACE_PTR ("ns_get_attached_object", node); + + + if (!node) { + ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Null Node ptr\n")); + return_PTR (NULL); + } + + if (!node->object || + ((ACPI_GET_DESCRIPTOR_TYPE (node->object) != ACPI_DESC_TYPE_OPERAND) && + (ACPI_GET_DESCRIPTOR_TYPE (node->object) != ACPI_DESC_TYPE_NAMED)) || + (ACPI_GET_OBJECT_TYPE (node->object) == ACPI_TYPE_LOCAL_DATA)) { + return_PTR (NULL); + } + + return_PTR (node->object); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_secondary_object + * + * PARAMETERS: Node - Parent Node to be examined + * + * RETURN: Current value of the object field from the Node whose + * handle is passed. + * + * DESCRIPTION: Obtain a secondary object associated with a namespace node. + * + ******************************************************************************/ + +union acpi_operand_object * +acpi_ns_get_secondary_object ( + union acpi_operand_object *obj_desc) +{ + ACPI_FUNCTION_TRACE_PTR ("ns_get_secondary_object", obj_desc); + + + if ((!obj_desc) || + (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA) || + (!obj_desc->common.next_object) || + (ACPI_GET_OBJECT_TYPE (obj_desc->common.next_object) == ACPI_TYPE_LOCAL_DATA)) { + return_PTR (NULL); + } + + return_PTR (obj_desc->common.next_object); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_attach_data + * + * PARAMETERS: Node - Namespace node + * Handler - Handler to be associated with the data + * Data - Data to be attached + * + * RETURN: Status + * + * DESCRIPTION: Low-level attach data. Create and attach a Data object. + * + ******************************************************************************/ + +acpi_status +acpi_ns_attach_data ( + struct acpi_namespace_node *node, + acpi_object_handler handler, + void *data) +{ + union acpi_operand_object *prev_obj_desc; + union acpi_operand_object *obj_desc; + union acpi_operand_object *data_desc; + + + /* We only allow one attachment per handler */ + + prev_obj_desc = NULL; + obj_desc = node->object; + while (obj_desc) { + if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA) && + (obj_desc->data.handler == handler)) { + return (AE_ALREADY_EXISTS); + } + + prev_obj_desc = obj_desc; + obj_desc = obj_desc->common.next_object; + } + + /* Create an internal object for the data */ + + data_desc = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_DATA); + if (!data_desc) { + return (AE_NO_MEMORY); + } + + data_desc->data.handler = handler; + data_desc->data.pointer = data; + + /* Install the data object */ + + if (prev_obj_desc) { + prev_obj_desc->common.next_object = data_desc; + } + else { + node->object = data_desc; + } + + return (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_detach_data + * + * PARAMETERS: Node - Namespace node + * Handler - Handler associated with the data + * + * RETURN: Status + * + * DESCRIPTION: Low-level detach data. Delete the data node, but the caller + * is responsible for the actual data. + * + ******************************************************************************/ + +acpi_status +acpi_ns_detach_data ( + struct acpi_namespace_node *node, + acpi_object_handler handler) +{ + union acpi_operand_object *obj_desc; + union acpi_operand_object *prev_obj_desc; + + + prev_obj_desc = NULL; + obj_desc = node->object; + while (obj_desc) { + if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA) && + (obj_desc->data.handler == handler)) { + if (prev_obj_desc) { + prev_obj_desc->common.next_object = obj_desc->common.next_object; + } + else { + node->object = obj_desc->common.next_object; + } + + acpi_ut_remove_reference (obj_desc); + return (AE_OK); + } + + prev_obj_desc = obj_desc; + obj_desc = obj_desc->common.next_object; + } + + return (AE_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_attached_data + * + * PARAMETERS: Node - Namespace node + * Handler - Handler associated with the data + * Data - Where the data is returned + * + * RETURN: Status + * + * DESCRIPTION: Low level interface to obtain data previously associated with + * a namespace node. + * + ******************************************************************************/ + +acpi_status +acpi_ns_get_attached_data ( + struct acpi_namespace_node *node, + acpi_object_handler handler, + void **data) +{ + union acpi_operand_object *obj_desc; + + + obj_desc = node->object; + while (obj_desc) { + if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA) && + (obj_desc->data.handler == handler)) { + *data = obj_desc->data.pointer; + return (AE_OK); + } + + obj_desc = obj_desc->common.next_object; + } + + return (AE_NOT_FOUND); +} + + diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c new file mode 100644 index 000000000000..a0e13e8d3764 --- /dev/null +++ b/drivers/acpi/namespace/nsparse.c @@ -0,0 +1,171 @@ +/****************************************************************************** + * + * Module Name: nsparse - namespace interface to AML parser + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/acparser.h> +#include <acpi/acdispat.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsparse") + + +/******************************************************************************* + * + * FUNCTION: ns_one_complete_parse + * + * PARAMETERS: pass_number - 1 or 2 + * table_desc - The table to be parsed. + * + * RETURN: Status + * + * DESCRIPTION: Perform one complete parse of an ACPI/AML table. + * + ******************************************************************************/ + +acpi_status +acpi_ns_one_complete_parse ( + u32 pass_number, + struct acpi_table_desc *table_desc) +{ + union acpi_parse_object *parse_root; + acpi_status status; + struct acpi_walk_state *walk_state; + + + ACPI_FUNCTION_TRACE ("ns_one_complete_parse"); + + + /* Create and init a Root Node */ + + parse_root = acpi_ps_create_scope_op (); + if (!parse_root) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Create and initialize a new walk state */ + + walk_state = acpi_ds_create_walk_state (table_desc->table_id, + NULL, NULL, NULL); + if (!walk_state) { + acpi_ps_free_op (parse_root); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + status = acpi_ds_init_aml_walk (walk_state, parse_root, NULL, + table_desc->aml_start, table_desc->aml_length, + NULL, pass_number); + if (ACPI_FAILURE (status)) { + acpi_ds_delete_walk_state (walk_state); + return_ACPI_STATUS (status); + } + + /* Parse the AML */ + + ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "*PARSE* pass %d parse\n", pass_number)); + status = acpi_ps_parse_aml (walk_state); + + acpi_ps_delete_parse_tree (parse_root); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_parse_table + * + * PARAMETERS: table_desc - An ACPI table descriptor for table to parse + * start_node - 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 ( + struct acpi_table_desc *table_desc, + struct acpi_namespace_node *start_node) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ns_parse_table"); + + + /* + * AML Parse, pass 1 + * + * In this pass, we load most of the namespace. Control methods + * are not parsed until later. A parse tree is not created. Instead, + * each Parser Op subtree is deleted when it is finished. This saves + * a great deal of memory, and allows a small cache of parse objects + * to service the entire parse. The second pass of the parse then + * performs another complete parse of the AML.. + */ + status = acpi_ns_one_complete_parse (1, table_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* + * AML Parse, pass 2 + * + * In this pass, we resolve forward references and other things + * that could not be completed during the first pass. + * Another complete parse of the AML is performed, but the + * overhead of this is compensated for by the fact that the + * parse objects are all cached. + */ + status = acpi_ns_one_complete_parse (2, table_desc); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + return_ACPI_STATUS (status); +} + + diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c new file mode 100644 index 000000000000..0e6dea23603b --- /dev/null +++ b/drivers/acpi/namespace/nssearch.c @@ -0,0 +1,381 @@ +/******************************************************************************* + * + * Module Name: nssearch - Namespace search + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nssearch") + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_search_node + * + * PARAMETERS: *target_name - Ascii ACPI name to search for + * *Node - Starting node where search will begin + * Type - Object type to match + * **return_node - Where the matched Named obj is returned + * + * RETURN: Status + * + * DESCRIPTION: Search a single level of the namespace. Performs a + * simple search of the specified level, and does not add + * entries or search parents. + * + * + * Named object lists are built (and subsequently dumped) in the + * order in which the names are encountered during the namespace load; + * + * All namespace searching is linear in this implementation, but + * could be easily modified to support any improved search + * algorithm. However, the linear search was chosen for simplicity + * and because the trees are small and the other interpreter + * execution overhead is relatively high. + * + ******************************************************************************/ + +acpi_status +acpi_ns_search_node ( + u32 target_name, + struct acpi_namespace_node *node, + acpi_object_type type, + struct acpi_namespace_node **return_node) +{ + struct acpi_namespace_node *next_node; + + + ACPI_FUNCTION_TRACE ("ns_search_node"); + + +#ifdef ACPI_DEBUG_OUTPUT + if (ACPI_LV_NAMES & acpi_dbg_level) { + char *scope_name; + + scope_name = acpi_ns_get_external_pathname (node); + if (scope_name) { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Searching %s (%p) For [%4.4s] (%s)\n", + scope_name, node, (char *) &target_name, + acpi_ut_get_type_name (type))); + + ACPI_MEM_FREE (scope_name); + } + } +#endif + + /* + * Search for name at this namespace level, which is to say that we + * must search for the name among the children of this object + */ + next_node = node->child; + while (next_node) { + /* Check for match against the name */ + + if (next_node->name.integer == target_name) { + /* Resolve a control method alias if any */ + + if (acpi_ns_get_type (next_node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) { + next_node = ACPI_CAST_PTR (struct acpi_namespace_node, next_node->object); + } + + /* + * Found matching entry. + */ + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n", + (char *) &target_name, acpi_ut_get_type_name (next_node->type), + next_node, acpi_ut_get_node_name (node), node)); + + *return_node = next_node; + return_ACPI_STATUS (AE_OK); + } + + /* + * The last entry in the list points back to the parent, + * so a flag is used to indicate the end-of-list + */ + if (next_node->flags & ANOBJ_END_OF_PEER_LIST) { + /* Searched entire list, we are done */ + + break; + } + + /* Didn't match name, move on to the next peer object */ + + next_node = next_node->peer; + } + + /* Searched entire namespace level, not found */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Name [%4.4s] (%s) not found in search in scope [%4.4s] %p first child %p\n", + (char *) &target_name, acpi_ut_get_type_name (type), + acpi_ut_get_node_name (node), node, node->child)); + + return_ACPI_STATUS (AE_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_search_parent_tree + * + * PARAMETERS: *target_name - Ascii ACPI name to search for + * *Node - Starting node where search will begin + * Type - Object type to match + * **return_node - Where the matched Node is returned + * + * RETURN: Status + * + * DESCRIPTION: Called when a name has not been found in the current namespace + * level. 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) + * + ******************************************************************************/ + +static acpi_status +acpi_ns_search_parent_tree ( + u32 target_name, + struct acpi_namespace_node *node, + acpi_object_type type, + struct acpi_namespace_node **return_node) +{ + acpi_status status; + struct acpi_namespace_node *parent_node; + + + ACPI_FUNCTION_TRACE ("ns_search_parent_tree"); + + + parent_node = acpi_ns_get_parent_node (node); + + /* + * If there is no parent (i.e., we are at the root) or type is "local", + * we won't be searching the parent tree. + */ + if (!parent_node) { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] has no parent\n", + (char *) &target_name)); + return_ACPI_STATUS (AE_NOT_FOUND); + } + + if (acpi_ns_local (type)) { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "[%4.4s] type [%s] must be local to this scope (no parent search)\n", + (char *) &target_name, acpi_ut_get_type_name (type))); + return_ACPI_STATUS (AE_NOT_FOUND); + } + + /* Search the parent tree */ + + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "Searching parent [%4.4s] for [%4.4s]\n", + acpi_ut_get_node_name (parent_node), (char *) &target_name)); + + /* + * Search parents until target is found or we have backed up to the root + */ + while (parent_node) { + /* + * Search parent scope. Use TYPE_ANY because we don't care about the + * object type at this point, we only care about the existence of + * the actual name we are searching for. Typechecking comes later. + */ + status = acpi_ns_search_node (target_name, parent_node, + ACPI_TYPE_ANY, return_node); + if (ACPI_SUCCESS (status)) { + return_ACPI_STATUS (status); + } + + /* + * Not found here, go up another level + * (until we reach the root) + */ + parent_node = acpi_ns_get_parent_node (parent_node); + } + + /* Not found in parent tree */ + + return_ACPI_STATUS (AE_NOT_FOUND); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_search_and_enter + * + * PARAMETERS: target_name - Ascii ACPI name to search for (4 chars) + * walk_state - Current state of the walk + * *Node - Starting node where search will begin + * interpreter_mode - Add names only in ACPI_MODE_LOAD_PASS_x. + * Otherwise,search only. + * Type - Object type to match + * Flags - Flags describing the search restrictions + * **return_node - Where the Node is returned + * + * RETURN: Status + * + * DESCRIPTION: Search for a name segment in a single namespace level, + * 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 ACPI_IMODE_EXECUTE, search only. + * In other modes, search and add if not found. + * + ******************************************************************************/ + +acpi_status +acpi_ns_search_and_enter ( + u32 target_name, + struct acpi_walk_state *walk_state, + struct acpi_namespace_node *node, + acpi_interpreter_mode interpreter_mode, + acpi_object_type type, + u32 flags, + struct acpi_namespace_node **return_node) +{ + acpi_status status; + struct acpi_namespace_node *new_node; + + + ACPI_FUNCTION_TRACE ("ns_search_and_enter"); + + + /* Parameter validation */ + + if (!node || !target_name || !return_node) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Null param: Node %p Name %X return_node %p\n", + node, target_name, return_node)); + + ACPI_REPORT_ERROR (("ns_search_and_enter: Null parameter\n")); + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Name must consist of printable characters */ + + if (!acpi_ut_valid_acpi_name (target_name)) { + ACPI_REPORT_ERROR (("ns_search_and_enter: Bad character in ACPI Name: %X\n", + target_name)); + return_ACPI_STATUS (AE_BAD_CHARACTER); + } + + /* Try to find the name in the namespace level specified by the caller */ + + *return_node = ACPI_ENTRY_NOT_FOUND; + status = acpi_ns_search_node (target_name, node, type, return_node); + if (status != AE_NOT_FOUND) { + /* + * If we found it AND the request specifies that a find is an error, + * return the error + */ + if ((status == AE_OK) && + (flags & ACPI_NS_ERROR_IF_FOUND)) { + status = AE_ALREADY_EXISTS; + } + + /* + * Either found it or there was an error + * -- finished either way + */ + return_ACPI_STATUS (status); + } + + /* + * The name was not found. 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 != ACPI_IMODE_LOAD_PASS1) && + (flags & ACPI_NS_SEARCH_PARENT)) { + /* + * Not found at this level - search parent tree according to the + * ACPI specification + */ + status = acpi_ns_search_parent_tree (target_name, node, type, return_node); + if (ACPI_SUCCESS (status)) { + return_ACPI_STATUS (status); + } + } + + /* + * In execute mode, just search, never add names. Exit now. + */ + if (interpreter_mode == ACPI_IMODE_EXECUTE) { + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "%4.4s Not found in %p [Not adding]\n", + (char *) &target_name, node)); + + return_ACPI_STATUS (AE_NOT_FOUND); + } + + /* Create the new named object */ + + new_node = acpi_ns_create_node (target_name); + if (!new_node) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Install the new object into the parent's list of children */ + + acpi_ns_install_node (walk_state, node, new_node, type); + *return_node = new_node; + + return_ACPI_STATUS (AE_OK); +} + diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c new file mode 100644 index 000000000000..75da76cc0b19 --- /dev/null +++ b/drivers/acpi/namespace/nsutils.c @@ -0,0 +1,1069 @@ +/****************************************************************************** + * + * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing + * parents and siblings and Scope manipulation + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/amlcode.h> +#include <acpi/actables.h> + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsutils") + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_report_error + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * component_id - Caller's component ID (for error output) + * Message - Error message to use on failure + * + * RETURN: None + * + * DESCRIPTION: Print warning message with full pathname + * + ******************************************************************************/ + +void +acpi_ns_report_error ( + char *module_name, + u32 line_number, + u32 component_id, + char *internal_name, + acpi_status lookup_status) +{ + acpi_status status; + char *name = NULL; + + + acpi_os_printf ("%8s-%04d: *** Error: Looking up ", + module_name, line_number); + + if (lookup_status == AE_BAD_CHARACTER) { + /* There is a non-ascii character in the name */ + + acpi_os_printf ("[0x%4.4X] (NON-ASCII)\n", + *(ACPI_CAST_PTR (u32, internal_name))); + } + else { + /* Convert path to external format */ + + status = acpi_ns_externalize_name (ACPI_UINT32_MAX, + internal_name, NULL, &name); + + /* Print target name */ + + if (ACPI_SUCCESS (status)) { + acpi_os_printf ("[%s]", name); + } + else { + acpi_os_printf ("[COULD NOT EXTERNALIZE NAME]"); + } + + if (name) { + ACPI_MEM_FREE (name); + } + } + + acpi_os_printf (" in namespace, %s\n", + acpi_format_exception (lookup_status)); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_report_method_error + * + * PARAMETERS: module_name - Caller's module name (for error output) + * line_number - Caller's line number (for error output) + * component_id - Caller's component ID (for error output) + * Message - Error message to use on failure + * + * RETURN: None + * + * DESCRIPTION: Print warning message with full pathname + * + ******************************************************************************/ + +void +acpi_ns_report_method_error ( + char *module_name, + u32 line_number, + u32 component_id, + char *message, + struct acpi_namespace_node *prefix_node, + char *path, + acpi_status method_status) +{ + acpi_status status; + struct acpi_namespace_node *node = prefix_node; + + + if (path) { + status = acpi_ns_get_node_by_path (path, prefix_node, + ACPI_NS_NO_UPSEARCH, &node); + if (ACPI_FAILURE (status)) { + acpi_os_printf ("report_method_error: Could not get node\n"); + return; + } + } + + acpi_os_printf ("%8s-%04d: *** Error: ", module_name, line_number); + acpi_ns_print_node_pathname (node, message); + acpi_os_printf (", %s\n", acpi_format_exception (method_status)); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_print_node_pathname + * + * PARAMETERS: Node - Object + * Msg - Prefix message + * + * DESCRIPTION: Print an object's full namespace pathname + * Manages allocation/freeing of a pathname buffer + * + ******************************************************************************/ + +void +acpi_ns_print_node_pathname ( + struct acpi_namespace_node *node, + char *msg) +{ + struct acpi_buffer buffer; + acpi_status status; + + + if (!node) { + acpi_os_printf ("[NULL NAME]"); + return; + } + + /* Convert handle to full pathname and print it (with supplied message) */ + + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + + status = acpi_ns_handle_to_pathname (node, &buffer); + if (ACPI_SUCCESS (status)) { + if (msg) { + acpi_os_printf ("%s ", msg); + } + + acpi_os_printf ("[%s] (Node %p)", (char *) buffer.pointer, node); + ACPI_MEM_FREE (buffer.pointer); + } +} + + +/******************************************************************************* + * + * 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 - Parent Node to be examined + * + * RETURN: Type field from Node whose handle is passed + * + ******************************************************************************/ + +acpi_object_type +acpi_ns_get_type ( + struct acpi_namespace_node *node) +{ + ACPI_FUNCTION_TRACE ("ns_get_type"); + + + if (!node) { + ACPI_REPORT_WARNING (("ns_get_type: Null Node input pointer\n")); + return_VALUE (ACPI_TYPE_ANY); + } + + return_VALUE ((acpi_object_type) node->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 + * + ******************************************************************************/ + +u32 +acpi_ns_local ( + acpi_object_type type) +{ + ACPI_FUNCTION_TRACE ("ns_local"); + + + if (!acpi_ut_valid_object_type (type)) { + /* Type code out of range */ + + ACPI_REPORT_WARNING (("ns_local: Invalid Object Type\n")); + return_VALUE (ACPI_NS_NORMAL); + } + + return_VALUE ((u32) acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_internal_name_length + * + * PARAMETERS: Info - Info struct initialized with the + * external name pointer. + * + * RETURN: Status + * + * DESCRIPTION: Calculate the length of the internal (AML) namestring + * corresponding to the external (ASL) namestring. + * + ******************************************************************************/ + +void +acpi_ns_get_internal_name_length ( + struct acpi_namestring_info *info) +{ + char *next_external_char; + u32 i; + + + ACPI_FUNCTION_ENTRY (); + + + next_external_char = info->external_name; + info->num_carats = 0; + info->num_segments = 0; + info->fully_qualified = FALSE; + + /* + * 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 (next_external_char[0])) { + info->fully_qualified = TRUE; + next_external_char++; + } + else { + /* + * Handle Carat prefixes + */ + while (*next_external_char == '^') { + info->num_carats++; + next_external_char++; + } + } + + /* + * 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. + */ + if (*next_external_char) { + info->num_segments = 1; + for (i = 0; next_external_char[i]; i++) { + if (acpi_ns_valid_path_separator (next_external_char[i])) { + info->num_segments++; + } + } + } + + info->length = (ACPI_NAME_SIZE * info->num_segments) + + 4 + info->num_carats; + + info->next_external_char = next_external_char; +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_build_internal_name + * + * PARAMETERS: Info - Info struct fully initialized + * + * RETURN: Status + * + * DESCRIPTION: Construct the internal (AML) namestring + * corresponding to the external (ASL) namestring. + * + ******************************************************************************/ + +acpi_status +acpi_ns_build_internal_name ( + struct acpi_namestring_info *info) +{ + u32 num_segments = info->num_segments; + char *internal_name = info->internal_name; + char *external_name = info->next_external_char; + char *result = NULL; + acpi_native_uint i; + + + ACPI_FUNCTION_TRACE ("ns_build_internal_name"); + + + /* Setup the correct prefixes, counts, and pointers */ + + if (info->fully_qualified) { + internal_name[0] = '\\'; + + if (num_segments <= 1) { + result = &internal_name[1]; + } + else if (num_segments == 2) { + internal_name[1] = AML_DUAL_NAME_PREFIX; + result = &internal_name[2]; + } + else { + internal_name[1] = AML_MULTI_NAME_PREFIX_OP; + internal_name[2] = (char) num_segments; + result = &internal_name[3]; + } + } + else { + /* + * Not fully qualified. + * Handle Carats first, then append the name segments + */ + i = 0; + if (info->num_carats) { + for (i = 0; i < info->num_carats; i++) { + internal_name[i] = '^'; + } + } + + if (num_segments <= 1) { + result = &internal_name[i]; + } + else if (num_segments == 2) { + internal_name[i] = AML_DUAL_NAME_PREFIX; + result = &internal_name[(acpi_native_uint) (i+1)]; + } + else { + internal_name[i] = AML_MULTI_NAME_PREFIX_OP; + internal_name[(acpi_native_uint) (i+1)] = (char) num_segments; + result = &internal_name[(acpi_native_uint) (i+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 the character to uppercase and save it */ + + result[i] = (char) ACPI_TOUPPER ((int) *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)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Move on the next segment */ + + external_name++; + result += ACPI_NAME_SIZE; + } + + /* Terminate the string */ + + *result = 0; + + if (info->fully_qualified) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (abs) \"\\%s\"\n", + internal_name, internal_name)); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (rel) \"%s\"\n", + internal_name, internal_name)); + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * 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 *internal_name; + struct acpi_namestring_info info; + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ns_internalize_name"); + + + if ((!external_name) || + (*external_name == 0) || + (!converted_name)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Get the length of the new internal name */ + + info.external_name = external_name; + acpi_ns_get_internal_name_length (&info); + + /* We need a segment to store the internal name */ + + internal_name = ACPI_MEM_CALLOCATE (info.length); + if (!internal_name) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Build the name */ + + info.internal_name = internal_name; + status = acpi_ns_build_internal_name (&info); + if (ACPI_FAILURE (status)) { + ACPI_MEM_FREE (internal_name); + return_ACPI_STATUS (status); + } + + *converted_name = internal_name; + return_ACPI_STATUS (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) +{ + acpi_native_uint names_index = 0; + acpi_native_uint num_segments = 0; + acpi_native_uint required_length; + acpi_native_uint prefix_length = 0; + acpi_native_uint i = 0; + acpi_native_uint j = 0; + + + ACPI_FUNCTION_TRACE ("ns_externalize_name"); + + + if (!internal_name_length || + !internal_name || + !converted_name) { + return_ACPI_STATUS (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; + } + else { + break; + } + } + + if (i == internal_name_length) { + prefix_length = i; + } + + break; + + default: + 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]) { + case AML_MULTI_NAME_PREFIX_OP: + + /* <count> 4-byte names */ + + names_index = prefix_length + 2; + num_segments = (acpi_native_uint) (u8) + internal_name[(acpi_native_uint) (prefix_length + 1)]; + break; + + case AML_DUAL_NAME_PREFIX: + + /* Two 4-byte names */ + + names_index = prefix_length + 1; + num_segments = 2; + break; + + case 0: + + /* null_name */ + + names_index = 0; + num_segments = 0; + break; + + default: + + /* one 4-byte name */ + + names_index = prefix_length; + num_segments = 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. + */ + required_length = prefix_length + (4 * num_segments) + + ((num_segments > 0) ? (num_segments - 1) : 0) + 1; + + /* + * Check to see if we're still in bounds. If not, there's a problem + * with internal_name (invalid format). + */ + if (required_length > internal_name_length) { + ACPI_REPORT_ERROR (("ns_externalize_name: Invalid internal name\n")); + return_ACPI_STATUS (AE_BAD_PATHNAME); + } + + /* + * Build converted_name + */ + *converted_name = ACPI_MEM_CALLOCATE (required_length); + if (!(*converted_name)) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + j = 0; + + for (i = 0; i < prefix_length; i++) { + (*converted_name)[j++] = internal_name[i]; + } + + if (num_segments > 0) { + for (i = 0; i < num_segments; 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++]; + } + } + + if (converted_name_length) { + *converted_name_length = (u32) required_length; + } + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_map_handle_to_node + * + * PARAMETERS: Handle - Handle to be converted to an Node + * + * RETURN: A Name table entry pointer + * + * DESCRIPTION: Convert a namespace handle to a real Node + * + * Note: Real integer handles allow for more verification + * and keep all pointers within this subsystem. + * + ******************************************************************************/ + +struct acpi_namespace_node * +acpi_ns_map_handle_to_node ( + acpi_handle handle) +{ + + ACPI_FUNCTION_ENTRY (); + + + /* + * Simple implementation. + */ + if (!handle) { + return (NULL); + } + + if (handle == ACPI_ROOT_OBJECT) { + return (acpi_gbl_root_node); + } + + /* We can at least attempt to verify the handle */ + + if (ACPI_GET_DESCRIPTOR_TYPE (handle) != ACPI_DESC_TYPE_NAMED) { + return (NULL); + } + + return ((struct acpi_namespace_node *) handle); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_convert_entry_to_handle + * + * PARAMETERS: Node - Node to be converted to a Handle + * + * RETURN: A user handle + * + * DESCRIPTION: Convert a real Node to a namespace handle + * + ******************************************************************************/ + +acpi_handle +acpi_ns_convert_entry_to_handle ( + struct acpi_namespace_node *node) +{ + + + /* + * Simple implementation for now; + */ + return ((acpi_handle) node); + + +/* --------------------------------------------------- + + if (!Node) + { + return (NULL); + } + + if (Node == acpi_gbl_root_node) + { + return (ACPI_ROOT_OBJECT); + } + + + return ((acpi_handle) Node); +------------------------------------------------------*/ +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_terminate + * + * PARAMETERS: none + * + * RETURN: none + * + * DESCRIPTION: free memory allocated for table storage. + * + ******************************************************************************/ + +void +acpi_ns_terminate (void) +{ + union acpi_operand_object *obj_desc; + + + ACPI_FUNCTION_TRACE ("ns_terminate"); + + + /* + * 1) Free the entire namespace -- all nodes and objects + * + * Delete all object descriptors attached to namepsace nodes + */ + acpi_ns_delete_namespace_subtree (acpi_gbl_root_node); + + /* Detach any objects attached to the root */ + + obj_desc = acpi_ns_get_attached_object (acpi_gbl_root_node); + if (obj_desc) { + acpi_ns_detach_object (acpi_gbl_root_node); + } + + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Namespace freed\n")); + + /* + * 2) Now we can delete the ACPI tables + */ + acpi_tb_delete_all_tables (); + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "ACPI Tables freed\n")); + + return_VOID; +} + + +/******************************************************************************* + * + * 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 + * + ******************************************************************************/ + +u32 +acpi_ns_opens_scope ( + acpi_object_type type) +{ + ACPI_FUNCTION_TRACE_STR ("ns_opens_scope", acpi_ut_get_type_name (type)); + + + if (!acpi_ut_valid_object_type (type)) { + /* type code out of range */ + + ACPI_REPORT_WARNING (("ns_opens_scope: Invalid Object Type %X\n", type)); + return_VALUE (ACPI_NS_NORMAL); + } + + return_VALUE (((u32) acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_node_by_path + * + * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The + * \ (backslash) and ^ (carat) prefixes, and the + * . (period) to separate segments are supported. + * start_node - Root of subtree to be searched, or NS_ALL for the + * root of the name space. If Name is fully + * qualified (first s8 is '\'), the passed value + * of Scope will not be accessed. + * Flags - Used to indicate whether to perform upsearch or + * not. + * return_node - Where the Node is returned + * + * DESCRIPTION: Look up a name relative to a given scope and return the + * corresponding Node. NOTE: Scope can be null. + * + * MUTEX: Locks namespace + * + ******************************************************************************/ + +acpi_status +acpi_ns_get_node_by_path ( + char *pathname, + struct acpi_namespace_node *start_node, + u32 flags, + struct acpi_namespace_node **return_node) +{ + union acpi_generic_state scope_info; + acpi_status status; + char *internal_path = NULL; + + + ACPI_FUNCTION_TRACE_PTR ("ns_get_node_by_path", pathname); + + + if (pathname) { + /* Convert path to internal representation */ + + status = acpi_ns_internalize_name (pathname, &internal_path); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Must lock namespace during lookup */ + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Setup lookup scope (search starting point) */ + + scope_info.scope.node = start_node; + + /* Lookup the name in the namespace */ + + status = acpi_ns_lookup (&scope_info, internal_path, + ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, + (flags | ACPI_NS_DONT_OPEN_SCOPE), + NULL, return_node); + if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s, %s\n", + internal_path, acpi_format_exception (status))); + } + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + +cleanup: + /* Cleanup */ + if (internal_path) { + ACPI_MEM_FREE (internal_path); + } + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_find_parent_name + * + * PARAMETERS: *child_node - Named Obj whose name is to be found + * + * RETURN: The ACPI name + * + * DESCRIPTION: Search for the given obj in its parent scope and return the + * name segment, or "????" if the parent name can't be found + * (which "should not happen"). + * + ******************************************************************************/ +#ifdef ACPI_FUTURE_USAGE +acpi_name +acpi_ns_find_parent_name ( + struct acpi_namespace_node *child_node) +{ + struct acpi_namespace_node *parent_node; + + + ACPI_FUNCTION_TRACE ("ns_find_parent_name"); + + + if (child_node) { + /* Valid entry. Get the parent Node */ + + parent_node = acpi_ns_get_parent_node (child_node); + if (parent_node) { + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Parent of %p [%4.4s] is %p [%4.4s]\n", + child_node, acpi_ut_get_node_name (child_node), + parent_node, acpi_ut_get_node_name (parent_node))); + + if (parent_node->name.integer) { + return_VALUE ((acpi_name) parent_node->name.integer); + } + } + + ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, + "Unable to find parent of %p (%4.4s)\n", + child_node, acpi_ut_get_node_name (child_node))); + } + + return_VALUE (ACPI_UNKNOWN_NAME); +} +#endif + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_parent_node + * + * PARAMETERS: Node - Current table entry + * + * RETURN: Parent entry of the given entry + * + * DESCRIPTION: Obtain the parent entry for a given entry in the namespace. + * + ******************************************************************************/ + + +struct acpi_namespace_node * +acpi_ns_get_parent_node ( + struct acpi_namespace_node *node) +{ + ACPI_FUNCTION_ENTRY (); + + + if (!node) { + return (NULL); + } + + /* + * Walk to the end of this peer list. The last entry is marked with a flag + * and the peer pointer is really a pointer back to the parent. This saves + * putting a parent back pointer in each and every named object! + */ + while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) { + node = node->peer; + } + + + return (node->peer); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_next_valid_node + * + * PARAMETERS: Node - Current table entry + * + * RETURN: Next valid Node in the linked node list. NULL if no more valid + * nodes. + * + * DESCRIPTION: Find the next valid node within a name table. + * Useful for implementing NULL-end-of-list loops. + * + ******************************************************************************/ + + +struct acpi_namespace_node * +acpi_ns_get_next_valid_node ( + struct acpi_namespace_node *node) +{ + + /* If we are at the end of this peer list, return NULL */ + + if (node->flags & ANOBJ_END_OF_PEER_LIST) { + return NULL; + } + + /* Otherwise just return the next peer */ + + return (node->peer); +} + + diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c new file mode 100644 index 000000000000..4de2444df300 --- /dev/null +++ b/drivers/acpi/namespace/nswalk.c @@ -0,0 +1,289 @@ +/****************************************************************************** + * + * Module Name: nswalk - Functions for walking the ACPI namespace + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nswalk") + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_next_node + * + * PARAMETERS: Type - Type of node to be searched for + * parent_node - Parent node whose children we are + * getting + * child_node - Previous child that was found. + * The NEXT child will be returned + * + * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if + * none is found. + * + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node + * within Scope is returned. + * + ******************************************************************************/ + +struct acpi_namespace_node * +acpi_ns_get_next_node ( + acpi_object_type type, + struct acpi_namespace_node *parent_node, + struct acpi_namespace_node *child_node) +{ + struct acpi_namespace_node *next_node = NULL; + + + ACPI_FUNCTION_ENTRY (); + + + if (!child_node) { + /* It's really the parent's _scope_ that we want */ + + if (parent_node->child) { + next_node = parent_node->child; + } + } + + else { + /* Start search at the NEXT node */ + + next_node = acpi_ns_get_next_valid_node (child_node); + } + + /* If any type is OK, we are done */ + + if (type == ACPI_TYPE_ANY) { + /* next_node is NULL if we are at the end-of-list */ + + return (next_node); + } + + /* Must search for the node -- but within this scope only */ + + while (next_node) { + /* If type matches, we are done */ + + if (next_node->type == type) { + return (next_node); + } + + /* Otherwise, move on to the next node */ + + next_node = acpi_ns_get_next_valid_node (next_node); + } + + /* Not found */ + + return (NULL); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_walk_namespace + * + * PARAMETERS: Type - acpi_object_type to search for + * start_node - 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 + * return_value - from the user_function if terminated early. + * Otherwise, returns NULL. + * RETURNS: Status + * + * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, + * starting (and ending) at the node specified by start_handle. + * The user_function is called whenever a node 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 ( + acpi_object_type type, + acpi_handle start_node, + u32 max_depth, + u8 unlock_before_callback, + acpi_walk_callback user_function, + void *context, + void **return_value) +{ + acpi_status status; + acpi_status mutex_status; + struct acpi_namespace_node *child_node; + struct acpi_namespace_node *parent_node; + acpi_object_type child_type; + u32 level; + + + ACPI_FUNCTION_TRACE ("ns_walk_namespace"); + + + /* Special case for the namespace Root Node */ + + if (start_node == ACPI_ROOT_OBJECT) { + start_node = acpi_gbl_root_node; + } + + /* Null child means "get first node" */ + + parent_node = start_node; + child_node = NULL; + child_type = ACPI_TYPE_ANY; + level = 1; + + /* + * Traverse the tree of nodes 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 node in this scope. Null if not found */ + + status = AE_OK; + child_node = acpi_ns_get_next_node (ACPI_TYPE_ANY, parent_node, child_node); + if (child_node) { + /* + * Found node, Get the type if we are not + * searching for ANY + */ + if (type != ACPI_TYPE_ANY) { + child_type = child_node->type; + } + + if (child_type == type) { + /* + * Found a matching node, invoke the user + * callback function + */ + if (unlock_before_callback) { + mutex_status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (mutex_status)) { + return_ACPI_STATUS (mutex_status); + } + } + + status = user_function (child_node, level, + context, return_value); + + if (unlock_before_callback) { + mutex_status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (mutex_status)) { + return_ACPI_STATUS (mutex_status); + } + } + + switch (status) { + case AE_OK: + case AE_CTRL_DEPTH: + + /* Just keep going */ + break; + + case AE_CTRL_TERMINATE: + + /* Exit now, with OK status */ + + return_ACPI_STATUS (AE_OK); + + default: + + /* All others are valid exceptions */ + + return_ACPI_STATUS (status); + } + } + + /* + * 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_node (ACPI_TYPE_ANY, child_node, NULL)) { + /* + * There is at least one child of this + * node, visit the onde + */ + level++; + parent_node = child_node; + child_node = NULL; + } + } + } + else { + /* + * No more children of this node (acpi_ns_get_next_node + * failed), go back upwards in the namespace tree to + * the node's parent. + */ + level--; + child_node = parent_node; + parent_node = acpi_ns_get_parent_node (parent_node); + } + } + + /* Complete walk, not terminated by user function */ + + return_ACPI_STATUS (AE_OK); +} + + diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c new file mode 100644 index 000000000000..1dc995586cbe --- /dev/null +++ b/drivers/acpi/namespace/nsxfeval.c @@ -0,0 +1,764 @@ +/******************************************************************************* + * + * Module Name: nsxfeval - Public interfaces to the ACPI subsystem + * ACPI Object evaluation interfaces + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <linux/module.h> + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> +#include <acpi/acinterp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsxfeval") + + +/******************************************************************************* + * + * FUNCTION: acpi_evaluate_object_typed + * + * PARAMETERS: Handle - Object handle (optional) + * *Pathname - Object pathname (optional) + * **external_params - List of parameters to pass to method, + * terminated by NULL. May be NULL + * if no parameters are being passed. + * *return_buffer - Where to put method's return value (if + * any). If NULL, no value is returned. + * return_type - Expected type of return object + * + * 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) + * + ******************************************************************************/ +#ifdef ACPI_FUTURE_USAGE +acpi_status +acpi_evaluate_object_typed ( + acpi_handle handle, + acpi_string pathname, + struct acpi_object_list *external_params, + struct acpi_buffer *return_buffer, + acpi_object_type return_type) +{ + acpi_status status; + u8 must_free = FALSE; + + + ACPI_FUNCTION_TRACE ("acpi_evaluate_object_typed"); + + + /* Return buffer must be valid */ + + if (!return_buffer) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + if (return_buffer->length == ACPI_ALLOCATE_BUFFER) { + must_free = TRUE; + } + + /* Evaluate the object */ + + status = acpi_evaluate_object (handle, pathname, external_params, return_buffer); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Type ANY means "don't care" */ + + if (return_type == ACPI_TYPE_ANY) { + return_ACPI_STATUS (AE_OK); + } + + if (return_buffer->length == 0) { + /* Error because caller specifically asked for a return value */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "No return value\n")); + + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + /* Examine the object type returned from evaluate_object */ + + if (((union acpi_object *) return_buffer->pointer)->type == return_type) { + return_ACPI_STATUS (AE_OK); + } + + /* Return object type does not match requested type */ + + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Incorrect return type [%s] requested [%s]\n", + acpi_ut_get_type_name (((union acpi_object *) return_buffer->pointer)->type), + acpi_ut_get_type_name (return_type))); + + if (must_free) { + /* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */ + + acpi_os_free (return_buffer->pointer); + return_buffer->pointer = NULL; + } + + return_buffer->length = 0; + return_ACPI_STATUS (AE_TYPE); +} +#endif /* ACPI_FUTURE_USAGE */ + + +/******************************************************************************* + * + * FUNCTION: acpi_evaluate_object + * + * PARAMETERS: Handle - Object handle (optional) + * Pathname - Object pathname (optional) + * external_params - List of parameters to pass to method, + * terminated by NULL. May be NULL + * if no parameters are being passed. + * return_buffer - 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, + struct acpi_object_list *external_params, + struct acpi_buffer *return_buffer) +{ + acpi_status status; + acpi_status status2; + struct acpi_parameter_info info; + acpi_size buffer_space_needed; + u32 i; + + + ACPI_FUNCTION_TRACE ("acpi_evaluate_object"); + + + info.node = handle; + info.parameters = NULL; + info.return_object = NULL; + info.parameter_type = ACPI_PARAM_ARGS; + + /* + * 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 (external_params && external_params->count) { + /* + * Allocate a new parameter block for the internal objects + * Add 1 to count to allow for null terminated internal list + */ + info.parameters = ACPI_MEM_CALLOCATE ( + ((acpi_size) external_params->count + 1) * + sizeof (void *)); + if (!info.parameters) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* + * Convert each external object in the list to an + * internal object + */ + for (i = 0; i < external_params->count; i++) { + status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i], + &info.parameters[i]); + if (ACPI_FAILURE (status)) { + acpi_ut_delete_internal_object_list (info.parameters); + return_ACPI_STATUS (status); + } + } + info.parameters[external_params->count] = NULL; + } + + + /* + * 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, &info); + } + 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 + */ + if (!pathname) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Both Handle and Pathname are NULL\n")); + } + else { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Handle is NULL and Pathname is relative\n")); + } + + 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 (&info); + } + else { + /* + * Both a Handle and a relative Pathname + */ + status = acpi_ns_evaluate_relative (pathname, &info); + } + } + + + /* + * If we are expecting a return value, and all went well above, + * copy the return value to an external object. + */ + if (return_buffer) { + if (!info.return_object) { + return_buffer->length = 0; + } + else { + if (ACPI_GET_DESCRIPTOR_TYPE (info.return_object) == ACPI_DESC_TYPE_NAMED) { + /* + * If we received a NS Node as a return object, this means that + * 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; + info.return_object = NULL; /* No need to delete a NS Node */ + return_buffer->length = 0; + } + + if (ACPI_SUCCESS (status)) { + /* + * Find out how large a buffer is needed + * to contain the returned object + */ + status = acpi_ut_get_object_size (info.return_object, + &buffer_space_needed); + if (ACPI_SUCCESS (status)) { + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed); + if (ACPI_FAILURE (status)) { + /* + * Caller's buffer is too small or a new one can't be allocated + */ + ACPI_DEBUG_PRINT ((ACPI_DB_INFO, + "Needed buffer size %X, %s\n", + (u32) buffer_space_needed, + acpi_format_exception (status))); + } + else { + /* + * We have enough space for the object, build it + */ + status = acpi_ut_copy_iobject_to_eobject (info.return_object, + return_buffer); + } + } + } + } + } + + if (info.return_object) { + /* + * Delete the internal return object. NOTE: Interpreter + * must be locked to avoid race condition. + */ + status2 = acpi_ex_enter_interpreter (); + if (ACPI_SUCCESS (status2)) { + /* + * Delete the internal return object. (Or at least + * decrement the reference count by one) + */ + acpi_ut_remove_reference (info.return_object); + acpi_ex_exit_interpreter (); + } + } + + /* + * Free the input parameter list (if we created one), + */ + if (info.parameters) { + /* Free the allocated parameter block */ + + acpi_ut_delete_internal_object_list (info.parameters); + } + + return_ACPI_STATUS (status); +} +EXPORT_SYMBOL(acpi_evaluate_object); + + +/******************************************************************************* + * + * 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 + * return_value - Location where return value of + * user_function is put if terminated early + * + * 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, + acpi_walk_callback user_function, + void *context, + void **return_value) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("acpi_walk_namespace"); + + + /* Parameter validation */ + + if ((type > ACPI_TYPE_EXTERNAL_MAX) || + (!max_depth) || + (!user_function)) { + return_ACPI_STATUS (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. + */ + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ns_walk_namespace (type, start_object, max_depth, ACPI_NS_WALK_UNLOCK, + user_function, context, return_value); + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); +} +EXPORT_SYMBOL(acpi_walk_namespace); + + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_device_callback + * + * PARAMETERS: Callback from acpi_get_device + * + * RETURN: Status + * + * DESCRIPTION: Takes callbacks from walk_namespace and filters out all non- + * present devices, or if they specified a HID, it filters based + * on that. + * + ******************************************************************************/ + +static acpi_status +acpi_ns_get_device_callback ( + acpi_handle obj_handle, + u32 nesting_level, + void *context, + void **return_value) +{ + struct acpi_get_devices_info *info = context; + acpi_status status; + struct acpi_namespace_node *node; + u32 flags; + struct acpi_device_id hid; + struct acpi_compatible_id_list *cid; + acpi_native_uint i; + + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + node = acpi_ns_map_handle_to_node (obj_handle); + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + if (!node) { + return (AE_BAD_PARAMETER); + } + + /* Run _STA to determine if device is present */ + + status = acpi_ut_execute_STA (node, &flags); + if (ACPI_FAILURE (status)) { + return (AE_CTRL_DEPTH); + } + + if (!(flags & 0x01)) { + /* Don't return at the device or children of the device if not there */ + + return (AE_CTRL_DEPTH); + } + + /* Filter based on device HID & CID */ + + if (info->hid != NULL) { + status = acpi_ut_execute_HID (node, &hid); + if (status == AE_NOT_FOUND) { + return (AE_OK); + } + else if (ACPI_FAILURE (status)) { + return (AE_CTRL_DEPTH); + } + + if (ACPI_STRNCMP (hid.value, info->hid, sizeof (hid.value)) != 0) { + /* Get the list of Compatible IDs */ + + status = acpi_ut_execute_CID (node, &cid); + if (status == AE_NOT_FOUND) { + return (AE_OK); + } + else if (ACPI_FAILURE (status)) { + return (AE_CTRL_DEPTH); + } + + /* Walk the CID list */ + + for (i = 0; i < cid->count; i++) { + if (ACPI_STRNCMP (cid->id[i].value, info->hid, + sizeof (struct acpi_compatible_id)) != 0) { + ACPI_MEM_FREE (cid); + return (AE_OK); + } + } + ACPI_MEM_FREE (cid); + } + } + + status = info->user_function (obj_handle, nesting_level, info->context, return_value); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_get_devices + * + * PARAMETERS: HID - HID to search for. Can be NULL. + * user_function - Called when a matching object is found + * Context - Passed to user function + * return_value - Location where return value of + * user_function is put if terminated early + * + * 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 of type + * Device is found. If the user function returns + * a non-zero value, the search is terminated immediately and this + * value is returned to the caller. + * + * This is a wrapper for walk_namespace, but the callback performs + * additional filtering. Please see acpi_get_device_callback. + * + ******************************************************************************/ + +acpi_status +acpi_get_devices ( + char *HID, + acpi_walk_callback user_function, + void *context, + void **return_value) +{ + acpi_status status; + struct acpi_get_devices_info info; + + + ACPI_FUNCTION_TRACE ("acpi_get_devices"); + + + /* Parameter validation */ + + if (!user_function) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* + * We're going to call their callback from OUR callback, so we need + * to know what it is, and their context parameter. + */ + info.context = context; + info.user_function = user_function; + info.hid = HID; + + /* + * 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. + */ + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, + ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, + ACPI_NS_WALK_UNLOCK, + acpi_ns_get_device_callback, &info, + return_value); + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); +} +EXPORT_SYMBOL(acpi_get_devices); + + +/******************************************************************************* + * + * FUNCTION: acpi_attach_data + * + * PARAMETERS: obj_handle - Namespace node + * Handler - Handler for this attachment + * Data - Pointer to data to be attached + * + * RETURN: Status + * + * DESCRIPTION: Attach arbitrary data and handler to a namespace node. + * + ******************************************************************************/ + +acpi_status +acpi_attach_data ( + acpi_handle obj_handle, + acpi_object_handler handler, + void *data) +{ + struct acpi_namespace_node *node; + acpi_status status; + + + /* Parameter validation */ + + if (!obj_handle || + !handler || + !data) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ns_attach_data (node, handler, data); + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_detach_data + * + * PARAMETERS: obj_handle - Namespace node handle + * Handler - Handler used in call to acpi_attach_data + * + * RETURN: Status + * + * DESCRIPTION: Remove data that was previously attached to a node. + * + ******************************************************************************/ + +acpi_status +acpi_detach_data ( + acpi_handle obj_handle, + acpi_object_handler handler) +{ + struct acpi_namespace_node *node; + acpi_status status; + + + /* Parameter validation */ + + if (!obj_handle || + !handler) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ns_detach_data (node, handler); + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_get_data + * + * PARAMETERS: obj_handle - Namespace node + * Handler - Handler used in call to attach_data + * Data - Where the data is returned + * + * RETURN: Status + * + * DESCRIPTION: Retrieve data that was previously attached to a namespace node. + * + ******************************************************************************/ + +acpi_status +acpi_get_data ( + acpi_handle obj_handle, + acpi_object_handler handler, + void **data) +{ + struct acpi_namespace_node *node; + acpi_status status; + + + /* Parameter validation */ + + if (!obj_handle || + !handler || + !data) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (obj_handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + status = acpi_ns_get_attached_data (node, handler, data); + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} + + diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c new file mode 100644 index 000000000000..f2405efd1b9a --- /dev/null +++ b/drivers/acpi/namespace/nsxfname.c @@ -0,0 +1,369 @@ +/****************************************************************************** + * + * Module Name: nsxfname - Public interfaces to the ACPI subsystem + * ACPI Namespace oriented interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <linux/module.h> + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsxfname") + + +/****************************************************************************** + * + * 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; + struct acpi_namespace_node *node = NULL; + struct acpi_namespace_node *prefix_node = NULL; + + + ACPI_FUNCTION_ENTRY (); + + + /* Parameter Validation */ + + if (!ret_handle || !pathname) { + return (AE_BAD_PARAMETER); + } + + /* Convert a parent handle to a prefix node */ + + if (parent) { + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + prefix_node = acpi_ns_map_handle_to_node (parent); + if (!prefix_node) { + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + } + + /* Special case for root, since we can't search for it */ + + if (ACPI_STRCMP (pathname, ACPI_NS_ROOT_PATH) == 0) { + *ret_handle = acpi_ns_convert_entry_to_handle (acpi_gbl_root_node); + return (AE_OK); + } + + /* + * Find the Node and convert to a handle + */ + status = acpi_ns_get_node_by_path (pathname, prefix_node, ACPI_NS_NO_UPSEARCH, + &node); + + *ret_handle = NULL; + if (ACPI_SUCCESS (status)) { + *ret_handle = acpi_ns_convert_entry_to_handle (node); + } + + return (status); +} +EXPORT_SYMBOL(acpi_get_handle); + + +/****************************************************************************** + * + * FUNCTION: acpi_get_name + * + * PARAMETERS: Handle - Handle to be converted to a pathname + * name_type - Full pathname or single segment + * Buffer - 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, + struct acpi_buffer *buffer) +{ + acpi_status status; + struct acpi_namespace_node *node; + + + /* Parameter validation */ + + if (name_type > ACPI_NAME_TYPE_MAX) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_validate_buffer (buffer); + if (ACPI_FAILURE (status)) { + return (status); + } + + if (name_type == ACPI_FULL_PATHNAME) { + /* Get the full pathname (From the namespace root) */ + + status = acpi_ns_handle_to_pathname (handle, buffer); + return (status); + } + + /* + * Wants the single segment ACPI name. + * Validate handle and convert to a namespace Node + */ + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + node = acpi_ns_map_handle_to_node (handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer (buffer, ACPI_PATH_SEGMENT_LENGTH); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + + /* Just copy the ACPI name from the Node and zero terminate it */ + + ACPI_STRNCPY (buffer->pointer, acpi_ut_get_node_name (node), + ACPI_NAME_SIZE); + ((char *) buffer->pointer) [ACPI_NAME_SIZE] = 0; + status = AE_OK; + + +unlock_and_exit: + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} +EXPORT_SYMBOL(acpi_get_name); + + +/****************************************************************************** + * + * 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 the + * namespace node and possibly by running several standard + * control methods (Such as in the case of a device.) + * + ******************************************************************************/ + +acpi_status +acpi_get_object_info ( + acpi_handle handle, + struct acpi_buffer *buffer) +{ + acpi_status status; + struct acpi_namespace_node *node; + struct acpi_device_info *info; + struct acpi_device_info *return_info; + struct acpi_compatible_id_list *cid_list = NULL; + acpi_size size; + + + /* Parameter validation */ + + if (!handle || !buffer) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_validate_buffer (buffer); + if (ACPI_FAILURE (status)) { + return (status); + } + + info = ACPI_MEM_CALLOCATE (sizeof (struct acpi_device_info)); + if (!info) { + return (AE_NO_MEMORY); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + node = acpi_ns_map_handle_to_node (handle); + if (!node) { + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + goto cleanup; + } + + /* Init return structure */ + + size = sizeof (struct acpi_device_info); + + info->type = node->type; + info->name = node->name.integer; + info->valid = 0; + + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* If not a device, we are all done */ + + if (info->type == ACPI_TYPE_DEVICE) { + /* + * Get extra info for ACPI Devices objects only: + * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods. + * + * Note: none of these methods are required, so they may or may + * not be present for this device. The Info->Valid bitfield is used + * to indicate which methods were found and ran successfully. + */ + + /* Execute the Device._HID method */ + + status = acpi_ut_execute_HID (node, &info->hardware_id); + if (ACPI_SUCCESS (status)) { + info->valid |= ACPI_VALID_HID; + } + + /* Execute the Device._UID method */ + + status = acpi_ut_execute_UID (node, &info->unique_id); + if (ACPI_SUCCESS (status)) { + info->valid |= ACPI_VALID_UID; + } + + /* Execute the Device._CID method */ + + status = acpi_ut_execute_CID (node, &cid_list); + if (ACPI_SUCCESS (status)) { + size += ((acpi_size) cid_list->count - 1) * + sizeof (struct acpi_compatible_id); + info->valid |= ACPI_VALID_CID; + } + + /* Execute the Device._STA method */ + + status = acpi_ut_execute_STA (node, &info->current_status); + if (ACPI_SUCCESS (status)) { + info->valid |= ACPI_VALID_STA; + } + + /* Execute the Device._ADR method */ + + status = acpi_ut_evaluate_numeric_object (METHOD_NAME__ADR, node, + &info->address); + if (ACPI_SUCCESS (status)) { + info->valid |= ACPI_VALID_ADR; + } + + /* Execute the Device._sx_d methods */ + + status = acpi_ut_execute_sxds (node, info->highest_dstates); + if (ACPI_SUCCESS (status)) { + info->valid |= ACPI_VALID_SXDS; + } + } + + /* Validate/Allocate/Clear caller buffer */ + + status = acpi_ut_initialize_buffer (buffer, size); + if (ACPI_FAILURE (status)) { + goto cleanup; + } + + /* Populate the return buffer */ + + return_info = buffer->pointer; + ACPI_MEMCPY (return_info, info, sizeof (struct acpi_device_info)); + + if (cid_list) { + ACPI_MEMCPY (&return_info->compatibility_id, cid_list, cid_list->size); + } + + +cleanup: + ACPI_MEM_FREE (info); + if (cid_list) { + ACPI_MEM_FREE (cid_list); + } + return (status); +} +EXPORT_SYMBOL(acpi_get_object_info); + diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c new file mode 100644 index 000000000000..19acf32674b9 --- /dev/null +++ b/drivers/acpi/namespace/nsxfobj.c @@ -0,0 +1,262 @@ +/******************************************************************************* + * + * Module Name: nsxfobj - Public interfaces to the ACPI subsystem + * ACPI Object oriented interfaces + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2005, R. Byron Moore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <linux/module.h> + +#include <acpi/acpi.h> +#include <acpi/acnamesp.h> + + +#define _COMPONENT ACPI_NAMESPACE + ACPI_MODULE_NAME ("nsxfobj") + +/******************************************************************************* + * + * 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) +{ + struct acpi_namespace_node *node; + acpi_status status; + + + /* Parameter Validation */ + + if (!ret_type) { + return (AE_BAD_PARAMETER); + } + + /* + * Special case for the predefined Root Node + * (return type ANY) + */ + if (handle == ACPI_ROOT_OBJECT) { + *ret_type = ACPI_TYPE_ANY; + return (AE_OK); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (handle); + if (!node) { + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (AE_BAD_PARAMETER); + } + + *ret_type = node->type; + + + status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} +EXPORT_SYMBOL(acpi_get_type); + + +/******************************************************************************* + * + * 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) +{ + struct acpi_namespace_node *node; + acpi_status status; + + + if (!ret_handle) { + return (AE_BAD_PARAMETER); + } + + /* Special case for the predefined Root Node (no parent) */ + + if (handle == ACPI_ROOT_OBJECT) { + return (AE_NULL_ENTRY); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* Convert and validate the handle */ + + node = acpi_ns_map_handle_to_node (handle); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Get the parent entry */ + + *ret_handle = + acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_node (node)); + + /* Return exception if parent is null */ + + if (!acpi_ns_get_parent_node (node)) { + status = AE_NULL_ENTRY; + } + + +unlock_and_exit: + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} +EXPORT_SYMBOL(acpi_get_parent); + + +/******************************************************************************* + * + * 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; + struct acpi_namespace_node *node; + struct acpi_namespace_node *parent_node = NULL; + struct acpi_namespace_node *child_node = NULL; + + + /* Parameter validation */ + + if (type > ACPI_TYPE_EXTERNAL_MAX) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + /* If null handle, use the parent */ + + if (!child) { + /* Start search at the beginning of the specified scope */ + + parent_node = acpi_ns_map_handle_to_node (parent); + if (!parent_node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + } + else { + /* Non-null handle, ignore the parent */ + /* Convert and validate the handle */ + + child_node = acpi_ns_map_handle_to_node (child); + if (!child_node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + } + + /* Internal function does the real work */ + + node = acpi_ns_get_next_node (type, parent_node, child_node); + if (!node) { + status = AE_NOT_FOUND; + goto unlock_and_exit; + } + + if (ret_handle) { + *ret_handle = acpi_ns_convert_entry_to_handle (node); + } + + +unlock_and_exit: + + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return (status); +} +EXPORT_SYMBOL(acpi_get_next_object); + |