引言
PCI是由Intel公司1991年推出的一种局部总线。从结构上看,PCI是在CPU和原来的系统总线之间插入的一级总线,具体由一个桥接电路实现对这一层的管理,并实现上下之间的接口以协调数据的传送。管理器提供了信号缓冲,使之能支持10种外设,并能在高时钟频率下保持高性能,它为显卡,声卡,网卡,MODEM等设备提供了连接接口,它的工作频率为33MHz/66MHz。 32 位PCI 的数据传输率为133MB/s,扩展后的数据传输峰值速率高达264 MB/s。
数字卫星解调卡主要用于接收卫星发来的调制信号的数字解调。设计中的桥接芯片可采用PLX公司的PCI9054。本文主要介绍数字卫星解调卡的WDM驱动程序开发方法。
1 PCI9054接口芯片
PCI9054是PLX公司推出的PCI接口芯片。 PLX9054作为一种接口芯片,在pci总线和local总线之间传递信息。PCI卡就是利用plx9054的这一特性,通过接口控制电路 ,为外围设备和pc机间 搭建一座硬件桥,完成数据的顺利传输。 选择 Plx9054 本地总线可以工作在M,C,J三种模式。 9054支持主模式,从模式,dma传输模式,可以用于试配卡和嵌入式系统 。Plx9054 有一个强大的双通道分散/收集dma控制器,支持pci主机和适配器内存的高效突发传输。两个独立的dma通道能从局部总线到pci总线和从pci总线到局部总线传输数据。每个通道包括一个dma控制器和一个专用双向FIFO。两个通道都支持块传输,分散/收集传输,应用或者不用EOT传输等。模式选择在plx9054 成为一个pci总线主设备之前由主设备使能位(pcicr)使能。另外,两个dma通道都能编程实现8,16,32bit局部总线带宽,使能/使无效内部等待周期,使能/使无效局部总线突发传输;执行pci存储器写并无效操作;设置pci中断(inta)或看是否本地中断(i.int)等 对于数据传输模式的选择,主要是根据硬件制作者对硬件设计的需求而定的。 PCI9054的内部结构如图1所示。
Block DMA要求PCI主机或Local主机能提供PCI和Local的起始地址、传输字节数和传输方向。主机首先设定DMA开始位并启动数据传输,一旦传输完成,PCI9054设定将DMACSR0[4]=1或者DMACSR1 [4]=1(分别对应通道0和通道1)来结束DMA。如果中断Enable位DMAMODE0[10]或者DMAMODE1[10]使能,那么,在传输结束时,PCI9054将向主机申请中断。在DMA传输中,PCI9054既是PCI总线的主控设备,又是Local总线的主控设备。另外,通过编程DMA传输模式还可以完成以下设置或功能:
(1)将本地总线宽度设为8位、16位或32位;
(2)设置本地总线为允许/禁止内部等待状态,若允许,则可等待0~15个本地等待状态;
(3)设置本地总线为突发传输4个双字长度;
(4)使本地地址采用固定模式或线性增长模式;
(5)完成PCI内存写和无效操作(commandcode=Fh)或者普通PCI内存写操作(commandcode=7h);
(6)使用/禁用BLAST#以暂停本地传输;
(7)在Scatter/Gather DMA传输模式中,当DMA传输完成或终止计数器计数到0时,插入PCI中断(INTA)或者本地中断(LINT);
(8)工作于DMA清除计数模式。
2 WDM驱动程序开发工具
PCI总线的传统开发工具是微软公司提供的DDK(Device Driver Kit),包括Windows98 DDK,Windows2000 DDK和Windows XP DDK。但是,使用其开发驱动程序比较复杂且开发周期长,它只适合发行类产品的驱动开发。
WDM模型是Windows2k/xp中分层化的驱动程序模型,图中左边是一个设备对象堆栈。操作系统的PnP管理器按照要求构造设备对象堆栈,当总线驱动程序检查到新硬件存在,PnP管理器就创建一个PDO (physical device object,物理设备对象),然后PnP管理器参照注册表中的信息查找与这个PDO相关的FiDO(filter device object,过滤器设备对象)和FDO(functional device object功能设备对象),并按其次序加载直到完成整个堆栈。在这个模型中,驱动程序的层或堆栈一起工作处理I/O请求。每个影响到设备的操作都使用IRP(I/O请求包),通常IRP先被送到设备堆栈的最上层驱动程序,然后经过逐渐过滤到下面的驱动程序。每一层驱动程序都可以决定如何处理或仅仅是向下层传递该IRP,这取决于设备以及IRP所携带的内容。直至该IRP被完成或取消。
3 DMA模式WDM驱动程序开发
本文介绍的数字卫星解调卡的硬件框图如图2所示。图中,当FPGA中的数据放进FIFO后,要经过PCI9054桥接芯片传输到PC机内存中,但由于应用程序不能直接操作硬件,所以在应用程序和硬件之间必须安装硬件驱动程序来完成应用程序对硬件的访问。可见,驱动程序对于整个设计至关重要,它关系到数据能否准确无误的送到指定的目的地。
驱动程序完成的主要功能如下:
(1)接收应用传送的符号率,配置符号率;
(2)接收应用程序传送的控制字,配置AD9851用作外部FIFO数据传输的时钟;
(3)设置数据传输为DMA方式,直到接收到应用程序发来的停止数据采集命令为止。驱动要保证数据传输顺利进行。
本设计使用Driver Works来开发WDM驱动程序。
3.1 基于Driver Works的WDM驱动程序框架
这里所要生成的是PCI设备的驱动程序。采用DMA方式传输时,生成WDM驱动程序框架的主要步骤如下:
(1)从VC++中启动Driver Works,设置驱动程序名称及存放的路径,设计时可取驱动名称为BPSKDRIVER;
(2)选择工程类型为WDM DRIVER;
(3)选择驱动类型为WDM Function Driver;
(4)选择硬件总线类型为PCI,在这里要注意,PCI Vendor ID和PCI Device ID应根据硬件信息填写;
(5)添加存储器空间和I/O空间所需的类对象,添加DMA资源,使用设备接口打开设备;
(6)用控制代码完成应用程序和驱动的交互,即在应用程序中使用Device IO Control来完成应用程序向驱动传输数据。
3.2 DMA传输控制
(1)DMA传输类的概念及初始化
按照上述步骤生成WDM驱动的框架后,其大部分例程函数(如Driver Entry、Add Device、Device Control、On Start Device)等已经由软件自动生成并能基本满足设计要求,下面重点介绍DMA传输控制函数。
设计中,对DMA寄存器的访问可采用I/O方式,并可利用Driver Works提供的KIoRange类产生该类的一个实例,然后在设备启动例程中初始化该实例,即可实现对硬件的两个I/O地址空间的映射,其中一个I/O地址空间用于访问桥接芯片PCI9054的寄存器,另一个I/O地址空间用于访问本地端的设备,其初始化方法如下:
其中,pResListTranslated、pResListRaw分别是IRQ中系统分配的翻译资源列表和原始资源列表。初始化完成后,就可以使用类的成员函数in,out对端口进行操作。例如:m_IoPortRange0.outd(0x30,0x40100),就可向IO端口0的偏移量为0x30的地址中写入0x40100。
进行DMA传输需要用到三个DMA传输类,分别为KdmaAdapter、KCommonDmaBuffer和KdmaTransfer。
KdmaAdapter是DMA适配器对象,可用于表示需要进行DMA传输的设备资源。此对象对于Master设备和Slave设备都是适用的。驱动中,此类函数可在On Start Device中由成员函数Initialize初始化。
KconnonDmaBuffer是DMA通用缓冲区对象。驱动中,此类可在On Start Device中由成员函数Initialize初始化。通用缓冲区是外部设备和驱动程序之间的一段物理上连续的虚拟内存,这个内存是从系统中分配出来的,是非常珍贵的资源,任何时候都可以被他的设备和驱动程序存取。通用缓冲区包括缓冲区空间大小、虚拟地址、逻辑地址等信息。由于通用缓冲区是非常珍贵的资源,所以它的大小也受到限制。为此,驱动时应对每个DMA请求进行分段,并为每个段提供一个传输段描述符数组。而且,当设备不支持分散/集中时,这个数组中的描述符只能有一个。每个描述符包含一个物理地址和相应的字节数,其结构如下:
其中的物理地址即逻辑地址,字节数则是相应的逻辑地址范围的长度。
KdmaTransfer为DMA传输对象,用来管理内存和设备之间的数据传输,但此时的DMA适配器必须可用。适配器对象可用来通知传输数据的类型和使用的DMA通道等。驱动中,此类可在OnStart Device中由成员函数Initialize初始化。在DMA传输中,数据可直接传输到系统物理内存中。管理这些内存的方式有Common Buffer和Packet两种。第一种方式是在物理内存中预先开辟一段连续的内存空间,CPU和PCI都可以对其进行访问,且在一次DMA传输过程中,物理地址保持不变,该方式适合传输大量数据和连续的DMA传输;而在Packet方式中,由于其内存物理地址不确定,因此适合间断性的DMA传输。
(2)回调函数
由于DMA传输采用分段传输,所以,每当准备传输一个新段时,KDmaTransfer的对象将通知驱动程序调用回调例程。回调函数的原型由typedef DMAREADY_CALLBACK指定,使用宏DEVMEMBER_DMAREADY可声明回调函数基类的成员函数。通过判断成员函数Bytes Remaining可判断传输是否完成。若返回值为0,则调用成员函数Terminate以完成相应的IRP,否则,回调函数继续传输。
(3)中断服务
本驱动需要处理两种中断,第一种是本地中断,它是当FIFO输出半满信号时由FPGA通过LINT#信号发给PCI9054的中断信号;第二种中断是DMA传输结束时由DMA中断控制器产生的。这两种中断可以通过对DMA的中断控制寄存器的特定位处理来区分。判断是否是本地中断时,可以通过判断DMA中断控制寄存器的第15位是否为1来确定,如果INTCSR[15]=1,则为本地中断;判断是否是DMA中断则可通过判断DMA中断控制寄存器的第23位是否为1来确定,如果INTCSR[23]=1,则为DMA中断。不同的中断,其处理方式不同。
3.3 驱动程序的创建及安装文件的修改
为了正确的创建WDM驱动程序,首先要建立WDM编程环境,并创建自己的库文件。参考文件中提供了一种WDM编程环境的建立方法,但是,按照书中的方法经常不能成功的建立编程环境,为此,笔者根据自己的经验介绍一种简单易行的方法:
(1)首先安装DDK;
(2)在开始菜单中选择Compuware Driver Studio\Develop下的DDK Build Setting;
(3)在打开的对话框中的DDK Root Directory中设置DDK的根目录(如E:\WINDDK\2600),然后点击Launch Program,并打开Compuware DriverStudio的Driver Works文件夹中Source里的VdwLibs.dsw文件。
(4)选择Build菜单中的Set Active Project Configuration,并在弹出的对话框中选择合适的Project configurations。而对于现行的32位机,它不需要像Win32 AMD64 Free等这样的工程;
(5)选好一个工程后,点击OK,然后点击Build with BUILD.EXE即可生成所需的库。然后再根据自己的需要重新选择新的Project configurations,以进行库的创建。
笔者的这种方法在于使用DDK Build Setting的Launch Program打开VdwILibs.dsw,编译没有出现错误,书中的方法则是先打开VC++,然后打开VdwLibs.dsw,选择Batch Build下的Rebuild All创建库,但是笔者试了几次均不成功。
库文件生成之后,即可打开创建好的驱动程序,并在VC++的菜单中打开DDK Build Setting,再在DDK Root Directory中设置DDK的路径为实际安装的路径,之后点击Build图标,就可以生成BPSKDRIVER.sys文件了。另外,驱动的类型可以自己设定,Windows系统定义了一系列的设备类名和GUID,找到驱动工程文件中后缀名为.inf的安装文件,将其内容修改成与硬件信息一致就可以了。然后将此文件拷贝到工程中的i386文件夹中。至此,一个完整的驱动就创建成功了。
4 结束语
本驱动现在已经经过测试,工作正常。并已经应用于数字卫星解调卡中。WDM编程环境的创建具有自己的见解,并且可以实现一次创建即成功,希望对同类驱动程序的开发具有借鉴作用。
-
芯片
+关注
关注
453文章
50360浏览量
421646 -
驱动
+关注
关注
12文章
1824浏览量
85169 -
总线
+关注
关注
10文章
2864浏览量
87973
发布评论请先 登录
相关推荐
评论