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