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