linux内核模块,驱动开发框架
linux内核模块为可装载模块,独立于内核本身,对内核功能进行扩展。
在开发过程中,我们通常将驱动编译成模块(.ko文件),并使用insmod
命令来加载内核模块,用rmmod
命令卸载内核模块。
linux驱动开发通常需要包含三个头文件:
#include <linux/kernel.h>//内核头文件
#include <linux/module.h>//内核模块头文件
#include <linux/init.h>//初始化头文件
1.初始化和退出函数编写
当使用insmod
命令时,函数module_init()会被调用;当使用rmmod
命令时,函数module_exit()会被调用。
对于字符设备来说,在初始化函数中,需要完成字符设备的注册。同样地,卸载时,需要完成字符设备的注销。
所以我们需要用到函数register_chrdev和unregister_chrdev。
register_chrdev( , , )函数用来注册字符设备,其有三个入口参数,分别是:主设备号、设备名、指向操作函数集合的变量。
unregister_chrdev( , )函数用来注销字符设备,有两个人口参数:主设备号和设备名。
2.操作函数编写
在初始化时,我们设置了一个指向操作函数集合的变量,它是一个file_operations类型的结构体变量。
我们可以作如下定义:
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = chrtest_open,
.read = chrtest_read,
.write = chrtest_write,
.release = chrtest_release,
};
编写驱动程序主要就是实现这些操作函数,如open()、release()、read()、write()等。
3.分配设备号
在初始化函数注册字符设备前,要先动态申请设备号,以获得一个未被使用的设备号,用来注册字符设备(当然你可以自己指定一个设备号,前提是不产生冲突)。
申请函数:alloc_chrdev_region( , , , )
释放函数:unregister_chrdev_region( , )
4.驱动开发框架
综上所述,linux字符设备驱动开发框架总结为如下:
- 包含头文件
- 声明设备名
声明操作函数结构体 - 实现初始化函数xxx_init()
{申请主设备号,注册字符设备} - 实现退出函数xxx_exit()
{释放主设备号,注销字符设备} - 实现操作函数
xxx_open()
xxx_release()
xxx_read()
xxx_write()
操作函数通过cdev.init(…)函数初始化到字符设备结构体中,然后与设备号一起通过cdev.add(…)函数对接到内核的open()、close()、read()、write()等函数中 - 将初始化函数、退出函数与内核对接
module_init(xxx_init);
module_exit(xxx_exit);