Linux设备驱动系列(三)——参数传递 1 模块参数宏 2

关注微信公众号:Linux内核拾遗

文章来源:mp.weixin.qq.com/s/ach-ex8gq…

在C语言应用程序中,可以通过在main函数定义中添加argc和argv参数来获取用户的输入。类似的,Linux设备驱动程序同样可以传递参数。本文将介绍Linux设备驱动程序中参数定义以及使用方法。

1 模块参数宏

Linux头文件”linux/module.h”提供了多个宏来声明内核模块的参数及其读写权限。

  • S_IWUSR、S_IRUSR、S_IXUSR;
  • S_IRGRP、S_IWGRP、S_IXGRP。

其中,R/W/X分别表示读、写和执行权限,USR/GRP分别表示用户和用户组。

允许通过”|”运算符来同时设置多个权限。

下面将简要介绍模块参数宏的使用方法,这些宏都在”linux/moduleparam.h”中定义。

1.1 module_param()

module_param()宏有三个参数:参数名,参数类型,以及参数权限掩码。

1
scss复制代码 module_param(name, type, perm);

定义的模块参数可以在”/sys/module/<module_name>/parameters/“下面找到。

1
2
scss复制代码 // /sys/module/my_driver/parameters/my_param
 module_param(my_param, int, S_IWUSR|S_IRUSR);

模块参数类型有以下几种:

  1. 布尔类型:bool,invbool;
  2. 字符指针类型:charp;
  3. 基本整型类型:int,long,short,uint,ulong,ushort。

1.2 module_param_array()

module_param_array()宏用于声明以”,”分隔的数组类型的参数:

1
scss复制代码 module_param_array(name, type, num, perm);

1.3 module_param_cb()

module_param_cb()宏用于注册一个回调函数,当参数取值改变时被调用。最常见的应用场景是在内核模块运行期间动态修改其配置。

如果用module_param_cb()声明一个具有可写权限的模块参数,当内核模块插入内核后,可以通过网对应的sysfs文件写入值来修改模块参数的取值,例如”echo 1 > /sys/module/my_driver/parameters/my_param”,那么注册的回调函数将会被调用。

1
2
3
4
5
6
7
8
c复制代码 struct kernel_param_ops
 {
   int (*set)(const char *val, const struct kernel_param *kp);
   int (*get)(char *buffer, const struct kernel_param *kp);
   void (*free)(void *arg);
 };
 
 module_param_cb(name, ops, param_ptr, perm);

module_param_cb()接收一个struct kernel_param_ops类型的参数作为模块参数的回调函数。

2 示例:Linux设备驱动参数传递

下面是一个简单的Linux设备驱动参数传递的示例代码,定义了4个模块参数:

module_param.c

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
41
42
43
44
45
46
47
48
49
50
51
52
arduino复制代码 #include<linux/kernel.h>
 #include<linux/init.h>
 #include<linux/module.h>
 #include<linux/moduleparam.h>
 
 int int_param, arr_param[4];
 char *str_param;
 int cb_param = 0;
 
 module_param(int_param, int, S_IRUSR|S_IWUSR);
 module_param(str_param, charp, S_IRUSR|S_IWUSR);                     
 module_param_array(arr_param, int, NULL, S_IRUSR|S_IWUSR);
 
 int notify_param(const char *val, const struct kernel_param *kp)
 {
   int res = param_set_int(val, kp);
   if(res == 0) {
     pr_info("New value of cb_param = %d\n", cb_param);
     return 0;
  }
   return -1;
 }
 const struct kernel_param_ops my_param_ops =
 {
  .set = &notify_param,
  .get = &param_get_int,
 };
 module_param_cb(cb_param, &my_param_ops, &cb_param, S_IRUGO|S_IWUSR );
 
 static int __init hello_world_init(void)
 {
   int i;
   pr_info("int_param = %d\ncb_param = %d\nstr_param = %s\n",
          int_param, cb_param, str_param);
   for (i = 0; i < ARRAY_SIZE(arr_param); i++)
     pr_info("arr_param[%d] = %d\n", i, arr_param[i]);
   pr_info("Kernel Module Inserted!\n");
   return 0;
 }
 
 static void __exit hello_world_exit(void)
 {
     pr_info("Kernel Module Removed!\n");
 }
 
 module_init(hello_world_init);
 module_exit(hello_world_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("feifei <feifei@gmail.com>");
 MODULE_DESCRIPTION("A simple linux device driver");
 MODULE_VERSION("1.0");

说明:如果不特别注明,示例代码均采用前文的示例Makefile文件(修改相应的.o文件名即可),这里不再重复给出。

最后编译运行,输出如图:

image-20240423232537367

关注微信公众号:Linux内核拾遗

文章来源:mp.weixin.qq.com/s/ach-ex8gq…

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%