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 is 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    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
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
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
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
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}