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