Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)-2簡(jiǎn)單字符模塊_第1頁(yè)
Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)-2簡(jiǎn)單字符模塊_第2頁(yè)
Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)-2簡(jiǎn)單字符模塊_第3頁(yè)
Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)-2簡(jiǎn)單字符模塊_第4頁(yè)
Linux設(shè)備驅(qū)動(dòng)開(kāi)發(fā)-2簡(jiǎn)單字符模塊_第5頁(yè)
已閱讀5頁(yè),還剩11頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、Linux設(shè)備驅(qū)動(dòng)程序-簡(jiǎn)單字符模塊這一章主要通過(guò)介紹字符設(shè)備的驅(qū)動(dòng)程序編寫(xiě),來(lái)學(xué)習(xí)Linux設(shè)備驅(qū)動(dòng)的基本知識(shí)。Globalmem可以為真正的設(shè)備驅(qū)動(dòng)程序提供樣板。一、主設(shè)備號(hào)和次設(shè)備號(hào)主設(shè)備號(hào)表示設(shè)備對(duì)應(yīng)的驅(qū)動(dòng)程序;次設(shè)備號(hào)由內(nèi)核使用,用于正確確定設(shè)備文件所指的設(shè)備。主設(shè)備號(hào)相同的設(shè)備使用相同的驅(qū)動(dòng)程序,次設(shè)備號(hào)用于區(qū)分具體設(shè)備的實(shí)例。比如PC機(jī)中的IDE設(shè)備,一般主設(shè)備號(hào)使用3,WINDOWS進(jìn)行的分區(qū),一般將主分區(qū)的次設(shè)備號(hào)為1,擴(kuò)展分區(qū)的次設(shè)備號(hào)為2、3、4,邏輯分區(qū)使用5、6.。內(nèi)核用dev_t類(lèi)型(<linux/types.h>)來(lái)保存設(shè)備編號(hào),dev_t是一個(gè)32位

2、的數(shù),12位表示主設(shè)備號(hào),20位表示次設(shè)備號(hào)。在實(shí)際使用中,是通過(guò)<linux/kdev_t.h>中定義的宏來(lái)轉(zhuǎn)換格式。(dev_t)->主設(shè)備號(hào)、次設(shè)備號(hào)MAJOR(dev_tdev)MINOR(dev_tdev)主設(shè)備號(hào)、次設(shè)備號(hào)->(dev_t)MKDEV(intmajor,intminor)對(duì)于查看/dev目錄下的設(shè)備的主次設(shè)備號(hào)可以使用如下命令:/mnt/yaffsls/dev-lcrw1rootroot5,1Jan100:00consolecrw1rootroot5,64Jan100:00cua0crw1rootroot5,65Jan100:00cua1cr

3、w-rw-rw-1rootroot1,7Jan100:00fulldrwxr-xr-x1rootroot0Jan100:00keyboardcrw-r1rootroot1,2Jan100:00kmemcrw-r1rootroot1,1Jan100:00memdrwxr-xr-x1rootroot0Jan100:00mtddrwxr-xr-x1rootroot0Jan100:00mtdblockcrw-rw-rw-1rootroot1,3Jan100:00nullcrw-r1rootroot1,4Jan100:00portcrw1rootroot108,0Jan100:00pppcrw-rw-r

4、w-1rootroot5,2Jan100:00ptmxcrw-r-r-1rootroot1,8Jan100:00randomlr-xr-xr-x1rootroot4Jan100:00root->rd/0crw-rw-rw-1rootroot5,0Jan100:00ttycrw1rootroot4,64Jan100:11ttyS0crw1rootroot4,65Jan100:00ttyS1crw-r-r-1rootroot1,9Jan100:00urandomcrw-rw-rw-1 rootroot1,5 Jan 1 00:00 zero建立一個(gè)字符設(shè)備之前,驅(qū)動(dòng)程序首先要做的事情就是獲得

