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

下載本文檔

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

文檔簡介

Linux字符設(shè)備驅(qū)動(dòng)程序第1頁Linux驅(qū)動(dòng)程序分類字符設(shè)備驅(qū)動(dòng):用于驅(qū)動(dòng)能夠像字節(jié)流(文獻(xiàn))同樣被訪問設(shè)備。應(yīng)用程序一般能夠利用open、close、read、write等系統(tǒng)調(diào)用訪問字符設(shè)備驅(qū)動(dòng)。塊設(shè)備驅(qū)動(dòng):塊設(shè)備和字符設(shè)備只在系統(tǒng)內(nèi)核內(nèi)部管理上有所區(qū)分。應(yīng)用程序?qū)τ谧址O(shè)備每一種I/O操作都會被內(nèi)核直接傳遞給對應(yīng)驅(qū)動(dòng)程序;而應(yīng)用程序?qū)τ趬K設(shè)備操作要通過虛擬文獻(xiàn)系統(tǒng)(VFS)和緩沖區(qū)管理系統(tǒng)間接地傳遞給驅(qū)動(dòng)程序處理。網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng):應(yīng)用程序必須利用套接字(socket)接口訪問網(wǎng)絡(luò)設(shè)備。第2頁第3頁網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)程序第4頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造字符設(shè)備開發(fā)基本步驟確定主設(shè)備號和次設(shè)備號實(shí)現(xiàn)字符驅(qū)動(dòng)程序?qū)崿F(xiàn)file_operations構(gòu)造體構(gòu)造字符設(shè)備構(gòu)造體cdev在模塊加載函數(shù)中注冊字符設(shè)備在模塊卸載函數(shù)中注銷字符設(shè)備創(chuàng)建設(shè)備文獻(xiàn)節(jié)點(diǎn)第5頁設(shè)備文獻(xiàn)與設(shè)備號為了體現(xiàn)“一切都是文獻(xiàn)”設(shè)計(jì)思想,linux將每個(gè)已安裝設(shè)備都表達(dá)為一種設(shè)備文獻(xiàn)。設(shè)備文獻(xiàn)一般位于/dev子目錄。對于字符設(shè)備,應(yīng)用程序能夠利用open、close、read、write等系統(tǒng)調(diào)用訪問其設(shè)備文獻(xiàn),這些I/O操作都被直接傳遞給該設(shè)備文獻(xiàn)所對應(yīng)設(shè)備。每個(gè)設(shè)備文獻(xiàn)中都存放了該設(shè)備“主設(shè)備號”和“次設(shè)備號”。一般由同一種內(nèi)核模塊管理多種設(shè)備占用同一種主設(shè)備號,詳細(xì)設(shè)備用次設(shè)備號標(biāo)識。用mknodfilenamecmajorminor命令創(chuàng)建設(shè)備文獻(xiàn)用rmfilename命令刪除設(shè)備文獻(xiàn)。注意刪除設(shè)備文獻(xiàn)并不會影響驅(qū)動(dòng)模塊。第6頁應(yīng)用程序如何訪問設(shè)備fd1=open(“/dev/ttyS1”,O_RDWR);//阻塞fd2=open(“/dev/ttyS1”,O_RDWR|O_NONBLOCK);//非阻塞intread(intfd,constvoid*buf,size_tlength);intwrite(intfd,constvoid*buf,size_tlength);intlseek(intfd,offset_toffset,intwhence);intioctl(intfd,intcmd,void*arg);intclose(intfd);第7頁設(shè)備號內(nèi)部體現(xiàn)設(shè)備編號內(nèi)部體現(xiàn)dev_t類型(32位):用來保存設(shè)備編號(包括主設(shè)備號(12位)和次設(shè)備號(20位))從dev_t取得主設(shè)備號和次設(shè)備號:MAJOR(dev_t);MINOR(dev_t);將主設(shè)備號和次設(shè)備號轉(zhuǎn)換成dev_t類型:MKDEV(intmajor,intminor);

