1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker use std::cmp; 6*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc; 7*bb4ee6a4SAndroid Build Coastguard Worker 8*bb4ee6a4SAndroid Build Coastguard Worker use base::debug; 9*bb4ee6a4SAndroid Build Coastguard Worker use base::error; 10*bb4ee6a4SAndroid Build Coastguard Worker use usb_util::EndpointDirection; 11*bb4ee6a4SAndroid Build Coastguard Worker use usb_util::EndpointType; 12*bb4ee6a4SAndroid Build Coastguard Worker use usb_util::TransferBuffer; 13*bb4ee6a4SAndroid Build Coastguard Worker use usb_util::TransferStatus; 14*bb4ee6a4SAndroid Build Coastguard Worker use usb_util::ENDPOINT_DIRECTION_OFFSET; 15*bb4ee6a4SAndroid Build Coastguard Worker 16*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::backend::device::BackendDevice; 17*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::backend::device::BackendDeviceType; 18*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::backend::error::Error; 19*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::backend::error::Result; 20*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::backend::transfer::BackendTransfer; 21*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::backend::transfer::BackendTransferType; 22*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::backend::utils::update_transfer_state; 23*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::xhci::scatter_gather_buffer::ScatterGatherBuffer; 24*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::xhci::xhci_transfer::TransferDirection; 25*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::xhci::xhci_transfer::XhciTransfer; 26*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::xhci::xhci_transfer::XhciTransferState; 27*bb4ee6a4SAndroid Build Coastguard Worker use crate::usb::xhci::xhci_transfer::XhciTransferType; 28*bb4ee6a4SAndroid Build Coastguard Worker use crate::utils::AsyncJobQueue; 29*bb4ee6a4SAndroid Build Coastguard Worker use crate::utils::FailHandle; 30*bb4ee6a4SAndroid Build Coastguard Worker 31*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, PartialEq, Eq)] 32*bb4ee6a4SAndroid Build Coastguard Worker pub enum ControlEndpointState { 33*bb4ee6a4SAndroid Build Coastguard Worker /// Control endpoint should receive setup stage next. 34*bb4ee6a4SAndroid Build Coastguard Worker SetupStage, 35*bb4ee6a4SAndroid Build Coastguard Worker /// Control endpoint should receive data stage next. 36*bb4ee6a4SAndroid Build Coastguard Worker DataStage, 37*bb4ee6a4SAndroid Build Coastguard Worker /// Control endpoint should receive status stage next. 38*bb4ee6a4SAndroid Build Coastguard Worker StatusStage, 39*bb4ee6a4SAndroid Build Coastguard Worker } 40*bb4ee6a4SAndroid Build Coastguard Worker 41*bb4ee6a4SAndroid Build Coastguard Worker /// Isochronous, Bulk or Interrupt endpoint. 42*bb4ee6a4SAndroid Build Coastguard Worker pub struct UsbEndpoint { 43*bb4ee6a4SAndroid Build Coastguard Worker fail_handle: Arc<dyn FailHandle>, 44*bb4ee6a4SAndroid Build Coastguard Worker job_queue: Arc<AsyncJobQueue>, 45*bb4ee6a4SAndroid Build Coastguard Worker endpoint_number: u8, 46*bb4ee6a4SAndroid Build Coastguard Worker direction: EndpointDirection, 47*bb4ee6a4SAndroid Build Coastguard Worker ty: EndpointType, 48*bb4ee6a4SAndroid Build Coastguard Worker } 49*bb4ee6a4SAndroid Build Coastguard Worker 50*bb4ee6a4SAndroid Build Coastguard Worker impl UsbEndpoint { 51*bb4ee6a4SAndroid Build Coastguard Worker /// Create new endpoint. This function will panic if endpoint type is control. new( fail_handle: Arc<dyn FailHandle>, job_queue: Arc<AsyncJobQueue>, endpoint_number: u8, direction: EndpointDirection, ty: EndpointType, ) -> UsbEndpoint52*bb4ee6a4SAndroid Build Coastguard Worker pub fn new( 53*bb4ee6a4SAndroid Build Coastguard Worker fail_handle: Arc<dyn FailHandle>, 54*bb4ee6a4SAndroid Build Coastguard Worker job_queue: Arc<AsyncJobQueue>, 55*bb4ee6a4SAndroid Build Coastguard Worker endpoint_number: u8, 56*bb4ee6a4SAndroid Build Coastguard Worker direction: EndpointDirection, 57*bb4ee6a4SAndroid Build Coastguard Worker ty: EndpointType, 58*bb4ee6a4SAndroid Build Coastguard Worker ) -> UsbEndpoint { 59*bb4ee6a4SAndroid Build Coastguard Worker assert!(ty != EndpointType::Control); 60*bb4ee6a4SAndroid Build Coastguard Worker UsbEndpoint { 61*bb4ee6a4SAndroid Build Coastguard Worker fail_handle, 62*bb4ee6a4SAndroid Build Coastguard Worker job_queue, 63*bb4ee6a4SAndroid Build Coastguard Worker endpoint_number, 64*bb4ee6a4SAndroid Build Coastguard Worker direction, 65*bb4ee6a4SAndroid Build Coastguard Worker ty, 66*bb4ee6a4SAndroid Build Coastguard Worker } 67*bb4ee6a4SAndroid Build Coastguard Worker } 68*bb4ee6a4SAndroid Build Coastguard Worker ep_addr(&self) -> u869*bb4ee6a4SAndroid Build Coastguard Worker fn ep_addr(&self) -> u8 { 70*bb4ee6a4SAndroid Build Coastguard Worker self.endpoint_number | ((self.direction as u8) << ENDPOINT_DIRECTION_OFFSET) 71*bb4ee6a4SAndroid Build Coastguard Worker } 72*bb4ee6a4SAndroid Build Coastguard Worker 73*bb4ee6a4SAndroid Build Coastguard Worker /// Returns true is this endpoint matches number and direction. match_ep(&self, endpoint_number: u8, dir: TransferDirection) -> bool74*bb4ee6a4SAndroid Build Coastguard Worker pub fn match_ep(&self, endpoint_number: u8, dir: TransferDirection) -> bool { 75*bb4ee6a4SAndroid Build Coastguard Worker let self_dir = match self.direction { 76*bb4ee6a4SAndroid Build Coastguard Worker EndpointDirection::HostToDevice => TransferDirection::Out, 77*bb4ee6a4SAndroid Build Coastguard Worker EndpointDirection::DeviceToHost => TransferDirection::In, 78*bb4ee6a4SAndroid Build Coastguard Worker }; 79*bb4ee6a4SAndroid Build Coastguard Worker self.endpoint_number == endpoint_number && self_dir == dir 80*bb4ee6a4SAndroid Build Coastguard Worker } 81*bb4ee6a4SAndroid Build Coastguard Worker 82*bb4ee6a4SAndroid Build Coastguard Worker /// Handle a xhci transfer. handle_transfer( &self, device: &mut BackendDeviceType, transfer: XhciTransfer, ) -> Result<()>83*bb4ee6a4SAndroid Build Coastguard Worker pub fn handle_transfer( 84*bb4ee6a4SAndroid Build Coastguard Worker &self, 85*bb4ee6a4SAndroid Build Coastguard Worker device: &mut BackendDeviceType, 86*bb4ee6a4SAndroid Build Coastguard Worker transfer: XhciTransfer, 87*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 88*bb4ee6a4SAndroid Build Coastguard Worker let buffer = match transfer 89*bb4ee6a4SAndroid Build Coastguard Worker .get_transfer_type() 90*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::GetXhciTransferType)? 91*bb4ee6a4SAndroid Build Coastguard Worker { 92*bb4ee6a4SAndroid Build Coastguard Worker XhciTransferType::Normal => transfer.create_buffer().map_err(Error::CreateBuffer)?, 93*bb4ee6a4SAndroid Build Coastguard Worker XhciTransferType::Noop => { 94*bb4ee6a4SAndroid Build Coastguard Worker return transfer 95*bb4ee6a4SAndroid Build Coastguard Worker .on_transfer_complete(&TransferStatus::Completed, 0) 96*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::TransferComplete); 97*bb4ee6a4SAndroid Build Coastguard Worker } 98*bb4ee6a4SAndroid Build Coastguard Worker _ => { 99*bb4ee6a4SAndroid Build Coastguard Worker error!("unhandled xhci transfer type by usb endpoint"); 100*bb4ee6a4SAndroid Build Coastguard Worker return transfer 101*bb4ee6a4SAndroid Build Coastguard Worker .on_transfer_complete(&TransferStatus::Error, 0) 102*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::TransferComplete); 103*bb4ee6a4SAndroid Build Coastguard Worker } 104*bb4ee6a4SAndroid Build Coastguard Worker }; 105*bb4ee6a4SAndroid Build Coastguard Worker 106*bb4ee6a4SAndroid Build Coastguard Worker match self.ty { 107*bb4ee6a4SAndroid Build Coastguard Worker EndpointType::Bulk => { 108*bb4ee6a4SAndroid Build Coastguard Worker self.handle_bulk_transfer(device, transfer, buffer)?; 109*bb4ee6a4SAndroid Build Coastguard Worker } 110*bb4ee6a4SAndroid Build Coastguard Worker EndpointType::Interrupt => { 111*bb4ee6a4SAndroid Build Coastguard Worker self.handle_interrupt_transfer(device, transfer, buffer)?; 112*bb4ee6a4SAndroid Build Coastguard Worker } 113*bb4ee6a4SAndroid Build Coastguard Worker _ => { 114*bb4ee6a4SAndroid Build Coastguard Worker return transfer 115*bb4ee6a4SAndroid Build Coastguard Worker .on_transfer_complete(&TransferStatus::Error, 0) 116*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::TransferComplete); 117*bb4ee6a4SAndroid Build Coastguard Worker } 118*bb4ee6a4SAndroid Build Coastguard Worker } 119*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 120*bb4ee6a4SAndroid Build Coastguard Worker } 121*bb4ee6a4SAndroid Build Coastguard Worker get_transfer_buffer( &self, buffer: &ScatterGatherBuffer, device: &mut BackendDeviceType, ) -> Result<TransferBuffer>122*bb4ee6a4SAndroid Build Coastguard Worker fn get_transfer_buffer( 123*bb4ee6a4SAndroid Build Coastguard Worker &self, 124*bb4ee6a4SAndroid Build Coastguard Worker buffer: &ScatterGatherBuffer, 125*bb4ee6a4SAndroid Build Coastguard Worker device: &mut BackendDeviceType, 126*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<TransferBuffer> { 127*bb4ee6a4SAndroid Build Coastguard Worker let len = buffer.len().map_err(Error::BufferLen)?; 128*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = device.request_transfer_buffer(len); 129*bb4ee6a4SAndroid Build Coastguard Worker if self.direction == EndpointDirection::HostToDevice { 130*bb4ee6a4SAndroid Build Coastguard Worker // Read data from ScatterGatherBuffer to a continuous memory. 131*bb4ee6a4SAndroid Build Coastguard Worker match &mut buf { 132*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Dma(dmabuf) => { 133*bb4ee6a4SAndroid Build Coastguard Worker if let Some(buf) = dmabuf.upgrade() { 134*bb4ee6a4SAndroid Build Coastguard Worker buffer 135*bb4ee6a4SAndroid Build Coastguard Worker .read(buf.lock().as_mut_slice()) 136*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::ReadBuffer)?; 137*bb4ee6a4SAndroid Build Coastguard Worker } else { 138*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::GetDmaBuffer); 139*bb4ee6a4SAndroid Build Coastguard Worker } 140*bb4ee6a4SAndroid Build Coastguard Worker } 141*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Vector(v) => { 142*bb4ee6a4SAndroid Build Coastguard Worker buffer.read(v.as_mut_slice()).map_err(Error::ReadBuffer)?; 143*bb4ee6a4SAndroid Build Coastguard Worker } 144*bb4ee6a4SAndroid Build Coastguard Worker } 145*bb4ee6a4SAndroid Build Coastguard Worker } 146*bb4ee6a4SAndroid Build Coastguard Worker Ok(buf) 147*bb4ee6a4SAndroid Build Coastguard Worker } 148*bb4ee6a4SAndroid Build Coastguard Worker handle_bulk_transfer( &self, device: &mut BackendDeviceType, xhci_transfer: XhciTransfer, buffer: ScatterGatherBuffer, ) -> Result<()>149*bb4ee6a4SAndroid Build Coastguard Worker fn handle_bulk_transfer( 150*bb4ee6a4SAndroid Build Coastguard Worker &self, 151*bb4ee6a4SAndroid Build Coastguard Worker device: &mut BackendDeviceType, 152*bb4ee6a4SAndroid Build Coastguard Worker xhci_transfer: XhciTransfer, 153*bb4ee6a4SAndroid Build Coastguard Worker buffer: ScatterGatherBuffer, 154*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 155*bb4ee6a4SAndroid Build Coastguard Worker let transfer_buffer = self.get_transfer_buffer(&buffer, device)?; 156*bb4ee6a4SAndroid Build Coastguard Worker let usb_transfer = device.build_bulk_transfer( 157*bb4ee6a4SAndroid Build Coastguard Worker self.ep_addr(), 158*bb4ee6a4SAndroid Build Coastguard Worker transfer_buffer, 159*bb4ee6a4SAndroid Build Coastguard Worker xhci_transfer.get_stream_id(), 160*bb4ee6a4SAndroid Build Coastguard Worker )?; 161*bb4ee6a4SAndroid Build Coastguard Worker self.do_handle_transfer(device, xhci_transfer, usb_transfer, buffer) 162*bb4ee6a4SAndroid Build Coastguard Worker } 163*bb4ee6a4SAndroid Build Coastguard Worker handle_interrupt_transfer( &self, device: &mut BackendDeviceType, xhci_transfer: XhciTransfer, buffer: ScatterGatherBuffer, ) -> Result<()>164*bb4ee6a4SAndroid Build Coastguard Worker fn handle_interrupt_transfer( 165*bb4ee6a4SAndroid Build Coastguard Worker &self, 166*bb4ee6a4SAndroid Build Coastguard Worker device: &mut BackendDeviceType, 167*bb4ee6a4SAndroid Build Coastguard Worker xhci_transfer: XhciTransfer, 168*bb4ee6a4SAndroid Build Coastguard Worker buffer: ScatterGatherBuffer, 169*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 170*bb4ee6a4SAndroid Build Coastguard Worker let transfer_buffer = self.get_transfer_buffer(&buffer, device)?; 171*bb4ee6a4SAndroid Build Coastguard Worker let usb_transfer = device.build_interrupt_transfer(self.ep_addr(), transfer_buffer)?; 172*bb4ee6a4SAndroid Build Coastguard Worker self.do_handle_transfer(device, xhci_transfer, usb_transfer, buffer) 173*bb4ee6a4SAndroid Build Coastguard Worker } 174*bb4ee6a4SAndroid Build Coastguard Worker do_handle_transfer( &self, device: &mut BackendDeviceType, xhci_transfer: XhciTransfer, mut usb_transfer: BackendTransferType, buffer: ScatterGatherBuffer, ) -> Result<()>175*bb4ee6a4SAndroid Build Coastguard Worker fn do_handle_transfer( 176*bb4ee6a4SAndroid Build Coastguard Worker &self, 177*bb4ee6a4SAndroid Build Coastguard Worker device: &mut BackendDeviceType, 178*bb4ee6a4SAndroid Build Coastguard Worker xhci_transfer: XhciTransfer, 179*bb4ee6a4SAndroid Build Coastguard Worker mut usb_transfer: BackendTransferType, 180*bb4ee6a4SAndroid Build Coastguard Worker buffer: ScatterGatherBuffer, 181*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 182*bb4ee6a4SAndroid Build Coastguard Worker let xhci_transfer = Arc::new(xhci_transfer); 183*bb4ee6a4SAndroid Build Coastguard Worker let tmp_transfer = xhci_transfer.clone(); 184*bb4ee6a4SAndroid Build Coastguard Worker match self.direction { 185*bb4ee6a4SAndroid Build Coastguard Worker EndpointDirection::HostToDevice => { 186*bb4ee6a4SAndroid Build Coastguard Worker let _trace = cros_tracing::trace_event!( 187*bb4ee6a4SAndroid Build Coastguard Worker USB, 188*bb4ee6a4SAndroid Build Coastguard Worker "Endpoint out transfer", 189*bb4ee6a4SAndroid Build Coastguard Worker self.ep_addr(), 190*bb4ee6a4SAndroid Build Coastguard Worker buffer.len() 191*bb4ee6a4SAndroid Build Coastguard Worker ); 192*bb4ee6a4SAndroid Build Coastguard Worker let callback = move |t: BackendTransferType| { 193*bb4ee6a4SAndroid Build Coastguard Worker update_transfer_state(&xhci_transfer, t.status())?; 194*bb4ee6a4SAndroid Build Coastguard Worker let state = xhci_transfer.state().lock(); 195*bb4ee6a4SAndroid Build Coastguard Worker match *state { 196*bb4ee6a4SAndroid Build Coastguard Worker XhciTransferState::Cancelled => { 197*bb4ee6a4SAndroid Build Coastguard Worker debug!("Xhci transfer has been cancelled"); 198*bb4ee6a4SAndroid Build Coastguard Worker drop(state); 199*bb4ee6a4SAndroid Build Coastguard Worker xhci_transfer 200*bb4ee6a4SAndroid Build Coastguard Worker .on_transfer_complete(&TransferStatus::Cancelled, 0) 201*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::TransferComplete) 202*bb4ee6a4SAndroid Build Coastguard Worker } 203*bb4ee6a4SAndroid Build Coastguard Worker XhciTransferState::Completed => { 204*bb4ee6a4SAndroid Build Coastguard Worker let status = t.status(); 205*bb4ee6a4SAndroid Build Coastguard Worker let actual_length = t.actual_length(); 206*bb4ee6a4SAndroid Build Coastguard Worker drop(state); 207*bb4ee6a4SAndroid Build Coastguard Worker xhci_transfer 208*bb4ee6a4SAndroid Build Coastguard Worker .on_transfer_complete(&status, actual_length as u32) 209*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::TransferComplete) 210*bb4ee6a4SAndroid Build Coastguard Worker } 211*bb4ee6a4SAndroid Build Coastguard Worker _ => { 212*bb4ee6a4SAndroid Build Coastguard Worker error!("xhci trasfer state (host to device) is invalid"); 213*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::BadXhciTransferState) 214*bb4ee6a4SAndroid Build Coastguard Worker } 215*bb4ee6a4SAndroid Build Coastguard Worker } 216*bb4ee6a4SAndroid Build Coastguard Worker }; 217*bb4ee6a4SAndroid Build Coastguard Worker let fail_handle = self.fail_handle.clone(); 218*bb4ee6a4SAndroid Build Coastguard Worker usb_transfer.set_callback(move |t: BackendTransferType| match callback(t) { 219*bb4ee6a4SAndroid Build Coastguard Worker Ok(_) => {} 220*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => { 221*bb4ee6a4SAndroid Build Coastguard Worker error!("bulk transfer callback failed: {:?}", e); 222*bb4ee6a4SAndroid Build Coastguard Worker fail_handle.fail(); 223*bb4ee6a4SAndroid Build Coastguard Worker } 224*bb4ee6a4SAndroid Build Coastguard Worker }); 225*bb4ee6a4SAndroid Build Coastguard Worker device.submit_transfer( 226*bb4ee6a4SAndroid Build Coastguard Worker self.fail_handle.clone(), 227*bb4ee6a4SAndroid Build Coastguard Worker &self.job_queue, 228*bb4ee6a4SAndroid Build Coastguard Worker tmp_transfer, 229*bb4ee6a4SAndroid Build Coastguard Worker usb_transfer, 230*bb4ee6a4SAndroid Build Coastguard Worker )?; 231*bb4ee6a4SAndroid Build Coastguard Worker } 232*bb4ee6a4SAndroid Build Coastguard Worker EndpointDirection::DeviceToHost => { 233*bb4ee6a4SAndroid Build Coastguard Worker let _trace = cros_tracing::trace_event!( 234*bb4ee6a4SAndroid Build Coastguard Worker USB, 235*bb4ee6a4SAndroid Build Coastguard Worker "Endpoint in transfer", 236*bb4ee6a4SAndroid Build Coastguard Worker self.ep_addr(), 237*bb4ee6a4SAndroid Build Coastguard Worker buffer.len() 238*bb4ee6a4SAndroid Build Coastguard Worker ); 239*bb4ee6a4SAndroid Build Coastguard Worker let _addr = self.ep_addr(); 240*bb4ee6a4SAndroid Build Coastguard Worker let callback = move |t: BackendTransferType| { 241*bb4ee6a4SAndroid Build Coastguard Worker update_transfer_state(&xhci_transfer, t.status())?; 242*bb4ee6a4SAndroid Build Coastguard Worker let state = xhci_transfer.state().lock(); 243*bb4ee6a4SAndroid Build Coastguard Worker match *state { 244*bb4ee6a4SAndroid Build Coastguard Worker XhciTransferState::Cancelled => { 245*bb4ee6a4SAndroid Build Coastguard Worker debug!("Xhci transfer has been cancelled"); 246*bb4ee6a4SAndroid Build Coastguard Worker drop(state); 247*bb4ee6a4SAndroid Build Coastguard Worker xhci_transfer 248*bb4ee6a4SAndroid Build Coastguard Worker .on_transfer_complete(&TransferStatus::Cancelled, 0) 249*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::TransferComplete) 250*bb4ee6a4SAndroid Build Coastguard Worker } 251*bb4ee6a4SAndroid Build Coastguard Worker XhciTransferState::Completed => { 252*bb4ee6a4SAndroid Build Coastguard Worker let status = t.status(); 253*bb4ee6a4SAndroid Build Coastguard Worker let actual_length = t.actual_length(); 254*bb4ee6a4SAndroid Build Coastguard Worker let copied_length = match t.buffer() { 255*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Vector(v) => { 256*bb4ee6a4SAndroid Build Coastguard Worker buffer.write(v.as_slice()).map_err(Error::WriteBuffer)? 257*bb4ee6a4SAndroid Build Coastguard Worker } 258*bb4ee6a4SAndroid Build Coastguard Worker TransferBuffer::Dma(buf) => { 259*bb4ee6a4SAndroid Build Coastguard Worker if let Some(buf) = buf.upgrade() { 260*bb4ee6a4SAndroid Build Coastguard Worker buffer 261*bb4ee6a4SAndroid Build Coastguard Worker .write(buf.lock().as_slice()) 262*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::WriteBuffer)? 263*bb4ee6a4SAndroid Build Coastguard Worker } else { 264*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::GetDmaBuffer); 265*bb4ee6a4SAndroid Build Coastguard Worker } 266*bb4ee6a4SAndroid Build Coastguard Worker } 267*bb4ee6a4SAndroid Build Coastguard Worker }; 268*bb4ee6a4SAndroid Build Coastguard Worker let actual_length = cmp::min(actual_length, copied_length); 269*bb4ee6a4SAndroid Build Coastguard Worker drop(state); 270*bb4ee6a4SAndroid Build Coastguard Worker xhci_transfer 271*bb4ee6a4SAndroid Build Coastguard Worker .on_transfer_complete(&status, actual_length as u32) 272*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::TransferComplete) 273*bb4ee6a4SAndroid Build Coastguard Worker } 274*bb4ee6a4SAndroid Build Coastguard Worker _ => { 275*bb4ee6a4SAndroid Build Coastguard Worker // update state is already invoked. This match should not be in any 276*bb4ee6a4SAndroid Build Coastguard Worker // other state. 277*bb4ee6a4SAndroid Build Coastguard Worker error!("xhci trasfer state (device to host) is invalid"); 278*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::BadXhciTransferState) 279*bb4ee6a4SAndroid Build Coastguard Worker } 280*bb4ee6a4SAndroid Build Coastguard Worker } 281*bb4ee6a4SAndroid Build Coastguard Worker }; 282*bb4ee6a4SAndroid Build Coastguard Worker let fail_handle = self.fail_handle.clone(); 283*bb4ee6a4SAndroid Build Coastguard Worker 284*bb4ee6a4SAndroid Build Coastguard Worker usb_transfer.set_callback(move |t: BackendTransferType| match callback(t) { 285*bb4ee6a4SAndroid Build Coastguard Worker Ok(_) => {} 286*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => { 287*bb4ee6a4SAndroid Build Coastguard Worker error!("bulk transfer callback {:?}", e); 288*bb4ee6a4SAndroid Build Coastguard Worker fail_handle.fail(); 289*bb4ee6a4SAndroid Build Coastguard Worker } 290*bb4ee6a4SAndroid Build Coastguard Worker }); 291*bb4ee6a4SAndroid Build Coastguard Worker 292*bb4ee6a4SAndroid Build Coastguard Worker device.submit_transfer( 293*bb4ee6a4SAndroid Build Coastguard Worker self.fail_handle.clone(), 294*bb4ee6a4SAndroid Build Coastguard Worker &self.job_queue, 295*bb4ee6a4SAndroid Build Coastguard Worker tmp_transfer, 296*bb4ee6a4SAndroid Build Coastguard Worker usb_transfer, 297*bb4ee6a4SAndroid Build Coastguard Worker )?; 298*bb4ee6a4SAndroid Build Coastguard Worker } 299*bb4ee6a4SAndroid Build Coastguard Worker } 300*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 301*bb4ee6a4SAndroid Build Coastguard Worker } 302*bb4ee6a4SAndroid Build Coastguard Worker } 303