1 /* $NetBSD: acpi.c,v 1.7 2002/03/24 03:32:14 sommerfeld 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.7 2002/03/24 03:32:14 sommerfeld 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 #ifdef ENABLE_DEBUGGER 57 #define ACPI_DBGR_INIT 0x01 58 #define ACPI_DBGR_TABLES 0x02 59 #define ACPI_DBGR_ENABLE 0x04 60 #define ACPI_DBGR_PROBE 0x08 61 #define ACPI_DBGR_RUNNING 0x10 62 63 int acpi_dbgr = 0x00; 64 #endif 65 66 int acpi_match(struct device *, struct cfdata *, void *); 67 void acpi_attach(struct device *, struct device *, void *); 68 69 int acpi_print(void *aux, const char *); 70 71 extern struct cfdriver acpi_cd; 72 73 struct cfattach acpi_ca = { 74 sizeof(struct acpi_softc), acpi_match, acpi_attach, 75 }; 76 77 /* 78 * This is a flag we set when the ACPI subsystem is active. Machine 79 * dependent code may wish to skip other steps (such as attaching 80 * subsystems that ACPI supercedes) when ACPI is active. 81 */ 82 int acpi_active; 83 84 /* 85 * Pointer to the ACPI subsystem's state. There can be only 86 * one ACPI instance. 87 */ 88 struct acpi_softc *acpi_softc; 89 90 void acpi_shutdown(void *); 91 ACPI_STATUS acpi_disable(struct acpi_softc *sc); 92 void acpi_build_tree(struct acpi_softc *); 93 ACPI_STATUS acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **); 94 95 void acpi_enable_fixed_events(struct acpi_softc *); 96 97 /* 98 * acpi_probe: 99 * 100 * Probe for ACPI support. This is called by the 101 * machine-dependent ACPI front-end. All of the 102 * actual work is done by ACPICA. 103 * 104 * NOTE: This is not an autoconfiguration interface function. 105 */ 106 int 107 acpi_probe(void) 108 { 109 static int beenhere; 110 ACPI_STATUS rv; 111 112 if (beenhere != 0) 113 panic("acpi_probe: ACPI has already been probed"); 114 beenhere = 1; 115 116 /* 117 * Start up ACPICA. 118 */ 119 #ifdef ENABLE_DEBUGGER 120 if (acpi_dbgr & ACPI_DBGR_INIT) 121 acpi_osd_debugger(); 122 #endif 123 124 rv = AcpiInitializeSubsystem(); 125 if (rv != AE_OK) { 126 printf("ACPI: unable to initialize ACPICA: %d\n", rv); 127 return (0); 128 } 129 130 #ifdef ENABLE_DEBUGGER 131 if (acpi_dbgr & ACPI_DBGR_TABLES) 132 acpi_osd_debugger(); 133 #endif 134 135 rv = AcpiLoadTables(); 136 if (rv != AE_OK) { 137 printf("ACPI: unable to load tables: %d\n", rv); 138 return (0); 139 } 140 141 /* 142 * Looks like we have ACPI! 143 */ 144 145 return (1); 146 } 147 148 /* 149 * acpi_match: 150 * 151 * Autoconfiguration `match' routine. 152 */ 153 int 154 acpi_match(struct device *parent, struct cfdata *match, void *aux) 155 { 156 struct acpibus_attach_args *aa = aux; 157 158 if (strcmp(aa->aa_busname, acpi_cd.cd_name) != 0) 159 return (0); 160 161 /* 162 * XXX Check other locators? Hard to know -- machine 163 * dependent code has already checked for the presence 164 * of ACPI by calling acpi_probe(), so I suppose we 165 * don't really have to do anything else. 166 */ 167 return (1); 168 } 169 170 /* 171 * acpi_attach: 172 * 173 * Autoconfiguration `attach' routine. Finish initializing 174 * ACPICA (some initialization was done in acpi_probe(), 175 * which was required to check for the presence of ACPI), 176 * and enable the ACPI subsystem. 177 */ 178 void 179 acpi_attach(struct device *parent, struct device *self, void *aux) 180 { 181 struct acpi_softc *sc = (void *) self; 182 struct acpibus_attach_args *aa = aux; 183 ACPI_STATUS rv; 184 185 printf("\n"); 186 187 if (acpi_softc != NULL) 188 panic("acpi_attach: ACPI has already been attached"); 189 190 sc->sc_iot = aa->aa_iot; 191 sc->sc_memt = aa->aa_memt; 192 sc->sc_pc = aa->aa_pc; 193 sc->sc_pciflags = aa->aa_pciflags; 194 195 acpi_softc = sc; 196 197 /* 198 * Install the default address space handlers. 199 */ 200 201 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 202 ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL); 203 if (rv != AE_OK) { 204 printf("%s: unable to install SYSTEM MEMORY handler: %d\n", 205 sc->sc_dev.dv_xname, rv); 206 return; 207 } 208 209 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 210 ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL); 211 if (rv != AE_OK) { 212 printf("%s: unable to install SYSTEM IO handler: %d\n", 213 sc->sc_dev.dv_xname, rv); 214 return; 215 } 216 217 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 218 ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); 219 if (rv != AE_OK) { 220 printf("%s: unable to install PCI CONFIG handler: %d\n", 221 sc->sc_dev.dv_xname, rv); 222 return; 223 } 224 225 /* 226 * Bring ACPI on-line. 227 * 228 * Note that we request that _STA (device init) and _INI (object init) 229 * methods not be run. 230 * 231 * XXX We need to arrange for the object init pass after we have 232 * XXX attached all of our children. 233 */ 234 #ifdef ENABLE_DEBUGGER 235 if (acpi_dbgr & ACPI_DBGR_ENABLE) 236 acpi_osd_debugger(); 237 #endif 238 rv = AcpiEnableSubsystem(ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT); 239 if (rv != AE_OK) { 240 printf("%s: unable to enable ACPI: %d\n", 241 sc->sc_dev.dv_xname, rv); 242 return; 243 } 244 acpi_active = 1; 245 246 /* 247 * Set up the default sleep state to enter when various 248 * switches are activated. 249 */ 250 sc->sc_switch_sleep[ACPI_SWITCH_POWERBUTTON] = ACPI_STATE_S5; 251 sc->sc_switch_sleep[ACPI_SWITCH_SLEEPBUTTON] = ACPI_STATE_S1; 252 sc->sc_switch_sleep[ACPI_SWITCH_LID] = ACPI_STATE_S1; 253 254 /* Our current state is "awake". */ 255 sc->sc_sleepstate = ACPI_STATE_S0; 256 257 /* 258 * Check for fixed-hardware features. 259 */ 260 acpi_enable_fixed_events(sc); 261 262 /* 263 * Scan the namespace and build our device tree. 264 */ 265 #ifdef ENABLE_DEBUGGER 266 if (acpi_dbgr & ACPI_DBGR_PROBE) 267 acpi_osd_debugger(); 268 #endif 269 acpi_build_tree(sc); 270 271 /* 272 * Register a shutdown hook that disables certain ACPI 273 * events that might happen and confuse us while we're 274 * trying to shut down. 275 */ 276 sc->sc_sdhook = shutdownhook_establish(acpi_shutdown, sc); 277 if (sc->sc_sdhook == NULL) 278 printf("%s: WARNING: unable to register shutdown hook\n", 279 sc->sc_dev.dv_xname); 280 281 #ifdef ENABLE_DEBUGGER 282 if (acpi_dbgr & ACPI_DBGR_RUNNING) 283 acpi_osd_debugger(); 284 #endif 285 } 286 287 /* 288 * acpi_shutdown: 289 * 290 * Shutdown hook for ACPI -- disable some events that 291 * might confuse us. 292 */ 293 void 294 acpi_shutdown(void *arg) 295 { 296 struct acpi_softc *sc = arg; 297 298 if (acpi_disable(sc) != AE_OK) 299 printf("%s: WARNING: unable to disable ACPI\n", 300 sc->sc_dev.dv_xname); 301 } 302 303 /* 304 * acpi_disable: 305 * 306 * Disable ACPI. 307 */ 308 ACPI_STATUS 309 acpi_disable(struct acpi_softc *sc) 310 { 311 ACPI_STATUS rv = AE_OK; 312 313 if (acpi_active) { 314 rv = AcpiDisable(); 315 if (rv == AE_OK) 316 acpi_active = 0; 317 } 318 return (rv); 319 } 320 321 struct acpi_make_devnode_state { 322 struct acpi_softc *softc; 323 struct acpi_scope *scope; 324 }; 325 326 /* 327 * acpi_build_tree: 328 * 329 * Scan relevant portions of the ACPI namespace and attach 330 * child devices. 331 */ 332 void 333 acpi_build_tree(struct acpi_softc *sc) 334 { 335 static const char *scopes[] = { 336 "\\_PR_", /* ACPI 1.0 processor namespace */ 337 "\\_SB_", /* system bus namespace */ 338 "\\_SI_", /* system idicator namespace */ 339 "\\_TZ_", /* ACPI 1.0 thermal zone namespace */ 340 NULL, 341 }; 342 struct acpi_attach_args aa; 343 struct acpi_make_devnode_state state; 344 struct acpi_scope *as; 345 struct acpi_devnode *ad; 346 ACPI_HANDLE parent; 347 int i; 348 349 TAILQ_INIT(&sc->sc_scopes); 350 351 state.softc = sc; 352 353 /* 354 * Scan the namespace and build our tree. 355 */ 356 for (i = 0; scopes[i] != NULL; i++) { 357 as = malloc(sizeof(*as), M_DEVBUF, M_WAITOK); 358 as->as_name = scopes[i]; 359 TAILQ_INIT(&as->as_devnodes); 360 361 TAILQ_INSERT_TAIL(&sc->sc_scopes, as, as_list); 362 363 state.scope = as; 364 365 if (AcpiGetHandle(ACPI_ROOT_OBJECT, (char *) scopes[i], 366 &parent) == AE_OK) { 367 AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100, 368 acpi_make_devnode, &state, NULL); 369 } 370 371 /* Now, for this namespace, try and attach the devices. */ 372 TAILQ_FOREACH(ad, &as->as_devnodes, ad_list) { 373 aa.aa_node = ad; 374 aa.aa_iot = sc->sc_iot; 375 aa.aa_memt = sc->sc_memt; 376 aa.aa_pc = sc->sc_pc; 377 aa.aa_pciflags = sc->sc_pciflags; 378 379 /* 380 * XXX We only attach devices which are: 381 * 382 * - present 383 * - enabled 384 * - to be shown 385 * - functioning properly 386 * 387 * However, if enabled, it's decoding resources, 388 * so we should claim them, if possible. Requires 389 * changes to bus_space(9). 390 */ 391 if ((ad->ad_devinfo.CurrentStatus & 392 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED| 393 ACPI_STA_DEV_SHOW|ACPI_STA_DEV_OK)) != 394 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED| 395 ACPI_STA_DEV_SHOW|ACPI_STA_DEV_OK)) 396 continue; 397 398 /* 399 * XXX Same problem as above... 400 */ 401 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0) 402 continue; 403 404 ad->ad_device = config_found(&sc->sc_dev, 405 &aa, acpi_print); 406 } 407 } 408 } 409 410 /* 411 * acpi_make_devnode: 412 * 413 * Make an ACPI devnode. 414 */ 415 ACPI_STATUS 416 acpi_make_devnode(ACPI_HANDLE handle, UINT32 level, void *context, 417 void **status) 418 { 419 struct acpi_make_devnode_state *state = context; 420 #ifdef ACPI_DEBUG 421 struct acpi_softc *sc = state->softc; 422 #endif 423 struct acpi_scope *as = state->scope; 424 struct acpi_devnode *ad; 425 ACPI_OBJECT_TYPE type; 426 ACPI_STATUS rv; 427 428 if (AcpiGetType(handle, &type) == AE_OK) { 429 switch (type) { 430 case ACPI_TYPE_DEVICE: 431 case ACPI_TYPE_PROCESSOR: 432 case ACPI_TYPE_THERMAL: 433 case ACPI_TYPE_POWER: 434 ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT|M_ZERO); 435 if (ad == NULL) 436 return (AE_NO_MEMORY); 437 438 ad->ad_handle = handle; 439 ad->ad_level = level; 440 ad->ad_scope = as; 441 ad->ad_type = type; 442 443 TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list); 444 445 rv = AcpiGetObjectInfo(handle, &ad->ad_devinfo); 446 if (rv != AE_OK) 447 goto out; 448 449 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0) 450 goto out; 451 452 #ifdef ACPI_DEBUG 453 printf("%s: HID %s found in scope %s level %d\n", 454 sc->sc_dev.dv_xname, ad->ad_devinfo.HardwareId, 455 as->as_name, ad->ad_level); 456 if (ad->ad_devinfo.Valid & ACPI_VALID_UID) 457 printf(" UID %s\n", 458 ad->ad_devinfo.UniqueId); 459 if (ad->ad_devinfo.Valid & ACPI_VALID_ADR) 460 printf(" ADR 0x%016qx\n", 461 ad->ad_devinfo.Address); 462 if (ad->ad_devinfo.Valid & ACPI_VALID_STA) 463 printf(" STA 0x%08x\n", 464 ad->ad_devinfo.CurrentStatus); 465 #endif 466 } 467 } 468 out: 469 return (AE_OK); 470 } 471 472 /* 473 * acpi_print: 474 * 475 * Autoconfiguration print routine. 476 */ 477 int 478 acpi_print(void *aux, const char *pnp) 479 { 480 struct acpi_attach_args *aa = aux; 481 #if 0 482 char *str; 483 #endif 484 485 if (pnp) { 486 printf("%s ", aa->aa_node->ad_devinfo.HardwareId); 487 #if 0 /* Not until we fix acpi_eval_string */ 488 if (acpi_eval_string(aa->aa_node->ad_handle, 489 "_STR", &str) == AE_OK) { 490 printf("[%s] ", str); 491 AcpiOsFree(str); 492 } 493 #endif 494 printf("at %s", pnp); 495 } 496 497 return (UNCONF); 498 } 499 500 /***************************************************************************** 501 * ACPI fixed-hardware feature handlers 502 *****************************************************************************/ 503 504 UINT32 acpi_fixed_power_button_handler(void *); 505 UINT32 acpi_fixed_sleep_button_handler(void *); 506 507 /* 508 * acpi_enable_fixed_events: 509 * 510 * Enable any fixed-hardware feature handlers. 511 */ 512 void 513 acpi_enable_fixed_events(struct acpi_softc *sc) 514 { 515 static int beenhere; 516 ACPI_STATUS rv; 517 518 /* 519 * Check for fixed-hardware buttons. 520 */ 521 522 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) { 523 if (beenhere == 0) 524 printf("%s: fixed-feature power button present\n", 525 sc->sc_dev.dv_xname); 526 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, 527 acpi_fixed_power_button_handler, sc); 528 if (rv != AE_OK) 529 printf("%s: unable to install handler for fixed " 530 "power button: %d\n", sc->sc_dev.dv_xname, rv); 531 } 532 533 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) { 534 if (beenhere == 0) 535 printf("%s: fixed-feature sleep button present\n", 536 sc->sc_dev.dv_xname); 537 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON, 538 acpi_fixed_sleep_button_handler, sc); 539 if (rv != AE_OK) 540 printf("%s: unable to install handler for fixed " 541 "power button: %d\n", sc->sc_dev.dv_xname, rv); 542 } 543 544 beenhere = 1; 545 } 546 547 /* 548 * acpi_fixed_power_button_handler: 549 * 550 * Fixed event handler for the power button. 551 */ 552 UINT32 553 acpi_fixed_power_button_handler(void *context) 554 { 555 struct acpi_softc *sc = context; 556 557 /* XXX XXX XXX */ 558 559 printf("%s: fixed power button pressed\n", sc->sc_dev.dv_xname); 560 561 return (INTERRUPT_HANDLED); 562 } 563 564 /* 565 * acpi_fixed_sleep_button_handler: 566 * 567 * Fixed event handler for the sleep button. 568 */ 569 UINT32 570 acpi_fixed_sleep_button_handler(void *context) 571 { 572 struct acpi_softc *sc = context; 573 574 /* XXX XXX XXX */ 575 576 printf("%s: fixed sleep button pressed\n", sc->sc_dev.dv_xname); 577 578 return (INTERRUPT_HANDLED); 579 } 580 581 /***************************************************************************** 582 * ACPI utility routines. 583 *****************************************************************************/ 584 585 /* 586 * acpi_eval_integer: 587 * 588 * Evaluate an integer object. 589 */ 590 ACPI_STATUS 591 acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp) 592 { 593 ACPI_STATUS rv; 594 ACPI_BUFFER buf; 595 ACPI_OBJECT param; 596 597 if (handle == NULL) 598 handle = ACPI_ROOT_OBJECT; 599 600 buf.Pointer = ¶m; 601 buf.Length = sizeof(param); 602 603 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 604 if (rv == AE_OK) { 605 if (param.Type == ACPI_TYPE_INTEGER) 606 *valp = param.Integer.Value; 607 else 608 rv = AE_TYPE; 609 } 610 611 return (rv); 612 } 613 614 #if 0 615 /* 616 * acpi_eval_string: 617 * 618 * Evaluate a (Unicode) string object. 619 * XXX current API may leak memory, so don't use this. 620 */ 621 ACPI_STATUS 622 acpi_eval_string(ACPI_HANDLE handle, char *path, char **stringp) 623 { 624 ACPI_STATUS rv; 625 ACPI_BUFFER buf; 626 ACPI_OBJECT *param; 627 628 if (handle == NULL) 629 handle = ACPI_ROOT_OBJECT; 630 631 buf.Pointer = NULL; 632 buf.Length = 0; 633 634 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 635 if (rv != AE_BUFFER_OVERFLOW) 636 return (rv); 637 638 buf.Pointer = AcpiOsAllocate(buf.Length); 639 if (buf.Pointer == NULL) 640 return (AE_NO_MEMORY); 641 642 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 643 param = (ACPI_OBJECT *)buf.Pointer; 644 if (rv == AE_OK) { 645 if (param->Type == ACPI_TYPE_STRING) { 646 /* XXX may leak buf.Pointer!! */ 647 *stringp = param->String.Pointer; 648 return (AE_OK); 649 } 650 rv = AE_TYPE; 651 } 652 653 AcpiOsFree(buf.Pointer); 654 return (rv); 655 } 656 #endif 657 658 659 /* 660 * acpi_eval_struct: 661 * 662 * Evaluate a more complex structure. Caller must free buf.Pointer. 663 */ 664 ACPI_STATUS 665 acpi_eval_struct(ACPI_HANDLE handle, char *path, ACPI_BUFFER *bufp) 666 { 667 ACPI_STATUS rv; 668 669 if (handle == NULL) 670 handle = ACPI_ROOT_OBJECT; 671 672 bufp->Pointer = NULL; 673 bufp->Length = 0; 674 675 rv = AcpiEvaluateObject(handle, path, NULL, bufp); 676 if (rv != AE_BUFFER_OVERFLOW) 677 return (rv); 678 679 bufp->Pointer = AcpiOsAllocate(bufp->Length); 680 if (bufp->Pointer == NULL) 681 return (AE_NO_MEMORY); 682 683 rv = AcpiEvaluateObject(handle, path, NULL, bufp); 684 685 return (rv); 686 } 687 688 /* 689 * acpi_get: 690 * 691 * Fetch data info the specified (empty) ACPI buffer. 692 */ 693 ACPI_STATUS 694 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, 695 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) 696 { 697 ACPI_STATUS rv; 698 699 buf->Pointer = NULL; 700 buf->Length = 0; 701 702 rv = (*getit)(handle, buf); 703 if (rv != AE_BUFFER_OVERFLOW) 704 return (rv); 705 706 buf->Pointer = AcpiOsCallocate(buf->Length); 707 if (buf->Pointer == NULL) 708 return (AE_NO_MEMORY); 709 710 return ((*getit)(handle, buf)); 711 } 712