首先两个文件 vser.c Makefile (记得大写的M)
vser.c
#include //内核初始化头文件
#include //内核模块文件
#include //linux内核
/********** 自定义初始化函数 ***********/
static int __init vser_init(void) /* __init 说明要将该函数放到 EIF 文件 __init 只读区 ,会加载后自动删除*/
{
printk("我是初始化函数: %s\n",__func__); //注意:内核中尽量不要用浮点数,所以printk不支持 %f
return 0;
}
/********** 自定义销毁函数 *************/
static void __exit vser_exit(void)
{
printk("我是销毁函数: %s\n",__func__);
}
module_init(vser_init);//将vser_init函数地址加入到内核初始化链表
module_exit(vser_exit);//将vser_exit函数地址加入到内核卸载链表
MODULE_LICENSE( "GPL" );//开元许可协议:GPL
MODULE_AUTHOR("1111" );//作者信息
MODULE_DESCRIPTION(",你可以编写自己喜欢的模块");//模块描述信息
MODULE_ALIAS ( "2222" ); //模块别名
Makefile
#动态编译内核驱动生成.ko文件的Makeifle
#自己的模块代码名
obj-m = vser.o #就会生成一个 vser.ko 文件 这是一个文件编译
#内核源代码路径
ifeq ($(ARCH),arm)
KERNELDIR ?= /home/student/linux-5.4.31
else
KERNELDIR ?= /lib/modules/${shell uname -r}/build
endif
#当前模块路径
PWD ?= $(shell pwd)
#编译源码生成 .ko 文件 make all
all:
${MAKE} -C ${KERNELDIR} M=${PWD} modules
#伪代码之清除垃圾
clean:
rm Module.* modules.* *.mod *.ko
等下运用 下面的内核的指令就可以了。 (运行命令生成 .ko 文件)
统一放在 一个文件夹里面。
1. (编译生成 .ko 文件)
命令: make 或者 make ARCH=arm
make
make ARCH=arm
2.模块加载
命令 : sudo insmod vser.ko (vser 上面编译的 .ko 文件 ) (普通用户权限下)
sudo insmod vser.ko
命令 : insmod vser.ko
insmod vser.ko
3. 查看模块信息
命令 : modinfo vser.ko
modinfo vser.ko
4. 模块卸载
命令 : sudo rmmod vser (普通用户)
sudo rmmod vser
命令: rmmod vser (超级用户)
rmmode vser
5. 查看 模块是否加载
命令: lsmod (一般最后加载的 在最前面 )
lsmod
6. 查看 模块运行问题
命令: dmesg
dmesg
1. bar .c
#include
void bar(void)
{
printk("加载外部函数名字 %s\n",__func__);
}
2. foo.c
#include
#include
#include
/**** extern 引入外部声明 ****/
extern void bar(void);
/**** 初始化函数 *****/
static int __init vser_init(void)
{
printk("加载函数名:%s\n",__func__);
bar(); //调用外部函数
return 0;
}
/**** 注销函数 ***/
static void __exit vser_exit(void)
{
printk("卸载函数名:%s\n",__func__);
}
/**** 加载和卸载函数插入内核链表 *****/
module_init(vser_init);
module_exit(vser_exit);
/**** 模块宏的声明 *****/
MODULE_LICENSE("GPL"); //开元许可协议
3.Makefile
#动态编译内核驱动生成.ko文件的Makeifle
#自己的模块代码名
obj-m = vser.o #就会生成一个 vser.ko 文件
vser-objs = foo.o bar.o
#内核源代码路径
ifeq ($(ARCH),arm)
KERNELDIR ?= /home/student/linux-5.4.31
else
KERNELDIR ?= /lib/modules/${shell uname -r}/build
endif
#当前模块路径
PWD ?= $(shell pwd)
#编译源码生成 .ko 文件 make all
all:
${MAKE} -C ${KERNELDIR} M=${PWD} modules
#伪代码之清除垃圾
clean:
rm Module.* modules.* *.mod *.ko
1. vser.c
#include //内核初始化头文件
#include //内核模块文件
#include //linux内核
/********** 自定义初始化函数 ***********/
static int baudrate= 9600;
static int port[4] = {0,1,2,3};
static char *name = "vser" ;
module_param(baudrate,int,S_IRUGO);
module_param_array(port, int,NULL,S_IRUGO);
module_param(name,charp,S_IRUGO);
static int __init vser_init(void) /* __init 说明要将该函数放到 EIF 文件 __init 只读区 ,会加载后自动删除*/
{
int i = 0;
printk("baudrate = d\n" , baudrate);
printk("prot=");
for(i =0; i<4;i++)
{
printk ( "%d, " , port[i]);
}
printk ( "\n");
printk( "name = %s\n" , name);
printk("我是初始化函数: %s\n",__func__); //注意:内核中尽量不要用浮点数,所以printk不支持 %f
return 0;
}
/********** 自定义销毁函数 *************/
static void __exit vser_exit(void)
{
printk("我是销毁函数: %s\n",__func__);
}
/**** 加载和卸载函数插入内核链表 *****/
module_init(vser_init);
module_exit(vser_exit);
/**** 模块宏的声明 *****/
MODULE_LICENSE("GPL"); //开元许可协议
2.Makefile
#动态编译内核驱动生成.ko文件的Makeifle
#自己的模块代码名
obj-m = vser.o #就会生成一个 vser.ko 文件
#内核源代码路径
ifeq ($(ARCH),arm)
KERNELDIR ?= /home/student/linux-5.4.31
else
KERNELDIR ?= /lib/modules/${shell uname -r}/build
endif
#当前模块路径
PWD ?= $(shell pwd)
#编译源码生成 .ko 文件 make all
all:
${MAKE} -C ${KERNELDIR} M=${PWD} modules
#伪代码之清除垃圾
clean:
rm Module.* modules.* *.mod *.ko
参数默认值
可以用命令改变 (先 make 编译 形成 vser.ko 文件 再 模块加载)
查看他们的值
dep.c
#include
#include
static int expval =5;
static void expfunc(void)
{
printk("依赖函数:expfunc\n");
}
EXPORT_SYMBOL(expval); //
EXPORT_SYMBOL_GPL(expfunc);
MODULE_LICENSE("GPL");
vser.c
#include
#include
#include
/**** extern 引入外部声明 ****/
extern void expfunc(void);
extern int expval;
/**** 初始化函数 *****/
static int __init vser_init(void)
{
printk("初始化函数:%s\n",__func__);
printk("expval = %d\n",expval);
expfunc();
return 0;
}
/**** 注销函数 ***/
static void __exit vser_exit(void)
{
printk("卸载函数名:%s\n",__func__);
}
/**** 加载和卸载函数插入内核链表 *****/
module_init(vser_init);
module_exit(vser_exit);
/**** 模块宏的声明 *****/
MODULE_LICENSE("GPL"); //开元许可协议
Makefile
#动态编译内核驱动生成.ko文件的Makeifle
#自己的模块代码名
obj-m = vser.o #就会生成一个 vser.ko 文件
obj-m += dep.o
#内核源代码路径
ifeq ($(ARCH),arm)
KERNELDIR ?= /home/student/linux-5.4.31
else
KERNELDIR ?= /lib/modules/${shell uname -r}/build
endif
#当前模块路径
PWD ?= $(shell pwd)
#编译源码生成 .ko 文件 make all
all:
${MAKE} -C ${KERNELDIR} M=${PWD} modules
#伪代码之清除垃圾
clean:
rm Module.* modules.* *.mod *.ko
运行步骤: (上面的 步骤都差不多,, 只是有一个的加载命令不一样)
1. make (形成 .ko 文件)
2. sudo rmmod vser ( 移除模块 防止之前的 vser.ko 已经加载)
3. sudo insmod vser.ko (加载模块)
4. lsmod (查看是否有 vser 模块)
5. dmesg (查看 模块的加载 输出)
6. sudo rmmod vser