Skip to content

Commit

Permalink
class, subclass, protocol names from usb-ids in lsusb verbose
Browse files Browse the repository at this point in the history
  • Loading branch information
tuna-f1sh committed Nov 15, 2023
1 parent 561210e commit 34b186b
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 30 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 2 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.87"
serde_with = "2.0.1"
simple_logger = "4.0.0"
usb-ids = { version = "1", optional = true }
usb-ids = { git = "https://github.com/tuna-f1sh/usb-ids.rs.git", version = "1" }
heck = "0.4.0"
clap_complete = { version = "4.0.6", optional = true }
clap_mangen = { version = "0.2.5", optional = true }
Expand All @@ -39,20 +39,17 @@ assert-json-diff = "2.0.2"
[target.x86_64-unknown-linux-gnu.dependencies]
udev = { version = "^0.8.0", optional = true, features = ["hwdb"] }
rusb = { git = "https://github.com/tuna-f1sh/rusb.git", version = "0.9.1" }
usb-ids = "1"

[target.arm-unknown-linux-gnueabihf.dependencies]
udev = { version = "^0.8.0", optional = true, features = ["hwdb"] }
rusb = { git = "https://github.com/tuna-f1sh/rusb.git", version = "0.9.1" }
usb-ids = "1"

[target.aarch64-unknown-linux-gnu.dependencies]
udev = { version = "^0.8.0", optional = true, features = ["hwdb"] }
rusb = { git = "https://github.com/tuna-f1sh/rusb.git", version = "0.9.1" }
usb-ids = "1"

