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