1use core::{
4 marker::PhantomData,
5 sync::atomic::{AtomicBool, AtomicU8, AtomicU32, Ordering},
6};
7
8use embassy_hal_internal::{Peri, PeripheralType, interrupt::InterruptExt};
9use embassy_sync::waitqueue::AtomicWaker;
10use embassy_usb_driver::{
11 Direction, Driver, EndpointAddress, EndpointAllocError, EndpointInfo, EndpointType,
12};
13
14use crate::{
15 event_link::{IcuInterrupt, InterruptEvent},
16 gpio::{Pin, PortFunction},
17 interrupt::typelevel::{Binding, Handler as InterruptHandler, Interrupt as InterruptType},
18 module_stop::ModuleStop,
19 pac::{
20 self,
21 usbfs::vals::{Dvsq, Pipesel, Type},
22 },
23 peripherals::USBFS,
24 usb::{
25 bus::{Bus, BusEvent},
26 control_pipe::ControlPipe,
27 endpoint::{EndpointIn, EndpointOut},
28 },
29};
30
31pub mod bus;
32pub mod control_pipe;
33pub mod endpoint;
34
35#[derive(Clone, Copy)]
36struct PipeConfig {
37 ep_addr: EndpointAddress,
38 ep_type: EndpointType,
39 max_packet: u16,
40 interval_ms: u8,
41}
42struct State {
43 bus_waker: AtomicWaker,
45 ep_wakers: [AtomicWaker; 10],
47 pending_bus: AtomicU32,
49 pipe_brdy: AtomicU32,
51 pipe_bemp: AtomicU32,
53 setup_ready: AtomicBool,
55 setup_lo: AtomicU32,
57 setup_hi: AtomicU32,
58 pipe_enabled: AtomicU32,
60}
61
62pub struct UsbInterruptHandler<I: Instance> {
64 _phantom: PhantomData<I>,
65}
66
67pub struct Usbfs<'a, I: Instance> {
69 _phantom: PhantomData<&'a I>,
70 pipes: [Option<PipeConfig>; 9],
71 next_ep_in: u8,
72 next_ep_out: u8,
73}
74
75impl State {
76 const fn new() -> Self {
77 Self {
78 bus_waker: AtomicWaker::new(),
79 ep_wakers: [const { AtomicWaker::new() }; 10],
80 pending_bus: AtomicU32::new(0),
81 pipe_brdy: AtomicU32::new(0),
82 pipe_bemp: AtomicU32::new(0),
83 setup_ready: AtomicBool::new(false),
84 setup_lo: AtomicU32::new(0),
85 setup_hi: AtomicU32::new(0),
86 pipe_enabled: AtomicU32::new(0),
87 }
88 }
89}
90
91static STATE: State = State::new();
92
93static EP_ADDR: [AtomicU8; 9] = [const { AtomicU8::new(0xFF) }; 9];
96
97#[allow(private_bounds)]
99pub trait Instance: SealedInstance + ModuleStop + PeripheralType + 'static + Send {}
100
101pub(crate) trait SealedInstance {
102 fn regs() -> pac::usbfs::Usbfs;
103}
104
105pub(crate) trait SealedDpPin<I: SealedInstance>: Pin + PeripheralType {
106 #[inline(always)]
109 fn set_pfunc(&self) {
110 }
120}
121
122#[allow(private_bounds)]
124pub trait DpPin<I: Instance>: SealedDpPin<I> {}
125
126#[allow(unused)]
127macro_rules! dp_pin {
128 ($instance:ident, $pin:ident, $pfunc:ident) => {
129 impl crate::usb::DpPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
130 impl crate::usb::SealedDpPin<crate::peripherals::$instance> for crate::peripherals::$pin {
131 }
133 };
134}
135
136#[cfg(not(ra6m5))]
137pub(crate) use dp_pin;
138
139pub(crate) trait SealedDmPin<I: SealedInstance>: Pin + PeripheralType {
140 #[inline(always)]
143 fn set_pfunc(&self) {
144 }
154}
155
156#[allow(private_bounds)]
158pub trait DmPin<I: Instance>: SealedDmPin<I> {}
159
160#[allow(unused)]
161macro_rules! dm_pin {
162 ($instance:ident, $pin:ident, $pfunc:ident) => {
163 impl crate::usb::DmPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
164 impl crate::usb::SealedDmPin<crate::peripherals::$instance> for crate::peripherals::$pin {
165 }
167 };
168}
169
170#[cfg(not(ra6m5))]
171pub(crate) use dm_pin;
172
173pub(crate) trait SealedVbusPin<I: SealedInstance>: Pin + PeripheralType {
174 const PERIPHERAL_FUNC: PortFunction;
175
176 #[inline(always)]
177 fn set_pfunc(&self) {
178 self.set_as_pf(Self::PERIPHERAL_FUNC);
179 }
180}
181
182#[allow(private_bounds)]
184pub trait VbusPin<I: Instance>: SealedVbusPin<I> {}
185
186macro_rules! vbus_pin {
187 ($instance:ident, $pin:ident, $pfunc:ident) => {
188 impl crate::usb::VbusPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
189 impl crate::usb::SealedVbusPin<crate::peripherals::$instance> for crate::peripherals::$pin {
190 const PERIPHERAL_FUNC: crate::gpio::PortFunction = crate::gpio::PortFunction::$pfunc;
191 }
192 };
193}
194
195pub(crate) use vbus_pin;
196
197impl SealedInstance for USBFS {
198 fn regs() -> pac::usbfs::Usbfs {
199 pac::USBFS
200 }
201}
202
203impl Instance for USBFS {}
204
205impl<I: Instance, Int: InterruptType> InterruptHandler<Int> for UsbInterruptHandler<I> {
206 unsafe fn on_interrupt() {
207 let r = I::regs();
208 Int::IRQ.icu_unpend();
209
210 let sts = r.intsts0().read();
211 trace!(
212 "USBFS IRQ: vbint={} dvst={} resm={} ctrt={} valid={} brdy={} bemp={}",
213 sts.vbint(),
214 sts.dvst(),
215 sts.resm(),
216 sts.ctrt(),
217 sts.valid(),
218 sts.brdy(),
219 sts.bemp(),
220 );
221
222 if sts.vbint() {
224 r.intsts0().modify(|r| r.set_vbint(false));
225 if sts.vbsts() {
226 debug!("USBFS IRQ: VBUS detected");
227 STATE
228 .pending_bus
229 .fetch_or(BusEvent::PowerDetected as _, Ordering::Release);
230 } else {
231 debug!("USBFS IRQ: VBUS removed");
232 STATE
233 .pending_bus
234 .fetch_or(BusEvent::PowerRemoved as _, Ordering::Release);
235 }
236 STATE.bus_waker.wake();
237 }
238
239 if sts.dvst() {
241 r.intsts0().modify(|r| r.set_dvst(false));
242 match sts.dvsq() {
243 Dvsq::Default => {
244 debug!("USBFS IRQ: bus reset (DVSQ=Default)");
245 STATE
246 .pending_bus
247 .fetch_or(BusEvent::Reset as _, Ordering::Release);
248 STATE.bus_waker.wake();
249 }
250 Dvsq::Suspend4 | Dvsq::Suspend5 | Dvsq::Suspend6 | Dvsq::Suspend7 => {
251 debug!("USBFS IRQ: suspend (DVSQ={:04b})", sts.dvsq().to_bits());
252 STATE
253 .pending_bus
254 .fetch_or(BusEvent::Suspend as _, Ordering::Release);
255 STATE.bus_waker.wake();
256 }
257 other => {
258 trace!("USBFS IRQ: DVST dvsq={:04b}", other.to_bits());
259 }
260 }
261 }
262
263 if sts.resm() {
265 r.intsts0().modify(|r| r.set_resm(false));
266 debug!("USBFS IRQ: resume");
267 STATE
268 .pending_bus
269 .fetch_or(BusEvent::Resume as _, Ordering::Release);
270 STATE.bus_waker.wake();
271 }
272
273 if sts.ctrt() {
275 r.intsts0().modify(|r| r.set_ctrt(false));
276 if sts.valid() {
277 let req = r.usbreq().read();
279 let val = r.usbval().read();
280 let idx = r.usbindx().read();
281 let len = r.usbleng().read();
282
283 let lo = u32::from(req.bmrequesttype())
284 | (u32::from(req.brequest()) << 8)
285 | ((val.wvalue() as u32) << 16);
286 let hi = idx.windex() as u32 | ((len.wlentuh() as u32) << 16);
287
288 debug!(
289 "USBFS IRQ: SETUP bmrt={:08b} req={:#04x} val={:#06x} idx={:#06x} len={}",
290 req.bmrequesttype(),
291 req.brequest(),
292 val.wvalue(),
293 idx.windex(),
294 len.wlentuh(),
295 );
296
297 STATE.setup_lo.store(lo, Ordering::Relaxed);
298 STATE.setup_hi.store(hi, Ordering::Relaxed);
299 STATE.setup_ready.store(true, Ordering::Release);
300 r.intsts0().modify(|r| r.set_valid(false));
302 STATE.ep_wakers[0].wake();
303 } else {
304 trace!("USBFS IRQ: CTRT without VALID (status stage)");
305 }
306 }
307
308 if sts.brdy() {
310 let brdy = r.brdysts().read();
311 let mut mask = 0u32;
312 for i in 0..10usize {
313 if brdy.brdy(i) {
314 r.brdysts().modify(|r| r.set_brdy(i, false));
316 mask |= 1 << i;
317 }
318 }
319 trace!("USBFS IRQ: BRDY pipes={:010b}", mask);
320 STATE.pipe_brdy.fetch_or(mask, Ordering::Release);
321 for i in 0..10usize {
322 if mask & (1 << i) != 0 {
323 STATE.ep_wakers[i].wake();
324 }
325 }
326 }
327
328 if sts.bemp() {
330 let bemp = r.bempsts().read();
331 let mut mask = 0u32;
332 for i in 0..10usize {
333 if bemp.bemp(i) {
334 r.bempsts().modify(|r| r.set_bemp(i, false));
335 mask |= 1 << i;
336 }
337 }
338 trace!("USBFS IRQ: BEMP pipes={:010b}", mask);
339 STATE.pipe_bemp.fetch_or(mask, Ordering::Release);
340 for i in 0..10usize {
341 if mask & (1 << i) != 0 {
342 STATE.ep_wakers[i].wake();
343 }
344 }
345 }
346 }
347}
348
349impl<'a, I: Instance> Usbfs<'a, I> {
351 pub fn new<
353 Int: InterruptType,
354 #[cfg(not(ra6m5))] P: DpPin<I>,
355 #[cfg(not(ra6m5))] M: DmPin<I>,
356 V: VbusPin<I>,
357 >(
358 _usb: Peri<'a, I>,
359 #[cfg(not(ra6m5))] dp: Peri<'a, P>,
360 #[cfg(not(ra6m5))] dm: Peri<'a, M>,
361 vbus: Peri<'a, V>,
362 irqs: impl Binding<Int, UsbInterruptHandler<I>> + 'a,
363 ) -> Self {
364 let _ = irqs;
365
366 I::start_module();
368
369 #[cfg(not(ra6m5))]
370 {
371 dp.set_pfunc();
372 dm.set_pfunc();
373 }
374 vbus.set_pfunc();
375
376 unsafe {
378 Int::IRQ.enable();
379 Int::IRQ.icu_enable(InterruptEvent::UsbfsInt);
380 }
381
382 info!("USBFS: driver created, interrupt enabled");
383
384 Self {
385 _phantom: PhantomData,
386 pipes: [None; 9],
387 next_ep_in: 1,
388 next_ep_out: 1,
389 }
390 }
391}
392
393impl<'a, I: Instance> Driver<'a> for Usbfs<'a, I> {
394 type EndpointOut = EndpointOut<'a, I>;
395 type EndpointIn = EndpointIn<'a, I>;
396 type ControlPipe = ControlPipe<'a, I>;
397 type Bus = Bus<'a, I>;
398
399 fn alloc_endpoint_out(
400 &mut self,
401 ep_type: EndpointType,
402 ep_addr: Option<EndpointAddress>,
403 max_packet_size: u16,
404 interval_ms: u8,
405 ) -> Result<Self::EndpointOut, EndpointAllocError> {
406 let pipe = find_free_pipe(&self.pipes, ep_type).ok_or(EndpointAllocError)?;
407
408 let ep_num = if let Some(addr) = ep_addr {
409 if addr.is_in() {
410 return Err(EndpointAllocError);
411 }
412 addr.index() as u8
413 } else {
414 let n = self.next_ep_out;
415 self.next_ep_out += 1;
416 n
417 };
418
419 let addr = EndpointAddress::from_parts(ep_num as usize, Direction::Out);
420 self.pipes[pipe - 1] = Some(PipeConfig {
421 ep_addr: addr,
422 ep_type,
423 max_packet: max_packet_size,
424 interval_ms,
425 });
426
427 Ok(EndpointOut {
428 _phantom: PhantomData,
429 info: EndpointInfo {
430 addr,
431 ep_type,
432 max_packet_size,
433 interval_ms,
434 },
435 pipe: pipe as u8,
436 })
437 }
438
439 fn alloc_endpoint_in(
440 &mut self,
441 ep_type: EndpointType,
442 ep_addr: Option<EndpointAddress>,
443 max_packet_size: u16,
444 interval_ms: u8,
445 ) -> Result<Self::EndpointIn, EndpointAllocError> {
446 let pipe = find_free_pipe(&self.pipes, ep_type).ok_or(EndpointAllocError)?;
447
448 let ep_num = if let Some(addr) = ep_addr {
449 if addr.is_out() {
450 return Err(EndpointAllocError);
451 }
452 addr.index() as u8
453 } else {
454 let n = self.next_ep_in;
455 self.next_ep_in += 1;
456 n
457 };
458
459 let addr = EndpointAddress::from_parts(ep_num as usize, Direction::In);
460 self.pipes[pipe - 1] = Some(PipeConfig {
461 ep_addr: addr,
462 ep_type,
463 max_packet: max_packet_size,
464 interval_ms,
465 });
466
467 Ok(EndpointIn {
468 _phantom: PhantomData,
469 info: EndpointInfo {
470 addr,
471 ep_type,
472 max_packet_size,
473 interval_ms,
474 },
475 pipe: pipe as u8,
476 })
477 }
478
479 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
480 let r = I::regs();
481
482 info!("USBFS: start (ctrl max_packet={})", control_max_packet_size);
483 r.syscfg().modify(|r| r.set_scke(true));
488
489 for _ in 0..200 {
491 cortex_m::asm::nop();
492 }
493
494 if !r.syscfg().read().scke() {
496 panic!("USBFS: SCKE=0 after SCKE=1 write");
497 }
498
499 #[cfg(usbfs_4m1)]
509 {
510 r.usbmc().modify(|r| {
511 r.set_vdcen(true);
512 });
513 debug!("USBFS: USBMC written (VDCEN=1)");
514 }
515
516 for _ in 0..1000 {
520 cortex_m::asm::nop();
521 }
522
523 r.syscfg().modify(|r| r.set_usbe(true));
524 r.syscfg().modify(|r| r.set_dcfm(false));
526 debug!("USBFS: SYSCFG after init={:?}", r.syscfg().read());
527
528 r.dcpmaxp()
530 .modify(|r| r.set_mxps(control_max_packet_size as u8));
531
532 for (idx, slot) in self.pipes.iter().enumerate() {
534 let Some(cfg) = slot else { continue };
535 let pipe = (idx + 1) as u8;
536
537 info!(
538 "USBFS: pipe {} epnum={} dir={} type={:02b} mxps={}",
539 pipe,
540 cfg.ep_addr.index(),
541 cfg.ep_addr.is_in(),
542 pipe_type(cfg.ep_type).to_bits(),
543 cfg.max_packet,
544 );
545
546 r.pipesel().modify(|r| {
548 r.set_pipesel(Pipesel::from_bits(pipe));
549 });
550
551 let is_in = cfg.ep_addr.is_in();
552 let is_bulk = cfg.ep_type == EndpointType::Bulk;
553 let is_double_buffered = is_bulk && pipe <= 5; r.pipecfg().modify(|r| {
556 r.set_epnum(cfg.ep_addr.index() as u8);
557 r.set_dir(is_in); r.set_type_(pipe_type(cfg.ep_type));
559 r.set_dblb(is_double_buffered);
560 r.set_shtnak(!is_in && is_bulk);
562 });
563
564 r.pipemaxp().modify(|r| r.set_mxps(cfg.max_packet));
565
566 if cfg.ep_type == EndpointType::Interrupt {
567 let iitv = cfg.interval_ms.trailing_zeros().min(7) as u8;
569 r.pipeperi().modify(|r| r.set_iitv(iitv));
570 }
571
572 r.pipectr(idx).modify(|r| {
574 r.set_sqclr(true);
575 r.set_aclrm(true);
576 });
577 r.pipectr(idx).modify(|r| r.set_aclrm(false));
578
579 EP_ADDR[idx].store(u8::from(cfg.ep_addr), Ordering::Release);
581 }
582
583 r.intenb0().modify(|r| {
585 r.set_brdye(true);
586 r.set_bempe(true);
587 r.set_ctre(true);
588 r.set_dvse(true);
589 r.set_rsme(true);
590 r.set_vbse(true);
591 });
592
593 r.bempenb().modify(|r| r.set_bemp(0, true));
595 r.brdyenb().modify(|r| r.set_brdy(0, true));
597
598 r.intsts0().write_value(Default::default());
603 r.intsts1().write_value(Default::default());
604
605 let vbsts = {
611 let a = r.intsts0().read().vbsts();
612 let b = r.intsts0().read().vbsts();
613 let c = r.intsts0().read().vbsts();
614 (c || a) && b || (a && c)
616 };
617 debug!("USBFS: VBSTS={}", vbsts);
618 if vbsts {
619 info!("USBFS: VBUS already present, synthesizing PowerDetected");
620 STATE
621 .pending_bus
622 .fetch_or(BusEvent::PowerDetected as _, Ordering::Release);
623 }
624
625 let max_packet_size = control_max_packet_size;
626 (
627 Bus {
628 _phantom: PhantomData,
629 },
630 ControlPipe {
631 _phantom: PhantomData,
632 max_packet_size,
633 },
634 )
635 }
636}
637
638fn find_free_pipe(pipes: &[Option<PipeConfig>; 9], ep_type: EndpointType) -> Option<usize> {
641 for (i, cfg) in pipes.iter().enumerate() {
642 if cfg.is_some() {
643 continue;
644 }
645 let pipe = i + 1; let ok = match ep_type {
647 EndpointType::Bulk => pipe <= 5,
648 EndpointType::Interrupt => pipe >= 6,
649 EndpointType::Isochronous => pipe <= 2,
650 EndpointType::Control => false,
651 };
652 if ok {
653 return Some(pipe);
654 }
655 }
656 None
657}
658
659fn pipe_type(ep_type: EndpointType) -> Type {
661 match ep_type {
662 EndpointType::Bulk => Type::_01,
663 EndpointType::Interrupt => Type::_10,
664 EndpointType::Isochronous => Type::_11,
665 EndpointType::Control => Type::_00,
666 }
667}