linux驅(qū)動(dòng)程序的編寫_第1頁
linux驅(qū)動(dòng)程序的編寫_第2頁
linux驅(qū)動(dòng)程序的編寫_第3頁
linux驅(qū)動(dòng)程序的編寫_第4頁
linux驅(qū)動(dòng)程序的編寫_第5頁
已閱讀5頁,還剩16頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

linux驅(qū)動(dòng)程序的編寫

底層(硬件層):需要你自己對(duì)于硬件相當(dāng)?shù)牧私?,能夠?dú)立繪制PCB并進(jìn)行焊接,之后調(diào)試板子,做好電路板。比如omap3530,你需要繪制至少四層PCB電路板,其中ARM核心板是最難掌握的部分,外圍電路要注意各種走線技巧等等。繪制完P(guān)CB之后就需要你的焊接功夫。將元器件焊接在PCB上。最后調(diào)試電路板,這是這一層設(shè)計(jì)中的收尾工作,也是最具有挑戰(zhàn)性的工作。調(diào)試電路需要大量的經(jīng)驗(yàn),對(duì)于初學(xué)者來說,需要很強(qiáng)的電路知識(shí),對(duì)于硬件的性能以及應(yīng)用要非常了解才行。

嵌入式系統(tǒng)組成:中間層(驅(qū)動(dòng)層):電路板已經(jīng)有現(xiàn)成的。你需要編程使一個(gè)死的板子,活起來,就是把程序下載進(jìn)去,能叫板子跑起來。這里需要你對(duì)于ARM芯片的結(jié)構(gòu)有很好的掌握,要會(huì)讀芯片資料(datasheet)通常都是英文的。了解其內(nèi)部資源我們就可以進(jìn)行驅(qū)動(dòng)編程了。我們平時(shí)所使用單片機(jī),一般都是寫好的程序,各個(gè)管腳在什么時(shí)序下輸出么信號(hào)(1或0),來操作實(shí)現(xiàn)相應(yīng)借口的外圍設(shè)備,比如液晶屏、LED燈等。單片機(jī)也可以叫做簡單的嵌入式。原理相同。ARM也可以向單片機(jī)一樣使用,但我們更多的是要對(duì)ARM加入操作系統(tǒng)的,這才是我們最常說的嵌入式。加入操作系統(tǒng)了以后,芯片對(duì)于個(gè)個(gè)資源的調(diào)度有了更系統(tǒng)的統(tǒng)籌規(guī)劃,可以更充分的利用ARM芯片的系統(tǒng)資源,提高性能,使資源合理分配。而通常的驅(qū)動(dòng)是在操作系統(tǒng)下工作的.比如基于LINUX或WINCE等等下的驅(qū)動(dòng)程序。驅(qū)動(dòng)程序是鏈接硬件平臺(tái)和操作系統(tǒng)的紐帶,當(dāng)然編寫驅(qū)動(dòng)要同時(shí)兼顧操作系統(tǒng)特點(diǎn)和硬件接口的特點(diǎn)。做驅(qū)動(dòng)的開發(fā),需要對(duì)于軟硬件都要有所了解,其中更偏重操作系統(tǒng)的理解。這部分工作也是最難做的。

嵌入式系統(tǒng)組成:上層(應(yīng)用層):應(yīng)用層,即我們所說的軟件編程了。就象我們手機(jī)里QQ和飛信一樣,我們需要根據(jù)我們手機(jī)的操作系統(tǒng)來編寫應(yīng)用程序。對(duì)于各個(gè)開發(fā)板,我們同樣需要根據(jù)它里邊的系統(tǒng)進(jìn)行應(yīng)用開發(fā)。這部分,應(yīng)該是幾乎脫離硬件了,我們只需簡單的了解硬件即可。我們只需深刻理解操作系統(tǒng)的中各個(gè)系統(tǒng)函數(shù)和接口函數(shù),即可進(jìn)行開發(fā)。需要很強(qiáng)的C++水平。嵌入式系統(tǒng)組成:嵌入式應(yīng)用對(duì)成本和實(shí)時(shí)性比較敏感,而對(duì)linux的應(yīng)用主要體現(xiàn)在對(duì)硬件的驅(qū)動(dòng)程序的編寫和上層應(yīng)用程序的開發(fā)上.嵌入式linux驅(qū)動(dòng)程序的基本結(jié)構(gòu)和標(biāo)準(zhǔn)Linux的結(jié)構(gòu)基本一致,也支持模塊化模式,所以,大部分驅(qū)動(dòng)程序編成模塊化形式,而且,要求可以在不同的體系結(jié)構(gòu)上安裝。linux是可以支持模塊化模式的,但由于嵌入式應(yīng)用是針對(duì)具體的應(yīng)用,所以,一般不采用該模式,而是把驅(qū)動(dòng)程序直接編譯進(jìn)內(nèi)核之中。但是這種模式是調(diào)試驅(qū)動(dòng)模塊的極佳方法。linux設(shè)備驅(qū)動(dòng)程序的功能

