字符设备驱动程序

news2025/2/23 14:08:13

简单做个模板框架

字符设备开发流程

在这里插入图片描述

  1. 确定设备号dev_t,动态分配 alloc_chrdev_region() 或静态分配 register_chrdev_region()
  2. 定义file_opeartion 结构体*fops *,在结构体成员中实现对应的 *open()、read()*等函数。
  3. cdev_init()fopscdev 绑定,cdev_add() 绑定设备号 dev_t 并注册进内核。
  4. class_create() 创建设备类型,device_create() 注册设备结点
代码实现
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

/*确定主设备号*/
//#define	DEV_MAJOR	11
#ifndef	DEV_MAJOR
#define	DEV_MAJOR 0
#endif
int dev_major = DEV_MAJOR;//主设备号					


#define	DEV_NAME	"chrdev"//设备名称

static struct cdev *chrtest_cdev;//cdev结构体

//static struct class *chrdev_class; //定义一个class用于自动创建类

static char kernel_buf[1024];


#define	MIN(a,b) (a < b ? a : b)

/*实现对应的open/read/write等函数,填入file_operations结构体 */
static ssize_t chrtest_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int err;
	printk("%s %s line %d\n", __FILE__,  __FUNCTION__, __LINE__);
	err = copy_to_user(buf, kernel_buf, MIN(1024, size));//内核空间的数据到用户空间的复制													 
	return MIN(1024, size);
}

static ssize_t chrtest_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	int err;
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	err = copy_from_user(kernel_buf, buf, MIN(1024, size));//将用户空间的buf复制到内核空间缓冲区kernel_buf中,因为用户空间内存不能直接访问内核空间的内存
	return MIN(1024, size);
}

static int chrtest_drv_open(struct inode *node, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

static int chrtest_drv_close(struct inode *node, struct file *file)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	return 0;
}

/*定义自己的file_operations结构体*/
static struct file_operations chrtest_fops = {
	.owner		= THIS_MODULE,
	.open		= chrtest_drv_open,
	.read		= chrtest_drv_read,
	.write		= chrtest_drv_write,
	.release	= chrtest_drv_close,
};

/*把file_operations结构体告诉内核:register_chrdev*/
/*注册驱动函数:写入口函数,安装驱动程序时就会调用这个入口函数*/
static int __init chrdev_init(void)
{
	int result;
	dev_t devno;/*定义一个dev_t变量来表示设备号*/

	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	/*字符设备驱动注册流程第二步:分配主次设备号,这里即支持静态指定,也支持动态申请*/
	if(0 != dev_major)
	{
		devno = MKDEV(dev_major, 0);
		result = register_chrdev_region(devno, 1, DEV_NAME);//"/proc/devices/chrdev"
	}
	else
	{
		result = alloc_chrdev_region(&devno, 0, 1, DEV_NAME);
		dev_major = MAJOR(devno);
	}

	/*自动分配设备号失败*/
	if(result < 0)
	{
		printk(KERN_ERR " %s driver can't use major %d\n", DEV_NAME, dev_major);
		return -ENODEV;
	}
	printk(KERN_DEBUG " %s driver can't use major %d\n", DEV_NAME, dev_major);
	
	/*字符设备驱动注册流程第三步:分配cdev结构体,我们这里使用动态申请的方式*/
	if(NULL == (chrtest_cdev = cdev_alloc()))
	{
		printk(KERN_ERR " %s driver can't alloc for the cdev\n", DEV_NAME);
		unregister_chrdev_region(devno, 1);
		return -ENOMEM;
	}

	/*字符设备驱动注册流程第四步:分配cdev结构体,绑定主次设备号、fops到cdev结构体中,并注册给Linux内核*/
	chrtest_cdev->owner = THIS_MODULE;//.owner表示谁拥有你这个驱动程序
	cdev_init(chrtest_cdev, &chrtest_fops);//初始化设备
	result = cdev_add(chrtest_cdev, devno, 1);
	if(0 != result)
	{
		printk(KERN_INFO "%s driver can't register cdev:result=%d\n", DEV_NAME, result);
		goto ERROR;
	}
	printk(KERN_INFO "%s driver can register cdev:result=%d\n", DEV_NAME, result);

	/*自动创建设备类型与/dev设备节点*/
	#if 0
	chrdev_class = class_create(THIS_MODULE, DEV_NAME);//创建设备类型 sys/class/chrdevbase
	if(IS_ERR(chrdev_class))
	{
		result = PTR_ERR(chrdev_class);
		goto ERROR;
	}
	device_create(chrdev_class, NULL, MKDEV(dev_major, 0), NULL, DEV_NAME);// /dev/chrdev 注册这个设备节点
	#endif


	return 0;


ERROR:
	printk(KERN_ERR" %s driver installed failure.\n", DEV_NAME);
    cdev_del(chrtest_cdev);
    unregister_chrdev_region(devno, 1);
    return result;

}

