diff -ur linux-2.5.67/drivers/block/genhd.c linux-2.5.67-cdev5/drivers/block/genhd.c
--- linux-2.5.67/drivers/block/genhd.c	2003-04-04 19:29:33.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/block/genhd.c	2003-04-14 20:41:31.000000000 +0200
@@ -244,6 +244,12 @@
 	return 0;
 }
 
+#define DISK_NR		16384
+
+static unsigned long disk_index_bits[DISK_NR / BITS_PER_LONG];
+static spinlock_t disk_index_lock = SPIN_LOCK_UNLOCKED;
+int force_dyndisks = 1;
+
 /**
  * add_gendisk - add partitioning information to kernel list
  * @disk: per-device partitioning information
@@ -251,13 +257,40 @@
  * This function registers the partitioning information in @disk
  * with the kernel.
  */
-void add_disk(struct gendisk *disk)
+int add_disk(struct gendisk *disk)
 {
+	if (!disk->major || (force_dyndisks && disk->flags & GENHD_FL_DYNAMIC)) {
+		char name[8], *p = name + 7;
+		int index;
+
+		spin_lock(&disk_index_lock);
+		index = find_first_zero_bit(disk_index_bits, DISK_NR);
+		if (index == DISK_NR) {
+			spin_unlock(&disk_index_lock);
+			return -EBUSY;
+		}
+		__set_bit(index, disk_index_bits);
+		spin_unlock(&disk_index_lock);
+
+		disk->major = 256 + index;
+		disk->first_minor = 0;
+
+		*p-- = 0;
+		while (index > 25) {
+			*p-- = 'a' + index % 26;
+			index = index / 26 - 1;
+		}
+		*p = 'a' + index;
+		sprintf(disk->disk_name, "disk%s", p);
+	}
+
 	disk->flags |= GENHD_FL_UP;
 	blk_register_region(MKDEV(disk->major, disk->first_minor),
 			    disk->minors, NULL, exact_match, exact_lock, disk);
 	register_disk(disk);
 	elv_register_queue(disk);
+
+	return 0;
 }
 
 EXPORT_SYMBOL(add_disk);
@@ -265,6 +298,11 @@
 
 void unlink_gendisk(struct gendisk *disk)
 {
+	if (disk->major >= 256 && disk->major < 256 + DISK_NR) {
+		spin_lock(&disk_index_lock);
+		clear_bit(disk->major - 256, disk_index_bits);
+		spin_unlock(&disk_index_lock);
+	}
 	elv_unregister_queue(disk);
 	blk_unregister_region(MKDEV(disk->major, disk->first_minor),
 			      disk->minors);
diff -ur linux-2.5.67/drivers/char/misc.c linux-2.5.67-cdev5/drivers/char/misc.c
--- linux-2.5.67/drivers/char/misc.c	2003-04-11 20:39:41.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/char/misc.c	2003-04-14 20:41:31.000000000 +0200
@@ -60,11 +60,8 @@
  * Assigned numbers, used for dynamic minors
  */
 #define DYNAMIC_MINORS 64 /* like dynamic majors */
-static unsigned char misc_minors[DYNAMIC_MINORS / 8];
 
-#ifdef CONFIG_SGI_NEWPORT_GFX
 extern void gfx_register(void);
-#endif
 extern void streamable_init(void);
 extern int rtc_DP8570A_init(void);
 extern int rtc_MK48T08_init(void);
@@ -100,45 +97,23 @@
 
 static int misc_open(struct inode * inode, struct file * file)
 {
-	int minor = minor(inode->i_rdev);
-	struct miscdevice *c;
 	int err = -ENODEV;
-	struct file_operations *old_fops, *new_fops = NULL;
-	
-	down(&misc_sem);
-	
-	c = misc_list.next;
-
-	while ((c != &misc_list) && (c->minor != minor))
-		c = c->next;
-	if (c != &misc_list)
-		new_fops = fops_get(c->fops);
-	if (!new_fops) {
-		char modname[20];
-		up(&misc_sem);
-		sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor);
-		request_module(modname);
-		down(&misc_sem);
-		c = misc_list.next;
-		while ((c != &misc_list) && (c->minor != minor))
-			c = c->next;
-		if (c == &misc_list || (new_fops = fops_get(c->fops)) == NULL)
-			goto fail;
-	}
-
-	err = 0;
-	old_fops = file->f_op;
-	file->f_op = new_fops;
-	if (file->f_op->open) {
-		err=file->f_op->open(inode,file);
-		if (err) {
-			fops_put(file->f_op);
-			file->f_op = fops_get(old_fops);
-		}
+#ifdef CONFIG_KMOD
+	char modname[32];
+	struct char_device *cdev = inode->i_cdev;
+	struct file_operations *fops;
+
+	sprintf(modname, "char-major-%d-%d", MISC_MAJOR, MINOR(cdev->cd_dev));
+	request_module(modname);
+	fops = fops_get(cdev->cd_fops);
+	if (fops) {
+		err = 0;
+		fops_put(file->f_op);
+		file->f_op = fops;
+		if (fops->open)
+			err = fops->open(inode, file);
 	}
-	fops_put(old_fops);
-fail:
-	up(&misc_sem);
+#endif
 	return err;
 }
 
@@ -167,34 +142,35 @@
 int misc_register(struct miscdevice * misc)
 {
 	static devfs_handle_t devfs_handle, dir;
-	struct miscdevice *c;
-	
-	if (misc->next || misc->prev)
-		return -EBUSY;
-	down(&misc_sem);
-	c = misc_list.next;
-
-	while ((c != &misc_list) && (c->minor != misc->minor))
-		c = c->next;
-	if (c != &misc_list) {
-		up(&misc_sem);
-		return -EBUSY;
-	}
+	struct char_device *cdev;
 
 	if (misc->minor == MISC_DYNAMIC_MINOR) {
-		int i = DYNAMIC_MINORS;
-		while (--i >= 0)
-			if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
-				break;
-		if (i<0)
-		{
-			up(&misc_sem);
-			return -EBUSY;
+		int i;
+
+		for (i = DYNAMIC_MINORS; i > 0; i--) {
+			cdev = cdget(MKDEV(MISC_MAJOR, i));
+			down(&cdev->cd_sem);
+			if (!cdev->cd_fops)
+				goto found;
+			up(&cdev->cd_sem);
+			cdput(cdev);
 		}
-		misc->minor = i;
-	}
-	if (misc->minor < DYNAMIC_MINORS)
-		misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
+	} else {
+		cdev = cdget(MKDEV(MISC_MAJOR, misc->minor));
+		down(&cdev->cd_sem);
+		if (!cdev->cd_fops)
+			goto found;
+		up(&cdev->cd_sem);
+	}
+	return -EBUSY;
+
+found:
+	cdev->cd_fops = misc->fops;
+	cdev->cd_name = misc->name;
+	up(&cdev->cd_sem);
+
+	down(&misc_sem);
+
 	if (!devfs_handle)
 		devfs_handle = devfs_mk_dir("misc");
 	dir = strchr (misc->name, '/') ? NULL : devfs_handle;
@@ -204,14 +180,10 @@
 				S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
 				misc->fops, NULL);
 
-	/*
-	 * Add it to the front, so that later devices can "override"
-	 * earlier defaults
-	 */
 	misc->prev = &misc_list;
 	misc->next = misc_list.next;
-	misc->prev->next = misc;
-	misc->next->prev = misc;
+	misc_list.next->prev = misc;
+	misc_list.next = misc;
 	up(&misc_sem);
 	return 0;
 }
@@ -228,18 +200,22 @@
 
 int misc_deregister(struct miscdevice * misc)
 {
-	int i = misc->minor;
-	if (!misc->next || !misc->prev)
+	struct char_device *cdev;
+
+	cdev = cdget(MKDEV(MISC_MAJOR, misc->minor));
+	down(&cdev->cd_sem);
+	if (cdev->cd_fops != misc->fops) {
+		up(&cdev->cd_sem);
 		return -EINVAL;
+	}
+	cdev->cd_fops = NULL;
+	cdev->cd_name = NULL;
+	up(&cdev->cd_sem);
+
 	down(&misc_sem);
 	misc->prev->next = misc->next;
 	misc->next->prev = misc->prev;
-	misc->next = NULL;
-	misc->prev = NULL;
-	devfs_unregister (misc->devfs_handle);
-	if (i < DYNAMIC_MINORS && i>0) {
-		misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
-	}
+	devfs_unregister(misc->devfs_handle);
 	up(&misc_sem);
 	return 0;
 }
diff -ur linux-2.5.67/drivers/char/tty_io.c linux-2.5.67-cdev5/drivers/char/tty_io.c
--- linux-2.5.67/drivers/char/tty_io.c	2003-04-11 20:09:41.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/char/tty_io.c	2003-04-14 20:41:31.000000000 +0200
@@ -122,7 +122,7 @@
 	.c_cc = INIT_C_CC
 };
 
-LIST_HEAD(tty_drivers);			/* linked list of tty drivers */
+LIST_HEAD(tty_majors);			/* linked list of tty majors */
 struct tty_ldisc ldiscs[NR_LDISCS];	/* line disc dispatch table	*/
 
 #ifdef CONFIG_UNIX98_PTYS
@@ -327,23 +327,32 @@
 /*
  * This routine returns a tty driver structure, given a device number
  */
-struct tty_driver *get_tty_driver(kdev_t device)
+static struct tty_driver *get_tty_driver(kdev_t device)
 {
-	int	major, minor;
+	struct char_device *cdev;
+	struct tty_major *major;
 	struct tty_driver *p;
-	
-	minor = minor(device);
-	major = major(device);
+	int minor;
+#ifdef CONFIG_KMOD
+	char name[20] = "";
+again:
+#endif
 
-	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		if (p->major != major)
-			continue;
-		if (minor < p->minor_start)
-			continue;
-		if (minor >= p->minor_start + p->num)
-			continue;
-		return p;
+	minor = minor(device);
+	cdev = cdget_major(major(device));
+	major = cdev->cd_data;
+	cdput(cdev);
+	list_for_each_entry(p, &major->drivers, tty_drivers) {
+		if (minor >= p->minor_start && minor < p->minor_start + p->num)
+			return p;
+	}
+#ifdef CONFIG_KMOD
+	if (!name[0]) {
+		sprintf(name, "char-major-%d", major(device));
+		request_module(name);
+		goto again;
 	}
+#endif
 	return NULL;
 }
 
