通过configfs配置的Linux USB gadget
概述
USB Linux Gadget是一种具有UDC (USB设备控制器)的设备,可以连接到USB主机,以扩展其附加功能,如串口或大容量存储能力。
一个gadget被它的主机视为一组配置,每个配置都包含一些接口,从gadget的角度来看,这些接口被称为功能,每个功能代表一个串行连接或一个SCSI磁盘。
Linux提供了许多gadget可以使用的功能。
创建一个gadget意味着决定将有哪些配置以及每个配置将提供哪些功能。
Configfs(请参阅Configfs—用户空间驱动的内核对象配置)非常适合告诉内核上述决定。本文档是关于如何实现这一点的。它还描述了如何将configfs集成到gadget中。
要求
为了使其工作,配置文件必须可用,因此CONFIGFS_FS必须为 'y' 或 'm' 在.config中。在撰写本文时,USB_LIBCOMPOSITE选择CONFIGFS_FS。
用法
(描述configfs提供的第一个功能的原始帖子可以在这里看到:http://www.spinics.net/lists/linux-usb/msg76388.html)
$ modprobe libcomposite
$ mount none $CONFIGFS_HOME -t configfs
其中CONFIGFS_HOME是configfs的挂载点。
1. 创建gadget
对于每个要创建的gadget,必须创建相应的目录:
$ mkdir $CONFIGFS_HOME/usb_gadget/<gadget name>
例如:
$ mkdir $CONFIGFS_HOME/usb_gadget/g1
$ cd $CONFIGFS_HOME/usb_gadget/g1
每个gadget需要指定其vendor id <VID>和product id <PID>:
$ echo <VID> > idVendor
$ echo <PID> > idProduct
gadget还需要它的序列号、制造商和产品字符串。为了有一个地方存储它们,必须为每种语言创建一个字符串子目录,例如:
$ mkdir strings/0x409
然后可以指定字符串:
$ echo <serial number> > strings/0x409/serialnumber $ echo <manufacturer> > strings/0x409/manufacturer $ echo <product> > strings/0x409/product
2. 创建配置
每个 gadget 将由许多配置组成,必须创建相应的目录:
$ mkdir configs/<name>.<number>
<name>可以是文件系统中合法的任意字符串,而<number>是配置的编号,例如:
$ mkdir configs/c.1
每个配置也需要它的字符串,所以必须为每种语言创建一个子目录,例如:
$ mkdir configs/c.1/strings/0x409
然后可以指定配置字符串:
$ echo <configuration> > configs/c.1/strings/0x409/configuration
也可以为配置设置一些属性,例如:
$ echo 120 > configs/c.1/MaxPower
3. 创建功能
gadget将提供一些功能,对于每个功能,必须创建相应的目录:
$ mkdir functions/<name>.<instance name>
其中<name>对应于一个允许的功能名称,<instance name>是文件系统中允许的任意字符串,例如:
$ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module()
每个函数都提供其特定的属性集,具有只读或读写访问权限。如适用,需要酌情写入。更多信息请参考Documentation/ABI/testing/configfs-usb-gadget。
4. 关联功能及其配置
此时,许多gadget被创建出来,每个gadget都有一些指定的配置和一些可用的功能。剩下的就是指定哪个功能在哪个配置中可用(同一个功能可以在多个配置中使用)。这是通过创建符号链接来实现的:
$ ln -s functions/<name>.<instance name> configs/<name>.<number>
例如:
$ ln -s functions/ncm.usb0 configs/c.1
5. 启用gadget
以上所有步骤的目的是组成gadget的配置和功能。
示例目录结构可能看起来像这样:
. ./strings ./strings/0x409 ./strings/0x409/serialnumber ./strings/0x409/product ./strings/0x409/manufacturer ./configs ./configs/c.1 ./configs/c.1/ncm.usb0 -> ../../../../usb_gadget/g1/functions/ncm.usb0 ./configs/c.1/strings ./configs/c.1/strings/0x409 ./configs/c.1/strings/0x409/configuration ./configs/c.1/bmAttributes ./configs/c.1/MaxPower ./functions ./functions/ncm.usb0 ./functions/ncm.usb0/ifname ./functions/ncm.usb0/qmult ./functions/ncm.usb0/host_addr ./functions/ncm.usb0/dev_addr ./UDC ./bcdUSB ./bcdDevice ./idProduct ./idVendor ./bMaxPacketSize0 ./bDeviceProtocol ./bDeviceSubClass ./bDeviceClass
这样的gadget必须最终启用,以便USB主机能够枚举它。
为了启用gadget,它必须绑定到UDC (USB设备控制器):
$ echo <udc name> > UDC
其中<udc name>是在/sys/class/udc/*,例如:
$ echo s3c-hsotg > UDC
6. 禁用gadget
$ echo "" > UDC
7. 清理
从配置中删除功能:
$ rm configs/<config name>.<number>/<function>
<config name >.<number>指定配置,<function>是指向从配置中删除的功能的符号链接,例如:
$ rm configs/c.1/ncm.usb0
删除配置中的字符串目录:
$ rmdir configs/<config name>.<number>/strings/<lang>
例如:
$ rmdir configs/c.1/strings/0x409
并删除配置:
$ rmdir configs/<config name>.<number>
例如:
rmdir configs/c.1
删除功能(功能模块不会被卸载):
$ rmdir functions/<name>.<instance name>
例如:
$ rmdir functions/ncm.usb0
删除gadget中的字符串目录:
$ rmdir strings/<lang>
例如:
$ rmdir strings/0x409
最后移除gadget:
$ cd ..
$ rmdir <gadget name>
例如:
$ rmdir g1
实施设计
下面介绍configfs的工作原理。在configfs中有项目和组,它们都表示为目录。项和组之间的区别在于,组可以包含其他组。下图中只显示了一个项目。项和组都可以具有属性,这些属性表示为文件。用户可以创建和删除目录,但不能删除文件,文件可以是只读的或读写的,这取决于它们所代表的内容。
configfs的文件系统部分操作config_items/groups和configfs_attributes,它们是通用的,对所有配置的元素具有相同的类型。但是,它们被嵌入到特定于使用的更大的结构中。下面的图片中有一个“cs”,它包含一个config_item和一个“sa”,它包含一个configfs_attribute。
文件系统视图是这样的:
./ ./cs (directory) | +--sa (file) | . . .
每当用户读取/写入“sa”文件时,都会调用一个函数,该函数接受一个struct config_item和一个struct configfs_attribute。在上述函数中,使用众所周知的container_of技术检索“cs”和“sa”,并调用适当的sa函数(show或store)并传递“cs”和字符缓冲区。“show”用于显示文件的内容(将数据从cs复制到缓冲区),而“store”用于修改文件的内容(将数据从缓冲区复制到cs),但这取决于两个函数的实现者来决定它们的操作。
typedef struct configured_structure cs; typedef struct specific_attribute sa; sa +----------------------------------+ cs | (*show)(cs *, buffer); | +-----------------+ | (*store)(cs *, buffer, length); | | | | | | +-------------+ | | +------------------+ | | | struct |-|----|------>|struct | | | | config_item | | | |configfs_attribute| | | +-------------+ | | +------------------+ | | | +----------------------------------+ | data to be set | . | | . +-----------------+ .
文件名由配置项/组设计器决定,而目录通常可以随意命名。一个组可以有许多自动创建的默认子组。
有关configfs的更多信息,请参见`Documentation/filesystems/configfs.rst`。
上面描述的概念转化为USB gadget如下:
1. 一个小工具有它的配置组,它有一些属性(idVendor, idProduct等)和默认子组(configs, functions, strings)。写入属性将导致信息存储在适当的位置。在配置、函数和字符串子组中,用户可以创建它们的子组来表示给定语言中的配置、函数和字符串组。
2. 用户创建配置和函数,在配置中创建到函数的符号链接。当将gadget的UDC属性写入时使用此信息,这意味着将gadget绑定到UDC。驱动程序/usb/gadget/configfs.c中的代码遍历所有配置,并且在每个配置中遍历所有函数并绑定它们。这样整个gadget就被绑定了。
3. 文件驱动程序/usb/gadget/configfs.c包含以下代码:
- gadget's config_group
- gadget's default groups (configs, functions, strings)
- associating functions with configurations (symlinks)
4. 个USB函数自然都有自己想要配置的视图,所以特定函数的config_groups定义在函数实现文件drivers/ USB /gadget/f_*.c中。
5. 函数的代码是以它所使用的方式编写的。
Usb_get_function_instance(),它反过来调用request_module。因此,只要modprobe工作正常,特定函数的模块就会自动加载。请注意,相反的情况是不正确的: 在 gadget 被禁用和卸载后,模块仍然是加载的。
本文来自博客园,作者:闹闹爸爸,转载请注明原文链接:https://www.cnblogs.com/wanglouxiaozi/p/15131949.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了