浅谈linux - 模块传参

概述

在实际应用中,模块和程序往往需要适应各种系统环境,针对不同环境,参数往往也会有所不同,为了提高灵活性,我们可以将参数从外部传入,让其适应更多系统和环境。

应用程序

众所周知,应用程序的入口函数为main函数,而main函数原型为:int main(int argc, char* argv[])。应用程序参数传入后,由argc和argv变量记录。其中argc存储参数个数,argv存储参数集合。

注意:应用程序将所有参数均存储为字符串类型,存放在argv参数中。具体见以下示例。

/**
 * @Filename : app_para.c
 * @Revision : $Revision: 1.00 $
 * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅)
 * @Description : 应用程序传参示例
**/

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    int a;    
    int b;  

    if (argc != 3) {    
        printf("Usage: %s <a> <b>\n",  argv[0]);    
        return -1;    
    }       
    /* 将字符串转整型: 如 "20" -> 20  */     
    a = strtoul(argv[1], NULL, 0);    
    b = strtoul(argv[2], NULL, 0); 

    printf("%d + %d = %d\n", a, b, a+b);     

    return 0;    
}

测试:在终端通过命令编译程序,然后执行程序并传入参数。

feng:drv_para$ gcc -o app app_para.c 
feng:drv_para$ ./app 6 12
6 + 12 = 18
feng:drv_para$ 

结论:示例接收来自命令行传入的参数(6,12)后,将其转换为整型,执行加法处理后输出结果(18)。

feng:drv_para$ ./app 6 12 
执行后:
argc = 3
argv[0] = ./app
argv[1] = 6
argv[2] = 12

内核模块

与应用程序不同,内核模块传参主要通过宏函数module_parammodule_param_array实现,在头文件linux/modulepara.h中定义。

/**
 * @传递参数
 * @name:参数名字   type:参数类型       perm:权限
**/
#define module_param(name, type, perm)                \
    module_param_named(name, name, type, perm)

/**
 * @传递数组参数
 * @name:数组名字   type:数组类型       nump:保存数组个数     perm:权限
**/
#define module_param_array(name, type, nump, perm)        \
    module_param_array_named(name, name, type, nump, perm)

内核模块支持的参数类型:

bool/invbool    /* 布尔值,invbool表示反转bool值,即true变false) */
charp           /* 字符串指针值 */
int/uint        /* 整型/无符号整型 */
short/ushort    /* 短整型/无符号短整型 */
long/ulong      /* 长整型/无法好长整型 */

参数权限:在linux/stat.h头文件中定义,用户大多数情况下指定为只读(S_IRUGO)即可。

/**
 * @读写权限,位置:linux/stat.h
**/

#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100

#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010

#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001

#define S_IRWXUGO    (S_IRWXU|S_IRWXG|S_IRWXO)   /* 读/写/执行 */
#define S_IALLUGO    (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO)
#define S_IRUGO      (S_IRUSR|S_IRGRP|S_IROTH)   /* 只读,绝大多数选择 */
#define S_IWUGO      (S_IWUSR|S_IWGRP|S_IWOTH)   /* 只写 */
#define S_IXUGO      (S_IXUSR|S_IXGRP|S_IXOTH)   /* 只能执行 */

在传递数组参数时,nump用于存储实际传入数组元素个数。

示例

★包含源文件drv_para.c和源文件Makefile(均已验证通过)。

 drv_para.c

/**
 * @Filename : drv_para.c
 * @Revision : $Revision: 1.00 $
 * @Author : Feng(更多编程相关的知识和源码见微信公众号:不只会拍照的程序猿,欢迎订阅)
 * @Description : 驱动模块传参示例
**/

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

/* 定义全局变量 */
static int val; 
static char *ps;
static int buf[5] = {0, 1, 2, 3, 4};
static int num = 1;

/* 传參声明 */
module_param(val, int, S_IRUGO);
module_param(ps, charp, S_IRUGO);
module_param_array(buf , int , &num , S_IRUGO);

/* 驱动加载时执行,调用insmod或者modprobe加载驱动 */
static int __init drv_para_init(void)
{
    int i;

    printk("hello : drv_para_init val[%d] ps[%s] buf[ ", val, ps);
    for (i=0; i<num; i++) 
        printk("%d ", buf[i]);
    printk("]\n");

    return 0;
}

