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