Commit 2f2bd7cb authored by Jamie Lentin's avatar Jamie Lentin Committed by Benjamin Tissoires
Browse files

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



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: 94eefa27 ("HID: lenovo: Use native middle-button mode for compact keyboards")
Signed-off-by: default avatarJamie Lentin <jm@lentin.co.uk>
Signed-off-by: default avatarMartin Kepplinger <martink@posteo.de>
Link: https://lore.kernel.org/r/20231002150914.22101-1-martink@posteo.de


Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
parent 46a0a2c9
Loading
Loading
Loading
Loading
+34 −16
Original line number Diff line number Diff line
@@ -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 @@ static int lenovo_probe(struct hid_device *hdev,
	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);