您的位置:首页 > 其它

基于vxworks的PCI设备驱动编写

2014-04-26 18:40 513 查看
最近几天,我在为公司自研的PCI板卡写板卡驱动,板卡类型主要为串口卡,AD采集,DA输出,DIO等类型的常用板卡。硬件实现很简单,桥片PXI9054+FPGA结构。因为板卡功能主要为定制,不是商用,所以功能很简单,寄存器定义的很简单,驱动编写相对的很简单。

我使用的vxworks版本号为vxworks6.X, 考虑到兼容性(vxworks5.5),没有使用vxbus总线,另一方面,也没有使用vxbus的必要。将驱动文件和映像文件一起编译,就可以满足应用的使用。因为板卡驱动需要支持X86平台和PPC平台,所以需要综合考虑。

1. PCI设备初始化。

在vxworks中,使用接口pciFindDevice()根据VENDERID和DEVID 查找设备的BusNo, DeviceNo,FuncNo; 自研的设备号和版本号 是0x10b5和0x9054;

例:查找设备

if(pciFindDevice(DIO_VENDERID,

DIO_DEVID,

uchBoardNo, //板卡号()

&BusNo,

&DeviceNo,

&FuncNo) != OK)

{

printf("%s(Line:%d):Can not find the specified board! \n", __FUNCTION__, __LINE__);


return ERROR;

}


根据获取到的BusNo, DeviceNo,FuncNo, 调用接口 pciConfigInLong(BusNo, DeviceNo, FuncNo, BarOffset, pulBaseAddr); 获取bar的空间值(偏移地址)。 一般BAR0的值为操作PXI9054寄存器的基地址,BAR2的值为操作板卡寄存器的偏移地址;

注意:1. 获取到的偏移地址需要根据PCI协议标准,将低4bit去掉: *pulBaseAddr = (*pulBaseAddr) & (~0xf);

2. 根据获取到的偏移地址的最低位,判断访问板卡寄存的方式是IO访问,还是内存访问。1为IO访问,0:内存访问。在X86上,IO访问和内存访问是不一样的。IO访问使用接口sysInlong()。 内存访问使用#define SYSOUTLONG_MEM(addr, data) (*((volatile unsigned long *)(addr)) = (data)) 的方式,在PPC上,一般使用内存访问。

3. 往bar的地址写-1,然后再重新读取值,可以获取bar空间的大小。(我很少用。)

2. 使用第一步获取到的bar2地址,配置板卡的寄存器,这个比较简单。

有一点需要说明,在配置寄存器的时候,使用的寄存器操作接口,要根据IO访问和内存访问,不同的CPU平台确定接口。

我们自研的板卡都是内存访问,因为使用X86平台和PPC平台,有大小端的格式,分别定义了不通的接口。

/*寄存器空间映射在内存空间*/

#ifdef CPU_FAMILY_X86

#define SYSINBYTE_MEM(addr) *((volatile unsigned char *)(addr))

#define SYSOUTBYTE_MEM(addr, data) (*((volatile unsigned char *)(addr)) = (data))

#define SYSINWORD_MEM(addr) *((volatile unsigned short *)(addr))

#define SYSOUTWORD_MEM(addr, data) (*((volatile unsigned short *)(addr)) = (data))

#define SYSINLONG_MEM(addr) *((volatile unsigned long *)(addr))

#define SYSOUTLONG_MEM(addr, data) (*((volatile unsigned long *)(addr)) = (data))

#endif

PPC平台部分接口:

unsigned short SYSINWORD_PPC(addr)

{

unsigned short usData;

usData = sysIn16(addr);

usData = SWAPWORD(usData);

return usData;

}

unsigned long SYSINLONG_PPC(addr)

{

unsigned long ulData;

ulData = sysIn32(addr);

ulData = SWAPLONG(ulData);

return ulData;

}

3. 中断的挂接

X86和PPC平台有些区别;

X86主要接口为:

void IntDisable(int level)

{

sysIntDisablePIC(level);

}

void IntEnable(int level)

{

sysIntEnablePIC(level);

}

STATUS IntConnect(int level, VOIDFUNCPTR routine, int parameter)

{

return (pciIntConnect(INUM_TO_IVEC(INT_NUM_GET(level)), routine, parameter));//注意 中断号的转换

}

PPC主要接口:

STATUS intConnect (VOIDFUNCPTR * vector, VOIDFUNCPTR routine,

int parameter);

extern int intDisable (int);

extern int intEnable (int);

中断号获取: 根据总线号,设备号,功能号,查询PCI配置空间0x3c, 找到中断号;

pciConfigInByte(BusNo, DeviceNo, FuncNo, PLX9054_PCIILR, &ucIntNum);

注意: 在自研的PCI板卡中,桥片 PXI9054 有一个bit需要配置, 0x68的11bit,需要置为1, 支持local bus总线,否则不能产生中断。

在FPGA给中断信号的时候,使用电平触发比较合理,沿触发,会丢中断。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: