xref: /openbsd/sys/dev/acpi/acpibtn.c (revision 404b540a)
1 /* $OpenBSD: acpibtn.c,v 1.21 2009/02/19 21:02:05 marco Exp $ */
2 /*
3  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/proc.h>
20 #include <sys/signalvar.h>
21 #include <sys/systm.h>
22 #include <sys/device.h>
23 #include <sys/malloc.h>
24 
25 #include <machine/bus.h>
26 
27 #include <dev/acpi/acpireg.h>
28 #include <dev/acpi/acpivar.h>
29 #include <dev/acpi/acpidev.h>
30 #include <dev/acpi/amltypes.h>
31 #include <dev/acpi/dsdt.h>
32 
33 #include <sys/sensors.h>
34 
35 int	acpibtn_match(struct device *, void *, void *);
36 void	acpibtn_attach(struct device *, struct device *, void *);
37 int	acpibtn_notify(struct aml_node *, int, void *);
38 
39 struct acpibtn_softc {
40 	struct device		sc_dev;
41 
42 	bus_space_tag_t		sc_iot;
43 	bus_space_handle_t	sc_ioh;
44 
45 	struct acpi_softc	*sc_acpi;
46 	struct aml_node		*sc_devnode;
47 
48 	int			sc_btn_type;
49 #define	ACPIBTN_UNKNOWN	-1
50 #define ACPIBTN_LID	0
51 #define ACPIBTN_POWER	1
52 #define ACPIBTN_SLEEP	2
53 };
54 
55 int	acpibtn_getsta(struct acpibtn_softc *);
56 
57 struct cfattach acpibtn_ca = {
58 	sizeof(struct acpibtn_softc), acpibtn_match, acpibtn_attach
59 };
60 
61 struct cfdriver acpibtn_cd = {
62 	NULL, "acpibtn", DV_DULL
63 };
64 
65 const char *acpibtn_hids[] = { ACPI_DEV_LD, ACPI_DEV_PBD, ACPI_DEV_SBD, 0 };
66 
67 int
68 acpibtn_match(struct device *parent, void *match, void *aux)
69 {
70 	struct acpi_attach_args	*aa = aux;
71 	struct cfdata		*cf = match;
72 
73 	/* sanity */
74 	return (acpi_matchhids(aa, acpibtn_hids, cf->cf_driver->cd_name));
75 }
76 
77 void
78 acpibtn_attach(struct device *parent, struct device *self, void *aux)
79 {
80 	struct acpibtn_softc	*sc = (struct acpibtn_softc *)self;
81 	struct acpi_attach_args *aa = aux;
82 
83 	sc->sc_acpi = (struct acpi_softc *)parent;
84 	sc->sc_devnode = aa->aaa_node;
85 
86 	if (!strcmp(aa->aaa_dev, ACPI_DEV_LD))
87 		sc->sc_btn_type = ACPIBTN_LID;
88 	else if (!strcmp(aa->aaa_dev, ACPI_DEV_PBD))
89 		sc->sc_btn_type = ACPIBTN_POWER;
90 	else if (!strcmp(aa->aaa_dev, ACPI_DEV_SBD))
91 		sc->sc_btn_type = ACPIBTN_SLEEP;
92 	else
93 		sc->sc_btn_type = ACPIBTN_UNKNOWN;
94 
95 	acpibtn_getsta(sc);
96 
97 	printf(": %s\n", sc->sc_devnode->name);
98 
99 	aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpibtn_notify,
100 	    sc, ACPIDEV_NOPOLL);
101 }
102 
103 int
104 acpibtn_getsta(struct acpibtn_softc *sc)
105 {
106 	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, NULL) != 0) {
107 		dnprintf(20, "%s: no _STA\n", DEVNAME(sc));
108 		/* XXX not all buttons have _STA so FALLTROUGH */
109 	}
110 
111 	return (0);
112 }
113 
114 int
115 acpibtn_notify(struct aml_node *node, int notify_type, void *arg)
116 {
117 	struct acpibtn_softc	*sc = arg;
118 
119 	dnprintf(10, "acpibtn_notify: %.2x %s\n", notify_type,
120 	    sc->sc_devnode->name);
121 
122 	switch (sc->sc_btn_type) {
123 	case ACPIBTN_LID:
124 	case ACPIBTN_SLEEP:
125 #ifdef ACPI_SLEEP_ENABLED
126 		acpi_sleep_state(sc->sc_acpi, ACPI_STATE_S3);
127 #endif /* ACPI_SLEEP_ENABLED */
128 		break;
129 	case ACPIBTN_POWER:
130 		if (notify_type == 0x80)
131 			psignal(initproc, SIGUSR2);
132 		break;
133 	default:
134 		printf("%s: spurious acpi button interrupt %i\n", DEVNAME(sc),
135 		    sc->sc_btn_type);
136 		break;
137 	}
138 
139 	return (0);
140 }
141