xref: /netbsd-src/sys/dev/acpi/acpi_util.c (revision 84b6468db257bd512ee8a1ad7a66d1ff757f2049)
1*84b6468dSjmcneill /*	$NetBSD: acpi_util.c,v 1.35 2025/01/11 11:40:43 jmcneill Exp $ */
20c88d0e4Sjruoho 
30c88d0e4Sjruoho /*-
46451a97aSthorpej  * 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*84b6468dSjmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_util.c,v 1.35 2025/01/11 11:40:43 jmcneill Exp $");
690c88d0e4Sjruoho 
700c88d0e4Sjruoho #include <sys/param.h>
71db8cbfd3Sbouyer #include <sys/kmem.h>
7253c2e439Sjmcneill #include <sys/cpu.h>
730c88d0e4Sjruoho 
740c88d0e4Sjruoho #include <dev/acpi/acpireg.h>
750c88d0e4Sjruoho #include <dev/acpi/acpivar.h>
76db8cbfd3Sbouyer #include <dev/acpi/acpi_intr.h>
770c88d0e4Sjruoho 
784ecce2b2Sthorpej #include <sys/device_calls.h>
794ecce2b2Sthorpej 
80f62244a8Sjmcneill #include <machine/acpi_machdep.h>
81f62244a8Sjmcneill 
820c88d0e4Sjruoho #define _COMPONENT	ACPI_BUS_COMPONENT
830c88d0e4Sjruoho ACPI_MODULE_NAME	("acpi_util")
840c88d0e4Sjruoho 
855e449c62Sjruoho static void		acpi_clean_node(ACPI_HANDLE, void *);
863da31819Sjmcneill static ACPI_STATUS	acpi_dsd_property(ACPI_HANDLE, const char *,
873da31819Sjmcneill 			    ACPI_BUFFER *, ACPI_OBJECT_TYPE, ACPI_OBJECT **);
885e449c62Sjruoho 
890f056e49Sjruoho static const char * const acpicpu_ids[] = {
900f056e49Sjruoho 	"ACPI0007",
910f056e49Sjruoho 	NULL
920f056e49Sjruoho };
930f056e49Sjruoho 
941ff08d8eSjmcneill static const struct device_compatible_entry dtlink_compat_data[] = {
951ff08d8eSjmcneill 	{ .compat = "PRP0001" },
961ff08d8eSjmcneill 	DEVICE_COMPAT_EOL
971ff08d8eSjmcneill };
981ff08d8eSjmcneill 
990c88d0e4Sjruoho /*
100cae7202cSthorpej  * ACPI device handle support.
101cae7202cSthorpej  */
102cae7202cSthorpej 
103cae7202cSthorpej static device_call_t
104cae7202cSthorpej acpi_devhandle_lookup_device_call(devhandle_t handle, const char *name,
105cae7202cSthorpej     devhandle_t *call_handlep)
106cae7202cSthorpej {
107cae7202cSthorpej 	__link_set_decl(acpi_device_calls, struct device_call_descriptor);
108cae7202cSthorpej 	struct device_call_descriptor * const *desc;
109cae7202cSthorpej 
110cae7202cSthorpej 	__link_set_foreach(desc, acpi_device_calls) {
111cae7202cSthorpej 		if (strcmp((*desc)->name, name) == 0) {
112cae7202cSthorpej 			return (*desc)->call;
113cae7202cSthorpej 		}
114cae7202cSthorpej 	}
115cae7202cSthorpej 	return NULL;
116cae7202cSthorpej }
117cae7202cSthorpej 
118cae7202cSthorpej static const struct devhandle_impl acpi_devhandle_impl = {
119cae7202cSthorpej 	.type = DEVHANDLE_TYPE_ACPI,
120cae7202cSthorpej 	.lookup_device_call = acpi_devhandle_lookup_device_call,
121cae7202cSthorpej };
122cae7202cSthorpej 
123cae7202cSthorpej devhandle_t
1243944ff70Sthorpej devhandle_from_acpi(devhandle_t super_handle, ACPI_HANDLE const hdl)
125cae7202cSthorpej {
1263944ff70Sthorpej 	devhandle_type_t super_type = devhandle_type(super_handle);
1273944ff70Sthorpej 	devhandle_t handle = { 0 };
1283944ff70Sthorpej 
1293944ff70Sthorpej 	if (super_type == DEVHANDLE_TYPE_ACPI) {
1303944ff70Sthorpej 		handle.impl = super_handle.impl;
1313944ff70Sthorpej 	} else {
1323944ff70Sthorpej 		KASSERT(super_type == DEVHANDLE_TYPE_INVALID);
1333944ff70Sthorpej 		handle.impl = &acpi_devhandle_impl;
1343944ff70Sthorpej 	}
1353944ff70Sthorpej 	handle.pointer = hdl;
136cae7202cSthorpej 
137cae7202cSthorpej 	return handle;
138cae7202cSthorpej }
139cae7202cSthorpej 
140cae7202cSthorpej ACPI_HANDLE
141cae7202cSthorpej devhandle_to_acpi(devhandle_t const handle)
142cae7202cSthorpej {
143cae7202cSthorpej 	KASSERT(devhandle_type(handle) == DEVHANDLE_TYPE_ACPI);
144cae7202cSthorpej 
145cae7202cSthorpej 	return handle.pointer;
146cae7202cSthorpej }
147cae7202cSthorpej 
148cae7202cSthorpej static int
149cae7202cSthorpej acpi_device_enumerate_children(device_t dev, devhandle_t call_handle, void *v)
150cae7202cSthorpej {
151cae7202cSthorpej 	struct device_enumerate_children_args *args = v;
152cae7202cSthorpej 	ACPI_HANDLE hdl = devhandle_to_acpi(call_handle);
153cae7202cSthorpej 	struct acpi_devnode *devnode, *ad;
154cae7202cSthorpej 
155cae7202cSthorpej 	devnode = acpi_match_node(hdl);
156cae7202cSthorpej 	KASSERT(devnode != NULL);
157cae7202cSthorpej 
158cae7202cSthorpej 	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
159cae7202cSthorpej 		if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE ||
160cae7202cSthorpej 		    !acpi_device_present(ad->ad_handle)) {
161cae7202cSthorpej 			continue;
162cae7202cSthorpej 		}
1633944ff70Sthorpej 		if (!args->callback(dev, devhandle_from_acpi(call_handle,
1643944ff70Sthorpej 							     ad->ad_handle),
165cae7202cSthorpej 				    args->callback_arg)) {
166cae7202cSthorpej 			break;
167cae7202cSthorpej 		}
168cae7202cSthorpej 	}
169cae7202cSthorpej 
170cae7202cSthorpej 	return 0;
171cae7202cSthorpej }
1724ecce2b2Sthorpej ACPI_DEVICE_CALL_REGISTER(DEVICE_ENUMERATE_CHILDREN_STR,
173cae7202cSthorpej 			  acpi_device_enumerate_children)
174cae7202cSthorpej 
175cae7202cSthorpej /*
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
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
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
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
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
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
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 *
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 /*
394660a9ad6Sthorpej  * Pack _HID and _CID ID strings into an OpenFirmware-style
3956451a97aSthorpej  * string list.
3966451a97aSthorpej  */
3976451a97aSthorpej char *
398568ac2aaSthorpej acpi_pack_compat_list(struct acpi_devnode *ad, size_t *sizep)
3996451a97aSthorpej {
400568ac2aaSthorpej 	ACPI_DEVICE_INFO *devinfo = ad->ad_devinfo;
401568ac2aaSthorpej 
4026451a97aSthorpej 	KASSERT(sizep != NULL);
4036451a97aSthorpej 
404660a9ad6Sthorpej 	char *sl = NULL;
405660a9ad6Sthorpej 	size_t slsize = 0;
4066451a97aSthorpej 	uint32_t i;
407568ac2aaSthorpej 	bool dtlink = false;
4086451a97aSthorpej 
409568ac2aaSthorpej 	ACPI_BUFFER buf;
410568ac2aaSthorpej 	ACPI_STATUS ret;
411568ac2aaSthorpej 	ACPI_OBJECT *obj;
412568ac2aaSthorpej 	char *compatible;
413568ac2aaSthorpej 	int n;
414568ac2aaSthorpej 
415568ac2aaSthorpej 	buf.Pointer = NULL;
416568ac2aaSthorpej 	buf.Length = ACPI_ALLOCATE_BUFFER;
417568ac2aaSthorpej 
418568ac2aaSthorpej 	if ((devinfo->Valid & ACPI_VALID_HID) != 0) {
419568ac2aaSthorpej 		const char *cp = devinfo->HardwareId.String;
420568ac2aaSthorpej 
421568ac2aaSthorpej 		if (device_compatible_pmatch_strlist(cp, strlen(cp) + 1,
422568ac2aaSthorpej 						     dtlink_compat_data)) {
423568ac2aaSthorpej 			dtlink = true;
424568ac2aaSthorpej 		} else {
425568ac2aaSthorpej 			strlist_append(&sl, &slsize, cp);
426568ac2aaSthorpej 		}
4276451a97aSthorpej 	}
4286451a97aSthorpej 
429568ac2aaSthorpej 	if ((devinfo->Valid & ACPI_VALID_CID) != 0) {
430568ac2aaSthorpej 		for (i = 0; i < devinfo->CompatibleIdList.Count; i++) {
431568ac2aaSthorpej 			const char *cp =
432568ac2aaSthorpej 			    devinfo->CompatibleIdList.Ids[i].String;
433568ac2aaSthorpej 
434568ac2aaSthorpej 			if (device_compatible_pmatch_strlist(cp, strlen(cp) + 1,
435568ac2aaSthorpej 							dtlink_compat_data)) {
436568ac2aaSthorpej 				dtlink = true;
437568ac2aaSthorpej 			} else {
438568ac2aaSthorpej 				strlist_append(&sl, &slsize, cp);
439568ac2aaSthorpej 			}
440568ac2aaSthorpej 		}
441568ac2aaSthorpej 	}
442568ac2aaSthorpej 
443568ac2aaSthorpej 	if (dtlink) {
444568ac2aaSthorpej 		ret = acpi_dsd_string(ad->ad_handle, "compatible",
445568ac2aaSthorpej 		    &compatible);
446568ac2aaSthorpej 		if (ACPI_SUCCESS(ret)) {
447568ac2aaSthorpej 			strlist_append(&sl, &slsize, compatible);
448568ac2aaSthorpej 			kmem_strfree(compatible);
449568ac2aaSthorpej 			goto done;
450568ac2aaSthorpej 		}
451568ac2aaSthorpej 
452568ac2aaSthorpej 		ret = acpi_dsd_property(ad->ad_handle, "compatible", &buf,
453568ac2aaSthorpej 		    ACPI_TYPE_PACKAGE, &obj);
454568ac2aaSthorpej 		if (ACPI_FAILURE(ret)) {
455568ac2aaSthorpej 			goto done;
456568ac2aaSthorpej 		}
457568ac2aaSthorpej 		if (obj->Package.Count == 0) {
458568ac2aaSthorpej 			goto done;
459568ac2aaSthorpej 		}
460568ac2aaSthorpej 		for (n = 0; n < obj->Package.Count; n++) {
461568ac2aaSthorpej 			if (obj->Package.Elements[n].Type != ACPI_TYPE_STRING) {
462568ac2aaSthorpej 				continue;
463568ac2aaSthorpej 			}
464660a9ad6Sthorpej 			strlist_append(&sl, &slsize,
465568ac2aaSthorpej 			    obj->Package.Elements[n].String.Pointer);
4666451a97aSthorpej 		}
4676451a97aSthorpej 	}
4686451a97aSthorpej 
469568ac2aaSthorpej  done:
470568ac2aaSthorpej 	if (buf.Pointer != NULL) {
471568ac2aaSthorpej 		ACPI_FREE(buf.Pointer);
472568ac2aaSthorpej 	}
473660a9ad6Sthorpej 	*sizep = slsize;
474660a9ad6Sthorpej 	return sl;
475660a9ad6Sthorpej }
476660a9ad6Sthorpej 
477660a9ad6Sthorpej /*
478660a9ad6Sthorpej  * The ACPI_PNP_DEVICE_ID type is somewhat inconvenient for us to
479660a9ad6Sthorpej  * use.  We'll need some temporary space to pack it into an array
480660a9ad6Sthorpej  * of C strings.  Room for 8 should be plenty, but we can allocate
481660a9ad6Sthorpej  * more if necessary.
482660a9ad6Sthorpej  */
483660a9ad6Sthorpej #define	ACPI_COMPATSTR_MAX	8
484660a9ad6Sthorpej 
485660a9ad6Sthorpej static const char **
486660a9ad6Sthorpej acpi_compatible_alloc_strarray(ACPI_PNP_DEVICE_ID *ids,
487660a9ad6Sthorpej     unsigned int count, const char **buf)
488660a9ad6Sthorpej {
489660a9ad6Sthorpej 	unsigned int i;
490660a9ad6Sthorpej 
491660a9ad6Sthorpej 	buf = kmem_tmpbuf_alloc(count * sizeof(const char *),
492660a9ad6Sthorpej 	    buf, ACPI_COMPATSTR_MAX * sizeof(const char *), KM_SLEEP);
493660a9ad6Sthorpej 	for (i = 0; i < count; i++) {
494660a9ad6Sthorpej 		buf[i] = ids[i].String;
495660a9ad6Sthorpej 	}
496660a9ad6Sthorpej 	return buf;
497660a9ad6Sthorpej }
498660a9ad6Sthorpej 
499660a9ad6Sthorpej static void
500660a9ad6Sthorpej acpi_compatible_free_strarray(const char **cpp, unsigned int count,
501660a9ad6Sthorpej     const char **buf)
502660a9ad6Sthorpej {
503660a9ad6Sthorpej 	kmem_tmpbuf_free(cpp, count * sizeof(const char *), buf);
504660a9ad6Sthorpej }
505660a9ad6Sthorpej 
5063da31819Sjmcneill static int
5073da31819Sjmcneill acpi_compatible_match_dtlink(const struct acpi_attach_args * const aa,
5083da31819Sjmcneill     const struct device_compatible_entry * const dce)
5093da31819Sjmcneill {
5103da31819Sjmcneill 	const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)];
5113da31819Sjmcneill 	ACPI_HANDLE handle = aa->aa_node->ad_handle;
5123da31819Sjmcneill 	ACPI_BUFFER buf;
5133da31819Sjmcneill 	char *compatible;
5143da31819Sjmcneill 	ACPI_STATUS ret;
5153da31819Sjmcneill 	ACPI_OBJECT *obj;
5163da31819Sjmcneill 	int rv = 0, n;
5173da31819Sjmcneill 
5183da31819Sjmcneill 	buf.Pointer = NULL;
5193da31819Sjmcneill 	buf.Length = ACPI_ALLOCATE_BUFFER;
5203da31819Sjmcneill 
5213da31819Sjmcneill 	/* Match a single string _DSD value */
5223da31819Sjmcneill 	ret = acpi_dsd_string(handle, "compatible", &compatible);
5233da31819Sjmcneill 	if (ACPI_SUCCESS(ret)) {
5243da31819Sjmcneill 		strings[0] = compatible;
5253da31819Sjmcneill 		rv = device_compatible_pmatch(strings, 1, dce);
5263da31819Sjmcneill 		kmem_strfree(compatible);
5273da31819Sjmcneill 		goto done;
5283da31819Sjmcneill 	}
5293da31819Sjmcneill 
5303da31819Sjmcneill 	/* Match from a list of strings in a _DSD value */
5313da31819Sjmcneill 	ret = acpi_dsd_property(handle, "compatible", &buf,
5323da31819Sjmcneill 	    ACPI_TYPE_PACKAGE, &obj);
5333da31819Sjmcneill 	if (ACPI_FAILURE(ret)) {
5343da31819Sjmcneill 		goto done;
5353da31819Sjmcneill 	}
5363da31819Sjmcneill 	if (obj->Package.Count == 0) {
5373da31819Sjmcneill 		goto done;
5383da31819Sjmcneill 	}
5393da31819Sjmcneill 	for (n = 0; n < imin(obj->Package.Count, ACPI_COMPATSTR_MAX); n++) {
5403da31819Sjmcneill 		if (obj->Package.Elements[n].Type != ACPI_TYPE_STRING) {
5413da31819Sjmcneill 			goto done;
5423da31819Sjmcneill 		}
5433da31819Sjmcneill 		strings[n] = obj->Package.Elements[n].String.Pointer;
5443da31819Sjmcneill 	}
5453da31819Sjmcneill 	rv = device_compatible_pmatch(strings, n, dce);
5463da31819Sjmcneill 
5473da31819Sjmcneill done:
5483da31819Sjmcneill 	if (buf.Pointer != NULL) {
5493da31819Sjmcneill 		ACPI_FREE(buf.Pointer);
5503da31819Sjmcneill 	}
5513da31819Sjmcneill 	if (rv) {
5523da31819Sjmcneill 		rv = (rv - 1) + ACPI_MATCHSCORE_CID;
5533da31819Sjmcneill 		return imin(rv, ACPI_MATCHSCORE_CID_MAX);
5543da31819Sjmcneill 	}
5553da31819Sjmcneill 	return 0;
5563da31819Sjmcneill }
5573da31819Sjmcneill 
558660a9ad6Sthorpej /*
559660a9ad6Sthorpej  * acpi_compatible_match --
560660a9ad6Sthorpej  *
561660a9ad6Sthorpej  *	Returns a weighted match value, comparing the _HID and _CID
5626584ea56Sandvar  *	IDs against a driver's compatibility data.
563660a9ad6Sthorpej  */
564660a9ad6Sthorpej int
565660a9ad6Sthorpej acpi_compatible_match(const struct acpi_attach_args * const aa,
566660a9ad6Sthorpej     const struct device_compatible_entry * const dce)
567660a9ad6Sthorpej {
568660a9ad6Sthorpej 	const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)];
569660a9ad6Sthorpej 	const char **cpp;
5701ff08d8eSjmcneill 	bool dtlink = false;
5711ff08d8eSjmcneill 	int rv;
572660a9ad6Sthorpej 
573660a9ad6Sthorpej 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
574660a9ad6Sthorpej 		return 0;
575660a9ad6Sthorpej 	}
576660a9ad6Sthorpej 
577660a9ad6Sthorpej 	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
578660a9ad6Sthorpej 
579660a9ad6Sthorpej 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
580660a9ad6Sthorpej 		strings[0] = ad->HardwareId.String;
581660a9ad6Sthorpej 
582660a9ad6Sthorpej 		/* Matching _HID wins big. */
583660a9ad6Sthorpej 		if (device_compatible_pmatch(strings, 1, dce) != 0) {
584660a9ad6Sthorpej 			return ACPI_MATCHSCORE_HID;
585660a9ad6Sthorpej 		}
5861ff08d8eSjmcneill 
5871ff08d8eSjmcneill 		if (device_compatible_pmatch(strings, 1,
5881ff08d8eSjmcneill 					     dtlink_compat_data) != 0) {
5891ff08d8eSjmcneill 			dtlink = true;
5901ff08d8eSjmcneill 		}
591660a9ad6Sthorpej 	}
592660a9ad6Sthorpej 
593660a9ad6Sthorpej 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
594660a9ad6Sthorpej 		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
595660a9ad6Sthorpej 		    ad->CompatibleIdList.Count, strings);
596660a9ad6Sthorpej 
597660a9ad6Sthorpej 		rv = device_compatible_pmatch(cpp,
598660a9ad6Sthorpej 		    ad->CompatibleIdList.Count, dce);
5991ff08d8eSjmcneill 		if (!dtlink &&
6001ff08d8eSjmcneill 		    device_compatible_pmatch(cpp, ad->CompatibleIdList.Count,
6011ff08d8eSjmcneill 					     dtlink_compat_data) != 0) {
6021ff08d8eSjmcneill 			dtlink = true;
6031ff08d8eSjmcneill 		}
604660a9ad6Sthorpej 		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
605660a9ad6Sthorpej 		    strings);
606660a9ad6Sthorpej 		if (rv) {
607660a9ad6Sthorpej 			rv = (rv - 1) + ACPI_MATCHSCORE_CID;
6081ff08d8eSjmcneill 			return imin(rv, ACPI_MATCHSCORE_CID_MAX);
609660a9ad6Sthorpej 		}
6101ff08d8eSjmcneill 	}
6111ff08d8eSjmcneill 
6121ff08d8eSjmcneill 	if (dtlink) {
6133da31819Sjmcneill 		return acpi_compatible_match_dtlink(aa, dce);
614660a9ad6Sthorpej 	}
615660a9ad6Sthorpej 
616660a9ad6Sthorpej 	return 0;
617660a9ad6Sthorpej }
618660a9ad6Sthorpej 
619660a9ad6Sthorpej /*
620660a9ad6Sthorpej  * acpi_compatible_lookup --
621660a9ad6Sthorpej  *
622660a9ad6Sthorpej  *	Returns the device_compatible_entry that matches the _HID
623660a9ad6Sthorpej  *	or _CID ID.
624660a9ad6Sthorpej  */
625660a9ad6Sthorpej const struct device_compatible_entry *
626660a9ad6Sthorpej acpi_compatible_lookup(const struct acpi_attach_args * const aa,
627660a9ad6Sthorpej     const struct device_compatible_entry * const dce)
628660a9ad6Sthorpej {
629660a9ad6Sthorpej 	const struct device_compatible_entry *rv = NULL;
630660a9ad6Sthorpej 	const char *strings[ACPI_COMPATSTR_MAX];
631660a9ad6Sthorpej 	const char **cpp;
632660a9ad6Sthorpej 
633660a9ad6Sthorpej 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
6346451a97aSthorpej 		return NULL;
6356451a97aSthorpej 	}
6366451a97aSthorpej 
637660a9ad6Sthorpej 	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
6386451a97aSthorpej 
6396451a97aSthorpej 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
640660a9ad6Sthorpej 		strings[0] = ad->HardwareId.String;
641660a9ad6Sthorpej 
642660a9ad6Sthorpej 		rv = device_compatible_plookup(strings, 1, dce);
643660a9ad6Sthorpej 		if (rv != NULL)
644660a9ad6Sthorpej 			return rv;
6456451a97aSthorpej 	}
6466451a97aSthorpej 
6476451a97aSthorpej 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
648660a9ad6Sthorpej 		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
649660a9ad6Sthorpej 		    ad->CompatibleIdList.Count, strings);
650660a9ad6Sthorpej 
651660a9ad6Sthorpej 		rv = device_compatible_plookup(cpp,
652660a9ad6Sthorpej 		    ad->CompatibleIdList.Count, dce);
653660a9ad6Sthorpej 		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
654660a9ad6Sthorpej 		    strings);
6556451a97aSthorpej 	}
6566451a97aSthorpej 
657660a9ad6Sthorpej 	return rv;
6586451a97aSthorpej }
6596451a97aSthorpej 
6606451a97aSthorpej /*
661d6afaa44Sjruoho  * Match given IDs against _HID and _CIDs.
6620c88d0e4Sjruoho  */
6630c88d0e4Sjruoho int
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 
6960f056e49Sjruoho /*
697d94e7e9cSjmcneill  * Match a PCI-defined bass-class, sub-class, and programming interface
698d94e7e9cSjmcneill  * against a handle's _CLS object.
699d94e7e9cSjmcneill  */
700d94e7e9cSjmcneill int
701d94e7e9cSjmcneill acpi_match_class(ACPI_HANDLE handle, uint8_t pci_class, uint8_t pci_subclass,
702d94e7e9cSjmcneill     uint8_t pci_interface)
703d94e7e9cSjmcneill {
704d94e7e9cSjmcneill 	ACPI_BUFFER buf;
705d94e7e9cSjmcneill 	ACPI_OBJECT *obj;
706d94e7e9cSjmcneill 	ACPI_STATUS rv;
707d94e7e9cSjmcneill 	int match = 0;
708d94e7e9cSjmcneill 
709d94e7e9cSjmcneill 	rv = acpi_eval_struct(handle, "_CLS", &buf);
710d94e7e9cSjmcneill 	if (ACPI_FAILURE(rv))
711d94e7e9cSjmcneill 		goto done;
712d94e7e9cSjmcneill 
713d94e7e9cSjmcneill 	obj = buf.Pointer;
714d94e7e9cSjmcneill 	if (obj->Type != ACPI_TYPE_PACKAGE)
715d94e7e9cSjmcneill 		goto done;
716d94e7e9cSjmcneill 	if (obj->Package.Count != 3)
717d94e7e9cSjmcneill 		goto done;
718d94e7e9cSjmcneill 	if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
719d94e7e9cSjmcneill 	    obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER ||
720d94e7e9cSjmcneill 	    obj->Package.Elements[2].Type != ACPI_TYPE_INTEGER)
721d94e7e9cSjmcneill 		goto done;
722d94e7e9cSjmcneill 
723d94e7e9cSjmcneill 	match = obj->Package.Elements[0].Integer.Value == pci_class &&
724d94e7e9cSjmcneill 		obj->Package.Elements[1].Integer.Value == pci_subclass &&
725d94e7e9cSjmcneill 		obj->Package.Elements[2].Integer.Value == pci_interface;
726d94e7e9cSjmcneill 
727d94e7e9cSjmcneill done:
728d94e7e9cSjmcneill 	if (buf.Pointer)
729d94e7e9cSjmcneill 		ACPI_FREE(buf.Pointer);
730660a9ad6Sthorpej 	return match ? ACPI_MATCHSCORE_CLS : 0;
731d94e7e9cSjmcneill }
732d94e7e9cSjmcneill 
733d94e7e9cSjmcneill /*
734a9db528eSjruoho  * Match a device node from a handle.
735a9db528eSjruoho  */
736a9db528eSjruoho struct acpi_devnode *
737a9db528eSjruoho acpi_match_node(ACPI_HANDLE handle)
738a9db528eSjruoho {
739a9db528eSjruoho 	struct acpi_devnode *ad;
740a9db528eSjruoho 	ACPI_STATUS rv;
741a9db528eSjruoho 
742a9db528eSjruoho 	if (handle == NULL)
743a9db528eSjruoho 		return NULL;
744a9db528eSjruoho 
745a9db528eSjruoho 	rv = AcpiGetData(handle, acpi_clean_node, (void **)&ad);
746a9db528eSjruoho 
747a9db528eSjruoho 	if (ACPI_FAILURE(rv))
748a9db528eSjruoho 		return NULL;
749a9db528eSjruoho 
750a9db528eSjruoho 	return ad;
751a9db528eSjruoho }
752a9db528eSjruoho 
753a9db528eSjruoho /*
754a9db528eSjruoho  * Permanently associate a device node with a handle.
755a9db528eSjruoho  */
756a9db528eSjruoho void
757a9db528eSjruoho acpi_match_node_init(struct acpi_devnode *ad)
758a9db528eSjruoho {
759a9db528eSjruoho 	(void)AcpiAttachData(ad->ad_handle, acpi_clean_node, ad);
760a9db528eSjruoho }
761a9db528eSjruoho 
762a9db528eSjruoho static void
763a9db528eSjruoho acpi_clean_node(ACPI_HANDLE handle, void *aux)
764a9db528eSjruoho {
765a9db528eSjruoho 	/* Nothing. */
766a9db528eSjruoho }
767a9db528eSjruoho 
768a9db528eSjruoho /*
7690f056e49Sjruoho  * Match a handle from a cpu_info. Returns NULL on failure.
7700f056e49Sjruoho  *
771a9db528eSjruoho  * Note that acpi_match_node() can be used if the device node
772a9db528eSjruoho  * is also required.
7730f056e49Sjruoho  */
7740f056e49Sjruoho ACPI_HANDLE
7750f056e49Sjruoho acpi_match_cpu_info(struct cpu_info *ci)
7760f056e49Sjruoho {
7770f056e49Sjruoho 	struct acpi_softc *sc = acpi_softc;
7780f056e49Sjruoho 	struct acpi_devnode *ad;
7790f056e49Sjruoho 	ACPI_INTEGER val;
7800f056e49Sjruoho 	ACPI_OBJECT *obj;
7810f056e49Sjruoho 	ACPI_BUFFER buf;
7820f056e49Sjruoho 	ACPI_HANDLE hdl;
7830f056e49Sjruoho 	ACPI_STATUS rv;
7840f056e49Sjruoho 
7852dd5064cSjmcneill 	if (sc == NULL)
7860f056e49Sjruoho 		return NULL;
7870f056e49Sjruoho 
7880f056e49Sjruoho 	/*
7890f056e49Sjruoho 	 * CPUs are declared in the ACPI namespace
7900f056e49Sjruoho 	 * either as a Processor() or as a Device().
7910f056e49Sjruoho 	 * In both cases the MADT entries are used
7920f056e49Sjruoho 	 * for the match (see ACPI 4.0, section 8.4).
7930f056e49Sjruoho 	 */
794de6a49e8Sskrll 	SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
7950f056e49Sjruoho 
7960f056e49Sjruoho 		hdl = ad->ad_handle;
7970f056e49Sjruoho 
7980f056e49Sjruoho 		switch (ad->ad_type) {
7990f056e49Sjruoho 
8000f056e49Sjruoho 		case ACPI_TYPE_DEVICE:
8010f056e49Sjruoho 
8020f056e49Sjruoho 			if (acpi_match_hid(ad->ad_devinfo, acpicpu_ids) == 0)
8030f056e49Sjruoho 				break;
8040f056e49Sjruoho 
8050f056e49Sjruoho 			rv = acpi_eval_integer(hdl, "_UID", &val);
8060f056e49Sjruoho 
8070f056e49Sjruoho 			if (ACPI_SUCCESS(rv) && val == ci->ci_acpiid)
8080f056e49Sjruoho 				return hdl;
8090f056e49Sjruoho 
8100f056e49Sjruoho 			break;
8110f056e49Sjruoho 
8120f056e49Sjruoho 		case ACPI_TYPE_PROCESSOR:
8130f056e49Sjruoho 
8140f056e49Sjruoho 			rv = acpi_eval_struct(hdl, NULL, &buf);
8150f056e49Sjruoho 
8160f056e49Sjruoho 			if (ACPI_FAILURE(rv))
8170f056e49Sjruoho 				break;
8180f056e49Sjruoho 
8190f056e49Sjruoho 			obj = buf.Pointer;
8200f056e49Sjruoho 
8210f056e49Sjruoho 			if (obj->Processor.ProcId == ci->ci_acpiid) {
8220f056e49Sjruoho 				ACPI_FREE(buf.Pointer);
8230f056e49Sjruoho 				return hdl;
8240f056e49Sjruoho 			}
8250f056e49Sjruoho 
8260f056e49Sjruoho 			ACPI_FREE(buf.Pointer);
8270f056e49Sjruoho 			break;
8280f056e49Sjruoho 		}
8290f056e49Sjruoho 	}
8300f056e49Sjruoho 
8310f056e49Sjruoho 	return NULL;
8320f056e49Sjruoho }
8330f056e49Sjruoho 
8340f056e49Sjruoho /*
8350f056e49Sjruoho  * Match a CPU from a handle. Returns NULL on failure.
8360f056e49Sjruoho  */
8370f056e49Sjruoho struct cpu_info *
8380f056e49Sjruoho acpi_match_cpu_handle(ACPI_HANDLE hdl)
8390f056e49Sjruoho {
8400f056e49Sjruoho 	struct cpu_info *ci;
8410f056e49Sjruoho 	ACPI_DEVICE_INFO *di;
8420f056e49Sjruoho 	CPU_INFO_ITERATOR cii;
8430f056e49Sjruoho 	ACPI_INTEGER val;
8440f056e49Sjruoho 	ACPI_OBJECT *obj;
8450f056e49Sjruoho 	ACPI_BUFFER buf;
8460f056e49Sjruoho 	ACPI_STATUS rv;
8470f056e49Sjruoho 
8480f056e49Sjruoho 	ci = NULL;
8490f056e49Sjruoho 	di = NULL;
8500f056e49Sjruoho 	buf.Pointer = NULL;
8510f056e49Sjruoho 
8520f056e49Sjruoho 	rv = AcpiGetObjectInfo(hdl, &di);
8530f056e49Sjruoho 
8540f056e49Sjruoho 	if (ACPI_FAILURE(rv))
8550f056e49Sjruoho 		return NULL;
8560f056e49Sjruoho 
8570f056e49Sjruoho 	switch (di->Type) {
8580f056e49Sjruoho 
8590f056e49Sjruoho 	case ACPI_TYPE_DEVICE:
8600f056e49Sjruoho 
8610f056e49Sjruoho 		if (acpi_match_hid(di, acpicpu_ids) == 0)
8620f056e49Sjruoho 			goto out;
8630f056e49Sjruoho 
8640f056e49Sjruoho 		rv = acpi_eval_integer(hdl, "_UID", &val);
8650f056e49Sjruoho 
8660f056e49Sjruoho 		if (ACPI_FAILURE(rv))
8670f056e49Sjruoho 			goto out;
8680f056e49Sjruoho 
8690f056e49Sjruoho 		break;
8700f056e49Sjruoho 
8710f056e49Sjruoho 	case ACPI_TYPE_PROCESSOR:
8720f056e49Sjruoho 
8730f056e49Sjruoho 		rv = acpi_eval_struct(hdl, NULL, &buf);
8740f056e49Sjruoho 
8750f056e49Sjruoho 		if (ACPI_FAILURE(rv))
8760f056e49Sjruoho 			goto out;
8770f056e49Sjruoho 
8780f056e49Sjruoho 		obj = buf.Pointer;
8790f056e49Sjruoho 		val = obj->Processor.ProcId;
8800f056e49Sjruoho 		break;
8810f056e49Sjruoho 
8820f056e49Sjruoho 	default:
8830f056e49Sjruoho 		goto out;
8840f056e49Sjruoho 	}
8850f056e49Sjruoho 
8860f056e49Sjruoho 	for (CPU_INFO_FOREACH(cii, ci)) {
8870f056e49Sjruoho 
8880f056e49Sjruoho 		if (ci->ci_acpiid == val)
8890f056e49Sjruoho 			goto out;
8900f056e49Sjruoho 	}
8910f056e49Sjruoho 
8920f056e49Sjruoho 	ci = NULL;
8930f056e49Sjruoho 
8940f056e49Sjruoho out:
8950f056e49Sjruoho 	if (di != NULL)
8960f056e49Sjruoho 		ACPI_FREE(di);
8970f056e49Sjruoho 
8980f056e49Sjruoho 	if (buf.Pointer != NULL)
8990f056e49Sjruoho 		ACPI_FREE(buf.Pointer);
9000f056e49Sjruoho 
9010f056e49Sjruoho 	return ci;
9020f056e49Sjruoho }
903db8cbfd3Sbouyer 
904db8cbfd3Sbouyer struct acpi_irq_handler {
905db8cbfd3Sbouyer 	uint32_t aih_irq;
906f62244a8Sjmcneill 	void *aih_ih;
907db8cbfd3Sbouyer };
908db8cbfd3Sbouyer 
909db8cbfd3Sbouyer void *
910f62244a8Sjmcneill acpi_intr_establish(device_t dev, uint64_t c, int ipl, bool mpsafe,
911f62244a8Sjmcneill     int (*intr)(void *), void *iarg, const char *xname)
912db8cbfd3Sbouyer {
913db8cbfd3Sbouyer 	ACPI_STATUS rv;
91451f154a4Sbouyer 	ACPI_HANDLE hdl = (void *)(uintptr_t)c;
915db8cbfd3Sbouyer 	struct acpi_resources res;
916db8cbfd3Sbouyer 	struct acpi_irq *irq;
91757c57328Sjmcneill 	void *aih = NULL;
918db8cbfd3Sbouyer 
919db8cbfd3Sbouyer 	rv = acpi_resource_parse(dev, hdl, "_CRS", &res,
920db8cbfd3Sbouyer 	    &acpi_resource_parse_ops_quiet);
921db8cbfd3Sbouyer 	if (ACPI_FAILURE(rv))
922db8cbfd3Sbouyer 		return NULL;
923db8cbfd3Sbouyer 
924db8cbfd3Sbouyer 	irq = acpi_res_irq(&res, 0);
925db8cbfd3Sbouyer 	if (irq == NULL)
926db8cbfd3Sbouyer 		goto end;
927db8cbfd3Sbouyer 
92857c57328Sjmcneill 	aih = acpi_intr_establish_irq(dev, irq, ipl, mpsafe,
92957c57328Sjmcneill 	    intr, iarg, xname);
930f62244a8Sjmcneill 
931db8cbfd3Sbouyer end:
932db8cbfd3Sbouyer 	acpi_resource_cleanup(&res);
93357c57328Sjmcneill 
93457c57328Sjmcneill 	return aih;
93557c57328Sjmcneill }
93657c57328Sjmcneill 
93757c57328Sjmcneill void *
93857c57328Sjmcneill acpi_intr_establish_irq(device_t dev, struct acpi_irq *irq, int ipl,
93957c57328Sjmcneill     bool mpsafe, int (*intr)(void *), void *iarg, const char *xname)
94057c57328Sjmcneill {
94157c57328Sjmcneill 	struct acpi_irq_handler *aih;
94257c57328Sjmcneill 	void *ih;
94357c57328Sjmcneill 
94457c57328Sjmcneill 	const int type = (irq->ar_type == ACPI_EDGE_SENSITIVE) ? IST_EDGE : IST_LEVEL;
94557c57328Sjmcneill 	ih = acpi_md_intr_establish(irq->ar_irq, ipl, type, intr, iarg, mpsafe, xname);
94657c57328Sjmcneill 	if (ih == NULL)
94757c57328Sjmcneill 		return NULL;
94857c57328Sjmcneill 
94957c57328Sjmcneill 	aih = kmem_alloc(sizeof(struct acpi_irq_handler), KM_SLEEP);
95057c57328Sjmcneill 	aih->aih_irq = irq->ar_irq;
95157c57328Sjmcneill 	aih->aih_ih = ih;
95257c57328Sjmcneill 
953db8cbfd3Sbouyer 	return aih;
954db8cbfd3Sbouyer }
955db8cbfd3Sbouyer 
956db8cbfd3Sbouyer void
957659765daSthorpej acpi_intr_mask(void *c)
958659765daSthorpej {
959659765daSthorpej 	struct acpi_irq_handler * const aih = c;
960659765daSthorpej 
961659765daSthorpej 	acpi_md_intr_mask(aih->aih_ih);
962659765daSthorpej }
963659765daSthorpej 
964659765daSthorpej void
965659765daSthorpej acpi_intr_unmask(void *c)
966659765daSthorpej {
967659765daSthorpej 	struct acpi_irq_handler * const aih = c;
968659765daSthorpej 
969659765daSthorpej 	acpi_md_intr_unmask(aih->aih_ih);
970659765daSthorpej }
971659765daSthorpej 
972659765daSthorpej void
973f62244a8Sjmcneill acpi_intr_disestablish(void *c)
974db8cbfd3Sbouyer {
975db8cbfd3Sbouyer 	struct acpi_irq_handler *aih = c;
976db8cbfd3Sbouyer 
977f62244a8Sjmcneill 	acpi_md_intr_disestablish(aih->aih_ih);
978db8cbfd3Sbouyer 	kmem_free(aih, sizeof(struct acpi_irq_handler));
979db8cbfd3Sbouyer }
980db8cbfd3Sbouyer 
981db8cbfd3Sbouyer const char *
982db8cbfd3Sbouyer acpi_intr_string(void *c, char *buf, size_t size)
983db8cbfd3Sbouyer {
984db8cbfd3Sbouyer 	struct acpi_irq_handler *aih = c;
985db8cbfd3Sbouyer 	intr_handle_t ih = aih->aih_irq;
986db8cbfd3Sbouyer 
987db8cbfd3Sbouyer 	return intr_string(ih, buf, size);
988db8cbfd3Sbouyer }
98900639337Sjmcneill 
99000639337Sjmcneill /*
9916451a97aSthorpej  * Device-Specific Data (_DSD) support
99200639337Sjmcneill  */
99300639337Sjmcneill 
99400639337Sjmcneill static UINT8 acpi_dsd_uuid[ACPI_UUID_LENGTH] = {
99500639337Sjmcneill 	0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
99600639337Sjmcneill 	0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
99700639337Sjmcneill };
99800639337Sjmcneill 
9999f624f6aSjmcneill static ACPI_STATUS
10009f624f6aSjmcneill acpi_dsd_property(ACPI_HANDLE handle, const char *prop, ACPI_BUFFER *pbuf, ACPI_OBJECT_TYPE type, ACPI_OBJECT **ret)
100100639337Sjmcneill {
100200639337Sjmcneill 	ACPI_OBJECT *obj, *uuid, *props, *pobj, *propkey, *propval;
100300639337Sjmcneill 	ACPI_STATUS rv;
100400639337Sjmcneill 	int n;
100500639337Sjmcneill 
10069f624f6aSjmcneill 	rv = AcpiEvaluateObjectTyped(handle, "_DSD", NULL, pbuf, ACPI_TYPE_PACKAGE);
100700639337Sjmcneill 	if (ACPI_FAILURE(rv))
100800639337Sjmcneill 		return rv;
100900639337Sjmcneill 
101000639337Sjmcneill 	props = NULL;
10119f624f6aSjmcneill 	obj = (ACPI_OBJECT *)pbuf->Pointer;
101200639337Sjmcneill 	for (n = 0; (n + 1) < obj->Package.Count; n += 2) {
101300639337Sjmcneill 		uuid = &obj->Package.Elements[n];
101400639337Sjmcneill 		if (uuid->Buffer.Length == ACPI_UUID_LENGTH &&
101500639337Sjmcneill 		    memcmp(uuid->Buffer.Pointer, acpi_dsd_uuid, ACPI_UUID_LENGTH) == 0) {
101600639337Sjmcneill 			props = &obj->Package.Elements[n + 1];
101700639337Sjmcneill 			break;
101800639337Sjmcneill 		}
101900639337Sjmcneill 	}
10209f624f6aSjmcneill 	if (props == NULL)
10219f624f6aSjmcneill 		return AE_NOT_FOUND;
102200639337Sjmcneill 
102300639337Sjmcneill 	for (n = 0; n < props->Package.Count; n++) {
102400639337Sjmcneill 		pobj = &props->Package.Elements[n];
102500639337Sjmcneill 		if (pobj->Type != ACPI_TYPE_PACKAGE || pobj->Package.Count != 2)
102600639337Sjmcneill 			continue;
102700639337Sjmcneill 		propkey = (ACPI_OBJECT *)&pobj->Package.Elements[0];
102800639337Sjmcneill 		propval = (ACPI_OBJECT *)&pobj->Package.Elements[1];
102900639337Sjmcneill 		if (propkey->Type != ACPI_TYPE_STRING)
103000639337Sjmcneill 			continue;
103100639337Sjmcneill 		if (strcmp(propkey->String.Pointer, prop) != 0)
103200639337Sjmcneill 			continue;
103300639337Sjmcneill 
10349f624f6aSjmcneill 		if (propval->Type != type) {
10359f624f6aSjmcneill 			return AE_TYPE;
103600639337Sjmcneill 		} else {
10379f624f6aSjmcneill 			*ret = propval;
10389f624f6aSjmcneill 			return AE_OK;
103900639337Sjmcneill 		}
104000639337Sjmcneill 		break;
104100639337Sjmcneill 	}
104200639337Sjmcneill 
10439f624f6aSjmcneill 	return AE_NOT_FOUND;
10449f624f6aSjmcneill }
10459f624f6aSjmcneill 
10469f624f6aSjmcneill ACPI_STATUS
10479f624f6aSjmcneill acpi_dsd_integer(ACPI_HANDLE handle, const char *prop, ACPI_INTEGER *val)
10489f624f6aSjmcneill {
10499f624f6aSjmcneill 	ACPI_OBJECT *propval;
10509f624f6aSjmcneill 	ACPI_STATUS rv;
10519f624f6aSjmcneill 	ACPI_BUFFER buf;
10529f624f6aSjmcneill 
10539f624f6aSjmcneill 	buf.Pointer = NULL;
10549f624f6aSjmcneill 	buf.Length = ACPI_ALLOCATE_BUFFER;
10559f624f6aSjmcneill 
10569f624f6aSjmcneill 	rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_INTEGER, &propval);
10579f624f6aSjmcneill 	if (ACPI_SUCCESS(rv))
10589f624f6aSjmcneill 		*val = propval->Integer.Value;
10599f624f6aSjmcneill 
10600aac85d5Smlelstv 	if (buf.Pointer != NULL)
10619f624f6aSjmcneill 		ACPI_FREE(buf.Pointer);
10629f624f6aSjmcneill 	return rv;
10639f624f6aSjmcneill }
10649f624f6aSjmcneill 
10659f624f6aSjmcneill ACPI_STATUS
10669f624f6aSjmcneill acpi_dsd_string(ACPI_HANDLE handle, const char *prop, char **val)
10679f624f6aSjmcneill {
10689f624f6aSjmcneill 	ACPI_OBJECT *propval;
10699f624f6aSjmcneill 	ACPI_STATUS rv;
10709f624f6aSjmcneill 	ACPI_BUFFER buf;
10719f624f6aSjmcneill 
10729f624f6aSjmcneill 	buf.Pointer = NULL;
10739f624f6aSjmcneill 	buf.Length = ACPI_ALLOCATE_BUFFER;
10749f624f6aSjmcneill 
10759f624f6aSjmcneill 	rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_STRING, &propval);
10769f624f6aSjmcneill 	if (ACPI_SUCCESS(rv))
10779f624f6aSjmcneill 		*val = kmem_strdup(propval->String.Pointer, KM_SLEEP);
10789f624f6aSjmcneill 
10790aac85d5Smlelstv 	if (buf.Pointer != NULL)
108000639337Sjmcneill 		ACPI_FREE(buf.Pointer);
108100639337Sjmcneill 	return rv;
108200639337Sjmcneill }
10836451a97aSthorpej 
1084bf7784c0Sjmcneill ACPI_STATUS
1085bf7784c0Sjmcneill acpi_dsd_bool(ACPI_HANDLE handle, const char *prop, bool *val)
1086bf7784c0Sjmcneill {
1087bf7784c0Sjmcneill 	ACPI_STATUS rv;
1088bf7784c0Sjmcneill 	ACPI_INTEGER ival;
1089bf7784c0Sjmcneill 
1090bf7784c0Sjmcneill 	rv = acpi_dsd_integer(handle, prop, &ival);
1091bf7784c0Sjmcneill 	if (ACPI_SUCCESS(rv)) {
1092bf7784c0Sjmcneill 		*val = ival != 0;
1093bf7784c0Sjmcneill 	}
1094bf7784c0Sjmcneill 
1095bf7784c0Sjmcneill 	return rv;
1096bf7784c0Sjmcneill }
10973da31819Sjmcneill 
10983da31819Sjmcneill 
10996451a97aSthorpej /*
11006451a97aSthorpej  * Device Specific Method (_DSM) support
11016451a97aSthorpej  */
11026451a97aSthorpej 
11036451a97aSthorpej ACPI_STATUS
11046451a97aSthorpej acpi_dsm_typed(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
11056451a97aSthorpej     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT_TYPE return_type,
11066451a97aSthorpej     ACPI_OBJECT **return_obj)
11076451a97aSthorpej {
11086451a97aSthorpej 	ACPI_OBJECT_LIST arg;
11096451a97aSthorpej 	ACPI_OBJECT obj[4];
11106451a97aSthorpej 	ACPI_BUFFER buf;
11116451a97aSthorpej 	ACPI_STATUS status;
11126451a97aSthorpej 
11136451a97aSthorpej 	arg.Count = 4;
11146451a97aSthorpej 	arg.Pointer = obj;
11156451a97aSthorpej 
11166451a97aSthorpej 	obj[0].Type = ACPI_TYPE_BUFFER;
11176451a97aSthorpej 	obj[0].Buffer.Length = ACPI_UUID_LENGTH;
11186451a97aSthorpej 	obj[0].Buffer.Pointer = uuid;
11196451a97aSthorpej 
11206451a97aSthorpej 	obj[1].Type = ACPI_TYPE_INTEGER;
11216451a97aSthorpej 	obj[1].Integer.Value = rev;
11226451a97aSthorpej 
11236451a97aSthorpej 	obj[2].Type = ACPI_TYPE_INTEGER;
11246451a97aSthorpej 	obj[2].Integer.Value = func;
11256451a97aSthorpej 
11266451a97aSthorpej 	if (arg3 != NULL) {
11276451a97aSthorpej 		obj[3] = *arg3;
11286451a97aSthorpej 	} else {
11296451a97aSthorpej 		obj[3].Type = ACPI_TYPE_PACKAGE;
11306451a97aSthorpej 		obj[3].Package.Count = 0;
11316451a97aSthorpej 		obj[3].Package.Elements = NULL;
11326451a97aSthorpej 	}
11336451a97aSthorpej 
11346451a97aSthorpej 	buf.Pointer = NULL;
11356451a97aSthorpej 	buf.Length = ACPI_ALLOCATE_BUFFER;
11366451a97aSthorpej 
11376451a97aSthorpej 	if (return_obj == NULL && return_type == ACPI_TYPE_ANY) {
11386451a97aSthorpej 		status = AcpiEvaluateObject(handle, "_DSM", &arg, NULL);
11396451a97aSthorpej 	} else {
11406451a97aSthorpej 		*return_obj = NULL;
11416451a97aSthorpej 		status = AcpiEvaluateObjectTyped(handle, "_DSM", &arg, &buf,
11426451a97aSthorpej 		    return_type);
11436451a97aSthorpej 	}
11446451a97aSthorpej 	if (ACPI_FAILURE(status)) {
11456451a97aSthorpej 		return status;
11466451a97aSthorpej 	}
11476451a97aSthorpej 	if (return_obj != NULL) {
11486451a97aSthorpej 		*return_obj = buf.Pointer;
11496451a97aSthorpej 	} else if (buf.Pointer != NULL) {
11506451a97aSthorpej 		ACPI_FREE(buf.Pointer);
11516451a97aSthorpej 	}
11526451a97aSthorpej 	return AE_OK;
11536451a97aSthorpej }
11546451a97aSthorpej 
11556451a97aSthorpej ACPI_STATUS
11566451a97aSthorpej acpi_dsm_integer(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
11576451a97aSthorpej     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_INTEGER *ret)
11586451a97aSthorpej {
11596451a97aSthorpej 	ACPI_OBJECT *obj;
11606451a97aSthorpej 	ACPI_STATUS status;
11616451a97aSthorpej 
11626451a97aSthorpej 	status = acpi_dsm_typed(handle, uuid, rev, func, arg3,
11636451a97aSthorpej 	    ACPI_TYPE_INTEGER, &obj);
11646451a97aSthorpej 	if (ACPI_FAILURE(status)) {
11656451a97aSthorpej 		return status;
11666451a97aSthorpej 	}
11676451a97aSthorpej 
11686451a97aSthorpej 	*ret = obj->Integer.Value;
11696451a97aSthorpej 	ACPI_FREE(obj);
11706451a97aSthorpej 
11716451a97aSthorpej 	return AE_OK;
11726451a97aSthorpej }
11736451a97aSthorpej 
11746451a97aSthorpej ACPI_STATUS
11756451a97aSthorpej acpi_dsm(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
11766451a97aSthorpej     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT **return_obj)
11776451a97aSthorpej {
11786451a97aSthorpej 	return acpi_dsm_typed(handle, uuid, rev, func, arg3, ACPI_TYPE_ANY,
11796451a97aSthorpej 	    return_obj);
11806451a97aSthorpej }
1181172e088eSjmcneill 
1182172e088eSjmcneill ACPI_STATUS
118348c56ea6Sjmcneill acpi_dsm_query(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
118448c56ea6Sjmcneill     ACPI_INTEGER *ret)
118548c56ea6Sjmcneill {
118648c56ea6Sjmcneill 	ACPI_OBJECT *obj;
118748c56ea6Sjmcneill 	ACPI_STATUS status;
118848c56ea6Sjmcneill 	uint8_t *data;
118948c56ea6Sjmcneill 	u_int n;
119048c56ea6Sjmcneill 
119148c56ea6Sjmcneill 	status = acpi_dsm(handle, uuid, rev, 0, NULL, &obj);
119248c56ea6Sjmcneill 	if (ACPI_FAILURE(status)) {
119348c56ea6Sjmcneill 		return status;
119448c56ea6Sjmcneill 	}
119548c56ea6Sjmcneill 
119648c56ea6Sjmcneill 	if (obj->Type == ACPI_TYPE_INTEGER) {
119748c56ea6Sjmcneill 		*ret = obj->Integer.Value;
119848c56ea6Sjmcneill 	} else if (obj->Type == ACPI_TYPE_BUFFER &&
119948c56ea6Sjmcneill 		   obj->Buffer.Length <= 8) {
120048c56ea6Sjmcneill 		*ret = 0;
120148c56ea6Sjmcneill 		data = (uint8_t *)obj->Buffer.Pointer;
120248c56ea6Sjmcneill 		for (n = 0; n < obj->Buffer.Length; n++) {
120348c56ea6Sjmcneill 			*ret |= (uint64_t)data[n] << (n * 8);
120448c56ea6Sjmcneill 		}
120548c56ea6Sjmcneill 	} else {
120648c56ea6Sjmcneill 		status = AE_TYPE;
120748c56ea6Sjmcneill 	}
120848c56ea6Sjmcneill 
120948c56ea6Sjmcneill 	ACPI_FREE(obj);
121048c56ea6Sjmcneill 
121148c56ea6Sjmcneill 	return status;
121248c56ea6Sjmcneill }
121348c56ea6Sjmcneill 
121448c56ea6Sjmcneill ACPI_STATUS
1215*84b6468dSjmcneill acpi_claim_childdevs(device_t dev, struct acpi_devnode *devnode,
1216*84b6468dSjmcneill     const char *method)
1217172e088eSjmcneill {
1218172e088eSjmcneill 	struct acpi_devnode *ad;
1219172e088eSjmcneill 
1220172e088eSjmcneill 	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
1221172e088eSjmcneill 		if (ad->ad_device != NULL)
1222172e088eSjmcneill 			continue;
1223*84b6468dSjmcneill 
1224*84b6468dSjmcneill 		if (method != NULL) {
1225*84b6468dSjmcneill 			ACPI_HANDLE h;
1226*84b6468dSjmcneill 			ACPI_STATUS rv;
1227*84b6468dSjmcneill 
1228*84b6468dSjmcneill 			rv = AcpiGetHandle(ad->ad_handle, method, &h);
1229*84b6468dSjmcneill 			if (ACPI_FAILURE(rv)) {
1230*84b6468dSjmcneill 				continue;
1231*84b6468dSjmcneill 			}
1232*84b6468dSjmcneill 		}
1233*84b6468dSjmcneill 
123485dfab94Sjmcneill 		aprint_debug_dev(dev, "claiming %s\n",
123585dfab94Sjmcneill 		    acpi_name(ad->ad_handle));
1236172e088eSjmcneill 		ad->ad_device = dev;
1237*84b6468dSjmcneill 		acpi_claim_childdevs(dev, ad, method);
1238172e088eSjmcneill 	}
1239172e088eSjmcneill 
1240172e088eSjmcneill 	return AE_OK;
1241172e088eSjmcneill }
1242