PCI驅(qū)動程序?qū)崿F(xiàn)分析報告_第1頁
PCI驅(qū)動程序?qū)崿F(xiàn)分析報告_第2頁
PCI驅(qū)動程序?qū)崿F(xiàn)分析報告_第3頁
PCI驅(qū)動程序?qū)崿F(xiàn)分析報告_第4頁
PCI驅(qū)動程序?qū)崿F(xiàn)分析報告_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、PCI驅(qū)動程序?qū)崿F(xiàn)分析報告關(guān)鍵數(shù)據(jù)結(jié)構(gòu)PCI設(shè)備上有三種地址空間:PCI的I/O空間、PCI的存儲空間和PCI的配置空間。CPU可以訪問PCI設(shè)備上的所有地址空間,其中 I/O空間和存儲空間提供給設(shè)備驅(qū)動程序使用,而配置空間則由Linux內(nèi)核中的PCI初始化代碼使用。內(nèi)核在啟動時負責對所有PCI設(shè) 備進行初始化,配置好所有的PCI設(shè)備,包括中斷號以及I/O基址,并在文件/proc/pci中列出所有找到的PCI設(shè)備,以及這些設(shè)備的 參數(shù)和屬性。Linux驅(qū)動程序通常使用結(jié)構(gòu)(struct)來表示一種設(shè)備,而結(jié)構(gòu)體中的變量則代表某一具體設(shè)備,該變量存放了與該設(shè)備相關(guān)的所有信 息。好的驅(qū)動程序都應(yīng)該

2、能驅(qū)動多個同種設(shè)備,每個設(shè)備之間用次設(shè)備號進行區(qū)分,如果采用結(jié)構(gòu)數(shù)據(jù)來代表所有能由該驅(qū)動程序驅(qū)動 的設(shè)備,那么就可以簡單地使用數(shù)組下標來表示次設(shè)備號。在PCI驅(qū)動程序中,下面幾個關(guān)鍵數(shù)據(jù)結(jié)構(gòu)起著非常核心的作用:. pci_driver這個數(shù)據(jù)結(jié)構(gòu)在文件include/linux/pci.h里,這是Linux內(nèi)核版本2.4之后為新型的PCI設(shè)備驅(qū)動程序所添加的,其中最 主要的是用于識別設(shè)備的id_table結(jié)構(gòu),以及用于檢測設(shè)備的函數(shù)probe()和卸載設(shè)備的函數(shù)remove():struct pci_driver struct list_head node;char 六name;const s

3、truct 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_d

4、ev 六dev, u32 state, int enable););pci_dev這個數(shù)據(jù)結(jié)構(gòu)也在文件include/linux/pci.h里,它詳細描述了一個PCI設(shè)備幾乎所有的硬件信息,包括廠商ID、設(shè)備ID、各種資源等:struct pci_dev struct list_head global_list;struct list_head bus_list;struct pci_bus 六bus;struct pci_bus 六subordinate;void 六sysdata;struct proc_dir_entry 六procent;unsigned int devfn;unsig

5、ned short vendor;unsigned short device;unsigned short subsystem_vendor;unsigned short subsystem_device;unsigned int class;u8hdr_type;u8rom_base_reg;struct pci_driver 六driver;void *driver_data;u64 dma_mask;u32current_state;unsigned short vendor_compatibleDEVICE_COUNT_COMPATIBLE;unsigned short device_

6、compatibleDEVICE_COUNT_COMPATIBLE;unsigned int irq;struct resource resourceDEVICE_COUNT_RESOURCE;struct resource dma_resourceDEVICE_COUNT_DMA;struct resource irq_resourceDEVICE_COUNT_IRQ;charname80;charslot_name8;int active;int ro;unsigned short regs;int (*prepare)(struct pci_dev 六dev);int (*activat

7、e)(struct pci_dev 六dev);int (*deactivate)(struct pci_dev 六dev););基本框架在用模塊方式實現(xiàn)pci設(shè)備驅(qū)動程序時,通常至少要實現(xiàn)以下幾個部分:初始化設(shè)備模塊、設(shè)備打開模塊、數(shù)據(jù)讀寫和控制模塊、中斷處理模塊、設(shè)備釋放模塊、設(shè)備卸載模塊。下面給出一個典型的 pci設(shè)備驅(qū)動程序的基本框架,從中不難體會到這幾個關(guān)鍵模塊是如何 組織起來的。/*指明該驅(qū)動程序適用于哪一些PCI設(shè)備*/static struct pci_device_id demo_pci_tbl _initdata = PCI_VENDOR_ID_DEMO, PCI_DEVI

