hid: lenovo: Resend all settings on reset_resume for compact keyboards

commit 2f2bd7cbd1 upstream.

The USB Compact Keyboard variant requires a reset_resume function to
restore keyboard configuration after a suspend in some situations. Move
configuration normally done on probe to lenovo_features_set_cptkbd(), then
recycle this for use on reset_resume.

Without, the keyboard and driver would end up in an inconsistent state,
breaking middle-button scrolling amongst other problems, and twiddling
sysfs values wouldn't help as the middle-button mode won't be set until
the driver is reloaded.

Tested on a USB and Bluetooth Thinkpad Compact Keyboard.

CC: stable@vger.kernel.org
Fixes: 94eefa2713 ("HID: lenovo: Use native middle-button mode for compact keyboards")
Signed-off-by: Jamie Lentin <jm@lentin.co.uk>
Signed-off-by: Martin Kepplinger <martink@posteo.de>
Link: https://lore.kernel.org/r/20231002150914.22101-1-martink@posteo.de
Signed-off-by: Benjamin Tissoires <bentiss@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Jamie Lentin 2023-10-02 15:09:14 +00:00 committed by Greg Kroah-Hartman
parent 496c5ca14f
commit 19ed109e1a
1 changed files with 34 additions and 16 deletions

View File

@ -526,6 +526,19 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
int ret;
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
/*
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
* regular keys
*/
ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
if (ret)
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
/* Switch middle button to native mode */
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
if (ret)
hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
if (ret)
hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
@ -1148,22 +1161,6 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
}
hid_set_drvdata(hdev, cptkbd_data);
/*
* Tell the keyboard a driver understands it, and turn F7, F9, F11 into
* regular keys (Compact only)
*/
if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD ||
hdev->product == USB_DEVICE_ID_LENOVO_CBTKBD) {
ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
if (ret)
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
}
/* Switch middle button to native mode */
ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
if (ret)
hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
/* Set keyboard settings to known state */
cptkbd_data->middlebutton_state = 0;
cptkbd_data->fn_lock = true;
@ -1286,6 +1283,24 @@ err:
return ret;
}
#ifdef CONFIG_PM
static int lenovo_reset_resume(struct hid_device *hdev)
{
switch (hdev->product) {
case USB_DEVICE_ID_LENOVO_CUSBKBD:
case USB_DEVICE_ID_LENOVO_TPIIUSBKBD:
if (hdev->type == HID_TYPE_USBMOUSE)
lenovo_features_set_cptkbd(hdev);
break;
default:
break;
}
return 0;
}
#endif
static void lenovo_remove_tpkbd(struct hid_device *hdev)
{
struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
@ -1402,6 +1417,9 @@ static struct hid_driver lenovo_driver = {
.raw_event = lenovo_raw_event,
.event = lenovo_event,
.report_fixup = lenovo_report_fixup,
#ifdef CONFIG_PM
.reset_resume = lenovo_reset_resume,
#endif
};
module_hid_driver(lenovo_driver);