本文已参与「新人创作礼」活动,一起开启掘金创作之路。
在应用层的C程序都是通过 main 函数的参数进行传递参数。 在驱动层则是使用模块参数 进行参数传递。 由于最近项目需要用到,就学习记录一下。
一、宏及参数介绍
1、模块参数宏
模块参数宏常用的有两个, module_param 和 module_param_array。 定义在文件 kernel\include\linux\moduleparam.h 中。
(1)module_param
module_param(参数名,参数类型,参数读/写权限)
(1)module_param_array
module_param_array(参数名,参数类型,数组长度,参数读/写权限)
2、参数名
在模块参数宏的第一个参数就是参数名,这个其实就是在驱动中定义个一个变量名,并且在传入参数时也会用到(例如:参数名=xxx)。 该变量的类型要与参数类型一致。
3、参数类型
参数类型可以为 byte 、 short 、 ushort 、 int 、 uint 、 long 、 ulong 、 charp (字符指针)、 booI 或 invbool (布尔的反), 。 参数类型要与参数名的变量类型一致。
4、数组长度
这个参数指的是传入的数组长度(不是定义的数组长度),是个变量,是个传出参数。 应该定义一个int类型的变量,然后将该变量的指针传入,这样可以获取到传入的参数个数。
5、参数读/写权限
可选的权限宏:
- S_IRWXUGO:用户、用户组、其他组有 读 写 执行 权限。
- S_IRUGO:用户、用户组、其他组有 读 权限。
- S_IWUGO:用户、用户组、其他组有 写 权限。
- 0:该参数不生效。
二、参数传递
参数传递发生在装载内核模块的时候,有两种情况,驱动模块外置加载、驱动模块内置加载。
1、驱动模块外置加载
在通过命名 insmod 加载驱动时可以进行传递参数。
insmod test.ko param1=value1 param2=value2
然后传入的参数会覆盖原本在驱动中定义的参数变量的默认值。
2、驱动模块内置加载
这种情况无法通过 insmod 加载驱动进行参数传递。 但是 bootloader 可以通过在 bootargs 里进行参数配置给内核驱动传递参数。以 modename.paramname=value 的形式。
三、测试代码
1、源码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
/*************************************************************************************************/
// 局部宏定义
/*************************************************************************************************/
#define EN_DEBUG 1 /* 调试信息开关 */
#if EN_DEBUG
#define PRINT(x...) printk(KERN_EMERG x) /* 提高打印等级 */
#else
#define PRINT(x...)
#endif
/*************************************************************************************************/
// 局部变量
/*************************************************************************************************/
static char *s_param_str = "str"; /* 字符串变量 */
static int s_param_int = 66; /* int变量 */
static int s_param_array[3] = {1,2,3}; /* int数组 */
static int s_param_array_len; /* int数组的长度 */
/**************************************************************************************************
** 函数名称: drv_init
** 功能: 驱动初始化函数,在加载时被调用
** 参数: 无
** 返回: 无
**************************************************************************************************/
static int __init drv_init(void)
{
int i;
PRINT("[KERNEL]:%s ------ \n", __FUNCTION__);
PRINT("[KERNEL]:s_param_str = %s \n", s_param_str);
PRINT("[KERNEL]:s_param_int = %d \n", s_param_int);
PRINT("[KERNEL]:s_param_array_len = %d \n", s_param_array_len);
for (i = 0; i < 3; ++i) {
PRINT("[KERNEL]:s_param_array[%d] = %d\n", i, s_param_array[i]);
}
return 0;
}
/**************************************************************************************************
** 函数名称: drv_exit
** 功能描述: 驱动退出函数,在卸载时被调用
** 参数: 无
** 返回: 无
**************************************************************************************************/
static void __exit drv_exit(void)
{
PRINT("[KERNEL]:%s ------ \n", __FUNCTION__);
}
/* 定义模块参数 */
module_param(s_param_str, charp, S_IRUGO);
module_param(s_param_int, int, S_IRUGO);
module_param_array(s_param_array, int, &s_param_array_len, S_IRUGO);
module_init(drv_init); /* 模块初始化 */
module_exit(drv_exit); /* 模块卸载 */
MODULE_AUTHOR("hrx"); /* 模块作者 */
MODULE_DESCRIPTION("Linux Driver"); /* 模块描述 */
MODULE_VERSION("1.0.0"); /* 模块版本 */
MODULE_LICENSE("GPL"); /* 模块遵守的License */
2、测试
(1)不传入参数
不传入参数则使用默认定义变量时的初试参数。
t@imx6qsabresd:/tmp# insmod param_demo.ko
[ 8294.829669] [KERNEL]:drv_init ------
[ 8294.833347] [KERNEL]:s_param_str = str
[ 8294.837271] [KERNEL]:s_param_int = 66
[ 8294.841028] [KERNEL]:s_param_array_len = 0
[ 8294.845262] [KERNEL]:s_param_array[0] = 1
[ 8294.849282] [KERNEL]:s_param_array[1] = 2
[ 8294.853297] [KERNEL]:s_param_array[2] = 3
(2)传入字符串及数字
root@imx6qsabresd:/tmp# insmod param_demo.ko s_param_str="newstr" s_param_int=88
[ 8365.399765] [KERNEL]:drv_init ------ o.ko s_param_str="newstr" s_param_int=88
[ 8365.403443] [KERNEL]:s_param_str = newstr
[ 8365.407620] [KERNEL]:s_param_int = 88
[ 8365.411380] [KERNEL]:s_param_array_len = 0
[ 8365.415615] [KERNEL]:s_param_array[0] = 1
[ 8365.419633] [KERNEL]:s_param_array[1] = 2
[ 8365.423681] [KERNEL]:s_param_array[2] = 3
可以发现变量 s_param_str 和 s_param_int 被改变了。
(3)传入数组内容
root@imx6qsabresd:/tmp# insmod param_demo.ko s_param_array=999,888,777
[ 8445.969720] [KERNEL]:drv_init ------
[ 8445.973398] [KERNEL]:s_param_str = str
[ 8445.977329] [KERNEL]:s_param_int = 66
[ 8445.981088] [KERNEL]:s_param_array_len = 3
[ 8445.985321] [KERNEL]:s_param_array[0] = 999
[ 8445.989515] [KERNEL]:s_param_array[1] = 888
[ 8445.993736] [KERNEL]:s_param_array[2] = 777
可以看到定义的数组内容发生了改变,数组长度变量被修改为3。
假如输入的参数长度大于定义的数组变量长度则会崩溃,驱动模块会加载失败。
root@imx6qsabresd:/tmp# insmod param_demo.ko s_param_array=999,888,777,888
[ 8550.298418] s_param_array: can only take 3 arguments
[ 8550.303397] param_demo: `999' invalid for parameter `s_param_array'
insmod: can't insert 'param_demo.ko': Invalid argument
\