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