xref: /openbmc/linux/drivers/acpi/utils.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  acpi_utils.c - ACPI Utility Functions ($Revision: 10 $)
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
61da177e4SLinus Torvalds  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
9fba2ae30SRafael J. Wysocki #define pr_fmt(fmt) "ACPI: utils: " fmt
10fba2ae30SRafael J. Wysocki 
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/module.h>
135a0e3ad6STejun Heo #include <linux/slab.h>
141da177e4SLinus Torvalds #include <linux/init.h>
151da177e4SLinus Torvalds #include <linux/types.h>
16fbfddae6SToshi Kani #include <linux/hardirq.h>
17fbfddae6SToshi Kani #include <linux/acpi.h>
1845fef5b8SBjørn Mork #include <linux/dynamic_debug.h>
191da177e4SLinus Torvalds 
20a192a958SLen Brown #include "internal.h"
212d12b6b3SLukas Wunner #include "sleep.h"
22a192a958SLen Brown 
231da177e4SLinus Torvalds /* --------------------------------------------------------------------------
241da177e4SLinus Torvalds                             Object Evaluation Helpers
251da177e4SLinus Torvalds    -------------------------------------------------------------------------- */
acpi_util_eval_error(acpi_handle h,acpi_string p,acpi_status s)26fba2ae30SRafael J. Wysocki static void acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
274fd7f518SHarvey Harrison {
28fba2ae30SRafael J. Wysocki 	acpi_handle_debug(h, "Evaluate [%s]: %s\n", p, acpi_format_exception(s));
294fd7f518SHarvey Harrison }
304fd7f518SHarvey Harrison 
311da177e4SLinus Torvalds acpi_status
acpi_extract_package(union acpi_object * package,struct acpi_buffer * format,struct acpi_buffer * buffer)324be44fcdSLen Brown acpi_extract_package(union acpi_object *package,
334be44fcdSLen Brown 		     struct acpi_buffer *format, struct acpi_buffer *buffer)
341da177e4SLinus Torvalds {
351da177e4SLinus Torvalds 	u32 size_required = 0;
361da177e4SLinus Torvalds 	u32 tail_offset = 0;
371da177e4SLinus Torvalds 	char *format_string = NULL;
381da177e4SLinus Torvalds 	u32 format_count = 0;
391da177e4SLinus Torvalds 	u32 i = 0;
401da177e4SLinus Torvalds 	u8 *head = NULL;
411da177e4SLinus Torvalds 	u8 *tail = NULL;
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 
444be44fcdSLen Brown 	if (!package || (package->type != ACPI_TYPE_PACKAGE)
454be44fcdSLen Brown 	    || (package->package.count < 1)) {
46fba2ae30SRafael J. Wysocki 		pr_debug("Invalid package argument\n");
47d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
481da177e4SLinus Torvalds 	}
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	if (!format || !format->pointer || (format->length < 1)) {
51fba2ae30SRafael J. Wysocki 		pr_debug("Invalid format argument\n");
52d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
531da177e4SLinus Torvalds 	}
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds 	if (!buffer) {
56fba2ae30SRafael J. Wysocki 		pr_debug("Invalid buffer argument\n");
57d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
581da177e4SLinus Torvalds 	}
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	format_count = (format->length / sizeof(char)) - 1;
611da177e4SLinus Torvalds 	if (format_count > package->package.count) {
62fba2ae30SRafael J. Wysocki 		pr_debug("Format specifies more objects [%d] than present [%d]\n",
63cece9296SLen Brown 			 format_count, package->package.count);
64d550d98dSPatrick Mochel 		return AE_BAD_DATA;
651da177e4SLinus Torvalds 	}
661da177e4SLinus Torvalds 
6750dd0969SJan Engelhardt 	format_string = format->pointer;
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds 	/*
701da177e4SLinus Torvalds 	 * Calculate size_required.
711da177e4SLinus Torvalds 	 */
721da177e4SLinus Torvalds 	for (i = 0; i < format_count; i++) {
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds 		union acpi_object *element = &(package->package.elements[i]);
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds 		switch (element->type) {
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds 		case ACPI_TYPE_INTEGER:
791da177e4SLinus Torvalds 			switch (format_string[i]) {
801da177e4SLinus Torvalds 			case 'N':
81439913ffSLin Ming 				size_required += sizeof(u64);
82439913ffSLin Ming 				tail_offset += sizeof(u64);
831da177e4SLinus Torvalds 				break;
841da177e4SLinus Torvalds 			case 'S':
854be44fcdSLen Brown 				size_required +=
86439913ffSLin Ming 				    sizeof(char *) + sizeof(u64) +
874be44fcdSLen Brown 				    sizeof(char);
881da177e4SLinus Torvalds 				tail_offset += sizeof(char *);
891da177e4SLinus Torvalds 				break;
901da177e4SLinus Torvalds 			default:
91fba2ae30SRafael J. Wysocki 				pr_debug("Invalid package element [%d]: got number, expected [%c]\n",
92cece9296SLen Brown 					 i, format_string[i]);
93d550d98dSPatrick Mochel 				return AE_BAD_DATA;
941da177e4SLinus Torvalds 			}
951da177e4SLinus Torvalds 			break;
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 		case ACPI_TYPE_STRING:
981da177e4SLinus Torvalds 		case ACPI_TYPE_BUFFER:
991da177e4SLinus Torvalds 			switch (format_string[i]) {
1001da177e4SLinus Torvalds 			case 'S':
1014be44fcdSLen Brown 				size_required +=
1024be44fcdSLen Brown 				    sizeof(char *) +
1034be44fcdSLen Brown 				    (element->string.length * sizeof(char)) +
1044be44fcdSLen Brown 				    sizeof(char);
1051da177e4SLinus Torvalds 				tail_offset += sizeof(char *);
1061da177e4SLinus Torvalds 				break;
1071da177e4SLinus Torvalds 			case 'B':
1084be44fcdSLen Brown 				size_required +=
109d93de345SFabian Frederick 				    sizeof(u8 *) + element->buffer.length;
1101da177e4SLinus Torvalds 				tail_offset += sizeof(u8 *);
1111da177e4SLinus Torvalds 				break;
1121da177e4SLinus Torvalds 			default:
113fba2ae30SRafael J. Wysocki 				pr_debug("Invalid package element [%d] got string/buffer, expected [%c]\n",
114cece9296SLen Brown 					 i, format_string[i]);
115d550d98dSPatrick Mochel 				return AE_BAD_DATA;
1161da177e4SLinus Torvalds 			}
1171da177e4SLinus Torvalds 			break;
118e3ec483aSZhang Rui 		case ACPI_TYPE_LOCAL_REFERENCE:
119e3ec483aSZhang Rui 			switch (format_string[i]) {
120e3ec483aSZhang Rui 			case 'R':
121e3ec483aSZhang Rui 				size_required += sizeof(void *);
122e3ec483aSZhang Rui 				tail_offset += sizeof(void *);
123e3ec483aSZhang Rui 				break;
124e3ec483aSZhang Rui 			default:
125fba2ae30SRafael J. Wysocki 				pr_debug("Invalid package element [%d] got reference, expected [%c]\n",
126e3ec483aSZhang Rui 					 i, format_string[i]);
127e3ec483aSZhang Rui 				return AE_BAD_DATA;
128e3ec483aSZhang Rui 			}
129e3ec483aSZhang Rui 			break;
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 		case ACPI_TYPE_PACKAGE:
1321da177e4SLinus Torvalds 		default:
133fba2ae30SRafael J. Wysocki 			pr_debug("Unsupported element at index=%d\n", i);
1341da177e4SLinus Torvalds 			/* TBD: handle nested packages... */
135d550d98dSPatrick Mochel 			return AE_SUPPORT;
1361da177e4SLinus Torvalds 		}
1371da177e4SLinus Torvalds 	}
1381da177e4SLinus Torvalds 
1391da177e4SLinus Torvalds 	/*
1401da177e4SLinus Torvalds 	 * Validate output buffer.
1411da177e4SLinus Torvalds 	 */
142e83dda06SAl Stone 	if (buffer->length == ACPI_ALLOCATE_BUFFER) {
1432d0acb4aSjhbird.choi@samsung.com 		buffer->pointer = ACPI_ALLOCATE_ZEROED(size_required);
144e83dda06SAl Stone 		if (!buffer->pointer)
145e83dda06SAl Stone 			return AE_NO_MEMORY;
146e83dda06SAl Stone 		buffer->length = size_required;
147e83dda06SAl Stone 	} else {
1481da177e4SLinus Torvalds 		if (buffer->length < size_required) {
1491da177e4SLinus Torvalds 			buffer->length = size_required;
150d550d98dSPatrick Mochel 			return AE_BUFFER_OVERFLOW;
151e83dda06SAl Stone 		} else if (buffer->length != size_required ||
152e83dda06SAl Stone 			   !buffer->pointer) {
153d550d98dSPatrick Mochel 			return AE_BAD_PARAMETER;
1541da177e4SLinus Torvalds 		}
155e83dda06SAl Stone 	}
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	head = buffer->pointer;
1581da177e4SLinus Torvalds 	tail = buffer->pointer + tail_offset;
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds 	/*
1611da177e4SLinus Torvalds 	 * Extract package data.
1621da177e4SLinus Torvalds 	 */
1631da177e4SLinus Torvalds 	for (i = 0; i < format_count; i++) {
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 		u8 **pointer = NULL;
1661da177e4SLinus Torvalds 		union acpi_object *element = &(package->package.elements[i]);
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 		switch (element->type) {
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds 		case ACPI_TYPE_INTEGER:
1711da177e4SLinus Torvalds 			switch (format_string[i]) {
1721da177e4SLinus Torvalds 			case 'N':
173439913ffSLin Ming 				*((u64 *) head) =
1744be44fcdSLen Brown 				    element->integer.value;
175439913ffSLin Ming 				head += sizeof(u64);
1761da177e4SLinus Torvalds 				break;
1771da177e4SLinus Torvalds 			case 'S':
1781da177e4SLinus Torvalds 				pointer = (u8 **) head;
1791da177e4SLinus Torvalds 				*pointer = tail;
180439913ffSLin Ming 				*((u64 *) tail) =
1814be44fcdSLen Brown 				    element->integer.value;
182439913ffSLin Ming 				head += sizeof(u64 *);
183439913ffSLin Ming 				tail += sizeof(u64);
1841da177e4SLinus Torvalds 				/* NULL terminate string */
1851da177e4SLinus Torvalds 				*tail = (char)0;
1861da177e4SLinus Torvalds 				tail += sizeof(char);
1871da177e4SLinus Torvalds 				break;
1881da177e4SLinus Torvalds 			default:
1891da177e4SLinus Torvalds 				/* Should never get here */
1901da177e4SLinus Torvalds 				break;
1911da177e4SLinus Torvalds 			}
1921da177e4SLinus Torvalds 			break;
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 		case ACPI_TYPE_STRING:
1951da177e4SLinus Torvalds 		case ACPI_TYPE_BUFFER:
1961da177e4SLinus Torvalds 			switch (format_string[i]) {
1971da177e4SLinus Torvalds 			case 'S':
1981da177e4SLinus Torvalds 				pointer = (u8 **) head;
1991da177e4SLinus Torvalds 				*pointer = tail;
2004be44fcdSLen Brown 				memcpy(tail, element->string.pointer,
2014be44fcdSLen Brown 				       element->string.length);
2021da177e4SLinus Torvalds 				head += sizeof(char *);
2031da177e4SLinus Torvalds 				tail += element->string.length * sizeof(char);
2041da177e4SLinus Torvalds 				/* NULL terminate string */
2051da177e4SLinus Torvalds 				*tail = (char)0;
2061da177e4SLinus Torvalds 				tail += sizeof(char);
2071da177e4SLinus Torvalds 				break;
2081da177e4SLinus Torvalds 			case 'B':
2091da177e4SLinus Torvalds 				pointer = (u8 **) head;
2101da177e4SLinus Torvalds 				*pointer = tail;
2114be44fcdSLen Brown 				memcpy(tail, element->buffer.pointer,
2124be44fcdSLen Brown 				       element->buffer.length);
2131da177e4SLinus Torvalds 				head += sizeof(u8 *);
214d93de345SFabian Frederick 				tail += element->buffer.length;
2151da177e4SLinus Torvalds 				break;
2161da177e4SLinus Torvalds 			default:
2171da177e4SLinus Torvalds 				/* Should never get here */
2181da177e4SLinus Torvalds 				break;
2191da177e4SLinus Torvalds 			}
2201da177e4SLinus Torvalds 			break;
221e3ec483aSZhang Rui 		case ACPI_TYPE_LOCAL_REFERENCE:
222e3ec483aSZhang Rui 			switch (format_string[i]) {
223e3ec483aSZhang Rui 			case 'R':
224e3ec483aSZhang Rui 				*(void **)head =
225e3ec483aSZhang Rui 				    (void *)element->reference.handle;
226e3ec483aSZhang Rui 				head += sizeof(void *);
227e3ec483aSZhang Rui 				break;
228e3ec483aSZhang Rui 			default:
229e3ec483aSZhang Rui 				/* Should never get here */
230e3ec483aSZhang Rui 				break;
231e3ec483aSZhang Rui 			}
232e3ec483aSZhang Rui 			break;
2331da177e4SLinus Torvalds 		case ACPI_TYPE_PACKAGE:
2341da177e4SLinus Torvalds 			/* TBD: handle nested packages... */
2351da177e4SLinus Torvalds 		default:
2361da177e4SLinus Torvalds 			/* Should never get here */
2371da177e4SLinus Torvalds 			break;
2381da177e4SLinus Torvalds 		}
2391da177e4SLinus Torvalds 	}
2401da177e4SLinus Torvalds 
241d550d98dSPatrick Mochel 	return AE_OK;
2421da177e4SLinus Torvalds }
2434be44fcdSLen Brown 
2441da177e4SLinus Torvalds EXPORT_SYMBOL(acpi_extract_package);
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds acpi_status
acpi_evaluate_integer(acpi_handle handle,acpi_string pathname,struct acpi_object_list * arguments,unsigned long long * data)2474be44fcdSLen Brown acpi_evaluate_integer(acpi_handle handle,
2481da177e4SLinus Torvalds 		      acpi_string pathname,
24927663c58SMatthew Wilcox 		      struct acpi_object_list *arguments, unsigned long long *data)
2501da177e4SLinus Torvalds {
2511da177e4SLinus Torvalds 	acpi_status status = AE_OK;
25240599072SPavel Machek 	union acpi_object element;
2531da177e4SLinus Torvalds 	struct acpi_buffer buffer = { 0, NULL };
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	if (!data)
256d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	buffer.length = sizeof(union acpi_object);
25940599072SPavel Machek 	buffer.pointer = &element;
2601da177e4SLinus Torvalds 	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
2611da177e4SLinus Torvalds 	if (ACPI_FAILURE(status)) {
2621da177e4SLinus Torvalds 		acpi_util_eval_error(handle, pathname, status);
263d550d98dSPatrick Mochel 		return status;
2641da177e4SLinus Torvalds 	}
2651da177e4SLinus Torvalds 
26640599072SPavel Machek 	if (element.type != ACPI_TYPE_INTEGER) {
2671da177e4SLinus Torvalds 		acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
268d550d98dSPatrick Mochel 		return AE_BAD_DATA;
2691da177e4SLinus Torvalds 	}
2701da177e4SLinus Torvalds 
27140599072SPavel Machek 	*data = element.integer.value;
2721da177e4SLinus Torvalds 
273fba2ae30SRafael J. Wysocki 	acpi_handle_debug(handle, "Return value [%llu]\n", *data);
2741da177e4SLinus Torvalds 
275d550d98dSPatrick Mochel 	return AE_OK;
2761da177e4SLinus Torvalds }
2771da177e4SLinus Torvalds 
2784be44fcdSLen Brown EXPORT_SYMBOL(acpi_evaluate_integer);
2791da177e4SLinus Torvalds 
acpi_get_local_address(acpi_handle handle,u32 * addr)2807ec16433SCalvin Johnson int acpi_get_local_address(acpi_handle handle, u32 *addr)
2817ec16433SCalvin Johnson {
2827ec16433SCalvin Johnson 	unsigned long long adr;
2837ec16433SCalvin Johnson 	acpi_status status;
2847ec16433SCalvin Johnson 
2857ec16433SCalvin Johnson 	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr);
2867ec16433SCalvin Johnson 	if (ACPI_FAILURE(status))
2877ec16433SCalvin Johnson 		return -ENODATA;
2887ec16433SCalvin Johnson 
2897ec16433SCalvin Johnson 	*addr = (u32)adr;
2907ec16433SCalvin Johnson 	return 0;
2917ec16433SCalvin Johnson }
2927ec16433SCalvin Johnson EXPORT_SYMBOL(acpi_get_local_address);
2937ec16433SCalvin Johnson 
29493064e15SStefan Binding #define ACPI_MAX_SUB_BUF_SIZE	9
29593064e15SStefan Binding 
acpi_get_subsystem_id(acpi_handle handle)29693064e15SStefan Binding const char *acpi_get_subsystem_id(acpi_handle handle)
29793064e15SStefan Binding {
29893064e15SStefan Binding 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
29993064e15SStefan Binding 	union acpi_object *obj;
30093064e15SStefan Binding 	acpi_status status;
30193064e15SStefan Binding 	const char *sub;
30293064e15SStefan Binding 	size_t len;
30393064e15SStefan Binding 
30493064e15SStefan Binding 	status = acpi_evaluate_object(handle, METHOD_NAME__SUB, NULL, &buffer);
30593064e15SStefan Binding 	if (ACPI_FAILURE(status)) {
30693064e15SStefan Binding 		acpi_handle_debug(handle, "Reading ACPI _SUB failed: %#x\n", status);
30793064e15SStefan Binding 		return ERR_PTR(-ENODATA);
30893064e15SStefan Binding 	}
30993064e15SStefan Binding 
31093064e15SStefan Binding 	obj = buffer.pointer;
31193064e15SStefan Binding 	if (obj->type == ACPI_TYPE_STRING) {
31293064e15SStefan Binding 		len = strlen(obj->string.pointer);
31393064e15SStefan Binding 		if (len < ACPI_MAX_SUB_BUF_SIZE && len > 0) {
31493064e15SStefan Binding 			sub = kstrdup(obj->string.pointer, GFP_KERNEL);
31593064e15SStefan Binding 			if (!sub)
31693064e15SStefan Binding 				sub = ERR_PTR(-ENOMEM);
31793064e15SStefan Binding 		} else {
31893064e15SStefan Binding 			acpi_handle_err(handle, "ACPI _SUB Length %zu is Invalid\n", len);
31993064e15SStefan Binding 			sub = ERR_PTR(-ENODATA);
32093064e15SStefan Binding 		}
32193064e15SStefan Binding 	} else {
32293064e15SStefan Binding 		acpi_handle_warn(handle, "Warning ACPI _SUB did not return a string\n");
32393064e15SStefan Binding 		sub = ERR_PTR(-ENODATA);
32493064e15SStefan Binding 	}
32593064e15SStefan Binding 
32693064e15SStefan Binding 	acpi_os_free(buffer.pointer);
32793064e15SStefan Binding 
32893064e15SStefan Binding 	return sub;
32993064e15SStefan Binding }
33093064e15SStefan Binding EXPORT_SYMBOL_GPL(acpi_get_subsystem_id);
33193064e15SStefan Binding 
3321da177e4SLinus Torvalds acpi_status
acpi_evaluate_reference(acpi_handle handle,acpi_string pathname,struct acpi_object_list * arguments,struct acpi_handle_list * list)3334be44fcdSLen Brown acpi_evaluate_reference(acpi_handle handle,
3341da177e4SLinus Torvalds 			acpi_string pathname,
3351da177e4SLinus Torvalds 			struct acpi_object_list *arguments,
3361da177e4SLinus Torvalds 			struct acpi_handle_list *list)
3371da177e4SLinus Torvalds {
3381da177e4SLinus Torvalds 	acpi_status status = AE_OK;
3391da177e4SLinus Torvalds 	union acpi_object *package = NULL;
3401da177e4SLinus Torvalds 	union acpi_object *element = NULL;
3411da177e4SLinus Torvalds 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
3421da177e4SLinus Torvalds 	u32 i = 0;
3431da177e4SLinus Torvalds 
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds 	if (!list) {
346d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
3471da177e4SLinus Torvalds 	}
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds 	/* Evaluate object. */
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds 	status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
3521da177e4SLinus Torvalds 	if (ACPI_FAILURE(status))
3531da177e4SLinus Torvalds 		goto end;
3541da177e4SLinus Torvalds 
35550dd0969SJan Engelhardt 	package = buffer.pointer;
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	if ((buffer.length == 0) || !package) {
3581da177e4SLinus Torvalds 		status = AE_BAD_DATA;
3591da177e4SLinus Torvalds 		acpi_util_eval_error(handle, pathname, status);
3601da177e4SLinus Torvalds 		goto end;
3611da177e4SLinus Torvalds 	}
3621da177e4SLinus Torvalds 	if (package->type != ACPI_TYPE_PACKAGE) {
3631da177e4SLinus Torvalds 		status = AE_BAD_DATA;
3641da177e4SLinus Torvalds 		acpi_util_eval_error(handle, pathname, status);
3651da177e4SLinus Torvalds 		goto end;
3661da177e4SLinus Torvalds 	}
3671da177e4SLinus Torvalds 	if (!package->package.count) {
3681da177e4SLinus Torvalds 		status = AE_BAD_DATA;
3691da177e4SLinus Torvalds 		acpi_util_eval_error(handle, pathname, status);
3701da177e4SLinus Torvalds 		goto end;
3711da177e4SLinus Torvalds 	}
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 	if (package->package.count > ACPI_MAX_HANDLES) {
37409e15086SXiongfeng Wang 		kfree(package);
375d550d98dSPatrick Mochel 		return AE_NO_MEMORY;
3761da177e4SLinus Torvalds 	}
3771da177e4SLinus Torvalds 	list->count = package->package.count;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	/* Extract package data. */
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 	for (i = 0; i < list->count; i++) {
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 		element = &(package->package.elements[i]);
3841da177e4SLinus Torvalds 
385cd0b2248SBob Moore 		if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
3861da177e4SLinus Torvalds 			status = AE_BAD_DATA;
3871da177e4SLinus Torvalds 			acpi_util_eval_error(handle, pathname, status);
3881da177e4SLinus Torvalds 			break;
3891da177e4SLinus Torvalds 		}
3901da177e4SLinus Torvalds 
391b6a16387SThomas Renninger 		if (!element->reference.handle) {
392b6a16387SThomas Renninger 			status = AE_NULL_ENTRY;
393c48cf1b9SRafael J. Wysocki 			acpi_util_eval_error(handle, pathname, status);
394b6a16387SThomas Renninger 			break;
395b6a16387SThomas Renninger 		}
3961da177e4SLinus Torvalds 		/* Get the  acpi_handle. */
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds 		list->handles[i] = element->reference.handle;
399fba2ae30SRafael J. Wysocki 		acpi_handle_debug(list->handles[i], "Found in reference list\n");
4001da177e4SLinus Torvalds 	}
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds       end:
4031da177e4SLinus Torvalds 	if (ACPI_FAILURE(status)) {
4041da177e4SLinus Torvalds 		list->count = 0;
4051da177e4SLinus Torvalds 		//kfree(list->handles);
4061da177e4SLinus Torvalds 	}
4071da177e4SLinus Torvalds 
40802438d87SLen Brown 	kfree(buffer.pointer);
4091da177e4SLinus Torvalds 
410d550d98dSPatrick Mochel 	return status;
4111da177e4SLinus Torvalds }
4121da177e4SLinus Torvalds 
4134be44fcdSLen Brown EXPORT_SYMBOL(acpi_evaluate_reference);
41438ac0f1bSMatthew Garrett 
41538ac0f1bSMatthew Garrett acpi_status
acpi_get_physical_device_location(acpi_handle handle,struct acpi_pld_info ** pld)4168ede06abSFeng Tang acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld)
41738ac0f1bSMatthew Garrett {
41838ac0f1bSMatthew Garrett 	acpi_status status;
41938ac0f1bSMatthew Garrett 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
42038ac0f1bSMatthew Garrett 	union acpi_object *output;
42138ac0f1bSMatthew Garrett 
42238ac0f1bSMatthew Garrett 	status = acpi_evaluate_object(handle, "_PLD", NULL, &buffer);
42338ac0f1bSMatthew Garrett 
42438ac0f1bSMatthew Garrett 	if (ACPI_FAILURE(status))
42538ac0f1bSMatthew Garrett 		return status;
42638ac0f1bSMatthew Garrett 
42738ac0f1bSMatthew Garrett 	output = buffer.pointer;
42838ac0f1bSMatthew Garrett 
42938ac0f1bSMatthew Garrett 	if (!output || output->type != ACPI_TYPE_PACKAGE
43038ac0f1bSMatthew Garrett 	    || !output->package.count
43138ac0f1bSMatthew Garrett 	    || output->package.elements[0].type != ACPI_TYPE_BUFFER
4328ede06abSFeng Tang 	    || output->package.elements[0].buffer.length < ACPI_PLD_REV1_BUFFER_SIZE) {
43338ac0f1bSMatthew Garrett 		status = AE_TYPE;
43438ac0f1bSMatthew Garrett 		goto out;
43538ac0f1bSMatthew Garrett 	}
43638ac0f1bSMatthew Garrett 
4378ede06abSFeng Tang 	status = acpi_decode_pld_buffer(
4388ede06abSFeng Tang 			output->package.elements[0].buffer.pointer,
4398ede06abSFeng Tang 			output->package.elements[0].buffer.length,
4408ede06abSFeng Tang 			pld);
4418ede06abSFeng Tang 
44238ac0f1bSMatthew Garrett out:
44338ac0f1bSMatthew Garrett 	kfree(buffer.pointer);
44438ac0f1bSMatthew Garrett 	return status;
44538ac0f1bSMatthew Garrett }
44638ac0f1bSMatthew Garrett EXPORT_SYMBOL(acpi_get_physical_device_location);
447275c58d7SToshi Kani 
448275c58d7SToshi Kani /**
449700b8422SRafael J. Wysocki  * acpi_evaluate_ost: Evaluate _OST for hotplug operations
450275c58d7SToshi Kani  * @handle: ACPI device handle
451275c58d7SToshi Kani  * @source_event: source event code
452275c58d7SToshi Kani  * @status_code: status code
453275c58d7SToshi Kani  * @status_buf: optional detailed information (NULL if none)
454275c58d7SToshi Kani  *
455275c58d7SToshi Kani  * Evaluate _OST for hotplug operations. All ACPI hotplug handlers
456275c58d7SToshi Kani  * must call this function when evaluating _OST for hotplug operations.
457275c58d7SToshi Kani  * When the platform does not support _OST, this function has no effect.
458275c58d7SToshi Kani  */
459275c58d7SToshi Kani acpi_status
acpi_evaluate_ost(acpi_handle handle,u32 source_event,u32 status_code,struct acpi_buffer * status_buf)46005730c19SJiang Liu acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
46105730c19SJiang Liu 		  struct acpi_buffer *status_buf)
462275c58d7SToshi Kani {
463275c58d7SToshi Kani 	union acpi_object params[3] = {
464275c58d7SToshi Kani 		{.type = ACPI_TYPE_INTEGER,},
465275c58d7SToshi Kani 		{.type = ACPI_TYPE_INTEGER,},
466275c58d7SToshi Kani 		{.type = ACPI_TYPE_BUFFER,}
467275c58d7SToshi Kani 	};
468275c58d7SToshi Kani 	struct acpi_object_list arg_list = {3, params};
469275c58d7SToshi Kani 
470275c58d7SToshi Kani 	params[0].integer.value = source_event;
471275c58d7SToshi Kani 	params[1].integer.value = status_code;
472275c58d7SToshi Kani 	if (status_buf != NULL) {
473275c58d7SToshi Kani 		params[2].buffer.pointer = status_buf->pointer;
474275c58d7SToshi Kani 		params[2].buffer.length = status_buf->length;
475275c58d7SToshi Kani 	} else {
476275c58d7SToshi Kani 		params[2].buffer.pointer = NULL;
477275c58d7SToshi Kani 		params[2].buffer.length = 0;
478275c58d7SToshi Kani 	}
479275c58d7SToshi Kani 
48005730c19SJiang Liu 	return acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
481275c58d7SToshi Kani }
48205730c19SJiang Liu EXPORT_SYMBOL(acpi_evaluate_ost);
483fbfddae6SToshi Kani 
484fbfddae6SToshi Kani /**
48545fef5b8SBjørn Mork  * acpi_handle_path: Return the object path of handle
4868373f8c6SAndy Shevchenko  * @handle: ACPI device handle
48745fef5b8SBjørn Mork  *
48845fef5b8SBjørn Mork  * Caller must free the returned buffer
48945fef5b8SBjørn Mork  */
acpi_handle_path(acpi_handle handle)49045fef5b8SBjørn Mork static char *acpi_handle_path(acpi_handle handle)
49145fef5b8SBjørn Mork {
49245fef5b8SBjørn Mork 	struct acpi_buffer buffer = {
49345fef5b8SBjørn Mork 		.length = ACPI_ALLOCATE_BUFFER,
49445fef5b8SBjørn Mork 		.pointer = NULL
49545fef5b8SBjørn Mork 	};
49645fef5b8SBjørn Mork 
49745fef5b8SBjørn Mork 	if (in_interrupt() ||
49845fef5b8SBjørn Mork 	    acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK)
49945fef5b8SBjørn Mork 		return NULL;
50045fef5b8SBjørn Mork 	return buffer.pointer;
50145fef5b8SBjørn Mork }
50245fef5b8SBjørn Mork 
50345fef5b8SBjørn Mork /**
504fbfddae6SToshi Kani  * acpi_handle_printk: Print message with ACPI prefix and object path
5058373f8c6SAndy Shevchenko  * @level: log level
5068373f8c6SAndy Shevchenko  * @handle: ACPI device handle
5078373f8c6SAndy Shevchenko  * @fmt: format string
508fbfddae6SToshi Kani  *
509fbfddae6SToshi Kani  * This function is called through acpi_handle_<level> macros and prints
510fbfddae6SToshi Kani  * a message with ACPI prefix and object path.  This function acquires
511fbfddae6SToshi Kani  * the global namespace mutex to obtain an object path.  In interrupt
512fbfddae6SToshi Kani  * context, it shows the object path as <n/a>.
513fbfddae6SToshi Kani  */
514fbfddae6SToshi Kani void
acpi_handle_printk(const char * level,acpi_handle handle,const char * fmt,...)515fbfddae6SToshi Kani acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...)
516fbfddae6SToshi Kani {
517fbfddae6SToshi Kani 	struct va_format vaf;
518fbfddae6SToshi Kani 	va_list args;
519fbfddae6SToshi Kani 	const char *path;
520fbfddae6SToshi Kani 
521fbfddae6SToshi Kani 	va_start(args, fmt);
522fbfddae6SToshi Kani 	vaf.fmt = fmt;
523fbfddae6SToshi Kani 	vaf.va = &args;
524fbfddae6SToshi Kani 
52545fef5b8SBjørn Mork 	path = acpi_handle_path(handle);
52645fef5b8SBjørn Mork 	printk("%sACPI: %s: %pV", level, path ? path : "<n/a>" , &vaf);
527fbfddae6SToshi Kani 
528fbfddae6SToshi Kani 	va_end(args);
52945fef5b8SBjørn Mork 	kfree(path);
530fbfddae6SToshi Kani }
531fbfddae6SToshi Kani EXPORT_SYMBOL(acpi_handle_printk);
532952c63e9SJiang Liu 
53345fef5b8SBjørn Mork #if defined(CONFIG_DYNAMIC_DEBUG)
53445fef5b8SBjørn Mork /**
53545fef5b8SBjørn Mork  * __acpi_handle_debug: pr_debug with ACPI prefix and object path
5368373f8c6SAndy Shevchenko  * @descriptor: Dynamic Debug descriptor
5378373f8c6SAndy Shevchenko  * @handle: ACPI device handle
5388373f8c6SAndy Shevchenko  * @fmt: format string
53945fef5b8SBjørn Mork  *
54045fef5b8SBjørn Mork  * This function is called through acpi_handle_debug macro and debug
54145fef5b8SBjørn Mork  * prints a message with ACPI prefix and object path. This function
54245fef5b8SBjørn Mork  * acquires the global namespace mutex to obtain an object path.  In
54345fef5b8SBjørn Mork  * interrupt context, it shows the object path as <n/a>.
54445fef5b8SBjørn Mork  */
54545fef5b8SBjørn Mork void
__acpi_handle_debug(struct _ddebug * descriptor,acpi_handle handle,const char * fmt,...)54645fef5b8SBjørn Mork __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle,
54745fef5b8SBjørn Mork 		    const char *fmt, ...)
54845fef5b8SBjørn Mork {
54945fef5b8SBjørn Mork 	struct va_format vaf;
55045fef5b8SBjørn Mork 	va_list args;
55145fef5b8SBjørn Mork 	const char *path;
55245fef5b8SBjørn Mork 
55345fef5b8SBjørn Mork 	va_start(args, fmt);
55445fef5b8SBjørn Mork 	vaf.fmt = fmt;
55545fef5b8SBjørn Mork 	vaf.va = &args;
55645fef5b8SBjørn Mork 
55745fef5b8SBjørn Mork 	path = acpi_handle_path(handle);
55845fef5b8SBjørn Mork 	__dynamic_pr_debug(descriptor, "ACPI: %s: %pV", path ? path : "<n/a>", &vaf);
55945fef5b8SBjørn Mork 
56045fef5b8SBjørn Mork 	va_end(args);
56145fef5b8SBjørn Mork 	kfree(path);
56245fef5b8SBjørn Mork }
56345fef5b8SBjørn Mork EXPORT_SYMBOL(__acpi_handle_debug);
56445fef5b8SBjørn Mork #endif
56545fef5b8SBjørn Mork 
566952c63e9SJiang Liu /**
5674c324548SRafael J. Wysocki  * acpi_evaluation_failure_warn - Log evaluation failure warning.
5684c324548SRafael J. Wysocki  * @handle: Parent object handle.
5694c324548SRafael J. Wysocki  * @name: Name of the object whose evaluation has failed.
5704c324548SRafael J. Wysocki  * @status: Status value returned by the failing object evaluation.
5714c324548SRafael J. Wysocki  */
acpi_evaluation_failure_warn(acpi_handle handle,const char * name,acpi_status status)5724c324548SRafael J. Wysocki void acpi_evaluation_failure_warn(acpi_handle handle, const char *name,
5734c324548SRafael J. Wysocki 				  acpi_status status)
5744c324548SRafael J. Wysocki {
5754c324548SRafael J. Wysocki 	acpi_handle_warn(handle, "%s evaluation failed: %s\n", name,
5764c324548SRafael J. Wysocki 			 acpi_format_exception(status));
5774c324548SRafael J. Wysocki }
5784c324548SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_evaluation_failure_warn);
5794c324548SRafael J. Wysocki 
5804c324548SRafael J. Wysocki /**
581952c63e9SJiang Liu  * acpi_has_method: Check whether @handle has a method named @name
582952c63e9SJiang Liu  * @handle: ACPI device handle
583952c63e9SJiang Liu  * @name: name of object or method
584952c63e9SJiang Liu  *
585952c63e9SJiang Liu  * Check whether @handle has a method named @name.
586952c63e9SJiang Liu  */
acpi_has_method(acpi_handle handle,char * name)587952c63e9SJiang Liu bool acpi_has_method(acpi_handle handle, char *name)
588952c63e9SJiang Liu {
589952c63e9SJiang Liu 	acpi_handle tmp;
590952c63e9SJiang Liu 
591952c63e9SJiang Liu 	return ACPI_SUCCESS(acpi_get_handle(handle, name, &tmp));
592952c63e9SJiang Liu }
593952c63e9SJiang Liu EXPORT_SYMBOL(acpi_has_method);
5940db98202SJiang Liu 
acpi_execute_simple_method(acpi_handle handle,char * method,u64 arg)5950db98202SJiang Liu acpi_status acpi_execute_simple_method(acpi_handle handle, char *method,
5960db98202SJiang Liu 				       u64 arg)
5970db98202SJiang Liu {
5980db98202SJiang Liu 	union acpi_object obj = { .type = ACPI_TYPE_INTEGER };
5990db98202SJiang Liu 	struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, };
6000db98202SJiang Liu 
6010db98202SJiang Liu 	obj.integer.value = arg;
6020db98202SJiang Liu 
6030db98202SJiang Liu 	return acpi_evaluate_object(handle, method, &arg_list, NULL);
6040db98202SJiang Liu }
6050db98202SJiang Liu EXPORT_SYMBOL(acpi_execute_simple_method);
6067d2421f8SJiang Liu 
6077d2421f8SJiang Liu /**
6087d2421f8SJiang Liu  * acpi_evaluate_ej0: Evaluate _EJ0 method for hotplug operations
6097d2421f8SJiang Liu  * @handle: ACPI device handle
6107d2421f8SJiang Liu  *
6117d2421f8SJiang Liu  * Evaluate device's _EJ0 method for hotplug operations.
6127d2421f8SJiang Liu  */
acpi_evaluate_ej0(acpi_handle handle)6137d2421f8SJiang Liu acpi_status acpi_evaluate_ej0(acpi_handle handle)
6147d2421f8SJiang Liu {
6157d2421f8SJiang Liu 	acpi_status status;
6167d2421f8SJiang Liu 
6177d2421f8SJiang Liu 	status = acpi_execute_simple_method(handle, "_EJ0", 1);
6187d2421f8SJiang Liu 	if (status == AE_NOT_FOUND)
6197d2421f8SJiang Liu 		acpi_handle_warn(handle, "No _EJ0 support for device\n");
6207d2421f8SJiang Liu 	else if (ACPI_FAILURE(status))
6217d2421f8SJiang Liu 		acpi_handle_warn(handle, "Eject failed (0x%x)\n", status);
6227d2421f8SJiang Liu 
6237d2421f8SJiang Liu 	return status;
6247d2421f8SJiang Liu }
6257d2421f8SJiang Liu 
6267d2421f8SJiang Liu /**
6277d2421f8SJiang Liu  * acpi_evaluate_lck: Evaluate _LCK method to lock/unlock device
6287d2421f8SJiang Liu  * @handle: ACPI device handle
6297d2421f8SJiang Liu  * @lock: lock device if non-zero, otherwise unlock device
6307d2421f8SJiang Liu  *
6317d2421f8SJiang Liu  * Evaluate device's _LCK method if present to lock/unlock device
6327d2421f8SJiang Liu  */
acpi_evaluate_lck(acpi_handle handle,int lock)6337d2421f8SJiang Liu acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
6347d2421f8SJiang Liu {
6357d2421f8SJiang Liu 	acpi_status status;
6367d2421f8SJiang Liu 
6377d2421f8SJiang Liu 	status = acpi_execute_simple_method(handle, "_LCK", !!lock);
6387d2421f8SJiang Liu 	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
6397d2421f8SJiang Liu 		if (lock)
6407d2421f8SJiang Liu 			acpi_handle_warn(handle,
6417d2421f8SJiang Liu 				"Locking device failed (0x%x)\n", status);
6427d2421f8SJiang Liu 		else
6437d2421f8SJiang Liu 			acpi_handle_warn(handle,
6447d2421f8SJiang Liu 				"Unlocking device failed (0x%x)\n", status);
6457d2421f8SJiang Liu 	}
6467d2421f8SJiang Liu 
6477d2421f8SJiang Liu 	return status;
6487d2421f8SJiang Liu }
649a65ac520SJiang Liu 
650a65ac520SJiang Liu /**
651132565d8SHans de Goede  * acpi_evaluate_reg: Evaluate _REG method to register OpRegion presence
652132565d8SHans de Goede  * @handle: ACPI device handle
653132565d8SHans de Goede  * @space_id: ACPI address space id to register OpRegion presence for
654132565d8SHans de Goede  * @function: Parameter to pass to _REG one of ACPI_REG_CONNECT or
655132565d8SHans de Goede  *            ACPI_REG_DISCONNECT
656132565d8SHans de Goede  *
657132565d8SHans de Goede  * Evaluate device's _REG method to register OpRegion presence.
658132565d8SHans de Goede  */
acpi_evaluate_reg(acpi_handle handle,u8 space_id,u32 function)659132565d8SHans de Goede acpi_status acpi_evaluate_reg(acpi_handle handle, u8 space_id, u32 function)
660132565d8SHans de Goede {
661132565d8SHans de Goede 	struct acpi_object_list arg_list;
662132565d8SHans de Goede 	union acpi_object params[2];
663132565d8SHans de Goede 
664132565d8SHans de Goede 	params[0].type = ACPI_TYPE_INTEGER;
665132565d8SHans de Goede 	params[0].integer.value = space_id;
666132565d8SHans de Goede 	params[1].type = ACPI_TYPE_INTEGER;
667132565d8SHans de Goede 	params[1].integer.value = function;
668132565d8SHans de Goede 	arg_list.count = 2;
669132565d8SHans de Goede 	arg_list.pointer = params;
670132565d8SHans de Goede 
671132565d8SHans de Goede 	return acpi_evaluate_object(handle, "_REG", &arg_list, NULL);
672132565d8SHans de Goede }
673132565d8SHans de Goede EXPORT_SYMBOL(acpi_evaluate_reg);
674132565d8SHans de Goede 
675132565d8SHans de Goede /**
676a65ac520SJiang Liu  * acpi_evaluate_dsm - evaluate device's _DSM method
677a65ac520SJiang Liu  * @handle: ACPI device handle
67894116f81SAndy Shevchenko  * @guid: GUID of requested functions, should be 16 bytes
679a65ac520SJiang Liu  * @rev: revision number of requested function
680a65ac520SJiang Liu  * @func: requested function number
681a65ac520SJiang Liu  * @argv4: the function specific parameter
682a65ac520SJiang Liu  *
68394116f81SAndy Shevchenko  * Evaluate device's _DSM method with specified GUID, revision id and
684a65ac520SJiang Liu  * function number. Caller needs to free the returned object.
685a65ac520SJiang Liu  *
686a65ac520SJiang Liu  * Though ACPI defines the fourth parameter for _DSM should be a package,
687a65ac520SJiang Liu  * some old BIOSes do expect a buffer or an integer etc.
688a65ac520SJiang Liu  */
689a65ac520SJiang Liu union acpi_object *
acpi_evaluate_dsm(acpi_handle handle,const guid_t * guid,u64 rev,u64 func,union acpi_object * argv4)69094116f81SAndy Shevchenko acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 func,
691a65ac520SJiang Liu 		  union acpi_object *argv4)
692a65ac520SJiang Liu {
693a65ac520SJiang Liu 	acpi_status ret;
694a65ac520SJiang Liu 	struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
695a65ac520SJiang Liu 	union acpi_object params[4];
696a65ac520SJiang Liu 	struct acpi_object_list input = {
697a65ac520SJiang Liu 		.count = 4,
698a65ac520SJiang Liu 		.pointer = params,
699a65ac520SJiang Liu 	};
700a65ac520SJiang Liu 
701a65ac520SJiang Liu 	params[0].type = ACPI_TYPE_BUFFER;
702a65ac520SJiang Liu 	params[0].buffer.length = 16;
70394116f81SAndy Shevchenko 	params[0].buffer.pointer = (u8 *)guid;
704a65ac520SJiang Liu 	params[1].type = ACPI_TYPE_INTEGER;
705a65ac520SJiang Liu 	params[1].integer.value = rev;
706a65ac520SJiang Liu 	params[2].type = ACPI_TYPE_INTEGER;
707a65ac520SJiang Liu 	params[2].integer.value = func;
708a65ac520SJiang Liu 	if (argv4) {
709a65ac520SJiang Liu 		params[3] = *argv4;
710a65ac520SJiang Liu 	} else {
711a65ac520SJiang Liu 		params[3].type = ACPI_TYPE_PACKAGE;
712a65ac520SJiang Liu 		params[3].package.count = 0;
713a65ac520SJiang Liu 		params[3].package.elements = NULL;
714a65ac520SJiang Liu 	}
715a65ac520SJiang Liu 
716a65ac520SJiang Liu 	ret = acpi_evaluate_object(handle, "_DSM", &input, &buf);
717a65ac520SJiang Liu 	if (ACPI_SUCCESS(ret))
718a65ac520SJiang Liu 		return (union acpi_object *)buf.pointer;
719a65ac520SJiang Liu 
720a65ac520SJiang Liu 	if (ret != AE_NOT_FOUND)
721a65ac520SJiang Liu 		acpi_handle_warn(handle,
72206eb8dc0SMichael Niewöhner 				 "failed to evaluate _DSM %pUb (0x%x)\n", guid, ret);
723a65ac520SJiang Liu 
724a65ac520SJiang Liu 	return NULL;
725a65ac520SJiang Liu }
726a65ac520SJiang Liu EXPORT_SYMBOL(acpi_evaluate_dsm);
727a65ac520SJiang Liu 
728a65ac520SJiang Liu /**
729a65ac520SJiang Liu  * acpi_check_dsm - check if _DSM method supports requested functions.
730a65ac520SJiang Liu  * @handle: ACPI device handle
73194116f81SAndy Shevchenko  * @guid: GUID of requested functions, should be 16 bytes at least
732a65ac520SJiang Liu  * @rev: revision number of requested functions
733a65ac520SJiang Liu  * @funcs: bitmap of requested functions
734a65ac520SJiang Liu  *
735a65ac520SJiang Liu  * Evaluate device's _DSM method to check whether it supports requested
736a65ac520SJiang Liu  * functions. Currently only support 64 functions at maximum, should be
737a65ac520SJiang Liu  * enough for now.
738a65ac520SJiang Liu  */
acpi_check_dsm(acpi_handle handle,const guid_t * guid,u64 rev,u64 funcs)73994116f81SAndy Shevchenko bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs)
740a65ac520SJiang Liu {
741a65ac520SJiang Liu 	int i;
742a65ac520SJiang Liu 	u64 mask = 0;
743a65ac520SJiang Liu 	union acpi_object *obj;
744a65ac520SJiang Liu 
745a7225598SDan Williams 	if (funcs == 0)
746a7225598SDan Williams 		return false;
747a7225598SDan Williams 
74894116f81SAndy Shevchenko 	obj = acpi_evaluate_dsm(handle, guid, rev, 0, NULL);
749a65ac520SJiang Liu 	if (!obj)
750a65ac520SJiang Liu 		return false;
751a65ac520SJiang Liu 
752a65ac520SJiang Liu 	/* For compatibility, old BIOSes may return an integer */
753a65ac520SJiang Liu 	if (obj->type == ACPI_TYPE_INTEGER)
754a65ac520SJiang Liu 		mask = obj->integer.value;
755a65ac520SJiang Liu 	else if (obj->type == ACPI_TYPE_BUFFER)
756a65ac520SJiang Liu 		for (i = 0; i < obj->buffer.length && i < 8; i++)
7574a798f50SColin Ian King 			mask |= (((u64)obj->buffer.pointer[i]) << (i * 8));
758a65ac520SJiang Liu 	ACPI_FREE(obj);
759a65ac520SJiang Liu 
760a65ac520SJiang Liu 	/*
761a65ac520SJiang Liu 	 * Bit 0 indicates whether there's support for any functions other than
76294116f81SAndy Shevchenko 	 * function 0 for the specified GUID and revision.
763a65ac520SJiang Liu 	 */
764a65ac520SJiang Liu 	if ((mask & 0x1) && (mask & funcs) == funcs)
765a65ac520SJiang Liu 		return true;
766a65ac520SJiang Liu 
767a65ac520SJiang Liu 	return false;
768a65ac520SJiang Liu }
769a65ac520SJiang Liu EXPORT_SYMBOL(acpi_check_dsm);
77014ca7a47SHans de Goede 
7712d12b6b3SLukas Wunner /**
77235009c80SAndy Shevchenko  * acpi_dev_hid_uid_match - Match device by supplied HID and UID
77335009c80SAndy Shevchenko  * @adev: ACPI device to match.
77435009c80SAndy Shevchenko  * @hid2: Hardware ID of the device.
77535009c80SAndy Shevchenko  * @uid2: Unique ID of the device, pass NULL to not check _UID.
77635009c80SAndy Shevchenko  *
77735009c80SAndy Shevchenko  * Matches HID and UID in @adev with given @hid2 and @uid2.
77835009c80SAndy Shevchenko  * Returns true if matches.
77935009c80SAndy Shevchenko  */
acpi_dev_hid_uid_match(struct acpi_device * adev,const char * hid2,const char * uid2)78035009c80SAndy Shevchenko bool acpi_dev_hid_uid_match(struct acpi_device *adev,
78135009c80SAndy Shevchenko 			    const char *hid2, const char *uid2)
78235009c80SAndy Shevchenko {
78335009c80SAndy Shevchenko 	const char *hid1 = acpi_device_hid(adev);
78435009c80SAndy Shevchenko 	const char *uid1 = acpi_device_uid(adev);
78535009c80SAndy Shevchenko 
78635009c80SAndy Shevchenko 	if (strcmp(hid1, hid2))
78735009c80SAndy Shevchenko 		return false;
78835009c80SAndy Shevchenko 
78935009c80SAndy Shevchenko 	if (!uid2)
79035009c80SAndy Shevchenko 		return true;
79135009c80SAndy Shevchenko 
79235009c80SAndy Shevchenko 	return uid1 && !strcmp(uid1, uid2);
79335009c80SAndy Shevchenko }
79435009c80SAndy Shevchenko EXPORT_SYMBOL(acpi_dev_hid_uid_match);
79535009c80SAndy Shevchenko 
79635009c80SAndy Shevchenko /**
797*5db72fdbSAndy Shevchenko  * acpi_dev_uid_to_integer - treat ACPI device _UID as integer
798*5db72fdbSAndy Shevchenko  * @adev: ACPI device to get _UID from
799*5db72fdbSAndy Shevchenko  * @integer: output buffer for integer
800*5db72fdbSAndy Shevchenko  *
801*5db72fdbSAndy Shevchenko  * Considers _UID as integer and converts it to @integer.
802*5db72fdbSAndy Shevchenko  *
803*5db72fdbSAndy Shevchenko  * Returns 0 on success, or negative error code otherwise.
804*5db72fdbSAndy Shevchenko  */
acpi_dev_uid_to_integer(struct acpi_device * adev,u64 * integer)805*5db72fdbSAndy Shevchenko int acpi_dev_uid_to_integer(struct acpi_device *adev, u64 *integer)
806*5db72fdbSAndy Shevchenko {
807*5db72fdbSAndy Shevchenko 	const char *uid;
808*5db72fdbSAndy Shevchenko 
809*5db72fdbSAndy Shevchenko 	if (!adev)
810*5db72fdbSAndy Shevchenko 		return -ENODEV;
811*5db72fdbSAndy Shevchenko 
812*5db72fdbSAndy Shevchenko 	uid = acpi_device_uid(adev);
813*5db72fdbSAndy Shevchenko 	if (!uid)
814*5db72fdbSAndy Shevchenko 		return -ENODATA;
815*5db72fdbSAndy Shevchenko 
816*5db72fdbSAndy Shevchenko 	return kstrtou64(uid, 0, integer);
817*5db72fdbSAndy Shevchenko }
818*5db72fdbSAndy Shevchenko EXPORT_SYMBOL(acpi_dev_uid_to_integer);
819*5db72fdbSAndy Shevchenko 
820*5db72fdbSAndy Shevchenko /**
821c68ae33eSLukas Wunner  * acpi_dev_found - Detect presence of a given ACPI device in the namespace.
8222d12b6b3SLukas Wunner  * @hid: Hardware ID of the device.
8232d12b6b3SLukas Wunner  *
8242d12b6b3SLukas Wunner  * Return %true if the device was present at the moment of invocation.
8252d12b6b3SLukas Wunner  * Note that if the device is pluggable, it may since have disappeared.
8262d12b6b3SLukas Wunner  *
8272d12b6b3SLukas Wunner  * For this function to work, acpi_bus_scan() must have been executed
8282d12b6b3SLukas Wunner  * which happens in the subsys_initcall() subsection. Hence, do not
8292d12b6b3SLukas Wunner  * call from a subsys_initcall() or earlier (use acpi_get_devices()
8302d12b6b3SLukas Wunner  * instead). Calling from module_init() is fine (which is synonymous
8312d12b6b3SLukas Wunner  * with device_initcall()).
8322d12b6b3SLukas Wunner  */
acpi_dev_found(const char * hid)833c68ae33eSLukas Wunner bool acpi_dev_found(const char *hid)
8342d12b6b3SLukas Wunner {
8352d12b6b3SLukas Wunner 	struct acpi_device_bus_id *acpi_device_bus_id;
8362d12b6b3SLukas Wunner 	bool found = false;
8372d12b6b3SLukas Wunner 
8382d12b6b3SLukas Wunner 	mutex_lock(&acpi_device_lock);
8392d12b6b3SLukas Wunner 	list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node)
8402d12b6b3SLukas Wunner 		if (!strcmp(acpi_device_bus_id->bus_id, hid)) {
8412d12b6b3SLukas Wunner 			found = true;
8422d12b6b3SLukas Wunner 			break;
8432d12b6b3SLukas Wunner 		}
8442d12b6b3SLukas Wunner 	mutex_unlock(&acpi_device_lock);
8452d12b6b3SLukas Wunner 
8462d12b6b3SLukas Wunner 	return found;
8472d12b6b3SLukas Wunner }
848c68ae33eSLukas Wunner EXPORT_SYMBOL(acpi_dev_found);
8492d12b6b3SLukas Wunner 
85067dcf8a3SAndy Shevchenko struct acpi_dev_match_info {
8518661423eSHans de Goede 	struct acpi_device_id hid[2];
8528661423eSHans de Goede 	const char *uid;
8538661423eSHans de Goede 	s64 hrv;
8548661423eSHans de Goede };
8558661423eSHans de Goede 
acpi_dev_match_cb(struct device * dev,const void * data)856418e3ea1SSuzuki K Poulose static int acpi_dev_match_cb(struct device *dev, const void *data)
8578661423eSHans de Goede {
8588661423eSHans de Goede 	struct acpi_device *adev = to_acpi_device(dev);
859418e3ea1SSuzuki K Poulose 	const struct acpi_dev_match_info *match = data;
8608661423eSHans de Goede 	unsigned long long hrv;
8618661423eSHans de Goede 	acpi_status status;
8628661423eSHans de Goede 
8638661423eSHans de Goede 	if (acpi_match_device_ids(adev, match->hid))
8648661423eSHans de Goede 		return 0;
8658661423eSHans de Goede 
8668661423eSHans de Goede 	if (match->uid && (!adev->pnp.unique_id ||
8678661423eSHans de Goede 	    strcmp(adev->pnp.unique_id, match->uid)))
8688661423eSHans de Goede 		return 0;
8698661423eSHans de Goede 
8708661423eSHans de Goede 	if (match->hrv == -1)
8718661423eSHans de Goede 		return 1;
8728661423eSHans de Goede 
8738661423eSHans de Goede 	status = acpi_evaluate_integer(adev->handle, "_HRV", NULL, &hrv);
8748661423eSHans de Goede 	if (ACPI_FAILURE(status))
8758661423eSHans de Goede 		return 0;
8768661423eSHans de Goede 
8778661423eSHans de Goede 	return hrv == match->hrv;
8788661423eSHans de Goede }
8798661423eSHans de Goede 
8808661423eSHans de Goede /**
8818661423eSHans de Goede  * acpi_dev_present - Detect that a given ACPI device is present
8828661423eSHans de Goede  * @hid: Hardware ID of the device.
8838661423eSHans de Goede  * @uid: Unique ID of the device, pass NULL to not check _UID
8848661423eSHans de Goede  * @hrv: Hardware Revision of the device, pass -1 to not check _HRV
8858661423eSHans de Goede  *
8868661423eSHans de Goede  * Return %true if a matching device was present at the moment of invocation.
8878661423eSHans de Goede  * Note that if the device is pluggable, it may since have disappeared.
8888661423eSHans de Goede  *
8898661423eSHans de Goede  * Note that unlike acpi_dev_found() this function checks the status
890e7b07d3eSAndy Shevchenko  * of the device. So for devices which are present in the DSDT, but
8918661423eSHans de Goede  * which are disabled (their _STA callback returns 0) this function
8928661423eSHans de Goede  * will return false.
8938661423eSHans de Goede  *
8948661423eSHans de Goede  * For this function to work, acpi_bus_scan() must have been executed
8958661423eSHans de Goede  * which happens in the subsys_initcall() subsection. Hence, do not
8968661423eSHans de Goede  * call from a subsys_initcall() or earlier (use acpi_get_devices()
8978661423eSHans de Goede  * instead). Calling from module_init() is fine (which is synonymous
8988661423eSHans de Goede  * with device_initcall()).
8998661423eSHans de Goede  */
acpi_dev_present(const char * hid,const char * uid,s64 hrv)9008661423eSHans de Goede bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
9018661423eSHans de Goede {
90267dcf8a3SAndy Shevchenko 	struct acpi_dev_match_info match = {};
9038661423eSHans de Goede 	struct device *dev;
9048661423eSHans de Goede 
905b75d2cd0SWolfram Sang 	strscpy(match.hid[0].id, hid, sizeof(match.hid[0].id));
9068661423eSHans de Goede 	match.uid = uid;
9078661423eSHans de Goede 	match.hrv = hrv;
9088661423eSHans de Goede 
90967dcf8a3SAndy Shevchenko 	dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
91054e3aca8SAndy Shevchenko 	put_device(dev);
9118661423eSHans de Goede 	return !!dev;
9128661423eSHans de Goede }
9138661423eSHans de Goede EXPORT_SYMBOL(acpi_dev_present);
9148661423eSHans de Goede 
91567dcf8a3SAndy Shevchenko /**
916bf263f64SDaniel Scally  * acpi_dev_get_next_match_dev - Return the next match of ACPI device
917e7b07d3eSAndy Shevchenko  * @adev: Pointer to the previous ACPI device matching this @hid, @uid and @hrv
918bf263f64SDaniel Scally  * @hid: Hardware ID of the device.
919bf263f64SDaniel Scally  * @uid: Unique ID of the device, pass NULL to not check _UID
920bf263f64SDaniel Scally  * @hrv: Hardware Revision of the device, pass -1 to not check _HRV
921bf263f64SDaniel Scally  *
922bf263f64SDaniel Scally  * Return the next match of ACPI device if another matching device was present
923bf263f64SDaniel Scally  * at the moment of invocation, or NULL otherwise.
924bf263f64SDaniel Scally  *
92581eeb2f5SAndy Shevchenko  * The caller is responsible for invoking acpi_dev_put() on the returned device.
92671f64283SAndy Shevchenko  * On the other hand the function invokes  acpi_dev_put() on the given @adev
92771f64283SAndy Shevchenko  * assuming that its reference counter had been increased beforehand.
928bf263f64SDaniel Scally  *
929bf263f64SDaniel Scally  * See additional information in acpi_dev_present() as well.
930bf263f64SDaniel Scally  */
931bf263f64SDaniel Scally struct acpi_device *
acpi_dev_get_next_match_dev(struct acpi_device * adev,const char * hid,const char * uid,s64 hrv)932bf263f64SDaniel Scally acpi_dev_get_next_match_dev(struct acpi_device *adev, const char *hid, const char *uid, s64 hrv)
933bf263f64SDaniel Scally {
934bf263f64SDaniel Scally 	struct device *start = adev ? &adev->dev : NULL;
935bf263f64SDaniel Scally 	struct acpi_dev_match_info match = {};
936bf263f64SDaniel Scally 	struct device *dev;
937bf263f64SDaniel Scally 
938b75d2cd0SWolfram Sang 	strscpy(match.hid[0].id, hid, sizeof(match.hid[0].id));
939bf263f64SDaniel Scally 	match.uid = uid;
940bf263f64SDaniel Scally 	match.hrv = hrv;
941bf263f64SDaniel Scally 
942bf263f64SDaniel Scally 	dev = bus_find_device(&acpi_bus_type, start, &match, acpi_dev_match_cb);
94371f64283SAndy Shevchenko 	acpi_dev_put(adev);
944bf263f64SDaniel Scally 	return dev ? to_acpi_device(dev) : NULL;
945bf263f64SDaniel Scally }
946bf263f64SDaniel Scally EXPORT_SYMBOL(acpi_dev_get_next_match_dev);
947bf263f64SDaniel Scally 
948bf263f64SDaniel Scally /**
949817b4d64SAndy Shevchenko  * acpi_dev_get_first_match_dev - Return the first match of ACPI device
95067dcf8a3SAndy Shevchenko  * @hid: Hardware ID of the device.
95167dcf8a3SAndy Shevchenko  * @uid: Unique ID of the device, pass NULL to not check _UID
95267dcf8a3SAndy Shevchenko  * @hrv: Hardware Revision of the device, pass -1 to not check _HRV
95367dcf8a3SAndy Shevchenko  *
954817b4d64SAndy Shevchenko  * Return the first match of ACPI device if a matching device was present
95567dcf8a3SAndy Shevchenko  * at the moment of invocation, or NULL otherwise.
95667dcf8a3SAndy Shevchenko  *
95781eeb2f5SAndy Shevchenko  * The caller is responsible for invoking acpi_dev_put() on the returned device.
958817b4d64SAndy Shevchenko  *
95967dcf8a3SAndy Shevchenko  * See additional information in acpi_dev_present() as well.
96067dcf8a3SAndy Shevchenko  */
961817b4d64SAndy Shevchenko struct acpi_device *
acpi_dev_get_first_match_dev(const char * hid,const char * uid,s64 hrv)962817b4d64SAndy Shevchenko acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv)
963817b4d64SAndy Shevchenko {
964bf263f64SDaniel Scally 	return acpi_dev_get_next_match_dev(NULL, hid, uid, hrv);
965817b4d64SAndy Shevchenko }
966817b4d64SAndy Shevchenko EXPORT_SYMBOL(acpi_dev_get_first_match_dev);
967817b4d64SAndy Shevchenko 
9688eb99e9aSHans de Goede /**
9698eb99e9aSHans de Goede  * acpi_reduced_hardware - Return if this is an ACPI-reduced-hw machine
9708eb99e9aSHans de Goede  *
9718eb99e9aSHans de Goede  * Return true when running on an ACPI-reduced-hw machine, false otherwise.
9728eb99e9aSHans de Goede  */
acpi_reduced_hardware(void)9738eb99e9aSHans de Goede bool acpi_reduced_hardware(void)
9748eb99e9aSHans de Goede {
9758eb99e9aSHans de Goede 	return acpi_gbl_reduced_hardware;
9768eb99e9aSHans de Goede }
9778eb99e9aSHans de Goede EXPORT_SYMBOL_GPL(acpi_reduced_hardware);
9788eb99e9aSHans de Goede 
97914ca7a47SHans de Goede /*
98014ca7a47SHans de Goede  * acpi_backlight= handling, this is done here rather then in video_detect.c
98114ca7a47SHans de Goede  * because __setup cannot be used in modules.
98214ca7a47SHans de Goede  */
98314ca7a47SHans de Goede char acpi_video_backlight_string[16];
98414ca7a47SHans de Goede EXPORT_SYMBOL(acpi_video_backlight_string);
98514ca7a47SHans de Goede 
acpi_backlight(char * str)98614ca7a47SHans de Goede static int __init acpi_backlight(char *str)
98714ca7a47SHans de Goede {
988b75d2cd0SWolfram Sang 	strscpy(acpi_video_backlight_string, str,
98914ca7a47SHans de Goede 		sizeof(acpi_video_backlight_string));
99014ca7a47SHans de Goede 	return 1;
99114ca7a47SHans de Goede }
99214ca7a47SHans de Goede __setup("acpi_backlight=", acpi_backlight);
9935aa5911aSToshi Kani 
9945aa5911aSToshi Kani /**
9955aa5911aSToshi Kani  * acpi_match_platform_list - Check if the system matches with a given list
9965aa5911aSToshi Kani  * @plat: pointer to acpi_platform_list table terminated by a NULL entry
9975aa5911aSToshi Kani  *
9985aa5911aSToshi Kani  * Return the matched index if the system is found in the platform list.
9995aa5911aSToshi Kani  * Otherwise, return a negative error code.
10005aa5911aSToshi Kani  */
acpi_match_platform_list(const struct acpi_platform_list * plat)10015aa5911aSToshi Kani int acpi_match_platform_list(const struct acpi_platform_list *plat)
10025aa5911aSToshi Kani {
10035aa5911aSToshi Kani 	struct acpi_table_header hdr;
10045aa5911aSToshi Kani 	int idx = 0;
10055aa5911aSToshi Kani 
10065aa5911aSToshi Kani 	if (acpi_disabled)
10075aa5911aSToshi Kani 		return -ENODEV;
10085aa5911aSToshi Kani 
10095aa5911aSToshi Kani 	for (; plat->oem_id[0]; plat++, idx++) {
10105aa5911aSToshi Kani 		if (ACPI_FAILURE(acpi_get_table_header(plat->table, 0, &hdr)))
10115aa5911aSToshi Kani 			continue;
10125aa5911aSToshi Kani 
10135aa5911aSToshi Kani 		if (strncmp(plat->oem_id, hdr.oem_id, ACPI_OEM_ID_SIZE))
10145aa5911aSToshi Kani 			continue;
10155aa5911aSToshi Kani 
10165aa5911aSToshi Kani 		if (strncmp(plat->oem_table_id, hdr.oem_table_id, ACPI_OEM_TABLE_ID_SIZE))
10175aa5911aSToshi Kani 			continue;
10185aa5911aSToshi Kani 
10195aa5911aSToshi Kani 		if ((plat->pred == all_versions) ||
10205aa5911aSToshi Kani 		    (plat->pred == less_than_or_equal && hdr.oem_revision <= plat->oem_revision) ||
10215aa5911aSToshi Kani 		    (plat->pred == greater_than_or_equal && hdr.oem_revision >= plat->oem_revision) ||
10225aa5911aSToshi Kani 		    (plat->pred == equal && hdr.oem_revision == plat->oem_revision))
10235aa5911aSToshi Kani 			return idx;
10245aa5911aSToshi Kani 	}
10255aa5911aSToshi Kani 
10265aa5911aSToshi Kani 	return -ENODEV;
10275aa5911aSToshi Kani }
10285aa5911aSToshi Kani EXPORT_SYMBOL(acpi_match_platform_list);
1029