摘 要:當前基于Linux內核的操作系統應用越來越廣泛,開發基于Linux的設備驅動程序,具有很強的實用性和可移植性。本文簡單介紹linux系統上PCI-E設備驅動的框架以及重要的數據結構。
關鍵詞:Linux;PCI-E;PCI;驅動
Abstract:At present,the operating system based on Linux kernel is used more and more widely. It is very practical and portable to develop the device driver based on Linux. This article briefly introduces the framework and the important data structure of PCI-E device driver on Linux system .
Key word: Linux;PCI-E;PCI;Driver
PCI-Express 簡稱PCI-E,是一種完全不同于PCI、具有高速串行點對點雙通道高帶寬傳輸模式的全新總線規范,所連接的設備分配獨享通道帶寬,不共享總線帶寬,支持端對端的可靠性傳輸。PCI-E在軟件層面上兼容的PCI技術和設備,支持PCI設備和內存模組的初始化,也就是說驅動程序、操作系統完全兼容。
1 PCI設備與驅動關系
PCI設備通常由一組參數唯一地標識,它們被vendorID,deviceID和class nodes所標識,即設備廠商,型號等,這些參數保存在 pci_device_id結構中。每個PCI設備都會被分配一個pci_dev變量。所有的PCI驅動程序都必須定義一個pci_driver結構變量,在該變量中包含了這個PCI驅動程序所提供的不同功能的函數,同時,在這個結構中也包含了一個device_driver結構,這個結構定義了PCI子系統與PCI設備之間的接口。在注冊PCI驅動程序時,這個結構將被初始化,同時這個 pci_driver變量會被鏈接到pci_bus_type中的驅動鏈上去。在pci_driver中有一個成員struct pci_device_id *id_table,它列出了這個設備驅動程序所能夠處理的所有PCI設備的ID值。
2 基本框架
在用模塊方式實現PCI設備驅動程序時,通常至少要實現以下幾個部分:初始化設備模塊、設備打開模塊、數據讀寫和控制模塊、中斷處理模塊、設備釋放模塊、設備卸載模塊。下面給出一個典型的PCI設備驅動程序的基本框架,從中不難體會到這幾個關鍵模塊是如何組織起來的。
staticstruct pci_device_id example_pci_tbl [] __initdata ={
{PCI_VENDOR_ID_EXAMPLE,PCI_DEVICE_ID_EXAMPLE,PCI_ANY_ID,
PCI_ANY_ID,0,0, EXAMPLE},
{0,}};
struct example_pci {/* 對特定PCI設備進行描述的數據結構 */
unsigned int magic;
struct example_pci *next;/* 使用鏈表保存所有同類的PCI設備 */
/* ... */}
staticvoid example_interrupt(int irq,void*dev_id,struct pt_regs *regs){/* 中斷處理模塊 */
/* ... */}
staticstruct file_operations example_fops ={ /* 設備文件操作接口 */
owner: THIS_MODULE,/* demo_fops所屬的設備模塊 */
read: example_read,/* 讀設備操作*/
write: example_write,/* 寫設備操作*/
ioctl: example_ioctl,/* 控制設備操作*/
open: example_open,/* 打開設備操作*/
elease: example_release /* 釋放設備操作*/
/* ... */};
staticstruct pci_driver example_pci_driver ={/ * 設備模塊信息 */
name: example_MODULE_NAME,/* 設備模塊名稱 */
id_table: example_pci_tbl,/* 能夠驅動的設備列表 */
probe: example_probe,/* 查找并初始化設備 */
remove: example_remove /* 卸載設備模塊 */
/* ... */};
staticint __init example_init_module (void){
/* ... */}
staticvoid __exit example_cleanup_module (void){
pci_unregister_driver(&demo_pci_driver);
}
module_init( example_init_module);/* 加載驅動程序模塊入口 */
module_exit( example_cleanup_module);/* 卸載驅動程序模塊入口 */
3 主要數據結構
上面這段代碼給出了一個典型的PCI設備驅動程序的框架,是一種相對固定的模式。主要用了幾個重要的數據結構。
struct pci_device_id {
__u32 vendor, device;/* Vendor and device ID or PCI_ANY_ID*/
__u32 subvendor, subdevice;/* Subsystem ID's or PCI_ANY_ID */
__u32 class, class_mask;/* (class,subclass,prog-if) triplet */
kernel_ulong_t driver_data;/* Data private to the driver */
};
vendorID:標識硬件制造商,是一個16位的寄存器。
deviceID:設備ID,由制造商選擇,也是一個16位的寄存器。
class:每個外部設備屬于某個類(class),也是一個16位的寄存器。
struct pci_driver {
struct list_head node;
char*name;
conststruct pci_device_id *id_table;/* must be non-NULL for probe to be called */
int(*probe)(struct pci_dev *dev,conststruct pci_device_id *id);/* New device inserted */
void(*remove)(struct pci_dev *dev);/* Device removed */
/* ... */};
struct pci_driver它的作用并不僅僅是識別設備的id_table結構,還包括了檢測設備的函數probe()和卸載設備的函數remove(),
struct pci_dev {
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 */
struct pci_slot *slot;/* Physical slot this device is in */
unsignedint devfn;/* encoded device & function index */
unsignedshort vendor;
unsignedshort device;
/* ... */};
它詳細描述了一個PCI設備幾乎所有的硬件信息,包括廠商ID、設備ID、各種資源等。
4 結束語
Linux PCI設備驅動實際包括Linux PCI設備驅動和具體設備本身驅動兩部分,Linux PCI驅動是內核自帶的,而我們需要完成的就是設備本身的驅動,比如本人做的超聲數據采集卡的驅動。
參考文獻
[1]:(美)博韋深入理解Linux內核[M],中國電力出版社,第三版。
[2]:(美)科波,LINUX設備驅動程序(第3版)[M],中國電力出版社,第三版。
作者簡介
林齊梅(1984-),男,廣東汕頭人,學士學位,研究方向:超聲探傷儀設備研發。