感谢支持
我们一直在努力

详细解析Windows usb驱动和Linux usb驱动的相似和差异

0 前言


很早以前就想写点东西来总结windows 下usb开发和linux 下usb 驱动开发的异同了,今天主要从相同点和不同点进行讲解吧,对于两个平台下usb驱动开发,usb协议是相同的,咱们先从usb协议开始谈起,然后讲解windows下usb驱动开发的方法,主要介绍3种方法,dw 3.2+DDK;WDM下DDK开发和WDF下KMDF Usb驱动开发。


虽然dw已经被WDF赶下台了,但是我这里还是要讲讲dw开发驱动程序的东西,因为我的第一个驱动程序就是采用dw+ddk 2600开发的,至今我都记得当时开发驱动的情景,那种感觉真的希望神仙来指路啊。在开发第一个usb驱动程序之前我没有做过驱动的经验,甚至都不知道,驱动是干嘛的。但是临危受命,只有往前冲,没有回头路,因为回头就意味着枪毙(被辞职,08年的流行语,被)。没有回头路,那就往前走呗。


没有文档,没有原理图,甚至连数据手册都没有给我,就跟我讲了讲这个项目要做什么工作。当时一片茫然,真希望神仙来指路。拿到项目需求,其实是口头上的,呵呵,没有 一行字的文档。没有办法,一边学习,一边做需求分析,请教做过这些事情的同事和同学。到csdn和国外的论坛发帖狂问。一边搜开发驱动的工具,比如ddk,dw等等,那个时候国内还没有人用WDF模型做驱动开发。


那时的水平真的就是一个字来形容,菜。搜了一大通,感觉还是用dw 吧,感觉还是挺比较容易用,选用了开发工具后,就不分昼夜的学习。有时工作到凌晨2点,雷锋同志说的好,时间就像乳沟,要挤还是有的,呵呵,中午也不休息了,干活,干活,干活。一个星期过去了没有一点进展,2个星期过去了,终于把需求搞明白了,这个时候,对dw+ddk+vc的开发环境也搭起来了,也买了几本书,每一本书都讲到关键的地方没了,呵呵,真气人啊。


神阿,救救我吧!老大每天都过来问一下,有什么进展了吗?唉,我每次都对着他笑笑,还好,老大还对我不错,要我好好的静下心来,理一理思路。当时他也帮我找找资料,但是后面证明都是没用的,呵呵,因为公司没有人做过usb驱动。


3个星期过去了,柳岸花明又一村,我终于可以往硬件发送控制命令了,但是硬件还没有给我回送数据。没办法,用bus hound 一抓包,看到有数据了,我兴奋了一吧。呵呵,终于看到了希望,看到了未来,那时候感谢党,感谢毛主席,心情澎湃了一个小时。


实验证明,希望越大,失望越大,我以为就要做出来了,但是没想到还是万里长征走完第一步,后面的路还很长,我们必须保留……。我后面就去写函数去读端点中的数据,但是一直都读不到,呵呵,调啊 调啊。希望会有的,面包会有的,我一直坚信自己,从来不怀疑自己的能力。


第4个星期的早上,我早早的就去上班了,还是坐在那里,安安静静的写代码,调程序,也不和别人说话,不断地看别人的代码,看dw上的例子,看ddk的例子。当时一个星期比我一个月看的东西还要多,总结一句话,静下心来看源码,源码就会像看故事会那样简单。第4个星期的星期3了。也是上午快吃中饭的时候,终于看到硬件不断的给我传数据了,我还是用bus hound抓包,数据是那么的正确,当时的心情是怎样的激动,我无法形容,现在都过去几年了,都清楚地记得,我当时吼了一声,公司的人都看着我,现在回想起来是那么的幼稚。一个驱动程序,一段不寻常的经历,让我想起一句话:没有压力,没有动力,不经历风雨怎能见彩虹。


以上就是我第一次做usb驱动的一段经历,那时流行采用dw+ddk开发驱动程序,现在开发dw软件的公司都停止开发了,多么可惜的一件事情啊,这么优秀的软件,这么易用的软件,就这样被淘汰了,最终将它的版本定格在3.2。但是国内现在还有一大拨人在使用dw开发驱动程序,我看网上有本书,叫圈圈教你玩usb,就是采用dw开发驱动的,粉丝还挺多的,证明dw还有一定的生命力,还有一定的市场,所以本文还是会讲到怎样采用dw做驱动开发。


