关于module_param()宏

为了增加驱动程序的灵活性,内核允许对驱动程序指定参数,而这些参数可在加载驱动程序模块时改变。

这些参数的值可由 insmod 或者 modprobe 在加载时指定后者也可以从它的配置文件(/etc/modprobe.conf)读取参数的值。这两个命令可在命令行里接受几种参数类型的赋值。

在用户态下编程可以通过main()的来传递命令行参数,而编写一个内核模块则通过module_param()

module_param宏是Linux 2.6内核中新增的,该宏被定义在include/linux/moduleparam.h文件中,具体定义如下:

#define module_param(name, type, perm)                
    module_param_named(name, name, type, perm)

其中使用了 3 个参数:要传递的参数变量名, 变量的数据类型, 以及访问参数的权限。

<<<

perm参数的作用是什么?

最后的 module_param 字段是一个权限值,表示此参数在sysfs文件系统中所对应的文件节点的属性。你应当使用 <linux/stat.h> 中定义的值. 这个值控制谁可以存取这些模块参数在 sysfs 中的表示.当perm为0时,表示此参数不存在 sysfs文件系统下对应的文件节点。 否则, 模块被加载后,在/sys/module/ 目录下将出现以此模块名命名的目录, 带有给定的权限.。
权限在include/linux/stat.h中有定义
比如:
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
使用 S_IRUGO 作为参数可以被所有人读取, 但是不能改变; S_IRUGO|S_IWUSR 允许 root 来改变参数. 注意, 如果一个参数被 sysfs 修改, 你的模块看到的参数值也改变了, 但是你的模块没有任何其他的通知. 你应当不要使模块参数可写, 除非你准备好检测这个改变并且因而作出反应.

>>>

这个宏定义应当放在任何函数之外, 典型地是出现在源文件的前面.定义如:

static char *whom = "world";
static int howmany = 1;
module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IRUGO);

模块参数支持许多类型:

bool

invbool
一个布尔型( true 或者 false)值(相关的变量应当是 int 类型). invbool 类型颠倒了值, 所以真值变成 false, 反之亦然.
charp :一个字符指针值. 内存为用户提供的字串分配, 指针因此设置.
int

long

short

uint

ulong

ushort
基本的变长整型值. 以 u 开头的是无符号值.

数组参数, 用逗号间隔的列表提供的值, 模块加载者也支持. 声明一个数组参数, 使用:

module_param_array(name,type,num,perm);

这里 name 是你的数组的名子(也是参数名),
type 是数组元素的类型,
num 是一个整型变量,
perm 是通常的权限值.
如果数组参数在加载时设置, num 被设置成提供的数的个数. 模块加载者拒绝比数组能放下的多的值.
测试模块,源程序hello.c内容如下:
#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 hello who="world" times=5
出现5次"hello,world!":
#(1)hello,world!
#(2)hello,world!
#(3)hello,world!
#(4)hello,world!
#(5)hello,world!
卸载:
# rmmod hello
出现:
#Goodbye,world!

 

 

module_param(name, type, perm)是一个宏,向当前模块传入参数,对源码分析如下
在include\linux\moduleparam.h中
#define module_param(name, type, perm)                \
    module_param_named(name, name, type, perm)
#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_call(name, set, get, arg, perm)                  \
    __module_param_call(MODULE_PARAM_PREFIX, name, set, get, arg, perm)