系統(tǒng)調(diào)用是操作系統(tǒng)內(nèi)核和應(yīng)用程序之間的接口,設(shè)備驅(qū)動(dòng)程序是操作系統(tǒng)內(nèi)核和機(jī)器硬件之間的接口。設(shè)備驅(qū)動(dòng)程序?yàn)閼?yīng)用程序屏蔽了硬件的細(xì)節(jié),這樣在應(yīng)用程序看來,硬件設(shè)備只是一個(gè)設(shè)備文件,應(yīng)用程序可以像操作普通文件一樣對(duì)硬件設(shè)備進(jìn)行操作。同時(shí),設(shè)備驅(qū)動(dòng)程序是內(nèi)核的一部分,它完成以下的功能:對(duì)設(shè)備初始化和釋放;把數(shù)據(jù)從內(nèi)核傳送到硬件和從硬件讀取數(shù)據(jù);讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)和回送應(yīng)用程序請求的數(shù)據(jù);檢測和處理設(shè)備出現(xiàn)的錯(cuò)誤。在linux操作系統(tǒng)下有字符設(shè)備和塊設(shè)備,網(wǎng)絡(luò)設(shè)備三類主要的設(shè)備文件類型。linux設(shè)備驅(qū)動(dòng)程序的功能

字符設(shè)備和塊設(shè)備的主要區(qū)別是:在對(duì)字符設(shè)備發(fā)出讀寫請求時(shí),實(shí)際的硬件I/O一般就緊接著發(fā)生了;塊設(shè)備利用一塊系統(tǒng)內(nèi)存作為緩沖區(qū),當(dāng)用戶進(jìn)程對(duì)設(shè)備請求滿足用戶要求時(shí),就返回請求的數(shù)據(jù)。塊設(shè)備是主要針對(duì)磁盤等慢速設(shè)備設(shè)計(jì)的,以免耗費(fèi)過多的CPU時(shí)間來等待。linux設(shè)備驅(qū)動(dòng)程序的功能

Linux字符設(shè)備驅(qū)動(dòng)的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)是cdev和file_operations結(jié)構(gòu)體。1)cdev結(jié)構(gòu)體在linux2.6內(nèi)核中,使用cdev結(jié)構(gòu)體描述一個(gè)字符設(shè)備,cdev結(jié)構(gòu)體的定義如下:struct

cdev{

struct

kobject

kobj;/*內(nèi)嵌的kobject對(duì)象*/

structmodule*owner;/*所屬模塊*/

struct

file_operations*ops;/*文件操作結(jié)構(gòu)體*/

struct

list_headlist;

dev_tdev;/*設(shè)備號(hào)*/unsignedintcount;};1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)cdev結(jié)構(gòu)體的dev_t成員定義了設(shè)備號(hào),為32位,其中12位主設(shè)備號(hào),20位次設(shè)備號(hào)。使用下列宏可以從dev_t獲得主設(shè)備號(hào)和次設(shè)備號(hào)。*dev_t這個(gè)不是structure,是簡單變量,只用于保存一組majornumber和minornumber.Linux提供一組mactor對(duì)其進(jìn)行讀寫:MAJOR(dev_tdev);//讀取設(shè)備的majornumberMINOR(dev_tdev);//讀取設(shè)備的minornumber1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)而使用下列宏則可以通過主設(shè)備號(hào)和次設(shè)備號(hào)生成dev_t;MKDEV(int

major,intminor);//從一組指定的majornumber和minornumber創(chuàng)建一個(gè)dev_tcdev結(jié)構(gòu)體的另一個(gè)重要成員file_operations定義了字符設(shè)備提供給文件系統(tǒng)的接口函數(shù)。

Linux2.6內(nèi)核提供了一組函數(shù)用于操作cdev結(jié)構(gòu)體:voidcdev_init(struct

cdev*,struct

file_operations*);struct

cdev*cdev_alloc(void);/*動(dòng)態(tài)申請一個(gè)cdev空間內(nèi)存*/voidcdev_put(struct

cdev*p);int

cdev_add(struct

cdev*,dev_t,unsigned);/*向系統(tǒng)添加、注冊一個(gè)cdev*/voidcdev_del(struct

cdev*);/*向系統(tǒng)注銷一個(gè)cdev*/1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)cdev_init()函數(shù)用于初始化cdev的成員,并建立cdev和file_operations之間的連接,其源代碼如下所示:voidcdev_init(struct

cdev*cdev,struct

file_operations*fops){memset(cdev,0,sizeof*cdev);

INIT_LIST_HEAD(&cdev->list);

kobject_init(&cdev->kobj,&ktype_cdev_default);

cdev->ops=fops;/*將傳入的文件操作結(jié)構(gòu)體指針賦值給cdev的ops*/}1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)cdev_alloc()函數(shù)用于動(dòng)態(tài)申請一個(gè)cdev內(nèi)存,其源代碼清單如下:struct

cdev*cdev_alloc(void){

struct

cdev*p=kzalloc(sizeof(struct

cdev),GFP_KERNEL);

if(p){

INIT_LIST_HEAD(&p->list);

kobject_init(&p->kobj,&ktype_cdev_dynamic); } returnp;}1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)cdev_add()函數(shù)和cdev_del()函數(shù)分別向系統(tǒng)添加和刪除一個(gè)cdev,完成字符設(shè)備的注冊和注銷。對(duì)cdev_add()的調(diào)用通常發(fā)生在字符設(shè)備驅(qū)動(dòng)模塊加載函數(shù)中,而對(duì)cdev_del()函數(shù)的調(diào)用通常發(fā)生在字符設(shè)備驅(qū)動(dòng)模塊卸載函數(shù)中。1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)2)分配和釋放設(shè)備號(hào)在調(diào)用cdev_add()函數(shù)向系統(tǒng)注冊字符設(shè)備之前,應(yīng)首先調(diào)用register_chrdev_region()或alloc_chrdev_region()函數(shù)向系統(tǒng)申請?jiān)O(shè)備號(hào),這兩個(gè)函數(shù)的原型為:int

register_chrdev_region(dev_t

from,unsigned

count,constchar*name);int

alloc_chrdev_region(dev_t*dev,unsigned

baseminor,unsigned

count,constchar*name);1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)register_chrdev_region()函數(shù)用于已知起始設(shè)備的設(shè)備號(hào)的情況,而alloc_chrdev_regione用于設(shè)備號(hào)未知,向系統(tǒng)動(dòng)態(tài)申請未被占用的設(shè)備號(hào)的情況,函數(shù)調(diào)用成功之后,會(huì)把得到的設(shè)備號(hào)放入第一個(gè)參數(shù)dev中。后者的優(yōu)點(diǎn)在于它會(huì)自動(dòng)避開設(shè)備號(hào)重復(fù)的沖突。相反地,在調(diào)用cdev_del()函數(shù)從系統(tǒng)注銷字符設(shè)備之后,unregister_chrdev_region()應(yīng)該被調(diào)用以釋放原先申請的設(shè)備號(hào),這個(gè)函數(shù)的原型為:voidunregister_chrdev_region(dev_t

from,unsignedcount);from:要分配設(shè)備編號(hào)范圍的起始值,經(jīng)常設(shè)置為0.count:所請求的連續(xù)設(shè)備編號(hào)的個(gè)數(shù)。Name:是和該設(shè)備范圍關(guān)聯(lián)的設(shè)備名稱,它將出現(xiàn)在/proc/devices和sysfs中。1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)3)file_operations結(jié)構(gòu)體file_operations結(jié)構(gòu)體中的成員函數(shù)是字符設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)的主體內(nèi)容,是這符設(shè)備驅(qū)動(dòng)與內(nèi)核的接口,是用戶空間對(duì)linux進(jìn)行系統(tǒng)調(diào)用的最終落實(shí)者。這些函數(shù)實(shí)際會(huì)在程序進(jìn)行l(wèi)inux的open()、write()、read()、close()等系統(tǒng)調(diào)用時(shí)最終被調(diào)用。字符設(shè)備驅(qū)動(dòng)程序中,具體實(shí)現(xiàn)這些函數(shù),通常,比如file_operation中的read這個(gè)函數(shù)指針將指向這個(gè)具體的驅(qū)動(dòng)程序中的函數(shù)xxx_read().

