xref: /openbmc/linux/drivers/acpi/acpica/utids.c (revision 4bb1e4e7)
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 - 2019, 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
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
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
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 - 1) * sizeof(struct acpi_pnp_device_id)) +
267 	    string_area_size;
268 
269 	cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size);
270 	if (!cid_list) {
271 		status = AE_NO_MEMORY;
272 		goto cleanup;
273 	}
274 
275 	/* Area for CID strings starts after the CID PNP_DEVICE_ID array */
276 
277 	next_id_string = ACPI_CAST_PTR(char, cid_list->ids) +
278 	    ((acpi_size)count * sizeof(struct acpi_pnp_device_id));
279 
280 	/* Copy/convert the CIDs to the return buffer */
281 
282 	for (i = 0; i < count; i++) {
283 		if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) {
284 
285 			/* Convert the Integer (EISAID) CID to a string */
286 
287 			acpi_ex_eisa_id_to_string(next_id_string,
288 						  cid_objects[i]->integer.
289 						  value);
290 			length = ACPI_EISAID_STRING_SIZE;
291 		} else {	/* ACPI_TYPE_STRING */
292 			/* Copy the String CID from the returned object */
293 			strcpy(next_id_string, cid_objects[i]->string.pointer);
294 			length = cid_objects[i]->string.length + 1;
295 		}
296 
297 		cid_list->ids[i].string = next_id_string;
298 		cid_list->ids[i].length = length;
299 		next_id_string += length;
300 	}
301 
302 	/* Finish the CID list */
303 
304 	cid_list->count = count;
305 	cid_list->list_size = cid_list_size;
306 	*return_cid_list = cid_list;
307 
308 cleanup:
309 
310 	/* On exit, we must delete the _CID return object */
311 
312 	acpi_ut_remove_reference(obj_desc);
313 	return_ACPI_STATUS(status);
314 }
315 
316 /*******************************************************************************
317  *
318  * FUNCTION:    acpi_ut_execute_CLS
319  *
320  * PARAMETERS:  device_node         - Node for the device
321  *              return_id           - Where the _CLS is returned
322  *
323  * RETURN:      Status
324  *
325  * DESCRIPTION: Executes the _CLS control method that returns PCI-defined
326  *              class code of the device. The _CLS value is always a package
327  *              containing PCI class information as a list of integers.
328  *              The returned string has format "BBSSPP", where:
329  *                BB = Base-class code
330  *                SS = Sub-class code
331  *                PP = Programming Interface code
332  *
333  ******************************************************************************/
334 
335 acpi_status
336 acpi_ut_execute_CLS(struct acpi_namespace_node *device_node,
337 		    struct acpi_pnp_device_id **return_id)
338 {
339 	union acpi_operand_object *obj_desc;
340 	union acpi_operand_object **cls_objects;
341 	u32 count;
342 	struct acpi_pnp_device_id *cls;
343 	u32 length;
344 	acpi_status status;
345 	u8 class_code[3] = { 0, 0, 0 };
346 
347 	ACPI_FUNCTION_TRACE(ut_execute_CLS);
348 
349 	status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CLS,
350 					 ACPI_BTYPE_PACKAGE, &obj_desc);
351 	if (ACPI_FAILURE(status)) {
352 		return_ACPI_STATUS(status);
353 	}
354 
355 	/* Get the size of the String to be returned, includes null terminator */
356 
357 	length = ACPI_PCICLS_STRING_SIZE;
358 	cls_objects = obj_desc->package.elements;
359 	count = obj_desc->package.count;
360 
361 	if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
362 		if (count > 0
363 		    && cls_objects[0]->common.type == ACPI_TYPE_INTEGER) {
364 			class_code[0] = (u8)cls_objects[0]->integer.value;
365 		}
366 		if (count > 1
367 		    && cls_objects[1]->common.type == ACPI_TYPE_INTEGER) {
368 			class_code[1] = (u8)cls_objects[1]->integer.value;
369 		}
370 		if (count > 2
371 		    && cls_objects[2]->common.type == ACPI_TYPE_INTEGER) {
372 			class_code[2] = (u8)cls_objects[2]->integer.value;
373 		}
374 	}
375 
376 	/* Allocate a buffer for the CLS */
377 
378 	cls =
379 	    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
380 				 (acpi_size)length);
381 	if (!cls) {
382 		status = AE_NO_MEMORY;
383 		goto cleanup;
384 	}
385 
386 	/* Area for the string starts after PNP_DEVICE_ID struct */
387 
388 	cls->string =
389 	    ACPI_ADD_PTR(char, cls, sizeof(struct acpi_pnp_device_id));
390 
391 	/* Simply copy existing string */
392 
393 	acpi_ex_pci_cls_to_string(cls->string, class_code);
394 	cls->length = length;
395 	*return_id = cls;
396 
397 cleanup:
398 
399 	/* On exit, we must delete the return object */
400 
401 	acpi_ut_remove_reference(obj_desc);
402 	return_ACPI_STATUS(status);
403 }
404