diff options
| -rw-r--r-- | drivers/char/tty_io.c | 73 | ||||
| -rw-r--r-- | fs/char_dev.c | 106 | ||||
| -rw-r--r-- | include/linux/fs.h | 9 |
3 files changed, 99 insertions, 89 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 4deacb6d95ed..ec5bd80e34ff 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2242,53 +2242,6 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) EXPORT_SYMBOL(tty_register_device); EXPORT_SYMBOL(tty_unregister_device); -/* that should be handled by register_chrdev_region() */ -static int get_range(struct tty_driver *driver) -{ - dev_t from = MKDEV(driver->major, driver->minor_start); - dev_t to = from + driver->num; - dev_t n, next; - int error = 0; - - for (n = from; MAJOR(n) < MAJOR(to); n = next) { - next = MKDEV(MAJOR(n)+1, 0); - error = register_chrdev_region(MAJOR(n), MINOR(n), - next - n, driver->name, &tty_fops); - if (error) - goto fail; - } - if (n != to) - error = register_chrdev_region(MAJOR(n), MINOR(n), - to - n, driver->name, &tty_fops); - if (!error) - return 0; -fail: - to = n; - for (n = from; MAJOR(n) < MAJOR(to); n = next) { - next = MKDEV(MAJOR(n)+1, 0); - unregister_chrdev_region(MAJOR(n), MINOR(n), - next - n, driver->name); - } - return error; -} - -/* that should be handled by unregister_chrdev_region() */ -static void put_range(struct tty_driver *driver) -{ - dev_t from = MKDEV(driver->major, driver->minor_start); - dev_t to = from + driver->num; - dev_t n, next; - - for (n = from; MAJOR(n) < MAJOR(to); n = next) { - next = MKDEV(MAJOR(n)+1, 0); - unregister_chrdev_region(MAJOR(n), MINOR(n), - next - n, driver->name); - } - if (n != to) - unregister_chrdev_region(MAJOR(n), MINOR(n), - to - n, driver->name); -} - /* * Called by a tty driver to register itself. */ @@ -2296,17 +2249,22 @@ int tty_register_driver(struct tty_driver *driver) { int error; int i; + dev_t dev; if (driver->flags & TTY_DRIVER_INSTALLED) return 0; if (!driver->major) { - error = register_chrdev_region(0, driver->minor_start, - driver->num, driver->name, &tty_fops); - if (error > 0) - driver->major = error; + error = alloc_chrdev_region(&dev, driver->num, + (char*)driver->name, &tty_fops); + if (!error) { + driver->major = MAJOR(dev); + driver->minor_start = MINOR(dev); + } } else { - error = get_range(driver); + dev = MKDEV(driver->major, driver->minor_start); + error = register_chrdev_region(dev, driver->num, + (char*)driver->name, &tty_fops); } if (error < 0) return error; @@ -2335,7 +2293,8 @@ int tty_unregister_driver(struct tty_driver *driver) if (*driver->refcount) return -EBUSY; - put_range(driver); + unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), + driver->num); list_del(&driver->tty_drivers); @@ -2412,20 +2371,20 @@ postcore_initcall(tty_class_init); */ void __init tty_init(void) { - if (register_chrdev_region(TTYAUX_MAJOR, 0, 1, + if (register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty", &tty_fops) < 0) panic("Couldn't register /dev/tty driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL); - if (register_chrdev_region(TTYAUX_MAJOR, 1, 1, + if (register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console", &tty_fops) < 0) panic("Couldn't register /dev/console driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); tty_add_class_device ("console", MKDEV(TTYAUX_MAJOR, 1), NULL); #ifdef CONFIG_UNIX98_PTYS - if (register_chrdev_region(TTYAUX_MAJOR, 2, 1, + if (register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx", &tty_fops) < 0) panic("Couldn't register /dev/ptmx driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); @@ -2433,7 +2392,7 @@ void __init tty_init(void) #endif #ifdef CONFIG_VT - if (register_chrdev_region(TTY_MAJOR, 0, 1, + if (register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0", &tty_fops) < 0) panic("Couldn't register /dev/tty0 driver\n"); devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); diff --git a/fs/char_dev.c b/fs/char_dev.c index 2621ba46bf9d..f20b95221a02 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -123,7 +123,8 @@ get_chrfops(unsigned int major, unsigned int minor) * * Returns a -ve errno on failure. */ -int register_chrdev_region(unsigned int major, unsigned int baseminor, +static struct char_device_struct * +__register_chrdev_region(unsigned int major, unsigned int baseminor, int minorct, const char *name, struct file_operations *fops) { @@ -133,7 +134,7 @@ int register_chrdev_region(unsigned int major, unsigned int baseminor, cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL); if (cd == NULL) - return -ENOMEM; + return ERR_PTR(-ENOMEM); write_lock_irq(&chrdevs_lock); @@ -167,32 +168,23 @@ int register_chrdev_region(unsigned int major, unsigned int baseminor, if (*cp && (*cp)->major == major && (*cp)->baseminor < baseminor + minorct) { ret = -EBUSY; - } else { - cd->next = *cp; - *cp = cd; + goto out; } + cd->next = *cp; + *cp = cd; + write_unlock_irq(&chrdevs_lock); + return cd; out: write_unlock_irq(&chrdevs_lock); - if (ret < 0) - kfree(cd); - return ret; + kfree(cd); + return ERR_PTR(ret); } -int register_chrdev(unsigned int major, const char *name, - struct file_operations *fops) +static struct char_device_struct * +__unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) { - return register_chrdev_region(major, 0, 256, name, fops); -} - -/* todo: make void - error printk here */ -int unregister_chrdev_region(unsigned int major, unsigned int baseminor, - int minorct, const char *name) -{ - struct char_device_struct *cd, **cp; - int ret = 0; - int i; - - i = major_to_index(major); + struct char_device_struct *cd = NULL, **cp; + int i = major_to_index(major); write_lock_irq(&chrdevs_lock); for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) @@ -200,21 +192,79 @@ int unregister_chrdev_region(unsigned int major, unsigned int baseminor, (*cp)->baseminor == baseminor && (*cp)->minorct == minorct) break; - if (!*cp || strcmp((*cp)->name, name)) - ret = -EINVAL; - else { + if (*cp) { cd = *cp; *cp = cd->next; - kfree(cd); } write_unlock_irq(&chrdevs_lock); + return cd; +} - return ret; +int register_chrdev_region(dev_t from, unsigned count, char *name, + struct file_operations *fops) +{ + 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, fops); + 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 count, char *name, + struct file_operations *fops) +{ + struct char_device_struct *cd; + cd = __register_chrdev_region(0, 0, count, name, fops); + 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, + struct file_operations *fops) +{ + struct char_device_struct *cd; + + cd = __register_chrdev_region(major, 0, 256, name, fops); + if (IS_ERR(cd)) + return PTR_ERR(cd); + return cd->major; +} + +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)); + } } int unregister_chrdev(unsigned int major, const char *name) { - return unregister_chrdev_region(major, 0, 256, name); + kfree(__unregister_chrdev_region(major, 0, 256)); + return 0; } /* diff --git a/include/linux/fs.h b/include/linux/fs.h index 7365aef817b5..1b7fac010f1f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1056,13 +1056,14 @@ extern void bd_release(struct block_device *); extern void blk_run_queues(void); /* fs/char_dev.c */ -extern int register_chrdev_region(unsigned int, unsigned int, int, - const char *, struct file_operations *); +extern int alloc_chrdev_region(dev_t *, unsigned, char *, + struct file_operations *); +extern int register_chrdev_region(dev_t, unsigned, char *, + struct file_operations *); extern int register_chrdev(unsigned int, const char *, struct file_operations *); extern int unregister_chrdev(unsigned int, const char *); -extern int unregister_chrdev_region(unsigned int, unsigned int, int, - const char *); +extern void unregister_chrdev_region(dev_t, unsigned); extern int chrdev_open(struct inode *, struct file *); /* fs/block_dev.c */ |
