ImageVerifierCode 换一换
格式:DOCX , 页数:15 ,大小:68.43KB ,
资源ID:10456852      下载积分:12 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/10456852.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(如何写驱动程序.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

如何写驱动程序.docx

1、如何写驱动程序我这里重点的介绍如何写驱动程序,对于一些应用程序我就不做介绍了,因为 我对于那些高层的东西写得很少。倘若再讲,有班门弄斧之嫌,呵呵! 作为 WIN98 和 WIN2K 推荐的一项新技术来说,USB 的驱动程序和以往的直接跟 硬件打交道的 WIN95 的 VXD 的方式的驱动程序不同,它应该是 WDM 类型的。USB 的 WDM 接口框图如下(这个图可以说是 USB 软件总体框图)对于 HID 的设备,就可以采用上图左上边的结构,其它类的话采用右上的结构, 其实右边的结构可以又细分成两层,一层是 Class Driver,一层是 Miniport Driver。而倒数第三行的 UH

2、CD 和 OpenHCI 分别是由 INTEL 和 COMPAQ 两位老大 定的一个和硬件有关的底层驱动程序标准,各位可以根据所需要的选择。对于 USB 的驱动程序,大家还得去了解 WDM 驱动程序的写法,或者早些时候的 NT 驱动程序,其实 WDM 驱动程序可以看做是 NT 驱动程序的一个 update,只是 增加了一些新的特性。“写驱动程序是一个很漫长和繁琐的工作,在此之前,你最好要熟悉硬件,熟 悉 C/C+,还要用过 DDK,会用一些调试程序,如 SOFTICE 和 WINDBG 之类。如 果一切就绪,你就可以开始写驱动程序,工作的进程有时侯会取决于你的运气” 。(这是一位留美的朋友对我

3、说的,我写出来和大家共享)下面是我从一个朋友那里得到的一篇文章的摘要:NT 驱动程序的分层结构驱动程序是指管理某个外围设备的一段程序代码。NT 采用更灵活的分层驱动方 法,允许杂应用程序和硬件之间 存在几个驱动程序层次。分层机制允许 NT 更 加广泛地定义驱动程序,包括文件系统、逻辑卷管理器和各种网络组件,各种 物理设备驱动程序等等。1、 设备驱动程序这些是管理实际数据传输和控制特定类型的物理设备的操作的驱动程序,包括 开始和完成 I/O 操作,处理中断和执行特定的设备要求的任何差错处理。2、 中间驱动程序NT 允许在物理设备驱动程序上分层任意数目的中间驱动程序。这些中间层次提 供扩展 I/O

4、 系统的功能一种方法,而不必修改底层的驱动程序。这也是微软鼓 吹的他们的系统灵活的一面!实际上我觉得这样反而牺牲了一些效率上的东西。3、 文件系统驱动程序(FSD)FSD 是一类比较特殊的驱动程序,通常负责维护各种文件系统 所需要的磁盘结 构。注意我们并不能使用 DDK 来开发 FSD,而必须使用 Microsoft 的文件系统 开发人员工具包。一般比较少写中间过滤驱动程序,过滤驱动程序它截获和修改高层发送给类驱 动程序的请求。这样就允许利用现有类驱动程序的功能,而不必从头开始写所 有程序。 NT 内核模式对象在我们的实际开发过程中的对象是设备,由于端口 驱动程序已经隐藏了硬件控制操作,因此我

5、在这里不讲述跟硬件相关的部份。 如果今后的开发对象不同,需要对硬件进行操作的时候,可能会对中断、DMA 等有比较详细的了解,这些内容可以参考 DDK 帮助。NT 使用对象技术管理所有的数据,下面分别对一般驱动程序所涉及的一些对象 做一介绍。不过在介绍这些对象之前,有必要先对驱动程序的结构做一介绍。驱动程序结构NT 驱动程序和一般的 DOS/Windows C 语言程序不一样,它没有 main()或者 WinMain()函数入口。和 DLL 类似地,它向操作系统显露一个名称为 DriverEntry()的函数,在启动驱动程序的时候,操作系统将调用这个入口。 DriverEntry 除了做一些必要

6、的设备初始化工作外,还初始化一些 Dispatch 例 程入口。我们知道,NT 应用和设备驱动程序打交道主要是通过 CreateFile、 ReadFile、WriteFile 和 DeviceIoControl 等 Win32 API 来进行的。这些 API 其实都对应着驱动程序的一些 Dispatch 例程。而驱动程序除了 DriverEntry 以 外,主要就是由这些 Dispatch 例程组成的。例如调用 Win32 API CreateFile 的时候,操作系统最终转化为对驱动程序 IRP_MJ_CREATE 功能代码所对应的 Dispatch 例程的调用,如果驱动程序没有提供该例程

7、, CreateFile 调用就会 失败。NT 中一些常用的功能代码和 Win32 API 的对象关系如下所示。功能代码说明IRP_MJ_CREATE备 CreateFileIRP_MJ_CLEANUP备时,取消挂起的 I/O 请求 CloseHandle IRP_MJ_CLOSE备 CloseHandle打开设在关闭设关闭设IRP_MJ_READ获得数据 ReadFileIRP_MJ_WRITE设备发送数据 WriteFile IRP_MJ_DEVICE_CONTROL模式客户程序可用的控制操作 DeviceIoControl IRP_MJ_INTERNAL_DEVICE_CONTROL控制

8、操作IRP_MJ_QUERY_INFORMATIONGetFileLengthIRP_MJ_SET_INFORMATIONSetFileLengthIRP_MJ_FLUSH_BUFFERS丢弃输入缓冲区FlushFileBuffersFlushConsoleInputBufferPurgeCommIRP_MJ_SHUTDOWN从设备向对用户模式或内核只对内核模式客户程序可用的得到文件的长度设置文件的长度写输出缓冲区或系统关闭InitialSystemShutdown和上面的驱动程序支持的功能代码相对应,一般的驱动程序看起来就象下面的 样子。DriverEntry() / 驱动程序入口Devic

9、eObject-MajorFunctionIRP_MJ_CREATE = XXDriverCreateClose; /XX 对应的是你自己给你的驱动程序的命名 DeviceObject-MajorFunctionIRP_MJ_CLOSE = XXDriverCreateClose;DeviceObject-MajorFunctionIRP_MJ_READ = XXDriverReadWrite;DeviceObject-MajorFunctionIRP_MJ_WRITE = XXDriverReadWrite;XXDriverCreateClose() / 对应 IRP_MJ_CREATE 和

10、 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。驱动程序对象是在操作系统启动驱动程序、在调用驱动程序 入 口 Drive

11、rEntry 之前就已经创建好了的,并且作为 DriverEntry 函数的参数传 递给驱动程序。如果驱动程序启动失败,操作系统将删除该对象。该对象的数 据结构如下。注意下表并不是完整地列出了 ntddk.h 中的 DEVICE_OBJECT 结构 体的所有数据项,这里仅列出了一般驱动程序可能使用到的数据项。Driver 对象数据项说明PDEVICE_OBJECT DeviceObject由本驱动程序创建的 Device 对象 的链表ULONG Flags PDRIVER_INITIALIZEDriverInit驱动程序初始化例程(一般较少用)PDRIVER_STARTIO DriverSta

12、rtIoStartIo 例程入口,一般该例程对 低层设备驱动程序用得较多, 高层 驱动程序较少使用本例程。PDRIVER_UNLOAD DriverUnload卸载驱动程序例程,如果想在控制面 版的设备里停止该设备,应该提供本 例程。PDRIVER_DISPATCHMajorFunctionIRP_MJ_MAXIMUM_FUNCTION+ 1驱动程序的 Dispatch 例程表在上面提到过驱动程序是管理同类型的所有设备,所以上面的结构中 DeviceObject 指向的就不是单个的设备对象,而是一个对象链表,这个链表的 维护在下面介绍 Device 对象时可以看到。 Device 对象与 De

13、vice Extension 驱动程序在调用 IoCreateDevice 函数成功后就创建了一个 Device 对象。下面 对 Device 对象几个比较重要的数据做一介绍。Device 对象数据项说明PVOIDDeviceExtension指向 Device Extension 结构的指针PDRIVER_OBJECTDriverObject指向这个设备的 Driver 对象的指针,IoCreateDevice 会 自动填写本数据。ULONG Flags指定这个设备的缓冲策略PDEVICE_OBJECTNextDevice指向属于这个驱动程序的下一个设备对象,依靠本数据 来维护设备对象链表C

14、CHAR StackSize发送到这个设备的 IRP 需要的 I/O 堆栈单元的最小数目 一般对分层驱动程序来说,本数据应该比其下层设备的 大 1Device 记录着设备的特徵和状态信息,对系统上的每个虚拟的、逻辑的和物理 的设备都有一个 Device 对象。例如对一个硬盘驱动程序,对一个物理硬盘有一 个名称为 Partition0 的 Device 对象,对应整个物理磁盘,同时对硬盘的每个 分区,也都有一个 Device 对象,它们的名称分别为 PartitionX(X 从 1 开始, 每个分区对应一个数字)。Device Extension 是连接到 Device 对象的一个很重要的数据结

15、构,它的数据 结构是由驱动程序设计者自己来确定的,在调用 IoCreateDevice 的时候应该指 定它的大小,Device Extension 其实是由操作系统在非份页内存池中为每个 Device 对象分配的一块内存。由于驱动程序必须是完全可重入的, 因此使用 任何全局变量和静态变量都不是好的办法,一般来说和设备有关的任何需要保 持的信息都应该放到 Device Extension 里去。设备的缓冲策略也必须提一下,这里的 Flag 的缓冲策略主要 决定设备读写(功 能代码 IRP_MJ_READ 和 IRP_MJ_WRITE)时候的缓冲策略,另外功能代码 IRP_MJ_DEVICE_CO

16、NTROL 时候的缓冲 策略是由 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) Dispa

