通讯方式:procfs/socket/syscall/IOCTL
常用的是socket/syscall/ioctl.
ioctl机制,ioctl机制可以在驱动中扩展特定的ioctl消息,用于将一些状态从内核反应到用户态。Ioctl有很好的数据同步保护机制,不要担心内核和用户层的数据访问冲突,但是ioctl不适合传输大量的数据,通过和内存映射结合可以很好的完成大量数据交换过程。但是,ioctl的发起方一定是在用户态,因此如果需要内核态主动发起一个通知消息给用户层,则非常的麻烦。可能需要用户态程序采用轮询机制不停的ioctl。
采用内存映射的方式,将内核地址映射到用户态。这种方式最直接,可以适用大量的数据传输机制。这种方式的缺点是很难进行“业务控制”,没有一种可靠的机制保障内核和用户态的调动同步,比如信号量等都不能跨内核、用户层使用。因此内存映射机制一般需要配合一种“消息机制”来控制数据的读取,比如采用“消息”类型的短数据通道来完成一个可靠的数据读取功能。
编写内核模块:
编写一个内核模块首先要确保内核打开了CONFIG_MODULES宏,并且已经编译了内核。
需要添加头文件<linux/module.h>
编写内核模块必须要实现一个init方法和一个exit方法。由于模块是可以在内核运行过程中动态的加载和卸载的,因此,在加载模块时要指定一个init方法作为入口函数,同样的,在卸载模块的时候,exit方法可以做一些清理工作。
一个最简单的内核模块的实现如下:
#include <linux/module.h>
static int __init xxx_init(void)
{
/* TODO: 在这个模块中你想做的事情 */
return 0;
}
static void __exit xxx_exit(void)
{
/* TODO: 卸载这个模块时需要做的清理工作 */
}
module_init(xxx_init);
module_exit(xxx_exit);
编写Makefile
Makefile
obj-m += testm.o
编译
make -C /lib/modules/`uname -r`/build M=$PWD
安装
make -C /lib/modules/`uname -r`/build M=$PWD modules_install
模块A中定义了函数funcA(),在模块B中想使用这个函数,那么在编写模块A时,就要使用EXPORT_SYMBOL宏将funcA()函数导出。在模块A中代码的写法:
int funcA(void)
{
printk("funcA inmodule A.\n");
return 0;
}
EXPORT_SYMBOL(funcA);