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