第3章字符設(shè)備驅(qū)動程序_第1頁
第3章字符設(shè)備驅(qū)動程序_第2頁
第3章字符設(shè)備驅(qū)動程序_第3頁
第3章字符設(shè)備驅(qū)動程序_第4頁
第3章字符設(shè)備驅(qū)動程序_第5頁
已閱讀5頁,還剩63頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1324第3章字符設(shè)備驅(qū)動程序scull的設(shè)計(jì)主設(shè)備號與次設(shè)備號一些重要的數(shù)據(jù)結(jié)構(gòu)字符設(shè)備的注冊open和releasescull的內(nèi)存使用read和write567scull的設(shè)計(jì)scull0~scull3由全局且持久的內(nèi)存區(qū)組成,可被多次打開,關(guān)閉后再打開,仍能保持原數(shù)據(jù)scullpipe0toscullpipe3FIFO(先進(jìn)先出)設(shè)備,類似管道,可由一個(gè)進(jìn)程讀,另一個(gè)進(jìn)程寫Scullsingle、scullpriv、sculluid、scullwuid與scull0類似,但在open操作方面有些限制1324第3章字符設(shè)備驅(qū)動程序scull的設(shè)計(jì)主設(shè)備號與次設(shè)備號一些重要的數(shù)據(jù)結(jié)構(gòu)字符設(shè)備的注冊open和releasescull的內(nèi)存使用read和write567主設(shè)備號與次設(shè)備號$ls–l/devcrw-rw-rw-1rootroot1,3Apr112002nullcrw1rootroot10,1Apr112002psauxcrw1rootroot4,1Oct2803:04tty1crw-rw-rw-1roottty4,64Apr112002ttys0crw-rw1rootuucp4,65Apr112002ttyS1crw--w1vcsatty7,1Apr112002vcs1crw--w1vcsatty7,129Apr112002vcsa1crw-rw-rw-1rootroot1,5Apr112002zero

主設(shè)備號通常用于標(biāo)識設(shè)備對應(yīng)的驅(qū)動程序,號相同的設(shè)備共用一個(gè)驅(qū)動程序;次設(shè)備號用于標(biāo)識驅(qū)動程序所服務(wù)的具體設(shè)備主設(shè)備號次設(shè)備號主設(shè)備號與次設(shè)備號設(shè)備編號的內(nèi)部表達(dá)內(nèi)核中,設(shè)備編號數(shù)據(jù)類型為dev_t,定義在<linux/types.h>中操作設(shè)備編號的宏MAJOR(dev_tdev);由dev_t數(shù)得到主設(shè)備號MINOR(dev_tdev);由dev_t數(shù)得到次設(shè)備號MKDEV(intmajor,intminor);由主、次設(shè)備號得到dev_t數(shù)主設(shè)備號次設(shè)備號12位20位dev_t主設(shè)備號與次設(shè)備號靜態(tài)分配設(shè)備編號intregister_chrdev_region(dev_tfirst,unsignedintcount,char*name);first:主設(shè)備號范圍起始值,次設(shè)備號通常為0count:連續(xù)設(shè)備號的個(gè)數(shù)name:設(shè)備編號范圍關(guān)聯(lián)的設(shè)備名稱,將出現(xiàn)在/proc/devices和/sysfs中成功返回0,失敗返回負(fù)數(shù)靜態(tài)分配需要預(yù)先知道可使用的設(shè)備號,如何知道?內(nèi)核源代碼樹的Documenttation/devices.text可查到尚有哪些號可用主設(shè)備號與次設(shè)備號動態(tài)分配設(shè)備編號intalloc_chrdev_region(dev_t*dev,unsignedintfirstminor,unsignedintcount,char*name);dev:調(diào)用成功后保存分配到的設(shè)備編號范圍的第一個(gè)數(shù)firstminor:第一個(gè)次設(shè)備號,通常用是0count與name與靜態(tài)分配時(shí)相同釋放設(shè)備編號voidunregister_chrdev_region(dev_tfirst,unsignedintcount);

主設(shè)備號與次設(shè)備號scull設(shè)備號分配if(scull_major){dev=MKDEV(scull_major,scull_minor);result=register_chrdev_region(dev,scull_nr_devs,"scull");}else{result=alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,"scull");scull_major=MAJOR(dev);}

