Annotation of sys/dev/acpi/acpi.c, Revision 1.1.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