Skip to content

Commit

Permalink
HID: lenovo: Detect quirk-free fw on cptkbd and stop applying workaround
Browse files Browse the repository at this point in the history
[ Upstream commit 46a0a2c ]

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 3cb5ff0 ("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>
  • Loading branch information
m-khvoinitsky authored and gregkh committed Nov 28, 2023
1 parent 8c68af2 commit 6e2076c
Showing 1 changed file with 45 additions and 23 deletions.
68 changes: 45 additions & 23 deletions drivers/hid/hid-lenovo.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ struct lenovo_drvdata {
int select_right;
int sensitivity;
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;
};

Expand Down Expand Up @@ -668,31 +673,48 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
{
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);

/* "wheel" scroll events */
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
usage->code == REL_HWHEEL)) {
/* Scroll events disable middle-click event */
cptkbd_data->middlebutton_state = 2;
return 0;
}
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 (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);
}

/* 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);
/* "wheel" scroll events */
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
usage->code == REL_HWHEEL)) {
/* Scroll events disable middle-click event */
cptkbd_data->middlebutton_state = 2;
return 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;
}
cptkbd_data->middlebutton_state = 0;
return 1;
}
return 1;
}

if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
Expand Down

0 comments on commit 6e2076c

Please sign in to comment.