Linux学习第12天:基于API函数的字符设备驱动开发:一字一符总见情

news2025/1/15 12:47:12

        本节学习的内容主要为基于LinuxAPI函数的字符设备驱动的开发,还包括在驱动模块加载的时候如何自动创建设备节点。总结的脑图如下:

一、驱动原理

1.分配和释放设备号

        申请设备号函数:

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

        注册设备号函数:

int reister_chrdev_region(dev_t from, unsigned count, const char *name)//rrom起始设备号 count数量 name设备名

        设备释放函数:

void unregister_chrdev_region(dev_t from, unsigned count)

        设备号分配实例:

1 int major; /* 主设备号 */
2 int minor; /* 次设备号 */
3 dev_t devid; /* 设备号 */
4 5
if (major) { /* 定义了主设备号 */
6 devid = MKDEV(major, 0); /* 大部分驱动次设备号都选择 0 */
7 register_chrdev_region(devid, 1, "test");
8 } else { /* 没有定义设备号 */
9 alloc_chrdev_region(&devid, 0, 1, "test"); /* 申请设备号 */
10 major = MAJOR(devid); /* 获取分配号的主设备号 */
11 minor = MINOR(devid); /* 获取分配号的次设备号 */
12 }

        大部分次设备号都选择0

2.注册方法

1)、字符设备结构

        cdev结构体在/include/linux/cdev.h中定义如下:

1 struct cdev {
2 struct kobject kobj;
3 struct module *owner;
4 const struct file_operations *ops;//file_operations
5 struct list_head list;
6 dev_t dev;//cdev
7 unsigned int count;
8 };

        编写字符设备驱动之前,需要定义一个cdev结构体变量,这个变量就表示一个字符设备。

struct cdev test_cdev;

2)、cdev_init

        初始化函数cdev_init内容如下:

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

        使用cdev_init函数初始化cdev变量代码如下:

1 struct cdev testcdev;
2 
3
/* 设备操作函数 */
4 static struct file_operations test_fops = {
5 .owner = THIS_MODULE,
6 /* 其他具体的初始项 */
7 };
8 
9
testcdev.owner = THIS_MODULE;
10 cdev_init(&testcdev, &test_fops); /* 初始化 cdev 结构体变量 */

3)、cdev_add

        cdev_add函数原型:

int cdev_add(struct cdev *p, dev_t dev, unsigned count)

        注册字符设备代码段内容:

1 struct cdev testcdev;
2 
3
/* 设备操作函数 */
4 static struct file_operations test_fops = {
5 .owner = THIS_MODULE,
6 /* 其他具体的初始项 */
7 };
8 
9testcdev.owner = THIS_MODULE;
10 cdev_init(&testcdev, &test_fops); /* 初始化 cdev 结构体变量 */
11 cdev_add(&testcdev, devid, 1); /* 添加字符设备 */

4)、cdev_del

        cdev_del原型内容:

void cdev(struct cdev *p)

二、自动创建设备节点

        自动创建设备节点以后,使用modprobe加载驱动模块成功的话就会自动在/dev目录下创建对应的设备文件。

1.modev机制

        udev程序实现设备文件的创建与删除。

2.创建和删除类

        class_create是类创建函数,class_create是个宏定义,内容如下:

1 #define class_create(owner, name) \//owner一般为THIS_MODULE name为类名字 返回值是指向结构体class的指针,也就是创建的类
2 ({ \
3 static struct lock_class_key __key; \
4 __class_create(owner, name, &__key); \
5 })
6 
7
struct class *__class_create(struct module *owner, const char *name,
8 struct lock_class_key *key)

        卸载驱动函数的时候需要删除类,class_destroy函数原型如下:

void class_destroy(struct class *cls)//cls就是要删除的类

3.创建设备

        创建好类以后,还需要在类下面创建一个设备,才能实现自动创建设备节点。

        device_create函数原型如下:

struct device *device_create(struct class *class,//clasd  要创建的类
struct device *parent,//parent 父设备 一般为NULL
dev_t devt,//devt 设备号
void *drvdata,//drvdata 设备可能会使用的一些数据 一般为NULL
const char *fmt, ...)//fmt 设备名字 生成/dev/xxx

        卸载时,需要删掉创建的设备。device_destroy函数原型如下:

