PCI驅(qū)動(dòng)編程基本框架_第1頁
PCI驅(qū)動(dòng)編程基本框架_第2頁
PCI驅(qū)動(dòng)編程基本框架_第3頁
PCI驅(qū)動(dòng)編程基本框架_第4頁
PCI驅(qū)動(dòng)編程基本框架_第5頁
已閱讀5頁,還剩11頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

Linux將所有外部設(shè)備看成是一類特殊文件,稱之為“設(shè)備文件”,如果說系統(tǒng)調(diào)用是Linux內(nèi)核和應(yīng)用程序之間的接口,那么設(shè)備驅(qū)動(dòng)程序則可以看成是Linux內(nèi)核與外部設(shè)備之間的接口。設(shè)備驅(qū)動(dòng)程序向應(yīng)用程序屏蔽了硬件在實(shí)現(xiàn)上的細(xì)節(jié),使得應(yīng)用程序可以像操作普通文件一樣來操作外部設(shè)備。字符設(shè)備和塊設(shè)備Linux抽象了對(duì)硬件的處理,所有的硬件設(shè)備都可以像普通文件一樣來看待:它們可以使用和操作文件相同的、標(biāo)準(zhǔn)的系統(tǒng)調(diào)用接口來完成打開、關(guān)閉、讀寫和I/O控制操作,而驅(qū)動(dòng)程序的主要任務(wù)也就是要實(shí)現(xiàn)這些系統(tǒng)調(diào)用函數(shù)。Linux系統(tǒng)中的所有硬件設(shè)備都使用一個(gè)特殊的設(shè)備文件來表示,例如,系統(tǒng)中的第一個(gè)IDE硬盤使用/dev/hda表示。每個(gè)設(shè)備文件對(duì)應(yīng)有兩個(gè)設(shè)備號(hào):一個(gè)是主設(shè)備號(hào),標(biāo)識(shí)該設(shè)備的種類,也標(biāo)識(shí)了該設(shè)備所使用的驅(qū)動(dòng)程序;另一個(gè)是次設(shè)備號(hào),標(biāo)識(shí)使用同一設(shè)備驅(qū)動(dòng)程序的不同硬件設(shè)備。設(shè)備文件的主設(shè)備號(hào)必須與設(shè)備驅(qū)動(dòng)程序在登錄該設(shè)備時(shí)申請(qǐng)的主設(shè)備號(hào)一致,否則用戶進(jìn)程將無法訪問到設(shè)備驅(qū)動(dòng)程序。在Linux操作系統(tǒng)下有兩類主要的設(shè)備文件:一類是字符設(shè)備,另一類則是塊設(shè)備。字符設(shè)備是以字節(jié)為單位逐個(gè)進(jìn)行I/O操作的設(shè)備,在對(duì)字符設(shè)備發(fā)出讀寫請(qǐng)求時(shí),實(shí)際的硬件I/O緊接著就發(fā)生了,一般來說字符設(shè)備中的緩存是可有可無的,而且也不支持隨機(jī)訪問。塊設(shè)備則是利用一塊系統(tǒng)內(nèi)存作為緩沖區(qū),當(dāng)用戶進(jìn)程對(duì)設(shè)備進(jìn)行讀寫請(qǐng)求時(shí),驅(qū)動(dòng)程序先查看緩沖區(qū)中的內(nèi)容,如果緩沖區(qū)中的數(shù)據(jù)能滿足用戶的要求就返回相應(yīng)的數(shù)據(jù),否則就調(diào)用相應(yīng)的請(qǐng)求函數(shù)來進(jìn)行實(shí)際的I/O操作。塊設(shè)備主要是針對(duì)磁盤等慢速設(shè)備設(shè)計(jì)的,其目的是避免耗費(fèi)過多的CPU時(shí)間來等待操作的完成。一般說來,PCI卡通常都屬于字符設(shè)備。設(shè)備驅(qū)動(dòng)程序接口Linux中的I/O子系統(tǒng)向內(nèi)核中的其他部分提供了一個(gè)統(tǒng)一的標(biāo)準(zhǔn)設(shè)備接口,這是通過include/linux/fs.h中的數(shù)據(jù)結(jié)構(gòu)file_operations來完成的:structfile_operations{structmodule*owner;loff_t(*llseek)(structfile*,loff_t,int);ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);

