devices/usb/backend/
transfer.rs

1// Copyright 2023 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 usb_util::Transfer;
6use usb_util::TransferBuffer;
7use usb_util::TransferStatus;
8use usb_util::UsbRequestSetup;
9
10use crate::usb::backend::endpoint::ControlEndpointState;
11use crate::usb::backend::error::Result;
12use crate::usb::backend::fido_backend::transfer::FidoTransfer;
13use crate::usb::xhci::xhci_transfer::XhciTransfer;
14
15/// BackendTransferHandle is a wrapper structure around a generic transfer handle whose
16/// implementation depends on the backend type that is being used.
17pub struct BackendTransferHandle {
18    handle: Box<dyn GenericTransferHandle>,
19}
20
21impl BackendTransferHandle {
22    pub fn new(handle: impl GenericTransferHandle + 'static) -> Self {
23        BackendTransferHandle {
24            handle: Box::new(handle),
25        }
26    }
27
28    pub fn cancel(&self) -> Result<()> {
29        self.handle.cancel()
30    }
31}
32
33pub enum BackendTransferType {
34    HostDevice(Transfer),
35    FidoDevice(FidoTransfer),
36}
37
38/// The backend transfer trait implemention is the interface of a generic transfer structure that
39/// each backend type should implement to be compatible with the generic backend device provider
40/// logic.
41pub trait BackendTransfer {
42    /// Returns the status of the transfer in a `TransferStatus` enum
43    fn status(&self) -> TransferStatus;
44    /// Returns the actual amount of data transferred, which may be less than the original length.
45    fn actual_length(&self) -> usize;
46    /// Returns a reference to the `TransferBuffer` object.
47    fn buffer(&self) -> &TransferBuffer;
48    /// Sets an optional callback on the transfer to be called when the transfer completes.
49    fn set_callback<C: 'static + Fn(BackendTransferType) + Send + Sync>(&mut self, cb: C);
50}
51
52// TODO(morg): refactor with multi_dispatch
53impl BackendTransfer for BackendTransferType {
54    fn status(&self) -> TransferStatus {
55        match self {
56            BackendTransferType::HostDevice(transfer) => BackendTransfer::status(transfer),
57            BackendTransferType::FidoDevice(transfer) => BackendTransfer::status(transfer),
58        }
59    }
60
61    fn actual_length(&self) -> usize {
62        match self {
63            BackendTransferType::HostDevice(transfer) => BackendTransfer::actual_length(transfer),
64            BackendTransferType::FidoDevice(transfer) => BackendTransfer::actual_length(transfer),
65        }
66    }
67
68    fn buffer(&self) -> &TransferBuffer {
69        match self {
70            BackendTransferType::HostDevice(transfer) => BackendTransfer::buffer(transfer),
71            BackendTransferType::FidoDevice(transfer) => BackendTransfer::buffer(transfer),
72        }
73    }
74
75    fn set_callback<C: 'static + Fn(BackendTransferType) + Send + Sync>(&mut self, cb: C) {
76        match self {
77            BackendTransferType::HostDevice(transfer) => {
78                BackendTransfer::set_callback(transfer, cb)
79            }
80            BackendTransferType::FidoDevice(transfer) => {
81                BackendTransfer::set_callback(transfer, cb)
82            }
83        }
84    }
85}
86
87/// Generic transfer handle is a generic handle that allows for cancellation of in-flight
88/// transfers. It should be implemented by all backends that need to be plugged into a generic
89/// BackendTransferHandle structure.
90pub trait GenericTransferHandle: Send {
91    /// All objects that implement this method need to make sure `cancel()` is safe to call
92    /// multiple times as its invocation should be idempotent. A transfer that has already been
93    /// canceled ought not to error if it gets canceled again.
94    fn cancel(&self) -> Result<()>;
95}
96
97pub struct ControlTransferState {
98    pub ctl_ep_state: ControlEndpointState,
99    pub control_request_setup: UsbRequestSetup,
100    pub data_stage_transfer: Option<XhciTransfer>,
101}