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