162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: utids - support for device Ids - HID, UID, CID, SUB, CLS 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acinterp.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define _COMPONENT ACPI_UTILITIES 1562306a36Sopenharmony_ciACPI_MODULE_NAME("utids") 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/******************************************************************************* 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * FUNCTION: acpi_ut_execute_HID 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * PARAMETERS: device_node - Node for the device 2262306a36Sopenharmony_ci * return_id - Where the string HID is returned 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * RETURN: Status 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * DESCRIPTION: Executes the _HID control method that returns the hardware 2762306a36Sopenharmony_ci * ID of the device. The HID is either an 32-bit encoded EISAID 2862306a36Sopenharmony_ci * Integer or a String. A string is always returned. An EISAID 2962306a36Sopenharmony_ci * is converted to a string. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * NOTE: Internal function, no parameter validation 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci ******************************************************************************/ 3462306a36Sopenharmony_ciacpi_status 3562306a36Sopenharmony_ciacpi_ut_execute_HID(struct acpi_namespace_node *device_node, 3662306a36Sopenharmony_ci struct acpi_pnp_device_id **return_id) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 3962306a36Sopenharmony_ci struct acpi_pnp_device_id *hid; 4062306a36Sopenharmony_ci u32 length; 4162306a36Sopenharmony_ci acpi_status status; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ut_execute_HID); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci status = acpi_ut_evaluate_object(device_node, METHOD_NAME__HID, 4662306a36Sopenharmony_ci ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, 4762306a36Sopenharmony_ci &obj_desc); 4862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 4962306a36Sopenharmony_ci return_ACPI_STATUS(status); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* Get the size of the String to be returned, includes null terminator */ 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci if (obj_desc->common.type == ACPI_TYPE_INTEGER) { 5562306a36Sopenharmony_ci length = ACPI_EISAID_STRING_SIZE; 5662306a36Sopenharmony_ci } else { 5762306a36Sopenharmony_ci length = obj_desc->string.length + 1; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* Allocate a buffer for the HID */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci hid = 6362306a36Sopenharmony_ci ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + 6462306a36Sopenharmony_ci (acpi_size)length); 6562306a36Sopenharmony_ci if (!hid) { 6662306a36Sopenharmony_ci status = AE_NO_MEMORY; 6762306a36Sopenharmony_ci goto cleanup; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Area for the string starts after PNP_DEVICE_ID struct */ 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci hid->string = 7362306a36Sopenharmony_ci ACPI_ADD_PTR(char, hid, sizeof(struct acpi_pnp_device_id)); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* Convert EISAID to a string or simply copy existing string */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (obj_desc->common.type == ACPI_TYPE_INTEGER) { 7862306a36Sopenharmony_ci acpi_ex_eisa_id_to_string(hid->string, obj_desc->integer.value); 7962306a36Sopenharmony_ci } else { 8062306a36Sopenharmony_ci strcpy(hid->string, obj_desc->string.pointer); 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci hid->length = length; 8462306a36Sopenharmony_ci *return_id = hid; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cicleanup: 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* On exit, we must delete the return object */ 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 9162306a36Sopenharmony_ci return_ACPI_STATUS(status); 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/******************************************************************************* 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * FUNCTION: acpi_ut_execute_UID 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * PARAMETERS: device_node - Node for the device 9962306a36Sopenharmony_ci * return_id - Where the string UID is returned 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * RETURN: Status 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * DESCRIPTION: Executes the _UID control method that returns the unique 10462306a36Sopenharmony_ci * ID of the device. The UID is either a 64-bit Integer (NOT an 10562306a36Sopenharmony_ci * EISAID) or a string. Always returns a string. A 64-bit integer 10662306a36Sopenharmony_ci * is converted to a decimal string. 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * NOTE: Internal function, no parameter validation 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci ******************************************************************************/ 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ciacpi_status 11362306a36Sopenharmony_ciacpi_ut_execute_UID(struct acpi_namespace_node *device_node, 11462306a36Sopenharmony_ci struct acpi_pnp_device_id **return_id) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 11762306a36Sopenharmony_ci struct acpi_pnp_device_id *uid; 11862306a36Sopenharmony_ci u32 length; 11962306a36Sopenharmony_ci acpi_status status; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ut_execute_UID); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci status = acpi_ut_evaluate_object(device_node, METHOD_NAME__UID, 12462306a36Sopenharmony_ci ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, 12562306a36Sopenharmony_ci &obj_desc); 12662306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 12762306a36Sopenharmony_ci return_ACPI_STATUS(status); 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Get the size of the String to be returned, includes null terminator */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (obj_desc->common.type == ACPI_TYPE_INTEGER) { 13362306a36Sopenharmony_ci length = ACPI_MAX64_DECIMAL_DIGITS + 1; 13462306a36Sopenharmony_ci } else { 13562306a36Sopenharmony_ci length = obj_desc->string.length + 1; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Allocate a buffer for the UID */ 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci uid = 14162306a36Sopenharmony_ci ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + 14262306a36Sopenharmony_ci (acpi_size)length); 14362306a36Sopenharmony_ci if (!uid) { 14462306a36Sopenharmony_ci status = AE_NO_MEMORY; 14562306a36Sopenharmony_ci goto cleanup; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* Area for the string starts after PNP_DEVICE_ID struct */ 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci uid->string = 15162306a36Sopenharmony_ci ACPI_ADD_PTR(char, uid, sizeof(struct acpi_pnp_device_id)); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Convert an Integer to string, or just copy an existing string */ 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (obj_desc->common.type == ACPI_TYPE_INTEGER) { 15662306a36Sopenharmony_ci acpi_ex_integer_to_string(uid->string, obj_desc->integer.value); 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci strcpy(uid->string, obj_desc->string.pointer); 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci uid->length = length; 16262306a36Sopenharmony_ci *return_id = uid; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cicleanup: 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* On exit, we must delete the return object */ 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 16962306a36Sopenharmony_ci return_ACPI_STATUS(status); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/******************************************************************************* 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * FUNCTION: acpi_ut_execute_CID 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * PARAMETERS: device_node - Node for the device 17762306a36Sopenharmony_ci * return_cid_list - Where the CID list is returned 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * RETURN: Status, list of CID strings 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * DESCRIPTION: Executes the _CID control method that returns one or more 18262306a36Sopenharmony_ci * compatible hardware IDs for the device. 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci * NOTE: Internal function, no parameter validation 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * A _CID method can return either a single compatible ID or a package of 18762306a36Sopenharmony_ci * compatible IDs. Each compatible ID can be one of the following: 18862306a36Sopenharmony_ci * 1) Integer (32 bit compressed EISA ID) or 18962306a36Sopenharmony_ci * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss") 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * The Integer CIDs are converted to string format by this function. 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci ******************************************************************************/ 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ciacpi_status 19662306a36Sopenharmony_ciacpi_ut_execute_CID(struct acpi_namespace_node *device_node, 19762306a36Sopenharmony_ci struct acpi_pnp_device_id_list **return_cid_list) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci union acpi_operand_object **cid_objects; 20062306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 20162306a36Sopenharmony_ci struct acpi_pnp_device_id_list *cid_list; 20262306a36Sopenharmony_ci char *next_id_string; 20362306a36Sopenharmony_ci u32 string_area_size; 20462306a36Sopenharmony_ci u32 length; 20562306a36Sopenharmony_ci u32 cid_list_size; 20662306a36Sopenharmony_ci acpi_status status; 20762306a36Sopenharmony_ci u32 count; 20862306a36Sopenharmony_ci u32 i; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ut_execute_CID); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Evaluate the _CID method for this device */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CID, 21562306a36Sopenharmony_ci ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING 21662306a36Sopenharmony_ci | ACPI_BTYPE_PACKAGE, &obj_desc); 21762306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 21862306a36Sopenharmony_ci return_ACPI_STATUS(status); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * Get the count and size of the returned _CIDs. _CID can return either 22362306a36Sopenharmony_ci * a Package of Integers/Strings or a single Integer or String. 22462306a36Sopenharmony_ci * Note: This section also validates that all CID elements are of the 22562306a36Sopenharmony_ci * correct type (Integer or String). 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { 22862306a36Sopenharmony_ci count = obj_desc->package.count; 22962306a36Sopenharmony_ci cid_objects = obj_desc->package.elements; 23062306a36Sopenharmony_ci } else { /* Single Integer or String CID */ 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci count = 1; 23362306a36Sopenharmony_ci cid_objects = &obj_desc; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci string_area_size = 0; 23762306a36Sopenharmony_ci for (i = 0; i < count; i++) { 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* String lengths include null terminator */ 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci switch (cid_objects[i]->common.type) { 24262306a36Sopenharmony_ci case ACPI_TYPE_INTEGER: 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci string_area_size += ACPI_EISAID_STRING_SIZE; 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci case ACPI_TYPE_STRING: 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci string_area_size += cid_objects[i]->string.length + 1; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci default: 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci status = AE_TYPE; 25562306a36Sopenharmony_ci goto cleanup; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* 26062306a36Sopenharmony_ci * Now that we know the length of the CIDs, allocate return buffer: 26162306a36Sopenharmony_ci * 1) Size of the base structure + 26262306a36Sopenharmony_ci * 2) Size of the CID PNP_DEVICE_ID array + 26362306a36Sopenharmony_ci * 3) Size of the actual CID strings 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci cid_list_size = sizeof(struct acpi_pnp_device_id_list) + 26662306a36Sopenharmony_ci (count * sizeof(struct acpi_pnp_device_id)) + string_area_size; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size); 26962306a36Sopenharmony_ci if (!cid_list) { 27062306a36Sopenharmony_ci status = AE_NO_MEMORY; 27162306a36Sopenharmony_ci goto cleanup; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* Area for CID strings starts after the CID PNP_DEVICE_ID array */ 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci next_id_string = ACPI_CAST_PTR(char, cid_list->ids) + 27762306a36Sopenharmony_ci ((acpi_size)count * sizeof(struct acpi_pnp_device_id)); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* Copy/convert the CIDs to the return buffer */ 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci for (i = 0; i < count; i++) { 28262306a36Sopenharmony_ci if (cid_objects[i]->common.type == ACPI_TYPE_INTEGER) { 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Convert the Integer (EISAID) CID to a string */ 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci acpi_ex_eisa_id_to_string(next_id_string, 28762306a36Sopenharmony_ci cid_objects[i]->integer. 28862306a36Sopenharmony_ci value); 28962306a36Sopenharmony_ci length = ACPI_EISAID_STRING_SIZE; 29062306a36Sopenharmony_ci } else { /* ACPI_TYPE_STRING */ 29162306a36Sopenharmony_ci /* Copy the String CID from the returned object */ 29262306a36Sopenharmony_ci strcpy(next_id_string, cid_objects[i]->string.pointer); 29362306a36Sopenharmony_ci length = cid_objects[i]->string.length + 1; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci cid_list->ids[i].string = next_id_string; 29762306a36Sopenharmony_ci cid_list->ids[i].length = length; 29862306a36Sopenharmony_ci next_id_string += length; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Finish the CID list */ 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci cid_list->count = count; 30462306a36Sopenharmony_ci cid_list->list_size = cid_list_size; 30562306a36Sopenharmony_ci *return_cid_list = cid_list; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cicleanup: 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* On exit, we must delete the _CID return object */ 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 31262306a36Sopenharmony_ci return_ACPI_STATUS(status); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/******************************************************************************* 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * FUNCTION: acpi_ut_execute_CLS 31862306a36Sopenharmony_ci * 31962306a36Sopenharmony_ci * PARAMETERS: device_node - Node for the device 32062306a36Sopenharmony_ci * return_id - Where the _CLS is returned 32162306a36Sopenharmony_ci * 32262306a36Sopenharmony_ci * RETURN: Status 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * DESCRIPTION: Executes the _CLS control method that returns PCI-defined 32562306a36Sopenharmony_ci * class code of the device. The _CLS value is always a package 32662306a36Sopenharmony_ci * containing PCI class information as a list of integers. 32762306a36Sopenharmony_ci * The returned string has format "BBSSPP", where: 32862306a36Sopenharmony_ci * BB = Base-class code 32962306a36Sopenharmony_ci * SS = Sub-class code 33062306a36Sopenharmony_ci * PP = Programming Interface code 33162306a36Sopenharmony_ci * 33262306a36Sopenharmony_ci ******************************************************************************/ 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ciacpi_status 33562306a36Sopenharmony_ciacpi_ut_execute_CLS(struct acpi_namespace_node *device_node, 33662306a36Sopenharmony_ci struct acpi_pnp_device_id **return_id) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 33962306a36Sopenharmony_ci union acpi_operand_object **cls_objects; 34062306a36Sopenharmony_ci u32 count; 34162306a36Sopenharmony_ci struct acpi_pnp_device_id *cls; 34262306a36Sopenharmony_ci u32 length; 34362306a36Sopenharmony_ci acpi_status status; 34462306a36Sopenharmony_ci u8 class_code[3] = { 0, 0, 0 }; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ut_execute_CLS); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci status = acpi_ut_evaluate_object(device_node, METHOD_NAME__CLS, 34962306a36Sopenharmony_ci ACPI_BTYPE_PACKAGE, &obj_desc); 35062306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 35162306a36Sopenharmony_ci return_ACPI_STATUS(status); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* Get the size of the String to be returned, includes null terminator */ 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci length = ACPI_PCICLS_STRING_SIZE; 35762306a36Sopenharmony_ci cls_objects = obj_desc->package.elements; 35862306a36Sopenharmony_ci count = obj_desc->package.count; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (obj_desc->common.type == ACPI_TYPE_PACKAGE) { 36162306a36Sopenharmony_ci if (count > 0 36262306a36Sopenharmony_ci && cls_objects[0]->common.type == ACPI_TYPE_INTEGER) { 36362306a36Sopenharmony_ci class_code[0] = (u8)cls_objects[0]->integer.value; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci if (count > 1 36662306a36Sopenharmony_ci && cls_objects[1]->common.type == ACPI_TYPE_INTEGER) { 36762306a36Sopenharmony_ci class_code[1] = (u8)cls_objects[1]->integer.value; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci if (count > 2 37062306a36Sopenharmony_ci && cls_objects[2]->common.type == ACPI_TYPE_INTEGER) { 37162306a36Sopenharmony_ci class_code[2] = (u8)cls_objects[2]->integer.value; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Allocate a buffer for the CLS */ 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci cls = 37862306a36Sopenharmony_ci ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + 37962306a36Sopenharmony_ci (acpi_size)length); 38062306a36Sopenharmony_ci if (!cls) { 38162306a36Sopenharmony_ci status = AE_NO_MEMORY; 38262306a36Sopenharmony_ci goto cleanup; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci /* Area for the string starts after PNP_DEVICE_ID struct */ 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci cls->string = 38862306a36Sopenharmony_ci ACPI_ADD_PTR(char, cls, sizeof(struct acpi_pnp_device_id)); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* Simply copy existing string */ 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci acpi_ex_pci_cls_to_string(cls->string, class_code); 39362306a36Sopenharmony_ci cls->length = length; 39462306a36Sopenharmony_ci *return_id = cls; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cicleanup: 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* On exit, we must delete the return object */ 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 40162306a36Sopenharmony_ci return_ACPI_STATUS(status); 40262306a36Sopenharmony_ci} 403