/* 驱动卸载时执行,调用rmsmod或者modprobe -r卸载驱动 */
static void __exit drv_para_exit(void)
{
    printk("bye : drv_para_exit\n");
}

module_init(drv_para_init);     /* 指定入口函数 */
module_exit(drv_para_exit);     /* 指定出口函数 */

MODULE_LICENSE("GPL");          /* 模块的许可证声明 */

/* 调用modinfo xx(模块名)查看 */
MODULE_AUTHOR("feng");          /* 模块的作者 */
MODULE_VERSION ("1.00");        /* 模块版本号 */
/* MODULE_DESCRIPTION("xxxxx");    模块描述 */
/* MODULE_ALIAS("xxx");            模块别名 */

 Makefile

#根文件所在目录
ROOTFS_DIR = /home/feng/atomic/rootfs

#交叉编译工具链
CROSS_COMPILE = arm-linux-gnueabihf-
CC = $(CROSS_COMPILE)gcc

#驱动目录路径
DRV_DIR = $(ROOTFS_DIR)/home/drv
DRV_DIR_LIB = $(ROOTFS_DIR)/lib/modules/4.1.15

#KERNELRELEASE由内核makefile赋值
ifeq ($(KERNELRELEASE), )

#内核路径
KERNEL_DIR =/home/feng/atomic/resource/linux-imx-rel_imx_4.1.15_2.1.0_ga

#当前文件路径
CURR_DIR = $(shell pwd)

all:
    #编译模块
    make -C $(KERNEL_DIR) M=$(CURR_DIR) modules

clean:
    #清除模块文件
    make -C $(KERNEL_DIR) M=$(CURR_DIR) clean

install:
    #拷贝模块文件
    cp -raf *.ko $(DRV_DIR_LIB)

else
#指定编译什么文件
obj-m += drv_para.o

endif

结论

1、进入目录,执行make命令编译模块;然后执行make install命令,拷贝模块到目标机指定目录。

feng:drv_para$ make
#编译模块
make -C /home/feng/atomic/resource/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/mnt/hgfs/Share/linux/atomic/driver/drv_para modules
make[1]: 进入目录“/home/feng/atomic/resource/linux-imx-rel_imx_4.1.15_2.1.0_ga”
  CC [M]  /mnt/hgfs/Share/linux/atomic/driver/drv_para/drv_para.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /mnt/hgfs/Share/linux/atomic/driver/drv_para/drv_para.mod.o
  LD [M]  /mnt/hgfs/Share/linux/atomic/driver/drv_para/drv_para.ko
make[1]: 离开目录“/home/feng/atomic/resource/linux-imx-rel_imx_4.1.15_2.1.0_ga”
feng:drv_para$ make install 
#拷贝模块文件
cp -raf *.ko /home/feng/atomic/rootfs/lib/modules/4.1.15
feng:drv_para$ 

2、在目标机上执行modprobe命令加载模块,并传入参数。

注意:若未传入参数,程序使用代码里定义的初始值

/ # modprobe drv_para.ko val=7 ps=seven buf=3,2,5,6,7
hello : drv_para_init val[7] ps[seven] buf[ 3 2 5 6 7 ]
/ # 

3、在目标机上执行modprobe -r命令卸载模块。

/ # modprobe -r drv_para.ko
bye : drv_para_exit
/ # 

4、综上、加载模块的时候,用户通过命令行传入参数val、ps、buf,模块接收到参数后,输出对应的值,从而验证外部传参是否正确。

往期 · 推荐

帮你自动化办公的python-自动提取pdf指定页(文件处理篇)

帮你自动化办公的python-自动提取pdf指定页(项目概述)

也没想象中那么神秘的数据结构-一种通用化的双向链表设计(底层源码)

也没想象中那么神秘的数据结构-一环扣一环的“链表”(双向链表)

我用C语言玩对象,偷偷关注着你的观察者模式(基类设计)

关注

更多精彩内容,请关注微信公众号:不只会拍照的程序猿,本人致力分享linux、设计模式、C语言、嵌入式、编程相关知识,也会抽空分享些摄影相关内容,同样也分享大量摄影、编程相关视频和源码,另外你若想要本文章源码请关注公众号:不只会拍照的程序猿,后台回复:linux驱动源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不只会拍照的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值