嵌入式驱动学习第三周——设备号与字符设备的注册、分配、释放

前言

   这一篇博客来谈谈字符设备的注册、分配与释放。

   嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程,未来预计四个月将高强度更新本专栏,喜欢的可以关注本博主并订阅本专栏,一起讨论一起学习。现在关注就是老粉啦!

目录

  • 前言
  • 1. 设备号
    • 1.1 设备号组成
    • 1.2 设备号的获取
  • 2. 字符设备分配
    • 2.1 静态分配
    • 2.2 动态分配
    • 2.3 实际代码编写
  • 3. 字符设备注册
    • 3.1 cdev结构体
    • 3.2 cdev_init()函数
    • 3.3 cdev_add()函数
  • 4. 字符设备释放
  • 参考资料

1. 设备号

1.1 设备号组成

   Linux中,为了方便管理,每个设备都有一个设备号,由主设备号次设备号两部分组成。主设备号表示某一个具体的驱动,次设备号表示使用这个驱动的各个设备。

   Linux下提供了dev_t数据类型表示设备号,其是一个unsigned int 类型,32位的数据,其中高12位为主设备号,低20位为次设备号,因此主设备号的范围不要超过0~4095。

1.2 设备号的获取

   在include/linux/kdev_t.h中,提供了关于设备号的操作函数(宏)

#define MINORBITS     20
#define MINORMASK     ((1U << MINORBITS) - 1)#define MAJOR(dev)    ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev)    ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma, mi) (((ma) << MINORBITS) | (mi))

   主要是最后三个,前面两个是为后三个服务的

  • MAJOR 用于从 dev_t 中获取主设备号,将 dev_t 右移 20 位即可
  • MINOR 用于从 dev_t 中获取次设备号,取 dev_t 的低 20 位的值即可
  • MKDEV 用于将给定的主设备号和次设备号的值组合成 dev_t 类型的设备号

2. 字符设备分配

   设备号的分配有两种,一种是静态分配,一种是动态分配

2.1 静态分配

   所谓的静态分配就是直接在注册时指定设备号,这个设备号可以是驱动开发者静态的指定一个设备号,比如200。有一些常用的设备号已经被 Linux 内核开发者给分配掉了,具体分配的内容可以查看文档 Documentation/devices.txt。并不是说内核开发者已经分配掉的主设备号我们就不能用了,具体能不能用还得看我们的硬件平台运行过程中有没有使用这个主设备号。

   使用cat /proc/devices可以查看当前系统中使用了的设备号,字符设备、块设备、网络设备均可以看到。

在这里插入图片描述

   可以使用函数register_chrdev_region来用给定的主设备号进行注册

/* * @description: 使用静态分配注册设备号* @param-from : 要分配的设备编号范围的初始值(次设备号常设为0)* @param-count: 连续编号范围* @param-name : 编号相关联的设备名称* @return     : 当返回值小于0,表示注册失败*/
int register_chrdev_region(dev_t from, unsigned count, const char *name)

2.2 动态分配

   静态分配还是不够灵活,需要先查看已使用的设备号,因此常用的还是动态分配,等到运行时,让系统自动分配一个没有使用的设备号,这样就避免了冲突。

/** @description    : 向linux申请一个没有使用过的设备号* @param-dev      : 用于保存申请到的设备号* @param-baseminor: 次设备号起始地址,alloc_chrdev_region 可以申请一段连续的多个设备号,这些设备号的主设备号一样,但是次设备号不同,次设备号以 baseminor 为起始地址地址开始递增。一般 baseminor 为 0,也就是说次设备号从 0 开始* @param-count    : 要申请的设备号数量* @param-name     : 设备名字* @return         : 小于0,则错误,自动分配设备号错误。否则分配得到的设备号就被第一个参数带出来*/
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

   用alloc_chrdev_region()函数得到设备号后,需要利用MAJOR宏和MINOR宏获取一下主设备号和次设备号。例如下面:

	alloc_chrdev_region(&chrdevTest.devid, 0, chrdevTest_CNT, chrdevTest_NAME);     // 申请设备号chrdevTest.major = MAJOR(chrdevTest.devid);     // 获取主设备号chrdevTest.minor = MINOR(chrdevTest.devid);     // 获取次设备号

   最后卸载驱动的时候需要释放设备号:

/** @description: 释放设备号* @param-from : 要释放的设备号* @param-count: 从from开始,要释放的设备号数量* @return     : 无*/
void unregister_chrdev_region(dev_t from, unsigned count)

2.3 实际代码编写

   在实际操作中,我们可以通过判断是否已经给定主设备号来选择静态分配还是动态分配,具体写法如下:

if (chrdevTest.major) {chrdevTest.devid = MKDEV(chrdevTest.major, 0);register_chrdev_region(chrdevTest.devid, chrdevTest_CNT, chrdevTest_NAME);
} else {alloc_chrdev_region(&chrdevTest.devid, 0, chrdevTest_CNT, chrdevTest_NAME);     // 申请设备号chrdevTest.major = MAJOR(chrdevTest.devid);     // 获取主设备号chrdevTest.minor = MINOR(chrdevTest.devid);     // 获取次设备号
}

3. 字符设备注册

3.1 cdev结构体

   在Linux中使用cdev结构体表示一个字符设备,cdev在include/linux/cdev.h文件中的定义:

struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;
};

   在 cdev 中有两个重要的成员变量:opsdev,这两个就是字符设备文件操作函数集合file_operations 以及设备号 dev_t。编写字符设备驱动之前需要定义一个 cdev 结构体变量,一般在设备结构体中定义,如下所示:

struct chrdevTest_dev {dev_t devid;struct cdev cdev;struct class *class;struct device *device;int major;int minor;struct device_node *nd;
};

3.2 cdev_init()函数

   使用cdev_init函数进行初始化:

/** @description: 初始化cdev结构体* @param-cdev : 要初始化的cdev结构体变量* @param-fops : 字符设备文件操作函数集合* @return     : 无*/
void cdev_init(struct cdev *cdev, const struct file_operations *fops)

3.3 cdev_add()函数

   cdev_add用于向Linux系统添加字符设备(cdev结构体变量)

/** @description: 向系统添加字符设备* @param-p    : 指向要添加的字符设备(cdev结构体变量)* @param-dev  : 设备所使用的设备号* @param-count: 要添加的设备数量* @return     : 无*/
int cdev_add(struct cdev *p, dev_t dev, unsigned count)

4. 字符设备释放

   卸载驱动时,一定要用cdev_del函数从Linux内核中删除相应的字符设备,即在出口函数中编写cdev_del。

/* * @description: 从Linux内核中删除相应的字符设备* @param-p    : 要删除的字符设备* @return     : 无*/
void cdev_del(struct cdev *p)

   删除字符设备后,再释放设备号,因此完整的流程是:

	cdev_del(&chrdevTest.cdev);unregister_chrdev_region(chrdevTest.devid, chrdevTest_CNT);

参考资料

[1] 【正点原子】I.MX6U嵌入式Linux驱区动开发指南 第四十章、第四十二章
[2] linux驱动2:设备号与字符设备注册与注销
[3] 字符设备驱动之register_chrdev_region()系列

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

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

相关文章

盲盒抽卡机小程序——开启神秘之旅!

亲爱的朋友们&#xff0c;欢迎来到盲盒抽卡机小程序&#xff01;这里&#xff0c;是一个充满神秘与惊喜的世界&#xff0c;让你随时随地体验抽卡的乐趣。在这里&#xff0c;你可以轻松尝试各种盲盒&#xff0c;发现隐藏的宝藏&#xff0c;感受心跳加速的刺激。 【丰富多样的盲…

小程序学习 1

pages/goods/search/home.wxml首页功能设定 1. loading入场 2. 下拉刷新 3. 搜索栏 4. 分类切换 5. 商品列表 6. 规格弹层 7. 加载更多 <view style"text-align: center; color: #b9b9b9" wx:if"{{pageLoading}}"><t-loading theme"circula…

利用ffmpeg对两个音频文件进行混音处理

前言 最近&#xff0c;拿到了一个语音识别程序&#xff0c;想测试一下它识别的准确性。原本程序有一段自己的测试音频&#xff0c;准确性还可以&#xff0c;但是&#xff0c;自己想增加一下测试素材的复杂性。想到了在原本的测试音频中引入干扰数据&#xff08;噪点&#xff…

python+realsense

单目相机(RGB影像):分辨率&#xff1a;320180,320240,424240,640360,640480,848480,960540,1280720,19201080&#xff1b;帧率&#xff1a;6,15,30,60 按照博文Python实战之Realsense_realsense python-CSDN博客的代码显示如下&#xff08;我更改了分辨率和帧率&#xff0c;大…

java八股文 笔记(持续更新中~)

1 Redis 2Mysql 3JVM 4java基础底层 5 spring 6 微服务 7.......(持续更新) One:Redis篇 1.穿透 2&#xff1a;击穿 3&#xff1a;雪崩 3 33 4:双写一致 5.持久化

【网站项目】012医院住院管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

内网穿透的应用-如何在Linux系统Docker安装JSON Crack并实现远程访问本地数据

文章目录 1. 在Linux上使用Docker安装JSONCrack2. 安装Cpolar内网穿透工具3. 配置JSON Crack界面公网地址4. 远程访问 JSONCrack 界面5. 固定 JSONCrack公网地址 JSON Crack 是一款免费的开源数据可视化应用程序&#xff0c;能够将 JSON、YAML、XML、CSV 等数据格式可视化为交互…

