diff options
Diffstat (limited to 'usb_util/src/usb_transfer.rs')
-rw-r--r-- | usb_util/src/usb_transfer.rs | 382 |
1 files changed, 0 insertions, 382 deletions
diff --git a/usb_util/src/usb_transfer.rs b/usb_util/src/usb_transfer.rs deleted file mode 100644 index e3ca623..0000000 --- a/usb_util/src/usb_transfer.rs +++ /dev/null @@ -1,382 +0,0 @@ -// 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::mem::size_of; -use std::os::raw::c_void; -use std::sync::{Arc, Weak}; - -use crate::bindings::{ - libusb_alloc_transfer, libusb_cancel_transfer, libusb_device_handle, libusb_free_transfer, - libusb_submit_transfer, libusb_transfer, libusb_transfer_status, LIBUSB_TRANSFER_CANCELLED, - LIBUSB_TRANSFER_COMPLETED, LIBUSB_TRANSFER_ERROR, LIBUSB_TRANSFER_NO_DEVICE, - LIBUSB_TRANSFER_OVERFLOW, LIBUSB_TRANSFER_STALL, LIBUSB_TRANSFER_TIMED_OUT, - LIBUSB_TRANSFER_TYPE_BULK, LIBUSB_TRANSFER_TYPE_CONTROL, LIBUSB_TRANSFER_TYPE_INTERRUPT, -}; -use crate::error::{Error, Result}; -use crate::types::UsbRequestSetup; - -/// Status of transfer. -#[derive(PartialEq)] -pub enum TransferStatus { - Completed, - Error, - TimedOut, - Cancelled, - Stall, - NoDevice, - Overflow, -} - -impl From<libusb_transfer_status> for TransferStatus { - fn from(s: libusb_transfer_status) -> Self { - match s { - LIBUSB_TRANSFER_COMPLETED => TransferStatus::Completed, - LIBUSB_TRANSFER_ERROR => TransferStatus::Error, - LIBUSB_TRANSFER_TIMED_OUT => TransferStatus::TimedOut, - LIBUSB_TRANSFER_CANCELLED => TransferStatus::Cancelled, - LIBUSB_TRANSFER_STALL => TransferStatus::Stall, - LIBUSB_TRANSFER_NO_DEVICE => TransferStatus::NoDevice, - LIBUSB_TRANSFER_OVERFLOW => TransferStatus::Overflow, - _ => TransferStatus::Error, - } - } -} - -/// Trait for usb transfer buffer. -pub trait UsbTransferBuffer: Send { - fn as_ptr(&mut self) -> *mut u8; - fn len(&self) -> i32; -} - -/// Default buffer size for control data transfer. -const CONTROL_DATA_BUFFER_SIZE: usize = 1024; - -/// Buffer type for control transfer. The first 8-bytes is a UsbRequestSetup struct. -#[repr(C, packed)] -pub struct ControlTransferBuffer { - pub setup_buffer: UsbRequestSetup, - pub data_buffer: [u8; CONTROL_DATA_BUFFER_SIZE], -} - -impl ControlTransferBuffer { - fn new() -> ControlTransferBuffer { - ControlTransferBuffer { - setup_buffer: UsbRequestSetup { - request_type: 0, - request: 0, - value: 0, - index: 0, - length: 0, - }, - data_buffer: [0; CONTROL_DATA_BUFFER_SIZE], - } - } - - /// Set request setup for this control buffer. - pub fn set_request_setup(&mut self, request_setup: &UsbRequestSetup) { - self.setup_buffer = *request_setup; - } -} - -impl UsbTransferBuffer for ControlTransferBuffer { - fn as_ptr(&mut self) -> *mut u8 { - self as *mut ControlTransferBuffer as *mut u8 - } - - fn len(&self) -> i32 { - if self.setup_buffer.length as usize > CONTROL_DATA_BUFFER_SIZE { - panic!("Setup packet has an oversize length"); - } - self.setup_buffer.length as i32 + size_of::<UsbRequestSetup>() as i32 - } -} - -/// Buffer type for Bulk transfer. -pub struct BulkTransferBuffer { - buffer: Vec<u8>, -} - -impl BulkTransferBuffer { - fn with_size(buffer_size: usize) -> Self { - BulkTransferBuffer { - buffer: vec![0; buffer_size], - } - } - - /// Get mutable interal slice of this buffer. - pub fn as_mut_slice(&mut self) -> &mut [u8] { - &mut self.buffer - } - - /// Get interal slice of this buffer. - pub fn as_slice(&self) -> &[u8] { - &self.buffer - } -} - -impl UsbTransferBuffer for BulkTransferBuffer { - fn as_ptr(&mut self) -> *mut u8 { - if self.buffer.len() == 0 { - // Vec::as_mut_ptr() won't give 0x0 even if len() is 0. - std::ptr::null_mut() - } else { - self.buffer.as_mut_ptr() - } - } - - fn len(&self) -> i32 { - self.buffer.len() as i32 - } -} - -type UsbTransferCompletionCallback<T> = dyn Fn(UsbTransfer<T>) + Send + 'static; - -// This wraps libusb_transfer pointer. -struct LibUsbTransfer { - ptr: *mut libusb_transfer, -} - -impl Drop for LibUsbTransfer { - fn drop(&mut self) { - // Safe because 'self.ptr' is allocated by libusb_alloc_transfer. - unsafe { - libusb_free_transfer(self.ptr); - } - } -} - -// It is safe to invoke libusb functions from multiple threads. -// We cannot modify libusb_transfer safely from multiple threads. All the modifications happens -// in construct (UsbTransfer::new) or consume (UsbTransfer::into_raw), we can consider this thread -// safe. -unsafe impl Send for LibUsbTransfer {} -unsafe impl Sync for LibUsbTransfer {} - -/// TransferCanceller can cancel the transfer. -pub struct TransferCanceller { - transfer: Weak<LibUsbTransfer>, -} - -impl TransferCanceller { - /// Return false if fail to cancel. - pub fn try_cancel(&self) -> bool { - match self.transfer.upgrade() { - Some(t) => { - // Safe because self.transfer has ownership of the raw pointer. - let r = unsafe { libusb_cancel_transfer(t.ptr) }; - if r == 0 { - true - } else { - false - } - } - None => false, - } - } -} - -struct UsbTransferInner<T: UsbTransferBuffer> { - transfer: Arc<LibUsbTransfer>, - callback: Option<Box<UsbTransferCompletionCallback<T>>>, - buffer: T, -} - -/// UsbTransfer owns a LibUsbTransfer, it's buffer and callback. -pub struct UsbTransfer<T: UsbTransferBuffer> { - inner: Box<UsbTransferInner<T>>, -} - -/// Build a control transfer. -pub fn control_transfer(timeout: u32) -> UsbTransfer<ControlTransferBuffer> { - UsbTransfer::<ControlTransferBuffer>::new( - 0, - LIBUSB_TRANSFER_TYPE_CONTROL as u8, - timeout, - ControlTransferBuffer::new(), - ) -} - -/// Build a data transfer. -pub fn bulk_transfer(endpoint: u8, timeout: u32, size: usize) -> UsbTransfer<BulkTransferBuffer> { - UsbTransfer::<BulkTransferBuffer>::new( - endpoint, - LIBUSB_TRANSFER_TYPE_BULK as u8, - timeout, - BulkTransferBuffer::with_size(size), - ) -} - -/// Build a data transfer. -pub fn interrupt_transfer( - endpoint: u8, - timeout: u32, - size: usize, -) -> UsbTransfer<BulkTransferBuffer> { - UsbTransfer::<BulkTransferBuffer>::new( - endpoint, - LIBUSB_TRANSFER_TYPE_INTERRUPT as u8, - timeout, - BulkTransferBuffer::with_size(size), - ) -} - -impl<T: UsbTransferBuffer> UsbTransfer<T> { - fn new(endpoint: u8, type_: u8, timeout: u32, buffer: T) -> Self { - // Safe because alloc is safe. - let transfer: *mut libusb_transfer = unsafe { libusb_alloc_transfer(0) }; - // Just panic on OOM. - assert!(!transfer.is_null()); - let inner = Box::new(UsbTransferInner { - transfer: Arc::new(LibUsbTransfer { ptr: transfer }), - callback: None, - buffer, - }); - // Safe because we inited transfer. - let raw_transfer: &mut libusb_transfer = unsafe { &mut *(inner.transfer.ptr) }; - raw_transfer.endpoint = endpoint; - raw_transfer.type_ = type_; - raw_transfer.timeout = timeout; - raw_transfer.callback = Some(UsbTransfer::<T>::on_transfer_completed); - UsbTransfer { inner } - } - - /// Set callback function for transfer completion. - pub fn set_callback<C: 'static + Fn(UsbTransfer<T>) + Send>(&mut self, cb: C) { - self.inner.callback = Some(Box::new(cb)); - } - - /// Get a reference to the buffer. - pub fn buffer(&self) -> &T { - &self.inner.buffer - } - - /// Get a mutable reference to the buffer. - pub fn buffer_mut(&mut self) -> &mut T { - &mut self.inner.buffer - } - - /// Get actual length of data that was transferred. - pub fn actual_length(&self) -> i32 { - let transfer = self.inner.transfer.ptr; - // Safe because inner.ptr is always allocated by libusb_alloc_transfer. - unsafe { (*transfer).actual_length } - } - - /// Get the transfer status of this transfer. - pub fn status(&self) -> TransferStatus { - let transfer = self.inner.transfer.ptr; - // Safe because inner.ptr is always allocated by libusb_alloc_transfer. - unsafe { TransferStatus::from((*transfer).status) } - } - - /// Submit this transfer to device handle. 'self' is consumed. On success, the memory will be - /// 'leaked' (and stored in user_data) and sent to libusb, when the async operation is done, - /// on_transfer_completed will recreate 'self' and deliver it to callback/free 'self'. On - /// faliure, 'self' is returned with an error. - /// - /// # Safety - /// - /// Assumes libusb_device_handle is an handled opened by libusb, self.inner.transfer.ptr is - /// initialized with correct buffer and length. - pub unsafe fn submit(self, handle: *mut libusb_device_handle) -> Result<TransferCanceller> { - let weak_transfer = Arc::downgrade(&self.inner.transfer); - let transfer = self.into_raw(); - (*transfer).dev_handle = handle; - match Error::from(libusb_submit_transfer(transfer)) { - Error::Success(_e) => Ok(TransferCanceller { - transfer: weak_transfer, - }), - err => { - UsbTransfer::<T>::from_raw(transfer); - Err(err) - } - } - } - - /// Invoke callback when transfer is completed. - /// - /// # Safety - /// - /// Assumes libusb_tranfser is finished. This function is called by libusb, don't call it - /// manually. - unsafe extern "C" fn on_transfer_completed(transfer: *mut libusb_transfer) { - let mut transfer = UsbTransfer::<T>::from_raw(transfer); - // Callback is reset to None. - if let Some(cb) = transfer.inner.callback.take() { - cb(transfer); - } - } - - fn into_raw(mut self) -> *mut libusb_transfer { - let transfer: *mut libusb_transfer = self.inner.transfer.ptr; - // Safe because transfer is allocated by libusb_alloc_transfer. - unsafe { - (*transfer).buffer = self.buffer_mut().as_ptr(); - (*transfer).length = self.buffer_mut().len(); - (*transfer).user_data = Box::into_raw(self.inner) as *mut c_void; - } - transfer - } - - unsafe fn from_raw(transfer: *mut libusb_transfer) -> Self { - UsbTransfer { - inner: Box::<UsbTransferInner<T>>::from_raw( - (*transfer).user_data as *mut UsbTransferInner<T>, - ), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::sync::Mutex; - - pub fn fake_submit_transfer<T: UsbTransferBuffer>(transfer: UsbTransfer<T>) { - let transfer = transfer.into_raw(); - unsafe { - match (*transfer).callback { - Some(cb) => cb(transfer), - // Although no callback is invoked, we still need on_transfer_completed to - // free memory. - None => panic!("Memory leak!"), - }; - } - } - - #[test] - fn check_control_buffer_size() { - assert_eq!( - size_of::<ControlTransferBuffer>(), - size_of::<UsbRequestSetup>() + CONTROL_DATA_BUFFER_SIZE - ); - } - - #[test] - fn submit_transfer_no_callback_test() { - let t = control_transfer(0); - fake_submit_transfer(t); - let t = bulk_transfer(0, 0, 1); - fake_submit_transfer(t); - } - - struct FakeTransferController { - data: Mutex<u8>, - } - - #[test] - fn submit_transfer_with_callback() { - let c = Arc::new(FakeTransferController { - data: Mutex::new(0), - }); - let c1 = Arc::downgrade(&c); - let mut t = control_transfer(0); - t.set_callback(move |_t| { - let c = c1.upgrade().unwrap(); - *c.data.lock().unwrap() = 3; - }); - fake_submit_transfer(t); - assert_eq!(*c.data.lock().unwrap(), 3); - } -} |