acpi.c revision 1.16
1/* $OpenBSD: acpi.c,v 1.16 2006/01/05 22:58:42 grange Exp $ */ 2/* 3 * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> 4 * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> 20#include <sys/systm.h> 21#include <sys/device.h> 22#include <sys/malloc.h> 23#include <sys/fcntl.h> 24#include <sys/ioccom.h> 25#include <sys/event.h> 26#include <sys/signalvar.h> 27#include <sys/proc.h> 28 29#include <machine/conf.h> 30#include <machine/bus.h> 31 32#include <dev/acpi/acpireg.h> 33#include <dev/acpi/acpivar.h> 34#include <dev/acpi/amltypes.h> 35#include <dev/acpi/dsdt.h> 36 37#ifdef ACPI_DEBUG 38int acpi_debug = 60; 39#endif 40 41#define ACPIEN_RETRIES 15 42 43int acpi_match(struct device *, void *, void *); 44void acpi_attach(struct device *, struct device *, void *); 45int acpi_submatch(struct device *, void *, void *); 46int acpi_print(void *, const char *); 47 48void acpi_map_pmregs(struct acpi_softc *); 49void acpi_unmap_pmregs(struct acpi_softc *); 50int acpi_read_pmreg(struct acpi_softc *, int); 51void acpi_write_pmreg(struct acpi_softc *, int, int); 52 53void acpi_gpe(struct aml_node *, void *); 54void acpi_foundhid(struct aml_node *, void *); 55 56int acpi_loadtables(struct acpi_softc *, struct acpi_rsdp *); 57void acpi_load_table(paddr_t, size_t, acpi_qhead_t *); 58void acpi_load_dsdt(paddr_t, struct acpi_q **); 59 60void acpi_softintr(void *); 61void acpi_init_states(struct acpi_softc *); 62 63void acpi_filtdetach(struct knote *); 64int acpi_filtread(struct knote *, long); 65 66#define ACPI_LOCK(sc) 67#define ACPI_UNLOCK(sc) 68 69/* XXX move this into dsdt softc at some point */ 70extern struct aml_node aml_root; 71 72struct filterops acpiread_filtops = { 73 1, NULL, acpi_filtdetach, acpi_filtread 74}; 75 76struct cfattach acpi_ca = { 77 sizeof(struct acpi_softc), acpi_match, acpi_attach 78}; 79 80struct cfdriver acpi_cd = { 81 NULL, "acpi", DV_DULL 82}; 83 84struct acpi_softc *acpi_softc; 85int acpi_s5, acpi_evindex, icount; 86 87/* Map Power Management registers */ 88void 89acpi_map_pmregs(struct acpi_softc *sc) 90{ 91 bus_addr_t addr; 92 bus_size_t size; 93 const char *name; 94 int reg; 95 96 for (reg = 0; reg < ACPIREG_MAXREG; reg++) { 97 size = 0; 98 switch (reg) { 99 case ACPIREG_SMICMD: 100 name = "smi"; 101 size = 1; 102 addr = sc->sc_fadt->smi_cmd; 103 break; 104 case ACPIREG_PM1A_STS: 105 case ACPIREG_PM1A_EN: 106 name = "pm1a_sts"; 107 size = sc->sc_fadt->pm1_evt_len >> 1; 108 addr = sc->sc_fadt->pm1a_evt_blk; 109 if (reg == ACPIREG_PM1A_EN && addr) { 110 addr += size; 111 name = "pm1a_en"; 112 } 113 break; 114 case ACPIREG_PM1A_CNT: 115 name = "pm1a_cnt"; 116 size = sc->sc_fadt->pm1_cnt_len; 117 addr = sc->sc_fadt->pm1a_cnt_blk; 118 break; 119 case ACPIREG_PM1B_STS: 120 case ACPIREG_PM1B_EN: 121 name = "pm1b_sts"; 122 size = sc->sc_fadt->pm1_evt_len >> 1; 123 addr = sc->sc_fadt->pm1b_evt_blk; 124 if (reg == ACPIREG_PM1B_EN && addr) { 125 addr += size; 126 name = "pm1b_en"; 127 } 128 break; 129 case ACPIREG_PM1B_CNT: 130 name = "pm1b_cnt"; 131 size = sc->sc_fadt->pm1_cnt_len; 132 addr = sc->sc_fadt->pm1b_cnt_blk; 133 break; 134 case ACPIREG_PM2_CNT: 135 name = "pm2_cnt"; 136 size = sc->sc_fadt->pm2_cnt_len; 137 addr = sc->sc_fadt->pm2_cnt_blk; 138 break; 139#if 0 140 case ACPIREG_PM_TMR: 141 /* Allocated in acpitimer */ 142 name = "pm_tmr"; 143 size = sc->sc_fadt->pm_tmr_len; 144 addr = sc->sc_fadt->pm_tmr_blk; 145 break; 146#endif 147 case ACPIREG_GPE0_STS: 148 case ACPIREG_GPE0_EN: 149 name = "gpe0_sts"; 150 size = sc->sc_fadt->gpe0_blk_len >> 1; 151 addr = sc->sc_fadt->gpe0_blk; 152 if (reg == ACPIREG_GPE0_EN && addr) { 153 addr += size; 154 name = "gpe0_en"; 155 } 156 break; 157 case ACPIREG_GPE1_STS: 158 case ACPIREG_GPE1_EN: 159 name = "gpe1_sts"; 160 size = sc->sc_fadt->gpe1_blk_len >> 1; 161 addr = sc->sc_fadt->gpe1_blk; 162 if (reg == ACPIREG_GPE1_EN && addr) { 163 addr += size; 164 name = "gpe1_en"; 165 } 166 break; 167 } 168 if (size && addr) { 169 dnprintf(50, "mapping: %.4x %.4x %s\n", 170 addr, size, name); 171 172 /* Size and address exist; map register space */ 173 bus_space_map(sc->sc_iot, addr, size, 0, 174 &sc->sc_pmregs[reg].ioh); 175 176 sc->sc_pmregs[reg].name = name; 177 sc->sc_pmregs[reg].size = size; 178 sc->sc_pmregs[reg].addr = addr; 179 } 180 } 181} 182 183void 184acpi_unmap_pmregs(struct acpi_softc *sc) 185{ 186 int idx; 187 188 for (idx = 0; idx < ACPIREG_MAXREG; idx++) { 189 if (sc->sc_pmregs[idx].size) { 190 bus_space_unmap(sc->sc_iot, sc->sc_pmregs[idx].ioh, 191 sc->sc_pmregs[idx].size); 192 } 193 } 194} 195 196/* Read from power management register */ 197int 198acpi_read_pmreg(struct acpi_softc *sc, int reg) 199{ 200 bus_space_handle_t ioh; 201 bus_size_t size; 202 int regval; 203 204 /* Special cases: 1A/1B blocks can be OR'ed together */ 205 if (reg == ACPIREG_PM1_EN) { 206 return (acpi_read_pmreg(sc, ACPIREG_PM1A_EN) | 207 acpi_read_pmreg(sc, ACPIREG_PM1B_EN)); 208 } 209 else if (reg == ACPIREG_PM1_STS) { 210 return (acpi_read_pmreg(sc, ACPIREG_PM1A_STS) | 211 acpi_read_pmreg(sc, ACPIREG_PM1B_STS)); 212 } 213 else if (reg == ACPIREG_PM1_CNT) { 214 return (acpi_read_pmreg(sc, ACPIREG_PM1A_CNT) | 215 acpi_read_pmreg(sc, ACPIREG_PM1B_CNT)); 216 } 217 218 if (reg >= ACPIREG_MAXREG || sc->sc_pmregs[reg].size == 0) 219 return (0); 220 221 regval = 0; 222 ioh = sc->sc_pmregs[reg].ioh; 223 size = sc->sc_pmregs[reg].size; 224 if (size > 4) 225 size = 4; 226 227 switch (size) { 228 case 1: 229 regval = bus_space_read_1(sc->sc_iot, ioh, 0); 230 break; 231 case 2: 232 regval = bus_space_read_2(sc->sc_iot, ioh, 0); 233 break; 234 case 4: 235 regval = bus_space_read_4(sc->sc_iot, ioh, 0); 236 break; 237 } 238 239 dnprintf(30, "acpi_readpm: %s = %.4x %x\n", 240 sc->sc_pmregs[reg].name, 241 sc->sc_pmregs[reg].addr, regval); 242 return (regval); 243} 244 245/* Write to power management register */ 246void 247acpi_write_pmreg(struct acpi_softc *sc, int reg, int regval) 248{ 249 bus_space_handle_t ioh; 250 bus_size_t size; 251 252 /* Special cases: 1A/1B blocks can be written with same value */ 253 if (reg == ACPIREG_PM1_EN) { 254 acpi_write_pmreg(sc, ACPIREG_PM1A_EN, regval); 255 acpi_write_pmreg(sc, ACPIREG_PM1B_EN, regval); 256 } 257 else if (reg == ACPIREG_PM1_STS) { 258 acpi_write_pmreg(sc, ACPIREG_PM1A_STS, regval); 259 acpi_write_pmreg(sc, ACPIREG_PM1B_STS, regval); 260 } 261 else if (reg == ACPIREG_PM1_CNT) { 262 acpi_write_pmreg(sc, ACPIREG_PM1A_CNT, regval); 263 acpi_write_pmreg(sc, ACPIREG_PM1B_CNT, regval); 264 } 265 266 /* All special case return here */ 267 if (reg >= ACPIREG_MAXREG) 268 return; 269 270 ioh = sc->sc_pmregs[reg].ioh; 271 size = sc->sc_pmregs[reg].size; 272 if (size > 4) 273 size = 4; 274 switch (size) { 275 case 1: 276 bus_space_write_1(sc->sc_iot, ioh, 0, regval); 277 break; 278 case 2: 279 bus_space_write_2(sc->sc_iot, ioh, 0, regval); 280 break; 281 case 4: 282 bus_space_write_4(sc->sc_iot, ioh, 0, regval); 283 break; 284 } 285 286 dnprintf(30, "acpi_writepm: %s = %.4x %x\n", 287 sc->sc_pmregs[reg].name, 288 sc->sc_pmregs[reg].addr, 289 regval); 290} 291 292void 293acpi_gpe(struct aml_node *node, void *arg) 294{ 295 struct aml_node *child; 296 struct acpi_softc *sc = arg; 297 uint32_t flag; 298 299 flag = acpi_read_pmreg(sc, ACPIREG_GPE0_EN); 300 for (child = node->child; child; child = child->sibling) { 301 printf("gpe: %s\n", child->name); 302 } 303 flag = -1; 304 flag &= ~(1L << 0x1C); 305} 306 307void 308acpi_foundhid(struct aml_node *node, void *arg) 309{ 310 struct acpi_softc *sc = (struct acpi_softc *)arg; 311 struct device *self = (struct device *)arg; 312 const char *dev; 313 struct aml_value res; 314 315 dnprintf(10, "found hid device: %s ", node->parent->name); 316 aml_eval_object(sc, node->child, &res, NULL); 317 318 switch (res.type) { 319 case AML_OBJTYPE_STRING: 320 dev = res.v_string; 321 break; 322 case AML_OBJTYPE_INTEGER: 323 dev = aml_eisaid(res.v_integer); 324 break; 325 default: 326 dev = "unknown"; 327 break; 328 } 329 dnprintf(10, " device: %s\n", dev); 330 331 if (!strcmp(dev, ACPI_DEV_AC)) { 332 struct acpi_attach_args aaa; 333 334 memset(&aaa, 0, sizeof(aaa)); 335 aaa.aaa_name = "acpiac"; 336 aaa.aaa_iot = sc->sc_iot; 337 aaa.aaa_memt = sc->sc_memt; 338 aaa.aaa_node = node->parent; 339 config_found(self, &aaa, acpi_print); 340 } else if (!strcmp(dev, ACPI_DEV_CMB)) { 341 struct acpi_attach_args aaa; 342 343 memset(&aaa, 0, sizeof(aaa)); 344 aaa.aaa_name = "acpibat"; 345 aaa.aaa_iot = sc->sc_iot; 346 aaa.aaa_memt = sc->sc_memt; 347 aaa.aaa_node = node->parent; 348 config_found(self, &aaa, acpi_print); 349 } 350} 351 352int 353acpi_match(struct device *parent, void *match, void *aux) 354{ 355 struct acpi_attach_args *aaa = aux; 356 struct cfdata *cf = match; 357 358 /* sanity */ 359 if (strcmp(aaa->aaa_name, cf->cf_driver->cd_name)) 360 return (0); 361 362 if (!acpi_probe(parent, cf, aaa)) 363 return (0); 364 365 return (1); 366} 367 368void 369acpi_attach(struct device *parent, struct device *self, void *aux) 370{ 371 struct acpi_attach_args *aaa = aux; 372 struct acpi_softc *sc = (struct acpi_softc *)self; 373 struct acpi_mem_map handle; 374 struct acpi_rsdp *rsdp; 375 struct acpi_q *entry; 376 struct acpi_dsdt *p_dsdt; 377 paddr_t facspa; 378 int idx; 379 380 sc->sc_iot = aaa->aaa_iot; 381 sc->sc_memt = aaa->aaa_memt; 382 383 printf(": "); 384 if (acpi_map(aaa->aaa_pbase, sizeof(struct acpi_rsdp), &handle)) 385 goto fail; 386 387 rsdp = (struct acpi_rsdp *)handle.va; 388 printf("revision %d ", (int)rsdp->rsdp_revision); 389 390 SIMPLEQ_INIT(&sc->sc_tables); 391 392 sc->sc_fadt = NULL; 393 sc->sc_facs = NULL; 394 sc->sc_powerbtn = 0; 395 sc->sc_sleepbtn = 0; 396 397 sc->sc_note = malloc(sizeof(struct klist), M_DEVBUF, M_NOWAIT); 398 memset(sc->sc_note, 0, sizeof(struct klist)); 399 400 if (acpi_loadtables(sc, rsdp)) { 401 acpi_unmap(&handle); 402 return; 403 } 404 405 acpi_unmap(&handle); 406 407 /* 408 * Find the FADT 409 */ 410 SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { 411 if (memcmp(entry->q_table, FADT_SIG, 412 sizeof(FADT_SIG) - 1) == 0) { 413 sc->sc_fadt = entry->q_table; 414 break; 415 } 416 } 417 if (sc->sc_fadt == NULL) 418 goto fail; 419 420 /* 421 * Check if we are able to enable ACPI control 422 */ 423 if (!sc->sc_fadt->smi_cmd || 424 (!sc->sc_fadt->acpi_enable && !sc->sc_fadt->acpi_disable)) 425 goto fail; 426 427 /* 428 * Load the DSDT from the FADT pointer -- use the 429 * extended (64-bit) pointer if it exists 430 */ 431 if (sc->sc_fadt->hdr_revision < 3 || sc->sc_fadt->x_dsdt == 0) 432 acpi_load_dsdt(sc->sc_fadt->dsdt, &entry); 433 else 434 acpi_load_dsdt(sc->sc_fadt->x_dsdt, &entry); 435 436 if (entry == NULL) 437 printf("!DSDT "); 438 SIMPLEQ_INSERT_HEAD(&sc->sc_tables, entry, q_next); 439 440 p_dsdt = entry->q_table; 441 acpi_parse_aml(sc, p_dsdt->aml, p_dsdt->hdr_length - 442 sizeof(p_dsdt->hdr)); 443 444 /* Find available sleeping states */ 445 acpi_init_states(sc); 446 447 /* 448 * Set up a pointer to the firmware control structure 449 */ 450 if (sc->sc_fadt->hdr_revision < 3 || sc->sc_fadt->x_firmware_ctl == 0) 451 facspa = sc->sc_fadt->firmware_ctl; 452 else 453 facspa = sc->sc_fadt->x_firmware_ctl; 454 455 if (acpi_map(facspa, sizeof(struct acpi_facs), &handle)) 456 printf("!FACS "); 457 else 458 sc->sc_facs = (struct acpi_facs *)handle.va; 459 460 /* Map Power Management registers */ 461 acpi_map_pmregs(sc); 462 463 /* 464 * Take over ACPI control. Note that once we do this, we 465 * effectively tell the system that we have ownership of 466 * the ACPI hardware registers, and that SMI should leave 467 * them alone 468 * 469 * This may prevent thermal control on some systems where 470 * that actually does work 471 */ 472#ifdef ACPI_ENABLE 473 acpi_write_pmreg(sc, ACPIREG_SMICMD, sc->sc_fadt->acpi_enable); 474 idx = 0; 475 do { 476 if (idx++ > ACPIEN_RETRIES) 477 goto fail; 478 } while (!(acpi_read_pmreg(sc, ACPIREG_PM1_CNT) & ACPI_PM1_SCI_EN)); 479#endif 480 481#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS 482 sc->sc_softih = softintr_establish(IPL_TTY, acpi_softintr, sc); 483#else 484 timeout_set(&sc->sc_timeout, acpi_softintr, sc); 485#endif 486 acpi_attach_machdep(sc); 487 488 for (idx = 0; idx < ACPIREG_MAXREG; idx++) { 489 if (sc->sc_pmregs[idx].name) { 490 printf("%8s = %.8x\n", 491 sc->sc_pmregs[idx].name, 492 acpi_read_pmreg(sc, idx)); 493 } 494 } 495 496 /* 497 * If we have an interrupt handler, we can get notification 498 * when certain status bits changes in the ACPI registers, 499 * so let us enable some events we can forward to userland 500 */ 501 if (sc->sc_interrupt) { 502 int16_t flag; 503 504 dnprintf(1,"slpbtn:%c pwrbtn:%c\n", 505 sc->sc_fadt->flags & FADT_SLP_BUTTON ? 'n' : 'y', 506 sc->sc_fadt->flags & FADT_PWR_BUTTON ? 'n' : 'y'); 507 508 /* Enable Sleep/Power buttons if they exist */ 509 flag = acpi_read_pmreg(sc, ACPIREG_PM1_EN); 510 if (!(sc->sc_fadt->flags & FADT_PWR_BUTTON)) { 511 flag |= ACPI_PM1_PWRBTN_EN; 512 } 513 if (!(sc->sc_fadt->flags & FADT_SLP_BUTTON)) { 514 flag |= ACPI_PM1_SLPBTN_EN; 515 } 516 acpi_write_pmreg(sc, ACPIREG_PM1_EN, flag); 517 518#if 0 519 flag = acpi_read_pmreg(sc, ACPIREG_GPE0_STS); 520 acpi_write_pmreg(sc, ACPIREG_GPE0_STS, flag); 521 acpi_write_pmreg(sc, ACPIREG_GPE0_EN, 0); 522 acpi_write_pmreg(sc, ACPIREG_GPE0_EN, (1L << 0x1D)); 523#endif 524 } 525 526 /* 527 * ACPI is enabled now -- attach timer 528 */ 529 { 530 struct acpi_attach_args aaa; 531 532 memset(&aaa, 0, sizeof(aaa)); 533 aaa.aaa_name = "acpitimer"; 534 aaa.aaa_iot = sc->sc_iot; 535 aaa.aaa_memt = sc->sc_memt; 536#if 0 537 aaa.aaa_pcit = sc->sc_pcit; 538 aaa.aaa_smbust = sc->sc_smbust; 539#endif 540 config_found(self, &aaa, acpi_print); 541 } 542 543 /* 544 * Attach table-defined devices 545 */ 546 SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { 547 struct acpi_attach_args aaa; 548 549 memset(&aaa, 0, sizeof(aaa)); 550 aaa.aaa_iot = sc->sc_iot; 551 aaa.aaa_memt = sc->sc_memt; 552#if 0 553 aaa.aaa_pcit = sc->sc_pcit; 554 aaa.aaa_smbust = sc->sc_smbust; 555#endif 556 aaa.aaa_table = entry->q_table; 557 558 config_found_sm(self, &aaa, acpi_print, acpi_submatch); 559 } 560 561 acpi_softc = sc; 562 563 /* attach devices found in dsdt */ 564 aml_find_node(aml_root.child, "_HID", acpi_foundhid, sc); 565 566 return; 567 568 fail: 569 printf(" failed attach\n"); 570} 571 572int 573acpi_submatch(struct device *parent, void *match, void *aux) 574{ 575 struct acpi_attach_args *aaa = (struct acpi_attach_args *)aux; 576 struct cfdata *cf = match; 577 578 if (aaa->aaa_table == NULL) 579 return (0); 580 return ((*cf->cf_attach->ca_match)(parent, match, aux)); 581} 582 583int 584acpi_print(void *aux, const char *pnp) 585{ 586 /* XXX ACPIVERBOSE should be replaced with dnprintf */ 587 struct acpi_attach_args *aa = aux; 588#ifdef ACPIVERBOSE 589 struct acpi_table_header *hdr = 590 (struct acpi_table_header *)aa->aaa_table; 591#endif 592 593 if (pnp) { 594 if (aa->aaa_name) 595 printf("%s at %s", aa->aaa_name, pnp); 596#ifdef ACPIVERBOSE 597 else 598 printf("acpi device at %s from", pnp); 599#endif 600 } 601#ifdef ACPIVERBOSE 602 if (hdr) 603 printf(" table %c%c%c%c", 604 hdr->signature[0], hdr->signature[1], 605 hdr->signature[2], hdr->signature[3]); 606#endif 607 608 return (UNCONF); 609} 610 611int 612acpi_loadtables(struct acpi_softc *sc, struct acpi_rsdp *rsdp) 613{ 614 struct acpi_mem_map hrsdt, handle; 615 struct acpi_table_header *hdr; 616 int i, ntables; 617 size_t len; 618 619 if (rsdp->rsdp_revision == 2) { 620 struct acpi_xsdt *xsdt; 621 622 if (acpi_map(rsdp->rsdp_xsdt, sizeof(*hdr), &handle)) { 623 printf("couldn't map rsdt\n"); 624 return (ENOMEM); 625 } 626 627 hdr = (struct acpi_table_header *)handle.va; 628 len = hdr->length; 629 acpi_unmap(&handle); 630 hdr = NULL; 631 632 acpi_map(rsdp->rsdp_xsdt, len, &hrsdt); 633 xsdt = (struct acpi_xsdt *)hrsdt.va; 634 635 ntables = (len - sizeof(struct acpi_table_header)) / 636 sizeof(xsdt->table_offsets[0]); 637 638 for (i = 0; i < ntables; i++) { 639 acpi_map(xsdt->table_offsets[i], sizeof(*hdr), 640 &handle); 641 hdr = (struct acpi_table_header *)handle.va; 642 acpi_load_table(xsdt->table_offsets[i], hdr->length, 643 &sc->sc_tables); 644 acpi_unmap(&handle); 645 } 646 acpi_unmap(&hrsdt); 647 } else { 648 struct acpi_rsdt *rsdt; 649 650 if (acpi_map(rsdp->rsdp_rsdt, sizeof(*hdr), &handle)) { 651 printf("couldn't map rsdt\n"); 652 return (ENOMEM); 653 } 654 655 hdr = (struct acpi_table_header *)handle.va; 656 len = hdr->length; 657 acpi_unmap(&handle); 658 hdr = NULL; 659 660 acpi_map(rsdp->rsdp_rsdt, len, &hrsdt); 661 rsdt = (struct acpi_rsdt *)hrsdt.va; 662 663 ntables = (len - sizeof(struct acpi_table_header)) / 664 sizeof(rsdt->table_offsets[0]); 665 666 for (i = 0; i < ntables; i++) { 667 acpi_map(rsdt->table_offsets[i], sizeof(*hdr), 668 &handle); 669 hdr = (struct acpi_table_header *)handle.va; 670 acpi_load_table(rsdt->table_offsets[i], hdr->length, 671 &sc->sc_tables); 672 acpi_unmap(&handle); 673 } 674 acpi_unmap(&hrsdt); 675 } 676 677 return (0); 678} 679 680void 681acpi_load_table(paddr_t pa, size_t len, acpi_qhead_t *queue) 682{ 683 struct acpi_mem_map handle; 684 struct acpi_q *entry; 685 686 entry = malloc(len + sizeof(struct acpi_q), M_DEVBUF, M_NOWAIT); 687 688 if (entry != NULL) { 689 if (acpi_map(pa, len, &handle)) { 690 free(entry, M_DEVBUF); 691 return; 692 } 693 memcpy(entry->q_data, handle.va, len); 694 entry->q_table = entry->q_data; 695 acpi_unmap(&handle); 696 SIMPLEQ_INSERT_TAIL(queue, entry, q_next); 697 } 698} 699 700void 701acpi_load_dsdt(paddr_t pa, struct acpi_q **dsdt) 702{ 703 struct acpi_mem_map handle; 704 struct acpi_table_header *hdr; 705 size_t len; 706 707 if (acpi_map(pa, sizeof(*hdr), &handle)) 708 return; 709 hdr = (struct acpi_table_header *)handle.va; 710 len = hdr->length; 711 acpi_unmap(&handle); 712 713 *dsdt = malloc(len + sizeof(struct acpi_q), M_DEVBUF, M_NOWAIT); 714 715 if (*dsdt != NULL) { 716 if (acpi_map(pa, len, &handle)) { 717 free(*dsdt, M_DEVBUF); 718 *dsdt = NULL; 719 return; 720 } 721 memcpy((*dsdt)->q_data, handle.va, len); 722 (*dsdt)->q_table = (*dsdt)->q_data; 723 acpi_unmap(&handle); 724 } 725} 726 727int 728acpi_interrupt(void *arg) 729{ 730 struct acpi_softc *sc = (struct acpi_softc *)arg; 731 u_int32_t processed, sts, en; 732 733 processed = 0; 734 735 sts = acpi_read_pmreg(sc, ACPIREG_GPE0_STS); 736 en = acpi_read_pmreg(sc, ACPIREG_GPE0_EN); 737 if (sts & en) { 738 dnprintf(10, "GPE interrupt: %.8x %.8x %.8x\n", 739 sts, en, sts & en); 740 acpi_write_pmreg(sc, ACPIREG_GPE0_EN, en & ~sts); 741 acpi_write_pmreg(sc, ACPIREG_GPE0_STS,en); 742 acpi_write_pmreg(sc, ACPIREG_GPE0_EN, en); 743 processed = 1; 744 for (en = 0; en < icount; en++) { 745 icount = (icount << 1) | 1; 746 } 747 icount++; 748 } 749 750 sts = acpi_read_pmreg(sc, ACPIREG_PM1_STS); 751 en = acpi_read_pmreg(sc, ACPIREG_PM1_EN); 752 if (sts & en) { 753 dnprintf(10,"GEN interrupt: %.4x\n", sts & en); 754 acpi_write_pmreg(sc, ACPIREG_PM1_EN, en & ~sts); 755 acpi_write_pmreg(sc, ACPIREG_PM1_STS,en); 756 acpi_write_pmreg(sc, ACPIREG_PM1_EN, en); 757 if (sts & ACPI_PM1_PWRBTN_STS) 758 sc->sc_powerbtn = 1; 759 if (sts & ACPI_PM1_SLPBTN_STS) 760 sc->sc_sleepbtn = 1; 761 processed = 1; 762 } 763 if (processed) { 764#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS 765 softintr_schedule(sc->sc_softih); 766#else 767 if (!timeout_pending(&sc->sc_timeout)) 768 timeout_add(&sc->sc_timeout, 0); 769#endif 770 } 771 772 return (processed); 773} 774 775void 776acpi_softintr(void *arg) 777{ 778 struct acpi_softc *sc = arg; 779 780 if (sc->sc_powerbtn) { 781 sc->sc_powerbtn = 0; 782 acpi_evindex++; 783 dnprintf(1,"power button pressed\n"); 784 KNOTE(sc->sc_note, ACPI_EVENT_COMPOSE(ACPI_EV_PWRBTN, 785 acpi_evindex)); 786 787 /* power down */ 788 acpi_s5 = 1; 789 psignal(initproc, SIGUSR1); 790 } 791 if (sc->sc_sleepbtn) { 792 sc->sc_sleepbtn = 0; 793 acpi_evindex++; 794 dnprintf(1,"sleep button pressed\n"); 795 KNOTE(sc->sc_note, ACPI_EVENT_COMPOSE(ACPI_EV_SLPBTN, 796 acpi_evindex)); 797 } 798} 799 800void 801acpi_init_states(struct acpi_softc *sc) 802{ 803 struct aml_value res, env; 804 char name[8]; 805 int i; 806 807 for (i = ACPI_STATE_S0; i <= ACPI_STATE_S5; i++) { 808 snprintf(name, sizeof(name), "_S%d_", i); 809 sc->sc_sleeptype[i].slp_typa = -1; 810 sc->sc_sleeptype[i].slp_typb = -1; 811 if (aml_eval_name(sc, aml_root.child, name, &res, &env)) 812 continue; 813 sc->sc_sleeptype[i].slp_typa = aml_intval(&res.v_package[0]); 814 sc->sc_sleeptype[i].slp_typb = aml_intval(&res.v_package[1]); 815 } 816} 817 818void 819acpi_enter_sleep_state(struct acpi_softc *sc, int state) 820{ 821#ifdef ACPI_ENABLE 822 u_int16_t flag; 823 824 flag = acpi_read_pmreg(sc, ACPIREG_PM1_CNT); 825 /* XXX This is sick and wrong and illegal! */ 826 acpi_write_pmreg(sc, ACPIREG_PM1_CNT, flag |= (state << 10)); 827 acpi_write_pmreg(sc, ACPIREG_PM1_CNT, flag |= ACPI_PM1_SLP_EN); 828#endif 829} 830 831void 832acpi_powerdown(void) 833{ 834 acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5); 835} 836 837int 838acpiopen(dev_t dev, int flag, int mode, struct proc *p) 839{ 840 struct acpi_softc *sc; 841 int error = 0; 842 843 if (!acpi_cd.cd_ndevs || minor(dev) != 0 || 844 !(sc = acpi_cd.cd_devs[minor(dev)])) 845 return (ENXIO); 846 847 if (!(flag & FREAD) || (flag & FWRITE)) 848 error = EINVAL; 849 850 return (error); 851} 852 853int 854acpiclose(dev_t dev, int flag, int mode, struct proc *p) 855{ 856 struct acpi_softc *sc; 857 858 if (!acpi_cd.cd_ndevs || minor(dev) != 0 || 859 !(sc = acpi_cd.cd_devs[minor(dev)])) 860 return (ENXIO); 861 862 return (0); 863} 864 865int 866acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 867{ 868 struct acpi_softc *sc; 869 int error = 0; 870 871 if (!acpi_cd.cd_ndevs || minor(dev) != 0 || 872 !(sc = acpi_cd.cd_devs[minor(dev)])) 873 return (ENXIO); 874 875 ACPI_LOCK(sc); 876 switch (cmd) { 877 case ACPI_IOC_SETSLEEPSTATE: 878 if (suser(p, 0) != 0) 879 error = EPERM; 880 else { 881 acpi_enter_sleep_state(sc, *(int *)data); 882 } 883 break; 884 885 case ACPI_IOC_GETFACS: 886 if (suser(p, 0) != 0) 887 error = EPERM; 888 else { 889 struct acpi_facs *facs = (struct acpi_facs *)data; 890 891 bcopy(sc->sc_facs, facs, sc->sc_facs->length); 892 } 893 break; 894 895 case ACPI_IOC_GETTABLE: 896 if (suser(p, 0) != 0) 897 error = EPERM; 898 else { 899 struct acpi_table *table = (struct acpi_table *)data; 900 struct acpi_table_header *hdr; 901 struct acpi_q *entry; 902 903 error = ENOENT; 904 SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { 905 if (table->offset-- == 0) { 906 hdr = (struct acpi_table_header *) 907 entry->q_table; 908 if (table->table == NULL) { 909 table->size = hdr->length; 910 error = 0; 911 } else if (hdr->length > table->size) 912 error = ENOSPC; 913 else 914 error = copyout(hdr, 915 table->table, hdr->length); 916 break; 917 } 918 } 919 } 920 break; 921 922 default: 923 error = ENOTTY; 924 } 925 926 ACPI_UNLOCK(sc); 927 return (error); 928} 929 930void 931acpi_filtdetach(struct knote *kn) 932{ 933 struct acpi_softc *sc = kn->kn_hook; 934 935 ACPI_LOCK(sc); 936 SLIST_REMOVE(sc->sc_note, kn, knote, kn_selnext); 937 ACPI_UNLOCK(sc); 938} 939 940int 941acpi_filtread(struct knote *kn, long hint) 942{ 943 /* XXX weird kqueue_scan() semantics */ 944 if (hint & !kn->kn_data) 945 kn->kn_data = hint; 946 947 return (1); 948} 949 950int 951acpikqfilter(dev_t dev, struct knote *kn) 952{ 953 struct acpi_softc *sc; 954 955 if (!acpi_cd.cd_ndevs || minor(dev) != 0 || 956 !(sc = acpi_cd.cd_devs[minor(dev)])) 957 return (ENXIO); 958 959 switch (kn->kn_filter) { 960 case EVFILT_READ: 961 kn->kn_fop = &acpiread_filtops; 962 break; 963 default: 964 return (1); 965 } 966 967 kn->kn_hook = sc; 968 969 ACPI_LOCK(sc); 970 SLIST_INSERT_HEAD(sc->sc_note, kn, kn_selnext); 971 ACPI_UNLOCK(sc); 972 973 return (0); 974} 975