aboutsummaryrefslogtreecommitdiffstats
path: root/usbh/src/pipe.rs
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2019-07-27 20:10:47 -0400
committerBrian Cully <bjc@kublai.com>2019-07-27 20:10:47 -0400
commit59ffeec652f56f9eed0a26d1caaa892f47be18fd (patch)
tree75f91063b1bef6c792433076fdd94dc69d6a7f71 /usbh/src/pipe.rs
parente4614865c52a2fabbede08384ccb57079530575b (diff)
downloadsamd21-demo-59ffeec652f56f9eed0a26d1caaa892f47be18fd.tar.gz
samd21-demo-59ffeec652f56f9eed0a26d1caaa892f47be18fd.zip
Reduce millis function pointer call to one location.
Trying to remove this function entirely from pipe/device in order to make it non-blocking. Right now it's only used for dispatch_retries.
Diffstat (limited to 'usbh/src/pipe.rs')
-rw-r--r--usbh/src/pipe.rs122
1 files changed, 59 insertions, 63 deletions
diff --git a/usbh/src/pipe.rs b/usbh/src/pipe.rs
index f442873..c6f2023 100644
--- a/usbh/src/pipe.rs
+++ b/usbh/src/pipe.rs
@@ -290,9 +290,9 @@ impl Pipe<'_, '_> {
}
}
- // This and `dispatch_result` are the only function that calls
- // `millis`. If we can make this just take the current timestamp,
- // we can make this non-blocking.
+ // This is the only function that calls `millis`. If we can make
+ // this just take the current timestamp, we can make this
+ // non-blocking.
pub(crate) fn dispatch_retries(
&mut self,
token: USBToken,
@@ -304,24 +304,37 @@ impl Pipe<'_, '_> {
trace!("initial regs");
self.log_regs();
+ self.dispatch_packet(token);
+
let until = millis() + USB_TIMEOUT;
- let mut last_result: Result<(), PipeErr> = Err(PipeErr::SWTimeout);
+ let mut last_err = PipeErr::SWTimeout;
let mut naks = 0;
- while naks <= retries {
- trace!("p{}: dispatch {:?} retry {}", self.num, token, naks);
-
- self.dispatch_packet(token);
- last_result = self.dispatch_result(token, until, millis);
- match last_result {
- Ok(_) => return Ok(()),
- Err(PipeErr::DataToggle) => self.dtgl(),
- Err(PipeErr::SWTimeout) => break,
- Err(PipeErr::Stall) => break,
- Err(_) => naks += 1,
+ while millis() < until {
+ match self.dispatch_result(token) {
+ Ok(true) => return Ok(()),
+ Ok(false) => continue,
+
+ Err(e) => {
+ last_err = e;
+ match last_err {
+ PipeErr::DataToggle => self.dtgl(),
+ PipeErr::Stall => break,
+ _ => {
+ naks += 1;
+ if naks > retries {
+ break;
+ } else {
+ self.dispatch_packet(token);
+ }
+ }
+ }
+ }
}
}
- last_result
+ trace!("dispatch err: {:?}", last_err);
+ self.log_regs();
+ Err(last_err)
}
fn dispatch_packet(&mut self, token: USBToken) {
@@ -343,54 +356,37 @@ impl Pipe<'_, '_> {
self.regs.statusclr.write(|w| w.pfreeze().set_bit());
}
- fn dispatch_result(
- &mut self,
- token: USBToken,
- until: usize,
- millis: &dyn Fn() -> usize,
- ) -> Result<(), PipeErr> {
- while millis() <= until {
- if self.is_transfer_complete(token)? {
- return Ok(());
- } else if self.regs.intflag.read().stall().bit_is_set() {
- trace!("stall");
- self.log_regs();
- self.regs.intflag.write(|w| w.stall().set_bit());
- return Err(PipeErr::Stall);
- } else if self.regs.intflag.read().trfail().bit_is_set() {
- trace!("trfail");
- self.log_regs();
- self.regs.intflag.write(|w| w.trfail().set_bit());
- return Err(PipeErr::TransferFail);
- } else if self.desc.bank0.status_bk.read().errorflow().bit_is_set() {
- trace!("errorflow");
- self.log_regs();
- self.desc
- .bank0
- .status_bk
- .write(|w| w.errorflow().clear_bit());
- return Err(PipeErr::Flow);
- } else if self.desc.bank0.status_pipe.read().touter().bit_is_set() {
- trace!("touter");
- self.log_regs();
- self.desc
- .bank0
- .status_pipe
- .write(|w| w.touter().clear_bit());
- return Err(PipeErr::HWTimeout);
- } else if self.desc.bank0.status_pipe.read().dtgler().bit_is_set() {
- trace!("dtgler");
- self.log_regs();
- self.desc
- .bank0
- .status_pipe
- .write(|w| w.dtgler().clear_bit());
- return Err(PipeErr::DataToggle);
- }
+ fn dispatch_result(&mut self, token: USBToken) -> Result<bool, PipeErr> {
+ if self.is_transfer_complete(token)? {
+ Ok(true)
+ } else if self.regs.intflag.read().stall().bit_is_set() {
+ self.regs.intflag.write(|w| w.stall().set_bit());
+ Err(PipeErr::Stall)
+ } else if self.regs.intflag.read().trfail().bit_is_set() {
+ self.regs.intflag.write(|w| w.trfail().set_bit());
+ Err(PipeErr::TransferFail)
+ } else if self.desc.bank0.status_bk.read().errorflow().bit_is_set() {
+ self.desc
+ .bank0
+ .status_bk
+ .write(|w| w.errorflow().clear_bit());
+ Err(PipeErr::Flow)
+ } else if self.desc.bank0.status_pipe.read().touter().bit_is_set() {
+ self.desc
+ .bank0
+ .status_pipe
+ .write(|w| w.touter().clear_bit());
+ Err(PipeErr::HWTimeout)
+ } else if self.desc.bank0.status_pipe.read().dtgler().bit_is_set() {
+ self.desc
+ .bank0
+ .status_pipe
+ .write(|w| w.dtgler().clear_bit());
+ Err(PipeErr::DataToggle)
+ } else {
+ // Nothing wrong, but not done yet.
+ Ok(false)
}
- trace!("swtimeout");
- self.log_regs();
- Err(PipeErr::SWTimeout)
}
fn is_transfer_complete(&mut self, token: USBToken) -> Result<bool, PipeErr> {