![嵌入式系統(tǒng)驅動程序開發(fā)_第1頁](http://file4.renrendoc.com/view11/M01/38/26/wKhkGWWd2iiAQB1DAAG9i0LfNVA748.jpg)
![嵌入式系統(tǒng)驅動程序開發(fā)_第2頁](http://file4.renrendoc.com/view11/M01/38/26/wKhkGWWd2iiAQB1DAAG9i0LfNVA7482.jpg)
![嵌入式系統(tǒng)驅動程序開發(fā)_第3頁](http://file4.renrendoc.com/view11/M01/38/26/wKhkGWWd2iiAQB1DAAG9i0LfNVA7483.jpg)
![嵌入式系統(tǒng)驅動程序開發(fā)_第4頁](http://file4.renrendoc.com/view11/M01/38/26/wKhkGWWd2iiAQB1DAAG9i0LfNVA7484.jpg)
![嵌入式系統(tǒng)驅動程序開發(fā)_第5頁](http://file4.renrendoc.com/view11/M01/38/26/wKhkGWWd2iiAQB1DAAG9i0LfNVA7485.jpg)
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第5章嵌入式系統(tǒng)驅動程序開發(fā)
1主要內容模塊編程編譯模塊進內核嵌入式系統(tǒng)驅動程序概述嵌入式系統(tǒng)驅動程序結構LED燈驅動程序實例2模塊編程內核模塊是Linux內核向外部提供的一個插口,其全稱為動態(tài)可加載內核模塊〔LoadableKernelModule,LKM〕。Linux本身是一個單內核,單內核的最大優(yōu)點是效率高,因為所有的內容都集成在一起,但其缺點是可擴展性和可維護性相對較差,模塊機制就是為了彌補這一缺陷。3模塊編程模塊是具有獨立功能的程序,它可以被單獨編譯,但不能獨立運行。模塊在運行時被鏈接到內核作為內核的一局部在內核空間運行,這與運行在用戶空間的進程是不同的。模塊通常由一組函數(shù)和數(shù)據(jù)結構組成,用來實現(xiàn)一種文件系統(tǒng)、一個驅動程序或其它內核上層的功能。4將模塊從內核中獨立出來,不必預先綁在kernelcodes中。這樣做有三種優(yōu)點:1〕將來修改內核時,不必全部重新編譯,可節(jié)省不少時間;2〕假設需要安裝新的模塊,不必重新編譯內核,只要插入〔通過insmode指令〕對應的模塊即可;3〕減少內核對系統(tǒng)資源的占用,內核可以集中精力做最根本的事情,把一些擴展功能都交由模塊實現(xiàn)。
5模塊編程模塊命令insmod掛載模塊insmodhello.ko將hello.ko模塊插入到內核中rmmod移除已掛載模塊rmmodhello.ko將hello.ko模塊從內核中卸載lsmod列出已經(jīng)加載的內核模塊modinfo查看模塊信息modinfohello.ko查看hello.ko模塊信息
modprobe自動根據(jù)依賴文件裝入模塊dmesg查看log信息6modprobe功能說明:自動處理可載入模塊。語法:modprobe[-acdlrtvV][--help][模塊文件][符號名稱=符號值]補充說明:modprobe可載入指定的個別模塊,或是載入一組相依的模塊。modprobe會根據(jù)depmod所產(chǎn)生的相依關系,決定要載入哪些模塊。假設在載入過程中發(fā)生錯誤,在modprobe會卸載整組的模塊。7modprobe參數(shù):
-a或--all載入全部的模塊。
-c或--show-conf顯示所有模塊的設置信息。
-d或--debug使用排錯模式。
-k或--autoclean指定模塊設置為"自動去除"模式。
-l或--list顯示可用的模塊。
-n或--show
僅僅顯示要執(zhí)行的操作,而不實際執(zhí)行
-q或--quiet不顯示錯誤信息。8modprobe參數(shù):
-r或--remove模塊閑置不用時,即自動卸載模塊。
-s或--syslog//將結果記錄到系統(tǒng)記錄中。
-t或--type指定模塊類型。
-v或--verbose執(zhí)行時顯示詳細的信息。
-V或--version顯示版本信息。
-C或--configconfigfile指定配置文件,默認使用/etc/modules.conf文件為配置文件。
-h或-help顯示幫助。9insmod掛載模塊insmod這個工具,和modprobe有點類似,但功能上沒有modprobe強,modprobe在掛載模塊是不用指定模塊文件的路徑,也不用帶文件的后綴.o或.ko;而insmod需要的是模塊的所在目錄的絕對路徑,并且一定要帶有模塊文件名后綴的(modulefile.o或modulesfile.ko〕10模塊編程一個linux內核模塊主要由以下幾個局部組成模塊加載函數(shù)(必須)模塊卸載函數(shù)(必須)模塊許可證聲明(必須)模塊參數(shù)(可選)模塊導出符號(可選)模塊作者等信息聲明(可選)11模塊編程模塊加載函數(shù)當通過insmod命令加載內核模塊時,模塊的加載函數(shù)會自動被內核執(zhí)行,完本錢模塊的相關初始化工作。linux模塊加載函數(shù)的形式如下:
staticintinitialization_function(void)
{
/*初始化代碼*/
}模塊加載函數(shù)必須以module_init(initialization_function)的形式被指定。它返回整型值,假設初始化成功,返回0,否那么返回錯誤編碼。當通過insmod和modprobe命令加載內核模塊時,模塊的加載函數(shù)會自動被內核執(zhí)行,完本錢模塊的相關初始化工作。12模塊編程模塊卸載函數(shù)當通過rmmod命令卸載內核模塊時,模塊的卸載函數(shù)會自動被內核執(zhí)行,完成與模塊加載函數(shù)相反的功能。linux內核模塊卸載函數(shù)的形式如下:
staticvoid
cleanup_function(void)
{
/*釋放代碼*/
}模塊卸載函數(shù)在模塊卸載的時候執(zhí)行,不返回任何值,必須以module_exit(cleanup_function)的形式來指定;模塊卸載函數(shù)在模塊卸載的時候執(zhí)行,不返回任何值,必須以“module_exit(函數(shù)名)〞的形式來指定。13模塊編程通常來說,模塊卸載函數(shù)要完成與模塊加載函數(shù)相反的功能:假設模塊加載函數(shù)注冊了XXX,那么模塊卸載函數(shù)應該注銷XXX;假設模塊記載函數(shù)的動態(tài)申請了內存,那么模塊函數(shù)應該釋放該該內存。假設模塊加載函數(shù)申請了硬件資源(中斷,DMA通道、I/O端口和I/O內存等)的占用,那么模塊卸載函數(shù)應該釋放這些硬件資源。模塊加載函數(shù)一般用來開啟硬件,模塊卸載函數(shù)一般要關閉硬件。14模塊編程模塊許可證聲明MODULE_LICENSE("DaulBSD/GPL")模塊許可證(LICENSE)聲明描述內核模塊的許可權限,如果不聲明LICENSE,模塊被加載時,將收到內核被污染(kerneltainted)的警告。在linux2.6內核中,可接受的LICENSE包括“GPL〞、“GPLv2〞、“GPLandadditionalrights〞、“DualBSD/GPL〞、“DualMPL/GPL〞和“Proprietary“。大多數(shù)情況下,內核模塊應遵循GPL兼容許可權。linux2.6內核模塊中最常見的是以MODULE_LICENSE(“DualBSD/GPL〞)語句聲明模塊采用BSD/GPL雙LICENSE。15模塊編程模塊導出符號Linux2.6的“/proc/kallsyms〞文件對應著內核符號表,它記錄了符號以及符號所在的內存地址。內核模塊可以使用如下宏導出符號(symbol,對應于函數(shù)或變量)到內核符號表。EXPORT_SYMBOL(符號名);EXPORT_SYMBOL_GPL(符號名);//只適用于包含GPL許可權的模塊。導出的符號將可以被其它模塊使用,使用前聲明一下即可以。
16模塊編程模塊作者等信息聲明MODULE_AUTOR("作者信息");MODULE_DESCRIPTION("模塊描述信息");MODULE_VERSION("版本信息");MODULE_ALIAS("別名信息");MODULE_DEVICE_TABLE("設備表信息");17模塊編程介紹printk()printk是在內核中運行的向控制臺輸出顯示的函數(shù)。模塊運行在內核空間,不能依賴于標準C庫的。標準C庫需要調用操作系統(tǒng)內核提供的系統(tǒng)調用來完成打印字符的工作。18printk有8個級別,定義在<include/linux/kernel.h>中:#defineKERN_EMERG“<0>〞/*緊急事件消息,系統(tǒng)崩潰之前提示,表示系統(tǒng)不可用*/#defineKERN_ALERT“<1>〞/*報告消息,表示必須立即采取措施*/#defineKERN_CRIT“<2>〞/*臨界條件,通常涉及嚴重的硬件或軟件操作失敗*/#defineKERN_ERR“<3>〞/*錯誤條件,驅動程序常用KERN_ERR來報告硬件的錯誤*/19printk有8個級別,定義在<include/linux/kernel.h>中:#defineKERN_WARNING“<4>〞/*警告條件,對可能出現(xiàn)問題的情況進行警告*/#defineKERN_NOTICE“<5>〞/*正常但又重要的條件,用于提醒*/#defineKERN_INFO“<6>〞/*提示信息,如驅動程序啟動時,打印硬件信息*/#defineKERN_DEBUG“<7>〞/*調試級別的消息*/20模塊編程通過〞insmodhello.ko〞命令可以加載它,加載時輸出〞helloworld〞。通過〞rmmodhello〞命令可以卸載它,卸載時輸出〞hellomoduleexit〞,查看輸出信息可通過dmesg命令。21編寫一個hello.c模塊:1〕編寫代碼:#include<linux/init.h>#include<linux/module.h>/*Neededbyallmodules*/MODULE_LICENSE(“DualBSD/GPL〞);staticinthello_init(void){printk(KERN_INFO“Helloworldenter\n〞);/*內核中打印信息要用printk(),用戶中用printf()。printk()可定義輸出級別*/return0;}staticvoidhello_exit(void){printk(KERN_INFO“HelloWorldexit\n");}module_init(hello_init);/*加載模塊。假設成功,返回0。失敗時,應輸出錯誤編碼*/module_exit(hello_exit);//卸載模塊,不返回任何值。MODULE_DESCRIPTION(“AsimpleHelloWorldModule〞);MODULE_ALIAS(“asimplestmodule〞);22加載模塊失敗時應輸出錯誤編碼,在Linux內核中,錯誤編碼是一個負值。在<linux/errno.h>中定義,包含-ENODEV、-ENOMEM之類的符號值。在2.6內核中,可用request_module(constchar*fmt,…)函數(shù)加載內核模塊。23模塊編程實例1-1:用命令在X86下加載和卸載hello模塊在同一目錄下編輯Makefile文件。添加這一行:obj-m:=hello.o編譯模塊:
#make-C/lib/modules/2.6.32-21-generic/buildM=$(pwd)modules編譯產(chǎn)生hello.ko目標文件加載hello命令:#sudoinsmod./hello.ko用rmmod可以卸載模塊#sudormmodhello通過lsmod命令可以獲得系統(tǒng)中加載的所有模塊以及模塊間的依賴關系。用命令dmesg來查看log信息。24模塊編程實例1-1說明obj-m:=hello.oobj-m表示要由hello.c文件編譯得到hello.o,并作為模塊編譯,obj-y表示要連接進內核,obj-x表示不會被編譯是內核模塊的安裝路徑,就是編譯內核的時候“make
modules_install〞在/lib/modules/目錄下生成的系統(tǒng)源碼包;M=后面的是指存放hello.c和Makefile所在的目錄。25模塊編程實例1-2:編譯arm版本的hello模塊#makeclean清理中間文件和目標文件。編譯arm下的模塊:#make-C../../workhome/ces-6410/uboot/htx-linux-2.6.24-yaffs2M=$(pwd)modules其中是目標板的linux內核源碼目錄。注:編譯過的的arm內核是目標板的內核,在編譯時只能用這個內核進行編譯。加載模塊:將目標文件hello.ko放到目標板上的下,再加載:#insmodhello.ko查看模塊用lsmod命令;用rmmod命令卸載模塊:#rmmodhello26模塊編程模塊參數(shù)模塊參數(shù)是模塊被加載的時候可以被傳遞給模塊的值,它本身對應模塊內部的全局變量??梢允褂谩癿odule_param(參數(shù)名,參數(shù)類型,讀/寫權限)〞為模塊定義一個參數(shù)。27模塊參數(shù)例如:以下代碼定義了一個整型參數(shù)和一個字符指針參數(shù)。
staticchar*book_name="linux設備驅動";
staticintnum=4000;
module_param(num,int,S_IRUGO);
module_param(book_name,charp,S_IRGUO);在裝載內核模塊時,用戶可以向內核模塊傳遞參數(shù),
形式為“sudoinsmod/modprobe模塊名(例如linux.ko)
參數(shù)名=參數(shù)值〞,如果不傳遞,參數(shù)將使用模塊內定義的默認值。28程序:hello_param.c#include<linux/module.h>//所有模塊都需要的頭文件
#include<linux/init.h>//init&exit相關宏
MODULE_LICENSE(“DualBSD/GPL");
staticchar*book_name=“dissectingLinuxDeviceDriver〞;staticintnum=4000;staticinthello_init(void)
{
printk("Hellomoduleinit\n");
return0;
}
staticvoidhello_exit(void)
{
printk("Hellomoduleexit\n");
}
module_init(hello_init);
module_exit(hello_exit);module_param(num,int,S_IRUGO);module_param(book_name,charp,S_IRUGO);29模塊編程Makefile模塊的編寫需要配置過的內核源碼,編譯過程首先會到內核源碼目錄下,讀取頂層Makefile文件,然后再返回模塊所在的目錄進行編譯。30模塊編程實例2:復雜點的Makefile文件Makefile內容ifneq($(KERNELRELEASE),)
obj-m:=hello.o
else
KDIR:=/lib/modules/$(shelluname-r)/build
PWD:=$(shellpwd)all:
$(MAKE)-C$(KDIR)M=$(PWD)
endifclean:
rm-f*.o*.ko*.mod.c.hello*編譯:make31實例2:復雜點的Makefile文件KERNELRELEASE是在內核源碼的頂層Makefile中定義的一個變量,當?shù)谝淮巫x取執(zhí)行此makefile時,沒有被定義,所以make將讀取執(zhí)行else之后的內容。如果make的目標是clean,直接執(zhí)行clean操作,然后結束。如果make的目標是all,-C$(KDIR)指明跳轉到內核源碼目錄下讀取那里的makefile;M=$(PWD)說明返回到當前目錄繼續(xù)讀入,執(zhí)行當前的makefile。32模塊編程模塊依賴于Linux版本、CPU等因素查看可以下載的Linux內核源碼包sudoapt-cachesearchlinux-source選定要下載的源碼包sudo下載完成后,在/usr/src下,文件名為:linux-source-2.6.32.tar.bz2的壓縮包33編譯模塊進內核2.6內核的源碼樹的目錄下一般都會有兩個文檔Kconfig〔2.4版本是Config.in〕和Makefile。分布到各目錄的Kconfig構成了一個分布式的內核配置數(shù)據(jù)庫,每個Kconfig分別描述了所屬目錄源文件相關的內核配置菜單。在內核配置makemenuconfig〔或xconfig等〕時,從Kconfig中讀出配置菜單,用戶配置完成后保存到.config〔在頂層目錄下生成〕中。在內核編譯時,主Makefile調用這個.config,就知道了用戶對內核的配置情況。34編譯模塊進內核Kconfig對應著內核的配置菜單,要想添加新的驅動到內核的源碼中,可以通過修改Kconfig來增加對我們驅動的配置菜單,這樣就有途徑選擇我們的驅動。假設想使這個驅動被編譯,還要修改該驅動所在目錄下的Makefile。因此,一般添加新的驅動時需要修改的文件有兩種〔注意不只是兩個〕。*Kconfig,*Makefile要想知道怎么修改這兩種文件,就要知道這兩種文件的語法結構。35〔1〕Kconfig每個菜單項都有一個關鍵字標識,最常見的就是config。語法: configsymbol optionssymbol就是新的菜單項,options是在這個新的菜單項下的屬性和選項,其中options局部有:a.類型定義:每個config菜單項都要有類型定義,bool:布爾類型,tristate三態(tài):內建、模塊、移除,string:字符串,hex:十六進制,integer:整型。編譯模塊進內核36編譯模塊進內核〔1〕Kconfigoptions局部有:a.類型定義:例:configHELLO_MODULE
bool"hellotestmodule"bool類型的只能選中或不選中,顯示為[];tristate類型的菜單項多了編譯成內核模塊的選項,顯示為<>,假設選擇編譯成內核模塊,那么會在.config中生成一個CONFIG_HELLO_MODULE=m的配置,假設選擇內建,就是直接編譯進內核,就會在.config中生成一個CONFIG_HELLO_MODULE=y的配置37〔1〕Kconfigoptions局部有:b.依賴型定義dependson或requires指此菜單的出現(xiàn)是否依賴于另一個定義:例如:configHELLO_MODULEbool“hellotestmodule〞 dependsonARCH_PXA這個例子說明HELLO_MODULE這個菜單項只對XScale處理器有效,即只有在選擇了ARCH_PXA,該菜單才可見〔可配置〕。編譯模塊進內核38〔1〕Kconfigoptions局部有:c.幫助性定義:只是增加幫助用關鍵字help或help編譯模塊進內核39編譯模塊進內核〔1〕Kconfigmenu"Networkdevicesupport"
configNETDEVICES
bool"EnableNetDevices"
dependsonNET
defaulty
help
Thisishelpdesciption。
...endmenu
40編譯模塊進內核〔1〕Kconfig在menu/endmenu中的內容會成為Networkdevicesupport的子菜單。每一個子菜單項都是由config來定義的。config下方的那些bool、dependson、default、help等為config的屬性,用于定義該菜單項的類型、依賴項、默認值、幫助信息等。
41編譯模塊進內核〔1〕Kconfig目錄層次迭代:在上級Kconfig中有類似語句:source“drivers/usb/Kconfig“或source"drivers/misc/Kconfig“用來包含〔或嵌套〕新的Kconfig文件,這樣便可以使各個目錄管理各自的配置內容,不必把那些配置都寫在同一個文件里,方便修改和管理。misc驅動是一些擁有著共同特性的簡單字符設備驅動。所有的misc設備被分配同一個主設備號MISC_MAJOR(10),但是每一個可以選擇一個單獨的次設備號。42編譯模塊進內核〔2〕內核的Makefile內核的Makefile分為5個組成局部:
1〕Makefile最頂層的Makefile
2〕.config內核的當前配置文件,編譯時成為頂層Makefile的一局部
3〕arch/$(ARCH)/Makefile和體系結構相關的Makefile
4〕s/Makefile.*一些Makefile的通用規(guī)那么
5〕kbuildMakefile各級目錄下的大概約500個文件,編譯時根據(jù)上層Makefile傳下來的宏定義和其它編譯規(guī)那么,將源代碼編譯成模塊或編入內核。43編譯模塊進內核〔2〕Makefile頂層的Makefile文件讀取.config文件的內容,并總體上負責build內核和模塊。ArchMakefile那么提供補充體系結構相關的信息。s目錄下的Makefile文件包含了所有用來根據(jù)kbuildMakefile構建內核所需的定義和規(guī)那么。44編譯模塊進內核〔2〕Makefileobj-$(CONFIG_HELLO)+=hello.o根據(jù).config文件的CONFIG_變量來決定文件的編譯方式〔編譯進內核或編譯成模塊〕451〕進入內核,在driver/misc下建立hello文件夾,并編寫一個名為hello.c的模塊:#include<linux/init.h>#include<linux/module.h>MODULE_LICENSE(“DualBSD/GPL〞);staticinthello_init(void){printk(KERN_INFO“Helloworld!\n");return0;}staticvoidhello_exit(void){printk(KERN_INFO"Goodbyeworld!\n");}module_init(hello_init);module_exit(hello_exit);實例3:將模塊編譯進內核在arm開發(fā)板上運行462〕建立Kconfig在hello文件夾下建立Kconfig,內容如下: menu“HelloDriver〞 comment“HelloDriver〞 configHELLO tristate“Hellosupport〞 help thisisahellodiriverwhichcansay“helloworld!〞; endmenu473〕建立Makefile在hello文件夾下建立Makefile,內容如下:obj-$(CONFIG_HELLO)+=hello.o4〕使Kconfig和Makefile生效編輯driver/misc/Kconfig,在ifMISC_DEVICES下添加語句:sourcedrivers/misc/hello/Kconfig編輯driver/misc/Makefile,添加:obj-$(CONFIG_HELLO)+=hello.o/485〕到內核的頂層目錄,執(zhí)行sudomakemenuconfig,選中該驅動在Devicedriver->Micsdevices->HelloDriver->495〕到內核的頂層目錄,執(zhí)行sudomakemenuconfig,選中該驅動在Devicedriver->Micsdevices->HelloDriver->按h輸出幫助信息按y,出現(xiàn)個*號,表示將其編譯進內核M編譯為模塊506〕編譯:#sudomake信息如下:516〕編譯:編譯結果如下:527〕把內核燒入教學平臺啟動信息如下:有helloworld信息輸出,說明已經(jīng)成功,hello驅動已在內核中注冊。538〕把hello驅動編譯成模塊:在第5步中,把驅動選擇改成以模塊方式編譯,選M,如下:548〕把hello驅動編譯成模塊:再來編譯,看到它正以模塊的方式被編譯:558〕把hello驅動編譯成模塊:編譯結果:569〕測試模塊在教學平臺啟動進入文件系統(tǒng)后,把hello.ko拷到下,如果沒有要事先建立?!?mkdir〕進入目錄,通過insmod進行掛載,rmmod進行卸載。到此,一個簡單的hello驅動編譯進內核和編譯成模塊的實驗完成。57設備驅動最通俗的解釋是“驅使硬件設備行動〞。設備驅動與底層硬件直接打交道,按照硬件設備的具體工作方式讀寫設備存放器,完成設備的輪詢、中斷、DMA通信,進行物理內存向虛擬內存的映射,最終使通信設備能夠收發(fā)數(shù)據(jù)。設備驅動的一個根本特征是設備處理的抽象概念。嵌入式系統(tǒng)驅動程序概述58嵌入式系統(tǒng)驅動程序概述在Linux系統(tǒng)中,所有的外部設備都被看作是目錄/dev下的一個文件,也就是系統(tǒng)把外部設備當作特殊文件來處理,并為外部設備提供一種標準接口,使得系統(tǒng)像訪問文件一樣訪問外部設備。應用程序通過調用標準的設備文件操作函數(shù)來翻開、關閉、讀取和寫入設備。例如系統(tǒng)中的第一個IDE硬盤被表示成/dev/had。59嵌入式系統(tǒng)驅動程序概述Linux支持三類硬件設備:一類是塊設備,類似磁盤以記錄塊或扇區(qū)為單位,成塊進行輸入/輸出的設備;另一類是字符設備,類似鍵盤以字符為單位,逐個進行輸入/輸出的設備。第三類是網(wǎng)路設備是一種特殊設備;/dev下沒有對應于網(wǎng)絡設備的文件,正常的文件操作(read,write等)對于網(wǎng)絡設備沒有意義。網(wǎng)絡設備可以通過套接口訪問。60字符設備指那些無需緩沖直接讀寫的設備,字符設備接口只支持順序存取的功能。塊設備那么僅能以塊為單位讀寫,典型的塊大小為512或1024字節(jié)。塊設備的存取是通過buffercache來進行并且可以隨機訪問,即不管塊位于設備中何處都可以對其進行讀寫。塊設備可以通過其設備相關文件進行訪問,但更為平常的訪問方法是通過文件系統(tǒng)。文件系統(tǒng)通常都建立在塊設備上。網(wǎng)絡設備可以通過套接口訪問。嵌入式系統(tǒng)驅動程序概述61塊〔磁盤〕設備和字符設備的設備相關文件可以通過mknod命令來創(chuàng)立,并使用主從設備號來描述此設備。網(wǎng)絡設備也用設備相關文件來表示,但Linux尋找和初始化網(wǎng)絡設備時才建立這種文件。由同一個設備驅動控制的所有設備具有相同的主設備號,從設備號那么被用來區(qū)分具有相同主設備號且由相同設備驅動控制的不同設備。嵌入式系統(tǒng)驅動程序概述62嵌入式系統(tǒng)驅動程序概述設備驅動程序實際是處理和操作硬件控制器的軟件,從本質上講,是內核中具有最高特權級的、駐留內存的、可共享的底層硬件處理例程。驅動程序是內核的一局部,是操作系統(tǒng)內核與硬件設備的直接接口,驅動程序屏蔽了硬件的細節(jié)。63嵌入式系統(tǒng)驅動程序概述設備驅動程序完成以下功能:對設備初始化和釋放;對設備進行管理,包括實時參數(shù)設置,以及提供對設備的操作接口;讀取應用程序傳送給設備文件的數(shù)據(jù)或者回送應用程序請求的數(shù)據(jù);檢測和處理設備出現(xiàn)的錯誤。64Linux操作系統(tǒng)將所有的設備全部看成文件,并通過文件的操作界面進行操作。對用戶程序而言,設備驅動程序隱藏了設備的具體細節(jié),對各種不同設備提供了一致的接口,一般來說,是把設備映射為一個特殊的設備文件,用戶程序可以像對其他文件一樣對此設備文件進行操作。65這意味著:由于每一個設備至少由文件系統(tǒng)的一個文件代表,因而都有一個“文件名〞。應用程序通常可以通過系統(tǒng)調用open()翻開設備文件,建立起與目標設備的連接。翻開了代表著目標設備的文件,即建立起與設備的連接后,可以通過read()、write()、ioctl()等常規(guī)的文件操作對目標設備進行操作。66嵌入式系統(tǒng)驅動程序結構在系統(tǒng)內部,I/O設備的存取通過一組固定的入口點來進行,入口點也可以理解為設備的句柄,就是對設備進行操作的根本函數(shù)。字符型設備驅動程序提供如下幾個入口點:open入口點。翻開設備準備I/O操作。對字符設備文件進行翻開操作,都會調用設備的open入口點。open子程序必須對將要進行的I/O操作做好必要的準備工作,如去除緩沖區(qū)等。如果設備是獨占的,即同一時刻只能有一個程序訪問此設備,那么open子程序必須設置一些標志以表示設備處于忙狀態(tài)。67嵌入式系統(tǒng)驅動程序結構close入口點。關閉一個設備。當最后一次使用設備完成后,調用close子程序。獨占設備必須標記設備方可再次使用。read入口點。從設備上讀數(shù)據(jù)。對于有緩沖區(qū)的I/O操作,一般是從緩沖區(qū)里讀數(shù)據(jù)。對字符設備文件進行讀操作將調用read子程序。68嵌入式系統(tǒng)驅動程序結構write入口點。往設備上寫數(shù)據(jù)。對于有緩沖區(qū)的I/O操作,一般是把數(shù)據(jù)寫入緩沖區(qū)里。ioctl入口點。執(zhí)行讀、寫之外的操作。select入口點。檢查設備,看數(shù)據(jù)是否可讀或設備是否可用于寫數(shù)據(jù)。select系統(tǒng)調用在檢查與設備文件相關的文件描述符時使用select入口點。69嵌入式系統(tǒng)驅動程序結構Linux系統(tǒng)設備驅動程序三個重要數(shù)據(jù)結構:file_operation〔文件操作〕file〔文件〕inode〔節(jié)點〕定義在include/linux/fs.h文件中
70嵌入式系統(tǒng)驅動程序結構file_operation將系統(tǒng)調用和驅動關聯(lián)起來,用來存儲內核驅動模塊提供的對設備進行各種操作的指針函數(shù)。71structfile_operation{
structmodule*owner;loff_t(*llseek)(structfile*,loff_t,int);ssize_t(*read)(structfile*,char*,size_t,loff_t*);ssize_t(*write)(structfile*,constchar*,size_t,loff_t*);int(*readdir)(structfile*,void*,filldir_t);nsignedint(*poll)(structfile*,structpoll_table_struct*);int(*ioctl)(structinode*,structfile*,unsignedint,unsignedlong);int(*mmap)(structfile*,structvm_area_struct*);int(*open)(structinode*,structfile*);int(*flush)(structfile*);int(*release)(structinode*,structfile*);int(*fsync)(structfile*,structdentry*,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(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);};};72file_operation結構中的成員幾乎全部是函數(shù)指針,所以實質上就是函數(shù)跳轉表。每個進程對設備的操作都會根據(jù)major、minor設備號,轉換成對file_operation結構的訪問。73file_operation結構中常用的操作:lseek,移動文件指針的位置,只能用于可以隨機存取的設備。read,進行讀操作,如果該成員為一個空指針,系統(tǒng)調用返回一個-EINVAL錯誤,正常情況下返回一個非負整數(shù)代表讀取的字節(jié)數(shù)。write,進行寫操作。select,進行選擇操作。如果驅動程序沒有提供select入口,select操作會認為設備已經(jīng)準備好進行任何I/O操作。ioctl,進行讀、寫以外的其他操作。open,翻開設備準備進行I/O操作。返回0表示翻開成功,返回負數(shù)表示失敗。如果驅動程序沒有提供open入口,那么只要/dev/driver文件存在就認為翻開成功。release,即close操作。74structfile主要用于與文件系統(tǒng)相關的設備驅動程序,可提供關于被翻開的文件的信息,定義如下:structfile{structlist_head f_list;structdentry *f_dentry;structvfsmount*f_vfsmnt;structfile_operations *f_op;atomic_t f_count;unsignedint f_flags;mode_t f_mode;loff_t f_pos;unsignedlong f_reada,f_ramax,f_raend,f_ralen,f_rawin;structfown_struct f_owner;unsignedint f_uid,f_gid;int f_error;unsignedlong f_version
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 突破學習困境教育視角下的學生生涯規(guī)劃優(yōu)化策略
- 科技教育中的德育元素與素質教育
- 小學英語課《This is my home》教學設計與反思
- 個人股權委托代持合同
- 個人自建房質押貸款合同
- 臨時勞動合同安全免責約定
- 個人房產(chǎn)轉讓合同A
- 事業(yè)單位臨時工勞動合同
- 2025年城市公共交通燃油供應合同
- 上海銷售合同范本
- 屋面細石混凝土保護層施工方案及方法
- 2024年1月山西省高三年級適應性調研測試(一模)理科綜合試卷(含答案)
- 110kv各類型變壓器的計算單
- 雙減政策之下老師如何打造高效課堂
- 5A+Chapter+1+Changes+at+home+課件(新思維小學英語)
- 安徽省2023年中考數(shù)學試卷(附答案)
- 護工(陪護)培訓教材(完整版)資料
- 機械加工生產(chǎn)計劃排程表
- 女性生殖系統(tǒng)解剖與生理 生殖系統(tǒng)的血管淋巴和神經(jīng)
- 易制毒化學品安全管理制度匯編
- GB/T 35506-2017三氟乙酸乙酯(ETFA)
評論
0/150
提交評論