转载的PCI驱动帖子整理

我有一块FPGA+PLX9030的继电器板,板的作用就是要通过上位机控制继电器的动作,在Windows平台下的驱动已经完成,并验证好用。现在想在运行有VxWorks5.5的Pentium3目标机上使用,则需要开发VxWorks的PCI驱动,目标机安装的是Tornado2.2版本。看了不少论文,里面提到了一些有用的思路,然后我就编写了下面的PCI设备初始化函数:
  int pciDevConfig()
{
  if(pciFindDevice(VENDOR_ID, DEVECE_ID, 0, (int *)&pciBus, (int *)&pciDev, (int *)&pciFunc) != OK)
  {
  logMsg("Device not found!\n", 0, 0, 0, 0, 0, 0);  
  return(ERROR);
  }
  logMsg("pciBus = %d!\n", pciBus, 0, 0, 0, 0, 0);
  logMsg("pciDev = %d!\n", pciDev, 0, 0, 0, 0, 0);
  logMsg("pciFunc = %d!\n", pciFunc, 0, 0, 0, 0, 0);

  pciConfigInLong (pciBus, pciDev, pciFunc, PCI_CFG_BASE_ADDRESS_2, (int *)&memBase); //9030使用的local address space 0
  logMsg("PCI_CFG_BASE_ADDRESS_2 = 0x%x!\n", memBase, 0, 0, 0, 0, 0);

  memBase &= PCI_MEMBASE_MASK;  

  pciConfigInLong (pciBus, pciDev, pciFunc, PCI_CFG_COMMAND, (int *)&nCommand);
  pciConfigOutLong(pciBus, pciDev, pciFunc, PCI_CFG_COMMAND,  
  nCommand | PCI_CMD_IO_ENABLE | PCI_CMD_MEM_ENABLE | PCI_CMD_MEM_ENABLE );  

  pciConfigInLong (pciBus, pciDev, pciFunc, PCI_CFG_MODE, (int *)&sleepMode);
  pciConfigOutLong(pciBus, pciDev, pciFunc, PCI_CFG_MODE, sleepMode | SLEEP_MODE_DIS);  

  if (sysMmuMapAdd(memBase, 0x2000,  
  VM_STATE_MASK_VALID | VM_STATE_MASK_WRITABLE |
  VM_STATE_MASK_CACHEABLE,
  VM_STATE_VALID | VM_STATE_WRITABLE |
  VM_STATE_CACHEABLE_NOT
  ) == ERROR)
  {
  printf("\nMmuMap Error\n");
  return ERROR;
  };

  return(OK);
}
在调试的时候,我是先将VxWorks镜像文件加载,然后启动Tornado,在新建的downloadable的项目中调用的这个函数,然后下载到目标机上执行。
我困惑的是:pciDevConfig必须是在硬件初始化的时候调用,即sysLib.c文件的sysHwInit()函数中调用吗?还有,即使我得到内存映射的地址,我怎么使用这个地址呢?
因为我使用的是内存空间,那么
  var = *((long *)memBase);
*((long *)memBase) = 0xXXXX;
这样就可以访问这片内存空间了吗?还是使用sysInWord、sysOutWord这类函数?

另外我可以在sysLib.c的PHYS_MEM_DESC sysPhysMemDesc结构体中手动指定PCI的内存映射地址吗,应该怎样实现?

这个问题困扰我好久了,希望有高手能够指点一二!  



1. 修改目标BSP目录下的sysLib.c文件中的sysHwInit()函数,如下所示:

#include "PlxPCI9056.h"

void sysHwInit (void)
{
  PHYS_MEM_DESC *pMmu;
  int ix = 0;
............................................
#ifdef INCLUDE_PCI
  pciConfigLibInit (PCI_MECHANISM_1, PCI_CONFIG_ADDR, PCI_CONFIG_DATA, NONE);
  sysPciIntInit (); /* it does pciIntLibInit() */

PCI_CAN_Init();

#endif /* INCLUDE_PCI */
.................................
}

