字符設(shè)備驅(qū)動(dòng)框架_第1頁(yè)
字符設(shè)備驅(qū)動(dòng)框架_第2頁(yè)
字符設(shè)備驅(qū)動(dòng)框架_第3頁(yè)
字符設(shè)備驅(qū)動(dòng)框架_第4頁(yè)
字符設(shè)備驅(qū)動(dòng)框架_第5頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、Linux中設(shè)備分類:按照對(duì)設(shè)備的訪問(wèn)方式可分為以下三類:1. 字符設(shè)備(char device)(1) 例如:鍵盤、鼠標(biāo)、串口、幀緩存等;(2) 通過(guò)/dev/下的設(shè)備節(jié)點(diǎn)訪問(wèn);以字節(jié)為單位訪問(wèn);(3) 一般只支持順序訪問(wèn);(特例:幀緩存framebuffer)(4) 無(wú)緩沖。2. 塊設(shè)備(block device)(1) 例如:磁盤、光驅(qū)、flash等;(2) 以固定大小為單位訪問(wèn):磁盤以扇區(qū)(512B)為單位;flash以頁(yè)為單位。(3) 支持隨機(jī)訪問(wèn);(4) 有緩沖(減少磁盤IO,提高效率)。3. 網(wǎng)絡(luò)設(shè)備(network device)(1) 無(wú)設(shè)備文件(節(jié)點(diǎn));(2) 應(yīng)用層通過(guò)s

2、ocket接口訪問(wèn)網(wǎng)絡(luò)設(shè)備(報(bào)文發(fā)送和接收的媒介)。設(shè)備驅(qū)動(dòng)在內(nèi)核中的結(jié)構(gòu):1. VFS虛擬文件系統(tǒng)作用:向應(yīng)用層提供一致的文件訪問(wèn)接口,正是由于VFS的存在,才可以將設(shè)備以文件的方式訪問(wèn)。2. 虛擬文件系統(tǒng),存在于內(nèi)存中,不在磁盤上,掉電丟失。例如:/proc、/sys、/tmp。設(shè)備號(hào):1. 作用:唯一地標(biāo)識(shí)一個(gè)設(shè)備;2. 類型:dev_t devno;即32位無(wú)符號(hào)整型;3. 組成:31 主設(shè)備號(hào)major 2019 次設(shè)備號(hào)minor 0(1) 主設(shè)備號(hào):用于區(qū)分不同類型(按功能劃分)的設(shè)備;(2) 此設(shè)備號(hào):用于區(qū)分相同類型的不同設(shè)備。注意:相同類型的設(shè)備(主設(shè)備號(hào)相同)可以使用同一

3、個(gè)驅(qū)動(dòng)。4. 構(gòu)建設(shè)備號(hào):int major = 250; int minor = 0;(1) dev_t devno = (major << 20) | minor;不建議使用;(2) 利用宏來(lái)構(gòu)建:dev_t devno = MKDEV (major, minor);注意:我們可以通過(guò)文件$(srctree)/documentation/device.txt來(lái)查看內(nèi)核對(duì)設(shè)備號(hào)的分配情況。(1) 該文本中的有對(duì)應(yīng)設(shè)備文件的設(shè)備號(hào)是已經(jīng)被申請(qǐng)過(guò)的,我們不可以重復(fù)使用(申請(qǐng));(2) 從中可以看出,我們?cè)诰帉戲?qū)動(dòng)程序時(shí)可以使用的主設(shè)備號(hào)范圍為240254,為了方便記憶,通常使用250

4、作為主設(shè)備號(hào)。字符設(shè)備驅(qū)動(dòng)框架:驅(qū)動(dòng):作用,為應(yīng)用層提供訪問(wèn)設(shè)備的接口(對(duì)設(shè)備發(fā)的各種操作)。一、 申請(qǐng)?jiān)O(shè)備號(hào)1. 構(gòu)建設(shè)備號(hào):dev_t devno = MKDEV (major, minor);2. 申請(qǐng)?jiān)O(shè)備號(hào):(1) 動(dòng)態(tài)申請(qǐng):alloc_chrdev_region;(2) 靜態(tài)申請(qǐng): register_chrdev_region。(3) 靜態(tài)申請(qǐng)?jiān)O(shè)備號(hào)的優(yōu)缺點(diǎn):優(yōu)點(diǎn):可以提前創(chuàng)建設(shè)備文件;缺點(diǎn):有可能會(huì)發(fā)成沖突,導(dǎo)致申請(qǐng)失敗。(4) register_chrdev_region函數(shù)詳解:注意: 最后一個(gè)參數(shù)是設(shè)備名稱。且在/proc/devices下會(huì)有關(guān)于當(dāng)前系統(tǒng)已經(jīng)注冊(cè)成功的設(shè)備信

