WDM(Windows Driver Model),即Windows驱动程序模型,是Microsoft力推的全新驱动程序模式,旨在通过一种灵活的方式来简化驱动程序的开发,实现对硬件的支持,并减少和降低所有所须开发的驱动程序的数量和复杂性。
在WDM驱动程序模型中主要包括两个驱动程序:功能驱动程序和总线驱动程序。由于总线驱动程序已经由操作系统提供,因此,关心的主要是功能驱动程序。一个完整的功能驱动程序包括许多例程:基本驱动程序例程:DriverEntry和AddDevice。I/O控制例程:StartIO、AdapterControl、OnInterrupt……派遣函数:DispatchPnP、DispatchPower、DispatchRead、DispatchWrite……当操作系统遇到一个I/O请求包(IRP)时,系统调用驱动程序中的例程来执行相应的操作。在这些例程中,DriverEntry例程和AddDevice例程对每个驱动程序都是必须的,当然还需要其他一些I/O控制例程和派遣函数。其中StartIO例程用于对IRP进行排队,AdapterControl例程用于执行DMA操作的驱动程序中,OnInterrupt例程为中断服务例程。
I/O请求包(IRP)主要由MajorFunction和MinorFunction字段构成,当然还可以包括Struct Read和Struct Write等控制参数。MajorFunction字段是IRP的主要功能代码,MinorFunction字段是IRP的次要功能代码,它们指明了驱动程序应该执行的具体操作。
常用的IRP主功能代码:IRP_MJ_CREATE 打开文件句柄
IRP_MJ_CLOSE 关闭文件句柄
IRP_MJ_READ 读取数据
IRP_MJ_WRITE 写数据
IRP_MJ_CLEANUP 清除挂起的IRP
IRP_MJ_DEVICE_CONTROL设备I/O控制
IRP_MJ_INTERNAL_DEVICE_CONTROL底层的设备I/O控制
IRP_MJ_SYSTEM_CONTROL系统管理与测试
IRP_MJ_POWER 电源管理
IRP_MJ_PNP 即插即用管理
WDM驱动程序的功能实现主要由特定的例程决定。在不同的情况下,操作系统或主机程序触发相应的例程,实现不同的操作。一个典型的WDM驱动程序由以下部分构成:
入口例程DriverEntry:主要用于WDM驱动程序的初始化,是所有驱动程序必须的。
即插即用例程:用户处理即插即用设备的添加、停止和删除等。
分发例程:用于处理主机程序的各种I/O请求。
电源管理例程:用于处理系统和设备的电源管理请求。
卸载例程:处理WDM驱动程序的卸载等操作。
驱动程序入口例程,即DruverEntry例程,是所有驱动程序的入口。DriverEntry例程由操作系统的I/O管理器在设备驱动功能加载的时候进行调用,主要负责WDM驱动程序的初始化。
即插即用例程,当设备连接到计算机上的时候,操作系统自动识别,自动选择并加载合适的驱动程序。当设备从系统中移除的时候,自动处理相应的清除工作。在设备连接和断开的时候,整个过程不需要用户的干预。其例程主要有两个:一个AddDevice例程和一个IRP_MJ_PNP例程。AddDevice 例程主要使用IoCreateDevice函数来创建和初始化一个设备对象,然后初始化设备扩展,并使用IoAttachDeviceToDeviceStack函数将设备连接到设备栈。IRP_MJ_PNP例程主要负责处理系统即插即用管理器发出的PnP信息,包括启动设备(IRP_MN_START_DEVICE)、停止设备(IRP_MN_STOP_DEVICE)、删除设备(IRP_MN_REMOVE_DEVICE)等。
分发例程,用于处理各种I/O请求,这是主机程序控制硬件的接口。每个分发例程对应一个Win32函数,主机程序便是通过Win32函数来和相应的分发例程通信的。常用的分发例程如下所示。
IRP_MJ_CREATE例程,对应的Win32函数为CreateFile。
IRP_MJ_CLOSE例程,对应的Win32函数为CloseHandle。
IRP_MJ_READ例程,对应的Win32函数为ReadFile。
IRP_MJ_WRITE例程,对应的Win32函数为WriteFile。
IRP_MJ_DEVICE_CONTROL例程,对应的Win32函数为DeviceIoControl。
一般来说,并不是所有的分发例程都是必须的,但是所有的驱动程序都要包含IRP_MJ_CREATE例程和IRP_MJ_CLOSE例程。如果没有这两个例程,主机程序便不能获得设备句柄,也就不能控制设备。
电源管理例程,用于管理设备或系统的电源状态,其有四个次功能代码:
IRP_MN_SET_POWER设置系统或设备电源状态。
IRP_MN_QUERY_POWER查询是否允许改变系统或设备的电源状态。
IRP_MN_WAIT_WAKE响应外部事件以唤醒设备。
IRP_MN_POWER_SEQUENCE确认设备是否进入指定的电源状态。
卸载例程,只在需要卸载驱动程序的时候调用,一般来说,驱动程序的卸载例程需要完成如下几个方面的工作:保存设备的状态,以便于设备恢复到最近保存的设备状态。释放该驱动程序所占用的内存空间。删除设备对象及其符号链接名或GUID描述符。通常情况下,卸载例程可以什么也不做,因为其主要的工作都在处理例程IRP_MN_REMOVE_DEVICE中完成。