diff options
-rw-r--r-- | devices/src/usb/host_backend/host_device.rs | 156 | ||||
-rw-r--r-- | usb_util/src/types.rs | 5 |
2 files changed, 68 insertions, 93 deletions
diff --git a/devices/src/usb/host_backend/host_device.rs b/devices/src/usb/host_backend/host_device.rs index c3b8d90..3213994 100644 --- a/devices/src/usb/host_backend/host_device.rs +++ b/devices/src/usb/host_backend/host_device.rs @@ -20,8 +20,8 @@ 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, ControlRequestType, - StandardControlRequest, UsbRequestSetup, + ControlRequestDataPhaseTransferDirection, ControlRequestRecipient, StandardControlRequest, + UsbRequestSetup, }; use usb_util::usb_transfer::{ control_transfer, ControlTransferBuffer, TransferStatus, UsbTransfer, @@ -37,51 +37,6 @@ pub enum ControlEndpointState { 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() { - 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<dyn FailHandle>, @@ -150,6 +105,63 @@ impl HostDevice { 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>, @@ -160,8 +172,11 @@ impl HostDevice { .buffer_mut() .set_request_setup(&self.control_request_setup); - let direction = self.control_request_setup.get_direction(); + 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 @@ -269,50 +284,7 @@ impl HostDevice { return Ok(()); } let buffer = self.buffer.take(); - match self.control_request_setup.get_direction() { - ControlRequestDataPhaseTransferDirection::HostToDevice => { - match HostToDeviceControlRequest::analyze_request_setup( - &self.control_request_setup, - )? { - HostToDeviceControlRequest::Other => { - self.execute_control_transfer(xhci_transfer, buffer)?; - } - 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)?; - } - }; - } - ControlRequestDataPhaseTransferDirection::DeviceToHost => { - self.execute_control_transfer(xhci_transfer, buffer)?; - } - } - + self.execute_control_transfer(xhci_transfer, buffer)?; self.ctl_ep_state = ControlEndpointState::SetupStage; } _ => { diff --git a/usb_util/src/types.rs b/usb_util/src/types.rs index eaebc70..f40dd6c 100644 --- a/usb_util/src/types.rs +++ b/usb_util/src/types.rs @@ -59,7 +59,7 @@ pub const DATA_PHASE_DIRECTION_OFFSET: u8 = 7; /// Bit mask of data phase transfer direction. pub const DATA_PHASE_DIRECTION: u8 = 1u8 << DATA_PHASE_DIRECTION_OFFSET; // Types of data phase transfer directions. -#[derive(PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum ControlRequestDataPhaseTransferDirection { HostToDevice = 0, DeviceToHost = 1, @@ -175,6 +175,9 @@ impl UsbRequestSetup { /// Return the type of standard control request. pub fn get_standard_request(&self) -> Option<StandardControlRequest> { + if self.get_type() != ControlRequestType::Standard { + return None; + } match self.request { 0x00 => Some(StandardControlRequest::GetStatus), 0x01 => Some(StandardControlRequest::ClearFeature), |