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}