usb gadget configfs 翻译

本文翻译Documentation/usb/gadget_configfs.txt文档。主要是讲述如何通过configfs配置USB Gadget的functions注意:这里使用的是配置,也就是要求内核必须存在对应的functions。与ffs的差别是,ffs可以创建一个新的functions,内核并不要求事先存在。

简介

Linux USB Gadget是一个拥有UDC(USB Device Controller)的设备,该设备可以用于连接到USB Host用于扩展额外的功能,比如串口或者大容量存储(MTP)。Android就是一个支持MTP的USB Gadget。当Android手机插入到电脑中(USB Host),电脑可以识别出一个多媒体设备出来。

USB Host可以通过一些configurations来识别gadget,configuration包括多个interfaces(这里可以理解为USB描述符直接的层级关系)。从gadget的角度来看是functions,每个fcunction代表一种功能,比如串口或者SCSI磁盘。
Linux为gadget提供一系列的functions,在drivers/usb/gadget/function/目录中定义。

创建gadget意味着决定将使用哪些configurations,以及每种configurations将提供的functions在这之前是以hardcode的方式在代码中设定的,比如drivers/usb/gadget/legacy/的gadget都是。

configfs(请参阅Documentation/filesystems/configfs/*)非常适合告诉内核有关上述决定的内容。为啥是configfs呢?因为configfs支持从用户空间配置内核空间的驱动。反之,sysfs支持同内核空间export一些对象供用户空间查看。本文档是讲关于如何做到的,以及描述了如何设计将configfs与usb gadget集成在一起。


要求

必须在内核中使能CONFIGFS_FS,当然USB_LIBCOMPOSITE也必须使能。与之对应的代码在fs/configfsdrivers/usb/gadget/


使用

(可以在这里看到通过configfs提供第一个功能的原始帖子:http://www.spinics.net/lists/linux-usb/msg76388.html)

inmod驱动

1
2
3
$ insmod libcomposite.ko
$ insmode configfs.ko
$ mount none $CONFIGFS_HOME -t configfs

这里的CONFIGS_HOMEconfigfs的挂载点,通常为mount -t configfs none /config

创建gadget

1、对于要创建的每个gadget,必须创建其相应的目录:

1
2
3
$ mkdir $CONFIGFS_HOME/usb_gadget/<gadget name>
$ cd $CONFIGFS_HOME/usb_gadget/g1
......

比如说:mkdir $CONFIGFS_HOME/usb_gadget/g1,你如果有多个gadget,就可以创建g2g3等。
2、配置PID和VID
每个gadget都要指定PID和VID:

1
2
$ echo <VID> > idVendor
$ echo <PID> > idProduct

3、创建并配置string字目录
gadget还需要其serial numbermanufacturerproduct。 为了有一个存储它们的地方,必须为每种语言创建一个strings子目录,比如:

1
2
3
4
$ mkdir strings/0x409
$ echo <serial number> > strings/0x409/serialnumber
$ echo <manufacturer> > strings/0x409/manufacturer
$ echo <product> > strings/0x409/product

创建configurations

每个gadget都包含许多配置,必须创建相应的目录:

1
$ mkdir configs/<name>.<number>

<name>必须是在文件系统中有效的字符串,<number>表示配置号,比如:

1
2
$ mkdir configs/c.1
......

每个配置也需要其字符串,因此必须为每种语言创建子目录,比如:

1
$ mkdir configs/c.1/strings/0x409

然后就可以指定配置字符串:

1
$ echo <configuration> > configs/c.1/strings/0x409/configuration

创建functions

gadget将提供一些functions,每个functions必须创建相应的目录,比如:

1
$ mkdir functions/<name>.<instance name>

其中<name>对应于一个允许的functions名称,而实例名称是文件系统中允许的任意字符串,例如(前提条件是必须加载usb_f_ncm.ko驱动):

1
2
$ mkdir functions/ncm.usb0
......

每个functions都提供其特定的属性集,具有只读或读写访问权限。 在适用的情况下,需要酌情编写。有关更多信息,请参阅Documentation/ABI/configfs-usb-gadget`

functionsconfiguration关联起来

此时会创建许多gadget,每个gadget都指定了许多配置,并提供了许多功能。 剩下的是指定哪种配置可用的功能(在多种配置中可以使用相同的功能)。这是通过创建符号链接来实现的。

1
$ ln -s functions/<name>.<instance name> configs/<name>.<number>

比如:

1
$ ln -s functions/ncm.usb0 configs/c.1

使能gadget

所有上述步骤都用于组成configurationfunctionsgadget,示例目录结构可能如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.
./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 Device Controller):

1
$ echo <udc name> > UDC

<udc name>可以从/sys/class/udc/*中找到。

关闭gadget

1
$ echo "" > UDC

清空

  • configurations中将functions删掉,比如将<config name>.<number>的configure与<function>之间的软连接删除:

    1
    2
    $ rm configs/<config name>.<number>/<function>
    $ rm configs/c.1/ncm.usb0
  • 删除configurations的字符串

    1
    $ rmdir configs/<config name>.<number>/strings/<lang>
  • 删除configurations

    1
    $ rmdir configs/<config name>.<number>
  • 删除functions

    1
    $ rmdir functions/<name>.<instance name>
  • 删除gadget的字符串

    1
    $ rmdir strings/<lang>
  • 删除gadget

    1
    2
    $ cd ..
    $ rmdir <gadget name>

实现方式

在configfs中有item(项目)group(组),都表示为目录。 项目和组之间的区别在于组可以包含其他组。 在下图中只显示了一个项目。 项目和组都可以具有属性,这些属性表示为文件。 用户可以创建和删除目录,但不能删除文件,这些文件可以是只读或读写,具体取决于它们所代表的内容。

configfs的文件系统部分在config_items/groupsconfigfs_attributes上操作,这些通用且所有已配置元素的类型相同。但是,它们嵌入在特定于使用的更大结构中。 在下面的图片中有一个cs包含一个config_item和一个包含configfs_attributesa

1
2
3
4
5
6
7
./
./cs (directory)
|
+--sa (file)
|
.
.

每当用户读/写sa文件时,都会调用一个接受struct config_itemstruct configfs_attribute的函数。在所述函数中,使用众所周知的container_of技术检索cssa,并调用适当的sa函数(show或store)并传递cs和字符缓冲区。show函数用于显示文件的内容(将数据从cs复制到缓冲区),而store函数用于修改文件的内容(将数据从缓冲区复制到cs),但这取决于实现者 这两个函数决定了他们实际做了什么。

文件名由配置项/组设计器决定,而一般目录可以随意命名。一个组可以自动创建许多默认子组。
请参阅:Documentation/filesystems/configfs/*

上述概念转换为USB gadget,如下所示:

1、gadget有自己的配置组,它具有一些属性(idVendor,idProduct等)和默认子组(配置,函数,字符串)。 写入属性会导致信息存储在适当的位置。在配置,函数和字符串子组中,用户可以创建其子组以表示给定语言中的配置,函数和字符串组。
2、用户创建配置和功能,在配置中创建功能的符号链接。在写入gadget的UDC属性时使用此信息,这意味着将小工具绑定到UDC。 drivers/usb/gadget/configfs.c中的代码遍历所有配置,并在每个配置中迭代所有函数并绑定它们。这样整个gadget就绑定了。
3、drivers/usb/gadget/configfs.c包含的代码如下:

1
2
3
- 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。 因此,只要insmod工作,就会自动加载特定函数的模块。请注意,反之亦然,在禁用并拆除gadget后,模块仍会加载。


参考资料

Title:usb gadget configfs 翻译

Author:Victor Huang

Time:2019-11-24 / 10:11

Link:http://wowothink.com/440dc3d9/

License: Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)