1 /* $NetBSD: acpi.c,v 1.5 2001/11/13 13:01:57 lukem 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.5 2001/11/13 13:01:57 lukem 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); 435 if (ad == NULL) 436 return (AE_NO_MEMORY); 437 memset(ad, 0, sizeof(*ad)); 438 439 ad->ad_handle = handle; 440 ad->ad_level = level; 441 ad->ad_scope = as; 442 ad->ad_type = type; 443 444 TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list); 445 446 rv = AcpiGetObjectInfo(handle, &ad->ad_devinfo); 447 if (rv != AE_OK) 448 goto out; 449 450 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0) 451 goto out; 452 453 #ifdef ACPI_DEBUG 454 printf("%s: HID %s found in scope %s level %d\n", 455 sc->sc_dev.dv_xname, ad->ad_devinfo.HardwareId, 456 as->as_name, ad->ad_level); 457 if (ad->ad_devinfo.Valid & ACPI_VALID_UID) 458 printf(" UID %s\n", 459 ad->ad_devinfo.UniqueId); 460 if (ad->ad_devinfo.Valid & ACPI_VALID_ADR) 461 printf(" ADR 0x%016qx\n", 462 ad->ad_devinfo.Address); 463 if (ad->ad_devinfo.Valid & ACPI_VALID_STA) 464 printf(" STA 0x%08x\n", 465 ad->ad_devinfo.CurrentStatus); 466 #endif 467 } 468 } 469 out: 470 return (AE_OK); 471 } 472 473 /* 474 * acpi_print: 475 * 476 * Autoconfiguration print routine. 477 */ 478 int 479 acpi_print(void *aux, const char *pnp) 480 { 481 struct acpi_attach_args *aa = aux; 482 char *str; 483 484 if (pnp) { 485 printf("%s ", aa->aa_node->ad_devinfo.HardwareId); 486 if (acpi_eval_string(aa->aa_node->ad_handle, 487 "_STR", &str) == AE_OK) { 488 printf("[%s] ", str); 489 AcpiOsFree(str); 490 } 491 printf("at %s", pnp); 492 } 493 494 return (UNCONF); 495 } 496 497 /***************************************************************************** 498 * ACPI fixed-hardware feature handlers 499 *****************************************************************************/ 500 501 UINT32 acpi_fixed_power_button_handler(void *); 502 UINT32 acpi_fixed_sleep_button_handler(void *); 503 504 /* 505 * acpi_enable_fixed_events: 506 * 507 * Enable any fixed-hardware feature handlers. 508 */ 509 void 510 acpi_enable_fixed_events(struct acpi_softc *sc) 511 { 512 static int beenhere; 513 ACPI_STATUS rv; 514 515 /* 516 * Check for fixed-hardware buttons. 517 */ 518 519 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) { 520 if (beenhere == 0) 521 printf("%s: fixed-feature power button present\n", 522 sc->sc_dev.dv_xname); 523 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, 524 acpi_fixed_power_button_handler, sc); 525 if (rv != AE_OK) 526 printf("%s: unable to install handler for fixed " 527 "power button: %d\n", sc->sc_dev.dv_xname, rv); 528 } 529 530 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) { 531 if (beenhere == 0) 532 printf("%s: fixed-feature sleep button present\n", 533 sc->sc_dev.dv_xname); 534 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON, 535 acpi_fixed_sleep_button_handler, sc); 536 if (rv != AE_OK) 537 printf("%s: unable to install handler for fixed " 538 "power button: %d\n", sc->sc_dev.dv_xname, rv); 539 } 540 541 beenhere = 1; 542 } 543 544 /* 545 * acpi_fixed_power_button_handler: 546 * 547 * Fixed event handler for the power button. 548 */ 549 UINT32 550 acpi_fixed_power_button_handler(void *context) 551 { 552 struct acpi_softc *sc = context; 553 554 /* XXX XXX XXX */ 555 556 printf("%s: fixed power button pressed\n", sc->sc_dev.dv_xname); 557 558 return (INTERRUPT_HANDLED); 559 } 560 561 /* 562 * acpi_fixed_sleep_button_handler: 563 * 564 * Fixed event handler for the sleep button. 565 */ 566 UINT32 567 acpi_fixed_sleep_button_handler(void *context) 568 { 569 struct acpi_softc *sc = context; 570 571 /* XXX XXX XXX */ 572 573 printf("%s: fixed sleep button pressed\n", sc->sc_dev.dv_xname); 574 575 return (INTERRUPT_HANDLED); 576 } 577 578 /***************************************************************************** 579 * ACPI utility routines. 580 *****************************************************************************/ 581 582 /* 583 * acpi_eval_integer: 584 * 585 * Evaluate an integer object. 586 */ 587 ACPI_STATUS 588 acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp) 589 { 590 ACPI_STATUS rv; 591 ACPI_BUFFER buf; 592 ACPI_OBJECT param; 593 594 if (handle == NULL) 595 handle = ACPI_ROOT_OBJECT; 596 597 buf.Pointer = ¶m; 598 buf.Length = sizeof(param); 599 600 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 601 if (rv == AE_OK) { 602 if (param.Type == ACPI_TYPE_INTEGER) 603 *valp = param.Integer.Value; 604 else 605 rv = AE_TYPE; 606 } 607 608 return (rv); 609 } 610 611 /* 612 * acpi_eval_string: 613 * 614 * Evaluage a (Unicode) string object. 615 */ 616 ACPI_STATUS 617 acpi_eval_string(ACPI_HANDLE handle, char *path, char **stringp) 618 { 619 ACPI_STATUS rv; 620 ACPI_BUFFER buf; 621 ACPI_OBJECT param; 622 623 if (handle == NULL) 624 handle = ACPI_ROOT_OBJECT; 625 626 buf.Pointer = NULL; 627 buf.Length = 0; 628 629 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 630 if (rv != AE_BUFFER_OVERFLOW) 631 return (rv); 632 633 buf.Pointer = AcpiOsAllocate(buf.Length); 634 if (buf.Pointer == NULL) 635 return (AE_NO_MEMORY); 636 637 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 638 if (rv == AE_OK) { 639 if (param.Type == ACPI_TYPE_STRING) { 640 *stringp = buf.Pointer; 641 return (AE_OK); 642 } 643 rv = AE_TYPE; 644 } 645 646 AcpiOsFree(buf.Pointer); 647 return (rv); 648 } 649 650 /* 651 * acpi_get: 652 * 653 * Fetch data info the specified (empty) ACPI buffer. 654 */ 655 ACPI_STATUS 656 acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, 657 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) 658 { 659 ACPI_STATUS rv; 660 661 buf->Pointer = NULL; 662 buf->Length = 0; 663 664 rv = (*getit)(handle, buf); 665 if (rv != AE_BUFFER_OVERFLOW) 666 return (rv); 667 668 buf->Pointer = AcpiOsCallocate(buf->Length); 669 if (buf->Pointer == NULL) 670 return (AE_NO_MEMORY); 671 672 return ((*getit)(handle, buf)); 673 } 674