WDM驱动程序的基本结构和实例-《Windows内核编程》

WDM驱动的基本结构分以下几部分进行阐述:

对于WDM驱动程序来说,一般都是基于分层的,即完成一个设备的操作,至少要由两个驱动设备共同完成。WDM驱动模型是建立在NT式驱动程序模型基础之上的。

 

1)物理设备对象和功能设备对象

物理设备对象(Physical Device Object,PDO)和功能设备对象(Function Device Object,FDO)的关系是“附加”与“被附加”的关系。

当PC插入某个设备时,PDO会自动创建。确切的说,是由总线驱动创建的。PDO不能单独操作设备,需要配合FDO一起使用。系统会提示检测到新设备,要求安装驱动程序。需要安装的驱动程序就是WDM程序,此驱动程序负责创建FDO,并且附加到PDO上。

当一个FDO附加到PDO上时,PDO设备对象的子域AttachedDevice会记录FDO的位置。PDO被称作底层驱动或下层驱动,而FDO被称作高层驱动或上层驱动。

复杂一点的情况是,在FDO和PDO之间还会存在过滤驱动。在FDO上面的过滤驱动被称作上层过滤驱动,在FDO下层的驱动被称作下层过滤驱动。每个设备对象中,有个StackSize子域,表明操作这个设备对象需要几层才能到达最下层的物理设备。

过滤驱动可以嵌套,即可以有很多个高层过滤驱动或多个底层过滤驱动。过滤驱动不是必须的,在WDM模型中PDO和FDO是必须的。

 

NT设备是被动装入的,例如当有设备插入PC时,系统不会有提示,用户需要自己指定加载何种驱动;而WDM驱动则不然,当插入设备时,系统会自动创建出PDO,并提示请求用户安装FDO。

 

2)WDM驱动的入口程序

和NT驱动一样也是DriverEntry,但是初始化作用被分散到其他例程中。如创建设备对象的工作被放在了AddService例程中,同时,在DriverEntry中,需要设置对IRP_MJ_PNP处理的派遣函数。

WDM驱动的DriverEntry和NT式驱动的DriverEntry有以下几点不同:

(1)增加了对AddService函数的设置;AddService例程负责创建FDO,并附加到PDO上。

(2)创建设备对象的操作不在这个函数中了,而转到了AddService例程中。

(3)必须加入IRP_MJ_PNP的派遣回调函数。IRP_MJ_PNP主要是负责计算机中即插即用的处理。

 

3)WDM驱动的AddService例程

AddService例程是WDM独有的。在DriverEntry中需设置AddService例程的函数地址,设置的方式是驱动对象中有个DriverExtension子域,DriverExtension中有个AddService子域,将该子域指向AddService例程的函数地址即可。

和DriverEntry不同,AddService例程的名字可以任意命名:

DRIVER_ADD_DEVICE AddDevice;

 

NTSTATUS AddDevice(

__in  struct _DRIVER_OBJECT *DriverObject, //驱动对象(I/O管理器创建的)

__in  struct _DEVICE_OBJECT *PhysicalDeviceObject //设备对象(底层总线驱动创建的PDO设备对象)

//传入该参数的目的是将FDO附加在PDO上

)

{ ... }

AddService函数的功能可分为:

(1)通过IoCreateDevice等函数,创建设备对象,该设备对象就是FDO。

(2)创建FDO后,需要将FDO的地址保存下来,保存的位置是在设备扩展中。

(3)驱动程序将创建的FDO附加到PDO上,附加这个动作是利用函数IoAttachDeviceToDeviceStack实现的:

PDEVICE_OBJECT IoAttachDeviceToDeviceStack(

__in  PDEVICE_OBJECT SourceDevice, //要附加到其他设备上的设备,

//将FDO附加在PDO之上时,此处即填FDO的地址

__in  PDEVICE_OBJECT TargetDevice //被附加的设备,将FDO直接附加在PDO上时

//(不考虑过滤驱动),此处即时PDO的地址

);

返回值:附加后,返回附加设备的下层设备。如果中间没有过滤驱动,返回值就是PDO;如果中间有过滤驱动,返回的是过滤驱动。

当FDO附加到PDO上时,PDO会通过AttachedDevice子域知道它上层的设备是FDO(或过滤驱动);而FDO无法知道下层是什么设备,因此,需要通过设备扩展设置FDO下层的设备,例如:

//设备扩展结构体

typedefstruct _DEVICE_EXTENSION

{

PDEVICE_OBJECT fdo; //功能设备对象FDO

PDEVICE_OBJECT NextStackDevice; //FDO的下层驱动设备

UNICODE_STRING ustrDeviceName; //设备名

UNICODE_STRING ustrSymLinkName; //符号链接

}DEVICE_EXTENSION, *PDEVICE_EXTENSION;

一般根据自己的需要定制自己的设备扩展。子域fdo是为了保存FDO的地址以备后用;子域NextStackDevice是为了定位设备的下一层设备。在附加操作完成后,需要设定符号链接,以便用户应用程序访问该设备。

 

4)DriverUnload例程

在NT式驱动中,DriverUnload例程主要负责做删除设备和取消符号链接。而在WDM驱动中,这部分操作被IRP_MN_REMOVE_DEVICE的处理函数所负责。因此,如果在DriverEntry中有申请内存的操作,可以在DriverUnload例程中回收这些内存,DriverUnload例程变得相对简单了。

 

5)对IRP_MN_REMOVE_DEVICE IRP的处理

驱动程序内部是由IRP驱动的。创建IRP的原因很多,IRP_MN_REMOVE_DEVICE这个IRP是当设备被卸载时,由即插即用管理器创建,并发送到驱动程序中的。IRP一般由两个号码指定该IRP的具体意义:一是主IRP号(Major IRP);一是辅IRP号(Minor IRP)。

每个IRP都由对应的派遣函数所处理,派遣函数是在DriverEntry中指定的。

在WDM驱动程序中,对设备的卸载一般是在对IRP_MN_REMOVE_DEVICE的处理函数中进行的。除了需要删除设备,取消符号链接外,在卸载函数中还需要将FDO从PDO上的堆栈中移除掉,使用函数IoDetachDevice:

VOID IoDetachDevice(

__inout  PDEVICE_OBJECT TargetDevice //下层堆栈上的设备对象

);

调用此函数后,可将FDO从设备链上删除,但PDO还是存在的,PDO的删除是由操作系统负责的。

 

目前开发WDM 驱动程序的方法有三种:

 

①使用 Microsoft 的 Windows DDK/WDK 工具开发。

②使用 KRFTech 公司的 WinDriver 。

③使用 NuMega 公司的 DriverStudio 。

版权声明:
作者:驱动外包
链接:http://www.51qudong.net/89.html
来源:算法优化_驱动外包_直播算法优化_MAC驱动开发_Linux驱动开发_usb驱动移植外包
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>