设备驱动分类
字符设备驱动、块设备驱动、网络设备驱动
linux中一切皆文件,我们在linux中打开一个窗口(字符设备文件),在dev目录下也对应了一个文件,例如我打开了两个窗口,对应两个文件/dev/pts/0和/dev/pts/1,现在在0窗口中向1窗口对应的文件中发送hello world,在1窗口会显示收到的hello world。
linux通过一个文件去操作一个字符设备,字符设备对应的文件都在dev目录下,dev目录下每一个文件都对应一个硬件,linux通过文件去访问设备。
网络设备没有体现一切皆文件的思想,网络设备驱动在/dev下没有对应的文件。
设备驱动模型:
总线,设备,驱动。总线是总线,设备是设备,驱动是驱动。
每一个设备在注册的时候会寻找匹配的驱动,每一个驱动在注册的时候会寻找匹配的设备。
总线帮忙完成匹配,每一种总线匹配的原则不一样,platform总线根据命名字匹配驱动和设备,注册的设备和驱动的名字相同就匹配上了,驱动就进入到运行周期。
驱动与驱动分离
驱动分层
linux内核模块
模块本身不编译进内核,这控制了内核的大小;模块一旦被加载,它就和内核中的其他部分完全一样。
模块的最终归属是内存,模块在加载的时候,内核会给模块分配一块内存,将模块放到内存中去 。
.ko文件是一个ELF可执行文件
modinfo查看模块信息
vermagic:version magic版本魔数,模块对应的内核版本。
modprobe:加载模块的时候把模块依赖的模块也加载进内核。
常用头文件:
linux/module.h:包含可装载模块需要的大量符号和函数的定义
linux/init.h:初始化和清除函数的定义
linux/moduleparam.h:模块传递参数的头文件。(不过我没用这个头文件,传参数也不报错呀)
模块导出symbol:
导出symbol后,其他模块就可以调用这个函数了。这个模块和其他模块一样,可以make,insmod等,只不过它没有module_init,module_exit函数。所以,模块不一定必须有module_init,module_exit函数。
cat /proc/kallsyms,查看内核中的变量和函数
第一列表示地址,第三列表示模块名。 模块被卸载,导出的symbol就没有了。
#include <linux/module.h>
#include <linux/init.h>
//#include <linux/moduleparam.h>
int add_integer(int a,int b)
{
return a+b;
}
EXPORT_SYMBOL(add_integer);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("HUANG TIENIU");
MODULE_DESCRIPTION("A simple module for module_param.");
最开始忘记加EXPORT_SYMBOL这一样代码,查询出来的只有一行。
不过,我这个地址都是0,怎么这么怪。
模块参数:
不指定参数时,使用默认参数。
#include <linux/module.h>
#include <linux/init.h>
//#include <linux/moduleparam.h>
int num=100;
char *name = "huangieniu";
static int module_param_init(void)
{
printk("--num-%d,name=%s--\n",num,name);
return 0;
}
static void module_param_exit(void)
{
printk("--module_param exit--\n");
}
module_param(num,int,S_IRUGO);
module_param(name,charp,S_IRUGO);
module_init(module_param_init);
module_exit(module_param_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("HUANG TIENIU");
MODULE_DESCRIPTION("A simple module for module_param.");
参数之间使用空格隔开,不要使用逗号。