首先貼代碼helloworld.c和Makefilelinux
/************************************************************************* > File Name: helloworld.c > Author: hailin.ma > Mail: mhl2018@126.com > Created Time: Wed 15 Jul 2015 02:39:35 PM CST ************************************************************************/ #include <linux/init.h> #include <linux/module.h> static char* mod_name = "hello"; static int mod_num = 1; static int __init hello_init(void) { printk(KERN_INFO"hello world init! mod_name = %s,mod_num = %d\n",mod_name,mod_num); return 0; } static void __exit hello_exit(void) { printk(KERN_INFO"hello world exit!\n"); } module_init(hello_init); module_exit(hello_exit); module_param(mod_name,charp,S_IRUGO); module_param(mod_num,int,S_IRUGO); MODULE_AUTHOR("hailin.ma <mhl2018@126.com>"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("A simple hello world module"); MODULE_ALIAS("simple driver test");
Makefileshell
#CFLAGS = -g KVERS = /lib/modules/$(shell uname -r)/build obj-m += hello.o hello-objs:=helloworld.o all: make -C $(KVERS) M=$(PWD) modules @rm *.o clean: make -C $(KVERS) M=$(PWD) clean
make 執行後將生成hello.ko文件,命令:insmod hello.ko 便可加載模塊到內核。加載 hello.ko 後,內核中將包含
/sys/module/hello 目錄,該目錄下又包含一個 refcnt 文件和一個 sections 目錄,在/sys/module/hello
目錄下運行「 tree –a」 獲得以下目錄樹:數組
modinfo <模塊名 >命令能夠得到模塊的信息,包括模塊做者、模塊的說明、模塊所支持
的參數以及 vermagic:函數
insmod 加載模塊ui
lsmod 查看已加載模塊,
lsmod 命令其實是讀取並分析「/proc/modules」 文件。
編碼
rmmod 卸載模塊spa
tail /var/log/messages 查看printk打印消息命令行
一個 Linux 內核模塊主要由以下幾個部分組成。
( 1 )模塊加載函數(通常須要)。
當經過 insmod 或 modprobe 命令加載內核模塊時,模塊的加載函數會自動被內核執行,完成
本模塊的相關初始化工做。3d
static int _ _init initialization_function(void) //初始化函數 { /* 初始化代碼 */ } module_init(initialization_function); //指定模塊初始化函數
模塊加載函數必須以「 module_init(函數名 )」 的形式被指定。它返回整型值,若初始化成功,
應返回 0。而在初始化失敗時,應該返回錯誤編碼。在 Linux 內核裏,錯誤編碼是一個負值,在
<linux/errno.h>中定義,包含-ENODEV、 -ENOMEM 之類的符號值。老是返回相應的錯誤編碼是
種很是好的習慣,由於只有這樣,用戶程序才能夠利用 perror 等方法把它們轉換成有意義的錯誤
信息字符串。
在 Linux 2.6 內核中,可使用 request_module(const char *fmt, …)函數加載內核模塊,驅動開
發人員能夠經過調用
request_module(module_name);
或
request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev));
這種靈活的方式加載其餘內核模塊。
在 Linux 中,全部標識爲_ _init 的函數在鏈接的時候都放在.init.text 這個區段內,此外,全部
的_ _init 函數在區段.initcall.init 中還保存了一份函數指針,在初始化時內核會經過這些函數指針
調用這些_ _init 函數,並在初始化完成後,釋放 init 區段(包括.init.text、 。initcall.init等)。指針
( 2)模塊卸載函數(通常須要)。
當經過 rmmod 命令卸載某模塊時,模塊的卸載函數會自動被內核執行,完成與模塊卸載函數
相反的功能。
static void _ _exit cleanup_function(void) //模塊卸載函數 { /* 釋放代碼 */ } module_exit(cleanup_function); //指定模塊卸載函數
模塊卸載函數在模塊卸載的時候執行,不返回 任何值,必須以「 module_exit(函數名 )」 的形
式來指定。
一般來講,模塊卸載函數要完成與模塊加載函數相反的功能, 以下所示。
! 若模塊加載函數註冊了 XXX,則模塊卸載函數應該註銷 XXX。
! 若模塊加載函數動態申請了內存,則模塊卸載函數應釋放該內存。
! 若模塊加載函數申請了硬件資源(中斷、 DMA 通道、 I/O 端口和 I/O 內存等)的佔用,
則模塊卸載函數應釋放這些硬件資源。
! 若模塊加載函數開啓了硬件,則卸載函數中通常要關閉之。
和_ _init 同樣, _ _exit 也可使對應函數在運行完成後自動回收內存。實際上, _ _init 和_ _exit
都是宏,其定義分別爲:
#define _ _init _ _attribute_ _ (( _ _section_ _ (".init.text")))
和
#ifdef MODULE
#define _ _exit _ _attribute_ _ (( _ _section_ _(".exit.text")))
#else
#define _ _exit _ _attribute_used_ _attribute_ _ (( _ _section_ _(".exit.text")))
#endif
數據也能夠被定義爲_ _initdata 和_ _exitdata,這兩個宏分別爲:
#define _ _initdata _ _attribute_ _ (( _ _section_ _ (".init.data")))
和
#define _ _exitdata _ _attribute_ _ (( _ _section_ _(".exit.data")))
( 3)模塊許可證聲明(必須)。
許可證( LICENSE)聲明描述內核模塊的許可權限,若是不聲明 LICENSE,模塊被加載時,
將收到內核被污染 ( kernel tainted)的警告。
在 Linux 2.6 內核中,可接受的 LICENSE 包括「GPL」、「GPL v2」、「GPL and additional rights」、
「 Dual BSD/GPL」、 「 Dual MPL/GPL」 和「 Proprietary」。
大多數狀況下,內核模塊應遵循 GPL 兼允許可權。 Linux 2.6 內核模塊最多見的是以
MODULE_LICENSE( "Dual BSD/GPL" )語句聲明模塊採用 BSD/GPL 雙 LICENSE。
( 4)模塊參數(可選)。
模塊參數是模塊被加載的時候能夠被傳遞給它的值,它自己對應模塊內部的全局變量。
咱們能夠用 「 module_param(參數名 ,參數類型,參數讀/寫權限)」 爲模塊定義一個參數,例以下
列代碼定義了 1 個整型參數和 1 個字符指針參數:
static char *book_name = " dissecting Linux Device Driver "; static int num = 4 000; module_param(num, int, S_IRUGO); module_param(book_name, charp, S_IRUGO);
在裝載內核模塊時,用戶能夠向模塊傳遞參數,形式爲「 insmode(或 modprobe)模塊名 參
數名 =參數值」,若是不傳遞,參數將使用模塊內定義的缺省值。
參數類型能夠是 byte、 short、 ushort、 int、 uint、 long、 ulong、 charp(字符指針)、 bool 或 invbool
(布爾的反),在模塊被編譯時會將 module_param 中聲明的類型與變量定義的類型進行比較,判斷
是否一致。
模塊被加載後,在/sys/module/目錄下將出現以此模塊名命名的目錄。當「參數讀/寫權限」 爲 0
時,表示此參數不存在 sysfs 文件系統下對應的文件節點,若是此模塊存在「參數讀/寫權限」 不爲 0
的命令行參數,在此模塊的目錄下還將出現 parameters 目錄,包含一系列以參數名命名的文件節點,
這些文件的權限值就是傳入 module_param()的「參數讀/寫權限」,而文件的內容爲參數的值。
除此以外,模塊也能夠擁有參數數組,形式爲「module_param_array(數組名,數組類型,數組長,參數
讀/寫權限)」。從 2.6.0~2.6.10 版本, 需將數組長變量名賦給「數組長」,從 2.6.10 版本開始, 需將數組
長變量的指針賦給「數組長」,當不須要保存實際輸入的數組元素個數時,能夠設置「數組長」 爲 NULL。
運行 insmod,不一樣參數用空格隔開
( 5)模塊導出符號(可選)。
內核模塊能夠導出符號( symbol,對應於函數或變量),這樣其餘模塊可使用本模塊中的變
量或函數。