if(result<0){printk(KERN_WARNING"scull:can'tgetmajor%d\n",scull_major);returnresult;}scull_major為全局變量,初始化值為SCULL_MAJOR,定義在scull.h中,設(shè)為0時(shí)為動態(tài)分配(默認(rèn)),否則為靜態(tài)分配。主設(shè)備號與次設(shè)備號scull_load靜態(tài)分配的問題是:若驅(qū)動程序僅自己使用,選擇一個(gè)未用的號來用沒什么問題,但若驅(qū)動程序被廣泛使用,則可能造成沖突動態(tài)分配的問題是:由于分配的主設(shè)備號不能始終一至,所以無法預(yù)先創(chuàng)建設(shè)備節(jié)點(diǎn)一旦分配了設(shè)備號,就可從/proc/devices中讀到,因此可寫一腳本代替insmod,在載入模塊后讀出設(shè)備號并創(chuàng)建節(jié)點(diǎn)。即用一腳本完成加載模塊、讀出主設(shè)備號及創(chuàng)建設(shè)備節(jié)點(diǎn)等操作。scull設(shè)備的這一腳本叫scull_load主設(shè)備號與次設(shè)備號/proc/devices文件如下:Characterdevices: 1mem 2pty 3ttyp 4ttyS 6lp 7vcs 10misc 13input 14sound 21sg 180usbBlockdevices:2fd8sd11sr65sd66sd

