Page MenuHomeFreeBSD

bhyve: usb_mouse: do not lose a button or wheel event
Needs ReviewPublic

Authored by wanpengqian_gmail.com on Wed, Oct 7, 5:53 AM.

Details

Reviewers
None
Group Reviewers
bhyve
Summary

The emulated tablet kept a single report. Every pointer event (from VNC, or
from another front end) overwrote it, and the guest's next interrupt-IN
transfer took whatever was there. A button press and the matching release
that both arrive before that transfer leave a report with the button up, so
the guest never sees the click; the wheel had the same problem. This happens
when the guest is slow to poll (for example Windows while it enumerates
devices) and when a front end delivers a press and release together, as a
touchpad tap does.

Queue the reports: a change of the buttons or a wheel step is appended (up to
a small bound), a plain move replaces the newest queued report so moves are
not piled up, and each interrupt-IN transfer takes the oldest. The guest then
sees every press, release and wheel step. GET_REPORT still returns the latest
state, and the checkpoint format is unchanged (the queue is not saved; a
restored tablet sends the latest state).

Signed-off-by: Wanpeng Qian <wanpengqian@gmail.com>
Sponsored by: keelos.dev

Test Plan

The change is a queue in front of the one report the device kept, so no
transition is overwritten before the guest reads it.

Reasoning about the race: stock usb_mouse keeps umouse_report and sets it in
umouse_event(); umouse_data_handler() copies it to the guest on an interrupt-IN
transfer. If a press (buttons != 0) and the release (buttons == 0) both arrive
between two IN transfers, the guest reads only the release and the click is
lost. With the queue both reports are delivered on successive transfers.

Where it bites in practice (keelOS): a Windows guest lost short clicks while it
was busy enumerating devices at first boot, and a remote-desktop front end that
delivers a tap as one press+release PDU lost taps even on an idle guest. On an
idle guest driven from VNC the loss does not appear, because each event triggers
an immediate interrupt that the idle guest services before the next event, so a
simple VNC click test shows no difference; the queue is what makes the busy and
batched-input cases correct.

It builds with and without WITH_BHYVE_SNAPSHOT; VNC pointer movement and
clicks continue to work; a checkpoint/restore of a guest with the tablet
restores and delivers pointer events (the format is unchanged).

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Skipped
Unit
Tests Skipped
Build Status
Buildable 77794
Build 74677: arc lint + arc unit