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