如何写驱动程序
C语言设备驱动编程入门

C语言设备驱动编程入门C语言设备驱动编程是一项常见的技术,用于编写操作系统的设备驱动程序。
设备驱动程序是操作系统与硬件设备之间的桥梁,它负责将用户操作转化为硬件设备能够理解和执行的指令。
本文将介绍C语言设备驱动编程的基本概念和入门知识,帮助读者了解并入门这一重要的编程技术。
一、设备驱动程序概述设备驱动程序是操作系统的一部分,它与操作系统内核紧密结合,用于实现对硬件设备的控制和管理。
设备驱动程序通常由硬件设备制造商提供,或者由操作系统开发者开发。
它负责处理硬件设备与操作系统之间的通信,使得用户能够方便地操作硬件设备。
设备驱动程序可以分为字符设备驱动和块设备驱动两种类型。
字符设备驱动用于处理流式数据的设备,如键盘、鼠标等;块设备驱动用于处理以块为单位的数据的设备,如硬盘、U盘等。
不同类型的设备驱动程序在实现上有所不同,但都需要用C语言编写。
二、设备驱动程序的基本结构设备驱动程序的基本结构包括设备初始化、设备打开、设备关闭和设备读写等函数。
下面我们逐步介绍这些函数的作用和实现方法。
1. 设备初始化函数设备初始化函数负责对设备进行初始化,包括设备的寄存器配置、中断设置等。
在这个函数中,我们需要了解硬件设备的相关规格和特性,并根据需要进行适当的配置。
2. 设备打开函数设备打开函数在设备被用户程序打开时被调用,它负责向操作系统申请资源,并进行相应的设置,例如打开文件、分配内存等。
3. 设备关闭函数设备关闭函数在设备被用户程序关闭时被调用,它负责释放设备所占用的资源,如释放文件占用的内存、关闭文件等。
4. 设备读写函数设备读写函数是设备驱动程序的核心部分,它负责设备与用户程序之间的数据交换。
设备读函数用于从设备中读取数据,设备写函数用于向设备中写入数据。
三、设备驱动程序的编写步骤编写设备驱动程序需要经过以下几个步骤:1. 了解硬件设备在编写设备驱动程序之前,我们需要详细了解硬件设备的规格和特性,包括硬件寄存器的地址、中断向量等。
常见打印驱动程序的编写方法

常见打印驱动程序的编写方法打印驱动程序是连接计算机和打印机之间的重要组件,它们负责管理和控制打印机的功能。
本文将介绍几种常见的打印驱动程序的编写方法。
一、GDI驱动程序GDI(图形设备接口)是Windows操作系统中用于处理图形和打印输出的API集合。
GDI驱动程序使用GDI在屏幕上绘制位图,并将其发送到打印机进行打印。
GDI驱动程序的优点是开发简单、成本低,适用于一般的打印任务。
其编写方法如下:1.使用GDI函数绘制位图:GDI提供了一系列函数用于绘制和处理图形,如创建设备上下文、选择画笔和画刷等。
2. 将位图数据发送到打印机:通过GDI函数将绘制好的位图数据发送到打印机进行打印,如使用Escape函数发送打印命令。
3.错误处理和状态更新:在使用GDI函数时,需要处理可能出现的错误,如打印机未连接、纸张用尽等。
同时,根据打印机的状态更新用户界面。
二、PCL驱动程序PCL(页面描述语言)是惠普公司开发的一种打印机控制语言,广泛应用于激光打印机。
PCL驱动程序将应用程序生成的页面描述语言转换为打印机可以理解的命令,实现页面的打印。
其编写方法如下:1. 解析页面描述语言:将应用程序生成的页面描述语言(如PCL、PostScript)解析成可理解的数据结构,如页面对象、文本对象等。
2.生成打印命令:根据解析后的数据结构,生成适用于目标打印机的打印命令序列,如选择字体、设置颜色等。
3.发送打印命令:将生成的打印命令序列发送到打印机,实现页面的打印。
三、XPS驱动程序XPS(XML Paper Specification)是微软开发的一种页面描述语言,用于描述和打印电子文档,如PDF。
XPS驱动程序将应用程序生成的XPS文档转换为打印机可以处理的命令,实现文档的打印。
其编写方法如下:1.解析XPS文档:将XPS文档解析成可理解的数据结构,如页面对象、图像对象等。
2.生成打印命令:根据解析后的数据结构,生成适用于目标打印机的打印命令序列,如选择页面大小、设置打印质量等。
Windows982000驱动程序编写方法