5、設(shè)備編號(hào)。其這主要函數(shù)在<linux/fs.h>中聲明:intregister_chrdev_region(dev_tfirst,unsignedintcount,char*name);/靜態(tài)指定設(shè)備編號(hào)intalloc_chrdev_region(dev_t*dev,unsignedintfirstminor,unsignedintcount,char*name);/動(dòng)態(tài)生成設(shè)備編號(hào)voidunregister_chrdev_region(dev_tfirst,unsignedintcount);/釋放設(shè)備編號(hào)分配之設(shè)備號(hào)的最佳方式是:默認(rèn)采用動(dòng)態(tài)分配,同時(shí)保留在加載甚至是編譯時(shí)

6、指定主設(shè)備號(hào)的余地。以下是在globalmeml.c中用來(lái)獲取主設(shè)備好的代碼:dev_tdevno=MKDEV(globalmem_major,0);/*申請(qǐng)?jiān)O(shè)備號(hào)*/if(globalmem_major)result=register_chrdev_region(devno,1,"globalmem");else/*動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào)*/result=alloc_chrdev_region(&devno,0,1,"globalmem");globalmem_major=MAJOR(devno);if(result<0)returnresult

7、;name是和該編號(hào)范圍file_operations在這部分中,比較重要的是在用函數(shù)獲取設(shè)備編號(hào)后,其中的參數(shù)中。關(guān)聯(lián)的設(shè)備名稱(chēng),它將出現(xiàn)在/proc/devices二、一些重要的數(shù)據(jù)結(jié)構(gòu)大部分基本的驅(qū)動(dòng)程序操作涉及及到三個(gè)重要的內(nèi)核數(shù)據(jù)結(jié)構(gòu),分別是file和inode,它們的定義都在<linux/fs.h>。三、字符設(shè)備的注冊(cè)內(nèi)核內(nèi)部使用structcdev結(jié)構(gòu)來(lái)表示字符設(shè)備。在內(nèi)核調(diào)用設(shè)備的操作之前,必須分配并注冊(cè)一個(gè)或多個(gè)structcdev。代碼應(yīng)包含<linux/cdev.h>,它定義了structcdev以及與其相關(guān)的一些輔助函數(shù)。我們一般將cdev結(jié)構(gòu)嵌

8、入到自己的設(shè)備特定結(jié)構(gòu)中去如:structglobalmem_devstructcdevcdev;/*cdev結(jié)構(gòu)體*/unsignedcharmemGLOBALMEM_SIZE;/*全局內(nèi)存*/;注冊(cè)一個(gè)獨(dú)立的cdev設(shè)備的基本過(guò)程如下:1、為自己的設(shè)備結(jié)構(gòu)體分配空間structglobalmem_dev*globalmem_devp;/*設(shè)備結(jié)構(gòu)體指針*/globalmem_devp=kmalloc(sizeof(structglobalmem_dev),GFP_KERNEL);if(!globalmem_devp)/*申請(qǐng)失敗*/result =-ENOMEM;gotofail_mall

