summary refs log tree commit diff
path: root/usb_util/src/usb_transfer.rs
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2019-07-09 17:21:54 -0700
committerCommit Bot <commit-bot@chromium.org>2019-10-17 00:20:24 +0000
commit6494117e1766337f5d688b98bfc3df999932c3ac (patch)
tree0c8b6fd24a615ae146bb0a2d6f4d8ce332f5cc42 /usb_util/src/usb_transfer.rs
parentbed8b0017d2cb283c20dc50241adb4f5b2668489 (diff)
downloadcrosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.gz
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.bz2
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.lz
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.xz
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.tar.zst
crosvm-6494117e1766337f5d688b98bfc3df999932c3ac.zip
usb: replace libusb with Rust usb_util library
Drop the dependency on libusb and reimplement the host USB backend using
usb_sys to wrap the Linux usbdevfs ioctls.

This allows sandboxing to work without any dependency on libusb patches,
and it gives us the flexibility to modify and update the USB backend
without depending on an external third-party library.

BUG=chromium:987833
TEST=`adb logcat` on nami with Nexus 5 attached
TEST=deploy app to phone with Android Studio
TEST=Run EdgeTPU USB accelerator demo (including DFU mode transition)

Cq-Depend: chromium:1773695
Change-Id: I4321c2b6142caac15f48f197795a37d59d268831
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1783601
Reviewed-by: Zach Reizner <zachr@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Diffstat (limited to 'usb_util/src/usb_transfer.rs')
-rw-r--r--usb_util/src/usb_transfer.rs382
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);
-    }
-}