微计算机系统
微计算机系统 void doWrite(int n) // 向驱动程序中写数据 { char *buf; ULONG nWritten; int i, j; buf = (char *) malloc(n); if (buf == NULL) { printf("Failed to allocate buffer for write"); Exit(1); } // start with the mod26 letter of the number of bytes to write j = (n % 26); // load buffer with dummy data (abcdefg...) for (i=0; i<n; i++, j=(j + 1)%26) { buf[i] = 'a' + j; } 42
微计算机系统
驱动程序装载 器,可动态调 用驱动程序
28
微计算机系统
驱动程序监视器界面
29
微计算机系统
驱动程序装载器界面
30
微计算机系统
31
微计算机系统
32
微计算机系统
33
微计算机系统
34
微计算机系统
35
微计算机系统
36
2)完成应用程序和驱动程序之间的信息交换
微计算机系统
下面我们来修改有关代码,以便增加驱动程序和应 用程序之间相互通信的内容。需要增加的内容包括: a. 使用Read和Write方式分别从驱动程序读入字符和 向驱动程序写字符。 b. 使用IO控制代码方式分别从驱动程序读入字符和 向驱动程序写字符。 c. 使用IO控制代码方式向驱动程序写字符串再从驱动 程序中读出该字符串,并返回反馈串信息。 注意:程序中暗红色显示的部分是我们添加或修改 过的语句,其他是DriverWorks自动生成的。语句中 “t<< xxxxx”这样的语句是向调试软件输出信息,该 信息可以再DriverMonitor或其他调试监视器中看到。
c语言打印机驱动编写教程

c语言打印机驱动编写教程C语言打印机驱动编写教程一、引言打印机是计算机外部设备中常用的输出设备之一,而编写打印机驱动程序则是实现计算机与打印机之间通信的关键。
本文将介绍如何使用C语言编写打印机驱动程序,以便正确地控制打印机的功能和输出。
二、了解打印机驱动程序的基本原理打印机驱动程序是连接计算机和打印机的桥梁,它负责将计算机发送的打印任务转化为打印机可以理解的指令,使其能够正确地输出打印结果。
通常,打印机驱动程序需要实现以下功能:1.与打印机建立通信连接;2.发送打印任务给打印机;3.控制打印机的各项功能,如纸张大小、打印质量等;4.处理打印机返回的状态信息。
三、编写打印机驱动程序的基本步骤1.了解打印机的通信协议不同品牌、型号的打印机通常采用不同的通信协议,因此首先需要了解目标打印机的通信协议,包括指令集和参数设置等。
可以通过查阅打印机的技术文档或者与厂家进行沟通来获取这些信息。
2.建立与打印机的通信连接在C语言中,可以使用串口或者USB等接口与打印机建立通信连接。
根据打印机的通信协议,编写相应的代码来实现与打印机的通信。
3.发送打印任务给打印机通过编写相应的代码,将需要打印的文档内容发送给打印机。
可以先将文档内容转化为打印机可以理解的格式,再发送给打印机。
常见的文档格式包括PDF、Word、Excel等。
4.控制打印机的各项功能根据打印机的功能和参数设置,编写相应的代码来控制打印机的各项功能,如选择纸张大小、设置打印质量等。
需要注意的是,不同型号的打印机可能支持的功能和参数设置有所不同,需要根据实际情况进行调整。
5.处理打印机返回的状态信息打印机通常会返回一些状态信息,如打印进度、错误提示等。
编写相应的代码来处理这些状态信息,以便及时反馈给用户或者进行错误处理。
四、编写示例代码下面是一个简单的示例代码,用于演示如何使用C语言编写打印机驱动程序:```#include <stdio.h>int main() {// 建立与打印机的通信连接// ...// 发送打印任务给打印机// ...// 控制打印机的各项功能// ...// 处理打印机返回的状态信息// ...return 0;}```五、总结本文简要介绍了如何使用C语言编写打印机驱动程序的基本步骤。
一、如何编写LinuxPCI驱动程序

