Skip to content

Latest commit

 

History

History
232 lines (161 loc) · 9.19 KB

File metadata and controls

232 lines (161 loc) · 9.19 KB

Bluetooth HID++ Limitations

This document explains why Logitech devices connected via Bluetooth have limited functionality on Linux compared to USB connections.

Verified: Tested 2026-01-21 with MX Master 3S via Bluetooth on Linux 6.18.5. All limitations confirmed.

Summary

Bluetooth-connected Logitech devices cannot be configured by logiops-rs. The Linux kernel's logitech-hidpp-device driver intercepts HID++ protocol responses, preventing userspace applications from communicating with the device.

Solution: Connect your device via USB (directly or using the Unifying/Bolt receiver) for full configuration support.

Other tools affected: Solaar, libratbag/Piper have the same limitation—they use the same hidraw interface and experience identical timeouts.

Technical Background

How HID++ Communication Works

Logitech's HID++ protocol is a bidirectional communication layer on top of standard HID. It allows:

  • Querying device capabilities (DPI ranges, battery level, feature support)
  • Configuring device settings (DPI, scroll wheel behavior, button mappings)
  • Receiving notifications (battery warnings, button presses for remapping)

Communication follows a request-response pattern over HID reports.

Why Bluetooth Fails

The Linux kernel includes a driver (hid-logitech-hidpp) that provides native support for Logitech HID++ devices. This driver:

  1. Automatically binds to all Logitech Bluetooth HID devices
  2. Consumes HID++ responses at the kernel transport layer
  3. Exposes limited data via sysfs (battery level only)

When logiops-rs sends an HID++ request to a Bluetooth device:

logiops-rs → HID++ request → kernel → device
device → HID++ response → kernel driver (consumed) ✗ logiops-rs never receives it

The response never reaches userspace, causing communication timeouts.

Verified behavior (MX Master 3S via Bluetooth):

INFO  logiops_core::device: initializing HID++ device path=/dev/hidraw13
WARN  logiops::registry: failed to initialize device error=read timeout after 1000ms

Why USB Works

USB HID transport has a different architecture that allows responses to reach both the kernel driver AND userspace:

logiops-rs → HID++ request → kernel → device
device → HID++ response → kernel → driver AND /dev/hidraw* → logiops-rs ✓

This includes:

  • Direct USB connection (cable)
  • Unifying receiver (USB dongle, pairs up to 6 devices)
  • Bolt receiver (USB dongle, newer protocol)

Feature Comparison

Bluetooth (Limited)

Feature logiops-rs Kernel sysfs Notes
Basic mouse/keyboard input N/A N/A Standard HID, works normally
Battery level ✓ Read-only /sys/class/power_supply/hidpp_battery_*
Device name ✓ Read-only Via model_name in sysfs
DPI adjustment HID++ blocked
SmartShift configuration HID++ blocked
Button remapping HID++ blocked
Gesture configuration HID++ blocked
Profile switching HID++ blocked

USB (Full Support)

Feature Status Implementation
Basic mouse/keyboard input ✓ Works Standard HID
Battery level ✓ Works Unified Battery (0x1000) or Battery Status (0x1001)
Device name ✓ Works DeviceName (0x0005)
DPI adjustment ✓ Works Adjustable DPI (0x2201)
SmartShift configuration ✓ Works SmartShift (0x2110)
Button remapping ✗ Planned Reprogrammable Controls (0x1b04) - Phase 3
Gesture configuration ✗ Planned Phase 3
Profile switching ✗ Planned Phase 5

What's Actually Implemented (Phase 2)

Currently logiops-rs can (on USB only):

  • Read: Device info, feature list, DPI, SmartShift config, battery status
  • Write: DPI value, SmartShift threshold/torque/mode
  • Auto-apply: Configuration from TOML file on device connect

Recommendations

For Users

  1. Use the included USB receiver - Most Logitech devices ship with a Unifying or Bolt receiver. Use it for full configuration support.

  2. Use USB cable if available - Some devices (like MX Master series) support direct USB connection.

  3. Accept Bluetooth limitations - If you must use Bluetooth, understand you'll be stuck with factory default settings.

Checking Your Connection Type

