• 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 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