1 /* $NetBSD: acpi.c,v 1.15 2002/07/29 03:26:20 augustss Exp $ */ 2 3 /* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Autoconfiguration support for the Intel ACPI Component Architecture 40 * ACPI reference implementation. 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.15 2002/07/29 03:26:20 augustss Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/device.h> 49 #include <sys/malloc.h> 50 51 #include <dev/acpi/acpica.h> 52 #include <dev/acpi/acpireg.h> 53 #include <dev/acpi/acpivar.h> 54 #include <dev/acpi/acpi_osd.h> 55 56 #ifndef ACPI_PCI_FIXUP 57 #define ACPI_PCI_FIXUP 1 58 #endif 59 60 #ifndef ACPI_ACTIVATE_DEV 61 #define ACPI_ACTIVATE_DEV 0 62 #endif 63 64 #if ACPI_PCI_FIXUP 65 #include <dev/acpi/acpica/Subsystem/acnamesp.h> /* AcpiNsGetNodeByPath() */ 66 #include <dev/pci/pcidevs.h> 67 #endif 68 69 #include <machine/acpi_machdep.h> 70 71 #ifdef ENABLE_DEBUGGER 72 #define ACPI_DBGR_INIT 0x01 73 #define ACPI_DBGR_TABLES 0x02 74 #define ACPI_DBGR_ENABLE 0x04 75 #define ACPI_DBGR_PROBE 0x08 76 #define ACPI_DBGR_RUNNING 0x10 77 78 int acpi_dbgr = 0x00; 79 #endif 80 81 int acpi_match(struct device *, struct cfdata *, void *); 82 void acpi_attach(struct device *, struct device *, void *); 83 84 int acpi_print(void *aux, const char *); 85 86 extern struct cfdriver acpi_cd; 87 88 struct cfattach acpi_ca = { 89 sizeof(struct acpi_softc), acpi_match, acpi_attach, 90 }; 91 92 /* 93 * This is a flag we set when the ACPI subsystem is active. Machine 94 * dependent code may wish to skip other steps (such as attaching 95 * subsystems that ACPI supercedes) when ACPI is active. 96 */ 97 int acpi_active; 98 99 /* 100 * Pointer to the ACPI subsystem's state. There can be only 101 * one ACPI instance. 102 */ 103 struct acpi_softc *acpi_softc; 104 105 void acpi_shutdown(void *); 106 ACPI_STATUS acpi_disable(struct acpi_softc *sc); 107 void acpi_build_tree(struct acpi_softc *); 108 ACPI_STATUS acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **); 109 110 void acpi_enable_fixed_events(struct acpi_softc *); 111 #if ACPI_PCI_FIXUP 112 void acpi_pci_fixup(struct acpi_softc *); 113 #endif 114 #if ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV 115 ACPI_STATUS acpi_allocate_resources(ACPI_HANDLE handle); 116 #endif 117 118 /* 119 * acpi_probe: 120 * 121 * Probe for ACPI support. This is called by the 122 * machine-dependent ACPI front-end. All of the 123 * actual work is done by ACPICA. 124 * 125 * NOTE: This is not an autoconfiguration interface function. 126 */ 127 int 128 acpi_probe(void) 129 { 130 static int beenhere; 131 ACPI_STATUS rv; 132 133 if (beenhere != 0) 134 panic("acpi_probe: ACPI has already been probed"); 135 beenhere = 1; 136 137 /* 138 * Start up ACPICA. 139 */ 140 #ifdef ENABLE_DEBUGGER 141 if (acpi_dbgr & ACPI_DBGR_INIT) 142 acpi_osd_debugger(); 143 #endif 144 145 rv = AcpiInitializeSubsystem(); 146 if (rv != AE_OK) { 147 printf("ACPI: unable to initialize ACPICA: %d\n", rv); 148 return (0); 149 } 150 151 #ifdef ENABLE_DEBUGGER 152 if (acpi_dbgr & ACPI_DBGR_TABLES) 153 acpi_osd_debugger(); 154 #endif 155 156 rv = AcpiLoadTables(); 157 if (rv != AE_OK) { 158 printf("ACPI: unable to load tables: %d\n", rv); 159 return (0); 160 } 161 162 /* 163 * Looks like we have ACPI! 164 */ 165 166 return (1); 167 } 168 169 /* 170 * acpi_match: 171 * 172 * Autoconfiguration `match' routine. 173 */ 174 int 175 acpi_match(struct device *parent, struct cfdata *match, void *aux) 176 { 177 struct acpibus_attach_args *aa = aux; 178 179 if (strcmp(aa->aa_busname, acpi_cd.cd_name) != 0) 180 return (0); 181 182 /* 183 * XXX Check other locators? Hard to know -- machine 184 * dependent code has already checked for the presence 185 * of ACPI by calling acpi_probe(), so I suppose we 186 * don't really have to do anything else. 187 */ 188 return (1); 189 } 190 191 /* 192 * acpi_attach: 193 * 194 * Autoconfiguration `attach' routine. Finish initializing 195 * ACPICA (some initialization was done in acpi_probe(), 196 * which was required to check for the presence of ACPI), 197 * and enable the ACPI subsystem. 198 */ 199 void 200 acpi_attach(struct device *parent, struct device *self, void *aux) 201 { 202 struct acpi_softc *sc = (void *) self; 203 struct acpibus_attach_args *aa = aux; 204 ACPI_STATUS rv; 205 206 printf("\n"); 207 208 if (acpi_softc != NULL) 209 panic("acpi_attach: ACPI has already been attached"); 210 211 sc->sc_iot = aa->aa_iot; 212 sc->sc_memt = aa->aa_memt; 213 sc->sc_pc = aa->aa_pc; 214 sc->sc_pciflags = aa->aa_pciflags; 215 216 acpi_softc = sc; 217 218 /* 219 * Install the default address space handlers. 220 */ 221 222 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 223 ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL); 224 if (rv != AE_OK) { 225 printf("%s: unable to install SYSTEM MEMORY handler: %d\n", 226 sc->sc_dev.dv_xname, rv); 227 return; 228 } 229 230 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 231 ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL); 232 if (rv != AE_OK) { 233 printf("%s: unable to install SYSTEM IO handler: %d\n", 234 sc->sc_dev.dv_xname, rv); 235 return; 236 } 237 238 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 239 ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); 240 if (rv != AE_OK) { 241 printf("%s: unable to install PCI CONFIG handler: %d\n", 242 sc->sc_dev.dv_xname, rv); 243 return; 244 } 245 246 /* 247 * Bring ACPI on-line. 248 * 249 * Note that we request that _STA (device init) and _INI (object init) 250 * methods not be run. 251 * 252 * XXX We need to arrange for the object init pass after we have 253 * XXX attached all of our children. 254 */ 255 #ifdef ENABLE_DEBUGGER 256 if (acpi_dbgr & ACPI_DBGR_ENABLE) 257 acpi_osd_debugger(); 258 #endif 259 rv = AcpiEnableSubsystem(ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT); 260 if (rv != AE_OK) { 261 printf("%s: unable to enable ACPI: %d\n", 262 sc->sc_dev.dv_xname, rv); 263 return; 264 } 265 acpi_active = 1; 266 267 /* 268 * Set up the default sleep state to enter when various 269 * switches are activated. 270 */ 271 sc->sc_switch_sleep[ACPI_SWITCH_POWERBUTTON] = ACPI_STATE_S5; 272 sc->sc_switch_sleep[ACPI_SWITCH_SLEEPBUTTON] = ACPI_STATE_S1; 273 sc->sc_switch_sleep[ACPI_SWITCH_LID] = ACPI_STATE_S1; 274 275 /* Our current state is "awake". */ 276 sc->sc_sleepstate = ACPI_STATE_S0; 277 278 /* Show SCI interrupt. */ 279 if (AcpiGbl_FADT != NULL) 280 printf("%s: SCI interrupting at irq %d\n", 281 sc->sc_dev.dv_xname, AcpiGbl_FADT->SciInt); 282 /* 283 * Check for fixed-hardware features. 284 */ 285 acpi_enable_fixed_events(sc); 286 287 /* 288 * Fix up PCI devices. 289 */ 290 #if ACPI_PCI_FIXUP 291 acpi_pci_fixup(sc); 292 #endif 293 294 /* 295 * Scan the namespace and build our device tree. 296 */ 297 #ifdef ENABLE_DEBUGGER 298 if (acpi_dbgr & ACPI_DBGR_PROBE) 299 acpi_osd_debugger(); 300 #endif 301 acpi_build_tree(sc); 302 303 /* 304 * Register a shutdown hook that disables certain ACPI 305 * events that might happen and confuse us while we're 306 * trying to shut down. 307 */ 308 sc->sc_sdhook = shutdownhook_establish(acpi_shutdown, sc); 309 if (sc->sc_sdhook == NULL) 310 printf("%s: WARNING: unable to register shutdown hook\n", 311 sc->sc_dev.dv_xname); 312 313 #ifdef ENABLE_DEBUGGER 314 if (acpi_dbgr & ACPI_DBGR_RUNNING) 315 acpi_osd_debugger(); 316 #endif 317 } 318 319 /* 320 * acpi_shutdown: 321 * 322 * Shutdown hook for ACPI -- disable some events that 323 * might confuse us. 324 */ 325 void 326 acpi_shutdown(void *arg) 327 { 328 struct acpi_softc *sc = arg; 329 330 if (acpi_disable(sc) != AE_OK) 331 printf("%s: WARNING: unable to disable ACPI\n", 332 sc->sc_dev.dv_xname); 333 } 334 335 /* 336 * acpi_disable: 337 * 338 * Disable ACPI. 339 */ 340 ACPI_STATUS 341 acpi_disable(struct acpi_softc *sc) 342 { 343 ACPI_STATUS rv = AE_OK; 344 345 if (acpi_active) { 346 rv = AcpiDisable(); 347 if (rv == AE_OK) 348 acpi_active = 0; 349 } 350 return (rv); 351 } 352 353 struct acpi_make_devnode_state { 354 struct acpi_softc *softc; 355 struct acpi_scope *scope; 356 }; 357 358 /* 359 * acpi_build_tree: 360 * 361 * Scan relevant portions of the ACPI namespace and attach 362 * child devices. 363 */ 364 void 365 acpi_build_tree(struct acpi_softc *sc) 366 { 367 static const char *scopes[] = { 368 "\\_PR_", /* ACPI 1.0 processor namespace */ 369 "\\_SB_", /* system bus namespace */ 370 "\\_SI_", /* system idicator namespace */ 371 "\\_TZ_", /* ACPI 1.0 thermal zone namespace */ 372 NULL, 373 }; 374 struct acpi_attach_args aa; 375 struct acpi_make_devnode_state state; 376 struct acpi_scope *as; 377 struct acpi_devnode *ad; 378 ACPI_HANDLE parent; 379 int i; 380 381 TAILQ_INIT(&sc->sc_scopes); 382 383 state.softc = sc; 384 385 /* 386 * Scan the namespace and build our tree. 387 */ 388 for (i = 0; scopes[i] != NULL; i++) { 389 as = malloc(sizeof(*as), M_DEVBUF, M_WAITOK); 390 as->as_name = scopes[i]; 391 TAILQ_INIT(&as->as_devnodes); 392 393 TAILQ_INSERT_TAIL(&sc->sc_scopes, as, as_list); 394 395 state.scope = as; 396 397 if (AcpiGetHandle(ACPI_ROOT_OBJECT, (char *) scopes[i], 398 &parent) == AE_OK) { 399 AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100, 400 acpi_make_devnode, &state, NULL); 401 } 402 403 /* Now, for this namespace, try and attach the devices. */ 404 TAILQ_FOREACH(ad, &as->as_devnodes, ad_list) { 405 aa.aa_node = ad; 406 aa.aa_iot = sc->sc_iot; 407 aa.aa_memt = sc->sc_memt; 408 aa.aa_pc = sc->sc_pc; 409 aa.aa_pciflags = sc->sc_pciflags; 410 411 /* 412 * XXX We only attach devices which are: 413 * 414 * - present 415 * - enabled 416 * - functioning properly 417 * 418 * However, if enabled, it's decoding resources, 419 * so we should claim them, if possible. Requires 420 * changes to bus_space(9). 421 */ 422 if ((ad->ad_devinfo.CurrentStatus & 423 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED| 424 ACPI_STA_DEV_OK)) != 425 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED| 426 ACPI_STA_DEV_OK)) 427 continue; 428 429 /* 430 * XXX Same problem as above... 431 */ 432 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0) 433 continue; 434 435 ad->ad_device = config_found(&sc->sc_dev, 436 &aa, acpi_print); 437 } 438 } 439 } 440 441 #if ACPI_ACTIVATE_DEV 442 static void 443 acpi_activate_device(ACPI_HANDLE handle, ACPI_DEVICE_INFO *di) 444 { 445 ACPI_STATUS rv; 446 447 #ifdef ACPI_DEBUG 448 printf("acpi_activate_device: %s, old status=%x\n", 449 di->HardwareId, di->CurrentStatus); 450 #endif 451 452 rv = acpi_allocate_resources(handle); 453 if (ACPI_FAILURE(rv)) { 454 printf("acpi: activate failed for %s\n", di->HardwareId); 455 } 456 457 (void)AcpiGetObjectInfo(handle, di); 458 #ifdef ACPI_DEBUG 459 printf("acpi_activate_device: %s, new status=%x\n", 460 di->HardwareId, di->CurrentStatus); 461 #endif 462 } 463 #endif /* ACPI_ACTIVATE_DEV */ 464 465 /* 466 * acpi_make_devnode: 467 * 468 * Make an ACPI devnode. 469 */ 470 ACPI_STATUS 471 acpi_make_devnode(ACPI_HANDLE handle, UINT32 level, void *context, 472 void **status) 473 { 474 struct acpi_make_devnode_state *state = context; 475 #ifdef ACPI_DEBUG 476 struct acpi_softc *sc = state->softc; 477 #endif 478 struct acpi_scope *as = state->scope; 479 struct acpi_devnode *ad; 480 ACPI_DEVICE_INFO devinfo; 481 ACPI_OBJECT_TYPE type; 482 ACPI_STATUS rv; 483 484 if (AcpiGetType(handle, &type) == AE_OK) { 485 rv = AcpiGetObjectInfo(handle, &devinfo); 486 if (rv != AE_OK) { 487 #ifdef ACPI_DEBUG 488 printf("%s: AcpiGetObjectInfo failed\n", 489 sc->sc_dev.dv_xname); 490 #endif 491 goto out; /* XXX why return OK */ 492 } 493 494 switch (type) { 495 case ACPI_TYPE_DEVICE: 496 #if ACPI_ACTIVATE_DEV 497 if ((devinfo.Valid & ACPI_VALID_STA) && 498 (devinfo.CurrentStatus & 499 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED)) == 500 ACPI_STA_DEV_PRESENT) 501 acpi_activate_device(handle, &devinfo); 502 /* FALLTHROUGH */ 503 #endif 504 505 case ACPI_TYPE_PROCESSOR: 506 case ACPI_TYPE_THERMAL: 507 case ACPI_TYPE_POWER: 508 ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT|M_ZERO); 509 if (ad == NULL) 510 return (AE_NO_MEMORY); 511 512 ad->ad_handle = handle; 513 ad->ad_level = level; 514 ad->ad_scope = as; 515 ad->ad_type = type; 516 517 TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list); 518 519 rv = AcpiGetObjectInfo(handle, &ad->ad_devinfo); 520 if (rv != AE_OK) 521 goto out; 522 523 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0) 524 goto out; 525 526 #ifdef ACPI_EXTRA_DEBUG 527 printf("%s: HID %s found in scope %s level %d\n", 528 sc->sc_dev.dv_xname, ad->ad_devinfo.HardwareId, 529 as->as_name, ad->ad_level); 530 if (ad->ad_devinfo.Valid & ACPI_VALID_UID) 531 printf(" UID %s\n", 532 ad->ad_devinfo.UniqueId); 533 if (ad->ad_devinfo.Valid & ACPI_VALID_ADR) 534 printf(" ADR 0x%016qx\n", 535 ad->ad_devinfo.Address); 536 if (ad->ad_devinfo.Valid & ACPI_VALID_STA) 537 printf(" STA 0x%08x\n", 538 ad->ad_devinfo.CurrentStatus); 539 #endif 540 } 541 } 542 out: 543 return (AE_OK); 544 } 545 546 /* 547 * acpi_print: 548 * 549 * Autoconfiguration print routine. 550 */ 551 int 552 acpi_print(void *aux, const char *pnp) 553 { 554 struct acpi_attach_args *aa = aux; 555 #if 0 556 char *str; 557 #endif 558 559 if (pnp) { 560 printf("%s ", aa->aa_node->ad_devinfo.HardwareId); 561 #if 0 /* Not until we fix acpi_eval_string */ 562 if (acpi_eval_string(aa->aa_node->ad_handle, 563 "_STR", &str) == AE_OK) { 564 printf("[%s] ", str); 565 AcpiOsFree(str); 566 } 567 #endif 568 printf("at %s", pnp); 569 } 570 571 return (UNCONF); 572 } 573 574 /***************************************************************************** 575 * ACPI fixed-hardware feature handlers 576 *****************************************************************************/ 577 578 UINT32 acpi_fixed_power_button_handler(void *); 579 UINT32 acpi_fixed_sleep_button_handler(void *); 580 581 /* 582 * acpi_enable_fixed_events: 583 * 584 * Enable any fixed-hardware feature handlers. 585 */ 586 void 587 acpi_enable_fixed_events(struct acpi_softc *sc) 588 { 589 static int beenhere; 590 ACPI_STATUS rv; 591 592 /* 593 * Check for fixed-hardware buttons. 594 */ 595 596 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) { 597 if (beenhere == 0) 598 printf("%s: fixed-feature power button present\n", 599 sc->sc_dev.dv_xname); 600 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, 601 acpi_fixed_power_button_handler, sc); 602 if (rv != AE_OK) 603 printf("%s: unable to install handler for fixed " 604 "power button: %d\n", sc->sc_dev.dv_xname, rv); 605 } 606 607 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) { 608 if (beenhere == 0) 609 printf("%s: fixed-feature sleep button present\n", 610 sc->sc_dev.dv_xname); 611 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON, 612 acpi_fixed_sleep_button_handler, sc); 613 if (rv != AE_OK) 614 printf("%s: unable to install handler for fixed " 615 "power button: %d\n", sc->sc_dev.dv_xname, rv); 616 } 617 618 beenhere = 1; 619 } 620 621 /* 622 * acpi_fixed_power_button_handler: 623 * 624 * Fixed event handler for the power button. 625 */ 626 UINT32 627 acpi_fixed_power_button_handler(void *context) 628 { 629 struct acpi_softc *sc = context; 630 631 /* XXX XXX XXX */ 632 633 printf("%s: fixed power button pressed\n", sc->sc_dev.dv_xname); 634 635 return (ACPI_INTERRUPT_HANDLED); 636 } 637 638 /* 639 * acpi_fixed_sleep_button_handler: 640 * 641 * Fixed event handler for the sleep button. 642 */ 643 UINT32 644 acpi_fixed_sleep_button_handler(void *context) 645 { 646 struct acpi_softc *sc = context; 647 648 /* XXX XXX XXX */ 649 650 printf("%s: fixed sleep button pressed\n", sc->sc_dev.dv_xname); 651 652 return (ACPI_INTERRUPT_HANDLED); 653 } 654 655 /***************************************************************************** 656 * ACPI utility routines. 657 *****************************************************************************/ 658 659 /* 660 * acpi_eval_integer: 661 * 662 * Evaluate an integer object. 663 */ 664 ACPI_STATUS 665 acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp) 666 { 667 ACPI_STATUS rv; 668 ACPI_BUFFER buf; 669 ACPI_OBJECT param; 670 671 if (handle == NULL) 672 handle = ACPI_ROOT_OBJECT; 673 674 buf.Pointer = ¶m; 675 buf.Length = sizeof(param); 676 677 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 678 if (rv == AE_OK) { 679 if (param.Type == ACPI_TYPE_INTEGER) 680 *valp = param.Integer.Value; 681 else 682 rv = AE_TYPE; 683 } 684 685 return (rv); 686 } 687 688 #if 0 689 /* 690 * acpi_eval_string: 691 * 692 * Evaluate a (Unicode) string object. 693 * XXX current API may leak memory, so don't use this. 694 */ 695 ACPI_STATUS 696 acpi_eval_string(ACPI_HANDLE handle, char *path, char **stringp) 697 { 698 ACPI_STATUS rv; 699 ACPI_BUFFER buf; 700 ACPI_OBJECT *param; 701 702 if (handle == NULL) 703 handle = ACPI_ROOT_OBJECT; 704 705 buf.Pointer = NULL; 706 buf.Length = 0; 707 708 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 709 if (rv != AE_BUFFER_OVERFLOW) 710 return (rv); 711 712 buf.Pointer = AcpiOsAllocate(buf.Length); 713 if (buf.Pointer == NULL) 714 return (AE_NO_MEMORY); 715 716 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 717 param = (ACPI_OBJECT *)buf.Pointer; 718 if (rv == AE_OK) { 719 if (param->Type == ACPI_TYPE_STRING) { 720 /* XXX may leak buf.Pointer!! */ 721 *stringp = param->String.Pointer; 722 return (AE_OK); 723 } 724 rv = AE_TYPE; 725 } 726 727 AcpiOsFree(buf.Pointer); 728 return (rv); 729 } 730 #endif 731 732 733 /* 734 * acpi_eval_struct: 735 * 736 * Evaluate a more complex structure. Caller must free buf.Pointer. 737 */ 738 ACPI_STATUS 739 acpi_eval_struct(ACPI_HANDLE handle, char *path, ACPI_BUFFER *bufp) 740 { 741 ACPI_STATUS rv; 742 743 if (handle == NULL) 744 handle = ACPI_ROOT_OBJECT; 745 746 bufp->Pointer = NULL; 747 bufp->Length = 0; 748 749 rv = AcpiEvaluateObject(handle, path, NULL, bufp); 750 if (rv != AE_BUFFER_OVERFLOW) 751 return (rv); 752 753 bufp->Pointer = AcpiOsAllocate(bufp->Length); 754 if (bufp->Pointer == NULL) 755 return (AE_NO_MEMORY); 756 757 rv = AcpiEvaluateObject(handle, path, NULL, bufp); 758 759 return (rv); 760 } 761 762 /* 763 * acpi_get: 764 * 765 * Fetch data info the specified (empty) ACPI buffer. 766 */ 767 ACPI_STATUS 768 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, 769 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) 770 { 771 ACPI_STATUS rv; 772 773 buf->Pointer = NULL; 774 buf->Length = 0; 775 776 rv = (*getit)(handle, buf); 777 if (rv != AE_BUFFER_OVERFLOW) 778 return (rv); 779 780 buf->Pointer = AcpiOsAllocate(buf->Length); 781 if (buf->Pointer == NULL) 782 return (AE_NO_MEMORY); 783 memset(buf->Pointer, 0, buf->Length); 784 785 return ((*getit)(handle, buf)); 786 } 787 788 789 /***************************************************************************** 790 * ACPI sleep support. 791 *****************************************************************************/ 792 793 static int 794 is_available_state(struct acpi_softc *sc, int state) 795 { 796 UINT8 type_a, type_b; 797 798 return (ACPI_SUCCESS(AcpiGetSleepTypeData((UINT8)state, 799 &type_a, &type_b))); 800 } 801 802 /* 803 * acpi_enter_sleep_state: 804 * 805 * enter to the specified sleep state. 806 */ 807 808 ACPI_STATUS 809 acpi_enter_sleep_state(struct acpi_softc *sc, int state) 810 { 811 int s; 812 ACPI_STATUS ret = AE_OK; 813 814 switch (state) { 815 case ACPI_STATE_S0: 816 break; 817 case ACPI_STATE_S1: 818 case ACPI_STATE_S2: 819 case ACPI_STATE_S3: 820 case ACPI_STATE_S4: 821 if (!is_available_state(sc, state)) { 822 printf("acpi: cannot enter the sleep state (%d).\n", 823 state); 824 break; 825 } 826 ret = AcpiEnterSleepStatePrep(state); 827 if (ACPI_FAILURE(ret)) { 828 printf("acpi: failed preparing to sleep (%s)\n", 829 AcpiFormatException(ret)); 830 break; 831 } 832 if (state==ACPI_STATE_S1) { 833 /* just enter the state */ 834 acpi_md_OsDisableInterrupt(); 835 AcpiEnterSleepState((UINT8)state); 836 AcpiUtReleaseMutex(ACPI_MTX_HARDWARE); 837 } else { 838 /* XXX: powerhooks(9) framework is too poor to 839 * support ACPI sleep state... 840 */ 841 dopowerhooks(PWR_SOFTSUSPEND); 842 s = splhigh(); 843 dopowerhooks(PWR_SUSPEND); 844 acpi_md_sleep(state); 845 dopowerhooks(PWR_RESUME); 846 splx(s); 847 dopowerhooks(PWR_SOFTRESUME); 848 if (state==ACPI_STATE_S4) 849 AcpiEnable(); 850 } 851 AcpiLeaveSleepState((UINT8)state); 852 break; 853 case ACPI_STATE_S5: 854 AcpiEnterSleepStatePrep(ACPI_STATE_S5); 855 acpi_md_OsDisableInterrupt(); 856 AcpiEnterSleepState(ACPI_STATE_S5); 857 printf("WARNING: powerdown failed!\n"); 858 break; 859 } 860 861 return (ret); 862 } 863 864 #if ACPI_PCI_FIXUP 865 ACPI_STATUS acpi_pci_fixup_bus(ACPI_HANDLE, UINT32, void *, void **); 866 /* 867 * acpi_pci_fixup: 868 * 869 * Set up PCI devices that BIOS didn't handle right. 870 * Iterate through all devices and try to get the _PTR 871 * (PCI Routing Table). If it exists then make sure all 872 * interrupt links that it uses are working. 873 */ 874 void 875 acpi_pci_fixup(struct acpi_softc *sc) 876 { 877 ACPI_HANDLE parent; 878 879 #ifdef ACPI_DEBUG 880 printf("acpi_pci_fixup starts:\n"); 881 #endif 882 if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent) != AE_OK) 883 return; 884 sc->sc_pci_bus = 0; 885 AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100, 886 acpi_pci_fixup_bus, sc, NULL); 887 } 888 889 static ACPI_HANDLE 890 acpi_get_node(char *name) 891 { 892 ACPI_NAMESPACE_NODE *ObjDesc; 893 ACPI_STATUS Status; 894 895 Status = AcpiNsGetNodeByPath(name, NULL, 0, &ObjDesc); 896 if (ACPI_FAILURE (Status)) { 897 printf("acpi_get_node: could not find: %s\n", 898 AcpiFormatException (Status)); 899 return NULL; 900 } 901 return ObjDesc; 902 } 903 904 static uint 905 acpi_get_intr(ACPI_HANDLE handle) 906 { 907 ACPI_BUFFER ret; 908 ACPI_STATUS rv; 909 ACPI_RESOURCE *res; 910 ACPI_RESOURCE_IRQ *irq; 911 uint intr; 912 913 intr = -1; 914 rv = acpi_get(handle, &ret, AcpiGetCurrentResources); 915 if (ACPI_FAILURE(rv)) 916 return (intr); 917 for (res = ret.Pointer; res->Id != ACPI_RSTYPE_END_TAG; 918 res = ACPI_NEXT_RESOURCE(res)) { 919 if (res->Id == ACPI_RSTYPE_IRQ) { 920 irq = (ACPI_RESOURCE_IRQ *)&res->Data; 921 if (irq->NumberOfInterrupts == 1) 922 intr = irq->Interrupts[0]; 923 break; 924 } 925 } 926 free(ret.Pointer, M_DEVBUF); 927 return (intr); 928 } 929 930 static void 931 acpi_pci_set_line(int bus, int dev, int pin, int line) 932 { 933 ACPI_STATUS err; 934 ACPI_PCI_ID pid; 935 UINT32 intr, id, bhlc; 936 int func, nfunc; 937 938 pid.Bus = bus; 939 pid.Device = dev; 940 pid.Function = 0; 941 942 err = AcpiOsReadPciConfiguration(&pid, PCI_BHLC_REG, &bhlc, 32); 943 if (err) 944 return; 945 if (PCI_HDRTYPE_MULTIFN(bhlc)) 946 nfunc = 8; 947 else 948 nfunc = 1; 949 950 for (func = 0; func < nfunc; func++) { 951 pid.Function = func; 952 953 err = AcpiOsReadPciConfiguration(&pid, PCI_ID_REG, &id, 32); 954 if (err || PCI_VENDOR(id) == PCI_VENDOR_INVALID || 955 PCI_VENDOR(id) == 0) 956 continue; 957 958 err = AcpiOsReadPciConfiguration(&pid, PCI_INTERRUPT_REG, 959 &intr, 32); 960 if (err) { 961 printf("AcpiOsReadPciConfiguration failed %d\n", err); 962 return; 963 } 964 if (pin == PCI_INTERRUPT_PIN(intr) && 965 line != PCI_INTERRUPT_LINE(intr)) { 966 #ifdef ACPI_DEBUG 967 printf("acpi fixup pci intr: %d:%d:%d %c: %d -> %d\n", 968 bus, dev, func, 969 pin + '@', PCI_INTERRUPT_LINE(intr), 970 line); 971 #endif 972 intr &= ~(PCI_INTERRUPT_LINE_MASK << 973 PCI_INTERRUPT_LINE_SHIFT); 974 intr |= line << PCI_INTERRUPT_LINE_SHIFT; 975 err = AcpiOsWritePciConfiguration(&pid, 976 PCI_INTERRUPT_REG, intr, 32); 977 if (err) { 978 printf("AcpiOsWritePciConfiguration failed" 979 " %d\n", err); 980 return; 981 } 982 } 983 } 984 } 985 986 ACPI_STATUS 987 acpi_pci_fixup_bus(ACPI_HANDLE handle, UINT32 level, void *context, 988 void **status) 989 { 990 struct acpi_softc *sc = context; 991 ACPI_STATUS rv; 992 ACPI_BUFFER buf; 993 UINT8 *Buffer; 994 ACPI_PCI_ROUTING_TABLE *PrtElement; 995 ACPI_HANDLE link; 996 uint line; 997 998 rv = acpi_get(handle, &buf, AcpiGetIrqRoutingTable); 999 if (ACPI_FAILURE(rv)) 1000 return (AE_OK); 1001 1002 #ifdef ACPI_DEBUG 1003 printf("%s: fixing up PCI\n", sc->sc_dev.dv_xname); 1004 #endif 1005 1006 for (Buffer = buf.Pointer; ; Buffer += PrtElement->Length) { 1007 PrtElement = (ACPI_PCI_ROUTING_TABLE *)Buffer; 1008 if (PrtElement->Length == 0) 1009 break; 1010 if (PrtElement->Source == NULL) 1011 continue; 1012 1013 link = acpi_get_node(PrtElement->Source); 1014 if (link == NULL) 1015 continue; 1016 line = acpi_get_intr(link); 1017 if (line == -1) { 1018 #ifdef ACPI_DEBUG 1019 printf("%s: fixing up link %s\n", sc->sc_dev.dv_xname, 1020 PrtElement->Source); 1021 #endif 1022 rv = acpi_allocate_resources(link); 1023 if (ACPI_FAILURE(rv)) { 1024 printf("%s: interrupt allocation failed %s\n", 1025 sc->sc_dev.dv_xname, PrtElement->Source); 1026 continue; 1027 } 1028 line = acpi_get_intr(link); 1029 if (line == -1) { 1030 printf("%s: get intr failed %s\n", 1031 sc->sc_dev.dv_xname, PrtElement->Source); 1032 continue; 1033 } 1034 } 1035 1036 acpi_pci_set_line(sc->sc_pci_bus, PrtElement->Address >> 16, 1037 PrtElement->Pin + 1, line); 1038 } 1039 1040 sc->sc_pci_bus++; 1041 1042 free(buf.Pointer, M_DEVBUF); 1043 return (AE_OK); 1044 } 1045 #endif /* ACPI_PCI_FIXUP */ 1046 1047 #if ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV 1048 /* XXX This very incomplete */ 1049 ACPI_STATUS 1050 acpi_allocate_resources(ACPI_HANDLE handle) 1051 { 1052 ACPI_BUFFER bufp, bufc, bufn; 1053 ACPI_RESOURCE *resp, *resc, *resn; 1054 ACPI_RESOURCE_IRQ *irq; 1055 ACPI_STATUS rv; 1056 uint delta; 1057 1058 rv = acpi_get(handle, &bufp, AcpiGetPossibleResources); 1059 if (ACPI_FAILURE(rv)) 1060 goto out; 1061 rv = acpi_get(handle, &bufc, AcpiGetCurrentResources); 1062 if (ACPI_FAILURE(rv)) { 1063 goto out1; 1064 } 1065 1066 bufn.Length = 1000; 1067 bufn.Pointer = resn = malloc(bufn.Length, M_DEVBUF, M_WAITOK); 1068 resp = bufp.Pointer; 1069 resc = bufc.Pointer; 1070 while (resc->Id != ACPI_RSTYPE_END_TAG && 1071 resp->Id != ACPI_RSTYPE_END_TAG) { 1072 while (resc->Id != resp->Id && resp->Id != ACPI_RSTYPE_END_TAG) 1073 resp = ACPI_NEXT_RESOURCE(resp); 1074 if (resp->Id == ACPI_RSTYPE_END_TAG) 1075 break; 1076 /* Found identical Id */ 1077 resn->Id = resc->Id; 1078 switch (resc->Id) { 1079 case ACPI_RSTYPE_IRQ: 1080 memcpy(&resn->Data, &resp->Data, 1081 sizeof(ACPI_RESOURCE_IRQ)); 1082 irq = (ACPI_RESOURCE_IRQ *)&resn->Data; 1083 irq->Interrupts[0] = 1084 ((ACPI_RESOURCE_IRQ *)&resp->Data)-> 1085 Interrupts[irq->NumberOfInterrupts-1]; 1086 irq->NumberOfInterrupts = 1; 1087 resn->Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ); 1088 break; 1089 case ACPI_RSTYPE_IO: 1090 memcpy(&resn->Data, &resp->Data, 1091 sizeof(ACPI_RESOURCE_IO)); 1092 resn->Length = resp->Length; 1093 break; 1094 default: 1095 printf("acpi_allocate_resources: res=%d\n", resc->Id); 1096 rv = AE_BAD_DATA; 1097 goto out2; 1098 } 1099 resc = ACPI_NEXT_RESOURCE(resc); 1100 resn = ACPI_NEXT_RESOURCE(resn); 1101 delta = (UINT8 *)resn - (UINT8 *)bufn.Pointer; 1102 if (delta >= bufn.Length-ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_DATA)) { 1103 bufn.Length *= 2; 1104 bufn.Pointer = realloc(bufn.Pointer, bufn.Length, 1105 M_DEVBUF, M_WAITOK); 1106 resn = (ACPI_RESOURCE *)((UINT8 *)bufn.Pointer + delta); 1107 } 1108 } 1109 if (resc->Id != ACPI_RSTYPE_END_TAG) { 1110 printf("acpi_allocate_resources: resc not exhausted\n"); 1111 rv = AE_BAD_DATA; 1112 goto out3; 1113 } 1114 1115 resn->Id = ACPI_RSTYPE_END_TAG; 1116 rv = AcpiSetCurrentResources(handle, &bufn); 1117 if (ACPI_FAILURE(rv)) { 1118 printf("acpi_allocate_resources: AcpiSetCurrentResources %s\n", 1119 AcpiFormatException(rv)); 1120 } 1121 1122 out3: 1123 free(bufn.Pointer, M_DEVBUF); 1124 out2: 1125 free(bufc.Pointer, M_DEVBUF); 1126 out1: 1127 free(bufp.Pointer, M_DEVBUF); 1128 out: 1129 return rv; 1130 } 1131 #endif /* ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV */ 1132