嵌入式驱动开发详解2(设备挂载问题)

文章目录

  • 前言
  • 设备号
    • 设备号的组成
    • 设备号的分配
      • 静态分配
      • 动态分配
  • 驱动挂载与卸载
  • 设备节点创建
  • 驱动挂载出现问题

前言

驱动的设备挂载和卸载是十分重要的内容,一旦操作不当可能会导致系统崩溃,接下来我将用字符设备的驱动挂载原理进行详细讲解,并把自己在学习过程中遇到的问题与解决办法进行展示。

设备号

设备号的组成

为了方便管理,Linux 中每个设备都有一个设备号,设备号由主设备号和次设备号两部分 组成,主设备号表示某一个具体的驱动,次设备号表示使用这个驱动的各个设备 (后面有关杂项MISC的平台开发是根据不同的次设备号实现的)。 Linux 提供了 一个名为 dev_t 的数据类型表示设备号,dev_t 定义在文件 include/linux/types.h 里面,dev_t 其实就是 unsigned int 类型,是一个 32 位的数据类型。这 32 位的数据构成了主设备号和次设备号两部分,其中高 12 位为主设备号,低 20 位为次设备号。因此 Linux 系统中主设备号范围为 0~4095,所以大家在选择主设备号的时候一定不要超过这个范围。在文 件 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))

其中:
宏 MINORBITS 表示次设备号位数,一共是 20 位。
宏 MINORMASK 表示次设备号掩码。
宏 MAJOR 用于从 dev_t 中获取主设备号,将 dev_t 右移 20 位即可。
宏 MINOR 用于从 dev_t 中获取次设备号,取 dev_t 的低 20 位的值即可。
宏 MKDEV 用于将给定的主设备号和次设备号的值组合成 dev_t 类型的设备号。

设备号的分配

静态分配

注册字符设备的时候需要给设备指定一个设备号,这个设备号可以是驱动开发者静态的指定一个 设备号,比如选择 200 这个主设备号。有一些常用的设备号已经被 Linux 内核开发者给分配掉 了,具体分配的内容可以查看文档 Documentation/devices.txt。并不是说内核开发者已经分配掉 的主设备号我们就不能用了,具体能不能用还得看我们的硬件平台运行过程中有没有使用这个 主设备号,使用 “cat /proc/devices” 命令即可查看当前系统中所有已经使用了的设备号。

动态分配

静态分配设备号需要我们检查当前系统中所有被使用了的设备号,然后挑选一个没有使用 的。而且静态分配设备号很容易带来冲突问题,Linux 社区推荐使用动态分配设备号,在注册字 符设备之前先申请一个设备号,系统会自动给你一个没有被使用的设备号,这样就避免了冲突。 卸载驱动的时候释放掉这个设备号即可。
设备号的申请函数如下:

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

函数 alloc_chrdev_region 用于申请设备号,此函数有 4 个参数:
dev:保存申请到的设备号。
baseminor:次设备号起始地址,alloc_chrdev_region 可以申请一段连续的多个设备号,这 些设备号的主设备号一样,但是次设备号不同,次设备号以 baseminor 为起始地址地址开始递 增。一般 baseminor 为 0,也就是说次设备号从 0 开始。
count:要申请的设备号数量。
name:设备名字。
注销字符设备之后要释放掉设备号,设备号释放函数如下:

void unregister_chrdev_region(dev_t from, unsigned count) 

此函数有两个参数:
from:要释放的设备号。
count:表示从 from 开始,要释放的设备号数量。

驱动挂载与卸载

输入如下命令加载 chrdevbase.ko 驱动文件:

insmod chrdevbase.ko 
//或者
modprobe chrdevbase.ko

如果不再使用某个设备的话可以将其驱动卸载掉,比如输入如下命令卸载掉 chrdevbase 这 个设备:

rmmod chrdevbase.ko

驱动挂载或者卸载之后可以通过下面这两个指令查看

lsmod
cat /proc/devices

