Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds function function to get BOS descriptor #46

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions examples/list_devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ fn list_devices() -> libusb::Result<()> {
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);

print_bos(&mut usb_device);

for n in 0..device_desc.num_configurations() {
let config_desc = match device.config_descriptor(n) {
Ok(c) => c,
Expand Down Expand Up @@ -95,6 +97,64 @@ fn print_device(device_desc: &libusb::DeviceDescriptor, handle: &mut Option<UsbD
println!(" bNumConfigurations {:3}", device_desc.num_configurations());
}

fn print_bos(UsbDevice: &mut Option<UsbDevice>) {
let h = match UsbDevice {
Some(h) => &h.handle,
None => return,
};
let bos_desc = match h.bos_descriptor() {
Ok(desc) => desc,
Err(_) => { return; },

};

println!(" BOS Descriptor:");
println!(" bDescriptorType {}", bos_desc.descriptor_type());
println!(" bNumDeviceCaps {}", bos_desc.num_device_caps());

for dev_cap in bos_desc.dev_capability() {
match dev_cap.dev_capability_type() {
2 => {
match h.bos_usb_2_0_extension_descriptor(&bos_desc, &dev_cap) {
Ok(desc) => {
println!(" USB 2.0 Extension Capabilities:");
println!(" bDevCapabilityType: {}", desc.dev_capability_type());
println!(" bmAttributes {:08x}h", desc.attributes());
},
Err(e) => println!("{}", e),
}
},
3 => {
match h.bos_superspeed_usb_descriptor(&bos_desc, &dev_cap) {
Ok(desc) => {
println!(" USB 3.0 Capabilities:");
println!(" bDevCapabilityType: {}", desc.dev_capability_type());
println!(" bmAttributes: {:02x}h", desc.attributes());
println!(" wSpeedSupported: {}", desc.speed_supported());
println!(" bFunctionalitySupport: {}", desc.functionality_support());
println!(" bU1devExitLat: {}", desc.u1_dev_exit_lat());
println!(" bU2devExitLat: {}", desc.u2_dev_exit_lat());
},
Err(e) => println!("{}", e),
}
},
4 => {
match h.bos_container_id_descriptor(&bos_desc, &dev_cap) {
Ok(desc) => {
print!(" Container ID: ");
for i in desc.container_id() {
print!("{:02X}", i);
}
println!();
},
Err(e) => println!("{}", e),
}
},
_ => {},
}
}
}

fn print_config(config_desc: &libusb::ConfigDescriptor, handle: &mut Option<UsbDevice>) {
println!(" Config Descriptor:");
println!(" bNumInterfaces {:3}", config_desc.num_interfaces());
Expand Down
304 changes: 304 additions & 0 deletions src/bos_descriptor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
use std::fmt;
use std::mem;
use libusb::*;

pub struct BosDescriptor {
descriptor: *const libusb_bos_descriptor,
}

pub struct BosDevCapabilityDescriptor {
addr: *const *const u8,
descriptor: *const libusb_bos_dev_capability_descriptor,
}

pub struct Usb20ExtensionDescriptor {
descriptor: *const libusb_usb_2_0_extension_descriptor,
}

pub struct SsUsbDescriptor {
descriptor: *const libusb_ss_usb_device_capability_descriptor,
}

pub struct ContainerIdDescriptor {
descriptor: *const libusb_container_id_descriptor,
}

impl Drop for BosDescriptor {
fn drop(&mut self) {
unsafe {
libusb_free_bos_descriptor(self.descriptor as *mut libusb_bos_descriptor);
}
}
}

impl Drop for Usb20ExtensionDescriptor {
fn drop(&mut self) {
unsafe {
libusb_free_usb_2_0_extension_descriptor(self.descriptor as *mut libusb_usb_2_0_extension_descriptor);
}
}
}

impl Drop for SsUsbDescriptor {
fn drop(&mut self) {
unsafe {
libusb_free_ss_usb_device_capability_descriptor(self.descriptor as *mut libusb_ss_usb_device_capability_descriptor);
}
}
}

impl Drop for ContainerIdDescriptor {
fn drop(&mut self) {
unsafe {
libusb_free_container_id_descriptor(self.descriptor as *mut libusb_container_id_descriptor);
}
}
}

/// BOS Descriptor
impl BosDescriptor {
pub fn length(&self) -> u8 {
unsafe {
(*self.descriptor).bLength
}
}

pub fn descriptor_type(&self) -> u8 {
unsafe {
(*self.descriptor).bDescriptorType
}
}

pub fn total_length(&self) -> u16 {
unsafe {
(*self.descriptor).wTotalLength
}
}

pub fn num_device_caps(&self) -> u8 {
unsafe {
(*self.descriptor).bNumDeviceCaps
}
}

pub fn dev_capability(&self) -> Vec<BosDevCapabilityDescriptor> {
unsafe {
let mut v: Vec<BosDevCapabilityDescriptor> = Vec::new();
for i in 0..self.num_device_caps() {
// 先转换成指针
let point = std::ptr::addr_of!((*self.descriptor).dev_capability).offset(i as _);
// 在将指针转换为 *const *const libusb_bos_dev_capability_descriptor,然后解引用两次
let dev_cap = &(*(*(point as * const *const libusb_bos_dev_capability_descriptor)));
let cap = from_libusb_bos_dev_capability_descriptor(point as *const *const u8, dev_cap);
v.push(cap);
}
v
}
}
}

/// Device Capability Descriptor
impl BosDevCapabilityDescriptor {
pub fn get_addr(&self) -> *const *const u8 {
self.addr
}

pub fn length(&self) -> u8 {
unsafe {
(*self.descriptor).bLength
}
}

pub fn descriptor_type(&self) -> u8 {
unsafe {
(*self.descriptor).bDescriptorType
}
}

pub fn dev_capability_type(&self) -> u8 {
unsafe {
(*self.descriptor).bDevCapabilityType
}
}
}

/// USB 2.0 Extension Descriptor
impl Usb20ExtensionDescriptor {
pub fn length(&self) -> u8 {
unsafe {
(*self.descriptor).bLength
}
}

pub fn descriptor_type(&self) -> u8 {
unsafe {
(*self.descriptor).bDescriptorType
}
}

pub fn dev_capability_type(&self) -> u8 {
unsafe {
(*self.descriptor).bDevCapabilityType
}
}

pub fn attributes(&self) -> u32 {
unsafe {
(*self.descriptor).bmAttributes
}
}
}

/// SuperSpeed USB Descriptor
impl SsUsbDescriptor {
pub fn length(&self) -> u8 {
unsafe {
(*self.descriptor).bLength
}
}

pub fn descriptor_type(&self) -> u8 {
unsafe {
(*self.descriptor).bDescriptorType
}
}

pub fn dev_capability_type(&self) -> u8 {
unsafe {
(*self.descriptor).bDevCapabilityType
}
}

pub fn attributes(&self) -> u8 {
unsafe {
(*self.descriptor).bmAttributes
}
}

pub fn speed_supported(&self) -> u16 {
unsafe {
(*self.descriptor).wSpeedSupported
}
}

pub fn functionality_support(&self) -> u8 {
unsafe {
(*self.descriptor).bFunctionalitySupport
}
}

pub fn u1_dev_exit_lat(&self) -> u8 {
unsafe {
(*self.descriptor).bU1DevExitLat
}
}

pub fn u2_dev_exit_lat(&self) -> u8 {
unsafe {
(*self.descriptor).bU2DevExitLat
}
}
}

/// Container ID Descriptor
impl ContainerIdDescriptor {
pub fn length(&self) -> u8 {
unsafe {
(*self.descriptor).bLength
}
}

pub fn descriptor_type(&self) -> u8 {
unsafe {
(*self.descriptor).bDescriptorType
}
}

pub fn dev_capability_type(&self) -> u8 {
unsafe {
(*self.descriptor).bDevCapabilityType
}
}

pub fn reserved(&self) -> u8 {
unsafe {
(*self.descriptor).bReserved
}
}

pub fn container_id(&self) -> [u8; 16] {
unsafe {
(*self.descriptor).ContainerId
}
}
}

impl fmt::Debug for BosDescriptor {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let mut debug = f.debug_struct("BosDescriptor");

let descriptor: &libusb_bos_descriptor = unsafe {
mem::transmute(self.descriptor)
};

debug.field("bLength", &descriptor.bLength);
debug.field("bDescriptorType", &descriptor.bDescriptorType);
debug.field("wTotalLength", &descriptor.wTotalLength);
debug.field("bNumDeviceCaps", &descriptor.bNumDeviceCaps);

debug.finish()
}
}

#[doc(hidden)]
pub fn from_libusb(bos: *const libusb_bos_descriptor) -> BosDescriptor {
BosDescriptor { descriptor: bos }
}

#[doc(hidden)]
pub fn from_libusb_bos_dev_capability_descriptor(addr: *const *const u8, bos: *const libusb_bos_dev_capability_descriptor) -> BosDevCapabilityDescriptor {
BosDevCapabilityDescriptor { addr: addr, descriptor: bos }
}

#[doc(hidden)]
pub fn from_libusb_usb_2_0_extension_descriptor(bos: *const libusb_usb_2_0_extension_descriptor) -> Usb20ExtensionDescriptor {
Usb20ExtensionDescriptor { descriptor: bos }
}

#[doc(hidden)]
pub fn from_libusb_ss_usb_device_capability_descriptor(bos: *const libusb_ss_usb_device_capability_descriptor) -> SsUsbDescriptor {
SsUsbDescriptor { descriptor: bos }
}

#[doc(hidden)]
pub fn from_libusb_container_id_descriptor(bos: *const libusb_container_id_descriptor) -> ContainerIdDescriptor {
ContainerIdDescriptor { descriptor: bos }
}

#[cfg(test)]
mod test {
use std::mem;

// The Drop trait impl calls libusb_free_config_descriptor(), which would attempt to free
// unallocated memory for a stack-allocated config descriptor. Allocating a config descriptor
// is not a simple malloc()/free() inside libusb. Mimicking libusb's allocation would be
// error-prone, difficult to maintain, and provide little benefit for the tests. It's easier to
// use mem::forget() to prevent the Drop trait impl from running. The config descriptor passed
// as `$config` should be stack-allocated to prevent memory leaks in the test suite.
macro_rules! with_bos {
($name:ident : $bos:expr => $body:block) => {
{
let $name = unsafe { super::from_libusb(&$bos) };
$body;
mem::forget($name);
}
}
}

#[test]
fn it_has_num_device_caps() {
with_bos!(bos: bos_descriptor!(bNumDeviceCaps: 3) => {
assert_eq!(3, bos.num_device_caps());
});
}
}
Loading