⼀、如何编写LinuxPCI驱动程序PCI的世界是⼴阔的,充满了(⼤部分令⼈不快的)惊喜。
由于每个CPU体系结构实现不同的芯⽚集,并且PCI设备有不同的需求(“特性”),因此Linux内核中的PCI⽀持并不像⼈们希望的那么简单。
这篇简短的⽂章介绍⽤于PCI设备驱动程序的Linux APIs。
1.1 PCI驱动程序结构PCI驱动程序通过pci_register_driver()在系统中"发现"PCI设备。
事实上,恰恰相反。
当PCI通⽤代码发现⼀个新设备时,具有匹配“描述”的驱动程序将被通知。
详情如下。
pci_register_driver()将设备的⼤部分探测留给PCI层,并⽀持在线插⼊/删除设备[因此在单个驱动程序中⽀持热插拔PCI、CardBus和Express-Card]。
pci_register_driver()调⽤需要传⼊⼀个函数指针表,从⽽指⽰驱动程序的更⾼⼀级结构体。
⼀旦驱动程序知道了⼀个PCI设备并获得了所有权,驱动程序通常需要执⾏以下初始化:启⽤设备请求MMIO / IOP资源设置DMA掩码⼤⼩(⽤于⼀致性DMA和流式DMA)分配和初始化共享控制数据(pci_allocate_coherent())访问设备配置空间(如果需要)注册IRQ处理程序(request_irq())初始化non-PCI(即LAN/SCSI/等芯⽚部分)启⽤DMA /处理引擎当使⽤设备完成时,可能需要卸载模块,驱动程序需要采取以下步骤:禁⽌设备产⽣irq释放IRQ (free_irq())停⽌所有DMA活动释放DMA缓冲区(包括流式DMA和⼀致性DMA)从其他⼦系统注销(例如scsi或netdev)释放MMIO / IOP资源禁⽤该设备下⾯⼏节将介绍这些主题中的⼤部分。
其余部分请查看LDD3或<linux/pci.h>。
如果PCI⼦系统没有配置(没有设置CONFIG_PCI),下⾯描述的⼤多数PCI函数都被定义为内联函数,要么完全空,要么只是返回⼀个适当的错误代码,以避免在驱动程序中出现⼤量ifdefs。
VC编写驱动方法

VC编写驱动方法编写VC驱动方法在VC开发中,驱动方法是一种非常重要的处理方式。
它可以帮助程序员更好地管理代码,增加代码的可读性以及可维护性。
下面将介绍一些常用的VC驱动方法。
1.初始化方法初始化方法是驱动程序启动时最先调用的方法,在这个方法中可以进行一些初始化操作,比如初始化一些全局变量、分配内存等。
在VC中,一般使用WinMain函数或者OnInitDialog方法来实现初始化。
2.事件处理方法事件处理方法是用来处理操作系统或者用户输入的事件的方法,比如鼠标点击事件、键盘按键事件等。
在VC中,可以通过添加事件响应函数来实现事件处理方法。
在这些方法中,可以根据事件的类型和参数来做出不同的反应。
3.获取数据方法获取数据方法是用来从外部或者数据库中获取数据的方法,比如从文件中读取配置信息、从网络中获取数据等。
这些方法可以根据需要进行适当的封装,例如提供参数来指定从哪个文件中读取配置信息,或者提供一个回调函数来处理网络数据。
4.更新数据方法更新数据方法是用来向外部或者数据库中写入数据的方法,比如向文件中写入日志信息、向数据库中插入新的记录等。
这些方法可以根据需要进行适当的封装,例如提供参数来指定要写入的文件或者数据库的位置,或者提供一个回调函数来处理写入的结果。
5.计算方法计算方法是用来进行一些数学或者逻辑计算的方法,比如计算两个数的和、判断一个数是否为质数等。
在VC中,可以将这些方法放在一个单独的类或者模块中,方便调用。
另外,为了增加代码的可读性,可以添加注释来说明计算的过程和结果。
6.绘制方法绘制方法是用来在屏幕上绘制图形或者文本的方法,比如绘制一个按钮、一个文本框等。
在VC中,可以通过使用GDI+库来实现绘制方法。
在这些方法中,可以使用各种图形和绘制函数来实现特定的绘制效果。
7.保存方法保存方法是用来将程序状态或者数据保存到磁盘或者其他设备中的方法,比如保存程序的配置信息、保存用户输入的数据等。
Windows下设备驱动程序的开发方法

