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