int register_chrdev()

来源:互联网 发布:传智大数据3期百度云 编辑:程序博客网 时间:2024/05/17 21:07
在i2c的static int at24cxx_detect(struct i2c_adapter *adapter, int address, int kind)中有一句,
major = register_chrdev(0, "at24cxx", &at24cxx_fops);

进去内核中:

1 int register_chrdev(unsigned int major, const char *name,2    const struct file_operations *fops)3 {4struct char_device_struct *cd;5struct cdev *cdev;6char *s;7int err = -ENOMEM;89cd = __register_chrdev_region(major, 0, 256, name);0if (IS_ERR(cd))11return PTR_ERR(cd);1213cdev = cdev_alloc();14if (!cdev)15goto out2;1617cdev->owner = fops->owner;18cdev->ops = fops;19kobject_set_name(&cdev->kobj, "%s", name);20for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/'))21*s = '!';2223err = cdev_add(cdev, MKDEV(cd->major, 0), 256);24if (err)25goto out;2627cd->cdev = cdev;2829return major ? 0 : cd->major;30out:31kobject_put(&cdev->kobj);32out2:33kfree(__unregister_chrdev_region(cd->major, 0, 256));34return err;35}
第9行调用了函数__register_chrdev_region(在这个函数中如果没有major会动态的分配一个):

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 = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);if (cd == NULL)return ERR_PTR(-ENOMEM);mutex_lock(&chrdevs_lock);/* temporary */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;strncpy(cd->name,name, 64);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;int new_min = baseminor;int new_max = baseminor + minorct - 1;/* 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);}
第13行cdev_alloc完成内存分配和初始化

struct cdev *cdev_alloc(void){struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);if (p) {p->kobj.ktype = &ktype_cdev_dynamic;INIT_LIST_HEAD(&p->list);kobject_init(&p->kobj);}return p;}
第17到19行设置cdev结构体的一些属性
第23行添加一个字符设备cdev_add

int cdev_add(struct cdev *p, dev_t dev, unsigned count){p->dev = dev;p->count = count;return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);}
进去cdev_add中的kobj_map(注意:
n = MAJOR(dev + range - 1) - MAJOR(dev) + 1 表示设备号范围(dev, dev+range)中不同的主设备号的个数。
通常n的值为1
),kobj_map作用就是封装好一个probe结构并将它的地址放入probes数组进而封装进cdev_map

int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range,     struct module *module, kobj_probe_t *probe,     int (*lock)(dev_t, void *), void *data){unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1;unsigned index = MAJOR(dev);unsigned i;struct probe *p;if (n > 255)n = 255;p = kmalloc(sizeof(struct probe) * n, GFP_KERNEL);if (p == NULL)return -ENOMEM;for (i = 0; i < n; i++, p++) {p->owner = module;p->get = probe;p->lock = lock;p->dev = dev;p->range = range;p->data = data;}mutex_lock(domain->lock);for (i = 0, p -= n; i < n; i++, p++, index++) {struct probe **s = &domain->probes[index % 255];while (*s && (*s)->range < range)s = &(*s)->next;p->next = *s;*s = p;}mutex_unlock(domain->lock);return 0;}
第29行,当major为0返回动态分配出的cdev中的主设备号。





0 0
原创粉丝点击