1 use std::time::Duration;
2 
3 use rusb::{
4     Context, Device, DeviceDescriptor, DeviceHandle, Direction, Result, TransferType, UsbContext,
5 };
6 
7 #[derive(Debug)]
8 struct Endpoint {
9     config: u8,
10     iface: u8,
11     setting: u8,
12     address: u8,
13 }
14 
convert_argument(input: &str) -> u1615 fn convert_argument(input: &str) -> u16 {
16     if input.starts_with("0x") {
17         return u16::from_str_radix(input.trim_start_matches("0x"), 16).unwrap();
18     }
19     u16::from_str_radix(input, 10)
20         .expect("Invalid input, be sure to add `0x` for hexadecimal values.")
21 }
22 
main()23 fn main() {
24     let args: Vec<String> = std::env::args().collect();
25 
26     if args.len() < 3 {
27         println!("usage: read_device <base-10/0xbase-16> <base-10/0xbase-16>");
28         return;
29     }
30 
31     let vid = convert_argument(args[1].as_ref());
32     let pid = convert_argument(args[2].as_ref());
33 
34     match Context::new() {
35         Ok(mut context) => match open_device(&mut context, vid, pid) {
36             Some((mut device, device_desc, mut handle)) => {
37                 read_device(&mut device, &device_desc, &mut handle).unwrap()
38             }
39             None => println!("could not find device {:04x}:{:04x}", vid, pid),
40         },
41         Err(e) => panic!("could not initialize libusb: {}", e),
42     }
43 }
44 
open_device<T: UsbContext>( context: &mut T, vid: u16, pid: u16, ) -> Option<(Device<T>, DeviceDescriptor, DeviceHandle<T>)>45 fn open_device<T: UsbContext>(
46     context: &mut T,
47     vid: u16,
48     pid: u16,
49 ) -> Option<(Device<T>, DeviceDescriptor, DeviceHandle<T>)> {
50     let devices = match context.devices() {
51         Ok(d) => d,
52         Err(_) => return None,
53     };
54 
55     for device in devices.iter() {
56         let device_desc = match device.device_descriptor() {
57             Ok(d) => d,
58             Err(_) => continue,
59         };
60 
61         if device_desc.vendor_id() == vid && device_desc.product_id() == pid {
62             match device.open() {
63                 Ok(handle) => return Some((device, device_desc, handle)),
64                 Err(e) => panic!("Device found but failed to open: {}", e),
65             }
66         }
67     }
68 
69     None
70 }
71 
read_device<T: UsbContext>( device: &mut Device<T>, device_desc: &DeviceDescriptor, handle: &mut DeviceHandle<T>, ) -> Result<()>72 fn read_device<T: UsbContext>(
73     device: &mut Device<T>,
74     device_desc: &DeviceDescriptor,
75     handle: &mut DeviceHandle<T>,
76 ) -> Result<()> {
77     handle.reset()?;
78 
79     let timeout = Duration::from_secs(1);
80     let languages = handle.read_languages(timeout)?;
81 
82     println!("Active configuration: {}", handle.active_configuration()?);
83     println!("Languages: {:?}", languages);
84 
85     if !languages.is_empty() {
86         let language = languages[0];
87 
88         println!(
89             "Manufacturer: {:?}",
90             handle
91                 .read_manufacturer_string(language, device_desc, timeout)
92                 .ok()
93         );
94         println!(
95             "Product: {:?}",
96             handle
97                 .read_product_string(language, device_desc, timeout)
98                 .ok()
99         );
100         println!(
101             "Serial Number: {:?}",
102             handle
103                 .read_serial_number_string(language, device_desc, timeout)
104                 .ok()
105         );
106     }
107 
108     match find_readable_endpoint(device, device_desc, TransferType::Interrupt) {
109         Some(endpoint) => read_endpoint(handle, endpoint, TransferType::Interrupt),
110         None => println!("No readable interrupt endpoint"),
111     }
112 
113     match find_readable_endpoint(device, device_desc, TransferType::Bulk) {
114         Some(endpoint) => read_endpoint(handle, endpoint, TransferType::Bulk),
115         None => println!("No readable bulk endpoint"),
116     }
117 
118     Ok(())
119 }
120 
find_readable_endpoint<T: UsbContext>( device: &mut Device<T>, device_desc: &DeviceDescriptor, transfer_type: TransferType, ) -> Option<Endpoint>121 fn find_readable_endpoint<T: UsbContext>(
122     device: &mut Device<T>,
123     device_desc: &DeviceDescriptor,
124     transfer_type: TransferType,
125 ) -> Option<Endpoint> {
126     for n in 0..device_desc.num_configurations() {
127         let config_desc = match device.config_descriptor(n) {
128             Ok(c) => c,
129             Err(_) => continue,
130         };
131 
132         for interface in config_desc.interfaces() {
133             for interface_desc in interface.descriptors() {
134                 for endpoint_desc in interface_desc.endpoint_descriptors() {
135                     if endpoint_desc.direction() == Direction::In
136                         && endpoint_desc.transfer_type() == transfer_type
137                     {
138                         return Some(Endpoint {
139                             config: config_desc.number(),
140                             iface: interface_desc.interface_number(),
141                             setting: interface_desc.setting_number(),
142                             address: endpoint_desc.address(),
143                         });
144                     }
145                 }
146             }
147         }
148     }
149 
150     None
151 }
152 
read_endpoint<T: UsbContext>( handle: &mut DeviceHandle<T>, endpoint: Endpoint, transfer_type: TransferType, )153 fn read_endpoint<T: UsbContext>(
154     handle: &mut DeviceHandle<T>,
155     endpoint: Endpoint,
156     transfer_type: TransferType,
157 ) {
158     println!("Reading from endpoint: {:?}", endpoint);
159 
160     let has_kernel_driver = match handle.kernel_driver_active(endpoint.iface) {
161         Ok(true) => {
162             handle.detach_kernel_driver(endpoint.iface).ok();
163             true
164         }
165         _ => false,
166     };
167 
168     println!(" - kernel driver? {}", has_kernel_driver);
169 
170     match configure_endpoint(handle, &endpoint) {
171         Ok(_) => {
172             let mut buf = [0; 256];
173             let timeout = Duration::from_secs(1);
174 
175             match transfer_type {
176                 TransferType::Interrupt => {
177                     match handle.read_interrupt(endpoint.address, &mut buf, timeout) {
178                         Ok(len) => {
179                             println!(" - read: {:?}", &buf[..len]);
180                         }
181                         Err(err) => println!("could not read from endpoint: {}", err),
182                     }
183                 }
184                 TransferType::Bulk => match handle.read_bulk(endpoint.address, &mut buf, timeout) {
185                     Ok(len) => {
186                         println!(" - read: {:?}", &buf[..len]);
187                     }
188                     Err(err) => println!("could not read from endpoint: {}", err),
189                 },
190                 _ => (),
191             }
192         }
193         Err(err) => println!("could not configure endpoint: {}", err),
194     }
195 
196     if has_kernel_driver {
197         handle.attach_kernel_driver(endpoint.iface).ok();
198     }
199 }
200 
configure_endpoint<T: UsbContext>( handle: &mut DeviceHandle<T>, endpoint: &Endpoint, ) -> Result<()>201 fn configure_endpoint<T: UsbContext>(
202     handle: &mut DeviceHandle<T>,
203     endpoint: &Endpoint,
204 ) -> Result<()> {
205     handle.set_active_configuration(endpoint.config)?;
206     handle.claim_interface(endpoint.iface)?;
207     handle.set_alternate_setting(endpoint.iface, endpoint.setting)?;
208     Ok(())
209 }
210