目录一、驱动开发环境的搭建 (1)1.1 关于DDK (1)1.2 关于驱动程序的编译 (1)1.3关于驱动程序的运行 (2)二、驱动程序的结构 (3)2.1 驱动程序的头文件 (3)2.2 驱动程序的入口点 (3)2.3 创建设备例程 (4)2.4 卸载驱动例程 (5)2.5 派遣例程 (6)三、编写驱动程序的基础知识 (6)3.1 内核模式下的字符串操作 (6)3.2 内核模式下各种开头函数的区别 (8)3.3 一个示例程序 (10)3.4 补充说明 (10)四、在驱动中使用链表 (10)4.1 内存的分配与释放 (10)4.2 使用LIST_ENTRY (12)4.3 使用自旋锁 (12)五、在驱动中读写文件 (15)5.1 使用OBJECT_ATTRIBUTES (15)5.2 创建、打开文件 (16)5.3 读写文件操作 (16)5.4 文件的其它相关操作 (18)六、在驱动中操作注册表 (18)6.1 创建、打开注册表 (19)6.2 读写注册表 (20)6.3 枚举注册表 (21)七、在驱动中获取系统时间 (21)7.1 获取启动毫秒数 (21)7.2 获取系统时间 (22)八、在驱动中创建内核线程 (23)8.1 创建内核线程 (23)8.2 关于线程同步 (24)九、初探IRP (25)9.1 IRP的概念 (25)9.2 IRP的处理 (26)9.3 IRP派遣例程示例 (27)十、驱动程序与应用层的通信 (29)10.1 使用WriteFile通信 (29)10.2 使用DeviceIoControl进行通信 (32)十二、驱动程序开发实例 (33)12.1 NT驱动程序 (33)12.2 WDM驱动程序 (35)十三、参考资料 (41)一、驱动开发环境的搭建1.1 关于DDK开发驱动程序必备的一个东西就是DDK(Device Development Kit,设备驱动开发包),它跟我们在ring3常听到的SDK差不多,只不过它们分别支持开发不同的程序而已。
c语言驱动代码怎么写代码驱动电脑的基本步骤

