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