From 1e4c1630837bda2dceea7769fa505f3f3678fbe3 Mon Sep 17 00:00:00 2001 From: Ian Rees Date: Thu, 24 Jun 2021 16:13:32 +1200 Subject: [PATCH] Use USB OUT endpoint transfer failed interrupt Previously, when the USB interrupt was unmasked and a host issued an OUT transfer that was not subsequently `read()`, the interrupt would continually fire until `read()` was called. This change provides a way for a USB class to acknowledge the transfer without reading the data, and so clear the interrupt flag. --- hal/src/thumbv6m/usb/bus.rs | 13 ++++++++++--- hal/src/thumbv7em/usb/bus.rs | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/hal/src/thumbv6m/usb/bus.rs b/hal/src/thumbv6m/usb/bus.rs index 3f2b2f95b2a6..c718ada23248 100644 --- a/hal/src/thumbv6m/usb/bus.rs +++ b/hal/src/thumbv6m/usb/bus.rs @@ -431,7 +431,7 @@ impl<'a> Bank<'a, OutBank> { /// Enables endpoint-specific interrupts. fn setup_ep_interrupts(&mut self) { self.epintenset(self.index()) - .write(|w| w.rxstp().set_bit().trcpt0().set_bit()); + .write(|w| w.rxstp().set_bit().trfail0().set_bit().trcpt0().set_bit()); } /// Copies data from the bank0 buffer to the provided array. The caller @@ -920,7 +920,11 @@ impl Inner { // instead it is cleared in the read handler. } - if bank0.is_transfer_complete() { + // A class may have used an empty read, via .read(&mut[]), on an OUT + // endpoint to signal that the class is not ready to receive more + // data. That action clears the transfer complete and failed flags, + // but not bk0rdy. So, check .is_ready() here. + if bank0.is_ready() { dbgprint!("ep {} READABLE\n", ep); ep_out |= mask; } @@ -978,7 +982,10 @@ impl Inner { // self.print_epstatus(idx, "read"); bank.clear_transfer_complete(); - bank.set_ready(false); + + if buf.len() != 0 { + bank.set_ready(false); + } drop(bank); diff --git a/hal/src/thumbv7em/usb/bus.rs b/hal/src/thumbv7em/usb/bus.rs index b9087e4fa1aa..6f04f4184928 100644 --- a/hal/src/thumbv7em/usb/bus.rs +++ b/hal/src/thumbv7em/usb/bus.rs @@ -432,7 +432,7 @@ impl<'a> Bank<'a, OutBank> { /// Enables endpoint-specific interrupts. fn setup_ep_interrupts(&mut self) { self.epintenset(self.index()) - .write(|w| w.rxstp().set_bit().trcpt0().set_bit()); + .write(|w| w.rxstp().set_bit().trfail0().set_bit().trcpt0().set_bit()); } /// Copies data from the bank0 buffer to the provided array. The caller @@ -866,7 +866,11 @@ impl Inner { // instead it is cleared in the read handler. } - if bank0.is_transfer_complete() { + // A class may have used an empty read, via .read(&mut[]), on an OUT + // endpoint to signal that the class is not ready to receive more + // data. That action clears the transfer complete and failed flags, + // but not bk0rdy. So, check .is_ready() here. + if bank0.is_ready() { dbgprint!("ep {} READABLE\n", ep); ep_out |= mask; } @@ -924,7 +928,10 @@ impl Inner { // self.print_epstatus(idx, "read"); bank.clear_transfer_complete(); - bank.set_ready(false); + + if buf.len() != 0 { + bank.set_ready(false); + } drop(bank);