如何写驱动程序_第1页
如何写驱动程序_第2页
如何写驱动程序_第3页
如何写驱动程序_第4页
如何写驱动程序_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

我这里重点的介绍何写驱动程序,于一些应用程序就不做介绍了,因为我对于那些高层的西写得很少。倘再讲,有班门弄之嫌,呵呵!作为WIN98和WIN2K推荐一项新技术来说USB的驱动程序和往的直接跟硬件打交道的WIN95的VXD的方式的驱动序不同,它应该WDM类型的。USB的WDM接口框如下(这个图可说是USB软件总体框)对于HID的设备,可以采用上图左边的结构,其它的话采用右上的结构其实右边的结构可又细分成两层,层是ClassDriver,层是MiniportDriver。而倒数第行的UHCD和OpenHCI分是由INTEL和COMPAQ两老大定的一个和硬件有的底层驱动程序准,各位可以根所需要的选择。对于USB的驱动程,大家还得去了WDM驱动程序的法,或者早些时候的NT驱动程序,其实WDM驱程序可以看做是NT动程序的一个update只是增加了一些新的特。“写驱动程序是一很漫长和繁琐的作,在此之前,最好要熟悉硬件,熟悉C/C++,还要用DDK,会用一些调试序,如SOFTICEWINDBG之类。如果一切就绪,你就以开始写驱动程,工作的进程有侯会取决于你的运气。(这是一位留美朋友对我说的,写出来和大家共)下面是我从一个朋那里得到的一篇章的摘要:NT驱动程序的分层结驱动程序是指管理个外围设备的一程序代码。NT采更灵活的分层驱方法,允许杂应用程和硬件之间存在几驱动程序层次。层机制允许NT更加广泛地定义驱动序,包括文件系、逻辑卷管理器各种网络组件,各种物理设备驱动程序等。1、设备驱动程序这些是管理实际数传输和控制特定型的物理设备的作的驱动程序,包括开始和完成I/O操,处理中断和执特定的设备要求任何差错处理。2、中间驱动程序NT允许在物理设备驱程序上分层任意目的中间驱动程序这些中间层次提供扩展I/O系统的能一种方法,而必修改底层的驱程序。这也是微软鼓吹的他们的系统灵的一面!实际上觉得这样反而牺了一些效率上的东西3、文件系统驱动序(FSD)FSD是一类比较特的驱动程序,通负责维护各种文件系所需要的磁盘结构。注意我们并不使用DDK来开发FSD而必须使用Microsoft的文件系开发人员工具包。一般比较少写中间滤驱动程序,过驱动程序它截获修改高层发送给类驱动程序的请求。这就允许利用现有驱动程序的功能而不必从头开始写所有程序。NT内核式对象在我们的际开发过程中的对象设备,由于端口驱动程序已经隐藏硬件控制操作,此我在这里不讲跟硬件相关的部份。如果今后的开发对不同,需要对硬进行操作的时候可能会对中断、DMA等有比较详细的了,这些内容可以考DDK帮助。NT使用对象技术管理有的数据,下面别对一般驱动程序涉及的一些对象做一介绍。不过在绍这些对象之前有必要先对驱动序的结构做一介绍。驱动程序结构NT驱动程序和一般的DOS/WindowsC语程序不一样,它没main()或者WinMain()函数入。和DLL类似地,它操作系统显露一名称为DriverEntry()的数,在启动驱动程序时候,操作系统调用这个入口。DriverEntry除了一些必要的设备始化工作外,还初始一些Dispatch例程入口。我们知道NT应用和设备驱程序打交道主要通过CreateFileReadFile、WriteFile和DeviceIoControl等Win32API进行的。这些API其实都对应着驱动序的一些Dispatch例程。而动程序除了DriverEntry以外,主要就是由这Dispatch例程组成。例如调用Win32APICreateFile的时候,操作系统终转化为对驱动序IRP_MJ_CREATE功代码所对应的Dispatch例程的调用如果驱动程序没提供该例程,CreateFile调用就会失败。NT中一些常用的功能码和Win32API对象关系如下所示功能代码说明IRP_MJ_CREATE备CreateFileIRP_MJ_CLEANUP备时,取消挂起的I/O请CloseHandleIRP_MJ_CLOSE备CloseHandle

打开设在关闭设关闭设IRP_MJ_READ获得数据ReadFileIRP_MJ_WRITE设备发送数据WriteFileIRP_MJ_DEVICE_CONTROL模式客户程序可用控制操作DeviceIoControlIRP_MJ_INTERNAL_DEVICE_CONTROL控制操作IRP_MJ_QUERY_INFORMATIONGetFileLengthIRP_MJ_SET_INFORMATIONSetFileLengthIRP_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结构体的所有数据项,里仅列出了一般动程序可能使用的数据项。Driver对象数据项说明PDEVICE_OBJECTDeviceObject由本驱动程序创建Device对象的链表ULONGFlagsPDRIVER_INITIALIZEDriverInit驱动程序初始化例(一般较少用)PDRIVER_STARTIODriverStartIoStartIo例程入口一般该例程对低层设备驱动程序得较多,高层驱动程序较少使用例程。PDRIVER_UNLOADDriverUnload卸载驱动程序例程如果想在控制面版的设备里停止该备,应该提供本例程。PDRIVER_DISPATCHMajorFunction[IRP_MJ_MAXIMUM_FUNCTION+1]驱动程序的Dispatch例程表在上面提到过驱动序是管理同类型所有设备,所以面的结构中DeviceObject指向的不是单个的设备象,而是一个对象表,这个链表的维护在下面介绍Device对象可以看到。Device象与DeviceExtension驱动程序在调用IoCreateDevice函数成功后就创建一个Device对象下面对Device对象几比较重要的数据做一绍。Device对象数据项说明PVOIDDeviceExtension指向DeviceExtension结构的指PDRIVER_OBJECTDriverObject指向这个设备的Driver对象指针,IoCreateDevice会自动填写本数。ULONGFlags指定这个设备的缓策略PDEVICE_OBJECTNextDevice指向属于这个驱动序的下一个设备象,依靠本数据来维护设备对象链CCHARStackSize发送到这个设备的IRP需的I/O堆栈单元最小数目一般对分层驱动程来说,本数据应比其下层设备的大1ULONGULONGAlignmentRequirement缓冲区要求的内存齐,一般对分层动程序来说,本值应该和其下层备的对齐一致Device记录着设备的徵和状态信息,系统上的每个虚拟、逻辑的和物理的设备都有一个Device对象例如对一个硬盘驱动序,对一个物理盘有一个名称为Partition0的Device对象对应整个物理磁,同时对硬盘的每个分区,也都有一个Device对,它们的名称分为PartitionX(X1开始,每个分区对应一个字)。DeviceExtension是接到Device对象一个很重要的数结构,它的数据结构是由驱动程序计者自己来确定,在调用IoCreateDevice的时候应该指定它的大小,DeviceExtension其实由操作系统在非页内存池中为每Device对象分配一块内存。由于驱动序必须是完全可入的,因此使用任何全局变量和静变量都不是好的法,一般来说和备有关的任何需要保持的信息都应该放DeviceExtension里去。设备的缓冲策略也须提一下,这里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请求的执行过。操作系统的I/O管器从非分页内存配一个IRP,响应一I/O请求。基于由客户指定的I/O函,I/O管理器将该IRP传递合适的驱动程序的Dispatch例程。Dispatch例程检查请的参数是否有效如果有效,驱动程根据请求的内容进行一系列的作。否则设置错误态信息直接返回操作完成时,将数(如果有)和状态息存放到IRP中返回给I/O管理器。I/O管理器对返回IRP进行适当的理后将最后状态和数(如果有)返回给用户。一个IRP的主要数项如下表所示。IRP包括一个IRP和一个IRPstack的域。由于WDM的式下都是包驱动的,所里IRP可以是一个非常重要东东。还有那个死的URB(GoddamnURB!)[人一辈子真很过瘾,有些人有些事你明明不欢或做不来,可是有时侯你又不得不硬头皮去做,就像大堆球迷围着一狗屎般的中国足球,那班傻儿真是要钱要脸,丢咱中国的脸]IRP主要数据项说明IO_STATUS_BLOCKIoStatus存放I/O请求的状PVOIDAssociatedIrp.SystemBuffer如果设备执行缓冲I/O,为指向系统空间缓冲区的指针。否则NULLPMDLMdlAddress如果设备执行直接I/O,向用户空间缓冲区的内存描述表的指针PVOIDUserBufferI/O缓冲区的用户间地址BOOLEANCancel指示IRP已被取消关于AssociatedIrp.SystemBuffer、MdlAddress和UserBuffer将下面的I/O缓冲区策略里更详细地讨论。NT还有更多其他的对,例如中断对象Controller对象定时器对象等等,但在我们开发的驱程序中并没有用,因此在这里不介绍。I/O缓冲策略很明显的,驱动程和客户应用程序常需要进行数据换,但我们知道驱动程序和客户应用程可能不在同一个址空间,因此操系统必须解决两者之间的数据交换。这就设计到设备的I/O冲策略。读写请求的I/O缓策略前面说到通过设置Device对的Flag可以选择制处理读写请求I/O缓冲策略。下面对这些冲策略分别做一绍。1、缓冲I/O(DO_BUFFERED_IO)在读写请求的一开,I/O管理器检用户缓冲区的可访问,然后分配与调用者的缓冲区一样的非分页池,并它的地址放在IRP的AssociatedIrp.SystemBuffer域。驱动程序就利这个域来进行实际据的传输。对于IRP_MJ_READ请求,I/O管理还把IRP的UserBuffer域设置成调者缓冲区的用户空间址。当请求完成,I/O管理器利用这地址将数据从驱动程序的系统空间贝回调用者的缓区。对于IRP_MJ_WRITE写请求,UserBuffer被设置为NULL,并把用户缓区的数据拷贝到统缓冲区中。2、直接I/O(DO_DIRECT_IO)I/O管理器首先检用户缓冲区的可问性,并在物理存中锁定它。然后它为该缓冲区创建一内存描述表(MDL),把MDL的地址存在IRP的MdlAddress域中。AssociatedIrp.SystemBuffer和UserBuffer都设置为NULL。驱动程序可调用函数MmGetSystemAddressForMdl得到户缓冲区的系统空间地址,从进行数据操作。这函数将调用者的冲区映射到非份页的地址空间。驱动序完成I/O请求,系统自动从系空间解除缓冲区的映射。3、这两种方法都是这种情况比较少用因为这需要驱动序自己来处理缓问题。I/O管理仅把调用者缓冲区的户空间地址放到IRPUserBuffer域。我们并不推荐这种方式。IOCTL缓冲区的缓策略IOCTL请求涉及来调用者的输入缓区和返回到调用者的出缓冲区。为了理解IOCTL请求,们先来看看WIN32APIDeviceIoControl函数原型。BOOLDeviceIoControl(HANDLEhDevice,//备句柄DWORDdwIoControlCode,//请求操作代LPVOIDlpInBuffer,//入缓冲区地址DWORDnInBufferSize,//入缓冲区大小LPVOIDlpOutBuffer,//出缓冲区地址DWORDnOutBufferSize,//出缓冲区大小LPDWORDlpBytesReturned,//放返回字节数的指针LPOVERLAPPEDlpOverlapped//用于同步操的Overlapped结构指针);IOCTL请求有四种冲策略,下面一介绍。1、输入输出缓冲I/O(METHOD_BUFFERED)I/O管理器首先分一个非分页池,足够大地存放调者的输入或输出缓冲区(不管哪个更大)非分页缓冲区的址放在IRP的AssociatedIrp.SystemBuffer域,然后把IOCTL输入数据拷贝到这非份页缓冲区中,并把IRP的UserBuffer域设置成调用者输出缓冲的用户空间地址。当驱动程序完IOCTL请求时,I/O理器将这个非份缓冲区中的数据拷贝到调用者的输缓冲区。注意这同一个非份页池时用于输入和输出缓冲区,因此驱动程在向缓冲区写东之前应该把输入所有数据读出来。2、直接输入缓冲出I/O(METHOD_IN_DIRECT)I/O管理器首先检调用者输入缓冲的可访问性,并在物内存中将其锁定然后为该输入缓冲创建一个MDL,把指定该MDL的指针放到IRP的MdlAddress域中。同,I/O管理器还在份页池中分配一出缓冲区,并把这个缓冲区的地址放在IRP的AssociatedIrp.SystemBuffer域中并把IRP的UserBuffer域置成调用者输出冲区的用户空间地址当驱动程序完成IOCTL请求时,I/O管器将非份页缓冲中的数据拷贝到用者的输出缓冲区3、缓冲输入直接出I/O(METHOD_OUT_DIRECT)I/O管理器首先检调用者输出缓冲的可访问性,并在物内存中将其锁定然后为该输出缓冲创建一个MDL,把指定该MDL的指针放到IRP的MdlAddress域中。同,I/O管理器还在份页池中分配一入缓冲区,并把这个缓冲区的地址放在IRP的AssociatedIrp.SystemBuffer域中同时把调用者用户输入缓冲中的数据拷贝到统缓冲区中,并IRP的UserBuffer域设置为NULL。4、上面三种方法不是(METHOD_NEITHER)I/O管理器把调用的输入缓冲区的址放到IRP当前I/O栈单元的Parameters.DeviceIoControl.TypeInputBuffer域,把输出缓冲区地址存放到IRP的UserBuffer域中。这两个址都是用户空间址。从上面的说明可以出,在执行缓冲I/O,I/O管理器将非份页池中分配内存,如果调用者缓冲区比较大时分配的非份页池将比较大。非份页池是系统比较宝贵的源,因此,如果用者的缓冲区比大时,我们一般用直接I/O的方式(如磁盘读写请求等,这样不仅节省统资源,另一方面由于省去了I/O管理在系统缓冲区和调者缓冲区之间的据拷贝,也提高了效率,这对存在大数据传送的驱动序尤其明显。可以注意到DDK中Samples下,几所有的例程的读请求都是直接I/O的而对于IOCTL请求是缓冲区I/O的多。开始驱动程序设计下面的文字是从Microsoft的DDK帮中节选出来的,让我们明白在开设计驱动程序应该注些什么问题,这都是具有普遍意的开发准则。应支持哪些I/O请求在始写任何代码之,应该首先确定们的驱动程序应处理哪些IRP例程。如果你在设计一个备驱动程序,你该支持和其他相类型设备的NT驱动程序相同的IRP_MJ_XXX和IOCTL请求代。如果你是在设计一中间层NT驱动程序应该首先确认你层驱动程序所管理的设备,因为一高层的驱动程序须具有低层驱动序绝大多数IRP_MJ_XXX例程入口高层驱动程序在到I/O请求时,确定自身IRP当前堆栈单元参数有效前提下,设置好IRP下一个低层驱动序的堆栈单元,然后再调用IoCallDriver将请求传递给下层驱程序处理。一旦决定好了你的动程序应该处理些IRP_MJ_XXX,可以开始确定驱程序应该有多少个Dispatch程。当然也可以考把某些RP_MJ_XXX理的例程合并为同一例处理。例如在ChangerDisk和VDisk里对IRP_MJ_CREATE和IRP_MJ_CLOSE处理的例程是同一函数。对IRP_MJ_READ和IRP_MJ_WRITE处理的程也是同一个函。应该有多少个Device象?一个驱动程序必须它所管理的每个能成为I/O请求目标的物理和逻辑设备创建一个命名Device对象一些低层的驱动程序可能要创建一些确定数目的Device对象例如一个硬盘驱程序必须为每一个物硬盘创建一个Device对象,同时还须为每个物理磁上的每个逻辑分区建一个Device对象。一个高层驱动驱动序必须为它所代的虚拟设备创建个Device对象,样更高层的驱动程才能连接它们的Device对象到个驱动程序的Device对象。另外,一个高驱动程序通常为低层驱动程序所建的Device对象建一系列的虚拟或逻Device对象。尽管你可以分阶段设计你的驱动程,因此一个处在发阶段的驱动程序不必一开始就创建出有它将要处理的有Device对象。从一开始就确定你最终要创建的所有Device对将有助于设计者所要决的任何同步问。另外,确定所要创建的Device对象有助于你定义Device对的DeviceExtension的内容和数据结构开始驱动程序开发驱动程序的开发是个从粗到细逐步精的过程。NTDDK的目录下有一个庞大的样板代码几乎覆盖了所有型的设备驱动程、高层驱动程序和过滤器驱动程序。在始开发你的驱动序之前,你应该这个样板库下面寻找是否有和你所要开的类似类型的例。例如我们所开的驱动程序,虽然DDK对USB描述得是很详细,我们是可以在src\storage\class目录发现很多和USB设备有的驱动程序。下我们来看开发驱程序的基本步骤。最简的驱动程序框写一个DriverEntry例程在里面调用IoCreateDevice创建一个Device对象。写一个处理IRP_MJ_CREATE请求的Dispatch例程的本框架(参见DDKKernel-ModeDrivers4.4.3描述的个DispatchCreate例程要完成的最基本工作。当然写了DispatchCreate例程后,要在DriverEntry例程为IRP_MJ_CREATE初化例程入口)。如驱动程序创建了于一个Device对,则必须为IRP_MJ_CLOSE请求写一个例程,例程通常情况下可以DispatchCreate共用个例程,参见参DDKKernel-ModeDrivers4.4.3。3、编译连接你的动程序。用下面的方法来测你的驱动程序。首先按上面介绍的法安装好驱动程。其次我们还得为NT逻设备名称和目标Device对象名之间建立起符号接,我们在前面已经知Device对象名称对WIN32用户模式是可见的,是不能直接通过API来访问,WIN32API只访问NT逻辑设名称。我们可以通过修改注册表来建立两种名称之间的号连接。运行REGEDT32.EXE在\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\SessionManager\DOSDevices下立起符号连接(这种号连接也可以在驱动序里调用函数IoCreateSymbolicLink来建)。重新启动系统。编写一个简单的测程序调用WIN32APICreateFile函数以刚才你名的NT逻辑设备名打开这个备。如果打开成,那么你也就成地写出了一个最简单的驱动程序了。支持更多的设备I/O求例如你的驱动程序能需要对IRP_MJ_READ请求做出响应(成后可用WIN32APIReadFile函数进测试)。如果你的动程序需要能够工卸载,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论