注:
1) 在目标BSP目录下的Config.h文件中要将PCI相关的宏定义打开
在工程的设置中"VxWorks"选项卡中 hardware -> buses -> PCI configuration 包含此配置。
3) 函数PCI_CAN_Init()调用位置,必须在 PCI 初始化完成之后和在 MMU 初始化(usrMmuInit())完成之前插入此函数的调用,否则驱动程序不能工作。

2. sysInWord、sysOutWord: 这样的函数是读写IO端口用的!
内存映射方式读取,参考下面的函数:

/************************************************************************/
/*Function : 从ulPortAddr+ucRegister内存地址读取数据
/*Input : ulPortAddr, 端口号(即CAN-X通道基地址);  
/* ucRegister, 读取的数据(即CAN的寄存器);
/*Output : 从ulPortAddr+ucRegister内存地址读取数据
/*RetValue : 从ulPortAddr+ucRegister内存地址读取数据
/*Author : qcj_21 at [2010-8-10 10:54:32]
/************************************************************************/
UCHAR CANR(ULONG ulPortAddr, UCHAR ucRegister)
{
return *(volatile unsigned char*)(ulPortAddr+ucRegister) ;
}


/************************************************************************/
/*Function : 向ulPortAddr+ucRegister内存地址写数据
/*Input : ulPortAddr, 端口号(即CAN-X通道基地址);  
/* ucRegister, 写入的数据(即CAN的寄存器);
/* ucValue, 写入的数据(即CAN寄存器的设置值);
/*Output : 无
/*RetValue : 无
/*Author : qcj_21 at [2010-8-10 11:09:15]
/************************************************************************/
void CANW(ULONG ulPortAddr, UCHAR ucRegister, UCHAR ucValue)
{
*(volatile unsigned char*)(ulPortAddr+ucRegister) = ucValue;
}


3. 另外我可以在sysLib.c的PHYS_MEM_DESC sysPhysMemDesc结构体中手动指定PCI的内存映射地址吗,应该怎样实现?
  这个问题取决于你的PCI板卡,是静态映射还是动态映射,如果是静态映射需要在PHYS_MEM_DESC sysPhysMemDesc中手动添加映射地址,如果是动态映射,你需要读取PCI的配置空间获取。



首先感谢这位大哥的帮助,
除了“在工程的设置中"VxWorks"选项卡中 hardware -> buses -> PCI configuration 包含此配置。”这个设置没有进行,其他的我都做了。

另外我还有个问题,如果PCI设备初始化函数是在sysLib.c中调用的,那么他就应该是在BSP文件夹中,那么我在这里得到的内存映射地址memBase在应用程序层面上怎么用啊,这个变量memBase应用程序根本看不到啊?
我开始是将mypciDevInit()函数写在mypciDevInit.c中,然后将mypciDevInit.c放在BSP路径下(pvPentium文件夹),编译没有问题,我就将基于这个BSP的bootable的项目新生成的VxWorks镜像重新引导启动(BootRom也重新制作了);接着开始编写应用程序,我又新建一个downloadable的项目,对pci内存进行读写,此时我想使用memBase这个变量,不知道怎么用啊?

也可能是我理解有问题,希望能够再指点一下。


这个问题如下:
/************************************************************************/
/*Function : 得到PlxPCI9056信息,即内存映射基地址和映射空间大小,IO空间基地址,中断号
/*Input : pnMemBaseAddress,内存映射基地址
/* pnIOBaseAddress, IO空间基地址
/* pnCAN_IRQNum, PCI9056总占用中断号
/* pnMemSpaceLen, 映射空间大小
/*Output : 无
/*RetValue : 无
/*Author : qcj_21 at [2010-9-28 15:17:29]
/************************************************************************/
void GetPlxPCI9056Info(UINT32 *pnMemBaseAddress,  
UINT32 *pnIOBaseAddress,
UINT32 *pnCAN_IRQNum,  
UINT32 *pnMemSpaceLen)
{
*pnMemBaseAddress = g_nMemBaseAddress;
*pnIOBaseAddress = g_nIOBaseAddress;
*pnCAN_IRQNum = g_nCAN_IRQNum;
*pnMemSpaceLen = g_nMemSpaceLen;

}

建议你先在windows平台下,用windriver提供的工具,先看一下映射的空间地址和中断号!



你可能感兴趣的:(windows,function,command,input,include,output)