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