ssize_t(*aio_read)(structkiocb*,conststructiovec*,unsignedlong,loff_t);ssize_t(*aio_write)(structkiocb*,conststructiovec*,unsignedlong,loff_t);int(*readdir)(structfile*,void*,filldir_t);unsignedint(*poll)(structfile*,structpoll_table_struct*);long(*unlocked_ioctl)(structfile*,unsignedint,unsignedlong);long(*compat_ioctl)(structfile*,unsignedint,unsignedlong);int(*mmap)(structfile*,structvm_area_struct*);int(*open)(structinode*,structfile*);int(*flush)(structfile*,fl_owner_tid);int(*release)(structinode*,structfile*);int(*fsync)(structfile*,loff_t,loff_t,intdatasync);int(*aio_fsync)(structkiocb*,intdatasync);int(*fasync)(int,structfile*,int);int(*lock)(structfile*,int,structfile_lock*);ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);int(*check_flags)(int);int(*flock)(structfile*,int,structfile_lock*);ssize_t(*splice_write)(structpipe_inode_info*,structfile*,loff_t*,size_t,unsignedint);ssize_t(*splice_read)(structfile*,loff_t*,structpipe_inode_info*,size_t,unsignedint);int(*setlease)(structfile*,long,structfile_lock**);long(*fallocate)(structfile*file,intmode,loff_toffset,loff_tlen);};當(dāng)應(yīng)用程序?qū)υO(shè)備文件進(jìn)行諸如open、close、read、write等操作時(shí),Linux內(nèi)核將通過file_operations結(jié)構(gòu)訪問驅(qū)動(dòng)程序提供的函數(shù)。例如,當(dāng)應(yīng)用程序?qū)υO(shè)備文件執(zhí)行讀操作時(shí),內(nèi)核將調(diào)用file_operations結(jié)構(gòu)中的read函數(shù)。設(shè)備驅(qū)動(dòng)程序模塊Linux下的設(shè)備驅(qū)動(dòng)程序可以按照兩種方式進(jìn)行編譯,一種是直接靜態(tài)編譯成內(nèi)核的一部分,另一種則是編譯成可以動(dòng)態(tài)加載的模塊。如果編譯進(jìn)內(nèi)核的話,會(huì)增加內(nèi)核的大小,

