Linux Input/HID development
 help / color / mirror / Atom feed
* [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master
@ 2026-09-04  3:48 Rafael Passos
  2026-09-04  4:02 ` sashiko-bot
  2026-09-04  7:44 ` Alexey Zagorodnikov
  0 siblings, 2 replies; 8+ messages in thread
From: Rafael Passos @ 2026-09-04  3:48 UTC (permalink / raw)
  To: lains, hadess, jikos, bentiss, erikhakan
  Cc: Shuah Khan, Brigham Campbell, Jori Koolstra, Rafael Passos,
	linux-input

The new added support for Logitech HID++ caused this mouse to
scroll too far for each tic when using the USB dongle (Bolt).
Previously, this mouse was handled as hid_generic over the Bold
connection, and logitech-hidpp when over Bluetooth.

Cause:
Over the Bolt receiver, the mouse reports  are forwarded over the generic
interface 1, instead of the new HID++ child device. The generic hid does
now know about the hi-res scrolling used by the HID++.
In my tests, I discovered this mouse has a multiplier factor of 15. This
multiplier is only handled by the logitech-hidpp driver. When piped to
hid_generic, the "hi-res" value was piped to a "low-res" field, making
the scroll unbearable.

The fix routes the wheel using the HID++, so the ticks are scaled by the
multiplier and correctly reported as a hi-res event.

I also had to move the hidpp_is_bolt_child function up, to use it in the
hidpp_connect_event function, where the gate for
hidpp_initialize_hires_scroll function lives.

Tested with:
- Logitech MX Master 3S (mouse) via Bolt receiver and Bluetooth.

Fixes: 022eb347ff3a ("HID: logitech: add Bolt receiver support for Logitech HID++ devices")
Signed-off-by: Rafael Passos <rafael@rcpassos.me>
---

Hi,
I decided to send this patch as soon as I made it work, to try to make
it into this fix cycle.

I do not have other devices to test this with.
It would *be great* to have other users testing this.

Lastly, I decided to make all the changes in a single patch. 
But I can break it up if asked.

Thanks,
Rafael


 drivers/hid/hid-logitech-hidpp.c | 47 ++++++++++++++++++++++----------
 1 file changed, 32 insertions(+), 15 deletions(-)

diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 1504de32b1c84..960543bfd5ea1 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -3900,6 +3900,19 @@ static int hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp,
 	return 1;
 }
 
+static bool hidpp_is_bolt_child(struct hid_device *hdev)
+{
+	struct device *parent = hdev->dev.parent;
+	struct hid_device *receiver_hdev;
+
+	if (!parent)
+		return false;
+
+	receiver_hdev = to_hid_device(parent);
+	return receiver_hdev->vendor == USB_VENDOR_ID_LOGITECH &&
+	       receiver_hdev->product == USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER;
+}
+
 /* -------------------------------------------------------------------------- */
 /* High-resolution scroll wheels                                              */
 /* -------------------------------------------------------------------------- */
@@ -3910,7 +3923,9 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp)
 	u8 multiplier = 1;
 
 	if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) {
-		ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
+		bool use_hidpp = hidpp_is_bolt_child(hidpp->hid_dev);
+
+		ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, use_hidpp);
 		if (ret == 0)
 			ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
 	} else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL) {
@@ -3998,6 +4013,19 @@ static int hidpp20_hires_wheel_raw_event(struct hidpp_device *hidpp,
 		return 1;
 	}
 
+	/* wheel movement event: 16-bit signed delta in HID++ ticks */
+	if ((data[3] & 0xf0) == 0x00 && size >= 7 && hidpp->input &&
+	    hidpp->vertical_wheel_counter.wheel_multiplier) {
+		s16 delta = get_unaligned_be16(&data[5]);
+
+		if (delta) {
+			hidpp_scroll_counter_handle_scroll(hidpp->input,
+				&hidpp->vertical_wheel_counter, delta);
+			input_sync(hidpp->input);
+		}
+		return 1;
+	}
+
 	return 0;
 }
 
@@ -4405,19 +4433,6 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
 	return ret;
 }
 
-static bool hidpp_is_bolt_child(struct hid_device *hdev)
-{
-	struct device *parent = hdev->dev.parent;
-	struct hid_device *receiver_hdev;
-
-	if (!parent)
-		return false;
-
-	receiver_hdev = to_hid_device(parent);
-	return receiver_hdev->vendor == USB_VENDOR_ID_LOGITECH &&
-	       receiver_hdev->product == USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER;
-}
-
 static int hidpp_bolt_init(struct hidpp_device *hidpp)
 {
 	struct hid_device *hdev = hidpp->hid_dev;
@@ -4579,7 +4594,9 @@ static void hidpp_connect_event(struct work_struct *work)
 	}
 
 	hidpp_initialize_battery(hidpp);
