acpi.c revision 1.7
1/*	$NetBSD: acpi.c,v 1.7 2002/03/24 03:32:14 sommerfeld 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.7 2002/03/24 03:32:14 sommerfeld 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#ifdef ENABLE_DEBUGGER
57#define	ACPI_DBGR_INIT		0x01
58#define	ACPI_DBGR_TABLES	0x02
59#define	ACPI_DBGR_ENABLE	0x04
60#define	ACPI_DBGR_PROBE		0x08
61#define	ACPI_DBGR_RUNNING	0x10
62
63int	acpi_dbgr = 0x00;
64#endif
65
66int	acpi_match(struct device *, struct cfdata *, void *);
67void	acpi_attach(struct device *, struct device *, void *);
68
69int	acpi_print(void *aux, const char *);
70
71extern struct cfdriver acpi_cd;
72
73struct cfattach acpi_ca = {
74	sizeof(struct acpi_softc), acpi_match, acpi_attach,
75};
76
77/*
78 * This is a flag we set when the ACPI subsystem is active.  Machine
79 * dependent code may wish to skip other steps (such as attaching
80 * subsystems that ACPI supercedes) when ACPI is active.
81 */
82int	acpi_active;
83
84/*
85 * Pointer to the ACPI subsystem's state.  There can be only
86 * one ACPI instance.
87 */
88struct acpi_softc *acpi_softc;
89
90void		acpi_shutdown(void *);
91ACPI_STATUS	acpi_disable(struct acpi_softc *sc);
92void		acpi_build_tree(struct acpi_softc *);
93ACPI_STATUS	acpi_make_devnode(ACPI_HANDLE, UINT32, void *, void **);
94
95void		acpi_enable_fixed_events(struct acpi_softc *);
96
97/*
98 * acpi_probe:
99 *
100 *	Probe for ACPI support.  This is called by the
101 *	machine-dependent ACPI front-end.  All of the
102 *	actual work is done by ACPICA.
103 *
104 *	NOTE: This is not an autoconfiguration interface function.
105 */
106int
107acpi_probe(void)
108{
109	static int beenhere;
110	ACPI_STATUS rv;
111
112	if (beenhere != 0)
113		panic("acpi_probe: ACPI has already been probed");
114	beenhere = 1;
115
116	/*
117	 * Start up ACPICA.
118	 */
119#ifdef ENABLE_DEBUGGER
120	if (acpi_dbgr & ACPI_DBGR_INIT)
121		acpi_osd_debugger();
122#endif
123
124	rv = AcpiInitializeSubsystem();
125	if (rv != AE_OK) {
126		printf("ACPI: unable to initialize ACPICA: %d\n", rv);
127		return (0);
128	}
129
130#ifdef ENABLE_DEBUGGER
131	if (acpi_dbgr & ACPI_DBGR_TABLES)
132		acpi_osd_debugger();
133#endif
134
135	rv = AcpiLoadTables();
136	if (rv != AE_OK) {
137		printf("ACPI: unable to load tables: %d\n", rv);
138		return (0);
139	}
140
141	/*
142	 * Looks like we have ACPI!
143	 */
144
145	return (1);
146}
147
148/*
149 * acpi_match:
150 *
151 *	Autoconfiguration `match' routine.
152 */
153int
154acpi_match(struct device *parent, struct cfdata *match, void *aux)
155{
156	struct acpibus_attach_args *aa = aux;
157
158	if (strcmp(aa->aa_busname, acpi_cd.cd_name) != 0)
159		return (0);
160
161	/*
162	 * XXX Check other locators?  Hard to know -- machine
163	 * dependent code has already checked for the presence
164	 * of ACPI by calling acpi_probe(), so I suppose we
165	 * don't really have to do anything else.
166	 */
167	return (1);
168}
169
170/*
171 * acpi_attach:
172 *
173 *	Autoconfiguration `attach' routine.  Finish initializing
174 *	ACPICA (some initialization was done in acpi_probe(),
175 *	which was required to check for the presence of ACPI),
176 *	and enable the ACPI subsystem.
177 */
178void
179acpi_attach(struct device *parent, struct device *self, void *aux)
180{
181	struct acpi_softc *sc = (void *) self;
182	struct acpibus_attach_args *aa = aux;
183	ACPI_STATUS rv;
184
185	printf("\n");
186
187	if (acpi_softc != NULL)
188		panic("acpi_attach: ACPI has already been attached");
189
190	sc->sc_iot = aa->aa_iot;
191	sc->sc_memt = aa->aa_memt;
192	sc->sc_pc = aa->aa_pc;
193	sc->sc_pciflags = aa->aa_pciflags;
194
195	acpi_softc = sc;
196
197	/*
198	 * Install the default address space handlers.
199	 */
200
201	rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
202	    ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL);
203	if (rv != AE_OK) {
204		printf("%s: unable to install SYSTEM MEMORY handler: %d\n",
205		    sc->sc_dev.dv_xname, rv);
206		return;
207	}
208
209	rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
210	    ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL);
211	if (rv != AE_OK) {
212		printf("%s: unable to install SYSTEM IO handler: %d\n",
213		    sc->sc_dev.dv_xname, rv);
214		return;
215	}
216
217	rv = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
218	    ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
219	if (rv != AE_OK) {
220		printf("%s: unable to install PCI CONFIG handler: %d\n",
221		    sc->sc_dev.dv_xname, rv);
222		return;
223	}
224
225	/*
226	 * Bring ACPI on-line.
227	 *
228	 * Note that we request that _STA (device init) and _INI (object init)
229	 * methods not be run.
230	 *
231	 * XXX We need to arrange for the object init pass after we have
232	 * XXX attached all of our children.
233	 */
234#ifdef ENABLE_DEBUGGER
235	if (acpi_dbgr & ACPI_DBGR_ENABLE)
236		acpi_osd_debugger();
237#endif
238	rv = AcpiEnableSubsystem(ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT);
239	if (rv != AE_OK) {
240		printf("%s: unable to enable ACPI: %d\n",
241		    sc->sc_dev.dv_xname, rv);
242		return;
243	}
244	acpi_active = 1;
245
246	/*
247	 * Set up the default sleep state to enter when various
248	 * switches are activated.
249	 */
250	sc->sc_switch_sleep[ACPI_SWITCH_POWERBUTTON] = ACPI_STATE_S5;
251	sc->sc_switch_sleep[ACPI_SWITCH_SLEEPBUTTON] = ACPI_STATE_S1;
252	sc->sc_switch_sleep[ACPI_SWITCH_LID]	     = ACPI_STATE_S1;
253
254	/* Our current state is "awake". */
255	sc->sc_sleepstate = ACPI_STATE_S0;
256
257	/*
258	 * Check for fixed-hardware features.
259	 */
260	acpi_enable_fixed_events(sc);
261
262	/*
263	 * Scan the namespace and build our device tree.
264	 */
265#ifdef ENABLE_DEBUGGER
266	if (acpi_dbgr & ACPI_DBGR_PROBE)
267		acpi_osd_debugger();
268#endif
269	acpi_build_tree(sc);
270
271	/*
272	 * Register a shutdown hook that disables certain ACPI
273	 * events that might happen and confuse us while we're
274	 * trying to shut down.
275	 */
276	sc->sc_sdhook = shutdownhook_establish(acpi_shutdown, sc);
277	if (sc->sc_sdhook == NULL)
278		printf("%s: WARNING: unable to register shutdown hook\n",
279		    sc->sc_dev.dv_xname);
280
281#ifdef ENABLE_DEBUGGER
282	if (acpi_dbgr & ACPI_DBGR_RUNNING)
283		acpi_osd_debugger();
284#endif
285}
286
287/*
288 * acpi_shutdown:
289 *
290 *	Shutdown hook for ACPI -- disable some events that
291 *	might confuse us.
292 */
293void
294acpi_shutdown(void *arg)
295{
296	struct acpi_softc *sc = arg;
297
298	if (acpi_disable(sc) != AE_OK)
299		printf("%s: WARNING: unable to disable ACPI\n",
300		    sc->sc_dev.dv_xname);
301}
302
303/*
304 * acpi_disable:
305 *
306 *	Disable ACPI.
307 */
308ACPI_STATUS
309acpi_disable(struct acpi_softc *sc)
310{
311	ACPI_STATUS rv = AE_OK;
312
313	if (acpi_active) {
314		rv = AcpiDisable();
315		if (rv == AE_OK)
316			acpi_active = 0;
317	}
318	return (rv);
319}
320
321struct acpi_make_devnode_state {
322	struct acpi_softc *softc;
323	struct acpi_scope *scope;
324};
325
326/*
327 * acpi_build_tree:
328 *
329 *	Scan relevant portions of the ACPI namespace and attach
330 *	child devices.
331 */
332void
333acpi_build_tree(struct acpi_softc *sc)
334{
335	static const char *scopes[] = {
336		"\\_PR_",	/* ACPI 1.0 processor namespace */
337		"\\_SB_",	/* system bus namespace */
338		"\\_SI_",	/* system idicator namespace */
339		"\\_TZ_",	/* ACPI 1.0 thermal zone namespace */
340		NULL,
341	};
342	struct acpi_attach_args aa;
343	struct acpi_make_devnode_state state;
344	struct acpi_scope *as;
345	struct acpi_devnode *ad;
346	ACPI_HANDLE parent;
347	int i;
348
349	TAILQ_INIT(&sc->sc_scopes);
350
351	state.softc = sc;
352
353	/*
354	 * Scan the namespace and build our tree.
355	 */
356	for (i = 0; scopes[i] != NULL; i++) {
357		as = malloc(sizeof(*as), M_DEVBUF, M_WAITOK);
358		as->as_name = scopes[i];
359		TAILQ_INIT(&as->as_devnodes);
360
361		TAILQ_INSERT_TAIL(&sc->sc_scopes, as, as_list);
362
363		state.scope = as;
364
365		if (AcpiGetHandle(ACPI_ROOT_OBJECT, (char *) scopes[i],
366		    &parent) == AE_OK) {
367			AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100,
368			    acpi_make_devnode, &state, NULL);
369		}
370
371		/* Now, for this namespace, try and attach the devices. */
372		TAILQ_FOREACH(ad, &as->as_devnodes, ad_list) {
373			aa.aa_node = ad;
374			aa.aa_iot = sc->sc_iot;
375			aa.aa_memt = sc->sc_memt;
376			aa.aa_pc = sc->sc_pc;
377			aa.aa_pciflags = sc->sc_pciflags;
378
379			/*
380			 * XXX We only attach devices which are:
381			 *
382			 *	- present
383			 *	- enabled
384			 *	- to be shown
385			 *	- functioning properly
386			 *
387			 * However, if enabled, it's decoding resources,
388			 * so we should claim them, if possible.  Requires
389			 * changes to bus_space(9).
390			 */
391			if ((ad->ad_devinfo.CurrentStatus &
392			     (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|
393			      ACPI_STA_DEV_SHOW|ACPI_STA_DEV_OK)) !=
394			    (ACPI_STA_DEV_PRESENT|ACPI_STA_DEV_ENABLED|
395			     ACPI_STA_DEV_SHOW|ACPI_STA_DEV_OK))
396				continue;
397
398			/*
399			 * XXX Same problem as above...
400			 */
401			if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0)
402				continue;
403
404			ad->ad_device = config_found(&sc->sc_dev,
405			    &aa, acpi_print);
406		}
407	}
408}
409
410/*
411 * acpi_make_devnode:
412 *
413 *	Make an ACPI devnode.
414 */
415ACPI_STATUS
416acpi_make_devnode(ACPI_HANDLE handle, UINT32 level, void *context,
417    void **status)
418{
419	struct acpi_make_devnode_state *state = context;
420#ifdef ACPI_DEBUG
421	struct acpi_softc *sc = state->softc;
422#endif
423	struct acpi_scope *as = state->scope;
424	struct acpi_devnode *ad;
425	ACPI_OBJECT_TYPE type;
426	ACPI_STATUS rv;
427
428	if (AcpiGetType(handle, &type) == AE_OK) {
429		switch (type) {
430		case ACPI_TYPE_DEVICE:
431		case ACPI_TYPE_PROCESSOR:
432		case ACPI_TYPE_THERMAL:
433		case ACPI_TYPE_POWER:
434			ad = malloc(sizeof(*ad), M_DEVBUF, M_NOWAIT|M_ZERO);
435			if (ad == NULL)
436				return (AE_NO_MEMORY);
437
438			ad->ad_handle = handle;
439			ad->ad_level = level;
440			ad->ad_scope = as;
441			ad->ad_type = type;
442
443			TAILQ_INSERT_TAIL(&as->as_devnodes, ad, ad_list);
444
445			rv = AcpiGetObjectInfo(handle, &ad->ad_devinfo);
446			if (rv != AE_OK)
447				goto out;
448
449			if ((ad->ad_devinfo.Valid & ACPI_VALID_HID) == 0)
450				goto out;
451
452#ifdef ACPI_DEBUG
453			printf("%s: HID %s found in scope %s level %d\n",
454			    sc->sc_dev.dv_xname, ad->ad_devinfo.HardwareId,
455			    as->as_name, ad->ad_level);
456			if (ad->ad_devinfo.Valid & ACPI_VALID_UID)
457				printf("       UID %s\n",
458				    ad->ad_devinfo.UniqueId);
459			if (ad->ad_devinfo.Valid & ACPI_VALID_ADR)
460				printf("       ADR 0x%016qx\n",
461				    ad->ad_devinfo.Address);
462			if (ad->ad_devinfo.Valid & ACPI_VALID_STA)
463				printf("       STA 0x%08x\n",
464				    ad->ad_devinfo.CurrentStatus);
465#endif
466		}
467	}
468 out:
469	return (AE_OK);
470}
471
472/*
473 * acpi_print:
474 *
475 *	Autoconfiguration print routine.
476 */
477int
478acpi_print(void *aux, const char *pnp)
479{
480	struct acpi_attach_args *aa = aux;
481#if 0
482	char *str;
483#endif
484
485	if (pnp) {
486		printf("%s ", aa->aa_node->ad_devinfo.HardwareId);
487#if 0 /* Not until we fix acpi_eval_string */
488		if (acpi_eval_string(aa->aa_node->ad_handle,
489		    "_STR", &str) == AE_OK) {
490			printf("[%s] ", str);
491			AcpiOsFree(str);
492		}
493#endif
494		printf("at %s", pnp);
495	}
496
497	return (UNCONF);
498}
499
500/*****************************************************************************
501 * ACPI fixed-hardware feature handlers
502 *****************************************************************************/
503
504UINT32		acpi_fixed_power_button_handler(void *);
505UINT32		acpi_fixed_sleep_button_handler(void *);
506
507/*
508 * acpi_enable_fixed_events:
509 *
510 *	Enable any fixed-hardware feature handlers.
511 */
512void
513acpi_enable_fixed_events(struct acpi_softc *sc)
514{
515	static int beenhere;
516	ACPI_STATUS rv;
517
518	/*
519	 * Check for fixed-hardware buttons.
520	 */
521
522	if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) {
523		if (beenhere == 0)
524			printf("%s: fixed-feature power button present\n",
525			    sc->sc_dev.dv_xname);
526		rv = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
527		    acpi_fixed_power_button_handler, sc);
528		if (rv != AE_OK)
529			printf("%s: unable to install handler for fixed "
530			    "power button: %d\n", sc->sc_dev.dv_xname, rv);
531	}
532
533	if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) {
534		if (beenhere == 0)
535			printf("%s: fixed-feature sleep button present\n",
536			    sc->sc_dev.dv_xname);
537		rv = AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
538		    acpi_fixed_sleep_button_handler, sc);
539		if (rv != AE_OK)
540			printf("%s: unable to install handler for fixed "
541			    "power button: %d\n", sc->sc_dev.dv_xname, rv);
542	}
543
544	beenhere = 1;
545}
546
547/*
548 * acpi_fixed_power_button_handler:
549 *
550 *	Fixed event handler for the power button.
551 */
552UINT32
553acpi_fixed_power_button_handler(void *context)
554{
555	struct acpi_softc *sc = context;
556
557	/* XXX XXX XXX */
558
559	printf("%s: fixed power button pressed\n", sc->sc_dev.dv_xname);
560
561	return (INTERRUPT_HANDLED);
562}
563
564/*
565 * acpi_fixed_sleep_button_handler:
566 *
567 *	Fixed event handler for the sleep button.
568 */
569UINT32
570acpi_fixed_sleep_button_handler(void *context)
571{
572	struct acpi_softc *sc = context;
573
574	/* XXX XXX XXX */
575
576	printf("%s: fixed sleep button pressed\n", sc->sc_dev.dv_xname);
577
578	return (INTERRUPT_HANDLED);
579}
580
581/*****************************************************************************
582 * ACPI utility routines.
583 *****************************************************************************/
584
585/*
586 * acpi_eval_integer:
587 *
588 *	Evaluate an integer object.
589 */
590ACPI_STATUS
591acpi_eval_integer(ACPI_HANDLE handle, char *path, int *valp)
592{
593	ACPI_STATUS rv;
594	ACPI_BUFFER buf;
595	ACPI_OBJECT param;
596
597	if (handle == NULL)
598		handle = ACPI_ROOT_OBJECT;
599
600	buf.Pointer = &param;
601	buf.Length = sizeof(param);
602
603	rv = AcpiEvaluateObject(handle, path, NULL, &buf);
604	if (rv == AE_OK) {
605		if (param.Type == ACPI_TYPE_INTEGER)
606			*valp = param.Integer.Value;
607		else
608			rv = AE_TYPE;
609	}
610
611	return (rv);
612}
613
614#if 0
615/*
616 * acpi_eval_string:
617 *
618 *	Evaluate a (Unicode) string object.
619 * XXX current API may leak memory, so don't use this.
620 */
621ACPI_STATUS
622acpi_eval_string(ACPI_HANDLE handle, char *path, char **stringp)
623{
624	ACPI_STATUS rv;
625	ACPI_BUFFER buf;
626	ACPI_OBJECT *param;
627
628	if (handle == NULL)
629		handle = ACPI_ROOT_OBJECT;
630
631	buf.Pointer = NULL;
632	buf.Length = 0;
633
634	rv = AcpiEvaluateObject(handle, path, NULL, &buf);
635	if (rv != AE_BUFFER_OVERFLOW)
636		return (rv);
637
638	buf.Pointer = AcpiOsAllocate(buf.Length);
639	if (buf.Pointer == NULL)
640		return (AE_NO_MEMORY);
641
642	rv = AcpiEvaluateObject(handle, path, NULL, &buf);
643	param = (ACPI_OBJECT *)buf.Pointer;
644	if (rv == AE_OK) {
645		if (param->Type == ACPI_TYPE_STRING) {
646			/* XXX may leak buf.Pointer!! */
647			*stringp = param->String.Pointer;
648			return (AE_OK);
649		}
650		rv = AE_TYPE;
651	}
652
653	AcpiOsFree(buf.Pointer);
654	return (rv);
655}
656#endif
657
658
659/*
660 * acpi_eval_struct:
661 *
662 *	Evaluate a more complex structure.  Caller must free buf.Pointer.
663 */
664ACPI_STATUS
665acpi_eval_struct(ACPI_HANDLE handle, char *path, ACPI_BUFFER *bufp)
666{
667	ACPI_STATUS rv;
668
669	if (handle == NULL)
670		handle = ACPI_ROOT_OBJECT;
671
672	bufp->Pointer = NULL;
673	bufp->Length = 0;
674
675	rv = AcpiEvaluateObject(handle, path, NULL, bufp);
676	if (rv != AE_BUFFER_OVERFLOW)
677		return (rv);
678
679	bufp->Pointer = AcpiOsAllocate(bufp->Length);
680	if (bufp->Pointer == NULL)
681		return (AE_NO_MEMORY);
682
683	rv = AcpiEvaluateObject(handle, path, NULL, bufp);
684
685	return (rv);
686}
687
688/*
689 * acpi_get:
690 *
691 *	Fetch data info the specified (empty) ACPI buffer.
692 */
693ACPI_STATUS
694acpi_get(ACPI_HANDLE handle, ACPI_BUFFER *buf,
695    ACPI_STATUS (*getit)(ACPI_HANDLE, ACPI_BUFFER *))
696{
697	ACPI_STATUS rv;
698
699	buf->Pointer = NULL;
700	buf->Length = 0;
701
702	rv = (*getit)(handle, buf);
703	if (rv != AE_BUFFER_OVERFLOW)
704		return (rv);
705
706	buf->Pointer = AcpiOsCallocate(buf->Length);
707	if (buf->Pointer == NULL)
708		return (AE_NO_MEMORY);
709
710	return ((*getit)(handle, buf));
711}
712