关注微信公众号:Linux 内核拾遗
文章来源:https://mp.weixin.qq.com/s/ach-ex8gqs7l_q6mQn6rwg
在 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()宏有三个参数:参数名,参数类型,以及参数权限掩码。
module_param(name, type, perm);
复制代码
定义的模块参数可以在"/sys/module//parameters/"下面找到。
// /sys/module/my_driver/parameters/my_param
module_param(my_param, int, S_IWUSR|S_IRUSR);
复制代码
模块参数类型有以下几种:
布尔类型:bool,invbool;
字符指针类型:charp;
基本整型类型:int,long,short,uint,ulong,ushort。
1.2 module_param_array()
module_param_array()宏用于声明以","分隔的数组类型的参数:
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",那么注册的回调函数将会被调用。
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
#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 = ¬ify_param,
.get = ¶m_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 文件名即可),这里不再重复给出。
最后编译运行,输出如图:
关注微信公众号:Linux 内核拾遗
文章来源:https://mp.weixin.qq.com/s/ach-ex8gqs7l_q6mQn6rwg
评论