[PATCH] HID: lenovo: Restrict detection of patched firmware only to USB cptkbd

Mikhail Khvainitski posted 1 patch 2 years ago
drivers/hid/hid-lenovo.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
[PATCH] HID: lenovo: Restrict detection of patched firmware only to USB cptkbd
Posted by Mikhail Khvainitski 2 years ago
Commit 46a0a2c96f0f ("HID: lenovo: Detect quirk-free fw on cptkbd and
stop applying workaround") introduced a regression for ThinkPad
TrackPoint Keyboard II which has similar quirks to cptkbd (so it uses
the same workarounds) but slightly different so that there are
false-positives during detecting well-behaving firmware. This commit
restricts detecting well-behaving firmware to the only model which
known to have one and have stable enough quirks to not cause
false-positives.

Fixes: 46a0a2c96f0f ("HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround")
Link: https://lore.kernel.org/linux-input/ZXRiiPsBKNasioqH@jekhomev/
Link: https://bbs.archlinux.org/viewtopic.php?pid=2135468#p2135468
Signed-off-by: Mikhail Khvainitski <me@khvoinitsky.org>
Tested-by: Yauhen Kharuzhy <jekhor@gmail.com>
---
 drivers/hid/hid-lenovo.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 7c1b33be9d13..149a3c74346b 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -692,7 +692,8 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
 		 * so set middlebutton_state to 3
 		 * to never apply workaround anymore
 		 */
-		if (cptkbd_data->middlebutton_state == 1 &&
+		if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD &&
+				cptkbd_data->middlebutton_state == 1 &&
 				usage->type == EV_REL &&
 				(usage->code == REL_X || usage->code == REL_Y)) {
 			cptkbd_data->middlebutton_state = 3;
-- 
2.43.0
Re: [PATCH] HID: lenovo: Restrict detection of patched firmware only to USB cptkbd
Posted by Jiri Kosina 2 years ago
On Tue, 12 Dec 2023, Mikhail Khvainitski wrote:

> Commit 46a0a2c96f0f ("HID: lenovo: Detect quirk-free fw on cptkbd and
> stop applying workaround") introduced a regression for ThinkPad
> TrackPoint Keyboard II which has similar quirks to cptkbd (so it uses
> the same workarounds) but slightly different so that there are
> false-positives during detecting well-behaving firmware. This commit
> restricts detecting well-behaving firmware to the only model which
> known to have one and have stable enough quirks to not cause
> false-positives.
> 
> Fixes: 46a0a2c96f0f ("HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround")
> Link: https://lore.kernel.org/linux-input/ZXRiiPsBKNasioqH@jekhomev/
> Link: https://bbs.archlinux.org/viewtopic.php?pid=2135468#p2135468
> Signed-off-by: Mikhail Khvainitski <me@khvoinitsky.org>
> Tested-by: Yauhen Kharuzhy <jekhor@gmail.com>
> ---
>  drivers/hid/hid-lenovo.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
> index 7c1b33be9d13..149a3c74346b 100644
> --- a/drivers/hid/hid-lenovo.c
> +++ b/drivers/hid/hid-lenovo.c
> @@ -692,7 +692,8 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
>  		 * so set middlebutton_state to 3
>  		 * to never apply workaround anymore
>  		 */
> -		if (cptkbd_data->middlebutton_state == 1 &&
> +		if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD &&
> +				cptkbd_data->middlebutton_state == 1 &&
>  				usage->type == EV_REL &&
>  				(usage->code == REL_X || usage->code == REL_Y)) {
>  			cptkbd_data->middlebutton_state = 3;

Applied, thanks.

-- 
Jiri Kosina
SUSE Labs
Re: [PATCH] HID: lenovo: Restrict detection of patched firmware only to USB cptkbd
Posted by Uli v. d. Ohe 2 years ago
I get buggy middle button scrolling behavior on my USB Compact Keyboard 
(i.e., "1st gen") with original, unmodified firmware and the patch (of 
Sep. 23).

Sometimes the keyboard sends REL_X events while the middle button is 
pressed. Thus the old "workaround" is disabled and middle button 
scrolling henceforth exhibits the known buggy behavior.

Explicitly, I can confirm that the following values occur, leading to 
erroneous disabling of the workaround:

cptkbd_data->middlebutton_state == 1
usage->type == 2 [i.e., EV_REL]
usage->code == 0 [i.e., REL_X]

The keyboard is identified by lsusb as:
ID 17ef:6047 Lenovo ThinkPad Compact Keyboard with TrackPoint

This was tested with kernel 6.1.67 which contains the backported patch 
(commit 6e2076cad8873cc2a9f96e4becab35425c3656dc).

I didn't test the latest patch of Dec. 12. However, I don't expect it to 
fix my issue as the only added condition
hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD
should be satisfied, which I understand is also the intention. 
(USB_DEVICE_ID_LENOVO_CUSBKBD == 0x6047, which is the device ID of my 
keyboard as reported by lsusb.)

Best regards,
Uli
Re: [PATCH] HID: lenovo: Restrict detection of patched firmware only to USB cptkbd
Posted by Mikhail Khvoinitsky 2 years ago
Hello.

Thank you for the report, sorry about that. I've received one more
report of the same issue by email.
So this means that the only reliable way is to add a sysfs parameter.
I'll send a patch.


On Fri, 22 Dec 2023 at 17:32, Uli v. d. Ohe <u-v@mailbox.org> wrote:
>
> I get buggy middle button scrolling behavior on my USB Compact Keyboard
> (i.e., "1st gen") with original, unmodified firmware and the patch (of
> Sep. 23).
>
> Sometimes the keyboard sends REL_X events while the middle button is
> pressed. Thus the old "workaround" is disabled and middle button
> scrolling henceforth exhibits the known buggy behavior.
>
> Explicitly, I can confirm that the following values occur, leading to
> erroneous disabling of the workaround:
>
> cptkbd_data->middlebutton_state == 1
> usage->type == 2 [i.e., EV_REL]
> usage->code == 0 [i.e., REL_X]
>
> The keyboard is identified by lsusb as:
> ID 17ef:6047 Lenovo ThinkPad Compact Keyboard with TrackPoint
>
> This was tested with kernel 6.1.67 which contains the backported patch
> (commit 6e2076cad8873cc2a9f96e4becab35425c3656dc).
>
> I didn't test the latest patch of Dec. 12. However, I don't expect it to
> fix my issue as the only added condition
> hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD
> should be satisfied, which I understand is also the intention.
> (USB_DEVICE_ID_LENOVO_CUSBKBD == 0x6047, which is the device ID of my
> keyboard as reported by lsusb.)
>
> Best regards,
> Uli
Re: [PATCH] HID: lenovo: Restrict detection of patched firmware only to USB cptkbd
Posted by Uli v. d. Ohe 2 years ago
> So this means that the only reliable way is to add a sysfs parameter.
> I'll send a patch.

Thank you for the quick action!

Perhaps it would be possible to modify the firmware further in order to 
facilitate reliable detection of this modified firmware? But for now the 
solution with a sysfs parameter (and defaulting to the workaround) seems 
good.

Best regards,
Uli
Re: [PATCH] HID: lenovo: Restrict detection of patched firmware only to USB cptkbd
Posted by Yauhen Kharuzhy 2 years ago
вс, 24 дек. 2023 г. в 18:51, Uli v. d. Ohe <u-v@mailbox.org>:
>
> > So this means that the only reliable way is to add a sysfs parameter.
> > I'll send a patch.
>
> Thank you for the quick action!
>
> Perhaps it would be possible to modify the firmware further in order to
> facilitate reliable detection of this modified firmware? But for now the
> solution with a sysfs parameter (and defaulting to the workaround) seems
> good.
Unfortunately no, the firmware is closed-source and was patched in
binary form AFAIR (by replacing 1-2 instructions). Moreover, it cannot
be updated in the wireless version of the keyboard (ThinkPad Compact
Keyboard II).
>
> Best regards,
> Uli



-- 
Yauhen Kharuzhy
[PATCH] HID: lenovo: Add middleclick_workaround sysfs knob for cptkbd
Posted by Mikhail Khvainitski 2 years ago
Previous attempt to autodetect well-behaving patched firmware
introduced in commit 46a0a2c96f0f ("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: 46a0a2c96f0f ("HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround")
Fixes: 43527a0094c1 ("HID: lenovo: Restrict detection of patched firmware only to USB cptkbd")
Signed-off-by: Mikhail Khvainitski <me@khvoinitsky.org>
---
 drivers/hid/hid-lenovo.c | 57 +++++++++++++++++++++++++++-------------
 1 file changed, 39 insertions(+), 18 deletions(-)

diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 149a3c74346b..f86c1ea83a03 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -54,10 +54,10 @@ struct lenovo_drvdata {
 	/* 0: Up
 	 * 1: Down (undecided)
 	 * 2: Scrolling
-	 * 3: Patched firmware, disable workaround
 	 */
 	u8 middlebutton_state;
 	bool fn_lock;
+	bool middleclick_workaround_cptkbd;
 };
 
 #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,
 	return count;
 }
 
+static ssize_t attr_middleclick_workaround_show_cptkbd(struct device *dev,
+		struct device_attribute *attr,
+		char *buf)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n",
+		cptkbd_data->middleclick_workaround_cptkbd);
+}
+
+static ssize_t attr_middleclick_workaround_store_cptkbd(struct device *dev,
+		struct device_attribute *attr,
+		const char *buf,
+		size_t count)
+{
+	struct hid_device *hdev = to_hid_device(dev);
+	struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
+	int value;
+
+	if (kstrtoint(buf, 10, &value))
+		return -EINVAL;
+	if (value < 0 || value > 1)
+		return -EINVAL;
+
+	cptkbd_data->middleclick_workaround_cptkbd = !!value;
+
+	return count;
+}
+
 
 static struct device_attribute dev_attr_fn_lock =
 	__ATTR(fn_lock, S_IWUSR | S_IRUGO,
@@ -632,10 +662,16 @@ static struct device_attribute dev_attr_sensitivity_cptkbd =
 			attr_sensitivity_show_cptkbd,
 			attr_sensitivity_store_cptkbd);
 
+static struct device_attribute dev_attr_middleclick_workaround_cptkbd =
+	__ATTR(middleclick_workaround, S_IWUSR | S_IRUGO,
+			attr_middleclick_workaround_show_cptkbd,
+			attr_middleclick_workaround_store_cptkbd);
+
 
 static struct attribute *lenovo_attributes_cptkbd[] = {
 	&dev_attr_fn_lock.attr,
 	&dev_attr_sensitivity_cptkbd.attr,
+	&dev_attr_middleclick_workaround_cptkbd.attr,
 	NULL
 };
 
@@ -686,23 +722,7 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
 {
 	struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
 
-	if (cptkbd_data->middlebutton_state != 3) {
-		/* REL_X and REL_Y events during middle button pressed
-		 * are only possible on patched, bug-free firmware
-		 * so set middlebutton_state to 3
-		 * to never apply workaround anymore
-		 */
-		if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD &&
-				cptkbd_data->middlebutton_state == 1 &&
-				usage->type == EV_REL &&
-				(usage->code == REL_X || usage->code == REL_Y)) {
-			cptkbd_data->middlebutton_state = 3;
-			/* send middle button press which was hold before */
-			input_event(field->hidinput->input,
-				EV_KEY, BTN_MIDDLE, 1);
-			input_sync(field->hidinput->input);
-		}
-
+	if (cptkbd_data->middleclick_workaround_cptkbd) {
 		/* "wheel" scroll events */
 		if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
 				usage->code == REL_HWHEEL)) {
@@ -1166,6 +1186,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
 	cptkbd_data->middlebutton_state = 0;
 	cptkbd_data->fn_lock = true;
 	cptkbd_data->sensitivity = 0x05;
+	cptkbd_data->middleclick_workaround_cptkbd = true;
 	lenovo_features_set_cptkbd(hdev);
 
 	ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd);
-- 
2.43.0
Re: [PATCH] HID: lenovo: Add middleclick_workaround sysfs knob for cptkbd
Posted by Jiri Kosina 1 year, 11 months ago
On Sat, 23 Dec 2023, Mikhail Khvainitski wrote:

> Previous attempt to autodetect well-behaving patched firmware
> introduced in commit 46a0a2c96f0f ("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: 46a0a2c96f0f ("HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround")
> Fixes: 43527a0094c1 ("HID: lenovo: Restrict detection of patched firmware only to USB cptkbd")
> Signed-off-by: Mikhail Khvainitski <me@khvoinitsky.org>

I am not a huge fan of sysctl device-specific knobs like this, but I guess 
this is the best we can get here, unfortunately.

Now applied, thanks a lot.

-- 
Jiri Kosina
SUSE Labs