字符设备驱动详解(主次设备号、注册/卸载字符设备驱动、创建设备节点、地址映射)

2023-11-13

1、主次设备号

(1)主次设备号是内核用来索引设备的,每个主次设备号在内核中都是唯一的,每个注册的设备都有一个分配的主次设备号;
(2)同一个主设备号可以有多个从设备号,主设备是对应的驱动程序,次设备号对应设备文件所指的设备。一个Soc可能接同样功能
的几个设备,这些设备属于同类设备甚至可以共享同一个驱动;那这几个设备就共用一个主设备号,然后再用次设备号来区分;
(3)多个次设备号共享主设备号是为了解决主设备号过多的问题,并且同类设备共享一个主设备号也便于理解和管理,但是仍有很多设备还是按照“一个主设备号对应一个设备”的原则组织;

2、查看设备的主次设备号

2.1、驱动已经注册并且创建了设备节点

在这里插入图片描述

(1)对设备的访问是通过文件系统内的设备名称进行的,这些文件被称为特殊文件、设备文件,通常位于/dev目录下;
(2)"c"开头的是字符设备,"b"开头的是块设备;
(3)红框里的就是主次设备号,可以看到主设备号218就对应多个次设备号;

2.2、驱动已经注册但还没有创建设备节点

root@ubuntu: cat /proc/devices 
Character devices:
 ······
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
216 rfcomm
226 drm
251 hidraw
252 bsg
253 watchdog
254 rtc

Block devices:
  1 ramdisk
  2 fd
259 blkext
  7 loop
  8 sd
  9 md
······
252 device-mapper
253 virtblk
254 mdp
root@ubuntu:~/dai_zhi_xin/kernel/jiuding_kernel/kernel# 

cat /proc/devices :可以查看已经注册的驱动程序,但是只显示主设备号;

3、设备编号的内部表达

typedef unsigned int __u32;
typedef __u32 __kernel_dev_t;
typedef __kernel_dev_t		dev_t;

//从设备编号中获取主设备号
MAJOR(dev_t dev);

//从设备号中获取次设备号
MINOR(dev_t dev);

//根据主次设备号构建出dev_t类型的设备编号
MKDEV(int major, int minor);

(1)在内核中用dev_t类型表示设备编号,其实dev_t就是unsigned int类型,只不过其中的某几位表示主设备号,剩下的位表示次设备号;
(2)不同版本的内核,dev_t中用来表示主设备号和次设备号的位数不同,为了兼容性我们不能在代码中直接写死,要用上面的宏定义来操作设备编号;
补充:2.6内核之前的版本限定最大255个主设备和255个次设备号;

4、分配设备编号

4.1、指定设备号和动态分配设备号

(1)指定设备号:当我们知道当前系统未被占用的设备编号,可以在申请设备号时指定一个空闲的设备编号。劣势:当我们写的驱动程序被别人移植时,因为别人的系统
环境和我们不同,驱动代码里指定的设备编号很可能已经被占用,这样就会报错;优势:因为知道设备编号,可以预先创建设备节点;
(2)动态分配编号:不指定设备编号,而是使用系统分配的空闲的设备标号。劣势:不同的系统,分配的设备编号不同,所以不能预先创建设备节点;
优势:驱动代码可移植性强,不用关心当前系统哪些设备号是空闲的;
总结:强烈建议使用动态分配设备编号,然后用加载脚本或者udev去解决设备节点的创建问题;在内核的设备号申请函数中,默认使用动态分配,但也保留的指定设备号的申请接口;

4.2、指定设备号

int register_chrdev_region(dev_t first, unsigned count, const char *name);

(1)first:要分配的设备编号范围的起始值,first的次设备号经常被置为零,但不是必须的;
(2)count:请求的连续设备编号的个数;
(3)name:和编号范围关联的设备名称,将出现在/proc/devices和sysfs中;
总结:这个函数要提前明确知道所需要的设备编号,如果你申请分配的主设备已经被占用则会出错;

4.3、动态分配设备号

int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char * name);

(1)dev:这是用于输出的参数,内核会将已分配范围的第一个编号返回回来;
(2)firstminor:申请的第一个次设备号,通常是0。如果你不填0,假如你填3,则次设备号就是从3开始,依次往后增长;
(3)count:就是你要申请多少个设备号,也就是次设备号有多少个;
(4)name:和编号范围关联的设备名称,将出现在/proc/devices和sysfs中;

5、释放设备号

void unregister_chrdev_region(dev_t first, unsigned int count);

(1)first:要释放的起始设备编号;
(2)count:释放多少个设备编号,因为一个主设备号对应多个次设备号;

6、注册字符设备驱动

#define MYCNT		1
#define MYNAME		"testchar"

struct cdev *pcdev;
dev_t mydev

