linux USB从设备使用gadget实现大容量存储设备

硬件平台:fresscale iMX6Q

linux内核版本4.1.15

Gadget 框架提出了一套标准API, 在底层, USB 设备控制器 (USB Device Controller, UDC) 驱动则实现这一套 API, 不同的 UDC (通常是 SOC 的一部分) 需要不同的驱动, 甚至基于同样的 UDC 的不同板子也需要进行代码修改。这一层我们可以称之为平台相关层。

Linux-USB Gadget 驱动框架(以下简称 Gadget )实现了 USB 协议定义的设备端的软件功能。相对于 Linux USB 主机端( Host ) 驱动而言, Gadget 驱动出现较晚,它出现在 2.4.23 以后

基于 API, Gadget 驱动实现了一套硬件无关的功能,这基本上可以对应到 USB 协议里 的各种 USB Class , 也有比如 USB Gadget Generic Serial 驱动,没有对应的 Class 。当然, Gadget 驱动还是受限于底层提供的功能的。比如 某些 Class 需要 USB Isochronous 端点,这时我们就不能支持该 Class 。
普通的 Gadget 驱动只实现一个功能(比如, u 盘, usb 网卡)。复合设备可以支持多个功能,后面将仔细研究一下复合设备的实现。像智能手机 , PDA 这样的设备,硬件支持较丰富的端点、 DMA Buffer, 给软件提了支持复合功能的基础。
有两点值得注意,第一是 usb gaget 驱动框架不象 usb 主机端有 usb core 的概念, usb 主机可能支持成百类型的外设,把通用功能抽象出来很有意义。 Usb device 端则通常没有这个需求,一些通用功能抽象在一些 Helper 函数里就可以了。第二是 usb 2.0 里提出了 OTG的概念,可以在同一接口上支持 host 以及 device 功能。 OTG 是一个比较复杂的规范,以后有时间再研究。

        

    Linux USB 设备端驱动有两部分组成。一部分是USB 设备控制器(USB Device Controller, UDC)驱动、另一部分是硬件无关的功能驱动(如:鼠标、u盘、usb串口、usb网络等);也可以分为3层的,

分别是:UDC   Controller Drivers(usb 从设备相关的硬件驱动)

               Gadget Drivers(提供了usb从设备的具体功能,如HID鼠标,键盘,串口,u盘等功能)

                Upper Layers(提供了usb从设备的core,提供了相应的驱动框架以及API)



使用usb gadget 实现大容量存储主要使用两种方式。

方式1:在linux3.0内核以前,使用insmod方式实现。

优点:资料多,支持老版本内核。

缺点:需要在模块插入阶段配置。只能[M]的方式编译出ko模块然后插入阶段配置,或者需要修改内核代码给一套默认参数,调用方式比较奇怪。

1,menuconfig配置相关的内核模块 [M] g_file_storage.ko

Device Drivers  --->

            [*] USB support  ---> 

                    <*>   USB Gadget Support  --->  

                                   USB Gadget Drivers 配置[M] g_file_storage.ko


    


        2 配置完成后,make uImage编译内核,然后 make modules编译模块,在 /driver/usb/gadget/下面形成驱动模块 g_mass_storage.ko文件,把这个文件拷贝到文件系统的   “/lib/modules/内核版本/kernel/drivers/usb/gadget/” 目录下面, modprobe 命令会在lib/modules路径下面搜索要加载的驱动模块库文件。

        

  3 机器里执行:

   modprobe  g_mass_storage file=/dev/mmcblk0  removable=1  

或者

    module_path=/lib/modules/内核版本/g_file_storage.ko

    insmod ${module_path} file=/dev/mmcblk1p1 stall=0 removable=1

  以上命令加载gadget msc驱动,传递SD卡为模块参数,使用micro usb 线连接板卡与PC,这时PC端识SDFAT32分区,可以拷贝文件到SD卡中,拷贝完成后可以在开发板中查看到SD卡中的新文件。 使用超级终端在SD卡创建文件,需要重新连接板卡与PCPC才能识别SD卡新创建的文件.

另外需要注意的是:从SD卡拷贝文件到PC,速度是比较快的,能达到18M/S,而从PC拷贝文件到SD卡速度很慢,大概是1.4M/s,最后拷贝的文件经过MD5验证,数据是安全的,未丢失数据。

Read:

b9cdf2cbec8014750fde35d9e32674f4-----origin sdcard file---OK--MAX SPEED=18M/S-

b9cdf2cbec8014750fde35d9e32674f4-----read to pc files

Write:

b9cdf2cbec8014750fde35d9e32674f4------pc file-OK-MAX SPEED=1.4M/S

b9cdf2cbec8014750fde35d9e32674f4------sdcard file


        方式2:在linux3.0内核之后的版本,使用insmod方式实现。

        

优点:使用configfs进行配置,配置方便,可在任何阶段使用,将会成为未来主流方式

缺点:不支持3.0以下的内核