虽然现在正规的商用软件都不采用dw了,因为它的版本不更新,出了bug都没有人维护了。但是用dw做研究还是挺不错的。开场白说完了。开始进入正题,本文的主要安排如下:首先介绍usb通信协议,同时介绍一款最简单的usb芯片,68013。然后接着讲解windows下的usb驱动开发。采用3种不同的方法开发usb驱动程序,最后讲解linux下usb驱动开发,当然两个平台开发usb驱动的异同点是贯穿全文的,不然就跑题了。


作为驱动开发人员,不需要你有多高的算法基础,因为驱动里面的算法都是基本的算法,只要你熟悉原理图,熟悉datesheet,然后学习DDK,WDK下自带的例子,就可以轻松上手,对于linux,同样也是这样,还有linux的源码是公开的,你可以编译,安装,就可以在/usr/src看到各种驱动的源码了,学习这些源码,不但可以提高我们的编程水平,而且使得我们写的驱动更有健壮性。下面我讲解的思路也是这样的,先将usb协议,在讲讲cy7c68013芯片,然后讲解dw,ddk,wdk下的例子,只要将这些例子都学会,可以说,你具有写驱动的水平了,至于要成为高手,就必须多总结经验,多积累经验。

1 Usb通信协议


Usb驱动程序是PC中最主要的设备驱动程序,usb总线协议比PCI总线协议复杂,但是对于我们usb驱动开发者来说,并需要对usb通信协议每个东东都搞清楚,比如usb物理层协议,usb传输层协议等等,只要了解即可。


1.1)usb总线协议


USB最多支持127个外设,但是考虑到Hub的情况,连接的外设没有这么多,因为Hub也当成了外设,对于每个PC都有一个或多个Host控制器设备,该Host控制器和一个根Hub作为一个整体,跟Hub下可以连接多个Hub,这样形成级连设置,Host分别有2种驱动,一种是1.0,另一种是2.0,分别对应着USB协议1.0和USB协议2.0。虽然存在Hub,但是对于用户来说,这些都是透明的,就好象USB设备和直接连接到USB Host控制器上一样。当USB设备插入和删除都会发电信号给系统,这样可以枚举USB设备。


USB 的连接模式是Host和Devcie的连接模式,所有的请求必须是Host向Device发出,这就使Host端设计相对复杂,而Device端设计相对简单。在USB的通信中,可以看成是一个分层的协议。分为三个层次,即最底层USB总线接口层、USB设备层、功能通信层,如图1-1所示。



图1 usb逻辑和控制图


对于每个USB设备,都有一个或者多个的接口(Interface),每个Interface都有多个端点(Endpoints),每个端点通过管道(Pipes)和USB Host控制器连接。每个USB设备都会有一个特殊的端点,即Endpoint0,它负责传输设备的描述信息,同时也负责传输PC与设备之间的控制信息,如图1-2所示:



图1-2 USB 管道与端点


现在讲讲usb传输吧,Usb传输一般分为3个部分:令牌传输,数据传输,握手阶段,传输的方式有4种:控制传输,这个是传输控制信息,Bulk传输,这个是批处理传输,中断传输,同步传输。


对于控制传输来说,一般采用端点0进行控制传输,主要用来配置设备、获取设备信息、发送命令或者获取设备的状态报告。总线驱动程序为它保留了10%的带宽,使得控制传输能在1ms内完成。


对于控制端点:


端点所传的数据净负荷的长度必须小于或等于其wMaxPacketSize,当传输的数据大于wMaxPacketSize时,必须分多次进行传送。除最后一次传输外,其它都应达到最大长度。最后一次传输含最后剩下的数据。控制传送的数据阶段结束的标志如下:


·已传了由Setup阶段指定的数据量。


·传了一个数据包,它的长度为0或它的数据区长度小于最大长度。


中断传输:主要用来以一个固定的速度传送少量的数据,对于中断传输,系统会预留带宽。


Bulk传输:用来传送大量的数据,数据传送是可靠的,当总线上的空间不足以发送整个批量包时,会划分成多个包传送。缺点:是当有多个usb设备时,bulk传输,由于系统没有给他预留usb带宽,有可能被其它以中断或同步传输的usb设备抢占带宽,造成bulk传输的设备不能正常使用。


