《電子技術(shù)應用》
您所在的位置:首頁 > 嵌入式技術(shù) > 設計應用 > Linux下基于PCI-E時統(tǒng)卡的驅(qū)動程序設計
Linux下基于PCI-E時統(tǒng)卡的驅(qū)動程序設計
2015年微型機與應用第24期
劉 凱,胡愛蘭
(華北計算機系統(tǒng)工程研究所,北京 100083)
摘要: 簡要介紹了Linux操作系統(tǒng)和PCI-Express(PCI-E)總線的特點以及Linux設備驅(qū)動的作用。以PEX8311時統(tǒng)卡為例,闡述了Linux系統(tǒng)下PCI-E驅(qū)動程序開發(fā)的流程和技巧,并通過DMA模式測試了驅(qū)動程序的可行性。
Abstract:
Key words :

  摘  要: 簡要介紹了Linux操作系統(tǒng)和PCI-Express(PCI-E)總線的特點以及Linux設備驅(qū)動的作用。以PEX8311時統(tǒng)卡為例,闡述了Linux系統(tǒng)下PCI-E驅(qū)動程序開發(fā)的流程和技巧,并通過DMA模式測試了驅(qū)動程序的可行性。

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

0 引言

  Linux操作系統(tǒng)憑借其開放的源代碼、良好的擴展性以及安全高效等特點,受到越來越多領(lǐng)域開發(fā)者的重視,并逐步成為各種計算機終端、服務器工作站及嵌入式平臺的主流操作系統(tǒng)。PCI-Express(PCI-E)作為最新一代的總線接口,其點對點的串行設計以及雙通道高帶寬的傳輸模式,大大提高了數(shù)據(jù)的傳輸速率[1],它的廣泛應用將全面取代PCI、AGP等總線。

  目前基于Linux平臺下的PCI-E總線的應用十分廣泛,小到微型嵌入式系統(tǒng),大到超大型服務器系統(tǒng),都可以看到二者的完美結(jié)合。而驅(qū)動程序作為硬件設備與操作系統(tǒng)之間的橋梁,對硬件的工作起著至關(guān)重要的作用。本文介紹的是Linux下基于PCI-E時統(tǒng)卡的驅(qū)動程序的開發(fā)過程。

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

  本文中使用的PCI-E時統(tǒng)卡是自主研發(fā)的一款硬件設備。該時統(tǒng)卡通過接受B碼終端發(fā)來的信號,然后經(jīng)FPGA進行解碼,獲得時間信息,并以1 pps脈沖為基準產(chǎn)生用戶所需要的20 Hz、100 Hz等中斷脈沖信號,最后通過PCI-E橋接芯片PEX8311進行數(shù)據(jù)交互,使得時統(tǒng)卡中的時間信息以及中斷信息能夠傳到計算機終端或服務器中。而要想讓安裝在計算機終端或者服務器中的時統(tǒng)卡能夠正常工作,就需要為其開發(fā)配套的驅(qū)動程序,主要就是針對PEX8311芯片的驅(qū)動。圖1所示為時統(tǒng)卡PEX8311芯片的結(jié)構(gòu)簡圖。數(shù)據(jù)經(jīng)由PFGA傳到Local Bus,然后通過內(nèi)部總線再到PCI-E總線,最后傳到計算機終端中。

001.jpg

2 Linux設備驅(qū)動程序

002.jpg

  Linux設備驅(qū)動程序是一種使計算機軟件與硬件設備進行交互的特殊程序。圖2所示為Linux設備驅(qū)動與操作系統(tǒng)及外設的關(guān)系。設備驅(qū)動程序位于Linux操作系統(tǒng)的內(nèi)核空間,它相當于操作系統(tǒng)內(nèi)核空間與物理層硬件設備之間的接口,它還為用戶層提供系統(tǒng)調(diào)用的接口函數(shù)。用戶層的應用程序不能直接訪問操作物理層的外部硬件設備,只有通過系統(tǒng)調(diào)用才可以訪問操作外部硬件設備[2]。因此可以看出設備驅(qū)動程序在操作系統(tǒng)中起到了相當大的作用。

