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