acpi.c revision 1.27
1/* $NetBSD: acpi.c,v 1.27 2003/01/05 22:33:21 christos 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.27 2003/01/05 22:33:21 christos Exp $"); 45 46#include "opt_acpi.h" 47 48#include <sys/param.h> 49#include <sys/systm.h> 50#include <sys/device.h> 51#include <sys/malloc.h> 52 53#include <dev/acpi/acpica.h> 54#include <dev/acpi/acpireg.h> 55#include <dev/acpi/acpivar.h> 56#include <dev/acpi/acpi_osd.h> 57#ifdef ACPIVERBOSE 58#include <dev/acpi/acpidevs_data.h> 59#endif 60 61#ifndef ACPI_PCI_FIXUP 62#define ACPI_PCI_FIXUP 1 63#endif 64 65#ifndef ACPI_ACTIVATE_DEV 66#define ACPI_ACTIVATE_DEV 0 67#endif 68 69#if ACPI_PCI_FIXUP 70#include <dev/acpi/acpica/Subsystem/acnamesp.h> /* AcpiNsGetNodeByPath() */ 71#include <dev/pci/pcidevs.h> 72#endif 73 74#include <machine/acpi_machdep.h> 75 76#ifdef ENABLE_DEBUGGER 77#define ACPI_DBGR_INIT 0x01 78#define ACPI_DBGR_TABLES 0x02 79#define ACPI_DBGR_ENABLE 0x04 80#define ACPI_DBGR_PROBE 0x08 81#define ACPI_DBGR_RUNNING 0x10 82 83int acpi_dbgr = 0x00; 84#endif 85 86int acpi_match(struct device *, struct cfdata *, void *); 87void acpi_attach(struct device *, struct device *, void *); 88 89int acpi_print(void *aux, const char *); 90 91extern struct cfdriver acpi_cd; 92 93CFATTACH_DECL(acpi, sizeof(struct acpi_softc), 94 acpi_match, acpi_attach, NULL, NULL); 95 96/* 97 * This is a flag we set when the ACPI subsystem is active. Machine 98 * dependent code may wish to skip other steps (such as attaching 99 * subsystems that ACPI supercedes) when ACPI is active. 100 */ 101int acpi_active; 102 103/* 104 * Pointer to the ACPI subsystem's state. There can be only 105 * one ACPI instance. 106 */ 107struct acpi_softc *acpi_softc; 108 109void acpi_shutdown(void *); 110ACPI_STATUS acpi_disable(struct acpi_softc *sc); 111void acpi_build_tree(struct acpi_softc *); 112ACPI_STATUS acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **); 113 114void acpi_enable_fixed_events(struct acpi_softc *); 115#if ACPI_PCI_FIXUP 116void acpi_pci_fixup(struct acpi_softc *); 117#endif 118#if ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV 119ACPI_STATUS acpi_allocate_resources(ACPI_HANDLE handle); 120#endif 121 122/* 123 * acpi_probe: 124 * 125 * Probe for ACPI support. This is called by the 126 * machine-dependent ACPI front-end. All of the 127 * actual work is done by ACPICA. 128 * 129 * NOTE: This is not an autoconfiguration interface function. 130 */ 131int 132acpi_probe(void) 133{ 134 static int beenhere; 135 ACPI_STATUS rv; 136 137 if (beenhere != 0) 138 panic("acpi_probe: ACPI has already been probed"); 139 beenhere = 1; 140 141 /* 142 * Start up ACPICA. 143 */ 144#ifdef ENABLE_DEBUGGER 145 if (acpi_dbgr & ACPI_DBGR_INIT) 146 acpi_osd_debugger(); 147#endif 148 149 rv = AcpiInitializeSubsystem(); 150 if (rv != AE_OK) { 151 printf("ACPI: unable to initialize ACPICA: %d\n", rv); 152 return (0); 153 } 154 155#ifdef ENABLE_DEBUGGER 156 if (acpi_dbgr & ACPI_DBGR_TABLES) 157 acpi_osd_debugger(); 158#endif 159 160 rv = AcpiLoadTables(); 161 if (rv != AE_OK) { 162 printf("ACPI: unable to load tables: %d\n", rv); 163 return (0); 164 } 165 166 /* 167 * Looks like we have ACPI! 168 */ 169 170 return (1); 171} 172 173/* 174 * acpi_match: 175 * 176 * Autoconfiguration `match' routine. 177 */ 178int 179acpi_match(struct device *parent, struct cfdata *match, void *aux) 180{ 181 struct acpibus_attach_args *aa = aux; 182 183 if (strcmp(aa->aa_busname, acpi_cd.cd_name) != 0) 184 return (0); 185 186 /* 187 * XXX Check other locators? Hard to know -- machine 188 * dependent code has already checked for the presence 189 * of ACPI by calling acpi_probe(), so I suppose we 190 * don't really have to do anything else. 191 */ 192 return (1); 193} 194 195/* 196 * acpi_attach: 197 * 198 * Autoconfiguration `attach' routine. Finish initializing 199 * ACPICA (some initialization was done in acpi_probe(), 200 * which was required to check for the presence of ACPI), 201 * and enable the ACPI subsystem. 202 */ 203void 204acpi_attach(struct device *parent, struct device *self, void *aux) 205{ 206 struct acpi_softc *sc = (void *) self; 207 struct acpibus_attach_args *aa = aux; 208 ACPI_STATUS rv; 209 210 printf("\n"); 211 212 if (acpi_softc != NULL) 213 panic("acpi_attach: ACPI has already been attached"); 214 215 sc->sc_iot = aa->aa_iot; 216 sc->sc_memt = aa->aa_memt; 217 sc->sc_pc = aa->aa_pc; 218 sc->sc_pciflags = aa->aa_pciflags; 219 sc->sc_ic = aa->aa_ic; 220 221 acpi_softc = sc; 222 223 /* 224 * Install the default address space handlers. 225 */ 226 227 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 228 ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL); 229 if (rv != AE_OK) { 230 printf("%s: unable to install SYSTEM MEMORY handler: %d\n", 231 sc->sc_dev.dv_xname, rv); 232 return; 233 } 234 235 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 236 ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL); 237 if (rv != AE_OK) { 238 printf("%s: unable to install SYSTEM IO handler: %d\n", 239 sc->sc_dev.dv_xname, rv); 240 return; 241 } 242 243 rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT, 244 ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); 245 if (rv != AE_OK) { 246 printf("%s: unable to install PCI CONFIG handler: %d\n", 247 sc->sc_dev.dv_xname, rv); 248 return; 249 } 250 251 /* 252 * Bring ACPI on-line. 253 * 254 * Note that we request that _STA (device init) and _INI (object init) 255 * methods not be run. 256 * 257 * XXX We need to arrange for the object init pass after we have 258 * XXX attached all of our children. 259 */ 260#ifdef ENABLE_DEBUGGER 261 if (acpi_dbgr & ACPI_DBGR_ENABLE) 262 acpi_osd_debugger(); 263#endif 264 rv = AcpiEnableSubsystem(ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT); 265 if (rv != AE_OK) { 266 printf("%s: unable to enable ACPI: %d\n", 267 sc->sc_dev.dv_xname, rv); 268 return; 269 } 270 acpi_active = 1; 271 272 /* 273 * Set up the default sleep state to enter when various 274 * switches are activated. 275 */ 276 sc->sc_switch_sleep[ACPI_SWITCH_POWERBUTTON] = ACPI_STATE_S5; 277 sc->sc_switch_sleep[ACPI_SWITCH_SLEEPBUTTON] = ACPI_STATE_S1; 278 sc->sc_switch_sleep[ACPI_SWITCH_LID] = ACPI_STATE_S1; 279 280 /* Our current state is "awake". */ 281 sc->sc_sleepstate = ACPI_STATE_S0; 282 283 /* Show SCI interrupt. */ 284 if (AcpiGbl_FADT != NULL) 285 printf("%s: SCI interrupting at irq %d\n", 286 sc->sc_dev.dv_xname, AcpiGbl_FADT->SciInt); 287 /* 288 * Check for fixed-hardware features. 289 */ 290 acpi_enable_fixed_events(sc); 291 292 /* 293 * Fix up PCI devices. 294 */ 295#if ACPI_PCI_FIXUP 296 acpi_pci_fixup(sc); 297#endif 298 299 /* 300 * Scan the namespace and build our device tree. 301 */ 302#ifdef ENABLE_DEBUGGER 303 if (acpi_dbgr & ACPI_DBGR_PROBE) 304 acpi_osd_debugger(); 305#endif 306 acpi_build_tree(sc); 307 308 /* 309 * Register a shutdown hook that disables certain ACPI 310 * events that might happen and confuse us while we're 311 * trying to shut down. 312 */ 313 sc->sc_sdhook = shutdownhook_establish(acpi_shutdown, sc); 314 if (sc->sc_sdhook == NULL) 315 printf("%s: WARNING: unable to register shutdown hook\n", 316 sc->sc_dev.dv_xname); 317 318#ifdef ENABLE_DEBUGGER 319 if (acpi_dbgr & ACPI_DBGR_RUNNING) 320 acpi_osd_debugger(); 321#endif 322} 323 324/* 325 * acpi_shutdown: 326 * 327 * Shutdown hook for ACPI -- disable some events that 328 * might confuse us. 329 */ 330void 331acpi_shutdown(void *arg) 332{ 333 struct acpi_softc *sc = arg; 334 335 if (acpi_disable(sc) != AE_OK) 336 printf("%s: WARNING: unable to disable ACPI\n", 337 sc->sc_dev.dv_xname); 338} 339 340/* 341 * acpi_disable: 342 * 343 * Disable ACPI. 344 */ 345ACPI_STATUS 346acpi_disable(struct acpi_softc *sc) 347{ 348 ACPI_STATUS rv = AE_OK; 349 350 if (acpi_active) { 351 rv = AcpiDisable(); 352 if (rv == AE_OK) 353 acpi_active = 0; 354 } 355 return (rv); 356} 357 358struct acpi_make_devnode_state { 359 struct acpi_softc *softc; 360 struct acpi_scope *scope; 361}; 362 363/* 364 * acpi_build_tree: 365 * 366 * Scan relevant portions of the ACPI namespace and attach 367 * child devices. 368 */ 369void 370acpi_build_tree(struct acpi_softc *sc) 371{ 372 static const char *scopes[] = { 373 "\\_PR_", /* ACPI 1.0 processor namespace */ 374 "\\_SB_", /* system bus namespace */ 375 "\\_SI_", /* system idicator namespace */ 376 "\\_TZ_", /* ACPI 1.0 thermal zone namespace */ 377 NULL, 378 }; 379 struct acpi_attach_args aa; 380 struct acpi_make_devnode_state state; 381 struct acpi_scope *as; 382 struct acpi_devnode *ad; 383 ACPI_HANDLE parent; 384 int i; 385 386 TAILQ_INIT(&sc->sc_scopes); 387 388 state.softc = sc; 389 390 /* 391 * Scan the namespace and build our tree. 392 */ 393 for (i = 0; scopes[i] != NULL; i++) { 394 as = malloc(sizeof(*as), M_DEVBUF, M_WAITOK); 395 as->as_name = scopes[i]; 396 TAILQ_INIT(&as->as_devnodes); 397 398 TAILQ_INSERT_TAIL(&sc->sc_scopes, as, as_list); 399 400 state.scope = as; 401 402 if (AcpiGetHandle(ACPI_ROOT_OBJECT, (char *) scopes[i], 403 &parent) == AE_OK) { 404 AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100, 405 acpi_make_devnode, &state, NULL); 406 } 407 408 /* Now, for this namespace, try and attach the devices. */ 409 TAILQ_FOREACH(ad, &as->as_devnodes, ad_list) { 410 aa.aa_node = ad; 411 aa.aa_iot = sc->sc_iot; 412 aa.aa_memt = sc->sc_memt; 413 aa.aa_pc = sc->sc_pc; 414 aa.aa_pciflags = sc->sc_pciflags; 415 aa.aa_ic = sc->sc_ic; 416 417 if (ad->ad_devinfo.Type == ACPI_TYPE_DEVICE) { 418 /* 419 * XXX We only attach devices which are: 420 * 421 * - present 422 * - enabled 423 * - functioning properly 424 * 425 * However, if enabled, it's decoding resources, 426 * so we should claim them, if possible. 427 * Requires changes to bus_space(9). 428 */ 429 if ((ad->ad_devinfo.CurrentStatus & 430 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED| 431 ACPI_STA_DEV_OK)) != 432 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED| 433 ACPI_STA_DEV_OK)) 434 continue; 435 436 /* 437 * XXX Same problem as above... 438 */ 439 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) 440 == 0) 441 continue; 442 } 443 444 ad->ad_device = config_found(&sc->sc_dev, 445 &aa, acpi_print); 446 } 447 } 448} 449 450#if ACPI_ACTIVATE_DEV 451static void 452acpi_activate_device(ACPI_HANDLE handle, ACPI_DEVICE_INFO *di) 453{ 454 ACPI_STATUS rv; 455 456#ifdef ACPI_DEBUG 457 printf("acpi_activate_device: %s, old status=%x\n", 458 di->HardwareId, di->CurrentStatus); 459#endif 460 461 rv = acpi_allocate_resources(handle); 462 if (ACPI_FAILURE(rv)) { 463 printf("acpi: activate failed for %s\n", di->HardwareId); 464 } else { 465 printf("acpi: activated %s\n", di->HardwareId); 466 } 467 468 (void)AcpiGetObjectInfo(handle, di); 469#ifdef ACPI_DEBUG 470 printf("acpi_activate_device: %s, new status=%x\n", 471 di->HardwareId, di->CurrentStatus); 472#endif 473} 474#endif /* ACPI_ACTIVATE_DEV */ 475 476/* 477 * acpi_make_devnode: 478 * 479 * Make an ACPI devnode. 480 */ 481ACPI_STATUS 482acpi_make_devnode(ACPI_HANDLE handle, UINT32 level, void *context, 483 void **status) 484{ 485 struct acpi_make_devnode_state *state = context; 486#if defined(ACPI_DEBUG) || defined(ACPI_EXTRA_DEBUG) 487 struct acpi_softc *sc = state->softc; 488#endif 489 struct acpi_scope *as = state->scope; 490 struct acpi_devnode *ad; 491 ACPI_DEVICE_INFO devinfo; 492 ACPI_OBJECT_TYPE type; 493 ACPI_STATUS rv; 494 495 if (AcpiGetType(handle, &type) == AE_OK) { 496 rv = AcpiGetObjectInfo(handle, &devinfo); 497 if (rv != AE_OK) { 498#ifdef ACPI_DEBUG 499 printf("%s: AcpiGetObjectInfo failed\n", 500 sc->sc_dev.dv_xname); 501#endif 502 goto out; /* XXX why return OK */ 503 } 504 505 switch (type) { 506 case ACPI_TYPE_DEVICE: 507#if ACPI_ACTIVATE_DEV 508 if ((devinfo.Valid & ACPI_VALID_STA) && 509 (devinfo.CurrentStatus & 510 (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED)) == 511 ACPI_STA_DEV_PRESENT) 512 acpi_activate_device(handle, &devinfo); 513 /* FALLTHROUGH */ 514#endif 515 516 case ACPI_TYPE_PROCESSOR: 517 case ACPI_TYPE_THERMAL: 518 case ACPI_TYPE_POWER: 519 ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT|M_ZERO); 520 if (ad == NULL) 521 return (AE_NO_MEMORY); 522 523 ad->ad_handle = handle; 524 ad->ad_level = level; 525 ad->ad_scope = as; 526 ad->ad_type = type; 527 528 TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list); 529 530 rv = AcpiGetObjectInfo(handle, &ad->ad_devinfo); 531 if (rv != AE_OK) 532 goto out; 533 534 if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0) 535 goto out; 536 537#ifdef ACPI_EXTRA_DEBUG 538 printf("%s: HID %s found in scope %s level %d\n", 539 sc->sc_dev.dv_xname, ad->ad_devinfo.HardwareId, 540 as->as_name, ad->ad_level); 541 if (ad->ad_devinfo.Valid & ACPI_VALID_UID) 542 printf(" UID %s\n", 543 ad->ad_devinfo.UniqueId); 544 if (ad->ad_devinfo.Valid & ACPI_VALID_ADR) 545 printf(" ADR 0x%016qx\n", 546 ad->ad_devinfo.Address); 547 if (ad->ad_devinfo.Valid & ACPI_VALID_STA) 548 printf(" STA 0x%08x\n", 549 ad->ad_devinfo.CurrentStatus); 550#endif 551 } 552 } 553 out: 554 return (AE_OK); 555} 556 557/* 558 * acpi_print: 559 * 560 * Autoconfiguration print routine. 561 */ 562int 563acpi_print(void *aux, const char *pnp) 564{ 565 struct acpi_attach_args *aa = aux; 566 567 if (pnp) { 568 if (aa->aa_node->ad_devinfo.Valid & ACPI_VALID_HID) { 569 char *pnpstr = aa->aa_node->ad_devinfo.HardwareId; 570 char *str; 571 572 aprint_normal("%s ", pnpstr); 573 if (acpi_eval_string(aa->aa_node->ad_handle, 574 "_STR", &str) == AE_OK) { 575 aprint_normal("[%s] ", str); 576 AcpiOsFree(str); 577 } 578#ifdef ACPIVERBOSE 579 else { 580 int i; 581 582 for (i = 0; i < sizeof(acpi_knowndevs) / 583 sizeof(acpi_knowndevs[0]); i++) { 584 if (strcmp(acpi_knowndevs[i].pnp, 585 pnpstr) == 0) { 586 printf("[%s] ", 587 acpi_knowndevs[i].str); 588 } 589 } 590 } 591 592#endif 593 } else { 594 /* XXX print something more meaningful.. */ 595 aprint_normal("ACPI Object Type 0x%02x ", 596 aa->aa_node->ad_devinfo.Type); 597 } 598 aprint_normal("at %s", pnp); 599 } else { 600 aprint_normal(" (%s", aa->aa_node->ad_devinfo.HardwareId); 601 if (aa->aa_node->ad_devinfo.Valid & ACPI_VALID_UID) { 602 char *uid; 603 604 if (aa->aa_node->ad_devinfo.UniqueId[0] == '\0') 605 uid = "<null>"; 606 else 607 uid = aa->aa_node->ad_devinfo.UniqueId; 608 aprint_normal("-%s", uid); 609 } 610 aprint_normal(")"); 611 } 612 613 return (UNCONF); 614} 615 616/***************************************************************************** 617 * ACPI fixed-hardware feature handlers 618 *****************************************************************************/ 619 620UINT32 acpi_fixed_power_button_handler(void *); 621UINT32 acpi_fixed_sleep_button_handler(void *); 622 623/* 624 * acpi_enable_fixed_events: 625 * 626 * Enable any fixed-hardware feature handlers. 627 */ 628void 629acpi_enable_fixed_events(struct acpi_softc *sc) 630{ 631 static int beenhere; 632 ACPI_STATUS rv; 633 634 /* 635 * Check for fixed-hardware buttons. 636 */ 637 638 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) { 639 if (beenhere == 0) 640 printf("%s: fixed-feature power button present\n", 641 sc->sc_dev.dv_xname); 642 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, 643 acpi_fixed_power_button_handler, sc); 644 if (rv != AE_OK) 645 printf("%s: unable to install handler for fixed " 646 "power button: %d\n", sc->sc_dev.dv_xname, rv); 647 } 648 649 if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) { 650 if (beenhere == 0) 651 printf("%s: fixed-feature sleep button present\n", 652 sc->sc_dev.dv_xname); 653 rv = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON, 654 acpi_fixed_sleep_button_handler, sc); 655 if (rv != AE_OK) 656 printf("%s: unable to install handler for fixed " 657 "power button: %d\n", sc->sc_dev.dv_xname, rv); 658 } 659 660 beenhere = 1; 661} 662 663/* 664 * acpi_fixed_power_button_handler: 665 * 666 * Fixed event handler for the power button. 667 */ 668UINT32 669acpi_fixed_power_button_handler(void *context) 670{ 671 struct acpi_softc *sc = context; 672 673 /* XXX XXX XXX */ 674 675 printf("%s: fixed power button pressed\n", sc->sc_dev.dv_xname); 676 677 return (ACPI_INTERRUPT_HANDLED); 678} 679 680/* 681 * acpi_fixed_sleep_button_handler: 682 * 683 * Fixed event handler for the sleep button. 684 */ 685UINT32 686acpi_fixed_sleep_button_handler(void *context) 687{ 688 struct acpi_softc *sc = context; 689 690 /* XXX XXX XXX */ 691 692 printf("%s: fixed sleep button pressed\n", sc->sc_dev.dv_xname); 693 694 return (ACPI_INTERRUPT_HANDLED); 695} 696 697/***************************************************************************** 698 * ACPI utility routines. 699 *****************************************************************************/ 700 701/* 702 * acpi_eval_integer: 703 * 704 * Evaluate an integer object. 705 */ 706ACPI_STATUS 707acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp) 708{ 709 ACPI_STATUS rv; 710 ACPI_BUFFER buf; 711 ACPI_OBJECT param; 712 713 if (handle == NULL) 714 handle = ACPI_ROOT_OBJECT; 715 716 buf.Pointer = ¶m; 717 buf.Length = sizeof(param); 718 719 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 720 if (rv == AE_OK) { 721 if (param.Type == ACPI_TYPE_INTEGER) 722 *valp = param.Integer.Value; 723 else 724 rv = AE_TYPE; 725 } 726 727 return (rv); 728} 729 730/* 731 * acpi_eval_string: 732 * 733 * Evaluate a (Unicode) string object. 734 */ 735ACPI_STATUS 736acpi_eval_string(ACPI_HANDLE handle, char *path, char **stringp) 737{ 738 ACPI_STATUS rv; 739 ACPI_BUFFER buf; 740 ACPI_OBJECT *param; 741 742 if (handle == NULL) 743 handle = ACPI_ROOT_OBJECT; 744 745 buf.Pointer = NULL; 746 buf.Length = 0; 747 748 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 749 if (rv != AE_BUFFER_OVERFLOW) 750 return (rv); 751 752 buf.Pointer = AcpiOsAllocate(buf.Length); 753 if (buf.Pointer == NULL) 754 return (AE_NO_MEMORY); 755 756 rv = AcpiEvaluateObject(handle, path, NULL, &buf); 757 param = (ACPI_OBJECT *)buf.Pointer; 758 if (rv == AE_OK) { 759 if (param->Type == ACPI_TYPE_STRING) { 760 char *ptr = param->String.Pointer; 761 size_t len; 762 while (*ptr++) 763 continue; 764 len = ptr - param->String.Pointer; 765 if ((*stringp = AcpiOsAllocate(len)) == NULL) { 766 rv = AE_NO_MEMORY; 767 goto done; 768 } 769 (void)memcpy(*stringp, param->String.Pointer, len); 770 goto done; 771 } 772 rv = AE_TYPE; 773 } 774done: 775 AcpiOsFree(buf.Pointer); 776 return (rv); 777} 778 779 780/* 781 * acpi_eval_struct: 782 * 783 * Evaluate a more complex structure. Caller must free buf.Pointer. 784 */ 785ACPI_STATUS 786acpi_eval_struct(ACPI_HANDLE handle, char *path, ACPI_BUFFER *bufp) 787{ 788 ACPI_STATUS rv; 789 790 if (handle == NULL) 791 handle = ACPI_ROOT_OBJECT; 792 793 bufp->Pointer = NULL; 794 bufp->Length = 0; 795 796 rv = AcpiEvaluateObject(handle, path, NULL, bufp); 797 if (rv != AE_BUFFER_OVERFLOW) 798 return (rv); 799 800 bufp->Pointer = AcpiOsAllocate(bufp->Length); 801 if (bufp->Pointer == NULL) 802 return (AE_NO_MEMORY); 803 804 rv = AcpiEvaluateObject(handle, path, NULL, bufp); 805 806 return (rv); 807} 808 809/* 810 * acpi_get: 811 * 812 * Fetch data info the specified (empty) ACPI buffer. 813 */ 814ACPI_STATUS 815acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf, 816 ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *)) 817{ 818 ACPI_STATUS rv; 819 820 buf->Pointer = NULL; 821 buf->Length = 0; 822 823 rv = (*getit)(handle, buf); 824 if (rv != AE_BUFFER_OVERFLOW) 825 return (rv); 826 827 buf->Pointer = AcpiOsAllocate(buf->Length); 828 if (buf->Pointer == NULL) 829 return (AE_NO_MEMORY); 830 memset(buf->Pointer, 0, buf->Length); 831 832 return ((*getit)(handle, buf)); 833} 834 835 836/***************************************************************************** 837 * ACPI sleep support. 838 *****************************************************************************/ 839 840static int 841is_available_state(struct acpi_softc *sc, int state) 842{ 843 UINT8 type_a, type_b; 844 845 return (ACPI_SUCCESS(AcpiGetSleepTypeData((UINT8)state, 846 &type_a, &type_b))); 847} 848 849/* 850 * acpi_enter_sleep_state: 851 * 852 * enter to the specified sleep state. 853 */ 854 855ACPI_STATUS 856acpi_enter_sleep_state(struct acpi_softc *sc, int state) 857{ 858 int s; 859 ACPI_STATUS ret = AE_OK; 860 861 switch (state) { 862 case ACPI_STATE_S0: 863 break; 864 case ACPI_STATE_S1: 865 case ACPI_STATE_S2: 866 case ACPI_STATE_S3: 867 case ACPI_STATE_S4: 868 if (!is_available_state(sc, state)) { 869 printf("acpi: cannot enter the sleep state (%d).\n", 870 state); 871 break; 872 } 873 ret = AcpiEnterSleepStatePrep(state); 874 if (ACPI_FAILURE(ret)) { 875 printf("acpi: failed preparing to sleep (%s)\n", 876 AcpiFormatException(ret)); 877 break; 878 } 879 if (state==ACPI_STATE_S1) { 880 /* just enter the state */ 881 acpi_md_OsDisableInterrupt(); 882 AcpiEnterSleepState((UINT8)state); 883 AcpiUtReleaseMutex(ACPI_MTX_HARDWARE); 884 } else { 885 /* XXX: powerhooks(9) framework is too poor to 886 * support ACPI sleep state... 887 */ 888 dopowerhooks(PWR_SOFTSUSPEND); 889 s = splhigh(); 890 dopowerhooks(PWR_SUSPEND); 891 acpi_md_sleep(state); 892 dopowerhooks(PWR_RESUME); 893 splx(s); 894 dopowerhooks(PWR_SOFTRESUME); 895 if (state==ACPI_STATE_S4) 896 AcpiEnable(); 897 } 898 AcpiLeaveSleepState((UINT8)state); 899 break; 900 case ACPI_STATE_S5: 901 AcpiEnterSleepStatePrep(ACPI_STATE_S5); 902 acpi_md_OsDisableInterrupt(); 903 AcpiEnterSleepState(ACPI_STATE_S5); 904 printf("WARNING: powerdown failed!\n"); 905 break; 906 } 907 908 return (ret); 909} 910 911#if ACPI_PCI_FIXUP 912ACPI_STATUS acpi_pci_fixup_bus(ACPI_HANDLE, UINT32, void *, void **); 913/* 914 * acpi_pci_fixup: 915 * 916 * Set up PCI devices that BIOS didn't handle right. 917 * Iterate through all devices and try to get the _PTR 918 * (PCI Routing Table). If it exists then make sure all 919 * interrupt links that it uses are working. 920 */ 921void 922acpi_pci_fixup(struct acpi_softc *sc) 923{ 924 ACPI_HANDLE parent; 925 926#ifdef ACPI_DEBUG 927 printf("acpi_pci_fixup starts:\n"); 928#endif 929 if (AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &parent) != AE_OK) 930 return; 931 sc->sc_pci_bus = 0; 932 AcpiWalkNamespace(ACPI_TYPE_DEVICE, parent, 100, 933 acpi_pci_fixup_bus, sc, NULL); 934} 935 936static ACPI_HANDLE 937acpi_get_node(char *name) 938{ 939 ACPI_NAMESPACE_NODE *ObjDesc; 940 ACPI_STATUS Status; 941 942 Status = AcpiNsGetNodeByPath(name, NULL, 0, &ObjDesc); 943 if (ACPI_FAILURE (Status)) { 944 printf("acpi_get_node: could not find: %s\n", 945 AcpiFormatException (Status)); 946 return NULL; 947 } 948 return ObjDesc; 949} 950 951static uint 952acpi_get_intr(ACPI_HANDLE handle) 953{ 954 ACPI_BUFFER ret; 955 ACPI_STATUS rv; 956 ACPI_RESOURCE *res; 957 ACPI_RESOURCE_IRQ *irq; 958 uint intr; 959 960 intr = -1; 961 rv = acpi_get(handle, &ret, AcpiGetCurrentResources); 962 if (ACPI_FAILURE(rv)) 963 return (intr); 964 for (res = ret.Pointer; res->Id != ACPI_RSTYPE_END_TAG; 965 res = ACPI_NEXT_RESOURCE(res)) { 966 if (res->Id == ACPI_RSTYPE_IRQ) { 967 irq = (ACPI_RESOURCE_IRQ *)&res->Data; 968 if (irq->NumberOfInterrupts == 1) 969 intr = irq->Interrupts[0]; 970 break; 971 } 972 } 973 free(ret.Pointer, M_DEVBUF); 974 return (intr); 975} 976 977static void 978acpi_pci_set_line(int bus, int dev, int pin, int line) 979{ 980 ACPI_STATUS err; 981 ACPI_PCI_ID pid; 982 UINT32 intr, id, bhlc; 983 int func, nfunc; 984 985 pid.Bus = bus; 986 pid.Device = dev; 987 pid.Function = 0; 988 989 err = AcpiOsReadPciConfiguration(&pid, PCI_BHLC_REG, &bhlc, 32); 990 if (err) 991 return; 992 if (PCI_HDRTYPE_MULTIFN(bhlc)) 993 nfunc = 8; 994 else 995 nfunc = 1; 996 997 for (func = 0; func < nfunc; func++) { 998 pid.Function = func; 999 1000 err = AcpiOsReadPciConfiguration(&pid, PCI_ID_REG, &id, 32); 1001 if (err || PCI_VENDOR(id) == PCI_VENDOR_INVALID || 1002 PCI_VENDOR(id) == 0) 1003 continue; 1004 1005 err = AcpiOsReadPciConfiguration(&pid, PCI_INTERRUPT_REG, 1006 &intr, 32); 1007 if (err) { 1008 printf("AcpiOsReadPciConfiguration failed %d\n", err); 1009 return; 1010 } 1011 if (pin == PCI_INTERRUPT_PIN(intr) && 1012 line != PCI_INTERRUPT_LINE(intr)) { 1013#ifdef ACPI_DEBUG 1014 printf("acpi fixup pci intr: %d:%d:%d %c: %d -> %d\n", 1015 bus, dev, func, 1016 pin + '@', PCI_INTERRUPT_LINE(intr), 1017 line); 1018#endif 1019 intr &= ~(PCI_INTERRUPT_LINE_MASK << 1020 PCI_INTERRUPT_LINE_SHIFT); 1021 intr |= line << PCI_INTERRUPT_LINE_SHIFT; 1022 err = AcpiOsWritePciConfiguration(&pid, 1023 PCI_INTERRUPT_REG, intr, 32); 1024 if (err) { 1025 printf("AcpiOsWritePciConfiguration failed" 1026 " %d\n", err); 1027 return; 1028 } 1029 } 1030 } 1031} 1032 1033ACPI_STATUS 1034acpi_pci_fixup_bus(ACPI_HANDLE handle, UINT32 level, void *context, 1035 void **status) 1036{ 1037 struct acpi_softc *sc = context; 1038 ACPI_STATUS rv; 1039 ACPI_BUFFER buf; 1040 UINT8 *Buffer; 1041 ACPI_PCI_ROUTING_TABLE *PrtElement; 1042 ACPI_HANDLE link; 1043 uint line; 1044 1045 rv = acpi_get(handle, &buf, AcpiGetIrqRoutingTable); 1046 if (ACPI_FAILURE(rv)) 1047 return (AE_OK); 1048 1049#ifdef ACPI_DEBUG 1050 printf("%s: fixing up PCI bus %d\n", sc->sc_dev.dv_xname, 1051 sc->sc_pci_bus); 1052#endif 1053 1054 for (Buffer = buf.Pointer; ; Buffer += PrtElement->Length) { 1055 PrtElement = (ACPI_PCI_ROUTING_TABLE *)Buffer; 1056 if (PrtElement->Length == 0) 1057 break; 1058 if (PrtElement->Source == NULL) 1059 continue; 1060 1061 link = acpi_get_node(PrtElement->Source); 1062 if (link == NULL) 1063 continue; 1064 line = acpi_get_intr(link); 1065 if (line == -1) { 1066#ifdef ACPI_DEBUG 1067 printf("%s: fixing up intr link %s\n", 1068 sc->sc_dev.dv_xname, PrtElement->Source); 1069#endif 1070 rv = acpi_allocate_resources(link); 1071 if (ACPI_FAILURE(rv)) { 1072 printf("%s: interrupt allocation failed %s\n", 1073 sc->sc_dev.dv_xname, PrtElement->Source); 1074 continue; 1075 } 1076 line = acpi_get_intr(link); 1077 if (line == -1) { 1078 printf("%s: get intr failed %s\n", 1079 sc->sc_dev.dv_xname, PrtElement->Source); 1080 continue; 1081 } 1082 } 1083 1084 acpi_pci_set_line(sc->sc_pci_bus, PrtElement->Address >> 16, 1085 PrtElement->Pin + 1, line); 1086 } 1087 1088 sc->sc_pci_bus++; 1089 1090 free(buf.Pointer, M_DEVBUF); 1091 return (AE_OK); 1092} 1093#endif /* ACPI_PCI_FIXUP */ 1094 1095#if ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV 1096/* XXX This very incomplete */ 1097ACPI_STATUS 1098acpi_allocate_resources(ACPI_HANDLE handle) 1099{ 1100 ACPI_BUFFER bufp, bufc, bufn; 1101 ACPI_RESOURCE *resp, *resc, *resn; 1102 ACPI_RESOURCE_IRQ *irq; 1103 ACPI_STATUS rv; 1104 uint delta; 1105 1106 rv = acpi_get(handle, &bufp, AcpiGetPossibleResources); 1107 if (ACPI_FAILURE(rv)) 1108 goto out; 1109 rv = acpi_get(handle, &bufc, AcpiGetCurrentResources); 1110 if (ACPI_FAILURE(rv)) { 1111 goto out1; 1112 } 1113 1114 bufn.Length = 1000; 1115 bufn.Pointer = resn = malloc(bufn.Length, M_DEVBUF, M_WAITOK); 1116 resp = bufp.Pointer; 1117 resc = bufc.Pointer; 1118 while (resc->Id != ACPI_RSTYPE_END_TAG && 1119 resp->Id != ACPI_RSTYPE_END_TAG) { 1120 while (resc->Id != resp->Id && resp->Id != ACPI_RSTYPE_END_TAG) 1121 resp = ACPI_NEXT_RESOURCE(resp); 1122 if (resp->Id == ACPI_RSTYPE_END_TAG) 1123 break; 1124 /* Found identical Id */ 1125 resn->Id = resc->Id; 1126 switch (resc->Id) { 1127 case ACPI_RSTYPE_IRQ: 1128 memcpy(&resn->Data, &resp->Data, 1129 sizeof(ACPI_RESOURCE_IRQ)); 1130 irq = (ACPI_RESOURCE_IRQ *)&resn->Data; 1131 irq->Interrupts[0] = 1132 ((ACPI_RESOURCE_IRQ *)&resp->Data)-> 1133 Interrupts[irq->NumberOfInterrupts-1]; 1134 irq->NumberOfInterrupts = 1; 1135 resn->Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ); 1136 break; 1137 case ACPI_RSTYPE_IO: 1138 memcpy(&resn->Data, &resp->Data, 1139 sizeof(ACPI_RESOURCE_IO)); 1140 resn->Length = resp->Length; 1141 break; 1142 default: 1143 printf("acpi_allocate_resources: res=%d\n", resc->Id); 1144 rv = AE_BAD_DATA; 1145 goto out2; 1146 } 1147 resc = ACPI_NEXT_RESOURCE(resc); 1148 resn = ACPI_NEXT_RESOURCE(resn); 1149 delta = (UINT8 *)resn - (UINT8 *)bufn.Pointer; 1150 if (delta >= 1151 bufn.Length-ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_DATA)) { 1152 bufn.Length *= 2; 1153 bufn.Pointer = realloc(bufn.Pointer, bufn.Length, 1154 M_DEVBUF, M_WAITOK); 1155 resn = (ACPI_RESOURCE *)((UINT8 *)bufn.Pointer + delta); 1156 } 1157 } 1158 if (resc->Id != ACPI_RSTYPE_END_TAG) { 1159 printf("acpi_allocate_resources: resc not exhausted\n"); 1160 rv = AE_BAD_DATA; 1161 goto out3; 1162 } 1163 1164 resn->Id = ACPI_RSTYPE_END_TAG; 1165 rv = AcpiSetCurrentResources(handle, &bufn); 1166 if (ACPI_FAILURE(rv)) { 1167 printf("acpi_allocate_resources: AcpiSetCurrentResources %s\n", 1168 AcpiFormatException(rv)); 1169 } 1170 1171out3: 1172 free(bufn.Pointer, M_DEVBUF); 1173out2: 1174 free(bufc.Pointer, M_DEVBUF); 1175out1: 1176 free(bufp.Pointer, M_DEVBUF); 1177out: 1178 return rv; 1179} 1180#endif /* ACPI_PCI_FIXUP || ACPI_ACTIVATE_DEV */ 1181