版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Linux驅(qū)動(dòng)程序設(shè)計(jì)主要內(nèi)容設(shè)備驅(qū)動(dòng)的基本原理設(shè)備驅(qū)動(dòng)的編寫方法2.6內(nèi)核設(shè)備模型框架設(shè)備驅(qū)動(dòng)中的中斷處理方法串口讀寫程序?qū)嵗鼵havezWang@G2嵌入式系統(tǒng)研究室設(shè)備驅(qū)動(dòng)的基本原理-1嵌入式系統(tǒng)研究室3ChavezWang@GUSERAPPVFSDEVICEopfuncDEV_REGISTERHARDWARE用戶空間內(nèi)核空間設(shè)備驅(qū)動(dòng)設(shè)備文件與設(shè)備文件系統(tǒng)Linux中,字符設(shè)備和塊設(shè)備都是通過(guò)文件節(jié)點(diǎn)進(jìn)行訪問(wèn)。每個(gè)設(shè)備對(duì)應(yīng)一個(gè)文件名,操作時(shí)對(duì)應(yīng)各自的驅(qū)動(dòng)程序。設(shè)備文件與設(shè)備文件系統(tǒng)Linux系統(tǒng)靠主次設(shè)備號(hào)來(lái)聯(lián)系驅(qū)動(dòng)程序和設(shè)備文件節(jié)點(diǎn),依靠主設(shè)備號(hào)標(biāo)志不同的驅(qū)動(dòng)程序注冊(cè)Linux設(shè)備號(hào)的方法為避免不同的驅(qū)動(dòng)程序具有相同的設(shè)備號(hào),需要提供一種分配設(shè)備號(hào)的機(jī)制每個(gè)驅(qū)動(dòng)程序分配一個(gè)主設(shè)備號(hào):不可行,Linux最多支持255個(gè)主設(shè)備根據(jù)/proc/devices中的對(duì)應(yīng)關(guān)系,用腳本動(dòng)態(tài)的創(chuàng)建設(shè)備文件:太麻煩,程序員不愿意設(shè)備文件系統(tǒng)自動(dòng)管理注冊(cè)Linux設(shè)備號(hào)的方法系統(tǒng)啟動(dòng)時(shí),會(huì)把設(shè)備驅(qū)動(dòng)程序掛載在/dev/目錄下,Linux設(shè)備文件的創(chuàng)建和刪除、目錄層次都都由各個(gè)設(shè)備驅(qū)動(dòng)程序管理/dev/下面每個(gè)文件都動(dòng)態(tài)對(duì)應(yīng)了一個(gè)系統(tǒng)上存在的設(shè)備驅(qū)動(dòng)程序。新添加(或者刪除)一個(gè)設(shè)備,比如u盤,系統(tǒng)就會(huì)自動(dòng)在/dev目錄中創(chuàng)建(或者刪除)對(duì)應(yīng)的設(shè)備節(jié)點(diǎn)。注冊(cè)Linux設(shè)備號(hào)的方法在設(shè)備文件系統(tǒng)中,由于分的比較細(xì)致,一些驅(qū)動(dòng)程序的對(duì)應(yīng)目標(biāo)跟以前比一樣,如:Linux2.4之前:/dev/fb0/dev/ttyS0Linux2.6之后:/dev/fb/0/dev/tts/0可以用符號(hào)鏈接進(jìn)行更改,以便與之前的相匹配:ln-s/dev/fb/0/dev/fb0ls-s/dev/tts/0/dev/ttyS0設(shè)備驅(qū)動(dòng)的基本原理-2設(shè)備分類字符設(shè)備:存取時(shí)沒(méi)有緩存、只能順序讀/寫的設(shè)備??赏ㄟ^(guò)設(shè)備文件節(jié)點(diǎn)被訪問(wèn)與普通文件的區(qū)別:普通文件的訪問(wèn)可以前后移動(dòng)訪問(wèn)指針,而大多數(shù)字符設(shè)備不支持該操作。典型的字符設(shè)備鼠標(biāo)鍵盤串口嵌入式系統(tǒng)研究室4ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-3設(shè)備分類塊設(shè)備:一般塊設(shè)備都有緩存支持,并且支持隨機(jī)存取創(chuàng)建的塊設(shè)備硬盤軟盤ramdisk嵌入式系統(tǒng)研究室5ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-4設(shè)備分類網(wǎng)絡(luò)設(shè)備:從BSDUNIX網(wǎng)絡(luò)組件移植而來(lái)。網(wǎng)絡(luò)設(shè)備沒(méi)有對(duì)應(yīng)地映射到文件系統(tǒng)的設(shè)備節(jié)點(diǎn)。在Linux中,網(wǎng)絡(luò)設(shè)備的訪問(wèn)采用Socket機(jī)制實(shí)現(xiàn)嵌入式系統(tǒng)研究室6ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-5設(shè)備號(hào):Linux采用主設(shè)備號(hào)和次設(shè)備號(hào)來(lái)標(biāo)志一個(gè)具體設(shè)備。主設(shè)備號(hào)用來(lái)標(biāo)志設(shè)備類型次設(shè)備號(hào)用來(lái)區(qū)分不同的具體設(shè)備系統(tǒng)創(chuàng)建一個(gè)設(shè)備驅(qū)動(dòng)程序時(shí),設(shè)備驅(qū)動(dòng)需要使用一個(gè)主設(shè)備號(hào)向內(nèi)核注冊(cè)此驅(qū)動(dòng)。創(chuàng)建一個(gè)設(shè)備節(jié)點(diǎn)的方法:mknod設(shè)備名設(shè)備類型主設(shè)備號(hào)次設(shè)備號(hào)例:mknodttyS0c644嵌入式系統(tǒng)研究室7ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-6-內(nèi)核模塊內(nèi)核模塊的概念:內(nèi)核模塊是一些可以讓操作系統(tǒng)內(nèi)核在需要時(shí)載入和執(zhí)行的代碼,不需要時(shí)可以從操作系統(tǒng)中卸載內(nèi)核模塊是Linux內(nèi)核運(yùn)行時(shí)動(dòng)態(tài)擴(kuò)展的一種技術(shù),可以在Linux內(nèi)核運(yùn)行期間向內(nèi)核動(dòng)態(tài)添加代碼,擴(kuò)展內(nèi)核的功能嵌入式系統(tǒng)研究室8ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-7-內(nèi)核模塊內(nèi)核模塊與應(yīng)用程序加載的不同:內(nèi)核模塊的加載只是向內(nèi)核預(yù)先注冊(cè)自己以便服務(wù)于將來(lái)的某個(gè)請(qǐng)求,只是加載了某項(xiàng)功能,而不需要馬上執(zhí)行應(yīng)用程序加載后就開始執(zhí)行內(nèi)核模塊不能使用外部函數(shù)庫(kù),只能使用內(nèi)核導(dǎo)出的函數(shù)應(yīng)用程序可以使用外部函數(shù)庫(kù)內(nèi)核模塊只能運(yùn)行在內(nèi)核空間,并且不生成新的進(jìn)程應(yīng)用程序運(yùn)行在用戶空間,一般一個(gè)應(yīng)用程序生成一個(gè)新的進(jìn)程嵌入式系統(tǒng)研究室9ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-8-內(nèi)核模塊內(nèi)核模塊的框架#include<linux/init.h>#include<linux/kernel.h>#include<linux/module.h>MODULE_LICENSE("DualBSD/GPL");staticinthello_init(void){ printk(KERN_ALERT"Hello,world\n"); return0;}staticvoidhello_exit(void){ printk(KERN_ALERT"Goodbye,world\n");}module_init(hello_init);module_exit(hello_exit);嵌入式系統(tǒng)研究室10ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-9-內(nèi)核模塊2.6系列內(nèi)核模塊的編譯與加載內(nèi)核源碼樹的每個(gè)子目錄都有一個(gè)kconfig文件,為makefile提供配置數(shù)據(jù)庫(kù),分別描述了所屬目錄源文件相關(guān)的內(nèi)核配置菜單項(xiàng)內(nèi)核配置時(shí),從kconfig中讀出配置菜單,配置后生成.config文件編譯內(nèi)核時(shí),makefile讀入對(duì)應(yīng)的.config文件生成內(nèi)核映像加入新驅(qū)動(dòng)到內(nèi)核源碼樹時(shí),需要修改相應(yīng)目錄的kconfig,將新驅(qū)動(dòng)加入內(nèi)核的配置菜單,同時(shí)需要修改makefile文件嵌入式系統(tǒng)研究室11ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-10-內(nèi)核模塊嵌入式系統(tǒng)研究室12ChavezWang@G.configMakefileKconfigKconfigKconfigmakefilemakefilearch/arm/makefileScrip/makefilemenuconfig輸出Kconfig配置文件Konfig文件樹是內(nèi)核的配置數(shù)據(jù)庫(kù)每個(gè)Kconfig文件描述一系列內(nèi)核配置菜單項(xiàng),每個(gè)菜單項(xiàng)提供一個(gè)關(guān)鍵字標(biāo)識(shí)語(yǔ)法:Config<symbol><configoptions>例:configHELLO_MODULE bool“hellotestmodule”嵌入式系統(tǒng)研究室13ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-11-內(nèi)核模塊設(shè)備驅(qū)動(dòng)的基本原理-12-內(nèi)核模塊Kconfig配置文件類型定義有:bool、tristate、string、hex、integer等依賴性定義:如果菜單項(xiàng)的出現(xiàn)依賴于另一個(gè)定義時(shí),就用關(guān)鍵字dependson或者requires標(biāo)識(shí)
config HELLO_MODULE bool“hellotestmodel”dependsonARCH_PXA幫助定義:關(guān)鍵字help或者–help--嵌入式系統(tǒng)研究室14ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-13-內(nèi)核模塊內(nèi)核的makefile:內(nèi)核源碼根目錄下的頂層makefile可以分為五部分該makefile本身,負(fù)責(zé)linux內(nèi)核的二進(jìn)制映像文件vmlinux和內(nèi)核模塊的編譯內(nèi)核配置文件.config,記錄內(nèi)核的當(dāng)前配置并在編譯時(shí)提供給makefile成為其一部分特定體系結(jié)構(gòu)相關(guān)目錄下的makefile,提供與體系結(jié)構(gòu)相關(guān)的信息Scripts下的makefile.*,包含一些內(nèi)核模塊編譯共用的定義和規(guī)則內(nèi)核源碼樹各子目錄中的與模塊編譯相關(guān)的kbuildmakefile。編譯時(shí),集成上層makefile傳下來(lái)的宏定義和其他編譯規(guī)則將源代碼編入內(nèi)核或編譯成內(nèi)核模塊嵌入式系統(tǒng)研究室15ChavezWang@GKbuildmakefile內(nèi)容:最簡(jiǎn)單的只有一行。以hello.c為例:obj-y+=hello.o:編譯進(jìn)內(nèi)核的二進(jìn)制映像中obj-m+=hello.o:編譯成內(nèi)核的可加載模塊obj-$(CONFIG_HELLO_MODULE)+=hello.o根據(jù)變量的不同,既可以編譯進(jìn)內(nèi)核,也可以編譯為模塊嵌入式系統(tǒng)研究室16ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-13-內(nèi)核模塊Kbuildmakefile內(nèi)容:若具有多個(gè)文件,如mymodule由file1.cfile2.c構(gòu)成,則Makefile定義為obj-m:=mymodule.oMymodule-objs:=file1.ofile2.o在內(nèi)核源碼樹之外的模塊,則用下面的方式編譯:
make-C<PATH_TO_KERNEL>M=$PWDmodules嵌入式系統(tǒng)研究室17ChavezWang@G設(shè)備驅(qū)動(dòng)的基本原理-13-內(nèi)核模塊驅(qū)動(dòng)程序的編譯設(shè)備驅(qū)動(dòng)程序的結(jié)構(gòu)-1設(shè)備驅(qū)動(dòng)程序從總體上看可以分為兩部分驅(qū)動(dòng)與內(nèi)核的接口層:實(shí)現(xiàn)在內(nèi)核的注冊(cè)加載和卸載清除工作。若采用了中斷處理,還要包括中斷處理函數(shù)的注冊(cè)與注銷。硬件設(shè)備接口層:主要描述驅(qū)動(dòng)程序與設(shè)備的交互。包括:硬件探測(cè)硬件初始化設(shè)備讀寫訪問(wèn)設(shè)備控制操作嵌入式系統(tǒng)研究室18ChavezWang@G虛擬文件系統(tǒng)與硬件驅(qū)動(dòng)的接口1Linux系統(tǒng)中用戶對(duì)設(shè)備的操作采用文件接口實(shí)現(xiàn)。虛擬文件系統(tǒng)將這種對(duì)文件的訪問(wèn)操作轉(zhuǎn)化為對(duì)設(shè)備的具體操作。虛擬文件系統(tǒng)為設(shè)備驅(qū)動(dòng)提供了一個(gè)標(biāo)準(zhǔn)化的文件操作實(shí)現(xiàn)接口。該接口定義在:Include/linux/fs.h中的file_operations定義嵌入式系統(tǒng)研究室19ChavezWang@G/**NOTE:*read,write,poll,fsync,readv,writevcanbecalled*withoutthebigkernellockheldinallfilesystems.*/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);
嵌入式系統(tǒng)研究室20ChavezWang@Gint(*mmap)(structfile*,structvm_area_struct*); int(*open)(structinode*,structfile*); int(*flush)(structfile*); int(*release)(structinode*,structfile*); int(*fsync)(structfile*,structdentry*,intdatasync); int(*aio_fsync)(structkiocb*,intdatasync); 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*filp,unsignedlongarg); int(*flock)(structfile*,int,structfile_lock*);};嵌入式系統(tǒng)研究室21ChavezWang@G注意:結(jié)構(gòu)體中的函數(shù),并不是每個(gè)都需要實(shí)現(xiàn)的。不需要實(shí)現(xiàn)的函數(shù),可以直接初始化為空。在嵌入式系統(tǒng)中,一般僅僅實(shí)現(xiàn)其中的幾個(gè)接口函數(shù):read,write,ioctl,open,release等,就可以完成應(yīng)用系統(tǒng)需要的功能嵌入式系統(tǒng)研究室22ChavezWang@G虛擬文件系統(tǒng)與硬件驅(qū)動(dòng)的接口2Open方法:方法open用于打開設(shè)備,open操作是對(duì)設(shè)備的第一個(gè)操作,如果open方法為空,則設(shè)備始終打開成功遞增使用計(jì)數(shù)檢查特定設(shè)備錯(cuò)誤如果設(shè)備是首次打開,則對(duì)其進(jìn)行初始化識(shí)別次設(shè)備號(hào)嵌入式系統(tǒng)研究室23ChavezWang@G虛擬文件系統(tǒng)與硬件驅(qū)動(dòng)的接口3虛擬文件系統(tǒng)與硬件驅(qū)動(dòng)的接口4release方法:方法release在關(guān)閉文件時(shí)調(diào)用,其工作與open方法相反釋放由open分配的filp->private_data中的左右內(nèi)容使用計(jì)數(shù)減一在最后一次關(guān)閉操作時(shí)關(guān)閉設(shè)備嵌入式系統(tǒng)研究室24ChavezWang@G虛擬文件系統(tǒng)與硬件驅(qū)動(dòng)的接口5read方法:方法read從設(shè)備中讀取數(shù)據(jù),函數(shù)返回非負(fù)值表示成功讀出的字節(jié)數(shù)返回值等于傳遞給read系統(tǒng)調(diào)用的count參數(shù),表明請(qǐng)求的數(shù)據(jù)傳輸成功返回值大于0,但小于傳遞給read系統(tǒng)調(diào)用的count參數(shù),表明部分?jǐn)?shù)據(jù)傳輸成功,根據(jù)設(shè)備的不同,導(dǎo)致這個(gè)問(wèn)題的原因也不同,一般采取再次讀取的方法返回值=0,表示到達(dá)文件的末尾返回值為負(fù)數(shù),表示出現(xiàn)錯(cuò)誤,并且指明何種錯(cuò)誤在阻塞型io中,read調(diào)用會(huì)出現(xiàn)阻塞。嵌入式系統(tǒng)研究室25ChavezWang@G虛擬文件系統(tǒng)與硬件驅(qū)動(dòng)的接口6write方法:方法write向設(shè)備中寫入數(shù)據(jù),函數(shù)返回非負(fù)值表示成功寫入的字節(jié)數(shù)返回值等于傳遞給write系統(tǒng)調(diào)用的count參數(shù),表明請(qǐng)求的數(shù)據(jù)傳輸成功返回值大于0,但小于傳遞給write系統(tǒng)調(diào)用的count參數(shù),表明部分?jǐn)?shù)據(jù)傳輸成功,根據(jù)設(shè)備的不同,導(dǎo)致這個(gè)問(wèn)題的原因也不同,一般采取再次寫入的方法返回值=0,表示沒(méi)有寫入任何數(shù)據(jù)。此時(shí)一般會(huì)重復(fù)調(diào)用write返回值為負(fù)數(shù),表示出現(xiàn)錯(cuò)誤,并且指明是何種錯(cuò)誤。在阻塞性io中,write調(diào)用會(huì)出現(xiàn)阻塞。嵌入式系統(tǒng)研究室26ChavezWang@G虛擬文件系統(tǒng)與硬件驅(qū)動(dòng)的接口7ioctl方法:方法ioctl為設(shè)備調(diào)用ioctl提供了一種執(zhí)行設(shè)備特定命令的方法,主要是讀寫之外的其他控制。如配置設(shè)備、進(jìn)入或者退出某種操作模式等。實(shí)驗(yàn)板上的SPI設(shè)備通道的選擇操作,即通過(guò)這種方式嵌入式系統(tǒng)研究室27ChavezWang@G虛擬文件系統(tǒng)與硬件驅(qū)動(dòng)的接口8*owner指向擁有該結(jié)構(gòu)的模塊,內(nèi)核使用指針維護(hù)模塊的使用計(jì)數(shù)llseek用來(lái)修改文件當(dāng)前位置,并將新位置作為結(jié)果返回。loff_t是在linux中定義的長(zhǎng)偏移量。出錯(cuò)時(shí)返回負(fù)值。嵌入式系統(tǒng)研究室28ChavezWang@G方法poll是系統(tǒng)調(diào)用select和poll的后端實(shí)現(xiàn),用這兩個(gè)系統(tǒng)調(diào)用來(lái)查詢?cè)O(shè)備是否可以讀寫或者是否處于某種狀態(tài)。如果poll為空,則驅(qū)動(dòng)設(shè)備會(huì)被認(rèn)為既可讀,又可寫,返回值是一個(gè)狀態(tài)掩碼。方法mmap將設(shè)備內(nèi)存映射到進(jìn)程地址空間。嵌入式系統(tǒng)研究室29ChavezWang@G虛擬文件系統(tǒng)與硬件驅(qū)動(dòng)的接口9簡(jiǎn)單的字符驅(qū)動(dòng)-1大多數(shù)字符設(shè)備比較簡(jiǎn)單,通常直接使用file_operations接口。本課程將以一個(gè)虛擬的字符設(shè)備test_char為例,說(shuō)明字符驅(qū)動(dòng)的結(jié)構(gòu)嵌入式系統(tǒng)研究室30ChavezWang@G簡(jiǎn)單的字符驅(qū)動(dòng)-2虛擬文件系統(tǒng)與設(shè)備驅(qū)動(dòng)程序的接口本設(shè)備之設(shè)計(jì)到讀寫和設(shè)備的打開關(guān)閉操作。因此可以定義以下file_opertions結(jié)構(gòu)體變量。structfile_operationstestchar_fops{ .read=test_read, .write=test_write, .open=test_open, .release=test_release};注意:定義結(jié)構(gòu)體變量之前需要先實(shí)現(xiàn)用到的函數(shù)嵌入式系統(tǒng)研究室31ChavezWang@G簡(jiǎn)單的字符驅(qū)動(dòng)-3staticchartest_val=‘a(chǎn)’;//用全局變量保存虛擬設(shè)備讀寫的數(shù)據(jù)staticssize_ttest_read(structfile*filp,char__user*buf,size_tcount,loff_t*l){ copy_to_user(buf,&val,sizeof(val)); returnsizeof(val);}//copy_to_user(void__user*to,constvoid*from,unsignedlongn);Staticssize_ttest_write(structfile*file,constchar__user*buf,size_tcount,loff_t*l){ copy_from_user(&val,buf,sizeof(val); returnsizeof(val);}//copy_from_user(void*to,void__user*from,unsignedlongn)Staticinttest_open(structinode*inode,structfile*filp){ try_module_get(THIS_MODULE);//模塊計(jì)數(shù)加一
return0;}Staticinttest_release(structinode*inode,structfile*filp){ module_put(THIS_MODULE);//模塊計(jì)數(shù)減一
return0;}嵌入式系統(tǒng)研究室32ChavezWang@G簡(jiǎn)單的字符驅(qū)動(dòng)-4驅(qū)動(dòng)模塊的加載和卸載操作
#defineTEST_MAJOR251 #defineTEST_NAME “TEST_CHAR” int__initinit_routine(void){ register_chrdev(TEST_MAJOR,TEST_NAME,&testchar_fops); return0;}//intregister_chrdev(unsignedintmajor,constchar*name,structfile_operations//*fops)Voidcleanup_routine(void){ unregister_chrdev(TEST_MAJOR,TEST_NAME);} module_init(init_routine); module_exit(cleanup_routine);嵌入式系統(tǒng)研究室33ChavezWang@GLinux2.6內(nèi)核設(shè)備模型-1Linux2.2版之前沒(méi)有統(tǒng)一的驅(qū)動(dòng)形式,2.4通過(guò)使用一組通用接口將PCI、PCMIA等整合到一個(gè)單一的設(shè)備結(jié)構(gòu)中,2.6內(nèi)核則更進(jìn)一步,試圖在整個(gè)系統(tǒng)的范圍內(nèi)對(duì)硬件設(shè)備進(jìn)行抽象,建立一個(gè)統(tǒng)一的全新設(shè)備模型新模型包括四個(gè)重要數(shù)據(jù)結(jié)構(gòu):structkobjectstructksetstructktypestructsubsystem嵌入式系統(tǒng)研究室34ChavezWang@GLinux2.6內(nèi)核設(shè)備模型-2structkobject結(jié)構(gòu):最底層的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)structkobject{ char *k_name;//動(dòng)態(tài)分配空間的設(shè)備名稱
char name[KOBJ_NAME_LEN];//長(zhǎng)度受限的設(shè)備名稱
atomic_t refcount;//引用計(jì)數(shù)
struct list_head entry;//掛接到所有集合中去的入口
structkobject*parent;// 商機(jī)對(duì)象的指針
structkset *kset;//所屬對(duì)象集合的指針
structkobj_type ktype;// 所屬對(duì)象類型指針
structdentry*dentry;//在sysfs系統(tǒng)中的文件節(jié)點(diǎn)路徑指針}嵌入式系統(tǒng)研究室35ChavezWang@GLinux2.6內(nèi)核設(shè)備模型-3structkset結(jié)構(gòu):用于描述同一類kobject集合structkset{ structsubsystem *subsys;//所在的subsystem的指針
structkobj_type *ktype;//集合中的對(duì)象類型
structlist_head list;//集合中的對(duì)象鏈表
structkobject kobj;//集合自身相關(guān)信息的內(nèi)核對(duì)象
structkset_hotplug_ops *hotplug_ops;//該集合的熱插拔函數(shù)}嵌入式系統(tǒng)研究室36ChavezWang@GLinux2.6內(nèi)核設(shè)備模型-4structkobj_ktype結(jié)構(gòu):structkobj_type{ void(*release)(structkobject*);//本類對(duì)象的釋放函數(shù)
structsysfs_ops *sysfs_ops;//本類對(duì)象在sysfs中的操作函數(shù)
structattribute**default_attrs;//本類對(duì)象在sysfs中的屬性}嵌入式系統(tǒng)研究室37ChavezWang@GLinux2.6內(nèi)核設(shè)備模型-5structsubsystem內(nèi)核對(duì)象子系統(tǒng):是最上層的數(shù)據(jù)結(jié)構(gòu),用于描述同屬一類設(shè)備的子系統(tǒng)structsubsystem{ structksetkset;//該子系統(tǒng)的內(nèi)核對(duì)象集合
structrw-semaphorerwsem;//互斥訪問(wèn)信號(hào)量}嵌入式系統(tǒng)研究室38ChavezWang@GLinux2.6內(nèi)核設(shè)備模型-6系統(tǒng)初始化時(shí),drivers/base/init.c中的driver-init()函數(shù)將幾個(gè)頂層子系統(tǒng)的subsystem數(shù)據(jù)結(jié)構(gòu)注冊(cè)到內(nèi)核初始化子系統(tǒng)數(shù)據(jù)結(jié)構(gòu)在sysfs文件系統(tǒng)下建立各個(gè)子系統(tǒng)的目錄樹五個(gè)子系統(tǒng):設(shè)備子系統(tǒng)devices_subbus總線子系統(tǒng)bus_subbus設(shè)備基類子系統(tǒng)class_subbus固件子系統(tǒng)(fireware_subbus)虛擬系統(tǒng)總線子系統(tǒng)(system_subbus)嵌入式系統(tǒng)研究室39ChavezWang@GLinux2.6內(nèi)核設(shè)備模型-7五個(gè)子系統(tǒng)構(gòu)成了管理框架初始化時(shí),初始化程序調(diào)用內(nèi)核對(duì)象注冊(cè)函數(shù)將設(shè)備數(shù)據(jù)結(jié)構(gòu)中的成員kobject結(jié)構(gòu)注冊(cè)到相應(yīng)的子系統(tǒng)中最終用戶可以通過(guò)sysfs文件系統(tǒng)看到所有設(shè)備的信息嵌入式系統(tǒng)研究室40ChavezWang@GLinux內(nèi)核的中斷處理-1中斷機(jī)制是實(shí)現(xiàn)外部I/O異步操作的重要方法Linux內(nèi)核對(duì)外部設(shè)備的中斷處理在設(shè)備驅(qū)動(dòng)程序里實(shí)現(xiàn)嵌入式系統(tǒng)研究室41ChavezWang@GLinux內(nèi)核的中斷處理-2中斷處理程序的注冊(cè)注冊(cè)函數(shù)Intrequest_irq(unsignedintirq,irqreturn_t(*handler)(int,void*,structpt_regs*), unsignedlongirq_flags,constchar*devname,void*dev_id);該函數(shù)成功則返回0;irq為要注冊(cè)的中斷號(hào)Handler指向中斷處理程序的函數(shù)指針irq-flags為中斷標(biāo)志,含義如下:SA_INTERRUPT:不受中斷屏蔽的影響,任何情況下都可以響應(yīng)。一般只有時(shí)鐘中斷具有此標(biāo)志。SA_SAMPLE_RAMDOM:產(chǎn)生中斷的間隔時(shí)間放入系統(tǒng)隨機(jī)數(shù)的內(nèi)核熵池SA_SHIRQ:表明為共享中斷嵌入式系統(tǒng)研究室42ChavezWang@GLinux內(nèi)核的中斷處理-3中斷處理程序的注冊(cè)dev_name:與中斷相關(guān)的設(shè)備名字。dev_id:主要用于共享中斷中,釋放共享中斷時(shí),根據(jù)dev_id的標(biāo)志信息來(lái)刪除指定的那個(gè)中斷處理程序處理的中斷。若dev_id設(shè)為null,則為獨(dú)占式的中斷嵌入式系統(tǒng)研究室43ChavezWang@GLinux內(nèi)核的中斷處理-4中斷處理程序的釋放Voidfree_irq(unsignedintirq,void*dev_id)若釋放的中斷是共享的,則dev_id對(duì)應(yīng)的中斷處理程序與中斷的綁定關(guān)系被刪除若刪除了最后一個(gè)中斷處理程序的綁定關(guān)系,則此中斷被禁用若要釋放的中斷是非共享的,則刪除中斷處理程序的同時(shí)也將禁用中斷嵌入式系統(tǒng)研究室44ChavezWang@GLinux內(nèi)核的中斷處理-5中斷處理程序的編寫中斷處理程序與其他內(nèi)核函數(shù)的不同之處:中斷處理程序發(fā)送或者接受數(shù)據(jù)都必須在內(nèi)核空間,不能在內(nèi)核與用戶空間之間發(fā)送或者接受數(shù)據(jù)中斷不能做任何可能發(fā)生休眠的操作,也不能調(diào)用schedule函數(shù)進(jìn)行進(jìn)程調(diào)度。staticirqreturn_tirq_handler(intirq,void*dev_id,structpt_regs*regs)當(dāng)中斷程序被調(diào)用并正確處理時(shí),返回IRQ_HANDLED,否則返回IRQ_NONE嵌入式系統(tǒng)研究室45ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-1問(wèn)題引入:通常中斷處理程序需要盡量做到短小和快速處理,以免中斷阻塞時(shí)間過(guò)長(zhǎng),影響實(shí)時(shí)性和中斷響應(yīng)速度但是,有些設(shè)備產(chǎn)生中斷后需要處理較多的與中斷相關(guān)的工作,所以速度會(huì)比較慢處理方法將中斷處理分為兩個(gè)部分:中斷處理程序部分:只做必要的有嚴(yán)格時(shí)限的工作,如中斷應(yīng)答和復(fù)位硬件等,一般需要屏蔽中斷的情況下處理其他需要時(shí)間的不是很緊急的工作推后處理。嵌入式系統(tǒng)研究室46ChavezWang@G內(nèi)核工作推后執(zhí)行的機(jī)制主要有:軟中斷tasklet工作隊(duì)列嵌入式系統(tǒng)研究室47ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-2軟中斷:通常用于執(zhí)行頻率很高的強(qiáng)實(shí)時(shí)性的場(chǎng)合。作為一種底層機(jī)制,很少由內(nèi)核程序員直接使用。enum{ HI_SOFTIRQ=0,//優(yōu)先級(jí)高的tasklet軟中斷
TIMER_SOFTIRQ,//定時(shí)器軟中斷
NET_TX_SOFTIRQ,//網(wǎng)絡(luò)數(shù)據(jù)包發(fā)送軟中斷
NET_RX_SOFTIRQ,//網(wǎng)絡(luò)數(shù)據(jù)包接收軟中斷
SCSI_SOFTIRQ,//SCSI軟中斷的軟中斷
TASKLET_SOFTIRQ.//tastlet軟中斷的軟中斷}嵌入式系統(tǒng)研究室48ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-3tasklet:小任務(wù),指一小段可以執(zhí)行的嗲嗎,通常以函數(shù)的形式出現(xiàn),對(duì)于io驅(qū)動(dòng)程序,是實(shí)現(xiàn)工作推后執(zhí)行的首選方法。tasklet基于軟中斷機(jī)制實(shí)現(xiàn),實(shí)際上只是一種軟中斷的應(yīng)用和包裝structtasklet_struct{ structtasklet_struct*next;//指向鏈表中的下一個(gè)結(jié)構(gòu)體
unsignedlongstate;//tasklet的狀態(tài),初始化時(shí)為0,被調(diào)用時(shí)為1 atomic_tcount;//引用計(jì)數(shù)器,若不為0,則不能執(zhí)行;若為0則可以執(zhí)行
void(*func)(unsignedlong);//tasklet處理函數(shù)
unsignedlongdata;//給tasklet處理函數(shù)的參數(shù)}嵌入式系統(tǒng)研究室49ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-4tasklet的使用tasklet聲明:DECLARE_TASKLET(name,func,data)//初始值為0,激活狀態(tài)DECLARE_TASKLET_DISABLED(name,func,data)//初始值為1,停用狀態(tài)name:tasklet_struct變量的名字func:是tasklet的執(zhí)行函數(shù)data:是tasklet執(zhí)行函數(shù)的參數(shù)嵌入式系統(tǒng)研究室50ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-5tasklet的使用tasklet執(zhí)行函數(shù)定義Voidfunc(unsignedlongdata)注意:必須與structtasklet_struct結(jié)構(gòu)中的func定義一致Func()要在tasklet聲明之前定義不能使用信號(hào)量或者其他可能引起阻塞的函數(shù),因?yàn)閠asklet不能休眠嵌入式系統(tǒng)研究室51ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-6tasklet的使用tasklet的調(diào)度tasklet_schedule(&name):將一個(gè)tasklet狀態(tài)置為準(zhǔn)備執(zhí)行狀態(tài),系統(tǒng)由合適的機(jī)會(huì)時(shí),就會(huì)盡快執(zhí)行Tasklet_disable():將tasklet的count計(jì)數(shù)增1,從而停用該taskletTasklet_enable():激活tasklet。Tasklet_kill():從等待執(zhí)行的tasklet隊(duì)列中刪除一個(gè)tasklet嵌入式系統(tǒng)研究室52ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-6工作隊(duì)列每個(gè)工作隊(duì)列有一個(gè)專門的線程,稱之為工作隊(duì)列線程工作隊(duì)列中推后執(zhí)行的工作由此線程完成,所有的工作在線程的上下文中被執(zhí)行。因此,允許重新調(diào)度甚至睡眠嵌入式系統(tǒng)研究室53ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-7工作隊(duì)列:structwork_struct數(shù)據(jù)結(jié)構(gòu)Structwork_struct{ unsignedlongpending;//工作是否等待處理
structlist_headentry;//工作隊(duì)列中的工作鏈表
void(*func)(void*);//處理函數(shù)
void*data;//處理函數(shù)的參數(shù)
void*wq_data;//內(nèi)部使用
structtimer_listtimer;//定時(shí)器}嵌入式系統(tǒng)研究室54ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-8工作隊(duì)列的使用創(chuàng)建工作隊(duì)列:Structworkquene_struct*create_workquene(constchar*name)//創(chuàng)建一個(gè)新工作隊(duì)列,返回新工作隊(duì)列的指針例如:structworksquene_struct*my_workqe; my_workqe=create_workquene(“my_workqe”);創(chuàng)建推后執(zhí)行的工作編譯時(shí)創(chuàng)建工作隊(duì)列:#defineDECLARE_WORK(name,func,data)\structwork_structn=__WORK_INITALIZER(name,func,data)運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建:Structwork_structmy_work;INIT_WORK(my_work,my_work_func,data);嵌入式系統(tǒng)研究室55ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-9工作隊(duì)列的使用定義工作的任務(wù)處理函數(shù)Voidfunc(void*data)將工作加入工作隊(duì)列中intquene_work(structworkquene_struct*squene,structwork_struct*work);//即時(shí)加入工作隊(duì)列intquene_delayed_work(structworkquene_struct*quene,structwork_struct*work,unsignedlongdelay);//延遲一段時(shí)間加入工作隊(duì)列Intcancel_delayed_work(structwork_struct*work)//取消延期加入工作隊(duì)列的工作;如果已經(jīng)加入則不受影響嵌入式系統(tǒng)研究室56ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-10工作隊(duì)列的使用刷新工作隊(duì)列Voidfastcallflush_workquene(structworkquene_struct*wq);//在卸載前,保證操作都已經(jīng)執(zhí)行完畢。如果沒(méi)有執(zhí)行完畢,會(huì)進(jìn)入休眠狀態(tài)銷毀工作隊(duì)列Voiddestroy_workquene(structworkquene_struct*wq);//銷毀使用完畢的工作隊(duì)列注意:不是所有的驅(qū)動(dòng)都需要自己的工作隊(duì)列。嵌入式系統(tǒng)研究室57ChavezWang@GLinux2.6內(nèi)核的工作推后執(zhí)行機(jī)制-6串行通信的基本概念串行通信與串口定義串行方式傳輸數(shù)據(jù)傳輸速度用bps或者波特率描述常用的串口為RS-232-C串口通信的基本參數(shù)每秒位數(shù)—波特率數(shù)據(jù)位奇偶校驗(yàn)位停止位數(shù)據(jù)流控制在Linux下進(jìn)行串口通信
打開串口類似于打開文件,必須使用O_NOCTTY方式:如果打開的是一個(gè)終端設(shè)備,程序不會(huì)成為對(duì)應(yīng)這個(gè)端口的控制終端#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>intfd;if((fd=open(“dev/ttyS0”,O_RDWR|O_NOCTTY))==1)perrro(“…”)設(shè)置串口通信參數(shù)波特率設(shè)置獲得端口波特率通過(guò)cfgetispeed函數(shù)和cfgetospeed函數(shù)實(shí)現(xiàn)設(shè)置端口波特率通過(guò)cfsetispeed函數(shù)和cfsetospeed函數(shù)實(shí)現(xiàn)數(shù)據(jù)位數(shù)據(jù)位指的是每次輸入字節(jié)中實(shí)際數(shù)據(jù)所占的比特?cái)?shù),通過(guò)修改termios結(jié)構(gòu)體中的c_cflag成員來(lái)實(shí)現(xiàn)。其中CS5CS6CS7CS8分別表示數(shù)據(jù)位為5、6、7、8位。設(shè)置時(shí),必須先使用CSIZE做位屏蔽。奇偶校驗(yàn)位奇偶校驗(yàn)可以選擇偶校驗(yàn)、奇校驗(yàn)、空格等方式,也可以不使用校驗(yàn)。如果要設(shè)置偶檢驗(yàn)的話,首先將ternios結(jié)構(gòu)體中c_cflag設(shè)置PARENB標(biāo)志,并清除PARODD標(biāo)志。奇校驗(yàn)同時(shí)設(shè)置ternios結(jié)構(gòu)體中c_cflag設(shè)置PARENB標(biāo)志和PARODD標(biāo)志。
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 《初級(jí)會(huì)計(jì)講義》課件
- 《圍絕經(jīng)期出血》課件
- 小學(xué)一年級(jí)上冊(cè)青島版5年制數(shù)學(xué)3610以內(nèi)數(shù)的加減混合運(yùn)算同步教案
- 小學(xué)一年級(jí)100以內(nèi)數(shù)學(xué)口算練習(xí)題大全
- 外墻腳手架承包合同6篇
- 三校聯(lián)考生物試卷生物科期末考試試卷
- 高考語(yǔ)文綜合素質(zhì) 晨讀材料專題輔導(dǎo)之三
- 《分配式噴油泵》課件
- 《贏得歷史的機(jī)遇》課件
- 四川省部分名校2023-2024學(xué)年高三上學(xué)期期末聯(lián)合考試英語(yǔ)試題(音頻暫未更新)
- JTG-D40-2011公路水泥混凝土路面設(shè)計(jì)規(guī)范
- 2024年4月自考02799獸醫(yī)臨床醫(yī)學(xué)試題
- 2024年全國(guó)高考體育單招考試語(yǔ)文試卷試題(含答案詳解)
- 市政工程勞動(dòng)力計(jì)劃
- 2023年七年級(jí)語(yǔ)文上冊(cè)期末測(cè)試卷(完美版)
- 2023年七年級(jí)地理上冊(cè)期末測(cè)試卷帶答案
- MOOC 普通植物病理學(xué)-西北農(nóng)林科技大學(xué) 中國(guó)大學(xué)慕課答案
- 種雞場(chǎng)的飼養(yǎng)管理制度
- 一年級(jí)數(shù)學(xué)上冊(cè)口算比賽
- 2019年4月自考00319行政組織理論試題及答案含解析
- 石油工程設(shè)計(jì)大賽油藏工程組獲獎(jiǎng)作品
評(píng)論
0/150
提交評(píng)論