Home | History | Annotate | Line # | Download | only in acpi
      1 /*	$NetBSD: acpi_util.c,v 1.37 2025/10/04 01:12:15 thorpej Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2003, 2007, 2021 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Charles M. Hannum of By Noon Software, Inc.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright 2001, 2003 Wasabi Systems, Inc.
     34  * All rights reserved.
     35  *
     36  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
     37  *
     38  * Redistribution and use in source and binary forms, with or without
     39  * modification, are permitted provided that the following conditions
     40  * are met:
     41  * 1. Redistributions of source code must retain the above copyright
     42  *    notice, this list of conditions and the following disclaimer.
     43  * 2. Redistributions in binary form must reproduce the above copyright
     44  *    notice, this list of conditions and the following disclaimer in the
     45  *    documentation and/or other materials provided with the distribution.
     46  * 3. All advertising materials mentioning features or use of this software
     47  *    must display the following acknowledgement:
     48  *	This product includes software developed for the NetBSD Project by
     49  *	Wasabi Systems, Inc.
     50  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     51  *    or promote products derived from this software without specific prior
     52  *    written permission.
     53  *
     54  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     56  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     57  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     58  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     59  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     60  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     61  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     62  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     63  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     64  * POSSIBILITY OF SUCH DAMAGE.
     65  */
     66 
     67 #include <sys/cdefs.h>
     68 __KERNEL_RCSID(0, "$NetBSD: acpi_util.c,v 1.37 2025/10/04 01:12:15 thorpej Exp $");
     69 
     70 #include <sys/param.h>
     71 #include <sys/kmem.h>
     72 #include <sys/cpu.h>
     73 
     74 #include <dev/acpi/acpireg.h>
     75 #include <dev/acpi/acpivar.h>
     76 #include <dev/acpi/acpi_intr.h>
     77 
     78 #include <sys/device_calls.h>
     79 
     80 #include <machine/acpi_machdep.h>
     81 
     82 #define _COMPONENT	ACPI_BUS_COMPONENT
     83 ACPI_MODULE_NAME	("acpi_util")
     84 
     85 static void		acpi_clean_node(ACPI_HANDLE, void *);
     86 static ACPI_STATUS	acpi_dsd_property(ACPI_HANDLE, const char *,
     87 			    ACPI_BUFFER *, ACPI_OBJECT_TYPE, ACPI_OBJECT **);
     88 
     89 static const char * const acpicpu_ids[] = {
     90 	"ACPI0007",
     91 	NULL
     92 };
     93 
     94 static const struct device_compatible_entry dtlink_compat_data[] = {
     95 	{ .compat = "PRP0001" },
     96 	DEVICE_COMPAT_EOL
     97 };
     98 
     99 /*
    100  * ACPI device handle support.
    101  */
    102 
    103 static device_call_t
    104 acpi_devhandle_lookup_device_call(devhandle_t handle, const char *name,
    105     devhandle_t *call_handlep)
    106 {
    107 	__link_set_decl(acpi_device_calls, struct device_call_descriptor);
    108 	struct device_call_descriptor * const *desc;
    109 
    110 	__link_set_foreach(desc, acpi_device_calls) {
    111 		if (strcmp((*desc)->name, name) == 0) {
    112 			return (*desc)->call;
    113 		}
    114 	}
    115 	return NULL;
    116 }
    117 
    118 static const struct devhandle_impl acpi_devhandle_impl = {
    119 	.type = DEVHANDLE_TYPE_ACPI,
    120 	.lookup_device_call = acpi_devhandle_lookup_device_call,
    121 };
    122 
    123 devhandle_t
    124 devhandle_from_acpi(devhandle_t super_handle, ACPI_HANDLE const hdl)
    125 {
    126 	devhandle_type_t super_type = devhandle_type(super_handle);
    127 	devhandle_t handle = { 0 };
    128 
    129 	if (super_type == DEVHANDLE_TYPE_ACPI) {
    130 		handle.impl = super_handle.impl;
    131 	} else {
    132 		KASSERT(super_type == DEVHANDLE_TYPE_INVALID);
    133 		handle.impl = &acpi_devhandle_impl;
    134 	}
    135 	handle.pointer = hdl;
    136 
    137 	return handle;
    138 }
    139 
    140 ACPI_HANDLE
    141 devhandle_to_acpi(devhandle_t const handle)
    142 {
    143 	KASSERT(devhandle_type(handle) == DEVHANDLE_TYPE_ACPI);
    144 
    145 	return handle.pointer;
    146 }
    147 
    148 static int
    149 acpi_device_enumerate_children(device_t dev, devhandle_t call_handle, void *v)
    150 {
    151 	struct device_enumerate_children_args *args = v;
    152 	ACPI_HANDLE hdl = devhandle_to_acpi(call_handle);
    153 	struct acpi_devnode *devnode, *ad;
    154 
    155 	devnode = acpi_match_node(hdl);
    156 	KASSERT(devnode != NULL);
    157 
    158 	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
    159 		if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE ||
    160 		    !acpi_device_present(ad->ad_handle)) {
    161 			continue;
    162 		}
    163 		if (!args->callback(dev, devhandle_from_acpi(call_handle,
    164 							     ad->ad_handle),
    165 				    args->callback_arg)) {
    166 			break;
    167 		}
    168 	}
    169 
    170 	return 0;
    171 }
    172 ACPI_DEVICE_CALL_REGISTER(DEVICE_ENUMERATE_CHILDREN_STR,
    173 			  acpi_device_enumerate_children)
    174 
    175 static int
    176 acpi_device_register(device_t dev, devhandle_t call_handle, void *v)
    177 {
    178 	ACPI_HANDLE handle = devhandle_to_acpi(call_handle);
    179 	ACPI_BUFFER buf;
    180 	ACPI_STATUS rv;
    181 
    182 	buf.Pointer = NULL;
    183 	buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    184 
    185 	rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf);
    186 
    187 	if (! ACPI_FAILURE(rv)) {
    188 		device_setprop_string(dev, "device-path", buf.Pointer);
    189 	}
    190 
    191 	ACPI_FREE(buf.Pointer);
    192 	return 0;
    193 }
    194 ACPI_DEVICE_CALL_REGISTER(DEVICE_REGISTER_STR,
    195 			  acpi_device_register)
    196 
    197 static bool
    198 prop_type_to_acpi(prop_type_t type, ACPI_OBJECT_TYPE *out)
    199 {
    200 	switch (type) {
    201 	case PROP_TYPE_NUMBER:
    202 	case PROP_TYPE_BOOL:
    203 		*out = ACPI_TYPE_INTEGER;
    204 		break;
    205 
    206 	case PROP_TYPE_DATA:
    207 		/*
    208 		 * If we're requesting DATA, when we map to ANY, since
    209 		 * we want to be able to fetch STRINGs as DATA, too.
    210 		 */
    211 		*out = ACPI_TYPE_ANY;
    212 		break;
    213 
    214 	case PROP_TYPE_STRING:
    215 		*out = ACPI_TYPE_STRING;
    216 		break;
    217 
    218 	case PROP_TYPE_UNKNOWN:
    219 		*out = ACPI_TYPE_ANY;
    220 		break;
    221 
    222 	default:
    223 		return false;
    224 	}
    225 
    226 	return true;
    227 }
    228 
    229 static bool
    230 acpi_type_to_prop(ACPI_OBJECT_TYPE acpitype, prop_type_t *out)
    231 {
    232 	switch (acpitype) {
    233 	case ACPI_TYPE_INTEGER:
    234 		*out = PROP_TYPE_NUMBER;
    235 		break;
    236 
    237 	case ACPI_TYPE_BUFFER:
    238 		*out = PROP_TYPE_DATA;
    239 		break;
    240 
    241 	case ACPI_TYPE_STRING:
    242 		*out = PROP_TYPE_STRING;
    243 		break;
    244 
    245 	default:
    246 		return false;
    247 	}
    248 
    249 	return true;
    250 }
    251 
    252 static int
    253 acpi_device_get_property(device_t dev, devhandle_t call_handle, void *v)
    254 {
    255 	struct device_get_property_args *args = v;
    256 	ACPI_HANDLE hdl = devhandle_to_acpi(call_handle);
    257 	ACPI_OBJECT *propval;
    258 	ACPI_OBJECT_TYPE acpitype;
    259 	ACPI_STATUS rv;
    260 	ACPI_BUFFER buf;
    261 	int error = 0;
    262 
    263 	/*
    264 	 * No need to clamp size; ACPI sizes are unsigned (UINT32),
    265 	 * and the upper layer has already clamped to fit in ssize_t.
    266 	 */
    267 
    268 	if (! prop_type_to_acpi(args->reqtype, &acpitype)) {
    269 		return EFTYPE;
    270 	}
    271 
    272 	buf.Pointer = NULL;
    273 	buf.Length = ACPI_ALLOCATE_BUFFER;
    274 
    275 	rv = acpi_dsd_property(hdl, args->prop, &buf, acpitype, &propval);
    276 	if (!ACPI_SUCCESS(rv)) {
    277 		if (rv == AE_TYPE) {
    278 			error = EFTYPE;
    279 			goto out;
    280 		}
    281 		error = ENOENT;
    282 		goto out;
    283 	}
    284 
    285 	args->encoding = _LITTLE_ENDIAN; /* ACPI is always little-endian */
    286 	if (! acpi_type_to_prop(propval->Type, &args->type)) {
    287 		error = EFTYPE;
    288 		goto out;
    289 	}
    290 
    291 	switch (propval->Type) {
    292 	case ACPI_TYPE_INTEGER:
    293 		args->propsize = sizeof(propval->Integer.Value);
    294 		if (args->buf != NULL) {
    295 			/*
    296 			 * We don't have a native boolean type, but we
    297 			 * can test for zero and equate that to false.
    298 			 */
    299 			if (args->reqtype == PROP_TYPE_BOOL) {
    300 				KASSERT(args->buflen == sizeof(bool));
    301 				*(bool *)args->buf =
    302 				    propval->Integer.Value != 0;
    303 				goto out;
    304 			}
    305 			/*
    306 			 * DATA requests the ANY type (so that it can
    307 			 * get STRINGs, too), so filter out non-NUMBER.
    308 			 */
    309 			if (args->reqtype != PROP_TYPE_NUMBER) {
    310 				error = EFTYPE;
    311 				goto out;
    312 			}
    313 			KASSERT(args->buflen == sizeof(uint64_t));
    314 			*(uint64_t *)args->buf =
    315 			    le64toh(propval->Integer.Value);
    316 		}
    317 		break;
    318 
    319 	case ACPI_TYPE_STRING:
    320 		/* +1 for trailing NUL */
    321 		args->propsize = propval->String.Length + 1;
    322 		if (args->buf != NULL) {
    323 			if (args->buflen < args->propsize) {
    324 				error = EFBIG;
    325 				goto out;
    326 			}
    327 			strlcpy(args->buf, propval->String.Pointer,
    328 			    args->buflen);
    329 		}
    330 		break;
    331 
    332 	case ACPI_TYPE_BUFFER:
    333 		args->propsize = propval->Buffer.Length;
    334 		if (args->buf != NULL) {
    335 			if (args->buflen < args->propsize) {
    336 				error = EFBIG;
    337 				goto out;
    338 			}
    339 			memcpy(args->buf, propval->Buffer.Pointer,
    340 			    args->propsize);
    341 		}
    342 		break;
    343 
    344 	default:
    345 		error = EFTYPE;
    346 		goto out;
    347 	}
    348 
    349  out:
    350 	if (buf.Pointer != NULL) {
    351 		ACPI_FREE(buf.Pointer);
    352 	}
    353 	return error;
    354 }
    355 ACPI_DEVICE_CALL_REGISTER(DEVICE_GET_PROPERTY_STR,
    356 			  acpi_device_get_property)
    357 
    358 /*
    359  * Evaluate an integer object.
    360  */
    361 ACPI_STATUS
    362 acpi_eval_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER *valp)
    363 {
    364 	ACPI_OBJECT obj;
    365 	ACPI_BUFFER buf;
    366 	ACPI_STATUS rv;
    367 
    368 	if (handle == NULL)
    369 		handle = ACPI_ROOT_OBJECT;
    370 
    371 	(void)memset(&obj, 0, sizeof(obj));
    372 	buf.Pointer = &obj;
    373 	buf.Length = sizeof(obj);
    374 
    375 	rv = AcpiEvaluateObject(handle, path, NULL, &buf);
    376 
    377 	if (ACPI_FAILURE(rv))
    378 		return rv;
    379 
    380 	/* Check that evaluation produced a return value. */
    381 	if (buf.Length == 0)
    382 		return AE_NULL_OBJECT;
    383 
    384 	if (obj.Type != ACPI_TYPE_INTEGER)
    385 		return AE_TYPE;
    386 
    387 	if (valp != NULL)
    388 		*valp = obj.Integer.Value;
    389 
    390 	return AE_OK;
    391 }
    392 
    393 /*
    394  * Evaluate an integer object with a single integer input parameter.
    395  */
    396 ACPI_STATUS
    397 acpi_eval_set_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER val)
    398 {
    399 	ACPI_OBJECT_LIST arg;
    400 	ACPI_OBJECT obj;
    401 
    402 	if (handle == NULL)
    403 		handle = ACPI_ROOT_OBJECT;
    404 
    405 	obj.Type = ACPI_TYPE_INTEGER;
    406 	obj.Integer.Value = val;
    407 
    408 	arg.Count = 1;
    409 	arg.Pointer = &obj;
    410 
    411 	return AcpiEvaluateObject(handle, path, &arg, NULL);
    412 }
    413 
    414 /*
    415  * Evaluate a (Unicode) string object.
    416  */
    417 ACPI_STATUS
    418 acpi_eval_string(ACPI_HANDLE handle, const char *path, char **stringp)
    419 {
    420 	ACPI_OBJECT *obj;
    421 	ACPI_BUFFER buf;
    422 	ACPI_STATUS rv;
    423 
    424 	rv = acpi_eval_struct(handle, path, &buf);
    425 
    426 	if (ACPI_FAILURE(rv))
    427 		return rv;
    428 
    429 	obj = buf.Pointer;
    430 
    431 	if (obj->Type != ACPI_TYPE_STRING) {
    432 		rv = AE_TYPE;
    433 		goto out;
    434 	}
    435 
    436 	if (obj->String.Length == 0) {
    437 		rv = AE_BAD_DATA;
    438 		goto out;
    439 	}
    440 
    441 	*stringp = ACPI_ALLOCATE(obj->String.Length + 1);
    442 
    443 	if (*stringp == NULL) {
    444 		rv = AE_NO_MEMORY;
    445 		goto out;
    446 	}
    447 
    448 	(void)memcpy(*stringp, obj->String.Pointer, obj->String.Length);
    449 
    450 	(*stringp)[obj->String.Length] = '\0';
    451 
    452 out:
    453 	ACPI_FREE(buf.Pointer);
    454 
    455 	return rv;
    456 }
    457 
    458 /*
    459  * Evaluate a structure. Caller must free buf.Pointer by ACPI_FREE().
    460  */
    461 ACPI_STATUS
    462 acpi_eval_struct(ACPI_HANDLE handle, const char *path, ACPI_BUFFER *buf)
    463 {
    464 
    465 	if (handle == NULL)
    466 		handle = ACPI_ROOT_OBJECT;
    467 
    468 	buf->Pointer = NULL;
    469 	buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    470 
    471 	return AcpiEvaluateObject(handle, path, NULL, buf);
    472 }
    473 
    474 /*
    475  * Evaluate a reference handle from an element in a package.
    476  */
    477 ACPI_STATUS
    478 acpi_eval_reference_handle(ACPI_OBJECT *elm, ACPI_HANDLE *handle)
    479 {
    480 
    481 	if (elm == NULL || handle == NULL)
    482 		return AE_BAD_PARAMETER;
    483 
    484 	switch (elm->Type) {
    485 
    486 	case ACPI_TYPE_ANY:
    487 	case ACPI_TYPE_LOCAL_REFERENCE:
    488 
    489 		if (elm->Reference.Handle == NULL)
    490 			return AE_NULL_ENTRY;
    491 
    492 		*handle = elm->Reference.Handle;
    493 
    494 		return AE_OK;
    495 
    496 	case ACPI_TYPE_STRING:
    497 		return AcpiGetHandle(NULL, elm->String.Pointer, handle);
    498 
    499 	default:
    500 		return AE_TYPE;
    501 	}
    502 }
    503 
    504 /*
    505  * Iterate over all objects in a package, and pass them all
    506  * to a function. If the called function returns non-AE_OK,
    507  * the iteration is stopped and that value is returned.
    508  */
    509 ACPI_STATUS
    510 acpi_foreach_package_object(ACPI_OBJECT *pkg,
    511     ACPI_STATUS (*func)(ACPI_OBJECT *, void *), void *arg)
    512 {
    513 	ACPI_STATUS rv = AE_OK;
    514 	uint32_t i;
    515 
    516 	if (pkg == NULL)
    517 		return AE_BAD_PARAMETER;
    518 
    519 	if (pkg->Type != ACPI_TYPE_PACKAGE)
    520 		return AE_TYPE;
    521 
    522 	for (i = 0; i < pkg->Package.Count; i++) {
    523 
    524 		rv = (*func)(&pkg->Package.Elements[i], arg);
    525 
    526 		if (ACPI_FAILURE(rv))
    527 			break;
    528 	}
    529 
    530 	return rv;
    531 }
    532 
    533 /*
    534  * Fetch data info the specified (empty) ACPI buffer.
    535  * Caller must free buf.Pointer by ACPI_FREE().
    536  */
    537 ACPI_STATUS
    538 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf,
    539     ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *))
    540 {
    541 
    542 	buf->Pointer = NULL;
    543 	buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    544 
    545 	return (*getit)(handle, buf);
    546 }
    547 
    548 /*
    549  * Return a complete pathname from a handle.
    550  *
    551  * Note that the function uses static data storage;
    552  * if the data is needed for future use, it should be
    553  * copied before any subsequent calls overwrite it.
    554  */
    555 const char *
    556 acpi_name(ACPI_HANDLE handle)
    557 {
    558 	static char name[80];
    559 	ACPI_BUFFER buf;
    560 	ACPI_STATUS rv;
    561 
    562 	if (handle == NULL)
    563 		handle = ACPI_ROOT_OBJECT;
    564 
    565 	buf.Pointer = name;
    566 	buf.Length = sizeof(name);
    567 
    568 	rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf);
    569 
    570 	if (ACPI_FAILURE(rv))
    571 		return "UNKNOWN";
    572 
    573 	return name;
    574 }
    575 
    576 /*
    577  * Pack _HID and _CID ID strings into an OpenFirmware-style
    578  * string list.
    579  */
    580 char *
    581 acpi_pack_compat_list(struct acpi_devnode *ad, size_t *sizep)
    582 {
    583 	ACPI_DEVICE_INFO *devinfo = ad->ad_devinfo;
    584 
    585 	KASSERT(sizep != NULL);
    586 
    587 	char *sl = NULL;
    588 	size_t slsize = 0;
    589 	uint32_t i;
    590 	bool dtlink = false;
    591 
    592 	ACPI_BUFFER buf;
    593 	ACPI_STATUS ret;
    594 	ACPI_OBJECT *obj;
    595 	char *compatible;
    596 	int n;
    597 
    598 	buf.Pointer = NULL;
    599 	buf.Length = ACPI_ALLOCATE_BUFFER;
    600 
    601 	if ((devinfo->Valid & ACPI_VALID_HID) != 0) {
    602 		const char *cp = devinfo->HardwareId.String;
    603 
    604 		if (device_compatible_pmatch_strlist(cp, strlen(cp) + 1,
    605 						     dtlink_compat_data)) {
    606 			dtlink = true;
    607 		} else {
    608 			strlist_append(&sl, &slsize, cp);
    609 		}
    610 	}
    611 
    612 	if ((devinfo->Valid & ACPI_VALID_CID) != 0) {
    613 		for (i = 0; i < devinfo->CompatibleIdList.Count; i++) {
    614 			const char *cp =
    615 			    devinfo->CompatibleIdList.Ids[i].String;
    616 
    617 			if (device_compatible_pmatch_strlist(cp, strlen(cp) + 1,
    618 							dtlink_compat_data)) {
    619 				dtlink = true;
    620 			} else {
    621 				strlist_append(&sl, &slsize, cp);
    622 			}
    623 		}
    624 	}
    625 
    626 	if (dtlink) {
    627 		ret = acpi_dsd_string(ad->ad_handle, "compatible",
    628 		    &compatible);
    629 		if (ACPI_SUCCESS(ret)) {
    630 			strlist_append(&sl, &slsize, compatible);
    631 			kmem_strfree(compatible);
    632 			goto done;
    633 		}
    634 
    635 		ret = acpi_dsd_property(ad->ad_handle, "compatible", &buf,
    636 		    ACPI_TYPE_PACKAGE, &obj);
    637 		if (ACPI_FAILURE(ret)) {
    638 			goto done;
    639 		}
    640 		if (obj->Package.Count == 0) {
    641 			goto done;
    642 		}
    643 		for (n = 0; n < obj->Package.Count; n++) {
    644 			if (obj->Package.Elements[n].Type != ACPI_TYPE_STRING) {
    645 				continue;
    646 			}
    647 			strlist_append(&sl, &slsize,
    648 			    obj->Package.Elements[n].String.Pointer);
    649 		}
    650 	}
    651 
    652  done:
    653 	if (buf.Pointer != NULL) {
    654 		ACPI_FREE(buf.Pointer);
    655 	}
    656 	*sizep = slsize;
    657 	return sl;
    658 }
    659 
    660 /*
    661  * The ACPI_PNP_DEVICE_ID type is somewhat inconvenient for us to
    662  * use.  We'll need some temporary space to pack it into an array
    663  * of C strings.  Room for 8 should be plenty, but we can allocate
    664  * more if necessary.
    665  */
    666 #define	ACPI_COMPATSTR_MAX	8
    667 
    668 static const char **
    669 acpi_compatible_alloc_strarray(ACPI_PNP_DEVICE_ID *ids,
    670     unsigned int count, const char **buf)
    671 {
    672 	unsigned int i;
    673 
    674 	buf = kmem_tmpbuf_alloc(count * sizeof(const char *),
    675 	    buf, ACPI_COMPATSTR_MAX * sizeof(const char *), KM_SLEEP);
    676 	for (i = 0; i < count; i++) {
    677 		buf[i] = ids[i].String;
    678 	}
    679 	return buf;
    680 }
    681 
    682 static void
    683 acpi_compatible_free_strarray(const char **cpp, unsigned int count,
    684     const char **buf)
    685 {
    686 	kmem_tmpbuf_free(cpp, count * sizeof(const char *), buf);
    687 }
    688 
    689 static int
    690 acpi_compatible_match_dtlink(const struct acpi_attach_args * const aa,
    691     const struct device_compatible_entry * const dce)
    692 {
    693 	const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)];
    694 	ACPI_HANDLE handle = aa->aa_node->ad_handle;
    695 	ACPI_BUFFER buf;
    696 	char *compatible;
    697 	ACPI_STATUS ret;
    698 	ACPI_OBJECT *obj;
    699 	int rv = 0, n;
    700 
    701 	buf.Pointer = NULL;
    702 	buf.Length = ACPI_ALLOCATE_BUFFER;
    703 
    704 	/* Match a single string _DSD value */
    705 	ret = acpi_dsd_string(handle, "compatible", &compatible);
    706 	if (ACPI_SUCCESS(ret)) {
    707 		strings[0] = compatible;
    708 		rv = device_compatible_pmatch(strings, 1, dce);
    709 		kmem_strfree(compatible);
    710 		goto done;
    711 	}
    712 
    713 	/* Match from a list of strings in a _DSD value */
    714 	ret = acpi_dsd_property(handle, "compatible", &buf,
    715 	    ACPI_TYPE_PACKAGE, &obj);
    716 	if (ACPI_FAILURE(ret)) {
    717 		goto done;
    718 	}
    719 	if (obj->Package.Count == 0) {
    720 		goto done;
    721 	}
    722 	for (n = 0; n < imin(obj->Package.Count, ACPI_COMPATSTR_MAX); n++) {
    723 		if (obj->Package.Elements[n].Type != ACPI_TYPE_STRING) {
    724 			goto done;
    725 		}
    726 		strings[n] = obj->Package.Elements[n].String.Pointer;
    727 	}
    728 	rv = device_compatible_pmatch(strings, n, dce);
    729 
    730 done:
    731 	if (buf.Pointer != NULL) {
    732 		ACPI_FREE(buf.Pointer);
    733 	}
    734 	if (rv) {
    735 		rv = (rv - 1) + ACPI_MATCHSCORE_CID;
    736 		return imin(rv, ACPI_MATCHSCORE_CID_MAX);
    737 	}
    738 	return 0;
    739 }
    740 
    741 /*
    742  * acpi_compatible_match --
    743  *
    744  *	Returns a weighted match value, comparing the _HID and _CID
    745  *	IDs against a driver's compatibility data.
    746  */
    747 int
    748 acpi_compatible_match(const struct acpi_attach_args * const aa,
    749     const struct device_compatible_entry * const dce)
    750 {
    751 	const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)];
    752 	const char **cpp;
    753 	bool dtlink = false;
    754 	int rv;
    755 
    756 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
    757 		return 0;
    758 	}
    759 
    760 	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
    761 
    762 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
    763 		strings[0] = ad->HardwareId.String;
    764 
    765 		/* Matching _HID wins big. */
    766 		if (device_compatible_pmatch(strings, 1, dce) != 0) {
    767 			return ACPI_MATCHSCORE_HID;
    768 		}
    769 
    770 		if (device_compatible_pmatch(strings, 1,
    771 					     dtlink_compat_data) != 0) {
    772 			dtlink = true;
    773 		}
    774 	}
    775 
    776 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
    777 		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
    778 		    ad->CompatibleIdList.Count, strings);
    779 
    780 		rv = device_compatible_pmatch(cpp,
    781 		    ad->CompatibleIdList.Count, dce);
    782 		if (!dtlink &&
    783 		    device_compatible_pmatch(cpp, ad->CompatibleIdList.Count,
    784 					     dtlink_compat_data) != 0) {
    785 			dtlink = true;
    786 		}
    787 		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
    788 		    strings);
    789 		if (rv) {
    790 			rv = (rv - 1) + ACPI_MATCHSCORE_CID;
    791 			return imin(rv, ACPI_MATCHSCORE_CID_MAX);
    792 		}
    793 	}
    794 
    795 	if (dtlink) {
    796 		return acpi_compatible_match_dtlink(aa, dce);
    797 	}
    798 
    799 	return 0;
    800 }
    801 
    802 /*
    803  * acpi_compatible_lookup --
    804  *
    805  *	Returns the device_compatible_entry that matches the _HID
    806  *	or _CID ID.
    807  */
    808 const struct device_compatible_entry *
    809 acpi_compatible_lookup(const struct acpi_attach_args * const aa,
    810     const struct device_compatible_entry * const dce)
    811 {
    812 	const struct device_compatible_entry *rv = NULL;
    813 	const char *strings[ACPI_COMPATSTR_MAX];
    814 	const char **cpp;
    815 
    816 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
    817 		return NULL;
    818 	}
    819 
    820 	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
    821 
    822 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
    823 		strings[0] = ad->HardwareId.String;
    824 
    825 		rv = device_compatible_plookup(strings, 1, dce);
    826 		if (rv != NULL)
    827 			return rv;
    828 	}
    829 
    830 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
    831 		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
    832 		    ad->CompatibleIdList.Count, strings);
    833 
    834 		rv = device_compatible_plookup(cpp,
    835 		    ad->CompatibleIdList.Count, dce);
    836 		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
    837 		    strings);
    838 	}
    839 
    840 	return rv;
    841 }
    842 
    843 /*
    844  * Match given IDs against _HID and _CIDs.
    845  */
    846 int
    847 acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids)
    848 {
    849 	uint32_t i, n;
    850 	char *id;
    851 
    852 	while (*ids) {
    853 
    854 		if ((ad->Valid & ACPI_VALID_HID) != 0) {
    855 
    856 			if (pmatch(ad->HardwareId.String, *ids, NULL) == 2)
    857 				return 1;
    858 		}
    859 
    860 		if ((ad->Valid & ACPI_VALID_CID) != 0) {
    861 
    862 			n = ad->CompatibleIdList.Count;
    863 
    864 			for (i = 0; i < n; i++) {
    865 
    866 				id = ad->CompatibleIdList.Ids[i].String;
    867 
    868 				if (pmatch(id, *ids, NULL) == 2)
    869 					return 1;
    870 			}
    871 		}
    872 
    873 		ids++;
    874 	}
    875 
    876 	return 0;
    877 }
    878 
    879 /*
    880  * Match a PCI-defined bass-class, sub-class, and programming interface
    881  * against a handle's _CLS object.
    882  */
    883 int
    884 acpi_match_class(ACPI_HANDLE handle, uint8_t pci_class, uint8_t pci_subclass,
    885     uint8_t pci_interface)
    886 {
    887 	ACPI_BUFFER buf;
    888 	ACPI_OBJECT *obj;
    889 	ACPI_STATUS rv;
    890 	int match = 0;
    891 
    892 	rv = acpi_eval_struct(handle, "_CLS", &buf);
    893 	if (ACPI_FAILURE(rv))
    894 		goto done;
    895 
    896 	obj = buf.Pointer;
    897 	if (obj->Type != ACPI_TYPE_PACKAGE)
    898 		goto done;
    899 	if (obj->Package.Count != 3)
    900 		goto done;
    901 	if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
    902 	    obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER ||
    903 	    obj->Package.Elements[2].Type != ACPI_TYPE_INTEGER)
    904 		goto done;
    905 
    906 	match = obj->Package.Elements[0].Integer.Value == pci_class &&
    907 		obj->Package.Elements[1].Integer.Value == pci_subclass &&
    908 		obj->Package.Elements[2].Integer.Value == pci_interface;
    909 
    910 done:
    911 	if (buf.Pointer)
    912 		ACPI_FREE(buf.Pointer);
    913 	return match ? ACPI_MATCHSCORE_CLS : 0;
    914 }
    915 
    916 /*
    917  * Match a device node from a handle.
    918  */
    919 struct acpi_devnode *
    920 acpi_match_node(ACPI_HANDLE handle)
    921 {
    922 	struct acpi_devnode *ad;
    923 	ACPI_STATUS rv;
    924 
    925 	if (handle == NULL)
    926 		return NULL;
    927 
    928 	rv = AcpiGetData(handle, acpi_clean_node, (void **)&ad);
    929 
    930 	if (ACPI_FAILURE(rv))
    931 		return NULL;
    932 
    933 	return ad;
    934 }
    935 
    936 /*
    937  * Permanently associate a device node with a handle.
    938  */
    939 void
    940 acpi_match_node_init(struct acpi_devnode *ad)
    941 {
    942 	(void)AcpiAttachData(ad->ad_handle, acpi_clean_node, ad);
    943 }
    944 
    945 static void
    946 acpi_clean_node(ACPI_HANDLE handle, void *aux)
    947 {
    948 	/* Nothing. */
    949 }
    950 
    951 /*
    952  * Match a handle from a cpu_info. Returns NULL on failure.
    953  *
    954  * Note that acpi_match_node() can be used if the device node
    955  * is also required.
    956  */
    957 ACPI_HANDLE
    958 acpi_match_cpu_info(struct cpu_info *ci)
    959 {
    960 	struct acpi_softc *sc = acpi_softc;
    961 	struct acpi_devnode *ad;
    962 	ACPI_INTEGER val;
    963 	ACPI_OBJECT *obj;
    964 	ACPI_BUFFER buf;
    965 	ACPI_HANDLE hdl;
    966 	ACPI_STATUS rv;
    967 
    968 	if (sc == NULL)
    969 		return NULL;
    970 
    971 	/*
    972 	 * CPUs are declared in the ACPI namespace
    973 	 * either as a Processor() or as a Device().
    974 	 * In both cases the MADT entries are used
    975 	 * for the match (see ACPI 4.0, section 8.4).
    976 	 */
    977 	SIMPLEQ_FOREACH(ad, &sc->sc_head, ad_list) {
    978 
    979 		hdl = ad->ad_handle;
    980 
    981 		switch (ad->ad_type) {
    982 
    983 		case ACPI_TYPE_DEVICE:
    984 
    985 			if (acpi_match_hid(ad->ad_devinfo, acpicpu_ids) == 0)
    986 				break;
    987 
    988 			rv = acpi_eval_integer(hdl, "_UID", &val);
    989 
    990 			if (ACPI_SUCCESS(rv) && val == ci->ci_acpiid)
    991 				return hdl;
    992 
    993 			break;
    994 
    995 		case ACPI_TYPE_PROCESSOR:
    996 
    997 			rv = acpi_eval_struct(hdl, NULL, &buf);
    998 
    999 			if (ACPI_FAILURE(rv))
   1000 				break;
   1001 
   1002 			obj = buf.Pointer;
   1003 
   1004 			if (obj->Processor.ProcId == ci->ci_acpiid) {
   1005 				ACPI_FREE(buf.Pointer);
   1006 				return hdl;
   1007 			}
   1008 
   1009 			ACPI_FREE(buf.Pointer);
   1010 			break;
   1011 		}
   1012 	}
   1013 
   1014 	return NULL;
   1015 }
   1016 
   1017 /*
   1018  * Match a CPU from a handle. Returns NULL on failure.
   1019  */
   1020 struct cpu_info *
   1021 acpi_match_cpu_handle(ACPI_HANDLE hdl)
   1022 {
   1023 	struct cpu_info *ci;
   1024 	ACPI_DEVICE_INFO *di;
   1025 	CPU_INFO_ITERATOR cii;
   1026 	ACPI_INTEGER val;
   1027 	ACPI_OBJECT *obj;
   1028 	ACPI_BUFFER buf;
   1029 	ACPI_STATUS rv;
   1030 
   1031 	ci = NULL;
   1032 	di = NULL;
   1033 	buf.Pointer = NULL;
   1034 
   1035 	rv = AcpiGetObjectInfo(hdl, &di);
   1036 
   1037 	if (ACPI_FAILURE(rv))
   1038 		return NULL;
   1039 
   1040 	switch (di->Type) {
   1041 
   1042 	case ACPI_TYPE_DEVICE:
   1043 
   1044 		if (acpi_match_hid(di, acpicpu_ids) == 0)
   1045 			goto out;
   1046 
   1047 		rv = acpi_eval_integer(hdl, "_UID", &val);
   1048 
   1049 		if (ACPI_FAILURE(rv))
   1050 			goto out;
   1051 
   1052 		break;
   1053 
   1054 	case ACPI_TYPE_PROCESSOR:
   1055 
   1056 		rv = acpi_eval_struct(hdl, NULL, &buf);
   1057 
   1058 		if (ACPI_FAILURE(rv))
   1059 			goto out;
   1060 
   1061 		obj = buf.Pointer;
   1062 		val = obj->Processor.ProcId;
   1063 		break;
   1064 
   1065 	default:
   1066 		goto out;
   1067 	}
   1068 
   1069 	for (CPU_INFO_FOREACH(cii, ci)) {
   1070 
   1071 		if (ci->ci_acpiid == val)
   1072 			goto out;
   1073 	}
   1074 
   1075 	ci = NULL;
   1076 
   1077 out:
   1078 	if (di != NULL)
   1079 		ACPI_FREE(di);
   1080 
   1081 	if (buf.Pointer != NULL)
   1082 		ACPI_FREE(buf.Pointer);
   1083 
   1084 	return ci;
   1085 }
   1086 
   1087 struct acpi_irq_handler {
   1088 	uint32_t aih_irq;
   1089 	void *aih_ih;
   1090 };
   1091 
   1092 void *
   1093 acpi_intr_establish(device_t dev, uint64_t c, int ipl, bool mpsafe,
   1094     int (*intr)(void *), void *iarg, const char *xname)
   1095 {
   1096 	ACPI_STATUS rv;
   1097 	ACPI_HANDLE hdl = (void *)(uintptr_t)c;
   1098 	struct acpi_resources res;
   1099 	struct acpi_irq *irq;
   1100 	void *aih = NULL;
   1101 
   1102 	rv = acpi_resource_parse(dev, hdl, "_CRS", &res,
   1103 	    &acpi_resource_parse_ops_quiet);
   1104 	if (ACPI_FAILURE(rv))
   1105 		return NULL;
   1106 
   1107 	irq = acpi_res_irq(&res, 0);
   1108 	if (irq == NULL)
   1109 		goto end;
   1110 
   1111 	aih = acpi_intr_establish_irq(dev, irq, ipl, mpsafe,
   1112 	    intr, iarg, xname);
   1113 
   1114 end:
   1115 	acpi_resource_cleanup(&res);
   1116 
   1117 	return aih;
   1118 }
   1119 
   1120 void *
   1121 acpi_intr_establish_irq(device_t dev, struct acpi_irq *irq, int ipl,
   1122     bool mpsafe, int (*intr)(void *), void *iarg, const char *xname)
   1123 {
   1124 	struct acpi_irq_handler *aih;
   1125 	void *ih;
   1126 
   1127 	const int type = (irq->ar_type == ACPI_EDGE_SENSITIVE) ? IST_EDGE : IST_LEVEL;
   1128 	ih = acpi_md_intr_establish(irq->ar_irq, ipl, type, intr, iarg, mpsafe, xname);
   1129 	if (ih == NULL)
   1130 		return NULL;
   1131 
   1132 	aih = kmem_alloc(sizeof(struct acpi_irq_handler), KM_SLEEP);
   1133 	aih->aih_irq = irq->ar_irq;
   1134 	aih->aih_ih = ih;
   1135 
   1136 	return aih;
   1137 }
   1138 
   1139 void
   1140 acpi_intr_mask(void *c)
   1141 {
   1142 	struct acpi_irq_handler * const aih = c;
   1143 
   1144 	acpi_md_intr_mask(aih->aih_ih);
   1145 }
   1146 
   1147 void
   1148 acpi_intr_unmask(void *c)
   1149 {
   1150 	struct acpi_irq_handler * const aih = c;
   1151 
   1152 	acpi_md_intr_unmask(aih->aih_ih);
   1153 }
   1154 
   1155 void
   1156 acpi_intr_disestablish(void *c)
   1157 {
   1158 	struct acpi_irq_handler *aih = c;
   1159 
   1160 	acpi_md_intr_disestablish(aih->aih_ih);
   1161 	kmem_free(aih, sizeof(struct acpi_irq_handler));
   1162 }
   1163 
   1164 const char *
   1165 acpi_intr_string(void *c, char *buf, size_t size)
   1166 {
   1167 	struct acpi_irq_handler *aih = c;
   1168 	intr_handle_t ih = aih->aih_irq;
   1169 
   1170 	return intr_string(ih, buf, size);
   1171 }
   1172 
   1173 /*
   1174  * Device-Specific Data (_DSD) support
   1175  */
   1176 
   1177 static UINT8 acpi_dsd_uuid[ACPI_UUID_LENGTH] = {
   1178 	0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
   1179 	0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
   1180 };
   1181 
   1182 static ACPI_STATUS
   1183 acpi_dsd_property(ACPI_HANDLE handle, const char *prop, ACPI_BUFFER *pbuf, ACPI_OBJECT_TYPE type, ACPI_OBJECT **ret)
   1184 {
   1185 	ACPI_OBJECT *obj, *uuid, *props, *pobj, *propkey, *propval;
   1186 	ACPI_STATUS rv;
   1187 	int n;
   1188 
   1189 	rv = AcpiEvaluateObjectTyped(handle, "_DSD", NULL, pbuf, ACPI_TYPE_PACKAGE);
   1190 	if (ACPI_FAILURE(rv))
   1191 		return rv;
   1192 
   1193 	props = NULL;
   1194 	obj = (ACPI_OBJECT *)pbuf->Pointer;
   1195 	for (n = 0; (n + 1) < obj->Package.Count; n += 2) {
   1196 		uuid = &obj->Package.Elements[n];
   1197 		if (uuid->Buffer.Length == ACPI_UUID_LENGTH &&
   1198 		    memcmp(uuid->Buffer.Pointer, acpi_dsd_uuid, ACPI_UUID_LENGTH) == 0) {
   1199 			props = &obj->Package.Elements[n + 1];
   1200 			break;
   1201 		}
   1202 	}
   1203 	if (props == NULL)
   1204 		return AE_NOT_FOUND;
   1205 
   1206 	for (n = 0; n < props->Package.Count; n++) {
   1207 		pobj = &props->Package.Elements[n];
   1208 		if (pobj->Type != ACPI_TYPE_PACKAGE || pobj->Package.Count != 2)
   1209 			continue;
   1210 		propkey = (ACPI_OBJECT *)&pobj->Package.Elements[0];
   1211 		propval = (ACPI_OBJECT *)&pobj->Package.Elements[1];
   1212 		if (propkey->Type != ACPI_TYPE_STRING)
   1213 			continue;
   1214 		if (strcmp(propkey->String.Pointer, prop) != 0)
   1215 			continue;
   1216 
   1217 		if (type != ACPI_TYPE_ANY && propval->Type != type) {
   1218 			return AE_TYPE;
   1219 		} else {
   1220 			*ret = propval;
   1221 			return AE_OK;
   1222 		}
   1223 		break;
   1224 	}
   1225 
   1226 	return AE_NOT_FOUND;
   1227 }
   1228 
   1229 ACPI_STATUS
   1230 acpi_dsd_integer(ACPI_HANDLE handle, const char *prop, ACPI_INTEGER *val)
   1231 {
   1232 	ACPI_OBJECT *propval;
   1233 	ACPI_STATUS rv;
   1234 	ACPI_BUFFER buf;
   1235 
   1236 	buf.Pointer = NULL;
   1237 	buf.Length = ACPI_ALLOCATE_BUFFER;
   1238 
   1239 	rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_INTEGER, &propval);
   1240 	if (ACPI_SUCCESS(rv))
   1241 		*val = propval->Integer.Value;
   1242 
   1243 	if (buf.Pointer != NULL)
   1244 		ACPI_FREE(buf.Pointer);
   1245 	return rv;
   1246 }
   1247 
   1248 ACPI_STATUS
   1249 acpi_dsd_string(ACPI_HANDLE handle, const char *prop, char **val)
   1250 {
   1251 	ACPI_OBJECT *propval;
   1252 	ACPI_STATUS rv;
   1253 	ACPI_BUFFER buf;
   1254 
   1255 	buf.Pointer = NULL;
   1256 	buf.Length = ACPI_ALLOCATE_BUFFER;
   1257 
   1258 	rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_STRING, &propval);
   1259 	if (ACPI_SUCCESS(rv))
   1260 		*val = kmem_strdup(propval->String.Pointer, KM_SLEEP);
   1261 
   1262 	if (buf.Pointer != NULL)
   1263 		ACPI_FREE(buf.Pointer);
   1264 	return rv;
   1265 }
   1266 
   1267 ACPI_STATUS
   1268 acpi_dsd_bool(ACPI_HANDLE handle, const char *prop, bool *val)
   1269 {
   1270 	ACPI_STATUS rv;
   1271 	ACPI_INTEGER ival;
   1272 
   1273 	rv = acpi_dsd_integer(handle, prop, &ival);
   1274 	if (ACPI_SUCCESS(rv)) {
   1275 		*val = ival != 0;
   1276 	}
   1277 
   1278 	return rv;
   1279 }
   1280 
   1281 
   1282 /*
   1283  * Device Specific Method (_DSM) support
   1284  */
   1285 
   1286 ACPI_STATUS
   1287 acpi_dsm_typed(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
   1288     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT_TYPE return_type,
   1289     ACPI_OBJECT **return_obj)
   1290 {
   1291 	ACPI_OBJECT_LIST arg;
   1292 	ACPI_OBJECT obj[4];
   1293 	ACPI_BUFFER buf;
   1294 	ACPI_STATUS status;
   1295 
   1296 	arg.Count = 4;
   1297 	arg.Pointer = obj;
   1298 
   1299 	obj[0].Type = ACPI_TYPE_BUFFER;
   1300 	obj[0].Buffer.Length = ACPI_UUID_LENGTH;
   1301 	obj[0].Buffer.Pointer = uuid;
   1302 
   1303 	obj[1].Type = ACPI_TYPE_INTEGER;
   1304 	obj[1].Integer.Value = rev;
   1305 
   1306 	obj[2].Type = ACPI_TYPE_INTEGER;
   1307 	obj[2].Integer.Value = func;
   1308 
   1309 	if (arg3 != NULL) {
   1310 		obj[3] = *arg3;
   1311 	} else {
   1312 		obj[3].Type = ACPI_TYPE_PACKAGE;
   1313 		obj[3].Package.Count = 0;
   1314 		obj[3].Package.Elements = NULL;
   1315 	}
   1316 
   1317 	buf.Pointer = NULL;
   1318 	buf.Length = ACPI_ALLOCATE_BUFFER;
   1319 
   1320 	if (return_obj == NULL && return_type == ACPI_TYPE_ANY) {
   1321 		status = AcpiEvaluateObject(handle, "_DSM", &arg, NULL);
   1322 	} else {
   1323 		*return_obj = NULL;
   1324 		status = AcpiEvaluateObjectTyped(handle, "_DSM", &arg, &buf,
   1325 		    return_type);
   1326 	}
   1327 	if (ACPI_FAILURE(status)) {
   1328 		return status;
   1329 	}
   1330 	if (return_obj != NULL) {
   1331 		*return_obj = buf.Pointer;
   1332 	} else if (buf.Pointer != NULL) {
   1333 		ACPI_FREE(buf.Pointer);
   1334 	}
   1335 	return AE_OK;
   1336 }
   1337 
   1338 ACPI_STATUS
   1339 acpi_dsm_integer(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
   1340     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_INTEGER *ret)
   1341 {
   1342 	ACPI_OBJECT *obj;
   1343 	ACPI_STATUS status;
   1344 
   1345 	status = acpi_dsm_typed(handle, uuid, rev, func, arg3,
   1346 	    ACPI_TYPE_INTEGER, &obj);
   1347 	if (ACPI_FAILURE(status)) {
   1348 		return status;
   1349 	}
   1350 
   1351 	*ret = obj->Integer.Value;
   1352 	ACPI_FREE(obj);
   1353 
   1354 	return AE_OK;
   1355 }
   1356 
   1357 ACPI_STATUS
   1358 acpi_dsm(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
   1359     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT **return_obj)
   1360 {
   1361 	return acpi_dsm_typed(handle, uuid, rev, func, arg3, ACPI_TYPE_ANY,
   1362 	    return_obj);
   1363 }
   1364 
   1365 ACPI_STATUS
   1366 acpi_dsm_query(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
   1367     ACPI_INTEGER *ret)
   1368 {
   1369 	ACPI_OBJECT *obj;
   1370 	ACPI_STATUS status;
   1371 	uint8_t *data;
   1372 	u_int n;
   1373 
   1374 	status = acpi_dsm(handle, uuid, rev, 0, NULL, &obj);
   1375 	if (ACPI_FAILURE(status)) {
   1376 		return status;
   1377 	}
   1378 
   1379 	if (obj->Type == ACPI_TYPE_INTEGER) {
   1380 		*ret = obj->Integer.Value;
   1381 	} else if (obj->Type == ACPI_TYPE_BUFFER &&
   1382 		   obj->Buffer.Length <= 8) {
   1383 		*ret = 0;
   1384 		data = (uint8_t *)obj->Buffer.Pointer;
   1385 		for (n = 0; n < obj->Buffer.Length; n++) {
   1386 			*ret |= (uint64_t)data[n] << (n * 8);
   1387 		}
   1388 	} else {
   1389 		status = AE_TYPE;
   1390 	}
   1391 
   1392 	ACPI_FREE(obj);
   1393 
   1394 	return status;
   1395 }
   1396 
   1397 ACPI_STATUS
   1398 acpi_claim_childdevs(device_t dev, struct acpi_devnode *devnode,
   1399     const char *method)
   1400 {
   1401 	struct acpi_devnode *ad;
   1402 
   1403 	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
   1404 		if (ad->ad_device != NULL)
   1405 			continue;
   1406 
   1407 		if (method != NULL) {
   1408 			ACPI_HANDLE h;
   1409 			ACPI_STATUS rv;
   1410 
   1411 			rv = AcpiGetHandle(ad->ad_handle, method, &h);
   1412 			if (ACPI_FAILURE(rv)) {
   1413 				continue;
   1414 			}
   1415 		}
   1416 
   1417 		aprint_debug_dev(dev, "claiming %s\n",
   1418 		    acpi_name(ad->ad_handle));
   1419 		ad->ad_device = dev;
   1420 		acpi_claim_childdevs(dev, ad, method);
   1421 	}
   1422 
   1423 	return AE_OK;
   1424 }
   1425