Skip to main content

android_usb_serial/drivers/
cp21xx.rs

1//! Silicon Labs CP21xx driver.
2
3use super::{Driver, EndpointPair, ModemStatus, WRITE_TIMEOUT_MS};
4use crate::config::{
5    DataBits, FlowControl, LineConfig, Parity, PurgeKind, StopBits, CHAR_XOFF, CHAR_XON,
6};
7use crate::error::{Result, UsbSerialError};
8use crate::reader::SerialReader;
9use crate::transport::{ControlRequest, SharedTransport};
10
11const REQTYPE_HOST_TO_DEVICE: u8 = 0x41;
12const REQTYPE_DEVICE_TO_HOST: u8 = 0xC1;
13
14const SILABSER_IFC_ENABLE_REQUEST_CODE: u8 = 0x00;
15const SILABSER_SET_LINE_CTL_REQUEST_CODE: u8 = 0x03;
16const SILABSER_SET_BREAK_REQUEST_CODE: u8 = 0x05;
17const SILABSER_SET_MHS_REQUEST_CODE: u8 = 0x07;
18const SILABSER_GET_MDMSTS_REQUEST_CODE: u8 = 0x08;
19const SILABSER_SET_XON_REQUEST_CODE: u8 = 0x09;
20const SILABSER_SET_XOFF_REQUEST_CODE: u8 = 0x0A;
21const SILABSER_FLUSH_REQUEST_CODE: u8 = 0x12;
22const SILABSER_SET_FLOW_REQUEST_CODE: u8 = 0x13;
23const SILABSER_SET_CHARS_REQUEST_CODE: u8 = 0x19;
24const SILABSER_SET_BAUDRATE_REQUEST_CODE: u8 = 0x1E;
25
26const UART_ENABLE: u16 = 0x0001;
27const UART_DISABLE: u16 = 0x0000;
28
29const DTR_ENABLE: u16 = 0x0101;
30const DTR_DISABLE: u16 = 0x0100;
31const RTS_ENABLE: u16 = 0x0202;
32const RTS_DISABLE: u16 = 0x0200;
33
34const STATUS_CTS: u8 = 0x10;
35const STATUS_DSR: u8 = 0x20;
36const STATUS_RI: u8 = 0x40;
37const STATUS_CD: u8 = 0x80;
38
39pub struct Cp21xxDriver {
40    port_index: usize,
41    iface: u8,
42    dtr: bool,
43    rts: bool,
44    is_restricted_port: bool,
45    endpoints: Option<EndpointPair>,
46    transport: Option<SharedTransport>,
47    reader: Option<SerialReader>,
48}
49
50impl Cp21xxDriver {
51    pub fn new(port_index: usize) -> Self {
52        Self {
53            port_index,
54            iface: port_index as u8,
55            dtr: false,
56            rts: false,
57            is_restricted_port: false,
58            endpoints: None,
59            transport: None,
60            reader: None,
61        }
62    }
63
64    fn cfg_out(&self, request: u8, value: u16) -> Result<()> {
65        self.transport
66            .as_ref()
67            .unwrap()
68            .control_out(&ControlRequest {
69                request_type: REQTYPE_HOST_TO_DEVICE,
70                request,
71                value,
72                index: self.port_index as u16,
73                data: vec![],
74                timeout_ms: WRITE_TIMEOUT_MS,
75            })?;
76        Ok(())
77    }
78
79    fn cfg_out_data(&self, request: u8, value: u16, data: Vec<u8>) -> Result<()> {
80        self.transport
81            .as_ref()
82            .unwrap()
83            .control_out(&ControlRequest {
84                request_type: REQTYPE_HOST_TO_DEVICE,
85                request,
86                value,
87                index: self.port_index as u16,
88                data,
89                timeout_ms: WRITE_TIMEOUT_MS,
90            })?;
91        Ok(())
92    }
93
94    fn cfg_in(&self, request: u8, value: u16, length: usize) -> Result<Vec<u8>> {
95        self.transport
96            .as_ref()
97            .unwrap()
98            .control_in(&ControlRequest {
99                request_type: REQTYPE_DEVICE_TO_HOST,
100                request,
101                value,
102                index: self.port_index as u16,
103                data: vec![0; length],
104                timeout_ms: WRITE_TIMEOUT_MS,
105            })
106    }
107
108    fn set_xon(&self, value: bool) -> Result<()> {
109        self.cfg_out(
110            if value {
111                SILABSER_SET_XON_REQUEST_CODE
112            } else {
113                SILABSER_SET_XOFF_REQUEST_CODE
114            },
115            0,
116        )
117    }
118}
119
120impl Driver for Cp21xxDriver {
121    fn open(&mut self, transport: &SharedTransport) -> Result<()> {
122        self.transport = Some(transport.clone());
123        let iface_count = transport.interfaces().len();
124        if self.port_index >= iface_count {
125            return Err(UsbSerialError::Io(format!(
126                "unknown port number {}",
127                self.port_index
128            )));
129        }
130        self.is_restricted_port = iface_count == 2 && self.port_index == 1;
131        self.iface = self.port_index as u8;
132        transport.claim_interface(self.iface)?;
133        self.endpoints = Some(EndpointPair::open(transport, self.iface)?);
134        self.cfg_out(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE)?;
135        self.cfg_out(
136            SILABSER_SET_MHS_REQUEST_CODE,
137            (if self.dtr { DTR_ENABLE } else { DTR_DISABLE })
138                | (if self.rts { RTS_ENABLE } else { RTS_DISABLE }),
139        )?;
140        self.set_flow_control(FlowControl::None)?;
141        Ok(())
142    }
143
144    fn close(&mut self) -> Result<()> {
145        if let Some(mut r) = self.reader.take() {
146            r.stop();
147        }
148        let _ = self.cfg_out(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
149        if let Some(t) = &self.transport {
150            let _ = t.release_interface(self.iface);
151        }
152        self.endpoints = None;
153        Ok(())
154    }
155
156    fn write(&mut self, data: &[u8]) -> Result<usize> {
157        let t = self.transport.as_ref().unwrap();
158        self.endpoints.as_mut().unwrap().write(t, data)
159    }
160
161    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
162        if let Some(reader) = &mut self.reader {
163            return reader.try_read(buf);
164        }
165        Ok(0)
166    }
167
168    fn set_line_config(&mut self, cfg: LineConfig) -> Result<()> {
169        if cfg.baud_rate == 0 {
170            return Err(UsbSerialError::Unsupported("invalid baud rate".into()));
171        }
172        self.cfg_out_data(
173            SILABSER_SET_BAUDRATE_REQUEST_CODE,
174            0,
175            vec![
176                (cfg.baud_rate & 0xff) as u8,
177                ((cfg.baud_rate >> 8) & 0xff) as u8,
178                ((cfg.baud_rate >> 16) & 0xff) as u8,
179                ((cfg.baud_rate >> 24) & 0xff) as u8,
180            ],
181        )?;
182
183        let mut bits = 0u16;
184        match cfg.data_bits {
185            DataBits::Five => {
186                if self.is_restricted_port {
187                    return Err(UsbSerialError::Unsupported("data bits 5".into()));
188                }
189                bits |= 0x0500;
190            }
191            DataBits::Six => {
192                if self.is_restricted_port {
193                    return Err(UsbSerialError::Unsupported("data bits 6".into()));
194                }
195                bits |= 0x0600;
196            }
197            DataBits::Seven => {
198                if self.is_restricted_port {
199                    return Err(UsbSerialError::Unsupported("data bits 7".into()));
200                }
201                bits |= 0x0700;
202            }
203            DataBits::Eight => bits |= 0x0800,
204        };
205        match cfg.parity {
206            Parity::None => {}
207            Parity::Odd => bits |= 0x0010,
208            Parity::Even => bits |= 0x0020,
209            Parity::Mark => {
210                if self.is_restricted_port {
211                    return Err(UsbSerialError::Unsupported("parity mark".into()));
212                }
213                bits |= 0x0030;
214            }
215            Parity::Space => {
216                if self.is_restricted_port {
217                    return Err(UsbSerialError::Unsupported("parity space".into()));
218                }
219                bits |= 0x0040;
220            }
221        }
222        match cfg.stop_bits {
223            StopBits::One => {}
224            StopBits::OnePointFive => {
225                return Err(UsbSerialError::Unsupported("stop bits 1.5".into()));
226            }
227            StopBits::Two => {
228                if self.is_restricted_port {
229                    return Err(UsbSerialError::Unsupported("stop bits 2".into()));
230                }
231                bits |= 2;
232            }
233        }
234        self.cfg_out(SILABSER_SET_LINE_CTL_REQUEST_CODE, bits)
235    }
236
237    fn set_flow_control(&mut self, flow: FlowControl) -> Result<()> {
238        if flow == FlowControl::XonXoffInline {
239            return Err(UsbSerialError::Unsupported("xon/xoff inline".into()));
240        }
241
242        let mut data = vec![0u8; 16];
243        if flow == FlowControl::RtsCts {
244            data[4] |= 0b1000_0000;
245            data[0] |= 0b0000_1000;
246        } else if self.rts {
247            data[4] |= 0b0100_0000;
248        }
249        if flow == FlowControl::DtrDsr {
250            data[0] |= 0b0000_0010;
251            data[0] |= 0b0001_0000;
252        } else if self.dtr {
253            data[0] |= 0b0000_0001;
254        }
255        if flow == FlowControl::XonXoff {
256            self.cfg_out_data(
257                SILABSER_SET_CHARS_REQUEST_CODE,
258                0,
259                vec![0, 0, 0, 0, CHAR_XON, CHAR_XOFF],
260            )?;
261            data[4] |= 0b0000_0011;
262            data[7] |= 0b1000_0000;
263            data[8] = 128;
264            data[12] = 128;
265        }
266        self.cfg_out_data(SILABSER_SET_FLOW_REQUEST_CODE, 0, data)?;
267        if flow == FlowControl::XonXoff {
268            self.set_xon(true)?;
269        }
270        Ok(())
271    }
272
273    fn set_dtr(&mut self, value: bool) -> Result<()> {
274        self.dtr = value;
275        self.cfg_out(
276            SILABSER_SET_MHS_REQUEST_CODE,
277            if value { DTR_ENABLE } else { DTR_DISABLE },
278        )
279    }
280
281    fn set_rts(&mut self, value: bool) -> Result<()> {
282        self.rts = value;
283        self.cfg_out(
284            SILABSER_SET_MHS_REQUEST_CODE,
285            if value { RTS_ENABLE } else { RTS_DISABLE },
286        )
287    }
288
289    fn set_break(&mut self, enabled: bool) -> Result<()> {
290        self.cfg_out(SILABSER_SET_BREAK_REQUEST_CODE, if enabled { 1 } else { 0 })
291    }
292
293    fn purge(&mut self, kind: PurgeKind) -> Result<()> {
294        let v = match kind {
295            PurgeKind::Rx => 0x0005,
296            PurgeKind::Tx => 0x000a,
297            PurgeKind::Both => 0x000f,
298        };
299        self.cfg_out(SILABSER_FLUSH_REQUEST_CODE, v)
300    }
301
302    fn modem_status(&mut self) -> Result<ModemStatus> {
303        let buf = self.cfg_in(SILABSER_GET_MDMSTS_REQUEST_CODE, 0, 1)?;
304        let status = buf[0];
305        Ok(ModemStatus {
306            cts: (status & STATUS_CTS) != 0,
307            dsr: (status & STATUS_DSR) != 0,
308            ri: (status & STATUS_RI) != 0,
309            cd: (status & STATUS_CD) != 0,
310        })
311    }
312
313    fn bulk_in_mps(&self) -> u16 {
314        self.endpoints.as_ref().map(|e| e.mps).unwrap_or(64)
315    }
316
317    fn take_bulk_in(&mut self) -> Option<Box<dyn crate::transport::BulkIn>> {
318        let transport = self.transport.as_ref()?;
319        self.endpoints.as_mut()?.take_in(transport)
320    }
321}