linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] drivers: hid: renegotiate resolution multipliers with device after reset
@ 2025-10-07 20:35 Benedek Kupper
  0 siblings, 0 replies; only message in thread
From: Benedek Kupper @ 2025-10-07 20:35 UTC (permalink / raw)
  To: linux-input; +Cc: linux-kernel, bentiss, jikos, Benedek Kupper

The scroll resolution multipliers are set in the context of
hidinput_connect(), which is only called at probe time: when the host
changes the value on the device with a SET_REPORT(FEATURE), and the device
accepts it, these multipliers are stored on the host side, and used to
calculate the final scroll event values sent to userspace.

After a USB suspend, the resume operation on many hubs and chipsets
involve a USB reset signal as well. A reset on the device side clears all
previous state information, including the value of the multiplier report.
This reset is not handled by the multiplier handling logic, so what ends up
happening is the host is still expecting high-resolution scroll events,
but the device is reset to default resolution, making the effective,
user-perceived scroll speed incredibly slow.

The solution is to renegotiate the multiplier selection after each reset.

This is not the only bug related to the high-resolution scrolling
implementation in the kernel (the other one is
https://bugzilla.kernel.org/show_bug.cgi?id=220144), but for this one,
there is no device side workaround for,
leading to poor user experience with our product:
https://github.com/UltimateHackingKeyboard/firmware/issues/1155
https://github.com/UltimateHackingKeyboard/firmware/issues/1261
https://github.com/UltimateHackingKeyboard/firmware/pull/1355
This patch was tested by an affected user and has been reported to
fix the issue (see discussion in 1355).

Signed-off-by: Benedek Kupper <kupper.benedek@gmail.com>
---
 drivers/hid/hid-generic.c | 9 +++++++++
 drivers/hid/hid-input.c   | 7 +++++++
 include/linux/hid.h       | 1 +
 3 files changed, 17 insertions(+)

diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c
index 9e04c6d0fcc8..c2de916747de 100644
--- a/drivers/hid/hid-generic.c
+++ b/drivers/hid/hid-generic.c
@@ -70,6 +70,14 @@ static int hid_generic_probe(struct hid_device *hdev,
 	return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 }
 
+static int hid_generic_reset_resume(struct hid_device *hdev)
+{
+	if (hdev->claimed & HID_CLAIMED_INPUT)
+		hidinput_reset_resume(hdev);
+
+	return 0;
+}
+
 static const struct hid_device_id hid_table[] = {
 	{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, HID_ANY_ID, HID_ANY_ID) },
 	{ }
@@ -81,6 +89,7 @@ static struct hid_driver hid_generic = {
 	.id_table = hid_table,
 	.match = hid_generic_match,
 	.probe = hid_generic_probe,
+	.reset_resume = hid_generic_reset_resume,
 };
 module_hid_driver(hid_generic);
 
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index f45f856a127f..3dd3822cc549 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -2382,6 +2382,13 @@ void hidinput_disconnect(struct hid_device *hid)
 }
 EXPORT_SYMBOL_GPL(hidinput_disconnect);
 
+void hidinput_reset_resume(struct hid_device *hid)
+{
+	/* renegotiate host-device shared state after reset */
+	hidinput_change_resolution_multipliers(hid);
+}
+EXPORT_SYMBOL_GPL(hidinput_reset_resume);
+
 #ifdef CONFIG_HID_KUNIT_TEST
 #include "hid-input-test.c"
 #endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 2cc4f1e4ea96..b78fb55ea85e 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -953,6 +953,7 @@ extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct h
 extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
 extern int hidinput_connect(struct hid_device *hid, unsigned int force);
 extern void hidinput_disconnect(struct hid_device *);
+void hidinput_reset_resume(struct hid_device *hid);
 
 struct hid_field *hid_find_field(struct hid_device *hdev, unsigned int report_type,
 				 unsigned int application, unsigned int usage);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2025-10-07 20:36 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-07 20:35 [PATCH] drivers: hid: renegotiate resolution multipliers with device after reset Benedek Kupper

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).