主设备号和次设备号

对字符设备的访问是通过文件系统内的设备名称进行的,这些名称被称为特殊文件、设备文件、或者简单称之为文件系统树的节点,它们通常位于/dev目录。字符设备驱动程序的设备文件可以通过ls -l命令输出的第一列中的c字符来识别,块设备也出现在/dev下,但它们由字符b来标识;

通过执行ls -l 命令,可以看到在修改日期之前,有两个用逗号分隔的数字,分别为主设备号和次设备号。

主设备号标识设备对应的驱动程序;linux设备内核允许多个驱动程序共享主设备号;

次设备号由内核使用,用用户正确确定设备文件所指的设备。依赖驱动程序的编写方式,我们可以通过次设备号获得一个指向内核设备的直接指针,也可以将次设备号当做设备本地数组的索引。不管哪种方式,除了知道次设备号用来指向驱动程序所实现的设备之外,内核本身不关心关于此设备号的其他信息;

crw-rw----.  root video    ,  Nov  : agpgart
crw-------. root root , Nov : autofs
drwxr-xr-x. root root Nov : block
drwxr-xr-x. root root Nov : bsg
crw-------. root root , Nov : btrfs-control
drwxr-xr-x. root root Nov : bus
lrwxrwxrwx. root root Nov : cdrom -> sr0
drwxr-xr-x. root root Nov : char
crw-------. root root , Nov : console
lrwxrwxrwx. root root Nov : core -> /proc/kcore
drwxr-xr-x. root root Nov : cpu
crw-------. root root , Nov : cpu_dma_latency
crw-------. root root , Nov : cuse
drwxr-xr-x. root root Nov : disk
crw-rw----+ root audio , Nov : dmmidi
设备编号的内部表达

内核中,dev_t类型(位于<linux/types.h>)用来保存设备编号,包括主设备号和次设备号;

 typedef __u32 __kernel_dev_t;

 typedef __kernel_dev_t        dev_t;

可见dev_t类型是个32位的无符号整数,其中12位用来表示主设备号,其余20位表示次设备号;我们不应该对设备编号的组织做假定,而应该始终使用如下两个宏(位于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))

如果需要将主次设备号转换成dev_t类型,则使用下面宏(位于linux/kdev_t.h):

 #define MKDEV(ma,mi)    (((ma) << MINORBITS) | (mi))
分配和释放设备编号

指定范围分配编号:

在建立一个字符设备之前,我们的驱动程序首先要做的事情就是获取一个或者多个设备编号,完成该工作的必要函数是register_chrdev_region,该函数在<linux/fs.h>中声明:

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

参数from标识要分配的设备号范围的起始值,次设备号经常设置为0,但对该函数不是必须的;

参数count标识分配设备号的个数,如果count非常大,则所请求的范围可能和下一个主设备号重叠,但是只要我们所请求的编号范围是可用的,则不会带来问题;

参数name是和该编号范围关联的设备名称,它将出现在/proc/devices和sysfs中;

动态分配设备编号:

在不知道要分配的设备号的时候,可以使用动态分配的方式,函数如下:

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

参数dev是仅用于输出的参数,在成功完成调用后将保存已分配范围的第一个编号;

参数baseminor是要使用的被请求的第一个次设备号,通常是0;

参数count标识分配设备号的个数;

参数name是和该编号范围关联的设备名称;

始终使用动态分配设备编号:

对于新的驱动程序,强烈建议不要随便选择一个当前设备未使用的设备号作为主设备号,而应该使用动态分配机制获取主设备号;驱动程序应该使用使用alloc_chrdev_region而不是register_chrdev_region函数;

动态分配的缺点:由于分配的主设备号不能始终保持一致,素以无法预先创建设备节点;对于驱动程序的一般做法是,为了加载一个使用动态主设备号的设备驱动程序,对insmod的调用可替换成一个简单的脚本,该脚本在调用insmod之后读取/proc/devices以获得新分配的主设备号,然后创建对应的设备文件;

释放设备编号:

在不使用设备编号的时候需要进行释放,函数如下:

 void unregister_chrdev_region(dev_t from, unsigned count)

