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 "acpi.h" 47 #include "accommon.h" 48 #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 }