1 /* $NetBSD: acpi.c,v 1.6 2002/01/12 16:43:53 tsutsui 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.6 2002/01/12 16:43:53 tsutsui 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 char *str; 482 483 if (pnp) { 484 printf("%s ", aa->aa_node->ad_devinfo.HardwareId); 485 if (acpi_eval_string(aa->aa_node->ad_handle, 486 "_STR", &str) == AE_OK) { 487 printf("[%s] ", str); 488 AcpiOsFree(str); 489 } 490 printf("at %s", pnp); 491 } 492 493 return (UNCONF); 494 } 495 496 /***************************************************************************** 497 * ACPI fixed-hardware feature handlers 498 *****************************************************************************/ 499 500 UINT32 acpi_fixed_power_button_handler(void *); 501 UINT32 acpi_fixed_sleep_button_handler(void *); 502 503 /* 504 * acpi_enable_fixed_events: 505 * 506 * Enable any fixed-hardware feature handlers. 507 */ 508 void 509 acpi_enable_fixed_events(struct acpi_softc *sc) 510 { 511 static int beenhere; 512 ACPI_STATUS rv; 513 514 /* 515 * Check for fixed-hardware buttons. 516 */ 517 518 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) { 519 if (beenhere == 0) 520 printf("%s: fixed-feature power button present\n", 521 sc->sc_dev.dv_xname); 522 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, 523 acpi_fixed_power_button_handler, sc); 524 if (rv != AE_OK) 525 printf("%s: unable to install handler for fixed " 526 "power button: %d\n", sc->sc_dev.dv_xname, rv); 527 } 528 529 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) { 530 if (beenhere == 0) 531 printf("%s: fixed-feature sleep button present\n", 532 sc->sc_dev.dv_xname); 533 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON, 534 acpi_fixed_sleep_button_handler, sc); 535 if (rv != AE_OK) 536 printf("%s: unable to install handler for fixed " 537 "power button: %d\n", sc->sc_dev.dv_xname, rv); 538 } 539 540 beenhere = 1; 541 } 542 543 /* 544 * acpi_fixed_power_button_handler: 545 * 546 * Fixed event handler for the power button. 547 */ 548 UINT32 549 acpi_fixed_power_button_handler(void *context) 550 { 551 struct acpi_softc *sc = context; 552 553 /* XXX XXX XXX */ 554 555 printf("%s: fixed power button pressed\n", sc->sc_dev.dv_xname); 556 557 return (INTERRUPT_HANDLED); 558 } 559 560 /* 561 * acpi_fixed_sleep_button_handler: 562 * 563 * Fixed event handler for the sleep button. 564 */ 565 UINT32 566 acpi_fixed_sleep_button_handler(void *context) 567 { 568 struct acpi_softc *sc = context; 569 570 /* XXX XXX XXX */ 571 572 printf("%s: fixed sleep button pressed\n", sc->sc_dev.dv_xname); 573 574 return (INTERRUPT_HANDLED); 575 } 576 577 /***************************************************************************** 578 * ACPI utility routines. 579 *****************************************************************************/ 580 581 /* 582 * acpi_eval_integer: 583 * 584 * Evaluate an integer object. 585 */ 586 ACPI_STATUS 587 acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp) 588 { 589 ACPI_STATUS rv; 590 ACPI_BUFFER buf; 591 ACPI_OBJECT param; 592 593 if (handle == NULL) 594 handle = ACPI_ROOT_OBJECT; 595 596 buf.Pointer = ¶m; 597 buf.Length = sizeof(param); 598 599 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 600 if (rv == AE_OK) { 601 if (param.Type == ACPI_TYPE_INTEGER) 602 *valp = param.Integer.Value; 603 else 604 rv = AE_TYPE; 605 } 606 607 return (rv); 608 } 609 610 /* 611 * acpi_eval_string: 612 * 613 * Evaluage a (Unicode) string object. 614 */ 615 ACPI_STATUS 616 acpi_eval_string(ACPI_HANDLE handle, char *path, char **stringp) 617 { 618 ACPI_STATUS rv; 619 ACPI_BUFFER buf; 620 ACPI_OBJECT param; 621 622 if (handle == NULL) 623 handle = ACPI_ROOT_OBJECT; 624 625 buf.Pointer = NULL; 626 buf.Length = 0; 627 628 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 629 if (rv != AE_BUFFER_OVERFLOW) 630 return (rv); 631 632 buf.Pointer = AcpiOsAllocate(buf.Length); 633 if (buf.Pointer == NULL) 634 return (AE_NO_MEMORY); 635 636 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 637 if (rv == AE_OK) { 638 if (param.Type == ACPI_TYPE_STRING) { 639 *stringp = buf.Pointer; 640 return (AE_OK); 641 } 642 rv = AE_TYPE; 643 } 644 645 AcpiOsFree(buf.Pointer); 646 return (rv); 647 } 648 649 /* 650 * acpi_get: 651 * 652 * Fetch data info the specified (empty) ACPI buffer. 653 */ 654 ACPI_STATUS 655 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, 656 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) 657 { 658 ACPI_STATUS rv; 659 660 buf->Pointer = NULL; 661 buf->Length = 0; 662 663 rv = (*getit)(handle, buf); 664 if (rv != AE_BUFFER_OVERFLOW) 665 return (rv); 666 667 buf->Pointer = AcpiOsCallocate(buf->Length); 668 if (buf->Pointer == NULL) 669 return (AE_NO_MEMORY); 670 671 return ((*getit)(handle, buf)); 672 } 673