17、tch 例程检查请求的参数是否有效,如果有效,驱动程序根据请求的 内容进行一系列的操作。否则设置错 误状态信息直接返回。(3) 操作完成时,将数据(如果有)和状态信息存放到 IRP 中 并返回给 I/O 管理 器。(4) I/O 管理器对返回的 IRP 进行适当的处理后将最后状态和 数据(如果有)返 回给用户。一个 IRP 的主要数据项如下表所示。IRP 包括一个 IRP 头和一个 IRP stack 的区域。由于 WDM 的模式下都是包驱动 的,所里 IRP 可以说是一个非常重要的东东。还有那个该死的 URB(God damn URB!)人一辈子真的很过瘾,有些人或有些事你明明不喜欢或做不来

18、,可是有 时侯你又不得不硬着头皮去做,就像一大堆球迷围着一堆狗屎般的中国足球, 那班傻儿真是要钱不要脸,丢咱中国人的脸IRP 主要数据项说明IO_STATUS_BLOCK IoStatus存放 I/O 请求的状态PVOIDAssociatedIrp.SystemBuffer如果设备执行缓冲 I/O,则为指向系统空间缓冲 区的指针。 否则为 NULLPMDL MdlAddress如果设备执行直接 I/O,指向用户空间缓冲区的内存描述表的指针PVOID UserBufferI/O 缓冲区的用户空间地址BOOLEAN Cancel指示 IRP 已被取消关于 AssociatedIrp.SystemB

