说明
本文是朱老师系列课程学习笔记
驱动开发步骤
(1)驱动源码编写、Makefile编写、编译
(2)insmod装载模块、测试、rmmod卸载模块
编译完成后得到了
1、内核源码树。2、编译ok的zImage
简单的模块源码分析
常用命令
(1) lsmod:list module
(2) insmod:install module
(3) modinfo,加xxx.ko,其中有个depends,如usb的wifi,wifi依赖usb
(4) rmmod,加模块名,不加ko
(5) 剩下的后面再说,modprobe,depmod
insmod命令,执行到module_init宏对应的函数
rmmod,对应module_exit
写程序注意规范性,加static,避免和内核里原有函数重复
模块中常用宏
(1)MODULE_LICENSE,模块许可证。一般声明GPL,最好不要少,否则可能会出现莫名其妙的错误(譬如一些明显存在的函数提升找不到)。
(2)MODULE_AUTHOR
(3)MODULE_DESCRIPTION
(4)MODULE_ALIAS别名
函数修饰符
(1)__init,宏定义,将被修饰的函数放入.init.text段中去(本来默认情况下函数是被放入.text段中)。
链接器链接放入.init.text段中,内核启动时统一会加载.init.text段中的这些模块安装函数,加载完后就会把这个段给释放掉以节省内存。
(2)__exit
printk
printf是C库函数,是在应用层编程中使用
printk是内核源码中的一个普通函数
打印级别的设置
编译驱动的Makefile
(1)KERN_DIR变量,编译模块的内核源码树的目录
(2)obj-m += module_test.o,将module_test.c文件编译成一个模块
(3)make -C $(KERN_DIR) M=pwd
modules 实际编译模块
利用make -C进入到内核源码树目录下,借用内核源码中定义的模块编译规则去编译这个模块,编译完成后把生成的文件还拷贝到当前目录下
实践
2个文件:module_test.c + Makefile
// module_test.c
var foo = 'bar';
// An highlighted block
#include <linux/module.h> // module_init module_exit
#include <linux/init.h> // __init __exit
// 模块安装函数
static int __init chrdev_init(void)
{
printk(KERN_INFO "chrdev_init helloworld init\n");
return 0;
}
// 模块卸载函数
static void __exit chrdev_exit(void)
{
printk(KERN_INFO "chrdev_exit helloworld exit\n");
}
module_init(chrdev_init);
module_exit(chrdev_exit);
// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE("GPL"); // 描述模块的许可证
MODULE_AUTHOR("aston"); // 描述模块的作者
MODULE_DESCRIPTION("module test"); // 描述模块的介绍信息
MODULE_ALIAS("alias xxx"); // 描述模块的别名信息
Makefile
#ubuntu的内核源码树
#KERN_VER = $(shell uname -r)
#KERN_DIR = /lib/modules/$(KERN_VER)/build
obj-m += module_test.o
all:
make -C $(KERN_DIR) M=`pwd` modules
.PHONY: clean
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
编译完得到module_test.ko是想要的
加载,卸载,信息查看
modinfo module_test.ko
sudo insmod module_test.ko
lsmod
rmmod module_test
dmesg查看insmod和rmmod的打印信息