Linux设备驱动第 2 章之 模块参数

2.8. 模块参数

        由于系统的不同,驱动程序需要的参数也许会发生变化。这包括设备编号以及其它一些用来控制驱动程序操作方式的参数。例如,SCSI适配器的驱动程序经常要处理一些选项,这些选项用来控制标记命令队列的使用,而集成设备电路驱动程序允许用户控制DMA操作。如果驱动程序用来控制一些早期的硬件,也许需要明确告诉驱动程序硬件的IO端口或者IO内存地址的位置。为满足这种需求,内核允许对驱动程序指定参数,而这些参数可以在加载驱动程序模块时改变。

        这些参数的值可在运行insmod或modprobe命令加载模块时赋值,而modprobe可以从它的配置文件中读取参数值。这两个命令可在命令行接受几种参数类型的赋值。例如,添加两个参数:一个是整数值howmany,另一个是字符串who。可用下面的命令行来加载内核模块:

insmod hello.ko howmany=10 who="AndyLiu"

这个命令的效果会让hello打印10次“hello,AndyLiu”。

在insmod改变模块参数之前,模块必须让这些参数对insmod命令可见。参数必须使用module_param宏来声明,这个宏在linux/moduleparam.h中定义。

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

module_param需要三个参数:变量的名称、类型以及用于sysfs入口项的访问许可掩码。这个宏必须放在任何函数之外,通常是在源文件的头部。这样,通过下面的代码来声明它的参数并使之对insmod可见。

static int howmany = 1;
static char *who = "AndyLiu";

module_param(howmany, int, S_IRUGO);

module_param(who, charp, S_IRUGO);

参见实例

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>

static int howmany = 1;
static char *who = "AndyLiu";

module_param(howmany, int, S_IRUGO);
module_param(who, charp, S_IRUGO);

static int __init mod_param_init(void)
{
int i;
printk(KERN_INFO "mod_param_init\n");

for(i = 0; i < howmany; i++){
printk(KERN_INFO "hello,%s\n", who);
}

return 0;
}


static void __exit mod_param_exit(void)
{
printk(KERN_INFO "mod_param_exit\n");
}


module_init(mod_param_init);
module_exit(mod_param_exit);

MODULE_LICENSE("Dual BSD/GPL");

ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:                               
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:                                             
        $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
else
    obj-m := mod_param.o
endif

内核支持的模块参数类型如下:

bool

invbool

布尔值(true或false),关联的变量应该是int类型。invbool类型反转其值,true值变成false,而false变成true。

charp

字符指针值。内核会为用户提供的字符串分配内存,并相应设置指针。

int

long

short

uint

ulong

ushort

具有不同长度的基本整数值。以u开头的类型用于无符号值。

模块装载器也支持数组参数,在提供数组值时用逗号划分各数组成员。要声明数组参数,需要使用下面的宏:

/**
 * module_param_array - a parameter which is an array of some type
 * @name: the name of the array variable
 * @type: the type, as per module_param()
 * @nump: optional pointer filled in with the number written
 * @perm: visibility in sysfs
 *
 * Input and output are as comma-separated values.  Commas inside values
 * don't work properly (eg. an array of charp).
 *
 * ARRAY_SIZE(@name) is used to determine the number of elements in the
 * array, so the definition must be visible.
 */
#define module_param_array(name, type, nump, perm)              \
        module_param_array_named(name, name, type, nump, perm)

其中,name是数组的名称(也就是参数的名称),type是数组元素的类型,nump是一个整数变量,而perm是常见的许可访问值。如果在装载时设置数组参数,则num会被设置为用户提供的值的个数。模块装载器会拒绝接受超过数组大小的值。

参见实例:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>

static int ages[] = {0, 0, 0};// 默认值
static int nump;
module_param_array(ages, int, &nump, S_IRUGO);


static int __init mod_param_init(void)
{
int i;
printk(KERN_INFO "mod_param_init\n");

for(i = 0; i < nump; i++){
printk(KERN_INFO "hello,ages[%d] = %d\n", i, ages[i]);
}

return 0;
}


static void __exit mod_param_exit(void)
{
printk(KERN_INFO "mod_param_exit\n");
}

module_init(mod_param_init);
module_exit(mod_param_exit);

MODULE_LICENSE("Dual BSD/GPL");

        如果需要的类型不在上面列出的清单中,模块代码中的钩子可以让我们来定义这些类型。请参考linux/moduleparam.h文件。备注:所有的模块参数都应该给定一个默认值;insmod只会在用户明确设置了参数的值的情况下才会改变参数的值。模块可以根据默认值来判断是否是一个显示指定的参数。

        module_param中的最后一个成员是访问许可值,应使用linux/stat.h中存在的定义。

#define S_IRWXUGO       (S_IRWXU|S_IRWXG|S_IRWXO)
#define S_IALLUGO       (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
#define S_IRUGO         (S_IRUSR|S_IRGRP|S_IROTH)
#define S_IWUGO         (S_IWUSR|S_IWGRP|S_IWOTH)

#define S_IXUGO         (S_IXUSR|S_IXGRP|S_IXOTH)

这个值用来控制谁能够访问sysfs中对模块参数的表述。如果perm被设置为0,就不会有对应的sysfs入口项;否则,模块参数会在/sys/module中出现,并设置为给定的访问许可。如果对参数使用S_IRUGO,则任何人可读取该参数,但不能修改;注意,如果一个参数通过sysfs而被修改,则如同模块修改了这个参数的值一样,但是内核不会以任何方式通知模块。大多数情况下,不应该让模块参数是可写的,除非打算检测这种修改并作出相应的动作。

猜你喜欢

转载自blog.csdn.net/xiezhi123456/article/details/80996404