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

news2024/12/22 18:43:57

前言

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

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

目录

  • 前言
  • 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.coloradmin.cn/o/1511133.html

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

相关文章

CentOS Linux - Oracle Primavera P6安装及分享

引言 根据计划&#xff0c;近期我制作了多套基于ORACLE Primavera P6 最新发布的23.12版本预构建了虚拟机环境&#xff0c;里面包含了全套P6 最新版应用服务&#xff0c;相比于之前常使用的WindowsServer&#xff0c;这次使用了Linux作为运行平台。 此虚拟机仅用于演示、培训和…

掌握Redis,看完这篇文章就够了

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Redis是什么&#xff1f;二、Redis安装三、Redis相关数据类型 四、基础操作&#xff08;使用了python连接redis&#xff09;1.字符串2.键对应操作3.哈希&am…

实时查询银行卡归属地的API接口,快速获取卡片发卡地信息

快速查询银行卡发卡地信息是一项非常实用的功能&#xff0c;对于进行业务合作、风险评估等方面都有很大的帮助。在本文中&#xff0c;我们将介绍一个实时查询银行卡归属地的API接口&#xff0c;并提供相应的代码示例。 该API接口可以通过输入银行卡号&#xff0c;查询该卡片的…

Tictoc3例子

在tictoc3中&#xff0c;实现了让 tic 和 toc 这两个简单模块之间传递消息&#xff0c;传递十次后结束仿真。 首先来介绍一下程序中用到的两个函数&#xff1a; 1.omnetpp中获取模块名称的函数 virtual const char *getName() const override {return name ? name : "&q…

Rust 安装与版本更新

Rust 简介 Rust &#xff0c;一门赋予每个人构建可靠且高效软件能力的语言&#xff0c;主打内存安全。 2024年2月&#xff0c;在一份 19 页的报告《回归基础构件&#xff1a;通往安全软件之路》中&#xff0c;白宫国家网络主任办公室&#xff08;ONCD&#xff09;呼吁开发者使…

linux ,Windows部署

Linux部署 准备好虚拟机 连接好查看版本&#xff1a;java -version安装jdk 解压命令&#xff1a;tar -zxvf 加jdk的压缩文件名cd /etc 在编辑vim profile文件 在最底下写入&#xff1a; export JAVA_HOME/root/soft/jdk1.8.0_151&#xff08;跟自己的jdk保持一致&#xff0…

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

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

Matlab中安装mltbx工具箱文件

准备 前提就是要已经下载好了相应的mltbx格式的工具箱文件 一般来说可以直接在开源的Github上下到相应的文件&#xff0c;这里以VeriStand Model Generation Support MATLAB add-on为例 注&#xff1a; 一般来说你可以下载到的文件有两种&#xff1a; Source Code &#xff…

实体店新模式探索:实体店如何转型与引流新策略

随着互联网的迅猛发展&#xff0c;线上购物逐渐成为了人们消费的主流方式。然而&#xff0c;实体店作为传统零售业的代表&#xff0c;依然具有其独特的价值和优势。 为了在这个变革的时代中保持竞争力&#xff0c;实体店必须积极探索新的模式&#xff0c;实现转型与引流。 作…

归并排序 刷题笔记

归并排序的写法 归并排序 分治双指针 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(…

OpenHarmony教程指南—ArkTS时钟

简单时钟 介绍 本示例通过使用ohos.display 接口以及Canvas组件来实现一个简单的时钟应用。 效果预览 使用说明 1.界面通过setInterval实现周期性实时刷新时间&#xff0c;使用Canvas绘制时钟&#xff0c;指针旋转角度通过计算得出。 例如&#xff1a;"2 * Math.PI /…

MyBatis 实现复杂查询

#{ } 与 ${ } 的区别(重点) #{ } 与 ${ } 在MyBatis中都是用于替换SQL参数的, 主要以下几点不同: 方式不同: ${ } 是直接替换为传递的参数, #{ } 则是先预处理,然后再设置参数 安全性不同: ${ } 存在SQL注入的风险, #{ }则不存在安全问题使用场景不同: …

【GO】HTTP标准库1 - http协议基础知识

目录 一 http协议 1 http协议 2 http request 3 请求方法 4 URL 5 协议版本 6 请求头 7 Content-type 9 POST与GET区别 10 HTTP Response 11 常见的状态与话术 12 HTTP 响应头 13 完整的HTTP响应 14 HTTPS 一 http协议 1 http协议 HTTP&#xff08;HyperText Tra…

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

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

Centos7 安装postgresql14后无法连接数据库

1、数据库服务器允许外部访问5432端口。 2、postgresql.conf 3、pg_hba.conf a、制定某个IP&#xff08;192.168.0.107&#xff09;访问 b、指定ip段访问 允许10.1.1.0~10.1.1.255网段登录数据库 host all all 10.1.1.0/24 trust c、指定全网访问 host a…

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

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

语音情感识别python项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 什么是语音情感识别&#xff1f; 语音情感识别&#xff0c;缩写为 SER&#xff0c;是试图从语音中识别人类情感和情感状态的行为。这是利用了这…

docker + nginx打包前端镜像

项目场景&#xff1a; 前端使用angular开发&#xff0c;Dockerfile如下&#xff1a; FROM nginx:1.16.1 AS base WORKDIR /app COPY nginx.conf.template /etc/nginx/ CMD ["/bin/bash", "-c", "envsubst ${APP_VERSION} < /app/index.html > …

Python环境安装及Selenium引入

Python环境安装 环境下载 Download Python | Python.org 环境安装 需使用管理员身份运行 查看环境是否安装成功 python --version 如果未成功则检查环境变量配置 安装 Selenium 库 pip install selenium Selenium 可以模拟用户在浏览器中的操作&#xff0c;如点击按钮、填写…

Vue3全家桶 - VueRouter - 【2】重定向路由

重定向路由 在路由规则数组中&#xff0c;可采用 redirect 来重定向到另一个地址&#xff1a; 通常是将 / 重定向到 某个页面&#xff1b; 示例展示&#xff1a; router/index.js&#xff1a;import { createRouter, createWebHashHistory, createWebHistory } from vue-route…