// 自定义一个file_operations结构体变量,并且去填充
static const struct file_operations test_fops = {
	.owner		= THIS_MODULE,				// 惯例,直接写即可
	
	.open		= test_chrdev_open,			// 将来应用open打开这个设备时实际调用的
	.release	= test_chrdev_release,		// 就是这个.open对应的函数
	.write 		= test_chrdev_write,
	.read		= test_chrdev_read,
};


//动态申请主次设备号
alloc_chrdev_region(&mydev, 12, MYCNT, MYNAME);

//给pcdev分配内存,指针实例化
pcdev = cdev_alloc(); 

//填充pcdev指向的结构体,有两种方式,调用cdev_init函数或者直接赋值
// cdev_init(pcdev, &test_fops);
pcdev->owner = THIS_MODULE;
pcdev->ops = &test_fops;

//注册字符设备驱动
cdev_add(pcdev, mydev, MYCNT);

(1)申请主次设备号;
(2)申请struct cdev结构体内存;
(3)填充struct cdev结构体,主要是赋值pcdev->ops,这是驱动程序的操作方法;

7、卸载字符设备驱动

//void cdev_del(struct cdev *p)
cdev_del(pcdev);

8、struct inode & struct file & struct file_operations

(1)struct inode:每个硬盘上的文件都有一个struct inode结构体来表示;
(2)struct file:每个打开的文件都对应一个struct file结构体;
(3)struct file_operations:字符驱动程序的操作方法;比如:open、read、write等操作如何操作字符设备;
参考博客:《驱动中重要的三个结构体介绍:struct inode、struct file、struct file_operations》

copy_to_user & copy_from_user

内核和用户空间之间的数据拷贝;参考博客:《内核空间和应用空间的数据拷贝(copy_to_user & copy_from_user)》

9、老版本的字符设备注册接口和卸载接口

//注册接口
static inline int register_chrdev(unsigned int major, const char *name,
				  const struct file_operations *fops)
				  
// 卸载接口 
static inline void unregister_chrdev(unsigned int major, const char *name)

(1)major:major传0进去表示要让内核帮我们自动分配一个合适的空白的没被使用的主设备号,内核如果成功分配就会返回分配的主设备好,如果分配失败会返回负数。major传大于0的数,表示想要申请这个数当主设备号,如果成功返回0,失败返回负数;
(2)name:设备的名字;
(3)fops:设备的操作方法,都是一些函数指针;

10、地址映射

参考博客:《静态映射和动态映射》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

