devices/usb/backend/
utils.rs1use std::sync::Arc;
6use std::sync::Weak;
7
8use anyhow::Context;
9use base::error;
10use base::EventType;
11use sync::Mutex;
12use usb_util::TransferStatus;
13
14use crate::usb::backend::device::BackendDevice;
15use crate::usb::backend::device::BackendDeviceType;
16use crate::usb::backend::error::Error;
17use crate::usb::backend::error::Result;
18use crate::usb::xhci::usb_hub::UsbPort;
19use crate::usb::xhci::xhci_transfer::XhciTransferState;
20use crate::utils::EventHandler;
21use crate::utils::EventLoop;
22
23#[macro_export]
24macro_rules! multi_dispatch {
35 ($self:ident, $enum:ident, $($types:ident )+, $func:ident) => {
36 match $self {
37 $(
38 $enum::$types(device) => device.$func(),
39 )+
40 }
41 };
42 ($self:ident, $enum:ident, $($types:ident )+, $func:ident, $param:expr) => {
43 match $self {
44 $(
45 $enum::$types(device) => device.$func($param),
46 )+
47 }
48 };
49 ($self:ident, $enum:ident, $($types:ident )+, $func:ident, $param1:expr, $param2: expr) => {
50 match $self {
51 $(
52 $enum::$types(device) => device.$func($param1, $param2),
53 )+
54 }
55 };
56 ($self:ident, $enum:ident, $($types:ident )+, $func:ident, $param1:expr, $param2: expr, $param3: expr) => {
57 match $self {
58 $(
59 $enum::$types(device) => device.$func($param1, $param2, $param3),
60 )+
61 }
62 };
63}
64
65pub(crate) use multi_dispatch;
66
67pub(crate) struct UsbUtilEventHandler {
68 pub device: Arc<Mutex<BackendDeviceType>>,
69 pub event_loop: Arc<EventLoop>,
70 pub port: Mutex<Weak<UsbPort>>,
71 pub self_ref: Mutex<Option<Arc<UsbUtilEventHandler>>>,
72}
73
74impl EventHandler for UsbUtilEventHandler {
75 fn on_event(&self) -> anyhow::Result<()> {
76 let (backend_result, is_lost) = {
77 let mut device_locked = self.device.lock();
78 let res = match &mut *device_locked {
79 BackendDeviceType::HostDevice(host_device) => host_device
80 .device
81 .lock()
82 .poll_transfers()
83 .context("UsbUtilEventHandler poll_transfers failed"),
84 BackendDeviceType::FidoDevice(fido_device) => fido_device
85 .read_hidraw_file()
86 .context("FidoDeviceEventHandler failed to read hidraw device"),
87 };
88 (res, device_locked.is_lost())
89 };
90
91 let is_detached = self.port.lock().upgrade().is_none_or(|port| {
92 if is_lost || backend_result.is_err() {
93 let _ = port.detach();
94 }
95 !port.is_attached()
97 });
98
99 if is_detached {
100 self.signal_detach();
101 }
102
103 if let Err(e) = backend_result {
104 error!("usb: backend event failure: {:#}", e);
105 }
106 Ok(())
107 }
108}
109
110impl UsbUtilEventHandler {
111 pub(crate) fn new(
112 device: Arc<Mutex<BackendDeviceType>>,
113 event_loop: Arc<EventLoop>,
114 ) -> Arc<Self> {
115 Arc::new(Self {
116 device,
117 event_loop,
118 port: Mutex::new(Weak::new()),
119 self_ref: Mutex::new(None),
120 })
121 }
122
123 pub fn activate(self: &Arc<Self>, event_type: EventType, port: Weak<UsbPort>) -> Result<()> {
126 *self.port.lock() = port;
127
128 self.event_loop
129 .add_event(
130 &*self.device.lock(),
131 event_type,
132 Arc::downgrade(self) as Weak<dyn EventHandler>,
133 )
134 .map_err(Error::AddToEventLoop)?;
135
136 *self.self_ref.lock() = Some(self.clone());
137 Ok(())
138 }
139
140 pub fn signal_detach(&self) {
142 let self_arc = match self.self_ref.lock().take() {
145 Some(arc) => arc,
146 None => return, };
148
149 std::thread::spawn(move || {
150 let mut retries = 0;
151 loop {
152 let can_finalize = {
153 let mut device = self_arc.device.lock();
154 if let BackendDeviceType::HostDevice(host_device) = &mut *device {
155 let _ = host_device.device.lock().poll_transfers();
156 }
157 device.can_finalize()
158 };
159
160 if can_finalize {
161 break;
162 }
163
164 std::thread::sleep(std::time::Duration::from_millis(100));
170 retries += 1;
171
172 if retries > 300 {
178 error!("Timeout waiting for host device to release all URBs.");
179 break;
180 }
181 }
182
183 if let Err(e) = self_arc.finalize_detach() {
184 error!("failed to finalize USB detachment: {}", e);
185 }
186 });
187 }
188
189 pub(crate) fn finalize_detach(&self) -> Result<()> {
191 let mut device = self.device.lock();
192 if let BackendDeviceType::HostDevice(host_device) = &mut *device {
193 host_device.device.lock().drop_dma_buffer();
194 }
195
196 let _ = device.detach_event_handler(&self.event_loop);
198 Ok(())
199 }
200}
201
202pub fn update_transfer_state(state: &mut XhciTransferState, status: TransferStatus) -> Result<()> {
204 if status == TransferStatus::Cancelled {
205 *state = XhciTransferState::Cancelled;
206 return Ok(());
207 }
208
209 match *state {
210 XhciTransferState::Cancelling => {
211 *state = XhciTransferState::Cancelled;
212 }
213 XhciTransferState::Submitted { .. } => {
214 *state = XhciTransferState::Completed;
215 }
216 _ => {
217 error!("xhci trasfer state is invalid");
218 *state = XhciTransferState::Completed;
219 return Err(Error::BadXhciTransferState);
220 }
221 }
222 Ok(())
223}