Merge #1159
1159: stm32 usb otg bug fixes r=Dirbaio a=chemicstry This fixes a couple of usb otg bugs that surfaced with `usb_ethernet` example from nrf: - Properly implemented `Endpoint::wait_enabled()` - Return `EndpointError::Disabled` when neccessary in `Endpoint::write()` Co-authored-by: chemicstry <chemicstry@gmail.com>
This commit is contained in:
@ -791,6 +791,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
||||
w.set_usbaep(enabled);
|
||||
})
|
||||
});
|
||||
|
||||
// Wake `Endpoint::wait_enabled()`
|
||||
T::state().ep_out_wakers[ep_addr.index()].wake();
|
||||
}
|
||||
Direction::In => {
|
||||
// SAFETY: DIEPCTL is shared with `Endpoint` so critical section is needed for RMW
|
||||
@ -807,6 +810,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
|
||||
w.set_usbaep(enabled);
|
||||
})
|
||||
});
|
||||
|
||||
// Wake `Endpoint::wait_enabled()`
|
||||
T::state().ep_in_wakers[ep_addr.index()].wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1031,7 +1037,21 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, In> {
|
||||
&self.info
|
||||
}
|
||||
|
||||
async fn wait_enabled(&mut self) {}
|
||||
async fn wait_enabled(&mut self) {
|
||||
poll_fn(|cx| {
|
||||
let ep_index = self.info.addr.index();
|
||||
|
||||
T::state().ep_in_wakers[ep_index].register(cx.waker());
|
||||
|
||||
// SAFETY: atomic read without side effects
|
||||
if unsafe { T::regs().diepctl(ep_index).read().usbaep() } {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, Out> {
|
||||
@ -1039,7 +1059,21 @@ impl<'d, T: Instance> embassy_usb_driver::Endpoint for Endpoint<'d, T, Out> {
|
||||
&self.info
|
||||
}
|
||||
|
||||
async fn wait_enabled(&mut self) {}
|
||||
async fn wait_enabled(&mut self) {
|
||||
poll_fn(|cx| {
|
||||
let ep_index = self.info.addr.index();
|
||||
|
||||
T::state().ep_out_wakers[ep_index].register(cx.waker());
|
||||
|
||||
// SAFETY: atomic read without side effects
|
||||
if unsafe { T::regs().doepctl(ep_index).read().usbaep() } {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> {
|
||||
@ -1092,6 +1126,8 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointOut for Endpoint<'d, T, Out> {
|
||||
|
||||
impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
|
||||
async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
|
||||
trace!("write ep={:?} data={:?}", self.info.addr, buf);
|
||||
|
||||
if buf.len() > self.info.max_packet_size as usize {
|
||||
return Err(EndpointError::BufferOverflow);
|
||||
}
|
||||
@ -1100,18 +1136,21 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
|
||||
let index = self.info.addr.index();
|
||||
let state = T::state();
|
||||
|
||||
// Wait for previous transfer to complete
|
||||
// Wait for previous transfer to complete and check if endpoint is disabled
|
||||
poll_fn(|cx| {
|
||||
state.ep_in_wakers[index].register(cx.waker());
|
||||
|
||||
// SAFETY: atomic read with no side effects
|
||||
if unsafe { r.diepctl(index).read().epena() } {
|
||||
Poll::Pending
|
||||
let diepctl = unsafe { r.diepctl(index).read() };
|
||||
if !diepctl.usbaep() {
|
||||
Poll::Ready(Err(EndpointError::Disabled))
|
||||
} else if !diepctl.epena() {
|
||||
Poll::Ready(Ok(()))
|
||||
} else {
|
||||
Poll::Ready(())
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
.await;
|
||||
.await?;
|
||||
|
||||
if buf.len() > 0 {
|
||||
poll_fn(|cx| {
|
||||
@ -1167,7 +1206,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
|
||||
unsafe { r.fifo(index).write_value(regs::Fifo(u32::from_ne_bytes(tmp))) };
|
||||
}
|
||||
|
||||
trace!("WRITE OK");
|
||||
trace!("write done ep={:?}", self.info.addr);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1205,8 +1244,8 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
|
||||
// Clear NAK to indicate we are ready to receive more data
|
||||
T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| {
|
||||
w.set_cnak(true);
|
||||
})
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
trace!("SETUP received: {:?}", data);
|
||||
Poll::Ready(data)
|
||||
|
Reference in New Issue
Block a user