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