《1》 module_init ( xxx ) 模塊在裝載到內核時調用,module_exit( xxx ) 模塊在被移除時調用。
《2》 內核API中看到具有兩個下劃線的前綴(__)的函數名稱,具有這種名稱的函數通常是接口的底層組件,應謹慎使用。
《3》 在構造內核模塊之前,應確保具備了正確版本的編譯器,模塊工具和其他必要的工具。內核文檔目錄中的Documentation/Changes文件列出了需要的工具版本。
《4》 modprobe也用來將模塊裝入到內核中。它和insmod的區別在於,它會考慮要裝載是否引用了一些當前內核不存在的符號。如果有這類引用,modprobe會在當前模塊搜索路徑中查找定義了這些符號的其他模塊。如果modprobe找到了這些模塊(即要裝載的模塊所依賴的模塊),它會同時將這些模塊裝載到內核。在加載模塊失敗的時候,可以通過查看/var/log/messages或者系統配置使用的文件。
《5》 針對內核版本的查看,在linux/version.h中相關的定義,這個頭文件自動包含於linux/module.h,並定義了下面的宏:
UTS_RELEASE
宏UTS_RELEASE擴展至爲一個描述內核版本的字符串,例如 “2.6.10”。
LINUX_VERSION_CODE
宏LINUX_VERSION_CODE擴展爲內核版本的二進制表示,版本發行號中的每一部分對應一個字節。例如,2.6.10對應的LINUX_VERSION_CODE是132618(即0x02060a)。使用這個宏,我們很容易確定正在使用的內核版本.
KERNEL_VERSION(major , minor , release)
宏KERNEL_VERSION以組成版本號的三部分(三個整數)爲參數,創建整數的版本號。例如, KERNEL_VERSION(2 ,6 ,10)擴展爲132618.這個宏在我們需要將當前版本和一個已知的檢查點比較時非常有用。
《6》 如果一個每模塊需要向其他模塊導出符號,則應該使用下面的宏。EXPORT_SYMBOL(name) ; EXPORT_SYMBOL_GPL(name) ; _GPL版本使得要導出的模塊只能被GPL許可證下的模塊使用。
《7》 所有模塊代碼都需要包含這兩行代碼:
#include <linux/module.h> 包含有可裝載模塊需要的大量符號和函數定義。
#include <linux/init.h> 包含init.h的目的是指定初始化和清除函數。
大部分模塊還包括moduleparam.h頭文件,這樣可以在裝載模塊時向模塊傳遞參數。
《8》 雖然不是嚴格要求模塊代碼使用許可證,但還是需要考慮使用的,例如:MODULE_LECENSE(" GPL") ; 內核可以識別的許可證有“GPL”(任一版本的GNU通用公關許可證),“GPL v2”(GPL版本2), “GPL and additional rights ”(GPL及附加權利) “,” Dual BSD/GPL (GPL雙重許可證)“,”Dual MPL/GPL(MPL/GPL雙重許可證)“ 以及 ”Proprietary(專有)的“,沒有顯示標記爲上述可識別許可證,則會被假定是專有的,而內核轉載這種內核就會被"污染"。
《9》 模塊中可以包含的其他描述性定義包括MODULE_AUTHOR(描述模塊作者),MODULE_DESCRIPTION(用來說明模塊用途的簡短描述),MODULE_VERSION(代碼修訂號;有關版本字符串的創建慣例,參考<linux/module.h>中的註釋),MODULE_ALIAS(模塊的別名)以及MODULE_DEVICE_TABLE(告訴用戶空間模塊所支持的設備)。
《10》模塊初始化函數通常如下:
/*__=2個_*/
static int __init initialization_function(void) _ _ init 給內核暗示,在模塊被裝載之後,模塊裝載器就會將初始化函數扔掉,釋放內存。
{
/* 初始化代碼*/
}
module_init(initialization_function) ;
static void __exit cleanup_function(void)
{
/* 這裏是清除代碼*/
}
module_exit(cleanup_function); //幫助內核找到模塊的清除函數是必須的
清除函數沒有返回值, _ _exit 修飾詞標記該代碼僅用於模塊卸載, 這樣的模塊只能在卸載或者關閉時被調用,其他的任何用法都是錯誤的。
《11》當我們在內核中註冊設施時,要時刻銘記註冊可能會失敗,當註冊失敗的時候,我們要撤銷之前的任何註冊工作。
示例:
int __init my_init_function (void)
{
int err;
err = register_this(ptr1 , "skull");
if(err) goto fail_this;
err = register_that(ptr2 , "skull");
if(err) goto fail_that;
err = register_those(ptr3 , "skull");
if(err) goto fail_those;
return 0 ; /*success*/
fail_those: unregister_that(ptr2 , "skull");
fail_that : unregister_this(ptr1 , "skull");
fail_this : return err;
}
不支持goto的使用的人,就是記錄任何成功註冊的措施,然後再出錯的時候調用模塊清除函數。
顯然,清除函數需要撤銷初始化函數所註冊的所有設施,並且在習慣上(但不是必須的),以相反於註冊的順序撤銷設施:
void __exit my_cleanup_function(void)
{
unregister_those(ptr3 , “skull”);
unregister_that(ptr2 , “skull”);
unregister_this(ptr1, skull);
return ;
}
《12》可以再insmod 或 modprobe 命令加載模塊的時候傳人蔘數,參數必須使用module_param宏來聲明,這個宏在moduleparam.h中定義。這個宏必須是放在任何函數之外, 通常是源文件的頭部。
主體的部分就是: static char *whom = “world” ;
static int howmany = 1 ;
module_param (howmany , int , S_IRUGO) ;
module_param (whom , charp , S_IRUGO) ;
使用的命令比如: insmod hellop howmany=10 whom=“Mom”
內核所能支持的模塊參數類型如下:
bool
invbool /* 布爾值(取true 或 false ), 關聯的變量應該是 int 型。 invbool 類型反轉其值, 也就是說, true 值變成 false ,而false 變成 true 。*/
charp /*字符指針值。內核會爲用戶提供的字符串分配內存, 並相應設置指針。*/
int long short uint ulong ushort 具有不同長度的基本整數值。以u開頭的類型用於無符號值。
模塊裝載器也支持數組參數, 要聲明數組參數需要使用下面的宏:
module_param_array(name , type , num , perm); /*name 數組名稱 type 數組類型 num 爲用戶提供的值得個數 perm 常見的訪問許可值。具體的細節請參閱moduleparam.h 文件*/ module_param 中最後一個參數是訪問許可值, 我們應使用<linux / stat . h> 中存在的定義。這個值用來控制誰能夠訪問sysfs中對模塊參數的表述。如果perm被設置成0 ,就不會有對應的sysfs入口項 ; 否則參數會在 /sys/module 中出現,並設置爲給定的訪問許可。如果對參數使用S_IRUGO , 則任何人均可讀取該參數, 但不能修改; S_IRUGO | S_IWUSR 允許root用戶修改該參數。