diff options
author | Brian Cully <bjc@kublai.com> | 2019-08-10 19:40:34 -0400 |
---|---|---|
committer | Brian Cully <bjc@kublai.com> | 2019-08-10 19:40:34 -0400 |
commit | c2d0f2af2f21a3c9539b89749bf6139c9f15b903 (patch) | |
tree | ae9ac0a35f22cd585f916d34805f3aa97cd2389f /src | |
parent | e5cff55c1dc5a9862ce4e78e3af816bbc5e1550b (diff) | |
download | atsamd-usb-host-c2d0f2af2f21a3c9539b89749bf6139c9f15b903.tar.gz atsamd-usb-host-c2d0f2af2f21a3c9539b89749bf6139c9f15b903.zip |
A bunch of cleanup and fixes.
Simplify the code a bunch to reduce it to states we actually care
about. This will now probe my Logitech G105, NIZ Plum 85EC, and
Keyboard.io Model 01.
* Don't listen for wakeup interrupts. Only listen for device
connection and disconnection, which wakeups sometimes mean.
* Remove the SETTLE_DELAY stuff on device connection, as this
appears to be handled in hardware, and prevents over-delay which
was causing the Model 01 to reset, since it wasn't getting a SOF
in time.
* Set initial max packet size for address 0 endpoint 0 based on
whether the connection is Full Speed or Low Speed.
* Remove all intflag checks from USB handler that we don't
explicitly set up.
* Always listen dor dconn/ddisc in handler. Since we're using a ring
buffer for event storage, we shouldn't miss these and always
handle them in order.
* Don't freeze pipes on errors. Let the hardware do it.
* Don't retransmit packets on errors, just keep polling hardware.
* Move trfail check to the end, since it's either dependent on
previous, more specific checks, or it's just a NAK (but, for some
reason, not ERRORFLOW).
* Add `modify` method to control pipe register.
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 73 | ||||
-rw-r--r-- | src/pipe.rs | 16 | ||||
-rw-r--r-- | src/pipe/ctrl_pipe.rs | 10 |
3 files changed, 27 insertions, 72 deletions
@@ -33,9 +33,6 @@ type EventWriter = Writer<'static, Event>; const NAK_LIMIT: usize = 15; -// Must be at least 100ms. cf §9.1.2 of USB 2.0. -const SETTLE_DELAY: usize = 205; // Delay in sec/1024 - // Ring buffer for sharing events from interrupt context. static mut EVENTS: Events = Events::new(Event::Error); @@ -48,7 +45,7 @@ enum DetachedState { #[derive(Clone, Copy, Debug, PartialEq)] enum AttachedState { - WaitForSettle(usize), + ResetBus, WaitResetComplete, WaitSOF(usize), } @@ -226,7 +223,6 @@ where } self.usb.host().intenset.write(|w| { - w.wakeup().set_bit(); w.dconn().set_bit(); w.ddisc().set_bit() }); @@ -255,9 +251,7 @@ where } Event::Attached => { if let TaskState::Detached(_) = self.task_state { - TaskState::Attached(AttachedState::WaitForSettle( - (self.millis)() + SETTLE_DELAY, - )) + TaskState::Attached(AttachedState::ResetBus) } else { self.task_state } @@ -316,11 +310,9 @@ where fn attached_fsm(&mut self, s: AttachedState) { match s { - AttachedState::WaitForSettle(until) => { - if (self.millis)() >= until { - self.usb.host().ctrlb.modify(|_, w| w.busreset().set_bit()); - self.task_state = TaskState::Attached(AttachedState::WaitResetComplete); - } + AttachedState::ResetBus => { + self.usb.host().ctrlb.modify(|_, w| w.busreset().set_bit()); + self.task_state = TaskState::Attached(AttachedState::WaitResetComplete); } AttachedState::WaitResetComplete => { @@ -378,7 +370,12 @@ where fn configure_dev(&mut self, drivers: &mut [&mut dyn Driver]) -> Result<(), TransferError> { let none: Option<&mut [u8]> = None; + let max_packet_size: u16 = match self.usb.host().status.read().speed().bits() { + 0x0 => 64, + _ => 8, + }; let mut a0ep0 = Addr0EP0 { + max_packet_size: max_packet_size, in_toggle: true, out_toggle: true, }; @@ -435,6 +432,7 @@ where } struct Addr0EP0 { + max_packet_size: u16, in_toggle: bool, out_toggle: bool, } @@ -456,7 +454,7 @@ impl Endpoint for Addr0EP0 { } fn max_packet_size(&self) -> u16 { - 8 + self.max_packet_size } fn in_toggle(&self) -> bool { @@ -488,62 +486,15 @@ pub fn handler(usbp: usize, events: &mut EventWriter) { } }; - if flags.hsof().bit_is_set() { - trace!(" +hsof"); - usb.host().intflag.write(|w| w.hsof().set_bit()); - unshift_event(Event::Attached); - } - - if flags.rst().bit_is_set() { - // We seem to get this whenever a device attaches/detaches. - trace!(" +rst"); - usb.host().intflag.write(|w| w.rst().set_bit()); - unshift_event(Event::Detached); - } - - if flags.uprsm().bit_is_set() { - trace!(" +uprsm"); - usb.host().intflag.write(|w| w.uprsm().set_bit()); - unshift_event(Event::Detached); - } - - if flags.dnrsm().bit_is_set() { - trace!(" +dnrsm"); - usb.host().intflag.write(|w| w.dnrsm().set_bit()); - unshift_event(Event::Detached); - } - - if flags.wakeup().bit_is_set() { - // §32.8.5.8 - since VBUSOK is set, then this happens when a - // device is connected. - trace!(" +wakeup"); - usb.host().intflag.write(|w| w.wakeup().set_bit()); - unshift_event(Event::Attached); - } - - if flags.ramacer().bit_is_set() { - trace!(" +ramacer"); - usb.host().intflag.write(|w| w.ramacer().set_bit()); - unshift_event(Event::Detached); - } - if flags.dconn().bit_is_set() { trace!(" +dconn"); usb.host().intflag.write(|w| w.dconn().set_bit()); - usb.host().intenclr.write(|w| w.dconn().set_bit()); - usb.host().intflag.write(|w| w.ddisc().set_bit()); - usb.host().intenset.write(|w| w.ddisc().set_bit()); - usb.host().intflag.write(|w| w.dconn().set_bit()); unshift_event(Event::Attached); } if flags.ddisc().bit_is_set() { trace!(" +ddisc"); usb.host().intflag.write(|w| w.ddisc().set_bit()); - usb.host().intenclr.write(|w| w.ddisc().set_bit()); - usb.host().intflag.write(|w| w.dconn().set_bit()); - usb.host().intenset.write(|w| w.dconn().set_bit()); - usb.host().intflag.write(|w| w.ddisc().set_bit()); unshift_event(Event::Detached); } } diff --git a/src/pipe.rs b/src/pipe.rs index e90b88b..7d8a4b7 100644 --- a/src/pipe.rs +++ b/src/pipe.rs @@ -420,8 +420,6 @@ impl Pipe<'_, '_> { naks += 1; if naks > retries { break; - } else { - self.dispatch_packet(ep, token); } } } @@ -481,27 +479,23 @@ impl Pipe<'_, '_> { if self.is_transfer_complete(token)? { self.regs.statusset.write(|w| w.pfreeze().set_bit()); Ok(true) - } else if self.regs.intflag.read().trfail().bit_is_set() { - self.regs.intflag.write(|w| w.trfail().set_bit()); - trace!("trfail"); - self.regs.statusset.write(|w| w.pfreeze().set_bit()); - self.log_regs(); - Err(PipeErr::TransferFail) } else if self.desc.bank0.status_bk.read().errorflow().bit_is_set() { trace!("errorflow"); - self.regs.statusset.write(|w| w.pfreeze().set_bit()); self.log_regs(); Err(PipeErr::Flow) } else if self.desc.bank0.status_pipe.read().touter().bit_is_set() { trace!("touter"); - self.regs.statusset.write(|w| w.pfreeze().set_bit()); self.log_regs(); Err(PipeErr::HWTimeout) } else if self.desc.bank0.status_pipe.read().dtgler().bit_is_set() { trace!("dtgler"); - self.regs.statusset.write(|w| w.pfreeze().set_bit()); 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"); + self.log_regs(); + Err(PipeErr::TransferFail) } else { // Nothing wrong, but not done yet. Ok(false) diff --git a/src/pipe/ctrl_pipe.rs b/src/pipe/ctrl_pipe.rs index 9301d51..91235cd 100644 --- a/src/pipe/ctrl_pipe.rs +++ b/src/pipe/ctrl_pipe.rs @@ -28,6 +28,16 @@ impl CtrlPipe { f(&mut w); self.0 = w.bits; } + + pub fn modify<F>(&mut self, f: F) + where + for<'w> F: FnOnce(&R, &'w mut W) -> &'w mut W, + { + let r = R { bits: self.0 }; + let mut w = W { bits: self.0 }; + f(&r, &mut w); + self.0 = w.bits; + } } impl From<u16> for CtrlPipe { |