Linux驅(qū)動(dòng)介紹和實(shí)例快速入門(mén)
一、驅(qū)動(dòng)簡(jiǎn)介
Linux的驅(qū)動(dòng)在本質(zhì)上就是一種軟件程序,上層軟件可以在不了解硬件特性的情況下,通過(guò)驅(qū)動(dòng)提供的接口,和計(jì)算機(jī)硬件進(jìn)行通信。
系統(tǒng)調(diào)用是內(nèi)核和應(yīng)用程序之間的接口,而驅(qū)動(dòng)程序是內(nèi)核和硬件之間的接口。它為應(yīng)用程序屏蔽了硬件的細(xì)節(jié),故對(duì)應(yīng)用程序而言,硬件設(shè)備只是一個(gè)設(shè)備文件,應(yīng)用程序可以像操作普通文件一樣對(duì)硬件設(shè)備進(jìn)行操作。
Linux驅(qū)動(dòng)程序只是內(nèi)核的一部分,管理著系統(tǒng)的設(shè)備控制器和相應(yīng)的設(shè)備。驅(qū)動(dòng)程序,英文名為"Device Driver",全稱(chēng)“設(shè)備驅(qū)動(dòng)程序”,是一種可以使計(jì)算機(jī)和設(shè)備通信的特殊程序,相當(dāng)于硬件的接口,操作系統(tǒng)只有通過(guò)這個(gè)接口才能控制硬件設(shè)備的工作。它主要完成以下幾個(gè)功能:
- 對(duì)設(shè)備初始化和釋放
- 傳送數(shù)據(jù)到硬盤(pán)和從硬件讀取數(shù)據(jù)
- 檢測(cè)和處理設(shè)備出現(xiàn)的錯(cuò)誤
二、驅(qū)動(dòng)分類(lèi)
計(jì)算機(jī)系統(tǒng)的硬件由CPU、存儲(chǔ)器、和外設(shè)組成。驅(qū)動(dòng)針對(duì)的對(duì)象都是存儲(chǔ)器和外設(shè)。Linux將外設(shè)和存儲(chǔ)器分為三個(gè)基礎(chǔ)大類(lèi):塊設(shè)備驅(qū)動(dòng),字符設(shè)備驅(qū)動(dòng)和網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)。
2.1、字符設(shè)備驅(qū)動(dòng)
字符設(shè)備是指那些必須以串行順序訪問(wèn)的設(shè)備,字符設(shè)備的I/O操作沒(méi)有通過(guò)緩存。字符設(shè)備的操作是以字節(jié)為基礎(chǔ)的,但一次只能執(zhí)行一個(gè)字節(jié)的操作。典型的如LCD、串口、LED、蜂鳴器、觸摸屏等等。
2.2、塊設(shè)備驅(qū)動(dòng)
塊設(shè)備是相對(duì)于字符設(shè)備定義的,可以以任意順序進(jìn)行訪問(wèn),以塊為單位進(jìn)行操作。塊設(shè)備驅(qū)動(dòng)的讀寫(xiě)都有緩存來(lái)支持,且塊設(shè)備必須能夠隨機(jī)存取。設(shè)備的塊大小是設(shè)備本身設(shè)計(jì)時(shí)定義好的,軟件是不能去更改的,不同設(shè)備的塊大小可以不一樣。常見(jiàn)的塊設(shè)備都是存儲(chǔ)類(lèi)設(shè)備,如:硬盤(pán)、NandFlash、iNand、SD等等。
2.3、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)
網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)是專(zhuān)為網(wǎng)卡設(shè)計(jì)的驅(qū)動(dòng)模型,面向數(shù)據(jù)包的接收和發(fā)送而設(shè)計(jì)的,它并不應(yīng)對(duì)于文件系統(tǒng)的節(jié)點(diǎn)。即不對(duì)應(yīng)于/dev目錄下的設(shè)備文件,應(yīng)用程序最終用套間字socket完成與網(wǎng)絡(luò)設(shè)備的接口。
除網(wǎng)絡(luò)設(shè)備外,字符設(shè)備和塊設(shè)備都被映射到Linux文件系統(tǒng)的文件和目錄,通過(guò)文件系統(tǒng)的系統(tǒng)調(diào)用接口open(),write(),read(),close()等即可訪問(wèn)字符設(shè)備和塊設(shè)備。塊設(shè)備比字符設(shè)備復(fù)雜,在它上面會(huì)首先建立一個(gè)磁盤(pán)/Flash文件系統(tǒng),如FAT、EXT3、TAFFS、TFFS等,F(xiàn)AT、EXT3、TAFFS、TFF規(guī)范了文件和目錄在存儲(chǔ)介質(zhì)上的組織。
三、驅(qū)動(dòng)的編譯和加載
Linux設(shè)備驅(qū)動(dòng)屬于內(nèi)核的一部分,Linux內(nèi)核的一個(gè)模塊可以以?xún)煞N方式被編譯和加載
3.1、編譯方式
內(nèi)部編譯:將驅(qū)動(dòng)程序源碼放在內(nèi)核源碼目錄中進(jìn)行編譯。
外部編譯:將驅(qū)動(dòng)程序源碼放在內(nèi)核源碼目錄外進(jìn)行編譯。
3.2、加載方式
靜態(tài)加載:編譯進(jìn)uImage中,系統(tǒng)啟動(dòng)時(shí)直接加載。
動(dòng)態(tài)加載:編譯.ko文件,動(dòng)態(tài)加載驅(qū)動(dòng)模塊。
3.3、編譯器
x86等架構(gòu)使用gcc即可,arm嵌入式設(shè)備需要使用相關(guān)交叉編譯工具鏈。
下面是內(nèi)核模塊的例子:
分析上述程序,發(fā)現(xiàn)一個(gè)Linux內(nèi)核模塊需包含模塊初始化和模塊卸載函數(shù),前者在insmod的時(shí)候運(yùn)行,后者在rmmod的時(shí)候運(yùn)行。初始化與卸載函數(shù)必須在宏module_init和module_exit使用前定義,否則會(huì)出現(xiàn)編譯錯(cuò)誤。
初始化與卸載函數(shù)必須在宏module_init和module_exit使用前定義,否則會(huì)出現(xiàn)編譯錯(cuò)誤。程序中的:
- MODULE_LICENSE(“GPL”)用于聲明模塊的許可證。
- MODULE_AUTHOR:說(shuō)明作者信息.。
- MODULE_DESCRIPTION:對(duì)本驅(qū)動(dòng)的描述。
如果要將其直接編譯入Linux內(nèi)核,則需要將源代碼文件拷貝入Linux內(nèi)核源代碼的相應(yīng)路徑里,并修改Makefile。
模塊初始化函數(shù)的任務(wù)是為以后調(diào)用模塊的函數(shù)做準(zhǔn)備,好像是模塊說(shuō),:" 我在這里, 這是我能做的”。
模塊的退出函數(shù)( 例子里是 hello_exit )就在模塊被卸載時(shí)調(diào)用.,它好像告訴內(nèi)核, "我不 再在那里了, 不要要求我做任何事了”。
這種編程的方法類(lèi)似于事件驅(qū)動(dòng)的編程, 但是雖然不是所有的應(yīng)用程序都是事件驅(qū)動(dòng)的, 每個(gè)內(nèi)核模塊都是。另外一個(gè)主要的不同, 在事件驅(qū)動(dòng)的應(yīng)用程序和內(nèi)核代碼之間, 是退出函數(shù): 一個(gè)終止的應(yīng)用程序可以在釋放資源方面 懶惰, 或者完全不做清理工作, 但是模塊的退出函數(shù)必須小心恢復(fù)每個(gè)由初始化函數(shù)建立的東西, 否則會(huì)保留一些東西直到系統(tǒng)重啟。
編寫(xiě)Makerfile文件來(lái)進(jìn)行編譯:
3.4、驅(qū)動(dòng)加載、卸載及debug