From 22cda6d6b362e47fcd5e1f8589297b43fdcb8204 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Tue, 8 Oct 2019 09:37:21 -0400 Subject: 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`. --- src/lib.rs | 5 ++- src/pipe.rs | 137 ++++++++++++++++++++++++++++++++++-------------------------- 2 files changed, 81 insertions(+), 61 deletions(-) (limited to 'src') 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 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 { - if self.is_transfer_complete(token)? { - self.regs.statusset.write(|w| w.pfreeze().set_bit()); + fn dispatch_result(&mut self, _token: PToken) -> Result { + 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 { - 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), } } -- cgit v1.2.3