acpi.c revision 1.4
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 60int acpi_dbgr = 0x00; 61#endif 62 63int acpi_match(struct device *, struct cfdata *, void *); 64void acpi_attach(struct device *, struct device *, void *); 65 66int acpi_print(void *aux, const char *); 67 68extern struct cfdriver acpi_cd; 69 70struct 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 */ 79int acpi_active; 80 81/* 82 * Pointer to the ACPI subsystem's state. There can be only 83 * one ACPI instance. 84 */ 85struct acpi_softc *acpi_softc; 86 87void acpi_shutdown(void *); 88ACPI_STATUS acpi_disable(struct acpi_softc *sc); 89void acpi_build_tree(struct acpi_softc *); 90ACPI_STATUS acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **); 91 92void 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 */ 103int 104acpi_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 */ 150int 151acpi_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 */ 175void 176acpi_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 */ 290void 291acpi_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 */ 305ACPI_STATUS 306acpi_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 318struct 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 */ 329void 330acpi_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 */ 412ACPI_STATUS 413acpi_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 */ 475int 476acpi_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 498UINT32 acpi_fixed_power_button_handler(void *); 499UINT32 acpi_fixed_sleep_button_handler(void *); 500 501/* 502 * acpi_enable_fixed_events: 503 * 504 * Enable any fixed-hardware feature handlers. 505 */ 506void 507acpi_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 */ 546UINT32 547acpi_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 */ 563UINT32 564acpi_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 */ 584ACPI_STATUS 585acpi_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 */ 613ACPI_STATUS 614acpi_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 */ 652ACPI_STATUS 653acpi_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