WDF模型驱动程序开发
WDF驱动程序开发
1. 引言
设备驱动程序是硬件设备连接到计算机系统的软件接口,任何设备都必须有相应的驱动程序才能在计算机系统上正常工作。设备驱动程序的优劣直接关系到整个系统的性能和稳定性,因此,设计和开发稳定高效的驱动程序具有重要意义。
WDF(Windows Driver Foundation)是微软提出的下一代全新的驱动程序模型,它是在WDM(windows Driver Model)的基础上发展而来的,支持面向对象、事件驱动的驱动程序开发,提供了比WDM更高层次抽象的高度灵活、可扩展、可诊断的驱动程序框架。WDF框架管理了大多数与操作系统相关的交互,实现了公共的驱动程序功能(如电源管理、PnP支持),隔离了设备驱动程序与操作系统内核,降低了驱动程序对内核的影响。
WDF提供了两个框架:KMDF(内核模式驱动程序框架)和UMDF(用户模式驱动程序框架)。本文只介绍KMDF的设计与实现。
2. WDF对象模型
KMDF框架支持面向对象、事件驱动的驱动程序模型。它定义了一系列的对象用来表示设备、驱动、中断等,每个对象有对应的属性、方法和事件。驱动程序利用这些方法创建对象、设置属性和响应事件。
框架定义的主要对象有:
WDFDRIVER对象,对应于WDM中的DRIVER_OBJECT。描述驱动在内存中的实例,包括加载的位置、有关的属性和所管理的设备。
WDFDEVICE对象,对应于WDM中的DEVICE_OBJECT。描述由驱动程序管理的单个设备实例,设备可以是命名的也可以是未命名的。用户模式程序可以通过设备接口或设备名称访问设备。WDFDEVICE对象具有丰富的属性,如pnp和电源管理相关的事件处理回调函数(callbacks)。
WDFREQUEST对象,对应于WDM中的IRP,表示一个I/O请求。
WDFQUEUE对象:每个WDFQUEUE对象和一个WDFDEVICE对象关联,描述一个特殊的I/O请求队列。它具有一系列的事件处理回调函数,当I/O请求进入队列时,框架将自动调用驱动程序中对应的callback。
WDFINTERRUPT对象:表示设备中断。驱动程序可以通过WDFINTERRUPT对象的中断使能和禁止事件处理callbacks使能或禁止设备中断;通过ISR和DPCforISR例程处理设备中断。
WDF的对象模型是层次化的模型。WDFDRIVER对象是根对象,其他对象都是它的子对象。对于大多数对象,驱动程序在创建他们的时候可以指定父对象,如果没有指定,则框架默认其父对象为WDFDRIVER对象。
WDF大大简化了WDM中的pnp和电源管理的开发。WDF框架为设备停止、设备删除、电源状态切换等pnp和电源管理事件提供了适合的缺省行为,驱动程序本身不再纠缠于复杂的pnp和电源管理事件处理。此外,WDF还集成了请求队列的支持,一个设备可以有多个请求队列,每个请求队列可以有一种模式。最简单的是 WdfIoQueueDispatchSerial模式,在这种模式下,请求队列将请求串行化后再处理;而WdfIoQueueDispatchParallel模式则自动在每个请求到来时调用相应的回调函数;最后WdfIoQueueDispatchManual模式允许驱动程序手工分发请求,类似于WDM的工作方式。
在WDM驱动程序中,I/O请求的取消是一个复杂难以理解的过程,开发人员必须有对内核深刻的理解才能正确处理I/O请求的取消。WDF框架支持内建的I/O请求取消处理,使得驱动程序处理取消I/O请求的工作大大简化。
3. WDF设备驱动程序的结构
与WDM驱动程序一样,WDF驱动程序得标准入口函数是DriverEntry。与WDM不同,WDF的DriverEntry只负责创建和初始化WDFDRIVER对象,告诉WDF框架处理增加新设备连接的回调函数。
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObj, PUNICODE_STRING RegistryPath)
{
NTSTATUS code;
WDF_DRIVER_CONFIG config;
WDFDRIVER hDriver;
// 初始化驱动配置结构,指定设备添加事件callback
WDF_DRIVER_CONFIG_INIT_NO_CONSTRAINTS(&config, MyEvtDeviceAdd);
// 创建WDFDRIVER对象
code = WdfDriverCreate(DriverObj,
RegistryPath,
WDF_NO_OBJECT_ATTRIBUTES,
&config, // 指向config结构的指针
NULL);
return(code);
}
每当有新设备连接到系统时,WDF框架自动调用EvtDeviceAdd设备添加callback。该回调函数初始化pnp和电源管理相关结构,设置相应的事件处理callbacks,然后创建WDFDEVICE对象和符号连接,初始化请求队列、中断处理等相关结构,设置相应的回调函数。
WDFSTATUS MyEvtDeviceAdd(WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit)
{
WDFSTATUS status = STATUS_SUCCESS;
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
WDF_OBJECT_ATTRIBUTES objAttributes;
WDFDEVICE device;
PMY_DEVICE_CONTEXT devContext;
WDF_IO_QUEUE_CONFIG ioCallbacks;
WDF_INTERRUPT_CONFIG interruptConfig;
// 初始化pnpPowerCallbacks ,设置与PnP和电源管理相关的事件回调函数
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
pnpPowerCallbacks.EvtDevicePrepareHardware = MyEvtPrepareHardware;
pnpPowerCallbacks.EvtDeviceReleaseHardware = MyEvtReleaseHardware;
pnpPowerCallbacks.EvtDeviceD0Entry= MyEvtDeviceD0Entry;
pnpPowerCallbacks.EvtDeviceD0Exit = MyEvtDeviceD0Exit;
WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, pnpPowerCallbacks);
// 创建设备对象,初始化相关的属性
WDF_OBJECT_ATTRIBUTES_INIT(&objAttributes);
WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&objAttributes,
MY_DEVICE_CONTEXT);
// 命名设备
status = WdfDeviceInitUpdateName(DeviceInit, L"\\device\\WDFDEMO");
if (!NT_SUCCESS(status)) return(status);
status = WdfDeviceCreate(&DeviceInit, &objAttributes, &device);
if ( !NT_SUCCESS(status)) return(status);
devContext = MyGetContextFromDevice(device);
devContext->WdfDevice = device;
// 创建符号连接
status = WdfDeviceCreateSymbolicLink(device, L"\\DosDevices\\WDFDEMO");
if (!NT_SUCCESS(status)) return(status);
// 创建和初始化请求队列
WDF_IO_QUEUE_CONFIG_INIT(&ioCallbacks, WdfIoQueueDispatchSerial,
WDF_NO_EVENT_CALLBACK, WDF_NO_EVENT_CALLBACK);
ioCallbacks.EvtIoDeviceControl = MyEvtDeviceControlIoctl;
status = WdfDeviceCreateDefaultQueue(device,&ioCallbacks,
WDF_NO_OBJECT_ATTRIBUTES,NULL);
if (!NT_SUCCESS(status)) return(status);
// 创建和初始化中断对象,MyIsr和MyDpc分别是中断服务例程和DPC例程
WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, FALSE, MyIsr, MyDpc);
interruptConfig.EvtInterruptEnable = MyEvtInterruptEnable;//中断使能
interruptConfig.EvtInterruptDisable = MyEvtInterruptDisable;//中断禁止
status = WdfInterruptCreate(device, &interruptConfig,&objAttributes,
&devContext->WdfInterrupt);
return(status);
}
WDF驱动程序下一步的工作就是编写各事件处理回调函数,当相应事件发生时,WDF框架会自动调用指定的回调函数进行处理。其中EvtDevicePrepareHardware回调函数在分配资源的时候被调用,框架将分配给设备的资源传递给回调函数,回调函数保存需要的资源,将共享内存映射到内核虚拟地址空间。与此对应的是EvtDeviceReleaseHardware回调函数,每当设备释放所占用的资源时,框架都将调用它。
EvtDeviceD0Entry 和 EvtDeviceD0Exit事件callbacks则分别在设备即将进入和离开D0电源状态时调用。EvtIoDeviceControl、EvtIoRead、EvtIoWrite等回调函数分别用来处理DeviceControl、Read、Write I/O请求。
当框架获得一个I/O请求时,它首先确定该请求应该放入哪个请求队列。如果驱动程序没有提供指定的队列,WDF框架默认将请求放入缺省请求队列会自动调用对应的回调函数。然后,框架寻找处理该请求的回调函数,如果驱动程序提供了相应的callback,则调用它处理请求。对于没有指定回调函数的I/O请求,WDF调用EvtIoStart回调函数处理。如果EvtIoStart callback也不存在,框架将返回STATUS_NOT_SUPPORTED。
设备中断的管理由EvtInterruptEnable callback、EvtInterruptDisable callback、中断服务例程(ISR)和DpcForISr例程实现。WDF框架在调用EvtDeviceD0Entry callback和注册ISR后,通过调用EvtInterruptEnable回调函数使能设备中断;而EvtInterruptDisable回调函数则在设备离开D0状态,EvtDeviceD0Exit callback调用前获得调用,完成禁止设备中断的工作。此外,中断服务例程和DpcForIsr例程具体完成中断服务的功能,与WDM驱动程序相似。
WDF模型驱动程序开发的更多相关文章
- 基于WDF的PCI/PCIe接口卡Windows驱动程序(1)-WDF概述及开发环境搭建
原文出处:http://www.cnblogs.com/jacklu/p/4619110.html 本科毕业设计是这方面的工作,所以想开几篇博客来介绍使用WDF开发PCI/PCIe接口卡的驱动程序方法 ...
- SCADESuite嵌入式软件基于模型的开发
SCADE Suite®产品是针对高安全性嵌入式软件的基于模型的开发环境 SCADE Suite是高安全性嵌入式软件的开发标准,其应用领域涵盖航空.国防.轨道交通.能源和重工业.专为最高等级的质量和安 ...
- inux 驱动程序开发中输入子系统总共能产生哪些事件类型(EV_KEY,EV_ABS,EV_REL)
inux 驱动程序开发中, 输入子系统总共能产生哪些事件类型?,以及分别是什么意思?详见如下: Linux中输入设备的事件类型有EV_SYN 0x00 同步事件EV_KEY 0x01 按键事件,如KE ...
- Windows驱动程序开发基础(四)驱动的编译调试和安装
Windows驱动程序开发基础,转载标明出处:http://blog.csdn.net/ikerpeng/article/details/38793995 以下说一下开发出来驱动程序以后怎样编译.一般 ...
- Linux驱动程序开发 - 设备控制接口
(2008-08-08 15:02:19) 转载▼ 标签: it linux kernel driver 分类: Linux 序言设备驱动程序的一个基本功能就是管理和控制设备,同时为用户应用程序提供管 ...
- Windows NT 驱动程序开发人员提示 -- 应注意避免的事项
下面是开发人员在使用 Windows NT 设备驱动程序时应当避免的事项列表: 1. 一定不要在没有标注 I/O 请求数据包 (IRP) 挂起 (IoMarkIrpPending) 的情况下通过调度 ...
- 基于 USB 传输的针式打印机驱动程序开发
1.引言 针式打印机曾经在相当长的一段时间占据打印机市场的主导地位,但是近年来由于喷墨.激光等非击打式打印机的冲击,针式打印机的市场份额逐年下降.即便如此,由于针式打印机在票据打印领域的不可取代性,同 ...
- 【DSP开发】【Linux开发】Linux下PCI设备驱动程序开发
PCI是一种广泛采用的总线标准,它提供了许多优于其它总线标准(如EISA)的新特性,目前已经成为计算机系统中应用最为广泛,并且最为通用的总线标准.Linux的内核能较好地支持PCI总线,本文以Inte ...
- Git 分支模型与开发规范
GitHub Flow & Git Flow 基于Git 的两种协作开发模式 01.分支模型 master:长期分支,一般用于管理对外发布版本,每个 commit 对一个 tag,也就是一个发 ...
随机推荐
- release下去除nslog宏
#ifdef __OPTIMIZE__ #define NSLog(...) #endif 加在pch文件里面
- P2661 信息传递 强连通分量
题目链接: http://www.luogu.org/problem/show?pid=2661 题解: 这题求最小的单向环. 可因为每个节点初度为1,所以所有的强联通分量都只能是单向环. 所以就是有 ...
- 数字式PID控制的应用总结
PID控制是一个二阶线性闭环控制器,通过调整比例.积分和微分三项参数,使得大多数的工业控制系统获得良好的闭环控制性能.PID控制优点:a. 技术成熟,b. 易被人们熟悉和掌握,c. 不需要建立数学模型 ...
- 20160725noip模拟赛“Paodekuai” alexandrali
T1: 我们可以用火柴棒来表示十进制下的0~9, 如图所示 现给定火柴数n, 问用这n根火柴能组成的最小数和最大数分别是多少. 所有火柴必须全部用完, 并且所有数字必须是正的且不含前缀零. [解题] ...
- TesserOCR训练
1.CMD命令行进入 图片目录.运行: tesseract.exe testcode.tif testcode batch.nochop makebox 注意:上面的 testcode 名称 必须保持 ...
- Linked List vs Array
Both Arrays and Linked List can be used to store linear data of similar types, but they both have so ...
- Project Euler 99:Largest exponential 最大的幂
Largest exponential Comparing two numbers written in index form like 211 and 37 is not difficult, as ...
- Project Euler 83:Path sum: four ways 路径和:4个方向
Path sum: four ways NOTE: This problem is a significantly more challenging version of Problem 81. In ...
- cv 论文(CNN相关)
最近发现很多以前看的论文都忘了,所以想写点东西来整理下之前的paper,paper主要是cv(computer vision)方向的. 第一篇:Gradient-based learning appl ...
- MIT算法导论——第五讲.Linear Time Sort
本栏目(Algorithms)下MIT算法导论专题是个人对网易公开课MIT算法导论的学习心得与笔记.所有内容均来自MIT公开课Introduction to Algorithms中Charles E. ...