diff options
Diffstat (limited to 'devices/src/usb')
-rw-r--r-- | devices/src/usb/host_backend/context.rs | 145 | ||||
-rw-r--r-- | devices/src/usb/host_backend/error.rs | 6 | ||||
-rw-r--r-- | devices/src/usb/host_backend/host_backend_device_provider.rs | 281 | ||||
-rw-r--r-- | devices/src/usb/host_backend/host_device.rs | 207 | ||||
-rw-r--r-- | devices/src/usb/host_backend/hotplug.rs | 45 | ||||
-rw-r--r-- | devices/src/usb/host_backend/mod.rs | 2 | ||||
-rw-r--r-- | devices/src/usb/host_backend/usb_endpoint.rs | 88 | ||||
-rw-r--r-- | devices/src/usb/host_backend/utils.rs | 27 | ||||
-rw-r--r-- | devices/src/usb/xhci/usb_hub.rs | 35 | ||||
-rw-r--r-- | devices/src/usb/xhci/xhci_backend_device.rs | 4 | ||||
-rw-r--r-- | devices/src/usb/xhci/xhci_transfer.rs | 9 |
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(); } |