|
PCI CONFIG-ADDRESS配置空间
PCI设备给我们提供了两个32位的I/O空间,可以让我们进行读写操作。一个是CF8H另一个是CFCH,这两个端口对应PCI桥路的两个寄存器。当桥路看到CPU在局部总线对这两个I/O空间进行双字操作时,就将该I/O操作转变为PCI总线的配置操作。寄存器CF8h用于产生配置空间的地址(CONFIG-ADDRESS),寄存器CFCh用于保存配置空间的读写数据(CONFIG-DATA)。
Config-address 配置空间如下图,我们在访问PCI空间时,就是按下图所示进行遍历。
寄存器号:选择配置空间中的一个双字(32位);
功能号:选择多功能设备中的某一个功能,有八种功能(0—7);
设备号:在一条总线上选择32个设备中的一个。0—31;
总线号:从系统256条总线中选择一条,共256条。0—255;
尽管理论上有256条总线,但实际PC机上的PCI插槽的总线号总是1,我们访问0到15就够了。二、遍历PCI
在windows下遍歷PCI,需用到winio.dll。
1、 配置CF8H配置空間。即,將第31位(使能位)置1,總號,設備號,功能號,寄存器號相等均置0,得到(二進制:10000000000000000000000000000000)(16進制:0x80000000)。
2、 確認需遍歷多少條BUS,設備號,功能號,從0開始。
3、 使用CF8H空間對PCI配置空間進行遍歷訪問。再利用位移方式,將bus號<<16,設備號<<11,功能號<<8和0x80000000相加得到值Reval。
4、 利用winio中的SetPortVal(0xcf8,Reval,4);再用GetPortVal到CFCH空間將遍歷的PCI值取回。Pci=GetPortVal(0xcfc).
5、 用Pci的值與0xffffffff進行比較,來半判斷設備是否存在。
代码如下:
#include
#include"winio.h"
#include "stdlib.h"
#include "stdio.h"
#define IO_AD 0xcf8
#define IO_DA 0xcfc
#pragma comment(lib,"winio.lib")
int main(int argc,CHAR *argv)
{
DWORD Bus_No,Dev,Func,Rt_Val,VID,DID,Class1,Class2,Class3,count=0;
if(InitializeWinIo())
{
printf("VID DID BUS# Dev# Fun#\n");
for(Bus_No=0;Bus_No<15;Bus_No++)
{
for(Dev=0;Dev<32;Dev++)
{
for(Func=0;Func<8;Func++)
{
DWORD Val=0x80000000+(Bus_No<<16)+(Dev<<11)+(Func<<8);
SetPortVal(IO_AD,Val,4);
GetPortVal(IO_DA,&Rt_Val,4);
if(Rt_Val!=0xffffffff)
{
count++;
VID=Rt_Val&0xffff;
DID=(Rt_Val>>16)&0xffff;
printf("%04X %04X %02X %02X %02x\n",VID,DID,Bus_No,Func,Dev);
if(Func==0)
{
Val=(Val&0xfffffff0)+0x0c;
SetPortVal(IO_AD,Val,4);
GetPortVal(IO_DA,&Rt_Val,4);
Rt_Val=Rt_Val>>16;
if((Rt_Val&0x80)==0)Func=8;
}
}
}
}
}
printf("Find PCI Device %d",count);
}
else
{
printf("Initialize Win IO Fail!\n");
exit(255);
}
return 0;
}
|
|