1.驱动简介
1.1.驱动是什么
计算机的外部设备需要和计算机进行数据交换,生产外部设备的厂家如何使计算机和自己的设备交换数据呢,就是通过驱动程序,从设备中读入到计算机中,早期的Win3.1,Win9x设备驱动是vxd,Win
NT是kdm, Win2k 统一发展成wdm模式。
1.2.sys文件
sys文件是驱动程序的可执行代码,其扩展名为.sys,驱动程序安装后保存在windows/system32/drivers目录中。
对于PnP设备,在设备插入后,sys文件会被windows装载到内存中,系统线程调用sys中的函数来和设备进行通信。
1.3.inf文件
inf文件是安装设备驱动程序时必须使用的文件,其扩展名为 .inf,驱动程序安装后保存在windows/inf目录中。
系统使用一个扩展名为INF的文本文件来控制与安装驱动程序相关的大部分活动。INF文件应该由驱动程序开发人员随驱动程序一起提供。通过INF文件可以告诉操作系统哪一个文件需要复制到用户硬盘上,应该增加或修改哪一个注册表项,如此等等。
inf中提供产品设备的产品id,以及对应的sys文件名,驱动class名,class guid,
1.4.usb-client driver
HOST 与DEVICE, ENDPOINT与PIPE
我们进行的USB驱动开发大多数是usb-client
driver,系统厂商大多数都已经把USB类驱动做好,我们则是在类驱动之上开发针对自己设备的驱动,习惯上称做usb-client
driver,其在整个软件构架中地位如下:
UHCD--USBD--USB CLIENT DRIVER--DLL OR APP
usb-client driver仍然遵守WDM模型,是WDM驱动。因为要支持PnP,所以要很小心的处理自己的资源以及IRP,
随时准备处理拔出或者插入设备的情况; 电源处理不当也会使系统无法唤醒。
需要了解的知识:wdm,usbdi,our usedevice,
wdm:
目标: a, 能提供接口函数,
b, 能实现pnp,电源消息处理,wmi,i/o等处理,
usbdi:
urb,irp,等时,中断,控制,批传输的概念
our usedevice:
我们的usb设备的传输类型,设备的能力。
2.WDM机制
WINDOWS 9X 及以前版本VXD,WIN NT 使用KDM机制,WIN2000后的驱动程序都使用WDM机制。
2.1.WDM驱动的分层机制
WDM驱动的分层图:
2.2.PDO以及IRP机制
一种设备使用相同的驱动程序,每层驱动程序装载后,有一个驱动对象(driver object)。
在驱动对象中,有设备链,一个节点是一个设备对象(device object), 称为pdo,对应一个设备,用设备链实现多个设备支持。
系统使用irp(i/o request
package)和设备进行通信,调用驱动程序函数时候,会传递需要操作的的设备对象pdo,以及进行通信使用的irp。
2.3.WDM驱动程序code构成
1, 函数构成:
基本函数:driverentry,adddevice,unload
入口函数driverentry必须使用driverentry命名,并向系统注册 其他函数名。
i/o控制函数:startio,oninterrupt,dpcforisr,adaptercontrol。
分发函数:Dispatchpnp,Dispatchpower,Dispatchwmi,dispatchread,
dispatchwrite。
其它见到的函数:deviceioctl,Dispatchcreate,Dispatchclose。
这些函数除了driverentry外,其它的都可以可以自己命名,由 driverentry向系统注册。
2,必要性说明:
必须函数:
基本函数:driverentry,adddevice,
分发函数:Dispatchpnp,Dispatchpower, Dispatchwmi,
可选函数:
处理请求队列需要的函数:i/o控制例程:startio,
如果设备需要产生中断:i/o控制例程:oninterrupt,dpcforisr,
DMA操作需要的函数:i/o控制函数:adaptercontrol,
分发函数:dispatchread,dispatchwrite,
2.4.必需的处理
基本函数:driverentry,adddevice,
分发函数:Dispatchpnp,Dispatchpower, Dispatchwmi,
在driverentry中必须完成所需要的其他函数的注册,使得系统可以调用这些函数与设备进行通信。
在有新的设备插入时系统会调用adddevice,由驱动程序自己调用IoCreateDevice创建设备对象,并attach到设备堆栈中,并初始化设备对象的Flag成员。
Dispatchpnp,处理PnP管理器的发出的主功能码为IRP_MJ_PNP 的i/o请求,实现设备对即插即用的支持。
Dispatchpower,处理电源管理器发出的主功能码为IRP_MJ_PNP 的i/o请求,实现设备对电源管理的支持。
Dispatchwmi,处理WMI管理器发出的主功能码为IRP_MJ_SYSTEM_CONTROL
的i/o请求,实现设备对WMI(WINDOWS management instrumentation)的支持,作用是可以监控设备性能。
详细资料,可以查阅ddk,D_P2003-050_MBCUSB2_TRN_WDMSTRUCT_CN.ppt
3.USB类驱动接口
3.1.USB类驱动和URB
在这个UHCD--USBD--USB CLIENT DRIVER--DLL OR APP结构中,
usbd将usb端口芯片驱动uhcd进行了包装,提供更便利的功能,使得其它设备驱动程序可以简单的利用这些功能。
usbd提供的函数就称为usbdi(usbd interface),主要利用 urb(usb request block),
将urb放入irp(可以自己分配irp)中传递给usbd,由usbd完成 usb设备的相关操作。
3.2.URB详细
请阅读DDK帮助。
3.3.常用函数
UsbBuildVendorRequest,UsbBuildGetDescriptorRequest,
UsbBuildSelectConfigurationRequest,USBD_ParseConfigurationDescriptorEx,
USBD_CreateConfigurationRequestEx,USBD_ParseDescriptors
4.我们的设备
我们的设备有一个控制管道,两个bulk读写管道(自己的命令都通过读写来完成),支持usb2.0, 支持标准usb请求。
5.SYS开发
5.1.安装配置开发环境
1、确定你已经安装了Visual C++,
2、安装2000 DDK,安装2000 DDK成功后,在“开始”->“程序”里应该有“Development
Kits”->“Windows 2000 DDK”的项目。(注意一定要先安装好VC,然后才安装DDK,这个顺序决不能颠倒!!)
DDKROOT环境变量设置为Windows 2000
DDK的基目录,如果不是的话,必须进行手工配置。请在控制面板“系统”属性的“高级”标签环境变量编辑器中设置好这个环境变量。例:DDK的安装路径为:E:WINDDK3790
则新建用户环境变量变量名为: DDK ROOT 变量值为: E:WINDDK3790
5.2.制作inf文件
系统使用一个扩展名为INF的文本文件来控制与安装驱动程序相关的大部分活动。INF文件应该由驱动程序开发人员随驱动程序一起提供。通过INF文件可以告诉操作系统哪一个文件需要复制到用户硬盘上,应该增加或修改哪一个注册表项,如此等等。
INF文件包含一些名字由方括号括起来的段,大部分段都含有一系列keyword = value形式的指令。例如:[Version]
Signature="$CHICAGO$" Class=UUSBD
ClassGUID=B51CA6BA-E750-4dff-9CDE-6AA963B17052{} provider=%LEADING%
DriverVer=08/27/2001,0.1.0.1
inf制作详细参看,D_P2003-050_MBCUSB2_TRN_INFSTRUCT_CN.ppt
5.3.编写以及编译驱动
1 、makefile 文件,2 、Sources文件
makefile的内容是:
# # DO NOT EDIT THIS FILE!!! Edit .sources. If you want to add a new
source # file to this component. This file merely indirects to the
real make file # that is shared by all the driver components of the
Windows NT DDK # !INCLUDE $(NTMAKEENV)makefile.def
Sources:
TARGETNAME=HelloWDM TARGETTYPE=DRIVER DRIVERTYPE=WDM TARGETPATH=OBJ
? INCLUDES=$(BASEDIR)inc; $(BASEDIR)incddk;
TARGETLIBS=$(BASEDIR)lib*freeusbd.lib? SOURCES=HelloWDM.cpp
这个文件指定了生成的驱动程序目标名、存放obj文件的位置、lib文件的位置、被编译的源文件对象
值得注意的是,“=”前后不能有空格,否则编译的时候会出错。
编译:
从开始菜单里选择编译环境 如:Windows 2000 Checked Build Environment.exe
它从配置文件sources中读出待编译的程序的配置,包括源文件、目标文件等,
从环境变量include中得到引用文件的地址,然后调用编译链接器进行实际的编译链接工作。 编译所产生的日志文件: Build.log
链接中执行的命令行 Build.wrn 链接中遇到的警告 Build.err 链接中遇到的错误
5.4.驱动的安装调试
Win2000以上都使用*.inf文件来控制与安装驱动程序相关的大部分活动。Inf文件由驱动开发人员随驱动程序一起提供。控制面板->添加新硬件,从硬件列表中选择其他设备,并单击从软盘安装,再单击浏览,找到*.inf所在文件夹后,确定。接下来点下一步就ok了。安装之后,该驱动将出现在设备管理其中。
调试手法:
dbgprint(),
systemdump,
assert(),
windbg跟踪,可以设置硬断点(插入dbgbreakpoint()函数)以及软断点(在运行到硬断点后,在windbg程序中打开源文件,设置软断点)
详细资料,查阅D_P2003-050_MBCUSB2_TRN_WDMDEVELOP1_CN.ppt,
D_P2003-050_MBCUSB2_TRN_WDMDEVELOP2_CN.ppt,机械工业出版社,《windows2000设备驱动程序设计指南》附录A驱动程序调试环境,附录B故障检验码
6.经验、教训总结
6.1.仔细check你的代码
驱动程序运行在kernelmodel下,与应用程序截然不同,你的代码如果出现任何问题,那么你看到的将是蓝色的系统崩溃屏幕,或者系统直接重新启动,
6.2.调试机的必要性
由于代码不可避免的会存在错误,所以,拥有调试机是必要的,否则你的大部分时间会浪费在等待计算机shutdown和reset上,工作的进展会如同蜗牛在爬行。
请注意你的dbug信息,尤其是dbgbreakpoint,如果你的机器不是处于调试模式下,断点将会挂起你的系统,黑屏,不能再进行任何操作,也看不到任何显示。
6.3.谨慎和认真
小心的处理每一个irp,以及你的任何资源,最好有一个可以确定它们被正确无误的处理和使用的手段,比如增加标志性的调试信息,使用计数等。否则你将花费很多很多的的时间去发现这些细微而致命的错误。