xref: /OK3568_Linux_fs/kernel/drivers/acpi/acpica/nsxfname.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /******************************************************************************
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Module Name: nsxfname - Public interfaces to the ACPI subsystem
5*4882a593Smuzhiyun  *                         ACPI Namespace oriented interfaces
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (C) 2000 - 2020, Intel Corp.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  *****************************************************************************/
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #define EXPORT_ACPI_INTERFACES
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <acpi/acpi.h>
14*4882a593Smuzhiyun #include "accommon.h"
15*4882a593Smuzhiyun #include "acnamesp.h"
16*4882a593Smuzhiyun #include "acparser.h"
17*4882a593Smuzhiyun #include "amlcode.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define _COMPONENT          ACPI_NAMESPACE
20*4882a593Smuzhiyun ACPI_MODULE_NAME("nsxfname")
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /* Local prototypes */
23*4882a593Smuzhiyun static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,
24*4882a593Smuzhiyun 				    struct acpi_pnp_device_id *source,
25*4882a593Smuzhiyun 				    char *string_area);
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /******************************************************************************
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * FUNCTION:    acpi_get_handle
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * PARAMETERS:  parent          - Object to search under (search scope).
32*4882a593Smuzhiyun  *              pathname        - Pointer to an asciiz string containing the
33*4882a593Smuzhiyun  *                                name
34*4882a593Smuzhiyun  *              ret_handle      - Where the return handle is returned
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * RETURN:      Status
37*4882a593Smuzhiyun  *
38*4882a593Smuzhiyun  * DESCRIPTION: This routine will search for a caller specified name in the
39*4882a593Smuzhiyun  *              name space. The caller can restrict the search region by
40*4882a593Smuzhiyun  *              specifying a non NULL parent. The parent value is itself a
41*4882a593Smuzhiyun  *              namespace handle.
42*4882a593Smuzhiyun  *
43*4882a593Smuzhiyun  ******************************************************************************/
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun acpi_status
acpi_get_handle(acpi_handle parent,acpi_string pathname,acpi_handle * ret_handle)46*4882a593Smuzhiyun acpi_get_handle(acpi_handle parent,
47*4882a593Smuzhiyun 		acpi_string pathname, acpi_handle *ret_handle)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun 	acpi_status status;
50*4882a593Smuzhiyun 	struct acpi_namespace_node *node = NULL;
51*4882a593Smuzhiyun 	struct acpi_namespace_node *prefix_node = NULL;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	ACPI_FUNCTION_ENTRY();
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/* Parameter Validation */
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	if (!ret_handle || !pathname) {
58*4882a593Smuzhiyun 		return (AE_BAD_PARAMETER);
59*4882a593Smuzhiyun 	}
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 	/* Convert a parent handle to a prefix node */
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	if (parent) {
64*4882a593Smuzhiyun 		prefix_node = acpi_ns_validate_handle(parent);
65*4882a593Smuzhiyun 		if (!prefix_node) {
66*4882a593Smuzhiyun 			return (AE_BAD_PARAMETER);
67*4882a593Smuzhiyun 		}
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	/*
71*4882a593Smuzhiyun 	 * Valid cases are:
72*4882a593Smuzhiyun 	 * 1) Fully qualified pathname
73*4882a593Smuzhiyun 	 * 2) Parent + Relative pathname
74*4882a593Smuzhiyun 	 *
75*4882a593Smuzhiyun 	 * Error for <null Parent + relative path>
76*4882a593Smuzhiyun 	 */
77*4882a593Smuzhiyun 	if (ACPI_IS_ROOT_PREFIX(pathname[0])) {
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		/* Pathname is fully qualified (starts with '\') */
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 		/* Special case for root-only, since we can't search for it */
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 		if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) {
84*4882a593Smuzhiyun 			*ret_handle =
85*4882a593Smuzhiyun 			    ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node);
86*4882a593Smuzhiyun 			return (AE_OK);
87*4882a593Smuzhiyun 		}
88*4882a593Smuzhiyun 	} else if (!prefix_node) {
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 		/* Relative path with null prefix is disallowed */
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 		return (AE_BAD_PARAMETER);
93*4882a593Smuzhiyun 	}
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	/* Find the Node and convert to a handle */
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	status =
98*4882a593Smuzhiyun 	    acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
99*4882a593Smuzhiyun 	if (ACPI_SUCCESS(status)) {
100*4882a593Smuzhiyun 		*ret_handle = ACPI_CAST_PTR(acpi_handle, node);
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	return (status);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
ACPI_EXPORT_SYMBOL(acpi_get_handle)106*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_get_handle)
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun /******************************************************************************
109*4882a593Smuzhiyun  *
110*4882a593Smuzhiyun  * FUNCTION:    acpi_get_name
111*4882a593Smuzhiyun  *
112*4882a593Smuzhiyun  * PARAMETERS:  handle          - Handle to be converted to a pathname
113*4882a593Smuzhiyun  *              name_type       - Full pathname or single segment
114*4882a593Smuzhiyun  *              buffer          - Buffer for returned path
115*4882a593Smuzhiyun  *
116*4882a593Smuzhiyun  * RETURN:      Pointer to a string containing the fully qualified Name.
117*4882a593Smuzhiyun  *
118*4882a593Smuzhiyun  * DESCRIPTION: This routine returns the fully qualified name associated with
119*4882a593Smuzhiyun  *              the Handle parameter. This and the acpi_pathname_to_handle are
120*4882a593Smuzhiyun  *              complementary functions.
121*4882a593Smuzhiyun  *
122*4882a593Smuzhiyun  ******************************************************************************/
123*4882a593Smuzhiyun acpi_status
124*4882a593Smuzhiyun acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer)
125*4882a593Smuzhiyun {
126*4882a593Smuzhiyun 	acpi_status status;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	/* Parameter validation */
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (name_type > ACPI_NAME_TYPE_MAX) {
131*4882a593Smuzhiyun 		return (AE_BAD_PARAMETER);
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	status = acpi_ut_validate_buffer(buffer);
135*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
136*4882a593Smuzhiyun 		return (status);
137*4882a593Smuzhiyun 	}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	/*
140*4882a593Smuzhiyun 	 * Wants the single segment ACPI name.
141*4882a593Smuzhiyun 	 * Validate handle and convert to a namespace Node
142*4882a593Smuzhiyun 	 */
143*4882a593Smuzhiyun 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
144*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
145*4882a593Smuzhiyun 		return (status);
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (name_type == ACPI_FULL_PATHNAME ||
149*4882a593Smuzhiyun 	    name_type == ACPI_FULL_PATHNAME_NO_TRAILING) {
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 		/* Get the full pathname (From the namespace root) */
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 		status = acpi_ns_handle_to_pathname(handle, buffer,
154*4882a593Smuzhiyun 						    name_type ==
155*4882a593Smuzhiyun 						    ACPI_FULL_PATHNAME ? FALSE :
156*4882a593Smuzhiyun 						    TRUE);
157*4882a593Smuzhiyun 	} else {
158*4882a593Smuzhiyun 		/* Get the single name */
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 		status = acpi_ns_handle_to_name(handle, buffer);
161*4882a593Smuzhiyun 	}
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
164*4882a593Smuzhiyun 	return (status);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
ACPI_EXPORT_SYMBOL(acpi_get_name)167*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_get_name)
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun /******************************************************************************
170*4882a593Smuzhiyun  *
171*4882a593Smuzhiyun  * FUNCTION:    acpi_ns_copy_device_id
172*4882a593Smuzhiyun  *
173*4882a593Smuzhiyun  * PARAMETERS:  dest                - Pointer to the destination PNP_DEVICE_ID
174*4882a593Smuzhiyun  *              source              - Pointer to the source PNP_DEVICE_ID
175*4882a593Smuzhiyun  *              string_area         - Pointer to where to copy the dest string
176*4882a593Smuzhiyun  *
177*4882a593Smuzhiyun  * RETURN:      Pointer to the next string area
178*4882a593Smuzhiyun  *
179*4882a593Smuzhiyun  * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data.
180*4882a593Smuzhiyun  *
181*4882a593Smuzhiyun  ******************************************************************************/
182*4882a593Smuzhiyun static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest,
183*4882a593Smuzhiyun 				    struct acpi_pnp_device_id *source,
184*4882a593Smuzhiyun 				    char *string_area)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	/* Create the destination PNP_DEVICE_ID */
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	dest->string = string_area;
189*4882a593Smuzhiyun 	dest->length = source->length;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	/* Copy actual string and return a pointer to the next string area */
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	memcpy(string_area, source->string, source->length);
194*4882a593Smuzhiyun 	return (string_area + source->length);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun /******************************************************************************
198*4882a593Smuzhiyun  *
199*4882a593Smuzhiyun  * FUNCTION:    acpi_get_object_info
200*4882a593Smuzhiyun  *
201*4882a593Smuzhiyun  * PARAMETERS:  handle              - Object Handle
202*4882a593Smuzhiyun  *              return_buffer       - Where the info is returned
203*4882a593Smuzhiyun  *
204*4882a593Smuzhiyun  * RETURN:      Status
205*4882a593Smuzhiyun  *
206*4882a593Smuzhiyun  * DESCRIPTION: Returns information about an object as gleaned from the
207*4882a593Smuzhiyun  *              namespace node and possibly by running several standard
208*4882a593Smuzhiyun  *              control methods (Such as in the case of a device.)
209*4882a593Smuzhiyun  *
210*4882a593Smuzhiyun  * For Device and Processor objects, run the Device _HID, _UID, _CID,
211*4882a593Smuzhiyun  * _CLS, _ADR, _sx_w, and _sx_d methods.
212*4882a593Smuzhiyun  *
213*4882a593Smuzhiyun  * Note: Allocates the return buffer, must be freed by the caller.
214*4882a593Smuzhiyun  *
215*4882a593Smuzhiyun  * Note: This interface is intended to be used during the initial device
216*4882a593Smuzhiyun  * discovery namespace traversal. Therefore, no complex methods can be
217*4882a593Smuzhiyun  * executed, especially those that access operation regions. Therefore, do
218*4882a593Smuzhiyun  * not add any additional methods that could cause problems in this area.
219*4882a593Smuzhiyun  * Because of this reason support for the following methods has been removed:
220*4882a593Smuzhiyun  * 1) _SUB method was removed (11/2015)
221*4882a593Smuzhiyun  * 2) _STA method was removed (02/2018)
222*4882a593Smuzhiyun  *
223*4882a593Smuzhiyun  ******************************************************************************/
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun acpi_status
acpi_get_object_info(acpi_handle handle,struct acpi_device_info ** return_buffer)226*4882a593Smuzhiyun acpi_get_object_info(acpi_handle handle,
227*4882a593Smuzhiyun 		     struct acpi_device_info **return_buffer)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun 	struct acpi_namespace_node *node;
230*4882a593Smuzhiyun 	struct acpi_device_info *info;
231*4882a593Smuzhiyun 	struct acpi_pnp_device_id_list *cid_list = NULL;
232*4882a593Smuzhiyun 	struct acpi_pnp_device_id *hid = NULL;
233*4882a593Smuzhiyun 	struct acpi_pnp_device_id *uid = NULL;
234*4882a593Smuzhiyun 	struct acpi_pnp_device_id *cls = NULL;
235*4882a593Smuzhiyun 	char *next_id_string;
236*4882a593Smuzhiyun 	acpi_object_type type;
237*4882a593Smuzhiyun 	acpi_name name;
238*4882a593Smuzhiyun 	u8 param_count = 0;
239*4882a593Smuzhiyun 	u16 valid = 0;
240*4882a593Smuzhiyun 	u32 info_size;
241*4882a593Smuzhiyun 	u32 i;
242*4882a593Smuzhiyun 	acpi_status status;
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	/* Parameter validation */
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (!handle || !return_buffer) {
247*4882a593Smuzhiyun 		return (AE_BAD_PARAMETER);
248*4882a593Smuzhiyun 	}
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
251*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
252*4882a593Smuzhiyun 		return (status);
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	node = acpi_ns_validate_handle(handle);
256*4882a593Smuzhiyun 	if (!node) {
257*4882a593Smuzhiyun 		(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
258*4882a593Smuzhiyun 		return (AE_BAD_PARAMETER);
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	/* Get the namespace node data while the namespace is locked */
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	info_size = sizeof(struct acpi_device_info);
264*4882a593Smuzhiyun 	type = node->type;
265*4882a593Smuzhiyun 	name = node->name.integer;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (node->type == ACPI_TYPE_METHOD) {
268*4882a593Smuzhiyun 		param_count = node->object->method.param_count;
269*4882a593Smuzhiyun 	}
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
272*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
273*4882a593Smuzhiyun 		return (status);
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
277*4882a593Smuzhiyun 		/*
278*4882a593Smuzhiyun 		 * Get extra info for ACPI Device/Processor objects only:
279*4882a593Smuzhiyun 		 * Run the Device _HID, _UID, _CLS, and _CID methods.
280*4882a593Smuzhiyun 		 *
281*4882a593Smuzhiyun 		 * Note: none of these methods are required, so they may or may
282*4882a593Smuzhiyun 		 * not be present for this device. The Info->Valid bitfield is used
283*4882a593Smuzhiyun 		 * to indicate which methods were found and run successfully.
284*4882a593Smuzhiyun 		 */
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 		/* Execute the Device._HID method */
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 		status = acpi_ut_execute_HID(node, &hid);
289*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
290*4882a593Smuzhiyun 			info_size += hid->length;
291*4882a593Smuzhiyun 			valid |= ACPI_VALID_HID;
292*4882a593Smuzhiyun 		}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 		/* Execute the Device._UID method */
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 		status = acpi_ut_execute_UID(node, &uid);
297*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
298*4882a593Smuzhiyun 			info_size += uid->length;
299*4882a593Smuzhiyun 			valid |= ACPI_VALID_UID;
300*4882a593Smuzhiyun 		}
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 		/* Execute the Device._CID method */
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 		status = acpi_ut_execute_CID(node, &cid_list);
305*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 			/* Add size of CID strings and CID pointer array */
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 			info_size +=
310*4882a593Smuzhiyun 			    (cid_list->list_size -
311*4882a593Smuzhiyun 			     sizeof(struct acpi_pnp_device_id_list));
312*4882a593Smuzhiyun 			valid |= ACPI_VALID_CID;
313*4882a593Smuzhiyun 		}
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 		/* Execute the Device._CLS method */
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 		status = acpi_ut_execute_CLS(node, &cls);
318*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
319*4882a593Smuzhiyun 			info_size += cls->length;
320*4882a593Smuzhiyun 			valid |= ACPI_VALID_CLS;
321*4882a593Smuzhiyun 		}
322*4882a593Smuzhiyun 	}
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	/*
325*4882a593Smuzhiyun 	 * Now that we have the variable-length data, we can allocate the
326*4882a593Smuzhiyun 	 * return buffer
327*4882a593Smuzhiyun 	 */
328*4882a593Smuzhiyun 	info = ACPI_ALLOCATE_ZEROED(info_size);
329*4882a593Smuzhiyun 	if (!info) {
330*4882a593Smuzhiyun 		status = AE_NO_MEMORY;
331*4882a593Smuzhiyun 		goto cleanup;
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	/* Get the fixed-length data */
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) {
337*4882a593Smuzhiyun 		/*
338*4882a593Smuzhiyun 		 * Get extra info for ACPI Device/Processor objects only:
339*4882a593Smuzhiyun 		 * Run the _ADR and, sx_w, and _sx_d methods.
340*4882a593Smuzhiyun 		 *
341*4882a593Smuzhiyun 		 * Notes: none of these methods are required, so they may or may
342*4882a593Smuzhiyun 		 * not be present for this device. The Info->Valid bitfield is used
343*4882a593Smuzhiyun 		 * to indicate which methods were found and run successfully.
344*4882a593Smuzhiyun 		 */
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 		/* Execute the Device._ADR method */
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 		status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node,
349*4882a593Smuzhiyun 							 &info->address);
350*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
351*4882a593Smuzhiyun 			valid |= ACPI_VALID_ADR;
352*4882a593Smuzhiyun 		}
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 		/* Execute the Device._sx_w methods */
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 		status = acpi_ut_execute_power_methods(node,
357*4882a593Smuzhiyun 						       acpi_gbl_lowest_dstate_names,
358*4882a593Smuzhiyun 						       ACPI_NUM_sx_w_METHODS,
359*4882a593Smuzhiyun 						       info->lowest_dstates);
360*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
361*4882a593Smuzhiyun 			valid |= ACPI_VALID_SXWS;
362*4882a593Smuzhiyun 		}
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		/* Execute the Device._sx_d methods */
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 		status = acpi_ut_execute_power_methods(node,
367*4882a593Smuzhiyun 						       acpi_gbl_highest_dstate_names,
368*4882a593Smuzhiyun 						       ACPI_NUM_sx_d_METHODS,
369*4882a593Smuzhiyun 						       info->highest_dstates);
370*4882a593Smuzhiyun 		if (ACPI_SUCCESS(status)) {
371*4882a593Smuzhiyun 			valid |= ACPI_VALID_SXDS;
372*4882a593Smuzhiyun 		}
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	/*
376*4882a593Smuzhiyun 	 * Create a pointer to the string area of the return buffer.
377*4882a593Smuzhiyun 	 * Point to the end of the base struct acpi_device_info structure.
378*4882a593Smuzhiyun 	 */
379*4882a593Smuzhiyun 	next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids);
380*4882a593Smuzhiyun 	if (cid_list) {
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 		/* Point past the CID PNP_DEVICE_ID array */
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 		next_id_string +=
385*4882a593Smuzhiyun 		    ((acpi_size)cid_list->count *
386*4882a593Smuzhiyun 		     sizeof(struct acpi_pnp_device_id));
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	/*
390*4882a593Smuzhiyun 	 * Copy the HID, UID, and CIDs to the return buffer. The variable-length
391*4882a593Smuzhiyun 	 * strings are copied to the reserved area at the end of the buffer.
392*4882a593Smuzhiyun 	 *
393*4882a593Smuzhiyun 	 * For HID and CID, check if the ID is a PCI Root Bridge.
394*4882a593Smuzhiyun 	 */
395*4882a593Smuzhiyun 	if (hid) {
396*4882a593Smuzhiyun 		next_id_string = acpi_ns_copy_device_id(&info->hardware_id,
397*4882a593Smuzhiyun 							hid, next_id_string);
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 		if (acpi_ut_is_pci_root_bridge(hid->string)) {
400*4882a593Smuzhiyun 			info->flags |= ACPI_PCI_ROOT_BRIDGE;
401*4882a593Smuzhiyun 		}
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	if (uid) {
405*4882a593Smuzhiyun 		next_id_string = acpi_ns_copy_device_id(&info->unique_id,
406*4882a593Smuzhiyun 							uid, next_id_string);
407*4882a593Smuzhiyun 	}
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	if (cid_list) {
410*4882a593Smuzhiyun 		info->compatible_id_list.count = cid_list->count;
411*4882a593Smuzhiyun 		info->compatible_id_list.list_size = cid_list->list_size;
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 		/* Copy each CID */
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 		for (i = 0; i < cid_list->count; i++) {
416*4882a593Smuzhiyun 			next_id_string =
417*4882a593Smuzhiyun 			    acpi_ns_copy_device_id(&info->compatible_id_list.
418*4882a593Smuzhiyun 						   ids[i], &cid_list->ids[i],
419*4882a593Smuzhiyun 						   next_id_string);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 			if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) {
422*4882a593Smuzhiyun 				info->flags |= ACPI_PCI_ROOT_BRIDGE;
423*4882a593Smuzhiyun 			}
424*4882a593Smuzhiyun 		}
425*4882a593Smuzhiyun 	}
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	if (cls) {
428*4882a593Smuzhiyun 		(void)acpi_ns_copy_device_id(&info->class_code,
429*4882a593Smuzhiyun 					     cls, next_id_string);
430*4882a593Smuzhiyun 	}
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	/* Copy the fixed-length data */
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	info->info_size = info_size;
435*4882a593Smuzhiyun 	info->type = type;
436*4882a593Smuzhiyun 	info->name = name;
437*4882a593Smuzhiyun 	info->param_count = param_count;
438*4882a593Smuzhiyun 	info->valid = valid;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	*return_buffer = info;
441*4882a593Smuzhiyun 	status = AE_OK;
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun cleanup:
444*4882a593Smuzhiyun 	if (hid) {
445*4882a593Smuzhiyun 		ACPI_FREE(hid);
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 	if (uid) {
448*4882a593Smuzhiyun 		ACPI_FREE(uid);
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 	if (cid_list) {
451*4882a593Smuzhiyun 		ACPI_FREE(cid_list);
452*4882a593Smuzhiyun 	}
453*4882a593Smuzhiyun 	if (cls) {
454*4882a593Smuzhiyun 		ACPI_FREE(cls);
455*4882a593Smuzhiyun 	}
456*4882a593Smuzhiyun 	return (status);
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
ACPI_EXPORT_SYMBOL(acpi_get_object_info)459*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_get_object_info)
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun /******************************************************************************
462*4882a593Smuzhiyun  *
463*4882a593Smuzhiyun  * FUNCTION:    acpi_install_method
464*4882a593Smuzhiyun  *
465*4882a593Smuzhiyun  * PARAMETERS:  buffer         - An ACPI table containing one control method
466*4882a593Smuzhiyun  *
467*4882a593Smuzhiyun  * RETURN:      Status
468*4882a593Smuzhiyun  *
469*4882a593Smuzhiyun  * DESCRIPTION: Install a control method into the namespace. If the method
470*4882a593Smuzhiyun  *              name already exists in the namespace, it is overwritten. The
471*4882a593Smuzhiyun  *              input buffer must contain a valid DSDT or SSDT containing a
472*4882a593Smuzhiyun  *              single control method.
473*4882a593Smuzhiyun  *
474*4882a593Smuzhiyun  ******************************************************************************/
475*4882a593Smuzhiyun acpi_status acpi_install_method(u8 *buffer)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun 	struct acpi_table_header *table =
478*4882a593Smuzhiyun 	    ACPI_CAST_PTR(struct acpi_table_header, buffer);
479*4882a593Smuzhiyun 	u8 *aml_buffer;
480*4882a593Smuzhiyun 	u8 *aml_start;
481*4882a593Smuzhiyun 	char *path;
482*4882a593Smuzhiyun 	struct acpi_namespace_node *node;
483*4882a593Smuzhiyun 	union acpi_operand_object *method_obj;
484*4882a593Smuzhiyun 	struct acpi_parse_state parser_state;
485*4882a593Smuzhiyun 	u32 aml_length;
486*4882a593Smuzhiyun 	u16 opcode;
487*4882a593Smuzhiyun 	u8 method_flags;
488*4882a593Smuzhiyun 	acpi_status status;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	/* Parameter validation */
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	if (!buffer) {
493*4882a593Smuzhiyun 		return (AE_BAD_PARAMETER);
494*4882a593Smuzhiyun 	}
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	/* Table must be a DSDT or SSDT */
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	if (!ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT) &&
499*4882a593Smuzhiyun 	    !ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_SSDT)) {
500*4882a593Smuzhiyun 		return (AE_BAD_HEADER);
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	/* First AML opcode in the table must be a control method */
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun 	parser_state.aml = buffer + sizeof(struct acpi_table_header);
506*4882a593Smuzhiyun 	opcode = acpi_ps_peek_opcode(&parser_state);
507*4882a593Smuzhiyun 	if (opcode != AML_METHOD_OP) {
508*4882a593Smuzhiyun 		return (AE_BAD_PARAMETER);
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	/* Extract method information from the raw AML */
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	parser_state.aml += acpi_ps_get_opcode_size(opcode);
514*4882a593Smuzhiyun 	parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state);
515*4882a593Smuzhiyun 	path = acpi_ps_get_next_namestring(&parser_state);
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	method_flags = *parser_state.aml++;
518*4882a593Smuzhiyun 	aml_start = parser_state.aml;
519*4882a593Smuzhiyun 	aml_length = (u32)ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	/*
522*4882a593Smuzhiyun 	 * Allocate resources up-front. We don't want to have to delete a new
523*4882a593Smuzhiyun 	 * node from the namespace if we cannot allocate memory.
524*4882a593Smuzhiyun 	 */
525*4882a593Smuzhiyun 	aml_buffer = ACPI_ALLOCATE(aml_length);
526*4882a593Smuzhiyun 	if (!aml_buffer) {
527*4882a593Smuzhiyun 		return (AE_NO_MEMORY);
528*4882a593Smuzhiyun 	}
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
531*4882a593Smuzhiyun 	if (!method_obj) {
532*4882a593Smuzhiyun 		ACPI_FREE(aml_buffer);
533*4882a593Smuzhiyun 		return (AE_NO_MEMORY);
534*4882a593Smuzhiyun 	}
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	/* Lock namespace for acpi_ns_lookup, we may be creating a new node */
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
539*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
540*4882a593Smuzhiyun 		goto error_exit;
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	/* The lookup either returns an existing node or creates a new one */
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	status =
546*4882a593Smuzhiyun 	    acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1,
547*4882a593Smuzhiyun 			   ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
548*4882a593Smuzhiyun 			   NULL, &node);
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {	/* ns_lookup */
553*4882a593Smuzhiyun 		if (status != AE_ALREADY_EXISTS) {
554*4882a593Smuzhiyun 			goto error_exit;
555*4882a593Smuzhiyun 		}
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 		/* Node existed previously, make sure it is a method node */
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 		if (node->type != ACPI_TYPE_METHOD) {
560*4882a593Smuzhiyun 			status = AE_TYPE;
561*4882a593Smuzhiyun 			goto error_exit;
562*4882a593Smuzhiyun 		}
563*4882a593Smuzhiyun 	}
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	/* Copy the method AML to the local buffer */
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	memcpy(aml_buffer, aml_start, aml_length);
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	/* Initialize the method object with the new method's information */
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun 	method_obj->method.aml_start = aml_buffer;
572*4882a593Smuzhiyun 	method_obj->method.aml_length = aml_length;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	method_obj->method.param_count = (u8)
575*4882a593Smuzhiyun 	    (method_flags & AML_METHOD_ARG_COUNT);
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	if (method_flags & AML_METHOD_SERIALIZED) {
578*4882a593Smuzhiyun 		method_obj->method.info_flags = ACPI_METHOD_SERIALIZED;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 		method_obj->method.sync_level = (u8)
581*4882a593Smuzhiyun 		    ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
582*4882a593Smuzhiyun 	}
583*4882a593Smuzhiyun 
584*4882a593Smuzhiyun 	/*
585*4882a593Smuzhiyun 	 * Now that it is complete, we can attach the new method object to
586*4882a593Smuzhiyun 	 * the method Node (detaches/deletes any existing object)
587*4882a593Smuzhiyun 	 */
588*4882a593Smuzhiyun 	status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD);
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	/*
591*4882a593Smuzhiyun 	 * Flag indicates AML buffer is dynamic, must be deleted later.
592*4882a593Smuzhiyun 	 * Must be set only after attach above.
593*4882a593Smuzhiyun 	 */
594*4882a593Smuzhiyun 	node->flags |= ANOBJ_ALLOCATED_BUFFER;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	/* Remove local reference to the method object */
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	acpi_ut_remove_reference(method_obj);
599*4882a593Smuzhiyun 	return (status);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun error_exit:
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	ACPI_FREE(aml_buffer);
604*4882a593Smuzhiyun 	ACPI_FREE(method_obj);
605*4882a593Smuzhiyun 	return (status);
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun ACPI_EXPORT_SYMBOL(acpi_install_method)
608