summary refs log tree commit diff
path: root/devices/src/usb
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 /devices/src/usb
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 'devices/src/usb')
-rw-r--r--devices/src/usb/host_backend/context.rs145
-rw-r--r--devices/src/usb/host_backend/error.rs6
-rw-r--r--devices/src/usb/host_backend/host_backend_device_provider.rs281
-rw-r--r--devices/src/usb/host_backend/host_device.rs207
-rw-r--r--devices/src/usb/host_backend/hotplug.rs45
-rw-r--r--devices/src/usb/host_backend/mod.rs2
-rw-r--r--devices/src/usb/host_backend/usb_endpoint.rs88
-rw-r--r--devices/src/usb/host_backend/utils.rs27
-rw-r--r--devices/src/usb/xhci/usb_hub.rs35
-rw-r--r--devices/src/usb/xhci/xhci_backend_device.rs4
-rw-r--r--devices/src/usb/xhci/xhci_transfer.rs9
11 files changed, 289 insertions, 560 deletions
diff --git a/devices/src/usb/host_backend/context.rs b/devices/src/usb/host_backend/context.rs
deleted file mode 100644
index 76ad4a4..0000000
--- a/devices/src/usb/host_backend/context.rs
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2019 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 super::error::*;
-use crate::utils::{EventHandler, EventLoop};
-use std::os::raw::c_short;
-use std::os::unix::io::RawFd;
-use std::sync::{Arc, Weak};
-use sys_util::{error, WatchingEvents};
-#[cfg(feature = "sandboxed-libusb")]
-use usb_util::device_handle::DeviceHandle;
-use usb_util::hotplug::UsbHotplugHandler;
-use usb_util::libusb_context::{LibUsbContext, LibUsbPollfdChangeHandler};
-#[cfg(not(feature = "sandboxed-libusb"))]
-use usb_util::libusb_device::LibUsbDevice;
-use vm_control::MaybeOwnedFd;
-
-/// Context wraps libusb context with libusb event handling.
-pub struct Context {
-    context: LibUsbContext,
-    event_loop: Arc<EventLoop>,
-    event_handler: Arc<dyn EventHandler>,
-}
-
-impl Context {
-    /// Create a new context.
-    pub fn new(event_loop: Arc<EventLoop>) -> Result<Context> {
-        let context = LibUsbContext::new().map_err(Error::CreateLibUsbContext)?;
-        let ctx = Context {
-            context: context.clone(),
-            event_loop,
-            event_handler: Arc::new(LibUsbEventHandler {
-                context: context.clone(),
-            }),
-        };
-        ctx.init_event_handler()?;
-        Ok(ctx)
-    }
-
-    pub fn set_hotplug_handler<H: UsbHotplugHandler + Sized>(&self, handler: H) {
-        if let Err(e) = self.context.set_hotplug_cb(handler) {
-            error!("cannot set hotplug handler: {:?}", e);
-        }
-    }
-
-    fn init_event_handler(&self) -> Result<()> {
-        for pollfd in self.context.get_pollfd_iter() {
-            usb_debug!("event loop add event {} events handler", pollfd.fd);
-            self.event_loop
-                .add_event(
-                    &MaybeOwnedFd::Borrowed(pollfd.fd),
-                    WatchingEvents::new(pollfd.events as u32),
-                    Arc::downgrade(&self.event_handler),
-                )
-                .map_err(Error::AddToEventLoop)?;
-        }
-
-        self.context
-            .set_pollfd_notifiers(Box::new(PollfdChangeHandler {
-                event_loop: self.event_loop.clone(),
-                event_handler: Arc::downgrade(&self.event_handler),
-            }));
-        Ok(())
-    }
-
-    /// Get libusb device with matching bus, addr, vid and pid.
-    #[cfg(not(feature = "sandboxed-libusb"))]
-    pub fn get_device(&self, bus: u8, addr: u8, vid: u16, pid: u16) -> Option<LibUsbDevice> {
-        let device_iter = match self.context.get_device_iter() {
-            Ok(iter) => iter,
-            Err(e) => {
-                error!("could not get libusb device iterator: {:?}", e);
-                return None;
-            }
-        };
-        for device in device_iter {
-            if device.get_bus_number() == bus && device.get_address() == addr {
-                if let Ok(descriptor) = device.get_device_descriptor() {
-                    if descriptor.idProduct == pid && descriptor.idVendor == vid {
-                        return Some(device);
-                    }
-                }
-            }
-        }
-        error!("device not found bus {}, addr {}", bus, addr);
-        None
-    }
-
-    #[cfg(feature = "sandboxed-libusb")]
-    pub fn get_device_handle(&self, fd: std::fs::File) -> Option<DeviceHandle> {
-        match self.context.handle_from_file(fd) {
-            Ok(handle) => Some(handle),
-            Err(e) => {
-                error!("could not build device from fd: {:?}", e);
-                None
-            }
-        }
-    }
-}
-
-struct LibUsbEventHandler {
-    context: LibUsbContext,
-}
-
-impl EventHandler for LibUsbEventHandler {
-    fn on_event(&self) -> std::result::Result<(), ()> {
-        self.context.handle_events_nonblock();
-        Ok(())
-    }
-}
-
-struct PollfdChangeHandler {
-    event_loop: Arc<EventLoop>,
-    event_handler: Weak<dyn EventHandler>,
-}
-
-impl LibUsbPollfdChangeHandler for PollfdChangeHandler {
-    fn add_poll_fd(&self, fd: RawFd, events: c_short) {
-        if let Err(e) = self.event_loop.add_event(
-            &MaybeOwnedFd::Borrowed(fd),
-            WatchingEvents::new(events as u32),
-            self.event_handler.clone(),
-        ) {
-            error!("cannot add event to event loop: {}", e);
-        }
-    }
-
-    fn remove_poll_fd(&self, fd: RawFd) {
-        if let Some(h) = self.event_handler.upgrade() {
-            if let Err(e) = h.on_event() {
-                error!("cannot handle event: {:?}", e);
-            }
-        }
-        if let Err(e) = self
-            .event_loop
-            .remove_event_for_fd(&MaybeOwnedFd::Borrowed(fd))
-        {
-            error!(
-                "failed to remove poll change handler from event loop: {}",
-                e
-            );
-        }
-    }
-}
diff --git a/devices/src/usb/host_backend/error.rs b/devices/src/usb/host_backend/error.rs
index ef097f9..3f1fed4 100644
--- a/devices/src/usb/host_backend/error.rs
+++ b/devices/src/usb/host_backend/error.rs
@@ -7,7 +7,7 @@ use crate::usb::xhci::xhci_transfer::Error as XhciTransferError;
 use crate::utils::Error as UtilsError;
 use msg_socket::MsgError;
 use std::fmt::{self, Display};
