 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 */

_
