Linux Gadget的一點研究之U盤和USB虛擬串口


        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,有三個分區。

      執行:

root@rfODNCC:/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
root@rfODNCC:/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轉串口命令

root@rfODNCC:/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
root@rfODNCC:/mnt# [  240.044830] g_serial gadget: high speed config #2: CDC ACM config

PC端安裝USB轉串口驅動後,可以從PC設備管理器上看到多出了一個串口。

要使得設備端能與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;
	}
可見第一次註冊gadget驅動後udc->driver爲true,在不卸載情況下再次註冊gadget時出現無法註冊的錯誤。

【以下爲轉載: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




發佈了64 篇原創文章 · 獲贊 3 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章