歡迎您光臨本站 註冊首頁

升級Linux硬體驅動結構

←手機掃碼閱讀     火星人 @ 2014-03-26 , reply:0

硬體驅動程序是界於硬體和Linux內核之間的軟體介面,是一種低級的、專用於某一硬體的軟體組件。這種軟體組件可以使硬體與更普遍的高級應用程序介面產生互動。為某一具體的子系統或硬體埠(例如SCSI、USB或PCMCIA)提供支持,不同於為所有SCSI、USB或PCMCIA硬體設備提供支持。由於新的硬體每天都在產生,因此測試每一個可能用於某一具體子系統的硬體是不可能的。內核只為具體的一些子系統提供支持,硬體驅動程序也只是為使用這些子系統具體的某些硬體提供支持。新內核保持高級應用程序介面與低級硬體功能的分離。用戶可以通過編寫合適的硬體驅動程序或修改內核,更容易地為現有系統增加對新硬體的支持。

Linux硬體驅動可以通過兩種方式集成到內核中:一是將其直接編譯進行內核從而一勞永逸;二是將其編寫成一種目標格式,在需要添加某種硬體時,內核可以將其調入。當用戶對Linux內核進行設置時,每個內核設置編譯器都可顯示各個可用內核設置變數的描述信息,從而使用戶決定哪個變數要被消除,哪個需要寫入內核,還有哪個可以編寫成一種可載入內核模塊。

直接將硬體驅動程序寫入內核優點在於,用戶可以隨時對它進行調用而無需安裝。但是這樣大大增加內核佔用的空間。將硬體驅動程序編寫成一種可載入的內核模塊,雖然會因為尋找驅動模塊而增加系統資源的佔用和運行時間,但是與龐大的內核所消耗的資源相比顯得微不足道。將硬體驅動程序編寫成一種可載入的內核模塊,還可為軟體開發提供許多便利。當用戶需要對某一硬體驅動程序進行開發或糾錯時,用戶可以動態地卸載舊的版本並載入新的版本,但是如果用戶的驅動程序已寫入內核,那麼必須對內核進行重新編寫,並且每次對修改後的程序進行測試時,都必須重新啟動系統。另外,將硬體驅動程序視為可載入的內核模塊進行開發和配置,這樣用戶就可以將硬體驅動程序作為一種獨立的系統進行升級,而不必對內核進行改動了。

用戶要做的只是編譯並安裝可載入內核模塊,其它的工作由模塊自已來完成。當系統首次訪問某一硬體設備時,只要存在使用「depmod」命令建立的模塊從屬關係樹,與之對應的模塊就可以自動載入。可載入內核模塊通常情況下安裝在系統/lib/modules目錄的一個子目錄下。該子目錄的名稱由建立內核的Makefile中的VERSION、PATCHLEVEL、SUBLEVEL和EXTRAVERSION等變數的值決定。

Linux 2.6內核為硬體驅動程序帶來一個新的、統一的框架。用戶對原本運行於舊版本內核下的硬體驅動程序進行定製。新驅動程序框架通過定義各種介面,為硬體的即插即用和電源管理提供全面支持。子系統可以通過這些介面與各個驅動程序進行通信。新驅動程序框架更加明確了匯流排和驅動程序之間的責任界限。Linux 2.6內核還引入了sysfs文件系統為每個系統的硬體樹進行分級處理。Linux 2.6內核還對可載入內核模塊規定了新的命名方法,使用的是.ko擴展名,而不是舊版本標準的.o (object)擴展名。

這裡將重點闡述2.6內核下的硬體驅動程序與以往內核下的硬體驅動程序在主體結構上的不同之處。

升級硬體驅動程序的基本結構

Linux 2.4內核下的硬體驅動標準模板如下:

#define MODULE
#include linux/module.h>
#include linux/config.h>
#include linux/init.h>
static int __init name_of_initialization_routine(void) {
/*
* code here
*/
}
static void __exit name_of_cleanup_routine(void) {
/*
* code here
*/
}
module_init(name_of_initialization_routine);
module_exit(name_of_cleanup_routine);
舊版本內核下的硬體驅動程序有一個普遍的問題,就是對初始化模塊和清除功能的名稱進行假設。當開發人員編寫舊版本內核下的硬體驅動程序時,如果使用預設的名稱init_module()和cleanup_module(),那麼就不需要對初始化模塊和清除功能的名稱進行記錄。這種方法經常會出現錯誤,已逐漸被淘汰。在2.6內核下,用戶必須使用module_init()宏和module_exit()宏對初始化和退出規程的名稱進行記錄。

