简单入门linux设备驱动之第三部分:向设备驱动程序传递参数

摘要:
现在让我们学习“Linux设备驱动程序第3部分:向设备驱动程序传递参数”。内容概述·1 linux设备驱动程序第3部分:向设备驱动程序传输参数·2模块参数宏·2.1模块_参数()·2.2模块_参数_数组()·2.3模块_参数_Cb()·2.3.1何时需要通知·3编程·4编译·5加载设备驱动程序·6使用dmesg命令验证参数·7卸载设备驱动程序在同一程序中,我们可以将参数传递给任何函数。

声明:内容搬自阿三哥网站,只是翻译了一下。侵删。https://embetronicx.com/tutorials/linux/device-drivers/

正文如下:

这是“linux设备驱动系列”的教程。本系列的目的是提供简单实用的示例,使每个人都能以简单的方式理解这些概念。现在让我们即将学习“linux设备驱动第三部分:向设备驱动程序传递参数”。

内容速览

·1 linux设备驱动第三部分:向设备驱动程序传递参数

·2 模块参数宏

  ·2.1 module_param()

  ·2.2 module_param_array()

  ·2.3 module_param_cb()

  ·2.3.1 我们什么时候需要通知(notification)?

·3 编程
·4 编译
·5 加载设备驱动程序
·6 使用 dmesg 命令验证参数
·7 卸载设备驱动程序

 

·1 linux设备驱动第三部分:向设备驱动程序传递参数

在同一个程序中,我们可以向任何函数传递参数。但是有没有可能向任意程序传递参数呢?我觉得可能有。对吗?是的,我们可以。在C语言的编程中,我们可以向程序传递参数。为了实现这个功能,我们需要在main()函数的定义中添加 argc 和 argv ;我想大家应该都知道这个。现在回到我们的话题,我们能够向设备驱动程序传递参数吗?好的,在这一小节的教程中,我们会关注这个话题。

·2 模块参数宏

·module_param()

·module_param_array()

·module_param_cb()

在讨论这些宏之前,我们必须要先了解变量的权限。

权限有以下几种类型:

·S_IWUSR

·S_IRUSR

·S_IXUSR

·S_IRGRP

·S_IWGRP

·S_IXGRP

其中的 S_I 是公共的头(header)。

R = 读(read),W = 写(write),X = 执行(execute)。

USR = 用户(user),GRP = 组(group)

使用或运算符“|”我们可以一次设置多个权限。

·2.1 module_param()

这个宏用来初始化变量。module_param()需要三个参数:变量名、变量的类型、变量在sysfs入口的权限。这个宏应该放在函数的外部;通常是放在源文件的头部附近。module_param()宏定义在linux/moduleparam.h中。

        module_param(name, type, perm);【perm-->permission】

module_param()宏会在/sys/module目录下创建一个下级目录。举个栗子:

        module_param(valueETX, int, S_IWUSR|S_IRUSR);

它会创建一个sysfs入口。(/sys/module/hello_world_module/parameters/valueETX)

模块参数支持很多种参数类型:

·bool  布尔变量(true/false)。

·invbool  invbool类型取布尔类型的相反值,比如true值会变成false值,false值会变成true值。

·charp  字符指针(char pointer)变量。系统会给用户提供的字符串分配内存,指针也被相应的赋值。

·int

·long

·short

·uint

·ulong

·ushort  不同长度的基本整数类型。u开头的变量表示为无符号值。

·2.2 module_param_array()

这个宏可以使用数组来传递参数。模块加载器支持数组参数;参数的值之间由逗号分隔。声明一个数组:

        module_param_array(name, type, num, perm);

其中:name--数组的名字,

   type--数组元素的类型,

   num--一个整数变量值(可选),不配置时使用NULL,

   perm--权限配置。

·2.3 module_param_cb()

这个宏用来注册参数被改变时的回调函数(callback)。我猜你可能不太能理解。让我来解释一番。

举个栗子,

我用module_param()函数创建了一个参数。

