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