主設(shè)備號與次設(shè)備號/*Scull_load*/#!/bin/shmodule="scull"device="scull"mode="664"/sbin/insmod./$module.ko$*||exit1rm-f/dev/${device}[0-3]major=$(awk"\$2==\"$module\"{print\$1}"/proc/devices)mknod/dev/${device}0c$major0mknod/dev/${device}1c$major1mknod/dev/${device}2c$major2mknod/dev/${device}3c$major3group="staff“grep-q'^staff:'/etc/group||group="wheel“chgrp$group/dev/${device}[0-3]chmod$mode/dev/${device}[0-3]#awk‘條件類型1{動作1}條件類型2{動作2}…’filename#grep[參數(shù)]‘搜索字符串’filename主設(shè)備號與次設(shè)備號也可編寫一個(gè)init腳本放在/etc/init.d下,可在系統(tǒng)初始化時(shí)加載模塊、并根據(jù)主設(shè)備號創(chuàng)建節(jié)點(diǎn)若只涉及單個(gè)驅(qū)動,因動態(tài)設(shè)備號的分配并不是真正隨機(jī)生成的,故只需在第一次加載時(shí)創(chuàng)建節(jié)點(diǎn),以后加載時(shí)無需再創(chuàng)節(jié)點(diǎn)1324第3章字符設(shè)備驅(qū)動程序scull的設(shè)計(jì)主設(shè)備號與次設(shè)備號一些重要的數(shù)據(jù)結(jié)構(gòu)字符設(shè)備的注冊open和releasescull的內(nèi)存使用read和write567一些重要的數(shù)據(jù)結(jié)構(gòu)大部分的驅(qū)動程序操作涉及到3個(gè)重要的內(nèi)核數(shù)據(jù)結(jié)構(gòu),分別是:file_operations:文件操作結(jié)構(gòu),保存文件操作方法file:文件結(jié)構(gòu),對應(yīng)一個(gè)打開的文件inode:節(jié)點(diǎn)結(jié)構(gòu),對應(yīng)一個(gè)文件在編寫真正的驅(qū)動程序前,需要對這3個(gè)結(jié)構(gòu)有一個(gè)基本的認(rèn)識。一些重要的數(shù)據(jù)結(jié)構(gòu)file_operations,在<linux/fs.h>中定義structfile_operations{ structmodule*owner; loff_t(*llseek)(structfile*,loff_t,int); ssize_t(*read)(structfile*,char__user*,size_t,loff_t*); ssize_t(*aio_read)(structkiocb*,char__user*,size_t,loff_t); ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*); ssize_t(*aio_write)(structkiocb*,constchar__user*,size_t,loff_t*); int(*readdir)(structfile*,void*,filldir_t); unsignedint(*poll)(structfile*,structpoll_table_struct*); int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong); int(*mmap)(structfile*,structvm_area_struct*);一些重要的數(shù)據(jù)結(jié)構(gòu) int(*open)(structinode*,structfile*); int(*flush)(structfile*); int(*release)(structinode*,structfile*); int(*fsync)(structfile*,structdentry*,int); int(*aio_fsync)(structkiocb*,int); int(*fasync)(int,structfile*,int); int(*lock)(structfile*,int,structfile_lock*); ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_t*); ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*); ssize_t(*sendfile)(structfile*,loff_t*,size_t,read_actor_t,void*); 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(*dir_notify)(structfile*,unsignedlong);};一些重要的數(shù)據(jù)結(jié)構(gòu)structmodule*owner第一個(gè)file_operations成員不是一個(gè)操作,是一個(gè)指向擁有這個(gè)結(jié)構(gòu)的模塊的指針。這個(gè)成員用來在它的操作還在被使用時(shí)阻止模塊被卸載。幾乎所有時(shí)間中,它被初始化為THIS_MODULE,一個(gè)在<linux/module.h>中定義的宏。loff_t(*llseek)(structfile*,loff_t,int);llseek方法用于改變文件中的當(dāng)前讀/寫位置,并且將新位置作為(正的)返回值。loff_t參數(shù)是一個(gè)“l(fā)ongoffset”,并且就算在32位平臺上也至少有64位寬。出錯時(shí)返回一個(gè)負(fù)的返回值。如果這個(gè)函數(shù)指針是NULL,seek調(diào)用會以無法預(yù)測的方式修改file結(jié)構(gòu)中的位置計(jì)數(shù)器(在"file結(jié)構(gòu)"一節(jié)中描述)。一些重要的數(shù)據(jù)結(jié)構(gòu)ssize_t(*read)(structfile*,char__user*,size_t,loff_t*);用來從設(shè)備中獲取數(shù)據(jù)。非負(fù)返回值代表成功讀取的字節(jié)數(shù)(返回值是一個(gè)“signedsize”類型,常常是目標(biāo)平臺本地的整數(shù)類型)。該函數(shù)指針為NULL時(shí)將導(dǎo)致調(diào)用失敗并返回-EINVAL(“Invalidargument”)ssize_t(*aio_read)(structkiocb*,char__user*,size_t,loff_t);初始化一個(gè)異步讀--在函數(shù)返回前可能不會結(jié)束的讀操作。如果這個(gè)方法是NULL,所有的讀操作會由read代替進(jìn)行(同步地)。一些重要的數(shù)據(jù)結(jié)構(gòu)ssize_t(*write)(structfile*,constchar__user*,size_t,loff_t*);發(fā)送數(shù)據(jù)給設(shè)備。非負(fù)返回值代表成功發(fā)送的字節(jié)數(shù).ssize_t(*aio_write)(structkiocb*,constchar__user*,size_t,loff_t*);設(shè)備上的一個(gè)異步寫入方法。int(*readdir)(structfile*,void*,filldir_t);對于設(shè)備文件,這個(gè)成員應(yīng)當(dāng)為NULL;它用來讀取目錄,僅對文件系統(tǒng)有用一些重要的數(shù)據(jù)結(jié)構(gòu)unsignedint(*poll)(structfile*,structpoll_table_struct*);poll方法是poll,epoll和select3個(gè)系統(tǒng)調(diào)用的后端實(shí)現(xiàn),用來查詢對一個(gè)或多個(gè)文件描述符的讀或?qū)懯欠駮蛔枞?。poll應(yīng)當(dāng)返回一個(gè)位掩碼,用于指示非阻塞的讀或?qū)懯欠窨赡?并且也會向內(nèi)核提供將調(diào)用進(jìn)程置于睡眠狀態(tài)直到I/O變?yōu)榭赡軙r(shí)的信息。如果一個(gè)驅(qū)動的poll方法為NULL,則設(shè)備會被認(rèn)為可讀可寫,且不會被阻塞。int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);ioctl方法提供了操作設(shè)備的非讀寫方法(如格式化軟盤)。另外,內(nèi)核還能識別一些ioctl命令而不必調(diào)用fops表的ioctl。如果設(shè)備不提供ioctl方法,對于內(nèi)核未預(yù)先定義的請求,ioctl系統(tǒng)調(diào)用將返回錯誤(-ENOTTY,即設(shè)備無這樣的ioctl)一些重要的數(shù)據(jù)結(jié)構(gòu)int(*mmap)(structfile*,structvm_area_struct*);mmap用來請求將設(shè)備內(nèi)存映射到進(jìn)程的地址空間。如果這個(gè)方法是NULL,mmap系統(tǒng)調(diào)用返回-ENODEV。int(*open)(structinode*,structfile*);通常是對設(shè)備文件進(jìn)行的第一個(gè)操作,但并不要求驅(qū)動一定要聲明一個(gè)對應(yīng)的方法。如果這個(gè)項(xiàng)是NULL,設(shè)備的打開永遠(yuǎn)成功,但系統(tǒng)不會通知驅(qū)動程序int(*release)(structinode*,structfile*);在file結(jié)構(gòu)被釋放時(shí)調(diào)用這個(gè)操作。如同open,release可以為NULL一些重要的數(shù)據(jù)結(jié)構(gòu)int(*fsync)(structfile*,structdentry*,int);這個(gè)方法是fsync系統(tǒng)調(diào)用的后端實(shí)現(xiàn),用戶調(diào)用它來刷新任何待處理的數(shù)據(jù)。如果為NULL,fsync系統(tǒng)調(diào)用返回-EINVAL。int(*aio_fsync)(structkiocb*,int);這是fsync方法的異步版本int(*fasync)(int,structfile*,int);這個(gè)操作用來通知設(shè)備其FASYNC標(biāo)志發(fā)生了改變。異步通知是一個(gè)高級的主題,在第6章中描述。如果驅(qū)動不支持異步通知,這個(gè)成員可以是NULL。一些重要的數(shù)據(jù)結(jié)構(gòu)int(*lock)(structfile*,int,structfile_lock*);lock方法用來實(shí)現(xiàn)文件加鎖;加鎖對常規(guī)文件是必不可少的特性,但是設(shè)備驅(qū)動幾乎從不實(shí)現(xiàn)它。ssize_t(*readv)(structfile*,conststructiovec*,unsignedlong,loff_t*);ssize_t(*writev)(structfile*,conststructiovec*,unsignedlong,loff_t*);這些方法用來實(shí)現(xiàn)分散/匯聚型的讀寫操作。應(yīng)用程序有時(shí)需要進(jìn)行涉及多個(gè)內(nèi)存區(qū)的單個(gè)讀或?qū)懖僮?,這些系統(tǒng)調(diào)用允許它們這樣做而不必額外增加數(shù)據(jù)拷貝操作。如果這些函數(shù)指針為NULL,就會調(diào)用read和write方法(可能多于一次)。一些重要的數(shù)據(jù)結(jié)構(gòu)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è)。例如,web服務(wù)器可以利用這個(gè)方法將某一個(gè)文件的內(nèi)容發(fā)送到網(wǎng)絡(luò)連接。設(shè)備驅(qū)動常常使sendfile為NULL。ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);sendpage是sendfile的另一半;它由內(nèi)核調(diào)用來發(fā)送數(shù)據(jù)到對應(yīng)的文件,一次一頁。設(shè)備驅(qū)動實(shí)際上不實(shí)現(xiàn)sendpage。一些重要的數(shù)據(jù)結(jié)構(gòu)unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);這個(gè)方法的目的是在進(jìn)程的地址空間找一個(gè)合適的位置,以便將底層設(shè)備中的內(nèi)存段映射到該位置。該任務(wù)通常由內(nèi)存管理代碼完成,但該方法的存在可允許驅(qū)動程序強(qiáng)制滿足特定設(shè)備需要的任何對齊需求。大部分驅(qū)動可以置這個(gè)方法為NULL。int(*check_flags)(int)這個(gè)方法允許模塊檢查傳遞給fnctl(F_SETFL...)調(diào)用的標(biāo)志一些重要的數(shù)據(jù)結(jié)構(gòu)int(*dir_notify)(structfile*,unsignedlong);這個(gè)方法在應(yīng)用程序使用fcntl來請求目錄改變通知時(shí)調(diào)用。只對文件系統(tǒng)有用;驅(qū)動不需要實(shí)現(xiàn)dir_notify。一些重要的數(shù)據(jù)結(jié)構(gòu)scull設(shè)備驅(qū)動只實(shí)現(xiàn)最重要的設(shè)備方法。它的file_operations結(jié)構(gòu)是如下初始化的:structfile_operationsscull_fops={ .owner=THIS_MODULE, .llseek=scull_llseek, .read=scull_read, .write=scull_write, .ioctl=scull_ioctl, .open=scull_open, .release=scull_release,};