5、息; 申請(qǐng)?jiān)O(shè)備號(hào)應(yīng)在加載函數(shù)中實(shí)現(xiàn);同時(shí),在卸載函數(shù)中我們也要調(diào)用unregister_chrdev_region來(lái)釋放設(shè)備號(hào)。二、 實(shí)現(xiàn)操作集合struct file_operations struct file_operations struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char _user *, size_t, loff_t *);ssize_t (*write) (struct file *,const char _user *

6、,size_t,loff_t *);unsigned int (*poll) (struct fiel *, poll_table *);int (*fasync) (int, struct file *, int);long (*unlock_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*release) (struct inode

7、 *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*lock) (struct file *, int, struct file_lock *);除owner成員外,其他成員均是對(duì)文件進(jìn)行相關(guān)操作的函數(shù)指針。1. 對(duì)設(shè)備的大多數(shù)操作函數(shù)都有參數(shù)struct file *filp;2. 在起始階段我們可以先定義一個(gè)空的操作集合:struct file_operations .owner = THIS_MODULE ;注意:(1) 可以看出宏THIS_MODULE代表結(jié)構(gòu)體struct module的起始地址;(

8、2) 我們可以通過(guò)“.<struct_member_name> = <>,”語(yǔ)法來(lái)給結(jié)構(gòu)體指定成員賦值。三、 注冊(cè)字符設(shè)備:1. 通過(guò)結(jié)構(gòu)體struct cdev將設(shè)備號(hào)devno和操作集合file_operations關(guān)聯(lián)起來(lái);2. 并將cdev結(jié)構(gòu)體加入到內(nèi)核維護(hù)的cdev鏈表中。(計(jì)算機(jī)系統(tǒng)支持很多字符設(shè)備,內(nèi)核會(huì)維護(hù)一個(gè)cdev鏈表,這樣我們就可以通過(guò)設(shè)備號(hào)找到對(duì)應(yīng)的操作集合了)3. cdev結(jié)構(gòu)體的定義如下:4. 我們通過(guò)調(diào)用內(nèi)核函數(shù)cdev_init和cdev_add來(lái)完成字符設(shè)備的注冊(cè)。注意:注冊(cè)字符設(shè)備應(yīng)在加載函數(shù)中實(shí)現(xiàn);同時(shí),在卸載函數(shù)中,我們要調(diào)用c

9、dev_del函數(shù)來(lái)注銷字符設(shè)備。且注銷字符設(shè)備應(yīng)在釋放設(shè)備號(hào)之前進(jìn)行。應(yīng)用層如何訪問(wèn)設(shè)備:1. 在Linux中一切皆文件;2. 因?yàn)閂FS(向應(yīng)用層提供一致的文件訪問(wèn)接口),應(yīng)用層也可以將設(shè)備當(dāng)做文件來(lái)訪問(wèn);3. 應(yīng)用層要想訪問(wèn)設(shè)備,首先要?jiǎng)?chuàng)建設(shè)備節(jié)點(diǎn):命令:mknod <device_name> c/b <major> <minor>注意:(1) mknod /dev/hello c 250 0(2) mknod /dev/hello c 250 1 錯(cuò)誤;(3) mknod /dev/hello1 c 250 0 正確,即可以有多個(gè)設(shè)備節(jié)點(diǎn)指向同一個(gè)設(shè)

