xref: /openbsd/sys/dev/acpi/acpisony.c (revision a6445c1d)
1 /* $OpenBSD: acpisony.c,v 1.6 2014/09/14 14:17:24 jsg Exp $ */
2 /*
3  * Copyright (c) 2010 Paul Irofti <pirofti@openbsd.org>
4  *
5  * Permission to use, copy, modify, and/or 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/systm.h>
20 
21 #include <dev/acpi/acpireg.h>
22 #include <dev/acpi/acpivar.h>
23 #include <dev/acpi/acpidev.h>
24 #include <dev/acpi/amltypes.h>
25 #include <dev/acpi/dsdt.h>
26 
27 #include <machine/apmvar.h>
28 
29 int	acpisony_match(struct device *, void *, void *);
30 void	acpisony_attach(struct device *, struct device *, void *);
31 int	acpisony_activate(struct device *, int);
32 int	acpisony_notify(struct aml_node *, int, void *);
33 
34 #ifdef ACPISONY_DEBUG
35 #define DPRINTF(x)	printf x
36 #else
37 #define DPRINTF(x)
38 #endif
39 
40 /* Notifications */
41 #define	SONY_NOTIFY_FN_KEY			0x90
42 
43 #define	SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED	0x85
44 #define	SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED	0x05
45 #define	SONY_NOTIFY_BRIGHTNESS_UP_PRESSED	0x86
46 #define	SONY_NOTIFY_BRIGHTNESS_UP_RELEASED	0x06
47 
48 #define	SONY_NOTIFY_DISPLAY_SWITCH_PRESSED	0x87
49 #define	SONY_NOTIFY_DISPLAY_SWITCH_RELEASED	0x07
50 
51 #define	SONY_NOTIFY_ZOOM_OUT_PRESSED		0x89
52 #define	SONY_NOTIFY_ZOOM_OUT_RELEASED		0x09
53 
54 #define	SONY_NOTIFY_ZOOM_IN_PRESSED		0x8a
55 #define	SONY_NOTIFY_ZOOM_IN_RELEASED		0x0a
56 
57 #define	SONY_NOTIFY_SUSPEND_PRESSED		0x8c
58 #define	SONY_NOTIFY_SUSPEND_RELEASED		0x0c
59 
60 struct acpisony_softc {
61 	struct device		sc_dev;
62 
63 	bus_space_tag_t		sc_iot;
64 	bus_space_handle_t	sc_ioh;
65 
66 	struct acpi_softc	*sc_acpi;
67 	struct aml_node		*sc_devnode;
68 };
69 
70 struct cfattach acpisony_ca = {
71 	sizeof(struct acpisony_softc), acpisony_match, acpisony_attach,
72 	NULL, acpisony_activate
73 };
74 
75 struct cfdriver acpisony_cd = {
76 	NULL, "acpisony", DV_DULL
77 };
78 
79 void acpisony_notify_setup(struct acpisony_softc *);
80 int acpisony_set_hotkey(struct acpisony_softc *, int, int);
81 int acpisony_find_offset(struct acpisony_softc *, int);
82 
83 void acpisony_brightness_down(struct acpisony_softc *);
84 int acpisony_get_brightness(struct acpisony_softc *);
85 void acpisony_set_brightness(struct acpisony_softc *, int);
86 
87 int
88 acpisony_match(struct device *parent, void *match, void *aux)
89 {
90 	struct acpi_attach_args *aa = aux;
91 	struct cfdata		*cf = match;
92 
93 	if (aa->aaa_name == NULL ||
94 	    strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
95 	    aa->aaa_table != NULL)
96 		return (0);
97 
98 	return (1);
99 }
100 
101 void
102 acpisony_attach(struct device *parent, struct device *self, void *aux)
103 {
104 	struct acpisony_softc	*sc = (struct acpisony_softc *)self;
105 	struct acpi_attach_args *aa = aux;
106 
107 	sc->sc_acpi = (struct acpi_softc *)parent;
108 	sc->sc_devnode = aa->aaa_node;
109 
110 	printf(": %s\n", sc->sc_devnode->name);
111 
112 	/* Setup the notification masks */
113 	acpisony_notify_setup(sc);
114 
115 	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
116 	    acpisony_notify, sc, ACPIDEV_NOPOLL);
117 }
118 
119 int
120 acpisony_activate(struct device *self, int act)
121 {
122 	struct acpisony_softc *sc = (struct acpisony_softc *)self;
123 
124 	switch (act) {
125 	case DVACT_WAKEUP:
126 		acpisony_notify_setup(sc);
127 		break;
128 	}
129 	return 0;
130 }
131 
132 int
133 acpisony_notify(struct aml_node *node, int notify, void *arg)
134 {
135 	struct acpisony_softc *sc = arg;
136 	int val, key = 0;
137 
138 	if (notify == SONY_NOTIFY_FN_KEY) {
139 		notify -= 0x90;
140 		DPRINTF(("notify = %X", notify));
141 
142 		if (notify == acpisony_find_offset(sc, 0x100)) {
143 			DPRINTF(("key = 0x100\n"));
144 			key = 0x100;
145 		}
146 		if (notify == acpisony_find_offset(sc, 0x127)) {
147 			DPRINTF(("key = 0x127\n"));
148 			key = 0x127;
149 		}
150 
151 		if (key) {
152 			val = acpisony_set_hotkey(sc, key, 0x200);
153 			if (val < 0) {
154 				printf("returned val = %X", val);
155 				return 1;
156 			}
157 			notify = val & 0xff;
158 
159 			DPRINTF(("Treat %X events, notify %X\n", key, notify));
160 		} else
161 			DPRINTF(("rfkill update, notify %X\n", notify));
162 	}
163 
164 	switch (notify) {
165 	case SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED:
166 		DPRINTF(("br-down-pressed\n"));
167 		acpisony_brightness_down(sc);
168 		break;
169 	case SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED:
170 		DPRINTF(("br-down-released\n"));
171 		break;
172 	case SONY_NOTIFY_BRIGHTNESS_UP_PRESSED:
173 		DPRINTF(("br-up-pressed\n"));
174 		break;
175 	case SONY_NOTIFY_BRIGHTNESS_UP_RELEASED:
176 		DPRINTF(("br-up-released\n"));
177 		break;
178 	case SONY_NOTIFY_DISPLAY_SWITCH_PRESSED:
179 		DPRINTF(("display-pressed\n"));
180 		break;
181 	case SONY_NOTIFY_DISPLAY_SWITCH_RELEASED:
182 		DPRINTF(("display-released\n"));
183 		break;
184 	case SONY_NOTIFY_ZOOM_IN_PRESSED:
185 		DPRINTF(("zoom-in-pressed\n"));
186 		break;
187 	case SONY_NOTIFY_ZOOM_IN_RELEASED:
188 		DPRINTF(("zoom-in-released\n"));
189 		break;
190 	case SONY_NOTIFY_ZOOM_OUT_PRESSED:
191 		DPRINTF(("zoom-out-pressed\n"));
192 		break;
193 	case SONY_NOTIFY_ZOOM_OUT_RELEASED:
194 		DPRINTF(("zoom-out-released\n"));
195 		break;
196 	case SONY_NOTIFY_SUSPEND_PRESSED:
197 		DPRINTF(("suspend-pressed\n"));
198 #ifndef SMALL_KERNEL
199 		if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ))
200 			acpi_addtask(sc->sc_acpi, acpi_sleep_task,
201 			    sc->sc_acpi, ACPI_STATE_S3);
202 #endif
203 		break;
204 	case SONY_NOTIFY_SUSPEND_RELEASED:
205 		DPRINTF(("suspend-released\n"));
206 		break;
207 	default:
208 		printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
209 		break;
210 	}
211 
212 	return 0;
213 }
214 
215 void
216 acpisony_notify_setup(struct acpisony_softc *sc)
217 {
218 	struct aml_value arg;
219 
220 	bzero(&arg, sizeof(arg));
221 	arg.type = AML_OBJTYPE_INTEGER;
222 
223 	arg.v_integer = 1;
224 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "ECON", 1, &arg, NULL);
225 
226 	/* Enable all events */
227 	arg.v_integer = 0xffff;
228 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
229 
230 	/* Enable hotkeys */
231 	arg.v_integer = 0x04;
232 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
233 	arg.v_integer = 0x02;
234 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
235 	arg.v_integer = 0x10;
236 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
237 	arg.v_integer = 0x00;
238 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
239 	arg.v_integer = 0x02;
240 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN03", 1, &arg, NULL);
241 	arg.v_integer = 0x101;
242 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
243 }
244 
245 int
246 acpisony_find_offset(struct acpisony_softc *sc, int key)
247 {
248 	struct aml_value arg, res;
249 	int val;
250 
251 	bzero(&arg, sizeof(arg));
252 	arg.type = AML_OBJTYPE_INTEGER;
253 
254 	for (arg.v_integer = 0x20; arg.v_integer < 0x30; arg.v_integer++) {
255 		aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN00", 1, &arg, &res);
256 		val = aml_val2int(&res);
257 		aml_freevalue(&res);
258 		if (val == key) {
259 			DPRINTF(("Matched key %X\n", val));
260 			return arg.v_integer - 0x20;
261 		}
262 	}
263 
264 	return -1;
265 }
266 
267 int
268 acpisony_set_hotkey(struct acpisony_softc *sc, int key, int val)
269 {
270 	int off, rc = -1;
271 	struct aml_value res, arg;
272 
273 	bzero(&arg, sizeof(arg));
274 	arg.type = AML_OBJTYPE_INTEGER;
275 
276 	off = acpisony_find_offset(sc, key);
277 	DPRINTF(("off = %X\n", off));
278 	if (off < 0)
279 		return rc;
280 
281 	arg.v_integer = off | val;
282 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, &res);
283 	rc = aml_val2int(&res);
284 	aml_freevalue(&res);
285 
286 	return rc;
287 }
288 
289 void
290 acpisony_brightness_down(struct acpisony_softc *sc)
291 {
292 	int val;
293 
294 	val = acpisony_get_brightness(sc);
295 	DPRINTF(("current value = %X", val));
296 	if (val > 0)
297 		val--;
298 	else
299 		val = 0;
300 	DPRINTF(("next value = %X", val));
301 	acpisony_set_brightness(sc, val);
302 }
303 
304 int
305 acpisony_get_brightness(struct acpisony_softc *sc)
306 {
307 	struct aml_value res;
308 	int val;
309 
310 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "GBRT", 0, NULL, &res);
311 	val = aml_val2int(&res);
312 	aml_freevalue(&res);
313 
314 	return val;
315 }
316 
317 void
318 acpisony_set_brightness(struct acpisony_softc *sc, int level)
319 {
320 	struct aml_value arg;
321 
322 	bzero(&arg, sizeof(arg));
323 	arg.type = AML_OBJTYPE_INTEGER;
324 	arg.v_integer = level;
325 	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBRT", 1, &arg, NULL);
326 	aml_freevalue(&arg);
327 }
328