摘 要:當(dāng)前基于Linux內(nèi)核的操作系統(tǒng)應(yīng)用越來越廣泛,開發(fā)基于Linux的設(shè)備驅(qū)動程序,具有很強(qiáng)的實(shí)用性和可移植性。本文簡單介紹linux系統(tǒng)上PCI-E設(shè)備驅(qū)動的框架以及重要的數(shù)據(jù)結(jié)構(gòu)。
關(guān)鍵詞:Linux;PCI-E;PCI;驅(qū)動
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、具有高速串行點(diǎn)對點(diǎn)雙通道高帶寬傳輸模式的全新總線規(guī)范,所連接的設(shè)備分配獨(dú)享通道帶寬,不共享總線帶寬,支持端對端的可靠性傳輸。PCI-E在軟件層面上兼容的PCI技術(shù)和設(shè)備,支持PCI設(shè)備和內(nèi)存模組的初始化,也就是說驅(qū)動程序、操作系統(tǒng)完全兼容。
1 PCI設(shè)備與驅(qū)動關(guān)系
PCI設(shè)備通常由一組參數(shù)唯一地標(biāo)識,它們被vendorID,deviceID和class nodes所標(biāo)識,即設(shè)備廠商,型號等,這些參數(shù)保存在 pci_device_id結(jié)構(gòu)中。每個PCI設(shè)備都會被分配一個pci_dev變量。所有的PCI驅(qū)動程序都必須定義一個pci_driver結(jié)構(gòu)變量,在該變量中包含了這個PCI驅(qū)動程序所提供的不同功能的函數(shù),同時,在這個結(jié)構(gòu)中也包含了一個device_driver結(jié)構(gòu),這個結(jié)構(gòu)定義了PCI子系統(tǒng)與PCI設(shè)備之間的接口。在注冊PCI驅(qū)動程序時,這個結(jié)構(gòu)將被初始化,同時這個 pci_driver變量會被鏈接到pci_bus_type中的驅(qū)動鏈上去。在pci_driver中有一個成員struct pci_device_id *id_table,它列出了這個設(shè)備驅(qū)動程序所能夠處理的所有PCI設(shè)備的ID值。
2 基本框架
在用模塊方式實(shí)現(xiàn)PCI設(shè)備驅(qū)動程序時,通常至少要實(shí)現(xiàn)以下幾個部分:初始化設(shè)備模塊、設(shè)備打開模塊、數(shù)據(jù)讀寫和控制模塊、中斷處理模塊、設(shè)備釋放模塊、設(shè)備卸載模塊。下面給出一個典型的PCI設(shè)備驅(qū)動程序的基本框架,從中不難體會到這幾個關(guān)鍵模塊是如何組織起來的。
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設(shè)備進(jìn)行描述的數(shù)據(jù)結(jié)構(gòu) */
unsigned int magic;
struct example_pci *next;/* 使用鏈表保存所有同類的PCI設(shè)備 */
/* ... */}
staticvoid example_interrupt(int irq,void*dev_id,struct pt_regs *regs){/* 中斷處理模塊 */
/* ... */}
staticstruct file_operations example_fops ={ /* 設(shè)備文件操作接口 */
owner: THIS_MODULE,/* demo_fops所屬的設(shè)備模塊 */
read: example_read,/* 讀設(shè)備操作*/
write: example_write,/* 寫設(shè)備操作*/
ioctl: example_ioctl,/* 控制設(shè)備操作*/
open: example_open,/* 打開設(shè)備操作*/
elease: example_release /* 釋放設(shè)備操作*/
/* ... */};
staticstruct pci_driver example_pci_driver ={/ * 設(shè)備模塊信息 */
name: example_MODULE_NAME,/* 設(shè)備模塊名稱 */
id_table: example_pci_tbl,/* 能夠驅(qū)動的設(shè)備列表 */
probe: example_probe,/* 查找并初始化設(shè)備 */
remove: example_remove /* 卸載設(shè)備模塊 */
/* ... */};
staticint __init example_init_module (void){
/* ... */}
staticvoid __exit example_cleanup_module (void){
pci_unregister_driver(&demo_pci_driver);
}
module_init( example_init_module);/* 加載驅(qū)動程序模塊入口 */
module_exit( example_cleanup_module);/* 卸載驅(qū)動程序模塊入口 */
3 主要數(shù)據(jù)結(jié)構(gòu)
上面這段代碼給出了一個典型的PCI設(shè)備驅(qū)動程序的框架,是一種相對固定的模式。主要用了幾個重要的數(shù)據(jù)結(jié)構(gòu)。
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:標(biāo)識硬件制造商,是一個16位的寄存器。
deviceID:設(shè)備ID,由制造商選擇,也是一個16位的寄存器。
class:每個外部設(shè)備屬于某個類(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它的作用并不僅僅是識別設(shè)備的id_table結(jié)構(gòu),還包括了檢測設(shè)備的函數(shù)probe()和卸載設(shè)備的函數(shù)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;
/* ... */};
它詳細(xì)描述了一個PCI設(shè)備幾乎所有的硬件信息,包括廠商ID、設(shè)備ID、各種資源等。
4 結(jié)束語
Linux PCI設(shè)備驅(qū)動實(shí)際包括Linux PCI設(shè)備驅(qū)動和具體設(shè)備本身驅(qū)動兩部分,Linux PCI驅(qū)動是內(nèi)核自帶的,而我們需要完成的就是設(shè)備本身的驅(qū)動,比如本人做的超聲數(shù)據(jù)采集卡的驅(qū)動。
參考文獻(xiàn)
[1]:(美)博韋深入理解Linux內(nèi)核[M],中國電力出版社,第三版。
[2]:(美)科波,LINUX設(shè)備驅(qū)動程序(第3版)[M],中國電力出版社,第三版。
作者簡介
林齊梅(1984-),男,廣東汕頭人,學(xué)士學(xué)位,研究方向:超聲探傷儀設(shè)備研發(fā)。