9、oc;memset(globalmem_devp,0,sizeof(structglobalmem_dev);2、初始化structcdevvoidcdev_init(structcdev*cdev,conststructfile_operations*fops)cdev.owner=THIS_MODULE;4、cdev設(shè)置完成,通知內(nèi)核structcdev的信息(在執(zhí)行這步之前必'須確定你對(duì)structcdev的以上設(shè)置已經(jīng)完成!)intcdev_add(structcdev*p,dev_tdev,unsignedcount)5、從系統(tǒng)中移除一個(gè)字符設(shè)備:voidcdev_del(s

10、tructcdev*p)以下globalmem的初始化代碼/*初始化并注冊(cè)cdev*/staticvoidglobalmem_setup_cdev(structglobalmem_dev*dev,intindex)interr,devno=MKDEV(globalmem_major,index);cdev_init(&dev->cdev,&globalmem_fops);dev->cdev.owner=THIS_MODULE;dev->cdev.ops=&globalmem_fops;err=cdev_add(&dev->cdev,dev

11、no,1);if(err)printk(KERN_NOTICE"Error%daddingglobalmem%d",err,index);/*設(shè)備驅(qū)動(dòng)模塊加載函數(shù)*/intglobalmem_init(void)intresult;dev_tdevno=MKDEV(globalmem_major,0);/*申請(qǐng)?jiān)O(shè)備號(hào)*/if(globalmem_major)result=register_chrdev_region(devno,1,"globalmem");else/*動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備號(hào)*/result=alloc_chrdev_region(&de

12、vno,0,1,"globalmem");globalmem_major=MAJOR(devno);if(result<0)returnresult;/*動(dòng)態(tài)申請(qǐng)?jiān)O(shè)備結(jié)構(gòu)體的內(nèi)存*/globalmem_devp=kmalloc(sizeof(structglobalmem_dev),GFP_KERNEL);if(!globalmem_devp)/*申請(qǐng)失敗*/result=-ENOMEM;gotofail_malloc;memset(globalmem_devp,0,sizeof(structglobalmem_dev);globalmem_setup_cdev(gl

13、obalmem_devp,0);return0;fail_malloc:unregister_chrdev_region(devno,1);returnresult;四、內(nèi)存申請(qǐng)函數(shù)Globalmem驅(qū)動(dòng)程序引入了兩個(gè)Linux內(nèi)核中用于內(nèi)存管理的核心函數(shù),它們的定義都在<linux/slab.h>:void*kmalloc(size_tsize,intflags);voidkfree(void*ptr);例子:#include<linux/slab.h>char*buff;buff=kmalloc(1024,GFP_KERNEL);if(buff!=NULL)kfre

14、e(buff);elseprintk("kmallocerrorn");flags的參數(shù)GFP_KERNEL請(qǐng)求動(dòng)態(tài)內(nèi)存總是分配成功,如無(wú)則等待。故不能用在中斷中。GFP_ATOMIC無(wú)條件分配內(nèi)存,沒(méi)有立即釋放,進(jìn)程不睡眠。GFP_DMA用于分配連續(xù)的物理內(nèi)存五、open和release、open方法提供給驅(qū)動(dòng)程序以初始化的能力,為以后的操作作準(zhǔn)備。應(yīng)完成的工作如下:(1)檢查設(shè)備特定的錯(cuò)誤(如設(shè)備未就緒或硬件問(wèn)題);(2)如果設(shè)備是首次打開(kāi),則對(duì)其進(jìn)行初始化;(3)如有必要,更新f_op文件指針;(4)分配并填寫(xiě)置于filp->private_data里的數(shù)據(jù)結(jié)構(gòu)

15、。而根據(jù)globalmem的實(shí)際情況,他的open函數(shù)只要完成第四步(將初始化過(guò)的structglobalmem_devdev的指針傳遞到filp->private_data里,以備后用)就好了,所以open函數(shù)很簡(jiǎn)單。但是其中用到了定義在<linux/kernel.h>中的container_of宏,源碼如下:#definecontainer_of(ptr,type,member)(consttypeof(type*)0)->member)*._mptr=(ptr);(type*)(char*)_mptr-offsetof(type,member);)其實(shí)從源碼可以看

16、出,其作用就是:通過(guò)指針ptr,獲得包含ptr所指向數(shù)據(jù)(是member結(jié)構(gòu)體)的type結(jié)構(gòu)體的指針。即是用指針得到另外一個(gè)指針。intglobalmem_open(structinode*inode,structfile*filp)/*將設(shè)備結(jié)構(gòu)體指針賦值給文件私有數(shù)據(jù)指針*/structglobalmem_dev*dev;dev=container_of(inode->i_cdev,structglobalmem_dev,cdev);filp->private_data=dev;return0;第一個(gè)參數(shù)是結(jié)構(gòu)體成員的指針,第二個(gè)參數(shù)為整個(gè)結(jié)構(gòu)體的類(lèi)型,第三個(gè)參數(shù)為傳入的第一

17、個(gè)參數(shù)即結(jié)構(gòu)體成員的類(lèi)型,返回值為整個(gè)結(jié)構(gòu)體的指針。、release方法提供釋放內(nèi)存,關(guān)閉設(shè)備的功能。應(yīng)完成的工作如下:(1)釋放由open分配的、保存在file->private_data中的所有內(nèi)容;(2)在最后一次關(guān)閉操作時(shí)關(guān)閉設(shè)備。有時(shí)執(zhí)行的內(nèi)容和exit里面的內(nèi)容重合,所以本代碼有的時(shí)候什么也不做。六、read和writeread和write方法的主要作用就是實(shí)現(xiàn)內(nèi)核與用戶(hù)空間之間的數(shù)據(jù)拷貝。因?yàn)長(zhǎng)inux的內(nèi)核空間和用戶(hù)空間隔離的,所以要實(shí)現(xiàn)數(shù)據(jù)拷貝就必須使用在<asm/uaccess.h>中定義的:read方法完成將數(shù)據(jù)從內(nèi)核拷貝到應(yīng)用程序空間,write方法相

18、反,將數(shù)據(jù)從應(yīng)用程序空間拷貝到內(nèi)核。對(duì)于這兩個(gè)方法,參數(shù)filp是文件指針,count是請(qǐng)求傳輸數(shù)據(jù)的長(zhǎng)度,buffer是用戶(hù)空間的數(shù)據(jù)緩沖區(qū),ppos(有時(shí)候?qū)懗蒮pos都是一個(gè)概念)是文件中進(jìn)行操作的偏移量,類(lèi)型為64位數(shù)。由于用戶(hù)空間和內(nèi)核空間的內(nèi)存映射方式完全不同,所以不能使用象memcpy之類(lèi)的函數(shù),必須使用如下函數(shù):unsignedlongcopy_to_user(void_user*to,constvoid*from,unsignedlongcount);unsignedlongcopy_from_user(void*to,constvoid_user*from,unsigned

19、longcount);如果要復(fù)制的為簡(jiǎn)單類(lèi)型,如char,long,int等,則可以使用簡(jiǎn)單的put_user()和get_user().如下所示:intval;/內(nèi)核空間整型變量get_user(val,(int*)arg);/用戶(hù)空間到內(nèi)核空間,arg是用戶(hù)空間的地址put_user(val,(int*)arg);/內(nèi)核空間到用戶(hù)空間,arg是用戶(hù)空間的地址至于read和write的具體函數(shù)比較簡(jiǎn)單,就在實(shí)驗(yàn)中驗(yàn)證好了。?read的返回值1 .返回值等于傳遞給read系統(tǒng)調(diào)用的count參數(shù),表明請(qǐng)求的數(shù)據(jù)傳輸成功。2 .返回值大于0,但小于傳遞給read系統(tǒng)調(diào)用的count參數(shù),表明部分

