Skip to content

MX Master 4 on Logi Bolt fails to initialize on boot with default 500 ms io_timeout #564

Description

@stekst

MX Master 4 on Logi Bolt fails to initialize on boot with default 500 ms io_timeout

Summary

The Logitech MX Master 4 connected through a Logi Bolt receiver may fail to initialize in logid during boot when using the default io_timeout of 500 ms.

The mouse itself remains fully usable as a normal pointer device, but logid does not initialize it, so configured functionality such as gestures, remapped buttons, SmartShift and thumb-wheel actions is unavailable.

Increasing the global io_timeout from the default 500 ms to 3000 ms completely resolves the issue on my system.

This appears to be closely related to #463, which describes similar initialization problems with an MX Master 3S connected through Logi Bolt.


Environment

Operating system

openSUSE Tumbleweed

logiops version

Current main at the time of testing:

v0.3.5-7-ge157995

Verified both in the source tree and with the installed binary:

$ git describe --always --tags
v0.3.5-7-ge157995

$ logid --version
v0.3.5-7-ge157995

Current commit:

e157995 Merge pull request #502 from LucasDondo/patch-1

The installed /usr/bin/logid was built from this same source revision.

Hardware

  • Logitech MX Master 4
  • Logitech MX Keys S
  • Logitech Logi Bolt Receiver
  • Both devices paired to the same Bolt receiver

Receiver USB ID:

$ lsusb | grep -i logitech
Bus 003 Device 005: ID 046d:c548 Logitech, Inc. Logi Bolt Receiver

The receiver is detected as:

/dev/hidraw3

Configuration

The relevant device configuration is an MX Master 4 configuration using several HID++ features, including:

  • DPI configuration
  • SmartShift
  • thumb wheel diversion
  • remappable buttons
  • gestures

For example:

devices: ({
    name: "MX Master 4";

    dpi: 1200;

    smartshift: {
        on: true;
        threshold: 30;
    };

    hiresscroll: {
        hires: false;
    };

    ...
});

Without changing the global timeout, this configuration works correctly whenever the mouse is successfully initialized.


Problem after boot

After boot, the logid service starts normally and detects the Bolt receiver.

However, it may only initialize the MX Keys S:

Aug 07 08:15:39 systemd[1]: Started Logitech Configuration Daemon.
Aug 07 08:15:39 logid[1680]: [INFO] Detected receiver at /dev/hidraw3
Aug 07 08:15:40 logid[1680]: [INFO] Device found: MX Keys S on /dev/hidraw3:3

There is no corresponding:

Device found: MX Master 4

The important detail is that the MX Master 4 itself still works normally as a mouse.

Pointer movement, clicking and normal scrolling work.

However, none of the logid functionality configured for the mouse works:

  • gestures do not work
  • remapped buttons do not work
  • configured SmartShift actions do not work
  • configured thumb-wheel actions do not work

So this does not appear to be a USB input or Bolt connectivity failure in general. It specifically appears to affect HID++ initialization by logid.


libinput behaviour

The mouse is visible to libinput through the Bolt receiver even while logid has failed to initialize it.

For example:

-event0  DEVICE_ADDED  Logitech USB Receiver
-event1  DEVICE_ADDED  Logitech USB Receiver Mouse
-event2  DEVICE_ADDED  Logitech USB Receiver Consumer Control
-event3  DEVICE_ADDED  Logitech USB Receiver System Control
-event6  DEVICE_ADDED  Logitech USB Receiver
-event21 DEVICE_ADDED  LogiOps Virtual Input

Moving the MX Master 4 generates normal pointer events:

event1 POINTER_MOTION ...
event1 POINTER_MOTION ...
event1 POINTER_MOTION ...

This confirms that the mouse and receiver are operational even when the HID++ initialization performed by logid has failed.


Debug output

Stopping the service and running logid manually in verbose mode:

sudo systemctl stop logid
sudo logid -v

initially produces:

[DEBUG] Unsupported device /dev/hidraw0 ignored
[DEBUG] Unsupported device /dev/hidraw1 ignored
[DEBUG] Unsupported device /dev/hidraw2 ignored
[INFO] Detected receiver at /dev/hidraw3
[DEBUG] Unsupported device /dev/hidraw4 ignored
[DEBUG] /dev/hidraw3:2 timed out, waiting for input from device to initialize.
[DEBUG] /dev/hidraw3:3 timed out, waiting for input from device to initialize.

At this point the MX Master 4 is still usable as a normal mouse, but it is not initialized by logiops.


Reconnect behaviour

Changing the Easy-Switch channel on the MX Master 4 and switching back immediately causes logid to recognize the mouse:

[INFO] Device found: MX Master 4 on /dev/hidraw3:2

It then correctly enumerates its HID++ capabilities:

[DEBUG] /dev/hidraw3:2 remappable buttons:
[DEBUG] CID  | reprog? | fn key? | mouse key? | gesture support?
[DEBUG] 0x50 |         |         | YES        |
[DEBUG] 0x51 |         |         | YES        |
[DEBUG] 0x52 | YES     |         | YES        | YES
[DEBUG] 0x53 | YES     |         | YES        | YES
[DEBUG] 0x56 | YES     |         | YES        | YES
[DEBUG] 0xc3 | YES     |         | YES        | YES
[DEBUG] 0xc4 | YES     |         | YES        | YES
[DEBUG] 0xd7 | YES     |         |            | YES
[DEBUG] 0x1a0| YES     |         | YES        | YES

The thumb wheel is also detected correctly:

[DEBUG] Thumb wheel detected (0x2150), capabilities:
[DEBUG] timestamp | touch | proximity | single tap
[DEBUG] YES       | YES   | NO        | NO
[DEBUG] Thumb wheel resolution: native (20), diverted (120)

After that, all configured gestures and button actions work immediately.

Physically disconnecting and reconnecting the Bolt receiver also causes both devices to initialize correctly:

[INFO] Receiver on /dev/hidraw3 disconnected
[INFO] Detected receiver at /dev/hidraw3
[INFO] Device found: MX Master 4 on /dev/hidraw3:2
[INFO] Device found: MX Keys S on /dev/hidraw3:3

Restarting logid alone is not a reliable workaround

Restarting the service does not necessarily solve the problem:

sudo systemctl restart logid

The receiver may again be detected while only the keyboard is initialized.

A real reconnect / wake-up event from the mouse reliably causes initialization.

This initially made the problem look like a Bolt reconnect issue.


Source-code investigation

The default timeout is defined in:

src/logid/Configuration.h

as:

static constexpr double io_timeout = 500;

When initialization times out, Receiver.cpp catches the TimeoutError:

} catch (TimeoutError& e) {
    if (!event.fromTimeoutCheck)
        logPrintf(DEBUG, "%s:%d timed out, waiting for input from device to"
                         " initialize.", _path.c_str(), event.index);
    waitForDevice(event.index);
}

So after the first initialization attempt times out, logiops calls:

waitForDevice(event.index);

Looking at ReceiverMonitor::waitForDevice():

void ReceiverMonitor::waitForDevice(hidpp::DeviceIndex index) {
    const std::lock_guard lock(_wait_mutex);

    if (!_waiters.count(index)) {
        _waiters.emplace(index, _receiver->rawDevice()->addEventHandler(
            {[index](const std::vector<uint8_t>& report) -> bool {
                /* Connection events should be handled by connect_ev_handler */
                auto sub_id = report[Offset::SubID];

                return report[Offset::DeviceIndex] == index &&
                       sub_id != Receiver::DeviceConnection &&
                       sub_id != Receiver::DeviceDisconnection;
            },
            [self_weak = _self, index](
                [[maybe_unused]] const std::vector<uint8_t>& report) {

                hidpp::DeviceConnectionEvent event{};
                event.withPayload = false;
                event.linkEstablished = true;
                event.index = index;
                event.fromTimeoutCheck = true;

                run_task([self_weak, event]() {
                    if (auto self = self_weak.lock())
                        self->_addHandler(event);
                });
            }
        }));
    }
}