此时这里只是设备被挂载了,有对应的设备号,但是不一定能自动创建节点,驱动加载成功需要在/dev 目录下创建一个与之对应的设备节点文件,应用程序就是通过操作这个设备节点文件来完成对具体设备的操作。关于是否创建了节点可以看后面的内容)
一般情况下我们都会在驱动函数里面配置好设备的节点,如果没有配置好节点的话需要我们手动配置,手动配置流程如下:输入如下命令创建/dev/chrdevbase 这个设备节 点文件:

mknod /dev/chrdevbase c 200 0 

其中“mknod”是创建节点命令,“/dev/chrdevbase”是要创建的节点文件,“c”表示这是个 字 符 设 备 ,“ 200 ” 是 设 备 的 主 设 备 号 ,“ 0 ” 是 设 备 的 次 设 备 号 。 创 建 完 成 以 后 就 会 存 在 /dev/chrdevbase 这个文件,可以使用 “ls /dev/chrdevbase -l” 命令查看。

设备节点创建

字符设备驱动开发重点是使用 register_chrdev 函数注册字符设备,当不再使用设备的时候就使用 unregister_chrdev 函数注销字符设备, 当使用这两个函数时,驱动模块加载成功以后还需要手动使用 mknod 命令创建 设备节点。 register_chrdev 和 unregister_chrdev 这两个函数是老版本驱动使用的函数,现在新的字符设备驱动已经不再使用这两个函数,而是使用 Linux 内核推荐的新字符设备驱动 API 函数。关于设备节点的具体内容如下:
mdev机制:设备的节点自动创建主要是依赖于这个机制。
udev 是一个用户程序,在 Linux 下通过 udev 来实现设备文件的创建与删除,udev 可以检 测系统中硬件设备状态,可以根据系统中硬件设备状态来创建或者删除设备文件。比如使用 modprobe 命令成功加载驱动模块以后就自动在/dev 目录下创建对应的设备节点文件,使用 rmmod 命令卸载驱动模块以后就删除掉/dev 目录下的设备节点文件。 使用 busybox 构建根文件 系统的时候,busybox 会创建一个 udev 的简化版本—mdev,所以在嵌入式 Linux 中我们使用mdev 来实现设备节点文件的自动创建与删除, Linux 系统中的热插拔事件也由 mdev 管理,在 /etc/init.d/rcS 文件中如下语句:

echo /sbin/mdev > /proc/sys/kernel/hotplug 

上述命令设置热插拔事件由 mdev 来管理,关于 udev 或 mdev 更加详细的工作原理这里就 不详细探讨了,我们重点来学习一下如何通过 mdev 来实现设备文件节点的自动创建与删除。
自动创建设备节点需要经过以下过程

  • 1、手动或者自动创建一个设备号
  • 2、使用 cdev 结构体表示一个字符设备,在 cdev 中有两个重要的成员变量:ops 和 dev,这两个就是字符设备文件操作函数集合 file_operations 以及设备号 dev_t。
  • 3、在 cdev_add 函数后面添加自动创建设备节点相关代码。这一步开始才是跟自动创建设备节点相关的内容,前面两步是铺垫。
  • 4、首先要创建一个 class 类,class 是个结构体。
  • 5、在这个类下创建一个设备。使用 device_create 函数在类下面创建设备。
    通过以上步骤,设备的节点便可实现自动挂载,挂载至/dev目录下。

驱动挂载出现问题

在做一次按键扫描的驱动阻塞实验时,发现把设备名称改为blockio时,通过modprobe可以将设备挂载成功,但是不能通过一个app程序去运行这个节点,经过查找原因,发现/dev目录下的blockio文件不是字符类型的设备,而是块类型设备,具体是什么设备可以通过brw-rw----前面的b和c推断出来,随后我用手动创建节点的方式将这个节点强制变为字符设备的形式在去用app程序运行这个节点便可以成功。具体的过程可以见下图:
在这里插入图片描述
当我们名称里面不含block时,自动生成的节点都是字符类型的可以运行,可能是block这个词汇比较敏感导致的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop分布式文件系统(一)——HDFS简介