8、CE_ID_DEMO,PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEMO,0,;/*對特定PCI設(shè)備進行描述的數(shù)據(jù)結(jié)構(gòu)*/struct demo_card unsigned int magic;/*使用鏈表保存所有同類的PCI設(shè)備*/struct demo_card *next;/* . */*中斷處理模塊*/static void demo_interrupt(int irq, void *dev_id, struct pt_regs *regs)/* . */*設(shè)備文件操作接口 */static struct file_operations demo_fops = own

9、er:THIS_MODULE,/* demo_fops所屬的設(shè)備模塊*/read:demo_read,/*讀設(shè)備操作*/write:demo_write,/*寫設(shè)備操作*/ioctl:demo_ioctl,/*控制設(shè)備操作*/mmap:demo_mmap,/*內(nèi)存重映射操作*/open:demo_open,/*打開設(shè)備操作*/release:demo_release/*釋放設(shè)備操作*/* . */);/*設(shè)備模塊信息*/static structpci_driverdemo_pci_driver = name:demo_MODULE_NAME,/*設(shè)備模塊名稱*/id_table:demo_p

10、ci_tbl,/*能夠驅(qū)動的設(shè)備列表*/probe:demo_probe,/*查找并初始化設(shè)備*/remove:demo_remove/*卸載設(shè)備模塊*/* . */);static int _init demo_init_module (void)/* . */static void _exit demo_cleanup_module (void)pci_unregister_driver(&demo_pci_driver);/*加載驅(qū)動程序模塊入口 */module_init(demo_init_module);/*卸載驅(qū)動程序模塊入口 */module_exit(demo_cleanup

11、_module);上面這段代碼給出了一個典型的PCI設(shè)備驅(qū)動程序的框架,是一種相對固定的模式。需要注意的是,同加載和卸載模塊相關(guān)的函數(shù)或數(shù) 據(jù)結(jié)構(gòu)都要在前面加上_init、_exit等標志符,以使同普通函數(shù)區(qū)分開來。構(gòu)造出這樣一個框架之后,接下去的工作就是如何完成框 架內(nèi)的各個功能模塊了。初始化設(shè)備模塊在Linux系統(tǒng)下,想要完成對一個PCI設(shè)備的初始化,需要完成以下工作:檢查PCI總線是否被Linux內(nèi)核支持;檢查設(shè)備是否插在總線插槽上,如果在的話則保存它所占用的插槽的位置等信息。讀出配置頭中的信息提供給驅(qū)動程序使用。當Linux內(nèi)核啟動并完成對所有PCI設(shè)備進行掃描、登錄和分配資源等初始化

12、操作的同時,會建立起系統(tǒng)中所有 PCI設(shè)備的拓撲結(jié)構(gòu),驅(qū)動程序首先調(diào)用函數(shù)pc i_present()檢查PCI總線是否已經(jīng)被Linux內(nèi)核支持,如果系統(tǒng)支持PCI總線結(jié)構(gòu),這個函數(shù)的返回值為0,如果驅(qū)動程序在調(diào)用這個函數(shù)時得到了一個非0的返回值,那么驅(qū)動程序就必須得中止自己的任務(wù)了。在 2.4以前的內(nèi)核中,需要手工調(diào)用pci_find_device()函數(shù)來查找PCI設(shè)備,但在2.4以后更好的辦法是調(diào)用pci_register_driver()函數(shù)來注冊PCI設(shè)備的驅(qū)動 程序,此時需要提供一個pci_driver結(jié)構(gòu),在該結(jié)構(gòu)中給出的probe探測例程將負責完成對硬件的檢測工作。static

