您的位置:首页 > 运维架构 > Linux

[linux device driver] Chapter 03:字符设备注册学习

2015-02-21 21:18 567 查看
从函数scullc_init中学习register_chrdev_region,进而进入到__register_chrdev_region,主要还是研究__register_chrdev_region这个函数。

__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, **cp;
int ret = 0;
int i;

cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL);
if (cd == NULL)
return ERR_PTR(-ENOMEM);

memset(cd, 0, sizeof(struct char_device_struct));

write_lock_irq(&chrdevs_lock);

/* temporary */ //如果major=0,那么就是动态分配,函数从chrdevs中找到未分配的数组元素分配。
if (major == 0) {
for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
if (chrdevs[i] == NULL)
break;
}

if (i == 0) {
ret = -EBUSY;
goto out;
}
major = i;
ret = major;
}

cd->major = major;
cd->baseminor = baseminor;
cd->minorct = minorct;
cd->name = name;

i = major_to_index(major);
//这个循环的作用是从major对应的散列表中找到一项*cp =  null,这样用于分配。
for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
if ((*cp)->major > major ||
((*cp)->major == major && (*cp)->baseminor >= baseminor))
break;
if (*cp && (*cp)->major == major &&
(*cp)->baseminor < baseminor + minorct) {
ret = -EBUSY;
goto out;
}
cd->next = *cp;//此时*cp = null
*cp = cd;   //把已经赋值好的cd挂到cp上,其实就是chrdevs[i]下对应的某个项
write_unlock_irq(&chrdevs_lock);
return cd;
out:
write_unlock_irq(&chrdevs_lock);
kfree(cd);
return ERR_PTR(ret);
}


从上面可以看出,__register_chrdev_region完成的工作主要有三个步骤:

1. 分配出一个char_device_struct 结构,使用对应的入参赋值。

2.从chrdevs上找到对应的major号的chrdevs[major],然后从这个散列表中一级一级往下查找对应的minor号,最近将已经分配好的char_device_struct挂载到chrdevs全局变量中。

值得注意的是__register_chrdev_region的这个部分:

for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
if ((*cp)->major > major ||
((*cp)->major == major && (*cp)->baseminor >= baseminor))
break;
if (*cp && (*cp)->major == major &&
(*cp)->baseminor < baseminor + minorct) {
ret = -EBUSY;
goto out;
}
cd->next = *cp;
*cp = cd;


这段代码的主要作用是从chrdevs[i]

chrdevs是一个255个char_device_struct的数组指针:

static struct char_device_struct {
struct char_device_struct *next;
unsigned int major;
unsigned int baseminor;
int minorct;
const char *name;
struct file_operations *fops;
struct cdev *cdev;		/* will die */
} *chrdevs[MAX_PROBE_HASH];


它是一个散列表,取得i项chardevs后,函数不停的判断(*cp)->major是否大于或者是等于且baseminor也大于等于baseminor,这样最后在正常情况下会因为*cp=null而退出,从而cd->next = null,而*cp=cd,将cd挂载到*cd上,其实也就是chrdevs下的某一项。相对来说介绍详细的文章是这个:http://blog.csdn.net/yel617/article/details/5627505
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