xref: /openbmc/linux/drivers/acpi/acpica/utids.c (revision 612c2932)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: utids - support for device Ids - HID, UID, CID, SUB, CLS
5  *
6  * Copyright (C) 2000 - 2023, Intel Corp.
7  *
8  *****************************************************************************/
9 
10 #include <acpi/acpi.h>
11 #include "accommon.h"
12 #include "acinterp.h"
13 
14 #define _COMPONENT          ACPI_UTILITIES
15 ACPI_MODULE_NAME("utids")
16 
17 /*******************************************************************************
18  *
19  * FUNCTION:    acpi_ut_execute_HID
20  *
21  * PARAMETERS:  device_node         - Node for the device
22  *              return_id           - Where the string HID is returned
23  *
24  * RETURN:      Status
25  *
26  * DESCRIPTION: Executes the _HID control method that returns the hardware
27  *              ID of the device. The HID is either an 32-bit encoded EISAID
28  *              Integer or a String. A string is always returned. An EISAID
29  *              is converted to a string.
30  *
31  *              NOTE: Internal function, no parameter validation
32  *
33  ******************************************************************************/
34 acpi_status
acpi_ut_execute_HID(struct acpi_namespace_node * device_node,struct acpi_pnp_device_id ** return_id)35 acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
36 		    struct acpi_pnp_device_id **return_id)
37 {
38 	union acpi_operand_object *obj_desc;
39 	struct acpi_pnp_device_id *hid;
40 	u32 length;
41 	acpi_status status;
42 
43 	ACPI_FUNCTION_TRACE(ut_execute_HID);
44 
45 	status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID,
46 					 ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
47 					 &obj_desc);
48 	if (ACPI_FAILURE(status)) {
49 		return_ACPI_STATUS(status);
50 	}
51 
52 	/* Get the size of the String to be returned, includes null terminator */
53 
54 	if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
55 		length = ACPI_EISAID_STRING_SIZE;
56 	} else {
57 		length = obj_desc->string.length + 1;
58 	}
59 
60 	/* Allocate a buffer for the HID */
61 
62 	hid =
63 	    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
64 				 (acpi_size)length);
65 	if (!hid) {
66 		status = AE_NO_MEMORY;
67 		goto cleanup;
68 	}
69 
70 	/* Area for the string starts after PNP_DEVICE_ID struct */
71 
72 	hid->string =
73 	    ACPI_ADD_PTR(char, hid, sizeof(struct acpi_pnp_device_id));
74 
75 	/* Convert EISAID to a string or simply copy existing string */
76 
77 	if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
78 		acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value);
79 	} else {
80 		strcpy(hid->string, obj_desc->string.pointer);
81 	}
82 
83 	hid->length = length;
84 	*return_id = hid;
85 
86 cleanup:
87 
88 	/* On exit, we must delete the return object */
89 
90 	acpi_ut_remove_reference(obj_desc);
91 	return_ACPI_STATUS(status);
92 }
93 
94 /*******************************************************************************
95  *
96  * FUNCTION:    acpi_ut_execute_UID
97  *
98  * PARAMETERS:  device_node         - Node for the device
99  *              return_id           - Where the string UID is returned
100  *
101  * RETURN:      Status
102  *
103  * DESCRIPTION: Executes the _UID control method that returns the unique
104  *              ID of the device. The UID is either a 64-bit Integer (NOT an
105  *              EISAID) or a string. Always returns a string. A 64-bit integer
106  *              is converted to a decimal string.
107  *
108  *              NOTE: Internal function, no parameter validation
109  *
110  ******************************************************************************/
111 
112 acpi_status
acpi_ut_execute_UID(struct acpi_namespace_node * device_node,struct acpi_pnp_device_id ** return_id)113 acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
114 		    struct acpi_pnp_device_id **return_id)
115 {
116 	union acpi_operand_object *obj_desc;
117 	struct acpi_pnp_device_id *uid;
118 	u32 length;
119 	acpi_status status;
120 
121 	ACPI_FUNCTION_TRACE(ut_execute_UID);
122 
123 	status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID,
124 					 ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
125 					 &obj_desc);
126 	if (ACPI_FAILURE(status)) {
127 		return_ACPI_STATUS(status);
128 	}
129 
130 	/* Get the size of the String to be returned, includes null terminator */
131 
132 	if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
133 		length = ACPI_MAX64_DECIMAL_DIGITS + 1;
134 	} else {
135 		length = obj_desc->string.length + 1;
136 	}
137 
138 	/* Allocate a buffer for the UID */
139 
140 	uid =
141 	    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
142 				 (acpi_size)length);
143 	if (!uid) {
144 		status = AE_NO_MEMORY;
145 		goto cleanup;
146 	}
147 
148 	/* Area for the string starts after PNP_DEVICE_ID struct */
149 
150 	uid->string =
151 	    ACPI_ADD_PTR(char, uid, sizeof(struct acpi_pnp_device_id));
152 
153 	/* Convert an Integer to string, or just copy an existing string */
154 
155 	if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
156 		acpi_ex_integer_to_string(uid->string, obj_desc->integer.value);
157 	} else {
158 		strcpy(uid->string, obj_desc->string.pointer);
159 	}
160 
161 	uid->length = length;
162 	*return_id = uid;
163 
164 cleanup:
165 
166 	/* On exit, we must delete the return object */
167 
168 	acpi_ut_remove_reference(obj_desc);
169 	return_ACPI_STATUS(status);
170 }
171 
172 /*******************************************************************************
173  *
174  * FUNCTION:    acpi_ut_execute_CID
175  *
176  * PARAMETERS:  device_node         - Node for the device
177  *              return_cid_list     - Where the CID list is returned
178  *
179  * RETURN:      Status, list of CID strings
180  *
181  * DESCRIPTION: Executes the _CID control method that returns one or more
182  *              compatible hardware IDs for the device.
183  *
184  *              NOTE: Internal function, no parameter validation
185  *
186  * A _CID method can return either a single compatible ID or a package of
187  * compatible IDs. Each compatible ID can be one of the following:
188  * 1) Integer (32 bit compressed EISA ID) or
189  * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss")
190  *
191  * The Integer CIDs are converted to string format by this function.
192  *
193  ******************************************************************************/
194 
195 acpi_status
acpi_ut_execute_CID(struct acpi_namespace_node * device_node,struct acpi_pnp_device_id_list ** return_cid_list)196 acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
197 		    struct acpi_pnp_device_id_list **return_cid_list)
198 {
199 	union acpi_operand_object **cid_objects;
200 	union acpi_operand_object *obj_desc;
201 	struct acpi_pnp_device_id_list *cid_list;
202 	char *next_id_string;
203 	u32 string_area_size;
204 	u32 length;
205 	u32 cid_list_size;
206 	acpi_status status;
207 	u32 count;
208 	u32 i;
209 
210 	ACPI_FUNCTION_TRACE(ut_execute_CID);
211 
212 	/* Evaluate the _CID method for this device */
213 
214 	status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID,
215 					 ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING
216 					 | ACPI_BTYPE_PACKAGE, &obj_desc);
217 	if (ACPI_FAILURE(status)) {
218 		return_ACPI_STATUS(status);
219 	}
220 
221 	/*
222 	 * Get the count and size of the returned _CIDs. _CID can return either
223 	 * a Package of Integers/Strings or a single Integer or String.
224 	 * Note: This section also validates that all CID elements are of the
225 	 * correct type (Integer or String).
226 	 */
227 	if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
228 		count = obj_desc->package.count;
229 		cid_objects = obj_desc->package.elements;
230 	} else {		/* Single Integer or String CID */
231 
232 		count = 1;
233 		cid_objects = &obj_desc;
234 	}
235 
236 	string_area_size = 0;
237 	for (i = 0; i < count; i++) {
238 
239 		/* String lengths include null terminator */
240 
241 		switch (cid_objects[i]->common.type) {
242 		case ACPI_TYPE_INTEGER:
243 
244 			string_area_size += ACPI_EISAID_STRING_SIZE;
245 			break;
246 
247 		case ACPI_TYPE_STRING:
248 
249 			string_area_size += cid_objects[i]->string.length + 1;
250 			break;
251 
252 		default:
253 
254 			status = AE_TYPE;
255 			goto cleanup;
256 		}
257 	}
258 
259 	/*
260 	 * Now that we know the length of the CIDs, allocate return buffer:
261 	 * 1) Size of the base structure +
262 	 * 2) Size of the CID PNP_DEVICE_ID array +
263 	 * 3) Size of the actual CID strings
264 	 */
265 	cid_list_size = sizeof(struct acpi_pnp_device_id_list) +
266 	    (count * sizeof(struct acpi_pnp_device_id)) + string_area_size;
267 
268 	cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size);
269 	if (!cid_list) {
270 		status = AE_NO_MEMORY;
271 		goto cleanup;
272 	}
273 
274 	/* Area for CID strings starts after the CID PNP_DEVICE_ID array */
275 
276 	next_id_string = ACPI_CAST_PTR(char, cid_list->ids) +
277 	    ((acpi_size)count * sizeof(struct acpi_pnp_device_id));
278 
279 	/* Copy/convert the CIDs to the return buffer */
280 
281 	for (i = 0; i < count; i++) {
282 		if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) {
283 
284 			/* Convert the Integer (EISAID) CID to a string */
285 
286 			acpi_ex_eisa_id_to_string(next_id_string,
287 						  cid_objects[i]->integer.
288 						  value);
289 			length = ACPI_EISAID_STRING_SIZE;
290 		} else {	/* ACPI_TYPE_STRING */
291 			/* Copy the String CID from the returned object */
292 			strcpy(next_id_string, cid_objects[i]->string.pointer);
293 			length = cid_objects[i]->string.length + 1;
294 		}
295 
296 		cid_list->ids[i].string = next_id_string;
297 		cid_list->ids[i].length = length;
298 		next_id_string += length;
299 	}
300 
301 	/* Finish the CID list */
302 
303 	cid_list->count = count;
304 	cid_list->list_size = cid_list_size;
305 	*return_cid_list = cid_list;
306 
307 cleanup:
308 
309 	/* On exit, we must delete the _CID return object */
310 
311 	acpi_ut_remove_reference(obj_desc);
312 	return_ACPI_STATUS(status);
313 }
314 
315 /*******************************************************************************
316  *
317  * FUNCTION:    acpi_ut_execute_CLS
318  *
319  * PARAMETERS:  device_node         - Node for the device
320  *              return_id           - Where the _CLS is returned
321  *
322  * RETURN:      Status
323  *
324  * DESCRIPTION: Executes the _CLS control method that returns PCI-defined
325  *              class code of the device. The _CLS value is always a package
326  *              containing PCI class information as a list of integers.
327  *              The returned string has format "BBSSPP", where:
328  *                BB = Base-class code
329  *                SS = Sub-class code
330  *                PP = Programming Interface code
331  *
332  ******************************************************************************/
333 
334 acpi_status
acpi_ut_execute_CLS(struct acpi_namespace_node * device_node,struct acpi_pnp_device_id ** return_id)335 acpi_ut_execute_CLS(struct acpi_namespace_node *device_node,
336 		    struct acpi_pnp_device_id **return_id)
337 {
338 	union acpi_operand_object *obj_desc;
339 	union acpi_operand_object **cls_objects;
340 	u32 count;
341 	struct acpi_pnp_device_id *cls;
342 	u32 length;
343 	acpi_status status;
344 	u8 class_code[3] = { 0, 0, 0 };
345 
346 	ACPI_FUNCTION_TRACE(ut_execute_CLS);
347 
348 	status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CLS,
349 					 ACPI_BTYPE_PACKAGE, &obj_desc);
350 	if (ACPI_FAILURE(status)) {
351 		return_ACPI_STATUS(status);
352 	}
353 
354 	/* Get the size of the String to be returned, includes null terminator */
355 
356 	length = ACPI_PCICLS_STRING_SIZE;
357 	cls_objects = obj_desc->package.elements;
358 	count = obj_desc->package.count;
359 
360 	if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
361 		if (count > 0
362 		    && cls_objects[0]->common.type == ACPI_TYPE_INTEGER) {
363 			class_code[0] = (u8)cls_objects[0]->integer.value;
364 		}
365 		if (count > 1
366 		    && cls_objects[1]->common.type == ACPI_TYPE_INTEGER) {
367 			class_code[1] = (u8)cls_objects[1]->integer.value;
368 		}
369 		if (count > 2
370 		    && cls_objects[2]->common.type == ACPI_TYPE_INTEGER) {
371 			class_code[2] = (u8)cls_objects[2]->integer.value;
372 		}
373 	}
374 
375 	/* Allocate a buffer for the CLS */
376 
377 	cls =
378 	    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
379 				 (acpi_size)length);
380 	if (!cls) {
381 		status = AE_NO_MEMORY;
382 		goto cleanup;
383 	}
384 
385 	/* Area for the string starts after PNP_DEVICE_ID struct */
386 
387 	cls->string =
388 	    ACPI_ADD_PTR(char, cls, sizeof(struct acpi_pnp_device_id));
389 
390 	/* Simply copy existing string */
391 
392 	acpi_ex_pci_cls_to_string(cls->string, class_code);
393 	cls->length = length;
394 	*return_id = cls;
395 
396 cleanup:
397 
398 	/* On exit, we must delete the return object */
399 
400 	acpi_ut_remove_reference(obj_desc);
401 	return_ACPI_STATUS(status);
402 }
403