版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xi_xix_i/article/details/133974856
1. module_param()函数简介
一般在写代码的时候,如果是编译器中调试可以通过一些设置来传入命令行参数,比如用vscode的时候可以通过launch.json设置,运行编译好的文件时也可以通过终端命令行输入,但是对于不随内核启动的那些要编译成.ko的驱动程序来说的话是不好命令行参数的,但是使用module_param()这个函数就可以传入参数。这个函数其实是个宏定义,定义在moduleparam.h这个文件下:
* Standard types are:
* byte, short, ushort, int, uint, long, ulong
* charp: a character pointer
* bool: a bool, values 0/1, y/n, Y/N.
* invbool: the above, only sense-reversed (N = true).
*/
#define module_param(name, type, perm) \
module_param_named(name, name, type, perm)
这个函数一共三个参数,name
表示你要传入的参数名,type
表示你传入的参数的类型,perm
表示这个参数的权限,在后续第三节提到的创建了参数节点之后,该参数指定了用户、组、root不同的读写权限(还没搞很明白,后面再找找资料补充补充)。而且内核的注释把能使用这个函数传入的参数类型说的很明白了,注意是没有char
类型的,只有指向char的指针。
include/linux/moduleparam.h:146:25: 错误: ‘param_ops_char’未声明(不在函数内)
如果报了这个错,大概率就是传了char
类型的参数,因为我就是一开始没注意传了char
类型的参数报了这个错。
2. module_param()函数测试
写个驱动程序,测试一下module_param()的实际效果:
static int test_param1 = 1;
static char test_char = 'a';
static char *test_param2 = &test_char;
module_param(test_param1, int, 0644);
module_param(test_param2, charp, 0644); /* 内核版本高了之后传参的类型只能是charp,如果传char的话会报错 */
...
...
static int __init chrdevbase_init(void)
{
int ret = 0;
printk("test_param1: %d, test_param2: %c\r\n", test_param1, *test_param2); /* 打印一下两个参数 */
/* 注册字符设备驱动 */
ret = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops);
if (ret < 0)
{
printk("register failed\r\n");
}
printk("chrdevbase_init()\r\n");
return 0;
}
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lagransun");
当不传入参数的时候结果如下:
传入参数的结果如下所示:
3. /sys/module/下生成节点
在驱动程序中调用module_param()
这个函数之后,还会在/sys/module/下生成对应的节点(如果perm
为0,则不会生成节点),可以根据当时传入的第三个参数perm
(权限),来对创建的参数节点进行读写,生成的节点的位置如下所示:
对该参数节点进行读写测试:
内核到底是通过怎么一个过程把传入的参数转化为/sys/module/下的参数节点的,还没深入研究,后续有时间还是要深入研究下的。