嵌入式linux驱动学习<1>

今日学习了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”);

猜你喜欢

转载自blog.csdn.net/m0_57730390/article/details/125710481