20、數(shù)據(jù)傳輸成功,根據(jù)設(shè)備的不同,導(dǎo)致這個(gè)問(wèn)題的原因也不同,一般采取再次讀取的方法。3 .返回值=0,表示到達(dá)文件的末尾。4 .返回值為負(fù)數(shù),表示出現(xiàn)錯(cuò)誤,并且指明是何種錯(cuò)誤。5 .在阻塞型io中,read調(diào)用會(huì)出現(xiàn)阻塞。?Write的返回值1 .返回值等于傳遞給write系統(tǒng)調(diào)用的count參數(shù),表明請(qǐng)求的數(shù)據(jù)傳輸成功。2 .返回值大于0,但小于傳遞給write系統(tǒng)調(diào)用的count參數(shù),表明部分?jǐn)?shù)據(jù)傳輸成功,根據(jù)設(shè)備的不同,導(dǎo)致這個(gè)問(wèn)題的原因也不同,一般采取再次讀取的方法。3 .返回值=0,表示沒(méi)有寫(xiě)入任何數(shù)據(jù)。標(biāo)準(zhǔn)庫(kù)在調(diào)用write時(shí),出現(xiàn)這種情況會(huì)重復(fù)調(diào)用write。4 .返回值為負(fù)數(shù),表示

21、出現(xiàn)錯(cuò)誤,并且指明是何種錯(cuò)誤。錯(cuò)誤號(hào)的定義參見(jiàn)<linux/errno.h>5 .在阻塞型io中,write調(diào)用會(huì)出現(xiàn)阻塞。七、模塊實(shí)驗(yàn)測(cè)試結(jié)果:rootNEU/#insmod/lib/modules/rootNEU/#Ismodglobalmem29200-Live0xbf000000rootNEU/#cat/proc/devicesCharacterdevices:1 mem2 pty3 ttyp4 /dev/vc/05 tty6 /dev/tty7 /dev/console8 /dev/ptmx9 vcs10 misc13 input14 sound21sg29fb81vid

