新唐NUC972最簡單的驅(qū)動教程
1.新建文本文檔,重命名為 hello_dev.c (驅(qū)動的開發(fā)同應(yīng)用的開發(fā)一樣,也是在文本文檔下開發(fā)的)。
2.包含頭文件
內(nèi)核模塊需要包含內(nèi)核相關(guān)頭文件,不同模塊根據(jù)功能的差異,所需要的頭文件也不相同,但是<linux/module.h>和<linux/init.h>是必不可少的。
#include <linux/module.h> #include <linux/init.h>
|
3.模塊初始化
模塊的初始化負(fù)責(zé)注冊模塊本身。如果一個內(nèi)核模塊沒有被注冊,則其內(nèi)部的各種方法(函數(shù))無法被應(yīng)用程序使用,只有已注冊模塊的各種方法才能夠被應(yīng)用程序使用并發(fā)揮各方法的實(shí)際功能。模塊并不是內(nèi)核內(nèi)部的代碼,而是獨(dú)立于內(nèi)核之外,通過初始化,能夠讓內(nèi)核之外的代碼來替內(nèi)核完成本應(yīng)該由內(nèi)核完成的功能,模塊初始化的功能相當(dāng)于模塊與內(nèi)核之間銜接的橋梁,告知內(nèi)核“我進(jìn)來了”。
static int __init module_init_func(void) { 初始化代碼 } module_init(module_init_func); |
說明:
(1) 模塊初始化函數(shù)一般都需聲明為 static,因?yàn)槌跏蓟瘮?shù)對于其它文件沒有任何意義;
(2) __init 表示初始化函數(shù)僅僅在初始化期間使用,一旦初始化完畢,將釋放初始化函數(shù)所占用的內(nèi)存,類似的還有__initdata;
(3) module_init 是必須的,沒有這個定義,內(nèi)核將無法執(zhí)行初始化代碼。module_init宏定義會在模塊的目標(biāo)代碼中增加一個特殊的代碼段,用于說明該初始化函數(shù)所在的位置。
當(dāng)使用 insmod 將模塊加載進(jìn)內(nèi)核的時候,初始化函數(shù)的代碼將會被執(zhí)行。模塊初始化代碼只與內(nèi)核模塊管理子系統(tǒng)打交道,并不與應(yīng)用程序交互。
4.模塊退出。
當(dāng)系統(tǒng)不再需要某個模塊,可以卸載這個模塊以釋放該模塊所占用的資源。模塊的退出相當(dāng)于告知內(nèi)核“我要離開了”。實(shí)現(xiàn)模塊退出的函數(shù)常稱為模塊的退出函數(shù)或者清除函數(shù)
static void __exit module_exit_func(void) { 模塊退出代碼 } module_exit(module_exit_func); |
說明:
(1) 模塊退出函數(shù)沒有返回值;
(2) __exit 標(biāo)記這段代碼僅用于模塊卸載;
(3) module_exit 不是必須的。但是,沒有 module_exit 定義的模塊無法被卸載,如果需要支持模塊卸載則必須有 module_exit。
當(dāng)使用 rmmod 卸載模塊時,退出函數(shù)的代碼將被執(zhí)行。模塊退出代碼只與內(nèi)核模塊管理子系統(tǒng)打交道,并不直接與應(yīng)用程序交互。
5.許可證
Linux 內(nèi)核是開源的,遵守 GPL 協(xié)議,所以要求加載進(jìn)內(nèi)核的模塊也最好遵循相關(guān)協(xié)議。為模塊指定遵守的協(xié)議用 MODULE_LINCENSE 來聲明,如:
MODULE_LICENSE("GPL"); |
內(nèi)核能夠識別的協(xié)議有“GPL”、“GPL v2”、“GPL and additional rights(GPL 及附加權(quán)利)”、“Dual BSD/GPL(BSD/GPL 雙重許可)”、“Dual MPL/GPL(MPL/GPL 雙重許可)”以及“Proprietary(私有)”。
如果一個模塊沒有指定任何許可協(xié)議,則會被認(rèn)為是私有協(xié)議。采用私有協(xié)議的模塊,在加載過程中會出現(xiàn)警告,并且不能被靜態(tài)編譯進(jìn)內(nèi)核。
執(zhí)行完上面步驟,一個最小的linux驅(qū)動便寫好了。全部代碼如下:
6.編譯
內(nèi)核模塊的編譯需要Makefile文件,在hello_dev.c所在路徑建立Makefile文件:
在Makefile輸入以下文本并保存。
obj-m := hello_dev.o PWD := $(shell pwd) KVER ?= $(shell uname -r) KDIR :=/home/qlqcetc/nuc970bsp/02.linux內(nèi)核3.10.x all: $(MAKE) -C $(KDIR) M=$(PWD) clean: rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions |
其中obj-m 指定要編譯的源文件是hello_dev.c,KDIR指定內(nèi)核的路徑,驅(qū)動模塊的編譯是需要內(nèi)核源碼的相關(guān)文件的,所以需要設(shè)置內(nèi)核源碼所在路徑。
中斷進(jìn)入驅(qū)動源碼所在文件夾:
#/home/qlqcetc/nuc970bsp/06.示例驅(qū)動程序/00.hello_dev
#ls
編譯:
#make
#ls
生成的hello_dev.ko就是驅(qū)動模塊,使用U盤將其復(fù)制到開發(fā)板的/lib/modules/路徑下(modules文件夾需要創(chuàng)建),就可以加載驅(qū)動模塊了。
開發(fā)板終端輸入:
# cd /lib/modules/
# insmod hello_dev.ko
可以看到驅(qū)動加載成功,驅(qū)動打印出信息:
開發(fā)板終端輸入:
# mkdir 3.10.101
# rmmod hello_dev.ko
可以看到驅(qū)動卸載成功,驅(qū)動打印出信息:
編輯:admin 最后修改時間:2018-10-23