Branch data Line data Source code
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 - 2020, 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 : 831 : acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
36 : : struct acpi_pnp_device_id **return_id)
37 : : {
38 : 831 : union acpi_operand_object *obj_desc;
39 : 831 : struct acpi_pnp_device_id *hid;
40 : 831 : u32 length;
41 : 831 : acpi_status status;
42 : :
43 : 831 : ACPI_FUNCTION_TRACE(ut_execute_HID);
44 : :
45 : 831 : status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID,
46 : : ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
47 : : &obj_desc);
48 [ + + ]: 831 : 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 [ + + ]: 288 : if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
55 : : length = ACPI_EISAID_STRING_SIZE;
56 : : } else {
57 : 60 : length = obj_desc->string.length + 1;
58 : : }
59 : :
60 : : /* Allocate a buffer for the HID */
61 : :
62 : 288 : hid =
63 : 288 : ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
64 : : (acpi_size)length);
65 [ - + ]: 288 : if (!hid) {
66 : 0 : status = AE_NO_MEMORY;
67 : 0 : goto cleanup;
68 : : }
69 : :
70 : : /* Area for the string starts after PNP_DEVICE_ID struct */
71 : :
72 : 288 : hid->string =
73 : 288 : 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 [ + + ]: 288 : if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
78 : 228 : acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value);
79 : : } else {
80 : 60 : strcpy(hid->string, obj_desc->string.pointer);
81 : : }
82 : :
83 : 288 : hid->length = length;
84 : 288 : *return_id = hid;
85 : :
86 : 288 : cleanup:
87 : :
88 : : /* On exit, we must delete the return object */
89 : :
90 : 288 : acpi_ut_remove_reference(obj_desc);
91 : 288 : 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 : 330 : acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
114 : : struct acpi_pnp_device_id **return_id)
115 : : {
116 : 330 : union acpi_operand_object *obj_desc;
117 : 330 : struct acpi_pnp_device_id *uid;
118 : 330 : u32 length;
119 : 330 : acpi_status status;
120 : :
121 : 330 : ACPI_FUNCTION_TRACE(ut_execute_UID);
122 : :
123 : 330 : status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID,
124 : : ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING,
125 : : &obj_desc);
126 [ + + ]: 330 : 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 [ + + ]: 72 : if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
133 : : length = ACPI_MAX64_DECIMAL_DIGITS + 1;
134 : : } else {
135 : 18 : length = obj_desc->string.length + 1;
136 : : }
137 : :
138 : : /* Allocate a buffer for the UID */
139 : :
140 : 72 : uid =
141 : 72 : ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
142 : : (acpi_size)length);
143 [ - + ]: 72 : if (!uid) {
144 : 0 : status = AE_NO_MEMORY;
145 : 0 : goto cleanup;
146 : : }
147 : :
148 : : /* Area for the string starts after PNP_DEVICE_ID struct */
149 : :
150 : 72 : uid->string =
151 : 72 : 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 [ + + ]: 72 : if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
156 : 54 : acpi_ex_integer_to_string(uid->string, obj_desc->integer.value);
157 : : } else {
158 : 18 : strcpy(uid->string, obj_desc->string.pointer);
159 : : }
160 : :
161 : 72 : uid->length = length;
162 : 72 : *return_id = uid;
163 : :
164 : 72 : cleanup:
165 : :
166 : : /* On exit, we must delete the return object */
167 : :
168 : 72 : acpi_ut_remove_reference(obj_desc);
169 : 72 : 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 : 501 : acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
197 : : struct acpi_pnp_device_id_list **return_cid_list)
198 : : {
199 : 501 : union acpi_operand_object **cid_objects;
200 : 501 : union acpi_operand_object *obj_desc;
201 : 501 : struct acpi_pnp_device_id_list *cid_list;
202 : 501 : char *next_id_string;
203 : 501 : u32 string_area_size;
204 : 501 : u32 length;
205 : 501 : u32 cid_list_size;
206 : 501 : acpi_status status;
207 : 501 : u32 count;
208 : 501 : u32 i;
209 : :
210 : 501 : ACPI_FUNCTION_TRACE(ut_execute_CID);
211 : :
212 : : /* Evaluate the _CID method for this device */
213 : :
214 : 501 : status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID,
215 : : ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING
216 : : | ACPI_BTYPE_PACKAGE, &obj_desc);
217 [ + + ]: 501 : 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 [ - + ]: 15 : if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
228 : 0 : count = obj_desc->package.count;
229 : 0 : 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 : 15 : string_area_size = 0;
237 [ + + ]: 30 : for (i = 0; i < count; i++) {
238 : :
239 : : /* String lengths include null terminator */
240 : :
241 [ + - - ]: 15 : switch (cid_objects[i]->common.type) {
242 : 15 : case ACPI_TYPE_INTEGER:
243 : :
244 : 15 : string_area_size += ACPI_EISAID_STRING_SIZE;
245 : 15 : break;
246 : :
247 : 0 : case ACPI_TYPE_STRING:
248 : :
249 : 0 : string_area_size += cid_objects[i]->string.length + 1;
250 : 0 : break;
251 : :
252 : 0 : default:
253 : :
254 : 0 : status = AE_TYPE;
255 : 0 : 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 : 15 : cid_list_size = sizeof(struct acpi_pnp_device_id_list) +
266 : 15 : ((count - 1) * sizeof(struct acpi_pnp_device_id)) +
267 : : string_area_size;
268 : :
269 : 15 : cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size);
270 [ - + ]: 15 : if (!cid_list) {
271 : 0 : status = AE_NO_MEMORY;
272 : 0 : goto cleanup;
273 : : }
274 : :
275 : : /* Area for CID strings starts after the CID PNP_DEVICE_ID array */
276 : :
277 : 15 : next_id_string = ACPI_CAST_PTR(char, cid_list->ids) +
278 : 15 : ((acpi_size)count * sizeof(struct acpi_pnp_device_id));
279 : :
280 : : /* Copy/convert the CIDs to the return buffer */
281 : :
282 [ + + ]: 30 : for (i = 0; i < count; i++) {
283 [ + - ]: 15 : if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) {
284 : :
285 : : /* Convert the Integer (EISAID) CID to a string */
286 : :
287 : 15 : acpi_ex_eisa_id_to_string(next_id_string,
288 : : cid_objects[i]->integer.
289 : : value);
290 : 15 : length = ACPI_EISAID_STRING_SIZE;
291 : : } else { /* ACPI_TYPE_STRING */
292 : : /* Copy the String CID from the returned object */
293 : 0 : strcpy(next_id_string, cid_objects[i]->string.pointer);
294 : 0 : length = cid_objects[i]->string.length + 1;
295 : : }
296 : :
297 : 15 : cid_list->ids[i].string = next_id_string;
298 : 15 : cid_list->ids[i].length = length;
299 : 15 : next_id_string += length;
300 : : }
301 : :
302 : : /* Finish the CID list */
303 : :
304 : 15 : cid_list->count = count;
305 : 15 : cid_list->list_size = cid_list_size;
306 : 15 : *return_cid_list = cid_list;
307 : :
308 : 15 : cleanup:
309 : :
310 : : /* On exit, we must delete the _CID return object */
311 : :
312 : 15 : acpi_ut_remove_reference(obj_desc);
313 : 15 : 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 : 330 : acpi_ut_execute_CLS(struct acpi_namespace_node *device_node,
337 : : struct acpi_pnp_device_id **return_id)
338 : : {
339 : 330 : union acpi_operand_object *obj_desc;
340 : 330 : union acpi_operand_object **cls_objects;
341 : 330 : u32 count;
342 : 330 : struct acpi_pnp_device_id *cls;
343 : 330 : u32 length;
344 : 330 : acpi_status status;
345 : 330 : u8 class_code[3] = { 0, 0, 0 };
346 : :
347 : 330 : ACPI_FUNCTION_TRACE(ut_execute_CLS);
348 : :
349 : 330 : status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CLS,
350 : : ACPI_BTYPE_PACKAGE, &obj_desc);
351 [ - + ]: 330 : 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 : 0 : length = ACPI_PCICLS_STRING_SIZE;
358 : 0 : cls_objects = obj_desc->package.elements;
359 : 0 : count = obj_desc->package.count;
360 : :
361 [ # # ]: 0 : if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
362 [ # # ]: 0 : if (count > 0
363 [ # # ]: 0 : && cls_objects[0]->common.type == ACPI_TYPE_INTEGER) {
364 : 0 : class_code[0] = (u8)cls_objects[0]->integer.value;
365 : : }
366 [ # # ]: 0 : if (count > 1
367 [ # # ]: 0 : && cls_objects[1]->common.type == ACPI_TYPE_INTEGER) {
368 : 0 : class_code[1] = (u8)cls_objects[1]->integer.value;
369 : : }
370 [ # # ]: 0 : if (count > 2
371 [ # # ]: 0 : && cls_objects[2]->common.type == ACPI_TYPE_INTEGER) {
372 : 0 : class_code[2] = (u8)cls_objects[2]->integer.value;
373 : : }
374 : : }
375 : :
376 : : /* Allocate a buffer for the CLS */
377 : :
378 : 0 : cls =
379 : 0 : ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) +
380 : : (acpi_size)length);
381 [ # # ]: 0 : if (!cls) {
382 : 0 : status = AE_NO_MEMORY;
383 : 0 : goto cleanup;
384 : : }
385 : :
386 : : /* Area for the string starts after PNP_DEVICE_ID struct */
387 : :
388 : 0 : cls->string =
389 : 0 : ACPI_ADD_PTR(char, cls, sizeof(struct acpi_pnp_device_id));
390 : :
391 : : /* Simply copy existing string */
392 : :
393 : 0 : acpi_ex_pci_cls_to_string(cls->string, class_code);
394 : 0 : cls->length = length;
395 : 0 : *return_id = cls;
396 : :
397 : 0 : cleanup:
398 : :
399 : : /* On exit, we must delete the return object */
400 : :
401 : 0 : acpi_ut_remove_reference(obj_desc);
402 : 0 : return_ACPI_STATUS(status);
403 : : }
|