Line data Source code
1 : /* $OpenBSD: acpithinkpad.c,v 1.61 2018/07/01 19:40:49 mlarkin Exp $ */
2 : /*
3 : * Copyright (c) 2008 joshua stein <jcs@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/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 : #include <dev/wscons/wsconsio.h>
27 :
28 : #include <machine/apmvar.h>
29 :
30 : #include "audio.h"
31 : #include "wskbd.h"
32 :
33 : /* #define ACPITHINKPAD_DEBUG */
34 :
35 : #ifdef ACPITHINKPAD_DEBUG
36 : #define DPRINTF(x) printf x
37 : #else
38 : #define DPRINTF(x)
39 : #endif
40 :
41 : #define THINKPAD_HKEY_VERSION1 0x0100
42 : #define THINKPAD_HKEY_VERSION2 0x0200
43 :
44 : #define THINKPAD_CMOS_VOLUME_DOWN 0x00
45 : #define THINKPAD_CMOS_VOLUME_UP 0x01
46 : #define THINKPAD_CMOS_VOLUME_MUTE 0x02
47 : #define THINKPAD_CMOS_BRIGHTNESS_UP 0x04
48 : #define THINKPAD_CMOS_BRIGHTNESS_DOWN 0x05
49 :
50 : #define THINKPAD_BLUETOOTH_PRESENT 0x01
51 : #define THINKPAD_BLUETOOTH_ENABLED 0x02
52 :
53 : /* wan (not wifi) card */
54 : #define THINKPAD_WAN_PRESENT 0x01
55 : #define THINKPAD_WAN_ENABLED 0x02
56 :
57 : #define THINKPAD_BUTTON_FN_F1 0x1001
58 : #define THINKPAD_BUTTON_LOCK_SCREEN 0x1002
59 : #define THINKPAD_BUTTON_BATTERY_INFO 0x1003
60 : #define THINKPAD_BUTTON_SUSPEND 0x1004
61 : #define THINKPAD_BUTTON_WIRELESS 0x1005
62 : #define THINKPAD_BUTTON_FN_F6 0x1006
63 : #define THINKPAD_BUTTON_EXTERNAL_SCREEN 0x1007
64 : #define THINKPAD_BUTTON_POINTER_SWITCH 0x1008
65 : #define THINKPAD_BUTTON_EJECT 0x1009
66 : #define THINKPAD_BUTTON_FN_F11 0x100b
67 : #define THINKPAD_BUTTON_HIBERNATE 0x100c
68 : #define THINKPAD_BUTTON_BRIGHTNESS_UP 0x1010
69 : #define THINKPAD_BUTTON_BRIGHTNESS_DOWN 0x1011
70 : #define THINKPAD_BUTTON_THINKLIGHT 0x1012
71 : #define THINKPAD_BUTTON_FN_SPACE 0x1014
72 : #define THINKPAD_BUTTON_VOLUME_UP 0x1015
73 : #define THINKPAD_BUTTON_VOLUME_DOWN 0x1016
74 : #define THINKPAD_BUTTON_VOLUME_MUTE 0x1017
75 : #define THINKPAD_BUTTON_THINKVANTAGE 0x1018
76 : #define THINKPAD_BUTTON_BLACK 0x101a
77 : #define THINKPAD_BUTTON_MICROPHONE_MUTE 0x101b
78 : #define THINKPAD_KEYLIGHT_CHANGED 0x101c
79 : #define THINKPAD_BUTTON_CONFIG 0x101d
80 : #define THINKPAD_BUTTON_FIND 0x101e
81 : #define THINKPAD_BUTTON_ALL_ACTIVEPROGS 0x101f
82 : #define THINKPAD_BUTTON_ALL_PROGS 0x1020
83 :
84 : #define THINKPAD_ADAPTIVE_NEXT 0x1101
85 : #define THINKPAD_ADAPTIVE_QUICK 0x1102
86 : #define THINKPAD_ADAPTIVE_SNIP 0x1105
87 : #define THINKPAD_ADAPTIVE_VOICE 0x1108
88 : #define THINKPAD_ADAPTIVE_GESTURES 0x110a
89 : #define THINKPAD_ADAPTIVE_SETTINGS 0x110e
90 : #define THINKPAD_ADAPTIVE_TAB 0x110f
91 : #define THINKPAD_ADAPTIVE_REFRESH 0x1110
92 : #define THINKPAD_ADAPTIVE_BACK 0x1111
93 : #define THINKPAD_PORT_REPL_DOCKED 0x4010
94 : #define THINKPAD_PORT_REPL_UNDOCKED 0x4011
95 : #define THINKPAD_TABLET_DOCKED 0x4012
96 : #define THINKPAD_TABLET_UNDOCKED 0x4013
97 : #define THINKPAD_LID_OPEN 0x5001
98 : #define THINKPAD_LID_CLOSED 0x5002
99 : #define THINKPAD_TABLET_SCREEN_NORMAL 0x500a
100 : #define THINKPAD_TABLET_SCREEN_ROTATED 0x5009
101 : #define THINKPAD_BRIGHTNESS_CHANGED 0x5010
102 : #define THINKPAD_TABLET_PEN_INSERTED 0x500b
103 : #define THINKPAD_TABLET_PEN_REMOVED 0x500c
104 : #define THINKPAD_SWITCH_NUMLOCK 0x6000
105 : #define THINKPAD_BUTTON_ROTATION_LOCK 0x6020
106 : #define THINKPAD_THERMAL_TABLE_CHANGED 0x6030
107 : #define THINKPAD_POWER_CHANGED 0x6040
108 : #define THINKPAD_BACKLIGHT_CHANGED 0x6050
109 : #define THINKPAD_BUTTON_FN_TOGGLE 0x6060
110 : #define THINKPAD_TABLET_SCREEN_CHANGED 0x60c0
111 : #define THINKPAD_SWITCH_WIRELESS 0x7000
112 :
113 : #define THINKPAD_NSENSORS 10
114 : #define THINKPAD_NTEMPSENSORS 8
115 :
116 : #define THINKPAD_SENSOR_FANRPM THINKPAD_NTEMPSENSORS
117 : #define THINKPAD_SENSOR_PORTREPL THINKPAD_NTEMPSENSORS + 1
118 :
119 : #define THINKPAD_ECOFFSET_VOLUME 0x30
120 : #define THINKPAD_ECOFFSET_VOLUME_MUTE_MASK 0x40
121 : #define THINKPAD_ECOFFSET_FANLO 0x84
122 : #define THINKPAD_ECOFFSET_FANHI 0x85
123 :
124 : #define THINKPAD_ADAPTIVE_MODE_HOME 1
125 : #define THINKPAD_ADAPTIVE_MODE_FUNCTION 3
126 :
127 : struct acpithinkpad_softc {
128 : struct device sc_dev;
129 :
130 : struct acpiec_softc *sc_ec;
131 : struct acpi_softc *sc_acpi;
132 : struct aml_node *sc_devnode;
133 :
134 : struct ksensor sc_sens[THINKPAD_NSENSORS];
135 : struct ksensordev sc_sensdev;
136 :
137 : uint64_t sc_thinklight;
138 : const char *sc_thinklight_get;
139 : const char *sc_thinklight_set;
140 :
141 : uint64_t sc_brightness;
142 : };
143 :
144 : extern void acpiec_read(struct acpiec_softc *, uint8_t, int, uint8_t *);
145 :
146 : int thinkpad_match(struct device *, void *, void *);
147 : void thinkpad_attach(struct device *, struct device *, void *);
148 : int thinkpad_hotkey(struct aml_node *, int, void *);
149 : int thinkpad_enable_events(struct acpithinkpad_softc *);
150 : int thinkpad_toggle_bluetooth(struct acpithinkpad_softc *);
151 : int thinkpad_toggle_wan(struct acpithinkpad_softc *);
152 : int thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t);
153 : int thinkpad_volume_down(struct acpithinkpad_softc *);
154 : int thinkpad_volume_up(struct acpithinkpad_softc *);
155 : int thinkpad_volume_mute(struct acpithinkpad_softc *);
156 : int thinkpad_brightness_up(struct acpithinkpad_softc *);
157 : int thinkpad_brightness_down(struct acpithinkpad_softc *);
158 : int thinkpad_adaptive_change(struct acpithinkpad_softc *);
159 : int thinkpad_activate(struct device *, int);
160 :
161 : /* wscons hook functions */
162 : void thinkpad_get_thinklight(struct acpithinkpad_softc *);
163 : void thinkpad_set_thinklight(void *, int);
164 : int thinkpad_get_backlight(struct wskbd_backlight *);
165 : int thinkpad_set_backlight(struct wskbd_backlight *);
166 : extern int (*wskbd_get_backlight)(struct wskbd_backlight *);
167 : extern int (*wskbd_set_backlight)(struct wskbd_backlight *);
168 : void thinkpad_get_brightness(struct acpithinkpad_softc *);
169 : void thinkpad_set_brightness(void *, int);
170 : int thinkpad_get_param(struct wsdisplay_param *);
171 : int thinkpad_set_param(struct wsdisplay_param *);
172 : extern int (*ws_get_param)(struct wsdisplay_param *);
173 : extern int (*ws_set_param)(struct wsdisplay_param *);
174 :
175 : void thinkpad_sensor_attach(struct acpithinkpad_softc *sc);
176 : void thinkpad_sensor_refresh(void *);
177 :
178 : #if NAUDIO > 0 && NWSKBD > 0
179 : void thinkpad_attach_deferred(void *);
180 : int thinkpad_get_volume_mute(struct acpithinkpad_softc *);
181 : extern int wskbd_set_mixermute(long, long);
182 : extern int wskbd_set_mixervolume(long, long);
183 : #endif
184 :
185 : struct cfattach acpithinkpad_ca = {
186 : sizeof(struct acpithinkpad_softc), thinkpad_match, thinkpad_attach,
187 : NULL, thinkpad_activate
188 : };
189 :
190 : struct cfdriver acpithinkpad_cd = {
191 : NULL, "acpithinkpad", DV_DULL
192 : };
193 :
194 : const char *acpithinkpad_hids[] = {
195 : "IBM0068",
196 : "LEN0068",
197 : "LEN0268",
198 : NULL
199 : };
200 :
201 : int
202 0 : thinkpad_match(struct device *parent, void *match, void *aux)
203 : {
204 0 : struct acpi_attach_args *aa = aux;
205 0 : struct cfdata *cf = match;
206 0 : int64_t res;
207 :
208 0 : if (!acpi_matchhids(aa, acpithinkpad_hids, cf->cf_driver->cd_name))
209 0 : return (0);
210 :
211 0 : if (aml_evalinteger((struct acpi_softc *)parent, aa->aaa_node,
212 : "MHKV", 0, NULL, &res))
213 0 : return (0);
214 :
215 0 : if (!(res == THINKPAD_HKEY_VERSION1 || res == THINKPAD_HKEY_VERSION2))
216 0 : return (0);
217 :
218 0 : return (1);
219 0 : }
220 :
221 : void
222 0 : thinkpad_sensor_attach(struct acpithinkpad_softc *sc)
223 : {
224 : int i;
225 :
226 0 : if (sc->sc_acpi->sc_ec == NULL)
227 0 : return;
228 0 : sc->sc_ec = sc->sc_acpi->sc_ec;
229 :
230 : /* Add temperature probes */
231 0 : strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
232 : sizeof(sc->sc_sensdev.xname));
233 0 : for (i=0; i<THINKPAD_NTEMPSENSORS; i++) {
234 0 : sc->sc_sens[i].type = SENSOR_TEMP;
235 0 : sensor_attach(&sc->sc_sensdev, &sc->sc_sens[i]);
236 : }
237 :
238 : /* Add fan probe */
239 0 : sc->sc_sens[THINKPAD_SENSOR_FANRPM].type = SENSOR_FANRPM;
240 0 : sensor_attach(&sc->sc_sensdev, &sc->sc_sens[THINKPAD_SENSOR_FANRPM]);
241 :
242 : /* Add port replicator indicator */
243 0 : sc->sc_sens[THINKPAD_SENSOR_PORTREPL].type = SENSOR_INDICATOR;
244 0 : sc->sc_sens[THINKPAD_SENSOR_PORTREPL].status = SENSOR_S_UNKNOWN;
245 0 : strlcpy(sc->sc_sens[THINKPAD_SENSOR_PORTREPL].desc, "port replicator",
246 : sizeof(sc->sc_sens[THINKPAD_SENSOR_PORTREPL].desc));
247 0 : sensor_attach(&sc->sc_sensdev, &sc->sc_sens[THINKPAD_SENSOR_PORTREPL]);
248 :
249 0 : sensordev_install(&sc->sc_sensdev);
250 0 : }
251 :
252 : void
253 0 : thinkpad_sensor_refresh(void *arg)
254 : {
255 0 : struct acpithinkpad_softc *sc = arg;
256 0 : uint8_t lo, hi, i;
257 0 : int64_t tmp;
258 0 : char sname[5];
259 :
260 : /* Refresh sensor readings */
261 0 : for (i=0; i<THINKPAD_NTEMPSENSORS; i++) {
262 0 : snprintf(sname, sizeof(sname), "TMP%d", i);
263 0 : aml_evalinteger(sc->sc_acpi, sc->sc_ec->sc_devnode,
264 : sname, 0, 0, &tmp);
265 0 : sc->sc_sens[i].value = (tmp * 1000000) + 273150000;
266 0 : if (tmp > 127 || tmp < -127)
267 0 : sc->sc_sens[i].flags = SENSOR_FINVALID;
268 : }
269 :
270 : /* Read fan RPM */
271 0 : acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANLO, 1, &lo);
272 0 : acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANHI, 1, &hi);
273 0 : sc->sc_sens[THINKPAD_SENSOR_FANRPM].value = ((hi << 8L) + lo);
274 0 : }
275 :
276 : void
277 0 : thinkpad_attach(struct device *parent, struct device *self, void *aux)
278 : {
279 0 : struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self;
280 0 : struct acpi_attach_args *aa = aux;
281 :
282 0 : sc->sc_acpi = (struct acpi_softc *)parent;
283 0 : sc->sc_devnode = aa->aaa_node;
284 :
285 0 : printf("\n");
286 :
287 : #if NAUDIO > 0 && NWSKBD > 0
288 : /* Defer speaker mute */
289 0 : if (thinkpad_get_volume_mute(sc) == 1)
290 0 : startuphook_establish(thinkpad_attach_deferred, sc);
291 : #endif
292 :
293 : /* Set event mask to receive everything */
294 0 : thinkpad_enable_events(sc);
295 0 : thinkpad_sensor_attach(sc);
296 :
297 : /* Check for ThinkLight or keyboard backlight */
298 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "KLCG",
299 0 : 0, NULL, &sc->sc_thinklight) == 0) {
300 0 : sc->sc_thinklight_get = "KLCG";
301 0 : sc->sc_thinklight_set = "KLCS";
302 0 : wskbd_get_backlight = thinkpad_get_backlight;
303 0 : wskbd_set_backlight = thinkpad_set_backlight;
304 0 : } else if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MLCG",
305 0 : 0, NULL, &sc->sc_thinklight) == 0) {
306 0 : sc->sc_thinklight_get = "MLCG";
307 0 : sc->sc_thinklight_set = "MLCS";
308 0 : wskbd_get_backlight = thinkpad_get_backlight;
309 0 : wskbd_set_backlight = thinkpad_set_backlight;
310 0 : }
311 :
312 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "PBLG",
313 0 : 0, NULL, &sc->sc_brightness) == 0) {
314 0 : ws_get_param = thinkpad_get_param;
315 0 : ws_set_param = thinkpad_set_param;
316 0 : }
317 :
318 : /* Run thinkpad_hotkey on button presses */
319 0 : aml_register_notify(sc->sc_devnode, aa->aaa_dev,
320 0 : thinkpad_hotkey, sc, ACPIDEV_POLL);
321 0 : }
322 :
323 : int
324 0 : thinkpad_enable_events(struct acpithinkpad_softc *sc)
325 : {
326 0 : struct aml_value arg, args[2];
327 0 : int64_t mask;
328 : int i;
329 :
330 : /* Get the supported event mask */
331 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKA",
332 : 0, NULL, &mask)) {
333 0 : printf("%s: no MHKA\n", DEVNAME(sc));
334 0 : return (1);
335 : }
336 :
337 : /* Update hotkey mask */
338 0 : bzero(args, sizeof(args));
339 0 : args[0].type = args[1].type = AML_OBJTYPE_INTEGER;
340 0 : for (i = 0; i < 32; i++) {
341 0 : args[0].v_integer = i + 1;
342 0 : args[1].v_integer = (((1 << i) & mask) != 0);
343 :
344 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKM",
345 : 2, args, NULL)) {
346 0 : printf("%s: couldn't toggle MHKM\n", DEVNAME(sc));
347 0 : return (1);
348 : }
349 : }
350 :
351 : /* Enable hotkeys */
352 0 : bzero(&arg, sizeof(arg));
353 0 : arg.type = AML_OBJTYPE_INTEGER;
354 0 : arg.v_integer = 1;
355 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKC",
356 : 1, &arg, NULL)) {
357 0 : printf("%s: couldn't enable hotkeys\n", DEVNAME(sc));
358 0 : return (1);
359 : }
360 :
361 0 : return (0);
362 0 : }
363 :
364 : int
365 0 : thinkpad_hotkey(struct aml_node *node, int notify_type, void *arg)
366 : {
367 0 : struct acpithinkpad_softc *sc = arg;
368 0 : int64_t event;
369 :
370 0 : if (notify_type == 0x00) {
371 : /* Poll sensors */
372 0 : thinkpad_sensor_refresh(sc);
373 0 : return (0);
374 : }
375 :
376 0 : if (notify_type != 0x80)
377 0 : return (1);
378 :
379 0 : for (;;) {
380 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKP",
381 : 0, NULL, &event))
382 : break;
383 0 : if (event == 0)
384 : break;
385 :
386 0 : switch (event) {
387 : case THINKPAD_BUTTON_BRIGHTNESS_UP:
388 0 : thinkpad_brightness_up(sc);
389 0 : break;
390 : case THINKPAD_BUTTON_BRIGHTNESS_DOWN:
391 0 : thinkpad_brightness_down(sc);
392 0 : break;
393 : case THINKPAD_BUTTON_WIRELESS:
394 0 : thinkpad_toggle_bluetooth(sc);
395 0 : break;
396 : case THINKPAD_BUTTON_SUSPEND:
397 : #ifndef SMALL_KERNEL
398 0 : if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ))
399 0 : acpi_addtask(sc->sc_acpi, acpi_sleep_task,
400 0 : sc->sc_acpi, ACPI_SLEEP_SUSPEND);
401 : #endif
402 : break;
403 : case THINKPAD_BUTTON_VOLUME_MUTE:
404 0 : thinkpad_volume_mute(sc);
405 0 : break;
406 : case THINKPAD_BUTTON_VOLUME_DOWN:
407 0 : thinkpad_volume_down(sc);
408 0 : break;
409 : case THINKPAD_BUTTON_VOLUME_UP:
410 0 : thinkpad_volume_up(sc);
411 0 : break;
412 : case THINKPAD_BUTTON_MICROPHONE_MUTE:
413 : #if NAUDIO > 0 && NWSKBD > 0
414 0 : wskbd_set_mixervolume(0, 0);
415 : #endif
416 0 : break;
417 : case THINKPAD_BUTTON_HIBERNATE:
418 : #if defined(HIBERNATE) && !defined(SMALL_KERNEL)
419 0 : if (acpi_record_event(sc->sc_acpi, APM_USER_HIBERNATE_REQ))
420 0 : acpi_addtask(sc->sc_acpi, acpi_sleep_task,
421 0 : sc->sc_acpi, ACPI_SLEEP_HIBERNATE);
422 : #endif
423 : break;
424 : case THINKPAD_BUTTON_THINKLIGHT:
425 0 : thinkpad_get_thinklight(sc);
426 0 : break;
427 : case THINKPAD_ADAPTIVE_NEXT:
428 : case THINKPAD_ADAPTIVE_QUICK:
429 0 : thinkpad_adaptive_change(sc);
430 0 : break;
431 : case THINKPAD_BACKLIGHT_CHANGED:
432 0 : thinkpad_get_brightness(sc);
433 0 : break;
434 : case THINKPAD_PORT_REPL_DOCKED:
435 0 : sc->sc_sens[THINKPAD_SENSOR_PORTREPL].value = 1;
436 0 : sc->sc_sens[THINKPAD_SENSOR_PORTREPL].status =
437 : SENSOR_S_OK;
438 0 : break;
439 : case THINKPAD_PORT_REPL_UNDOCKED:
440 0 : sc->sc_sens[THINKPAD_SENSOR_PORTREPL].value = 0;
441 0 : sc->sc_sens[THINKPAD_SENSOR_PORTREPL].status =
442 : SENSOR_S_OK;
443 0 : break;
444 : default:
445 : /* unknown or boring event */
446 : DPRINTF(("%s: unhandled event 0x%03llx\n", DEVNAME(sc),
447 : event));
448 : break;
449 : }
450 : }
451 :
452 0 : return (0);
453 0 : }
454 :
455 : int
456 0 : thinkpad_toggle_bluetooth(struct acpithinkpad_softc *sc)
457 : {
458 0 : struct aml_value arg;
459 0 : int64_t bluetooth;
460 :
461 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GBDC",
462 : 0, NULL, &bluetooth))
463 0 : return (1);
464 :
465 0 : if (!(bluetooth & THINKPAD_BLUETOOTH_PRESENT))
466 0 : return (1);
467 :
468 0 : bzero(&arg, sizeof(arg));
469 0 : arg.type = AML_OBJTYPE_INTEGER;
470 0 : arg.v_integer = bluetooth ^ THINKPAD_BLUETOOTH_ENABLED;
471 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBDC",
472 : 1, &arg, NULL)) {
473 0 : printf("%s: couldn't toggle bluetooth\n", DEVNAME(sc));
474 0 : return (1);
475 : }
476 :
477 0 : return (0);
478 0 : }
479 :
480 : int
481 0 : thinkpad_toggle_wan(struct acpithinkpad_softc *sc)
482 : {
483 0 : struct aml_value arg;
484 0 : int64_t wan;
485 :
486 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GWAN",
487 : 0, NULL, &wan))
488 0 : return (1);
489 :
490 0 : if (!(wan & THINKPAD_WAN_PRESENT))
491 0 : return (1);
492 :
493 0 : bzero(&arg, sizeof(arg));
494 0 : arg.type = AML_OBJTYPE_INTEGER;
495 0 : arg.v_integer = wan ^ THINKPAD_WAN_ENABLED;
496 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SWAN",
497 : 1, &arg, NULL)) {
498 0 : printf("%s: couldn't toggle wan\n", DEVNAME(sc));
499 0 : return (1);
500 : }
501 :
502 0 : return (0);
503 0 : }
504 :
505 : int
506 0 : thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t cmd)
507 : {
508 0 : struct aml_value arg;
509 :
510 0 : bzero(&arg, sizeof(arg));
511 0 : arg.type = AML_OBJTYPE_INTEGER;
512 0 : arg.v_integer = cmd;
513 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode, "\\UCMS", 1, &arg, NULL);
514 0 : return (0);
515 0 : }
516 :
517 : int
518 0 : thinkpad_volume_down(struct acpithinkpad_softc *sc)
519 : {
520 0 : return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_DOWN));
521 : }
522 :
523 : int
524 0 : thinkpad_volume_up(struct acpithinkpad_softc *sc)
525 : {
526 0 : return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_UP));
527 : }
528 :
529 : int
530 0 : thinkpad_volume_mute(struct acpithinkpad_softc *sc)
531 : {
532 0 : return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_MUTE));
533 : }
534 :
535 : int
536 0 : thinkpad_brightness_up(struct acpithinkpad_softc *sc)
537 : {
538 0 : return (thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_UP));
539 : }
540 :
541 : int
542 0 : thinkpad_brightness_down(struct acpithinkpad_softc *sc)
543 : {
544 0 : return (thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_DOWN));
545 : }
546 :
547 : int
548 0 : thinkpad_adaptive_change(struct acpithinkpad_softc *sc)
549 : {
550 0 : struct aml_value arg;
551 0 : int64_t mode;
552 :
553 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GTRW",
554 : 0, NULL, &mode)) {
555 0 : printf("%s: couldn't get adaptive keyboard mode\n", DEVNAME(sc));
556 0 : return (1);
557 : }
558 :
559 0 : bzero(&arg, sizeof(arg));
560 0 : arg.type = AML_OBJTYPE_INTEGER;
561 :
562 0 : if (mode == THINKPAD_ADAPTIVE_MODE_FUNCTION)
563 0 : arg.v_integer = THINKPAD_ADAPTIVE_MODE_HOME;
564 : else
565 0 : arg.v_integer = THINKPAD_ADAPTIVE_MODE_FUNCTION;
566 :
567 0 : if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "STRW",
568 : 1, &arg, NULL)) {
569 0 : printf("%s: couldn't set adaptive keyboard mode\n", DEVNAME(sc));
570 0 : return (1);
571 : }
572 :
573 0 : return (0);
574 0 : }
575 :
576 : int
577 0 : thinkpad_activate(struct device *self, int act)
578 : {
579 :
580 0 : struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self;
581 0 : int64_t res;
582 : #if NAUDIO > 0 && NWSKBD > 0
583 : int mute;
584 : #endif
585 :
586 0 : switch (act) {
587 : case DVACT_WAKEUP:
588 0 : if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GTRW",
589 0 : 0, NULL, &res) == 0)
590 0 : thinkpad_adaptive_change(sc);
591 : #if NAUDIO > 0 && NWSKBD > 0
592 0 : mute = thinkpad_get_volume_mute(sc);
593 0 : if (mute != -1)
594 0 : wskbd_set_mixermute(mute, 1);
595 : #endif
596 : break;
597 : }
598 0 : return (0);
599 0 : }
600 :
601 : void
602 0 : thinkpad_get_thinklight(struct acpithinkpad_softc *sc)
603 : {
604 0 : if (sc->sc_thinklight_get)
605 0 : aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
606 0 : sc->sc_thinklight_get, 0, NULL, &sc->sc_thinklight);
607 0 : }
608 :
609 : void
610 0 : thinkpad_set_thinklight(void *arg0, int arg1)
611 : {
612 0 : struct acpithinkpad_softc *sc = arg0;
613 0 : struct aml_value arg;
614 :
615 0 : memset(&arg, 0, sizeof(arg));
616 0 : arg.type = AML_OBJTYPE_INTEGER;
617 0 : arg.v_integer = sc->sc_thinklight & 0x0f;
618 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode,
619 0 : sc->sc_thinklight_set, 1, &arg, NULL);
620 0 : }
621 :
622 : int
623 0 : thinkpad_get_backlight(struct wskbd_backlight *kbl)
624 : {
625 0 : struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
626 :
627 0 : KASSERT(sc != NULL);
628 :
629 0 : kbl->min = 0;
630 0 : kbl->max = (sc->sc_thinklight >> 8) & 0x0f;
631 0 : kbl->curval = sc->sc_thinklight & 0x0f;
632 :
633 0 : if (kbl->max == 0)
634 0 : return (ENOTTY);
635 :
636 0 : return 0;
637 0 : }
638 :
639 : int
640 0 : thinkpad_set_backlight(struct wskbd_backlight *kbl)
641 : {
642 0 : struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
643 : int maxval;
644 :
645 0 : KASSERT(sc != NULL);
646 :
647 0 : maxval = (sc->sc_thinklight >> 8) & 0x0f;
648 :
649 0 : if (maxval == 0)
650 0 : return (ENOTTY);
651 :
652 0 : if (kbl->curval > maxval)
653 0 : return EINVAL;
654 :
655 0 : sc->sc_thinklight &= ~0xff;
656 0 : sc->sc_thinklight |= kbl->curval;
657 0 : acpi_addtask(sc->sc_acpi, thinkpad_set_thinklight, sc, 0);
658 0 : acpi_wakeup(sc->sc_acpi);
659 0 : return 0;
660 0 : }
661 :
662 : void
663 0 : thinkpad_get_brightness(struct acpithinkpad_softc *sc)
664 : {
665 0 : aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
666 0 : "PBLG", 0, NULL, &sc->sc_brightness);
667 0 : }
668 :
669 : void
670 0 : thinkpad_set_brightness(void *arg0, int arg1)
671 : {
672 0 : struct acpithinkpad_softc *sc = arg0;
673 0 : struct aml_value arg;
674 :
675 0 : memset(&arg, 0, sizeof(arg));
676 0 : arg.type = AML_OBJTYPE_INTEGER;
677 0 : arg.v_integer = sc->sc_brightness & 0xff;
678 0 : aml_evalname(sc->sc_acpi, sc->sc_devnode,
679 : "PBLS", 1, &arg, NULL);
680 0 : }
681 :
682 : int
683 0 : thinkpad_get_param(struct wsdisplay_param *dp)
684 : {
685 0 : struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
686 :
687 0 : if (sc == NULL)
688 0 : return -1;
689 :
690 0 : switch (dp->param) {
691 : case WSDISPLAYIO_PARAM_BRIGHTNESS:
692 0 : dp->min = 0;
693 0 : dp->max = (sc->sc_brightness >> 8) & 0xff;
694 0 : dp->curval = sc->sc_brightness & 0xff;
695 0 : return 0;
696 : default:
697 0 : return -1;
698 : }
699 0 : }
700 :
701 : int
702 0 : thinkpad_set_param(struct wsdisplay_param *dp)
703 : {
704 0 : struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
705 : int maxval;
706 :
707 0 : if (sc == NULL)
708 0 : return -1;
709 :
710 0 : maxval = (sc->sc_brightness >> 8) & 0xff;
711 :
712 0 : switch (dp->param) {
713 : case WSDISPLAYIO_PARAM_BRIGHTNESS:
714 0 : if (dp->curval < 0)
715 0 : dp->curval = 0;
716 0 : if (dp->curval > maxval)
717 0 : dp->curval = maxval;
718 0 : sc->sc_brightness &= ~0xff;
719 0 : sc->sc_brightness |= dp->curval;
720 0 : acpi_addtask(sc->sc_acpi, thinkpad_set_brightness, sc, 0);
721 0 : acpi_wakeup(sc->sc_acpi);
722 0 : return 0;
723 : default:
724 0 : return -1;
725 : }
726 0 : }
727 :
728 : #if NAUDIO > 0 && NWSKBD > 0
729 : void
730 0 : thinkpad_attach_deferred(void *v __unused)
731 : {
732 0 : wskbd_set_mixermute(1, 1);
733 0 : }
734 :
735 : int
736 0 : thinkpad_get_volume_mute(struct acpithinkpad_softc *sc)
737 : {
738 0 : uint8_t vol = 0;
739 :
740 0 : if (sc->sc_acpi->sc_ec == NULL)
741 0 : return (-1);
742 :
743 0 : acpiec_read(sc->sc_acpi->sc_ec, THINKPAD_ECOFFSET_VOLUME, 1, &vol);
744 0 : return ((vol & THINKPAD_ECOFFSET_VOLUME_MUTE_MASK) ==
745 : THINKPAD_ECOFFSET_VOLUME_MUTE_MASK);
746 0 : }
747 : #endif
|