2727#include <linux/hid.h>
2828#include <linux/module.h>
2929#include <linux/platform_data/x86/asus-wmi.h>
30- #include <linux/platform_data/x86/asus-wmi-leds-ids.h>
3130#include <linux/input/mt.h>
3231#include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
3332#include <linux/power_supply.h>
@@ -48,8 +47,9 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
4847#define T100CHI_MOUSE_REPORT_ID 0x06
4948#define FEATURE_REPORT_ID 0x0d
5049#define INPUT_REPORT_ID 0x5d
50+ #define HID_USAGE_PAGE_VENDOR 0xff310000
5151#define FEATURE_KBD_REPORT_ID 0x5a
52- #define FEATURE_KBD_REPORT_SIZE 16
52+ #define FEATURE_KBD_REPORT_SIZE 64
5353#define FEATURE_KBD_LED_REPORT_ID1 0x5d
5454#define FEATURE_KBD_LED_REPORT_ID2 0x5e
5555
@@ -90,6 +90,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
9090#define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
9191#define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
9292#define QUIRK_ROG_ALLY_XPAD BIT(13)
93+ #define QUIRK_ROG_NKEY_ID1ID2_INIT BIT(14)
9394
9495#define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
9596 QUIRK_NO_INIT_REPORTS | \
@@ -101,7 +102,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
101102#define TRKID_SGN ((TRKID_MAX + 1) >> 1)
102103
103104struct asus_kbd_leds {
104- struct led_classdev cdev ;
105+ struct asus_hid_listener listener ;
105106 struct hid_device * hdev ;
106107 struct work_struct work ;
107108 unsigned int brightness ;
@@ -126,7 +127,6 @@ struct asus_drvdata {
126127 struct input_dev * tp_kbd_input ;
127128 struct asus_kbd_leds * kbd_backlight ;
128129 const struct asus_touchpad_info * tp ;
129- bool enable_backlight ;
130130 struct power_supply * battery ;
131131 struct power_supply_desc battery_desc ;
132132 int battery_capacity ;
@@ -317,13 +317,24 @@ static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size)
317317static int asus_event (struct hid_device * hdev , struct hid_field * field ,
318318 struct hid_usage * usage , __s32 value )
319319{
320- if ((usage -> hid & HID_USAGE_PAGE ) == 0xff310000 &&
320+ if ((usage -> hid & HID_USAGE_PAGE ) == HID_USAGE_PAGE_VENDOR &&
321321 (usage -> hid & HID_USAGE ) != 0x00 &&
322322 (usage -> hid & HID_USAGE ) != 0xff && !usage -> type ) {
323323 hid_warn (hdev , "Unmapped Asus vendor usagepage code 0x%02x\n" ,
324324 usage -> hid & HID_USAGE );
325325 }
326326
327+ if (usage -> type == EV_KEY && value ) {
328+ switch (usage -> code ) {
329+ case KEY_KBDILLUMUP :
330+ return !asus_hid_event (ASUS_EV_BRTUP );
331+ case KEY_KBDILLUMDOWN :
332+ return !asus_hid_event (ASUS_EV_BRTDOWN );
333+ case KEY_KBDILLUMTOGGLE :
334+ return !asus_hid_event (ASUS_EV_BRTTOGGLE );
335+ }
336+ }
337+
327338 return 0 ;
328339}
329340
@@ -394,15 +405,41 @@ static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t bu
394405
395406static int asus_kbd_init (struct hid_device * hdev , u8 report_id )
396407{
408+ /*
409+ * The handshake is first sent as a set_report, then retrieved
410+ * from a get_report. They should be equal.
411+ */
397412 const u8 buf [] = { report_id , 0x41 , 0x53 , 0x55 , 0x53 , 0x20 , 0x54 ,
398413 0x65 , 0x63 , 0x68 , 0x2e , 0x49 , 0x6e , 0x63 , 0x2e , 0x00 };
399414 int ret ;
400415
401416 ret = asus_kbd_set_report (hdev , buf , sizeof (buf ));
402- if (ret < 0 )
403- hid_err (hdev , "Asus failed to send init command: %d\n" , ret );
417+ if (ret < 0 ) {
418+ hid_err (hdev , "Asus handshake %02x failed to send: %d\n" ,
419+ report_id , ret );
420+ return ret ;
421+ }
404422
405- return ret ;
423+ u8 * readbuf __free (kfree ) = kzalloc (FEATURE_KBD_REPORT_SIZE , GFP_KERNEL );
424+ if (!readbuf )
425+ return - ENOMEM ;
426+
427+ ret = hid_hw_raw_request (hdev , report_id , readbuf ,
428+ FEATURE_KBD_REPORT_SIZE , HID_FEATURE_REPORT ,
429+ HID_REQ_GET_REPORT );
430+ if (ret < 0 ) {
431+ hid_warn (hdev , "Asus handshake %02x failed to receive ack: %d\n" ,
432+ report_id , ret );
433+ } else if (memcmp (readbuf , buf , sizeof (buf )) != 0 ) {
434+ hid_warn (hdev , "Asus handshake %02x returned invalid response: %*ph\n" ,
435+ report_id , FEATURE_KBD_REPORT_SIZE , readbuf );
436+ }
437+
438+ /*
439+ * Do not return error if handshake is wrong until this is
440+ * verified to work for all devices.
441+ */
442+ return 0 ;
406443}
407444
408445static int asus_kbd_get_functions (struct hid_device * hdev ,
@@ -423,7 +460,7 @@ static int asus_kbd_get_functions(struct hid_device *hdev,
423460 if (!readbuf )
424461 return - ENOMEM ;
425462
426- ret = hid_hw_raw_request (hdev , FEATURE_KBD_REPORT_ID , readbuf ,
463+ ret = hid_hw_raw_request (hdev , report_id , readbuf ,
427464 FEATURE_KBD_REPORT_SIZE , HID_FEATURE_REPORT ,
428465 HID_REQ_GET_REPORT );
429466 if (ret < 0 ) {
@@ -468,11 +505,11 @@ static void asus_schedule_work(struct asus_kbd_leds *led)
468505 spin_unlock_irqrestore (& led -> lock , flags );
469506}
470507
471- static void asus_kbd_backlight_set (struct led_classdev * led_cdev ,
472- enum led_brightness brightness )
508+ static void asus_kbd_backlight_set (struct asus_hid_listener * listener ,
509+ int brightness )
473510{
474- struct asus_kbd_leds * led = container_of (led_cdev , struct asus_kbd_leds ,
475- cdev );
511+ struct asus_kbd_leds * led = container_of (listener , struct asus_kbd_leds ,
512+ listener );
476513 unsigned long flags ;
477514
478515 spin_lock_irqsave (& led -> lock , flags );
@@ -482,20 +519,6 @@ static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
482519 asus_schedule_work (led );
483520}
484521
485- static enum led_brightness asus_kbd_backlight_get (struct led_classdev * led_cdev )
486- {
487- struct asus_kbd_leds * led = container_of (led_cdev , struct asus_kbd_leds ,
488- cdev );
489- enum led_brightness brightness ;
490- unsigned long flags ;
491-
492- spin_lock_irqsave (& led -> lock , flags );
493- brightness = led -> brightness ;
494- spin_unlock_irqrestore (& led -> lock , flags );
495-
496- return brightness ;
497- }
498-
499522static void asus_kbd_backlight_work (struct work_struct * work )
500523{
501524 struct asus_kbd_leds * led = container_of (work , struct asus_kbd_leds , work );
@@ -512,34 +535,6 @@ static void asus_kbd_backlight_work(struct work_struct *work)
512535 hid_err (led -> hdev , "Asus failed to set keyboard backlight: %d\n" , ret );
513536}
514537
515- /* WMI-based keyboard backlight LED control (via asus-wmi driver) takes
516- * precedence. We only activate HID-based backlight control when the
517- * WMI control is not available.
518- */
519- static bool asus_kbd_wmi_led_control_present (struct hid_device * hdev )
520- {
521- struct asus_drvdata * drvdata = hid_get_drvdata (hdev );
522- u32 value ;
523- int ret ;
524-
525- if (!IS_ENABLED (CONFIG_ASUS_WMI ))
526- return false;
527-
528- if (drvdata -> quirks & QUIRK_ROG_NKEY_KEYBOARD &&
529- dmi_check_system (asus_use_hid_led_dmi_ids )) {
530- hid_info (hdev , "using HID for asus::kbd_backlight\n" );
531- return false;
532- }
533-
534- ret = asus_wmi_evaluate_method (ASUS_WMI_METHODID_DSTS ,
535- ASUS_WMI_DEVID_KBD_BACKLIGHT , 0 , & value );
536- hid_dbg (hdev , "WMI backlight check: rc %d value %x" , ret , value );
537- if (ret )
538- return false;
539-
540- return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT );
541- }
542-
543538/*
544539 * We don't care about any other part of the string except the version section.
545540 * Example strings: FGA80100.RC72LA.312_T01, FGA80100.RC71LS.318_T01
@@ -639,48 +634,35 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
639634 unsigned char kbd_func ;
640635 int ret ;
641636
642- if (drvdata -> quirks & QUIRK_ROG_NKEY_KEYBOARD ) {
643- /* Initialize keyboard */
644- ret = asus_kbd_init (hdev , FEATURE_KBD_REPORT_ID );
645- if (ret < 0 )
646- return ret ;
647-
648- /* The LED endpoint is initialised in two HID */
649- ret = asus_kbd_init (hdev , FEATURE_KBD_LED_REPORT_ID1 );
650- if (ret < 0 )
651- return ret ;
652-
653- ret = asus_kbd_init (hdev , FEATURE_KBD_LED_REPORT_ID2 );
654- if (ret < 0 )
655- return ret ;
637+ ret = asus_kbd_init (hdev , FEATURE_KBD_REPORT_ID );
638+ if (ret < 0 )
639+ return ret ;
656640
657- if (dmi_match (DMI_PRODUCT_FAMILY , "ProArt P16" )) {
658- ret = asus_kbd_disable_oobe (hdev );
659- if (ret < 0 )
660- return ret ;
661- }
641+ /* Get keyboard functions */
642+ ret = asus_kbd_get_functions (hdev , & kbd_func , FEATURE_KBD_REPORT_ID );
643+ if (ret < 0 )
644+ return ret ;
662645
663- if (drvdata -> quirks & QUIRK_ROG_ALLY_XPAD ) {
664- intf = to_usb_interface (hdev -> dev .parent );
665- udev = interface_to_usbdev (intf );
666- validate_mcu_fw_version (hdev ,
667- le16_to_cpu (udev -> descriptor .idProduct ));
668- }
646+ /* Check for backlight support */
647+ if (!(kbd_func & SUPPORT_KBD_BACKLIGHT ))
648+ return - ENODEV ;
669649
670- } else {
671- /* Initialize keyboard */
672- ret = asus_kbd_init (hdev , FEATURE_KBD_REPORT_ID );
673- if (ret < 0 )
674- return ret ;
650+ if (drvdata -> quirks & QUIRK_ROG_NKEY_ID1ID2_INIT ) {
651+ asus_kbd_init (hdev , FEATURE_KBD_LED_REPORT_ID1 );
652+ asus_kbd_init (hdev , FEATURE_KBD_LED_REPORT_ID2 );
653+ }
675654
676- /* Get keyboard functions */
677- ret = asus_kbd_get_functions (hdev , & kbd_func , FEATURE_KBD_REPORT_ID );
655+ if ( dmi_match ( DMI_PRODUCT_FAMILY , "ProArt P16" )) {
656+ ret = asus_kbd_disable_oobe (hdev );
678657 if (ret < 0 )
679658 return ret ;
659+ }
680660
681- /* Check for backlight support */
682- if (!(kbd_func & SUPPORT_KBD_BACKLIGHT ))
683- return - ENODEV ;
661+ if (drvdata -> quirks & QUIRK_ROG_ALLY_XPAD ) {
662+ intf = to_usb_interface (hdev -> dev .parent );
663+ udev = interface_to_usbdev (intf );
664+ validate_mcu_fw_version (hdev ,
665+ le16_to_cpu (udev -> descriptor .idProduct ));
684666 }
685667
686668 drvdata -> kbd_backlight = devm_kzalloc (& hdev -> dev ,
@@ -692,14 +674,11 @@ static int asus_kbd_register_leds(struct hid_device *hdev)
692674 drvdata -> kbd_backlight -> removed = false;
693675 drvdata -> kbd_backlight -> brightness = 0 ;
694676 drvdata -> kbd_backlight -> hdev = hdev ;
695- drvdata -> kbd_backlight -> cdev .name = "asus::kbd_backlight" ;
696- drvdata -> kbd_backlight -> cdev .max_brightness = 3 ;
697- drvdata -> kbd_backlight -> cdev .brightness_set = asus_kbd_backlight_set ;
698- drvdata -> kbd_backlight -> cdev .brightness_get = asus_kbd_backlight_get ;
677+ drvdata -> kbd_backlight -> listener .brightness_set = asus_kbd_backlight_set ;
699678 INIT_WORK (& drvdata -> kbd_backlight -> work , asus_kbd_backlight_work );
700679 spin_lock_init (& drvdata -> kbd_backlight -> lock );
701680
702- ret = devm_led_classdev_register ( & hdev -> dev , & drvdata -> kbd_backlight -> cdev );
681+ ret = asus_hid_register_listener ( & drvdata -> kbd_backlight -> listener );
703682 if (ret < 0 ) {
704683 /* No need to have this still around */
705684 devm_kfree (& hdev -> dev , drvdata -> kbd_backlight );
@@ -924,11 +903,6 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
924903
925904 drvdata -> input = input ;
926905
927- if (drvdata -> enable_backlight &&
928- !asus_kbd_wmi_led_control_present (hdev ) &&
929- asus_kbd_register_leds (hdev ))
930- hid_warn (hdev , "Failed to initialize backlight.\n" );
931-
932906 return 0 ;
933907}
934908
@@ -1001,15 +975,6 @@ static int asus_input_mapping(struct hid_device *hdev,
1001975 return -1 ;
1002976 }
1003977
1004- /*
1005- * Check and enable backlight only on devices with UsagePage ==
1006- * 0xff31 to avoid initializing the keyboard firmware multiple
1007- * times on devices with multiple HID descriptors but same
1008- * PID/VID.
1009- */
1010- if (drvdata -> quirks & QUIRK_USE_KBD_BACKLIGHT )
1011- drvdata -> enable_backlight = true;
1012-
1013978 set_bit (EV_REP , hi -> input -> evbit );
1014979 return 1 ;
1015980 }
@@ -1102,7 +1067,7 @@ static int __maybe_unused asus_resume(struct hid_device *hdev) {
11021067
11031068 if (drvdata -> kbd_backlight ) {
11041069 const u8 buf [] = { FEATURE_KBD_REPORT_ID , 0xba , 0xc5 , 0xc4 ,
1105- drvdata -> kbd_backlight -> cdev . brightness };
1070+ drvdata -> kbd_backlight -> brightness };
11061071 ret = asus_kbd_set_report (hdev , buf , sizeof (buf ));
11071072 if (ret < 0 ) {
11081073 hid_err (hdev , "Asus failed to set keyboard backlight: %d\n" , ret );
@@ -1126,8 +1091,11 @@ static int __maybe_unused asus_reset_resume(struct hid_device *hdev)
11261091
11271092static int asus_probe (struct hid_device * hdev , const struct hid_device_id * id )
11281093{
1129- int ret ;
1094+ struct hid_report_enum * rep_enum ;
11301095 struct asus_drvdata * drvdata ;
1096+ struct hid_report * rep ;
1097+ bool is_vendor = false;
1098+ int ret ;
11311099
11321100 drvdata = devm_kzalloc (& hdev -> dev , sizeof (* drvdata ), GFP_KERNEL );
11331101 if (drvdata == NULL ) {
@@ -1211,12 +1179,30 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
12111179 return ret ;
12121180 }
12131181
1182+ /* Check for vendor for RGB init and handle generic devices properly. */
1183+ rep_enum = & hdev -> report_enum [HID_INPUT_REPORT ];
1184+ list_for_each_entry (rep , & rep_enum -> report_list , list ) {
1185+ if ((rep -> application & HID_USAGE_PAGE ) == HID_USAGE_PAGE_VENDOR )
1186+ is_vendor = true;
1187+ }
1188+
12141189 ret = hid_hw_start (hdev , HID_CONNECT_DEFAULT );
12151190 if (ret ) {
12161191 hid_err (hdev , "Asus hw start failed: %d\n" , ret );
12171192 return ret ;
12181193 }
12191194
1195+ if (is_vendor && (drvdata -> quirks & QUIRK_USE_KBD_BACKLIGHT ) &&
1196+ asus_kbd_register_leds (hdev ))
1197+ hid_warn (hdev , "Failed to initialize backlight.\n" );
1198+
1199+ /*
1200+ * For ROG keyboards, skip rename for consistency and ->input check as
1201+ * some devices do not have inputs.
1202+ */
1203+ if (drvdata -> quirks & QUIRK_ROG_NKEY_KEYBOARD )
1204+ return 0 ;
1205+
12201206 /*
12211207 * Check that input registration succeeded. Checking that
12221208 * HID_CLAIMED_INPUT is set prevents a UAF when all input devices
@@ -1253,6 +1239,8 @@ static void asus_remove(struct hid_device *hdev)
12531239 unsigned long flags ;
12541240
12551241 if (drvdata -> kbd_backlight ) {
1242+ asus_hid_unregister_listener (& drvdata -> kbd_backlight -> listener );
1243+
12561244 spin_lock_irqsave (& drvdata -> kbd_backlight -> lock , flags );
12571245 drvdata -> kbd_backlight -> removed = true;
12581246 spin_unlock_irqrestore (& drvdata -> kbd_backlight -> lock , flags );
@@ -1384,10 +1372,10 @@ static const struct hid_device_id asus_devices[] = {
13841372 QUIRK_USE_KBD_BACKLIGHT },
13851373 { HID_USB_DEVICE (USB_VENDOR_ID_ASUSTEK ,
13861374 USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD ),
1387- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
1375+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_NKEY_ID1ID2_INIT },
13881376 { HID_USB_DEVICE (USB_VENDOR_ID_ASUSTEK ,
13891377 USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 ),
1390- QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
1378+ QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_NKEY_ID1ID2_INIT },
13911379 { HID_USB_DEVICE (USB_VENDOR_ID_ASUSTEK ,
13921380 USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR ),
13931381 QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
0 commit comments