开发文档.docx

上传人:b****7 文档编号:11216552 上传时间:2023-02-25 格式:DOCX 页数:77 大小:106.08KB
下载 相关 举报
开发文档.docx_第1页
第1页 / 共77页
开发文档.docx_第2页
第2页 / 共77页
开发文档.docx_第3页
第3页 / 共77页
开发文档.docx_第4页
第4页 / 共77页
开发文档.docx_第5页
第5页 / 共77页
点击查看更多>>
下载资源
资源描述

开发文档.docx

《开发文档.docx》由会员分享,可在线阅读,更多相关《开发文档.docx(77页珍藏版)》请在冰豆网上搜索。

开发文档.docx

开发文档

开发文档.txt世上最珍贵的不是永远得不到或已经得到的,而是你已经得到并且随时都有可能失去的东西!

爱情是灯,友情是影子。

灯灭时,你会发现周围都是影子。

朋友,是在最后可以给你力量的人。

本文由张枕书贡献

pdf文档可能在WAP端浏览体验不佳。

建议您优先选择TXT,或下载源文件到本机查看。

WDFUSB设备驱动开发教程(1.2版)

《WDFUSB设备驱动开发教程》——基于CY001

作者:

张佩,ChinaHearing技术团队版本:

1.1时间:

2010-4-19

文档说明:

作者写作此文档的初衷,是为了配合CY001USB内核驱动开发套件,更好地让使用者入门并熟悉USB驱动开发.但本文档完全可以从开发板中独立出来,因为这里面说讲到的绝大部分内容都是通用的USB技术知识.USB接口越来越流行并已经发展到3.0版本了,他的强势甚至让1394不得不折腰.USB规范以其易用性和廉价性,应用遍及电子产业方方面面.OSR推广的OSRFX2USB开发板,对于美国人自己来说,可能不算贵(70美金),但依我的愚见,乘以汇率后的价格对于中国的程序员来说太贵了.我们因此而推出了CY001USB内核驱动开发套件,板子+代码+文档,堪称完美的组合.

版权声明:

本文档是作者和团队成员,前后10余月时间推敲完成,前后几易其稿.不仅对内容的准确性斟酌再三,亦对文字,修辞方面,力求润色.不敢奢望完美,但其间辛苦心知肚明.文档免费向读者开放,技术爱好者可以通过任何途径传播,复印.但若以此文档进行以盈利为目地的培训,出版,销售等事务,则不被允许,保留追究之权利.

点击进入:

驱网介绍:

CY001介绍讨论帖订购地址:

CY001淘宝店联系作者:

ChinaHearing@

1

WDFUSB设备驱动开发教程(1.2版)

目录

一.WDF简介……4

WDF的特点……4I/O与队列……4兼容性……6PNP和电源实现……6其他……8二.1.USB设备硬件结构……9主从结构……9

2.硬件拓扑……103.USB中断……11三.USB软件结构……12

总线驱动……12系统类驱动……13功能驱动……14父驱动与混合设备……14过滤驱动……16USB驱动栈,设备栈……16四.1.2.内核开发……18设备驱动……18入口函数……18

3.USB描述符……203.1描述符介绍……203.2程序读取描述符……254.初始化……274.1设备初始化函数……274.2创建设备对象……304.3设备命名,符号链接……315.启动设备……355.1

2

接口配置……36

WDFUSB设备驱动开发教程(1.2版)

5.2设备电源能力和策略……385.3辅助操作……436.停止设备/反初始化……456.17.USB设备反配置……45

数据I/O操作……467.17.27.37.4USB控制命令……46构造并发送控制命令……47读USB中断端口……49连续读操作……50

7.5数据处理函数……517.6中断端口的效率……527.78.读写批量端口……53

设备控制……55I/OTarget对象……551.2.3.4.4.14.2获取USB版本……56管道重置……59设备重置(Reset)……60管道中止与终止……61中止操作……61终止操作……62

五,驱动验证-WDFVerifier……63六,1.2.4.用户程序……73内核读写……73控制命令……73注意点……74

3

WDFUSB设备驱动开发教程(1.2版)

一.WDF简介

