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中不允許'//'類型的代碼注釋,如上面代碼中的注釋只能使用'/**/'。