Linux bsp驱动学习三:模块参数和模块之间通信 为了增加模块的灵活性,可以给模块添加参数。模块参数可以控制模块的内部逻辑,从而使模块在不同的情况下,完成不同的功能,简单的说,模块参数就像函数的参数一样。
一、模块参数 用户空间的应用程序可以接受用户的参数,设备驱动程序有时候也需要接受参数。
例如一个模块可以实现两种相似的功能,这时可以传递一个参数到驱动模块,以决定其使用哪一种功能。参数需要在加载模块时指定,
例如 inmod xxx.ko param=1。
可以用“module_param(参数名,参数数据类型,参数读写权限)”来为模块定义个参数
1 2 3 4 static long a = 1 ;static int b = 1 ;module_param(a, long , S_IRUGO); module_param(b, int , S_IRUGO);
参数数据类型可以是 byte、short、ushort、int、uint、long、ulong、bool 和 charp(字符指针类型)。模块参数的类型中没有浮点类型,因为通常不在内核中使用浮点数。。
二、模块的文件格式ELF 了解模块以何种格式存储在硬盘中,对于理解模块间怎样通信是非常有必要的。使用 file 命令可以知道 hello.ko 模块使用的是 ELF 文件格式,命令如下:
1 2 root@igkboard:~/workdir/01# file kernel_hello.ko kernel_hello.ko: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), BuildID[sha1]=e83d8bb2113c7027d689b7ecc1a5eb995389532d, not stripped
下表描述的是ELF目标文件的总体结构。省去了ELF 一些繁琐的结构,把最主要的结构提取出来,形成了下表的文件基本结构图
ELF 文件基本结构图
ELF Header
.text
.data
其他
.Section Table
.symtab
其他
ELF Header 头位于文件的最前部。其包含了描述整个文件 的基本属性,例如 ELF 文件版本、目标机器型号、程序入 口地址等。
.text 表示代码段,存放文件的代码部分。
.data 表示数据段,存放已经初始化的数据等。
.Section Table 表描述了 ELF 文件包含的所有段的信息,例如每个段的段名、段的长度、在文件中的偏移、读写权限及段的其他属性。
.symtab 表示符号表。符号表是一种映射函数到真实内存地址的数据结构。其就像一个字典,其记录了在编译阶段,无法确定地址的函数。该符号表将在模块文件加载阶段,由系统赋予真实的内存地址。
三、模块之间的通信 模块是为了完成某种特定任务而设计的。其功能比较单一,为了丰富系统的功能,所以模块之间常常进行通信。它们之间可以共享变量、数据结构,也可以调用对方提供的功能函数。
模块2的加载过程为:
1. 使用insmod 模块2.ko加载模块2.
2. 内核为模块2分配空间,然后将模块的代码和数据装入分配内存中。
3. 内核发现符号表中有函数1,函数2可以导出,于是将其内存地址记录在内核符号表中
等到模块1加载进内核时,系统会执行以下操作:
insmod命令会为模块分配空间,然后将模块的代码和数据装入内存中去。
内核在模块1的符号表(symtab)中发现一些未解析的函数,而这些函数的定义位于模块2的代码中。所以模块1会通过内核符号表,查找到相应的函数,并将函数地址填到模块1的符号表中。
于是,通过模块1加载的过程之后,模块1就可以使用模块2提供的“函数1”和”函数2”了
四、模块中间的通信实例 本实例通过两个模块介绍模块之间的通信。模块 add_sub 提供了两个导出函数 add_integer()和 sub_integer(),分别完成两个数字的加法和减法。模块 test 用来调用模块 add_sub 提供的两个方法,完成加法或者减法操作。
工程截图
1、add_sub模块 模块 add_sub 中提供了一个加法函数和一个减法函数,其 add_sub.c 文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <linux/init.h> #include <linux/module.h> #include "add_sub.h" long add_integer (long a, long b) { return a+b; } long sub_integer (long a, long b) { return a-b; } EXPORT_SYMBOL(add_integer); EXPORT_SYMBOL(sub_integer); MODULE_LICENSE("Dual BSD/GPL" ); MODULE_AUTHOR("NongJieYing <njy_roxy@outlook.com>" );
add_sub.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #ifndef _ADD_SUB_H_ #define _ADD_SUB_H_ long add_integer (long a, long b) ; long sub_integer (long a, long b) ; #endif
对add_sub.c的Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 KERNEL_DIR := /home/noah/imx6ull/bsp/kernel/linux-imx PWD :=$(shell pwd) appname += add_sub obj-m := $(appname) .o PRINC_INC = $(PWD) EXTRA_CFLAGS += -I $(PRINC_INC) modules: $(MAKE) -I $(PRINC_INC) -C $(KERNEL_DIR) M=$(PWD) modules @make clear clear: @rm -f *.o *.cmd *.mod *.mod.c @rm -rf *~ core .depend .tmp_versions modules.order -f @rm -f .*ko.cmd .*.o.cmd .*.o.d @rm -f *.unsigned clean: @rm -f *.ko
2、test模块 test.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <linux/init.h> #include <linux/module.h> #include "add_sub.h" static long a =1 ; static long b =1 ; static int AddOrSub = 1 ;static __init int test_init (void ) { long result = 0 ; printk(KERN_ALERT "test init\n" ); if (AddOrSub == 1 ) { result = add_integer(a, b); } else { result = sub_integer(a, b); } printk(KERN_ALERT "The %s result is %ld\n" , AddOrSub==1 ?"Add" :"Sub" , result); return 0 ; } static __exit void test_exit (void ) { printk(KERN_ALERT "test exit\n" ); } module_init(test_init); module_exit(test_exit); module_param(a, long , S_IRUGO); module_param(b, long , S_IRUGO); module_param(AddOrSub, int , S_IRUGO); MODULE_LICENSE("Dual BSD/GPL" ); MODULE_AUTHOR("NongJieYing <njy_roxy@outlook.com>" ); MODULE_DESCRIPTION("The module for testing module params and EXPORT_SYMBOL" ); MODULE_VERSION("V1.0" );
test.c的Makefile:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 KERNEL_DIR := /home/noah/imx6ull/bsp/kernel/linux-imx PWD :=$(shell pwd) appname += test obj-m := $(appname) .o PRINC_INC = $(PWD) / EXTRA_CFLAGS += -I $(PRINC_INC) KBUILD_EXTRA_SYMBOLS =$(PWD) /../add_sub/Module.symvers INCLUDES := $(PWD) modules: $(MAKE) -I $(PRINC_INC) -C $(KERNEL_DIR) M=$(PWD) modules @make clear clear: @rm -f *.o *.cmd *.mod *.mod.c @rm -rf *~ core .depend .tmp_versions modules.order -f @rm -f .*ko.cmd .*.o.cmd .*.o.d @rm -f *.unsigned clean: @rm -f *.ko
分别在各自的文件夹下执行make,各自复制文件到tftp文件夹下,然后由开发板下载至开发板内存内
1 2 3 4 5 6 7 # 开发板下 root@igkboard:~/workdir# tftp -gr add_sub.ko 192.168.0.202 root@igkboard:~/workdir# ls 01 02 add_sub.ko root@igkboard:~/workdir# tftp -gr test.ko 192.168.0.202 root@igkboard:~/workdir# ls 01 02 add_sub.ko test.ko
1 2 3 4 5 6 7 8 9 10 11 # 开发板下 # 先加载add_sub.ko模块,test 模块才能访问add_sub模块提供的导出函数 root@igkboard:~/workdir/04# insmod add_sub.ko # 再使用insmod加载模块,并传递参数到模块中。参数AddOrSub=1表示a+b root@igkboard:~/workdir/04# insmod test.ko a=4 b=5 AddOrSub=1 root@igkboard:~/workdir/04# dmesg | tail -5 [ 31.851546] fec 2188000.ethernet eth1: Link is Up - 100Mbps/Full - flow control off [ 31.851643] IPv6: ADDRCONF(NETDEV_CHANGE): eth1: link becomes ready [ 350.048344] test: no symbol version for add_integer [ 350.048998] test init [ 350.049022] The Add result is 9
测试成功