在用戶態下編程可以通過main()的來傳遞命令行參數,而編寫一個內核模塊則通過module_param()!
1.為什么引入
?在用戶態下編程可以通過main()來傳遞命令行參數,而編寫一個內核模塊則可通過module_param()來傳遞命令行參數
內核允許對驅動程序在加載的時候傳遞參數,在編寫內核程序的時候。要在代碼中用宏module_param來指定接受的參數名,而這個宏在<linux/moduleparam.h>中的定義如下 /* Helper functions: type is byte, short, ushort, int, uint, long, ?? ulong, charp, bool or invbool, or XXX if you define param_get_XXX, ?? param_set_XXX and param_check_XXX. */ #define module_param_named(name, value, type, perm)??? ??? ??? ?? \ ??? param_check_##type(name, &(value));??? ??? ??? ??? ?? \ ??? module_param_call(name, param_set_##type, param_get_##type, &value, perm); \ ??? __MODULE_PARM_TYPE(name, #type) #define module_param(name, type, perm)??? ??? ??? ??? \ ??? module_param_named(name, name, type, perm) 由此可知 module_param的實現是通過module_param_named(name, name, type, perm)的。 其中使用了 3 個參數:要傳遞的參數變量名,變量的數據類型,以及訪問參數的權限。
#include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h>???????? MODULE_LICENSE("Dual BSD/GPL");???? static char *who= "world";???????????? static int times = 1;??????? module_param(times,int,S_IRUSR);???? module_param(who,charp,S_IRUSR);?? static int hello_init(void)?????? { int i; for(i=0;i<times;i++) printk(KERN_ALERT "(%d) hello, %s!\n",i,who); return 0; } static void hello_exit(void) { printk(KERN_ALERT"Goodbye, %s!\n",who); } module_init(hello_init); module_exit(hello_exit); 編譯生成可執行文件hello 插入: # insmod hellowho="world"times=5出現5次"hello,world!": #(1)hello,world! #(2)hello,world! #(3)hello,world! # (4)hello,world! #(5)hello,world! 卸載: # rmmodhello出現: #Goodbye,world! |
?
驅動程序module的工作流程主要分為四個部分:
1、 insmod module
2、 驅動module的初始化(初始化結束后即進入“潛伏”狀態,直到有系統調用)
3、 當操作設備時,即有系統調用時,調用驅動module提供的各個服務函數
4、 rmmod module
一、 驅動程序的加載
Linux驅動程序分為兩種形式:一種是直接編譯進內核,另一種是編譯成module,然后在需要該驅動module時手動加載。
在用insmod加載module時,還可以給提供模塊參數,如:
static char *whom=”world”;
static int howmany=10;
module_param(howmany,int,S_IRUGO);
module_param(whom,charp,S_IRUGO);
這樣,當使用insmod scull.ko whom=”string” howmany=20這樣的命令加載驅動時,whom和howmay的值就會傳入scull驅動模塊了。
二、 驅動module的初始化
scull_init_module函數中主要做了以下幾件事情:
a) 分配并注冊主設備號和次設備號
int register_chrdev_region(dev_t first, unsigned int count, char *name)
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name)
b) 初始化代表設備的struct結構體:scull_dev
c) 初始化互斥體init_MUTEX
d) 初始化在內核中代表設備的cdev結構體,最主要是將該設備與file_operations結構體聯系起來。在Linux內核中,cdev結構體才是真正代表了某個設備。在內核調用設備的open,read等操作之前,必須先分配并注冊一個或者多個cdev結構。
三、設備操作
涉及open ,close ioclt,release等函數
四、卸載
scull_cleanup_module