ConfigFS 简介:文件系统、作用与目录结构
ConfigFS 是 Linux 内核提供的一种基于内存的虚拟文件系统,专门用于在用户空间动态配置 USB Gadget 设备。它通过标准的文件读写操作,将复杂的 USB 描述符、端点配置和功能组合抽象为目录与文件,使得开发者无需编写内核模块即可灵活构建复合 USB 设备。
核心定位:ConfigFS 是连接 USB Gadget 内核驱动与用户空间配置的桥梁,它将 USB 协议中的设备描述符、配置描述符、接口描述符、端点描述符等层级结构,映射为文件系统中的目录树。
ConfigFS 与 USB Gadget 的关系
USB Gadget 框架负责在嵌入式设备上模拟 USB 外设(如 U 盘、串口、网卡等),而 ConfigFS 则为该框架提供了用户空间的配置接口。两者之间的关系可以用下图表示:
从架构上看,ConfigFS 处于用户空间与内核 USB Gadget 框架之间,承担着配置翻译与状态同步的职责。用户通过文件系统操作写入配置,内核自动解析并生成对应的 USB 描述符,最终通过 UDC(USB Device Controller)驱动呈现给主机。
| 层次 | 组件 | 职责 |
|---|---|---|
| 用户空间 | Shell 脚本 / 应用程序 | 通过 mkdir、echo、ln 等命令操作 ConfigFS 目录与文件 |
| 虚拟文件系统 | ConfigFS | 将 USB 配置结构映射为目录树,提供标准文件接口 |
| 内核驱动 | libcomposite + UDC | 解析 ConfigFS 配置,生成 USB 描述符,管理枚举过程 |
| 硬件层 | USB Device Controller | 物理层传输,响应主机请求 |
ConfigFS 的挂载
ConfigFS 默认不会自动挂载,需要手动挂载到指定路径。标准挂载点通常为 /sys/kernel/config,挂载命令如下:
# 创建挂载点目录(如果不存在)
mkdir -p /sys/kernel/config
# 挂载 ConfigFS 文件系统
mount -t configfs none /sys/kernel/config
提示:在大多数嵌入式 Linux 发行版中,如果内核启用了
CONFIG_CONFIGFS_FS 和 CONFIG_USB_GADGET,上述挂载操作通常会在系统初始化时由 init 脚本自动完成。可以通过 mount | grep configfs 检查是否已挂载。
挂载成功后,/sys/kernel/config 目录下会出现 usb_gadget 子目录,这是所有 USB Gadget 配置的根目录。如果该目录不存在,说明内核未启用 USB Gadget 相关配置。
ConfigFS 目录结构
ConfigFS 的目录结构严格遵循 USB 协议的分层模型。每个 USB Gadget 设备对应 /sys/kernel/config/usb_gadget/<gadget_name> 下的一个目录树。以下是标准结构:
上述目录结构中,每个层级对应 USB 协议中的不同描述符层级:
| ConfigFS 路径 | 对应 USB 协议层级 | 关键文件/子目录 |
|---|---|---|
usb_gadget/<gadget>/ |
设备描述符 | idVendor、idProduct、bcdUSB、bcdDevice |
.../strings/0x409/ |
设备字符串描述符 | manufacturer、product、serialnumber |
.../configs/c.1/ |
配置描述符 | MaxPower、bmAttributes、strings/0x409/configuration |
.../functions/ |
接口描述符 + 端点描述符 | 各功能实例目录(如 mass_storage.usb0) |
.../configs/c.1/ 下的符号链接 |
配置与功能的绑定关系 | 指向 functions/ 下功能实例的符号链接 |
.../UDC |
设备状态控制 | 写入 UDC 名称以启用/禁用设备 |
注意:ConfigFS 的目录结构是严格分层的,必须按照 USB 协议规范逐级创建。例如,必须先设置
idVendor 和 idProduct,再创建 configs 和 functions 子目录,最后将功能符号链接到配置目录下。顺序错误会导致配置失败。
ConfigFS 的核心作用总结
ConfigFS 在复合 USB Gadget 配置中扮演了以下关键角色:
- 配置抽象:将 USB 描述符的二进制结构抽象为可读写的文本文件和目录,降低配置复杂度。
- 动态组合:支持在运行时动态添加/删除功能(如同时模拟 U 盘和串口),无需重新编译内核或重启系统。
- 标准化接口:提供与内核版本无关的稳定用户空间 API,脚本和应用程序可以跨内核版本复用。
- 状态同步:文件系统的读写操作实时反映到内核 USB Gadget 状态,无需额外 ioctl 或系统调用。