1.char_device_struct
在linux/fs/char_dev.c中
static struct char_device_struct {
//指向下一个链表结点
struct char_device_struct *next;
//主设备号
unsigned int major;
//次设备号
unsigned int baseminor;
//数量
int minorct;
//名字
char name[64];
//内核字符对象--已经被丢弃
struct cdev *cdev; /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
2._register_chrdev_region函数分析
在linux/fs/char_dev.c中
__register_chrdev_region()
static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,
int minorct, const char *name)
{
struct char_device_struct *cd, *curr, *prev = NULL;
int ret;
int i;
//设备号大于512号,出错
if (major >= CHRDEV_MAJOR_MAX) {
pr_err("CHRDEV \"%s\" major requested (%u) is greater than the maximum (%u)\n",
name, major, CHRDEV_MAJOR_MAX-1);
return ERR_PTR(-EINVAL);
}
if (minorct > MINORMASK + 1 - baseminor) {
pr_err("CHRDEV \"%s\" minor range requested (%u-%u) is out of range of maximum range (%u-%u) for a single major\n",
name, baseminor, baseminor + minorct - 1, 0, MINORMASK);
return ERR_PTR(-EINVAL);
}
//1.动态申请内存
cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
if (cd == NULL)
return ERR_PTR(-ENOMEM);
mutex_lock(&chrdevs_lock);
//主设备号为0,动态分配主设备号
if (major == 0) {
ret = find_dynamic_major();
if (ret < 0) {
pr_err("CHRDEV \"%s\" dynamic allocation region is full\n",
name);
goto out;
}
major = ret;
}
ret = -EBUSY;
//主设备号转换为数组下标
i = major_to_index(major);
//遍历某个数组下标所指向的链表
for (curr = chrdevs[i]; curr; prev = curr, curr = curr->next) {
//比较主设备号,小于要注册的主设备号
if (curr->major < major)
continue;
//大于,跳出循环
if (curr->major > major)
break;
//主设备号相等的话,比较次设备号,次设备号小于的话重新循环
if (curr->baseminor + curr->minorct <= baseminor)
continue;
//大于的话直接跳出循环
if (curr->baseminor >= baseminor + minorct)
break;
goto out;
}
cd->major = major;
cd->baseminor = baseminor;
cd->minorct = minorct;
strlcpy(cd->name, name, sizeof(cd->name));
if (!prev) {
cd->next = curr;
chrdevs[i] = cd;
} else {
cd->next = prev->next;
prev->next = cd;
}
mutex_unlock(&chrdevs_lock);
return cd;
out:
mutex_unlock(&chrdevs_lock);
kfree(cd);
return ERR_PTR(ret);
}
find_dynamic_major()
static int find_dynamic_major(void)
{
int i;
struct char_device_struct *cd;
//优先从254-314分配主设备号
for (i = ARRAY_SIZE(chrdevs)-1; i >= CHRDEV_MAJOR_DYN_END/*234*/; i--) {
if (chrdevs[i] == NULL)
return i;
}
//从384-511中选择主设备号
for (i = CHRDEV_MAJOR_DYN_EXT_START/*511*/;
i >= CHRDEV_MAJOR_DYN_EXT_END/*314*/; i--) {
for (cd = chrdevs[major_to_index(i)]; cd; cd = cd->next)
//1.如果主设备号被占用,退出第二层循环
if (cd->major == i)
break;
//如果384-511中有主设备号没有被占有,则返回当前下标
if (cd == NULL)
return i;
}
return -EBUSY/*-16*/;
}
3.结论
- 主设备号为0,内核动态分配主设备号
- 优先使用:234~255
- 其次使用:384~511
- 主设备号最大为512