pci驱动与硬件通信
接上一篇博文,當將PCI設備空間的資源映射出來之后。只需要做兩件事情,PCI設備的基本框架就建立起來了。
首先注冊驅動程序,調用如下函數:
int iosDrvInstall() / STATUS iosDevAdd()
先來講int iosDrvInstall()函數:
Int iosDrvInstall(
FUNCPTR pCreate, FUNCPTR pDelete,
FUNCPTR pOpen, FUNCPTR pClose,
FUNCPTR pRead, FUNCPTR pWrite,
FUNCPTR pIoctl /*pointer to driver ioctl function*/
)
前面的文章已經提到過。除了最后一個參數之外,其它參數都可以為NULL,最后一個參數向系統注冊一個應用程序與驅動通信的函數。應用程序通過調用
(
int fd,
int request,
void *data
);
三個參數分別代表文件描述符,請求操作碼和需要傳往驅動的數據。
假設我們在函數iosDrvInstall()最后注冊的IOCtl函數為:pci_Ioctl()。
pci_Ioctl(int fd, int request, void *data)
注意:這里這個函數也需要包含三個參數,與ioctl的參數對應,當在應用層調用ioctl()函數的時候,ioctl()中的第三個參數就會根據文件描述符來識別出正確的設備并將與驅動通信的數據寫入到驅動中的IOCTL函數中,這里是:pci_Ioctl()。
pci_Ioctl()函數的大體框架如下:
LOCAL STATUS pci_Ioctl(int DevID,int request, void *arg){
…
Switch(request)
{
case(X1):
…
break;
case(X2):
…
break;
default:
…
}
return 1;
}
在每個分支針對傳進來的操作碼進行操作。操作碼一般是定義的宏,不同的操作我們定義一個不同的值來做標識。
在case語句中一般需要進行寄存器的寫入或者讀出,我們會用到下面的函數:
sysInLong(int port)sysOutLong(int port, long data)
其中sysInLong()函數用于從寄存器讀出數據,其中的參數為寄存器的地址。
sysOutLong()函數用于向寄存器port中寫入數據data。
還記得上面的pci_Ioctl()函數嗎,這個函數中的第三個參數就是用于讀出或者寫入數據。為了實現讀出或者寫入并使的這些數據能輕松在應用程序和驅動之間傳遞,這個參數最好入上面一樣申明為void *。
但是請注意:sysInLong (),sysOutLong()函數中的port參數雖然都代表寄存器地址,但是不能直接使用芯片手冊或者是FPGA設計者提供的地址,需要加一個設備基址,也就是上一篇文章中提到的“ioaddr”,這個地址是PCI設備空間的io基址。因此這兩個讀入和寫入函數一般會進行封裝,方便操作。
可以這樣做:
#define xxxDevice_Write(reg, value) sysOutLong(ioaddr+(reg), value)#define xxxDevice_Read(reg) ((unsigned int) sysInLong(ioaddr+(reg)))
?
之后就可以直接調用這兩個宏,用于寫入或者讀出了。
?
現在可以介紹
iosDevAdd(DEV_HDR *pDevHdr, char *name, int drvnum)
了,我們可以這樣來調用該函數:
其中第一個參數是設備抽象中的第一個參數,也就是內核中的數據結構:DEV_HDR(pDrvCtrl參見前面的文章);第二個參數是我們為設備取的名字,也就是一個字符串;第三個參數為iosDrvInstall()函數的返回值。因此我們需要先調用iosDrvInstall()函數,再調用iosDevAdd函數。
經過上面的介紹,驅動的大體框架就建立好了。具體的操作就根據具體情況來進行了。
本博客還會繼續介紹Windows下基于WDM的PCI設備驅動程序開發和Linux下的PCI驅動程序開發。如果有可能還會介紹Windows下WDF的PCI驅動程序的開發。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的pci驱动与硬件通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring mvc 3.0 入门及应用
- 下一篇: 加密解密技术—对称算法加密