10、備。操作集合打開(kāi)open:1. 統(tǒng)計(jì)計(jì)數(shù),檢查錯(cuò)誤;(一個(gè)設(shè)備可以被多個(gè)進(jìn)程打開(kāi))2. 申請(qǐng)資源:(1) 在xxx_open()函數(shù)中也可以申請(qǐng)資源;(2) 若在open中申請(qǐng)資源,則對(duì)應(yīng)要在release中釋放資源;(3) 若在加載函數(shù)中申請(qǐng)資源,則對(duì)應(yīng)要在卸載函數(shù)中釋放資源。3. 識(shí)別次設(shè)備號(hào)。(在一個(gè)驅(qū)動(dòng)識(shí)別多個(gè)設(shè)備中有應(yīng)用)4. 在應(yīng)用層調(diào)用open函數(shù)打開(kāi)設(shè)備的實(shí)現(xiàn)過(guò)程:(1) int fd = open (“/dev/hello”, O_RDWR);(2) sys_open();系統(tǒng)調(diào)用(3) vfs_open();虛擬文件系統(tǒng)提供的操作接口注意:在vfs_open()函數(shù)執(zhí)行時(shí),

11、會(huì)在內(nèi)存中創(chuàng)建兩個(gè)結(jié)構(gòu)體: struct inode dev_t i_rdev; struct cdev *i_cdev;記錄所打開(kāi)文件的靜態(tài)信息;是將磁盤上的inode節(jié)點(diǎn)信息讀過(guò)來(lái)的。 struct file struct file *f_op;記錄所打開(kāi)文件的動(dòng)態(tài)信息:包括打開(kāi)方式、當(dāng)前讀寫位置、用戶信息等。(4) xxx_open(struct inode *, struct file *);注意: 應(yīng)用層的文件描述符fd與內(nèi)核中的struct file結(jié)構(gòu)體是一一對(duì)應(yīng)的,即每打開(kāi)一個(gè)設(shè)備文件,就會(huì)在內(nèi)存中創(chuàng)建一個(gè)struct file類型的結(jié)構(gòu)體變量。每個(gè)進(jìn)程都維護(hù)有一個(gè)文件描述符表

12、:fd與struct file的對(duì)應(yīng)關(guān)系。 與xxx_open()函數(shù)相對(duì)應(yīng)的是xxx_release()函數(shù)。(1) file結(jié)構(gòu)體:(文件的靜態(tài)屬性)struct fileconst struct file_operations *f_op;/操作集合結(jié)構(gòu)體指針unsigned int f_flags;/文件打開(kāi)方式:如O_NONBLOCKloff_t f_ops;/當(dāng)前讀寫位置void *private_data;/文件私有數(shù)據(jù),通常用來(lái)存放設(shè)備結(jié)構(gòu)體的地址;應(yīng)用: 在多個(gè)同類型的設(shè)備共用一個(gè)驅(qū)動(dòng)程序時(shí):為了在驅(qū)動(dòng)中識(shí)別不同的設(shè)備,可以將設(shè)備結(jié)構(gòu)體的地址保存到file結(jié)構(gòu)體的私有成員中;

13、 利用file結(jié)構(gòu)體的f_flags成員,判斷進(jìn)程是以阻塞還是非阻塞方式訪問(wèn)文件。(2) inode結(jié)構(gòu)體:(文件的動(dòng)態(tài)信息)struct inodeumode_t i_mode;/inode的權(quán)限uid_t i_uid;/inode擁有者的idgid_t i_gid;/inode所屬的組iddev_t i_rdev;/設(shè)備號(hào)struct timespec i_atime;/inode最近一次的存取時(shí)間struct timespec i_mtime;/inode最近一次的修改時(shí)間struct timespec i_ctime;/inode的產(chǎn)生時(shí)間union /若是塊設(shè)備,為其對(duì)應(yīng)的block

14、_device結(jié)構(gòu)體指針struct block_device *i_bdev;struct cdev *i_cdev;/若是字符設(shè)備,為其對(duì)應(yīng)的cdev結(jié)構(gòu)體指針;讀read:相應(yīng)地,read()->sys_read()->vfs_read()->xxx_read()->copy_to_user。APP:ssize_t read (int fd, void *buf, size_t count);driver:ssize_t xxx_read (struct file *,char _user *,size_t,loff_t *);讀(寫)操作在內(nèi)核空間和用戶空間會(huì)發(fā)