目录 1. HDFS设计目标2. HDFS组件3. HDFS数据复制4. HDFS健壮性4.1 磁盘数据错误&#xff0c;心跳检测和重新复制4.2 集群均衡4.3 数据完整性4.4 元数据磁盘错误4.5 快照 5. HDFS数据组织5.1 数据块存储5.2 流水线复制5.3 文件的删除和恢复 参考 1. HDFS设计目标 1.错误检测和快…

VUE练习

使用new Vue()创建Vue实例&#xff0c;传入配置对象&#xff08;el data&#xff09; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial…

论文笔记3-XCube: Large-Scale 3D Generative Modeling using Sparse Voxel Hierarchies

目录 Abtract 相关工作 核心算法&#xff1a; 整体流程概述 具体流程解析 1. 输入&#xff08;Input&#xff09; 2. 稀疏结构 VAE&#xff08;Sparse Structure VAE&#xff09; 3.分层体素潜在扩散&#xff08;Hierarchical Voxel Latent Diffusion&#xff09;…

js.二叉搜索树中第K小的元素

链接&#xff1a;230. 二叉搜索树中第 K 小的元素 - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 小的元素&#xff08;从 1 开始计数&#xff09;。 示例 1…

RabbitMQ 安装延迟队列插件 rabbitmq_delayed_message_exchange

前言&#xff1a; RabbitMQ 延迟队列插件&#xff08;rabbitmq_delayed_message_exchange&#xff09;是一个社区开发的插件&#xff0c;它为 RabbitMQ 添加了支持延迟消息的功能。通过这个插件&#xff0c;用户可以创建一种特殊的交换机类型 x-delayed-message&#xff0c;该…

Java安全—原生反序列化重写方法链条分析触发类

前言 在Java安全中反序列化是一个非常重要点&#xff0c;有原生态的反序列化&#xff0c;还有一些特定漏洞情况下的。今天主要讲一下原生态的反序列化&#xff0c;这部分内容对于没Java基础的来说可能有点难&#xff0c;包括我。 序列化与反序列化 序列化&#xff1a;将内存…

【人工智能】深入解析GPT、BERT与Transformer模型|从原理到应用的完整教程

在当今人工智能迅猛发展的时代&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域涌现出许多强大的模型&#xff0c;其中GPT、BERT与Transformer无疑是最受关注的三大巨头。这些模型不仅在学术界引起了广泛讨论&#xff0c;也在工业界得到了广泛应用。那么&#xff0c;G…

d3-contour 生成等高线图

D3.js 是一个强大的 JavaScript 库&#xff0c;用于创建动态、交互式数据可视化。d3-contour 是 D3.js 的一个扩展模块&#xff0c;用于生成等高线图&#xff08;contour plots&#xff09;。 属性和方法 属性 x: 一个函数&#xff0c;用于从数据点中提取 x 坐标。y: 一个函…

Apache Zeppelin:一个基于Web的大数据可视化分析平台

今天给大家推荐一下 Apache Zeppelin&#xff0c;它是一个基于 Web 的交互式数据接入、数据分析、数据可视化以及协作文档 Notebook&#xff0c;类似于 Jupyter Notebook。 Apache Zeppelin 支持使用 SQL、Java、Scala、Python、R 等编程语言进行数据处理和分析&#xff0c;同时…

使用 pycharm 新建不使用 python 虚拟环境( venv、conda )的工程

有时候我们发现一个好玩的 demo&#xff0c;想赶快在电脑上 pip install 一下跑起来&#xff0c;发现因为 python 的 venv、conda 环境还挺费劲的&#xff0c;因为随着时间的发展&#xff0c;之前记得很清楚的 venv、conda 的用法&#xff0c;不经常使用&#xff0c;半天跑不起…

计算机网络 实验八 应用层相关协议分析

一、实验目的 熟悉CMailServer邮件服务软件和Outlook Express客户端软件的基本配置与使用&#xff1b;分析SMTP及POP3协议报文格式和SMTP及POP3协议的工作过程。 二、实验原理 为了观察到邮件发送的全部过程&#xff0c;需要在本地计算机上配置邮件服务器和客户代理。在这里我…

