162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: nsxfname - Public interfaces to the ACPI subsystem 562306a36Sopenharmony_ci * ACPI Namespace oriented interfaces 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci *****************************************************************************/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define EXPORT_ACPI_INTERFACES 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <acpi/acpi.h> 1462306a36Sopenharmony_ci#include "accommon.h" 1562306a36Sopenharmony_ci#include "acnamesp.h" 1662306a36Sopenharmony_ci#include "acparser.h" 1762306a36Sopenharmony_ci#include "amlcode.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define _COMPONENT ACPI_NAMESPACE 2062306a36Sopenharmony_ciACPI_MODULE_NAME("nsxfname") 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Local prototypes */ 2362306a36Sopenharmony_cistatic char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, 2462306a36Sopenharmony_ci struct acpi_pnp_device_id *source, 2562306a36Sopenharmony_ci char *string_area); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/****************************************************************************** 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * FUNCTION: acpi_get_handle 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * PARAMETERS: parent - Object to search under (search scope). 3262306a36Sopenharmony_ci * pathname - Pointer to an asciiz string containing the 3362306a36Sopenharmony_ci * name 3462306a36Sopenharmony_ci * ret_handle - Where the return handle is returned 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * RETURN: Status 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * DESCRIPTION: This routine will search for a caller specified name in the 3962306a36Sopenharmony_ci * name space. The caller can restrict the search region by 4062306a36Sopenharmony_ci * specifying a non NULL parent. The parent value is itself a 4162306a36Sopenharmony_ci * namespace handle. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci ******************************************************************************/ 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciacpi_status 4662306a36Sopenharmony_ciacpi_get_handle(acpi_handle parent, 4762306a36Sopenharmony_ci const char *pathname, acpi_handle *ret_handle) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci acpi_status status; 5062306a36Sopenharmony_ci struct acpi_namespace_node *node = NULL; 5162306a36Sopenharmony_ci struct acpi_namespace_node *prefix_node = NULL; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci ACPI_FUNCTION_ENTRY(); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* Parameter Validation */ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (!ret_handle || !pathname) { 5862306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci /* Convert a parent handle to a prefix node */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (parent) { 6462306a36Sopenharmony_ci prefix_node = acpi_ns_validate_handle(parent); 6562306a36Sopenharmony_ci if (!prefix_node) { 6662306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * Valid cases are: 7262306a36Sopenharmony_ci * 1) Fully qualified pathname 7362306a36Sopenharmony_ci * 2) Parent + Relative pathname 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * Error for <null Parent + relative path> 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci if (ACPI_IS_ROOT_PREFIX(pathname[0])) { 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* Pathname is fully qualified (starts with '\') */ 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* Special case for root-only, since we can't search for it */ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci if (!strcmp(pathname, ACPI_NS_ROOT_PATH)) { 8462306a36Sopenharmony_ci *ret_handle = 8562306a36Sopenharmony_ci ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node); 8662306a36Sopenharmony_ci return (AE_OK); 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci } else if (!prefix_node) { 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* Relative path with null prefix is disallowed */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* Find the Node and convert to a handle */ 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci status = 9862306a36Sopenharmony_ci acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); 9962306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 10062306a36Sopenharmony_ci *ret_handle = ACPI_CAST_PTR(acpi_handle, node); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return (status); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_handle) 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/****************************************************************************** 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * FUNCTION: acpi_get_name 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * PARAMETERS: handle - Handle to be converted to a pathname 11362306a36Sopenharmony_ci * name_type - Full pathname or single segment 11462306a36Sopenharmony_ci * buffer - Buffer for returned path 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * RETURN: Pointer to a string containing the fully qualified Name. 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * DESCRIPTION: This routine returns the fully qualified name associated with 11962306a36Sopenharmony_ci * the Handle parameter. This and the acpi_pathname_to_handle are 12062306a36Sopenharmony_ci * complementary functions. 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci ******************************************************************************/ 12362306a36Sopenharmony_ciacpi_status 12462306a36Sopenharmony_ciacpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer *buffer) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci acpi_status status; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci /* Parameter validation */ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (name_type > ACPI_NAME_TYPE_MAX) { 13162306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci status = acpi_ut_validate_buffer(buffer); 13562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 13662306a36Sopenharmony_ci return (status); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* 14062306a36Sopenharmony_ci * Wants the single segment ACPI name. 14162306a36Sopenharmony_ci * Validate handle and convert to a namespace Node 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 14462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 14562306a36Sopenharmony_ci return (status); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (name_type == ACPI_FULL_PATHNAME || 14962306a36Sopenharmony_ci name_type == ACPI_FULL_PATHNAME_NO_TRAILING) { 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Get the full pathname (From the namespace root) */ 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci status = acpi_ns_handle_to_pathname(handle, buffer, 15462306a36Sopenharmony_ci name_type == 15562306a36Sopenharmony_ci ACPI_FULL_PATHNAME ? FALSE : 15662306a36Sopenharmony_ci TRUE); 15762306a36Sopenharmony_ci } else { 15862306a36Sopenharmony_ci /* Get the single name */ 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci status = acpi_ns_handle_to_name(handle, buffer); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 16462306a36Sopenharmony_ci return (status); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_name) 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/****************************************************************************** 17062306a36Sopenharmony_ci * 17162306a36Sopenharmony_ci * FUNCTION: acpi_ns_copy_device_id 17262306a36Sopenharmony_ci * 17362306a36Sopenharmony_ci * PARAMETERS: dest - Pointer to the destination PNP_DEVICE_ID 17462306a36Sopenharmony_ci * source - Pointer to the source PNP_DEVICE_ID 17562306a36Sopenharmony_ci * string_area - Pointer to where to copy the dest string 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * RETURN: Pointer to the next string area 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data. 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci ******************************************************************************/ 18262306a36Sopenharmony_cistatic char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, 18362306a36Sopenharmony_ci struct acpi_pnp_device_id *source, 18462306a36Sopenharmony_ci char *string_area) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci /* Create the destination PNP_DEVICE_ID */ 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci dest->string = string_area; 18962306a36Sopenharmony_ci dest->length = source->length; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* Copy actual string and return a pointer to the next string area */ 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci memcpy(string_area, source->string, source->length); 19462306a36Sopenharmony_ci return (string_area + source->length); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/****************************************************************************** 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * FUNCTION: acpi_get_object_info 20062306a36Sopenharmony_ci * 20162306a36Sopenharmony_ci * PARAMETERS: handle - Object Handle 20262306a36Sopenharmony_ci * return_buffer - Where the info is returned 20362306a36Sopenharmony_ci * 20462306a36Sopenharmony_ci * RETURN: Status 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * DESCRIPTION: Returns information about an object as gleaned from the 20762306a36Sopenharmony_ci * namespace node and possibly by running several standard 20862306a36Sopenharmony_ci * control methods (Such as in the case of a device.) 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * For Device and Processor objects, run the Device _HID, _UID, _CID, 21162306a36Sopenharmony_ci * _CLS, _ADR, _sx_w, and _sx_d methods. 21262306a36Sopenharmony_ci * 21362306a36Sopenharmony_ci * Note: Allocates the return buffer, must be freed by the caller. 21462306a36Sopenharmony_ci * 21562306a36Sopenharmony_ci * Note: This interface is intended to be used during the initial device 21662306a36Sopenharmony_ci * discovery namespace traversal. Therefore, no complex methods can be 21762306a36Sopenharmony_ci * executed, especially those that access operation regions. Therefore, do 21862306a36Sopenharmony_ci * not add any additional methods that could cause problems in this area. 21962306a36Sopenharmony_ci * Because of this reason support for the following methods has been removed: 22062306a36Sopenharmony_ci * 1) _SUB method was removed (11/2015) 22162306a36Sopenharmony_ci * 2) _STA method was removed (02/2018) 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci ******************************************************************************/ 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ciacpi_status 22662306a36Sopenharmony_ciacpi_get_object_info(acpi_handle handle, 22762306a36Sopenharmony_ci struct acpi_device_info **return_buffer) 22862306a36Sopenharmony_ci{ 22962306a36Sopenharmony_ci struct acpi_namespace_node *node; 23062306a36Sopenharmony_ci struct acpi_device_info *info; 23162306a36Sopenharmony_ci struct acpi_pnp_device_id_list *cid_list = NULL; 23262306a36Sopenharmony_ci struct acpi_pnp_device_id *hid = NULL; 23362306a36Sopenharmony_ci struct acpi_pnp_device_id *uid = NULL; 23462306a36Sopenharmony_ci struct acpi_pnp_device_id *cls = NULL; 23562306a36Sopenharmony_ci char *next_id_string; 23662306a36Sopenharmony_ci acpi_object_type type; 23762306a36Sopenharmony_ci acpi_name name; 23862306a36Sopenharmony_ci u8 param_count = 0; 23962306a36Sopenharmony_ci u16 valid = 0; 24062306a36Sopenharmony_ci u32 info_size; 24162306a36Sopenharmony_ci u32 i; 24262306a36Sopenharmony_ci acpi_status status; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* Parameter validation */ 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (!handle || !return_buffer) { 24762306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 25162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 25262306a36Sopenharmony_ci return (status); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci node = acpi_ns_validate_handle(handle); 25662306a36Sopenharmony_ci if (!node) { 25762306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 25862306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* Get the namespace node data while the namespace is locked */ 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci info_size = sizeof(struct acpi_device_info); 26462306a36Sopenharmony_ci type = node->type; 26562306a36Sopenharmony_ci name = node->name.integer; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (node->type == ACPI_TYPE_METHOD) { 26862306a36Sopenharmony_ci param_count = node->object->method.param_count; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 27262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 27362306a36Sopenharmony_ci return (status); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { 27762306a36Sopenharmony_ci /* 27862306a36Sopenharmony_ci * Get extra info for ACPI Device/Processor objects only: 27962306a36Sopenharmony_ci * Run the Device _HID, _UID, _CLS, and _CID methods. 28062306a36Sopenharmony_ci * 28162306a36Sopenharmony_ci * Note: none of these methods are required, so they may or may 28262306a36Sopenharmony_ci * not be present for this device. The Info->Valid bitfield is used 28362306a36Sopenharmony_ci * to indicate which methods were found and run successfully. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Execute the Device._HID method */ 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci status = acpi_ut_execute_HID(node, &hid); 28962306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 29062306a36Sopenharmony_ci info_size += hid->length; 29162306a36Sopenharmony_ci valid |= ACPI_VALID_HID; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* Execute the Device._UID method */ 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci status = acpi_ut_execute_UID(node, &uid); 29762306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 29862306a36Sopenharmony_ci info_size += uid->length; 29962306a36Sopenharmony_ci valid |= ACPI_VALID_UID; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* Execute the Device._CID method */ 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci status = acpi_ut_execute_CID(node, &cid_list); 30562306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* Add size of CID strings and CID pointer array */ 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci info_size += 31062306a36Sopenharmony_ci (cid_list->list_size - 31162306a36Sopenharmony_ci sizeof(struct acpi_pnp_device_id_list)); 31262306a36Sopenharmony_ci valid |= ACPI_VALID_CID; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Execute the Device._CLS method */ 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci status = acpi_ut_execute_CLS(node, &cls); 31862306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 31962306a36Sopenharmony_ci info_size += cls->length; 32062306a36Sopenharmony_ci valid |= ACPI_VALID_CLS; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* 32562306a36Sopenharmony_ci * Now that we have the variable-length data, we can allocate the 32662306a36Sopenharmony_ci * return buffer 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci info = ACPI_ALLOCATE_ZEROED(info_size); 32962306a36Sopenharmony_ci if (!info) { 33062306a36Sopenharmony_ci status = AE_NO_MEMORY; 33162306a36Sopenharmony_ci goto cleanup; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Get the fixed-length data */ 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { 33762306a36Sopenharmony_ci /* 33862306a36Sopenharmony_ci * Get extra info for ACPI Device/Processor objects only: 33962306a36Sopenharmony_ci * Run the _ADR and, sx_w, and _sx_d methods. 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci * Notes: none of these methods are required, so they may or may 34262306a36Sopenharmony_ci * not be present for this device. The Info->Valid bitfield is used 34362306a36Sopenharmony_ci * to indicate which methods were found and run successfully. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Execute the Device._ADR method */ 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, node, 34962306a36Sopenharmony_ci &info->address); 35062306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 35162306a36Sopenharmony_ci valid |= ACPI_VALID_ADR; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* Execute the Device._sx_w methods */ 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci status = acpi_ut_execute_power_methods(node, 35762306a36Sopenharmony_ci acpi_gbl_lowest_dstate_names, 35862306a36Sopenharmony_ci ACPI_NUM_sx_w_METHODS, 35962306a36Sopenharmony_ci info->lowest_dstates); 36062306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 36162306a36Sopenharmony_ci valid |= ACPI_VALID_SXWS; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* Execute the Device._sx_d methods */ 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci status = acpi_ut_execute_power_methods(node, 36762306a36Sopenharmony_ci acpi_gbl_highest_dstate_names, 36862306a36Sopenharmony_ci ACPI_NUM_sx_d_METHODS, 36962306a36Sopenharmony_ci info->highest_dstates); 37062306a36Sopenharmony_ci if (ACPI_SUCCESS(status)) { 37162306a36Sopenharmony_ci valid |= ACPI_VALID_SXDS; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* 37662306a36Sopenharmony_ci * Create a pointer to the string area of the return buffer. 37762306a36Sopenharmony_ci * Point to the end of the base struct acpi_device_info structure. 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids); 38062306a36Sopenharmony_ci if (cid_list) { 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* Point past the CID PNP_DEVICE_ID array */ 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci next_id_string += 38562306a36Sopenharmony_ci ((acpi_size)cid_list->count * 38662306a36Sopenharmony_ci sizeof(struct acpi_pnp_device_id)); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* 39062306a36Sopenharmony_ci * Copy the HID, UID, and CIDs to the return buffer. The variable-length 39162306a36Sopenharmony_ci * strings are copied to the reserved area at the end of the buffer. 39262306a36Sopenharmony_ci * 39362306a36Sopenharmony_ci * For HID and CID, check if the ID is a PCI Root Bridge. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ci if (hid) { 39662306a36Sopenharmony_ci next_id_string = acpi_ns_copy_device_id(&info->hardware_id, 39762306a36Sopenharmony_ci hid, next_id_string); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (acpi_ut_is_pci_root_bridge(hid->string)) { 40062306a36Sopenharmony_ci info->flags |= ACPI_PCI_ROOT_BRIDGE; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (uid) { 40562306a36Sopenharmony_ci next_id_string = acpi_ns_copy_device_id(&info->unique_id, 40662306a36Sopenharmony_ci uid, next_id_string); 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (cid_list) { 41062306a36Sopenharmony_ci info->compatible_id_list.count = cid_list->count; 41162306a36Sopenharmony_ci info->compatible_id_list.list_size = cid_list->list_size; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Copy each CID */ 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci for (i = 0; i < cid_list->count; i++) { 41662306a36Sopenharmony_ci next_id_string = 41762306a36Sopenharmony_ci acpi_ns_copy_device_id(&info->compatible_id_list. 41862306a36Sopenharmony_ci ids[i], &cid_list->ids[i], 41962306a36Sopenharmony_ci next_id_string); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (acpi_ut_is_pci_root_bridge(cid_list->ids[i].string)) { 42262306a36Sopenharmony_ci info->flags |= ACPI_PCI_ROOT_BRIDGE; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (cls) { 42862306a36Sopenharmony_ci (void)acpi_ns_copy_device_id(&info->class_code, 42962306a36Sopenharmony_ci cls, next_id_string); 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* Copy the fixed-length data */ 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci info->info_size = info_size; 43562306a36Sopenharmony_ci info->type = type; 43662306a36Sopenharmony_ci info->name = name; 43762306a36Sopenharmony_ci info->param_count = param_count; 43862306a36Sopenharmony_ci info->valid = valid; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci *return_buffer = info; 44162306a36Sopenharmony_ci status = AE_OK; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cicleanup: 44462306a36Sopenharmony_ci if (hid) { 44562306a36Sopenharmony_ci ACPI_FREE(hid); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci if (uid) { 44862306a36Sopenharmony_ci ACPI_FREE(uid); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci if (cid_list) { 45162306a36Sopenharmony_ci ACPI_FREE(cid_list); 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci if (cls) { 45462306a36Sopenharmony_ci ACPI_FREE(cls); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci return (status); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_get_object_info) 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci/****************************************************************************** 46262306a36Sopenharmony_ci * 46362306a36Sopenharmony_ci * FUNCTION: acpi_install_method 46462306a36Sopenharmony_ci * 46562306a36Sopenharmony_ci * PARAMETERS: buffer - An ACPI table containing one control method 46662306a36Sopenharmony_ci * 46762306a36Sopenharmony_ci * RETURN: Status 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci * DESCRIPTION: Install a control method into the namespace. If the method 47062306a36Sopenharmony_ci * name already exists in the namespace, it is overwritten. The 47162306a36Sopenharmony_ci * input buffer must contain a valid DSDT or SSDT containing a 47262306a36Sopenharmony_ci * single control method. 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci ******************************************************************************/ 47562306a36Sopenharmony_ciacpi_status acpi_install_method(u8 *buffer) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct acpi_table_header *table = 47862306a36Sopenharmony_ci ACPI_CAST_PTR(struct acpi_table_header, buffer); 47962306a36Sopenharmony_ci u8 *aml_buffer; 48062306a36Sopenharmony_ci u8 *aml_start; 48162306a36Sopenharmony_ci char *path; 48262306a36Sopenharmony_ci struct acpi_namespace_node *node; 48362306a36Sopenharmony_ci union acpi_operand_object *method_obj; 48462306a36Sopenharmony_ci struct acpi_parse_state parser_state; 48562306a36Sopenharmony_ci u32 aml_length; 48662306a36Sopenharmony_ci u16 opcode; 48762306a36Sopenharmony_ci u8 method_flags; 48862306a36Sopenharmony_ci acpi_status status; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* Parameter validation */ 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (!buffer) { 49362306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* Table must be a DSDT or SSDT */ 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (!ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_DSDT) && 49962306a36Sopenharmony_ci !ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_SSDT)) { 50062306a36Sopenharmony_ci return (AE_BAD_HEADER); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* First AML opcode in the table must be a control method */ 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci parser_state.aml = buffer + sizeof(struct acpi_table_header); 50662306a36Sopenharmony_ci opcode = acpi_ps_peek_opcode(&parser_state); 50762306a36Sopenharmony_ci if (opcode != AML_METHOD_OP) { 50862306a36Sopenharmony_ci return (AE_BAD_PARAMETER); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* Extract method information from the raw AML */ 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci parser_state.aml += acpi_ps_get_opcode_size(opcode); 51462306a36Sopenharmony_ci parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state); 51562306a36Sopenharmony_ci path = acpi_ps_get_next_namestring(&parser_state); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci method_flags = *parser_state.aml++; 51862306a36Sopenharmony_ci aml_start = parser_state.aml; 51962306a36Sopenharmony_ci aml_length = (u32)ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * Allocate resources up-front. We don't want to have to delete a new 52362306a36Sopenharmony_ci * node from the namespace if we cannot allocate memory. 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci aml_buffer = ACPI_ALLOCATE(aml_length); 52662306a36Sopenharmony_ci if (!aml_buffer) { 52762306a36Sopenharmony_ci return (AE_NO_MEMORY); 52862306a36Sopenharmony_ci } 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); 53162306a36Sopenharmony_ci if (!method_obj) { 53262306a36Sopenharmony_ci ACPI_FREE(aml_buffer); 53362306a36Sopenharmony_ci return (AE_NO_MEMORY); 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Lock namespace for acpi_ns_lookup, we may be creating a new node */ 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 53962306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 54062306a36Sopenharmony_ci goto error_exit; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* The lookup either returns an existing node or creates a new one */ 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci status = 54662306a36Sopenharmony_ci acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, 54762306a36Sopenharmony_ci ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, 54862306a36Sopenharmony_ci NULL, &node); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { /* ns_lookup */ 55362306a36Sopenharmony_ci if (status != AE_ALREADY_EXISTS) { 55462306a36Sopenharmony_ci goto error_exit; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* Node existed previously, make sure it is a method node */ 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (node->type != ACPI_TYPE_METHOD) { 56062306a36Sopenharmony_ci status = AE_TYPE; 56162306a36Sopenharmony_ci goto error_exit; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* Copy the method AML to the local buffer */ 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci memcpy(aml_buffer, aml_start, aml_length); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* Initialize the method object with the new method's information */ 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci method_obj->method.aml_start = aml_buffer; 57262306a36Sopenharmony_ci method_obj->method.aml_length = aml_length; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci method_obj->method.param_count = (u8) 57562306a36Sopenharmony_ci (method_flags & AML_METHOD_ARG_COUNT); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (method_flags & AML_METHOD_SERIALIZED) { 57862306a36Sopenharmony_ci method_obj->method.info_flags = ACPI_METHOD_SERIALIZED; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci method_obj->method.sync_level = (u8) 58162306a36Sopenharmony_ci ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* 58562306a36Sopenharmony_ci * Now that it is complete, we can attach the new method object to 58662306a36Sopenharmony_ci * the method Node (detaches/deletes any existing object) 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_ci status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci /* 59162306a36Sopenharmony_ci * Flag indicates AML buffer is dynamic, must be deleted later. 59262306a36Sopenharmony_ci * Must be set only after attach above. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci node->flags |= ANOBJ_ALLOCATED_BUFFER; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* Remove local reference to the method object */ 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci acpi_ut_remove_reference(method_obj); 59962306a36Sopenharmony_ci return (status); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cierror_exit: 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci ACPI_FREE(aml_buffer); 60462306a36Sopenharmony_ci ACPI_FREE(method_obj); 60562306a36Sopenharmony_ci return (status); 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ciACPI_EXPORT_SYMBOL(acpi_install_method) 608