HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround
[ Upstream commit 46a0a2c96f0f47628190f122c2e3d879e590bcbe ]
Built-in firmware of cptkbd handles scrolling by itself (when middle
button is pressed) but with issues: it does not support horizontal and
hi-res scrolling and upon middle button release it sends middle button
click even if there was a scrolling event. Commit 3cb5ff0220
("HID:
lenovo: Hide middle-button press until release") workarounds last
issue but it's impossible to workaround scrolling-related issues
without firmware modification.
Likely, Dennis Schneider has reverse engineered the firmware and
provided an instruction on how to patch it [1]. However,
aforementioned workaround prevents userspace (libinput) from knowing
exact moment when middle button has been pressed down and performing
"On-Button scrolling". This commit detects correctly-behaving patched
firmware if cursor movement events has been received during middle
button being pressed and stops applying workaround for this device.
Link: https://hohlerde.org/rauch/en/elektronik/projekte/tpkbd-fix/ [1]
Signed-off-by: Mikhail Khvainitski <me@khvoinitsky.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
1ba7df5457
commit
62d21f9df4
@@ -50,7 +50,12 @@ struct lenovo_drvdata {
|
|||||||
int select_right;
|
int select_right;
|
||||||
int sensitivity;
|
int sensitivity;
|
||||||
int press_speed;
|
int press_speed;
|
||||||
u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
|
/* 0: Up
|
||||||
|
* 1: Down (undecided)
|
||||||
|
* 2: Scrolling
|
||||||
|
* 3: Patched firmware, disable workaround
|
||||||
|
*/
|
||||||
|
u8 middlebutton_state;
|
||||||
bool fn_lock;
|
bool fn_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -478,31 +483,48 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
|
|||||||
{
|
{
|
||||||
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
|
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
|
||||||
|
|
||||||
/* "wheel" scroll events */
|
if (cptkbd_data->middlebutton_state != 3) {
|
||||||
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
|
/* REL_X and REL_Y events during middle button pressed
|
||||||
usage->code == REL_HWHEEL)) {
|
* are only possible on patched, bug-free firmware
|
||||||
/* Scroll events disable middle-click event */
|
* so set middlebutton_state to 3
|
||||||
cptkbd_data->middlebutton_state = 2;
|
* to never apply workaround anymore
|
||||||
return 0;
|
*/
|
||||||
}
|
if (cptkbd_data->middlebutton_state == 1 &&
|
||||||
|
usage->type == EV_REL &&
|
||||||
/* Middle click events */
|
(usage->code == REL_X || usage->code == REL_Y)) {
|
||||||
if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
|
cptkbd_data->middlebutton_state = 3;
|
||||||
if (value == 1) {
|
/* send middle button press which was hold before */
|
||||||
cptkbd_data->middlebutton_state = 1;
|
input_event(field->hidinput->input,
|
||||||
} else if (value == 0) {
|
EV_KEY, BTN_MIDDLE, 1);
|
||||||
if (cptkbd_data->middlebutton_state == 1) {
|
input_sync(field->hidinput->input);
|
||||||
/* No scrolling inbetween, send middle-click */
|
}
|
||||||
input_event(field->hidinput->input,
|
|
||||||
EV_KEY, BTN_MIDDLE, 1);
|
/* "wheel" scroll events */
|
||||||
input_sync(field->hidinput->input);
|
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
|
||||||
input_event(field->hidinput->input,
|
usage->code == REL_HWHEEL)) {
|
||||||
EV_KEY, BTN_MIDDLE, 0);
|
/* Scroll events disable middle-click event */
|
||||||
input_sync(field->hidinput->input);
|
cptkbd_data->middlebutton_state = 2;
|
||||||
}
|
return 0;
|
||||||
cptkbd_data->middlebutton_state = 0;
|
}
|
||||||
|
|
||||||
|
/* Middle click events */
|
||||||
|
if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
|
||||||
|
if (value == 1) {
|
||||||
|
cptkbd_data->middlebutton_state = 1;
|
||||||
|
} else if (value == 0) {
|
||||||
|
if (cptkbd_data->middlebutton_state == 1) {
|
||||||
|
/* No scrolling inbetween, send middle-click */
|
||||||
|
input_event(field->hidinput->input,
|
||||||
|
EV_KEY, BTN_MIDDLE, 1);
|
||||||
|
input_sync(field->hidinput->input);
|
||||||
|
input_event(field->hidinput->input,
|
||||||
|
EV_KEY, BTN_MIDDLE, 0);
|
||||||
|
input_sync(field->hidinput->input);
|
||||||
|
}
|
||||||
|
cptkbd_data->middlebutton_state = 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user