/* 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数*/
static void __exit chrdev_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	/*注销设备类型与/dev设备节点*/
	#if 0
	device_destroy(chrdev_class, NKDEV(dev_major, 0));//注销此设备节点
	class_destroy(chrdev_class);//删除这个设备类型
	#endif

	cdev_del(chrtest_cdev);//注销字符设备
	unregister_chrdev_region(MKDEV(dev_major, 0), 1);//释放设备号
													 

	printk(KERN_ERR"%s driver version 1.0.0 removed!\n", DEV_NAME);
	return;
}

module_init(chrdev_init);
module_exit(chrdev_exit);

MODULE_LICENSE("GPL");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1895702.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在 Selenium Python 中解决验证码 | 2024 完整指南

由于在进行网络自动化时遇到验证码是让许多人感到不知所措的问题。这些验证码专为区分人类用户和自动化脚本而设计&#xff0c;对于使用Selenium进行网络爬虫或自动化任务而言&#xff0c;无疑是一个巨大的挑战。2024年的完全指南将为您提供全面的解决方案&#xff0c;帮助您高…

Mac本地部署大模型-单机运行

前些天在一台linux服务器&#xff08;8核&#xff0c;32G内存&#xff0c;无显卡&#xff09;使用ollama运行阿里通义千问Qwen1.5和Qwen2.0低参数版本大模型&#xff0c;Qwen2-1.5B可以运行&#xff0c;但是推理速度有些慢。 一直还没有尝试在macbook上运行测试大模型&#xf…

ARIES,数据恢复算法,万变不离其宗...

今天来聊两个问题&#xff1a; 1. 如果缓冲池&#xff08;buffer pool&#xff09;满了&#xff0c;哪些数据页&#xff08;page&#xff09;要刷盘&#xff0c;哪些数据页不刷盘&#xff1f; 2. 数据库崩了&#xff0c;怎么利用检查点&#xff08;checkpoint&#xff09;与预写…

MATLAB环境下4种噪声生成

生成噪声包括: 1)粉红色(闪烁)噪声-功率谱密度斜率-3 dB/oct。&#xff0c; - 10db /dec 2)红色(布朗)噪声-功率谱密度斜率-6 dB/oct。&#xff0c; - 20db /dec 3)蓝色噪声-功率谱密度斜率3 dB/oct。&#xff0c; 10db /dec 4)紫色(紫色)噪声-功率谱密度斜率 6db /oct。&…

鸿蒙如何打包应用程序

总结鸿蒙应用程序包 之前文章详细讲解了关于三种程序包的内容&#xff0c;现在简单总结一下&#xff1a; 1. 总结 首先需要搞清楚鸿蒙项目的模块Module的分类: Module分为“Ability”和“Library”两种类型 HAP HAP: Harmony Ability Package , 叫做鸿蒙Ability包。 “Abil…

【虚幻引擎】UE4初学者系列教程开发进阶实战篇——生存游戏案例

一、课程体系 1 学前必读 2 Character类相关基础 -人物移动控制 -动画蓝图 3 常见游戏机制基础 -碰撞器、触发器 -物体使用接口 -视角切换 4其他相关设计 -背包系统 -锻造系统 -物体破碎效果 -简易种植系统 -互动物体动画 5课程结语 二、UI部分 思维导图部分 实操部分 …

若依多数据源原理分析

首先&#xff0c;想明白不同的接口想要使用不同的数据源。 那么自然想到了AOP&#xff0c;自定义注解。 通过自定义注解标注当前方法到底使用的是哪个数据源。 上面是前置条件。 看下若依是怎么处理的&#xff1a; 1.定义自定义注解&#xff0c;以及对应的多数据源的枚举类…

p标签文本段落中因编辑器换行引起的空格问题完美解决方案

目录 1.修改前的代码&#xff1a;2.修改后的代码3.总结 在HTML文档中&#xff0c;如何要在&#xff08;p标签&#xff09;内写一段很长的文本段落&#xff0c;并且没有 换行。由于IDE或者编辑器界面大小有限或需要在vue中逻辑处理动态显示文本&#xff0c;一行写完太长&#x…

深入浅出 LangChain 与智能 Agent:构建下一代 AI 助手

我们小时候都玩过乐高积木。通过堆砌各种颜色和形状的积木&#xff0c;我们可以构建出城堡、飞机、甚至整个城市。现在&#xff0c;想象一下如果有一个数字世界的乐高&#xff0c;我们可以用这样的“积木”来构建智能程序&#xff0c;这些程序能够阅读、理解和撰写文本&#xf…

在RT-Thread-Studio中添加arm_math库

1.在CMSIS\Lib\GCC中找到对应的库&#xff0c;如本文使用的libarm_cortexM4lf_math.a。将库拷贝到工程&#xff0c;并做如下图设置。搜索路径为库文件在项目中的实际位置。 2.将CMSIS\DSP\Include下的文件复制到工程目录中&#xff0c;并添加包含路径 3.添加宏定义&#xff0c…

【MySQL】MySQL 9.0悄悄的来了

MySQL 9.0.0 中的变化 MySQL 9.0 中的新功能 JavaScript 存储程序 MySQL 企业版现在支持用 JavaScript 编写的存储程序&#xff0c;例如使用 CREATE FUNCTION下面显示的语句和 JavaScript 代码创建的这个简单示例&#xff1a; CREATE FUNCTION gcd(a INT, b INT) RETURNS …

【PTGui、Pano2VR6、UE4】VR全景拍摄及漫游交互制作操作实例(更新中)

一、基本思路 首先进行VR全景拍摄&#xff0c;获取高质量的全景图像&#xff1b;然后使用PTGui进行图像拼接&#xff0c;确保图像的连续性与准确性&#xff1b;接着利用Pano2VR6进行VR漫游的制作&#xff0c;添加交互元素与多媒体内容&#xff1b;最后进行作品的调试与优化&am…

11.SQL注入-盲注基于(base on boolian)

SQL注入-盲注基于boolian案例利用 首先总结一下sql语句中的函数意思 #查看当前所在的数据库 mysql> select database(); ------------ | database() | ------------ | pikachu | ------------ 1 row in set (0.00 sec)#函数substr里1是从第几位开始取字符&#xff0c;2…

时序模型综述论文

时序模型综述论文&#xff1a; A Survey of Time Series Foundation Models: Generalizing Time Series Representation with Large Language Model

抖音矩阵智能剪辑系统源码,saas多平台多账号一站式管理,系统搭建流程

‘1. 将MySQL升级至5.6版本&#xff0c;PHP更新至7.2版本&#xff0c;并使用Apache作为服务器。数据库应命名为“juzhen”。 2. 在Nginx环境下&#xff0c;实现伪静态的切换。 3. 将安装包解压至项目的根目录&#xff0c;并定位至application/database.php文件以更换数据库密…

Linux shell编程学习笔记62: top命令 linux下的任务管理器

0 前言 top命令是Unix 和 Linux下常用的性能分析工具&#xff0c;提供了一个动态的、交互式的实时视图&#xff0c;显示系统的整体性能信息&#xff0c;以及正在运行的进程的相关信息&#xff0c;包括各个进程的资源占用状况&#xff0c;类似于Windows的任务管理器。 1 top命令…

JVM原理(十五):JVM虚拟机静态分配与动态分配

1. 分派 本节讲解的分派调用过程将会揭示多态性特征的一-些最基本的体现&#xff0c;如“重载”和“重写”在Java虚拟机之中是如何实现的。 1.1. 静态分派 案例&#xff1a; 我们先来看一段代码: Human mannew Man(); 我们把上面代码中的“Human"称为变量的“静态类型…

前端面试8

基础知识 解释一下什么是跨域问题&#xff0c;以及如何解决&#xff1f; 跨域问题是由于浏览器的同源策略限制了从一个源加载的网页脚本访问另一个源的数据。解决方法包括使用JSONP、CORS&#xff08;跨源资源共享&#xff09;、设置代理服务器等。 描述一下事件冒泡和事件捕获…

企业搭建知识库:解锁无限潜力的钥匙

在当今这个信息爆炸的时代&#xff0c;企业如何高效地管理、传播与利用知识&#xff0c;已成为衡量其竞争力的重要标尺。知识库&#xff0c;作为这一背景下的产物&#xff0c;正逐步成为企业不可或缺的数字资产。它不仅是一个自助式的数字门户&#xff0c;更是连接员工、客户与…

编程建模文件

你可以在MATLAB命令提示符下以编程方式执行大多数Simulink建模基础。与基本建模操作&#xff08;如创建模型、向模型添加块和设置参数&#xff09;相对应的命令列在“模型编辑基础知识”的“功能”部分中。这些示例显示了其中一些命令以及如何使用它们。 加载模型 加载模型会…