Bulk传输也像控制传输一样,端点所传的数据净负荷的长度必须小于或等于其wMaxPacketSize,当传输的数据大于wMaxPacketSize时,必须分多次进行传送。除最后一次传输外,其它都应达到最大长度。最后一次传输含最后剩下的数据。控制传送的数据阶段结束的标志如下:


·已传了由bulk传输指定的数据量。


·传了一个数据包,它的长度为0或它的数据区长度小于最大长度。


这里要注意了,硬件设计的时候,主要必须能给PC端传送short包,什么意思呢,因为usb bulk传输结束的条件有2个,当数据没有全部传送成功时,我们可以根据short包或zero包来判断这次传输的结束。


同步传输:也叫等时传输,用来传送大量不可靠传输,不保证数据的到达,但能保证恒定的数据流,一般用于摄像机等视频设备的数据采集。


Usb协议中除了上面的讲解的内容,还有usb描述符,usb描述符包括,usb设备描述符,usb配置描述符,usb接口描述符和usb端点描述符。Usb设备描述符长度为18个字节,主要用来枚举设备使用,其中重要的字节是PID/VID,因为它可以用来枚举设备。还有一个字节不得不将,也是面试时,考官容易考试的,SerialNumber字段,各位看官看好了,估计你不知道这个字节的作用了吧。你做usb驱动有过在一个usb口安装usb驱动后,到另外一个口还提示你安装驱动的经验吗,呵呵,这就是SerialNumber了,如何设置,就不说了。各位看官自己研究吧。


Usb配置描述符和usb接口描述符都不重点讲解了,它们的长度都是9个字节,下面在讲讲usb端点描述符,usb端点描符的长度为7个字节,其中重要的字段为端点地址,如果是0x82表示端点是一个端点号为2的IN端点,而0x02表示一个端点号为2的OUT端点。还有bmAttributes的低2位表示端点的类型,如0表示控制端点,而1表示同步端点,2表示bulk端点,3表示中断端点。还有一个就是wMaxpacketsize,不用我说,大家看到这个知道它表示什么意思了,对了,就是表示该端点最大的传输size,如果总的传输大小比这个大,就必须分割成多个块进行传输,每个块的size为wMaxpacketsize,最后剩余的数据放在最后一个块里面输出。剩下的就是bInterval字节的,它只对同步和中断端点有效,对于中断端点,该值得范围为1-255ms,代表2次巡检间的最大时间间隔。对于同步端点,固定为1,表示每隔一个帧周期(1ms)都应该巡检。

1.2)68013 芯片资料


Cypress 68013的芯片数据手册在这里不一一列出了,具体的资料大家给到它的官网上下载,下面是56脚CY7C68013A接口图:



l     单片集成USB2.0收发器、SIE和增强型8051微处理器。


l     软件:从内部RAM运行的8051程序来自于:


——通过USB接口下载,或


——从EEPROM下载


——外部储存器设备(仅对128脚配置)


l     4个可编程的批量/中断/同步端点


——缓冲器可选:双倍、三倍和四倍。


l     8位或16位外部数据接口。


l     GPIF


——允许直接连接到大部分并行接口;8位或16位。


——通过可编程的波形描述器和配置寄存器来定义波形。


——支持多就绪(RDY)和控制(CTL)输出。


——高达48 MHz的时钟速率。


——每指令周期4个时钟。


——两个UARTS。


——三个定时器/计数器。


——扩展的中断系统。


——两个数据指针。


l     通过枚举支持总线供电应用。


l     3.3V操作电压。


l     灵巧的串行接口引擎。


l     USB中断向量。


l     对控制传输的设置(SETUP)和数据(DATA)部分使用独立的数据缓冲器。


l     集成的I2C兼容控制器,运行速率100或400 kHz。


l     8051的时钟频率为48MHz, 24MHz, 或12MHz。


l     4个集成的FIFO。


——以更低的系统开销组合FIFO。


——自动转换到/自16位总线。


——支持主或从操作。


——FIFO可以使用外部提供的时钟或异步选通。


——容易与ASIC和DSP芯片接口。


l     对FIFO和GPIF接口的特殊自动中断向量。


l     多达40个通用I/O接口。


l     四种封装可选—128脚TQFP, 100脚TQFP, 56脚QFN和56脚SSOP。

 

