【Linux】字符设备驱动框架

一.注意
1.区别
裸机驱动:底层,和寄存器打交道,MCU会提供库;驱动和用户程序是杂揉在一起的。
linux驱动:直接操作寄存器不现实,需要根据linux下框架开发,/include/linux/fs.h中有个叫file_operations的结构体,它是linux内核驱动操作函数集合,框架开发其实就是file_operations结构体成员变量的实现:open、 close、 write 和 read 等。驱动与用户程序分层开发。file_operations各项成员变量解析.
2.在linux下一切皆文件,驱动注册完成后,驱动表现为/dev/xxx文件
3.驱动属于内核空间,当用户程序(用户空间)通过open操作打开/dev/xxx这个驱动,需要使用一个叫做“系统调用”的方法来实现从用户空间“陷入” 到内核空间,这样才能实现对底层驱动的操作。
在这里插入图片描述
二.驱动框架
1.实现file_operations结构体中成员变量函数,chrtest_open即具体驱动对应的open操作

/* 打开设备 */
static int chrtest_open(struct inode *inode, struct file *filp)
{
/* 用户实现具体功能 */
	return 0;
}
/* 从设备读取 */
static ssize_t chrtest_read(struct file *filp, char __user *buf,
size_t cnt, loff_t *offt)
{
/* 用户实现具体功能 */
	return 0;
}
/* 向设备写数据 */
static ssize_t chrtest_write(struct file *filp,
const char __user *buf,
size_t cnt, loff_t *offt)
{
/* 用户实现具体功能 */
	return 0;
}
/* 关闭/释放设备 */
static int chrtest_release(struct inode *inode, struct file *filp)
{
/* 用户实现具体功能 */
	return 0;
}

2.实例化file_operations结构体,并利用以上函数初始化test_fops

static struct file_operations test_fops = {
	.owner = THIS_MODULE,
	.open = chrtest_open,
	.read = chrtest_read,
	.write = chrtest_write,
	.release = chrtest_release,
};

3.注册驱动/注销驱动

/* 驱动入口函数 */
static int __init xxx_init(void)
{
	/* 入口函数具体内容 */
	int retvalue = 0;

	/* 注册字符设备驱动 */
	retvalue = register_chrdev(200, "chrtest", &test_fops);
	if(retvalue < 0){
	/* 字符设备注册失败,自行处理 */
	}
	return 0;
}
/* 驱动出口函数 */
static void __exit xxx_exit(void)
{
	/* 注销字符设备驱动 */
	unregister_chrdev(200, "chrtest");
}
/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(xxx_init);
module_exit(xxx_exit);

三.实验程序编写
1.在vscode中,ctrl+shift+p打开控制台,搜索"c/c++:编辑配置(json)",加入linux源码头文件路径
在这里插入图片描述
这样就可以使用linux头文件了
在这里插入图片描述
但是注意此处写法#include <linux/delay.h>,头文件开头不需要"/",因为路径"/home/xuqiang/work/arm/linux-5.11.11/include/",末尾已有"/";
若路径末尾不加"/",而写在头文件中,如:#include </linux/delay.h>,则会报错.

问题1:头文件虽然被包含,但是跳转过去发现是/usr/include这个gcc默认包含路径,并不是我们下载用于开发的内核源码路径
在这里插入图片描述
解决:在"c/c++:编辑配置(json)“中如下位置添加参数”-nostdinc",强制gcc不读取默认include路径

"compilerArgs": [
              "-nostdinc"    
] 

在这里插入图片描述

问题2:发现没有generated这个路径以及路径下的头文件,需要编译内核才会生成,见【Linux】交叉编译linux内核到ARM平台

2.于是可以在Vscode下编写驱动如下

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/delay.h>


#define HELLO_MAJOR 200
#define HELLO_MAME  "hello"


static int hello_open(struct inode *inode,struct file *filp)
{
    printk("hello world!\n");
    return 0;
}
static int hello_release(struct inode *inode, struct file *filp)
{
	printk("baibai world!\n");
    return 0;
}
struct file_operations hello_fops;
hello_fops = {
	.owner = THIS_MODULE,
	.open = hello_open,
	.release = hello_release,
};
/* 驱动出口函数 */
static void __exit hello_exit(void)
{
	/* 注销字符设备驱动 */
	unregister_chrdev(HELLO_MAJOR, HELLO_MAME);
}
/* 驱动入口函数 */
static int __init hello_init(void)
{
	/* 入口函数具体内容 */
	int retvalue = 0;

	/* 注册字符设备驱动 */
	retvalue = register_chrdev(HELLO_MAJOR, HELLO_MAME,&hello_fops);
	if(retvalue < 0){
	/* 字符设备注册失败,自行处理 */
	}
	return 0;
}


/* 将上面两个函数指定为驱动的入口和出口函数 */
module_init(hello_init);
module_exit(hello_exit);

3.接下来可以编写相应的APP来测试驱动

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

外来务工人员徐某

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值