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