Skip to main content

rpi_hal/usb/
mod.rs

1//! USB host support for the BCM2836/2837's built-in DWC2 OTG
2//! controller, built up in stages rather than attempted as one unit:
3//! host controller bring-up first, enumeration and a HID class driver
4//! next (the smallest real thing that validates the controller
5//! actually works end to end), Ethernet only once those are solid
6//! (its own class driver plus a full TCP/IP stack on top, far more
7//! surface area than HID). So far there's controller/root-port
8//! bring-up ([`dwc2::Dwc2Host`](crate::usb::dwc2::Dwc2Host)); the
9//! standard control transfers that enumerate a device (reading its
10//! [device](crate::usb::control::get_device_descriptor) and
11//! [configuration](crate::usb::control::get_configuration_descriptor)
12//! descriptors, [SET_ADDRESS](crate::usb::control::set_address),
13//! [SET_CONFIGURATION](crate::usb::control::set_configuration)); and the
14//! hub-class requests that drive the on-board hub's downstream ports
15//! ([hub descriptor](crate::usb::control::get_hub_descriptor),
16//! [`set_port_power`](crate::usb::control::set_port_power),
17//! [`get_port_status`](crate::usb::control::get_port_status),
18//! [`set_port_reset`](crate::usb::control::set_port_reset)). A
19//! device behind the hub can be reset and its descriptor read through
20//! it — at high speed directly, or at full/low speed via split
21//! transactions through the hub's transaction translator (see
22//! [`dwc2::SplitTarget`](crate::usb::dwc2::SplitTarget)) — and
23//! interrupt-IN endpoints can be polled
24//! ([`dwc2::Channel::interrupt_in`](crate::usb::dwc2::Channel::interrupt_in)),
25//! directly (the hub's own status-change endpoint) or through the hub
26//! at full/low speed via periodic split scheduling (the report endpoint
27//! of a HID keyboard on a physical port). [`enumerate`](crate::usb::enumerate) ties the whole
28//! bring-up together — root-port reset, root-hub configuration, and
29//! per-port reset/probe/address, applied again to any port that turns
30//! out to have a hub on it, so a device several hubs deep is found and
31//! pointed at the right transaction translator for where it sits — and
32//! hands each device to a
33//! callback (see the `usb_enum`/`usb_hid_keyboard` examples).
34//! The [bus type](crate::usb::Bus) is the same walk with its state kept
35//! afterwards, so [a later sweep](crate::usb::Bus::poll) can bring up a
36//! device that attaches after the walk and report one that goes away —
37//! which a single pass cannot, and which matters on boards where a
38//! soldered-on device takes longer to announce itself than the walk
39//! takes to run.
40//! On top of
41//! that sit the class drivers — HID ([`hid`](crate::usb::hid)), turning a
42//! device's report endpoint into input events: a boot-protocol keyboard
43//! and mouse, and a gamepad decoded through its own HID report descriptor
44//! ([`hid::gamepad`](crate::usb::hid::gamepad)) — and the beginnings of the
45//! on-board LAN9514
46//! USB-Ethernet controller ([`lan9514`](crate::usb::lan9514)), so far
47//! reaching its registers over vendor control transfers. Still missing:
48//! bulk transfers (which Ethernet frame RX/TX needs), and the rest of the
49//! LAN9514 driver and a network stack on top. Each is
50//! real, separate work still to come, layered on top of
51//! [`dwc2`](crate::usb::dwc2)/[`control`](crate::usb::control).
52//!
53//! On this project's target board (a Pi 2 Model B rev 1.1), the
54//! on-board USB port(s) and the Ethernet jack are both wired through
55//! an SMSC LAN9514 (a combined USB hub + 10/100 Ethernet controller)
56//! sitting on this DWC2 controller's single root port. That means the
57//! very first "device" this stack will ever see attached, on real
58//! hardware, is that hub itself — reaching anything actually plugged
59//! into a physical port (a keyboard, a mouse, the Ethernet path) needs
60//! hub traversal, not just enumerating one device directly on the
61//! root port.
62//!
63//! All of the above is confirmed working on real hardware: this stack
64//! enumerates the on-board LAN9514 hub, powers and resets its
65//! downstream ports, reaches through it to read the descriptors of
66//! both the hub's own high-speed Ethernet function and a full-speed
67//! keyboard on a physical port (the latter via split transactions),
68//! polls the hub's interrupt status-change endpoint to detect a
69//! device being unplugged/replugged, and reads live key presses from
70//! that keyboard's interrupt report endpoint over a periodic split.
71//! Getting the initial bring-up
72//! working depended on one thing that no amount of DWC2 register tuning
73//! could substitute for — the controller must be
74//! powered on through the VideoCore mailbox first (see
75//! [`dwc2`](crate::usb::dwc2)'s module doc); before that the register
76//! block responds normally but no transaction ever runs.
77
78// rustdoc reports one `redundant explicit link target` in this module
79// tree and gives no source location for it, in any error format, so
80// there is nothing to point at and fix. It appeared when `Bus` was added
81// and is not a link in this file: stripping every explicit link target
82// from `mod.rs` leaves the warning, and restoring the previous `mod.rs`
83// alongside the current `hub.rs` clears it. Allowed here rather than
84// crate-wide so a locatable one elsewhere still fails the build.
85#![allow(rustdoc::redundant_explicit_links)]
86
87/// USB protocol-level control transfers built on [`dwc2`] — see
88/// [`control::get_device_descriptor`].
89pub mod control;
90/// Typed views over the standard USB descriptors (device, configuration,
91/// interface, endpoint) — see [`descriptor::DeviceDescriptor`].
92pub mod descriptor;
93/// Host-mode bring-up for the DWC2 core itself, plus the low-level
94/// DMA-mode control-transfer channel primitives — see
95/// [`dwc2::Dwc2Host`].
96pub mod dwc2;
97/// What a USB Ethernet controller looks like from above, whichever one a
98/// board has — see [`ethernet::Ethernet`].
99pub mod ethernet;
100/// HID class drivers built on the enumeration above — boot-protocol
101/// keyboard and mouse (see [`hid::keyboard::Keyboard`]) plus a
102/// report-descriptor-driven gamepad (see [`hid::gamepad::Gamepad`]).
103pub mod hid;
104/// Driving a hub's downstream ports (bring-up, port reset, speed/split
105/// detection) — see [`hub::Hub`].
106pub mod hub;
107/// The LAN7800 USB-Ethernet controller, the Ethernet half of a Pi 3B+'s
108/// LAN7515 — see [`lan7800::Lan7800`].
109pub mod lan7800;
110/// The on-board LAN9514 USB-Ethernet controller — see
111/// [`lan9514::Lan9514`].
112pub mod lan9514;
113
114use core::ops::ControlFlow;
115
116use crate::mailbox::{Mailbox, PowerDeviceId};
117use crate::timer::Timer;
118use crate::usb::control::{clear_port_feature, probe_and_address, PORT_FEATURE_C_CONNECTION};
119use crate::usb::descriptor::DeviceDescriptor;
120use crate::usb::dwc2::{Channel, ControlEndpoint, Dwc2Host, TransferError};
121use crate::usb::hub::Hub;
122
123/// Address assigned to the on-board root hub during [`enumerate`].
124/// Downstream devices are addressed from here upward.
125const ROOT_HUB_ADDRESS: u8 = 1;
126
127/// Highest USB device address (USB 2.0 spec §9.4.6 — `wValue` of
128/// SET_ADDRESS is 7 bits, and 0 is the unaddressed default). A bus with
129/// more devices than this on it is one [`enumerate`] stops walking.
130const MAX_ADDRESS: u8 = 127;
131
132/// `bDeviceClass` identifying a device as a hub (USB 2.0 spec §11.23.1)
133/// — what [`enumerate`] keys its recursion off. A hub declares this in
134/// its *device* descriptor rather than per-interface, so a downstream
135/// hub is recognizable from the descriptor read while addressing it,
136/// with no configuration descriptor needed.
137const CLASS_HUB: u8 = 9;
138
139/// How deep below the root hub [`enumerate`] descends, as a
140/// [`Device::depth`] — a device at this depth is reported, but a hub at
141/// it is not recursed into.
142///
143/// USB 2.0 spec §4.1.1 caps a bus at seven tiers: the host controller,
144/// up to five hubs in a chain, and the device. The board's root hub is
145/// the first of those five, so four more may hang below it, which puts
146/// the deepest reachable device four levels down.
147const MAX_HUB_DEPTH: u8 = 4;
148
149/// How many hubs a [`Bus`] tracks, the root hub included. Beyond this it
150/// has nowhere to record the topology a device's split target is derived
151/// from, so rather than guess it stops with
152/// [`EnumerationError::TooManyHubs`].
153///
154/// Eight is far past any real arrangement — USB's own five-hub chain
155/// limit means reaching it takes a *wide* tree of hubs, not a deep one —
156/// and the table costs a few hundred bytes, so the cap is here to make
157/// the storage finite rather than to ration anything.
158pub const MAX_HUBS: usize = 8;
159
160/// How many downstream ports per hub a [`Bus`] tracks. Ports past this on
161/// a single hub are left alone: no device on one is brought up, so none
162/// is reported as attached and none can go missing later.
163///
164/// A USB 2.0 hub descriptor can claim up to 255 ports and no physical hub
165/// comes close; 15 covers every one built, including the 13-port
166/// controllers inside monitor docks.
167pub const MAX_PORTS: usize = 15;
168
169/// Marks a downstream port that has something on it this couldn't bring
170/// up, as against `0` for an empty port and a real address for a device.
171///
172/// Not a valid USB address (they stop at [`MAX_ADDRESS`]), so it can't be
173/// confused with one. It exists to make "occupied" and "usable" separate
174/// answers: without it a device that fails to enumerate looks like an
175/// empty port, and [`Bus::poll`] resets it again on every sweep for as
176/// long as it stays plugged in.
177const PORT_FAILED: u8 = u8::MAX;
178
179/// Powers the USB host controller on through the VideoCore mailbox — the
180/// mandatory first step before [`dwc2::Dwc2Host::init`], since the
181/// firmware hands the core off only partially powered (see [`dwc2`]'s
182/// module doc: without this the register block responds normally but no
183/// transaction ever runs). Returns `true` once the controller is powered
184/// and present, `false` if the mailbox call fails or the firmware reports
185/// the controller absent.
186pub fn power_on(mailbox: &mut Mailbox) -> bool {
187    matches!(
188        mailbox.set_power_state(PowerDeviceId::UsbHcd, true),
189        Ok(true)
190    )
191}
192
193/// What went wrong bringing up the bus or the root hub in [`enumerate`].
194/// Failures enumerating an individual downstream port are *not* reported
195/// this way — [`enumerate`] skips a port that misbehaves and carries on —
196/// so this only covers the shared bring-up every device depends on.
197#[derive(Clone, Copy, Debug, PartialEq, Eq)]
198pub enum EnumerationError {
199    /// No device is connected on the root port (nothing to enumerate).
200    NotConnected,
201    /// The root port didn't enable after a reset — the root device never
202    /// came up.
203    PortNotEnabled,
204    /// A descriptor (the root hub's configuration or class descriptor)
205    /// was too short to parse.
206    MalformedDescriptor,
207    /// Every host channel was already handed out, so enumeration
208    /// couldn't get one to run its control transfers on — see
209    /// [`Dwc2Host::alloc_channel`].
210    OutOfChannels,
211    /// All 127 USB device addresses are in use, so the device just reset
212    /// cannot be given one. The devices already found are still reported;
213    /// the walk stops at the one that didn't fit.
214    OutOfAddresses,
215    /// More hubs are on the bus than a [`Bus`] can track (see
216    /// [`MAX_HUBS`]). Reported rather than passed over, because the
217    /// topology a [`Bus`] keeps is what every device's split target is
218    /// derived from: an untracked hub means devices below it would be
219    /// addressed through the wrong transaction translator, which is a
220    /// worse answer than stopping.
221    TooManyHubs,
222    /// An underlying control transfer failed.
223    Transfer(TransferError),
224}
225
226impl From<TransferError> for EnumerationError {
227    fn from(error: TransferError) -> Self {
228        EnumerationError::Transfer(error)
229    }
230}
231
232/// A downstream device found and addressed by [`enumerate`], handed to
233/// its per-device callback. Everything needed to talk to the device
234/// further (read its configuration, configure it, poll its endpoints) is
235/// here, plus where on the bus it was found.
236#[derive(Clone, Copy, Debug, PartialEq, Eq)]
237pub struct Device {
238    /// The hub downstream port (1-based) the device is on.
239    pub port: u8,
240    /// Address of the hub whose [`Self::port`] this is — the root hub
241    /// for a device plugged straight into the board, or a downstream
242    /// hub's own address for one found behind it. With [`Self::port`]
243    /// it names the device's position on the bus, which survives a
244    /// reboot in a way the assigned address doesn't.
245    pub hub_address: u8,
246    /// How many hubs below the root hub the device sits: `0` on one of
247    /// the root hub's own ports, `1` behind a hub plugged into one of
248    /// those, and so on — up to four, the deepest USB allows.
249    pub depth: u8,
250    /// The device's addressed endpoint 0 — address, speed, endpoint-0
251    /// max packet size, and split target all filled in.
252    pub endpoint: ControlEndpoint,
253    /// The device's parsed device descriptor.
254    pub descriptor: DeviceDescriptor,
255}
256
257/// What a [`Bus`] found happening, handed to the callback of
258/// [`Bus::enumerate`] and [`Bus::poll`].
259#[derive(Clone, Copy, Debug, PartialEq, Eq)]
260pub enum Event {
261    /// A device was brought up: reset, addressed, and ready to talk to.
262    Attached(Device),
263    /// A device is gone — the port it was on no longer reports it
264    /// connected. Its address has already been freed and may be handed to
265    /// something else on the next attach, so a driver holding this device
266    /// should stop using it here rather than later.
267    ///
268    /// Unplugging a hub reports every device that was behind it, deepest
269    /// first, and the hub itself last.
270    Detached {
271        /// Address of the hub whose port the device was on.
272        hub_address: u8,
273        /// That hub's downstream port (1-based).
274        port: u8,
275        /// The address the device had, now free.
276        address: u8,
277    },
278}
279
280/// One tracked hub: everything [`Bus`] needs to revisit its ports later,
281/// which a [`Hub`] alone doesn't carry.
282#[derive(Clone, Copy)]
283struct HubRecord {
284    /// The configured hub itself — endpoint, port count, speed, and the
285    /// status-change endpoint.
286    hub: Hub,
287    /// [`Device::depth`] of the devices on this hub's ports.
288    depth: u8,
289    /// What is on each downstream port, indexed by port minus one: `0`
290    /// for nothing, [`PORT_FAILED`] for something that wouldn't come up,
291    /// otherwise the device's address. This is the memory the hub itself
292    /// doesn't have — it reports only what is plugged in now — and
293    /// comparing the two is what turns a port reading into an arrival or
294    /// a departure.
295    ports: [u8; MAX_PORTS],
296}
297
298/// The USB bus behind the controller: which devices are on it, where, and
299/// at what addresses — kept across calls so devices that appear or vanish
300/// after the first walk can still be brought up or reported.
301///
302/// [`enumerate`] is this with the state thrown away, which is enough when
303/// everything is plugged in before the board boots and never moves. It
304/// stops being enough as soon as something attaches late. A device that
305/// takes seconds to come up is missed by a one-shot walk and there is no
306/// second look, and the reason there can't be one is that the walk owns
307/// the two things bringing a device up requires: the next free address,
308/// and the hub topology every split target is derived from. A `Bus` holds
309/// both, so [`Self::poll`] can do what [`Self::enumerate`] did, later and
310/// for one port.
311///
312/// Typical use is [`Self::enumerate`] once at startup and [`Self::poll`]
313/// from the main loop:
314///
315/// ```ignore
316/// let mut bus = Bus::new(&dwc2);
317/// bus.enumerate(&timer, |channel, timer, event| { .. })?;
318/// loop {
319///     bus.poll(&timer, |channel, timer, event| { .. })?;
320///     timer.delay_ms(250);
321/// }
322/// ```
323///
324/// Both take the same callback, so the code that recognizes a device
325/// doesn't care whether it was there at boot or arrived later — which is
326/// the point, since on some boards that is a matter of timing rather than
327/// of anything the user did.
328pub struct Bus<'a> {
329    dwc2: &'a Dwc2Host,
330    /// One bit per USB device address, bit *n* set while address *n* is
331    /// assigned. A bitmap rather than a counter because addresses come
332    /// back when devices are unplugged, and a bus that is replugged all
333    /// day would otherwise run out.
334    addresses: u128,
335    hubs: [Option<HubRecord>; MAX_HUBS],
336    /// Set when a walk hits something it cannot carry on past, so the
337    /// walk can stop the way a callback does — by returning
338    /// [`ControlFlow::Break`] — and still have the reason surface as an
339    /// error from the public method.
340    fault: Option<EnumerationError>,
341}
342
343impl<'a> Bus<'a> {
344    /// A bus with nothing on it yet, for an
345    /// already-[initialized](dwc2::Dwc2Host::init) controller. Nothing is
346    /// touched until [`Self::enumerate`].
347    pub fn new(dwc2: &'a Dwc2Host) -> Self {
348        Bus {
349            dwc2,
350            addresses: 0,
351            hubs: [None; MAX_HUBS],
352            fault: None,
353        }
354    }
355
356    /// Walks the whole bus from the root port, reporting every device it
357    /// brings up as [`Event::Attached`], and records the topology so
358    /// [`Self::poll`] can pick up from here.
359    ///
360    /// The caller must have waited for
361    /// [`dwc2::Dwc2Host::port_connected`]. This resets the root port,
362    /// brings up and configures the root hub (soldered on, on every board
363    /// this targets — see this module's doc), powers its downstream
364    /// ports, then for each connected port resets it, reads the device's
365    /// descriptor, and assigns it an address before reporting it. Each
366    /// device is addressed before the next port is touched, since two
367    /// just-reset devices must never sit at address 0 at once.
368    ///
369    /// A device that turns out to be a hub itself is brought up the same
370    /// way the root hub was and walked in turn, depth first, so the whole
371    /// bus is reported however many hubs deep it goes (up to the four
372    /// levels below the root hub that USB allows). Each device carries
373    /// the [`hub_address`](Device::hub_address)/[`port`](Device::port) it
374    /// was found on and its [`depth`](Device::depth), and its
375    /// [`endpoint`](Device::endpoint) already points at the right
376    /// transaction translator for its position — the nearest high-speed
377    /// hub above it, which for a device several levels down is not
378    /// necessarily the hub it is plugged into (see
379    /// [`Hub::split_target`]).
380    ///
381    /// `on_event` receives the [`Channel`] the walk ran on (to do further
382    /// transfers), the timer, and the [`Event`]; return
383    /// [`ControlFlow::Break`] from it to stop early, e.g. once the device
384    /// of interest is found. A hub is reported before the devices behind
385    /// it, so breaking on one stops before it is walked.
386    ///
387    /// A port whose reset or descriptor read fails is skipped rather than
388    /// aborting the walk, as is a hub that fails to configure (it is
389    /// still reported, just not descended into). Calling this again
390    /// discards everything known and starts over, which is what a bus
391    /// that has been reset out from under this type needs.
392    pub fn enumerate<F>(&mut self, timer: &Timer, mut on_event: F) -> Result<(), EnumerationError>
393    where
394        F: FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
395    {
396        let dwc2 = self.dwc2;
397        if !dwc2.port_connected() {
398            return Err(EnumerationError::NotConnected);
399        }
400        dwc2.reset_port(timer);
401        if !dwc2.port_enabled() {
402            return Err(EnumerationError::PortNotEnabled);
403        }
404
405        self.addresses = 0;
406        self.hubs = [None; MAX_HUBS];
407        self.fault = None;
408
409        let mut channel = dwc2
410            .alloc_channel()
411            .ok_or(EnumerationError::OutOfChannels)?;
412        let channel = &mut channel;
413
414        // Address the root device (the on-board hub), then configure it
415        // and power its downstream ports. It is the first thing to take
416        // an address, so it always lands on ROOT_HUB_ADDRESS.
417        let root = ControlEndpoint {
418            address: 0,
419            low_speed: dwc2.port_speed() == 2,
420            max_packet_size: 8,
421            split: None,
422        };
423        let address = self
424            .take_address()
425            .ok_or(EnumerationError::OutOfAddresses)?;
426        debug_assert_eq!(address, ROOT_HUB_ADDRESS);
427        let (hub_endpoint, _root_descriptor) = probe_and_address(channel, timer, root, address)?;
428        let hub = Hub::configure(channel, timer, hub_endpoint, dwc2.port_speed() == 0)?;
429        let index = self
430            .record_hub(hub, 0)
431            .ok_or(EnumerationError::TooManyHubs)?;
432
433        // Whether the walk ran to the end or a callback broke out of it
434        // makes no difference here: stopping early is the caller's own
435        // request, not something to report as a failure. A fault is, and
436        // is picked up below.
437        let _ = self.walk_hub(channel, timer, index, &mut on_event);
438
439        match self.fault.take() {
440            Some(error) => Err(error),
441            None => Ok(()),
442        }
443    }
444
445    /// Asks every tracked hub what has changed since the last look,
446    /// bringing up anything newly attached and reporting anything gone.
447    /// One sweep, then it returns — pacing is the caller's.
448    ///
449    /// Every port of every tracked hub is read with GET_PORT_STATUS and
450    /// compared against what this type last saw there, so the cost of a
451    /// sweep scales with how many ports are on the bus rather than with
452    /// how much is happening on it. On a board whose root hub has four
453    /// ports and carries one four-port hub, that is eight control
454    /// transfers per sweep.
455    ///
456    /// A hub also has a status-change endpoint that would name just the
457    /// ports that moved (see
458    /// [`Hub::status_endpoint`]), which is
459    /// cheaper and is what a full host uses. It isn't used here, because
460    /// this crate's DWC2 driver cannot yet schedule high-speed periodic
461    /// transfers reliably: on the bench that endpoint returned
462    /// [`TransferError::FrameOverrun`], and — worse — completed
463    /// successfully with an all-zero bitmap while the hub's own port
464    /// status showed a connection change outstanding. A device attached to
465    /// such a hub is then never seen at all. Reading the ports says the
466    /// same thing over transfers that do work.
467    ///
468    /// Linux makes the same arrangement from the other direction: its hub
469    /// driver runs on that endpoint, but `hub_activate()` reads every port
470    /// directly whenever a hub is initialized, resumed or reset, and ten
471    /// consecutive endpoint errors force exactly that reset — so a hub
472    /// whose endpoint misbehaves degrades into polling rather than going
473    /// silent. Here polling is the floor; the endpoint becomes an
474    /// optimization on top of it once the periodic scheduling is fixed,
475    /// which changes nothing about what this method promises.
476    ///
477    /// A port that now reports a device gets the same bring-up
478    /// [`Self::enumerate`] gives one — reset, address, report — including
479    /// being walked in turn if it is a hub with devices already on it. A
480    /// port that has lost one reports [`Event::Detached`] for it, and for
481    /// everything that was behind it if it was a hub.
482    ///
483    /// Requires [`Self::enumerate`] to have run: with no hubs tracked
484    /// there is nothing to read, and this returns `Ok(())` having done
485    /// nothing. It does not notice the *root port* itself being
486    /// disconnected — on every board this targets the root hub is
487    /// soldered on, so that is a condition this type doesn't model.
488    ///
489    /// A port whose device fails to come up is tried once and then left
490    /// alone until the port's connection changes again, so a device this
491    /// can't talk to costs one attempt rather than a port reset on every
492    /// sweep for as long as it stays plugged in.
493    pub fn poll<F>(&mut self, timer: &Timer, mut on_event: F) -> Result<(), EnumerationError>
494    where
495        F: FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
496    {
497        let dwc2 = self.dwc2;
498        let mut channel = dwc2
499            .alloc_channel()
500            .ok_or(EnumerationError::OutOfChannels)?;
501        let channel = &mut channel;
502        let on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()> =
503            &mut on_event;
504
505        for index in 0..MAX_HUBS {
506            let Some(record) = self.hubs[index] else {
507                continue;
508            };
509            if self
510                .sweep_hub(channel, timer, index, &record, on_event)
511                .is_break()
512            {
513                break;
514            }
515        }
516
517        match self.fault.take() {
518            Some(error) => Err(error),
519            None => Ok(()),
520        }
521    }
522
523    /// Reads every port of one hub and reconciles what it reports against
524    /// what this type last recorded there, bringing up what has arrived
525    /// and tearing down what has gone.
526    ///
527    /// The comparison is against the port's present state rather than its
528    /// change bits, which makes a missed sweep harmless: a device plugged
529    /// and still plugged reads the same however many sweeps ago it
530    /// arrived, whereas a change bit is a one-shot that has to be caught.
531    /// The two sides are complementary — the hub knows the present and
532    /// remembers nothing, this type remembers and knows nothing of the
533    /// present — and neither alone can tell an arrival from a departure.
534    fn sweep_hub(
535        &mut self,
536        channel: &mut Channel,
537        timer: &Timer,
538        index: usize,
539        record: &HubRecord,
540        on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
541    ) -> ControlFlow<()> {
542        for port in 1..=record.hub.num_ports.min(MAX_PORTS as u8) {
543            let Ok(status) = record.hub.port_status(channel, timer, port) else {
544                continue;
545            };
546
547            // Read live rather than from `record`: an attach earlier in
548            // this same sweep may have walked a hub and filled in ports
549            // the snapshot still shows as empty.
550            let known = self.hubs[index].map_or(0, |r| r.ports[port as usize - 1]);
551
552            let flow = match (status.connected(), known) {
553                // Newly arrived.
554                (true, 0) => self.attach(channel, timer, index, port, on_event),
555                // Still there, or tried once and not worth retrying until
556                // the port is disturbed again.
557                (true, _) => ControlFlow::Continue(()),
558                // Empty and known to be.
559                (false, 0) => ControlFlow::Continue(()),
560                // Gone. A port that only ever failed to come up was never
561                // reported as attached, so nothing is reported now either
562                // — clearing the marker is the whole job, and it is what
563                // lets the next device on this port be tried afresh.
564                (false, PORT_FAILED) => {
565                    self.set_port(index, port, 0);
566                    ControlFlow::Continue(())
567                }
568                (false, _) => self.detach(channel, timer, index, port, on_event),
569            };
570
571            if status.connected() != (known != 0) {
572                // Acknowledge the connection change this sweep just acted
573                // on. Nothing here reads that bit — the comparison above
574                // is what decides — but leaving it latched would keep the
575                // hub's status-change endpoint asserted forever, which
576                // matters to whoever uses it next.
577                let _ = clear_port_feature(
578                    channel,
579                    timer,
580                    record.hub.endpoint(),
581                    port,
582                    PORT_FEATURE_C_CONNECTION,
583                );
584            }
585
586            if flow.is_break() {
587                return ControlFlow::Break(());
588            }
589        }
590        ControlFlow::Continue(())
591    }
592
593    /// Walks every port of the hub at `index`, bringing up whatever is
594    /// connected. The initial pass over a hub that has just been
595    /// configured, where nothing is known yet and every connected port is
596    /// therefore new.
597    ///
598    /// Taking `on_event` as a `dyn FnMut` rather than a generic is what
599    /// makes the recursion through [`Self::attach`] possible at all: a
600    /// generic callback would have to monomorphize into a distinct
601    /// function per nesting level, which for a function that calls itself
602    /// does not terminate.
603    fn walk_hub(
604        &mut self,
605        channel: &mut Channel,
606        timer: &Timer,
607        index: usize,
608        on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
609    ) -> ControlFlow<()> {
610        let Some(record) = self.hubs[index] else {
611            return ControlFlow::Continue(());
612        };
613        for port in 1..=record.hub.num_ports.min(MAX_PORTS as u8) {
614            let Ok(status) = record.hub.port_status(channel, timer, port) else {
615                continue;
616            };
617            if !status.connected() {
618                continue;
619            }
620            if self
621                .attach(channel, timer, index, port, on_event)
622                .is_break()
623            {
624                return ControlFlow::Break(());
625            }
626        }
627        ControlFlow::Continue(())
628    }
629
630    /// Resets `port` of the hub at `index`, addresses whatever answers,
631    /// reports it, and — if it is a hub — configures it, records it, and
632    /// walks it in turn.
633    ///
634    /// A port that fails anywhere along the way is marked
635    /// [`PORT_FAILED`] and otherwise left alone rather than failing the
636    /// whole walk: it holds something this can't talk to, which says
637    /// nothing about the other ports. The marker is what stops
638    /// [`Self::poll`] resetting it again on every sweep for as long as it
639    /// stays plugged in; unplugging it clears the marker, so the next
640    /// device there gets a fresh attempt.
641    fn attach(
642        &mut self,
643        channel: &mut Channel,
644        timer: &Timer,
645        index: usize,
646        port: u8,
647        on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
648    ) -> ControlFlow<()> {
649        let Some(record) = self.hubs[index] else {
650            return ControlFlow::Continue(());
651        };
652
653        let Ok(status) = record.hub.reset_port(channel, timer, port) else {
654            self.set_port(index, port, PORT_FAILED);
655            return ControlFlow::Continue(());
656        };
657        if !status.enabled() {
658            self.set_port(index, port, PORT_FAILED);
659            return ControlFlow::Continue(());
660        }
661
662        let Some(address) = self.take_address() else {
663            self.fault = Some(EnumerationError::OutOfAddresses);
664            return ControlFlow::Break(());
665        };
666        let probe = ControlEndpoint {
667            address: 0,
668            low_speed: status.low_speed(),
669            max_packet_size: 8,
670            split: record.hub.split_target(port, &status),
671        };
672        let Ok((endpoint, descriptor)) = probe_and_address(channel, timer, probe, address) else {
673            // The address was never taken up, so it goes straight back
674            // rather than being burned by a device that didn't answer.
675            self.release_address(address);
676            self.set_port(index, port, PORT_FAILED);
677            return ControlFlow::Continue(());
678        };
679        self.set_port(index, port, address);
680
681        let device = Device {
682            port,
683            hub_address: record.hub.endpoint().address,
684            depth: record.depth,
685            endpoint,
686            descriptor,
687        };
688        if on_event(channel, timer, Event::Attached(device)).is_break() {
689            return ControlFlow::Break(());
690        }
691
692        // A hub declares itself in its device descriptor, so this is
693        // already known without reading anything further. Configuring it
694        // powers and settles its own ports, after which it is driven
695        // exactly like the root hub was.
696        if descriptor.device_class == CLASS_HUB && record.depth < MAX_HUB_DEPTH {
697            let Ok(hub) = Hub::configure(channel, timer, endpoint, status.high_speed()) else {
698                return ControlFlow::Continue(());
699            };
700            let Some(child) = self.record_hub(hub, record.depth + 1) else {
701                self.fault = Some(EnumerationError::TooManyHubs);
702                return ControlFlow::Break(());
703            };
704            return self.walk_hub(channel, timer, child, on_event);
705        }
706        ControlFlow::Continue(())
707    }
708
709    /// Reports the device that was on `port` of the hub at `index` as
710    /// gone, along with everything that was behind it if it was a hub,
711    /// and frees every address involved.
712    ///
713    /// The teardown runs to completion even if the callback breaks partway
714    /// through: a half-freed topology would leave addresses that can never
715    /// be handed out again and hubs that are polled forever. The break is
716    /// remembered and returned once the state is consistent.
717    fn detach(
718        &mut self,
719        channel: &mut Channel,
720        timer: &Timer,
721        index: usize,
722        port: u8,
723        on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
724    ) -> ControlFlow<()> {
725        let Some(record) = self.hubs[index].as_mut() else {
726            return ControlFlow::Continue(());
727        };
728        let address = core::mem::take(&mut record.ports[port as usize - 1]);
729        if address == 0 {
730            return ControlFlow::Continue(());
731        }
732        let hub_address = record.hub.endpoint().address;
733
734        // Deepest first, so a driver hears about the device it holds
735        // before the hub that device was behind.
736        let mut stop = self.detach_subtree(channel, timer, address, on_event);
737        self.release_address(address);
738        if on_event(
739            channel,
740            timer,
741            Event::Detached {
742                hub_address,
743                port,
744                address,
745            },
746        )
747        .is_break()
748        {
749            stop = ControlFlow::Break(());
750        }
751        stop
752    }
753
754    /// Tears down the hub at `address`, if the departed device was one:
755    /// every device on its ports goes too, and theirs, and so on.
756    fn detach_subtree(
757        &mut self,
758        channel: &mut Channel,
759        timer: &Timer,
760        address: u8,
761        on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
762    ) -> ControlFlow<()> {
763        let Some(index) = (0..MAX_HUBS)
764            .find(|i| self.hubs[*i].is_some_and(|record| record.hub.endpoint().address == address))
765        else {
766            return ControlFlow::Continue(());
767        };
768        // Out of the table first: nothing below can reach back up to a hub
769        // that is already gone, and this bounds the recursion no matter
770        // what the table says.
771        let record = self.hubs[index].take();
772        let Some(record) = record else {
773            return ControlFlow::Continue(());
774        };
775
776        let mut stop = ControlFlow::Continue(());
777        for (port, &below) in record.ports.iter().enumerate() {
778            // A port that never came up was never reported as attached, so
779            // there is nothing to report or free for it now — and
780            // `PORT_FAILED` is not an address, so treating it as one would
781            // free a bit of the address pool that belongs to somebody else.
782            if below == 0 || below == PORT_FAILED {
783                continue;
784            }
785            if self
786                .detach_subtree(channel, timer, below, on_event)
787                .is_break()
788            {
789                stop = ControlFlow::Break(());
790            }
791            self.release_address(below);
792            if on_event(
793                channel,
794                timer,
795                Event::Detached {
796                    hub_address: address,
797                    port: port as u8 + 1,
798                    address: below,
799                },
800            )
801            .is_break()
802            {
803                stop = ControlFlow::Break(());
804            }
805        }
806        stop
807    }
808
809    /// Takes the lowest free USB device address, or `None` if all 127 are
810    /// in use.
811    fn take_address(&mut self) -> Option<u8> {
812        let address = (1..=MAX_ADDRESS).find(|a| self.addresses & (1u128 << a) == 0)?;
813        self.addresses |= 1u128 << address;
814        Some(address)
815    }
816
817    /// Returns an address to the pool. It can be handed out again
818    /// immediately, which is why [`Event::Detached`] carries it: a driver
819    /// still talking to that address after being told is talking to
820    /// whatever got plugged in next.
821    ///
822    /// Anything past [`MAX_ADDRESS`] is ignored rather than shifted by:
823    /// the bitmap is 128 bits wide, so a stray [`PORT_FAILED`] reaching
824    /// here would shift past the end of it — which is a panic in a debug
825    /// build and, worse, silently wraps round and frees somebody else's
826    /// address in a release one.
827    fn release_address(&mut self, address: u8) {
828        if address <= MAX_ADDRESS {
829            self.addresses &= !(1u128 << address);
830        }
831    }
832
833    /// Files a configured hub in the tracking table, returning its index,
834    /// or `None` if the table is full.
835    fn record_hub(&mut self, hub: Hub, depth: u8) -> Option<usize> {
836        let index = (0..MAX_HUBS).find(|i| self.hubs[*i].is_none())?;
837        self.hubs[index] = Some(HubRecord {
838            hub,
839            depth,
840            ports: [0; MAX_PORTS],
841        });
842        Some(index)
843    }
844
845    /// Records what is on a downstream port of the hub at `index` — an
846    /// address, `0` for nothing, or [`PORT_FAILED`]. A no-op if that hub
847    /// is no longer tracked, which is what a port of a hub torn down
848    /// mid-sweep looks like.
849    fn set_port(&mut self, index: usize, port: u8, value: u8) {
850        if let Some(record) = self.hubs[index].as_mut() {
851            record.ports[port as usize - 1] = value;
852        }
853    }
854}
855
856/// Enumerates every device behind the on-board root hub, calling
857/// `on_device` once per successfully-addressed downstream device.
858///
859/// [`Bus::enumerate`] without keeping the bus around afterwards — the
860/// whole walk, including recursion into downstream hubs, with the
861/// topology discarded when it returns. That is all a program needs when
862/// everything is plugged in before the board boots and nothing moves,
863/// which is most of them.
864///
865/// Reach for [`Bus`] instead when something can attach after startup, or
866/// when a device being unplugged has to be noticed. A device slow enough
867/// to come up is indistinguishable from an absent one here, and that is
868/// a matter of the board's timing rather than of anything the user did:
869/// see [`Bus::poll`].
870pub fn enumerate<F>(
871    dwc2: &Dwc2Host,
872    timer: &Timer,
873    mut on_device: F,
874) -> Result<(), EnumerationError>
875where
876    F: FnMut(&mut Channel, &Timer, Device) -> ControlFlow<()>,
877{
878    Bus::new(dwc2).enumerate(timer, |channel, timer, event| match event {
879        Event::Attached(device) => on_device(channel, timer, device),
880        // Nothing can be gone from a bus this call has only just met.
881        Event::Detached { .. } => ControlFlow::Continue(()),
882    })
883}