void device_destroy(struct class *class, dev_t devt)//class 删除的类 devt删除的设备号

三、设置文件私有数据

        编写open函数的时候将设备结构体作为私有数据添加到设备文件中,如下:

/* 设备结构体 */
1 struct test_dev{
2 dev_t devid; /* 设备号 */
3 struct cdev cdev; /* cdev */
4 struct class *class; /* 类 */
5 struct device *device; /* 设备 */
6 int major; /* 主设备号 */
7 int minor; /* 次设备号 */
8 };
9
10 struct test_dev testdev;
11
12 /* open 函数 */
13 static int test_open(struct inode *inode, struct file *filp)
14 {
15 filp->private_data = &testdev; /* 设置私有数据 */
16 return 0;
17 }

        在open函数里面设置好私有数据以后,在write、read、close等函数中直接读取private_data即可得到设备结构体。

        本节学习的内容看似就几个函数而已,但是要将其替换改动到原来的驱动函数中还是需要一定的代码功力的。切记戒骄戒躁,放平心态,一遍一遍不厌其烦的去调试,去总结。相信功夫不负有心人,铁棒总能磨成针......


Linux版本号4.1.15   芯片MX6ULL

本文为参考正点原子开发板配套教程整理而得,仅用于学习交流使用,不得用于商业用途。

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

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

相关文章

改进YOLOv5小目标检测:构建多尺度骨干和特征增强模块,提升小目标检测

构建多尺度骨干和特征增强模块,提升小目标检测 背景代码使用配置文件如下🔥🔥🔥 提升小目标检测,创新提升 🔥🔥🔥 测试在小目标数据集进行提点 👉👉👉: 新设计的创新想法,包含详细的代码和说明,具备有效的创新组合 🐤🐤🐤 1. 本文包含两个创新改…

SQL优化--count优化

select count(*) from tb_user ;在之前的测试中,我们发现,如果数据量很大,在执行count操作时,是非常耗时的。 MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个 数,效率很…

档案管理系统设计与实现

摘 要 近年来,随着企业彼此间的竞争日趋激烈,信息技术在企业的发展中占据着越来越重要的地位。在企业的运输生产中,档案已成为企业运输经营中不可或缺的一部分,为管理者进行管理决策和进行各种经营活动提供了重要的依据&#xf…

前后端分离--Vue的入门基础版

目录 一.前后端分离 二.Vue的简介 三.Vue的入门案例 四.Vue的生命周期 一.前后端分离 前后端分离是一种软件架构模式,将应用程序的前端(用户界面)和后端(数据处理和业务逻辑)独立开发、独立部署。在前后端分离的架…

【数据结构】AVL树的删除(解析有点东西哦)

文章目录 前言一、普通二叉搜索树的删除1. 删除结点的左右结点都不为空2. 删除结点的左结点为空,右节点不为空3. 删除结点的右结点为空,左节点不为空4. 删除结点的左右结点都不为空 二、AVL树的删除1. 删除结点,整棵树的高度不变化1.1 parent…

RISV-V架构的寄存器介绍

1、RISC-V的通用寄存器 (1)在编写汇编代码时,使用寄存器的ABI名字,一般不直接使用寄存器的编号; (2)x0-x31是用来做整形运算的寄存器,f0-f31是用来做浮点数运算的寄存器;…

傅里叶变换应用 (01/2):频域和相位

一、说明 我努力理解傅里叶变换,直到我将这个概念映射到现实世界的直觉上。这是一系列技术性越来越强的解释中的第一篇文章。我希望直觉也能帮助你! 二、傅里叶变换中频域简介 声音是一种机械波,是空气中的振动或其他介质。音符对应于波的频率…

【LeetCode75】第五十七题 电话号码的字母组合

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 给我们按下的按键,让我们返回对应按键可能产生的所有可能。 这是一道很经典的递归题,我们首先先拿一个数组把每个…

day45:C++ day5,运算符重载剩余部分、静态成员、继承

#include <iostream> #include <cstring> #define pi 3.14 using namespace std;class Shape { protected:double round;double area; public://无参构造Shape():round(40),area(100){cout<<"Shape::无参构造函数&#xff0c;默认周长为40&#xff0c;面…

