1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Asus Notebooks WMI hotkey driver |
4 | * |
5 | * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com> |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/init.h> |
13 | #include <linux/input.h> |
14 | #include <linux/input/sparse-keymap.h> |
15 | #include <linux/fb.h> |
16 | #include <linux/dmi.h> |
17 | #include <linux/i8042.h> |
18 | |
19 | #include <acpi/video.h> |
20 | |
21 | #include "asus-wmi.h" |
22 | |
23 | #define ASUS_NB_WMI_FILE "asus-nb-wmi" |
24 | |
25 | MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>" ); |
26 | MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver" ); |
27 | MODULE_LICENSE("GPL" ); |
28 | |
29 | #define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" |
30 | |
31 | MODULE_ALIAS("wmi:" ASUS_NB_WMI_EVENT_GUID); |
32 | |
33 | /* |
34 | * WAPF defines the behavior of the Fn+Fx wlan key |
35 | * The significance of values is yet to be found, but |
36 | * most of the time: |
37 | * Bit | Bluetooth | WLAN |
38 | * 0 | Hardware | Hardware |
39 | * 1 | Hardware | Software |
40 | * 4 | Software | Software |
41 | */ |
42 | static int wapf = -1; |
43 | module_param(wapf, uint, 0444); |
44 | MODULE_PARM_DESC(wapf, "WAPF value" ); |
45 | |
46 | static int tablet_mode_sw = -1; |
47 | module_param(tablet_mode_sw, uint, 0444); |
48 | MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip 3:lid-flip-rog" ); |
49 | |
50 | static struct quirk_entry *quirks; |
51 | |
52 | static bool asus_q500a_i8042_filter(unsigned char data, unsigned char str, |
53 | struct serio *port) |
54 | { |
55 | static bool extended; |
56 | bool ret = false; |
57 | |
58 | if (str & I8042_STR_AUXDATA) |
59 | return false; |
60 | |
61 | if (unlikely(data == 0xe1)) { |
62 | extended = true; |
63 | ret = true; |
64 | } else if (unlikely(extended)) { |
65 | extended = false; |
66 | ret = true; |
67 | } |
68 | |
69 | return ret; |
70 | } |
71 | |
72 | static struct quirk_entry quirk_asus_unknown = { |
73 | .wapf = 0, |
74 | .wmi_backlight_set_devstate = true, |
75 | }; |
76 | |
77 | static struct quirk_entry quirk_asus_q500a = { |
78 | .i8042_filter = asus_q500a_i8042_filter, |
79 | .wmi_backlight_set_devstate = true, |
80 | }; |
81 | |
82 | /* |
83 | * For those machines that need software to control bt/wifi status |
84 | * and have duplicate events(ACPI and WMI) for display toggle |
85 | */ |
86 | static struct quirk_entry quirk_asus_x55u = { |
87 | .wapf = 4, |
88 | .wmi_backlight_set_devstate = true, |
89 | .no_display_toggle = true, |
90 | }; |
91 | |
92 | static struct quirk_entry quirk_asus_wapf4 = { |
93 | .wapf = 4, |
94 | .wmi_backlight_set_devstate = true, |
95 | }; |
96 | |
97 | static struct quirk_entry quirk_asus_x200ca = { |
98 | .wapf = 2, |
99 | .wmi_backlight_set_devstate = true, |
100 | }; |
101 | |
102 | static struct quirk_entry quirk_asus_x550lb = { |
103 | .wmi_backlight_set_devstate = true, |
104 | .xusb2pr = 0x01D9, |
105 | }; |
106 | |
107 | static struct quirk_entry quirk_asus_forceals = { |
108 | .wmi_backlight_set_devstate = true, |
109 | .wmi_force_als_set = true, |
110 | }; |
111 | |
112 | static struct quirk_entry quirk_asus_use_kbd_dock_devid = { |
113 | .tablet_switch_mode = asus_wmi_kbd_dock_devid, |
114 | }; |
115 | |
116 | static struct quirk_entry quirk_asus_use_lid_flip_devid = { |
117 | .wmi_backlight_set_devstate = true, |
118 | .tablet_switch_mode = asus_wmi_lid_flip_devid, |
119 | }; |
120 | |
121 | static struct quirk_entry quirk_asus_tablet_mode = { |
122 | .wmi_backlight_set_devstate = true, |
123 | .tablet_switch_mode = asus_wmi_lid_flip_rog_devid, |
124 | }; |
125 | |
126 | static struct quirk_entry quirk_asus_ignore_fan = { |
127 | .wmi_ignore_fan = true, |
128 | }; |
129 | |
130 | static int dmi_matched(const struct dmi_system_id *dmi) |
131 | { |
132 | pr_info("Identified laptop model '%s'\n" , dmi->ident); |
133 | quirks = dmi->driver_data; |
134 | return 1; |
135 | } |
136 | |
137 | static const struct dmi_system_id asus_quirks[] = { |
138 | { |
139 | .callback = dmi_matched, |
140 | .ident = "ASUSTeK COMPUTER INC. Q500A" , |
141 | .matches = { |
142 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
143 | DMI_MATCH(DMI_PRODUCT_NAME, "Q500A" ), |
144 | }, |
145 | .driver_data = &quirk_asus_q500a, |
146 | }, |
147 | { |
148 | .callback = dmi_matched, |
149 | .ident = "ASUSTeK COMPUTER INC. U32U" , |
150 | .matches = { |
151 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc." ), |
152 | DMI_MATCH(DMI_PRODUCT_NAME, "U32U" ), |
153 | }, |
154 | .driver_data = &quirk_asus_wapf4, |
155 | }, |
156 | { |
157 | .callback = dmi_matched, |
158 | .ident = "ASUSTeK COMPUTER INC. X302UA" , |
159 | .matches = { |
160 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
161 | DMI_MATCH(DMI_PRODUCT_NAME, "X302UA" ), |
162 | }, |
163 | .driver_data = &quirk_asus_wapf4, |
164 | }, |
165 | { |
166 | .callback = dmi_matched, |
167 | .ident = "ASUSTeK COMPUTER INC. X401U" , |
168 | .matches = { |
169 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
170 | DMI_MATCH(DMI_PRODUCT_NAME, "X401U" ), |
171 | }, |
172 | .driver_data = &quirk_asus_x55u, |
173 | }, |
174 | { |
175 | .callback = dmi_matched, |
176 | .ident = "ASUSTeK COMPUTER INC. X401A" , |
177 | .matches = { |
178 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
179 | DMI_MATCH(DMI_PRODUCT_NAME, "X401A" ), |
180 | }, |
181 | .driver_data = &quirk_asus_wapf4, |
182 | }, |
183 | { |
184 | .callback = dmi_matched, |
185 | .ident = "ASUSTeK COMPUTER INC. X401A1" , |
186 | .matches = { |
187 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
188 | DMI_MATCH(DMI_PRODUCT_NAME, "X401A1" ), |
189 | }, |
190 | .driver_data = &quirk_asus_wapf4, |
191 | }, |
192 | { |
193 | .callback = dmi_matched, |
194 | .ident = "ASUSTeK COMPUTER INC. X45U" , |
195 | .matches = { |
196 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
197 | DMI_MATCH(DMI_PRODUCT_NAME, "X45U" ), |
198 | }, |
199 | .driver_data = &quirk_asus_wapf4, |
200 | }, |
201 | { |
202 | .callback = dmi_matched, |
203 | .ident = "ASUSTeK COMPUTER INC. X456UA" , |
204 | .matches = { |
205 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
206 | DMI_MATCH(DMI_PRODUCT_NAME, "X456UA" ), |
207 | }, |
208 | .driver_data = &quirk_asus_wapf4, |
209 | }, |
210 | { |
211 | .callback = dmi_matched, |
212 | .ident = "ASUSTeK COMPUTER INC. X456UF" , |
213 | .matches = { |
214 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
215 | DMI_MATCH(DMI_PRODUCT_NAME, "X456UF" ), |
216 | }, |
217 | .driver_data = &quirk_asus_wapf4, |
218 | }, |
219 | { |
220 | .callback = dmi_matched, |
221 | .ident = "ASUSTeK COMPUTER INC. X501U" , |
222 | .matches = { |
223 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
224 | DMI_MATCH(DMI_PRODUCT_NAME, "X501U" ), |
225 | }, |
226 | .driver_data = &quirk_asus_x55u, |
227 | }, |
228 | { |
229 | .callback = dmi_matched, |
230 | .ident = "ASUSTeK COMPUTER INC. X501A" , |
231 | .matches = { |
232 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
233 | DMI_MATCH(DMI_PRODUCT_NAME, "X501A" ), |
234 | }, |
235 | .driver_data = &quirk_asus_wapf4, |
236 | }, |
237 | { |
238 | .callback = dmi_matched, |
239 | .ident = "ASUSTeK COMPUTER INC. X501A1" , |
240 | .matches = { |
241 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
242 | DMI_MATCH(DMI_PRODUCT_NAME, "X501A1" ), |
243 | }, |
244 | .driver_data = &quirk_asus_wapf4, |
245 | }, |
246 | { |
247 | .callback = dmi_matched, |
248 | .ident = "ASUSTeK COMPUTER INC. X550CA" , |
249 | .matches = { |
250 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
251 | DMI_MATCH(DMI_PRODUCT_NAME, "X550CA" ), |
252 | }, |
253 | .driver_data = &quirk_asus_wapf4, |
254 | }, |
255 | { |
256 | .callback = dmi_matched, |
257 | .ident = "ASUSTeK COMPUTER INC. X550CC" , |
258 | .matches = { |
259 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
260 | DMI_MATCH(DMI_PRODUCT_NAME, "X550CC" ), |
261 | }, |
262 | .driver_data = &quirk_asus_wapf4, |
263 | }, |
264 | { |
265 | .callback = dmi_matched, |
266 | .ident = "ASUSTeK COMPUTER INC. X550CL" , |
267 | .matches = { |
268 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
269 | DMI_MATCH(DMI_PRODUCT_NAME, "X550CL" ), |
270 | }, |
271 | .driver_data = &quirk_asus_wapf4, |
272 | }, |
273 | { |
274 | .callback = dmi_matched, |
275 | .ident = "ASUSTeK COMPUTER INC. X550VB" , |
276 | .matches = { |
277 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
278 | DMI_MATCH(DMI_PRODUCT_NAME, "X550VB" ), |
279 | }, |
280 | .driver_data = &quirk_asus_wapf4, |
281 | }, |
282 | { |
283 | .callback = dmi_matched, |
284 | .ident = "ASUSTeK COMPUTER INC. X551CA" , |
285 | .matches = { |
286 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
287 | DMI_MATCH(DMI_PRODUCT_NAME, "X551CA" ), |
288 | }, |
289 | .driver_data = &quirk_asus_wapf4, |
290 | }, |
291 | { |
292 | .callback = dmi_matched, |
293 | .ident = "ASUSTeK COMPUTER INC. X55A" , |
294 | .matches = { |
295 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
296 | DMI_MATCH(DMI_PRODUCT_NAME, "X55A" ), |
297 | }, |
298 | .driver_data = &quirk_asus_wapf4, |
299 | }, |
300 | { |
301 | .callback = dmi_matched, |
302 | .ident = "ASUSTeK COMPUTER INC. X55C" , |
303 | .matches = { |
304 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
305 | DMI_MATCH(DMI_PRODUCT_NAME, "X55C" ), |
306 | }, |
307 | .driver_data = &quirk_asus_wapf4, |
308 | }, |
309 | { |
310 | .callback = dmi_matched, |
311 | .ident = "ASUSTeK COMPUTER INC. X55U" , |
312 | .matches = { |
313 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
314 | DMI_MATCH(DMI_PRODUCT_NAME, "X55U" ), |
315 | }, |
316 | .driver_data = &quirk_asus_x55u, |
317 | }, |
318 | { |
319 | .callback = dmi_matched, |
320 | .ident = "ASUSTeK COMPUTER INC. X55VD" , |
321 | .matches = { |
322 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
323 | DMI_MATCH(DMI_PRODUCT_NAME, "X55VD" ), |
324 | }, |
325 | .driver_data = &quirk_asus_wapf4, |
326 | }, |
327 | { |
328 | .callback = dmi_matched, |
329 | .ident = "ASUSTeK COMPUTER INC. X75A" , |
330 | .matches = { |
331 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
332 | DMI_MATCH(DMI_PRODUCT_NAME, "X75A" ), |
333 | }, |
334 | .driver_data = &quirk_asus_wapf4, |
335 | }, |
336 | { |
337 | .callback = dmi_matched, |
338 | .ident = "ASUSTeK COMPUTER INC. X75VBP" , |
339 | .matches = { |
340 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
341 | DMI_MATCH(DMI_PRODUCT_NAME, "X75VBP" ), |
342 | }, |
343 | .driver_data = &quirk_asus_wapf4, |
344 | }, |
345 | { |
346 | .callback = dmi_matched, |
347 | .ident = "ASUSTeK COMPUTER INC. X75VD" , |
348 | .matches = { |
349 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
350 | DMI_MATCH(DMI_PRODUCT_NAME, "X75VD" ), |
351 | }, |
352 | .driver_data = &quirk_asus_wapf4, |
353 | }, |
354 | { |
355 | .callback = dmi_matched, |
356 | .ident = "ASUSTeK COMPUTER INC. 1015E" , |
357 | .matches = { |
358 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
359 | DMI_MATCH(DMI_PRODUCT_NAME, "1015E" ), |
360 | }, |
361 | .driver_data = &quirk_asus_wapf4, |
362 | }, |
363 | { |
364 | .callback = dmi_matched, |
365 | .ident = "ASUSTeK COMPUTER INC. 1015U" , |
366 | .matches = { |
367 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
368 | DMI_MATCH(DMI_PRODUCT_NAME, "1015U" ), |
369 | }, |
370 | .driver_data = &quirk_asus_wapf4, |
371 | }, |
372 | { |
373 | .callback = dmi_matched, |
374 | .ident = "ASUSTeK COMPUTER INC. X200CA" , |
375 | .matches = { |
376 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
377 | DMI_MATCH(DMI_PRODUCT_NAME, "X200CA" ), |
378 | }, |
379 | .driver_data = &quirk_asus_x200ca, |
380 | }, |
381 | { |
382 | .callback = dmi_matched, |
383 | .ident = "ASUSTeK COMPUTER INC. UX330UAK" , |
384 | .matches = { |
385 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
386 | DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK" ), |
387 | }, |
388 | .driver_data = &quirk_asus_forceals, |
389 | }, |
390 | { |
391 | .callback = dmi_matched, |
392 | .ident = "ASUSTeK COMPUTER INC. X550LB" , |
393 | .matches = { |
394 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
395 | DMI_MATCH(DMI_PRODUCT_NAME, "X550LB" ), |
396 | }, |
397 | .driver_data = &quirk_asus_x550lb, |
398 | }, |
399 | { |
400 | .callback = dmi_matched, |
401 | .ident = "ASUSTeK COMPUTER INC. UX430UQ" , |
402 | .matches = { |
403 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
404 | DMI_MATCH(DMI_PRODUCT_NAME, "UX430UQ" ), |
405 | }, |
406 | .driver_data = &quirk_asus_forceals, |
407 | }, |
408 | { |
409 | .callback = dmi_matched, |
410 | .ident = "ASUSTeK COMPUTER INC. UX430UNR" , |
411 | .matches = { |
412 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
413 | DMI_MATCH(DMI_PRODUCT_NAME, "UX430UNR" ), |
414 | }, |
415 | .driver_data = &quirk_asus_forceals, |
416 | }, |
417 | { |
418 | .callback = dmi_matched, |
419 | .ident = "Asus Transformer T100TA / T100HA / T100CHI" , |
420 | .matches = { |
421 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
422 | /* Match *T100* */ |
423 | DMI_MATCH(DMI_PRODUCT_NAME, "T100" ), |
424 | }, |
425 | .driver_data = &quirk_asus_use_kbd_dock_devid, |
426 | }, |
427 | { |
428 | .callback = dmi_matched, |
429 | .ident = "Asus Transformer T101HA" , |
430 | .matches = { |
431 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
432 | DMI_MATCH(DMI_PRODUCT_NAME, "T101HA" ), |
433 | }, |
434 | .driver_data = &quirk_asus_use_kbd_dock_devid, |
435 | }, |
436 | { |
437 | .callback = dmi_matched, |
438 | .ident = "Asus Transformer T200TA" , |
439 | .matches = { |
440 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
441 | DMI_MATCH(DMI_PRODUCT_NAME, "T200TA" ), |
442 | }, |
443 | .driver_data = &quirk_asus_use_kbd_dock_devid, |
444 | }, |
445 | { |
446 | .callback = dmi_matched, |
447 | .ident = "ASUS ZenBook Flip UX360" , |
448 | .matches = { |
449 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
450 | /* Match UX360* */ |
451 | DMI_MATCH(DMI_PRODUCT_NAME, "UX360" ), |
452 | }, |
453 | .driver_data = &quirk_asus_use_lid_flip_devid, |
454 | }, |
455 | { |
456 | .callback = dmi_matched, |
457 | .ident = "ASUS TP200s / E205SA" , |
458 | .matches = { |
459 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
460 | DMI_MATCH(DMI_PRODUCT_NAME, "E205SA" ), |
461 | }, |
462 | .driver_data = &quirk_asus_use_lid_flip_devid, |
463 | }, |
464 | { |
465 | .callback = dmi_matched, |
466 | .ident = "ASUS ROG FLOW X13" , |
467 | .matches = { |
468 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
469 | /* Match GV301** */ |
470 | DMI_MATCH(DMI_PRODUCT_NAME, "GV301" ), |
471 | }, |
472 | .driver_data = &quirk_asus_tablet_mode, |
473 | }, |
474 | { |
475 | .callback = dmi_matched, |
476 | .ident = "ASUS ROG FLOW X16" , |
477 | .matches = { |
478 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
479 | DMI_MATCH(DMI_PRODUCT_NAME, "GV601R" ), |
480 | }, |
481 | .driver_data = &quirk_asus_tablet_mode, |
482 | }, |
483 | { |
484 | .callback = dmi_matched, |
485 | .ident = "ASUS ROG FLOW X16" , |
486 | .matches = { |
487 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
488 | DMI_MATCH(DMI_PRODUCT_NAME, "GV601V" ), |
489 | }, |
490 | .driver_data = &quirk_asus_tablet_mode, |
491 | }, |
492 | { |
493 | .callback = dmi_matched, |
494 | .ident = "ASUS VivoBook E410MA" , |
495 | .matches = { |
496 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC." ), |
497 | DMI_MATCH(DMI_PRODUCT_NAME, "E410MA" ), |
498 | }, |
499 | .driver_data = &quirk_asus_ignore_fan, |
500 | }, |
501 | {}, |
502 | }; |
503 | |
504 | static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) |
505 | { |
506 | int ret; |
507 | |
508 | quirks = &quirk_asus_unknown; |
509 | dmi_check_system(list: asus_quirks); |
510 | |
511 | driver->quirks = quirks; |
512 | driver->panel_power = FB_BLANK_UNBLANK; |
513 | |
514 | /* overwrite the wapf setting if the wapf paramater is specified */ |
515 | if (wapf != -1) |
516 | quirks->wapf = wapf; |
517 | else |
518 | wapf = quirks->wapf; |
519 | |
520 | if (tablet_mode_sw != -1) |
521 | quirks->tablet_switch_mode = tablet_mode_sw; |
522 | |
523 | if (quirks->i8042_filter) { |
524 | ret = i8042_install_filter(filter: quirks->i8042_filter); |
525 | if (ret) { |
526 | pr_warn("Unable to install key filter\n" ); |
527 | return; |
528 | } |
529 | pr_info("Using i8042 filter function for receiving events\n" ); |
530 | } |
531 | } |
532 | |
533 | static const struct key_entry asus_nb_wmi_keymap[] = { |
534 | { KE_KEY, ASUS_WMI_BRN_DOWN, { KEY_BRIGHTNESSDOWN } }, |
535 | { KE_KEY, ASUS_WMI_BRN_UP, { KEY_BRIGHTNESSUP } }, |
536 | { KE_KEY, 0x2a, { KEY_SELECTIVE_SCREENSHOT } }, |
537 | { KE_IGNORE, 0x2b, }, /* PrintScreen (also send via PS/2) on newer models */ |
538 | { KE_IGNORE, 0x2c, }, /* CapsLock (also send via PS/2) on newer models */ |
539 | { KE_KEY, 0x30, { KEY_VOLUMEUP } }, |
540 | { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, |
541 | { KE_KEY, 0x32, { KEY_MUTE } }, |
542 | { KE_KEY, 0x33, { KEY_SCREENLOCK } }, |
543 | { KE_KEY, 0x35, { KEY_SCREENLOCK } }, |
544 | { KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */ |
545 | { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, |
546 | { KE_KEY, 0x41, { KEY_NEXTSONG } }, |
547 | { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */ |
548 | { KE_KEY, 0x45, { KEY_PLAYPAUSE } }, |
549 | { KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */ |
550 | { KE_KEY, 0x50, { KEY_EMAIL } }, |
551 | { KE_KEY, 0x51, { KEY_WWW } }, |
552 | { KE_KEY, 0x55, { KEY_CALC } }, |
553 | { KE_IGNORE, 0x57, }, /* Battery mode */ |
554 | { KE_IGNORE, 0x58, }, /* AC mode */ |
555 | { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ |
556 | { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */ |
557 | { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */ |
558 | { KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */ |
559 | { KE_KEY, 0x60, { KEY_TOUCHPAD_ON } }, |
560 | { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */ |
561 | { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */ |
562 | { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */ |
563 | { KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */ |
564 | { KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */ |
565 | { KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */ |
566 | { KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */ |
567 | { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, |
568 | { KE_IGNORE, 0x6E, }, /* Low Battery notification */ |
569 | { KE_KEY, 0x71, { KEY_F13 } }, /* General-purpose button */ |
570 | { KE_IGNORE, 0x79, }, /* Charger type dectection notification */ |
571 | { KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */ |
572 | { KE_IGNORE, 0x7B, }, /* Charger connect/disconnect notification */ |
573 | { KE_KEY, 0x7c, { KEY_MICMUTE } }, |
574 | { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ |
575 | { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ |
576 | { KE_KEY, 0x82, { KEY_CAMERA } }, |
577 | { KE_KEY, 0x85, { KEY_CAMERA } }, |
578 | { KE_KEY, 0x86, { KEY_PROG1 } }, /* MyASUS Key */ |
579 | { KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */ |
580 | { KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */ |
581 | { KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */ |
582 | { KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */ |
583 | { KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */ |
584 | { KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */ |
585 | { KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */ |
586 | { KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */ |
587 | { KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */ |
588 | { KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */ |
589 | { KE_KEY, 0x95, { KEY_MEDIA } }, |
590 | { KE_KEY, 0x99, { KEY_PHONE } }, /* Conflicts with fan mode switch */ |
591 | { KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */ |
592 | { KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */ |
593 | { KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */ |
594 | { KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */ |
595 | { KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */ |
596 | { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */ |
597 | { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */ |
598 | { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */ |
599 | { KE_KEY, 0xAE, { KEY_FN_F5 } }, /* Fn+F5 fan mode on 2020+ */ |
600 | { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */ |
601 | { KE_KEY, 0xB5, { KEY_CALC } }, |
602 | { KE_IGNORE, 0xC0, }, /* External display connect/disconnect notification */ |
603 | { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, |
604 | { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, |
605 | { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ |
606 | { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ |
607 | { KE_KEY, 0xBD, { KEY_PROG2 } }, /* Lid flip action on ROG xflow laptops */ |
608 | { KE_END, 0}, |
609 | }; |
610 | |
611 | static void asus_nb_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, |
612 | unsigned int *value, bool *autorelease) |
613 | { |
614 | switch (*code) { |
615 | case ASUS_WMI_BRN_DOWN: |
616 | case ASUS_WMI_BRN_UP: |
617 | if (acpi_video_handles_brightness_key_presses()) |
618 | *code = ASUS_WMI_KEY_IGNORE; |
619 | |
620 | break; |
621 | } |
622 | } |
623 | |
624 | static struct asus_wmi_driver asus_nb_wmi_driver = { |
625 | .name = ASUS_NB_WMI_FILE, |
626 | .owner = THIS_MODULE, |
627 | .event_guid = ASUS_NB_WMI_EVENT_GUID, |
628 | .keymap = asus_nb_wmi_keymap, |
629 | .input_name = "Asus WMI hotkeys" , |
630 | .input_phys = ASUS_NB_WMI_FILE "/input0" , |
631 | .detect_quirks = asus_nb_wmi_quirks, |
632 | .key_filter = asus_nb_wmi_key_filter, |
633 | }; |
634 | |
635 | |
636 | static int __init asus_nb_wmi_init(void) |
637 | { |
638 | return asus_wmi_register_driver(driver: &asus_nb_wmi_driver); |
639 | } |
640 | |
641 | static void __exit asus_nb_wmi_exit(void) |
642 | { |
643 | asus_wmi_unregister_driver(driver: &asus_nb_wmi_driver); |
644 | } |
645 | |
646 | module_init(asus_nb_wmi_init); |
647 | module_exit(asus_nb_wmi_exit); |
648 | |