1,menuconfig配置相关的内核模块

    

Device Drivers  --->

            [*] USB support  ---> 

                    <*>   USB Gadget Support  --->  

                                             <*>   USB Gadget Drivers (USB functions configurable through configfs)  --->

                                             [*]       Mass storage  

       2,挂载configfs文件系统:

                   $ mount none $CONFIGFS_HOME -t configfs
                    where CONFIGFS_HOME is the mount point for configfs

                    例:

                    # mount -t configfs none /sys/kernel/config

        3,新建garget是实例:

                    For each gadget to be created its corresponding directory must be created:

                    $ mkdir $CONFIGFS_HOME/usb_gadget/<gadget name>

                    例:

                    $ mkdir $CONFIGFS_HOME/usb_gadget/g1

                    $ cd   $CONFIGFS_HOME/usb_gadget/g1

         4,配置idVendor与idProduct

                定义产品的VendorID和ProductID

                Each gadget needs to have its vendor id <VID> and product id <PID> specified:

                $ echo <VID> > idVendor

                $ echo <PID> > idProduct

                例:

        # echo "0xabcd"  > idVendor

        # echo "0x1234" > idProduct

         5,初始化描述符字符串:

                将开发商、产品和序列号字符串写入内核:

               $ mkdir strings/0x409


                Then the strings can be specified:


                $ echo <serial number> > strings/0x409/serialnumber
                $ echo <manufacturer> > strings/0x409/manufacturer

                $ echo <product> > strings/0x409/product

                例:

          # echo "0123456789ABCDEF" > strings/0x409/serialnumber

          # echo "Master"  > strings/0x409/manufacturer

          # echo "Demo"  > strings/0x409/product

    4,创建功能实例:

          The gadget will provide some functions, for each function its corresponding
                directory must be created:


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

         这里的名称是模块名称,类比于g_mass_storage.ko去掉前缀,去掉结尾,即得到名称,

         查看名称可以查看 drivers/usb/gadget/function/Makefile 得到相应的名称,去掉usb_f_前缀,去掉.o后缀

        

                where <name> corresponds to one of allowed function names and instance name
                is an arbitrary string allowed in a filesystem, e.g.:

                例子:    
                $ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module()

                usb存储的话:

                $ mkdir mass_storage.usb0

                如果成功:打印正确信息如下:

                

                如果失败打印错误信息,没有找到相应的功能实现:

                



            4,创建配置实例:

            Each gadget will consist of a number of configurations, their corresponding
            directories must be created:
            $ mkdir configs/<name>.<number>
            where <name> can be any string which is legal in a filesystem and the
            <number> is the configuration's number, e.g.:

            例:

            # mkdir configs/c.1/ #创建实例c.1

            # mkdir configs/c.1/strings/0x409 #创建描述字符串

            # echo "DRAGON" > configfs/c.1/strings/0x409/configuration #描述符字符串写入DRAGON

            # echo 120 > configs/c.1/MaxPower 写入最大电流需求

            # ln -s functions/mass_storage.usb0/ configs/c.1/ #捆绑功能实例mass_storage到配置c.1


            5,绑定gedget实例到UDC物理硬件

            首先查看板子上的UDC设备

            [root@dragonExt g1]# ls /sys/class/udc/
            ci_hdrc.0

            

        Such a gadget must be finally enabled so that the USB host can enumerate it.
        In order to enable the gadget it must be bound to a UDC (USB Device Controller).


        $ echo <udc name> > UDC

        例:

        # echo ci_hdrc.0 >UDC   #绑定gedget实例到UDC物理硬件

        此时此刻,接入usb线到pc,U盘出来了。恭喜

        注:卸载gadget设备:

        echo "" > UDC



下面附上我的完整配置实例enable_usb_gadget_mass_storage_configfs.sh

#!/bin/sh

#set -xv
set -e
mount -t configfs none /sys/kernel/config/
cd /sys/kernel/config/usb_gadget/
mkdir g1
cd g1/

echo "0xABCD" >idVendor 
echo "0x1017" >idProduct  
cat idVendor 
cat idProduct
 
mkdir strings/0x409/
echo "012345678ABCDEF" >strings/0x409/serialnumber 
echo "Dragon" 				 >strings/0x409/manufacturer 
echo "DragonMSC" 					 >strings/0x409/product 



mkdir functions/mass_storage.usb0
echo /dev/mmcblk1p1 >functions/mass_storage.usb0/lun.0/file 

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

echo "abc" > configs/c.1/strings/0x409/configuration 
cat configs/c.1/strings/0x409/configuration 
ln -s functions/mass_storage.usb0/ configs/c.1/

ls /sys/class/udc/
echo ci_hdrc.0 >UDC

echo !!!!!!!!!!!!!!!!!!
echo !!!!!OK!!!!!!!!!!!
echo !!!!!!!!!!!!!!!!!!


猜你喜欢

转载自blog.csdn.net/dragon101788/article/details/80888078