第8頁主設(shè)備號與次設(shè)備號分派主設(shè)備號手工分派主設(shè)備號:找一種內(nèi)核沒有使用主設(shè)備號來使用。#include<linux/fs.h>intregister_chrdev_region(dev_tfirst,unsignedintcount,char*name);要分派設(shè)備編號范圍起始值,次設(shè)備號經(jīng)常為0所祈求連續(xù)設(shè)備編號個(gè)數(shù)和該編號范圍關(guān)聯(lián)設(shè)備名稱第9頁主設(shè)備號與次設(shè)備號動(dòng)態(tài)分派主設(shè)備號:#include<linux/fs.h>intalloc_chrdev_resion(dev_t*dev,unsignedintfirstminor,unsignedintcount,char*name);輸出設(shè)備號要使用被祈求第一種次設(shè)備號第10頁主設(shè)備號與次設(shè)備號釋放設(shè)備號voidunregister_chrdev_region(dev_tfirst,unsignedintcount);一般在模塊清除函數(shù)中調(diào)用。第11頁統(tǒng)計(jì)字符設(shè)備構(gòu)造體cdev實(shí)現(xiàn)字符驅(qū)動(dòng)程序cdev構(gòu)造體structcdev{ structkobjectkobj;/*內(nèi)嵌kobject對象*/ structmodule*owner;/*所屬模塊*/ structfile_operations*ops;/*文獻(xiàn)操作構(gòu)造體*/ structlist_headlist; dev_tdev;/*設(shè)備號*/ unsignedintcount;};cdevkobj、list、count字段不用我們關(guān)系和維護(hù)(內(nèi)核代勞),我們只需將其ops字段指向?yàn)槲覀冏约篺ileoperations構(gòu)造。第12頁對cdev構(gòu)造體操作操作cdev函數(shù)voidcdev_init(structcdev*,structfile_operations*);structcdev*cdev_alloc(void);intcdev_add(structcdev*,dev_t,unsigned);voidcdev_del(structcdev*);用于初始化cdev組員,并建立cdev和file_operations之間連接分別向系統(tǒng)刪除一種cdev,完成字符設(shè)備注銷,一般在模塊卸載函數(shù)中調(diào)用分別向系統(tǒng)添加一種cdev,完成字符設(shè)備注冊,一般在模塊加載函數(shù)中調(diào)用函數(shù)用于動(dòng)態(tài)申請一種cdev內(nèi)存第13頁file_operations構(gòu)造體file_operations構(gòu)造體字符驅(qū)動(dòng)和內(nèi)核接口:在include/linux/fs.h定義字符驅(qū)動(dòng)只要實(shí)現(xiàn)一種file_operations構(gòu)造體并注冊到內(nèi)核中,內(nèi)核就有了操作此設(shè)備能力。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*,const

char__user*,size_t,loff_t*);

unsigned

int(*poll)(structfile*,structpoll_table_struct*);

int(*ioctl)(structinode*,structfile*,unsigned

int,unsigned

long);

int(*open)(structinode*,structfile*);

int(*flush)(structfile*,fl_owner_tid);

int(*release)(structinode*,structfile*);//………};第14頁file_operations構(gòu)造體

file_operations主要組員:structmodule*owner:

指向模塊本身open:打開設(shè)備release:關(guān)閉設(shè)備read:從設(shè)備上讀數(shù)據(jù)write:向設(shè)備上寫數(shù)據(jù)ioctl:I/O控制函數(shù)llseek:定位讀寫指針mmap:映射設(shè)備空間到進(jìn)程地址空間第15頁fileoperations初始化structfile_operationsmy_fops={.owner=THIS_MODULE,.llseek=my_llseek,.read=my_read,.write=my_write,.ioctl=my_ioctl,.open=my_open,.release=my_release,};第16頁file構(gòu)造體file構(gòu)造代表一種打開文獻(xiàn),它由內(nèi)核在應(yīng)用程序open時(shí)創(chuàng)建,并將該文獻(xiàn)所對應(yīng)fileoperations統(tǒng)計(jì)在file構(gòu)造中。在應(yīng)用程序調(diào)用close函數(shù),內(nèi)核會釋放該數(shù)據(jù)構(gòu)造。structfile{ structfile_operations *f_op; unsignedint f_flags; fmode_t f_mode; loff_t f_pos;struct dentry *f_dentry void* private_data;};第17頁file構(gòu)造體file構(gòu)造體

file構(gòu)造:file_operations構(gòu)造有關(guān)一種構(gòu)造體。描述一種正在打開設(shè)備文獻(xiàn)。組員:loff_tf_pos:

目前讀/寫位置unsignedintf_flags標(biāo)識文獻(xiàn)打開時(shí),是否可讀或可寫O_RDONLYO_NONBLOCKO_SYNCstructfile_operations*f_op文獻(xiàn)有關(guān)操作,指向所實(shí)現(xiàn)structfile_operationsvoid*private_data:

