基于WINDOWSDDK的USB键盘驱动开发
【摘要】USB接口具有方便快速等优点,已经发展成为一种比较普遍的计算机与外设的接口。基于微软windows系统DDK,本文介绍了一种非标准USB键盘的windows设备驱动程序的开发过程与方法。
【关键词】设备驱动;驱动开发包;非标准键盘
1.引言
USB总线的成功关键是使用户感到了使用USB设备的方便。即插即用(PnP)概念的使用使某些硬件的安装过程得到了简化。USB规范中指出,适合迁移到USB1.1上的硬件限定于那些低速到中速的外设,包括键盘,鼠标等。即这些设备的数据传输速率低于12Mb/sec,并且能通过单一的PC接口被系统软件识别。现在标准的usb键盘设备只需要遵循一些hid设备的协议就可以被windows操作系统自动识别无需设备制造商开发驱动程序,但有些键盘带有特殊功能,所以需要设备驱动程序。
2.Usb软件系统简介
USB设备对于USB系统来说是一个端点的集合,端点被分成组,一组端点实现一个接口,如图1所示。设备端点和主机软件之间利用管道进行数据交互。设备驱动程序就是通过这些接口和管道与设备进行通信的。
USB数据传输就是指发生在主机软件和USB设备上特定端点(endpoint)之间的数据交互,一个设备可以具有若干管道(pipe)。一般情况下,一个管道中数据传输与其他管道中的数据传输是相互独立的。这种发生在管道中的数据流动共有4种基本类型:
(1)控制传输,一般发生在设备枚举阶段
(2)块传输,一般用于usb disk
(3)中断传输,一般用于键盘鼠标类设备
(4)流传输,一般用于语音视频流设备
USB设备驱动程序都必须使用这些管道和接口来管理设备,而不是直接通过内存或I/O端口来存取来管理。
3.Windows驱动程序的工作原理
3.1 Windows驱动程序基本架构
驱动程序与应用程序的最大差别在于驱动程序的架构。应用程序从头到尾都在main或者winmain函数的控制下执行,驱动程序不存在这样的函数,而只是一个由I/O管理组件根据需要调用的子例程的集合,I/O管理组件根据不同的情况调用驱动程序中不同的例程。构成内核模式驱动程序的主要例程包括:初始化和清除例程,I/O系统服务调度例程,数据传输例程和资源回调例程,下面是一个基本的驱动例程架构:
extern”C”
NTSTATUS
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
DriverObject->DriverUnload=Driver Unload; DriverExtension->AddDevice=AddDevice;
DriverObject->DriverStartIo=StartIo;
DriverObject->MajorFunction[IRP_MJ_PNP]=DispatchPnp; MajorFunction[IRP_MJ_POWER]=DispatchPower;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]=DispatchWmi;
... Length+sizeof(WCHAR));
if(!servkey.Buffer)
return STATUS_INSUFFICIENT_RESOURCES;
servkey.Maximum Length=Registry Path->Length+sizeof(WCHAR);
RtlCopyUnicodeString(&servkey,RegistryPath);
return STATUS_SUCCESS; Device Extension;
dx->fdo=fdo;
dx->pdo=pdo;
dx->UsageCount=1;
KeInitializeEvent(&dx->StoppingEvent,NotificationEvent,FALSE);
dx->OpenHandleCount=0;
dx->GotResources=false;
dx->Paused=false;
dx->IODisabled=true;
dx->Stopping=false;
dx->UsbConfigurationHandle=NULL;
dx->UsbPipeHandle=NULL;
dx->UsbTimeout=10;
DebugPrint(”FDO is %x”,fdo);
//Register and enable our device interface
status=IoRegisterDeviceInterface
(pdo,&USBKBD_GUID,NULL,&dx->ifSymLinkName);
if(!NT_SUCCESS(status)) {
IoDeleteDevice(fdo);
return status; }
dx->NextStackDevice=IoAttachDeviceToDeviceStack(fdo,pdo);
fdo->Flags|=DO_BUFFERED_IO|DO_POWER_PAGABLE;
fdo->Flags &=~DO_DEVICE_INITIAL IZING;
return STATUS_SUCCESS;
}
当USB堆栈分配完资源后,将发送一个IRP_MN_START_DEVICE,此时DriverEntry例程中指定的IRP_MJ_PNP处理函数将被激活。它将完成下面的工作:获取设备描述符;获取配置描述符;从配置描述符中选择一个接口,并用该接口配置设备。这就是USB设备的枚举过程,如枚举成功,将配置信息放在设备扩展中,这时的驱动程序已经完全就绪,等待应用程序发出与设备进行通信的请求。
4.2 USB键盘设备的数据交互过程
当应用程序与设备进行数据传输时,应用程序首先必须调用CreateFile打开设备,然后利用返回句柄对设备进行读写操作,用户在调用CreateFile时使用的文件名一般是驱动程序里建立一个符合链接(SymLinkName)。对于驱动程序,当应用程序调用CreateFile时,相应于IRP_MJ_CREATE的处理函数被激活,并完成下面工作:获取当前IRP的堆栈指针,通过堆栈指针获得要打开的文件名,然后通过文件名找到内部管道ID,如对当前接口此管道ID合法,则将该管道打开,并返回给应用程序一个句柄。
管道打开后,APP将会调用ReadFile或者WriteFile从设备读取数据或向设备写数据。此时驱动程序中对应于IRP_MJ_READ或者IRP_MJ_WRITE的处理函数被激活。这些处理函数将读写请求转换成相应的USB请求包(URP)传递给下层驱动程序,并等待I/O处理的最后完成。本项目USB设备数据传输采用中断方式,IRP_MJ_READ对应函数UsbKbdRead,IRP_MJ_WRITE对应函数UsbKbdWrite,IRP_MJ_CREATE对应函数UsbKbdCreate,对于UsbKbdCreate函数里配置设备接口时,由于标准键盘的中断传输就是单方向只有一个管道,本文的非标准键盘是自定义的也需要对键盘进行写操作,所以需要配置一个IN和OUT管道,所以配置函数UsbSelectConfiguration里需要配置设备传递来中断端点的管道信息。
5.驱动程序的编译调试
为了能在VC下利用DDK编译驱动程序,创建文本文件build.bat,并粘贴下面代码
@echo on
set DDKPATH=D:\WINDDK @ddk安装目录
set PRJDRV=F:
set PRJPATH=F:\UsbKbd @项目程序目录
rem call BuildDriver.bat %DDKPATH% %PRJDRV% %PRJPATH% %1 %2
if %1==““goto usage1
if %2==““goto usage2
if not exist %DDKPATH%\bin\setenv.bat goto usage
call %DDKPATH%\bin\setenv.bat %DDKPATH% %1 %2
@echo on
%PRJDRV%
cd %PRJPATH%
build %1 %2
goto exit
:usage1
echo usage can’t know DDK path!
goto exit
:usage2
echo usage can’t know os type!
:exit
建立一个新的makefile工程,并在build command line那里设定build.bat free wxp,就是进行free版本的编译并利用wxp的DDK,本项目调试主要通过DebugPrint打印信息。
6.结束语
本文分析了驱动程序的工作原理,给出了编写驱动程序的主要过程,给出编写驱动程序的总体架构,并在主要细节上作了解释,为开发人员提供一定的参考。
参考文献
[1]Art Baker.Windows2000设备驱动程序设计指南[M].北京:机械工业出版
社,2001.
[2]杨龙,刘岩.USB设备驱动程序的设计与开发[J].北京:装备指挥技术学院学报,2003-01-Vol14.
[3]刘蓬,张培仁.用DDK开发WDM驱动程序[J].合肥:计算机应用,2003(12):vol23.
[4]Walter Oney.Programming the Microsoft Windows Driver Model[M].1999.
因篇幅问题不能全部显示,请点此查看更多更全内容