3 Linux設備驅(qū)動開發(fā)過程

  Linux設備驅(qū)動程序的編寫可以模塊化,主要包括:設備的初始化、驅(qū)動模塊的加載與卸載、設備的打開與釋放、數(shù)據(jù)讀寫與操作、中斷響應。

  3.1 設備的初始化

  Linux系統(tǒng)啟動后會自動檢測計算機終端上所有的PCI-E設備的信息,并記錄在pci_dev結(jié)構(gòu)體中,其中包括硬件設備的廠商號、設備號等大部分的硬件信息。PCI-E驅(qū)動程序就是根據(jù)廠商號和設備號來連接設備并加載驅(qū)動的,這就需要在驅(qū)動程序中定義該驅(qū)動所支持的硬件參數(shù)信息。本文中使用的時統(tǒng)卡的PCI-E橋接芯片是PEX8311,其硬件參數(shù)信息定義分別為廠商號、設備號、子廠商號、子設備號、類別和類別掩碼。初始化代碼如下。

  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ū)動模塊的加載與卸載

  硬件設備驅(qū)動的加載,必須要有一個主設備號。設備號的分配有兩種方式:靜態(tài)分配和動態(tài)分配。靜態(tài)分配指的是由開發(fā)人員指定一個固定的設備號;動態(tài)分配則是由操作系統(tǒng)自動分配設備號。在不能明確某設備號是否被使用的情況下,建議使用動態(tài)分配的方式獲得設備號,這樣就避免了因設備號沖突導致硬件設備不能正常工作的情況出現(xiàn)。分配了設備號就可以注冊設備并加載設備驅(qū)動了。而當該設備不再使用時,可以將該設備的驅(qū)動模塊卸載掉,以此來減少系統(tǒng)內(nèi)核的占用以及其他系統(tǒng)資源的開銷。驅(qū)動模塊加載與卸載的代碼如下。

  //驅(qū)動模塊的加載

  static int__init plxpci_init(void)

  {

  ……

  /*注冊設備,register_chrdev函數(shù)的第一個參數(shù)為0,表示系統(tǒng)自動分配一個空閑的主設備號*/

  card->MajorID=register_chrdev(0,PLX_DRIVER_NAME,&plxpci_fops);

  pci_register_driver(&PlxPciDriver);

  ……

  }

  //驅(qū)動模塊的卸載

  static void__exit plxpci_cleanup(void)

  {

  unregister_chrdev(major,PLX_DRIVER_NAME);

  pci_unregister_driver(&plxpci_driver);

  }

  3.3 設備的打開與釋放

  Linux系統(tǒng)內(nèi)核在驅(qū)動模塊加載之后就可以打開硬件設備。設備的打開模塊主要是獲取設備的控制權(quán),允許中斷的產(chǎn)生等。而當不再使用該設備時,就需要釋放該設備。設備的釋放模塊的任務與設備的打開模塊的任務正好相反,主要是釋放對設備的控制權(quán)、中斷以及之前系統(tǒng)分配的一些資源等。設備打開與釋放的代碼如下。

  //設備的打開

  static int plxpci_open(struct inode*inode,struct file*file)

  {

  ……

  /*獲取設備的控制權(quán)*/

  dev->open_mode|=file->f_mode&(FMODE_READ|FMODE_WRITE);

  /*允許中斷產(chǎn)生*/

  plxpci_enable_IRQ(dev);

  return 0;

  }

  //設備的釋放

  static int plxpci_release(struct inode*inode,struct file*file)

  {

  ……

  /*釋放對設備的控制權(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ū)動程序使用的是DMA(Direct Memory Access)傳輸模式。DMA傳輸模式無需計算機或本地控制器的干預,傳輸效率很高,從而大大降低了控制器的工作量且提高了數(shù)據(jù)的傳輸速率及效率[3]。要完成DMA傳輸模式就需要了解時統(tǒng)卡上主要的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的傳輸模式,就可以從時統(tǒng)卡中讀出時間信息。DMA傳輸?shù)拇a如下。

  //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系統(tǒng)中非常寶貴的資源,任何驅(qū)動程序都需要申請中斷并注冊中斷處理才可以使用中斷。可以使用中斷的方式來讀取硬件設備中的數(shù)據(jù)。而如果硬件設備不支持中斷,則只能采用輪詢的方式來讀取數(shù)據(jù)。硬件設備中一般包含好幾種不同的中斷,例如1 Hz、20 Hz、100 Hz等。因此,當讀取中斷狀態(tài)位之后還需要將不同的中斷識別區(qū)分開來才能使用。另外,為方便用戶層的應用軟件對中斷的使用,使用信號機制來向用戶層發(fā)送中斷信號,通知用戶層的應用軟件獲取中斷狀態(tài)位。中斷響應程序如下。

  //中斷響應

  irq_handler_t plxpci_interrupt(int irq,void*dev_id,struct pt_regs*regs)

  {

  ……

  /*讀取中斷狀態(tài)位,其中包含多種中斷,需要在下一步識別并解析出不同的中斷*/

  status=inb(PLXPCI_IRQ_REG(dev));

  if(status)

  {

  /*識別20 Hz中斷*/

  if(status&IRQ_FLAG_20 Hz)

  {

  ……

  }

  ……

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

  tasklet_schedule(&dev->tlet);

  }

  return(IRQ_HANDLED);

  }

