xref: /kernel/linux/linux-5.10/drivers/acpi/utils.c (revision 8c2ecf20)
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