Re: [PATCH v3 0/5] rust: usb: host-side abstractions for a bulk-endpoint driver

From: Shuai Liu

Date: Fri Oct 30 2026 - 05:49:10 EST


Hi Mike,

Glad both findings were real. Here is a shape for the Altsetting token,
along with why I think the strict borrow-based draining version cannot
work in this design.

Why a &mut-based draining shape cannot work here:

- The window is shared by design. The adapter holds it on one side
(close() during suspend/reset/disconnect) and the driver receives an
Arc<IoWindow> on the other. There is no &mut IoWindow to take:
Arc::get_mut() needs refcount == 1, and Arc::make_mut() would clone
the window out from under the draining protocol.
- The drain itself is a cross-owner runtime protocol: the adapter
blocks until every outstanding Io token has been dropped. A
compile-time guarantee would require the compiler to see across that
ownership boundary, which it cannot.

Since the open/closed state is already checked at runtime, the setting
validity can ride the same mechanism while keeping the token-shaped
lookup API you asked about:

impl IoWindow {
/// ENODEV once the window is closed or the device unconfigured.
pub fn altsetting(&self) -> Result<Altsetting<'_>>;
}

impl Altsetting<'_> {
/// Validates the endpoint's bmAttributes against the active
/// alternate setting. The result is a plain value.
pub fn endpoint<K: EndpointKind>(&self, addr: u8) -> Option<Endpoint<K>>;
}

Endpoint stays Copy so queues can keep storing it, but it carries the
setting generation it was born in:

pub struct Endpoint<K: EndpointKind> {
addr: u8,
born: SettingGen,
_kind: PhantomData<K>,
}

set_alternate_setting() keeps your v4 behaviour (EBUSY while a queue is
registered, cancellation in the queue's Drop) and additionally bumps
the window's generation on success. Every transfer entry point checks
`ep.born == window.generation` before submitting and returns EINVAL for
a stale proof. That turns "Endpoints obtained earlier must be looked up
again after a switch" from a doc line into a rule the transfer path
actually enforces, at the cost of one integer compare per transfer.

This also mirrors the window's own open/active machinery: revocation is
runtime, the proof is just cheaper to validate than the window state.
A debug_assert on the same condition in the unsafe C call sites would
catch missing checks in development without costing anything in
production.

Best regards,
Shuai Liu