WDF的特点微软刚开始设计WDF的时候,准备搞一套新的Miniport驱动,如果真是这样的话,那么系统中可能又多了一个WDFMiniport,就好象NDISMiniport一样.但好在不少人提出反对意见:

Miniport驱动越来越多,驱动越来越难写.有人就以NDIS为例,在NDIS中想获取并处理IRP是一件难事,而很多时候,人们又急切地想获取IRP对象,这就成为一件极其痛苦的事情.另外一件痛苦是,某个微端口被推出后,往往只对较新的系统给予支持,而旧系统则不支持.以AVStream微端口驱动为例,就只支持XP及以后的系统,如果要在Win2000上安装AVStream驱动,则非常麻烦.这使得编程人员难以实现驱动程序的多平台支持.综合分析了各种微端口的缺点,大家最后得到了几个共识:

新的驱动框架,应该做到WDM兼容,使得程序员在编程过程中能很方便地在WDF-WDM之间进行切换.新的驱动框架,应该做到向后兼容.也就是说,WDF推出于Vista系统之后,但它必须向后支持WinXP,2000这些旧的操作系统.I/O与队列WDF的一个主要特点是,所有的东西都被封装成一个对象,而所有的操作都被定义成一个事件(Event)或回调(Callback).WDF对每个框架对象都维护一个引用计数,这样就能有效地控制对象的生命周期.举例来说:

WDF的一个优点是将I/O进行了封装,使得程序员不用直接面对IRP,而只要处理WDFREQUEST对象,处理也变得异常简单.而I/O的对象不再是设备对象,而是一个新的I/Otarget对象.I/Otarget对象比DEVICE_OBJECT更广,它不仅可以代表设备,也可以代表驱动,队列等.队列对象是一个全新事务,WDM编程中涉及到队列的地方不多,WDF却让他成为了不可避免的部件.但队列是专门用来管理WDFREQUEST对象的,因为WDFREQUEST对象是对IRP的封装,所以队列归根到底是对IRP的管理.队列允许WDFREQUEST对象以三种方式发送给驱动处理:

并行,串行,手动.由于对IRP的管理,使用失措,而导致的驱动问题,是WDM程序的一大难点.现在队列的引入,让IRP从野马变成了驯良的座骑.由于队列比较重要,下面我们分别来讲一讲.三者中,并行最好理解了,和WDM中的无序方式一样,所有的IRP都是并行处理的,也就是说,收到一个IRP就立即处理一个IRP.串行和手动可能较难理解,下面我们举例演示串行队列的使用.我们假设有一个用户线程X以同步方式向内核发送一个命令.内核框架收到命令后,判断出命令应当归于串行队列1.此时串行队列1中已经有3个排队命令.下图中,图1显示了新命令的入队过程;图2显示了命令的处理过程;图3显示了命令完成后的线程,队列状态.

4

WDFUSB设备驱动开发教程(1.2版)

线程X(串行队列当前被处理

33

WDF1

1)Request1Request2Request3

///////User内核22*黄色小球代表一个Request1.用户线向内核驱动发送一个请求,WDF框架首先获得处理这个请求的机会.2.此请求隶属于串行队列,WDF便将请求排到串行队列的最后面:

Request4.3.线程将一直等待Request4的完成图1Request排队

线程X

(串行队列1)

/////////////////////

Request4

2

WDF

12

被处理

*黄色小球代表一个Request1.队列中的前面三个请求别处理完成,Request4被处理.2.Request4处理结束后,WDF回向通知用户线程,并返回处理结果.图2完成Request

线程X

WDF

////////////////////////////

1内核中的串行队列空(或者继续接受新命令)图3新状态2线程X继续执行

5

WDFUSB设备驱动开发教程(1.2版)

