Skip to main content

usb_gadget/function/
loopback.rs

1//! Loopback function (for testing).
2//!
3//! The Linux kernel configuration option `CONFIG_USB_CONFIGFS_F_LB_SS` must be enabled.
4//! The loopback function loops back a configurable number of transfers, useful for testing
5//! USB device controllers and host-side software.
6//!
7//! # Example
8//!
9//! ```no_run
10//! use usb_gadget::{
11//!     default_udc, function::loopback::Loopback, Class, Config, Gadget, Id, Strings,
12//! };
13//!
14//! let (loopback, func) = Loopback::new();
15//!
16//! let udc = default_udc().expect("cannot get UDC");
17//! let reg = Gadget::new(
18//!     Class::vendor_specific(0, 0),
19//!     Id::LINUX_FOUNDATION_COMPOSITE,
20//!     Strings::new("Manufacturer", "Loopback", "0123456"),
21//! )
22//! .with_config(Config::new("Loopback Config 1").with_function(func))
23//! .bind(&udc)
24//! .expect("cannot bind to UDC");
25//!
26//! println!(
27//!     "Loopback {} at {} status {:?}",
28//!     reg.name().to_string_lossy(),
29//!     reg.path().display(),
30//!     loopback.status()
31//! );
32//! ```
33
34use std::{ffi::OsString, io::Result};
35
36use super::{
37    util::{FunctionDir, Status},
38    Function, Handle,
39};
40
41/// Builder for USB loopback function.
42///
43/// None values will use the f_loopback module defaults.
44/// See `drivers/usb/gadget/function/f_loopback.c`.
45#[derive(Debug, Clone, Default)]
46#[non_exhaustive]
47pub struct LoopbackBuilder {
48    /// Number of requests to allocate per endpoint.
49    pub qlen: Option<u32>,
50    /// Size of each bulk transfer buffer in bytes.
51    pub bulk_buflen: Option<u32>,
52}
53
54impl LoopbackBuilder {
55    /// Build the USB function.
56    ///
57    /// The returned handle must be added to a USB gadget configuration.
58    #[must_use]
59    pub fn build(self) -> (Loopback, Handle) {
60        let dir = FunctionDir::new();
61        (Loopback { dir: dir.clone() }, Handle::new(LoopbackFunction { builder: self, dir }))
62    }
63}
64
65#[derive(Debug)]
66struct LoopbackFunction {
67    builder: LoopbackBuilder,
68    dir: FunctionDir,
69}
70
71impl Function for LoopbackFunction {
72    fn driver(&self) -> OsString {
73        "Loopback".into()
74    }
75
76    fn dir(&self) -> FunctionDir {
77        self.dir.clone()
78    }
79
80    fn register(&self) -> Result<()> {
81        if let Some(qlen) = self.builder.qlen {
82            self.dir.write("qlen", qlen.to_string())?;
83        }
84        if let Some(bulk_buflen) = self.builder.bulk_buflen {
85            self.dir.write("bulk_buflen", bulk_buflen.to_string())?;
86        }
87
88        Ok(())
89    }
90}
91
92/// USB loopback function.
93///
94/// Loops back a configurable number of bulk transfers. Useful for testing
95/// USB device controllers with host-side test software like the `usbtest` driver.
96#[derive(Debug)]
97pub struct Loopback {
98    dir: FunctionDir,
99}
100
101impl Loopback {
102    /// Creates a new USB loopback function with default settings.
103    pub fn new() -> (Loopback, Handle) {
104        Self::builder().build()
105    }
106
107    /// Creates a new USB loopback function builder.
108    pub fn builder() -> LoopbackBuilder {
109        LoopbackBuilder::default()
110    }
111
112    /// Access to registration status.
113    pub fn status(&self) -> Status {
114        self.dir.status()
115    }
116}