15、生數(shù)據(jù)交互。在xxx_read(xxx_write)函數(shù)中我們通過(guò)調(diào)用內(nèi)核函數(shù):copy_to_user(cpy_from_user)將數(shù)據(jù)返回給用戶buffer(將用戶數(shù)據(jù)讀到本地buffer)。1. read()函數(shù):(1) 成功:返回實(shí)際讀到的字節(jié)數(shù);(2) 失?。悍祷?1并設(shè)置errno(非負(fù))。注意:errno就是通過(guò)將xxx_read()函數(shù)的失敗返回值取絕對(duì)值得到的。2. xxx_read()函數(shù):(1) 成功:返回實(shí)際讀到的字節(jié)數(shù);(2) 失敗:返回負(fù)的錯(cuò)誤碼-EFAULT。3. copy_to_user()函數(shù):(1) 成功:返回0;(2) 失?。悍祷厥S鄾](méi)有拷貝成功的字節(jié)數(shù)

16、。注意:(1) copy_to_user和copy_from_user在執(zhí)行時(shí)進(jìn)程有可能會(huì)阻塞(sleep),所以不能用于中斷處理;(2) copy_from_user():成功返回0;失敗返回剩余沒(méi)有寫成功的字節(jié)數(shù)。(3) 二者包含在頭文件<asm/uaccess.h>中。實(shí)例:mmap操作:一些設(shè)備,諸如:video/audio/framebuffer,在用戶空間和內(nèi)核空間之間會(huì)有很多的數(shù)據(jù)交互,使用copy_to_user/copy_from_user,要在用戶空間和內(nèi)核空間進(jìn)行不斷地切換,開(kāi)銷太大。我們可以利用mmap操作,作用:將設(shè)備內(nèi)存映射到用戶空間訪問(wèn),減小開(kāi)銷。(類

17、似于進(jìn)程間通信的共享內(nèi)存機(jī)制)ioctl操作:對(duì)設(shè)備的訪問(wèn)控制,如果都用讀寫操作來(lái)實(shí)現(xiàn),未免開(kāi)銷太大;例如,控制LED燈的亮滅,我們完全可以利用ioctl函數(shù)來(lái)實(shí)現(xiàn)。APP:int ioctl (int d, int request, . . .);driver:long (*unlock_ioctl) (struct file *,unsigned int,unsigned long);注意:在2.6.35內(nèi)核之前,應(yīng)用層ioctl函數(shù)驅(qū)動(dòng)中的ioctl函數(shù)指針;在2.6.35內(nèi)核之后,則對(duì)應(yīng)unlock_ioctl函數(shù)指針。ioctl操作是通過(guò)命令字來(lái)控制底層設(shè)備的,命令字的組成如下:8b

18、it:type類型8bit:nr編號(hào)2bit:dir數(shù)據(jù)方向14bit:size數(shù)據(jù)尺寸用2bit來(lái)表示數(shù)據(jù)傳輸方向,有4種情況:無(wú)數(shù)據(jù)傳輸、用戶->內(nèi)核、內(nèi)核->用戶、雙向傳輸。通常,我們利用ioctl操作來(lái)控制設(shè)備,不涉及數(shù)據(jù)傳輸。內(nèi)核通過(guò)四個(gè)宏用來(lái)定義命令字,且命令字要在驅(qū)動(dòng)中和應(yīng)用程序中約定好:_IO/_IOR/_IOW/_IORW。實(shí)例:利用ioctl對(duì)串口波特率進(jìn)行讀寫:(1) 獲取波特率:int baudrate; ioctl(fd, GET_BAUD,(unsigned long)&baudrate); 為了保存波特率,我們需要對(duì)參數(shù)進(jìn)行強(qiáng)制類型轉(zhuǎn)換。(2) 設(shè)置波特率:ioctl(fd, SET_BAUD, 115200);注意:(1) 處于安全考慮,在用戶操作設(shè)備時(shí),需要判斷進(jìn)程是否具有管理員的權(quán)限;(2) 我們可以調(diào)用內(nèi)核capable()函數(shù)來(lái)判斷進(jìn)程的權(quán)限:返回值為0,無(wú)權(quán)限;返回值為1,有權(quán)限。驅(qū)動(dòng)程序的調(diào)試:1. /printk注釋2. #ifde

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 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ì)用戶上傳內(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)論