xref: /freebsd/sys/contrib/dev/acpica/components/utilities/utids.c (revision 0e97acdf58fe27b09c4824a474b0344daf997c5f)
1 /******************************************************************************
2  *
3  * Module Name: utids - support for device IDs - HID, UID, CID
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2014, 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 #define __UTIDS_C__
45 
46 #include <contrib/dev/acpica/include/acpi.h>
47 #include <contrib/dev/acpica/include/accommon.h>
48 #include <contrib/dev/acpica/include/acinterp.h>
49 
50 
51 #define _COMPONENT          ACPI_UTILITIES
52         ACPI_MODULE_NAME    ("utids")
53 
54 
55 /*******************************************************************************
56  *
57  * FUNCTION:    AcpiUtExecute_HID
58  *
59  * PARAMETERS:  DeviceNode          - Node for the device
60  *              ReturnId            - Where the string HID is returned
61  *
62  * RETURN:      Status
63  *
64  * DESCRIPTION: Executes the _HID control method that returns the hardware
65  *              ID of the device. The HID is either an 32-bit encoded EISAID
66  *              Integer or a String. A string is always returned. An EISAID
67  *              is converted to a string.
68  *
69  *              NOTE: Internal function, no parameter validation
70  *
71  ******************************************************************************/
72 
73 ACPI_STATUS
74 AcpiUtExecute_HID (
75     ACPI_NAMESPACE_NODE     *DeviceNode,
76     ACPI_PNP_DEVICE_ID      **ReturnId)
77 {
78     ACPI_OPERAND_OBJECT     *ObjDesc;
79     ACPI_PNP_DEVICE_ID      *Hid;
80     UINT32                  Length;
81     ACPI_STATUS             Status;
82 
83 
84     ACPI_FUNCTION_TRACE (UtExecute_HID);
85 
86 
87     Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__HID,
88                 ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &ObjDesc);
89     if (ACPI_FAILURE (Status))
90     {
91         return_ACPI_STATUS (Status);
92     }
93 
94     /* Get the size of the String to be returned, includes null terminator */
95 
96     if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER)
97     {
98         Length = ACPI_EISAID_STRING_SIZE;
99     }
100     else
101     {
102         Length = ObjDesc->String.Length + 1;
103     }
104 
105     /* Allocate a buffer for the HID */
106 
107     Hid = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_PNP_DEVICE_ID) + (ACPI_SIZE) Length);
108     if (!Hid)
109     {
110         Status = AE_NO_MEMORY;
111         goto Cleanup;
112     }
113 
114     /* Area for the string starts after PNP_DEVICE_ID struct */
115 
116     Hid->String = ACPI_ADD_PTR (char, Hid, sizeof (ACPI_PNP_DEVICE_ID));
117 
118     /* Convert EISAID to a string or simply copy existing string */
119 
120     if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER)
121     {
122         AcpiExEisaIdToString (Hid->String, ObjDesc->Integer.Value);
123     }
124     else
125     {
126         ACPI_STRCPY (Hid->String, ObjDesc->String.Pointer);
127     }
128 
129     Hid->Length = Length;
130     *ReturnId = Hid;
131 
132 
133 Cleanup:
134 
135     /* On exit, we must delete the return object */
136 
137     AcpiUtRemoveReference (ObjDesc);
138     return_ACPI_STATUS (Status);
139 }
140 
141 
142 /*******************************************************************************
143  *
144  * FUNCTION:    AcpiUtExecute_SUB
145  *
146  * PARAMETERS:  DeviceNode          - Node for the device
147  *              ReturnId            - Where the _SUB is returned
148  *
149  * RETURN:      Status
150  *
151  * DESCRIPTION: Executes the _SUB control method that returns the subsystem
152  *              ID of the device. The _SUB value is always a string containing
153  *              either a valid PNP or ACPI ID.
154  *
155  *              NOTE: Internal function, no parameter validation
156  *
157  ******************************************************************************/
158 
159 ACPI_STATUS
160 AcpiUtExecute_SUB (
161     ACPI_NAMESPACE_NODE     *DeviceNode,
162     ACPI_PNP_DEVICE_ID      **ReturnId)
163 {
164     ACPI_OPERAND_OBJECT     *ObjDesc;
165     ACPI_PNP_DEVICE_ID      *Sub;
166     UINT32                  Length;
167     ACPI_STATUS             Status;
168 
169 
170     ACPI_FUNCTION_TRACE (UtExecute_SUB);
171 
172 
173     Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__SUB,
174                 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     Length = ObjDesc->String.Length + 1;
183 
184     /* Allocate a buffer for the SUB */
185 
186     Sub = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_PNP_DEVICE_ID) + (ACPI_SIZE) Length);
187     if (!Sub)
188     {
189         Status = AE_NO_MEMORY;
190         goto Cleanup;
191     }
192 
193     /* Area for the string starts after PNP_DEVICE_ID struct */
194 
195     Sub->String = ACPI_ADD_PTR (char, Sub, sizeof (ACPI_PNP_DEVICE_ID));
196 
197     /* Simply copy existing string */
198 
199     ACPI_STRCPY (Sub->String, ObjDesc->String.Pointer);
200     Sub->Length = Length;
201     *ReturnId = Sub;
202 
203 
204 Cleanup:
205 
206     /* On exit, we must delete the return object */
207 
208     AcpiUtRemoveReference (ObjDesc);
209     return_ACPI_STATUS (Status);
210 }
211 
212 
213 /*******************************************************************************
214  *
215  * FUNCTION:    AcpiUtExecute_UID
216  *
217  * PARAMETERS:  DeviceNode          - Node for the device
218  *              ReturnId            - Where the string UID is returned
219  *
220  * RETURN:      Status
221  *
222  * DESCRIPTION: Executes the _UID control method that returns the unique
223  *              ID of the device. The UID is either a 64-bit Integer (NOT an
224  *              EISAID) or a string. Always returns a string. A 64-bit integer
225  *              is converted to a decimal string.
226  *
227  *              NOTE: Internal function, no parameter validation
228  *
229  ******************************************************************************/
230 
231 ACPI_STATUS
232 AcpiUtExecute_UID (
233     ACPI_NAMESPACE_NODE     *DeviceNode,
234     ACPI_PNP_DEVICE_ID      **ReturnId)
235 {
236     ACPI_OPERAND_OBJECT     *ObjDesc;
237     ACPI_PNP_DEVICE_ID      *Uid;
238     UINT32                  Length;
239     ACPI_STATUS             Status;
240 
241 
242     ACPI_FUNCTION_TRACE (UtExecute_UID);
243 
244 
245     Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__UID,
246                 ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &ObjDesc);
247     if (ACPI_FAILURE (Status))
248     {
249         return_ACPI_STATUS (Status);
250     }
251 
252     /* Get the size of the String to be returned, includes null terminator */
253 
254     if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER)
255     {
256         Length = ACPI_MAX64_DECIMAL_DIGITS + 1;
257     }
258     else
259     {
260         Length = ObjDesc->String.Length + 1;
261     }
262 
263     /* Allocate a buffer for the UID */
264 
265     Uid = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_PNP_DEVICE_ID) + (ACPI_SIZE) Length);
266     if (!Uid)
267     {
268         Status = AE_NO_MEMORY;
269         goto Cleanup;
270     }
271 
272     /* Area for the string starts after PNP_DEVICE_ID struct */
273 
274     Uid->String = ACPI_ADD_PTR (char, Uid, sizeof (ACPI_PNP_DEVICE_ID));
275 
276     /* Convert an Integer to string, or just copy an existing string */
277 
278     if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER)
279     {
280         AcpiExIntegerToString (Uid->String, ObjDesc->Integer.Value);
281     }
282     else
283     {
284         ACPI_STRCPY (Uid->String, ObjDesc->String.Pointer);
285     }
286 
287     Uid->Length = Length;
288     *ReturnId = Uid;
289 
290 
291 Cleanup:
292 
293     /* On exit, we must delete the return object */
294 
295     AcpiUtRemoveReference (ObjDesc);
296     return_ACPI_STATUS (Status);
297 }
298 
299 
300 /*******************************************************************************
301  *
302  * FUNCTION:    AcpiUtExecute_CID
303  *
304  * PARAMETERS:  DeviceNode          - Node for the device
305  *              ReturnCidList       - Where the CID list is returned
306  *
307  * RETURN:      Status, list of CID strings
308  *
309  * DESCRIPTION: Executes the _CID control method that returns one or more
310  *              compatible hardware IDs for the device.
311  *
312  *              NOTE: Internal function, no parameter validation
313  *
314  * A _CID method can return either a single compatible ID or a package of
315  * compatible IDs. Each compatible ID can be one of the following:
316  * 1) Integer (32 bit compressed EISA ID) or
317  * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss")
318  *
319  * The Integer CIDs are converted to string format by this function.
320  *
321  ******************************************************************************/
322 
323 ACPI_STATUS
324 AcpiUtExecute_CID (
325     ACPI_NAMESPACE_NODE     *DeviceNode,
326     ACPI_PNP_DEVICE_ID_LIST **ReturnCidList)
327 {
328     ACPI_OPERAND_OBJECT     **CidObjects;
329     ACPI_OPERAND_OBJECT     *ObjDesc;
330     ACPI_PNP_DEVICE_ID_LIST *CidList;
331     char                    *NextIdString;
332     UINT32                  StringAreaSize;
333     UINT32                  Length;
334     UINT32                  CidListSize;
335     ACPI_STATUS             Status;
336     UINT32                  Count;
337     UINT32                  i;
338 
339 
340     ACPI_FUNCTION_TRACE (UtExecute_CID);
341 
342 
343     /* Evaluate the _CID method for this device */
344 
345     Status = AcpiUtEvaluateObject (DeviceNode, METHOD_NAME__CID,
346                 ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_PACKAGE,
347                 &ObjDesc);
348     if (ACPI_FAILURE (Status))
349     {
350         return_ACPI_STATUS (Status);
351     }
352 
353     /*
354      * Get the count and size of the returned _CIDs. _CID can return either
355      * a Package of Integers/Strings or a single Integer or String.
356      * Note: This section also validates that all CID elements are of the
357      * correct type (Integer or String).
358      */
359     if (ObjDesc->Common.Type == ACPI_TYPE_PACKAGE)
360     {
361         Count = ObjDesc->Package.Count;
362         CidObjects = ObjDesc->Package.Elements;
363     }
364     else /* Single Integer or String CID */
365     {
366         Count = 1;
367         CidObjects = &ObjDesc;
368     }
369 
370     StringAreaSize = 0;
371     for (i = 0; i < Count; i++)
372     {
373         /* String lengths include null terminator */
374 
375         switch (CidObjects[i]->Common.Type)
376         {
377         case ACPI_TYPE_INTEGER:
378 
379             StringAreaSize += ACPI_EISAID_STRING_SIZE;
380             break;
381 
382         case ACPI_TYPE_STRING:
383 
384             StringAreaSize += CidObjects[i]->String.Length + 1;
385             break;
386 
387         default:
388 
389             Status = AE_TYPE;
390             goto Cleanup;
391         }
392     }
393 
394     /*
395      * Now that we know the length of the CIDs, allocate return buffer:
396      * 1) Size of the base structure +
397      * 2) Size of the CID PNP_DEVICE_ID array +
398      * 3) Size of the actual CID strings
399      */
400     CidListSize = sizeof (ACPI_PNP_DEVICE_ID_LIST) +
401         ((Count - 1) * sizeof (ACPI_PNP_DEVICE_ID)) +
402         StringAreaSize;
403 
404     CidList = ACPI_ALLOCATE_ZEROED (CidListSize);
405     if (!CidList)
406     {
407         Status = AE_NO_MEMORY;
408         goto Cleanup;
409     }
410 
411     /* Area for CID strings starts after the CID PNP_DEVICE_ID array */
412 
413     NextIdString = ACPI_CAST_PTR (char, CidList->Ids) +
414         ((ACPI_SIZE) Count * sizeof (ACPI_PNP_DEVICE_ID));
415 
416     /* Copy/convert the CIDs to the return buffer */
417 
418     for (i = 0; i < Count; i++)
419     {
420         if (CidObjects[i]->Common.Type == ACPI_TYPE_INTEGER)
421         {
422             /* Convert the Integer (EISAID) CID to a string */
423 
424             AcpiExEisaIdToString (NextIdString, CidObjects[i]->Integer.Value);
425             Length = ACPI_EISAID_STRING_SIZE;
426         }
427         else /* ACPI_TYPE_STRING */
428         {
429             /* Copy the String CID from the returned object */
430 
431             ACPI_STRCPY (NextIdString, CidObjects[i]->String.Pointer);
432             Length = CidObjects[i]->String.Length + 1;
433         }
434 
435         CidList->Ids[i].String = NextIdString;
436         CidList->Ids[i].Length = Length;
437         NextIdString += Length;
438     }
439 
440     /* Finish the CID list */
441 
442     CidList->Count = Count;
443     CidList->ListSize = CidListSize;
444     *ReturnCidList = CidList;
445 
446 
447 Cleanup:
448 
449     /* On exit, we must delete the _CID return object */
450 
451     AcpiUtRemoveReference (ObjDesc);
452     return_ACPI_STATUS (Status);
453 }
454