diff options
Diffstat (limited to 'app/src/usb.rs')
-rw-r--r-- | app/src/usb.rs | 624 |
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); - } -} |