1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)通常,一個(gè)設(shè)備驅(qū)動(dòng)程序包括兩個(gè)基本的任務(wù):驅(qū)動(dòng)設(shè)備的某些函數(shù)作為系統(tǒng)調(diào)用執(zhí)行;而某些函數(shù)則負(fù)責(zé)處理中斷(即中斷處理函數(shù))。而file_operations

結(jié)構(gòu)的每一個(gè)成員的名稱都對(duì)應(yīng)著一個(gè)系統(tǒng)調(diào)用。用戶程序利用系統(tǒng)調(diào)用,比如在對(duì)一個(gè)設(shè)備文件進(jìn)行諸如read操作時(shí),這時(shí)對(duì)應(yīng)于該設(shè)備文件的驅(qū)動(dòng)程序就會(huì)執(zhí)行相關(guān)的ssize_t(*read)(structfile*,char*,size_t,loff_t*);函數(shù)。在操作系統(tǒng)內(nèi)部,外部設(shè)備的存取是通過一組固定入口點(diǎn)進(jìn)行的,這些入口點(diǎn)由每個(gè)外設(shè)的驅(qū)動(dòng)程序提供,由file_operations結(jié)構(gòu)向系統(tǒng)進(jìn)行說明,因此,編寫設(shè)備驅(qū)動(dòng)程序的主要工作就是編寫子函數(shù),并填充file_operations的各個(gè)域。file_operations結(jié)構(gòu)在kernel/include/linux/fs.h中可以找到。1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)struct

file_operations{

structmodule*owner;/*擁有該結(jié)構(gòu)的模塊的指針,一般為THIS_MODULES*/

loff_t(*llseek)(structfile*,loff_t,int);/*用來修改文件當(dāng)前的讀寫位置*/

ssize_t(*read)(structfile*,char*,size_t,loff_t*);/*從設(shè)備中同步讀取數(shù)據(jù)*/

ssize_t(*write)(structfile*,constchar*,size_t,loff_t*);/*向設(shè)備發(fā)送數(shù)據(jù)*/ssize_t(*aio_read)(structfile*,char*,size_t,loff_t*);/*初始化一個(gè)異步的讀取操作*/

ssize_t(*aio_write)(structfile*,constchar*,size_t,loff_t*);/*初始化一個(gè)異步的寫入操作*/

int(*readdir)(structfile*,void*,filldir_t);/*僅用于讀取目錄,對(duì)于設(shè)備文件,該字符為null*/ unsignedint(*poll)(structfile*,struct

poll_table_struct*);/*輪詢函數(shù),判斷目前是否可以進(jìn)行非阻塞的讀取或?qū)懭?/

int(*ioctl)(struct

inode*,structfile*,unsignedint,unsignedlong);/*執(zhí)行設(shè)備I/O的控制命令*/

int(*mmap)(structfile*,struct

vm_area_struct*);/*用于請求將設(shè)備內(nèi)存映射到進(jìn)程地址空間*/

int(*open)(struct

inode*,structfile*);/*打開*/

int(*flush)(structfile*);

int(*release)(struct

inode*,structfile*);/*關(guān)閉*/

int(*fsync)(structfile*,struct

dentry*,int

datasync);/*刷新待處理的數(shù)據(jù)*/

int(*fasync)(int,structfile*,int);/*通知設(shè)備FASYNC標(biāo)志發(fā)生變化*/

int(*lock)(structfile*,int,struct

file_lock*);

ssize_t(*readv)(structfile*,conststruct

iovec*,unsignedlong,loff_t*);

ssize_t(*writev)(structfile*,conststruct

iovec*,unsignedlong,loff_t*);

ssize_t(*sendpage)(structfile*,structpage*,int,size_t,loff_t*,int);/*通常為NULL*/ unsignedlong(*get_unmapped_area)(structfile*,unsignedlong,unsignedlong,unsignedlong,unsignedlong);#ifdefMAGIC_ROM_PTR

int(*romptr)(structfile*,struct

vm_area_struct*);#endif/*MAGIC_ROM_PTR*/};1字符設(shè)備驅(qū)動(dòng)結(jié)構(gòu)File_operations結(jié)構(gòu)中的成員全部是函數(shù)指針,所以實(shí)質(zhì)上就是函數(shù)的跳轉(zhuǎn)表。每個(gè)進(jìn)程對(duì)設(shè)備的操作,都會(huì)根據(jù)major、minor設(shè)備號(hào),轉(zhuǎn)換成對(duì)file_op

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論