劉 凱,胡愛蘭(華北計算機系統工程研究所,北京 100083)
Linux 下基于PC I-E時統卡的驅動程序設計
劉 凱,胡愛蘭
(華北計算機系統工程研究所,北京 100083)
簡要介紹了Linux操作系統和PCI-Express(PCI-E)總線的特點以及Linux設備驅動的作用。以PEX8311時統卡為例,闡述了Linux系統下PCI-E驅動程序開發的流程和技巧,并通過DMA模式測試了驅動程序的可行性。
設備驅動;Linux;PCI-Express;PEX8311;DMA
Linux操作系統憑借其開放的源代碼、良好的擴展性以及安全高效等特點,受到越來越多領域開發者的重視,并逐步成為各種計算機終端、服務器工作站及嵌入式平臺的主流操作系統。PCI-Express(PCI-E)作為最新一代的總線接口,其點對點的串行設計以及雙通道高帶寬的傳輸模式,大大提高了數據的傳輸速率[1],它的廣泛應用將全面取代PCI、AGP等總線。
目前基于Linux平臺下的 PCI-E總線的應用十分廣泛,小到微型嵌入式系統,大到超大型服務器系統,都可以看到二者的完美結合。而驅動程序作為硬件設備與操作系統之間的橋梁,對硬件的工作起著至關重要的作用。本文介紹的是Linux下基于PCI-E時統卡的驅動程序的開發過程。
本文中使用的PCI-E時統卡是自主研發的一款硬件設備。該時統卡通過接受B碼終端發來的信號,然后經FPGA進行解碼,獲得時間信息,并以1 pps脈沖為基準產生用戶所需要的 20 Hz、100 Hz等中斷脈沖信號,最后通過PCI-E橋接芯片PEX8311進行數據交互,使得時統卡中的時間信息以及中斷信息能夠傳到計算機終端或服務器中。而要想讓安裝在計算機終端或者服務器中的時統卡能夠正常工作,就需要為其開發配套的驅動程序,主要就是針對PEX8311芯片的驅動。圖1所示為時統卡PEX8311芯片的結構簡圖。數據經由PFGA傳到Local Bus,然后通過內部總線再到 PCI-E總線,最后傳到計算機終端中。

圖1 時統卡PEX8311芯片的結構簡圖
Linux設備驅動程序是一種使計算機軟件與硬件設備進行交互的特殊程序。圖2所示為Linux設備驅動與操作系統及外設的關系。設備驅動程序位于Linux操作系統的內核空間,它相當于操作系統內核空間與物理層硬件設備之間的接口,它還為用戶層提供系統調用的接口函數。用戶層的應用程序不能直接訪問操作物理層的外部硬件設備,只有通過系統調用才可以訪問操作外部硬件設備[2]。因此可以看出設備驅動程序在操作系統中起到了相當大的作用。

