acpi.c revision 1.95
1/*	$NetBSD: acpi.c,v 1.95 2006/09/26 01:50:43 jmcneill Exp $	*/
2
3/*-
4 * Copyright (c) 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum of By Noon Software, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the NetBSD
21 *	Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 *    contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39/*
40 * Copyright 2001, 2003 Wasabi Systems, Inc.
41 * All rights reserved.
42 *
43 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 *    notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 *    notice, this list of conditions and the following disclaimer in the
52 *    documentation and/or other materials provided with the distribution.
53 * 3. All advertising materials mentioning features or use of this software
54 *    must display the following acknowledgement:
55 *	This product includes software developed for the NetBSD Project by
56 *	Wasabi Systems, Inc.
57 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
58 *    or promote products derived from this software without specific prior
59 *    written permission.
60 *
61 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
63 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
64 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
65 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
66 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
68 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
69 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
70 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
71 * POSSIBILITY OF SUCH DAMAGE.
72 */
73
74/*
75 * Autoconfiguration support for the Intel ACPI Component Architecture
76 * ACPI reference implementation.
77 */
78
79#include <sys/cdefs.h>
80__KERNEL_RCSID(0, "$NetBSD: acpi.c,v 1.95 2006/09/26 01:50:43 jmcneill Exp $");
81
82#include "opt_acpi.h"
83#include "opt_pcifixup.h"
84
85#include <sys/param.h>
86#include <sys/systm.h>
87#include <sys/device.h>
88#include <sys/malloc.h>
89#include <sys/kernel.h>
90#include <sys/proc.h>
91#include <sys/sysctl.h>
92
93#include <dev/acpi/acpica.h>
94#include <dev/acpi/acpireg.h>
95#include <dev/acpi/acpivar.h>
96#include <dev/acpi/acpi_osd.h>
97#include <dev/acpi/acpi_timer.h>
98#ifdef ACPIVERBOSE
99#include <dev/acpi/acpidevs_data.h>
100#endif
101
102#if defined(ACPI_PCI_FIXUP)
103#error The option ACPI_PCI_FIXUP has been obsoleted by PCI_INTR_FIXUP_DISABLED.  Please adjust your kernel configuration file.
104#endif
105
106#ifdef PCI_INTR_FIXUP_DISABLED
107#include <dev/pci/pcidevs.h>
108#endif
109
110MALLOC_DECLARE(M_ACPI);
111
112#include <machine/acpi_machdep.h>
113
114#ifdef ACPI_DEBUGGER
115#define	ACPI_DBGR_INIT		0x01
116#define	ACPI_DBGR_TABLES	0x02
117#define	ACPI_DBGR_ENABLE	0x04
118#define	ACPI_DBGR_PROBE		0x08
119#define	ACPI_DBGR_RUNNING	0x10
120
121static int acpi_dbgr = 0x00;
122#endif
123
124static int	acpi_match(struct device *, struct cfdata *, void *);
125static void	acpi_attach(struct device *, struct device *, void *);
126
127static int	acpi_print(void *aux, const char *);
128
129static int	sysctl_hw_acpi_sleepstate(SYSCTLFN_ARGS);
130
131extern struct cfdriver acpi_cd;
132
133CFATTACH_DECL(acpi, sizeof(struct acpi_softc),
134    acpi_match, acpi_attach, NULL, NULL);
135
136/*
137 * This is a flag we set when the ACPI subsystem is active.  Machine
138 * dependent code may wish to skip other steps (such as attaching
139 * subsystems that ACPI supercedes) when ACPI is active.
140 */
141int	acpi_active;
142int	acpi_force_load;
143
144/*
145 * Pointer to the ACPI subsystem's state.  There can be only
146 * one ACPI instance.
147 */
148struct acpi_softc *acpi_softc;
149
150/*
151 * Locking stuff.
152 */
153static struct simplelock acpi_slock;
154static int acpi_locked;
155
156/*
157 * sysctl-related information
158 */
159
160static int acpi_node = CTL_EOL;
161static uint64_t acpi_root_pointer;	/* found as hw.acpi.root */
162static int acpi_sleepstate = ACPI_STATE_S0;
163
164/*
165 * Prototypes.
166 */
167static void		acpi_shutdown(void *);
168static void		acpi_build_tree(struct acpi_softc *);
169static ACPI_STATUS	acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **);
170
171static void		acpi_enable_fixed_events(struct acpi_softc *);
172
173/*
174 * acpi_probe:
175 *
176 *	Probe for ACPI support.  This is called by the
177 *	machine-dependent ACPI front-end.  All of the
178 *	actual work is done by ACPICA.
179 *
180 *	NOTE: This is not an autoconfiguration interface function.
181 */
182int
183acpi_probe(void)
184{
185	static int beenhere;
186	ACPI_STATUS rv;
187
188	if (beenhere != 0)
189		panic("acpi_probe: ACPI has already been probed");
190	beenhere = 1;
191
192	simple_lock_init(&acpi_slock);
193	acpi_locked = 0;
194
195	/*
196	 * Start up ACPICA.
197	 */
198#ifdef ACPI_DEBUGGER
199	if (acpi_dbgr & ACPI_DBGR_INIT)
200		acpi_osd_debugger();
201#endif
202
203	rv = AcpiInitializeSubsystem();
204	if (ACPI_FAILURE(rv)) {
205		printf("ACPI: unable to initialize ACPICA: %s\n",
206		    AcpiFormatException(rv));
207		return 0;
208	}
209
210#ifdef ACPI_DEBUGGER
211	if (acpi_dbgr & ACPI_DBGR_TABLES)
212		acpi_osd_debugger();
213#endif
214
215	rv = AcpiLoadTables();
216	if (ACPI_FAILURE(rv)) {
217		printf("ACPI: unable to load tables: %s\n",
218		    AcpiFormatException(rv));
219		return 0;
220	}
221
222
223	if (!acpi_force_load && (acpi_find_quirks() & ACPI_QUIRK_BROKEN)) {
224		printf("ACPI: BIOS implementation in listed as broken:\n");
225		printf("ACPI: X/RSDT: OemId <%6.6s,%8.8s,%08x>, "
226		       "AslId <%4.4s,%08x>\n",
227			AcpiGbl_XSDT->OemId, AcpiGbl_XSDT->OemTableId,
228		        AcpiGbl_XSDT->OemRevision,
229			AcpiGbl_XSDT->AslCompilerId,
230		        AcpiGbl_XSDT->AslCompilerRevision);
231		printf("ACPI: not used. set acpi_force_load to use anyway.\n");
232		return 0;
233	}
234
235	/*
236	 * Looks like we have ACPI!
237	 */
238
239	return 1;
240}
241
242ACPI_STATUS
243acpi_OsGetRootPointer(UINT32 Flags, ACPI_POINTER *PhysicalAddress)
244{
245	ACPI_STATUS rv;
246
247	/*
248	 * IA-32: Use AcpiFindRootPointer() to locate the RSDP.
249	 *
250	 * IA-64: Use the EFI.
251	 *
252	 * We let MD code handle this since there are multiple
253	 * ways to do it.
254	 */
255
256	rv = acpi_md_OsGetRootPointer(Flags, PhysicalAddress);
257
258	if (acpi_root_pointer == 0 && ACPI_SUCCESS(rv))
259		acpi_root_pointer =
260		    (uint64_t)PhysicalAddress->Pointer.Physical;
261
262	return rv;
263}
264
265/*
266 * acpi_match:
267 *
268 *	Autoconfiguration `match' routine.
269 */
270static int
271acpi_match(struct device *parent, struct cfdata *match, void *aux)
272{
273	/*
274	 * XXX Check other locators?  Hard to know -- machine
275	 * dependent code has already checked for the presence
276	 * of ACPI by calling acpi_probe(), so I suppose we
277	 * don't really have to do anything else.
278	 */
279	return 1;
280}
281
282/*
283 * acpi_attach:
284 *
285 *	Autoconfiguration `attach' routine.  Finish initializing
286 *	ACPICA (some initialization was done in acpi_probe(),
287 *	which was required to check for the presence of ACPI),
288 *	and enable the ACPI subsystem.
289 */
290static void
291acpi_attach(struct device *parent, struct device *self, void *aux)
292{
293	struct acpi_softc *sc = (void *) self;
294	struct acpibus_attach_args *aa = aux;
295	ACPI_STATUS rv;
296
297	aprint_naive(": Advanced Configuration and Power Interface\n");
298	aprint_normal(": Advanced Configuration and Power Interface\n");
299
300	if (acpi_softc != NULL)
301		panic("acpi_attach: ACPI has already been attached");
302
303	sysmon_power_settype("acpi");
304
305	aprint_verbose("%s: using Intel ACPI CA subsystem version %08x\n",
306	    sc->sc_dev.dv_xname, ACPI_CA_VERSION);
307
308	aprint_verbose("%s: X/RSDT: OemId <%6.6s,%8.8s,%08x>, AslId <%4.4s,%08x>\n",
309	    sc->sc_dev.dv_xname,
310	    AcpiGbl_XSDT->OemId, AcpiGbl_XSDT->OemTableId,
311	    AcpiGbl_XSDT->OemRevision,
312	    AcpiGbl_XSDT->AslCompilerId, AcpiGbl_XSDT->AslCompilerRevision);
313
314	sc->sc_quirks = acpi_find_quirks();
315
316	sc->sc_iot = aa->aa_iot;
317	sc->sc_memt = aa->aa_memt;
318	sc->sc_pc = aa->aa_pc;
319	sc->sc_pciflags = aa->aa_pciflags;
320	sc->sc_ic = aa->aa_ic;
321
322	acpi_softc = sc;
323
324	/*
325	 * Bring ACPI on-line.
326	 */
327#ifdef ACPI_DEBUGGER
328	if (acpi_dbgr & ACPI_DBGR_ENABLE)
329		acpi_osd_debugger();
330#endif
331
332	rv = AcpiEnableSubsystem(0);
333	if (ACPI_FAILURE(rv)) {
334		aprint_error("%s: unable to enable ACPI: %s\n",
335		    sc->sc_dev.dv_xname, AcpiFormatException(rv));
336		return;
337	}
338
339	/* early EC handler initialization if ECDT table is available */
340#if NACPIEC > 0
341	acpiec_early_attach(&sc->sc_dev);
342#endif
343
344	rv = AcpiInitializeObjects(0);
345	if (ACPI_FAILURE(rv)) {
346		aprint_error("%s: unable to initialize ACPI objects: %s\n",
347		    sc->sc_dev.dv_xname, AcpiFormatException(rv));
348		return;
349	}
350	acpi_active = 1;
351
352	/* Our current state is "awake". */
353	sc->sc_sleepstate = ACPI_STATE_S0;
354
355	/* Show SCI interrupt. */
356	if (AcpiGbl_FADT != NULL)
357		aprint_verbose("%s: SCI interrupting at int %d\n",
358		    sc->sc_dev.dv_xname, AcpiGbl_FADT->SciInt);
359	/*
360	 * Check for fixed-hardware features.
361	 */
362	acpi_enable_fixed_events(sc);
363	acpitimer_init();
364
365	/*
366	 * Scan the namespace and build our device tree.
367	 */
368#ifdef ACPI_DEBUGGER
369	if (acpi_dbgr & ACPI_DBGR_PROBE)
370		acpi_osd_debugger();
371#endif
372	acpi_md_callback((struct device *)sc);
373	acpi_build_tree(sc);
374
375	if (acpi_root_pointer != 0 && acpi_node != CTL_EOL) {
376		(void)sysctl_createv(NULL, 0, NULL, NULL,
377		    CTLFLAG_IMMEDIATE,
378		    CTLTYPE_QUAD, "root", NULL, NULL,
379		    acpi_root_pointer, NULL, 0,
380		    CTL_HW, acpi_node, CTL_CREATE, CTL_EOL);
381	}
382
383
384	/*
385	 * Register a shutdown hook that disables certain ACPI
386	 * events that might happen and confuse us while we're
387	 * trying to shut down.
388	 */
389	sc->sc_sdhook = shutdownhook_establish(acpi_shutdown, sc);
390	if (sc->sc_sdhook == NULL)
391		aprint_error("%s: WARNING: unable to register shutdown hook\n",
392		    sc->sc_dev.dv_xname);
393
394#ifdef ACPI_DEBUGGER
395	if (acpi_dbgr & ACPI_DBGR_RUNNING)
396		acpi_osd_debugger();
397#endif
398}
399
400/*
401 * acpi_shutdown:
402 *
403 *	Shutdown hook for ACPI -- disable some events that
404 *	might confuse us.
405 */
406static void
407acpi_shutdown(void *arg)
408{
409	/* nothing */
410}
411
412#if 0
413/*
414 * acpi_disable:
415 *
416 *	Disable ACPI.
417 */
418static ACPI_STATUS
419acpi_disable(struct acpi_softc *sc)
420{
421	ACPI_STATUS rv = AE_OK;
422
423	if (acpi_active) {
424		rv = AcpiDisable();
425		if (ACPI_SUCCESS(rv))
426			acpi_active = 0;
427	}
428	return rv;
429}
430#endif
431
432struct acpi_make_devnode_state {
433	struct acpi_softc *softc;
434	struct acpi_scope *scope;
435};
436
437/*
438 * acpi_build_tree:
439 *
440 *	Scan relevant portions of the ACPI namespace and attach
441 *	child devices.
442 */
443static void
444acpi_build_tree(struct acpi_softc *sc)
445{
446	static const char *scopes[] = {
447		"\\_PR_",	/* ACPI 1.0 processor namespace */
448		"\\_SB_",	/* system bus namespace */
449		"\\_SI_",	/* system indicator namespace */
450		"\\_TZ_",	/* ACPI 1.0 thermal zone namespace */
451		NULL,
452	};
453	struct acpi_attach_args aa;
454	struct acpi_make_devnode_state state;
455	struct acpi_scope *as;
456	struct acpi_devnode *ad;
457	ACPI_HANDLE parent;
458	ACPI_STATUS rv;
459	int i;
460
461	TAILQ_INIT(&sc->sc_scopes);
462
463	state.softc = sc;
464
465	/*
466	 * Scan the namespace and build our tree.
467	 */
468	for (i = 0; scopes[i] != NULL; i++) {
469		as = malloc(sizeof(*as), M_ACPI, M_WAITOK);
470		as->as_name = scopes[i];
471		TAILQ_INIT(&as->as_devnodes);
472
473		TAILQ_INSERT_TAIL(&sc->sc_scopes, as, as_list);
474
475		state.scope = as;
476
477		rv = AcpiGetHandle(ACPI_ROOT_OBJECT, scopes[i],
478		    &parent);
479		if (ACPI_SUCCESS(rv)) {
480			AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100,
481			    acpi_make_devnode, &state, NULL);
482		}
483
484		/* Now, for this namespace, try and attach the devices. */
485		TAILQ_FOREACH(ad, &as->as_devnodes, ad_list) {
486			aa.aa_node = ad;
487			aa.aa_iot = sc->sc_iot;
488			aa.aa_memt = sc->sc_memt;
489			aa.aa_pc = sc->sc_pc;
490			aa.aa_pciflags = sc->sc_pciflags;
491			aa.aa_ic = sc->sc_ic;
492
493			if (ad->ad_devinfo->Type == ACPI_TYPE_DEVICE) {
494				/*
495				 * XXX We only attach devices which are:
496				 *
497				 *	- present
498				 *	- enabled
499				 *	- functioning properly
500				 *
501				 * However, if enabled, it's decoding resources,
502				 * so we should claim them, if possible.
503				 * Requires changes to bus_space(9).
504				 */
505				if ((ad->ad_devinfo->Valid & ACPI_VALID_STA) ==
506				    ACPI_VALID_STA &&
507				    (ad->ad_devinfo->CurrentStatus &
508				     (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|
509				      ACPI_STA_DEV_OK)) !=
510				    (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|
511				     ACPI_STA_DEV_OK))
512					continue;
513
514				/*
515				 * XXX Same problem as above...
516				 */
517				if ((ad->ad_devinfo->Valid & ACPI_VALID_HID)
518				    == 0)
519					continue;
520			}
521
522			ad->ad_device = config_found_ia(&sc->sc_dev,
523			    "acpinodebus", &aa, acpi_print);
524		}
525	}
526	config_found_ia(&sc->sc_dev, "acpiapmbus", NULL, NULL);
527}
528
529#ifdef ACPI_ACTIVATE_DEV
530static void
531acpi_activate_device(ACPI_HANDLE handle, ACPI_DEVICE_INFO **di)
532{
533	ACPI_STATUS rv;
534	ACPI_BUFFER buf;
535
536	buf.Pointer = NULL;
537	buf.Length = ACPI_ALLOCATE_BUFFER;
538
539#ifdef ACPI_DEBUG
540	aprint_normal("acpi_activate_device: %s, old status=%x\n",
541	       (*di)->HardwareId.Value, (*di)->CurrentStatus);
542#endif
543
544	rv = acpi_allocate_resources(handle);
545	if (ACPI_FAILURE(rv)) {
546		aprint_error("acpi: activate failed for %s\n",
547		       (*di)->HardwareId.Value);
548	} else {
549		aprint_normal("acpi: activated %s\n", (*di)->HardwareId.Value);
550	}
551
552	(void)AcpiGetObjectInfo(handle, &buf);
553	AcpiOsFree(*di);
554	*di = buf.Pointer;
555
556#ifdef ACPI_DEBUG
557	aprint_normal("acpi_activate_device: %s, new status=%x\n",
558	       (*di)->HardwareId.Value, (*di)->CurrentStatus);
559#endif
560}
561#endif /* ACPI_ACTIVATE_DEV */
562
563/*
564 * acpi_make_devnode:
565 *
566 *	Make an ACPI devnode.
567 */
568static ACPI_STATUS
569acpi_make_devnode(ACPI_HANDLE handle, UINT32 level, void *context,
570    void **status)
571{
572	struct acpi_make_devnode_state *state = context;
573#if defined(ACPI_DEBUG) || defined(ACPI_EXTRA_DEBUG)
574	struct acpi_softc *sc = state->softc;
575#endif
576	struct acpi_scope *as = state->scope;
577	struct acpi_devnode *ad;
578	ACPI_OBJECT_TYPE type;
579	ACPI_BUFFER buf;
580	ACPI_DEVICE_INFO *devinfo;
581	ACPI_STATUS rv;
582
583	rv = AcpiGetType(handle, &type);
584	if (ACPI_SUCCESS(rv)) {
585		buf.Pointer = NULL;
586		buf.Length = ACPI_ALLOCATE_BUFFER;
587		rv = AcpiGetObjectInfo(handle, &buf);
588		if (ACPI_FAILURE(rv)) {
589#ifdef ACPI_DEBUG
590			aprint_normal("%s: AcpiGetObjectInfo failed: %s\n",
591			    sc->sc_dev.dv_xname, AcpiFormatException(rv));
592#endif
593			goto out; /* XXX why return OK */
594		}
595
596		devinfo = buf.Pointer;
597
598		switch (type) {
599		case ACPI_TYPE_DEVICE:
600#ifdef ACPI_ACTIVATE_DEV
601			if ((devinfo->Valid & (ACPI_VALID_STA|ACPI_VALID_HID)) ==
602			    (ACPI_VALID_STA|ACPI_VALID_HID) &&
603			    (devinfo->CurrentStatus &
604			     (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED)) ==
605			    ACPI_STA_DEV_PRESENT)
606				acpi_activate_device(handle, &devinfo);
607
608			/* FALLTHROUGH */
609#endif
610
611		case ACPI_TYPE_PROCESSOR:
612		case ACPI_TYPE_THERMAL:
613		case ACPI_TYPE_POWER:
614			ad = malloc(sizeof(*ad), M_ACPI, M_NOWAIT|M_ZERO);
615			if (ad == NULL)
616				return AE_NO_MEMORY;
617
618			ad->ad_devinfo = devinfo;
619			ad->ad_handle = handle;
620			ad->ad_level = level;
621			ad->ad_scope = as;
622			ad->ad_type = type;
623
624			TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list);
625
626			if ((ad->ad_devinfo->Valid & ACPI_VALID_HID) == 0)
627				goto out;
628
629#ifdef ACPI_EXTRA_DEBUG
630			aprint_normal("%s: HID %s found in scope %s level %d\n",
631			    sc->sc_dev.dv_xname,
632			    ad->ad_devinfo->HardwareId.Value,
633			    as->as_name, ad->ad_level);
634			if (ad->ad_devinfo->Valid & ACPI_VALID_UID)
635				aprint_normal("       UID %s\n",
636				    ad->ad_devinfo->UniqueId.Value);
637			if (ad->ad_devinfo->Valid & ACPI_VALID_ADR)
638				aprint_normal("       ADR 0x%016qx\n",
639				    ad->ad_devinfo->Address);
640			if (ad->ad_devinfo->Valid & ACPI_VALID_STA)
641				aprint_normal("       STA 0x%08x\n",
642				    ad->ad_devinfo->CurrentStatus);
643#endif
644		}
645	}
646 out:
647	return AE_OK;
648}
649
650/*
651 * acpi_print:
652 *
653 *	Autoconfiguration print routine for ACPI node bus.
654 */
655static int
656acpi_print(void *aux, const char *pnp)
657{
658	struct acpi_attach_args *aa = aux;
659	ACPI_STATUS rv;
660
661	if (pnp) {
662		if (aa->aa_node->ad_devinfo->Valid & ACPI_VALID_HID) {
663			char *pnpstr =
664			    aa->aa_node->ad_devinfo->HardwareId.Value;
665			char *str;
666
667			aprint_normal("%s ", pnpstr);
668			rv = acpi_eval_string(aa->aa_node->ad_handle,
669			    "_STR", &str);
670			if (ACPI_SUCCESS(rv)) {
671				aprint_normal("[%s] ", str);
672				AcpiOsFree(str);
673			}
674#ifdef ACPIVERBOSE
675			else {
676				int i;
677
678				for (i = 0; i < sizeof(acpi_knowndevs) /
679				    sizeof(acpi_knowndevs[0]); i++) {
680					if (strcmp(acpi_knowndevs[i].pnp,
681					    pnpstr) == 0) {
682						aprint_normal("[%s] ",
683						    acpi_knowndevs[i].str);
684					}
685				}
686			}
687
688#endif
689		} else {
690			aprint_normal("ACPI Object Type '%s' (0x%02x) ",
691			   AcpiUtGetTypeName(aa->aa_node->ad_devinfo->Type),
692			   aa->aa_node->ad_devinfo->Type);
693		}
694		aprint_normal("at %s", pnp);
695	} else {
696		if (aa->aa_node->ad_devinfo->Valid & ACPI_VALID_HID) {
697			aprint_normal(" (%s", aa->aa_node->ad_devinfo->HardwareId.Value);
698			if (aa->aa_node->ad_devinfo->Valid & ACPI_VALID_UID) {
699				const char *uid;
700
701				uid = aa->aa_node->ad_devinfo->UniqueId.Value;
702				if (uid[0] == '\0')
703					uid = "<null>";
704				aprint_normal("-%s", uid);
705			}
706			aprint_normal(")");
707		}
708	}
709
710	return UNCONF;
711}
712
713/*****************************************************************************
714 * ACPI fixed-hardware feature handlers
715 *****************************************************************************/
716
717static UINT32	acpi_fixed_button_handler(void *);
718static void	acpi_fixed_button_pressed(void *);
719
720/*
721 * acpi_enable_fixed_events:
722 *
723 *	Enable any fixed-hardware feature handlers.
724 */
725static void
726acpi_enable_fixed_events(struct acpi_softc *sc)
727{
728	static int beenhere;
729	ACPI_STATUS rv;
730
731	KASSERT(beenhere == 0);
732	beenhere = 1;
733
734	/*
735	 * Check for fixed-hardware buttons.
736	 */
737
738	if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) {
739		aprint_normal("%s: fixed-feature power button present\n",
740		    sc->sc_dev.dv_xname);
741		sc->sc_smpsw_power.smpsw_name = sc->sc_dev.dv_xname;
742		sc->sc_smpsw_power.smpsw_type = PSWITCH_TYPE_POWER;
743		if (sysmon_pswitch_register(&sc->sc_smpsw_power) != 0) {
744			aprint_error("%s: unable to register fixed power "
745			    "button with sysmon\n", sc->sc_dev.dv_xname);
746		} else {
747			rv = AcpiInstallFixedEventHandler(
748			    ACPI_EVENT_POWER_BUTTON,
749			    acpi_fixed_button_handler, &sc->sc_smpsw_power);
750			if (ACPI_FAILURE(rv)) {
751				aprint_error("%s: unable to install handler "
752				    "for fixed power button: %s\n",
753				    sc->sc_dev.dv_xname,
754				    AcpiFormatException(rv));
755			}
756		}
757	}
758
759	if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) {
760		aprint_normal("%s: fixed-feature sleep button present\n",
761		    sc->sc_dev.dv_xname);
762		sc->sc_smpsw_sleep.smpsw_name = sc->sc_dev.dv_xname;
763		sc->sc_smpsw_sleep.smpsw_type = PSWITCH_TYPE_SLEEP;
764		if (sysmon_pswitch_register(&sc->sc_smpsw_power) != 0) {
765			aprint_error("%s: unable to register fixed sleep "
766			    "button with sysmon\n", sc->sc_dev.dv_xname);
767		} else {
768			rv = AcpiInstallFixedEventHandler(
769			    ACPI_EVENT_SLEEP_BUTTON,
770			    acpi_fixed_button_handler, &sc->sc_smpsw_sleep);
771			if (ACPI_FAILURE(rv)) {
772				aprint_error("%s: unable to install handler "
773				    "for fixed sleep button: %s\n",
774				    sc->sc_dev.dv_xname,
775				    AcpiFormatException(rv));
776			}
777		}
778	}
779}
780
781/*
782 * acpi_fixed_button_handler:
783 *
784 *	Event handler for the fixed buttons.
785 */
786static UINT32
787acpi_fixed_button_handler(void *context)
788{
789	struct sysmon_pswitch *smpsw = context;
790	int rv;
791
792#ifdef ACPI_BUT_DEBUG
793	printf("%s: fixed button handler\n", smpsw->smpsw_name);
794#endif
795
796	rv = AcpiOsQueueForExecution(OSD_PRIORITY_LO,
797	    acpi_fixed_button_pressed, smpsw);
798	if (ACPI_FAILURE(rv))
799		printf("%s: WARNING: unable to queue fixed button pressed "
800		    "callback: %s\n", smpsw->smpsw_name,
801		    AcpiFormatException(rv));
802
803	return ACPI_INTERRUPT_HANDLED;
804}
805
806/*
807 * acpi_fixed_button_pressed:
808 *
809 *	Deal with a fixed button being pressed.
810 */
811static void
812acpi_fixed_button_pressed(void *context)
813{
814	struct sysmon_pswitch *smpsw = context;
815
816#ifdef ACPI_BUT_DEBUG
817	printf("%s: fixed button pressed, calling sysmon\n",
818	    smpsw->smpsw_name);
819#endif
820
821	sysmon_pswitch_event(smpsw, PSWITCH_EVENT_PRESSED);
822}
823
824/*****************************************************************************
825 * ACPI utility routines.
826 *****************************************************************************/
827
828/*
829 * acpi_eval_integer:
830 *
831 *	Evaluate an integer object.
832 */
833ACPI_STATUS
834acpi_eval_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER *valp)
835{
836	ACPI_STATUS rv;
837	ACPI_BUFFER buf;
838	ACPI_OBJECT param;
839
840	if (handle == NULL)
841		handle = ACPI_ROOT_OBJECT;
842
843	buf.Pointer = &param;
844	buf.Length = sizeof(param);
845
846	rv = AcpiEvaluateObjectTyped(handle, path, NULL, &buf, ACPI_TYPE_INTEGER);
847	if (ACPI_SUCCESS(rv))
848		*valp = param.Integer.Value;
849
850	return rv;
851}
852
853/*
854 * acpi_eval_string:
855 *
856 *	Evaluate a (Unicode) string object.
857 */
858ACPI_STATUS
859acpi_eval_string(ACPI_HANDLE handle, const char *path, char **stringp)
860{
861	ACPI_STATUS rv;
862	ACPI_BUFFER buf;
863
864	if (handle == NULL)
865		handle = ACPI_ROOT_OBJECT;
866
867	buf.Pointer = NULL;
868	buf.Length = ACPI_ALLOCATE_BUFFER;
869
870	rv = AcpiEvaluateObjectTyped(handle, path, NULL, &buf, ACPI_TYPE_STRING);
871	if (ACPI_SUCCESS(rv)) {
872		ACPI_OBJECT *param = buf.Pointer;
873		const char *ptr = param->String.Pointer;
874		size_t len = param->String.Length;
875		if ((*stringp = AcpiOsAllocate(len)) == NULL)
876			rv = AE_NO_MEMORY;
877		else
878			(void)memcpy(*stringp, ptr, len);
879		AcpiOsFree(param);
880	}
881
882	return rv;
883}
884
885
886/*
887 * acpi_eval_struct:
888 *
889 *	Evaluate a more complex structure.
890 *	Caller must free buf.Pointer by AcpiOsFree().
891 */
892ACPI_STATUS
893acpi_eval_struct(ACPI_HANDLE handle, const char *path, ACPI_BUFFER *bufp)
894{
895	ACPI_STATUS rv;
896
897	if (handle == NULL)
898		handle = ACPI_ROOT_OBJECT;
899
900	bufp->Pointer = NULL;
901	bufp->Length = ACPI_ALLOCATE_BUFFER;
902
903	rv = AcpiEvaluateObject(handle, path, NULL, bufp);
904
905	return rv;
906}
907
908/*
909 * acpi_foreach_package_object:
910 *
911 *	Iterate over all objects in a in a packages and pass then all
912 *	to a function. If the called function returns non AE_OK, the
913 *	iteration is stopped and that value is returned.
914 */
915
916ACPI_STATUS
917acpi_foreach_package_object(ACPI_OBJECT *pkg,
918    ACPI_STATUS (*func)(ACPI_OBJECT *, void *),
919    void *arg)
920{
921	ACPI_STATUS rv = AE_OK;
922	int i;
923
924	if (pkg == NULL || pkg->Type != ACPI_TYPE_PACKAGE)
925		return AE_BAD_PARAMETER;
926
927	for (i = 0; i < pkg->Package.Count; i++) {
928		rv = (*func)(&pkg->Package.Elements[i], arg);
929		if (ACPI_FAILURE(rv))
930			break;
931	}
932
933	return rv;
934}
935
936const char *
937acpi_name(ACPI_HANDLE handle)
938{
939	static char buffer[80];
940	ACPI_BUFFER buf;
941	ACPI_STATUS rv;
942
943	buf.Length = sizeof(buffer);
944	buf.Pointer = buffer;
945
946	rv = AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf);
947	if (ACPI_FAILURE(rv))
948		return "(unknown acpi path)";
949	return buffer;
950}
951
952/*
953 * acpi_get:
954 *
955 *	Fetch data info the specified (empty) ACPI buffer.
956 *	Caller must free buf.Pointer by AcpiOsFree().
957 */
958ACPI_STATUS
959acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf,
960    ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *))
961{
962	buf->Pointer = NULL;
963	buf->Length = ACPI_ALLOCATE_BUFFER;
964
965	return (*getit)(handle, buf);
966}
967
968
969/*
970 * acpi_match_hid
971 *
972 *	Match given ids against _HID and _CIDs
973 */
974int
975acpi_match_hid(ACPI_DEVICE_INFO *ad, const char * const *ids)
976{
977	int i;
978
979	while (*ids) {
980		if (ad->Valid & ACPI_VALID_HID) {
981			if (pmatch(ad->HardwareId.Value, *ids, NULL) == 2)
982				return 1;
983		}
984
985		if (ad->Valid & ACPI_VALID_CID) {
986			for (i = 0; i < ad->CompatibilityId.Count; i++) {
987				if (pmatch(ad->CompatibilityId.Id[i].Value, *ids, NULL) == 2)
988					return 1;
989			}
990		}
991		ids++;
992	}
993
994	return 0;
995}
996
997/*
998 * acpi_set_wake_gpe
999 *
1000 *	Set GPE as both Runtime and Wake
1001 */
1002void
1003acpi_set_wake_gpe(ACPI_HANDLE handle)
1004{
1005	ACPI_BUFFER buf;
1006	ACPI_STATUS rv;
1007	ACPI_OBJECT *p, *elt;
1008
1009	rv = acpi_eval_struct(handle, METHOD_NAME__PRW, &buf);
1010	if (ACPI_FAILURE(rv))
1011		return;			/* just ignore */
1012
1013	p = buf.Pointer;
1014	if (p->Type != ACPI_TYPE_PACKAGE || p->Package.Count < 2)
1015		goto out;		/* just ignore */
1016
1017	elt = p->Package.Elements;
1018
1019	/* TBD: package support */
1020	AcpiSetGpeType(NULL, elt[0].Integer.Value, ACPI_GPE_TYPE_WAKE_RUN);
1021	AcpiEnableGpe(NULL, elt[0].Integer.Value, ACPI_NOT_ISR);
1022
1023 out:
1024	AcpiOsFree(buf.Pointer);
1025}
1026
1027
1028/*****************************************************************************
1029 * ACPI sleep support.
1030 *****************************************************************************/
1031
1032static int
1033is_available_state(struct acpi_softc *sc, int state)
1034{
1035	UINT8 type_a, type_b;
1036
1037	return ACPI_SUCCESS(AcpiGetSleepTypeData((UINT8)state,
1038				&type_a, &type_b));
1039}
1040
1041/*
1042 * acpi_enter_sleep_state:
1043 *
1044 *	enter to the specified sleep state.
1045 */
1046
1047ACPI_STATUS
1048acpi_enter_sleep_state(struct acpi_softc *sc, int state)
1049{
1050	int s;
1051	ACPI_STATUS ret = AE_OK;
1052
1053	if (state == acpi_sleepstate)
1054		return AE_OK;
1055
1056	aprint_normal("%s: entering state %d\n", sc->sc_dev.dv_xname, state);
1057
1058	switch (state) {
1059	case ACPI_STATE_S0:
1060		break;
1061	case ACPI_STATE_S1:
1062	case ACPI_STATE_S2:
1063	case ACPI_STATE_S3:
1064	case ACPI_STATE_S4:
1065		if (!is_available_state(sc, state)) {
1066			aprint_error("%s: cannot enter the sleep state (%d).\n",
1067			    sc->sc_dev.dv_xname, state);
1068			break;
1069		}
1070		ret = AcpiEnterSleepStatePrep(state);
1071		if (ACPI_FAILURE(ret)) {
1072			aprint_error("%s: failed preparing to sleep (%s)\n",
1073			    sc->sc_dev.dv_xname, AcpiFormatException(ret));
1074			break;
1075		}
1076		acpi_sleepstate = state;
1077		if (state == ACPI_STATE_S1) {
1078			/* just enter the state */
1079			acpi_md_OsDisableInterrupt();
1080			AcpiEnterSleepState((UINT8)state);
1081		} else {
1082			/* XXX: powerhooks(9) framework is too poor to
1083			 * support ACPI sleep state...
1084			 */
1085			dopowerhooks(PWR_SOFTSUSPEND);
1086			s = splhigh();
1087			dopowerhooks(PWR_SUSPEND);
1088			acpi_md_sleep(state);
1089			dopowerhooks(PWR_RESUME);
1090			splx(s);
1091			dopowerhooks(PWR_SOFTRESUME);
1092			if (state==ACPI_STATE_S4)
1093				AcpiEnable();
1094		}
1095		AcpiLeaveSleepState((UINT8)state);
1096		break;
1097	case ACPI_STATE_S5:
1098		ret = AcpiEnterSleepStatePrep(ACPI_STATE_S5);
1099		if (ACPI_FAILURE(ret)) {
1100			aprint_error("%s: failed preparing to sleep (%s)\n",
1101			       sc->sc_dev.dv_xname, AcpiFormatException(ret));
1102			break;
1103		}
1104		acpi_sleepstate = state;
1105		acpi_md_OsDisableInterrupt();
1106		AcpiEnterSleepState(ACPI_STATE_S5);
1107		aprint_error("%s: WARNING powerdown failed!\n",
1108		    sc->sc_dev.dv_xname);
1109		break;
1110	}
1111
1112	aprint_normal("%s: resuming\n", sc->sc_dev.dv_xname);
1113	acpi_sleepstate = ACPI_STATE_S0;
1114	return ret;
1115}
1116
1117#if defined(ACPI_ACTIVATE_DEV)
1118/* XXX This very incomplete */
1119ACPI_STATUS
1120acpi_allocate_resources(ACPI_HANDLE handle)
1121{
1122	ACPI_BUFFER bufp, bufc, bufn;
1123	ACPI_RESOURCE *resp, *resc, *resn;
1124	ACPI_RESOURCE_IRQ *irq;
1125	ACPI_RESOURCE_EXTENDED_IRQ *xirq;
1126	ACPI_STATUS rv;
1127	uint delta;
1128
1129	rv = acpi_get(handle, &bufp, AcpiGetPossibleResources);
1130	if (ACPI_FAILURE(rv))
1131		goto out;
1132	rv = acpi_get(handle, &bufc, AcpiGetCurrentResources);
1133	if (ACPI_FAILURE(rv)) {
1134		goto out1;
1135	}
1136
1137	bufn.Length = 1000;
1138	bufn.Pointer = resn = malloc(bufn.Length, M_ACPI, M_WAITOK);
1139	resp = bufp.Pointer;
1140	resc = bufc.Pointer;
1141	while (resc->Type != ACPI_RESOURCE_TYPE_END_TAG &&
1142	       resp->Type != ACPI_RESOURCE_TYPE_END_TAG) {
1143		while (resc->Type != resp->Type && resp->Type != ACPI_RESOURCE_TYPE_END_TAG)
1144			resp = ACPI_NEXT_RESOURCE(resp);
1145		if (resp->Type == ACPI_RESOURCE_TYPE_END_TAG)
1146			break;
1147		/* Found identical Id */
1148		resn->Type = resc->Type;
1149		switch (resc->Type) {
1150		case ACPI_RESOURCE_TYPE_IRQ:
1151			memcpy(&resn->Data, &resp->Data,
1152			       sizeof(ACPI_RESOURCE_IRQ));
1153			irq = (ACPI_RESOURCE_IRQ *)&resn->Data;
1154			irq->Interrupts[0] =
1155			    ((ACPI_RESOURCE_IRQ *)&resp->Data)->
1156			        Interrupts[irq->InterruptCount-1];
1157			irq->InterruptCount = 1;
1158			resn->Length = ACPI_RS_SIZE(ACPI_RESOURCE_IRQ);
1159			break;
1160		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1161			memcpy(&resn->Data, &resp->Data,
1162			       sizeof(ACPI_RESOURCE_EXTENDED_IRQ));
1163			xirq = (ACPI_RESOURCE_EXTENDED_IRQ *)&resn->Data;
1164#if 0
1165			/*
1166			 * XXX not duplicating the interrupt logic above
1167			 * because its not clear what it accomplishes.
1168			 */
1169			xirq->Interrupts[0] =
1170			    ((ACPI_RESOURCE_EXT_IRQ *)&resp->Data)->
1171			    Interrupts[irq->NumberOfInterrupts-1];
1172			xirq->NumberOfInterrupts = 1;
1173#endif
1174			resn->Length = ACPI_RS_SIZE(ACPI_RESOURCE_EXTENDED_IRQ);
1175			break;
1176		case ACPI_RESOURCE_TYPE_IO:
1177			memcpy(&resn->Data, &resp->Data,
1178			       sizeof(ACPI_RESOURCE_IO));
1179			resn->Length = resp->Length;
1180			break;
1181		default:
1182			printf("acpi_allocate_resources: res=%d\n", resc->Type);
1183			rv = AE_BAD_DATA;
1184			goto out2;
1185		}
1186		resc = ACPI_NEXT_RESOURCE(resc);
1187		resn = ACPI_NEXT_RESOURCE(resn);
1188		resp = ACPI_NEXT_RESOURCE(resp);
1189		delta = (UINT8 *)resn - (UINT8 *)bufn.Pointer;
1190		if (delta >=
1191		    bufn.Length-ACPI_RS_SIZE(ACPI_RESOURCE_DATA)) {
1192			bufn.Length *= 2;
1193			bufn.Pointer = realloc(bufn.Pointer, bufn.Length,
1194					       M_ACPI, M_WAITOK);
1195			resn = (ACPI_RESOURCE *)((UINT8 *)bufn.Pointer + delta);
1196		}
1197	}
1198	if (resc->Type != ACPI_RESOURCE_TYPE_END_TAG) {
1199		printf("acpi_allocate_resources: resc not exhausted\n");
1200		rv = AE_BAD_DATA;
1201		goto out3;
1202	}
1203
1204	resn->Type = ACPI_RESOURCE_TYPE_END_TAG;
1205	rv = AcpiSetCurrentResources(handle, &bufn);
1206	if (ACPI_FAILURE(rv)) {
1207		printf("acpi_allocate_resources: AcpiSetCurrentResources %s\n",
1208		       AcpiFormatException(rv));
1209	}
1210
1211out3:
1212	free(bufn.Pointer, M_ACPI);
1213out2:
1214	AcpiOsFree(bufc.Pointer);
1215out1:
1216	AcpiOsFree(bufp.Pointer);
1217out:
1218	return rv;
1219}
1220#endif /* ACPI_ACTIVATE_DEV */
1221
1222SYSCTL_SETUP(sysctl_acpi_setup, "sysctl hw.acpi subtree setup")
1223{
1224	const struct sysctlnode *node;
1225	const struct sysctlnode *ssnode;
1226
1227	if (sysctl_createv(clog, 0, NULL, NULL,
1228	    CTLFLAG_PERMANENT,
1229	    CTLTYPE_NODE, "hw", NULL,
1230	    NULL, 0, NULL, 0,
1231	    CTL_HW, CTL_EOL) != 0)
1232		return;
1233
1234	if (sysctl_createv(clog, 0, NULL, &node,
1235	    CTLFLAG_PERMANENT,
1236	    CTLTYPE_NODE, "acpi", NULL,
1237	    NULL, 0, NULL, 0,
1238	    CTL_HW, CTL_CREATE, CTL_EOL) != 0)
1239		return;
1240
1241	acpi_node = node->sysctl_num;
1242
1243	/* ACPI sleepstate sysctl */
1244	if (sysctl_createv(NULL, 0, NULL, &node,
1245	    CTLFLAG_PERMANENT,
1246	    CTLTYPE_NODE, "machdep", NULL,
1247	    NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL) != 0)
1248		return;
1249	if (sysctl_createv(NULL, 0, &node, &ssnode,
1250	    CTLFLAG_READWRITE, CTLTYPE_INT, "sleep_state",
1251	    NULL, sysctl_hw_acpi_sleepstate, 0, NULL, 0, CTL_CREATE,
1252	    CTL_EOL) != 0)
1253		return;
1254}
1255
1256static int
1257sysctl_hw_acpi_sleepstate(SYSCTLFN_ARGS)
1258{
1259	int error, t;
1260	struct sysctlnode node;
1261
1262	node = *rnode;
1263	t = acpi_sleepstate;
1264	node.sysctl_data = &t;
1265	error = sysctl_lookup(SYSCTLFN_CALL(&node));
1266	if (error || newp == NULL)
1267		return error;
1268
1269	if (acpi_softc == NULL)
1270		return ENOSYS;
1271
1272	acpi_enter_sleep_state(acpi_softc, t);
1273
1274	return 0;
1275}
1276