Skip to content

Commit

Permalink
Add DeviceHandle::into_raw()
Browse files Browse the repository at this point in the history
As exotic as it may be, libusbredir requires to give the device handle
ownership to the library. This function helps to achieve this, without
having to leak the a DeviceHandle with mem::forget.

Signed-off-by: Marc-André Lureau <[email protected]>
  • Loading branch information
elmarco committed Aug 1, 2021
1 parent 009254b commit eaac734
Showing 1 changed file with 39 additions and 25 deletions.
64 changes: 39 additions & 25 deletions src/device_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl<'a> Iterator for ClaimedInterfacesIter<'a> {
#[derive(Eq, PartialEq)]
pub struct DeviceHandle<T: UsbContext> {
context: T,
handle: NonNull<libusb_device_handle>,
handle: Option<NonNull<libusb_device_handle>>,
interfaces: ClaimedInterfaces,
}

Expand All @@ -116,10 +116,12 @@ impl<T: UsbContext> Drop for DeviceHandle<T> {
fn drop(&mut self) {
unsafe {
for iface in self.interfaces.iter() {
libusb_release_interface(self.handle.as_ptr(), iface as c_int);
libusb_release_interface(self.as_raw(), iface as c_int);
}

libusb_close(self.handle.as_ptr());
if self.handle.is_some() {
libusb_close(self.as_raw());
}
}
}
}
Expand All @@ -143,7 +145,19 @@ impl<T: UsbContext> DeviceHandle<T> {
/// This structure tracks claimed interfaces, and will get out if sync if interfaces are
/// manipulated externally. Use only libusb endpoint IO functions.
pub fn as_raw(&self) -> *mut libusb_device_handle {
self.handle.as_ptr()
// Safety: handle is Some() after initialization
self.handle.unwrap().as_ptr()
}

/// Consumes the `DeviceHandle`, returning the raw libusb_device_handle
/// pointer, for advanced use in unsafe code.
///
/// # Safety
///
/// Panics if you have any claimed interfaces on this handle.
pub fn into_raw(mut self) -> *mut libusb_device_handle {
assert_eq!(self.interfaces.size(), 0);
self.handle.take().unwrap().as_ptr()
}

/// Get the context associated with this device
Expand All @@ -156,7 +170,7 @@ impl<T: UsbContext> DeviceHandle<T> {
unsafe {
device::Device::from_libusb(
self.context.clone(),
std::ptr::NonNull::new_unchecked(libusb_get_device(self.handle.as_ptr())),
std::ptr::NonNull::new_unchecked(libusb_get_device(self.as_raw())),
)
}
}
Expand All @@ -171,7 +185,7 @@ impl<T: UsbContext> DeviceHandle<T> {
) -> DeviceHandle<T> {
DeviceHandle {
context,
handle,
handle: Some(handle),
interfaces: ClaimedInterfaces::new(),
}
}
Expand All @@ -181,7 +195,7 @@ impl<T: UsbContext> DeviceHandle<T> {
let mut config = mem::MaybeUninit::<c_int>::uninit();

try_unsafe!(libusb_get_configuration(
self.handle.as_ptr(),
self.as_raw(),
config.as_mut_ptr()
));
Ok(unsafe { config.assume_init() } as u8)
Expand All @@ -190,35 +204,35 @@ impl<T: UsbContext> DeviceHandle<T> {
/// Sets the device's active configuration.
pub fn set_active_configuration(&mut self, config: u8) -> crate::Result<()> {
try_unsafe!(libusb_set_configuration(
self.handle.as_ptr(),
self.as_raw(),
c_int::from(config)
));
Ok(())
}

/// Puts the device in an unconfigured state.
pub fn unconfigure(&mut self) -> crate::Result<()> {
try_unsafe!(libusb_set_configuration(self.handle.as_ptr(), -1));
try_unsafe!(libusb_set_configuration(self.as_raw(), -1));
Ok(())
}

/// Resets the device.
pub fn reset(&mut self) -> crate::Result<()> {
try_unsafe!(libusb_reset_device(self.handle.as_ptr()));
try_unsafe!(libusb_reset_device(self.as_raw()));
Ok(())
}

/// Clear the halt/stall condition for an endpoint.
pub fn clear_halt(&mut self, endpoint: u8) -> crate::Result<()> {
try_unsafe!(libusb_clear_halt(self.handle.as_ptr(), endpoint));
try_unsafe!(libusb_clear_halt(self.as_raw(), endpoint));
Ok(())
}

/// Indicates whether the device has an attached kernel driver.
///
/// This method is not supported on all platforms.
pub fn kernel_driver_active(&self, iface: u8) -> crate::Result<bool> {
match unsafe { libusb_kernel_driver_active(self.handle.as_ptr(), c_int::from(iface)) } {
match unsafe { libusb_kernel_driver_active(self.as_raw(), c_int::from(iface)) } {
0 => Ok(false),
1 => Ok(true),
err => Err(error::from_libusb(err)),
Expand All @@ -230,7 +244,7 @@ impl<T: UsbContext> DeviceHandle<T> {
/// This method is not supported on all platforms.
pub fn detach_kernel_driver(&mut self, iface: u8) -> crate::Result<()> {
try_unsafe!(libusb_detach_kernel_driver(
self.handle.as_ptr(),
self.as_raw(),
c_int::from(iface)
));
Ok(())
Expand All @@ -241,7 +255,7 @@ impl<T: UsbContext> DeviceHandle<T> {
/// This method is not supported on all platforms.
pub fn attach_kernel_driver(&mut self, iface: u8) -> crate::Result<()> {
try_unsafe!(libusb_attach_kernel_driver(
self.handle.as_ptr(),
self.as_raw(),
c_int::from(iface)
));
Ok(())
Expand All @@ -258,7 +272,7 @@ impl<T: UsbContext> DeviceHandle<T> {
/// this function was never called.
pub fn set_auto_detach_kernel_driver(&mut self, auto_detach: bool) -> crate::Result<()> {
try_unsafe!(libusb_set_auto_detach_kernel_driver(
self.handle.as_ptr(),
self.as_raw(),
auto_detach.into()
));
Ok(())
Expand All @@ -270,7 +284,7 @@ impl<T: UsbContext> DeviceHandle<T> {
/// when the device handle goes out of scope.
pub fn claim_interface(&mut self, iface: u8) -> crate::Result<()> {
try_unsafe!(libusb_claim_interface(
self.handle.as_ptr(),
self.as_raw(),
c_int::from(iface)
));
self.interfaces.insert(iface);
Expand All @@ -280,7 +294,7 @@ impl<T: UsbContext> DeviceHandle<T> {
/// Releases a claimed interface.
pub fn release_interface(&mut self, iface: u8) -> crate::Result<()> {
try_unsafe!(libusb_release_interface(
self.handle.as_ptr(),
self.as_raw(),
c_int::from(iface)
));
self.interfaces.remove(iface);
Expand All @@ -290,7 +304,7 @@ impl<T: UsbContext> DeviceHandle<T> {
/// Sets an interface's active setting.
pub fn set_alternate_setting(&mut self, iface: u8, setting: u8) -> crate::Result<()> {
try_unsafe!(libusb_set_interface_alt_setting(
self.handle.as_ptr(),
self.as_raw(),
c_int::from(iface),
c_int::from(setting)
));
Expand Down Expand Up @@ -331,7 +345,7 @@ impl<T: UsbContext> DeviceHandle<T> {
let mut transferred = mem::MaybeUninit::<c_int>::uninit();
unsafe {
match libusb_interrupt_transfer(
self.handle.as_ptr(),
self.as_raw(),
endpoint,
buf.as_mut_ptr() as *mut c_uchar,
buf.len() as c_int,
Expand Down Expand Up @@ -384,7 +398,7 @@ impl<T: UsbContext> DeviceHandle<T> {
let mut transferred = mem::MaybeUninit::<c_int>::uninit();
unsafe {
match libusb_interrupt_transfer(
self.handle.as_ptr(),
self.as_raw(),
endpoint,
buf.as_ptr() as *mut c_uchar,
buf.len() as c_int,
Expand Down Expand Up @@ -439,7 +453,7 @@ impl<T: UsbContext> DeviceHandle<T> {
let mut transferred = mem::MaybeUninit::<c_int>::uninit();
unsafe {
match libusb_bulk_transfer(
self.handle.as_ptr(),
self.as_raw(),
endpoint,
buf.as_mut_ptr() as *mut c_uchar,
buf.len() as c_int,
Expand Down Expand Up @@ -487,7 +501,7 @@ impl<T: UsbContext> DeviceHandle<T> {
let mut transferred = mem::MaybeUninit::<c_int>::uninit();
unsafe {
match libusb_bulk_transfer(
self.handle.as_ptr(),
self.as_raw(),
endpoint,
buf.as_ptr() as *mut c_uchar,
buf.len() as c_int,
Expand Down Expand Up @@ -549,7 +563,7 @@ impl<T: UsbContext> DeviceHandle<T> {
}
let res = unsafe {
libusb_control_transfer(
self.handle.as_ptr(),
self.as_raw(),
request_type,
request,
value,
Expand Down Expand Up @@ -607,7 +621,7 @@ impl<T: UsbContext> DeviceHandle<T> {
}
let res = unsafe {
libusb_control_transfer(
self.handle.as_ptr(),
self.as_raw(),
request_type,
request,
value,
Expand Down Expand Up @@ -668,7 +682,7 @@ impl<T: UsbContext> DeviceHandle<T> {
let capacity = buf.capacity() as i32;

let res = unsafe {
libusb_get_string_descriptor_ascii(self.handle.as_ptr(), index, ptr, capacity)
libusb_get_string_descriptor_ascii(self.as_raw(), index, ptr, capacity)
};

if res < 0 {
Expand Down

0 comments on commit eaac734

Please sign in to comment.