Skip to main content

crab_usb/
host.rs

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
17/// USB 主机控制器
18pub struct USBHost {
19    pub(crate) backend: Box<dyn BackendOp>,
20    pub(crate) initialized: bool,
21}
22
23impl USBHost {
24    /// 初始化主机控制器
25    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    /// 处理事件
89    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}