設置測試系統開發環境及Hello World入門模塊在前面中已經講到,請參考:http://www.linuxidc.com/Linux/2012-04/58409.htm
一,核心模塊與應用程序的對比
應用程序:小規模及中規模程序,從頭到尾執行單個任務。
核心模塊:預先注冊自己,以便服務於將來的某個請求。然後他的初始化函數就立即結束。
退出時候,應用程序可以不釋放自己申請的資源,而模塊在退出之前必須仔細撤銷初始化函數所做的一切。
二,用戶空間和內核空間
模塊運行在內核空間,應用程序運行在內核空間。
每當應用程序執行系統調用或者被硬件中斷掛起時,Unix將執行模式從用戶空間切換到內核空間。
應用程序在虛擬內存中布局,並具有一塊很大的棧空間(保存函數調用歷史以及當前活動函數中的自動變量)。內核具有非常小的棧,所以我們自己的函數必須和整個內核空間調用鏈一同共享這個棧。
【注意】在內核API中看到有兩個下劃線_ _的函數名:接口的底層組件
三,初始化和關閉
static int _ _init initialization_function(void)
{
/*初始化代碼*/
return <int>;
}
module_init(initialization_function); //說明內核初始化位置,沒有這個函數,則初始化函數無法調用
【注意】_ _init _ _initdata表明函數只在初始化期間使用,模塊裝載完成後不再使用。
static void _ _init cleanup_function(void)//沒有返回值
清除函數 類似 module_exit(cleanup_function)
四,初始化過程中的錯誤處理
1)時刻銘記,注冊可能會失敗,因此模塊代碼要始終檢查返回值。
2)當注冊時,有些模塊注冊失敗,則需要自行撤銷已注冊的設施。否則內核處於一種不穩定狀態。唯一有效的解決辦法:重新引導系統
3)使用goto
int _ _my_init_function(void)
{
int err;
err=regeister_this(ptr1,"skull");
if(err) goto fail_this;
err=regeister_that(ptr2,"skull");
if(err) goto fail_that;
err=regeister_those(ptr3,"skull");
if(err) goto fail_those;
return 0;//成功
fail_this:return err;
fail_those:unregeister_those(ptr3,"skull");
fail_that:unregeister_that(ptr3,"skull");
}
4)初始化函數還在運行時,內核就完全可能會調用我們的模塊。所以我們應在用來支持某個設施的所有內部初始化完成之前,不要注冊任何設施。
五,模塊參數支持很多類型;
1)基本類型:
bool :布爾類型
invbool:顛倒了值的bool類型;
charp :字符指針類型,內存為用戶提供的字符串分配;
int :整型
long :長整型
short :短整型
uint :無符號整型
ulong :無符號長整型
ushort :無符號短整型
定義模塊參數的方法:
module_param(name, type, perm);
其中,name:表示參數的名字;
type:表示參數的類型;
perm:表示參數的訪問權限;
2)數組類型:用逗號間隔的列表提供的值;
聲明一個數組參數:
module_param_array(name, type, num, perm);
其中,name:表示數組的名字;
type:表示參數的類型;
num :表示數組中元素數量;
perm:表示參數的訪問權限;
3)參數的訪問權限
modlue_param和module_param_array中的perm用於設定該參數的訪問權限;
perm表示該參數在sysfs文件系統中所對應的文件節點的屬性;你用該使用<linux/stat.h>中定義的權限值;這個值控制誰可以存取這些模塊參數在sysfs文件系統中的表示;當perm為0時,表示此參數不存在sysfs文件系統下對應的文件節點;否則,模塊被加載後,在/sys/module/目錄下將會出現以此模塊名命名的目錄,帶有給定的權限;
比如:
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
注意:如果一個參數被sysfs修改了,那麼你的模塊看到的參數值也被修改了,但是你的模塊不會收到任何通知;你應當不要使模塊參數可寫,除非你准備好檢測這個改變並因而作出反應;
六,在用戶空間編寫驅動程序
用戶空間驅動程序的優點:
1)可以和整個C庫鏈接
2)驅動程序不用借助外部程序(對於復雜的外設,常常需要和驅動一起發行用戶提供策略的應用程序)就可以完成許多非常規的任務。
3)在驅動中可以使用浮點數,在某些特殊的硬件中,可能需要使用浮點數,而linux內核並不提供浮點數的支持。如果能在用戶態實現驅動,就可以輕松解決這一問題
4) 驅動的問題不會導致整個系統掛起,有過驅動開發經驗的人一定會對調試深有感觸,一些錯誤常常導致整個系統掛起。而用戶態的驅動在調試上就要方便很多。
5) 用戶內存可以換出
6)設計良好的驅動仍然可以支持對設備的並發訪問
7)可以給出封閉源碼的驅動程序,不必采用GPL,更為靈活
用戶空間驅動的最常見例子是X-server,很多USB設備的驅動也可以放到用戶空間。目前,很多人嘗試在用戶態為PCI設備提供驅動
用戶空間驅動的缺點:
1)中斷在用戶空間不可用,最新的UIO接口已經解決了這一問題
2)響應時間較慢
3)只能支持字符設備,無法支持塊設備和網絡設備
4)可靠性較低,很多驅動都是閉源的,我們沒法通過閱讀代碼解決問題
5)有些硬件廠商只提供和某些linux開發版(常常早就過時了)相匹配的用戶空間驅動
相關閱讀:
【Linux 驅動】第一章 設備驅動程序簡介 http://www.linuxidc.com/Linux/2012-04/58410.htm
【Linux 驅動】驅動開發第一步----開發環境搭配 http://www.linuxidc.com/Linux/2012-04/58409.htm