简介
这篇文章主要介绍如何通过configfs在应用层实现用户空间的gadget驱动
U盘配置过程
内核打开configfs以及usb存储设备相关选项
CONFIG_CONFIGFS_FS : 为用户空间提供访问配置内核驱动的configfs文件系统

CONFIG_USB_LIBCOMPOSITE:提供usb gadget composite框架

CONFIG_USB_CHIPIDEA和CONFIG_USB_CHIPIDEA_UDC:打开UDC(USB Device Controller)的配置,配置硬件控制器


CONFIG_USB_CONFIGFS_MASS_STORAGE和CONFIG_USB_F_MASS_STORAGE:对应于usb_f_mass_storage.ko驱动


其他相关的选项(不知道是不是需要勾选的,反正都勾选了)


然后编译内核以及驱动,更新设备的内核,加载相关驱动,挂载configfs
insmod configfs.ko
insmod libcomposite.ko
insmod usb_f_mass_storage.ko
mount -t configfs none /sys/kernel/config/

创建g1实例
cd /sys/kernel/config/
ls
cd usb_gadget/
ls
mkdir g1
cd g1
ls

设置USB版本,PID, VID。(这里的PID和 VID的设置是我读取我的U盘 lsusb得到的,不过这个应该可以自己随便设置的)
echo 0x0200 > bcdUSB
echo "0x0781" > idVendor
echo "0x5151" > idProduct


创建并设置strings目录
mkdir strings/0x409
ls strings/0x409/
echo "12345678" > strings/0x409/serialnumber
echo "copyright" > strings/0x409/manufacturer
echo "moniupan" > strings/0x409/product


创建configuration和字符串,注意第三行的名字必须按照你加载的驱动后面的usb_f_*.ko来填写,比如我们加载的是usb_f_mass_storage.ko,那么这里的*就是mass_storage。如果不按照这样来的话,下一步创建funcitions会提示错误。
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "mass_storage" > configs/c.1/strings/0x409/configuration

创建funcitions
root@copyright:/sys/kernel/config/usb_gadget/g1# mkdir functions/mass_storage.0
[ 822.354698] Mass Storage Function, version: 2009/09/11
[ 822.361138] LUN: removable file: (no medium)

将functions和configuration关联起来
root@copyright:/sys/kernel/config/usb_gadget/g1# ln -s functions/mass_storage.0 configs/c.1
[ 986.215888] Number of LUNs=1
root@copyright:/sys/kernel/config/usb_gadget/g1#

绑定到UDC,使能gadget
root@copyright:/sys/kernel/config/usb_gadget/g1# ls -l /sys/class/udc/
total 0
lrwxrwxrwx 1 root root 0 Jun 30 03:06 ci_hdrc.0 -> ../../devices/platform/soc/2100000.aips-bus/2184000.usb/ci_hdrc.0/udc/ci_hdrc.0
root@copyright:/sys/kernel/config/usb_gadget/g1# echo ci_hdrc.0 > UDC

切记echo的时候不要加上绝对路径,只要把UDC的名字写入即可

U盘验证过程
这时候板子链接我的电脑,Ubuntu系统,dmesg下的枚举信息如下,可以看到

但是这个时候还没有找到分区信息,因为前面的时候还没配置U盘要使用的是哪个分区
我的板子弹出的内核打印

添加U盘存储分区配置
不清楚自己板子上哪块分区可以拿来做实验,所以我的想法是,板子外接一个SD卡,拿SD卡的分区来做为模拟U盘的分区,板子插上SD卡显示的分区是/dev/sdb1



U盘划分一个分区
这里介绍划分一个分区的做法,划分两个分区的做法可以参考链接一,输入如下命令配置
cd functions/mass_storage.0/
ls
echo /dev/sdb1 > lun.0/file
echo 1 > lun.0/removable
echo 0 > lun.0/nofua


添加分区后验证
添加分区后,我的Ubuntu系统,dmesg一下可以看到sdb分区的打印

电脑上也识别到这个模拟U盘

然后尝试接到我的Windows,貌似这两系统的驱动还不一样,反正Windows没识别出来,更新驱动也没用,先不管啦


CDC-NCM配置过程
相关的内核项打开,过程类似前面的U盘配置过程,这里就不赘述了


升级内核,加载驱动
insmod configfs.ko
insmod libcomposite.ko
insmod u_ether.ko
insmod usb_f_ncm.ko