2 驱动基础知识


   68013带有自己的驱动的程序的,但是在这里为了讲解usb驱动程序的开发方法,我们还是自己的驱动程序吧,我自己的驱动程序比它自带的驱动程序效果更好,呵呵,传输速度更快,网上有网友说,Ezusb 驱动程序的缺点一大堆,下面讨论驱动程序的编写方法,在本文中,widows环境下我主要想讲解不同的工具的开发方法和技巧。


 


2.1 windows 驱动开发基础


    windowsPc开发驱动的方法主要有,windriverdriverstudio 3.2+ddkddkWDK4种,windriver开发驱动最简单,但它开发的驱动不符合微软的wdm模型的思想,在本文中,不对windriver进行讲解,主要讲解driverstudio 3.2(dw 3.2)+ddk,及ddk,和wdk进行驱动开发。


       Driverstudio 简单来说,就像apiMFC,它是对ddk的进一步的封装,采用driverstudiodriverworks能够很方便的生成程序框架。而且生成的程序满足wdm模型,因此它以它的易用性影响了一代人。下面首先讲解采用vc6.0+driverstudio 3.2 +ddk搭建驱动开发环境。


1.装系统XP->安装VC 6.0—>安装DDK->driver studio 3.2


2.如果安装的是DDK2600,则需要安装补丁,ntstrsafecsq,到网上下载文件ntstrsafe.lib+csq.lib.rar,把解压出来的两个库文件拷贝到WinXP_DDK的安装目录下的库目录中(我的是E:\WINDDK\2600\lib\wxp\i386)。


3.对driver studio,VC6.0ddk进行简单的设置;


  1)在VC6.0 菜单的DriverStudio菜单下的DDK Build Settings,在弹出的对话框中选择已经安装的DDK目录(我的是E:\WINDDK\2600);


   (2) VC6.0–>Tools–>Options,点击“Directories”选项卡:)“Show directories for:”下选择Include files,然后检查有没有包含ddk的头文件目录(我的是E:\WINDDK\2600\inc\wxp),如果没有则加上;Show directories for:”下选择Library files,然后检查有没有包含ddk的库文件目录(我的是E:\WINDDK\2600\lib\wxp\i386),如果没有则加上;


   (3)启动driverstudio,在develop下的DDK Building Settings中确保“DDK Root Directory”下方的内容是ddk的安装目录(我的是E:\WINDDK\2600),然后点击下方的“Luanch Program”正式启动vc6的开发环境。


   (4) VC6.0进入菜单File–>Open Workspace(打开位于DriverStudio3.2安装目录的\DriverWorks\Source\vdwlibs.dsw)–>进入菜单Build–>batch Build,点击“Select x86″按钮只选中全部的32位库(对于32位的电脑一定不要选中64位的库,否则后面编译会出错)–>点击按钮“Rebuild AlL”开始编译。


(5)编译一个DriverStudio自带的实例,启动VC6.0,点击菜单File–>Open Workspace,打开项目文件:


C:\Program Files\Compuware\DriverStudio\DriverWorks\Examples\wdm\


hellowdm\HelloWdm.dsw,然后编译,如果没有报错,那说明安装和配置成功。


  (6)应用driverstudioDriver wizard生成驱动程序框架:此后系统会一步一步引导你完成设置,最后自动生产的驱动程序框架。设置好后将生成驱动文件,然后用VC6.0进行编译:进行Build菜单,Rebuild AlL将生成.sys文件,说明驱动模块编译成功!


 


    讲解完dw3.2的环境搭建后,接着谈谈wdm的驱动到底有哪些内容,本文主要讲解的驱动都是功能驱动,过滤驱动本文不在进行讲解。无论是dw3.2还是ddkwdk开发驱动都包括以下内容:


1. pnp   2.电源管理,3.内存管理等。


    对于dw3.2+ddk或单独采用ddk开发驱动来说,还有派遣函数等内容,而对于wdk来说,就没有派遣函数了,都用队列来处理。


    本文主要针对usb驱动进行讲解,在dw3.2中,与usb驱动相关的几个类如下:


        1.KUsbLowerDevice :主要用于逻辑设备的编程;


     2.KusbInterface:主要用于接口设备的编程;


     3.KusbPipe:主要用于管道的编程;


 


       对于dw3.2+ddk怎么开发usb驱动程序,首先采用driverworksDriverWizard生成usb驱动框架,生成的流程在这里不进行讲解了,网上有10分钟开发一个usb驱动程序等资料。


      