图3新状态每个设备对象都有一个默认队列,未经特殊说明的请求类型都被送往这个默认队列中,如要把某些请求排列到特殊队列,则需特别说明.一般总是把默认队列设置为并行队列,这是为了将效率最大化.只将部分需特别处理以保证安全的对象,放置到串行队列中.而手动队列一般放置一些特殊的请求,这些请求往往是为了等待某个条件被满足以达到同步目的,或等待需要的数据到来,如从USB的中断端口读取数据.多个队列之间可以互通生气,就是说,队列中的请求,A可以被送到B队列中进行排队,这种交流存在于任何的两种队列之间.在不少情况下,需要用到队列转移,比如说,IRP_MJ_DEVICE_IO_CONTROL类型的请求,一般都可以被并行处理的,但控制号为CTL_CODE为IOCTL_REQUEST_1的DEVICE_IO_CONTROL请求却必须被串行处理;这时候我们可以把IRP_MJ_DEVICE_IO_CONTROL请求设置为在并行队列中排队,这样绝大部分的控制请求都将被并行处理,而当并行队列的处理函数遇到控制码为IOCTL_REQUEST_1的时候,放弃对它的处理,并重新将他送到串行队列中排队等待.兼容性兼容性体现在两个方面,很令人振奋:

对WDM的兼容,对旧系统的兼容.能兼容WDM,或者说能轻松切换到WDM模式是WDF的一大优点.如果不实现这一点,将给很多人带来痛苦.特别是当人们使用某个小端口驱动,将代码写了一大半的时候,忽然发现某个必须用WDM才能完成而难以实现的问题时,将导致天大的痛苦.在WDF程序中可以很容易获取IRPs,deviceobjects,driverobjects这三种对象,并按照WDM方式处理它们.实际上,这就够了.对旧系统的兼容,这一点一直以来,就不是微软的强项.但WDF却令人刮目相看.虽然在它的第一版被发布的时候Vista系统已经推出,但他却能够支持所有的NT系统,并且所提供的WDF示例代码,能够在所有NT平台上跑.这使得我们可以一个驱动同时支持WIn2000,XP,Vista,Win7这些系统,而不用在代码中对系统进行判断,更不用每个系统各写一个驱动版本.其实很多组件达不到这个要求,让我们看看NDIS,AVStream的表现吧,就有理由回过头来赞赏WDF.PNP和电源实现恐怕这才是最令人高兴的!

几乎没有人能写出PNP/电源处理没有一点问题的驱动代码来.真的,因为实在是太复杂了,分叉路径太多了.WDF为PNP,电源,电源策略三者定义的状态值,据说达到近两百种之多——想要实际领略一下,请在WDK文档中搜索查看WDF_DEVICE_PNP_STATE,WDF_DEVICE_POWER_STATE和WDF_DEVICE_POWER_POLICY_STATE,三者加起来超过了270个枚举量.按照最苛刻的要求,你当然也要在驱动中把这些状态都进行处理,哪怕大部分状态只有百万分之一的几率发生.恐怕没有人曾经把这么多的状态都自己处理过吧——用WDM代码!

其他令人头疼的问题还包括:

pendingI/O,correctI/Ohandlingandsynchronization,DMA.它们都看似容易,却实在很难被处理的,因为其内部实现的复杂性.我不准备在这里对此内容进行讨论.但值得欣慰的是,WDF将从此让我们好过起来,当遇到上述这些问题的时候——微笑吧,程序员们!

蓝屏会远离我们的,而更强壮的驱动代码在朝我们招手.

6

WDFUSB设备驱动开发教程(1.2版)

WDF对电源和PNP的设计方式是,进行最基本的处理,框架向程序提供回调接口,如果程序注册了某个回调,则框架在对应的状态变化时刻调用此回调,否则就使用默认的处理方式.下面是PNP/Power/Power策略三者的回调函数结构体定义.

//PNP/电源回调typedefstruct_WDF_PNPPOWER_EVENT_CALLBACKS{ULONGSize;//结构体长度.结构体版本存在升级趋势.//初始与结束回调函数.//初始:

EvtDeviceD0Entry早于EvtDevicePrepareHardware被调用;//结束:

EvtDeviceD0Exit晚于EvtDeviceReleaseHardware被调用;PFN_WDF_DEVICE_D0_ENTRYEvtDeviceD0Entry;//进入D0电源状态PFN_WDF_DEVICE_D0_EXITEvtDeviceD0Exit;//退出D0电源状态PFN_WDF_DEVICE_PREPARE_HARDWAREEvtDevicePrepareHardware;PFN_WDF_DEVICE_RELEASE_HARDWAREEvtDeviceReleaseHardware;//设备被REMOVE后,调用此回调来释放在EvtDeviceSelfManagedIoInit中//为每个框架设备对象申请的资源.PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUPEvtDeviceSelfManagedIoCleanup;//当设备被REMOVE后,此回调被调用来处理遗留的IOREQUEST对象.PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSHEvtDeviceSelfManagedIoFlush;//首次进入D0状态后,系统为驱动创建的每个框架设备对象调用此函数,来申请//专属于此设备对象的资源.PFN_WDF_DEVICE_SELF_MANAGED_IO_INITEvtDeviceSelfManagedIoInit;//上面申请的设备资源将被暂停,三者可能性:

//设备休眠,设备拔除,或者PNP管理器试图重新分配系统资源.PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPENDEvtDeviceSelfManagedIoSuspend;//资源被暂停后又可以重新使用了.只有当系统从休眠状态醒来时,才会被调用.PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTARTEvtDeviceSelfManagedIoRestart;//设备被异常拔除PFN_WDF_DEVICE_SURPRISE_REMOVALEvtDeviceSurpriseRemoval;//查询设备是否能够被移除PFN_WDF_DEVICE_QUERY_REMOVEEvtDeviceQueryRemove;//查询设备是否可被停止PFN_WDF_DEVICE_QUERY_STOPEvtDeviceQueryStop;//当驱动使用一些特殊文件的时候,此回调被调用.//特殊文件是这三者:

页文件,休眠文件,Dump文件PFN_WDF_DEVICE_USAGE_NOTIFICATIONEvtDeviceUsageNotification;//系统初始化的时候,或者驱动属下的多个设备对象之间的关系发生变化时,此回调被调用.PFN_WDF_DEVICE_RELATIONS_QUERYEvtDeviceRelationsQuery;}WDF_PNPPOWER_EVENT_CALLBACKS,*PWDF_PNPPOWER_EVENT_CALLBACKS;

以及:

//电源策略回调//关于电源策略请看下面章节介绍typedefstruct_WDF_POWER_POLICY_EVENT_CALLBACKS{ULONGSize;//结构体长度.//设备将进入休眠状态了,尚未离开D0状态.//实现电源策略:

让设备可以从即将进入的睡眠状态中醒来.PFN_WDF_DEVICE_ARM_WAKE_FROM_S0EvtDeviceArmWakeFromS0;7

WDFUSB设备驱动开发教程(1.2版)

//设备从休眠状态中被唤醒,进入D0状态.//实现电源策略:

为了让设备进入休眠后不再醒来,要在这里做一些设置PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0EvtDeviceDisarmWakeFromS0;//设备自己把自己从休眠状态中被唤醒,此时已经进入D0状态.//但EvtDeviceDisarmWakeFromS0还没有调用.//实现电源策略:

能接受并处理唤醒信号.PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGEREDEvtDeviceWakeFromS0Triggered;//下面的三个函数类似前三个,但这里的系统状态是Sx,而前面的系统状态是S0下.//上面的唤醒,仅仅是设备唤醒自己;而这里的唤醒,也包括把系统从Sx唤醒到S0下.PFN_WDF_DEVICE_ARM_WAKE_FROM_SXEvtDeviceArmWakeFromSx;PFN_WDF_DEVICE_DISARM_WAKE_FROM_SXEvtDeviceDisarmWakeFromSx;PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGEREDEvtDeviceWakeFromSxTriggered;//是EvtDeviceArmWakeFromSx的高级版本,提供了更详细信息.在WDF1.7以后才有.//不应该同时存注册这两个回调函数.他多了两个参数,使得函数能够明白自己被调用的原因.PFN_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASONEvtDeviceArmWakeFromSxWithReason;}WDF_POWER_POLICY_EVENT_CALLBACKS,*PWDF_POWER_POLICY_EVENT_CALLBACKS;

