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