Linux设备驱动程序 之 主次设备号的更多相关文章

  1. Linux设备驱动程序学习----1.设备驱动程序简介

    设备驱动程序简介 更多内容请参考Linux设备驱动程序学习----目录 1. 简介   Linux系统的优点是,系统内部实现细节对所有人都是公开的.Linux内核由大量复杂的代码组成,设备驱动程序可以 ...

  2. Linux设备驱动程序 之 字符设备的注册

    内核内部使用struct cdev结构来标识字符设备,在内核调用设备的操作之前,必须分配并注册一个或者多个上述结构,为此,我们的代码需要包含<linux/cdev.h>,其中定义了这个结构 ...

  3. Linux串口驱动程序(3)-打开设备

    先来分析一下串口打开的过程: 1.用户调用open函数打开串口设备文件:2.在内核中通过tty子系统,把open操作层层传递到串口驱动程序中:3.在串口驱动程序中的xx_open最终实现这个操作.这里 ...

  4. ARM Linux字符设备驱动程序

    1.主设备号和次设备号(二者一起为设备号): 一个字符设备或块设备都有一个主设备号和一个次设备号.主设备号用来标识与设备文件相连的驱动程序,用来反  映设备类型.次设备号被驱动程序用来辨别操作的是哪个 ...

  5. 如何编写Linux设备驱动程序

    一.Linux device driver 的概念 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口.设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看 ...

  6. Linux内核入门到放弃-设备驱动程序-《深入Linux内核架构》笔记

    I/O体系结构 总线系统 PCI(Peripheral Component Interconnect) ISA(Industrial Standard Architecture) SBus IEEE1 ...

  7. 深入理解Linux内核-I/O体系结构和设备驱动程序

    系统总线:1.链接CPU.RAM.I/O设备之间的数据流动.例如:PCI.ISA.EISA.MCA.SCSI.USB2.任何I\O设备有且仅能链接一条总线. I\O端口:1.每个连接到I\O总线上的设 ...

  8. linux设备驱动程序-i2c(0)-i2c设备驱动源码实现

    (基于4.14内核版本) 为了梳理清楚linux内核中的i2c实现框架,从本文开始,博主将分几个章节分别解析i2c总线在linux内核中的形成过程.匹配过程.以及设备驱动程序源码实现. 在介绍linu ...

  9. Linux设备驱动程序学习----目录

    目录 设备驱动程序简介 1.设备驱动程序简介 构造和运行模块 2.内核模块和应用程序的对比 3.模块编译和装载 4.模块的内核符号表  5.模块初始化和关闭  6.模块参数  7.用户空间编写驱动程序 ...

随机推荐

  1. JS ES7

    指数运算符(幂) ** console.log(3 ** 2); //9 判断数组中包含 Array.prototype.includes(value) var arr1 = [1,2,'a','b' ...

  2. php的小数位数最长多少位

    在php中, echo 0.1234567890123456;exit; // 结果为:0.12345678901235, 整数部分为0时,最多到14位小数,如果后面还有,就自动四舍五入 echo 7 ...

  3. 如何将公式插入到word

    平台:win10 x64+ office 2010+ Mathpix Snipping Tool +mathtype6.9b   直接安装就行,下载好了以后,要和word连接起来还需要下载一个插件,有 ...

  4. mysql启动失败,unit not found

    1 mysql启动 Failed to start mysqld.service: Unit not found.   2 查询/etc/init.d/下是否存在mysqld ll /etc/init ...

  5. python主要模块 和 常用方法简览

    ******************** PY核心模块方法 ******************** os模块: os.remove() 删除文件 os.unlink() 删除文件 os.rename ...

  6. Hadoop_16_MapRduce_MapTask并行度(切片)的决定机制

    MapTask的并行度决定map阶段的任务处理并发度,进而影响到整个job的处理速度那么,mapTask并行实例是否越多 越好呢?其并行度又是如何决定呢?Mapper数量由输入文件的数目.大小及配置参 ...

  7. PAT Basic 1083 是否存在相等的差 (20 分)

    给定 N 张卡片,正面分别写上 1.2.…….N,然后全部翻面,洗牌,在背面分别写上 1.2.…….N.将每张牌的正反两面数字相减(大减小),得到 N 个非负差值,其中是否存在相等的差? 输入格式: ...

  8. List去重比较

    import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashSet; import java.ut ...

  9. C# UdpClient使用

    客户端: public class UdpClientManager { //接收数据事件 public Action<string> recvMessageEvent = null; / ...

  10. integer == 号问题

    integer a=123 integer b=123 integer c=250 integer d=250 a==b(true) c==d (false) Integer中把-128-127 缓存 ...