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