162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: nsxfname - Public interfaces to the ACPI subsystem
562306a36Sopenharmony_ci *                         ACPI Namespace oriented interfaces
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *****************************************************************************/
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define EXPORT_ACPI_INTERFACES
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <acpi/acpi.h>
1462306a36Sopenharmony_ci#include "accommon.h"
1562306a36Sopenharmony_ci#include "acnamesp.h"
1662306a36Sopenharmony_ci#include "acparser.h"
1762306a36Sopenharmony_ci#include "amlcode.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define _COMPONENT          ACPI_NAMESPACE
2062306a36Sopenharmony_ciACPI_MODULE_NAME("nsxfname")
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* Local prototypes */
2362306a36Sopenharmony_cistatic char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,
2462306a36Sopenharmony_ci				    struct acpi_pnp_device_id *source,
2562306a36Sopenharmony_ci				    char *string_area);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/******************************************************************************
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * FUNCTION:    acpi_get_handle
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * PARAMETERS:  parent          - Object to search under (search scope).
3262306a36Sopenharmony_ci *              pathname        - Pointer to an asciiz string containing the
3362306a36Sopenharmony_ci *                                name
3462306a36Sopenharmony_ci *              ret_handle      - Where the return handle is returned
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * RETURN:      Status
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * DESCRIPTION: This routine will search for a caller specified name in the
3962306a36Sopenharmony_ci *              name space. The caller can restrict the search region by
4062306a36Sopenharmony_ci *              specifying a non NULL parent. The parent value is itself a
4162306a36Sopenharmony_ci *              namespace handle.
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci ******************************************************************************/
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciacpi_status
4662306a36Sopenharmony_ciacpi_get_handle(acpi_handle parent,
4762306a36Sopenharmony_ci		const char *pathname, acpi_handle *ret_handle)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	acpi_status status;
5062306a36Sopenharmony_ci	struct acpi_namespace_node *node = NULL;
5162306a36Sopenharmony_ci	struct acpi_namespace_node *prefix_node = NULL;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	ACPI_FUNCTION_ENTRY();
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	/* Parameter Validation */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (!ret_handle || !pathname) {
5862306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* Convert a parent handle to a prefix node */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (parent) {
6462306a36Sopenharmony_ci		prefix_node = acpi_ns_validate_handle(parent);
6562306a36Sopenharmony_ci		if (!prefix_node) {
6662306a36Sopenharmony_ci			return (AE_BAD_PARAMETER);
6762306a36Sopenharmony_ci		}
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/*
7162306a36Sopenharmony_ci	 * Valid cases are:
7262306a36Sopenharmony_ci	 * 1) Fully qualified pathname
7362306a36Sopenharmony_ci	 * 2) Parent + Relative pathname
7462306a36Sopenharmony_ci	 *
7562306a36Sopenharmony_ci	 * Error for <null Parent + relative path>
7662306a36Sopenharmony_ci	 */
7762306a36Sopenharmony_ci	if (ACPI_IS_ROOT_PREFIX(pathname[0])) {
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		/* Pathname is fully qualified (starts with '\') */
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		/* Special case for root-only, since we can't search for it */
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci		if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) {
8462306a36Sopenharmony_ci			*ret_handle =
8562306a36Sopenharmony_ci			    ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node);
8662306a36Sopenharmony_ci			return (AE_OK);
8762306a36Sopenharmony_ci		}
8862306a36Sopenharmony_ci	} else if (!prefix_node) {
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		/* Relative path with null prefix is disallowed */
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* Find the Node and convert to a handle */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	status =
9862306a36Sopenharmony_ci	    acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
9962306a36Sopenharmony_ci	if (ACPI_SUCCESS(status)) {
10062306a36Sopenharmony_ci		*ret_handle = ACPI_CAST_PTR(acpi_handle, node);
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	return (status);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_handle)
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/******************************************************************************
10962306a36Sopenharmony_ci *
11062306a36Sopenharmony_ci * FUNCTION:    acpi_get_name
11162306a36Sopenharmony_ci *
11262306a36Sopenharmony_ci * PARAMETERS:  handle          - Handle to be converted to a pathname
11362306a36Sopenharmony_ci *              name_type       - Full pathname or single segment
11462306a36Sopenharmony_ci *              buffer          - Buffer for returned path
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * RETURN:      Pointer to a string containing the fully qualified Name.
11762306a36Sopenharmony_ci *
11862306a36Sopenharmony_ci * DESCRIPTION: This routine returns the fully qualified name associated with
11962306a36Sopenharmony_ci *              the Handle parameter. This and the acpi_pathname_to_handle are
12062306a36Sopenharmony_ci *              complementary functions.
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci ******************************************************************************/
12362306a36Sopenharmony_ciacpi_status
12462306a36Sopenharmony_ciacpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	acpi_status status;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* Parameter validation */
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	if (name_type > ACPI_NAME_TYPE_MAX) {
13162306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	status = acpi_ut_validate_buffer(buffer);
13562306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
13662306a36Sopenharmony_ci		return (status);
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/*
14062306a36Sopenharmony_ci	 * Wants the single segment ACPI name.
14162306a36Sopenharmony_ci	 * Validate handle and convert to a namespace Node
14262306a36Sopenharmony_ci	 */
14362306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
14462306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
14562306a36Sopenharmony_ci		return (status);
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	if (name_type == ACPI_FULL_PATHNAME ||
14962306a36Sopenharmony_ci	    name_type == ACPI_FULL_PATHNAME_NO_TRAILING) {
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci		/* Get the full pathname (From the namespace root) */
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci		status = acpi_ns_handle_to_pathname(handle, buffer,
15462306a36Sopenharmony_ci						    name_type ==
15562306a36Sopenharmony_ci						    ACPI_FULL_PATHNAME ? FALSE :
15662306a36Sopenharmony_ci						    TRUE);
15762306a36Sopenharmony_ci	} else {
15862306a36Sopenharmony_ci		/* Get the single name */
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci		status = acpi_ns_handle_to_name(handle, buffer);
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
16462306a36Sopenharmony_ci	return (status);
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_name)
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/******************************************************************************
17062306a36Sopenharmony_ci *
17162306a36Sopenharmony_ci * FUNCTION:    acpi_ns_copy_device_id
17262306a36Sopenharmony_ci *
17362306a36Sopenharmony_ci * PARAMETERS:  dest                - Pointer to the destination PNP_DEVICE_ID
17462306a36Sopenharmony_ci *              source              - Pointer to the source PNP_DEVICE_ID
17562306a36Sopenharmony_ci *              string_area         - Pointer to where to copy the dest string
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci * RETURN:      Pointer to the next string area
17862306a36Sopenharmony_ci *
17962306a36Sopenharmony_ci * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data.
18062306a36Sopenharmony_ci *
18162306a36Sopenharmony_ci ******************************************************************************/
18262306a36Sopenharmony_cistatic char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,
18362306a36Sopenharmony_ci				    struct acpi_pnp_device_id *source,
18462306a36Sopenharmony_ci				    char *string_area)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	/* Create the destination PNP_DEVICE_ID */
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	dest->string = string_area;
18962306a36Sopenharmony_ci	dest->length = source->length;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* Copy actual string and return a pointer to the next string area */
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	memcpy(string_area, source->string, source->length);
19462306a36Sopenharmony_ci	return (string_area + source->length);
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci/******************************************************************************
19862306a36Sopenharmony_ci *
19962306a36Sopenharmony_ci * FUNCTION:    acpi_get_object_info
20062306a36Sopenharmony_ci *
20162306a36Sopenharmony_ci * PARAMETERS:  handle              - Object Handle
20262306a36Sopenharmony_ci *              return_buffer       - Where the info is returned
20362306a36Sopenharmony_ci *
20462306a36Sopenharmony_ci * RETURN:      Status
20562306a36Sopenharmony_ci *
20662306a36Sopenharmony_ci * DESCRIPTION: Returns information about an object as gleaned from the
20762306a36Sopenharmony_ci *              namespace node and possibly by running several standard
20862306a36Sopenharmony_ci *              control methods (Such as in the case of a device.)
20962306a36Sopenharmony_ci *
21062306a36Sopenharmony_ci * For Device and Processor objects, run the Device _HID, _UID, _CID,
21162306a36Sopenharmony_ci * _CLS, _ADR, _sx_w, and _sx_d methods.
21262306a36Sopenharmony_ci *
21362306a36Sopenharmony_ci * Note: Allocates the return buffer, must be freed by the caller.
21462306a36Sopenharmony_ci *
21562306a36Sopenharmony_ci * Note: This interface is intended to be used during the initial device
21662306a36Sopenharmony_ci * discovery namespace traversal. Therefore, no complex methods can be
21762306a36Sopenharmony_ci * executed, especially those that access operation regions. Therefore, do
21862306a36Sopenharmony_ci * not add any additional methods that could cause problems in this area.
21962306a36Sopenharmony_ci * Because of this reason support for the following methods has been removed:
22062306a36Sopenharmony_ci * 1) _SUB method was removed (11/2015)
22162306a36Sopenharmony_ci * 2) _STA method was removed (02/2018)
22262306a36Sopenharmony_ci *
22362306a36Sopenharmony_ci ******************************************************************************/
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ciacpi_status
22662306a36Sopenharmony_ciacpi_get_object_info(acpi_handle handle,
22762306a36Sopenharmony_ci		     struct acpi_device_info **return_buffer)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct acpi_namespace_node *node;
23062306a36Sopenharmony_ci	struct acpi_device_info *info;
23162306a36Sopenharmony_ci	struct acpi_pnp_device_id_list *cid_list = NULL;
23262306a36Sopenharmony_ci	struct acpi_pnp_device_id *hid = NULL;
23362306a36Sopenharmony_ci	struct acpi_pnp_device_id *uid = NULL;
23462306a36Sopenharmony_ci	struct acpi_pnp_device_id *cls = NULL;
23562306a36Sopenharmony_ci	char *next_id_string;
23662306a36Sopenharmony_ci	acpi_object_type type;
23762306a36Sopenharmony_ci	acpi_name name;
23862306a36Sopenharmony_ci	u8 param_count = 0;
23962306a36Sopenharmony_ci	u16 valid = 0;
24062306a36Sopenharmony_ci	u32 info_size;
24162306a36Sopenharmony_ci	u32 i;
24262306a36Sopenharmony_ci	acpi_status status;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/* Parameter validation */
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (!handle || !return_buffer) {
24762306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
25162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
25262306a36Sopenharmony_ci		return (status);
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	node = acpi_ns_validate_handle(handle);
25662306a36Sopenharmony_ci	if (!node) {
25762306a36Sopenharmony_ci		(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
25862306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	/* Get the namespace node data while the namespace is locked */
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	info_size = sizeof(struct acpi_device_info);
26462306a36Sopenharmony_ci	type = node->type;
26562306a36Sopenharmony_ci	name = node->name.integer;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (node->type == ACPI_TYPE_METHOD) {
26862306a36Sopenharmony_ci		param_count = node->object->method.param_count;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
27262306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
27362306a36Sopenharmony_ci		return (status);
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
27762306a36Sopenharmony_ci		/*
27862306a36Sopenharmony_ci		 * Get extra info for ACPI Device/Processor objects only:
27962306a36Sopenharmony_ci		 * Run the Device _HID, _UID, _CLS, and _CID methods.
28062306a36Sopenharmony_ci		 *
28162306a36Sopenharmony_ci		 * Note: none of these methods are required, so they may or may
28262306a36Sopenharmony_ci		 * not be present for this device. The Info->Valid bitfield is used
28362306a36Sopenharmony_ci		 * to indicate which methods were found and run successfully.
28462306a36Sopenharmony_ci		 */
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		/* Execute the Device._HID method */
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		status = acpi_ut_execute_HID(node, &hid);
28962306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
29062306a36Sopenharmony_ci			info_size += hid->length;
29162306a36Sopenharmony_ci			valid |= ACPI_VALID_HID;
29262306a36Sopenharmony_ci		}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		/* Execute the Device._UID method */
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci		status = acpi_ut_execute_UID(node, &uid);
29762306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
29862306a36Sopenharmony_ci			info_size += uid->length;
29962306a36Sopenharmony_ci			valid |= ACPI_VALID_UID;
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		/* Execute the Device._CID method */
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		status = acpi_ut_execute_CID(node, &cid_list);
30562306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci			/* Add size of CID strings and CID pointer array */
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci			info_size +=
31062306a36Sopenharmony_ci			    (cid_list->list_size -
31162306a36Sopenharmony_ci			     sizeof(struct acpi_pnp_device_id_list));
31262306a36Sopenharmony_ci			valid |= ACPI_VALID_CID;
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		/* Execute the Device._CLS method */
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		status = acpi_ut_execute_CLS(node, &cls);
31862306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
31962306a36Sopenharmony_ci			info_size += cls->length;
32062306a36Sopenharmony_ci			valid |= ACPI_VALID_CLS;
32162306a36Sopenharmony_ci		}
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/*
32562306a36Sopenharmony_ci	 * Now that we have the variable-length data, we can allocate the
32662306a36Sopenharmony_ci	 * return buffer
32762306a36Sopenharmony_ci	 */
32862306a36Sopenharmony_ci	info = ACPI_ALLOCATE_ZEROED(info_size);
32962306a36Sopenharmony_ci	if (!info) {
33062306a36Sopenharmony_ci		status = AE_NO_MEMORY;
33162306a36Sopenharmony_ci		goto cleanup;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* Get the fixed-length data */
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
33762306a36Sopenharmony_ci		/*
33862306a36Sopenharmony_ci		 * Get extra info for ACPI Device/Processor objects only:
33962306a36Sopenharmony_ci		 * Run the _ADR and, sx_w, and _sx_d methods.
34062306a36Sopenharmony_ci		 *
34162306a36Sopenharmony_ci		 * Notes: none of these methods are required, so they may or may
34262306a36Sopenharmony_ci		 * not be present for this device. The Info->Valid bitfield is used
34362306a36Sopenharmony_ci		 * to indicate which methods were found and run successfully.
34462306a36Sopenharmony_ci		 */
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		/* Execute the Device._ADR method */
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node,
34962306a36Sopenharmony_ci							 &info->address);
35062306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
35162306a36Sopenharmony_ci			valid |= ACPI_VALID_ADR;
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		/* Execute the Device._sx_w methods */
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		status = acpi_ut_execute_power_methods(node,
35762306a36Sopenharmony_ci						       acpi_gbl_lowest_dstate_names,
35862306a36Sopenharmony_ci						       ACPI_NUM_sx_w_METHODS,
35962306a36Sopenharmony_ci						       info->lowest_dstates);
36062306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
36162306a36Sopenharmony_ci			valid |= ACPI_VALID_SXWS;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci		/* Execute the Device._sx_d methods */
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci		status = acpi_ut_execute_power_methods(node,
36762306a36Sopenharmony_ci						       acpi_gbl_highest_dstate_names,
36862306a36Sopenharmony_ci						       ACPI_NUM_sx_d_METHODS,
36962306a36Sopenharmony_ci						       info->highest_dstates);
37062306a36Sopenharmony_ci		if (ACPI_SUCCESS(status)) {
37162306a36Sopenharmony_ci			valid |= ACPI_VALID_SXDS;
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/*
37662306a36Sopenharmony_ci	 * Create a pointer to the string area of the return buffer.
37762306a36Sopenharmony_ci	 * Point to the end of the base struct acpi_device_info structure.
37862306a36Sopenharmony_ci	 */
37962306a36Sopenharmony_ci	next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids);
38062306a36Sopenharmony_ci	if (cid_list) {
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		/* Point past the CID PNP_DEVICE_ID array */
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		next_id_string +=
38562306a36Sopenharmony_ci		    ((acpi_size)cid_list->count *
38662306a36Sopenharmony_ci		     sizeof(struct acpi_pnp_device_id));
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/*
39062306a36Sopenharmony_ci	 * Copy the HID, UID, and CIDs to the return buffer. The variable-length
39162306a36Sopenharmony_ci	 * strings are copied to the reserved area at the end of the buffer.
39262306a36Sopenharmony_ci	 *
39362306a36Sopenharmony_ci	 * For HID and CID, check if the ID is a PCI Root Bridge.
39462306a36Sopenharmony_ci	 */
39562306a36Sopenharmony_ci	if (hid) {
39662306a36Sopenharmony_ci		next_id_string = acpi_ns_copy_device_id(&info->hardware_id,
39762306a36Sopenharmony_ci							hid, next_id_string);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci		if (acpi_ut_is_pci_root_bridge(hid->string)) {
40062306a36Sopenharmony_ci			info->flags |= ACPI_PCI_ROOT_BRIDGE;
40162306a36Sopenharmony_ci		}
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (uid) {
40562306a36Sopenharmony_ci		next_id_string = acpi_ns_copy_device_id(&info->unique_id,
40662306a36Sopenharmony_ci							uid, next_id_string);
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (cid_list) {
41062306a36Sopenharmony_ci		info->compatible_id_list.count = cid_list->count;
41162306a36Sopenharmony_ci		info->compatible_id_list.list_size = cid_list->list_size;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		/* Copy each CID */
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci		for (i = 0; i < cid_list->count; i++) {
41662306a36Sopenharmony_ci			next_id_string =
41762306a36Sopenharmony_ci			    acpi_ns_copy_device_id(&info->compatible_id_list.
41862306a36Sopenharmony_ci						   ids[i], &cid_list->ids[i],
41962306a36Sopenharmony_ci						   next_id_string);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci			if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) {
42262306a36Sopenharmony_ci				info->flags |= ACPI_PCI_ROOT_BRIDGE;
42362306a36Sopenharmony_ci			}
42462306a36Sopenharmony_ci		}
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (cls) {
42862306a36Sopenharmony_ci		(void)acpi_ns_copy_device_id(&info->class_code,
42962306a36Sopenharmony_ci					     cls, next_id_string);
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	/* Copy the fixed-length data */
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	info->info_size = info_size;
43562306a36Sopenharmony_ci	info->type = type;
43662306a36Sopenharmony_ci	info->name = name;
43762306a36Sopenharmony_ci	info->param_count = param_count;
43862306a36Sopenharmony_ci	info->valid = valid;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	*return_buffer = info;
44162306a36Sopenharmony_ci	status = AE_OK;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cicleanup:
44462306a36Sopenharmony_ci	if (hid) {
44562306a36Sopenharmony_ci		ACPI_FREE(hid);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci	if (uid) {
44862306a36Sopenharmony_ci		ACPI_FREE(uid);
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci	if (cid_list) {
45162306a36Sopenharmony_ci		ACPI_FREE(cid_list);
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci	if (cls) {
45462306a36Sopenharmony_ci		ACPI_FREE(cls);
45562306a36Sopenharmony_ci	}
45662306a36Sopenharmony_ci	return (status);
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_object_info)
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci/******************************************************************************
46262306a36Sopenharmony_ci *
46362306a36Sopenharmony_ci * FUNCTION:    acpi_install_method
46462306a36Sopenharmony_ci *
46562306a36Sopenharmony_ci * PARAMETERS:  buffer         - An ACPI table containing one control method
46662306a36Sopenharmony_ci *
46762306a36Sopenharmony_ci * RETURN:      Status
46862306a36Sopenharmony_ci *
46962306a36Sopenharmony_ci * DESCRIPTION: Install a control method into the namespace. If the method
47062306a36Sopenharmony_ci *              name already exists in the namespace, it is overwritten. The
47162306a36Sopenharmony_ci *              input buffer must contain a valid DSDT or SSDT containing a
47262306a36Sopenharmony_ci *              single control method.
47362306a36Sopenharmony_ci *
47462306a36Sopenharmony_ci ******************************************************************************/
47562306a36Sopenharmony_ciacpi_status acpi_install_method(u8 *buffer)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	struct acpi_table_header *table =
47862306a36Sopenharmony_ci	    ACPI_CAST_PTR(struct acpi_table_header, buffer);
47962306a36Sopenharmony_ci	u8 *aml_buffer;
48062306a36Sopenharmony_ci	u8 *aml_start;
48162306a36Sopenharmony_ci	char *path;
48262306a36Sopenharmony_ci	struct acpi_namespace_node *node;
48362306a36Sopenharmony_ci	union acpi_operand_object *method_obj;
48462306a36Sopenharmony_ci	struct acpi_parse_state parser_state;
48562306a36Sopenharmony_ci	u32 aml_length;
48662306a36Sopenharmony_ci	u16 opcode;
48762306a36Sopenharmony_ci	u8 method_flags;
48862306a36Sopenharmony_ci	acpi_status status;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* Parameter validation */
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	if (!buffer) {
49362306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	/* Table must be a DSDT or SSDT */
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (!ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT) &&
49962306a36Sopenharmony_ci	    !ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_SSDT)) {
50062306a36Sopenharmony_ci		return (AE_BAD_HEADER);
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/* First AML opcode in the table must be a control method */
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	parser_state.aml = buffer + sizeof(struct acpi_table_header);
50662306a36Sopenharmony_ci	opcode = acpi_ps_peek_opcode(&parser_state);
50762306a36Sopenharmony_ci	if (opcode != AML_METHOD_OP) {
50862306a36Sopenharmony_ci		return (AE_BAD_PARAMETER);
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* Extract method information from the raw AML */
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	parser_state.aml += acpi_ps_get_opcode_size(opcode);
51462306a36Sopenharmony_ci	parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state);
51562306a36Sopenharmony_ci	path = acpi_ps_get_next_namestring(&parser_state);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	method_flags = *parser_state.aml++;
51862306a36Sopenharmony_ci	aml_start = parser_state.aml;
51962306a36Sopenharmony_ci	aml_length = (u32)ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/*
52262306a36Sopenharmony_ci	 * Allocate resources up-front. We don't want to have to delete a new
52362306a36Sopenharmony_ci	 * node from the namespace if we cannot allocate memory.
52462306a36Sopenharmony_ci	 */
52562306a36Sopenharmony_ci	aml_buffer = ACPI_ALLOCATE(aml_length);
52662306a36Sopenharmony_ci	if (!aml_buffer) {
52762306a36Sopenharmony_ci		return (AE_NO_MEMORY);
52862306a36Sopenharmony_ci	}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
53162306a36Sopenharmony_ci	if (!method_obj) {
53262306a36Sopenharmony_ci		ACPI_FREE(aml_buffer);
53362306a36Sopenharmony_ci		return (AE_NO_MEMORY);
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* Lock namespace for acpi_ns_lookup, we may be creating a new node */
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
53962306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
54062306a36Sopenharmony_ci		goto error_exit;
54162306a36Sopenharmony_ci	}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	/* The lookup either returns an existing node or creates a new one */
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	status =
54662306a36Sopenharmony_ci	    acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1,
54762306a36Sopenharmony_ci			   ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
54862306a36Sopenharmony_ci			   NULL, &node);
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {	/* ns_lookup */
55362306a36Sopenharmony_ci		if (status != AE_ALREADY_EXISTS) {
55462306a36Sopenharmony_ci			goto error_exit;
55562306a36Sopenharmony_ci		}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		/* Node existed previously, make sure it is a method node */
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		if (node->type != ACPI_TYPE_METHOD) {
56062306a36Sopenharmony_ci			status = AE_TYPE;
56162306a36Sopenharmony_ci			goto error_exit;
56262306a36Sopenharmony_ci		}
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Copy the method AML to the local buffer */
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	memcpy(aml_buffer, aml_start, aml_length);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	/* Initialize the method object with the new method's information */
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	method_obj->method.aml_start = aml_buffer;
57262306a36Sopenharmony_ci	method_obj->method.aml_length = aml_length;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	method_obj->method.param_count = (u8)
57562306a36Sopenharmony_ci	    (method_flags & AML_METHOD_ARG_COUNT);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	if (method_flags & AML_METHOD_SERIALIZED) {
57862306a36Sopenharmony_ci		method_obj->method.info_flags = ACPI_METHOD_SERIALIZED;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci		method_obj->method.sync_level = (u8)
58162306a36Sopenharmony_ci		    ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	/*
58562306a36Sopenharmony_ci	 * Now that it is complete, we can attach the new method object to
58662306a36Sopenharmony_ci	 * the method Node (detaches/deletes any existing object)
58762306a36Sopenharmony_ci	 */
58862306a36Sopenharmony_ci	status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD);
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	/*
59162306a36Sopenharmony_ci	 * Flag indicates AML buffer is dynamic, must be deleted later.
59262306a36Sopenharmony_ci	 * Must be set only after attach above.
59362306a36Sopenharmony_ci	 */
59462306a36Sopenharmony_ci	node->flags |= ANOBJ_ALLOCATED_BUFFER;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	/* Remove local reference to the method object */
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	acpi_ut_remove_reference(method_obj);
59962306a36Sopenharmony_ci	return (status);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cierror_exit:
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	ACPI_FREE(aml_buffer);
60462306a36Sopenharmony_ci	ACPI_FREE(method_obj);
60562306a36Sopenharmony_ci	return (status);
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_method)
608