1 /* $OpenBSD: acpisony.c,v 1.10 2022/04/06 18:59:27 naddy Exp $ */
2 /*
3 * Copyright (c) 2010 Paul Irofti <paul@irofti.net>
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 const 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
acpisony_match(struct device * parent,void * match,void * aux)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
acpisony_attach(struct device * parent,struct device * self,void * aux)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
acpisony_activate(struct device * self,int act)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
acpisony_notify(struct aml_node * node,int notify,void * arg)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, SLEEP_SUSPEND);
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
acpisony_notify_setup(struct acpisony_softc * sc)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
acpisony_find_offset(struct acpisony_softc * sc,int key)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
acpisony_set_hotkey(struct acpisony_softc * sc,int key,int val)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
acpisony_brightness_down(struct acpisony_softc * sc)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
acpisony_get_brightness(struct acpisony_softc * sc)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
acpisony_set_brightness(struct acpisony_softc * sc,int level)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