xref: /openbmc/linux/drivers/acpi/acpica/nsutils.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
595b482a8SLen Brown  *                        parents and siblings and Scope manipulation
695b482a8SLen Brown  *
7*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
895b482a8SLen Brown  *
995857638SErik Schmauss  *****************************************************************************/
1095b482a8SLen Brown 
1195b482a8SLen Brown #include <acpi/acpi.h>
12e2f7a777SLen Brown #include "accommon.h"
13e2f7a777SLen Brown #include "acnamesp.h"
14e2f7a777SLen Brown #include "amlcode.h"
1595b482a8SLen Brown 
1695b482a8SLen Brown #define _COMPONENT          ACPI_NAMESPACE
1795b482a8SLen Brown ACPI_MODULE_NAME("nsutils")
1895b482a8SLen Brown 
1995b482a8SLen Brown /* Local prototypes */
2095b482a8SLen Brown #ifdef ACPI_OBSOLETE_FUNCTIONS
2195b482a8SLen Brown acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node *node_to_search);
2295b482a8SLen Brown #endif
2395b482a8SLen Brown 
2495b482a8SLen Brown /*******************************************************************************
2595b482a8SLen Brown  *
2695b482a8SLen Brown  * FUNCTION:    acpi_ns_print_node_pathname
2795b482a8SLen Brown  *
28ba494beeSBob Moore  * PARAMETERS:  node            - Object
29ba494beeSBob Moore  *              message         - Prefix message
3095b482a8SLen Brown  *
3195b482a8SLen Brown  * DESCRIPTION: Print an object's full namespace pathname
3295b482a8SLen Brown  *              Manages allocation/freeing of a pathname buffer
3395b482a8SLen Brown  *
3495b482a8SLen Brown  ******************************************************************************/
3595b482a8SLen Brown 
3695b482a8SLen Brown void
acpi_ns_print_node_pathname(struct acpi_namespace_node * node,const char * message)3795b482a8SLen Brown acpi_ns_print_node_pathname(struct acpi_namespace_node *node,
3895b482a8SLen Brown 			    const char *message)
3995b482a8SLen Brown {
4095b482a8SLen Brown 	struct acpi_buffer buffer;
4195b482a8SLen Brown 	acpi_status status;
4295b482a8SLen Brown 
4395b482a8SLen Brown 	if (!node) {
4495b482a8SLen Brown 		acpi_os_printf("[NULL NAME]");
4595b482a8SLen Brown 		return;
4695b482a8SLen Brown 	}
4795b482a8SLen Brown 
4895b482a8SLen Brown 	/* Convert handle to full pathname and print it (with supplied message) */
4995b482a8SLen Brown 
5095b482a8SLen Brown 	buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
5195b482a8SLen Brown 
522e5321cbSLv Zheng 	status = acpi_ns_handle_to_pathname(node, &buffer, TRUE);
5395b482a8SLen Brown 	if (ACPI_SUCCESS(status)) {
5495b482a8SLen Brown 		if (message) {
5595b482a8SLen Brown 			acpi_os_printf("%s ", message);
5695b482a8SLen Brown 		}
5795b482a8SLen Brown 
581537f303SBob Moore 		acpi_os_printf("%s", (char *)buffer.pointer);
5995b482a8SLen Brown 		ACPI_FREE(buffer.pointer);
6095b482a8SLen Brown 	}
6195b482a8SLen Brown }
6295b482a8SLen Brown 
6395b482a8SLen Brown /*******************************************************************************
6495b482a8SLen Brown  *
6595b482a8SLen Brown  * FUNCTION:    acpi_ns_get_type
6695b482a8SLen Brown  *
67ba494beeSBob Moore  * PARAMETERS:  node        - Parent Node to be examined
6895b482a8SLen Brown  *
6995b482a8SLen Brown  * RETURN:      Type field from Node whose handle is passed
7095b482a8SLen Brown  *
7195b482a8SLen Brown  * DESCRIPTION: Return the type of a Namespace node
7295b482a8SLen Brown  *
7395b482a8SLen Brown  ******************************************************************************/
7495b482a8SLen Brown 
acpi_ns_get_type(struct acpi_namespace_node * node)7595b482a8SLen Brown acpi_object_type acpi_ns_get_type(struct acpi_namespace_node * node)
7695b482a8SLen Brown {
7795b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_get_type);
7895b482a8SLen Brown 
7995b482a8SLen Brown 	if (!node) {
8095b482a8SLen Brown 		ACPI_WARNING((AE_INFO, "Null Node parameter"));
81fd1af712SBob Moore 		return_UINT8(ACPI_TYPE_ANY);
8295b482a8SLen Brown 	}
8395b482a8SLen Brown 
84fd1af712SBob Moore 	return_UINT8(node->type);
8595b482a8SLen Brown }
8695b482a8SLen Brown 
8795b482a8SLen Brown /*******************************************************************************
8895b482a8SLen Brown  *
8995b482a8SLen Brown  * FUNCTION:    acpi_ns_local
9095b482a8SLen Brown  *
91ba494beeSBob Moore  * PARAMETERS:  type        - A namespace object type
9295b482a8SLen Brown  *
9395b482a8SLen Brown  * RETURN:      LOCAL if names must be found locally in objects of the
9495b482a8SLen Brown  *              passed type, 0 if enclosing scopes should be searched
9595b482a8SLen Brown  *
9695b482a8SLen Brown  * DESCRIPTION: Returns scope rule for the given object type.
9795b482a8SLen Brown  *
9895b482a8SLen Brown  ******************************************************************************/
9995b482a8SLen Brown 
acpi_ns_local(acpi_object_type type)10095b482a8SLen Brown u32 acpi_ns_local(acpi_object_type type)
10195b482a8SLen Brown {
10295b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_local);
10395b482a8SLen Brown 
10495b482a8SLen Brown 	if (!acpi_ut_valid_object_type(type)) {
10595b482a8SLen Brown 
10695b482a8SLen Brown 		/* Type code out of range  */
10795b482a8SLen Brown 
108f6a22b0bSBob Moore 		ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));
109fd1af712SBob Moore 		return_UINT32(ACPI_NS_NORMAL);
11095b482a8SLen Brown 	}
11195b482a8SLen Brown 
112fd1af712SBob Moore 	return_UINT32(acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
11395b482a8SLen Brown }
11495b482a8SLen Brown 
11595b482a8SLen Brown /*******************************************************************************
11695b482a8SLen Brown  *
11795b482a8SLen Brown  * FUNCTION:    acpi_ns_get_internal_name_length
11895b482a8SLen Brown  *
119ba494beeSBob Moore  * PARAMETERS:  info            - Info struct initialized with the
12095b482a8SLen Brown  *                                external name pointer.
12195b482a8SLen Brown  *
12295b482a8SLen Brown  * RETURN:      None
12395b482a8SLen Brown  *
12495b482a8SLen Brown  * DESCRIPTION: Calculate the length of the internal (AML) namestring
12595b482a8SLen Brown  *              corresponding to the external (ASL) namestring.
12695b482a8SLen Brown  *
12795b482a8SLen Brown  ******************************************************************************/
12895b482a8SLen Brown 
acpi_ns_get_internal_name_length(struct acpi_namestring_info * info)12995b482a8SLen Brown void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info)
13095b482a8SLen Brown {
13195b482a8SLen Brown 	const char *next_external_char;
13295b482a8SLen Brown 	u32 i;
13395b482a8SLen Brown 
13495b482a8SLen Brown 	ACPI_FUNCTION_ENTRY();
13595b482a8SLen Brown 
13695b482a8SLen Brown 	next_external_char = info->external_name;
13795b482a8SLen Brown 	info->num_carats = 0;
13895b482a8SLen Brown 	info->num_segments = 0;
13995b482a8SLen Brown 	info->fully_qualified = FALSE;
14095b482a8SLen Brown 
14195b482a8SLen Brown 	/*
1421fad8738SBob Moore 	 * For the internal name, the required length is 4 bytes per segment,
1431fad8738SBob Moore 	 * plus 1 each for root_prefix, multi_name_prefix_op, segment count,
1441fad8738SBob Moore 	 * trailing null (which is not really needed, but no there's harm in
1451fad8738SBob Moore 	 * putting it there)
14695b482a8SLen Brown 	 *
14795b482a8SLen Brown 	 * strlen() + 1 covers the first name_seg, which has no path separator
14895b482a8SLen Brown 	 */
14904a81dceSBob Moore 	if (ACPI_IS_ROOT_PREFIX(*next_external_char)) {
15095b482a8SLen Brown 		info->fully_qualified = TRUE;
15195b482a8SLen Brown 		next_external_char++;
15295b482a8SLen Brown 
15395b482a8SLen Brown 		/* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */
15495b482a8SLen Brown 
15504a81dceSBob Moore 		while (ACPI_IS_ROOT_PREFIX(*next_external_char)) {
15695b482a8SLen Brown 			next_external_char++;
15795b482a8SLen Brown 		}
15895b482a8SLen Brown 	} else {
159d4913dc6SBob Moore 		/* Handle Carat prefixes */
160d4913dc6SBob Moore 
16104a81dceSBob Moore 		while (ACPI_IS_PARENT_PREFIX(*next_external_char)) {
16295b482a8SLen Brown 			info->num_carats++;
16395b482a8SLen Brown 			next_external_char++;
16495b482a8SLen Brown 		}
16595b482a8SLen Brown 	}
16695b482a8SLen Brown 
16795b482a8SLen Brown 	/*
16895b482a8SLen Brown 	 * Determine the number of ACPI name "segments" by counting the number of
16995b482a8SLen Brown 	 * path separators within the string. Start with one segment since the
17095b482a8SLen Brown 	 * segment count is [(# separators) + 1], and zero separators is ok.
17195b482a8SLen Brown 	 */
17295b482a8SLen Brown 	if (*next_external_char) {
17395b482a8SLen Brown 		info->num_segments = 1;
17495b482a8SLen Brown 		for (i = 0; next_external_char[i]; i++) {
17504a81dceSBob Moore 			if (ACPI_IS_PATH_SEPARATOR(next_external_char[i])) {
17695b482a8SLen Brown 				info->num_segments++;
17795b482a8SLen Brown 			}
17895b482a8SLen Brown 		}
17995b482a8SLen Brown 	}
18095b482a8SLen Brown 
18132786755SBob Moore 	info->length = (ACPI_NAMESEG_SIZE * info->num_segments) +
18295b482a8SLen Brown 	    4 + info->num_carats;
18395b482a8SLen Brown 
18495b482a8SLen Brown 	info->next_external_char = next_external_char;
18595b482a8SLen Brown }
18695b482a8SLen Brown 
18795b482a8SLen Brown /*******************************************************************************
18895b482a8SLen Brown  *
18995b482a8SLen Brown  * FUNCTION:    acpi_ns_build_internal_name
19095b482a8SLen Brown  *
191ba494beeSBob Moore  * PARAMETERS:  info            - Info struct fully initialized
19295b482a8SLen Brown  *
19395b482a8SLen Brown  * RETURN:      Status
19495b482a8SLen Brown  *
19595b482a8SLen Brown  * DESCRIPTION: Construct the internal (AML) namestring
19695b482a8SLen Brown  *              corresponding to the external (ASL) namestring.
19795b482a8SLen Brown  *
19895b482a8SLen Brown  ******************************************************************************/
19995b482a8SLen Brown 
acpi_ns_build_internal_name(struct acpi_namestring_info * info)20095b482a8SLen Brown acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info)
20195b482a8SLen Brown {
20295b482a8SLen Brown 	u32 num_segments = info->num_segments;
20395b482a8SLen Brown 	char *internal_name = info->internal_name;
20495b482a8SLen Brown 	const char *external_name = info->next_external_char;
20595b482a8SLen Brown 	char *result = NULL;
20695b482a8SLen Brown 	u32 i;
20795b482a8SLen Brown 
20895b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_build_internal_name);
20995b482a8SLen Brown 
21095b482a8SLen Brown 	/* Setup the correct prefixes, counts, and pointers */
21195b482a8SLen Brown 
21295b482a8SLen Brown 	if (info->fully_qualified) {
21304a81dceSBob Moore 		internal_name[0] = AML_ROOT_PREFIX;
21495b482a8SLen Brown 
21595b482a8SLen Brown 		if (num_segments <= 1) {
21695b482a8SLen Brown 			result = &internal_name[1];
21795b482a8SLen Brown 		} else if (num_segments == 2) {
21895b482a8SLen Brown 			internal_name[1] = AML_DUAL_NAME_PREFIX;
21995b482a8SLen Brown 			result = &internal_name[2];
22095b482a8SLen Brown 		} else {
2219ff5a21aSBob Moore 			internal_name[1] = AML_MULTI_NAME_PREFIX;
22295b482a8SLen Brown 			internal_name[2] = (char)num_segments;
22395b482a8SLen Brown 			result = &internal_name[3];
22495b482a8SLen Brown 		}
22595b482a8SLen Brown 	} else {
22695b482a8SLen Brown 		/*
22795b482a8SLen Brown 		 * Not fully qualified.
22895b482a8SLen Brown 		 * Handle Carats first, then append the name segments
22995b482a8SLen Brown 		 */
23095b482a8SLen Brown 		i = 0;
23195b482a8SLen Brown 		if (info->num_carats) {
23295b482a8SLen Brown 			for (i = 0; i < info->num_carats; i++) {
23304a81dceSBob Moore 				internal_name[i] = AML_PARENT_PREFIX;
23495b482a8SLen Brown 			}
23595b482a8SLen Brown 		}
23695b482a8SLen Brown 
23795b482a8SLen Brown 		if (num_segments <= 1) {
23895b482a8SLen Brown 			result = &internal_name[i];
23995b482a8SLen Brown 		} else if (num_segments == 2) {
24095b482a8SLen Brown 			internal_name[i] = AML_DUAL_NAME_PREFIX;
24195b482a8SLen Brown 			result = &internal_name[(acpi_size)i + 1];
24295b482a8SLen Brown 		} else {
2439ff5a21aSBob Moore 			internal_name[i] = AML_MULTI_NAME_PREFIX;
24495b482a8SLen Brown 			internal_name[(acpi_size)i + 1] = (char)num_segments;
24595b482a8SLen Brown 			result = &internal_name[(acpi_size)i + 2];
24695b482a8SLen Brown 		}
24795b482a8SLen Brown 	}
24895b482a8SLen Brown 
24995b482a8SLen Brown 	/* Build the name (minus path separators) */
25095b482a8SLen Brown 
25195b482a8SLen Brown 	for (; num_segments; num_segments--) {
25232786755SBob Moore 		for (i = 0; i < ACPI_NAMESEG_SIZE; i++) {
25304a81dceSBob Moore 			if (ACPI_IS_PATH_SEPARATOR(*external_name) ||
25495b482a8SLen Brown 			    (*external_name == 0)) {
25595b482a8SLen Brown 
25695b482a8SLen Brown 				/* Pad the segment with underscore(s) if segment is short */
25795b482a8SLen Brown 
25895b482a8SLen Brown 				result[i] = '_';
25995b482a8SLen Brown 			} else {
26095b482a8SLen Brown 				/* Convert the character to uppercase and save it */
26195b482a8SLen Brown 
2624fa4616eSBob Moore 				result[i] = (char)toupper((int)*external_name);
26395b482a8SLen Brown 				external_name++;
26495b482a8SLen Brown 			}
26595b482a8SLen Brown 		}
26695b482a8SLen Brown 
26795b482a8SLen Brown 		/* Now we must have a path separator, or the pathname is bad */
26895b482a8SLen Brown 
26904a81dceSBob Moore 		if (!ACPI_IS_PATH_SEPARATOR(*external_name) &&
27095b482a8SLen Brown 		    (*external_name != 0)) {
271a1acd22fSBob Moore 			return_ACPI_STATUS(AE_BAD_PATHNAME);
27295b482a8SLen Brown 		}
27395b482a8SLen Brown 
27495b482a8SLen Brown 		/* Move on the next segment */
27595b482a8SLen Brown 
27695b482a8SLen Brown 		external_name++;
27732786755SBob Moore 		result += ACPI_NAMESEG_SIZE;
27895b482a8SLen Brown 	}
27995b482a8SLen Brown 
28095b482a8SLen Brown 	/* Terminate the string */
28195b482a8SLen Brown 
28295b482a8SLen Brown 	*result = 0;
28395b482a8SLen Brown 
28495b482a8SLen Brown 	if (info->fully_qualified) {
28595b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
28695b482a8SLen Brown 				  "Returning [%p] (abs) \"\\%s\"\n",
28795b482a8SLen Brown 				  internal_name, internal_name));
28895b482a8SLen Brown 	} else {
28995b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Returning [%p] (rel) \"%s\"\n",
29095b482a8SLen Brown 				  internal_name, internal_name));
29195b482a8SLen Brown 	}
29295b482a8SLen Brown 
29395b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
29495b482a8SLen Brown }
29595b482a8SLen Brown 
29695b482a8SLen Brown /*******************************************************************************
29795b482a8SLen Brown  *
29895b482a8SLen Brown  * FUNCTION:    acpi_ns_internalize_name
29995b482a8SLen Brown  *
30095b482a8SLen Brown  * PARAMETERS:  *external_name          - External representation of name
301ba494beeSBob Moore  *              **Converted name        - Where to return the resulting
30295b482a8SLen Brown  *                                        internal represention of the name
30395b482a8SLen Brown  *
30495b482a8SLen Brown  * RETURN:      Status
30595b482a8SLen Brown  *
30695b482a8SLen Brown  * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0")
30795b482a8SLen Brown  *              to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
30895b482a8SLen Brown  *
30995b482a8SLen Brown  *******************************************************************************/
31095b482a8SLen Brown 
31195b482a8SLen Brown acpi_status
acpi_ns_internalize_name(const char * external_name,char ** converted_name)31295b482a8SLen Brown acpi_ns_internalize_name(const char *external_name, char **converted_name)
31395b482a8SLen Brown {
31495b482a8SLen Brown 	char *internal_name;
31595b482a8SLen Brown 	struct acpi_namestring_info info;
31695b482a8SLen Brown 	acpi_status status;
31795b482a8SLen Brown 
31895b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_internalize_name);
31995b482a8SLen Brown 
32095b482a8SLen Brown 	if ((!external_name) || (*external_name == 0) || (!converted_name)) {
32195b482a8SLen Brown 		return_ACPI_STATUS(AE_BAD_PARAMETER);
32295b482a8SLen Brown 	}
32395b482a8SLen Brown 
32495b482a8SLen Brown 	/* Get the length of the new internal name */
32595b482a8SLen Brown 
32695b482a8SLen Brown 	info.external_name = external_name;
32795b482a8SLen Brown 	acpi_ns_get_internal_name_length(&info);
32895b482a8SLen Brown 
32995b482a8SLen Brown 	/* We need a segment to store the internal  name */
33095b482a8SLen Brown 
33195b482a8SLen Brown 	internal_name = ACPI_ALLOCATE_ZEROED(info.length);
33295b482a8SLen Brown 	if (!internal_name) {
33395b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
33495b482a8SLen Brown 	}
33595b482a8SLen Brown 
33695b482a8SLen Brown 	/* Build the name */
33795b482a8SLen Brown 
33895b482a8SLen Brown 	info.internal_name = internal_name;
33995b482a8SLen Brown 	status = acpi_ns_build_internal_name(&info);
34095b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
34195b482a8SLen Brown 		ACPI_FREE(internal_name);
34295b482a8SLen Brown 		return_ACPI_STATUS(status);
34395b482a8SLen Brown 	}
34495b482a8SLen Brown 
34595b482a8SLen Brown 	*converted_name = internal_name;
34695b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
34795b482a8SLen Brown }
34895b482a8SLen Brown 
34995b482a8SLen Brown /*******************************************************************************
35095b482a8SLen Brown  *
35195b482a8SLen Brown  * FUNCTION:    acpi_ns_externalize_name
35295b482a8SLen Brown  *
353c163f90cSErik Schmauss  * PARAMETERS:  internal_name_length - Length of the internal name below
35495b482a8SLen Brown  *              internal_name       - Internal representation of name
35595b482a8SLen Brown  *              converted_name_length - Where the length is returned
35695b482a8SLen Brown  *              converted_name      - Where the resulting external name
35795b482a8SLen Brown  *                                    is returned
35895b482a8SLen Brown  *
35995b482a8SLen Brown  * RETURN:      Status
36095b482a8SLen Brown  *
36195b482a8SLen Brown  * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
36295b482a8SLen Brown  *              to its external (printable) form (e.g. "\_PR_.CPU0")
36395b482a8SLen Brown  *
36495b482a8SLen Brown  ******************************************************************************/
36595b482a8SLen Brown 
36695b482a8SLen Brown acpi_status
acpi_ns_externalize_name(u32 internal_name_length,const char * internal_name,u32 * converted_name_length,char ** converted_name)36795b482a8SLen Brown acpi_ns_externalize_name(u32 internal_name_length,
36895b482a8SLen Brown 			 const char *internal_name,
36995b482a8SLen Brown 			 u32 * converted_name_length, char **converted_name)
37095b482a8SLen Brown {
37195b482a8SLen Brown 	u32 names_index = 0;
37295b482a8SLen Brown 	u32 num_segments = 0;
37395b482a8SLen Brown 	u32 required_length;
37495b482a8SLen Brown 	u32 prefix_length = 0;
37595b482a8SLen Brown 	u32 i = 0;
37695b482a8SLen Brown 	u32 j = 0;
37795b482a8SLen Brown 
37895b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_externalize_name);
37995b482a8SLen Brown 
38095b482a8SLen Brown 	if (!internal_name_length || !internal_name || !converted_name) {
38195b482a8SLen Brown 		return_ACPI_STATUS(AE_BAD_PARAMETER);
38295b482a8SLen Brown 	}
38395b482a8SLen Brown 
384d4913dc6SBob Moore 	/* Check for a prefix (one '\' | one or more '^') */
385d4913dc6SBob Moore 
38695b482a8SLen Brown 	switch (internal_name[0]) {
38704a81dceSBob Moore 	case AML_ROOT_PREFIX:
3881d1ea1b7SChao Guan 
38995b482a8SLen Brown 		prefix_length = 1;
39095b482a8SLen Brown 		break;
39195b482a8SLen Brown 
39204a81dceSBob Moore 	case AML_PARENT_PREFIX:
3931d1ea1b7SChao Guan 
39495b482a8SLen Brown 		for (i = 0; i < internal_name_length; i++) {
39504a81dceSBob Moore 			if (ACPI_IS_PARENT_PREFIX(internal_name[i])) {
39695b482a8SLen Brown 				prefix_length = i + 1;
39795b482a8SLen Brown 			} else {
39895b482a8SLen Brown 				break;
39995b482a8SLen Brown 			}
40095b482a8SLen Brown 		}
40195b482a8SLen Brown 
40295b482a8SLen Brown 		if (i == internal_name_length) {
40395b482a8SLen Brown 			prefix_length = i;
40495b482a8SLen Brown 		}
40595b482a8SLen Brown 
40695b482a8SLen Brown 		break;
40795b482a8SLen Brown 
40895b482a8SLen Brown 	default:
4091d1ea1b7SChao Guan 
41095b482a8SLen Brown 		break;
41195b482a8SLen Brown 	}
41295b482a8SLen Brown 
41395b482a8SLen Brown 	/*
41495b482a8SLen Brown 	 * Check for object names. Note that there could be 0-255 of these
41595b482a8SLen Brown 	 * 4-byte elements.
41695b482a8SLen Brown 	 */
41795b482a8SLen Brown 	if (prefix_length < internal_name_length) {
41895b482a8SLen Brown 		switch (internal_name[prefix_length]) {
4199ff5a21aSBob Moore 		case AML_MULTI_NAME_PREFIX:
42095b482a8SLen Brown 
42195b482a8SLen Brown 			/* <count> 4-byte names */
42295b482a8SLen Brown 
42395b482a8SLen Brown 			names_index = prefix_length + 2;
42495b482a8SLen Brown 			num_segments = (u8)
42595b482a8SLen Brown 			    internal_name[(acpi_size)prefix_length + 1];
42695b482a8SLen Brown 			break;
42795b482a8SLen Brown 
42895b482a8SLen Brown 		case AML_DUAL_NAME_PREFIX:
42995b482a8SLen Brown 
43095b482a8SLen Brown 			/* Two 4-byte names */
43195b482a8SLen Brown 
43295b482a8SLen Brown 			names_index = prefix_length + 1;
43395b482a8SLen Brown 			num_segments = 2;
43495b482a8SLen Brown 			break;
43595b482a8SLen Brown 
43695b482a8SLen Brown 		case 0:
43795b482a8SLen Brown 
43895b482a8SLen Brown 			/* null_name */
43995b482a8SLen Brown 
44095b482a8SLen Brown 			names_index = 0;
44195b482a8SLen Brown 			num_segments = 0;
44295b482a8SLen Brown 			break;
44395b482a8SLen Brown 
44495b482a8SLen Brown 		default:
44595b482a8SLen Brown 
44695b482a8SLen Brown 			/* one 4-byte name */
44795b482a8SLen Brown 
44895b482a8SLen Brown 			names_index = prefix_length;
44995b482a8SLen Brown 			num_segments = 1;
45095b482a8SLen Brown 			break;
45195b482a8SLen Brown 		}
45295b482a8SLen Brown 	}
45395b482a8SLen Brown 
45495b482a8SLen Brown 	/*
45595b482a8SLen Brown 	 * Calculate the length of converted_name, which equals the length
45695b482a8SLen Brown 	 * of the prefix, length of all object names, length of any required
45795b482a8SLen Brown 	 * punctuation ('.') between object names, plus the NULL terminator.
45895b482a8SLen Brown 	 */
45995b482a8SLen Brown 	required_length = prefix_length + (4 * num_segments) +
46095b482a8SLen Brown 	    ((num_segments > 0) ? (num_segments - 1) : 0) + 1;
46195b482a8SLen Brown 
46295b482a8SLen Brown 	/*
46395b482a8SLen Brown 	 * Check to see if we're still in bounds. If not, there's a problem
46495b482a8SLen Brown 	 * with internal_name (invalid format).
46595b482a8SLen Brown 	 */
46695b482a8SLen Brown 	if (required_length > internal_name_length) {
46795b482a8SLen Brown 		ACPI_ERROR((AE_INFO, "Invalid internal name"));
46895b482a8SLen Brown 		return_ACPI_STATUS(AE_BAD_PATHNAME);
46995b482a8SLen Brown 	}
47095b482a8SLen Brown 
471d4913dc6SBob Moore 	/* Build the converted_name */
472d4913dc6SBob Moore 
47395b482a8SLen Brown 	*converted_name = ACPI_ALLOCATE_ZEROED(required_length);
47495b482a8SLen Brown 	if (!(*converted_name)) {
47595b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
47695b482a8SLen Brown 	}
47795b482a8SLen Brown 
47895b482a8SLen Brown 	j = 0;
47995b482a8SLen Brown 
48095b482a8SLen Brown 	for (i = 0; i < prefix_length; i++) {
48195b482a8SLen Brown 		(*converted_name)[j++] = internal_name[i];
48295b482a8SLen Brown 	}
48395b482a8SLen Brown 
48495b482a8SLen Brown 	if (num_segments > 0) {
48595b482a8SLen Brown 		for (i = 0; i < num_segments; i++) {
48695b482a8SLen Brown 			if (i > 0) {
48795b482a8SLen Brown 				(*converted_name)[j++] = '.';
48895b482a8SLen Brown 			}
48995b482a8SLen Brown 
49047abd13cSBob Moore 			/* Copy and validate the 4-char name segment */
49147abd13cSBob Moore 
492a3ce7a8eSBob Moore 			ACPI_COPY_NAMESEG(&(*converted_name)[j],
49347abd13cSBob Moore 					  &internal_name[names_index]);
49447abd13cSBob Moore 			acpi_ut_repair_name(&(*converted_name)[j]);
49500eb3255SBob Moore 
49632786755SBob Moore 			j += ACPI_NAMESEG_SIZE;
49732786755SBob Moore 			names_index += ACPI_NAMESEG_SIZE;
49895b482a8SLen Brown 		}
49995b482a8SLen Brown 	}
50095b482a8SLen Brown 
50195b482a8SLen Brown 	if (converted_name_length) {
50295b482a8SLen Brown 		*converted_name_length = (u32) required_length;
50395b482a8SLen Brown 	}
50495b482a8SLen Brown 
50595b482a8SLen Brown 	return_ACPI_STATUS(AE_OK);
50695b482a8SLen Brown }
50795b482a8SLen Brown 
50895b482a8SLen Brown /*******************************************************************************
50995b482a8SLen Brown  *
510f24b664dSBob Moore  * FUNCTION:    acpi_ns_validate_handle
51195b482a8SLen Brown  *
512ba494beeSBob Moore  * PARAMETERS:  handle          - Handle to be validated and typecast to a
513f24b664dSBob Moore  *                                namespace node.
51495b482a8SLen Brown  *
515f24b664dSBob Moore  * RETURN:      A pointer to a namespace node
51695b482a8SLen Brown  *
517f24b664dSBob Moore  * DESCRIPTION: Convert a namespace handle to a namespace node. Handles special
518f24b664dSBob Moore  *              cases for the root node.
51995b482a8SLen Brown  *
520f24b664dSBob Moore  * NOTE: Real integer handles would allow for more verification
52195b482a8SLen Brown  *       and keep all pointers within this subsystem - however this introduces
522f24b664dSBob Moore  *       more overhead and has not been necessary to this point. Drivers
523f24b664dSBob Moore  *       holding handles are typically notified before a node becomes invalid
524f24b664dSBob Moore  *       due to a table unload.
525d4913dc6SBob Moore  *
52695b482a8SLen Brown  ******************************************************************************/
52795b482a8SLen Brown 
acpi_ns_validate_handle(acpi_handle handle)528f24b664dSBob Moore struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle)
52995b482a8SLen Brown {
53095b482a8SLen Brown 
53195b482a8SLen Brown 	ACPI_FUNCTION_ENTRY();
53295b482a8SLen Brown 
533d4913dc6SBob Moore 	/* Parameter validation */
534d4913dc6SBob Moore 
53595b482a8SLen Brown 	if ((!handle) || (handle == ACPI_ROOT_OBJECT)) {
53695b482a8SLen Brown 		return (acpi_gbl_root_node);
53795b482a8SLen Brown 	}
53895b482a8SLen Brown 
53995b482a8SLen Brown 	/* We can at least attempt to verify the handle */
54095b482a8SLen Brown 
54195b482a8SLen Brown 	if (ACPI_GET_DESCRIPTOR_TYPE(handle) != ACPI_DESC_TYPE_NAMED) {
54295b482a8SLen Brown 		return (NULL);
54395b482a8SLen Brown 	}
54495b482a8SLen Brown 
54595b482a8SLen Brown 	return (ACPI_CAST_PTR(struct acpi_namespace_node, handle));
54695b482a8SLen Brown }
54795b482a8SLen Brown 
54895b482a8SLen Brown /*******************************************************************************
54995b482a8SLen Brown  *
55095b482a8SLen Brown  * FUNCTION:    acpi_ns_terminate
55195b482a8SLen Brown  *
55295b482a8SLen Brown  * PARAMETERS:  none
55395b482a8SLen Brown  *
55495b482a8SLen Brown  * RETURN:      none
55595b482a8SLen Brown  *
55695b482a8SLen Brown  * DESCRIPTION: free memory allocated for namespace and ACPI table storage.
55795b482a8SLen Brown  *
55895b482a8SLen Brown  ******************************************************************************/
55995b482a8SLen Brown 
acpi_ns_terminate(void)56095b482a8SLen Brown void acpi_ns_terminate(void)
56195b482a8SLen Brown {
5623f69fe15SBob Moore 	acpi_status status;
56325823e78SBob Moore 
5643b2d6911SSeunghun Han 	ACPI_FUNCTION_TRACE(ns_terminate);
5653b2d6911SSeunghun Han 
56695b482a8SLen Brown 	/*
5673f69fe15SBob Moore 	 * Free the entire namespace -- all nodes and all objects
5683f69fe15SBob Moore 	 * attached to the nodes
56995b482a8SLen Brown 	 */
57095b482a8SLen Brown 	acpi_ns_delete_namespace_subtree(acpi_gbl_root_node);
57195b482a8SLen Brown 
5723f69fe15SBob Moore 	/* Delete any objects attached to the root node */
57395b482a8SLen Brown 
5743f69fe15SBob Moore 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
5753f69fe15SBob Moore 	if (ACPI_FAILURE(status)) {
5763f69fe15SBob Moore 		return_VOID;
57795b482a8SLen Brown 	}
57895b482a8SLen Brown 
5793f69fe15SBob Moore 	acpi_ns_delete_node(acpi_gbl_root_node);
5803f69fe15SBob Moore 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
5813f69fe15SBob Moore 
58295b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n"));
58395b482a8SLen Brown 	return_VOID;
58495b482a8SLen Brown }
58595b482a8SLen Brown 
58695b482a8SLen Brown /*******************************************************************************
58795b482a8SLen Brown  *
58895b482a8SLen Brown  * FUNCTION:    acpi_ns_opens_scope
58995b482a8SLen Brown  *
590ba494beeSBob Moore  * PARAMETERS:  type        - A valid namespace type
59195b482a8SLen Brown  *
59295b482a8SLen Brown  * RETURN:      NEWSCOPE if the passed type "opens a name scope" according
59395b482a8SLen Brown  *              to the ACPI specification, else 0
59495b482a8SLen Brown  *
59595b482a8SLen Brown  ******************************************************************************/
59695b482a8SLen Brown 
acpi_ns_opens_scope(acpi_object_type type)59795b482a8SLen Brown u32 acpi_ns_opens_scope(acpi_object_type type)
59895b482a8SLen Brown {
5990e770b32SBob Moore 	ACPI_FUNCTION_ENTRY();
60095b482a8SLen Brown 
6010e770b32SBob Moore 	if (type > ACPI_TYPE_LOCAL_MAX) {
60295b482a8SLen Brown 
60395b482a8SLen Brown 		/* type code out of range  */
60495b482a8SLen Brown 
605f6a22b0bSBob Moore 		ACPI_WARNING((AE_INFO, "Invalid Object Type 0x%X", type));
6060e770b32SBob Moore 		return (ACPI_NS_NORMAL);
60795b482a8SLen Brown 	}
60895b482a8SLen Brown 
6090e770b32SBob Moore 	return (((u32)acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE);
61095b482a8SLen Brown }
61195b482a8SLen Brown 
61295b482a8SLen Brown /*******************************************************************************
61395b482a8SLen Brown  *
614c2d981aaSLv Zheng  * FUNCTION:    acpi_ns_get_node_unlocked
61595b482a8SLen Brown  *
616ba494beeSBob Moore  * PARAMETERS:  *pathname   - Name to be found, in external (ASL) format. The
61795b482a8SLen Brown  *                            \ (backslash) and ^ (carat) prefixes, and the
61895b482a8SLen Brown  *                            . (period) to separate segments are supported.
61995b482a8SLen Brown  *              prefix_node  - Root of subtree to be searched, or NS_ALL for the
62095b482a8SLen Brown  *                            root of the name space. If Name is fully
62195b482a8SLen Brown  *                            qualified (first s8 is '\'), the passed value
62295b482a8SLen Brown  *                            of Scope will not be accessed.
623ba494beeSBob Moore  *              flags       - Used to indicate whether to perform upsearch or
62495b482a8SLen Brown  *                            not.
62595b482a8SLen Brown  *              return_node - Where the Node is returned
62695b482a8SLen Brown  *
62795b482a8SLen Brown  * DESCRIPTION: Look up a name relative to a given scope and return the
62895b482a8SLen Brown  *              corresponding Node. NOTE: Scope can be null.
62995b482a8SLen Brown  *
630c2d981aaSLv Zheng  * MUTEX:       Doesn't locks namespace
63195b482a8SLen Brown  *
63295b482a8SLen Brown  ******************************************************************************/
63395b482a8SLen Brown 
63495b482a8SLen Brown acpi_status
acpi_ns_get_node_unlocked(struct acpi_namespace_node * prefix_node,const char * pathname,u32 flags,struct acpi_namespace_node ** return_node)635c2d981aaSLv Zheng acpi_ns_get_node_unlocked(struct acpi_namespace_node *prefix_node,
63695b482a8SLen Brown 			  const char *pathname,
63795b482a8SLen Brown 			  u32 flags, struct acpi_namespace_node **return_node)
63895b482a8SLen Brown {
63995b482a8SLen Brown 	union acpi_generic_state scope_info;
64095b482a8SLen Brown 	acpi_status status;
64195b482a8SLen Brown 	char *internal_path;
64295b482a8SLen Brown 
643c2d981aaSLv Zheng 	ACPI_FUNCTION_TRACE_PTR(ns_get_node_unlocked,
644c2d981aaSLv Zheng 				ACPI_CAST_PTR(char, pathname));
64595b482a8SLen Brown 
646f8c9bfe4SBob Moore 	/* Simplest case is a null pathname */
647f8c9bfe4SBob Moore 
64895b482a8SLen Brown 	if (!pathname) {
64995b482a8SLen Brown 		*return_node = prefix_node;
65095b482a8SLen Brown 		if (!prefix_node) {
65195b482a8SLen Brown 			*return_node = acpi_gbl_root_node;
65295b482a8SLen Brown 		}
6531fad8738SBob Moore 
65495b482a8SLen Brown 		return_ACPI_STATUS(AE_OK);
65595b482a8SLen Brown 	}
65695b482a8SLen Brown 
657f8c9bfe4SBob Moore 	/* Quick check for a reference to the root */
658f8c9bfe4SBob Moore 
659f8c9bfe4SBob Moore 	if (ACPI_IS_ROOT_PREFIX(pathname[0]) && (!pathname[1])) {
660f8c9bfe4SBob Moore 		*return_node = acpi_gbl_root_node;
661f8c9bfe4SBob Moore 		return_ACPI_STATUS(AE_OK);
662f8c9bfe4SBob Moore 	}
663f8c9bfe4SBob Moore 
66495b482a8SLen Brown 	/* Convert path to internal representation */
66595b482a8SLen Brown 
66695b482a8SLen Brown 	status = acpi_ns_internalize_name(pathname, &internal_path);
66795b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
66895b482a8SLen Brown 		return_ACPI_STATUS(status);
66995b482a8SLen Brown 	}
67095b482a8SLen Brown 
67195b482a8SLen Brown 	/* Setup lookup scope (search starting point) */
67295b482a8SLen Brown 
67395b482a8SLen Brown 	scope_info.scope.node = prefix_node;
67495b482a8SLen Brown 
67595b482a8SLen Brown 	/* Lookup the name in the namespace */
67695b482a8SLen Brown 
67795b482a8SLen Brown 	status = acpi_ns_lookup(&scope_info, internal_path, ACPI_TYPE_ANY,
67895b482a8SLen Brown 				ACPI_IMODE_EXECUTE,
67995b482a8SLen Brown 				(flags | ACPI_NS_DONT_OPEN_SCOPE), NULL,
68095b482a8SLen Brown 				return_node);
68195b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
6827bcc06e8SBob Moore 		ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s, %s\n",
68395b482a8SLen Brown 				  pathname, acpi_format_exception(status)));
68495b482a8SLen Brown 	}
68595b482a8SLen Brown 
68695b482a8SLen Brown 	ACPI_FREE(internal_path);
68795b482a8SLen Brown 	return_ACPI_STATUS(status);
68895b482a8SLen Brown }
689c2d981aaSLv Zheng 
690c2d981aaSLv Zheng /*******************************************************************************
691c2d981aaSLv Zheng  *
692c2d981aaSLv Zheng  * FUNCTION:    acpi_ns_get_node
693c2d981aaSLv Zheng  *
694c2d981aaSLv Zheng  * PARAMETERS:  *pathname   - Name to be found, in external (ASL) format. The
695c2d981aaSLv Zheng  *                            \ (backslash) and ^ (carat) prefixes, and the
696c2d981aaSLv Zheng  *                            . (period) to separate segments are supported.
697c2d981aaSLv Zheng  *              prefix_node  - Root of subtree to be searched, or NS_ALL for the
698c2d981aaSLv Zheng  *                            root of the name space. If Name is fully
699c2d981aaSLv Zheng  *                            qualified (first s8 is '\'), the passed value
700c2d981aaSLv Zheng  *                            of Scope will not be accessed.
701c2d981aaSLv Zheng  *              flags       - Used to indicate whether to perform upsearch or
702c2d981aaSLv Zheng  *                            not.
703c2d981aaSLv Zheng  *              return_node - Where the Node is returned
704c2d981aaSLv Zheng  *
705c2d981aaSLv Zheng  * DESCRIPTION: Look up a name relative to a given scope and return the
706c2d981aaSLv Zheng  *              corresponding Node. NOTE: Scope can be null.
707c2d981aaSLv Zheng  *
708c2d981aaSLv Zheng  * MUTEX:       Locks namespace
709c2d981aaSLv Zheng  *
710c2d981aaSLv Zheng  ******************************************************************************/
711c2d981aaSLv Zheng 
712c2d981aaSLv Zheng acpi_status
acpi_ns_get_node(struct acpi_namespace_node * prefix_node,const char * pathname,u32 flags,struct acpi_namespace_node ** return_node)713c2d981aaSLv Zheng acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
714c2d981aaSLv Zheng 		 const char *pathname,
715c2d981aaSLv Zheng 		 u32 flags, struct acpi_namespace_node **return_node)
716c2d981aaSLv Zheng {
717c2d981aaSLv Zheng 	acpi_status status;
718c2d981aaSLv Zheng 
719c2d981aaSLv Zheng 	ACPI_FUNCTION_TRACE_PTR(ns_get_node, ACPI_CAST_PTR(char, pathname));
720c2d981aaSLv Zheng 
721c2d981aaSLv Zheng 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
722c2d981aaSLv Zheng 	if (ACPI_FAILURE(status)) {
723c2d981aaSLv Zheng 		return_ACPI_STATUS(status);
724c2d981aaSLv Zheng 	}
725c2d981aaSLv Zheng 
726c2d981aaSLv Zheng 	status = acpi_ns_get_node_unlocked(prefix_node, pathname,
727c2d981aaSLv Zheng 					   flags, return_node);
728c2d981aaSLv Zheng 
729c2d981aaSLv Zheng 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
730c2d981aaSLv Zheng 	return_ACPI_STATUS(status);
731c2d981aaSLv Zheng }
732