22、eo4linux90mtd128ptm136pts180usb189usb_device204s3c2410_serial253globalmem254devfsBlockdevices:1ramdisk31mtdblock180ubrootNEU/#rootNEU/#mknod/dev/globalmemc2530rootNEU/#ls/dev/globalmem/dev/globalmemrootNEU/#echohello>/dev/globalmemwritten6bytes(s)from0rootNEU/#cat/dev/globalmemread4096bytes(s)fro

23、m0hellocat:readerror:NosuchdeviceoraddressrootNEU/#八、附錄:file_operations結(jié)構(gòu) :structmodule*owner第一個(gè)file_operations成員根本不是一個(gè)操作;它是一個(gè)指向擁有這個(gè)結(jié)構(gòu)的模塊的指針.這個(gè)成員用來(lái)在它的操作還在被使用時(shí)阻止模塊被卸載.幾乎所有時(shí)間中,它被簡(jiǎn)單初始化為T(mén)HIS_MODULE,一個(gè)在<linux/module.h>中定義的宏.loff_t(*llseek)(structfile*,loff_t,int);llseek方法用作改變文件中的當(dāng)前讀/寫(xiě)位置,并且新位置作為(正的)

24、返回值.loff_t參數(shù)是一個(gè)"longoffset",并且就算在32位平臺(tái)上也至少64位寬.錯(cuò)誤由一個(gè)負(fù)返回值指示.如果這個(gè)函數(shù)指針是NULL,seek調(diào)用會(huì)以潛在地?zé)o法預(yù)知的方式修改file結(jié)構(gòu)中的位置計(jì)數(shù)器(在"file結(jié)構(gòu)"一節(jié)中描述).ssize_t(*read)(structfile*,char_user*,size_t,loff_t*);用來(lái)從設(shè)備中獲取數(shù)據(jù).在這個(gè)位置的一個(gè)空指針導(dǎo)致read系統(tǒng)調(diào)用以-EINVAL("Invalidargument")失敗.一個(gè)非負(fù)返回值代表了成功讀取的字節(jié)數(shù)(返回值是一個(gè)"

25、signedsize"類(lèi)型,常常是目標(biāo)平臺(tái)本地的整數(shù)類(lèi)型).ssize_t(*aio_read)(structkiocb*,char_user*,size_t,loff_t);初始化一個(gè)異步讀-可能在函數(shù)返回前不結(jié)束的讀操作.如果這個(gè)方法是NULL,所有的操作會(huì)由read代替進(jìn)行(同步地).ssize_t(*write)(structfile*,constchar_user*,size_t,loff_t*);發(fā)送數(shù)據(jù)給設(shè)備.如果NULL,-EINVAL返回給調(diào)用write系統(tǒng)調(diào)用的程序.如果非負(fù),返回值代表成功寫(xiě)的字節(jié)數(shù).ssize_t(*aio_write)(structkiocb

26、*,constchar_user*,size_t,loff_t*);初始化設(shè)備上的一個(gè)異步寫(xiě).int(*readdir)(structfile*,void*,filldir_t);對(duì)于設(shè)備文件這個(gè)成員應(yīng)當(dāng)為NULL;它用來(lái)讀取目錄,并且僅對(duì)文件系統(tǒng)有用.unsignedint(*poll)(structfile*,structpoll_table_struct*);poll方法是3個(gè)系統(tǒng)調(diào)用的后端:poll,epoll,和select,都用作查詢(xún)對(duì)一個(gè)或多個(gè)文件描述符的讀或?qū)懯欠駮?huì)阻塞.poll方法應(yīng)當(dāng)返回一個(gè)位掩碼指示是否非阻塞的讀或?qū)懯强赡艿?并且,可能地,提供給內(nèi)核信息用來(lái)使調(diào)用進(jìn)程睡眠