13、 int _init demo_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)struct demo_card 六card;/*啟動pci設(shè)備*/if (pci_enable_device(pci_dev)return -EIO;/*設(shè)備DMA標識*/if (pci_set_dma_mask(pci_dev, DEMO_DMA_MASK) return -ENODEV;/*在內(nèi)核空間中動態(tài)申請內(nèi)存*/if (card = kmalloc(sizeof(struct demo_card), GFP_KERNEL

14、) = NULL) printk(KERN_ERR pci_demo: out of memoryn);return -ENOMEM;memset(card, 0, sizeof(六card);/*讀取pci配置信息*/card-iobase = pci_resource_start (pci_dev, 1);card-pci_dev = pci_dev;card-pci_id = pci_id-device;card-irq = pci_dev-irq;card-next = devs;card-magic = DEMO_CARD_MAGIC;/*設(shè)置成總線主DMA模式*/pci_set_m

15、aster(pci_dev);/*申請i/o資源*/request_region(card-iobase, 64, card_namespci_id-driver_data);return 0;打開設(shè)備模塊在這個模塊里主要實現(xiàn)申請中斷、檢查讀寫模式以及申請對設(shè)備的控制權(quán)等。在申請控制權(quán)的時候,非阻塞方式遇忙返回,否則進程主 動接受調(diào)度,進入睡眠狀態(tài),等待其它進程釋放對設(shè)備的控制權(quán)。static int demo_open(struct inode *inode, struct file *file)/*申請中斷,注冊中斷處理程序*/request_irq(card-irq, &demo_int

16、errupt, SA_SHIRQ,card_namespci_id-driver_data, card) /*檢查讀寫模式*/if(file-f_mode & FMODE_READ) /* . */if(file-f_mode & FMODE_WRITE) /* . */*申請對設(shè)備的控制權(quán)*/down(&card-open_sem);while(card-open_mode & file-f_mode) if (file-f_flags & o_nonblock) /* NONBLOCK 模式,返回-EBUSY */up(&card-open_sem);return -EBUSY; else

17、 /*等待調(diào)度,獲得控制權(quán)*/card-open_mode |= f_mode & (FMODE_READ | FMODE_WRITE);up(&card-open_sem);/*設(shè)備打開計數(shù)增1 */MOD_INC_USE_COUNT;/* . */數(shù)據(jù)讀寫和控制信息模塊PCI設(shè)備驅(qū)動程序可以通過demo_fops結(jié)構(gòu)中的函數(shù)demo_ioc tl(),向應(yīng)用程序提供對硬件進行控制的接口。例如,通過它可以從事實上,在demo_fops里還可以實現(xiàn)諸如demo_read( )、demo_mmap()等操作,Linux內(nèi)核源碼中的driver目錄里提供了許多 設(shè)備驅(qū)動程序的源代碼,找那里可以找到

18、類似的例子。在對資源的訪問方式上,除了有 I/O指令以外,還有對外設(shè)I/O內(nèi)存的訪問。對 這些內(nèi)存的操作一方面可以通過把I/O內(nèi)存重新映射后作為普通內(nèi)存進行操作,另一方面也可以通過總線主 DMA(Bus Master DMA) 的方式讓設(shè)備把數(shù)據(jù)通過DMA傳送到系統(tǒng)內(nèi)存中。中斷處理模塊PC的中斷資源比較有限,只有015的中斷號,因此大部分外部設(shè)備都是以共享的形式申請中斷號的。當中斷發(fā)生的時候,中斷處理程序首先負責對中斷進行識別,然后再做進一步的處理。static void demo_interrupt(int irq, void *dev_id, struct pt_regs 六regs)st

19、ruct demo_card 六card = (struct demo_card *)dev_id;u32 status;spin_lock(&card-lock);status = inl(card-iobase + GLOB_STA);if(!(status & INT_MASK)spin_unlock(&card-lock);return; /* not for us */*告訴設(shè)備已經(jīng)收到中斷*/outl(status & INT_MASK, card-iobase + GLOB_STA);spin_unlock(&card-lock);/*其它進一步的處理,如更新DMA緩沖區(qū)指針等*/釋放設(shè)備模塊釋放設(shè)備模塊主要負責釋放對設(shè)備的控制權(quán),釋放占用的

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論