1 /****************************************************************************** 2 * 3 * Module Name: utids - support for device IDs - HID, UID, CID 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, 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 /******************************************************************************* 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 ******************************************************************************/ 68 acpi_status 69 acpi_ut_execute_HID(struct acpi_namespace_node *device_node, 70 struct acpica_device_id **return_id) 71 { 72 union acpi_operand_object *obj_desc; 73 struct acpica_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 acpica_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 DEVICE_ID struct */ 105 106 hid->string = ACPI_ADD_PTR(char, hid, sizeof(struct acpica_device_id)); 107 108 /* Convert EISAID to a string or simply copy existing string */ 109 110 if (obj_desc->common.type == ACPI_TYPE_INTEGER) { 111 acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value); 112 } else { 113 ACPI_STRCPY(hid->string, obj_desc->string.pointer); 114 } 115 116 hid->length = length; 117 *return_id = hid; 118 119 cleanup: 120 121 /* On exit, we must delete the return object */ 122 123 acpi_ut_remove_reference(obj_desc); 124 return_ACPI_STATUS(status); 125 } 126 127 /******************************************************************************* 128 * 129 * FUNCTION: acpi_ut_execute_UID 130 * 131 * PARAMETERS: device_node - Node for the device 132 * return_id - Where the string UID is returned 133 * 134 * RETURN: Status 135 * 136 * DESCRIPTION: Executes the _UID control method that returns the unique 137 * ID of the device. The UID is either a 64-bit Integer (NOT an 138 * EISAID) or a string. Always returns a string. A 64-bit integer 139 * is converted to a decimal string. 140 * 141 * NOTE: Internal function, no parameter validation 142 * 143 ******************************************************************************/ 144 145 acpi_status 146 acpi_ut_execute_UID(struct acpi_namespace_node *device_node, 147 struct acpica_device_id **return_id) 148 { 149 union acpi_operand_object *obj_desc; 150 struct acpica_device_id *uid; 151 u32 length; 152 acpi_status status; 153 154 ACPI_FUNCTION_TRACE(ut_execute_UID); 155 156 status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID, 157 ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, 158 &obj_desc); 159 if (ACPI_FAILURE(status)) { 160 return_ACPI_STATUS(status); 161 } 162 163 /* Get the size of the String to be returned, includes null terminator */ 164 165 if (obj_desc->common.type == ACPI_TYPE_INTEGER) { 166 length = ACPI_MAX64_DECIMAL_DIGITS + 1; 167 } else { 168 length = obj_desc->string.length + 1; 169 } 170 171 /* Allocate a buffer for the UID */ 172 173 uid = 174 ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) + 175 (acpi_size) length); 176 if (!uid) { 177 status = AE_NO_MEMORY; 178 goto cleanup; 179 } 180 181 /* Area for the string starts after DEVICE_ID struct */ 182 183 uid->string = ACPI_ADD_PTR(char, uid, sizeof(struct acpica_device_id)); 184 185 /* Convert an Integer to string, or just copy an existing string */ 186 187 if (obj_desc->common.type == ACPI_TYPE_INTEGER) { 188 acpi_ex_integer_to_string(uid->string, obj_desc->integer.value); 189 } else { 190 ACPI_STRCPY(uid->string, obj_desc->string.pointer); 191 } 192 193 uid->length = length; 194 *return_id = uid; 195 196 cleanup: 197 198 /* On exit, we must delete the return object */ 199 200 acpi_ut_remove_reference(obj_desc); 201 return_ACPI_STATUS(status); 202 } 203 204 /******************************************************************************* 205 * 206 * FUNCTION: acpi_ut_execute_CID 207 * 208 * PARAMETERS: device_node - Node for the device 209 * return_cid_list - Where the CID list is returned 210 * 211 * RETURN: Status, list of CID strings 212 * 213 * DESCRIPTION: Executes the _CID control method that returns one or more 214 * compatible hardware IDs for the device. 215 * 216 * NOTE: Internal function, no parameter validation 217 * 218 * A _CID method can return either a single compatible ID or a package of 219 * compatible IDs. Each compatible ID can be one of the following: 220 * 1) Integer (32 bit compressed EISA ID) or 221 * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") 222 * 223 * The Integer CIDs are converted to string format by this function. 224 * 225 ******************************************************************************/ 226 227 acpi_status 228 acpi_ut_execute_CID(struct acpi_namespace_node *device_node, 229 struct acpica_device_id_list **return_cid_list) 230 { 231 union acpi_operand_object **cid_objects; 232 union acpi_operand_object *obj_desc; 233 struct acpica_device_id_list *cid_list; 234 char *next_id_string; 235 u32 string_area_size; 236 u32 length; 237 u32 cid_list_size; 238 acpi_status status; 239 u32 count; 240 u32 i; 241 242 ACPI_FUNCTION_TRACE(ut_execute_CID); 243 244 /* Evaluate the _CID method for this device */ 245 246 status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID, 247 ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING 248 | ACPI_BTYPE_PACKAGE, &obj_desc); 249 if (ACPI_FAILURE(status)) { 250 return_ACPI_STATUS(status); 251 } 252 253 /* 254 * Get the count and size of the returned _CIDs. _CID can return either 255 * a Package of Integers/Strings or a single Integer or String. 256 * Note: This section also validates that all CID elements are of the 257 * correct type (Integer or String). 258 */ 259 if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { 260 count = obj_desc->package.count; 261 cid_objects = obj_desc->package.elements; 262 } else { /* Single Integer or String CID */ 263 264 count = 1; 265 cid_objects = &obj_desc; 266 } 267 268 string_area_size = 0; 269 for (i = 0; i < count; i++) { 270 271 /* String lengths include null terminator */ 272 273 switch (cid_objects[i]->common.type) { 274 case ACPI_TYPE_INTEGER: 275 string_area_size += ACPI_EISAID_STRING_SIZE; 276 break; 277 278 case ACPI_TYPE_STRING: 279 string_area_size += cid_objects[i]->string.length + 1; 280 break; 281 282 default: 283 status = AE_TYPE; 284 goto cleanup; 285 } 286 } 287 288 /* 289 * Now that we know the length of the CIDs, allocate return buffer: 290 * 1) Size of the base structure + 291 * 2) Size of the CID DEVICE_ID array + 292 * 3) Size of the actual CID strings 293 */ 294 cid_list_size = sizeof(struct acpica_device_id_list) + 295 ((count - 1) * sizeof(struct acpica_device_id)) + string_area_size; 296 297 cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size); 298 if (!cid_list) { 299 status = AE_NO_MEMORY; 300 goto cleanup; 301 } 302 303 /* Area for CID strings starts after the CID DEVICE_ID array */ 304 305 next_id_string = ACPI_CAST_PTR(char, cid_list->ids) + 306 ((acpi_size) count * sizeof(struct acpica_device_id)); 307 308 /* Copy/convert the CIDs to the return buffer */ 309 310 for (i = 0; i < count; i++) { 311 if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) { 312 313 /* Convert the Integer (EISAID) CID to a string */ 314 315 acpi_ex_eisa_id_to_string(next_id_string, 316 cid_objects[i]->integer. 317 value); 318 length = ACPI_EISAID_STRING_SIZE; 319 } else { /* ACPI_TYPE_STRING */ 320 321 /* Copy the String CID from the returned object */ 322 323 ACPI_STRCPY(next_id_string, 324 cid_objects[i]->string.pointer); 325 length = cid_objects[i]->string.length + 1; 326 } 327 328 cid_list->ids[i].string = next_id_string; 329 cid_list->ids[i].length = length; 330 next_id_string += length; 331 } 332 333 /* Finish the CID list */ 334 335 cid_list->count = count; 336 cid_list->list_size = cid_list_size; 337 *return_cid_list = cid_list; 338 339 cleanup: 340 341 /* On exit, we must delete the _CID return object */ 342 343 acpi_ut_remove_reference(obj_desc); 344 return_ACPI_STATUS(status); 345 } 346