@@ -2102,29 +2111,46 @@
  */
 int tty_register_driver(struct tty_driver *driver)
 {
+	struct char_device *cdev;
+	struct tty_major *major;
 	int error;
-        int i;
+	int i;
 
 	if (driver->flags & TTY_DRIVER_INSTALLED)
 		return 0;
 
-	error = register_chrdev_region(driver->major, driver->minor_start,
-				       driver->num, driver->name, &tty_fops);
-	if (error < 0)
-		return error;
-	else if(driver->major == 0)
+	down_tty_sem(0);
+	error = register_chrdev(driver->major, driver->name, &tty_fops);
+	if (!driver->major)
 		driver->major = error;
+	cdev = cdget_major(driver->major);
+	if (error == -EBUSY && cdev->cd_fops == &tty_fops) {
+		error = 0;
+		major = cdev->cd_data;
+	} else if (error >= 0) {
+		cdev->cd_data = major = kmalloc(sizeof(*major), GFP_KERNEL);
+		if (!major) {
+			unregister_chrdev(driver->major, driver->name);
+			goto out;
+		}
+		INIT_LIST_HEAD(&major->drivers);
+		list_add(&major->list, &tty_majors);
+	} else
+		goto out;
 
 	if (!driver->put_char)
 		driver->put_char = tty_default_put_char;
 	
-	list_add(&driver->tty_drivers, &tty_drivers);
+	list_add_tail(&driver->tty_drivers, &major->drivers);
 	
 	if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
 		for(i = 0; i < driver->num; i++)
 		    tty_register_device(driver, driver->minor_start + i);
 	}
 	proc_tty_register_driver(driver);
+out:
+	cdput(cdev);
+	up_tty_sem(0);
 	return error;
 }
 
@@ -2133,18 +2159,28 @@
  */
 int tty_unregister_driver(struct tty_driver *driver)
 {
-	int retval, i;
+	struct char_device *cdev;
+	struct tty_major *major;
 	struct termios *tp;
-
+	int i;
+	
 	if (*driver->refcount)
 		return -EBUSY;
 
-	retval = unregister_chrdev_region(driver->major, driver->minor_start,
-					  driver->num, driver->name);
-	if (retval)
-		return retval;
-
+	down_tty_sem(0);
+	cdev = cdget_major(driver->major);
+	major = cdev->cd_data;
 	list_del(&driver->tty_drivers);
+	if (list_empty(&major->drivers)) {
+		unregister_chrdev(driver->major, driver->name);
+		list_del(&major->list);
+		kfree(major);
+	} else if (cdev->cd_name == driver->name) {
+		struct tty_driver *p;
+		p = list_entry(major->drivers.next, struct tty_driver, tty_drivers);
+		cdev->cd_name = p->name;
+	}
+	up_tty_sem(0);
 
 	/*
 	 * Free the termios and termios_locked structures because
diff -ur linux-2.5.67/drivers/scsi/sd.c linux-2.5.67-cdev5/drivers/scsi/sd.c
--- linux-2.5.67/drivers/scsi/sd.c	2003-03-19 02:16:32.000000000 +0100
+++ linux-2.5.67-cdev5/drivers/scsi/sd.c	2003-04-14 20:41:31.000000000 +0200
@@ -1314,12 +1314,8 @@
 
 	spin_lock(&sd_index_lock);
 	index = find_first_zero_bit(sd_index_bits, SD_DISKS);
-	if (index == SD_DISKS) {
-		spin_unlock(&sd_index_lock);
-		error = -EBUSY;
-		goto out_put;
-	}
-	__set_bit(index, sd_index_bits);
+	if (index != SD_DISKS)
+		__set_bit(index, sd_index_bits);
 	spin_unlock(&sd_index_lock);
 
 	sdkp->device = sdp;
@@ -1328,22 +1324,24 @@
 	sdkp->index = index;
 
 	gd->de = sdp->de;
-	gd->major = sd_major(index >> 4);
-	gd->first_minor = (index & 15) << 4;
 	gd->minors = 16;
 	gd->fops = &sd_fops;
-
-	if (index >= 26) {
-		sprintf(gd->disk_name, "sd%c%c",
-			'a' + index/26-1,'a' + index % 26);
-	} else {
-		sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
+	if (index != SD_DISKS) {
+		gd->major = sd_major(index >> 4);
+		gd->first_minor = (index & 15) << 4;
+
+		if (index >= 26) {
+			sprintf(gd->disk_name, "sd%c%c",
+				'a' + index/26-1,'a' + index % 26);
+		} else {
+			sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
+		}
 	}
 
 	sd_init_onedisk(sdkp, gd);
 
 	gd->driverfs_dev = &sdp->sdev_driverfs_dev;
-	gd->flags = GENHD_FL_DRIVERFS | GENHD_FL_DEVFS;
+	gd->flags = GENHD_FL_DRIVERFS | GENHD_FL_DEVFS | GENHD_FL_DYNAMIC;
 	if (sdp->removable)
 		gd->flags |= GENHD_FL_REMOVABLE;
 	gd->private_data = &sdkp->driver;
@@ -1351,7 +1349,9 @@
 
 	sd_devlist_insert(sdkp);
 	set_capacity(gd, sdkp->capacity);
-	add_disk(gd);
+	error = add_disk(gd);
+	if (error)
+		goto out_put;
 
 	printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
 	       "id %d, lun %d\n", sdp->removable ? "removable " : "",
diff -ur linux-2.5.67/drivers/scsi/sg.c linux-2.5.67-cdev5/drivers/scsi/sg.c
--- linux-2.5.67/drivers/scsi/sg.c	2003-03-19 02:16:32.000000000 +0100
+++ linux-2.5.67-cdev5/drivers/scsi/sg.c	2003-04-14 20:41:31.000000000 +0200
@@ -107,13 +107,14 @@
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
 
-#define SG_DEV_ARR_LUMP 6	/* amount to over allocate sg_dev_arr by */
-
 static int sg_attach(Scsi_Device *);
 static void sg_detach(Scsi_Device *);
 
 static Scsi_Request *dummy_cmdp;	/* only used for sizeof */
 
+#define SG_MINORS	256
+static unsigned long sg_index_bits[SG_MINORS / BITS_PER_LONG];
+static LIST_HEAD(sg_devlist);
 static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED;	/* Also used to lock
 							   file descriptor list for device */
 
@@ -177,6 +178,7 @@
 } Sg_fd;
 
 typedef struct sg_device { /* holds the state of each scsi generic device */
+	struct list_head list;
 	struct Scsi_Device_Template *driver;
 	Scsi_Device *device;
 	wait_queue_head_t o_excl_wait;	/* queue open() when O_EXCL in use */
@@ -187,7 +189,7 @@
 	volatile char exclude;	/* opened for exclusive access */
 	char sgdebug;		/* 0->off, 1->sense, 9->dump dev, 10-> all devs */
 	struct device sg_driverfs_dev;
-	struct gendisk *disk;
+	struct char_device *cdev;
 } Sg_device;
 
 static int sg_fasync(int fd, struct file *filp, int mode);
@@ -214,7 +216,7 @@
 static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
 static char *sg_page_malloc(int rqSz, int lowDma, int *retSzp);
 static void sg_page_free(char *buff, int size);
-static Sg_fd *sg_add_sfp(Sg_device * sdp, int dev);
+static Sg_fd *sg_add_sfp(struct char_device *cdev);
 static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
 static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
 static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
@@ -226,14 +228,8 @@
 static int sg_allow_access(unsigned char opcode, char dev_type);
 static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
 // static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
-static Sg_device *sg_get_dev(int dev);
 static inline unsigned char *sg_scatg2virt(const struct scatterlist *sclp);
-#ifdef CONFIG_PROC_FS
-static int sg_last_dev(void);
-#endif
 
-static Sg_device **sg_dev_arr = NULL;
-static int sg_dev_max;
 static int sg_nr_dev;
 
 #define SZ_SG_HEADER sizeof(struct sg_header)
@@ -244,25 +240,23 @@
 static int
 sg_open(struct inode *inode, struct file *filp)
 {
-	int dev = minor(inode->i_rdev);
 	int flags = filp->f_flags;
 	Sg_device *sdp;
 	Sg_fd *sfp;
 	int res;
 	int retval = -EBUSY;
 
-	SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
-	sdp = sg_get_dev(dev);
-	if ((!sdp) || (!sdp->device))
-		return -ENXIO;
-	if (sdp->detached)
-		return -ENODEV;
+	SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%lx, flags=0x%x\n", inode->i_cdev->cd_dev, flags));
+	sfp = sg_add_sfp(inode->i_cdev);
+	if (IS_ERR(sfp))
+		return PTR_ERR(sfp);
+	sdp = inode->i_cdev->cd_data;
 
 	/* This driver's module count bumped by fops_get in <linux/fs.h> */
 	/* Prevent the device driver from vanishing while we sleep */
 	retval = scsi_device_get(sdp->device);
 	if (retval)
-		return retval;
+		goto error_free;
 
 	if (!((flags & O_NONBLOCK) ||
 	      scsi_block_when_processing_errors(sdp->device))) {
@@ -296,26 +290,13 @@
 			goto error_out;
 		}
 	}
-	if (sdp->detached) {
-		retval = -ENODEV;
-		goto error_out;
-	}
-	if (!sdp->headfp) {	/* no existing opens on this device */
-		sdp->sgdebug = 0;
-		sdp->sg_tablesize = sdp->device->host->sg_tablesize;
-	}
-	if ((sfp = sg_add_sfp(sdp, dev)))
-		filp->private_data = sfp;
-	else {
-		if (flags & O_EXCL)
-			sdp->exclude = 0;	/* undo if error */
-		retval = -ENOMEM;
-		goto error_out;
-	}
+	filp->private_data = sfp;
 	return 0;
 
       error_out:
 	scsi_device_put(sdp->device);
+      error_free:
+	sg_remove_sfp(sdp, sfp);
 	return retval;
 }
 
@@ -328,7 +309,7 @@
 
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
-	SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
+	SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->cdev->cd_name));
 	sg_fasync(-1, filp, 0);	/* remove filp from async notification list */
 	if (0 == sg_remove_sfp(sdp, sfp)) {	/* Returns 1 when sdp gone */
 		if (!sdp->detached) {
@@ -355,7 +336,7 @@
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
 	SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n",
-				   sdp->disk->disk_name, (int) count));
+				   sdp->cdev->cd_name, (int) count));
 	if (ppos != &filp->f_pos) ;	/* FIXME: Hmm.  Seek to the right place, or fail?  */
 	if ((k = verify_area(VERIFY_WRITE, buf, count)))
 		return k;