另外,在2.6內核下,用戶無論是在源代碼中還是在Makefile文件中都不再需要對#define MODULE進行描述。內核搭建系統會自動對此類符號進行定義並校驗。當用戶為2.6內核編寫硬體驅動程序時,必然會用到此類搭建系統。

要想對已有的模塊進行編譯,並使之載入到2.6內核,必須首先完成一些基本的結構變化。然而,當用戶利用此類結構載入模塊時,會注意到在標準輸出設備和系統日誌上會顯示一個壞模塊的出錯信息。為了消除這條信息,用戶需要為MODULE_LICENSE()宏增加一個示例,例如MODULE_LICENSE("GPL")。這種2.4內核以後的版本才引入的宏,可以將模塊定義為獲得GPL Version 2或更新版本許可的模塊。其它有效的值還有"GPL v2"、"GPL and additional rights"、"Dual BSD/GPL"(選擇BSD或GPL許可)、"Dual MPL/GPL"(選擇Mozilla 或GPL許可)和"Proprietary"。

2.6內核下硬體驅動程序最簡單的類屬模板如下:

#include img src="/files/misc/lt.gif">linux/module.h>
#include img src="/files/misc/lt.gif">linux/config.h>
#include img src="/files/misc/lt.gif">linux/init.h>
MODULE_LICENSE("GPL");
static int __init name_of_initialization_routine(void) {
/* code goes here */
return 0;
}
static void __exit name_of_cleanup_routine(void) {
/* code goes here */
}
module_init(name_of_initialization_routine);
module_exit(name_of_cleanup_routine);



除了硬體驅動自身所需要的變化外,在Linux 2.6內核下,與之相應的最重要的變化是在內核搭建過程中完成的。

模塊搭建過程中的變化

對於所有開發可載入硬體驅動程序的人來說,對他們影響較大的一個基本變化不是源於內核源代碼,而是將外部模塊編譯過程整合為標準的內核搭建機制。如果用戶使用的不是集成開發環境(例如TimeSys公司的TimeStorm,它可以檢測內核版本並自動建立Makefile),那麼用戶需要手工為硬體驅動程序建立Makefile。

在2.4和更舊版本的內核下,模塊的開發和編譯位置不受限制,只要將適當的編譯標記移到命令行或模塊的Makefile中就可以了。這些標記包括兩個編譯模塊時必須的符號定義和一個指針。該指針指向包含有內核所含文件的目錄。以下面的語句為例,用戶可以建立一個名為testmod.o的可載入內核模塊:
#gcc -D__KERNEL__ -DMODULE -I/usr/src/linux-2.4.21/include -O2 -c testmod.c

為2.6內核搭建模塊的過程比較簡單,但是要想滿足所有成功編譯所需要的條件就不那麼容易。用戶既不需要手工指定以模塊為導向的說明(例如MODULE, __KERNEL__等),也不必指定新的符號(如KBUILD_BASENAME和KBUILD_MODNAME等),只要對外部模塊植入標準內核搭建系統的過程進行整合就可以了。用戶也不必指定諸如-O2之類的選項,因為用戶編譯的模塊與其它可載入內核模塊一樣,進程會自動調用所有的強制性標誌。至於Makefile的編寫就簡單得多了,例如為testmod.ko模塊編寫的可與2.6內核兼容的Makefile如下所示:
obj-m := testmod.o。

然而,為了建立外部模塊,用戶必須先完成內核源代碼樹介面的編寫。這樣可以建立一些臨時目錄以供編譯時使用。下面是一個為2.6內核構建模塊的命令行。它可以從包含模塊源代碼目錄下執行:
# make -C /usr/src/linux-2.6.1 SUBDIRS=$PWD modules

此示例命令假設用戶的模塊源代碼和Makefile所在的目錄與用戶正在運行的命令中的相同。如果用戶不使用POSIX命令(例如BASH),那麼可以通過「SUBDIRS=`pwd`」命令,用$PWD變數代替SUBDIRS參數。這樣用戶就可以使用「pwd」命令識別工作目錄。建立出口的命令如下所示:

#make: Entering directory `/usr/src/linux-2.6.1´
*** Warning: Overriding SUBDIRS on the command line can cause
*** inconsistencies
make[1]: `arch/i386/kernel/asm-offsets.s´ is up to date.
Building modules, stage 2.
MODPOST
CC /home/wvh/timesys/2.6/testmod/testmod.mod.o
LD [M] /home/wvh/timesys/2.6/testmod/testmod.ko
#make: Leaving directory `/usr/src/linux-2.6.1´



