今日学习了linux的驱动框架
首先是整体框架的搭建
今日学到了Linux的驱动框架,其驱动框架如下。主要框架就是驱动入口函数、驱动出口函数、注册驱动入口函数和注册驱动出口函数、 LICENSE和作者信息。其主体代码块如下:
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#define CHRDEVBASE_MAJOR 200 /* 主设备号 */
#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */
static int test_chardev_open(struct inode *inode, struct file *file)
{
printk("chrdevbase open!\r\n");
return 0;
}
static int test_chardev_release(struct inode *inode, struct file *file)
{
printk("chrdevbase release!\r\n");
return 0;
}
/*
* 设备操作函数结构体
*/
static struct file_operations test_fops = {
.owner = THIS_MODULE, //惯例,直接写就行
.open = test_chardev_open,
.release = test_chardev_release,
};
/*
* @description : 驱动入口函数
* @param : 无
* @return : 0 成功;其他 失败
*/
static int __init chrdevbase_init(void)
{
int retvalue = 0;
//在moudel_init宏调用的函数中去注册字符设备驱动
//主设备号传0意味着系统自动分配一个没有被使用的主要设备号
retvalue = register_chrdev(0, CHRDEVBASE_NAME, &test_fops);
if(retvalue < 0){
printk("chrdevbase driver register failed\r\n");
}
printk("register_chrdev sucess!\r\n");
}
/*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
static void __exit chrdevbase_exit(void)
{
/* 注销字符设备驱动 */
unregister_chrdev(CHRDEVBASE_MAJOR,CHRDEVBASE_NAME);
printk("chrdevbase exit!\r\n");
}
/*
* 将上面两个函数指定为驱动的入口和出口函数
*/
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
/*
* LICENSE和作者信息
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");
其次是各个模块的描述
设备操作函数结构体
在介绍设备操作结构体之前我们得明白系统整体工作原理是:应用层–>API–>设备驱动–>硬件,而设备操作函数结构体就是关联应用层调用API中的open、read、close等函数的关键结构体,此结构体将API中的open、read、close等关键操作函数和底层真正实现操作的open、read、close函数关联起来(因为没有万能的open、read、close函数,每个函数实现的操作都需要自己来在底层驱动中实现)。
在这里插入代码片
/*
* 设备操作函数结构体
*/
static struct file_operations test_fops = {
.owner = THIS_MODULE, //惯例,直接写就行
.open = test_chardev_open,
.read = test_chardev_read,
.write = test_chardev_write,
.release = test_chardev_release,
};
驱动入口函数
驱动入口函数其实就是将chrdev_init这个函数和insmod命令绑定起来,终端里面敲insmod即执行chrdev_init这个函数
模块的安装
(1)先lsmod再insmod看安装前后系统内模块记录。实践测试标明内核会将最新安装的模块放在lsmod显示的最前面。
(2)insmod与module_init宏。模块源代码中用module_init宏声明了一个函数(在我们这个例子里是chrdev_init函数),作用就是指定chrdev_init这个函数和insmod命令绑定起来,也就是说当我们insmod module_test.ko时,insmod命令内部实际执行的操作就是帮我们调用chrdev_init函数。
照此分析,那insmod时就应该能看到chrdev_init中使用printk打印出来的一个chrdev_init字符串,但是实际没看到。原因是ubuntu中拦截了,要怎么才能看到呢?在ubuntu中使用dmesg命令就可以看到了。
(3)模块安装时insmod内部除了帮我们调用module_init宏所声明的函数外,实际还做了一些别的事(譬如lsmod能看到多了一个模块也是insmod帮我们在内部做了记录),但是我们就不用管了。
/*
* @description : 驱动入口函数
* @param : 无
* @return : 0 成功;其他 失败
*/
static int __init chrdevbase_init(void)
{
int retvalue = 0;
//在moudel_init宏调用的函数中去注册字符设备驱动
//主设备号传0意味着系统自动分配一个没有被使用的主要设备号
retvalue = register_chrdev(0, CHRDEVBASE_NAME, &test_fops);
if(retvalue < 0){
printk("chrdevbase driver register failed\r\n");
}
printk("register_chrdev sucess!\r\n");
}
驱动出口函数
module_exit和rmmod的对应关系
static void __exit chrdevbase_exit(void)
{
/* 注销字符设备驱动 */
unregister_chrdev(CHRDEVBASE_MAJOR,CHRDEVBASE_NAME);
printk("chrdevbase exit!\r\n");
}
将上面两个函数指定为驱动的入口和出口函数
module_init(chrdevbase_init);
module_exit(chrdevbase_exit);
LICENSE和作者信息
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“jason”);