Skip to main content

usb_gadget/function/
sourcesink.rs

1//! Source/Sink function (for testing).
2//!
3//! The Linux kernel configuration option `CONFIG_USB_CONFIGFS_F_LB_SS` must be enabled.
4//! The source/sink function either sinks and sources bulk data, and also supports
5//! isochronous transfers. It implements control requests for "chapter 9" conformance
6//! testing.
7//!
8//! # Example
9//!
10//! ```no_run
11//! use usb_gadget::{
12//!     default_udc, function::sourcesink::SourceSink, Class, Config, Gadget, Id, Strings,
13//! };
14//!
15//! let (ss, func) = SourceSink::new();
16//!
17//! let udc = default_udc().expect("cannot get UDC");
18//! let reg = Gadget::new(
19//!     Class::vendor_specific(0, 0),
20//!     Id::LINUX_FOUNDATION_COMPOSITE,
21//!     Strings::new("Manufacturer", "SourceSink", "0123456"),
22//! )
23//! .with_config(Config::new("SourceSink Config 1").with_function(func))
24//! .bind(&udc)
25//! .expect("cannot bind to UDC");
26//!
27//! println!(
28//!     "SourceSink {} at {} status {:?}",
29//!     reg.name().to_string_lossy(),
30//!     reg.path().display(),
31//!     ss.status()
32//! );
33//! ```
34
35use std::{ffi::OsString, io::Result};
36
37use super::{
38    util::{FunctionDir, Status},
39    Function, Handle,
40};
41
42/// Builder for USB source/sink function.
43///
44/// None values will use the f_sourcesink module defaults.
45/// See `drivers/usb/gadget/function/f_sourcesink.c`.
46#[derive(Debug, Clone, Default)]
47#[non_exhaustive]
48pub struct SourceSinkBuilder {
49    /// Data pattern to use (0 = all zeros, 1 = mod63, 2 = none).
50    pub pattern: Option<u32>,
51    /// Isochronous transfer polling interval (1..16).
52    pub isoc_interval: Option<u32>,
53    /// Maximum packet size for isochronous endpoints.
54    pub isoc_maxpacket: Option<u32>,
55    /// Isochronous transfer multiplier (0..2, for HS/SS).
56    pub isoc_mult: Option<u32>,
57    /// Maximum burst for isochronous endpoints (0..15, for SS).
58    pub isoc_maxburst: Option<u32>,
59    /// Size of each bulk transfer buffer in bytes.
60    pub bulk_buflen: Option<u32>,
61    /// Number of bulk request buffers to allocate.
62    pub bulk_qlen: Option<u32>,
63    /// Number of isochronous request buffers to allocate.
64    pub iso_qlen: Option<u32>,
65}
66
67impl SourceSinkBuilder {
68    /// Build the USB function.
69    ///
70    /// The returned handle must be added to a USB gadget configuration.
71    #[must_use]
72    pub fn build(self) -> (SourceSink, Handle) {
73        let dir = FunctionDir::new();
74        (SourceSink { dir: dir.clone() }, Handle::new(SourceSinkFunction { builder: self, dir }))
75    }
76}
77
78#[derive(Debug)]
79struct SourceSinkFunction {
80    builder: SourceSinkBuilder,
81    dir: FunctionDir,
82}
83
84impl Function for SourceSinkFunction {
85    fn driver(&self) -> OsString {
86        "SourceSink".into()
87    }
88
89    fn dir(&self) -> FunctionDir {
90        self.dir.clone()
91    }
92
93    fn register(&self) -> Result<()> {
94        if let Some(pattern) = self.builder.pattern {
95            self.dir.write("pattern", pattern.to_string())?;
96        }
97        if let Some(isoc_interval) = self.builder.isoc_interval {
98            self.dir.write("isoc_interval", isoc_interval.to_string())?;
99        }
100        if let Some(isoc_maxpacket) = self.builder.isoc_maxpacket {
101            self.dir.write("isoc_maxpacket", isoc_maxpacket.to_string())?;
102        }
103        if let Some(isoc_mult) = self.builder.isoc_mult {
104            self.dir.write("isoc_mult", isoc_mult.to_string())?;
105        }
106        if let Some(isoc_maxburst) = self.builder.isoc_maxburst {
107            self.dir.write("isoc_maxburst", isoc_maxburst.to_string())?;
108        }
109        if let Some(bulk_buflen) = self.builder.bulk_buflen {
110            self.dir.write("bulk_buflen", bulk_buflen.to_string())?;
111        }
112        if let Some(bulk_qlen) = self.builder.bulk_qlen {
113            self.dir.write("bulk_qlen", bulk_qlen.to_string())?;
114        }
115        if let Some(iso_qlen) = self.builder.iso_qlen {
116            self.dir.write("iso_qlen", iso_qlen.to_string())?;
117        }
118
119        Ok(())
120    }
121}
122
123/// USB source/sink function.
124///
125/// Sources and sinks bulk data with configurable isochronous support.
126/// Useful for USB conformance testing and benchmarking with host-side tools
127/// like the `usbtest` driver.
128#[derive(Debug)]
129pub struct SourceSink {
130    dir: FunctionDir,
131}
132
133impl SourceSink {
134    /// Creates a new USB source/sink function with default settings.
135    pub fn new() -> (SourceSink, Handle) {
136        Self::builder().build()
137    }
138
139    /// Creates a new USB source/sink function builder.
140    pub fn builder() -> SourceSinkBuilder {
141        SourceSinkBuilder::default()
142    }
143
144    /// Access to registration status.
145    pub fn status(&self) -> Status {
146        self.dir.status()
147    }
148}