Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: asus: Add support for ASUS N-Key keyboard

The ASUS N-Key keyboard uses the productId of 0x1866 and is used in
almost all modern ASUS gaming laptops with slight changes to the
firmware. This patch enables: Fn+key hotkeys, keyboard backlight
brightness control.

Additionally this keyboard requires the LED interface to be
initialized before such things as keyboard backlight control work.

Signed-off-by: Luke D Jones <luke@ljones.dev>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Luke D Jones and committed by
Jiri Kosina
b92b8024 bf36c6b9

+110 -14
+109 -14
drivers/hid/hid-asus.c
··· 48 48 #define INPUT_REPORT_ID 0x5d 49 49 #define FEATURE_KBD_REPORT_ID 0x5a 50 50 #define FEATURE_KBD_REPORT_SIZE 16 51 + #define FEATURE_KBD_LED_REPORT_ID1 0x5d 52 + #define FEATURE_KBD_LED_REPORT_ID2 0x5e 51 53 52 54 #define SUPPORT_KBD_BACKLIGHT BIT(0) 53 55 ··· 82 80 #define QUIRK_T101HA_DOCK BIT(9) 83 81 #define QUIRK_T90CHI BIT(10) 84 82 #define QUIRK_MEDION_E1239T BIT(11) 83 + #define QUIRK_ROG_NKEY_KEYBOARD BIT(12) 85 84 86 85 #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ 87 86 QUIRK_NO_INIT_REPORTS | \ ··· 335 332 if (drvdata->quirks & QUIRK_MEDION_E1239T) 336 333 return asus_e1239t_event(drvdata, data, size); 337 334 335 + if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { 336 + /* 337 + * Skip these report ID, the device emits a continuous stream associated 338 + * with the AURA mode it is in which looks like an 'echo'. 339 + */ 340 + if (report->id == FEATURE_KBD_LED_REPORT_ID1 || 341 + report->id == FEATURE_KBD_LED_REPORT_ID2) { 342 + return -1; 343 + /* Additional report filtering */ 344 + } else if (report->id == FEATURE_KBD_REPORT_ID) { 345 + /* 346 + * G14 and G15 send these codes on some keypresses with no 347 + * discernable reason for doing so. We'll filter them out to avoid 348 + * unmapped warning messages later. 349 + */ 350 + if (data[1] == 0xea || data[1] == 0xec || data[1] == 0x02 || 351 + data[1] == 0x8a || data[1] == 0x9e) { 352 + return -1; 353 + } 354 + } 355 + } 356 + 338 357 return 0; 339 358 } 340 359 ··· 369 344 if (!dmabuf) 370 345 return -ENOMEM; 371 346 372 - ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, dmabuf, 347 + /* 348 + * The report ID should be set from the incoming buffer due to LED and key 349 + * interfaces having different pages 350 + */ 351 + ret = hid_hw_raw_request(hdev, buf[0], dmabuf, 373 352 buf_size, HID_FEATURE_REPORT, 374 353 HID_REQ_SET_REPORT); 375 354 kfree(dmabuf); ··· 423 394 *kbd_func = readbuf[6]; 424 395 425 396 kfree(readbuf); 397 + return ret; 398 + } 399 + 400 + static int rog_nkey_led_init(struct hid_device *hdev) 401 + { 402 + u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 }; 403 + u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20, 404 + 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; 405 + u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1, 406 + 0x05, 0x20, 0x31, 0x00, 0x08 }; 407 + int ret; 408 + 409 + hid_info(hdev, "Asus initialise N-KEY Device"); 410 + /* The first message is an init start */ 411 + ret = asus_kbd_set_report(hdev, buf_init_start, sizeof(buf_init_start)); 412 + if (ret < 0) { 413 + hid_warn(hdev, "Asus failed to send init start command: %d\n", ret); 414 + return ret; 415 + } 416 + /* Followed by a string */ 417 + ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2)); 418 + if (ret < 0) { 419 + hid_warn(hdev, "Asus failed to send init command 1.0: %d\n", ret); 420 + return ret; 421 + } 422 + /* Followed by a string */ 423 + ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3)); 424 + if (ret < 0) { 425 + hid_warn(hdev, "Asus failed to send init command 1.1: %d\n", ret); 426 + return ret; 427 + } 428 + 429 + /* begin second report ID with same data */ 430 + buf_init2[0] = FEATURE_KBD_LED_REPORT_ID2; 431 + buf_init3[0] = FEATURE_KBD_LED_REPORT_ID2; 432 + 433 + ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2)); 434 + if (ret < 0) { 435 + hid_warn(hdev, "Asus failed to send init command 2.0: %d\n", ret); 436 + return ret; 437 + } 438 + ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3)); 439 + if (ret < 0) 440 + hid_warn(hdev, "Asus failed to send init command 2.1: %d\n", ret); 441 + 426 442 return ret; 427 443 } 428 444 ··· 534 460 unsigned char kbd_func; 535 461 int ret; 536 462 537 - /* Initialize keyboard */ 538 - ret = asus_kbd_init(hdev); 539 - if (ret < 0) 540 - return ret; 463 + if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { 464 + ret = rog_nkey_led_init(hdev); 465 + if (ret < 0) 466 + return ret; 467 + } else { 468 + /* Initialize keyboard */ 469 + ret = asus_kbd_init(hdev); 470 + if (ret < 0) 471 + return ret; 541 472 542 - /* Get keyboard functions */ 543 - ret = asus_kbd_get_functions(hdev, &kbd_func); 544 - if (ret < 0) 545 - return ret; 473 + /* Get keyboard functions */ 474 + ret = asus_kbd_get_functions(hdev, &kbd_func); 475 + if (ret < 0) 476 + return ret; 546 477 547 - /* Check for backlight support */ 548 - if (!(kbd_func & SUPPORT_KBD_BACKLIGHT)) 549 - return -ENODEV; 478 + /* Check for backlight support */ 479 + if (!(kbd_func & SUPPORT_KBD_BACKLIGHT)) 480 + return -ENODEV; 481 + } 550 482 551 483 drvdata->kbd_backlight = devm_kzalloc(&hdev->dev, 552 484 sizeof(struct asus_kbd_leds), ··· 831 751 usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))) 832 752 return -1; 833 753 834 - /* ASUS-specific keyboard hotkeys */ 835 - if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) { 754 + /* ASUS-specific keyboard hotkeys and led backlight */ 755 + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR) { 836 756 switch (usage->hid & HID_USAGE) { 837 757 case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break; 838 758 case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break; ··· 859 779 860 780 /* Fn+F5 "fan" symbol on FX503VD */ 861 781 case 0x99: asus_map_key_clear(KEY_PROG4); break; 782 + 783 + /* Fn+F5 "fan" symbol on N-Key keyboard */ 784 + case 0xae: asus_map_key_clear(KEY_PROG4); break; 785 + 786 + /* Fn+Ret "Calc" symbol on N-Key keyboard */ 787 + case 0x92: asus_map_key_clear(KEY_CALC); break; 788 + 789 + /* Fn+Left Aura mode previous on N-Key keyboard */ 790 + case 0xb2: asus_map_key_clear(KEY_PROG2); break; 791 + 792 + /* Fn+Right Aura mode next on N-Key keyboard */ 793 + case 0xb3: asus_map_key_clear(KEY_PROG3); break; 862 794 863 795 default: 864 796 /* ASUS lazily declares 256 usages, ignore the rest, ··· 1218 1126 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, 1219 1127 USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD), 1220 1128 QUIRK_USE_KBD_BACKLIGHT }, 1129 + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, 1130 + USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD), 1131 + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, 1221 1132 { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, 1222 1133 USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD), 1223 1134 QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
+1
drivers/hid/hid-ids.h
··· 190 190 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 191 191 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 192 192 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 193 + #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 193 194 #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 194 195 195 196 #define USB_VENDOR_ID_ATEN 0x0557