aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/usb.rs
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/usb.rs')
-rw-r--r--app/src/usb.rs624
1 files changed, 0 insertions, 624 deletions
diff --git a/app/src/usb.rs b/app/src/usb.rs
deleted file mode 100644
index a5788a1..0000000
--- a/app/src/usb.rs
+++ /dev/null
@@ -1,624 +0,0 @@
-mod pipe;
-mod usbproto;
-
-use pipe::{DataBuf, PipeErr, PipeTable, USBPipeType, USBToken};
-use rb::{Reader, RingBuffer, Writer};
-use usbproto::*;
-
-use crate::rtc;
-
-use embedded_hal::digital::v2::OutputPin;
-use log::{info, warn};
-use trinket_m0::{
- calibration::{usb_transn_cal, usb_transp_cal, usb_trim_cal},
- clock::{ClockGenId, ClockSource, GenericClockController},
- gpio::{self, Floating, Input, OpenDrain, Output},
- PM, USB,
-};
-
-#[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,
- WaitResetComplete,
- WaitSOF,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum SteadyState {
- Configuring,
- Running,
- Error,
-}
-
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum TaskState {
- Detached(DetachedState),
- Attached(AttachedState),
- Steady(SteadyState),
-}
-
-const MAX_DEVICES: usize = 16;
-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;
-
-#[repr(C)]
-#[derive(Debug)]
-struct EPInfo {
- ep_addr: u32,
- mak_pkt_size: u32,
- ep_attribs: u8,
-}
-
-impl EPInfo {
- fn bm_snd_toggle(&self) -> bool {
- const POS: u8 = 0;
- const MASK: u8 = 0x1;
- ((self.ep_attribs >> POS) & MASK) == 1
- }
- fn bm_rcv_toggle(&self) -> bool {
- const POS: u8 = 1;
- const MASK: u8 = 0x1;
- ((self.ep_attribs >> POS) & MASK) == 1
- }
- fn bm_nak_power(&self) -> u8 {
- const POS: u8 = 2;
- const MASK: u8 = 0x3f;
- (self.ep_attribs >> POS) & MASK
- }
-}
-
-#[derive(Debug)]
-struct USBDeviceAddress(u32);
-
-impl USBDeviceAddress {
- fn bm_address(&self) -> u8 {
- const POS: u8 = 0;
- const MASK: u32 = 0x7;
- ((self.0 >> POS) & MASK) as u8
- }
- fn bm_parent(&self) -> u8 {
- const POS: u8 = 3;
- const MASK: u32 = 0x7;
- ((self.0 >> POS) & MASK) as u8
- }
- fn bm_hub(&self) -> bool {
- const POS: u8 = 6;
- const MASK: u32 = 0x1;
- ((self.0 >> POS) & MASK) == 1
- }
-}
-
-pub struct USBHost {
- usb: USB,
-
- events: EventReader,
- task_state: TaskState,
- delay: usize,
-
- // Need chunk of RAM for USB pipes, which gets used with DESCADD
- // register.
- pipe_table: PipeTable,
-
- // 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>>>,
-}
-
-impl USBHost {
- 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,
- ) -> (Self, impl FnMut()) {
- let (eventr, mut eventw) = unsafe { EVENTS.split() };
- let mut rc = Self {
- usb: usb,
- events: eventr,
- task_state: TaskState::Detached(DetachedState::Initialize),
- delay: 0,
- pipe_table: PipeTable::new(),
-
- _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,
- };
-
- if let Some(he_pin) = host_enable_pin {
- rc.host_enable_pin = Some(he_pin.into_open_drain_output(port));
- }
-
- info!("setting up usb clock");
- 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);
-
- rc.reset_periph();
-
- let usbp = &rc.usb as *const _ as usize;
- (rc, move || handler(usbp, &mut eventw))
- }
-
- pub fn reset_periph(&mut self) {
- info!("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());
- info!("...done");
- }
-
- pub fn task(&mut self) {
- static mut LAST_EVENT: Event = Event::Error;
- unsafe {
- if LAST_EVENT != LATEST_EVENT {
- info!("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 {
- self.delay = rtc::millis() + SETTLE_DELAY;
- TaskState::Attached(AttachedState::WaitForSettle)
- } 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 {
- info!(
- "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() {
- // info!("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 = rtc::millis() + SETTLE_DELAY;
- // TaskState::Attached(AttachedState::WaitForSettle)
- // } else {
- // self.task_state
- // }
- // }
- // };
- }
-
- self.poll_devices();
- self.fsm();
-
- unsafe {
- LAST_EVENT = LATEST_EVENT;
- }
- }
-
- fn poll_devices(&mut self) {
- for _ in 0..MAX_DEVICES {}
- }
-
- 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 => {
- if rtc::millis() >= self.delay {
- 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() {
- info!("reset was sent");
- self.usb.host().intflag.write(|w| w.rst().set_bit());
-
- // Make sure we always have a control pipe set up.
- self.init_pipe0();
-
- // 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.delay = rtc::millis() + 20;
- self.task_state = TaskState::Attached(AttachedState::WaitSOF);
- }
- }
-
- AttachedState::WaitSOF => {
- if self.usb.host().intflag.read().hsof().bit_is_set() {
- self.usb.host().intflag.write(|w| w.hsof().set_bit());
- if rtc::millis() >= self.delay {
- self.task_state = TaskState::Steady(SteadyState::Configuring);
- }
- }
- }
- }
- }
-
- fn steady_fsm(&mut self, s: SteadyState) {
- match s {
- SteadyState::Configuring => {
- let low_speed = 0;
- self.task_state = match self.configure_dev(0, 0, low_speed) {
- Ok(_) => TaskState::Steady(SteadyState::Running),
- Err(e) => {
- warn!("Enumeration error: {:?}", e);
- TaskState::Steady(SteadyState::Error)
- }
- }
- }
-
- SteadyState::Running => {}
-
- SteadyState::Error => {}
- }
- }
-
- fn configure_dev(&mut self, _parent: u32, _port: u32, _low_speed: u32) -> Result<(), PipeErr> {
- // addr: 0x20007774
- let tmp: USBDeviceDescriptor = Default::default();
- // addr: 0x20007788
- let vol_descr = ::vcell::VolatileCell::new(tmp);
- self.control_req(
- 0,
- 0,
- BMRequestType::get_descr(),
- USBRequest::GetDescriptor,
- WValue::from((0, USBDescriptor::Device as u8)),
- 0,
- Some(DataBuf::from(&vol_descr)),
- )?;
-
- let desc = vol_descr.get();
- info!(
- " -- len: {}, ver: {:04x}, bMaxPacketSize: {}, bNumConfigurations: {}",
- desc.b_length, desc.bcd_usb, desc.b_max_packet_size, desc.b_num_configurations
- );
- info!(" -- vid: {:x}, pid: {:x}", desc.id_vendor, desc.id_product);
-
- // Assign address to this device and:
- // - Stash bMaxPacketSize
- // Then SET_ADDRESS(newAddr)
- let new_address: u8 = 1;
- self.control_req(
- 0,
- 0,
- BMRequestType::set(),
- USBRequest::SetAddress,
- WValue::from((new_address, 0)),
- 0,
- None,
- )?;
- info!(" -- address set");
- // Delay according to §9.2.6.3 of USB 2.0
- let until = rtc::millis() + 300;
- while rtc::millis() < until {}
-
- info!("getting config");
- let tmp: USBConfigurationDescriptor = Default::default();
- //let vol_descr = ::vcell::VolatileCell::new(tmp);
- self.control_req(
- new_address,
- 0,
- BMRequestType::get_descr(),
- USBRequest::GetConfiguration,
- WValue::from((0, 0)),
- 0,
- Some(DataBuf::from(&tmp)),
- )?;
-
- //let desc = vol_descr.get();
- info!("cdesc.len: {}", tmp.b_length);
-
- // Once addressed, SET_CONFIGURATION(0)
- info!("+++ setting configuration");
- let conf: u8 = 0;
- self.control_req(
- new_address,
- 0,
- BMRequestType::set(),
- USBRequest::SetConfiguration,
- WValue::from((conf, 0)),
- 0,
- None,
- )?;
- info!(" -- configuration set");
-
- // Now we should be able to access it normally.
-
- Ok(())
- }
-
- fn control_req(
- &mut self,
- addr: u8,
- ep: u8,
- bm_request_type: BMRequestType,
- b_request: USBRequest,
- w_value: WValue,
- w_index: u16,
- buf: Option<DataBuf>,
- ) -> Result<(), PipeErr> {
- if let Some(ref b) = buf {
- assert!(b.ptr as usize & 0x3 == 0);
- assert!(b.len <= 65_535);
- }
-
- /*
- * Setup stage.
- */
- let setup_packet = USBSetupPacket {
- bm_request_type: bm_request_type,
- b_request: b_request,
- w_value: w_value,
- w_index: w_index,
- w_length: match buf {
- None => 0,
- Some(ref b) => b.len as u16,
- },
- };
- let mut pipe = self.pipe_table.pipe_for(self.usb.host_mut(), addr, ep);
- pipe.send(USBToken::Setup, &DataBuf::from(&setup_packet), NAK_LIMIT)?;
-
- /*
- * Data stage.
- */
- if let Some(b) = buf {
- match bm_request_type.direction() {
- USBSetupDirection::DeviceToHost => {
- info!("buf0: {:?}", &b);
- pipe.in_transfer(&b, NAK_LIMIT)?;
- info!("buf1: {:?}", &b);
- }
-
- USBSetupDirection::HostToDevice => {
- info!("Should OUT for {}b", b.len);
- }
- }
- }
-
- /*
- * Status stage.
- */
- pipe.desc.bank0.pcksize.write(|w| {
- // FIXME: see note in `Pipe.send`.
- unsafe { w.bits(0) }
- });
-
- // PSTATUSSET.DTGL set -- TODO: figure out if this is
- // necessary.
- pipe.regs.statusset.write(|w| w.dtgl().set_bit());
-
- let token = match bm_request_type.direction() {
- USBSetupDirection::DeviceToHost => USBToken::Out,
- USBSetupDirection::HostToDevice => USBToken::In,
- };
-
- // TODO: should probably make `pipe.send` have optional
- // `DataBuf`, rather than exposing `dispatch_retries`.
- info!("dispatching status stage");
- pipe.dispatch_retries(token, NAK_LIMIT)?;
- Ok(())
- }
-
- // Set up a default pipe for the control endpoint 0 on pipe 0.
- fn init_pipe0(&mut self) {
- let speed = self.usb.host().status.read().speed().bits();
- let pipe = self.pipe_table.pipe_for(self.usb.host_mut(), 0, 0);
- pipe.regs.cfg.write(|w| {
- unsafe { w.ptype().bits(USBPipeType::Control as u8) };
- w.bk().clear_bit()
- });
- pipe.desc.bank0.pcksize.write(|w| match speed {
- 0 => w.size().bytes64(),
- _ => w.size().bytes8(),
- });
- }
-}
-
-pub fn handler(usbp: usize, events: &mut EventWriter) {
- let usb: &mut USB = unsafe { core::mem::transmute(usbp) };
- let flags = usb.host().intflag.read();
-
- info!("USB - {:x}", flags.bits());
-
- let mut unshift_event = |e: Event| {
- unsafe { LATEST_EVENT = e };
- if let Err(_) = events.unshift(e) {
- info!("Couldn't write USB event to queue.");
- }
- };
-
- if flags.hsof().bit_is_set() {
- info!(" +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.
- info!(" +rst");
- usb.host().intflag.write(|w| w.rst().set_bit());
- unshift_event(Event::Detached);
- }
-
- if flags.uprsm().bit_is_set() {
- info!(" +uprsm");
- usb.host().intflag.write(|w| w.uprsm().set_bit());
- unshift_event(Event::Detached);
- }
-
- if flags.dnrsm().bit_is_set() {
- info!(" +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.
- info!(" +wakeup");
- usb.host().intflag.write(|w| w.wakeup().set_bit());
- unshift_event(Event::Attached);
- }
-
- if flags.ramacer().bit_is_set() {
- info!(" +ramacer");
- usb.host().intflag.write(|w| w.ramacer().set_bit());
- unshift_event(Event::Detached);
- }
-
- if flags.dconn().bit_is_set() {
- info!(" +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() {
- info!(" +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);
- }
-}