"make"命令的成功完成將產生testmod.ko模塊。對該模塊的命名使用的是新的內核模塊命名規則。如果用戶已經對系統的啟動程序進行了修改,以便通過名稱清楚地載入模塊,那麼用戶需要確定在升級到2.6內核后,這些模塊的命名是否遵循了新的命名規則。

適應2.6內核的內部變化

Linux 2.6內核還帶來了許多內部變化,用戶需要改變已有的驅動程序以適應這種變化。這些變化包括內核的非同步I/O機理、DMA支持層、存儲器與頁分配機理、數據塊硬體驅動程序和新的類屬硬碟介面等。例如,用來分配並管理存儲器與頁的功能就發生了新的變化。在2.6內核下,系統使用了一種名叫mempool的標準介面。對模塊參考計數的使用和管理也發生了變化。模塊參考計數主要用於決定一個模塊是否正在使用,並對沒有被使用的模塊進行安全卸載。在2.6內核下,命令序列已被工作序列所代替,其中,對大量不同驅動程序產生影響的一個重要變化是參數模塊的新介面。MODULE_PARM()宏已由詳細的參數說明所代替。這種說明來源於新的module_param()宏。

Linux 2.6內核的優先能力和對SMP的識別能力,為驅動程序編寫人員帶來一些新問題。在單處理機系統中,在無優先能力的Linux內核下,一些驅動程序可以假設在兩個處理器間不必再提供重入介面,因為它們無法同時運行驅動程序。驅動程序可以使用「spinlock」或「mutex」命令來保護那些可從多進程訪問的數據。這些問題的考慮對於為嵌入式環境(如TimeSys Linux)編寫高性能和實時硬體驅動程序的人來說尤為重要。

其它考慮因素

如果用戶較為依賴Linux 2.6內核的工作,那麼還需要對驅動程序做一些其它的改動。例如,儘管自從2.3內核誕生后,devfs文件系統已經被寫入內核,並且在2.6內核設置中被標註為捨棄指令,但是它卻經常在一些特殊領域中使用。例如在嵌入式計算中, devfs可提供較強的靈活性和一個緊縮的/dev文件名。devfs文件系統是介於hardcoded硬體節點間的中間步驟。此類節點主要用於早期的Linux和Unix系統中。同時,它還是udev、hotplug和sysfs文件系統的綜合。對udev的支持技術目前正在被寫入Linux 2.6內核。TimeSys公司已經開發出了擁有此類技術的商業Linux系統。如果用戶正在使用其它的Linux發行版,那麼用戶也許會發現devfs支持和集成技術對於驅動程序來說十分重要。

如果用戶想使用devfs文件系統,那麼必須首先在搭建內核時激活對它的支持。這一步可以在內核設置編輯程序的File systems→Pseudo filesystems中完成。使用devfs還需要改變硬體驅動程序對硬體節點的識別方法。當用戶使用傳統的/dev目錄作為Linux硬體描述符文件的放置位置時,硬體驅動程序通過啟動register_blkdev() 或register_chrdev()函數來註冊新硬體。具體使用哪一個,要看驅動程序註冊的是一個數據塊硬體還是字元硬體,而且必須事先知道硬體的主號碼和次號碼。另外,因為udev是一個可熱插拔程序,它可以自動建立並刪除/dev目錄下的登錄項,所以這一方法同樣也適用於新的udev硬體機理。

使用devfs硬體文件系統時,硬體驅動程序必須使用devfs_register()系統呼叫來註冊它們的硬體。驅動程序可以繼續使用此前指定的主次編碼,也可通過為devfs_register()呼叫指定DEVFS_FL_AUTO_DEVNUM 標誌,由devfs自動指定編碼。

小結

用戶常常由於提高系統性能、增加系統功能、實現系統單一化和標準化等原因對內核進行修改。每一個新版本Linux內核都會帶來許多新的變化,這些變化在不同層次上對開發人員有很大的影響。本文概括了在2.6內核下硬體驅動程序的變化及模塊搭建過程的變化。諸如TimeStorm之類的工具可以為用戶提供升級驅動程序的模板,並可自動為可載入內核模塊建立並管理Makefile。然而,如果用戶正在手工維護現有的硬體驅動程序或開發新的硬體驅動程序,那麼用戶將需要認真的考慮2.6內核的變化,做出正確的選擇。

[火星人 ] 升級Linux硬體驅動結構已經有493次圍觀

http://coctec.com/docs/linux/show-post-190716.html