|
|
Log in / Subscribe / Register

rust: usb: synchronous + asynchronous bulk/control transfers + helpers

From:  Mike Lothian <mike-AT-fireburn.co.uk>
To:  rust-for-linux-AT-vger.kernel.org
Subject:  [RFC PATCH v2 00/11] rust: usb: synchronous + asynchronous bulk/control transfers + helpers
Date:  Fri, 03 Jul 2026 04:00:04 +0100
Message-ID:  <20260703030020.2694-1-mike@fireburn.co.uk>
Cc:  linux-usb-AT-vger.kernel.org, Greg Kroah-Hartman <gregkh-AT-linuxfoundation.org>, Daniel Almeida <daniel.almeida-AT-collabora.com>, Miguel Ojeda <ojeda-AT-kernel.org>, Boqun Feng <boqun-AT-kernel.org>, Gary Guo <gary-AT-garyguo.net>, Björn Roy Baron <bjorn3_gh-AT-protonmail.com>, Benno Lossin <lossin-AT-kernel.org>, Andreas Hindborg <a.hindborg-AT-kernel.org>, Alice Ryhl <aliceryhl-AT-google.com>, Trevor Gross <tmgross-AT-umich.edu>, Danilo Krummrich <dakr-AT-kernel.org>, Alexandre Courbot <acourbot-AT-nvidia.com>, linux-kernel-AT-vger.kernel.org, Mike Lothian <mike-AT-fireburn.co.uk>
Archive-link:  Article

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



Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds