162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing 562306a36Sopenharmony_ci * parents and siblings and Scope manipulation 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci *****************************************************************************/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <acpi/acpi.h> 1262306a36Sopenharmony_ci#include "accommon.h" 1362306a36Sopenharmony_ci#include "acnamesp.h" 1462306a36Sopenharmony_ci#include "amlcode.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define _COMPONENT ACPI_NAMESPACE 1762306a36Sopenharmony_ciACPI_MODULE_NAME("nsutils") 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* Local prototypes */ 2062306a36Sopenharmony_ci#ifdef ACPI_OBSOLETE_FUNCTIONS 2162306a36Sopenharmony_ciacpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search); 2262306a36Sopenharmony_ci#endif 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/******************************************************************************* 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * FUNCTION: acpi_ns_print_node_pathname 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * PARAMETERS: node - Object 2962306a36Sopenharmony_ci * message - Prefix message 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * DESCRIPTION: Print an object's full namespace pathname 3262306a36Sopenharmony_ci * Manages allocation/freeing of a pathname buffer 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci ******************************************************************************/ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_civoid 3762306a36Sopenharmony_ciacpi_ns_print_node_pathname(struct acpi_namespace_node *node, 3862306a36Sopenharmony_ci const char *message) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct acpi_buffer buffer; 4162306a36Sopenharmony_ci acpi_status status; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!node) { 4462306a36Sopenharmony_ci acpi_os_printf("[NULL NAME]"); 4562306a36Sopenharmony_ci return; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Convert handle to full pathname and print it (with supplied message) */ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci status = acpi_ns_handle_to_pathname(node, &buffer, TRUE); 5362306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 5462306a36Sopenharmony_ci if (message) { 5562306a36Sopenharmony_ci acpi_os_printf("%s ", message); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci acpi_os_printf("%s", (char *)buffer.pointer); 5962306a36Sopenharmony_ci ACPI_FREE(buffer.pointer); 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/******************************************************************************* 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * FUNCTION: acpi_ns_get_type 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * PARAMETERS: node - Parent Node to be examined 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * RETURN: Type field from Node whose handle is passed 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * DESCRIPTION: Return the type of a Namespace node 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci ******************************************************************************/ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciacpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_get_type); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!node) { 8062306a36Sopenharmony_ci ACPI_WARNING((AE_INFO, "Null Node parameter")); 8162306a36Sopenharmony_ci return_UINT8(ACPI_TYPE_ANY); 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return_UINT8(node->type); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/******************************************************************************* 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * FUNCTION: acpi_ns_local 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * PARAMETERS: type - A namespace object type 9262306a36Sopenharmony_ci * 9362306a36Sopenharmony_ci * RETURN: LOCAL if names must be found locally in objects of the 9462306a36Sopenharmony_ci * passed type, 0 if enclosing scopes should be searched 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * DESCRIPTION: Returns scope rule for the given object type. 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci ******************************************************************************/ 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciu32 acpi_ns_local(acpi_object_type type) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_local); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (!acpi_ut_valid_object_type(type)) { 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* Type code out of range */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type)); 10962306a36Sopenharmony_ci return_UINT32(ACPI_NS_NORMAL); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return_UINT32(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/******************************************************************************* 11662306a36Sopenharmony_ci * 11762306a36Sopenharmony_ci * FUNCTION: acpi_ns_get_internal_name_length 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * PARAMETERS: info - Info struct initialized with the 12062306a36Sopenharmony_ci * external name pointer. 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * RETURN: None 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * DESCRIPTION: Calculate the length of the internal (AML) namestring 12562306a36Sopenharmony_ci * corresponding to the external (ASL) namestring. 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci ******************************************************************************/ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_civoid acpi_ns_get_internal_name_length(struct acpi_namestring_info *info) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci const char *next_external_char; 13262306a36Sopenharmony_ci u32 i; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ACPI_FUNCTION_ENTRY(); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci next_external_char = info->external_name; 13762306a36Sopenharmony_ci info->num_carats = 0; 13862306a36Sopenharmony_ci info->num_segments = 0; 13962306a36Sopenharmony_ci info->fully_qualified = FALSE; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * For the internal name, the required length is 4 bytes per segment, 14362306a36Sopenharmony_ci * plus 1 each for root_prefix, multi_name_prefix_op, segment count, 14462306a36Sopenharmony_ci * trailing null (which is not really needed, but no there's harm in 14562306a36Sopenharmony_ci * putting it there) 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci * strlen() + 1 covers the first name_seg, which has no path separator 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci if (ACPI_IS_ROOT_PREFIX(*next_external_char)) { 15062306a36Sopenharmony_ci info->fully_qualified = TRUE; 15162306a36Sopenharmony_ci next_external_char++; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */ 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci while (ACPI_IS_ROOT_PREFIX(*next_external_char)) { 15662306a36Sopenharmony_ci next_external_char++; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci /* Handle Carat prefixes */ 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci while (ACPI_IS_PARENT_PREFIX(*next_external_char)) { 16262306a36Sopenharmony_ci info->num_carats++; 16362306a36Sopenharmony_ci next_external_char++; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * Determine the number of ACPI name "segments" by counting the number of 16962306a36Sopenharmony_ci * path separators within the string. Start with one segment since the 17062306a36Sopenharmony_ci * segment count is [(# separators) + 1], and zero separators is ok. 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci if (*next_external_char) { 17362306a36Sopenharmony_ci info->num_segments = 1; 17462306a36Sopenharmony_ci for (i = 0; next_external_char[i]; i++) { 17562306a36Sopenharmony_ci if (ACPI_IS_PATH_SEPARATOR(next_external_char[i])) { 17662306a36Sopenharmony_ci info->num_segments++; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci info->length = (ACPI_NAMESEG_SIZE * info->num_segments) + 18262306a36Sopenharmony_ci 4 + info->num_carats; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci info->next_external_char = next_external_char; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/******************************************************************************* 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * FUNCTION: acpi_ns_build_internal_name 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * PARAMETERS: info - Info struct fully initialized 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * RETURN: Status 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * DESCRIPTION: Construct the internal (AML) namestring 19662306a36Sopenharmony_ci * corresponding to the external (ASL) namestring. 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci ******************************************************************************/ 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ciacpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci u32 num_segments = info->num_segments; 20362306a36Sopenharmony_ci char *internal_name = info->internal_name; 20462306a36Sopenharmony_ci const char *external_name = info->next_external_char; 20562306a36Sopenharmony_ci char *result = NULL; 20662306a36Sopenharmony_ci u32 i; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_build_internal_name); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* Setup the correct prefixes, counts, and pointers */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (info->fully_qualified) { 21362306a36Sopenharmony_ci internal_name[0] = AML_ROOT_PREFIX; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (num_segments <= 1) { 21662306a36Sopenharmony_ci result = &internal_name[1]; 21762306a36Sopenharmony_ci } else if (num_segments == 2) { 21862306a36Sopenharmony_ci internal_name[1] = AML_DUAL_NAME_PREFIX; 21962306a36Sopenharmony_ci result = &internal_name[2]; 22062306a36Sopenharmony_ci } else { 22162306a36Sopenharmony_ci internal_name[1] = AML_MULTI_NAME_PREFIX; 22262306a36Sopenharmony_ci internal_name[2] = (char)num_segments; 22362306a36Sopenharmony_ci result = &internal_name[3]; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } else { 22662306a36Sopenharmony_ci /* 22762306a36Sopenharmony_ci * Not fully qualified. 22862306a36Sopenharmony_ci * Handle Carats first, then append the name segments 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci i = 0; 23162306a36Sopenharmony_ci if (info->num_carats) { 23262306a36Sopenharmony_ci for (i = 0; i < info->num_carats; i++) { 23362306a36Sopenharmony_ci internal_name[i] = AML_PARENT_PREFIX; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (num_segments <= 1) { 23862306a36Sopenharmony_ci result = &internal_name[i]; 23962306a36Sopenharmony_ci } else if (num_segments == 2) { 24062306a36Sopenharmony_ci internal_name[i] = AML_DUAL_NAME_PREFIX; 24162306a36Sopenharmony_ci result = &internal_name[(acpi_size)i + 1]; 24262306a36Sopenharmony_ci } else { 24362306a36Sopenharmony_ci internal_name[i] = AML_MULTI_NAME_PREFIX; 24462306a36Sopenharmony_ci internal_name[(acpi_size)i + 1] = (char)num_segments; 24562306a36Sopenharmony_ci result = &internal_name[(acpi_size)i + 2]; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* Build the name (minus path separators) */ 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci for (; num_segments; num_segments--) { 25262306a36Sopenharmony_ci for (i = 0; i < ACPI_NAMESEG_SIZE; i++) { 25362306a36Sopenharmony_ci if (ACPI_IS_PATH_SEPARATOR(*external_name) || 25462306a36Sopenharmony_ci (*external_name == 0)) { 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci /* Pad the segment with underscore(s) if segment is short */ 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci result[i] = '_'; 25962306a36Sopenharmony_ci } else { 26062306a36Sopenharmony_ci /* Convert the character to uppercase and save it */ 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci result[i] = (char)toupper((int)*external_name); 26362306a36Sopenharmony_ci external_name++; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* Now we must have a path separator, or the pathname is bad */ 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (!ACPI_IS_PATH_SEPARATOR(*external_name) && 27062306a36Sopenharmony_ci (*external_name != 0)) { 27162306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PATHNAME); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Move on the next segment */ 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci external_name++; 27762306a36Sopenharmony_ci result += ACPI_NAMESEG_SIZE; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* Terminate the string */ 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci *result = 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (info->fully_qualified) { 28562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 28662306a36Sopenharmony_ci "Returning [%p] (abs) \"\\%s\"\n", 28762306a36Sopenharmony_ci internal_name, internal_name)); 28862306a36Sopenharmony_ci } else { 28962306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Returning [%p] (rel) \"%s\"\n", 29062306a36Sopenharmony_ci internal_name, internal_name)); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci/******************************************************************************* 29762306a36Sopenharmony_ci * 29862306a36Sopenharmony_ci * FUNCTION: acpi_ns_internalize_name 29962306a36Sopenharmony_ci * 30062306a36Sopenharmony_ci * PARAMETERS: *external_name - External representation of name 30162306a36Sopenharmony_ci * **Converted name - Where to return the resulting 30262306a36Sopenharmony_ci * internal represention of the name 30362306a36Sopenharmony_ci * 30462306a36Sopenharmony_ci * RETURN: Status 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0") 30762306a36Sopenharmony_ci * to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci *******************************************************************************/ 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ciacpi_status 31262306a36Sopenharmony_ciacpi_ns_internalize_name(const char *external_name, char **converted_name) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci char *internal_name; 31562306a36Sopenharmony_ci struct acpi_namestring_info info; 31662306a36Sopenharmony_ci acpi_status status; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_internalize_name); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if ((!external_name) || (*external_name == 0) || (!converted_name)) { 32162306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* Get the length of the new internal name */ 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci info.external_name = external_name; 32762306a36Sopenharmony_ci acpi_ns_get_internal_name_length(&info); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* We need a segment to store the internal name */ 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci internal_name = ACPI_ALLOCATE_ZEROED(info.length); 33262306a36Sopenharmony_ci if (!internal_name) { 33362306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Build the name */ 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci info.internal_name = internal_name; 33962306a36Sopenharmony_ci status = acpi_ns_build_internal_name(&info); 34062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 34162306a36Sopenharmony_ci ACPI_FREE(internal_name); 34262306a36Sopenharmony_ci return_ACPI_STATUS(status); 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci *converted_name = internal_name; 34662306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/******************************************************************************* 35062306a36Sopenharmony_ci * 35162306a36Sopenharmony_ci * FUNCTION: acpi_ns_externalize_name 35262306a36Sopenharmony_ci * 35362306a36Sopenharmony_ci * PARAMETERS: internal_name_length - Length of the internal name below 35462306a36Sopenharmony_ci * internal_name - Internal representation of name 35562306a36Sopenharmony_ci * converted_name_length - Where the length is returned 35662306a36Sopenharmony_ci * converted_name - Where the resulting external name 35762306a36Sopenharmony_ci * is returned 35862306a36Sopenharmony_ci * 35962306a36Sopenharmony_ci * RETURN: Status 36062306a36Sopenharmony_ci * 36162306a36Sopenharmony_ci * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30) 36262306a36Sopenharmony_ci * to its external (printable) form (e.g. "\_PR_.CPU0") 36362306a36Sopenharmony_ci * 36462306a36Sopenharmony_ci ******************************************************************************/ 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ciacpi_status 36762306a36Sopenharmony_ciacpi_ns_externalize_name(u32 internal_name_length, 36862306a36Sopenharmony_ci const char *internal_name, 36962306a36Sopenharmony_ci u32 * converted_name_length, char **converted_name) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci u32 names_index = 0; 37262306a36Sopenharmony_ci u32 num_segments = 0; 37362306a36Sopenharmony_ci u32 required_length; 37462306a36Sopenharmony_ci u32 prefix_length = 0; 37562306a36Sopenharmony_ci u32 i = 0; 37662306a36Sopenharmony_ci u32 j = 0; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_externalize_name); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (!internal_name_length || !internal_name || !converted_name) { 38162306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PARAMETER); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Check for a prefix (one '\' | one or more '^') */ 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci switch (internal_name[0]) { 38762306a36Sopenharmony_ci case AML_ROOT_PREFIX: 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci prefix_length = 1; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci case AML_PARENT_PREFIX: 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci for (i = 0; i < internal_name_length; i++) { 39562306a36Sopenharmony_ci if (ACPI_IS_PARENT_PREFIX(internal_name[i])) { 39662306a36Sopenharmony_ci prefix_length = i + 1; 39762306a36Sopenharmony_ci } else { 39862306a36Sopenharmony_ci break; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (i == internal_name_length) { 40362306a36Sopenharmony_ci prefix_length = i; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci default: 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* 41462306a36Sopenharmony_ci * Check for object names. Note that there could be 0-255 of these 41562306a36Sopenharmony_ci * 4-byte elements. 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci if (prefix_length < internal_name_length) { 41862306a36Sopenharmony_ci switch (internal_name[prefix_length]) { 41962306a36Sopenharmony_ci case AML_MULTI_NAME_PREFIX: 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* <count> 4-byte names */ 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci names_index = prefix_length + 2; 42462306a36Sopenharmony_ci num_segments = (u8) 42562306a36Sopenharmony_ci internal_name[(acpi_size)prefix_length + 1]; 42662306a36Sopenharmony_ci break; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci case AML_DUAL_NAME_PREFIX: 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* Two 4-byte names */ 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci names_index = prefix_length + 1; 43362306a36Sopenharmony_ci num_segments = 2; 43462306a36Sopenharmony_ci break; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci case 0: 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* null_name */ 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci names_index = 0; 44162306a36Sopenharmony_ci num_segments = 0; 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci default: 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* one 4-byte name */ 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci names_index = prefix_length; 44962306a36Sopenharmony_ci num_segments = 1; 45062306a36Sopenharmony_ci break; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* 45562306a36Sopenharmony_ci * Calculate the length of converted_name, which equals the length 45662306a36Sopenharmony_ci * of the prefix, length of all object names, length of any required 45762306a36Sopenharmony_ci * punctuation ('.') between object names, plus the NULL terminator. 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci required_length = prefix_length + (4 * num_segments) + 46062306a36Sopenharmony_ci ((num_segments > 0) ? (num_segments - 1) : 0) + 1; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* 46362306a36Sopenharmony_ci * Check to see if we're still in bounds. If not, there's a problem 46462306a36Sopenharmony_ci * with internal_name (invalid format). 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_ci if (required_length > internal_name_length) { 46762306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Invalid internal name")); 46862306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_PATHNAME); 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* Build the converted_name */ 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci *converted_name = ACPI_ALLOCATE_ZEROED(required_length); 47462306a36Sopenharmony_ci if (!(*converted_name)) { 47562306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci j = 0; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci for (i = 0; i < prefix_length; i++) { 48162306a36Sopenharmony_ci (*converted_name)[j++] = internal_name[i]; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (num_segments > 0) { 48562306a36Sopenharmony_ci for (i = 0; i < num_segments; i++) { 48662306a36Sopenharmony_ci if (i > 0) { 48762306a36Sopenharmony_ci (*converted_name)[j++] = '.'; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Copy and validate the 4-char name segment */ 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci ACPI_COPY_NAMESEG(&(*converted_name)[j], 49362306a36Sopenharmony_ci &internal_name[names_index]); 49462306a36Sopenharmony_ci acpi_ut_repair_name(&(*converted_name)[j]); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci j += ACPI_NAMESEG_SIZE; 49762306a36Sopenharmony_ci names_index += ACPI_NAMESEG_SIZE; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (converted_name_length) { 50262306a36Sopenharmony_ci *converted_name_length = (u32) required_length; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci/******************************************************************************* 50962306a36Sopenharmony_ci * 51062306a36Sopenharmony_ci * FUNCTION: acpi_ns_validate_handle 51162306a36Sopenharmony_ci * 51262306a36Sopenharmony_ci * PARAMETERS: handle - Handle to be validated and typecast to a 51362306a36Sopenharmony_ci * namespace node. 51462306a36Sopenharmony_ci * 51562306a36Sopenharmony_ci * RETURN: A pointer to a namespace node 51662306a36Sopenharmony_ci * 51762306a36Sopenharmony_ci * DESCRIPTION: Convert a namespace handle to a namespace node. Handles special 51862306a36Sopenharmony_ci * cases for the root node. 51962306a36Sopenharmony_ci * 52062306a36Sopenharmony_ci * NOTE: Real integer handles would allow for more verification 52162306a36Sopenharmony_ci * and keep all pointers within this subsystem - however this introduces 52262306a36Sopenharmony_ci * more overhead and has not been necessary to this point. Drivers 52362306a36Sopenharmony_ci * holding handles are typically notified before a node becomes invalid 52462306a36Sopenharmony_ci * due to a table unload. 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci ******************************************************************************/ 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistruct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci ACPI_FUNCTION_ENTRY(); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* Parameter validation */ 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if ((!handle) || (handle == ACPI_ROOT_OBJECT)) { 53662306a36Sopenharmony_ci return (acpi_gbl_root_node); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci /* We can at least attempt to verify the handle */ 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (ACPI_GET_DESCRIPTOR_TYPE(handle) != ACPI_DESC_TYPE_NAMED) { 54262306a36Sopenharmony_ci return (NULL); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return (ACPI_CAST_PTR(struct acpi_namespace_node, handle)); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci/******************************************************************************* 54962306a36Sopenharmony_ci * 55062306a36Sopenharmony_ci * FUNCTION: acpi_ns_terminate 55162306a36Sopenharmony_ci * 55262306a36Sopenharmony_ci * PARAMETERS: none 55362306a36Sopenharmony_ci * 55462306a36Sopenharmony_ci * RETURN: none 55562306a36Sopenharmony_ci * 55662306a36Sopenharmony_ci * DESCRIPTION: free memory allocated for namespace and ACPI table storage. 55762306a36Sopenharmony_ci * 55862306a36Sopenharmony_ci ******************************************************************************/ 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_civoid acpi_ns_terminate(void) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci acpi_status status; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ns_terminate); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* 56762306a36Sopenharmony_ci * Free the entire namespace -- all nodes and all objects 56862306a36Sopenharmony_ci * attached to the nodes 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci acpi_ns_delete_namespace_subtree(acpi_gbl_root_node); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* Delete any objects attached to the root node */ 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 57562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 57662306a36Sopenharmony_ci return_VOID; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci acpi_ns_delete_node(acpi_gbl_root_node); 58062306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n")); 58362306a36Sopenharmony_ci return_VOID; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci/******************************************************************************* 58762306a36Sopenharmony_ci * 58862306a36Sopenharmony_ci * FUNCTION: acpi_ns_opens_scope 58962306a36Sopenharmony_ci * 59062306a36Sopenharmony_ci * PARAMETERS: type - A valid namespace type 59162306a36Sopenharmony_ci * 59262306a36Sopenharmony_ci * RETURN: NEWSCOPE if the passed type "opens a name scope" according 59362306a36Sopenharmony_ci * to the ACPI specification, else 0 59462306a36Sopenharmony_ci * 59562306a36Sopenharmony_ci ******************************************************************************/ 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ciu32 acpi_ns_opens_scope(acpi_object_type type) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci ACPI_FUNCTION_ENTRY(); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci if (type > ACPI_TYPE_LOCAL_MAX) { 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* type code out of range */ 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type)); 60662306a36Sopenharmony_ci return (ACPI_NS_NORMAL); 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci return (((u32)acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE); 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/******************************************************************************* 61362306a36Sopenharmony_ci * 61462306a36Sopenharmony_ci * FUNCTION: acpi_ns_get_node_unlocked 61562306a36Sopenharmony_ci * 61662306a36Sopenharmony_ci * PARAMETERS: *pathname - Name to be found, in external (ASL) format. The 61762306a36Sopenharmony_ci * \ (backslash) and ^ (carat) prefixes, and the 61862306a36Sopenharmony_ci * . (period) to separate segments are supported. 61962306a36Sopenharmony_ci * prefix_node - Root of subtree to be searched, or NS_ALL for the 62062306a36Sopenharmony_ci * root of the name space. If Name is fully 62162306a36Sopenharmony_ci * qualified (first s8 is '\'), the passed value 62262306a36Sopenharmony_ci * of Scope will not be accessed. 62362306a36Sopenharmony_ci * flags - Used to indicate whether to perform upsearch or 62462306a36Sopenharmony_ci * not. 62562306a36Sopenharmony_ci * return_node - Where the Node is returned 62662306a36Sopenharmony_ci * 62762306a36Sopenharmony_ci * DESCRIPTION: Look up a name relative to a given scope and return the 62862306a36Sopenharmony_ci * corresponding Node. NOTE: Scope can be null. 62962306a36Sopenharmony_ci * 63062306a36Sopenharmony_ci * MUTEX: Doesn't locks namespace 63162306a36Sopenharmony_ci * 63262306a36Sopenharmony_ci ******************************************************************************/ 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ciacpi_status 63562306a36Sopenharmony_ciacpi_ns_get_node_unlocked(struct acpi_namespace_node *prefix_node, 63662306a36Sopenharmony_ci const char *pathname, 63762306a36Sopenharmony_ci u32 flags, struct acpi_namespace_node **return_node) 63862306a36Sopenharmony_ci{ 63962306a36Sopenharmony_ci union acpi_generic_state scope_info; 64062306a36Sopenharmony_ci acpi_status status; 64162306a36Sopenharmony_ci char *internal_path; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ns_get_node_unlocked, 64462306a36Sopenharmony_ci ACPI_CAST_PTR(char, pathname)); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Simplest case is a null pathname */ 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (!pathname) { 64962306a36Sopenharmony_ci *return_node = prefix_node; 65062306a36Sopenharmony_ci if (!prefix_node) { 65162306a36Sopenharmony_ci *return_node = acpi_gbl_root_node; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Quick check for a reference to the root */ 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (ACPI_IS_ROOT_PREFIX(pathname[0]) && (!pathname[1])) { 66062306a36Sopenharmony_ci *return_node = acpi_gbl_root_node; 66162306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* Convert path to internal representation */ 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci status = acpi_ns_internalize_name(pathname, &internal_path); 66762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 66862306a36Sopenharmony_ci return_ACPI_STATUS(status); 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* Setup lookup scope (search starting point) */ 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci scope_info.scope.node = prefix_node; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Lookup the name in the namespace */ 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci status = acpi_ns_lookup(&scope_info, internal_path, ACPI_TYPE_ANY, 67862306a36Sopenharmony_ci ACPI_IMODE_EXECUTE, 67962306a36Sopenharmony_ci (flags | ACPI_NS_DONT_OPEN_SCOPE), NULL, 68062306a36Sopenharmony_ci return_node); 68162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 68262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s, %s\n", 68362306a36Sopenharmony_ci pathname, acpi_format_exception(status))); 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci ACPI_FREE(internal_path); 68762306a36Sopenharmony_ci return_ACPI_STATUS(status); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci/******************************************************************************* 69162306a36Sopenharmony_ci * 69262306a36Sopenharmony_ci * FUNCTION: acpi_ns_get_node 69362306a36Sopenharmony_ci * 69462306a36Sopenharmony_ci * PARAMETERS: *pathname - Name to be found, in external (ASL) format. The 69562306a36Sopenharmony_ci * \ (backslash) and ^ (carat) prefixes, and the 69662306a36Sopenharmony_ci * . (period) to separate segments are supported. 69762306a36Sopenharmony_ci * prefix_node - Root of subtree to be searched, or NS_ALL for the 69862306a36Sopenharmony_ci * root of the name space. If Name is fully 69962306a36Sopenharmony_ci * qualified (first s8 is '\'), the passed value 70062306a36Sopenharmony_ci * of Scope will not be accessed. 70162306a36Sopenharmony_ci * flags - Used to indicate whether to perform upsearch or 70262306a36Sopenharmony_ci * not. 70362306a36Sopenharmony_ci * return_node - Where the Node is returned 70462306a36Sopenharmony_ci * 70562306a36Sopenharmony_ci * DESCRIPTION: Look up a name relative to a given scope and return the 70662306a36Sopenharmony_ci * corresponding Node. NOTE: Scope can be null. 70762306a36Sopenharmony_ci * 70862306a36Sopenharmony_ci * MUTEX: Locks namespace 70962306a36Sopenharmony_ci * 71062306a36Sopenharmony_ci ******************************************************************************/ 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ciacpi_status 71362306a36Sopenharmony_ciacpi_ns_get_node(struct acpi_namespace_node *prefix_node, 71462306a36Sopenharmony_ci const char *pathname, 71562306a36Sopenharmony_ci u32 flags, struct acpi_namespace_node **return_node) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci acpi_status status; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname)); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 72262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 72362306a36Sopenharmony_ci return_ACPI_STATUS(status); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci status = acpi_ns_get_node_unlocked(prefix_node, pathname, 72762306a36Sopenharmony_ci flags, return_node); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 73062306a36Sopenharmony_ci return_ACPI_STATUS(status); 73162306a36Sopenharmony_ci} 732