第一个驱动模块 __init __exit printk函数分析
代码:#include <linux/module.h>
#include <linux/init.h>
// 模块安装函数
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(“Mark”); // 描述模块的作者
MODULE_DESCRIPTION(“test for driver”); // 描述模块的介绍信息
MODULE_ALIAS(“alias test”); // 描述模块的别名信息
分析:
默认情况下函数是放在.text段里面的,有了下面的宏就不一样了。
__init :在linux/init.h里面
#define __init __section(.init.text) __cold notrace
往下分析:
define __section(S) attribute ((section(#S)))
意思就是把chrdev_init函数放到了.init.text段。整个内核中的所有的这类函数都会被链接器链接放入.init.text段中,所以所有的内核模块的__init修饰的函数其实是被统一放在一起的。内核启动时统一会加载.init.text段中的这些模块安装函数,加载完后就会把这个段给释放掉以节省内存
__exit :在linux/init.h里面
#define __exit __section(.exit.text) __exitused __cold
把chrdev_exit函数放到了.exit.text段
lsmod 显示的时候会把最后面安装的模块显示在最前面。
printk函数分析:
printk的打印级别是用来控制printk打印的这条信息是否在终端上显示的。从0-7的紧急程度依次下降,0是打印级别最高的
#define KERN_EMERG “<0>” /* system is unusable /
#define KERN_ALERT “<1>” / action must be taken immediately /
#define KERN_CRIT “<2>” / critical conditions /
#define KERN_ERR “<3>” / error conditions /
#define KERN_WARNING “<4>” / warning conditions /
#define KERN_NOTICE “<5>” / normal but significant condition /
#define KERN_INFO “<6>” / informational /
#define KERN_DEBUG “<7>” / debug-level messages */
操作系统的命令行中也有一个打印信息级别属性,值为0-7。
当前操作系统中执行printk的时候会去对比printk中的打印级别和我的命令行中设置的打印级别,小于我的命令行设置级别的信息会被放行打印出来,大于的就被拦截的。譬如我的ubuntu中的打印级别默认是4,那么printk中设置的级别比4小的就能打印出来,比4大的就不能打印出来。
查看操作系统的命令行的printk的级别:
cat /proc/sys/kernel/printk
设置操作系统的命令行的printk的级别:
echo 7 > /proc/sys/kernel/printk
所以这里总结一下就是:
操作系统命令行可以设置打印信息级别的:0-7
printk也有8种打印级别,printk的打印级别小于命令行设置的,就可以打印出来。
例如:命令行设置打印界别为3,那么printk中就只有0 1 2可以打印出来。
头文件说明:
驱动源代码中包含的头文件和原来应用编程程序中包含的头文件不是一回事。应用编程中包含的头文件是应用层的头文件,是应用程序的编译器带来的(譬如gcc的头文件路径在 /usr/include下,这些东西是和操作系统无关的)。驱动源码属于内核源码的一部分,驱动源码中的头文件其实就是内核源代码目录下的include目录下的头文件
发现了一个很有意思的现象:
我们编译模块的时候,可以不用指定编译器,指定内核为ubuntu的时候,它是使用的gcc。指定内核为ARM的时候,是使用的arm-linux-gcc,猜想与内核中的Makefile有关,它可能指定了。
将程序放到ARM板子上面去运行:
insmod module_test.ko,安装ok,printk(KERN_INFO “chrdev_init helloworld init\n”);,,打印出现。我们终端的打印级别设置的7,printk使用的6就打印出来了。当我把终端设置为6的时候,再次加载就没有了打印信息。
modinfo查看模块信息:
modinfo: can’t open ‘/lib/modules/2.6.35.7/modules.dep’: No such file or directory
解决方法:
1.进入内核源码目录kernel
1.1.执行模块编译命令,编译模块(指定为-M的)
make modules
1.2.执行模块安装命令 (把指定为-M的模块安装到某个目录下面去)
make modules_install INSTALL_MOD_PATH=/opt/
结果是在/opt目录下面会新生成一个新目录lib
2.将生成的lib下所有的东西拷贝到开发板使用的rootfs/lib下即可
mv /opt/lib/* /opt/rootfs/lib
3.在用modinfo查看模块信息,ok