還要改動(dòng)內(nèi)核的源文件,而且不能動(dòng)態(tài)地卸載,不利于調(diào)試,所有推薦使用模塊方式。從本質(zhì)上來講,模塊也是內(nèi)核的一部分,它不同于普通的應(yīng)用程序,不能調(diào)用位于用戶態(tài)下的C或者C++庫函數(shù),而只能調(diào)用Linux內(nèi)核提供的函數(shù),在/proc/ksyms中可以查看到內(nèi)核提供的所有函數(shù)。在以模塊方式編寫驅(qū)動(dòng)程序時(shí),要實(shí)現(xiàn)兩個(gè)必不可少的函數(shù)init_module()和cleanup_module(),而且至少要包含和兩個(gè)頭文件。一般使用LDD3例程中使用的makefile作為基本的版本,稍作改變之后用來編譯驅(qū)動(dòng),編譯生成的模塊(一般為.ko文件)可以使用命令insmod載入Linux內(nèi)核,從而成為內(nèi)核的一個(gè)組成部分,此時(shí)內(nèi)核會(huì)調(diào)用模塊中的函數(shù)init_module()。當(dāng)不需要該模塊時(shí),可以使用rmmod命令進(jìn)行卸載,此進(jìn)內(nèi)核會(huì)調(diào)用模塊中的函數(shù)cleanup_module()。任何時(shí)候都可以使用命令來lsmod查看目前已經(jīng)加載的模塊以及正在使用該模塊的用戶數(shù)。設(shè)備驅(qū)動(dòng)程序結(jié)構(gòu)了解設(shè)備驅(qū)動(dòng)程序的基本結(jié)構(gòu)(或者稱為框架),對(duì)開發(fā)人員而言是非常重要的,Linux的設(shè)備驅(qū)動(dòng)程序大致可以分為如下幾個(gè)部分:驅(qū)動(dòng)程序的注冊(cè)與注銷、設(shè)備的打開與釋放、設(shè)備的讀寫操作、設(shè)備的控制操作、設(shè)備的中斷和輪詢處理。驅(qū)動(dòng)程序的注冊(cè)與注銷向系統(tǒng)增加一個(gè)驅(qū)動(dòng)程序意味著要賦予它一個(gè)主設(shè)備號(hào),這可以通過在驅(qū)動(dòng)程序的初始化過程中調(diào)用register_chrdev()或者register_blkdev()來完成。而在關(guān)閉字符設(shè)備或者塊設(shè)備時(shí),則需要通過調(diào)用unregister_chrdev(咸unregister_blkdev()從內(nèi)核中注銷設(shè)備,同時(shí)釋放占用的主設(shè)備號(hào)。但是現(xiàn)在程序員都傾向于動(dòng)態(tài)創(chuàng)建設(shè)備號(hào)和設(shè)備結(jié)點(diǎn),動(dòng)態(tài)創(chuàng)建設(shè)備號(hào)和設(shè)備結(jié)點(diǎn)需要幾個(gè)指定的函數(shù),具體可以參見“Linux字符驅(qū)動(dòng)中動(dòng)態(tài)分配設(shè)備號(hào)與動(dòng)態(tài)生成設(shè)備節(jié)點(diǎn)”。設(shè)備的打開與釋放打開設(shè)備是通過調(diào)用file_operations結(jié)構(gòu)中的函數(shù)open()來完成的,它是驅(qū)動(dòng)程序用來為今后的操作完成初始化準(zhǔn)備工作的。在大部分驅(qū)動(dòng)程序中,open()通常需要完成下列工作:1?檢查設(shè)備相關(guān)錯(cuò)誤,如設(shè)備尚未準(zhǔn)備好等。2?如果是第一次打開,則初始化硬件設(shè)備。3?識(shí)別次設(shè)備號(hào),如果有必要?jiǎng)t更新讀寫操作的當(dāng)前位置指針f_ops。4.分配和填寫要放在file->private_data里的數(shù)據(jù)結(jié)構(gòu)。5?使用計(jì)數(shù)增1。釋放設(shè)備是通過調(diào)用file_operations結(jié)構(gòu)中的函數(shù)release()來完成的,這個(gè)設(shè)備方法有時(shí)也被稱為close(),它的作用正好與open()相反,通常要完成下列工作:1?使用計(jì)數(shù)減1。2.釋放在file->private_data中分配的內(nèi)存。3?如果使用計(jì)算為0則關(guān)閉設(shè)備。設(shè)備的讀寫操作字符設(shè)備的讀寫操作相對(duì)比較簡單,直接使用函數(shù)read()和write()就可以了。但如果是塊設(shè)備的話,則需要調(diào)用函數(shù)block_read()和block_write()來進(jìn)行數(shù)據(jù)讀寫,這兩個(gè)函數(shù)將向設(shè)備請(qǐng)求表中增加讀寫請(qǐng)求,以便Linux內(nèi)核可以對(duì)請(qǐng)求順序進(jìn)行優(yōu)化。由于是對(duì)內(nèi)存緩沖區(qū)而不是直接對(duì)設(shè)備進(jìn)行操作的,因此能很大程度上加快讀寫速度。如果內(nèi)存緩沖區(qū)中沒有所要讀入的數(shù)據(jù),或者需要執(zhí)行寫操作將數(shù)據(jù)寫入設(shè)備,那么就要執(zhí)行真正的數(shù)據(jù)傳輸,這是通過調(diào)用數(shù)據(jù)結(jié)構(gòu)blk_dev_struct中的函數(shù)request_fn()來完成的。設(shè)備的控制操作除了讀寫操作外,應(yīng)用程序有時(shí)還需要對(duì)設(shè)備進(jìn)行控制,這可以通過設(shè)備驅(qū)動(dòng)程序中的函數(shù)ioctl()來完成,ioctl系統(tǒng)調(diào)用有下面的原型:intioctl(intfd,unsignedlongcmd,…),第一個(gè)參數(shù)是文件描述符,第二個(gè)參數(shù)是具體的命令,一般使用宏定義來確定,第三個(gè)參數(shù)一般是傳遞給驅(qū)動(dòng)中處理設(shè)備控制操作函數(shù)的參數(shù)。ioctl()的用法與具體設(shè)備密切關(guān)聯(lián),因此需要根據(jù)設(shè)備的實(shí)際情況進(jìn)行具體分析。設(shè)備的中斷和輪詢處理對(duì)于不支持中斷的硬件設(shè)備,讀寫時(shí)需要輪流查詢?cè)O(shè)備狀態(tài),以便決定是否繼續(xù)進(jìn)行數(shù)據(jù)傳輸。如果設(shè)備支持中斷,則可以按中斷方式進(jìn)行操作。