#define __module_param_call(prefix, name, set, get, arg, perm)        \
    /* Default value instead of permissions? */            \
    static int __param_perm_check_##name __attribute__((unused)) =    \
    BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2));    \
    static char __param_str_##name[] = prefix #name;        \
    static struct kernel_param const __param_##name            \
    __attribute_used__                        \
    __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
    = { __param_str_##name, perm, set, get, arg }
__attibute__ 是gcc的关键字,可参考
http://gcc.gnu.org/onlinedocs/gcc-4.0.0/gcc/Variable-Attributes.html
__attibute__将参数编译到__param段中,
module_param是一步一步展开的,
上面几个宏在include\linux\moduleparam.h中的顺序刚好相反
module_param宏的类似函数调用的顺序
module_param->module_param_named->module_param_call->__module_param_call
展开的顺序正好相反
__module_param_call->module_param_call->module_param_named->module_param
type类型可以是byte,short,ushort,int,
uint,long,ulong,charp(注:字符指针),bool,invbool, 
perm表示此参数在sysfs文件系统中所对应的文件节点的属性。
权限在include/linux/stat.h中有定义
比如:
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
当perm为0时,表示此参数不存在 sysfs文件系统下对应的文件节点。
模块被加载后,在/sys/module/ 目录下将出现以此模块名命名的目录。
测试一下,插入一个驱动模块mp.ko,
sudo insmod mp.ko 
发现 /sys/module下出现mp这个文件夹
mp中有drivers/,sections/,parameters/,initstate,refcnt,srcversion
其中initstate 里面内容为:live
refcnt里面内容为:0
srcversion里面内容为:F9BDEBF706329B443C28E08,很长,应该是一个唯一数字
driver文件夹里面是空的
sections有__param,__versions
__param里面内容为0xd081e0a8
__versions里面内容为0xd081e100
parameters有count,info(注:自己定义的参数)
count里面的内容为1(注:输出次数)
info里面的内容为a site about linux driver.(注:输出内容)
如果此模块存在perm不为0的命令行参数,
在此模块的目录下将出现parameters目录,
包含一系列以参数名命名的文件节点,
这些文件的权限值等于perm,文件的内容为参数的值。
在/sys/module/mp/出现的参数,在module结构中的对应如下
struct module
{
    enum module_state state;
    /* Member of list of modules */
    struct list_head list;
    ......
    /* Sysfs stuff. */
    struct module_kobject mkobj;
    struct module_param_attrs *param_attrs;
    struct module_attribute *modinfo_attrs;
    const char *version;
    const char *srcversion;
    struct kobject *drivers_dir;
    /* Exported symbols */
    const struct kernel_symbol *syms;
    unsigned int num_syms;
    const unsigned long *crcs;
    ......
    /* Section attributes */
    struct module_sect_attrs *sect_attrs;
#endif
    ......
};
enum module_state
{
    MODULE_STATE_LIVE,
    MODULE_STATE_COMING,
    MODULE_STATE_GOING,
};
state对应/sys/module/mp/initstate
drivers_dir对应/sys/module/mp/driver文件夹
version对应/sys/module/mp/sections/__version
srcversion对应/sys/module/mp/srcversion
测试模块,源程序mp.c内容如下:
#include <linux/module.h>
#include <linux/moduleparam.h>             
static char *info= "a site about linux driver.";           
static int count= 1;    
static int mp= 0;       
    
module_param(mp,int,0);
module_param(count,int,S_IRUSR);     
module_param(info,charp,S_IRUSR);   
MODULE_AUTHOR("ioctrl");
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)       
{
    int i;
    for(i=0;i<count;i++)
    {
       printk(KERN_NOTICE www.linuxdriver.cn  is ");
       printk(info);
        printk("\n");
      }
   return 0;
}
static void hello_exit(void) 
{
    printk(KERN_NOTICE"exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
编译
手工插入,插入时传递参数 count=10,info="驱动开发网站。"
命令如下:
sudo insmod mp.ko count=10 info="驱动开发网站。"
然后用dmesg查看消息
看到如下,共10条记录
[16122.280000] www.linuxdriver.cn  is 驱动开发网站
[16122.280000] www.linuxdriver.cn  is 驱动开发网站
[16122.280000] www.linuxdriver.cn  is 驱动开发网站
[16122.280000] www.linuxdriver.cn  is 驱动开发网站
[16122.280000] www.linuxdriver.cn  is 驱动开发网站
[16122.280000] www.linuxdriver.cn  is 驱动开发网站
[16122.280000] www.linuxdriver.cn  is 驱动开发网站
[16122.280000] www.linuxdriver.cn  is 驱动开发网站
[16122.280000] www.linuxdriver.cn  is 驱动开发网站
[16122.280000] www.linuxdriver.cn  is 驱动开发网站

你可能感兴趣的:(驱动开发,module_param)