summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--devices/src/usb/host_backend/context.rs157
-rw-r--r--devices/src/usb/host_backend/error.rs78
-rw-r--r--devices/src/usb/host_backend/host_backend_device_provider.rs324
-rw-r--r--devices/src/usb/host_backend/host_device.rs541
-rw-r--r--devices/src/usb/host_backend/hotplug.rs45
-rw-r--r--devices/src/usb/host_backend/mod.rs11
-rw-r--r--devices/src/usb/host_backend/usb_endpoint.rs253
-rw-r--r--devices/src/usb/host_backend/utils.rs109
-rw-r--r--devices/src/usb/mod.rs3
-rw-r--r--devices/src/usb/xhci/mod.rs12
-rw-r--r--devices/src/usb/xhci/xhci_transfer.rs4
-rw-r--r--vm_control/Cargo.toml3
-rw-r--r--vm_control/src/lib.rs60
13 files changed, 1588 insertions, 12 deletions
diff --git a/devices/src/usb/host_backend/context.rs b/devices/src/usb/host_backend/context.rs
new file mode 100644
index 0000000..3fd8d3d
--- /dev/null
+++ b/devices/src/usb/host_backend/context.rs
@@ -0,0 +1,157 @@
+// 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 std::os::raw::c_short;
+use std::os::unix::io::RawFd;
+use std::sync::{Arc, Weak};
+use sys_util::WatchingEvents;
+use usb::usb_util::hotplug::UsbHotplugHandler;
+use usb::usb_util::libusb_context::{LibUsbContext, LibUsbPollfdChangeHandler};
+use usb::usb_util::libusb_device::LibUsbDevice;
+use utils::{EventHandler, EventLoop};
+use vm_control::MaybeOwnedFd;
+
+/// Context wraps libusb context with libusb event handling.
+pub struct Context {
+    context: LibUsbContext,
+    event_loop: Arc<EventLoop>,
+    event_handler: Arc<EventHandler>,
+}
+
+impl Context {
+    /// Create a new context.
+    #[cfg(not(feature = "sandboxed-libusb"))]
+    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)
+    }
+
+    #[cfg(feature = "sandboxed-libusb")]
+    pub fn new(event_loop: Arc<EventLoop>) -> Result<Context> {
+        let context = LibUsbContext::new_jailed().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(&self, fd: std::fs::File) -> Option<LibUsbDevice> {
+        match self.context.get_device_from_fd(fd) {
+            Ok(dev) => Some(dev),
+            Err(e) => {
+                error!("could not build device from fd: {:?}", e);
+                None
+            }
+        }
+    }
+}
+
+struct LibUsbEventHandler {
+    context: LibUsbContext,
+}
+
+impl EventHandler for LibUsbEventHandler {
+    fn on_event(&self, _fd: RawFd) -> std::result::Result<(), ()> {
+        self.context.handle_events_nonblock();
+        Ok(())
+    }
+}
+
+struct PollfdChangeHandler {
+    event_loop: Arc<EventLoop>,
+    event_handler: Weak<EventHandler>,
+}
+
+impl LibUsbPollfdChangeHandler for PollfdChangeHandler {
+    fn add_poll_fd(&self, fd: RawFd, events: c_short) {
+        self.event_loop.add_event(
+            &MaybeOwnedFd::Borrowed(fd),
+            WatchingEvents::new(events as u32),
+            self.event_handler.clone(),
+        );
+    }
+
+    fn remove_poll_fd(&self, fd: RawFd) {
+        if let Some(h) = self.event_handler.upgrade() {
+            match h.on_event(0) {
+                Ok(()) => {}
+                Err(e) => error!("cannot handle event: {:?}", e),
+            }
+        }
+        match self
+            .event_loop
+            .remove_event_for_fd(&MaybeOwnedFd::Borrowed(fd))
+        {
+            Ok(_) => {}
+            Err(e) => 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
new file mode 100644
index 0000000..b414c97
--- /dev/null
+++ b/devices/src/usb/host_backend/error.rs
@@ -0,0 +1,78 @@
+// 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 msg_socket::MsgError;
+use std::fmt::{self, Display};
+use usb::usb_util::error::Error as UsbUtilError;
+use usb::xhci::scatter_gather_buffer::Error as BufferError;
+use usb::xhci::xhci_transfer::Error as XhciTransferError;
+use utils::Error as UtilsError;
+
+#[derive(Debug)]
+pub enum Error {
+    AddToEventLoop(UtilsError),
+    StartAsyncJobQueue(UtilsError),
+    QueueAsyncJob(UtilsError),
+    CreateLibUsbContext(UsbUtilError),
+    GetActiveConfig(UsbUtilError),
+    SetActiveConfig(UsbUtilError),
+    SetInterfaceAltSetting(UsbUtilError),
+    ClearHalt(UsbUtilError),
+    GetEndpointType,
+    CreateControlSock(std::io::Error),
+    SetupControlSock(std::io::Error),
+    ReadControlSock(MsgError),
+    WriteControlSock(MsgError),
+    GetXhciTransferType(XhciTransferError),
+    TransferComplete(XhciTransferError),
+    ReadBuffer(BufferError),
+    WriteBuffer(BufferError),
+    BufferLen(BufferError),
+    /// Cannot get interface descriptor for (interface, altsetting).
+    GetInterfaceDescriptor((i32, u16)),
+    GetEndpointDescriptor(u8),
+    GetRequestSetupType,
+    BadXhciTransferState,
+    BadBackendProviderState,
+}
+
+impl Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::Error::*;
+
+        match self {
+            AddToEventLoop(e) => write!(f, "failed to add to event loop: {}", e),
+            StartAsyncJobQueue(e) => write!(f, "failed to start async job queue: {}", e),
+            QueueAsyncJob(e) => write!(f, "failed to queue async job: {}", e),
+            CreateLibUsbContext(e) => write!(f, "failed to create libusb context: {:?}", e),
+            GetActiveConfig(e) => write!(f, "failed to get active config: {:?}", e),
+            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),
+            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),
+            ReadControlSock(e) => write!(f, "failed to read control sock: {}", e),
+            WriteControlSock(e) => write!(f, "failed to write control sock: {}", e),
+            GetXhciTransferType(e) => write!(f, "failed to get xhci transfer type: {}", e),
+            TransferComplete(e) => write!(f, "xhci transfer completed: {}", e),
+            ReadBuffer(e) => write!(f, "failed to read buffer: {}", e),
+            WriteBuffer(e) => write!(f, "failed to write buffer: {}", e),
+            BufferLen(e) => write!(f, "failed to get buffer length: {}", e),
+            GetInterfaceDescriptor((i, alt_setting)) => write!(
+                f,
+                "failed to get interface descriptor for interface {}, alt setting {}",
+                i, alt_setting
+            ),
+            GetEndpointDescriptor(ep_idx) => {
+                write!(f, "failed to get endpoint descriptor for ep: {}", ep_idx)
+            }
+            GetRequestSetupType => write!(f, "failed to get request setup"),
+            BadXhciTransferState => write!(f, "xhci transfer is in a bad state"),
+            BadBackendProviderState => write!(f, "backend provider is in a bad state"),
+        }
+    }
+}
+
+pub type Result<T> = std::result::Result<T, Error>;
diff --git a/devices/src/usb/host_backend/host_backend_device_provider.rs b/devices/src/usb/host_backend/host_backend_device_provider.rs
new file mode 100644
index 0000000..95b52fd
--- /dev/null
+++ b/devices/src/usb/host_backend/host_backend_device_provider.rs
@@ -0,0 +1,324 @@
+// 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 super::context::Context;
+use super::error::*;
+use super::host_device::HostDevice;
+use super::hotplug::HotplugHandler;
+use msg_socket::{MsgReceiver, MsgSender, MsgSocket};
+use std::mem;
+use std::os::unix::io::{AsRawFd, RawFd};
+use std::time::Duration;
+use sys_util::net::UnixSeqpacket;
+use sys_util::WatchingEvents;
+use usb::xhci::usb_hub::UsbHub;
+use usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
+use utils::AsyncJobQueue;
+use utils::{EventHandler, EventLoop, FailHandle};
+use vm_control::{UsbControlCommand, UsbControlResult, UsbControlSocket};
+
+const SOCKET_TIMEOUT_MS: u64 = 2000;
+
+/// Host backend device provider is a xhci backend device provider that would provide pass through
+/// devices.
+pub enum HostBackendDeviceProvider {
+    // The provider is created but not yet started.
+    Created {
+        sock: MsgSocket<UsbControlResult, UsbControlCommand>,
+    },
+    // The provider is started on an event loop.
+    Started {
+        inner: Arc<ProviderInner>,
+    },
+    // The provider has failed.
+    Failed,
+}
+
+impl HostBackendDeviceProvider {
+    pub fn new() -> Result<(UsbControlSocket, HostBackendDeviceProvider)> {
+        let (child_sock, control_sock) = UnixSeqpacket::pair().map_err(Error::CreateControlSock)?;
+        control_sock
+            .set_write_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
+            .map_err(Error::SetupControlSock)?;
+        control_sock
+            .set_read_timeout(Some(Duration::from_millis(SOCKET_TIMEOUT_MS)))
+            .map_err(Error::SetupControlSock)?;
+
+        let provider = HostBackendDeviceProvider::Created {
+            sock: MsgSocket::new(child_sock),
+        };
+        Ok((MsgSocket::new(control_sock), provider))
+    }
+
+    fn start_helper(
+        &mut self,
+        fail_handle: Arc<FailHandle>,
+        event_loop: Arc<EventLoop>,
+        hub: Arc<UsbHub>,
+    ) -> 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 handler: Arc<EventHandler> = inner.clone();
+                event_loop
+                    .add_event(
+                        &inner.sock,
+                        WatchingEvents::empty().set_read(),
+                        Arc::downgrade(&handler),
+                    )
+                    .map_err(Error::AddToEventLoop)?;
+                *self = HostBackendDeviceProvider::Started { inner };
+                Ok(())
+            }
+            HostBackendDeviceProvider::Started { inner: _ } => {
+                error!("Host backend provider has already started");
+                Err(Error::BadBackendProviderState)
+            }
+            HostBackendDeviceProvider::Failed => {
+                error!("Host backend provider has already failed");
+                Err(Error::BadBackendProviderState)
+            }
+        }
+    }
+}
+
+impl XhciBackendDeviceProvider for HostBackendDeviceProvider {
+    fn start(
+        &mut self,
+        fail_handle: Arc<FailHandle>,
+        event_loop: Arc<EventLoop>,
+        hub: Arc<UsbHub>,
+    ) -> std::result::Result<(), ()> {
+        self.start_helper(fail_handle, event_loop, hub)
+            .map_err(|e| {
+                error!("failed to start host backend device provider: {}", e);
+                ()
+            })
+    }
+
+    fn keep_fds(&self) -> Vec<RawFd> {
+        match self {
+            HostBackendDeviceProvider::Created { sock } => vec![sock.as_raw_fd()],
+            _ => {
+                error!(
+                    "Trying to get keepfds when HostBackendDeviceProvider is not in created state"
+                );
+                vec![]
+            }
+        }
+    }
+}
+
+/// ProviderInner listens to control socket.
+pub struct ProviderInner {
+    fail_handle: Arc<FailHandle>,
+    job_queue: Arc<AsyncJobQueue>,
+    ctx: Context,
+    sock: MsgSocket<UsbControlResult, UsbControlCommand>,
+    usb_hub: Arc<UsbHub>,
+}
+
+impl ProviderInner {
+    fn new(
+        fail_handle: Arc<FailHandle>,
+        job_queue: Arc<AsyncJobQueue>,
+        ctx: Context,
+        sock: MsgSocket<UsbControlResult, UsbControlCommand>,
+        usb_hub: Arc<UsbHub>,
+    ) -> ProviderInner {
+        ProviderInner {
+            fail_handle,
+            job_queue,
+            ctx,
+            sock,
+            usb_hub,
+        }
+    }
+
+    fn on_event_helper(&self, _fd: RawFd) -> 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_fd = usb_file.as_raw_fd();
+
+                    let device = match self.ctx.get_device(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_handle = {
+                        // This is safe only when fd is an fd of the current device.
+                        match unsafe { device.open_fd(device_fd) } {
+                            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(());
+                            }
+                        }
+                    };
+                    (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 { port } => {
+                let port_number = port;
+                let result = match self.usb_hub.get_port(port_number) {
+                    Some(port) => match *port.get_backend_device() {
+                        Some(ref device) => {
+                            let vid = device.get_vid();
+                            let pid = device.get_pid();
+                            UsbControlResult::Device {
+                                port: port_number,
+                                vid,
+                                pid,
+                            }
+                        }
+                        None => UsbControlResult::NoSuchDevice,
+                    },
+                    None => UsbControlResult::NoSuchPort,
+                };
+                // 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(())
+            }
+        }
+    }
+}
+
+impl EventHandler for ProviderInner {
+    fn on_event(&self, fd: RawFd) -> std::result::Result<(), ()> {
+        self.on_event_helper(fd).map_err(|e| {
+            error!("host backend device provider failed: {}", e);
+            ()
+        })
+    }
+}
diff --git a/devices/src/usb/host_backend/host_device.rs b/devices/src/usb/host_backend/host_device.rs
new file mode 100644
index 0000000..ae3faa0
--- /dev/null
+++ b/devices/src/usb/host_backend/host_device.rs
@@ -0,0 +1,541 @@
+// 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::mem::drop;
+use std::sync::Arc;
+use sync::Mutex;
+
+use super::error::*;
+use super::usb_endpoint::UsbEndpoint;
+use super::utils::{submit_transfer, update_transfer_state};
+use std::collections::HashMap;
+use usb::usb_util::device_handle::DeviceHandle;
+use usb::usb_util::error::Error as LibUsbError;
+use usb::usb_util::libusb_device::LibUsbDevice;
+use usb::usb_util::types::{
+    ControlRequestDataPhaseTransferDirection, ControlRequestRecipient, ControlRequestType,
+    StandardControlRequest, UsbRequestSetup,
+};
+use usb::usb_util::usb_transfer::{
+    control_transfer, ControlTransferBuffer, TransferStatus, UsbTransfer,
+};
+use usb::xhci::scatter_gather_buffer::ScatterGatherBuffer;
+use usb::xhci::xhci_backend_device::{BackendType, UsbDeviceAddress, XhciBackendDevice};
+use usb::xhci::xhci_transfer::{XhciTransfer, XhciTransferState, XhciTransferType};
+use utils::AsyncJobQueue;
+use utils::FailHandle;
+
+#[derive(PartialEq)]
+pub enum ControlEndpointState {
+    /// Control endpoint should receive setup stage next.
+    SetupStage,
+    /// Control endpoint should receive data stage next.
+    DataStage,
+    /// Control endpoint should receive status stage next.
+    StatusStage,
+}
+
+// Types of host to device control requests. We want to handle it use libusb functions instead of
+// control transfers.
+enum HostToDeviceControlRequest {
+    SetAddress,
+    SetConfig,
+    SetInterface,
+    ClearFeature,
+    // It could still be some standard control request.
+    Other,
+}
+
+impl HostToDeviceControlRequest {
+    /// Analyze request setup.
+    pub fn analyze_request_setup(
+        request_setup: &UsbRequestSetup,
+    ) -> Result<HostToDeviceControlRequest> {
+        match request_setup.get_type().ok_or(Error::GetRequestSetupType)? {
+            ControlRequestType::Standard => {}
+            _ => return Ok(HostToDeviceControlRequest::Other),
+        };
+
+        let recipient = request_setup.get_recipient();
+        let standard_request = request_setup.get_standard_request();
+
+        match (recipient, standard_request) {
+            (ControlRequestRecipient::Device, Some(StandardControlRequest::SetAddress)) => {
+                Ok(HostToDeviceControlRequest::SetAddress)
+            }
+
+            (ControlRequestRecipient::Device, Some(StandardControlRequest::SetConfiguration)) => {
+                Ok(HostToDeviceControlRequest::SetConfig)
+            }
+
+            (ControlRequestRecipient::Interface, Some(StandardControlRequest::SetInterface)) => {
+                Ok(HostToDeviceControlRequest::SetInterface)
+            }
+
+            (ControlRequestRecipient::Endpoint, Some(StandardControlRequest::ClearFeature)) => {
+                Ok(HostToDeviceControlRequest::ClearFeature)
+            }
+            _ => Ok(HostToDeviceControlRequest::Other),
+        }
+    }
+}
+
+/// Host device is a device connected to host.
+pub struct HostDevice {
+    fail_handle: Arc<FailHandle>,
+    // 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>>,
+    ctl_ep_state: ControlEndpointState,
+    alt_settings: HashMap<u16, u16>,
+    claimed_interfaces: Vec<i32>,
+    control_request_setup: UsbRequestSetup,
+    buffer: Option<ScatterGatherBuffer>,
+    job_queue: Arc<AsyncJobQueue>,
+}
+
+impl Drop for HostDevice {
+    fn drop(&mut self) {
+        self.release_interfaces();
+    }
+}
+
+impl HostDevice {
+    /// Create a new host device.
+    pub fn new(
+        fail_handle: Arc<FailHandle>,
+        job_queue: Arc<AsyncJobQueue>,
+        device: LibUsbDevice,
+        device_handle: DeviceHandle,
+    ) -> HostDevice {
+        let device = 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![],
+            control_request_setup: UsbRequestSetup::new(0, 0, 0, 0, 0),
+            buffer: None,
+            job_queue,
+        };
+        device
+    }
+
+    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();
+    }
+
+    fn handle_control_transfer(&mut self, transfer: XhciTransfer) -> Result<()> {
+        let xhci_transfer = Arc::new(transfer);
+        match xhci_transfer
+            .get_transfer_type()
+            .map_err(Error::GetXhciTransferType)?
+        {
+            XhciTransferType::SetupStage(setup) => {
+                if self.ctl_ep_state != ControlEndpointState::SetupStage {
+                    error!("Control endpoint is in an inconsistant state");
+                    return Ok(());
+                }
+                usb_debug!("setup stage setup buffer: {:?}", setup);
+                self.control_request_setup = setup;
+                xhci_transfer
+                    .on_transfer_complete(&TransferStatus::Completed, 0)
+                    .map_err(Error::TransferComplete)?;
+                self.ctl_ep_state = ControlEndpointState::DataStage;
+            }
+            XhciTransferType::DataStage(buffer) => {
+                if self.ctl_ep_state != ControlEndpointState::DataStage {
+                    error!("Control endpoint is in an inconsistant state");
+                    return Ok(());
+                }
+                self.buffer = Some(buffer);
+                xhci_transfer
+                    .on_transfer_complete(&TransferStatus::Completed, 0)
+                    .map_err(Error::TransferComplete)?;
+                self.ctl_ep_state = ControlEndpointState::StatusStage;
+            }
+            XhciTransferType::StatusStage => {
+                if self.ctl_ep_state == ControlEndpointState::SetupStage {
+                    error!("Control endpoint is in an inconsistant state");
+                    return Ok(());
+                }
+                let buffer = self.buffer.take();
+                match self.control_request_setup.get_direction() {
+                    Some(ControlRequestDataPhaseTransferDirection::HostToDevice) => {
+                        match HostToDeviceControlRequest::analyze_request_setup(
+                            &self.control_request_setup,
+                        )? {
+                            HostToDeviceControlRequest::Other => {
+                                let mut control_transfer = control_transfer(0);
+                                control_transfer
+                                    .buffer_mut()
+                                    .set_request_setup(&self.control_request_setup);
+                                if let Some(buffer) = buffer {
+                                    buffer
+                                        .read(&mut control_transfer.buffer_mut().data_buffer)
+                                        .map_err(Error::ReadBuffer)?;
+                                }
+                                let tmp_transfer = xhci_transfer.clone();
+                                let callback = move |t: UsbTransfer<ControlTransferBuffer>| {
+                                    update_transfer_state(&xhci_transfer, &t)?;
+                                    let state = xhci_transfer.state().lock();
+                                    match *state {
+                                        XhciTransferState::Cancelled => {
+                                            drop(state);
+                                            xhci_transfer
+                                                .on_transfer_complete(&TransferStatus::Cancelled, 0)
+                                                .map_err(Error::TransferComplete)?;
+                                        }
+                                        XhciTransferState::Completed => {
+                                            let status = t.status();
+                                            let actual_length = t.actual_length();
+                                            drop(state);
+                                            xhci_transfer
+                                                .on_transfer_complete(&status, actual_length as u32)
+                                                .map_err(Error::TransferComplete)?;
+                                        }
+                                        _ => {
+                                            // update_transfer_state is already invoked before
+                                            // match. This transfer  could only be `Cancelled` or
+                                            // `Completed`. Any other states means there is a bug
+                                            // in crosvm implementation.
+                                            error!("should not take this branch");
+                                            return Err(Error::BadXhciTransferState);
+                                        }
+                                    }
+                                    Ok(())
+                                };
+                                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();
+                                        }
+                                    },
+                                );
+                                submit_transfer(
+                                    self.fail_handle.clone(),
+                                    &self.job_queue,
+                                    tmp_transfer,
+                                    &self.device_handle,
+                                    control_transfer,
+                                )?;
+                            }
+                            HostToDeviceControlRequest::SetAddress => {
+                                usb_debug!("host device handling set address");
+                                let addr = self.control_request_setup.value as u32;
+                                self.set_address(addr);
+                                xhci_transfer
+                                    .on_transfer_complete(&TransferStatus::Completed, 0)
+                                    .map_err(Error::TransferComplete)?;
+                            }
+                            HostToDeviceControlRequest::SetConfig => {
+                                usb_debug!("host device handling set config");
+                                let status = self.set_config()?;
+                                xhci_transfer
+                                    .on_transfer_complete(&status, 0)
+                                    .map_err(Error::TransferComplete)?;
+                            }
+                            HostToDeviceControlRequest::SetInterface => {
+                                usb_debug!("host device handling set interface");
+                                let status = self.set_interface()?;
+                                xhci_transfer
+                                    .on_transfer_complete(&status, 0)
+                                    .map_err(Error::TransferComplete)?;
+                            }
+                            HostToDeviceControlRequest::ClearFeature => {
+                                usb_debug!("host device handling clear feature");
+                                let status = self.clear_feature()?;
+                                xhci_transfer
+                                    .on_transfer_complete(&status, 0)
+                                    .map_err(Error::TransferComplete)?;
+                            }
+                        };
+                    }
+                    Some(ControlRequestDataPhaseTransferDirection::DeviceToHost) => {
+                        let mut control_transfer = control_transfer(0);
+                        control_transfer
+                            .buffer_mut()
+                            .set_request_setup(&self.control_request_setup);
+                        let tmp_transfer = xhci_transfer.clone();
+                        let callback = move |t: UsbTransfer<ControlTransferBuffer>| {
+                            usb_debug!("setup token control transfer callback invoked");
+                            update_transfer_state(&xhci_transfer, &t)?;
+                            let state = xhci_transfer.state().lock();
+                            match *state {
+                                XhciTransferState::Cancelled => {
+                                    usb_debug!("transfer cancelled");
+                                    drop(state);
+                                    xhci_transfer
+                                        .on_transfer_complete(&TransferStatus::Cancelled, 0)
+                                        .map_err(Error::TransferComplete)?;
+                                }
+                                XhciTransferState::Completed => {
+                                    let status = t.status();
+                                    if let Some(ref buffer) = buffer {
+                                        let _bytes = buffer
+                                            .write(&t.buffer().data_buffer)
+                                            .map_err(Error::WriteBuffer)?
+                                            as u32;
+                                        let _actual_length = t.actual_length();
+                                        usb_debug!(
+                                            "transfer completed bytes: {} actual length {}",
+                                            _bytes,
+                                            _actual_length
+                                        );
+                                    }
+                                    drop(state);
+                                    xhci_transfer
+                                        .on_transfer_complete(&status, 0)
+                                        .map_err(Error::TransferComplete)?;
+                                }
+                                _ => {
+                                    // update_transfer_state is already invoked before this match.
+                                    // Any other states indicates a bug in crosvm.
+                                    error!("should not take this branch");
+                                    return Err(Error::BadXhciTransferState);
+                                }
+                            }
+                            Ok(())
+                        };
+                        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();
+                                }
+                            },
+                        );
+                        submit_transfer(
+                            self.fail_handle.clone(),
+                            &self.job_queue,
+                            tmp_transfer,
+                            &self.device_handle,
+                            control_transfer,
+                        )?;
+                    }
+                    None => error!("Unknown transfer direction!"),
+                }
+
+                self.ctl_ep_state = ControlEndpointState::SetupStage;
+            }
+            _ => {
+                // Non control transfer should not be handled in this function.
+                error!("Non control (could be noop) transfer sent to control endpoint.");
+                xhci_transfer
+                    .on_transfer_complete(&TransferStatus::Completed, 0)
+                    .map_err(Error::TransferComplete)?;
+            }
+        }
+        Ok(())
+    }
+
+    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;
+        usb_debug!(
+            "Set config control transfer is received with config: {}",
+            config
+        );
+        self.release_interfaces();
+        let cur_config = self
+            .device_handle
+            .lock()
+            .get_active_configuration()
+            .map_err(Error::GetActiveConfig)?;
+        usb_debug!("current config is: {}", cur_config);
+        if config != cur_config {
+            self.device_handle
+                .lock()
+                .set_active_configuration(config)
+                .map_err(Error::SetActiveConfig)?;
+        }
+        self.claim_interfaces();
+        self.create_endpoints()?;
+        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
+            .lock()
+            .set_interface_alt_setting(interface as i32, alt_setting as i32)
+            .map_err(Error::SetInterfaceAltSetting)?;
+        self.alt_settings.insert(interface, alt_setting);
+        self.create_endpoints()?;
+        Ok(TransferStatus::Completed)
+    }
+
+    fn clear_feature(&mut self) -> Result<TransferStatus> {
+        usb_debug!("clear feature");
+        let request_setup = &self.control_request_setup;
+        // 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
+                .lock()
+                .clear_halt(request_setup.index as u8)
+                .map_err(Error::ClearHalt)?;
+        }
+        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) {
+                Ok(()) => {
+                    usb_debug!("claimed interface {}", i);
+                    self.claimed_interfaces.push(i);
+                }
+                Err(e) => {
+                    error!("unable to claim interface {}: {:?}", i, e);
+                }
+            }
+        }
+    }
+
+    fn create_endpoints(&mut self) -> 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 interface = config_descriptor
+                .get_interface_descriptor(*i as u8, *alt_setting as i32)
+                .ok_or(Error::GetInterfaceDescriptor((*i, *alt_setting)))?;
+            for ep_idx in 0..interface.bNumEndpoints {
+                let ep_dp = interface
+                    .endpoint_descriptor(ep_idx)
+                    .ok_or(Error::GetEndpointDescriptor(ep_idx))?;
+                let ep_num = ep_dp.get_endpoint_number();
+                if ep_num == 0 {
+                    usb_debug!("endpoint 0 in endpoint descriptors");
+                    continue;
+                }
+                let direction = ep_dp.get_direction();
+                let ty = ep_dp.get_endpoint_type().ok_or(Error::GetEndpointType)?;
+                self.endpoints.push(UsbEndpoint::new(
+                    self.fail_handle.clone(),
+                    self.job_queue.clone(),
+                    self.device_handle.clone(),
+                    ep_num,
+                    direction,
+                    ty,
+                ));
+            }
+        }
+        Ok(())
+    }
+
+    fn submit_transfer_helper(&mut self, transfer: XhciTransfer) -> Result<()> {
+        if transfer.get_endpoint_number() == 0 {
+            return self.handle_control_transfer(transfer);
+        }
+        for ep in &self.endpoints {
+            if ep.match_ep(transfer.get_endpoint_number(), transfer.get_transfer_dir()) {
+                return ep.handle_transfer(transfer);
+            }
+        }
+        warn!("Could not find endpoint for transfer");
+        transfer
+            .on_transfer_complete(&TransferStatus::Error, 0)
+            .map_err(Error::TransferComplete)
+    }
+}
+
+impl XhciBackendDevice for HostDevice {
+    fn get_backend_type(&self) -> BackendType {
+        let d = match self.device.get_device_descriptor() {
+            Ok(d) => d,
+            Err(_) => return BackendType::Usb2,
+        };
+
+        // See definition of bcdUsb.
+        const USB3_MASK: u16 = 0x0300;
+        match d.bcdUSB & USB3_MASK {
+            USB3_MASK => BackendType::Usb3,
+            _ => BackendType::Usb2,
+        }
+    }
+
+    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() {
+            Ok(d) => d.idVendor,
+            Err(e) => {
+                error!("cannot get device descriptor: {:?}", e);
+                0
+            }
+        }
+    }
+
+    fn get_pid(&self) -> u16 {
+        match self.device.get_device_descriptor() {
+            Ok(d) => d.idProduct,
+            Err(e) => {
+                error!("cannot get device descriptor: {:?}", e);
+                0
+            }
+        }
+    }
+
+    fn submit_transfer(&mut self, transfer: XhciTransfer) -> std::result::Result<(), ()> {
+        self.submit_transfer_helper(transfer).map_err(|e| {
+            error!("failed to submit transfer: {}", e);
+            ()
+        })
+    }
+
+    fn set_address(&mut self, _address: UsbDeviceAddress) {
+        // It's a standard, set_address, device request. We do nothing here. As described in XHCI
+        // spec. See set address command ring trb.
+        usb_debug!(
+            "Set address control transfer is received with address: {}",
+            _address
+        );
+    }
+}
diff --git a/devices/src/usb/host_backend/hotplug.rs b/devices/src/usb/host_backend/hotplug.rs
new file mode 100644
index 0000000..218402a
--- /dev/null
+++ b/devices/src/usb/host_backend/hotplug.rs
@@ -0,0 +1,45 @@
+// 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 usb::usb_util::hotplug::{HotplugEvent, UsbHotplugHandler};
+use usb::usb_util::libusb_device::LibUsbDevice;
+use usb::xhci::usb_hub::UsbHub;
+
+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) {
+        match event {
+            HotplugEvent::DeviceLeft => {
+                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
new file mode 100644
index 0000000..8951a08
--- /dev/null
+++ b/devices/src/usb/host_backend/mod.rs
@@ -0,0 +1,11 @@
+// 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.
+
+pub mod context;
+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
new file mode 100644
index 0000000..fcdacaa
--- /dev/null
+++ b/devices/src/usb/host_backend/usb_endpoint.rs
@@ -0,0 +1,253 @@
+// 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::cmp;
+use std::sync::Arc;
+use sync::Mutex;
+
+use super::error::*;
+use super::utils::{submit_transfer, update_transfer_state};
+use usb::usb_util::device_handle::DeviceHandle;
+use usb::usb_util::types::{EndpointDirection, EndpointType, ENDPOINT_DIRECTION_OFFSET};
+use usb::usb_util::usb_transfer::{
+    bulk_transfer, interrupt_transfer, BulkTransferBuffer, TransferStatus, UsbTransfer,
+};
+use usb::xhci::scatter_gather_buffer::ScatterGatherBuffer;
+use usb::xhci::xhci_transfer::{
+    TransferDirection, XhciTransfer, XhciTransferState, XhciTransferType,
+};
+use utils::AsyncJobQueue;
+use utils::FailHandle;
+
+/// Isochronous, Bulk or Interrupt endpoint.
+pub struct UsbEndpoint {
+    fail_handle: Arc<FailHandle>,
+    job_queue: Arc<AsyncJobQueue>,
+    device_handle: Arc<Mutex<DeviceHandle>>,
+    endpoint_number: u8,
+    direction: EndpointDirection,
+    ty: EndpointType,
+}
+
+impl UsbEndpoint {
+    /// Create new endpoint. This function will panic if endpoint type is control.
+    pub fn new(
+        fail_handle: Arc<FailHandle>,
+        job_queue: Arc<AsyncJobQueue>,
+        device_handle: Arc<Mutex<DeviceHandle>>,
+        endpoint_number: u8,
+        direction: EndpointDirection,
+        ty: EndpointType,
+    ) -> UsbEndpoint {
+        assert!(ty != EndpointType::Control);
+        UsbEndpoint {
+            fail_handle,
+            job_queue,
+            device_handle,
+            endpoint_number,
+            direction,
+            ty,
+        }
+    }
+
+    fn ep_addr(&self) -> u8 {
+        self.endpoint_number | ((self.direction as u8) << ENDPOINT_DIRECTION_OFFSET)
+    }
+
+    /// Returns true is this endpoint matches number and direction.
+    pub fn match_ep(&self, endpoint_number: u8, dir: TransferDirection) -> bool {
+        let self_dir = match self.direction {
+            EndpointDirection::HostToDevice => TransferDirection::Out,
+            EndpointDirection::DeviceToHost => TransferDirection::In,
+        };
+        self.endpoint_number == endpoint_number && self_dir == dir
+    }
+
+    /// Handle a xhci transfer.
+    pub fn handle_transfer(&self, transfer: XhciTransfer) -> Result<()> {
+        let buffer = match transfer
+            .get_transfer_type()
+            .map_err(Error::GetXhciTransferType)?
+        {
+            XhciTransferType::Normal(buffer) => buffer,
+            XhciTransferType::Noop => {
+                return transfer
+                    .on_transfer_complete(&TransferStatus::Completed, 0)
+                    .map_err(Error::TransferComplete);
+            }
+            _ => {
+                error!("unhandled xhci transfer type by usb endpoint");
+                return transfer
+                    .on_transfer_complete(&TransferStatus::Error, 0)
+                    .map_err(Error::TransferComplete);
+            }
+        };
+
+        match self.ty {
+            EndpointType::Bulk => {
+                self.handle_bulk_transfer(transfer, buffer)?;
+            }
+            EndpointType::Interrupt => {
+                self.handle_interrupt_transfer(transfer, buffer)?;
+            }
+            _ => {
+                return transfer
+                    .on_transfer_complete(&TransferStatus::Error, 0)
+                    .map_err(Error::TransferComplete);
+            }
+        }
+        Ok(())
+    }
+
+    fn handle_bulk_transfer(
+        &self,
+        xhci_transfer: XhciTransfer,
+        buffer: ScatterGatherBuffer,
+    ) -> Result<()> {
+        let usb_transfer =
+            bulk_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?);
+        self.do_handle_transfer(xhci_transfer, usb_transfer, buffer)
+    }
+
+    fn handle_interrupt_transfer(
+        &self,
+        xhci_transfer: XhciTransfer,
+        buffer: ScatterGatherBuffer,
+    ) -> Result<()> {
+        let usb_transfer =
+            interrupt_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?);
+        self.do_handle_transfer(xhci_transfer, usb_transfer, buffer)
+    }
+
+    fn do_handle_transfer(
+        &self,
+        xhci_transfer: XhciTransfer,
+        mut usb_transfer: UsbTransfer<BulkTransferBuffer>,
+        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?}",
+                    self.ep_addr(),
+                    buffer.len(),
+                    usb_transfer.buffer_mut().as_mut_slice()
+                );
+                let callback = move |t: UsbTransfer<BulkTransferBuffer>| {
+                    usb_debug!("out transfer callback");
+                    update_transfer_state(&xhci_transfer, &t)?;
+                    let state = xhci_transfer.state().lock();
+                    match *state {
+                        XhciTransferState::Cancelled => {
+                            usb_debug!("transfer has been cancelled");
+                            drop(state);
+                            xhci_transfer
+                                .on_transfer_complete(&TransferStatus::Cancelled, 0)
+                                .map_err(Error::TransferComplete)
+                        }
+                        XhciTransferState::Completed => {
+                            let status = t.status();
+                            let actual_length = t.actual_length();
+                            drop(state);
+                            xhci_transfer
+                                .on_transfer_complete(&status, actual_length as u32)
+                                .map_err(Error::TransferComplete)
+                        }
+                        _ => {
+                            error!("xhci trasfer state (host to device) is invalid");
+                            Err(Error::BadXhciTransferState)
+                        }
+                    }
+                };
+                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();
+                        }
+                    },
+                );
+                submit_transfer(
+                    self.fail_handle.clone(),
+                    &self.job_queue,
+                    tmp_transfer,
+                    &self.device_handle,
+                    usb_transfer,
+                )?;
+            }
+            EndpointDirection::DeviceToHost => {
+                usb_debug!(
+                    "in transfer ep_addr {:#x}, buffer len {:?}",
+                    self.ep_addr(),
+                    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()
+                    );
+                    update_transfer_state(&xhci_transfer, &t)?;
+                    let state = xhci_transfer.state().lock();
+                    match *state {
+                        XhciTransferState::Cancelled => {
+                            usb_debug!("transfer has been cancelled");
+                            drop(state);
+                            xhci_transfer
+                                .on_transfer_complete(&TransferStatus::Cancelled, 0)
+                                .map_err(Error::TransferComplete)
+                        }
+                        XhciTransferState::Completed => {
+                            let status = t.status();
+                            let actual_length = t.actual_length() as usize;
+                            let copied_length = buffer
+                                .write(t.buffer().as_slice())
+                                .map_err(Error::WriteBuffer)?;
+                            let actual_length = cmp::min(actual_length, copied_length);
+                            drop(state);
+                            xhci_transfer
+                                .on_transfer_complete(&status, actual_length as u32)
+                                .map_err(Error::TransferComplete)
+                        }
+                        _ => {
+                            // update state is already invoked. This match should not be in any
+                            // other state.
+                            error!("xhci trasfer state (device to host) is invalid");
+                            Err(Error::BadXhciTransferState)
+                        }
+                    }
+                };
+                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();
+                        }
+                    },
+                );
+
+                submit_transfer(
+                    self.fail_handle.clone(),
+                    &self.job_queue,
+                    tmp_transfer,
+                    &self.device_handle,
+                    usb_transfer,
+                )?;
+            }
+        }
+        Ok(())
+    }
+}
diff --git a/devices/src/usb/host_backend/utils.rs b/devices/src/usb/host_backend/utils.rs
new file mode 100644
index 0000000..9f1abc9
--- /dev/null
+++ b/devices/src/usb/host_backend/utils.rs
@@ -0,0 +1,109 @@
+// 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::mem;
+use std::sync::Arc;
+use sync::Mutex;
+
+use super::error::*;
+use usb::usb_util::device_handle::DeviceHandle;
+use usb::usb_util::usb_transfer::{TransferStatus, UsbTransfer, UsbTransferBuffer};
+use usb::xhci::xhci_transfer::{XhciTransfer, XhciTransferState};
+use utils::AsyncJobQueue;
+use utils::FailHandle;
+
+/// Helper function to update xhci_transfer state.
+pub fn update_transfer_state<T: UsbTransferBuffer>(
+    xhci_transfer: &Arc<XhciTransfer>,
+    usb_transfer: &UsbTransfer<T>,
+) -> Result<()> {
+    let status = usb_transfer.status();
+    let mut state = xhci_transfer.state().lock();
+
+    if status == TransferStatus::Cancelled {
+        *state = XhciTransferState::Cancelled;
+        return Ok(());
+    }
+
+    match *state {
+        XhciTransferState::Cancelling => {
+            *state = XhciTransferState::Cancelled;
+        }
+        XhciTransferState::Submitted { cancel_callback: _ } => {
+            *state = XhciTransferState::Completed;
+        }
+        _ => {
+            error!("xhci trasfer state is invalid");
+            *state = XhciTransferState::Completed;
+            return Err(Error::BadXhciTransferState);
+        }
+    }
+    Ok(())
+}
+
+/// Helper function to submit usb_transfer to device handle.
+pub fn submit_transfer<T: UsbTransferBuffer>(
+    fail_handle: Arc<FailHandle>,
+    job_queue: &Arc<AsyncJobQueue>,
+    xhci_transfer: Arc<XhciTransfer>,
+    device_handle: &Arc<Mutex<DeviceHandle>>,
+    usb_transfer: UsbTransfer<T>,
+) -> Result<()> {
+    let transfer_status = {
+        // We need to hold the lock to avoid race condition.
+        // While we are trying to submit the transfer, another thread might want to cancel the same
+        // transfer. Holding the lock here makes sure one of them is cancelled.
+        let mut state = xhci_transfer.state().lock();
+        match mem::replace(&mut *state, XhciTransferState::Cancelled) {
+            XhciTransferState::Created => {
+                let canceller = usb_transfer.get_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");
+                    }
+                    false => {
+                        usb_debug!("fail to cancel");
+                    }
+                });
+                *state = XhciTransferState::Submitted { cancel_callback };
+                match device_handle.lock().submit_async_transfer(usb_transfer) {
+                    Err(e) => {
+                        error!("fail to submit transfer {:?}", e);
+                        *state = XhciTransferState::Completed;
+                        TransferStatus::NoDevice
+                    }
+                    // If it's submitted, we don't need to send on_transfer_complete now.
+                    Ok(_) => return Ok(()),
+                }
+            }
+            XhciTransferState::Cancelled => {
+                warn!("Transfer is already cancelled");
+                TransferStatus::Cancelled
+            }
+            _ => {
+                // The transfer could not be in the following states:
+                // Submitted: A transfer should only be submitted once.
+                // Cancelling: Transfer is cancelling only when it's submitted and someone is
+                // trying to cancel it.
+                // Completed: A completed transfer should not be submitted again.
+                error!("xhci trasfer state is invalid");
+                return Err(Error::BadXhciTransferState);
+            }
+        }
+    };
+    // We are holding locks to of backends, we want to call on_transfer_complete
+    // without any lock.
+    job_queue
+        .queue_job(
+            move || match xhci_transfer.on_transfer_complete(&transfer_status, 0) {
+                Ok(_) => {}
+                Err(e) => {
+                    error!("transfer complete failed: {:?}", e);
+                    fail_handle.fail();
+                }
+            },
+        )
+        .map_err(Error::QueueAsyncJob)
+}
diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs
index 15c42b5..78d93bd 100644
--- a/devices/src/usb/mod.rs
+++ b/devices/src/usb/mod.rs
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+extern crate usb_util;
+
 #[macro_use]
 mod log;
