use crate::{buffer, gpt, ral};
use usb_device::{
bus::PollResult,
endpoint::{EndpointAddress, EndpointType},
UsbDirection, UsbError,
};
fn ctrl_ep0_out() -> EndpointAddress {
EndpointAddress::from_parts(0, UsbDirection::Out)
}
fn ctrl_ep0_in() -> EndpointAddress {
EndpointAddress::from_parts(0, UsbDirection::In)
}
fn all_ep_addrs(count: usize) -> impl Iterator<Item = EndpointAddress> {
(0..count).flat_map(|index| {
let ep_out = EndpointAddress::from_parts(index, UsbDirection::Out);
let ep_in = EndpointAddress::from_parts(index, UsbDirection::In);
[ep_out, ep_in]
})
}
fn non_zero_ep_addrs(count: usize) -> impl Iterator<Item = EndpointAddress> {
all_ep_addrs(count).skip(2)
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Speed {
LowFull,
High,
}
impl Default for Speed {
fn default() -> Self {
Speed::High
}
}
pub struct Driver {
usb: ral::usb::Instance,
phy: ral::usbphy::Instance,
buffer_allocator: buffer::Allocator,
ep_allocator: crate::state::EndpointAllocator<'static>,
ep_out: u16,
}
impl Driver {
pub fn new<P: crate::Peripherals, const SIZE: usize, const EP_COUNT: usize>(
peripherals: P,
buffer: &'static crate::buffer::EndpointMemory<SIZE>,
state: &'static crate::state::EndpointState<EP_COUNT>,
) -> Self {
let ral::Instances { usb, usbphy: phy } = ral::instances(peripherals);
let ep_allocator = state.allocator().expect("Endpoint state already assigned");
Driver {
usb,
phy,
buffer_allocator: buffer
.allocator()
.expect("Endpoint memory already assigned"),
ep_allocator,
ep_out: 0,
}
}
pub fn initialize(&mut self, speed: Speed) {
ral::write_reg!(ral::usbphy, self.phy, CTRL_SET, SFTRST: 1);
ral::write_reg!(ral::usbphy, self.phy, CTRL_CLR, SFTRST: 1);
ral::write_reg!(ral::usbphy, self.phy, CTRL_CLR, CLKGATE: 1);
ral::write_reg!(ral::usbphy, self.phy, PWD, 0);
ral::write_reg!(ral::usb, self.usb, USBCMD, RST: 1);
while ral::read_reg!(ral::usb, self.usb, USBCMD, RST == 1) {}
ral::write_reg!(ral::usb, self.usb, USBCMD, ITC: 0);
ral::write_reg!(ral::usb, self.usb, USBMODE, CM: CM_2, SLOM: 1);
ral::modify_reg!(ral::usb, self.usb, PORTSC1, PFSC: (speed == Speed::LowFull) as u32);
ral::modify_reg!(ral::usb, self.usb, USBSTS, |usbsts| usbsts);
ral::write_reg!(ral::usb, self.usb, USBINTR, 0);
ral::write_reg!(
ral::usb,
self.usb,
ASYNCLISTADDR,
self.ep_allocator.qh_list_addr() as u32
)
}
pub fn enable_zlt(&mut self, ep_addr: EndpointAddress) {
if let Some(ep) = self.ep_allocator.endpoint_mut(ep_addr) {
ep.enable_zlt();
}
}
pub fn set_interrupts(&mut self, interrupts: bool) {
if interrupts {
ral::modify_reg!(ral::usb, self.usb, USBINTR, UE: 1, URE: 1, PCE: 1);
} else {
ral::modify_reg!(ral::usb, self.usb, USBINTR, UE: 0, URE: 0, PCE: 0);
}
}
pub fn gpt_mut<R>(&mut self, instance: gpt::Instance, f: impl FnOnce(&mut gpt::Gpt) -> R) -> R {
let mut gpt = gpt::Gpt::new(&mut self.usb, instance);
f(&mut gpt)
}
pub fn set_address(&mut self, address: u8) {
ral::write_reg!(ral::usb, self.usb, DEVICEADDR, USBADR: address as u32, USBADRA: 1);
debug!("ADDRESS {}", address);
}
pub fn attach(&mut self) {
ral::modify_reg!(ral::usb, self.usb, USBCMD, RS: 1);
}
pub fn bus_reset(&mut self) {
ral::modify_reg!(ral::usb, self.usb, ENDPTSTAT, |endptstat| endptstat);
ral::modify_reg!(ral::usb, self.usb, ENDPTCOMPLETE, |endptcomplete| {
endptcomplete
});
ral::modify_reg!(ral::usb, self.usb, ENDPTNAK, |endptnak| endptnak);
ral::write_reg!(ral::usb, self.usb, ENDPTNAKEN, 0);
while ral::read_reg!(ral::usb, self.usb, ENDPTPRIME) != 0 {}
ral::write_reg!(ral::usb, self.usb, ENDPTFLUSH, u32::max_value());
while ral::read_reg!(ral::usb, self.usb, ENDPTFLUSH) != 0 {}
debug_assert!(
ral::read_reg!(ral::usb, self.usb, PORTSC1, PR == 1),
"Took too long to handle bus reset"
);
debug!("RESET");
}
pub fn is_allocated(&self, addr: EndpointAddress) -> bool {
self.ep_allocator.endpoint(addr).is_some()
}
pub fn ctrl0_read(&mut self, buffer: &mut [u8]) -> Result<usize, UsbError> {
let ctrl_out = self.ep_allocator.endpoint_mut(ctrl_ep0_out()).unwrap();
if ctrl_out.has_setup(&self.usb) && buffer.len() >= 8 {
debug!("EP0 Out SETUP");
let setup = ctrl_out.read_setup(&self.usb);
buffer[..8].copy_from_slice(&setup.to_le_bytes());
if !ctrl_out.is_primed(&self.usb) {
ctrl_out.clear_nack(&self.usb);
let max_packet_len = ctrl_out.max_packet_len();
ctrl_out.schedule_transfer(&self.usb, max_packet_len);
}
Ok(8)
} else {
ctrl_out.check_errors()?;
if ctrl_out.is_primed(&self.usb) {
return Err(UsbError::WouldBlock);
}
ctrl_out.clear_complete(&self.usb);
ctrl_out.clear_nack(&self.usb);
let read = ctrl_out.read(buffer);
debug!("EP0 Out {}", read);
let max_packet_len = ctrl_out.max_packet_len();
ctrl_out.schedule_transfer(&self.usb, max_packet_len);
Ok(read)
}
}
pub fn ctrl0_write(&mut self, buffer: &[u8]) -> Result<usize, UsbError> {
let ctrl_in = self.ep_allocator.endpoint_mut(ctrl_ep0_in()).unwrap();
debug!("EP0 In {}", buffer.len());
ctrl_in.check_errors()?;
if ctrl_in.is_primed(&self.usb) {
return Err(UsbError::WouldBlock);
}
ctrl_in.clear_nack(&self.usb);
let written = ctrl_in.write(buffer);
ctrl_in.schedule_transfer(&self.usb, written);
let ctrl_out = self.ep_allocator.endpoint_mut(ctrl_ep0_out()).unwrap();
if !ctrl_out.is_primed(&self.usb) {
ctrl_out.clear_complete(&self.usb);
ctrl_out.clear_nack(&self.usb);
ctrl_out.schedule_transfer(&self.usb, 0);
}
Ok(written)
}
pub fn ep_read(&mut self, buffer: &mut [u8], addr: EndpointAddress) -> Result<usize, UsbError> {
let ep = self.ep_allocator.endpoint_mut(addr).unwrap();
debug!("EP{} Out", ep.address().index());
ep.check_errors()?;
if ep.is_primed(&self.usb) || (self.ep_out & (1 << ep.address().index()) == 0) {
return Err(UsbError::WouldBlock);
}
ep.clear_complete(&self.usb); ep.clear_nack(&self.usb);
let read = ep.read(buffer);
let max_packet_len = ep.max_packet_len();
ep.schedule_transfer(&self.usb, max_packet_len);
Ok(read)
}
pub fn ep_write(&mut self, buffer: &[u8], addr: EndpointAddress) -> Result<usize, UsbError> {
let ep = self.ep_allocator.endpoint_mut(addr).unwrap();
ep.check_errors()?;
if ep.is_primed(&self.usb) {
return Err(UsbError::WouldBlock);
}
ep.clear_nack(&self.usb);
let written = ep.write(buffer);
ep.schedule_transfer(&self.usb, written);
Ok(written)
}
pub fn ep_stall(&mut self, stall: bool, addr: EndpointAddress) {
let ep = self.ep_allocator.endpoint_mut(addr).unwrap();
ep.set_stalled(&self.usb, stall);
if !stall && addr.direction() == UsbDirection::Out && !ep.is_primed(&self.usb) {
let max_packet_len = ep.max_packet_len();
ep.schedule_transfer(&self.usb, max_packet_len);
}
}
pub fn is_ep_stalled(&self, addr: EndpointAddress) -> bool {
self.ep_allocator
.endpoint(addr)
.unwrap()
.is_stalled(&self.usb)
}
pub fn allocate_buffer(&mut self, max_packet_len: usize) -> Option<buffer::Buffer> {
self.buffer_allocator.allocate(max_packet_len)
}
pub fn allocate_ep(
&mut self,
addr: EndpointAddress,
buffer: buffer::Buffer,
kind: EndpointType,
) {
self.ep_allocator
.allocate_endpoint(addr, buffer, kind)
.unwrap();
debug!("ALLOC EP{} {:?} {:?}", addr.index(), addr.direction(), kind);
}
pub fn on_configured(&mut self) {
self.enable_endpoints();
self.prime_endpoints();
}
fn enable_endpoints(&mut self) {
for addr in all_ep_addrs(self.ep_allocator.capacity()) {
if let Some(ep) = self.ep_allocator.endpoint_mut(addr) {
ep.enable(&self.usb);
}
}
}
fn prime_endpoints(&mut self) {
for addr in non_zero_ep_addrs(self.ep_allocator.capacity()) {
if let Some(ep) = self.ep_allocator.endpoint_mut(addr) {
if ep.is_enabled(&self.usb) && ep.address().direction() == UsbDirection::Out {
let max_packet_len = ep.max_packet_len();
ep.schedule_transfer(&self.usb, max_packet_len);
}
}
}
}
fn initialize_endpoints(&mut self) {
for addr in non_zero_ep_addrs(self.ep_allocator.capacity()) {
if let Some(ep) = self.ep_allocator.endpoint_mut(addr) {
ep.initialize(&self.usb);
}
}
}
pub fn poll(&mut self) -> PollResult {
let usbsts = ral::read_reg!(ral::usb, self.usb, USBSTS);
use ral::usb::USBSTS;
if usbsts & USBSTS::URI::mask != 0 {
ral::write_reg!(ral::usb, self.usb, USBSTS, URI: 1);
return PollResult::Reset;
}
if usbsts & USBSTS::PCI::mask != 0 {
ral::write_reg!(ral::usb, self.usb, USBSTS, PCI: 1);
self.initialize_endpoints();
}
if usbsts & USBSTS::UI::mask != 0 {
ral::write_reg!(ral::usb, self.usb, USBSTS, UI: 1);
trace!(
"{:X} {:X}",
ral::read_reg!(ral::usb, self.usb, ENDPTSETUPSTAT),
ral::read_reg!(ral::usb, self.usb, ENDPTCOMPLETE)
);
self.ep_out = ral::read_reg!(ral::usb, self.usb, ENDPTCOMPLETE, ERCE) as u16;
let ep_in_complete = ral::read_reg!(ral::usb, self.usb, ENDPTCOMPLETE, ETCE);
ral::write_reg!(ral::usb, self.usb, ENDPTCOMPLETE, ETCE: ep_in_complete);
let ep_setup = ral::read_reg!(ral::usb, self.usb, ENDPTSETUPSTAT) as u16;
PollResult::Data {
ep_out: self.ep_out,
ep_in_complete: ep_in_complete as u16,
ep_setup,
}
} else {
PollResult::None
}
}
}