27、直到I/O變?yōu)榭赡?如果一個(gè)驅(qū)動(dòng)的poll方法為NULL,設(shè)備假定為不阻塞地可讀可寫(xiě).int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);ioctl系統(tǒng)調(diào)用提供了發(fā)出設(shè)備特定命令的方法(例如格式化軟盤(pán)的一個(gè)磁道,這不是讀也不是寫(xiě)).另外,幾個(gè)ioctl命令被內(nèi)核識(shí)別而不必引用fops表.如果設(shè)備不提供ioctl方法,對(duì)于任何未事先定義的請(qǐng)求(-ENOTTY,"設(shè)備無(wú)這樣的ioctl"),系統(tǒng)調(diào)用返回一個(gè)錯(cuò)誤.int(*mmap)(structfile*,structvm_area_struct*);m

28、map用來(lái)請(qǐng)求將設(shè)備內(nèi)存映射到進(jìn)程的地址空間.如果這個(gè)方法是NULL,mmap系統(tǒng)調(diào)用返回-ENODEV.int(*open)(structinode*,structfile*);盡管這常常是對(duì)設(shè)備文件進(jìn)行的第一個(gè)操作,不要求驅(qū)動(dòng)聲明一個(gè)對(duì)應(yīng)的方法.如果這個(gè)項(xiàng)是NULL,設(shè)備打開(kāi)一直成功,但是你的驅(qū)動(dòng)不會(huì)得到通知.int(*flush)(structfile*);flush操作在進(jìn)程關(guān)閉它的設(shè)備文件描述符的拷貝時(shí)調(diào)用;它應(yīng)當(dāng)執(zhí)行(并且等待)設(shè)備的任何未完成的操作.這個(gè)必須不要和用戶(hù)查詢(xún)請(qǐng)求的fsync操作混淆了.當(dāng)前,flush在很少驅(qū)動(dòng)中使用;SCSI磁帶驅(qū)動(dòng)使用它,例如,為確保所有寫(xiě)的數(shù)據(jù)

29、在設(shè)備關(guān)閉前寫(xiě)到磁帶上.如果flush為NULL,內(nèi)核簡(jiǎn)單地忽略用戶(hù)應(yīng)用程序的請(qǐng)求.int(*release)(structinode*,structfile*);在文件結(jié)構(gòu)被釋放時(shí)引用這個(gè)操作.如同open,release可以為NULL.int(*fsync)(structfile*,structdentry*,int);這個(gè)方法是fsync系統(tǒng)調(diào)用的后端,用戶(hù)調(diào)用來(lái)刷新任何掛著的數(shù)據(jù).如果這個(gè)指針是NULL,系統(tǒng)調(diào)用返回-EINVAL.int(*aio_fsync)(structkiocb*,int);這是fsync方法的異步版本.int(*fasync)(int,structfile*,

30、int);這個(gè)操作用來(lái)通知設(shè)備它的FASYNC標(biāo)志的改變.異步通知是一個(gè)高級(jí)的主題,在第6章中描述.這個(gè)成員可以是NULL如果驅(qū)動(dòng)不支持異步通知.int(*lock)(structfile*,int,structfile_lock*);lock方法用來(lái)實(shí)現(xiàn)文件加鎖;加鎖對(duì)常規(guī)文件是必不可少的特性,但是設(shè)備驅(qū)動(dòng)幾乎從不實(shí)現(xiàn)它.ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*);

