int register_chrdev_region(dev_t from, unsigned count, const char *name){ struct char_device_struct *cd; dev_t to = from + count; dev_t n, next; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n)+1, 0); if (next > to) next = to; cd = __register_chrdev_region(MAJOR(n), MINOR(n), next - n, name); if (IS_ERR(cd)) goto fail; } return 0;fail: to = n; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n)+1, 0); kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); } return PTR_ERR(cd);}
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name){ struct char_device_struct *cd; cd = __register_chrdev_region(0, baseminor, count, name); if (IS_ERR(cd)) return PTR_ERR(cd); *dev = MKDEV(cd->major, cd->baseminor); return 0;}
int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops){ struct char_device_struct *cd; struct cdev *cdev; char *s; int err = -ENOMEM; cd = __register_chrdev_region(major, 0, 256, name); if (IS_ERR(cd)) return PTR_ERR(cd); cdev = cdev_alloc(); if (!cdev) goto out2; cdev->owner = fops->owner; cdev->ops = fops; kobject_set_name(&cdev->kobj, "%s", name); for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/')) *s = '!'; err = cdev_add(cdev, MKDEV(cd->major, 0), 256); if (err) goto out; cd->cdev = cdev; return major ? 0 : cd->major;out: kobject_put(&cdev->kobj);out2: kfree(__unregister_chrdev_region(cd->major, 0, 256)); return err;}
static struct char_device_struct * __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct){ struct char_device_struct *cd = NULL, **cp; int i = major_to_index(major); mutex_lock(&chrdevs_lock); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) if ((*cp)->major == major && (*cp)->baseminor == baseminor && (*cp)->minorct == minorct) break; if (*cp) { cd = *cp; *cp = cd->next; } mutex_unlock(&chrdevs_lock); return cd;}void unregister_chrdev_region(dev_t from, unsigned count){ dev_t to = from + count; dev_t n, next; for (n = from; n < to; n = next) { next = MKDEV(MAJOR(n)+1, 0); if (next > to) next = to; kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); }}void unregister_chrdev(unsigned int major, const char *name){ struct char_device_struct *cd; cd = __unregister_chrdev_region(major, 0, 256); if (cd && cd->cdev) cdev_del(cd->cdev); kfree(cd);}