简单的驱动模块及参数传递

简单的驱动模块及参数传递https://mp.weixin.qq.com/s?__biz=Mzg3NDkwMjc2NA==&mid=2247483788&idx=1&sn=3fb26a53b5dc688a2cd749860387f655&chksm=cec8e40ff9bf6d195369b20c2e62ef147df0a5fa1a03462e2502f10be71faa4ec3966ba354ec#rd

 本文将简单介绍如何编写一个简单的驱动模块,并介绍如何向驱动模块传递参数的方法。

模块参数

在进行驱动模块设计时,可通过参数传递动态配置驱动模块,以达到灵活配置的目的。

如需要设计一个复杂的驱动模块,有些参数需要软件动态配置。

那么就可以定义一个配置文件,把这个配置文件的路径传递给模块。在驱动模块加载时,根据配置文件定义的参数,配置当前的驱动模块,以达到灵活配置的目的。

如何向模块传递参数?

Linux kernel 提供了一个简单的框架。

//include/linux/moduleparam.h
/**
 * module_param - typesafe helper for a module/cmdline parameter
 * @value: the variable to alter, and exposed parameter name.
 * @type: the type of the parameter
 * @perm: visibility in sysfs.
 *
 * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
 * ".") the kernel commandline parameter.  Note that - is changed to _, so
 * the user can use "foo-bar=1" even for variable "foo_bar".
 *
 * @perm is 0 if the the variable is not to appear in sysfs, or 0444
 * for world-readable, 0644 for root-writable, etc.  Note that if it
 * is writable, you may need to use kernel_param_lock() around
 * accesses (esp. charp, which can be kfreed when it changes).
 *
 * The @type is simply pasted to refer to a param_ops_##type and a
 * param_check_##type: for convenience many standard types are provided but
 * you can create your own by defining those variables.
 *
 * 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)

/**
 * module_param_named - typesafe helper for a renamed module/cmdline parameter
 * @name: a valid C identifier which is the parameter name.
 * @value: the actual lvalue to alter.
 * @type: the type of the parameter
 * @perm: visibility in sysfs.
 *
 * Usually it's a good idea to have variable names and user-exposed names the
 * same, but that's harder if the variable must be non-static or is inside a
 * structure.  This allows exposure under a different name.
 */
#define module_param_named(name, value, type, perm)                        \
        param_check_##type(name, &(value));                                \
        module_param_cb(name, &param_ops_##type, &value, perm);            \
        __MODULE_PARM_TYPE(name, #type)


//<perm>,sysfs入口项的访问许可掩码,在<linux/stat.h>中定义。
#define S_IRUSR 00400 文件所有者可读
#define S_IWUSR 00200 文件所有者可写
#define S_IXUSR 00100 文件所有者可执行
#define S_IRGRP 00040 与文件所有者同组的用户可读
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IROTH 00004 与文件所有者不同组的用户可读
#define S_IWOTH 00002
#define S_IXOTH 00001

传递单个参数

static unsigned int val = 0;        //声明变量
module_param(val, uint, S_IRUGO);   //定义参数
  • val,参数名

  • uint,表示参数的数据类型,是下列之一:byte, short, ushort, int, uint, long, ulong, charp, bool, invbool

  • S_IRUGO,指定了在sysfs中相应文件的访问权限。访问权限与linux文件访问权限相同的方式管理,如0644,或使用stat.h中的宏如S_IRUGO表示。0 表示完全关闭在sysfs中相对应的项。

传递多个参数 

static int val[NUM];
static int n_val;
module_param_array(val, int, &n_val, S_IRUGO);
  • val,参数数组,数组的大小决定能输入多少个参数

  • n_val,参数个数,最终传递数组元素个数存在n_val中

  • int,数据类型

  • S_IRUGO,sysfs的访问权限

模块的装载/卸载 

insmod <module> <opt: parm1> <opt: parm2>
modprobe <module> <opt: parm1> <opt: parm2>
rmmod <module>

modprobe

modprobe和insmod功能相似。

modprobe除了会装载指定模块之外还会装载指定模块所依赖的其他模块。modprobe只能从标准已安装模块目录中搜索需要装载的模块,因此需要将驱动拷贝到/lib/modules/$(uname -r)/目录下。

简单的示例

源码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/moduleparam.h>

/* FUNCTION CONTROL */
#define TOM_MOD_PARM
/* FUNCTION CONTROL END */
static char* name = "Tom";
#ifdef TOM_MOD_PARM
module_param(name, charp, 0644);
#endif

//使用__init修饰的函数表明该函数仅在初始化阶段有效,初始化结束后释放该函数所占用的资源。
static int __init hello_init(void)
{
    printk(KERN_WARNING "Hello %s!\n", name);
    printk(KERN_WARNING "Nice to meet you!\n");

    //打印当前进程及进程ID
    printk(KERN_INFO "This process is \"%s\" (pid %i) \n", current->comm, current->pid);
    return 0;
}
//使用__exit修饰的函数会链接到指定的elf段,表明该函数仅用于模块卸载。
static void __exit hello_exit(void)
{
    //打印当前进程及进程ID
    printk(KERN_INFO "This process is \"%s\" (pid %i) \n", current->comm, current->pid);
    printk(KERN_WARNING "Goodbye! %s!\n", name);
    return;
}

module_init(hello_init);  //注册入口函数
module_exit(hello_exit);  //注册出口函数

MODULE_LICENSE("GPL");

 编译Makefile

KERNEL_DIR=/<path>/linux-4.1.15
CROSS_COMPILE=arm-none-eabi-
ARCH=arm

obj-m := hello.o

# -C 指定内核源码路径
# -M 指定构造modules目标的源代码所在的目录
# modules 目标指向obj-m变量中设定的模块
all:
make -C $(KERNEL_DIR) M=`pwd` modules
rm *.o *.order .*.cmd *.mod.c *.mod.o .tmp_versions -rf 

clean:
rm *.o *.ko *.order *.symvers .*.cmd *.mod.c *.mod.o  .tmp_versions -rf

 加载模块

# insmod hello.ko 
[10689.134471] Hello Tom!
[10689.137296] Nice to meet you!
[10689.140282] This process is "insmod" (pid 236) 
# 
# rmmod hello.ko 
[10694.632803] This process is "rmmod" (pid 237) 
[10694.637496] Goodbye! Tom!

结束语

希望本文可以帮助到大家!

如需获取文中的测试程序源码,可通过后台回复获取!水平有限,如有错漏的地方请不吝指出,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值