关注微信公众号: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_parammodule_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
评论