vue 实现关键字高亮效果

vue 实现关键字高亮效果 这是啥子意思呢&#xff0c;就是类似于百度搜索&#xff0c;根据关键词搜索结果&#xff0c;搜索结果中&#xff0c;与关键词相同的字显示红色&#xff0c;仅此而已&#xff0c;没有什么大的功能。简单写一下demo。 环境 我使用的是 vue3 ts 的语法来…

【大数据学习 | Spark-Core】广播变量和累加器

1. 共享变量 Spark两种共享变量&#xff1a;广播变量&#xff08;broadcast variable&#xff09;与累加器&#xff08;accumulator&#xff09;。 累加器用来对信息进行聚合&#xff0c;相当于mapreduce中的counter&#xff1b;而广播变量用来高效分发较大的对象&#xff0c…

2024年11月24日Github流行趋势

项目名称&#xff1a;FreeCAD 项目维护者&#xff1a;wwmayer, yorikvanhavre, berndhahnebach, chennes, WandererFan等项目介绍&#xff1a;FreeCAD是一个免费且开源的多平台3D参数化建模工具。项目star数&#xff1a;20,875项目fork数&#xff1a;4,117 项目名称&#xff1…

零基础学安全--shell脚本学习(1)脚本创建执行及变量使用

目录 学习连接 什么是shell shell的分类 查看当前系统支持shell 学习前提 开始学习 第一种执行脚本方法 ​编辑 第二种执行脚本方法 第三种执行脚本方法 变量声明和定义 ​编辑 查看变量 删除变量 学习连接 声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣…

Java后端如何进行文件上传和下载 —— 本地版

简介&#xff1a; 本文详细介绍了在Java后端进行文件上传和下载的实现方法&#xff0c;包括文件上传保存到本地的完整流程、文件下载的代码实现&#xff0c;以及如何处理文件预览、下载大小限制和运行失败的问题&#xff0c;并提供了完整的代码示例。 大体思路 1、文件上传 …

Z2400024基于Java+SSM+mysql+maven开发的社区论坛系统的设计与实现(附源码 配置 文档)

基于SSM开发的社区论坛系统 1.摘要2.主要功能3.系统运行环境4.项目技术5.系统界面截图6.源码获取 1.摘要 本文介绍了一个基于SSM&#xff08;Spring、Spring MVC、MyBatis&#xff09;框架开发的社区论坛系统。该系统旨在打造一个高品质的开发者社区&#xff0c;为开发者提供一…

JAVA笔记 | 策略模式+枚举Enum简单实现策略模式(可直接套用)

本篇为更为简单的策略模式应用&#xff0c;使用枚举来进行策略分配 上一篇(链接如下)更像是策略工厂模式来分配策略 JAVA笔记 | 实际上用到的策略模式(可直接套用)-CSDN博客 先创建策略相关类 //策略类 public interface PetStrategy {/*** 执行动作 - 跑RUN*/String run(Str…

RabbitMQ 篇-深入了解延迟消息、MQ 可靠性(生产者可靠性、MQ 可靠性、消费者可靠性)

??博客主页&#xff1a;【_-CSDN博客】** 感谢大家点赞??收藏评论** 文章目录 ???1.0 RabbitMQ 的可靠性 ? ? ? ? 2.0 发送者的可靠性 ? ? ? ? 2.1 生产者重试机制 ? ? ? ? 2.2 生产者确认机制 ? ? ? ? 2.2.1 开启生产者确认机制 ? ? ? ? 2.2…

Redis(概念、IO模型、多路选择算法、安装和启停)

一、概念 关系型数据库是典型的行存储数据库&#xff0c;存在的问题是&#xff0c;按行存储的数据在物理层面占用的是连续存储空间&#xff0c;不适合海量数据存储。 Redis在生产中使用的最多的是用作数据缓存。 服务器先在缓存中查询数据&#xff0c;查到则返回&#xff0c;…