私有數(shù)據(jù)指針。驅(qū)動(dòng)程序能夠?qū)⑦@個(gè)字段用于任何目標(biāo)或者忽視這個(gè)字段。第18頁inode構(gòu)造體內(nèi)核用inode構(gòu)造在內(nèi)部表達(dá)文獻(xiàn),用于存放文獻(xiàn)訪問權(quán)限、屬主、組、大小、生產(chǎn)時(shí)間等VFS關(guān)懷信息。其字段中我們只關(guān)懷i_rdev(設(shè)備號),和i_cdev(和該文獻(xiàn)所對應(yīng)cdev構(gòu)造)我們在創(chuàng)建設(shè)備文獻(xiàn)時(shí),內(nèi)核會自動(dòng)創(chuàng)建一種對應(yīng)inode構(gòu)造體,并將其i_cdev字段指向?qū)?yīng)字符設(shè)備構(gòu)造體cdev(事先已經(jīng)在內(nèi)核中注冊過)。Inode與file區(qū)分:file表達(dá)打開文獻(xiàn)描述符,多種file構(gòu)造,能夠指向單個(gè)inode構(gòu)造。structinode{ dev_ti_rdev; structcdev*i_cdev; //………};第19頁Inode構(gòu)造體Inode構(gòu)造中兩個(gè)主要字段:dev_ti_rdev;對表達(dá)設(shè)備文獻(xiàn)inode構(gòu)造,該字段包括了真正設(shè)備編號。structcdev*i_cdev;structcdev是表達(dá)字符設(shè)備內(nèi)核內(nèi)部構(gòu)造。當(dāng)inode指向一種字符設(shè)備文獻(xiàn)時(shí),該字段包括了指向structcdev構(gòu)造指針從一種inode中取得主設(shè)備號和次設(shè)備號:unsignedintiminor(structinode*inode);unsignedintimajor(structinode*inode);第20頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造注冊設(shè)備

,在模塊或驅(qū)動(dòng)初始化時(shí)調(diào)用Linux-2.4及之前Linux-2.6intregister_chrdev(unsignedintmajor,constchar*name, structfile_operations*fops)如何操作字符設(shè)備接口voidcdev_init(structcdev*,structfile_operations*);intcdev_add(structcdev*,dev_t,unsigned);第21頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造注銷設(shè)備:在模塊卸載時(shí)調(diào)用Linux-2.4及之前Linux-2.6intunregister_chrdev(unsignedintmajor, constchar*name);voidcdev_del(structcdev*);第22頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造//設(shè)備驅(qū)動(dòng)模塊加載函數(shù)staticint__initxxx_init(void){ ... cdev_init(&xxx_dev.cdev,&xxx_fops);//初始化cdev xxx_dev.cdev.owner=THIS_MODULE; //獲取字符設(shè)備號 if(xxx_major) { register_chrdev_region(xxx_dev_no,1,DEV_NAME); } else { alloc_chrdev_region(&xxx_dev_no,0,1,DEV_NAME); } ret=cdev_add(&xxx_dev.cdev,xxx_dev_no,1);//注冊設(shè)備 ...}第23頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造/*設(shè)備驅(qū)動(dòng)模塊卸載函數(shù)*/staticvoid__exitxxx_exit(void){ unregister_chrdev_region(xxx_dev_no,1);//釋放占用設(shè)備號

cdev_del(&xxx_dev.cdev);//注銷設(shè)備 ...}第24頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造打開模塊使用計(jì)數(shù)加1識別次設(shè)備號硬件操作:檢查設(shè)備有關(guān)錯(cuò)誤(諸如設(shè)備未就緒或類似硬件問題);假如設(shè)備是初次打開,則對其初始化;假如有中斷操作,申請中斷處理程序;intopen(structinode*inode,structfile*filp);第25頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造關(guān)閉模塊使用計(jì)數(shù)減1釋放由open分派,保存在filp>private_data里所有內(nèi)容。硬件操作:假如申請了中斷,則釋放中斷處理程序。在最后一次關(guān)閉操作時(shí)關(guān)閉設(shè)備。intrelease(structinode*inode,structfile*filp);第26頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造

read/writessize_tread(structfile*filp,char__user*buff,size_tcount,loff_t*offp);ssize_twrite(structfile*filp,constchar__user*buff,size_tcount,loff_t*offp);指向顧客空間緩沖區(qū),這個(gè)緩沖區(qū)或者保存將寫入數(shù)據(jù),或者是一種寄存新讀入數(shù)據(jù)空緩沖區(qū)。顧客在文獻(xiàn)中存取操作位置第27頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造

顧客空間和內(nèi)核空間之間數(shù)據(jù)拷貝過程,不能簡單用指針操作或者memcpy來進(jìn)行數(shù)據(jù)拷貝顧客空間數(shù)據(jù)是能夠被換出,會產(chǎn)生一種頁面失效異常。顧客空間地址無法在內(nèi)核空間中使用。顧客空間和內(nèi)核空間之間進(jìn)行數(shù)據(jù)拷貝函數(shù):假如要復(fù)制內(nèi)存是簡單類型,如char、int、long等,put_user()和get_user()unsignedlongcopy_from_user(void*to,constvoid__user*from,unsignedlongcount);unsignedlongcopy_to_user(void__user*to,constvoid*from,unsignedlongcount);第28頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造讀設(shè)備模板ssize_txxx_read(structfile*filp,char__user*buf, size_tcount,loff_t*f_pos){ ... copy_to_user(buf,...,...); ...}寫設(shè)備模板ssize_txxx_write(structfile*filp,constchar__user*buf, size_tcount,loff_t*f_pos){ ... copy_from_user(...,buf,...); ...}第29頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造

ioctl函數(shù)為設(shè)備驅(qū)動(dòng)程序執(zhí)行“命令”提供了一種特有入口點(diǎn)用來設(shè)置或者讀取設(shè)備屬性信息。intioctl(structinode*inode,structfile*filp, unsignedintcmd,unsignedlongarg);事先定義IO控制命令代碼arg為對應(yīng)于cmd命令參數(shù)第30頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造cmd參數(shù)定義不推薦用0x1,0x2,0x3之類值Linux對ioctl()cmd參數(shù)有特殊定義構(gòu)造命令編號宏:_IO(type,nr)用于構(gòu)造無參數(shù)命令編號;_IOR(type,nr,datatype)用于構(gòu)造從驅(qū)動(dòng)程序中讀取數(shù)據(jù)命令編號;_IOW(type,nr,datatype)用于寫入數(shù)據(jù)命令;_IOWR(type,nr,datatype)用于雙向傳輸。type和number位字段通過參數(shù)傳入,而size位字段通過對datatype參數(shù)取sizeof取得。

設(shè)備類型(type)

序列號(number)方向(direction)

數(shù)據(jù)尺寸(size)

8bit

8bit

2bit13/14bit第31頁字符設(shè)備驅(qū)動(dòng)程序基本構(gòu)造Ioctl函數(shù)模板intxxx_ioctl(structinode*inode,structfile*filp,unsignedintcmd,unsignedlongarg){ ... switch(cmd) { caseXXX_CMD1: ... break; caseXXX_CMD2: ... break; default:///*不能支持命令*/ return-ENOTTY; } return0;}第32頁階段總結(jié)第33頁階段總結(jié)第34頁添加驅(qū)動(dòng)程序到內(nèi)核配備內(nèi)核編譯內(nèi)核添加驅(qū)動(dòng)程序到內(nèi)核中第35頁添加驅(qū)動(dòng)程序到內(nèi)核配備內(nèi)核配備命令包括: makeconfig makemenuconfig makexconfig makegconfig

可通過“上”、“下”、“左”、“右”鍵移動(dòng)菜單,選擇某項(xiàng)按“Y”,取消選擇按“N”,假如選擇某項(xiàng)編譯為模塊按“M”,進(jìn)入子菜單按“Enter”,返回上一級菜單按“Esc”使用makeconfig、makemenuconfig等命令后,會生成一種.config配備文獻(xiàn)(是隱身文獻(xiàn),通過ls–a才能看到)

第36頁添加驅(qū)動(dòng)程序到內(nèi)核編譯內(nèi)核可用如下命令編譯內(nèi)核:makeARC=armCROSS_COMPILE=arm-linux-zImage源代碼根目錄Makefile中將ARCH和CROSS_COMPILE直接指定為arm和arm-linux-,如:

這樣就沒有必要每次編譯時(shí)候都指定體系構(gòu)造和交叉編譯器了,只須使用下面命令就能夠了:

makezImageARCH ?=armCROSS_COMPILE ?=arm-linux-第37頁添加驅(qū)動(dòng)程序到內(nèi)核添加驅(qū)動(dòng)程序到內(nèi)核Linux2.6內(nèi)核配備系統(tǒng)由下列3個(gè)部分組成。Makefile:分布在Linux內(nèi)核源代碼中Makefite定義Linux內(nèi)核編譯規(guī)則配備文獻(xiàn)(Kconfig):給顧客提供配備選擇功能。配備工具:包括配備命令解釋器(對配備腳本中使用配備命令進(jìn)行解釋)配備顧客界面(提供字符界面和圖形界面)。這些配備工具都是使用腳本語言編寫,如Tcl/TK、Perl等。在Linux內(nèi)核中增加程序需要完成下列3項(xiàng)工作。將編寫源代碼復(fù)制到Linux內(nèi)核源代碼對應(yīng)目錄。在目錄Kconfig文獻(xiàn)中增加新源代碼對應(yīng)項(xiàng)目標(biāo)編譯配備選項(xiàng)。在目錄Makefile文獻(xiàn)中增加對新源代碼編譯條目。第38頁添加驅(qū)動(dòng)程序到內(nèi)核實(shí)例:在內(nèi)核源代碼drivers目錄下為ARM體系構(gòu)造新增testdrivertestdriver樹形目錄:

溫馨提示

  • 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

提交評論