android_usb_serial/drivers/
cdc_acm.rs1use super::{line_coding_bytes, Driver, EndpointPair, ModemStatus, WRITE_TIMEOUT_MS};
4use crate::config::{FlowControl, LineConfig, PurgeKind};
5use crate::error::{ReadOutcome, Result, UsbSerialError};
6use crate::reader::SerialReader;
7use crate::transport::{
8 BulkIn, ControlRequest, SharedTransport, USB_RECIP_INTERFACE, USB_TYPE_CLASS,
9};
10use std::sync::atomic::{AtomicBool, AtomicU16, Ordering};
11use std::sync::{Arc, Mutex};
12use std::thread::{self, JoinHandle};
13
14const USB_SUBCLASS_ACM: u8 = 2;
15const SET_LINE_CODING: u8 = 0x20;
16const SET_CONTROL_LINE_STATE: u8 = 0x22;
17const SEND_BREAK: u8 = 0x23;
18const NOTIFICATION_REQUEST_TYPE: u8 = 0xa1;
19const SERIAL_STATE_NOTIFICATION: u8 = 0x20;
20const SERIAL_STATE_NOTIFICATION_SIZE: usize = 10;
21const SERIAL_STATE_RX_CARRIER: u16 = 1 << 0;
22const SERIAL_STATE_TX_CARRIER: u16 = 1 << 1;
23const SERIAL_STATE_RING_SIGNAL: u16 = 1 << 3;
24const NOTIFICATION_READ_TIMEOUT_MS: u32 = 200;
25
26struct CdcNotificationReader {
27 state: Arc<AtomicU16>,
28 error: Arc<Mutex<Option<String>>>,
29 stop: Arc<AtomicBool>,
30 thread: Option<JoinHandle<()>>,
31}
32
33impl CdcNotificationReader {
34 fn start(mut endpoint: Box<dyn BulkIn>, max_packet_size: u16, control_index: u8) -> Self {
35 let state = Arc::new(AtomicU16::new(0));
36 let error = Arc::new(Mutex::new(None));
37 let stop = Arc::new(AtomicBool::new(false));
38 let thread_state = Arc::clone(&state);
39 let thread_error = Arc::clone(&error);
40 let thread_stop = Arc::clone(&stop);
41 let buffer_size = usize::from(max_packet_size).max(SERIAL_STATE_NOTIFICATION_SIZE);
42
43 let thread = thread::spawn(move || {
44 let mut buffer = vec![0; buffer_size];
45 while !thread_stop.load(Ordering::Relaxed) {
46 match endpoint.read(&mut buffer, NOTIFICATION_READ_TIMEOUT_MS) {
47 Ok(ReadOutcome::Data(data)) if !data.is_empty() => {
48 if let Some(serial_state) =
51 parse_serial_state_notification(&data, control_index)
52 {
53 thread_state.store(serial_state, Ordering::Relaxed);
54 }
55 }
56 Ok(ReadOutcome::TimedOut) | Ok(ReadOutcome::Data(_)) => {}
57 Ok(ReadOutcome::Cancelled) => break,
58 Err(error) => {
59 if !thread_stop.load(Ordering::Relaxed) {
60 *thread_error.lock().unwrap() = Some(error.to_string());
61 }
62 break;
63 }
64 }
65 }
66 });
67
68 Self {
69 state,
70 error,
71 stop,
72 thread: Some(thread),
73 }
74 }
75
76 fn modem_status(&self) -> Result<ModemStatus> {
77 if let Some(error) = self.error.lock().unwrap().take() {
78 return Err(UsbSerialError::Io(error));
79 }
80
81 let state = self.state.load(Ordering::Relaxed);
82 Ok(ModemStatus {
83 cts: false,
84 dsr: state & SERIAL_STATE_TX_CARRIER != 0,
85 ri: state & SERIAL_STATE_RING_SIGNAL != 0,
86 cd: state & SERIAL_STATE_RX_CARRIER != 0,
87 })
88 }
89
90 fn stop(&mut self) {
91 self.stop.store(true, Ordering::Relaxed);
92 if let Some(thread) = self.thread.take() {
93 let _ = thread.join();
94 }
95 }
96}
97
98impl Drop for CdcNotificationReader {
99 fn drop(&mut self) {
100 self.stop();
101 }
102}
103
104fn parse_serial_state_notification(data: &[u8], control_index: u8) -> Option<u16> {
107 if data.len() < SERIAL_STATE_NOTIFICATION_SIZE {
108 return None;
109 }
110 if data[0] != NOTIFICATION_REQUEST_TYPE || data[1] != SERIAL_STATE_NOTIFICATION {
111 return None;
112 }
113 let index = u16::from_le_bytes([data[4], data[5]]);
114 if index != u16::from(control_index) {
115 return None;
116 }
117 let payload_size = usize::from(u16::from_le_bytes([data[6], data[7]]));
118 if payload_size < 2 || data.len() < 8 + 2 {
120 return None;
121 }
122 Some(u16::from_le_bytes([data[8], data[9]]))
123}
124
125pub struct CdcAcmDriver {
126 port_index: usize,
127 control_index: u8,
128 control_iface: u8,
129 data_iface: u8,
130 dtr: bool,
131 rts: bool,
132 endpoints: Option<EndpointPair>,
133 transport: Option<SharedTransport>,
134 control_claimed: bool,
135 data_claimed: bool,
136 reader: Option<SerialReader>,
137 notification_reader: Option<CdcNotificationReader>,
138}
139
140impl CdcAcmDriver {
141 pub fn new(port_index: usize) -> Self {
142 Self {
143 port_index,
144 control_index: 0,
145 control_iface: 0,
146 data_iface: 0,
147 dtr: false,
148 rts: false,
149 endpoints: None,
150 transport: None,
151 control_claimed: false,
152 data_claimed: false,
153 reader: None,
154 notification_reader: None,
155 }
156 }
157
158 fn acm_control(&self, request: u8, value: u16, data: Vec<u8>) -> Result<()> {
159 let transport = self.transport.as_ref().unwrap();
160 let req = ControlRequest {
161 request_type: USB_TYPE_CLASS | USB_RECIP_INTERFACE,
162 request,
163 value,
164 index: self.control_index as u16,
165 data,
166 timeout_ms: WRITE_TIMEOUT_MS,
167 };
168 transport.control_out(&req)?;
169 Ok(())
170 }
171
172 fn resolve_interfaces(&mut self, transport: &SharedTransport) -> Result<()> {
173 let ifaces = transport.interfaces();
174 let desc = transport.raw_device_descriptor();
175 let is_iad = desc.len() >= 7 && desc[4] == 0xEF && desc[5] == 0x02 && desc[6] == 0x01;
176 if is_iad {
177 if let Some((ctrl, data)) = resolve_iad_pair(transport, self.port_index) {
178 self.control_iface = ctrl;
179 self.data_iface = data;
180 self.control_index = ctrl;
181 return Ok(());
182 }
183 }
184 let comm: Vec<u8> = ifaces
185 .iter()
186 .filter(|i| i.class == 2 && i.subclass == USB_SUBCLASS_ACM)
187 .map(|i| i.id)
188 .collect();
189 let data: Vec<u8> = ifaces
190 .iter()
191 .filter(|i| i.class == 10)
192 .map(|i| i.id)
193 .collect();
194 if comm.is_empty() && data.is_empty() {
195 if let Some(iface) = ifaces.first() {
197 self.control_iface = iface.id;
198 self.data_iface = iface.id;
199 self.control_index = iface.id;
200 return Ok(());
201 }
202 return Err(UsbSerialError::ProbeFailed("no CDC interfaces".into()));
203 }
204 if comm.is_empty() {
205 return Err(UsbSerialError::ProbeFailed("no CDC comm interfaces".into()));
206 }
207 let idx = self.port_index.min(comm.len() - 1);
208 self.control_iface = comm[idx];
209 self.data_iface = data.get(idx).copied().unwrap_or(comm[idx]);
210 self.control_index = self.control_iface;
211 Ok(())
212 }
213}
214
215fn resolve_iad_pair(transport: &SharedTransport, port_index: usize) -> Option<(u8, u8)> {
216 let raw = transport.raw_descriptors();
217 let mut iad_ports: Vec<(u8, u8)> = Vec::new();
218 let mut pos = 0usize;
219 while pos + 2 <= raw.len() {
220 let len = raw[pos] as usize;
221 if len < 2 || pos + len > raw.len() {
222 break;
223 }
224 if raw[pos + 1] == 0x0B && len >= 8 && raw[pos + 4] == 2 && raw[pos + 5] == 2 {
225 let first = raw[pos + 2];
226 let count = raw[pos + 3];
227 if count >= 2 {
228 iad_ports.push((first, first + 1));
229 }
230 }
231 pos += len;
232 }
233 iad_ports.get(port_index).copied()
234}
235
236impl Driver for CdcAcmDriver {
237 fn open(&mut self, transport: &SharedTransport) -> Result<()> {
238 self.resolve_interfaces(transport)?;
239 self.transport = Some(transport.clone());
240
241 let result = (|| {
242 transport.claim_interface(self.control_iface)?;
243 self.control_claimed = true;
244 if self.data_iface != self.control_iface {
245 transport.claim_interface(self.data_iface)?;
246 self.data_claimed = true;
247 }
248
249 if let Some(endpoint) = transport
250 .endpoints(self.control_iface)
251 .into_iter()
252 .find(|endpoint| endpoint.is_interrupt_in())
253 {
254 let interrupt_in =
255 transport.open_interrupt_in(endpoint.address, endpoint.max_packet_size)?;
256 self.notification_reader = Some(CdcNotificationReader::start(
257 interrupt_in,
258 endpoint.max_packet_size,
259 self.control_index,
260 ));
261 }
262
263 self.endpoints = Some(EndpointPair::open(transport, self.data_iface)?);
264 Ok(())
265 })();
266
267 if result.is_err() {
268 let _ = self.close();
269 }
270 result
271 }
272
273 fn close(&mut self) -> Result<()> {
274 if let Some(mut r) = self.reader.take() {
275 r.stop();
276 }
277 if let Some(mut r) = self.notification_reader.take() {
278 r.stop();
279 }
280 if let Some(t) = &self.transport {
281 if self.data_claimed {
282 self.data_claimed = false;
283 let _ = t.release_interface(self.data_iface);
284 }
285 if self.control_claimed {
286 self.control_claimed = false;
287 let _ = t.release_interface(self.control_iface);
288 }
289 }
290 self.endpoints = None;
291 Ok(())
292 }
293
294 fn write(&mut self, data: &[u8]) -> Result<usize> {
295 let transport = self.transport.as_ref().unwrap();
296 self.endpoints.as_mut().unwrap().write(transport, data)
297 }
298
299 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
300 if let Some(reader) = &mut self.reader {
301 return reader.try_read(buf);
302 }
303 Ok(0)
304 }
305
306 fn set_line_config(&mut self, cfg: LineConfig) -> Result<()> {
307 self.acm_control(SET_LINE_CODING, 0, line_coding_bytes(&cfg).to_vec())
308 }
309
310 fn set_flow_control(&mut self, flow: FlowControl) -> Result<()> {
311 if flow == FlowControl::None {
312 Ok(())
313 } else {
314 Err(UsbSerialError::Unsupported("flow control".into()))
315 }
316 }
317
318 fn set_dtr(&mut self, value: bool) -> Result<()> {
319 self.dtr = value;
320 let v = (self.rts as u16) << 1 | (self.dtr as u16);
321 self.acm_control(SET_CONTROL_LINE_STATE, v, vec![])
322 }
323
324 fn set_rts(&mut self, value: bool) -> Result<()> {
325 self.rts = value;
326 let v = (self.rts as u16) << 1 | (self.dtr as u16);
327 self.acm_control(SET_CONTROL_LINE_STATE, v, vec![])
328 }
329
330 fn set_break(&mut self, enabled: bool) -> Result<()> {
331 self.acm_control(SEND_BREAK, if enabled { 0xffff } else { 0 }, vec![])
332 }
333
334 fn purge(&mut self, _kind: PurgeKind) -> Result<()> {
335 Ok(())
336 }
337
338 fn modem_status(&mut self) -> Result<ModemStatus> {
339 self.notification_reader
340 .as_ref()
341 .map(CdcNotificationReader::modem_status)
342 .unwrap_or_else(|| Ok(ModemStatus::default()))
343 }
344
345 fn bulk_in_mps(&self) -> u16 {
346 self.endpoints.as_ref().map(|e| e.mps).unwrap_or(64)
347 }
348
349 fn take_bulk_in(&mut self) -> Option<Box<dyn crate::transport::BulkIn>> {
350 let transport = self.transport.as_ref()?;
351 self.endpoints.as_mut()?.take_in(transport)
352 }
353}