aboutsummaryrefslogtreecommitdiffstats
path: root/usbh/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'usbh/src/lib.rs')
-rwxr-xr-xusbh/src/lib.rs474
1 files changed, 0 insertions, 474 deletions
diff --git a/usbh/src/lib.rs b/usbh/src/lib.rs
deleted file mode 100755
index 1ed414c..0000000
--- a/usbh/src/lib.rs
+++ /dev/null
@@ -1,474 +0,0 @@
-#![no_std]
-#![allow(dead_code)]
-
-mod device;
-mod pipe;
-mod usbproto;
-
-use device::{Device, DeviceTable};
-use pipe::{PipeErr, PipeTable, NO_DATA_STAGE};
-use rb::{Reader, RingBuffer, Writer};
-use usbproto::*;
-
-use atsamd_hal::{
- calibration::{usb_transn_cal, usb_transp_cal, usb_trim_cal},
- clock::{ClockGenId, ClockSource, GenericClockController},
- gpio::{self, Floating, Input, OpenDrain, Output},
- target_device::{PM, USB},
-};
-use embedded_hal::digital::v2::OutputPin;
-use log::{debug, error, trace, warn};
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-pub enum Event {
- Error,
- Detached,
- Attached,
-}
-type Events = RingBuffer<Event>;
-type EventReader = Reader<'static, Event>;
-type EventWriter = Writer<'static, Event>;
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum DetachedState {
- Initialize,
- WaitForDevice,
- Illegal,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum AttachedState {
- WaitForSettle(usize),
- WaitResetComplete,
- WaitSOF(usize),
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum SteadyState {
- Configuring,
- Running,
- Error,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum TaskState {
- Detached(DetachedState),
- Attached(AttachedState),
- Steady(SteadyState),
-}
-
-// Must be at least 100ms. cf §9.1.2 of USB 2.0.
-const SETTLE_DELAY: usize = 205; // Delay in sec/1024
-const NAK_LIMIT: usize = 15;
-
-static mut EVENTS: Events = Events::new(Event::Error);
-// FIXME: this is just for testing. The enum needs to be
-// thread-safe if this is the way we're going.
-static mut LATEST_EVENT: Event = Event::Detached;
-
-pub struct USBHost<F>
-where
- F: Fn() -> usize + 'static,
-{
- usb: USB,
-
- events: EventReader,
- task_state: TaskState,
-
- // Need chunk of RAM for USB pipes, which gets used with DESCADD
- // register.
- pipe_table: PipeTable,
-
- devices: DeviceTable,
- addr0: Device,
-
- // need sof 1kHz pad?
- _sof_pad: gpio::Pa23<gpio::PfG>,
- _dm_pad: gpio::Pa24<gpio::PfG>,
- _dp_pad: gpio::Pa25<gpio::PfG>,
- host_enable_pin: Option<gpio::Pa28<Output<OpenDrain>>>,
-
- // To get current milliseconds.
- millis: &'static F,
-}
-
-impl<F> USBHost<F>
-where
- F: Fn() -> usize + 'static,
-{
- pub fn new(
- usb: USB,
- sof_pin: gpio::Pa23<Input<Floating>>,
- dm_pin: gpio::Pa24<Input<Floating>>,
- dp_pin: gpio::Pa25<Input<Floating>>,
- host_enable_pin: Option<gpio::Pa28<Input<Floating>>>,
- port: &mut gpio::Port,
- clocks: &mut GenericClockController,
- pm: &mut PM,
- millis: &'static F,
- ) -> (Self, impl FnMut()) {
- let (eventr, mut eventw) = unsafe { EVENTS.split() };
-
- let mut rc = Self {
- usb: usb,
-
- events: eventr,
- task_state: TaskState::Detached(DetachedState::Initialize),
-
- pipe_table: PipeTable::new(),
-
- devices: DeviceTable::new(millis),
- addr0: Device::new(0, 8, millis),
-
- _sof_pad: sof_pin.into_function_g(port),
- _dm_pad: dm_pin.into_function_g(port),
- _dp_pad: dp_pin.into_function_g(port),
- host_enable_pin: None,
-
- millis: millis,
- };
-
- if let Some(he_pin) = host_enable_pin {
- rc.host_enable_pin = Some(he_pin.into_open_drain_output(port));
- }
-
- pm.apbbmask.modify(|_, w| w.usb_().set_bit());
-
- // Set up USB clock from 48MHz source on generic clock 6.
- clocks.configure_gclk_divider_and_source(ClockGenId::GCLK6, 1, ClockSource::DFLL48M, false);
- let gclk6 = clocks
- .get_gclk(ClockGenId::GCLK6)
- .expect("Could not get clock 6");
- clocks.usb(&gclk6);
-
- let usbp = &rc.usb as *const _ as usize;
- (rc, move || handler(usbp, &mut eventw))
- }
-
- pub fn reset_periph(&mut self) {
- debug!("resetting usb");
- // Reset the USB peripheral and wait for sync.
- self.usb.host().ctrla.write(|w| w.swrst().set_bit());
- while self.usb.host().syncbusy.read().swrst().bit_is_set() {}
-
- // Specify host mode.
- self.usb.host().ctrla.modify(|_, w| w.mode().host());
-
- // Unsafe due to use of raw bits method.
- unsafe {
- self.usb.host().padcal.write(|w| {
- w.transn().bits(usb_transn_cal());
- w.transp().bits(usb_transp_cal());
- w.trim().bits(usb_trim_cal())
- });
- }
-
- // Use normal, which is 0 and apparently means low-and-full capable
- self.usb.host().ctrlb.modify(|_, w| w.spdconf().normal());
- // According to docs, 1,2,3 are reserved, but .fs returns 3
- //self.usb.host().ctrlb.modify(|_, w| w.spdconf().fs());
-
- self.usb.host().ctrla.modify(|_, w| w.runstdby().set_bit()); // keep usb clock running in standby.
-
- // Set address of USB SRAM.
- // Unsafe due to use of raw bits method.
- unsafe {
- self.usb
- .host()
- .descadd
- .write(|w| w.bits(&self.pipe_table as *const _ as u32));
- }
-
- if let Some(he_pin) = &mut self.host_enable_pin {
- he_pin.set_high().expect("turning on usb host enable pin");
- }
-
- self.usb.host().intenset.write(|w| {
- w.wakeup().set_bit();
- w.dconn().set_bit();
- w.ddisc().set_bit()
- });
-
- self.usb.host().ctrla.modify(|_, w| w.enable().set_bit());
- while self.usb.host().syncbusy.read().enable().bit_is_set() {}
-
- // Set VBUS OK to allow host operation.
- self.usb.host().ctrlb.modify(|_, w| w.vbusok().set_bit());
- debug!("...done");
- }
-
- pub fn task(&mut self) {
- static mut LAST_EVENT: Event = Event::Error;
- unsafe {
- if LAST_EVENT != LATEST_EVENT {
- trace!("new event: {:?}", LATEST_EVENT);
- }
- }
-
- static mut LAST_TASK_STATE: TaskState = TaskState::Detached(DetachedState::Illegal);
- self.task_state = match unsafe { LATEST_EVENT } {
- Event::Error => TaskState::Detached(DetachedState::Illegal),
- Event::Detached => {
- if let TaskState::Detached(_) = self.task_state {
- self.task_state
- } else {
- TaskState::Detached(DetachedState::Initialize)
- }
- }
- Event::Attached => {
- if let TaskState::Detached(_) = self.task_state {
- TaskState::Attached(AttachedState::WaitForSettle(
- (self.millis)() + SETTLE_DELAY,
- ))
- } else {
- self.task_state
- }
- }
- };
-
- static mut LAST_CBITS: u16 = 0;
- static mut LAST_FLAGS: u16 = 0;
- let cbits = self.usb.host().ctrlb.read().bits();
- let bits = self.usb.host().intflag.read().bits();
- unsafe {
- if LAST_CBITS != cbits || LAST_FLAGS != bits || LAST_TASK_STATE != self.task_state {
- trace!(
- "cb: {:x}, f: {:x} changing state {:?} -> {:?}",
- cbits,
- bits,
- LAST_TASK_STATE,
- self.task_state,
- );
- }
- LAST_CBITS = cbits;
- LAST_FLAGS = bits;
- LAST_TASK_STATE = self.task_state
- };
-
- if let Some(_event) = self.events.shift() {
- // trace!("Found event: {:?}", event);
- // self.task_state = match event {
- // Event::None => TaskState::Detached(DetachedState::Illegal),
- // Event::Detached => {
- // if let TaskState::Detached(_) = self.task_state {
- // self.task_state
- // } else {
- // TaskState::Detached(DetachedState::Initialize)
- // }
- // }
- // Event::Attached => {
- // if let TaskState::Detached(_) = self.task_state {
- // self.delay = self.millis() + SETTLE_DELAY;
- // TaskState::Attached(AttachedState::WaitForSettle)
- // } else {
- // self.task_state
- // }
- // }
- // };
- }
-
- self.fsm();
-
- unsafe {
- LAST_EVENT = LATEST_EVENT;
- }
- }
-
- fn poll_devices(&mut self) {}
-
- fn fsm(&mut self) {
- // respond to events from interrupt.
- match self.task_state {
- TaskState::Detached(s) => self.detached_fsm(s),
- TaskState::Attached(s) => self.attached_fsm(s),
- TaskState::Steady(s) => self.steady_fsm(s),
- };
- }
-
- fn detached_fsm(&mut self, s: DetachedState) {
- match s {
- DetachedState::Initialize => {
- self.reset_periph();
- // TODO: Free resources.
-
- self.task_state = TaskState::Detached(DetachedState::WaitForDevice);
- }
-
- // Do nothing state. Just wait for an interrupt to come in
- // saying we have a device attached.
- DetachedState::WaitForDevice => {}
-
- // TODO: should probably reset everything if we end up here somehow.
- DetachedState::Illegal => {}
- }
- }
-
- 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::WaitResetComplete => {
- if self.usb.host().intflag.read().rst().bit_is_set() {
- trace!("reset was sent");
- self.usb.host().intflag.write(|w| w.rst().set_bit());
-
- // Seems unneccesary, since SOFE will be set
- // immediately after reset according to §32.6.3.3.
- self.usb.host().ctrlb.modify(|_, w| w.sofe().set_bit());
- // USB spec requires 20ms of SOF after bus reset.
- self.task_state =
- TaskState::Attached(AttachedState::WaitSOF((self.millis)() + 20));
- }
- }
-
- AttachedState::WaitSOF(until) => {
- if self.usb.host().intflag.read().hsof().bit_is_set() {
- self.usb.host().intflag.write(|w| w.hsof().set_bit());
- if (self.millis)() >= until {
- self.task_state = TaskState::Steady(SteadyState::Configuring);
- }
- }
- }
- }
- }
-
- fn steady_fsm(&mut self, s: SteadyState) {
- match s {
- SteadyState::Configuring => {
- self.task_state = match self.configure_dev() {
- Ok(_) => TaskState::Steady(SteadyState::Running),
- Err(e) => {
- warn!("Enumeration error: {:?}", e);
- TaskState::Steady(SteadyState::Error)
- }
- }
- }
-
- SteadyState::Running => {
- self.devices.run(&mut self.pipe_table, self.usb.host_mut());
- }
-
- SteadyState::Error => {}
- }
- }
-
- fn configure_dev(&mut self) -> Result<(), PipeErr> {
- let mut pipe = self
- .pipe_table
- .pipe_for(self.usb.host_mut(), &self.addr0.ep0);
- let mut vol_descr = ::vcell::VolatileCell::<DeviceDescriptor>::new(Default::default());
- pipe.control_transfer(
- &mut self.addr0.ep0,
- RequestType::get_descr(),
- RequestCode::GetDescriptor,
- WValue::from((0, DescriptorType::Device as u8)),
- 0,
- Some(&mut vol_descr),
- self.millis,
- )?;
-
- let desc = vol_descr.get();
- trace!(" -- devDesc: {:?}", desc);
-
- match self.devices.next(desc.b_max_packet_size, self.millis) {
- // TODO: new error for being out of devices.
- None => Err(PipeErr::Other("out of devices")),
- Some(device) => {
- debug!("Setting address to {}.", device.addr);
- pipe.control_transfer(
- &mut self.addr0.ep0,
- RequestType::set(),
- RequestCode::SetAddress,
- WValue::from((device.addr, 0)),
- 0,
- NO_DATA_STAGE,
- self.millis,
- )?;
-
- // Now that the device is addressed, `Device` can handle the
- // rest of the setup in its FSM.
- Ok(())
- }
- }
- }
-}
-
-pub fn handler(usbp: usize, events: &mut EventWriter) {
- let usb: &mut USB = unsafe { core::mem::transmute(usbp) };
- let flags = usb.host().intflag.read();
-
- trace!("USB - {:x}", flags.bits());
-
- let mut unshift_event = |e: Event| {
- unsafe { LATEST_EVENT = e };
- if let Err(_) = events.unshift(e) {
- error!("Couldn't write USB event to queue.");
- }
- };
-
- 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());
- // // Stop reset signal, in case of disconnection during reset
- // uhd_stop_reset(); // nothing on samd21
- 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);
- }
-}