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