一些重要的數(shù)據(jù)結(jié)構(gòu)structfile,definedin<linux/fs.h>文件結(jié)構(gòu)代表一個(gè)打開的文件,由內(nèi)核在open時(shí)創(chuàng)建,并傳遞給在文件上操作的任何函數(shù),直到最后關(guān)閉在文件的所有實(shí)例都關(guān)閉后,內(nèi)核釋放這個(gè)數(shù)據(jù)結(jié)構(gòu)在內(nèi)核源碼中,指向structfile的指針常常稱為file或者filp(“filepointer”)。本書用filp表示這個(gè)指針,以避免和結(jié)構(gòu)自身混淆。因此,file指的是結(jié)構(gòu),而filp是結(jié)構(gòu)指針一些重要的數(shù)據(jù)結(jié)構(gòu)structfile{ mode_tf_mode; loff_tf_pos; unsignedintf_flags; structfile_operations*f_op; void*private_data; structdentry*f_dentry;};一些重要的數(shù)據(jù)結(jié)構(gòu)mode_tf_mode;文件模式。它通過FMODE_READ和FMODE_WRITE位來標(biāo)示文件是否可讀或可寫(或兩者都是)loff_tf_pos;當(dāng)前讀寫位置。loff_t在所有平臺下都是64位(在gcc術(shù)語里是longlong)。驅(qū)動如果需要知道文件中的當(dāng)前位置,可以讀這個(gè)值,但不應(yīng)該修改它。read/write會使用它們接收到的最后那個(gè)指針參數(shù)來更新這一位置,而不是直接對filp->f_pos進(jìn)行操作。這一規(guī)則的一個(gè)例外是llseek,它的目的就是修改文件位置一些重要的數(shù)據(jù)結(jié)構(gòu)unsignedintf_flags;這些是文件標(biāo)志,例如O_RDONLY,O_NONBLOCK,和O_SYNC。為了檢查用戶請求的是否非阻塞操作,驅(qū)動程序應(yīng)當(dāng)檢查O_NONBLOCK標(biāo)志。而其他標(biāo)志很少用到。注意,檢查讀/寫權(quán)限應(yīng)該查看f_mode,而非f_flags。所有的標(biāo)志在頭文件<linux/fcntl.h>中定義。一些重要的數(shù)據(jù)結(jié)構(gòu)structfile_operations*f_op;與文件關(guān)聯(lián)的操作。內(nèi)核在執(zhí)行open操作時(shí)對指針賦值,以后需要處理這些操作時(shí)就讀取這個(gè)指針。filp->f_op中的值決不會為方便引用而保存起來。這意味著你可在需要的時(shí)候修改文件關(guān)聯(lián)的操作,在返回調(diào)用者之后新方法就會生效。例如,對應(yīng)于主設(shè)備號1(/dev/null,/dev/zero,等等)的open代碼根據(jù)要打開的次設(shè)備號替代filp->f_op中的操作。這種技巧允許相同主設(shè)備號下的設(shè)備實(shí)現(xiàn)多種操作行為,而不會增加系統(tǒng)調(diào)用的負(fù)擔(dān)。這種替換文件操作的能力在面向?qū)ο缶幊讨蟹Q為"方法重載"。一些重要的數(shù)據(jù)結(jié)構(gòu)void*private_data;open系統(tǒng)調(diào)用在調(diào)用驅(qū)動程序的open方法之前將這個(gè)指針設(shè)置為NULL。驅(qū)動程序可以將這個(gè)字段用于任何目的或者忽略它。驅(qū)動程序可以用這個(gè)成員來指向已分配的數(shù)據(jù),但是一定要在內(nèi)核銷毀file結(jié)構(gòu)之前,在release方法中釋放內(nèi)存。private_data是一個(gè)有用的資源,可用于在系統(tǒng)調(diào)用間保存狀態(tài)信息,本書大部分例子模塊都使用它。structdentry*f_dentry;文件對應(yīng)的目錄項(xiàng)(dentry)結(jié)構(gòu)。除了用filp->f_dentry->d_inode的方式來訪問索引節(jié)點(diǎn)inode結(jié)構(gòu)之外,設(shè)備驅(qū)動開發(fā)者一般無需要關(guān)心dentry結(jié)構(gòu)一些重要的數(shù)據(jù)結(jié)構(gòu)structinode,<linux/fs.h>內(nèi)核用inode結(jié)構(gòu)在內(nèi)部表示文件,因此它和file結(jié)構(gòu)不同,后者表示打開的文件。對于單個(gè)文件,可能會有許多個(gè)表示打開的文件描述符file結(jié)構(gòu),但它們都指向單個(gè)inode結(jié)構(gòu)。inode結(jié)構(gòu)包含了大量有關(guān)文件的信息。作為一個(gè)通用的規(guī)則,這個(gè)結(jié)構(gòu)只有2個(gè)成員對于編寫驅(qū)動代碼有用:structinode{ dev_ti_rdev; structcdev*i_cdev; …};一些重要的數(shù)據(jù)結(jié)構(gòu)dev_ti_rdev;對于表示設(shè)備文件的節(jié)點(diǎn)inode結(jié)構(gòu),這個(gè)成員包含了實(shí)際的設(shè)備編號structcdev*i_cdev;structcdev是內(nèi)核的內(nèi)部結(jié)構(gòu),代表字符設(shè)備;當(dāng)inode指向一個(gè)字符設(shè)備文件時(shí),這個(gè)成員包含一個(gè)指向structcdev結(jié)構(gòu)的指針內(nèi)核開發(fā)者已經(jīng)增加了2個(gè)宏,可用來從一個(gè)inode中獲取主次編號:unsignedintiminor(structinode*inode);unsignedintimajor(structinode*inode);1324第3章字符設(shè)備驅(qū)動程序scull的設(shè)計(jì)主設(shè)備號與次設(shè)備號一些重要的數(shù)據(jù)結(jié)構(gòu)字符設(shè)備的注冊open和releasescull的內(nèi)存使用read和write567字符設(shè)備的注冊內(nèi)核字符設(shè)備結(jié)構(gòu)與接口(在<linux/cdev.h>中)structcdev{ structkobjectkobj; structmodule*owner; conststructfile_operations*ops; structlist_headlist; dev_tdev; unsignedintcount;};structcdev*cdev_alloc(void);voidcdev_init(structcdev*,conststructfile_operations*);intcdev_add(structcdev*,dev_t,unsigned);voidcdev_del(structcdev*);字符設(shè)備的注冊分配structcdev結(jié)構(gòu)(動態(tài)):structcdev*my_cdev=cdev_alloc();my_cdev->ops=&my_fops;初始化structcdev結(jié)構(gòu)voidcdev_init(structcdev*cdev,structfile_operations*fops);將structcdev結(jié)構(gòu)的信息告訴內(nèi)核intcdev_add(structcdev*dev,dev_tnum,unsignedintcount);num:該設(shè)備對應(yīng)的第一個(gè)設(shè)備編號count:與該設(shè)備關(guān)聯(lián)的設(shè)備編號的數(shù)量字符設(shè)備的注冊cdev_add使用注意事項(xiàng):這個(gè)調(diào)用可能失敗。如果它返回一個(gè)負(fù)的錯誤碼,則設(shè)備并沒有增加到系統(tǒng)中,故需要檢測它的返回值cdev_add一返回,設(shè)備就“活”了,它的操作就會被內(nèi)核調(diào)用。因此,如果你的驅(qū)動程序沒有完全準(zhǔn)備好處理設(shè)備上的操作,你不應(yīng)當(dāng)調(diào)用cdev_add.要從系統(tǒng)中去除一個(gè)字符設(shè)備時(shí),調(diào)用:voidcdev_del(structcdev*dev);字符設(shè)備的注冊Scull設(shè)備注冊先定義自己的設(shè)備結(jié)構(gòu)scull_dev,并包含內(nèi)核字符設(shè)備結(jié)構(gòu)cdevstructscull_dev{structscull_qset*data;/*Pointertofirstquantumset*/intquantum;/*thecurrentquantumsize*/intqset;/*thecurrentarraysize*/unsignedlongsize;/*amountofdatastoredhere*/unsignedintaccess_key;/*usedbysculluidandscullpriv*/structsemaphoresem;/*mutualexclusionsemaphore*/

structcdevcdev;/*Chardevicestructure*/};字符設(shè)備的注冊初始化structcdevstaticvoidscull_setup_cdev(structscull_dev*dev,intindex){interr,devno=MKDEV(scull_major,scull_minor+index);cdev_init(&dev->cdev,&scull_fops);dev->cdev.owner=THIS_MODULE;dev->cdev.ops=&scull_fops;err=cdev_add(&dev->cdev,devno,1);/*Failgracefullyifneedbe*/if(err)printk(KERN_NOTICE"Error%daddingscull%d",err,index);}字符設(shè)備的注冊intscull_init_module(void){ intresult,i; dev_tdev=0; if(scull_major){ dev=MKDEV(scull_major,scull_minor); result=register_chrdev_region(dev,scull_nr_devs,"scull"); }else{ result=alloc_chrdev_region(&dev,scull_minor,scull_nr_devs,"scull"); scull_major=MAJOR(dev); } if(result<0){ printk(KERN_WARNING"scull:can'tgetmajor%d\n",scull_major); returnresult; }字符設(shè)備的注冊scull_devices=kmalloc(scull_nr_devs*sizeof(structscull_dev),GFP_KERNEL);if(!scull_devibces){ result=-ENOMEM; gotofail; } memset(scull_devices,0,scull_nr_devs*sizeof(structscull_dev));

for(i=0;i<scull_nr_devs;i++){scull_devices[i].quantum=scull_quantum;scull_devices[i].qset=scull_qset;init_MUTEX(&scull_devices[i].sem);scull_setup_cdev(&scull_devices[i],i);}structscull_dev*scull_devices;#defineSCULL_NR_DEVS4intscull_nr_devs=SCULL_NR_DEVSstructscull_dev{structscull_qset*data;intquantum;intqset;unsignedlongsize;unsignedintaccess_key;structsemaphoresem;structcdevcdev;};字符設(shè)備的注冊return0;fail: scull_cleanup_module();returnresult;}module_init(scull_init_module);module_exit(scull_cleanup_module);字符設(shè)備的注冊voidscull_cleanup_module(void){ inti;dev_tdevno=MKDEV(scull_major,scull_minor);if(scull_devices){ for(i=0;i<scull_nr_devs;i++){ scull_trim(scull_devices+i); cdev_del(&scull_devices[i].cdev); } kfree(scull_devices); }unregister_chrdev_region(devno,scull_nr_devs);}字符設(shè)備的注冊注冊一個(gè)字符設(shè)備的早期(2.6前)方法intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations*fops);major:主設(shè)備號,可以對應(yīng)256個(gè)次設(shè)備號,主次設(shè)備號均不能大于255name:驅(qū)動程序名稱fops:默認(rèn)的操作結(jié)構(gòu)該調(diào)用將為主設(shè)備號注冊0~255作為次號,并為設(shè)備建立一個(gè)cdev結(jié)構(gòu)intunregister_chrdev(unsignedintmajor,constchar*name);

1324第3章字符設(shè)備驅(qū)動程序scull的設(shè)計(jì)主設(shè)備號與次設(shè)備號一些重要的數(shù)據(jù)結(jié)構(gòu)字符設(shè)備的注冊open和releasescull的內(nèi)存使用read和write567open和releaseopen方法進(jìn)行設(shè)備的初始化,在大部分驅(qū)動程序中,完成如下工作檢查設(shè)備特定的錯誤初始化設(shè)備(若是首次打開)更新f_op指針(若有必要)分配并填寫filp->private_data里的數(shù)據(jù)結(jié)構(gòu)open原型int(*open)(structinode*inode,structfile*filp);inode中包含有cdev結(jié)構(gòu),但是需要的是scull_devstructinode{dev_ti_rdev;structcdev*i_cdev;…};open和release利用container_of(pointer,container_type,container_field);可由cdev結(jié)構(gòu)得到包含它的scull_dev結(jié)構(gòu)

structscull_dev*dev; dev=container_of(inode->i_cdev,structscull_dev,cdev);得到scull_dev后,將其保存在file結(jié)構(gòu)中,方便以后訪問filp->private_data=dev;structscull_dev{structscull_qset*data;intquantum;intqset;unsignedlongsize;unsignedintaccess_key;structsemaphoresem;

structcdevcdev;};open和releasescull的open如下intscull_open(structinode*inode,structfile*filp){structscull_dev*dev;dev=container_of(inode->i_cdev,structscull_dev,cdev);filp->private_data=dev;

if((filp->f_flags&O_ACCMODE)==O_WRONLY){scull_trim(dev);/*刪除舊量子及量子集(若有),并初始化scull_dev}return0;}open和releaserelease方法釋放由open分配的,保存在filp->private_data中的內(nèi)容關(guān)閉設(shè)備(在最后一次調(diào)用時(shí))scull的release如下:intscull_release(structinode*inode,structfile*filp){return0;}1324第3章字符設(shè)備驅(qū)動程序scull的設(shè)計(jì)主設(shè)備號與次設(shè)備號一些重要的數(shù)據(jù)結(jié)構(gòu)字符設(shè)備的注冊open和releasescull的內(nèi)存使用read和write567structscull_dev{structscull_qset*data;intquantum,qset;unsignedlongsize;…structcdevcdev;};structscull_qset{void**data;structscull_qset*next;};對應(yīng)一內(nèi)存區(qū),量子數(shù)組,量子集SCULL_QUANTUM=4000BSCULL_QSET=1000scull的內(nèi)存使用intscull_trim(structscull_dev*dev){structscull_qset*next,*dptr;intqset=dev->qset;inti;for(dptr=dev->data;dptr;dptr=next){if(dptr->data){for(i=0;i<qset;i++)kfree(dptr->data[i]);kfree(dptr->data);dptr->data=NULL;}next=dptr->next;kfree(dptr);}

dev->size=0;dev->quantum=scull_quantum;dev->qset=scull_qset;dev->data=NULL;return0;}該函數(shù)刪除舊量子及量子集(若有),并初始化設(shè)備結(jié)構(gòu)structscull_dev{structscull_qset*data;intquantum;intqset;unsignedlongsize;…};1324第3章字符設(shè)備驅(qū)動程序scull的設(shè)計(jì)主設(shè)備號與次設(shè)備號一些重要的數(shù)據(jù)結(jié)構(gòu)字符設(shè)備的注冊open和releasescull的內(nèi)存使用read和write567read和writeread從設(shè)備讀取數(shù)據(jù)到用戶空間,write從用戶空間寫數(shù)據(jù)到設(shè)備,原型如下:ssize_tread(structfile*filp,char__user*buff,size_tcount,loff_t*offp);ssize_twrite(structfile*filp,constchar__user*buff,size_tcount,loff_t*offp);filp:文件指針count:請求傳輸?shù)淖止?jié)數(shù)offp:指明用戶在文件中進(jìn)行存取操作的位置buff:指向用戶空間緩沖區(qū)read和writebuff是用戶空間指針,內(nèi)核代碼不能直接引用read和write內(nèi)核空間與用戶空間進(jìn)行數(shù)據(jù)交換的函數(shù)是:unsignedlongcopy_to_user(void__user*to,constvoid*from,unsignedlongcount);unsignedlongcopy_from_user(void*to,constvoid__user*from,unsignedlongcount);用一些特殊的與架構(gòu)相關(guān)的方法來實(shí)現(xiàn),確保在內(nèi)核和用戶空間安全、正確地交換數(shù)據(jù)拷貝前對指針進(jìn)行檢查,若指針無效,則不拷貝;另外,若在拷貝過程中遇到無效地址,則僅會復(fù)制部分?jǐn)?shù)據(jù),返回值為還需要拷貝的內(nèi)存數(shù)值。read和writessize_tscull_read(structfile*filp,char__user*buf,size_tcount,loff_t*f_pos){structscull_dev*dev=filp->private_data;structscull_qset*dptr;intquantum=dev->quantum,qset=dev->qset;intitemsize=quantum*qset;intitem,s_pos,q_pos,rest;ssize_tretval=0;if(down_interruptible(&dev->sem))return-ERESTARTSYS;if(*f_pos>=dev->size)gotoout;if(*f_pos+count>dev->size)count=dev->size-*f_pos;…item=(long)*f_pos/itemsize;rest=(long)*f_pos%itemsize;s_pos=rest/quantum;q_pos=rest%quantum;dptr=scull_follow(dev,item);if(dptr==NULL||!dptr->data||!dptr->data[s_pos])gotoout;if(count>quantum-q_pos)count=quantum-q_pos;if(copy_to_user(buf,dptr->data[s_pos]+q_pos,count)){retval=-EFAULT;gotoout;}*f_pos+=count;retval=count;out:up(&dev->sem);returnretval;}read和writessize_tscull_write(structfile*filp,constchar__user*buf,size_tcount,loff_t*f_pos){structscull_dev*dev=filp->private_data;structscull_qset*dptr;intquantum=dev->quantum,qset=dev->qset;intitemsize=quantum*qset;intitem,s_pos,q_pos,rest;ssize_tretval=-ENOMEM;

if(down_interruptible(&dev->sem))

return-ERESTARTSYS;item=(long)*f_pos/itemsize;rest=(long)*f_pos%itemsize;

s_pos=rest/quantum;q

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論