[RFC PATCH v2 00/11] rust: usb: synchronous + asynchronous bulk/control transfers + helpers

From: Mike Lothian

Date: Thu Jul 02 2026 - 23:00:56 EST


This is v2 of the USB transfer bindings, rebased onto current drm-next
(no functional change from the version prepared but never sent after
v1's review -- see "Changes since v1" below for what that review fixed).
It adds the synchronous transfer primitives a driver needs at bring-up
to the Rust USB abstraction (rust/kernel/usb.rs), which currently lets
a driver bind a device (probe/disconnect) but provides no way to move
data, so any real driver still has to drop to C:

1/11 bulk_send() / bulk_recv() over usb_bulk_msg()
2/11 control_send() / control_recv() over usb_control_msg_send()/_recv()
3/11 set_interface() over usb_set_interface()
4/11 Interface::number() bInterfaceNumber accessor
5/11 clear_halt() over usb_clear_halt()
6/11 interrupt_recv() over usb_interrupt_msg()
7/11 reset_configuration() over usb_reset_configuration()
8/11 bulk_in_queue() / BulkInQueue persistently-queued async bulk IN
9/11 bulk_out_queue() / BulkOutQueue pipelined async bulk OUT
10/11 Device private + transfers gated on Interface<Bound>
11/11 let drivers choose the transfer allocation flags

usb::Device is kept private; the transfer methods are exposed on
usb::Interface<Bound> so a transfer cannot be issued before the
interface's device is bound to the driver. Each method documents its
blocking/sleeping context, timeouts are taken as a Delta, transfer
lengths are range-checked into the C int types, and every FFI call
carries a SAFETY comment. All the transfer methods take the endpoint's
bEndpointAddress as it appears in the descriptor (e.g. 0x84) and use
its low four bits as the endpoint number, so the convention is uniform
across bulk_send/bulk_recv, interrupt_recv and clear_halt.

DMA-buffer handling: bulk_send/bulk_recv/interrupt_recv copy through an
internally-allocated bounce buffer, so any &[u8]/&mut [u8] is accepted
rather than pushing an unenforced DMA-capable-memory precondition onto
callers. Patch 11 lets the caller choose the allocation flags for that
bounce (GFP_KERNEL normally, GFP_NOIO/GFP_NOFS from a reset/resume or
error-handling path) instead of hardcoding GFP_KERNEL, per Oliver
Neukum's v1 review.

Patches 8 and 9 add the asynchronous URB path (usb_submit_urb) for
endpoints where the per-transfer device-ACK round-trip of the
synchronous calls is too costly. bulk_in_queue() keeps depth IN URBs
perpetually posted and hands each completion to BulkInQueue::recv();
bulk_out_queue() pipelines OUT URBs submit-and-reap so a back-to-back
burst is not serialised.

The additions were developed for an out-of-tree in-kernel Rust
DisplayLink DL3 dock driver, but are generic and not driver-specific.
Each patch builds on its own, so the tree stays bisectable; the full
series builds in-tree on drm-next (LLVM/Rust) with no new warnings.

The consumer is the in-kernel Rust DisplayLink DL3 dock driver, posted
alongside as drm/vino ("[RFC PATCH v2 00/6] drm/vino: DisplayLink DL3
dock driver"). Source:
https://github.com/FireBurn/vino-scripts
https://github.com/FireBurn/linux/tree/vino
https://gitlab.freedesktop.org/FireBurn/linux/-/tree/vino

Changes since v1:
- Keep usb::Device private (it was made public in v1); expose the
transfer methods on usb::Interface<Bound> instead, so they cannot be
called before the device is bound. New patch 10. (Danilo Krummrich)
- Interface::as_bound() lets a driver that defers transfers to a work
item reach the bound transfer surface, with a flush-before-unbind
contract.
- Drivers now choose the transfer allocation flags instead of a
hardcoded GFP_KERNEL. New patch 11. (Oliver Neukum)
- Rebased onto current drm-next; no other functional change.

Mike Lothian (11):
rust: usb: add synchronous bulk transfer support
rust: usb: add synchronous control transfer support
rust: usb: add usb::Device::set_interface()
rust: usb: add usb::Interface::number()
rust: usb: add usb::Device::clear_halt()
rust: usb: add usb::Device::interrupt_recv()
rust: usb: add usb::Device::reset_configuration()
rust: usb: add an asynchronous persistently-queued bulk IN reader
rust: usb: add an asynchronous pipelined bulk OUT queue
rust: usb: keep usb::Device private and gate transfers on
Interface<Bound>
rust: usb: let drivers choose the transfer allocation flags

rust/helpers/usb.c | 35 ++
rust/kernel/usb.rs | 845 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 869 insertions(+), 11 deletions(-)

--
2.55.0