* [PATCH] HID: logitech-dj: forward Bolt receiver input to the dj child device
@ 2026-09-01 16:22 Grégoire Stein via B4 Relay
2026-09-01 16:37 ` sashiko-bot
2026-09-01 19:29 ` Erik Håkansson
0 siblings, 2 replies; 4+ messages in thread
From: Grégoire Stein via B4 Relay @ 2026-09-01 16:22 UTC (permalink / raw)
To: Filipe Laíns, Jiri Kosina, Benjamin Tissoires,
Erik Håkansson
Cc: linux-input, linux-kernel, Grégoire Stein
From: Grégoire Stein <greyxor@protonmail.com>
Since Bolt receivers got support in hid-logitech-dj, one detent of the
wheel on an MX Master 4 scrolls 2 to 5 times too far.
For Bolt only LOGITECH_DJ_INTERFACE_NUMBER is kept as a dj interface and
everything else is left as a generic-hid device. Interface 1 therefore
registers an input device of its own, and the paired device's reports
are never forwarded to the dj child device, which ends up receiving
nothing at all.
hid-logitech-hidpp still binds to that child and enables hi-res
scrolling through feature 0x2121. The wheel starts emitting several
ticks per detent, but hidpp_event() applies the multiplier on an input
device that never sees a report. The ticks reach userspace over the
receiver's own mouse interface, where hid-input has no resolution
multiplier and scales each one by 120:
[Logitech USB Receiver Mouse] REL_WHEEL=2 REL_WHEEL_HI_RES=240
[Logitech USB Receiver Mouse] REL_WHEEL=3 REL_WHEEL_HI_RES=360
[Logitech Wireless Mouse PID:b042] (nothing)
Interface 0 is the keyboard endpoint, interface 1 the mouse endpoint and
interface 2 carries DJ/HID++, which is the same layout as the other
HID++ receivers. Set no_dj_interfaces to 3 and drop the special case, so
interfaces 0 and 1 are claimed by the dj driver and their reports get
forwarded to the child, where the multiplier is applied.
Bolt support was tested with a keyboard, and a keyboard has no wheel
multiplier to get wrong, which is probably why this was missed.
Fixes: 022eb347ff3a ("HID: logitech: add Bolt receiver support for Logitech HID++ devices")
Signed-off-by: Grégoire Stein <greyxor@protonmail.com>
---
Tested on 7.3-rc1 with an MX Master 4 on a Bolt receiver (046d:c548).
Before the patch one detent gives REL_WHEEL 2-5 / REL_WHEEL_HI_RES
240-600 on the receiver's own mouse endpoint, and the dj child device
gets no reports at all. After it everything comes in on the child device
at 120 per detent.
checkpatch says "trailing statements should be on next line" for the
added case, it is written like the eight cases already in that switch.
I only have a mouse here. Erik, could you check that the MX Keys for
Business still works with this applied?
---
drivers/hid/hid-logitech-dj.c | 22 +++++-----------------
1 file changed, 5 insertions(+), 17 deletions(-)
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 1d619d2345e1..5a8f63ced627 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -1907,9 +1907,6 @@ static int logi_dj_probe(struct hid_device *hdev,
* treat these as logitech-dj interfaces then this causes input events
* reported through this extra interface to not be reported correctly.
* To avoid this, we treat these as generic-hid devices.
- *
- * Bolt receivers only use LOGITECH_DJ_INTERFACE_NUMBER for receiver
- * reporting. Treat all other Bolt interfaces as generic-hid devices.
*/
switch (id->driver_data) {
case recvr_type_dj: no_dj_interfaces = 3; break;
@@ -1920,23 +1917,14 @@ static int logi_dj_probe(struct hid_device *hdev,
case recvr_type_27mhz: no_dj_interfaces = 2; break;
case recvr_type_bluetooth: no_dj_interfaces = 2; break;
case recvr_type_dinovo: no_dj_interfaces = 2; break;
+ case recvr_type_bolt: no_dj_interfaces = 3; break;
}
if (hid_is_usb(hdev)) {
intf = to_usb_interface(hdev->dev.parent);
- if (intf) {
- bool generic_hid_interface;
-
- if (id->driver_data == recvr_type_bolt)
- generic_hid_interface =
- intf->altsetting->desc.bInterfaceNumber !=
- LOGITECH_DJ_INTERFACE_NUMBER;
- else
- generic_hid_interface =
- intf->altsetting->desc.bInterfaceNumber >= no_dj_interfaces;
- if (generic_hid_interface) {
- hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
- return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
- }
+ if (intf && intf->altsetting->desc.bInterfaceNumber >=
+ no_dj_interfaces) {
+ hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
+ return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
}
}
---
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
change-id: 20260901-bolt-scroll-fix-0f81412fa351
Best regards,
--
Grégoire Stein <greyxor@protonmail.com>
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] HID: logitech-dj: forward Bolt receiver input to the dj child device
2026-09-01 16:22 [PATCH] HID: logitech-dj: forward Bolt receiver input to the dj child device Grégoire Stein via B4 Relay
@ 2026-09-01 16:37 ` sashiko-bot
2026-09-01 17:55 ` GreyXor
2026-09-01 19:29 ` Erik Håkansson
1 sibling, 1 reply; 4+ messages in thread
From: sashiko-bot @ 2026-09-01 16:37 UTC (permalink / raw)
To: Grégoire Stein; +Cc: dmitry.torokhov, linux-input
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
New issues:
- [High] The shared `djrcv_dev->unnumbered_application` field is overwritten when multiple interfaces of a Bolt receiver use unnumbered reports, leading to corrupted input routing.
Pre-existing issues:
- [Critical] Worker teardown race leading to a Use-After-Free of `djrcv_dev` when the device is unbound or disconnected.
--
commit 8ddfaefb25fbb11d3135bd6028112cdebd298409
Author: Grégoire Stein <greyxor@protonmail.com>
HID: logitech-dj: forward Bolt receiver input to the dj child device
This patch drops the special case for Bolt receivers and sets no_dj_interfaces
to 3, allowing interfaces 0 and 1 to be claimed by the dj driver so their
reports get properly forwarded to the child device.
> diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
> index 1d619d2345e12..5a8f63ced627c 100644
> --- a/drivers/hid/hid-logitech-dj.c
> +++ b/drivers/hid/hid-logitech-dj.c
> @@ -1907,9 +1907,6 @@ static int logi_dj_probe(struct hid_device *hdev,
> * treat these as logitech-dj interfaces then this causes input events
> * reported through this extra interface to not be reported correctly.
> * To avoid this, we treat these as generic-hid devices.
> - *
> - * Bolt receivers only use LOGITECH_DJ_INTERFACE_NUMBER for receiver
> - * reporting. Treat all other Bolt interfaces as generic-hid devices.
> */
> switch (id->driver_data) {
> case recvr_type_dj: no_dj_interfaces = 3; break;
> @@ -1920,23 +1917,14 @@ static int logi_dj_probe(struct hid_device *hdev,
> case recvr_type_27mhz: no_dj_interfaces = 2; break;
> case recvr_type_bluetooth: no_dj_interfaces = 2; break;
> case recvr_type_dinovo: no_dj_interfaces = 2; break;
> + case recvr_type_bolt: no_dj_interfaces = 3; break;
> }
> if (hid_is_usb(hdev)) {
> intf = to_usb_interface(hdev->dev.parent);
> - if (intf) {
> - bool generic_hid_interface;
> -
> - if (id->driver_data == recvr_type_bolt)
> - generic_hid_interface =
> - intf->altsetting->desc.bInterfaceNumber !=
> - LOGITECH_DJ_INTERFACE_NUMBER;
> - else
> - generic_hid_interface =
> - intf->altsetting->desc.bInterfaceNumber >= no_dj_interfaces;
> - if (generic_hid_interface) {
> - hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
> - return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
> - }
> + if (intf && intf->altsetting->desc.bInterfaceNumber >=
> + no_dj_interfaces) {
> + hdev->quirks |= HID_QUIRK_INPUT_PER_APP;
> + return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
> }
> }
[Severity: High]
Does this code overwrite the shared djrcv_dev->unnumbered_application field
when multiple interfaces of a Bolt receiver use unnumbered reports?
By dropping the special case for Bolt, both the keyboard (interface 0) and
mouse (interface 1) bind to hid-logitech-dj. Because they share the same
dj_receiver_dev struct, the sequentially probed mouse interface overwrites
unnumbered_application with HID_GD_MOUSE:
drivers/hid/hid-logitech-dj.c:logi_dj_probe() {
...
if (!input_report_enum->numbered)
djrcv_dev->unnumbered_application = rep->application;
...
}
When unnumbered keyboard reports arrive on interface 0, does this cause them to
be incorrectly routed and formatted as mouse reports in logi_dj_raw_event()?
[Severity: Critical]
This is a pre-existing issue, but is there a use-after-free regression during
device teardown in logi_dj_remove()?
In logi_dj_remove(), the asynchronous work is cancelled before the hardware
is stopped:
drivers/hid/hid-logitech-dj.c:logi_dj_remove() {
...
cancel_work_sync(&djrcv_dev->work);
hid_hw_close(hdev);
hid_hw_stop(hdev);
...
}
Since the hardware polling is not yet stopped, an incoming hardware interrupt
can re-queue the work via schedule_work() in
logi_dj_recv_queue_unknown_work() just before djrcv_dev is freed by
dj_put_receiver_dev().
Does this leave a window for incoming interrupts to queue freed work items,
leading to a use-after-free when the delayedwork_callback executes and
accesses djrcv_dev->lock?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260901-bolt-scroll-fix-v1-1-58bca7ae487f@protonmail.com?part=1
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] HID: logitech-dj: forward Bolt receiver input to the dj child device
2026-09-01 16:37 ` sashiko-bot
@ 2026-09-01 17:55 ` GreyXor
0 siblings, 0 replies; 4+ messages in thread
From: GreyXor @ 2026-09-01 17:55 UTC (permalink / raw)
To: sashiko-reviews; +Cc: dmitry.torokhov, linux-input
On Tue, Sep 01, 2026 at 04:37:31PM +0000, sashiko-bot@kernel.org wrote:
> [Severity: High]
> Does this code overwrite the shared djrcv_dev->unnumbered_application field
> when multiple interfaces of a Bolt receiver use unnumbered reports?
No. That assignment is guarded by:
if (!input_report_enum->numbered)
djrcv_dev->unnumbered_application = rep->application;
and only interface 0 of the Bolt receiver is unnumbered. Report
descriptors as read from the hardware (046d:c548):
interface 0 no report IDs (keyboard, unnumbered)
interface 1 IDs 2,3,4,11,60,61 (mouse)
interface 2 IDs 16,17 (DJ/HID++)
interface 3 IDs 40,41,42
Interface 1 is numbered, so it never reaches the assignment. Interface 0
is the only writer and sets HID_GD_KEYBOARD once, so there is no second
writer and no overwrite.
This is also why the patch is needed for keyboards: before it, interface 0
returned early as a generic-hid device and unnumbered_application was
never set at all, so a Bolt keyboard's unnumbered reports could not be
forwarded to the child device.
recvr_type_dj and recvr_type_gaming_hidpp have used no_dj_interfaces = 3
with this same interface layout for years.
> [Severity: Critical]
> This is a pre-existing issue, but is there a use-after-free regression during
> device teardown in logi_dj_remove()?
This patch does not touch logi_dj_remove(). The requeue is already
guarded: logi_dj_remove() clears djrcv_dev->ready under djrcv_dev->lock
before calling cancel_work_sync(), and delayedwork_callback() returns
early on !djrcv_dev->ready.
Thanks,
Grégoire
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] HID: logitech-dj: forward Bolt receiver input to the dj child device
2026-09-01 16:22 [PATCH] HID: logitech-dj: forward Bolt receiver input to the dj child device Grégoire Stein via B4 Relay
2026-09-01 16:37 ` sashiko-bot
@ 2026-09-01 19:29 ` Erik Håkansson
1 sibling, 0 replies; 4+ messages in thread
From: Erik Håkansson @ 2026-09-01 19:29 UTC (permalink / raw)
To: greyxor, Filipe Laíns, Jiri Kosina, Benjamin Tissoires
Cc: linux-input, linux-kernel, Kateřina Medvědová
Hi!
> Interface 0 is the keyboard endpoint, interface 1 the mouse endpoint and
> interface 2 carries DJ/HID++, which is the same layout as the other
> HID++ receivers. Set no_dj_interfaces to 3 and drop the special case, so
> interfaces 0 and 1 are claimed by the dj driver and their reports get
> forwarded to the child, where the multiplier is applied.
Thanks for finding this!
I can confirm that my MX Keys Business work fine after your patch.
However, your patch basically reverts to what I had in v1 of my patch.
The reason for the change was that Katerina Medvedova reported that
without the special treatment for Bolt, her mouse became very
sensitive, including phantom scrolls, and her keypresses were scrambled.
> Bolt support was tested with a keyboard, and a keyboard has no wheel
> multiplier to get wrong, which is probably why this was missed.
Katerina, you tested with a mouse and two different keyboards, I believe?
Can you perhaps test again with this patch to see if your issues remain
or if there was something else that caused it.
Best regards,
Erik Håkansson
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-01 19:29 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-01 16:22 [PATCH] HID: logitech-dj: forward Bolt receiver input to the dj child device Grégoire Stein via B4 Relay
2026-09-01 16:37 ` sashiko-bot
2026-09-01 17:55 ` GreyXor
2026-09-01 19:29 ` Erik Håkansson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox