荔园在线
荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀
[回到开始]
[上一篇][下一篇]
发信人: Laurence (God love Me), 信区: Program
标 题: [转载] Windows 2000驱动程序的设计
发信站: 荔园晨风BBS站 (Tue Sep 18 11:23:17 2001), 转信
【 以下文字转载自 Electronics 讨论区 】
【 原文由 Laurence 所发表 】
Windows 2000驱动程序的设计
清华大学电子工程系 谭章熹
本文介绍了Windows 2000 WDM驱动程序结构及其编写的注意事项,最后给出了一个
简单的WDM驱动程序及客户端程序的原码(Zip,24KB),希望能对大家有所帮助。
---- 1. 简介:
---- Windows 2000原名Windows NT 5.0是继Windows NT 4.0的新一代操作系统,
它不但继承了Windows NT 4.0的种种优点,而且在技术上又有了许多的突破,其中
一项就是对驱动程序结构的变化,即引入了全新的WDM (Win32 Driver Model)的驱
动程序构架。说是新技术,其实早在1997年Microsoft就提出了该项技术并在
Windows 98中得到了充分的应用,换句话说,Windows 98也支持WDM。这样WDM就成
为了一个跨平台的驱动程序模型,不仅如此WDM驱动程序还可以在不修改源代码的
情况下经过重新编译后在非Intel平台上运行,可以不夸张的讲WDM算得上是21世纪
的驱动程序构架。
---- 2.WDM的工作原理:
---- WDM是在NT 4.0驱动程序结构上发展起来的,所以它与NT 4.0的驱动程序极为
相似,但是它却有了本质上的提高,比如它支持USB、IEEE 1394、ACPI等全新的硬件标准。
虽然
Windows 98与Windows 2000都支持WDM,可是并不意味着Windows 98下的VxD可以在
Windows 2000下运行,而NT下的VDD却可以在Windows 98下运行。不过原先准备在
两个平台上同时运行需要编写两个截然不同的驱动程序,而现在只需要编写一个
WDM驱动程序就可以了。同NT 4.0驱动程序一样,WDM驱动程序也是分层的,即不同
层上的驱动程序有着不同的优先权,而Windows 9x下的VxD则没有此结构。另外,
WDM还引入了功能设备对象FDO(functional device object)与物理设备对象PDO
(physical device object)两个新概念来描述硬件,一个PDO代表一个真实硬件
,在驱动程序看来则是一个FDO,见图1。另外值得注意的是,一个硬件只允许有一
个PDO,但却可以拥有多个FDO,而在驱动程序中我们不是直接操作硬件而是操作相
应的PDO与FDO。在Ring-3与Ring-0通讯方面,操作系统为每一个用户请求打包成一
个IRP(IO Request Packet)结构,将其发送至驱动程序并通过识别IRP中的PDO来
识别是发送给哪一个设备的。另外,在驱动程序的加载方面WDM既不靠驱动程序名
称也不靠一个具有某种特殊意义的ID,而是依靠一个128位的GUID来识别驱动程序
(Windows下许多东西都是靠此进行识别的)。
---- 3.具体实现:
---- 同许多应用程序一样,WDM驱动程序是PE格式的,但是它却没有WinMain或
main这样的入口,取而代之的是DriverEntry:
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
//不同于前面的PDO
IN PUNICODE_STRING RegistryPath)
{
DriverObject- >DriverExtension- >AddDevice =
AddDevice; // DriverExtension
中存放着驱动程序扩展信息,包括设备所需要的硬件资源等。
DriverObject- >MajorFunction[IRP_MJ_CREATE]
= RequestCreate;
DriverObject- >MajorFunction[IRP_MJ_CLOSE]
= RequestClose;
DriverObject- >MajorFunction[IRP_MJ_DEVICE_CONTROL]
= RequestControl;
DriverObject- >MajorFunction[IRP_MJ_PNP]
= RequestPnp;
return STATUS_SUCCESS;
}
在DriverEntry驱动程序要向操作系统登记并注册一些消息处理器,而且还要指明
是否对驱动程序输入输出的数据进行缓冲,另外还要我们提供一个AddDevice例程
来把驱动程序添加到驱动程序堆栈中。其中,IRP_MJ_XXXXX为驱动程序所收到的系
统消息,RequestXXXXX为相应的消息处理函数。在客户端程序中,我们一般要采用
DeviceIoControl通过自定义的控制码与驱动程序通信(在VxD中大多也采用这种方
式)。看看驱动程序所收到的系统消息,我们不难发现当用户调用
DeviceIoControl时操作系统就会向驱动程序发出一条IRP_MJ_DEVICE_CONTROL消息
,以触发RequestControl消息处理函数。
NTSTATUS RequestControl(IN PDEVICE_OBJECT
DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
ULONG ControlCode;
ULONG InputLength,OutputLength;
NTSTATUS status;
IrpStack=IoGetCurrentIrpStackLocation(Irp);
//获取当前IRP所在的I/O堆栈
ControlCode=IrpStack- >Parameters.DeviceIoControl.
IoControlCode; //取得控制码
InputLength=IrpStack- >Parameters.DeviceIoControl.
InputBufferLength; //取输入缓冲区大小
OutputLength=IrpStack- >Parameters.DeviceIoControl.
OutputBufferLength;//取输出缓冲区大小
switch(ControlCode)
{
case HELLOWDM_IOCTL_HELLO: DbgPrint
("Hello from WDM.\n");//向调试器输出字符串
status=STATUS_SUCCESS; //置返回值
break;
default: status=STATUS_INVALID_DEVICE_REQUEST;
//输入的控制码不支持
}
return CompleteRequest(Irp, status, 0);
//调用CompleteRequest通知操作系统完成IRP操作
}
---- 在客户端方面,先调用Setupapi.dll中的 SetupDiGetClassDevs并用上面提
到的128位 GUID建立Ring-0与Ring-3接口:
HDEVINFO info=SetupDiGetClassDevs ((LPGUID)&GUID_HELLOWDM,NULL,
//GUID_HELLOWDM 是128位GUID NULL,DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
然后使用SetupDiEnumDeviceInterfaces 对所获得的接口进行枚举以获得接口数据
,接着连续两次调用SetupDiGetDeviceInterfaceDetail 获得接口详细信息,其中
包括调用CreateFil e所需的一个型为\\.\0000000000000004#
{3d93c5c0-0085-11d1-821e-0080c88327ab} 的字符串,最后调用方法和VxD的调用
大体相同这里就不赘述了。不过由于使用了 Setupapi.dll中的API所以还需要使用
SetupDiDestroyDeviceInfoList来释放所申请的资源。
---- 4.几点说明:
---- 由于WDM是跨平台和跨操作系统的的驱动程序模型,所以在编写时一定不要使
用汇编。另外,在编写时还应注意对IRP_MJ_PNP消息的响应以及其他系统消息的传
递,这里的传递是向其它在驱动程序堆栈中的驱动程序而不是向客户端程序,详细
的信息请参考本文所提供的例程。最后,由于笔者写此文章时Windows 2000尚未正
式发布,一切的编写工作都是在Windows 98上用98DDK与VC6.0完成的,并且用
Numega SoftIce 4.0调试通过。
--
I behold a island before
My dream there
So great, so encouraging,
※ 来源:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.0.112]
--
※ 转载:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.1.31]
[回到开始]
[上一篇][下一篇]
荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店