时间:2024-07-28
何丽华,梁杰申,肖楚海
Windows已经成为PC的主流操作系统,要想实现在Windows操作系统下对硬件设备的操作,必须通过在WDM模型下设计驱动程序这个软接口。USB,是Universal Serial Bus(通用串行总线)的简称,为个人电脑与其外围设备之间的连接提供了一种标准化、单一化的接口[1]。它的主要优点体现在:操作简单,即插即用;成本低廉,携带方便;标准统一;可以连接多个设备;通信速率快;可靠性高等。鉴于USB的这些特点,它已经成为PC的首选接口。
USB驱动的设计基于WDM(Windows Driver Module),即Win32驱动模型。WDM是Microsoft公司力推的新型驱动模型[2],旨在通过一种灵活的方式简化驱动程序的开发,在实现对新硬件支持的基础上,减少并降低必须开发的驱动程序的数量和复杂性。
WDM有两种运行模式,即内核模式和用户模式。在内核模式下,程序的运行不受操作系统的任何限制,对I/O有完全的访问权;在用户模式下,操作系统提供某种机制,可以限制程序的各种I/O操作。
WDM驱动程序采用了分层驱动的方式,不同层之间的驱动程序完成不同的操作,不同层之间可以互相调用,在WDM中引入了功能设备对象(FDO Filter Device Object)和物理设备对象(PDO Project Device Object)来描述硬件。一个PDO对应一个真实的硬件,一个硬件只允许有一个PDO但是却可以有多个FDO。在驱动程序中直接操作的不是硬件设备,而是相应的PDO和FDO[3]。在用户态和内核态通信方面,系统为每一个用户请求打包形成一个IRP结构,将其发送至驱动程序,并通过识别IRP中的PDO来区分时发送给哪一个设备的。
图1 WDM驱动程序模型
驱动模型如图1所示:中总线驱动程序位于最底层,总线驱动程序为实际的I/O总线服务,比如USB。微软已经为Windows操作系统提供了总线驱动程序。一个总线驱动程序负责的工作有:枚举总线上的设备;向操作系统报告总线上的动态事件;响应即插即用和电源管理的I/O请求;管理总线上的设备。总线驱动程序创建一个物理设备对象来代表它发现的设备。即发现总线上的所有设备和检测设备添加或者删除,创建物理设备对象PDO;功能驱动程序处理设备的I/O请求包(IRP),负责创建功能设备对象FDO;其他层的驱动程序是一些过滤程序(Filter Driver),对应的设备对象是过滤器设备。安装硬件设备时操作系统的即插即用管理器按照设备驱动程序的要求构造设备的对象,首先是最底层的总线驱动程序检测到实际的物理设备,创建物理设备对象PDO,然后,即插即用管理器查询注册表,按注册表信息依次加载过滤驱动程序和功能驱动程序,可生成相应的功能设备对象FDO,并建立设备对象和驱动程序的对应关系,这样一个完整的设备驱动程序就建立了[4]。
在开发工具的选择上本文选择用Microsoft公司提供的Windows DDK,Win2000DDK。DDK软件包中包括有关设备驱动程序开发的文档、编译驱动程序时所需要的头文件和库文件、调试工具和一些设备驱动程序范例。但是直接使用DDK开发比较困难,而且设备的驱动程序本身比较复杂,一旦运行错误可能会对整个操作系统产生灾难性的后果。所以我们选择配合第三方软件来实现。DriverStudio是由Numega公司出品的专门用于设备驱动程序开发的软件包,包含VtoolsD、SoftICE和DriverWorks等开发工具。可以实现驱动制作的“自动化”,安装驱动向导一步一步的生成驱动。
首先在PC机上先安装Visual C++,然后安装Win2KDDK,因为在安装DriverStudio的时候要求指定DDK的路径。所以安装顺序不能错,安装完成后在VC的界面里会有DriverStudio菜单项。
由于DriverWorks所用的类库是对DDK的库函数的封装,还必须在Visual C++中编所需要的库文件。本文用的是DriverStudio2.6,所以先改正它的Bug,然后通过NuMega DriverStudio /Tools/DDK Build Settings 进入到DriverStudio的路径。选择Visual C++的BatchBuild工具对DriverStudio安装目录下的vdwlibs.dsw库进行编译,这里我们只需要选择WDM的库就可以了。
做好了前面的配置工作,我们就可以按照 DriverStudio的DriverWorks来一步一步的生成驱动。在利用DriverStudio 2.6 的向导DriverWizand 完成驱动程序的框架时共有10个步骤:(1)选择路径并填写工程名,这里的工程名我们命名为MW70A;(2)选择驱动程序类型WDM;(3)选择USB设备总线类型,填写PID(产品识别号)和VID(厂商识别号)。这里根据我们的固件程序我们填写为PID7070,VID0707;(4)选择I/O请求IRP处理的方式,这里用端点2的In和Out用Bulk传输。并且将其最大的传输值设为65535,USB的包最大为64个字节,我们这样设是为了不让PC成为限制USB速率的瓶颈;(5)选择所生成的驱动程序文件中的类名和驱动程序文件名,取默认值:MW70A;(6)选择驱动程序支持的功能项,我们选择Read、Write、Device Control、Cleanup、install;(7)自动产生端点2的Bulk传输读写代码;(8)定义排队的方式,这里不理会,取默认值。(9)定义应用程序调用DeviceIoControl函数对WDM驱动程序通信的控制命令,并对应不同的数据存取方式,取默认值;(10)选择是否生成一个Win32Console应用程序以及Debug跟踪代码等,并产生了此设备的GUID、供电方式、等。编译这个工程,即得到所需的驱动程序。在sysobjchki386里就有我们的MW70A.sys,在sys文件夹下有我们的MW70A.inf文件。按照LPC2368的固定端点配置(如表1),这里我们使用默认的端点0和批量传输的断点2实现USB设备的枚举和读写操作。
表1 LPC2368的端点配置
应用程序要访问我们的驱动程序,不是通过驱动程序名称来访问的,而是通过一个128位的全局惟一标示符(GUID)实现对驱动程序的识别[6]。这个GUID是我们上面制作驱动的第10步自动产生的应用程序,首先通过调用GUID来查找驱动程序。驱动程序通过安装文件(.inf)中PID和VID识别USB设备。通过检查设备的连接状态,来判断进入下一个环节。(详见图2.)
F(!NT_SUCCESS(m_ConstructorStatus))
{
Return;
}
NTSTATUS DriverEntry(PUNICODE_STRING RegistryPath);
图2 驱动程序调用过程
WDM驱动都有一个主要的初始化入口点,即一个称为DriverEntry的例程;它有一个标准的函数原型,当WDM驱动程序被装入时,内核调用DriverEntry例程,来设置主要的回调例程。在运行中,内核会调用不同的回调例程来完成不同的任务,主要负责驱动程序的装载、初始化总线上的设备、创建FDO、IRP的分类派遣以及卸载本层驱动程序等操作。
大多数的WDM设备对象,都是在调用即插即用管理器调用AddDevice例程入口时被创建的[7]。插入新设备后,当系统找到由安装系统文件所指示的驱动程序时,这个例程被调用。在此之后,一系列的即插即用IRP被发送到驱动程序,设备驱动程序可进行相应的功能处理。AddDevice函数是WDM驱动程序的一个特殊函数,PnP管理器为每个设备实例调用该函数。virtual NTSTATUS AddDevice(PDEVICE_OBJECT Pdo);
生成的API函数如下表(表2):
表2 API应用程序和驱动请求
应用程序使用Win32API函数来与操作系统通信,驱动程序彼此间用I/O要求信息包(I/O Request Packet,IRP)来通信。DriverWorks为IRP进行了封装,IRP是整个驱动处理的核心,Win32函数与所生成的IRP对应关系如上表。
读操作是从应用程序调要Win32API函数ReadFile开始的。当应用程序调用ReadFile函数时,系统通过ntdll.dll调用ntreadfile向设备驱动程序发送一个IRP[8],驱动程序接到该IRP后,开辟用以接收数据的内存区,判断所读数据是否大于最大信息包规格,因为每次只读取最大信息包个字节。然后建立相应端点的URB并向下层驱动程序提交该URB。此时I/O管理器执行Read,把数据放到缓冲区内。
安装驱动程序的时候,最好把MW70A.inf和MW70A.sys放在一个文件夹下面,当有对应的USB设备连接到电脑上时,可以手动选择驱动程序,找到对应的MW70A.inf,根据里面的PID和VID就可以自动安装。所以只要固件程序里面的PID和VID和驱动程序里面的一样就可以实现安装。
驱动程序工作在内核模式下,可以用DriverStudio中的SoftICE测试,测试流程如下:
使用Symbol Loader加载驱动程序,然后使用SoftICE跟踪测试,确认驱动程序正常加载;对核心的中断响应代码,应用SoftICE中的Genint命令产生虚拟中断,单步跟踪中断。USB硬件发送大量的数据,可以通过BUS Hound来查看。可以方便的看到其传输的数据和速率。
在程序的调试过程中,应注意可能因内存访问分页错误、设备资源和系统资源冲突、I/O使用错误、程序中指针使用错误等因素造成系统“死机”“蓝屏”等现象。在不同的机器上测试时,要对其他软件的兼容性做处理。
设计驱动程序是一个复杂繁琐的过程,而利用DriverWorks工具简化了开发过程,加快了开发周期,提高了开发效益。Windows已经成为PC的主流操作系统,基于Windows操作系统的USB设备驱动程序的开发,是一个难点也是一个热点。本文的USB驱动用在CAN总线数据的采集上,完全能够满足CAN的最大波特率1Mbps,极大的节省了开发时间,提高了开发效益。
[1]傅得立.基于 USB2.0的数据记录回放单元设计[D].中国科学院广电研究所,2007.
[2]张瑾.USB及其设备开发[J].现代电子技术,2005,(2):11-22.
[3]Cant C.Writing Windows WDM Device Drivers[J].R&D Books,1999,35(6):3-8.
[4]于勇.基于Windows的USB接口WDM驱动研究和应用[D].南京信息工程大学,2008.
[5]武安河.Windows2000/XP WDM驱动程序开发[M].2版.北京:机械工业出版社,2005:98-99.
[6]张帆 史彩成.Windows驱动开发技术详解[M].北京北京:电子工业出版社,2008:400-456.
[7]张念淮,江浩.USB总线接口开发指南[M].北京:国防工业出版社,2001:56-78.
[8]Cant C.Windows WDM 设备驱动程序开发指南[M].北京:机械工业出版社,2000:89-96.
我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自各大过期杂志,内容仅供学习参考,不准确地方联系删除处理!