Move data chunking from the driver to the lib

This commit is contained in:
alexmoon 2022-03-29 20:26:30 -04:00 committed by Dario Nieuwenhuis
parent 1672fdc666
commit 77e0aca03b
3 changed files with 160 additions and 129 deletions

View file

@ -186,7 +186,6 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
Ok(ControlPipe { Ok(ControlPipe {
_phantom: PhantomData, _phantom: PhantomData,
max_packet_size, max_packet_size,
request: None,
}) })
} }
@ -502,72 +501,19 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
pub struct ControlPipe<'d, T: Instance> { pub struct ControlPipe<'d, T: Instance> {
_phantom: PhantomData<&'d mut T>, _phantom: PhantomData<&'d mut T>,
max_packet_size: u16, max_packet_size: u16,
request: Option<Request>,
}
impl<'d, T: Instance> ControlPipe<'d, T> {
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, ReadError> {
let regs = T::regs();
// Wait until ready
regs.intenset.write(|w| w.ep0datadone().set());
poll_fn(|cx| {
EP_OUT_WAKERS[0].register(cx.waker());
let regs = T::regs();
if regs
.events_ep0datadone
.read()
.events_ep0datadone()
.bit_is_set()
{
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
unsafe { read_dma::<T>(0, buf) }
}
async fn write(&mut self, buf: &[u8], last_chunk: bool) {
let regs = T::regs();
regs.events_ep0datadone.reset();
unsafe { write_dma::<T>(0, buf) }
regs.shorts
.modify(|_, w| w.ep0datadone_ep0status().bit(last_chunk));
regs.intenset.write(|w| w.ep0datadone().set());
let res = with_timeout(
Duration::from_millis(10),
poll_fn(|cx| {
EP_IN_WAKERS[0].register(cx.waker());
let regs = T::regs();
if regs.events_ep0datadone.read().bits() != 0 {
Poll::Ready(())
} else {
Poll::Pending
}
}),
)
.await;
if res.is_err() {
error!("ControlPipe::write timed out.");
}
}
} }
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 AcceptInFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a; type DataInFuture<'a> = impl Future<Output = ()> + 'a where Self: 'a;
fn max_packet_size(&self) -> usize {
usize::from(self.max_packet_size)
}
fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> { fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a> {
async move { async move {
assert!(self.request.is_none());
let regs = T::regs(); let regs = T::regs();
// Wait for SETUP packet // Wait for SETUP packet
@ -605,29 +551,65 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
.write(|w| w.tasks_ep0rcvout().set_bit()); .write(|w| w.tasks_ep0rcvout().set_bit());
} }
self.request = Some(req);
req req
} }
} }
fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a> { fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a> {
async move { async move {
let req = unwrap!(self.request); let regs = T::regs();
assert!(req.direction == UsbDirection::Out);
assert!(req.length > 0);
let req_length = usize::from(req.length); // Wait until ready
let max_packet_size = usize::from(self.max_packet_size); regs.intenset.write(|w| w.ep0datadone().set());
let mut total = 0; poll_fn(|cx| {
for chunk in buf.chunks_mut(max_packet_size) { EP_OUT_WAKERS[0].register(cx.waker());
let size = self.read(chunk).await?; let regs = T::regs();
total += size; if regs
if size < max_packet_size || total == req_length { .events_ep0datadone
break; .read()
.events_ep0datadone()
.bit_is_set()
{
Poll::Ready(())
} else {
Poll::Pending
}
})
.await;
unsafe { read_dma::<T>(0, buf) }
} }
} }
Ok(total) fn data_in<'a>(&'a mut self, buf: &'a [u8], last_packet: bool) -> Self::DataInFuture<'a> {
async move {
let regs = T::regs();
regs.events_ep0datadone.reset();
unsafe {
write_dma::<T>(0, buf);
}
regs.shorts
.modify(|_, w| w.ep0datadone_ep0status().bit(last_packet));
regs.intenset.write(|w| w.ep0datadone().set());
let res = with_timeout(
Duration::from_millis(10),
poll_fn(|cx| {
EP_IN_WAKERS[0].register(cx.waker());
let regs = T::regs();
if regs.events_ep0datadone.read().bits() != 0 {
Poll::Ready(())
} else {
Poll::Pending
}
}),
)
.await;
if res.is_err() {
error!("ControlPipe::data_in timed out.");
}
} }
} }
@ -636,37 +618,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let regs = T::regs(); let regs = T::regs();
regs.tasks_ep0status regs.tasks_ep0status
.write(|w| w.tasks_ep0status().bit(true)); .write(|w| w.tasks_ep0status().bit(true));
self.request = None;
}
fn accept_in<'a>(&'a mut self, buf: &'a [u8]) -> Self::AcceptInFuture<'a> {
async move {
#[cfg(feature = "defmt")]
debug!("control in accept {:x}", buf);
#[cfg(not(feature = "defmt"))]
debug!("control in accept {:x?}", buf);
let req = unwrap!(self.request);
assert!(req.direction == UsbDirection::In);
let req_len = usize::from(req.length);
let len = buf.len().min(req_len);
let need_zlp = len != req_len && (len % usize::from(self.max_packet_size)) == 0;
let mut chunks = buf[0..len]
.chunks(usize::from(self.max_packet_size))
.chain(need_zlp.then(|| -> &[u8] { &[] }));
while let Some(chunk) = chunks.next() {
self.write(chunk, chunks.size_hint().0 == 0).await;
}
self.request = None;
}
} }
fn reject(&mut self) { fn reject(&mut self) {
debug!("control reject"); debug!("control reject");
let regs = T::regs(); let regs = T::regs();
regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true)); regs.tasks_ep0stall.write(|w| w.tasks_ep0stall().bit(true));
self.request = None;
} }
} }

