1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! Interface for host bus hardware
//!
//! In order to use `usbh` on a given device, there must be a [`HostBus`] implementation specific to that device.
//!
//! This interface is still evolving, as there is only one (partially complete) implementation so far.
//!
use crate::types::{ConnectionSpeed, DeviceAddress, SetupPacket, TransferType};
use defmt::Format;
use usb_device::UsbDirection;
pub trait HostBus {
/// Reset the controller into it's initial state.
///
/// This is called once as the UsbHost is initialized, and will be called again when [`crate::UsbHost::reset`] is called.
///
/// It must do any necessary preparation needed to enable the hardware and put it into the appropriate mode to act as a host.
///
/// It must also reset any internal state related to this HostBus interface to a default configuration.
///
/// If applicable, this is also the point where all interrupts should be enabled that are necessary to generate the
/// appropriate [`Event`]s when `poll` is called.
///
/// This method must *not* enable interrupts on start-of-frame. SOF-interrupts are separately controlled by [`HostBus::interrupt_on_sof`].
fn reset_controller(&mut self);
/// Reset the bus, but keep the controller initialized.
///
/// Must cause a RESET condition on the bus.
///
/// Must not disable any interrupts previously set up, but may suspend generating SOF / keep-alive packets, requiring the host to
/// call [`HostBus::enable_sof`] after the reset is complete.
fn reset_bus(&mut self);
/// Enable sending SOF (for full-speed) or keep-alive (for low-speed) packets
///
/// This prevents the attached device from entering suspend mode.
fn enable_sof(&mut self);
/// Check if SOF packets are currently enabled
fn sof_enabled(&self) -> bool;
/// Set device address, endpoint and transfer type for an upcoming transfer
///
/// A `dev_addr` of `0` is represented as `None`.
///
/// This method is always called before a transfer is initiated. It must have effect for all future transactions (`SETUP`, `DATA`, ...),
/// until `set_recipient` is called again.
fn set_recipient(
&mut self,
dev_addr: Option<DeviceAddress>,
endpoint: u8,
transfer_type: TransferType,
);
/// Write a SETUP packet to the bus
///
/// Once the packet has been acknowledged by the device, a [`Event::TransComplete`] must be generated.
///
/// This method must not modify the buffers used for DATA transfers.
/// In particular if [`HostBus::prepare_data_out`] is called before [`HostBus::write_setup`], as soon as [`Event::TransComplete`]
/// occurs, the data buffer must be in the prepared state, and ready for a [`HostBus::write_data_out_prepared`] call.
fn write_setup(&mut self, setup: SetupPacket);
/// Write a DATA IN packet to the bus, then receive `length` bytes
///
/// Once all data has been received, a [`Event::TransComplete`] must be generated.
fn write_data_in(&mut self, length: u16, pid: bool);
/// Write a DATA OUT packet to the bus, after loading the given `data` into the output buffer
///
/// Once all data has been sent, a [`Event::TransComplete`] must be generated.
///
/// The default implementation is a wrapper around [`HostBus::prepare_data_out`] followed by [`HostBus::write_data_out_prepared`].
fn write_data_out(&mut self, data: &[u8]) {
self.prepare_data_out(data);
self.write_data_out_prepared();
}
/// Load the given `data` into the output buffer
///
/// After this method was called, a [`HostBus::write_data_out_prepared`] call should write this data.
///
/// The prepared data may be overwritten by any future call to [`HostBus::prepare_data_out`], [`HostBus::write_data_in`] or [`HostBus::write_data_out`].
///
/// In other words: the data buffer can be shared by IN and OUT transfers, since there will only ever be one of them in progress at any time.
fn prepare_data_out(&mut self, data: &[u8]);
/// Write a DATA OUT packet to the bus, assuming the buffers were already prepared
///
/// The data sent will have been passed to [`HostBus::prepare_data_out`] before this call.
///
/// Once all data has been sent, a [`Event::TransComplete`] must be generated.
fn write_data_out_prepared(&mut self);
/// Check if there is an event pending on the bus, if there is return it.
///
/// This will be called whenever application code calls [`crate::UsbHost::poll`].
fn poll(&mut self) -> Option<Event>;
unsafe fn control_buffer(&self, len: usize) -> &[u8];
fn create_interrupt_pipe(
&mut self,
device_address: DeviceAddress,
endpoint_number: u8,
direction: UsbDirection,
size: u16,
interval: u8,
) -> Option<(*mut u8, u8)>;
fn release_interrupt_pipe(&mut self, pipe_ref: u8);
fn received_len(&self) -> u16;
fn pipe_buf(&self, pipe_index: u8) -> &[u8];
fn pipe_continue(&self, pipe_index: u8);
/// Enable/disable interrupt on SOF
///
/// While enabled, the host bus should generate (call `poll` on the hsot) whenever
/// a start-of-frame is sent.
/// This is used by the enumeration process to implement wait times.
///
/// If the controller does not support SOF interrupts natively, they can be implemented
/// with a platform-specific timer.
fn interrupt_on_sof(&mut self, enable: bool);
}
#[derive(Copy, Clone, Format, PartialEq)]
pub enum Event {
/// A new device was attached, with given speed
Attached(ConnectionSpeed),
/// The device is no longer attached
Detached,
/// A control transaction (SETUP, DATA IN or DATA OUT) has completed
TransComplete,
/// Device sent a STALL. This usually means that the device does not understand our communication
Stall,
/// Device has resumed from sleep?
Resume,
/// An error has occured (details in the Error)
Error(Error),
/// Data from interrupt pipe is available to be read or written
InterruptPipe(u8),
Sof,
}
#[derive(Copy, Clone, Format, PartialEq)]
pub enum Error {
/// CRC mismatch
Crc,
/// Bit stuffing rules were not followed
BitStuffing,
/// Data was received faster than it could be processed
RxOverflow,
/// Expected data to be received, but it did not arrive in time
RxTimeout,
/// Data sequence error. Saw DATA0 when expecting DATA1 or vice versa.
DataSequence,
/// None of the above. Hardware specific error condition.
Other,
}