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