|  | 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()) | 
|  | } | 
|  | } |