19、uffer、MdlAddress 和 UserBuffer 将在 下面的 I/O 缓冲区策略里面更详细地讨论。NT 还有更多其他的对象,例如中断对象、Controller 对象、定时器对象等等, 但在我们开发的驱动程序中并没有用到,因此在这里不做介绍。I/O 缓冲策略很明显的,驱动程序和客户应用程序经常需要进行数据交换,但我们知道驱动 程序和客户应用程序可能不在同一个地址空间,因此操作系统必须解决两者之 间的数据交换。这就就设计到设备的 I/O 缓冲策略。读写请求的 I/O 缓冲策略前面说到通过设置 Device 对象的 Flag 可以选择控制处理读写请求的 I/O 缓冲 策略。下面对这些缓冲

20、策略分别做一介绍。1、缓冲 I/O(DO_BUFFERED_IO)在读写请求的一开始,I/O 管理器检查用户缓冲区的可访问性,然后分配与调 用者的缓冲区一样大的非分页池,并把它的地址放在 IRP 的 AssociatedIrp.SystemBuffer 域中。驱动程序就利用这个域来进行实际数据的 传输。对于 IRP_MJ_READ 读请求,I/O 管理器还把 IRP 的 UserBuffer 域设置成调用者 缓冲区的用户空间地址。当请求完成时,I/O 管理器利用 这个地址将数据从驱 动程序的系统空间拷贝回调用者的缓冲区。对于 IRP_MJ_WRITE 写请求, UserBuffer 被设置为

