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