Skip to content

Commit 7601fef

Browse files
author
Jiri Kosina
committed
Merge branch 'for-6.7/lenovo' into for-linus
- Suspend/Resume fix for USB Thinkpad Compact Keyboard (Jamie Lentin) - firmware detection improvement for Lenovo cptkbd (Mikhail Khvainitski)
2 parents f5883ef + 2f2bd7c commit 7601fef

File tree

1 file changed

+79
-39
lines changed

1 file changed

+79
-39
lines changed

drivers/hid/hid-lenovo.c

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,12 @@ struct lenovo_drvdata {
5151
int select_right;
5252
int sensitivity;
5353
int press_speed;
54-
u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
54+
/* 0: Up
55+
* 1: Down (undecided)
56+
* 2: Scrolling
57+
* 3: Patched firmware, disable workaround
58+
*/
59+
u8 middlebutton_state;
5560
bool fn_lock;
5661
};
5762

@@ -521,6 +526,19 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
521526
int ret;
522527
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
523528

529+
/*
530+
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
531+
* regular keys
532+
*/
533+
ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
534+
if (ret)
535+
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
536+
537+
/* Switch middle button to native mode */
538+
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
539+
if (ret)
540+
hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
541+
524542
ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
525543
if (ret)
526544
hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
@@ -668,31 +686,48 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
668686
{
669687
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
670688

671-
/* "wheel" scroll events */
672-
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
673-
usage->code == REL_HWHEEL)) {
674-
/* Scroll events disable middle-click event */
675-
cptkbd_data->middlebutton_state = 2;
676-
return 0;
677-
}
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 (cptkbd_data->middlebutton_state == 1 &&
696+
usage->type == EV_REL &&
697+
(usage->code == REL_X || usage->code == REL_Y)) {
698+
cptkbd_data->middlebutton_state = 3;
699+
/* send middle button press which was hold before */
700+
input_event(field->hidinput->input,
701+
EV_KEY, BTN_MIDDLE, 1);
702+
input_sync(field->hidinput->input);
703+
}
704+
705+
/* "wheel" scroll events */
706+
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
707+
usage->code == REL_HWHEEL)) {
708+
/* Scroll events disable middle-click event */
709+
cptkbd_data->middlebutton_state = 2;
710+
return 0;
711+
}
678712

679-
/* Middle click events */
680-
if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
681-
if (value == 1) {
682-
cptkbd_data->middlebutton_state = 1;
683-
} else if (value == 0) {
684-
if (cptkbd_data->middlebutton_state == 1) {
685-
/* No scrolling inbetween, send middle-click */
686-
input_event(field->hidinput->input,
687-
EV_KEY, BTN_MIDDLE, 1);
688-
input_sync(field->hidinput->input);
689-
input_event(field->hidinput->input,
690-
EV_KEY, BTN_MIDDLE, 0);
691-
input_sync(field->hidinput->input);
713+
/* Middle click events */
714+
if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
715+
if (value == 1) {
716+
cptkbd_data->middlebutton_state = 1;
717+
} else if (value == 0) {
718+
if (cptkbd_data->middlebutton_state == 1) {
719+
/* No scrolling inbetween, send middle-click */
720+
input_event(field->hidinput->input,
721+
EV_KEY, BTN_MIDDLE, 1);
722+
input_sync(field->hidinput->input);
723+
input_event(field->hidinput->input,
724+
EV_KEY, BTN_MIDDLE, 0);
725+
input_sync(field->hidinput->input);
726+
}
727+
cptkbd_data->middlebutton_state = 0;
692728
}
693-
cptkbd_data->middlebutton_state = 0;
729+
return 1;
694730
}
695-
return 1;
696731
}
697732

698733
if (usage->type == EV_KEY && usage->code == KEY_FN_ESC && value == 1) {
@@ -1126,22 +1161,6 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
11261161
}
11271162
hid_set_drvdata(hdev, cptkbd_data);
11281163

1129-
/*
1130-
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
1131-
* regular keys (Compact only)
1132-
*/
1133-
if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD ||
1134-
hdev->product == USB_DEVICE_ID_LENOVO_CBTKBD) {
1135-
ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
1136-
if (ret)
1137-
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
1138-
}
1139-
1140-
/* Switch middle button to native mode */
1141-
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
1142-
if (ret)
1143-
hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
1144-
11451164
/* Set keyboard settings to known state */
11461165
cptkbd_data->middlebutton_state = 0;
11471166
cptkbd_data->fn_lock = true;
@@ -1264,6 +1283,24 @@ static int lenovo_probe(struct hid_device *hdev,
12641283
return ret;
12651284
}
12661285

1286+
#ifdef CONFIG_PM
1287+
static int lenovo_reset_resume(struct hid_device *hdev)
1288+
{
1289+
switch (hdev->product) {
1290+
case USB_DEVICE_ID_LENOVO_CUSBKBD:
1291+
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
1292+
if (hdev->type == HID_TYPE_USBMOUSE)
1293+
lenovo_features_set_cptkbd(hdev);
1294+
1295+
break;
1296+
default:
1297+
break;
1298+
}
1299+
1300+
return 0;
1301+
}
1302+
#endif
1303+
12671304
static void lenovo_remove_tpkbd(struct hid_device *hdev)
12681305
{
12691306
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
@@ -1380,6 +1417,9 @@ static struct hid_driver lenovo_driver = {
13801417
.raw_event = lenovo_raw_event,
13811418
.event = lenovo_event,
13821419
.report_fixup = lenovo_report_fixup,
1420+
#ifdef CONFIG_PM
1421+
.reset_resume = lenovo_reset_resume,
1422+
#endif
13831423
};
13841424
module_hid_driver(lenovo_driver);
13851425

0 commit comments

Comments
 (0)