pci设备的wdm驱动程序设计探讨与研究.doc_第1页
pci设备的wdm驱动程序设计探讨与研究.doc_第2页
pci设备的wdm驱动程序设计探讨与研究.doc_第3页
pci设备的wdm驱动程序设计探讨与研究.doc_第4页
pci设备的wdm驱动程序设计探讨与研究.doc_第5页
免费预览已结束,剩余14页可下载查看

下载本文档

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

文档简介

DriverStudio是一套NuMega公司为简化Windows设备驱动程序和应用程序而开发的开发、编译和调试的软件工具包。其中的DriverWorks以面向对象(OOP)的方式,将WDM和NT下的驱动程序编写所需的与内核访问及对硬件的访问封装成类,加上设计的驱动程序代码生成向导,大大简化了驱动程序开发的难度,减少了工作量。同时,DriverWorks被嵌入到VC中,方便了开发。本文以DriverWorks为工具,介绍开发PCI设备驱动程序的开发。1. 利用向导生成程序框架和设备配置信息在驱动程序向导中,生成了驱动程序的基本框架和用户自定义信息,虽然没有实现PCI设备的具体功能,但对于功能的实现设置了框架,功能代码都在该框架下完成,因此需要详细说明。打开VC,出现DriverStudio嵌入的工具栏,如图1。点击第一个按钮“Launch DriverWorks Driver Wizard”,打开了先导的第一页如图2。图1 DriverWorks工具栏图2 NT/WDM设备驱动程序向导第一步在该页中填写驱动程序工程的名称和路径,点击“Next”进入下一页,如图3。图3 NT/WDM设备驱动程序向导第二步在该页中选择驱动程序的运行系统。有两个选项:Windows NT4.0和WDM,分别对应的是WindowsNT4.0和Windows98/Windows2000。这里选择WDM。点击“Next”进入下一页,如图4。图4 NT/WDM设备驱动程序向导第三步在该页中,选择设备的类型并填写相应信息。选择“PCI”,填写PCI设备的设备标识符。“PCI Vendor ID”是厂商标识符;“PCI Device ID”为设备标识符;“PCI Subsystem ID”为子系统ID号;“PCI Revision ID”为修订号。这些信息由PCI设备在PCI总线配置时提供给系统的,供系统识别PCI设备的,系统根据这些信息来匹配已注册的PCI设备的驱动程序。一般只用到“PCI Device ID”和“PCI Device ID”,不可为零。“PCI Subsystem ID”和“PCI Revision ID”可为零,表示忽略。这些信息必须与PCI设备的硬件是一致的。点击“Next”进入下一页,如图5。图5 NT/WDM设备驱动程序向导第四步DriverWorks将PCI设备驱动程序封装成三个类:驱动程序类、设备类和IRP排队处理类。驱动程序类处理驱动程序的加载和卸载等工作,设备类实现对PCI设备的具体功能实现,如驱动程序的PNP处理、设备功能实现、中断处理、电源管理等,IRP排队处理类处理驱动程序的IRP排队串行处理,有两种类型:系统管理的和驱动程序管理的。在该页中,填写驱动程序类的名称和文件名称,一般不必修改,与工程名称相同即可。点击“Next”进入下一页,如图6。图6 NT/WDM设备驱动程序向导第五步在该页中,选择需要驱动程序处理的分发例程。“Read”和“Write”项对应的是应用程序调用驱动程序的ReadFile和WriteFile函数,这两个函数都是单向的,当处理数量较大的数据最好使用。“Device Control”对应的是应用程序的DeviceIoControl函数,该函数处理用户自定义的IOCTL,可以向驱动程序发送数据和返回数据。“Flush”项提供刷新I/O缓冲区的例程,一般用不到,可不选。“Internal Device Control”项提供其它驱动程序的调用,一般的PCI设备驱动程序无需与其它驱动程序通信,可不选。“Cleanup”项提供了清除所有IRP的例程,当驱动程序停止或卸载之前,需要清楚所有的IRP,保证驱动程序安全地停止。其他两项为默认。点击“Next”进入下一页,如图7。图7 NT/WDM设备驱动程序向导第六步在该页中选择IRP串行处理的类型和串行处理的函数。在对PCI设备的操作中往往不能将应用程序的请求立刻处理,或有多个应用程序同时请求,因此需要将这些请求进行串行化,使对IRP的处理不至于混乱。如果驱动程序可以立即将IRP处理完毕,就不必串行化。分发例程可以将IRP进行排队,交给统一处理IRP的例程StartIo串行处理。串行的处理例程有两种类型:驱动程序自行处理和系统处理。驱动程序可以设置多个StartIo处理函数,对于PCI设备来说,一般只对一个设备操作,只需一个StartIo处理。一般处理ReadFile和WriteFile函数的分发例程需要进行IRP排队,在此全部选中。点击“Next”进入下一页,如图8。图8 NT/WDM设备驱动程序向导第七步在该页中,添加需要存储在系统注册表中的内容。当驱动程序开始运行后,驱动程序就将信息从注册表中读出,当驱动程序卸载后,就存入注册表中。点击“Next”进入下一页,如图9。图9 NT/WDM设备驱动程序向导第八步在该页中,设置PCI设备类的信息。可以重新设置设备类的名称。在“Resources”项中,设置PCI设备的硬件资源。点击“Add IO Port(s)”设置PCI设备分配的I./O端口,如图10。图10 I/O端口设置“Name”是对应I/O端口资源的变量,DriveWorks将端口访问的操作封装成类KIoRange。对于每个映射为I/O端口的PCI 地址映射空间,都需要定义一个变量,负责管理I/O端口的信息和操作。在“PCI Base Address”项中,选定PCI 地址映射空间。在“Share options”中,选定访问的限制范围,对于PCI设备,其他驱动程序和系统没有兴趣来访问别的设备,另外考虑安全性,防止非法操作,一般选择“Exclusive to this device”。点击“Add Memory Range”设置内存资源,如图11。图11 内存设置内存设置与I/O端口设置类似,DriverWorks将对内存的操作封装成类KMomeryRange。点击“Add IRQ”设置中断服务程序,一个PCI设备最多可以有4个中断源,每个诊断源需要一个服务程序。但一般的PCI设备只有一个中断源,这里只设置一个。如图12。图12 设置中断资源DriverStudio将对中断的处理封装成了类KInterrupt,同时将DPC也封装成类KDeferredCall。如果不需要DPC,可以不选择“Create DPC”。其他中断的信息将在下面说明。同时,对DMA的操作也封装成类KDmaAdapter,点击“Add DMA”设置DMA内容,如图13。图13 设置DMA资源一般的主模式PCI设备都支持“Bus Master DMA”和“Scatter/Gether support”,即总线主控能力和分散/集中能力。共享选项选择“Exclusive to this device”。这些PCI设备类的信息设置好后,进入下一页,如图14。图14 NT/WDM设备驱动程序向导第九步在该页中添加自定义IOCTL,其对话框如图15。图15 添加自定义IOCTL首先填写IOCTL的名称,然后填写功能代码的系列号,0x0000x7FF为系统保留,0x8000xFFF为用户代码。“Method”项为数据传输的类型,可选Buffered、IN_DIRECT、OUT_DIRECT或Neither。参数Buffered适合少量的数据的传输;IN_DIRECT或OUT_DIRECT适合有大量的需要快速处理的应用DMA或PIO的数据上行或下行的传输;参数Neither很少使用,在PCI设备驱动程序中更不使用。这些参数在AddDevice中定义后,在驱动程序不可再更改。“Access”项定义应用程序访问IOCTL的权限类型,可选Any、Read、Write、Read/Write。如果IOCTL需要进行串行化,选择“Queue (Serialize) this request”。图16 其他设置驱动程序一般需要测试应用程序来连接驱动程序,并进行测试,DriverWorks可以直接生成一个简单的控制台应用程序。DriverWorks还可以在代码中生成调试代码等一些辅助代码和信息,在该页中可以选择,建议都选择,反正再生成Free版的驱动程序就会自动去掉这些代码。点击“Finish”,驱动程序框架就生成好了。由于DriverWorks将DDK中定义的驱动程序模型构架封装成了类,在VC中可以看到,有两个工程,一个驱动程序工程和测试应用程序工程。在驱动程序工程中,如果在第六步中选择了“DriverMeneged”的DPC类型将有三个类:从基类KDriver派生的PCIDemo类、从基类KPnpDevice派生的PCIDemoDevice类和从基类KDriverManagedQueueEx派生的PCIDemoDevice_DriverManagedQueue类,如果选择了“SystemMenaged”的DPC类型就只有前两个类。PCIDemo类负责驱动程序的装载和卸载,处理的内容包括对应的DDK中的DriverEntry、AddDevice和Unload例程(封装,没有显示)。PCIDemoDevice负责PCI设备的功能实现,从设备的Pnp处理、电源管理、分发例程处理和中断处理等,主要的代码编写都在该类中。如果没有对分发例程进行串行化,就没有类PCIDemoDevice_DriverManagedQueue,该类管理StartIo例程。由于WDM驱动程序的机制基本是系统内核回调例程的方式,因此有些例程之间的关系不明显,但是又互相联系紧密,这在实现具体功能时,再分析。2. PCI设备的配置空间的访问当驱动程序启动后,如果PNP管理器检测到PCI设备,就会发送IRP_MN_START_DEVICE的IRP给驱动程序处理。由于PCI总线为PnP总线,PCI设备的硬件资源都是有PCI总线配置机构动态分配的。驱动程序必须先将该IRP交给PCI总线驱动程序处理,取得PCI设备的配置信息后,驱动程序再处理该IRP,取得PCI设备的资源,进行分配和处理。该IRP在类PCIDemoDevice中对应的函数为OnStartDevice。如果在先导中设置好了PCI设备的资源,就不必再处理了,先导已把资源处理完毕。因此,在一般情况下驱动程序无需再访问PCI设备的配置空间,但是如果需要访问配置空间可通过类KPciConfiguration。在WDM中,访问PCI设备配置空间通过向PCI总线发送读写配置空间的IRP来实现的,该类封装了这些操作,使配置空间的操作非常方便。KPciConfiguration在使用之前,需要初始化,使之连接到访问的设备上。对于WDM,传递在物理设备对象栈的栈顶的设备对象。如下:KPciConfiguration PciDemoConfiguration(m_Lower.TopOfStack();其中m_Lower是KpnpLowerDevice类的实例,在AddDevice例程中初始化后,连接到该驱动程序上。函数TopOfStack返回当前设备堆栈顶部的设备对象。对KPciConfiguration或者调用函数Initialize也可。函数ReadHeader/WriteHeader、ReadBaseAddress/WriteBaseAddress等函数对应访问PCI设备的配置空间,具体请常见DriverWorks的帮助文档。3. I/O端口的访问类KIoRange封装了对I/O端口的操作。对PCI设备首先需要在函数OnStartDevice函数中取得I/O资源,然后初始化。如下:status = m_IoPortRange1.Initialize(pResListTranslated,/转换后的资源列表指针pResListRaw,/原始的资源列表指针PciConfig.BaseAddressIndexToOrdinal(1)/1代表分配的I/O资源在PCI基地址的序数,PCI设备最多可以有6个内存或I/O资源空间。);参数pResListTranslated和pResListRaw在DDK中从IRP_MN_START_DEVICE的IRP中取出。DriverWorks封装了IRP为KIrp。在OnStartDevice函数中由函数AllocatedResources和TranslatedResources得到上述参数。在WDM中,对于I/O端口,系统将其看成寄存器,必须将I/O资源分配成可由系统访问的非分页内存,函数Initialize完成该工作。在处理资源的代码中必须进行运行错误处理,否则就会在驱动程序的运行中,引起系统崩溃。在其他例程中,就可以调用类KIoRange的成员函数inX/outX函数进行访问PCI设备。这些函数没有运行级别的限制,可自由使用。例如:VOID outb( ULONG ByteOffset,/以字节为单位的地址偏移量 PUCHAR Buffer,/指向输入数据的指针 ULONG Count/输入数据的字节数);当驱动程序停止运行之前,一定要卸载资源,对于I/O端口调用成员函数Invalidate。4. 内存的访问类KMemoryRange封装了对PCI设备的映射内存的访问。在WDM中,驱动程序得到的只是PCI总线配置机构分配的物理内存,如果在驱动程序中是无法使用的,必须将其转换成系统可以访问的非分页内存,在DDK中,调用函数MmMapIoSpace。在KMemoryRange的成员函数Initialize中实现这个转换。在OnStartDevice函数中,如下:status = m_MemoryRange0.Initialize(pResListTranslated,pResListRaw,PciConfig.BaseAddressIndexToOrdinal(0);函数的参量同I/O端口的操作。KMemoryRange的其他成员函数操作同I/O端口的操作。5. 中断的处理在DDK中,中断资源的获得也是在IRP_MN_START_DEVICE的处理中,然后调用函数IoConnectInterrupt进行连接。在DriverWorks中,将中断的处理封装成类KInterrupt和宏MEMBER_ISR。其应用如下:在类PCIDemoDevice的定义中,public:DEVMEMBER_DISPATCHERS/自动声明用KDevice继承来的分发例程MEMBER_ISR(PCIDemoDevice, Isr_Irq);/声明连接的中断服务例程BOOLEAN Isr_Irq(void);/声明中断服务例程函数protected:KInterruptm_Irq;/中断变量在OnStartDevice函数中,调用KInterrupt的成员函数InitializeAndConnect初始化中断变量和调用宏LinkTo连接中断例程。status = m_Irq.InitializeAndConnect(pResListTranslated,/转换后的资源列表指针LinkTo(Isr_Irq), /连接中断服务例程this);在初始化和连接中断之前,最好将PCI设备的中断源进行屏蔽,PCI设备一般会有中断管理寄存器,屏蔽其中断许可位。当中断连接成功后,再将中断位打开。并且一定要加运行错误处理,防止驱动程序将系统崩溃。中断服务例程的框图如下:进入中断处理程序是否是自己的设备的中断?处理中断返回FALSE返回TRUE返回是否图17 中断服务例程框图在中断服务例程中,首先必须根据硬件信息来判断该中断是否是自己的设备发出的。这是因为PCI总线共享中断,系统在接收到中断后,顺序调用各个注册该中断资源的驱动程序的中断处理例程,如果有返回TRUE的例程,就代表该中断已处理,就不再调用其他例程,如果是返回FALSE的例程,则说明该中断没有处理,则继续调用其他的例程。如果返回错误,就会扰乱系统,造成系统崩溃。PCI设备一般都有寄存器来标志中断源的状态,可以通过访问这些寄存器来判断是否是自己设备的中断。在中断服务例程中,相应的处理最好简洁快速,因为中断例程运行的级别很高,当有中断请求时,不但会打断应用程序的执行,而且会打断在硬件中断级以下的所有运行程序。在WDM中,提供了DPC(Deferred Procedure Call)例程,将在中断例程中耗时的但不需要立即处理的任务延时处理。比如,驱动程序接受应用程序的写PCI设备的数据,当写完后,硬件产生中断标志执行完毕,这时需要结束该IRP,就可以将结束IRP这个耗时的任务交给DPC完成。对于DPC的操作也封装成类KDeferredCall,在PCI设备中一般会用到一个DPC来支持中断,其用法在函数OnStartDevice中与中断服务例程连接,如下:m_DpcFor_Irq.Setup(LinkTo(DpcFor_Irq), this);典型的中断-DPC用法的实例如下图:WriteFileWriteStartIoIsr_IrqDpcFor_Irq应用程序驱动程序图18 中断处理过程示例在该实例中,由应用程序调用函数WriteFile,将数据传递给驱动程序,驱动程序的类PCIDemoDevice的成员函数Write例程负责处理该IRP,由于需要中断的配合(假定),无法立即执行完毕,必须将IRP串行化,类PCIDemoDevice_DriverManagedQueue的成员函数StartIo如果没有其他任务,就开始处理该IRP,处理完毕后立即返回,但不能结束IRP,当PCI设备完成操作后,就会产生中断,在中断服务例程中把IRP交给类PCIDemoDevice的成员函数DpcFor_Irq,在DPC中处理完后结束该IRP。当驱动程序停止运行之前,一定要调用类KInterrupt的成员函数Invalidate断开中断的连接,释放资源。在DriverWorks中,只需在中断服务例程和DPC中增加功能代码,其他的先导已经都做好了。6. DMA的处理PCI设备根据总线访问能力分为主模式和从模式两种,主模式设备可以发起总线操作,而从模式只能接受总线操作。在PC机中,主模式设备可以进行DMA操作,从模式没有该功能,但可依靠系统的DMA控制器进行DMA数据传输。从模式设备应用DMA很少,这里只讨论主模式设备。在Windows2000中的DMA传输基于如图19所示的抽象模型。在这个模型中,计算机被认为有这样一组“映射寄存器”,它们在CPU的物理地址和总线地址之间做相互转换。每个映射寄存器保存着一个物理页帧的地址。硬件使用一个“逻辑的”或总线专有的地址来读写内存。对驱动程序来说映射寄存器扮演了与页表项相同的角色。适配器对象总线物理地址内存物理地址映射寄存器图19 DMA传输中的抽象计算机模型Windows 2000内核使用一个称为适配器对象的数据结构来描述设备上的DMA特征,并用它来控制访问潜在的共享资源,如系统DMA通道和映射寄存器。在DriverWorks中,由类KDmaTransfer描述DMA适配器。DMA数据传输的具体操作则是由类KDmaTransfer来实现的。在DMA的传输中,PCI设备将数据直接传输到系统物理内存中,管理这些内存的方式有两种:Common Buffer和Packet。第一种方式是在系统的物理内存中预先开辟一段地址连续的内存空间,是CPU和PCI设备都能对其访问,管理这种功能的是类KCommonDmaBuffer。另一种方式是使用MDL(Memory Descriptor List)描述的内存空间来作为DMA传输数据的源或目标。如果驱动程序需要不断地进行DMA传输,最好使用Common Buffer方式;如果驱动程序间断性的使用DMA则可以使用Packet方式,因为该方式每次的传输使用的物理地址不一样,而Common Buffer方式使用的物理地址在驱动程序的一次运行期间都是一样的,适合不断的DMA传输。当DMA启动命令交给系统后,系统就开始进行分配映射寄存器等工作,当完成后,系统调用驱动程序的自定义回调函数,开始DMA传输。因此,需要定义回调函数,并与中断服务例程和DPC例程联合工作。首先在类PCIDemoDevice中声明:public:DEVMEMBER_DMAREADY(PCIDemoDevice,OnDmaReady)/声明DMA传输启动后的回调函数protected:KDmaTransfer m_DmaTransfer;KDmaAdapter m_Dma;KCommonDmaBuffer m_CommonDmaBuffer;在函数OnStartDevice中,初始化DMA变量。m_Dma.Initialize(&dd, m_Lower.TopOfStack();m_CommonDmaBuffer.Initialize(m_Dma, 0x100);在SerialWrite函数中,启动DMA如下:void PCIDemoDevice:SerialWrite(KIrp I)status = m_DmaTransfer.Initiate(this, /设备指针&m_Dma, /KdmaAdapter指针0I.Mdl(), /数据的源或目的FromMemoryToDevice, /传输方向,或FromDeviceToMemoryLinkTo(OnDmaReady), /连接的回调函数&m_CommonDmaBuffer, /物理内存NULL, /如果使用宏MEMBER_DMAREADYWITHCONTEXT,作为其回调函数的参数FALSE);/指示当DMA传输完毕,是否释放DMA适配器和映射寄存器典型的DMA传输流程如图20。WriteFile发起IRPOnDmaReady检测是否有数据待发设置PCI设备的DMA通道,启动DMADMA传输完毕,PCI设备产生中断调用DPC 结束IRP是否SerialWrite启动DMAFile发起IRP图20 DMA传输流程在上图中DMA启动后,系统调用回调函数OnDmaReady,如果有数据需要传输,就操作PCI设备的DMA寄存器,并开始数据的传输。当传输完毕后,PCI设备产生中断请求,在驱动程序的中断服务例程中,启动DPC。在DPC中,调用类KDmaTransfer的成员函数Continue,再次启动DMA,系统就再次调用回调函数OnDmaReady,如果数据传输完毕,则调用类KDmaTransfer的成员函数Terminate结束DMA操作,并结束IRP;如果数据没有传输完毕,则继续循环,直到数据传输完毕为止。回调函数OnDmaReady的原型和处理如下:void PCIDemoDevice:OnDmaReady(KDmaTransfer* pXfer, KIrp I)if(pXfer-BytesRemaining() 0) PTRANSFER_DESCRIPTOR pTransferDescriptor;ULONG Count;Count = pXfer-GetTransferDescriptors(&pTransferDescriptor);/将内存物理地址信息发送给硬件elsepXfer-Terminate();I.Complete(STATUS_SUCCESS, 0);7. 驱动程序的安装DriverWorks根据先导已生成INF文件,需要更改的只是用户的信息,比如“ProviderName”、“NewDeviceClass”等,其他信息已经定义好,这里不再多述。8. 驱动程序的调试和调用由于PCI设备的硬件资源是动态配置的,只有当PCI设备上电后,驱动程序才能获得资源信息,再加上驱动程序主要是对硬件的操作,调试驱动程序应很小心,最好采取循序渐进的方法,一步一步实现功能,否则,经常死机,错误不容易查找。调试工具使用SoftIce。难度主要集中在中断处理和DMA上。在代码中,先导自动添加了很多调试信息, 关于SoftIce的使用,请参见其他文档。WDM驱动程序的设备访问可以符号链接,也可以使用设备接口

温馨提示

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

评论

0/150

提交评论