xref: /aosp_15_r20/external/crosvm/devices/src/usb/backend/endpoint.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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