31、這些方法實(shí)現(xiàn)發(fā)散/匯聚讀和寫(xiě)操作.應(yīng)用程序偶爾需要做一個(gè)包含多個(gè)內(nèi)存區(qū)的單個(gè)讀或?qū)懖僮?;這些系統(tǒng)調(diào)用允許它們這樣做而不必對(duì)數(shù)據(jù)進(jìn)行額外拷貝.如果這些函數(shù)指針為NULL,read和write方法被調(diào)用(可能多于一次).ssize_t(*sendfile)(structfile*,loff_t*,size_t,read_actor_t,void*);這個(gè)方法實(shí)現(xiàn)sendfile系統(tǒng)調(diào)用的讀,使用最少的拷貝從一個(gè)文件描述符搬移數(shù)據(jù)到另一個(gè).例如,它被一個(gè)需要發(fā)送文件內(nèi)容到一個(gè)網(wǎng)絡(luò)連接的web服務(wù)器使用.設(shè)備驅(qū)動(dòng)常常使sendfile為NULL.ssize_t(*sendpage)(structfil

32、e*,structpage*,int,size_t,loff_t*,int);sendpage是sendfile的另一半;它由內(nèi)核調(diào)用來(lái)發(fā)送數(shù)據(jù),一次一頁(yè),到對(duì)應(yīng)的文件.設(shè)備驅(qū)動(dòng)實(shí)際上不實(shí)現(xiàn)sendpage.unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);這個(gè)方法的目的是在進(jìn)程的地址空間找一個(gè)合適的位置來(lái)映射在底層設(shè)備上的內(nèi)存段中.這個(gè)任務(wù)通常由內(nèi)存管理代碼進(jìn)行;這個(gè)方法存在為了使驅(qū)動(dòng)能強(qiáng)制特殊設(shè)備可能有的任何的對(duì)齊請(qǐng)求.大部分驅(qū)動(dòng)可以置這個(gè)方法為

33、NULL.10int(*check_flags)(int)這個(gè)方法允許模塊檢查傳遞給fnctl(F_SETFL)調(diào)用的標(biāo)志.int(*dir_notify)(structfile*,unsignedlong);這個(gè)方法在應(yīng)用程序使用fcntl來(lái)請(qǐng)求目錄改變通知時(shí)調(diào)用.只對(duì)文件系統(tǒng)有用;驅(qū)動(dòng)不需要實(shí)現(xiàn)dir_notifyfile_operations結(jié)構(gòu)是整個(gè)Linux內(nèi)核的重要數(shù)據(jù)結(jié)構(gòu),它也是file、inode結(jié)構(gòu)的重要成員,表中分別說(shuō)明結(jié)構(gòu)中主要的成員:表file_operations結(jié)構(gòu)Ownermodule的擁有者。Llseek重新定位讀寫(xiě)位置。Read從設(shè)備中讀取數(shù)據(jù)。Write向字

34、符設(shè)備中寫(xiě)入數(shù)據(jù)。Readdir只用于文件系統(tǒng),對(duì)設(shè)備無(wú)用。Ioctl控制設(shè)備,除讀寫(xiě)操作外的其他控制命令。Mmap將設(shè)備內(nèi)存映射到進(jìn)程地址空間,通常只用于塊設(shè)備。Open打開(kāi)設(shè)備并初始化設(shè)備。Flush清除內(nèi)容,一般只用于網(wǎng)絡(luò)文件系統(tǒng)中。Release關(guān)閉設(shè)備并釋放資源。Fsync實(shí)現(xiàn)內(nèi)存與設(shè)備的同步,如將內(nèi)存數(shù)據(jù)寫(xiě)入硬盤(pán)。Fasync實(shí)現(xiàn)內(nèi)存與設(shè)備之間的異步通訊。Lock文件鎖定,用于文件共享時(shí)的互斥訪問(wèn)。Readv在進(jìn)行讀操作前要驗(yàn)證地址是否可讀。Writev在進(jìn)行寫(xiě)操作前要驗(yàn)證地址是否可寫(xiě)。在嵌入式系統(tǒng)的開(kāi)發(fā)中,我們一般僅僅實(shí)現(xiàn)其中幾個(gè)接口函數(shù):read、write、ioctl、ope

