Skip to main content

usb_gadget/function/
other.rs

1//! Other USB function.
2
3use std::{
4    collections::HashMap,
5    ffi::{OsStr, OsString},
6    io::{Error, ErrorKind, Result},
7    os::unix::prelude::OsStrExt,
8    path::{Component, Path, PathBuf},
9};
10
11use super::{
12    util::{FunctionDir, Status},
13    Function, Handle,
14};
15
16/// Builder for other USB function implemented by a kernel function driver.
17#[derive(Debug, Clone)]
18pub struct OtherBuilder {
19    /// Function driver name.
20    driver: OsString,
21    /// Properties to set.
22    properties: HashMap<PathBuf, Vec<u8>>,
23}
24
25impl OtherBuilder {
26    /// Build the USB function.
27    ///
28    /// The returned handle must be added to a USB gadget configuration.
29    #[must_use]
30    pub fn build(self) -> (Other, Handle) {
31        let dir = FunctionDir::new();
32        (Other { dir: dir.clone() }, Handle::new(OtherFunction { builder: self, dir }))
33    }
34
35    /// Set a property value.
36    pub fn set(&mut self, name: impl AsRef<Path>, value: impl AsRef<[u8]>) -> Result<()> {
37        let path = name.as_ref().to_path_buf();
38        if !path.components().all(|c| matches!(c, Component::Normal(_))) {
39            return Err(Error::new(ErrorKind::InvalidInput, "property path must be relative"));
40        }
41
42        self.properties.insert(path, value.as_ref().to_vec());
43        Ok(())
44    }
45}
46
47#[derive(Debug)]
48struct OtherFunction {
49    builder: OtherBuilder,
50    dir: FunctionDir,
51}
52
53impl Function for OtherFunction {
54    fn driver(&self) -> OsString {
55        self.builder.driver.clone()
56    }
57
58    fn dir(&self) -> FunctionDir {
59        self.dir.clone()
60    }
61
62    fn register(&self) -> Result<()> {
63        for (prop, val) in &self.builder.properties {
64            self.dir.write(prop, val)?;
65        }
66
67        Ok(())
68    }
69}
70
71/// Other USB function implemented by a kernel function driver.
72///
73/// Driver name `xxx` corresponds to kernel module `usb_f_xxx.ko`.
74#[derive(Debug)]
75pub struct Other {
76    dir: FunctionDir,
77}
78
79impl Other {
80    /// Create a new other function implemented by the specified kernel function driver.
81    pub fn new(driver: impl AsRef<OsStr>) -> Result<(Other, Handle)> {
82        Ok(Self::builder(driver)?.build())
83    }
84
85    /// Build a new other function implemented by the specified kernel function driver.
86    pub fn builder(driver: impl AsRef<OsStr>) -> Result<OtherBuilder> {
87        let driver = driver.as_ref();
88        if driver.as_bytes().contains(&b'.') || driver.as_bytes().contains(&b'/') || !driver.is_ascii() {
89            return Err(Error::new(ErrorKind::InvalidInput, "invalid driver name"));
90        }
91
92        Ok(OtherBuilder { driver: driver.to_os_string(), properties: HashMap::new() })
93    }
94
95    /// Access to registration status.
96    pub fn status(&self) -> Status {
97        self.dir.status()
98    }
99
100    /// Get a property value.
101    pub fn get(&self, name: impl AsRef<Path>) -> Result<Vec<u8>> {
102        self.dir.read(name)
103    }
104}