module_param(valueETX, int, S_IWUSR|S_IRUSR);

你可以在命令行改变valueETX的值,如下:

>>sudo su
>>echo 1 > /sys/module/hello_world_module/parameters/valueETX

它会更新变量valueETX的值。但是没有办法通知你的模块:valueETX的值已经改变了。

使用module_param_cb(),我们就能收到通知。

如果你想你的变量发生改变时你能收到通知,我们就需要注册我们的处理函数到文件操作结构体中。

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);
};

 更详细的解释请参考之后的程序。

·2.3.1 我们什么时候需要通知(notification)?

我来告诉你实际应用场景。无论什么时候变量被置为1,你都必须往硬件寄存器写入一些东西。如果改变了变量但是没有人通知你你要怎么办呢?我想你应该明白了。如果你还没理解,请看下面的解释吧。

·3 编程

在这个例子里,我们解释了一切(module_param, module_param_array, module_param_cb)。

对于module_param(),我创建了两个变量。一个是整数(valueETX),另一个是字符串(namaETX)。

对于module_param_array(),我创建了一个整数数组变量(arr_valueETX)。

对于module_param_cb(),我创建了一个整数变量(cb_valueETX)。

你可以使用sysfs入口改变所有变量的值,入口位于/sys/module/hello_world_module/parameters/目录下。

但是你改变时不会受到任何通知,除了你使用module_param_cb()宏创建的变量。

github上获取源代码

/***************************************************************************//**
*  file       hello_world.c
*
*  details    Simple hello world driver
*
*  author     EmbeTronicX
*
* *******************************************************************************/
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/moduleparam.h>
 
int valueETX, arr_valueETX[4];
char *nameETX;
int cb_valueETX = 0;
 
module_param(valueETX, int, S_IRUSR|S_IWUSR);                      //integer value
module_param(nameETX, charp, S_IRUSR|S_IWUSR);                     //String
module_param_array(arr_valueETX, int, NULL, S_IRUSR|S_IWUSR);      //Array of integers
 
