imxrt_usbd/
driver.rs

1//! Internal USB driver
2//!
3//! The goal is to keep this somewhat agnostic from the usb-device
4//! bus behaviors, so that it could be used separately. However, it's
5//! not yet exposed in the package's API.
6
7use crate::{buffer, gpt, ral};
8use usb_device::{
9    bus::PollResult,
10    endpoint::{EndpointAddress, EndpointType},
11    UsbDirection, UsbError,
12};
13
14/// Direct index to the OUT control endpoint
15fn ctrl_ep0_out() -> EndpointAddress {
16    // Constructor not currently const. Otherwise, this would
17    // be a const.
18    EndpointAddress::from_parts(0, UsbDirection::Out)
19}
20
21/// Direct index to the IN control endpoint
22fn ctrl_ep0_in() -> EndpointAddress {
23    EndpointAddress::from_parts(0, UsbDirection::In)
24}
25
26/// USB low / full / high speed setting.
27#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
28pub enum Speed {
29    /// Throttle to low / full speeds.
30    ///
31    /// If a host is capable of high-speed, this will prevent
32    /// the device from enumerating as a high-speed device.
33    LowFull,
34    /// High speed.
35    ///
36    /// A high-speed device can still interface a low / full
37    /// speed host, so use this setting for the most flexibility.
38    #[default]
39    High,
40}
41
42/// A USB driver
43///
44/// After you allocate a `Driver` with [`new()`](Driver::new), you must
45///
46/// - call [`initialize()`](Driver::initialize) once
47/// - supply endpoint memory with [`set_endpoint_memory()`](USB::set_endpoint_memory)
48pub struct Driver {
49    usb: ral::usb::Instance,
50    phy: ral::usbphy::Instance,
51    buffer_allocator: buffer::Allocator,
52    ep_allocator: crate::state::EndpointAllocator<'static>,
53    /// Track which read endpoints have completed, so as to not
54    /// confuse the device and appear out of sync with poll() calls.
55    ///
56    /// Persisting the ep_out mask across poll() calls lets us make
57    /// sure that results of ep_read calls match what's signaled from
58    /// poll() calls. During testing, we saw that poll() wouldn't signal
59    /// ep_out complete. But, the class could still call ep_read(), and
60    /// it would return data. The usb-device test_class treats that as
61    /// a failure, so we should keep behaviors consistent.
62    ep_out: u16,
63}
64
65impl Driver {
66    /// Create a new `Driver`
67    ///
68    /// Creation does nothing except for assign static memory to the driver.
69    /// After creating the driver, call [`initialize()`](USB::initialize).
70    ///
71    /// # Panics
72    ///
73    /// Panics if the endpoint bufer or state has already been assigned to another USB
74    /// driver.
75    pub fn new<P: crate::Peripherals, const SIZE: usize, const EP_COUNT: usize>(
76        peripherals: P,
77        buffer: &'static crate::buffer::EndpointMemory<SIZE>,
78        state: &'static crate::state::EndpointState<EP_COUNT>,
79    ) -> Self {
80        // Safety: taking static memory. Assumes that the provided
81        // USB instance is a singleton, which is the only safe way for it
82        // to exist.
83        let ral::Instances { usb, usbphy: phy } = ral::instances(peripherals);
84        let ep_allocator = state.allocator().expect("Endpoint state already assigned");
85        Driver {
86            usb,
87            phy,
88            buffer_allocator: buffer
89                .allocator()
90                .expect("Endpoint memory already assigned"),
91            ep_allocator,
92            ep_out: 0,
93        }
94    }
95
96    /// Initialize the USB physical layer, and the USB core registers
97    ///
98    /// Assumes that the CCM clock gates are enabled, and the PLL is on.
99    ///
100    /// You **must** call this once, before creating the complete USB
101    /// bus.
102    pub fn initialize(&mut self, speed: Speed) {
103        ral::write_reg!(ral::usbphy, self.phy, CTRL_SET, SFTRST: 1);
104        ral::write_reg!(ral::usbphy, self.phy, CTRL_CLR, SFTRST: 1);
105        ral::write_reg!(ral::usbphy, self.phy, CTRL_CLR, CLKGATE: 1);
106        ral::write_reg!(ral::usbphy, self.phy, PWD, 0);
107
108        ral::write_reg!(ral::usb, self.usb, USBCMD, RST: 1);
109        while ral::read_reg!(ral::usb, self.usb, USBCMD, RST == 1) {}
110        // ITC is reset to some non-immediate value. Use the 'immediate' value by default.
111        // (Note: this also zeros all other USBCMD fields.)
112        ral::write_reg!(ral::usb, self.usb, USBCMD, ITC: 0);
113
114        ral::write_reg!(ral::usb, self.usb, USBMODE, CM: CM_2, SLOM: 1);
115        ral::modify_reg!(ral::usb, self.usb, PORTSC1, PFSC: (speed == Speed::LowFull) as u32);
116
117        ral::modify_reg!(ral::usb, self.usb, USBSTS, |usbsts| usbsts);
118        // Disable interrupts by default
119        ral::write_reg!(ral::usb, self.usb, USBINTR, 0);
120
121        ral::write_reg!(
122            ral::usb,
123            self.usb,
124            ASYNCLISTADDR,
125            self.ep_allocator.qh_list_addr() as u32
126        )
127    }
128
129    /// Enable zero-length termination (ZLT) for the given endpoint
130    ///
131    /// When ZLT is enabled, software does not need to send a zero-length packet
132    /// to terminate a transfer where the number of bytes equals the max packet size.
133    /// The hardware will send this zero-length packet itself. By default, ZLT is off,
134    /// and software is expected to send these packets. Enable this if you're confident
135    /// that your (third-party) device / USB class isn't already sending these packets.
136    ///
137    /// This call does nothing if the endpoint isn't allocated.
138    pub fn enable_zlt(&mut self, ep_addr: EndpointAddress) {
139        if let Some(ep) = self.ep_allocator.endpoint_mut(ep_addr) {
140            ep.enable_zlt();
141        }
142    }
143
144    /// Enable (`true`) or disable (`false`) USB interrupts
145    pub fn set_interrupts(&mut self, interrupts: bool) {
146        if interrupts {
147            // Keep this in sync with the poll() behaviors
148            ral::modify_reg!(ral::usb, self.usb, USBINTR, UE: 1, URE: 1);
149        } else {
150            ral::modify_reg!(ral::usb, self.usb, USBINTR, UE: 0, URE: 0);
151        }
152    }
153
154    /// Acquire mutable access to a GPT timer
155    pub fn gpt_mut<R>(&mut self, instance: gpt::Instance, f: impl FnOnce(&mut gpt::Gpt) -> R) -> R {
156        let mut gpt = gpt::Gpt::new(&mut self.usb, instance);
157        f(&mut gpt)
158    }
159
160    pub fn set_address(&mut self, address: u8) {
161        // See the "quirk" note in the UsbBus impl. We're using USBADRA to let
162        // the hardware set the address before the status phase.
163        ral::write_reg!(ral::usb, self.usb, DEVICEADDR, USBADR: address as u32, USBADRA: 1);
164        debug!("ADDRESS {=u8}", address);
165    }
166
167    pub fn attach(&mut self) {
168        ral::modify_reg!(ral::usb, self.usb, USBCMD, RS: 1);
169    }
170
171    pub fn bus_reset(&mut self) {
172        ral::modify_reg!(ral::usb, self.usb, ENDPTSTAT, |endptstat| endptstat);
173
174        ral::modify_reg!(ral::usb, self.usb, ENDPTCOMPLETE, |endptcomplete| {
175            endptcomplete
176        });
177        ral::modify_reg!(ral::usb, self.usb, ENDPTNAK, |endptnak| endptnak);
178        ral::write_reg!(ral::usb, self.usb, ENDPTNAKEN, 0);
179
180        while ral::read_reg!(ral::usb, self.usb, ENDPTPRIME) != 0 {}
181        ral::write_reg!(ral::usb, self.usb, ENDPTFLUSH, u32::max_value());
182        while ral::read_reg!(ral::usb, self.usb, ENDPTFLUSH) != 0 {}
183
184        debug_assert!(
185            ral::read_reg!(ral::usb, self.usb, PORTSC1, PR == 1),
186            "Took too long to handle bus reset"
187        );
188        debug!("RESET");
189
190        self.initialize_endpoints();
191    }
192
193    /// Check if the endpoint is valid
194    pub fn is_allocated(&self, addr: EndpointAddress) -> bool {
195        self.ep_allocator.endpoint(addr).is_some()
196    }
197
198    /// Read either a setup, or a data buffer, from EP0 OUT
199    ///
200    /// # Panics
201    ///
202    /// Panics if EP0 OUT isn't allocated.
203    pub fn ctrl0_read(&mut self, buffer: &mut [u8]) -> Result<usize, UsbError> {
204        let ctrl_out = self.ep_allocator.endpoint_mut(ctrl_ep0_out()).unwrap();
205        if ctrl_out.has_setup(&self.usb) && buffer.len() >= 8 {
206            debug!("EP0 Out SETUP");
207            let setup = ctrl_out.read_setup(&self.usb);
208            buffer[..8].copy_from_slice(&setup.to_le_bytes());
209
210            if !ctrl_out.is_primed(&self.usb) {
211                ctrl_out.clear_nack(&self.usb);
212                let max_packet_len = ctrl_out.max_packet_len();
213                ctrl_out.schedule_transfer(&self.usb, max_packet_len);
214            }
215
216            Ok(8)
217        } else {
218            ctrl_out.check_errors()?;
219
220            if ctrl_out.is_primed(&self.usb) {
221                return Err(UsbError::WouldBlock);
222            }
223
224            ctrl_out.clear_complete(&self.usb);
225            ctrl_out.clear_nack(&self.usb);
226
227            let read = ctrl_out.read(buffer);
228            debug!("EP0 Out {=usize}", read);
229            let max_packet_len = ctrl_out.max_packet_len();
230            ctrl_out.schedule_transfer(&self.usb, max_packet_len);
231
232            Ok(read)
233        }
234    }
235
236    /// Write to the host from EP0 IN
237    ///
238    /// Schedules the next OUT transfer to satisfy a status phase.
239    ///
240    /// # Panics
241    ///
242    /// Panics if EP0 IN isn't allocated, or if EP0 OUT isn't allocated.
243    pub fn ctrl0_write(&mut self, buffer: &[u8]) -> Result<usize, UsbError> {
244        let ctrl_in = self.ep_allocator.endpoint_mut(ctrl_ep0_in()).unwrap();
245        debug!("EP0 In {=usize}", buffer.len());
246        ctrl_in.check_errors()?;
247
248        if ctrl_in.is_primed(&self.usb) {
249            return Err(UsbError::WouldBlock);
250        }
251
252        ctrl_in.clear_nack(&self.usb);
253
254        let written = ctrl_in.write(buffer);
255        ctrl_in.schedule_transfer(&self.usb, written);
256
257        // Might need an OUT schedule for a status phase...
258        let ctrl_out = self.ep_allocator.endpoint_mut(ctrl_ep0_out()).unwrap();
259        if !ctrl_out.is_primed(&self.usb) {
260            ctrl_out.clear_complete(&self.usb);
261            ctrl_out.clear_nack(&self.usb);
262            ctrl_out.schedule_transfer(&self.usb, 0);
263        }
264
265        Ok(written)
266    }
267
268    /// Read data from an endpoint, and schedule the next transfer
269    ///
270    /// # Panics
271    ///
272    /// Panics if the endpoint isn't allocated.
273    pub fn ep_read(&mut self, buffer: &mut [u8], addr: EndpointAddress) -> Result<usize, UsbError> {
274        let ep = self.ep_allocator.endpoint_mut(addr).unwrap();
275        debug!("EP{=usize} Out", ep.address().index());
276        ep.check_errors()?;
277
278        if ep.is_primed(&self.usb) || (self.ep_out & (1 << ep.address().index()) == 0) {
279            return Err(UsbError::WouldBlock);
280        }
281
282        ep.clear_complete(&self.usb); // Clears self.ep_out bit on the next poll() call...
283        ep.clear_nack(&self.usb);
284
285        let read = ep.read(buffer);
286
287        let max_packet_len = ep.max_packet_len();
288        ep.schedule_transfer(&self.usb, max_packet_len);
289
290        Ok(read)
291    }
292
293    /// Write data to an endpoint
294    ///
295    /// # Panics
296    ///
297    /// Panics if the endpoint isn't allocated.
298    pub fn ep_write(&mut self, buffer: &[u8], addr: EndpointAddress) -> Result<usize, UsbError> {
299        let ep = self.ep_allocator.endpoint_mut(addr).unwrap();
300        ep.check_errors()?;
301
302        if ep.is_primed(&self.usb) {
303            return Err(UsbError::WouldBlock);
304        }
305
306        ep.clear_nack(&self.usb);
307
308        let written = ep.write(buffer);
309        ep.schedule_transfer(&self.usb, written);
310
311        Ok(written)
312    }
313
314    /// Stall an endpoint
315    ///
316    /// # Panics
317    ///
318    /// Panics if the endpoint isn't allocated
319    pub fn ep_stall(&mut self, stall: bool, addr: EndpointAddress) {
320        let ep = self.ep_allocator.endpoint_mut(addr).unwrap();
321        ep.set_stalled(&self.usb, stall);
322
323        // Re-prime any OUT endpoints if we're unstalling
324        if !stall && addr.direction() == UsbDirection::Out && !ep.is_primed(&self.usb) {
325            let max_packet_len = ep.max_packet_len();
326            ep.schedule_transfer(&self.usb, max_packet_len);
327        }
328    }
329
330    /// Checks if an endpoint is stalled
331    ///
332    /// # Panics
333    ///
334    /// Panics if the endpoint isn't allocated
335    pub fn is_ep_stalled(&self, addr: EndpointAddress) -> bool {
336        self.ep_allocator
337            .endpoint(addr)
338            .unwrap()
339            .is_stalled(&self.usb)
340    }
341
342    /// Allocate a buffer from the endpoint memory
343    pub fn allocate_buffer(&mut self, max_packet_len: usize) -> Option<buffer::Buffer> {
344        self.buffer_allocator.allocate(max_packet_len)
345    }
346
347    /// Allocate a specific endpoint
348    ///
349    /// # Panics
350    ///
351    /// Panics if the endpoint is already allocated.
352    pub fn allocate_ep(
353        &mut self,
354        addr: EndpointAddress,
355        buffer: buffer::Buffer,
356        kind: EndpointType,
357    ) {
358        self.ep_allocator
359            .allocate_endpoint(addr, buffer, kind)
360            .unwrap();
361
362        debug!(
363            "ALLOC EP{=usize} {} {}",
364            addr.index(),
365            addr.direction(),
366            kind
367        );
368    }
369
370    /// Invoked when the device transitions into the configured state
371    pub fn on_configured(&mut self) {
372        self.enable_endpoints();
373        self.prime_endpoints();
374    }
375
376    /// Enable all non-zero endpoints
377    ///
378    /// This should only be called when the device is configured
379    fn enable_endpoints(&mut self) {
380        for ep in self.ep_allocator.nonzero_endpoints_iter_mut() {
381            ep.enable(&self.usb);
382        }
383    }
384
385    /// Prime all non-zero, enabled OUT endpoints
386    fn prime_endpoints(&mut self) {
387        for ep in self.ep_allocator.nonzero_endpoints_iter_mut() {
388            if ep.is_enabled(&self.usb) && ep.address().direction() == UsbDirection::Out {
389                let max_packet_len = ep.max_packet_len();
390                ep.schedule_transfer(&self.usb, max_packet_len);
391            }
392        }
393    }
394
395    /// Initialize (or reinitialize) all non-zero endpoints
396    fn initialize_endpoints(&mut self) {
397        for ep in self.ep_allocator.nonzero_endpoints_iter_mut() {
398            ep.initialize(&self.usb);
399        }
400    }
401
402    /// Poll for reset or USB traffic
403    pub fn poll(&mut self) -> PollResult {
404        let usbsts = ral::read_reg!(ral::usb, self.usb, USBSTS);
405        use ral::usb::USBSTS;
406
407        if usbsts & USBSTS::URI::mask != 0 {
408            ral::write_reg!(ral::usb, self.usb, USBSTS, URI: 1);
409            return PollResult::Reset;
410        }
411
412        if usbsts & USBSTS::UI::mask != 0 {
413            ral::write_reg!(ral::usb, self.usb, USBSTS, UI: 1);
414
415            trace!(
416                "ENDPTSETUPSTAT: {=u32:#010X}  ENDPTCOMPLETE: {=u32:#010X}",
417                ral::read_reg!(ral::usb, self.usb, ENDPTSETUPSTAT),
418                ral::read_reg!(ral::usb, self.usb, ENDPTCOMPLETE)
419            );
420            // Note: could be complete in one register read, but this is a little
421            // easier to comprehend...
422            self.ep_out = ral::read_reg!(ral::usb, self.usb, ENDPTCOMPLETE, ERCE) as u16;
423
424            let ep_in_complete = ral::read_reg!(ral::usb, self.usb, ENDPTCOMPLETE, ETCE);
425            ral::write_reg!(ral::usb, self.usb, ENDPTCOMPLETE, ETCE: ep_in_complete);
426
427            let ep_setup = ral::read_reg!(ral::usb, self.usb, ENDPTSETUPSTAT) as u16;
428
429            PollResult::Data {
430                ep_out: self.ep_out,
431                ep_in_complete: ep_in_complete as u16,
432                ep_setup,
433            }
434        } else {
435            PollResult::None
436        }
437    }
438}