@@ -508,7 +489,7 @@
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
 	SCSI_LOG_TIMEOUT(3, printk("sg_write: %s, count=%d\n",
-				   sdp->disk->disk_name, (int) count));
+				   sdp->cdev->cd_name, (int) count));
 	if (sdp->detached)
 		return -ENODEV;
 	if (!((filp->f_flags & O_NONBLOCK) ||
@@ -695,7 +676,6 @@
 
 	srp->my_cmdp = SRpnt;
 	q = SRpnt->sr_device->request_queue;
-	SRpnt->sr_request->rq_disk = sdp->disk;
 	SRpnt->sr_sense_buffer[0] = 0;
 	SRpnt->sr_cmd_len = hp->cmd_len;
 	SRpnt->sr_use_sg = srp->data.k_use_sg;
@@ -747,7 +727,7 @@
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
 	SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: %s, cmd=0x%x\n",
-				   sdp->disk->disk_name, (int) cmd_in));
+				   sdp->cdev->cd_name, (int) cmd_in));
 	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
 
 	switch (cmd_in) {
@@ -1050,7 +1030,7 @@
 	} else if (count < SG_MAX_QUEUE)
 		res |= POLLOUT | POLLWRNORM;
 	SCSI_LOG_TIMEOUT(3, printk("sg_poll: %s, res=0x%x\n",
-				   sdp->disk->disk_name, (int) res));
+				   sdp->cdev->cd_name, (int) res));
 	return res;
 }
 
@@ -1064,7 +1044,7 @@
 	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
 		return -ENXIO;
 	SCSI_LOG_TIMEOUT(3, printk("sg_fasync: %s, mode=%d\n",
-				   sdp->disk->disk_name, mode));
+				   sdp->cdev->cd_name, mode));
 
 	retval = fasync_helper(fd, filp, mode, &sfp->async_qp);
 	return (retval < 0) ? retval : 0;
@@ -1256,7 +1236,7 @@
 	srp->done = 1;
 
 	SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n",
-		sdp->disk->disk_name, srp->header.pack_id, (int) SRpnt->sr_result));
+		sdp->cdev->cd_name, srp->header.pack_id, (int) SRpnt->sr_result));
 	srp->header.resid = SCpnt->resid;
 	/* N.B. unit of duration changes here from jiffies to millisecs */
 	srp->header.duration =
@@ -1331,8 +1311,7 @@
 sg_device_kdev_read(struct device *driverfs_dev, char *page)
 {
 	Sg_device *sdp = list_entry(driverfs_dev, Sg_device, sg_driverfs_dev);
-	return sprintf(page, "%x\n", MKDEV(sdp->disk->major,
-					   sdp->disk->first_minor));
+	return sprintf(page, "%lx\n", (long)sdp->cdev->cd_dev);
 }
 static DEVICE_ATTR(kdev,S_IRUGO,sg_device_kdev_read,NULL);
 
@@ -1347,70 +1326,30 @@
 static int
 sg_attach(Scsi_Device * scsidp)
 {
-	struct gendisk *disk;
+	struct char_device *cdev;
 	Sg_device *sdp = NULL;
+	dev_t dev;
 	unsigned long iflags;
 	int k, error;
 
-	disk = alloc_disk(1);
-	if (!disk)
-		return -ENOMEM;
+	write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	k = find_first_zero_bit(sg_index_bits, SG_MINORS);
+	if (k < SG_MINORS) {
+		__set_bit(k, sg_index_bits);
+		dev = MKDEV(SCSI_GENERIC_MAJOR, k);
+	} else
+		dev = 0;
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	cdev = alloc_chrdev(dev);
+	if (!cdev)
+		return -EBUSY;
 
 	error = scsi_slave_attach(scsidp);
 	if (error)
 		goto out_put;
-		
-	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-	if (sg_nr_dev >= sg_dev_max) {	/* try to resize */
-		Sg_device **tmp_da;
-		int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
-
-		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-		tmp_da = (Sg_device **)vmalloc(
-				tmp_dev_max * sizeof(Sg_device *));
-		if (NULL == tmp_da) {
-			printk(KERN_ERR
-			       "sg_attach: device array cannot be resized\n");
-			error = -ENOMEM;
-			goto out_detach;
-		}
-		write_lock_irqsave(&sg_dev_arr_lock, iflags);
-		memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *));
-		memcpy(tmp_da, sg_dev_arr,
-		       sg_dev_max * sizeof (Sg_device *));
-		vfree((char *) sg_dev_arr);
-		sg_dev_arr = tmp_da;
-		sg_dev_max = tmp_dev_max;
-	}
 
-find_empty_slot:
-	for (k = 0; k < sg_dev_max; k++)
-		if (!sg_dev_arr[k])
-			break;
-	if (k > SG_MAX_DEVS_MASK) {
-		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-		printk(KERN_WARNING
-		       "Unable to attach sg device <%d, %d, %d, %d>"
-		       " type=%d, minor number exceed %d\n",
-		       scsidp->host->host_no, scsidp->channel, scsidp->id,
-		       scsidp->lun, scsidp->type, SG_MAX_DEVS_MASK);
-		if (NULL != sdp)
-			vfree((char *) sdp);
-		error = -ENODEV;
-		goto out_detach;
-	}
-	if (k < sg_dev_max) {
-		if (NULL == sdp) {
-			write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-			sdp = (Sg_device *)vmalloc(sizeof(Sg_device));
-			write_lock_irqsave(&sg_dev_arr_lock, iflags);
-			if (!sg_dev_arr[k])
-				goto find_empty_slot;
-		}
-	} else
-		sdp = NULL;
+	sdp = kmalloc(sizeof(Sg_device), GFP_KERNEL);
 	if (NULL == sdp) {
-		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 		printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
 		error = -ENOMEM;
 		goto out_detach;
@@ -1419,11 +1358,8 @@
 	SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
 	memset(sdp, 0, sizeof(*sdp));
 	sdp->driver = &sg_template;
-	disk->private_data = &sdp->driver;
-	sprintf(disk->disk_name, "sg%d", k);
-	disk->major = SCSI_GENERIC_MAJOR;
-	disk->first_minor = k;
-	sdp->disk = disk;
+	cdev->cd_data = sdp;
+	sdp->cdev = cdev;
 	sdp->device = scsidp;
 	init_waitqueue_head(&sdp->o_excl_wait);
 	sdp->headfp = NULL;
@@ -1440,15 +1376,19 @@
 	sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
 	sdp->sg_driverfs_dev.bus = scsidp->sdev_driverfs_dev.bus;
 
+	error = add_chrdev(cdev, &sg_fops);
+	if (error)
+		goto out_free_sdp;
+	write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	list_add(&sdp->list, &sg_devlist);
 	sg_nr_dev++;
-	sg_dev_arr[k] = sdp;
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 
 	device_register(&sdp->sg_driverfs_dev);
 	device_create_file(&sdp->sg_driverfs_dev, &dev_attr_type);
 	device_create_file(&sdp->sg_driverfs_dev, &dev_attr_kdev);
 	sdp->de = devfs_register(scsidp->de, "generic", DEVFS_FL_DEFAULT,
-				 SCSI_GENERIC_MAJOR, k,
+				 MAJOR(cdev->cd_dev), MINOR(cdev->cd_dev),
 				 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
 				 &sg_fops, sdp);
 	switch (scsidp->type) {
@@ -1467,10 +1407,12 @@
 	}
 	return 0;
 
+out_free_sdp:
+	kfree(sdp);
 out_detach:
 	scsi_slave_detach(scsidp);
 out_put:
-	put_disk(disk);
+	del_chrdev(cdev);
 	return error;
 }
 
@@ -1483,16 +1425,13 @@
 	Sg_fd *tsfp;
 	Sg_request *srp;
 	Sg_request *tsrp;
-	int k, delay;
+	int delay;
 
-	if (NULL == sg_dev_arr)
-		return;
 	delay = 0;
 	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-	for (k = 0; k < sg_dev_max; k++) {
-		sdp = sg_dev_arr[k];
-		if ((NULL == sdp) || (sdp->device != scsidp))
-			continue;	/* dirty but lowers nesting */
+	list_for_each_entry(sdp, &sg_devlist, list) {
+		if (sdp->device != scsidp)
+			continue;
 		if (sdp->headfp) {
 			sdp->detached = 1;
 			for (sfp = sdp->headfp; sfp; sfp = tsfp) {
@@ -1512,13 +1451,12 @@
 						    POLL_HUP);
 				}
 			}
-			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
-			if (NULL == sdp->headfp) {
-				sg_dev_arr[k] = NULL;
-			}
+			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%s, dirty\n", sdp->cdev->cd_name));
+			if (NULL == sdp->headfp)
+				list_del(&sdp->list);
 		} else {	/* nothing active, simple case */
-			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
-			sg_dev_arr[k] = NULL;
+			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%s\n", sdp->cdev->cd_name));
+			list_del(&sdp->list);
 		}
 		scsi_slave_detach(scsidp);
 		sg_nr_dev--;
@@ -1532,10 +1470,12 @@
 		device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_type);
 		device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_kdev);
 		device_unregister(&sdp->sg_driverfs_dev);
-		put_disk(sdp->disk);
-		sdp->disk = NULL;
+		if (MAJOR(sdp->cdev->cd_dev) == SCSI_GENERIC_MAJOR)
+			clear_bit(MINOR(sdp->cdev->cd_dev), sg_index_bits);
+		del_chrdev(sdp->cdev);
+		sdp->cdev = NULL;
 		if (NULL == sdp->headfp)
-			vfree((char *) sdp);
+			kfree(sdp);
 	}
 
 	if (delay)
@@ -1643,11 +1583,6 @@
 #endif				/* CONFIG_PROC_FS */
 	scsi_unregister_device(&sg_template);
 	unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
-	if (sg_dev_arr != NULL) {
-		vfree((char *) sg_dev_arr);
-		sg_dev_arr = NULL;
-	}
-	sg_dev_max = 0;
 }
 
 static int
@@ -2447,14 +2382,15 @@
 #endif
 
 static Sg_fd *
