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