USBgadget设备驱动解析.docx
《USBgadget设备驱动解析.docx》由会员分享,可在线阅读,更多相关《USBgadget设备驱动解析.docx(40页珍藏版)》请在冰点文库上搜索。
USBgadget设备驱动解析
USBgadget设备驱动解析
利用LinuxUSBgadget设备驱动能够实现一些比较有意思的功能,举两个例子:
1、一个嵌入式产品中的某个储备设备,或是一个储备设备的某个分区,能够作为一个U盘被PC设不,从而专门方便的完成文件交互,那个功能被广泛的应用于手机、数码相机等产品中。
一个嵌入式设备通过USB连接到你的PC后,在你的PC端会显现一个新的网络连接,在嵌入式设备上也会有一个网卡设备,你能够配置它们的IP地址,并进行网络通讯,俗称USBNET。
所有USB通讯的设备端都有usbdevice程序,通常称它们为usb固件。
在一些功能简单的设备里,用一些专用的可编程USB操纵器就能够了。
而在一些运行了类似linux操作系统的复杂的嵌入式系统中,要完成usbdevice程序,就会要求你不仅熟悉usbdevice操纵器的操作,还要熟悉操作系统的驱动架构。
我想通过“功能体验”、“驱动调试”、“gadget驱动结构分析”、“编写一个自己的gadget驱动”这4个方面解析linuxusbgadget设备驱动的编写方法。
一、linux模拟U盘功能的实现
在硬件环境为华清远见的fs2410平台,软件环境为linux-2.6.26的linux系统上,实现模拟U盘的功能。
向内核添加代码
#include
#include
#include
修改arch/arm/mach-s3c2410/mach-smdk2410.c
/*USBdevice上拉电阻处理*/
staticvoidsmdk2410_udc_pullup(enums3c2410_udc_cmd_ecmd)
{
u8*s3c2410_pullup_info[]={
"",
"Pull-upenable",
"Pull-updisable",
"UDCreset,incaseof"
};
printk("smdk2410_udc:
%s\\n",s3c2410_pullup_info[cmd]);
s3c2410_gpio_cfgpin(S3C2410_GPG9,S3C2410_GPG9_OUTP);
switch(cmd)
{
caseS3C2410_UDC_P_ENABLE:
s3c2410_gpio_setpin(S3C2410_GPG9,1);//setgpg9outputHIGH
break;
caseS3C2410_UDC_P_DISABLE:
s3c2410_gpio_setpin(S3C2410_GPG9,0);//setgpg9outputLOW
break;
caseS3C2410_UDC_P_RESET:
//FIXME!
!
!
break;
default:
break;
}
}
staticstructs3c2410_udc_mach_infosmdk2410_udc_cfg__initdata={
.udc_command=smdk2410_udc_pullup,
};
staticstructplatform_device*smdk2410_devices[]__initdata={
…,
&s3c_device_usbgadget,/*USBgadgetdevice设备登记*/
};
staticvoid__initsdmk2410_init(void)
{
u32upll_value;
set_s3c2410fb_info(&smdk2410_lcdcfg);
s3c24xx_udc_set_platdata(&smdk2410_udc_cfg);/*初始化*/
s3c_device_sdi.dev.platform_data=&smdk2410_mmc_cfg;
/*TurnoffsuspendonbothUSBports,andswitchthe
*selectableUSBporttoUSBdevicemode.*/
修改drivers/usb/gadget/file_storage.c
staticvoidstart_transfer(structfsg_dev*fsg,structusb_ep*ep,
structusb_request*req,int*pbusy,
enumfsg_buffer_state*state)
{
intrc;
udelay(800);
……
}
配置内核支持U盘模拟
<*>USBGadgetSupport--->
USBPeripheralController(S3C2410USBDeviceController)--->
S3C2410USBDeviceController
[*]S3C2410udcdebugmessages
USBGadgetDrivers
File-backedStorageGadget
3、编译内核
#makezImage
#makemodules
在名目drivers/usb/gadget下生成g_file_storage.ko
加载驱动,测试功能
利用前面的生成的内核,启动系统后,加载g_file_storage.ko
#insmodg_file_storage.ko
#insmodg_file_storage.kofile=/dev/mtdblock2stall=0removable=1
0.03USB:
usb_gadget_register_driver()\'g_file_storage\'
0.04USB:
bindinggadgetdriver\'g_file_storage\'
0.05USB:
s3c2410_set_selfpowered()
g_file_storagegadget:
File-backedStorageGadget,version:
20October2004
g_file_storagegadget:
NumberofLUNs=1
g_file_storagegadget-lun0:
ro=0,file:
/dev/mtdblock3
0.06USB:
udc_enablecalled
smdk2410_udc:
Pull-upenable
连接设备到windows,windows系统会自动设备到一个新的U盘加入。
格式化U盘,存入文件。
卸载U盘后,在目标板上执行如下操作:
#mkdir/mnt/gadget
#mount-tvfat/dev/mtdblock2/mnt/gadget/
#ls
能够看到windows存入U盘的文件。
二、usbnet功能的实现
配置内核支持usbnet
<*>USBGadgetSupport--->
USBPeripheralController(S3C2410USBDeviceController)--->
S3C2410USBDeviceController
[*]S3C2410udcdebugmessages
USBGadgetDrivers
EthernetGadget(withCDCEthernetsupport)
[*]RNDISsupport
2、编译内核
#makezImage
#makemodules
在名目drivers/usb/gadget下生成g_ether.ko
3、加载驱动,测试功能
利用前面的生成的内核,启动系统后,加载g_ether.ko
#insmodg_ether.ko
#ifconfigusb0192.168.1.120
……
usb0Linkencap:
EthernetHWaddr5E:
C5:
F6:
D4:
2B:
91
inetaddr:
192.168.1.120Bcast:
192.168.1.255Mask:
255.255.255.0
UPBROADCASTRUNNINGMULTICASTMTU:
1500Metric:
1
RXpackets:
253errors:
0dropped:
0overruns:
0frame:
0
TXpackets:
43errors:
0dropped:
0overruns:
0carrier:
0
collisions:
0txqueuelen:
1000
RXbytes:
35277(34.4KiB)TXbytes:
10152(9.9KiB)
连接设备到windows,windows系统会提示安装驱动,按照提示安装上RNDIS驱动。
那个驱动能够在网络上找到。
现在windows会新生成一个网络连接,配置它的ip地址等信息。
然后就能够和目标系统通过USB实现网络通讯了。
LinuxUSBgadget设备驱动解析
(2)---驱动调试
这一节要紧把在实现“linux模拟U盘功能”过程中的一些调试过程记录下来,并加以解析。
背景知识
1、USBMassStorage类规范概述
USB组织在universalSerialBusMassStorageClassSpaceification1.1版本中定义了海量储备设备类(MassStorageClass)的规范,那个类规范包括四个独立的子类规范,即:
1.USBMassStorageClassControl/Bulk/Interrupt(CBI)Transport
2.USBMassStorageClassBulk-OnlyTransport
3.USBMassStorageClassATACommandBlock
4.USBMassStorageClassUFICommandSpecification
前两个子规范定义了数据/命令/状态在USB上的传输方法。
Bulk-Only传输规范仅仅使用Bulk端点传送数据/命令/状态,CBI传输规范则使用Control/Bulk/Interrupt三种类型的端点进行数据/命令/状态传送。
后两个子规范则定义了储备介质的操作命令。
ATA命令规范用于硬盘,UFI命令规范是针对USB移动储备。
MicrosoftWindows中提供对MassStorage协议的支持,因此USB移动设备只需要遵循MassStorage协议来组织数据和处理命令,即可实现与PC机交换数据。
而Flash的储备单元组织形式采纳FAT16文件系统,如此,就能够直截了当在Windows的扫瞄器中通过可移动磁盘来交换数据了,Windows负责对FAT16文件系统的治理,USB设备不需要干预FAT16文件系统操作的具体细节。
USB(Host)唯独通过描述符了解设备的有关信息,按照这些信息,建立起通信,在这些描述符中,规定了设备所使用的协议、端点情形等。
因此,正确地提供描述符,是USB设备正常工作的先决条件。
Linux-2.6.26内核中在利用USBgadget驱动实现模拟U盘时要紧涉及到file_storage.c、s3c2410_udc.c等驱动文件(这些文件的具体结构,将在下一篇文章中描述)。
现在我们想先从这些代码中找到USB描述描述符,从中确定使用的储备类规范,从而确定协议。
确定通讯协议是我们调试的基础。
储备类规范是由接口描述符决定的。
接口描述符各项的定义义如下:
其中,bInterfaceClass、bInterfaceSubClass、bInterfaceProtocol能够判定出设备是否是储备类,以及属于哪种储备子类和储备介质的操作命令。
在file_storage.c文件中,
/*USBprotocolvalue=thetransportmethod*/
#defineUSB_PR_CBI0x00//Control/Bulk/Interrupt
#defineUSB_PR_CB0x01//Control/Bulkw/ointerrupt
#defineUSB_PR_BULK0x50//Bulk-only
/*USBsubclassvalue=theprotocolencapsulation*/
#defineUSB_SC_RBC0x01//ReducedBlockCommands(flash)
#defineUSB_SC_80200x02//SFF-8020i,MMC-2,ATAPI(CD-ROM)
#defineUSB_SC_QIC0x03//QIC-157(tape)
#defineUSB_SC_UFI0x04//UFI(floppy)
#defineUSB_SC_80700x05//SFF-8070i(removable)
#defineUSB_SC_SCSI0x06//TransparentSCSI
默认的情形是:
mod_data={//Defaultvalues
.transport_parm="BBB",
.protocol_parm="SCSI",
……
默认的赋值如下:
bInterfaceClass=08表示:
储备类
bInterfaceSubClass=0x06表示:
透亮的SCSI指令
bInterfaceProtocol=0x50表示:
bulk-only传输
2、Bulk-Only传输协议
下面看看Bulk-Only传输协议:
(详细的规范请阅读《UniversalSerialBusMassStorageClassBulk-OnlyTransport》)
设备插入到USB后,USB即对设备进行搜索,并要求设备提供相应的描述符。
在USBHost得到上述描述符后,即完成了设备的配置,识不出为Bulk-Only的MassStorage设备,然后即进入Bulk-Only传输方式。
在此方式下,USB与设备间的所有数据均通过Bulk-In和Bulk-Out来进行传输,不再通过操纵端点传输任何数据。
在这种传输方式下,有三种类型的数据在USB和设备之间传送,CBW、CSW和一般数据。
CBW(CommandBlockWrapper,即命令块包)是从USBHost发送到设备的命令,命令格式遵从接口中的bInterfaceSubClass所指定的命令块,那个地点为SCSI传输命令集。
USB设备需要将SCSI命令从CBW中提取出来,执行相应的命令,完成以后,向Host发出反映当前命令执行状态的CSW(CommandStatusWrapper),Host按照CSW来决定是否连续发送下一个CBW或是数据。
Host要求USB设备执行的命令可能为发送数据,则现在需要将特定数据传送出去,完毕后发出CSW,以使Host进行下一步的操作。
USB设备所执行的操作可用下图描述:
CBW的格式如下:
dCBWSignature:
CBW的标识,固定值:
43425355h(littleendian)。
dCBWTag:
主机发送的一个命令块标识,设备需要原样作为dCSWTag(CSW中的一部分)再发送给Host;要紧用于关联CSW到对应的CBW。
dCBWDataTransferLength:
此次CBW命令要求在命令与回应之间传输的字节数。
如果为0,则不传输数据。
bmCBWFlags:
反映数据传输的方向,0表示来自Host,1表示发至Host;
bCBWLUN:
关于有多个LUN逻辑单元的设备,用来选择具体目标。
如果没有多个LUN,则写0。
bCBWCBLength:
命令的长度,范畴在0~16.
CBWCB:
传输的具体命令,符合bInterfaceSubClass.中定义的命令规范,此处是SCSI
CSW命令格式如下:
dCSWSignature:
CSW的标识,固定值:
53425355h(littleendian)
dCSWTag:
设置那个标识和CBW中的dCBWTag一致,参照上面关于dCBWTag的讲明
dCSWDataResidue:
还需要传送的数据,此数据按照dCBWDataTransferLength-此次差不多传送的数据得到
bCSWStatus:
指示命令的执行状态。
如果命令正确执行,bCSWStatus返回0即可。
3、SCSI指令集
Bulk-Only的CBW中的CBWCB中的内容即为如下格式的命令块描述符(CommandBlockDescriptor)。
SCSI-2有三种字长的命令,6字节、10字节和12字节,MicrosoftWindows环境下支持12字节长的命令。
OperationCode:
操作代码,表示特定的命令。
高3位为GroupCode,共有8种组合,
即8个组,低5五位为CommandCode,能够有32种命令。
LogicolunitNumber:
为了兼容SCSI-1而设的,此处能够不必关怀。
Logicalblockaddress:
为高位在前,低位在后的逻辑块地址,即扇区地址。
第2位为高位,第3、4、5依次为低位。
Transferlength:
为需要从逻辑块地址处开始传输的扇区数(例如在Write命令中)。
Parameterlistlength:
为需要传输的数据长度(例如在ModeSense命令中);
Allocationlength:
为初始程序为返回数据所分配的最大字节数,此值能够为零,表示不需要传送数据。
SCSI指令集的DirectAccesss类型储备介质的传输命令有许多,MassStorage协议只用到了其中的一些。
更多的SCSI指令参见:
http:
//en.wikipedia.org/wiki/SCSI_command
指令代码指令名称讲明
04hFormatUnit格式化储备单元
12hInquiry索取器件信息
1BhStart/Stopload/unload
55hModeselect承诺Host对外部设备设置参数。
5AhModeSense向host传输参数
EhPrevent/AllowMediumRemoval写爱护
>28hRead(10)Host读储备介质中的二进制数据
A8hRead(12)同上,只是比较详细一点
25hReadCapacity要求设备返回当前容量
23hReadFormatCapacity查询当前容量及可用空间
03hRequestSense要求设备向主机返回执行结果,及状态数据
01hRexeroUnit返回零轨道
2BhSeek(10)为设备分配到特定地址
1DhSendDiagnostic执行固件复位并执行诊断
00hTestUnitReady要求设备报告是否处于Ready状态
2FhVerify在储备中验证数据
2AhWrite(10)从主机向介质写二进制数据
AAhWrite(12)同上,只是比较详细
2EhWriteandVerify写二进制数据并验证
关于不同的命令,其命令块描述符略有不同,其要求的返回内容也有所不同,按照相应的文档,能够对每种要求作出适当的回应。
例如,下面是INQUIRY要求的命令块描述符和其返回内容的数据格式:
如:
INQUIRY
命令描述符:
返回数据格式
Host会依次发出INQUIRY、ReadCapacity、UFIModeSense要求,如果上述要求的返回结果都正确,则Host会发出READ命令,读取文件系统0簇0扇区的MBR数据,进入文件系统识不时期。
4、利用USBView观看结果
可通过USBView软件查看到USB设置时期猎取到的信息。
二、显现的要紧咨询题
在调试过程中遇到了一个咨询题。
现象是:
在目标板加载完驱动后,即执行完:
#insmodg_file_storage.kofile=/dev/mtdblock2stall=0removable=1
后,接好USB线。
现在在windows端设备出有usbstorage设备加入,但显现不了盘符。
下面记录下调试过程。
三、调试过程
按照规范,当完成SCSI指令集中Inquiry命令时,能够显现盘符。
因此能够通过bushound软件查看通讯过程,找出缘故。
下面是利用bushound工具在显现咨询题时采集到的数据。
DevPhaseDataInfoTimeCmd.Phase.Ofs
-------------------------------------------------------------------
26CTL80060001-00001200GETDESCRIPTR0us1.1.0
26DI12011001-00000010-2505a5a4-12030102........%.......4.8ms1.2.0
0301..1.2.16
26CTL80060002-00000900GETDESCRIPTR14us2.1.0
26DI09022000-010104c0-01........3.9ms2.2.0
26CTL80060002-00002000GETDESCRIPTR16us3.1.0
26DI09022000-010104c0-01090400-00020806...............4.9ms3.2.0
50050705-81024000-00070502-02400000P.....@......@..3.2.16
26CTL800600