圖2 Linux設備驅動與操作系統及外設的關系
Linux設備驅動程序的編寫可以模塊化,主要包括:設備的初始化、驅動模塊的加載與卸載、設備的打開與釋放、數據讀寫與操作、中斷響應。
3.1 設備的初始化
Linux系統啟動后會自動檢測計算機終端上所有的PCI-E設備的信息,并記錄在pci_dev結構體中,其中包括硬件設備的廠商號、設備號等大部分的硬件信息。PCI-E驅動程序就是根據廠商號和設備號來連接設備并加載驅動的,這就需要在驅動程序中定義該驅動所支持的硬件參數信息。本文中使用的時統卡的PCI-E橋接芯片是 PEX8311,其硬件參數信息定義分別為廠商號、設備號、子廠商號、子設備號、類別和類別掩碼。初始化代碼如下。
3.2 驅動模塊的加載與卸載
硬件設備驅動的加載,必須要有一個主設備號。設備號的分配有兩種方式:靜態分配和動態分配。靜態分配指的是由開發人員指定一個固定的設備號;動態分配則是由操作系統自動分配設備號。在不能明確某設備號是否被使用的情況下,建議使用動態分配的方式獲得設備號,這樣就避免了因設備號沖突導致硬件設備不能正常工作的情況出現。分配了設備號就可以注冊設備并加載設備驅動了。而當該設備不再使用時,可以將該設備的驅動模塊卸載掉,以此來減少系統內核的占用以及其他系統資源的開銷。驅動模塊加載與卸載的代碼如下。
//驅動模塊的加載
static int__init plxpci_init(void)
{
……
/*注冊設備,register_chrdev函數的第一個參數為 0,表示系統自動分配一個空閑的主設備號*/
card->MajorID=register_chrdev(0,PLX_DRIVER_NAME,&plxpci_fops);
pci_register_driver(&PlxPciDriver);
……
}
//驅動模塊的卸載
static void__exit plxpci_cleanup(void)
{
unregister_chrdev(major,PLX_DRIVER_NAME);
pci_unregister_driver(&plxpci_driver);
}
3.3 設備的打開與釋放
Linux系統內核在驅動模塊加載之后就可以打開硬件設備。設備的打開模塊主要是獲取設備的控制權,允許中斷的產生等。而當不再使用該設備時,就需要釋放該設備。設備的釋放模塊的任務與設備的打開模塊的任務正好相反,主要是釋放對設備的控制權、中斷以及之前系統分配的一些資源等。設備打開與釋放的代碼如下。
//設備的打開
static int plxpci_open(struct inode*inode,struct file*file)
{
……
/*獲取設備的控制權 */
dev->open_mode|=file->f_mode&(FMODE_READ| FMODE_WRITE);
/*允許中斷產生*/
plxpci_enable_IRQ(dev);
return 0;
}
//設備的釋放
static int plxpci_release(struct inode*inode,struct file*file)
{
……
/*釋放對設備的控制權 */
dev->open_mode&=(~file->f_mode)&(FMODE_READ| FMODE_WRITE);
free_irq(card->irq,card);
kfree(card);
return0;
}
3.4 數據讀寫與操作
本文中驅動程序使用的是DMA(Direct Memory Access)傳輸模式。DMA傳輸模式無需計算機或本地控制器的干預,傳輸效率很高,從而大大降低了控制器的工作量且提高了數據的傳輸速率及效率[3]。要完成 DMA傳輸模式就需要了解時統卡上主要的PCI-E橋接芯片PEX8311的工作模式。從參考文獻[4]中可知,PEX8311芯片中有幾個重要的寄存器:(1)LCS_DMAMODE0,地址是80h,該寄存器主要用來設置DMA的模式。(2)LCS_DMADPR0,地址是 90h,該寄存器主要用來設置 DMA的傳輸方向。當LCS_DMADPR0[3]=1,表示傳輸方向從Local Bus到PCI-E,若為0,則方向相反。(3)LCS_DMACSR0,地址是A8h,該寄存器主要用來啟動DMA傳輸。成功設置了DMA的傳輸模式,就可以從時統卡中讀出時間信息。DMA傳輸的代碼如下。
//DMA傳輸模式
{
……
/*設置DMA傳輸方向*/
PlxPci_PlxRegisterWrite(pDevice,0x90,SglPciAddress|(1<<0)|(1<<3));
/*設置DMA模式*/
PlxPci_PlxRegisterWrite(pDevice,0x80,0x00020642);
/*啟動DMA傳輸*/
RegValue=PlxPci_PlxRegisterRead(pDevice,0xA8,NULL);
RegValue|=(1<<0);
PlxPci_PlxRegisterWrite(pDevice,0xA8,RegValue);
RegValue|=(1<<1);
PlxPci_PlxRegisterWrite(pDevice,0xA8,RegValue);
……
}
3.5 中斷響應
中斷是 Linux系統中非常寶貴的資源,任何驅動程序都需要申請中斷并注冊中斷處理才可以使用中斷。可以使用中斷的方式來讀取硬件設備中的數據。而如果硬件設備不支持中斷,則只能采用輪詢的方式來讀取數據。硬件設備中一般包含好幾種不同的中斷,例如1 Hz、20 Hz、100 Hz等。因此,當讀取中斷狀態位之后還需要將不同的中斷識別區分開來才能使用。另外,為方便用戶層的應用軟件對中斷的使用,使用信號機制來向用戶層發送中斷信號,通知用戶層的應用軟件獲取中斷狀態位。中斷響應程序如下。
//中斷響應
irq_handler_t plxpci_interrupt(int irq,void*dev_id,struct pt_regs*regs)
{
……
/*讀取中斷狀態位,其中包含多種中斷,需要在下一步識別并解析出不同的中斷*/


/*通知調度函數向應用層軟件發送中斷信號*/
tasklet_schedule(&dev->tlet);
}
return(IRQ_HANDLED);
}
4.1 驅動程序的加載
本文中開發及測試平臺所使用的操作系統是中標麒麟 Linux操作系統,該系統的內核版本是 2.6.32。Linux下驅動程序模塊的加載通常有動態加載和靜態加載兩種方式。靜態加載就是把編譯生成的驅動程序文件plx8311.ko編譯到內核中,每次系統啟動時自動調用,這種方式比較適合最終版本的驅動程序。動態加載就是通過insmod命令加載驅動程序,通過rmmod命令可以卸載驅動程序,這樣隨時可以修改驅動程序,對于還在調試階段的程序比較方便。
4.2 測試過程與結果
測試前首先保證在計算機終端中安裝好時統卡,并連接B碼終端,然后加載驅動程序,使用 lsmod命令查看驅動程序是否已經加載好。圖3所示為plx8311驅動加載成功。當驅動程序可以正常加載,并且能夠通過測試程序讀出時統卡中的時間信息和中斷信息,則說明編寫的驅動程序是可行的。圖4所示為測試結果,前面顯示的是從時統卡中讀出的當前時間,后面3個數字表示從啟動測試程序到當前時刻所獲得的1 Hz、20 Hz、100 Hz中斷信號的個數。

