#![no_std]
use embed_doc_image::embed_doc_image;
pub mod bus;
pub mod driver;
pub mod types;
mod discovery;
mod enumeration;
mod transfer;
pub mod descriptor;
use bus::HostBus;
use core::num::NonZeroU8;
use defmt::Format;
use discovery::DiscoveryState;
use enumeration::EnumerationState;
use types::{DeviceAddress, SetupPacket, TransferType};
use usb_device::{
control::{Recipient, Request, RequestType},
UsbDirection,
};
const MAX_PIPES: usize = 32;
#[derive(Copy, Clone)]
enum State {
Enumeration(EnumerationState),
Discovery(DeviceAddress, DiscoveryState),
Configuring(DeviceAddress, u8),
Configured(DeviceAddress, u8),
Dormant(DeviceAddress),
}
#[derive(Copy, Clone, PartialEq)]
pub enum ControlError {
WouldBlock,
InvalidPipe,
}
#[derive(Copy, Clone, Format)]
pub enum Event {
None,
Attached(types::ConnectionSpeed),
Detached,
ControlInData(Option<PipeId>, u16),
ControlOutComplete(Option<PipeId>),
Stall,
Resume,
InterruptPipe(u8),
BusError(bus::Error),
Sof,
}
#[non_exhaustive]
pub enum PollResult {
NoDevice,
Busy,
Idle,
BusError(bus::Error),
DiscoveryError(DeviceAddress),
}
#[embed_doc_image("usb-host-phases", "doc/usb-host-phases.png")]
pub struct UsbHost<B> {
bus: B,
state: State,
active_transfer: Option<(Option<PipeId>, transfer::Transfer)>,
last_address: u8,
pipes: [Option<Pipe>; MAX_PIPES],
}
#[derive(Copy, Clone)]
enum Pipe {
Control {
dev_addr: DeviceAddress,
},
Interrupt {
dev_addr: DeviceAddress,
bus_ref: u8,
direction: UsbDirection,
size: u16,
ptr: *mut u8,
},
}
unsafe impl Send for Pipe {}
#[derive(Copy, Clone, PartialEq, Format)]
pub struct PipeId(u8);
impl<B: HostBus> UsbHost<B> {
pub fn new(mut bus: B) -> Self {
bus.reset_controller();
Self {
bus,
state: State::Enumeration(EnumerationState::WaitForDevice),
active_transfer: None,
last_address: 0,
pipes: [None; MAX_PIPES],
}
}
pub fn poll(&mut self, drivers: &mut [&mut dyn driver::Driver<B>]) -> PollResult {
let event = if let Some(event) = self.bus.poll() {
match event {
bus::Event::Attached(speed) => Event::Attached(speed),
bus::Event::Detached => Event::Detached,
bus::Event::TransComplete => {
if let Some((pipe_id, transfer)) = self.active_transfer.take() {
match transfer.stage_complete(self) {
transfer::PollResult::ControlInComplete(length) => {
Event::ControlInData(pipe_id, length)
}
transfer::PollResult::ControlOutComplete => {
Event::ControlOutComplete(pipe_id)
}
transfer::PollResult::Continue(transfer) => {
self.active_transfer = Some((pipe_id, transfer));
Event::None
}
}
} else {
panic!("BUG: received WriteComplete while no transfer was in progress")
}
}
bus::Event::Resume => {
Event::Resume
}
bus::Event::Stall => {
Event::Stall
}
bus::Event::Error(error) => Event::BusError(error),
bus::Event::InterruptPipe(buf_ref) => Event::InterruptPipe(buf_ref),
bus::Event::Sof => Event::Sof,
}
} else {
Event::None
};
match &self.state {
State::Enumeration(enumeration_state) => {
match enumeration::process_enumeration(event, *enumeration_state, self) {
EnumerationState::Assigned(speed, dev_addr) => {
for driver in drivers {
driver.attached(dev_addr, speed);
}
let discovery_state = discovery::start_discovery(dev_addr, self);
self.state = State::Discovery(dev_addr, discovery_state);
}
other => {
self.state = State::Enumeration(other);
}
};
}
State::Discovery(dev_addr, discovery_state) => {
let dev_addr = *dev_addr;
match discovery::process_discovery(event, dev_addr, *discovery_state, drivers, self)
{
DiscoveryState::Done => {
let mut chosen_config = None;
for driver in drivers {
if let Some(config) = driver.configure(dev_addr) {
chosen_config = Some(config);
break;
}
}
if let Some(config) = chosen_config {
self.set_configuration(dev_addr, None, config).ok().unwrap();
self.state = State::Configuring(dev_addr, config);
} else {
self.state = State::Dormant(dev_addr);
}
}
DiscoveryState::ParseError => {
self.state = State::Dormant(dev_addr);
return PollResult::DiscoveryError(dev_addr);
}
other => {
self.state = State::Discovery(dev_addr, other);
}
}
}
State::Configuring(dev_addr, config) => {
let dev_addr = *dev_addr;
let config = *config;
match event {
Event::ControlOutComplete(_) => {
for driver in drivers {
driver.configured(dev_addr, config, self);
}
self.state = State::Configured(dev_addr, config);
}
Event::Detached => {
for driver in drivers {
driver.detached(dev_addr);
}
self.reset();
}
_ => {}
}
}
State::Configured(dev_addr, _config) => match event {
Event::Detached => {
for driver in drivers {
driver.detached(*dev_addr);
}
self.cleanup(*dev_addr);
}
Event::ControlInData(pipe_id, len) => {
if let Some(pipe_id) = pipe_id {
let data = unsafe { self.bus.control_buffer(len as usize) };
for driver in drivers {
driver.completed_control(*dev_addr, pipe_id, Some(data));
}
}
}
Event::ControlOutComplete(pipe_id) => {
if let Some(pipe_id) = pipe_id {
for driver in drivers {
driver.completed_control(*dev_addr, pipe_id, None);
}
}
}
Event::InterruptPipe(pipe_ref) => {
let matching_pipe = self
.pipes
.iter()
.enumerate()
.find(|(_, pipe)| {
if let Some(Pipe::Interrupt { bus_ref, .. }) = pipe {
*bus_ref == pipe_ref
} else {
false
}
})
.map(|(id, pipe)| (PipeId(id as u8), pipe.unwrap()));
if let Some((
pipe_id,
Pipe::Interrupt {
dev_addr,
size,
ptr,
direction,
..
},
)) = matching_pipe
{
match direction {
UsbDirection::In => {
let buf =
unsafe { core::slice::from_raw_parts(ptr, size as usize) };
for driver in drivers {
driver.completed_in(dev_addr, pipe_id, buf);
}
}
UsbDirection::Out => {
let buf =
unsafe { core::slice::from_raw_parts_mut(ptr, size as usize) };
for driver in drivers {
driver.completed_out(dev_addr, pipe_id, buf);
}
}
}
}
self.bus.pipe_continue(pipe_ref);
}
Event::BusError(error) => return PollResult::BusError(error),
_ => {}
},
State::Dormant(dev_addr) => match event {
Event::Detached => {
for driver in drivers {
driver.detached(*dev_addr);
}
self.reset();
}
_ => {}
},
}
if let State::Enumeration(EnumerationState::WaitForDevice) = self.state {
PollResult::NoDevice
} else if self.active_transfer.is_some() {
PollResult::Busy
} else {
PollResult::Idle
}
}
pub fn reset(&mut self) {
self.bus.reset_controller();
self.state = State::Enumeration(EnumerationState::WaitForDevice);
self.active_transfer = None;
self.last_address = 0;
self.pipes = [None; MAX_PIPES];
}
fn alloc_pipe(&mut self) -> Option<(PipeId, &mut Option<Pipe>)> {
self.pipes
.iter_mut()
.enumerate()
.find(|(_, slot)| slot.is_none())
.map(|(i, slot)| (PipeId(i as u8), slot))
}
pub fn create_control_pipe(&mut self, dev_addr: DeviceAddress) -> Option<PipeId> {
self.alloc_pipe().map(|(id, slot)| {
slot.replace(Pipe::Control { dev_addr });
id
})
}
fn next_address(&mut self) -> DeviceAddress {
self.last_address = self.last_address.wrapping_add(1);
if self.last_address == 0 {
self.last_address += 1;
}
DeviceAddress(NonZeroU8::new(self.last_address).unwrap())
}
pub fn control_in(
&mut self,
dev_addr: Option<DeviceAddress>,
pipe_id: Option<PipeId>,
setup: SetupPacket,
) -> Result<(), ControlError> {
self.validate_control_pipe(dev_addr, pipe_id)?;
if self.active_transfer.is_some() {
return Err(ControlError::WouldBlock);
}
self.active_transfer = Some((pipe_id, transfer::Transfer::new_control_in(setup.length)));
self.bus.set_recipient(dev_addr, 0, TransferType::Control);
self.bus.write_setup(setup);
Ok(())
}
pub fn control_out(
&mut self,
dev_addr: Option<DeviceAddress>,
pipe_id: Option<PipeId>,
setup: SetupPacket,
data: &[u8],
) -> Result<(), ControlError> {
self.validate_control_pipe(dev_addr, pipe_id)?;
if self.active_transfer.is_some() {
return Err(ControlError::WouldBlock);
}
self.active_transfer = Some((
pipe_id,
transfer::Transfer::new_control_out(data.len() as u16),
));
self.bus.set_recipient(dev_addr, 0, TransferType::Control);
self.bus.prepare_data_out(data);
self.bus.write_setup(setup);
Ok(())
}
fn validate_control_pipe(
&self,
dev_addr: Option<DeviceAddress>,
pipe_id: Option<PipeId>,
) -> Result<(), ControlError> {
let is_valid = match (dev_addr, pipe_id) {
(None, None) | (Some(_), None) => true,
(None, Some(_)) => false,
(Some(given_dev_addr), Some(pipe_id)) => {
if let Some(Pipe::Control { dev_addr }) = self.pipes[pipe_id.0 as usize] {
dev_addr == given_dev_addr
} else {
false
}
}
};
if is_valid {
Ok(())
} else {
Err(ControlError::InvalidPipe)
}
}
pub fn get_descriptor(
&mut self,
dev_addr: Option<DeviceAddress>,
pipe_id: Option<PipeId>,
recipient: Recipient,
descriptor_type: u8,
descriptor_index: u8,
length: u16,
) -> Result<(), ControlError> {
self.control_in(
dev_addr,
pipe_id,
SetupPacket::new(
UsbDirection::In,
RequestType::Standard,
recipient,
Request::GET_DESCRIPTOR,
((descriptor_type as u16) << 8) | (descriptor_index as u16),
0,
length,
),
)
}
fn set_address(&mut self, address: DeviceAddress) -> Result<(), ControlError> {
self.control_out(
None,
None,
SetupPacket::new(
UsbDirection::Out,
RequestType::Standard,
Recipient::Device,
Request::SET_ADDRESS,
address.into(),
0,
0,
),
&[],
)
}
pub fn set_configuration(
&mut self,
dev_addr: DeviceAddress,
pipe_id: Option<PipeId>,
configuration: u8,
) -> Result<(), ControlError> {
self.control_out(
Some(dev_addr),
pipe_id,
SetupPacket::new(
UsbDirection::Out,
RequestType::Standard,
Recipient::Device,
Request::SET_CONFIGURATION,
configuration as u16,
0,
0,
),
&[],
)
}
pub fn create_interrupt_pipe(
&mut self,
dev_addr: DeviceAddress,
ep_number: u8,
direction: UsbDirection,
size: u16,
interval: u8,
) -> Option<PipeId> {
self.bus()
.create_interrupt_pipe(dev_addr, ep_number, direction, size, interval)
.and_then(|(ptr, bus_ref)| {
self.alloc_pipe().map(|(id, slot)| {
slot.replace(Pipe::Interrupt {
dev_addr,
bus_ref,
direction,
size,
ptr,
});
id
})
})
}
pub fn bus(&mut self) -> &mut B {
&mut self.bus
}
fn cleanup(&mut self, addr: DeviceAddress) {
for pipe in self.pipes.iter_mut() {
match pipe {
Some(Pipe::Control { dev_addr } | Pipe::Interrupt { dev_addr, .. })
if *dev_addr == addr =>
{
*pipe = None;
}
_ => {}
}
}
}
}