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}