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