aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2019-08-10 19:40:34 -0400
committerBrian Cully <bjc@kublai.com>2019-08-10 19:40:34 -0400
commitc2d0f2af2f21a3c9539b89749bf6139c9f15b903 (patch)
treeae9ac0a35f22cd585f916d34805f3aa97cd2389f
parente5cff55c1dc5a9862ce4e78e3af816bbc5e1550b (diff)
downloadatsamd-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.
-rw-r--r--src/lib.rs73
-rw-r--r--src/pipe.rs16
-rw-r--r--src/pipe/ctrl_pipe.rs10
3 files changed, 27 insertions, 72 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 93a3993..c4285fb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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 {