文章目录
一、设备号
相关定义在 kdev_t.h
为 unsigned int 类型,由主设备号和次设备号组成。
31~20 bit | 19~0 bit |
---|---|
12bit | 20bit |
主设备号 | 次设备号 |
/* 次设备号所占位数为20,低20位为次设备号 */
#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))
主次设备号的理论取值范围
主设备号:2^12=1024*4=4k
次设备号:2^20=1024*1024=1M
使用cat /proc/devices
查看 已注册的 主设备号
。
格式:主设备号 设备名
可以看到不同类型的设备(字符设备、块设备)的主设备号相互独立
/ #
/ # cat /proc/devices
Character devices:
1 mem
4 /dev/vc/0
4 tty
5 /dev/tty
5 /dev/console
5 /dev/ptmx
7 vcs
10 misc
13 input
29 fb
81 video4linux
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
207 ttymxc
226 drm
250 ttyLP
251 watchdog
252 ptp
253 pps
254 rtc
Block devices:
1 ramdisk
259 blkext
7 loop
8 sd
31 mtdblock
65 sd
66 sd
67 sd
68 sd
69 sd
70 sd
71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
/ #
区分主次设备号的原因:
一个 设备驱动(file_operation)
占有 一个主设备号和多个次设备号
;
一个设备文件
占有 一个主设备号和一个次设备号
;
所以 设备驱动
与 设备文件
是一对一或者一对多的关系。就是多个设备可以共用一个驱动。
主设备号
相同次设备号
不相同,可以对应多个设备文件;但是是通过主次设备号在 cdev_map
中找到的 cdev->file_operations
;
主设备号
一样,次设备号
在同一给定范围内:就指向同一个 cdev->file_operations
。由此来实现。
在Linux内核中:
主设备号
标识 设备对应的驱动程序
,告诉Linux内核使用 哪一个驱动程序
为该设备(也就是/dev下的设备文件)服务
次设备号
标识具体且唯一的 某个设备
。
二、hash table
哈希表、散列表 chrdevs
用来管理设备号
static struct char_device_struct {
struct char_device_struct *next;
unsigned int major; /* 主设备号 */
unsigned int baseminor; /* 次设备号,起始号码 */
int minorct; /* 次设备号数目 */
char name[64];
struct cdev *cdev; /* 重点关注,此结构体内包含 file_operations 和 dev_t */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
数组的优缺点:查找快;增删元素效率低,容量固定
链表的优缺点:增删元素效率高,容量不限;查找慢(从头节点遍历)。
哈希表:数组和链表的结合。
以 主设备号
为编号,使用哈希函数f(major)=major%255
来计算 数组下标
。
主设备号冲突(如0、255),则以 次设备号
为比较值来排序 链表节点
(参见上图 和 94的设备号注册函数)。
哈希函数的设计目标:链表节点尽量平均分布在各个数组元素中,查询设备号的时间较为稳定。