mysql中 多表查询介绍

在 MySQL 中&#xff0c;多表查询是 SQL 语句的重要组成部分&#xff0c;用于从两个或多个表中检索数据。多表查询可以帮助我们更灵活地处理复杂的数据关系&#xff0c;并从中获取所需的信息。以下是 MySQL 中常见的多表查询及其特点、区别和应用场景。 常见多表查询 1. **内连…

《量子计算:下一个大风口,还是一个热炒概念?》

引言 量子计算,作为一项颠覆性的技术,一直以来备受关注。它被认为是未来计算领域的一次革命,可能改变我们对计算能力和数据处理的理解。然而,随着技术的不断进步和商业应用的探索,人们开始思考,量子计算到底是一个即将到来的大风口,还是一个被过度炒作的概念? 量子计…

归并排序 刷题笔记

归并排序的写法 归并排序 分治双指针 1.定义一个mid if(l>r)return ; 2.分治 sort(q,l,mid); sort(q,mid1,r); 3. 双指针 int il,jmid,k0; 将双序列扫入 缓存数组 条件 while(i<mid&&j<r) 两个数列比较大小 小的一方 进入缓存数组 4. 扫尾 while(…

基于USB数据采集器的电能质量监测系统

目录 摘要 1 Abstract 3 第一章 引言 5 1.1 研究背景 5 1.2 研究现状 5 1.3 研究工作 6 第二章 电能质量及其分析方法 8 2.1 电能质量定义 8 2.2 电力系统频率偏差 8 2.3 供电电压允许偏差 10 2.4 公用电网谐波 12 2.5 电压波动和闪变 13 2.6 三相电压不平衡度 15 2.7 常见的电…

[嵌入式AI从0开始到入土]16_ffmpeg_ascend编译安装及性能测试

[嵌入式AI从0开始到入土]嵌入式AI系列教程 注&#xff1a;等我摸完鱼再把链接补上 可以关注我的B站号工具人呵呵的个人空间&#xff0c;后期会考虑出视频教程&#xff0c;务必催更&#xff0c;以防我变身鸽王。 第1期 昇腾Altas 200 DK上手 第2期 下载昇腾案例并运行 第3期 官…

前端精准测试调用链路分析

精准测试在评估需求的测试范围时&#xff0c;需要评估一下代码的影响范围&#xff0c;这个范围有两部分&#xff1a;一是需求直接修改的代码&#xff1b;二是修改代码影响到的功能模块。代码影响到的功能一般是通过调用链路分析来实现的&#xff0c;java和kotlin代码可以由java…

前端页面访问后台hiveserver2,阶段性报错

1、运行环境 Windows11下安装VMware&#xff0c;VMware下安装CentOS7 Linux系统&#xff0c;三台虚拟机集群部署hadoop&#xff0c;安装hive&#xff1b; 在Linux下安装Eclipse&#xff0c;创建maven工程&#xff0c;使用hive-jdbc-2.3.2访问hiveserver2 2、在windows11下&…

Python从0到100(四):Python中的运算符介绍

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

就业班 2401--3.12 Linux Day16 PXE布置——自动化装系统

什么是PXE&#xff1f; PXE&#xff0c;全名Pre-boot Execution Environment&#xff0c;预启动执行环境&#xff1b;通过网络接口启动计算机&#xff0c;不依赖本地存储设备&#xff08;如硬盘&#xff09;或本地已安装的操作系统&#xff1b;由Intel和Systemsoft公司于1999年…

云游戏发行是什么?云游戏发行的演进历程

云游戏发行是一系列基于云游戏技术的游戏发行策略或行为&#xff0c;融合云试玩、云微端、可玩广告、跨端移植等技术&#xff0c;从而在传统游戏发行生态的基础上实现更为卓越的发行效果。 云游戏发行出现的原因 近年来&#xff0c;游戏市场出现负增长。其原因一方面在于游戏版…

一套plm系统大约多少钱?彩虹PLM系统

一套PLM&#xff08;产品生命周期管理&#xff09;系统的价格因多个因素而异&#xff0c;包括企业规模、需求复杂性、系统功能、技术支持和厂商选择等。一般来说&#xff0c;面向小型和微型企业的PLM产品&#xff0c;其价位在5万元~15万元左右&#xff1b;面向中型企业的中端PL…

【Docker】容器的生态系统

Docker提供了一整套技术支持&#xff0c;包括核心技术、平台技术、支持技术。 核心技术 容器核心技术是指能让Container&#xff08;容器&#xff09;在host&#xff08;集群、主机&#xff09;上运行起来的那些技术。 1&#xff09;容器规范&#xff1a;OCI&#xff08;runt…