View file

@ -137,30 +137,35 @@ 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 AcceptInFuture<'a>: Future<Output = ()> + 'a type DataInFuture<'a>: Future<Output = ()> + 'a
where where
Self: 'a; Self: 'a;
/// Maximum packet size for the control pipe
fn max_packet_size(&self) -> usize;
/// Reads a single setup packet from the endpoint. /// Reads a single setup packet from the endpoint.
fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a>; fn setup<'a>(&'a mut self) -> Self::SetupFuture<'a>;
/// Reads the data packet of a control write sequence. /// Reads a DATA OUT packet into `buf` in response to a control write request.
/// ///
/// Must be called after `setup()` for requests with `direction` of `Out` /// Must be called after `setup()` for requests with `direction` of `Out`
/// and `length` greater than zero. /// and `length` greater than zero.
///
/// `buf.len()` must be greater than or equal to the request's `length`.
fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a>; fn data_out<'a>(&'a mut self, buf: &'a mut [u8]) -> Self::DataOutFuture<'a>;
/// Sends a DATA IN packet with `data` in response to a control read request.
///
/// If `last_packet` is true, the STATUS packet will be ACKed following the transfer of `data`.
fn data_in<'a>(&'a mut self, data: &'a [u8], last_packet: bool) -> Self::DataInFuture<'a>;
/// Accepts a control request. /// Accepts a control request.
///
/// Causes the STATUS packet for the current request to be ACKed.
fn accept(&mut self); fn accept(&mut self);
/// Accepts a control read request with `data`.
///
/// `data.len()` must be less than or equal to the request's `length`.
fn accept_in<'a>(&'a mut self, data: &'a [u8]) -> Self::AcceptInFuture<'a>;
/// Rejects a control request. /// Rejects a control request.
///
/// Sets a STALL condition on the pipe to indicate an error.
fn reject(&mut self); fn reject(&mut self);
} }

View file

@ -55,7 +55,7 @@ pub const MAX_INTERFACE_COUNT: usize = 4;
pub struct UsbDevice<'d, D: Driver<'d>> { pub struct UsbDevice<'d, D: Driver<'d>> {
bus: D::Bus, bus: D::Bus,
control: D::ControlPipe, control: ControlPipe<D::ControlPipe>,
config: Config<'d>, config: Config<'d>,
device_descriptor: &'d [u8], device_descriptor: &'d [u8],
@ -92,7 +92,10 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
Self { Self {
bus: driver, bus: driver,
config, config,
control: ControlPipe {
control, control,
request: None,
},
device_descriptor, device_descriptor,
config_descriptor, config_descriptor,
bos_descriptor, bos_descriptor,
@ -140,32 +143,19 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
} }
} }
async fn control_in_accept_writer(
&mut self,
req: Request,
f: impl FnOnce(&mut DescriptorWriter),
) {
let mut buf = [0; 256];
let mut w = DescriptorWriter::new(&mut buf);
f(&mut w);
let pos = w.position().min(usize::from(req.length));
self.control.accept_in(&buf[..pos]).await;
}
async fn handle_control_out(&mut self, req: Request) { async fn handle_control_out(&mut self, req: Request) {
const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16;
const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16;
// If the request has a data state, we must read it. // If the request has a data state, we must read it.
let data = if req.length > 0 { let data = if req.length > 0 {
let size = match self.control.data_out(self.control_buf).await { match self.control.data_out(self.control_buf).await {
Ok(size) => size, Ok(data) => data,
Err(_) => { Err(_) => {
warn!("usb: failed to read CONTROL OUT data stage."); warn!("usb: failed to read CONTROL OUT data stage.");
return; return;
} }
}; }
&self.control_buf[0..size]
} else { } else {
&[] &[]
}; };
@ -315,8 +305,9 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
descriptor_type::CONFIGURATION => self.control.accept_in(self.config_descriptor).await, descriptor_type::CONFIGURATION => self.control.accept_in(self.config_descriptor).await,
descriptor_type::STRING => { descriptor_type::STRING => {
if index == 0 { if index == 0 {
self.control_in_accept_writer(req, |w| { self.control
w.write(descriptor_type::STRING, &lang_id::ENGLISH_US.to_le_bytes()) .accept_in_writer(req, |w| {
w.write(descriptor_type::STRING, &lang_id::ENGLISH_US.to_le_bytes());
}) })
.await .await
} else { } else {
@ -333,7 +324,7 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
}; };
if let Some(s) = s { if let Some(s) = s {
self.control_in_accept_writer(req, |w| w.string(s)).await; self.control.accept_in_writer(req, |w| w.string(s)).await;
} else { } else {
self.control.reject() self.control.reject()
} }
@ -343,3 +334,81 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
} }
} }
} }
struct ControlPipe<C: driver::ControlPipe> {
control: C,
request: Option<Request>,
}
impl<C: driver::ControlPipe> ControlPipe<C> {
async fn setup(&mut self) -> Request {
assert!(self.request.is_none());
let req = self.control.setup().await;
self.request = Some(req);
req
}
async fn data_out<'a>(&mut self, buf: &'a mut [u8]) -> Result<&'a [u8], ReadError> {
let req = self.request.unwrap();
assert_eq!(req.direction, UsbDirection::Out);
assert!(req.length > 0);
let req_length = usize::from(req.length);
let max_packet_size = self.control.max_packet_size();
let mut total = 0;
for chunk in buf.chunks_mut(max_packet_size) {
let size = self.control.data_out(chunk).await?;
total += size;
if size < max_packet_size || total == req_length {
break;
}
}
Ok(&buf[0..total])
}
async fn accept_in(&mut self, buf: &[u8]) -> () {
#[cfg(feature = "defmt")]
debug!("control in accept {:x}", buf);
#[cfg(not(feature = "defmt"))]
debug!("control in accept {:x?}", buf);
let req = unwrap!(self.request);
assert!(req.direction == UsbDirection::In);
let req_len = usize::from(req.length);
let len = buf.len().min(req_len);
let max_packet_size = self.control.max_packet_size();
let need_zlp = len != req_len && (len % usize::from(max_packet_size)) == 0;
let mut chunks = buf[0..len]
.chunks(max_packet_size)
.chain(need_zlp.then(|| -> &[u8] { &[] }));
while let Some(chunk) = chunks.next() {
self.control.data_in(chunk, chunks.size_hint().0 == 0).await;
}
self.request = None;
}
async fn accept_in_writer(&mut self, req: Request, f: impl FnOnce(&mut DescriptorWriter)) {
let mut buf = [0; 256];
let mut w = DescriptorWriter::new(&mut buf);
f(&mut w);
let pos = w.position().min(usize::from(req.length));
self.accept_in(&buf[..pos]).await;
}
fn accept(&mut self) {
assert!(self.request.is_some());
self.control.accept();
self.request = None;
}
fn reject(&mut self) {
assert!(self.request.is_some());
self.control.reject();
self.request = None;
}
}