对于DDKWDK的最大的不同是DDK采用wdm模型,而WDK采用的是WDF模型,WDM中的IrpWDFWDFREQUEST对象表示,WDFREQUEST是对Irp的封装,而wdm中的i/o对象在wdk中不再是一个设备对象,wdki/o target表示,i/o target 对象比设备对象(device_object)表示的范围更大,可以表示驱动,和队列对象等。


其次DDKWDK的不同就是在ddk中,用队列用的比较少,而在wdk中无处不见队列,而wdm的对象都是杂乱的并行队列,而wdf中队列分成了3种,串行队列,并行队列,手动队列。


DDKWDK的另外一个不同就是电源管理和Pnp了,WDK几乎不要用户在写电源管理和Pnp代码了。


呵呵,总结一句,WDKDDK的代码更加简洁,少了很多代码。这些不同,我会在后面的举例中,都可以看到。其中ddkusb讲解,我就采用ddk下面的例子,bulkusb进行讲解,而对于wdk usb讲解,我采用的是wdk下的例子,usbsamp


Window驱动的开发基础先介绍到这里了,对于最基本的DriverEntryAdddevice等,我还会在后面的例子中进行讲解。另外WDF又分成2种,第一种是KMDF,第二种是UMDFKMDF是内核的驱动,UMDF是用户层的驱动。


 


2.2 应用程序与驱动之间的通信


当应用程序通过USB管道发送或接收数据时,它首先调用Win32 API(ReadFileCreateFileWriteFileDeviceIoControl)调用使得功能驱动程序收到一个IRP。而驱动程序的工作是把客户的请求(应用软件)引导到正确端点的管道上。它把请求提交到总线驱动程序,总线驱动程序再把请求分解成多个事物(transaction),然后这些事务被送到总线。


应用程序可以调用ReadFileCreateFileWriteFileDeviceIoControlAPI通过IRP来和驱动程序进行通信。Windows中,应用程序实现与WDM通信的过程是:应用程序先用CreateFile函数打开设备,然后用DeviceIoControlWDM通信,包括从WDM中读数据和写数据给WDM。也可以使用ReadFileWDM中读数据或用WriteFile写数据给WDM,当应用程序退出时,用CloseHandle关闭设备。对应的IRP如下所示:


 


1 Win32 API 对应的IRP



























Win32函数


IRP主功能代码(IRP_MJ_xxx)


KDevice类成员函数


CreateFile


CREATE


Create


ReadFile


READ


Read


WriteFile


WRITE


Write


DeviceIoControl


DEVICE_CONTROL


DeviceControl


CloseHandle


CLOSE CLENUP


Close CleanUp


 


23 驱动程序与底层硬件之间的通信


驱动程序(FDO)和硬件之间的通信主要是在功能驱动层,首先构造USB请求包,然后将USB请求包发送到底层驱动总线上,具体的流程如下:


(1)     当设备插入到PC时,驱动程序调用DriverEntry()例程,主要用于负责驱动程序的初始化,用于初始化驱动程序范围的数据结构和资源。DriverEntry()例程包括主要有以下3个功能。设置AddDeviceUnloadDispath和其它例程的入口指针;


(2)PC给硬件发送控制命令,即厂商请求。


对于dw3.2来说,发送厂商请求的函数为:BuildVendorRequest,然后构建URB将厂商请求发给硬件;发送Urb的命令为:SubmitUrb函数;


对于ddk来说,发送厂商请求的函数如下:


IoBuildDeviceIoControlRequest,它创建一个I/O控制码的Irp,然后将URB作为Irp的参数,用IoCallDriver发送到底层总线驱动,然后转发到硬件,对硬件设备进行控制;


对于wdk,发送厂商请求分为同步和异步2种方式:


 


(3)对设备进行读写;


dw3.2对设备进行读的函数如下:


要对usb设备进行进行读(read),首先必须发送控制请求,然后在将该请求以urb发给底层usb总线,然后获取硬件返回的数据。


发送请求有以下几种方式:


1)      对于KUsbLowerDevice类来说,发送厂商请求,函数如下:BuildVendorRequest


