PCI设备的WDM驱动程序设计-9052.doc_第1页
PCI设备的WDM驱动程序设计-9052.doc_第2页
PCI设备的WDM驱动程序设计-9052.doc_第3页
PCI设备的WDM驱动程序设计-9052.doc_第4页
PCI设备的WDM驱动程序设计-9052.doc_第5页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

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

文档简介

PCI设备的WDM驱动程序设计柳泉 罗耀华 柳华伟摘要:本文详细地讨论了利用DDK开发PCI设备的WDM驱动程序的设计原理、方法及在设计中注意事项,实现了以芯片PCI9052开发的PCI卡的具有内存和I/O读写及中断处理的WDM驱动程序。关键字:PCI,WDM,驱动程序,DDK在Windows操作系统中,为了保证系统的安全性和可移植性,对应用程序对硬件的操作进行了限制,尤其Windows 2000和Windows XP,不支持直接对系统的硬件资源的操作。因而在设计开发PCI设备时,需要开发相应的驱动程序来实现对PCI设备的操作,用户应用程序通过驱动程序来访问PCI设备。由于计算机硬件设备都存在不同的特点,因此各种设备的驱动程序也都有自己的特点,比如PCI设备、USB设备等等。尽管在整体框架中基本相同,但设备功能上不同,因此本文以PCI桥芯片PCI9052开发的PCI卡为硬件设备,来探讨PCI设备的驱动程序的开发。1 驱动程序类型和开发工具的选择在WINDOWS操作系统下,支持PCI总线及其设备的驱动程序类型有支持Windows 98/95的VxD、支持Windows NT的NT式驱动程序和支持Windows 2000、Windows XP和Windows 98的WDM(Windows Driver Model)。前两种驱动程序类型由于其支持的操作系统的逐渐淘汰而淘汰。现在主流的操作系统是Windows 2000和Windows XP,因此开发PCI设备的驱动程序最好的方案是WDM驱动程序。在一个系统中开发出WDM驱动程序,稍加修改即可在其他系统中编译运行。WDM是在Windows NT驱动程序体系的基础上发展而来的,修改或增加了即插即用、电源管理等功能,使之适应硬件和用户的要求。开发WDM驱动程序的主要工具是微软为各操作系统提供的开发软件包 Device Driver Kits(DDK) ,该软件包为驱动程序开发者提供了用于驱动程序开发的资源文件、编译连接程序、开发技术文档等。还有第三方提供的开发工具:NuMega公司的DriverStudio和Jungo公司的WinDriver,这些工具是在DDK的基础上为方便开发用户而进行开发的工具。在使用中,虽然利用DDK开发驱动程序难度较大,但是代码非常简洁,结构清晰,效率也高。利用第三方开发工具使用简单,开发速度较快,但对于驱动程序的理解和深入开发不如DDK。因此选择DDK开发PCI设备驱动程序,虽然开始会觉得非常复杂,但从执行效率和功能上会更有利。2 PCI设备驱动程序的特点在开发驱动程序之前对PCI总线和硬件设备进行了解是十分必要的,而且还要详细地掌握PCI设备的特性以及PCI设备驱动程序在设备程序栈的关系等,以便进行WDM驱动程序的设计。PCI总线是一种高性能、与CPU无关的32/64位地址数据复用的总线,它支持突发传输、即插即用、电源管理等功能,不但能满足现在的应用需要,而且能够适应未来的需求。PCI总线支持硬件资源动态自动配置,以支持即插即用。在PCI设备插入PCI插槽或上电后,PCI总线配置机构自动根据PCI设备的要求实现配置。PCI总线支持内存读写、I/O端口读写、中断机制和DMA功能。由于这些硬件特点使PCI设备的WDM驱动程序的设计变得很复杂。在开发WDM驱动程序之前,还有必须掌握PCI设备的需要分配的资源等配置信息以及PCI设备的功能和操作方法。在WDM中,采用了分层的驱动程序体系结构,总线驱动程序或类驱动程序在最底层直接与设备打交道,设备功能驱动程序在上层通过与低层驱动程序打交道,实现设备的功能,中间还可以有类过滤驱动程序或设备过滤驱动程序用于数据的过滤或转换。在PCI总线的驱动程序层中,其层次图如图4:更多的PCI设备的功能驱动程序和过滤驱动程序上层PCI类过滤驱动程序上层PCI设备过滤驱动程序PCI设备功能驱动程序低层PCI类过滤驱动过滤程序低层PCI设备过滤驱动程序PCI总线过滤驱动程序PCI总线驱动程序图1 通用PCI总线的WDM驱动程序栈在实际开发中,一般无需分很多层次,只需要开发一个设备驱动程序即可。设备驱动程序直接与PCI总线驱动程序打交道,进行硬件操作,以实现PCI设备的功能。3 WDM驱动程序的设计在PCI设备的WDM驱动程序中,一般是编写功能驱动程序。PCI总线驱动程序由操作系统实现,过滤驱动程序一般在特殊的情况下需要编写。因此本文只讨论PCI设备功能驱动程序的设计。在PCI设备功能驱动程序中,需要处理PCI设备的内存、端口的读写、中断处理和DMA数据传输,实现PCI设备的功能,因此,PCI设备功能驱动程序是很标准的WDM设备驱动程序。PCI设备驱动程序在框架上与其他类型的设备驱动程序基本相同,包括初始化、创建设备、卸载和删除设备、即插即用处理、分发例程处理、电源管理、WMI等部分,限于篇幅,在此只讨论PCI设备的特别之处。(1)PCI设备资源的获得PCI设备的硬件资源是由PCI配置机构动态分配的,由PCI设备实现PCI配置寄存器,提出需要分配的硬件资源,由PCI配置机构分配资源。驱动程序需要取得这些资源,才能操作硬件。因此,PCI设备的硬件资源分配与管理是驱动程序中很重要的部分。硬件资源主要包括映射内存空间、I/O空间、中断。在WDM体系中,取得这些资源有四种方法:读写PCI配置寄存器、调用硬件抽象层(HAL)函数、向PCI总线驱动程序发送读写配置IRP和向PCI总线驱动程序传递开启设备IRP。第一种方法通过读写PCI总线配置I/O寄存器,来取得PCI设备的配置信息,其中包括资源的分配。这种方法需要将几乎所有的PCI设备枚举一遍,考虑到这种方法是对公共寄存器的读写,不利于系统的安全性,最好不使用这种方法,但是在调试PCI设备硬件时是个很好的方法。第二种方法通过调用函数HalGetBusData和HalGetBusDataByOffset来实现的,但是这种方法是为了能够与Windows NT的驱动程序兼容,而保留下来的方法,不推荐使用,其功能被第三种方法取代。在WDM体系中,总线驱动程序必须实现总线上设备的管理功能。PCI总线驱动程序实现了对PCI设备资源的枚举,设备驱动程序通过向PCI总线驱动程序传递设备配置IRP_MJ_PNP,经总线驱动程序的处理后,设备驱动程序得到PCI设备的资源信息。第四种方法是推荐的方法,当系统的PNP管理器在取得设备的资源后会自动向驱动程序发出IRP_MN_START_DEVICE的IRP,在该IRP栈中包含了设备的资源信息。好的驱动程序都应该使用这种方法,在此主要讨论该方法。每个支持PNP功能的驱动程序,都应实现IRP_MN_START_DEVICE处理。在该IRP处理中应先交给低层驱动程序处理后,再根据IRP栈内内容进行资源分配。如下:NTSTATUS PnpStartDevice(IN PDEVICE_OBJECT fdo, IN PIRP pIrp ) NTSTATUS status;PIO_STACK_LOCATION stack;pIrp-IoStatus.Status = STATUS_SUCCESS;/先由低层驱动程序处理,并等待KeInitializeEvent(&event,NotificationEvent,FALSE);IoCopyCurrentIrpStackLocationToNext(pIrp);IoSetCompletionRoutine(pIrp,(PIO_COMPLETION_ROUTINE) OnRequestComplete,(PVOID) &event,TRUE,TRUE,TRUE);status=IoCallDriver(DEVICE_EXTENSION *)fdo-DeviceExtension) - pLowerDeviceObject ,pIrp);if (status = STATUS_PENDING) KeWaitForSingleObject(PVOID)&event,Executive,KernelMode,FALSE,NULL);if (!NT_SUCCESS(status)return CompleteRequest(pIrp, status);stack = IoGetCurrentIrpStackLocation(pIrp);ResourceRaw = stack-Parameters.StartDevice.AllocatedResources -List0.PartialResourceList-PartialDescriptors;Resource = stack-Parameters.StartDevice.AllocatedResourcesTranslated -List0.PartialResourceList-PartialDescriptors;for (i = 0; i Count; +i, +Resource, +ResourceRaw)switch (ResourceRaw-Type)case CmResourceTypeInterrupt:/中断资源 IrqL = (KIRQL) Resource-u.Interrupt.Level;/中断IRQL vector = Resource-u.Interrupt.Vector;/中断向量 affinity = Resource-u.Interrupt.Affinity;/中断分发的处理器集 /判断中断触发的类型if (ResourceRaw-Flags = CM_RESOURCE_INTERRUPT_LATCHED) mode = Latched;/低电平触发 elsemode = LevelSensitive;/下降沿出发/是否共享,PCI中断都是共享的irqshare = Resource-ShareDisposition = CmResourceShareShared;/连接中断status = IoConnectInterrupt(&pdx-pInterruptObject, (PKSERVICE_ROUTINE)OnInterrupt,(PVOID)pdx,NULL,vector,IrqL,IrqL,mode, irqshare,affinity,FALSE); case CmResourceTypePort:/端口资源 pdx-PhysicalIOBase = ResourceRaw-u.Port.Start;/开始物理地址 pdx-IOCount = ResourceRaw-u.Port.Length;/地址数量pdx-IOBase = (ULONG *)MmMapIoSpace(pdx-PhysicalIOBase,pdx-IOCount,MmNonCached);/映射端口 break; case CmResourceTypeMemory:/内存资源pdx-PhysicalMemBase = ResourceRaw-u.Memory.Start;/开始地址pdx-MemCount = ResourceRaw-u.Memory.Length;/地址数量pdx-MemBase = (ULONG *)MmMapIoSpace(pdx-PhysicalMemBase,pdx-MemCount,MmNonCached);/映射内存if (pdx-MemBase = NULL)return STATUS_INSUFFICIENT_RESOURCES;/其他资源一般没有,可默认处理default:break; return STATUS_SUCCESS;在以上的代码中,限于篇幅,没有增加错误处理代码,在实际中应用一定需要进行在调用系统函数之后,进行相应的处理,如果不符合要求,立即退出,否则在其他例程中会发生错误,使系统崩溃。同时,在退出之前,一定要释放已分配的资源。(2)内存读写Windows工作在保护模式下,与实模式的区别在于CPU寻址方式不同,可以实现虚拟内存。在Windows系统中对内存又分为分页和非分页内存。分页内存一般用于应用程序,系统提供分页和分段使用户应用程序使用的内存可以在程序空闲的时候由系统将其从物理内存调配到硬盘中,以节省物理内存资源,当程序重新运行的时候,再由系统将其调配到物理内存,这样,系统可以得到比物理内存非常大的内存量,允许更多得应用程序保持运行。而非分页内存为系统常驻内存,不可以从物理内存调配到硬盘上,因此内存无需分页。在WDM驱动程序中,对于硬件的内存映射一般需要用非分页内存,因为在一些运行在DISPATCH_LEVEL或更高得中断级例程中,禁止使用分页内存,比如在中断处理程序中就不可以使用分页内存。再者,使用非分页内存无需太多的转换,非常安全,效率也高。如果使用分页内存,系统就有可能将其调配到硬盘上,容易产出错误。但是,不能过多地使用非分页内存。在PCI设备的驱动程序中,获得的设备内存是一段映射物理内存,这是无法使用的,需要将其映射成系统可以访问的非分页内存。函数MmMapIoSpace完成该功能。该函数的原型为:PVOID MmMapIoSpace( IN PHYSICAL_ADDRESS PhysicalAddress, IN ULONG NumberOfBytes, IN MEMORY_CACHING_TYPE CacheEnable);参数PhysicalAddress为物理地址;NumberOfBytes为地址的数量;CacheEnable为内存是否可以隐藏,取值可为MmNonCached,MmCached,MmWriteCombined,这里必须取为MmNonCached。其应用实例见以上代码中的“内存资源”处理部分。当访问设备内存时,使用函数UCHAR READ_REGISTER_UCHAR(IN PUCHAR Register);ULONG READ_REGISTER_ULONG(IN PULONG Register);USHORT READ_REGISTER_USHORT(IN PUSHORT Register);VOID READ_REGISTER_BUFFER_UCHAR(IN PUCHAR Register,IN PUCHAR Buffer,IN ULONG Count);VOID READ_REGISTER_BUFFER_UCHAR(IN PULONG Register,IN PULONG Buffer,IN ULONG Count);VOID READ_REGISTER_BUFFER_UCHAR(IN PUSHORT Register,IN PUSHORT Buffer,IN ULONG Count);VOID WRITE_REGISTER_UCHAR(IN PUCHAR Register,IN UCHAR Value);VOID WRITE_REGISTER_ULONG(IN PULONG Register,IN ULONG Value);VOID WRITE_REGISTER_USHORT(IN PUSHORT Register,IN USHORT Value);VOID WRITE_REGISTER_BUFFER_UCHAR(IN PUCHAR Register,IN PUCHAR Buffer,IN ULONG Count);VOID WRITE_REGISTER_BUFFER_UCHAR(IN PULONG Register,IN PULONG Buffer,IN ULONG Count);VOID WRITE_REGISTER_BUFFER_UCHAR(IN PUSHORT Register,IN PUSHORT Buffer,IN ULONG Count);以上函数对应的分别是对PCI设备内存的读写函数,参数Register为映射后的内存地址,在使用时,应进行相应的数据类型转换。其他参数为数据参数。XXX_REGISTER_XXX读写单个地址的内容;XXX_REGISTER_BUFFER_XXX读写一段内存的内容,这在PCI设备支持突发读写(Burst Transmission)时应用。例如读写单个内存的地址:WRITE_REGISTER_UCHAR(PUCHAR)pdx-MmBase,0x03C);(3)I/O读写在PC上,I/O空间是一个64K字节的寻址空间。I/O端口的寻址方式与内存是不一样的。但是在WDM驱动程序中,对其处理与内存是一样的,把其看作寄存器,映射为设备内存。其映射方法和访问函数的用法与内存资源一样,只不过函数XXX_REGISTER_XXX改为XXX_PORT_XXX。(4)中断的处理在PCI总线中,很多设备共享一个中断,这就需要在中断处理函数要格外小心,处理不当,就会导致系统崩溃。驱动程序首先要在IRP_MN_START_DEVICE中获得中断资源,然后需要连接到中断处理函数中,使其当有中断请求时,进入中断服务例程。连接中断的函数为IoConnectInterrupt,具体用法见上段程序中的“中断资源”部分。十分需要注意的是在连接中断之前,一定要确定PCI设备不会产生中断请求,最好在PCI设备上电后,中断为屏蔽状态。在连接中断后,调用开启中断请求的函数需要同步处理,以防在函数的执行中,出现运行时间上的错误,而且在开启中断时,一定要在所有的硬件资源分配以后,否则如果有中断产生,系统就会立即调用中断处理例程,如果例程中使用了还没有分配的资源,就会出现意想不到的结果。同步处理使用函数:BOOLEAN KeSynchronizeExecution(IN PKINTERRUPT Interrupt,IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,IN PVOID SynchronizeContext);参数Interrupt为IoConnectInterrupt返回的变量,SynchronizeRoutine为函数名称,SynchronizeContext为函数的输入参数。调用方式如下:KeSynchronizeExecution(pdx-pInterruptObject,(PKSYNCHRONIZE_ROUTINE)EnablePciInterrupt,pdx);在中断服务例程中,首先必须根据硬件信息来判断该中断是否是自己的设备发出的。这是因为PCI总线共享中断,系统在接收到中断后,顺序调用各个注册该中断资源的驱动程序的中断处理例程,如果有返回TRUE的例程,就代表该中断已处理,就不再调用其他例程,如果是返回FALSE的例程,则说明该中断没有处理,则继续调用其他的例程。如果返回错误,就会扰乱系统,造成系统崩溃。其框图如图3。进入中断处理程序是否是自己的设备的中断?处理中断返回FALSE返回TRUE返回是否图2 中断服务例程框图在中断服务例程中,相应的处理最好简洁快速,因为中断例程运行的级别很高,当有中断请求时,不但会打断应用程序的执行,而且会打断在硬件中断级以下的所有运行程序。在WDM中,提供了DPC(Deferred Procedure Call)例程,将在中断例程中耗时的但不需要立即处理的任务延时处理。比如,驱动程序接受应用程序的写PCI设备的数据,当写完后,硬件产生中断标志执行完毕,这时需要结束该IRP,就可以将结束IRP这个耗时的任务交给DPC完成。典型的用法示例如图4:WriteFileDispatchWriteStartIoOnInterruptDPC应用程序驱动程序图3 中断处理过程示例在该实例中,由应用程序调用函数WriteF

温馨提示

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

评论

0/150

提交评论