usb: abort control data in/out on reset or when receiving another SETUP.

This removes the horrible timeout hack.
This commit is contained in:
Dario Nieuwenhuis 2022-04-06 03:14:22 +02:00
parent f6d11dfba5
commit 22a47aeeb2
3 changed files with 50 additions and 31 deletions

View file

@ -6,7 +6,6 @@ use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
use core::task::Poll; use core::task::Poll;
use cortex_m::peripheral::NVIC; use cortex_m::peripheral::NVIC;
use embassy::interrupt::InterruptExt; use embassy::interrupt::InterruptExt;
use embassy::time::{with_timeout, Duration};
use embassy::util::Unborrow; use embassy::util::Unborrow;
use embassy::waitqueue::AtomicWaker; use embassy::waitqueue::AtomicWaker;
use embassy_hal_common::unborrow; use embassy_hal_common::unborrow;
@ -59,6 +58,7 @@ impl<'d, T: Instance> Driver<'d, T> {
if regs.events_usbreset.read().bits() != 0 { if regs.events_usbreset.read().bits() != 0 {
regs.intenclr.write(|w| w.usbreset().clear()); regs.intenclr.write(|w| w.usbreset().clear());
BUS_WAKER.wake(); BUS_WAKER.wake();
EP0_WAKER.wake();
} }
if regs.events_ep0setup.read().bits() != 0 { if regs.events_ep0setup.read().bits() != 0 {
@ -585,7 +585,7 @@ pub struct ControlPipe<'d, T: Instance> {
impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
type SetupFuture<'a> = impl Future<Output = Request> + 'a where Self: 'a; type SetupFuture<'a> = impl Future<Output = Request> + 'a where Self: 'a;
type DataOutFuture<'a> = impl Future<Output = Result<usize, ReadError>> + 'a where Self: 'a; type DataOutFuture<'a> = impl Future<Output = Result<usize, ReadError>> + 'a where Self: 'a;
type DataInFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; type DataInFuture<'a> = impl Future<Output = Result<(), WriteError>> + 'a where Self: 'a;
fn max_packet_size(&self) -> usize { fn max_packet_size(&self) -> usize {
usize::from(self.max_packet_size) usize::from(self.max_packet_size)
@ -596,7 +596,10 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let regs = T::regs(); let regs = T::regs();
// Wait for SETUP packet // Wait for SETUP packet
regs.intenset.write(|w| w.ep0setup().set()); regs.intenset.write(|w| {
w.ep0setup().set();
w.ep0datadone().set()
});
poll_fn(|cx| { poll_fn(|cx| {
EP0_WAKER.register(cx.waker()); EP0_WAKER.register(cx.waker());
let regs = T::regs(); let regs = T::regs();
@ -639,22 +642,27 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let regs = T::regs(); let regs = T::regs();
// Wait until ready // Wait until ready
regs.intenset.write(|w| w.ep0datadone().set()); regs.intenset.write(|w| {
w.usbreset().set();
w.ep0setup().set();
w.ep0datadone().set()
});
poll_fn(|cx| { poll_fn(|cx| {
EP0_WAKER.register(cx.waker()); EP0_WAKER.register(cx.waker());
let regs = T::regs(); let regs = T::regs();
if regs if regs.events_usbreset.read().bits() != 0 {
.events_ep0datadone trace!("aborted control data_out: usb reset");
.read() Poll::Ready(Err(ReadError::Disabled))
.events_ep0datadone() } else if regs.events_ep0setup.read().bits() != 0 {
.bit_is_set() trace!("aborted control data_out: received another SETUP");
{ Poll::Ready(Err(ReadError::Disabled))
Poll::Ready(()) } else if regs.events_ep0datadone.read().bits() != 0 {
Poll::Ready(Ok(()))
} else { } else {
Poll::Pending Poll::Pending
} }
}) })
.await; .await?;
unsafe { read_dma::<T>(0, buf) } unsafe { read_dma::<T>(0, buf) }
} }
@ -671,24 +679,29 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
regs.shorts regs.shorts
.modify(|_, w| w.ep0datadone_ep0status().bit(last_packet)); .modify(|_, w| w.ep0datadone_ep0status().bit(last_packet));
regs.intenset.write(|w| w.ep0datadone().set()); regs.intenset.write(|w| {
let res = with_timeout( w.usbreset().set();
Duration::from_millis(10), w.ep0setup().set();
w.ep0datadone().set()
});
poll_fn(|cx| { poll_fn(|cx| {
cx.waker().wake_by_ref();
EP0_WAKER.register(cx.waker()); EP0_WAKER.register(cx.waker());
let regs = T::regs(); let regs = T::regs();
if regs.events_ep0datadone.read().bits() != 0 { if regs.events_usbreset.read().bits() != 0 {
Poll::Ready(()) trace!("aborted control data_in: usb reset");
Poll::Ready(Err(WriteError::Disabled))
} else if regs.events_ep0setup.read().bits() != 0 {
trace!("aborted control data_in: received another SETUP");
Poll::Ready(Err(WriteError::Disabled))
} else if regs.events_ep0datadone.read().bits() != 0 {
Poll::Ready(Ok(()))
} else { } else {
Poll::Pending Poll::Pending
} }
}), })
) .await
.await;
if res.is_err() {
error!("ControlPipe::data_in timed out.");
}
} }
} }

View file

@ -295,7 +295,13 @@ impl<C: driver::ControlPipe> ControlPipe<C> {
.chain(need_zlp.then(|| -> &[u8] { &[] })); .chain(need_zlp.then(|| -> &[u8] { &[] }));
while let Some(chunk) = chunks.next() { while let Some(chunk) = chunks.next() {
self.control.data_in(chunk, chunks.size_hint().0 == 0).await; match self.control.data_in(chunk, chunks.size_hint().0 == 0).await {
Ok(()) => {}
Err(e) => {
warn!("control accept_in failed: {:?}", e);
return;
}
}
} }
} }

View file

@ -147,7 +147,7 @@ pub trait ControlPipe {
type DataOutFuture<'a>: Future<Output = Result<usize, ReadError>> + 'a type DataOutFuture<'a>: Future<Output = Result<usize, ReadError>> + 'a
where where
Self: 'a; Self: 'a;
type DataInFuture<'a>: Future<Output = ()> + 'a type DataInFuture<'a>: Future<Output = Result<(), WriteError>> + 'a
where where
Self: 'a; Self: 'a;