05、驱动模块传参
驱动模块传参是一种在内核开发中极为重要的技术,它允许开发者在运行时向内核模块动态传递和修改参数。这种灵活性不仅节省了频繁编译模块的时间,还显著提升了调试效率。例如,在嵌入式系统中,我们可以通过驱动模块传参来调整串口驱动的波特率、数据位数、校验位以及停止位等关键参数,从而快速验证不同配置下的功能表现。
一、驱动模块传参宏
Linux 内核为实现这一功能提供了三个主要宏:
module_param(name, type, perm)
该宏用于传递基本类型参数,如布尔型、整型、长整型及其无符号版本等。通过这种方式,我们可以轻松地将诸如设备编号、优先级或开关标志等信息传递给内核模块。module_param_array(name, type, num, perm)
当需要传递一组参数时,可以使用此宏。与module_param
不同的是,它额外支持一个num
参数,用于记录传递数组的元素个数。这使得处理多值输入变得简单而直观。module_param_string(name, string, len, perm)
此宏专门用于字符串类型的参数传递。由于字符串长度可能存在不确定性,因此需要指定最大长度以避免缓冲区溢出问题。
这些宏定义均位于内核源码中的 include/linux/moduleparam.h
文件内,并且由于 module.h
已经引用了 export.h
,所以在实际使用中无需单独包含 moduleparam.h
文件。
二、参数权限控制
为了确保系统的安全性与稳定性,每个通过上述宏传递的参数都需要设置其对应的权限属性(perm
)。这些权限决定了谁能够访问或修改该参数,并且它们遵循 Unix 文件权限模型。以下是常用的权限宏定义:
文件所有者相关权限
S_IRUSR (00400)
:文件所有者可读。S_IWUSR (00200)
:文件所有者可写。S_IXUSR (00100)
:文件所有者可执行。
同组用户相关权限
S_IRGRP (00040)
:与文件所有者同组的用户可读。S_IWGRP (00020)
:与文件所有者同组的用户可写。S_IXGRP (00010)
:与文件所有者同组的用户可执行。
其他用户相关权限
S_IROTH (00004)
:与其他用户可读。S_IWOTH (00002)
:与其他用户可写。S_IXOTH (00001)
:与其他用户可执行。
此外,也可以直接使用八进制数字表示权限,例如 S_IRUGO (0444)
表示所有用户均可读但不可写。
三、实验程序
C++
#include <linux/init.h>
#include <linux/module.h>
// 定义变量
static int number; // 整型变量
static char *name; // 字符指针
static int para[8]; // 数组
static char str1[10]; // 字符串
static int n_para; // 数组元素个数
// 使用宏进行参数传递
module_param(number, int, S_IRUGO); // 传递整型参数
module_param(name, charp, S_IRUGO); // 传递字符指针
module_param_array(para, int, &n_para, S_IRUGO); // 传递数组
module_param_string(str, str1, sizeof(str1), S_IRUGO); // 传递字符串
// 驱动入口函数
static int __init parameter_init(void) {
static int i;
// 打印传递的参数
printk(KERN_EMERG "Number: %d\n", number);
printk(KERN_EMERG "Name: %s\n", name);
for (i = 0; i < n_para; i++) {
printk(KERN_EMERG "Para[%d]: %d\n", i, para[i]);
}
printk(KERN_EMERG "String: %s\n", str1);
return 0;
}
static void __exit parameter_exit(void)//驱动出口函数
{
printk(KERN_EMERG "parameter_exit\n");
}
module_init(parameter_init);//注册入口函数
module_exit(parameter_exit);//注册出口函数
MODULE_LICENSE("GPL v2");//同意GPL开源协议
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
以上代码将传递 int 类型参数 number、 char 类型参数 name、 int 类型的数组 para 和 char类型字符串 str1, 并在驱动入口函数中, 对各个参数进行打印。
对应Makefile为:
C++
export ARCH=arm64
export CROSS_COMPILE=/home/book/rk/tspi/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
obj-m +=parameter.o #此处要和你的驱动源文件同名
KDIR := /home/book/rk/tspi/kernel #这里是你的内核目录
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules #make#操作
clean:
make -C $(KDIR) M=$(PWD) clean #make clean操作
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
parameter.ko 驱动加载可以传递 3 个参数, 分别为 int 类型的参数 number, char 类型的参数 name 和 int 数组类型的参数 para。 使用以下命令进行驱动的加载, 加载完成之后的打印信息如
四、实验
insmod parameter.ko number=100 name="linux" para=2,1,0 str="linux"