c语言驱动代码怎么写代码驱动电脑的基本步骤C语言驱动代码:如何编写代码驱动电脑的基本步骤在计算机科学中,驱动程序是指用于控制硬件设备的程序,它充当了计算机操作系统与硬件之间的桥梁。
C语言是一种功能强大的编程语言,用于编写高效的驱动程序。
本文将介绍编写C语言驱动代码的基本步骤。
1. 确定驱动目标在编写驱动程序之前,需要明确驱动的目标是什么。
驱动可以是针对不同硬件设备的,如打印机、鼠标等。
在本文中,我们将以一个简单的案例来说明,即键盘驱动程序。
这个驱动程序将使计算机能够识别和响应键盘输入。
2. 学习设备相关文档在编写驱动程序之前,需要详细了解被驱动设备的特点和功能。
这通常通过查阅设备的技术文档或供应商提供的开发者文档来实现。
对于键盘驱动程序,需要查阅键盘的通信协议和按键编码等信息。
3. 编写初始化代码初始化代码用于准备驱动程序与设备之间的通信。
键盘驱动程序通常需要打开设备的接口,并设置设备的初始状态,以便能够接收按键输入。
这可能涉及到与设备进行握手的通信过程。
4. 编写中断处理程序键盘驱动程序需要能够实时响应用户的按键操作。
为了实现这一点,中断处理程序被用来处理从键盘设备发出的中断信号。
中断处理程序负责解析按键事件,并根据用户的输入进行相应的操作。
例如,当用户按下某个键时,中断处理程序可以将该按键的字符发送给操作系统或其他应用程序。
5. 实现设备控制功能驱动程序还可以提供一些额外的设备控制功能,以便于用户与设备进行交互。
例如,在键盘驱动程序中,可以实现控制LED灯的功能,通过向设备发送控制指令,来控制键盘上的灯光。
6. 进行测试和调试编写完驱动程序后,需要进行测试和调试,以确保其能够正常工作。
这可以通过连接设备并运行相应的应用程序来完成。
在测试过程中,需要验证驱动程序是否能够正确地解析键盘输入,并对其做出正确的响应。
在编写C语言驱动代码时,还有一些编码规范和最佳实践需要遵循。
例如,应避免使用与已有库函数或全局变量相同的命名,以防止命名冲突。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
我这里重点的介绍如何写驱动程序,对于一些应用程序我就不做介绍了,因为我对于那些高层的东西写得很少。
倘若再讲,有班门弄斧之嫌,呵呵!作为WIN98和WIN2K推荐的一项新技术来说,USB的驱动程序和以往的直接跟硬件打交道的WIN95的VXD的方式的驱动程序不同,它应该是WDM类型的。
USB的WDM接口框图如下(这个图可以说是USB软件总体框图)对于HID的设备,就可以采用上图左上边的结构,其它类的话采用右上的结构,其实右边的结构可以又细分成两层,一层是Class Driver,一层是Miniport Driver。
而倒数第三行的UHCD和OpenHCI分别是由INTEL和COMPAQ两位老大定的一个和硬件有关的底层驱动程序标准,各位可以根据所需要的选择。
对于USB的驱动程序,大家还得去了解WDM驱动程序的写法,或者早些时候的NT驱动程序,其实WDM驱动程序可以看做是NT驱动程序的一个update,只是增加了一些新的特性。
“写驱动程序是一个很漫长和繁琐的工作,在此之前,你最好要熟悉硬件,熟悉C/C++,还要用过DDK,会用一些调试程序,如SOFTICE和WINDBG之类。
如果一切就绪,你就可以开始写驱动程序,工作的进程有时侯会取决于你的运气”。
(这是一位留美的朋友对我说的,我写出来和大家共享)下面是我从一个朋友那里得到的一篇文章的摘要:NT驱动程序的分层结构驱动程序是指管理某个外围设备的一段程序代码。
NT采用更灵活的分层驱动方法,允许杂应用程序和硬件之间存在几个驱动程序层次。
分层机制允许NT更加广泛地定义驱动程序,包括文件系统、逻辑卷管理器和各种网络组件,各种物理设备驱动程序等等。
1、设备驱动程序这些是管理实际数据传输和控制特定类型的物理设备的操作的驱动程序,包括开始和完成I/O操作,处理中断和执行特定的设备要求的任何差错处理。
2、中间驱动程序NT允许在物理设备驱动程序上分层任意数目的中间驱动程序。
这些中间层次提供扩展I/O系统的功能一种方法,而不必修改底层的驱动程序。
这也是微软鼓吹的他们的系统灵活的一面!实际上我觉得这样反而牺牲了一些效率上的东西。
3、文件系统驱动程序(FSD)FSD是一类比较特殊的驱动程序,通常负责维护各种文件系统所需要的磁盘结构。
注意我们并不能使用DDK来开发FSD,而必须使用Microsoft的文件系统开发人员工具包。
一般比较少写中间过滤驱动程序,过滤驱动程序它截获和修改高层发送给类驱动程序的请求。
这样就允许利用现有类驱动程序的功能,而不必从头开始写所有程序。
NT内核模式对象在我们的实际开发过程中的对象是设备,由于端口驱动程序已经隐藏了硬件控制操作,因此我在这里不讲述跟硬件相关的部份。
如果今后的开发对象不同,需要对硬件进行操作的时候,可能会对中断、DMA等有比较详细的了解,这些内容可以参考DDK帮助。
NT使用对象技术管理所有的数据,下面分别对一般驱动程序所涉及的一些对象做一介绍。
不过在介绍这些对象之前,有必要先对驱动程序的结构做一介绍。
驱动程序结构NT驱动程序和一般的DOS/Windows C语言程序不一样,它没有main()或者WinMain()函数入口。
和DLL类似地,它向操作系统显露一个名称为DriverEntry()的函数,在启动驱动程序的时候,操作系统将调用这个入口。
DriverEntry除了做一些必要的设备初始化工作外,还初始化一些Dispatch例程入口。
我们知道,NT应用和设备驱动程序打交道主要是通过CreateFile、 ReadFile、WriteFile 和DeviceIoControl等Win32 API来进行的。
这些API其实都对应着驱动程序的一些Dispatch例程。
而驱动程序除了DriverEntry以外,主要就是由这些Dispatch例程组成的。
例如调用Win32 API CreateFile的时候,操作系统最终转化为对驱动程序IRP_MJ_CREATE功能代码所对应的 Dispatch例程的调用,如果驱动程序没有提供该例程, CreateFile调用就会失败。
NT中一些常用的功能代码和Win32 API的对象关系如下所示。
功能代码说明IRP_MJ_CREATE 打开设备CreateFileIRP_MJ_CLEANUP 在关闭设备时,取消挂起的I/O请求CloseHandleIRP_MJ_CLOSE 关闭设备CloseHandleIRP_MJ_READ 从设备获得数据ReadFileIRP_MJ_WRITE 向设备发送数据WriteFileIRP_MJ_DEVICE_CONTROL 对用户模式或内核模式客户程序可用的控制操作DeviceIoControlIRP_MJ_INTERNAL_DEVICE_CONTROL 只对内核模式客户程序可用的控制操作IRP_MJ_QUERY_INFORMATION 得到文件的长度GetFileLengthIRP_MJ_SET_INFORMATION 设置文件的长度SetFileLengthIRP_MJ_FLUSH_BUFFERS 写输出缓冲区或丢弃输入缓冲区FlushFileBuffersFlushConsoleInputBufferPurgeCommIRP_MJ_SHUTDOWN 系统关闭InitialSystemShutdown和上面的驱动程序支持的功能代码相对应,一般的驱动程序看起来就象下面的样子。
DriverEntry(…) // 驱动程序入口{…DeviceObject->MajorFunction[IRP_MJ_CREATE] = XXDriverCreateClose; //XX 对应的是你自己给你的驱动程序的命名DeviceObject->MajorFunction[IRP_MJ_CLOSE] = XXDriverCreateClose; DeviceObject->MajorFunction[IRP_MJ_READ] = XXDriverReadWrite; DeviceObject->MajorFunction[IRP_MJ_WRITE] = XXDriverReadWrite;…}XXDriverCreateClose(…) // 对应IRP_MJ_CREATE和IRP_MJ_CLOSE的例程{//……….}XXDriverDeviceControl(…)// 对应IRP_MJ_DEVICE_CONTROL的例程{//……….}XXDriverReadWrite(…) // 对应IRP_MJ_READ和IRP_MJ_WRITE的例程{//……….}一个驱动程序并不需要支持所有的功能代码,比如如果一个驱动程序根本就不必要与用户模式客户程序交互,那么就不用支持IRP_MJ_CREATE和 IRP_MJ_CLOSE。
又如设备不支持设备读写,就不用支持IRP_MJ_READ和IRP_MJ_WRITE。
驱动程序对象是在操作系统启动驱动程序、在调用驱动程序入口DriverEntry之前就已经创建好了的,并且作为DriverEntry 函数的参数传递给驱动程序。
如果驱动程序启动失败,操作系统将删除该对象。
该对象的数据结构如下。
注意下表并不是完整地列出了ntddk.h中的DEVICE_OBJECT结构体的所有数据项,这里仅列出了一般驱动程序可能使用到的数据项。
在上面提到过驱动程序是管理同类型的所有设备,所以上面的结构中DeviceObject指向的就不是单个的设备对象,而是一个对象链表,这个链表的维护在下面介绍Device对象时可以看到。
Device对象与Device Extension 驱动程序在调用IoCreateDevice函数成功后就创建了一个Device 对象。
下面对Device对象几个比较重要的数据做一介绍。
Device记录着设备的特徵和状态信息,对系统上的每个虚拟的、逻辑的和物理的设备都有一个Device对象。
例如对一个硬盘驱动程序,对一个物理硬盘有一个名称为Partition0的Device对象,对应整个物理磁盘,同时对硬盘的每个分区,也都有一个 Device对象,它们的名称分别为PartitionX(X从1开始,每个分区对应一个数字)。
Device Extension是连接到Device对象的一个很重要的数据结构,它的数据结构是由驱动程序设计者自己来确定的,在调用IoCreateDevice的时候应该指定它的大小,Device Extension其实是由操作系统在非份页内存池中为每个Device 对象分配的一块内存。
由于驱动程序必须是完全可重入的,因此使用任何全局变量和静态变量都不是好的办法,一般来说和设备有关的任何需要保持的信息都应该放到Device Extension里去。
设备的缓冲策略也必须提一下,这里的Flag的缓冲策略主要决定设备读写(功能代码IRP_MJ_READ和IRP_MJ_WRITE)时候的缓冲策略,另外功能代码IRP_MJ_DEVICE_CONTROL时候的缓冲策略是由IOCTL控制代码本身来决定的。
两者不能混为一谈。
在下面我将专门用一节来讨论I/O的缓冲策略。
I/O请求包(IRP)在上面的结构里面已经出现了IRP了,在这里对它做一说明。
在NT中,几乎所有的I/O都是包驱动的,可以说驱动程序和操作系统其他部份都是通过I/O请求包来进行交互的。
我们来看看一个I/O请求的执行过程。
(1) 操作系统的I/O管理器从非分页内存分配一个IRP,响应一个I/O请求。
基于由客户指定的I/O函数,I/O管理器将该 IRP传递给合适的驱动程序的Dispatch例程。
(2) Dispatch例程检查请求的参数是否有效,如果有效,驱动程序根据请求的内容进行一系列的操作。
否则设置错误状态信息直接返回。
(3) 操作完成时,将数据(如果有)和状态信息存放到IRP中并返回给I/O管理器。
(4) I/O管理器对返回的IRP进行适当的处理后将最后状态和数据(如果有)返回给用户。
一个IRP的主要数据项如下表所示。
IRP包括一个IRP头和一个IRP stack 的区域。
由于WDM的模式下都是包驱动的,所里IRP可以说是一个非常重要的东东。
还有那个该死的URB(God damn URB!)[人一辈子真的很过瘾,有些人或有些事你明明不喜欢或做不来,可是有时侯你又不得不硬着头皮去做,就像一大堆球迷围着一堆狗屎般的中国足球,那班傻儿真是要钱不要脸,丢咱中国人的脸]关于AssociatedIrp.SystemBuffer、MdlAddress和UserBuffer将在下面的I/O 缓冲区策略里面更详细地讨论。
NT还有更多其他的对象,例如中断对象、Controller对象、定时器对象等等,但在我们开发的驱动程序中并没有用到,因此在这里不做介绍。