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 => transfer.create_buffer().map_err(Error::CreateBuffer)?,
102            XhciTransferType::Noop => {
103                return transfer
104                    .on_transfer_complete(&TransferStatus::Completed, 0)
105                    .map_err(Error::TransferComplete);
106            }
107            _ => {
108                error!("unhandled xhci transfer type by usb endpoint");
109                return transfer
110                    .on_transfer_complete(&TransferStatus::Error, 0)
111                    .map_err(Error::TransferComplete);
112            }
113        };
114
115        match self.ty {
116            EndpointType::Bulk => {
117                self.handle_bulk_transfer(device, transfer, buffer)?;
118            }
119            EndpointType::Interrupt => {
120                self.handle_interrupt_transfer(device, transfer, buffer)?;
121            }
122            _ => {
123                return transfer
124                    .on_transfer_complete(&TransferStatus::Error, 0)
125                    .map_err(Error::TransferComplete);
126            }
127        }
128        Ok(())
129    }
130
131    fn get_transfer_buffer(
132        &self,
133        buffer: &ScatterGatherBuffer,
134        device: &mut BackendDeviceType,
135    ) -> Result<TransferBuffer> {
136        let len = buffer.len().map_err(Error::BufferLen)?;
137        let mut buf = device.request_transfer_buffer(len);
138        if self.direction == EndpointDirection::HostToDevice {
139            // Read data from ScatterGatherBuffer to a continuous memory.
140            match &mut buf {
141                TransferBuffer::Dma(dmabuf) => {
142                    if let Some(buf) = dmabuf.upgrade() {
143                        buffer
144                            .read(buf.lock().as_mut_slice())
145                            .map_err(Error::ReadBuffer)?;
146                    } else {
147                        return Err(Error::GetDmaBuffer);
148                    }
149                }
150                TransferBuffer::Vector(v) => {
151                    buffer.read(v.as_mut_slice()).map_err(Error::ReadBuffer)?;
152                }
153            }
154        }
155        Ok(buf)
156    }
157
158    fn handle_bulk_transfer(
159        &self,
160        device: &mut BackendDeviceType,
161        xhci_transfer: XhciTransfer,
162        buffer: ScatterGatherBuffer,
163    ) -> Result<()> {
164        let transfer_buffer = self.get_transfer_buffer(&buffer, device)?;
165        let usb_transfer = device.build_bulk_transfer(
166            self.ep_addr(),
167            transfer_buffer,
168            xhci_transfer.get_stream_id(),
169        )?;
170        self.do_handle_transfer(device, xhci_transfer, usb_transfer, buffer)
171    }
172
173    fn handle_interrupt_transfer(
174        &self,
175        device: &mut BackendDeviceType,
176        xhci_transfer: XhciTransfer,
177        buffer: ScatterGatherBuffer,
178    ) -> Result<()> {
179        let transfer_buffer = self.get_transfer_buffer(&buffer, device)?;
180        let usb_transfer = device.build_interrupt_transfer(self.ep_addr(), transfer_buffer)?;
181        self.do_handle_transfer(device, xhci_transfer, usb_transfer, buffer)
182    }
183
184    fn do_handle_transfer(
185        &self,
186        device: &mut BackendDeviceType,
187        xhci_transfer: XhciTransfer,
188        mut usb_transfer: BackendTransferType,
189        buffer: ScatterGatherBuffer,
190    ) -> Result<()> {
191        let xhci_transfer = Arc::new(xhci_transfer);
192        let tmp_transfer = xhci_transfer.clone();
193        match self.direction {
194            EndpointDirection::HostToDevice => {
195                let _trace = cros_tracing::trace_event!(
196                    USB,
197                    "Endpoint out transfer",
198                    self.ep_addr(),
199                    buffer.len()
200                );
201                let callback = move |t: BackendTransferType| {
202                    let mut state = xhci_transfer.state().lock();
203                    update_transfer_state(&mut state, t.status())?;
204                    match *state {
205                        XhciTransferState::Cancelled => {
206                            debug!("Xhci transfer has been cancelled");
207                            drop(state);
208                            xhci_transfer
209                                .on_transfer_complete(&TransferStatus::Cancelled, 0)
210                                .map_err(Error::TransferComplete)
211                        }
212                        XhciTransferState::Completed => {
213                            let status = t.status();
214                            let actual_length = t.actual_length();
215                            drop(state);
216                            xhci_transfer
217                                .on_transfer_complete(&status, actual_length as u32)
218                                .map_err(Error::TransferComplete)
219                        }
220                        _ => {
221                            error!("xhci trasfer state (host to device) is invalid");
222                            Err(Error::BadXhciTransferState)
223                        }
224                    }
225                };
226                let fail_handle = self.fail_handle.clone();
227                usb_transfer.set_callback(move |t: BackendTransferType| match callback(t) {
228                    Ok(_) => {}
229                    Err(e) => {
230                        error!("bulk transfer callback failed: {:?}", e);
231                        fail_handle.fail();
232                    }
233                });
234                device.submit_transfer(
235                    self.fail_handle.clone(),
236                    &self.job_queue,
237                    tmp_transfer,
238                    usb_transfer,
239                )?;
240            }
241            EndpointDirection::DeviceToHost => {
242                let _trace = cros_tracing::trace_event!(
243                    USB,
244                    "Endpoint in transfer",
245                    self.ep_addr(),
246                    buffer.len()
247                );
248                let _addr = self.ep_addr();
249                let callback = move |t: BackendTransferType| {
250                    let mut state = xhci_transfer.state().lock();
251                    update_transfer_state(&mut state, t.status())?;
252                    match *state {
253                        XhciTransferState::Cancelled => {
254                            debug!("Xhci transfer has been cancelled");
255                            drop(state);
256                            xhci_transfer
257                                .on_transfer_complete(&TransferStatus::Cancelled, 0)
258                                .map_err(Error::TransferComplete)
259                        }
260                        XhciTransferState::Completed => {
261                            let status = t.status();
262                            let actual_length = t.actual_length();
263                            let copied_length = match t.buffer() {
264                                TransferBuffer::Vector(v) => {
265                                    buffer.write(v.as_slice()).map_err(Error::WriteBuffer)?
266                                }
267                                TransferBuffer::Dma(buf) => {
268                                    if let Some(buf) = buf.upgrade() {
269                                        buffer
270                                            .write(buf.lock().as_slice())
271                                            .map_err(Error::WriteBuffer)?
272                                    } else {
273                                        return Err(Error::GetDmaBuffer);
274                                    }
275                                }
276                            };
277                            let actual_length = cmp::min(actual_length, copied_length);
278                            drop(state);
279                            xhci_transfer
280                                .on_transfer_complete(&status, actual_length as u32)
281                                .map_err(Error::TransferComplete)
282                        }
283                        _ => {
284                            // update state is already invoked. This match should not be in any
285                            // other state.
286                            error!("xhci trasfer state (device to host) is invalid");
287                            Err(Error::BadXhciTransferState)
288                        }
289                    }
290                };
291                let fail_handle = self.fail_handle.clone();
292
293                usb_transfer.set_callback(move |t: BackendTransferType| match callback(t) {
294                    Ok(_) => {}
295                    Err(e) => {
296                        error!("bulk transfer callback {:?}", e);
297                        fail_handle.fail();
298                    }
299                });
300
301                device.submit_transfer(
302                    self.fail_handle.clone(),
303                    &self.job_queue,
304                    tmp_transfer,
305                    usb_transfer,
306                )?;
307            }
308        }
309        Ok(())
310    }
311}