blob: af0042d82fb9b5d0c9bcd49d192bab24237a4c41 [file] [log] [blame] [edit]
use std::{
fmt::{self, Debug},
mem,
ptr::NonNull,
};
use libusb1_sys::*;
use crate::{
config_descriptor::{self, ConfigDescriptor},
device_descriptor::{self, DeviceDescriptor},
device_handle::DeviceHandle,
error,
fields::{self, Speed},
Error, UsbContext,
};
/// A reference to a USB device.
#[derive(Eq, PartialEq)]
pub struct Device<T: UsbContext> {
context: T,
device: NonNull<libusb_device>,
}
impl<T: UsbContext> Drop for Device<T> {
/// Releases the device reference.
fn drop(&mut self) {
unsafe {
libusb_unref_device(self.device.as_ptr());
}
}
}
impl<T: UsbContext> Clone for Device<T> {
fn clone(&self) -> Self {
unsafe { Self::from_libusb(self.context.clone(), self.device) }
}
}
unsafe impl<T: UsbContext> Send for Device<T> {}
unsafe impl<T: UsbContext> Sync for Device<T> {}
impl<T: UsbContext> Debug for Device<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let descriptor = match self.device_descriptor() {
Ok(descriptor) => descriptor,
Err(e) => {
return write!(f, "Can't read device descriptor {:?}", e);
}
};
write!(
f,
"Bus {:03} Device {:03}: ID {:04x}:{:04x}",
self.bus_number(),
self.address(),
descriptor.vendor_id(),
descriptor.product_id(),
)
}
}
impl<T: UsbContext> Device<T> {
/// Get the raw libusb_device pointer, for advanced use in unsafe code
pub fn as_raw(&self) -> *mut libusb_device {
self.device.as_ptr()
}
/// Get the context associated with this device
pub fn context(&self) -> &T {
&self.context
}
/// # Safety
///
/// Converts an existing `libusb_device` pointer into a `Device<T>`.
/// `device` must be a pointer to a valid `libusb_device`. Rusb increments refcount.
pub unsafe fn from_libusb(context: T, device: NonNull<libusb_device>) -> Device<T> {
libusb_ref_device(device.as_ptr());
Device { context, device }
}
/// Reads the device descriptor.
pub fn device_descriptor(&self) -> crate::Result<DeviceDescriptor> {
let mut descriptor = mem::MaybeUninit::<libusb_device_descriptor>::uninit();
// since libusb 1.0.16, this function always succeeds
try_unsafe!(libusb_get_device_descriptor(
self.device.as_ptr(),
descriptor.as_mut_ptr()
));
Ok(device_descriptor::from_libusb(unsafe {
descriptor.assume_init()
}))
}
/// Reads a configuration descriptor.
pub fn config_descriptor(&self, config_index: u8) -> crate::Result<ConfigDescriptor> {
let mut config = mem::MaybeUninit::<*const libusb_config_descriptor>::uninit();
try_unsafe!(libusb_get_config_descriptor(
self.device.as_ptr(),
config_index,
config.as_mut_ptr()
));
Ok(unsafe { config_descriptor::from_libusb(config.assume_init()) })
}
/// Reads the configuration descriptor for the current configuration.
pub fn active_config_descriptor(&self) -> crate::Result<ConfigDescriptor> {
let mut config = mem::MaybeUninit::<*const libusb_config_descriptor>::uninit();
try_unsafe!(libusb_get_active_config_descriptor(
self.device.as_ptr(),
config.as_mut_ptr()
));
Ok(unsafe { config_descriptor::from_libusb(config.assume_init()) })
}
/// Returns the number of the bus that the device is connected to.
pub fn bus_number(&self) -> u8 {
unsafe { libusb_get_bus_number(self.device.as_ptr()) }
}
/// Returns the device's address on the bus that it's connected to.
pub fn address(&self) -> u8 {
unsafe { libusb_get_device_address(self.device.as_ptr()) }
}
/// Returns the device's connection speed.
pub fn speed(&self) -> Speed {
fields::speed_from_libusb(unsafe { libusb_get_device_speed(self.device.as_ptr()) })
}
/// Opens the device.
pub fn open(&self) -> crate::Result<DeviceHandle<T>> {
let mut handle = mem::MaybeUninit::<*mut libusb_device_handle>::uninit();
try_unsafe!(libusb_open(self.device.as_ptr(), handle.as_mut_ptr()));
Ok(unsafe {
let ptr = NonNull::new(handle.assume_init()).ok_or(Error::NoDevice)?;
DeviceHandle::from_libusb(self.context.clone(), ptr)
})
}
/// Returns the device's port number
pub fn port_number(&self) -> u8 {
unsafe { libusb_get_port_number(self.device.as_ptr()) }
}
/// Returns the device's parent
pub fn get_parent(&self) -> Option<Self> {
let device = unsafe { libusb_get_parent(self.device.as_ptr()) };
NonNull::new(device)
.map(|device| unsafe { Device::from_libusb(self.context.clone(), device) })
}
/// Get the list of all port numbers from root for the specified device
pub fn port_numbers(&self) -> Result<Vec<u8>, Error> {
// As per the USB 3.0 specs, the current maximum limit for the depth is 7.
let mut ports = [0; 7];
let result = unsafe {
libusb_get_port_numbers(self.device.as_ptr(), ports.as_mut_ptr(), ports.len() as i32)
};
let ports_number = if result < 0 {
return Err(error::from_libusb(result));
} else {
result
};
Ok(ports[0..ports_number as usize].to_vec())
}
}