Linux kernel2.6以上的版本中,USB设备驱动的接口改为了gadget,在kernel/driver/usb/gadget目录下主要包含了平台USB UDC驱动和gadget接口驱动。
kernel/driver/usb/gadget目下的serial.c是一个常用的驱动文件,它可以配置为bulk传输驱动或CDC ACM驱动(USB转串口驱动)。配置的方式有两种,一可以在编译前手动更改驱动文件中的变量“use_acm"的默认值,现在默认值为”true“,对应为CDC ACM驱动,改为”false"后对应为bulk驱动;二可以将驱动编译成模块,然后在insmod时传递一个参数就行了。
运行make menuconfig看一下:
将“USB Gadget Support -->"选择编译为模块,方便动态加载驱动。
进行“USB Gadget Support -->"配置子菜单:
配置红色方框标注的模块。
运行命令: make M=driver/usb/gagdet modules
编译后在driver/usb/gagdet 下生产g_file_storage.ko和g_serial.ko,分别对应为U盘驱动和USB转串口驱动。
笔者的嵌入式板上有个SD卡,linux驱动后挂载主目录是/dev/mmcblk0,分区目录是/dev/mmcblk0p1,/dev/mmcblk0p2,/dev/mmcblk0p3,有三个分区。
执行:
- [email protected]:/mnt# insmod g_file_storage.ko file=/dev/mmcblk0 stall=0 removable=1
- [ 69.783477] g_file_storage gadget: No serial-number string provided!
- [ 69.798980] g_file_storage gadget: File-backed Storage Gadget, version: 1 September 2010
- [ 69.807495] g_file_storage gadget: Number of LUNs=1
- [ 69.812622] g_file_storage gadget-lun0: ro=0, nofua=0, file: /dev/mmcblk0
- [ 69.819763] musb-hdrc musb-hdrc.0: MUSB HDRC host driver
- [ 69.825622] musb-hdrc musb-hdrc.0: new USB bus registered, assigned bus number 2
- [ 69.833801] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002
- [ 69.840942] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
- [ 69.848510] usb usb2: Product: MUSB HDRC host driver
- [ 69.853668] usb usb2: Manufacturer: Linux 2.6.37-05branch musb-hcd
- [ 69.860137] usb usb2: SerialNumber: musb-hdrc.0
- [ 69.872558] hub 2-0:1.0: USB hub found
- [ 69.876647] hub 2-0:1.0: 1 port detected
- [email protected]:/mnt# [ 70.169555] g_file_storage gadget: high speed config #1
连接USB到PC,可以看到PC端出现SD卡的分区目录。
PS:insmod g_file_storage.ko file=/dev/mmcblk0 stall=0 removable=1 和 insmod g_file_storage.ko file=/dev/mmcblk0有点区别,后续可以查找理解stall 和 removable的具体作用。
接着制作一个嵌入式设备端fat32文件分区,然后挂载到PC上:
1.在主机ubuntu上建立fat32文件映像,大小为2M。
#dd if=/dev/zero of=fat32.img bs=1k count=2048
#mkfs.vfat fat32.img
2.向fat32.img中写入一些文件,以用来测试:
#mkdir fat32
#sudo mount -t vfat -o loop fat32.img fat32
#cd fat32
#touch hello.txt
#echo hello,wolrd>hello.txt
#sync
3.把主机ubuntu上的fat32.img 拷贝到嵌入式设备的根文件系统中。
4.在嵌入式设备中加载g_file_storage驱动
insmod g_file_storage.ko file=/opt/fat32.img stall=0 removable=1 //我将fat32.img放在/opt下
5.USB线连接设备和PC,弹出发现移动磁盘,打开盘,里面有个hello.txt文件。
6.在PC端打开U盘,增加一个文件系统,如text.txt,然后在设备端通过命令挂载映像,命令为:
mount -t vfat -o loop /opt/fat32.img /media //挂载到media目录下
到media目录,cd /media
看到/media目下有两个文件hello.txt和test.txt,且内容和在PC端看到的一致。
注意:如果此时在PC端再次修改了文件。这设备端不能立即看到PC修改的结果。即PC和设备端不能同步。
此时可以在设备进行umount /media,然后重新mount一次就可以看到PC更改的结果。同样在设备端修改的文件,PC端也不能立即看到修改结果,需重新插拔USB线才能看到更新。至于原因,暂时不知道。
卸载g_file_storage
执行加载USB转串口命令
- [email protected]:/mnt# insmod g_serial.ko
- [ 239.675933] g_serial gadget: Gadget Serial v2.4
- [ 239.680786] g_serial gadget: g_serial ready
- [ 239.685241] musb-hdrc musb-hdrc.0: MUSB HDRC host driver
- [ 239.691009] musb-hdrc musb-hdrc.0: new USB bus registered, assigned bus number 2
- [ 239.707153] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002
- [ 239.714324] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
- [ 239.721893] usb usb2: Product: MUSB HDRC host driver
- [ 239.727111] usb usb2: Manufacturer: Linux 2.6.37-05branch musb-hcd
- [ 239.733581] usb usb2: SerialNumber: musb-hdrc.0
- [ 239.747467] hub 2-0:1.0: USB hub found
- [ 239.751434] hub 2-0:1.0: 1 port detected
- [email protected]:/mnt# [ 240.044830] g_serial gadget: high speed config #2: CDC ACM config
要使得设备端能与PC端通过USB转串口进行通信,设备端还需要手动创建设备文件节点,参考内核文档(Documents/usb/gagdet_serial.txt)中的部分内容:
This will also automatically load the underlying gadget peripheral
controller driver. This must be done each time you reboot the gadget
side Linux system. You can add this to the start up scripts, if
desired.
Your system should use mdev (from busybox) or udev to make the
device nodes. After this gadget driver has been set up you should
then see a /dev/ttyGS0 node:
# ls -l /dev/ttyGS0 | cat
crw-rw---- 1 root root 253, 0 May 8 14:10 /dev/ttyGS0
#
Note that the major number (253, above) is system-specific. If
you need to create /dev nodes by hand, the right numbers to use
will be in the /sys/class/tty/ttyGS0/dev file.
作者创建设备节点为:先cat /sys/class/tty/ttyGS0/dev,得到主设备号后,mknod /dev/ttyGS0 c major_num 0
然后PC打开一个串口软件,打开对应的串口端口。
设备端执行 echo “hello” > /dev/ttyGS0,PC端串口软件收到相应数据。
PS:UDC(设备控制器)驱动主要是与硬件平台相关的,它会实现gadget功能驱动所需要的接口,一般的UDC仅支持注册一个gadget功能驱动,所以上面是在将g_file_storage驱动卸载后才能重新加载g_serial.ko。否则会出现失败。
看看UDC驱动代码中的注册gadget驱动函数usb_gadget_probe_driver中的部分程序:
- spin_lock_irqsave(&udc->lock, flags);
- if (udc->driver) {
- spin_unlock_irqrestore(&udc->lock, flags);
- return -EBUSY;
- }
【以下为转载:http://blog.csdn.net/embededswordman/article/details/6689593】
Linux支持连接各种USB从设备,同时也支持自己作为设备插入到其他主机当中。最典型的例子就是Android OS的手机,插入电脑可以被识别为U盘之类的设备。
对于SOC来说,这部分直接对应了USB Device部分的操作。
为了避免与作为主机时支持的"设备驱动 (USB Device Driver)"一词混淆, Linux给这部分的实现取名为"Gadget",小玩具。内核源码的目录为\drivers\usb\gadget,里面包含了内核所支持的不同类型的USB Device Controller (UDC)驱动的实现,以及框架和不同gadget的实现。
以AT91 ARM9为例,最底层的驱动为at91_udc.c(对于支持高速USB 2.0的SOC是atmel_usba_udc.c),它实现了gadget.h定义的统一接口,然后上层的各种gadget driver(如serial.c等)调用这一套统一的接口去实现不同类型的功能,如USB串口、U盘、USB以太网等等。
Atmel USB串口的框架图:
USB串口的描述和使用方法在内核目录\Documentation\usb\gadget_serial.txt中有详细且清晰的描述,就不再这里重复。一旦加载模块后会自动在/dev/下创建设备文件,程序就可以open它并且write,即使USB线没有连接上。之前一直纠结在为什么g_serial没有向上层提供USB cable connect/disconnect的事件,后来想想在使用串口的时候也是一样的情况,打开一个即使没有连接线的串口,也可以发送数据,只是没有人会收到而已。不过与串口唯一的不同在于,如果通讯正在进行中拔掉USB线,那么再次连接USB线后需要重新open一次ttyGS0设备文件才可以重新发送,否则write不能向串口一样正常工作而返回出错。
参考部分:
官方Gadget框架的描述:http://www.linux-usb.org/gadget/
基于9263的配置过程:http://www.cublog.cn/u3/111925/showart_2278264.html
华清讲师刘洪涛的BLOG:http://blog.csdn.net/hongtao_liu/article/details/4555645