pci设备驱动开发,首先是要发现pci设备,从中获得pci设备的配置空间,并从中得到基本基本的资源信息。
首先进行pci设备查找的函数为:
STATUS pciFindDevice
(
int vendorId,
int deviceId,
int index,
int *pBusNo,
int *pDeviceNo,
int *pFuncNo
)
函数中的参数从命名来看都很好理解,注意第三个参数 ‘index’,这是在系统中有多个pci设备时我们需要从0开始查找,知道查找到我们想要驱动设备(第一个参数vendorId和第二个参数deviceId相同的设备)。
从参数列表中我们可以看到,后面三个参数都是指针类型,这三个参数就是唯一标识该pci设备的资源参数,也是我们在查找pci设备的时候需要获得该设备空间中的pci设备资源。
根据上面的说明我们可以写出这样的代码来查找pci设备:
int pciBus, pciDevice, pciFunc;
int found = 0;
int i;
for (i=0; i<DEV_MAX_NUM; i++) {
if (pciFindDevice(VENDOR_ID,DEVICE_ID,i,&pciBus,&pciDevice,&pciFunc)
== OK) {
found = TRUE;
printf("pci device found!\n");
break;
}
}
注:一定要保证VENDOR_ID,DEVICE_ID的正确性。可以将设备上电之后通过pciDeviceShow命令来查看系统中pci设备的详细信息。为了安全起见最好,打印设备已经找到的信息。如上例,如果找不到函数应该立刻返回。代码中的found就是用来预防找不到设备的情况。
当查找到对应的设备之后,我们需要获取该设备配置空间的基本资源。
DRV_CTRL * pDrvCtrl;
pDrvCtrl = calloc(1, sizeof(DRV_CTRL));
pDrvCtrl->pciBus = pciBus;
pDrvCtrl->pciDevice = pciDevice;
pDrvCtrl->pciFunc = pciFunc;
第一句是为该设备分配内存空间,其中DRV_CTRL的定义见“WindRiver驱动开发基础”这篇文章。
要访问pci设备空间有专门的访问控制函数,这里我们使用:
pciConfigInLong():从pci配置空间指定位置读取一个字长。
pciConfigInLong
(
int busNo,
int deviceNo,
int funcNo,
int offset,
UINT32 *pData
)
注:最后一个参数用于存放都会的数据
通过pciConfigInLong()函数我们需要获取下面的几个信息:IO地址,PCI设备地址,中断号。并且需要映射内存,使能I/O
代码如下:
UINT32 membaseCsr;
UINT32 iobaseCsr;
UINT8 irq;
pciConfigInLong(pDrvCtrl->pciBus, pDrvCtrl->pciDevice, pDrvCtrl->pciFunc,PCI_CFG_BASE_ADDRESS_0, &iobaseCsr);
pciConfigInLong(pDrvCtrl->pciBus, pDrvCtrl->pciDevice, pDrvCtrl->pciFunc,PCI_CFG_BASE_ADDRESS_1, &membaseCsr);
pciConfigInByte(pDrvCtrl->pciBus, pDrvCtrl->pciDevice, pDrvCtrl->pciFunc,PCI_CFG_DEV_INT_LINE, &irq);
pciConfigOutWord(pciBus, pciDevice, pciFunc, PCI_CFG_COMMAND,CI_CMD_IO_ENABLE | PCI_CMD_MEM_ENABLE | PCI_CMD_MASTER_ENABLE);
membaseCsr &=PCI_MEMBASE_MASK;
iobaseCsr &=PCI_IOBASE_MASK;
pDrvCtrl->membase = membaseCsr;
pDrvCtrl->iobase = iobaseCsr;
pDrvCtrl->created = 0;
pDrvCtrl->irq = irq;
/*为了便于后面使用IO地址将IO地址专门保存本起来*/
ioaddr = iobaseCsr;
至此pci设备的发现,设备空间的资源获取就完成,接下来的任务是创建设备,注册设备,与硬件通信等。
还需要注意的是WindRiver中不允许'//'类型的代码注释,如上面代码中的注释只能使用'/**/'。