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