Skip to main content

embassy_usb_synopsys_otg/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)]
3#![allow(unsafe_op_in_unsafe_fn)]
4#![doc = include_str!("../README.md")]
5#![warn(missing_docs)]
6
7// This must go FIRST so that all the other modules see its macros.
8mod fmt;
9
10use core::cell::UnsafeCell;
11use core::future::poll_fn;
12use core::marker::PhantomData;
13use core::sync::atomic::{AtomicBool, AtomicU16, AtomicU32, Ordering};
14use core::task::Poll;
15
16use embassy_sync::waitqueue::AtomicWaker;
17use embassy_usb_driver::{
18    Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut,
19    EndpointType, Event, Unsupported,
20};
21
22use crate::fmt::Bytes;
23
24pub mod otg_v1;
25
26use otg_v1::{Otg, regs, vals};
27
28/// Handle interrupts.
29pub unsafe fn on_interrupt<const MAX_EP_COUNT: usize>(r: Otg, state: &State<MAX_EP_COUNT>, ep_count: usize) {
30    trace!("irq");
31
32    let ints = r.gintsts().read();
33    if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
34        // Mask interrupts and notify `Bus` to process them
35        r.gintmsk().write(|w| {
36            w.set_iepint(true);
37            w.set_oepint(true);
38            w.set_rxflvlm(true);
39        });
40        state.bus_waker.wake();
41    }
42
43    // Handle RX
44    while r.gintsts().read().rxflvl() {
45        let status = r.grxstsp().read();
46        trace!("=== status {:08x}", status.0);
47        let ep_num = status.epnum() as usize;
48        let len = status.bcnt() as usize;
49
50        assert!(ep_num < ep_count);
51
52        match status.pktstsd() {
53            vals::Pktstsd::SETUP_DATA_RX => {
54                trace!("SETUP_DATA_RX");
55                assert!(len == 8, "invalid SETUP packet length={}", len);
56                assert!(ep_num == 0, "invalid SETUP packet endpoint={}", ep_num);
57
58                // flushing TX if something stuck in control endpoint
59                if r.dieptsiz(ep_num).read().pktcnt() != 0 {
60                    r.grstctl().modify(|w| {
61                        w.set_txfnum(ep_num as _);
62                        w.set_txfflsh(true);
63                    });
64                    while r.grstctl().read().txfflsh() {}
65                }
66
67                let data = &state.cp_state.setup_data;
68                data[0].store(r.fifo(0).read().data(), Ordering::Relaxed);
69                data[1].store(r.fifo(0).read().data(), Ordering::Relaxed);
70            }
71            vals::Pktstsd::OUT_DATA_RX => {
72                trace!("OUT_DATA_RX ep={} len={}", ep_num, len);
73
74                if state.ep_states[ep_num].out_size.load(Ordering::Acquire) == EP_OUT_BUFFER_EMPTY {
75                    // SAFETY: Buffer size is allocated to be equal to endpoint's maximum packet size
76                    // We trust the peripheral to not exceed its configured MPSIZ
77                    let buf =
78                        unsafe { core::slice::from_raw_parts_mut(*state.ep_states[ep_num].out_buffer.get(), len) };
79
80                    let mut chunks = buf.chunks_exact_mut(4);
81                    for chunk in &mut chunks {
82                        // RX FIFO is shared so always read from fifo(0)
83                        let data = r.fifo(0).read().0;
84                        chunk.copy_from_slice(&data.to_ne_bytes());
85                    }
86                    let rem = chunks.into_remainder();
87                    if !rem.is_empty() {
88                        let data = r.fifo(0).read().0;
89                        rem.copy_from_slice(&data.to_ne_bytes()[0..rem.len()]);
90                    }
91
92                    state.ep_states[ep_num].out_size.store(len as u16, Ordering::Release);
93                    state.ep_states[ep_num].out_waker.wake();
94                } else {
95                    error!("ep_out buffer overflow index={}", ep_num);
96
97                    // discard FIFO data
98                    let len_words = (len + 3) / 4;
99                    for _ in 0..len_words {
100                        r.fifo(0).read().data();
101                    }
102                }
103            }
104            vals::Pktstsd::OUT_DATA_DONE => {
105                trace!("OUT_DATA_DONE ep={}", ep_num);
106            }
107            vals::Pktstsd::SETUP_DATA_DONE => {
108                trace!("SETUP_DATA_DONE ep={}", ep_num);
109            }
110            x => trace!("unknown PKTSTS: {}", x.to_bits()),
111        }
112    }
113
114    // IN endpoint interrupt
115    if ints.iepint() {
116        let mut ep_mask = r.daint().read().iepint();
117        let mut ep_num = 0;
118
119        // Iterate over endpoints while there are non-zero bits in the mask
120        while ep_mask != 0 {
121            if ep_mask & 1 != 0 {
122                let ep_ints = r.diepint(ep_num).read();
123
124                // clear all
125                r.diepint(ep_num).write_value(ep_ints);
126
127                // TXFE is cleared in DIEPEMPMSK
128                if ep_ints.txfe() {
129                    critical_section::with(|_| {
130                        r.diepempmsk().modify(|w| {
131                            w.set_ineptxfem(w.ineptxfem() & !(1 << ep_num));
132                        });
133                    });
134                }
135
136                state.ep_states[ep_num].in_waker.wake();
137                trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0);
138            }
139
140            ep_mask >>= 1;
141            ep_num += 1;
142        }
143    }
144
145    // out endpoint interrupt
146    if ints.oepint() {
147        trace!("oepint");
148        let mut ep_mask = r.daint().read().oepint();
149        let mut ep_num = 0;
150
151        // Iterate over endpoints while there are non-zero bits in the mask
152        while ep_mask != 0 {
153            if ep_mask & 1 != 0 {
154                let ep_ints = r.doepint(ep_num).read();
155                // clear all
156                r.doepint(ep_num).write_value(ep_ints);
157
158                if ep_ints.stup() {
159                    state.cp_state.setup_ready.store(true, Ordering::Release);
160                }
161                state.ep_states[ep_num].out_waker.wake();
162                trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
163            }
164
165            ep_mask >>= 1;
166            ep_num += 1;
167        }
168    }
169
170    if ints.eopf() {
171        let frame_number = r.dsts().read().fnsof();
172        let frame_is_odd = frame_number & 0x01 == 1;
173
174        // If an isochronous endpoint has an IN message waiting in its FIFO, but the host didn't poll for it before eof,
175        // switch the packet polarity, in the hope that it will be polled for in the next frame.
176        for ep_num in (0..ep_count).into_iter().filter(|ep_num| {
177            let diepctl = r.diepctl(*ep_num).read();
178            // Find iso endpoints
179            diepctl.eptyp() == vals::Eptyp::ISOCHRONOUS
180                // That have and unsent IN message
181                && diepctl.epena()
182                // Where the frame polarity matches the current frame
183                && diepctl.eonum_dpid() == frame_is_odd
184        }) {
185            trace!("Unsent message at EOF for ep: {}, frame: {}", ep_num, frame_number);
186
187            let ep_diepctl = r.diepctl(ep_num);
188            let ep_diepint = r.diepint(ep_num);
189
190            // Set NAK
191            ep_diepctl.modify(|m| m.set_snak(true));
192            while !ep_diepint.read().inepne() {}
193
194            // Disable the endpoint
195            ep_diepctl.modify(|m| {
196                m.set_snak(true);
197                m.set_epdis(true);
198            });
199            while !ep_diepint.read().epdisd() {}
200            ep_diepint.modify(|m| m.set_epdisd(true));
201
202            // Switch the packet polarity
203            ep_diepctl.modify(|r| {
204                if frame_is_odd {
205                    r.set_sd0pid_sevnfrm(true);
206                } else {
207                    r.set_sd1pid_soddfrm(true);
208                }
209            });
210
211            // Enable the endpoint again
212            ep_diepctl.modify(|w| {
213                w.set_cnak(true);
214                w.set_epena(true);
215            });
216        }
217    }
218}
219
220/// USB PHY type
221#[derive(Copy, Clone, Debug, Eq, PartialEq)]
222pub enum PhyType {
223    /// Internal Full-Speed PHY
224    ///
225    /// Available on most High-Speed peripherals.
226    InternalFullSpeed,
227    /// Internal High-Speed PHY
228    ///
229    /// Available on a few STM32 chips.
230    InternalHighSpeed,
231    /// External ULPI Full-Speed PHY (or High-Speed PHY in Full-Speed mode)
232    ExternalFullSpeed,
233    /// External ULPI High-Speed PHY
234    ExternalHighSpeed,
235}
236
237impl PhyType {
238    /// Get whether this PHY is any of the internal types.
239    pub fn internal(&self) -> bool {
240        match self {
241            PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true,
242            PhyType::ExternalHighSpeed | PhyType::ExternalFullSpeed => false,
243        }
244    }
245
246    /// Get whether this PHY is any of the high-speed types.
247    pub fn high_speed(&self) -> bool {
248        match self {
249            PhyType::InternalFullSpeed | PhyType::ExternalFullSpeed => false,
250            PhyType::ExternalHighSpeed | PhyType::InternalHighSpeed => true,
251        }
252    }
253
254    fn to_dspd(&self) -> vals::Dspd {
255        match self {
256            PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL,
257            PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED,
258            PhyType::ExternalFullSpeed => vals::Dspd::FULL_SPEED_EXTERNAL,
259            PhyType::ExternalHighSpeed => vals::Dspd::HIGH_SPEED,
260        }
261    }
262}
263
264/// Indicates that [State::ep_out_buffers] is empty.
265const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX;
266
267struct EpState {
268    in_waker: AtomicWaker,
269    out_waker: AtomicWaker,
270    /// RX FIFO is shared so extra buffers are needed to dequeue all data without waiting on each endpoint.
271    /// Buffers are ready when associated [State::ep_out_size] != [EP_OUT_BUFFER_EMPTY].
272    out_buffer: UnsafeCell<*mut u8>,
273    out_size: AtomicU16,
274}
275
276// SAFETY: The EndpointAllocator ensures that the buffer points to valid memory exclusive for each endpoint and is
277// large enough to hold the maximum packet size. Access to the buffer is synchronized between the USB interrupt and the
278// EndpointOut impl using the out_size atomic variable.
279unsafe impl Send for EpState {}
280unsafe impl Sync for EpState {}
281
282struct ControlPipeSetupState {
283    /// Holds received SETUP packets. Available if [Ep0State::setup_ready] is true.
284    setup_data: [AtomicU32; 2],
285    setup_ready: AtomicBool,
286}
287
288/// USB OTG driver state.
289pub struct State<const EP_COUNT: usize> {
290    cp_state: ControlPipeSetupState,
291    ep_states: [EpState; EP_COUNT],
292    bus_waker: AtomicWaker,
293}
294
295unsafe impl<const EP_COUNT: usize> Send for State<EP_COUNT> {}
296unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {}
297
298impl<const EP_COUNT: usize> State<EP_COUNT> {
299    /// Create a new State.
300    pub const fn new() -> Self {
301        Self {
302            cp_state: ControlPipeSetupState {
303                setup_data: [const { AtomicU32::new(0) }; 2],
304                setup_ready: AtomicBool::new(false),
305            },
306            ep_states: [const {
307                EpState {
308                    in_waker: AtomicWaker::new(),
309                    out_waker: AtomicWaker::new(),
310                    out_buffer: UnsafeCell::new(0 as _),
311                    out_size: AtomicU16::new(EP_OUT_BUFFER_EMPTY),
312                }
313            }; EP_COUNT],
314            bus_waker: AtomicWaker::new(),
315        }
316    }
317}
318
319#[derive(Debug, Clone, Copy)]
320struct EndpointData {
321    ep_type: EndpointType,
322    max_packet_size: u16,
323    fifo_size_words: u16,
324}
325
326/// USB driver config.
327#[non_exhaustive]
328#[derive(Clone, Copy, PartialEq, Eq, Debug)]
329pub struct Config {
330    /// Enable VBUS detection.
331    ///
332    /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
333    /// This is done by checking whether there is 5V on the VBUS pin or not.
334    ///
335    /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
336    /// (If there's no power in VBUS your device would be off anyway, so it's fine to always assume
337    /// there's power in VBUS, i.e. the USB cable is always plugged in.)
338    ///
339    /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
340    /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
341    ///
342    /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
343    /// voltage divider. See ST application note AN4879 and the reference manual for more details.
344    pub vbus_detection: bool,
345
346    /// Enable transceiver delay.
347    ///
348    /// Some ULPI PHYs like the Microchip USB334x series require a delay between the ULPI register write that initiates
349    /// the HS Chirp and the subsequent transmit command, otherwise the HS Chirp does not get executed and the deivce
350    /// enumerates in FS mode. Some USB Link IP like those in the STM32H7 series support adding this delay to work with
351    /// the affected PHYs.
352    pub xcvrdly: bool,
353}
354
355impl Default for Config {
356    fn default() -> Self {
357        Self {
358            vbus_detection: false,
359            xcvrdly: false,
360        }
361    }
362}
363
364/// USB OTG driver.
365pub struct Driver<'d, const MAX_EP_COUNT: usize> {
366    config: Config,
367    ep_in: [Option<EndpointData>; MAX_EP_COUNT],
368    ep_out: [Option<EndpointData>; MAX_EP_COUNT],
369    ep_out_buffer: &'d mut [u8],
370    ep_out_buffer_offset: usize,
371    instance: OtgInstance<'d, MAX_EP_COUNT>,
372}
373
374impl<'d, const MAX_EP_COUNT: usize> Driver<'d, MAX_EP_COUNT> {
375    /// Initializes the USB OTG peripheral.
376    ///
377    /// # Arguments
378    ///
379    /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets.
380    /// Must be large enough to fit all OUT endpoint max packet sizes.
381    /// Endpoint allocation will fail if it is too small.
382    /// * `instance` - The USB OTG peripheral instance and its configuration.
383    /// * `config` - The USB driver configuration.
384    pub fn new(ep_out_buffer: &'d mut [u8], instance: OtgInstance<'d, MAX_EP_COUNT>, config: Config) -> Self {
385        Self {
386            config,
387            ep_in: [None; MAX_EP_COUNT],
388            ep_out: [None; MAX_EP_COUNT],
389            ep_out_buffer,
390            ep_out_buffer_offset: 0,
391            instance,
392        }
393    }
394
395    /// Returns the total amount of words (u32) allocated in dedicated FIFO.
396    fn allocated_fifo_words(&self) -> u16 {
397        self.instance.extra_rx_fifo_words + ep_fifo_size(&self.ep_out) + ep_fifo_size(&self.ep_in)
398    }
399
400    /// Creates an [`Endpoint`] with the given parameters.
401    fn alloc_endpoint<D: Dir>(
402        &mut self,
403        ep_type: EndpointType,
404        ep_addr: Option<EndpointAddress>,
405        max_packet_size: u16,
406        interval_ms: u8,
407    ) -> Result<Endpoint<'d, D>, EndpointAllocError> {
408        trace!(
409            "allocating type={:?} mps={:?} interval_ms={}, dir={:?}",
410            ep_type,
411            max_packet_size,
412            interval_ms,
413            D::dir()
414        );
415
416        if D::dir() == Direction::Out {
417            if self.ep_out_buffer_offset + max_packet_size as usize > self.ep_out_buffer.len() {
418                error!("Not enough endpoint out buffer capacity");
419                return Err(EndpointAllocError);
420            }
421        };
422
423        let fifo_size_words = match D::dir() {
424            Direction::Out => (max_packet_size + 3) / 4,
425            // INEPTXFD requires minimum size of 16 words
426            Direction::In => u16::max((max_packet_size + 3) / 4, 16),
427        };
428
429        if fifo_size_words + self.allocated_fifo_words() > self.instance.fifo_depth_words {
430            error!("Not enough FIFO capacity");
431            return Err(EndpointAllocError);
432        }
433
434        let eps = match D::dir() {
435            Direction::Out => &mut self.ep_out[..self.instance.endpoint_count],
436            Direction::In => &mut self.ep_in[..self.instance.endpoint_count],
437        };
438
439        // Find endpoint slot
440        let slot = if let Some(addr) = ep_addr {
441            // Use the specified endpoint address
442            let requested_index = addr.index();
443            if requested_index >= self.instance.endpoint_count {
444                return Err(EndpointAllocError);
445            }
446            if requested_index == 0 && ep_type != EndpointType::Control {
447                return Err(EndpointAllocError); // EP0 is reserved for control
448            }
449            if eps[requested_index].is_some() {
450                return Err(EndpointAllocError); // Already allocated
451            }
452            Some((requested_index, &mut eps[requested_index]))
453        } else {
454            // Find any free endpoint slot
455            eps.iter_mut().enumerate().find(|(i, ep)| {
456                if *i == 0 && ep_type != EndpointType::Control {
457                    // reserved for control pipe
458                    false
459                } else {
460                    ep.is_none()
461                }
462            })
463        };
464
465        let index = match slot {
466            Some((index, ep)) => {
467                *ep = Some(EndpointData {
468                    ep_type,
469                    max_packet_size,
470                    fifo_size_words,
471                });
472                index
473            }
474            None => {
475                error!("No free endpoints available");
476                return Err(EndpointAllocError);
477            }
478        };
479
480        trace!("  index={}", index);
481
482        let state = &self.instance.state.ep_states[index];
483        if D::dir() == Direction::Out {
484            // Buffer capacity check was done above, now allocation cannot fail
485            unsafe {
486                *state.out_buffer.get() = self.ep_out_buffer.as_mut_ptr().offset(self.ep_out_buffer_offset as _);
487            }
488            self.ep_out_buffer_offset += max_packet_size as usize;
489        }
490
491        Ok(Endpoint {
492            _phantom: PhantomData,
493            regs: self.instance.regs,
494            state,
495            info: EndpointInfo {
496                addr: EndpointAddress::from_parts(index, D::dir()),
497                ep_type,
498                max_packet_size,
499                interval_ms,
500            },
501        })
502    }
503}
504
505impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Driver<'d> for Driver<'d, MAX_EP_COUNT> {
506    type EndpointOut = Endpoint<'d, Out>;
507    type EndpointIn = Endpoint<'d, In>;
508    type ControlPipe = ControlPipe<'d>;
509    type Bus = Bus<'d, MAX_EP_COUNT>;
510
511    fn alloc_endpoint_in(
512        &mut self,
513        ep_type: EndpointType,
514        ep_addr: Option<EndpointAddress>,
515        max_packet_size: u16,
516        interval_ms: u8,
517    ) -> Result<Self::EndpointIn, EndpointAllocError> {
518        self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
519    }
520
521    fn alloc_endpoint_out(
522        &mut self,
523        ep_type: EndpointType,
524        ep_addr: Option<EndpointAddress>,
525        max_packet_size: u16,
526        interval_ms: u8,
527    ) -> Result<Self::EndpointOut, EndpointAllocError> {
528        self.alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
529    }
530
531    fn start(mut self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
532        let ep_out = self
533            .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
534            .unwrap();
535        let ep_in = self
536            .alloc_endpoint(EndpointType::Control, None, control_max_packet_size, 0)
537            .unwrap();
538        assert_eq!(ep_out.info.addr.index(), 0);
539        assert_eq!(ep_in.info.addr.index(), 0);
540
541        trace!("start");
542
543        let regs = self.instance.regs;
544        let cp_setup_state = &self.instance.state.cp_state;
545        (
546            Bus {
547                config: self.config,
548                ep_in: self.ep_in,
549                ep_out: self.ep_out,
550                inited: false,
551                instance: self.instance,
552            },
553            ControlPipe {
554                max_packet_size: control_max_packet_size,
555                setup_state: cp_setup_state,
556                ep_out,
557                ep_in,
558                regs,
559            },
560        )
561    }
562}
563
564/// USB bus.
565pub struct Bus<'d, const MAX_EP_COUNT: usize> {
566    config: Config,
567    ep_in: [Option<EndpointData>; MAX_EP_COUNT],
568    ep_out: [Option<EndpointData>; MAX_EP_COUNT],
569    instance: OtgInstance<'d, MAX_EP_COUNT>,
570    inited: bool,
571}
572
573impl<'d, const MAX_EP_COUNT: usize> Bus<'d, MAX_EP_COUNT> {
574    fn restore_irqs(&mut self) {
575        self.instance.regs.gintmsk().write(|w| {
576            w.set_usbrst(true);
577            w.set_enumdnem(true);
578            w.set_usbsuspm(true);
579            w.set_wuim(true);
580            w.set_iepint(true);
581            w.set_oepint(true);
582            w.set_rxflvlm(true);
583            w.set_srqim(true);
584            w.set_otgint(true);
585        });
586    }
587
588    /// Returns the PHY type.
589    pub fn phy_type(&self) -> PhyType {
590        self.instance.phy_type
591    }
592
593    /// Configures the PHY as a device.
594    pub fn configure_as_device(&mut self) {
595        let r = self.instance.regs;
596        let phy_type = self.instance.phy_type;
597        r.gusbcfg().write(|w| {
598            // Force device mode
599            w.set_fdmod(true);
600            // Enable internal full-speed PHY
601            w.set_physel(phy_type.internal() && !phy_type.high_speed());
602        });
603    }
604
605    /// Applies configuration specific to
606    /// Core ID 0x0000_1100 and 0x0000_1200
607    pub fn config_v1(&mut self) {
608        let r = self.instance.regs;
609        let phy_type = self.instance.phy_type;
610        assert!(phy_type != PhyType::InternalHighSpeed);
611
612        r.gccfg_v1().modify(|w| {
613            // Enable internal full-speed PHY, logic is inverted
614            w.set_pwrdwn(phy_type.internal());
615        });
616
617        // F429-like chips have the GCCFG.NOVBUSSENS bit
618        r.gccfg_v1().modify(|w| {
619            w.set_novbussens(!self.config.vbus_detection);
620            w.set_vbusasen(false);
621            w.set_vbusbsen(self.config.vbus_detection);
622            w.set_sofouten(false);
623        });
624    }
625
626    /// Applies configuration specific to
627    /// Core ID 0x0000_2000, 0x0000_2100, 0x0000_2300, 0x0000_3000 and 0x0000_3100
628    pub fn config_v2v3(&mut self) {
629        let r = self.instance.regs;
630        let phy_type = self.instance.phy_type;
631
632        // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
633        r.gccfg_v2().modify(|w| {
634            // Enable internal full-speed PHY, logic is inverted
635            w.set_pwrdwn(phy_type.internal() && !phy_type.high_speed());
636            w.set_phyhsen(phy_type.internal() && phy_type.high_speed());
637        });
638
639        r.gccfg_v2().modify(|w| {
640            w.set_vbden(self.config.vbus_detection);
641        });
642
643        // Force B-peripheral session
644        r.gotgctl().modify(|w| {
645            w.set_bvaloen(!self.config.vbus_detection);
646            w.set_bvaloval(true);
647        });
648    }
649
650    /// Applies configuration specific to
651    /// Core ID 0x0000_5000
652    pub fn config_v5(&mut self) {
653        let r = self.instance.regs;
654        let phy_type = self.instance.phy_type;
655
656        if phy_type == PhyType::InternalHighSpeed {
657            r.gccfg_v3().modify(|w| {
658                w.set_vbvaloven(!self.config.vbus_detection);
659                w.set_vbvaloval(!self.config.vbus_detection);
660                w.set_vbden(self.config.vbus_detection);
661            });
662        } else {
663            r.gotgctl().modify(|w| {
664                w.set_bvaloen(!self.config.vbus_detection);
665                w.set_bvaloval(!self.config.vbus_detection);
666            });
667            r.gccfg_v3().modify(|w| {
668                w.set_vbden(self.config.vbus_detection);
669            });
670        }
671    }
672
673    fn init(&mut self) {
674        let r = self.instance.regs;
675        let phy_type = self.instance.phy_type;
676
677        // Soft disconnect.
678        r.dctl().write(|w| w.set_sdis(true));
679
680        // Set speed.
681        r.dcfg().write(|w| {
682            w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
683            w.set_dspd(phy_type.to_dspd());
684            if self.config.xcvrdly {
685                w.set_xcvrdly(true);
686            }
687        });
688
689        // Unmask transfer complete EP interrupt
690        r.diepmsk().write(|w| {
691            w.set_xfrcm(true);
692        });
693
694        // Unmask SETUP received EP interrupt
695        r.doepmsk().write(|w| {
696            w.set_stupm(true);
697        });
698
699        // Unmask and clear core interrupts
700        self.restore_irqs();
701        r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
702
703        // Unmask global interrupt
704        r.gahbcfg().write(|w| {
705            w.set_gint(true); // unmask global interrupt
706        });
707
708        // Connect
709        r.dctl().write(|w| w.set_sdis(false));
710    }
711
712    fn init_fifo(&mut self) {
713        trace!("init_fifo");
714
715        let regs = self.instance.regs;
716        // ERRATA NOTE: Don't interrupt FIFOs being written to. The interrupt
717        // handler COULD interrupt us here and do FIFO operations, so ensure
718        // the interrupt does not occur.
719        critical_section::with(|_| {
720            // Configure RX fifo size. All endpoints share the same FIFO area.
721            let rx_fifo_size_words = self.instance.extra_rx_fifo_words + ep_fifo_size(&self.ep_out);
722            trace!("configuring rx fifo size={}", rx_fifo_size_words);
723
724            regs.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
725
726            // Configure TX (USB in direction) fifo size for each endpoint
727            let mut fifo_top = rx_fifo_size_words;
728            for i in 0..self.instance.endpoint_count {
729                if let Some(ep) = self.ep_in[i] {
730                    trace!(
731                        "configuring tx fifo ep={}, offset={}, size={}",
732                        i, fifo_top, ep.fifo_size_words
733                    );
734
735                    let dieptxf = if i == 0 { regs.dieptxf0() } else { regs.dieptxf(i - 1) };
736
737                    dieptxf.write(|w| {
738                        w.set_fd(ep.fifo_size_words);
739                        w.set_sa(fifo_top);
740                    });
741
742                    fifo_top += ep.fifo_size_words;
743                }
744            }
745
746            assert!(
747                fifo_top <= self.instance.fifo_depth_words,
748                "FIFO allocations exceeded maximum capacity"
749            );
750
751            // Flush fifos
752            regs.grstctl().write(|w| {
753                w.set_rxfflsh(true);
754                w.set_txfflsh(true);
755                w.set_txfnum(0x10);
756            });
757        });
758
759        loop {
760            let x = regs.grstctl().read();
761            if !x.rxfflsh() && !x.txfflsh() {
762                break;
763            }
764        }
765    }
766
767    fn configure_endpoints(&mut self) {
768        trace!("configure_endpoints");
769
770        let regs = self.instance.regs;
771
772        // Configure IN endpoints
773        for (index, ep) in self.ep_in.iter().enumerate() {
774            if let Some(ep) = ep {
775                critical_section::with(|_| {
776                    regs.diepctl(index).write(|w| {
777                        if index == 0 {
778                            w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
779                        } else {
780                            w.set_mpsiz(ep.max_packet_size);
781                            w.set_eptyp(to_eptyp(ep.ep_type));
782                            w.set_sd0pid_sevnfrm(true);
783                            w.set_txfnum(index as _);
784                            w.set_snak(true);
785                        }
786                    });
787                });
788            }
789        }
790
791        // Configure OUT endpoints
792        for (index, ep) in self.ep_out.iter().enumerate() {
793            if let Some(ep) = ep {
794                critical_section::with(|_| {
795                    regs.doepctl(index).write(|w| {
796                        if index == 0 {
797                            w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
798                        } else {
799                            w.set_mpsiz(ep.max_packet_size);
800                            w.set_eptyp(to_eptyp(ep.ep_type));
801                            w.set_sd0pid_sevnfrm(true);
802                        }
803                    });
804
805                    regs.doeptsiz(index).modify(|w| {
806                        w.set_xfrsiz(ep.max_packet_size as _);
807                        if index == 0 {
808                            w.set_rxdpid_stupcnt(3);
809                        } else {
810                            w.set_pktcnt(1);
811                        }
812                    });
813                });
814            }
815        }
816
817        // Enable IRQs for allocated endpoints
818        regs.daintmsk().modify(|w| {
819            w.set_iepm(ep_irq_mask(&self.ep_in));
820            w.set_oepm(ep_irq_mask(&self.ep_out));
821        });
822    }
823
824    fn disable_all_endpoints(&mut self) {
825        for i in 0..self.instance.endpoint_count {
826            self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false);
827            self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false);
828        }
829    }
830}
831
832impl<'d, const MAX_EP_COUNT: usize> embassy_usb_driver::Bus for Bus<'d, MAX_EP_COUNT> {
833    async fn poll(&mut self) -> Event {
834        poll_fn(move |cx| {
835            if !self.inited {
836                self.init();
837                self.inited = true;
838
839                // If no vbus detection, just return a single PowerDetected event at startup.
840                if !self.config.vbus_detection {
841                    return Poll::Ready(Event::PowerDetected);
842                }
843            }
844
845            let regs = self.instance.regs;
846            self.instance.state.bus_waker.register(cx.waker());
847
848            let ints = regs.gintsts().read();
849
850            if ints.srqint() {
851                trace!("vbus detected");
852
853                regs.gintsts().write(|w| w.set_srqint(true)); // clear
854                self.restore_irqs();
855
856                if self.config.vbus_detection {
857                    return Poll::Ready(Event::PowerDetected);
858                }
859            }
860
861            if ints.otgint() {
862                let otgints = regs.gotgint().read();
863                regs.gotgint().write_value(otgints); // clear all
864                self.restore_irqs();
865
866                if otgints.sedet() {
867                    trace!("vbus removed");
868                    if self.config.vbus_detection {
869                        self.disable_all_endpoints();
870                        return Poll::Ready(Event::PowerRemoved);
871                    }
872                }
873            }
874
875            if ints.usbrst() {
876                trace!("reset");
877
878                self.init_fifo();
879                self.configure_endpoints();
880
881                // Reset address
882                critical_section::with(|_| {
883                    regs.dcfg().modify(|w| {
884                        w.set_dad(0);
885                    });
886                });
887
888                regs.gintsts().write(|w| w.set_usbrst(true)); // clear
889                self.restore_irqs();
890            }
891
892            if ints.enumdne() {
893                trace!("enumdne");
894
895                let speed = regs.dsts().read().enumspd();
896                let trdt = (self.instance.calculate_trdt_fn)(speed);
897                trace!("  speed={} trdt={}", speed.to_bits(), trdt);
898                regs.gusbcfg().modify(|w| w.set_trdt(trdt));
899
900                regs.gintsts().write(|w| w.set_enumdne(true)); // clear
901                self.restore_irqs();
902
903                return Poll::Ready(Event::Reset);
904            }
905
906            if ints.usbsusp() {
907                trace!("suspend");
908                regs.gintsts().write(|w| w.set_usbsusp(true)); // clear
909                self.restore_irqs();
910                return Poll::Ready(Event::Suspend);
911            }
912
913            if ints.wkupint() {
914                trace!("resume");
915                regs.gintsts().write(|w| w.set_wkupint(true)); // clear
916                self.restore_irqs();
917                return Poll::Ready(Event::Resume);
918            }
919
920            Poll::Pending
921        })
922        .await
923    }
924
925    fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
926        trace!("endpoint_set_stalled ep={:?} en={}", ep_addr, stalled);
927
928        assert!(
929            ep_addr.index() < self.instance.endpoint_count,
930            "endpoint_set_stalled index {} out of range",
931            ep_addr.index()
932        );
933
934        let regs = self.instance.regs;
935        let state = self.instance.state;
936        match ep_addr.direction() {
937            Direction::Out => {
938                critical_section::with(|_| {
939                    regs.doepctl(ep_addr.index()).modify(|w| {
940                        w.set_stall(stalled);
941                    });
942                });
943
944                state.ep_states[ep_addr.index()].out_waker.wake();
945            }
946            Direction::In => {
947                critical_section::with(|_| {
948                    regs.diepctl(ep_addr.index()).modify(|w| {
949                        w.set_stall(stalled);
950                    });
951                });
952
953                state.ep_states[ep_addr.index()].in_waker.wake();
954            }
955        }
956    }
957
958    fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
959        assert!(
960            ep_addr.index() < self.instance.endpoint_count,
961            "endpoint_is_stalled index {} out of range",
962            ep_addr.index()
963        );
964
965        let regs = self.instance.regs;
966        match ep_addr.direction() {
967            Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
968            Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
969        }
970    }
971
972    fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
973        trace!("endpoint_set_enabled ep={:?} en={}", ep_addr, enabled);
974
975        assert!(
976            ep_addr.index() < self.instance.endpoint_count,
977            "endpoint_set_enabled index {} out of range",
978            ep_addr.index()
979        );
980
981        let regs = self.instance.regs;
982        let state = self.instance.state;
983        match ep_addr.direction() {
984            Direction::Out => {
985                critical_section::with(|_| {
986                    // cancel transfer if active
987                    if !enabled && regs.doepctl(ep_addr.index()).read().epena() {
988                        regs.doepctl(ep_addr.index()).modify(|w| {
989                            w.set_snak(true);
990                            w.set_epdis(true);
991                        })
992                    }
993
994                    regs.doepctl(ep_addr.index()).modify(|w| {
995                        w.set_usbaep(enabled);
996                    });
997                });
998
999                // Wake `Endpoint::wait_enabled()`
1000                state.ep_states[ep_addr.index()].out_waker.wake();
1001            }
1002            Direction::In => {
1003                critical_section::with(|_| {
1004                    // cancel transfer if active
1005                    if !enabled && regs.diepctl(ep_addr.index()).read().epena() {
1006                        regs.diepctl(ep_addr.index()).modify(|w| {
1007                            w.set_snak(true); // set NAK
1008                            w.set_epdis(true);
1009                        })
1010                    }
1011
1012                    regs.diepctl(ep_addr.index()).modify(|w| {
1013                        w.set_usbaep(enabled);
1014                        w.set_cnak(enabled); // clear NAK that might've been set by SNAK above.
1015                    });
1016
1017                    // Flush tx fifo
1018                    regs.grstctl().write(|w| {
1019                        w.set_txfflsh(true);
1020                        w.set_txfnum(ep_addr.index() as _);
1021                    });
1022                    loop {
1023                        let x = regs.grstctl().read();
1024                        if !x.txfflsh() {
1025                            break;
1026                        }
1027                    }
1028                });
1029
1030                // Wake `Endpoint::wait_enabled()`
1031                state.ep_states[ep_addr.index()].in_waker.wake();
1032            }
1033        }
1034    }
1035
1036    async fn enable(&mut self) {
1037        trace!("enable");
1038        // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
1039    }
1040
1041    async fn disable(&mut self) {
1042        trace!("disable");
1043
1044        // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
1045        //Bus::disable(self);
1046    }
1047
1048    async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
1049        Err(Unsupported)
1050    }
1051}
1052
1053/// USB endpoint direction.
1054trait Dir {
1055    /// Returns the direction value.
1056    fn dir() -> Direction;
1057}
1058
1059/// Marker type for the "IN" direction.
1060pub enum In {}
1061impl Dir for In {
1062    fn dir() -> Direction {
1063        Direction::In
1064    }
1065}
1066
1067/// Marker type for the "OUT" direction.
1068pub enum Out {}
1069impl Dir for Out {
1070    fn dir() -> Direction {
1071        Direction::Out
1072    }
1073}
1074
1075/// USB endpoint.
1076pub struct Endpoint<'d, D> {
1077    _phantom: PhantomData<D>,
1078    regs: Otg,
1079    info: EndpointInfo,
1080    state: &'d EpState,
1081}
1082
1083impl<'d> embassy_usb_driver::Endpoint for Endpoint<'d, In> {
1084    fn info(&self) -> &EndpointInfo {
1085        &self.info
1086    }
1087
1088    async fn wait_enabled(&mut self) {
1089        poll_fn(|cx| {
1090            let ep_index = self.info.addr.index();
1091
1092            self.state.in_waker.register(cx.waker());
1093
1094            if self.regs.diepctl(ep_index).read().usbaep() {
1095                Poll::Ready(())
1096            } else {
1097                Poll::Pending
1098            }
1099        })
1100        .await
1101    }
1102}
1103
1104impl<'d> embassy_usb_driver::Endpoint for Endpoint<'d, Out> {
1105    fn info(&self) -> &EndpointInfo {
1106        &self.info
1107    }
1108
1109    async fn wait_enabled(&mut self) {
1110        poll_fn(|cx| {
1111            let ep_index = self.info.addr.index();
1112
1113            self.state.out_waker.register(cx.waker());
1114
1115            if self.regs.doepctl(ep_index).read().usbaep() {
1116                Poll::Ready(())
1117            } else {
1118                Poll::Pending
1119            }
1120        })
1121        .await
1122    }
1123}
1124
1125impl<'d> embassy_usb_driver::EndpointOut for Endpoint<'d, Out> {
1126    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
1127        trace!("read start len={}", buf.len());
1128
1129        poll_fn(|cx| {
1130            let index = self.info.addr.index();
1131            self.state.out_waker.register(cx.waker());
1132
1133            let doepctl = self.regs.doepctl(index).read();
1134            trace!("read ep={:?}: doepctl {:08x}", self.info.addr, doepctl.0,);
1135            if !doepctl.usbaep() {
1136                trace!("read ep={:?} error disabled", self.info.addr);
1137                return Poll::Ready(Err(EndpointError::Disabled));
1138            }
1139
1140            let len = self.state.out_size.load(Ordering::Relaxed);
1141            if len != EP_OUT_BUFFER_EMPTY {
1142                trace!("read ep={:?} done len={}", self.info.addr, len);
1143
1144                if len as usize > buf.len() {
1145                    return Poll::Ready(Err(EndpointError::BufferOverflow));
1146                }
1147
1148                // SAFETY: exclusive access ensured by `out_size` atomic variable
1149                let data = unsafe { core::slice::from_raw_parts(*self.state.out_buffer.get(), len as usize) };
1150                buf[..len as usize].copy_from_slice(data);
1151
1152                // Release buffer
1153                self.state.out_size.store(EP_OUT_BUFFER_EMPTY, Ordering::Release);
1154
1155                critical_section::with(|_| {
1156                    // Receive 1 packet
1157                    self.regs.doeptsiz(index).modify(|w| {
1158                        w.set_xfrsiz(self.info.max_packet_size as _);
1159                        w.set_pktcnt(1);
1160                    });
1161
1162                    if self.info.ep_type == EndpointType::Isochronous {
1163                        // Isochronous endpoints must set the correct even/odd frame bit to
1164                        // correspond with the next frame's number.
1165                        let frame_number = self.regs.dsts().read().fnsof();
1166                        let frame_is_odd = frame_number & 0x01 == 1;
1167
1168                        self.regs.doepctl(index).modify(|r| {
1169                            if frame_is_odd {
1170                                r.set_sd0pid_sevnfrm(true);
1171                            } else {
1172                                r.set_sd1pid_soddfrm(true);
1173                            }
1174                        });
1175                    }
1176
1177                    // Clear NAK to indicate we are ready to receive more data
1178                    self.regs.doepctl(index).modify(|w| {
1179                        w.set_cnak(true);
1180                    });
1181                });
1182
1183                Poll::Ready(Ok(len as usize))
1184            } else {
1185                Poll::Pending
1186            }
1187        })
1188        .await
1189    }
1190}
1191
1192impl<'d> embassy_usb_driver::EndpointIn for Endpoint<'d, In> {
1193    async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
1194        trace!("write ep={:?} data={:?}", self.info.addr, Bytes(buf));
1195
1196        if buf.len() > self.info.max_packet_size as usize {
1197            return Err(EndpointError::BufferOverflow);
1198        }
1199
1200        let index = self.info.addr.index();
1201        // Wait for previous transfer to complete and check if endpoint is disabled
1202        poll_fn(|cx| {
1203            self.state.in_waker.register(cx.waker());
1204
1205            let diepctl = self.regs.diepctl(index).read();
1206            let dtxfsts = self.regs.dtxfsts(index).read();
1207            trace!(
1208                "write ep={:?}: diepctl {:08x} ftxfsts {:08x}",
1209                self.info.addr, diepctl.0, dtxfsts.0
1210            );
1211            if !diepctl.usbaep() {
1212                trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
1213                Poll::Ready(Err(EndpointError::Disabled))
1214            } else if !diepctl.epena() {
1215                trace!("write ep={:?} wait for prev: ready", self.info.addr);
1216                Poll::Ready(Ok(()))
1217            } else {
1218                trace!("write ep={:?} wait for prev: pending", self.info.addr);
1219                Poll::Pending
1220            }
1221        })
1222        .await?;
1223
1224        if buf.len() > 0 {
1225            poll_fn(|cx| {
1226                self.state.in_waker.register(cx.waker());
1227
1228                let size_words = (buf.len() + 3) / 4;
1229
1230                let fifo_space = self.regs.dtxfsts(index).read().ineptfsav() as usize;
1231                if size_words > fifo_space {
1232                    // Not enough space in fifo, enable tx fifo empty interrupt
1233                    critical_section::with(|_| {
1234                        self.regs.diepempmsk().modify(|w| {
1235                            w.set_ineptxfem(w.ineptxfem() | (1 << index));
1236                        });
1237                    });
1238
1239                    trace!("tx fifo for ep={} full, waiting for txfe", index);
1240
1241                    Poll::Pending
1242                } else {
1243                    trace!("write ep={:?} wait for fifo: ready", self.info.addr);
1244                    Poll::Ready(())
1245                }
1246            })
1247            .await
1248        }
1249
1250        // ERRATA: Transmit data FIFO is corrupted when a write sequence to the FIFO is interrupted with
1251        // accesses to certain OTG_FS registers.
1252        //
1253        // Prevent the interrupt (which might poke FIFOs) from executing while copying data to FIFOs.
1254        critical_section::with(|_| {
1255            // Setup transfer size
1256            self.regs.dieptsiz(index).write(|w| {
1257                w.set_mcnt(1);
1258                w.set_pktcnt(1);
1259                w.set_xfrsiz(buf.len() as _);
1260            });
1261
1262            if self.info.ep_type == EndpointType::Isochronous {
1263                // Isochronous endpoints must set the correct even/odd frame bit to
1264                // correspond with the next frame's number.
1265                let frame_number = self.regs.dsts().read().fnsof();
1266                let frame_is_odd = frame_number & 0x01 == 1;
1267
1268                self.regs.diepctl(index).modify(|r| {
1269                    if frame_is_odd {
1270                        r.set_sd0pid_sevnfrm(true);
1271                    } else {
1272                        r.set_sd1pid_soddfrm(true);
1273                    }
1274                });
1275            }
1276
1277            // Enable endpoint
1278            self.regs.diepctl(index).modify(|w| {
1279                w.set_cnak(true);
1280                w.set_epena(true);
1281            });
1282
1283            // Write data to FIFO
1284            let fifo = self.regs.fifo(index);
1285            let mut chunks = buf.chunks_exact(4);
1286            for chunk in &mut chunks {
1287                let val = u32::from_ne_bytes(chunk.try_into().unwrap());
1288                fifo.write_value(regs::Fifo(val));
1289            }
1290            // Write any last chunk
1291            let rem = chunks.remainder();
1292            if !rem.is_empty() {
1293                let mut tmp = [0u8; 4];
1294                tmp[0..rem.len()].copy_from_slice(rem);
1295                let tmp = u32::from_ne_bytes(tmp);
1296                fifo.write_value(regs::Fifo(tmp));
1297            }
1298        });
1299
1300        trace!("write done ep={:?}", self.info.addr);
1301
1302        Ok(())
1303    }
1304}
1305
1306/// USB control pipe.
1307pub struct ControlPipe<'d> {
1308    max_packet_size: u16,
1309    regs: Otg,
1310    setup_state: &'d ControlPipeSetupState,
1311    ep_in: Endpoint<'d, In>,
1312    ep_out: Endpoint<'d, Out>,
1313}
1314
1315impl<'d> embassy_usb_driver::ControlPipe for ControlPipe<'d> {
1316    fn max_packet_size(&self) -> usize {
1317        usize::from(self.max_packet_size)
1318    }
1319
1320    async fn setup(&mut self) -> [u8; 8] {
1321        poll_fn(|cx| {
1322            self.ep_out.state.out_waker.register(cx.waker());
1323
1324            if self.setup_state.setup_ready.load(Ordering::Relaxed) {
1325                let mut data = [0; 8];
1326                data[0..4].copy_from_slice(&self.setup_state.setup_data[0].load(Ordering::Relaxed).to_ne_bytes());
1327                data[4..8].copy_from_slice(&self.setup_state.setup_data[1].load(Ordering::Relaxed).to_ne_bytes());
1328                self.setup_state.setup_ready.store(false, Ordering::Release);
1329
1330                // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1331                self.regs.doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
1332                    w.set_rxdpid_stupcnt(3);
1333                });
1334
1335                // Clear NAK to indicate we are ready to receive more data
1336                self.regs
1337                    .doepctl(self.ep_out.info.addr.index())
1338                    .modify(|w| w.set_cnak(true));
1339
1340                trace!("SETUP received: {:?}", Bytes(&data));
1341                Poll::Ready(data)
1342            } else {
1343                trace!("SETUP waiting");
1344                Poll::Pending
1345            }
1346        })
1347        .await
1348    }
1349
1350    async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> {
1351        trace!("control: data_out");
1352        let len = self.ep_out.read(buf).await?;
1353        trace!("control: data_out read: {:?}", Bytes(&buf[..len]));
1354        Ok(len)
1355    }
1356
1357    async fn data_in(&mut self, data: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> {
1358        trace!("control: data_in write: {:?}", Bytes(data));
1359        self.ep_in.write(data).await?;
1360
1361        // wait for status response from host after sending the last packet
1362        if last {
1363            trace!("control: data_in waiting for status");
1364            self.ep_out.read(&mut []).await?;
1365            trace!("control: complete");
1366        }
1367
1368        Ok(())
1369    }
1370
1371    async fn accept(&mut self) {
1372        trace!("control: accept");
1373
1374        self.ep_in.write(&[]).await.ok();
1375
1376        trace!("control: accept OK");
1377    }
1378
1379    async fn reject(&mut self) {
1380        trace!("control: reject");
1381
1382        // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
1383        self.regs.diepctl(self.ep_in.info.addr.index()).modify(|w| {
1384            w.set_stall(true);
1385        });
1386        self.regs.doepctl(self.ep_out.info.addr.index()).modify(|w| {
1387            w.set_stall(true);
1388        });
1389    }
1390
1391    async fn accept_set_address(&mut self, addr: u8) {
1392        trace!("setting addr: {}", addr);
1393        critical_section::with(|_| {
1394            self.regs.dcfg().modify(|w| {
1395                w.set_dad(addr);
1396            });
1397        });
1398
1399        // synopsys driver requires accept to be sent after changing address
1400        self.accept().await
1401    }
1402}
1403
1404/// Translates HAL [EndpointType] into PAC [vals::Eptyp]
1405fn to_eptyp(ep_type: EndpointType) -> vals::Eptyp {
1406    match ep_type {
1407        EndpointType::Control => vals::Eptyp::CONTROL,
1408        EndpointType::Isochronous => vals::Eptyp::ISOCHRONOUS,
1409        EndpointType::Bulk => vals::Eptyp::BULK,
1410        EndpointType::Interrupt => vals::Eptyp::INTERRUPT,
1411    }
1412}
1413
1414/// Calculates total allocated FIFO size in words
1415fn ep_fifo_size(eps: &[Option<EndpointData>]) -> u16 {
1416    eps.iter().map(|ep| ep.map(|ep| ep.fifo_size_words).unwrap_or(0)).sum()
1417}
1418
1419/// Generates IRQ mask for enabled endpoints
1420fn ep_irq_mask(eps: &[Option<EndpointData>]) -> u16 {
1421    eps.iter().enumerate().fold(
1422        0,
1423        |mask, (index, ep)| {
1424            if ep.is_some() { mask | (1 << index) } else { mask }
1425        },
1426    )
1427}
1428
1429/// Calculates MPSIZ value for EP0, which uses special values.
1430fn ep0_mpsiz(max_packet_size: u16) -> u16 {
1431    match max_packet_size {
1432        8 => 0b11,
1433        16 => 0b10,
1434        32 => 0b01,
1435        64 => 0b00,
1436        other => panic!("Unsupported EP0 size: {}", other),
1437    }
1438}
1439
1440/// Hardware-dependent USB IP configuration.
1441pub struct OtgInstance<'d, const MAX_EP_COUNT: usize> {
1442    /// The USB peripheral.
1443    pub regs: Otg,
1444    /// The USB state.
1445    pub state: &'d State<MAX_EP_COUNT>,
1446    /// FIFO depth in words.
1447    pub fifo_depth_words: u16,
1448    /// Number of used endpoints.
1449    pub endpoint_count: usize,
1450    /// The PHY type.
1451    pub phy_type: PhyType,
1452    /// Extra RX FIFO words needed by some implementations.
1453    pub extra_rx_fifo_words: u16,
1454    /// Function to calculate TRDT value based on some internal clock speed.
1455    pub calculate_trdt_fn: fn(speed: vals::Dspd) -> u8,
1456}