-	if (!hid_is_usb(hidpp->hid_dev))
+
+	if (!hid_is_usb(hidpp->hid_dev) ||
+	    hidpp_is_bolt_child(hidpp->hid_dev))
 		hidpp_initialize_hires_scroll(hidpp);
 
 	/* forward current battery state */
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master
  2026-09-04  3:48 [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master Rafael Passos
@ 2026-09-04  4:02 ` sashiko-bot
  2026-09-04  7:44 ` Alexey Zagorodnikov
  1 sibling, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-09-04  4:02 UTC (permalink / raw)
  To: Rafael Passos; +Cc: linux-input, dmitry.torokhov

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Unconditional and improperly guarded cast of the parent device to `struct hid_device` in `hidpp_is_bolt_child()` causes type confusion and out-of-bounds memory access for Bluetooth and native USB devices.
- [High] Time-of-check to time-of-use (TOCTOU) data race between `hidpp20_hires_wheel_raw_event()` and `hidpp_connect_event()` leading to a Use-After-Free of `hidpp->input`.
--

commit 1aae454b03bbd4a45bdfdb3bc2a196f15d06fbfa
Author: Rafael Passos <rafael@rcpassos.me>

HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master

This commit fixes hi-res scrolling on the MX Master 3S when connected
via the Bolt receiver by routing wheel events through the HID++ driver
instead of hid_generic. It also adjusts initialization checks for Bolt
devices.

> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> index 1504de32b1c84..960543bfd5ea1 100644
> --- a/drivers/hid/hid-logitech-hidpp.c
> +++ b/drivers/hid/hid-logitech-hidpp.c
> @@ -3900,6 +3900,19 @@ static int hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp,
>  	return 1;
>  }
>  
> +static bool hidpp_is_bolt_child(struct hid_device *hdev)
> +{
> +	struct device *parent = hdev->dev.parent;
> +	struct hid_device *receiver_hdev;
> +
> +	if (!parent)
> +		return false;
> +
> +	receiver_hdev = to_hid_device(parent);
> +	return receiver_hdev->vendor == USB_VENDOR_ID_LOGITECH &&
> +	       receiver_hdev->product == USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER;
> +}
> +

[Severity: High]
Does this safely handle native USB devices? When this is called for a native
USB device, the parent device is a struct usb_interface, not a struct
hid_device. 

Using to_hid_device(parent) subtracts the container_of offset for a
hid_device from the dev pointer, resulting in a pointer well before the
allocated usb_interface structure. Accessing receiver_hdev->vendor will then
cause an out-of-bounds memory read.

[ ... ]

