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