所有的回调函数,都在被动级别上运行,这替我们省去了很多麻烦.这使得程序在进行初始化或反初始化的时候,不用担心运行于分发级别(DISPATCH_LEVEL)而顾忌重重.因为在分发级别上运行的代码有很多限制,常常免不了要使用WorkItem,而使用workitem往往又必须同时实现同步,相当麻烦.上述的回调函数和WDM的分发函数间,谈不上一一对应,但也存在着比较强的对应关系.比如函数EvtDevicePrepareHardware对应了WDM中的PNP_START_DEVICE分发;函数EvtDeviceReleaseHardware对应了WDM中的PNP_STOP_DEVICE分发;函数EvtDeviceSurpriseRemoval对应了WDM中的PNP_SURPRISE_REMOVE分发;函数EvtDeviceD0Entry/EvtDeviceD0Exit对应了WDM中的PNP_SET_POWER分发,等等.在处理PNP_START_DEVICE的时候,免不了要担心一下是第几次调用StartDevice函数来,考虑电源状态是否已进入D0状态.EvtDevicePrepareHardware回调却不必有此顾虑,因为框架已在内部做了考虑.其他WDF中包含了两套子框架,即:

KMDF和UMDF.KMDF用来编写内核驱动;UMDF用来编写用户层驱动.本章中只涉及KMDF的内容,所以绝大部分情况下,WDF仅指KMDF而言.WDF仍在不断的发展中,四五年的时间里,他得到了越来越多人们的推崇,而对于他的将来,人们还有更多的憧憬.比如希望微软总有一天能够将WDF代码开源;比如WDF也许有一天会改成用C++来实现,以实现更多的封装,继承特性.等等.

8

WDFUSB设备驱动开发教程(1.2版)

二.1.

USB设备硬件结构主从结构

首先从硬件角度介绍USB,本文档的任务在于内核开发,硬件知识只能点到为止.USB的全称是UniversalSerialBUS(通用串行总线).硬件上,他有两个显著的特点:

串行数据传输,支持热拔插.从1996年1月第一个版本发布到今天,USB已经经历了四个版本:

1.0,1.1,2.0和3.0.其应用遍及各个领域,方方面面.USB的另外一个特点是他采用主从结构.两个可以互联的设备,一定有主从之分.这导致了两台主机(主设备)或者两台MP3(从设备)之间,没有办法互联.只能在设备(MP3)和主机之间建立主从互联关系.当然,后来出现了OTG,可以让设备更换角色.但并未能改变主从结构的本质.能成为USB主机,就一定要具备两种设备:

USB主控制器,USB根集线器.主控制器用来处理根集线器上的数据,交给系统处理;根集线器用来连接多个外部设备.读者请注意不能把这里的根集线器和普通USB集线器全然划等号,应当把USB集线器也理解为USB外部设备的一种,不是主机的组成部分.

主控制器根集线器集线器端口外部设备

图1主机和设备从上图我们了解到,设备->集线器->控制器->系统,就像碗中杯,杯中勺一样,层层套叠.我们在使用的电脑,每台电脑都有若干个控制器,控制器上有一个或多个根集线器,集线器上又对外暴露出一个或多个USBA型接口让外部设备连接.将设备管理器的视图模式选为"按连接排序设备"后,可看到下图所示的层次结构.

图2控制器,集线器和设备最上层是USBEHCI接口的控制器,中间层是控制器上唯一的根集线器,最下层是连接在根集线器上的设备.每个USB控制器,作为一个USB族群之灵魂,其驱动程序负责为子设备分配总线地址.总线地址为7位宽,由于控制器自己占一个地址,故而最多可提供(27-1=127)个子设备地址,也就是说,每个控制器上最多能连接127个子设备.并且,这个数目包含了根集线器.电器特性方面,标准USB接口有4个金属针脚,对应着USB线中,就是4根金属线:

9

WDFUSB设备驱动开发教程(1.2版)

两根电源线,两根数据线.两根电源线,一个接5V电源,一个接地.两根数据线,实现了数据的差分传输,提高了稳定性,等于是一根线,也就是"串行"之由来了.说到电源线,就说说设备供电.USB设备可以自己供电,也可以从总线获取电源.总线获取的电源,就是通过5V电源线传过来的.U盘,像鼠键这类小型设备,电源或者100mA5V电流足以满足其设备需求,故而多从总线获取电源;移动硬盘,打印机,专业USB声卡这种较大设备,往往需要外置电源,也就是自己供电.巧得很,我发现XP系统中的根集线器驱动程

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1