1use crate::transport::InterfaceInfo;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum DriverType {
11 CdcAcm,
12 Cp21xx,
13 Ftdi,
14 Prolific,
15 Ch34x,
16 GsmModem,
17 ChromeCcd,
18}
19
20#[derive(Debug, Clone)]
22pub struct ProbeEntry {
23 pub vendor_id: u16,
24 pub product_id: u16,
25 pub driver: DriverType,
26}
27
28#[derive(Debug, Clone, Default)]
30pub struct ProbeTable {
31 entries: Vec<ProbeEntry>,
32}
33
34impl ProbeTable {
35 pub fn default_table() -> Self {
37 let mut table = Self::default();
38 table.add_product(0x0403, 0x6001, DriverType::Ftdi);
40 table.add_product(0x0403, 0x6010, DriverType::Ftdi);
41 table.add_product(0x0403, 0x6011, DriverType::Ftdi);
42 table.add_product(0x0403, 0x6014, DriverType::Ftdi);
43 table.add_product(0x0403, 0x6015, DriverType::Ftdi);
44 table.add_product(0x10C4, 0xEA60, DriverType::Cp21xx);
45 table.add_product(0x10C4, 0xEA70, DriverType::Cp21xx);
46 table.add_product(0x10C4, 0xEA71, DriverType::Cp21xx);
47 table.add_product(0x067B, 0x2303, DriverType::Prolific);
48 table.add_product(0x067B, 0x23A3, DriverType::Prolific);
49 table.add_product(0x067B, 0x23B3, DriverType::Prolific);
50 table.add_product(0x067B, 0x23C3, DriverType::Prolific);
51 table.add_product(0x067B, 0x23D3, DriverType::Prolific);
52 table.add_product(0x067B, 0x23E3, DriverType::Prolific);
53 table.add_product(0x067B, 0x23F3, DriverType::Prolific);
54 table.add_product(0x1A86, 0x7523, DriverType::Ch34x);
55 table.add_product(0x1A86, 0x5523, DriverType::Ch34x);
56 table.add_product(0x18D1, 0x5014, DriverType::ChromeCcd);
57 table.add_product(0x1782, 0x4D10, DriverType::GsmModem);
58 table.add_product(0x1782, 0x4D12, DriverType::GsmModem);
59 table
60 }
61
62 pub fn add_product(&mut self, vendor_id: u16, product_id: u16, driver: DriverType) {
64 self.entries.push(ProbeEntry {
65 vendor_id,
66 product_id,
67 driver,
68 });
69 }
70
71 pub fn find(
73 &self,
74 vendor_id: u16,
75 product_id: u16,
76 interfaces: &[InterfaceInfo],
77 ) -> DriverType {
78 if let Some(entry) = self
79 .entries
80 .iter()
81 .find(|e| e.vendor_id == vendor_id && e.product_id == product_id)
82 {
83 return entry.driver;
84 }
85 if cdc_acm_port_count(interfaces) > 0 {
86 return DriverType::CdcAcm;
87 }
88 DriverType::CdcAcm }
90
91 pub fn port_count(&self, driver: DriverType, interfaces: &[InterfaceInfo]) -> usize {
93 match driver {
94 DriverType::CdcAcm => cdc_acm_port_count(interfaces),
95 DriverType::Ftdi | DriverType::Cp21xx => interfaces.len().max(1),
96 DriverType::ChromeCcd => 3,
97 DriverType::Ch34x | DriverType::Prolific | DriverType::GsmModem => 1,
98 }
99 }
100
101 pub fn port_count_product(
103 &self,
104 vendor_id: u16,
105 product_id: u16,
106 driver: DriverType,
107 interfaces: &[InterfaceInfo],
108 ) -> usize {
109 if !interfaces.is_empty() {
110 return self.port_count(driver, interfaces);
111 }
112 match (vendor_id, product_id) {
113 (0x0403, 0x6010 | 0x6011 | 0x6014 | 0x6015) => 2,
114 (0x10C4, 0xEA70 | 0xEA71) => 2,
115 (0x18D1, 0x5014) => 3,
116 _ => self.port_count(driver, interfaces),
117 }
118 }
119
120 pub fn entries(&self) -> &[ProbeEntry] {
122 &self.entries
123 }
124}
125
126pub fn cdc_acm_port_count(interfaces: &[InterfaceInfo]) -> usize {
128 let comm = interfaces
129 .iter()
130 .filter(|i| i.class == 2 && i.subclass == 2)
131 .count();
132 let data = interfaces.iter().filter(|i| i.class == 10).count();
133 comm.min(data)
134 .max(if comm == 0 && data == 0 { 0 } else { 1 })
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn default_table_finds_ftdi() {
143 let table = ProbeTable::default_table();
144 let driver = table.find(0x0403, 0x6001, &[]);
145 assert_eq!(driver, DriverType::Ftdi);
146 }
147
148 #[test]
149 fn cdc_probe_fn_fallback() {
150 let table = ProbeTable::default_table();
151 let ifaces = vec![
152 InterfaceInfo {
153 id: 0,
154 class: 2,
155 subclass: 2,
156 protocol: 0,
157 },
158 InterfaceInfo {
159 id: 1,
160 class: 10,
161 subclass: 0,
162 protocol: 0,
163 },
164 ];
165 let driver = table.find(0x9999, 0x0001, &ifaces);
166 assert_eq!(driver, DriverType::CdcAcm);
167 assert_eq!(table.port_count(driver, &ifaces), 1);
168 }
169}