1 /*-
2 * Copyright (c) 2012 Alexander Motin <mav@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 #include "opt_acpi.h"
29 #include "opt_evdev.h"
30 #include <sys/param.h>
31 #include <sys/conf.h>
32 #include <sys/uio.h>
33 #include <sys/proc.h>
34 #include <sys/kernel.h>
35 #include <sys/bus.h>
36 #include <sys/sbuf.h>
37 #include <sys/module.h>
38 #include <sys/sysctl.h>
39
40 #include <contrib/dev/acpica/include/acpi.h>
41 #include <contrib/dev/acpica/include/accommon.h>
42 #include <dev/acpica/acpivar.h>
43 #include "acpi_wmi_if.h"
44
45 #include <dev/backlight/backlight.h>
46 #include "backlight_if.h"
47
48 #ifdef EVDEV_SUPPORT
49 #include <dev/evdev/input.h>
50 #include <dev/evdev/evdev.h>
51 #define NO_KEY KEY_RESERVED
52 #endif
53
54 #define _COMPONENT ACPI_OEM
55 ACPI_MODULE_NAME("ASUS-WMI")
56
57 #define ACPI_ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66"
58 #define ACPI_ASUS_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
59 #define ACPI_EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000"
60
61 /* WMI Methods */
62 #define ASUS_WMI_METHODID_SPEC 0x43455053
63 #define ASUS_WMI_METHODID_SFUN 0x4E554653
64 #define ASUS_WMI_METHODID_DSTS 0x53544344
65 #define ASUS_WMI_METHODID_DSTS2 0x53545344
66 #define ASUS_WMI_METHODID_DEVS 0x53564544
67 #define ASUS_WMI_METHODID_INIT 0x54494E49
68 #define ASUS_WMI_METHODID_HKEY 0x59454B48
69
70 #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE
71
72 /* Wireless */
73 #define ASUS_WMI_DEVID_HW_SWITCH 0x00010001
74 #define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002
75 #define ASUS_WMI_DEVID_CWAP 0x00010003
76 #define ASUS_WMI_DEVID_WLAN 0x00010011
77 #define ASUS_WMI_DEVID_BLUETOOTH 0x00010013
78 #define ASUS_WMI_DEVID_GPS 0x00010015
79 #define ASUS_WMI_DEVID_WIMAX 0x00010017
80 #define ASUS_WMI_DEVID_WWAN3G 0x00010019
81 #define ASUS_WMI_DEVID_UWB 0x00010021
82
83 /* LEDs */
84 #define ASUS_WMI_DEVID_LED1 0x00020011
85 #define ASUS_WMI_DEVID_LED2 0x00020012
86 #define ASUS_WMI_DEVID_LED3 0x00020013
87 #define ASUS_WMI_DEVID_LED4 0x00020014
88 #define ASUS_WMI_DEVID_LED5 0x00020015
89 #define ASUS_WMI_DEVID_LED6 0x00020016
90
91 /* Backlight and Brightness */
92 #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
93 #define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012
94 #define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021
95 #define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022
96
97 /* Misc */
98 #define ASUS_WMI_DEVID_CAMERA 0x00060013
99 #define ASUS_WMI_DEVID_CARDREADER 0x00080013
100 #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011
101 #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012
102 #define ASUS_WMI_DEVID_TUF_RGB_MODE 0x00100056
103 #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
104 #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012
105 #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
106 #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075
107
108 /* DSTS masks */
109 #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001
110 #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002
111 #define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000
112 #define ASUS_WMI_DSTS_USER_BIT 0x00020000
113 #define ASUS_WMI_DSTS_BIOS_BIT 0x00040000
114 #define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF
115 #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00
116
117 /* Events */
118 #define ASUS_WMI_EVENT_QUEUE_SIZE 0x10
119 #define ASUS_WMI_EVENT_QUEUE_END 0x1
120 #define ASUS_WMI_EVENT_MASK 0xFFFF
121 #define ASUS_WMI_EVENT_VALUE_ATK 0xFF
122
123 struct acpi_asus_wmi_softc {
124 device_t dev;
125 device_t wmi_dev;
126 const char *notify_guid;
127 struct sysctl_ctx_list *sysctl_ctx;
128 struct sysctl_oid *sysctl_tree;
129 int dsts_id;
130 int handle_keys;
131 bool event_queue;
132 struct cdev *kbd_bkl;
133 uint32_t kbd_bkl_level;
134 uint32_t tuf_rgb_mode;
135 uint32_t ttp_mode;
136 #ifdef EVDEV_SUPPORT
137 struct evdev_dev *evdev;
138 #endif
139 };
140
141 static struct {
142 char *name;
143 int dev_id;
144 char *description;
145 int flag_rdonly;
146 } acpi_asus_wmi_sysctls[] = {
147 {
148 .name = "hw_switch",
149 .dev_id = ASUS_WMI_DEVID_HW_SWITCH,
150 .description = "hw_switch",
151 },
152 {
153 .name = "wireless_led",
154 .dev_id = ASUS_WMI_DEVID_WIRELESS_LED,
155 .description = "Wireless LED control",
156 },
157 {
158 .name = "cwap",
159 .dev_id = ASUS_WMI_DEVID_CWAP,
160 .description = "Alt+F2 function",
161 },
162 {
163 .name = "wlan",
164 .dev_id = ASUS_WMI_DEVID_WLAN,
165 .description = "WLAN power control",
166 },
167 {
168 .name = "bluetooth",
169 .dev_id = ASUS_WMI_DEVID_BLUETOOTH,
170 .description = "Bluetooth power control",
171 },
172 {
173 .name = "gps",
174 .dev_id = ASUS_WMI_DEVID_GPS,
175 .description = "GPS power control",
176 },
177 {
178 .name = "wimax",
179 .dev_id = ASUS_WMI_DEVID_WIMAX,
180 .description = "WiMAX power control",
181 },
182 {
183 .name = "wwan3g",
184 .dev_id = ASUS_WMI_DEVID_WWAN3G,
185 .description = "WWAN-3G power control",
186 },
187 {
188 .name = "uwb",
189 .dev_id = ASUS_WMI_DEVID_UWB,
190 .description = "UWB power control",
191 },
192 {
193 .name = "led1",
194 .dev_id = ASUS_WMI_DEVID_LED1,
195 .description = "LED1 control",
196 },
197 {
198 .name = "led2",
199 .dev_id = ASUS_WMI_DEVID_LED2,
200 .description = "LED2 control",
201 },
202 {
203 .name = "led3",
204 .dev_id = ASUS_WMI_DEVID_LED3,
205 .description = "LED3 control",
206 },
207 {
208 .name = "led4",
209 .dev_id = ASUS_WMI_DEVID_LED4,
210 .description = "LED4 control",
211 },
212 {
213 .name = "led5",
214 .dev_id = ASUS_WMI_DEVID_LED5,
215 .description = "LED5 control",
216 },
217 {
218 .name = "led6",
219 .dev_id = ASUS_WMI_DEVID_LED6,
220 .description = "LED6 control",
221 },
222 {
223 .name = "backlight",
224 .dev_id = ASUS_WMI_DEVID_BACKLIGHT,
225 .description = "LCD backlight on/off control",
226 },
227 {
228 .name = "brightness",
229 .dev_id = ASUS_WMI_DEVID_BRIGHTNESS,
230 .description = "LCD backlight brightness control",
231 },
232 {
233 .name = "kbd_backlight",
234 .dev_id = ASUS_WMI_DEVID_KBD_BACKLIGHT,
235 .description = "Keyboard backlight brightness control",
236 },
237 {
238 .name = "light_sensor",
239 .dev_id = ASUS_WMI_DEVID_LIGHT_SENSOR,
240 .description = "Ambient light sensor",
241 },
242 {
243 .name = "camera",
244 .dev_id = ASUS_WMI_DEVID_CAMERA,
245 .description = "Camera power control",
246 },
247 {
248 .name = "cardreader",
249 .dev_id = ASUS_WMI_DEVID_CARDREADER,
250 .description = "Cardreader power control",
251 },
252 {
253 .name = "touchpad",
254 .dev_id = ASUS_WMI_DEVID_TOUCHPAD,
255 .description = "Touchpad control",
256 },
257 {
258 .name = "touchpad_led",
259 .dev_id = ASUS_WMI_DEVID_TOUCHPAD_LED,
260 .description = "Touchpad LED control",
261 },
262 {
263 .name = "themperature",
264 .dev_id = ASUS_WMI_DEVID_THERMAL_CTRL,
265 .description = "Temperature (C)",
266 .flag_rdonly = 1
267 },
268 {
269 .name = "fan_speed",
270 .dev_id = ASUS_WMI_DEVID_FAN_CTRL,
271 .description = "Fan speed (0-3)",
272 .flag_rdonly = 1
273 },
274 {
275 .name = "processor_state",
276 .dev_id = ASUS_WMI_DEVID_PROCESSOR_STATE,
277 .flag_rdonly = 1
278 },
279 {
280 .name = "throttle_thermal_policy",
281 .dev_id = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
282 .description = "Throttle Thermal Policy "
283 "(0 - default, 1 - overboost, 2 - silent)",
284 },
285 { NULL, 0, NULL, 0 }
286 };
287
288 #ifdef EVDEV_SUPPORT
289 static const struct {
290 UINT32 notify;
291 uint16_t key;
292 } acpi_asus_wmi_evdev_map[] = {
293 { 0x20, KEY_BRIGHTNESSDOWN },
294 { 0x2f, KEY_BRIGHTNESSUP },
295 { 0x30, KEY_VOLUMEUP },
296 { 0x31, KEY_VOLUMEDOWN },
297 { 0x32, KEY_MUTE },
298 { 0x35, KEY_SCREENLOCK },
299 { 0x38, KEY_PROG3 }, /* Armoury Crate */
300 { 0x40, KEY_PREVIOUSSONG },
301 { 0x41, KEY_NEXTSONG },
302 { 0x43, KEY_STOPCD }, /* Stop/Eject */
303 { 0x45, KEY_PLAYPAUSE },
304 { 0x4f, KEY_LEFTMETA }, /* Fn-locked "Windows" Key */
305 { 0x4c, KEY_MEDIA }, /* WMP Key */
306 { 0x50, KEY_EMAIL },
307 { 0x51, KEY_WWW },
308 { 0x55, KEY_CALC },
309 { 0x57, NO_KEY }, /* Battery mode */
310 { 0x58, NO_KEY }, /* AC mode */
311 { 0x5C, KEY_F15 }, /* Power Gear key */
312 { 0x5D, KEY_WLAN }, /* Wireless console Toggle */
313 { 0x5E, KEY_WLAN }, /* Wireless console Enable */
314 { 0x5F, KEY_WLAN }, /* Wireless console Disable */
315 { 0x60, KEY_TOUCHPAD_ON },
316 { 0x61, KEY_SWITCHVIDEOMODE }, /* SDSP LCD only */
317 { 0x62, KEY_SWITCHVIDEOMODE }, /* SDSP CRT only */
318 { 0x63, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT */
319 { 0x64, KEY_SWITCHVIDEOMODE }, /* SDSP TV */
320 { 0x65, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + TV */
321 { 0x66, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + TV */
322 { 0x67, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + TV */
323 { 0x6B, KEY_TOUCHPAD_TOGGLE },
324 { 0x6E, NO_KEY }, /* Low Battery notification */
325 { 0x71, KEY_F13 }, /* General-purpose button */
326 { 0x79, NO_KEY }, /* Charger type dectection notification */
327 { 0x7a, KEY_ALS_TOGGLE }, /* Ambient Light Sensor Toggle */
328 { 0x7c, KEY_MICMUTE },
329 { 0x7D, KEY_BLUETOOTH }, /* Bluetooth Enable */
330 { 0x7E, KEY_BLUETOOTH }, /* Bluetooth Disable */
331 { 0x82, KEY_CAMERA },
332 { 0x86, KEY_PROG1 }, /* MyASUS Key */
333 { 0x88, KEY_RFKILL }, /* Radio Toggle Key */
334 { 0x8A, KEY_PROG1 }, /* Color enhancement mode */
335 { 0x8C, KEY_SWITCHVIDEOMODE }, /* SDSP DVI only */
336 { 0x8D, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + DVI */
337 { 0x8E, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + DVI */
338 { 0x8F, KEY_SWITCHVIDEOMODE }, /* SDSP TV + DVI */
339 { 0x90, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + DVI */
340 { 0x91, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + TV + DVI */
341 { 0x92, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + TV + DVI */
342 { 0x93, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + TV + DVI */
343 { 0x95, KEY_MEDIA },
344 { 0x99, KEY_PHONE }, /* Conflicts with fan mode switch */
345 { 0xA0, KEY_SWITCHVIDEOMODE }, /* SDSP HDMI only */
346 { 0xA1, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + HDMI */
347 { 0xA2, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + HDMI */
348 { 0xA3, KEY_SWITCHVIDEOMODE }, /* SDSP TV + HDMI */
349 { 0xA4, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + HDMI */
350 { 0xA5, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + TV + HDMI */
351 { 0xA6, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + TV + HDMI */
352 { 0xA7, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + TV + HDMI */
353 { 0xAE, KEY_FN_F5 }, /* Fn+F5 fan mode on 2020+ */
354 { 0xB3, KEY_PROG4 }, /* AURA */
355 { 0xB5, KEY_CALC },
356 { 0xC4, KEY_KBDILLUMUP },
357 { 0xC5, KEY_KBDILLUMDOWN },
358 { 0xC6, NO_KEY }, /* Ambient Light Sensor notification */
359 { 0xFA, KEY_PROG2 }, /* Lid flip action */
360 { 0xBD, KEY_PROG2 }, /* Lid flip action on ROG xflow laptops */
361 };
362 #endif
363
364 ACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device");
365
366 static void acpi_asus_wmi_identify(driver_t *driver, device_t parent);
367 static int acpi_asus_wmi_probe(device_t dev);
368 static int acpi_asus_wmi_attach(device_t dev);
369 static int acpi_asus_wmi_detach(device_t dev);
370 static int acpi_asus_wmi_suspend(device_t dev);
371 static int acpi_asus_wmi_resume(device_t dev);
372
373 static int acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS);
374 static int acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id,
375 int arg, int oldarg);
376 static int acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id);
377 static int acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
378 UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval);
379 static int acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
380 UINT32 dev_id, UINT32 *retval);
381 static int acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
382 UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval);
383 static int acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify,
384 int *code);
385 static void acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context);
386 static int acpi_asus_wmi_backlight_update_status(device_t dev,
387 struct backlight_props *props);
388 static int acpi_asus_wmi_backlight_get_status(device_t dev,
389 struct backlight_props *props);
390 static int acpi_asus_wmi_backlight_get_info(device_t dev,
391 struct backlight_info *info);
392
393 static device_method_t acpi_asus_wmi_methods[] = {
394 /* Device interface */
395 DEVMETHOD(device_identify, acpi_asus_wmi_identify),
396 DEVMETHOD(device_probe, acpi_asus_wmi_probe),
397 DEVMETHOD(device_attach, acpi_asus_wmi_attach),
398 DEVMETHOD(device_detach, acpi_asus_wmi_detach),
399 DEVMETHOD(device_suspend, acpi_asus_wmi_suspend),
400 DEVMETHOD(device_resume, acpi_asus_wmi_resume),
401
402 /* Backlight interface */
403 DEVMETHOD(backlight_update_status, acpi_asus_wmi_backlight_update_status),
404 DEVMETHOD(backlight_get_status, acpi_asus_wmi_backlight_get_status),
405 DEVMETHOD(backlight_get_info, acpi_asus_wmi_backlight_get_info),
406
407 DEVMETHOD_END
408 };
409
410 static driver_t acpi_asus_wmi_driver = {
411 "acpi_asus_wmi",
412 acpi_asus_wmi_methods,
413 sizeof(struct acpi_asus_wmi_softc),
414 };
415
416 DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver, 0, 0);
417 MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1);
418 MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1);
419 MODULE_DEPEND(acpi_asus_wmi, backlight, 1, 1, 1);
420 #ifdef EVDEV_SUPPORT
421 MODULE_DEPEND(acpi_asus_wmi, evdev, 1, 1, 1);
422 #endif
423
424 static const uint32_t acpi_asus_wmi_backlight_levels[] = { 0, 33, 66, 100 };
425
426 static inline uint32_t
devstate_to_kbd_bkl_level(UINT32 val)427 devstate_to_kbd_bkl_level(UINT32 val)
428 {
429 return (acpi_asus_wmi_backlight_levels[val & 0x3]);
430 }
431
432 static inline UINT32
kbd_bkl_level_to_devstate(uint32_t bkl)433 kbd_bkl_level_to_devstate(uint32_t bkl)
434 {
435 UINT32 val;
436 int i;
437
438 for (i = 0; i < nitems(acpi_asus_wmi_backlight_levels); i++) {
439 if (bkl < acpi_asus_wmi_backlight_levels[i])
440 break;
441 }
442 val = (i - 1) & 0x3;
443 if (val != 0)
444 val |= 0x80;
445 return(val);
446 }
447
448 static void
acpi_asus_wmi_identify(driver_t * driver,device_t parent)449 acpi_asus_wmi_identify(driver_t *driver, device_t parent)
450 {
451
452 /* Don't do anything if driver is disabled. */
453 if (acpi_disabled("asus_wmi"))
454 return;
455
456 /* Add only a single device instance. */
457 if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL)
458 return;
459
460 /* Check management GUID to see whether system is compatible. */
461 if (!ACPI_WMI_PROVIDES_GUID_STRING(parent,
462 ACPI_ASUS_WMI_MGMT_GUID))
463 return;
464
465 if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL)
466 device_printf(parent, "add acpi_asus_wmi child failed\n");
467 }
468
469 static int
acpi_asus_wmi_probe(device_t dev)470 acpi_asus_wmi_probe(device_t dev)
471 {
472
473 if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev),
474 ACPI_ASUS_WMI_MGMT_GUID))
475 return (EINVAL);
476 device_set_desc(dev, "ASUS WMI device");
477 return (0);
478 }
479
480 static int
acpi_asus_wmi_attach(device_t dev)481 acpi_asus_wmi_attach(device_t dev)
482 {
483 struct acpi_asus_wmi_softc *sc;
484 UINT32 val;
485 int dev_id, i, code;
486 bool have_kbd_bkl = false;
487
488 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
489
490 sc = device_get_softc(dev);
491 sc->dev = dev;
492 sc->wmi_dev = device_get_parent(dev);
493 sc->handle_keys = 1;
494
495 /* Check management GUID. */
496 if (!ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
497 ACPI_ASUS_WMI_MGMT_GUID)) {
498 device_printf(dev,
499 "WMI device does not provide the ASUS management GUID\n");
500 return (EINVAL);
501 }
502
503 /* Find proper DSTS method. */
504 sc->dsts_id = ASUS_WMI_METHODID_DSTS;
505 next:
506 for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
507 dev_id = acpi_asus_wmi_sysctls[i].dev_id;
508 if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
509 continue;
510 break;
511 }
512 if (acpi_asus_wmi_sysctls[i].name == NULL) {
513 if (sc->dsts_id == ASUS_WMI_METHODID_DSTS) {
514 sc->dsts_id = ASUS_WMI_METHODID_DSTS2;
515 goto next;
516 } else {
517 device_printf(dev, "Can not detect DSTS method ID\n");
518 return (EINVAL);
519 }
520 }
521
522 /* Find proper and attach to notufy GUID. */
523 if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
524 ACPI_ASUS_WMI_EVENT_GUID))
525 sc->notify_guid = ACPI_ASUS_WMI_EVENT_GUID;
526 else if (ACPI_WMI_PROVIDES_GUID_STRING(sc->wmi_dev,
527 ACPI_EEEPC_WMI_EVENT_GUID))
528 sc->notify_guid = ACPI_EEEPC_WMI_EVENT_GUID;
529 else
530 sc->notify_guid = NULL;
531 if (sc->notify_guid != NULL) {
532 if (ACPI_WMI_INSTALL_EVENT_HANDLER(sc->wmi_dev,
533 sc->notify_guid, acpi_asus_wmi_notify, dev))
534 sc->notify_guid = NULL;
535 }
536 if (sc->notify_guid == NULL)
537 device_printf(dev, "Could not install event handler!\n");
538
539 /* Initialize. */
540 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
541 ASUS_WMI_METHODID_INIT, 0, 0, 0, &val) && bootverbose)
542 device_printf(dev, "Initialization: %#x\n", val);
543 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
544 ASUS_WMI_METHODID_SPEC, 0, 0x9, 0, &val) && bootverbose)
545 device_printf(dev, "WMI BIOS version: %d.%d\n",
546 val >> 16, val & 0xFF);
547 if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev,
548 ASUS_WMI_METHODID_SFUN, 0, 0, 0, &val) && bootverbose)
549 device_printf(dev, "SFUN value: %#x\n", val);
550
551 ACPI_SERIAL_BEGIN(asus_wmi);
552
553 sc->sysctl_ctx = device_get_sysctl_ctx(dev);
554 sc->sysctl_tree = device_get_sysctl_tree(dev);
555 SYSCTL_ADD_INT(sc->sysctl_ctx,
556 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
557 "handle_keys", CTLFLAG_RW, &sc->handle_keys,
558 0, "Handle some hardware keys inside the driver");
559 for (i = 0; acpi_asus_wmi_sysctls[i].name != NULL; ++i) {
560 dev_id = acpi_asus_wmi_sysctls[i].dev_id;
561 if (acpi_wpi_asus_get_devstate(sc, dev_id, &val))
562 continue;
563 switch (dev_id) {
564 case ASUS_WMI_DEVID_THERMAL_CTRL:
565 case ASUS_WMI_DEVID_PROCESSOR_STATE:
566 case ASUS_WMI_DEVID_FAN_CTRL:
567 case ASUS_WMI_DEVID_BRIGHTNESS:
568 if (val == 0)
569 continue;
570 break;
571 case ASUS_WMI_DEVID_KBD_BACKLIGHT:
572 sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
573 have_kbd_bkl = true;
574 /* FALLTHROUGH */
575 default:
576 if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0)
577 continue;
578 break;
579 }
580
581 if (acpi_asus_wmi_sysctls[i].flag_rdonly != 0) {
582 SYSCTL_ADD_PROC(sc->sysctl_ctx,
583 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
584 acpi_asus_wmi_sysctls[i].name,
585 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
586 sc, i, acpi_asus_wmi_sysctl, "I",
587 acpi_asus_wmi_sysctls[i].description);
588 } else {
589 SYSCTL_ADD_PROC(sc->sysctl_ctx,
590 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO,
591 acpi_asus_wmi_sysctls[i].name,
592 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
593 sc, i, acpi_asus_wmi_sysctl, "I",
594 acpi_asus_wmi_sysctls[i].description);
595 }
596 }
597 ACPI_SERIAL_END(asus_wmi);
598
599 /* Detect and flush event queue */
600 if (sc->dsts_id == ASUS_WMI_METHODID_DSTS2) {
601 for (i = 0; i <= ASUS_WMI_EVENT_QUEUE_SIZE; i++) {
602 if (acpi_asus_wmi_get_event_code(sc->wmi_dev,
603 ASUS_WMI_EVENT_VALUE_ATK, &code) != 0) {
604 device_printf(dev,
605 "Can not flush event queue\n");
606 break;
607 }
608 if (code == ASUS_WMI_EVENT_QUEUE_END ||
609 code == ASUS_WMI_EVENT_MASK) {
610 sc->event_queue = true;
611 break;
612 }
613 }
614 }
615
616 #ifdef EVDEV_SUPPORT
617 if (sc->notify_guid != NULL) {
618 sc->evdev = evdev_alloc();
619 evdev_set_name(sc->evdev, device_get_desc(dev));
620 evdev_set_phys(sc->evdev, device_get_nameunit(dev));
621 evdev_set_id(sc->evdev, BUS_HOST, 0, 0, 1);
622 evdev_support_event(sc->evdev, EV_SYN);
623 evdev_support_event(sc->evdev, EV_KEY);
624 for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) {
625 if (acpi_asus_wmi_evdev_map[i].key != NO_KEY)
626 evdev_support_key(sc->evdev,
627 acpi_asus_wmi_evdev_map[i].key);
628 }
629
630 if (evdev_register(sc->evdev) != 0) {
631 device_printf(dev, "Can not register evdev\n");
632 acpi_asus_wmi_detach(dev);
633 return (ENXIO);
634 }
635 }
636 #endif
637
638 if (have_kbd_bkl) {
639 sc->kbd_bkl = backlight_register("acpi_asus_wmi", dev);
640 if (sc->kbd_bkl == NULL) {
641 device_printf(dev, "Can not register backlight\n");
642 acpi_asus_wmi_detach(dev);
643 return (ENXIO);
644 }
645 }
646
647 return (0);
648 }
649
650 static int
acpi_asus_wmi_detach(device_t dev)651 acpi_asus_wmi_detach(device_t dev)
652 {
653 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
654
655 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
656
657 if (sc->kbd_bkl != NULL)
658 backlight_destroy(sc->kbd_bkl);
659
660 if (sc->notify_guid) {
661 ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid);
662 #ifdef EVDEV_SUPPORT
663 evdev_free(sc->evdev);
664 #endif
665 }
666
667 return (0);
668 }
669
670 static int
acpi_asus_wmi_suspend(device_t dev)671 acpi_asus_wmi_suspend(device_t dev)
672 {
673 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
674
675 if (sc->kbd_bkl != NULL) {
676 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
677 acpi_wpi_asus_set_devstate(sc,
678 ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, NULL);
679 }
680
681 return (0);
682 }
683
684 static int
acpi_asus_wmi_resume(device_t dev)685 acpi_asus_wmi_resume(device_t dev)
686 {
687 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
688
689 if (sc->kbd_bkl != NULL) {
690 ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
691 acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
692 kbd_bkl_level_to_devstate(sc->kbd_bkl_level), NULL);
693 }
694
695 return (0);
696 }
697
698 static int
acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)699 acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)
700 {
701 struct acpi_asus_wmi_softc *sc;
702 int arg;
703 int oldarg;
704 int error = 0;
705 int function;
706 int dev_id;
707
708 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
709
710 sc = (struct acpi_asus_wmi_softc *)oidp->oid_arg1;
711 function = oidp->oid_arg2;
712 dev_id = acpi_asus_wmi_sysctls[function].dev_id;
713
714 ACPI_SERIAL_BEGIN(asus_wmi);
715 arg = acpi_asus_wmi_sysctl_get(sc, dev_id);
716 oldarg = arg;
717 error = sysctl_handle_int(oidp, &arg, 0, req);
718 if (!error && req->newptr != NULL)
719 error = acpi_asus_wmi_sysctl_set(sc, dev_id, arg, oldarg);
720 ACPI_SERIAL_END(asus_wmi);
721
722 return (error);
723 }
724
725 static int
acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc * sc,int dev_id)726 acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id)
727 {
728 UINT32 val = 0;
729
730 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
731 ACPI_SERIAL_ASSERT(asus_wmi);
732
733 switch(dev_id) {
734 case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY:
735 return (sc->ttp_mode);
736 default:
737 break;
738 }
739
740 acpi_wpi_asus_get_devstate(sc, dev_id, &val);
741
742 switch(dev_id) {
743 case ASUS_WMI_DEVID_THERMAL_CTRL:
744 val = (val - 2731 + 5) / 10;
745 break;
746 case ASUS_WMI_DEVID_PROCESSOR_STATE:
747 case ASUS_WMI_DEVID_FAN_CTRL:
748 break;
749 case ASUS_WMI_DEVID_BRIGHTNESS:
750 val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK;
751 break;
752 case ASUS_WMI_DEVID_KBD_BACKLIGHT:
753 val &= 0x3;
754 break;
755 default:
756 if (val & ASUS_WMI_DSTS_UNKNOWN_BIT)
757 val = -1;
758 else
759 val = !!(val & ASUS_WMI_DSTS_STATUS_BIT);
760 break;
761 }
762
763 return (val);
764 }
765
766 static int
acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc * sc,int dev_id,int arg,int oldarg)767 acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg)
768 {
769 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
770 ACPI_SERIAL_ASSERT(asus_wmi);
771
772 switch(dev_id) {
773 case ASUS_WMI_DEVID_KBD_BACKLIGHT:
774 arg = min(0x3, arg);
775 if (arg != 0)
776 arg |= 0x80;
777 break;
778 case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY:
779 arg = min(0x2, arg);
780 sc->ttp_mode = arg;
781 break;
782 }
783
784 acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL);
785
786 return (0);
787 }
788
789 static __inline void
acpi_asus_wmi_free_buffer(ACPI_BUFFER * buf)790 acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) {
791 if (buf && buf->Pointer) {
792 AcpiOsFree(buf->Pointer);
793 }
794 }
795
796 static int
acpi_asus_wmi_get_event_code(device_t wmi_dev,UINT32 notify,int * code)797 acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify, int *code)
798 {
799 ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL };
800 ACPI_OBJECT *obj;
801 int error = 0;
802
803 if (ACPI_FAILURE(ACPI_WMI_GET_EVENT_DATA(wmi_dev, notify, &response)))
804 return (EIO);
805 obj = (ACPI_OBJECT*) response.Pointer;
806 if (obj && obj->Type == ACPI_TYPE_INTEGER)
807 *code = obj->Integer.Value & ASUS_WMI_EVENT_MASK;
808 else
809 error = EINVAL;
810 acpi_asus_wmi_free_buffer(&response);
811 return (error);
812 }
813
814 #ifdef EVDEV_SUPPORT
815 static void
acpi_asus_wmi_push_evdev_event(struct evdev_dev * evdev,UINT32 notify)816 acpi_asus_wmi_push_evdev_event(struct evdev_dev *evdev, UINT32 notify)
817 {
818 int i;
819 uint16_t key;
820
821 for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) {
822 if (acpi_asus_wmi_evdev_map[i].notify == notify &&
823 acpi_asus_wmi_evdev_map[i].key != NO_KEY) {
824 key = acpi_asus_wmi_evdev_map[i].key;
825 evdev_push_key(evdev, key, 1);
826 evdev_sync(evdev);
827 evdev_push_key(evdev, key, 0);
828 evdev_sync(evdev);
829 break;
830 }
831 }
832 }
833 #endif
834
835 static void
acpi_asus_wmi_handle_event(struct acpi_asus_wmi_softc * sc,int code)836 acpi_asus_wmi_handle_event(struct acpi_asus_wmi_softc *sc, int code)
837 {
838 UINT32 val;
839
840 if (code != 0) {
841 acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT,
842 code);
843 #ifdef EVDEV_SUPPORT
844 acpi_asus_wmi_push_evdev_event(sc->evdev, code);
845 #endif
846 }
847 if (code && sc->handle_keys) {
848 /* Keyboard backlight control. */
849 if (code == 0xc4 || code == 0xc5) {
850 acpi_wpi_asus_get_devstate(sc,
851 ASUS_WMI_DEVID_KBD_BACKLIGHT, &val);
852 val &= 0x3;
853 if (code == 0xc4) {
854 if (val < 0x3)
855 val++;
856 } else if (val > 0)
857 val--;
858 if (val != 0)
859 val |= 0x80;
860 acpi_wpi_asus_set_devstate(sc,
861 ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL);
862 sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
863 }
864 /* Touchpad control. */
865 if (code == 0x6b) {
866 acpi_wpi_asus_get_devstate(sc,
867 ASUS_WMI_DEVID_TOUCHPAD, &val);
868 val = !(val & 1);
869 acpi_wpi_asus_set_devstate(sc,
870 ASUS_WMI_DEVID_TOUCHPAD, val, NULL);
871 }
872 /* Throttle thermal policy control. */
873 if (code == 0xae) {
874 sc->ttp_mode++;
875 if (sc->ttp_mode > 2)
876 sc->ttp_mode = 0;
877 acpi_wpi_asus_set_devstate(sc,
878 ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
879 sc->ttp_mode, NULL);
880 }
881 /* TUF laptop RGB mode control. */
882 if (code == 0xb3) {
883 const uint32_t cmd = 0xb4; /* Save to BIOS */
884 const uint32_t r = 0xff, g = 0xff, b = 0xff;
885 const uint32_t speed = 0xeb; /* Medium */
886 if (sc->tuf_rgb_mode < 2)
887 sc->tuf_rgb_mode++;
888 else if (sc->tuf_rgb_mode == 2)
889 sc->tuf_rgb_mode = 10;
890 else sc->tuf_rgb_mode = 0;
891 acpi_asus_wmi_evaluate_method(sc->wmi_dev,
892 ASUS_WMI_METHODID_DEVS,
893 ASUS_WMI_DEVID_TUF_RGB_MODE,
894 cmd | (sc->tuf_rgb_mode << 8) | (r << 16) | (g << 24),
895 b | (speed << 8), NULL);
896 }
897 }
898 }
899
900 static void
acpi_asus_wmi_notify(ACPI_HANDLE h,UINT32 notify,void * context)901 acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
902 {
903 device_t dev = context;
904 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
905 int code = 0, i = 1;
906
907 ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
908
909 if (sc->event_queue)
910 i += ASUS_WMI_EVENT_QUEUE_SIZE;
911 do {
912 if (acpi_asus_wmi_get_event_code(sc->wmi_dev, notify, &code)
913 != 0) {
914 device_printf(dev, "Failed to get event code\n");
915 return;
916 }
917 if (code == ASUS_WMI_EVENT_QUEUE_END ||
918 code == ASUS_WMI_EVENT_MASK)
919 return;
920 acpi_asus_wmi_handle_event(sc, code);
921 if (notify != ASUS_WMI_EVENT_VALUE_ATK)
922 return;
923 } while (--i != 0);
924 if (sc->event_queue)
925 device_printf(dev, "Can not read event queue, "
926 "last code: 0x%x\n", code);
927 }
928
929 static int
acpi_asus_wmi_evaluate_method(device_t wmi_dev,int method,UINT32 arg0,UINT32 arg1,UINT32 arg2,UINT32 * retval)930 acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method,
931 UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval)
932 {
933 UINT32 params[3] = { arg0, arg1, arg2 };
934 UINT32 result;
935 ACPI_OBJECT *obj;
936 ACPI_BUFFER in = { sizeof(params), ¶ms };
937 ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL };
938
939 if (ACPI_FAILURE(ACPI_WMI_EVALUATE_CALL(wmi_dev,
940 ACPI_ASUS_WMI_MGMT_GUID, 1, method, &in, &out))) {
941 acpi_asus_wmi_free_buffer(&out);
942 return (-EINVAL);
943 }
944 obj = out.Pointer;
945 if (obj && obj->Type == ACPI_TYPE_INTEGER)
946 result = (UINT32) obj->Integer.Value;
947 else
948 result = 0;
949 acpi_asus_wmi_free_buffer(&out);
950 if (retval)
951 *retval = result;
952 return (result == ASUS_WMI_UNSUPPORTED_METHOD ? -ENODEV : 0);
953 }
954
955 static int
acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 * retval)956 acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
957 UINT32 dev_id, UINT32 *retval)
958 {
959
960 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
961 sc->dsts_id, dev_id, 0, 0, retval));
962 }
963
964 static int
acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc * sc,UINT32 dev_id,UINT32 ctrl_param,UINT32 * retval)965 acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
966 UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval)
967 {
968
969 return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
970 ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, 0, retval));
971 }
972
973 static int
acpi_asus_wmi_backlight_update_status(device_t dev,struct backlight_props * props)974 acpi_asus_wmi_backlight_update_status(device_t dev, struct backlight_props
975 *props)
976 {
977 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
978
979 acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
980 kbd_bkl_level_to_devstate(props->brightness), NULL);
981 sc->kbd_bkl_level = props->brightness;
982
983 return (0);
984 }
985
986 static int
acpi_asus_wmi_backlight_get_status(device_t dev,struct backlight_props * props)987 acpi_asus_wmi_backlight_get_status(device_t dev, struct backlight_props *props)
988 {
989 struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
990
991 props->brightness = sc->kbd_bkl_level;
992 props->nlevels = nitems(acpi_asus_wmi_backlight_levels);
993 memcpy(props->levels, acpi_asus_wmi_backlight_levels,
994 sizeof(acpi_asus_wmi_backlight_levels));
995
996 return (0);
997 }
998
999 static int
acpi_asus_wmi_backlight_get_info(device_t dev,struct backlight_info * info)1000 acpi_asus_wmi_backlight_get_info(device_t dev, struct backlight_info *info)
1001 {
1002 info->type = BACKLIGHT_TYPE_KEYBOARD;
1003 strlcpy(info->name, "ASUS Keyboard", BACKLIGHTMAXNAMELENGTH);
1004
1005 return (0);
1006 }
1007