xref: /openbmc/linux/drivers/acpi/acpica/nsxfname.c (revision 612c2932)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: nsxfname - Public interfaces to the ACPI subsystem
595b482a8SLen Brown  *                         ACPI Namespace oriented interfaces
695b482a8SLen Brown  *
7*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
895b482a8SLen Brown  *
995857638SErik Schmauss  *****************************************************************************/
1095b482a8SLen Brown 
11839e928fSLv Zheng #define EXPORT_ACPI_INTERFACES
12839e928fSLv Zheng 
1395b482a8SLen Brown #include <acpi/acpi.h>
14e2f7a777SLen Brown #include "accommon.h"
15e2f7a777SLen Brown #include "acnamesp.h"
16b2f7ddcfSLin Ming #include "acparser.h"
17b2f7ddcfSLin Ming #include "amlcode.h"
1895b482a8SLen Brown 
1995b482a8SLen Brown #define _COMPONENT          ACPI_NAMESPACE
2095b482a8SLen Brown ACPI_MODULE_NAME("nsxfname")
2195b482a8SLen Brown 
2215b8dd53SBob Moore /* Local prototypes */
2378e25fefSLv Zheng static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,
2478e25fefSLv Zheng 				    struct acpi_pnp_device_id *source,
2515b8dd53SBob Moore 				    char *string_area);
2615b8dd53SBob Moore 
2795b482a8SLen Brown /******************************************************************************
2895b482a8SLen Brown  *
2995b482a8SLen Brown  * FUNCTION:    acpi_get_handle
3095b482a8SLen Brown  *
31ba494beeSBob Moore  * PARAMETERS:  parent          - Object to search under (search scope).
32ba494beeSBob Moore  *              pathname        - Pointer to an asciiz string containing the
3395b482a8SLen Brown  *                                name
3495b482a8SLen Brown  *              ret_handle      - Where the return handle is returned
3595b482a8SLen Brown  *
3695b482a8SLen Brown  * RETURN:      Status
3795b482a8SLen Brown  *
3895b482a8SLen Brown  * DESCRIPTION: This routine will search for a caller specified name in the
3995b482a8SLen Brown  *              name space. The caller can restrict the search region by
4095b482a8SLen Brown  *              specifying a non NULL parent. The parent value is itself a
4195b482a8SLen Brown  *              namespace handle.
4295b482a8SLen Brown  *
4395b482a8SLen Brown  ******************************************************************************/
4415b8dd53SBob Moore 
4595b482a8SLen Brown acpi_status
acpi_get_handle(acpi_handle parent,const char * pathname,acpi_handle * ret_handle)4695b482a8SLen Brown acpi_get_handle(acpi_handle parent,
4791fdb91cSSakari Ailus 		const char *pathname, acpi_handle *ret_handle)
4895b482a8SLen Brown {
4995b482a8SLen Brown 	acpi_status status;
5095b482a8SLen Brown 	struct acpi_namespace_node *node = NULL;
5195b482a8SLen Brown 	struct acpi_namespace_node *prefix_node = NULL;
5295b482a8SLen Brown 
5395b482a8SLen Brown 	ACPI_FUNCTION_ENTRY();
5495b482a8SLen Brown 
5595b482a8SLen Brown 	/* Parameter Validation */
5695b482a8SLen Brown 
5795b482a8SLen Brown 	if (!ret_handle || !pathname) {
5895b482a8SLen Brown 		return (AE_BAD_PARAMETER);
5995b482a8SLen Brown 	}
6095b482a8SLen Brown 
6195b482a8SLen Brown 	/* Convert a parent handle to a prefix node */
6295b482a8SLen Brown 
6395b482a8SLen Brown 	if (parent) {
64f24b664dSBob Moore 		prefix_node = acpi_ns_validate_handle(parent);
6595b482a8SLen Brown 		if (!prefix_node) {
6695b482a8SLen Brown 			return (AE_BAD_PARAMETER);
6795b482a8SLen Brown 		}
6895b482a8SLen Brown 	}
6995b482a8SLen Brown 
7095b482a8SLen Brown 	/*
7195b482a8SLen Brown 	 * Valid cases are:
7295b482a8SLen Brown 	 * 1) Fully qualified pathname
7395b482a8SLen Brown 	 * 2) Parent + Relative pathname
7495b482a8SLen Brown 	 *
7595b482a8SLen Brown 	 * Error for <null Parent + relative path>
7695b482a8SLen Brown 	 */
7704a81dceSBob Moore 	if (ACPI_IS_ROOT_PREFIX(pathname[0])) {
7895b482a8SLen Brown 
7995b482a8SLen Brown 		/* Pathname is fully qualified (starts with '\') */
8095b482a8SLen Brown 
8195b482a8SLen Brown 		/* Special case for root-only, since we can't search for it */
8295b482a8SLen Brown 
834fa4616eSBob Moore 		if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) {
8495b482a8SLen Brown 			*ret_handle =
85f24b664dSBob Moore 			    ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node);
8695b482a8SLen Brown 			return (AE_OK);
8795b482a8SLen Brown 		}
8895b482a8SLen Brown 	} else if (!prefix_node) {
8995b482a8SLen Brown 
9095b482a8SLen Brown 		/* Relative path with null prefix is disallowed */
9195b482a8SLen Brown 
9295b482a8SLen Brown 		return (AE_BAD_PARAMETER);
9395b482a8SLen Brown 	}
9495b482a8SLen Brown 
9595b482a8SLen Brown 	/* Find the Node and convert to a handle */
9695b482a8SLen Brown 
9795b482a8SLen Brown 	status =
9895b482a8SLen Brown 	    acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
9995b482a8SLen Brown 	if (ACPI_SUCCESS(status)) {
100f24b664dSBob Moore 		*ret_handle = ACPI_CAST_PTR(acpi_handle, node);
10195b482a8SLen Brown 	}
10295b482a8SLen Brown 
10395b482a8SLen Brown 	return (status);
10495b482a8SLen Brown }
10595b482a8SLen Brown 
ACPI_EXPORT_SYMBOL(acpi_get_handle)10695b482a8SLen Brown ACPI_EXPORT_SYMBOL(acpi_get_handle)
10795b482a8SLen Brown 
10895b482a8SLen Brown /******************************************************************************
10995b482a8SLen Brown  *
11095b482a8SLen Brown  * FUNCTION:    acpi_get_name
11195b482a8SLen Brown  *
112ba494beeSBob Moore  * PARAMETERS:  handle          - Handle to be converted to a pathname
11395b482a8SLen Brown  *              name_type       - Full pathname or single segment
114ba494beeSBob Moore  *              buffer          - Buffer for returned path
11595b482a8SLen Brown  *
11695b482a8SLen Brown  * RETURN:      Pointer to a string containing the fully qualified Name.
11795b482a8SLen Brown  *
11895b482a8SLen Brown  * DESCRIPTION: This routine returns the fully qualified name associated with
11995b482a8SLen Brown  *              the Handle parameter. This and the acpi_pathname_to_handle are
12095b482a8SLen Brown  *              complementary functions.
12195b482a8SLen Brown  *
12295b482a8SLen Brown  ******************************************************************************/
12395b482a8SLen Brown acpi_status
12495b482a8SLen Brown acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer)
12595b482a8SLen Brown {
12695b482a8SLen Brown 	acpi_status status;
12795b482a8SLen Brown 
12895b482a8SLen Brown 	/* Parameter validation */
12995b482a8SLen Brown 
13095b482a8SLen Brown 	if (name_type > ACPI_NAME_TYPE_MAX) {
13195b482a8SLen Brown 		return (AE_BAD_PARAMETER);
13295b482a8SLen Brown 	}
13395b482a8SLen Brown 
13495b482a8SLen Brown 	status = acpi_ut_validate_buffer(buffer);
13595b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
13695b482a8SLen Brown 		return (status);
13795b482a8SLen Brown 	}
13895b482a8SLen Brown 
139523db19bSLv Zheng 	/*
140523db19bSLv Zheng 	 * Wants the single segment ACPI name.
141523db19bSLv Zheng 	 * Validate handle and convert to a namespace Node
142523db19bSLv Zheng 	 */
143523db19bSLv Zheng 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
144523db19bSLv Zheng 	if (ACPI_FAILURE(status)) {
145523db19bSLv Zheng 		return (status);
146523db19bSLv Zheng 	}
147523db19bSLv Zheng 
148d1e7ffe5SLv Zheng 	if (name_type == ACPI_FULL_PATHNAME ||
149d1e7ffe5SLv Zheng 	    name_type == ACPI_FULL_PATHNAME_NO_TRAILING) {
15095b482a8SLen Brown 
15195b482a8SLen Brown 		/* Get the full pathname (From the namespace root) */
15295b482a8SLen Brown 
153d1e7ffe5SLv Zheng 		status = acpi_ns_handle_to_pathname(handle, buffer,
154d1e7ffe5SLv Zheng 						    name_type ==
155d1e7ffe5SLv Zheng 						    ACPI_FULL_PATHNAME ? FALSE :
156d1e7ffe5SLv Zheng 						    TRUE);
157523db19bSLv Zheng 	} else {
158523db19bSLv Zheng 		/* Get the single name */
159523db19bSLv Zheng 
160523db19bSLv Zheng 		status = acpi_ns_handle_to_name(handle, buffer);
16195b482a8SLen Brown 	}
16295b482a8SLen Brown 
16395b482a8SLen Brown 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
16495b482a8SLen Brown 	return (status);
16595b482a8SLen Brown }
16695b482a8SLen Brown 
ACPI_EXPORT_SYMBOL(acpi_get_name)16795b482a8SLen Brown ACPI_EXPORT_SYMBOL(acpi_get_name)
16895b482a8SLen Brown 
16995b482a8SLen Brown /******************************************************************************
17095b482a8SLen Brown  *
17115b8dd53SBob Moore  * FUNCTION:    acpi_ns_copy_device_id
17215b8dd53SBob Moore  *
17378e25fefSLv Zheng  * PARAMETERS:  dest                - Pointer to the destination PNP_DEVICE_ID
17478e25fefSLv Zheng  *              source              - Pointer to the source PNP_DEVICE_ID
17515b8dd53SBob Moore  *              string_area         - Pointer to where to copy the dest string
17615b8dd53SBob Moore  *
17715b8dd53SBob Moore  * RETURN:      Pointer to the next string area
17815b8dd53SBob Moore  *
17978e25fefSLv Zheng  * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data.
18015b8dd53SBob Moore  *
18115b8dd53SBob Moore  ******************************************************************************/
18278e25fefSLv Zheng static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,
18378e25fefSLv Zheng 				    struct acpi_pnp_device_id *source,
18415b8dd53SBob Moore 				    char *string_area)
18515b8dd53SBob Moore {
18678e25fefSLv Zheng 	/* Create the destination PNP_DEVICE_ID */
18715b8dd53SBob Moore 
18815b8dd53SBob Moore 	dest->string = string_area;
18915b8dd53SBob Moore 	dest->length = source->length;
19015b8dd53SBob Moore 
19115b8dd53SBob Moore 	/* Copy actual string and return a pointer to the next string area */
19215b8dd53SBob Moore 
1934fa4616eSBob Moore 	memcpy(string_area, source->string, source->length);
19415b8dd53SBob Moore 	return (string_area + source->length);
19515b8dd53SBob Moore }
19615b8dd53SBob Moore 
19715b8dd53SBob Moore /******************************************************************************
19815b8dd53SBob Moore  *
19995b482a8SLen Brown  * FUNCTION:    acpi_get_object_info
20095b482a8SLen Brown  *
201ba494beeSBob Moore  * PARAMETERS:  handle              - Object Handle
20215b8dd53SBob Moore  *              return_buffer       - Where the info is returned
20395b482a8SLen Brown  *
20495b482a8SLen Brown  * RETURN:      Status
20595b482a8SLen Brown  *
20695b482a8SLen Brown  * DESCRIPTION: Returns information about an object as gleaned from the
20795b482a8SLen Brown  *              namespace node and possibly by running several standard
20895b482a8SLen Brown  *              control methods (Such as in the case of a device.)
20995b482a8SLen Brown  *
210e7c2c3c9SHans de Goede  * For Device and Processor objects, run the Device _HID, _UID, _CID,
21107cb390fSBob Moore  * _CLS, _ADR, _sx_w, and _sx_d methods.
21215b8dd53SBob Moore  *
21315b8dd53SBob Moore  * Note: Allocates the return buffer, must be freed by the caller.
21415b8dd53SBob Moore  *
215c6c6069cSBob Moore  * Note: This interface is intended to be used during the initial device
216c6c6069cSBob Moore  * discovery namespace traversal. Therefore, no complex methods can be
217c6c6069cSBob Moore  * executed, especially those that access operation regions. Therefore, do
218c6c6069cSBob Moore  * not add any additional methods that could cause problems in this area.
219e7c2c3c9SHans de Goede  * Because of this reason support for the following methods has been removed:
220e7c2c3c9SHans de Goede  * 1) _SUB method was removed (11/2015)
221e7c2c3c9SHans de Goede  * 2) _STA method was removed (02/2018)
222c6c6069cSBob Moore  *
22395b482a8SLen Brown  ******************************************************************************/
22415b8dd53SBob Moore 
22595b482a8SLen Brown acpi_status
acpi_get_object_info(acpi_handle handle,struct acpi_device_info ** return_buffer)22615b8dd53SBob Moore acpi_get_object_info(acpi_handle handle,
22715b8dd53SBob Moore 		     struct acpi_device_info **return_buffer)
22895b482a8SLen Brown {
22995b482a8SLen Brown 	struct acpi_namespace_node *node;
23095b482a8SLen Brown 	struct acpi_device_info *info;
23178e25fefSLv Zheng 	struct acpi_pnp_device_id_list *cid_list = NULL;
23278e25fefSLv Zheng 	struct acpi_pnp_device_id *hid = NULL;
23378e25fefSLv Zheng 	struct acpi_pnp_device_id *uid = NULL;
234f65358e5SSuravee Suthikulpanit 	struct acpi_pnp_device_id *cls = NULL;
23515b8dd53SBob Moore 	char *next_id_string;
23615b8dd53SBob Moore 	acpi_object_type type;
23715b8dd53SBob Moore 	acpi_name name;
23815b8dd53SBob Moore 	u8 param_count = 0;
239f65358e5SSuravee Suthikulpanit 	u16 valid = 0;
24015b8dd53SBob Moore 	u32 info_size;
24115b8dd53SBob Moore 	u32 i;
24215b8dd53SBob Moore 	acpi_status status;
24395b482a8SLen Brown 
24495b482a8SLen Brown 	/* Parameter validation */
24595b482a8SLen Brown 
24615b8dd53SBob Moore 	if (!handle || !return_buffer) {
24795b482a8SLen Brown 		return (AE_BAD_PARAMETER);
24895b482a8SLen Brown 	}
24995b482a8SLen Brown 
25095b482a8SLen Brown 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
25195b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
252ef0b67feSBob Moore 		return (status);
25395b482a8SLen Brown 	}
25495b482a8SLen Brown 
255f24b664dSBob Moore 	node = acpi_ns_validate_handle(handle);
25695b482a8SLen Brown 	if (!node) {
25795b482a8SLen Brown 		(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
25815b8dd53SBob Moore 		return (AE_BAD_PARAMETER);
25995b482a8SLen Brown 	}
26095b482a8SLen Brown 
26115b8dd53SBob Moore 	/* Get the namespace node data while the namespace is locked */
26295b482a8SLen Brown 
26315b8dd53SBob Moore 	info_size = sizeof(struct acpi_device_info);
26415b8dd53SBob Moore 	type = node->type;
26515b8dd53SBob Moore 	name = node->name.integer;
26695b482a8SLen Brown 
26795b482a8SLen Brown 	if (node->type == ACPI_TYPE_METHOD) {
26815b8dd53SBob Moore 		param_count = node->object->method.param_count;
26995b482a8SLen Brown 	}
27095b482a8SLen Brown 
27195b482a8SLen Brown 	status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
27295b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
27315b8dd53SBob Moore 		return (status);
27495b482a8SLen Brown 	}
27595b482a8SLen Brown 
27615b8dd53SBob Moore 	if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
27795b482a8SLen Brown 		/*
27815b8dd53SBob Moore 		 * Get extra info for ACPI Device/Processor objects only:
27907cb390fSBob Moore 		 * Run the Device _HID, _UID, _CLS, and _CID methods.
28095b482a8SLen Brown 		 *
28195b482a8SLen Brown 		 * Note: none of these methods are required, so they may or may
28295b482a8SLen Brown 		 * not be present for this device. The Info->Valid bitfield is used
28315b8dd53SBob Moore 		 * to indicate which methods were found and run successfully.
28495b482a8SLen Brown 		 */
28595b482a8SLen Brown 
28695b482a8SLen Brown 		/* Execute the Device._HID method */
28795b482a8SLen Brown 
28815b8dd53SBob Moore 		status = acpi_ut_execute_HID(node, &hid);
28995b482a8SLen Brown 		if (ACPI_SUCCESS(status)) {
29015b8dd53SBob Moore 			info_size += hid->length;
29115b8dd53SBob Moore 			valid |= ACPI_VALID_HID;
29295b482a8SLen Brown 		}
29395b482a8SLen Brown 
29495b482a8SLen Brown 		/* Execute the Device._UID method */
29595b482a8SLen Brown 
29615b8dd53SBob Moore 		status = acpi_ut_execute_UID(node, &uid);
29795b482a8SLen Brown 		if (ACPI_SUCCESS(status)) {
29815b8dd53SBob Moore 			info_size += uid->length;
29915b8dd53SBob Moore 			valid |= ACPI_VALID_UID;
30095b482a8SLen Brown 		}
30195b482a8SLen Brown 
30295b482a8SLen Brown 		/* Execute the Device._CID method */
30395b482a8SLen Brown 
30495b482a8SLen Brown 		status = acpi_ut_execute_CID(node, &cid_list);
30595b482a8SLen Brown 		if (ACPI_SUCCESS(status)) {
30615b8dd53SBob Moore 
30715b8dd53SBob Moore 			/* Add size of CID strings and CID pointer array */
30815b8dd53SBob Moore 
30915b8dd53SBob Moore 			info_size +=
31015b8dd53SBob Moore 			    (cid_list->list_size -
31178e25fefSLv Zheng 			     sizeof(struct acpi_pnp_device_id_list));
31215b8dd53SBob Moore 			valid |= ACPI_VALID_CID;
31395b482a8SLen Brown 		}
314f65358e5SSuravee Suthikulpanit 
315f65358e5SSuravee Suthikulpanit 		/* Execute the Device._CLS method */
316f65358e5SSuravee Suthikulpanit 
317f65358e5SSuravee Suthikulpanit 		status = acpi_ut_execute_CLS(node, &cls);
318f65358e5SSuravee Suthikulpanit 		if (ACPI_SUCCESS(status)) {
319f65358e5SSuravee Suthikulpanit 			info_size += cls->length;
320f65358e5SSuravee Suthikulpanit 			valid |= ACPI_VALID_CLS;
321f65358e5SSuravee Suthikulpanit 		}
32215b8dd53SBob Moore 	}
32315b8dd53SBob Moore 
32415b8dd53SBob Moore 	/*
32515b8dd53SBob Moore 	 * Now that we have the variable-length data, we can allocate the
32615b8dd53SBob Moore 	 * return buffer
32715b8dd53SBob Moore 	 */
32815b8dd53SBob Moore 	info = ACPI_ALLOCATE_ZEROED(info_size);
32915b8dd53SBob Moore 	if (!info) {
33015b8dd53SBob Moore 		status = AE_NO_MEMORY;
33115b8dd53SBob Moore 		goto cleanup;
33215b8dd53SBob Moore 	}
33315b8dd53SBob Moore 
33415b8dd53SBob Moore 	/* Get the fixed-length data */
33515b8dd53SBob Moore 
33615b8dd53SBob Moore 	if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
33715b8dd53SBob Moore 		/*
33815b8dd53SBob Moore 		 * Get extra info for ACPI Device/Processor objects only:
339e7c2c3c9SHans de Goede 		 * Run the _ADR and, sx_w, and _sx_d methods.
34015b8dd53SBob Moore 		 *
341a7d5caf6SBob Moore 		 * Notes: none of these methods are required, so they may or may
34215b8dd53SBob Moore 		 * not be present for this device. The Info->Valid bitfield is used
34315b8dd53SBob Moore 		 * to indicate which methods were found and run successfully.
34415b8dd53SBob Moore 		 */
34595b482a8SLen Brown 
34695b482a8SLen Brown 		/* Execute the Device._ADR method */
34795b482a8SLen Brown 
34895b482a8SLen Brown 		status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node,
34995b482a8SLen Brown 							 &info->address);
35095b482a8SLen Brown 		if (ACPI_SUCCESS(status)) {
35115b8dd53SBob Moore 			valid |= ACPI_VALID_ADR;
35215b8dd53SBob Moore 		}
35315b8dd53SBob Moore 
35415b8dd53SBob Moore 		/* Execute the Device._sx_w methods */
35515b8dd53SBob Moore 
35615b8dd53SBob Moore 		status = acpi_ut_execute_power_methods(node,
35715b8dd53SBob Moore 						       acpi_gbl_lowest_dstate_names,
35815b8dd53SBob Moore 						       ACPI_NUM_sx_w_METHODS,
35915b8dd53SBob Moore 						       info->lowest_dstates);
36015b8dd53SBob Moore 		if (ACPI_SUCCESS(status)) {
36115b8dd53SBob Moore 			valid |= ACPI_VALID_SXWS;
36295b482a8SLen Brown 		}
36395b482a8SLen Brown 
36495b482a8SLen Brown 		/* Execute the Device._sx_d methods */
36595b482a8SLen Brown 
36615b8dd53SBob Moore 		status = acpi_ut_execute_power_methods(node,
36715b8dd53SBob Moore 						       acpi_gbl_highest_dstate_names,
36815b8dd53SBob Moore 						       ACPI_NUM_sx_d_METHODS,
36915b8dd53SBob Moore 						       info->highest_dstates);
37095b482a8SLen Brown 		if (ACPI_SUCCESS(status)) {
37115b8dd53SBob Moore 			valid |= ACPI_VALID_SXDS;
37295b482a8SLen Brown 		}
37395b482a8SLen Brown 	}
37495b482a8SLen Brown 
37515b8dd53SBob Moore 	/*
37615b8dd53SBob Moore 	 * Create a pointer to the string area of the return buffer.
37715b8dd53SBob Moore 	 * Point to the end of the base struct acpi_device_info structure.
37815b8dd53SBob Moore 	 */
37915b8dd53SBob Moore 	next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids);
38015b8dd53SBob Moore 	if (cid_list) {
38195b482a8SLen Brown 
38278e25fefSLv Zheng 		/* Point past the CID PNP_DEVICE_ID array */
38315b8dd53SBob Moore 
38415b8dd53SBob Moore 		next_id_string +=
38515b8dd53SBob Moore 		    ((acpi_size)cid_list->count *
38678e25fefSLv Zheng 		     sizeof(struct acpi_pnp_device_id));
38795b482a8SLen Brown 	}
38895b482a8SLen Brown 
38915b8dd53SBob Moore 	/*
39007cb390fSBob Moore 	 * Copy the HID, UID, and CIDs to the return buffer. The variable-length
39107cb390fSBob Moore 	 * strings are copied to the reserved area at the end of the buffer.
39215b8dd53SBob Moore 	 *
39315b8dd53SBob Moore 	 * For HID and CID, check if the ID is a PCI Root Bridge.
39415b8dd53SBob Moore 	 */
39515b8dd53SBob Moore 	if (hid) {
39615b8dd53SBob Moore 		next_id_string = acpi_ns_copy_device_id(&info->hardware_id,
39715b8dd53SBob Moore 							hid, next_id_string);
39895b482a8SLen Brown 
39915b8dd53SBob Moore 		if (acpi_ut_is_pci_root_bridge(hid->string)) {
40015b8dd53SBob Moore 			info->flags |= ACPI_PCI_ROOT_BRIDGE;
40115b8dd53SBob Moore 		}
40215b8dd53SBob Moore 	}
40315b8dd53SBob Moore 
40415b8dd53SBob Moore 	if (uid) {
40515b8dd53SBob Moore 		next_id_string = acpi_ns_copy_device_id(&info->unique_id,
40615b8dd53SBob Moore 							uid, next_id_string);
40715b8dd53SBob Moore 	}
40895b482a8SLen Brown 
40995b482a8SLen Brown 	if (cid_list) {
41015b8dd53SBob Moore 		info->compatible_id_list.count = cid_list->count;
41115b8dd53SBob Moore 		info->compatible_id_list.list_size = cid_list->list_size;
41215b8dd53SBob Moore 
41315b8dd53SBob Moore 		/* Copy each CID */
41415b8dd53SBob Moore 
41515b8dd53SBob Moore 		for (i = 0; i < cid_list->count; i++) {
41615b8dd53SBob Moore 			next_id_string =
41715b8dd53SBob Moore 			    acpi_ns_copy_device_id(&info->compatible_id_list.
41815b8dd53SBob Moore 						   ids[i], &cid_list->ids[i],
41915b8dd53SBob Moore 						   next_id_string);
42015b8dd53SBob Moore 
42115b8dd53SBob Moore 			if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) {
42215b8dd53SBob Moore 				info->flags |= ACPI_PCI_ROOT_BRIDGE;
42315b8dd53SBob Moore 			}
42415b8dd53SBob Moore 		}
42595b482a8SLen Brown 	}
42695b482a8SLen Brown 
427f65358e5SSuravee Suthikulpanit 	if (cls) {
428aaf7566fSBob Moore 		(void)acpi_ns_copy_device_id(&info->class_code,
429f65358e5SSuravee Suthikulpanit 					     cls, next_id_string);
430f65358e5SSuravee Suthikulpanit 	}
431f65358e5SSuravee Suthikulpanit 
43215b8dd53SBob Moore 	/* Copy the fixed-length data */
43315b8dd53SBob Moore 
43415b8dd53SBob Moore 	info->info_size = info_size;
43515b8dd53SBob Moore 	info->type = type;
43615b8dd53SBob Moore 	info->name = name;
43715b8dd53SBob Moore 	info->param_count = param_count;
43815b8dd53SBob Moore 	info->valid = valid;
43915b8dd53SBob Moore 
44015b8dd53SBob Moore 	*return_buffer = info;
44115b8dd53SBob Moore 	status = AE_OK;
44215b8dd53SBob Moore 
44395b482a8SLen Brown cleanup:
44415b8dd53SBob Moore 	if (hid) {
44515b8dd53SBob Moore 		ACPI_FREE(hid);
44615b8dd53SBob Moore 	}
44715b8dd53SBob Moore 	if (uid) {
44815b8dd53SBob Moore 		ACPI_FREE(uid);
44915b8dd53SBob Moore 	}
45095b482a8SLen Brown 	if (cid_list) {
45195b482a8SLen Brown 		ACPI_FREE(cid_list);
45295b482a8SLen Brown 	}
453f65358e5SSuravee Suthikulpanit 	if (cls) {
454f65358e5SSuravee Suthikulpanit 		ACPI_FREE(cls);
455f65358e5SSuravee Suthikulpanit 	}
45695b482a8SLen Brown 	return (status);
45795b482a8SLen Brown }
45895b482a8SLen Brown 
ACPI_EXPORT_SYMBOL(acpi_get_object_info)45995b482a8SLen Brown ACPI_EXPORT_SYMBOL(acpi_get_object_info)
460b2f7ddcfSLin Ming 
461b2f7ddcfSLin Ming /******************************************************************************
462b2f7ddcfSLin Ming  *
463b2f7ddcfSLin Ming  * FUNCTION:    acpi_install_method
464b2f7ddcfSLin Ming  *
465ba494beeSBob Moore  * PARAMETERS:  buffer         - An ACPI table containing one control method
466b2f7ddcfSLin Ming  *
467b2f7ddcfSLin Ming  * RETURN:      Status
468b2f7ddcfSLin Ming  *
469b2f7ddcfSLin Ming  * DESCRIPTION: Install a control method into the namespace. If the method
470b2f7ddcfSLin Ming  *              name already exists in the namespace, it is overwritten. The
471b2f7ddcfSLin Ming  *              input buffer must contain a valid DSDT or SSDT containing a
472b2f7ddcfSLin Ming  *              single control method.
473b2f7ddcfSLin Ming  *
474b2f7ddcfSLin Ming  ******************************************************************************/
475b2f7ddcfSLin Ming acpi_status acpi_install_method(u8 *buffer)
476b2f7ddcfSLin Ming {
477b2f7ddcfSLin Ming 	struct acpi_table_header *table =
478b2f7ddcfSLin Ming 	    ACPI_CAST_PTR(struct acpi_table_header, buffer);
479b2f7ddcfSLin Ming 	u8 *aml_buffer;
480b2f7ddcfSLin Ming 	u8 *aml_start;
481b2f7ddcfSLin Ming 	char *path;
482b2f7ddcfSLin Ming 	struct acpi_namespace_node *node;
483b2f7ddcfSLin Ming 	union acpi_operand_object *method_obj;
484b2f7ddcfSLin Ming 	struct acpi_parse_state parser_state;
485b2f7ddcfSLin Ming 	u32 aml_length;
486b2f7ddcfSLin Ming 	u16 opcode;
487b2f7ddcfSLin Ming 	u8 method_flags;
488b2f7ddcfSLin Ming 	acpi_status status;
489b2f7ddcfSLin Ming 
490b2f7ddcfSLin Ming 	/* Parameter validation */
491b2f7ddcfSLin Ming 
492b2f7ddcfSLin Ming 	if (!buffer) {
4939c0d7939SLv Zheng 		return (AE_BAD_PARAMETER);
494b2f7ddcfSLin Ming 	}
495b2f7ddcfSLin Ming 
496b2f7ddcfSLin Ming 	/* Table must be a DSDT or SSDT */
497b2f7ddcfSLin Ming 
4985599fb69SBob Moore 	if (!ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT) &&
4995599fb69SBob Moore 	    !ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_SSDT)) {
5009c0d7939SLv Zheng 		return (AE_BAD_HEADER);
501b2f7ddcfSLin Ming 	}
502b2f7ddcfSLin Ming 
503b2f7ddcfSLin Ming 	/* First AML opcode in the table must be a control method */
504b2f7ddcfSLin Ming 
505b2f7ddcfSLin Ming 	parser_state.aml = buffer + sizeof(struct acpi_table_header);
506b2f7ddcfSLin Ming 	opcode = acpi_ps_peek_opcode(&parser_state);
507b2f7ddcfSLin Ming 	if (opcode != AML_METHOD_OP) {
5089c0d7939SLv Zheng 		return (AE_BAD_PARAMETER);
509b2f7ddcfSLin Ming 	}
510b2f7ddcfSLin Ming 
511b2f7ddcfSLin Ming 	/* Extract method information from the raw AML */
512b2f7ddcfSLin Ming 
513b2f7ddcfSLin Ming 	parser_state.aml += acpi_ps_get_opcode_size(opcode);
514b2f7ddcfSLin Ming 	parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state);
515b2f7ddcfSLin Ming 	path = acpi_ps_get_next_namestring(&parser_state);
5161fad8738SBob Moore 
517b2f7ddcfSLin Ming 	method_flags = *parser_state.aml++;
518b2f7ddcfSLin Ming 	aml_start = parser_state.aml;
51945bbbbe2SSven Barth 	aml_length = (u32)ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);
520b2f7ddcfSLin Ming 
521b2f7ddcfSLin Ming 	/*
522b2f7ddcfSLin Ming 	 * Allocate resources up-front. We don't want to have to delete a new
523b2f7ddcfSLin Ming 	 * node from the namespace if we cannot allocate memory.
524b2f7ddcfSLin Ming 	 */
525b2f7ddcfSLin Ming 	aml_buffer = ACPI_ALLOCATE(aml_length);
526b2f7ddcfSLin Ming 	if (!aml_buffer) {
5279c0d7939SLv Zheng 		return (AE_NO_MEMORY);
528b2f7ddcfSLin Ming 	}
529b2f7ddcfSLin Ming 
530b2f7ddcfSLin Ming 	method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
531b2f7ddcfSLin Ming 	if (!method_obj) {
532b2f7ddcfSLin Ming 		ACPI_FREE(aml_buffer);
5339c0d7939SLv Zheng 		return (AE_NO_MEMORY);
534b2f7ddcfSLin Ming 	}
535b2f7ddcfSLin Ming 
536b2f7ddcfSLin Ming 	/* Lock namespace for acpi_ns_lookup, we may be creating a new node */
537b2f7ddcfSLin Ming 
538b2f7ddcfSLin Ming 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
539b2f7ddcfSLin Ming 	if (ACPI_FAILURE(status)) {
540b2f7ddcfSLin Ming 		goto error_exit;
541b2f7ddcfSLin Ming 	}
542b2f7ddcfSLin Ming 
543b2f7ddcfSLin Ming 	/* The lookup either returns an existing node or creates a new one */
544b2f7ddcfSLin Ming 
545b2f7ddcfSLin Ming 	status =
546b2f7ddcfSLin Ming 	    acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1,
547b2f7ddcfSLin Ming 			   ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
548b2f7ddcfSLin Ming 			   NULL, &node);
549b2f7ddcfSLin Ming 
550b2f7ddcfSLin Ming 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
551b2f7ddcfSLin Ming 
552b2f7ddcfSLin Ming 	if (ACPI_FAILURE(status)) {	/* ns_lookup */
553b2f7ddcfSLin Ming 		if (status != AE_ALREADY_EXISTS) {
554b2f7ddcfSLin Ming 			goto error_exit;
555b2f7ddcfSLin Ming 		}
556b2f7ddcfSLin Ming 
557b2f7ddcfSLin Ming 		/* Node existed previously, make sure it is a method node */
558b2f7ddcfSLin Ming 
559b2f7ddcfSLin Ming 		if (node->type != ACPI_TYPE_METHOD) {
560b2f7ddcfSLin Ming 			status = AE_TYPE;
561b2f7ddcfSLin Ming 			goto error_exit;
562b2f7ddcfSLin Ming 		}
563b2f7ddcfSLin Ming 	}
564b2f7ddcfSLin Ming 
565b2f7ddcfSLin Ming 	/* Copy the method AML to the local buffer */
566b2f7ddcfSLin Ming 
5674fa4616eSBob Moore 	memcpy(aml_buffer, aml_start, aml_length);
568b2f7ddcfSLin Ming 
569b2f7ddcfSLin Ming 	/* Initialize the method object with the new method's information */
570b2f7ddcfSLin Ming 
571b2f7ddcfSLin Ming 	method_obj->method.aml_start = aml_buffer;
572b2f7ddcfSLin Ming 	method_obj->method.aml_length = aml_length;
573b2f7ddcfSLin Ming 
574b2f7ddcfSLin Ming 	method_obj->method.param_count = (u8)
575b2f7ddcfSLin Ming 	    (method_flags & AML_METHOD_ARG_COUNT);
576b2f7ddcfSLin Ming 
577b2f7ddcfSLin Ming 	if (method_flags & AML_METHOD_SERIALIZED) {
57826294842SLin Ming 		method_obj->method.info_flags = ACPI_METHOD_SERIALIZED;
57926294842SLin Ming 
580b2f7ddcfSLin Ming 		method_obj->method.sync_level = (u8)
581b2f7ddcfSLin Ming 		    ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
582b2f7ddcfSLin Ming 	}
583b2f7ddcfSLin Ming 
584b2f7ddcfSLin Ming 	/*
585b2f7ddcfSLin Ming 	 * Now that it is complete, we can attach the new method object to
586b2f7ddcfSLin Ming 	 * the method Node (detaches/deletes any existing object)
587b2f7ddcfSLin Ming 	 */
588b2f7ddcfSLin Ming 	status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD);
589b2f7ddcfSLin Ming 
590b2f7ddcfSLin Ming 	/*
591b2f7ddcfSLin Ming 	 * Flag indicates AML buffer is dynamic, must be deleted later.
592b2f7ddcfSLin Ming 	 * Must be set only after attach above.
593b2f7ddcfSLin Ming 	 */
594b2f7ddcfSLin Ming 	node->flags |= ANOBJ_ALLOCATED_BUFFER;
595b2f7ddcfSLin Ming 
596b2f7ddcfSLin Ming 	/* Remove local reference to the method object */
597b2f7ddcfSLin Ming 
598b2f7ddcfSLin Ming 	acpi_ut_remove_reference(method_obj);
5999c0d7939SLv Zheng 	return (status);
600b2f7ddcfSLin Ming 
601b2f7ddcfSLin Ming error_exit:
602b2f7ddcfSLin Ming 
603b2f7ddcfSLin Ming 	ACPI_FREE(aml_buffer);
604b2f7ddcfSLin Ming 	ACPI_FREE(method_obj);
6059c0d7939SLv Zheng 	return (status);
606b2f7ddcfSLin Ming }
607b2f7ddcfSLin Ming ACPI_EXPORT_SYMBOL(acpi_install_method)
608