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