模块参数

了解了内核模块、中断、定时器等内容后,我们缓一下来补充之前的一些内容和相关内容,接下来主要是了解内核态与用户态之间数据传递的机制,这次先了解内核模块参数,该部分在中断时有使用到,但未整理说明,现在补充学习下。
那么什么是内核态和用户态呢?
简单来理解,内核模块和内核就是运行在内核态,而用户程序和命令行操作等则运行在用户态,即程序运行的空间状态不一样,那么两者如何通信?本次说到的内核模块参数会感受到。
作为内核模块参数,我们只有将驱动代码编译成ko文件,再使用insmod和modprobe命令加载时才会使用到(也可在加载模块后在/sys里修改),而一旦将其编译进内核,那么我们会使用到内核启动参数,这个后期再说明。
在include/linux/moduleparam.h文件里有关于内核模块参数的定义,而我们常用到的宏有如下:
#define module_param(name, type, perm) \
        module_param_named(name, name, type, perm)
#define module_param_array(name, type, nump, perm) \
        module_param_array_named(name, name, type, nump, perm)
#define MODULE_PARM_DESC(_parm, desc) \
        __MODULE_INFO(parm, _parm, #_parm ":" desc)
其中module_param 和module_param_array是定义相关参数时使用,而 MODULE_PARM_DESC仅仅是对参数进行描述,说明该参数的作用,上述宏的相关参数说明如下:
1.name与_parm是参数名;
2.type:参数的类型,可使用的类型如下:
byte, short, ushort, int, uint, long, ulong
charp: a character pointer
bool: a bool, values 0/1, y/n, Y/N.
invbool: the above, only sense-reversed (N = true).
3.perm:在include/uapi/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
一般可使用其中一个或几个进行“或”操作的组合,但我们更常用8进制数来表示(如0644,0777等),如果该值为0,则在/sys下不会有相应的参数结点存在。
4.nump:数组参数的大小;
5.desc:参数描述字符串。
接下来我们看一例:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>

static int int_param = 1;
static int arr[] = {1,2,3,4,5,6};
static int n = ARRAY_SIZE(arr);

module_param(int_param, int, 0644);
MODULE_PARM_DESC(int_param, "integer type parameter");
module_param_array(arr, int, &n, 0644);
MODULE_PARM_DESC(arr, "integer type array parameter");

static __init int param_init(void)
{
        int i;

        printk("Hello param!\n");
        printk("int_param=%d\n", int_param);

        for(i = 0; i < n; i++)
        {
                printk("arr[%d] = %d\n", i, arr[i]);
        }
        return 0;
}

static __exit void param_exit(void)
{
        printk("Bye param!\n");
}

module_init(param_init);
module_exit(param_exit);

MODULE_LICENSE("GPL");
相应的Makefile如下:
obj-m += module_param_exam.o

CUR_PATH:=$(shell pwd)
LINUX_KERNEL_PATH:=/home/xinu/linux-3.13.6

all:
        make -C $(LINUX_KERNEL_PATH) M=$(CUR_PATH) modules

clean:
        make -C $(LINUX_KERNEL_PATH) M=$(CUR_PATH) clean
相应的源码文件目录树如下:
/home/xinu/xinu/linux_kernel_driver_l1/module_param_exam/
├── Makefile
└── module_param_exam.c
从源码里可以看到在使用内核参数前需先定义变量,再使用module_param等宏来说明该变量作为参数使用。
而make后如何加载呢?
由于源码里的变量都有初始化,故而有如下形式:
sudo insmod module_param_exam.ko sudo insmod module_param_exam.ko int_param=2
sudo insmod module_param_exam.ko arr=2,3,4,5,6,7
sudo insmod module_param_exam.ko int_param=2 arr=3,4,5,6,7,8
那如果我们不知道模块文件有没有相关参数,该怎么办呢?
可以找modinfo命令帮忙,我们的模块使用该命令有如下内容输出:
xinu@slam:~/xinu/linux_kernel_driver_l1/module_param_exam$ modinfo module_param_exam.ko
filename: /home/xinu/xinu/linux_kernel_driver_l1/module_param_exam/module_param_exam.ko
license: GPL srcversion: 09B84A711F0A86613CC18D8
depends: vermagic: 3.13.6 SMP mod_unload modversions
parm: int_param:integer type parameter (int)
parm: arr:integer type array parameter (array of int)
还有,模块加载后,我们可在/sys目录查找相关结点,获得参数的值,以我们本例有如下内容:
xinu@slam:~/xinu/$ ls -l /sys/module/module_param_exam/parameters/
total 0
-rw-r–r– 1 root root 4096 Apr 28 18:15 arr
-rw-r–r– 1 root root 4096 Apr 28 18:15 int_param
xinu@slam:~/xinu/$ cat /sys/module/module_param_exam/parameters/int_param
 1
xinu@slam:~/xinu/$ cat /sys/module/module_param_exam/parameters/arr
1,2,3,4,5,6
至此,我们对内核模块参数加载了解了,这几天将继续说明内核态与用户态数据传递的其他方式。
参考网址:
http://blog.csdn.net/yao_guet/article/details/6542054
http://www.ibm.com/developerworks/cn/linux/l-kerns-usrs/index.html
http://www.embeddedlinux.org.cn/html/yingjianqudong/201304/17-2548.html

评论

此博客中的热门博文

I/O映射之I/O端口

通过Netlink检测网线插拔

使用seq_file