[ARM筆記]設(shè)備驅(qū)動概述
mknod命令建立一個目錄項和一個特殊文件的對應(yīng)索引節(jié)點。第一個參數(shù)Name項是設(shè)備的名稱,選擇一個描述性的設(shè)備名稱。
本文引用地址:http://butianyuan.cn/article/201611/340660.htmmknod命令有兩種形式,它們有不同的標(biāo)志。mknod命令的第一種形式只能由root用戶或系統(tǒng)組成員執(zhí)行。在第一種形式中,使用了b或c標(biāo)志。b標(biāo)志表示這個特殊文件是面向塊的設(shè)備(磁盤、軟盤或磁帶)。c標(biāo)志表示這個特殊文件是面向字符的設(shè)備(其他設(shè)備)。在 mknod 命令的第二種形式中,使用了p標(biāo)志來創(chuàng)建FIFO(已命名的管道)。
因此,標(biāo)志集合總共有三種選擇,如下:
* b 表示特殊文件是面向塊的設(shè)備(磁盤、軟盤或磁帶)。
* c 表示特殊文件是面向字符的設(shè)備(其他設(shè)備)。
* p 創(chuàng)建 FIFO(已命名的管道)。
在介紹創(chuàng)建設(shè)備文件時,主設(shè)備號和從設(shè)備號是不可或缺的。傳統(tǒng)方式中的設(shè)備管理中,除了設(shè)備類型外,內(nèi)核還需要一對主次設(shè)備號的參數(shù),才能唯一標(biāo)識一個設(shè)備。主設(shè)備號相同的設(shè)備使用相同的驅(qū)動程序,次設(shè)備號用于區(qū)分具體設(shè)備的實例。比如PC機中的IDE設(shè)備,一般主設(shè)備號使用3,WINDOWS下進(jìn)行的分區(qū),一般將主分區(qū)的次設(shè)備號為1,擴(kuò)展分區(qū)的次設(shè)備號為2、3、4,邏輯分區(qū)使用5、6…。
第一種形式的最后兩個參數(shù)便是指定主設(shè)備號和次設(shè)備號,它幫助操作系統(tǒng)查找設(shè)備驅(qū)動程序代碼,和指定具體的次設(shè)備。一個設(shè)備的主設(shè)備號和次設(shè)備號由該設(shè)備的配置方法分配。主設(shè)備號是由/usr/src/linux/include/linux/major.h定義的,如下定義了一個DOC設(shè)備:
#define IGEL_FLASH_MAJOR 62
如命令mknod doc b 62 0
其中的doc為定義的名字,b指塊設(shè)備,0指的是整個DOC。如果把0換為1,則1指的是DOC的第一個分區(qū)。2是第2個,依次類推。
mknod console c 5 1
console是設(shè)備的名字;c指字符設(shè)備,還可選b(塊設(shè)備);5是該設(shè)備在major.h中定義的標(biāo)記,主設(shè)備號/dev/devices里面記錄現(xiàn)有的設(shè)備,創(chuàng)建設(shè)備文件時,找個系統(tǒng)中還沒有用過的就可以了;1是指第一個子設(shè)備。當(dāng)你要給兩個同樣的設(shè)備加載驅(qū)動的時候就要用到這些區(qū)別了。
3. Linux驅(qū)動程序的加載和卸載
Linux內(nèi)核中采用可加載的模塊化設(shè)計,一般情況下編譯的Linux內(nèi)核是支持可插入式模塊的,也就是將最基本的核心代碼編譯在內(nèi)核中,其它的代碼可以選擇是在內(nèi)核中,或者編譯為內(nèi)核的模塊文件。如果需要某種功能,比如需要訪問一個NTFS分區(qū),就加載相應(yīng)的NTFS模塊。這種設(shè)計可以使內(nèi)核文件不至于太大,但是又可以支持很多的功能,必要時動態(tài)地加載。這是一種跟微內(nèi)核設(shè)計不太一樣,但卻是切實可行的內(nèi)核設(shè)計方案。
3.1 Linux驅(qū)動的加載方式
由于Linux系統(tǒng)內(nèi)核有如上的特點,所以設(shè)備驅(qū)動程序也秉承了這種特性。常見的驅(qū)動程序就是作為內(nèi)核模塊動態(tài)加載的,比如聲卡驅(qū)動和網(wǎng)卡驅(qū)動等。而Linux最基礎(chǔ)的驅(qū)動,如CPU、PCI總線、TCP/IP協(xié)議、VFS等驅(qū)動程序則編譯在內(nèi)核文件中。因此,Linux驅(qū)動的加載可分為靜態(tài)加載和動態(tài)加載兩種不同的方式。
* 靜態(tài)加載:系統(tǒng)啟動時自動加載驅(qū)動到內(nèi)核,自動的注冊設(shè)備并創(chuàng)建設(shè)備接點,也就是說把驅(qū)動程序直接編譯到內(nèi)核,系統(tǒng)啟動后應(yīng)用程序可以直接運行、調(diào)用。靜態(tài)加載的缺點是調(diào)試起來比較麻煩,每次修改一個地方都要重新編譯下載內(nèi)核,效率較低。
* 動態(tài)加載:即模塊加載,系統(tǒng)啟動時不會進(jìn)行加載驅(qū)動程序,需要人為手動加載,就是說系統(tǒng)啟動后我們的應(yīng)用程序不能直接應(yīng)用驅(qū)動,而是我們必須手動的用insmod命令去加載模塊,然后才能使用相應(yīng)的設(shè)備和應(yīng)用,在不需要的時候用rmmod命令來卸載。
其中動態(tài)加載我們又可以分為三種去研究:
加載驅(qū)動后,我們自己去創(chuàng)建主設(shè)備號,從設(shè)備號,利用cat /proc/devices 去查看主設(shè)備號是否重復(fù),然后根據(jù)應(yīng)用程序中使用的設(shè)備名稱用mknod命令去創(chuàng)建設(shè)備文件接點。
加載驅(qū)動后,驅(qū)動程序會利用register_chrdev()函數(shù)自動產(chǎn)生主設(shè)備號去在內(nèi)核中注冊設(shè)備,我們利用cat /proc/devices命令和驅(qū)動程序中注冊的設(shè)備名去查詢主設(shè)備號和從設(shè)備號后,在根據(jù)應(yīng)用程序使用的設(shè)備名,去利用mknod去創(chuàng)建。(利用驅(qū)動中注冊的設(shè)備名是查詢自動生成的主設(shè)備號,驅(qū)動中的設(shè)備名稱不一定要和創(chuàng)建的設(shè)備接點名相同,他們之間可以用主設(shè)備號去關(guān)聯(lián),而應(yīng)用程序的設(shè)備名稱則必須和創(chuàng)建的設(shè)備接點名相同)。
加載驅(qū)動后,驅(qū)動程序利用devfs系統(tǒng),這個系統(tǒng)可以自動的產(chǎn)生主設(shè)備號,然后自動的創(chuàng)建設(shè)備接點。我們只要加載驅(qū)動后,直接運行應(yīng)用程序就行了。
一般嵌入式驅(qū)動開發(fā)者會先用動態(tài)加載的方式來調(diào)試,調(diào)試完畢后再編譯到內(nèi)核里。下面我們將向讀者介紹下如何使用insmod動態(tài)加載模塊。
3.2 Linux驅(qū)動加載和卸載
當(dāng)我們編寫好需要加載的模塊、創(chuàng)建了其在內(nèi)核的設(shè)備掛載節(jié)點之后,下一步要進(jìn)行的操作就是將該設(shè)備模塊加載到內(nèi)核,也就是把編譯后的驅(qū)動程序的.ko文件加載到內(nèi)核。這個工作將由insmod完成。這個程序?qū)⒓虞d模塊的代碼段和數(shù)據(jù)段到內(nèi)核,接著,執(zhí)行一個類似ld的函數(shù),它連接模塊中任何未解決的符號連接到內(nèi)核的符號表上。
insmod接收許多命令行選項,它能夠在連接到當(dāng)前內(nèi)核之前,為模塊中的參數(shù)賦值,加載時配置比編譯時配置給了用戶更多的靈活性,感興趣的讀者可以查閱相關(guān)的資料。一般常用的命令方式為:
#insmod /路徑 模塊編譯后生成文件.ko
模塊可以用rmmod工具從內(nèi)核去除。需要注意的是,如果內(nèi)核認(rèn)為模塊還在用,或者內(nèi)核被配置成不允許模塊去除,模塊去除會失敗。除了上述兩種命令,還有一些相關(guān)的命令,在模塊加載時可以用到。如下所示:
lsmod:列出當(dāng)前系統(tǒng)中加載的模塊,其中顯示信息中分為三列,依次是:模塊名、模塊大小、模塊使用的數(shù)量。
modprobe:使用modprobe命令,可以智能插入模塊,它可以根據(jù)模塊間的依存關(guān)系,以及/etc/modules.conf文件中的內(nèi)容智能插入模塊。
insmod:也是插入模塊的命令,但是它不會自動解決依存關(guān)系。
modinfo:用來查看模塊信息。
4. 學(xué)習(xí)Linux驅(qū)動程序的基礎(chǔ)及方法
Linux設(shè)備驅(qū)動的學(xué)習(xí)是一項浩大的工程,讀者需要一定的基礎(chǔ)。在前面,我們專門講到過驅(qū)動程序是連接硬件設(shè)備和操作系統(tǒng)的橋梁。
因此,驅(qū)動的開發(fā)不僅要有良好的硬件基礎(chǔ),懂得SRAM、Flash、SDRAM、磁盤的讀寫方式,UART、I2C、USB等設(shè)備的接口,輪詢、中斷、DMA的原理,PCI總線的工作方式以及CPU的內(nèi)存管理單元(MMU)等硬件處理的方式;還需要對Linux內(nèi)核有一定的了解,雖然并不要求工程師對內(nèi)核各個部分有深入的研究,但至少要了解設(shè)備驅(qū)動與內(nèi)核的接口,尤其是對于塊設(shè)備、網(wǎng)絡(luò)設(shè)備、Flash設(shè)備、串口設(shè)備等復(fù)雜設(shè)備的驅(qū)動框架等。
另外,在應(yīng)用中很有可能多個程序訪問同一個設(shè)備,這也就需要具有良好的多任務(wù)并發(fā)控制和同步的基礎(chǔ)。動手實踐永遠(yuǎn)是學(xué)習(xí)任何軟件開發(fā)的最好方法,學(xué)習(xí)Linux設(shè)備驅(qū)動也不例外。
一般來說,編寫一個Linux設(shè)備驅(qū)動程序的大致流程如下:
(1)查看原理圖、數(shù)據(jù)手冊,了解設(shè)備的操作方法。
(2)在內(nèi)核中找到相近的驅(qū)動程序,以它為模板進(jìn)行開發(fā),有時候需要從零開始。
(3)實現(xiàn)驅(qū)動程序的初始化:比如向內(nèi)核注冊這個驅(qū)動程序,這樣應(yīng)用程序傳入文件名時,內(nèi)核才能找到相應(yīng)的驅(qū)動程序。
(4)設(shè)計所要實現(xiàn)的操作,比如:open、close、read、write等函數(shù)。
(5)實現(xiàn)中斷函數(shù)(中斷并不是每個設(shè)備驅(qū)動所必需的)。
(6)編譯該驅(qū)動程序到內(nèi)核中,或者用insmod命令加載。
(7)測試驅(qū)動程序。
評論