挂载configfs,创建g2实例
mount -t configfs none /sys/kernel/config/
cd /sys/kernel/config/
ls
cd usb_gadget/
mkdir g2
cd g2/
ls

设置USB版本,PID, VID。(这里的PID和 VID的设置我是根据内核的ncm.c中来的)
echo 0x0200 > bcdUSB
echo 0x0525 > idVendor
echo 0xa4a1 > idProduct


创建并设置strings目录
mkdir strings/0x409
echo "123456789" > strings/0x409/serialnumber
echo "copyright_manufacture" > strings/0x409/manufacturer
echo "copyright_product" > strings/0x409/product

创建configuration和字符串,注意第三行的名字是ncm
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "ncm" > configs/c.1/strings/0x409/configuration

创建funcitions
root@copyright:/sys/kernel/config/usb_gadget/g2# mkdir functions/ncm.0
[ 260.395518] using random self ethernet address
[ 260.400003] using random host ethernet address

将functions和configuration关联起来
ln -s functions/ncm.0 configs/c.1

绑定到UDC,使能gadget
root@copyright:/sys/kernel/config/usb_gadget/g2# ls -l /sys/class/udc/
total 0
lrwxrwxrwx 1 root root 0 Jun 30 03:58 ci_hdrc.0 -> ../../devices/platform/soc/2100000.aips-bus/2184000.usb/ci_hdrc.0/udc/ci_hdrc.0
root@copyright:/sys/kernel/config/usb_gadget/g2# echo ci_hdrc.0 > UDC
[ 193.443011] usb0: HOST MAC 56:1f:48:5f:28:9d
[ 193.461533] usb0: MAC f6:d4:5f:72:f4:75
root@copyright:/sys/kernel/config/usb_gadget/g2# [ 193.621532] IPv6: ADDRCONF(NETDEV_UP): usb0: link is not ready

板子上查看发现usb0节点已经有了
root@copyright:/sys/kernel/config/usb_gadget/g2# ifconfig -a | grep usb
usb0 Link encap:Ethernet HWaddr f6:d4:5f:72:f4:75
root@copyright:/sys/kernel/config/usb_gadget/g2# ifconfig usb0
usb0 Link encap:Ethernet HWaddr f6:d4:5f:72:f4:75
inet addr:192.168.7.2 Bcast:192.168.7.255 Mask:255.255.255.0
UP BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

CDC-NCM验证过程
配置好后,将板子上的usb device接口接到我的PC,Ubuntu系统弹出的内核热插拔消息
[5034810.987491] usb 1-2: new high-speed USB device number 84 using xhci_hcd
[5034811.137990] usb 1-2: New USB device found, idVendor=0525, idProduct=a4a1, bcdDevice= 4.01
[5034811.137999] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[5034811.138004] usb 1-2: Product: copyright_product
[5034811.138008] usb 1-2: Manufacturer: copyright_manufacture
[5034811.138013] usb 1-2: SerialNumber: 123456789
[5034811.165335] cdc_ncm 1-2:1.0: MAC-Address: 56:1f:48:5f:28:9d
[5034811.165807] cdc_ncm 1-2:1.0 usb0: register 'cdc_ncm' at usb-0000:00:14.0-2, CDC NCM, 56:1f:48:5f:28:9d
[5034811.213378] cdc_ncm 1-2:1.0 enp0s20f0u2: renamed from usb0
[5034811.254119] cdc_ncm 1-2:1.0 enp0s20f0u2: 425 mbit/s downlink 425 mbit/s uplink
[5034811.318224] IPv6: ADDRCONF(NETDEV_CHANGE): enp0s20f0u2: link becomes ready

可以看到enp0s20f0u2: renamed from usb0和enp0s20f0u2: link becomes ready等关键打印,ifconfig命令查看,发现enp0s20f0u2节点已经有了

设置IP(这里一定要设置子网掩码)

我的PC设置好了后,板子这边的打印usb0 : link becomes ready

板子这边ping我的PC

我的PC来ping我的板子

参考链接
其他问题
- 参考链接一中有实现两个独立的
U盘的方法,后续可以自己试试 -
在测试的时候发现,不知道是不是我板子的问题,无论是配置成
U盘还是NCM设备,时不时会自动断联又重联 -
drivers/usb/gadget目录下ko不是有两个目录嘛function跟legacy,之前不懂有什么差别,这次使用了configfs,大概知道了就是,function是放可以通过用户态配置的驱动,而legacy则是帮你都做好了的
chipidea不清楚是什么,是一种usb设计的规范?