二 Linux设备驱动的模块化编程

MODULE_LICENSE("GPL");
GPL:GNU通用公共许可证 , 如果不加版本声明 , 编译的时候会报错 , 关于这个声明的具体作用 , 可自行上网百度 。
2)模块的加载函数也即模块的入口函数 – 相当于应用程序的main函数
模块的加载函数有两种写法 , 第一种写法 , 又叫缺省写法:
int init_module(void) {}
当加载这个模块的时候 , 会调用到这个模块的函数执行 。
缺点:当大家都采用这种写法时 , 内核中将会有太多的, 使阅读时难以区分 。
第二种写法 , 称为自定义写法 , 顾名思义 , 就是入口函数名字可以自己定义 , 如 :
static int hello_init(void) {}
但是加载的时候 , 系统如何知道你这个自定义的函数就是入口函数呢?所以需要声明这个自定义函数就是入库函数 , 如下:
module_init(hello_init);
我们大多也都采用这种写法 。
3)模块的卸载函数也即模块的出口函数
这个函数通常要做的是释放入口函数里面申请的资源 。同上 , 也有两种写法 , 第一种缺省写法:
【二Linux设备驱动的模块化编程】void cleanup_module(void) {}
第二种自定义函数写法 , 也就是我们常用的写法:
static void hello_exit(void) {};module_exit(hello_exit);
用或者vim编辑一个最简单的模块hello.c:
#include #include static int hello_init(void){printk("%s : %d\n", __func__, __LINE__);return 0;}static void hello_exit(void){printk("%s : %d\n", __func__, __LINE__);}MODULE_LICENSE("GPL");module_init(hello_init);module_exit(hello_exit);
其中 , 包含的头文件是内核源码库里面的 , 这个在前面讲过 。在模块的加载函数和卸载函数中我们加入了打印 , 通过打印我们能知道代码的执行过程 。但是 , 注意这里用的打印是内核里面的 , 而不是用户空间的 , 时内核源码库提供的 , 这段代码最终也是运行在内核空间的 。
如何编译这个模块:
因为有些同学想了解编译模块的具体是如何实现的 , 所以在这里我就给大家详解一下 , 如果不想了解 , 直接cp我的使用即可 。

二  Linux设备驱动的模块化编程

文章插图
参考内核源码文档-> //.txt , 其中第二章 , How to Build是我们要仔细阅读的:
To build, you must have athattheandfiles used in the build. Also, themust have been built with. If you are using a, there will be afor theyou areby your .
大概意思就是说如果你想编译一个外部模块 , 那么你必须要有一个提前编译过的并且有效的内核 , 这个内核里面包括编译模块所需要的头文件等 , 并且这个内核中的属性选项被(Make 可以配置的) 。或者如果你用的是一个工作的内核 , 比如你在一个系统(Linux内核+图形库等的组合)上面编译模块 , 那么这个系统会提供一些 , 我们刚开始学习 , 不涉及具体的硬件 , 就先在一个的内核中编译运行我们的模块 。