驱动程序原理介绍
USB大储存设备(MassStorage)是以文件为单位进行储存的从设备(Gadget)。在主设备主机(任何操作系统)上它以U盘的方式出现,在有Linux操作系统的从设备主机上linux设备驱动程序pdf,它以Gadget驱动程序方式出现,实现从设备与主设备的通讯。
GadgetMassStorage是USB设备的一个典型的Gadget驱动程序使用事例,它说明了能适应不断减小的吞吐量的双缓存区技术,给出了一个在USB主设备主机上侦测大储存设备驱动程序的典型方式。
大储存设备的储存通过常规文件或块设备来实现,它通过模块选项"file"选择大储存设备文件。通过模块选项"ro"限制访问权限。假如可选的模块选项"removable",指示它是否是一个可移去的介质。
GadgetMassStorage设备支持控制-批量(CBControl-Bulk),控制-批量-中断(CBIControl-Bulk-Interrupt)和仅批量(Bulk-Only)传输,通过可选的"transport"模块选项来选择。它还支持下边的合同:RBC(0x01),ATAPI或SFF-8020i(0x02),QIC-157(0c03),通过可选的"protocol"模块选项来选择。
大储存设备可以有多个逻辑单元(LUN),每位LUN有自己的文件,LUN的数目由可选的模块选项"luns"(1到8)选择,相应的文件用冒号分开的"file"或"or"的列表定义。缺省的LUN个数从"file"元素的个数获取,假如"file"没有被提供,则为1。假如"removable"没有被设置,这么,每位LUN必须指定文件。假如"removable"被设置,一个没定义或空的文件名意味着LUN的介质没有装载。大储存设备的模块选项选项说明如表3所示。
表3大储存设备的模块选项选项说明
模块选项
说明
file=filename[,filename...]
假如"removable"没被设置,用于储存的文件或块设备名是须要的。
ro=b[,b...]
缺省是false,仅读访问的逻辑值。
removable
缺省是false,可移去媒体的逻辑值。
luns=N
缺省值N=文件名的个数是支持的LUN的个数。
transport=XXX
缺省值是BBB(Bulk-Only),传输名(CB,CBI,orBBB)。
protocol=YYY
缺省值是SCSI,合同名(RBC,8020或ATAPI,QIC,UFI,8070,或SCSI,也有可能1-6项都支持)。
vendor=0xVVVV
缺省值是0x0525(NetChip),USB供应商ID。
product=0xPPPP
缺省值是0xa4a5(FSG),USB产品ID。
release=0xRRRR
USB发布号(bcdDevice)。
buflen=N
缺省值N=16384,使用的buffer大小(是页大小的整数倍)。
stall
根据USB设备控制器的类型来决定缺省值(一般是true),是否准许驱动程序停止bulk端点的逻辑值。
对于Gadget设备来说,最少的要求是:仅一个bulk-in和一个bulk-out端点是必须的(一个interrupt-out对于CBI来说也是必须的)。显存的最小要求是两个16k的buffer,可通过参数可配置buffer的大小。
假如编译时未设置CONFIG_USB_FILE_STORAGE_TEST选项,则仅"file","ro","removable",和"luns"选项可用,
文件的路径名和ro设置在sysfs文件系统中的gadget/lun子目录下的"ro"和"file"文件属性里。假如"removable"选项被设置什么是linux,对那些文件的写将模拟弹出/装上媒体(写一个空行意味着弹出)操作。当媒体被装载时,"ro"的设置不容许改变。
本Gadget驱动程序基于GadgetZero,SCSI(SmallComputerSystemInterface)命令插口基于SCSIII插口规范,某些例外(如:操作码0x23,即READFORMATCAPACITIES)基于USB大储存类UFI命令规范(UniversalSerialBusMassStorageClassUFICommandSpecification)。
FSG(FileStorageGadget)驱动程序设计是很直接的:它用一个主线程处理大多数工作。
中断处理类库域从控制器驱动程序反弹:块(bulk)恳求和中断(interrupt)恳求完成通知(completionnotification)风波、ep0风波以及断掉联接风波。通过调用唤起函数wakeup,完成风波completion被传到主线程。
许多ep0恳求在中断期间被处理,但设置插口SetInterface、设置配置SetConfiguration和设备复位恳求通过SIGUSR1讯号以"exception(例外)"的方式转发给线程(由于它们应当中断任何正在进行的文件I/O操作)。
线程的主要工作是实现SCSI交互的标准命令/数据/状态。该线程和它的子类库饱含对挂起sigal/exception(讯号/异常)的测试—所有那些选择(polling)判定是必须的,由于内核没有命令集jmp/longjmp的等价句子。
只要线程活着,它将保持对大储存设备文件的引用。这将制止依赖于文件系统的大储存设备文件的卸载(umount)并可能在例如系统关掉的操作中造成问题。为了制止这种问题,线程捕捉INT,TERM,和KILL讯号并把它们转化成EXIT异常操作。
在线程的正常操作中,线程在Gadget的fsg_bind()反弹期间开始启动,但是在fsg_unbind()期间停止。但它也能在收到一个讯号时退出,但是当线程是死了的时侯,让Gadget运行是没意义。为此,在线程退出前,注销Gadget驱动程序。这样存在两个问题:第一,驱动程序在两个地方注销;第二,正退出的线程应能间接地调用fsg_unbind(),fsg_unbind()应能按顺序告诉线程退出。第一个问题通过使用REGISTERED原子标示来解决,驱动程序将仅注销一次。第二个问题通过使fsg_unbind()检测fsg->state来解决查看linux是什么系统,假如状态已被设置FSG_STATE_TERMINATED,它将不尝试停止线程。
为了提供最大的吞吐量,驱动程序使用了缓冲区头(结构fsg_buffhd)的环型流水线(circularpipeline)。从原理上来说流水线可以任意长,实际中常用两级(如:双缓冲区)。每位缓冲区头装有一个bulk-in和一个bulk-out恳求表针(由于缓冲区可被用作输入和输出,传输方向总是以主机的角度来定义),缓存区头还指向缓冲区和各类状态参数。
流水线的使用遵照一个简单的合同,有一个参数fsg->next_buffhd_to_fill指向下一个使用的缓冲区头。在任何时侯缓冲区头可能还在被一个较早的恳求使用,因而每位缓冲区头有一个状态参数指示它是EMPTY,FULL,或BUSY。典型的使用是等待缓冲区头为EMPTY,文件I/O或USBI/O填充缓冲区(在缓冲区头是BUSY期间),当I/O完成时标示缓冲区头为FULL。接着缓冲将被清空(可能再度通过USBI/O,这期间标示为BUSY),但是最后再度标示为EMPTY(可能通过completion解释器)。
关于ep0恳求的状态级响应有一些细节须要注意。一些例如设备复位的ep0恳求,能中断正在进行的文件I/O操作,这可能在很长的时间中发生。在这个延后期间,主机可能舍弃最初的ep0恳求并发出一个新的。当这发生时,驱动程序不应当通知主机最初的恳求的完成,由于主机将不再等待它。因而驱动程序给每位ep0恳求指定一个惟一的标签linux设备驱动程序pdf,并保持跟踪与一个常年运行的异常相关的恳求的标签值(设备复位、接口变化或配置变化)。当异常处理完成时,仅假如当前ep0恳求标签等于异常恳求的标签值时,状态级反应被递交。这样仅近来接收的ep0恳求将得到一个状态级的响应。
FSG驱动程序代码包括Gadget的细节处理、USBMassStorage处理和SCSI合同的处理。代码在driver/usb/Gadget/file_storage.c中。