-use usb_util::error::Error as UsbUtilError;
+use usb_util::Error as UsbUtilError;
 
 #[derive(Debug)]
 pub enum Error {
@@ -19,6 +19,7 @@ pub enum Error {
     SetActiveConfig(UsbUtilError),
     SetInterfaceAltSetting(UsbUtilError),
     ClearHalt(UsbUtilError),
+    CreateTransfer(UsbUtilError),
     GetEndpointType,
     CreateControlSock(std::io::Error),
     SetupControlSock(std::io::Error),
@@ -30,7 +31,7 @@ pub enum Error {
     WriteBuffer(BufferError),
     BufferLen(BufferError),
     /// Cannot get interface descriptor for (interface, altsetting).
-    GetInterfaceDescriptor((i32, u16)),
+    GetInterfaceDescriptor((u8, u8)),
     GetEndpointDescriptor(u8),
     BadXhciTransferState,
     BadBackendProviderState,
@@ -49,6 +50,7 @@ impl Display for Error {
             SetActiveConfig(e) => write!(f, "failed to set active config: {:?}", e),
             SetInterfaceAltSetting(e) => write!(f, "failed to set interface alt setting: {:?}", e),
             ClearHalt(e) => write!(f, "failed to clear halt: {:?}", e),
+            CreateTransfer(e) => write!(f, "failed to create transfer: {:?}", e),
             GetEndpointType => write!(f, "failed to get endpoint type"),
             CreateControlSock(e) => write!(f, "failed to create contro sock: {}", e),
             SetupControlSock(e) => write!(f, "failed to setup control sock: {}", e),
diff --git a/devices/src/usb/host_backend/host_backend_device_provider.rs b/devices/src/usb/host_backend/host_backend_device_provider.rs
index f479bcb..f60983f 100644
--- a/devices/src/usb/host_backend/host_backend_device_provider.rs
+++ b/devices/src/usb/host_backend/host_backend_device_provider.rs
@@ -4,22 +4,23 @@
 
 use std::sync::Arc;
 
-use super::context::Context;
 use super::error::*;
 use super::host_device::HostDevice;
-use super::hotplug::HotplugHandler;
 use crate::usb::xhci::usb_hub::UsbHub;
 use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
 use crate::utils::AsyncJobQueue;
 use crate::utils::{EventHandler, EventLoop, FailHandle};
 use msg_socket::{MsgReceiver, MsgSender, MsgSocket};
+use std::collections::HashMap;
 use std::mem;
 use std::os::unix::io::{AsRawFd, RawFd};
 use std::time::Duration;
+use sync::Mutex;
 use sys_util::net::UnixSeqpacket;
 use sys_util::{error, WatchingEvents};
+use usb_util::Device;
 use vm_control::{
-    UsbControlAttachedDevice, UsbControlCommand, UsbControlResult, UsbControlSocket,
+    MaybeOwnedFd, UsbControlAttachedDevice, UsbControlCommand, UsbControlResult, UsbControlSocket,
     USB_CONTROL_MAX_PORTS,
 };
 
@@ -64,12 +65,15 @@ impl HostBackendDeviceProvider {
     ) -> Result<()> {
         match mem::replace(self, HostBackendDeviceProvider::Failed) {
             HostBackendDeviceProvider::Created { sock } => {
-                let ctx = Context::new(event_loop.clone())?;
-                let hotplug_handler = HotplugHandler::new(hub.clone());
-                ctx.set_hotplug_handler(hotplug_handler);
                 let job_queue =
                     AsyncJobQueue::init(&event_loop).map_err(Error::StartAsyncJobQueue)?;
-                let inner = Arc::new(ProviderInner::new(fail_handle, job_queue, ctx, sock, hub));
+                let inner = Arc::new(ProviderInner::new(
+                    fail_handle,
+                    job_queue,
+                    event_loop.clone(),
+                    sock,
+                    hub,
+                ));
                 let handler: Arc<dyn EventHandler> = inner.clone();
                 event_loop
                     .add_event(
@@ -123,25 +127,125 @@ impl XhciBackendDeviceProvider for HostBackendDeviceProvider {
 pub struct ProviderInner {
     fail_handle: Arc<dyn FailHandle>,
     job_queue: Arc<AsyncJobQueue>,
-    ctx: Context,
+    event_loop: Arc<EventLoop>,
     sock: MsgSocket<UsbControlResult, UsbControlCommand>,
     usb_hub: Arc<UsbHub>,
+
+    // Map of USB hub port number to per-device context.
+    devices: Mutex<HashMap<u8, HostDeviceContext>>,
+}
+
+struct HostDeviceContext {
+    event_handler: Arc<dyn EventHandler>,
+    device: Arc<Mutex<Device>>,
 }
 
 impl ProviderInner {
     fn new(
         fail_handle: Arc<dyn FailHandle>,
         job_queue: Arc<AsyncJobQueue>,
-        ctx: Context,
+        event_loop: Arc<EventLoop>,
         sock: MsgSocket<UsbControlResult, UsbControlCommand>,
         usb_hub: Arc<UsbHub>,
     ) -> ProviderInner {
         ProviderInner {
             fail_handle,
             job_queue,
-            ctx,
+            event_loop,
             sock,
             usb_hub,
+            devices: Mutex::new(HashMap::new()),
+        }
+    }
+
+    /// Open a usbdevfs file to create a host USB device object.
+    /// `fd` should be an open file descriptor for a file in `/dev/bus/usb`.
+    fn handle_attach_device(&self, fd: Option<MaybeOwnedFd>) -> UsbControlResult {
+        let usb_file = match fd {
+            Some(MaybeOwnedFd::Owned(file)) => file,
+            _ => {
+                error!("missing fd in UsbControlCommand::AttachDevice message");
+                return UsbControlResult::FailedToOpenDevice;
+            }
+        };
+
+        let raw_fd = usb_file.as_raw_fd();
+        let device = match Device::new(usb_file) {
+            Ok(d) => d,
+            Err(e) => {
+                error!("could not construct USB device from fd: {}", e);
+                return UsbControlResult::NoSuchDevice;
+            }
+        };
+
+        let arc_mutex_device = Arc::new(Mutex::new(device));
+
+        let event_handler: Arc<dyn EventHandler> = Arc::new(UsbUtilEventHandler {
+            device: arc_mutex_device.clone(),
+        });
+
+        if let Err(e) = self.event_loop.add_event(
+            &MaybeOwnedFd::Borrowed(raw_fd),
+            WatchingEvents::empty().set_read().set_write(),
+            Arc::downgrade(&event_handler),
+        ) {
+            error!("failed to add USB device fd to event handler: {}", e);
+            return UsbControlResult::FailedToOpenDevice;
+        }
+
+        let device_ctx = HostDeviceContext {
+            event_handler,
+            device: arc_mutex_device.clone(),
+        };
+
+        // Resetting the device is used to make sure it is in a known state, but it may
+        // still function if the reset fails.
+        if let Err(e) = arc_mutex_device.lock().reset() {
+            error!("failed to reset device after attach: {:?}", e);
+        }
+
+        let host_device = Box::new(HostDevice::new(
+            self.fail_handle.clone(),
+            self.job_queue.clone(),
+            arc_mutex_device,
+        ));
+        let port = self.usb_hub.connect_backend(host_device);
+        match port {
+            Ok(port) => {
+                self.devices.lock().insert(port, device_ctx);
+                UsbControlResult::Ok { port }
+            }
+            Err(e) => {
+                error!("failed to connect device to hub: {}", e);
+                UsbControlResult::NoAvailablePort
+            }
+        }
+    }
+
+    fn handle_detach_device(&self, port: u8) -> UsbControlResult {
+        match self.usb_hub.disconnect_port(port) {
+            Ok(()) => {
+                if let Some(device_ctx) = self.devices.lock().remove(&port) {
+                    let _ = device_ctx.event_handler.on_event();
+                    let device = device_ctx.device.lock();
+                    let fd = device.fd();
+
+                    if let Err(e) = self
+                        .event_loop
+                        .remove_event_for_fd(&MaybeOwnedFd::Borrowed(fd.as_raw_fd()))
+                    {
+                        error!(
+                            "failed to remove poll change handler from event loop: {}",
+                            e
+                        );
+                    }
+                }
+                UsbControlResult::Ok { port }
+            }
+            Err(e) => {
+                error!("failed to disconnect device from port {}: {}", port, e);
+                UsbControlResult::NoSuchDevice
+            }
         }
     }
 
@@ -168,146 +272,13 @@ impl ProviderInner {
 
     fn on_event_helper(&self) -> Result<()> {
         let cmd = self.sock.recv().map_err(Error::ReadControlSock)?;
-        match cmd {
-            UsbControlCommand::AttachDevice {
-                bus,
-                addr,
-                vid,
-                pid,
-                fd: usb_fd,
-            } => {
-                let _ = usb_fd;
-                #[cfg(not(feature = "sandboxed-libusb"))]
-                let device = match self.ctx.get_device(bus, addr, vid, pid) {
-                    Some(d) => d,
-                    None => {
-                        error!(
-                            "cannot get device bus: {}, addr: {}, vid: {}, pid: {}",
-                            bus, addr, vid, pid
-                        );
-                        // The send failure will be logged, but event loop still think the event is
-                        // handled.
-                        let _ = self
-                            .sock
-                            .send(&UsbControlResult::NoSuchDevice)
-                            .map_err(Error::WriteControlSock)?;
-                        return Ok(());
-                    }
-                };
-                #[cfg(feature = "sandboxed-libusb")]
-                let (device, device_handle) = {
-                    use vm_control::MaybeOwnedFd;
-
-                    let usb_file = match usb_fd {
-                        Some(MaybeOwnedFd::Owned(file)) => file,
-                        _ => {
-                            let _ = self
-                                .sock
-                                .send(&UsbControlResult::FailedToOpenDevice)
-                                .map_err(Error::WriteControlSock);
-                            return Ok(());
-                        }
-                    };
-
-                    let device_handle = match self.ctx.get_device_handle(usb_file) {
-                        Some(d) => d,
-                        None => {
-                            error!(
-                                "cannot get device bus: {}, addr: {}, vid: {}, pid: {}",
-                                bus, addr, vid, pid
-                            );
-                            // The send failure will be logged, but event loop still think the event
-                            // is handled.
-                            let _ = self
-                                .sock
-                                .send(&UsbControlResult::NoSuchDevice)
-                                .map_err(Error::WriteControlSock);
-                            return Ok(());
-                        }
-                    };
-
-                    let device = device_handle.get_device();
-
-                    // Resetting the device is used to make sure it is in a known state, but it may
-                    // still function if the reset fails.
-                    if let Err(e) = device_handle.reset() {
-                        error!("failed to reset device after attach: {:?}", e);
-                    }
-                    (device, device_handle)
-                };
-
-                #[cfg(not(feature = "sandboxed-libusb"))]
-                let device_handle = match device.open() {
-                    Ok(handle) => handle,
-                    Err(e) => {
-                        error!("fail to open device: {:?}", e);
-                        // The send failure will be logged, but event loop still think the event is
-                        // handled.
-                        let _ = self
-                            .sock
-                            .send(&UsbControlResult::FailedToOpenDevice)
-                            .map_err(Error::WriteControlSock);
-                        return Ok(());
-                    }
-                };
-                let device = Box::new(HostDevice::new(
-                    self.fail_handle.clone(),
-                    self.job_queue.clone(),
-                    device,
-                    device_handle,
-                ));
-                let port = self.usb_hub.connect_backend(device);
-                match port {
-                    Ok(port) => {
-                        // The send failure will be logged, but event loop still think the event is
-                        // handled.
-                        let _ = self
-                            .sock
-                            .send(&UsbControlResult::Ok { port })
-                            .map_err(Error::WriteControlSock);
-                    }
-                    Err(e) => {
-                        error!("failed to connect device to hub: {}", e);
-                        // The send failure will be logged, but event loop still think the event is
-                        // handled.
-                        let _ = self
-                            .sock
-                            .send(&UsbControlResult::NoAvailablePort)
-                            .map_err(Error::WriteControlSock);
-                    }
-                }
-                Ok(())
-            }
-            UsbControlCommand::DetachDevice { port } => {
-                match self.usb_hub.disconnect_port(port) {
-                    Ok(()) => {
-                        // The send failure will be logged, but event loop still think the event is
-                        // handled.
-                        let _ = self
-                            .sock
-                            .send(&UsbControlResult::Ok { port })
-                            .map_err(Error::WriteControlSock);
-                    }
-                    Err(e) => {
-                        error!("failed to disconnect device from port {}: {}", port, e);
-                        // The send failure will be logged, but event loop still think the event is
-                        // handled.
-                        let _ = self
-                            .sock
-                            .send(&UsbControlResult::NoSuchDevice)
-                            .map_err(Error::WriteControlSock);
-                    }
-                }
-                Ok(())
-            }
-            UsbControlCommand::ListDevice { ports } => {
-                let result = self.handle_list_devices(ports);
-                // The send failure will be logged, but event loop still think the event is
-                // handled.
-                let _ = self.sock.send(&result).map_err(Error::WriteControlSock);
-                Ok(())
-            }
-        }
+        let result = match cmd {
+            UsbControlCommand::AttachDevice { fd, .. } => self.handle_attach_device(fd),
+            UsbControlCommand::DetachDevice { port } => self.handle_detach_device(port),
+            UsbControlCommand::ListDevice { ports } => self.handle_list_devices(ports),
+        };
+        self.sock.send(&result).map_err(Error::WriteControlSock)?;
+        Ok(())
     }
 }
 
@@ -318,3 +289,13 @@ impl EventHandler for ProviderInner {
         })
     }
 }
+
+struct UsbUtilEventHandler {
+    device: Arc<Mutex<Device>>,
+}
+
+impl EventHandler for UsbUtilEventHandler {
+    fn on_event(&self) -> std::result::Result<(), ()> {
+        self.device.lock().poll_transfers().map_err(|_e| ())
+    }
+}
diff --git a/devices/src/usb/host_backend/host_device.rs b/devices/src/usb/host_backend/host_device.rs
index 8841f00..3b85ea2 100644
--- a/devices/src/usb/host_backend/host_device.rs
+++ b/devices/src/usb/host_backend/host_device.rs
@@ -4,7 +4,6 @@
 
 use std::mem::drop;
 use std::sync::Arc;
-use sync::Mutex;
 
 use super::error::*;
 use super::usb_endpoint::UsbEndpoint;
@@ -14,17 +13,14 @@ use crate::usb::xhci::xhci_backend_device::{BackendType, UsbDeviceAddress, XhciB
 use crate::usb::xhci::xhci_transfer::{XhciTransfer, XhciTransferState, XhciTransferType};
 use crate::utils::AsyncJobQueue;
 use crate::utils::FailHandle;
+use data_model::DataInit;
 use std::collections::HashMap;
+use std::mem;
+use sync::Mutex;
 use sys_util::{error, warn};
-use usb_util::device_handle::DeviceHandle;
-use usb_util::error::Error as LibUsbError;
-use usb_util::libusb_device::LibUsbDevice;
-use usb_util::types::{
-    ControlRequestDataPhaseTransferDirection, ControlRequestRecipient, StandardControlRequest,
-    UsbRequestSetup,
-};
-use usb_util::usb_transfer::{
-    control_transfer, ControlTransferBuffer, TransferStatus, UsbTransfer,
+use usb_util::{
+    ConfigDescriptorTree, ControlRequestDataPhaseTransferDirection, ControlRequestRecipient,
+    Device, StandardControlRequest, Transfer, TransferStatus, UsbRequestSetup,
 };
 
 #[derive(PartialEq)]
@@ -43,11 +39,10 @@ pub struct HostDevice {
     // Endpoints only contains data endpoints (1 to 30). Control transfers are handled at device
     // level.
     endpoints: Vec<UsbEndpoint>,
-    device: LibUsbDevice,
-    device_handle: Arc<Mutex<DeviceHandle>>,
+    device: Arc<Mutex<Device>>,
     ctl_ep_state: ControlEndpointState,
-    alt_settings: HashMap<u16, u16>,
-    claimed_interfaces: Vec<i32>,
+    alt_settings: HashMap<u8, u8>,
+    claimed_interfaces: Vec<u8>,
     control_request_setup: UsbRequestSetup,
     executed: bool,
     job_queue: Arc<AsyncJobQueue>,
@@ -64,14 +59,12 @@ impl HostDevice {
     pub fn new(
         fail_handle: Arc<dyn FailHandle>,
         job_queue: Arc<AsyncJobQueue>,
-        device: LibUsbDevice,
-        device_handle: DeviceHandle,
+        device: Arc<Mutex<Device>>,
     ) -> HostDevice {
         HostDevice {
             fail_handle,
             endpoints: vec![],
             device,
-            device_handle: Arc::new(Mutex::new(device_handle)),
             ctl_ep_state: ControlEndpointState::SetupStage,
             alt_settings: HashMap::new(),
             claimed_interfaces: vec![],
@@ -81,30 +74,6 @@ impl HostDevice {
         }
     }
 
-    fn get_interface_number_of_active_config(&self) -> i32 {
-        match self.device.get_active_config_descriptor() {
-            Err(LibUsbError::NotFound) => {
-                usb_debug!("device is in unconfigured state");
-                0
-            }
-            Err(e) => {
-                // device might be disconnected now.
-                error!("unexpected error: {:?}", e);
-                0
-            }
-            Ok(descriptor) => descriptor.bNumInterfaces as i32,
-        }
-    }
-
-    fn release_interfaces(&mut self) {
-        for i in &self.claimed_interfaces {
-            if let Err(e) = self.device_handle.lock().release_interface(*i) {
-                error!("could not release interface: {:?}", e);
-            }
-        }
-        self.claimed_interfaces = Vec::new();
-    }
-
     // Check for requests that should be intercepted and emulated using libusb
     // functions rather than passed directly to the device.
     // Returns true if the request has been intercepted or false if the request
@@ -167,20 +136,34 @@ impl HostDevice {
         xhci_transfer: Arc<XhciTransfer>,
         buffer: Option<ScatterGatherBuffer>,
     ) -> Result<()> {
-        let mut control_transfer = control_transfer(0);
-        control_transfer
-            .buffer_mut()
-            .set_request_setup(&self.control_request_setup);
-
         if self.intercepted_control_transfer(&xhci_transfer)? {
             return Ok(());
         }
 
+        // 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.
+        #[derive(Copy, Clone)]
+        #[repr(C, packed)]
+        struct ControlTransferBuffer {
+            pub setup: UsbRequestSetup,
+            pub data: [u8; CONTROL_DATA_BUFFER_SIZE],
+        }
+
+        // Safe because it only has data and has no implicit padding.
+        unsafe impl DataInit for ControlTransferBuffer {}
+
+        let mut control_request = ControlTransferBuffer {
+            setup: self.control_request_setup,
+            data: [0; CONTROL_DATA_BUFFER_SIZE],
+        };
+
         let direction = self.control_request_setup.get_direction();
         let buffer = if direction == ControlRequestDataPhaseTransferDirection::HostToDevice {
             if let Some(buffer) = buffer {
                 buffer
-                    .read(&mut control_transfer.buffer_mut().data_buffer)
+                    .read(&mut control_request.data)
                     .map_err(Error::ReadBuffer)?;
             }
             // buffer is consumed here for HostToDevice transfers.
@@ -190,8 +173,13 @@ impl HostDevice {
             buffer
         };
 
+        let control_buffer = control_request.as_slice().to_vec();
+
+        let mut control_transfer =
+            Transfer::new_control(control_buffer).map_err(Error::CreateTransfer)?;
+
         let tmp_transfer = xhci_transfer.clone();
-        let callback = move |t: UsbTransfer<ControlTransferBuffer>| {
+        let callback = move |t: Transfer| {
             usb_debug!("setup token control transfer callback invoked");
             update_transfer_state(&xhci_transfer, &t)?;
             let state = xhci_transfer.state().lock();
@@ -207,10 +195,14 @@ impl HostDevice {
                     let status = t.status();
                     let actual_length = t.actual_length();
                     if direction == ControlRequestDataPhaseTransferDirection::DeviceToHost {
-                        if let Some(buffer) = &buffer {
-                            buffer
-                                .write(&t.buffer().data_buffer)
-                                .map_err(Error::WriteBuffer)?;
+                        if let Some(control_request_data) =
+                            t.buffer.get(mem::size_of::<UsbRequestSetup>()..)
+                        {
+                            if let Some(buffer) = &buffer {
+                                buffer
+                                    .write(&control_request_data)
+                                    .map_err(Error::WriteBuffer)?;
+                            }
                         }
                     }
                     drop(state);
@@ -231,20 +223,18 @@ impl HostDevice {
         };
 
         let fail_handle = self.fail_handle.clone();
-        control_transfer.set_callback(
-            move |t: UsbTransfer<ControlTransferBuffer>| match callback(t) {
-                Ok(_) => {}
-                Err(e) => {
-                    error!("control transfer callback failed {:?}", e);
-                    fail_handle.fail();
-                }
-            },
-        );
+        control_transfer.set_callback(move |t: Transfer| match callback(t) {
+            Ok(_) => {}
+            Err(e) => {
+                error!("control transfer callback failed {:?}", e);
+                fail_handle.fail();
+            }
+        });
         submit_transfer(
             self.fail_handle.clone(),
             &self.job_queue,
             tmp_transfer,
-            &self.device_handle,
+            &mut self.device.lock(),
             control_transfer,
         )
     }
@@ -309,40 +299,50 @@ impl HostDevice {
 
     fn set_config(&mut self) -> Result<TransferStatus> {
         // It's a standard, set_config, device request.
-        let config = (self.control_request_setup.value & 0xff) as i32;
+        let config = (self.control_request_setup.value & 0xff) as u8;
         usb_debug!(
             "Set config control transfer is received with config: {}",
             config
         );
         self.release_interfaces();
         let cur_config = self
-            .device_handle
+            .device
             .lock()
             .get_active_configuration()
             .map_err(Error::GetActiveConfig)?;
         usb_debug!("current config is: {}", cur_config);
         if config != cur_config {
-            self.device_handle
+            self.device
                 .lock()
                 .set_active_configuration(config)
                 .map_err(Error::SetActiveConfig)?;
         }
-        self.claim_interfaces();
-        self.create_endpoints()?;
+        let config_descriptor = self
+            .device
+            .lock()
+            .get_active_config_descriptor()
+            .map_err(Error::GetActiveConfig)?;
+        self.claim_interfaces(&config_descriptor);
+        self.create_endpoints(&config_descriptor)?;
         Ok(TransferStatus::Completed)
     }
 
     fn set_interface(&mut self) -> Result<TransferStatus> {
         usb_debug!("set interface");
         // It's a standard, set_interface, interface request.
-        let interface = self.control_request_setup.index;
-        let alt_setting = self.control_request_setup.value;
-        self.device_handle
+        let interface = self.control_request_setup.index as u8;
+        let alt_setting = self.control_request_setup.value as u8;
+        self.device
             .lock()
-            .set_interface_alt_setting(interface as i32, alt_setting as i32)
+            .set_interface_alt_setting(interface, alt_setting)
             .map_err(Error::SetInterfaceAltSetting)?;
         self.alt_settings.insert(interface, alt_setting);
-        self.create_endpoints()?;
+        let config_descriptor = self
+            .device
+            .lock()
+            .get_active_config_descriptor()
+            .map_err(Error::GetActiveConfig)?;
+        self.create_endpoints(&config_descriptor)?;
         Ok(TransferStatus::Completed)
     }
 
@@ -352,7 +352,7 @@ impl HostDevice {
         // It's a standard, clear_feature, endpoint request.
         const STD_FEATURE_ENDPOINT_HALT: u16 = 0;
         if request_setup.value == STD_FEATURE_ENDPOINT_HALT {
-            self.device_handle
+            self.device
                 .lock()
                 .clear_halt(request_setup.index as u8)
                 .map_err(Error::ClearHalt)?;
@@ -360,9 +360,9 @@ impl HostDevice {
         Ok(TransferStatus::Completed)
     }
 
-    fn claim_interfaces(&mut self) {
-        for i in 0..self.get_interface_number_of_active_config() {
-            match self.device_handle.lock().claim_interface(i) {
+    fn claim_interfaces(&mut self, config_descriptor: &ConfigDescriptorTree) {
+        for i in 0..config_descriptor.num_interfaces() {
+            match self.device.lock().claim_interface(i) {
                 Ok(()) => {
                     usb_debug!("claimed interface {}", i);
                     self.claimed_interfaces.push(i);
@@ -374,23 +374,16 @@ impl HostDevice {
         }
     }
 
-    fn create_endpoints(&mut self) -> Result<()> {
+    fn create_endpoints(&mut self, config_descriptor: &ConfigDescriptorTree) -> Result<()> {
         self.endpoints = Vec::new();
-        let config_descriptor = match self.device.get_active_config_descriptor() {
-            Err(e) => {
-                error!("device might be disconnected: {:?}", e);
-                return Ok(());
-            }
-            Ok(descriptor) => descriptor,
-        };
         for i in &self.claimed_interfaces {
-            let alt_setting = self.alt_settings.get(&(*i as u16)).unwrap_or(&0);
+            let alt_setting = self.alt_settings.get(i).unwrap_or(&0);
             let interface = config_descriptor
-                .get_interface_descriptor(*i as u8, *alt_setting as i32)
+                .get_interface_descriptor(*i, *alt_setting)
                 .ok_or(Error::GetInterfaceDescriptor((*i, *alt_setting)))?;
             for ep_idx in 0..interface.bNumEndpoints {
                 let ep_dp = interface
-                    .endpoint_descriptor(ep_idx)
+                    .get_endpoint_descriptor(ep_idx)
                     .ok_or(Error::GetEndpointDescriptor(ep_idx))?;
                 let ep_num = ep_dp.get_endpoint_number();
                 if ep_num == 0 {
@@ -402,7 +395,7 @@ impl HostDevice {
                 self.endpoints.push(UsbEndpoint::new(
                     self.fail_handle.clone(),
                     self.job_queue.clone(),
-                    self.device_handle.clone(),
+                    self.device.clone(),
                     ep_num,
                     direction,
                     ty,
@@ -412,6 +405,15 @@ impl HostDevice {
         Ok(())
     }
 
+    fn release_interfaces(&mut self) {
+        for i in &self.claimed_interfaces {
+            if let Err(e) = self.device.lock().release_interface(*i) {
+                error!("could not release interface: {:?}", e);
+            }
+        }
+        self.claimed_interfaces = Vec::new();
+    }
+
     fn submit_transfer_helper(&mut self, transfer: XhciTransfer) -> Result<()> {
         if transfer.get_endpoint_number() == 0 {
             return self.handle_control_transfer(transfer);
@@ -430,7 +432,7 @@ impl HostDevice {
 
 impl XhciBackendDevice for HostDevice {
     fn get_backend_type(&self) -> BackendType {
-        let d = match self.device.get_device_descriptor() {
+        let d = match self.device.lock().get_device_descriptor() {
             Ok(d) => d,
             Err(_) => return BackendType::Usb2,
         };
@@ -443,16 +445,8 @@ impl XhciBackendDevice for HostDevice {
         }
     }
 
-    fn host_bus(&self) -> u8 {
-        self.device.get_bus_number()
-    }
-
-    fn host_address(&self) -> u8 {
-        self.device.get_address()
-    }
-
     fn get_vid(&self) -> u16 {
-        match self.device.get_device_descriptor() {
+        match self.device.lock().get_device_descriptor() {
             Ok(d) => d.idVendor,
             Err(e) => {
                 error!("cannot get device descriptor: {:?}", e);
@@ -462,7 +456,7 @@ impl XhciBackendDevice for HostDevice {
     }
 
     fn get_pid(&self) -> u16 {
-        match self.device.get_device_descriptor() {
+        match self.device.lock().get_device_descriptor() {
             Ok(d) => d.idProduct,
             Err(e) => {
                 error!("cannot get device descriptor: {:?}", e);
@@ -488,16 +482,9 @@ impl XhciBackendDevice for HostDevice {
 
     fn reset(&mut self) -> std::result::Result<(), ()> {
         usb_debug!("resetting host device");
-        let result = self.device_handle.lock().reset();
-        match result {
-            Err(LibUsbError::NotFound) => {
-                // libusb will return NotFound if it fails to re-claim
-                // the interface after the reset.
-                Ok(())
-            }
-            _ => result.map_err(|e| {
-                error!("failed to reset device: {:?}", e);
-            }),
-        }
+        self.device
+            .lock()
+            .reset()
+            .map_err(|e| error!("failed to reset device: {:?}", e))
     }
 }
diff --git a/devices/src/usb/host_backend/hotplug.rs b/devices/src/usb/host_backend/hotplug.rs
deleted file mode 100644
index 0764660..0000000
--- a/devices/src/usb/host_backend/hotplug.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2019 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::sync::Arc;
-
-use crate::usb::xhci::usb_hub::UsbHub;
-use sys_util::error;
-use usb_util::hotplug::{HotplugEvent, UsbHotplugHandler};
-use usb_util::libusb_device::LibUsbDevice;
-
-pub struct HotplugHandler {
-    hub: Arc<UsbHub>,
-}
-
-impl HotplugHandler {
-    pub fn new(hub: Arc<UsbHub>) -> Self {
-        HotplugHandler { hub }
-    }
-}
-
-impl UsbHotplugHandler for HotplugHandler {
-    fn hotplug_event(&self, device: LibUsbDevice, event: HotplugEvent) {
-        if event != HotplugEvent::DeviceLeft {
-            return;
-        }
-
-        let bus = device.get_bus_number();
-        let address = device.get_address();
-        let descriptor = match device.get_device_descriptor() {
-            Ok(d) => d,
-            Err(e) => {
-                error!("cannot get device descriptor: {:?}", e);
-                return;
-            }
-        };
-        let vid = descriptor.idVendor;
-        let pid = descriptor.idProduct;
-
-        if let Err(e) = self.hub.try_detach(bus, address, vid, pid) {
-            error!("device left event triggered failed detach from hub: {}", e);
-            return;
-        }
-    }
-}
diff --git a/devices/src/usb/host_backend/mod.rs b/devices/src/usb/host_backend/mod.rs
index ea0f44c..aa0f568 100644
--- a/devices/src/usb/host_backend/mod.rs
+++ b/devices/src/usb/host_backend/mod.rs
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-pub mod context;
 pub mod error;
 pub mod host_backend_device_provider;
 pub mod host_device;
-mod hotplug;
 pub mod usb_endpoint;
 mod utils;
diff --git a/devices/src/usb/host_backend/usb_endpoint.rs b/devices/src/usb/host_backend/usb_endpoint.rs
index 329d6ff..f9f06ff 100644
--- a/devices/src/usb/host_backend/usb_endpoint.rs
+++ b/devices/src/usb/host_backend/usb_endpoint.rs
@@ -4,7 +4,6 @@
 
 use std::cmp;
 use std::sync::Arc;
-use sync::Mutex;
 
 use super::error::*;
 use super::utils::{submit_transfer, update_transfer_state};
@@ -14,18 +13,17 @@ use crate::usb::xhci::xhci_transfer::{
 };
 use crate::utils::AsyncJobQueue;
 use crate::utils::FailHandle;
+use sync::Mutex;
 use sys_util::error;
-use usb_util::device_handle::DeviceHandle;
-use usb_util::types::{EndpointDirection, EndpointType, ENDPOINT_DIRECTION_OFFSET};
-use usb_util::usb_transfer::{
-    bulk_transfer, interrupt_transfer, BulkTransferBuffer, TransferStatus, UsbTransfer,
+use usb_util::{
+    Device, EndpointDirection, EndpointType, Transfer, TransferStatus, ENDPOINT_DIRECTION_OFFSET,
 };
 
 /// Isochronous, Bulk or Interrupt endpoint.
 pub struct UsbEndpoint {
     fail_handle: Arc<dyn FailHandle>,
     job_queue: Arc<AsyncJobQueue>,
-    device_handle: Arc<Mutex<DeviceHandle>>,
+    device: Arc<Mutex<Device>>,
     endpoint_number: u8,
     direction: EndpointDirection,
     ty: EndpointType,
@@ -36,7 +34,7 @@ impl UsbEndpoint {
     pub fn new(
         fail_handle: Arc<dyn FailHandle>,
         job_queue: Arc<AsyncJobQueue>,
-        device_handle: Arc<Mutex<DeviceHandle>>,
+        device: Arc<Mutex<Device>>,
         endpoint_number: u8,
         direction: EndpointDirection,
         ty: EndpointType,
@@ -45,7 +43,7 @@ impl UsbEndpoint {
         UsbEndpoint {
             fail_handle,
             job_queue,
-            device_handle,
+            device,
             endpoint_number,
             direction,
             ty,
@@ -101,13 +99,23 @@ impl UsbEndpoint {
         Ok(())
     }
 
+    fn get_transfer_buffer(&self, buffer: &ScatterGatherBuffer) -> Result<Vec<u8>> {
+        let mut v = vec![0u8; buffer.len().map_err(Error::BufferLen)?];
+        if self.direction == EndpointDirection::HostToDevice {
+            // Read data from ScatterGatherBuffer to a continuous memory.
+            buffer.read(v.as_mut_slice()).map_err(Error::ReadBuffer)?;
+        }
+        Ok(v)
+    }
+
     fn handle_bulk_transfer(
         &self,
         xhci_transfer: XhciTransfer,
         buffer: ScatterGatherBuffer,
     ) -> Result<()> {
+        let transfer_buffer = self.get_transfer_buffer(&buffer)?;
         let usb_transfer =
-            bulk_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?);
+            Transfer::new_bulk(self.ep_addr(), transfer_buffer).map_err(Error::CreateTransfer)?;
         self.do_handle_transfer(xhci_transfer, usb_transfer, buffer)
     }
 
@@ -116,32 +124,28 @@ impl UsbEndpoint {
         xhci_transfer: XhciTransfer,
         buffer: ScatterGatherBuffer,
     ) -> Result<()> {
-        let usb_transfer =
-            interrupt_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?);
+        let transfer_buffer = self.get_transfer_buffer(&buffer)?;
+        let usb_transfer = Transfer::new_interrupt(self.ep_addr(), transfer_buffer)
+            .map_err(Error::CreateTransfer)?;
         self.do_handle_transfer(xhci_transfer, usb_transfer, buffer)
     }
 
     fn do_handle_transfer(
         &self,
         xhci_transfer: XhciTransfer,
-        mut usb_transfer: UsbTransfer<BulkTransferBuffer>,
+        mut usb_transfer: Transfer,
         buffer: ScatterGatherBuffer,
     ) -> Result<()> {
         let xhci_transfer = Arc::new(xhci_transfer);
         let tmp_transfer = xhci_transfer.clone();
         match self.direction {
             EndpointDirection::HostToDevice => {
-                // Read data from ScatterGatherBuffer to a continuous memory.
-                buffer
-                    .read(usb_transfer.buffer_mut().as_mut_slice())
-                    .map_err(Error::ReadBuffer)?;
                 usb_debug!(
-                    "out transfer ep_addr {:#x}, buffer len {:?}, data {:#x?}",
+                    "out transfer ep_addr {:#x}, buffer len {:?}",
                     self.ep_addr(),
                     buffer.len(),
-                    usb_transfer.buffer_mut().as_mut_slice()
                 );
-                let callback = move |t: UsbTransfer<BulkTransferBuffer>| {
+                let callback = move |t: Transfer| {
                     usb_debug!("out transfer callback");
                     update_transfer_state(&xhci_transfer, &t)?;
                     let state = xhci_transfer.state().lock();
@@ -168,20 +172,18 @@ impl UsbEndpoint {
                     }
                 };
                 let fail_handle = self.fail_handle.clone();
-                usb_transfer.set_callback(
-                    move |t: UsbTransfer<BulkTransferBuffer>| match callback(t) {
-                        Ok(_) => {}
-                        Err(e) => {
-                            error!("bulk transfer callback failed: {:?}", e);
-                            fail_handle.fail();
-                        }
-                    },
-                );
+                usb_transfer.set_callback(move |t: Transfer| match callback(t) {
+                    Ok(_) => {}
+                    Err(e) => {
+                        error!("bulk transfer callback failed: {:?}", e);
+                        fail_handle.fail();
+                    }
+                });
                 submit_transfer(
                     self.fail_handle.clone(),
                     &self.job_queue,
                     tmp_transfer,
-                    &self.device_handle,
+                    &mut self.device.lock(),
                     usb_transfer,
                 )?;
             }
@@ -192,12 +194,8 @@ impl UsbEndpoint {
                     buffer.len()
                 );
                 let _addr = self.ep_addr();
-                let callback = move |t: UsbTransfer<BulkTransferBuffer>| {
-                    usb_debug!(
-                        "ep {:#x} in transfer data {:?}",
-                        _addr,
-                        t.buffer().as_slice()
-                    );
+                let callback = move |t: Transfer| {
+                    usb_debug!("ep {:#x} in transfer data {:?}", _addr, t.buffer.as_slice());
                     update_transfer_state(&xhci_transfer, &t)?;
                     let state = xhci_transfer.state().lock();
                     match *state {
@@ -212,7 +210,7 @@ impl UsbEndpoint {
                             let status = t.status();
                             let actual_length = t.actual_length() as usize;
                             let copied_length = buffer
-                                .write(t.buffer().as_slice())
+                                .write(t.buffer.as_slice())
                                 .map_err(Error::WriteBuffer)?;
                             let actual_length = cmp::min(actual_length, copied_length);
                             drop(state);
@@ -230,21 +228,19 @@ impl UsbEndpoint {
                 };
                 let fail_handle = self.fail_handle.clone();
 
-                usb_transfer.set_callback(
-                    move |t: UsbTransfer<BulkTransferBuffer>| match callback(t) {
-                        Ok(_) => {}
-                        Err(e) => {
-                            error!("bulk transfer callback {:?}", e);
-                            fail_handle.fail();
-                        }
-                    },
-                );
+                usb_transfer.set_callback(move |t: Transfer| match callback(t) {
+                    Ok(_) => {}
+                    Err(e) => {
+                        error!("bulk transfer callback {:?}", e);
+                        fail_handle.fail();
+                    }
+                });
 
                 submit_transfer(
                     self.fail_handle.clone(),
                     &self.job_queue,
                     tmp_transfer,
-                    &self.device_handle,
+                    &mut self.device.lock(),
                     usb_transfer,
                 )?;
             }
diff --git a/devices/src/usb/host_backend/utils.rs b/devices/src/usb/host_backend/utils.rs
index bcbec20..ac506e7 100644
--- a/devices/src/usb/host_backend/utils.rs
+++ b/devices/src/usb/host_backend/utils.rs
@@ -4,20 +4,18 @@
 
 use std::mem;
 use std::sync::Arc;
-use sync::Mutex;
 
 use super::error::*;
 use crate::usb::xhci::xhci_transfer::{XhciTransfer, XhciTransferState};
 use crate::utils::AsyncJobQueue;
 use crate::utils::FailHandle;
 use sys_util::{error, warn};
-use usb_util::device_handle::DeviceHandle;
-use usb_util::usb_transfer::{TransferStatus, UsbTransfer, UsbTransferBuffer};
+use usb_util::{Device, Transfer, TransferStatus};
 
 /// Helper function to update xhci_transfer state.
-pub fn update_transfer_state<T: UsbTransferBuffer>(
+pub fn update_transfer_state(
     xhci_transfer: &Arc<XhciTransfer>,
-    usb_transfer: &UsbTransfer<T>,
+    usb_transfer: &Transfer,
 ) -> Result<()> {
     let status = usb_transfer.status();
     let mut state = xhci_transfer.state().lock();
@@ -44,12 +42,12 @@ pub fn update_transfer_state<T: UsbTransferBuffer>(
 }
 
 /// Helper function to submit usb_transfer to device handle.
-pub fn submit_transfer<T: UsbTransferBuffer>(
+pub fn submit_transfer(
     fail_handle: Arc<dyn FailHandle>,
     job_queue: &Arc<AsyncJobQueue>,
     xhci_transfer: Arc<XhciTransfer>,
-    device_handle: &Arc<Mutex<DeviceHandle>>,
-    usb_transfer: UsbTransfer<T>,
+    device: &mut Device,
+    usb_transfer: Transfer,
 ) -> Result<()> {
     let transfer_status = {
         // We need to hold the lock to avoid race condition.
@@ -58,7 +56,7 @@ pub fn submit_transfer<T: UsbTransferBuffer>(
         let mut state = xhci_transfer.state().lock();
         match mem::replace(&mut *state, XhciTransferState::Cancelled) {
             XhciTransferState::Created => {
-                match device_handle.lock().submit_async_transfer(usb_transfer) {
+                match device.submit_transfer(usb_transfer) {
                     Err(e) => {
                         error!("fail to submit transfer {:?}", e);
                         *state = XhciTransferState::Completed;
@@ -66,13 +64,12 @@ pub fn submit_transfer<T: UsbTransferBuffer>(
                     }
                     // If it's submitted, we don't need to send on_transfer_complete now.
                     Ok(canceller) => {
-                        // TODO(jkwang) refactor canceller to return Cancel::Ok or Cancel::Err.
-                        let cancel_callback = Box::new(move || match canceller.try_cancel() {
-                            true => {
-                                usb_debug!("cancel issued to libusb backend");
+                        let cancel_callback = Box::new(move || match canceller.cancel() {
+                            Ok(()) => {
+                                usb_debug!("cancel issued to kernel");
                             }
-                            false => {
-                                usb_debug!("fail to cancel");
+                            Err(e) => {
+                                usb_debug!("fail to cancel: {}", e);
                             }
                         });
                         *state = XhciTransferState::Submitted { cancel_callback };
diff --git a/devices/src/usb/xhci/usb_hub.rs b/devices/src/usb/xhci/usb_hub.rs
index 28c7f19..d54eaa9 100644
--- a/devices/src/usb/xhci/usb_hub.rs
+++ b/devices/src/usb/xhci/usb_hub.rs
@@ -205,41 +205,6 @@ impl UsbHub {
         UsbHub { ports }
     }
 
-    /// Try to detach device of bus, addr, vid, pid
-    pub fn try_detach(&self, bus: u8, addr: u8, vid: u16, pid: u16) -> Result<()> {
-        for port in &self.ports {
-            // This block exists so that we only hold the backend device
-            // lock while checking the address. It needs to be dropped before
-            // calling port.detach(), because that acquires the backend
-            // device lock again.
-            {
-                let backend_device = port.get_backend_device();
-
-                let d = match backend_device.as_ref() {
-                    None => continue,
-                    Some(d) => d,
-                };
-
-                if d.host_bus() != bus
-                    || d.host_address() != addr
-                    || d.get_vid() != vid
-                    || d.get_pid() != pid
-                {
-                    continue;
-                }
-            }
-
-            return port.detach();
-        }
-
-        Err(Error::NoSuchDevice {
-            bus,
-            addr,
-            vid,
-            pid,
-        })
-    }
-
     /// Reset all ports.
     pub fn reset(&self) -> Result<()> {
         usb_debug!("reseting usb hub");
diff --git a/devices/src/usb/xhci/xhci_backend_device.rs b/devices/src/usb/xhci/xhci_backend_device.rs
index e104cdc..a3d9e66 100644
--- a/devices/src/usb/xhci/xhci_backend_device.rs
+++ b/devices/src/usb/xhci/xhci_backend_device.rs
@@ -18,10 +18,6 @@ pub enum BackendType {
 pub trait XhciBackendDevice: Send {
     /// Returns the type of USB device provided by this device.
     fn get_backend_type(&self) -> BackendType;
-    /// Returns host bus number of this device.
-    fn host_bus(&self) -> u8;
-    /// Returns host address of this device.
-    fn host_address(&self) -> u8;
     /// Get vendor id of this device.
     fn get_vid(&self) -> u16;
     /// Get product id of this device.
diff --git a/devices/src/usb/xhci/xhci_transfer.rs b/devices/src/usb/xhci/xhci_transfer.rs
index fa6d5de..625f97e 100644
--- a/devices/src/usb/xhci/xhci_transfer.rs
+++ b/devices/src/usb/xhci/xhci_transfer.rs
@@ -17,8 +17,7 @@ use std::mem;
 use std::sync::{Arc, Weak};
 use sync::Mutex;
 use sys_util::{error, Error as SysError, EventFd, GuestMemory};
-use usb_util::types::UsbRequestSetup;
-use usb_util::usb_transfer::TransferStatus;
+use usb_util::{TransferStatus, UsbRequestSetup};
 
 #[derive(Debug)]
 pub enum Error {
@@ -67,7 +66,7 @@ pub enum XhciTransferState {
     /// When transfer is submitted, it will contain a transfer callback, which should be invoked
     /// when the transfer is cancelled.
     Submitted {
-        cancel_callback: Box<dyn FnMut() + Send>,
+        cancel_callback: Box<dyn FnOnce() + Send>,
     },
     Cancelling,
     Cancelled,
@@ -78,9 +77,7 @@ impl XhciTransferState {
     /// Try to cancel this transfer, if it's possible.
     pub fn try_cancel(&mut self) {
         match mem::replace(self, XhciTransferState::Created) {
-            XhciTransferState::Submitted {
-                mut cancel_callback,
-            } => {
+            XhciTransferState::Submitted { cancel_callback } => {
                 *self = XhciTransferState::Cancelling;
                 cancel_callback();
             }