字符设备驱动详解(主次设备号、注册/卸载字符设备驱动、创建设备节点、地址映射) 的相关文章

  • python获取上传/下载速度

    我想在我的计算机上监控上传和下载速度 一个名为 conky 的程序已经在 conky conf 中执行了以下操作 Connection quality alignr wireless link qual perc wlan0 downspe
  • 通过 Visual Studio 2017 使用远程调试时 Linux 控制台输出在哪里?

    我的Visual Studio 2017 VS2017 成功连接Linux系统 代码如下 include
  • 在centos中安装sqlite3 dev和其他包

    我正在尝试使用 cpanel 在 centos 机器上安装 sqlite dev 和其他库 以便能够编译应用程序 我对 debian 比 centos 更熟悉 我知道我需要的库是 libsqlite3 dev libkrb5 dev lib
  • tcpdump 是否受 iptables 过滤影响?

    如果我的开发机器有iptables规则到FORWARD一些数据包 这些数据包是否被 tcpdump 捕获 我有这个问题 因为我知道存在其他链称为INPUT如果数据包路由到 它会过滤发往应用程序的数据包FORWARD链 它会到达吗tcpdum
  • C 语言的符号表

    我目前正在开发一种执行模式匹配的静态分析工具 我在用Flex https github com westes flex生成词法分析器 我编写了代码来管理符号表 我不太有经验C 所以我决定将符号表实现为线性链表 include
  • 添加文件时运行 shell 命令

    我的 Linux 机器上有一个名为 images 的文件夹 该文件夹连接到一个网站 该网站的管理员可以向该网站添加图片 但是 当添加图片时 我想要一个命令来运行调整目录中所有图片的大小 简而言之 我想知道当新文件添加到特定位置时如何使服务器
  • 如何获取 (Linux) 机器的 IP 地址?

    这个问题和之前问的几乎一样如何获取本地计算机的IP地址 https stackoverflow com questions 122208 get the ip address of local computer 问题 但是我需要找到一个的I
  • CMake 链接 glfw3 lib 错误

    我正在使用 CLion 并且正在使用 glfw3 库编写一个程序 http www glfw org docs latest http www glfw org docs latest 我安装并正确执行了库中的所有操作 我有 a 和 h 文
  • Bash - 在与当前终端分开的另一个终端中启动命令的新实例

    我有一个简单的 bash 脚本 test sh 设置如下 bin bash args if args 0 check capture then watch n 1 ls lag home user capture0 watch n 1 ls
  • 内核的panic()函数是否完全冻结所有其他进程?

    我想确认内核的panic 功能和其他类似kernel halt and machine halt 一旦触发 保证机器完全冻结 那么 所有的内核和用户进程都被冻结了吗 是panic 可以被调度程序中断吗 中断处理程序仍然可以执行吗 用例 如果
  • 配置tomat的server.xml文件并自动生成mod_jk.conf

    我在用apache 2 2 15 and tomcat6 6 0 24 on CentOS 6 4并希望使用 tomcat 服务器的功能 通过添加以下内容自动生成 mod jk conf 文件
  • 在生产服务器上使用 Subversion 使文件生效的最佳方法是什么?

    目前我已经设置了 subversion 这样当我在 Eclipse PDT 中进行更改时 我可以提交更改 它们将保存在 home administrator 中项目文件 该文件具有 subversion 推荐的 branches tags
  • 绕过 dev/urandom|random 进行测试

    我想编写一个功能测试用例 用已知的随机数值来测试程序 我已经在单元测试期间用模拟对其进行了测试 但我也希望用于功能测试 当然不是全部 最简单的方法是什么 dev urandom仅覆盖一个进程 有没有办法做类似的事情chroot对于单个文件并
  • 如何使用Android获取Linux内核的版本?

    如何在 Android 应用程序中获取 Linux 内核的版本 不是 100 确定 但我认为调用 uname r 需要 root 访问权限 无论如何 有一种不太肮脏的方法可以做到这一点 那就是 System getProperty os v
  • 我什么时候应该编写 Linux 内核模块?

    有些人出于某种原因想要将 Linux 中的代码从用户空间移动到内核空间 很多时候 原因似乎是代码应该具有特别高的优先级 或者只是 内核空间更快 这对我来说似乎很奇怪 我什么时候应该考虑编写内核模块 有一套标准吗 我怎样才能激励将代码保存在
  • 如何在 Mac OSX Mavericks 中正确运行字符串工具?

    如何在 Mac OSX Mavericks 中正确运行字符串工具 我尝试按照我在网上找到的示例来运行它 strings a UserParser class 但我收到此错误 错误 Applications Xcode app Content
  • 尽管我已在 python ctypes 中设置了信号处理程序,但并未调用它

    我尝试过使用 sigaction 和 ctypes 设置信号处理程序 我知道它可以与python中的信号模块一起使用 但我想尝试学习 当我向该进程发送 SIGTERM 时 但它没有调用我设置的处理程序 只打印 终止 为什么它不调用处理程序
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • [A-Z] 表示 [A-Za-z] 是怎么回事?

    我已经注意到 至少在我使用的一些基于 Unix 的系统上 ls A Z 已经给了我预期的结果ls A Za z 让我无法轻松获得以大写字母开头的该死的文件列表 我刚刚遇到了同样的事情grep 我无法让它停止与小写字母匹配 A Z 直到我最终
  • 何时用引号将 shell 变量括起来?

    我应该或不应该在 shell 脚本中用引号括住变量吗 例如 下列说法正确的是 xdg open URL eq 2 or xdg open URL eq 2 如果是这样 为什么 一般规则 如果它可以为空或包含空格 或实际上任何空格 或特殊字符

