Line data Source code
1 : /* $OpenBSD: acpisony.c,v 1.7 2017/02/28 10:39:07 natano 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 0 : acpisony_match(struct device *parent, void *match, void *aux)
89 : {
90 0 : struct acpi_attach_args *aa = aux;
91 0 : struct cfdata *cf = match;
92 :
93 0 : if (aa->aaa_name == NULL ||
94 0 : strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
95 0 : aa->aaa_table != NULL)
96 0 : return (0);
97 :
98 0 : return (1);
99 0 : }
100 :
101 : void
102 0 : acpisony_attach(struct device *parent, struct device *self, void *aux)
103 : {
104 0 : struct acpisony_softc *sc = (struct acpisony_softc *)self;
105 0 : struct acpi_attach_args *aa = aux;
106 :
107 0 : sc->sc_acpi = (struct acpi_softc *)parent;
108 0 : sc->sc_devnode = aa->aaa_node;
109 :
110 0 : printf(": %s\n", sc->sc_devnode->name);
111 :
112 : /* Setup the notification masks */
113 0 : acpisony_notify_setup(sc);
114 :
115 0 : aml_register_notify(sc->sc_devnode, aa->aaa_dev,
116 0 : acpisony_notify, sc, ACPIDEV_NOPOLL);
117 0 : }
118 :
119 : int
120 0 : acpisony_activate(struct device *self, int act)
121 : {
122 0 : struct acpisony_softc *sc = (struct acpisony_softc *)self;
123 :
124 0 : switch (act) {
125 : case DVACT_WAKEUP:
126 0 : acpisony_notify_setup(sc);
127 0 : break;
128 : }
129 0 : return 0;
130 : }
131 :
132 : int
133 0 : acpisony_notify(struct aml_node *node, int notify, void *arg)
134 : {
135 0 : struct acpisony_softc *sc = arg;
136 : int val, key = 0;
137 :
138 0 : if (notify == SONY_NOTIFY_FN_KEY) {
139 0 : notify -= 0x90;
140 : DPRINTF(("notify = %X", notify));
141 :
142 0 : if (notify == acpisony_find_offset(sc, 0x100)) {
143 : DPRINTF(("key = 0x100\n"));
144 : key = 0x100;
145 0 : }
146 0 : if (notify == acpisony_find_offset(sc, 0x127)) {
147 : DPRINTF(("key = 0x127\n"));
148 : key = 0x127;
149 0 : }
150 :
151 0 : if (key) {
152 0 : val = acpisony_set_hotkey(sc, key, 0x200);
153 0 : if (val < 0) {
154 0 : printf("returned val = %X", val);
155 0 : return 1;
156 : }
157 0 : notify = val & 0xff;
158 :
159 : DPRINTF(("Treat %X events, notify %X\n", key, notify));
160 0 : } else
161 : DPRINTF(("rfkill update, notify %X\n", notify));
162 : }
163 :
164 0 : switch (notify) {
165 : case SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED:
166 : DPRINTF(("br-down-pressed\n"));
167 0 : acpisony_brightness_down(sc);
168 0 : 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 0 : if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ))
200 0 : acpi_addtask(sc->sc_acpi, acpi_sleep_task,
201 0 : sc->sc_acpi, ACPI_SLEEP_SUSPEND);
202 : #endif
203 : break;
204 : case SONY_NOTIFY_SUSPEND_RELEASED:
205 : DPRINTF(("suspend-released\n"));
206 : break;
207 : default:
208 0 : printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
209 0 : break;
210 : }
211 :
212 0 : return 0;
213 0 : }
214 :
215 : void
216 0 : acpisony_notify_setup(struct acpisony_softc *sc)
217 : {
218 0 : struct aml_value arg;
219 :
220 0 : bzero(&arg, sizeof(arg));
221 0 : arg.type = AML_OBJTYPE_INTEGER;
222 :
223 0 : arg.v_integer = 1;
224 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "ECON", 1, &arg, NULL);
225 :
226 : /* Enable all events */
227 0 : arg.v_integer = 0xffff;
228 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
229 :
230 : /* Enable hotkeys */
231 0 : arg.v_integer = 0x04;
232 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
233 0 : arg.v_integer = 0x02;
234 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
235 0 : arg.v_integer = 0x10;
236 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
237 0 : arg.v_integer = 0x00;
238 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
239 0 : arg.v_integer = 0x02;
240 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN03", 1, &arg, NULL);
241 0 : arg.v_integer = 0x101;
242 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
243 0 : }
244 :
245 : int
246 0 : acpisony_find_offset(struct acpisony_softc *sc, int key)
247 : {
248 0 : struct aml_value arg, res;
249 : int val;
250 :
251 0 : bzero(&arg, sizeof(arg));
252 0 : arg.type = AML_OBJTYPE_INTEGER;
253 :
254 0 : for (arg.v_integer = 0x20; arg.v_integer < 0x30; arg.v_integer++) {
255 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN00", 1, &arg, &res);
256 0 : val = aml_val2int(&res);
257 0 : aml_freevalue(&res);
258 0 : if (val == key) {
259 : DPRINTF(("Matched key %X\n", val));
260 0 : return arg.v_integer - 0x20;
261 : }
262 : }
263 :
264 0 : return -1;
265 0 : }
266 :
267 : int
268 0 : acpisony_set_hotkey(struct acpisony_softc *sc, int key, int val)
269 : {
270 : int off, rc = -1;
271 0 : struct aml_value res, arg;
272 :
273 0 : bzero(&arg, sizeof(arg));
274 0 : arg.type = AML_OBJTYPE_INTEGER;
275 :
276 0 : off = acpisony_find_offset(sc, key);
277 : DPRINTF(("off = %X\n", off));
278 0 : if (off < 0)
279 0 : return rc;
280 :
281 0 : arg.v_integer = off | val;
282 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, &res);
283 0 : rc = aml_val2int(&res);
284 0 : aml_freevalue(&res);
285 :
286 0 : return rc;
287 0 : }
288 :
289 : void
290 0 : acpisony_brightness_down(struct acpisony_softc *sc)
291 : {
292 : int val;
293 :
294 0 : val = acpisony_get_brightness(sc);
295 : DPRINTF(("current value = %X", val));
296 0 : if (val > 0)
297 0 : val--;
298 : else
299 : val = 0;
300 : DPRINTF(("next value = %X", val));
301 0 : acpisony_set_brightness(sc, val);
302 0 : }
303 :
304 : int
305 0 : acpisony_get_brightness(struct acpisony_softc *sc)
306 : {
307 0 : struct aml_value res;
308 : int val;
309 :
310 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "GBRT", 0, NULL, &res);
311 0 : val = aml_val2int(&res);
312 0 : aml_freevalue(&res);
313 :
314 0 : return val;
315 0 : }
316 :
317 : void
318 0 : acpisony_set_brightness(struct acpisony_softc *sc, int level)
319 : {
320 0 : struct aml_value arg;
321 :
322 0 : bzero(&arg, sizeof(arg));
323 0 : arg.type = AML_OBJTYPE_INTEGER;
324 0 : arg.v_integer = level;
325 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBRT", 1, &arg, NULL);
326 0 : aml_freevalue(&arg);
327 0 : }
|