主设备号和次设备号

2023-05-16

     Linux的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备文件。应用程序可以打开、关闭和读写这些设备文件,完成对设备的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。对于常用设备,Linux有约定俗成的编号,如硬盘的主设备号是3。

     一个字符设备或者块设备都有一个主设备号和次设备号。主设备号和次设备号统称为设备号。主设备号用来表示一个特定的驱动程序。次设备号用来表示使用该驱动程序的各设备。例如一个嵌入式系统,有两个LED指示灯,LED灯需要独立的打开或者关闭。那么,可以写一个LED灯的字符设备驱动程序,可以将其主设备号注册成5号设备,次设备号分别为1和2。这里,次设备号就分别表示两个LED灯。

     设备文件通常都在 /dev 目录下。如:

beyes@linux-beyes:~/C/kernel/memory> ll /dev |more
总计 0
crw-rw----  1 root uucp    470 04-14 18:16 ttyS6
crw-rw----  1 root uucp    471 04-14 18:16 ttyS7
crw-rw----  1 root tty         7,   0 08-08 18:58 vcs
crw-rw----  1 root tty         7,   1 08-08 18:58 vcs1
crw-rw-rw-  1 root root    1,   7 08-08 18:58 full
crw-rw-rw-  1 root root    1,   3 04-14 18:16 null

 

如上,前面第一个字符为c 的表示字符设备。在字符设备里,有主设备号和次设备号。如上1,4,7 分别是主设备号,0,1,3,7,70,71都是次设备号。一般的,主设备号标识出与设备关联的设备驱动。如 /dev/null 和 /dev/full 由 1 号驱动来管理,/dev/vcs 和/dev/vcs1由 7 号驱动来管理,/dev/ttyS6 由 4 号驱动来管理。

现在的 Linux 内核允许多个驱动共享一个主设备号,但更多的设备都遵循一个驱动对一个主设备号的原则。

内核由次设备号确定当前所指向的是哪个设备。根据所编写的驱动程序,可以从内核那里得到一个直接指向设备的指针,或者使用次设备号作为一个设备本地数组的索引。但不论如何,内核自身几乎不知道次设备号的什么事情。

设备号的内部表示

在内核中,dev_t  类型( 在 <linux/types.h> 头文件有定义 ) 用来表示设备号,包括主设备号和次设备号两部分。对于 2.6.x 内核,dev_t 是个 32 位量,其中 12 位用来表示主设备号,20 位用来表示次设备号。
在 linux/types.h 头文件里定义有

typedef __kernel_dev_t          dev_t;

typedef __u32 __kernel_dev_t;

 

主设备号和次设备号的获取

