drivers/char/tty_io.c | 73 +++++++--------------------------- fs/char_dev.c | 106 ++++++++++++++++++++++++++++++++++++-------------- include/linux/fs.h | 9 ++-- 3 files changed, 99 insertions(+), 89 deletions(-) diff -puN drivers/char/tty_io.c~T28-tty-C69 drivers/char/tty_io.c --- 25/drivers/char/tty_io.c~T28-tty-C69 2003-05-05 22:38:00.000000000 -0700 +++ 25-akpm/drivers/char/tty_io.c 2003-05-05 22:38:44.000000000 -0700 @@ -2130,53 +2130,6 @@ void tty_unregister_device(struct tty_dr 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. */ @@ -2184,17 +2137,22 @@ int tty_register_driver(struct tty_drive { 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; @@ -2223,7 +2181,8 @@ int tty_unregister_driver(struct tty_dri if (*driver->refcount) return -EBUSY; - put_range(driver); + unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), + driver->num); list_del(&driver->tty_drivers); @@ -2304,25 +2263,25 @@ 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"); - 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"); #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"); #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 -puN fs/char_dev.c~T28-tty-C69 fs/char_dev.c --- 25/fs/char_dev.c~T28-tty-C69 2003-05-05 22:38:00.000000000 -0700 +++ 25-akpm/fs/char_dev.c 2003-05-05 22:38:00.000000000 -0700 @@ -125,7 +125,8 @@ get_chrfops(unsigned int major, unsigned * * 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) { @@ -135,7 +136,7 @@ int register_chrdev_region(unsigned int cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL); if (cd == NULL) - return -ENOMEM; + return ERR_PTR(-ENOMEM); write_lock_irq(&chrdevs_lock); @@ -169,32 +170,23 @@ int register_chrdev_region(unsigned int 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) @@ -202,21 +194,79 @@ int unregister_chrdev_region(unsigned in (*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 -puN include/linux/fs.h~T28-tty-C69 include/linux/fs.h --- 25/include/linux/fs.h~T28-tty-C69 2003-05-05 22:38:00.000000000 -0700 +++ 25-akpm/include/linux/fs.h 2003-05-05 22:38:00.000000000 -0700 @@ -1056,13 +1056,14 @@ extern void bd_release(struct block_devi 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 */ _