35、n、release,就可以完成應(yīng)用系統(tǒng)需要的功能。structfile_operationsglobalmem_fops=.owner=THIS_MODULE,.llseek=scull_llseek,.read=scull_read,.write=scull_write,.ioctl=scull_ioctl,.open=scull_open,.release=scull_release,;staticstructfile_operationsglobalmem_fops=完成了將驅(qū)動(dòng)函數(shù)映射為標(biāo)準(zhǔn)接口,上面的這種特殊表示方法不是標(biāo)準(zhǔn)C的語(yǔ)法,這是GNU譯器的一種特殊擴(kuò)展,它使用名字對(duì)進(jìn)行結(jié)構(gòu)

36、字段的初始化,它的好處體現(xiàn)在結(jié)構(gòu)清晰,易于理解,并且避免了結(jié)構(gòu)發(fā)生變化帶來(lái)的許多問(wèn)題。structfile結(jié)構(gòu)定義于<linux/fs.h>,是設(shè)備驅(qū)動(dòng)中第二個(gè)最重要的數(shù)據(jù)結(jié)構(gòu).系統(tǒng)中每個(gè)打開(kāi)的文件有一個(gè)關(guān)聯(lián)的structfile在內(nèi)核空間).它由內(nèi)核在open時(shí)創(chuàng)建,并傳遞給在文件上操作的任何函數(shù),直到最后的關(guān)閉.在文件的所有實(shí)例都關(guān)閉后,內(nèi)核釋放這個(gè)數(shù)據(jù)結(jié)構(gòu).在內(nèi)核源碼中,structfile的指針常常稱(chēng)為file或者filp("filepointer").我們將一直稱(chēng)這個(gè)指針為filp以避免和結(jié)構(gòu)自身混淆.因此,file指的是結(jié)構(gòu),而filp是結(jié)構(gòu)指針.m

37、ode_tf_mode;文件模式確定文件是可讀的或者是可寫(xiě)的(或者都是),通過(guò)位FMODE_READ和FMODE_WRITE.你可能想在你的open或者ioctl函數(shù)中檢查這個(gè)成員的讀寫(xiě)許可,但是你不需要檢查讀寫(xiě)許可,因?yàn)閮?nèi)核在調(diào)用你的方法之前檢查.當(dāng)文件還沒(méi)有為那種存取而打開(kāi)時(shí)讀或?qū)懙钠髨D被拒絕,驅(qū)動(dòng)甚至不知道這個(gè)情況.loff_tf_pos;當(dāng)前讀寫(xiě)位置.loff_t在所有平臺(tái)都是64位(在gcc術(shù)語(yǔ)里是longlong).驅(qū)動(dòng)可以讀這個(gè)值,如果它需要知道文件中的當(dāng)前位置,但是正常地不應(yīng)該改變它讀和寫(xiě)應(yīng)當(dāng)使用它們作為最后參數(shù)而收到的指針來(lái)更新一個(gè)位置,代替直接作用于filp->f_p

38、os.這個(gè)規(guī)則的一個(gè)例外是在llseek方法中,它的目的就是改變文件位置.另一種解釋?zhuān)捍俗兞匡@示出當(dāng)前讀寫(xiě)位置,而由read,write,llseek等可修改讀寫(xiě)位置的函數(shù)改變,用在管理文件指針的設(shè)備驅(qū)動(dòng)程序上。unsignedintf_flags;這些是文件標(biāo)志,例如O_RDONLY,O_NONBLOCK,和O_SYNC.驅(qū)動(dòng)應(yīng)當(dāng)檢查O_NONBLOCK標(biāo)志來(lái)看是否是請(qǐng)求非阻塞操作(我們?cè)诘谝徽碌?quot;阻塞和非阻塞操作"一節(jié)中討論非阻塞I/O);其他標(biāo)志很少使用.特別地,應(yīng)當(dāng)檢查讀/寫(xiě)許可,使用f_mode而不是f_flags.所有的標(biāo)志在頭文件<linux/fcntl.h>中定義.structfile_operations*f_op;和文件關(guān)聯(lián)的操作.內(nèi)核安排指針作為它的open實(shí)現(xiàn)的一部分,接著讀取它當(dāng)它需要分派任何的操作時(shí).filp->

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論