Home | History | Annotate | Line # | Download | only in acpi
acpi_util.c revision 1.25
      1 /*	$NetBSD: acpi_util.c,v 1.25 2021/08/09 20:49:09 andvar 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.25 2021/08/09 20:49:09 andvar 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 <machine/acpi_machdep.h>
     79 
     80 #define _COMPONENT	ACPI_BUS_COMPONENT
     81 ACPI_MODULE_NAME	("acpi_util")
     82 
     83 static void		acpi_clean_node(ACPI_HANDLE, void *);
     84 
     85 static const char * const acpicpu_ids[] = {
     86 	"ACPI0007",
     87 	NULL
     88 };
     89 
     90 /*
     91  * ACPI device handle support.
     92  */
     93 
     94 static device_call_t
     95 acpi_devhandle_lookup_device_call(devhandle_t handle, const char *name,
     96     devhandle_t *call_handlep)
     97 {
     98 	__link_set_decl(acpi_device_calls, struct device_call_descriptor);
     99 	struct device_call_descriptor * const *desc;
    100 
    101 	__link_set_foreach(desc, acpi_device_calls) {
    102 		if (strcmp((*desc)->name, name) == 0) {
    103 			return (*desc)->call;
    104 		}
    105 	}
    106 	return NULL;
    107 }
    108 
    109 static const struct devhandle_impl acpi_devhandle_impl = {
    110 	.type = DEVHANDLE_TYPE_ACPI,
    111 	.lookup_device_call = acpi_devhandle_lookup_device_call,
    112 };
    113 
    114 devhandle_t
    115 devhandle_from_acpi(ACPI_HANDLE const hdl)
    116 {
    117 	devhandle_t handle = {
    118 		.impl = &acpi_devhandle_impl,
    119 		.pointer = hdl,
    120 	};
    121 
    122 	return handle;
    123 }
    124 
    125 ACPI_HANDLE
    126 devhandle_to_acpi(devhandle_t const handle)
    127 {
    128 	KASSERT(devhandle_type(handle) == DEVHANDLE_TYPE_ACPI);
    129 
    130 	return handle.pointer;
    131 }
    132 
    133 static int
    134 acpi_device_enumerate_children(device_t dev, devhandle_t call_handle, void *v)
    135 {
    136 	struct device_enumerate_children_args *args = v;
    137 	ACPI_HANDLE hdl = devhandle_to_acpi(call_handle);
    138 	struct acpi_devnode *devnode, *ad;
    139 
    140 	devnode = acpi_match_node(hdl);
    141 	KASSERT(devnode != NULL);
    142 
    143 	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
    144 		if (ad->ad_devinfo->Type != ACPI_TYPE_DEVICE ||
    145 		    !acpi_device_present(ad->ad_handle)) {
    146 			continue;
    147 		}
    148 		if (!args->callback(dev, devhandle_from_acpi(ad->ad_handle),
    149 				    args->callback_arg)) {
    150 			break;
    151 		}
    152 	}
    153 
    154 	return 0;
    155 }
    156 ACPI_DEVICE_CALL_REGISTER("device-enumerate-children",
    157 			  acpi_device_enumerate_children)
    158 
    159 /*
    160  * Evaluate an integer object.
    161  */
    162 ACPI_STATUS
    163 acpi_eval_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER *valp)
    164 {
    165 	ACPI_OBJECT obj;
    166 	ACPI_BUFFER buf;
    167 	ACPI_STATUS rv;
    168 
    169 	if (handle == NULL)
    170 		handle = ACPI_ROOT_OBJECT;
    171 
    172 	(void)memset(&obj, 0, sizeof(obj));
    173 	buf.Pointer = &obj;
    174 	buf.Length = sizeof(obj);
    175 
    176 	rv = AcpiEvaluateObject(handle, path, NULL, &buf);
    177 
    178 	if (ACPI_FAILURE(rv))
    179 		return rv;
    180 
    181 	/* Check that evaluation produced a return value. */
    182 	if (buf.Length == 0)
    183 		return AE_NULL_OBJECT;
    184 
    185 	if (obj.Type != ACPI_TYPE_INTEGER)
    186 		return AE_TYPE;
    187 
    188 	if (valp != NULL)
    189 		*valp = obj.Integer.Value;
    190 
    191 	return AE_OK;
    192 }
    193 
    194 /*
    195  * Evaluate an integer object with a single integer input parameter.
    196  */
    197 ACPI_STATUS
    198 acpi_eval_set_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER val)
    199 {
    200 	ACPI_OBJECT_LIST arg;
    201 	ACPI_OBJECT obj;
    202 
    203 	if (handle == NULL)
    204 		handle = ACPI_ROOT_OBJECT;
    205 
    206 	obj.Type = ACPI_TYPE_INTEGER;
    207 	obj.Integer.Value = val;
    208 
    209 	arg.Count = 1;
    210 	arg.Pointer = &obj;
    211 
    212 	return AcpiEvaluateObject(handle, path, &arg, NULL);
    213 }
    214 
    215 /*
    216  * Evaluate a (Unicode) string object.
    217  */
    218 ACPI_STATUS
    219 acpi_eval_string(ACPI_HANDLE handle, const char *path, char **stringp)
    220 {
    221 	ACPI_OBJECT *obj;
    222 	ACPI_BUFFER buf;
    223 	ACPI_STATUS rv;
    224 
    225 	rv = acpi_eval_struct(handle, path, &buf);
    226 
    227 	if (ACPI_FAILURE(rv))
    228 		return rv;
    229 
    230 	obj = buf.Pointer;
    231 
    232 	if (obj->Type != ACPI_TYPE_STRING) {
    233 		rv = AE_TYPE;
    234 		goto out;
    235 	}
    236 
    237 	if (obj->String.Length == 0) {
    238 		rv = AE_BAD_DATA;
    239 		goto out;
    240 	}
    241 
    242 	*stringp = ACPI_ALLOCATE(obj->String.Length + 1);
    243 
    244 	if (*stringp == NULL) {
    245 		rv = AE_NO_MEMORY;
    246 		goto out;
    247 	}
    248 
    249 	(void)memcpy(*stringp, obj->String.Pointer, obj->String.Length);
    250 
    251 	(*stringp)[obj->String.Length] = '\0';
    252 
    253 out:
    254 	ACPI_FREE(buf.Pointer);
    255 
    256 	return rv;
    257 }
    258 
    259 /*
    260  * Evaluate a structure. Caller must free buf.Pointer by ACPI_FREE().
    261  */
    262 ACPI_STATUS
    263 acpi_eval_struct(ACPI_HANDLE handle, const char *path, ACPI_BUFFER *buf)
    264 {
    265 
    266 	if (handle == NULL)
    267 		handle = ACPI_ROOT_OBJECT;
    268 
    269 	buf->Pointer = NULL;
    270 	buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    271 
    272 	return AcpiEvaluateObject(handle, path, NULL, buf);
    273 }
    274 
    275 /*
    276  * Evaluate a reference handle from an element in a package.
    277  */
    278 ACPI_STATUS
    279 acpi_eval_reference_handle(ACPI_OBJECT *elm, ACPI_HANDLE *handle)
    280 {
    281 
    282 	if (elm == NULL || handle == NULL)
    283 		return AE_BAD_PARAMETER;
    284 
    285 	switch (elm->Type) {
    286 
    287 	case ACPI_TYPE_ANY:
    288 	case ACPI_TYPE_LOCAL_REFERENCE:
    289 
    290 		if (elm->Reference.Handle == NULL)
    291 			return AE_NULL_ENTRY;
    292 
    293 		*handle = elm->Reference.Handle;
    294 
    295 		return AE_OK;
    296 
    297 	case ACPI_TYPE_STRING:
    298 		return AcpiGetHandle(NULL, elm->String.Pointer, handle);
    299 
    300 	default:
    301 		return AE_TYPE;
    302 	}
    303 }
    304 
    305 /*
    306  * Iterate over all objects in a package, and pass them all
    307  * to a function. If the called function returns non-AE_OK,
    308  * the iteration is stopped and that value is returned.
    309  */
    310 ACPI_STATUS
    311 acpi_foreach_package_object(ACPI_OBJECT *pkg,
    312     ACPI_STATUS (*func)(ACPI_OBJECT *, void *), void *arg)
    313 {
    314 	ACPI_STATUS rv = AE_OK;
    315 	uint32_t i;
    316 
    317 	if (pkg == NULL)
    318 		return AE_BAD_PARAMETER;
    319 
    320 	if (pkg->Type != ACPI_TYPE_PACKAGE)
    321 		return AE_TYPE;
    322 
    323 	for (i = 0; i < pkg->Package.Count; i++) {
    324 
    325 		rv = (*func)(&pkg->Package.Elements[i], arg);
    326 
    327 		if (ACPI_FAILURE(rv))
    328 			break;
    329 	}
    330 
    331 	return rv;
    332 }
    333 
    334 /*
    335  * Fetch data info the specified (empty) ACPI buffer.
    336  * Caller must free buf.Pointer by ACPI_FREE().
    337  */
    338 ACPI_STATUS
    339 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf,
    340     ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *))
    341 {
    342 
    343 	buf->Pointer = NULL;
    344 	buf->Length = ACPI_ALLOCATE_LOCAL_BUFFER;
    345 
    346 	return (*getit)(handle, buf);
    347 }
    348 
    349 /*
    350  * Return a complete pathname from a handle.
    351  *
    352  * Note that the function uses static data storage;
    353  * if the data is needed for future use, it should be
    354  * copied before any subsequent calls overwrite it.
    355  */
    356 const char *
    357 acpi_name(ACPI_HANDLE handle)
    358 {
    359 	static char name[80];
    360 	ACPI_BUFFER buf;
    361 	ACPI_STATUS rv;
    362 
    363 	if (handle == NULL)
    364 		handle = ACPI_ROOT_OBJECT;
    365 
    366 	buf.Pointer = name;
    367 	buf.Length = sizeof(name);
    368 
    369 	rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf);
    370 
    371 	if (ACPI_FAILURE(rv))
    372 		return "UNKNOWN";
    373 
    374 	return name;
    375 }
    376 
    377 /*
    378  * Pack _HID and _CID ID strings into an OpenFirmware-style
    379  * string list.
    380  */
    381 char *
    382 acpi_pack_compat_list(ACPI_DEVICE_INFO *ad, size_t *sizep)
    383 {
    384 	KASSERT(sizep != NULL);
    385 
    386 	char *sl = NULL;
    387 	size_t slsize = 0;
    388 	uint32_t i;
    389 
    390 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
    391 		strlist_append(&sl, &slsize, ad->HardwareId.String);
    392 	}
    393 
    394 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
    395 		for (i = 0; i < ad->CompatibleIdList.Count; i++) {
    396 			strlist_append(&sl, &slsize,
    397 			    ad->CompatibleIdList.Ids[i].String);
    398 		}
    399 	}
    400 
    401 	*sizep = slsize;
    402 	return sl;
    403 }
    404 
    405 /*
    406  * The ACPI_PNP_DEVICE_ID type is somewhat inconvenient for us to
    407  * use.  We'll need some temporary space to pack it into an array
    408  * of C strings.  Room for 8 should be plenty, but we can allocate
    409  * more if necessary.
    410  */
    411 #define	ACPI_COMPATSTR_MAX	8
    412 
    413 static const char **
    414 acpi_compatible_alloc_strarray(ACPI_PNP_DEVICE_ID *ids,
    415     unsigned int count, const char **buf)
    416 {
    417 	unsigned int i;
    418 
    419 	buf = kmem_tmpbuf_alloc(count * sizeof(const char *),
    420 	    buf, ACPI_COMPATSTR_MAX * sizeof(const char *), KM_SLEEP);
    421 	for (i = 0; i < count; i++) {
    422 		buf[i] = ids[i].String;
    423 	}
    424 	return buf;
    425 }
    426 
    427 static void
    428 acpi_compatible_free_strarray(const char **cpp, unsigned int count,
    429     const char **buf)
    430 {
    431 	kmem_tmpbuf_free(cpp, count * sizeof(const char *), buf);
    432 }
    433 
    434 /*
    435  * acpi_compatible_match --
    436  *
    437  *	Returns a weighted match value, comparing the _HID and _CID
    438  *	IDs against a driver's compatibility data.
    439  */
    440 int
    441 acpi_compatible_match(const struct acpi_attach_args * const aa,
    442     const struct device_compatible_entry * const dce)
    443 {
    444 	const char *strings[ACPI_COMPATSTR_MAX * sizeof(const char *)];
    445 	const char **cpp;
    446 
    447 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
    448 		return 0;
    449 	}
    450 
    451 	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
    452 
    453 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
    454 		strings[0] = ad->HardwareId.String;
    455 
    456 		/* Matching _HID wins big. */
    457 		if (device_compatible_pmatch(strings, 1, dce) != 0) {
    458 			return ACPI_MATCHSCORE_HID;
    459 		}
    460 	}
    461 
    462 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
    463 		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
    464 		    ad->CompatibleIdList.Count, strings);
    465 		int rv;
    466 
    467 		rv = device_compatible_pmatch(cpp,
    468 		    ad->CompatibleIdList.Count, dce);
    469 		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
    470 		    strings);
    471 		if (rv) {
    472 			rv = (rv - 1) + ACPI_MATCHSCORE_CID;
    473 			if (rv > ACPI_MATCHSCORE_CID_MAX) {
    474 				rv = ACPI_MATCHSCORE_CID_MAX;
    475 			}
    476 			return rv;
    477 		}
    478 	}
    479 
    480 	return 0;
    481 }
    482 
    483 /*
    484  * acpi_compatible_lookup --
    485  *
    486  *	Returns the device_compatible_entry that matches the _HID
    487  *	or _CID ID.
    488  */
    489 const struct device_compatible_entry *
    490 acpi_compatible_lookup(const struct acpi_attach_args * const aa,
    491     const struct device_compatible_entry * const dce)
    492 {
    493 	const struct device_compatible_entry *rv = NULL;
    494 	const char *strings[ACPI_COMPATSTR_MAX];
    495 	const char **cpp;
    496 
    497 	if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
    498 		return NULL;
    499 	}
    500 
    501 	ACPI_DEVICE_INFO *ad = aa->aa_node->ad_devinfo;
    502 
    503 	if ((ad->Valid & ACPI_VALID_HID) != 0) {
    504 		strings[0] = ad->HardwareId.String;
    505 
    506 		rv = device_compatible_plookup(strings, 1, dce);
    507 		if (rv != NULL)
    508 			return rv;
    509 	}
    510 
    511 	if ((ad->Valid & ACPI_VALID_CID) != 0) {
    512 		cpp = acpi_compatible_alloc_strarray(ad->CompatibleIdList.Ids,
    513 		    ad->CompatibleIdList.Count, strings);
    514 
    515 		rv = device_compatible_plookup(cpp,
    516 		    ad->CompatibleIdList.Count, dce);
    517 		acpi_compatible_free_strarray(cpp, ad->CompatibleIdList.Count,
    518 		    strings);
    519 	}
    520 
    521 	return rv;
    522 }
    523 
    524 /*
    525  * Match given IDs against _HID and _CIDs.
    526  */
    527 int
    528 acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids)
    529 {
    530 	uint32_t i, n;
    531 	char *id;
    532 
    533 	while (*ids) {
    534 
    535 		if ((ad->Valid & ACPI_VALID_HID) != 0) {
    536 
    537 			if (pmatch(ad->HardwareId.String, *ids, NULL) == 2)
    538 				return 1;
    539 		}
    540 
    541 		if ((ad->Valid & ACPI_VALID_CID) != 0) {
    542 
    543 			n = ad->CompatibleIdList.Count;
    544 
    545 			for (i = 0; i < n; i++) {
    546 
    547 				id = ad->CompatibleIdList.Ids[i].String;
    548 
    549 				if (pmatch(id, *ids, NULL) == 2)
    550 					return 1;
    551 			}
    552 		}
    553 
    554 		ids++;
    555 	}
    556 
    557 	return 0;
    558 }
    559 
    560 /*
    561  * Match a PCI-defined bass-class, sub-class, and programming interface
    562  * against a handle's _CLS object.
    563  */
    564 int
    565 acpi_match_class(ACPI_HANDLE handle, uint8_t pci_class, uint8_t pci_subclass,
    566     uint8_t pci_interface)
    567 {
    568 	ACPI_BUFFER buf;
    569 	ACPI_OBJECT *obj;
    570 	ACPI_STATUS rv;
    571 	int match = 0;
    572 
    573 	rv = acpi_eval_struct(handle, "_CLS", &buf);
    574 	if (ACPI_FAILURE(rv))
    575 		goto done;
    576 
    577 	obj = buf.Pointer;
    578 	if (obj->Type != ACPI_TYPE_PACKAGE)
    579 		goto done;
    580 	if (obj->Package.Count != 3)
    581 		goto done;
    582 	if (obj->Package.Elements[0].Type != ACPI_TYPE_INTEGER ||
    583 	    obj->Package.Elements[1].Type != ACPI_TYPE_INTEGER ||
    584 	    obj->Package.Elements[2].Type != ACPI_TYPE_INTEGER)
    585 		goto done;
    586 
    587 	match = obj->Package.Elements[0].Integer.Value == pci_class &&
    588 		obj->Package.Elements[1].Integer.Value == pci_subclass &&
    589 		obj->Package.Elements[2].Integer.Value == pci_interface;
    590 
    591 done:
    592 	if (buf.Pointer)
    593 		ACPI_FREE(buf.Pointer);
    594 	return match ? ACPI_MATCHSCORE_CLS : 0;
    595 }
    596 
    597 /*
    598  * Match a device node from a handle.
    599  */
    600 struct acpi_devnode *
    601 acpi_match_node(ACPI_HANDLE handle)
    602 {
    603 	struct acpi_devnode *ad;
    604 	ACPI_STATUS rv;
    605 
    606 	if (handle == NULL)
    607 		return NULL;
    608 
    609 	rv = AcpiGetData(handle, acpi_clean_node, (void **)&ad);
    610 
    611 	if (ACPI_FAILURE(rv))
    612 		return NULL;
    613 
    614 	return ad;
    615 }
    616 
    617 /*
    618  * Permanently associate a device node with a handle.
    619  */
    620 void
    621 acpi_match_node_init(struct acpi_devnode *ad)
    622 {
    623 	(void)AcpiAttachData(ad->ad_handle, acpi_clean_node, ad);
    624 }
    625 
    626 static void
    627 acpi_clean_node(ACPI_HANDLE handle, void *aux)
    628 {
    629 	/* Nothing. */
    630 }
    631 
    632 /*
    633  * Match a handle from a cpu_info. Returns NULL on failure.
    634  *
    635  * Note that acpi_match_node() can be used if the device node
    636  * is also required.
    637  */
    638 ACPI_HANDLE
    639 acpi_match_cpu_info(struct cpu_info *ci)
    640 {
    641 	struct acpi_softc *sc = acpi_softc;
    642 	struct acpi_devnode *ad;
    643 	ACPI_INTEGER val;
    644 	ACPI_OBJECT *obj;
    645 	ACPI_BUFFER buf;
    646 	ACPI_HANDLE hdl;
    647 	ACPI_STATUS rv;
    648 
    649 	if (sc == NULL || acpi_active == 0)
    650 		return NULL;
    651 
    652 	/*
    653 	 * CPUs are declared in the ACPI namespace
    654 	 * either as a Processor() or as a Device().
    655 	 * In both cases the MADT entries are used
    656 	 * for the match (see ACPI 4.0, section 8.4).
    657 	 */
    658 	SIMPLEQ_FOREACH(ad, &sc->ad_head, ad_list) {
    659 
    660 		hdl = ad->ad_handle;
    661 
    662 		switch (ad->ad_type) {
    663 
    664 		case ACPI_TYPE_DEVICE:
    665 
    666 			if (acpi_match_hid(ad->ad_devinfo, acpicpu_ids) == 0)
    667 				break;
    668 
    669 			rv = acpi_eval_integer(hdl, "_UID", &val);
    670 
    671 			if (ACPI_SUCCESS(rv) && val == ci->ci_acpiid)
    672 				return hdl;
    673 
    674 			break;
    675 
    676 		case ACPI_TYPE_PROCESSOR:
    677 
    678 			rv = acpi_eval_struct(hdl, NULL, &buf);
    679 
    680 			if (ACPI_FAILURE(rv))
    681 				break;
    682 
    683 			obj = buf.Pointer;
    684 
    685 			if (obj->Processor.ProcId == ci->ci_acpiid) {
    686 				ACPI_FREE(buf.Pointer);
    687 				return hdl;
    688 			}
    689 
    690 			ACPI_FREE(buf.Pointer);
    691 			break;
    692 		}
    693 	}
    694 
    695 	return NULL;
    696 }
    697 
    698 /*
    699  * Match a CPU from a handle. Returns NULL on failure.
    700  */
    701 struct cpu_info *
    702 acpi_match_cpu_handle(ACPI_HANDLE hdl)
    703 {
    704 	struct cpu_info *ci;
    705 	ACPI_DEVICE_INFO *di;
    706 	CPU_INFO_ITERATOR cii;
    707 	ACPI_INTEGER val;
    708 	ACPI_OBJECT *obj;
    709 	ACPI_BUFFER buf;
    710 	ACPI_STATUS rv;
    711 
    712 	ci = NULL;
    713 	di = NULL;
    714 	buf.Pointer = NULL;
    715 
    716 	rv = AcpiGetObjectInfo(hdl, &di);
    717 
    718 	if (ACPI_FAILURE(rv))
    719 		return NULL;
    720 
    721 	switch (di->Type) {
    722 
    723 	case ACPI_TYPE_DEVICE:
    724 
    725 		if (acpi_match_hid(di, acpicpu_ids) == 0)
    726 			goto out;
    727 
    728 		rv = acpi_eval_integer(hdl, "_UID", &val);
    729 
    730 		if (ACPI_FAILURE(rv))
    731 			goto out;
    732 
    733 		break;
    734 
    735 	case ACPI_TYPE_PROCESSOR:
    736 
    737 		rv = acpi_eval_struct(hdl, NULL, &buf);
    738 
    739 		if (ACPI_FAILURE(rv))
    740 			goto out;
    741 
    742 		obj = buf.Pointer;
    743 		val = obj->Processor.ProcId;
    744 		break;
    745 
    746 	default:
    747 		goto out;
    748 	}
    749 
    750 	for (CPU_INFO_FOREACH(cii, ci)) {
    751 
    752 		if (ci->ci_acpiid == val)
    753 			goto out;
    754 	}
    755 
    756 	ci = NULL;
    757 
    758 out:
    759 	if (di != NULL)
    760 		ACPI_FREE(di);
    761 
    762 	if (buf.Pointer != NULL)
    763 		ACPI_FREE(buf.Pointer);
    764 
    765 	return ci;
    766 }
    767 
    768 struct acpi_irq_handler {
    769 	uint32_t aih_irq;
    770 	void *aih_ih;
    771 };
    772 
    773 void *
    774 acpi_intr_establish(device_t dev, uint64_t c, int ipl, bool mpsafe,
    775     int (*intr)(void *), void *iarg, const char *xname)
    776 {
    777 	ACPI_STATUS rv;
    778 	ACPI_HANDLE hdl = (void *)(uintptr_t)c;
    779 	struct acpi_resources res;
    780 	struct acpi_irq *irq;
    781 	void *aih = NULL;
    782 
    783 	rv = acpi_resource_parse(dev, hdl, "_CRS", &res,
    784 	    &acpi_resource_parse_ops_quiet);
    785 	if (ACPI_FAILURE(rv))
    786 		return NULL;
    787 
    788 	irq = acpi_res_irq(&res, 0);
    789 	if (irq == NULL)
    790 		goto end;
    791 
    792 	aih = acpi_intr_establish_irq(dev, irq, ipl, mpsafe,
    793 	    intr, iarg, xname);
    794 
    795 end:
    796 	acpi_resource_cleanup(&res);
    797 
    798 	return aih;
    799 }
    800 
    801 void *
    802 acpi_intr_establish_irq(device_t dev, struct acpi_irq *irq, int ipl,
    803     bool mpsafe, int (*intr)(void *), void *iarg, const char *xname)
    804 {
    805 	struct acpi_irq_handler *aih;
    806 	void *ih;
    807 
    808 	const int type = (irq->ar_type == ACPI_EDGE_SENSITIVE) ? IST_EDGE : IST_LEVEL;
    809 	ih = acpi_md_intr_establish(irq->ar_irq, ipl, type, intr, iarg, mpsafe, xname);
    810 	if (ih == NULL)
    811 		return NULL;
    812 
    813 	aih = kmem_alloc(sizeof(struct acpi_irq_handler), KM_SLEEP);
    814 	aih->aih_irq = irq->ar_irq;
    815 	aih->aih_ih = ih;
    816 
    817 	return aih;
    818 }
    819 
    820 void
    821 acpi_intr_mask(void *c)
    822 {
    823 	struct acpi_irq_handler * const aih = c;
    824 
    825 	acpi_md_intr_mask(aih->aih_ih);
    826 }
    827 
    828 void
    829 acpi_intr_unmask(void *c)
    830 {
    831 	struct acpi_irq_handler * const aih = c;
    832 
    833 	acpi_md_intr_unmask(aih->aih_ih);
    834 }
    835 
    836 void
    837 acpi_intr_disestablish(void *c)
    838 {
    839 	struct acpi_irq_handler *aih = c;
    840 
    841 	acpi_md_intr_disestablish(aih->aih_ih);
    842 	kmem_free(aih, sizeof(struct acpi_irq_handler));
    843 }
    844 
    845 const char *
    846 acpi_intr_string(void *c, char *buf, size_t size)
    847 {
    848 	struct acpi_irq_handler *aih = c;
    849 	intr_handle_t ih = aih->aih_irq;
    850 
    851 	return intr_string(ih, buf, size);
    852 }
    853 
    854 /*
    855  * Device-Specific Data (_DSD) support
    856  */
    857 
    858 static UINT8 acpi_dsd_uuid[ACPI_UUID_LENGTH] = {
    859 	0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
    860 	0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
    861 };
    862 
    863 static ACPI_STATUS
    864 acpi_dsd_property(ACPI_HANDLE handle, const char *prop, ACPI_BUFFER *pbuf, ACPI_OBJECT_TYPE type, ACPI_OBJECT **ret)
    865 {
    866 	ACPI_OBJECT *obj, *uuid, *props, *pobj, *propkey, *propval;
    867 	ACPI_STATUS rv;
    868 	int n;
    869 
    870 	rv = AcpiEvaluateObjectTyped(handle, "_DSD", NULL, pbuf, ACPI_TYPE_PACKAGE);
    871 	if (ACPI_FAILURE(rv))
    872 		return rv;
    873 
    874 	props = NULL;
    875 	obj = (ACPI_OBJECT *)pbuf->Pointer;
    876 	for (n = 0; (n + 1) < obj->Package.Count; n += 2) {
    877 		uuid = &obj->Package.Elements[n];
    878 		if (uuid->Buffer.Length == ACPI_UUID_LENGTH &&
    879 		    memcmp(uuid->Buffer.Pointer, acpi_dsd_uuid, ACPI_UUID_LENGTH) == 0) {
    880 			props = &obj->Package.Elements[n + 1];
    881 			break;
    882 		}
    883 	}
    884 	if (props == NULL)
    885 		return AE_NOT_FOUND;
    886 
    887 	for (n = 0; n < props->Package.Count; n++) {
    888 		pobj = &props->Package.Elements[n];
    889 		if (pobj->Type != ACPI_TYPE_PACKAGE || pobj->Package.Count != 2)
    890 			continue;
    891 		propkey = (ACPI_OBJECT *)&pobj->Package.Elements[0];
    892 		propval = (ACPI_OBJECT *)&pobj->Package.Elements[1];
    893 		if (propkey->Type != ACPI_TYPE_STRING)
    894 			continue;
    895 		if (strcmp(propkey->String.Pointer, prop) != 0)
    896 			continue;
    897 
    898 		if (propval->Type != type) {
    899 			return AE_TYPE;
    900 		} else {
    901 			*ret = propval;
    902 			return AE_OK;
    903 		}
    904 		break;
    905 	}
    906 
    907 	return AE_NOT_FOUND;
    908 }
    909 
    910 ACPI_STATUS
    911 acpi_dsd_integer(ACPI_HANDLE handle, const char *prop, ACPI_INTEGER *val)
    912 {
    913 	ACPI_OBJECT *propval;
    914 	ACPI_STATUS rv;
    915 	ACPI_BUFFER buf;
    916 
    917 	buf.Pointer = NULL;
    918 	buf.Length = ACPI_ALLOCATE_BUFFER;
    919 
    920 	rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_INTEGER, &propval);
    921 	if (ACPI_SUCCESS(rv))
    922 		*val = propval->Integer.Value;
    923 
    924 	if (buf.Pointer != NULL)
    925 		ACPI_FREE(buf.Pointer);
    926 	return rv;
    927 }
    928 
    929 ACPI_STATUS
    930 acpi_dsd_string(ACPI_HANDLE handle, const char *prop, char **val)
    931 {
    932 	ACPI_OBJECT *propval;
    933 	ACPI_STATUS rv;
    934 	ACPI_BUFFER buf;
    935 
    936 	buf.Pointer = NULL;
    937 	buf.Length = ACPI_ALLOCATE_BUFFER;
    938 
    939 	rv = acpi_dsd_property(handle, prop, &buf, ACPI_TYPE_STRING, &propval);
    940 	if (ACPI_SUCCESS(rv))
    941 		*val = kmem_strdup(propval->String.Pointer, KM_SLEEP);
    942 
    943 	if (buf.Pointer != NULL)
    944 		ACPI_FREE(buf.Pointer);
    945 	return rv;
    946 }
    947 
    948 /*
    949  * Device Specific Method (_DSM) support
    950  */
    951 
    952 ACPI_STATUS
    953 acpi_dsm_typed(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
    954     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT_TYPE return_type,
    955     ACPI_OBJECT **return_obj)
    956 {
    957 	ACPI_OBJECT_LIST arg;
    958 	ACPI_OBJECT obj[4];
    959 	ACPI_BUFFER buf;
    960 	ACPI_STATUS status;
    961 
    962 	arg.Count = 4;
    963 	arg.Pointer = obj;
    964 
    965 	obj[0].Type = ACPI_TYPE_BUFFER;
    966 	obj[0].Buffer.Length = ACPI_UUID_LENGTH;
    967 	obj[0].Buffer.Pointer = uuid;
    968 
    969 	obj[1].Type = ACPI_TYPE_INTEGER;
    970 	obj[1].Integer.Value = rev;
    971 
    972 	obj[2].Type = ACPI_TYPE_INTEGER;
    973 	obj[2].Integer.Value = func;
    974 
    975 	if (arg3 != NULL) {
    976 		obj[3] = *arg3;
    977 	} else {
    978 		obj[3].Type = ACPI_TYPE_PACKAGE;
    979 		obj[3].Package.Count = 0;
    980 		obj[3].Package.Elements = NULL;
    981 	}
    982 
    983 	buf.Pointer = NULL;
    984 	buf.Length = ACPI_ALLOCATE_BUFFER;
    985 
    986 	if (return_obj == NULL && return_type == ACPI_TYPE_ANY) {
    987 		status = AcpiEvaluateObject(handle, "_DSM", &arg, NULL);
    988 	} else {
    989 		*return_obj = NULL;
    990 		status = AcpiEvaluateObjectTyped(handle, "_DSM", &arg, &buf,
    991 		    return_type);
    992 	}
    993 	if (ACPI_FAILURE(status)) {
    994 		return status;
    995 	}
    996 	if (return_obj != NULL) {
    997 		*return_obj = buf.Pointer;
    998 	} else if (buf.Pointer != NULL) {
    999 		ACPI_FREE(buf.Pointer);
   1000 	}
   1001 	return AE_OK;
   1002 }
   1003 
   1004 ACPI_STATUS
   1005 acpi_dsm_integer(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
   1006     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_INTEGER *ret)
   1007 {
   1008 	ACPI_OBJECT *obj;
   1009 	ACPI_STATUS status;
   1010 
   1011 	status = acpi_dsm_typed(handle, uuid, rev, func, arg3,
   1012 	    ACPI_TYPE_INTEGER, &obj);
   1013 	if (ACPI_FAILURE(status)) {
   1014 		return status;
   1015 	}
   1016 
   1017 	*ret = obj->Integer.Value;
   1018 	ACPI_FREE(obj);
   1019 
   1020 	return AE_OK;
   1021 }
   1022 
   1023 ACPI_STATUS
   1024 acpi_dsm(ACPI_HANDLE handle, uint8_t *uuid, ACPI_INTEGER rev,
   1025     ACPI_INTEGER func, const ACPI_OBJECT *arg3, ACPI_OBJECT **return_obj)
   1026 {
   1027 	return acpi_dsm_typed(handle, uuid, rev, func, arg3, ACPI_TYPE_ANY,
   1028 	    return_obj);
   1029 }
   1030 
   1031 ACPI_STATUS
   1032 acpi_claim_childdevs(device_t dev, struct acpi_devnode *devnode)
   1033 {
   1034 	struct acpi_devnode *ad;
   1035 
   1036 	SIMPLEQ_FOREACH(ad, &devnode->ad_child_head, ad_child_list) {
   1037 		if (ad->ad_device != NULL)
   1038 			continue;
   1039 		aprint_debug_dev(dev, "claiming %s\n",
   1040 		    acpi_name(ad->ad_handle));
   1041 		ad->ad_device = dev;
   1042 		acpi_claim_childdevs(dev, ad);
   1043 	}
   1044 
   1045 	return AE_OK;
   1046 }
   1047