devices/usb/backend/
endpoint.rs

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
5use std::cmp;
6use std::sync::Arc;
7
8use base::debug;
9use base::error;
10use usb_util::EndpointDirection;
11use usb_util::EndpointType;
12use usb_util::TransferBuffer;
13use usb_util::TransferStatus;
14use usb_util::ENDPOINT_DIRECTION_OFFSET;
15
16use crate::usb::backend::device::BackendDevice;
17use crate::usb::backend::device::BackendDeviceType;
18use crate::usb::backend::error::Error;
19use crate::usb::backend::error::Result;
20use crate::usb::backend::transfer::BackendTransfer;
21use crate::usb::backend::transfer::BackendTransferType;
22use crate::usb::backend::utils::update_transfer_state;
23use crate::usb::xhci::scatter_gather_buffer::ScatterGatherBuffer;
24use crate::usb::xhci::xhci_transfer::TransferDirection;
25use crate::usb::xhci::xhci_transfer::XhciTransfer;
26use crate::usb::xhci::xhci_transfer::XhciTransferState;
27use crate::usb::xhci::xhci_transfer::XhciTransferType;
28use crate::utils::AsyncJobQueue;
29use crate::utils::FailHandle;
30
31#[derive(Copy, Clone, PartialEq, Eq)]
32pub 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.
42pub 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
50impl UsbEndpoint {
51    /// Create new endpoint. This function will panic if endpoint type is control.
52    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
69    fn ep_addr(&self) -> u8 {
70        self.endpoint_number | ((self.direction as u8) << ENDPOINT_DIRECTION_OFFSET)
71    }
72
73    /// Returns true if this endpoint matches number and direction.
74    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.
83    // This function should return an error only when we want to remove the ring handler from the
84    // event loop. For any error that might originate from the guest driver, it should report an
85    // error to the guest and return Ok.
86    pub fn handle_transfer(
87        &self,
88        device: &mut BackendDeviceType,
89        transfer: XhciTransfer,
90    ) -> Result<()> {
91        let transfer_type = match transfer.get_transfer_type() {
92            Ok(ty) => ty,
93            Err(e) => {
94                error!("failed to get transfer type: {}", e);
95                return transfer
96                    .on_transfer_complete(&TransferStatus::Error, 0)
97                    .map_err(Error::TransferComplete);
98            }
99        };
100        let buffer = match transfer_type {
101            XhciTransferType::Normal | XhciTransferType::Isochronous => {
102                transfer.create_buffer().map_err(Error::CreateBuffer)?
103            }
104            XhciTransferType::Noop => {
105                return transfer
106                    .on_transfer_complete(&TransferStatus::Completed, 0)
107                    .map_err(Error::TransferComplete);
108            }
109            _ => {
110                error!("unhandled xhci transfer type by usb endpoint");
111                return transfer
112                    .on_transfer_complete(&TransferStatus::Error, 0)
113                    .map_err(Error::TransferComplete);
114            }
115        };
116
117        match self.ty {
118            EndpointType::Bulk => {
119                self.handle_bulk_transfer(device, transfer, buffer)?;
120            }
121            EndpointType::Interrupt => {
122                self.handle_interrupt_transfer(device, transfer, buffer)?;
123            }
124            EndpointType::Isochronous => {
125                self.handle_isochronous_transfer(device, transfer, buffer)?;
126            }
127            _ => {
128                return transfer
129                    .on_transfer_complete(&TransferStatus::Error, 0)
130                    .map_err(Error::TransferComplete);
131            }
132        }
133        Ok(())
134    }
135
136    fn get_transfer_buffer(
137        &self,
138        buffer: &ScatterGatherBuffer,
139        device: &mut BackendDeviceType,
140    ) -> Result<TransferBuffer> {
141        let len = buffer.len().map_err(Error::BufferLen)?;
142        let mut buf = device.request_transfer_buffer(len);
143        if self.direction == EndpointDirection::HostToDevice {
144            // Read data from ScatterGatherBuffer to a continuous memory.
145            match &mut buf {
146                TransferBuffer::Dma(dmabuf) => {
147                    if let Some(buf) = dmabuf.upgrade() {
148                        buffer
149                            .read(buf.lock().as_mut_slice())
150                            .map_err(Error::ReadBuffer)?;
151                    } else {
152                        return Err(Error::GetDmaBuffer);
153                    }
154                }
155                TransferBuffer::Vector(v) => {
156                    buffer.read(v.as_mut_slice()).map_err(Error::ReadBuffer)?;
157                }
158            }
159        }
160        Ok(buf)
161    }
162
163    fn handle_bulk_transfer(
164        &self,
165        device: &mut BackendDeviceType,
166        xhci_transfer: XhciTransfer,
167        buffer: ScatterGatherBuffer,
168    ) -> Result<()> {
169        let transfer_buffer = self.get_transfer_buffer(&buffer, device)?;
170        let usb_transfer = device.build_bulk_transfer(
171            self.ep_addr(),
172            transfer_buffer,
173            xhci_transfer.get_stream_id(),
174        )?;
175        self.do_handle_transfer(device, xhci_transfer, usb_transfer, buffer)
176    }
177
178    fn handle_interrupt_transfer(
179        &self,
180        device: &mut BackendDeviceType,
181        xhci_transfer: XhciTransfer,
182        buffer: ScatterGatherBuffer,
183    ) -> Result<()> {
184        let transfer_buffer = self.get_transfer_buffer(&buffer, device)?;
185        let usb_transfer = device.build_interrupt_transfer(self.ep_addr(), transfer_buffer)?;
186        self.do_handle_transfer(device, xhci_transfer, usb_transfer, buffer)
187    }
188
189    fn handle_isochronous_transfer(
190        &self,
191        device: &mut BackendDeviceType,
192        xhci_transfer: XhciTransfer,
193        buffer: ScatterGatherBuffer,
194    ) -> Result<()> {
195        // We do not support OUT transfer yet.
196        if self.direction == EndpointDirection::HostToDevice {
197            return xhci_transfer
198                .on_transfer_complete(&TransferStatus::Error, 0)
199                .map_err(Error::TransferComplete);
200        }
201
202        let max_payload = xhci_transfer
203            .get_max_payload()
204            .map_err(Error::TransferGetMaxPayload)?;
205        let transfer_buffer = self.get_transfer_buffer(&buffer, device)?;
206        let usb_transfer =
207            device.build_isochronous_transfer(self.ep_addr(), transfer_buffer, max_payload)?;
208        self.do_handle_transfer(device, xhci_transfer, usb_transfer, buffer)
209    }
210
211    fn do_handle_transfer(
212        &self,
213        device: &mut BackendDeviceType,
214        xhci_transfer: XhciTransfer,
215        mut usb_transfer: BackendTransferType,
216        buffer: ScatterGatherBuffer,
217    ) -> Result<()> {
218        let xhci_transfer = Arc::new(xhci_transfer);
219        let tmp_transfer = xhci_transfer.clone();
220        match self.direction {
221            EndpointDirection::HostToDevice => {
222                let _trace = cros_tracing::trace_event!(
223                    USB,
224                    "Endpoint out transfer",
225                    self.ep_addr(),
226                    buffer.len()
227                );
228                let callback = move |t: BackendTransferType| {
229                    let mut state = xhci_transfer.state().lock();
230                    update_transfer_state(&mut state, t.status())?;
231                    match *state {
232                        XhciTransferState::Cancelled => {
233                            debug!("Xhci transfer has been cancelled");
234                            drop(state);
235                            xhci_transfer
236                                .on_transfer_complete(&TransferStatus::Cancelled, 0)
237                                .map_err(Error::TransferComplete)
238                        }
239                        XhciTransferState::Completed => {
240                            let status = t.status();
241                            let actual_length = t.actual_length();
242                            drop(state);
243                            xhci_transfer
244                                .on_transfer_complete(&status, actual_length as u32)
245                                .map_err(Error::TransferComplete)
246                        }
247                        _ => {
248                            error!("xhci trasfer state (host to device) is invalid");
249                            Err(Error::BadXhciTransferState)
250                        }
251                    }
252                };
253                let fail_handle = self.fail_handle.clone();
254                usb_transfer.set_callback(move |t: BackendTransferType| match callback(t) {
255                    Ok(_) => {}
256                    Err(e) => {
257                        error!("bulk transfer callback failed: {:?}", e);
258                        fail_handle.fail();
259                    }
260                });
261                device.submit_transfer(
262                    self.fail_handle.clone(),
263                    &self.job_queue,
264                    tmp_transfer,
265                    usb_transfer,
266                )?;
267            }
268            EndpointDirection::DeviceToHost => {
269                let _trace = cros_tracing::trace_event!(
270                    USB,
271                    "Endpoint in transfer",
272                    self.ep_addr(),
273                    buffer.len()
274                );
275                let _addr = self.ep_addr();
276                let callback = move |t: BackendTransferType| {
277                    let mut state = xhci_transfer.state().lock();
278                    update_transfer_state(&mut state, t.status())?;
279                    match *state {
280                        XhciTransferState::Cancelled => {
281                            debug!("Xhci transfer has been cancelled");
282                            drop(state);
283                            xhci_transfer
284                                .on_transfer_complete(&TransferStatus::Cancelled, 0)
285                                .map_err(Error::TransferComplete)
286                        }
287                        XhciTransferState::Completed => {
288                            let status = t.status();
289                            let actual_length = t.actual_length();
290                            let copied_length = match t.buffer() {
291                                TransferBuffer::Vector(v) => {
292                                    buffer.write(v.as_slice()).map_err(Error::WriteBuffer)?
293                                }
294                                TransferBuffer::Dma(buf) => {
295                                    if let Some(buf) = buf.upgrade() {
296                                        buffer
297                                            .write(buf.lock().as_slice())
298                                            .map_err(Error::WriteBuffer)?
299                                    } else {
300                                        return Err(Error::GetDmaBuffer);
301                                    }
302                                }
303                            };
304                            let actual_length = cmp::min(actual_length, copied_length);
305                            drop(state);
306                            xhci_transfer
307                                .on_transfer_complete(&status, actual_length as u32)
308                                .map_err(Error::TransferComplete)
309                        }
310                        _ => {
311                            // update state is already invoked. This match should not be in any
312                            // other state.
313                            error!("xhci trasfer state (device to host) is invalid");
314                            Err(Error::BadXhciTransferState)
315                        }
316                    }
317                };
318                let fail_handle = self.fail_handle.clone();
319
320                usb_transfer.set_callback(move |t: BackendTransferType| match callback(t) {
321                    Ok(_) => {}
322                    Err(e) => {
323                        error!("bulk transfer callback {:?}", e);
324                        fail_handle.fail();
325                    }
326                });
327
328                device.submit_transfer(
329                    self.fail_handle.clone(),
330                    &self.job_queue,
331                    tmp_transfer,
332                    usb_transfer,
333                )?;
334            }
335        }
336        Ok(())
337    }
338}