-sg_add_sfp(Sg_device * sdp, int dev)
+sg_add_sfp(struct char_device *cdev)
 {
+	Sg_device *sdp;
 	Sg_fd *sfp;
 	unsigned long iflags;
 
 	sfp = (Sg_fd *) sg_page_malloc(sizeof (Sg_fd), 0, 0);
 	if (!sfp)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 	memset(sfp, 0, sizeof (Sg_fd));
 	init_waitqueue_head(&sfp->read_wait);
 	sfp->rq_list_lock = RW_LOCK_UNLOCKED;
@@ -2462,15 +2398,25 @@
 	sfp->timeout = SG_DEFAULT_TIMEOUT;
 	sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
 	sfp->force_packid = SG_DEF_FORCE_PACK_ID;
-	sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
-	    sdp->device->host->unchecked_isa_dma : 1;
 	sfp->cmd_q = SG_DEF_COMMAND_Q;
 	sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
-	sfp->parentdp = sdp;
+
 	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-	if (!sdp->headfp)
+	sdp = cdev->cd_data;
+	if (!sdp || !sdp->device || sdp->detached) {
+		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+		sg_page_free((char *) sfp, sizeof (Sg_fd));
+		return ERR_PTR(-ENODEV);
+	}
+	sfp->parentdp = sdp;
+	sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
+	    sdp->device->host->unchecked_isa_dma : 1;
+
+	if (!sdp->headfp) {	/* no existing opens on this device */
 		sdp->headfp = sfp;
-	else {			/* add to tail of existing list */
+		sdp->sgdebug = 0;
+		sdp->sg_tablesize = sdp->device->host->sg_tablesize;
+	} else {		/* add to tail of existing list */
 		Sg_fd *pfp = sdp->headfp;
 		while (pfp->nextfp)
 			pfp = pfp->nextfp;
@@ -2537,16 +2483,8 @@
 		write_lock_irqsave(&sg_dev_arr_lock, iflags);
 		__sg_remove_sfp(sdp, sfp);
 		if (sdp->detached && (NULL == sdp->headfp)) {
-			int k, maxd;
-
-			maxd = sg_dev_max;
-			for (k = 0; k < maxd; ++k) {
-				if (sdp == sg_dev_arr[k])
-					break;
-			}
-			if (k < maxd)
-				sg_dev_arr[k] = NULL;
-			vfree((char *) sdp);
+			list_del(&sdp->list);
+			kfree(sdp);
 			res = 1;
 		}
 		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
@@ -2662,37 +2600,6 @@
 }
 
 #ifdef CONFIG_PROC_FS
-static int
-sg_last_dev()
-{
-	int k;
-	unsigned long iflags;
-
-	read_lock_irqsave(&sg_dev_arr_lock, iflags);
-	for (k = sg_dev_max - 1; k >= 0; --k)
-		if (sg_dev_arr[k] && sg_dev_arr[k]->device)
-			break;
-	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	return k + 1;		/* origin 1 */
-}
-#endif
-
-static Sg_device *
-sg_get_dev(int dev)
-{
-	Sg_device *sdp = NULL;
-	unsigned long iflags;
-
-	if (sg_dev_arr && (dev >= 0)) {
-		read_lock_irqsave(&sg_dev_arr_lock, iflags);
-		if (dev < sg_dev_max)
-			sdp = sg_dev_arr[dev];
-		read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	}
-	return sdp;
-}
-
-#ifdef CONFIG_PROC_FS
 
 static struct proc_dir_entry *sg_proc_sgp = NULL;
 
@@ -2951,45 +2858,38 @@
 		   off_t offset, int size)
 {
 	Sg_device *sdp;
-	int j, max_dev;
+	unsigned long iflags;
 
-	if (NULL == sg_dev_arr) {
-		PRINT_PROC("sg_dev_arr NULL, driver not initialized\n");
-		return 1;
-	}
-	max_dev = sg_last_dev();
-	PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
-		   sg_dev_max, max_dev);
 	PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
-	for (j = 0; j < max_dev; ++j) {
-		if ((sdp = sg_get_dev(j))) {
-			struct scsi_device *scsidp = sdp->device;
-
-			if (NULL == scsidp) {
-				PRINT_PROC("device %d detached ??\n", j);
-				continue;
-			}
+	read_lock_irqsave(&sg_dev_arr_lock, iflags);
+	list_for_each_entry(sdp, &sg_devlist, list) {
+		struct scsi_device *scsidp = sdp->device;
 
-			if (sg_get_nth_sfp(sdp, 0)) {
-				PRINT_PROC(" >>> device=%s ",
-					sdp->disk->disk_name);
-				if (sdp->detached)
-					PRINT_PROC("detached pending close ");
-				else
-					PRINT_PROC
-					    ("scsi%d chan=%d id=%d lun=%d   em=%d",
-					     scsidp->host->host_no,
-					     scsidp->channel, scsidp->id,
-					     scsidp->lun,
-					     scsidp->host->hostt->emulated);
-				PRINT_PROC(" sg_tablesize=%d excl=%d\n",
-					   sdp->sg_tablesize, sdp->exclude);
-			}
-			if (0 == sg_proc_debug_helper(buffer, len, begin,
-						      offset, size, sdp))
-				return 0;
+		if (NULL == scsidp) {
+			PRINT_PROC("device %s detached ??\n", sdp->cdev->cd_name);
+			continue;
 		}
+
+		if (sg_get_nth_sfp(sdp, 0)) {
+			PRINT_PROC(" >>> device=%s ",
+				sdp->cdev->cd_name);
+			if (sdp->detached)
+				PRINT_PROC("detached pending close ");
+			else
+				PRINT_PROC
+				    ("scsi%d chan=%d id=%d lun=%d   em=%d",
+				     scsidp->host->host_no,
+				     scsidp->channel, scsidp->id,
+				     scsidp->lun,
+				     scsidp->host->hostt->emulated);
+			PRINT_PROC(" sg_tablesize=%d excl=%d\n",
+				   sdp->sg_tablesize, sdp->exclude);
+		}
+		if (0 == sg_proc_debug_helper(buffer, len, begin,
+					      offset, size, sdp))
+			return 0;
 	}
+	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 	return 1;
 }
 
@@ -3004,13 +2904,12 @@
 sg_proc_dev_info(char *buffer, int *len, off_t * begin, off_t offset, int size)
 {
 	Sg_device *sdp;
-	int j, max_dev;
 	struct scsi_device *scsidp;
+	unsigned long iflags;
 
-	max_dev = sg_last_dev();
-	for (j = 0; j < max_dev; ++j) {
-		sdp = sg_get_dev(j);
-		if (sdp && (scsidp = sdp->device) && (!sdp->detached))
+	read_lock_irqsave(&sg_dev_arr_lock, iflags);
+	list_for_each_entry(sdp, &sg_devlist, list) {
+		if ((scsidp = sdp->device) && !sdp->detached)
 			PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
 				   scsidp->host->host_no, scsidp->channel,
 				   scsidp->id, scsidp->lun, (int) scsidp->type,
@@ -3021,6 +2920,7 @@
 		else
 			PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
 	}
+	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 	return 1;
 }
 
@@ -3051,18 +2951,18 @@
 		     off_t offset, int size)
 {
 	Sg_device *sdp;
-	int j, max_dev;
 	struct scsi_device *scsidp;
+	unsigned long iflags;
 
-	max_dev = sg_last_dev();
-	for (j = 0; j < max_dev; ++j) {
-		sdp = sg_get_dev(j);
-		if (sdp && (scsidp = sdp->device) && (!sdp->detached))
+	read_lock_irqsave(&sg_dev_arr_lock, iflags);
+	list_for_each_entry(sdp, &sg_devlist, list) {
+		if ((scsidp = sdp->device) && !sdp->detached)
 			PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n",
 				   scsidp->vendor, scsidp->model, scsidp->rev);
 		else
 			PRINT_PROC("<no active device>\n");
 	}
+	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 	return 1;
 }
 
diff -ur linux-2.5.67/drivers/usb/class/usblp.c linux-2.5.67-cdev5/drivers/usb/class/usblp.c
--- linux-2.5.67/drivers/usb/class/usblp.c	2003-04-04 19:30:54.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/usb/class/usblp.c	2003-04-14 20:41:31.000000000 +0200
@@ -383,7 +383,7 @@
 static void usblp_cleanup (struct usblp *usblp)
 {
 	devfs_unregister (usblp->devfs);
-	usb_deregister_dev (1, usblp->minor);
+	usb_deregister_dev (usblp->minor);
 	info("usblp%d: removed", usblp->minor);
 
 	usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
@@ -832,7 +832,7 @@
 	init_waitqueue_head(&usblp->wait);
 	usblp->ifnum = intf->altsetting->desc.bInterfaceNumber;
 
-	retval = usb_register_dev(&usblp_fops, USBLP_MINOR_BASE, 1, &usblp->minor);
+	retval = usb_register_dev(&usblp_fops, USBLP_MINOR_BASE, &usblp->minor);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		goto abort;
@@ -930,7 +930,7 @@
 	return 0;
 
 abort_minor:
-	usb_deregister_dev (1, usblp->minor);
+	usb_deregister_dev (usblp->minor);
 abort:
 	if (usblp) {
 		if (usblp->writebuf)
diff -ur linux-2.5.67/drivers/usb/core/file.c linux-2.5.67-cdev5/drivers/usb/core/file.c
--- linux-2.5.67/drivers/usb/core/file.c	2003-04-04 19:30:55.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/usb/core/file.c	2003-04-14 20:41:31.000000000 +0200
@@ -31,41 +31,9 @@
 static devfs_handle_t usb_devfs_handle;	/* /dev/usb dir. */
 
 #define MAX_USB_MINORS	256
-static struct file_operations *usb_minors[MAX_USB_MINORS];
-static spinlock_t minor_lock = SPIN_LOCK_UNLOCKED;
-
-static int usb_open(struct inode * inode, struct file * file)
-{
-	int minor = minor(inode->i_rdev);
-	struct file_operations *c;
-	int err = -ENODEV;
-	struct file_operations *old_fops, *new_fops = NULL;
-
-	spin_lock (&minor_lock);
-	c = usb_minors[minor];
-
-	if (!c || !(new_fops = fops_get(c))) {
-		spin_unlock(&minor_lock);
-		return err;
-	}
-	spin_unlock(&minor_lock);
-
-	old_fops = file->f_op;
-	file->f_op = new_fops;
-	/* Curiouser and curiouser... NULL ->open() as "no device" ? */
-	if (file->f_op->open)
-		err = file->f_op->open(inode,file);
-	if (err) {
-		fops_put(file->f_op);
-		file->f_op = fops_get(old_fops);
-	}
-	fops_put(old_fops);
-	return err;
-}
 
 static struct file_operations usb_fops = {
 	.owner =	THIS_MODULE,
-	.open =		usb_open,
 };
 
 int usb_major_init(void)
@@ -106,12 +74,10 @@
  * device, and 0 on success, alone with a value that the driver should
  * use in start_minor.
  */
-int usb_register_dev (struct file_operations *fops, int minor, int num_minors, int *start_minor)
+int usb_register_dev (struct file_operations *fops, int minor, int *start_minor)
 {
+	struct char_device *cdev;
 	int i;
-	int j;
-	int good_spot;
-	int retval = -EINVAL;
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
 	/* 
@@ -122,37 +88,29 @@
 	minor = 0;
 #endif
 
-	dbg ("asking for %d minors, starting at %d", num_minors, minor);
+	dbg ("asking for 1 minors, starting at %d", minor);
 
 	if (fops == NULL)
-		goto exit;
+		return  -EINVAL;
 
 	*start_minor = 0; 
-	spin_lock (&minor_lock);
 	for (i = minor; i < MAX_USB_MINORS; ++i) {
-		if (usb_minors[i])
-			continue;
-
-		good_spot = 1;
-		for (j = 1; j <= num_minors-1; ++j)
-			if (usb_minors[i+j]) {
-				good_spot = 0;
-				break;
+		cdev = cdget(MKDEV(USB_MAJOR, i));
+		if (!cdev->cd_fops) {
+			down(&cdev->cd_sem);
+			if (!cdev->cd_fops) {
+				dbg("found a minor chunk free, starting at %d", i);
+				cdev->cd_fops = fops;
+				up(&cdev->cd_sem);
+				*start_minor = i;
+				return 0;
 			}
-		if (good_spot == 0)
-			continue;
-
-		*start_minor = i;
-		dbg("found a minor chunk free, starting at %d", i);
-		for (i = *start_minor; i < (*start_minor + num_minors); ++i)
-			usb_minors[i] = fops;
-
-		retval = 0;
-		goto exit;
+			up(&cdev->cd_sem);
+		}
+		cdput(cdev);
 	}
-exit:
-	spin_unlock (&minor_lock);
-	return retval;
+
+	return -EBUSY;
 }
 EXPORT_SYMBOL(usb_register_dev);
 
@@ -168,16 +126,21 @@
  * 
  * This should be called by all drivers that use the USB major number.
  */
-void usb_deregister_dev (int num_minors, int start_minor)
+void usb_deregister_dev (int minor)
 {
-	int i;
+	struct char_device *cdev;
 
 	dbg ("removing %d minors starting at %d", num_minors, start_minor);
 
-	spin_lock (&minor_lock);
-	for (i = start_minor; i < (start_minor + num_minors); ++i)
-		usb_minors[i] = NULL;
-	spin_unlock (&minor_lock);
+	cdev = cdget(MKDEV(USB_MAJOR, minor));
+	down(&cdev->cd_sem);
+	if (cdev->cd_fops) {
+		cdev->cd_fops = NULL;
+		cdput(cdev);
+	} else
+		printk("usb_deregister_dev: releasing invalid dev %d\n", minor);
+	up(&cdev->cd_sem);
+	cdput(cdev);
 }
 EXPORT_SYMBOL(usb_deregister_dev);
 
diff -ur linux-2.5.67/drivers/usb/image/mdc800.c linux-2.5.67-cdev5/drivers/usb/image/mdc800.c
--- linux-2.5.67/drivers/usb/image/mdc800.c	2003-04-11 20:10:27.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/usb/image/mdc800.c	2003-04-14 20:41:31.000000000 +0200
@@ -477,7 +477,7 @@
 
 	down (&mdc800->io_lock);
 
-	retval = usb_register_dev (&mdc800_device_ops, MDC800_DEVICE_MINOR_BASE, 1, &mdc800->minor);
+	retval = usb_register_dev (&mdc800_device_ops, MDC800_DEVICE_MINOR_BASE, &mdc800->minor);
 	if (retval && (retval != -ENODEV)) {
 		err ("Not able to get a minor for this device.");
 		return -ENODEV;
@@ -540,7 +540,7 @@
 		if (mdc800->state == NOT_CONNECTED)
 			return;
 
-		usb_deregister_dev (1, mdc800->minor);
+		usb_deregister_dev (mdc800->minor);
 
 		mdc800->state=NOT_CONNECTED;
 
diff -ur linux-2.5.67/drivers/usb/image/scanner.c linux-2.5.67-cdev5/drivers/usb/image/scanner.c
--- linux-2.5.67/drivers/usb/image/scanner.c	2003-04-04 19:30:56.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/usb/image/scanner.c	2003-04-14 20:41:31.000000000 +0200
@@ -840,7 +840,7 @@
 
 	dbg("%s: De-allocating minor:%d", __FUNCTION__, scn->scn_minor);
 	devfs_unregister(scn->devfs);
-	usb_deregister_dev(1, scn->scn_minor);
+	usb_deregister_dev(scn->scn_minor);
 	usb_free_urb(scn->scn_irq);
 	usb_put_dev(scn->scn_dev);
 	up (&(scn->sem));
@@ -1006,7 +1006,7 @@
 	
 	down(&scn_mutex);
 
-	retval = usb_register_dev(&usb_scanner_fops, SCN_BASE_MNR, 1, &scn_minor);
+	retval = usb_register_dev(&usb_scanner_fops, SCN_BASE_MNR, &scn_minor);
 	if (retval) {
 		err ("Not able to get a minor for this device.");
 		up(&scn_mutex);
diff -ur linux-2.5.67/drivers/usb/input/hiddev.c linux-2.5.67-cdev5/drivers/usb/input/hiddev.c
--- linux-2.5.67/drivers/usb/input/hiddev.c	2003-04-04 19:30:56.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/usb/input/hiddev.c	2003-04-14 20:41:31.000000000 +0200
@@ -230,7 +230,7 @@
 static void hiddev_cleanup(struct hiddev *hiddev)
 {
 	devfs_unregister(hiddev->devfs);
-	usb_deregister_dev(1, hiddev->minor);
+	usb_deregister_dev(hiddev->minor);
 	hiddev_table[hiddev->minor] = NULL;
 	kfree(hiddev);
 }
@@ -695,14 +695,14 @@
 	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
 		return -1;
 
-	retval = usb_register_dev(&hiddev_fops, HIDDEV_MINOR_BASE, 1, &minor);
+	retval = usb_register_dev(&hiddev_fops, HIDDEV_MINOR_BASE, &minor);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		return -1;
 	}
 
 	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) {
-		usb_deregister_dev (1, minor);
+		usb_deregister_dev (minor);
 		return -1;
 	}
 	memset(hiddev, 0, sizeof(struct hiddev));
diff -ur linux-2.5.67/drivers/usb/media/dabusb.c linux-2.5.67-cdev5/drivers/usb/media/dabusb.c
--- linux-2.5.67/drivers/usb/media/dabusb.c	2003-01-27 22:37:46.000000000 +0100
+++ linux-2.5.67-cdev5/drivers/usb/media/dabusb.c	2003-04-14 20:41:31.000000000 +0200
@@ -731,7 +731,7 @@
 	if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF && usbdev->descriptor.idProduct == 0x9999)
 		return -ENODEV;
 
-	retval = usb_register_dev (&dabusb_fops, DABUSB_MINOR, 1, &devnum);
+	retval = usb_register_dev (&dabusb_fops, DABUSB_MINOR, &devnum);
 	if (retval)
 		return -ENOMEM;
 
@@ -778,7 +778,7 @@
 
 	usb_set_intfdata (intf, NULL);
 	if (s) {
-		usb_deregister_dev (1, s->devnum);
+		usb_deregister_dev (s->devnum);
 		s->remove_pending = 1;
 		wake_up (&s->wait);
 		if (s->state == _started)
diff -ur linux-2.5.67/drivers/usb/misc/auerswald.c linux-2.5.67-cdev5/drivers/usb/misc/auerswald.c
--- linux-2.5.67/drivers/usb/misc/auerswald.c	2003-04-04 19:30:57.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/usb/misc/auerswald.c	2003-04-14 20:41:31.000000000 +0200
@@ -1956,7 +1956,7 @@
 	init_waitqueue_head (&cp->bufferwait);
 
 	down (&dev_table_mutex);
-	ret = usb_register_dev (&auerswald_fops, AUER_MINOR_BASE, 1, &dtindex);
+	ret = usb_register_dev (&auerswald_fops, AUER_MINOR_BASE, &dtindex);
 	if (ret) {
 		err ("Not able to get a minor for this device.");
 		up (&dev_table_mutex);
@@ -2095,7 +2095,7 @@
 	devfs_unregister (cp->devfs);
 
 	/* give back our USB minor number */
-	usb_deregister_dev (1, cp->dtindex);
+	usb_deregister_dev (cp->dtindex);
 
 	/* Stop the interrupt endpoint */
 	auerswald_int_release (cp);
diff -ur linux-2.5.67/drivers/usb/misc/brlvger.c linux-2.5.67-cdev5/drivers/usb/misc/brlvger.c
--- linux-2.5.67/drivers/usb/misc/brlvger.c	2003-04-04 19:30:57.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/usb/misc/brlvger.c	2003-04-14 20:41:31.000000000 +0200
@@ -312,7 +312,7 @@
 
 	down(&reserve_sem);
 
-	retval = usb_register_dev(&brlvger_fops, BRLVGER_MINOR, 1, &i);
+	retval = usb_register_dev(&brlvger_fops, BRLVGER_MINOR, &i);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		goto error;
@@ -421,7 +421,7 @@
 		info("Display %d disconnecting", priv->subminor);
 
 		devfs_unregister(priv->devfs);
-		usb_deregister_dev(1, priv->subminor);
+		usb_deregister_dev(priv->subminor);
 
 		down(&disconnect_sem);
 		display_table[priv->subminor] = NULL;
diff -ur linux-2.5.67/drivers/usb/misc/rio500.c linux-2.5.67-cdev5/drivers/usb/misc/rio500.c
--- linux-2.5.67/drivers/usb/misc/rio500.c	2003-04-04 19:30:57.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/usb/misc/rio500.c	2003-04-14 20:41:31.000000000 +0200
@@ -454,7 +454,7 @@
 
 	info("USB Rio found at address %d", dev->devnum);
 
-	retval = usb_register_dev(&usb_rio_fops, RIO_MINOR, 1, &rio->minor);
+	retval = usb_register_dev(&usb_rio_fops, RIO_MINOR, &rio->minor);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		return -ENOMEM;
@@ -497,7 +497,7 @@
 	usb_set_intfdata (intf, NULL);
 	if (rio) {
 		devfs_unregister(rio->devfs);
-		usb_deregister_dev(1, rio->minor);
+		usb_deregister_dev(rio->minor);
 
 		down(&(rio->lock));
 		if (rio->isopen) {
diff -ur linux-2.5.67/drivers/usb/misc/usblcd.c linux-2.5.67-cdev5/drivers/usb/misc/usblcd.c
--- linux-2.5.67/drivers/usb/misc/usblcd.c	2003-03-10 19:49:00.000000000 +0100
+++ linux-2.5.67-cdev5/drivers/usb/misc/usblcd.c	2003-04-14 20:41:31.000000000 +0200
@@ -268,7 +268,7 @@
 		(i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF),
 		dev->devnum);
 
-	retval = usb_register_dev(&usb_lcd_fops, USBLCD_MINOR, 1, &lcd->minor);
+	retval = usb_register_dev(&usb_lcd_fops, USBLCD_MINOR, &lcd->minor);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		return -ENOMEM;
@@ -300,7 +300,7 @@
 
 	usb_set_intfdata (intf, NULL);
 	if (lcd) {
-		usb_deregister_dev(1, lcd->minor);
+		usb_deregister_dev(lcd->minor);
 
 		if (lcd->isopen) {
 			lcd->isopen = 0;
diff -ur linux-2.5.67/drivers/usb/usb-skeleton.c linux-2.5.67-cdev5/drivers/usb/usb-skeleton.c
--- linux-2.5.67/drivers/usb/usb-skeleton.c	2003-04-11 20:10:26.000000000 +0200
+++ linux-2.5.67-cdev5/drivers/usb/usb-skeleton.c	2003-04-14 20:41:31.000000000 +0200
@@ -522,7 +522,7 @@
 		return -ENODEV;
 	}
 
-	retval = usb_register_dev (&skel_fops, USB_SKEL_MINOR_BASE, 1, &minor);
+	retval = usb_register_dev (&skel_fops, USB_SKEL_MINOR_BASE, &minor);
 	if (retval) {
 		/* something prevented us from registering this driver */
 		err ("Not able to get a minor for this device.");
@@ -630,7 +630,7 @@
 	dev = NULL;
 
 exit_minor:
-	usb_deregister_dev (1, minor);
+	usb_deregister_dev (minor);
 
 exit:
 	if (dev) {
@@ -677,7 +677,7 @@
 	devfs_unregister (dev->devfs);
 
 	/* give back our dynamic minor */
-	usb_deregister_dev (1, minor);
+	usb_deregister_dev (minor);
 
 	/* terminate an ongoing write */
 	if (atomic_read (&dev->write_busy)) {
diff -ur linux-2.5.67/fs/char_dev.c linux-2.5.67-cdev5/fs/char_dev.c
--- linux-2.5.67/fs/char_dev.c	2003-04-11 20:10:33.000000000 +0200
+++ linux-2.5.67-cdev5/fs/char_dev.c	2003-04-14 20:41:31.000000000 +0200
@@ -15,208 +15,284 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
 
-#ifdef CONFIG_KMOD
 #include <linux/kmod.h>
-#endif
 
-#define MAX_PROBE_HASH 255	/* random */
+#define HASH_BITS	6
+#define HASH_SIZE	(1UL << HASH_BITS)
+#define HASH_MASK	(HASH_SIZE-1)
+static struct list_head cdev_hashtable[HASH_SIZE];
+static spinlock_t cdev_lock = SPIN_LOCK_UNLOCKED;
+static kmem_cache_t *cdev_cachep;
+static LIST_HEAD(cdev_list);
+
+#define alloc_cdev() \
+	 ((struct char_device *) kmem_cache_alloc(cdev_cachep, SLAB_KERNEL))
+#define destroy_cdev(cdev) kmem_cache_free(cdev_cachep, (cdev))
 
-static rwlock_t chrdevs_lock = RW_LOCK_UNLOCKED;
+static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct char_device *cdev = (struct char_device *) foo;
 
-static struct char_device_struct {
-	struct char_device_struct *next;
-	unsigned int major;
-	unsigned int baseminor;
-	int minorct;
-	const char *name;
-	struct file_operations *fops;
-} *chrdevs[MAX_PROBE_HASH];
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		memset(cdev, 0, sizeof(*cdev));
+		sema_init(&cdev->cd_sem, 1);
+	}
+}
 
-/* index in the above */
-static inline int major_to_index(int major)
+void __init cdev_cache_init(void)
 {
-	return major % MAX_PROBE_HASH;
+	int i;
+	struct list_head *head = cdev_hashtable;
+
+	i = HASH_SIZE;
+	do {
+		INIT_LIST_HEAD(head);
+		head++;
+		i--;
+	} while (i);
+
+	cdev_cachep = kmem_cache_create("cdev_cache",
+					 sizeof(struct char_device),
+					 0, SLAB_HWCACHE_ALIGN, init_once,
+					 NULL);
+	if (!cdev_cachep)
+		panic("Cannot create cdev_cache SLAB cache");
 }
 
-/* get char device names in somewhat random order */
-int get_chrdev_list(char *page)
+/*
+ * Most likely _very_ bad one - but then it's hardly critical for small
+ * /dev and can be fixed when somebody will need really large one.
+ */
+static inline unsigned long hash(dev_t dev)
 {
-	struct char_device_struct *cd;
-	int i, len;
+	unsigned long tmp = dev;
+	tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
+	return tmp & HASH_MASK;
+}
 
-	len = sprintf(page, "Character devices:\n");
+static struct char_device *cdfind(dev_t dev, struct list_head *head)
+{
+	struct list_head *p;
+	struct char_device *cdev;
 
-	read_lock(&chrdevs_lock);
-	for (i = 0; i < ARRAY_SIZE(chrdevs) ; i++) {
-		for (cd = chrdevs[i]; cd; cd = cd->next)
-			len += sprintf(page+len, "%3d %s\n",
-				       cd->major, cd->name);
+	list_for_each(p, head) {
+		cdev = list_entry(p, struct char_device, cd_hash);
+		if (cdev->cd_dev == dev) {
+			atomic_inc(&cdev->cd_count);
+			return cdev;
+		}
 	}
-	read_unlock(&chrdevs_lock);
+	return NULL;
+}
 
-	return len;
+struct char_device *cdget(dev_t dev)
+{
+	struct list_head * head = cdev_hashtable + hash(dev);
+	struct char_device *cdev, *new_cdev;
+
+	spin_lock(&cdev_lock);
+	cdev = cdfind(dev, head);
+	spin_unlock(&cdev_lock);
+	if (cdev)
+		return cdev;
+
+	new_cdev = alloc_cdev();
+	if (!new_cdev)
+		return NULL;
+	atomic_set(&new_cdev->cd_count, 1);
+	new_cdev->cd_dev = dev;
+
+	spin_lock(&cdev_lock);
+	cdev = cdfind(dev, head);
+	if (!cdev) {
+		list_add(&new_cdev->cd_hash, head);
+		spin_unlock(&cdev_lock);
+		return new_cdev;
+	}
+	spin_unlock(&cdev_lock);
+	destroy_cdev(new_cdev);
+	return cdev;
 }
 
-/*
- * Return the function table of a device, if present.
- * Increment the reference count of module in question.
- */
-static struct file_operations *
-lookup_chrfops(unsigned int major, unsigned int minor)
+void cdput(struct char_device *cdev)
 {
-	struct char_device_struct *cd;
-	struct file_operations *ret = NULL;
-	int i;
+	if (atomic_dec_and_lock(&cdev->cd_count, &cdev_lock)) {
+		list_del(&cdev->cd_hash);
+		spin_unlock(&cdev_lock);
+		destroy_cdev(cdev);
+	}
+}
+
+#define CHRDEV_NR	32768
 
-	i = major_to_index(major);
+static unsigned long char_index_bits[CHRDEV_NR / BITS_PER_LONG];
+static spinlock_t char_index_lock = SPIN_LOCK_UNLOCKED;
 
-	read_lock(&chrdevs_lock);
-	for (cd = chrdevs[i]; cd; cd = cd->next) {
-		if (major == cd->major &&
-		    minor - cd->baseminor < cd->minorct) {
-			ret = fops_get(cd->fops);
-			break;
+struct char_device *alloc_chrdev(dev_t dev)
+{
+	if (!dev) {
+		int index;
+
+		spin_lock(&char_index_lock);
+		index = find_first_zero_bit(char_index_bits, CHRDEV_NR);
+		if (index == CHRDEV_NR) {
+			spin_unlock(&char_index_lock);
+			return NULL;
 		}
+		__set_bit(index, char_index_bits);
+		spin_unlock(&char_index_lock);
+		dev = 0x10000 + index;
 	}
-	read_unlock(&chrdevs_lock);
+	return cdget(dev);
+}
 
-	return ret;
+int add_chrdev(struct char_device *cdev, struct file_operations *fops)
+{
+	int res = 0;
+
+	down(&cdev->cd_sem);
+	if (!cdev->cd_fops)
+		cdev->cd_fops = fops;
+	else
+		res = -EBUSY;
+	up(&cdev->cd_sem);
+
+	return res;
 }
 
-/*
- * Return the function table of a device, if present.
- * Load the driver if needed.
- * Increment the reference count of module in question.
- */
-static struct file_operations *
-get_chrfops(unsigned int major, unsigned int minor)
+void unlink_chrdev(struct char_device *cdev)
 {
-	struct file_operations *ret = NULL;
+	cdev->cd_fops = NULL;
+}
 
-	if (!major)
-		return NULL;
+void del_chrdev(struct char_device *cdev)
+{
+	int i = cdev->cd_dev - 0x10000;
 
-	ret = lookup_chrfops(major, minor);
+	unlink_chrdev(cdev);
+	if (cdev->cd_dev >= 0x10000 && i < CHRDEV_NR) {
+		spin_lock(&char_index_lock);
+		clear_bit(i, char_index_bits);
+		spin_unlock(&char_index_lock);
+	}
+	cdput(cdev);
+}
 
-#ifdef CONFIG_KMOD
-	if (!ret) {
-		char name[32];
-		sprintf(name, "char-major-%d", major);
-		request_module(name);
+int get_chrdev_list(char *page)
+{
+	struct char_device *cdev;
+	int len;
 
-		read_lock(&chrdevs_lock);
-		ret = lookup_chrfops(major, minor);
-		read_unlock(&chrdevs_lock);
+	len = sprintf(page, "Character devices:\n");
+	spin_lock(&cdev_lock);
+	list_for_each_entry(cdev, &cdev_list, cd_list) {
+		if (cdev->cd_name)
+			len += sprintf(page+len, "%3d %s\n",
+				       MAJOR(cdev->cd_dev), cdev->cd_name);
 	}
-#endif
-	return ret;
+	spin_unlock(&cdev_lock);
+	return len;
 }
 
 /*
- * Register a single major with a specified minor range.
- *
- * If major == 0 this functions will dynamically allocate a major and return
- * its number.
- *
- * If major > 0 this function will attempt to reserve the passed range of
- * minors and will return zero on success.
- *
- * Returns a -ve errno on failure.
- */
-int register_chrdev_region(unsigned int major, unsigned int baseminor,
-			   int minorct, const char *name,
-			   struct file_operations *fops)
+	Return the function table of a device.
+	Load the driver if needed.
+	Increment the reference count of module in question.
+*/
+static struct file_operations *get_chrfops(struct char_device *cdev)
 {
-	struct char_device_struct *cd, **cp;
-	int ret = 0;
-	int i;
+	struct file_operations *fops;
 
-	cd = kmalloc(sizeof(struct char_device_struct), GFP_KERNEL);
-	if (cd == NULL)
-		return -ENOMEM;
+	down(&cdev->cd_sem);
+	fops = fops_get(cdev->cd_fops);
+	up(&cdev->cd_sem);
+	if (fops)
+		return fops;
+
+	cdev = cdget_major(MAJOR(cdev->cd_dev));
+	down(&cdev->cd_sem);
+	fops = fops_get(cdev->cd_fops);
+	up(&cdev->cd_sem);
+#ifdef CONFIG_KMOD
+	if (!fops) {
+		char name[32];
 
-	write_lock_irq(&chrdevs_lock);
+		sprintf(name, "char-major-%d", MAJOR(cdev->cd_dev));
+		request_module(name);
+		down(&cdev->cd_sem);
+		fops = fops_get(cdev->cd_fops);
+		up(&cdev->cd_sem);
+	}
+#endif
+	cdput(cdev);
+	if (fops && fops->open)
+		return fops;
+	fops_put(fops);
+	return NULL;
+}
 
-	/* temporary */
-	if (major == 0) {
-		for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
-			if (chrdevs[i] == NULL)
-				break;
-		}
+int register_chrdev(unsigned int major, const char * name, struct file_operations *fops)
+{
+	struct char_device *cdev;
+	int res;
 
-		if (i == 0) {
-			ret = -EBUSY;
-			goto out;
+	if (major == 0) {
+		for (major = MAX_CHRDEV-1; major > 0; major--) {
+			cdev = cdget_major(major);
+			down(&cdev->cd_sem);
+			if (!cdev->cd_fops) {
+				res = major;
+				goto found;
+			}
+			up(&cdev->cd_sem); 
+			cdput(cdev);
 		}
-		major = i;
-		ret = major;
+		return -EBUSY;
 	}
 
-	cd->major = major;
-	cd->baseminor = baseminor;
-	cd->minorct = minorct;
-	cd->name = name;
-	cd->fops = fops;
-
-	i = major_to_index(major);
-
-	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
-		if ((*cp)->major > major ||
-		    ((*cp)->major == major && (*cp)->baseminor >= baseminor))
-			break;
-	if (*cp && (*cp)->major == major &&
-	    (*cp)->baseminor < baseminor + minorct) {
-		ret = -EBUSY;
-	} else {
-		cd->next = *cp;
-		*cp = cd;
-	}
-out:
-	write_unlock_irq(&chrdevs_lock);
-	if (ret < 0)
-		kfree(cd);
-	return ret;
-}
+	if (major >= MAX_CHRDEV)
+		return -EINVAL;
 
-int register_chrdev(unsigned int major, const char *name,
-		    struct file_operations *fops)
-{
-	return register_chrdev_region(major, 0, 256, name, fops);
+	cdev = cdget_major(major);
+	down(&cdev->cd_sem);
+	if (cdev->cd_fops) {
+		up(&cdev->cd_sem);
+		cdput(cdev);
+		return -EBUSY;
+	}
+	res = 0;
+found:
+	cdev->cd_fops = fops;
+	cdev->cd_name = name;
+	list_add_tail(&cdev->cd_list, &cdev_list);
+	up(&cdev->cd_sem);
+	return 0;
 }
 
-/* todo: make void - error printk here */
-int unregister_chrdev_region(unsigned int major, unsigned int baseminor,
-			     int minorct, const char *name)
+int unregister_chrdev(unsigned int major, const char * name)
 {
-	struct char_device_struct *cd, **cp;
-	int ret = 0;
-	int i;
+	struct char_device *cdev;
+	int res;
 
-	i = major_to_index(major);
+	if (major >= MAX_CHRDEV)
+		return -EINVAL;
 
-	write_lock_irq(&chrdevs_lock);
-	for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
-		if ((*cp)->major == major &&
-		    (*cp)->baseminor == baseminor &&
-		    (*cp)->minorct == minorct)
-			break;
-	if (!*cp || strcmp((*cp)->name, name))
-		ret = -EINVAL;
-	else {
-		cd = *cp;
-		*cp = cd->next;
-		kfree(cd);
+	cdev = cdget_major(major);
+	down(&cdev->cd_sem);
+	res = -EINVAL;
+	if (cdev->cd_fops && !strcmp(cdev->cd_name, name)) {
+		list_del(&cdev->cd_list);
+		cdev->cd_fops = NULL;
+		cdev->cd_name = NULL;
+		cdput(cdev);
+		res = 0;
 	}
-	write_unlock_irq(&chrdevs_lock);
+	up(&cdev->cd_sem);
 
-	return ret;
-}
-
-int unregister_chrdev(unsigned int major, const char *name)
-{
-	return unregister_chrdev_region(major, 0, 256, name);
+	cdput(cdev);
+	return res;
 }
 
 /*
@@ -224,14 +300,16 @@
  */
 int chrdev_open(struct inode * inode, struct file * filp)
 {
+	struct file_operations *fops;
 	int ret = -ENODEV;
 
-	filp->f_op = get_chrfops(major(inode->i_rdev), minor(inode->i_rdev));
-	if (filp->f_op) {
+	fops = get_chrfops(inode->i_cdev);
+	if (fops) {
 		ret = 0;
-		if (filp->f_op->open != NULL) {
+		filp->f_op = fops;
+		if (fops->open) {
 			lock_kernel();
-			ret = filp->f_op->open(inode,filp);
+			ret = fops->open(inode, filp);
 			unlock_kernel();
 		}
 	}
@@ -249,21 +327,13 @@
 
 const char *cdevname(kdev_t dev)
 {
-	static char buffer[40];
-	const char *name = "unknown-char";
-	unsigned int major = major(dev);
-	unsigned int minor = minor(dev);
-	int i = major_to_index(major);
-	struct char_device_struct *cd;
-
-	read_lock(&chrdevs_lock);
-	for (cd = chrdevs[i]; cd; cd = cd->next)
-		if (cd->major == major)
-			break;
-	if (cd)
-		name = cd->name;
-	sprintf(buffer, "%s(%d,%d)", name, major, minor);
-	read_unlock(&chrdevs_lock);
+	static char buffer[64];
+	struct char_device *cdev;
+
+	cdev = cdget(kdev_t_to_nr(dev));
+	down(&cdev->cd_sem);
+	sprintf(buffer, "%s(%ld,%ld)", cdev->cd_name ? cdev->cd_name : "unknown-char", major(dev), minor(dev));
+	up(&cdev->cd_sem);
 
 	return buffer;
 }
diff -ur linux-2.5.67/fs/dcache.c linux-2.5.67-cdev5/fs/dcache.c
--- linux-2.5.67/fs/dcache.c	2003-04-11 20:10:33.000000000 +0200
+++ linux-2.5.67-cdev5/fs/dcache.c	2003-04-14 20:41:32.000000000 +0200
@@ -1593,6 +1593,7 @@
 EXPORT_SYMBOL(d_genocide);
 
 extern void bdev_cache_init(void);
+extern void cdev_cache_init(void);
 
 void __init vfs_caches_init(unsigned long mempages)
 {
@@ -1613,4 +1614,5 @@
 	files_init(mempages); 
 	mnt_init(mempages);
 	bdev_cache_init();
+	cdev_cache_init();
 }
diff -ur linux-2.5.67/fs/devfs/base.c linux-2.5.67-cdev5/fs/devfs/base.c
--- linux-2.5.67/fs/devfs/base.c	2003-04-04 19:31:15.000000000 +0200
+++ linux-2.5.67-cdev5/fs/devfs/base.c	2003-04-14 20:41:32.000000000 +0200
@@ -2012,6 +2012,7 @@
     if ( S_ISCHR (de->mode) )
     {
 	inode->i_rdev = to_kdev_t(de->u.cdev.dev);
+	inode->i_cdev = cdget(de->u.cdev.dev);
     }
     else if ( S_ISBLK (de->mode) )
     {
diff -ur linux-2.5.67/fs/inode.c linux-2.5.67-cdev5/fs/inode.c
--- linux-2.5.67/fs/inode.c	2003-04-11 20:10:33.000000000 +0200
+++ linux-2.5.67-cdev5/fs/inode.c	2003-04-14 20:41:32.000000000 +0200
@@ -128,6 +128,7 @@
 		memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
 		inode->i_pipe = NULL;
 		inode->i_bdev = NULL;
+		inode->i_cdev = NULL;
 		inode->i_rdev = to_kdev_t(0);
 		inode->i_security = NULL;
 		if (security_inode_alloc(inode)) {
@@ -145,7 +146,7 @@
 		mapping->assoc_mapping = NULL;
 		mapping->backing_dev_info = &default_backing_dev_info;
 		if (sb->s_bdev)
-			mapping->backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
+			inode->i_data.backing_dev_info = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
 		memset(&inode->u, 0, sizeof(inode->u));
 		inode->i_mapping = mapping;
 	}
@@ -241,6 +242,10 @@
 		inode->i_sb->s_op->clear_inode(inode);
 	if (inode->i_bdev)
 		bd_forget(inode);
+	else if (inode->i_cdev) {
+		cdput(inode->i_cdev);
+		inode->i_cdev = NULL;
+	}
 	inode->i_state = I_CLEAR;
 }
 
@@ -1310,6 +1315,7 @@
 	if (S_ISCHR(mode)) {
 		inode->i_fop = &def_chr_fops;
 		inode->i_rdev = to_kdev_t(rdev);
+		inode->i_cdev = cdget(rdev);
 	} else if (S_ISBLK(mode)) {
 		inode->i_fop = &def_blk_fops;
 		inode->i_rdev = to_kdev_t(rdev);
@@ -1318,6 +1324,5 @@
 	else if (S_ISSOCK(mode))
 		inode->i_fop = &bad_sock_fops;
 	else
-		printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n",
-		       mode);
+		printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o)\n", mode);
 }
diff -ur linux-2.5.67/fs/proc/proc_tty.c linux-2.5.67-cdev5/fs/proc/proc_tty.c
--- linux-2.5.67/fs/proc/proc_tty.c	2002-10-16 22:33:19.000000000 +0200
+++ linux-2.5.67-cdev5/fs/proc/proc_tty.c	2003-04-14 20:41:32.000000000 +0200
@@ -14,8 +14,6 @@
 #include <linux/tty.h>
 #include <asm/bitops.h>
 
-extern struct tty_ldisc ldiscs[];
-
 
 static int tty_drivers_read_proc(char *page, char **start, off_t off,
 				 int count, int *eof, void *data);
@@ -35,61 +33,64 @@
 {
 	int	len = 0;
 	off_t	begin = 0;
+	struct tty_major *m;
 	struct tty_driver *p;
 	char	range[20], deftype[20];
 	char	*type;
 
-	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		if (p->num > 1)
-			sprintf(range, "%d-%d", p->minor_start,
-				p->minor_start + p->num - 1);
-		else
-			sprintf(range, "%d", p->minor_start);
-		switch (p->type) {
-		case TTY_DRIVER_TYPE_SYSTEM:
-			if (p->subtype == SYSTEM_TYPE_TTY)
-				type = "system:/dev/tty";
-			else if (p->subtype == SYSTEM_TYPE_SYSCONS)
-				type = "system:console";
-			else if (p->subtype == SYSTEM_TYPE_CONSOLE)
-				type = "system:vtmaster";
-			else
-				type = "system";
-			break;
-		case TTY_DRIVER_TYPE_CONSOLE:
-			type = "console";
-			break;
-		case TTY_DRIVER_TYPE_SERIAL:
-			if (p->subtype == 2)
-				type = "serial:callout";
+	list_for_each_entry(m, &tty_majors, list) {
+		list_for_each_entry(p, &m->drivers, tty_drivers) {
+			if (p->num > 1)
+				sprintf(range, "%d-%d", p->minor_start,
+					p->minor_start + p->num - 1);
 			else
-				type = "serial";
-			break;
-		case TTY_DRIVER_TYPE_PTY:
-			if (p->subtype == PTY_TYPE_MASTER)
-				type = "pty:master";
-			else if (p->subtype == PTY_TYPE_SLAVE)
-				type = "pty:slave";
-			else
-				type = "pty";
-			break;
-		default:
-			sprintf(deftype, "type:%d.%d", p->type, p->subtype);
-			type = deftype;
-			break;
-		}
-		len += sprintf(page+len, "%-20s /dev/%-8s %3d %7s %s\n",
-			       p->driver_name ? p->driver_name : "unknown",
-			       p->name, p->major, range, type);
-		if (len+begin > off+count)
-			break;
-		if (len+begin < off) {
-			begin += len;
-			len = 0;
+				sprintf(range, "%d", p->minor_start);
+			switch (p->type) {
+			case TTY_DRIVER_TYPE_SYSTEM:
+				if (p->subtype == SYSTEM_TYPE_TTY)
+					type = "system:/dev/tty";
+				else if (p->subtype == SYSTEM_TYPE_SYSCONS)
+					type = "system:console";
+				else if (p->subtype == SYSTEM_TYPE_CONSOLE)
+					type = "system:vtmaster";
+				else
+					type = "system";
+				break;
+			case TTY_DRIVER_TYPE_CONSOLE:
+				type = "console";
+				break;
+			case TTY_DRIVER_TYPE_SERIAL:
+				if (p->subtype == 2)
+					type = "serial:callout";
+				else
+					type = "serial";
+				break;
+			case TTY_DRIVER_TYPE_PTY:
+				if (p->subtype == PTY_TYPE_MASTER)
+					type = "pty:master";
+				else if (p->subtype == PTY_TYPE_SLAVE)
+					type = "pty:slave";
+				else
+					type = "pty";
+				break;
+			default:
+				sprintf(deftype, "type:%d.%d", p->type, p->subtype);
+				type = deftype;
+				break;
+			}
+			len += sprintf(page+len, "%-20s /dev/%-8s %3d %7s %s\n",
+				       p->driver_name ? p->driver_name : "unknown",
+				       p->name, p->major, range, type);
+			if (len+begin > off+count)
+				goto done;
+			if (len+begin < off) {
+				begin += len;
+				len = 0;
+			}
 		}
 	}
-	if (!p)
-		*eof = 1;
+	*eof = 1;
+done:
 	if (off >= len+begin)
 		return 0;
 	*start = page + (off-begin);
diff -ur linux-2.5.67/include/asm-i386/posix_types.h linux-2.5.67-cdev5/include/asm-i386/posix_types.h
--- linux-2.5.67/include/asm-i386/posix_types.h	2003-02-28 22:25:03.000000000 +0100
+++ linux-2.5.67-cdev5/include/asm-i386/posix_types.h	2003-04-14 20:41:32.000000000 +0200
@@ -7,7 +7,7 @@
  * assume GCC is being used.
  */
 
-typedef unsigned short	__kernel_dev_t;
+typedef unsigned long	__kernel_dev_t;
 typedef unsigned long	__kernel_ino_t;
 typedef unsigned short	__kernel_mode_t;
 typedef unsigned short	__kernel_nlink_t;
diff -ur linux-2.5.67/include/linux/fs.h linux-2.5.67-cdev5/include/linux/fs.h
--- linux-2.5.67/include/linux/fs.h	2003-04-11 20:11:24.000000000 +0200
+++ linux-2.5.67-cdev5/include/linux/fs.h	2003-04-14 20:41:32.000000000 +0200
@@ -331,6 +331,17 @@
 	struct address_space	*assoc_mapping;	/* ditto */
 };
 
+struct char_device {
+	struct list_head	cd_hash;
+	struct list_head	cd_list;
+	struct file_operations *cd_fops;
+	const char *		cd_name;
+	atomic_t		cd_count;
+	dev_t			cd_dev;
+	struct semaphore	cd_sem;
+	void *			cd_data;
+};
+
 struct block_device {
 	struct list_head	bd_hash;
 	atomic_t		bd_count;
@@ -382,6 +393,7 @@
 	struct list_head	i_devices;
 	struct pipe_inode_info	*i_pipe;
 	struct block_device	*i_bdev;
+	struct char_device	*i_cdev;
 
 	unsigned long		i_dnotify_mask; /* Directory notify events */
 	struct dnotify_struct	*i_dnotify; /* for directory notifications */
@@ -1055,14 +1067,17 @@
 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 register_chrdev(unsigned int, const 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 int chrdev_open(struct inode *, struct file *);
+extern struct char_device *cdget(dev_t);
+extern void cdput(struct char_device *);
+extern struct char_device *alloc_chrdev(dev_t);
+extern int add_chrdev(struct char_device *, struct file_operations *);
+extern void unlink_chrdev(struct char_device *);
+extern void del_chrdev(struct char_device *);
+
+#define cdget_major(maj)	cdget(MKDEV(0, maj))
 
 /* fs/block_dev.c */
 #define BDEVNAME_SIZE	32	/* Largest string for a blockdev identifier */
diff -ur linux-2.5.67/include/linux/genhd.h linux-2.5.67-cdev5/include/linux/genhd.h
--- linux-2.5.67/include/linux/genhd.h	2003-03-19 02:17:32.000000000 +0100
+++ linux-2.5.67-cdev5/include/linux/genhd.h	2003-04-14 20:41:32.000000000 +0200
@@ -71,6 +71,7 @@
 #define GENHD_FL_DEVFS	4
 #define GENHD_FL_CD	8
 #define GENHD_FL_UP	16
+#define GENHD_FL_DYNAMIC 32
 
 struct disk_stats {
 	unsigned read_sectors, write_sectors;
@@ -190,7 +191,7 @@
 extern void disk_round_stats(struct gendisk *disk);
 
 /* drivers/block/genhd.c */
-extern void add_disk(struct gendisk *disk);
+extern int add_disk(struct gendisk *disk);
 extern void del_gendisk(struct gendisk *gp);
 extern void unlink_gendisk(struct gendisk *gp);
 extern struct gendisk *get_gendisk(dev_t dev, int *part);
diff -ur linux-2.5.67/include/linux/kdev_t.h linux-2.5.67-cdev5/include/linux/kdev_t.h
--- linux-2.5.67/include/linux/kdev_t.h	2003-04-11 20:11:25.000000000 +0200
+++ linux-2.5.67-cdev5/include/linux/kdev_t.h	2003-04-14 20:41:32.000000000 +0200
@@ -70,7 +70,7 @@
  * static arrays, and they are sized for a 8-bit index.
  */
 typedef struct {
-	unsigned short value;
+	unsigned long value;
 } kdev_t;
 
 #define KDEV_MINOR_BITS		8
@@ -110,7 +110,7 @@
 
 /* Mask off the high bits for now.. */
 #define minor(dev)	((dev).value & 0xff)
-#define major(dev)	(((dev).value >> KDEV_MINOR_BITS) & 0xff)
+#define major(dev)	((dev).value >> KDEV_MINOR_BITS)
 
 /* These are for user-level "dev_t" */
 #define MINORBITS	8
diff -ur linux-2.5.67/include/linux/major.h linux-2.5.67-cdev5/include/linux/major.h
--- linux-2.5.67/include/linux/major.h	2003-04-04 19:32:23.000000000 +0200
+++ linux-2.5.67-cdev5/include/linux/major.h	2003-04-14 20:41:32.000000000 +0200
@@ -160,6 +160,13 @@
 #define IBM_FS3270_MAJOR	228
 
 /*
+ * Important: Don't change this to 256.  Major number 255 is and must be
+ * reserved for future expansion into a larger dev_t space.
+ */
+#define MAX_CHRDEV		255
+#define MAX_BLKDEV		255
+
+/*
  * Tests for SCSI devices.
  */
 
diff -ur linux-2.5.67/include/linux/tty_driver.h linux-2.5.67-cdev5/include/linux/tty_driver.h
--- linux-2.5.67/include/linux/tty_driver.h	2003-02-16 02:18:32.000000000 +0100
+++ linux-2.5.67-cdev5/include/linux/tty_driver.h	2003-04-14 20:41:32.000000000 +0200
@@ -175,7 +175,13 @@
 	struct list_head tty_drivers;
 };
 
-extern struct list_head tty_drivers;
+struct tty_major {
+	struct list_head list;
+	struct list_head drivers;
+};
+
+extern struct list_head tty_majors;
+extern struct tty_ldisc ldiscs[];
 
 /* tty driver magic number */
 #define TTY_DRIVER_MAGIC		0x5402
diff -ur linux-2.5.67/include/linux/usb.h linux-2.5.67-cdev5/include/linux/usb.h
--- linux-2.5.67/include/linux/usb.h	2003-03-19 02:17:35.000000000 +0100
+++ linux-2.5.67-cdev5/include/linux/usb.h	2003-04-14 20:41:32.000000000 +0200
@@ -440,8 +440,8 @@
 extern int usb_register(struct usb_driver *);
 extern void usb_deregister(struct usb_driver *);
 
-extern int usb_register_dev(struct file_operations *fops, int minor, int num_minors, int *start_minor);
-extern void usb_deregister_dev(int num_minors, int start_minor);
+extern int usb_register_dev(struct file_operations *fops, int minor, int *start_minor);
+extern void usb_deregister_dev(int minor);
 
 extern int usb_device_probe(struct device *dev);
 extern int usb_device_remove(struct device *dev);
diff -ur linux-2.5.67/kernel/ksyms.c linux-2.5.67-cdev5/kernel/ksyms.c
--- linux-2.5.67/kernel/ksyms.c	2003-04-11 20:11:34.000000000 +0200
+++ linux-2.5.67-cdev5/kernel/ksyms.c	2003-04-14 20:41:32.000000000 +0200
@@ -202,6 +202,8 @@
 EXPORT_SYMBOL(set_blocksize);
 EXPORT_SYMBOL(sb_set_blocksize);
 EXPORT_SYMBOL(sb_min_blocksize);
+EXPORT_SYMBOL(cdget);
+EXPORT_SYMBOL(cdput);
 EXPORT_SYMBOL(bdget);
 EXPORT_SYMBOL(bdput);
 EXPORT_SYMBOL(bd_claim);
