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