Skip to main content

usb_gadget/function/
serial.rs

1//! Serial functions.
2
3use std::{
4    ffi::{OsStr, OsString},
5    io::{Error, ErrorKind, Result},
6    path::PathBuf,
7};
8
9use super::{
10    util::{FunctionDir, Status},
11    Function, Handle,
12};
13
14/// Class of USB serial function.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[non_exhaustive]
17pub enum SerialClass {
18    /// Abstract Control Model (CDC ACM).
19    ///
20    /// The Linux kernel configuration option `CONFIG_USB_CONFIGFS_ACM` must be enabled.
21    Acm,
22    /// Generic serial.
23    ///
24    /// The Linux kernel configuration option `CONFIG_USB_CONFIGFS_SERIAL` must be enabled.
25    Generic,
26}
27
28impl SerialClass {
29    fn driver(&self) -> &OsStr {
30        OsStr::new(match self {
31            SerialClass::Acm => "acm",
32            SerialClass::Generic => "gser",
33        })
34    }
35}
36
37/// Builder for USB serial function.
38#[derive(Debug, Clone)]
39#[non_exhaustive]
40pub struct SerialBuilder {
41    serial_class: SerialClass,
42    /// Console?
43    pub console: Option<bool>,
44}
45
46impl SerialBuilder {
47    /// Build the USB function.
48    ///
49    /// The returned handle must be added to a USB gadget configuration.
50    #[must_use]
51    pub fn build(self) -> (Serial, Handle) {
52        let dir = FunctionDir::new();
53        (Serial { dir: dir.clone() }, Handle::new(SerialFunction { builder: self, dir }))
54    }
55}
56
57#[derive(Debug)]
58struct SerialFunction {
59    builder: SerialBuilder,
60    dir: FunctionDir,
61}
62
63impl Function for SerialFunction {
64    fn driver(&self) -> OsString {
65        self.builder.serial_class.driver().to_os_string()
66    }
67
68    fn dir(&self) -> FunctionDir {
69        self.dir.clone()
70    }
71
72    fn register(&self) -> Result<()> {
73        if let Some(console) = self.builder.console {
74            // Console support is optional.
75            let _ = self.dir.write("console", if console { "1" } else { "0" });
76        }
77
78        Ok(())
79    }
80}
81
82/// USB serial function.
83#[derive(Debug)]
84pub struct Serial {
85    dir: FunctionDir,
86}
87
88impl Serial {
89    /// Creates a new USB serial function.
90    pub fn new(serial_class: SerialClass) -> (Serial, Handle) {
91        Self::builder(serial_class).build()
92    }
93
94    /// Creates a new USB serial function builder.
95    pub fn builder(serial_class: SerialClass) -> SerialBuilder {
96        SerialBuilder { serial_class, console: None }
97    }
98
99    /// Access to registration status.
100    pub fn status(&self) -> Status {
101        self.dir.status()
102    }
103
104    /// Path to TTY device.
105    pub fn tty(&self) -> Result<PathBuf> {
106        let port_num: u32 =
107            self.dir.read_string("port_num")?.parse().map_err(|err| Error::new(ErrorKind::InvalidData, err))?;
108        Ok(format!("/dev/ttyGS{port_num}").into())
109    }
110}