18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * acpi_utils.c - ACPI Utility Functions ($Revision: 10 $) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/hardirq.h> 158c2ecf20Sopenharmony_ci#include <linux/acpi.h> 168c2ecf20Sopenharmony_ci#include <linux/dynamic_debug.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "internal.h" 198c2ecf20Sopenharmony_ci#include "sleep.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define _COMPONENT ACPI_BUS_COMPONENT 228c2ecf20Sopenharmony_ciACPI_MODULE_NAME("utils"); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 258c2ecf20Sopenharmony_ci Object Evaluation Helpers 268c2ecf20Sopenharmony_ci -------------------------------------------------------------------------- */ 278c2ecf20Sopenharmony_cistatic void 288c2ecf20Sopenharmony_ciacpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci#ifdef ACPI_DEBUG_OUTPUT 318c2ecf20Sopenharmony_ci char prefix[80] = {'\0'}; 328c2ecf20Sopenharmony_ci struct acpi_buffer buffer = {sizeof(prefix), prefix}; 338c2ecf20Sopenharmony_ci acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer); 348c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n", 358c2ecf20Sopenharmony_ci (char *) prefix, p, acpi_format_exception(s))); 368c2ecf20Sopenharmony_ci#else 378c2ecf20Sopenharmony_ci return; 388c2ecf20Sopenharmony_ci#endif 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ciacpi_status 428c2ecf20Sopenharmony_ciacpi_extract_package(union acpi_object *package, 438c2ecf20Sopenharmony_ci struct acpi_buffer *format, struct acpi_buffer *buffer) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci u32 size_required = 0; 468c2ecf20Sopenharmony_ci u32 tail_offset = 0; 478c2ecf20Sopenharmony_ci char *format_string = NULL; 488c2ecf20Sopenharmony_ci u32 format_count = 0; 498c2ecf20Sopenharmony_ci u32 i = 0; 508c2ecf20Sopenharmony_ci u8 *head = NULL; 518c2ecf20Sopenharmony_ci u8 *tail = NULL; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (!package || (package->type != ACPI_TYPE_PACKAGE) 558c2ecf20Sopenharmony_ci || (package->package.count < 1)) { 568c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Invalid package argument\n"); 578c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (!format || !format->pointer || (format->length < 1)) { 618c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Invalid format argument\n"); 628c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (!buffer) { 668c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Invalid buffer argument\n"); 678c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci format_count = (format->length / sizeof(char)) - 1; 718c2ecf20Sopenharmony_ci if (format_count > package->package.count) { 728c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Format specifies more objects [%d]" 738c2ecf20Sopenharmony_ci " than exist in package [%d].\n", 748c2ecf20Sopenharmony_ci format_count, package->package.count); 758c2ecf20Sopenharmony_ci return AE_BAD_DATA; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci format_string = format->pointer; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* 818c2ecf20Sopenharmony_ci * Calculate size_required. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci for (i = 0; i < format_count; i++) { 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci union acpi_object *element = &(package->package.elements[i]); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci switch (element->type) { 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci case ACPI_TYPE_INTEGER: 908c2ecf20Sopenharmony_ci switch (format_string[i]) { 918c2ecf20Sopenharmony_ci case 'N': 928c2ecf20Sopenharmony_ci size_required += sizeof(u64); 938c2ecf20Sopenharmony_ci tail_offset += sizeof(u64); 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci case 'S': 968c2ecf20Sopenharmony_ci size_required += 978c2ecf20Sopenharmony_ci sizeof(char *) + sizeof(u64) + 988c2ecf20Sopenharmony_ci sizeof(char); 998c2ecf20Sopenharmony_ci tail_offset += sizeof(char *); 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci default: 1028c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Invalid package element" 1038c2ecf20Sopenharmony_ci " [%d]: got number, expecting" 1048c2ecf20Sopenharmony_ci " [%c]\n", 1058c2ecf20Sopenharmony_ci i, format_string[i]); 1068c2ecf20Sopenharmony_ci return AE_BAD_DATA; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci case ACPI_TYPE_STRING: 1118c2ecf20Sopenharmony_ci case ACPI_TYPE_BUFFER: 1128c2ecf20Sopenharmony_ci switch (format_string[i]) { 1138c2ecf20Sopenharmony_ci case 'S': 1148c2ecf20Sopenharmony_ci size_required += 1158c2ecf20Sopenharmony_ci sizeof(char *) + 1168c2ecf20Sopenharmony_ci (element->string.length * sizeof(char)) + 1178c2ecf20Sopenharmony_ci sizeof(char); 1188c2ecf20Sopenharmony_ci tail_offset += sizeof(char *); 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci case 'B': 1218c2ecf20Sopenharmony_ci size_required += 1228c2ecf20Sopenharmony_ci sizeof(u8 *) + element->buffer.length; 1238c2ecf20Sopenharmony_ci tail_offset += sizeof(u8 *); 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci default: 1268c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Invalid package element" 1278c2ecf20Sopenharmony_ci " [%d] got string/buffer," 1288c2ecf20Sopenharmony_ci " expecting [%c]\n", 1298c2ecf20Sopenharmony_ci i, format_string[i]); 1308c2ecf20Sopenharmony_ci return AE_BAD_DATA; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci case ACPI_TYPE_LOCAL_REFERENCE: 1348c2ecf20Sopenharmony_ci switch (format_string[i]) { 1358c2ecf20Sopenharmony_ci case 'R': 1368c2ecf20Sopenharmony_ci size_required += sizeof(void *); 1378c2ecf20Sopenharmony_ci tail_offset += sizeof(void *); 1388c2ecf20Sopenharmony_ci break; 1398c2ecf20Sopenharmony_ci default: 1408c2ecf20Sopenharmony_ci printk(KERN_WARNING PREFIX "Invalid package element" 1418c2ecf20Sopenharmony_ci " [%d] got reference," 1428c2ecf20Sopenharmony_ci " expecting [%c]\n", 1438c2ecf20Sopenharmony_ci i, format_string[i]); 1448c2ecf20Sopenharmony_ci return AE_BAD_DATA; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci case ACPI_TYPE_PACKAGE: 1498c2ecf20Sopenharmony_ci default: 1508c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, 1518c2ecf20Sopenharmony_ci "Found unsupported element at index=%d\n", 1528c2ecf20Sopenharmony_ci i)); 1538c2ecf20Sopenharmony_ci /* TBD: handle nested packages... */ 1548c2ecf20Sopenharmony_ci return AE_SUPPORT; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* 1598c2ecf20Sopenharmony_ci * Validate output buffer. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci if (buffer->length == ACPI_ALLOCATE_BUFFER) { 1628c2ecf20Sopenharmony_ci buffer->pointer = ACPI_ALLOCATE_ZEROED(size_required); 1638c2ecf20Sopenharmony_ci if (!buffer->pointer) 1648c2ecf20Sopenharmony_ci return AE_NO_MEMORY; 1658c2ecf20Sopenharmony_ci buffer->length = size_required; 1668c2ecf20Sopenharmony_ci } else { 1678c2ecf20Sopenharmony_ci if (buffer->length < size_required) { 1688c2ecf20Sopenharmony_ci buffer->length = size_required; 1698c2ecf20Sopenharmony_ci return AE_BUFFER_OVERFLOW; 1708c2ecf20Sopenharmony_ci } else if (buffer->length != size_required || 1718c2ecf20Sopenharmony_ci !buffer->pointer) { 1728c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci head = buffer->pointer; 1778c2ecf20Sopenharmony_ci tail = buffer->pointer + tail_offset; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * Extract package data. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci for (i = 0; i < format_count; i++) { 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci u8 **pointer = NULL; 1858c2ecf20Sopenharmony_ci union acpi_object *element = &(package->package.elements[i]); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci switch (element->type) { 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci case ACPI_TYPE_INTEGER: 1908c2ecf20Sopenharmony_ci switch (format_string[i]) { 1918c2ecf20Sopenharmony_ci case 'N': 1928c2ecf20Sopenharmony_ci *((u64 *) head) = 1938c2ecf20Sopenharmony_ci element->integer.value; 1948c2ecf20Sopenharmony_ci head += sizeof(u64); 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci case 'S': 1978c2ecf20Sopenharmony_ci pointer = (u8 **) head; 1988c2ecf20Sopenharmony_ci *pointer = tail; 1998c2ecf20Sopenharmony_ci *((u64 *) tail) = 2008c2ecf20Sopenharmony_ci element->integer.value; 2018c2ecf20Sopenharmony_ci head += sizeof(u64 *); 2028c2ecf20Sopenharmony_ci tail += sizeof(u64); 2038c2ecf20Sopenharmony_ci /* NULL terminate string */ 2048c2ecf20Sopenharmony_ci *tail = (char)0; 2058c2ecf20Sopenharmony_ci tail += sizeof(char); 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci default: 2088c2ecf20Sopenharmony_ci /* Should never get here */ 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci break; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci case ACPI_TYPE_STRING: 2148c2ecf20Sopenharmony_ci case ACPI_TYPE_BUFFER: 2158c2ecf20Sopenharmony_ci switch (format_string[i]) { 2168c2ecf20Sopenharmony_ci case 'S': 2178c2ecf20Sopenharmony_ci pointer = (u8 **) head; 2188c2ecf20Sopenharmony_ci *pointer = tail; 2198c2ecf20Sopenharmony_ci memcpy(tail, element->string.pointer, 2208c2ecf20Sopenharmony_ci element->string.length); 2218c2ecf20Sopenharmony_ci head += sizeof(char *); 2228c2ecf20Sopenharmony_ci tail += element->string.length * sizeof(char); 2238c2ecf20Sopenharmony_ci /* NULL terminate string */ 2248c2ecf20Sopenharmony_ci *tail = (char)0; 2258c2ecf20Sopenharmony_ci tail += sizeof(char); 2268c2ecf20Sopenharmony_ci break; 2278c2ecf20Sopenharmony_ci case 'B': 2288c2ecf20Sopenharmony_ci pointer = (u8 **) head; 2298c2ecf20Sopenharmony_ci *pointer = tail; 2308c2ecf20Sopenharmony_ci memcpy(tail, element->buffer.pointer, 2318c2ecf20Sopenharmony_ci element->buffer.length); 2328c2ecf20Sopenharmony_ci head += sizeof(u8 *); 2338c2ecf20Sopenharmony_ci tail += element->buffer.length; 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci default: 2368c2ecf20Sopenharmony_ci /* Should never get here */ 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci case ACPI_TYPE_LOCAL_REFERENCE: 2418c2ecf20Sopenharmony_ci switch (format_string[i]) { 2428c2ecf20Sopenharmony_ci case 'R': 2438c2ecf20Sopenharmony_ci *(void **)head = 2448c2ecf20Sopenharmony_ci (void *)element->reference.handle; 2458c2ecf20Sopenharmony_ci head += sizeof(void *); 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci default: 2488c2ecf20Sopenharmony_ci /* Should never get here */ 2498c2ecf20Sopenharmony_ci break; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci case ACPI_TYPE_PACKAGE: 2538c2ecf20Sopenharmony_ci /* TBD: handle nested packages... */ 2548c2ecf20Sopenharmony_ci default: 2558c2ecf20Sopenharmony_ci /* Should never get here */ 2568c2ecf20Sopenharmony_ci break; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return AE_OK; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_extract_package); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ciacpi_status 2668c2ecf20Sopenharmony_ciacpi_evaluate_integer(acpi_handle handle, 2678c2ecf20Sopenharmony_ci acpi_string pathname, 2688c2ecf20Sopenharmony_ci struct acpi_object_list *arguments, unsigned long long *data) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci acpi_status status = AE_OK; 2718c2ecf20Sopenharmony_ci union acpi_object element; 2728c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { 0, NULL }; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (!data) 2758c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci buffer.length = sizeof(union acpi_object); 2788c2ecf20Sopenharmony_ci buffer.pointer = &element; 2798c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, pathname, arguments, &buffer); 2808c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 2818c2ecf20Sopenharmony_ci acpi_util_eval_error(handle, pathname, status); 2828c2ecf20Sopenharmony_ci return status; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (element.type != ACPI_TYPE_INTEGER) { 2868c2ecf20Sopenharmony_ci acpi_util_eval_error(handle, pathname, AE_BAD_DATA); 2878c2ecf20Sopenharmony_ci return AE_BAD_DATA; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci *data = element.integer.value; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%llu]\n", *data)); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return AE_OK; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_evaluate_integer); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ciacpi_status 3008c2ecf20Sopenharmony_ciacpi_evaluate_reference(acpi_handle handle, 3018c2ecf20Sopenharmony_ci acpi_string pathname, 3028c2ecf20Sopenharmony_ci struct acpi_object_list *arguments, 3038c2ecf20Sopenharmony_ci struct acpi_handle_list *list) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci acpi_status status = AE_OK; 3068c2ecf20Sopenharmony_ci union acpi_object *package = NULL; 3078c2ecf20Sopenharmony_ci union acpi_object *element = NULL; 3088c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 3098c2ecf20Sopenharmony_ci u32 i = 0; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (!list) { 3138c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci /* Evaluate object. */ 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, pathname, arguments, &buffer); 3198c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 3208c2ecf20Sopenharmony_ci goto end; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci package = buffer.pointer; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if ((buffer.length == 0) || !package) { 3258c2ecf20Sopenharmony_ci status = AE_BAD_DATA; 3268c2ecf20Sopenharmony_ci acpi_util_eval_error(handle, pathname, status); 3278c2ecf20Sopenharmony_ci goto end; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci if (package->type != ACPI_TYPE_PACKAGE) { 3308c2ecf20Sopenharmony_ci status = AE_BAD_DATA; 3318c2ecf20Sopenharmony_ci acpi_util_eval_error(handle, pathname, status); 3328c2ecf20Sopenharmony_ci goto end; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci if (!package->package.count) { 3358c2ecf20Sopenharmony_ci status = AE_BAD_DATA; 3368c2ecf20Sopenharmony_ci acpi_util_eval_error(handle, pathname, status); 3378c2ecf20Sopenharmony_ci goto end; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (package->package.count > ACPI_MAX_HANDLES) { 3418c2ecf20Sopenharmony_ci kfree(package); 3428c2ecf20Sopenharmony_ci return AE_NO_MEMORY; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci list->count = package->package.count; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Extract package data. */ 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci for (i = 0; i < list->count; i++) { 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci element = &(package->package.elements[i]); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { 3538c2ecf20Sopenharmony_ci status = AE_BAD_DATA; 3548c2ecf20Sopenharmony_ci acpi_util_eval_error(handle, pathname, status); 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (!element->reference.handle) { 3598c2ecf20Sopenharmony_ci status = AE_NULL_ENTRY; 3608c2ecf20Sopenharmony_ci acpi_util_eval_error(handle, pathname, status); 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci /* Get the acpi_handle. */ 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci list->handles[i] = element->reference.handle; 3668c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n", 3678c2ecf20Sopenharmony_ci list->handles[i])); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci end: 3718c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 3728c2ecf20Sopenharmony_ci list->count = 0; 3738c2ecf20Sopenharmony_ci //kfree(list->handles); 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci kfree(buffer.pointer); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return status; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_evaluate_reference); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ciacpi_status 3848c2ecf20Sopenharmony_ciacpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci acpi_status status; 3878c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 3888c2ecf20Sopenharmony_ci union acpi_object *output; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci status = acpi_evaluate_object(handle, "_PLD", NULL, &buffer); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 3938c2ecf20Sopenharmony_ci return status; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci output = buffer.pointer; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (!output || output->type != ACPI_TYPE_PACKAGE 3988c2ecf20Sopenharmony_ci || !output->package.count 3998c2ecf20Sopenharmony_ci || output->package.elements[0].type != ACPI_TYPE_BUFFER 4008c2ecf20Sopenharmony_ci || output->package.elements[0].buffer.length < ACPI_PLD_REV1_BUFFER_SIZE) { 4018c2ecf20Sopenharmony_ci status = AE_TYPE; 4028c2ecf20Sopenharmony_ci goto out; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci status = acpi_decode_pld_buffer( 4068c2ecf20Sopenharmony_ci output->package.elements[0].buffer.pointer, 4078c2ecf20Sopenharmony_ci output->package.elements[0].buffer.length, 4088c2ecf20Sopenharmony_ci pld); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciout: 4118c2ecf20Sopenharmony_ci kfree(buffer.pointer); 4128c2ecf20Sopenharmony_ci return status; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_get_physical_device_location); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/** 4178c2ecf20Sopenharmony_ci * acpi_evaluate_ost: Evaluate _OST for hotplug operations 4188c2ecf20Sopenharmony_ci * @handle: ACPI device handle 4198c2ecf20Sopenharmony_ci * @source_event: source event code 4208c2ecf20Sopenharmony_ci * @status_code: status code 4218c2ecf20Sopenharmony_ci * @status_buf: optional detailed information (NULL if none) 4228c2ecf20Sopenharmony_ci * 4238c2ecf20Sopenharmony_ci * Evaluate _OST for hotplug operations. All ACPI hotplug handlers 4248c2ecf20Sopenharmony_ci * must call this function when evaluating _OST for hotplug operations. 4258c2ecf20Sopenharmony_ci * When the platform does not support _OST, this function has no effect. 4268c2ecf20Sopenharmony_ci */ 4278c2ecf20Sopenharmony_ciacpi_status 4288c2ecf20Sopenharmony_ciacpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code, 4298c2ecf20Sopenharmony_ci struct acpi_buffer *status_buf) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci union acpi_object params[3] = { 4328c2ecf20Sopenharmony_ci {.type = ACPI_TYPE_INTEGER,}, 4338c2ecf20Sopenharmony_ci {.type = ACPI_TYPE_INTEGER,}, 4348c2ecf20Sopenharmony_ci {.type = ACPI_TYPE_BUFFER,} 4358c2ecf20Sopenharmony_ci }; 4368c2ecf20Sopenharmony_ci struct acpi_object_list arg_list = {3, params}; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci params[0].integer.value = source_event; 4398c2ecf20Sopenharmony_ci params[1].integer.value = status_code; 4408c2ecf20Sopenharmony_ci if (status_buf != NULL) { 4418c2ecf20Sopenharmony_ci params[2].buffer.pointer = status_buf->pointer; 4428c2ecf20Sopenharmony_ci params[2].buffer.length = status_buf->length; 4438c2ecf20Sopenharmony_ci } else { 4448c2ecf20Sopenharmony_ci params[2].buffer.pointer = NULL; 4458c2ecf20Sopenharmony_ci params[2].buffer.length = 0; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return acpi_evaluate_object(handle, "_OST", &arg_list, NULL); 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_evaluate_ost); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci/** 4538c2ecf20Sopenharmony_ci * acpi_handle_path: Return the object path of handle 4548c2ecf20Sopenharmony_ci * @handle: ACPI device handle 4558c2ecf20Sopenharmony_ci * 4568c2ecf20Sopenharmony_ci * Caller must free the returned buffer 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_cistatic char *acpi_handle_path(acpi_handle handle) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct acpi_buffer buffer = { 4618c2ecf20Sopenharmony_ci .length = ACPI_ALLOCATE_BUFFER, 4628c2ecf20Sopenharmony_ci .pointer = NULL 4638c2ecf20Sopenharmony_ci }; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (in_interrupt() || 4668c2ecf20Sopenharmony_ci acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK) 4678c2ecf20Sopenharmony_ci return NULL; 4688c2ecf20Sopenharmony_ci return buffer.pointer; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/** 4728c2ecf20Sopenharmony_ci * acpi_handle_printk: Print message with ACPI prefix and object path 4738c2ecf20Sopenharmony_ci * @level: log level 4748c2ecf20Sopenharmony_ci * @handle: ACPI device handle 4758c2ecf20Sopenharmony_ci * @fmt: format string 4768c2ecf20Sopenharmony_ci * 4778c2ecf20Sopenharmony_ci * This function is called through acpi_handle_<level> macros and prints 4788c2ecf20Sopenharmony_ci * a message with ACPI prefix and object path. This function acquires 4798c2ecf20Sopenharmony_ci * the global namespace mutex to obtain an object path. In interrupt 4808c2ecf20Sopenharmony_ci * context, it shows the object path as <n/a>. 4818c2ecf20Sopenharmony_ci */ 4828c2ecf20Sopenharmony_civoid 4838c2ecf20Sopenharmony_ciacpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct va_format vaf; 4868c2ecf20Sopenharmony_ci va_list args; 4878c2ecf20Sopenharmony_ci const char *path; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci va_start(args, fmt); 4908c2ecf20Sopenharmony_ci vaf.fmt = fmt; 4918c2ecf20Sopenharmony_ci vaf.va = &args; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci path = acpi_handle_path(handle); 4948c2ecf20Sopenharmony_ci printk("%sACPI: %s: %pV", level, path ? path : "<n/a>" , &vaf); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci va_end(args); 4978c2ecf20Sopenharmony_ci kfree(path); 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_handle_printk); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci#if defined(CONFIG_DYNAMIC_DEBUG) 5028c2ecf20Sopenharmony_ci/** 5038c2ecf20Sopenharmony_ci * __acpi_handle_debug: pr_debug with ACPI prefix and object path 5048c2ecf20Sopenharmony_ci * @descriptor: Dynamic Debug descriptor 5058c2ecf20Sopenharmony_ci * @handle: ACPI device handle 5068c2ecf20Sopenharmony_ci * @fmt: format string 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * This function is called through acpi_handle_debug macro and debug 5098c2ecf20Sopenharmony_ci * prints a message with ACPI prefix and object path. This function 5108c2ecf20Sopenharmony_ci * acquires the global namespace mutex to obtain an object path. In 5118c2ecf20Sopenharmony_ci * interrupt context, it shows the object path as <n/a>. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_civoid 5148c2ecf20Sopenharmony_ci__acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, 5158c2ecf20Sopenharmony_ci const char *fmt, ...) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct va_format vaf; 5188c2ecf20Sopenharmony_ci va_list args; 5198c2ecf20Sopenharmony_ci const char *path; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci va_start(args, fmt); 5228c2ecf20Sopenharmony_ci vaf.fmt = fmt; 5238c2ecf20Sopenharmony_ci vaf.va = &args; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci path = acpi_handle_path(handle); 5268c2ecf20Sopenharmony_ci __dynamic_pr_debug(descriptor, "ACPI: %s: %pV", path ? path : "<n/a>", &vaf); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci va_end(args); 5298c2ecf20Sopenharmony_ci kfree(path); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__acpi_handle_debug); 5328c2ecf20Sopenharmony_ci#endif 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/** 5358c2ecf20Sopenharmony_ci * acpi_has_method: Check whether @handle has a method named @name 5368c2ecf20Sopenharmony_ci * @handle: ACPI device handle 5378c2ecf20Sopenharmony_ci * @name: name of object or method 5388c2ecf20Sopenharmony_ci * 5398c2ecf20Sopenharmony_ci * Check whether @handle has a method named @name. 5408c2ecf20Sopenharmony_ci */ 5418c2ecf20Sopenharmony_cibool acpi_has_method(acpi_handle handle, char *name) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci acpi_handle tmp; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp)); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_has_method); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ciacpi_status acpi_execute_simple_method(acpi_handle handle, char *method, 5508c2ecf20Sopenharmony_ci u64 arg) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci union acpi_object obj = { .type = ACPI_TYPE_INTEGER }; 5538c2ecf20Sopenharmony_ci struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, }; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci obj.integer.value = arg; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return acpi_evaluate_object(handle, method, &arg_list, NULL); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_execute_simple_method); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci/** 5628c2ecf20Sopenharmony_ci * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations 5638c2ecf20Sopenharmony_ci * @handle: ACPI device handle 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * Evaluate device's _EJ0 method for hotplug operations. 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ciacpi_status acpi_evaluate_ej0(acpi_handle handle) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci acpi_status status; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci status = acpi_execute_simple_method(handle, "_EJ0", 1); 5728c2ecf20Sopenharmony_ci if (status == AE_NOT_FOUND) 5738c2ecf20Sopenharmony_ci acpi_handle_warn(handle, "No _EJ0 support for device\n"); 5748c2ecf20Sopenharmony_ci else if (ACPI_FAILURE(status)) 5758c2ecf20Sopenharmony_ci acpi_handle_warn(handle, "Eject failed (0x%x)\n", status); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return status; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci/** 5818c2ecf20Sopenharmony_ci * acpi_evaluate_lck: Evaluate _LCK method to lock/unlock device 5828c2ecf20Sopenharmony_ci * @handle: ACPI device handle 5838c2ecf20Sopenharmony_ci * @lock: lock device if non-zero, otherwise unlock device 5848c2ecf20Sopenharmony_ci * 5858c2ecf20Sopenharmony_ci * Evaluate device's _LCK method if present to lock/unlock device 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_ciacpi_status acpi_evaluate_lck(acpi_handle handle, int lock) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci acpi_status status; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci status = acpi_execute_simple_method(handle, "_LCK", !!lock); 5928c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { 5938c2ecf20Sopenharmony_ci if (lock) 5948c2ecf20Sopenharmony_ci acpi_handle_warn(handle, 5958c2ecf20Sopenharmony_ci "Locking device failed (0x%x)\n", status); 5968c2ecf20Sopenharmony_ci else 5978c2ecf20Sopenharmony_ci acpi_handle_warn(handle, 5988c2ecf20Sopenharmony_ci "Unlocking device failed (0x%x)\n", status); 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci return status; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci/** 6058c2ecf20Sopenharmony_ci * acpi_evaluate_reg: Evaluate _REG method to register OpRegion presence 6068c2ecf20Sopenharmony_ci * @handle: ACPI device handle 6078c2ecf20Sopenharmony_ci * @space_id: ACPI address space id to register OpRegion presence for 6088c2ecf20Sopenharmony_ci * @function: Parameter to pass to _REG one of ACPI_REG_CONNECT or 6098c2ecf20Sopenharmony_ci * ACPI_REG_DISCONNECT 6108c2ecf20Sopenharmony_ci * 6118c2ecf20Sopenharmony_ci * Evaluate device's _REG method to register OpRegion presence. 6128c2ecf20Sopenharmony_ci */ 6138c2ecf20Sopenharmony_ciacpi_status acpi_evaluate_reg(acpi_handle handle, u8 space_id, u32 function) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct acpi_object_list arg_list; 6168c2ecf20Sopenharmony_ci union acpi_object params[2]; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci params[0].type = ACPI_TYPE_INTEGER; 6198c2ecf20Sopenharmony_ci params[0].integer.value = space_id; 6208c2ecf20Sopenharmony_ci params[1].type = ACPI_TYPE_INTEGER; 6218c2ecf20Sopenharmony_ci params[1].integer.value = function; 6228c2ecf20Sopenharmony_ci arg_list.count = 2; 6238c2ecf20Sopenharmony_ci arg_list.pointer = params; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci return acpi_evaluate_object(handle, "_REG", &arg_list, NULL); 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_evaluate_reg); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci/** 6308c2ecf20Sopenharmony_ci * acpi_evaluate_dsm - evaluate device's _DSM method 6318c2ecf20Sopenharmony_ci * @handle: ACPI device handle 6328c2ecf20Sopenharmony_ci * @guid: GUID of requested functions, should be 16 bytes 6338c2ecf20Sopenharmony_ci * @rev: revision number of requested function 6348c2ecf20Sopenharmony_ci * @func: requested function number 6358c2ecf20Sopenharmony_ci * @argv4: the function specific parameter 6368c2ecf20Sopenharmony_ci * 6378c2ecf20Sopenharmony_ci * Evaluate device's _DSM method with specified GUID, revision id and 6388c2ecf20Sopenharmony_ci * function number. Caller needs to free the returned object. 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci * Though ACPI defines the fourth parameter for _DSM should be a package, 6418c2ecf20Sopenharmony_ci * some old BIOSes do expect a buffer or an integer etc. 6428c2ecf20Sopenharmony_ci */ 6438c2ecf20Sopenharmony_ciunion acpi_object * 6448c2ecf20Sopenharmony_ciacpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 func, 6458c2ecf20Sopenharmony_ci union acpi_object *argv4) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci acpi_status ret; 6488c2ecf20Sopenharmony_ci struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; 6498c2ecf20Sopenharmony_ci union acpi_object params[4]; 6508c2ecf20Sopenharmony_ci struct acpi_object_list input = { 6518c2ecf20Sopenharmony_ci .count = 4, 6528c2ecf20Sopenharmony_ci .pointer = params, 6538c2ecf20Sopenharmony_ci }; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci params[0].type = ACPI_TYPE_BUFFER; 6568c2ecf20Sopenharmony_ci params[0].buffer.length = 16; 6578c2ecf20Sopenharmony_ci params[0].buffer.pointer = (u8 *)guid; 6588c2ecf20Sopenharmony_ci params[1].type = ACPI_TYPE_INTEGER; 6598c2ecf20Sopenharmony_ci params[1].integer.value = rev; 6608c2ecf20Sopenharmony_ci params[2].type = ACPI_TYPE_INTEGER; 6618c2ecf20Sopenharmony_ci params[2].integer.value = func; 6628c2ecf20Sopenharmony_ci if (argv4) { 6638c2ecf20Sopenharmony_ci params[3] = *argv4; 6648c2ecf20Sopenharmony_ci } else { 6658c2ecf20Sopenharmony_ci params[3].type = ACPI_TYPE_PACKAGE; 6668c2ecf20Sopenharmony_ci params[3].package.count = 0; 6678c2ecf20Sopenharmony_ci params[3].package.elements = NULL; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci ret = acpi_evaluate_object(handle, "_DSM", &input, &buf); 6718c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(ret)) 6728c2ecf20Sopenharmony_ci return (union acpi_object *)buf.pointer; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (ret != AE_NOT_FOUND) 6758c2ecf20Sopenharmony_ci acpi_handle_warn(handle, 6768c2ecf20Sopenharmony_ci "failed to evaluate _DSM (0x%x)\n", ret); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci return NULL; 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_evaluate_dsm); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci/** 6838c2ecf20Sopenharmony_ci * acpi_check_dsm - check if _DSM method supports requested functions. 6848c2ecf20Sopenharmony_ci * @handle: ACPI device handle 6858c2ecf20Sopenharmony_ci * @guid: GUID of requested functions, should be 16 bytes at least 6868c2ecf20Sopenharmony_ci * @rev: revision number of requested functions 6878c2ecf20Sopenharmony_ci * @funcs: bitmap of requested functions 6888c2ecf20Sopenharmony_ci * 6898c2ecf20Sopenharmony_ci * Evaluate device's _DSM method to check whether it supports requested 6908c2ecf20Sopenharmony_ci * functions. Currently only support 64 functions at maximum, should be 6918c2ecf20Sopenharmony_ci * enough for now. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_cibool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci int i; 6968c2ecf20Sopenharmony_ci u64 mask = 0; 6978c2ecf20Sopenharmony_ci union acpi_object *obj; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (funcs == 0) 7008c2ecf20Sopenharmony_ci return false; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci obj = acpi_evaluate_dsm(handle, guid, rev, 0, NULL); 7038c2ecf20Sopenharmony_ci if (!obj) 7048c2ecf20Sopenharmony_ci return false; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* For compatibility, old BIOSes may return an integer */ 7078c2ecf20Sopenharmony_ci if (obj->type == ACPI_TYPE_INTEGER) 7088c2ecf20Sopenharmony_ci mask = obj->integer.value; 7098c2ecf20Sopenharmony_ci else if (obj->type == ACPI_TYPE_BUFFER) 7108c2ecf20Sopenharmony_ci for (i = 0; i < obj->buffer.length && i < 8; i++) 7118c2ecf20Sopenharmony_ci mask |= (((u64)obj->buffer.pointer[i]) << (i * 8)); 7128c2ecf20Sopenharmony_ci ACPI_FREE(obj); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* 7158c2ecf20Sopenharmony_ci * Bit 0 indicates whether there's support for any functions other than 7168c2ecf20Sopenharmony_ci * function 0 for the specified GUID and revision. 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_ci if ((mask & 0x1) && (mask & funcs) == funcs) 7198c2ecf20Sopenharmony_ci return true; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return false; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_check_dsm); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci/** 7268c2ecf20Sopenharmony_ci * acpi_dev_hid_uid_match - Match device by supplied HID and UID 7278c2ecf20Sopenharmony_ci * @adev: ACPI device to match. 7288c2ecf20Sopenharmony_ci * @hid2: Hardware ID of the device. 7298c2ecf20Sopenharmony_ci * @uid2: Unique ID of the device, pass NULL to not check _UID. 7308c2ecf20Sopenharmony_ci * 7318c2ecf20Sopenharmony_ci * Matches HID and UID in @adev with given @hid2 and @uid2. 7328c2ecf20Sopenharmony_ci * Returns true if matches. 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_cibool acpi_dev_hid_uid_match(struct acpi_device *adev, 7358c2ecf20Sopenharmony_ci const char *hid2, const char *uid2) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci const char *hid1 = acpi_device_hid(adev); 7388c2ecf20Sopenharmony_ci const char *uid1 = acpi_device_uid(adev); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (strcmp(hid1, hid2)) 7418c2ecf20Sopenharmony_ci return false; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci if (!uid2) 7448c2ecf20Sopenharmony_ci return true; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return uid1 && !strcmp(uid1, uid2); 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_dev_hid_uid_match); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci/** 7518c2ecf20Sopenharmony_ci * acpi_dev_found - Detect presence of a given ACPI device in the namespace. 7528c2ecf20Sopenharmony_ci * @hid: Hardware ID of the device. 7538c2ecf20Sopenharmony_ci * 7548c2ecf20Sopenharmony_ci * Return %true if the device was present at the moment of invocation. 7558c2ecf20Sopenharmony_ci * Note that if the device is pluggable, it may since have disappeared. 7568c2ecf20Sopenharmony_ci * 7578c2ecf20Sopenharmony_ci * For this function to work, acpi_bus_scan() must have been executed 7588c2ecf20Sopenharmony_ci * which happens in the subsys_initcall() subsection. Hence, do not 7598c2ecf20Sopenharmony_ci * call from a subsys_initcall() or earlier (use acpi_get_devices() 7608c2ecf20Sopenharmony_ci * instead). Calling from module_init() is fine (which is synonymous 7618c2ecf20Sopenharmony_ci * with device_initcall()). 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_cibool acpi_dev_found(const char *hid) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct acpi_device_bus_id *acpi_device_bus_id; 7668c2ecf20Sopenharmony_ci bool found = false; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci mutex_lock(&acpi_device_lock); 7698c2ecf20Sopenharmony_ci list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) 7708c2ecf20Sopenharmony_ci if (!strcmp(acpi_device_bus_id->bus_id, hid)) { 7718c2ecf20Sopenharmony_ci found = true; 7728c2ecf20Sopenharmony_ci break; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci mutex_unlock(&acpi_device_lock); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci return found; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_dev_found); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistruct acpi_dev_match_info { 7818c2ecf20Sopenharmony_ci struct acpi_device_id hid[2]; 7828c2ecf20Sopenharmony_ci const char *uid; 7838c2ecf20Sopenharmony_ci s64 hrv; 7848c2ecf20Sopenharmony_ci}; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_cistatic int acpi_dev_match_cb(struct device *dev, const void *data) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct acpi_device *adev = to_acpi_device(dev); 7898c2ecf20Sopenharmony_ci const struct acpi_dev_match_info *match = data; 7908c2ecf20Sopenharmony_ci unsigned long long hrv; 7918c2ecf20Sopenharmony_ci acpi_status status; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (acpi_match_device_ids(adev, match->hid)) 7948c2ecf20Sopenharmony_ci return 0; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (match->uid && (!adev->pnp.unique_id || 7978c2ecf20Sopenharmony_ci strcmp(adev->pnp.unique_id, match->uid))) 7988c2ecf20Sopenharmony_ci return 0; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (match->hrv == -1) 8018c2ecf20Sopenharmony_ci return 1; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci status = acpi_evaluate_integer(adev->handle, "_HRV", NULL, &hrv); 8048c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 8058c2ecf20Sopenharmony_ci return 0; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci return hrv == match->hrv; 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci/** 8118c2ecf20Sopenharmony_ci * acpi_dev_present - Detect that a given ACPI device is present 8128c2ecf20Sopenharmony_ci * @hid: Hardware ID of the device. 8138c2ecf20Sopenharmony_ci * @uid: Unique ID of the device, pass NULL to not check _UID 8148c2ecf20Sopenharmony_ci * @hrv: Hardware Revision of the device, pass -1 to not check _HRV 8158c2ecf20Sopenharmony_ci * 8168c2ecf20Sopenharmony_ci * Return %true if a matching device was present at the moment of invocation. 8178c2ecf20Sopenharmony_ci * Note that if the device is pluggable, it may since have disappeared. 8188c2ecf20Sopenharmony_ci * 8198c2ecf20Sopenharmony_ci * Note that unlike acpi_dev_found() this function checks the status 8208c2ecf20Sopenharmony_ci * of the device. So for devices which are present in the dsdt, but 8218c2ecf20Sopenharmony_ci * which are disabled (their _STA callback returns 0) this function 8228c2ecf20Sopenharmony_ci * will return false. 8238c2ecf20Sopenharmony_ci * 8248c2ecf20Sopenharmony_ci * For this function to work, acpi_bus_scan() must have been executed 8258c2ecf20Sopenharmony_ci * which happens in the subsys_initcall() subsection. Hence, do not 8268c2ecf20Sopenharmony_ci * call from a subsys_initcall() or earlier (use acpi_get_devices() 8278c2ecf20Sopenharmony_ci * instead). Calling from module_init() is fine (which is synonymous 8288c2ecf20Sopenharmony_ci * with device_initcall()). 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_cibool acpi_dev_present(const char *hid, const char *uid, s64 hrv) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci struct acpi_dev_match_info match = {}; 8338c2ecf20Sopenharmony_ci struct device *dev; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); 8368c2ecf20Sopenharmony_ci match.uid = uid; 8378c2ecf20Sopenharmony_ci match.hrv = hrv; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); 8408c2ecf20Sopenharmony_ci put_device(dev); 8418c2ecf20Sopenharmony_ci return !!dev; 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_dev_present); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci/** 8468c2ecf20Sopenharmony_ci * acpi_dev_get_first_match_dev - Return the first match of ACPI device 8478c2ecf20Sopenharmony_ci * @hid: Hardware ID of the device. 8488c2ecf20Sopenharmony_ci * @uid: Unique ID of the device, pass NULL to not check _UID 8498c2ecf20Sopenharmony_ci * @hrv: Hardware Revision of the device, pass -1 to not check _HRV 8508c2ecf20Sopenharmony_ci * 8518c2ecf20Sopenharmony_ci * Return the first match of ACPI device if a matching device was present 8528c2ecf20Sopenharmony_ci * at the moment of invocation, or NULL otherwise. 8538c2ecf20Sopenharmony_ci * 8548c2ecf20Sopenharmony_ci * The caller is responsible to call put_device() on the returned device. 8558c2ecf20Sopenharmony_ci * 8568c2ecf20Sopenharmony_ci * See additional information in acpi_dev_present() as well. 8578c2ecf20Sopenharmony_ci */ 8588c2ecf20Sopenharmony_cistruct acpi_device * 8598c2ecf20Sopenharmony_ciacpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci struct acpi_dev_match_info match = {}; 8628c2ecf20Sopenharmony_ci struct device *dev; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); 8658c2ecf20Sopenharmony_ci match.uid = uid; 8668c2ecf20Sopenharmony_ci match.hrv = hrv; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb); 8698c2ecf20Sopenharmony_ci return dev ? to_acpi_device(dev) : NULL; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_dev_get_first_match_dev); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci/* 8748c2ecf20Sopenharmony_ci * acpi_backlight= handling, this is done here rather then in video_detect.c 8758c2ecf20Sopenharmony_ci * because __setup cannot be used in modules. 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_cichar acpi_video_backlight_string[16]; 8788c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_video_backlight_string); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic int __init acpi_backlight(char *str) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci strlcpy(acpi_video_backlight_string, str, 8838c2ecf20Sopenharmony_ci sizeof(acpi_video_backlight_string)); 8848c2ecf20Sopenharmony_ci return 1; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci__setup("acpi_backlight=", acpi_backlight); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci/** 8898c2ecf20Sopenharmony_ci * acpi_match_platform_list - Check if the system matches with a given list 8908c2ecf20Sopenharmony_ci * @plat: pointer to acpi_platform_list table terminated by a NULL entry 8918c2ecf20Sopenharmony_ci * 8928c2ecf20Sopenharmony_ci * Return the matched index if the system is found in the platform list. 8938c2ecf20Sopenharmony_ci * Otherwise, return a negative error code. 8948c2ecf20Sopenharmony_ci */ 8958c2ecf20Sopenharmony_ciint acpi_match_platform_list(const struct acpi_platform_list *plat) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci struct acpi_table_header hdr; 8988c2ecf20Sopenharmony_ci int idx = 0; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci if (acpi_disabled) 9018c2ecf20Sopenharmony_ci return -ENODEV; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci for (; plat->oem_id[0]; plat++, idx++) { 9048c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_get_table_header(plat->table, 0, &hdr))) 9058c2ecf20Sopenharmony_ci continue; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (strncmp(plat->oem_id, hdr.oem_id, ACPI_OEM_ID_SIZE)) 9088c2ecf20Sopenharmony_ci continue; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (strncmp(plat->oem_table_id, hdr.oem_table_id, ACPI_OEM_TABLE_ID_SIZE)) 9118c2ecf20Sopenharmony_ci continue; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if ((plat->pred == all_versions) || 9148c2ecf20Sopenharmony_ci (plat->pred == less_than_or_equal && hdr.oem_revision <= plat->oem_revision) || 9158c2ecf20Sopenharmony_ci (plat->pred == greater_than_or_equal && hdr.oem_revision >= plat->oem_revision) || 9168c2ecf20Sopenharmony_ci (plat->pred == equal && hdr.oem_revision == plat->oem_revision)) 9178c2ecf20Sopenharmony_ci return idx; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci return -ENODEV; 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_match_platform_list); 923