Skip to content

Commit c46f7cb

Browse files
committed
Merge branch 'platform-drivers-x86-asus-kbd' into for-next
2 parents 5d4ae0b + 4748bb4 commit c46f7cb

4 files changed

Lines changed: 325 additions & 190 deletions

File tree

drivers/hid/hid-asus.c

Lines changed: 101 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
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

103104
struct 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)
317317
static 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

395406
static 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

408445
static 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-
499522
static 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

11271092
static 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

Comments
 (0)