基本框架在用模塊方式實(shí)現(xiàn)PCI設(shè)備驅(qū)動(dòng)程序時(shí),通常至少要實(shí)現(xiàn)以下幾個(gè)部分:初始化設(shè)備模塊、設(shè)備打開模塊、數(shù)據(jù)讀寫和控制模塊、中斷處理模塊、設(shè)備釋放模塊、設(shè)備卸載模塊。下面給出一個(gè)典型的PCI設(shè)備驅(qū)動(dòng)程序的基本框架,從中不難體會(huì)到這幾個(gè)關(guān)鍵模塊是如何組織起來的。/*指明該驅(qū)動(dòng)程序適用于哪一些PCI設(shè)備*/staticstructpci_device_idmy_pci_tbl[]__initdata={{PCI_VENDOR_ID,PCI_DEVICE_ID,PCI_ANY_ID,PCI_ANY_ID,O,0,0},{0,}};/*對(duì)特定PCI設(shè)備進(jìn)行描述的數(shù)據(jù)結(jié)構(gòu)*/structdevice_private{}/*中斷處理模塊*/staticirqreturn_tdevice_interrupt(intirq,void*dev_id){/*...*/}/*設(shè)備文件操作接口*/staticstructfile_operationsdevice_fops={owner:THIS_MODULE,/*demo_fops所屬的設(shè)備模塊*/read:device_read,/*讀設(shè)備操作*/write:device_write,/*寫設(shè)備操作*/ioctl:device_ioctl,/*控制設(shè)備操作*/mmap:device_mmap,/*內(nèi)存重映射操作*/open:device_open,/*打開設(shè)備操作*/release:device_release/*釋放設(shè)備操作*//*...*/};/*設(shè)備模塊信息*/staticstructpci_drivermy_pci_driver={

name:DEVICE_MODULE_NAME,/*設(shè)備模塊名稱*/id_table:device_pci_tbl,/*能夠驅(qū)動(dòng)的設(shè)備列表*/probe:device_probe,/*查找并初始化設(shè)備*/remove:device_remove/*卸載設(shè)備模塊*//*...*/};staticint__initinit_module(void){/*...*/}staticvoid__exitcleanup_module(void){pci_unregister_driver(&my_pci_driver);}/*加載驅(qū)動(dòng)程序模塊入口*/module_init(init_module);/*卸載驅(qū)動(dòng)程序模塊入口*/module_exit(cleanup_module);上面這段代碼給出了一個(gè)典型的PCI設(shè)備驅(qū)動(dòng)程序的框架,是一種相對(duì)固定的模式。需要注意的是,同加載和卸載模塊相關(guān)的函數(shù)或數(shù)據(jù)結(jié)構(gòu)都要在前面加上__init、__exit等標(biāo)志符,以使同普通函數(shù)區(qū)分開來。構(gòu)造出這樣一個(gè)框架之后,接下去的工作就是如何完成框架內(nèi)的各個(gè)功能模塊了。針對(duì)相應(yīng)設(shè)備定義描述該P(yáng)CI設(shè)備的數(shù)據(jù)結(jié)構(gòu):structdevice_privatestructdevice_private/*注冊(cè)字符驅(qū)動(dòng)和發(fā)現(xiàn)PCI設(shè)備的時(shí)候使用*/structpci_dev*my_pdev;〃structcdevmy_cdev;〃dev_tmy_dev;atomic_tcreated;/*用于獲取PCI設(shè)備配置空間的基本信息*/unsignedlongmmio_addr;unsignedlongregs_len;intirq;//中斷號(hào)

