日期:2014-05-16 浏览次数:20858 次
【驱动模块的组成】
1. 头文件:两个必须包含的
#include<linux/module.h>
#include<linux/init.h>
2.模块加载函数(必须):module_init(xxxxxx);
3.模块卸载函数(必须):module_exit(xxxxxx);
4.模块许可声明(必须):MODULE_LICENSE("GPL");
5.模块参数(可选):module_param( var, type, flag);、模块功能函数(可选)、其他。
【编译内核模块的条件】
1.使用正确版本的编译工具、模块工具等。
2.一份内核源码。
3.内核源码至少编译过一次。
【模块文件格式】
| ELF Header | .text | .data | 其他 | Section Table | .symtab | 其他 |
其中.symtab 表示符号表:一种映射函数到真实内存地址的数据结构。
【将模块加入内核】
内核源码的组合是通过目录结构实现的,每个目录下面都有两个文件Kconfig和Makefile。Kconfig描述了所属目录源文件相关的内核配置菜单。在执行内核配置make menuconfig命令时,从Kconfig中读出菜单,用户选择配置后保存到.config文件。在内核编译是,执行主目录下的Makefile时,调用这个.config文件,完成用户配置项的编译。
Kconfig文件的语法可查看内核Documentation/kbuild/kconfig-language.txt文件。
所以向Linux内核添加模块时,需要: 将驱动程序源文件放到Linux内核源码的相应目录中,在目录的Kconfig文件中添加对应的编译选择,在目录的Makefile中添加对应的编译语句。
此外可以动态加载卸载模块:insmod xxx.ko 、rmmod xxx.ko、modprobe。查看模块:lsmod、modinfo
【字符设备驱动】
1.主设备号和次设备号:dev_t类型表示设备号
typedef u_long dev_t;
2.分配设备号:
静态分配设备号:register_chrdev_region();
动态分配设备号:alloc_chrdev_region();
3.释放设备号:unregister_chrdev_region();
4.Linux中用cdev结构体描述字符设备:
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
};
struct list_head {
struct list_head *next, *prev;
};
内核使用inode结构体在内部表示文件,Linux中用inode结构体表示/dev/目录下的设备文件,每个字符设备在/dev/目录下都有一个设备文件,打开设备文件时,系统会产生一个inode结点,然后通过inode结点的i_cdev字段找到cdev字符结构体,通过cdev的ops指针,找到设备的操作函数。
723 struct inode {
724 struct hlist_node i_hash;
725 struct list_head i_list; /* backing dev IO list */
726 struct list_head i_sb_list;
727 struct list_head i_dentry;
728 unsigned long i_ino;
729 atomic_t i_cou