On 2023-09-21 10:21, Martin Kepplinger wrote:
After system suspend the middle-button mode is being reset to compatibility mode which simply breaks functionality for the devices where native mode is configured during probe(). Fix this by setting native mode in reset_resume() for the appropriate devices. Fixes: 94eefa271323 ("HID: lenovo: Use native middle-button mode for compact keyboards") Signed-off-by: Martin Kepplinger <martink@xxxxxxxxx> --- drivers/hid/hid-lenovo.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 44763c0da444..d20562b9eca6 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -1344,6 +1344,28 @@ static int lenovo_input_configured(struct hid_device *hdev, return 0; } +static int __maybe_unused lenovo_resume(struct hid_device *hdev) +{ + int ret; + + switch (hdev->product) { + case USB_DEVICE_ID_LENOVO_CUSBKBD: + case USB_DEVICE_ID_LENOVO_CBTKBD: + case USB_DEVICE_ID_LENOVO_TPIIUSBKBD: + case USB_DEVICE_ID_LENOVO_TPIIBTKBD: + /* Switch middle button to native mode again */ + ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
This will only reset the middle button state and not the Function key state, which I believe has similar problems. This was my attempt at solving this:
https://github.com/lentinj/linux/commit/f1c4e2de780abf8526bcdc9496c463f1ff4fe53b
...which should ensure everything is in a consistent state with what the kernel expects.
I never submitted this since sending commands was sporadically resulting in timeouts, although I'm fairly sure it was unrelated to this patch, and quite possibly a hardware problem with my keyboard. I'd be interested to know how you get on.
Also, the above will send the command to both the USB keyboard & mouse devices, only the mouse will respond. So worth prepending something like:
if (((hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD) || (hdev->product == USB_DEVICE_ID_LENOVO_TPIIUSBKBD)) && hdev->type != HID_TYPE_USBMOUSE) { hid_dbg(hdev, "Ignoring keyboard half of device\n"); return 0; } ...to avoid sending known-useless messages.
+ if (ret) + hid_warn(hdev, "Failed to switch middle button: %d\n", + ret); + break; + default: + ret = 0; + break; + } + + return ret; +} static const struct hid_device_id lenovo_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, @@ -1380,6 +1402,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_resume, +#endif }; module_hid_driver(lenovo_driver);