1 | /****************************************************************************** |
2 | * |
3 | * Module Name: utids - support for device IDs - HID, UID, CID, SUB, CLS |
4 | * |
5 | *****************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, Intel Corp. |
9 | * All rights reserved. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions, and the following disclaimer, |
16 | * without modification. |
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
18 | * substantially similar to the "NO WARRANTY" disclaimer below |
19 | * ("Disclaimer") and any redistribution must be conditioned upon |
20 | * including a substantially similar Disclaimer requirement for further |
21 | * binary redistribution. |
22 | * 3. Neither the names of the above-listed copyright holders nor the names |
23 | * of any contributors may be used to endorse or promote products derived |
24 | * from this software without specific prior written permission. |
25 | * |
26 | * Alternatively, this software may be distributed under the terms of the |
27 | * GNU General Public License ("GPL") version 2 as published by the Free |
28 | * Software Foundation. |
29 | * |
30 | * NO WARRANTY |
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
41 | * POSSIBILITY OF SUCH DAMAGES. |
42 | */ |
43 | |
44 | #include "acpi.h" |
45 | #include "accommon.h" |
46 | #include "acinterp.h" |
47 | |
48 | |
49 | #define _COMPONENT ACPI_UTILITIES |
50 | ACPI_MODULE_NAME ("utids" ) |
51 | |
52 | |
53 | /******************************************************************************* |
54 | * |
55 | * FUNCTION: AcpiUtExecute_HID |
56 | * |
57 | * PARAMETERS: DeviceNode - Node for the device |
58 | * ReturnId - Where the string HID is returned |
59 | * |
60 | * RETURN: Status |
61 | * |
62 | * DESCRIPTION: Executes the _HID control method that returns the hardware |
63 | * ID of the device. The HID is either an 32-bit encoded EISAID |
64 | * Integer or a String. A string is always returned. An EISAID |
65 | * is converted to a string. |
66 | * |
67 | * NOTE: Internal function, no parameter validation |
68 | * |
69 | ******************************************************************************/ |
70 | |
71 | ACPI_STATUS |
72 | AcpiUtExecute_HID ( |
73 | ACPI_NAMESPACE_NODE *DeviceNode, |
74 | ACPI_PNP_DEVICE_ID **ReturnId) |
75 | { |
76 | ACPI_OPERAND_OBJECT *ObjDesc; |
77 | ACPI_PNP_DEVICE_ID *Hid; |
78 | UINT32 Length; |
79 | ACPI_STATUS Status; |
80 | |
81 | |
82 | ACPI_FUNCTION_TRACE (UtExecute_HID); |
83 | |
84 | |
85 | Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__HID, |
86 | ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &ObjDesc); |
87 | if (ACPI_FAILURE (Status)) |
88 | { |
89 | return_ACPI_STATUS (Status); |
90 | } |
91 | |
92 | /* Get the size of the String to be returned, includes null terminator */ |
93 | |
94 | if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER) |
95 | { |
96 | Length = ACPI_EISAID_STRING_SIZE; |
97 | } |
98 | else |
99 | { |
100 | Length = ObjDesc->String.Length + 1; |
101 | } |
102 | |
103 | /* Allocate a buffer for the HID */ |
104 | |
105 | Hid = ACPI_ALLOCATE_ZEROED ( |
106 | sizeof (ACPI_PNP_DEVICE_ID) + (ACPI_SIZE) Length); |
107 | if (!Hid) |
108 | { |
109 | Status = AE_NO_MEMORY; |
110 | goto Cleanup; |
111 | } |
112 | |
113 | /* Area for the string starts after PNP_DEVICE_ID struct */ |
114 | |
115 | Hid->String = ACPI_ADD_PTR (char, Hid, sizeof (ACPI_PNP_DEVICE_ID)); |
116 | |
117 | /* Convert EISAID to a string or simply copy existing string */ |
118 | |
119 | if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER) |
120 | { |
121 | AcpiExEisaIdToString (Hid->String, ObjDesc->Integer.Value); |
122 | } |
123 | else |
124 | { |
125 | strcpy (Hid->String, ObjDesc->String.Pointer); |
126 | } |
127 | |
128 | Hid->Length = Length; |
129 | *ReturnId = Hid; |
130 | |
131 | |
132 | Cleanup: |
133 | |
134 | /* On exit, we must delete the return object */ |
135 | |
136 | AcpiUtRemoveReference (ObjDesc); |
137 | return_ACPI_STATUS (Status); |
138 | } |
139 | |
140 | |
141 | /******************************************************************************* |
142 | * |
143 | * FUNCTION: AcpiUtExecute_UID |
144 | * |
145 | * PARAMETERS: DeviceNode - Node for the device |
146 | * ReturnId - Where the string UID is returned |
147 | * |
148 | * RETURN: Status |
149 | * |
150 | * DESCRIPTION: Executes the _UID control method that returns the unique |
151 | * ID of the device. The UID is either a 64-bit Integer (NOT an |
152 | * EISAID) or a string. Always returns a string. A 64-bit integer |
153 | * is converted to a decimal string. |
154 | * |
155 | * NOTE: Internal function, no parameter validation |
156 | * |
157 | ******************************************************************************/ |
158 | |
159 | ACPI_STATUS |
160 | AcpiUtExecute_UID ( |
161 | ACPI_NAMESPACE_NODE *DeviceNode, |
162 | ACPI_PNP_DEVICE_ID **ReturnId) |
163 | { |
164 | ACPI_OPERAND_OBJECT *ObjDesc; |
165 | ACPI_PNP_DEVICE_ID *Uid; |
166 | UINT32 Length; |
167 | ACPI_STATUS Status; |
168 | |
169 | |
170 | ACPI_FUNCTION_TRACE (UtExecute_UID); |
171 | |
172 | |
173 | Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__UID, |
174 | ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &ObjDesc); |
175 | if (ACPI_FAILURE (Status)) |
176 | { |
177 | return_ACPI_STATUS (Status); |
178 | } |
179 | |
180 | /* Get the size of the String to be returned, includes null terminator */ |
181 | |
182 | if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER) |
183 | { |
184 | Length = ACPI_MAX64_DECIMAL_DIGITS + 1; |
185 | } |
186 | else |
187 | { |
188 | Length = ObjDesc->String.Length + 1; |
189 | } |
190 | |
191 | /* Allocate a buffer for the UID */ |
192 | |
193 | Uid = ACPI_ALLOCATE_ZEROED ( |
194 | sizeof (ACPI_PNP_DEVICE_ID) + (ACPI_SIZE) Length); |
195 | if (!Uid) |
196 | { |
197 | Status = AE_NO_MEMORY; |
198 | goto Cleanup; |
199 | } |
200 | |
201 | /* Area for the string starts after PNP_DEVICE_ID struct */ |
202 | |
203 | Uid->String = ACPI_ADD_PTR (char, Uid, sizeof (ACPI_PNP_DEVICE_ID)); |
204 | |
205 | /* Convert an Integer to string, or just copy an existing string */ |
206 | |
207 | if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER) |
208 | { |
209 | AcpiExIntegerToString (Uid->String, ObjDesc->Integer.Value); |
210 | } |
211 | else |
212 | { |
213 | strcpy (Uid->String, ObjDesc->String.Pointer); |
214 | } |
215 | |
216 | Uid->Length = Length; |
217 | *ReturnId = Uid; |
218 | |
219 | |
220 | Cleanup: |
221 | |
222 | /* On exit, we must delete the return object */ |
223 | |
224 | AcpiUtRemoveReference (ObjDesc); |
225 | return_ACPI_STATUS (Status); |
226 | } |
227 | |
228 | |
229 | /******************************************************************************* |
230 | * |
231 | * FUNCTION: AcpiUtExecute_CID |
232 | * |
233 | * PARAMETERS: DeviceNode - Node for the device |
234 | * ReturnCidList - Where the CID list is returned |
235 | * |
236 | * RETURN: Status, list of CID strings |
237 | * |
238 | * DESCRIPTION: Executes the _CID control method that returns one or more |
239 | * compatible hardware IDs for the device. |
240 | * |
241 | * NOTE: Internal function, no parameter validation |
242 | * |
243 | * A _CID method can return either a single compatible ID or a package of |
244 | * compatible IDs. Each compatible ID can be one of the following: |
245 | * 1) Integer (32 bit compressed EISA ID) or |
246 | * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") |
247 | * |
248 | * The Integer CIDs are converted to string format by this function. |
249 | * |
250 | ******************************************************************************/ |
251 | |
252 | ACPI_STATUS |
253 | AcpiUtExecute_CID ( |
254 | ACPI_NAMESPACE_NODE *DeviceNode, |
255 | ACPI_PNP_DEVICE_ID_LIST **ReturnCidList) |
256 | { |
257 | ACPI_OPERAND_OBJECT **CidObjects; |
258 | ACPI_OPERAND_OBJECT *ObjDesc; |
259 | ACPI_PNP_DEVICE_ID_LIST *CidList; |
260 | char *NextIdString; |
261 | UINT32 StringAreaSize; |
262 | UINT32 Length; |
263 | UINT32 CidListSize; |
264 | ACPI_STATUS Status; |
265 | UINT32 Count; |
266 | UINT32 i; |
267 | |
268 | |
269 | ACPI_FUNCTION_TRACE (UtExecute_CID); |
270 | |
271 | |
272 | /* Evaluate the _CID method for this device */ |
273 | |
274 | Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__CID, |
275 | ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_PACKAGE, |
276 | &ObjDesc); |
277 | if (ACPI_FAILURE (Status)) |
278 | { |
279 | return_ACPI_STATUS (Status); |
280 | } |
281 | |
282 | /* |
283 | * Get the count and size of the returned _CIDs. _CID can return either |
284 | * a Package of Integers/Strings or a single Integer or String. |
285 | * Note: This section also validates that all CID elements are of the |
286 | * correct type (Integer or String). |
287 | */ |
288 | if (ObjDesc->Common.Type == ACPI_TYPE_PACKAGE) |
289 | { |
290 | Count = ObjDesc->Package.Count; |
291 | CidObjects = ObjDesc->Package.Elements; |
292 | } |
293 | else /* Single Integer or String CID */ |
294 | { |
295 | Count = 1; |
296 | CidObjects = &ObjDesc; |
297 | } |
298 | |
299 | StringAreaSize = 0; |
300 | for (i = 0; i < Count; i++) |
301 | { |
302 | /* String lengths include null terminator */ |
303 | |
304 | switch (CidObjects[i]->Common.Type) |
305 | { |
306 | case ACPI_TYPE_INTEGER: |
307 | |
308 | StringAreaSize += ACPI_EISAID_STRING_SIZE; |
309 | break; |
310 | |
311 | case ACPI_TYPE_STRING: |
312 | |
313 | StringAreaSize += CidObjects[i]->String.Length + 1; |
314 | break; |
315 | |
316 | default: |
317 | |
318 | Status = AE_TYPE; |
319 | goto Cleanup; |
320 | } |
321 | } |
322 | |
323 | /* |
324 | * Now that we know the length of the CIDs, allocate return buffer: |
325 | * 1) Size of the base structure + |
326 | * 2) Size of the CID PNP_DEVICE_ID array + |
327 | * 3) Size of the actual CID strings |
328 | */ |
329 | CidListSize = sizeof (ACPI_PNP_DEVICE_ID_LIST) + |
330 | ((Count - 1) * sizeof (ACPI_PNP_DEVICE_ID)) + |
331 | StringAreaSize; |
332 | |
333 | CidList = ACPI_ALLOCATE_ZEROED (CidListSize); |
334 | if (!CidList) |
335 | { |
336 | Status = AE_NO_MEMORY; |
337 | goto Cleanup; |
338 | } |
339 | |
340 | /* Area for CID strings starts after the CID PNP_DEVICE_ID array */ |
341 | |
342 | NextIdString = ACPI_CAST_PTR (char, CidList->Ids) + |
343 | ((ACPI_SIZE) Count * sizeof (ACPI_PNP_DEVICE_ID)); |
344 | |
345 | /* Copy/convert the CIDs to the return buffer */ |
346 | |
347 | for (i = 0; i < Count; i++) |
348 | { |
349 | if (CidObjects[i]->Common.Type == ACPI_TYPE_INTEGER) |
350 | { |
351 | /* Convert the Integer (EISAID) CID to a string */ |
352 | |
353 | AcpiExEisaIdToString ( |
354 | NextIdString, CidObjects[i]->Integer.Value); |
355 | Length = ACPI_EISAID_STRING_SIZE; |
356 | } |
357 | else /* ACPI_TYPE_STRING */ |
358 | { |
359 | /* Copy the String CID from the returned object */ |
360 | |
361 | strcpy (NextIdString, CidObjects[i]->String.Pointer); |
362 | Length = CidObjects[i]->String.Length + 1; |
363 | } |
364 | |
365 | CidList->Ids[i].String = NextIdString; |
366 | CidList->Ids[i].Length = Length; |
367 | NextIdString += Length; |
368 | } |
369 | |
370 | /* Finish the CID list */ |
371 | |
372 | CidList->Count = Count; |
373 | CidList->ListSize = CidListSize; |
374 | *ReturnCidList = CidList; |
375 | |
376 | |
377 | Cleanup: |
378 | |
379 | /* On exit, we must delete the _CID return object */ |
380 | |
381 | AcpiUtRemoveReference (ObjDesc); |
382 | return_ACPI_STATUS (Status); |
383 | } |
384 | |
385 | |
386 | /******************************************************************************* |
387 | * |
388 | * FUNCTION: AcpiUtExecute_CLS |
389 | * |
390 | * PARAMETERS: DeviceNode - Node for the device |
391 | * ReturnId - Where the _CLS is returned |
392 | * |
393 | * RETURN: Status |
394 | * |
395 | * DESCRIPTION: Executes the _CLS control method that returns PCI-defined |
396 | * class code of the device. The _CLS value is always a package |
397 | * containing PCI class information as a list of integers. |
398 | * The returned string has format "BBSSPP", where: |
399 | * BB = Base-class code |
400 | * SS = Sub-class code |
401 | * PP = Programming Interface code |
402 | * |
403 | ******************************************************************************/ |
404 | |
405 | ACPI_STATUS |
406 | AcpiUtExecute_CLS ( |
407 | ACPI_NAMESPACE_NODE *DeviceNode, |
408 | ACPI_PNP_DEVICE_ID **ReturnId) |
409 | { |
410 | ACPI_OPERAND_OBJECT *ObjDesc; |
411 | ACPI_OPERAND_OBJECT **ClsObjects; |
412 | UINT32 Count; |
413 | ACPI_PNP_DEVICE_ID *Cls; |
414 | UINT32 Length; |
415 | ACPI_STATUS Status; |
416 | UINT8 ClassCode[3] = {0, 0, 0}; |
417 | |
418 | |
419 | ACPI_FUNCTION_TRACE (UtExecute_CLS); |
420 | |
421 | |
422 | Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__CLS, |
423 | ACPI_BTYPE_PACKAGE, &ObjDesc); |
424 | if (ACPI_FAILURE (Status)) |
425 | { |
426 | return_ACPI_STATUS (Status); |
427 | } |
428 | |
429 | /* Get the size of the String to be returned, includes null terminator */ |
430 | |
431 | Length = ACPI_PCICLS_STRING_SIZE; |
432 | ClsObjects = ObjDesc->Package.Elements; |
433 | Count = ObjDesc->Package.Count; |
434 | |
435 | if (ObjDesc->Common.Type == ACPI_TYPE_PACKAGE) |
436 | { |
437 | if (Count > 0 && ClsObjects[0]->Common.Type == ACPI_TYPE_INTEGER) |
438 | { |
439 | ClassCode[0] = (UINT8) ClsObjects[0]->Integer.Value; |
440 | } |
441 | if (Count > 1 && ClsObjects[1]->Common.Type == ACPI_TYPE_INTEGER) |
442 | { |
443 | ClassCode[1] = (UINT8) ClsObjects[1]->Integer.Value; |
444 | } |
445 | if (Count > 2 && ClsObjects[2]->Common.Type == ACPI_TYPE_INTEGER) |
446 | { |
447 | ClassCode[2] = (UINT8) ClsObjects[2]->Integer.Value; |
448 | } |
449 | } |
450 | |
451 | /* Allocate a buffer for the CLS */ |
452 | |
453 | Cls = ACPI_ALLOCATE_ZEROED ( |
454 | sizeof (ACPI_PNP_DEVICE_ID) + (ACPI_SIZE) Length); |
455 | if (!Cls) |
456 | { |
457 | Status = AE_NO_MEMORY; |
458 | goto Cleanup; |
459 | } |
460 | |
461 | /* Area for the string starts after PNP_DEVICE_ID struct */ |
462 | |
463 | Cls->String = ACPI_ADD_PTR (char, Cls, sizeof (ACPI_PNP_DEVICE_ID)); |
464 | |
465 | /* Simply copy existing string */ |
466 | |
467 | AcpiExPciClsToString (Cls->String, ClassCode); |
468 | Cls->Length = Length; |
469 | *ReturnId = Cls; |
470 | |
471 | |
472 | Cleanup: |
473 | |
474 | /* On exit, we must delete the return object */ |
475 | |
476 | AcpiUtRemoveReference (ObjDesc); |
477 | return_ACPI_STATUS (Status); |
478 | } |
479 | |