/*用于保存分配給PCI設(shè)備的內(nèi)存空間的信息*/dma_addr_trx_dma_addrp;dma_addr_ttx_dma_addrp;/*基本的同步手段*/spinlock_tlock_send;spinlock_tlock_rev;/*保存內(nèi)存空間轉(zhuǎn)換后的地址信息*/void__iomem*ioaddr;unsignedlongvirts_addr;intopen_flag//設(shè)備打開標(biāo)記};初始化設(shè)備模塊:name:id_table:等staticstructpci_drivermy_pci_driver={DRV_NAME,//驅(qū)動(dòng)的名字,一般是一個(gè)宏定義my_pci_tbl,};初始化設(shè)備模塊:name:id_table:等staticstructpci_drivermy_pci_driver={DRV_NAME,//驅(qū)動(dòng)的名字,一般是一個(gè)宏定義my_pci_tbl,//包含了相關(guān)物理PCI設(shè)備的基本信息,vendorID,deviceID};probe:remove:pci_probe,//用于發(fā)現(xiàn)PCI設(shè)備__devexit_p(pci_remove),//PCI設(shè)備的移除//my_pci_tbl其實(shí)是一個(gè)structpci_device結(jié)構(gòu),該結(jié)構(gòu)可以有很多項(xiàng),每一項(xiàng)代表一個(gè)設(shè)備//該結(jié)構(gòu)可以包含很多項(xiàng),每一項(xiàng)表明使用該結(jié)構(gòu)的驅(qū)動(dòng)支持的設(shè)備//注意:需要以一個(gè)空的項(xiàng)結(jié)尾,也就是:{0,}staticstructpci_device_idmy_pci_tbl[]__initdata={{vendor_id,device_id,PCI_ANY_ID,PCI_ANY_ID,O,0,0},{0,}};staticint__initinit_module(void){intresult;printk(KERN_INFO"my_pci_driverbuilton%s,%s\n",_DATE_,_TIME_);result=pci_register_driver(&my_pci_driver);〃注冊(cè)設(shè)備驅(qū)動(dòng)if(result)returnresult;return0;}卸載設(shè)備模塊:staticvoid__devexitmy_pci_remove(structpci_dev*pci_dev){structdevice_private*private;private=(structdevice_private*)pci_get_drvdata(pci_dev);printk("FCswitch->irq=%d\n",private->irq);//register_w32是封裝的宏,便于直接操作//#defineregister_w32(reg,val32)iowrite32((val32),device_private->ioaddr+(reg))//這里的作用是關(guān)中斷,硬件復(fù)位