C语言入门Day_21 函数的使用

目录 前言&#xff1a; 1.变量作用域 2.代码执行顺序 3.易错点 4.思维导图 前言&#xff1a; 我们是先定义函数&#xff0c;再调用函数。完成了函数的定义以后&#xff0c;我们就可以开始调用函数了&#xff0c;让我们来回顾一下&#xff1a; 调用函数分为两部分&#…

1131. 绝对值表达式的最大值

1131. 绝对值表达式的最大值 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;求方向一次遍历两度统计 参考代码&#xff1a;求方向一次遍历两度统计 原题链接&#xff1a; 1131. 绝对值表达式的最大值 https://leetcode.cn/problems/maximum-of-absolute-val…

网络安全深入学习第二课——热门框架漏洞(RCE—Thinkphp5.0.23 代码执行)

文章目录 一、什么是框架&#xff1f;二、导致框架漏洞原因二、使用步骤三、ThinkPHP介绍四、Thinkphp框架特征五、Thinkphp5.0.23 远程代码执行1、漏洞影响范围2、漏洞成因 六、POC数据包Windows下的Linux下的 七、漏洞手工复现1、先Burp抓包&#xff0c;把抓到的请求包发送到…

【AI语言大模型】文心一言功能使用介绍

一、前言 文心一言是一个知识增强的大语言模型,基于飞桨深度学习平台和文心知识增强大模型,持续从海量数据和大规模知识中融合学习具备知识增强、检索增强和对话增强的技术特色。 最近收到百度旗下产品【文心一言】的产品,抱着试一试的心态体验了一下,整体感觉:还行! 二…

自动化测试API【软件测试】

自动化测试 selenium 1. 为什么使用selenium&#xff1f; 开源免费支持多浏览器支持多系统支持多语言编程提供了丰富的web自动化测试API 2. API 查找页面元素 find Element() find Elements() 元素定位的方式 xpath selector 通常情况下&#xff0c;不需要手动来编写xpath…

Learn Prompt-经验法则

还记得我们在“基础用法”当中提到的三个经验法则吗&#xff1f; 尝试提示的多种表述以获得最佳结果使用清晰简短的提示&#xff0c;避免不必要的词语减少不精确的描述 现在经过了几页的学习&#xff0c;我认为是时候引入一些新的原则了。 3. 一个话题对应一个chat​ ChatG…

Kafka开篇

前言 从本篇开始对个人Kafka学习做一个总结, 目标有这么几个。 从概念架构角度, 对消息中间件形成概要认知;从使用角度, 掌握其常见用法;从性能角度, 探究其高性能实现机制; 消息中间件的用途 从消息生产和消费的角度, 平衡消费者和消费者的速率差。基于该点可以做到削峰填…

白炽灯对新生儿视力有影响吗?推荐专业的儿童台灯

大家都知道婴儿还在成长发育的重要阶段&#xff0c;身体各方面都是比较脆弱的&#xff0c;对外界事务的感知也很敏感&#xff0c;一点点的刺激都会影响的婴儿。而白炽灯是否适合婴儿使用这个问题&#xff0c;我的建议是尽量不要用白炽灯。 因为白炽灯光线不是很柔和&#xff0c…

周易算卦流程c++实现

代码 #include<iostream> using namespace std; #include<vector> #include<cstdlib> #include<ctime> #include<Windows.h>int huaYiXiangLiang(int all, int& left) {Sleep(3000);srand(time(0));left rand() % all 1;while (true) {if…

许可分析 license分析 第十二章

许可分析是指对软件许可证进行详细的分析和评估&#xff0c;以了解组织内部对软件许可的需求和使用情况。通过许可分析&#xff0c;可以帮助组织更好地管理和优化软件许可证的使用。以下是一些可能的许可分析方法和步骤&#xff1a; 软件许可证的分配和使用权限&#xff1a;制定…

01Spring的Ioc思想和依赖注入手段(DI)

传统方式创建对象的缺陷 连接MySQL实现登录功能 控制层UserController public class UserController {//多态,半面向接口编程private UserService userService new UserServiceImpl();public void login(){String username "admin";String password "1234…