版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、字符設(shè)備驅(qū)動第第5章章 字符設(shè)備驅(qū)動字符設(shè)備驅(qū)動計算機(jī)科學(xué)技術(shù)系李偉民李偉民2012年年8月月字符設(shè)備驅(qū)動提綱提綱w Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu) - Linux設(shè)備號管理設(shè)備號管理 - 一些重要的數(shù)據(jù)結(jié)構(gòu)一些重要的數(shù)據(jù)結(jié)構(gòu)w globalmem設(shè)備驅(qū)動設(shè)備驅(qū)動 - globalmem驅(qū)動編寫方法和分析驅(qū)動編寫方法和分析 - globalmem設(shè)備驅(qū)動在用戶空間的驗證設(shè)備驅(qū)動在用戶空間的驗證 字符設(shè)備驅(qū)動引言引言 Linux提供提供3種基本的設(shè)備驅(qū)動接口種基本的設(shè)備驅(qū)動接口,包括字符包括字符,塊設(shè)備和網(wǎng)塊設(shè)備和網(wǎng)絡(luò)設(shè)備驅(qū)動絡(luò)設(shè)備驅(qū)動,其中字符設(shè)備是應(yīng)用最廣其中字符設(shè)備是應(yīng)用最廣,
2、和用戶應(yīng)用程序聯(lián)和用戶應(yīng)用程序聯(lián)系最直接的驅(qū)動。系最直接的驅(qū)動。 比起塊設(shè)備或者網(wǎng)絡(luò)驅(qū)動程序更加易于理解。比起塊設(shè)備或者網(wǎng)絡(luò)驅(qū)動程序更加易于理解。 字符設(shè)備驅(qū)動字符設(shè)備開發(fā)的基本步驟字符設(shè)備開發(fā)的基本步驟w 字符設(shè)備的特點(diǎn)字符設(shè)備的特點(diǎn)像字節(jié)流一樣來存取的設(shè)備像字節(jié)流一樣來存取的設(shè)備( 如同文件如同文件 )通過通過/dev下的文件系統(tǒng)結(jié)點(diǎn)來訪問下的文件系統(tǒng)結(jié)點(diǎn)來訪問通常至少需要實現(xiàn)通常至少需要實現(xiàn) open, close, read, 和和 write 等系統(tǒng)調(diào)用等系統(tǒng)調(diào)用只能順序訪問的數(shù)據(jù)通道,不能前后移動訪問指針。特例只能順序訪問的數(shù)據(jù)通道,不能前后移動訪問指針。特例:比如比如frameb
3、uffer設(shè)備就是這樣的設(shè)備,應(yīng)用程序可以使用設(shè)備就是這樣的設(shè)備,應(yīng)用程序可以使用mmap或或lseek訪問圖像的各個區(qū)域。訪問圖像的各個區(qū)域。字符設(shè)備驅(qū)動字符設(shè)備開發(fā)的基本步驟字符設(shè)備開發(fā)的基本步驟w 確定主設(shè)備號和次設(shè)備號確定主設(shè)備號和次設(shè)備號w 實現(xiàn)字符驅(qū)動程序?qū)崿F(xiàn)字符驅(qū)動程序?qū)崿F(xiàn)實現(xiàn)file_operations結(jié)構(gòu)體結(jié)構(gòu)體實現(xiàn)初始化函數(shù),注冊字符設(shè)備實現(xiàn)初始化函數(shù),注冊字符設(shè)備實現(xiàn)銷毀函數(shù),釋放字符設(shè)備實現(xiàn)銷毀函數(shù),釋放字符設(shè)備w 創(chuàng)建設(shè)備文件節(jié)點(diǎn)創(chuàng)建設(shè)備文件節(jié)點(diǎn)字符設(shè)備驅(qū)動主設(shè)備號與次設(shè)備號主設(shè)備號與次設(shè)備號w 主設(shè)備號與次設(shè)備號主設(shè)備號與次設(shè)備號主設(shè)備號:主設(shè)備號:主設(shè)備號是內(nèi)核
4、識別一個設(shè)備的標(biāo)識。整數(shù)主設(shè)備號是內(nèi)核識別一個設(shè)備的標(biāo)識。整數(shù)(占占12bits),范圍從,范圍從0到到4095,通常使用,通常使用1到到255??梢酝ㄟ^??梢酝ㄟ^/proc/devices文件來查看驅(qū)動系統(tǒng)設(shè)備文件來查看驅(qū)動系統(tǒng)設(shè)備的主設(shè)備號。的主設(shè)備號。次設(shè)備號:次設(shè)備號:次設(shè)備號由內(nèi)核使用,用于正確確定設(shè)備文件所指的設(shè)備,驅(qū)動次設(shè)備號由內(nèi)核使用,用于正確確定設(shè)備文件所指的設(shè)備,驅(qū)動程序遍歷設(shè)備時,每發(fā)現(xiàn)一個它能驅(qū)動的設(shè)備,就創(chuàng)建一個設(shè)備對象,并為程序遍歷設(shè)備時,每發(fā)現(xiàn)一個它能驅(qū)動的設(shè)備,就創(chuàng)建一個設(shè)備對象,并為其分配一個次設(shè)備號以區(qū)分不同的設(shè)備。這樣當(dāng)應(yīng)用程序訪問設(shè)備節(jié)點(diǎn)時驅(qū)其分配一個次
5、設(shè)備號以區(qū)分不同的設(shè)備。這樣當(dāng)應(yīng)用程序訪問設(shè)備節(jié)點(diǎn)時驅(qū)動程序就可以根據(jù)次設(shè)備號知道它所訪問的設(shè)備了。整數(shù)動程序就可以根據(jù)次設(shè)備號知道它所訪問的設(shè)備了。整數(shù)(占占20bits),范圍,范圍從從0到到1048575,一般使用,一般使用0到到255。字符設(shè)備驅(qū)動主設(shè)備號與次設(shè)備號主設(shè)備號與次設(shè)備號ls -l /devcrw-r- 1 root root 1, 1 Jan 1 00:00 memcrw-r- 1 root root 1, 2 Jan 1 00:00 kmemcrw-rw-rw- 1 root root 1, 3 Jan 1 00:00 nullcrw-r- 1 root root 1,
6、 4 Jan 1 00:00 portcrw-rw-rw- 1 root root 1, 5 Jan 1 00:00 zerocrw-rw-rw- 1 root root 1, 7 Jan 1 00:00 fullcrw-r-r- 1 root root 1, 8 Jan 1 00:00 randomcrw-r-r- 1 root root 1, 9 Jan 1 00:00 urandomcrw-rw-rw- 1 root root 5, 0 Jan 1 00:00 ttycrw- 1 root root 5, 1 Jan 1 00:00 consolecrw-rw-rw- 1 root ro
7、ot 5, 2 Jan 1 00:00 ptmxdrwxr-xr-x 1 root root 0 Jan 1 00:00 ptydrwxr-xr-x 2 root root 0 Jan 1 00:00 ptsdrwxr-xr-x 1 root root 0 Jan 1 00:00 rddrwxr-xr-x 1 root root 0 Jan 1 00:00 mtddrwxr-xr-x 1 root root 0 Jan 1 00:00 mtdblockcrw- 1 root root 4, 64 Jan 1 00:15 ttyS0crw- 1 root root 4, 65 Jan 1 00:
8、00 ttyS1crw- 1 root root 4, 66 Jan 1 00:00 ttyS2crw- 1 root root 4, 67 Jan 1 00:00 ttyS3crw- 1 root root 4, 68 Jan 1 00:00 ttyS4drwxr-xr-x 1 root root 0 Jan 1 00:00 miscc:字符設(shè)備b:塊設(shè)備主設(shè)備號次設(shè)備號字符設(shè)備驅(qū)動設(shè)備編號的內(nèi)部表達(dá)設(shè)備編號的內(nèi)部表達(dá)dev_t類型類型(32位位):用來保存設(shè)備編號用來保存設(shè)備編號(包括主設(shè)備號包括主設(shè)備號(12位位)和次設(shè)備和次設(shè)備號號(20位位) 。從從dev_t獲得主設(shè)備號和次設(shè)備號獲
9、得主設(shè)備號和次設(shè)備號 :MAJOR(dev_t); MINOR(dev_t) 。將主設(shè)備號和次設(shè)備號轉(zhuǎn)換成將主設(shè)備號和次設(shè)備號轉(zhuǎn)換成dev_t類型類型 :MKDEV(int major,int minor) 字符設(shè)備驅(qū)動主設(shè)備號與次設(shè)備號主設(shè)備號與次設(shè)備號w 分配主設(shè)備號分配主設(shè)備號手工分配:手工分配:找一個內(nèi)核沒有使用過的主設(shè)備號來使用找一個內(nèi)核沒有使用過的主設(shè)備號來使用動態(tài)分配:動態(tài)分配:我們通常不知道設(shè)備將要使用哪些主設(shè)備號我們通常不知道設(shè)備將要使用哪些主設(shè)備號#include int register_chrdev_region( dev_t first, unsigned int c
10、ount, char *name );要分配的設(shè)備編要分配的設(shè)備編號范圍的起始值,號范圍的起始值,次設(shè)備號經(jīng)常為次設(shè)備號經(jīng)常為0所請求的連續(xù)設(shè)所請求的連續(xù)設(shè)備編號的個數(shù)備編號的個數(shù)和該編號范圍關(guān)聯(lián)的和該編號范圍關(guān)聯(lián)的設(shè)備名稱設(shè)備名稱,它將出現(xiàn)在它將出現(xiàn)在/proc/devices和和sysfs中中#include int alloc_chrdev_resion(dev_t *dev,unsigned int firstminor, unsigned int count,char *name);輸出的設(shè)備號要使用的被請求的第一個次設(shè)備號字符設(shè)備驅(qū)動主設(shè)備號與次設(shè)備號主設(shè)備號與次設(shè)備號w 釋放設(shè)備
11、號釋放設(shè)備號void unregister_chrdev_region(dev_t first, unsigned int count);通常在模塊的清通常在模塊的清除函數(shù)中調(diào)用。除函數(shù)中調(diào)用。字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w cdev結(jié)構(gòu)體結(jié)構(gòu)體Linux2.6內(nèi)核中,使用內(nèi)核中,使用cdev結(jié)構(gòu)體描述一個字符設(shè)備結(jié)構(gòu)體描述一個字符設(shè)備struct cdev struct kobject kobj; /* 內(nèi)嵌的kobject 對象 */ struct module *owner; /*所屬模塊*/ struct file_operations *ops; /*文件操
12、作結(jié)構(gòu)體*/ struct list_head list; dev_t dev; /*設(shè)備號*/ unsigned int count; ;字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w 操作操作cdev的函數(shù)的函數(shù)void cdev_init( struct cdev *, struc t file_operations *);struct cdev *cdev_alloc(void) ;int cdev_add(st ruct cdev *, dev_t, unsigned) ;void cdev_del(struct cdev *);用于初始化cdev的成員,并建立cdev和f
13、ile_operations之間的連接函數(shù)用于動態(tài)申請一個cdev 內(nèi)存分別向系統(tǒng)刪除一個cdev,完成字符設(shè)備的注銷,通常在模塊的卸載函數(shù)中調(diào)用分別向系統(tǒng)添加一個cdev,完成字符設(shè)備的注冊,通常在模塊加載函數(shù)中調(diào)用字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w file_operations結(jié)構(gòu)體結(jié)構(gòu)體字符驅(qū)動和內(nèi)核的接口,在字符驅(qū)動和內(nèi)核的接口,在include/linux/fs.h中定義,它定義了維系在設(shè)備中定義,它定義了維系在設(shè)備驅(qū)動上的操作函數(shù)。驅(qū)動上的操作函數(shù)。在進(jìn)程在進(jìn)程PCB中中,每個打開文件每個打開文件,包括設(shè)備文件包括設(shè)備文件 (內(nèi)部用一個內(nèi)部用一個 struc
14、t file 結(jié)構(gòu)來代結(jié)構(gòu)來代表表, 稍后我們會看到稍后我們會看到)與它自身的函數(shù)集合相關(guān)連與它自身的函數(shù)集合相關(guān)連, 它通過包含一個稱為它通過包含一個稱為 f_op 的指向一個的指向一個 file_operations 結(jié)構(gòu)成員指針建立關(guān)系結(jié)構(gòu)成員指針建立關(guān)系字符驅(qū)動只要實現(xiàn)一個字符驅(qū)動只要實現(xiàn)一個file_operations結(jié)構(gòu)體結(jié)構(gòu)體,并注冊到內(nèi)核中,內(nèi)核就有了并注冊到內(nèi)核中,內(nèi)核就有了操作此設(shè)備的能力操作此設(shè)備的能力用戶通過系統(tǒng)調(diào)用用戶通過系統(tǒng)調(diào)用open,read,write等在這個結(jié)構(gòu)中有相應(yīng)的方法對應(yīng)等在這個結(jié)構(gòu)中有相應(yīng)的方法對應(yīng) 字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備
15、驅(qū)動結(jié)構(gòu)w file_operations結(jié)構(gòu)體的主要成員結(jié)構(gòu)體的主要成員struct module *owner :它是一個指向擁有這個結(jié)構(gòu)的模塊的指針,它被簡它是一個指向擁有這個結(jié)構(gòu)的模塊的指針,它被簡單初始化為單初始化為 THIS_MODULE, 一個在一個在 中定義的宏中定義的宏。loff_t (*llseek) (struct file *, loff_t, int): llseek 方法用作改變文件中的當(dāng)前讀方法用作改變文件中的當(dāng)前讀/寫位置寫位置, 并且新位置作為并且新位置作為(正的正的)返回值。返回值。ssize_t (*read) (struct file *, char _
16、user *, size_t, loff_t *):用來從設(shè)備中獲用來從設(shè)備中獲取數(shù)據(jù)。取數(shù)據(jù)。ssize_t (*aio_read)(struct kiocb *, char _user *, size_t, loff_t):初始化一個異初始化一個異步讀步讀 - 可能在函數(shù)返回前不結(jié)束的讀操作可能在函數(shù)返回前不結(jié)束的讀操作. 字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w file_operations結(jié)構(gòu)體的主要成員結(jié)構(gòu)體的主要成員ssize_t (*write) (struct file *, const char _user *, size_t, loff_t *):發(fā)送數(shù)據(jù)
17、給發(fā)送數(shù)據(jù)給設(shè)備設(shè)備. 如果如果 NULL, -EINVAL,如果非負(fù),如果非負(fù), 返回值代表成功寫的字節(jié)數(shù)返回值代表成功寫的字節(jié)數(shù)。ssize_t (*aio_write)(struct kiocb *, const char _user *, size_t, loff_t *):初始初始化設(shè)備上的一個異步寫。化設(shè)備上的一個異步寫。 int (*readdir) (struct file *, void *, filldir_t):對于設(shè)備文件這個成員應(yīng)當(dāng)為對于設(shè)備文件這個成員應(yīng)當(dāng)為 NULL; 它用來讀取目錄它用來讀取目錄, 并且僅對文件系統(tǒng)有用并且僅對文件系統(tǒng)有用unsigned int
18、 (*poll) (struct file *, struct poll_table_struct *): poll 方法是方法是 3 個個系統(tǒng)調(diào)用的后端系統(tǒng)調(diào)用的后端: poll, epoll, 和和 select, 都用作查詢對一個或多個文件描述符都用作查詢對一個或多個文件描述符的讀或?qū)懯欠駮枞淖x或?qū)懯欠駮枞址O(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)wfile_operations結(jié)構(gòu)體的主要成員結(jié)構(gòu)體的主要成員 int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long): ioctl
19、 系系統(tǒng)調(diào)用提供了發(fā)出設(shè)備特定命令的方法統(tǒng)調(diào)用提供了發(fā)出設(shè)備特定命令的方法(例如格式化軟盤的一個磁道例如格式化軟盤的一個磁道, 這不是讀也不是這不是讀也不是寫寫)。int (*mmap) (struct file *, struct vm_area_struct *):mmap 用來請求將設(shè)備內(nèi)存映射用來請求將設(shè)備內(nèi)存映射到進(jìn)程的地址空間到進(jìn)程的地址空間. 如果這個方法是如果這個方法是 NULL, mmap 系統(tǒng)調(diào)用返回系統(tǒng)調(diào)用返回 ENODEV。 int (*open) (struct inode *, struct file *):盡管這常常是對設(shè)備文件進(jìn)行的第一個操作盡管這常常是對設(shè)備文
20、件進(jìn)行的第一個操作, 不要求驅(qū)動聲明一個對應(yīng)的方法不要求驅(qū)動聲明一個對應(yīng)的方法. 如果這個項是如果這個項是 NULL, 設(shè)備打開一直成功設(shè)備打開一直成功, 但是你的但是你的驅(qū)動不會得到通知驅(qū)動不會得到通知. int (*flush) (struct file *): flush 操作在進(jìn)程關(guān)閉它的設(shè)備文件描述符的拷貝時調(diào)用,操作在進(jìn)程關(guān)閉它的設(shè)備文件描述符的拷貝時調(diào)用,它應(yīng)當(dāng)執(zhí)行它應(yīng)當(dāng)執(zhí)行(并且等待并且等待)設(shè)備的任何未完成的操作設(shè)備的任何未完成的操作.如果如果 flush 為為 NULL, 內(nèi)核簡單地忽略內(nèi)核簡單地忽略用戶應(yīng)用程序的請求用戶應(yīng)用程序的請求.字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)
21、構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)wfile_operations結(jié)構(gòu)體的主要成員結(jié)構(gòu)體的主要成員int (*release) (struct inode *, struct file *):在文件結(jié)構(gòu)被釋放時用該操作在文件結(jié)構(gòu)被釋放時用該操作。int (*fsync) (struct file *, struct dentry *, int):這個方法是這個方法是 fsync 系統(tǒng)調(diào)用的后系統(tǒng)調(diào)用的后端端, 用戶調(diào)用來刷新任何掛著的數(shù)據(jù)。用戶調(diào)用來刷新任何掛著的數(shù)據(jù)。 int (*fasync) (int, struct file *, int):這個操作用來通知設(shè)備它的這個操作用來通知設(shè)備它的 FASYN
22、C 標(biāo)標(biāo)志的改變志的改變int (*lock) (struct file *, int, struct file_lock *): lock 方法用來實現(xiàn)文件加鎖方法用來實現(xiàn)文件加鎖ssize_t (*sendfile)(struct file *, loff_t *, size_t read_actor_t, void *):sendpage 是是 sendfile 的另一半的另一半; 它由內(nèi)核調(diào)用來發(fā)送數(shù)據(jù)它由內(nèi)核調(diào)用來發(fā)送數(shù)據(jù), 一次一頁一次一頁, 到對應(yīng)的文件到對應(yīng)的文件. 設(shè)設(shè)備驅(qū)動上不實現(xiàn)備驅(qū)動上不實現(xiàn) sendpage字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)wfil
23、e_operations結(jié)構(gòu)體的主要成員結(jié)構(gòu)體的主要成員int (*release) (struct inode *, struct file *):在文件結(jié)構(gòu)被釋放時用該操作在文件結(jié)構(gòu)被釋放時用該操作。int (*fsync) (struct file *, struct dentry *, int):這個方法是這個方法是 fsync 系統(tǒng)調(diào)用的后系統(tǒng)調(diào)用的后端端, 用戶調(diào)用來刷新任何掛著的數(shù)據(jù)。用戶調(diào)用來刷新任何掛著的數(shù)據(jù)。 int (*fasync) (int, struct file *, int):這個操作用來通知設(shè)備它的這個操作用來通知設(shè)備它的 FASYNC 標(biāo)標(biāo)志的改變志的改變i
24、nt (*lock) (struct file *, int, struct file_lock *): lock 方法用來實現(xiàn)文件加鎖方法用來實現(xiàn)文件加鎖ssize_t (*sendfile)(struct file *, loff_t *, size_t read_actor_t, void *):sendpage 是是 sendfile 的另一半的另一半; 它由內(nèi)核調(diào)用來發(fā)送數(shù)據(jù)它由內(nèi)核調(diào)用來發(fā)送數(shù)據(jù), 一次一頁一次一頁, 到對應(yīng)的文件到對應(yīng)的文件. 設(shè)設(shè)備驅(qū)動上不實現(xiàn)備驅(qū)動上不實現(xiàn) sendpage字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w file結(jié)構(gòu)體結(jié)構(gòu)體file結(jié)
25、構(gòu)與用戶空間程序中的結(jié)構(gòu)與用戶空間程序中的FILE沒有任何關(guān)聯(lián),沒有任何關(guān)聯(lián),F(xiàn)ILE在在C庫中定義庫中定義且不會出現(xiàn)在內(nèi)核代碼中,且不會出現(xiàn)在內(nèi)核代碼中,struct file是一個內(nèi)核結(jié)構(gòu),不會出現(xiàn)在是一個內(nèi)核結(jié)構(gòu),不會出現(xiàn)在用戶程序。用戶程序。file結(jié)構(gòu)代表一個打開的文件(不限定于設(shè)備驅(qū)動程序)。它由內(nèi)核結(jié)構(gòu)代表一個打開的文件(不限定于設(shè)備驅(qū)動程序)。它由內(nèi)核在在open時創(chuàng)建,并傳遞給在該文件上進(jìn)行操作的所有函數(shù),直到時創(chuàng)建,并傳遞給在該文件上進(jìn)行操作的所有函數(shù),直到close函數(shù)。在文件的所有實例都被關(guān)閉之后,內(nèi)核會釋放。函數(shù)。在文件的所有實例都被關(guān)閉之后,內(nèi)核會釋放。指向指向st
26、ruct file的指針通常被稱為的指針通常被稱為filp。字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w file結(jié)構(gòu)體的主要成員結(jié)構(gòu)體的主要成員mode_t f_mode:文件模式,它通過文件模式,它通過FMODE_READ和和FMODE_WRITE來標(biāo)來標(biāo)識文件是否可讀或可寫(或可讀寫)識文件是否可讀或可寫(或可讀寫)。loff_t f_pos:初始化當(dāng)前讀寫位置。驅(qū)動可以讀這個值初始化當(dāng)前讀寫位置。驅(qū)動可以讀這個值, 如果它需要知道文如果它需要知道文件中的當(dāng)前位置件中的當(dāng)前位置, 但是正常地不應(yīng)該改變它但是正常地不應(yīng)該改變它; 讀和寫會使用它們接收到的最后讀和寫會使用它們接收
27、到的最后那個指針參數(shù)來更新一個位置那個指針參數(shù)來更新一個位置, 代替直接作用于代替直接作用于 filp-f_pos 。 unsigned int f_flags:這些是文件標(biāo)志這些是文件標(biāo)志, 例如例如 O_RDONLY, O_NONBLOCK, 和和 O_SYNC。驅(qū)動應(yīng)當(dāng)檢查。驅(qū)動應(yīng)當(dāng)檢查 O_NONBLOCK 標(biāo)志來看是否是請求非阻塞操標(biāo)志來看是否是請求非阻塞操作作; 其他標(biāo)志很少使用。其他標(biāo)志很少使用。字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w file結(jié)構(gòu)體的主要成員結(jié)構(gòu)體的主要成員struct file_operations *f_op:和文件關(guān)聯(lián)的操作和文件關(guān)聯(lián)的操
28、作. 內(nèi)核安排指針作為它的內(nèi)核安排指針作為它的 open 實現(xiàn)的一部分實現(xiàn)的一部分, 接著讀取它當(dāng)它需要分派任何的操作時接著讀取它當(dāng)它需要分派任何的操作時. filp-f_op 中的中的值從不由內(nèi)核保存為后面的引用值從不由內(nèi)核保存為后面的引用; 這意味著你可改變你的文件關(guān)聯(lián)的文件操這意味著你可改變你的文件關(guān)聯(lián)的文件操作作, 在你返回調(diào)用者之后新方法會起作用在你返回調(diào)用者之后新方法會起作用。void *private_data: open 系統(tǒng)調(diào)用設(shè)置這個指針為系統(tǒng)調(diào)用設(shè)置這個指針為 NULL, 在為驅(qū)動調(diào)用在為驅(qū)動調(diào)用 open 方法之前方法之前. 你可自由使用這個成員或者忽略它你可自由使用這
29、個成員或者忽略它; 你可以使用這個成員來你可以使用這個成員來指向分配的數(shù)據(jù)指向分配的數(shù)據(jù), 但是接著你必須記住在內(nèi)核銷毀文件結(jié)構(gòu)之前但是接著你必須記住在內(nèi)核銷毀文件結(jié)構(gòu)之前, 在在 release 方法中釋放那個內(nèi)存。方法中釋放那個內(nèi)存。 struct dentry *f_dentry:關(guān)聯(lián)到文件的目錄入口關(guān)聯(lián)到文件的目錄入口( dentry )結(jié)構(gòu)。結(jié)構(gòu)。 字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w inode結(jié)構(gòu)體結(jié)構(gòu)體inode 結(jié)構(gòu)由內(nèi)核在內(nèi)部用來表示文件結(jié)構(gòu)由內(nèi)核在內(nèi)部用來表示文件. 因此因此, 它和代表打開文件描述符的文它和代表打開文件描述符的文件結(jié)構(gòu)是不同的件結(jié)構(gòu)是
30、不同的. 可能有代表單個文件的多個打開描述符的許多文件結(jié)構(gòu)可能有代表單個文件的多個打開描述符的許多文件結(jié)構(gòu), 但但是它們都指向一個單個是它們都指向一個單個 inode 結(jié)構(gòu)結(jié)構(gòu). inode 結(jié)構(gòu)包含大量關(guān)于文件的信息結(jié)構(gòu)包含大量關(guān)于文件的信息. 作作為一個通用的規(guī)則為一個通用的規(guī)則, 這個結(jié)構(gòu)只有這個結(jié)構(gòu)只有 2 個成員對于編寫驅(qū)動代碼有用個成員對于編寫驅(qū)動代碼有用:dev_t i_rdev :對表示設(shè)備文件的:對表示設(shè)備文件的inode結(jié)構(gòu)結(jié)構(gòu), 這個成員包含實際的設(shè)備編號這個成員包含實際的設(shè)備編號struct cdev *i_cdev :代表字符設(shè)備代表字符設(shè)備;當(dāng)節(jié)點(diǎn)指的是一個字符設(shè)備
31、文件時當(dāng)節(jié)點(diǎn)指的是一個字符設(shè)備文件時,這個這個成員包含一個指針成員包含一個指針, 指向這個結(jié)構(gòu)指向這個結(jié)構(gòu)。從一個從一個 inode 中獲取主次編號中獲取主次編號: unsigned int iminor(struct inode *inode); unsigned int imajor(struct inode *inode); 字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w 注冊設(shè)備,在模塊或驅(qū)動初始化時調(diào)用注冊設(shè)備,在模塊或驅(qū)動初始化時調(diào)用Linux2.4及之前及之前:Linux2.6:int register_chrdev(unsigned int major, const
32、char *name, struct file_operations *fops)void cdev_init( struct cdev *, struc t file_operations *);int cdev_add(struct cdev *, dev_t, unsigned) ;在運(yùn)行時獲取一在運(yùn)行時獲取一個獨(dú)立的個獨(dú)立的cdev結(jié)構(gòu)結(jié)構(gòu)該設(shè)備關(guān)聯(lián)的設(shè)該設(shè)備關(guān)聯(lián)的設(shè)備編號的數(shù)量備編號的數(shù)量驅(qū)動程序沒有完全準(zhǔn)備好處理設(shè)備上的驅(qū)動程序沒有完全準(zhǔn)備好處理設(shè)備上的操作,不能調(diào)用操作,不能調(diào)用cdev_add字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w 注銷設(shè)備,在模塊或驅(qū)動卸載時
33、調(diào)用注銷設(shè)備,在模塊或驅(qū)動卸載時調(diào)用Linux2.4及之前及之前:Linux2.6: int unregister_chrdev(unsigned int major, const char *name); void cdev_del (struct cdev *);字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)/ /設(shè)備驅(qū)動模塊加載函數(shù)設(shè)備驅(qū)動模塊加載函數(shù)static int _init xxx_init(void) .cdev_init(&xxx_dev.cdev, &xxx_fops); / /初始化初始化cdevxxx_dev.cdev.owner = THIS_MODULE;
34、/ /獲取字符設(shè)備號獲取字符設(shè)備號if (xxx_major) register_chrdev_region(xxx_dev_no, 1, DEV_NAME);elsealloc_chrdev_region(&xxx_dev_no, 0, 1, DEV_NAME);ret = cdev_add(&xxx_dev.cdev, xxx_dev_no, 1 ) ; / /注冊設(shè)備注冊設(shè)備.字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)/*設(shè)備驅(qū)動模塊卸載函數(shù)*/ static void _exit xxx_exit(void) unregister_chrdev_region(xxx_dev
35、_no, 1); / /釋放占用的設(shè)備號 cdev_del(&xxx_dev.cdev); / /注銷設(shè)備 . 字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w 設(shè)備的打開設(shè)備的打開open 應(yīng)當(dāng)進(jìn)行下面的工作應(yīng)當(dāng)進(jìn)行下面的工作: 1) 檢查設(shè)備特定的錯誤檢查設(shè)備特定的錯誤(例如設(shè)備沒準(zhǔn)備好例如設(shè)備沒準(zhǔn)備好, 或者類似或者類似 的硬件錯誤的硬件錯誤 2) 如果它第一次打開如果它第一次打開, 初始化設(shè)備初始化設(shè)備 3) 如果需要如果需要, 更新更新 f_op 指針,模塊計數(shù)加指針,模塊計數(shù)加1 4) 分配并填充要放進(jìn)分配并填充要放進(jìn) filp-private_data 的任何數(shù)據(jù)結(jié)構(gòu)的任
36、何數(shù)據(jù)結(jié)構(gòu)。 5)識別次設(shè)備號識別次設(shè)備號 6)如果有中斷操作,申請中斷處理程序。如果有中斷操作,申請中斷處理程序。int open(struct inode *inode, struct file *filp) ;字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w設(shè)備的關(guān)閉設(shè)備的關(guān)閉release 方法在應(yīng)用程序調(diào)用方法在應(yīng)用程序調(diào)用close()系統(tǒng)調(diào)用時被調(diào)用系統(tǒng)調(diào)用時被調(diào)用,它的角色是它的角色是 open 的反面的反面. 1) 釋放釋放 open 分配在分配在 filp-private_data 中的任何東西中的任何東西 2) 在最后的在最后的 close 關(guān)閉設(shè)備,模塊計數(shù)減關(guān)
37、閉設(shè)備,模塊計數(shù)減1 3)如果申請了中斷,則釋放中斷處理程序如果申請了中斷,則釋放中斷處理程序.int release(struct inode *inode, struct file *filp) ; 字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)wread和和writessize_t read(struct file *filp, char _user *buff, size_t count, loff_t *offp); ssize_t write(struct file *filp, const char _user *buff, size_t count, loff_t *o
38、ffp); 指向用戶空間的緩沖區(qū),這個緩沖區(qū)或者保存將寫入的數(shù)據(jù),或者是一個存放新讀入數(shù)據(jù)的空緩沖區(qū)。用戶在文件中存取操作的位置buff參數(shù)是用戶空間指針,內(nèi)核代碼不能直接引用其中的內(nèi)容。字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)w 用戶空間與內(nèi)核空間的數(shù)據(jù)拷貝用戶空間與內(nèi)核空間的數(shù)據(jù)拷貝不能簡單的用指針操作或者不能簡單的用指針操作或者memcpy來進(jìn)行數(shù)據(jù)拷貝,要用內(nèi)核函數(shù)來進(jìn)行數(shù)據(jù)拷貝,要用內(nèi)核函數(shù)如果要復(fù)制的內(nèi)存是簡單類型,如如果要復(fù)制的內(nèi)存是簡單類型,如char、int、long 等,用等,用put_user()和和get_user()unsigned long copy_
39、from_user(void *to, const void _user *from, unsigned long count) ;unsigned long copy_to_user(void _user *to, const void *from, unsigned long count );字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)l 讀設(shè)備模板讀設(shè)備模板ssize_t xxx_read(struct file *filp, char _user *buf, size_t count ,loff_t*f_pos) .copy_to_user(buf, ., . ); . l
40、寫設(shè)備模板寫設(shè)備模板 ssize_t xxx_write(struct file *fil p, const char _user *buf , size_t count ,loff_t *f_pos) . copy_from_user(., buf, . ); . 字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)wioctl函數(shù)函數(shù)ioctl函數(shù)主要完成以下兩個功能:函數(shù)主要完成以下兩個功能: 1) 為設(shè)備驅(qū)動程序執(zhí)行為設(shè)備驅(qū)動程序執(zhí)行“命令命令”提供了一個特有的入口點(diǎn)提供了一個特有的入口點(diǎn) 2) 用來設(shè)置或者讀取設(shè)備的屬性信息用來設(shè)置或者讀取設(shè)備的屬性信息 int ioctl (st
41、ruct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); 事先定義的IO控制命令代碼argarg為對應(yīng)于為對應(yīng)于cmdcmd命令的參數(shù)命令的參數(shù) 字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)wcmd參數(shù)的定義參數(shù)的定義不推薦用不推薦用0 x1,0 x2,0 x3之類的值,會導(dǎo)致不同的設(shè)備驅(qū)動擁有相同之類的值,會導(dǎo)致不同的設(shè)備驅(qū)動擁有相同的命令號。的命令號。 Linux對對ioctl()的的cmd參數(shù)有特殊的定義參數(shù)有特殊的定義 設(shè)備類型(type) 序列號(number) 方向(direction) 數(shù)據(jù)尺寸(size) 8bit 8bit 2bit 13/14bit 字符設(shè)備驅(qū)動Linux字符設(shè)備驅(qū)動結(jié)構(gòu)字符設(shè)備驅(qū)動結(jié)構(gòu)wcmd參數(shù)的定義參數(shù)的定義內(nèi)核還定義了以下四個宏來輔助生成命令:內(nèi)核還定義了以下四個宏來輔助生成命令:lIO(typeIO(type,nr)nr)用于構(gòu)造無參數(shù)的命令編號;l_IOR(type_IOR(type,nrnr,datatype)datatype)用于構(gòu)造從驅(qū)動程序中讀取數(shù)據(jù)的命令編號;l_IOW(type_IOW(type,nrnr,da
溫馨提示
- 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)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年上海房屋裝修工程調(diào)解合同
- 2024年度二手房出售合同中的附件:房產(chǎn)證復(fù)印件及交易證明
- 2024年度承包合同園林綠化工程承包合同(04版)
- 2024年度汽車銷售代理權(quán)合同
- 保潔個人年終工作總結(jié)
- 2024年庫房火災(zāi)保險合同
- 2024年奶制品銷售協(xié)議
- 2024雙方關(guān)于電商平臺運(yùn)營合作的合同
- 2024丙丁雙方廣告發(fā)布與代理合同
- 2024年建筑工程施工安全防護(hù)補(bǔ)充協(xié)議
- JTG∕T F30-2014 公路水泥混凝土路面施工技術(shù)細(xì)則
- 2024年高中語文學(xué)業(yè)水平過關(guān)測試四-名句名篇默寫積累過關(guān)訓(xùn)練(全國通用)學(xué)生版
- 糖尿病性舞蹈病
- 醫(yī)學(xué)類-教學(xué)查房異位妊娠(宮外孕)
- 眼視光技術(shù)職業(yè)生涯規(guī)劃大賽
- 《第八課 我的身體》參考課件
- 肥料創(chuàng)業(yè)計劃書
- 信息通信網(wǎng)絡(luò)運(yùn)行管理員(高級)理論考試題庫(學(xué)員用)
- 公司卷煙物流管理規(guī)范
- 報告醫(yī)療器械不良事件
- 物聯(lián)網(wǎng)安全分析報告
評論
0/150
提交評論