xref: /netbsd/sys/dev/acpi/acpi_util.c (revision b61b358a)
1*b61b358aSthorpej /*	$NetBSD: acpi_util.c,v 1.33 2022/07/23 03:08:17 thorpej Exp $ */
20c88d0e4Sjruoho 
30c88d0e4Sjruoho /*-
433af1b8eSthorpej  * Copyright (c) 2003, 2007, 2021 The NetBSD Foundation, Inc.
50c88d0e4Sjruoho  * All rights reserved.
60c88d0e4Sjruoho  *
70c88d0e4Sjruoho  * This code is derived from software contributed to The NetBSD Foundation
80c88d0e4Sjruoho  * by Charles M. Hannum of By Noon Software, Inc.
90c88d0e4Sjruoho  *
100c88d0e4Sjruoho  * Redistribution and use in source and binary forms, with or without
110c88d0e4Sjruoho  * modification, are permitted provided that the following conditions
120c88d0e4Sjruoho  * are met:
130c88d0e4Sjruoho  * 1. Redistributions of source code must retain the above copyright
140c88d0e4Sjruoho  *    notice, this list of conditions and the following disclaimer.
150c88d0e4Sjruoho  * 2. Redistributions in binary form must reproduce the above copyright
160c88d0e4Sjruoho  *    notice, this list of conditions and the following disclaimer in the
170c88d0e4Sjruoho  *    documentation and/or other materials provided with the distribution.
180c88d0e4Sjruoho  *
190c88d0e4Sjruoho  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
200c88d0e4Sjruoho  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
210c88d0e4Sjruoho  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
220c88d0e4Sjruoho  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
230c88d0e4Sjruoho  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
240c88d0e4Sjruoho  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
250c88d0e4Sjruoho  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
260c88d0e4Sjruoho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
270c88d0e4Sjruoho  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
280c88d0e4Sjruoho  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
290c88d0e4Sjruoho  * POSSIBILITY OF SUCH DAMAGE.
300c88d0e4Sjruoho  */
310c88d0e4Sjruoho 
320c88d0e4Sjruoho /*
330c88d0e4Sjruoho  * Copyright 2001, 2003 Wasabi Systems, Inc.
340c88d0e4Sjruoho  * All rights reserved.
350c88d0e4Sjruoho  *
360c88d0e4Sjruoho  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
370c88d0e4Sjruoho  *
380c88d0e4Sjruoho  * Redistribution and use in source and binary forms, with or without
390c88d0e4Sjruoho  * modification, are permitted provided that the following conditions
400c88d0e4Sjruoho  * are met:
410c88d0e4Sjruoho  * 1. Redistributions of source code must retain the above copyright
420c88d0e4Sjruoho  *    notice, this list of conditions and the following disclaimer.
430c88d0e4Sjruoho  * 2. Redistributions in binary form must reproduce the above copyright
440c88d0e4Sjruoho  *    notice, this list of conditions and the following disclaimer in the
450c88d0e4Sjruoho  *    documentation and/or other materials provided with the distribution.
460c88d0e4Sjruoho  * 3. All advertising materials mentioning features or use of this software
470c88d0e4Sjruoho  *    must display the following acknowledgement:
480c88d0e4Sjruoho  *	This product includes software developed for the NetBSD Project by
490c88d0e4Sjruoho  *	Wasabi Systems, Inc.
500c88d0e4Sjruoho  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
510c88d0e4Sjruoho  *    or promote products derived from this software without specific prior
520c88d0e4Sjruoho  *    written permission.
530c88d0e4Sjruoho  *
540c88d0e4Sjruoho  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
550c88d0e4Sjruoho  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
560c88d0e4Sjruoho  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
570c88d0e4Sjruoho  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
580c88d0e4Sjruoho  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
590c88d0e4Sjruoho  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
600c88d0e4Sjruoho  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
610c88d0e4Sjruoho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
620c88d0e4Sjruoho  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
630c88d0e4Sjruoho  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
640c88d0e4Sjruoho  * POSSIBILITY OF SUCH DAMAGE.
650c88d0e4Sjruoho  */
660c88d0e4Sjruoho 
670c88d0e4Sjruoho #include <sys/cdefs.h>
68*b61b358aSthorpej __KERNEL_RCSID(0, "$NetBSD: acpi_util.c,v 1.33 2022/07/23 03:08:17 thorpej Exp $");
690c88d0e4Sjruoho 
700c88d0e4Sjruoho #include <sys/param.h>
7127ab5385Sbouyer #include <sys/kmem.h>
72c3ae344aSjmcneill #include <sys/cpu.h>
730c88d0e4Sjruoho 
740c88d0e4Sjruoho #include <dev/acpi/acpireg.h>
750c88d0e4Sjruoho #include <dev/acpi/acpivar.h>
7627ab5385Sbouyer #include <dev/acpi/acpi_intr.h>
770c88d0e4Sjruoho 
786ed8e091Sthorpej #include <sys/device_calls.h>
796ed8e091Sthorpej 
80488c5b15Sjmcneill #include <machine/acpi_machdep.h>
81488c5b15Sjmcneill 
820c88d0e4Sjruoho #define _COMPONENT	ACPI_BUS_COMPONENT
830c88d0e4Sjruoho ACPI_MODULE_NAME	("acpi_util")
840c88d0e4Sjruoho 
855e449c62Sjruoho static void		acpi_clean_node(ACPI_HANDLE, void *);
86312915a9Sjmcneill static ACPI_STATUS	acpi_dsd_property(ACPI_HANDLE, const char *,
87312915a9Sjmcneill 			    ACPI_BUFFER *, ACPI_OBJECT_TYPE, ACPI_OBJECT **);
885e449c62Sjruoho 
894bd16782Sjruoho static const char * const acpicpu_ids[] = {
904bd16782Sjruoho 	"ACPI0007",
914bd16782Sjruoho 	NULL
924bd16782Sjruoho };
934bd16782Sjruoho 
948b25d0adSjmcneill static const struct device_compatible_entry dtlink_compat_data[] = {
958b25d0adSjmcneill 	{ .compat = "PRP0001" },
968b25d0adSjmcneill 	DEVICE_COMPAT_EOL
978b25d0adSjmcneill };
988b25d0adSjmcneill 
990c88d0e4Sjruoho /*
10037aee2b1Sthorpej  * ACPI device handle support.
10137aee2b1Sthorpej  */
10237aee2b1Sthorpej 
10337aee2b1Sthorpej static device_call_t
acpi_devhandle_lookup_device_call(devhandle_t handle,const char * name,devhandle_t * call_handlep)10437aee2b1Sthorpej acpi_devhandle_lookup_device_call(devhandle_t handle, const char *name,
10537aee2b1Sthorpej     devhandle_t *call_handlep)
10637aee2b1Sthorpej {
10737aee2b1Sthorpej 	__link_set_decl(acpi_device_calls, struct device_call_descriptor);
10837aee2b1Sthorpej 	struct device_call_descriptor * const *desc;
10937aee2b1Sthorpej 
11037aee2b1Sthorpej 	__link_set_foreach(desc, acpi_device_calls) {
11137aee2b1Sthorpej 		if (strcmp((*desc)->name, name) == 0) {
11237aee2b1Sthorpej 			return (*desc)->call;
11337aee2b1Sthorpej 		}
11437aee2b1Sthorpej 	}
11537aee2b1Sthorpej 	return NULL;
11637aee2b1Sthorpej }
11737aee2b1Sthorpej 
11837aee2b1Sthorpej static const struct devhandle_impl acpi_devhandle_impl = {
11937aee2b1Sthorpej 	.type = DEVHANDLE_TYPE_ACPI,
12037aee2b1Sthorpej 	.lookup_device_call = acpi_devhandle_lookup_device_call,
12137aee2b1Sthorpej };
12237aee2b1Sthorpej 
12337aee2b1Sthorpej devhandle_t
devhandle_from_acpi(devhandle_t super_handle,ACPI_HANDLE const hdl)12409eb5c43Sthorpej devhandle_from_acpi(devhandle_t super_handle, ACPI_HANDLE const hdl)
12537aee2b1Sthorpej {
12609eb5c43Sthorpej 	devhandle_type_t super_type = devhandle_type(super_handle);
12709eb5c43Sthorpej 	devhandle_t handle = { 0 };
12809eb5c43Sthorpej 
12909eb5c43Sthorpej 	if (super_type == DEVHANDLE_TYPE_ACPI) {
13009eb5c43Sthorpej 		handle.impl = super_handle.impl;
13109eb5c43Sthorpej 	} else {
13209eb5c43Sthorpej 		KASSERT(super_type == DEVHANDLE_TYPE_INVALID);
13309eb5c43Sthorpej 		handle.impl = &acpi_devhandle_impl;
13409eb5c43Sthorpej 	}
13509eb5c43Sthorpej 	handle.pointer = hdl;
13637aee2b1Sthorpej 
13737aee2b1Sthorpej 	return handle;
13837aee2b1Sthorpej }
13937aee2b1Sthorpej 
14037aee2b1Sthorpej ACPI_HANDLE
devhandle_to_acpi(devhandle_t const handle)14137aee2b1Sthorpej devhandle_to_acpi(devhandle_t const handle)
14237aee2b1Sthorpej {
14337aee2b1Sthorpej 	KASSERT(devhandle_type(handle) == DEVHANDLE_TYPE_ACPI);
14437aee2b1Sthorpej 
14537aee2b1Sthorpej 	return handle.pointer;
14637aee2b1Sthorpej }
14737aee2b1Sthorpej 
14837aee2b1Sthorpej static int
acpi_device_enumerate_children(device_t dev,devhandle_t call_handle,void * v)14937aee2b1Sthorpej acpi_device_enumerate_children(device_t dev, devhandle_t call_handle, void *v)
15037aee2b1Sthorpej {
15137aee2b1Sthorpej 	struct device_enumerate_children_args *args = v;
15237aee2b1Sthorpej 	ACPI_HANDLE hdl = devhandle_to_acpi(call_handle);
15337aee2b1Sthorpej 	struct acpi_devnode *devnode, *ad;
15437aee2b1Sthorpej 
15537aee2b1Sthorpej 	devnode = acpi_match_node(hdl);
15637aee2b1Sthorpej 	KASSERT(devnode != NULL);
15737aee2b1Sthorpej 
15837aee2b1Sthorpej 	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
15937aee2b1Sthorpej 		if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE ||
16037aee2b1Sthorpej 		    !acpi_device_present(ad->ad_handle)) {
16137aee2b1Sthorpej 			continue;
16237aee2b1Sthorpej 		}
16309eb5c43Sthorpej 		if (!args->callback(dev, devhandle_from_acpi(call_handle,
16409eb5c43Sthorpej 							     ad->ad_handle),
16537aee2b1Sthorpej 				    args->callback_arg)) {
16637aee2b1Sthorpej 			break;
16737aee2b1Sthorpej 		}
16837aee2b1Sthorpej 	}
16937aee2b1Sthorpej 
17037aee2b1Sthorpej 	return 0;
17137aee2b1Sthorpej }
ACPI_DEVICE_CALL_REGISTER(DEVICE_ENUMERATE_CHILDREN_STR,acpi_device_enumerate_children)1726ed8e091Sthorpej ACPI_DEVICE_CALL_REGISTER(DEVICE_ENUMERATE_CHILDREN_STR,
17337aee2b1Sthorpej 			  acpi_device_enumerate_children)
17437aee2b1Sthorpej 
17537aee2b1Sthorpej /*
1760c88d0e4Sjruoho  * Evaluate an integer object.
1770c88d0e4Sjruoho  */
1780c88d0e4Sjruoho ACPI_STATUS
1790c88d0e4Sjruoho acpi_eval_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER *valp)
1800c88d0e4Sjruoho {
1810c88d0e4Sjruoho 	ACPI_OBJECT obj;
1820c88d0e4Sjruoho 	ACPI_BUFFER buf;
1830c88d0e4Sjruoho 	ACPI_STATUS rv;
1840c88d0e4Sjruoho 
1850c88d0e4Sjruoho 	if (handle == NULL)
1860c88d0e4Sjruoho 		handle = ACPI_ROOT_OBJECT;
1870c88d0e4Sjruoho 
188678179dfSgsutre 	(void)memset(&obj, 0, sizeof(obj));
1890c88d0e4Sjruoho 	buf.Pointer = &obj;
1900c88d0e4Sjruoho 	buf.Length = sizeof(obj);
1910c88d0e4Sjruoho 
1920c88d0e4Sjruoho 	rv = AcpiEvaluateObject(handle, path, NULL, &buf);
1930c88d0e4Sjruoho 
1940c88d0e4Sjruoho 	if (ACPI_FAILURE(rv))
1950c88d0e4Sjruoho 		return rv;
1960c88d0e4Sjruoho 
197678179dfSgsutre 	/* Check that evaluation produced a return value. */
198678179dfSgsutre 	if (buf.Length == 0)
199678179dfSgsutre 		return AE_NULL_OBJECT;
200678179dfSgsutre 
2010c88d0e4Sjruoho 	if (obj.Type != ACPI_TYPE_INTEGER)
2020c88d0e4Sjruoho 		return AE_TYPE;
2030c88d0e4Sjruoho 
2040c88d0e4Sjruoho 	if (valp != NULL)
2050c88d0e4Sjruoho 		*valp = obj.Integer.Value;
2060c88d0e4Sjruoho 
2070c88d0e4Sjruoho 	return AE_OK;
2080c88d0e4Sjruoho }
2090c88d0e4Sjruoho 
2100c88d0e4Sjruoho /*
2110c88d0e4Sjruoho  * Evaluate an integer object with a single integer input parameter.
2120c88d0e4Sjruoho  */
2130c88d0e4Sjruoho ACPI_STATUS
acpi_eval_set_integer(ACPI_HANDLE handle,const char * path,ACPI_INTEGER val)2140c88d0e4Sjruoho acpi_eval_set_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER val)
2150c88d0e4Sjruoho {
2160c88d0e4Sjruoho 	ACPI_OBJECT_LIST arg;
2170c88d0e4Sjruoho 	ACPI_OBJECT obj;
2180c88d0e4Sjruoho 
2190c88d0e4Sjruoho 	if (handle == NULL)
2200c88d0e4Sjruoho 		handle = ACPI_ROOT_OBJECT;
2210c88d0e4Sjruoho 
2220c88d0e4Sjruoho 	obj.Type = ACPI_TYPE_INTEGER;
2230c88d0e4Sjruoho 	obj.Integer.Value = val;
2240c88d0e4Sjruoho 
2250c88d0e4Sjruoho 	arg.Count = 1;
2260c88d0e4Sjruoho 	arg.Pointer = &obj;
2270c88d0e4Sjruoho 
2280c88d0e4Sjruoho 	return AcpiEvaluateObject(handle, path, &arg, NULL);
2290c88d0e4Sjruoho }
2300c88d0e4Sjruoho 
2310c88d0e4Sjruoho /*
2320c88d0e4Sjruoho  * Evaluate a (Unicode) string object.
2330c88d0e4Sjruoho  */
2340c88d0e4Sjruoho ACPI_STATUS
acpi_eval_string(ACPI_HANDLE handle,const char * path,char ** stringp)2350c88d0e4Sjruoho acpi_eval_string(ACPI_HANDLE handle, const char *path, char **stringp)
2360c88d0e4Sjruoho {
2370c88d0e4Sjruoho 	ACPI_OBJECT *obj;
2380c88d0e4Sjruoho 	ACPI_BUFFER buf;
2390c88d0e4Sjruoho 	ACPI_STATUS rv;
2400c88d0e4Sjruoho 
2410c88d0e4Sjruoho 	rv = acpi_eval_struct(handle, path, &buf);
2420c88d0e4Sjruoho 
2430c88d0e4Sjruoho 	if (ACPI_FAILURE(rv))
2440c88d0e4Sjruoho 		return rv;
2450c88d0e4Sjruoho 
2460c88d0e4Sjruoho 	obj = buf.Pointer;
2470c88d0e4Sjruoho 
2480c88d0e4Sjruoho 	if (obj->Type != ACPI_TYPE_STRING) {
2490c88d0e4Sjruoho 		rv = AE_TYPE;
2500c88d0e4Sjruoho 		goto out;
2510c88d0e4Sjruoho 	}
2520c88d0e4Sjruoho 
2530c88d0e4Sjruoho 	if (obj->String.Length == 0) {
2540c88d0e4Sjruoho 		rv = AE_BAD_DATA;
2550c88d0e4Sjruoho 		goto out;
2560c88d0e4Sjruoho 	}
2570c88d0e4Sjruoho 
2580c88d0e4Sjruoho 	*stringp = ACPI_ALLOCATE(obj->String.Length + 1);
2590c88d0e4Sjruoho 
2600c88d0e4Sjruoho 	if (*stringp == NULL) {
2610c88d0e4Sjruoho 		rv = AE_NO_MEMORY;
2620c88d0e4Sjruoho 		goto out;
2630c88d0e4Sjruoho 	}
2640c88d0e4Sjruoho 
2650c88d0e4Sjruoho 	(void)memcpy(*stringp, obj->String.Pointer, obj->String.Length);
2660c88d0e4Sjruoho 
2670c88d0e4Sjruoho 	(*stringp)[obj->String.Length] = '\0';
2680c88d0e4Sjruoho 
2690c88d0e4Sjruoho out:
2700c88d0e4Sjruoho 	ACPI_FREE(buf.Pointer);
2710c88d0e4Sjruoho 
2720c88d0e4Sjruoho 	return rv;
2730c88d0e4Sjruoho }
2740c88d0e4Sjruoho 
2750c88d0e4Sjruoho /*
276d6afaa44Sjruoho  * Evaluate a structure. Caller must free buf.Pointer by ACPI_FREE().
2770c88d0e4Sjruoho  */
2780c88d0e4Sjruoho ACPI_STATUS
acpi_eval_struct(ACPI_HANDLE handle,const char * path,ACPI_BUFFER * buf)2790c88d0e4Sjruoho acpi_eval_struct(ACPI_HANDLE handle, const char *path, ACPI_BUFFER *buf)
2800c88d0e4Sjruoho {
2810c88d0e4Sjruoho 
2820c88d0e4Sjruoho 	if (handle == NULL)
2830c88d0e4Sjruoho 		handle = ACPI_ROOT_OBJECT;
2840c88d0e4Sjruoho 
2850c88d0e4Sjruoho 	buf->Pointer = NULL;
2860c88d0e4Sjruoho 	buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
2870c88d0e4Sjruoho 
2880c88d0e4Sjruoho 	return AcpiEvaluateObject(handle, path, NULL, buf);
2890c88d0e4Sjruoho }
2900c88d0e4Sjruoho 
2910c88d0e4Sjruoho /*
2920c88d0e4Sjruoho  * Evaluate a reference handle from an element in a package.
2930c88d0e4Sjruoho  */
2940c88d0e4Sjruoho ACPI_STATUS
acpi_eval_reference_handle(ACPI_OBJECT * elm,ACPI_HANDLE * handle)2950c88d0e4Sjruoho acpi_eval_reference_handle(ACPI_OBJECT *elm, ACPI_HANDLE *handle)
2960c88d0e4Sjruoho {
2970c88d0e4Sjruoho 
2980c88d0e4Sjruoho 	if (elm == NULL || handle == NULL)
2990c88d0e4Sjruoho 		return AE_BAD_PARAMETER;
3000c88d0e4Sjruoho 
3010c88d0e4Sjruoho 	switch (elm->Type) {
3020c88d0e4Sjruoho 
3030c88d0e4Sjruoho 	case ACPI_TYPE_ANY:
3040c88d0e4Sjruoho 	case ACPI_TYPE_LOCAL_REFERENCE:
3050c88d0e4Sjruoho 
3060c88d0e4Sjruoho 		if (elm->Reference.Handle == NULL)
3070c88d0e4Sjruoho 			return AE_NULL_ENTRY;
3080c88d0e4Sjruoho 
3090c88d0e4Sjruoho 		*handle = elm->Reference.Handle;
3100c88d0e4Sjruoho 
3110c88d0e4Sjruoho 		return AE_OK;
3120c88d0e4Sjruoho 
3130c88d0e4Sjruoho 	case ACPI_TYPE_STRING:
3140c88d0e4Sjruoho 		return AcpiGetHandle(NULL, elm->String.Pointer, handle);
3150c88d0e4Sjruoho 
3160c88d0e4Sjruoho 	default:
3170c88d0e4Sjruoho 		return AE_TYPE;
3180c88d0e4Sjruoho 	}
3190c88d0e4Sjruoho }
3200c88d0e4Sjruoho 
3210c88d0e4Sjruoho /*
3220c88d0e4Sjruoho  * Iterate over all objects in a package, and pass them all
3230c88d0e4Sjruoho  * to a function. If the called function returns non-AE_OK,
3240c88d0e4Sjruoho  * the iteration is stopped and that value is returned.
3250c88d0e4Sjruoho  */
3260c88d0e4Sjruoho ACPI_STATUS
acpi_foreach_package_object(ACPI_OBJECT * pkg,ACPI_STATUS (* func)(ACPI_OBJECT *,void *),void * arg)3270c88d0e4Sjruoho acpi_foreach_package_object(ACPI_OBJECT *pkg,
3280c88d0e4Sjruoho     ACPI_STATUS (*func)(ACPI_OBJECT *, void *), void *arg)
3290c88d0e4Sjruoho {
3300c88d0e4Sjruoho 	ACPI_STATUS rv = AE_OK;
3310c88d0e4Sjruoho 	uint32_t i;
3320c88d0e4Sjruoho 
333e7c11148Sjruoho 	if (pkg == NULL)
3340c88d0e4Sjruoho 		return AE_BAD_PARAMETER;
3350c88d0e4Sjruoho 
336e7c11148Sjruoho 	if (pkg->Type != ACPI_TYPE_PACKAGE)
337e7c11148Sjruoho 		return AE_TYPE;
338e7c11148Sjruoho 
3390c88d0e4Sjruoho 	for (i = 0; i < pkg->Package.Count; i++) {
3400c88d0e4Sjruoho 
3410c88d0e4Sjruoho 		rv = (*func)(&pkg->Package.Elements[i], arg);
3420c88d0e4Sjruoho 
3430c88d0e4Sjruoho 		if (ACPI_FAILURE(rv))
3440c88d0e4Sjruoho 			break;
3450c88d0e4Sjruoho 	}
3460c88d0e4Sjruoho 
3470c88d0e4Sjruoho 	return rv;
3480c88d0e4Sjruoho }
3490c88d0e4Sjruoho 
3500c88d0e4Sjruoho /*
3510c88d0e4Sjruoho  * Fetch data info the specified (empty) ACPI buffer.
3520c88d0e4Sjruoho  * Caller must free buf.Pointer by ACPI_FREE().
3530c88d0e4Sjruoho  */
3540c88d0e4Sjruoho ACPI_STATUS
acpi_get(ACPI_HANDLE handle,ACPI_BUFFER * buf,ACPI_STATUS (* getit)(ACPI_HANDLE,ACPI_BUFFER *))3550c88d0e4Sjruoho acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf,
3560c88d0e4Sjruoho     ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *))
3570c88d0e4Sjruoho {
3580c88d0e4Sjruoho 
3590c88d0e4Sjruoho 	buf->Pointer = NULL;
3600c88d0e4Sjruoho 	buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
3610c88d0e4Sjruoho 
3620c88d0e4Sjruoho 	return (*getit)(handle, buf);
3630c88d0e4Sjruoho }
3640c88d0e4Sjruoho 
3650c88d0e4Sjruoho /*
3660c88d0e4Sjruoho  * Return a complete pathname from a handle.
3670c88d0e4Sjruoho  *
3680c88d0e4Sjruoho  * Note that the function uses static data storage;
3690c88d0e4Sjruoho  * if the data is needed for future use, it should be
3700c88d0e4Sjruoho  * copied before any subsequent calls overwrite it.
3710c88d0e4Sjruoho  */
3720c88d0e4Sjruoho const char *
acpi_name(ACPI_HANDLE handle)3730c88d0e4Sjruoho acpi_name(ACPI_HANDLE handle)
3740c88d0e4Sjruoho {
3750c88d0e4Sjruoho 	static char name[80];
3760c88d0e4Sjruoho 	ACPI_BUFFER buf;
3770c88d0e4Sjruoho 	ACPI_STATUS rv;
3780c88d0e4Sjruoho 
379e7c11148Sjruoho 	if (handle == NULL)
380e7c11148Sjruoho 		handle = ACPI_ROOT_OBJECT;
381e7c11148Sjruoho 
3820c88d0e4Sjruoho 	buf.Pointer = name;
3830c88d0e4Sjruoho 	buf.Length = sizeof(name);
3840c88d0e4Sjruoho 
3850c88d0e4Sjruoho 	rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf);
3860c88d0e4Sjruoho 
3870c88d0e4Sjruoho 	if (ACPI_FAILURE(rv))
3880c88d0e4Sjruoho 		return "UNKNOWN";
3890c88d0e4Sjruoho 
3900c88d0e4Sjruoho 	return name;
3910c88d0e4Sjruoho }
3920c88d0e4Sjruoho 
3930c88d0e4Sjruoho /*
394537afe45Sthorpej  * Pack _HID and _CID ID strings into an OpenFirmware-style
39533af1b8eSthorpej  * string list.
39633af1b8eSthorpej  */
39733af1b8eSthorpej char *
acpi_pack_compat_list(struct acpi_devnode * ad,size_t * sizep)398*b61b358aSthorpej acpi_pack_compat_list(struct acpi_devnode *ad, size_t *sizep)
39933af1b8eSthorpej {
400*b61b358aSthorpej 	ACPI_DEVICE_INFO *devinfo = ad->ad_devinfo;
401*b61b358aSthorpej 
40233af1b8eSthorpej 	KASSERT(sizep != NULL);
40333af1b8eSthorpej 
404537afe45Sthorpej 	char *sl = NULL;
405537afe45Sthorpej 	size_t slsize = 0;
40633af1b8eSthorpej 	uint32_t i;
407*b61b358aSthorpej 	bool dtlink = false;
40833af1b8eSthorpej 
409*b61b358aSthorpej 	ACPI_BUFFER buf;
410*b61b358aSthorpej 	ACPI_STATUS ret;
411*b61b358aSthorpej 	ACPI_OBJECT *obj;
412*b61b358aSthorpej 	char *compatible;
413*b61b358aSthorpej 	int n;
414*b61b358aSthorpej 
415*b61b358aSthorpej 	buf.Pointer = NULL;
416*b61b358aSthorpej 	buf.Length = ACPI_ALLOCATE_BUFFER;
417*b61b358aSthorpej 
418*b61b358aSthorpej 	if ((devinfo->Valid & ACPI_VALID_HID) != 0) {
419*b61b358aSthorpej 		const char *cp = devinfo->HardwareId.String;
420*b61b358aSthorpej 
421*b61b358aSthorpej 		if (device_compatible_pmatch_strlist(cp, strlen(cp) + 1,
422*b61b358aSthorpej 						     dtlink_compat_data)) {
423*b61b358aSthorpej 			dtlink = true;
424*b61b358aSthorpej 		} else {
425*b61b358aSthorpej 			strlist_append(&sl, &slsize, cp);
426*b61b358aSthorpej 		}
42733af1b8eSthorpej 	}
42833af1b8eSthorpej 
429*b61b358aSthorpej 	if ((devinfo->Valid & ACPI_VALID_CID) != 0) {
430*b61b358aSthorpej 		for (i = 0; i < devinfo->CompatibleIdList.Count; i++) {
431*b61b358aSthorpej 			const char *cp =
432*b61b358aSthorpej 			    devinfo->CompatibleIdList.Ids[i].String;
433*b61b358aSthorpej 
434*b61b358aSthorpej 			if (device_compatible_pmatch_strlist(cp, strlen(cp) + 1,
435*b61b358aSthorpej 							dtlink_compat_data)) {
436*b61b358aSthorpej 				dtlink = true;
437*b61b358aSthorpej 			} else {
438*b61b358aSthorpej 				strlist_append(&sl, &slsize, cp);
439*b61b358aSthorpej 			}
440*b61b358aSthorpej 		}
441*b61b358aSthorpej 	}
442*b61b358aSthorpej 
443*b61b358aSthorpej 	if (dtlink) {
444*b61b358aSthorpej 		ret = acpi_dsd_string(ad->ad_handle, "compatible",
445*b61b358aSthorpej 		    &compatible);
446*b61b358aSthorpej 		if (ACPI_SUCCESS(ret)) {
447*b61b358aSthorpej 			strlist_append(&sl, &slsize, compatible);
448*b61b358aSthorpej 			kmem_strfree(compatible);
449*b61b358aSthorpej 			goto done;
450*b61b358aSthorpej 		}
451*b61b358aSthorpej 
452*b61b358aSthorpej 		ret = acpi_dsd_property(ad->ad_handle, "compatible", &buf,
453*b61b358aSthorpej 		    ACPI_TYPE_PACKAGE, &obj);
454*b61b358aSthorpej 		if (ACPI_FAILURE(ret)) {
455*b61b358aSthorpej 			goto done;
456*b61b358aSthorpej 		}
457*b61b358aSthorpej 		if (obj->Package.Count == 0) {
458*b61b358aSthorpej 			goto done;
459*b61b358aSthorpej 		}
460*b61b358aSthorpej 		for (n = 0; n < obj->Package.Count; n++) {
461*b61b358aSthorpej 			if (obj->Package.Elements[n].Type != ACPI_TYPE_STRING) {
462*b61b358aSthorpej 				continue;
463*b61b358aSthorpej 			}
464537afe45Sthorpej 			strlist_append(&sl, &slsize,
465*b61b358aSthorpej 			    obj->Package.Elements[n].String.Pointer);
46633af1b8eSthorpej 		}
46733af1b8eSthorpej 	}
46833af1b8eSthorpej 
469*b61b358aSthorpej  done:
470*b61b358aSthorpej 	if (buf.Pointer != NULL) {
471*b61b358aSthorpej 		ACPI_FREE(buf.Pointer);
472*b61b358aSthorpej 	}
473537afe45Sthorpej 	*sizep = slsize;
474537afe45Sthorpej 	return sl;
475537afe45Sthorpej }
476537afe45Sthorpej 
477537afe45Sthorpej /*
478537afe45Sthorpej  * The ACPI_PNP_DEVICE_ID type is somewhat inconvenient for us to
479537afe45Sthorpej  * use.  We'll need some temporary space to pack it into an array
480537afe45Sthorpej  * of C strings.  Room for 8 should be plenty, but we can allocate
481537afe45Sthorpej  * more if necessary.
482537afe45Sthorpej  */
483537afe45Sthorpej #define	ACPI_COMPATSTR_MAX	8
484537afe45Sthorpej 
485537afe45Sthorpej static const char **
acpi_compatible_alloc_strarray(ACPI_PNP_DEVICE_ID * ids,unsigned int count,const char ** buf)486537afe45Sthorpej acpi_compatible_alloc_strarray(ACPI_PNP_DEVICE_ID *ids,
487537afe45Sthorpej     unsigned int count, const char **buf)
488537afe45Sthorpej {
489537afe45Sthorpej 	unsigned int i;
490537afe45Sthorpej 
491537afe45Sthorpej 	buf = kmem_tmpbuf_alloc(count * sizeof(const char *),
492537afe45Sthorpej 	    buf, ACPI_COMPATSTR_MAX * sizeof(const char *), KM_SLEEP);
493537afe45Sthorpej 	for (i = 0; i < count; i++) {
494537afe45Sthorpej 		buf[i] = ids[i].String;
495537afe45Sthorpej 	}
496537afe45Sthorpej 	return buf;
497537afe45Sthorpej }
498537afe45Sthorpej 
499537afe45Sthorpej static void
acpi_compatible_free_strarray(const char ** cpp,unsigned int count,const char ** buf)500537afe45Sthorpej acpi_compatible_free_strarray(const char **cpp, unsigned int count,
501537afe45Sthorpej     const char **buf)
502537afe45Sthorpej {
503537afe45Sthorpej 	kmem_tmpbuf_free(cpp, count * sizeof(const char *), buf);
504537afe45Sthorpej }
505537afe45Sthorpej 
506312915a9Sjmcneill static int
acpi_compatible_match_dtlink(const struct acpi_attach_args * const aa,const struct device_compatible_entry * const dce)507312915a9Sjmcneill acpi_compatible_match_dtlink(const struct acpi_attach_args * const aa,
508312915a9Sjmcneill     const struct device_compatible_entry * const dce)
509312915a9Sjmcneill {
510312915a9Sjmcneill 	const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)];
511312915a9Sjmcneill 	ACPI_HANDLE handle = aa->aa_node->ad_handle;
512312915a9Sjmcneill 	ACPI_BUFFER buf;
513312915a9Sjmcneill 	char *compatible;
514312915a9Sjmcneill 	ACPI_STATUS ret;
515312915a9Sjmcneill 	ACPI_OBJECT *obj;
516312915a9Sjmcneill 	int rv = 0, n;
517312915a9Sjmcneill 
518312915a9Sjmcneill 	buf.Pointer = NULL;
519312915a9Sjmcneill 	buf.Length = ACPI_ALLOCATE_BUFFER;
520312915a9Sjmcneill 
521312915a9Sjmcneill 	/* Match a single string _DSD value */
522312915a9Sjmcneill 	ret = acpi_dsd_string(handle, "compatible", &compatible);
523312915a9Sjmcneill 	if (ACPI_SUCCESS(ret)) {
524312915a9Sjmcneill 		strings[0] = compatible;
525312915a9Sjmcneill 		rv = device_compatible_pmatch(strings, 1, dce);
526312915a9Sjmcneill 		kmem_strfree(compatible);
527312915a9Sjmcneill 		goto done;
528312915a9Sjmcneill 	}
529312915a9Sjmcneill 
530312915a9Sjmcneill 	/* Match from a list of strings in a _DSD value */
531312915a9Sjmcneill 	ret = acpi_dsd_property(handle, "compatible", &buf,
532312915a9Sjmcneill 	    ACPI_TYPE_PACKAGE, &obj);
533312915a9Sjmcneill 	if (ACPI_FAILURE(ret)) {
534312915a9Sjmcneill 		goto done;
535312915a9Sjmcneill 	}
536312915a9Sjmcneill 	if (obj->Package.Count == 0) {
537312915a9Sjmcneill 		goto done;
538312915a9Sjmcneill 	}
539312915a9Sjmcneill 	for (n = 0; n < imin(obj->Package.Count, ACPI_COMPATSTR_MAX); n++) {
540312915a9Sjmcneill 		if (obj->Package.Elements[n].Type != ACPI_TYPE_STRING) {
541312915a9Sjmcneill 			goto done;
542312915a9Sjmcneill 		}
543312915a9Sjmcneill 		strings[n] = obj->Package.Elements[n].String.Pointer;
544312915a9Sjmcneill 	}
545312915a9Sjmcneill 	rv = device_compatible_pmatch(strings, n, dce);
546312915a9Sjmcneill 
547312915a9Sjmcneill done:
548312915a9Sjmcneill 	if (buf.Pointer != NULL) {
549312915a9Sjmcneill 		ACPI_FREE(buf.Pointer);
550312915a9Sjmcneill 	}
551312915a9Sjmcneill 	if (rv) {
552312915a9Sjmcneill 		rv = (rv - 1) + ACPI_MATCHSCORE_CID;
553312915a9Sjmcneill 		return imin(rv, ACPI_MATCHSCORE_CID_MAX);
554312915a9Sjmcneill 	}
555312915a9Sjmcneill 	return 0;
556312915a9Sjmcneill }
557312915a9Sjmcneill 
558537afe45Sthorpej /*
559537afe45Sthorpej  * acpi_compatible_match --
560537afe45Sthorpej  *
561537afe45Sthorpej  *	Returns a weighted match value, comparing the _HID and _CID
562a0b1e536Sandvar  *	IDs against a driver's compatibility data.
563537afe45Sthorpej  */
564537afe45Sthorpej int
acpi_compatible_match(const struct acpi_attach_args * const aa,const struct device_compatible_entry * const dce)565537afe45Sthorpej acpi_compatible_match(const struct acpi_attach_args * const aa,
566537afe45Sthorpej     const struct device_compatible_entry * const dce)
567537afe45Sthorpej {
568537afe45Sthorpej 	const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)];
569537afe45Sthorpej 	const char **cpp;
5708b25d0adSjmcneill 	bool dtlink = false;
5718b25d0adSjmcneill 	int rv;
572537afe45Sthorpej 
573537afe45Sthorpej 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
574537afe45Sthorpej 		return 0;
575537afe45Sthorpej 	}
576537afe45Sthorpej 
577537afe45Sthorpej 	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
578537afe45Sthorpej 
579537afe45Sthorpej 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
580537afe45Sthorpej 		strings[0] = ad->HardwareId.String;
581537afe45Sthorpej 
582537afe45Sthorpej 		/* Matching _HID wins big. */
583537afe45Sthorpej 		if (device_compatible_pmatch(strings, 1, dce) != 0) {
584537afe45Sthorpej 			return ACPI_MATCHSCORE_HID;
585537afe45Sthorpej 		}
5868b25d0adSjmcneill 
5878b25d0adSjmcneill 		if (device_compatible_pmatch(strings, 1,
5888b25d0adSjmcneill 					     dtlink_compat_data) != 0) {
5898b25d0adSjmcneill 			dtlink = true;
5908b25d0adSjmcneill 		}
591537afe45Sthorpej 	}
592537afe45Sthorpej 
593537afe45Sthorpej 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
594537afe45Sthorpej 		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
595537afe45Sthorpej 		    ad->CompatibleIdList.Count, strings);
596537afe45Sthorpej 
597537afe45Sthorpej 		rv = device_compatible_pmatch(cpp,
598537afe45Sthorpej 		    ad->CompatibleIdList.Count, dce);
5998b25d0adSjmcneill 		if (!dtlink &&
6008b25d0adSjmcneill 		    device_compatible_pmatch(cpp, ad->CompatibleIdList.Count,
6018b25d0adSjmcneill 					     dtlink_compat_data) != 0) {
6028b25d0adSjmcneill 			dtlink = true;
6038b25d0adSjmcneill 		}
604537afe45Sthorpej 		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
605537afe45Sthorpej 		    strings);
606537afe45Sthorpej 		if (rv) {
607537afe45Sthorpej 			rv = (rv - 1) + ACPI_MATCHSCORE_CID;
6088b25d0adSjmcneill 			return imin(rv, ACPI_MATCHSCORE_CID_MAX);
609537afe45Sthorpej 		}
6108b25d0adSjmcneill 	}
6118b25d0adSjmcneill 
6128b25d0adSjmcneill 	if (dtlink) {
613312915a9Sjmcneill 		return acpi_compatible_match_dtlink(aa, dce);
614537afe45Sthorpej 	}
615537afe45Sthorpej 
616537afe45Sthorpej 	return 0;
617537afe45Sthorpej }
618537afe45Sthorpej 
619537afe45Sthorpej /*
620537afe45Sthorpej  * acpi_compatible_lookup --
621537afe45Sthorpej  *
622537afe45Sthorpej  *	Returns the device_compatible_entry that matches the _HID
623537afe45Sthorpej  *	or _CID ID.
624537afe45Sthorpej  */
625537afe45Sthorpej const struct device_compatible_entry *
acpi_compatible_lookup(const struct acpi_attach_args * const aa,const struct device_compatible_entry * const dce)626537afe45Sthorpej acpi_compatible_lookup(const struct acpi_attach_args * const aa,
627537afe45Sthorpej     const struct device_compatible_entry * const dce)
628537afe45Sthorpej {
629537afe45Sthorpej 	const struct device_compatible_entry *rv = NULL;
630537afe45Sthorpej 	const char *strings[ACPI_COMPATSTR_MAX];
631537afe45Sthorpej 	const char **cpp;
632537afe45Sthorpej 
633537afe45Sthorpej 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
63433af1b8eSthorpej 		return NULL;
63533af1b8eSthorpej 	}
63633af1b8eSthorpej 
637537afe45Sthorpej 	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
63833af1b8eSthorpej 
63933af1b8eSthorpej 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
640537afe45Sthorpej 		strings[0] = ad->HardwareId.String;
641537afe45Sthorpej 
642537afe45Sthorpej 		rv = device_compatible_plookup(strings, 1, dce);
643537afe45Sthorpej 		if (rv != NULL)
644537afe45Sthorpej 			return rv;
64533af1b8eSthorpej 	}
64633af1b8eSthorpej 
64733af1b8eSthorpej 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
648537afe45Sthorpej 		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
649537afe45Sthorpej 		    ad->CompatibleIdList.Count, strings);
650537afe45Sthorpej 
651537afe45Sthorpej 		rv = device_compatible_plookup(cpp,
652537afe45Sthorpej 		    ad->CompatibleIdList.Count, dce);
653537afe45Sthorpej 		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
654537afe45Sthorpej 		    strings);
65533af1b8eSthorpej 	}
65633af1b8eSthorpej 
657537afe45Sthorpej 	return rv;
65833af1b8eSthorpej }
65933af1b8eSthorpej 
66033af1b8eSthorpej /*
661d6afaa44Sjruoho  * Match given IDs against _HID and _CIDs.
6620c88d0e4Sjruoho  */
6630c88d0e4Sjruoho int
acpi_match_hid(ACPI_DEVICE_INFO * ad,const char * const * ids)6640c88d0e4Sjruoho acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids)
6650c88d0e4Sjruoho {
6660c88d0e4Sjruoho 	uint32_t i, n;
6670c88d0e4Sjruoho 	char *id;
6680c88d0e4Sjruoho 
6690c88d0e4Sjruoho 	while (*ids) {
6700c88d0e4Sjruoho 
6710c88d0e4Sjruoho 		if ((ad->Valid & ACPI_VALID_HID) != 0) {
6720c88d0e4Sjruoho 
6730c88d0e4Sjruoho 			if (pmatch(ad->HardwareId.String, *ids, NULL) == 2)
6740c88d0e4Sjruoho 				return 1;
6750c88d0e4Sjruoho 		}
6760c88d0e4Sjruoho 
6770c88d0e4Sjruoho 		if ((ad->Valid & ACPI_VALID_CID) != 0) {
6780c88d0e4Sjruoho 
6790c88d0e4Sjruoho 			n = ad->CompatibleIdList.Count;
6800c88d0e4Sjruoho 
6810c88d0e4Sjruoho 			for (i = 0; i < n; i++) {
6820c88d0e4Sjruoho 
6830c88d0e4Sjruoho 				id = ad->CompatibleIdList.Ids[i].String;
6840c88d0e4Sjruoho 
6850c88d0e4Sjruoho 				if (pmatch(id, *ids, NULL) == 2)
6860c88d0e4Sjruoho 					return 1;
6870c88d0e4Sjruoho 			}
6880c88d0e4Sjruoho 		}
6890c88d0e4Sjruoho 
6900c88d0e4Sjruoho 		ids++;
6910c88d0e4Sjruoho 	}
6920c88d0e4Sjruoho 
6930c88d0e4Sjruoho 	return 0;
6940c88d0e4Sjruoho }
6950c88d0e4Sjruoho 
6964bd16782Sjruoho /*
697560c4949Sjmcneill  * Match a PCI-defined bass-class, sub-class, and programming interface
698560c4949Sjmcneill  * against a handle's _CLS object.
699560c4949Sjmcneill  */
700560c4949Sjmcneill int
acpi_match_class(ACPI_HANDLE handle,uint8_t pci_class,uint8_t pci_subclass,uint8_t pci_interface)701560c4949Sjmcneill acpi_match_class(ACPI_HANDLE handle, uint8_t pci_class, uint8_t pci_subclass,
702560c4949Sjmcneill     uint8_t pci_interface)
703560c4949Sjmcneill {
704560c4949Sjmcneill 	ACPI_BUFFER buf;
705560c4949Sjmcneill 	ACPI_OBJECT *obj;
706560c4949Sjmcneill 	ACPI_STATUS rv;
707560c4949Sjmcneill 	int match = 0;
708560c4949Sjmcneill 
709560c4949Sjmcneill 	rv = acpi_eval_struct(handle, "_CLS", &buf);
710560c4949Sjmcneill 	if (ACPI_FAILURE(rv))
711560c4949Sjmcneill 		goto done;
712560c4949Sjmcneill 
713560c4949Sjmcneill 	obj = buf.Pointer;
714560c4949Sjmcneill 	if (obj->Type != ACPI_TYPE_PACKAGE)
715560c4949Sjmcneill 		goto done;
716560c4949Sjmcneill 	if (obj->Package.Count != 3)
717560c4949Sjmcneill 		goto done;
718560c4949Sjmcneill 	if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
719560c4949Sjmcneill 	    obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER ||
720560c4949Sjmcneill 	    obj->Package.Elements[2].Type != ACPI_TYPE_INTEGER)
721560c4949Sjmcneill 		goto done;
722560c4949Sjmcneill 
723560c4949Sjmcneill 	match = obj->Package.Elements[0].Integer.Value == pci_class &&
724560c4949Sjmcneill 		obj->Package.Elements[1].Integer.Value == pci_subclass &&
725560c4949Sjmcneill 		obj->Package.Elements[2].Integer.Value == pci_interface;
726560c4949Sjmcneill 
727560c4949Sjmcneill done:
728560c4949Sjmcneill 	if (buf.Pointer)
729560c4949Sjmcneill 		ACPI_FREE(buf.Pointer);
730537afe45Sthorpej 	return match ? ACPI_MATCHSCORE_CLS : 0;
731560c4949Sjmcneill }
732560c4949Sjmcneill 
733560c4949Sjmcneill /*
7342d023696Sjruoho  * Match a device node from a handle.
7352d023696Sjruoho  */
7362d023696Sjruoho struct acpi_devnode *
acpi_match_node(ACPI_HANDLE handle)7372d023696Sjruoho acpi_match_node(ACPI_HANDLE handle)
7382d023696Sjruoho {
7392d023696Sjruoho 	struct acpi_devnode *ad;
7402d023696Sjruoho 	ACPI_STATUS rv;
7412d023696Sjruoho 
7422d023696Sjruoho 	if (handle == NULL)
7432d023696Sjruoho 		return NULL;
7442d023696Sjruoho 
7452d023696Sjruoho 	rv = AcpiGetData(handle, acpi_clean_node, (void **)&ad);
7462d023696Sjruoho 
7472d023696Sjruoho 	if (ACPI_FAILURE(rv))
7482d023696Sjruoho 		return NULL;
7492d023696Sjruoho 
7502d023696Sjruoho 	return ad;
7512d023696Sjruoho }
7522d023696Sjruoho 
7532d023696Sjruoho /*
7542d023696Sjruoho  * Permanently associate a device node with a handle.
7552d023696Sjruoho  */
7562d023696Sjruoho void
acpi_match_node_init(struct acpi_devnode * ad)7572d023696Sjruoho acpi_match_node_init(struct acpi_devnode *ad)
7582d023696Sjruoho {
7592d023696Sjruoho 	(void)AcpiAttachData(ad->ad_handle, acpi_clean_node, ad);
7602d023696Sjruoho }
7612d023696Sjruoho 
7622d023696Sjruoho static void
acpi_clean_node(ACPI_HANDLE handle,void * aux)7632d023696Sjruoho acpi_clean_node(ACPI_HANDLE handle, void *aux)
7642d023696Sjruoho {
7652d023696Sjruoho 	/* Nothing. */
7662d023696Sjruoho }
7672d023696Sjruoho 
7682d023696Sjruoho /*
7694bd16782Sjruoho  * Match a handle from a cpu_info. Returns NULL on failure.
7704bd16782Sjruoho  *
7712d023696Sjruoho  * Note that acpi_match_node() can be used if the device node
7722d023696Sjruoho  * is also required.
7734bd16782Sjruoho  */
7744bd16782Sjruoho ACPI_HANDLE
acpi_match_cpu_info(struct cpu_info * ci)7754bd16782Sjruoho acpi_match_cpu_info(struct cpu_info *ci)
7764bd16782Sjruoho {
7774bd16782Sjruoho 	struct acpi_softc *sc = acpi_softc;
7784bd16782Sjruoho 	struct acpi_devnode *ad;
7794bd16782Sjruoho 	ACPI_INTEGER val;
7804bd16782Sjruoho 	ACPI_OBJECT *obj;
7814bd16782Sjruoho 	ACPI_BUFFER buf;
7824bd16782Sjruoho 	ACPI_HANDLE hdl;
7834bd16782Sjruoho 	ACPI_STATUS rv;
7844bd16782Sjruoho 
7854bd16782Sjruoho 	if (sc == NULL || acpi_active == 0)
7864bd16782Sjruoho 		return NULL;
7874bd16782Sjruoho 
7884bd16782Sjruoho 	/*
7894bd16782Sjruoho 	 * CPUs are declared in the ACPI namespace
7904bd16782Sjruoho 	 * either as a Processor() or as a Device().
7914bd16782Sjruoho 	 * In both cases the MADT entries are used
7924bd16782Sjruoho 	 * for the match (see ACPI 4.0, section 8.4).
7934bd16782Sjruoho 	 */
794ac3c40c2Sskrll 	SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
7954bd16782Sjruoho 
7964bd16782Sjruoho 		hdl = ad->ad_handle;
7974bd16782Sjruoho 
7984bd16782Sjruoho 		switch (ad->ad_type) {
7994bd16782Sjruoho 
8004bd16782Sjruoho 		case ACPI_TYPE_DEVICE:
8014bd16782Sjruoho 
8024bd16782Sjruoho 			if (acpi_match_hid(ad->ad_devinfo, acpicpu_ids) == 0)
8034bd16782Sjruoho 				break;
8044bd16782Sjruoho 
8054bd16782Sjruoho 			rv = acpi_eval_integer(hdl, "_UID", &val);
8064bd16782Sjruoho 
8074bd16782Sjruoho 			if (ACPI_SUCCESS(rv) && val == ci->ci_acpiid)
8084bd16782Sjruoho 				return hdl;
8094bd16782Sjruoho 
8104bd16782Sjruoho 			break;
8114bd16782Sjruoho 
8124bd16782Sjruoho 		case ACPI_TYPE_PROCESSOR:
8134bd16782Sjruoho 
8144bd16782Sjruoho 			rv = acpi_eval_struct(hdl, NULL, &buf);
8154bd16782Sjruoho 
8164bd16782Sjruoho 			if (ACPI_FAILURE(rv))
8174bd16782Sjruoho 				break;
8184bd16782Sjruoho 
8194bd16782Sjruoho 			obj = buf.Pointer;
8204bd16782Sjruoho 
8214bd16782Sjruoho 			if (obj->Processor.ProcId == ci->ci_acpiid) {
8224bd16782Sjruoho 				ACPI_FREE(buf.Pointer);
8234bd16782Sjruoho 				return hdl;
8244bd16782Sjruoho 			}
8254bd16782Sjruoho 
8264bd16782Sjruoho 			ACPI_FREE(buf.Pointer);
8274bd16782Sjruoho 			break;
8284bd16782Sjruoho 		}
8294bd16782Sjruoho 	}
8304bd16782Sjruoho 
8314bd16782Sjruoho 	return NULL;
8324bd16782Sjruoho }
8334bd16782Sjruoho 
8344bd16782Sjruoho /*
8354bd16782Sjruoho  * Match a CPU from a handle. Returns NULL on failure.
8364bd16782Sjruoho  */
8374bd16782Sjruoho struct cpu_info *
acpi_match_cpu_handle(ACPI_HANDLE hdl)8384bd16782Sjruoho acpi_match_cpu_handle(ACPI_HANDLE hdl)
8394bd16782Sjruoho {
8404bd16782Sjruoho 	struct cpu_info *ci;
8414bd16782Sjruoho 	ACPI_DEVICE_INFO *di;
8424bd16782Sjruoho 	CPU_INFO_ITERATOR cii;
8434bd16782Sjruoho 	ACPI_INTEGER val;
8444bd16782Sjruoho 	ACPI_OBJECT *obj;
8454bd16782Sjruoho 	ACPI_BUFFER buf;
8464bd16782Sjruoho 	ACPI_STATUS rv;
8474bd16782Sjruoho 
8484bd16782Sjruoho 	ci = NULL;
8494bd16782Sjruoho 	di = NULL;
8504bd16782Sjruoho 	buf.Pointer = NULL;
8514bd16782Sjruoho 
8524bd16782Sjruoho 	rv = AcpiGetObjectInfo(hdl, &di);
8534bd16782Sjruoho 
8544bd16782Sjruoho 	if (ACPI_FAILURE(rv))
8554bd16782Sjruoho 		return NULL;
8564bd16782Sjruoho 
8574bd16782Sjruoho 	switch (di->Type) {
8584bd16782Sjruoho 
8594bd16782Sjruoho 	case ACPI_TYPE_DEVICE:
8604bd16782Sjruoho 
8614bd16782Sjruoho 		if (acpi_match_hid(di, acpicpu_ids) == 0)
8624bd16782Sjruoho 			goto out;
8634bd16782Sjruoho 
8644bd16782Sjruoho 		rv = acpi_eval_integer(hdl, "_UID", &val);
8654bd16782Sjruoho 
8664bd16782Sjruoho 		if (ACPI_FAILURE(rv))
8674bd16782Sjruoho 			goto out;
8684bd16782Sjruoho 
8694bd16782Sjruoho 		break;
8704bd16782Sjruoho 
8714bd16782Sjruoho 	case ACPI_TYPE_PROCESSOR:
8724bd16782Sjruoho 
8734bd16782Sjruoho 		rv = acpi_eval_struct(hdl, NULL, &buf);
8744bd16782Sjruoho 
8754bd16782Sjruoho 		if (ACPI_FAILURE(rv))
8764bd16782Sjruoho 			goto out;
8774bd16782Sjruoho 
8784bd16782Sjruoho 		obj = buf.Pointer;
8794bd16782Sjruoho 		val = obj->Processor.ProcId;
8804bd16782Sjruoho 		break;
8814bd16782Sjruoho 
8824bd16782Sjruoho 	default:
8834bd16782Sjruoho 		goto out;
8844bd16782Sjruoho 	}
8854bd16782Sjruoho 
8864bd16782Sjruoho 	for (CPU_INFO_FOREACH(cii, ci)) {
8874bd16782Sjruoho 
8884bd16782Sjruoho 		if (ci->ci_acpiid == val)
8894bd16782Sjruoho 			goto out;
8904bd16782Sjruoho 	}
8914bd16782Sjruoho 
8924bd16782Sjruoho 	ci = NULL;
8934bd16782Sjruoho 
8944bd16782Sjruoho out:
8954bd16782Sjruoho 	if (di != NULL)
8964bd16782Sjruoho 		ACPI_FREE(di);
8974bd16782Sjruoho 
8984bd16782Sjruoho 	if (buf.Pointer != NULL)
8994bd16782Sjruoho 		ACPI_FREE(buf.Pointer);
9004bd16782Sjruoho 
9014bd16782Sjruoho 	return ci;
9024bd16782Sjruoho }
90327ab5385Sbouyer 
90427ab5385Sbouyer struct acpi_irq_handler {
90527ab5385Sbouyer 	uint32_t aih_irq;
906488c5b15Sjmcneill 	void *aih_ih;
90727ab5385Sbouyer };
90827ab5385Sbouyer 
90927ab5385Sbouyer void *
acpi_intr_establish(device_t dev,uint64_t c,int ipl,bool mpsafe,int (* intr)(void *),void * iarg,const char * xname)910488c5b15Sjmcneill acpi_intr_establish(device_t dev, uint64_t c, int ipl, bool mpsafe,
911488c5b15Sjmcneill     int (*intr)(void *), void *iarg, const char *xname)
91227ab5385Sbouyer {
91327ab5385Sbouyer 	ACPI_STATUS rv;
914b4014e03Sbouyer 	ACPI_HANDLE hdl = (void *)(uintptr_t)c;
91527ab5385Sbouyer 	struct acpi_resources res;
91627ab5385Sbouyer 	struct acpi_irq *irq;
91753eb8527Sjmcneill 	void *aih = NULL;
91827ab5385Sbouyer 
91927ab5385Sbouyer 	rv = acpi_resource_parse(dev, hdl, "_CRS", &res,
92027ab5385Sbouyer 	    &acpi_resource_parse_ops_quiet);
92127ab5385Sbouyer 	if (ACPI_FAILURE(rv))
92227ab5385Sbouyer 		return NULL;
92327ab5385Sbouyer 
92427ab5385Sbouyer 	irq = acpi_res_irq(&res, 0);
92527ab5385Sbouyer 	if (irq == NULL)
92627ab5385Sbouyer 		goto end;
92727ab5385Sbouyer 
92853eb8527Sjmcneill 	aih = acpi_intr_establish_irq(dev, irq, ipl, mpsafe,
92953eb8527Sjmcneill 	    intr, iarg, xname);
930488c5b15Sjmcneill 
93127ab5385Sbouyer end:
93227ab5385Sbouyer 	acpi_resource_cleanup(&res);
93353eb8527Sjmcneill 
93453eb8527Sjmcneill 	return aih;
93553eb8527Sjmcneill }
93653eb8527Sjmcneill 
93753eb8527Sjmcneill void *
acpi_intr_establish_irq(device_t dev,struct acpi_irq * irq,int ipl,bool mpsafe,int (* intr)(void *),void * iarg,const char * xname)93853eb8527Sjmcneill acpi_intr_establish_irq(device_t dev, struct acpi_irq *irq, int ipl,
93953eb8527Sjmcneill     bool mpsafe, int (*intr)(void *), void *iarg, const char *xname)
94053eb8527Sjmcneill {
94153eb8527Sjmcneill 	struct acpi_irq_handler *aih;
94253eb8527Sjmcneill 	void *ih;
94353eb8527Sjmcneill 
94453eb8527Sjmcneill 	const int type = (irq->ar_type == ACPI_EDGE_SENSITIVE) ? IST_EDGE : IST_LEVEL;
94553eb8527Sjmcneill 	ih = acpi_md_intr_establish(irq->ar_irq, ipl, type, intr, iarg, mpsafe, xname);
94653eb8527Sjmcneill 	if (ih == NULL)
94753eb8527Sjmcneill 		return NULL;
94853eb8527Sjmcneill 
94953eb8527Sjmcneill 	aih = kmem_alloc(sizeof(struct acpi_irq_handler), KM_SLEEP);
95053eb8527Sjmcneill 	aih->aih_irq = irq->ar_irq;
95153eb8527Sjmcneill 	aih->aih_ih = ih;
95253eb8527Sjmcneill 
95327ab5385Sbouyer 	return aih;
95427ab5385Sbouyer }
95527ab5385Sbouyer 
95627ab5385Sbouyer void
acpi_intr_mask(void * c)95797faf389Sthorpej acpi_intr_mask(void *c)
95897faf389Sthorpej {
95997faf389Sthorpej 	struct acpi_irq_handler * const aih = c;
96097faf389Sthorpej 
96197faf389Sthorpej 	acpi_md_intr_mask(aih->aih_ih);
96297faf389Sthorpej }
96397faf389Sthorpej 
96497faf389Sthorpej void
acpi_intr_unmask(void * c)96597faf389Sthorpej acpi_intr_unmask(void *c)
96697faf389Sthorpej {
96797faf389Sthorpej 	struct acpi_irq_handler * const aih = c;
96897faf389Sthorpej 
96997faf389Sthorpej 	acpi_md_intr_unmask(aih->aih_ih);
97097faf389Sthorpej }
97197faf389Sthorpej 
97297faf389Sthorpej void
acpi_intr_disestablish(void * c)973488c5b15Sjmcneill acpi_intr_disestablish(void *c)
97427ab5385Sbouyer {
97527ab5385Sbouyer 	struct acpi_irq_handler *aih = c;
97627ab5385Sbouyer 
977488c5b15Sjmcneill 	acpi_md_intr_disestablish(aih->aih_ih);
97827ab5385Sbouyer 	kmem_free(aih, sizeof(struct acpi_irq_handler));
97927ab5385Sbouyer }
98027ab5385Sbouyer 
98127ab5385Sbouyer const char *
acpi_intr_string(void * c,char * buf,size_t size)98227ab5385Sbouyer acpi_intr_string(void *c, char *buf, size_t size)
98327ab5385Sbouyer {
98427ab5385Sbouyer 	struct acpi_irq_handler *aih = c;
98527ab5385Sbouyer 	intr_handle_t ih = aih->aih_irq;
98627ab5385Sbouyer 
98727ab5385Sbouyer 	return intr_string(ih, buf, size);
98827ab5385Sbouyer }
989ee3102aaSjmcneill 
990ee3102aaSjmcneill /*
99133af1b8eSthorpej  * Device-Specific Data (_DSD) support
992ee3102aaSjmcneill  */
993ee3102aaSjmcneill 
994ee3102aaSjmcneill static UINT8 acpi_dsd_uuid[ACPI_UUID_LENGTH] = {
995ee3102aaSjmcneill 	0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
996ee3102aaSjmcneill 	0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
997ee3102aaSjmcneill };
998ee3102aaSjmcneill 
99901fc4962Sjmcneill static ACPI_STATUS
acpi_dsd_property(ACPI_HANDLE handle,const char * prop,ACPI_BUFFER * pbuf,ACPI_OBJECT_TYPE type,ACPI_OBJECT ** ret)100001fc4962Sjmcneill acpi_dsd_property(ACPI_HANDLE handle, const char *prop, ACPI_BUFFER *pbuf, ACPI_OBJECT_TYPE type, ACPI_OBJECT **ret)
1001ee3102aaSjmcneill {
1002ee3102aaSjmcneill 	ACPI_OBJECT *obj, *uuid, *props, *pobj, *propkey, *propval;
1003ee3102aaSjmcneill 	ACPI_STATUS rv;
1004ee3102aaSjmcneill 	int n;
1005ee3102aaSjmcneill 
100601fc4962Sjmcneill 	rv = AcpiEvaluateObjectTyped(handle, "_DSD", NULL, pbuf, ACPI_TYPE_PACKAGE);
1007ee3102aaSjmcneill 	if (ACPI_FAILURE(rv))
1008ee3102aaSjmcneill 		return rv;
1009ee3102aaSjmcneill 
1010ee3102aaSjmcneill 	props = NULL;
101101fc4962Sjmcneill 	obj = (ACPI_OBJECT *)pbuf->Pointer;
1012ee3102aaSjmcneill 	for (n = 0; (n + 1) < obj->Package.Count; n += 2) {
1013ee3102aaSjmcneill 		uuid = &obj->Package.Elements[n];
1014ee3102aaSjmcneill 		if (uuid->Buffer.Length == ACPI_UUID_LENGTH &&
1015ee3102aaSjmcneill 		    memcmp(uuid->Buffer.Pointer, acpi_dsd_uuid, ACPI_UUID_LENGTH) == 0) {
1016ee3102aaSjmcneill 			props = &obj->Package.Elements[n + 1];
1017ee3102aaSjmcneill 			break;
1018ee3102aaSjmcneill 		}
1019ee3102aaSjmcneill 	}
102001fc4962Sjmcneill 	if (props == NULL)
102101fc4962Sjmcneill 		return AE_NOT_FOUND;
1022ee3102aaSjmcneill 
1023ee3102aaSjmcneill 	for (n = 0; n < props->Package.Count; n++) {
1024ee3102aaSjmcneill 		pobj = &props->Package.Elements[n];
1025ee3102aaSjmcneill 		if (pobj->Type != ACPI_TYPE_PACKAGE || pobj->Package.Count != 2)
1026ee3102aaSjmcneill 			continue;
1027ee3102aaSjmcneill 		propkey = (ACPI_OBJECT *)&pobj->Package.Elements[0];
1028ee3102aaSjmcneill 		propval = (ACPI_OBJECT *)&pobj->Package.Elements[1];
1029ee3102aaSjmcneill 		if (propkey->Type != ACPI_TYPE_STRING)
1030ee3102aaSjmcneill 			continue;
1031ee3102aaSjmcneill 		if (strcmp(propkey->String.Pointer, prop) != 0)
1032ee3102aaSjmcneill 			continue;
1033ee3102aaSjmcneill 
103401fc4962Sjmcneill 		if (propval->Type != type) {
103501fc4962Sjmcneill 			return AE_TYPE;
1036ee3102aaSjmcneill 		} else {
103701fc4962Sjmcneill 			*ret = propval;
103801fc4962Sjmcneill 			return AE_OK;
1039ee3102aaSjmcneill 		}
1040ee3102aaSjmcneill 		break;
1041ee3102aaSjmcneill 	}
1042ee3102aaSjmcneill 
104301fc4962Sjmcneill 	return AE_NOT_FOUND;
104401fc4962Sjmcneill }
104501fc4962Sjmcneill 
104601fc4962Sjmcneill ACPI_STATUS
acpi_dsd_integer(ACPI_HANDLE handle,const char * prop,ACPI_INTEGER * val)104701fc4962Sjmcneill acpi_dsd_integer(ACPI_HANDLE handle, const char *prop, ACPI_INTEGER *val)
104801fc4962Sjmcneill {
104901fc4962Sjmcneill 	ACPI_OBJECT *propval;
105001fc4962Sjmcneill 	ACPI_STATUS rv;
105101fc4962Sjmcneill 	ACPI_BUFFER buf;
105201fc4962Sjmcneill 
105301fc4962Sjmcneill 	buf.Pointer = NULL;
105401fc4962Sjmcneill 	buf.Length = ACPI_ALLOCATE_BUFFER;
105501fc4962Sjmcneill 
105601fc4962Sjmcneill 	rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_INTEGER, &propval);
105701fc4962Sjmcneill 	if (ACPI_SUCCESS(rv))
105801fc4962Sjmcneill 		*val = propval->Integer.Value;
105901fc4962Sjmcneill 
10601fd42d68Smlelstv 	if (buf.Pointer != NULL)
106101fc4962Sjmcneill 		ACPI_FREE(buf.Pointer);
106201fc4962Sjmcneill 	return rv;
106301fc4962Sjmcneill }
106401fc4962Sjmcneill 
106501fc4962Sjmcneill ACPI_STATUS
acpi_dsd_string(ACPI_HANDLE handle,const char * prop,char ** val)106601fc4962Sjmcneill acpi_dsd_string(ACPI_HANDLE handle, const char *prop, char **val)
106701fc4962Sjmcneill {
106801fc4962Sjmcneill 	ACPI_OBJECT *propval;
106901fc4962Sjmcneill 	ACPI_STATUS rv;
107001fc4962Sjmcneill 	ACPI_BUFFER buf;
107101fc4962Sjmcneill 
107201fc4962Sjmcneill 	buf.Pointer = NULL;
107301fc4962Sjmcneill 	buf.Length = ACPI_ALLOCATE_BUFFER;
107401fc4962Sjmcneill 
107501fc4962Sjmcneill 	rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_STRING, &propval);
107601fc4962Sjmcneill 	if (ACPI_SUCCESS(rv))
107701fc4962Sjmcneill 		*val = kmem_strdup(propval->String.Pointer, KM_SLEEP);
107801fc4962Sjmcneill 
10791fd42d68Smlelstv 	if (buf.Pointer != NULL)
1080ee3102aaSjmcneill 		ACPI_FREE(buf.Pointer);
1081ee3102aaSjmcneill 	return rv;
1082ee3102aaSjmcneill }
108333af1b8eSthorpej 
10848430034eSjmcneill ACPI_STATUS
acpi_dsd_bool(ACPI_HANDLE handle,const char * prop,bool * val)10858430034eSjmcneill acpi_dsd_bool(ACPI_HANDLE handle, const char *prop, bool *val)
10868430034eSjmcneill {
10878430034eSjmcneill 	ACPI_STATUS rv;
10888430034eSjmcneill 	ACPI_INTEGER ival;
10898430034eSjmcneill 
10908430034eSjmcneill 	rv = acpi_dsd_integer(handle, prop, &ival);
10918430034eSjmcneill 	if (ACPI_SUCCESS(rv)) {
10928430034eSjmcneill 		*val = ival != 0;
10938430034eSjmcneill 	}
10948430034eSjmcneill 
10958430034eSjmcneill 	return rv;
10968430034eSjmcneill }
1097312915a9Sjmcneill 
1098312915a9Sjmcneill 
109933af1b8eSthorpej /*
110033af1b8eSthorpej  * Device Specific Method (_DSM) support
110133af1b8eSthorpej  */
110233af1b8eSthorpej 
110333af1b8eSthorpej ACPI_STATUS
acpi_dsm_typed(ACPI_HANDLE handle,uint8_t * uuid,ACPI_INTEGER rev,ACPI_INTEGER func,const ACPI_OBJECT * arg3,ACPI_OBJECT_TYPE return_type,ACPI_OBJECT ** return_obj)110433af1b8eSthorpej acpi_dsm_typed(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
110533af1b8eSthorpej     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT_TYPE return_type,
110633af1b8eSthorpej     ACPI_OBJECT **return_obj)
110733af1b8eSthorpej {
110833af1b8eSthorpej 	ACPI_OBJECT_LIST arg;
110933af1b8eSthorpej 	ACPI_OBJECT obj[4];
111033af1b8eSthorpej 	ACPI_BUFFER buf;
111133af1b8eSthorpej 	ACPI_STATUS status;
111233af1b8eSthorpej 
111333af1b8eSthorpej 	arg.Count = 4;
111433af1b8eSthorpej 	arg.Pointer = obj;
111533af1b8eSthorpej 
111633af1b8eSthorpej 	obj[0].Type = ACPI_TYPE_BUFFER;
111733af1b8eSthorpej 	obj[0].Buffer.Length = ACPI_UUID_LENGTH;
111833af1b8eSthorpej 	obj[0].Buffer.Pointer = uuid;
111933af1b8eSthorpej 
112033af1b8eSthorpej 	obj[1].Type = ACPI_TYPE_INTEGER;
112133af1b8eSthorpej 	obj[1].Integer.Value = rev;
112233af1b8eSthorpej 
112333af1b8eSthorpej 	obj[2].Type = ACPI_TYPE_INTEGER;
112433af1b8eSthorpej 	obj[2].Integer.Value = func;
112533af1b8eSthorpej 
112633af1b8eSthorpej 	if (arg3 != NULL) {
112733af1b8eSthorpej 		obj[3] = *arg3;
112833af1b8eSthorpej 	} else {
112933af1b8eSthorpej 		obj[3].Type = ACPI_TYPE_PACKAGE;
113033af1b8eSthorpej 		obj[3].Package.Count = 0;
113133af1b8eSthorpej 		obj[3].Package.Elements = NULL;
113233af1b8eSthorpej 	}
113333af1b8eSthorpej 
113433af1b8eSthorpej 	buf.Pointer = NULL;
113533af1b8eSthorpej 	buf.Length = ACPI_ALLOCATE_BUFFER;
113633af1b8eSthorpej 
113733af1b8eSthorpej 	if (return_obj == NULL && return_type == ACPI_TYPE_ANY) {
113833af1b8eSthorpej 		status = AcpiEvaluateObject(handle, "_DSM", &arg, NULL);
113933af1b8eSthorpej 	} else {
114033af1b8eSthorpej 		*return_obj = NULL;
114133af1b8eSthorpej 		status = AcpiEvaluateObjectTyped(handle, "_DSM", &arg, &buf,
114233af1b8eSthorpej 		    return_type);
114333af1b8eSthorpej 	}
114433af1b8eSthorpej 	if (ACPI_FAILURE(status)) {
114533af1b8eSthorpej 		return status;
114633af1b8eSthorpej 	}
114733af1b8eSthorpej 	if (return_obj != NULL) {
114833af1b8eSthorpej 		*return_obj = buf.Pointer;
114933af1b8eSthorpej 	} else if (buf.Pointer != NULL) {
115033af1b8eSthorpej 		ACPI_FREE(buf.Pointer);
115133af1b8eSthorpej 	}
115233af1b8eSthorpej 	return AE_OK;
115333af1b8eSthorpej }
115433af1b8eSthorpej 
115533af1b8eSthorpej ACPI_STATUS
acpi_dsm_integer(ACPI_HANDLE handle,uint8_t * uuid,ACPI_INTEGER rev,ACPI_INTEGER func,const ACPI_OBJECT * arg3,ACPI_INTEGER * ret)115633af1b8eSthorpej acpi_dsm_integer(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
115733af1b8eSthorpej     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_INTEGER *ret)
115833af1b8eSthorpej {
115933af1b8eSthorpej 	ACPI_OBJECT *obj;
116033af1b8eSthorpej 	ACPI_STATUS status;
116133af1b8eSthorpej 
116233af1b8eSthorpej 	status = acpi_dsm_typed(handle, uuid, rev, func, arg3,
116333af1b8eSthorpej 	    ACPI_TYPE_INTEGER, &obj);
116433af1b8eSthorpej 	if (ACPI_FAILURE(status)) {
116533af1b8eSthorpej 		return status;
116633af1b8eSthorpej 	}
116733af1b8eSthorpej 
116833af1b8eSthorpej 	*ret = obj->Integer.Value;
116933af1b8eSthorpej 	ACPI_FREE(obj);
117033af1b8eSthorpej 
117133af1b8eSthorpej 	return AE_OK;
117233af1b8eSthorpej }
117333af1b8eSthorpej 
117433af1b8eSthorpej ACPI_STATUS
acpi_dsm(ACPI_HANDLE handle,uint8_t * uuid,ACPI_INTEGER rev,ACPI_INTEGER func,const ACPI_OBJECT * arg3,ACPI_OBJECT ** return_obj)117533af1b8eSthorpej acpi_dsm(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
117633af1b8eSthorpej     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT **return_obj)
117733af1b8eSthorpej {
117833af1b8eSthorpej 	return acpi_dsm_typed(handle, uuid, rev, func, arg3, ACPI_TYPE_ANY,
117933af1b8eSthorpej 	    return_obj);
118033af1b8eSthorpej }
11812ae5b509Sjmcneill 
11822ae5b509Sjmcneill ACPI_STATUS
acpi_dsm_query(ACPI_HANDLE handle,uint8_t * uuid,ACPI_INTEGER rev,ACPI_INTEGER * ret)1183ae008ef2Sjmcneill acpi_dsm_query(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
1184ae008ef2Sjmcneill     ACPI_INTEGER *ret)
1185ae008ef2Sjmcneill {
1186ae008ef2Sjmcneill 	ACPI_OBJECT *obj;
1187ae008ef2Sjmcneill 	ACPI_STATUS status;
1188ae008ef2Sjmcneill 	uint8_t *data;
1189ae008ef2Sjmcneill 	u_int n;
1190ae008ef2Sjmcneill 
1191ae008ef2Sjmcneill 	status = acpi_dsm(handle, uuid, rev, 0, NULL, &obj);
1192ae008ef2Sjmcneill 	if (ACPI_FAILURE(status)) {
1193ae008ef2Sjmcneill 		return status;
1194ae008ef2Sjmcneill 	}
1195ae008ef2Sjmcneill 
1196ae008ef2Sjmcneill 	if (obj->Type == ACPI_TYPE_INTEGER) {
1197ae008ef2Sjmcneill 		*ret = obj->Integer.Value;
1198ae008ef2Sjmcneill 	} else if (obj->Type == ACPI_TYPE_BUFFER &&
1199ae008ef2Sjmcneill 		   obj->Buffer.Length <= 8) {
1200ae008ef2Sjmcneill 		*ret = 0;
1201ae008ef2Sjmcneill 		data = (uint8_t *)obj->Buffer.Pointer;
1202ae008ef2Sjmcneill 		for (n = 0; n < obj->Buffer.Length; n++) {
1203ae008ef2Sjmcneill 			*ret |= (uint64_t)data[n] << (n * 8);
1204ae008ef2Sjmcneill 		}
1205ae008ef2Sjmcneill 	} else {
1206ae008ef2Sjmcneill 		status = AE_TYPE;
1207ae008ef2Sjmcneill 	}
1208ae008ef2Sjmcneill 
1209ae008ef2Sjmcneill 	ACPI_FREE(obj);
1210ae008ef2Sjmcneill 
1211ae008ef2Sjmcneill 	return status;
1212ae008ef2Sjmcneill }
1213ae008ef2Sjmcneill 
1214ae008ef2Sjmcneill ACPI_STATUS
acpi_claim_childdevs(device_t dev,struct acpi_devnode * devnode)12152ae5b509Sjmcneill acpi_claim_childdevs(device_t dev, struct acpi_devnode *devnode)
12162ae5b509Sjmcneill {
12172ae5b509Sjmcneill 	struct acpi_devnode *ad;
12182ae5b509Sjmcneill 
12192ae5b509Sjmcneill 	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
12202ae5b509Sjmcneill 		if (ad->ad_device != NULL)
12212ae5b509Sjmcneill 			continue;
12226a1f27f6Sjmcneill 		aprint_debug_dev(dev, "claiming %s\n",
12236a1f27f6Sjmcneill 		    acpi_name(ad->ad_handle));
12242ae5b509Sjmcneill 		ad->ad_device = dev;
12252ae5b509Sjmcneill 		acpi_claim_childdevs(dev, ad);
12262ae5b509Sjmcneill 	}
12272ae5b509Sjmcneill 
12282ae5b509Sjmcneill 	return AE_OK;
12292ae5b509Sjmcneill }
1230