Skip to main content

android_usb_serial/drivers/
mod.rs

1//! USB serial driver implementations.
2//!
3//! Each chip family implements the [`Driver`](crate::drivers::Driver) trait. Prefer
4//! [`crate::open_port`], which calls [`create_driver`](crate::drivers::create_driver)
5//! after [`crate::ProbeTable`] selection.
6
7mod cdc_acm;
8mod ch34x;
9mod chrome_ccd;
10mod cp21xx;
11mod ftdi;
12mod gsm_modem;
13mod prolific;
14
15pub use cdc_acm::CdcAcmDriver;
16pub use ch34x::Ch34xDriver;
17pub use chrome_ccd::ChromeCcdDriver;
18pub use cp21xx::Cp21xxDriver;
19pub use ftdi::ftdi_baud_encoding;
20pub use ftdi::FtdiDriver;
21pub use gsm_modem::GsmModemDriver;
22pub use prolific::ProlificDriver;
23
24use crate::config::{FlowControl, LineConfig, PurgeKind};
25use crate::error::Result;
26use crate::probe::DriverType;
27use crate::reader::SerialReader;
28use crate::rx_filter::RxFilter;
29use crate::transport::{BulkIn, BulkOut, SharedTransport};
30
31/// Default bulk OUT timeout used by drivers.
32pub const WRITE_TIMEOUT_MS: u32 = 5000;
33
34/// Modem status lines reported by chips that support them.
35#[derive(Debug, Clone, Copy, Default)]
36pub struct ModemStatus {
37    pub cts: bool,
38    pub dsr: bool,
39    pub ri: bool,
40    pub cd: bool,
41}
42
43/// Chip-specific USB serial protocol (control transfers + bulk endpoints).
44pub trait Driver: Send {
45    fn open(&mut self, transport: &SharedTransport) -> Result<()>;
46    fn close(&mut self) -> Result<()>;
47    fn write(&mut self, data: &[u8]) -> Result<usize>;
48    fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
49    fn set_line_config(&mut self, cfg: LineConfig) -> Result<()>;
50    fn set_flow_control(&mut self, flow: FlowControl) -> Result<()>;
51    fn set_dtr(&mut self, value: bool) -> Result<()>;
52    fn set_rts(&mut self, value: bool) -> Result<()>;
53    fn set_break(&mut self, enabled: bool) -> Result<()>;
54    fn purge(&mut self, kind: PurgeKind) -> Result<()>;
55    fn modem_status(&mut self) -> Result<ModemStatus>;
56    fn bulk_in_mps(&self) -> u16;
57    fn take_bulk_in(&mut self) -> Option<Box<dyn BulkIn>>;
58    fn rx_filters(&self) -> Vec<Box<dyn RxFilter>> {
59        Vec::new()
60    }
61    fn start_reader(&mut self) -> Result<SerialReader> {
62        let bulk = self
63            .take_bulk_in()
64            .ok_or_else(|| crate::error::UsbSerialError::Io("no bulk in".into()))?;
65        Ok(SerialReader::start(
66            bulk,
67            self.bulk_in_mps(),
68            200,
69            self.rx_filters(),
70        ))
71    }
72}
73
74/// Construct an uninitialized driver for `driver_type` / `port_index`.
75pub fn create_driver(driver_type: DriverType, port_index: usize) -> Box<dyn Driver> {
76    match driver_type {
77        DriverType::CdcAcm => Box::new(CdcAcmDriver::new(port_index)),
78        DriverType::Ftdi => Box::new(FtdiDriver::new(port_index)),
79        DriverType::Cp21xx => Box::new(Cp21xxDriver::new(port_index)),
80        DriverType::Ch34x => Box::new(Ch34xDriver::new(port_index)),
81        DriverType::Prolific => Box::new(ProlificDriver::new(port_index)),
82        DriverType::GsmModem => Box::new(GsmModemDriver::new(port_index)),
83        DriverType::ChromeCcd => Box::new(ChromeCcdDriver::new(port_index)),
84    }
85}
86
87pub fn line_coding_bytes(cfg: &LineConfig) -> [u8; 7] {
88    let stop = match cfg.stop_bits {
89        crate::config::StopBits::One => 0u8,
90        crate::config::StopBits::OnePointFive => 1,
91        crate::config::StopBits::Two => 2,
92    };
93    let parity = match cfg.parity {
94        crate::config::Parity::None => 0,
95        crate::config::Parity::Odd => 1,
96        crate::config::Parity::Even => 2,
97        crate::config::Parity::Mark => 3,
98        crate::config::Parity::Space => 4,
99    };
100    let data = match cfg.data_bits {
101        crate::config::DataBits::Five => 5,
102        crate::config::DataBits::Six => 6,
103        crate::config::DataBits::Seven => 7,
104        crate::config::DataBits::Eight => 8,
105    };
106    [
107        (cfg.baud_rate & 0xff) as u8,
108        ((cfg.baud_rate >> 8) & 0xff) as u8,
109        ((cfg.baud_rate >> 16) & 0xff) as u8,
110        ((cfg.baud_rate >> 24) & 0xff) as u8,
111        stop,
112        parity,
113        data,
114    ]
115}
116
117struct EndpointPair {
118    bulk_in: Option<Box<dyn BulkIn>>,
119    bulk_out: Option<Box<dyn BulkOut>>,
120    in_ep: u8,
121    out_ep: u8,
122    mps: u16,
123}
124
125impl EndpointPair {
126    pub(crate) fn from_addresses(in_ep: u8, out_ep: u8, mps: u16) -> Self {
127        Self {
128            bulk_in: None,
129            bulk_out: None,
130            in_ep,
131            out_ep,
132            mps,
133        }
134    }
135
136    fn open(transport: &SharedTransport, iface: u8) -> Result<Self> {
137        let eps = transport.endpoints(iface);
138        let in_ep = eps
139            .iter()
140            .find(|e| e.is_bulk_in())
141            .ok_or_else(|| crate::error::UsbSerialError::ProbeFailed("no bulk in".into()))?;
142        let out_ep = eps
143            .iter()
144            .find(|e| e.is_bulk_out())
145            .ok_or_else(|| crate::error::UsbSerialError::ProbeFailed("no bulk out".into()))?;
146        Ok(Self {
147            bulk_in: None,
148            bulk_out: None,
149            in_ep: in_ep.address,
150            out_ep: out_ep.address,
151            mps: in_ep.max_packet_size,
152        })
153    }
154
155    fn ensure_out(&mut self, transport: &SharedTransport) -> Result<()> {
156        if self.bulk_out.is_none() {
157            self.bulk_out = Some(transport.open_bulk_out(self.out_ep, self.mps)?);
158        }
159        Ok(())
160    }
161
162    fn ensure_in(&mut self, transport: &SharedTransport) -> Result<()> {
163        if self.bulk_in.is_none() {
164            self.bulk_in = Some(transport.open_bulk_in(self.in_ep, self.mps)?);
165        }
166        Ok(())
167    }
168
169    fn write(&mut self, transport: &SharedTransport, data: &[u8]) -> Result<usize> {
170        // Only claim OUT — IN may already be owned by SerialReader after take_in().
171        // Opening IN again hits nusb "endpoint already in use".
172        self.ensure_out(transport)?;
173        self.bulk_out
174            .as_mut()
175            .unwrap()
176            .write(data, WRITE_TIMEOUT_MS)
177    }
178
179    fn take_in(&mut self, transport: &SharedTransport) -> Option<Box<dyn BulkIn>> {
180        self.ensure_in(transport).ok()?;
181        self.bulk_in.take()
182    }
183}