为了写出可移植的驱动程序,不能假定主设备号和次设备号的位数。不同的机型中,主设备号和次设备号的位数可能是不同的。应该使用MAJOR宏得到主设备号,使用MINOR宏来得到次设备号。下面是两个宏的定义:(linux/kdev_t.h

 

#define MINORBITS   20                                  /*次设备号*/  

#define MINORMASK   ((1U << MINORBITS) - 1)             /*次设备号掩码*/  

#define MAJOR(dev)  ((unsigned int) ((dev) >> MINORBITS))   /*dev右移20位得到主设备号*/  

#define MINOR(dev)  ((unsigned int) ((dev) & MINORMASK))   /*与次设备掩码与,得到次设备号*/ 

 

MAJOR宏将dev_t向右移动20位,得到主设备号;MINOR宏将dev_t的高12位清零,得到次设备号。相反,可以将主设备号和次设备号转换为设备号类型(dev_t),使用宏MKDEV可以完成这个功能。

#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))

MKDEV宏将主设备号(ma)左移20位,然后与次设备号(mi)相与,得到设备号

 

静态分配设备号

静态分配设备号,就是驱动程序开发者,静态地指定一个设备号。对于一部分常用的设备,内核开发者已经为其分配了设备号。这些设备号可以在内核源码documentation/ devices.txt文件中找到。如果只有开发者自己使用这些设备驱动程序,那么其可以选择一个尚未使用的设备号。在不添加新硬件的时候,这种方式不会产生设备号冲突。但是当添加新硬件时,则很可能造成设备号冲突,影响设备的使用。


动态分配设备号

由于静态分配设备号存在冲突的问题,所以内核社区建议开发者使用动态分配设备号的方法。动态分配设备号的函数是alloc_chrdev_region()。

 

查看设备号

当静态分配设备号时,需要查看系统中已经存在的设备号,从而决定使用哪个新设备号。可以读取/proc/devices文件获得设备的设备号。/proc/devices文件包含字符设备和块设备的设备号,如下所示:

 

[root@tom /]# cat /proc/devices /*cat命令查看/proc/devices文件的内容*/  

Character devices:                  /*字符设备*/  

   1 mem  

   4 /dev/vc/0  

   7 vcs  

   13 input  

   14 sound  

   21 sg  

Block devices:                      /*块设备*/  

   1 ramdisk  

   2 fd  

   8 sd  

   253 device-mapper  

   254 mdp 

 

申请和释放设备号

内核维护着一个特殊的数据结构,用来存放设备号与设备的关系。在安装设备时,应该给设备申请一个设备号,使系统可以明确设备对应的设备号。设备驱动程序中的很多功能,是通过设备号来操作设备的。下面,首先对申请设备号进行简述。

1.申请设备号

在构建字符设备之前,首先要向系统申请一个或者多个设备号。完成该工作的函数是register_chrdev_region(),该函数在<linux/fs.h>中定义:

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

其中,from是要分配的设备号范围的起始值。一般只提供from的主设备号,from的次设备号通常被设置成0。count是需要申请的连续设备号的个数。最后name是和该范围编号关联的设备名称,该名称不能超过64字节。

和大多数内核函数一样,register_chrdev_region()函数成功时返回0。错误时,返回一个负的错误码,并且不能为字符设备分配设备号。 

     在Linux中有非常多的字符设备,在人为的为字符设备分配设备号时,很可能发生冲突。Linux内核开发者一直在努力将设备号变为动态的。可以使用alloc_chrdev_region()函数达到这个目的。(linux/fs.h)

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

在上面的函数中,dev作为输出参数,在函数成功返回后将保存已经分配的设备号。函数有可能申请一段连续的设备号,这是dev返回第一个设备号。baseminor表示要申请的第一个次设备号,其通常设为0。count和name与register_chrdev_region()函数的对应参数一样。count表示要申请的连续设备号个数,name表示设备的名字。

 

2.释放设备号

使用上面两种方式申请的设备号,都应该在不使用设备时,释放设备号。设备号的释放统一使用下面的函数:

void unregister_chrdev_region(dev_t from, unsigned count);  

在上面这个函数中,from表示要释放的设备号,count表示从from开始要释放的设备号个数。通常,在模块的卸载函数中调用unregister_chrdev_region()函数。

 

次设备号的主要用途

1、区分设备驱动程序控制的实际设备;

2、区分不同用途的设备 (misc 系列设备)

3、区分块设备的分区 (partition)

通常,为了使应用程序区分所控制设备的类型,内核使用主设备号。而存在多台同类设备时,为了选择其中的一种,设备驱动程序就使用次设备号。

 

 

 

 

 

 

 

区分块设备的分区

块设备具有被称为分区的分配领域。例如,硬盘在物理上是一个设备,从内核的角度,硬盘被分为多个分区,而以这些分区为对象则形成了文件系统,此时,次设备号既表示设备,也表示分区

brw-rw----  1 root disk    8,  16 2009-09-24 sdb
brw-rw----  1 root disk    8,  17 2009-09-24 sdb1
brw-rw----  1 root disk    8,  18 2009-09-24 sdb2
brw-rw----  1 root disk    8,  21 2009-09-24 sdb5
brw-rw----  1 root disk    8,  22 2009-09-24 sdb6
brw-rw----  1 root disk    8,  23 2009-09-24 sdb7
brw-rw----  1 root disk    8,  24 2009-09-24 sdb8
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

主设备号和次设备号 的相关文章

  • STM32-ESP8266wifi模块实现

    1 ESP8266WiFi模块介绍 1 1ESP8266wifi 模块 低功耗串口WiFi模块ESP8266内置一个Tensilica xff08 泰思立达 xff09 Xtensa架构的32位处理器L106 xff0c 具有5级流水线 A
  • ESP8266WiFi模块实现代码

    ESP8266WiFi模块实现TCP连接服务器 在前面的博客里 xff08 STM32 ESP8266wifi模块实现 xff09 说到了通过AT命令配置ESP8266实现TCP连接 他的流程是 xff0c 1 xff0c 使能串口 xff
  • 2021-05-14 Redis面试题 redis 部署生产环境

    redis 部署生产环境 redis cluster xff0c 10 台机器 xff0c 5 台机器部署了 redis 主实例 xff0c 另外 5 台机器部署了 redis 的从实例 xff0c 每个主实例挂了一个从实例 xff0c 5
  • 实现Basic认证

    Basic认证是一种较为简单的HTTP认证方式 xff0c 客户端通过明文 xff08 Base64编码格式 xff09 传输用户名和密码到服务端进行认证 xff0c 通常需要配合HTTPS来保证信息传输的安全 Maven依赖 lt par
  • STM32的串口空闲中断

    STM32串口使用DMA方式接收数据可以减小CPU的开销 对于接收定长数据 xff0c 可以将DMA接收缓冲区的长度设定为待接收数据的长度 xff0c 这样利用DMA的传输完成中断DMAx IT TCy就可以知道已经接收了一帧数据 对于接收
  • C#完整的通信代码(点对点,点对多,同步,异步,UDP,TCP)

    C code namespace UDPServer class Program static void Main string args int recv byte data 61 new byte 1024 构建TCP 服务器 得到本机
  • http digest认证(Java server)

    背景 xff1a 服务器接收客户端请求 xff0c 处理并验证 并返回服务器的验证结果 关于digest认证的相关概念及验证原理查看相关的说明 xff0c 此处只对处理进行贴码 CODE import com alibaba fastjso
  • 测试apache时出现[error] [client 192.168.6.1] File does not exist: /etc/httpd/htdocs

    问题 xff1a 测试apache时出现 error client 192 168 6 1 File does not exist etc httpd htdocs 解决方法 xff1a 1 创建文件夹htdocs xff08 etc ht
  • HAL库 STM32 串口通信函数

    HAL UART Receive IT串口 xff01 HAL UART Receive IT amp UART1 Handler u8 aRxBuffer RXBUFFERSIZE HAL UART Receive IT函数使用的时候 简
  • linux环境下安装QT超详细

    QT安装 1 首先下载QT安装包 QT官网 xff1a Index of archive qt 我这里使用的是qt opensource linux x64 5 14 0 run版本 2 打开终端 xff0c 输入命令 xff0c 赋予安装
  • 使用ssh连接虚拟机保姆级教程

    首先安装SSH 安装先检测是否已经安装SSH xff1a service ssh status 如果出现提示 xff1a ssh unrecognized service 说明没有安装openSSH xff0c 则需安装ssh SSH 服务
  • 小游戏2048设计思路超简单

    2048作为一个经典的小游戏 xff0c 对于C语言的逻辑练习是一个比较好的案例了 xff0c 看似很复杂 xff0c 但是如果掌握了设计思路 xff0c 那么就不会觉得难了 xff0c 而且会了这个之后对今后编程的也会有很大的帮助 先分析
  • ES-Elasticsearch查看所有索引及查看某索引下的信息

    1 查看所有索引 xff0c 地址栏直接访问下面的连接 http localhost 9200 cat indicesv amp pretty 2 查看某索引下存的信息 xff0c 查询的信息为索引结构信息 xff08 indexName为
  • 教你十分钟搭建博客,已在多台电脑测试,无坑

    1 前期工作 1 注册Github账号 官网地址 xff1a GitHub 2 下载安装git Git软件下载地址 xff1a Git Downloading Package git scm com 安装的话一直点next就可以了 3 绑定
  • MQTT使用TLS加密

    使用TLS加密在MQTT的使用中是比较常见的 xff0c TLS加密过程在网上有很多说明 xff0c 但是没几个应用教程的 xff0c MQTT软件中的EMQX软件是支持TLS加密的 xff0c 只不过要进行一些设置 安装EMQX软件 首先
  • linux下将QT移植至arm环境

    前言 讲下整个项目流程 xff0c 我们的目标是把qt编出来程序放在arm开发板上面跑 xff0c 首先下载QT源码和tslib源码 xff08 QT源码编译和QT程序运行需要tslib库的支持 xff09 xff0c 在虚拟机里使用交叉编
  • linux下移植onvif至arm环境

    前言 onvif是一种网络摄像头协议 xff0c linux网络摄像头这一块是需要移植onvif协议的 xff0c 整个移植过程是这样的 xff0c 首先onvif协议是依赖于gsoap的 xff0c 所以需要先将gsoap编译安装 xff
  • C语言使用二级指针实现字符串分割

    话不多说 xff0c 直接上代码 include lt stdio h gt int opt char p char ch char res char q 61 p if q 61 61 NULL q 61 61 39 0 39 retur
  • 已include包却提示未定义标识符

    已 include lt string gt xff0c include lt vector gt 却提示string xff0c vector未定义的标识符 因为没定义默认的命名空间 xff0c 改为std string xff0c st

随机推荐

  • jpg和png的区别小结

    png图像的大小是jpg图像大小的数倍 xff0c png为可移植网络图形格式 xff0c 也是一种位图文件存储格式 xff0c 可以进行无损压缩 xff0c jpg是最常见的图像格式 xff0c 图像占用的存储较小 xff0c 但是牺牲了
  • 色彩空间中的HSL、HSV、HSB有什么区别?

    作者 xff1a 大蔚陈 链接 xff1a https www zhihu com question 22077462 answer 29483467 来源 xff1a 知乎 著作权归作者所有 商业转载请联系作者获得授权 xff0c 非商业
  • opencv小程序练习——createBackgroundSubtractorMOG2()实现跟踪

    思想 xff1a 使用createBackgroundSubtractorMOG2 使用运动物体背景分割 使用findContours 查找轮廓并画出 实现一定感官上的跟踪功能 代码如下 xff1a include lt opencv2 o
  • opencv_tutorial_code学习——canny边缘检测后findContours

    tutorial code ShapeDescriptors findContours demo cpp 步骤 xff1a 1 灰度化 2 滤波 3 canny边缘检测 4 findContours canny output contour
  • idea开发工具右侧没有maven工具栏

    一 解决方式一 依次点击 View gt Tool Windows gt Maven xff0c 如下图 xff1a 二 解决方式二 点击如图所示IDEA界面最左下角的按钮 xff0c 如下图 xff1a 三 解决方式三 1 打开项目的 p
  • 语义分割与实例分割的区别

    目前的分割任务主要有两种 xff1a xff08 1 xff09 像素级别的语义分割 xff08 2 xff09 实例分割 这个有意思 xff0c 什么叫实例分割呢 xff1f 它与语义分割有什么区别与联系呢 xff1f 顾名思义 xff0
  • tiny-dnn配置运行

    tiny dnn是一个轻量级的CNN xff08 卷积神经网络 xff09 xff0c 不需要各种依赖和GPU xff0c 由三千多行C 43 43 代码完成 适配android平台的话 xff0c 感觉这个比较好做一点 下载地址 xff1
  • SSM笔记

    进入数据库 xff1a 34 D Program Files x86 mysql 5 7 20 winx64 bin mysql exe 34 u root p admin 展示数据库 xff1a show databases 创建数据库
  • 工程编译那点事:Makefile和cmake(一)

    makefile 前言Makefile介绍 Makefile规则make是如何工作的Makefile使用变量让make自动推导另类风格的Makefilemake中的函数文件搜索绝对顶级的大型工程Makefile 前言 一个项目 xff0c
  • 头文件相互包含问题

    先来看看以下这个例子 xff1a Keyboard h的代码为 span class token macro property span class token directive hash span span class token di
  • 解决roslaunch启动stage_ros节点仿真时输出rostopic hz速率较低的问题(始终为10Hz)

    问题描述 xff1a 在实验过程中偶然间发现无论是odom还是laser scan的输出频率都只有10Hz clock输出速率有50Hz 直接使用命令 rosrun stage ros stageros test world能够正常输出50
  • STM32八种IO口模式区别

    xff08 1 xff09 GPIO Mode AIN 模拟输入 xff08 2 xff09 GPIO Mode IN FLOATING 浮空输入 xff08 3 xff09 GPIO Mode IPD 下拉输入 xff08 4 xff09
  • linux下C++实现Http请求类(GET,POST,上传,下载)

    linux下C 43 43 实现Http请求类 GET xff0c POST xff0c 上传 xff0c 下载 Http协议简述 协议 xff1a 网络协议的简称 xff0c 网络协议是通信计算机双方必须共同遵从的一组约定 如怎么样建立连
  • 正点原子MiniFly V1.2学习笔记四---txQueue队列数据哪来

    笔记二的第四点中 xff0c 把解包出来的指令发送到 rxQueue队列里 xff0c 然后从txQueue队列取数据发送到串口 那么txQueue队列的数据从哪里来的 一 txQueue数据从哪里来 xff1f 二 什么地方会调用radi
  • redis链接工具

    redis链接工具 今天推荐一款redis链接工具 xff0c 其实世面上连接redis的工具很多 xff0c 但是好用的很少 例如 xff1a redis desktop manager这款工具也不错 xff0c 但是我个人不能使用 xf
  • Linux 网络编程——UDP编程

    一 概述 UDP 是 User Datagram Protocol 的简称 xff0c 中文名是用户数据报协议 xff0c 是一个简单的面向数据报的运输层协议 xff0c 在网络中用于处理数据包 xff0c 是一种无连接的协议 UDP 不提
  • 给指定的寄存器地址:0x0001eea7 ,赋值

    coretexM0平台上给指定的寄存器地址 xff1a 0x0001eea7 赋值100 怎么实现 xff1f xff08 volatile char xff09 0x0001eea7 61 100 xff1b 常见错误1 xff1a xf
  • 常见cmake命令总结

    常见cmake命令总结 cmake常见命令 cmake minimum required 指定CMake的最小版本要求 cmake minimum required VERSION 2 8 project 定义工程名称 project PR
  • 利用Qt Phonon框架制作音视频播放器

    Phonon严格来说其实非为Qt的library xff0c Phonon原本就是KDE 4的开放源代码多媒体API xff0c 後来与Qt合并与开发 xff0c 所以简单来说就是Qt使用Phonon这个多媒体框架来提供一般影音多媒体档案的
  • 主设备号和次设备号

    Linux的设备管理是和文件系统紧密结合的 xff0c 各种设备都以文件的形式存放在 dev目录下 xff0c 称为设备文件 应用程序可以打开 关闭和读写这些设备文件 xff0c 完成对设备的操作 xff0c 就像操作普通的数据文件一样 为