21、NULL,并把用户缓冲 区的数据拷贝到系统缓冲区中。 2、 直接 I/O(DO_DIRECT_IO)I/O 管理器首先检查用户缓冲区的可访问性,并在物理内存中锁定它。然后它 为该缓冲区创建一个内存描述表(MDL),并把 MDL 的地址存放在 IRP 的 MdlAddress 域中。AssociatedIrp.SystemBuffer 和 UserBuffer 都被设置为 NULL。驱动程序可以调用函数 MmGetSystemAddressForMdl 得到用户缓冲区的 系统空间地址,从而 进行数据操作。这个函数将调用者的缓冲区映射到非份页 的地址空间。驱动程序完成 I/O 请求后,系统自动从系

22、统空间解除缓冲区的映 射。3、 这两种方法都不是这种情况比较少用,因为这需要驱动程序自己来处理缓冲问题。 I/O 管理器仅 把调用者缓冲区的用户空间地址放到 IRP 的 UserBuffer 域中。我们并不推荐 这种方式。IOCTL 缓冲区的缓冲策略IOCTL 请求涉及来自调用者的输入缓冲区和返回到调用者的输出 缓冲区。为了 理解 IOCTL 请求,我们先来看看 WIN32 API DeviceIoControl 函数的原型。 BOOL DeviceIoControl (HANDLE hDevice, / 设备句柄DWORD dwIoControlCode, / IOCTL 请求操作代码LPV

23、OID lpInBuffer, / 输入缓冲区地址DWORD nInBufferSize, / 输入缓冲区大小LPVOID lpOutBuffer, / 输出缓冲区地址DWORD nOutBufferSize, / 输出缓冲区大小LPDWORD lpBytesReturned, / 存放返回字节数的指针LPOVERLAPPED lpOverlapped / 用于同步操作的 Overlapped 结构体指针);IOCTL 请求有四种缓冲策略,下面一一介绍。1、 输入输出缓冲 I/O(METHOD_BUFFERED)I/O 管理器首先分配一个非分页池,它足够大地存放调用者的输入或输出缓冲 区(不管

24、哪个更大)。非分页缓冲区的地址放在 IRP 的 AssociatedIrp.SystemBuffer 域中,然后把 IOCTL 的输入数据拷贝到这个非份 页缓冲区中,并把 IRP 的 UserBuffer 域设置成调用者输出缓冲区的用户空间地 址。当驱动程序完成 IOCTL 请求时,I/O 管理器将这个非份页缓冲区中的数据 拷贝到调用者的输出缓冲区。注意这里同一个非份页池同时用于输入和输出缓 冲区,因此驱动程序在向缓冲区写东西之前应该把输入的所有数据读出来。 2、 直接输入缓冲输出 I/O(METHOD_IN_DIRECT)I/O 管理器首先检查调用者输入缓冲区的可访问性,并在物理内存中将其锁

25、定。 然后为该输入缓冲区创建一个 MDL,并把指定该 MDL 的指针存放到 IRP 的 MdlAddress 域中。同时,I/O 管理器还在非份页池中分配一输出缓冲区,并把 这个缓冲区的地址存放在 IRP 的 AssociatedIrp.SystemBuffer 域中,并把 IRP 的 UserBuffer 域设置成调用者输出缓冲区的用户空间地址。当驱动程序完成 IOCTL 请求时,I/O 管理器将非份页缓冲区中的数据拷贝到调用者的输出缓冲区。3、 缓冲输入直接输出 I/O(METHOD_OUT_DIRECT)I/O 管理器首先检查调用者输出缓冲区的可访问性,并在物理内存中将其锁定。 然后为该

26、输出缓冲区创建一个 MDL,并把指定该 MDL 的指针存放到 IRP 的 MdlAddress 域中。同时,I/O 管理器还在非份页池中分配一输入缓冲区,并把 这个缓冲区的地址存放在 IRP 的 AssociatedIrp.SystemBuffer 域中,同时把调 用者用户输入缓冲区中的数据拷贝到系统缓冲区中,并把 IRP 的 UserBuffer 域设置为 NULL。4、 上面三种方法都不是(METHOD_NEITHER)I/O 管理器把调用者的输入缓冲区的地址放到 IRP 当前 I/O 堆栈单元的 Parameters.Devi ceIoControl.TypeInputBuffer 域中