PURB BuildVendorRequest(


   PUCHAR TransferBuffer,               //为驱动程序存放传输数据的内存


   ULONG TransferBufferLength,   //传输的字节数


   UCHAR RequestTypeReservedBits,  //为类别请求字节的保留位


   UCHAR Request,                          //具体的请求数值


   USHORT Value,                            //为数值


   BOOLEAN bIn=FALSE,                //False表示主机到设备


   BOOLEAN bShortOk=FALSE,       //传输字节数是否可以少于指定的字节数


   PURB Link=NULL                        //指为连接下一个传输的URB


   UCHAR Index=0,                          //为索引值


   USHORT Function=URB_FUNCTION_VENDOR_DEVICE,  //类别请求


   PURB pUrb=NULL                     //NULL表示分配一个新的URB


);


 


然后将URB发送给底层USB总线,提交的函数原型如下:


NTSTATUS SubmitUrb(
   PURB pUrb,
              //创建的URB

   PIO_COMPLETION_ROUTINE CompletionRoutine=NULL,
 //完成例程
   PVOID CompletionContext=NULL,
           //传替给完成例程的参数
   ULONG mSecTimeOut=0
                        //同步调用的超时参数
);


 


dw 3.2下有个usbtherm的例子,里面读取数据的函数,如下:


NTSTATUS UsbThermometer::ReadRamAsynch( UCHAR offset, PIO_COMPLETION_ROUTINE pCompRoutine)


{


     t << “Entering UsbThermometer::ReadRamAsynch\n”;


 


     KIrp I = KIrp::Allocate( m_Usb.StackRequirement() );


     if ( I.IsNull() )


         return STATUS_INSUFFICIENT_RESOURCES;


     // allocate a new context structure


     THERMO_READ_COMPLETION_INFO* pCompInfo = new (NonPagedPool) THERMO_READ_COMPLETION_INFO;


     // make sure it succeeded


     if ( pCompInfo == NULL )


     {


         KIrp::Deallocate(I);


         return STATUS_INSUFFICIENT_RESOURCES;


     }


     RtlZeroMemory(pCompInfo,sizeof(THERMO_READ_COMPLETION_INFO));


     // initialize the context structure


     pCompInfo->m_pClass = this;


     pCompInfo->m_OffsetRead = offset;


     // allocate and initialize an URB, and store the pointer in the context structure


     pCompInfo->m_pUrb =


              m_Usb.BuildVendorRequest(


                   pCompInfo->m_buffer,             // transfer buffer


                   8,                                   // transfer buffer size


                   0,                                   // request reserved bits


                  2,                                   // request


                   offset,                              // Value


                   TRUE,                                // In


                   FALSE,                               // Short Ok


                   NULL,                                // link urb


                   0,                                   // index


                   URB_FUNCTION_VENDOR_ENDPOINT     // function


                   );


     if ( pCompInfo->m_pUrb == NULL )


     {


         delete pCompInfo;


         KIrp::Deallocate(I);


         return STATUS_INSUFFICIENT_RESOURCES;


     }


     // submit the URB to USBD


     return m_Usb.SubmitUrb(I, pCompInfo->m_pUrb, pCompRoutine, pCompInfo);


}


 


 


对于KusbPipe类来说,构建urb又多了几个函数,其实都差不多,BuildControlTransferBuildInterruptTransferBuildBulkTransferBuildIsochronousTransfer,分别对应的控制传输,中断传输,块传输,同步传输。这些都在usb驱动开发的dw 3.2驱动开发中以例子的形式进行讲解,同时对于usb写,其实是一样的,都是这些函数,只是传输方向变了,改变一个参数就行。


 


ddk对设备进行读时的函数如下:UsbBuildInterruptOrBulkTransferRequest,然后调用IoCallDriverURB请求转发给底层总线驱动,在转发给硬件设备。


 


wdk对设备进行读时的函数如下(分为同步和异步2种方式)


 


1)对于usb设备:


同步控制命令(控制传输):


WdfUsbTargetDeviceSendControlTransferSynchronously


函数功能:builds a USB control transfer request and sends it synchronously to an I/O target.


NTSTATUS WdfUsbTargetDeviceSendControlTransferSynchronously(


  [in]           WDFUSBDEVICE UsbDevice,


  [in, optional]   WDFREQUEST Request,


  [in, optional]   PWDF_REQUEST_SEND_OPTIONS RequestOptions,


  [in]           PWDF_USB_CONTROL_SETUP_PACKET SetupPacket,


  [in, optional]   PWDF_MEMORY_DESCRIPTOR MemoryDescriptor,


  [out, optional]  PULONG BytesTransferred


);


 


 


