Skip to content

Commit 2814646

Browse files
m-khvoinitskyJiri Kosina
authored andcommitted
HID: lenovo: Add middleclick_workaround sysfs knob for cptkbd
Previous attempt to autodetect well-behaving patched firmware introduced in commit 46a0a2c ("HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround") has shown that there are false-positives on original firmware (on both 1st gen and 2nd gen keyboards) which causes the middle button click workaround to be mistakenly disabled. This commit adds explicit parameter to sysfs to control this workaround. Fixes: 46a0a2c ("HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround") Fixes: 43527a0 ("HID: lenovo: Restrict detection of patched firmware only to USB cptkbd") Signed-off-by: Mikhail Khvainitski <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent fef018d commit 2814646

File tree

1 file changed

+39
-18
lines changed

1 file changed

+39
-18
lines changed

drivers/hid/hid-lenovo.c

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@ struct lenovo_drvdata {
5454
/* 0: Up
5555
* 1: Down (undecided)
5656
* 2: Scrolling
57-
* 3: Patched firmware, disable workaround
5857
*/
5958
u8 middlebutton_state;
6059
bool fn_lock;
60+
bool middleclick_workaround_cptkbd;
6161
};
6262

6363
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
@@ -621,6 +621,36 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
621621
return count;
622622
}
623623

624+
static ssize_t attr_middleclick_workaround_show_cptkbd(struct device *dev,
625+
struct device_attribute *attr,
626+
char *buf)
627+
{
628+
struct hid_device *hdev = to_hid_device(dev);
629+
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
630+
631+
return snprintf(buf, PAGE_SIZE, "%u\n",
632+
cptkbd_data->middleclick_workaround_cptkbd);
633+
}
634+
635+
static ssize_t attr_middleclick_workaround_store_cptkbd(struct device *dev,
636+
struct device_attribute *attr,
637+
const char *buf,
638+
size_t count)
639+
{
640+
struct hid_device *hdev = to_hid_device(dev);
641+
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
642+
int value;
643+
644+
if (kstrtoint(buf, 10, &value))
645+
return -EINVAL;
646+
if (value < 0 || value > 1)
647+
return -EINVAL;
648+
649+
cptkbd_data->middleclick_workaround_cptkbd = !!value;
650+
651+
return count;
652+
}
653+
624654

625655
static struct device_attribute dev_attr_fn_lock =
626656
__ATTR(fn_lock, S_IWUSR | S_IRUGO,
@@ -632,10 +662,16 @@ static struct device_attribute dev_attr_sensitivity_cptkbd =
632662
attr_sensitivity_show_cptkbd,
633663
attr_sensitivity_store_cptkbd);
634664

665+
static struct device_attribute dev_attr_middleclick_workaround_cptkbd =
666+
__ATTR(middleclick_workaround, S_IWUSR | S_IRUGO,
667+
attr_middleclick_workaround_show_cptkbd,
668+
attr_middleclick_workaround_store_cptkbd);
669+
635670

636671
static struct attribute *lenovo_attributes_cptkbd[] = {
637672
&dev_attr_fn_lock.attr,
638673
&dev_attr_sensitivity_cptkbd.attr,
674+
&dev_attr_middleclick_workaround_cptkbd.attr,
639675
NULL
640676
};
641677

@@ -686,23 +722,7 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
686722
{
687723
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
688724

689-
if (cptkbd_data->middlebutton_state != 3) {
690-
/* REL_X and REL_Y events during middle button pressed
691-
* are only possible on patched, bug-free firmware
692-
* so set middlebutton_state to 3
693-
* to never apply workaround anymore
694-
*/
695-
if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD &&
696-
cptkbd_data->middlebutton_state == 1 &&
697-
usage->type == EV_REL &&
698-
(usage->code == REL_X || usage->code == REL_Y)) {
699-
cptkbd_data->middlebutton_state = 3;
700-
/* send middle button press which was hold before */
701-
input_event(field->hidinput->input,
702-
EV_KEY, BTN_MIDDLE, 1);
703-
input_sync(field->hidinput->input);
704-
}
705-
725+
if (cptkbd_data->middleclick_workaround_cptkbd) {
706726
/* "wheel" scroll events */
707727
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
708728
usage->code == REL_HWHEEL)) {
@@ -1166,6 +1186,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
11661186
cptkbd_data->middlebutton_state = 0;
11671187
cptkbd_data->fn_lock = true;
11681188
cptkbd_data->sensitivity = 0x05;
1189+
cptkbd_data->middleclick_workaround_cptkbd = true;
11691190
lenovo_features_set_cptkbd(hdev);
11701191

11711192
ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd);

0 commit comments

Comments
 (0)