1.ko模块传参
1.1概念
- 之前在装载驱动时候使用
insmod hello_driver.ko指令,实际上该指令可以传递参数
- 传参示例
insmod hello_driver.ko myname="makabaka" val=22
- 通过传参可以向驱动里面传入参数,驱动可对参数做相应处理,这点类似函数传参
- 例如在wifi驱动上面,wifi芯片在运行的时候会运行其内部原厂代码(firmware固件,为.bin文件),当我们要运行wifi驱动的时候需要告诉固件驱动固件的位置.如
insmod rtxxx.ko path=/lib/modules/firmware/xxx.bin
- 既然用到了参数,那么在内核里面就得提供相应接口来接收参数
/*
功能:接收参数
参数:
参数1:表示参数名字
参数2:表示参数类型
参数3:文件权限,针对文件
1.可以直接写数字,如0666,0777
2.或者使用宏,S_IRUGO|S_IWUGO|S_IXUGO
分别表示对所有者,同组者,其他用户有读,写,执行权限,即0777
*/
module_param(name, type, perm)
sudo insmod param.ko my_name="wtf" my_value=66
1.2示例代码
#include <linux/init.h>
#include <linux/module.h>
static int my_value = 77;
static char *my_name = "makabaka";
/*模块装载函数实现*/
static int __init hello_drv_init(void)
{
printk("--------%s---------\n", __FUNCTION__);
printk("name = %s, value = %d\n", my_name, my_value);
return 0;
}
/*模块卸载函数实现*/
static void __exit hello_drv_exit(void)
{
printk("--------%s---------\n", __FUNCTION__);
}
module_init(hello_drv_init);
module_exit(hello_drv_exit);
MODULE_LICENSE("GPL");
/*接收参数*/
module_param(my_value, int, 0644);
/*所有用户可读写执行,然权限太大会报错*/
//module_param(my_name, charp, 0777);
//module_param(my_name, charp, S_IRUGO|S_IWUGO|S_IXUGO);
/*所有用户有读权限,拥有着有写权限*/
module_param(my_name, charp, S_IRUGO|S_IWUSR);
# 没加参数前
pi@raspberrypi:~/my_drivers $ sudo insmod param.ko
pi@raspberrypi:~/my_drivers $ sudo rmmode param
pi@raspberrypi:~/my_drivers $ dmesg
...
[ 4782.525509] --------hello_drv_init---------
[ 4782.525516] name = makabaka, value = 77
[ 5081.692546] --------hello_drv_exit---------
# 加参数后,可见传参成功
pi@raspberrypi:~/my_drivers $ sudo insmod param.ko my_name="wtf" my_value=66
pi@raspberrypi:~/my_drivers $ sudo rmmode param
...
[ 5383.877852] --------hello_drv_init---------
[ 5383.877871] name = wtf, value = 66
[ 5440.380181] --------hello_drv_exit---------
2.ko模块的符号导出
2.1概念
- 在内核中允许很多ko文件存在,在装载文件的时候这些代码就会被装载到内核空间
- 在内核空间里面会自动执行入口函数
module.init()
- 那么内核里面不同的ko文件可能存在相互调用的情况
- Linux内核采用的是以模块化形式管理内核代码.内核中的每个模块相互之间是相互独立的,也就是说A模块的全局变量和函数,B模块是无法访问的
- 有些时候,我们写一些模块代码的时候,发现部分函数功能别人已经实现了,此时我们就想如果我们可以调用他们已经实现好的函数接口就好了.那如何才能做到这点呢?符号导出了,也就是说你可以把你实现的函数接口和全局变量导出,以供其他模块使用
- 在Linux内核里面,如果一个模块已经以静态的方式编译进的内核,那么它导出的符号就会出现在全局的内核符号表中
2.2示例
- 编写2个驱动文件,一个是
hello_driver.c,一个为math.c.前者调用后者内部的函数
math.c,如果你想其中的某个函数被外部调用,那么就应该将其导出
#include <linux/module.h>
#include <linux/init.h>
int my_add(int a, int b)
{
return a + b;
}
/*导出符号表*/
EXPORT_SYMBOL(my_add);
int my_sub(int a, int b)
{
return a - b;
}
/*导出符号表*/
EXPORT_SYMBOL(my_sub);
/*此处不需要模块的装载卸载的入口声明,直接定义函数*/
MODULE_LICENSE("GPL");
#ifndef __MATH_H__
#define __MATH_H__
int my_add(int a, int b);
int my_sub(int a, int b);
#endif
#include <linux/init.h>
#include <linux/module.h>
#include <linux/stat.h>
#include "math.h"/*需引入头文件*/
/*模块装载函数实现*/
static int __init hello_drv_init(void)
{
printk("--------%s---------\n", __FUNCTION__);
/*调用math模块的函数*/
printk("a+b=%d, a-b=%d\n", my_add(22, 33), my_sub(22, 33));
return 0;
}
/*模块卸载函数实现*/
static void __exit hello_drv_exit(void)
{
printk("--------%s---------\n", __FUNCTION__);
}
module_init(hello_drv_init);
module_exit(hello_drv_exit);
MODULE_LICENSE("GPL");
hanqi@hanqi-PC:~/my_drivers$ make
make -C /home/hanqi/pi/linux-rpi-4.14.y M=/home/hanqi/my_drivers modules ARCH=arm CROSS_COMPILE=/home/hanqi/pi/toolchain/tools-master/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
make[1]: Entering directory '/home/hanqi/pi/linux-rpi-4.14.y'
CC [M] /home/hanqi/my_drivers/math.o
CC [M] /home/hanqi/my_drivers/hello_driver.o
Building modules, stage 2.
MODPOST 2 modules
CC /home/hanqi/my_drivers/hello_driver.mod.o
LD [M] /home/hanqi/my_drivers/hello_driver.ko # 调用者ko
CC /home/hanqi/my_drivers/math.mod.o
LD [M] /home/hanqi/my_drivers/math.ko # 被调用者ko
make[1]: Leaving directory '/home/hanqi/pi/linux-rpi-4.14.y'
- 运行,如果先装载调用者驱动的话(hello_driver.ko),会报错,因为被调用者的驱动没有加载到内核里面,即其符号表没有导出,故无法找到相关功能函数
# 找不到符号
pi@raspberrypi:~/my_drivers $ sudo insmod hello_driver.ko
insmod: ERROR: could not insert module hello_driver.ko: Unknown symbol in module
- 正确姿势应该是先加载功能驱动模块,在加载调用者驱动
# 先装载功能驱动
pi@raspberrypi:~/my_drivers $ sudo insmod math.ko
# 查看符号表是否导出,里面存在math文件,故成功
pi@raspberrypi:~/my_drivers $ ls /sys/module/
8250 dwc_otg lockd rfkill uio
auth_rpcgss fb loop rng_core uio_pdrv_genirq
bcm2708_fb firmware_class math scsi_mod usbcore
bcm2835_mmc fixed mmcblk scsi_transport_iscsi usbhid
block fscache module sdhci usb_storage
brcmfmac fuse mousedev smsc95xx vc_mem
brcmutil hid netpoll snd vt
brd i2c_dev nfs snd_bcm2835 watchdog
cachefiles ip_tables nfs_layout_nfsv41_files snd_pcm workqueue
cfg80211 ipv6 nfsv4 snd_timer x_tables
configfs kdb printk spurious xz_dec
cpufreq kernel random srcutree
cryptomgr keyboard rc_core sunrpc
debug_core kgdboc rcupdate sysrq
dns_resolver lan78xx rcutree tcp_cubic
# 再装载用户驱动
pi@raspberrypi:~/my_drivers $ sudo insmod hello_driver.ko
# 查看运行结果
pi@raspberrypi:~/my_drivers $ dmesg
[ 7806.485637] --------hello_drv_init---------
[ 7806.485650] a+b=55, a-b=-11