[zz]主设备号和次设备号

摘要:
如上1,4,7分别是主设备号,0,1,3,7,70,71都是次设备号。对于2.6.x内核,dev_t是个32位量,其中12位用来表示主设备号,20位用来表示次设备号。不同的机型中,主设备号和次设备号的位数可能是不同的。应该使用MAJOR宏得到主设备号,使用MINOR宏来得到次设备号。相反,可以将主设备号和次设备号转换为设备号类型,使用宏MKDEV可以完成这个功能。一般只提供from的主设备号,from的次设备号通常被设置成0。

每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备,而次设备号用来区分同一类型的多个设备。对于常用设备,Linux有约定俗成的编号,如硬盘的主设备号是3。

-------------------------------------------------------------------------------------------------------------------------------------------------------------

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 uucp4,7004-14 18:16 ttyS6
crw-rw---- 1 root uucp4,7104-14 18:16 ttyS7
crw-rw---- 1 root tty7,008-08 18:58 vcs
crw-rw---- 1 root tty 7,108-08 18:58 vcs1
crw-rw-rw- 1 root root1,708-08 18:58 full
crw-rw-rw- 1 root root1,304-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_tdev_t;

typedef __u32 __kernel_dev_t;

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

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

#defineMINORBITS20/*次设备号*/

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

#defineMAJOR(dev)((unsignedint)((dev)>>MINORBITS))/*dev右移20位得到主设备号*/

#defineMINOR(dev)((unsignedint)((dev)&MINORMASK))/*与次设备掩码与,得到次设备号*/

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

#defineMKDEV(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文件的内容*/

Characterdevices:/*字符设备*/

1mem

4/dev/vc/0

7vcs

13input

14sound

21sg

Blockdevices:/*块设备*/

1ramdisk

2fd

8sd

253device-mapper

254mdp

申请和释放设备号

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

1.申请设备号

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

intregister_chrdev_region(dev_tfrom,unsignedcount,constchar*name);

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

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

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

intalloc_chrdev_region(dev_t*dev,unsignedbaseminor,unsignedcount,constchar*name)

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

2.释放设备号

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

voidunregister_chrdev_region(dev_tfrom,unsignedcount);

在上面这个函数中,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,172009-09-24 sdb1
brw-rw---- 1 root disk 8,182009-09-24 sdb2
brw-rw---- 1 root disk 8,212009-09-24 sdb5
brw-rw---- 1 root disk 8,222009-09-24 sdb6
brw-rw---- 1 root disk 8,232009-09-24 sdb7
brw-rw---- 1 root disk 8,242009-09-24 sdb8

免责声明:文章转载自《[zz]主设备号和次设备号》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇MDF,了解一下stm32之PWM学习下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Linux编辑内核配置

下面简单介绍一下Linux内核编译过程 该操作时在Linux redhat 6.5进行操作,Ubuntu操作同理,只需要下载对应的Linux内核就可以 1.下载linux-2.6.37.tar.bz2 链接:https://pan.baidu.com/s/1h_rjk8VjpQXr_InO-pw27Q 提取码:3kk1 2.解压内核源文件 tar -xvf...

Mac 下VIM配置

Mac下VIM配置  首先,我们去这里下载MacVim,也可用这个网址:(http://code.google.com/p/macvim/),进入后的界面如下: _______________________________________________________________________ Download Download MacVim...

Linux C errno出错处理

1. 出错处理errno 每个进程维护一个全局整型变量errno, 记录系统(调用)的最后一次错误代码. errno及其常量值定义位于<errno.h>.以前, errno不是线程安全的, 其定义是: extern int errno; 现在, 为支持多线程环境, errno定义是: extern int *__errno_location(...

Mac OS X下给树莓派安装Raspbian系统

先到树莓派的官方网站去下载一个系统镜像,推荐下载最新版的Raspbian系统。 将下载的ZIP压缩包解压后,将得到树莓派Raspbian系统的img镜像文件,打开MAC OS X自带“终端”,并切换当前目录到镜像所在位置,然后按照以下步骤即可将Raspbian系统刷入。 1. 确认镜像位于当前目录下 查看当前目录文件及其大小: ls -lh 得到如下类似...

Linux中通过/proc/stat等文件计算Cpu使用率

Linux平台Cpu使用率的计算 proc文件系统 /proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为内核与进程提供通信的接口。用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取/proc目录中的文件时,proc文件系统是动态从系统...

最优秀的5个Linux文本编辑器

from: http://article.yeeyan.org/view/169956/174836 作为不久前举办的比赛的一部分内容,我从那些选出他们最喜欢的Linux文本编辑器的极客读者们那获得了约200个反馈。 基于这个数据, 最最优秀的Linux文本编辑器是 Vi / Vim Editor Vim以绝对优势获胜在大家的意料之中。如果你不熟悉最好的5...