1 use rusb::{
2     ConfigDescriptor, DeviceDescriptor, DeviceHandle, DeviceList, EndpointDescriptor,
3     InterfaceDescriptor, Language, Result, Speed, UsbContext,
4 };
5 use std::time::Duration;
6 
7 use usb_ids::{self, FromId};
8 
9 struct UsbDevice<T: UsbContext> {
10     handle: DeviceHandle<T>,
11     language: Language,
12     timeout: Duration,
13 }
14 
main()15 fn main() {
16     list_devices().unwrap();
17 }
18 
list_devices() -> Result<()>19 fn list_devices() -> Result<()> {
20     let timeout = Duration::from_secs(1);
21 
22     for device in DeviceList::new()?.iter() {
23         let device_desc = match device.device_descriptor() {
24             Ok(d) => d,
25             Err(_) => continue,
26         };
27 
28         let mut usb_device = {
29             match device.open() {
30                 Ok(h) => match h.read_languages(timeout) {
31                     Ok(l) => {
32                         if !l.is_empty() {
33                             Some(UsbDevice {
34                                 handle: h,
35                                 language: l[0],
36                                 timeout,
37                             })
38                         } else {
39                             None
40                         }
41                     }
42                     Err(_) => None,
43                 },
44                 Err(_) => None,
45             }
46         };
47 
48         println!(
49             "Bus {:03} Device {:03} ID {:04x}:{:04x} {}",
50             device.bus_number(),
51             device.address(),
52             device_desc.vendor_id(),
53             device_desc.product_id(),
54             get_speed(device.speed())
55         );
56         print_device(&device_desc, &mut usb_device);
57 
58         for n in 0..device_desc.num_configurations() {
59             let config_desc = match device.config_descriptor(n) {
60                 Ok(c) => c,
61                 Err(_) => continue,
62             };
63 
64             print_config(&config_desc, &mut usb_device);
65 
66             for interface in config_desc.interfaces() {
67                 for interface_desc in interface.descriptors() {
68                     print_interface(&interface_desc, &mut usb_device);
69 
70                     for endpoint_desc in interface_desc.endpoint_descriptors() {
71                         print_endpoint(&endpoint_desc);
72                     }
73                 }
74             }
75         }
76     }
77 
78     Ok(())
79 }
80 
print_device<T: UsbContext>(device_desc: &DeviceDescriptor, handle: &mut Option<UsbDevice<T>>)81 fn print_device<T: UsbContext>(device_desc: &DeviceDescriptor, handle: &mut Option<UsbDevice<T>>) {
82     let vid = device_desc.vendor_id();
83     let pid = device_desc.product_id();
84 
85     let vendor_name = match usb_ids::Vendor::from_id(device_desc.vendor_id()) {
86         Some(vendor) => vendor.name(),
87         None => "Unknown vendor",
88     };
89 
90     let product_name =
91         match usb_ids::Device::from_vid_pid(device_desc.vendor_id(), device_desc.product_id()) {
92             Some(product) => product.name(),
93             None => "Unknown product",
94         };
95 
96     println!("Device Descriptor:");
97     println!("  bLength              {:3}", device_desc.length());
98     println!("  bDescriptorType      {:3}", device_desc.descriptor_type());
99     println!(
100         "  bcdUSB             {:2}.{}{}",
101         device_desc.usb_version().major(),
102         device_desc.usb_version().minor(),
103         device_desc.usb_version().sub_minor()
104     );
105     println!("  bDeviceClass        {:#04x}", device_desc.class_code());
106     println!(
107         "  bDeviceSubClass     {:#04x}",
108         device_desc.sub_class_code()
109     );
110     println!("  bDeviceProtocol     {:#04x}", device_desc.protocol_code());
111     println!("  bMaxPacketSize0      {:3}", device_desc.max_packet_size());
112     println!("  idVendor          {vid:#06x} {vendor_name}",);
113     println!("  idProduct         {pid:#06x} {product_name}",);
114     println!(
115         "  bcdDevice          {:2}.{}{}",
116         device_desc.device_version().major(),
117         device_desc.device_version().minor(),
118         device_desc.device_version().sub_minor()
119     );
120     println!(
121         "  iManufacturer        {:3} {}",
122         device_desc.manufacturer_string_index().unwrap_or(0),
123         handle.as_mut().map_or(String::new(), |h| h
124             .handle
125             .read_manufacturer_string(h.language, device_desc, h.timeout)
126             .unwrap_or_default())
127     );
128     println!(
129         "  iProduct             {:3} {}",
130         device_desc.product_string_index().unwrap_or(0),
131         handle.as_mut().map_or(String::new(), |h| h
132             .handle
133             .read_product_string(h.language, device_desc, h.timeout)
134             .unwrap_or_default())
135     );
136     println!(
137         "  iSerialNumber        {:3} {}",
138         device_desc.serial_number_string_index().unwrap_or(0),
139         handle.as_mut().map_or(String::new(), |h| h
140             .handle
141             .read_serial_number_string(h.language, device_desc, h.timeout)
142             .unwrap_or_default())
143     );
144     println!(
145         "  bNumConfigurations   {:3}",
146         device_desc.num_configurations()
147     );
148 }
149 
print_config<T: UsbContext>(config_desc: &ConfigDescriptor, handle: &mut Option<UsbDevice<T>>)150 fn print_config<T: UsbContext>(config_desc: &ConfigDescriptor, handle: &mut Option<UsbDevice<T>>) {
151     println!("  Config Descriptor:");
152     println!("    bLength              {:3}", config_desc.length());
153     println!(
154         "    bDescriptorType      {:3}",
155         config_desc.descriptor_type()
156     );
157     println!("    wTotalLength      {:#06x}", config_desc.total_length());
158     println!(
159         "    bNumInterfaces       {:3}",
160         config_desc.num_interfaces()
161     );
162     println!("    bConfigurationValue  {:3}", config_desc.number());
163     println!(
164         "    iConfiguration       {:3} {}",
165         config_desc.description_string_index().unwrap_or(0),
166         handle.as_mut().map_or(String::new(), |h| h
167             .handle
168             .read_configuration_string(h.language, config_desc, h.timeout)
169             .unwrap_or_default())
170     );
171     println!("    bmAttributes:");
172     println!("      Self Powered     {:>5}", config_desc.self_powered());
173     println!("      Remote Wakeup    {:>5}", config_desc.remote_wakeup());
174     println!("    bMaxPower           {:4}mW", config_desc.max_power());
175 
176     if !config_desc.extra().is_empty() {
177         println!("    {:?}", config_desc.extra());
178     } else {
179         println!("    no extra data");
180     }
181 }
182 
print_interface<T: UsbContext>( interface_desc: &InterfaceDescriptor, handle: &mut Option<UsbDevice<T>>, )183 fn print_interface<T: UsbContext>(
184     interface_desc: &InterfaceDescriptor,
185     handle: &mut Option<UsbDevice<T>>,
186 ) {
187     println!("    Interface Descriptor:");
188     println!("      bLength              {:3}", interface_desc.length());
189     println!(
190         "      bDescriptorType      {:3}",
191         interface_desc.descriptor_type()
192     );
193     println!(
194         "      bInterfaceNumber     {:3}",
195         interface_desc.interface_number()
196     );
197     println!(
198         "      bAlternateSetting    {:3}",
199         interface_desc.setting_number()
200     );
201     println!(
202         "      bNumEndpoints        {:3}",
203         interface_desc.num_endpoints()
204     );
205     println!(
206         "      bInterfaceClass     {:#04x}",
207         interface_desc.class_code()
208     );
209     println!(
210         "      bInterfaceSubClass  {:#04x}",
211         interface_desc.sub_class_code()
212     );
213     println!(
214         "      bInterfaceProtocol  {:#04x}",
215         interface_desc.protocol_code()
216     );
217     println!(
218         "      iInterface           {:3} {}",
219         interface_desc.description_string_index().unwrap_or(0),
220         handle.as_mut().map_or(String::new(), |h| h
221             .handle
222             .read_interface_string(h.language, interface_desc, h.timeout)
223             .unwrap_or_default())
224     );
225 
226     if interface_desc.extra().is_empty() {
227         println!("    {:?}", interface_desc.extra());
228     } else {
229         println!("    no extra data");
230     }
231 }
232 
print_endpoint(endpoint_desc: &EndpointDescriptor)233 fn print_endpoint(endpoint_desc: &EndpointDescriptor) {
234     println!("      Endpoint Descriptor:");
235     println!("        bLength              {:3}", endpoint_desc.length());
236     println!(
237         "        bDescriptorType      {:3}",
238         endpoint_desc.descriptor_type()
239     );
240     println!(
241         "        bEndpointAddress    {:#04x} EP {} {:?}",
242         endpoint_desc.address(),
243         endpoint_desc.number(),
244         endpoint_desc.direction()
245     );
246     println!("        bmAttributes:");
247     println!(
248         "          Transfer Type          {:?}",
249         endpoint_desc.transfer_type()
250     );
251     println!(
252         "          Synch Type             {:?}",
253         endpoint_desc.sync_type()
254     );
255     println!(
256         "          Usage Type             {:?}",
257         endpoint_desc.usage_type()
258     );
259     println!(
260         "        wMaxPacketSize    {:#06x}",
261         endpoint_desc.max_packet_size()
262     );
263     println!(
264         "        bInterval            {:3}",
265         endpoint_desc.interval()
266     );
267 }
268 
get_speed(speed: Speed) -> &'static str269 fn get_speed(speed: Speed) -> &'static str {
270     match speed {
271         Speed::SuperPlus => "10000 Mbps",
272         Speed::Super => "5000 Mbps",
273         Speed::High => " 480 Mbps",
274         Speed::Full => "  12 Mbps",
275         Speed::Low => " 1.5 Mbps",
276         _ => "(unknown)",
277     }
278 }
279