# List Logitech HID devices with their driver and bus type
for h in /sys/class/hidraw/hidraw*; do
  uevent=$(cat "$h/device/uevent" 2>/dev/null)
  if echo "$uevent" | grep -q "046D"; then
    name=$(echo "$uevent" | grep HID_NAME | cut -d= -f2)
    driver=$(echo "$uevent" | grep DRIVER | cut -d= -f2)
    bus=$(echo "$uevent" | grep MODALIAS | grep -oP 'b\K[0-9a-f]{4}')
    echo "$(basename $h): $name"
    echo "  Driver: $driver"
    echo "  Bus: $bus (0003=USB, 0005=Bluetooth)"
  fi
done

Example output:

hidraw13: Logitech MX Master 3S
  Driver: logitech-hidpp-device
  Bus: 0005 (0003=USB, 0005=Bluetooth)   ← Bluetooth, won't work with logiops-rs

Reading Battery on Bluetooth

Even though configuration doesn't work, you can read battery level:

# Find Logitech battery devices
ls /sys/class/power_supply/ | grep hidpp

# Read battery percentage
cat /sys/class/power_supply/hidpp_battery_*/capacity

# Read charging status
cat /sys/class/power_supply/hidpp_battery_*/status

Workarounds (Advanced)

Driver Unbinding (Does NOT Work)

You might think unbinding the kernel driver would allow userspace access:

# Find your device ID
ls /sys/bus/hid/drivers/logitech-hidpp-device/
# Shows: 0005:046D:B034.0023

# Unbind the driver
echo "0005:046D:B034.0023" | sudo tee /sys/bus/hid/drivers/logitech-hidpp-device/unbind

Result: The /dev/hidraw* device disappears entirely. The HID driver creates the hidraw node, so without any driver bound, there's no device to communicate with.

Attempting to rebind to hid-generic also fails because it won't accept devices that match the more specific logitech-hidpp-device driver.

Blacklisting the Kernel Driver (Trade-off)

You can prevent the kernel driver from loading entirely:

# /etc/modprobe.d/logitech-hidpp-blacklist.conf
blacklist hid_logitech_hidpp

Then reboot or rmmod hid_logitech_hidpp.

Warning: This affects ALL Logitech HID++ devices (USB and Bluetooth) and disables:

  • System battery indicator for all Logitech devices
  • Kernel-level power management
  • High-resolution scrolling provided by the kernel

Not recommended unless you only use USB devices and want logiops-rs to handle everything.

Configure on Another OS

If you need specific settings on Bluetooth:

  • Configure on Windows/macOS using Logitech Options+
  • Settings are stored in device onboard memory
  • Bluetooth connection will use those stored settings

Why Not Fix This in the Kernel?

The kernel developers attempted to improve Bluetooth HID++ support in Linux 6.1 by enabling it for all Logitech Bluetooth devices by default. This was reverted because:

  1. Device compatibility issues: Some devices that don't fully support HID++ would be left with a "dead mouse" when the driver gave up
  2. Match function limitations: The ->match() function wasn't designed for use outside hid-generic
  3. Corner cases: The driver has unhandled edge cases where it gives up on devices it shouldn't

The fix was postponed to Linux 6.2/6.3 but the fundamental architecture remains: the kernel driver owns the HID++ response stream for Bluetooth devices.

This is an architectural decision, not a bug. The kernel prioritizes system-level battery monitoring and power management over userspace configuration tools.

Future Considerations

Potential improvements for logiops-rs:

  1. Hybrid mode: Detect Bluetooth devices and read battery from sysfs while warning about configuration limitations

  2. Connection type detection: Automatically identify USB vs Bluetooth and adjust behavior

  3. Graceful degradation: Show device info even when configuration isn't possible

  4. Notification to user: Clear warning when a Bluetooth device is detected

Planned Features (Will Also Be Bluetooth-Blocked)

These features are planned for future phases but will have the same Bluetooth limitation:

Feature Phase HID++ Feature ID
Button remapping 3 Reprogrammable Controls (0x1b04)
Gesture configuration 3 TBD
HiRes scrolling 3 HiRes Wheel (0x2121)
Profile switching 5 Onboard Profiles (0x8100)

References