目錄
- (一)模塊化編程簡介
- (二)安裝卸載模塊命令.
- (三)將自定義功能添加到內核三種方法
- (1)修改Kconfig和Makefile
- (2)直接修改功能對應目錄下的Makefile文件
- (3)在內核目錄中,將功能編譯成模塊文件,后期加載到內核中
- (四)模塊文件模板
- (五)單模塊編程
- (六)多模塊編程
- (1)多個模塊編譯成多個.ko文件
- (2)多個模塊編譯成一個.ko文件
- (七)向模塊傳參
(一)模塊化編程簡介
Linux 內核整體結構已經很龐大,包含了很多的組件,而對于我們工程師而言,有兩種方法,將需要的功能包含進內核當中。
一:將所有的功能都編譯進 Linux 內核。
二:將需要的功能編譯成模塊,在需要的時候動態地添加。
我們在開發測試時常選擇第二種方式,原因是程序反復修改,不適合直接編譯到內核。 模塊起到約束作用,意味著內核中所有的模塊化程序均要遵循統一規則,否則無法添加到內核。
(二)安裝卸載模塊命令.
命令 | 解釋 |
---|---|
insmod | 將模塊添加進內核 |
rmmod | 將模塊從內核卸載 |
lsmod | 查看已安裝到內核的模塊 |
modprobe | 載入指定的個別模塊,或是載入一組相依賴的模塊。 modprobe 會根據 depmod 所產生的依賴關系,決定要載入哪些模塊。若在載入 過程中發生錯誤,在 modprobe 會卸載整組的模塊。依賴關系是通過讀取 /lib/modules/2.6.xx/modules.dep 得到的。而該文件是通過depmod 所建立。 |
modinfo | 查看模塊信息。使用方法:modinfo XXX.ko |
tree –a | 查看當前目錄的整個樹結構 |
(三)將自定義功能添加到內核三種方法
(1)修改Kconfig和Makefile
通過修改內核的配置文件
Kconfig:在Kconfig文件中將自定義功能添加到選項菜單中,用來進行是否將功能添加到內核的選項功能的配置,Y標識編譯到內核M標識編譯為模塊文件N標識不對功能做任何操作
config TINY4412_HELLO_MODULE //配置選項名tristate "Tiny4412 module sample" //在菜單中顯示的名稱//tristate :三態,Y,M,N,此位置或者為bool雙態,Y,Ndepends on ARCH_EXYNOS4 //依賴的處理架構help //提示相關的信息Tiny4412 module sample.
我們在linux-3.5/drivers/char的Kconfig中加入上面的代碼:
執行:
make menuconfig
//需要在頂級目錄執行
//若無法打開需要安裝庫 apt install ncurses-dev
在界面里多出了一項:
這里僅僅是添加了編譯選項,還需要在對應的Makefile文件進行修改
兩個文件必須同時修改才能達到將功能添加到內核的操作
進入到linux-3.5/drivers/char執行
vim Makefile
經過上面的kcofig和Makefile修改,我們在頂級目錄下執行make -j8 就可以編譯內核,然后下載到開發板查看現象了
(2)直接修改功能對應目錄下的Makefile文件
具體的修改和前面方法類似,不做過多介紹
obj-y += mem.o random.o
obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o
obj-$(CONFIG_TTY_PRINTK):選項名稱
obj-y:y標識yes 直接選中編譯到內核,無需在Kconfig中進行功能選項配置
obj-m:直接編譯成模塊文件,Linux中模塊文件編譯后以.ko結尾
(3)在內核目錄中,將功能編譯成模塊文件,后期加載到內核中
將模塊加載到內核的方法
insmod xxx.ko
查看模塊使用情況:
lsmod xxx.ko
將模塊從內核卸載:
rmmod xxx.ko
可以在任意目錄下對模塊文件進行編譯,而不局限內核目錄
關于模塊文件的編寫,我們在下面進行詳細的講解。
(四)模塊文件模板
1.模塊文件模板(module.c)
static int __init XXX_init(void)//模塊加載函數
{
//這里面做一些初始化工作
return 0;
}
static void __exit XXX_exit(void)//模塊卸載函數
{
//這里面做一些模塊卸載相關的工作
}
moudle_init(XXX_init); // 當執行#insmod 時調用,可以看作模塊的入口
moudle_exit(XXX_exit); // 執行#rmmod 時調用,完成模塊注銷操作//必須有
MODULE_LICENSE("GPL");//模塊的開源許可協議 // 模塊的聲明(非必須)
MODULE_AUTHOR // 聲明作者
MODULE_DESCRIPTION // 對模塊簡單的描述
MODULE_VERSION // 聲明模塊的版本
MODULE_ALIAS // 模塊的別名
MODULE_DEVICE_TABLE // 告訴用戶空間這個模塊所支持的設備
模塊的卸載函數和模塊加載函數實現相反的功能,主要包括:
1) 若模塊加載函數注冊了 XXX,則模塊卸載函數注銷 XXX
2) 若模塊加載函數動態分配了內存,則模塊卸載函數釋放這些內存
3) 若模塊加載函數申請了硬件資源,則模塊卸載函數釋放這些硬件資源
4) 若模塊加載函數開啟了硬件資源,則模塊卸載函數一定要關閉這些資源
2.Makefile模板文件
CFLAG=-C
TARGET=cdev #你自己的模塊文件名
KERNEL=/driver/linux-3.5 #linux內核頂級目錄路徑
obj-m +=$(TARGET).o
all:make $(CFLAG) $(KERNEL) M=$(PWD)
clean:make $(CFLAG) $(KERNEL) M=$(PWD) clean
(五)單模塊編程
單模塊即一個模塊編譯成一個.ko文件
例子:
tiny_hello_module.c
#include <linux/kernel.h>
#include <linux/module.h>
//加載函數入口
static int __init Test_module_init(void)
{printk("歡迎撬開內核驅動編程的大門\n");return 0;
}
//卸載函數入口
static void __exit Test_module_cleanup(void)
{printk("很機智,知難而退\n");
}
module_init(Test_module_init);
module_exit(Test_module_cleanup);
MODULE_LICENSE("GPL");//如果不準尋GPL協議會報污染內核
/*
MODULE_AUTHOR // 聲明作者
MODULE_DESCRIPTION // 對模塊簡單的描述
MODULE_VERSION // 聲明模塊的版本
MODULE_ALIAS // 模塊的別名
MODULE_DEVICE_TABLE // 告訴用戶空間這個模塊所支持的設備
*/
Makefile
CFLAG=-C
TARGET=tiny_hello_module
KERNEL=/driver/linux-3.5
obj-m += $(TARGET).o
all:make $(CFLAG) $(KERNEL) M=$(PWD)
clean:make $(CFLAG) $(KERNEL) M=$(PWD) clean
執行make后,會生成.ko模塊文件
make
(六)多模塊編程
多模塊即多個模塊.c編譯成多個.ko文件,一般這種情況下存在模塊之間的功能調用,如模塊1調用了模塊2中的功能函數。
內核模塊之間要進行功能調用,需要借助接口EXPORT_SYMBOL(被調用函數名) 對被調用函數進行聲明。
多模塊加載順序:
先加載被調用功能所在的模塊到內核,再加載調用功能的模塊到內核,卸載的順序相反
(1)多個模塊編譯成多個.ko文件
模塊1:
#include <linux/kernel.h>
#include <linux/module.h>
void print()
{printk("this is a module test\n");
}
EXPORT_SYMBOL(print);
//加載函數入口
static int __init Test_module_init(void)
{printk("歡迎撬開驅動大門\n");print();return 0;
}
//卸載函數入口
static void __exit Test_module_cleanup(void)
{printk("知難而退,聰明\n");
}
module_init(Test_module_init);
module_exit(Test_module_cleanup);
MODULE_LICENSE("GPL");//如果不準尋GPL協議會報污染內核
模塊2:
#include <linux/kernel.h>
#include <linux/module.h>
extern void print();
//加載函數入口
static int __init Test_module_init(void)
{print();printk("歡迎撬開內核驅動編程的大門\n");return 0;
}
//卸載函數入口
static void __exit Test_module_cleanup(void)
{printk("很機智,知難而退\n");
}
module_init(Test_module_init);
module_exit(Test_module_cleanup);
MODULE_LICENSE("GPL");//如果不遵循GPL協議會報污染內核
Makefile
CFLAG=-C
TARGET=tiny_hello_module
TARGET1=test_hello_module
KERNEL=/driver/linux-3.5
obj-m += $(TARGET).o $(TARGET1).o
all:make $(CFLAG) $(KERNEL) M=$(PWD)
clean:make $(CFLAG) $(KERNEL) M=$(PWD) clean
(2)多個模塊編譯成一個.ko文件
被加載功能:
#include <linux/kernel.h>
#include <linux/module.h>
void print()
{
printk("this is a module test\n");
}
EXPORT_SYMBOL(print);
加載功能的模塊
#include <linux/kernel.h>
#include <linux/module.h>
extern void print();
//加載函數入口
static int __init Test_module_init(void)
{print();printk("歡迎撬開內核驅動編程的大門\n");return 0;
}
//卸載函數入口
static void __exit Test_module_cleanup(void)
{printk("很機智,知難而退\n");
}
module_init(Test_module_init);
module_exit(Test_module_cleanup);
MODULE_LICENSE("GPL");//如果不準尋GPL協議會報污染內核
Makefile
CFLAG=-C
TARGET=tiny_hello_module
TARGET1=test_hello_module
KERNEL=/driver/linux-3.5
obj-m += test.o
test-objs += $(TARGET).o $(TARGET1).o
all:make $(CFLAG) $(KERNEL) M=$(PWD)
clean:make $(CFLAG) $(KERNEL) M=$(PWD) clean
(七)向模塊傳參
普通變量:
module_param(變量名, 變量的類型, 權限)
語法:module_param(變量名,變量類型,變量的訪問權限)
變量的訪問權限:變量在文件系統以一個文件形式呈現,這個文件權限屬性就是“變量的訪問權限”。
變量傳遞參數:insmod xx.ko 變量名=值
type支持的基本類型有:
bool :布爾類型
invbool:顛倒了值的bool類型;
charp :字符指針類型,內存為用戶提供的字符串分配;(char )
int :整型
long :長整型
short :短整型
uint :無符號整型(unsigned int)
ulong :無符號長整型(unsigned long)
ushort :無符號短整型(unsignedshort)
指針類只能char,對應名字 charp .
example:
#include <linux/kernel.h>
#include <linux/module.h>
int num=0;
module_param(num,int,0);
//加載函數入口
static int __init Test_module_init(void)
{
int i=0;
for(i=0;i<num;i++)printk("歡迎撬開內核驅動編程的大門\n");return 0;
}
//卸載函數入口
static void __exit Test_module_cleanup(void)
{printk("很機智,知難而退\n");
}
module_init(Test_module_init);
module_exit(Test_module_cleanup);
MODULE_LICENSE("GPL");//如果不準尋GPL協議會報污染內核
Makefile
CFLAG=-C
TARGET=tiny_hello_module
KERNEL=/driver/linux-3.5
obj-m +=$(TARGET).o
all:make $(CFLAG) $(KERNEL) M=$(PWD)
clean:make $(CFLAG) $(KERNEL) M=$(PWD) clean
[root@ubuntu:/home]#insmod tiny_hello_module.ko num=5
數組變量:
對于數組類型變量使用module_param_array。
語法:module_param_array(數組名,數組元素類型,&用來保存傳遞數組袁術個數的變量,變量的訪問權限)num 是一個 char ,int,long 或uchar,uint,ulong類型的變量,用于保存傳遞給數組的元素個數。
數組傳遞參數: insmod xx.ko 數組名=元素0,元素1,元素2, ……