+mod host_backend;
 pub mod xhci;
diff --git a/devices/src/usb/xhci/mod.rs b/devices/src/usb/xhci/mod.rs
index f181529..3aabdc6 100644
--- a/devices/src/usb/xhci/mod.rs
+++ b/devices/src/usb/xhci/mod.rs
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-extern crate usb_util;
-
 mod command_ring_controller;
 mod device_slot;
 mod event_ring;
@@ -12,12 +10,12 @@ mod intr_resample_handler;
 mod ring_buffer;
 mod ring_buffer_controller;
 mod ring_buffer_stop_cb;
-mod scatter_gather_buffer;
+pub mod scatter_gather_buffer;
 mod transfer_ring_controller;
-mod usb_hub;
+pub mod usb_hub;
 mod xhci_abi;
 mod xhci_abi_schema;
-mod xhci_backend_device;
-mod xhci_backend_device_provider;
+pub mod xhci_backend_device;
+pub mod xhci_backend_device_provider;
 mod xhci_regs;
-mod xhci_transfer;
+pub mod xhci_transfer;
diff --git a/devices/src/usb/xhci/xhci_transfer.rs b/devices/src/usb/xhci/xhci_transfer.rs
index 9dc64ea..76fecdc 100644
--- a/devices/src/usb/xhci/xhci_transfer.rs
+++ b/devices/src/usb/xhci/xhci_transfer.rs
@@ -5,8 +5,6 @@
 use super::interrupter::{Error as InterrupterError, Interrupter};
 use super::scatter_gather_buffer::{Error as BufferError, ScatterGatherBuffer};
 use super::usb_hub::{Error as HubError, UsbPort};
