Linux驱动之模块参数——学习笔记(6)

469 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

在应用层的C程序都是通过 main 函数的参数进行传递参数。 在驱动层则是使用模块参数 进行参数传递。 由于最近项目需要用到,就学习记录一下。


一、宏及参数介绍

1、模块参数宏

模块参数宏常用的有两个, module_parammodule_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_strs_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

\