1use alloc::boxed::Box;
2#[cfg(any(kmod, umod))]
3use alloc::vec::Vec;
4
5#[cfg(kmod)]
6pub use super::backend::kmod::*;
7#[cfg(umod)]
8pub use super::backend::umod::*;
9pub use crate::device::{
10 Device, DeviceInfo, HubDeviceInfo, InterfaceSession, ProbeChanges, ProbedDevice,
11};
12use crate::{
13 backend::{BackendOp, ty::*},
14 err::Result,
15};
16
17pub struct USBHost {
19 pub(crate) backend: Box<dyn BackendOp>,
20 pub(crate) initialized: bool,
21}
22
23impl USBHost {
24 pub async fn init(&mut self) -> Result<()> {
26 if self.initialized {
27 return Ok(());
28 }
29 self.backend.init().await?;
30 self.initialized = true;
31 Ok(())
32 }
33
34 #[cfg(any(kmod, umod))]
35 pub async fn probe_devices(&mut self) -> Result<ProbeChanges> {
36 let changes = self.backend.device_list().await?;
37 let mut connected = Vec::new();
38 for dev in changes.connected {
39 let dev_info = match dev {
40 ProbedDeviceInfoOp::Device(inner) => ProbedDevice::Device(DeviceInfo { inner }),
41 ProbedDeviceInfoOp::Hub(inner) => ProbedDevice::Hub(HubDeviceInfo { inner }),
42 };
43 connected.push(dev_info);
44 }
45 Ok(ProbeChanges {
46 connected,
47 disconnected: changes.disconnected,
48 })
49 }
50
51 #[cfg(kmod)]
52 pub fn create_event_handler(&mut self) -> EventHandler {
53 let handler = self.backend.create_event_handler();
54 EventHandler { handler }
55 }
56
57 pub fn enable_irq(&mut self) -> Result {
58 self.backend.enable_irq()
59 }
60
61 pub fn disable_irq(&mut self) -> Result {
62 self.backend.disable_irq()
63 }
64
65 #[cfg(kmod)]
66 pub fn dwc2_transfer_stats(&self) -> Option<Dwc2TransferStats> {
67 self.backend.dwc2_transfer_stats()
68 }
69
70 #[cfg(kmod)]
71 pub fn reset_dwc2_transfer_stats(&self) {
72 self.backend.reset_dwc2_transfer_stats();
73 }
74
75 pub async fn open_device(&mut self, dev: &DeviceInfo) -> Result<Device> {
76 let device = self.backend.open_device(dev.inner.as_ref()).await?;
77 let mut device: Device = device.into();
78 device.init().await?;
79 Ok(device)
80 }
81}
82
83pub struct EventHandler {
84 handler: Box<dyn EventHandlerOp>,
85}
86
87impl EventHandler {
88 pub fn handle_event(&self) -> Event {
90 self.handler.handle_event()
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use alloc::sync::Arc;
97 use core::{
98 future::Future,
99 pin::Pin,
100 ptr,
101 sync::atomic::{AtomicUsize, Ordering},
102 task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
103 };
104
105 use futures::{FutureExt, future::LocalBoxFuture};
106 use usb_if::err::USBError;
107
108 use super::*;
109 use crate::backend::{
110 BackendOp,
111 ty::{DeviceOp, ProbeChangesOp},
112 };
113
114 #[derive(Default)]
115 struct IrqCalls {
116 init: AtomicUsize,
117 enable: AtomicUsize,
118 disable: AtomicUsize,
119 }
120
121 struct TestBackend {
122 calls: Arc<IrqCalls>,
123 }
124
125 impl BackendOp for TestBackend {
126 fn init<'a>(&'a mut self) -> futures::future::BoxFuture<'a, crate::err::Result> {
127 self.calls.init.fetch_add(1, Ordering::Relaxed);
128 async { Ok(()) }.boxed()
129 }
130
131 #[cfg(any(kmod, umod))]
132 fn device_list<'a>(
133 &'a mut self,
134 ) -> futures::future::BoxFuture<'a, crate::err::Result<ProbeChangesOp>> {
135 async {
136 Ok(ProbeChangesOp {
137 connected: Vec::new(),
138 disconnected: Vec::new(),
139 })
140 }
141 .boxed()
142 }
143
144 fn open_device<'a>(
145 &'a mut self,
146 _dev: &'a dyn crate::backend::ty::DeviceInfoOp,
147 ) -> LocalBoxFuture<'a, crate::err::Result<Box<dyn DeviceOp>>> {
148 async { Err(USBError::NotSupported) }.boxed_local()
149 }
150
151 #[cfg(kmod)]
152 fn create_event_handler(&mut self) -> Box<dyn crate::backend::ty::EventHandlerOp> {
153 Box::new(TestEventHandler)
154 }
155
156 fn enable_irq(&mut self) -> crate::err::Result {
157 self.calls.enable.fetch_add(1, Ordering::Relaxed);
158 Ok(())
159 }
160
161 fn disable_irq(&mut self) -> crate::err::Result {
162 self.calls.disable.fetch_add(1, Ordering::Relaxed);
163 Ok(())
164 }
165 }
166
167 #[cfg(kmod)]
168 struct TestEventHandler;
169
170 #[cfg(kmod)]
171 impl crate::backend::ty::EventHandlerOp for TestEventHandler {
172 fn handle_event(&self) -> crate::backend::ty::Event {
173 crate::backend::ty::Event::Nothing
174 }
175 }
176
177 fn block_on_ready<F: Future>(mut future: F) -> F::Output {
178 let waker = noop_waker();
179 let mut context = Context::from_waker(&waker);
180 match unsafe { Pin::new_unchecked(&mut future) }.poll(&mut context) {
181 Poll::Ready(output) => output,
182 Poll::Pending => panic!("test future unexpectedly pending"),
183 }
184 }
185
186 fn noop_waker() -> Waker {
187 unsafe fn clone(_: *const ()) -> RawWaker {
188 RawWaker::new(ptr::null(), &VTABLE)
189 }
190 unsafe fn wake(_: *const ()) {}
191 unsafe fn wake_by_ref(_: *const ()) {}
192 unsafe fn drop(_: *const ()) {}
193
194 static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
195
196 unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &VTABLE)) }
197 }
198
199 #[test]
200 fn host_irq_control_forwards_to_backend() {
201 let calls = Arc::new(IrqCalls::default());
202 let mut host = USBHost {
203 backend: Box::new(TestBackend {
204 calls: calls.clone(),
205 }),
206 initialized: false,
207 };
208
209 host.enable_irq().unwrap();
210 host.disable_irq().unwrap();
211
212 assert_eq!(calls.enable.load(Ordering::Relaxed), 1);
213 assert_eq!(calls.disable.load(Ordering::Relaxed), 1);
214 }
215
216 #[test]
217 fn host_init_is_idempotent() {
218 let calls = Arc::new(IrqCalls::default());
219 let mut host = USBHost {
220 backend: Box::new(TestBackend {
221 calls: calls.clone(),
222 }),
223 initialized: false,
224 };
225
226 block_on_ready(host.init()).unwrap();
227 block_on_ready(host.init()).unwrap();
228
229 assert_eq!(calls.init.load(Ordering::Relaxed), 1);
230 }
231}