diff options
Diffstat (limited to 'usb_util/src/libusb_context.rs')
-rw-r--r-- | usb_util/src/libusb_context.rs | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/usb_util/src/libusb_context.rs b/usb_util/src/libusb_context.rs new file mode 100644 index 0000000..821d2ad --- /dev/null +++ b/usb_util/src/libusb_context.rs @@ -0,0 +1,156 @@ +// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use std; + +use bindings; +use error::{Error, Result}; +use libusb_device::LibUsbDevice; +use std::sync::Arc; + +pub struct LibUsbContextInner { + context: *mut bindings::libusb_context, +} + +// Safe because libusb_context could be accessed from multiple threads safely. +unsafe impl Send for LibUsbContextInner {} +unsafe impl Sync for LibUsbContextInner {} + +impl Drop for LibUsbContextInner { + fn drop(&mut self) { + // Safe beacuse 'self.context' points to a valid context allocated by libusb_init. + unsafe { + bindings::libusb_exit(self.context); + } + } +} + +/// Wrapper for libusb_context. The libusb libary initialization/deinitialization +/// is managed by this context. +/// See: http://libusb.sourceforge.net/api-1.0/group__libusb__lib.html +#[derive(Clone)] +pub struct LibUsbContext { + inner: Arc<LibUsbContextInner>, +} + +impl LibUsbContext { + /// Create a new LibUsbContext. + pub fn new() -> Result<LibUsbContext> { + let mut ctx: *mut bindings::libusb_context = std::ptr::null_mut(); + // Safe because '&mut ctx' points to a valid memory (on stack). + try_libusb!(unsafe { bindings::libusb_init(&mut ctx) }); + Ok(LibUsbContext { + inner: Arc::new(LibUsbContextInner { context: ctx }), + }) + } + + /// Returns a list of USB devices currently attached to the system. + pub fn get_device_iter(&self) -> Result<DeviceIter> { + let mut list: *mut *mut bindings::libusb_device = std::ptr::null_mut(); + // Safe because 'inner.context' points to a valid context and '&mut list' points to a valid + // memory. + try_libusb!(unsafe { bindings::libusb_get_device_list(self.inner.context, &mut list) }); + + Ok(DeviceIter { + context: self.inner.clone(), + list, + index: 0, + }) + } + + /// Check at runtime if the loaded library has a given capability. + pub fn has_capability(&self, cap: u32) -> bool { + // Safe because libusb_init is called before this call happens. + unsafe { bindings::libusb_has_capability(cap) != 0 } + } + + /// Return an iter of poll fds. Those fds that should be polled to handle libusb events. + pub fn get_pollfd_iter(&self) -> PollFdIter { + // Safe because 'inner.context' is inited. + let list: *mut *const bindings::libusb_pollfd = + unsafe { bindings::libusb_get_pollfds(self.inner.context) }; + PollFdIter { list, index: 0 } + } + + /// Handle libusb events in a non block way. + pub fn handle_event_nonblock(&self) { + static mut zero_time: bindings::timeval = bindings::timeval { + tv_sec: 0, + tv_usec: 0, + }; + // Safe because 'inner.context' points to valid context. + unsafe { + bindings::libusb_handle_events_timeout_completed( + self.inner.context, + &mut zero_time as *mut bindings::timeval, + std::ptr::null_mut(), + ); + } + } +} + +/// Iterator for device list. +pub struct DeviceIter { + context: Arc<LibUsbContextInner>, + list: *mut *mut bindings::libusb_device, + index: isize, +} + +impl Drop for DeviceIter { + fn drop(&mut self) { + // Safe because 'self.list' is inited by a valid pointer from libusb_get_device_list. + unsafe { + bindings::libusb_free_device_list(self.list, 1); + } + } +} + +impl Iterator for DeviceIter { + type Item = LibUsbDevice; + + fn next(&mut self) -> Option<LibUsbDevice> { + // Safe becuase 'self.list' is valid, the list is null terminated. + unsafe { + let current_ptr = self.list.offset(self.index); + if (*current_ptr).is_null() { + return None; + } + self.index += 1; + Some(LibUsbDevice::new(self.context.clone(), *current_ptr)) + } + } +} + +/// Iterator for pollfds. +pub struct PollFdIter { + list: *mut *const bindings::libusb_pollfd, + index: isize, +} + +impl Drop for PollFdIter { + fn drop(&mut self) { + // Safe because 'self.list' points to valid memory of pollfd list. + unsafe { + bindings::libusb_free_pollfds(self.list); + } + } +} + +impl Iterator for PollFdIter { + type Item = bindings::libusb_pollfd; + + fn next(&mut self) -> Option<bindings::libusb_pollfd> { + // Safe because 'self.index' never grow out of the null pointer index. + unsafe { + let current_ptr = self.list.offset(self.index); + if (*current_ptr).is_null() { + return None; + } + + self.index += 1; + // Safe because 'current_ptr' is not null. + Some((**current_ptr).clone()) + } + } +} |