常用的模块操作:
lsmod将模块列表显示,打印出当前内核中已经安装的模块列表
module_init()和module_exit()是模块编程中最基本也是必须的两个函数。
module_init()是驱动程序初始化的入口点。而module_exit()注销由模块提供的所有功能。
#include <linux/module.h> // module_init module_exit #include <linux/init.h> // __init chrdev_init __exit chrdev_exit // 模块安装函数 static int __init chrdev_init(void) { printk(KERN_INFO "chrdev_init helloworld init "); //printk("<7>" "chrdev_init helloworld init "); //printk("<7> chrdev_init helloworld init "); return 0; } // 模块下载函数 static void __exit chrdev_exit(void) { printk(KERN_INFO "chrdev_exit helloworld exit "); } module_init(chrdev_init); module_exit(chrdev_exit); // MODULE_xxx这种宏作用是用来添加模块描述信息 MODULE_LICENSE("GPL"); // 描述模块的许可证 MODULE_AUTHOR("aston"); // 描述模块的作者 MODULE_DESCRIPTION("module test"); // 描述模块的介绍信息 MODULE_ALIAS("alias xxx"); // 描述模块的别名信息
__init,本质上是个宏定义,在内核源代码中就有#define __init xxxx。这个__init的作用就是将被他修饰的函数放入.init.text段中去(本来默认情况下函数是被放入.text段中)。
整个内核中的所有的这类函数都会被链接器链接放入.init.text段中,所以所有的内核模块的__init修饰的函数其实是被统一放在一起的。内核启动时统一会加载.init.text段中的这些模块安装函数,加载完后就会把这个段给释放掉以节省内存。
makefile编写
ubuntu的内核源码树,如果要编译的模块在ubuntu中使用 就打开这2个 #KERN_VER = $(shell uname -r) #KERN_DIR = /lib/modules/$(KERN_VER)/build # 开发板的linux内核的源码树目录 KERN_DIR = /home/book/per/kernel/linux-2.6.22.6 #/root/driver/kernel obj-m += module_test.o//和.c的文件名一致 -m表示编译成模块了 如果是-y即表示编译进内核 all: make -C $(KERN_DIR) M=`pwd` modules //-C进入摸个目录 `pwd` modules 作用pwd 是shell命令中的pwd 表示当前路径,记住当前目录,编译完成后再回到当前的目录来,modules表示目标, cp: cp *.ko /root/porting_x210/rootfs/rootfs/driver_test .PHONY: clean //.PHONY伪目标 ,把clean生成为伪目标
Makefile分析
(1)KERN_DIR,变量的值就是我们用来编译这个模块的内核源码树的目录
(2)obj-m += module_test.o,这一行就表示我们要将module_test.c文件编译成一个模块 -m
(3)make -C $(KERN_DIR) M=`pwd` modules 这个命令用来实际编译模块,工作原理就是:利用make -C进入到我们指定的内核源码树目录下,然后在源码目录树下借用内核源码中定义的模块编译规则去编译这个模块,编译完成后把生成的文件还拷贝到当前目录下,完成编译。
(4)make clean ,用来清除编译痕迹
总结:模块的makefile非常简单,本身并不能完成模块的编译,而是通过make -C进入到内核源码树下借用内核源码的体系来完成模块的编译链接的。这个Makefile本身是非常模式化的,3和4部分是永远不用动的,只有1和2需要动。1是内核源码树的目录,你必须根据自己的编译环境
编写完成后可以将其置入自己的开发版,insmod rmmod lsmod实验
模块的安装:
先lsmod再insmod看安装前后系统内模块记录。内核会将最新安装的模块放在lsmod显示的最前面
insmod与module_init宏。模块源代码中用module_init宏声明了一个函数(在我们这个例子里是chrdev_init函数),作用就是指定chrdev_init这个函数和insmod命令绑定起来,也就是说当我们insmod module_test.ko时,insmod命令内部实际执行的操作就是帮我们调用chrdev_init函数。
insmod时就应该能看到chrdev_init中使用printk打印出来的一个chrdev_init字符串,但是实际没看到。原因是ubuntu中拦截了,中使用dmesg命令就可以看到了。
补充: