劉 凱,胡愛蘭(華北計(jì)算機(jī)系統(tǒng)工程研究所,北京 100083)
Linux 下基于PC I-E時(shí)統(tǒng)卡的驅(qū)動(dòng)程序設(shè)計(jì)
劉 凱,胡愛蘭
(華北計(jì)算機(jī)系統(tǒng)工程研究所,北京 100083)
簡要介紹了Linux操作系統(tǒng)和PCI-Express(PCI-E)總線的特點(diǎn)以及Linux設(shè)備驅(qū)動(dòng)的作用。以PEX8311時(shí)統(tǒng)卡為例,闡述了Linux系統(tǒng)下PCI-E驅(qū)動(dòng)程序開發(fā)的流程和技巧,并通過DMA模式測試了驅(qū)動(dòng)程序的可行性。
設(shè)備驅(qū)動(dòng);Linux;PCI-Express;PEX8311;DMA
Linux操作系統(tǒng)憑借其開放的源代碼、良好的擴(kuò)展性以及安全高效等特點(diǎn),受到越來越多領(lǐng)域開發(fā)者的重視,并逐步成為各種計(jì)算機(jī)終端、服務(wù)器工作站及嵌入式平臺的主流操作系統(tǒng)。PCI-Express(PCI-E)作為最新一代的總線接口,其點(diǎn)對點(diǎn)的串行設(shè)計(jì)以及雙通道高帶寬的傳輸模式,大大提高了數(shù)據(jù)的傳輸速率[1],它的廣泛應(yīng)用將全面取代PCI、AGP等總線。
目前基于Linux平臺下的 PCI-E總線的應(yīng)用十分廣泛,小到微型嵌入式系統(tǒng),大到超大型服務(wù)器系統(tǒng),都可以看到二者的完美結(jié)合。而驅(qū)動(dòng)程序作為硬件設(shè)備與操作系統(tǒng)之間的橋梁,對硬件的工作起著至關(guān)重要的作用。本文介紹的是Linux下基于PCI-E時(shí)統(tǒng)卡的驅(qū)動(dòng)程序的開發(fā)過程。
本文中使用的PCI-E時(shí)統(tǒng)卡是自主研發(fā)的一款硬件設(shè)備。該時(shí)統(tǒng)卡通過接受B碼終端發(fā)來的信號,然后經(jīng)FPGA進(jìn)行解碼,獲得時(shí)間信息,并以1 pps脈沖為基準(zhǔn)產(chǎn)生用戶所需要的 20 Hz、100 Hz等中斷脈沖信號,最后通過PCI-E橋接芯片PEX8311進(jìn)行數(shù)據(jù)交互,使得時(shí)統(tǒng)卡中的時(shí)間信息以及中斷信息能夠傳到計(jì)算機(jī)終端或服務(wù)器中。而要想讓安裝在計(jì)算機(jī)終端或者服務(wù)器中的時(shí)統(tǒng)卡能夠正常工作,就需要為其開發(fā)配套的驅(qū)動(dòng)程序,主要就是針對PEX8311芯片的驅(qū)動(dòng)。圖1所示為時(shí)統(tǒng)卡PEX8311芯片的結(jié)構(gòu)簡圖。數(shù)據(jù)經(jīng)由PFGA傳到Local Bus,然后通過內(nèi)部總線再到 PCI-E總線,最后傳到計(jì)算機(jī)終端中。
圖1 時(shí)統(tǒng)卡PEX8311芯片的結(jié)構(gòu)簡圖
Linux設(shè)備驅(qū)動(dòng)程序是一種使計(jì)算機(jī)軟件與硬件設(shè)備進(jìn)行交互的特殊程序。圖2所示為Linux設(shè)備驅(qū)動(dòng)與操作系統(tǒng)及外設(shè)的關(guān)系。設(shè)備驅(qū)動(dòng)程序位于Linux操作系統(tǒng)的內(nèi)核空間,它相當(dāng)于操作系統(tǒng)內(nèi)核空間與物理層硬件設(shè)備之間的接口,它還為用戶層提供系統(tǒng)調(diào)用的接口函數(shù)。用戶層的應(yīng)用程序不能直接訪問操作物理層的外部硬件設(shè)備,只有通過系統(tǒng)調(diào)用才可以訪問操作外部硬件設(shè)備[2]。因此可以看出設(shè)備驅(qū)動(dòng)程序在操作系統(tǒng)中起到了相當(dāng)大的作用。
圖2 Linux設(shè)備驅(qū)動(dòng)與操作系統(tǒng)及外設(shè)的關(guān)系
Linux設(shè)備驅(qū)動(dòng)程序的編寫可以模塊化,主要包括:設(shè)備的初始化、驅(qū)動(dòng)模塊的加載與卸載、設(shè)備的打開與釋放、數(shù)據(jù)讀寫與操作、中斷響應(yīng)。
3.1 設(shè)備的初始化
Linux系統(tǒng)啟動(dòng)后會(huì)自動(dòng)檢測計(jì)算機(jī)終端上所有的PCI-E設(shè)備的信息,并記錄在pci_dev結(jié)構(gòu)體中,其中包括硬件設(shè)備的廠商號、設(shè)備號等大部分的硬件信息。PCI-E驅(qū)動(dòng)程序就是根據(jù)廠商號和設(shè)備號來連接設(shè)備并加載驅(qū)動(dòng)的,這就需要在驅(qū)動(dòng)程序中定義該驅(qū)動(dòng)所支持的硬件參數(shù)信息。本文中使用的時(shí)統(tǒng)卡的PCI-E橋接芯片是 PEX8311,其硬件參數(shù)信息定義分別為廠商號、設(shè)備號、子廠商號、子設(shè)備號、類別和類別掩碼。初始化代碼如下。
3.2 驅(qū)動(dòng)模塊的加載與卸載
硬件設(shè)備驅(qū)動(dòng)的加載,必須要有一個(gè)主設(shè)備號。設(shè)備號的分配有兩種方式:靜態(tài)分配和動(dòng)態(tài)分配。靜態(tài)分配指的是由開發(fā)人員指定一個(gè)固定的設(shè)備號;動(dòng)態(tài)分配則是由操作系統(tǒng)自動(dòng)分配設(shè)備號。在不能明確某設(shè)備號是否被使用的情況下,建議使用動(dòng)態(tài)分配的方式獲得設(shè)備號,這樣就避免了因設(shè)備號沖突導(dǎo)致硬件設(shè)備不能正常工作的情況出現(xiàn)。分配了設(shè)備號就可以注冊設(shè)備并加載設(shè)備驅(qū)動(dòng)了。而當(dāng)該設(shè)備不再使用時(shí),可以將該設(shè)備的驅(qū)動(dòng)模塊卸載掉,以此來減少系統(tǒng)內(nèi)核的占用以及其他系統(tǒng)資源的開銷。驅(qū)動(dòng)模塊加載與卸載的代碼如下。
//驅(qū)動(dòng)模塊的加載
static int__init plxpci_init(void)
{
……
/*注冊設(shè)備,register_chrdev函數(shù)的第一個(gè)參數(shù)為 0,表示系統(tǒng)自動(dòng)分配一個(gè)空閑的主設(shè)備號*/
card->MajorID=register_chrdev(0,PLX_DRIVER_NAME,&plxpci_fops);
pci_register_driver(&PlxPciDriver);
……
}
//驅(qū)動(dòng)模塊的卸載
static void__exit plxpci_cleanup(void)
{
unregister_chrdev(major,PLX_DRIVER_NAME);
pci_unregister_driver(&plxpci_driver);
}
3.3 設(shè)備的打開與釋放
Linux系統(tǒng)內(nèi)核在驅(qū)動(dòng)模塊加載之后就可以打開硬件設(shè)備。設(shè)備的打開模塊主要是獲取設(shè)備的控制權(quán),允許中斷的產(chǎn)生等。而當(dāng)不再使用該設(shè)備時(shí),就需要釋放該設(shè)備。設(shè)備的釋放模塊的任務(wù)與設(shè)備的打開模塊的任務(wù)正好相反,主要是釋放對設(shè)備的控制權(quán)、中斷以及之前系統(tǒng)分配的一些資源等。設(shè)備打開與釋放的代碼如下。
//設(shè)備的打開
static int plxpci_open(struct inode*inode,struct file*file)
{
……
/*獲取設(shè)備的控制權(quán) */
dev->open_mode|=file->f_mode&(FMODE_READ| FMODE_WRITE);
/*允許中斷產(chǎn)生*/
plxpci_enable_IRQ(dev);
return 0;
}
//設(shè)備的釋放
static int plxpci_release(struct inode*inode,struct file*file)
{
……
/*釋放對設(shè)備的控制權(quán) */
dev->open_mode&=(~file->f_mode)&(FMODE_READ| FMODE_WRITE);
free_irq(card->irq,card);
kfree(card);
return0;
}
3.4 數(shù)據(jù)讀寫與操作
本文中驅(qū)動(dòng)程序使用的是DMA(Direct Memory Access)傳輸模式。DMA傳輸模式無需計(jì)算機(jī)或本地控制器的干預(yù),傳輸效率很高,從而大大降低了控制器的工作量且提高了數(shù)據(jù)的傳輸速率及效率[3]。要完成 DMA傳輸模式就需要了解時(shí)統(tǒng)卡上主要的PCI-E橋接芯片PEX8311的工作模式。從參考文獻(xiàn)[4]中可知,PEX8311芯片中有幾個(gè)重要的寄存器:(1)LCS_DMAMODE0,地址是80h,該寄存器主要用來設(shè)置DMA的模式。(2)LCS_DMADPR0,地址是 90h,該寄存器主要用來設(shè)置 DMA的傳輸方向。當(dāng)LCS_DMADPR0[3]=1,表示傳輸方向從Local Bus到PCI-E,若為0,則方向相反。(3)LCS_DMACSR0,地址是A8h,該寄存器主要用來啟動(dòng)DMA傳輸。成功設(shè)置了DMA的傳輸模式,就可以從時(shí)統(tǒng)卡中讀出時(shí)間信息。DMA傳輸?shù)拇a如下。
//DMA傳輸模式
{
……
/*設(shè)置DMA傳輸方向*/
PlxPci_PlxRegisterWrite(pDevice,0x90,SglPciAddress|(1<<0)|(1<<3));
/*設(shè)置DMA模式*/
PlxPci_PlxRegisterWrite(pDevice,0x80,0x00020642);
/*啟動(dòng)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 中斷響應(yīng)
中斷是 Linux系統(tǒng)中非常寶貴的資源,任何驅(qū)動(dòng)程序都需要申請中斷并注冊中斷處理才可以使用中斷。可以使用中斷的方式來讀取硬件設(shè)備中的數(shù)據(jù)。而如果硬件設(shè)備不支持中斷,則只能采用輪詢的方式來讀取數(shù)據(jù)。硬件設(shè)備中一般包含好幾種不同的中斷,例如1 Hz、20 Hz、100 Hz等。因此,當(dāng)讀取中斷狀態(tài)位之后還需要將不同的中斷識別區(qū)分開來才能使用。另外,為方便用戶層的應(yīng)用軟件對中斷的使用,使用信號機(jī)制來向用戶層發(fā)送中斷信號,通知用戶層的應(yīng)用軟件獲取中斷狀態(tài)位。中斷響應(yīng)程序如下。
//中斷響應(yīng)
irq_handler_t plxpci_interrupt(int irq,void*dev_id,struct pt_regs*regs)
{
……
/*讀取中斷狀態(tài)位,其中包含多種中斷,需要在下一步識別并解析出不同的中斷*/
/*通知調(diào)度函數(shù)向應(yīng)用層軟件發(fā)送中斷信號*/
tasklet_schedule(&dev->tlet);
}
return(IRQ_HANDLED);
}
4.1 驅(qū)動(dòng)程序的加載
本文中開發(fā)及測試平臺所使用的操作系統(tǒng)是中標(biāo)麒麟 Linux操作系統(tǒng),該系統(tǒng)的內(nèi)核版本是 2.6.32。Linux下驅(qū)動(dòng)程序模塊的加載通常有動(dòng)態(tài)加載和靜態(tài)加載兩種方式。靜態(tài)加載就是把編譯生成的驅(qū)動(dòng)程序文件plx8311.ko編譯到內(nèi)核中,每次系統(tǒng)啟動(dòng)時(shí)自動(dòng)調(diào)用,這種方式比較適合最終版本的驅(qū)動(dòng)程序。動(dòng)態(tài)加載就是通過insmod命令加載驅(qū)動(dòng)程序,通過rmmod命令可以卸載驅(qū)動(dòng)程序,這樣隨時(shí)可以修改驅(qū)動(dòng)程序,對于還在調(diào)試階段的程序比較方便。
4.2 測試過程與結(jié)果
測試前首先保證在計(jì)算機(jī)終端中安裝好時(shí)統(tǒng)卡,并連接B碼終端,然后加載驅(qū)動(dòng)程序,使用 lsmod命令查看驅(qū)動(dòng)程序是否已經(jīng)加載好。圖3所示為plx8311驅(qū)動(dòng)加載成功。當(dāng)驅(qū)動(dòng)程序可以正常加載,并且能夠通過測試程序讀出時(shí)統(tǒng)卡中的時(shí)間信息和中斷信息,則說明編寫的驅(qū)動(dòng)程序是可行的。圖4所示為測試結(jié)果,前面顯示的是從時(shí)統(tǒng)卡中讀出的當(dāng)前時(shí)間,后面3個(gè)數(shù)字表示從啟動(dòng)測試程序到當(dāng)前時(shí)刻所獲得的1 Hz、20 Hz、100 Hz中斷信號的個(gè)數(shù)。
圖3 驅(qū)動(dòng)加載成功
圖4 測試結(jié)果
Linux系統(tǒng)的開源性加上 PCI-E總線在計(jì)算機(jī)系統(tǒng)中的廣泛應(yīng)用,使得其兩者的結(jié)合越來越緊密,Linux系統(tǒng)下的PCI-E的驅(qū)動(dòng)開發(fā)也得到了廣泛的關(guān)注。本文結(jié)合實(shí)際項(xiàng)目開發(fā),通過對PEX8311時(shí)統(tǒng)卡的驅(qū)動(dòng)程序編寫過程中的各模塊的介紹,闡述了整個(gè)驅(qū)動(dòng)的開發(fā)流程和相關(guān)技巧,并通過編寫測試程序完成了驅(qū)動(dòng)程序的測試工作,驗(yàn)證了驅(qū)動(dòng)的可用性。
[1]BUDRUK R,ANDERSON D,SHANLEY T.PCI Express系統(tǒng)體系結(jié)構(gòu)標(biāo)準(zhǔn)教材[M].田玉敏,王崧,張波,譯.北京:電子工業(yè)出版社,2005.
[2]鄭強(qiáng).Linux驅(qū)動(dòng)開發(fā)入門與實(shí)踐[M].北京:清華大學(xué)出版社,2010.
[3]范晶,胡愛蘭.基于狀態(tài)機(jī)的 PEX8311的 DMA實(shí)現(xiàn)[J].微型機(jī)與應(yīng)用,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時(shí)統(tǒng)卡的驅(qū)動(dòng)程序設(shè)計(jì)[J].微型機(jī)與應(yīng)用,2015,34(24):13-15,18.
2015-06-23)
劉凱(1989-),男,碩士研究生,主要研究方向:Linux下嵌入式硬件驅(qū)動(dòng)。
胡愛蘭(1973-),女,高級工程師,主要研究方向:通信、信息處理及計(jì)算機(jī)應(yīng)用。