blob: 1ae49507355855d6ccecddb0cfcb6788bc5b9b3b [file] [log] [blame]
use rusb::{
ConfigDescriptor, DeviceDescriptor, DeviceHandle, DeviceList, EndpointDescriptor,
InterfaceDescriptor, Language, Result, Speed, UsbContext,
};
use std::time::Duration;
use usb_ids::{self, FromId};
struct UsbDevice<T: UsbContext> {
handle: DeviceHandle<T>,
language: Language,
timeout: Duration,
}
fn main() {
list_devices().unwrap();
}
fn list_devices() -> Result<()> {
let timeout = Duration::from_secs(1);
for device in DeviceList::new()?.iter() {
let device_desc = match device.device_descriptor() {
Ok(d) => d,
Err(_) => continue,
};
let mut usb_device = {
match device.open() {
Ok(h) => match h.read_languages(timeout) {
Ok(l) => {
if !l.is_empty() {
Some(UsbDevice {
handle: h,
language: l[0],
timeout,
})
} else {
None
}
}
Err(_) => None,
},
Err(_) => None,
}
};
println!(
"Bus {:03} Device {:03} ID {:04x}:{:04x} {}",
device.bus_number(),
device.address(),
device_desc.vendor_id(),
device_desc.product_id(),
get_speed(device.speed())
);
print_device(&device_desc, &mut usb_device);
for n in 0..device_desc.num_configurations() {
let config_desc = match device.config_descriptor(n) {
Ok(c) => c,
Err(_) => continue,
};
print_config(&config_desc, &mut usb_device);
for interface in config_desc.interfaces() {
for interface_desc in interface.descriptors() {
print_interface(&interface_desc, &mut usb_device);
for endpoint_desc in interface_desc.endpoint_descriptors() {
print_endpoint(&endpoint_desc);
}
}
}
}
}
Ok(())
}
fn print_device<T: UsbContext>(device_desc: &DeviceDescriptor, handle: &mut Option<UsbDevice<T>>) {
let vid = device_desc.vendor_id();
let pid = device_desc.product_id();
let vendor_name = match usb_ids::Vendor::from_id(device_desc.vendor_id()) {
Some(vendor) => vendor.name(),
None => "Unknown vendor",
};
let product_name =
match usb_ids::Device::from_vid_pid(device_desc.vendor_id(), device_desc.product_id()) {
Some(product) => product.name(),
None => "Unknown product",
};
println!("Device Descriptor:");
println!(" bLength {:3}", device_desc.length());
println!(" bDescriptorType {:3}", device_desc.descriptor_type());
println!(
" bcdUSB {:2}.{}{}",
device_desc.usb_version().major(),
device_desc.usb_version().minor(),
device_desc.usb_version().sub_minor()
);
println!(" bDeviceClass {:#04x}", device_desc.class_code());
println!(
" bDeviceSubClass {:#04x}",
device_desc.sub_class_code()
);
println!(" bDeviceProtocol {:#04x}", device_desc.protocol_code());
println!(" bMaxPacketSize0 {:3}", device_desc.max_packet_size());
println!(" idVendor {vid:#06x} {vendor_name}",);
println!(" idProduct {pid:#06x} {product_name}",);
println!(
" bcdDevice {:2}.{}{}",
device_desc.device_version().major(),
device_desc.device_version().minor(),
device_desc.device_version().sub_minor()
);
println!(
" iManufacturer {:3} {}",
device_desc.manufacturer_string_index().unwrap_or(0),
handle.as_mut().map_or(String::new(), |h| h
.handle
.read_manufacturer_string(h.language, device_desc, h.timeout)
.unwrap_or_default())
);
println!(
" iProduct {:3} {}",
device_desc.product_string_index().unwrap_or(0),
handle.as_mut().map_or(String::new(), |h| h
.handle
.read_product_string(h.language, device_desc, h.timeout)
.unwrap_or_default())
);
println!(
" iSerialNumber {:3} {}",
device_desc.serial_number_string_index().unwrap_or(0),
handle.as_mut().map_or(String::new(), |h| h
.handle
.read_serial_number_string(h.language, device_desc, h.timeout)
.unwrap_or_default())
);
println!(
" bNumConfigurations {:3}",
device_desc.num_configurations()
);
}
fn print_config<T: UsbContext>(config_desc: &ConfigDescriptor, handle: &mut Option<UsbDevice<T>>) {
println!(" Config Descriptor:");
println!(" bLength {:3}", config_desc.length());
println!(
" bDescriptorType {:3}",
config_desc.descriptor_type()
);
println!(" wTotalLength {:#06x}", config_desc.total_length());
println!(
" bNumInterfaces {:3}",
config_desc.num_interfaces()
);
println!(" bConfigurationValue {:3}", config_desc.number());
println!(
" iConfiguration {:3} {}",
config_desc.description_string_index().unwrap_or(0),
handle.as_mut().map_or(String::new(), |h| h
.handle
.read_configuration_string(h.language, config_desc, h.timeout)
.unwrap_or_default())
);
println!(" bmAttributes:");
println!(" Self Powered {:>5}", config_desc.self_powered());
println!(" Remote Wakeup {:>5}", config_desc.remote_wakeup());
println!(" bMaxPower {:4}mW", config_desc.max_power());
if !config_desc.extra().is_empty() {
println!(" {:?}", config_desc.extra());
} else {
println!(" no extra data");
}
}
fn print_interface<T: UsbContext>(
interface_desc: &InterfaceDescriptor,
handle: &mut Option<UsbDevice<T>>,
) {
println!(" Interface Descriptor:");
println!(" bLength {:3}", interface_desc.length());
println!(
" bDescriptorType {:3}",
interface_desc.descriptor_type()
);
println!(
" bInterfaceNumber {:3}",
interface_desc.interface_number()
);
println!(
" bAlternateSetting {:3}",
interface_desc.setting_number()
);
println!(
" bNumEndpoints {:3}",
interface_desc.num_endpoints()
);
println!(
" bInterfaceClass {:#04x}",
interface_desc.class_code()
);
println!(
" bInterfaceSubClass {:#04x}",
interface_desc.sub_class_code()
);
println!(
" bInterfaceProtocol {:#04x}",
interface_desc.protocol_code()
);
println!(
" iInterface {:3} {}",
interface_desc.description_string_index().unwrap_or(0),
handle.as_mut().map_or(String::new(), |h| h
.handle
.read_interface_string(h.language, interface_desc, h.timeout)
.unwrap_or_default())
);
if interface_desc.extra().is_empty() {
println!(" {:?}", interface_desc.extra());
} else {
println!(" no extra data");
}
}
fn print_endpoint(endpoint_desc: &EndpointDescriptor) {
println!(" Endpoint Descriptor:");
println!(" bLength {:3}", endpoint_desc.length());
println!(
" bDescriptorType {:3}",
endpoint_desc.descriptor_type()
);
println!(
" bEndpointAddress {:#04x} EP {} {:?}",
endpoint_desc.address(),
endpoint_desc.number(),
endpoint_desc.direction()
);
println!(" bmAttributes:");
println!(
" Transfer Type {:?}",
endpoint_desc.transfer_type()
);
println!(
" Synch Type {:?}",
endpoint_desc.sync_type()
);
println!(
" Usage Type {:?}",
endpoint_desc.usage_type()
);
println!(
" wMaxPacketSize {:#06x}",
endpoint_desc.max_packet_size()
);
println!(
" bInterval {:3}",
endpoint_desc.interval()
);
}
fn get_speed(speed: Speed) -> &'static str {
match speed {
Speed::SuperPlus => "10000 Mbps",
Speed::Super => "5000 Mbps",
Speed::High => " 480 Mbps",
Speed::Full => " 12 Mbps",
Speed::Low => " 1.5 Mbps",
_ => "(unknown)",
}
}