PCI驅動開發學習筆記(一)

一、PCI設備編號

         PCI設備的ID號由總線號(BUS NUMBER)、設備號(DEVICE NUMBER)和功能號(FUNCTION NUMBER)組成。

         一條PCI總線的設備號由PCI設備的IDSEL信號與PCI總線地址線的連接關係確定,即每一個PCI插槽的總線號和設備號都是固定的,這是硬件工程師決定的。

         PCI功能號與PCI設備的具體設計相關。在一個PCI設備中最多有8個功能設備,而且每一個功能設備都有各自的PCI配置空間,而在絕大數PCI設備中只有一個功能設備。

lspci  --- 枚舉PCI設備
         01:00.0 VGA compatible controller: NVIDIA Corporation GM107 [GeForce GTX 745] (rev a2)
        (bus number 0~0xff[2^8]):(device number 0~0x1f[2^5]).(function number 0~0x07[2^3])  Class:Vendor Device (revision)

二、PCI配置空間

每個PCI邏輯設備都有自己的配置空間,裏面存儲了一些基本信息,生產商,IRQ中斷號,還有就是定義了mem空間和io空間的起始地址和大小。

HOST主橋使用寄存器號,訪問PCI設備配置空間的某個寄存器。

三、PCI驅動函數接口

         1.  pci驅動註冊

          pci_register_driver(struct pci_driver *drv)

          pci_unregister_driver(struct pci_driver *drv)

static struct pci_device_id vt8623_devices[] = {
    {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)},
    {0, 0, 0, 0, 0, 0, 0}
};       
static struct pci_driver vt8623fb_pci_driver = {
    .name       = "vt8623fb",
    .id_table   = vt8623_devices,
    .probe      = vt8623_pci_probe,
    .remove     = vt8623_pci_remove,
    .suspend    = vt8623_pci_suspend,
    .resume     = vt8623_pci_resume,
};

pci_register_driver(&vt8623fb_pci_driver);

          2. 激活PCI設備

                在驅動程序可以訪問PCI設備的任何設備資源之前(I/O區域或者中斷),驅動程序必須調用該函數:

     int pci_enable_device(struct pci_dev *dev);                       /*driver/pci/pci.c*/
     這個函數主要就是把PCI配置空間的Command域的0位和1 位置成了1,從而達到了開啓設備的目的。

          3.  訪問PCI配置空間

    int pci_read_config_byte(conststruct pci_dev *dev,int where, u8 *val);/*8位,讀入一個字節*/
     
    int pci_read_config_word(conststruct pci_dev *dev,int where, u16 *val);/*16位,讀入兩個字節*/
     
    int pci_read_config_dword(conststruct pci_dev *dev,int where, u32 *val);/*32位,讀入四個字節*/
    int pci_write_config_byte(conststruct pci_dev *dev,int where, u8 *val);/*8位,寫入一個字節*/
     
    int pci_write_config_word(conststruct pci_dev *dev,int where, u16 *val);/*16位,寫入兩個字節*/
     
    int pci_write_config_dword(conststruct pci_dev *dev,int where, u32 *val);/*32位,寫入四個字節*/

          4. 申請IO端口和內存資源

               通知內核該設備對應的IO端口和內存資源已經使用,其他的PCI設備不要再使用這個區域

             int  pci_request_regions(struct pci_dev *dev, const char *res_name)

             int  pci_release_regions(struct pci_dev *pdev)

             int  pci_request_mem_regions(struct pci_dev *pdev, const char *name)

             int  pci_release_mem_regions(struct pci_dev *pdev)

             int  pci_request_io_regions(struct pci_dev *pdev, const char *name)

             int  pci_release_io_regions(struct pci_dev *pdev)

 

           5. 訪問PCI的I/O和內存空間

             int pci_resource_[start|end|flags|len](struct pci_dev *dev,  int bar)  //Bar值的範圍爲0-5

 在硬件加電初始化時,BIOS固件統一檢查了所有的PCI設備,並統一爲他們分配了一個和其他互不衝突的地址,讓他們的驅動程序可以向這些地址映射他們的寄存器,這些地址被BIOS寫進了各個設備的配置空間,因爲這個活動是一個PCI的標準的活動,所以自然寫到各個設備的配置空間裏而不是他們風格各異的控制寄存器空間裏。當操作系統初始化時,他爲每個PCI設備分配了pci_dev結構,並且把BIOS獲得的並寫到了配置空間中的地址讀出來寫到了pci_dev中的resource字段中。這樣以後我們在讀這些地址就不需要在訪問配置空間了,直接跟pci_dev要就可以了,我們這裏的四個函數就是直接從pci_dev讀出了相關數據。

Linux認爲這個地址是IO地址,如果要訪問的話可以通過ioremap映射到內核空間,然後通過readl/writel等IO接口進行操作。

           6.  私有數據

             pci_set_drvdata    設置驅動私有數據

             pci_get_drvdata    獲取驅動私有數據

           7. 主設備模式

              pci_set_master    設定設備工作在總線主設備模式

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章