> @@ -3910,7 +3923,9 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp)
>  	u8 multiplier = 1;
>  
>  	if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) {
> -		ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
> +		bool use_hidpp = hidpp_is_bolt_child(hidpp->hid_dev);
> +

[Severity: High]
Could this unconditionally trigger the out-of-bounds read described above for
all HID++ 2.0 devices? This includes native USB and Bluetooth devices where
the parent is not a hid_device.

[ ... ]

> @@ -3998,6 +4013,19 @@ static int hidpp20_hires_wheel_raw_event(struct hidpp_device *hidpp,
>  		return 1;
>  	}
>  
> +	/* wheel movement event: 16-bit signed delta in HID++ ticks */
> +	if ((data[3] & 0xf0) == 0x00 && size >= 7 && hidpp->input &&
> +	    hidpp->vertical_wheel_counter.wheel_multiplier) {
> +		s16 delta = get_unaligned_be16(&data[5]);
> +
> +		if (delta) {
> +			hidpp_scroll_counter_handle_scroll(hidpp->input,
> +				&hidpp->vertical_wheel_counter, delta);

[Severity: High]
Is there a Time-of-Check to Time-of-Use (TOCTOU) race condition here?

Since hid_device_io_start() has already been called during probe, hardware
events can fire concurrently with hidpp_connect_event().

If this raw event handler checks hidpp->input and proceeds, but
concurrently hidpp_connect_event() encounters an error (e.g. from
input_register_device failing) and executes:

    hidpp->input = NULL;
    input_free_device(input);

Could this lockless dereference of hidpp->input in
hidpp_scroll_counter_handle_scroll() result in a use-after-free?

[ ... ]

> @@ -4579,7 +4594,9 @@ static void hidpp_connect_event(struct work_struct *work)
>  	}
>  
>  	hidpp_initialize_battery(hidpp);
> -	if (!hid_is_usb(hidpp->hid_dev))
> +
> +	if (!hid_is_usb(hidpp->hid_dev) ||
> +	    hidpp_is_bolt_child(hidpp->hid_dev))
>  		hidpp_initialize_hires_scroll(hidpp);

[Severity: High]
Could this also trigger the out-of-bounds read in hidpp_is_bolt_child() for
native USB devices?

For a native USB device, hid_is_usb() is true, so !hid_is_usb() evaluates to
false. This forces the logical OR to evaluate hidpp_is_bolt_child(), passing
the USB device into the function that unsafely casts the parent device.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260904034843.1340846-1-rafael@rcpassos.me?part=1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master
  2026-09-04  3:48 [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master Rafael Passos
  2026-09-04  4:02 ` sashiko-bot
@ 2026-09-04  7:44 ` Alexey Zagorodnikov
  2026-09-04 16:34   ` Erik Håkansson
  1 sibling, 1 reply; 8+ messages in thread
From: Alexey Zagorodnikov @ 2026-09-04  7:44 UTC (permalink / raw)
  To: Rafael Passos, lains, hadess, jikos, bentiss, erikhakan
  Cc: Shuah Khan, Brigham Campbell, Jori Koolstra, linux-input

Hi, thanks for your patch. I've tested it with my MX Master 4 + Bolt.

I'm not seeing a regression from mainline hid++ enabling, as in Solaar 
high-res scrolling was disabled in my config.

But with hid++ for Bolt enabled by mainline and your patch fixing 
high-res scroll init, I finally got smooth high-res scrolling on MX 
Master 4 via a Bolt connection.

Tested-by: Alexey Zagorodnikov <xglooom@gmail.com>

On 9/4/26 08:48, Rafael Passos wrote:
> The new added support for Logitech HID++ caused this mouse to
> scroll too far for each tic when using the USB dongle (Bolt).
> Previously, this mouse was handled as hid_generic over the Bold
> connection, and logitech-hidpp when over Bluetooth.
>
> Cause:
> Over the Bolt receiver, the mouse reports  are forwarded over the generic
> interface 1, instead of the new HID++ child device. The generic hid does
> now know about the hi-res scrolling used by the HID++.
> In my tests, I discovered this mouse has a multiplier factor of 15. This
> multiplier is only handled by the logitech-hidpp driver. When piped to
> hid_generic, the "hi-res" value was piped to a "low-res" field, making
> the scroll unbearable.
>
> The fix routes the wheel using the HID++, so the ticks are scaled by the
> multiplier and correctly reported as a hi-res event.
>
> I also had to move the hidpp_is_bolt_child function up, to use it in the
> hidpp_connect_event function, where the gate for
> hidpp_initialize_hires_scroll function lives.
>
> Tested with:
> - Logitech MX Master 3S (mouse) via Bolt receiver and Bluetooth.
>
> Fixes: 022eb347ff3a ("HID: logitech: add Bolt receiver support for Logitech HID++ devices")
> Signed-off-by: Rafael Passos <rafael@rcpassos.me>
> ---
>
> Hi,
> I decided to send this patch as soon as I made it work, to try to make
> it into this fix cycle.
>
> I do not have other devices to test this with.
> It would *be great* to have other users testing this.
>
> Lastly, I decided to make all the changes in a single patch.
> But I can break it up if asked.
>
> Thanks,
> Rafael
>
>
>   drivers/hid/hid-logitech-hidpp.c | 47 ++++++++++++++++++++++----------
>   1 file changed, 32 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
> index 1504de32b1c84..960543bfd5ea1 100644
> --- a/drivers/hid/hid-logitech-hidpp.c
> +++ b/drivers/hid/hid-logitech-hidpp.c
> @@ -3900,6 +3900,19 @@ static int hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp,
>   	return 1;
>   }
>   
> +static bool hidpp_is_bolt_child(struct hid_device *hdev)
> +{
> +	struct device *parent = hdev->dev.parent;
> +	struct hid_device *receiver_hdev;
> +
> +	if (!parent)
> +		return false;
> +
> +	receiver_hdev = to_hid_device(parent);
> +	return receiver_hdev->vendor == USB_VENDOR_ID_LOGITECH &&
> +	       receiver_hdev->product == USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER;
> +}
> +
>   /* -------------------------------------------------------------------------- */
>   /* High-resolution scroll wheels                                              */
>   /* -------------------------------------------------------------------------- */
> @@ -3910,7 +3923,9 @@ static int hi_res_scroll_enable(struct hidpp_device *hidpp)
>   	u8 multiplier = 1;
>   
>   	if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) {
> -		ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
> +		bool use_hidpp = hidpp_is_bolt_child(hidpp->hid_dev);
> +
> +		ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, use_hidpp);
>   		if (ret == 0)
>   			ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
>   	} else if (hidpp->capabilities & HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL) {
> @@ -3998,6 +4013,19 @@ static int hidpp20_hires_wheel_raw_event(struct hidpp_device *hidpp,
>   		return 1;
>   	}
>   
> +	/* wheel movement event: 16-bit signed delta in HID++ ticks */
> +	if ((data[3] & 0xf0) == 0x00 && size >= 7 && hidpp->input &&
> +	    hidpp->vertical_wheel_counter.wheel_multiplier) {
> +		s16 delta = get_unaligned_be16(&data[5]);
> +
> +		if (delta) {
> +			hidpp_scroll_counter_handle_scroll(hidpp->input,
> +				&hidpp->vertical_wheel_counter, delta);
> +			input_sync(hidpp->input);
> +		}
> +		return 1;
> +	}
> +
>   	return 0;
>   }
>   
> @@ -4405,19 +4433,6 @@ static int hidpp_initialize_battery(struct hidpp_device *hidpp)
>   	return ret;
>   }
>   
> -static bool hidpp_is_bolt_child(struct hid_device *hdev)
> -{
> -	struct device *parent = hdev->dev.parent;
> -	struct hid_device *receiver_hdev;
> -
> -	if (!parent)
> -		return false;
> -
> -	receiver_hdev = to_hid_device(parent);
> -	return receiver_hdev->vendor == USB_VENDOR_ID_LOGITECH &&
> -	       receiver_hdev->product == USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER;
> -}
> -
>   static int hidpp_bolt_init(struct hidpp_device *hidpp)
>   {
>   	struct hid_device *hdev = hidpp->hid_dev;
> @@ -4579,7 +4594,9 @@ static void hidpp_connect_event(struct work_struct *work)
>   	}
>   
>   	hidpp_initialize_battery(hidpp);
> -	if (!hid_is_usb(hidpp->hid_dev))
> +
> +	if (!hid_is_usb(hidpp->hid_dev) ||
> +	    hidpp_is_bolt_child(hidpp->hid_dev))
>   		hidpp_initialize_hires_scroll(hidpp);
>   
>   	/* forward current battery state */

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master
  2026-09-04  7:44 ` Alexey Zagorodnikov
@ 2026-09-04 16:34   ` Erik Håkansson
  2026-09-04 17:03     ` Benjamin Tissoires
  2026-09-04 18:17     ` Alexey Zagorodnikov
  0 siblings, 2 replies; 8+ messages in thread
From: Erik Håkansson @ 2026-09-04 16:34 UTC (permalink / raw)
  To: Alexey Zagorodnikov, Rafael Passos, lains, hadess, jikos, bentiss
  Cc: Shuah Khan, Brigham Campbell, Jori Koolstra, linux-input

Hi!
Is this the same issue as in
https://lore.kernel.org/linux-input/20260901-bolt-scroll-fix-v1-1-58bca7ae487f@protonmail.com/
The symptoms seem similar at least, and if so the approach to fixing
it in that case is to simply treat Bolt devices like previous DJ
devices, rather than having special treatment for Bolt.
Can you who have Bolt mice maybe test that patch too to see if it
solves the same issue?
Regards
Erik

On 9/4/26 09:44, Alexey Zagorodnikov wrote:
> Hi, thanks for your patch. I've tested it with my MX Master 4 + Bolt.
>
> I'm not seeing a regression from mainline hid++ enabling, as in Solaar 
> high-res scrolling was disabled in my config.
>
> But with hid++ for Bolt enabled by mainline and your patch fixing 
> high-res scroll init, I finally got smooth high-res scrolling on MX 
> Master 4 via a Bolt connection.
>
> Tested-by: Alexey Zagorodnikov <xglooom@gmail.com>
>
> On 9/4/26 08:48, Rafael Passos wrote:
>> The new added support for Logitech HID++ caused this mouse to
>> scroll too far for each tic when using the USB dongle (Bolt).
>> Previously, this mouse was handled as hid_generic over the Bold
>> connection, and logitech-hidpp when over Bluetooth.
>>
>> Cause:
>> Over the Bolt receiver, the mouse reports  are forwarded over the 
>> generic
>> interface 1, instead of the new HID++ child device. The generic hid does
>> now know about the hi-res scrolling used by the HID++.
>> In my tests, I discovered this mouse has a multiplier factor of 15. This
>> multiplier is only handled by the logitech-hidpp driver. When piped to
>> hid_generic, the "hi-res" value was piped to a "low-res" field, making
>> the scroll unbearable.
>>
>> The fix routes the wheel using the HID++, so the ticks are scaled by the
>> multiplier and correctly reported as a hi-res event.
>>
>> I also had to move the hidpp_is_bolt_child function up, to use it in the
>> hidpp_connect_event function, where the gate for
>> hidpp_initialize_hires_scroll function lives.
>>
>> Tested with:
>> - Logitech MX Master 3S (mouse) via Bolt receiver and Bluetooth.
>>
>> Fixes: 022eb347ff3a ("HID: logitech: add Bolt receiver support for 
>> Logitech HID++ devices")
>> Signed-off-by: Rafael Passos <rafael@rcpassos.me>
>> ---
>>
>> Hi,
>> I decided to send this patch as soon as I made it work, to try to make
>> it into this fix cycle.
>>
>> I do not have other devices to test this with.
>> It would *be great* to have other users testing this.
>>
>> Lastly, I decided to make all the changes in a single patch.
>> But I can break it up if asked.
>>
>> Thanks,
>> Rafael
>>
>>
>>   drivers/hid/hid-logitech-hidpp.c | 47 ++++++++++++++++++++++----------
>>   1 file changed, 32 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/hid/hid-logitech-hidpp.c 
>> b/drivers/hid/hid-logitech-hidpp.c
>> index 1504de32b1c84..960543bfd5ea1 100644
>> --- a/drivers/hid/hid-logitech-hidpp.c
>> +++ b/drivers/hid/hid-logitech-hidpp.c
>> @@ -3900,6 +3900,19 @@ static int 
>> hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp,
>>       return 1;
>>   }
>>   +static bool hidpp_is_bolt_child(struct hid_device *hdev)
>> +{
>> +    struct device *parent = hdev->dev.parent;
>> +    struct hid_device *receiver_hdev;
>> +
>> +    if (!parent)
>> +        return false;
>> +
>> +    receiver_hdev = to_hid_device(parent);
>> +    return receiver_hdev->vendor == USB_VENDOR_ID_LOGITECH &&
>> +           receiver_hdev->product == 
>> USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER;
>> +}
>> +
>>   /* 
>> -------------------------------------------------------------------------- 
>> */
>>   /* High-resolution scroll 
>> wheels                                              */
>>   /* 
>> -------------------------------------------------------------------------- 
>> */
>> @@ -3910,7 +3923,9 @@ static int hi_res_scroll_enable(struct 
>> hidpp_device *hidpp)
>>       u8 multiplier = 1;
>>         if (hidpp->capabilities & 
>> HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) {
>> -        ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
>> +        bool use_hidpp = hidpp_is_bolt_child(hidpp->hid_dev);
>> +
>> +        ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, use_hidpp);
>>           if (ret == 0)
>>               ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
>>       } else if (hidpp->capabilities & 
>> HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL) {
>> @@ -3998,6 +4013,19 @@ static int 
>> hidpp20_hires_wheel_raw_event(struct hidpp_device *hidpp,
>>           return 1;
>>       }
>>   +    /* wheel movement event: 16-bit signed delta in HID++ ticks */
>> +    if ((data[3] & 0xf0) == 0x00 && size >= 7 && hidpp->input &&
>> +        hidpp->vertical_wheel_counter.wheel_multiplier) {
>> +        s16 delta = get_unaligned_be16(&data[5]);
>> +
>> +        if (delta) {
>> +            hidpp_scroll_counter_handle_scroll(hidpp->input,
>> +                &hidpp->vertical_wheel_counter, delta);
>> +            input_sync(hidpp->input);
>> +        }
>> +        return 1;
>> +    }
>> +
>>       return 0;
>>   }
>>   @@ -4405,19 +4433,6 @@ static int hidpp_initialize_battery(struct 
>> hidpp_device *hidpp)
>>       return ret;
>>   }
>>   -static bool hidpp_is_bolt_child(struct hid_device *hdev)
>> -{
>> -    struct device *parent = hdev->dev.parent;
>> -    struct hid_device *receiver_hdev;
>> -
>> -    if (!parent)
>> -        return false;
>> -
>> -    receiver_hdev = to_hid_device(parent);
>> -    return receiver_hdev->vendor == USB_VENDOR_ID_LOGITECH &&
>> -           receiver_hdev->product == 
>> USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER;
>> -}
>> -
>>   static int hidpp_bolt_init(struct hidpp_device *hidpp)
>>   {
>>       struct hid_device *hdev = hidpp->hid_dev;
>> @@ -4579,7 +4594,9 @@ static void hidpp_connect_event(struct 
>> work_struct *work)
>>       }
>>         hidpp_initialize_battery(hidpp);
>> -    if (!hid_is_usb(hidpp->hid_dev))
>> +
>> +    if (!hid_is_usb(hidpp->hid_dev) ||
>> +        hidpp_is_bolt_child(hidpp->hid_dev))
>>           hidpp_initialize_hires_scroll(hidpp);
>>         /* forward current battery state */

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master
  2026-09-04 16:34   ` Erik Håkansson
@ 2026-09-04 17:03     ` Benjamin Tissoires
  2026-09-04 18:20       ` Alexey Zagorodnikov
  2026-09-04 18:17     ` Alexey Zagorodnikov
  1 sibling, 1 reply; 8+ messages in thread
From: Benjamin Tissoires @ 2026-09-04 17:03 UTC (permalink / raw)
  To: Erik Håkansson
  Cc: Alexey Zagorodnikov, Rafael Passos, lains, hadess, jikos,
	Shuah Khan, Brigham Campbell, Jori Koolstra, linux-input

On Sep 04 2026, Erik Håkansson wrote:
> Hi!
> Is this the same issue as in
> https://lore.kernel.org/linux-input/20260901-bolt-scroll-fix-v1-1-58bca7ae487f@protonmail.com/
> The symptoms seem similar at least, and if so the approach to fixing
> it in that case is to simply treat Bolt devices like previous DJ
> devices, rather than having special treatment for Bolt.
> Can you who have Bolt mice maybe test that patch too to see if it
> solves the same issue?

FWIW, my initial decision a few years back when Bolt was introduced was
to not include it in the kernel, because there are too many things it's
missing, the most problematic one being that we don't know which device
sends which event.

So basically, there is a chance that the driver sets high-resolution
scrolling on a bolt device, when 2 mice are connected, and one is
capable of it and the other is not. This is unlikely to happen, but is
hard to solve in the kernel.

So I'm happy to wait for testing and patches, but I would also like a
conclusion where bolt doesn't belong to the kernel, and we just revert
the inclusion of the receiver in the dj driver.

Cheers,
Benjamin

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master
  2026-09-04 16:34   ` Erik Håkansson
  2026-09-04 17:03     ` Benjamin Tissoires
@ 2026-09-04 18:17     ` Alexey Zagorodnikov
  2026-09-04 20:21       ` Rafael Passos
  1 sibling, 1 reply; 8+ messages in thread
From: Alexey Zagorodnikov @ 2026-09-04 18:17 UTC (permalink / raw)
  To: Erik Håkansson, Rafael Passos, lains, hadess, jikos, bentiss
  Cc: Shuah Khan, Brigham Campbell, Jori Koolstra, linux-input

I've tried your patch, and MX Master 4 + Bolt goes crazy, it moves on 
vertical with very high speed, and very very slow on horizontal.

On 9/4/26 21:34, Erik Håkansson wrote:
> Hi!
> Is this the same issue as in
> https://lore.kernel.org/linux-input/20260901-bolt-scroll-fix-v1-1-58bca7ae487f@protonmail.com/ 
>
> The symptoms seem similar at least, and if so the approach to fixing
> it in that case is to simply treat Bolt devices like previous DJ
> devices, rather than having special treatment for Bolt.
> Can you who have Bolt mice maybe test that patch too to see if it
> solves the same issue?
> Regards
> Erik
>
> On 9/4/26 09:44, Alexey Zagorodnikov wrote:
>> Hi, thanks for your patch. I've tested it with my MX Master 4 + Bolt.
>>
>> I'm not seeing a regression from mainline hid++ enabling, as in 
>> Solaar high-res scrolling was disabled in my config.
>>
>> But with hid++ for Bolt enabled by mainline and your patch fixing 
>> high-res scroll init, I finally got smooth high-res scrolling on MX 
>> Master 4 via a Bolt connection.
>>
>> Tested-by: Alexey Zagorodnikov <xglooom@gmail.com>
>>
>> On 9/4/26 08:48, Rafael Passos wrote:
>>> The new added support for Logitech HID++ caused this mouse to
>>> scroll too far for each tic when using the USB dongle (Bolt).
>>> Previously, this mouse was handled as hid_generic over the Bold
>>> connection, and logitech-hidpp when over Bluetooth.
>>>
>>> Cause:
>>> Over the Bolt receiver, the mouse reports  are forwarded over the 
>>> generic
>>> interface 1, instead of the new HID++ child device. The generic hid 
>>> does
>>> now know about the hi-res scrolling used by the HID++.
>>> In my tests, I discovered this mouse has a multiplier factor of 15. 
>>> This
>>> multiplier is only handled by the logitech-hidpp driver. When piped to
>>> hid_generic, the "hi-res" value was piped to a "low-res" field, making
>>> the scroll unbearable.
>>>
>>> The fix routes the wheel using the HID++, so the ticks are scaled by 
>>> the
>>> multiplier and correctly reported as a hi-res event.
>>>
>>> I also had to move the hidpp_is_bolt_child function up, to use it in 
>>> the
>>> hidpp_connect_event function, where the gate for
>>> hidpp_initialize_hires_scroll function lives.
>>>
>>> Tested with:
>>> - Logitech MX Master 3S (mouse) via Bolt receiver and Bluetooth.
>>>
>>> Fixes: 022eb347ff3a ("HID: logitech: add Bolt receiver support for 
>>> Logitech HID++ devices")
>>> Signed-off-by: Rafael Passos <rafael@rcpassos.me>
>>> ---
>>>
>>> Hi,
>>> I decided to send this patch as soon as I made it work, to try to make
>>> it into this fix cycle.
>>>
>>> I do not have other devices to test this with.
>>> It would *be great* to have other users testing this.
>>>
>>> Lastly, I decided to make all the changes in a single patch.
>>> But I can break it up if asked.
>>>
>>> Thanks,
>>> Rafael
>>>
>>>
>>>   drivers/hid/hid-logitech-hidpp.c | 47 
>>> ++++++++++++++++++++++----------
>>>   1 file changed, 32 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/drivers/hid/hid-logitech-hidpp.c 
>>> b/drivers/hid/hid-logitech-hidpp.c
>>> index 1504de32b1c84..960543bfd5ea1 100644
>>> --- a/drivers/hid/hid-logitech-hidpp.c
>>> +++ b/drivers/hid/hid-logitech-hidpp.c
>>> @@ -3900,6 +3900,19 @@ static int 
>>> hidpp10_consumer_keys_raw_event(struct hidpp_device *hidpp,
>>>       return 1;
>>>   }
>>>   +static bool hidpp_is_bolt_child(struct hid_device *hdev)
>>> +{
>>> +    struct device *parent = hdev->dev.parent;
>>> +    struct hid_device *receiver_hdev;
>>> +
>>> +    if (!parent)
>>> +        return false;
>>> +
>>> +    receiver_hdev = to_hid_device(parent);
>>> +    return receiver_hdev->vendor == USB_VENDOR_ID_LOGITECH &&
>>> +           receiver_hdev->product == 
>>> USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER;
>>> +}
>>> +
>>>   /* 
>>> -------------------------------------------------------------------------- 
>>> */
>>>   /* High-resolution scroll 
>>> wheels                                              */
>>>   /* 
>>> -------------------------------------------------------------------------- 
>>> */
>>> @@ -3910,7 +3923,9 @@ static int hi_res_scroll_enable(struct 
>>> hidpp_device *hidpp)
>>>       u8 multiplier = 1;
>>>         if (hidpp->capabilities & 
>>> HIDPP_CAPABILITY_HIDPP20_HI_RES_WHEEL) {
>>> -        ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, false);
>>> +        bool use_hidpp = hidpp_is_bolt_child(hidpp->hid_dev);
>>> +
>>> +        ret = hidpp_hrw_set_wheel_mode(hidpp, false, true, use_hidpp);
>>>           if (ret == 0)
>>>               ret = hidpp_hrw_get_wheel_capability(hidpp, &multiplier);
>>>       } else if (hidpp->capabilities & 
>>> HIDPP_CAPABILITY_HIDPP20_HI_RES_SCROLL) {
>>> @@ -3998,6 +4013,19 @@ static int 
>>> hidpp20_hires_wheel_raw_event(struct hidpp_device *hidpp,
>>>           return 1;
>>>       }
>>>   +    /* wheel movement event: 16-bit signed delta in HID++ ticks */
>>> +    if ((data[3] & 0xf0) == 0x00 && size >= 7 && hidpp->input &&
>>> +        hidpp->vertical_wheel_counter.wheel_multiplier) {
>>> +        s16 delta = get_unaligned_be16(&data[5]);
>>> +
>>> +        if (delta) {
>>> + hidpp_scroll_counter_handle_scroll(hidpp->input,
>>> +                &hidpp->vertical_wheel_counter, delta);
>>> +            input_sync(hidpp->input);
>>> +        }
>>> +        return 1;
>>> +    }
>>> +
>>>       return 0;
>>>   }
>>>   @@ -4405,19 +4433,6 @@ static int hidpp_initialize_battery(struct 
>>> hidpp_device *hidpp)
>>>       return ret;
>>>   }
>>>   -static bool hidpp_is_bolt_child(struct hid_device *hdev)
>>> -{
>>> -    struct device *parent = hdev->dev.parent;
>>> -    struct hid_device *receiver_hdev;
>>> -
>>> -    if (!parent)
>>> -        return false;
>>> -
>>> -    receiver_hdev = to_hid_device(parent);
>>> -    return receiver_hdev->vendor == USB_VENDOR_ID_LOGITECH &&
>>> -           receiver_hdev->product == 
>>> USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER;
>>> -}
>>> -
>>>   static int hidpp_bolt_init(struct hidpp_device *hidpp)
>>>   {
>>>       struct hid_device *hdev = hidpp->hid_dev;
>>> @@ -4579,7 +4594,9 @@ static void hidpp_connect_event(struct 
>>> work_struct *work)
>>>       }
>>>         hidpp_initialize_battery(hidpp);
>>> -    if (!hid_is_usb(hidpp->hid_dev))
>>> +
>>> +    if (!hid_is_usb(hidpp->hid_dev) ||
>>> +        hidpp_is_bolt_child(hidpp->hid_dev))
>>>           hidpp_initialize_hires_scroll(hidpp);
>>>         /* forward current battery state */

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master
  2026-09-04 17:03     ` Benjamin Tissoires
@ 2026-09-04 18:20       ` Alexey Zagorodnikov
  0 siblings, 0 replies; 8+ messages in thread
From: Alexey Zagorodnikov @ 2026-09-04 18:20 UTC (permalink / raw)
  To: Benjamin Tissoires, Erik Håkansson
  Cc: Rafael Passos, lains, hadess, jikos, Shuah Khan, Brigham Campbell,
	Jori Koolstra, linux-input

 >we just revert the inclusion of the receiver in the dj driver.

Please no, we finally able to achieve hi-res scrolling, like it was on 
unifying and bluetooth connections.

Maybe place it behind some quirk flags if causes more trouble on other 
setup.

On 9/4/26 22:03, Benjamin Tissoires wrote:
> On Sep 04 2026, Erik Håkansson wrote:
>> Hi!
>> Is this the same issue as in
>> https://lore.kernel.org/linux-input/20260901-bolt-scroll-fix-v1-1-58bca7ae487f@protonmail.com/
>> The symptoms seem similar at least, and if so the approach to fixing
>> it in that case is to simply treat Bolt devices like previous DJ
>> devices, rather than having special treatment for Bolt.
>> Can you who have Bolt mice maybe test that patch too to see if it
>> solves the same issue?
> FWIW, my initial decision a few years back when Bolt was introduced was
> to not include it in the kernel, because there are too many things it's
> missing, the most problematic one being that we don't know which device
> sends which event.
>
> So basically, there is a chance that the driver sets high-resolution
> scrolling on a bolt device, when 2 mice are connected, and one is
> capable of it and the other is not. This is unlikely to happen, but is
> hard to solve in the kernel.
>
> So I'm happy to wait for testing and patches, but I would also like a
> conclusion where bolt doesn't belong to the kernel, and we just revert
> the inclusion of the receiver in the dj driver.
>
> Cheers,
> Benjamin

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master
  2026-09-04 18:17     ` Alexey Zagorodnikov
@ 2026-09-04 20:21       ` Rafael Passos
  0 siblings, 0 replies; 8+ messages in thread
From: Rafael Passos @ 2026-09-04 20:21 UTC (permalink / raw)
  To: Alexey Zagorodnikov, Erik Håkansson, Rafael Passos, lains,
	hadess, jikos, bentiss
  Cc: Shuah Khan, Brigham Campbell, Jori Koolstra, linux-input

Hi Erik,

On Fri Sep 4, 2026 at 3:17 PM -03, Alexey Zagorodnikov wrote:
> I've tried your patch, and MX Master 4 + Bolt goes crazy, it moves on 
> vertical with very high speed, and very very slow on horizontal.
>
> On 9/4/26 21:34, Erik Håkansson wrote:
>> Hi!
>> Is this the same issue as in
>> https://lore.kernel.org/linux-input/20260901-bolt-scroll-fix-v1-1-58bca7ae487f@protonmail.com/ 

I tested this patch and had the same behavior as Alexey in
my MX Master 3S. It affects the mouse movement, not the wheel.

If I coud ask, could you test my patch in your system too?

Thanks,
Rafael Passos

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-09-04 20:19 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-04  3:48 [PATCH] HID: logitech-hidpp: fix hi-res scroll for Bolt-connected MX Master Rafael Passos
2026-09-04  4:02 ` sashiko-bot
2026-09-04  7:44 ` Alexey Zagorodnikov
2026-09-04 16:34   ` Erik Håkansson
2026-09-04 17:03     ` Benjamin Tissoires
2026-09-04 18:20       ` Alexey Zagorodnikov
2026-09-04 18:17     ` Alexey Zagorodnikov
2026-09-04 20:21       ` Rafael Passos

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox