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