-use super::usb_util::types::UsbRequestSetup;
-use super::usb_util::usb_transfer::TransferStatus;
 use super::xhci_abi::{
     AddressedTrb, Error as TrbError, EventDataTrb, SetupStageTrb, TransferDescriptor, TrbCast,
     TrbCompletionCode, TrbType,
@@ -18,6 +16,8 @@ use std::mem;
 use std::sync::{Arc, Weak};
 use sync::Mutex;
 use sys_util::{Error as SysError, EventFd, GuestMemory};
+use usb::usb_util::types::UsbRequestSetup;
+use usb::usb_util::usb_transfer::TransferStatus;
 
 #[derive(Debug)]
 pub enum Error {
diff --git a/vm_control/Cargo.toml b/vm_control/Cargo.toml
index 5e03b9e..924389a 100644
--- a/vm_control/Cargo.toml
+++ b/vm_control/Cargo.toml
@@ -3,6 +3,9 @@ name = "vm_control"
 version = "0.1.0"
 authors = ["The Chromium OS Authors"]
 
+[features]
+sandboxed-libusb = []
+
 [dependencies]
 byteorder = "*"
 data_model = { path = "../data_model" }
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index 72531fb..ee24b61 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -23,7 +23,7 @@ use std::fs::File;
 use std::io::{Seek, SeekFrom};
 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
 
-use libc::{EINVAL, ENODEV};
+use libc::{EINVAL, EIO, ENODEV};
 
 use byteorder::{LittleEndian, WriteBytesExt};
 use kvm::{Datamatch, IoeventAddress, Vm};
@@ -34,6 +34,7 @@ use sys_util::{
 };
 
 /// A file descriptor either borrowed or owned by this.
+#[derive(Debug)]
 pub enum MaybeOwnedFd {
     /// Owned by this enum variant, and will be destructed automatically if not moved out.
     Owned(File),
@@ -98,10 +99,54 @@ impl Default for VmRunMode {
     }
 }
 
+#[derive(MsgOnSocket, Debug)]
+pub enum UsbControlCommand {
+    AttachDevice {
+        bus: u8,
+        addr: u8,
+        vid: u16,
+        pid: u16,
+        fd: Option<MaybeOwnedFd>,
+    },
+    DetachDevice {
+        port: u8,
+    },
+    ListDevice {
+        port: u8,
+    },
+}
+
+#[derive(MsgOnSocket, Debug)]
+pub enum UsbControlResult {
+    Ok { port: u8 },
+    NoAvailablePort,
+    NoSuchDevice,
+    NoSuchPort,
+    FailedToOpenDevice,
+    Device { port: u8, vid: u16, pid: u16 },
+}
+
+impl Display for UsbControlResult {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        use self::UsbControlResult::*;
+
+        match self {
+            Ok { port } => write!(f, "ok {}", port),
+            NoAvailablePort => write!(f, "no_available_port"),
+            NoSuchDevice => write!(f, "no_such_device"),
+            NoSuchPort => write!(f, "no_such_port"),
+            FailedToOpenDevice => write!(f, "failed_to_open_device"),
+            Device { port, vid, pid } => write!(f, "device {} {:04x} {:04x}", port, vid, pid),
+        }
+    }
+}
+
+pub type UsbControlSocket = MsgSocket<UsbControlCommand, UsbControlResult>;
+
 /// A request to the main process to perform some operation on the VM.
 ///
 /// Unless otherwise noted, each request should expect a `VmResponse::Ok` to be received on success.
-#[derive(MsgOnSocket)]
+#[derive(MsgOnSocket, Debug)]
 pub enum VmRequest {
     /// Set the size of the VM's balloon in bytes.
     BalloonAdjust(u64),
@@ -130,6 +175,8 @@ pub enum VmRequest {
     /// Resize a disk chosen by `disk_index` to `new_size` in bytes.
     /// `disk_index` is a 0-based count of `--disk`, `--rwdisk`, and `-r` command-line options.
     DiskResize { disk_index: usize, new_size: u64 },
+    /// Command to use controller.
+    UsbCommand(UsbControlCommand),
 }
 
 fn register_memory(
@@ -268,6 +315,10 @@ impl VmRequest {
                     VmResponse::Err(SysError::new(ENODEV))
                 }
             }
+            VmRequest::UsbCommand(ref cmd) => {
+                error!("not implemented yet");
+                VmResponse::Ok
+            }
         }
     }
 }
@@ -275,7 +326,7 @@ impl VmRequest {
 /// Indication of success or failure of a `VmRequest`.
 ///
 /// Success is usually indicated `VmResponse::Ok` unless there is data associated with the response.
-#[derive(MsgOnSocket)]
+#[derive(MsgOnSocket, Debug)]
 pub enum VmResponse {
     /// Indicates the request was executed successfully.
     Ok,
@@ -292,6 +343,8 @@ pub enum VmResponse {
         slot: u32,
         desc: GpuMemoryDesc,
     },
+    /// Results of usb control commands.
+    UsbResponse(UsbControlResult),
 }
 
 impl Display for VmResponse {
@@ -311,6 +364,7 @@ impl Display for VmResponse {
                 "gpu memory allocated and registered to page frame number {:#x} and memory slot {}",
                 pfn, slot
             ),
+            UsbResponse(result) => write!(f, "usb control request get result {:?}", result),
         }
     }
 }