1.内核中所有已分配的字符设备编号都记录在一个名为 chrdevs 散列表里。该散列表中的每一个元素是一个 char_device_struct 结构,它的定义如下:
static struct char_device_struct {
struct char_device_struct *next; // 指向散列冲突链表中的下一个元素的指针
unsigned int major; // 主设备号
unsigned int baseminor; // 起始次设备号
int minorct; // 设备编号的范围大小
char name[64]; // 处理该设备编号范围内的设备驱动的名称
struct file_operations *fops;
struct cdev *cdev; // 指向字符设备驱动程序描述符的指针
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
1>内核并不是为每一个字符设备编号定义一个 char_device_struct 结构,而是为一组对应同一个字符设备驱动的设备编号范围定义一个 char_device_struct 结构。chrdevs 散列表的大小是 255,散列算法是把每组字符设备编号范围的主设备号以 255 取模插入相应的散列桶中。同一个散列桶中的字符设备编号范围是按起始次设备号递增排序的。
2.注册
内核提供了三个函数来注册一组字符设备编号,这三个函数分别是 register_chrdev_region()、alloc_chrdev_region() 和
register_chrdev()。这三个函数都会调用一个共用的
__register_chrdev_region() 函数来注册一组设备编号范围(即一个 char_device_struct 结构)。
1>int register_chrdev_region(dev_t from, unsigned count, const char *name)
from :要分配的设备编号范围的初始值(次设备号常设为0);
Count:连续编号范围.
name:编号相关联的设备名称. (/proc/devices);
2>动态分配:
int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name);
firstminor是请求的最小的次编号;
count是请求的连续设备编号的总数;
name为设备名,返回值小于0表示分配失败。
然后通过major=MMOR(dev)获取主设备号
3>释放:
Void unregist_chrdev_region(dev_t first,unsigned int count);
调用Documentation/devices.txt中能够找到已分配的设备号.
3.__register_chrdev_region() 函数的实现代码
/*
84 * Register a single major with a specified minor range.
85 *
86 * If major == 0 this functions will dynamically allocate a major and return
87 * its number.
88 *
89 * If major > 0 this function will attempt to reserve the passed range of
90 * minors and will return zero on success.
91 *
92 * Returns a -ve errno on failure.
93 */
94static struct char_device_struct *
95__register_chrdev_region(unsigned int major, unsigned int baseminor,
96 int minorct, const char *name)
97{
98 struct char_device_struct *cd, **cp;
99 int ret = 0;
100 int i;
101
102 cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
103 if (cd == NULL)
104 return ERR_PTR(-ENOMEM);
105
106 mutex_lock(&chrdevs_lock);
107
108 /* temporary */
109 if (major == 0) {
110 for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
111 if (chrdevs[i] == NULL)
112 break;
113 }
114
115 if (i == 0) {
116 ret = -EBUSY;
117 goto out;
118 }
119 major = i;
120 ret = major;
121 }
122
123 cd->major = major;
124 cd->baseminor = baseminor;
125 cd->minorct = minorct;
126 strlcpy(cd->name, name, sizeof(cd->name));
127
128 i = major_to_index(major);
129
130 for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
131 if ((*cp)->major > major ||
132 ((*cp)->major == major &&
133 (((*cp)->baseminor >= baseminor) ||
134 ((*cp)->baseminor + (*cp)->minorct > baseminor))))
135 break;
136
137 /* Check for overlapping minor ranges. */
138 if (*cp && (*cp)->major == major) {
139 int old_min = (*cp)->baseminor;
140 int old_max = (*cp)->baseminor + (*cp)->m