#![allow(rustdoc::redundant_explicit_links)]
pub mod control;
pub mod descriptor;
pub mod dwc2;
pub mod ethernet;
pub mod hid;
pub mod hub;
pub mod lan7800;
pub mod lan9514;
use core::ops::ControlFlow;
use crate::mailbox::{Mailbox, PowerDeviceId};
use crate::timer::Timer;
use crate::usb::control::{clear_port_feature, probe_and_address, PORT_FEATURE_C_CONNECTION};
use crate::usb::descriptor::DeviceDescriptor;
use crate::usb::dwc2::{Channel, ControlEndpoint, Dwc2Host, TransferError};
use crate::usb::hub::Hub;
const ROOT_HUB_ADDRESS: u8 = 1;
const MAX_ADDRESS: u8 = 127;
const CLASS_HUB: u8 = 9;
const MAX_HUB_DEPTH: u8 = 4;
pub const MAX_HUBS: usize = 8;
pub const MAX_PORTS: usize = 15;
const PORT_FAILED: u8 = u8::MAX;
pub fn power_on(mailbox: &mut Mailbox) -> bool {
matches!(
mailbox.set_power_state(PowerDeviceId::UsbHcd, true),
Ok(true)
)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EnumerationError {
NotConnected,
PortNotEnabled,
MalformedDescriptor,
OutOfChannels,
OutOfAddresses,
TooManyHubs,
Transfer(TransferError),
}
impl From<TransferError> for EnumerationError {
fn from(error: TransferError) -> Self {
EnumerationError::Transfer(error)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Device {
pub port: u8,
pub hub_address: u8,
pub depth: u8,
pub endpoint: ControlEndpoint,
pub descriptor: DeviceDescriptor,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Event {
Attached(Device),
Detached {
hub_address: u8,
port: u8,
address: u8,
},
}
#[derive(Clone, Copy)]
struct HubRecord {
hub: Hub,
depth: u8,
ports: [u8; MAX_PORTS],
}
pub struct Bus<'a> {
dwc2: &'a Dwc2Host,
addresses: u128,
hubs: [Option<HubRecord>; MAX_HUBS],
fault: Option<EnumerationError>,
}
impl<'a> Bus<'a> {
pub fn new(dwc2: &'a Dwc2Host) -> Self {
Bus {
dwc2,
addresses: 0,
hubs: [None; MAX_HUBS],
fault: None,
}
}
pub fn enumerate<F>(&mut self, timer: &Timer, mut on_event: F) -> Result<(), EnumerationError>
where
F: FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
{
let dwc2 = self.dwc2;
if !dwc2.port_connected() {
return Err(EnumerationError::NotConnected);
}
dwc2.reset_port(timer);
if !dwc2.port_enabled() {
return Err(EnumerationError::PortNotEnabled);
}
self.addresses = 0;
self.hubs = [None; MAX_HUBS];
self.fault = None;
let mut channel = dwc2
.alloc_channel()
.ok_or(EnumerationError::OutOfChannels)?;
let channel = &mut channel;
let root = ControlEndpoint {
address: 0,
low_speed: dwc2.port_speed() == 2,
max_packet_size: 8,
split: None,
};
let address = self
.take_address()
.ok_or(EnumerationError::OutOfAddresses)?;
debug_assert_eq!(address, ROOT_HUB_ADDRESS);
let (hub_endpoint, _root_descriptor) = probe_and_address(channel, timer, root, address)?;
let hub = Hub::configure(channel, timer, hub_endpoint, dwc2.port_speed() == 0)?;
let index = self
.record_hub(hub, 0)
.ok_or(EnumerationError::TooManyHubs)?;
let _ = self.walk_hub(channel, timer, index, &mut on_event);
match self.fault.take() {
Some(error) => Err(error),
None => Ok(()),
}
}
pub fn poll<F>(&mut self, timer: &Timer, mut on_event: F) -> Result<(), EnumerationError>
where
F: FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
{
let dwc2 = self.dwc2;
let mut channel = dwc2
.alloc_channel()
.ok_or(EnumerationError::OutOfChannels)?;
let channel = &mut channel;
let on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()> =
&mut on_event;
for index in 0..MAX_HUBS {
let Some(record) = self.hubs[index] else {
continue;
};
if self
.sweep_hub(channel, timer, index, &record, on_event)
.is_break()
{
break;
}
}
match self.fault.take() {
Some(error) => Err(error),
None => Ok(()),
}
}
fn sweep_hub(
&mut self,
channel: &mut Channel,
timer: &Timer,
index: usize,
record: &HubRecord,
on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
) -> ControlFlow<()> {
for port in 1..=record.hub.num_ports.min(MAX_PORTS as u8) {
let Ok(status) = record.hub.port_status(channel, timer, port) else {
continue;
};
let known = self.hubs[index].map_or(0, |r| r.ports[port as usize - 1]);
let flow = match (status.connected(), known) {
(true, 0) => self.attach(channel, timer, index, port, on_event),
(true, _) => ControlFlow::Continue(()),
(false, 0) => ControlFlow::Continue(()),
(false, PORT_FAILED) => {
self.set_port(index, port, 0);
ControlFlow::Continue(())
}
(false, _) => self.detach(channel, timer, index, port, on_event),
};
if status.connected() != (known != 0) {
let _ = clear_port_feature(
channel,
timer,
record.hub.endpoint(),
port,
PORT_FEATURE_C_CONNECTION,
);
}
if flow.is_break() {
return ControlFlow::Break(());
}
}
ControlFlow::Continue(())
}
fn walk_hub(
&mut self,
channel: &mut Channel,
timer: &Timer,
index: usize,
on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
) -> ControlFlow<()> {
let Some(record) = self.hubs[index] else {
return ControlFlow::Continue(());
};
for port in 1..=record.hub.num_ports.min(MAX_PORTS as u8) {
let Ok(status) = record.hub.port_status(channel, timer, port) else {
continue;
};
if !status.connected() {
continue;
}
if self
.attach(channel, timer, index, port, on_event)
.is_break()
{
return ControlFlow::Break(());
}
}
ControlFlow::Continue(())
}
fn attach(
&mut self,
channel: &mut Channel,
timer: &Timer,
index: usize,
port: u8,
on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
) -> ControlFlow<()> {
let Some(record) = self.hubs[index] else {
return ControlFlow::Continue(());
};
let Ok(status) = record.hub.reset_port(channel, timer, port) else {
self.set_port(index, port, PORT_FAILED);
return ControlFlow::Continue(());
};
if !status.enabled() {
self.set_port(index, port, PORT_FAILED);
return ControlFlow::Continue(());
}
let Some(address) = self.take_address() else {
self.fault = Some(EnumerationError::OutOfAddresses);
return ControlFlow::Break(());
};
let probe = ControlEndpoint {
address: 0,
low_speed: status.low_speed(),
max_packet_size: 8,
split: record.hub.split_target(port, &status),
};
let Ok((endpoint, descriptor)) = probe_and_address(channel, timer, probe, address) else {
self.release_address(address);
self.set_port(index, port, PORT_FAILED);
return ControlFlow::Continue(());
};
self.set_port(index, port, address);
let device = Device {
port,
hub_address: record.hub.endpoint().address,
depth: record.depth,
endpoint,
descriptor,
};
if on_event(channel, timer, Event::Attached(device)).is_break() {
return ControlFlow::Break(());
}
if descriptor.device_class == CLASS_HUB && record.depth < MAX_HUB_DEPTH {
let Ok(hub) = Hub::configure(channel, timer, endpoint, status.high_speed()) else {
return ControlFlow::Continue(());
};
let Some(child) = self.record_hub(hub, record.depth + 1) else {
self.fault = Some(EnumerationError::TooManyHubs);
return ControlFlow::Break(());
};
return self.walk_hub(channel, timer, child, on_event);
}
ControlFlow::Continue(())
}
fn detach(
&mut self,
channel: &mut Channel,
timer: &Timer,
index: usize,
port: u8,
on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
) -> ControlFlow<()> {
let Some(record) = self.hubs[index].as_mut() else {
return ControlFlow::Continue(());
};
let address = core::mem::take(&mut record.ports[port as usize - 1]);
if address == 0 {
return ControlFlow::Continue(());
}
let hub_address = record.hub.endpoint().address;
let mut stop = self.detach_subtree(channel, timer, address, on_event);
self.release_address(address);
if on_event(
channel,
timer,
Event::Detached {
hub_address,
port,
address,
},
)
.is_break()
{
stop = ControlFlow::Break(());
}
stop
}
fn detach_subtree(
&mut self,
channel: &mut Channel,
timer: &Timer,
address: u8,
on_event: &mut dyn FnMut(&mut Channel, &Timer, Event) -> ControlFlow<()>,
) -> ControlFlow<()> {
let Some(index) = (0..MAX_HUBS)
.find(|i| self.hubs[*i].is_some_and(|record| record.hub.endpoint().address == address))
else {
return ControlFlow::Continue(());
};
let record = self.hubs[index].take();
let Some(record) = record else {
return ControlFlow::Continue(());
};
let mut stop = ControlFlow::Continue(());
for (port, &below) in record.ports.iter().enumerate() {
if below == 0 || below == PORT_FAILED {
continue;
}
if self
.detach_subtree(channel, timer, below, on_event)
.is_break()
{
stop = ControlFlow::Break(());
}
self.release_address(below);
if on_event(
channel,
timer,
Event::Detached {
hub_address: address,
port: port as u8 + 1,
address: below,
},
)
.is_break()
{
stop = ControlFlow::Break(());
}
}
stop
}
fn take_address(&mut self) -> Option<u8> {
let address = (1..=MAX_ADDRESS).find(|a| self.addresses & (1u128 << a) == 0)?;
self.addresses |= 1u128 << address;
Some(address)
}
fn release_address(&mut self, address: u8) {
if address <= MAX_ADDRESS {
self.addresses &= !(1u128 << address);
}
}
fn record_hub(&mut self, hub: Hub, depth: u8) -> Option<usize> {
let index = (0..MAX_HUBS).find(|i| self.hubs[*i].is_none())?;
self.hubs[index] = Some(HubRecord {
hub,
depth,
ports: [0; MAX_PORTS],
});
Some(index)
}
fn set_port(&mut self, index: usize, port: u8, value: u8) {
if let Some(record) = self.hubs[index].as_mut() {
record.ports[port as usize - 1] = value;
}
}
}
pub fn enumerate<F>(
dwc2: &Dwc2Host,
timer: &Timer,
mut on_device: F,
) -> Result<(), EnumerationError>
where
F: FnMut(&mut Channel, &Timer, Device) -> ControlFlow<()>,
{
Bus::new(dwc2).enumerate(timer, |channel, timer, event| match event {
Event::Attached(device) => on_device(channel, timer, device),
Event::Detached { .. } => ControlFlow::Continue(()),
})
}