圖3 驅動加載成功

圖4 測試結果
Linux系統的開源性加上 PCI-E總線在計算機系統中的廣泛應用,使得其兩者的結合越來越緊密,Linux系統下的PCI-E的驅動開發也得到了廣泛的關注。本文結合實際項目開發,通過對PEX8311時統卡的驅動程序編寫過程中的各模塊的介紹,闡述了整個驅動的開發流程和相關技巧,并通過編寫測試程序完成了驅動程序的測試工作,驗證了驅動的可用性。
[1]BUDRUK R,ANDERSON D,SHANLEY T.PCI Express系統體系結構標準教材[M].田玉敏,王崧,張波,譯.北京:電子工業出版社,2005.
[2]鄭強.Linux驅動開發入門與實踐[M].北京:清華大學出版社,2010.
[3]范晶,胡愛蘭.基于狀態機的 PEX8311的 DMA實現[J].微型機與應用,2014,33(22):30-33.
[4]PLX.PEX8311 AA data book version 1.0[OL].[2015-04-15].http://www.plxtech.com/mydata.
Design of driver based on PCI-E tim ing card on Linux
Liu Kai,Hu Ailan
(National Computer System Engineering Research Institute of China,Beijing 100083,China)
This paper briefly introduces the characteristics of Linux OS and PCI-Express(PCI-E)bus and the functions of device drivers on Linux.Case in timing card based on PEX8311,this paper elaborates the development processes and skills of PCIE drivers on Linux,and tests the feasibility of the drivers by DMA.
device driver;Linux;PCI-Express;PEX8311;DMA
TP311.1
A
1674-7720(2015)24-0013-03
劉凱,胡愛蘭.Linux下基于PCI-E時統卡的驅動程序設計[J].微型機與應用,2015,34(24):13-15,18.
2015-06-23)
劉凱(1989-),男,碩士研究生,主要研究方向:Linux下嵌入式硬件驅動。
胡愛蘭(1973-),女,高級工程師,主要研究方向:通信、信息處理及計算機應用。