register_w32(IntrMask,0x00000001);register_w32(Reg_reset,0x00000001);//移除動(dòng)態(tài)創(chuàng)建的設(shè)備號(hào)和設(shè)備device_destroy(device_class,device->my_dev);class_destroy(device_class);cdev_del(&private->my_cdev);unregister_chrdev_region(priv->my_dev」);〃清理用于映射到用戶空間的內(nèi)存頁面for(private->virts_addr=(unsignedlong)private->rx_buf_virts;private->virts_addr<(unsignedlong)private->rx_buf_virts+BUF_SIZE;private->virts_addr+=PAGE_SIZE){ClearPageReserved(virt_to_page(FCswitch->virts_addr));}//釋放分配的內(nèi)存空間pci_free_consistent(private->my_pdev,BUF_SIZE,private->rx_buf_virts,private->rx_dma_addrp);free_irq(private->irq,private);iounmap(private->ioaddr);pci_release_regions(pci_dev);kfree(private);pci_set_drvdata(pci_dev,NULL);pci_disable_device(pci_dev);}//總之模塊卸載函數(shù)的職責(zé)就是釋放一切分配過的資源,根據(jù)自己代碼的需要進(jìn)行具體的操作PCI設(shè)備的探測(cè)(probe):

staticint__devinitpci_probe(structpci_dev*pci_dev,conststructpci_device_id*pci_id){unsignedlongmmio_start;unsignedlongmmio_end;unsignedlongmmio_flags;unsignedlongmmio_len;void__iomem*ioaddrl=NULL;structdevice_private*private;intresult;printk("probefunctionisrunning'n");/*啟動(dòng)PCI設(shè)備*/if(pci_enable_device(pci_dev)){printk(KERN_ERR"%s:cannotenabledevice\n",pci_name(pci_dev));return-ENODEV;}printk("enabledevice\n");/*在內(nèi)核空間中動(dòng)態(tài)申請(qǐng)內(nèi)存*/if((private=kmalloc(sizeof(structdevice_private),GFP_KERNEL))==NULL){printk(KERN_ERR"pci_demo:outofmemory'n");return-ENOMEM;}memset(private,0,sizeof(*private));private->my_pdev=pci_dev;mmio_start=pci_resource_start(pci_dev,0);mmio_end=pci_resource_end(pci_dev,0);mmio_flags=pci_resource_flags(pci_dev,0);mmio_len=pci_resource_len(pci_dev,0);printk("mmio_startis0x%0x\n",(unsignedint)mmio_start);printk("mmio_lenis0x%0x\n",(unsignedint)mmio_len);if(!(mmio_flags&IORESOURCE_MEM)){printk(KERN_ERR"cannotfindproperPCIdevicebaseaddress,aborting.'n');result=-ENODEV;gotoerr_out;}

/*對(duì)PCI區(qū)進(jìn)行標(biāo)記,標(biāo)記該區(qū)域已經(jīng)分配出去*/result=pci_request_regions(pci_dev,DEVICE_NAME);if(result)gotoerr_out;/*設(shè)置成總線主DMA模式*/pci_set_master(pci_dev);/*ioremap重映射一個(gè)物理地址范圍到處理器的虛擬地址空間,使它對(duì)內(nèi)核可用.*/ioaddrl=ioremap(mmio_start,mmio」en);if(ioaddrl==NULL){printk(KERN_ERR"%s:cannotremapmmio,aborting\n",pci_name(pci_dev));result=-EIO;gotoerr_out;}printk("ioaddr1=0x%0x\n",(unsignedint)ioaddr1);private->ioaddr=ioaddr1;private->mmio_addr=mmio_start;private->regs」en=mmio」en;private->irq=pci_dev->irq;printk("irqis%d\n",pci_dev->irq);/*初始化自旋鎖*/spin_lock_init(&private->lock_send);spin」ock_init(&private->lock_rev);if(my_register_chrdev(private))//注:這里的注冊(cè)字符設(shè)備,類似于前面的文章中介紹過的動(dòng)態(tài)創(chuàng)建設(shè)備號(hào)和動(dòng)態(tài)生成設(shè)備結(jié)點(diǎn){printk("chrdevregisterfail\n");gotoerr_out;}〃下面這兩個(gè)函數(shù)根據(jù)具體的硬件來處理,主要就是內(nèi)存分配、對(duì)硬件進(jìn)行初始化設(shè)置等device_init_buf(xx_device)〃這個(gè)函數(shù)主要進(jìn)行內(nèi)存分配,內(nèi)存映射,獲取中斷device_hw_start(xx_device)〃這個(gè)函數(shù)主要是往寄存器中寫一些值,復(fù)位硬件,開中

斷,打開DMA等〃把設(shè)備指針地址放入PCI設(shè)備中的設(shè)備指針中,便于后面調(diào)用pci_get_drvdatapci_set_drvdata(pci_dev,FCswitch);return0;err_out:printk("errorprocess*");resource_cleanup_dev(FCswitch);〃如果出現(xiàn)任何問題,釋放已經(jīng)分配了的資源returnresult;}//probe函數(shù)的作用就是啟動(dòng)pci設(shè)備,讀取配置空間信息,進(jìn)行相應(yīng)的初始化中斷處理:〃中斷處理,主要就是讀取中斷寄存器,然后調(diào)用中斷處理函數(shù)來處理中斷的下半部分,一般通過tasklet或者workqueue來實(shí)現(xiàn)注意:由于使用request_irq獲得的中斷是共享中斷,因此在中斷處理函數(shù)的上半部需要區(qū)分是不是該設(shè)備發(fā)出的中斷,這就需要讀取中斷狀態(tài)寄存器的值來判斷,如果不是該設(shè)備發(fā)起的中斷則返回IRQ_NONE奄staticirqreturn_tdevice_interrupt(intirq,void*dev_id)if(READ(IntMask)==0x00000001){returnIRQ_NONE;}WRITE(IntMask,0x00000001);tasklet_schedule(&my_tasklet);//需要先申明tasklet并關(guān)聯(lián)處理函數(shù)

returnIRQ_HANDLED;//聲明taskletstaticvoidmy_tasklet_process(unsignedlongunused);DECLARE_TASKLET(my_tasklet,my_tasklet_process,(unsignedlong)&private);〃第三個(gè)參數(shù)為傳遞給my_tasklet_process函數(shù)的參數(shù)設(shè)備驅(qū)動(dòng)的接口:staticstructfile_operationsdevice_fops={owner:THIS_MODULE,open:device_open,//打開設(shè)備ioctl:device_ioctl,〃設(shè)備控制操作mmap:device_mmap,〃內(nèi)存重映射操作release:device_release,〃釋放設(shè)備打開設(shè)備:open方法提供給驅(qū)動(dòng)來做任何的初始化來準(zhǔn)備后續(xù)的操作.open方法的原型是:int(*open)(structinode*inode,structfile*filp);inode參數(shù)有我們需要的信息,以它的i_cdev成員的形式,里面包含我們之前建立的cdev結(jié)構(gòu).唯一的問題是通常我們不想要cdev結(jié)構(gòu)本身,我們需要的是包含cdev結(jié)構(gòu)的device_private結(jié)構(gòu).龍staticintdevice_open(structinode*inode,structfile*filp){structdevice_private*private;private=container_of(inode->i_cdev,structdevice_private,my_cdev);

filp->private_data=private;private->open_flag++;try_module_get(THIS_MODULE);return0;}釋放設(shè)備:release方法的角色是open的反面,設(shè)備方法應(yīng)當(dāng)進(jìn)行下面的任務(wù):?釋放open分配在filp->private_data中的任何東西?在最后的close關(guān)閉設(shè)備staticintFCswitch_release(structinode*inode,structfile*filp){structdevice_private*private=filp->private_data;private->open_flag--;module_put(THIS_MODULE);printk("pcideviceclosesuccess*");return0;}設(shè)備控制操作:PCI設(shè)備驅(qū)動(dòng)程序可以通過device_fops

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論