aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2019-10-08 09:37:21 -0400
committerBrian Cully <bjc@kublai.com>2019-10-08 09:37:21 -0400
commit22cda6d6b362e47fcd5e1f8589297b43fdcb8204 (patch)
treec81d918547ccdb4361a62c6c2983c02c44dba3a5
parent6d6fd2617ab909987e5ddecfb36519f0667ecf57 (diff)
downloadatsamd-usb-host-22cda6d6b362e47fcd5e1f8589297b43fdcb8204.tar.gz
atsamd-usb-host-22cda6d6b362e47fcd5e1f8589297b43fdcb8204.zip
Handle all known transfer/pipe errors.
* Remove `PipeErr::Other`. * Add more variants to `PipeErr`. * Integrate `is_transfer_complete` into `dispatch_result` and simplify. * Cache volatile `intflag` on entry to `dispatch_result` to ensure consistent handling. * Clear fail/perr `intflag` bits in `dispatch_result`.
-rw-r--r--src/lib.rs5
-rw-r--r--src/pipe.rs137
2 files changed, 81 insertions, 61 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 69b3fd3..5e8cc3c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -543,7 +543,10 @@ impl From<PipeErr> for TransferError {
PipeErr::PipeErr => Self::Permanent("pipe error"),
PipeErr::HWTimeout => Self::Permanent("hardware timeout"),
PipeErr::SWTimeout => Self::Permanent("software timeout"),
- PipeErr::Other(s) => Self::Permanent(s),
+ PipeErr::PID => Self::Permanent("pid error"),
+ PipeErr::DataPID => Self::Permanent("data pid error"),
+ PipeErr::CRC16 => Self::Permanent("crc16 error"),
+ //PipeErr::Other(s) => Self::Permanent(s),
}
}
}
diff --git a/src/pipe.rs b/src/pipe.rs
index 8739efd..8b10dc5 100644
--- a/src/pipe.rs
+++ b/src/pipe.rs
@@ -53,12 +53,9 @@ pub(crate) enum PipeErr {
HWTimeout,
DataToggle,
SWTimeout,
- Other(&'static str),
-}
-impl From<&'static str> for PipeErr {
- fn from(v: &'static str) -> Self {
- Self::Other(v)
- }
+ PID,
+ DataPID,
+ CRC16,
}
pub(crate) struct PipeTable {
@@ -182,14 +179,16 @@ impl Pipe<'_, '_> {
if let Some(b) = buf {
// TODO: data stage, has up to 5,000ms (in 500ms
// per-packet chunks) to complete. cf ยง9.2.6.4 of USB 2.0.
- match bm_request_type.direction()? {
- RequestDirection::DeviceToHost => {
+ match bm_request_type.direction() {
+ Ok(RequestDirection::DeviceToHost) => {
transfer_len = self.in_transfer(ep, b, NAK_LIMIT, millis)?;
}
- RequestDirection::HostToDevice => {
+ Ok(RequestDirection::HostToDevice) => {
transfer_len = self.out_transfer(ep, b, NAK_LIMIT, millis)?;
}
+
+ Err(_) => Err(PipeErr::PID)?,
}
}
@@ -203,9 +202,10 @@ impl Pipe<'_, '_> {
unsafe { w.multi_packet_size().bits(0) }
});
- let token = match bm_request_type.direction()? {
- RequestDirection::DeviceToHost => PToken::Out,
- RequestDirection::HostToDevice => PToken::In,
+ let token = match bm_request_type.direction() {
+ Ok(RequestDirection::DeviceToHost) => PToken::Out,
+ Ok(RequestDirection::HostToDevice) => PToken::In,
+ Err(_) => Err(PipeErr::PID)?,
};
trace!("dispatching status stage");
@@ -436,8 +436,6 @@ impl Pipe<'_, '_> {
self.regs
.cfg
.modify(|_, w| unsafe { w.ptoken().bits(token as u8) });
- self.regs.intflag.modify(|_, w| w.trfail().set_bit());
- self.regs.intflag.modify(|_, w| w.perr().set_bit());
match token {
PToken::Setup => {
@@ -477,60 +475,79 @@ impl Pipe<'_, '_> {
self.regs.statusclr.write(|w| w.pfreeze().set_bit());
}
- fn dispatch_result(&mut self, token: PToken) -> Result<bool, PipeErr> {
- if self.is_transfer_complete(token)? {
- self.regs.statusset.write(|w| w.pfreeze().set_bit());
+ fn dispatch_result(&mut self, _token: PToken) -> Result<bool, PipeErr> {
+ let flags = self.regs.intflag.read();
+ if flags.txstp().bit_is_set() {
+ self.regs.intflag.write(|w| w.txstp().set_bit());
Ok(true)
- } else if self.desc.bank0.status_bk.read().errorflow().bit_is_set() {
- trace!("errorflow");
- self.log_regs();
- Err(PipeErr::Flow)
- } else if self.desc.bank0.status_pipe.read().touter().bit_is_set() {
- trace!("touter");
- self.log_regs();
- Err(PipeErr::HWTimeout)
- } else if self.desc.bank0.status_pipe.read().dtgler().bit_is_set() {
- trace!("dtgler");
- self.log_regs();
- Err(PipeErr::DataToggle)
- } else if self.regs.intflag.read().trfail().bit_is_set() {
- self.regs.intflag.write(|w| w.trfail().set_bit());
- trace!("trfail");
+ } else if flags.trcpt0().bit_is_set() {
+ self.regs.intflag.write(|w| w.trcpt0().set_bit());
+ Ok(true)
+ } else if flags.stall().bit_is_set() {
+ self.regs.intflag.write(|w| w.stall().set_bit());
+ trace!("stall");
self.log_regs();
- Err(PipeErr::TransferFail)
+ Err(PipeErr::Stall)
+ } else if flags.trfail().bit_is_set() || flags.perr().bit_is_set() {
+ self.regs.intflag.write(|w| {
+ w.trfail().set_bit();
+ w.perr().set_bit()
+ });
+
+ if self.desc.bank0.status_pipe.read().dtgler().bit_is_set() {
+ self.desc
+ .bank0
+ .status_pipe
+ .write(|w| w.dtgler().clear_bit());
+ trace!("dtgler");
+ self.log_regs();
+ Err(PipeErr::DataToggle)
+ } else if self.desc.bank0.status_bk.read().errorflow().bit_is_set() {
+ self.desc
+ .bank0
+ .status_bk
+ .write(|w| w.errorflow().clear_bit());
+ trace!("errorflow");
+ self.log_regs();
+ 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());
+ trace!("touter");
+ self.log_regs();
+ Err(PipeErr::HWTimeout)
+ } else if self.desc.bank0.status_pipe.read().crc16er().bit_is_set() {
+ self.desc
+ .bank0
+ .status_pipe
+ .write(|w| w.crc16er().clear_bit());
+ trace!("crc16er");
+ self.log_regs();
+ Err(PipeErr::CRC16)
+ } else if self.desc.bank0.status_pipe.read().pider().bit_is_set() {
+ self.desc.bank0.status_pipe.write(|w| w.pider().clear_bit());
+ trace!("pider");
+ self.log_regs();
+ Err(PipeErr::PID)
+ } else if self.desc.bank0.status_pipe.read().dapider().bit_is_set() {
+ self.desc
+ .bank0
+ .status_pipe
+ .write(|w| w.dapider().clear_bit());
+ trace!("dapider");
+ self.log_regs();
+ Err(PipeErr::DataPID)
+ } else {
+ Err(PipeErr::TransferFail)
+ }
} else {
// Nothing wrong, but not done yet.
Ok(false)
}
}
- fn is_transfer_complete(&mut self, token: PToken) -> Result<bool, PipeErr> {
- match token {
- PToken::Setup => {
- if self.regs.intflag.read().txstp().bit_is_set() {
- self.regs.intflag.write(|w| w.txstp().set_bit());
- Ok(true)
- } else {
- Ok(false)
- }
- }
- PToken::In => {
- if self.regs.intflag.read().trcpt0().bit_is_set() {
- self.regs.intflag.write(|w| w.trcpt0().set_bit());
- Ok(true)
- } else {
- Ok(false)
- }
- }
- PToken::Out => {
- if self.regs.intflag.read().trcpt0().bit_is_set() {
- self.regs.intflag.write(|w| w.trcpt0().set_bit());
- Ok(true)
- } else {
- Ok(false)
- }
- }
- _ => Err(PipeErr::InvalidToken),
}
}