随机推荐

  • 基于NI_TestStand的智能驾驶自动化测试

    在汽车产业不断发展的今天 智能驾驶已经成为了汽车中必不可少的一部分 虽然目前真正的无人驾驶技术还未广泛应用于我们的日常生活中 但各式各样的驾驶辅助系统 如碰撞预警 自动刹车 自适应巡航等功能已经在为我们的驾驶员保驾护航 今天小编就带大家一起
  • deepin v23

    deepin v23虚拟机windows远程控制 仅限内网 解决deepin在虚拟机中鼠标卡顿延迟问题 需要安装x11vnc和xrdp 1 安装ssh 2 安装x11vnc 2 1 x11vnc配置开机自启 3 安装xrdp 3 1 打开终
  • ffmpeg rtsp 推流_RTSP网络摄像头 WEB端播放 并实时人脸检测

    彩色视频为摄像头的原始数据 灰色视频 灰度化 缩放 用来检测人脸 人脸图片为比对成功后回显 项目地址 https github com 15225845996 rtsp face 功能描述 1 浏览器实时播放摄像头信息 2 实时人脸检测 圈
  • Window主机加固

    win r 输入cmd进入命令提示符 用dir调出所有任务 cd 可以进入一个指定目录 cd 穿越或返回上一层 文件名有空格不连贯就是蓝标 箭头所指 没有空格的就是红色所指 它们的区别在于有空格是有双引号的 没有空格是没有的 切换盘的话 直
  • [数据分析与可视化] Python绘制数据地图2-GeoPandas地图可视化

    本文主要介绍GeoPandas结合matplotlib实现地图的基础可视化 GeoPandas是一个Python开源项目 旨在提供丰富而简单的地理空间数据处理接口 GeoPandas扩展了Pandas的数据类型 并使用matplotlib进
  • Excel单元格数值统计

    Excel单元格数值统计 Excel 工作表中对选定区域的数值进行统计的功能非常实用 仿照Excel的这个功能 请对给定表格中选中区域中的单元格进行求和统计 并输出统计结果 为简化计算 假设当前输入中每个单元格内容仅为数字或公式两种 如果为
  • 2021-08-02

    触发器 查询 删除 修改 一 什么是触发器 触发器 trigger 是SQL server 提供给程序员和数据分析员来保证数据完整性的一种方法 它是与表事件相关的特殊的存储过程 它的执行不是由程序调用 也不是手工启动 而是由事件来触发 二
  • 分割2021算法合集

    魔改nnU Net夺冠 2021 BraTS 脑肿瘤分割竞赛第一名解决方案 魔改nnU Net夺冠 2021 BraTS 脑肿瘤分割竞赛第一名解决方案 代码 https github com rixez Brats21 KAIST MRI
  • 电子信息工程考研:12大专业方向解读

    导读 模式识别与智能系统专业解读 通信与信息系统专业解读 电路与系统专业解读 信号与信息处理专业解读 电子与通信工程专业解读 电力电子与电力传动专业解读 光电信息工程专业解读 物理电子学专业解读 控制工程专业解读 集成电路工程专业解读 精密
  • mysql row()函数_详解mysql数据库binlog三种模式的区别(row,statement,mixed)

    概述 Mysql binlog日志有三种格式 分别为Statement MiXED 以及ROW 这三种格式之间有什么区别呢 下面先介绍下各自的优缺点 ROW 日志中会记录成每一行数据被修改的形式 然后在slave端再对相同的数据进行修改 只
  • 5.12 树和森林的遍历

    一 树的遍历 1 先根遍历 根左右 深度优先遍历 若树非空 先访问根节点 再依次对每棵子树进行先根遍历 树的先根遍历 void PreOrder TreeNode R if R NULL visit R 访问根结点 while R还有下一棵
  • 动态图分类:DySAT算法及其Python实现

    动态图分类 DySAT算法及其Python实现 动态图分类是计算机视觉领域的一个重要任务 其目标是对动态图像序列进行分类 DySAT算法是一种基于结构Self Attention和时域Self Attention的深度学习模型 用于解决动态
  • 在阿里云里面服务器怎么样可以更好的链接数据库

    环境 阿里云ubuntu服务器 阿里云RDS数据库 问题 如何在阿里云服务器的终端使用shell命令连接RDS云数据库 解决方法 1 阿里云服务器安装MySQL sudo apt get install mysql server 如果出现u
  • 非标准包 game.rgss3a 的打开方法

    写在前面 最近在玩 RPG 游戏 想拆一个 Game rgss3a 包 在网上找了很久的拆包方法 感觉写的比较凌乱 我来给大家整理一下吧 不过我本人的技术能力也很差 不确定说的是不是对的 就当是给大家提供几个方法 大家都自己试一下吧 先说
  • 近源渗透学习

    一 近源渗透 近源渗透测试是网络空间安全领域逐渐兴起的一种新的安全评估手段 它是一种集常规网络攻防 物理接近 社会工程学及无线电通信攻防等能力于一体的高规格网络安全评估行动 网络安全评估小组在签订渗透测试授权协议后 通过乔装 社工等方式实地
  • git 常用命令---修改Git默认编辑器为vim

    1 配置 git config global user email you example com 配置git用户名 git config global user name Your Name 配置git邮件 git config glob
  • C++类使用未定义类型 use undefined class

    a h file include
  • [论文笔记]AutoAssign 阅读笔记

    AutoAssign 阅读笔记 AutoAssign Differentiable Label Assignment for Dense Object Detection 摘要 1 引言 2 相关工作 固定标签分配 Fixed Label
  • Vue.js 生命周期函数

    系列文章目录 Vue js基础简答题 文章目录 系列文章目录 前言 一 创建阶段 1 beforeCreate 2 created 3 beforeMount 4 mounted 二 运行阶段 1 beforeUpdate 2 update
  • 字符设备驱动详解(主次设备号、注册/卸载字符设备驱动、创建设备节点、地址映射)

    1 主次设备号 1 主次设备号是内核用来索引设备的 每个主次设备号在内核中都是唯一的 每个注册的设备都有一个分配的主次设备号 2 同一个主设备号可以有多个从设备号 主设备是对应的驱动程序 次设备号对应设备文件所指的设备 一个Soc可能接同样