My understanding is therefore:

  1. Receiver enumeration discovers the device.
  2. Initial HID++ communication with the MX Master 4 does not complete within 500 ms.
  3. A TimeoutError occurs.
  4. logid switches to waitForDevice().
  5. Normal pointer movement continues to work via the standard receiver mouse interface.
  6. That pointer activity apparently does not produce the HID++ report required by the waiter.
  7. A real reconnect / Easy-Switch event causes sufficient HID++ activity.
  8. _addHandler() is executed again and initialization succeeds.

Workaround / fix

The configuration schema supports a global io_timeout:

std::optional<double> io_timeout;

Setting:

io_timeout: 3000.0;

before the devices section completely resolves the problem:

io_timeout: 3000.0;

devices: ({
    name: "MX Master 4";

    ...
});

With this configuration, after restarting logid:

Aug 07 08:38:27 systemd[1]: Started Logitech Configuration Daemon.
Aug 07 08:38:27 logid[26035]: [INFO] Detected receiver at /dev/hidraw3
Aug 07 08:38:29 logid[26035]: [INFO] Device found: MX Master 4 on /dev/hidraw3:2
Aug 07 08:38:30 logid[26035]: [INFO] Device found: MX Keys S on /dev/hidraw3:3

Most importantly, this also works after an actual reboot.

The MX Master 4 is initialized automatically and all configured gestures work immediately without:

  • moving the mouse during daemon startup
  • switching Easy-Switch channels
  • power cycling the mouse
  • unplugging the Bolt receiver
  • manually restarting logid

Result

Default configuration

io_timeout = 500 ms

Result:

Bolt receiver detected
MX Keys S detected
MX Master 4 sometimes times out
MX Master 4 logiops configuration not active

Increased timeout

io_timeout: 3000.0;

Result:

Bolt receiver detected
MX Master 4 detected
MX Keys S detected
All MX Master 4 logiops functionality active

This has been reproducible on my system.


Possible causes / potential solutions

Based on the above testing, it appears that 500 ms may simply be too short for some Bolt-connected devices to answer the initial HID++ requests, especially during system startup.

Potential solutions might be:

  1. Increase the default io_timeout.

    For example, raising it from 500 ms to something in the 2000–3000 ms range.

  2. Retry device initialization after a timeout.

    Instead of immediately relying entirely on waitForDevice(), retry the initial HID++ communication a small number of times.

    For example:

    initial attempt
        ↓ timeout
    wait briefly
        ↓
    retry
        ↓ timeout
    wait briefly
        ↓
    retry
        ↓
    fall back to waitForDevice()
    

    This may avoid increasing the timeout globally for every HID++ operation.

  3. Use a larger timeout specifically during receiver/device initialization.

    The normal 500 ms timeout might still be desirable for regular communication after the device has been initialized.

  4. Improve the waitForDevice() retry trigger.

    The MX Master 4 remains fully functional as a pointer while waitForDevice() is active, but ordinary mouse activity apparently does not trigger the HID++ event needed to retry initialization.

A short initialization-specific retry mechanism may therefore be preferable to simply increasing every I/O timeout.


Related issue

This looks very similar to #463 ("MX Master 3S with Bolt not detected").

That issue describes an MX Master 3S connected through Bolt which is not reliably detected at startup and can be recovered by mouse activity / power cycling.

Later comments in #463 also report successful workarounds using an increased global io_timeout.

The MX Master 4 appears to exhibit the same underlying behaviour.

The additional observations here are:

  • reproduced with an MX Master 4
  • reproduced on current main (v0.3.5-7-ge157995)
  • default 500 ms timeout confirmed in the current source
  • timeout path traced through Receiver.cpp and ReceiverMonitor::waitForDevice()
  • 3000 ms is sufficient on this system
  • verified after a full reboot
  • no receiver reconnect or mouse power cycle is required with the increased timeout

I'm happy to provide additional verbose logs, test patches or test an initialization/retry change on the MX Master 4 + Bolt setup if useful.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions