您当前的位置:五五电子网电子知识单片机-工控设备DSP/FPGA技术pci卡设计心得(二) 正文
pci卡设计心得(二)

pci卡设计心得(二)

点击数:7452 次   录入时间:03-04 11:38:25   整理:http://www.55dianzi.com   DSP/FPGA技术
再说软件驱动,我说过我编的是vxd,用vtools编的,可以用vc++直接编译成vxd文件,至于为什么必须用vxd驱动我想就不用说了。我的vxd的主要任务就是在系统中找到我的PCI卡,并读出本地芯片所映射的内存物理地址,在windows系统中,用户程序不能直接访问物理地址,只能使用线性地址,所以vxd还有做的一件事就是将物理地址转换成线性地址供win app使用。 vxd查找pci卡就是靠搜索vendorID和devICeID,它是通过依次搜索总线号和设备号(具体什么意思我也说不清,反正知道就行了),看是否有符合指定的vendorID和deviceID,如果符合则认为找到了pci卡的配置空间,因为配置空间的第一个双字就是vendorID和deviceID.然后向下面的地址依次读就可以读出pci卡的配置空间其他信息,包括sPACe0映射的内存基地址。读出此地址来再进行物理地址到线性地址的转换,就可以完全供win app使用了(可以通过指针访问),来读取9052 LOCal上挂的芯片了。
具体的查找方式主要通过vxd程序中首先向io地址0xcf8写入最高位为1的双字0x80000000,这个数的第16到23位代表了总线号,第11到15位代表了设备号,第8到14位代表了功能号,然后就可以读取io地址0xcfc的双字,如果有效的话说明此pci配置空间地址上挂了一个pci卡,从0xcfc读出的数则为此pci卡配置空间的第一个双字,即vendorID和deviceID,我是将vendorID和deviceID一起使用的,即判断读出的双字是否等于我在9052配置eeprom中标定的数,如果是则说明找到了我的pci卡,如果不是则继续找。向0xcf8写入的数+0x800,在继续
读0xcfc,依次下去,直到找到。如果当此数加到0x80ffff00时还没找到(即总线号搜索完毕),则表明没法找到,那就要找找自己的原因了,可能是板子的配置错了。
找到了pci卡的配置空间后,读出space0的基地址,然后进行物理地址到线性地址的转换,我又偷了懒,vtools提供的example中有实现此功能的vxd源代码,直接用vc++编译成vxd就可以共win app使用了。所以实际上我的app程序使用了两个vxd,一个用来专门找卡,一个用来地址转换。
至于app如何调用vxd,可以参看vc的参考书,一般都有介绍。
下面将一下如何安装vxd到系统中,我编的vxd都是动态加载的(PNP一般都用动态加载vxd)要编写一个inf文件以便系统将vxd安装进去。我用的是windriver生成的inf文件模板,然后再按照需要进行修改,自然加上我的大名了。编完了inf文件后,就可以安装了。一般情况如果你插上pci卡windows启动后就会发现新硬件,你只要按照以前安装硬件的步骤进行就可以了只是在选择安装文件时选择自己编写的inf文件就可以了。我觉得一般的安装过程就是将vxd文件拷入系统的文件夹,即windows目录下,以便当app加载vxd时,系统可以找到vxd程序,进行动态加载。
下面是我的inf文件

[Version]
Signature=$CHICAGO$ ;必须这么写
Class=PLX ;可以自己改
Provider=%SHENLI% ;制作者

[Manufacturer]
%Manufacture%=SECTION0

[SECTION0]
%my_card%=my.install,PCI\VEN_10b5&DEV_9050 ;my.install表示了安装过程所要做的事,

[my.install]
CopyFiles=CopyFiles_PLX10b5 ;主要做拷贝文件和注册表添加
AddReg=AddReg_PLX10b5


[CopyFiles_PLX10b5]
Vxd8_25.vxd

[AddReg_PLX10b5]
HKR,,DevLoader,0,Vxd8_25.vxd


[Strings]
Manufacture="BUAA202" ;这些信息会在安装时显示
my_card="PLX9052"


下面提供了vxd中查询pci卡的代码,这个代码是参考清华bbs驱动版精华区huyuguang大虾的大作,他提供了更详细的代码
有兴趣可以参考。

BOOL findpci(DWORD DeviceVendor,PCIINF *pciinf)//我的卡的DeviceVendor=0x905210b5
{
DWORD io_cf8;
DWORD io_cfc;
int i;
DWORD buf[16];

io_cf8=0x80000000;
for(;;)
{
DWORD_OUT(0xcf8,io_cf8);//向0xcf8输出双字 io_cf8
io_cfc=DWORD_IN(0xcfc); //从0xcfc读入双字
if(io_cfc==DeviceVendor)//find pci9052
{
for(i=0;i<16;i++)
{
DWORD_OUT(0xcf8,io_cf8+4*i);
buf[i]=DWORD_IN(0xcfc);
}
pciinf->VendorID=(WORD)(buf[0]&0xffff);
pciinf->DeviceID=(WORD)((buf[0]&0xffff0000)/0x10000);
pciinf->Command=(WORD)(buf[1]&0xffff);
pciinf->Status=(WORD)((buf[1]&0xffff0000)/0x10000);
pciinf->RevisionID=(UCHAR)(buf[2]&0xff);
pciinf->CacheLineSize=(UCHAR)(buf[3]&0xff);
pciinf->LatencyTimer=(UCHAR)((buf[3]&0xff00)/0x100);
pciinf->HeaderType=(UCHAR)((buf[3]&0xff0000)/0x10000);
pciinf->BIST=(UCHAR)((buf[3]&0xff000000)/0x1000000);
pciinf->BaseAddresses[0]=buf[4];
pciinf->BaseAddresses[1]=buf[5];
pciinf->BaseAddresses[2]=buf[6];
pciinf->BaseAddresses[3]=buf[7];
pciinf->BaseAddresses[4]=buf[8];
pciinf->BaseAddresses[5]=buf[9];
pciinf->SubsystemVendorID=(USHORT)(buf[11]&0xffff);
pciinf->SubsystEMID=(USHORT)((buf[12]&0xffff0000)/0x10000);
pciinf->InterruptLine=(UCHAR)(buf[15]&0xff);
pciinf->InterruptPIN=(UCHAR)((buf[15]&0xff00)/0x100);
pciinf->MinimumGrant=(UCHAR)((buf[15]&0xff0000)/0x10000);
pciinf->MaximumLatency=(UCHAR)((buf[15]&0xff000000)/0x1000000);
break;
}
else
io_cf8+=0x800;
if(io_cf8>=0x80ffff00)
return 1;
}
return 0;
}

以上都是我这次制作卡的一些心得,还有很多不清楚的地方,写出来只是想让感兴趣的pci门外汉了解一下,但愿能有所帮助。肯定有很多错误,希望各位大虾指正,但求不会误人子弟。pci大虾见笑了




本文关键字:暂无联系方式DSP/FPGA技术单片机-工控设备 - DSP/FPGA技术