blob: 8841f0069717b66c647f59ed14355fbbd171ef6a [file] [log] [blame]
// 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 crate::usb::xhci::scatter_gather_buffer::ScatterGatherBuffer;
use crate::usb::xhci::xhci_backend_device::{BackendType, UsbDeviceAddress, XhciBackendDevice};
use crate::usb::xhci::xhci_transfer::{XhciTransfer, XhciTransferState, XhciTransferType};
use crate::utils::AsyncJobQueue;
use crate::utils::FailHandle;
use std::collections::HashMap;
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,
};
#[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,
}
/// Host device is a device connected to host.
pub struct HostDevice {
fail_handle: Arc<dyn 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,
executed: bool,
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<dyn FailHandle>,
job_queue: Arc<AsyncJobQueue>,
device: LibUsbDevice,
device_handle: DeviceHandle,
) -> 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![],
control_request_setup: UsbRequestSetup::new(0, 0, 0, 0, 0),
executed: false,
job_queue,
}
}
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
// should be passed through to the device.
fn intercepted_control_transfer(&mut self, xhci_transfer: &XhciTransfer) -> Result<bool> {
let direction = self.control_request_setup.get_direction();
let recipient = self.control_request_setup.get_recipient();
let standard_request = self.control_request_setup.get_standard_request();
if direction != ControlRequestDataPhaseTransferDirection::HostToDevice {
// Only host to device requests are intercepted currently.
return Ok(false);
}
let status = match standard_request {
Some(StandardControlRequest::SetAddress) => {
if recipient != ControlRequestRecipient::Device {
return Ok(false);
}
usb_debug!("host device handling set address");
let addr = self.control_request_setup.value as u32;
self.set_address(addr);
TransferStatus::Completed
}
Some(StandardControlRequest::SetConfiguration) => {
if recipient != ControlRequestRecipient::Device {
return Ok(false);
}
usb_debug!("host device handling set config");
self.set_config()?
}
Some(StandardControlRequest::SetInterface) => {
if recipient != ControlRequestRecipient::Interface {
return Ok(false);
}
usb_debug!("host device handling set interface");
self.set_interface()?
}
Some(StandardControlRequest::ClearFeature) => {
if recipient != ControlRequestRecipient::Endpoint {
return Ok(false);
}
usb_debug!("host device handling clear feature");
self.clear_feature()?
}
_ => {
// Other requests will be passed through to the device.
return Ok(false);
}
};
xhci_transfer
.on_transfer_complete(&status, 0)
.map_err(Error::TransferComplete)?;
Ok(true)
}
fn execute_control_transfer(
&mut self,
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(());
}
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)
.map_err(Error::ReadBuffer)?;
}
// buffer is consumed here for HostToDevice transfers.
None
} else {
// buffer will be used later in the callback for DeviceToHost transfers.
buffer
};
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();
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)?;
}
}
drop(state);
usb_debug!("transfer completed with actual length {}", actual_length);
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 state 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,
)
}
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(());
}
// Requests with a DataStage will be executed here.
// Requests without a DataStage will be executed in StatusStage.
self.execute_control_transfer(xhci_transfer, Some(buffer))?;
self.executed = true;
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(());
}
if self.executed {
// Request was already executed during DataStage.
// Just complete the StatusStage transfer.
xhci_transfer
.on_transfer_complete(&TransferStatus::Completed, 0)
.map_err(Error::TransferComplete)?;
} else {
// Execute the request now since there was no DataStage.
self.execute_control_transfer(xhci_transfer, None)?;
}
self.executed = false;
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
);
}
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);
}),
}
}
}