《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 嵌入式技術(shù) > 設(shè)計(jì)應(yīng)用 > Linux下基于PCI-E時(shí)統(tǒng)卡的驅(qū)動(dòng)程序設(shè)計(jì)
Linux下基于PCI-E時(shí)統(tǒng)卡的驅(qū)動(dòng)程序設(shè)計(jì)
2015年微型機(jī)與應(yīng)用第24期
劉 凱,胡愛(à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)程序的可行性。
Abstract:
Key words :

  摘  要: 簡(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)程序的可行性。

  關(guān)鍵詞: 設(shè)備驅(qū)動(dòng);Linux;PCI-Express;PEX8311;DMA

0 引言

  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ò)程。

1 PCI-E時(shí)統(tǒng)卡

  本文中使用的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ī)終端中。

001.jpg

2 Linux設(shè)備驅(qū)動(dòng)程序

002.jpg

  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)大的作用。

3 Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)過(guò)程

  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)、類別和類別掩碼。初始化代碼如下。

  static struct pci_device_id PlxPciIdTable()=

  {

  #if(PLX_CHIP==8311)

  {0x10B5,0x8311,PCI_ANY_ID,PCI_ANY_ID,0x000000,0x000000},

  {0x10B5,0x86E1,PCI_ANY_ID,PCI_ANY_ID,0x000000,0x000000},

  #endif

  };

  MODULE_DEVICE_TABLE(pci,PlxPciIdTable);

  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)銷。驅(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è)備不支持中斷,則只能采用輪詢的方式來(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í)別并解析出不同的中斷*/

  status=inb(PLXPCI_IRQ_REG(dev));

  if(status)

  {

  /*識(shí)別20 Hz中斷*/

  if(status&IRQ_FLAG_20 Hz)

  {

  ……

  }

  ……

  /*通知調(diào)度函數(shù)向應(yīng)用層軟件發(fā)送中斷信號(hào)*/

  tasklet_schedule(&dev->tlet);

  }

  return(IRQ_HANDLED);

  }

4 驅(qū)動(dòng)程序的測(cè)試

  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é)果

003.jpg


  測(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ù)。

5 結(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)的可用性。

  參考文獻(xiàn)

  [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.


此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。