全部博文(2005)
分类:
2007-05-17 15:12:27
WDM 引入设备对象的概念来描述一个设备,主要包括物理设备对象(PDO)、功能设备对象(FDO)和过滤设备对象(FIDO)。其中,PDO 对应实际的物理设备,FDO 和filter DO时相应驱动程序的处理对象。一个物理设备有且只能有一个PDO 和一个FDO,但却可以有多个filter DO。WDM 驱动程序直接操作的不是硬件本身,而是相应的PDO、FDO 和filter DO。当用户发出请求时,操作系统会将其打包形成一个IRP结构,并把它发送至驱动程序,通过识别IRP 中的设备对象来区分它是发送给哪个设备的。WDM 驱动采用分层驱动的方法,即在用户应用程序和硬件设备之间存在着几个不同的驱动程序,每个驱动程序对应一层,且不同层上的驱动程序可以相互调用。下面详细讲解驱动程序种类:为适用于即插即用系统,WDM 新定义了驱动程序的分层结构,其主要包括如下3 中类型的驱动程序。
(1)总线驱动程序:负责驱动I/O总线,处理总线上的全部事务,控制对其总线上所有设备的访问。计算机上每种类型的总线都需要有一个总线驱动程序,它是必不可少的。如果每台计算机上包含有多个同种类型总线,则其只需一个总线驱动程序就可以同时驱动它们。
(2)功能驱动程序:用于驱动一个单独的设备,控制并实现该设备的主要功能,它是设备的主要驱动程序,也是必不可少的。对于一个设备,PnP管理器最多只能为其加载一个功能驱动程序,但一个功能驱动程序可以同时服务于多个设备。
(3)过滤驱动程序:用于过滤发向设备、设备类或总线的I/O请求。它是可选的,即一个设备可以拥有零个或多个过滤驱动程序。一个过滤驱动程序可以同时服务于多个设备对象,其又可被进一步划分为总线过滤驱动程序、上层过滤驱动程序和下层过滤驱动程序。一个设备通常需要使用一个总线驱动程序、一个功能驱动程序、零个或多个过滤驱动程序。它们有的由操作系统提供,有的需要由开发人员自行编写,这根据具体设备的不同而不同。WDM 驱动程序是系统内核模式的驱动程序,它可以执行任何有效的CPU指令,尤其是I/O操作。内核模式的其他组件通过发送I/O请求的方式运行WDM 驱动程序中的代码,这些I/O 请求负责指明驱动程序应完成的具体操作。
WDM 驱动程序组成:简单地说,驱动程序是一些例程地集合,它们被动地存在,等待主机系统软件(PnP管理器、I/O管理器、电源管理器等)来调用或激活它们。具体驱动程序不同,其所包含的例程也不同,一个WDM驱动程序至少包括5 个例程:
(1)驱动程序入口例程:处理驱动程序的初始化。
(2)即插即用例程:处理PnP 设备的添加、删除和停止。
(3)分发例程:处理用户应用程序发出的各种I/O 请求。
(4)电源管理例程:处理电源管理请求。
(5)卸载例程:处理驱动程序的卸载。
1.驱动程序入口例程
DriverEntry 例程是驱动程序的入口点,由I/O管理器在驱动程序加载时调用。它负责执行一些初始化操作,主要工作是设置驱动对象(DriverObject)中指向各种例程的指针。在其驱动程序中必须包含这些例程的具体函数实现,以便主机系统软件的调用。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { NTSTATUS ntStatus = STATUS_SUCCESS; DriverObject->DriverExtension->AddDevice = TestAddDevice; DriverObject->MajorFunction[IRP_MJ_PNP] = TestPnpIrp; DriverObject->MajorFunction[IRP_MJ_POWER] = TestPowerIrp; DriverObject->MajorFunction[IRP_MJ_CREATE] = TestCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = TestClose; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TestIOCTL; DriverObject->DriverUnload = TestDrvUnload; return ntStatus; } |
DriverEntry 为驱动程序的入口函数,它向操作系统注册“事件处理函数”
DriverObject->DriverExtension->AddDevice = TestAddDevice;
TestAddDevice为即插即用例程主要做如下工作:
实现设备对象的创建
//创建设备对象 ntStatus = IoCreateDevice (DriverObject,sizeof (DEVICE_EXTENSION), &KernelDeviceNameUnicode,FILE_DEVICE_UNKNOWN,0,FALSE,&fdo); |
实现符号链接名'Glx-gliet-
//创建符号链接名 ntStatus = IoCreateSymbolicLink (&UserDeviceLinkUnicode, &KernelDeviceNameUnicode); |
DEVICE_EXTENSION 设备扩展初始化
//将符号链接名拷贝到自定义数据结构中-设备扩展中 RtlCopyMemory(pdx->DeviceLinkName,UserDeviceLinkBuffer, sizeof(UserDeviceLinkBuffer)); pdx->OpenHandles = 0; pdx->ConfigurationHandle = NULL; pdx->DeviceDescriptor = NULL; pdx->Interface = NULL; //设置读写请求使用直接I/O fdo->Flags &= ~DO_DEVICE_INITIALIZING; fdo->Flags |= DO_DIRECT_IO; //将物理设备对象保存到设备扩展中 pdx->PhysicalDeviceObject=PhysicalDeviceObject; |
挂接到设备栈
//把设备对象连接到设备栈 pdx->LowerDeviceObject =IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject); |
初始化事件
//初始化一个内核事件 KeInitializeEvent(&pdx->evRemove,NotificationEvent,FALSE); |
DriverObject->MajorFunction[IRP_MJ_PNP] = TestPnpIrp;
TestPnpIrp 为即插即用例程主要做如下工作:
//完成大部分初始化工作 MinorFunction = IrpStack->MinorFunction; switch (MinorFunction) { case IRP_MN_START_DEVICE: //进行资源分配 ntStatus = PnpHandleStartDevice(fdo,Irp); break; case IRP_MN_STOP_DEVICE: //首先向下传递该IRP PnpHandleDefault(fdo,Irp); ntStatus = PnpHandleStopDevice(fdo); break; case IRP_MN_REMOVE_DEVICE: //删除设备 ntStatus = PnpHandleRemoveDevice(fdo,Irp); break; default: //向下传递所有其他PnP IRP ntStatus = PnpHandleDefault(fdo, Irp); } |