HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround
[ Upstream commit46a0a2c96f
] 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. Commit3cb5ff0220
("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
64f062baf2
commit
8d25ec69f8
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -529,31 +534,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