在PCI驅動程序中,下面幾個關鍵數據結構起著非常核心的作用: 1)pci_driver:1)這個數據結構在文件include/linux/pci.h里,這是Linux內核版本2.4之後為新型的PCI 設備驅動程序所添加的,其中最主要的是用於識別設備的 id_table結構,以及用於檢測 設備的函數probe()和卸載設備的函數remove() : struct pci_driver { struct list_head node; char *name; const struct pci_device_id *id_table; int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); void (*remove) (struct pci_dev *dev); int (*save_state) (struct pci_dev *dev, u32 state); int (*suspend)(struct pci_dev *dev, u32 state); int (*resume) (struct pci_dev *dev); int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); };<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />其中name 是驅動程序名稱;id_table指向一個與驅動程序相關的設備ID表的指針.大多數驅動程序應當用MODULE_DEVICE_TABLE(pci,…)將該設備 ID表導出.在調用prob( )時設成NULL 以讓系統檢測到所有的pci設備.代碼中是這樣定義的: MODULE_DEVICE_TABLE(pci, sil_pci_tbl);probe 指向設備檢測函數probe( ) 的指針.該函數將在pci設備ID與設備ID表匹配且還沒有被其它驅動程序處理時(一般在對已存在的設備執行 pci_register_driver或以後又有新設備插入時)被調用.調用時傳入一個指向struct pci_driver結構的指針和與設備匹配的設備ID表做參數.若成功(驅動程序檢測到pci設備)則返回0,否則返回一個負的錯誤代碼.這個函數總是在上下文之間調用的,因此可以進入睡眠狀態的 remove指向一個設備卸載函數remove( )的指針.該函數在pci設備被卸載時(如在註銷設備驅動程序或者手動拔出該設備)被調用.同probe一樣,該函數也是可以睡眠的. 2)pci_dev: 1)這個數據結構也在文件include/linux/pci.h里,它詳細描述了一個PCI設備幾乎所有的 硬體信息,包括廠商ID、設備 ID、各種資源等:struct pci_dev {struct list_head global_list;/* node in list of all PCI devices */struct list_head bus_list;/* node in per-bus list */struct pci_bus*bus;/* bus this device is on */struct pci_bus*subordinate;/* bus this device bridges to */void*sysdata;/* hook for sys-specific extension */struct proc_dir_entry *procent;/* device entry in /proc/bus/pci */unsigned intdevfn;/* encoded device & function index */unsigned shortvendor;unsigned shortdevice;unsigned shortsubsystem_vendor;unsigned shortsubsystem_device;unsigned intclass;/* 3 bytes: (base,sub,prog-if) */u8hdr_type;/* PCI header type (`multi' flag masked out) */u8rom_base_reg;/* which config register controls the ROM */struct pci_driver *driver;/* which driver has allocated this device */u64dma_mask;/* Mask of the bits of bus address thisdevice implements.Normally this is0xffffffff.You only need to changethis if your device has broken DMAor supports 64-bit transfers.*/pci_power_tcurrent_state;/* Current operating state. In ACPI-speak,this is D0-D3, D0 being fully functional,and D3 being off. */structdevicedev;/* Generic device interface *//* device is compatible with these IDs */unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE];unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE];intcfg_size;/* Size of configuration space *//** Instead of touching interrupt line and base address registers* directly, use the values stored here. They might be different!*/unsigned intirq;struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions expansion ROMs *//* These fields are used by common fixups */unsigned inttransparent:1;/* Transparent PCI bridge */unsigned intmultifunction:1;/* Part of multi-function device *//* keep track of device state */unsigned intis_enabled:1;/* pci_enable_device has been called */unsigned intis_busmaster:1; /* device is busmaster */unsigned intno_msi:1;/* device may not use msi */u32saved_config_space[16]; /* config space saved at suspend time */struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */int rom_attr_enabled;/* has display of the rom attribute been enabled? */ struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */}; 同載入和卸載模塊相關的函數或數據結構都要在前面加上__init、__exit等 標誌符,以使同普通函數區分開來.static int __init sil_init(void) {return pci_module_init(&sil_pci_driver);} 驅動程式通過pci_module_init向內核註冊自己(我們有時會看到pci_register_driver函數,其實他們是同一個,在內核代碼中會看到,只是個簡單的#define): pci_module_init(&sil_pci_driver); 調用函數后,如果pci_device_id數組中標識的設備存在於系統中,並且該設備恰好還沒有驅動程式,則該驅動程式會被安裝. 註冊驅動程式成功后,sil_init_one會被調用,在這個函數中,我們能通過插入一些列印輸出語句看到 PCI的設置地址空間和I/O地址區域的一些情況.pci_enable_device和pci_disable_device 在一個pci設備可以被使用之前,必須調用pci_enable_device進行激活,該函數會調用底層代碼激活PCI設備上的I/O和內存,使之可用.而 pci_disable_device所做的事情剛好相反,告訴系統該PCI設備不再使用, 同時,禁用相關的一些資源.