/*----------------------Module_param_cb()--------------------------------*/
int notify_param(const char *val, const struct kernel_param *kp)
{
        int res = param_set_int(val, kp); // Use helper for write variable
        if(res==0) {
                printk(KERN_INFO "Call back function called...
");
                printk(KERN_INFO "New value of cb_valueETX = %d
", cb_valueETX);
                return 0;
        }
        return -1;
}
 
const struct kernel_param_ops my_param_ops = 
{
        .set = &notify_param, // Use our setter ...
        .get = &param_get_int, // .. and standard getter
};
 
module_param_cb(cb_valueETX, &my_param_ops, &cb_valueETX, S_IRUGO|S_IWUSR );
/*-------------------------------------------------------------------------*/

/*
** Module init function
*/
static int __init hello_world_init(void)
{
        int i;
        printk(KERN_INFO "ValueETX = %d  
", valueETX);
        printk(KERN_INFO "cb_valueETX = %d  
", cb_valueETX);
        printk(KERN_INFO "NameETX = %s 
", nameETX);
        for (i = 0; i < (sizeof arr_valueETX / sizeof (int)); i++) {
                printk(KERN_INFO "Arr_value[%d] = %d
", i, arr_valueETX[i]);
        }
        printk(KERN_INFO "Kernel Module Inserted Successfully...
");
    return 0;
}

/*
** Module Exit function
*/
static void __exit hello_world_exit(void)
{
    printk(KERN_INFO "Kernel Module Removed Successfully...
");
}
 
module_init(hello_world_init);
module_exit(hello_world_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeTronicX <embetronicx@gmail.com>");
MODULE_DESCRIPTION("A simple hello world driver");
MODULE_VERSION("1.0");

·4 编译

Makefile代码如下

obj-m += hello_world_module.o

KDIR = /lib/modules/$(shell uname -r)/build

all:
    make -C $(KDIR)  M=$(shell pwd) modules

clean:
    make -C $(KDIR)  M=$(shell pwd) clean

在终端输入 sudo make

简单入门linux设备驱动之第三部分:向设备驱动程序传递参数第1张

·5 加载设备驱动程序

 sudo insmod hello_world_module.ko valueETX=14 nameETX="EmbeTronicX" arr_valueETX=100,102,104,106

 简单入门linux设备驱动之第三部分:向设备驱动程序传递参数第2张

·6 使用 dmesg 命令验证参数

 现在我们的模块已经加载好了。使用 dmesg 命令查看。下面的图片中,每个值都被传递到了我们的设备驱动程序中。

 简单入门linux设备驱动之第三部分:向设备驱动程序传递参数第3张

 现在我们来检验一下module_param_cb()是否被调用。为此,我要在sysfs中改变变量的值。你有两种方法来写这个变量。

1. sudo sh -c "echo 13 > /sys/module/driver/parameters/cb_valueETX"

2. 输入 sudo su 。输入密码如果需要的话。然后输入  echo 13 > /sus/module/hello_world_module/parameters/cb_valueETX

简单入门linux设备驱动之第三部分:向设备驱动程序传递参数第4张

现在使用 demsg 命令检验。

简单入门linux设备驱动之第三部分:向设备驱动程序传递参数第5张

 结果如上。我们的回调函数已经被调用了。但是你改变其他变量的值,你却不会收到通知。

 ·7 卸载设备驱动程序

 最后使用命令 sudo rmmod hello_world_module 卸载驱动程序。

---------------------分割线-------------------

我希望大家都已经理解了。如果你有任何疑问,请在下面评论。在下一小节中,我们会了解linux设备驱动程序中的major号和minor号。

免责声明:文章转载自《简单入门linux设备驱动之第三部分:向设备驱动程序传递参数》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇js保持div悬浮,不随页面向下滚动而被覆盖Eclipse+APKTool动态调试APK下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

linux 系统时间与硬件时间与中国标准时间

转载原文: https://blog.csdn.net/tvk872/article/details/82957445 Linux下设置时区 提供两种最根本有效的方式,就是更改时区。这里以更改为国内上海时间例子,其他地方时区同理。 方法一 备份文件mv /etc/localtime /etc/localtime.bak 复制时区文件cp /usr/sh...

Linux用户空间与内核地址空间

Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中。 Linux内核地址映射模型 x86 CPU采用了段页式地址映射模型。进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内...

linux下find查找命令用法

转自http://www.jb51.net/os/RedHat/1307.html Linux下find命令在目录结构中搜索文件,并执行指定的操作。Linux下find命令提供了相当多的查找条件,功能很强大。由于find具有强大的功能,所以它的选项也很多,其中大部分选项都值得我们花时间来了解一下。即使系统中含有网络文件系统( NFS),find命令在该文件...

Linux中Cron任务间隔执行:每隔几分钟/几小时/几天

一、配置   1)全局用户配置文件(/etc/crontab)   直接VI等编辑就可以。   2)个人用户配置(临时配置)      加任务:     crontab -e     0 */1 * * * command     0 */2 * * * command   查询任务是否加了:     crontab -l     0 */1 * * *...

linux下磁盘爆满问题排查

排查服务器硬盘占用情况 切换到根目录查看磁盘使用率 df -h根据mounted on 来确定哪里占用比较高,比如根目录/查看根目录占用情况 : du -h -d1 /以此类推,du -h -d1 可查看当前文件夹下所有文件的占用 由此一步步往下查看  最终锁定到/app/remote-hawk-dc/logs/debug 文件下 删除/app/remot...

buildroot 制作Linux文件系统初级使用教程

buildroot 下载地址:https://buildroot.org/download.html 放在Linux文件下解压出来。 使用make menuconfig 进行配置相关的东西。 在使用这条命令之前,首先要安装相关的东西。 运行如下命令进行安装相关的库文件,我的是在Ubuntu14.04的环境下进行的。 sudo apt-get install...