1 // Copyright 2019 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::cmp; 6 use std::sync::Arc; 7 use sync::Mutex; 8 9 use super::error::*; 10 use super::utils::{submit_transfer, update_transfer_state}; 11 use crate::usb::xhci::scatter_gather_buffer::ScatterGatherBuffer; 12 use crate::usb::xhci::xhci_transfer::{ 13 TransferDirection, XhciTransfer, XhciTransferState, XhciTransferType, 14 }; 15 use crate::utils::AsyncJobQueue; 16 use crate::utils::FailHandle; 17 use sys_util::error; 18 use usb_util::device_handle::DeviceHandle; 19 use usb_util::types::{EndpointDirection, EndpointType, ENDPOINT_DIRECTION_OFFSET}; 20 use usb_util::usb_transfer::{ 21 bulk_transfer, interrupt_transfer, BulkTransferBuffer, TransferStatus, UsbTransfer, 22 }; 23 24 /// Isochronous, Bulk or Interrupt endpoint. 25 pub struct UsbEndpoint { 26 fail_handle: Arc<dyn FailHandle>, 27 job_queue: Arc<AsyncJobQueue>, 28 device_handle: Arc<Mutex<DeviceHandle>>, 29 endpoint_number: u8, 30 direction: EndpointDirection, 31 ty: EndpointType, 32 } 33 34 impl UsbEndpoint { 35 /// Create new endpoint. This function will panic if endpoint type is control. new( fail_handle: Arc<dyn FailHandle>, job_queue: Arc<AsyncJobQueue>, device_handle: Arc<Mutex<DeviceHandle>>, endpoint_number: u8, direction: EndpointDirection, ty: EndpointType, ) -> UsbEndpoint36 pub fn new( 37 fail_handle: Arc<dyn FailHandle>, 38 job_queue: Arc<AsyncJobQueue>, 39 device_handle: Arc<Mutex<DeviceHandle>>, 40 endpoint_number: u8, 41 direction: EndpointDirection, 42 ty: EndpointType, 43 ) -> UsbEndpoint { 44 assert!(ty != EndpointType::Control); 45 UsbEndpoint { 46 fail_handle, 47 job_queue, 48 device_handle, 49 endpoint_number, 50 direction, 51 ty, 52 } 53 } 54 ep_addr(&self) -> u855 fn ep_addr(&self) -> u8 { 56 self.endpoint_number | ((self.direction as u8) << ENDPOINT_DIRECTION_OFFSET) 57 } 58 59 /// Returns true is this endpoint matches number and direction. match_ep(&self, endpoint_number: u8, dir: TransferDirection) -> bool60 pub fn match_ep(&self, endpoint_number: u8, dir: TransferDirection) -> bool { 61 let self_dir = match self.direction { 62 EndpointDirection::HostToDevice => TransferDirection::Out, 63 EndpointDirection::DeviceToHost => TransferDirection::In, 64 }; 65 self.endpoint_number == endpoint_number && self_dir == dir 66 } 67 68 /// Handle a xhci transfer. handle_transfer(&self, transfer: XhciTransfer) -> Result<()>69 pub fn handle_transfer(&self, transfer: XhciTransfer) -> Result<()> { 70 let buffer = match transfer 71 .get_transfer_type() 72 .map_err(Error::GetXhciTransferType)? 73 { 74 XhciTransferType::Normal(buffer) => buffer, 75 XhciTransferType::Noop => { 76 return transfer 77 .on_transfer_complete(&TransferStatus::Completed, 0) 78 .map_err(Error::TransferComplete); 79 } 80 _ => { 81 error!("unhandled xhci transfer type by usb endpoint"); 82 return transfer 83 .on_transfer_complete(&TransferStatus::Error, 0) 84 .map_err(Error::TransferComplete); 85 } 86 }; 87 88 match self.ty { 89 EndpointType::Bulk => { 90 self.handle_bulk_transfer(transfer, buffer)?; 91 } 92 EndpointType::Interrupt => { 93 self.handle_interrupt_transfer(transfer, buffer)?; 94 } 95 _ => { 96 return transfer 97 .on_transfer_complete(&TransferStatus::Error, 0) 98 .map_err(Error::TransferComplete); 99 } 100 } 101 Ok(()) 102 } 103 handle_bulk_transfer( &self, xhci_transfer: XhciTransfer, buffer: ScatterGatherBuffer, ) -> Result<()>104 fn handle_bulk_transfer( 105 &self, 106 xhci_transfer: XhciTransfer, 107 buffer: ScatterGatherBuffer, 108 ) -> Result<()> { 109 let usb_transfer = 110 bulk_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?); 111 self.do_handle_transfer(xhci_transfer, usb_transfer, buffer) 112 } 113 handle_interrupt_transfer( &self, xhci_transfer: XhciTransfer, buffer: ScatterGatherBuffer, ) -> Result<()>114 fn handle_interrupt_transfer( 115 &self, 116 xhci_transfer: XhciTransfer, 117 buffer: ScatterGatherBuffer, 118 ) -> Result<()> { 119 let usb_transfer = 120 interrupt_transfer(self.ep_addr(), 0, buffer.len().map_err(Error::BufferLen)?); 121 self.do_handle_transfer(xhci_transfer, usb_transfer, buffer) 122 } 123 do_handle_transfer( &self, xhci_transfer: XhciTransfer, mut usb_transfer: UsbTransfer<BulkTransferBuffer>, buffer: ScatterGatherBuffer, ) -> Result<()>124 fn do_handle_transfer( 125 &self, 126 xhci_transfer: XhciTransfer, 127 mut usb_transfer: UsbTransfer<BulkTransferBuffer>, 128 buffer: ScatterGatherBuffer, 129 ) -> Result<()> { 130 let xhci_transfer = Arc::new(xhci_transfer); 131 let tmp_transfer = xhci_transfer.clone(); 132 match self.direction { 133 EndpointDirection::HostToDevice => { 134 // Read data from ScatterGatherBuffer to a continuous memory. 135 buffer 136 .read(usb_transfer.buffer_mut().as_mut_slice()) 137 .map_err(Error::ReadBuffer)?; 138 usb_debug!( 139 "out transfer ep_addr {:#x}, buffer len {:?}, data {:#x?}", 140 self.ep_addr(), 141 buffer.len(), 142 usb_transfer.buffer_mut().as_mut_slice() 143 ); 144 let callback = move |t: UsbTransfer<BulkTransferBuffer>| { 145 usb_debug!("out transfer callback"); 146 update_transfer_state(&xhci_transfer, &t)?; 147 let state = xhci_transfer.state().lock(); 148 match *state { 149 XhciTransferState::Cancelled => { 150 usb_debug!("transfer has been cancelled"); 151 drop(state); 152 xhci_transfer 153 .on_transfer_complete(&TransferStatus::Cancelled, 0) 154 .map_err(Error::TransferComplete) 155 } 156 XhciTransferState::Completed => { 157 let status = t.status(); 158 let actual_length = t.actual_length(); 159 drop(state); 160 xhci_transfer 161 .on_transfer_complete(&status, actual_length as u32) 162 .map_err(Error::TransferComplete) 163 } 164 _ => { 165 error!("xhci trasfer state (host to device) is invalid"); 166 Err(Error::BadXhciTransferState) 167 } 168 } 169 }; 170 let fail_handle = self.fail_handle.clone(); 171 usb_transfer.set_callback( 172 move |t: UsbTransfer<BulkTransferBuffer>| match callback(t) { 173 Ok(_) => {} 174 Err(e) => { 175 error!("bulk transfer callback failed: {:?}", e); 176 fail_handle.fail(); 177 } 178 }, 179 ); 180 submit_transfer( 181 self.fail_handle.clone(), 182 &self.job_queue, 183 tmp_transfer, 184 &self.device_handle, 185 usb_transfer, 186 )?; 187 } 188 EndpointDirection::DeviceToHost => { 189 usb_debug!( 190 "in transfer ep_addr {:#x}, buffer len {:?}", 191 self.ep_addr(), 192 buffer.len() 193 ); 194 let _addr = self.ep_addr(); 195 let callback = move |t: UsbTransfer<BulkTransferBuffer>| { 196 usb_debug!( 197 "ep {:#x} in transfer data {:?}", 198 _addr, 199 t.buffer().as_slice() 200 ); 201 update_transfer_state(&xhci_transfer, &t)?; 202 let state = xhci_transfer.state().lock(); 203 match *state { 204 XhciTransferState::Cancelled => { 205 usb_debug!("transfer has been cancelled"); 206 drop(state); 207 xhci_transfer 208 .on_transfer_complete(&TransferStatus::Cancelled, 0) 209 .map_err(Error::TransferComplete) 210 } 211 XhciTransferState::Completed => { 212 let status = t.status(); 213 let actual_length = t.actual_length() as usize; 214 let copied_length = buffer 215 .write(t.buffer().as_slice()) 216 .map_err(Error::WriteBuffer)?; 217 let actual_length = cmp::min(actual_length, copied_length); 218 drop(state); 219 xhci_transfer 220 .on_transfer_complete(&status, actual_length as u32) 221 .map_err(Error::TransferComplete) 222 } 223 _ => { 224 // update state is already invoked. This match should not be in any 225 // other state. 226 error!("xhci trasfer state (device to host) is invalid"); 227 Err(Error::BadXhciTransferState) 228 } 229 } 230 }; 231 let fail_handle = self.fail_handle.clone(); 232 233 usb_transfer.set_callback( 234 move |t: UsbTransfer<BulkTransferBuffer>| match callback(t) { 235 Ok(_) => {} 236 Err(e) => { 237 error!("bulk transfer callback {:?}", e); 238 fail_handle.fail(); 239 } 240 }, 241 ); 242 243 submit_transfer( 244 self.fail_handle.clone(), 245 &self.job_queue, 246 tmp_transfer, 247 &self.device_handle, 248 usb_transfer, 249 )?; 250 } 251 } 252 Ok(()) 253 } 254 } 255