[features]
libusb = ["dep:rusb", "dep:usb-ids"]
libusb = ["dep:rusb"]
udev = ["dep:udev"]
usb_test = []
cli_generate = ["dep:clap_complete", "dep:clap_mangen"] # for generating man and completions
Expand Down
66 changes: 44 additions & 22 deletions src/lsusb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub mod profiler {
/// Attempt to retrieve the current bConfigurationValue and iConfiguration for a device
/// This will only return the current configuration, not all possible configurations
/// If there are any failures in retrieving the data, None is returned
#[allow(unused_variables)]
fn get_sysfs_configuration_string(sysfs_name: &str) -> Option<(u8, String)> {
#[cfg(target_os = "linux")]
// Determine bConfigurationValue value on linux
Expand All @@ -78,6 +79,7 @@ pub mod profiler {
None
}

#[allow(unused_variables)]
fn get_sysfs_string(sysfs_name: &str, name: &str) -> Option<String> {
#[cfg(target_os = "linux")]
match std::fs::read_to_string(format!("/sys/bus/usb/devices/{}/{}", sysfs_name, name)) {
Expand Down Expand Up @@ -248,11 +250,12 @@ pub mod profiler {
ret
}

#[allow(unused_variables)]
fn build_interfaces<T: libusb::UsbContext>(
device: &libusb::Device<T>,
handle: &mut Option<UsbDevice<T>>,
config_desc: &libusb::ConfigDescriptor,
_with_udev: bool,
with_udev: bool,
) -> error::Result<Vec<usb::USBInterface>> {
let mut ret: Vec<usb::USBInterface> = Vec::new();

Expand Down Expand Up @@ -283,7 +286,7 @@ pub mod profiler {
};

#[cfg(all(target_os = "linux", feature = "udev"))]
if _with_udev {
if with_udev {
udev::get_udev_info(
&mut _interface.driver,
&mut _interface.syspath,
Expand Down Expand Up @@ -357,12 +360,13 @@ pub mod profiler {
Ok(ret)
}

#[allow(unused_variables)]
fn build_spdevice_extra<T: libusb::UsbContext>(
device: &libusb::Device<T>,
handle: &mut Option<UsbDevice<T>>,
device_desc: &libusb::DeviceDescriptor,
sp_device: &system_profiler::USBDevice,
_with_udev: bool,
with_udev: bool,
) -> error::Result<usb::USBDeviceExtra> {
let mut _extra = usb::USBDeviceExtra {
max_packet_size: device_desc.max_packet_size(),
Expand All @@ -385,12 +389,12 @@ pub mod profiler {
handle,
device_desc,
sp_device,
_with_udev,
with_udev,
)?,
};

#[cfg(all(target_os = "linux", feature = "udev"))]
if _with_udev {
if with_udev {
udev::get_udev_info(
&mut _extra.driver,
&mut _extra.syspath,
Expand Down Expand Up @@ -823,6 +827,24 @@ pub mod display {
.as_ref()
.expect("Cannot print verbose without extra data");

// lsusb doesn't show 0x00 for defined at interface level
let class_name = if device.base_class_code() != Some(0) {
device.class_name()
} else {
None
};
// or 0x00 sub-class/protocol
let sub_class_name = if device.sub_class != Some(0) {
device.sub_class_name()
} else {
None
};
let protocol_name = if device.protocol != Some(0) {
device.protocol_name()
} else {
None
};

println!("Device Descriptor:");
// These are constants - length is 18 bytes for descriptor, type is 1
println!(" bLength 18");
Expand All @@ -834,16 +856,9 @@ pub mod display {
.as_ref()
.map_or(String::new(), |v| v.to_string())
);
println!(
" bDeviceClass {:3} {}",
device.class.as_ref().map_or(0, |c| u8::from(c.to_owned())),
device
.class
.as_ref()
.map_or(String::new(), |c| c.to_string())
);
println!(" bDeviceSubClass {:3}", device.sub_class.unwrap_or(0));
println!(" bDeviceProtocol {:3}", device.protocol.unwrap_or(0));
println!(" bDeviceClass {:3} {}", device.base_class_code().unwrap_or(0), class_name.unwrap_or_default());
println!(" bDeviceSubClass {:3} {}", device.sub_class.unwrap_or(0), sub_class_name.unwrap_or_default());
println!(" bDeviceProtocol {:3} {}", device.protocol.unwrap_or(0), protocol_name.unwrap_or_default());
println!(" bMaxPacketSize0 {:3}", device_extra.max_packet_size);
println!(
" idVendor {:#06x} {}",
Expand Down Expand Up @@ -921,19 +936,26 @@ pub mod display {
}

fn print_interface(interface: &usb::USBInterface) {
let sub_class_name = if interface.sub_class != 0x00 {
interface.sub_class_name()
} else {
None
};
let protocol_name = if interface.protocol != 0x00 {
interface.protocol_name()
} else {
None
};

println!(" Interface Descriptor:");
println!(" bLength {:3}", interface.length);
println!(" bDescriptorType 4"); // type 4 for interface
println!(" bInterfaceNumber {:3}", interface.number);
println!(" bAlternateSetting {:3}", interface.alt_setting);
println!(" bNumEndpoints {:3}", interface.endpoints.len());
println!(
" bInterfaceClass {:3} {}",
u8::from(interface.class.to_owned()),
interface.class
);
println!(" bInterfaceSubClass {:3}", interface.sub_class);
println!(" bInterfaceProtocol {:3}", interface.protocol);
println!(" bInterfaceClass {:3} {}", u8::from(interface.class.to_owned()), interface.class_name().unwrap_or_default());
println!(" bInterfaceSubClass {:3} {}", interface.sub_class, sub_class_name.unwrap_or_default());
println!(" bInterfaceProtocol {:3} {}", interface.protocol, protocol_name.unwrap_or_default());
println!(
" iInterface {:3} {}",
interface.string_index, interface.name
Expand Down
29 changes: 29 additions & 0 deletions src/system_profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1116,6 +1116,35 @@ impl USBDevice {

format_strs
}

/// Gets the base class code byte from [`ClassCode`]
pub fn base_class_code(&self) -> Option<u8> {
self.class.as_ref().map(|c| u8::from(*c))
}

/// Name of class from Linux USB IDs repository
pub fn class_name(&self) -> Option<&str> {
match self.base_class_code() {
Some(cid) => usb_ids::Classes::iter().find(|c| c.id() == cid).map(|c| c.name()),
None => None,
}
}

/// Name of sub class from Linux USB IDs repository
pub fn sub_class_name(&self) -> Option<&str> {
match (self.base_class_code(), self.sub_class) {
(Some(cid), Some(sid)) => usb_ids::SubClass::from_cid_scid(cid, sid).map(|sc| sc.name()),
_ => None,
}
}

/// Name of protocol from Linux USB IDs repository
pub fn protocol_name(&self) -> Option<&str> {
match (self.base_class_code(), self.sub_class, self.protocol) {
(Some(cid), Some(sid), Some(pid)) => usb_ids::Protocol::from_cid_scid_pid(cid, sid, pid).map(|p| p.name()),
_ => None,
}
}
}

impl fmt::Display for USBDevice {
Expand Down
25 changes: 24 additions & 1 deletion src/usb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ pub enum DescriptorUsage {
/// USB class code defines [ref](https://www.usb.org/defined-class-codes)
///
/// Technically this is the 'Base Class' - the 'Class Code' is the full triplet of (Base Class, Sub Class, Protocol). TODO rename in 2.0 release
#[derive(Debug, ValueEnum, Default, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Debug, ValueEnum, Default, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ClassCode {
#[default]
Expand Down Expand Up @@ -694,6 +694,29 @@ impl USBInterface {
pub fn path(&self, bus: u8, ports: &[u8], config: u8) -> String {
get_interface_path(bus, ports, config, self.number)
}

/// Name of class from Linux USB IDs repository
pub fn class_name(&self) -> Option<&str> {
usb_ids::Classes::iter()
.find(|c| c.id() == u8::from(self.class))
.map(|c| c.name())
}

/// Name of sub class from Linux USB IDs repository
pub fn sub_class_name(&self) -> Option<&str> {
usb_ids::SubClass::from_cid_scid(u8::from(self.class), self.sub_class)
.map(|sc| sc.name())
}

/// Name of protocol from Linux USB IDs repository
pub fn protocol_name(&self) -> Option<&str> {
usb_ids::Protocol::from_cid_scid_pid(
u8::from(self.class),
self.sub_class,
self.protocol,
)
.map(|p| p.name())
}
}

/// Devices can have multiple configurations, each with different attributes and interfaces
Expand Down

0 comments on commit 34b186b

Please sign in to comment.