/*
* Register a single major with a specified minor range.
*
* If major == 0 this functions will dynamically allocate a major and return
* its number.
*
* If major > 0 this function will attempt to reserve the passed range of
* minors and will return zero on success.
*
* Returns a -ve errno on failure.
*/
static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,
int minorct, const char *name)
/*参数1:主设备号,参数2:次设备号,参数3:要申请号的设备个数,参数4:驱动名称*/
{
struct char_device_struct *cd, **cp; /*一个结构体类型的指针,和一个结构体类型的二级指针*/
int ret = 0;
int i;
cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); //动态申请一个struct char_device_struct大小的内存空间
if (cd == NULL) //如果没有申请成功
return ERR_PTR(-ENOMEM); //返回错误值
mutex_lock(&chrdevs_lock); //锁机制
/*此if语句的目的在于寻找设备号列表中的空的位置*/
/* temporary */
if (major == 0) { //如果主设备号为0
for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) { 从设备号列表的最后一个往前循环
if (chrdevs[i] == NULL) //如果设备列表中i为空
break; //跳出循环
}
if (i == 0) { //如果是列表没有空的
ret = -EBUSY; //显然有问题
goto out; //跳转到out
}
major = i; //把设备列表空位置作为主设备号
ret = major; //存储主设备号
}
cd->major = major; //新元素的主设备号赋值
cd->baseminor = baseminor; //新元素的次设备号赋值
cd->minorct = minorct; //新元素的可容纳次设备的数量赋值
strlcpy(cd->name, name, sizeof(cd->name)); //复制名字到新元素
i = major_to_index(major); //主设备号应与列表号一致
/*寻找新元素插入的位置*/
for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) //第二个表示如果当前元素存在的话
if ((*cp)->major > major || //如果当前元素的主设备号大于要添加的主设备号
((*cp)->major == major && //当前元素的主设备号等于要添加的主设备号
(((*cp)->baseminor >= baseminor) || //并且次设备号大于等于要添加的次设备号
((*cp)->baseminor + (*cp)->minorct > baseminor)))) //如果次设备号+申请设备号的数量 > 次设备号
break; //跳出循环
/* Check for overlapping minor ranges. */
if (*cp && (*cp)->major == major) { //如果当前元素存在并且主设备号和要添加的主设备号一致
int old_min = (*cp)->baseminor; //更新旧的最小值,值为当前元素的次设备号
int old_max = (*cp)->baseminor + (*cp)->minorct - 1;//更新旧的最大值,值为当前次设备号+要申请号的设备个数-1,-1是因为从0开始的次设备号
int new_min = baseminor;//新的最小值为要添加的次设备号
int new_max = baseminor + minorct - 1;//新的最大值为要添加的次设备号+要申请号的设备个数-1,-1是因为次设备号从0开始
/* New driver overlaps from the left. */
//新的区间可以在旧的区间的左侧或者右侧
if (new_max >= old_min && new_max <= old_max) { //显然生成的新的最大值必须要大于旧的最大值或者小旧的最小值
ret = -EBUSY;
goto out;
}
/* New driver overlaps from the right. */
if (new_min <= old_max && new_min >= old_min) { //显然生成的新的最小值必须要大于旧的最大值或者小旧的最小值
ret = -EBUSY;
goto out;
}
}
/*往链表内添加新元素*/
cd->next = *cp; //新元素的指向当前元素
*cp = cd; //当前元素更新为新元素
mutex_unlock(&chrdevs_lock); //锁机制
return cd; //返回当前元素的结构体指针
out:
mutex_unlock(&chrdevs_lock);
kfree(cd);
return ERR_PTR(ret);
}
程序说明:
1.函数传入的参数1:主设备号 2:次设备号 3:申请设备号的设备个数 4:设备名称
2.此函数一开始先动态申请一个内存,用来存储struct char_device_struct这种类型,然后通过各种筛选,寻找链表中要插入的位置,然后判断次设备号是否合法,然后将新元素插入链表
3.函数返回值为新元素的指针,也就是新元素的地址