27、,把输出缓冲 区的地址 存放到 IRP 的 UserBuffer 域中。这两个地址都是用户空间地 址。 从上面的说明可以看出,在执行缓冲 I/O 时,I/O 管理器将在非份页池 中分配 内存,如果调用者的缓冲区比较大时,分配的非份页池也将比较大。非份页池 是系统比较宝贵的资源,因此,如果调用者的缓 冲区比较大时,我们一般采用 直接 I/O 的方式(例如磁盘读写请求等),这样不仅节省系统资源,另一方面由 于省去了 I/O 管理器在系统缓冲 区和调用者缓冲区之间的数据拷贝,也提高了 效率,这对存在大量数据传送的驱动程序尤其明显。可以注意到 DDK 中的 Samples 下,几乎所有的例程的读写请求

28、都是直 接 I/O 的, 而对于 IOCTL 请求则是缓冲区 I/O 的居多。开始驱动程序设计下面的文字是从 Microsoft 的 DDK 帮助中节选出来的,它让我们明 白在开始设 计驱动程序应该注意些什么问题,这些都是具有普遍 意义的开发准则。应该支 持哪些 I/O 请求在开始写任何代码之前, 应该首先确定我们的驱动程序应该处 理哪些 IRP 例程。如果你在设计一个设备驱动程序,你应该支持和其他相同类型 设备的 NT 驱动 程序相同的 IRP_MJ_XXX 和 IOCTL 请求代码。如果你是在设计一个中间层 NT 驱动程序,应该首先确认你下层 驱动程序所管 理的设备,因为一个高层的驱动程序

29、必须具有低层驱动程序绝大多数 IRP_MJ_XXX 例程入口。高层驱动程序在接到 I/O 请求时,在确定自身 IRP 当前 堆栈单元参数有效的前提下,设置好 IRP 中下一个低层驱动程序的堆栈单元, 然后再调用 IoCallDriver 将请求传递给下层驱动程序处理。一旦决定好了你的驱动程序应该处理哪些 IRP_MJ_XXX,就可以开始 确定驱动 程序应该有多少个 Dispatch 例程。当然也可以考虑把某些 RP_MJ_XXX 处理的 例程合并为同一例程处理。例如在 ChangerDisk 和 VDisk 里,对 IRP_MJ_CREATE 和 IRP_MJ_CLOSE 处理的例程就是同一函

30、数。对 IRP_MJ_READ 和 IRP_MJ_WRITE 处理的例程也是同一个函数。应该有多少个 Device 对象?一个驱动程序必须为它所管理的每个可能成为 I/O 请求的目标的物理和逻辑设 备创建一个命名 Device 对象。一些低层的驱动程序还可能要创建一些不确定数 目的 Device 对象。例如一个硬盘驱动程序必须为每一个物理硬盘创建一个 Device 对象,同时还必须为每个物理磁盘上的每个逻辑分区创建一个 Device 对象。一个高层驱动驱动程序必须为它所代表的虚拟设备创建一个 Device 对象,这 样更高层的驱动程序才能连接它们的 Device 对象到这个驱动程序的 Devi

31、ce 对 象。另外,一个高层驱动程序通常为它低层驱动程序所创建的 Device 对象创建 一系列的虚拟或逻辑 Device 对象。尽管你可以分阶段来设计你的驱动程序,因此一个处在开发阶段的驱动程序不 必一开始就创建出所有它将要处理的所有 Device 对象。但从一开始就确定好你 最终要创建的所有 Device 对象将有助于设计者所要解决的任何同步问题。另外, 确定所要创建的 Device 对象还有助于你定义 Device 对象的 Device Extension 的内容和数据结构。开始驱动程序开发驱动程序的开发是一个从粗到细逐步求精的过程。NT DDK 的 src 目录下有一 个庞大的样板代码,几乎覆盖了所有类型的设备驱动程序、高层驱动程序和过 滤器驱动程序。在开始开发你的驱动程序之前,你应该在这个样板库下面寻找 是否有和你所要开发的类似类型的例程。例如我们所开发的驱动程序,虽然 DDK 对 USB 描述得不是很详细,我们还是可以在 srcstorage class 目录发现 很多和 USB 设备有关的驱动程序。下面我们来看开发驱动程序的基本步骤。 最简的驱动程序框架1、 写一个 DriverEntry 例程,在里面调用 IoCreateDevice 创建 一个 Device 对象。1、写一个处理 I

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1