USB Linux Gadget 是一种设备,它具有一个 UDC(USB 设备控制器),并且可以连接到 USB 主机,通过添加功能扩展主机,如串行端口或大容量存储功能。
1 2 3
A USB Linux Gadget is a device which has a UDC (USB Device Controller) and can be connected to a USB Host to extend it with additional functions like a serial port or a mass storage capability.
A gadget is seen by its host as a set of configurations, each of which contains a number of interfaces which, from the gadget's perspective, are known as functions, each function representing e.g. a serial connection or a SCSI disk.
Linux 提供了许多功能供 Gadget 使用。
1
Linux provides a number of functions for gadgets to use.
创建一个 Gadget 意味着决定将有哪些配置,以及每个配置将提供哪些功能。
1 2
Creating a gadget means deciding what configurations there will be and which functions each configuration will provide.
Configfs (please see `Documentation/filesystems/configfs.rst`) lends itself nicely for the purpose of telling the kernel about the above mentioned decision. This document is about how to do it.
它还描述了 Gadget 中的 configfs 集成设计。
1
It also describes how configfs integration into gadget is designed.
In order for this to work configfs must be available, so CONFIGFS_FS must be 'y' or 'm' in .config. As of this writing USB_LIBCOMPOSITE selects CONFIGFS_FS.
(The original post describing the first function made available through configfs can be seen here: http://www.spinics.net/lists/linux-usb/msg76388.html)
1 2
$ modprobe libcomposite $ mount none $CONFIGFS_HOME -t configfs
其中 CONFIGFS_HOME 是 configfs 的挂载点。
1
where CONFIGFS_HOME is the mount point for configfs
1. 创建 Gadgets
为每个要创建的 Gadget 创建相应的目录:
1
$ mkdir$CONFIGFS_HOME/usb_gadget/<gadget name>
1
For each gadget to be created its corresponding directory must be created:
例如:
1
$ mkdir$CONFIGFS_HOME/usb_gadget/g1
进入对应的目录:
1
$ cd$CONFIGFS_HOME/usb_gadget/g1
每个 Gadget 需要指定其供应商 ID(VID)和产品 ID(PID):
1 2
$ echo <VID> > idVendor $ echo <PID> > idProduct
1
Each gadget needs to have its vendor id <VID> and product id <PID> specified:
A gadget also needs its serial number, manufacturer and product strings. In order to have a place to store them, a strings subdirectory must be created for each language, e.g.:
0x0404 Chinese (Taiwan) 0x0804 Chinese (PRC) 0x0c04 Chinese (Hong Kong SAR, PRC) 0x1004 Chinese (Singapore) 0x1404 Chinese (Macau SAR) 0x0409 English (United States) 0x0809 English (United Kingdom)
Each function provides its specific set of attributes, with either read-only or read-write access. Where applicable they need to be written to as appropriate. Please refer to Documentation/ABI/*/configfs-usb-gadget* for more information.
At this moment a number of gadgets is created, each of which has a number of configurations specified and a number of functions available. What remains is specifying which function is available in which configuration (the same function can be used in multiple configurations). This is achieved with creating symbolic links:
例如:
1
$ ln -s functions/ncm.usb0 configs/c.1
5. 启用 Gadget
以上所有步骤的目的是将 Gadget 组成配置和功能。
1
All the above steps serve the purpose of composing the gadget of configurations and functions.
一个示例目录结构可能如下所示:
1
An example directory structure might look like this:
Below the idea of how configfs works is presented. In configfs there are items and groups, both represented as directories. The difference between an item and a group is that a group can contain other groups. In the picture below only an item is shown. Both items and groups can have attributes, which are represented as files. The user can create and remove directories, but cannot remove files, which can be read-only or read-write, depending on what they represent.
The filesystem part of configfs operates on config_items/groups and configfs_attributes which are generic and of the same type for all configured elements. However, they are embedded in usage-specific larger structures. In the picture below there is a "cs" which contains a config_item and an "sa" which contains a configfs_attribute.
Whenever a user reads/writes the "sa" file, a function is called which accepts a struct config_item and a struct configfs_attribute. In the said function the "cs" and "sa" are retrieved using the well known container_of technique and an appropriate sa's function (show or store) is called and passed the "cs" and a character buffer. The "show" is for displaying the file's contents (copy data from the cs to the buffer), while the "store" is for modifying the file's contents (copy data from the buffer to the cs), but it is up to the implementer of the two functions to decide what they actually do.
The file names are decided by the config item/group designer, while the directories in general can be named at will. A group can have a number of its default sub-groups created automatically.
1. A gadget has its config group, which has some attributes (idVendor, idProduct etc) and default sub-groups (configs, functions, strings). Writing to the attributes causes the information to be stored in appropriate locations. In the configs, functions and strings sub-groups a user can create their sub-groups to represent configurations, functions, and groups of strings in a given language.
2. The user creates configurations and functions, in the configurations creates symbolic links to functions. This information is used when the gadget's UDC attribute is written to, which means binding the gadget to the UDC. The code in drivers/usb/gadget/configfs.c iterates over all configurations, and in each configuration it iterates over all functions and binds them. This way the whole gadget is bound.
drivers/usb/gadget/configfs.c 文件包含以下代码:
Gadget 的 config_group
Gadget 的默认组(configs、functions、strings)
将功能与配置关联(符号链接)
1 2 3 4 5
3. The file drivers/usb/gadget/configfs.c contains code for
- gadget's config_group - gadget's default groups (configs, functions, strings) - associating functions with configurations (symlinks)
每个 USB 功能自然有其希望配置的视图,因此在 functions 实现文件 drivers/usb/gadget/f_*.c 中定义了特定功能的 config_groups。
1 2 3
4. Each USB function naturally has its own view of what it wants configured, so config_groups for particular functions are defined in the functions implementation files drivers/usb/gadget/f_*.c.
5. Function's code is written in such a way that it uses usb_get_function_instance(), which, in turn, calls request_module. So, provided that modprobe works, modules for particular functions are loaded automatically. Please note that the converse is not true: after a gadget is disabled and torn down, the modules remain loaded.
useful links
一些开源仓库基于上面介绍的 usb configfs,USB Gadget API 等,搞了些 cool things.
A comprehensive list of all ConfigFS, FunctionFS, USB Gadget API, etc. tools and libraries on Github(*)
Ok, so I’m writing a comprehensive list for all libraries, tools, modules, and scripts for any linux distro or kernel that I can find on Github, so I can learn more about how to make use of it.
What is this?
For those who don’t know what any of the above APIs are, they are the underlying APIs that power things like the MTP protocol that is associated with your mobile electronics, such as smartphone and digital cameras. The Media Transfer Protocol (MTP) is the protocol that allows host devices to pretend to be peripheral storage devices to other hosts. This is what makes it possible for your cell phone or digital camera to show up as a storage device on your PC, even though they are technically small computers.
You can read more about these APIs from the kernel docs:
The really cool thing about these kernel APIs is that they can work at the USB protocol layer. Which means any USB device can be emulated by a linux machine any way you want. You are not limited to just the MTP protocol.
The reason I am exploring these tools is that I want to see exactly what kind of things I can do with this API. Something that has interested me about this API since I came across it was whether or not it could support hosting a bootable mass storage device. This could allow me to do something like providing Ventoy (or Medicat) over the Gadget API. I was thinking that I could build some kind of stack with this that would allow me to install an operating system dynamically on the host using live ISO, then once the OS has been installed provision it via Ansible over RNDIS without ever having to reboot the device doing the install. Basically, it would provide a method for a fully unattended bare metal install that could fit in your pocket.
What’s this about kernels (plural)?
Note that earlier, in the first paragraph, I said any linux distro as well as any kernel. Since implementations of this API typically require USB OTG or USB Dual Role hardware, the kernel that is likely to have the most stable tools/libraries is going to be the Android kernel. This is something to keep in mind when discussing these APIs.
(TL;DR) The list
(*) - Most of these libraries are on Github, but it is worth-while to at least point out the Android Code Search
Seemingly really well rounded C library for linux for encapsulating the ConfigFS API. It also includes some bash tools for automatically creating and monitoring USB Gadgets
A repository for testing FunctionFS features on both the remote host and peripheral device. Have been ignoring most of these kinds of repos, but added this one, since it included tests to be run on the remote host.
Rooted Android tool used to spoof what your phone appears as to your computer. Really good tool for visually showing you what the ConfigFS/FunctionFS is capable of.