Annotation of sys/dev/acpi/acpi.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: acpi.c,v 1.88 2007/04/17 16:07:45 mk 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: #include <sys/kthread.h>
! 29:
! 30: #include <machine/conf.h>
! 31: #include <machine/cpufunc.h>
! 32: #include <machine/bus.h>
! 33:
! 34: #include <dev/pci/pcivar.h>
! 35: #include <dev/acpi/acpireg.h>
! 36: #include <dev/acpi/acpivar.h>
! 37: #include <dev/acpi/amltypes.h>
! 38: #include <dev/acpi/acpidev.h>
! 39: #include <dev/acpi/dsdt.h>
! 40:
! 41: #include <machine/apmvar.h>
! 42:
! 43: #ifdef ACPI_DEBUG
! 44: int acpi_debug = 16;
! 45: #endif
! 46: int acpi_enabled = 0;
! 47: int acpi_poll_enabled = 0;
! 48: int acpi_hasprocfvs = 0;
! 49:
! 50: #define ACPIEN_RETRIES 15
! 51:
! 52: void acpi_isr_thread(void *);
! 53: void acpi_create_thread(void *);
! 54:
! 55: int acpi_match(struct device *, void *, void *);
! 56: void acpi_attach(struct device *, struct device *, void *);
! 57: int acpi_submatch(struct device *, void *, void *);
! 58: int acpi_print(void *, const char *);
! 59:
! 60: void acpi_map_pmregs(struct acpi_softc *);
! 61:
! 62: void acpi_founddock(struct aml_node *, void *);
! 63: void acpi_foundpss(struct aml_node *, void *);
! 64: void acpi_foundhid(struct aml_node *, void *);
! 65: void acpi_foundec(struct aml_node *, void *);
! 66: void acpi_foundtmp(struct aml_node *, void *);
! 67: void acpi_inidev(struct aml_node *, void *);
! 68:
! 69: int acpi_loadtables(struct acpi_softc *, struct acpi_rsdp *);
! 70: void acpi_load_table(paddr_t, size_t, acpi_qhead_t *);
! 71: void acpi_load_dsdt(paddr_t, struct acpi_q **);
! 72:
! 73: void acpi_init_states(struct acpi_softc *);
! 74: void acpi_init_gpes(struct acpi_softc *);
! 75: void acpi_init_pm(struct acpi_softc *);
! 76:
! 77: void acpi_foundprt(struct aml_node *, void *);
! 78:
! 79: void acpi_filtdetach(struct knote *);
! 80: int acpi_filtread(struct knote *, long);
! 81:
! 82: void acpi_enable_onegpe(struct acpi_softc *, int, int);
! 83: int acpi_gpe_level(struct acpi_softc *, int, void *);
! 84: int acpi_gpe_edge(struct acpi_softc *, int, void *);
! 85:
! 86: #define ACPI_LOCK(sc)
! 87: #define ACPI_UNLOCK(sc)
! 88:
! 89: /* XXX move this into dsdt softc at some point */
! 90: extern struct aml_node aml_root;
! 91:
! 92: struct filterops acpiread_filtops = {
! 93: 1, NULL, acpi_filtdetach, acpi_filtread
! 94: };
! 95:
! 96: struct cfattach acpi_ca = {
! 97: sizeof(struct acpi_softc), acpi_match, acpi_attach
! 98: };
! 99:
! 100: struct cfdriver acpi_cd = {
! 101: NULL, "acpi", DV_DULL
! 102: };
! 103:
! 104: struct acpi_softc *acpi_softc;
! 105: int acpi_s5, acpi_evindex;
! 106:
! 107: #ifdef __i386__
! 108: #define acpi_bus_space_map _bus_space_map
! 109: #define acpi_bus_space_unmap _bus_space_unmap
! 110: #elif defined(__amd64__)
! 111: #define acpi_bus_space_map _x86_memio_map
! 112: #define acpi_bus_space_unmap _x86_memio_unmap
! 113: #else
! 114: #error ACPI supported on i386/amd64 only
! 115: #endif
! 116:
! 117: #define pch(x) (((x)>=' ' && (x)<='z') ? (x) : ' ')
! 118:
! 119: void
! 120: acpi_delay(struct acpi_softc *sc, int64_t uSecs)
! 121: {
! 122: /* XXX this needs to become a tsleep later */
! 123: delay(uSecs);
! 124: }
! 125:
! 126: int
! 127: acpi_gasio(struct acpi_softc *sc, int iodir, int iospace, uint64_t address,
! 128: int access_size, int len, void *buffer)
! 129: {
! 130: u_int8_t *pb;
! 131: bus_space_handle_t ioh;
! 132: struct acpi_mem_map mh;
! 133: pci_chipset_tag_t pc;
! 134: pcitag_t tag;
! 135: bus_addr_t ioaddr;
! 136: int reg, idx, ival, sval;
! 137:
! 138: dnprintf(50, "gasio: %.2x 0x%.8llx %s\n",
! 139: iospace, address, (iodir == ACPI_IOWRITE) ? "write" : "read");
! 140:
! 141: pb = (u_int8_t *)buffer;
! 142: switch (iospace) {
! 143: case GAS_SYSTEM_MEMORY:
! 144: /* copy to/from system memory */
! 145: acpi_map(address, len, &mh);
! 146: if (iodir == ACPI_IOREAD)
! 147: memcpy(buffer, mh.va, len);
! 148: else
! 149: memcpy(mh.va, buffer, len);
! 150: acpi_unmap(&mh);
! 151: break;
! 152:
! 153: case GAS_SYSTEM_IOSPACE:
! 154: /* read/write from I/O registers */
! 155: ioaddr = address;
! 156: if (acpi_bus_space_map(sc->sc_iot, ioaddr, len, 0, &ioh) != 0) {
! 157: printf("Unable to map iospace!\n");
! 158: return (-1);
! 159: }
! 160: for (reg = 0; reg < len; reg += access_size) {
! 161: if (iodir == ACPI_IOREAD) {
! 162: switch (access_size) {
! 163: case 1:
! 164: *(uint8_t *)(pb+reg) = bus_space_read_1(
! 165: sc->sc_iot, ioh, reg);
! 166: dnprintf(80, "os_in8(%llx) = %x\n",
! 167: reg+address, *(uint8_t *)(pb+reg));
! 168: break;
! 169: case 2:
! 170: *(uint16_t *)(pb+reg) = bus_space_read_2(
! 171: sc->sc_iot, ioh, reg);
! 172: dnprintf(80, "os_in16(%llx) = %x\n",
! 173: reg+address, *(uint16_t *)(pb+reg));
! 174: break;
! 175: case 4:
! 176: *(uint32_t *)(pb+reg) = bus_space_read_4(
! 177: sc->sc_iot, ioh, reg);
! 178: break;
! 179: }
! 180: } else {
! 181: switch (access_size) {
! 182: case 1:
! 183: bus_space_write_1(sc->sc_iot, ioh, reg,
! 184: *(uint8_t *)(pb+reg));
! 185: dnprintf(80, "os_out8(%llx,%x)\n",
! 186: reg+address, *(uint8_t *)(pb+reg));
! 187: break;
! 188: case 2:
! 189: bus_space_write_2(sc->sc_iot, ioh, reg,
! 190: *(uint16_t *)(pb+reg));
! 191: dnprintf(80, "os_out16(%llx,%x)\n",
! 192: reg+address, *(uint16_t *)(pb+reg));
! 193: break;
! 194: case 4:
! 195: bus_space_write_4(sc->sc_iot, ioh, reg,
! 196: *(uint32_t *)(pb+reg));
! 197: break;
! 198: }
! 199: }
! 200:
! 201: /* During autoconf some devices are still gathering
! 202: * information. Delay here to give them an opportunity
! 203: * to finish. During runtime we simply need to ignore
! 204: * transient values.
! 205: */
! 206: if (cold)
! 207: delay(10000);
! 208: }
! 209: acpi_bus_space_unmap(sc->sc_iot, ioh, len, &ioaddr);
! 210: break;
! 211:
! 212: case GAS_PCI_CFG_SPACE:
! 213: /* format of address:
! 214: * bits 00..15 = register
! 215: * bits 16..31 = function
! 216: * bits 32..47 = device
! 217: * bits 48..63 = bus
! 218: */
! 219: pc = NULL;
! 220: tag = pci_make_tag(pc,
! 221: ACPI_PCI_BUS(address), ACPI_PCI_DEV(address),
! 222: ACPI_PCI_FN(address));
! 223:
! 224: /* XXX: This is ugly. read-modify-write does a byte at a time */
! 225: reg = ACPI_PCI_REG(address);
! 226: for (idx = reg; idx < reg+len; idx++) {
! 227: ival = pci_conf_read(pc, tag, idx & ~0x3);
! 228: if (iodir == ACPI_IOREAD) {
! 229: *pb = ival >> (8 * (idx & 0x3));
! 230: } else {
! 231: sval = *pb;
! 232: ival &= ~(0xFF << (8* (idx & 0x3)));
! 233: ival |= sval << (8* (idx & 0x3));
! 234: pci_conf_write(pc, tag, idx & ~0x3, ival);
! 235: }
! 236: pb++;
! 237: }
! 238: break;
! 239: case GAS_EMBEDDED:
! 240: if (sc->sc_ec == NULL)
! 241: break;
! 242: #ifndef SMALL_KERNEL
! 243: if (iodir == ACPI_IOREAD)
! 244: acpiec_read(sc->sc_ec, (u_int8_t)address, len, buffer);
! 245: else
! 246: acpiec_write(sc->sc_ec, (u_int8_t)address, len, buffer);
! 247: #endif
! 248: break;
! 249: }
! 250: return (0);
! 251: }
! 252:
! 253: void
! 254: acpi_inidev(struct aml_node *node, void *arg)
! 255: {
! 256: struct acpi_softc *sc = (struct acpi_softc *)arg;
! 257: struct aml_value res;
! 258:
! 259: /*
! 260: * XXX per the ACPI spec 6.5.1 only run _INI when device is there
! 261: * or when there is no _STA.
! 262: * The tricky bit is that the parent can have a _STA that is disabled
! 263: * and the children do not have a _STA. In that case the _INI will
! 264: * execute! This needs to be fixed.
! 265: */
! 266:
! 267: memset(&res, 0, sizeof res);
! 268: if (aml_evalname(sc, node, "_STA", 0, NULL, &res))
! 269: res.v_integer = STA_PRESENT; /* no _STA, fake it */
! 270:
! 271: if (res.v_integer & STA_PRESENT)
! 272: aml_evalnode(sc, node, 0, NULL, NULL);
! 273: aml_freevalue(&res);
! 274: }
! 275:
! 276: void
! 277: acpi_foundprt(struct aml_node *node, void *arg)
! 278: {
! 279: struct acpi_softc *sc = (struct acpi_softc *)arg;
! 280: struct device *self = (struct device *)arg;
! 281: const char *dev;
! 282: struct acpi_attach_args aaa;
! 283:
! 284: dnprintf(10, "found prt entry: %s\n", node->parent->name);
! 285:
! 286: memset(&aaa, 0, sizeof(aaa));
! 287: aaa.aaa_iot = sc->sc_iot;
! 288: aaa.aaa_memt = sc->sc_memt;
! 289: aaa.aaa_node = node;
! 290: aaa.aaa_dev = dev;
! 291: aaa.aaa_name = "acpiprt";
! 292:
! 293: config_found(self, &aaa, acpi_print);
! 294: }
! 295:
! 296: int
! 297: acpi_match(struct device *parent, void *match, void *aux)
! 298: {
! 299: struct acpi_attach_args *aaa = aux;
! 300: struct cfdata *cf = match;
! 301:
! 302: /* sanity */
! 303: if (strcmp(aaa->aaa_name, cf->cf_driver->cd_name))
! 304: return (0);
! 305:
! 306: if (!acpi_probe(parent, cf, aaa))
! 307: return (0);
! 308:
! 309: return (1);
! 310: }
! 311:
! 312: int acpi_add_device(struct aml_node *node, void *arg);
! 313:
! 314: int
! 315: acpi_add_device(struct aml_node *node, void *arg)
! 316: {
! 317: struct device *self = arg;
! 318: struct acpi_softc *sc = arg;
! 319: struct acpi_attach_args aaa;
! 320:
! 321: memset(&aaa, 0, sizeof(aaa));
! 322: aaa.aaa_node = node;
! 323: aaa.aaa_dev = "";
! 324: aaa.aaa_iot = sc->sc_iot;
! 325: aaa.aaa_memt = sc->sc_memt;
! 326: if (node == NULL || node->value == NULL)
! 327: return 0;
! 328:
! 329: switch (node->value->type) {
! 330: case AML_OBJTYPE_PROCESSOR:
! 331: aaa.aaa_name = "acpicpu";
! 332: break;
! 333: case AML_OBJTYPE_THERMZONE:
! 334: aaa.aaa_name = "acpitz";
! 335: break;
! 336: default:
! 337: return 0;
! 338: }
! 339: config_found(self, &aaa, acpi_print);
! 340: return 0;
! 341: }
! 342:
! 343: void
! 344: acpi_attach(struct device *parent, struct device *self, void *aux)
! 345: {
! 346: struct acpi_attach_args *aaa = aux;
! 347: struct acpi_softc *sc = (struct acpi_softc *)self;
! 348: struct acpi_mem_map handle;
! 349: struct acpi_rsdp *rsdp;
! 350: struct acpi_q *entry;
! 351: struct acpi_dsdt *p_dsdt;
! 352: #ifndef SMALL_KERNEL
! 353: struct device *dev;
! 354: struct acpi_ac *ac;
! 355: struct acpi_bat *bat;
! 356: paddr_t facspa;
! 357: #endif
! 358: sc->sc_iot = aaa->aaa_iot;
! 359: sc->sc_memt = aaa->aaa_memt;
! 360:
! 361:
! 362: if (acpi_map(aaa->aaa_pbase, sizeof(struct acpi_rsdp), &handle)) {
! 363: printf(": can't map memory\n");
! 364: return;
! 365: }
! 366:
! 367: rsdp = (struct acpi_rsdp *)handle.va;
! 368: printf(": rev %d", (int)rsdp->rsdp_revision);
! 369:
! 370: SIMPLEQ_INIT(&sc->sc_tables);
! 371:
! 372: sc->sc_fadt = NULL;
! 373: sc->sc_facs = NULL;
! 374: sc->sc_powerbtn = 0;
! 375: sc->sc_sleepbtn = 0;
! 376:
! 377: sc->sc_note = malloc(sizeof(struct klist), M_DEVBUF, M_NOWAIT);
! 378: if (sc->sc_note == NULL) {
! 379: printf(": can't allocate memory\n");
! 380: acpi_unmap(&handle);
! 381: return;
! 382: }
! 383: memset(sc->sc_note, 0, sizeof(struct klist));
! 384:
! 385: if (acpi_loadtables(sc, rsdp)) {
! 386: printf(": can't load tables\n");
! 387: acpi_unmap(&handle);
! 388: return;
! 389: }
! 390:
! 391: acpi_unmap(&handle);
! 392:
! 393: /*
! 394: * Find the FADT
! 395: */
! 396: SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) {
! 397: if (memcmp(entry->q_table, FADT_SIG,
! 398: sizeof(FADT_SIG) - 1) == 0) {
! 399: sc->sc_fadt = entry->q_table;
! 400: break;
! 401: }
! 402: }
! 403: if (sc->sc_fadt == NULL) {
! 404: printf(": no FADT\n");
! 405: return;
! 406: }
! 407:
! 408: #ifdef ACPI_ENABLE
! 409: /*
! 410: * Check if we are able to enable ACPI control
! 411: */
! 412: if (!sc->sc_fadt->smi_cmd ||
! 413: (!sc->sc_fadt->acpi_enable && !sc->sc_fadt->acpi_disable)) {
! 414: printf(": ACPI control unavailable\n");
! 415: return;
! 416: }
! 417: #endif
! 418:
! 419: /* Create opcode hashtable */
! 420: aml_hashopcodes();
! 421:
! 422: acpi_enabled=1;
! 423:
! 424: /* Create Default AML objects */
! 425: aml_create_defaultobjects();
! 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: /* Load SSDT's */
! 445: SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) {
! 446: if (memcmp(entry->q_table, SSDT_SIG,
! 447: sizeof(SSDT_SIG) - 1) == 0) {
! 448: p_dsdt = entry->q_table;
! 449: acpi_parse_aml(sc, p_dsdt->aml, p_dsdt->hdr_length -
! 450: sizeof(p_dsdt->hdr));
! 451: }
! 452: }
! 453:
! 454: /* Perform post-parsing fixups */
! 455: aml_postparse();
! 456:
! 457: /* Walk AML Tree */
! 458: /* aml_walkroot(); */
! 459:
! 460: #ifndef SMALL_KERNEL
! 461: /* Find available sleeping states */
! 462: acpi_init_states(sc);
! 463:
! 464: /* Find available sleep/resume related methods. */
! 465: acpi_init_pm(sc);
! 466:
! 467: /*
! 468: * Set up a pointer to the firmware control structure
! 469: */
! 470: if (sc->sc_fadt->hdr_revision < 3 || sc->sc_fadt->x_firmware_ctl == 0)
! 471: facspa = sc->sc_fadt->firmware_ctl;
! 472: else
! 473: facspa = sc->sc_fadt->x_firmware_ctl;
! 474:
! 475: if (acpi_map(facspa, sizeof(struct acpi_facs), &handle))
! 476: printf(" !FACS");
! 477: else
! 478: sc->sc_facs = (struct acpi_facs *)handle.va;
! 479:
! 480: /* Map Power Management registers */
! 481: acpi_map_pmregs(sc);
! 482:
! 483: /* Initialize GPE handlers */
! 484: acpi_init_gpes(sc);
! 485:
! 486: /* some devices require periodic polling */
! 487: timeout_set(&sc->sc_dev_timeout, acpi_poll, sc);
! 488: #endif /* SMALL_KERNEL */
! 489:
! 490: /*
! 491: * Take over ACPI control. Note that once we do this, we
! 492: * effectively tell the system that we have ownership of
! 493: * the ACPI hardware registers, and that SMI should leave
! 494: * them alone
! 495: *
! 496: * This may prevent thermal control on some systems where
! 497: * that actually does work
! 498: */
! 499: #ifdef ACPI_ENABLE
! 500: int idx;
! 501:
! 502: acpi_write_pmreg(sc, ACPIREG_SMICMD, 0, sc->sc_fadt->acpi_enable);
! 503: idx = 0;
! 504: do {
! 505: if (idx++ > ACPIEN_RETRIES) {
! 506: printf(": can't enable ACPI\n");
! 507: return;
! 508: }
! 509: } while (!(acpi_read_pmreg(sc, ACPIREG_PM1_CNT, 0) & ACPI_PM1_SCI_EN));
! 510: #endif
! 511:
! 512: printf("\n");
! 513:
! 514: printf("%s: tables ", DEVNAME(sc));
! 515: SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) {
! 516: printf("%.4s ", entry->q_table);
! 517: }
! 518: printf("\n");
! 519:
! 520: #ifndef SMALL_KERNEL
! 521: /*
! 522: * ACPI is enabled now -- attach timer
! 523: */
! 524: {
! 525: struct acpi_attach_args aaa;
! 526:
! 527: memset(&aaa, 0, sizeof(aaa));
! 528: aaa.aaa_name = "acpitimer";
! 529: aaa.aaa_iot = sc->sc_iot;
! 530: aaa.aaa_memt = sc->sc_memt;
! 531: #if 0
! 532: aaa.aaa_pcit = sc->sc_pcit;
! 533: aaa.aaa_smbust = sc->sc_smbust;
! 534: #endif
! 535: config_found(self, &aaa, acpi_print);
! 536: }
! 537: #endif /* SMALL_KERNEL */
! 538:
! 539: /*
! 540: * Attach table-defined devices
! 541: */
! 542: SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) {
! 543: struct acpi_attach_args aaa;
! 544:
! 545: memset(&aaa, 0, sizeof(aaa));
! 546: aaa.aaa_iot = sc->sc_iot;
! 547: aaa.aaa_memt = sc->sc_memt;
! 548: #if 0
! 549: aaa.aaa_pcit = sc->sc_pcit;
! 550: aaa.aaa_smbust = sc->sc_smbust;
! 551: #endif
! 552: aaa.aaa_table = entry->q_table;
! 553: config_found_sm(self, &aaa, acpi_print, acpi_submatch);
! 554: }
! 555:
! 556: acpi_softc = sc;
! 557:
! 558: /* initialize runtime environment */
! 559: aml_find_node(aml_root.child, "_INI", acpi_inidev, sc);
! 560:
! 561: /* attach pci interrupt routing tables */
! 562: aml_find_node(aml_root.child, "_PRT", acpi_foundprt, sc);
! 563:
! 564: #ifndef SMALL_KERNEL
! 565: /* XXX EC needs to be attached first on some systems */
! 566: aml_find_node(aml_root.child, "_HID", acpi_foundec, sc);
! 567:
! 568: aml_walknodes(&aml_root, AML_WALK_PRE, acpi_add_device, sc);
! 569:
! 570: /* attach battery, power supply and button devices */
! 571: aml_find_node(aml_root.child, "_HID", acpi_foundhid, sc);
! 572:
! 573: /* attach docks */
! 574: aml_find_node(aml_root.child, "_DCK", acpi_founddock, sc);
! 575:
! 576: /* create list of devices we want to query when APM come in */
! 577: SLIST_INIT(&sc->sc_ac);
! 578: SLIST_INIT(&sc->sc_bat);
! 579: TAILQ_FOREACH(dev, &alldevs, dv_list) {
! 580: if (!strncmp(dev->dv_xname, "acpiac", strlen("acpiac"))) {
! 581: ac = malloc(sizeof(struct acpi_ac), M_DEVBUF, M_WAITOK);
! 582: memset(ac, 0, sizeof(struct acpi_ac));
! 583: ac->aac_softc = (struct acpiac_softc *)dev;
! 584: SLIST_INSERT_HEAD(&sc->sc_ac, ac, aac_link);
! 585: }
! 586: if (!strncmp(dev->dv_xname, "acpibat", strlen("acpibat"))) {
! 587: bat = malloc(sizeof(struct acpi_bat), M_DEVBUF,
! 588: M_WAITOK);
! 589: memset(bat, 0, sizeof(struct acpi_bat));
! 590: bat->aba_softc = (struct acpibat_softc *)dev;
! 591: SLIST_INSERT_HEAD(&sc->sc_bat, bat, aba_link);
! 592: }
! 593: }
! 594:
! 595: /* Setup threads */
! 596: sc->sc_thread = malloc(sizeof(struct acpi_thread), M_DEVBUF, M_WAITOK);
! 597: sc->sc_thread->sc = sc;
! 598: sc->sc_thread->running = 1;
! 599:
! 600: kthread_create_deferred(acpi_create_thread, sc);
! 601: #endif /* SMALL_KERNEL */
! 602: }
! 603:
! 604: int
! 605: acpi_submatch(struct device *parent, void *match, void *aux)
! 606: {
! 607: struct acpi_attach_args *aaa = (struct acpi_attach_args *)aux;
! 608: struct cfdata *cf = match;
! 609:
! 610: if (aaa->aaa_table == NULL)
! 611: return (0);
! 612: return ((*cf->cf_attach->ca_match)(parent, match, aux));
! 613: }
! 614:
! 615: int
! 616: acpi_print(void *aux, const char *pnp)
! 617: {
! 618: /* XXX ACPIVERBOSE should be replaced with dnprintf */
! 619: struct acpi_attach_args *aa = aux;
! 620: #ifdef ACPIVERBOSE
! 621: struct acpi_table_header *hdr =
! 622: (struct acpi_table_header *)aa->aaa_table;
! 623: #endif
! 624:
! 625: if (pnp) {
! 626: if (aa->aaa_name)
! 627: printf("%s at %s", aa->aaa_name, pnp);
! 628: #ifdef ACPIVERBOSE
! 629: else
! 630: printf("acpi device at %s from", pnp);
! 631: #else
! 632: else
! 633: return (QUIET);
! 634: #endif
! 635: }
! 636: #ifdef ACPIVERBOSE
! 637: if (hdr)
! 638: printf(" table %c%c%c%c",
! 639: hdr->signature[0], hdr->signature[1],
! 640: hdr->signature[2], hdr->signature[3]);
! 641: #endif
! 642:
! 643: return (UNCONF);
! 644: }
! 645:
! 646: int
! 647: acpi_loadtables(struct acpi_softc *sc, struct acpi_rsdp *rsdp)
! 648: {
! 649: struct acpi_mem_map hrsdt, handle;
! 650: struct acpi_table_header *hdr;
! 651: int i, ntables;
! 652: size_t len;
! 653:
! 654: if (rsdp->rsdp_revision == 2) {
! 655: struct acpi_xsdt *xsdt;
! 656:
! 657: if (acpi_map(rsdp->rsdp_xsdt, sizeof(*hdr), &handle)) {
! 658: printf("couldn't map rsdt\n");
! 659: return (ENOMEM);
! 660: }
! 661:
! 662: hdr = (struct acpi_table_header *)handle.va;
! 663: len = hdr->length;
! 664: acpi_unmap(&handle);
! 665: hdr = NULL;
! 666:
! 667: acpi_map(rsdp->rsdp_xsdt, len, &hrsdt);
! 668: xsdt = (struct acpi_xsdt *)hrsdt.va;
! 669:
! 670: ntables = (len - sizeof(struct acpi_table_header)) /
! 671: sizeof(xsdt->table_offsets[0]);
! 672:
! 673: for (i = 0; i < ntables; i++) {
! 674: acpi_map(xsdt->table_offsets[i], sizeof(*hdr), &handle);
! 675: hdr = (struct acpi_table_header *)handle.va;
! 676: acpi_load_table(xsdt->table_offsets[i], hdr->length,
! 677: &sc->sc_tables);
! 678: acpi_unmap(&handle);
! 679: }
! 680: acpi_unmap(&hrsdt);
! 681: } else {
! 682: struct acpi_rsdt *rsdt;
! 683:
! 684: if (acpi_map(rsdp->rsdp_rsdt, sizeof(*hdr), &handle)) {
! 685: printf("couldn't map rsdt\n");
! 686: return (ENOMEM);
! 687: }
! 688:
! 689: hdr = (struct acpi_table_header *)handle.va;
! 690: len = hdr->length;
! 691: acpi_unmap(&handle);
! 692: hdr = NULL;
! 693:
! 694: acpi_map(rsdp->rsdp_rsdt, len, &hrsdt);
! 695: rsdt = (struct acpi_rsdt *)hrsdt.va;
! 696:
! 697: ntables = (len - sizeof(struct acpi_table_header)) /
! 698: sizeof(rsdt->table_offsets[0]);
! 699:
! 700: for (i = 0; i < ntables; i++) {
! 701: acpi_map(rsdt->table_offsets[i], sizeof(*hdr), &handle);
! 702: hdr = (struct acpi_table_header *)handle.va;
! 703: acpi_load_table(rsdt->table_offsets[i], hdr->length,
! 704: &sc->sc_tables);
! 705: acpi_unmap(&handle);
! 706: }
! 707: acpi_unmap(&hrsdt);
! 708: }
! 709:
! 710: return (0);
! 711: }
! 712:
! 713: void
! 714: acpi_load_table(paddr_t pa, size_t len, acpi_qhead_t *queue)
! 715: {
! 716: struct acpi_mem_map handle;
! 717: struct acpi_q *entry;
! 718:
! 719: entry = malloc(len + sizeof(struct acpi_q), M_DEVBUF, M_NOWAIT);
! 720:
! 721: if (entry != NULL) {
! 722: if (acpi_map(pa, len, &handle)) {
! 723: free(entry, M_DEVBUF);
! 724: return;
! 725: }
! 726: memcpy(entry->q_data, handle.va, len);
! 727: entry->q_table = entry->q_data;
! 728: acpi_unmap(&handle);
! 729: SIMPLEQ_INSERT_TAIL(queue, entry, q_next);
! 730: }
! 731: }
! 732:
! 733: void
! 734: acpi_load_dsdt(paddr_t pa, struct acpi_q **dsdt)
! 735: {
! 736: struct acpi_mem_map handle;
! 737: struct acpi_table_header *hdr;
! 738: size_t len;
! 739:
! 740: if (acpi_map(pa, sizeof(*hdr), &handle))
! 741: return;
! 742: hdr = (struct acpi_table_header *)handle.va;
! 743: len = hdr->length;
! 744: acpi_unmap(&handle);
! 745:
! 746: *dsdt = malloc(len + sizeof(struct acpi_q), M_DEVBUF, M_NOWAIT);
! 747:
! 748: if (*dsdt != NULL) {
! 749: if (acpi_map(pa, len, &handle)) {
! 750: free(*dsdt, M_DEVBUF);
! 751: *dsdt = NULL;
! 752: return;
! 753: }
! 754: memcpy((*dsdt)->q_data, handle.va, len);
! 755: (*dsdt)->q_table = (*dsdt)->q_data;
! 756: acpi_unmap(&handle);
! 757: }
! 758: }
! 759:
! 760: int
! 761: acpiopen(dev_t dev, int flag, int mode, struct proc *p)
! 762: {
! 763: struct acpi_softc *sc;
! 764: int error = 0;
! 765:
! 766: if (!acpi_cd.cd_ndevs || minor(dev) != 0 ||
! 767: !(sc = acpi_cd.cd_devs[minor(dev)]))
! 768: return (ENXIO);
! 769:
! 770: return (error);
! 771: }
! 772:
! 773: int
! 774: acpiclose(dev_t dev, int flag, int mode, struct proc *p)
! 775: {
! 776: struct acpi_softc *sc;
! 777:
! 778: if (!acpi_cd.cd_ndevs || minor(dev) != 0 ||
! 779: !(sc = acpi_cd.cd_devs[minor(dev)]))
! 780: return (ENXIO);
! 781:
! 782: return (0);
! 783: }
! 784:
! 785: int
! 786: acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
! 787: {
! 788: int error = 0;
! 789: #ifndef SMALL_KERNEL
! 790: struct acpi_softc *sc;
! 791: struct acpi_ac *ac;
! 792: struct acpi_bat *bat;
! 793: struct apm_power_info *pi = (struct apm_power_info *)data;
! 794: int bats;
! 795: unsigned int remaining, rem, minutes, rate;
! 796:
! 797: if (!acpi_cd.cd_ndevs || minor(dev) != 0 ||
! 798: !(sc = acpi_cd.cd_devs[minor(dev)]))
! 799: return (ENXIO);
! 800:
! 801: ACPI_LOCK(sc);
! 802: /* fake APM */
! 803: switch (cmd) {
! 804: case APM_IOC_GETPOWER:
! 805: /* A/C */
! 806: pi->ac_state = APM_AC_UNKNOWN;
! 807: SLIST_FOREACH(ac, &sc->sc_ac, aac_link) {
! 808: if (ac->aac_softc->sc_ac_stat == PSR_ONLINE)
! 809: pi->ac_state = APM_AC_ON;
! 810: else if (ac->aac_softc->sc_ac_stat == PSR_OFFLINE)
! 811: if (pi->ac_state == APM_AC_UNKNOWN)
! 812: pi->ac_state = APM_AC_OFF;
! 813: }
! 814:
! 815: /* battery */
! 816: pi->battery_state = APM_BATT_UNKNOWN;
! 817: pi->battery_life = 0;
! 818: pi->minutes_left = 0;
! 819: bats = 0;
! 820: remaining = rem = 0;
! 821: minutes = 0;
! 822: rate = 0;
! 823: SLIST_FOREACH(bat, &sc->sc_bat, aba_link) {
! 824: if (bat->aba_softc->sc_bat_present == 0)
! 825: continue;
! 826:
! 827: if (bat->aba_softc->sc_bif.bif_last_capacity == 0)
! 828: continue;
! 829:
! 830: bats++;
! 831: rem = (bat->aba_softc->sc_bst.bst_capacity * 100) /
! 832: bat->aba_softc->sc_bif.bif_last_capacity;
! 833: if (rem > 100)
! 834: rem = 100;
! 835: remaining += rem;
! 836:
! 837: if (bat->aba_softc->sc_bst.bst_rate == BST_UNKNOWN)
! 838: continue;
! 839: else if (bat->aba_softc->sc_bst.bst_rate > 1)
! 840: rate = bat->aba_softc->sc_bst.bst_rate;
! 841:
! 842: minutes += bat->aba_softc->sc_bst.bst_capacity;
! 843: }
! 844:
! 845: if (bats == 0) {
! 846: pi->battery_state = APM_BATTERY_ABSENT;
! 847: pi->battery_life = 0;
! 848: pi->minutes_left = (unsigned int)-1;
! 849: break;
! 850: }
! 851:
! 852: if (pi->ac_state == APM_AC_ON || rate == 0)
! 853: pi->minutes_left = (unsigned int)-1;
! 854: else
! 855: pi->minutes_left = 100 * minutes / rate;
! 856:
! 857: /* running on battery */
! 858: pi->battery_life = remaining / bats;
! 859: if (pi->battery_life > 50)
! 860: pi->battery_state = APM_BATT_HIGH;
! 861: else if (pi->battery_life > 25)
! 862: pi->battery_state = APM_BATT_LOW;
! 863: else
! 864: pi->battery_state = APM_BATT_CRITICAL;
! 865:
! 866: break;
! 867:
! 868: default:
! 869: error = ENOTTY;
! 870: }
! 871:
! 872: ACPI_UNLOCK(sc);
! 873: #else
! 874: error = ENXIO;
! 875: #endif /* SMALL_KERNEL */
! 876: return (error);
! 877: }
! 878:
! 879: void
! 880: acpi_filtdetach(struct knote *kn)
! 881: {
! 882: struct acpi_softc *sc = kn->kn_hook;
! 883:
! 884: ACPI_LOCK(sc);
! 885: SLIST_REMOVE(sc->sc_note, kn, knote, kn_selnext);
! 886: ACPI_UNLOCK(sc);
! 887: }
! 888:
! 889: int
! 890: acpi_filtread(struct knote *kn, long hint)
! 891: {
! 892: /* XXX weird kqueue_scan() semantics */
! 893: if (hint & !kn->kn_data)
! 894: kn->kn_data = hint;
! 895:
! 896: return (1);
! 897: }
! 898:
! 899: int
! 900: acpikqfilter(dev_t dev, struct knote *kn)
! 901: {
! 902: struct acpi_softc *sc;
! 903:
! 904: if (!acpi_cd.cd_ndevs || minor(dev) != 0 ||
! 905: !(sc = acpi_cd.cd_devs[minor(dev)]))
! 906: return (ENXIO);
! 907:
! 908: switch (kn->kn_filter) {
! 909: case EVFILT_READ:
! 910: kn->kn_fop = &acpiread_filtops;
! 911: break;
! 912: default:
! 913: return (1);
! 914: }
! 915:
! 916: kn->kn_hook = sc;
! 917:
! 918: ACPI_LOCK(sc);
! 919: SLIST_INSERT_HEAD(sc->sc_note, kn, kn_selnext);
! 920: ACPI_UNLOCK(sc);
! 921:
! 922: return (0);
! 923: }
! 924:
! 925: /* move all stuff that doesn't go on the boot media in here */
! 926: #ifndef SMALL_KERNEL
! 927: int
! 928: acpi_interrupt(void *arg)
! 929: {
! 930: struct acpi_softc *sc = (struct acpi_softc *)arg;
! 931: u_int32_t processed, sts, en, idx, jdx;
! 932:
! 933: processed = 0;
! 934:
! 935: dnprintf(40, "ACPI Interrupt\n");
! 936: for (idx = 0; idx < sc->sc_lastgpe; idx += 8) {
! 937: sts = acpi_read_pmreg(sc, ACPIREG_GPE_STS, idx>>3);
! 938: en = acpi_read_pmreg(sc, ACPIREG_GPE_EN, idx>>3);
! 939: if (en & sts) {
! 940: dnprintf(10, "GPE block: %.2x %.2x %.2x\n", idx, sts,
! 941: en);
! 942: acpi_write_pmreg(sc, ACPIREG_GPE_EN, idx>>3, en & ~sts);
! 943: for (jdx = 0; jdx < 8; jdx++) {
! 944: if (en & sts & (1L << jdx)) {
! 945: /* Signal this GPE */
! 946: sc->gpe_table[idx+jdx].active = 1;
! 947: processed = 1;
! 948: }
! 949: }
! 950: }
! 951: }
! 952:
! 953: sts = acpi_read_pmreg(sc, ACPIREG_PM1_STS, 0);
! 954: en = acpi_read_pmreg(sc, ACPIREG_PM1_EN, 0);
! 955: if (sts & en) {
! 956: dnprintf(10,"GEN interrupt: %.4x\n", sts & en);
! 957: acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, en & ~sts);
! 958: acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0, en);
! 959: acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, en);
! 960: if (sts & ACPI_PM1_PWRBTN_STS)
! 961: sc->sc_powerbtn = 1;
! 962: if (sts & ACPI_PM1_SLPBTN_STS)
! 963: sc->sc_sleepbtn = 1;
! 964: processed = 1;
! 965: }
! 966:
! 967: if (processed) {
! 968: sc->sc_wakeup = 0;
! 969: wakeup(sc);
! 970: }
! 971:
! 972: return (processed);
! 973: }
! 974:
! 975: void
! 976: acpi_enable_onegpe(struct acpi_softc *sc, int gpe, int enable)
! 977: {
! 978: uint8_t mask = (1L << (gpe & 7));
! 979: uint8_t en;
! 980:
! 981: /* Read enabled register */
! 982: en = acpi_read_pmreg(sc, ACPIREG_GPE_EN, gpe>>3);
! 983: dnprintf(50, "%sabling GPE %.2x (current: %sabled) %.2x\n",
! 984: enable ? "en" : "dis", gpe, (en & mask) ? "en" : "dis", en);
! 985: if (enable)
! 986: en |= mask;
! 987: else
! 988: en &= ~mask;
! 989: acpi_write_pmreg(sc, ACPIREG_GPE_EN, gpe>>3, en);
! 990: }
! 991:
! 992: int
! 993: acpi_set_gpehandler(struct acpi_softc *sc, int gpe, int (*handler)
! 994: (struct acpi_softc *, int, void *), void *arg, const char *label)
! 995: {
! 996: if (gpe >= sc->sc_lastgpe || handler == NULL)
! 997: return -EINVAL;
! 998:
! 999: if (sc->gpe_table[gpe].handler != NULL) {
! 1000: dnprintf(10, "error: GPE %.2x already enabled!\n", gpe);
! 1001: return -EBUSY;
! 1002: }
! 1003:
! 1004: dnprintf(50, "Adding GPE handler %.2x (%s)\n", gpe, label);
! 1005: sc->gpe_table[gpe].handler = handler;
! 1006: sc->gpe_table[gpe].arg = arg;
! 1007:
! 1008: /* Defer enabling GPEs */
! 1009:
! 1010: return (0);
! 1011: }
! 1012:
! 1013: int
! 1014: acpi_gpe_level(struct acpi_softc *sc, int gpe, void *arg)
! 1015: {
! 1016: struct aml_node *node = arg;
! 1017: uint8_t mask;
! 1018:
! 1019: dnprintf(10, "handling Level-sensitive GPE %.2x\n", gpe);
! 1020: mask = (1L << (gpe & 7));
! 1021:
! 1022: aml_evalnode(sc, node, 0, NULL, NULL);
! 1023: acpi_write_pmreg(sc, ACPIREG_GPE_STS, gpe>>3, mask);
! 1024: acpi_write_pmreg(sc, ACPIREG_GPE_EN, gpe>>3, mask);
! 1025:
! 1026: return (0);
! 1027: }
! 1028:
! 1029: int
! 1030: acpi_gpe_edge(struct acpi_softc *sc, int gpe, void *arg)
! 1031: {
! 1032:
! 1033: struct aml_node *node = arg;
! 1034: uint8_t mask;
! 1035:
! 1036: dnprintf(10, "handling Edge-sensitive GPE %.2x\n", gpe);
! 1037: mask = (1L << (gpe & 7));
! 1038:
! 1039: aml_evalnode(sc, node, 0, NULL, NULL);
! 1040: acpi_write_pmreg(sc, ACPIREG_GPE_STS, gpe>>3, mask);
! 1041: acpi_write_pmreg(sc, ACPIREG_GPE_EN, gpe>>3, mask);
! 1042:
! 1043: return (0);
! 1044: }
! 1045:
! 1046: void
! 1047: acpi_init_gpes(struct acpi_softc *sc)
! 1048: {
! 1049: struct aml_node *gpe;
! 1050: char name[12];
! 1051: int idx, ngpe;
! 1052:
! 1053: sc->sc_lastgpe = sc->sc_fadt->gpe0_blk_len << 2;
! 1054: if (sc->sc_fadt->gpe1_blk_len) {
! 1055: }
! 1056: dnprintf(50, "Last GPE: %.2x\n", sc->sc_lastgpe);
! 1057:
! 1058: /* Allocate GPE table */
! 1059: sc->gpe_table = malloc(sc->sc_lastgpe * sizeof(struct gpe_block),
! 1060: M_DEVBUF, M_WAITOK);
! 1061: memset(sc->gpe_table, 0, sc->sc_lastgpe * sizeof(struct gpe_block));
! 1062:
! 1063: ngpe = 0;
! 1064:
! 1065: /* Clear GPE status */
! 1066: for (idx = 0; idx < sc->sc_lastgpe; idx += 8) {
! 1067: acpi_write_pmreg(sc, ACPIREG_GPE_EN, idx>>3, 0);
! 1068: acpi_write_pmreg(sc, ACPIREG_GPE_STS, idx>>3, -1);
! 1069: }
! 1070: for (idx = 0; idx < sc->sc_lastgpe; idx++) {
! 1071: /* Search Level-sensitive GPES */
! 1072: snprintf(name, sizeof(name), "\\_GPE._L%.2X", idx);
! 1073: gpe = aml_searchname(&aml_root, name);
! 1074: if (gpe != NULL)
! 1075: acpi_set_gpehandler(sc, idx, acpi_gpe_level, gpe,
! 1076: "level");
! 1077: if (gpe == NULL) {
! 1078: /* Search Edge-sensitive GPES */
! 1079: snprintf(name, sizeof(name), "\\_GPE._E%.2X", idx);
! 1080: gpe = aml_searchname(&aml_root, name);
! 1081: if (gpe != NULL)
! 1082: acpi_set_gpehandler(sc, idx, acpi_gpe_edge, gpe,
! 1083: "edge");
! 1084: }
! 1085: }
! 1086: sc->sc_maxgpe = ngpe;
! 1087: }
! 1088:
! 1089: void
! 1090: acpi_init_states(struct acpi_softc *sc)
! 1091: {
! 1092: struct aml_value res;
! 1093: char name[8];
! 1094: int i;
! 1095:
! 1096: for (i = ACPI_STATE_S0; i <= ACPI_STATE_S5; i++) {
! 1097: snprintf(name, sizeof(name), "_S%d_", i);
! 1098: sc->sc_sleeptype[i].slp_typa = -1;
! 1099: sc->sc_sleeptype[i].slp_typb = -1;
! 1100: if (aml_evalname(sc, aml_root.child, name, 0, NULL, &res) == 0) {
! 1101: if (res.type == AML_OBJTYPE_PACKAGE) {
! 1102: sc->sc_sleeptype[i].slp_typa = aml_val2int(res.v_package[0]);
! 1103: sc->sc_sleeptype[i].slp_typb = aml_val2int(res.v_package[1]);
! 1104: }
! 1105: aml_freevalue(&res);
! 1106: }
! 1107: }
! 1108: }
! 1109:
! 1110: void
! 1111: acpi_init_pm(struct acpi_softc *sc)
! 1112: {
! 1113: sc->sc_tts = aml_searchname(aml_root.child, "_TTS");
! 1114: sc->sc_pts = aml_searchname(aml_root.child, "_PTS");
! 1115: sc->sc_wak = aml_searchname(aml_root.child, "_WAK");
! 1116: sc->sc_bfs = aml_searchname(aml_root.child, "_BFS");
! 1117: sc->sc_gts = aml_searchname(aml_root.child, "_GTS");
! 1118: }
! 1119:
! 1120: void
! 1121: acpi_enter_sleep_state(struct acpi_softc *sc, int state)
! 1122: {
! 1123: #ifdef ACPI_ENABLE
! 1124: struct aml_value env;
! 1125: u_int16_t rega, regb;
! 1126: int retries;
! 1127:
! 1128: if (state == ACPI_STATE_S0)
! 1129: return;
! 1130: if (sc->sc_sleeptype[state].slp_typa == -1 ||
! 1131: sc->sc_sleeptype[state].slp_typb == -1) {
! 1132: printf("%s: state S%d unavailable\n",
! 1133: sc->sc_dev.dv_xname, state);
! 1134: return;
! 1135: }
! 1136:
! 1137: env.type = AML_OBJTYPE_INTEGER;
! 1138: env.v_integer = state;
! 1139: /* _TTS(state) */
! 1140: if (sc->sc_tts) {
! 1141: if (aml_evalnode(sc, sc->sc_tts, 1, &env, NULL) != 0) {
! 1142: dnprintf(10, "%s evaluating method _TTS failed.\n",
! 1143: DEVNAME(sc));
! 1144: return;
! 1145: }
! 1146: }
! 1147: switch (state) {
! 1148: case ACPI_STATE_S1:
! 1149: case ACPI_STATE_S2:
! 1150: resettodr();
! 1151: dopowerhooks(PWR_SUSPEND);
! 1152: break;
! 1153: case ACPI_STATE_S3:
! 1154: resettodr();
! 1155: dopowerhooks(PWR_STANDBY);
! 1156: break;
! 1157: }
! 1158: /* _PTS(state) */
! 1159: if (sc->sc_pts) {
! 1160: if (aml_evalnode(sc, sc->sc_pts, 1, &env, NULL) != 0) {
! 1161: dnprintf(10, "%s evaluating method _PTS failed.\n",
! 1162: DEVNAME(sc));
! 1163: return;
! 1164: }
! 1165: }
! 1166: sc->sc_state = state;
! 1167: /* _GTS(state) */
! 1168: if (sc->sc_gts) {
! 1169: if (aml_evalnode(sc, sc->sc_gts, 1, &env, NULL) != 0) {
! 1170: dnprintf(10, "%s evaluating method _GTS failed.\n",
! 1171: DEVNAME(sc));
! 1172: return;
! 1173: }
! 1174: }
! 1175: disable_intr();
! 1176:
! 1177: /* Clear WAK_STS bit */
! 1178: acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0, ACPI_PM1_WAK_STS);
! 1179:
! 1180: /* Write SLP_TYPx values */
! 1181: rega = acpi_read_pmreg(sc, ACPIREG_PM1A_CNT, 0);
! 1182: regb = acpi_read_pmreg(sc, ACPIREG_PM1B_CNT, 0);
! 1183: rega &= ~(ACPI_PM1_SLP_TYPX_MASK | ACPI_PM1_SLP_EN);
! 1184: regb &= ~(ACPI_PM1_SLP_TYPX_MASK | ACPI_PM1_SLP_EN);
! 1185: rega |= ACPI_PM1_SLP_TYPX(sc->sc_sleeptype[state].slp_typa);
! 1186: regb |= ACPI_PM1_SLP_TYPX(sc->sc_sleeptype[state].slp_typb);
! 1187: acpi_write_pmreg(sc, ACPIREG_PM1A_CNT, 0, rega);
! 1188: acpi_write_pmreg(sc, ACPIREG_PM1B_CNT, 0, regb);
! 1189:
! 1190: /* Set SLP_EN bit */
! 1191: rega |= ACPI_PM1_SLP_EN;
! 1192: regb |= ACPI_PM1_SLP_EN;
! 1193: acpi_write_pmreg(sc, ACPIREG_PM1A_CNT, 0, rega);
! 1194: acpi_write_pmreg(sc, ACPIREG_PM1B_CNT, 0, regb);
! 1195:
! 1196: /* Loop on WAK_STS */
! 1197: for (retries = 1000; retries > 0; retries--) {
! 1198: rega = acpi_read_pmreg(sc, ACPIREG_PM1A_STS, 0);
! 1199: regb = acpi_read_pmreg(sc, ACPIREG_PM1B_STS, 0);
! 1200: if (rega & ACPI_PM1_WAK_STS ||
! 1201: regb & ACPI_PM1_WAK_STS)
! 1202: break;
! 1203: DELAY(10);
! 1204: }
! 1205:
! 1206: enable_intr();
! 1207: #endif
! 1208: }
! 1209:
! 1210: void
! 1211: acpi_resume(struct acpi_softc *sc)
! 1212: {
! 1213: struct aml_value env;
! 1214:
! 1215: env.type = AML_OBJTYPE_INTEGER;
! 1216: env.v_integer = sc->sc_state;
! 1217:
! 1218: if (sc->sc_bfs) {
! 1219: if (aml_evalnode(sc, sc->sc_pts, 1, &env, NULL) != 0) {
! 1220: dnprintf(10, "%s evaluating method _BFS failed.\n",
! 1221: DEVNAME(sc));
! 1222: }
! 1223: }
! 1224: dopowerhooks(PWR_RESUME);
! 1225: inittodr(0);
! 1226: if (sc->sc_wak) {
! 1227: if (aml_evalnode(sc, sc->sc_wak, 1, &env, NULL) != 0) {
! 1228: dnprintf(10, "%s evaluating method _WAK failed.\n",
! 1229: DEVNAME(sc));
! 1230: }
! 1231: }
! 1232: sc->sc_state = ACPI_STATE_S0;
! 1233: if (sc->sc_tts) {
! 1234: env.v_integer = sc->sc_state;
! 1235: if (aml_evalnode(sc, sc->sc_wak, 1, &env, NULL) != 0) {
! 1236: dnprintf(10, "%s evaluating method _TTS failed.\n",
! 1237: DEVNAME(sc));
! 1238: }
! 1239: }
! 1240: }
! 1241:
! 1242: void
! 1243: acpi_powerdown(void)
! 1244: {
! 1245: acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5);
! 1246: }
! 1247:
! 1248: void
! 1249: acpi_isr_thread(void *arg)
! 1250: {
! 1251: struct acpi_thread *thread = arg;
! 1252: struct acpi_softc *sc = thread->sc;
! 1253: u_int32_t gpe;
! 1254:
! 1255: acpi_attach_machdep(sc);
! 1256:
! 1257: /*
! 1258: * If we have an interrupt handler, we can get notification
! 1259: * when certain status bits changes in the ACPI registers,
! 1260: * so let us enable some events we can forward to userland
! 1261: */
! 1262: if (sc->sc_interrupt) {
! 1263: int16_t flag;
! 1264:
! 1265: dnprintf(1,"slpbtn:%c pwrbtn:%c\n",
! 1266: sc->sc_fadt->flags & FADT_SLP_BUTTON ? 'n' : 'y',
! 1267: sc->sc_fadt->flags & FADT_PWR_BUTTON ? 'n' : 'y');
! 1268: dnprintf(10, "Enabling acpi interrupts...\n");
! 1269: sc->sc_wakeup = 1;
! 1270:
! 1271: /* Enable Sleep/Power buttons if they exist */
! 1272: flag = acpi_read_pmreg(sc, ACPIREG_PM1_EN, 0);
! 1273: if (!(sc->sc_fadt->flags & FADT_PWR_BUTTON)) {
! 1274: flag |= ACPI_PM1_PWRBTN_EN;
! 1275: }
! 1276: if (!(sc->sc_fadt->flags & FADT_SLP_BUTTON)) {
! 1277: flag |= ACPI_PM1_SLPBTN_EN;
! 1278: }
! 1279: acpi_write_pmreg(sc, ACPIREG_PM1_EN, 0, flag);
! 1280:
! 1281: /* Enable handled GPEs here */
! 1282: for (gpe = 0; gpe < sc->sc_lastgpe; gpe++) {
! 1283: if (sc->gpe_table[gpe].handler)
! 1284: acpi_enable_onegpe(sc, gpe, 1);
! 1285: }
! 1286: }
! 1287:
! 1288: while (thread->running) {
! 1289: dnprintf(10, "sleep... %d\n", sc->sc_wakeup);
! 1290: while (sc->sc_wakeup)
! 1291: tsleep(sc, PWAIT, "acpi_idle", 0);
! 1292: sc->sc_wakeup = 1;
! 1293: dnprintf(10, "wakeup..\n");
! 1294:
! 1295: for (gpe = 0; gpe < sc->sc_lastgpe; gpe++) {
! 1296: struct gpe_block *pgpe = &sc->gpe_table[gpe];
! 1297:
! 1298: if (pgpe->active) {
! 1299: pgpe->active = 0;
! 1300: dnprintf(50, "softgpe: %.2x\n", gpe);
! 1301: if (pgpe->handler)
! 1302: pgpe->handler(sc, gpe, pgpe->arg);
! 1303: }
! 1304: }
! 1305: if (sc->sc_powerbtn) {
! 1306: sc->sc_powerbtn = 0;
! 1307:
! 1308: aml_notify_dev(ACPI_DEV_PBD, 0x80);
! 1309:
! 1310: acpi_evindex++;
! 1311: dnprintf(1,"power button pressed\n");
! 1312: KNOTE(sc->sc_note, ACPI_EVENT_COMPOSE(ACPI_EV_PWRBTN,
! 1313: acpi_evindex));
! 1314: }
! 1315: if (sc->sc_sleepbtn) {
! 1316: sc->sc_sleepbtn = 0;
! 1317:
! 1318: aml_notify_dev(ACPI_DEV_SBD, 0x80);
! 1319:
! 1320: acpi_evindex++;
! 1321: dnprintf(1,"sleep button pressed\n");
! 1322: KNOTE(sc->sc_note, ACPI_EVENT_COMPOSE(ACPI_EV_SLPBTN,
! 1323: acpi_evindex));
! 1324: }
! 1325:
! 1326: /* handle polling here to keep code non-concurrent*/
! 1327: if (sc->sc_poll) {
! 1328: sc->sc_poll = 0;
! 1329: acpi_poll_notify();
! 1330: }
! 1331: }
! 1332: free(thread, M_DEVBUF);
! 1333:
! 1334: kthread_exit(0);
! 1335: }
! 1336:
! 1337: void
! 1338: acpi_create_thread(void *arg)
! 1339: {
! 1340: struct acpi_softc *sc = arg;
! 1341:
! 1342: if (kthread_create(acpi_isr_thread, sc->sc_thread, NULL, DEVNAME(sc))
! 1343: != 0) {
! 1344: printf("%s: unable to create isr thread, GPEs disabled\n",
! 1345: DEVNAME(sc));
! 1346: return;
! 1347: }
! 1348: }
! 1349:
! 1350: int
! 1351: acpi_map_address(struct acpi_softc *sc, struct acpi_gas *gas, bus_addr_t base, bus_size_t size,
! 1352: bus_space_handle_t *pioh, bus_space_tag_t *piot)
! 1353: {
! 1354: int iospace = GAS_SYSTEM_IOSPACE;
! 1355:
! 1356: /* No GAS structure, default to I/O space */
! 1357: if (gas != NULL) {
! 1358: base += gas->address;
! 1359: iospace = gas->address_space_id;
! 1360: }
! 1361: switch (iospace) {
! 1362: case GAS_SYSTEM_MEMORY:
! 1363: *piot = sc->sc_memt;
! 1364: break;
! 1365: case GAS_SYSTEM_IOSPACE:
! 1366: *piot = sc->sc_iot;
! 1367: break;
! 1368: default:
! 1369: return -1;
! 1370: }
! 1371: if (bus_space_map(*piot, base, size, 0, pioh))
! 1372: return -1;
! 1373:
! 1374: return 0;
! 1375: }
! 1376:
! 1377: /* Map Power Management registers */
! 1378: void
! 1379: acpi_map_pmregs(struct acpi_softc *sc)
! 1380: {
! 1381: bus_addr_t addr;
! 1382: bus_size_t size;
! 1383: const char *name;
! 1384: int reg;
! 1385:
! 1386: for (reg = 0; reg < ACPIREG_MAXREG; reg++) {
! 1387: size = 0;
! 1388: switch (reg) {
! 1389: case ACPIREG_SMICMD:
! 1390: name = "smi";
! 1391: size = 1;
! 1392: addr = sc->sc_fadt->smi_cmd;
! 1393: break;
! 1394: case ACPIREG_PM1A_STS:
! 1395: case ACPIREG_PM1A_EN:
! 1396: name = "pm1a_sts";
! 1397: size = sc->sc_fadt->pm1_evt_len >> 1;
! 1398: addr = sc->sc_fadt->pm1a_evt_blk;
! 1399: if (reg == ACPIREG_PM1A_EN && addr) {
! 1400: addr += size;
! 1401: name = "pm1a_en";
! 1402: }
! 1403: break;
! 1404: case ACPIREG_PM1A_CNT:
! 1405: name = "pm1a_cnt";
! 1406: size = sc->sc_fadt->pm1_cnt_len;
! 1407: addr = sc->sc_fadt->pm1a_cnt_blk;
! 1408: break;
! 1409: case ACPIREG_PM1B_STS:
! 1410: case ACPIREG_PM1B_EN:
! 1411: name = "pm1b_sts";
! 1412: size = sc->sc_fadt->pm1_evt_len >> 1;
! 1413: addr = sc->sc_fadt->pm1b_evt_blk;
! 1414: if (reg == ACPIREG_PM1B_EN && addr) {
! 1415: addr += size;
! 1416: name = "pm1b_en";
! 1417: }
! 1418: break;
! 1419: case ACPIREG_PM1B_CNT:
! 1420: name = "pm1b_cnt";
! 1421: size = sc->sc_fadt->pm1_cnt_len;
! 1422: addr = sc->sc_fadt->pm1b_cnt_blk;
! 1423: break;
! 1424: case ACPIREG_PM2_CNT:
! 1425: name = "pm2_cnt";
! 1426: size = sc->sc_fadt->pm2_cnt_len;
! 1427: addr = sc->sc_fadt->pm2_cnt_blk;
! 1428: break;
! 1429: #if 0
! 1430: case ACPIREG_PM_TMR:
! 1431: /* Allocated in acpitimer */
! 1432: name = "pm_tmr";
! 1433: size = sc->sc_fadt->pm_tmr_len;
! 1434: addr = sc->sc_fadt->pm_tmr_blk;
! 1435: break;
! 1436: #endif
! 1437: case ACPIREG_GPE0_STS:
! 1438: case ACPIREG_GPE0_EN:
! 1439: name = "gpe0_sts";
! 1440: size = sc->sc_fadt->gpe0_blk_len >> 1;
! 1441: addr = sc->sc_fadt->gpe0_blk;
! 1442:
! 1443: dnprintf(20, "gpe0 block len : %x\n",
! 1444: sc->sc_fadt->gpe0_blk_len >> 1);
! 1445: dnprintf(20, "gpe0 block addr: %x\n",
! 1446: sc->sc_fadt->gpe0_blk);
! 1447: if (reg == ACPIREG_GPE0_EN && addr) {
! 1448: addr += size;
! 1449: name = "gpe0_en";
! 1450: }
! 1451: break;
! 1452: case ACPIREG_GPE1_STS:
! 1453: case ACPIREG_GPE1_EN:
! 1454: name = "gpe1_sts";
! 1455: size = sc->sc_fadt->gpe1_blk_len >> 1;
! 1456: addr = sc->sc_fadt->gpe1_blk;
! 1457:
! 1458: dnprintf(20, "gpe1 block len : %x\n",
! 1459: sc->sc_fadt->gpe1_blk_len >> 1);
! 1460: dnprintf(20, "gpe1 block addr: %x\n",
! 1461: sc->sc_fadt->gpe1_blk);
! 1462: if (reg == ACPIREG_GPE1_EN && addr) {
! 1463: addr += size;
! 1464: name = "gpe1_en";
! 1465: }
! 1466: break;
! 1467: }
! 1468: if (size && addr) {
! 1469: dnprintf(50, "mapping: %.4x %.4x %s\n",
! 1470: addr, size, name);
! 1471:
! 1472: /* Size and address exist; map register space */
! 1473: bus_space_map(sc->sc_iot, addr, size, 0,
! 1474: &sc->sc_pmregs[reg].ioh);
! 1475:
! 1476: sc->sc_pmregs[reg].name = name;
! 1477: sc->sc_pmregs[reg].size = size;
! 1478: sc->sc_pmregs[reg].addr = addr;
! 1479: }
! 1480: }
! 1481: }
! 1482:
! 1483: /* Read from power management register */
! 1484: int
! 1485: acpi_read_pmreg(struct acpi_softc *sc, int reg, int offset)
! 1486: {
! 1487: bus_space_handle_t ioh;
! 1488: bus_size_t size, __size;
! 1489: int regval;
! 1490:
! 1491: __size = 0;
! 1492: /* Special cases: 1A/1B blocks can be OR'ed together */
! 1493: switch (reg) {
! 1494: case ACPIREG_PM1_EN:
! 1495: return (acpi_read_pmreg(sc, ACPIREG_PM1A_EN, offset) |
! 1496: acpi_read_pmreg(sc, ACPIREG_PM1B_EN, offset));
! 1497: case ACPIREG_PM1_STS:
! 1498: return (acpi_read_pmreg(sc, ACPIREG_PM1A_STS, offset) |
! 1499: acpi_read_pmreg(sc, ACPIREG_PM1B_STS, offset));
! 1500: case ACPIREG_PM1_CNT:
! 1501: return (acpi_read_pmreg(sc, ACPIREG_PM1A_CNT, offset) |
! 1502: acpi_read_pmreg(sc, ACPIREG_PM1B_CNT, offset));
! 1503: case ACPIREG_GPE_STS:
! 1504: __size = 1;
! 1505: dnprintf(50, "read GPE_STS offset: %.2x %.2x %.2x\n", offset,
! 1506: sc->sc_fadt->gpe0_blk_len>>1, sc->sc_fadt->gpe1_blk_len>>1);
! 1507: if (offset < (sc->sc_fadt->gpe0_blk_len >> 1)) {
! 1508: reg = ACPIREG_GPE0_STS;
! 1509: }
! 1510: break;
! 1511: case ACPIREG_GPE_EN:
! 1512: __size = 1;
! 1513: dnprintf(50, "read GPE_EN offset: %.2x %.2x %.2x\n",
! 1514: offset, sc->sc_fadt->gpe0_blk_len>>1,
! 1515: sc->sc_fadt->gpe1_blk_len>>1);
! 1516: if (offset < (sc->sc_fadt->gpe0_blk_len >> 1)) {
! 1517: reg = ACPIREG_GPE0_EN;
! 1518: }
! 1519: break;
! 1520: }
! 1521:
! 1522: if (reg >= ACPIREG_MAXREG || sc->sc_pmregs[reg].size == 0)
! 1523: return (0);
! 1524:
! 1525: regval = 0;
! 1526: ioh = sc->sc_pmregs[reg].ioh;
! 1527: size = sc->sc_pmregs[reg].size;
! 1528: if (__size)
! 1529: size = __size;
! 1530: if (size > 4)
! 1531: size = 4;
! 1532:
! 1533: switch (size) {
! 1534: case 1:
! 1535: regval = bus_space_read_1(sc->sc_iot, ioh, offset);
! 1536: break;
! 1537: case 2:
! 1538: regval = bus_space_read_2(sc->sc_iot, ioh, offset);
! 1539: break;
! 1540: case 4:
! 1541: regval = bus_space_read_4(sc->sc_iot, ioh, offset);
! 1542: break;
! 1543: }
! 1544:
! 1545: dnprintf(30, "acpi_readpm: %s = %.4x:%.4x %x\n",
! 1546: sc->sc_pmregs[reg].name,
! 1547: sc->sc_pmregs[reg].addr, offset, regval);
! 1548: return (regval);
! 1549: }
! 1550:
! 1551: /* Write to power management register */
! 1552: void
! 1553: acpi_write_pmreg(struct acpi_softc *sc, int reg, int offset, int regval)
! 1554: {
! 1555: bus_space_handle_t ioh;
! 1556: bus_size_t size, __size;
! 1557:
! 1558: __size = 0;
! 1559: /* Special cases: 1A/1B blocks can be written with same value */
! 1560: switch (reg) {
! 1561: case ACPIREG_PM1_EN:
! 1562: acpi_write_pmreg(sc, ACPIREG_PM1A_EN, offset, regval);
! 1563: acpi_write_pmreg(sc, ACPIREG_PM1B_EN, offset, regval);
! 1564: break;
! 1565: case ACPIREG_PM1_STS:
! 1566: acpi_write_pmreg(sc, ACPIREG_PM1A_STS, offset, regval);
! 1567: acpi_write_pmreg(sc, ACPIREG_PM1B_STS, offset, regval);
! 1568: break;
! 1569: case ACPIREG_PM1_CNT:
! 1570: acpi_write_pmreg(sc, ACPIREG_PM1A_CNT, offset, regval);
! 1571: acpi_write_pmreg(sc, ACPIREG_PM1B_CNT, offset, regval);
! 1572: break;
! 1573: case ACPIREG_GPE_STS:
! 1574: __size = 1;
! 1575: dnprintf(50, "write GPE_STS offset: %.2x %.2x %.2x %.2x\n",
! 1576: offset, sc->sc_fadt->gpe0_blk_len>>1,
! 1577: sc->sc_fadt->gpe1_blk_len>>1, regval);
! 1578: if (offset < (sc->sc_fadt->gpe0_blk_len >> 1)) {
! 1579: reg = ACPIREG_GPE0_STS;
! 1580: }
! 1581: break;
! 1582: case ACPIREG_GPE_EN:
! 1583: __size = 1;
! 1584: dnprintf(50, "write GPE_EN offset: %.2x %.2x %.2x %.2x\n",
! 1585: offset, sc->sc_fadt->gpe0_blk_len>>1,
! 1586: sc->sc_fadt->gpe1_blk_len>>1, regval);
! 1587: if (offset < (sc->sc_fadt->gpe0_blk_len >> 1)) {
! 1588: reg = ACPIREG_GPE0_EN;
! 1589: }
! 1590: break;
! 1591: }
! 1592:
! 1593: /* All special case return here */
! 1594: if (reg >= ACPIREG_MAXREG)
! 1595: return;
! 1596:
! 1597: ioh = sc->sc_pmregs[reg].ioh;
! 1598: size = sc->sc_pmregs[reg].size;
! 1599: if (__size)
! 1600: size = __size;
! 1601: if (size > 4)
! 1602: size = 4;
! 1603: switch (size) {
! 1604: case 1:
! 1605: bus_space_write_1(sc->sc_iot, ioh, offset, regval);
! 1606: break;
! 1607: case 2:
! 1608: bus_space_write_2(sc->sc_iot, ioh, offset, regval);
! 1609: break;
! 1610: case 4:
! 1611: bus_space_write_4(sc->sc_iot, ioh, offset, regval);
! 1612: break;
! 1613: }
! 1614:
! 1615: dnprintf(30, "acpi_writepm: %s = %.4x:%.4x %x\n",
! 1616: sc->sc_pmregs[reg].name, sc->sc_pmregs[reg].addr, offset, regval);
! 1617: }
! 1618:
! 1619: void
! 1620: acpi_foundec(struct aml_node *node, void *arg)
! 1621: {
! 1622: struct acpi_softc *sc = (struct acpi_softc *)arg;
! 1623: struct device *self = (struct device *)arg;
! 1624: const char *dev;
! 1625: struct aml_value res;
! 1626: struct acpi_attach_args aaa;
! 1627:
! 1628: if (aml_evalnode(sc, node, 0, NULL, &res) != 0)
! 1629: return;
! 1630:
! 1631: switch (res.type) {
! 1632: case AML_OBJTYPE_STRING:
! 1633: dev = res.v_string;
! 1634: break;
! 1635: case AML_OBJTYPE_INTEGER:
! 1636: dev = aml_eisaid(aml_val2int(&res));
! 1637: break;
! 1638: default:
! 1639: dev = "unknown";
! 1640: break;
! 1641: }
! 1642:
! 1643: if (strcmp(dev, ACPI_DEV_ECD))
! 1644: return;
! 1645:
! 1646: memset(&aaa, 0, sizeof(aaa));
! 1647: aaa.aaa_iot = sc->sc_iot;
! 1648: aaa.aaa_memt = sc->sc_memt;
! 1649: aaa.aaa_node = node->parent;
! 1650: aaa.aaa_dev = dev;
! 1651: aaa.aaa_name = "acpiec";
! 1652: config_found(self, &aaa, acpi_print);
! 1653: aml_freevalue(&res);
! 1654: }
! 1655:
! 1656: void
! 1657: acpi_foundhid(struct aml_node *node, void *arg)
! 1658: {
! 1659: struct acpi_softc *sc = (struct acpi_softc *)arg;
! 1660: struct device *self = (struct device *)arg;
! 1661: const char *dev;
! 1662: struct aml_value res;
! 1663: struct acpi_attach_args aaa;
! 1664:
! 1665: dnprintf(10, "found hid device: %s ", node->parent->name);
! 1666: if (aml_evalnode(sc, node, 0, NULL, &res) != 0)
! 1667: return;
! 1668:
! 1669: switch (res.type) {
! 1670: case AML_OBJTYPE_STRING:
! 1671: dev = res.v_string;
! 1672: break;
! 1673: case AML_OBJTYPE_INTEGER:
! 1674: dev = aml_eisaid(aml_val2int(&res));
! 1675: break;
! 1676: default:
! 1677: dev = "unknown";
! 1678: break;
! 1679: }
! 1680: dnprintf(10, " device: %s\n", dev);
! 1681:
! 1682: memset(&aaa, 0, sizeof(aaa));
! 1683: aaa.aaa_iot = sc->sc_iot;
! 1684: aaa.aaa_memt = sc->sc_memt;
! 1685: aaa.aaa_node = node->parent;
! 1686: aaa.aaa_dev = dev;
! 1687:
! 1688: if (!strcmp(dev, ACPI_DEV_AC))
! 1689: aaa.aaa_name = "acpiac";
! 1690: else if (!strcmp(dev, ACPI_DEV_CMB))
! 1691: aaa.aaa_name = "acpibat";
! 1692: else if (!strcmp(dev, ACPI_DEV_LD) ||
! 1693: !strcmp(dev, ACPI_DEV_PBD) ||
! 1694: !strcmp(dev, ACPI_DEV_SBD))
! 1695: aaa.aaa_name = "acpibtn";
! 1696:
! 1697: if (aaa.aaa_name)
! 1698: config_found(self, &aaa, acpi_print);
! 1699: aml_freevalue(&res);
! 1700: }
! 1701:
! 1702: void
! 1703: acpi_founddock(struct aml_node *node, void *arg)
! 1704: {
! 1705: struct acpi_softc *sc = (struct acpi_softc *)arg;
! 1706: struct device *self = (struct device *)arg;
! 1707: const char *dev;
! 1708: struct acpi_attach_args aaa;
! 1709:
! 1710: dnprintf(10, "found dock entry: %s\n", node->parent->name);
! 1711:
! 1712: memset(&aaa, 0, sizeof(aaa));
! 1713: aaa.aaa_iot = sc->sc_iot;
! 1714: aaa.aaa_memt = sc->sc_memt;
! 1715: aaa.aaa_node = node->parent;
! 1716: aaa.aaa_dev = dev;
! 1717: aaa.aaa_name = "acpidock";
! 1718:
! 1719: config_found(self, &aaa, acpi_print);
! 1720: }
! 1721: #endif /* SMALL_KERNEL */
CVSweb