4 驅(qū)動程序的測試

  4.1 驅(qū)動程序的加載

  本文中開發(fā)及測試平臺所使用的操作系統(tǒng)是中標麒麟Linux操作系統(tǒng),該系統(tǒng)的內(nèi)核版本是2.6.32。Linux下驅(qū)動程序模塊的加載通常有動態(tài)加載和靜態(tài)加載兩種方式。靜態(tài)加載就是把編譯生成的驅(qū)動程序文件plx8311.ko編譯到內(nèi)核中,每次系統(tǒng)啟動時自動調(diào)用,這種方式比較適合最終版本的驅(qū)動程序。動態(tài)加載就是通過insmod命令加載驅(qū)動程序,通過rmmod命令可以卸載驅(qū)動程序,這樣隨時可以修改驅(qū)動程序,對于還在調(diào)試階段的程序比較方便。

  4.2 測試過程與結(jié)果

003.jpg


  測試前首先保證在計算機終端中安裝好時統(tǒng)卡,并連接B碼終端,然后加載驅(qū)動程序,使用lsmod命令查看驅(qū)動程序是否已經(jīng)加載好。圖3所示為plx8311驅(qū)動加載成功。當驅(qū)動程序可以正常加載,并且能夠通過測試程序讀出時統(tǒng)卡中的時間信息和中斷信息,則說明編寫的驅(qū)動程序是可行的。圖4所示為測試結(jié)果,前面顯示的是從時統(tǒng)卡中讀出的當前時間,后面3個數(shù)字表示從啟動測試程序到當前時刻所獲得的1 Hz、20 Hz、100 Hz中斷信號的個數(shù)。

5 結(jié)論

  Linux系統(tǒng)的開源性加上PCI-E總線在計算機系統(tǒng)中的廣泛應用,使得其兩者的結(jié)合越來越緊密,Linux系統(tǒng)下的PCI-E的驅(qū)動開發(fā)也得到了廣泛的關(guān)注。本文結(jié)合實際項目開發(fā),通過對PEX8311時統(tǒng)卡的驅(qū)動程序編寫過程中的各模塊的介紹,闡述了整個驅(qū)動的開發(fā)流程和相關(guān)技巧,并通過編寫測試程序完成了驅(qū)動程序的測試工作,驗證了驅(qū)動的可用性。

  參考文獻

  [1] BUDRUK R, ANDERSON D, SHANLEY T. PCI Express系統(tǒng)體系結(jié)構(gòu)標準教材[M].田玉敏,王崧,張波,譯.北京:電子工業(yè)出版社,2005.

  [2] 鄭強.Linux驅(qū)動開發(fā)入門與實踐[M].北京:清華大學出版社,2010.

  [3] 范晶,胡愛蘭.基于狀態(tài)機的PEX8311的DMA實現(xiàn)[J].微型機與應用,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)載。