举例如下:


 


WDF_USB_CONTROL_SETUP_PACKET  controlSetupPacket;


WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(


                                         &controlSetupPacket,


                                         BmRequestHostToDevice,


                                         BmRequestToDevice,


                                         USBFX2LK_REENUMERATE,


                                         0,


                                         0


                                         );


 


status = WdfUsbTargetDeviceSendControlTransferSynchronously(


                                         UsbDevice,


                                         WDF_NO_HANDLE,


                                         NULL,


                                         &controlSetupPacket,


                                         NULL,


                                         NULL


                                         );


 


异步操作(控制传输):


WdfUsbTargetDeviceFormatRequestForControlTransfer


NTSTATUS
  
  WdfUsbTargetDeviceFormatRequestForControlTransfer(
    IN WDFUSBDEVICE  UsbDevice,
    IN WDFREQUEST  Request,
    IN PWDF_USB_CONTROL_SETUP_PACKET  SetupPacket,
    IN OPTIONAL WDFMEMORY  TransferMemory,
    IN OPTIONAL PWDFMEMORY_OFFSET  TransferOffset
    );


该函数和同步控制传输函数的区别是只构建控制传输请求,但是不发送控制传输请求,而同步操作WdfUsbTargetDeviceSendControlTransferSynchronously构建完控制传输请求的同时,也发送给I/O target


 


2)对于usb管道:


同步写:


WdfUsbTargetPipeWriteSynchronously函数,函数原型如下:


The WdfUsbTargetPipeWriteSynchronously method builds a write request and sends it synchronously to a specified USB output pipe.


NTSTATUS
  WdfUsbTargetPipeWriteSynchronously(
    IN WDFUSBPIPE  Pipe,
    IN OPTIONAL WDFREQUEST  Request,
    IN OPTIONAL PWDF_REQUEST_SEND_OPTIONS  RequestOptions,
    IN OPTIONAL PWDF_MEMORY_DESCRIPTOR  MemoryDescriptor,
    OUT OPTIONAL PULONG  BytesWritten
    );


异步写:


usb 写数据发送请求的函数为WdfUsbTargetPipeFormatRequestForWrite,然后将WdfRequestSend将请求发送出去。


NTSTATUS WdfUsbTargetPipeFormatRequestForWrite(
    IN WDFUSBPIPE  Pipe,
    IN WDFREQUEST  Request,
    IN OPTIONAL WDFMEMORY  WriteMemory,
    IN OPTIONAL PWDFMEMORY_OFFSET  WriteOffset
    );


 


该函数和同步写函数WdfUsbTargetPipeWriteSynchronously的区别是异步写函数需要调用WdfRequestSend发送请求。WdfRequestSend函数原型如下:


BOOLEAN
  WdfRequestSend(
    IN WDFREQUEST  Request,
    IN WDFIOTARGET  Target,
    IN OPTIONAL PWDF_REQUEST_SEND_OPTIONS  RequestOptions
    );


 


同步读:


WdfUsbTargetPipeReadSynchronously函数,函数原型如下:


NTSTATUS WdfUsbTargetPipeReadSynchronously(
    IN WDFUSBPIPE  Pipe,
    IN OPTIONAL WDFREQUEST  Request,
    IN OPTIONAL PWDF_REQUEST_SEND_OPTIONS  RequestOptions,
    IN OPTIONAL PWDF_MEMORY_DESCRIPTOR  MemoryDescriptor,
    OUT OPTIONAL PULONG  BytesRead
    );


 


异步读:


WdfUsbTargetPipeFormatRequestForRead函数原型如下:


NTSTATUS
  WdfUsbTargetPipeFormatRequestForRead(
    IN WDFUSBPIPE  Pipe,
    IN WDFREQUEST  Request,
    IN OPTIONAL WDFMEMORY  ReadMemory,
    IN OPTIONAL PWDFMEMORY_OFFSET  ReadOffset
    );


 


同步读和异步读的差别和同步写与异步写的区别类似。

待续。。。。。。

赞(0) 打赏
转载请注明出处:服务器评测 » 详细解析Windows usb驱动和Linux usb驱动的相似和差异
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