## Automatically generated incremental diff
## From:   linux-2.5.2-pre5
## To:     linux-2.5.2-pre6
## Robot:  $Id: make-incremental-diff,v 1.9 2001/12/10 00:06:56 hpa Exp $

diff -urN linux-2.5.2-pre5/Makefile linux/Makefile
--- linux-2.5.2-pre5/Makefile	Tue Jan  1 14:04:24 2002
+++ linux/Makefile	Tue Jan  1 14:04:27 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 2
-EXTRAVERSION =-pre5
+EXTRAVERSION =-pre6
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.5.2-pre5/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c
--- linux-2.5.2-pre5/arch/cris/drivers/usb-host.c	Mon Oct  8 11:43:54 2001
+++ linux/arch/cris/drivers/usb-host.c	Tue Jan  1 14:04:27 2002
@@ -196,7 +196,7 @@
 static kmem_cache_t *usb_desc_cache;
 static struct usb_bus *etrax_usb_bus;
 
-static void dump_urb (purb_t purb);
+static void dump_urb (struct urb *urb);
 static void init_rx_buffers(void);
 static int etrax_rh_unlink_urb (urb_t *urb);
 static void etrax_rh_send_irq(urb_t *urb);
@@ -240,24 +240,24 @@
 };
 
 #ifdef USB_DEBUG_DESC
-static void dump_urb(purb_t purb)
+static void dump_urb(struct urb *urb)
 {
-	printk("\nurb                   :0x%08X\n", purb);
-	printk("next                  :0x%08X\n", purb->next);
-	printk("dev                   :0x%08X\n", purb->dev);
-	printk("pipe                  :0x%08X\n", purb->pipe);
-	printk("status                :%d\n", purb->status);
-	printk("transfer_flags        :0x%08X\n", purb->transfer_flags);
-	printk("transfer_buffer       :0x%08X\n", purb->transfer_buffer);
-	printk("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk("actual_length         :%d\n", purb->actual_length);
-	printk("setup_packet          :0x%08X\n", purb->setup_packet);
-	printk("start_frame           :%d\n", purb->start_frame);
-	printk("number_of_packets     :%d\n", purb->number_of_packets);
-	printk("interval              :%d\n", purb->interval);
-	printk("error_count           :%d\n", purb->error_count);
-	printk("context               :0x%08X\n", purb->context);
-	printk("complete              :0x%08X\n\n", purb->complete);
+	printk("\nurb                   :0x%08X\n", urb);
+	printk("next                  :0x%08X\n", urb->next);
+	printk("dev                   :0x%08X\n", urb->dev);
+	printk("pipe                  :0x%08X\n", urb->pipe);
+	printk("status                :%d\n", urb->status);
+	printk("transfer_flags        :0x%08X\n", urb->transfer_flags);
+	printk("transfer_buffer       :0x%08X\n", urb->transfer_buffer);
+	printk("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+	printk("actual_length         :%d\n", urb->actual_length);
+	printk("setup_packet          :0x%08X\n", urb->setup_packet);
+	printk("start_frame           :%d\n", urb->start_frame);
+	printk("number_of_packets     :%d\n", urb->number_of_packets);
+	printk("interval              :%d\n", urb->interval);
+	printk("error_count           :%d\n", urb->error_count);
+	printk("context               :0x%08X\n", urb->context);
+	printk("complete              :0x%08X\n\n", urb->complete);
 }
 
 static void dump_in_desc(USB_IN_Desc_t *in)
diff -urN linux-2.5.2-pre5/arch/i386/defconfig linux/arch/i386/defconfig
--- linux-2.5.2-pre5/arch/i386/defconfig	Sat Dec  8 20:30:25 2001
+++ linux/arch/i386/defconfig	Tue Jan  1 14:04:27 2002
@@ -409,6 +409,7 @@
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
+# CONFIG_DE2104X is not set
 # CONFIG_TULIP is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DGRS is not set
@@ -624,7 +625,7 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 CONFIG_TMPFS=y
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
diff -urN linux-2.5.2-pre5/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c
--- linux-2.5.2-pre5/drivers/acorn/block/mfmhd.c	Thu Oct 25 13:58:35 2001
+++ linux/drivers/acorn/block/mfmhd.c	Tue Jan  1 14:04:27 2002
@@ -1311,10 +1311,8 @@
 	major:		MAJOR_NR,
 	major_name:	"mfm",
 	minor_shift:	6,
-	max_p:		1 << 6,
 	part:		mfm,
 	sizes:		mfm_sizes,
-	real_devices:	(void *)mfm_info,
 };
 
 static struct block_device_operations mfm_fops =
@@ -1473,7 +1471,7 @@
 	mfm_info[target].busy = 1;
 	restore_flags (flags);
 
-	maxp = mfm_gendisk.max_p;
+	maxp = 1 << mfm_gendisk.minor_shift;
 	start = target << mfm_gendisk.minor_shift;
 
 	for (i = maxp - 1; i >= 0; i--) {
diff -urN linux-2.5.2-pre5/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- linux-2.5.2-pre5/drivers/block/DAC960.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/block/DAC960.c	Tue Jan  1 14:04:27 2002
@@ -1973,9 +1973,7 @@
   Controller->GenericDiskInfo.major = MajorNumber;
   Controller->GenericDiskInfo.major_name = "rd";
   Controller->GenericDiskInfo.minor_shift = DAC960_MaxPartitionsBits;
-  Controller->GenericDiskInfo.max_p = DAC960_MaxPartitions;
   Controller->GenericDiskInfo.nr_real = DAC960_MaxLogicalDrives;
-  Controller->GenericDiskInfo.real_devices = Controller;
   Controller->GenericDiskInfo.next = NULL;
   Controller->GenericDiskInfo.fops = &DAC960_BlockDeviceOperations;
   /*
@@ -2024,10 +2022,9 @@
   Information Partition Sector Counts and Block Sizes.
 */
 
-static void DAC960_ComputeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
+static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller)
 {
-  DAC960_Controller_T *Controller =
-    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
+  GenericDiskInfo_T *GenericDiskInfo = &Controller->GenericDiskInfo;
   int LogicalDriveNumber, i;
   for (LogicalDriveNumber = 0;
        LogicalDriveNumber < DAC960_MaxLogicalDrives;
@@ -2658,7 +2655,7 @@
       int LogicalDriveNumber;
       if (Controller == NULL) continue;
       DAC960_InitializeController(Controller);
-      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+      DAC960_ComputeGenericDiskInfo(Controller);
       for (LogicalDriveNumber = 0;
 	   LogicalDriveNumber < DAC960_MaxLogicalDrives;
 	   LogicalDriveNumber++)
@@ -3161,7 +3158,7 @@
 				Controller->ControllerNumber,
 				LogicalDriveNumber);
 	      Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
-	      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+	      DAC960_ComputeGenericDiskInfo(Controller);
 	    }
 	  if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount)
 	    {
@@ -3173,7 +3170,7 @@
 				Controller->ControllerNumber,
 				LogicalDriveNumber);
 	      Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
-	      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+	      DAC960_ComputeGenericDiskInfo(Controller);
 	    }
 	  if (NewEnquiry->StatusFlags.DeferredWriteError !=
 	      OldEnquiry->StatusFlags.DeferredWriteError)
@@ -4513,7 +4510,7 @@
 		{
 		  memset(LogicalDeviceInfo, 0,
 			 sizeof(DAC960_V2_LogicalDeviceInfo_T));
-		  DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+		  DAC960_ComputeGenericDiskInfo(Controller);
 		}
 	    }
 	  if (LogicalDeviceInfo != NULL)
@@ -4630,7 +4627,7 @@
 	      kfree(LogicalDeviceInfo);
 	      Controller->LogicalDriveInitiallyAccessible
 			  [LogicalDriveNumber] = false;
-	      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+	      DAC960_ComputeGenericDiskInfo(Controller);
 	    }
 	  Controller->V2.NeedLogicalDeviceInformation = false;
 	}
@@ -5299,7 +5296,7 @@
   if (!Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber])
     {
       Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
-      DAC960_ComputeGenericDiskInfo(&Controller->GenericDiskInfo);
+      DAC960_ComputeGenericDiskInfo(Controller);
       DAC960_RegisterDisk(Controller, LogicalDriveNumber);
     }
   if (Controller->GenericDiskInfo.sizes[MINOR(Inode->i_rdev)] == 0)
diff -urN linux-2.5.2-pre5/drivers/block/acsi.c linux/drivers/block/acsi.c
--- linux-2.5.2-pre5/drivers/block/acsi.c	Sun Dec 16 12:20:20 2001
+++ linux/drivers/block/acsi.c	Tue Jan  1 14:04:27 2002
@@ -1386,10 +1386,8 @@
 	major:		MAJOR_NR,
 	major_name:	"ad",
 	minor_shift:	4,
-	max_p:		1 << 4,
 	part:		acsi_part,
 	sizes:		acsi_sizes,
-	real_devices:	(void *)acsi_info,
 	fops:		&acsi_fops,
 };
 	
diff -urN linux-2.5.2-pre5/drivers/block/blkpg.c linux/drivers/block/blkpg.c
--- linux-2.5.2-pre5/drivers/block/blkpg.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/block/blkpg.c	Tue Jan  1 14:04:27 2002
@@ -85,14 +85,16 @@
 		return -ENXIO;
 
 	/* existing drive? */
-	drive = (MINOR(dev) >> g->minor_shift);
+	drive = (minor(dev) >> g->minor_shift);
 	first_minor = (drive << g->minor_shift);
-	end_minor   = first_minor + g->max_p;
+	end_minor   = first_minor + (1 << g->minor_shift);
 	if (drive >= g->nr_real)
 		return -ENXIO;
 
 	/* drive and partition number OK? */
-	if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
+	if (first_minor != minor(dev))
+		return -EINVAL;
+	if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
 		return -EINVAL;
 
 	/* partition number in use? */
@@ -136,10 +138,13 @@
 		return -ENXIO;
 
 	/* drive and partition number OK? */
-	drive = (MINOR(dev) >> g->minor_shift);
+	drive = (minor(dev) >> g->minor_shift);
 	first_minor = (drive << g->minor_shift);
-	if (first_minor != MINOR(dev) || p->pno <= 0 || p->pno >= g->max_p)
+
+	if (first_minor != minor(dev))
 		return -EINVAL;
+	if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
+  		return -EINVAL;
 
 	/* existing drive and partition? */
 	minor = first_minor + p->pno;
@@ -147,7 +152,7 @@
 		return -ENXIO;
 
 	/* partition in use? Incomplete check for now. */
-	devp = MKDEV(MAJOR(dev), minor);
+	devp = mk_kdev(major(dev), minor);
 	if (is_mounted(devp) || is_swap_partition(devp))
 		return -EBUSY;
 
@@ -203,7 +208,7 @@
 	int intval, *iptr;
 	unsigned short usval;
 
-	if (!dev)
+	if (kdev_none(dev))
 		return -EINVAL;
 
 	intval = block_ioctl(dev, cmd, arg);
@@ -227,25 +232,25 @@
 				return -EACCES;
 			if(arg > 0xff)
 				return -EINVAL;
-			read_ahead[MAJOR(dev)] = arg;
+			read_ahead[major(dev)] = arg;
 			return 0;
 		case BLKRAGET:
 			if (!arg)
 				return -EINVAL;
-			return put_user(read_ahead[MAJOR(dev)], (long *) arg);
+			return put_user(read_ahead[major(dev)], (long *) arg);
 
 		case BLKFRASET:
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
-			if (!(iptr = max_readahead[MAJOR(dev)]))
+			if (!(iptr = max_readahead[major(dev)]))
 				return -EINVAL;
-			iptr[MINOR(dev)] = arg;
+			iptr[minor(dev)] = arg;
 			return 0;
 
 		case BLKFRAGET:
-			if (!(iptr = max_readahead[MAJOR(dev)]))
+			if (!(iptr = max_readahead[major(dev)]))
 				return -EINVAL;
-			return put_user(iptr[MINOR(dev)], (long *) arg);
+			return put_user(iptr[minor(dev)], (long *) arg);
 
 		case BLKSECTGET:
 			if ((q = blk_get_queue(dev)) == NULL)
@@ -271,7 +276,7 @@
 		case BLKGETSIZE64:
 			g = get_gendisk(dev);
 			if (g)
-				ullval = g->part[MINOR(dev)].nr_sects;
+				ullval = g->part[minor(dev)].nr_sects;
 
 			if (cmd == BLKGETSIZE)
 				return put_user((unsigned long)ullval, (unsigned long *)arg);
diff -urN linux-2.5.2-pre5/drivers/block/cciss.c linux/drivers/block/cciss.c
--- linux-2.5.2-pre5/drivers/block/cciss.c	Sun Dec 16 12:20:20 2001
+++ linux/drivers/block/cciss.c	Tue Jan  1 14:04:27 2002
@@ -1886,7 +1886,6 @@
 	hba[i]->gendisk.major = MAJOR_NR + i;
 	hba[i]->gendisk.major_name = "cciss";
 	hba[i]->gendisk.minor_shift = NWD_SHIFT;
-	hba[i]->gendisk.max_p = MAX_PART;
 	hba[i]->gendisk.part = hba[i]->hd;
 	hba[i]->gendisk.sizes = hba[i]->sizes;
 	hba[i]->gendisk.nr_real = hba[i]->num_luns;
diff -urN linux-2.5.2-pre5/drivers/block/cciss.h linux/drivers/block/cciss.h
--- linux-2.5.2-pre5/drivers/block/cciss.h	Wed Dec 12 13:41:03 2001
+++ linux/drivers/block/cciss.h	Tue Jan  1 14:04:27 2002
@@ -8,7 +8,7 @@
 
 #define NWD		16
 #define NWD_SHIFT	4
-#define MAX_PART	16
+#define MAX_PART	(1 << NWD_SHIFT)
 
 #define IO_OK		0
 #define IO_ERROR	1
diff -urN linux-2.5.2-pre5/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- linux-2.5.2-pre5/drivers/block/cpqarray.c	Sun Dec 16 12:20:20 2001
+++ linux/drivers/block/cpqarray.c	Tue Jan  1 14:04:27 2002
@@ -483,7 +483,6 @@
 		ida_gendisk[i].major = MAJOR_NR + i;
 		ida_gendisk[i].major_name = "ida";
 		ida_gendisk[i].minor_shift = NWD_SHIFT;
-		ida_gendisk[i].max_p = 16;
 		ida_gendisk[i].part = ida + (i*256);
 		ida_gendisk[i].sizes = ida_sizes + (i*256);
 		ida_gendisk[i].nr_real = 0; 
diff -urN linux-2.5.2-pre5/drivers/block/elevator.c linux/drivers/block/elevator.c
--- linux-2.5.2-pre5/drivers/block/elevator.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/block/elevator.c	Tue Jan  1 14:04:27 2002
@@ -70,7 +70,7 @@
 	 * if the device is different (not a normal case) just check if
 	 * bio is after rq
 	 */
-	if (next_rq->rq_dev != rq->rq_dev)
+	if (!kdev_same(next_rq->rq_dev, rq->rq_dev))
 		return bio->bi_sector > rq->sector;
 
 	/*
@@ -113,7 +113,7 @@
 	/*
 	 * same device and no special stuff set, merge is ok
 	 */
-	if (rq->rq_dev == bio->bi_dev && !rq->waiting && !rq->special)
+	if (kdev_same(rq->rq_dev, bio->bi_dev) && !rq->waiting && !rq->special)
 		return 1;
 
 	return 0;
diff -urN linux-2.5.2-pre5/drivers/block/floppy.c linux/drivers/block/floppy.c
--- linux-2.5.2-pre5/drivers/block/floppy.c	Sun Dec 16 12:23:05 2001
+++ linux/drivers/block/floppy.c	Tue Jan  1 14:04:27 2002
@@ -270,10 +270,10 @@
 static int initialising=1;
 
 static inline int TYPE(kdev_t x) {
-	return  (MINOR(x)>>2) & 0x1f;
+	return  (minor(x)>>2) & 0x1f;
 }
 static inline int DRIVE(kdev_t x) {
-	return (MINOR(x)&0x03) | ((MINOR(x)&0x80) >> 5);
+	return (minor(x)&0x03) | ((minor(x)&0x80) >> 5);
 }
 #define ITYPE(x) (((x)>>2) & 0x1f)
 #define TOMINOR(x) ((x & 3) | ((x & 4) << 5))
@@ -2906,7 +2906,7 @@
 			unlock_fdc();
 			return;
 		}
-		if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+		if (major(CURRENT->rq_dev) != MAJOR_NR)
 			panic(DEVICE_NAME ": request list destroyed");
 
 		device = CURRENT->rq_dev;
@@ -3332,7 +3332,7 @@
 			if (ITYPE(drive_state[cnt].fd_device) == type &&
 			    drive_state[cnt].fd_ref)
 				check_disk_change(
-					MKDEV(FLOPPY_MAJOR,
+					mk_kdev(FLOPPY_MAJOR,
 					      drive_state[cnt].fd_device));
 		}
 	} else {
@@ -3717,7 +3717,7 @@
 	if (TYPE(inode->i_rdev) >= NUMBER(floppy_type))
 		return -ENXIO;
 	old_dev = UDRS->fd_device;
-	if (UDRS->fd_ref && old_dev != MINOR(inode->i_rdev))
+	if (UDRS->fd_ref && old_dev != minor(inode->i_rdev))
 		return -EBUSY;
 
 	if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){
@@ -3768,11 +3768,11 @@
 		}
 	}
 
-	UDRS->fd_device = MINOR(inode->i_rdev);
-	if (old_dev != -1 && old_dev != MINOR(inode->i_rdev)) {
+	UDRS->fd_device = minor(inode->i_rdev);
+	if (old_dev != -1 && old_dev != minor(inode->i_rdev)) {
 		if (buffer_drive == drive)
 			buffer_track = -1;
-		invalidate_buffers(MKDEV(FLOPPY_MAJOR,old_dev));
+		invalidate_buffers(mk_kdev(FLOPPY_MAJOR,old_dev));
 	}
 
 	/* Allow ioctls if we have write-permissions even if read-only open.
@@ -3806,7 +3806,7 @@
 {
 	int drive = DRIVE(dev);
 
-	if (MAJOR(dev) != MAJOR_NR) {
+	if (major(dev) != MAJOR_NR) {
 		DPRINT("check_floppy_change: not a floppy\n");
 		return 0;
 	}
@@ -3868,7 +3868,7 @@
 			UDRS->generation++;
 		if (NO_GEOM){
 			/* auto-sensing */
-			int size = floppy_blocksizes[MINOR(dev)];
+			int size = floppy_blocksizes[minor(dev)];
 			if (!size)
 				size = 1024;
 			if (!(bh = getblk(dev,0,size))){
@@ -4275,7 +4275,7 @@
 		if (fdc_state[FDC(drive)].version == FDC_NONE)
 			continue;
 		for (i = 0; i<NUMBER(floppy_type); i++)
-			register_disk(NULL, MKDEV(MAJOR_NR,TOMINOR(drive)+i*4),
+			register_disk(NULL, mk_kdev(MAJOR_NR,TOMINOR(drive)+i*4),
 					1, &floppy_fops, 0);
 	}
 	return have_no_fdc;
diff -urN linux-2.5.2-pre5/drivers/block/genhd.c linux/drivers/block/genhd.c
--- linux-2.5.2-pre5/drivers/block/genhd.c	Sat Dec  8 09:49:52 2001
+++ linux/drivers/block/genhd.c	Tue Jan  1 14:04:27 2002
@@ -103,7 +103,7 @@
 get_gendisk(kdev_t dev)
 {
 	struct gendisk *gp = NULL;
-	int maj = MAJOR(dev);
+	int maj = major(dev);
 
 	read_lock(&gendisk_lock);
 	for (gp = gendisk_head; gp; gp = gp->next)
@@ -124,7 +124,7 @@
 
 	gp = get_gendisk(dev);
 	if (gp)
-		return gp->part[MINOR(dev)].start_sect;
+		return gp->part[minor(dev)].start_sect;
 	return 0;
 }
 
@@ -137,7 +137,7 @@
 
 	gp = get_gendisk(dev);
 	if (gp)
-		return gp->part[MINOR(dev)].nr_sects;
+		return gp->part[minor(dev)].nr_sects;
 	return 0;
 }
 
diff -urN linux-2.5.2-pre5/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- linux-2.5.2-pre5/drivers/block/ll_rw_blk.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/block/ll_rw_blk.c	Tue Jan  1 14:04:27 2002
@@ -109,12 +109,12 @@
  **/
 inline request_queue_t *blk_get_queue(kdev_t dev)
 {
-	struct blk_dev_struct *bdev = blk_dev + MAJOR(dev);
+	struct blk_dev_struct *bdev = blk_dev + major(dev);
 
 	if (bdev->queue)
 		return bdev->queue(dev);
 	else
-		return &blk_dev[MAJOR(dev)].request_queue;
+		return &blk_dev[major(dev)].request_queue;
 }
 
 void blk_queue_prep_rq(request_queue_t *q, prep_rq_fn *pfn)
@@ -309,7 +309,7 @@
 {
 	int bit;
 
-	printk("%s: dev %x: ", msg, rq->rq_dev);
+	printk("%s: dev %02x:%02x: ", msg, major(rq->rq_dev), minor(rq->rq_dev));
 	bit = 0;
 	do {
 		if (rq->flags & (1 << bit))
@@ -910,8 +910,8 @@
 {
 	int minor,major;
 
-	major = MAJOR(dev);
-	minor = MINOR(dev);
+	major = major(dev);
+	minor = minor(dev);
 	if (major < 0 || major >= MAX_BLKDEV) return 0;
 	return ro_bits[major][minor >> 5] & (1 << (minor & 31));
 }
@@ -920,8 +920,8 @@
 {
 	int minor,major;
 
-	major = MAJOR(dev);
-	minor = MINOR(dev);
+	major = major(dev);
+	minor = minor(dev);
 	if (major < 0 || major >= MAX_BLKDEV) return;
 	if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31);
 	else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31));
@@ -929,7 +929,7 @@
 
 void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
 {
-	unsigned int major = MAJOR(rq->rq_dev);
+	unsigned int major = major(rq->rq_dev);
 	int rw = rq_data_dir(rq);
 	unsigned int index;
 
@@ -1016,7 +1016,7 @@
 		return;
 
 	if (rq_data_dir(req) != rq_data_dir(next)
-	    || req->rq_dev != next->rq_dev
+	    || !kdev_same(req->rq_dev, next->rq_dev)
 	    || req->nr_sectors + next->nr_sectors > q->max_sectors
 	    || next->waiting || next->special)
 		return;
@@ -1245,14 +1245,14 @@
 	struct gendisk *g;
 	kdev_t dev0;
 
-	major = MAJOR(bio->bi_dev);
+	major = major(bio->bi_dev);
 	if ((g = get_gendisk(bio->bi_dev))) {
-		minor = MINOR(bio->bi_dev);
+		minor = minor(bio->bi_dev);
 		drive = (minor >> g->minor_shift);
 		minor0 = (drive << g->minor_shift); /* whole disk device */
 		/* that is, minor0 = (minor & ~((1<<g->minor_shift)-1)); */
-		dev0 = MKDEV(major, minor0);
-		if (dev0 != bio->bi_dev) {
+		dev0 = mk_kdev(major, minor0);
+		if (!kdev_same(dev0, bio->bi_dev)) {
 			bio->bi_dev = dev0;
 			bio->bi_sector += g->part[minor].start_sect;
 		}
@@ -1287,8 +1287,8 @@
  * */
 void generic_make_request(struct bio *bio)
 {
-	int major = MAJOR(bio->bi_dev);
-	int minor = MINOR(bio->bi_dev);
+	int major = major(bio->bi_dev);
+	int minor = minor(bio->bi_dev);
 	request_queue_t *q;
 	sector_t minorsize = 0;
 	int ret, nr_sectors = bio_sectors(bio);
@@ -1477,7 +1477,7 @@
 	if (!nr)
 		return;
 
-	major = MAJOR(bhs[0]->b_dev);
+	major = major(bhs[0]->b_dev);
 
 	/* Determine correct block size for this device. */
 	correct_size = get_hardsect_size(bhs[0]->b_dev);
diff -urN linux-2.5.2-pre5/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- linux-2.5.2-pre5/drivers/block/paride/pd.c	Sun Dec 16 15:38:31 2001
+++ linux/drivers/block/paride/pd.c	Tue Jan  1 14:04:27 2002
@@ -347,7 +347,6 @@
 	major:		PD_MAJOR,
 	major_name:	PD_NAME,
 	minor_shift:	PD_BITS,
-	max_p:		PD_PARTNS,
 	part:		pd_hd,
 	sizes:		pd_sizes,
 	fops:		&pd_fops,
diff -urN linux-2.5.2-pre5/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- linux-2.5.2-pre5/drivers/block/ps2esdi.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/block/ps2esdi.c	Tue Jan  1 14:04:27 2002
@@ -160,10 +160,8 @@
 	major:		MAJOR_NR,
 	major_name:	"ed",
 	minor_shift:	6,
-	max_p:		1 << 6,
 	part:		ps2esdi,
 	sizes:		ps2esdi_sizes,
-	real_devices:	(void *)ps2esdi_info,
 	fops:		&ps2esdi_fops,
 };
 
diff -urN linux-2.5.2-pre5/drivers/block/xd.c linux/drivers/block/xd.c
--- linux-2.5.2-pre5/drivers/block/xd.c	Sun Dec 16 12:20:20 2001
+++ linux/drivers/block/xd.c	Tue Jan  1 14:04:27 2002
@@ -130,10 +130,8 @@
 	major:		MAJOR_NR,
 	major_name:	"xd",
 	minor_shift:	6,
-	max_p:		1 << 6,
 	part:		xd_struct,
 	sizes:		xd_sizes,
-	real_devices:	(void *)xd_info,
 	fops:		&xd_fops,
 };
 
diff -urN linux-2.5.2-pre5/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- linux-2.5.2-pre5/drivers/cdrom/cdrom.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/cdrom/cdrom.c	Tue Jan  1 14:04:27 2002
@@ -337,7 +337,7 @@
 int register_cdrom(struct cdrom_device_info *cdi)
 {
 	static char banner_printed;
-	int major = MAJOR(cdi->dev);
+	int major = major(cdi->dev);
         struct cdrom_device_ops *cdo = cdi->ops;
         int *change_capability = (int *)&cdo->capability; /* hack */
 
@@ -408,7 +408,7 @@
 int unregister_cdrom(struct cdrom_device_info *unreg)
 {
 	struct cdrom_device_info *cdi, *prev;
-	int major = MAJOR(unreg->dev);
+	int major = major(unreg->dev);
 
 	cdinfo(CD_OPEN, "entering unregister_cdrom\n"); 
 
@@ -417,7 +417,7 @@
 
 	prev = NULL;
 	cdi = topCdromPtr;
-	while (cdi != NULL && cdi->dev != unreg->dev) {
+	while (cdi != NULL && !kdev_same(cdi->dev, unreg->dev)) {
 		prev = cdi;
 		cdi = cdi->next;
 	}
@@ -440,7 +440,7 @@
 	struct cdrom_device_info *cdi;
 
 	cdi = topCdromPtr;
-	while (cdi != NULL && cdi->dev != dev)
+	while (cdi != NULL && !kdev_same(cdi->dev, dev))
 		cdi = cdi->next;
 
 	return cdi;
diff -urN linux-2.5.2-pre5/drivers/char/agp/agpgart_fe.c linux/drivers/char/agp/agpgart_fe.c
--- linux-2.5.2-pre5/drivers/char/agp/agpgart_fe.c	Fri Nov 30 08:26:04 2001
+++ linux/drivers/char/agp/agpgart_fe.c	Tue Jan  1 14:04:27 2002
@@ -694,7 +694,7 @@
 
 static int agp_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	agp_file_private *priv;
 	agp_client *client;
 	int rc = -ENXIO;
diff -urN linux-2.5.2-pre5/drivers/char/console.c linux/drivers/char/console.c
--- linux-2.5.2-pre5/drivers/char/console.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/char/console.c	Tue Jan  1 14:04:27 2002
@@ -2171,7 +2171,7 @@
 
 static kdev_t vt_console_device(struct console *c)
 {
-	return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
+	return mk_kdev(TTY_MAJOR, c->index ? c->index : fg_console + 1);
 }
 
 struct console vt_console_driver = {
@@ -2325,7 +2325,7 @@
 	int console_num;
 	if (!tty)
 		return;
-	console_num = MINOR(tty->device) - (tty->driver.minor_start);
+	console_num = minor(tty->device) - (tty->driver.minor_start);
 	if (!vc_cons_allocated(console_num))
 		return;
 	set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
@@ -2340,7 +2340,7 @@
 	int console_num;
 	if (!tty)
 		return;
-	console_num = MINOR(tty->device) - (tty->driver.minor_start);
+	console_num = minor(tty->device) - (tty->driver.minor_start);
 	if (!vc_cons_allocated(console_num))
 		return;
 	clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
@@ -2368,7 +2368,7 @@
 	unsigned int	currcons;
 	int i;
 
-	currcons = MINOR(tty->device) - tty->driver.minor_start;
+	currcons = minor(tty->device) - tty->driver.minor_start;
 
 	i = vc_allocate(currcons);
 	if (i)
@@ -2391,7 +2391,7 @@
 	if (!tty)
 		return;
 	if (tty->count != 1) return;
-	vcs_make_devfs (MINOR (tty->device) - tty->driver.minor_start, 1);
+	vcs_make_devfs (minor(tty->device) - tty->driver.minor_start, 1);
 	tty->driver_data = 0;
 }
 
diff -urN linux-2.5.2-pre5/drivers/char/drm/drm_drv.h linux/drivers/char/drm/drm_drv.h
--- linux-2.5.2-pre5/drivers/char/drm/drm_drv.h	Sun Oct 21 10:40:36 2001
+++ linux/drivers/char/drm/drm_drv.h	Tue Jan  1 14:04:27 2002
@@ -719,7 +719,7 @@
 	int i;
 
 	for (i = 0; i < DRM(numdevs); i++) {
-		if (MINOR(inode->i_rdev) == DRM(minor)[i]) {
+		if (minor(inode->i_rdev) == DRM(minor)[i]) {
 			dev = &(DRM(device)[i]);
 			break;
 		}
diff -urN linux-2.5.2-pre5/drivers/char/drm/drm_fops.h linux/drivers/char/drm/drm_fops.h
--- linux-2.5.2-pre5/drivers/char/drm/drm_fops.h	Sun Dec 16 15:43:58 2001
+++ linux/drivers/char/drm/drm_fops.h	Tue Jan  1 14:04:27 2002
@@ -38,7 +38,7 @@
 
 int DRM(open_helper)(struct inode *inode, struct file *filp, drm_device_t *dev)
 {
-	kdev_t	     minor = MINOR(inode->i_rdev);
+	int	     minor = minor(inode->i_rdev);
 	drm_file_t   *priv;
 
 	if (filp->f_flags & O_EXCL)   return -EBUSY; /* No exclusive opens */
diff -urN linux-2.5.2-pre5/drivers/char/drm/drm_stub.h linux/drivers/char/drm/drm_stub.h
--- linux-2.5.2-pre5/drivers/char/drm/drm_stub.h	Sun Dec 16 15:43:58 2001
+++ linux/drivers/char/drm/drm_stub.h	Tue Jan  1 14:04:27 2002
@@ -53,7 +53,7 @@
 
 static int DRM(stub_open)(struct inode *inode, struct file *filp)
 {
-	int                    minor = MINOR(inode->i_rdev);
+	int                    minor = minor(inode->i_rdev);
 	int                    err   = -ENODEV;
 	struct file_operations *old_fops;
 
diff -urN linux-2.5.2-pre5/drivers/char/mem.c linux/drivers/char/mem.c
--- linux-2.5.2-pre5/drivers/char/mem.c	Fri Sep 14 14:04:07 2001
+++ linux/drivers/char/mem.c	Tue Jan  1 14:04:27 2002
@@ -538,7 +538,7 @@
 
 static int memory_open(struct inode * inode, struct file * filp)
 {
-	switch (MINOR(inode->i_rdev)) {
+	switch (minor(inode->i_rdev)) {
 		case 1:
 			filp->f_op = &mem_fops;
 			break;
diff -urN linux-2.5.2-pre5/drivers/char/misc.c linux/drivers/char/misc.c
--- linux-2.5.2-pre5/drivers/char/misc.c	Fri Nov  2 17:46:47 2001
+++ linux/drivers/char/misc.c	Tue Jan  1 14:04:27 2002
@@ -104,7 +104,7 @@
 
 static int misc_open(struct inode * inode, struct file * file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct miscdevice *c;
 	int err = -ENODEV;
 	struct file_operations *old_fops, *new_fops = NULL;
diff -urN linux-2.5.2-pre5/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- linux-2.5.2-pre5/drivers/char/n_tty.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/char/n_tty.c	Tue Jan  1 14:04:28 2002
@@ -45,8 +45,8 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 
-#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
-#define SYSCONS_DEV  MKDEV(TTYAUX_MAJOR,1)
+#define IS_CONSOLE_DEV(dev)	(kdev_val(dev) == __mkdev(TTY_MAJOR,0))
+#define IS_SYSCONS_DEV(dev)	(kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -955,8 +955,8 @@
 	/* NOTE: not yet done after every sleep pending a thorough
 	   check of the logic of this change. -- jlc */
 	/* don't stop on /dev/console */
-	if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
-	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV &&
+	if (!IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) &&
+	    !IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev) &&
 	    current->tty == tty) {
 		if (tty->pgrp <= 0)
 			printk("read_chan: tty->pgrp <= 0!\n");
@@ -1135,8 +1135,8 @@
 
 	/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
 	if (L_TOSTOP(tty) && 
-	    file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
-	    file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {
+	    !IS_CONSOLE_DEV(file->f_dentry->d_inode->i_rdev) &&
+	    !IS_SYSCONS_DEV(file->f_dentry->d_inode->i_rdev)) {
 		retval = tty_check_change(tty);
 		if (retval)
 			return retval;
diff -urN linux-2.5.2-pre5/drivers/char/pty.c linux/drivers/char/pty.c
--- linux-2.5.2-pre5/drivers/char/pty.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/char/pty.c	Tue Jan  1 14:04:28 2002
@@ -88,14 +88,14 @@
 		set_bit(TTY_OTHER_CLOSED, &tty->flags);
 #ifdef CONFIG_UNIX98_PTYS
 		{
-			unsigned int major = MAJOR(tty->device) - UNIX98_PTY_MASTER_MAJOR;
+			unsigned int major = major(tty->device) - UNIX98_PTY_MASTER_MAJOR;
 			if ( major < UNIX98_NR_MAJORS ) {
-				devpts_pty_kill( MINOR(tty->device)
+				devpts_pty_kill( minor(tty->device)
 			  - tty->driver.minor_start + tty->driver.name_base );
 			}
 		}
 #endif
-		tty_unregister_devfs (&tty->link->driver, MINOR (tty->device));
+		tty_unregister_devfs (&tty->link->driver, minor(tty->device));
 		tty_vhangup(tty->link);
 	}
 }
@@ -239,7 +239,7 @@
 #ifdef CONFIG_UNIX98_PTYS
 static int pty_get_device_number(struct tty_struct *tty, unsigned int *value)
 {
-	unsigned int result = MINOR(tty->device)
+	unsigned int result = minor(tty->device)
 		- tty->driver.minor_start + tty->driver.name_base;
 	return put_user(result, value);
 }
@@ -314,7 +314,7 @@
 	retval = -ENODEV;
 	if (!tty || !tty->link)
 		goto out;
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= NR_PTYS))
 		goto out;
 	pty = (struct pty_struct *)(tty->driver.driver_state) + line;
@@ -336,7 +336,7 @@
 		tty_register_devfs(&tty->link->driver,
 				   DEVFS_FL_CURRENT_OWNER | DEVFS_FL_WAIT,
 				   tty->link->driver.minor_start +
-				   MINOR(tty->device)-tty->driver.minor_start);
+				   minor(tty->device)-tty->driver.minor_start);
 	retval = 0;
 out:
 	return retval;
diff -urN linux-2.5.2-pre5/drivers/char/raw.c linux/drivers/char/raw.c
--- linux-2.5.2-pre5/drivers/char/raw.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/char/raw.c	Tue Jan  1 14:04:28 2002
@@ -74,7 +74,7 @@
 	int sector_size;
 	int sector_bits;
 
-	minor = MINOR(inode->i_rdev);
+	minor = minor(inode->i_rdev);
 	
 	/* 
 	 * Is it the control device? 
@@ -134,7 +134,7 @@
 	int minor;
 	struct block_device *bdev;
 	
-	minor = MINOR(inode->i_rdev);
+	minor = minor(inode->i_rdev);
 	down(&raw_devices[minor].mutex);
 	bdev = raw_devices[minor].binding;
 	raw_devices[minor].inuse--;
@@ -192,8 +192,8 @@
 			 * major/minor numbers make sense. 
 			 */
 
-			if ((rq.block_major == NODEV && 
-			     rq.block_minor != NODEV) ||
+			if ((rq.block_major == 0 && 
+			     rq.block_minor != 0) ||
 			    rq.block_major > MAX_BLKDEV ||
 			    rq.block_minor > MINORMASK) {
 				err = -EINVAL;
@@ -209,7 +209,7 @@
 			if (raw_devices[minor].binding)
 				bdput(raw_devices[minor].binding);
 			raw_devices[minor].binding = 
-				bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor)));
+				bdget(kdev_t_to_nr(mk_kdev(rq.block_major, rq.block_minor)));
 			up(&raw_devices[minor].mutex);
 		} else {
 			struct block_device *bdev;
@@ -218,8 +218,8 @@
 			bdev = raw_devices[minor].binding;
 			if (bdev) {
 				dev = to_kdev_t(bdev->bd_dev);
-				rq.block_major = MAJOR(dev);
-				rq.block_minor = MINOR(dev);
+				rq.block_major = major(dev);
+				rq.block_minor = minor(dev);
 			} else {
 				rq.block_major = rq.block_minor = 0;
 			}
@@ -271,7 +271,7 @@
 	 * First, a few checks on device size limits 
 	 */
 
-	minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+	minor = minor(filp->f_dentry->d_inode->i_rdev);
 
 	new_iobuf = 0;
 	iobuf = filp->f_iobuf;
@@ -291,12 +291,12 @@
 	sector_bits = raw_devices[minor].sector_bits;
 	sector_mask = sector_size- 1;
 	
-	if (blk_size[MAJOR(dev)])
-		limit = (((loff_t) blk_size[MAJOR(dev)][MINOR(dev)]) << BLOCK_SIZE_BITS) >> sector_bits;
+	if (blk_size[major(dev)])
+		limit = (((loff_t) blk_size[major(dev)][minor(dev)]) << BLOCK_SIZE_BITS) >> sector_bits;
 	else
 		limit = INT_MAX;
 	dprintk ("rw_raw_dev: dev %d:%d (+%d)\n",
-		 MAJOR(dev), MINOR(dev), limit);
+		 major(dev), minor(dev), limit);
 	
 	err = -EINVAL;
 	if ((*offp & sector_mask) || (size & sector_mask))
diff -urN linux-2.5.2-pre5/drivers/char/serial.c linux/drivers/char/serial.c
--- linux-2.5.2-pre5/drivers/char/serial.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/char/serial.c	Tue Jan  1 14:04:28 2002
@@ -3141,7 +3141,7 @@
 	unsigned long		page;
 
 	MOD_INC_USE_COUNT;
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= NR_PORTS)) {
 		MOD_DEC_USE_COUNT;
 		return -ENODEV;
diff -urN linux-2.5.2-pre5/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- linux-2.5.2-pre5/drivers/char/tty_io.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/char/tty_io.c	Tue Jan  1 14:04:28 2002
@@ -102,10 +102,10 @@
 
 #include <linux/kmod.h>
 
-#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
-#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
-#define SYSCONS_DEV MKDEV(TTYAUX_MAJOR,1)
-#define PTMX_DEV MKDEV(TTYAUX_MAJOR,2)
+#define IS_CONSOLE_DEV(dev)	(kdev_val(dev) == __mkdev(TTY_MAJOR,0))
+#define IS_TTY_DEV(dev)		(kdev_val(dev) == __mkdev(TTYAUX_MAJOR,0))
+#define IS_SYSCONS_DEV(dev)	(kdev_val(dev) == __mkdev(TTYAUX_MAJOR,1))
+#define IS_PTMX_DEV(dev)	(kdev_val(dev) == __mkdev(TTYAUX_MAJOR,2))
 
 #undef TTY_DEBUG_HANGUP
 
@@ -185,7 +185,7 @@
 static char *
 _tty_make_name(struct tty_struct *tty, const char *name, char *buf)
 {
-	int idx = (tty)?MINOR(tty->device) - tty->driver.minor_start:0;
+	int idx = (tty)? minor(tty->device) - tty->driver.minor_start:0;
 
 	if (!tty) /* Hmm.  NULL pointer.  That's fun. */
 		strcpy(buf, "NULL tty");
@@ -196,7 +196,7 @@
 	return buf;
 }
 
-#define TTY_NUMBER(tty) (MINOR((tty)->device) - (tty)->driver.minor_start + \
+#define TTY_NUMBER(tty) (minor((tty)->device) - (tty)->driver.minor_start + \
 			 (tty)->driver.name_base)
 
 char *tty_name(struct tty_struct *tty, char *buf)
@@ -331,8 +331,8 @@
 	int	major, minor;
 	struct tty_driver *p;
 	
-	minor = MINOR(device);
-	major = MAJOR(device);
+	minor = minor(device);
+	major = major(device);
 
 	for (p = tty_drivers; p; p = p->next) {
 		if (p->major != major)
@@ -442,8 +442,8 @@
 	file_list_lock();
 	for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) {
 		struct file * filp = list_entry(l, struct file, f_list);
-		if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV ||
-		    filp->f_dentry->d_inode->i_rdev == SYSCONS_DEV) {
+		if (IS_CONSOLE_DEV(filp->f_dentry->d_inode->i_rdev) ||
+		    IS_SYSCONS_DEV(filp->f_dentry->d_inode->i_rdev)) {
 			cons_filp = filp;
 			continue;
 		}
@@ -652,7 +652,7 @@
 	   moved it to there.  This should only be done for the N_TTY
 	   line discipline, anyway.  Same goes for write_chan(). -- jlc. */
 #if 0
-	if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */
+	if (!IS_CONSOLE_DEV(inode->i_rdev) && /* don't stop on /dev/console */
 	    (tty->pgrp > 0) &&
 	    (current->tty == tty) &&
 	    (tty->pgrp != current->pgrp))
@@ -741,8 +741,8 @@
 	 *      well as /dev/tty0.
 	 */
 	inode = file->f_dentry->d_inode;
-	is_console = (inode->i_rdev == SYSCONS_DEV ||
-		      inode->i_rdev == CONSOLE_DEV);
+	is_console = IS_SYSCONS_DEV(inode->i_rdev) ||
+		     IS_CONSOLE_DEV(inode->i_rdev);
 
 	if (is_console && redirect)
 		tty = redirect;
@@ -803,7 +803,7 @@
 	if (!driver)
 		return -ENODEV;
 
-	idx = MINOR(device) - driver->minor_start;
+	idx = minor(device) - driver->minor_start;
 
 	/* 
 	 * Check whether we need to acquire the tty semaphore to avoid
@@ -857,7 +857,7 @@
 		if (!o_tty)
 			goto free_mem_out;
 		initialize_tty_struct(o_tty);
-		o_tty->device = (kdev_t) MKDEV(driver->other->major,
+		o_tty->device = mk_kdev(driver->other->major,
 					driver->other->minor_start + idx);
 		o_tty->driver = *driver->other;
 
@@ -1049,7 +1049,7 @@
 
 	tty_fasync(-1, filp, 0);
 
-	idx = MINOR(tty->device) - tty->driver.minor_start;
+	idx = minor(tty->device) - tty->driver.minor_start;
 	pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 		      tty->driver.subtype == PTY_TYPE_MASTER);
 	o_tty = tty->link;
@@ -1285,7 +1285,7 @@
 retry_open:
 	noctty = filp->f_flags & O_NOCTTY;
 	device = inode->i_rdev;
-	if (device == TTY_DEV) {
+	if (IS_TTY_DEV(device)) {
 		if (!current->tty)
 			return -ENXIO;
 		device = current->tty->device;
@@ -1293,13 +1293,13 @@
 		/* noctty = 1; */
 	}
 #ifdef CONFIG_VT
-	if (device == CONSOLE_DEV) {
+	if (IS_CONSOLE_DEV(device)) {
 		extern int fg_console;
-		device = MKDEV(TTY_MAJOR, fg_console + 1);
+		device = mk_kdev(TTY_MAJOR, fg_console + 1);
 		noctty = 1;
 	}
 #endif
-	if (device == SYSCONS_DEV) {
+	if (IS_SYSCONS_DEV(device)) {
 		struct console *c = console_drivers;
 		while(c && !c->device)
 			c = c->next;
@@ -1310,7 +1310,7 @@
 		noctty = 1;
 	}
 
-	if (device == PTMX_DEV) {
+	if (IS_PTMX_DEV(device)) {
 #ifdef CONFIG_UNIX98_PTYS
 
 		/* find a free pty. */
@@ -1324,7 +1324,7 @@
 			for (minor = driver->minor_start ;
 			     minor < driver->minor_start + driver->num ;
 			     minor++) {
-				device = MKDEV(driver->major, minor);
+				device = mk_kdev(driver->major, minor);
 				if (!init_dev(device, &tty)) goto ptmx_found; /* ok! */
 			}
 		}
@@ -1332,7 +1332,7 @@
 	ptmx_found:
 		set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 		minor -= driver->minor_start;
-		devpts_pty_new(driver->other->name_base + minor, MKDEV(driver->other->major, minor + driver->other->minor_start));
+		devpts_pty_new(driver->other->name_base + minor, mk_kdev(driver->other->major, minor + driver->other->minor_start));
 		tty_register_devfs(&pts_driver[major], DEVFS_FL_DEFAULT,
 				   pts_driver[major].minor_start + minor);
 		noctty = 1;
@@ -1505,8 +1505,8 @@
 static int tioccons(struct inode *inode,
 	struct tty_struct *tty, struct tty_struct *real_tty)
 {
-	if (inode->i_rdev == SYSCONS_DEV ||
-	    inode->i_rdev == CONSOLE_DEV) {
+	if (IS_SYSCONS_DEV(inode->i_rdev) ||
+	    IS_CONSOLE_DEV(inode->i_rdev)) {
 		if (!suser())
 			return -EPERM;
 		redirect = NULL;
@@ -2002,7 +2002,7 @@
 {
 #ifdef CONFIG_DEVFS_FS
 	umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
-	kdev_t device = MKDEV (driver->major, minor);
+	kdev_t device = mk_kdev(driver->major, minor);
 	int idx = minor - driver->minor_start;
 	char buf[32];
 
@@ -2289,8 +2289,8 @@
 	dev_ptmx_driver = dev_tty_driver;
 	dev_ptmx_driver.driver_name = "/dev/ptmx";
 	dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5;
-	dev_ptmx_driver.major= MAJOR(PTMX_DEV);
-	dev_ptmx_driver.minor_start = MINOR(PTMX_DEV);
+	dev_ptmx_driver.major= TTYAUX_MAJOR;
+	dev_ptmx_driver.minor_start = 2;
 	dev_ptmx_driver.type = TTY_DRIVER_TYPE_SYSTEM;
 	dev_ptmx_driver.subtype = SYSTEM_TYPE_SYSPTMX;
 
diff -urN linux-2.5.2-pre5/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- linux-2.5.2-pre5/drivers/char/vc_screen.c	Sun Sep 16 21:22:40 2001
+++ linux/drivers/char/vc_screen.c	Tue Jan  1 14:04:28 2002
@@ -49,7 +49,8 @@
 vcs_size(struct inode *inode)
 {
 	int size;
-	int currcons = MINOR(inode->i_rdev) & 127;
+	int minor = minor(inode->i_rdev);
+	int currcons = minor & 127;
 	if (currcons == 0)
 		currcons = fg_console;
 	else
@@ -59,7 +60,7 @@
 
 	size = video_num_lines * video_num_columns;
 
-	if (MINOR(inode->i_rdev) & 128)
+	if (minor & 128)
 		size = 2*size + HEADER_SIZE;
 	return size;
 }
@@ -97,7 +98,7 @@
 vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	unsigned int currcons = MINOR(inode->i_rdev);
+	unsigned int currcons = minor(inode->i_rdev);
 	long pos = *ppos;
 	long viewed, attr, read;
 	int col, maxcol;
@@ -266,7 +267,7 @@
 vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	unsigned int currcons = MINOR(inode->i_rdev);
+	unsigned int currcons = minor(inode->i_rdev);
 	long pos = *ppos;
 	long viewed, attr, size, written;
 	char *con_buf0;
@@ -449,7 +450,7 @@
 static int
 vcs_open(struct inode *inode, struct file *filp)
 {
-	unsigned int currcons = (MINOR(inode->i_rdev) & 127);
+	unsigned int currcons = minor(inode->i_rdev) & 127;
 	if(currcons && !vc_cons_allocated(currcons-1))
 		return -ENXIO;
 	return 0;
diff -urN linux-2.5.2-pre5/drivers/ide/ataraid.c linux/drivers/ide/ataraid.c
--- linux-2.5.2-pre5/drivers/ide/ataraid.c	Thu Oct 25 13:58:35 2001
+++ linux/drivers/ide/ataraid.c	Tue Jan  1 14:04:28 2002
@@ -269,7 +269,6 @@
 	ataraid_gendisk.major       = ATAMAJOR;
 	ataraid_gendisk.major_name  = "ataraid";
 	ataraid_gendisk.minor_shift = 4;
-	ataraid_gendisk.max_p	    = 15;
 	ataraid_gendisk.sizes	    = &ataraid_gendisk_sizes[0];
 	ataraid_gendisk.nr_real	    = 16;
 	ataraid_gendisk.fops        = &ataraid_fops;
diff -urN linux-2.5.2-pre5/drivers/ide/hd.c linux/drivers/ide/hd.c
--- linux-2.5.2-pre5/drivers/ide/hd.c	Sun Dec 16 15:37:16 2001
+++ linux/drivers/ide/hd.c	Tue Jan  1 14:04:28 2002
@@ -693,7 +693,6 @@
 	major:		MAJOR_NR,
 	major_name:	"hd",
 	minor_shift:	6,
-	max_p:		1 << 6,
 	part:		hd,
 	sizes:		hd_sizes,
 	fops:		&hd_fops,
diff -urN linux-2.5.2-pre5/drivers/ide/ide-cd.c linux/drivers/ide/ide-cd.c
--- linux-2.5.2-pre5/drivers/ide/ide-cd.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/ide/ide-cd.c	Tue Jan  1 14:04:28 2002
@@ -2015,7 +2015,7 @@
 
 	/* Now try to get the total cdrom capacity. */
 	minor = (drive->select.b.unit) << PARTN_BITS;
-	dev = MKDEV(HWIF(drive)->major, minor);
+	dev = mk_kdev(HWIF(drive)->major, minor);
 	stat = cdrom_get_last_written(dev, &toc->capacity);
 	if (stat)
 		stat = cdrom_read_capacity(drive, &toc->capacity, sense);
@@ -2481,7 +2481,7 @@
 	struct cdrom_device_info *devinfo = &info->devinfo;
 	int minor = (drive->select.b.unit) << PARTN_BITS;
 
-	devinfo->dev = MKDEV (HWIF(drive)->major, minor);
+	devinfo->dev = mk_kdev(HWIF(drive)->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
 	*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
@@ -2678,8 +2678,8 @@
 	/*
 	 * default to read-only always and fix latter at the bottom
 	 */
-	set_device_ro(MKDEV(HWIF(drive)->major, minor), 1);
-	set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE);
+	set_device_ro(mk_kdev(HWIF(drive)->major, minor), 1);
+	set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
 	blk_queue_hardsect_size(&drive->queue, CD_FRAMESIZE);
 
 	blk_queue_prep_rq(&drive->queue, ll_10byte_cmd_build);
@@ -2801,7 +2801,7 @@
 	nslots = ide_cdrom_probe_capabilities (drive);
 
 	if (CDROM_CONFIG_FLAGS(drive)->dvd_ram)
-		set_device_ro(MKDEV(HWIF(drive)->major, minor), 0);
+		set_device_ro(mk_kdev(HWIF(drive)->major, minor), 0);
 
 	if (ide_cdrom_register (drive, nslots)) {
 		printk ("%s: ide_cdrom_setup failed to register device with the cdrom driver.\n", drive->name);
@@ -2848,7 +2848,7 @@
 static
 int ide_cdrom_check_media_change (ide_drive_t *drive)
 {
-	return cdrom_media_changed(MKDEV (HWIF (drive)->major,
+	return cdrom_media_changed(mk_kdev (HWIF (drive)->major,
 			(drive->select.b.unit) << PARTN_BITS));
 }
 
@@ -2876,7 +2876,7 @@
 	 * 1024 even for CDROM's
 	 */
 	blk_size[HWIF(drive)->major] = HWIF(drive)->gd->sizes;
-	set_blocksize(MKDEV(HWIF(drive)->major, minor), CD_FRAMESIZE);
+	set_blocksize(mk_kdev(HWIF(drive)->major, minor), CD_FRAMESIZE);
 }
 
 static
diff -urN linux-2.5.2-pre5/drivers/ide/ide-probe.c linux/drivers/ide/ide-probe.c
--- linux-2.5.2-pre5/drivers/ide/ide-probe.c	Sun Dec 16 12:20:20 2001
+++ linux/drivers/ide/ide-probe.c	Tue Jan  1 14:04:28 2002
@@ -796,9 +796,7 @@
 	gd->major	= hwif->major;		/* our major device number */
 	gd->major_name	= IDE_MAJOR_NAME;	/* treated special in genhd.c */
 	gd->minor_shift	= PARTN_BITS;		/* num bits for partitions */
-	gd->max_p	= 1<<PARTN_BITS;	/* 1 + max partitions / drive */
 	gd->nr_real	= units;		/* current num real drives */
-	gd->real_devices= hwif;			/* ptr to internal data */
 	gd->next	= NULL;			/* linked list of major devs */
 	gd->fops        = ide_fops;             /* file operations */
 	gd->de_arr	= kmalloc (sizeof *gd->de_arr * units, GFP_KERNEL);
diff -urN linux-2.5.2-pre5/drivers/ide/ide.c linux/drivers/ide/ide.c
--- linux-2.5.2-pre5/drivers/ide/ide.c	Sun Dec 16 12:21:02 2001
+++ linux/drivers/ide/ide.c	Tue Jan  1 14:04:28 2002
@@ -580,7 +580,7 @@
 	}
 
 	if (!end_that_request_first(rq, uptodate, nr_secs)) {
-		add_blkdev_randomness(MAJOR(rq->rq_dev));
+		add_blkdev_randomness(major(rq->rq_dev));
 		blkdev_dequeue_request(rq);
         	hwgroup->rq = NULL;
 		end_that_request_last(rq);
@@ -653,7 +653,7 @@
 			continue;
 		if (drive->media!=ide_disk && drive->media!=ide_floppy)
 			continue;
-		register_disk(gd,MKDEV(hwif->major,unit<<PARTN_BITS),
+		register_disk(gd,mk_kdev(hwif->major,unit<<PARTN_BITS),
 #ifdef CONFIG_BLK_DEV_ISAPNP
 			(drive->forced_geom && drive->noprobe) ? 1 :
 #endif /* CONFIG_BLK_DEV_ISAPNP */
@@ -1223,7 +1223,7 @@
 {
 	ide_startstop_t startstop;
 	unsigned long block;
-	unsigned int minor = MINOR(rq->rq_dev), unit = minor >> PARTN_BITS;
+	unsigned int minor = minor(rq->rq_dev), unit = minor >> PARTN_BITS;
 	ide_hwif_t *hwif = HWIF(drive);
 
 	BUG_ON(!(rq->flags & REQ_STARTED));
@@ -1478,7 +1478,7 @@
  */
 request_queue_t *ide_get_queue (kdev_t dev)
 {
-	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[MAJOR(dev)].data;
+	ide_hwif_t *hwif = (ide_hwif_t *)blk_dev[major(dev)].data;
 
 	return &hwif->drives[DEVICE_NR(dev) & 1].queue;
 }
@@ -1784,7 +1784,7 @@
  */
 ide_drive_t *get_info_ptr (kdev_t i_rdev)
 {
-	int		major = MAJOR(i_rdev);
+	int		major = major(i_rdev);
 	unsigned int	h;
 
 	for (h = 0; h < MAX_HWIFS; ++h) {
@@ -1851,7 +1851,7 @@
 #endif
 	rq->errors = 0;
 	rq->rq_status = RQ_ACTIVE;
-	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);
+	rq->rq_dev = mk_kdev(major,(drive->select.b.unit)<<PARTN_BITS);
 	if (action == ide_wait)
 		rq->waiting = &wait;
 	spin_lock_irqsave(&ide_lock, flags);
@@ -1880,7 +1880,7 @@
 {
         struct gendisk *g = HWIF(drive)->gd;
         int minor = (drive->select.b.unit << g->minor_shift);
-        kdev_t dev = MKDEV(g->major, minor);
+        kdev_t dev = mk_kdev(g->major, minor);
 
         grok_partitions(dev, current_capacity(drive));
 }
@@ -1939,7 +1939,7 @@
 			if (drive->revalidate) {
 				drive->revalidate = 0;
 				if (!initializing)
-					(void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS));
+					(void) ide_revalidate_disk(mk_kdev(hwif->major, unit<<PARTN_BITS));
 			}
 		}
 	}
@@ -2119,7 +2119,7 @@
 		minor = drive->select.b.unit << PARTN_BITS;
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
-				kdev_t devp = MKDEV(hwif->major, minor+p);
+				kdev_t devp = mk_kdev(hwif->major, minor+p);
 				invalidate_device(devp, 0);
 			}
 		}
@@ -2624,9 +2624,8 @@
 	kdev_t dev;
 	ide_settings_t *setting;
 
-	if (!inode || !(dev = inode->i_rdev))
-		return -EINVAL;
-	major = MAJOR(dev); minor = MINOR(dev);
+	dev = inode->i_rdev;
+	major = major(dev); minor = minor(dev);
 	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)
 		return -ENODEV;
 
@@ -2635,7 +2634,7 @@
 			err = ide_read_setting(drive, setting);
 			return err >= 0 ? put_user(err, (long *) arg) : err;
 		} else {
-			if ((MINOR(inode->i_rdev) & PARTN_MASK))
+			if ((minor(inode->i_rdev) & PARTN_MASK))
 				return -EINVAL;
 			return ide_write_setting(drive, setting, arg);
 		}
@@ -2651,7 +2650,7 @@
 			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
 			if (put_user(bios_cyl, (unsigned short *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
 		}
@@ -2664,7 +2663,7 @@
 			if (put_user(drive->bios_head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->bios_sect, (byte *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->bios_cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
 		}
@@ -2676,7 +2675,7 @@
 			if (put_user(drive->head, (byte *) &loc->heads)) return -EFAULT;
 			if (put_user(drive->sect, (byte *) &loc->sectors)) return -EFAULT;
 			if (put_user(drive->cyl, (unsigned int *) &loc->cylinders)) return -EFAULT;
-			if (put_user((unsigned)drive->part[MINOR(inode->i_rdev)&PARTN_MASK].start_sect,
+			if (put_user((unsigned)drive->part[minor(inode->i_rdev)&PARTN_MASK].start_sect,
 				(unsigned long *) &loc->start)) return -EFAULT;
 			return 0;
 		}
@@ -2687,7 +2686,7 @@
 
 		case HDIO_OBSOLETE_IDENTITY:
 		case HDIO_GET_IDENTITY:
-			if (MINOR(inode->i_rdev) & PARTN_MASK)
+			if (minor(inode->i_rdev) & PARTN_MASK)
 				return -EINVAL;
 			if (drive->id == NULL)
 				return -ENOMSG;
diff -urN linux-2.5.2-pre5/drivers/md/lvm.c linux/drivers/md/lvm.c
--- linux-2.5.2-pre5/drivers/md/lvm.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/md/lvm.c	Tue Jan  1 14:04:28 2002
@@ -378,7 +378,6 @@
 	major:		MAJOR_NR,
 	major_name:	LVM_NAME,
 	minor_shift:	0,
-	max_p:		1,
 	part:		lvm_hd_struct,
 	sizes:		lvm_size,
 	nr_real:	MAX_LV,
diff -urN linux-2.5.2-pre5/drivers/md/md.c linux/drivers/md/md.c
--- linux-2.5.2-pre5/drivers/md/md.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/md/md.c	Tue Jan  1 14:04:28 2002
@@ -118,11 +118,9 @@
 	major: MD_MAJOR,
 	major_name: "md",
 	minor_shift: 0,
-	max_p: 1,
 	part: md_hd_struct,
 	sizes: md_size,
 	nr_real: MAX_MD_DEVS,
-	real_devices: NULL,
 	next: NULL,
 	fops: &md_fops,
 };
diff -urN linux-2.5.2-pre5/drivers/message/i2o/i2o_block.c linux/drivers/message/i2o/i2o_block.c
--- linux-2.5.2-pre5/drivers/message/i2o/i2o_block.c	Sun Dec 16 12:20:20 2001
+++ linux/drivers/message/i2o/i2o_block.c	Tue Jan  1 14:04:28 2002
@@ -1778,7 +1778,6 @@
 	major:		MAJOR_NR,
 	major_name:	"i2o/hd",
 	minor_shift:	4,
-	max_p:		1<<4,
 	part:		i2ob,
 	sizes:		i2ob_sizes,
 	nr_real:	MAX_I2OB,
diff -urN linux-2.5.2-pre5/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c
--- linux-2.5.2-pre5/drivers/mtd/ftl.c	Tue Nov 27 09:23:27 2001
+++ linux/drivers/mtd/ftl.c	Tue Jan  1 14:04:28 2002
@@ -72,33 +72,12 @@
 #include <linux/hdreg.h>
 #include <stdarg.h>
 
-#if (LINUX_VERSION_CODE >= 0x20100)
 #include <linux/vmalloc.h>
-#endif
-#if (LINUX_VERSION_CODE >= 0x20303)
 #include <linux/blkpg.h>
-#endif
 
 #include <linux/mtd/ftl.h>
-/*====================================================================*/
-/* Stuff which really ought to be in compatmac.h */
-
-#if (LINUX_VERSION_CODE < 0x20328)
-#define register_disk(dev, drive, minors, ops, size) \
-    do { (dev)->part[(drive)*(minors)].nr_sects = size; \
-        if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
-        resetup_one_dev(dev, drive); } while (0);
-#endif
 
-#if (LINUX_VERSION_CODE < 0x20320)
-#define BLK_DEFAULT_QUEUE(n)    blk_dev[n].request_fn
-#define blk_init_queue(q, req)  q = (req)
-#define blk_cleanup_queue(q)    q = NULL
-#define request_arg_t           void
-#else
 #define request_arg_t           request_queue_t *q
-#endif
-
 
 /*====================================================================*/
 
@@ -206,10 +185,6 @@
     major:		FTL_MAJOR,
     major_name:		"ftl",
     minor_shift:	PART_BITS,
-    max_p:		MAX_PART,
-#if (LINUX_VERSION_CODE < 0x20328)
-    max_nr:		MAX_DEV*MAX_PART,
-#endif
     part:		ftl_hd,
     sizes:		ftl_sizes,
 };
@@ -224,23 +199,12 @@
 
 static void ftl_erase_callback(struct erase_info *done);
 
-#if LINUX_VERSION_CODE < 0x20326
-static struct file_operations ftl_blk_fops = {
-    open:	ftl_open,
-    release:	ftl_close,
-    ioctl:	ftl_ioctl,
-    read:	block_read,
-    write:	block_write,
-    fsync:	block_fsync
-};
-#else
 static struct block_device_operations ftl_blk_fops = {
     owner:	THIS_MODULE,
     open:	ftl_open,
     release:	ftl_close,
     ioctl:	ftl_ioctl,
 };
-#endif
 
 /*======================================================================
 
@@ -1177,22 +1141,11 @@
     case BLKRRPART:
 	ret = ftl_reread_partitions(minor);
 	break;
-#if (LINUX_VERSION_CODE < 0x20303)
-    case BLKFLSBUF:
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
-#endif
-	fsync_dev(inode->i_rdev);
-	invalidate_buffers(inode->i_rdev);
-	break;
-    RO_IOCTLS(inode->i_rdev, arg);
-#else
     case BLKROSET:
     case BLKROGET:
     case BLKFLSBUF:
 	ret = blk_ioctl(inode->i_rdev, cmd, arg);
 	break;
-#endif
     default:
 	ret = -EINVAL;
     }
diff -urN linux-2.5.2-pre5/drivers/mtd/nftlcore.c linux/drivers/mtd/nftlcore.c
--- linux-2.5.2-pre5/drivers/mtd/nftlcore.c	Tue Nov 27 09:23:27 2001
+++ linux/drivers/mtd/nftlcore.c	Tue Jan  1 14:04:28 2002
@@ -62,14 +62,9 @@
 static struct gendisk nftl_gendisk = {
 	major:		MAJOR_NR,
 	major_name:	"nftl",
-	minor_shift:	NFTL_PARTN_BITS,	/* Bits to shift to get real from partition */
-	max_p:		(1<<NFTL_PARTN_BITS)-1,	/* Number of partitions per real */
-#if LINUX_VERSION_CODE < 0x20328
-	max_nr:		MAX_NFTLS,      /* maximum number of real */
-	init:		dummy_init,     /* init function */
-#endif
-	part:		part_table,     /* hd struct */
-	sizes:		nftl_sizes,     /* block sizes */
+	minor_shift:	NFTL_PARTN_BITS,	/* # of partition bits */
+	part:		part_table,		/* hd struct */
+	sizes:		nftl_sizes,		/* block sizes */
 };
 
 struct NFTLrecord *NFTLs[MAX_NFTLS];
diff -urN linux-2.5.2-pre5/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- linux-2.5.2-pre5/drivers/net/irda/irda-usb.c	Sat Dec  8 20:28:45 2001
+++ linux/drivers/net/irda/irda-usb.c	Tue Jan  1 14:04:28 2002
@@ -112,9 +112,9 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
 static int irda_usb_open(struct irda_usb_cb *self);
 static int irda_usb_close(struct irda_usb_cb *self);
-static void speed_bulk_callback(purb_t purb);
-static void write_bulk_callback(purb_t purb);
-static void irda_usb_receive(purb_t purb);
+static void speed_bulk_callback(struct urb *urb);
+static void write_bulk_callback(struct urb *urb);
+static void irda_usb_receive(struct urb *urb);
 static int irda_usb_net_init(struct net_device *dev);
 static int irda_usb_net_open(struct net_device *dev);
 static int irda_usb_net_close(struct net_device *dev);
@@ -248,15 +248,15 @@
 {
 	unsigned long flags;
 	__u8 *frame;
-	purb_t purb;
+	struct urb *urb;
 	int ret;
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
 		   self->new_speed, self->new_xbofs);
 
 	/* Grab the speed URB */
-	purb = &self->speed_urb;
-	if (purb->status != 0) {
+	urb = &self->speed_urb;
+	if (urb->status != 0) {
 		WARNING(__FUNCTION__ "(), URB still in use!\n");
 		return;
 	}
@@ -270,15 +270,15 @@
 	irda_usb_build_header(self, frame, 1);
 
 	/* Submit the 0 length IrDA frame to trigger new speed settings */
-        FILL_BULK_URB(purb, self->usbdev,
+        FILL_BULK_URB(urb, self->usbdev,
 		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
                       frame, IRDA_USB_SPEED_MTU,
                       speed_bulk_callback, self);
-	purb->transfer_buffer_length = USB_IRDA_HEADER;
-	purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
-	purb->timeout = MSECS_TO_JIFFIES(100);
+	urb->transfer_buffer_length = USB_IRDA_HEADER;
+	urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
+	urb->timeout = MSECS_TO_JIFFIES(100);
 
-	if ((ret = usb_submit_urb(purb))) {
+	if ((ret = usb_submit_urb(urb))) {
 		WARNING(__FUNCTION__ "(), failed Speed URB\n");
 	}
 	spin_unlock_irqrestore(&self->lock, flags);
@@ -288,9 +288,9 @@
 /*
  * Note : this function will be called with both speed_urb and empty_urb...
  */
-static void speed_bulk_callback(purb_t purb)
+static void speed_bulk_callback(struct urb *urb)
 {
-	struct irda_usb_cb *self = purb->context;
+	struct irda_usb_cb *self = urb->context;
 	
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
@@ -301,9 +301,9 @@
 	}
 
 	/* Check for timeout and other USB nasties */
-	if (purb->status != 0) {
+	if (urb->status != 0) {
 		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags);
 
 		/* Don't do anything here, that might confuse the USB layer.
 		 * Instead, we will wait for irda_usb_net_timeout(), the
@@ -314,10 +314,10 @@
 	}
 
 	/* urb is now available */
-	purb->status = 0;
+	urb->status = 0;
 
 	/* If it was the speed URB, allow the stack to send more packets */
-	if(purb == &self->speed_urb) {
+	if(urb == &self->speed_urb) {
 		netif_wake_queue(self->netdev);
 	}
 }
@@ -329,7 +329,7 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct irda_usb_cb *self = netdev->priv;
-	purb_t purb = &self->tx_urb;
+	struct urb *urb = &self->tx_urb;
 	unsigned long flags;
 	s32 speed;
 	s16 xbofs;
@@ -372,7 +372,7 @@
 		}
 	}
 
-	if (purb->status != 0) {
+	if (urb->status != 0) {
 		WARNING(__FUNCTION__ "(), URB still in use!\n");
 		dev_kfree_skb(skb);
 		return 0;
@@ -392,22 +392,22 @@
 	/* FIXME: Make macro out of this one */
 	((struct irda_skb_cb *)skb->cb)->context = self;
 
-        FILL_BULK_URB(purb, self->usbdev, 
+        FILL_BULK_URB(urb, self->usbdev, 
 		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
                       skb->data, IRDA_USB_MAX_MTU,
                       write_bulk_callback, skb);
-	purb->transfer_buffer_length = skb->len;
+	urb->transfer_buffer_length = skb->len;
 	/* Note : unlink *must* be Asynchronous because of the code in 
 	 * irda_usb_net_timeout() -> call in irq - Jean II */
-	purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
+	urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
 	/* This flag (USB_ZERO_PACKET) indicates that what we send is not
 	 * a continuous stream of data but separate packets.
 	 * In this case, the USB layer will insert an empty USB frame (TD)
 	 * after each of our packets that is exact multiple of the frame size.
 	 * This is how the dongle will detect the end of packet - Jean II */
-	purb->transfer_flags |= USB_ZERO_PACKET;
+	urb->transfer_flags |= USB_ZERO_PACKET;
 	/* Timeout need to be shorter than NET watchdog timer */
-	purb->timeout = MSECS_TO_JIFFIES(200);
+	urb->timeout = MSECS_TO_JIFFIES(200);
 
 	/* Generate min turn time. FIXME: can we do better than this? */
 	/* Trying to a turnaround time at this level is trying to measure
@@ -451,7 +451,7 @@
 	}
 	
 	/* Ask USB to send the packet */
-	if ((res = usb_submit_urb(purb))) {
+	if ((res = usb_submit_urb(urb))) {
 		WARNING(__FUNCTION__ "(), failed Tx URB\n");
 		self->stats.tx_errors++;
 		/* Let USB recover : We will catch that in the watchdog */
@@ -472,9 +472,9 @@
 /*
  * Note : this function will be called only for tx_urb...
  */
-static void write_bulk_callback(purb_t purb)
+static void write_bulk_callback(struct urb *urb)
 {
-	struct sk_buff *skb = purb->context;
+	struct sk_buff *skb = urb->context;
 	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
 	
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
@@ -487,12 +487,12 @@
 
 	/* Free up the skb */
 	dev_kfree_skb_any(skb);
-	purb->context = NULL;
+	urb->context = NULL;
 
 	/* Check for timeout and other USB nasties */
-	if (purb->status != 0) {
+	if (urb->status != 0) {
 		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
-		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, __FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", urb->status, urb->transfer_flags);
 
 		/* Don't do anything here, that might confuse the USB layer,
 		 * and we could go in recursion and blow the kernel stack...
@@ -504,7 +504,7 @@
 	}
 
 	/* urb is now available */
-	purb->status = 0;
+	urb->status = 0;
 
 	/* If the network is closed, stop everything */
 	if ((!self->netopen) || (!self->present)) {
@@ -534,7 +534,7 @@
 static void irda_usb_net_timeout(struct net_device *netdev)
 {
 	struct irda_usb_cb *self = netdev->priv;
-	purb_t purb;
+	struct urb *urb;
 	int	done = 0;	/* If we have made any progress */
 
 	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
@@ -546,13 +546,13 @@
 	}
 
 	/* Check speed URB */
-	purb = &(self->speed_urb);
-	if (purb->status != 0) {
-		IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
+	urb = &(self->speed_urb);
+	if (urb->status != 0) {
+		IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
 
-		switch (purb->status) {
+		switch (urb->status) {
 		case -EINPROGRESS:
-			usb_unlink_urb(purb);
+			usb_unlink_urb(urb);
 			/* Note : above will  *NOT* call netif_wake_queue()
 			 * in completion handler, we will come back here.
 			 * Jean II */
@@ -563,7 +563,7 @@
 		case -ETIMEDOUT:		/* -110 */
 		case -ENOENT:			/* -2 (urb unlinked by us)  */
 		default:			/* ??? - Play safe */
-			purb->status = 0;
+			urb->status = 0;
 			netif_wake_queue(self->netdev);
 			done = 1;
 			break;
@@ -571,11 +571,11 @@
 	}
 
 	/* Check Tx URB */
-	purb = &(self->tx_urb);
-	if (purb->status != 0) {
-		struct sk_buff *skb = purb->context;
+	urb = &(self->tx_urb);
+	if (urb->status != 0) {
+		struct sk_buff *skb = urb->context;
 
-		IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
+		IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
 
 		/* Increase error count */
 		self->stats.tx_errors++;
@@ -589,11 +589,11 @@
 		irda_usb_change_speed_xbofs(self);
 #endif /* IU_BUG_KICK_TIMEOUT */
 
-		switch (purb->status) {
+		switch (urb->status) {
 		case -EINPROGRESS:
-			usb_unlink_urb(purb);
+			usb_unlink_urb(urb);
 			/* Note : above will  *NOT* call netif_wake_queue()
-			 * in completion handler, because purb->status will
+			 * in completion handler, because urb->status will
 			 * be -ENOENT. We will fix that at the next watchdog,
 			 * leaving more time to USB to recover...
 			 * Also, we are in interrupt, so we need to have
@@ -608,9 +608,9 @@
 		default:			/* ??? - Play safe */
 			if(skb != NULL) {
 				dev_kfree_skb_any(skb);
-				purb->context = NULL;
+				urb->context = NULL;
 			}
-			purb->status = 0;
+			urb->status = 0;
 			netif_wake_queue(self->netdev);
 			done = 1;
 			break;
@@ -685,7 +685,7 @@
  *
  * Jean II
  */
-static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
+static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struct urb *urb)
 {
 	struct irda_skb_cb *cb;
 	int ret;
@@ -693,8 +693,8 @@
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
 	/* Check that we have an urb */
-	if (!purb) {
-		WARNING(__FUNCTION__ "(), Bug : purb == NULL\n");
+	if (!urb) {
+		WARNING(__FUNCTION__ "(), Bug : urb == NULL\n");
 		return;
 	}
 
@@ -720,17 +720,17 @@
 	cb->context = self;
 
 	/* Reinitialize URB */
-	FILL_BULK_URB(purb, self->usbdev, 
+	FILL_BULK_URB(urb, self->usbdev, 
 		      usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), 
 		      skb->data, skb->truesize,
                       irda_usb_receive, skb);
-	purb->transfer_flags = USB_QUEUE_BULK;
+	urb->transfer_flags = USB_QUEUE_BULK;
 	/* Note : unlink *must* be synchronous because of the code in 
 	 * irda_usb_net_close() -> free the skb - Jean II */
-	purb->status = 0;
-	purb->next = NULL;	/* Don't auto resubmit URBs */
+	urb->status = 0;
+	urb->next = NULL;	/* Don't auto resubmit URBs */
 	
-	ret = usb_submit_urb(purb);
+	ret = usb_submit_urb(urb);
 	if (ret) {
 		/* If this ever happen, we are in deep s***.
 		 * Basically, the Rx path will stop... */
@@ -740,19 +740,19 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Function irda_usb_receive(purb)
+ * Function irda_usb_receive(urb)
  *
  *     Called by the USB subsystem when a frame has been received
  *
  */
-static void irda_usb_receive(purb_t purb) 
+static void irda_usb_receive(struct urb *urb) 
 {
-	struct sk_buff *skb = (struct sk_buff *) purb->context;
+	struct sk_buff *skb = (struct sk_buff *) urb->context;
 	struct irda_usb_cb *self; 
 	struct irda_skb_cb *cb;
 	struct sk_buff *new;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", purb->actual_length);
+	IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", urb->actual_length);
 	
 	/* Find ourselves */
 	cb = (struct irda_skb_cb *) skb->cb;
@@ -768,27 +768,27 @@
 	}
 	
 	/* Check the status */
-	if (purb->status != 0) {
-		switch (purb->status) {
+	if (urb->status != 0) {
+		switch (urb->status) {
 		case -EILSEQ:
 			self->stats.rx_errors++;
 			self->stats.rx_crc_errors++;	
 			break;
 		case -ECONNRESET:		/* -104 */
-			IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags);
+			IRDA_DEBUG(0, __FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", urb->transfer_flags);
 			/* uhci_cleanup_unlink() is going to kill the Rx
 			 * URB just after we return. No problem, at this
 			 * point the URB will be idle ;-) - Jean II */
 			break;
 		default:
-			IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags);
+			IRDA_DEBUG(0, __FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", urb->status, urb->transfer_flags);
 			break;
 		}
 		goto done;
 	}
 	
 	/* Check for empty frames */
-	if (purb->actual_length <= USB_IRDA_HEADER) {
+	if (urb->actual_length <= USB_IRDA_HEADER) {
 		WARNING(__FUNCTION__ "(), empty frame!\n");
 		goto done;
 	}
@@ -801,7 +801,7 @@
         get_fast_time(&self->stamp);
 
 	/* Fix skb, and remove USB-IrDA header */
-	skb_put(skb, purb->actual_length);
+	skb_put(skb, urb->actual_length);
 	skb_pull(skb, USB_IRDA_HEADER);
 
 	/* Don't waste a lot of memory on small IrDA frames */
@@ -834,7 +834,7 @@
         netif_rx(new);
 
 done:
-	/* Note : at this point, the URB we've just received (purb)
+	/* Note : at this point, the URB we've just received (urb)
 	 * is still referenced by the USB layer. For example, if we
 	 * have received a -ECONNRESET, uhci_cleanup_unlink() will
 	 * continue to process it (in fact, cleaning it up).
@@ -848,8 +848,8 @@
 	/* Submit the idle URB to replace the URB we've just received */
 	irda_usb_submit(self, skb, self->idle_rx_urb);
 	/* Recycle Rx URB : Now, the idle URB is the present one */
-	self->idle_rx_urb = purb;
-	purb->context = NULL;
+	self->idle_rx_urb = urb;
+	urb->context = NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -992,14 +992,14 @@
 
 	/* Deallocate all the Rx path buffers (URBs and skb) */
 	for (i = 0; i < IU_MAX_RX_URBS; i++) {
-		purb_t purb = &(self->rx_urb[i]);
-		struct sk_buff *skb = (struct sk_buff *) purb->context;
+		struct urb *urb = &(self->rx_urb[i]);
+		struct sk_buff *skb = (struct sk_buff *) urb->context;
 		/* Cancel the receive command */
-		usb_unlink_urb(purb);
+		usb_unlink_urb(urb);
 		/* The skb is ours, free it */
 		if(skb) {
 			dev_kfree_skb(skb);
-			purb->context = NULL;
+			urb->context = NULL;
 		}
 	}
 	/* Cancel Tx and speed URB */
diff -urN linux-2.5.2-pre5/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- linux-2.5.2-pre5/drivers/pcmcia/ds.c	Fri Nov 30 08:26:04 2001
+++ linux/drivers/pcmcia/ds.c	Tue Jan  1 14:04:28 2002
@@ -558,7 +558,7 @@
 
 static int ds_open(struct inode *inode, struct file *file)
 {
-    socket_t i = MINOR(inode->i_rdev);
+    socket_t i = minor(inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -590,7 +590,7 @@
 
 static int ds_release(struct inode *inode, struct file *file)
 {
-    socket_t i = MINOR(inode->i_rdev);
+    socket_t i = minor(inode->i_rdev);
     socket_info_t *s;
     user_info_t *user, **link;
 
@@ -622,7 +622,7 @@
 static ssize_t ds_read(struct file *file, char *buf,
 		       size_t count, loff_t *ppos)
 {
-    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_t i = minor(file->f_dentry->d_inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -651,7 +651,7 @@
 static ssize_t ds_write(struct file *file, const char *buf,
 			size_t count, loff_t *ppos)
 {
-    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_t i = minor(file->f_dentry->d_inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -684,7 +684,7 @@
 /* No kernel lock - fine */
 static u_int ds_poll(struct file *file, poll_table *wait)
 {
-    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_t i = minor(file->f_dentry->d_inode->i_rdev);
     socket_info_t *s;
     user_info_t *user;
 
@@ -707,7 +707,7 @@
 static int ds_ioctl(struct inode * inode, struct file * file,
 		    u_int cmd, u_long arg)
 {
-    socket_t i = MINOR(inode->i_rdev);
+    socket_t i = minor(inode->i_rdev);
     socket_info_t *s;
     u_int size;
     int ret, err;
diff -urN linux-2.5.2-pre5/drivers/s390/block/dasd_int.h linux/drivers/s390/block/dasd_int.h
--- linux-2.5.2-pre5/drivers/s390/block/dasd_int.h	Sun Sep 30 12:26:07 2001
+++ linux/drivers/s390/block/dasd_int.h	Tue Jan  1 14:04:28 2002
@@ -88,7 +88,6 @@
 	major:D_MAJOR, \
 	major_name:D_NAME, \
 	minor_shift:D_PARTN_BITS, \
-	max_p:1 << D_PARTN_BITS, \
 	max_nr:D_PER_MAJOR, \
 	nr_real:D_PER_MAJOR,
 static inline struct request * 
@@ -111,7 +110,6 @@
 	major:D_MAJOR, \
 	major_name:D_NAME, \
 	minor_shift:D_PARTN_BITS, \
-	max_p:1 << D_PARTN_BITS, \
 	nr_real:D_PER_MAJOR, \
         fops:&dasd_device_operations, 
 static inline struct request * 
diff -urN linux-2.5.2-pre5/drivers/scsi/scsi_lib.c linux/drivers/scsi/scsi_lib.c
--- linux-2.5.2-pre5/drivers/scsi/scsi_lib.c	Sun Dec 16 12:20:21 2001
+++ linux/drivers/scsi/scsi_lib.c	Tue Jan  1 14:04:28 2002
@@ -385,7 +385,7 @@
 	if (req->waiting)
 		complete(req->waiting);
 
-	add_blkdev_randomness(MAJOR(req->rq_dev));
+	add_blkdev_randomness(major(req->rq_dev));
 
 	/*
 	 * This will goose the queue request function at the end, so we don't
@@ -744,7 +744,7 @@
 {
 	struct Scsi_Device_Template *spnt;
 	kdev_t dev = req->rq_dev;
-	int major = MAJOR(dev);
+	int major = major(dev);
 
 	for (spnt = scsi_devicelist; spnt; spnt = spnt->next) {
 		/*
diff -urN linux-2.5.2-pre5/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c
--- linux-2.5.2-pre5/drivers/scsi/scsicam.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/scsi/scsicam.c	Tue Jan  1 14:04:28 2002
@@ -29,7 +29,7 @@
 unsigned char *scsi_bios_ptable(kdev_t dev)
 {
 	unsigned char *res = kmalloc(66, GFP_KERNEL);
-	kdev_t rdev = MKDEV(MAJOR(dev), MINOR(dev) & ~0xf);
+	kdev_t rdev = mk_kdev(major(dev), minor(dev) & ~0x0f);
 
 	if (res) {
 		struct buffer_head *bh = bread(rdev, 0, block_size(rdev));
diff -urN linux-2.5.2-pre5/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- linux-2.5.2-pre5/drivers/scsi/sd.c	Tue Jan  1 14:04:25 2002
+++ linux/drivers/scsi/sd.c	Tue Jan  1 14:04:28 2002
@@ -66,7 +66,7 @@
 #define SCSI_DISKS_PER_MAJOR	16
 #define SD_MAJOR_NUMBER(i)	SD_MAJOR((i) >> 8)
 #define SD_MINOR_NUMBER(i)	((i) & 255)
-#define MKDEV_SD_PARTITION(i)	MKDEV(SD_MAJOR_NUMBER(i), (i) & 255)
+#define MKDEV_SD_PARTITION(i)	mk_kdev(SD_MAJOR_NUMBER(i), (i) & 255)
 #define MKDEV_SD(index)		MKDEV_SD_PARTITION((index) << 4)
 #define N_USED_SD_MAJORS	(1 + ((sd_template.dev_max - 1) >> 4))
 
@@ -569,7 +569,6 @@
 	major:		SCSI_DISK0_MAJOR,
 	major_name:	"sd",
 	minor_shift:	4,
-	max_p:		1 << 4,
 	fops:		&sd_fops,
 };
 
@@ -1116,7 +1115,7 @@
 	}
 
 	for (i = 0; i < N_USED_SD_MAJORS; i++) {
-		request_queue_t *q = blk_get_queue(SD_MAJOR(i));
+		request_queue_t *q = blk_get_queue(mk_kdev(SD_MAJOR(i), 0));
 		int parts_per_major = (SCSI_DISKS_PER_MAJOR << 4);
 
 		blksize_size[SD_MAJOR(i)] =
@@ -1141,12 +1140,9 @@
 		sd_gendisks[i].major = SD_MAJOR(i);
 		sd_gendisks[i].major_name = "sd";
 		sd_gendisks[i].minor_shift = 4;
-		sd_gendisks[i].max_p = 1 << 4;
 		sd_gendisks[i].part = sd + i * (N << 4);
 		sd_gendisks[i].sizes = sd_sizes + i * (N << 4);
 		sd_gendisks[i].nr_real = 0;
-		sd_gendisks[i].real_devices =
-		    (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR);
 	}
 
 	return 0;
@@ -1309,7 +1305,7 @@
 	for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++)
 		if (dpnt->device == SDp) {
 
-			max_p = sd_gendisk.max_p;
+			max_p = 1 << sd_gendisk.minor_shift;
 			start = i << sd_gendisk.minor_shift;
 			dev = MKDEV_SD_PARTITION(start);
 			wipe_partitions(dev);
diff -urN linux-2.5.2-pre5/drivers/scsi/sd.h linux/drivers/scsi/sd.h
--- linux-2.5.2-pre5/drivers/scsi/sd.h	Sun Dec 16 15:46:45 2001
+++ linux/drivers/scsi/sd.h	Tue Jan  1 14:04:28 2002
@@ -45,7 +45,7 @@
 #define N_SD_MAJORS	8
 
 #define SD_MAJOR_MASK	(N_SD_MAJORS - 1)
-#define SD_PARTITION(i)		(((MAJOR(i) & SD_MAJOR_MASK) << 8) | (MINOR(i) & 255))
+#define SD_PARTITION(i)		(((major(i) & SD_MAJOR_MASK) << 8) | (minor(i) & 255))
 
 #endif
 
diff -urN linux-2.5.2-pre5/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- linux-2.5.2-pre5/drivers/scsi/wd7000.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/scsi/wd7000.c	Tue Jan  1 14:04:28 2002
@@ -140,6 +140,11 @@
  *  03/01/1998
  *
  *  WD7000 driver now work on kernels >= 2.1.x
+ *
+ *
+ * 12/31/2001 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * use host->host_lock, not io_request_lock, cleanups
  */
 
 #include <linux/module.h>
@@ -166,6 +171,11 @@
 
 #define ANY2SCSI_INLINE		/* undef this to use old macros */
 #undef  WD7000_DEBUG		/* general debug                */
+#ifdef WD7000_DEBUG
+#define dprintk printk
+#else
+#define dprintk(format,args...)
+#endif
 
 #include "wd7000.h"
 #include <linux/stat.h>
@@ -557,7 +567,7 @@
 } Icb;
 
 #ifdef MODULE
-static char * wd7000 = NULL;
+static char *wd7000;
 MODULE_PARM(wd7000, "s");
 #endif
 
@@ -568,23 +578,23 @@
  *  structure is not part of the Adapter structure.
  */
 static Scb scbs[MAX_SCBS];
-static Scb *scbfree = NULL;	/* free list         */
+static Scb *scbfree;		/* free list         */
 static int freescbs = MAX_SCBS;	/* free list counter */
 
 /*
  *  END of data/declarations - code follows.
  */
-static void setup_error (char *mesg, int *ints)
+static void __init setup_error(char *mesg, int *ints)
 {
     if (ints[0] == 3)
-        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
-                ints[1], ints[2], ints[3], mesg);
+        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n",
+               ints[1], ints[2], ints[3], mesg);
     else if (ints[0] == 4)
-        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
-                ints[1], ints[2], ints[3], ints[4], mesg);
+        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n",
+               ints[1], ints[2], ints[3], ints[4], mesg);
     else
-        printk ("wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
-                ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
+        printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n",
+               ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
 }
 
 
@@ -604,21 +614,23 @@
  */
 static int __init wd7000_setup(char *str)
 {
-	static short wd7000_card_num = 0;
-	short i, j;
+	static short wd7000_card_num; /* .bss will zero this */
+	short i;
 	int ints[6];
 
 	(void)get_options(str, ARRAY_SIZE(ints), ints);
 
 	if (wd7000_card_num >= NUM_CONFIGS) {
-		printk("wd7000_setup: Too many \"wd7000=\" configurations in "
-		"command line!\n");
+		printk(KERN_ERR __FUNCTION__
+			": Too many \"wd7000=\" configurations in "
+			"command line!\n");
 		return 0;
 	}
 
 	if ((ints[0] < 3) || (ints[0] > 5)) {
-		printk("wd7000_setup: Error in command line!  "
-		"Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>[,<BUS_OFF>]]\n");
+		printk(KERN_ERR __FUNCTION__ ": Error in command line!  "
+			"Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>"
+			"[,<BUS_OFF>]]\n");
 	} else {
 		for (i = 0; i < NUM_IRQS; i++)
 			if (ints[1] == wd7000_irq[i])
@@ -652,7 +664,8 @@
 
 		if (ints[0] > 3) {
 			if ((ints[4] < 500) || (ints[4] > 31875)) {
-				setup_error("BUS_ON value is out of range (500 to 31875 nanoseconds)!", ints);
+				setup_error("BUS_ON value is out of range (500"
+					    " to 31875 nanoseconds)!", ints);
 				configs[wd7000_card_num].bus_on = BUS_ON;
 			} else
 				configs[wd7000_card_num].bus_on = ints[4] / 125;
@@ -661,36 +674,47 @@
 
 		if (ints[0] > 4) {
 			if ((ints[5] < 500) || (ints[5] > 31875)) {
-				setup_error("BUS_OFF value is out of range (500 to 31875 nanoseconds)!", ints);
+				setup_error("BUS_OFF value is out of range (500"
+					    " to 31875 nanoseconds)!", ints);
 				configs[wd7000_card_num].bus_off = BUS_OFF;
 			} else
-				configs[wd7000_card_num].bus_off = ints[5] / 125;
+				configs[wd7000_card_num].bus_off = ints[5] /
+								   125;
 		} else
 			configs[wd7000_card_num].bus_off = BUS_OFF;
 
 		if (wd7000_card_num) {
-			for (i = 0; i < (wd7000_card_num - 1); i++)
-				for (j = i + 1; j < wd7000_card_num; j++)
+			for (i = 0; i < (wd7000_card_num - 1); i++) {
+				int j = i + 1;
+
+				for (; j < wd7000_card_num; j++)
 					if (configs[i].irq == configs[j].irq) {
-						setup_error("duplicated IRQ!", ints);
+						setup_error("duplicated IRQ!",
+							    ints);
 						return 0;
-					} else if (configs[i].dma == configs[j].dma) {
-						setup_error("duplicated DMA channel!", ints);
+					}
+					if (configs[i].dma == configs[j].dma) {
+						setup_error("duplicated DMA "
+							    "channel!", ints);
 						return 0;
-					} else if (configs[i].iobase == configs[j].iobase) {
-						setup_error ("duplicated I/O base address!", ints);
+					}
+					if (configs[i].iobase ==
+					    configs[j].iobase) {
+						setup_error("duplicated I/O "
+							    "base address!",
+							    ints);
 						return 0;
 					}
+			}
 		}
 
-#ifdef WD7000_DEBUG
-		printk ("wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, BUS_ON=%dns, BUS_OFF=%dns\n",
+		dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, "
+				  "BUS_ON=%dns, BUS_OFF=%dns\n",
 			configs[wd7000_card_num].irq,
 			configs[wd7000_card_num].dma,
 			configs[wd7000_card_num].iobase,
 			configs[wd7000_card_num].bus_on * 125,
 			configs[wd7000_card_num].bus_off * 125);
-#endif
 
 		wd7000_card_num++;
 	}
@@ -811,7 +835,7 @@
 	return (1);
     }
 
-    printk ("wd7000 command_out: WAIT failed(%d)\n", len + 1);
+    printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1);
 
     return (0);
 }
@@ -827,7 +851,7 @@
  *  the satisfiability of a request is not dependent on the size of the
  *  request.
  */
-static inline Scb *alloc_scbs (int needed)
+static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
 {
     register Scb *scb, *p;
     register unsigned long flags;
@@ -842,18 +866,18 @@
     save_flags (flags);
     cli ();
     while (busy) {		/* someone else is allocating */
-	spin_unlock_irq(&io_request_lock);
+	spin_unlock_irq(&host->host_lock);
 	for (now = jiffies; now == jiffies; );	/* wait a jiffy */
-	spin_lock_irq(&io_request_lock);
+	spin_lock_irq(&host->host_lock);
     }
     busy = 1;			/* not busy now; it's our turn */
 
     while (freescbs < needed) {
 	timeout = jiffies + WAITnexttimeout;
 	do {
-	    spin_unlock_irq(&io_request_lock);
+	    spin_unlock_irq(&host->host_lock);
 	    for (now = jiffies; now == jiffies; );	/* wait a jiffy */
-	    spin_lock_irq(&io_request_lock);
+	    spin_lock_irq(&host->host_lock);
 	} while (freescbs < needed && time_before_eq(jiffies, timeout));
 	/*
 	 *  If we get here with enough free Scbs, we can take them.
@@ -929,9 +953,7 @@
     Mailbox *ogmbs = host->mb.ogmb;
     int *next_ogmb = &(host->next_ogmb);
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_mail_out: 0x%06lx", (long) scbptr);
-#endif
+    dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
 
     /* We first look for a free outgoing mailbox */
     save_flags (flags);
@@ -939,9 +961,7 @@
     ogmb = *next_ogmb;
     for (i = 0; i < OGMB_CNT; i++) {
 	if (ogmbs[ogmb].status == 0) {
-#ifdef WD7000_DEBUG
-	    printk (" using OGMB 0x%x", ogmb);
-#endif
+	    dprintk(" using OGMB 0x%x", ogmb);
 	    ogmbs[ogmb].status = 1;
 	    any2scsi ((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
 
@@ -953,9 +973,7 @@
     }
     restore_flags (flags);
 
-#ifdef WD7000_DEBUG
-    printk (", scb is 0x%06lx", (long) scbptr);
-#endif
+    dprintk(", scb is 0x%06lx", (long) scbptr);
 
     if (i >= OGMB_CNT) {
 	/*
@@ -966,9 +984,7 @@
 	 *  that marks OGMB's free, waiting even with interrupts off
 	 *  should work, since they are freed very quickly in most cases.
 	 */
-#ifdef WD7000_DEBUG
-	printk (", no free OGMBs.\n");
-#endif
+	dprintk(", no free OGMBs.\n");
 	return (0);
     }
 
@@ -977,9 +993,7 @@
     start_ogmb = START_OGMB | ogmb;
     command_out (host, &start_ogmb, 1);
 
-#ifdef WD7000_DEBUG
-    printk (", awaiting interrupt.\n");
-#endif
+    dprintk(", awaiting interrupt.\n");
 
     return (1);
 }
@@ -1026,7 +1040,7 @@
     }
 #ifdef WD7000_DEBUG
     if (scsierr || hosterr)
-	printk ("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
+	dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n",
 		scsierr, in_error, hosterr);
 #endif
     return (scsierr | (hosterr << 16));
@@ -1035,10 +1049,7 @@
 
 static void wd7000_scsi_done (Scsi_Cmnd *SCpnt)
 {
-#ifdef WD7000_DEBUG
-    printk ("wd7000_scsi_done: 0x%06lx\n", (long) SCpnt);
-#endif
-
+    dprintk("wd7000_scsi_done: 0x%06lx\n", (long)SCpnt);
     SCpnt->SCp.phase = 0;
 }
 
@@ -1057,15 +1068,11 @@
 
     host->int_counter++;
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
-#endif
+    dprintk("wd7000_intr_handle: irq = %d, host = 0x%06lx\n", irq, (long) host);
 
     flag = inb (host->iobase + ASC_INTR_STAT);
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
-#endif
+    dprintk("wd7000_intr_handle: intr stat = 0x%02x\n", flag);
 
     if (!(inb (host->iobase + ASC_STAT) & INT_IM)) {
 	/* NB: these are _very_ possible if IRQ 15 is being used, since
@@ -1076,9 +1083,7 @@
 	 * can sort these out.  Otherwise, electrical noise and other such
 	 * problems would be indistinguishable from valid interrupts...
 	 */
-#ifdef WD7000_DEBUG
-	printk ("wd7000_intr_handle: phantom interrupt...\n");
-#endif
+	dprintk("wd7000_intr_handle: phantom interrupt...\n");
 	wd7000_intr_ack (host);
 	return;
     }
@@ -1086,9 +1091,7 @@
     if (flag & MB_INTR) {
 	/* The interrupt is for a mailbox */
 	if (!(flag & IMB_INTR)) {
-#ifdef WD7000_DEBUG
-	    printk ("wd7000_intr_handle: free outgoing mailbox\n");
-#endif
+	    dprintk("wd7000_intr_handle: free outgoing mailbox\n");
 	    /*
 	     * If sleep_on() and the "interrupt on free OGMB" command are
 	     * used in mail_out(), wake_up() should correspondingly be called
@@ -1102,10 +1105,8 @@
 	    icmb = flag & MB_MASK;
 	    icmb_status = icmbs[icmb].status;
 	    if (icmb_status & 0x80) {	/* unsolicited - result in ICMB */
-#ifdef WD7000_DEBUG
-		printk ("wd7000_intr_handle: unsolicited interrupt 0x%02x\n",
+		dprintk("wd7000_intr_handle: unsolicited interrupt 0x%02x\n",
 			icmb_status);
-#endif
 		wd7000_intr_ack (host);
 		return;
 	    }
@@ -1135,18 +1136,17 @@
 
     wd7000_intr_ack (host);
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_intr_handle: return from interrupt handler\n");
-#endif
+    dprintk("wd7000_intr_handle: return from interrupt handler\n");
 }
 
 void do_wd7000_intr_handle (int irq, void *dev_id, struct pt_regs *regs)
 {
     unsigned long flags;
+    struct Scsi_Host *host = dev_id;
 
-    spin_lock_irqsave(&io_request_lock, flags);
+    spin_lock_irqsave(&host->host_lock, flags);
     wd7000_intr_handle(irq, dev_id, regs);
-    spin_unlock_irqrestore(&io_request_lock, flags);
+    spin_unlock_irqrestore(&host->host_lock, flags);
 }
 
 
@@ -1163,7 +1163,7 @@
     idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7);
     SCpnt->scsi_done = done;
     SCpnt->SCp.phase = 1;
-    scb = alloc_scbs (1);
+    scb = alloc_scbs(SCpnt->host, 1);
     scb->idlun = idlun;
     memcpy (scb->cdb, cdb, cdblen);
     scb->direc = 0x40;		/* Disable direction check */
@@ -1179,9 +1179,7 @@
 	if (SCpnt->host->sg_tablesize == SG_NONE) {
 	    panic ("wd7000_queuecommand: scatter/gather not supported.\n");
 	}
-#ifdef WD7000_DEBUG
-	printk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
-#endif
+	dprintk ("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
 
 	sgb = scb->sgb;
 	scb->op = 1;
@@ -1367,14 +1365,12 @@
     save_flags (flags);
     cli ();
 
-#ifdef WD7000_DEBUG
-    printk ("Buffer = <%.*s>, length = %d\n", length, buffer, length);
-#endif
+    dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
 
     /*
      * Currently this is a no-op
      */
-    printk ("Sorry, this function is currently out of order...\n");
+    dprintk("Sorry, this function is currently out of order...\n");
 
     restore_flags (flags);
 
@@ -1521,9 +1517,7 @@
     Adapter *host = NULL;
     struct Scsi_Host *sh;
 
-#ifdef WD7000_DEBUG
-    printk ("wd7000_detect: started\n");
-#endif
+    dprintk("wd7000_detect: started\n");
 
 #ifdef MODULE
 	if (wd7000)
@@ -1573,12 +1567,12 @@
 	 * BIOS SIGNATURE has been found.
 	 */
 #ifdef WD7000_DEBUG
-	printk ("wd7000_detect: pass %d\n", pass + 1);
+	dprintk("wd7000_detect: pass %d\n", pass + 1);
 
 	if (biosaddr_ptr == NUM_ADDRS)
-	    printk ("WD-7000 SST BIOS not detected...\n");
+	    dprintk("WD-7000 SST BIOS not detected...\n");
 	else
-	    printk ("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
+	    dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n",
 		    wd7000_biosaddr[biosaddr_ptr]);
 #endif
 
@@ -1587,15 +1581,11 @@
 
 	iobase = configs[pass].iobase;
 
-#ifdef WD7000_DEBUG
-	printk ("wd7000_detect: check IO 0x%x region...\n", iobase);
-#endif
+	dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);
 
 	if (request_region (iobase, 4, "wd7000")) {
 
-#ifdef WD7000_DEBUG
-	    printk ("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
-#endif
+	    dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
 	    /*
 	     * ASC reset...
 	     */
@@ -1603,17 +1593,11 @@
 	    delay (1);
 	    outb (0, iobase + ASC_CONTROL);
 
-	    if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0))
-#ifdef WD7000_DEBUG
-	    {
-		printk ("failed!\n");
+	    if (WAIT (iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+		dprintk("failed!\n");
 		goto err_release;
-	    }
-	    else 
-		printk ("ok!\n");
-#else
-	    goto err_release;
-#endif
+	    } else 
+		dprintk("ok!\n");
 
 	    if (inb (iobase + ASC_INTR_STAT) == 1) {
 		/*
@@ -1629,10 +1613,8 @@
 
 		host = (Adapter *) sh->hostdata;
 
-#ifdef WD7000_DEBUG
-		printk ("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
-#endif
-
+		dprintk("wd7000_detect: adapter allocated at 0x%x\n",
+			(int)host);
 		memset (host, 0, sizeof (Adapter));
 
 		host->irq = configs[pass].irq;
@@ -1643,11 +1625,9 @@
 		host->bus_off = configs[pass].bus_off;
 		host->sh = wd7000_host[host->irq - IRQ_MIN] = sh;
 
-#ifdef WD7000_DEBUG
-		printk ("wd7000_detect: Trying init WD-7000 card at IO "
+		dprintk("wd7000_detect: Trying init WD-7000 card at IO "
 			"0x%x, IRQ %d, DMA %d...\n",
 			host->iobase, host->irq, host->dma);
-#endif
 
 		if (!wd7000_init (host)) 	/* Initialization failed */
 		    goto err_unregister;
@@ -1675,12 +1655,9 @@
                 printk ("  BUS_ON time: %dns, BUS_OFF time: %dns\n",
                         host->bus_on * 125, host->bus_off * 125);
 	    }
-	}
-
-#ifdef WD7000_DEBUG
-	else
-	    printk ("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
-#endif
+	} else
+		dprintk("wd7000_detect: IO 0x%x region already allocated!\n",
+			iobase);
 
 	continue;
 
@@ -1730,9 +1707,8 @@
  */
 int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip)
 {
-#ifdef WD7000_DEBUG
-    printk ("wd7000_biosparam: dev=%s, size=%d, ", kdevname (dev), disk->capacity);
-#endif
+    dprintk("wd7000_biosparam: dev=%s, size=%d, ", kdevname(dev),
+	    disk->capacity);
 
     /*
      * try default translation
@@ -1766,14 +1742,13 @@
 	    ip[2] = info[2];
 
 	    if (info[0] == 255)
-		printk ("wd7000_biosparam: current partition table is using extended translation.\n");
+		printk(KERN_INFO __FUNCTION__ ": current partition table is "
+			"using extended translation.\n");
 	}
     }
 
-#ifdef WD7000_DEBUG
-    printk ("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
-    printk ("WARNING: check, if the bios geometry is correct.\n");
-#endif
+    dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
+    dprintk("WARNING: check, if the bios geometry is correct.\n");
 
     return (0);
 }
diff -urN linux-2.5.2-pre5/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- linux-2.5.2-pre5/drivers/sound/es1371.c	Sun Sep 30 12:26:08 2001
+++ linux/drivers/sound/es1371.c	Tue Jan  1 14:04:28 2002
@@ -1213,7 +1213,7 @@
 
 static int es1371_open_mixdev(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct list_head *list;
 	struct es1371_state *s;
 
@@ -1913,7 +1913,7 @@
 
 static int es1371_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct list_head *list;
@@ -2342,7 +2342,7 @@
 
 static int es1371_open_dac(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct list_head *list;
@@ -2584,7 +2584,7 @@
 
 static int es1371_midi_open(struct inode *inode, struct file *file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
 	struct list_head *list;
diff -urN linux-2.5.2-pre5/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c
--- linux-2.5.2-pre5/drivers/sound/sound_core.c	Sun Nov 25 10:17:47 2001
+++ linux/drivers/sound/sound_core.c	Tue Jan  1 14:04:28 2002
@@ -478,7 +478,7 @@
 int soundcore_open(struct inode *inode, struct file *file)
 {
 	int chain;
-	int unit=MINOR(inode->i_rdev);
+	int unit = minor(inode->i_rdev);
 	struct sound_unit *s;
 	struct file_operations *new_fops = NULL;
 
diff -urN linux-2.5.2-pre5/drivers/usb/audio.c linux/drivers/usb/audio.c
--- linux-2.5.2-pre5/drivers/usb/audio.c	Sat Dec  8 20:28:44 2001
+++ linux/drivers/usb/audio.c	Tue Jan  1 14:04:28 2002
@@ -833,7 +833,7 @@
 	}
 }		
 
-static int usbin_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_prepare_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i, maxsize, offs;
 
@@ -850,7 +850,7 @@
  * return value: 0 if descriptor should be restarted, -1 otherwise
  * convert sample format on the fly if necessary
  */
-static int usbin_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_retire_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, dmafree;
 	unsigned char *cp;
@@ -930,7 +930,7 @@
 /*
  * we output sync data
  */
-static int usbin_sync_prepare_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_prepare_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
 	unsigned int i, offs;
@@ -948,7 +948,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbin_sync_retire_desc(struct usbin *u, purb_t urb)
+static int usbin_sync_retire_desc(struct usbin *u, struct urb *urb)
 {
 	unsigned int i;
 	
@@ -996,7 +996,7 @@
 {
 	struct usb_device *dev = as->state->usbdev;
 	struct usbin *u = &as->usbin;
-	purb_t urb;
+	struct urb *urb;
 	unsigned long flags;
 	unsigned int maxsze, bufsz;
 
@@ -1186,7 +1186,7 @@
 	}
 }		
 
-static int usbout_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_prepare_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i, ufmtsh, dfmtsh, err = 0, cnt, scnt, offs;
 	unsigned char *cp = urb->transfer_buffer;
@@ -1238,7 +1238,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_retire_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i;
 
@@ -1285,7 +1285,7 @@
 	spin_unlock_irqrestore(&as->lock, flags);
 }
 
-static int usbout_sync_prepare_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_prepare_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned int i, offs;
 
@@ -1299,7 +1299,7 @@
 /*
  * return value: 0 if descriptor should be restarted, -1 otherwise
  */
-static int usbout_sync_retire_desc(struct usbout *u, purb_t urb)
+static int usbout_sync_retire_desc(struct usbout *u, struct urb *urb)
 {
 	unsigned char *cp = urb->transfer_buffer;
 	unsigned int f, i;
@@ -1361,7 +1361,7 @@
 {
 	struct usb_device *dev = as->state->usbdev;
 	struct usbout *u = &as->usbout;
-	purb_t urb;
+	struct urb *urb;
 	unsigned long flags;
 	unsigned int maxsze, bufsz;
 
diff -urN linux-2.5.2-pre5/drivers/usb/dabusb.c linux/drivers/usb/dabusb.c
--- linux-2.5.2-pre5/drivers/usb/dabusb.c	Fri Nov 30 08:26:04 2001
+++ linux/drivers/usb/dabusb.c	Tue Jan  1 14:04:28 2002
@@ -83,24 +83,24 @@
 }
 /*-------------------------------------------------------------------*/
 #ifdef DEBUG 
-static void dump_urb (purb_t purb)
+static void dump_urb (struct urb *urb)
 {
-	dbg("urb                   :%p", purb);
-	dbg("next                  :%p", purb->next);
-	dbg("dev                   :%p", purb->dev);
-	dbg("pipe                  :%08X", purb->pipe);
-	dbg("status                :%d", purb->status);
-	dbg("transfer_flags        :%08X", purb->transfer_flags);
-	dbg("transfer_buffer       :%p", purb->transfer_buffer);
-	dbg("transfer_buffer_length:%d", purb->transfer_buffer_length);
-	dbg("actual_length         :%d", purb->actual_length);
-	dbg("setup_packet          :%p", purb->setup_packet);
-	dbg("start_frame           :%d", purb->start_frame);
-	dbg("number_of_packets     :%d", purb->number_of_packets);
-	dbg("interval              :%d", purb->interval);
-	dbg("error_count           :%d", purb->error_count);
-	dbg("context               :%p", purb->context);
-	dbg("complete              :%p", purb->complete);
+	dbg("urb                   :%p", urb);
+	dbg("next                  :%p", urb->next);
+	dbg("dev                   :%p", urb->dev);
+	dbg("pipe                  :%08X", urb->pipe);
+	dbg("status                :%d", urb->status);
+	dbg("transfer_flags        :%08X", urb->transfer_flags);
+	dbg("transfer_buffer       :%p", urb->transfer_buffer);
+	dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);
+	dbg("actual_length         :%d", urb->actual_length);
+	dbg("setup_packet          :%p", urb->setup_packet);
+	dbg("start_frame           :%d", urb->start_frame);
+	dbg("number_of_packets     :%d", urb->number_of_packets);
+	dbg("interval              :%d", urb->interval);
+	dbg("error_count           :%d", urb->error_count);
+	dbg("context               :%p", urb->context);
+	dbg("complete              :%p", urb->complete);
 }
 #endif
 /*-------------------------------------------------------------------*/
@@ -167,7 +167,7 @@
 	return 0;
 }
 /*-------------------------------------------------------------------*/
-static void dabusb_iso_complete (purb_t purb)
+static void dabusb_iso_complete (struct urb *purb)
 {
 	pbuff_t b = purb->context;
 	pdabusb_t s = b->s;
@@ -482,7 +482,7 @@
 	int rem;
 	int cnt;
 	pbuff_t b;
-	purb_t purb = NULL;
+	struct urb *purb = NULL;
 
 	dbg("dabusb_read");
 
diff -urN linux-2.5.2-pre5/drivers/usb/dabusb.h linux/drivers/usb/dabusb.h
--- linux-2.5.2-pre5/drivers/usb/dabusb.h	Tue Oct  3 09:24:40 2000
+++ linux/drivers/usb/dabusb.h	Tue Jan  1 14:04:28 2002
@@ -38,7 +38,7 @@
 typedef struct 
 {
 	pdabusb_t s;
-	purb_t purb;
+	struct urb *purb;
 	struct list_head buff_list;
 } buff_t,*pbuff_t;
 
diff -urN linux-2.5.2-pre5/drivers/usb/devio.c linux/drivers/usb/devio.c
--- linux-2.5.2-pre5/drivers/usb/devio.c	Sat Dec  8 20:28:44 2001
+++ linux/drivers/usb/devio.c	Tue Jan  1 14:04:28 2002
@@ -245,7 +245,7 @@
         return NULL;
 }
 
-static void async_completed(purb_t urb)
+static void async_completed(struct urb *urb)
 {
         struct async *as = (struct async *)urb->context;
         struct dev_state *ps = as->ps;
@@ -471,9 +471,7 @@
 	 */
 	lock_kernel();
 	ret = -ENOENT;
-	if (ITYPE(inode->i_ino) != IDEVICE)
-		goto out;
-	dev = inode->u.usbdev_i.p.dev;
+	dev = inode->u.generic_ip;
 	if (!dev)
 		goto out;
 	ret = -ENOMEM;
diff -urN linux-2.5.2-pre5/drivers/usb/hcd/Config.in linux/drivers/usb/hcd/Config.in
--- linux-2.5.2-pre5/drivers/usb/hcd/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/Config.in	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,7 @@
+#
+# USB Host Controller Drivers
+#
+dep_tristate '  EHCI HCD (USB 2.0) support (EXPERIMENTAL)' CONFIG_EHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+# dep_tristate '  OHCI HCD support (EXPERIMENTAL)' CONFIG_OHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+# dep_tristate '  UHCI HCD (most Intel and VIA) support (EXPERIMENTAL)' CONFIG_UHCI_HCD $CONFIG_USB $CONFIG_EXPERIMENTAL
+
diff -urN linux-2.5.2-pre5/drivers/usb/hcd/Makefile linux/drivers/usb/hcd/Makefile
--- linux-2.5.2-pre5/drivers/usb/hcd/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/Makefile	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,27 @@
+#
+# Makefile for USB Host Controller Driver
+# framework and drivers
+#
+
+O_TARGET	:=
+
+obj-$(CONFIG_EHCI_HCD)			+= ehci-hcd.o
+# obj-$(CONFIG_OHCI_HCD)			+= ohci-hcd.o
+# obj-$(CONFIG_UHCI_HCD)			+= uhci-hcd.o
+
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Take multi-part drivers out of obj-y and put components in.
+obj-y		:= $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+OX_OBJS		:= $(obj-y)
+MX_OBJS		:= $(obj-m)
+MIX_OBJS	:= $(int-m)
+
+include $(TOPDIR)/Rules.make
diff -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-dbg.c linux/drivers/usb/hcd/ehci-dbg.c
--- linux-2.5.2-pre5/drivers/usb/hcd/ehci-dbg.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-dbg.c	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+#ifdef EHCI_VERBOSE_DEBUG
+#	define vdbg dbg
+#else
+	static inline void vdbg (char *fmt, ...) { }
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCSPARAMS register - host controller structural parameters */
+/* see EHCI 0.95 Spec, Table 2-4 for each value */
+static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
+{
+	u32	params = readl (&ehci->caps->hcs_params);
+
+	dbg ("%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d",
+		label, params,
+		HCS_DEBUG_PORT (params),
+		HCS_INDICATOR (params) ? " ind" : "",
+		HCS_N_CC (params),
+		HCS_N_PCC (params),
+	        HCS_PORTROUTED (params) ? "" : " ordered",
+		HCS_PPC (params) ? "" : " !ppc",
+		HCS_N_PORTS (params)
+		);
+	/* Port routing, per EHCI 0.95 Spec, Section 2.2.5 */
+	if (HCS_PORTROUTED (params)) {
+		int i;
+		char buf [46], tmp [7], byte;
+
+		buf[0] = 0;
+		for (i = 0; i < HCS_N_PORTS (params); i++) {
+			byte = readb (&ehci->caps->portroute[(i>>1)]);
+			sprintf(tmp, "%d ", 
+				((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
+			strcat(buf, tmp);
+		}
+		dbg ("%s: %s portroute %s", 
+			ehci->hcd.bus_name, label,
+			buf);
+	}
+}
+#else
+
+static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+/* check the values in the HCCPARAMS register - host controller capability parameters */
+/* see EHCI 0.95 Spec, Table 2-5 for each value */
+static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
+{
+	u32	params = readl (&ehci->caps->hcc_params);
+
+	if (HCC_EXT_CAPS (params)) {
+		// EHCI 0.96 ... could interpret these (legacy?)
+		dbg ("%s extended capabilities at pci %d",
+			label, HCC_EXT_CAPS (params));
+	}
+	if (HCC_ISOC_CACHE (params)) {
+		dbg ("%s hcc_params 0x%04x caching frame %s%s%s",
+		     label, params,
+		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+		     HCC_CANPARK (params) ? " park" : "",
+		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+	} else {
+		dbg ("%s hcc_params 0x%04x caching %d uframes %s%s%s",
+		     label,
+		     params,
+		     HCC_ISOC_THRES (params),
+		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
+		     HCC_CANPARK (params) ? " park" : "",
+		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+	}
+}
+#else
+
+static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
+
+#endif
+
+#ifdef	DEBUG
+
+#if 0
+static void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	dbg ("%s %p info1 %x info2 %x hw_curr %x qtd_next %x", label,
+		qh, qh->hw_info1, qh->hw_info2,
+		qh->hw_current, qh->hw_qtd_next);
+	dbg ("  alt+errs= %x, token= %x, page0= %x, page1= %x",
+		qh->hw_alt_next, qh->hw_token,
+		qh->hw_buf [0], qh->hw_buf [1]);
+	if (qh->hw_buf [2]) {
+		dbg ("  page2= %x, page3= %x, page4= %x",
+			qh->hw_buf [2], qh->hw_buf [3],
+			qh->hw_buf [4]);
+	}
+}
+#endif
+
+static const char *const fls_strings [] =
+    { "1024", "512", "256", "??" };
+
+#else
+#if 0
+static inline void dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) {}
+#endif
+#endif	/* DEBUG */
+
+/* functions have the "wrong" filename when they're output... */
+
+#define dbg_status(ehci, label, status) \
+	dbg ("%s status 0x%x%s%s%s%s%s%s%s%s%s%s", \
+		label, status, \
+		(status & STS_ASS) ? " Async" : "", \
+		(status & STS_PSS) ? " Periodic" : "", \
+		(status & STS_RECL) ? " Recl" : "", \
+		(status & STS_HALT) ? " Halt" : "", \
+		(status & STS_IAA) ? " IAA" : "", \
+		(status & STS_FATAL) ? " FATAL" : "", \
+		(status & STS_FLR) ? " FLR" : "", \
+		(status & STS_PCD) ? " PCD" : "", \
+		(status & STS_ERR) ? " ERR" : "", \
+		(status & STS_INT) ? " INT" : "" \
+		)
+
+#define dbg_cmd(ehci, label, command) \
+	dbg ("%s %x cmd %s=%d ithresh=%d%s%s%s%s period=%s%s %s", \
+		label, command, \
+		(command & CMD_PARK) ? "park" : "(park)", \
+		CMD_PARK_CNT (command), \
+		(command >> 16) & 0x3f, \
+		(command & CMD_LRESET) ? " LReset" : "", \
+		(command & CMD_IAAD) ? " IAAD" : "", \
+		(command & CMD_ASE) ? " Async" : "", \
+		(command & CMD_PSE) ? " Periodic" : "", \
+		fls_strings [(command >> 2) & 0x3], \
+		(command & CMD_RESET) ? " Reset" : "", \
+		(command & CMD_RUN) ? "RUN" : "HALT" \
+		)
+
+#define dbg_port(hcd, label, port, status) \
+	dbg ("%s port %d status 0x%x%s%s speed=%d%s%s%s%s%s%s%s%s%s", \
+		label, port, status, \
+		(status & PORT_OWNER) ? " OWNER" : "", \
+		(status & PORT_POWER) ? " POWER" : "", \
+		(status >> 10) & 3, \
+		(status & PORT_RESET) ? " RESET" : "", \
+		(status & PORT_SUSPEND) ? " SUSPEND" : "", \
+		(status & PORT_RESUME) ? " RESUME" : "", \
+		(status & PORT_OCC) ? " OCC" : "", \
+		(status & PORT_OC) ? " OC" : "", \
+		(status & PORT_PEC) ? " PEC" : "", \
+		(status & PORT_PE) ? " PE" : "", \
+		(status & PORT_CSC) ? " CSC" : "", \
+		(status & PORT_CONNECT) ? " CONNECT" : "" \
+	    )
+
diff -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-hcd.c linux/drivers/usb/hcd/ehci-hcd.c
--- linux-2.5.2-pre5/drivers/usb/hcd/ehci-hcd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-hcd.c	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,758 @@
+/*
+ * Copyright (c) 2000-2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+
+#ifndef CONFIG_USB_DEBUG
+	#define CONFIG_USB_DEBUG	/* this is still experimental! */
+#endif
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "../hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+//#undef KERN_DEBUG
+//#define KERN_DEBUG ""
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hc_driver implementation ... experimental, incomplete.
+ * Based on the 0.96 register interface specification.
+ *
+ * There are lots of things to help out with here ... notably
+ * everything "periodic", and of course testing with all sorts
+ * of usb 2.0 devices and configurations.
+ *
+ * USB 2.0 shows up in upcoming www.pcmcia.org technology.
+ * First was PCMCIA, like ISA; then CardBus, which is PCI.
+ * Next comes "CardBay", using USB 2.0 signals.
+ *
+ * Contains additional contributions by:
+ *	Brad Hards
+ *	Rory Bolt
+ *	...
+ */
+
+#define DRIVER_VERSION "$Revision: 0.25 $"
+#define DRIVER_AUTHOR "David Brownell"
+#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
+
+
+// #define EHCI_VERBOSE_DEBUG
+// #define have_iso
+
+#ifdef	DEBUG
+#	define	EHCI_SLAB_FLAGS		(SLAB_POISON)
+#else
+#	define	EHCI_SLAB_FLAGS		0
+#endif
+
+/* magic numbers that can affect system performance */
+#define	EHCI_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */
+#define	EHCI_TUNE_RL_HS		0	/* nak throttle; see 4.9 */
+#define	EHCI_TUNE_RL_TT		0
+#define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
+#define	EHCI_TUNE_MULT_TT	1
+
+/* Initial IRQ latency:  lower than default */
+static int log2_irq_thresh = 0;		// 0 to 6
+MODULE_PARM (log2_irq_thresh, "i");
+MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
+
+/* Some A steppings of the NEC controller need soft retries */
+//#define	EHCI_SOFT_RETRIES	5	/* after CERR-induced fault */
+
+#define	INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
+
+/*-------------------------------------------------------------------------*/
+
+#include "ehci.h"
+#include "ehci-dbg.c"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * hc states include: unknown, halted, ready, running
+ * transitional states are messy just now
+ * trying to avoid "running" unless urbs are active
+ * a "ready" hc can be finishing prefetched work
+ */
+
+/* halt a non-running controller */
+static void ehci_reset (struct ehci_hcd *ehci)
+{
+	u32	command = readl (&ehci->regs->command);
+
+	command |= CMD_RESET;
+	dbg_cmd (ehci, "reset", command);
+	writel (command, &ehci->regs->command);
+	while (readl (&ehci->regs->command) & CMD_RESET)
+		continue;
+	ehci->hcd.state = USB_STATE_HALT;
+}
+
+/* idle the controller (from running) */
+static void ehci_ready (struct ehci_hcd *ehci)
+{
+	u32	command;
+
+#ifdef DEBUG
+	if (!HCD_IS_RUNNING (ehci->hcd.state))
+		BUG ();
+#endif
+
+	while (!(readl (&ehci->regs->status) & (STS_ASS | STS_PSS)))
+		udelay (100);
+	command = readl (&ehci->regs->command);
+	command &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
+	writel (command, &ehci->regs->command);
+
+	// hardware can take 16 microframes to turn off ...
+	ehci->hcd.state = USB_STATE_READY;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#include "ehci-hub.c"
+#include "ehci-mem.c"
+#include "ehci-q.c"
+#include "ehci-sched.c"
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_tasklet (unsigned long param);
+
+/* called by khubd or root hub init threads */
+
+static int ehci_start (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			temp;
+	struct usb_device	*udev;
+	int			retval;
+	u32			hcc_params;
+	u8                      tempbyte;
+
+	// FIXME:  given EHCI 0.96 or later, and a controller with
+	// the USBLEGSUP/USBLEGCTLSTS extended capability, make sure
+	// the BIOS doesn't still own this controller.
+
+	spin_lock_init (&ehci->lock);
+
+	ehci->caps = (struct ehci_caps *) hcd->regs;
+	ehci->regs = (struct ehci_regs *) (hcd->regs + ehci->caps->length);
+	dbg_hcs_params (ehci, "ehci_start");
+	dbg_hcc_params (ehci, "ehci_start");
+
+	/*
+	 * hw default: 1K periodic list heads, one per frame.
+	 * periodic_size can shrink by USBCMD update if hcc_params allows.
+	 */
+	ehci->periodic_size = DEFAULT_I_TDPS;
+	if ((retval = ehci_mem_init (ehci, EHCI_SLAB_FLAGS | SLAB_KERNEL)) < 0)
+		return retval;
+	hcc_params = readl (&ehci->caps->hcc_params);
+
+	/* controllers may cache some of the periodic schedule ... */
+	if (HCC_ISOC_CACHE (hcc_params)) 	// full frame cache
+		ehci->i_thresh = 8;
+	else					// N microframes cached
+		ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
+
+	ehci->async = 0;
+	ehci->reclaim = 0;
+	ehci->next_frame = -1;
+
+	/* controller state:  unknown --> reset */
+
+	/* EHCI spec section 4.1 */
+	ehci_reset (ehci);
+	writel (INTR_MASK, &ehci->regs->intr_enable);
+	writel (ehci->periodic_dma, &ehci->regs->frame_list);
+
+	/*
+	 * hcc_params controls whether ehci->regs->segment must (!!!)
+	 * be used; it constrains QH/ITD/SITD and QTD locations.
+	 * By default, pci_alloc_consistent() won't hand out addresses
+	 * above 4GB (via pdev->dma_mask) so we know this value.
+	 *
+	 * NOTE:  that pdev->dma_mask setting means that all DMA mappings
+	 * for I/O buffers will have the same restriction, though it's
+	 * neither necessary nor desirable in that case.
+	 */
+	if (HCC_64BIT_ADDR (hcc_params)) {
+		writel (0, &ehci->regs->segment);
+		info ("using segment 0 for 64bit DMA addresses ...");
+	}
+
+	/* clear interrupt enables, set irq latency */
+	temp = readl (&ehci->regs->command) & 0xff;
+	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
+	    log2_irq_thresh = 0;
+	temp |= 1 << (16 + log2_irq_thresh);
+	// keeping default periodic framelist size
+	temp &= ~(CMD_IAAD | CMD_ASE | CMD_PSE),
+	writel (temp, &ehci->regs->command);
+	dbg_cmd (ehci, "init", temp);
+
+	/* set async sleep time = 10 us ... ? */
+
+	ehci->tasklet.func = ehci_tasklet;
+	ehci->tasklet.data = (unsigned long) ehci;
+
+	/* wire up the root hub */
+	hcd->bus->root_hub = udev = usb_alloc_dev (NULL, hcd->bus);
+	if (!udev) {
+done2:
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
+	 * are explicitly handed to companion controller(s), so no TT is
+	 * involved with the root hub.
+	 */
+	ehci->hcd.state = USB_STATE_READY;
+	writel (FLAG_CF, &ehci->regs->configured_flag);
+	readl (&ehci->regs->command);	/* unblock posted write */
+
+        /* PCI Serial Bus Release Number is at 0x60 offset */
+	pci_read_config_byte(hcd->pdev, 0x60, &tempbyte);
+	temp = readw (&ehci->caps->hci_version);
+	info ("USB %x.%x support enabled, EHCI rev %x.%2x",
+	      ((tempbyte & 0xf0)>>4),
+	      (tempbyte & 0x0f),
+	       temp >> 8,
+	       temp & 0xff);
+
+	/*
+	 * From here on, khubd concurrently accesses the root
+	 * hub; drivers will be talking to enumerated devices.
+	 *
+	 * Before this point the HC was idle/ready.  After, khubd
+	 * and device drivers may start it running.
+	 */
+	usb_connect (udev);
+	udev->speed = USB_SPEED_HIGH;
+	if (usb_new_device (udev) != 0) {
+		if (hcd->state == USB_STATE_RUNNING)
+			ehci_ready (ehci);
+		while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
+			udelay (100);
+		ehci_reset (ehci);
+		// usb_disconnect (udev); 
+		hcd->bus->root_hub = 0;
+		usb_free_dev (udev); 
+		retval = -ENODEV;
+		goto done2;
+	}
+
+	return 0;
+}
+
+/* always called by thread; normally rmmod */
+
+static void ehci_stop (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+
+	dbg ("%s: stop", hcd->bus_name);
+
+	if (hcd->state == USB_STATE_RUNNING)
+		ehci_ready (ehci);
+	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
+		udelay (100);
+	ehci_reset (ehci);
+
+	// root hub is shut down separately (first, when possible)
+	scan_async (ehci);
+	if (ehci->next_frame != -1)
+		scan_periodic (ehci);
+	ehci_mem_cleanup (ehci);
+
+	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+}
+
+static int ehci_get_frame (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+/* suspend/resume, section 4.3 */
+
+static int ehci_suspend (struct usb_hcd *hcd, u32 state)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			params;
+	int			ports;
+	int			i;
+
+	dbg ("%s: suspend to %d", hcd->bus_name, state);
+
+	params = readl (&ehci->caps->hcs_params);
+	ports = HCS_N_PORTS (params);
+
+	// FIXME:  This assumes what's probably a D3 level suspend...
+
+	// FIXME:  usb wakeup events on this bus should resume the machine.
+	// pci config register PORTWAKECAP controls which ports can do it;
+	// bios may have initted the register...
+
+	/* suspend each port, then stop the hc */
+	for (i = 0; i < ports; i++) {
+		int	temp = readl (&ehci->regs->port_status [i]);
+
+		if ((temp & PORT_PE) == 0
+				|| (temp & PORT_OWNER) != 0)
+			continue;
+dbg ("%s: suspend port %d", hcd->bus_name, i);
+		temp |= PORT_SUSPEND;
+		writel (temp, &ehci->regs->port_status [i]);
+	}
+
+	if (hcd->state == USB_STATE_RUNNING)
+		ehci_ready (ehci);
+	while (readl (&ehci->regs->status) & (STS_ASS | STS_PSS))
+		udelay (100);
+	writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command);
+
+// save pci FLADJ value
+
+	/* who tells PCI to reduce power consumption? */
+
+	return 0;
+}
+
+static int ehci_resume (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			params;
+	int			ports;
+	int			i;
+
+	dbg ("%s: resume", hcd->bus_name);
+
+	params = readl (&ehci->caps->hcs_params);
+	ports = HCS_N_PORTS (params);
+
+	// FIXME:  if controller didn't retain state,
+	// return and let generic code clean it up
+	// test configured_flag ?
+
+	/* resume HC and each port */
+// restore pci FLADJ value
+	// khubd and drivers will set HC running, if needed;
+	hcd->state = USB_STATE_READY;
+	for (i = 0; i < ports; i++) {
+		int	temp = readl (&ehci->regs->port_status [i]);
+
+		if ((temp & PORT_PE) == 0
+				|| (temp & PORT_SUSPEND) != 0)
+			continue;
+dbg ("%s: resume port %d", hcd->bus_name, i);
+		temp |= PORT_RESUME;
+		writel (temp, &ehci->regs->port_status [i]);
+		readl (&ehci->regs->command);	/* unblock posted writes */
+
+		wait_ms (20);
+		temp &= ~PORT_RESUME;
+		writel (temp, &ehci->regs->port_status [i]);
+	}
+	readl (&ehci->regs->command);	/* unblock posted writes */
+	return 0;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * tasklet scheduled by some interrupts and other events
+ * calls driver completion functions ... but not in_irq()
+ */
+static void ehci_tasklet (unsigned long param)
+{
+	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
+
+	if (ehci->reclaim_ready)
+		end_unlink_async (ehci);
+	scan_async (ehci);
+	if (ehci->next_frame != -1)
+		scan_periodic (ehci);
+
+	// FIXME:  when nothing is connected to the root hub,
+	// turn off the RUN bit so the host can enter C3 "sleep" power
+	// saving mode; make root hub code scan memory less often.
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void ehci_irq (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			status = readl (&ehci->regs->status);
+	int			bh = 0;
+
+	/* clear (just) interrupts */
+	status &= INTR_MASK;
+	writel (status, &ehci->regs->status);
+	readl (&ehci->regs->command);	/* unblock posted write */
+
+	if (unlikely (hcd->state == USB_STATE_HALT))	/* irq sharing? */
+		return;
+
+#ifdef	EHCI_VERBOSE_DEBUG
+	/* unrequested/ignored: Port Change Detect, Frame List Rollover */
+	if (status & INTR_MASK)
+		dbg_status (ehci, "irq", status);
+#endif
+
+	/* INT, ERR, and IAA interrupt rates can be throttled */
+
+	/* normal [4.15.1.2] or error [4.15.1.1] completion */
+	if (likely ((status & (STS_INT|STS_ERR)) != 0))
+		bh = 1;
+
+	/* complete the unlinking of some qh [4.15.2.3] */
+	if (status & STS_IAA) {
+		ehci->reclaim_ready = 1;
+		bh = 1;
+	}
+
+	/* PCI errors [4.15.2.4] */
+	if (unlikely ((status & STS_FATAL) != 0)) {
+		err ("%s: fatal error, state %x", hcd->bus_name, hcd->state);
+		ehci_reset (ehci);
+		// generic layer kills/unlinks all urbs
+		// then tasklet cleans up the rest
+		bh = 1;
+	}
+
+	/* most work doesn't need to be in_irq() */
+	if (likely (bh == 1))
+		tasklet_schedule (&ehci->tasklet);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ *
+ * urb + dev is in hcd_dev.urb_list
+ * we're queueing TDs onto software and hardware lists
+ *
+ * hcd-specific init for hcpriv hasn't been done yet
+ *
+ * NOTE:  EHCI queues control and bulk requests transparently, like OHCI.
+ */
+static int ehci_urb_enqueue (
+	struct usb_hcd	*hcd,
+	struct urb	*urb,
+	int		mem_flags
+) {
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	struct list_head	qtd_list;
+
+	urb->transfer_flags &= ~EHCI_STATE_UNLINK;
+	INIT_LIST_HEAD (&qtd_list);
+	switch (usb_pipetype (urb->pipe)) {
+
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		submit_async (ehci, urb, &qtd_list, mem_flags);
+		break;
+
+	case PIPE_INTERRUPT:
+		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
+			return -ENOMEM;
+		return intr_submit (ehci, urb, &qtd_list, mem_flags);
+
+	case PIPE_ISOCHRONOUS:
+#ifdef have_iso
+		if (urb->dev->speed == USB_SPEED_HIGH)
+			return itd_submit (ehci, urb);
+		else
+			return sitd_submit (ehci, urb);
+#else
+		// FIXME highspeed iso stuff is written but never run/tested.
+		// and the split iso support isn't even written yet.
+		dbg ("no iso support yet");
+		return -ENOSYS;
+#endif /* have_iso */
+
+	}
+	return 0;
+}
+
+/* remove from hardware lists
+ * completions normally happen asynchronously
+ */
+
+static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	struct ehci_qh		*qh = (struct ehci_qh *) urb->hcpriv;
+	unsigned long		flags;
+
+	dbg ("%s urb_dequeue %p qh state %d",
+		hcd->bus_name, urb, qh->qh_state);
+
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		spin_lock_irqsave (&ehci->lock, flags);
+		if (ehci->reclaim) {
+dbg ("dq: reclaim busy, %s", RUN_CONTEXT);
+			if (in_interrupt ()) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				return -EAGAIN;
+			}
+			while (qh->qh_state == QH_STATE_LINKED
+					&& ehci->reclaim
+					&& ehci->hcd.state != USB_STATE_HALT
+					) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+// yeech ... this could spin for up to two frames!
+dbg ("wait for dequeue: state %d, reclaim %p, hcd state %d",
+    qh->qh_state, ehci->reclaim, ehci->hcd.state
+);
+				udelay (100);
+				spin_lock_irqsave (&ehci->lock, flags);
+			}
+		}
+		if (qh->qh_state == QH_STATE_LINKED)
+			start_unlink_async (ehci, qh);
+		spin_unlock_irqrestore (&ehci->lock, flags);
+		return 0;
+
+	case PIPE_INTERRUPT:
+		intr_deschedule (ehci, urb->start_frame, qh, urb->interval);
+		if (ehci->hcd.state == USB_STATE_HALT)
+			urb->status = -ESHUTDOWN;
+		qh_completions (ehci, &qh->qtd_list, 1);
+		return 0;
+
+	case PIPE_ISOCHRONOUS:
+		// itd or sitd ...
+
+		// wait till next completion, do it then.
+		// completion irqs can wait up to 128 msec,
+		urb->transfer_flags |= EHCI_STATE_UNLINK;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// bulk qh holds the data toggle
+
+static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
+{
+	struct hcd_dev		*dev = (struct hcd_dev *)udev->hcpriv;
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	int			i;
+	unsigned long		flags;
+
+	/* ASSERT:  nobody can be submitting urbs for this any more */
+
+	dbg ("%s: free_config devnum %d", hcd->bus_name, udev->devnum);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < 32; i++) {
+		if (dev->ep [i]) {
+			struct ehci_qh		*qh;
+
+			// FIXME:  this might be an itd/sitd too ...
+			// or an interrupt urb (not on async list)
+			// can use "union ehci_shadow"
+
+			qh = (struct ehci_qh *) dev->ep [i];
+			vdbg ("free_config, ep 0x%02x qh %p", i, qh);
+			if (!list_empty (&qh->qtd_list)) {
+				dbg ("ep 0x%02x qh %p not empty!", i, qh);
+				BUG ();
+			}
+			dev->ep [i] = 0;
+
+			/* wait_ms() won't spin here -- we're a thread */
+			while (qh->qh_state == QH_STATE_LINKED
+					&& ehci->reclaim
+					&& ehci->hcd.state != USB_STATE_HALT
+					) {
+				spin_unlock_irqrestore (&ehci->lock, flags);
+				wait_ms (1);
+				spin_lock_irqsave (&ehci->lock, flags);
+			}
+			if (qh->qh_state == QH_STATE_LINKED) {
+				start_unlink_async (ehci, qh);
+				while (qh->qh_state != QH_STATE_IDLE) {
+					spin_unlock_irqrestore (&ehci->lock,
+						flags);
+					wait_ms (1);
+					spin_lock_irqsave (&ehci->lock, flags);
+				}
+			}
+			qh_unput (ehci, qh);
+		}
+	}
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const char	hcd_name [] = "ehci-hcd";
+
+static const struct hc_driver ehci_driver = {
+	description:		hcd_name,
+
+	/*
+	 * generic hardware linkage
+	 */
+	irq:			ehci_irq,
+	flags:			HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	start:			ehci_start,
+#ifdef	CONFIG_PM
+	suspend:		ehci_suspend,
+	resume:			ehci_resume,
+#endif
+	stop:			ehci_stop,
+
+	/*
+	 * memory lifecycle (except per-request)
+	 */
+	hcd_alloc:		ehci_hcd_alloc,
+	hcd_free:		ehci_hcd_free,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	urb_enqueue:		ehci_urb_enqueue,
+	urb_dequeue:		ehci_urb_dequeue,
+	free_config:		ehci_free_config,
+
+	/*
+	 * scheduling support
+	 */
+	get_frame_number:	ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	hub_status_data:	ehci_hub_status_data,
+	hub_control:		ehci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI spec says PCI is required. */
+
+/* PCI driver selection metadata; PCI hotplugging uses this */
+static const struct pci_device_id __devinitdata pci_ids [] = { {
+
+	/* handle any USB 2.0 EHCI controller */
+
+	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x20),
+	class_mask: 	~0,
+	driver_data:	(unsigned long) &ehci_driver,
+
+	/* no matter who makes it */
+	vendor:		PCI_ANY_ID,
+	device:		PCI_ANY_ID,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ehci_pci_driver = {
+	name:		(char *) hcd_name,
+	id_table:	pci_ids,
+
+	probe:		usb_hcd_pci_probe,
+	remove:		usb_hcd_pci_remove,
+
+#ifdef	CONFIG_PM
+	suspend:	usb_hcd_pci_suspend,
+	resume:		usb_hcd_pci_resume,
+#endif
+};
+
+#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
+
+EXPORT_NO_SYMBOLS;
+MODULE_DESCRIPTION (DRIVER_INFO);
+MODULE_AUTHOR (DRIVER_AUTHOR);
+MODULE_LICENSE ("GPL");
+
+static int __init init (void) 
+{
+	dbg (DRIVER_INFO);
+	dbg ("block sizes: qh %d qtd %d itd %d sitd %d",
+		sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
+		sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
+
+	return pci_module_init (&ehci_pci_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void) 
+{	
+	pci_unregister_driver (&ehci_pci_driver);
+}
+module_exit (cleanup);
diff -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-hub.c linux/drivers/usb/hcd/ehci-hub.c
--- linux-2.5.2-pre5/drivers/usb/hcd/ehci-hub.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-hub.c	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Root Hub ... the nonsharable stuff
+ *
+ * Registers don't need cpu_to_le32, that happens transparently
+ */
+
+/*-------------------------------------------------------------------------*/
+
+static int check_reset_complete (
+	struct ehci_hcd	*ehci,
+	int		index,
+	int		port_status
+) {
+	if (!(port_status & PORT_CONNECT)) {
+		ehci->reset_done [index] = 0;
+		return port_status;
+	}
+
+	/* if reset finished and it's still not enabled -- handoff */
+	if (!(port_status & PORT_PE)) {
+		dbg ("%s port %d full speed, give to companion, 0x%x",
+			ehci->hcd.bus_name, index + 1, port_status);
+
+		// what happens if HCS_N_CC(params) == 0 ?
+		port_status |= PORT_OWNER;
+		writel (port_status, &ehci->regs->port_status [index]);
+
+	} else
+		dbg ("%s port %d high speed", ehci->hcd.bus_name, index + 1);
+
+	return port_status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+
+/* build "status change" packet (one or two bytes) from HC registers */
+
+static int
+ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
+{
+	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
+	u32		temp, status = 0;
+	int		ports, i, retval = 1;
+	unsigned long	flags;
+
+	/* init status to no-changes */
+	buf [0] = 0;
+	temp = readl (&ehci->caps->hcs_params);
+	ports = HCS_N_PORTS (temp);
+	if (ports > 7) {
+		buf [1] = 0;
+		retval++;
+	}
+	
+	/* no hub change reports (bit 0) for now (power, ...) */
+
+	/* port N changes (bit N)? */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (i = 0; i < ports; i++) {
+		temp = readl (&ehci->regs->port_status [i]);
+		if (temp & PORT_OWNER) {
+			// get disconnected ports back if no companion driver
+			if (temp & PORT_CONNECT)
+				continue;
+			temp &= ~(PORT_OWNER|PORT_CSC);
+			writel (temp, &ehci->regs->port_status [i]);
+		}
+		if (!(temp & PORT_CONNECT))
+			ehci->reset_done [i] = 0;
+		if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) {
+			set_bit (i, buf);
+			status = STS_PCD;
+		}
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return status ? retval : 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+ehci_hub_descriptor (
+	struct ehci_hcd			*ehci,
+	struct usb_hub_descriptor	*desc
+) {
+	u32		params = readl (&ehci->caps->hcs_params);
+	int		ports = HCS_N_PORTS (params);
+	u16		temp;
+
+	desc->bDescriptorType = 0x29;
+	desc->bPwrOn2PwrGood = 0;	/* FIXME: f(system power) */
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = ports;
+	temp = 1 + (ports / 8);
+	desc->bDescLength = 7 + 2 * temp;
+
+	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+	memset (&desc->bitmap [0], 0, temp);
+	memset (&desc->bitmap [temp], 0xff, temp);
+
+	temp = 0x0008;			/* per-port overcurrent reporting */
+	if (HCS_PPC (params))		/* per-port power control */
+	    temp |= 0x0001;
+	if (HCS_INDICATOR (params))	/* per-port indicators (LEDs) */
+	    temp |= 0x0080;
+	desc->wHubCharacteristics = cpu_to_le16 (temp);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int ehci_hub_control (
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength
+) {
+	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
+	u32		params = readl (&ehci->caps->hcs_params);
+	int		ports = HCS_N_PORTS (params);
+	u32		temp;
+	unsigned long	flags;
+	int		retval = 0;
+
+	/*
+	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+	 * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+	 * (track current state ourselves) ... blink for diagnostics,
+	 * power, "this is the one", etc.  EHCI spec supports this.
+	 */
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	switch (typeReq) {
+	case ClearHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+		if (temp & PORT_OWNER)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			writel (temp & ~PORT_PE,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			writel (temp | PORT_PEC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+		case USB_PORT_FEAT_C_SUSPEND:
+			/* ? */
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC (params))
+				writel (temp & ~PORT_POWER,
+					&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			writel (temp | PORT_CSC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			writel (temp | PORT_OCC,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			/* GetPortStatus clears reset */
+			break;
+		default:
+			goto error;
+		}
+		readl (&ehci->regs->command);	/* unblock posted write */
+		break;
+	case GetHubDescriptor:
+		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
+			buf);
+		break;
+	case GetHubStatus:
+		/* no hub-wide feature/status flags */
+		memset (buf, 0, 4);
+		//cpu_to_le32s ((u32 *) buf);
+		break;
+	case GetPortStatus:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		memset (buf, 0, 4);
+		temp = readl (&ehci->regs->port_status [wIndex]);
+
+		// wPortChange bits
+		if (temp & PORT_CSC)
+			set_bit (USB_PORT_FEAT_C_CONNECTION, buf);
+		if (temp & PORT_PEC)
+			set_bit (USB_PORT_FEAT_C_ENABLE, buf);
+		// USB_PORT_FEAT_C_SUSPEND
+		if (temp & PORT_OCC)
+			set_bit (USB_PORT_FEAT_C_OVER_CURRENT, buf);
+
+		/* whoever resets must GetPortStatus to complete it!! */
+		if ((temp & PORT_RESET)
+				&& jiffies > ehci->reset_done [wIndex]) {
+			set_bit (USB_PORT_FEAT_C_RESET, buf);
+
+			/* force reset to complete */
+			writel (temp & ~PORT_RESET,
+					&ehci->regs->port_status [wIndex]);
+			do {
+				temp = readl (
+					&ehci->regs->port_status [wIndex]);
+				udelay (10);
+			} while (temp & PORT_RESET);
+
+			/* see what we found out */
+			temp = check_reset_complete (ehci, wIndex, temp);
+		}
+
+		// don't show wPortStatus if it's owned by a companion hc
+		if (!(temp & PORT_OWNER)) {
+			if (temp & PORT_CONNECT) {
+				set_bit (USB_PORT_FEAT_CONNECTION, buf);
+				set_bit (USB_PORT_FEAT_HIGHSPEED, buf);
+			}
+			if (temp & PORT_PE)
+				set_bit (USB_PORT_FEAT_ENABLE, buf);
+			if (temp & PORT_SUSPEND)
+				set_bit (USB_PORT_FEAT_SUSPEND, buf);
+			if (temp & PORT_OC)
+				set_bit (USB_PORT_FEAT_OVER_CURRENT, buf);
+			if (temp & PORT_RESET)
+				set_bit (USB_PORT_FEAT_RESET, buf);
+			if (temp & PORT_POWER)
+				set_bit (USB_PORT_FEAT_POWER, buf);
+		}
+
+#ifndef	EHCI_VERBOSE_DEBUG
+	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */
+#endif
+		dbg_port (hcd, "GetStatus", wIndex + 1, temp);
+		cpu_to_le32s ((u32 *) buf);
+		break;
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* no hub-wide feature/status flags */
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case SetPortFeature:
+		if (!wIndex || wIndex > ports)
+			goto error;
+		wIndex--;
+		temp = readl (&ehci->regs->port_status [wIndex]);
+		if (temp & PORT_OWNER)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			writel (temp | PORT_SUSPEND,
+				&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC (params))
+				writel (temp | PORT_POWER,
+					&ehci->regs->port_status [wIndex]);
+			break;
+		case USB_PORT_FEAT_RESET:
+			/* line status bits may report this as low speed */
+			if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+					&& PORT_USB11 (temp)) {
+				dbg ("%s port %d low speed, give to companion",
+					hcd->bus_name, wIndex + 1);
+				temp |= PORT_OWNER;
+			} else {
+				vdbg ("%s port %d reset",
+					hcd->bus_name, wIndex + 1);
+				temp |= PORT_RESET;
+				temp &= ~PORT_PE;
+
+				/*
+				 * caller must wait, then call GetPortStatus
+				 * usb 2.0 spec says 50 ms resets on root
+				 */
+				ehci->reset_done [wIndex] = jiffies
+				    	+ ((50 /* msec */ * HZ) / 1000);
+			}
+			writel (temp, &ehci->regs->port_status [wIndex]);
+			break;
+		default:
+			goto error;
+		}
+		readl (&ehci->regs->command);	/* unblock posted writes */
+		break;
+
+	default:
+error:
+		/* "stall" on error */
+		retval = -EPIPE;
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return retval;
+}
diff -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-mem.c linux/drivers/usb/hcd/ehci-mem.c
--- linux-2.5.2-pre5/drivers/usb/hcd/ehci-mem.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-mem.c	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * There's basically three types of memory:
+ *	- data used only by the HCD ... kmalloc is fine
+ *	- async and periodic schedules, shared by HC and HCD ... these
+ *	  need to use pci_pool or pci_alloc_consistent
+ *	- driver buffers, read/written by HC ... single shot DMA mapped 
+ *
+ * There's also PCI "register" data, which is memory mapped.
+ * No memory seen by this driver is pagable.
+ */
+
+/*-------------------------------------------------------------------------*/
+/* 
+ * Allocator / cleanup for the per device structure
+ * Called by hcd init / removal code
+ */
+static struct usb_hcd *ehci_hcd_alloc (void)
+{
+	struct ehci_hcd *ehci;
+
+	ehci = (struct ehci_hcd *)
+		kmalloc (sizeof (struct ehci_hcd), GFP_KERNEL);
+	if (ehci != 0) {
+		memset (ehci, 0, sizeof (struct ehci_hcd));
+		return &ehci->hcd;
+	}
+	return 0;
+}
+
+static void ehci_hcd_free (struct usb_hcd *hcd)
+{
+	kfree (hcd_to_ehci (hcd));
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Allocate the key transfer structures from the previously allocated pool */
+
+static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, int flags)
+{
+	struct ehci_qtd		*qtd;
+	dma_addr_t		dma;
+
+	qtd = pci_pool_alloc (ehci->qtd_pool, flags, &dma);
+	if (qtd != 0) {
+		memset (qtd, 0, sizeof *qtd);
+		qtd->qtd_dma = dma;
+		qtd->hw_next = EHCI_LIST_END;
+		qtd->hw_alt_next = EHCI_LIST_END;
+		INIT_LIST_HEAD (&qtd->qtd_list);
+	}
+	return qtd;
+}
+
+static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
+{
+	pci_pool_free (ehci->qtd_pool, qtd, qtd->qtd_dma);
+}
+
+
+static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
+{
+	struct ehci_qh		*qh;
+	dma_addr_t		dma;
+
+	qh = (struct ehci_qh *)
+		pci_pool_alloc (ehci->qh_pool, flags, &dma);
+	if (qh) {
+		memset (qh, 0, sizeof *qh);
+		atomic_set (&qh->refcount, 1);
+		qh->qh_dma = dma;
+		// INIT_LIST_HEAD (&qh->qh_list);
+		INIT_LIST_HEAD (&qh->qtd_list);
+	}
+	return qh;
+}
+
+/* to share a qh (cpu threads, or hc) */
+static inline struct ehci_qh *qh_put (/* ehci, */ struct ehci_qh *qh)
+{
+	// dbg ("put %p (%d++)", qh, qh->refcount.counter);
+	atomic_inc (&qh->refcount);
+	return qh;
+}
+
+static void qh_unput (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	// dbg ("unput %p (--%d)", qh, qh->refcount.counter);
+	if (!atomic_dec_and_test (&qh->refcount))
+		return;
+	/* clean qtds first, and know this is not linked */
+	if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
+		dbg ("unused qh not empty!");
+		BUG ();
+	}
+	pci_pool_free (ehci->qh_pool, qh, qh->qh_dma);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* The queue heads and transfer descriptors are managed from pools tied 
+ * to each of the "per device" structures.
+ * This is the initialisation and cleanup code.
+ */
+
+static void ehci_mem_cleanup (struct ehci_hcd *ehci)
+{
+	/* PCI consistent memory and pools */
+	if (ehci->qtd_pool)
+		pci_pool_destroy (ehci->qtd_pool);
+	ehci->qtd_pool = 0;
+
+	if (ehci->qh_pool) {
+		pci_pool_destroy (ehci->qh_pool);
+		ehci->qh_pool = 0;
+	}
+
+	if (ehci->itd_pool)
+		pci_pool_destroy (ehci->itd_pool);
+	ehci->itd_pool = 0;
+
+	if (ehci->sitd_pool)
+		pci_pool_destroy (ehci->sitd_pool);
+	ehci->sitd_pool = 0;
+
+	if (ehci->periodic)
+		pci_free_consistent (ehci->hcd.pdev,
+			ehci->periodic_size * sizeof (u32),
+			ehci->periodic, ehci->periodic_dma);
+	ehci->periodic = 0;
+
+	/* shadow periodic table */
+	if (ehci->pshadow)
+		kfree (ehci->pshadow);
+	ehci->pshadow = 0;
+}
+
+/* remember to add cleanup code (above) if you add anything here */
+static int ehci_mem_init (struct ehci_hcd *ehci, int flags)
+{
+	int i;
+
+	/* QTDs for control/bulk/intr transfers */
+	ehci->qtd_pool = pci_pool_create ("ehci_qtd", ehci->hcd.pdev,
+			sizeof (struct ehci_qtd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->qtd_pool) {
+		dbg ("no qtd pool");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/* QH for control/bulk/intr transfers */
+	ehci->qh_pool = pci_pool_create ("ehci_qh", ehci->hcd.pdev,
+			sizeof (struct ehci_qh),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->qh_pool) {
+		dbg ("no qh pool");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/* ITD for high speed ISO transfers */
+	ehci->itd_pool = pci_pool_create ("ehci_itd", ehci->hcd.pdev,
+			sizeof (struct ehci_itd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->itd_pool) {
+		dbg ("no itd pool");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/* SITD for full/low speed split ISO transfers */
+	ehci->sitd_pool = pci_pool_create ("ehci_sitd", ehci->hcd.pdev,
+			sizeof (struct ehci_sitd),
+			32 /* byte alignment (for hw parts) */,
+			4096 /* can't cross 4K */,
+			flags);
+	if (!ehci->sitd_pool) {
+		dbg ("no sitd pool");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+
+	/* Hardware periodic table */
+	ehci->periodic = (u32 *)
+		pci_alloc_consistent (ehci->hcd.pdev,
+			ehci->periodic_size * sizeof (u32),
+			&ehci->periodic_dma);
+	if (ehci->periodic == 0) {
+		dbg ("no hw periodic table");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+	for (i = 0; i < ehci->periodic_size; i++)
+		ehci->periodic [i] = EHCI_LIST_END;
+
+	/* software shadow of hardware table */
+	ehci->pshadow = kmalloc (ehci->periodic_size * sizeof (void *),
+		flags & ~EHCI_SLAB_FLAGS);
+	if (ehci->pshadow == 0) {
+		dbg ("no shadow periodic table");
+		ehci_mem_cleanup (ehci);
+		return -ENOMEM;
+	}
+	memset (ehci->pshadow, 0, ehci->periodic_size * sizeof (void *));
+
+	return 0;
+}
diff -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-q.c linux/drivers/usb/hcd/ehci-q.c
--- linux-2.5.2-pre5/drivers/usb/hcd/ehci-q.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-q.c	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI hardware queue manipulation
+ *
+ * Control, bulk, and interrupt traffic all use "qh" lists.  They list "qtd"
+ * entries describing USB transactions, max 16-20kB/entry (with 4kB-aligned
+ * buffers needed for the larger number).  We use one QH per endpoint, queue
+ * multiple (bulk or control) urbs per endpoint.  URBs may need several qtds.
+ * A scheduled interrupt qh always has one qtd, one urb.
+ *
+ * ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
+ * interrupts) needs careful scheduling.  Performance improvements can be
+ * an ongoing challenge.
+ * 
+ * USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
+ * or otherwise through transaction translators (TTs) in USB 2.0 hubs using
+ * (b) special fields in qh entries or (c) split iso entries.  TTs will
+ * buffer low/full speed data so the host collects it at high speed.
+ */
+
+#ifdef	EHCI_SOFT_RETRIES
+static int soft_retries = EHCI_SOFT_RETRIES;
+MODULE_PARM (soft_retries, "i");
+MODULE_PARM_DESC (soft_retries, "Number of software retries for endpoint i/o");
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* fill a qtd, returning how much of the buffer we were able to queue up */
+
+static int
+qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len, int token)
+{
+	int	i, count;
+
+	/* one buffer entry per 4K ... first might be short or unaligned */
+	qtd->hw_buf [0] = cpu_to_le32 (buf);
+	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
+	if (likely (len < count))		/* ... iff needed */
+		count = len;
+	else {
+		buf +=  0x1000;
+		buf &= ~0x0fff;
+
+		/* per-qtd limit: from 16K to 20K (best alignment) */
+		for (i = 1; count < len && i < 5; i++) {
+			u64	addr = buf;
+			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
+			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
+			buf += 0x1000;
+			if ((count + 0x1000) < len)
+				count += 0x1000;
+			else
+				count = len;
+		}
+	}
+	qtd->hw_token = cpu_to_le32 ((count << 16) | token);
+	qtd->length = count;
+
+#if 0
+	vdbg ("  qtd_fill %p, token %8x bytes %d dma %x",
+		qtd, le32_to_cpu (qtd->hw_token), count, qtd->hw_buf [0]);
+#endif
+
+	return count;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* update halted (but potentially linked) qh */
+
+static inline void qh_update (struct ehci_qh *qh, struct ehci_qtd *qtd)
+{
+	qh->hw_current = 0;
+	qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
+	qh->hw_alt_next = EHCI_LIST_END;
+
+	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
+	qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline void qtd_copy_status (struct urb *urb, size_t length, u32 token)
+{
+	/* count IN/OUT bytes, not SETUP (even short packets) */
+	if (likely (QTD_PID (token) != 2))
+		urb->actual_length += length - QTD_LENGTH (token);
+
+	/* don't modify error codes */
+	if (unlikely (urb->status == -EINPROGRESS && (token & QTD_STS_HALT))) {
+		if (token & QTD_STS_BABBLE) {
+			urb->status = -EOVERFLOW;
+		} else if (!QTD_CERR (token)) {
+			if (token & QTD_STS_DBE)
+				urb->status = (QTD_PID (token) == 1) /* IN ? */
+					? -ENOSR  /* hc couldn't read data */
+					: -ECOMM; /* hc couldn't write data */
+			else if (token & QTD_STS_MMF)	/* missed tt uframe */
+				urb->status = -EPROTO;
+			else if (token & QTD_STS_XACT) {
+				if (QTD_LENGTH (token))
+					urb->status = -EPIPE;
+				else {
+					dbg ("3strikes");
+					urb->status = -EPROTO;
+				}
+			} else	/* presumably a stall */
+				urb->status = -EPIPE;
+
+		/* CERR nonzero + data left + halt --> stall */
+		} else if (QTD_LENGTH (token))
+			urb->status = -EPIPE;
+		else	/* unknown */
+			urb->status = -EPROTO;
+		dbg ("devpath %s ep %d-%s qtd token %x --> status %d",
+			urb->dev->devpath, usb_pipeendpoint (urb->pipe),
+			usb_pipein (urb->pipe) ? "in" : "out",
+			token, urb->status);
+
+		/* stall indicates some recovery action is needed */
+		if (urb->status == -EPIPE) {
+			int	pipe = urb->pipe;
+
+			if (!usb_pipecontrol (pipe))
+				usb_endpoint_halt (urb->dev,
+					usb_pipeendpoint (pipe),
+					usb_pipeout (pipe));
+			if (urb->dev->tt && !usb_pipeint (pipe)) {
+err ("must CLEAR_TT_BUFFER, hub %s port %d%s addr %d ep %d",
+    urb->dev->tt->hub->devpath, urb->dev->ttport,
+    urb->dev->tt->multi ? "" : " (all-ports TT)",
+    urb->dev->devnum, usb_pipeendpoint (urb->pipe));
+				// FIXME something (khubd?) should make the hub
+				// CLEAR_TT_BUFFER ASAP, it's blocking other
+				// fs/ls requests... hub_tt_clear_buffer() ?
+			}
+		}
+	}
+}
+
+static void ehci_urb_complete (
+	struct ehci_hcd		*ehci,
+	dma_addr_t		addr,
+	struct urb		*urb
+) {
+	if (urb->transfer_buffer_length && usb_pipein (urb->pipe))
+		pci_dma_sync_single (ehci->hcd.pdev, addr,
+			urb->transfer_buffer_length,
+			PCI_DMA_FROMDEVICE);
+
+	/* cleanse status if we saw no error */
+	if (likely (urb->status == -EINPROGRESS)) {
+		if (urb->actual_length != urb->transfer_buffer_length
+				&& (urb->transfer_flags & USB_DISABLE_SPD))
+			urb->status = -EREMOTEIO;
+		else
+			urb->status = 0;
+	}
+
+	/* only report unlinks once */
+	if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN))
+		urb->complete (urb);
+}
+
+/* urb->lock ignored from here on (hcd is done with urb) */
+
+static void ehci_urb_done (
+	struct ehci_hcd		*ehci,
+	dma_addr_t		addr,
+	struct urb		*urb
+) {
+	if (urb->transfer_buffer_length)
+		pci_unmap_single (ehci->hcd.pdev,
+			addr,
+			urb->transfer_buffer_length,
+			usb_pipein (urb->pipe)
+			    ? PCI_DMA_FROMDEVICE
+			    : PCI_DMA_TODEVICE);
+	if (likely (urb->hcpriv != 0)) {
+		qh_unput (ehci, (struct ehci_qh *) urb->hcpriv);
+		urb->hcpriv = 0;
+	}
+
+	if (likely (urb->status == -EINPROGRESS)) {
+		if (urb->actual_length != urb->transfer_buffer_length
+				&& (urb->transfer_flags & USB_DISABLE_SPD))
+			urb->status = -EREMOTEIO;
+		else
+			urb->status = 0;
+	}
+
+	/* hand off urb ownership */
+	usb_hcd_giveback_urb (&ehci->hcd, urb);
+}
+
+
+/*
+ * Process completed qtds for a qh, issuing completions if needed.
+ * When freeing:  frees qtds, unmaps buf, returns URB to driver.
+ * When not freeing (queued periodic qh):  retain qtds, mapping, and urb.
+ * Races up to qh->hw_current; returns number of urb completions.
+ */
+static int
+qh_completions (
+	struct ehci_hcd		*ehci,
+	struct list_head	*qtd_list,
+	int			freeing
+) {
+	struct ehci_qtd		*qtd = 0;
+	struct list_head	*next = 0;
+	u32			token;
+	struct ehci_qh		*qh = 0;
+	struct urb		*urb = 0;
+	int			halted = 0;
+	unsigned long		flags;
+	int			retval = 0;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+	if (unlikely (list_empty (qtd_list))) {
+		spin_unlock_irqrestore (&ehci->lock, flags);
+		return retval;
+	}
+
+	for (qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+			next != qtd_list;
+			qtd = list_entry (next, struct ehci_qtd, qtd_list)) {
+		token = le32_to_cpu (qtd->hw_token);
+		if (!qh) {
+			urb = qtd->urb;
+			qh = (struct ehci_qh *) urb->hcpriv;
+		}
+		if (likely (qh != 0)) {
+			halted = halted
+				|| (ehci->hcd.state == USB_STATE_HALT)
+				|| (qh->qh_state == QH_STATE_IDLE);
+
+			if (unlikely ((token & QTD_STS_HALT) != 0)) {
+#ifdef	EHCI_SOFT_RETRIES
+				/* extra soft retries for protocol errors */
+				if (!halted
+						&& qh->retries < soft_retries
+						&& (QTD_STS_HALT|QTD_STS_XACT)
+							== (token & 0xff)
+						&& QTD_CERR (token) == 0) {
+					if (qh->retries == 0)
+						dbg ("soft retry, qh %p qtd %p",
+							qh, qtd);
+					qh->retries++;
+					token &= ~0x0ff;
+					token |= QTD_STS_ACTIVE;
+					token |= (EHCI_TUNE_CERR << 10);
+					/* qtd update not needed */
+					qh->hw_token = cpu_to_le32 (token);
+					spin_unlock_irqrestore (&ehci->lock,
+						flags);
+					return;
+
+				} else if (qh->retries >= soft_retries
+						&& soft_retries) {
+					dbg ("retried %d times, qh %p qtd %p",
+						qh->retries, qh, qtd);
+				}
+#endif	/* EHCI_SOFT_RETRIES */
+				halted = 1;
+			}
+
+			if (unlikely ((token & QTD_STS_ACTIVE) != 0)) {
+				/* stop scan if qtd is visible to the HC */
+				if (!halted) {
+					urb = 0;
+					break;
+				}
+
+				/* continue cleanup if HC is halted */
+				if (ehci->hcd.state == USB_STATE_HALT) {
+					urb->status = -ESHUTDOWN;
+					goto scrub;
+				}
+
+				/* stall? some other urb was unlinked? */
+				if (urb->status == -EINPROGRESS) {
+dbg ("?why? qh %p, qtd %p halted, urb %p, token %8x, len %d",
+	qh, qtd, urb, token, urb->actual_length);
+spin_unlock_irqrestore (&ehci->lock, flags);
+return retval;
+	    /*
+	     * FIXME: write this code.  When one queued urb is unlinked,
+	     * unlink every succeeding urb.
+	     */
+					continue;
+				}
+
+				/* else stopped for some other reason */
+			} 
+scrub:
+			spin_lock (&urb->lock);
+			qtd_copy_status (urb, qtd->length, token);
+			spin_unlock (&urb->lock);
+		}
+		next = qtd->qtd_list.next;
+
+		/*
+		 * NOTE:  this won't work right with interrupt urbs that
+		 * need multiple qtds ... only the first scan of qh->qtd_list
+		 * starts at the right qtd, yet multiple scans could happen
+		 * for transfers that are scheduled across multiple uframes. 
+		 */
+		if (likely (freeing != 0))
+			list_del (&qtd->qtd_list);
+		else {
+			/* restore everything the HC could change
+			 * from an interrupt QTD
+			 */
+			qtd->hw_token = (qtd->hw_token
+					& ~__constant_cpu_to_le32 (0x8300))
+				| cpu_to_le32 (qtd->length << 16)
+				| __constant_cpu_to_le32 (QTD_IOC
+					| (EHCI_TUNE_CERR << 10)
+					| QTD_STS_ACTIVE);
+			qtd->hw_buf [0] &= ~__constant_cpu_to_le32 (0x0fff);
+
+			/* this offset, and the length above,
+			 * are likely wrong on QTDs #2..N
+			 */
+			qtd->hw_buf [0] |= cpu_to_le32 (0x0fff & qtd->buf_dma);
+		}
+
+		spin_unlock_irqrestore (&ehci->lock, flags);
+
+#if 0
+		if (urb->status == -EINPROGRESS)
+			vdbg ("  qtd %p ok, urb %p, token %8x, len %d",
+				qtd, urb, token, urb->actual_length);
+		else
+			vdbg ("urb %p status %d, qtd %p, token %8x, len %d",
+				urb, urb->status, qtd, token,
+				urb->actual_length);
+#endif
+
+		/* SETUP for control urb? */
+		if (unlikely (QTD_PID (token) == 2))
+			pci_unmap_single (ehci->hcd.pdev,
+				qtd->buf_dma, sizeof (devrequest),
+				PCI_DMA_TODEVICE);
+
+		/* another queued urb? */
+		if (unlikely (qtd->urb != urb)) {
+			if (likely (freeing != 0))
+				ehci_urb_done (ehci, qtd->buf_dma, urb);
+			else
+				ehci_urb_complete (ehci, qtd->buf_dma, urb);
+			retval++;
+			urb = qtd->urb;
+		}
+
+		if (likely (freeing != 0))
+			ehci_qtd_free (ehci, qtd);
+		spin_lock_irqsave (&ehci->lock, flags);
+		qtd = list_entry (next, struct ehci_qtd, qtd_list);
+	}
+
+	/* patch up list head? */
+	if (unlikely (halted && qh && !list_empty (qtd_list))) {
+		qh_update (qh, list_entry (qtd_list->next,
+				struct ehci_qtd, qtd_list));
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	/* last urb's completion might still need calling */
+	if (likely (qtd && urb)) {
+		if (likely (freeing != 0))
+			ehci_urb_done (ehci, qtd->buf_dma, urb);
+		else
+			ehci_urb_complete (ehci, qtd->buf_dma, urb);
+		retval++;
+	}
+	return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *
+qh_urb_transaction (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*head,
+	int			flags
+) {
+	struct ehci_qtd		*qtd, *qtd_prev;
+	dma_addr_t		buf, map_buf;
+	int			len, maxpacket;
+	u32			token;
+
+	/*
+	 * URBs map to sequences of QTDs:  one logical transaction
+	 */
+	qtd = ehci_qtd_alloc (ehci, flags);
+	if (unlikely (!qtd))
+		return 0;
+	qtd_prev = 0;
+	list_add_tail (&qtd->qtd_list, head);
+	qtd->urb = urb;
+
+	token = QTD_STS_ACTIVE;
+	token |= (EHCI_TUNE_CERR << 10);
+	/* for split transactions, SplitXState initialized to zero */
+
+	if (usb_pipecontrol (urb->pipe)) {
+		/* control request data is passed in the "setup" pid */
+
+		/* NOTE:  this isn't smart about 64bit DMA, since it uses the
+		 * default (32bit) mask rather than using the whole address
+		 * space.  we could set pdev->dma_mask to all-ones while
+		 * getting this mapping, locking it and restoring before
+		 * allocating qtd/qh/... or maybe only do that for the main
+		 * data phase (below).
+		 */
+		qtd->buf_dma = pci_map_single (
+					ehci->hcd.pdev,
+					urb->setup_packet,
+					sizeof (devrequest),
+					PCI_DMA_TODEVICE);
+		if (unlikely (!qtd->buf_dma))
+			goto cleanup;
+
+		/* SETUP pid */
+		qtd_fill (qtd, qtd->buf_dma, sizeof (devrequest),
+			token | (2 /* "setup" */ << 8));
+
+		/* ... and always at least one more pid */
+		token ^= QTD_TOGGLE;
+		qtd_prev = qtd;
+		qtd = ehci_qtd_alloc (ehci, flags);
+		if (unlikely (!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		list_add_tail (&qtd->qtd_list, head);
+	} 
+
+	/*
+	 * data transfer stage:  buffer setup
+	 */
+	len = urb->transfer_buffer_length;
+	if (likely (len > 0)) {
+		/* NOTE:  sub-optimal mapping with 64bit DMA (see above) */
+		buf = map_buf = pci_map_single (ehci->hcd.pdev,
+			urb->transfer_buffer, len,
+			usb_pipein (urb->pipe)
+			    ? PCI_DMA_FROMDEVICE
+			    : PCI_DMA_TODEVICE);
+		if (unlikely (!buf))
+			goto cleanup;
+	} else
+		buf = map_buf = 0;
+
+	if (!buf || usb_pipein (urb->pipe))
+		token |= (1 /* "in" */ << 8);
+	/* else it's already initted to "out" pid (0 << 8) */
+
+	maxpacket = usb_maxpacket (urb->dev, urb->pipe,
+			usb_pipeout (urb->pipe));
+
+	/*
+	 * buffer gets wrapped in one or more qtds;
+	 * last one may be "short" (including zero len)
+	 * and may serve as a control status ack
+	 */
+	for (;;) {
+		int this_qtd_len;
+
+		qtd->urb = urb;
+		qtd->buf_dma = map_buf;
+		this_qtd_len = qtd_fill (qtd, buf, len, token);
+		len -= this_qtd_len;
+		buf += this_qtd_len;
+
+		/* qh makes control packets use qtd toggle; maybe switch it */
+		if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+			token ^= QTD_TOGGLE;
+
+		if (likely (len <= 0))
+			break;
+
+		qtd_prev = qtd;
+		qtd = ehci_qtd_alloc (ehci, flags);
+		if (unlikely (!qtd))
+			goto cleanup;
+		qtd->urb = urb;
+		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		list_add_tail (&qtd->qtd_list, head);
+	}
+
+	/*
+	 * control requests may need a terminating data "status" ack;
+	 * bulk ones may need a terminating short packet (zero length).
+	 */
+	if (likely (buf != 0)) {
+		int	one_more = 0;
+
+		if (usb_pipecontrol (urb->pipe)) {
+			one_more = 1;
+			token ^= 0x0100;	/* "in" <--> "out"  */
+			token |= QTD_TOGGLE;	/* force DATA1 */
+		} else if (usb_pipebulk (urb->pipe)
+				&& (urb->transfer_flags & USB_ZERO_PACKET)
+				&& !(urb->transfer_buffer_length % maxpacket)) {
+			one_more = 1;
+		}
+		if (one_more) {
+			qtd_prev = qtd;
+			qtd = ehci_qtd_alloc (ehci, flags);
+			if (unlikely (!qtd))
+				goto cleanup;
+			qtd->urb = urb;
+			qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+			list_add_tail (&qtd->qtd_list, head);
+
+			/* never any data in such packets */
+			qtd_fill (qtd, 0, 0, token);
+		}
+	}
+
+	/* by default, enable interrupt on urb completion */
+	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
+		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
+	return head;
+
+cleanup:
+	urb->status = -ENOMEM;
+	qh_completions (ehci, head, 1);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Hardware maintains data toggle (like OHCI) ... here we (re)initialize
+ * the hardware data toggle in the QH, and set the pseudo-toggle in udev
+ * so we can see if usb_clear_halt() was called.  NOP for control, since
+ * we set up qh->hw_info1 to always use the QTD toggle bits. 
+ */
+static inline void
+clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh)
+{
+	vdbg ("clear toggle, dev %d ep 0x%x-%s",
+		udev->devnum, ep, is_out ? "out" : "in");
+	qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
+	usb_settoggle (udev, ep, is_out, 1);
+}
+
+// Would be best to create all qh's from config descriptors,
+// when each interface/altsetting is established.  Unlink
+// any previous qh and cancel its urbs first; endpoints are
+// implicitly reset then (data toggle too).
+// That'd mean updating how usbcore talks to HCDs. (2.5?)
+
+
+/*
+ * Each QH holds a qtd list; a QH is used for everything except iso.
+ *
+ * For interrupt urbs, the scheduler must set the microframe scheduling
+ * mask(s) each time the QH gets scheduled.  For highspeed, that's
+ * just one microframe in the s-mask.  For split interrupt transactions
+ * there are additional complications: c-mask, maybe FSTNs.
+ */
+static struct ehci_qh *
+ehci_qh_make (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			flags
+) {
+	struct ehci_qh		*qh = ehci_qh_alloc (ehci, flags);
+	u32			info1 = 0, info2 = 0;
+
+	if (!qh)
+		return qh;
+
+	/*
+	 * init endpoint/device data for this QH
+	 */
+	info1 |= usb_pipeendpoint (urb->pipe) << 8;
+	info1 |= usb_pipedevice (urb->pipe) << 0;
+
+	/* using TT? */
+	switch (urb->dev->speed) {
+	case USB_SPEED_LOW:
+		info1 |= (1 << 12);	/* EPS "low" */
+		/* FALL THROUGH */
+
+	case USB_SPEED_FULL:
+		/* EPS 0 means "full" */
+		info1 |= (EHCI_TUNE_RL_TT << 28);
+		if (usb_pipecontrol (urb->pipe)) {
+			info1 |= (1 << 27);	/* for TT */
+			info1 |= 1 << 14;	/* toggle from qtd */
+		}
+		info1 |= usb_maxpacket (urb->dev, urb->pipe,
+					usb_pipeout (urb->pipe)) << 16;
+
+		info2 |= (EHCI_TUNE_MULT_TT << 30);
+		info2 |= urb->dev->ttport << 23;
+		info2 |= urb->dev->tt->hub->devnum << 16;
+
+		/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets c-mask }
+		 * ... and a 0.96 scheduler might use FSTN nodes too
+		 */
+		break;
+
+	case USB_SPEED_HIGH:		/* no TT involved */
+		info1 |= (2 << 12);	/* EPS "high" */
+		info1 |= (EHCI_TUNE_RL_HS << 28);
+		if (usb_pipecontrol (urb->pipe)) {
+			info1 |= 64 << 16;	/* usb2 fixed maxpacket */
+			info1 |= 1 << 14;	/* toggle from qtd */
+		} else if (usb_pipebulk (urb->pipe)) {
+			info1 |= 512 << 16;	/* usb2 fixed maxpacket */
+			info2 |= (EHCI_TUNE_MULT_HS << 30);
+		} else
+			info1 |= usb_maxpacket (urb->dev, urb->pipe,
+						usb_pipeout (urb->pipe)) << 16;
+		break;
+	default:
+#ifdef DEBUG
+		BUG ();
+#endif
+	}
+
+	/* NOTE:  if (usb_pipeint (urb->pipe)) { scheduler sets s-mask } */
+
+	qh->qh_state = QH_STATE_IDLE;
+	qh->hw_info1 = cpu_to_le32 (info1);
+	qh->hw_info2 = cpu_to_le32 (info2);
+
+	/* initialize sw and hw queues with these qtds */
+	list_splice (qtd_list, &qh->qtd_list);
+	qh_update (qh, list_entry (qtd_list->next, struct ehci_qtd, qtd_list));
+
+	/* initialize data toggle state */
+	if (!usb_pipecontrol (urb->pipe))
+		clear_toggle (urb->dev,
+			usb_pipeendpoint (urb->pipe),
+			usb_pipeout (urb->pipe),
+			qh);
+
+	return qh;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* move qh (and its qtds) onto async queue; maybe enable queue.  */
+
+static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	u32		dma = QH_NEXT (qh->qh_dma);
+	struct ehci_qh	*q;
+
+	if (unlikely (!(q = ehci->async))) {
+		u32	cmd = readl (&ehci->regs->command);
+
+		/* in case a clear of CMD_ASE didn't take yet */
+		while (readl (&ehci->regs->status) & STS_ASS)
+			udelay (100);
+
+		qh->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
+		qh->qh_next.qh = qh;
+		qh->hw_next = dma;
+		ehci->async = qh;
+		writel ((u32)qh->qh_dma, &ehci->regs->async_next);
+		cmd |= CMD_ASE | CMD_RUN;
+		writel (cmd, &ehci->regs->command);
+		ehci->hcd.state = USB_STATE_RUNNING;
+		/* posted write need not be known to HC yet ... */
+	} else {
+		/* splice right after "start" of ring */
+		qh->hw_info1 &= ~__constant_cpu_to_le32 (QH_HEAD); /* [4.8] */
+		qh->qh_next = q->qh_next;
+		qh->hw_next = q->hw_next;
+		q->qh_next.qh = qh;
+		q->hw_next = dma;
+	}
+	qh->qh_state = QH_STATE_LINKED;
+	/* qtd completions reported later by interrupt */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+submit_async (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	struct ehci_qtd		*qtd;
+	struct hcd_dev		*dev;
+	int			epnum;
+	unsigned long		flags;
+	struct ehci_qh		*qh = 0;
+
+	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe))
+		epnum |= 0x10;
+
+	vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
+		ehci->hcd.bus_name, urb, urb->transfer_buffer_length,
+		epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
+		qtd, dev ? dev->ep [epnum] : (void *)~0);
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	qh = (struct ehci_qh *) dev->ep [epnum];
+	if (likely (qh != 0)) {
+		u32	hw_next = QTD_NEXT (qtd->qtd_dma);
+
+		/* maybe patch the qh used for set_address */
+		if (unlikely (epnum == 0
+				&& le32_to_cpu (qh->hw_info1 & 0x7f) == 0))
+			qh->hw_info1 |= cpu_to_le32 (usb_pipedevice(urb->pipe));
+
+		/* is an URB is queued to this qh already? */
+		if (unlikely (!list_empty (&qh->qtd_list))) {
+			struct ehci_qtd		*last_qtd;
+
+			// dbg_qh ("non-empty qh", ehci, qh);
+			last_qtd = list_entry (qh->qtd_list.prev,
+					struct ehci_qtd, qtd_list);
+			last_qtd->hw_next = hw_next;
+
+			/* previous urb allows short rx? maybe optimize. */
+			if (!(last_qtd->urb->transfer_flags & USB_DISABLE_SPD)
+					&& (epnum & 0x10)) {
+				// only the last QTD for now
+				last_qtd->hw_alt_next = hw_next;
+			}
+
+		/* no URB queued */
+		} else {
+			// dbg_qh ("empty qh", ehci, qh);
+
+// FIXME:  how handle usb_clear_halt() for an EP with queued URBs?
+// usbcore may not let us handle that cleanly...
+// likely must cancel them all first!
+
+			/* usb_clear_halt() means qh data toggle gets reset */
+			if (usb_pipebulk (urb->pipe)
+					&& unlikely (!usb_gettoggle (urb->dev,
+						(epnum & 0x0f),
+						!(epnum & 0x10)))) {
+				clear_toggle (urb->dev,
+					epnum & 0x0f, !(epnum & 0x10), qh);
+			}
+			qh_update (qh, qtd);
+		}
+		list_splice (qtd_list, qh->qtd_list.prev);
+
+	} else {
+		/* can't sleep here, we have ehci->lock... */
+		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
+		if (likely (qh != 0)) {
+			// dbg_qh ("new qh", ehci, qh);
+			dev->ep [epnum] = qh;
+		} else
+			urb->status = -ENOMEM;
+	}
+
+	/* Control/bulk operations through TTs don't need scheduling,
+	 * the HC and TT handle it when the TT has a buffer ready.
+	 */
+	if (likely (qh != 0)) {
+		urb->hcpriv = qh_put (qh);
+		if (likely (qh->qh_state == QH_STATE_IDLE))
+			qh_link_async (ehci, qh_put (qh));
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (unlikely (!qh))
+		qh_completions (ehci, qtd_list, 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* the async qh for the qtds being reclaimed are now unlinked from the HC */
+/* caller must not own ehci->lock */
+
+static void end_unlink_async (struct ehci_hcd *ehci)
+{
+	struct ehci_qh		*qh = ehci->reclaim;
+
+	qh->qh_state = QH_STATE_IDLE;
+	qh->qh_next.qh = 0;
+	qh_unput (ehci, qh);			// refcount from reclaim 
+	ehci->reclaim = 0;
+	ehci->reclaim_ready = 0;
+
+	qh_completions (ehci, &qh->qtd_list, 1);
+
+	// FIXME unlink any urb should unlink all following urbs,
+	// so that this will never happen
+	if (!list_empty (&qh->qtd_list)
+			&& HCD_IS_RUNNING (ehci->hcd.state))
+		qh_link_async (ehci, qh);
+	else
+		qh_unput (ehci, qh);		// refcount from async list
+}
+
+
+/* makes sure the async qh will become idle */
+/* caller must own ehci->lock */
+
+static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int		cmd = readl (&ehci->regs->command);
+	struct ehci_qh	*prev;
+
+#ifdef DEBUG
+	if (ehci->reclaim
+			|| !ehci->async
+			|| qh->qh_state != QH_STATE_LINKED
+#ifdef CONFIG_SMP
+// this macro lies except on SMP compiles
+			|| !spin_is_locked (&ehci->lock)
+#endif
+			)
+		BUG ();
+#endif
+
+	qh->qh_state = QH_STATE_UNLINK;
+	ehci->reclaim = qh = qh_put (qh);
+
+	// dbg_qh ("start unlink", ehci, qh);
+
+	/* Remove the last QH (qhead)?  Stop async schedule first. */
+	if (unlikely (qh == ehci->async && qh->qh_next.qh == qh)) {
+		/* can't get here without STS_ASS set */
+		if (ehci->hcd.state != USB_STATE_HALT) {
+			if (cmd & CMD_PSE)
+				writel (cmd & __constant_cpu_to_le32 (~CMD_ASE),
+					&ehci->regs->command);
+			else {
+				ehci_ready (ehci);
+				while (!(readl (&ehci->regs->status) & STS_ASS))
+					udelay (100);
+			}
+		}
+		qh->qh_next.qh = ehci->async = 0;
+
+		ehci->reclaim_ready = 1;
+		tasklet_schedule (&ehci->tasklet);
+		return;
+	} 
+
+	if (unlikely (ehci->hcd.state == USB_STATE_HALT)) {
+		ehci->reclaim_ready = 1;
+		tasklet_schedule (&ehci->tasklet);
+		return;
+	}
+
+	prev = ehci->async;
+	while (prev->qh_next.qh != qh && prev->qh_next.qh != ehci->async)
+		prev = prev->qh_next.qh;
+#ifdef DEBUG
+	if (prev->qh_next.qh != qh)
+		BUG ();
+#endif
+
+	if (qh->hw_info1 & __constant_cpu_to_le32 (QH_HEAD)) {
+		ehci->async = prev;
+		prev->hw_info1 |= __constant_cpu_to_le32 (QH_HEAD);
+	}
+	prev->hw_next = qh->hw_next;
+	prev->qh_next = qh->qh_next;
+
+	ehci->reclaim_ready = 0;
+	cmd |= CMD_IAAD;
+	writel (cmd, &ehci->regs->command);
+	/* posted write need not be known to HC yet ... */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_async (struct ehci_hcd *ehci)
+{
+	struct ehci_qh		*qh;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+rescan:
+	qh = ehci->async;
+	if (likely (qh != 0)) {
+		do {
+			/* clean any finished work for this qh */
+			if (!list_empty (&qh->qtd_list)) {
+				// dbg_qh ("scan_async", ehci, qh);
+				qh = qh_put (qh);
+				spin_unlock_irqrestore (&ehci->lock, flags);
+
+				/* concurrent unlink could happen here */
+				qh_completions (ehci, &qh->qtd_list, 1);
+
+				spin_lock_irqsave (&ehci->lock, flags);
+				qh_unput (ehci, qh);
+			}
+
+			/* unlink idle entries (reduces PCI usage) */
+			if (list_empty (&qh->qtd_list) && !ehci->reclaim) {
+				if (qh->qh_next.qh != qh) {
+					// dbg ("irq/empty");
+					start_unlink_async (ehci, qh);
+				} else {
+					// FIXME:  arrange to stop
+					// after it's been idle a while.
+				}
+			}
+			qh = qh->qh_next.qh;
+			if (!qh)		/* unlinked? */
+				goto rescan;
+		} while (qh != ehci->async);
+	}
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+}
diff -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci-sched.c linux/drivers/usb/hcd/ehci-sched.c
--- linux-2.5.2-pre5/drivers/usb/hcd/ehci-sched.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci-sched.c	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,1053 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI scheduled transaction support:  interrupt, iso, split iso
+ * These are called "periodic" transactions in the EHCI spec.
+ */
+
+/*
+ * Ceiling microseconds (typical) for that many bytes at high speed
+ * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
+ * to preallocate bandwidth)
+ */
+#define EHCI_HOST_DELAY	5	/* nsec, guess */
+#define HS_USECS(bytes) NS_TO_US ( ((55 * 8 * 2083)/1000) \
+	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+	+ EHCI_HOST_DELAY)
+#define HS_USECS_ISO(bytes) NS_TO_US ( ((long)(38 * 8 * 2.083)) \
+	+ ((2083UL * (3167 + BitTime (bytes)))/1000) \
+	+ EHCI_HOST_DELAY)
+	
+static int ehci_get_frame (struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * periodic_next_shadow - return "next" pointer on shadow list
+ * @periodic: host pointer to qh/itd/sitd
+ * @tag: hardware tag for type of this record
+ */
+static union ehci_shadow *
+periodic_next_shadow (union ehci_shadow *periodic, int tag)
+{
+	switch (tag) {
+	case Q_TYPE_QH:
+		return &periodic->qh->qh_next;
+	case Q_TYPE_FSTN:
+		return &periodic->fstn->fstn_next;
+#ifdef have_iso
+	case Q_TYPE_ITD:
+		return &periodic->itd->itd_next;
+	case Q_TYPE_SITD:
+		return &periodic->sitd->sitd_next;
+#endif /* have_iso */
+	}
+	dbg ("BAD shadow %p tag %d", periodic->ptr, tag);
+	// BUG ();
+	return 0;
+}
+
+/* returns true after successful unlink */
+/* caller must hold ehci->lock */
+static int periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
+{
+	union ehci_shadow	*prev_p = &ehci->pshadow [frame];
+	u32			*hw_p = &ehci->periodic [frame];
+	union ehci_shadow	here = *prev_p;
+	union ehci_shadow	*next_p;
+
+	/* find predecessor of "ptr"; hw and shadow lists are in sync */
+	while (here.ptr && here.ptr != ptr) {
+		prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
+		hw_p = &here.qh->hw_next;
+		here = *prev_p;
+	}
+	/* an interrupt entry (at list end) could have been shared */
+	if (!here.ptr) {
+		dbg ("entry %p no longer on frame [%d]", ptr, frame);
+		return 0;
+	}
+	// vdbg ("periodic unlink %p from frame %d", ptr, frame);
+
+	/* update hardware list ... HC may still know the old structure, so
+	 * don't change hw_next until it'll have purged its cache
+	 */
+	next_p = periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
+	*hw_p = here.qh->hw_next;
+
+	/* unlink from shadow list; HCD won't see old structure again */
+	*prev_p = *next_p;
+	next_p->ptr = 0;
+
+	return 1;
+}
+
+/* how many of the uframe's 125 usecs are allocated? */
+static unsigned short
+periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
+{
+	u32			*hw_p = &ehci->periodic [frame];
+	union ehci_shadow	*q = &ehci->pshadow [frame];
+	unsigned		usecs = 0;
+#ifdef have_iso
+	u32			temp = 0;
+#endif
+
+	while (q->ptr) {
+		switch (Q_NEXT_TYPE (*hw_p)) {
+		case Q_TYPE_QH:
+			/* is it in the S-mask? */
+			if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
+				usecs += q->qh->usecs;
+			q = &q->qh->qh_next;
+			break;
+		case Q_TYPE_FSTN:
+			/* for "save place" FSTNs, count the relevant INTR
+			 * bandwidth from the previous frame
+			 */
+			if (q->fstn->hw_prev != EHCI_LIST_END) {
+				dbg ("not counting FSTN bandwidth yet ...");
+			}
+			q = &q->fstn->fstn_next;
+			break;
+#ifdef have_iso
+		case Q_TYPE_ITD:
+			temp = le32_to_cpu (q->itd->transaction [uframe]);
+			temp >>= 16;
+			temp &= 0x0fff;
+			if (temp)
+				usecs += HS_USECS_ISO (temp);
+			q = &q->itd->itd_next;
+			break;
+		case Q_TYPE_SITD:
+			temp = q->sitd->hw_fullspeed_ep &
+				__constant_cpu_to_le32 (1 << 31);
+
+			// FIXME:  this doesn't count data bytes right...
+
+			/* is it in the S-mask?  (count SPLIT, DATA) */
+			if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
+				if (temp)
+					usecs += HS_USECS (188);
+				else
+					usecs += HS_USECS (1);
+			}
+
+			/* ... C-mask?  (count CSPLIT, DATA) */
+			if (q->sitd->hw_uframe &
+					cpu_to_le32 (1 << (8 + uframe))) {
+				if (temp)
+					usecs += HS_USECS (0);
+				else
+					usecs += HS_USECS (188);
+			}
+			q = &q->sitd->sitd_next;
+			break;
+#endif /* have_iso */
+		default:
+			BUG ();
+		}
+	}
+#ifdef	DEBUG
+	if (usecs > 100)
+		err ("overallocated uframe %d, periodic is %d usecs",
+			frame * 8 + uframe, usecs);
+#endif
+	return usecs;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void intr_deschedule (
+	struct ehci_hcd	*ehci,
+	unsigned	frame,
+	struct ehci_qh	*qh,
+	unsigned	period
+) {
+	unsigned long	flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	do {
+		periodic_unlink (ehci, frame, qh);
+		qh_unput (ehci, qh);
+		frame += period;
+	} while (frame < ehci->periodic_size);
+
+	qh->qh_state = QH_STATE_UNLINK;
+	qh->qh_next.ptr = 0;
+	ehci->periodic_urbs--;
+
+	/* maybe turn off periodic schedule */
+	if (!ehci->periodic_urbs) {
+		u32	cmd = readl (&ehci->regs->command);
+
+		/* did setting PSE not take effect yet?
+		 * takes effect only at frame boundaries...
+		 */
+		while (!(readl (&ehci->regs->status) & STS_PSS))
+			udelay (20);
+
+		cmd &= ~CMD_PSE;
+		writel (cmd, &ehci->regs->command);
+		/* posted write ... */
+
+		ehci->next_frame = -1;
+	} else
+		vdbg ("periodic schedule still enabled");
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+
+	/*
+	 * If the hc may be looking at this qh, then delay a uframe
+	 * (yeech!) to be sure it's done.
+	 * No other threads may be mucking with this qh.
+	 */
+	if (((ehci_get_frame (&ehci->hcd) - frame) % period) == 0)
+		udelay (125);
+
+	qh->qh_state = QH_STATE_IDLE;
+	qh->hw_next = EHCI_LIST_END;
+
+	vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
+		qh, period, frame,
+		atomic_read (&qh->refcount), ehci->periodic_urbs);
+}
+
+static int intr_submit (
+	struct ehci_hcd		*ehci,
+	struct urb		*urb,
+	struct list_head	*qtd_list,
+	int			mem_flags
+) {
+	unsigned		epnum, period;
+	unsigned		temp;
+	unsigned short		mult, usecs;
+	unsigned long		flags;
+	struct ehci_qh		*qh;
+	struct hcd_dev		*dev;
+	int			status = 0;
+
+	/* get endpoint and transfer data */
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe)) {
+		temp = urb->dev->epmaxpacketin [epnum];
+		epnum |= 0x10;
+	} else
+		temp = urb->dev->epmaxpacketout [epnum];
+	mult = 1;
+	if (urb->dev->speed == USB_SPEED_HIGH) {
+		/* high speed "high bandwidth" is coded in ep maxpacket */
+		mult += (temp >> 11) & 0x03;
+		temp &= 0x03ff;
+	} else {
+		dbg ("no intr/tt scheduling yet"); 
+		status = -ENOSYS;
+		goto done;
+	}
+
+	/*
+	 * NOTE: current completion/restart logic doesn't handle more than
+	 * one qtd in a periodic qh ... 16-20 KB/urb is pretty big for this.
+	 * such big requests need many periods to transfer.
+	 */
+	if (unlikely (qtd_list->next != qtd_list->prev)) {
+		dbg ("only one intr qtd per urb allowed"); 
+		status = -EINVAL;
+		goto done;
+	}
+
+	usecs = HS_USECS (urb->transfer_buffer_length);
+
+	/*
+	 * force a power-of-two (frames) sized polling interval
+	 *
+	 * NOTE: endpoint->bInterval for highspeed is measured in uframes,
+	 * while for full/low speeds it's in frames.  Here we "know" that
+	 * urb->interval doesn't give acccess to high interrupt rates.
+	 */
+	period = ehci->periodic_size;
+	temp = period;
+	if (unlikely (urb->interval < 1))
+		urb->interval = 1;
+	while (temp > urb->interval)
+		temp >>= 1;
+	period = urb->interval = temp;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* get the qh (must be empty and idle) */
+	dev = (struct hcd_dev *)urb->dev->hcpriv;
+	qh = (struct ehci_qh *) dev->ep [epnum];
+	if (qh) {
+		/* only allow one queued interrupt urb per EP */
+		if (unlikely (qh->qh_state != QH_STATE_IDLE
+				|| !list_empty (&qh->qtd_list))) {
+			dbg ("interrupt urb already queued");
+			status = -EBUSY;
+		} else {
+			/* maybe reset hardware's data toggle in the qh */
+			if (unlikely (!usb_gettoggle (urb->dev, epnum & 0x0f,
+					!(epnum & 0x10)))) {
+				qh->hw_token |=
+					__constant_cpu_to_le32 (QTD_TOGGLE);
+				usb_settoggle (urb->dev, epnum & 0x0f,
+					!(epnum & 0x10), 1);
+			}
+			/* trust the QH was set up as interrupt ... */
+			list_splice (qtd_list, &qh->qtd_list);
+			qh_update (qh, list_entry (qtd_list->next,
+						struct ehci_qtd, qtd_list));
+		}
+	} else {
+		/* can't sleep here, we have ehci->lock... */
+		qh = ehci_qh_make (ehci, urb, qtd_list, SLAB_ATOMIC);
+		qtd_list = &qh->qtd_list;
+		if (likely (qh != 0)) {
+			// dbg ("new INTR qh %p", qh);
+			dev->ep [epnum] = qh;
+		} else
+			status = -ENOMEM;
+	}
+
+	/* Schedule this periodic QH. */
+	if (likely (status == 0)) {
+		unsigned	frame = urb->interval;
+
+		qh->hw_next = EHCI_LIST_END;
+		qh->hw_info2 |= cpu_to_le32 (mult << 30);
+		qh->usecs = usecs;
+
+		urb->hcpriv = qh_put (qh);
+		status = -ENOSPC;
+
+		/* pick a set of schedule slots, link the QH into them */
+		do {
+			int	uframe;
+
+			/* Select some frame 0..(urb->interval - 1) with a
+			 * microframe that can hold this transaction.
+			 *
+			 * FIXME for TT splits, need uframes for start and end.
+			 * FSTNs can put end into next frame (uframes 0 or 1).
+			 */
+			frame--;
+			for (uframe = 0; uframe < 8; uframe++) {
+				int	claimed;
+				claimed = periodic_usecs (ehci, frame, uframe);
+				/* 80% periodic == 100 usec max committed */
+				if ((claimed + usecs) <= 100) {
+					vdbg ("frame %d.%d: %d usecs, plus %d",
+						frame, uframe, claimed, usecs);
+					break;
+				}
+			}
+			if (uframe == 8)
+				continue;
+// FIXME delete when code below handles non-empty queues
+			if (ehci->pshadow [frame].ptr)
+				continue;
+
+			/* QH will run once each period, starting there  */
+			urb->start_frame = frame;
+			status = 0;
+
+			/* set S-frame mask */
+			qh->hw_info2 |= cpu_to_le32 (1 << uframe);
+			// dbg_qh ("Schedule INTR qh", ehci, qh);
+
+			/* stuff into the periodic schedule */
+			qh->qh_state = QH_STATE_LINKED;
+			vdbg ("qh %p usecs %d period %d starting frame %d.%d",
+				qh, qh->usecs, period, frame, uframe);
+			do {
+				if (unlikely ((int)ehci->pshadow [frame].ptr)) {
+// FIXME -- just link to the end, before any qh with a shorter period,
+// AND handle it already being (implicitly) linked into this frame
+					BUG ();
+				} else {
+					ehci->pshadow [frame].qh = qh_put (qh);
+					ehci->periodic [frame] =
+						QH_NEXT (qh->qh_dma);
+				}
+				frame += period;
+			} while (frame < ehci->periodic_size);
+
+			/* maybe enable periodic schedule processing */
+			if (!ehci->periodic_urbs++) {
+				u32	cmd;
+
+				/* did clearing PSE did take effect yet?
+				 * takes effect only at frame boundaries...
+				 */
+				while (readl (&ehci->regs->status) & STS_PSS)
+					udelay (20);
+
+				cmd = readl (&ehci->regs->command) | CMD_PSE;
+				writel (cmd, &ehci->regs->command);
+				/* posted write ... PSS happens later */
+				ehci->hcd.state = USB_STATE_RUNNING;
+
+				/* make sure tasklet scans these */
+				ehci->next_frame = ehci_get_frame (&ehci->hcd);
+			}
+			break;
+
+		} while (frame);
+	}
+	spin_unlock_irqrestore (&ehci->lock, flags);
+done:
+	if (status) {
+		usb_complete_t	complete = urb->complete;
+
+		urb->complete = 0;
+		urb->status = status;
+		qh_completions (ehci, qtd_list, 1);
+		urb->complete = complete;
+	}
+	return status;
+}
+
+static unsigned long
+intr_complete (
+	struct ehci_hcd	*ehci,
+	unsigned	frame,
+	struct ehci_qh	*qh,
+	unsigned long	flags		/* caller owns ehci->lock ... */
+) {
+	struct ehci_qtd	*qtd;
+	struct urb	*urb;
+	int		unlinking;
+
+	/* nothing to report? */
+	if (likely ((qh->hw_token & __constant_cpu_to_le32 (QTD_STS_ACTIVE))
+			!= 0))
+		return flags;
+	
+	qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list);
+	urb = qtd->urb;
+	unlinking = (urb->status == -ENOENT) || (urb->status == -ECONNRESET);
+
+	/* call any completions, after patching for reactivation */
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	/* NOTE:  currently restricted to one qtd per qh! */
+	if (qh_completions (ehci, &qh->qtd_list, 0) == 0)
+		urb = 0;
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* never reactivate requests that were unlinked ... */
+	if (likely (urb != 0)) {
+		if (unlinking
+				|| urb->status == -ECONNRESET
+				|| urb->status == -ENOENT
+				// || (urb->dev == null)
+				|| ehci->hcd.state == USB_STATE_HALT)
+			urb = 0;
+		// FIXME look at all those unlink cases ... we always
+		// need exactly one completion that reports unlink.
+		// the one above might not have been it!
+	}
+
+	/* normally reactivate */
+	if (likely (urb != 0)) {
+		if (usb_pipeout (urb->pipe))
+			pci_dma_sync_single (ehci->hcd.pdev,
+				qtd->buf_dma,
+				urb->transfer_buffer_length,
+				PCI_DMA_TODEVICE);
+		urb->status = -EINPROGRESS;
+		urb->actual_length = 0;
+
+		/* patch qh and restart */
+		qh_update (qh, qtd);
+	}
+	return flags;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	have_iso
+
+static inline void itd_free (struct ehci_hcd *ehci, struct ehci_itd *itd)
+{
+	pci_pool_free (ehci->itd_pool, itd, itd->itd_dma);
+}
+
+/*
+ * Create itd and allocate into uframes within specified frame.
+ * Caller must update the resulting uframe links.
+ */
+static struct ehci_itd *
+itd_make (
+	struct ehci_hcd	*ehci,
+	struct urb	*urb,
+	unsigned	index,		// urb->iso_frame_desc [index]
+	unsigned	frame,		// scheduled start
+	dma_addr_t	dma,		// mapped transfer buffer
+	int		mem_flags
+) {
+	struct ehci_itd	*itd;
+	u64		temp;
+	u32		buf1;
+	unsigned	epnum, maxp, multi, usecs;
+	unsigned	length;
+	unsigned	i, bufnum;
+
+	/* allocate itd, start to fill it */
+	itd = pci_pool_alloc (ehci->itd_pool, mem_flags, &dma);
+	if (!itd)
+		return itd;
+
+	itd->hw_next = EHCI_LIST_END;
+	itd->urb = urb;
+	itd->index = index;
+	INIT_LIST_HEAD (&itd->itd_list);
+	itd->uframe = (frame * 8) % ehci->periodic_size;
+
+	/* tell itd about the buffer its transfers will consume */
+	length = urb->iso_frame_desc [index].length;
+	dma += urb->iso_frame_desc [index].offset;
+	temp = dma & ~0x0fff;
+	for (i = 0; i < 7; i++) {
+		itd->hw_bufp [i] = cpu_to_le32 ((u32) temp);
+		itd->hw_bufp_hi [i] = cpu_to_le32 ((u32)(temp >> 32));
+		temp += 0x0fff;
+	}
+
+	/*
+	 * this might be a "high bandwidth" highspeed endpoint,
+	 * as encoded in the ep descriptor's maxpacket field
+	 */
+	epnum = usb_pipeendpoint (urb->pipe);
+	if (usb_pipein (urb->pipe)) {
+		maxp = urb->dev->epmaxpacketin [epnum];
+		buf1 = (1 << 11) | maxp;
+	} else {
+		maxp = urb->dev->epmaxpacketout [epnum];
+		buf1 = maxp;
+	}
+	multi = 1;
+	multi += (temp >> 11) & 0x03;
+	maxp &= 0x03ff;
+
+	/* "plus" info in low order bits of buffer pointers */
+	itd->hw_bufp [0] |= cpu_to_le32 ((epnum << 8) | urb->dev->devnum);
+	itd->hw_bufp [1] |= cpu_to_le32 (buf1);
+	itd->hw_bufp [2] |= cpu_to_le32 (multi);
+
+	/* schedule as many uframes as needed */
+	maxp *= multi;
+	usecs = HS_USECS_ISO (maxp);
+	bufnum = 0;
+	for (i = 0; i < 8; i++) {
+		unsigned	t, offset, scratch;
+
+		if (length <= 0) {
+			itd->hw_transaction [i] = 0;
+			continue;
+		}
+
+		/* don't commit more than 80% periodic == 100 usec */
+		if ((periodic_usecs (ehci, itd->uframe, i) + usecs) > 100)
+			continue;
+
+		/* we'll use this uframe; figure hw_transaction */
+		t = EHCI_ISOC_ACTIVE;
+		t |= bufnum << 12;		// which buffer?
+		offset = temp & 0x0fff;		// offset therein
+		t |= offset;
+		if ((offset + maxp) >= 4096) 	// hc auto-wraps end-of-"page"
+			bufnum++;
+		if (length <= maxp) {
+			// interrupt only needed at end-of-urb
+			if ((index + 1) == urb->number_of_packets)
+				t |= EHCI_ITD_IOC;
+			scratch = length;
+		} else
+			scratch = maxp;
+		t |= scratch << 16;
+		t = cpu_to_le32 (t);
+
+		itd->hw_transaction [i] = itd->transaction [i] = t;
+		length -= scratch;
+	}
+	if (length > 0) {
+		dbg ("iso frame too big, urb %p [%d], %d extra (of %d)",
+			urb, index, length, urb->iso_frame_desc [index].length);
+		itd_free (ehci, itd);
+		itd = 0;
+	}
+	return itd;
+}
+
+static inline void
+itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
+{
+	u32		ptr;
+
+	ptr = cpu_to_le32 (itd->itd_dma);	// type 0 == itd
+	if (ehci->pshadow [frame].ptr) {
+		if (!itd->itd_next.ptr) {
+			itd->itd_next = ehci->pshadow [frame];
+			itd->hw_next = ehci->periodic [frame];
+		} else if (itd->itd_next.ptr != ehci->pshadow [frame].ptr) {
+			dbg ("frame %d itd link goof", frame);
+			BUG ();
+		}
+	}
+	ehci->pshadow [frame].itd = itd;
+	ehci->periodic [frame] = ptr;
+}
+
+#define	ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
+
+static unsigned long
+itd_complete (struct ehci_hcd *ehci, struct ehci_itd *itd, unsigned long flags)
+{
+	struct urb		*urb = itd->urb;
+
+	/* if not unlinking: */
+	if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
+			&& ehci->hcd.state != USB_STATE_HALT) {
+		int			i;
+		iso_packet_descriptor_t	*desc;
+		struct ehci_itd		*first_itd = urb->hcpriv;
+
+		/* update status for this frame's transfers */
+		desc = &urb->iso_frame_desc [itd->index];
+		desc->status = 0;
+		desc->actual_length = 0;
+		for (i = 0; i < 8; i++) {
+			u32	 t = itd->hw_transaction [i];
+			if (t & (ISO_ERRS | EHCI_ISOC_ACTIVE)) {
+				if (t & EHCI_ISOC_ACTIVE)
+					desc->status = -EXDEV;
+				else if (t & EHCI_ISOC_BUF_ERR)
+					desc->status = usb_pipein (urb->pipe)
+						? -ENOSR  /* couldn't read */
+						: -ECOMM; /* couldn't write */
+				else if (t & EHCI_ISOC_BABBLE)
+					desc->status = -EOVERFLOW;
+				else /* (t & EHCI_ISOC_XACTERR) */
+					desc->status = -EPROTO;
+				break;
+			}
+			desc->actual_length += EHCI_ITD_LENGTH (t);
+		}
+
+		/* handle completion now? */
+		if ((itd->index + 1) != urb->number_of_packets)
+			return flags;
+
+		i = usb_pipein (urb->pipe);
+		if (i)
+			pci_dma_sync_single (ehci->hcd.pdev,
+				first_itd->buf_dma,
+				urb->transfer_buffer_length,
+				PCI_DMA_FROMDEVICE);
+
+		/* call completion with no locks; it can unlink ... */
+		spin_unlock_irqrestore (&ehci->lock, flags);
+		urb->complete (urb);
+		spin_lock_irqsave (&ehci->lock, flags);
+
+		/* re-activate this URB? or unlink? */
+		if (!(urb->transfer_flags & EHCI_STATE_UNLINK)
+				&& ehci->hcd.state != USB_STATE_HALT) {
+			if (!i)
+				pci_dma_sync_single (ehci->hcd.pdev,
+					first_itd->buf_dma,
+					urb->transfer_buffer_length,
+					PCI_DMA_TODEVICE);
+
+			itd = urb->hcpriv;
+			do {
+				for (i = 0; i < 8; i++)
+					itd->hw_transaction [i]
+						= itd->transaction [i];
+				itd = list_entry (itd->itd_list.next,
+						struct ehci_itd, itd_list);
+			} while (itd != urb->hcpriv);
+			return flags;
+		}
+
+	/* unlink done only on the last itd */
+	} else if ((itd->index + 1) != urb->number_of_packets)
+		return flags;
+
+	/* we're unlinking ... */
+
+	/* decouple urb from the hcd */
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	if (ehci->hcd.state == USB_STATE_HALT)
+		urb->status = -ESHUTDOWN;
+	itd = urb->hcpriv;
+	urb->hcpriv = 0;
+	ehci_urb_done (ehci, itd->buf_dma, urb);
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/* take itds out of the hc's periodic schedule */
+	list_entry (itd->itd_list.prev, struct ehci_itd, itd_list)
+		->itd_list.next = 0;
+	do {
+		struct ehci_itd	*next;
+
+		if (itd->itd_list.next)
+			next = list_entry (itd->itd_list.next,
+				struct ehci_itd, itd_list);
+		else
+			next = 0;
+
+		// FIXME:  hc WILL (!) lap us here, if we get behind
+		// by 128 msec (or less, with smaller periodic_size).
+		// Reading/caching these itds will cause trouble...
+
+		periodic_unlink (ehci, itd->uframe, itd);
+		itd_free (ehci, itd);
+		itd = next;
+	} while (itd);
+	return flags;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb)
+{
+	struct ehci_itd		*first_itd = 0, *itd;
+	unsigned		frame_index;
+	dma_addr_t		dma;
+	unsigned long		flags;
+
+	dbg ("itd_submit");
+
+	/* set up one dma mapping for this urb */
+	dma = pci_map_single (ehci->hcd.pdev,
+		urb->transfer_buffer, urb->transfer_buffer_length,
+		usb_pipein (urb->pipe)
+		    ? PCI_DMA_FROMDEVICE
+		    : PCI_DMA_TODEVICE);
+	if (dma == 0)
+		return -ENOMEM;
+
+	/*
+	 * Schedule as needed.  This is VERY optimistic about free
+	 * bandwidth!  But the API assumes drivers can pick frames
+	 * intelligently (how?), so there's no other good option.
+	 *
+	 * FIXME  this doesn't handle urb->next rings, or try to
+	 * use the iso periodicity.
+	 */
+	if (urb->transfer_flags & USB_ISO_ASAP) { 
+		urb->start_frame = ehci_get_frame (&ehci->hcd);
+		urb->start_frame++;
+	}
+	urb->start_frame %= ehci->periodic_size;
+
+	/* create and populate itds (doing uframe scheduling) */
+	spin_lock_irqsave (&ehci->lock, flags);
+	for (frame_index = 0;
+			frame_index < urb->number_of_packets;
+			frame_index++) {
+		itd = itd_make (ehci, urb, frame_index,
+			urb->start_frame + frame_index,
+			dma, SLAB_ATOMIC);
+		if (itd) {
+			if (first_itd)
+				list_add_tail (&itd->itd_list,
+						&first_itd->itd_list);
+			else
+				first_itd = itd;
+		} else {
+			spin_unlock_irqrestore (&ehci->lock, flags);
+			if (first_itd) {
+				while (!list_empty (&first_itd->itd_list)) {
+					itd = list_entry (
+						first_itd->itd_list.next,
+						struct ehci_itd, itd_list);
+					list_del (&itd->itd_list);
+					itd_free (ehci, itd);
+				}
+				itd_free (ehci, first_itd);
+			}
+			pci_unmap_single (ehci->hcd.pdev,
+				dma, urb->transfer_buffer_length,
+				usb_pipein (urb->pipe)
+				    ? PCI_DMA_FROMDEVICE
+				    : PCI_DMA_TODEVICE);
+			return -ENOMEM;
+		}
+	}
+
+	/* stuff into the schedule */
+	itd = first_itd;
+	do {
+		unsigned	i;
+
+		for (i = 0; i < 8; i++) {
+			if (!itd->hw_transaction [i])
+				continue;
+			itd_link (ehci, itd->uframe + i, itd);
+		}
+		itd = list_entry (itd->itd_list.next,
+			struct ehci_itd, itd_list);
+	} while (itd != first_itd);
+	urb->hcpriv = first_itd;
+
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * "Split ISO TDs" ... used for USB 1.1 devices going through
+ * the TTs in USB 2.0 hubs.
+ */
+
+static inline void
+sitd_free (struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+{
+	pci_pool_free (ehci->sitd_pool, sitd, sitd->sitd_dma);
+}
+
+static struct ehci_sitd *
+sitd_make (
+	struct ehci_hcd	*ehci,
+	struct urb	*urb,
+	unsigned	index,		// urb->iso_frame_desc [index]
+	unsigned	uframe,		// scheduled start
+	dma_addr_t	dma,		// mapped transfer buffer
+	int		mem_flags
+) {
+	struct ehci_sitd	*sitd;
+	unsigned		length;
+
+	sitd = pci_pool_alloc (ehci->sitd_pool, mem_flags, &dma);
+	if (!sitd)
+		return sitd;
+	sitd->urb = urb;
+	length = urb->iso_frame_desc [index].length;
+	dma += urb->iso_frame_desc [index].offset;
+
+#if 0
+	// FIXME:  do the rest!
+#else
+	sitd_free (ehci, sitd);
+	return 0;
+#endif
+
+}
+
+static inline void
+sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
+{
+	u32		ptr;
+
+	ptr = cpu_to_le32 (sitd->sitd_dma | 2);	// type 2 == sitd
+	if (ehci->pshadow [frame].ptr) {
+		if (!sitd->sitd_next.ptr) {
+			sitd->sitd_next = ehci->pshadow [frame];
+			sitd->hw_next = ehci->periodic [frame];
+		} else if (sitd->sitd_next.ptr != ehci->pshadow [frame].ptr) {
+			dbg ("frame %d sitd link goof", frame);
+			BUG ();
+		}
+	}
+	ehci->pshadow [frame].sitd = sitd;
+	ehci->periodic [frame] = ptr;
+}
+
+static unsigned long
+sitd_complete (
+	struct ehci_hcd *ehci,
+	struct ehci_sitd	*sitd,
+	unsigned long		flags
+) {
+	// FIXME -- implement!
+
+	dbg ("NYI -- sitd_complete");
+	return flags;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb)
+{
+	// struct ehci_sitd	*first_sitd = 0;
+	unsigned		frame_index;
+	dma_addr_t		dma;
+	int			mem_flags;
+
+	dbg ("NYI -- sitd_submit");
+
+	// FIXME -- implement!
+
+	// FIXME:  setup one big dma mapping
+	dma = 0;
+
+	mem_flags = SLAB_ATOMIC;
+
+	for (frame_index = 0;
+			frame_index < urb->number_of_packets;
+			frame_index++) {
+		struct ehci_sitd	*sitd;
+		unsigned		uframe;
+
+		// FIXME:  use real arguments, schedule this!
+		uframe = -1;
+
+		sitd = sitd_make (ehci, urb, frame_index,
+				uframe, dma, mem_flags);
+
+		if (sitd) {
+    /*
+			if (first_sitd)
+				list_add_tail (&sitd->sitd_list,
+						&first_sitd->sitd_list);
+			else
+				first_sitd = sitd;
+    */
+		} else {
+			// FIXME:  clean everything up
+		}
+	}
+
+	// if we have a first sitd, then
+		// store them all into the periodic schedule!
+		// urb->hcpriv = first sitd in sitd_list
+
+	return -ENOSYS;
+}
+
+#endif	/* have_iso */
+
+/*-------------------------------------------------------------------------*/
+
+static void scan_periodic (struct ehci_hcd *ehci)
+{
+	unsigned	frame;
+	unsigned	clock;
+	unsigned long	flags;
+
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/*
+	 * When running, scan from last scan point up to "now"
+	 * Touches as few pages as possible:  cache-friendly.
+	 * It's safe to scan entries more than once, though.
+	 */
+	if (HCD_IS_RUNNING (ehci->hcd.state)) {
+		frame = ehci->next_frame;
+		clock = ehci_get_frame (&ehci->hcd);
+
+	/* when shutting down, scan everything for thoroughness */
+	} else {
+		frame = 0;
+		clock = ehci->periodic_size - 1;
+	}
+	for (;;) {
+		union ehci_shadow	 q;
+		u32	type;
+
+restart:
+		q.ptr = ehci->pshadow [frame].ptr;
+		type = Q_NEXT_TYPE (ehci->periodic [frame]);
+
+		/* scan each element in frame's queue for completions */
+		while (q.ptr != 0) {
+			int			last;
+			union ehci_shadow	temp;
+
+			switch (type) {
+			case Q_TYPE_QH:
+				last = (q.qh->hw_next == EHCI_LIST_END);
+				flags = intr_complete (ehci, frame,
+						qh_put (q.qh), flags);
+				type = Q_NEXT_TYPE (q.qh->hw_next);
+				temp = q.qh->qh_next;
+				qh_unput (ehci, q.qh);
+				q = temp;
+				break;
+			case Q_TYPE_FSTN:
+				last = (q.fstn->hw_next == EHCI_LIST_END);
+				/* for "save place" FSTNs, look at QH entries
+				 * in the previous frame for completions.
+				 */
+				if (q.fstn->hw_prev != EHCI_LIST_END) {
+					dbg ("ignoring completions from FSTNs");
+				}
+				type = Q_NEXT_TYPE (q.fstn->hw_next);
+				temp = q.fstn->fstn_next;
+				break;
+#ifdef have_iso
+			case Q_TYPE_ITD:
+				last = (q.itd->hw_next == EHCI_LIST_END);
+				flags = itd_complete (ehci, q.itd, flags);
+				type = Q_NEXT_TYPE (q.itd->hw_next);
+				q = q.itd->itd_next;
+				break;
+			case Q_TYPE_SITD:
+				last = (q.sitd->hw_next == EHCI_LIST_END);
+				flags = sitd_complete (ehci, q.sitd, flags);
+				type = Q_NEXT_TYPE (q.sitd->hw_next);
+				q = q.sitd->sitd_next;
+				break;
+#endif /* have_iso */
+			default:
+				dbg ("corrupt type %d frame %d shadow %p",
+					type, frame, q.ptr);
+				// BUG ();
+				last = 1;
+				q.ptr = 0;
+			}
+
+			/* did completion remove an interior q entry? */
+			if (unlikely (q.ptr == 0 && !last))
+				goto restart;
+		}
+
+		/* stop when we catch up to the HC */
+
+		// FIXME:  this assumes we won't get lapped when
+		// latencies climb; that should be rare, but...
+		// detect it, and just go all the way around.
+		// FLR might help detect this case, so long as latencies
+		// don't exceed periodic_size msec (default 1.024 sec).
+
+		// FIXME:  likewise assumes HC doesn't halt mid-scan
+
+		if (frame == clock) {
+			unsigned	now;
+
+			if (!HCD_IS_RUNNING (ehci->hcd.state))
+				break;
+			ehci->next_frame = clock;
+			now = ehci_get_frame (&ehci->hcd);
+			if (clock == now)
+				break;
+			clock = now;
+		} else if (++frame >= ehci->periodic_size)
+			frame = 0;
+	} 
+	spin_unlock_irqrestore (&ehci->lock, flags);
+ }
diff -urN linux-2.5.2-pre5/drivers/usb/hcd/ehci.h linux/drivers/usb/hcd/ehci.h
--- linux-2.5.2-pre5/drivers/usb/hcd/ehci.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd/ehci.h	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_EHCI_HCD_H
+#define __LINUX_EHCI_HCD_H
+
+/* definitions used for the EHCI driver */
+
+/* ehci_hcd->lock guards shared data against other CPUs:
+ *   ehci_hcd:	async, reclaim, periodic (and shadow), ...
+ *   hcd_dev:	ep[]
+ *   ehci_qh:	qh_next, qtd_list
+ *   ehci_qtd:	qtd_list
+ *
+ * Also, hold this lock when talking to HC registers or
+ * when updating hw_* fields in shared qh/qtd/... structures.
+ */
+
+#define	EHCI_MAX_ROOT_PORTS	15		/* see HCS_N_PORTS */
+
+struct ehci_hcd {			/* one per controller */
+	spinlock_t		lock;
+
+	/* async schedule support */
+	struct ehci_qh		*async;
+	struct ehci_qh		*reclaim;
+	int			reclaim_ready;
+
+	/* periodic schedule support */
+#define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
+	unsigned		periodic_size;
+	u32			*periodic;	/* hw periodic table */
+	dma_addr_t		periodic_dma;
+	unsigned		i_thresh;	/* uframes HC might cache */
+
+	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
+	int			next_frame;	/* scan periodic, start here */
+	unsigned		periodic_urbs;	/* how many urbs scheduled? */
+
+	/* deferred work from IRQ, etc */
+	struct tasklet_struct	tasklet;
+
+	/* per root hub port */
+	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
+
+	/* glue to PCI and HCD framework */
+	struct usb_hcd		hcd;
+	struct ehci_caps	*caps;
+	struct ehci_regs	*regs;
+
+	/* per-HC memory pools (could be per-PCI-bus, but ...) */
+	struct pci_pool		*qh_pool;	/* qh per active urb */
+	struct pci_pool		*qtd_pool;	/* one or more per qh */
+	struct pci_pool		*itd_pool;	/* itd per iso urb */
+	struct pci_pool		*sitd_pool;	/* sitd per split iso urb */
+};
+
+/* unwrap an HCD pointer to get an EHCI_HCD pointer */ 
+#define hcd_to_ehci(hcd_ptr) list_entry(hcd_ptr, struct ehci_hcd, hcd)
+
+/* NOTE:  urb->transfer_flags expected to not use this bit !!! */
+#define EHCI_STATE_UNLINK	0x8000		/* urb being unlinked */
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+	u8		length;		/* CAPLENGTH - size of this struct */
+	u8		reserved;       /* offset 0x1 */
+	u16		hci_version;    /* HCIVERSION - offset 0x2 */
+	u32		hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p)	(((p)>>20)&0xf)	/* bits 23:20, debug port? */
+#define HCS_INDICATOR(p)	((p)&(1 << 16))	/* true: has port indicators */
+#define HCS_N_CC(p)		(((p)>>12)&0xf)	/* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p)		(((p)>>8)&0xf)	/* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p)	((p)&(1 << 7))	/* true: port routing */ 
+#define HCS_PPC(p)		((p)&(1 << 4))	/* true: port power control */ 
+#define HCS_N_PORTS(p)		(((p)>>0)&0xf)	/* bits 3:0, ports on HC */
+
+	u32		hcc_params;      /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p)		(((p)>>8)&0xff)	/* for pci extended caps */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p)		((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
+	u8		portroute [8];	 /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+	/* USBCMD: offset 0x00 */
+	u32		command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK	(1<<11)		/* enable "park" on async qh */
+#define CMD_PARK_CNT(c)	(((c)>>8)&3)	/* how many transfers to park for */
+#define CMD_LRESET	(1<<7)		/* partial reset (no ports, etc) */
+#define CMD_IAAD	(1<<6)		/* "doorbell" interrupt async advance */
+#define CMD_ASE		(1<<5)		/* async schedule enable */
+#define CMD_PSE  	(1<<4)		/* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET	(1<<1)		/* reset HC not bus */
+#define CMD_RUN		(1<<0)		/* start/stop HC */
+
+	/* USBSTS: offset 0x04 */
+	u32		status;
+#define STS_ASS		(1<<15)		/* Async Schedule Status */
+#define STS_PSS		(1<<14)		/* Periodic Schedule Status */
+#define STS_RECL	(1<<13)		/* Reclamation */
+#define STS_HALT	(1<<12)		/* Not running (any reason) */
+/* some bits reserved */
+	/* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA		(1<<5)		/* Interrupted on async advance */
+#define STS_FATAL	(1<<4)		/* such as some PCI access errors */
+#define STS_FLR		(1<<3)		/* frame list rolled over */
+#define STS_PCD		(1<<2)		/* port change detect */
+#define STS_ERR		(1<<1)		/* "error" completion (overflow, ...) */
+#define STS_INT		(1<<0)		/* "normal" completion (short, ...) */
+
+	/* USBINTR: offset 0x08 */
+	u32		intr_enable;
+
+	/* FRINDEX: offset 0x0C */
+	u32		frame_index;	/* current microframe number */
+	/* CTRLDSSEGMENT: offset 0x10 */
+	u32		segment; 	/* address bits 63:32 if needed */
+	/* PERIODICLISTBASE: offset 0x14 */
+	u32		frame_list; 	/* points to periodic list */
+	/* ASYNCICLISTADDR: offset 0x18 */
+	u32		async_next;	/* address of next async queue head */
+
+	u32		reserved [9];
+
+	/* CONFIGFLAG: offset 0x40 */
+	u32		configured_flag;
+#define FLAG_CF		(1<<0)		/* true: we'll support "high speed" */
+
+	/* PORTSC: offset 0x44 */
+	u32		port_status [0];	/* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E	(1<<22)		/* wake on overcurrent (enable) */
+#define PORT_WKDISC_E	(1<<21)		/* wake on disconnect (enable) */
+#define PORT_WKCONN_E	(1<<20)		/* wake on connect (enable) */
+/* 19:16 for port testing */
+/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */
+#define PORT_OWNER	(1<<13)		/* true: companion hc owns this port */
+#define PORT_POWER	(1<<12)		/* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10))==(1<<10))	/* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET	(1<<8)		/* reset port */
+#define PORT_SUSPEND	(1<<7)		/* suspend port */
+#define PORT_RESUME	(1<<6)		/* resume it */
+#define PORT_OCC	(1<<5)		/* over current change */
+#define PORT_OC		(1<<4)		/* over current active */
+#define PORT_PEC	(1<<3)		/* port enable change */
+#define PORT_PE		(1<<2)		/* port enable */
+#define PORT_CSC	(1<<1)		/* connect status change */
+#define PORT_CONNECT	(1<<0)		/* device connected */
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+#define	QTD_NEXT(dma)	cpu_to_le32((u32)dma)
+
+/*
+ * EHCI Specification 0.95 Section 3.5
+ * QTD: describe data transfer components (buffer, direction, ...) 
+ * See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
+ *
+ * These are associated only with "QH" (Queue Head) structures,
+ * used with control, bulk, and interrupt transfers.
+ */
+struct ehci_qtd {
+	/* first part defined by EHCI spec */
+	u32			hw_next;	  /* see EHCI 3.5.1 */
+	u32			hw_alt_next;      /* see EHCI 3.5.2 */
+	u32			hw_token;         /* see EHCI 3.5.3 */       
+#define	QTD_TOGGLE	(1 << 31)	/* data toggle */
+#define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
+#define	QTD_IOC		(1 << 15)	/* interrupt on complete */
+#define	QTD_CERR(tok)	(((tok)>>10) & 0x3)
+#define	QTD_PID(tok)	(((tok)>>8) & 0x3)
+#define	QTD_STS_ACTIVE	(1 << 7)	/* HC may execute this */
+#define	QTD_STS_HALT	(1 << 6)	/* halted on error */
+#define	QTD_STS_DBE	(1 << 5)	/* data buffer error (in HC) */
+#define	QTD_STS_BABBLE	(1 << 4)	/* device was babbling (qtd halted) */
+#define	QTD_STS_XACT	(1 << 3)	/* device gave illegal response */
+#define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
+#define	QTD_STS_STS	(1 << 1)	/* split transaction state */
+#define	QTD_STS_PING	(1 << 0)	/* issue PING? */
+	u32			hw_buf [5];        /* see EHCI 3.5.4 */
+	u32			hw_buf_hi [5];        /* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		qtd_dma;		/* qtd address */
+	struct list_head	qtd_list;		/* sw qtd list */
+
+	/* dma same in urb's qtds, except 1st control qtd (setup buffer) */
+	struct urb		*urb;			/* qtd's urb */
+	dma_addr_t		buf_dma;		/* buffer address */
+	size_t			length;			/* length of buffer */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/* type tag from {qh,itd,sitd,fstn}->hw_next */
+#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
+
+/* values for that type tag */
+#define Q_TYPE_ITD	__constant_cpu_to_le32 (0 << 1)
+#define Q_TYPE_QH	__constant_cpu_to_le32 (1 << 1)
+#define Q_TYPE_SITD 	__constant_cpu_to_le32 (2 << 1)
+#define Q_TYPE_FSTN 	__constant_cpu_to_le32 (3 << 1)
+
+/* next async queue entry, or pointer to interrupt/periodic QH */
+#define	QH_NEXT(dma)	(cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+
+/* for periodic/async schedules and qtd lists, mark end of list */
+#define	EHCI_LIST_END	__constant_cpu_to_le32(1) /* "null pointer" to hw */
+
+/*
+ * Entries in periodic shadow table are pointers to one of four kinds
+ * of data structure.  That's dictated by the hardware; a type tag is
+ * encoded in the low bits of the hardware's periodic schedule.  Use
+ * Q_NEXT_TYPE to get the tag.
+ *
+ * For entries in the async schedule, the type tag always says "qh".
+ */
+union ehci_shadow {
+	struct ehci_qh 		*qh;		/* Q_TYPE_QH */
+	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
+	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
+	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
+	void			*ptr;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.6
+ * QH: describes control/bulk/interrupt endpoints
+ * See Fig 3-7 "Queue Head Structure Layout".
+ *
+ * These appear in both the async and (for interrupt) periodic schedules.
+ */
+
+struct ehci_qh {
+	/* first part defined by EHCI spec */
+	u32			hw_next;	 /* see EHCI 3.6.1 */
+	u32			hw_info1;        /* see EHCI 3.6.2 */
+#define	QH_HEAD		0x00008000
+	u32			hw_info2;        /* see EHCI 3.6.2 */
+	u32			hw_current;	 /* qtd list - see EHCI 3.6.4 */
+	
+	/* qtd overlay (hardware parts of a struct ehci_qtd) */
+	u32			hw_qtd_next;
+	u32			hw_alt_next;
+	u32			hw_token;
+	u32			hw_buf [5];
+	u32			hw_buf_hi [5];
+
+	/* the rest is HCD-private */
+	dma_addr_t		qh_dma;		/* address of qh */
+	union ehci_shadow	qh_next;	/* ptr to qh; or periodic */
+	struct list_head	qtd_list;	/* sw qtd list */
+
+	atomic_t		refcount;
+	unsigned short		usecs;		/* intr bandwidth */
+	short			qh_state;
+#define	QH_STATE_LINKED		1		/* HC sees this */
+#define	QH_STATE_UNLINK		2		/* HC may still see this */
+#define	QH_STATE_IDLE		3		/* HC doesn't see this */
+
+#ifdef EHCI_SOFT_RETRIES
+	int			retries;
+#endif
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.3
+ * Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
+ *
+ * Schedule records for high speed iso xfers
+ */
+struct ehci_itd {
+	/* first part defined by EHCI spec */
+	u32			hw_next;           /* see EHCI 3.3.1 */
+	u32			hw_transaction [8]; /* see EHCI 3.3.2 */
+#define EHCI_ISOC_ACTIVE        (1<<31)        /* activate transfer this slot */
+#define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
+#define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
+#define EHCI_ISOC_XACTERR       (1<<28)        /* XactErr - transaction error */
+#define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
+#define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
+
+	u32			hw_bufp [7];	/* see EHCI 3.3.3 */ 
+	u32			hw_bufp_hi [7];	/* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		itd_dma;	/* for this itd */
+	union ehci_shadow	itd_next;	/* ptr to periodic q entry */
+
+	struct urb		*urb;
+	unsigned		index;		/* in urb->iso_frame_desc */
+	struct list_head	itd_list;	/* list of urb frames' itds */
+	dma_addr_t		buf_dma;	/* frame's buffer address */
+
+	unsigned		uframe;		/* in periodic schedule */
+	u32			transaction [8]; /* copy of hw_transaction */
+
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.95 Section 3.4 
+ * siTD, aka split-transaction isochronous Transfer Descriptor
+ *       ... describe low/full speed iso xfers through TT in hubs
+ * see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
+ */
+struct ehci_sitd {
+	/* first part defined by EHCI spec */
+	u32			hw_next;
+/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
+	u32			hw_fullspeed_ep;  /* see EHCI table 3-9 */
+	u32                     hw_uframe;        /* see EHCI table 3-10 */
+        u32                     hw_tx_results1;   /* see EHCI table 3-11 */
+	u32                     hw_tx_results2;   /* see EHCI table 3-12 */
+	u32                     hw_tx_results3;   /* see EHCI table 3-12 */
+        u32                     hw_backpointer;   /* see EHCI table 3-13 */
+	u32			hw_buf_hi [2];	  /* Appendix B */
+
+	/* the rest is HCD-private */
+	dma_addr_t		sitd_dma;
+	union ehci_shadow	sitd_next;	/* ptr to periodic q entry */
+	struct urb		*urb;
+	dma_addr_t		buf_dma;	/* buffer address */
+} __attribute__ ((aligned (32)));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * EHCI Specification 0.96 Section 3.7
+ * Periodic Frame Span Traversal Node (FSTN)
+ *
+ * Manages split interrupt transactions (using TT) that span frame boundaries
+ * into uframes 0/1; see 4.12.2.2.  In those uframes, a "save place" FSTN
+ * makes the HC jump (back) to a QH to scan for fs/ls QH completions until
+ * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
+ */
+struct ehci_fstn {
+	u32			hw_next;	/* any periodic q entry */
+	u32			hw_prev;	/* qh or EHCI_LIST_END */
+
+	/* the rest is HCD-private */
+	dma_addr_t		fstn_dma;
+	union ehci_shadow	fstn_next;	/* ptr to periodic q entry */
+} __attribute__ ((aligned (32)));
+
+#endif /* __LINUX_EHCI_HCD_H */
diff -urN linux-2.5.2-pre5/drivers/usb/hcd.c linux/drivers/usb/hcd.c
--- linux-2.5.2-pre5/drivers/usb/hcd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd.c	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,1305 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/uts.h>			/* for UTS_SYSNAME */
+
+#ifndef CONFIG_USB_DEBUG
+	#define CONFIG_USB_DEBUG	/* this is experimental! */
+#endif
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver framework
+ *
+ * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing
+ * HCD-specific behaviors/bugs.
+ *
+ * This does error checks, tracks devices and urbs, and delegates to a
+ * "hc_driver" only for code (and data) that really needs to know about
+ * hardware differences.  That includes root hub registers, i/o queues,
+ * and so on ... but as little else as possible.
+ *
+ * Shared code includes most of the "root hub" code (these are emulated,
+ * though each HC's hardware works differently) and PCI glue, plus request
+ * tracking overhead.  The HCD code should only block on spinlocks or on
+ * hardware handshaking; blocking on software events (such as other kernel
+ * threads releasing resources, or completing actions) is all generic.
+ *
+ * Happens the USB 2.0 spec says this would be invisible inside the "USBD",
+ * and includes mostly a "HCDI" (HCD Interface) along with some APIs used
+ * only by the hub driver ... and that neither should be seen or used by
+ * usb client device drivers.
+ *
+ * Contributors of ideas or unattributed patches include: David Brownell,
+ * Roman Weissgaerber, Rory Bolt, ...
+ *
+ * HISTORY:
+ * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* host controllers we manage */
+static LIST_HEAD (hcd_list);
+
+/* used when updating list of hcds */
+static DECLARE_MUTEX (hcd_list_lock);
+
+/* used when updating hcd data */
+static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
+
+static struct usb_operations hcd_operations;
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Sharable chunks of root hub code.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* usb 2.0 root hub device descriptor */
+static const u8 usb2_rh_dev_descriptor [18] = {
+	0x12,       /*  __u8  bLength; */
+	0x01,       /*  __u8  bDescriptorType; Device */
+	0x00, 0x02, /*  __u16 bcdUSB; v2.0 */
+
+	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*  __u8  bDeviceSubClass; */
+	0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/
+	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+
+	0x00, 0x00, /*  __u16 idVendor; */
+ 	0x00, 0x00, /*  __u16 idProduct; */
+ 	0x40, 0x02, /*  __u16 bcdDevice; (v2.4) */
+
+	0x03,       /*  __u8  iManufacturer; */
+	0x02,       /*  __u8  iProduct; */
+	0x01,       /*  __u8  iSerialNumber; */
+	0x01        /*  __u8  bNumConfigurations; */
+};
+
+/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */
+
+/* usb 1.1 root hub device descriptor */
+static const u8 usb11_rh_dev_descriptor [18] = {
+	0x12,       /*  __u8  bLength; */
+	0x01,       /*  __u8  bDescriptorType; Device */
+	0x10, 0x01, /*  __u16 bcdUSB; v1.1 */
+
+	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+	0x00,	    /*  __u8  bDeviceSubClass; */
+	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
+	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+
+	0x00, 0x00, /*  __u16 idVendor; */
+ 	0x00, 0x00, /*  __u16 idProduct; */
+ 	0x40, 0x02, /*  __u16 bcdDevice; (v2.4) */
+
+	0x03,       /*  __u8  iManufacturer; */
+	0x02,       /*  __u8  iProduct; */
+	0x01,       /*  __u8  iSerialNumber; */
+	0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Configuration descriptor for all our root hubs */
+
+static const u8 rh_config_descriptor [] = {
+
+	/* one configuration */
+	0x09,       /*  __u8  bLength; */
+	0x02,       /*  __u8  bDescriptorType; Configuration */
+	0x19, 0x00, /*  __u16 wTotalLength; */
+	0x01,       /*  __u8  bNumInterfaces; (1) */
+	0x01,       /*  __u8  bConfigurationValue; */
+	0x00,       /*  __u8  iConfiguration; */
+	0x40,       /*  __u8  bmAttributes; 
+				 Bit 7: Bus-powered,
+				     6: Self-powered,
+				     5 Remote-wakwup,
+				     4..0: resvd */
+	0x00,       /*  __u8  MaxPower; */
+      
+	/* USB 1.1:
+	 * USB 2.0, single TT organization (mandatory):
+	 *	one interface, protocol 0
+	 *
+	 * USB 2.0, multiple TT organization (optional):
+	 *	two interfaces, protocols 1 (like single TT)
+	 *	and 2 (multiple TT mode) ... config is
+	 *	sometimes settable
+	 *	NOT IMPLEMENTED
+	 */
+
+	/* one interface */
+	0x09,       /*  __u8  if_bLength; */
+	0x04,       /*  __u8  if_bDescriptorType; Interface */
+	0x00,       /*  __u8  if_bInterfaceNumber; */
+	0x00,       /*  __u8  if_bAlternateSetting; */
+	0x01,       /*  __u8  if_bNumEndpoints; */
+	0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+	0x00,       /*  __u8  if_bInterfaceSubClass; */
+	0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+	0x00,       /*  __u8  if_iInterface; */
+     
+	/* one endpoint (status change endpoint) */
+	0x07,       /*  __u8  ep_bLength; */
+	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+ 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+ 	0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+	0x0c        /*  __u8  ep_bInterval; (12ms -- usb 2.0 spec) */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * helper routine for returning string descriptors in UTF-16LE
+ * input can actually be ISO-8859-1; ASCII is its 7-bit subset
+ */
+static int ascii2utf (char *ascii, u8 *utf, int utfmax)
+{
+	int retval;
+
+	for (retval = 0; *ascii && utfmax > 1; utfmax -= 2, retval += 2) {
+		*utf++ = *ascii++ & 0x7f;
+		*utf++ = 0;
+	}
+	return retval;
+}
+
+/*
+ * rh_string - provides manufacturer, product and serial strings for root hub
+ * @id: the string ID number (1: serial number, 2: product, 3: vendor)
+ * @pci_desc: PCI device descriptor for the relevant HC
+ * @type: string describing our driver 
+ * @data: return packet in UTF-16 LE
+ * @len: length of the return packet
+ *
+ * Produces either a manufacturer, product or serial number string for the
+ * virtual root hub device.
+ */
+static int rh_string (
+	int		id,
+	struct pci_dev	*pci_desc,
+	char		*type,
+	u8		*data,
+	int		len
+) {
+	char buf [100];
+
+	// language ids
+	if (id == 0) {
+		*data++ = 4; *data++ = 3;	/* 4 bytes string data */
+		*data++ = 0; *data++ = 0;	/* some language id */
+		return 4;
+
+	// serial number
+	} else if (id == 1) {
+		strcpy (buf, pci_desc->slot_name);
+
+	// product description
+	} else if (id == 2) {
+                strcpy (buf, pci_desc->name);
+
+ 	// id 3 == vendor description
+	} else if (id == 3) {
+                sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, type);
+
+	// unsupported IDs --> "protocol stall"
+	} else
+	    return 0;
+
+	data [0] = 2 + ascii2utf (buf, data + 2, len - 2);
+	data [1] = 3;	/* type == string */
+	return data [0];
+}
+
+
+/* Root hub control transfers execute synchronously */
+static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
+{
+	devrequest	*cmd = (devrequest *) urb->setup_packet;
+ 	u16		typeReq, wValue, wIndex, wLength;
+	const u8	*bufp = 0;
+	u8		*ubuf = urb->transfer_buffer;
+	int		len = 0;
+
+	typeReq  = (cmd->requesttype << 8) | cmd->request;
+	wValue   = le16_to_cpu (cmd->value);
+	wIndex   = le16_to_cpu (cmd->index);
+	wLength  = le16_to_cpu (cmd->length);
+
+	if (wLength > urb->transfer_buffer_length)
+		goto error;
+
+	/* set up for success */
+	urb->status = 0;
+	urb->actual_length = wLength;
+	switch (typeReq) {
+
+	/* DEVICE REQUESTS */
+
+	case DeviceRequest | USB_REQ_GET_STATUS:
+		// DEVICE_REMOTE_WAKEUP
+		ubuf [0] = 1; // selfpowered
+		ubuf [1] = 0;
+			/* FALLTHROUGH */
+	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+	case DeviceOutRequest | USB_REQ_SET_FEATURE:
+		dbg ("no device features yet yet");
+		break;
+	case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+		ubuf [0] = 1;
+			/* FALLTHROUGH */
+	case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+		break;
+	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+		switch (wValue & 0xff00) {
+		case USB_DT_DEVICE << 8:
+			if (hcd->driver->flags & HCD_USB2)
+				bufp = usb2_rh_dev_descriptor;
+			else if (hcd->driver->flags & HCD_USB11)
+				bufp = usb11_rh_dev_descriptor;
+			else
+				goto error;
+			len = 18;
+			break;
+		case USB_DT_CONFIG << 8:
+			bufp = rh_config_descriptor;
+			len = sizeof rh_config_descriptor;
+			break;
+		case USB_DT_STRING << 8:
+			urb->actual_length = rh_string (
+				wValue & 0xff,
+				 hcd->pdev,
+				(char *) hcd->description,
+				ubuf, wLength);
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case DeviceRequest | USB_REQ_GET_INTERFACE:
+		ubuf [0] = 0;
+			/* FALLTHROUGH */
+	case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+		break;
+	case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+		// wValue == urb->dev->devaddr
+		dbg ("%s root hub device address %d",
+			hcd->bus_name, wValue);
+		break;
+
+	/* INTERFACE REQUESTS (no defined feature/status flags) */
+
+	/* ENDPOINT REQUESTS */
+
+	case EndpointRequest | USB_REQ_GET_STATUS:
+		// ENDPOINT_HALT flag
+		ubuf [0] = 0;
+		ubuf [1] = 0;
+			/* FALLTHROUGH */
+	case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+	case EndpointOutRequest | USB_REQ_SET_FEATURE:
+		dbg ("no endpoint features yet");
+		break;
+
+	/* CLASS REQUESTS (and errors) */
+
+	default:
+		/* non-generic request */
+		urb->status = hcd->driver->hub_control (hcd,
+			typeReq, wValue, wIndex,
+			ubuf, wLength);
+		break;
+error:
+		/* "protocol stall" on error */
+		urb->status = -EPIPE;
+		dbg ("unsupported hub control message (maxchild %d)",
+				urb->dev->maxchild);
+	}
+	if (urb->status) {
+		urb->actual_length = 0;
+		dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d",
+			typeReq, wValue, wIndex, wLength, urb->status);
+	}
+	if (bufp) {
+		if (urb->transfer_buffer_length < len)
+			len = urb->transfer_buffer_length;
+		urb->actual_length = len;
+		// always USB_DIR_IN, toward host
+		memcpy (ubuf, bufp, len);
+	}
+
+	/* any errors get returned through the urb completion */
+	usb_hcd_giveback_urb (hcd, urb);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Root Hub interrupt transfers are synthesized with a timer.
+ * Completions are called in_interrupt() but not in_irq().
+ */
+
+static void rh_report_status (unsigned long ptr);
+
+static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 
+{
+	int	len = 1 + (urb->dev->maxchild / 8);
+
+	/* rh_timer protected by hcd_data_lock */
+	if (timer_pending (&hcd->rh_timer)
+			|| urb->status != -EINPROGRESS
+			|| !HCD_IS_RUNNING (hcd->state)
+			|| urb->transfer_buffer_length < len) {
+		dbg ("not queuing status urb, stat %d", urb->status);
+		return -EINVAL;
+	}
+
+	urb->hcpriv = hcd;	/* nonzero to indicate it's queued */
+	init_timer (&hcd->rh_timer);
+	hcd->rh_timer.function = rh_report_status;
+	hcd->rh_timer.data = (unsigned long) urb;
+	hcd->rh_timer.expires = jiffies
+		+ (HZ * (urb->interval < 30
+				? 30
+				: urb->interval)) / 1000;
+	add_timer (&hcd->rh_timer);
+	return 0;
+}
+
+/* timer callback */
+
+static void rh_report_status (unsigned long ptr)
+{
+	struct urb	*urb;
+	struct usb_hcd	*hcd;
+	int		length;
+	unsigned long	flags;
+
+	urb = (struct urb *) ptr;
+	spin_lock_irqsave (&urb->lock, flags);
+	if (!urb->dev) {
+		spin_unlock_irqrestore (&urb->lock, flags);
+		return;
+	}
+
+	hcd = urb->dev->bus->hcpriv;
+	if (urb->status == -EINPROGRESS) {
+		if (HCD_IS_RUNNING (hcd->state)) {
+			length = hcd->driver->hub_status_data (hcd,
+					urb->transfer_buffer);
+			spin_unlock_irqrestore (&urb->lock, flags);
+			if (length > 0) {
+				urb->actual_length = length;
+				urb->status = 0;
+				urb->complete (urb);
+			}
+			spin_lock_irqsave (&hcd_data_lock, flags);
+			urb->status = -EINPROGRESS;
+			if (HCD_IS_RUNNING (hcd->state)
+					&& rh_status_urb (hcd, urb) != 0) {
+				/* another driver snuck in? */
+				dbg ("%s, can't resubmit roothub status urb?",
+					hcd->bus_name);
+				spin_unlock_irqrestore (&hcd_data_lock, flags);
+				BUG ();
+			}
+			spin_unlock_irqrestore (&hcd_data_lock, flags);
+		} else
+			spin_unlock_irqrestore (&urb->lock, flags);
+	} else {
+		/* this urb's been unlinked */
+		urb->hcpriv = 0;
+		spin_unlock_irqrestore (&urb->lock, flags);
+
+		usb_hcd_giveback_urb (hcd, urb);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
+{
+	if (usb_pipeint (urb->pipe)) {
+		int		retval;
+		unsigned long	flags;
+
+		spin_lock_irqsave (&hcd_data_lock, flags);
+		retval = rh_status_urb (hcd, urb);
+		spin_unlock_irqrestore (&hcd_data_lock, flags);
+		return retval;
+	}
+	if (usb_pipecontrol (urb->pipe))
+		return rh_call_control (hcd, urb);
+	else
+		return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	del_timer_sync (&hcd->rh_timer);
+	hcd->rh_timer.data = 0;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	/* we rely on RH callback code not unlinking its URB! */
+	usb_hcd_giveback_urb (hcd, urb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PCI
+
+/* PCI-based HCs are normal, but custom bus glue should be ok */
+
+static void hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+static void hc_died (struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_pci_probe - initialize PCI-based HCDs
+ * @dev: USB Host Controller being probed
+ * @id: pci hotplug id connecting controller to HCD framework
+ *
+ * Allocates basic PCI resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct hc_driver	*driver;
+	unsigned long		resource, len;
+	void			*base;
+	u8			latency, limit;
+	struct usb_bus		*bus;
+	struct usb_hcd		*hcd;
+	int			retval, region;
+	char			buf [8], *bufp = buf;
+
+	if (!id || !(driver = (struct hc_driver *) id->driver_data))
+		return -EINVAL;
+
+	if (pci_enable_device (dev) < 0)
+		return -ENODEV;
+	
+        if (!dev->irq) {
+        	err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
+			dev->slot_name);
+   	        return -ENODEV;
+        }
+	
+	if (driver->flags & HCD_MEMORY) {	// EHCI, OHCI
+		region = 0;
+		resource = pci_resource_start (dev, 0);
+		len = pci_resource_len (dev, 0);
+		if (!request_mem_region (resource, len, driver->description)) {
+			dbg ("controller already in use");
+			return -EBUSY;
+		}
+		base = ioremap_nocache (resource, len);
+		if (base == NULL) {
+			dbg ("error mapping memory");
+			retval = -EFAULT;
+clean_1:
+			release_mem_region (resource, len);
+			err ("init %s fail, %d", dev->slot_name, retval);
+			return retval;
+		}
+
+	} else { 				// UHCI
+		resource = len = 0;
+		for (region = 0; region < PCI_ROM_RESOURCE; region++) {
+			if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+				continue;
+
+			resource = pci_resource_start (dev, region);
+			len = pci_resource_len (dev, region);
+			if (request_region (resource, len,
+					driver->description))
+				break;
+		}
+		if (region == PCI_ROM_RESOURCE) {
+			dbg ("no i/o regions available");
+			return -EBUSY;
+		}
+		base = (void *) resource;
+	}
+
+	// driver->start(), later on, will transfer device from
+	// control by SMM/BIOS to control by Linux (if needed)
+
+	pci_set_master (dev);
+	hcd = driver->hcd_alloc ();
+	if (hcd == NULL){
+		dbg ("hcd alloc fail");
+		retval = -ENOMEM;
+clean_2:
+		if (driver->flags & HCD_MEMORY) {
+			iounmap (base);
+			goto clean_1;
+		} else {
+			release_region (resource, len);
+			err ("init %s fail, %d", dev->slot_name, retval);
+			return retval;
+		}
+	}
+	dev->driver_data = hcd;
+	hcd->driver = driver;
+	hcd->description = driver->description;
+	hcd->pdev = dev;
+	info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
+
+	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+	if (latency) {
+		pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
+		if (limit && limit < latency) {
+			dbg ("PCI latency reduced to max %d", limit);
+			pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
+		}
+	}
+
+#ifndef __sparc__
+	sprintf (buf, "%d", dev->irq);
+#else
+	bufp = __irq_itoa(irq);
+#endif
+	if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
+			!= 0) {
+		err ("request interrupt %s failed", bufp);
+		retval = -EBUSY;
+clean_3:
+		driver->hcd_free (hcd);
+		goto clean_2;
+	}
+	hcd->irq = dev->irq;
+
+	hcd->regs = base;
+	hcd->region = region;
+	info ("irq %s, %s %p", bufp,
+		(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
+		base);
+
+// FIXME simpler: make "bus" be that data, not pointer to it.
+	bus = usb_alloc_bus (&hcd_operations);
+	if (bus == NULL) {
+		dbg ("usb_alloc_bus fail");
+		retval = -ENOMEM;
+		free_irq (dev->irq, hcd);
+		goto clean_3;
+	}
+	hcd->bus = bus;
+	hcd->bus_name = dev->slot_name;
+	bus->hcpriv = (void *) hcd;
+
+	INIT_LIST_HEAD (&hcd->dev_list);
+	INIT_LIST_HEAD (&hcd->hcd_list);
+
+	down (&hcd_list_lock);
+	list_add (&hcd->hcd_list, &hcd_list);
+	up (&hcd_list_lock);
+
+	usb_register_bus (bus);
+
+	if ((retval = driver->start (hcd)) < 0)
+		usb_hcd_pci_remove (dev);
+
+	return retval;
+} 
+EXPORT_SYMBOL (usb_hcd_pci_probe);
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
+ * @dev: USB Host Controller being removed
+ *
+ * Reverses the effect of usb_hcd_pci_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ * Store this function in the HCD's struct pci_driver as remove().
+ */
+void usb_hcd_pci_remove (struct pci_dev *dev)
+{
+	struct usb_hcd		*hcd;
+	struct usb_device	*hub;
+
+	hcd = (struct usb_hcd *) dev->driver_data;
+	if (!hcd)
+		return;
+	info ("remove: %s, state %x", hcd->bus_name, hcd->state);
+
+	if (in_interrupt ()) BUG ();
+
+	hub = hcd->bus->root_hub;
+	hcd->state = USB_STATE_QUIESCING;
+
+	dbg ("%s: roothub graceful disconnect", hcd->bus_name);
+	usb_disconnect (&hub);
+	// usb_disconnect (&hcd->bus->root_hub);
+
+	hcd->driver->stop (hcd);
+	hcd->state = USB_STATE_HALT;
+
+	free_irq (hcd->irq, hcd);
+	if (hcd->driver->flags & HCD_MEMORY) {
+		iounmap (hcd->regs);
+		release_mem_region (pci_resource_start (dev, 0),
+			pci_resource_len (dev, 0));
+	} else {
+		release_region (pci_resource_start (dev, hcd->region),
+			pci_resource_len (dev, hcd->region));
+	}
+
+	down (&hcd_list_lock);
+	list_del (&hcd->hcd_list);
+	up (&hcd_list_lock);
+
+	usb_deregister_bus (hcd->bus);
+	usb_free_bus (hcd->bus);
+	hcd->bus = NULL;
+
+	hcd->driver->hcd_free (hcd);
+}
+EXPORT_SYMBOL (usb_hcd_pci_remove);
+
+
+#ifdef	CONFIG_PM
+
+/*
+ * Some "sleep" power levels imply updating struct usb_driver
+ * to include a callback asking hcds to do their bit by checking
+ * if all the drivers can suspend.  Gets involved with remote wakeup.
+ *
+ * If there are pending urbs, then HCs will need to access memory,
+ * causing extra power drain.  New sleep()/wakeup() PM calls might
+ * be needed, beyond PCI suspend()/resume().  The root hub timer
+ * still be accessing memory though ...
+ *
+ * FIXME:  USB should have some power budgeting support working with
+ * all kinds of hubs.
+ *
+ * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
+ * D1 and D2 states should do something, yes?
+ *
+ * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
+ * for all supported states, so that USB remote wakeup can work for any
+ * devices that support it (and are connected via powered hubs).
+ *
+ * FIXME:  resume doesn't seem to work right any more...
+ */
+
+
+// 2.4 kernels have issued concurrent resumes (w/APM)
+// we defend against that error; PCI doesn't yet.
+
+/**
+ * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
+ * @dev: USB Host Controller being suspended
+ *
+ * Store this function in the HCD's struct pci_driver as suspend().
+ */
+int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
+{
+	struct usb_hcd		*hcd;
+	int			retval;
+
+	hcd = (struct usb_hcd *) dev->driver_data;
+	info ("suspend %s to state %d", hcd->bus_name, state);
+
+	pci_save_state (dev, hcd->pci_state);
+
+	// FIXME for all connected devices, leaf-to-root:
+	// driver->suspend()
+	// proposed "new 2.5 driver model" will automate that
+
+	/* driver may want to disable DMA etc */
+	retval = hcd->driver->suspend (hcd, state);
+	hcd->state = USB_STATE_SUSPENDED;
+
+ 	pci_set_power_state (dev, state);
+	return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_suspend);
+
+/**
+ * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+ * @dev: USB Host Controller being resumed
+ *
+ * Store this function in the HCD's struct pci_driver as resume().
+ */
+int usb_hcd_pci_resume (struct pci_dev *dev)
+{
+	struct usb_hcd		*hcd;
+	int			retval;
+
+	hcd = (struct usb_hcd *) dev->driver_data;
+	info ("resume %s", hcd->bus_name);
+
+	/* guard against multiple resumes (APM bug?) */
+	atomic_inc (&hcd->resume_count);
+	if (atomic_read (&hcd->resume_count) != 1) {
+		err ("concurrent PCI resumes for %s", hcd->bus_name);
+		retval = 0;
+		goto done;
+	}
+
+	retval = -EBUSY;
+	if (hcd->state != USB_STATE_SUSPENDED) {
+		dbg ("can't resume, not suspended!");
+		goto done;
+	}
+	hcd->state = USB_STATE_RESUMING;
+
+	pci_set_power_state (dev, 0);
+	pci_restore_state (dev, hcd->pci_state);
+
+	retval = hcd->driver->resume (hcd);
+	if (!HCD_IS_RUNNING (hcd->state)) {
+		dbg ("resume %s failure, retval %d", hcd->bus_name, retval);
+		hc_died (hcd);
+// FIXME:  recover, reset etc.
+	} else {
+		// FIXME for all connected devices, root-to-leaf:
+		// driver->resume ();
+		// proposed "new 2.5 driver model" will automate that
+	}
+
+done:
+	atomic_dec (&hcd->resume_count);
+	return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_resume);
+
+#endif	/* CONFIG_PM */
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Generic HC operations.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* called from khubd, or root hub init threads for hcd-private init */
+static int hcd_alloc_dev (struct usb_device *udev)
+{
+	struct hcd_dev		*dev;
+	struct usb_hcd		*hcd;
+	unsigned long		flags;
+
+	if (!udev || udev->hcpriv)
+		return -EINVAL;
+	if (!udev->bus || !udev->bus->hcpriv)
+		return -ENODEV;
+	hcd = udev->bus->hcpriv;
+	if (hcd->state == USB_STATE_QUIESCING)
+		return -ENOLINK;
+
+	dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL);
+	if (dev == NULL)
+		return -ENOMEM;
+	memset (dev, 0, sizeof *dev);
+
+	INIT_LIST_HEAD (&dev->dev_list);
+	INIT_LIST_HEAD (&dev->urb_list);
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_add (&dev->dev_list, &hcd->dev_list);
+	// refcount is implicit
+	udev->hcpriv = dev;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void hc_died (struct usb_hcd *hcd)
+{
+	struct list_head	*devlist, *urblist;
+	struct hcd_dev		*dev;
+	struct urb		*urb;
+	unsigned long		flags;
+	
+	/* flag every pending urb as done */
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_for_each (devlist, &hcd->dev_list) {
+		dev = list_entry (devlist, struct hcd_dev, dev_list);
+		list_for_each (urblist, &dev->urb_list) {
+			urb = list_entry (urblist, struct urb, urb_list);
+			dbg ("shutdown %s urb %p pipe %x, current status %d",
+				hcd->bus_name, urb, urb->pipe, urb->status);
+			if (urb->status == -EINPROGRESS)
+				urb->status = -ESHUTDOWN;
+		}
+	}
+	urb = (struct urb *) hcd->rh_timer.data;
+	if (urb)
+		urb->status = -ESHUTDOWN;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	if (urb)
+		rh_status_dequeue (hcd, urb);
+	hcd->driver->stop (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount */
+/* caller surrenders "ownership" of urb (and chain at urb->next).  */
+
+static int hcd_submit_urb (struct urb *urb)
+{
+	int			status;
+	struct usb_hcd		*hcd;
+	struct hcd_dev		*dev;
+	unsigned long		flags;
+	int			pipe;
+	int			mem_flags;
+
+	if (!urb || urb->hcpriv || !urb->complete)
+		return -EINVAL;
+
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	INIT_LIST_HEAD (&urb->urb_list);
+
+	if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0)
+		return -ENODEV;
+	hcd = urb->dev->bus->hcpriv;
+	dev = urb->dev->hcpriv;
+	if (!hcd || !dev)
+		return -ENODEV;
+
+	/* can't submit new urbs when quiescing, halted, ... */
+	if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
+		return -ESHUTDOWN;
+	pipe = urb->pipe;
+	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
+			usb_pipeout (pipe)))
+		return -EPIPE;
+
+	// FIXME paging/swapping requests over USB should not use GFP_KERNEL
+	// and might even need to use GFP_NOIO ... that flag actually needs
+	// to be passed from the higher level.
+	mem_flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
+
+#ifdef DEBUG
+	{
+	unsigned int	orig_flags = urb->transfer_flags;
+	unsigned int	allowed;
+
+	/* enforce simple/standard policy */
+	allowed = USB_ASYNC_UNLINK;	// affects later unlinks
+	allowed |= USB_NO_FSBR;		// only affects UHCI
+	switch (usb_pipetype (pipe)) {
+	case PIPE_CONTROL:
+		allowed |= USB_DISABLE_SPD;
+		break;
+	case PIPE_BULK:
+		allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
+				| USB_ZERO_PACKET | URB_NO_INTERRUPT;
+		break;
+	case PIPE_INTERRUPT:
+		allowed |= USB_DISABLE_SPD;
+		break;
+	case PIPE_ISOCHRONOUS:
+		allowed |= USB_ISO_ASAP;
+		break;
+	}
+	urb->transfer_flags &= allowed;
+
+	/* warn if submitter gave bogus flags */
+	if (urb->transfer_flags != orig_flags)
+		warn ("BOGUS urb flags, %x --> %x",
+			orig_flags, urb->transfer_flags);
+	}
+#endif
+	/*
+	 * FIXME:  alloc periodic bandwidth here, for interrupt and iso?
+	 * Need to look at the ring submit mechanism for iso tds ... they
+	 * aren't actually "periodic" in 2.4 kernels.
+	 *
+	 * FIXME:  make urb timeouts be generic, keeping the HCD cores
+	 * as simple as possible.
+	 */
+
+	// NOTE:  a generic device/urb monitoring hook would go here.
+	// hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
+	// It would catch submission paths for all urbs.
+
+	/*
+	 * Atomically queue the urb,  first to our records, then to the HCD.
+	 * Access to urb->status is controlled by urb->lock ... changes on
+	 * i/o completion (normal or fault) or unlinking.
+	 */
+
+	// FIXME:  verify that quiescing hc works right (RH cleans up)
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) {
+		usb_inc_dev_use (urb->dev);
+		list_add (&urb->urb_list, &dev->urb_list);
+		status = 0;
+	} else {
+		INIT_LIST_HEAD (&urb->urb_list);
+		status = -ESHUTDOWN;
+	}
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	if (!status) {
+		if (urb->dev == hcd->bus->root_hub)
+			status = rh_urb_enqueue (hcd, urb);
+		else
+			status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
+	}
+	if (status) {
+		if (urb->dev) {
+			urb->status = status;
+			usb_hcd_giveback_urb (hcd, urb);
+		}
+	}
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called in any context */
+static int hcd_get_frame_number (struct usb_device *udev)
+{
+	struct usb_hcd	*hcd = (struct usb_hcd *)udev->bus->hcpriv;
+	return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct completion_splice {		// modified urb context:
+	/* did we complete? */
+	int			done;
+
+	/* original urb data */
+	void			(*complete)(struct urb *);
+	void			*context;
+};
+
+static void unlink_complete (struct urb *urb)
+{
+	struct completion_splice	*splice;
+
+	splice = (struct completion_splice *) urb->context;
+
+	/* issue original completion call */
+	urb->complete = splice->complete;
+	urb->context = splice->context;
+	urb->complete (urb);
+
+	splice->done = 1;
+}
+
+/*
+ * called in any context; note ASYNC_UNLINK restrictions
+ *
+ * caller guarantees urb won't be recycled till both unlink()
+ * and the urb's completion function return
+ */
+static int hcd_unlink_urb (struct urb *urb)
+{
+	struct hcd_dev			*dev;
+	struct usb_hcd			*hcd = 0;
+	unsigned long			flags;
+	struct completion_splice	splice;
+	int				retval;
+
+	if (!urb)
+		return -EINVAL;
+
+	// FIXME:  add some explicit records to flag the
+	// state where the URB is "in periodic completion".
+	// Workaround is for driver to set the urb status
+	// to "-EINPROGRESS", so it can get through here
+	// and unlink from the completion handler.
+
+	/*
+	 * we contend for urb->status with the hcd core,
+	 * which changes it while returning the urb.
+	 */
+	spin_lock_irqsave (&urb->lock, flags);
+	if (!urb->hcpriv
+			|| urb->status != -EINPROGRESS
+			|| urb->transfer_flags & USB_TIMEOUT_KILLED) {
+		retval = -EINVAL;
+		goto done;
+	}
+
+	if (!urb->dev || !urb->dev->bus) {
+		retval = -ENODEV;
+		goto done;
+	}
+	dev = urb->dev->hcpriv;
+	hcd = urb->dev->bus->hcpriv;
+	if (!dev || !hcd) {
+		retval = -ENODEV;
+		goto done;
+	}
+
+	/* maybe set up to block on completion notification */
+	if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
+		urb->status = -ETIMEDOUT;
+	else if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+		if (in_interrupt ()) {
+			dbg ("non-async unlink in_interrupt");
+			retval = -EWOULDBLOCK;
+			goto done;
+		}
+		/* synchronous unlink: block till we see the completion */
+		splice.done = 0;
+		splice.complete = urb->complete;
+		splice.context = urb->context;
+		urb->complete = unlink_complete;
+		urb->context = &splice;
+		urb->status = -ENOENT;
+	} else {
+		/* asynchronous unlink */
+		urb->status = -ECONNRESET;
+	}
+	spin_unlock_irqrestore (&urb->lock, flags);
+
+	if (urb == (struct urb *) hcd->rh_timer.data) {
+		rh_status_dequeue (hcd, urb);
+		retval = 0;
+	} else {
+		retval = hcd->driver->urb_dequeue (hcd, urb);
+// FIXME:  if retval and we tried to splice, whoa!!
+if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
+	}
+
+    	/* block till giveback, if needed */
+	if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED))
+			&& HCD_IS_RUNNING (hcd->state)
+			&& !retval) {
+		while (!splice.done) {
+			set_current_state (TASK_UNINTERRUPTIBLE);
+			schedule_timeout ((2/*msec*/ * HZ) / 1000);
+			dbg ("%s: wait for giveback urb %p",
+				hcd->bus_name, urb);
+		}
+	}
+	goto bye;
+done:
+	spin_unlock_irqrestore (&urb->lock, flags);
+bye:
+	if (retval)
+		dbg ("%s: hcd_unlink_urb fail %d",
+		    hcd ? hcd->bus_name : "(no bus?)",
+		    retval);
+	return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup */
+
+// FIXME:  likely best to have explicit per-setting (config+alt)
+// setup primitives in the usbcore-to-hcd driver API, so nothing
+// is implicit.  kernel 2.5 needs a bunch of config cleanup...
+
+static int hcd_free_dev (struct usb_device *udev)
+{
+	struct hcd_dev		*dev;
+	struct usb_hcd		*hcd;
+	unsigned long		flags;
+
+	if (!udev || !udev->hcpriv)
+		return -EINVAL;
+
+	if (!udev->bus || !udev->bus->hcpriv)
+		return -ENODEV;
+
+	// should udev->devnum == -1 ??
+
+	dev = udev->hcpriv;
+	hcd = udev->bus->hcpriv;
+
+	/* device driver problem with refcounts? */
+	if (!list_empty (&dev->urb_list)) {
+		dbg ("free busy dev, %s devnum %d (bug!)",
+			hcd->bus_name, udev->devnum);
+		return -EINVAL;
+	}
+
+	hcd->driver->free_config (hcd, udev);
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_del (&dev->dev_list);
+	udev->hcpriv = NULL;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	kfree (dev);
+	return 0;
+}
+
+static struct usb_operations hcd_operations = {
+	allocate:		hcd_alloc_dev,
+	get_frame_number:	hcd_get_frame_number,
+	submit_urb:		hcd_submit_urb,
+	unlink_urb:		hcd_unlink_urb,
+	deallocate:		hcd_free_dev,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+{
+	struct usb_hcd		*hcd = __hcd;
+	int			start = hcd->state;
+
+	hcd->driver->irq (hcd);
+	if (hcd->state != start && hcd->state == USB_STATE_HALT)
+		hc_died (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function.  The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv).  It also released all HCD locks;
+ * the device driver won't cause deadlocks if it resubmits this URB,
+ * and won't confuse things by modifying and resubmitting this one.
+ * Bandwidth and other resources will be deallocated.
+ *
+ * HCDs must not use this for periodic URBs that are still scheduled
+ * and will be reissued.  They should just call their completion handlers
+ * until the urb is returned to the device driver by unlinking.
+ *
+ * In common cases, urb->next will be submitted before the completion
+ * function gets called.  That's not done if the URB includes error
+ * status (including unlinking).
+ */
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+{
+	unsigned long		flags;
+	struct usb_device	*dev;
+
+	/* Release periodic transfer bandwidth */
+	if (urb->bandwidth) {
+		switch (usb_pipetype (urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_release_bandwidth (urb->dev, urb, 0);
+			break;
+		case PIPE_ISOCHRONOUS:
+			usb_release_bandwidth (urb->dev, urb, 1);
+			break;
+		}
+	}
+
+	/* clear all state linking urb to this dev (and hcd) */
+
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_del_init (&urb->urb_list);
+	dev = urb->dev;
+	urb->dev = NULL;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	// NOTE:  a generic device/urb monitoring hook would go here.
+	// hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
+	// It would catch exit/unlink paths for all urbs, but non-exit
+	// completions for periodic urbs need hooks inside the HCD.
+	// hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
+
+	if (urb->status)
+		dbg ("giveback urb %p status %d", urb, urb->status);
+
+	/* if no error, make sure urb->next progresses */
+	else if (urb->next) {
+		int 	status;
+
+		status = usb_submit_urb (urb->next);
+		if (status) {
+			dbg ("urb %p chain fail, %d", urb->next, status);
+			urb->next->status = -ENOTCONN;
+		}
+
+		/* HCDs never modify the urb->next chain, and only use it here,
+		 * so that if urb->complete sees an URB there with -ENOTCONN,
+		 * it knows the driver chained it but it couldn't be submitted.
+		 */
+	}
+
+	/* pass ownership to the completion handler */
+	usb_dec_dev_use (dev);
+	urb->complete (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
diff -urN linux-2.5.2-pre5/drivers/usb/hcd.h linux/drivers/usb/hcd.h
--- linux-2.5.2-pre5/drivers/usb/hcd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hcd.h	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2001 by David Brownell
+ * 
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver (usb_hcd) framework
+ *
+ * Since "struct usb_bus" is so thin, you can't share much code in it.
+ * This framework is a layer over that, and should be more sharable.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_hcd {	/* usb_bus.hcpriv points to this */
+
+	/*
+	 * housekeeping
+	 */
+	struct usb_bus		*bus;		/* hcd is-a bus */
+	struct list_head	hcd_list;
+
+	const char		*bus_name;
+
+	const char		*description;	/* "ehci-hcd" etc */
+
+	struct timer_list	rh_timer;	/* drives root hub */
+	struct list_head	dev_list;	/* devices on this bus */
+
+	/*
+	 * hardware info/state
+	 */
+	struct hc_driver	*driver;	/* hw-specific hooks */
+	int			irq;		/* irq allocated */
+	void			*regs;		/* device memory/io */
+
+#ifdef	CONFIG_PCI
+	/* a few non-PCI controllers exist, mostly for OHCI */
+	struct pci_dev		*pdev;		/* pci is typical */
+	int			region;		/* pci region for regs */
+	u32			pci_state [16];	/* for PM state save */
+	atomic_t		resume_count;	/* multiple resumes issue */
+#endif
+
+	int			state;
+#	define	__ACTIVE		0x01
+#	define	__SLEEPY		0x02
+#	define	__SUSPEND		0x04
+#	define	__TRANSIENT		0x80
+
+#	define	USB_STATE_HALT		0
+#	define	USB_STATE_RUNNING	(__ACTIVE)
+#	define	USB_STATE_READY		(__ACTIVE|__SLEEPY)
+#	define	USB_STATE_QUIESCING	(__SUSPEND|__TRANSIENT|__ACTIVE)
+#	define	USB_STATE_RESUMING	(__SUSPEND|__TRANSIENT)
+#	define	USB_STATE_SUSPENDED	(__SUSPEND)
+
+#define	HCD_IS_RUNNING(state) ((state) & __ACTIVE)
+#define	HCD_IS_SUSPENDED(state) ((state) & __SUSPEND)
+
+	/* more shared queuing code would be good; it should support
+	 * smarter scheduling, handle transaction translators, etc;
+	 * input size of periodic table to an interrupt scheduler. 
+	 * (ohci 32, uhci 1024, ehci 256/512/1024).
+	 */
+};
+
+struct hcd_dev {	/* usb_device.hcpriv points to this */
+	struct list_head	dev_list;	/* on this hcd */
+	struct list_head	urb_list;	/* pending on this dev */
+
+	/* per-configuration HC/HCD state, such as QH or ED */
+	void			*ep[32];
+};
+
+// urb.hcpriv is really hardware-specific
+
+struct hcd_timeout {	/* timeouts we allocate */
+	struct list_head	timeout_list;
+	struct timer_list	timer;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* each driver provides one of these, and hardware init support */
+
+struct hc_driver {
+	const char	*description;	/* "ehci-hcd" etc */
+
+	/* irq handler */
+	void	(*irq) (struct usb_hcd *hcd);
+
+	int	flags;
+#define	HCD_MEMORY	0x0001		/* HC regs use memory (else I/O) */
+#define	HCD_USB11	0x0010		/* USB 1.1 */
+#define	HCD_USB2	0x0020		/* USB 2.0 */
+
+	/* called to init HCD and root hub */
+	int	(*start) (struct usb_hcd *hcd);
+
+	/* called after all devices were suspended */
+	int	(*suspend) (struct usb_hcd *hcd, u32 state);
+
+	/* called before any devices get resumed */
+	int	(*resume) (struct usb_hcd *hcd);
+
+	/* cleanly make HCD stop writing memory and doing I/O */
+	void	(*stop) (struct usb_hcd *hcd);
+
+	/* return current frame number */
+	int	(*get_frame_number) (struct usb_hcd *hcd);
+
+// FIXME: rework generic-to-specific HCD linkage (specific contains generic)
+
+	/* memory lifecycle */
+	struct usb_hcd	*(*hcd_alloc) (void);
+	void		(*hcd_free) (struct usb_hcd *hcd);
+
+	/* manage i/o requests, device state */
+	int	(*urb_enqueue) (struct usb_hcd *hcd, struct urb *urb,
+					int mem_flags);
+	int	(*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+
+	// frees configuration resources -- allocated as needed during
+	// urb_enqueue, and not freed by urb_dequeue
+	void		(*free_config) (struct usb_hcd *hcd,
+				struct usb_device *dev);
+
+	/* root hub support */
+	int		(*hub_status_data) (struct usb_hcd *hcd, char *buf);
+	int		(*hub_control) (struct usb_hcd *hcd,
+				u16 typeReq, u16 wValue, u16 wIndex,
+				char *buf, u16 wLength);
+};
+
+extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
+
+#ifdef CONFIG_PCI
+
+extern int usb_hcd_pci_probe (struct pci_dev *dev,
+				const struct pci_device_id *id);
+extern void usb_hcd_pci_remove (struct pci_dev *dev);
+
+#ifdef CONFIG_PM
+// FIXME:  see Documentation/power/pci.txt (2.4.6 and later?)
+// extern int usb_hcd_pci_save_state (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state);
+extern int usb_hcd_pci_resume (struct pci_dev *dev);
+// extern int usb_hcd_pci_enable_wake (struct pci_dev *dev, u32 state, int flg);
+#endif /* CONFIG_PM */
+
+#endif /* CONFIG_PCI */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * HCD Root Hub support
+ */
+
+#include "hub.h"
+
+/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
+#define DeviceRequest \
+	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+#define DeviceOutRequest \
+	((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_DEVICE)<<8)
+
+#define InterfaceRequest \
+	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+
+#define EndpointRequest \
+	((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+#define EndpointOutRequest \
+	((USB_DIR_OUT|USB_TYPE_STANDARD|USB_RECIP_INTERFACE)<<8)
+
+/* table 9.6 standard features */
+#define DEVICE_REMOTE_WAKEUP	1
+#define ENDPOINT_HALT		0
+
+/* class requests from the USB 2.0 hub spec, table 11-15 */
+/* GetBusState and SetHubDescriptor are optional, omitted */
+#define ClearHubFeature		(0x2000 | USB_REQ_CLEAR_FEATURE)
+#define ClearPortFeature	(0x2300 | USB_REQ_CLEAR_FEATURE)
+#define GetHubDescriptor	(0xa000 | USB_REQ_GET_DESCRIPTOR)
+#define GetHubStatus		(0xa000 | USB_REQ_GET_STATUS)
+#define GetPortStatus		(0xa300 | USB_REQ_GET_STATUS)
+#define SetHubFeature		(0x2000 | USB_REQ_SET_FEATURE)
+#define SetPortFeature		(0x2300 | USB_REQ_SET_FEATURE)
+
+
+/*-------------------------------------------------------------------------*/
+
+/* hub.h ... DeviceRemovable in 2.4.2-ac11, gone in 2.4.10 */
+// bleech -- resurfaced in 2.4.11 or 2.4.12
+#define bitmap 	DeviceRemovable
+
+
+/*-------------------------------------------------------------------------*/
+
+/* random stuff */
+
+#define	RUN_CONTEXT (in_irq () ? "in_irq" \
+		: (in_interrupt () ? "in_interrupt" : "can sleep"))
diff -urN linux-2.5.2-pre5/drivers/usb/hub.c linux/drivers/usb/hub.c
--- linux-2.5.2-pre5/drivers/usb/hub.c	Mon Nov 12 09:34:16 2001
+++ linux/drivers/usb/hub.c	Tue Jan  1 14:04:28 2002
@@ -35,7 +35,7 @@
 static DECLARE_MUTEX(usb_address0_sem);
 
 static LIST_HEAD(hub_event_list);	/* List of hubs needing servicing */
-static LIST_HEAD(hub_list);		/* List containing all of the hubs (for cleanup) */
+static LIST_HEAD(hub_list);		/* List of all hubs (for cleanup) */
 
 static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
 static int khubd_pid = 0;			/* PID of khubd */
@@ -110,22 +110,30 @@
 		data, sizeof(struct usb_hub_status), HZ);
 }
 
+/* completion function, fires on port status changes and various faults */
 static void hub_irq(struct urb *urb)
 {
 	struct usb_hub *hub = (struct usb_hub *)urb->context;
 	unsigned long flags;
 
-	/* Cause a hub reset after 10 consecutive errors */
-	if (urb->status) {
-		if (urb->status == -ENOENT)
-			return;
-
-		dbg("nonzero status in irq %d", urb->status);
+	switch (urb->status) {
+	case -ENOENT:		/* synchronous unlink */
+	case -ECONNRESET:	/* async unlink */
+	case -ESHUTDOWN:	/* hardware going away */
+		return;
 
+	default:		/* presumably an error */
+		/* Cause a hub reset after 10 consecutive errors */
+		dbg("hub '%s' status %d for interrupt transfer",
+			urb->dev->devpath, urb->status);
 		if ((++hub->nerrors < 10) || hub->error)
 			return;
-
 		hub->error = urb->status;
+		/* FALL THROUGH */
+	
+	/* let khubd handle things */
+	case 0:			/* we got data:  port status changed */
+		break;
 	}
 
 	hub->nerrors = 0;
@@ -152,7 +160,8 @@
 	wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
 }
 
-static int usb_hub_configure(struct usb_hub *hub, struct usb_endpoint_descriptor *endpoint)
+static int usb_hub_configure(struct usb_hub *hub,
+	struct usb_endpoint_descriptor *endpoint)
 {
 	struct usb_device *dev = hub->dev;
 	struct usb_hub_status hubstatus;
@@ -162,22 +171,30 @@
 
 	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
 	if (!hub->descriptor) {
-		err("Unable to kmalloc %Zd bytes for hub descriptor", sizeof(*hub->descriptor));
+		err("Unable to kmalloc %Zd bytes for hub descriptor",
+			sizeof(*hub->descriptor));
 		return -1;
 	}
 
-	/* Request the entire hub descriptor. */
-	ret = usb_get_hub_descriptor(dev, hub->descriptor, sizeof(*hub->descriptor));
-		/* <hub->descriptor> is large enough for a hub with 127 ports;
-		 * the hub can/will return fewer bytes here. */
+	/* Request the entire hub descriptor.
+	 * hub->descriptor can handle USB_MAXCHILDREN ports,
+	 * but the hub can/will return fewer bytes here.
+	 */
+	ret = usb_get_hub_descriptor(dev, hub->descriptor,
+			sizeof(*hub->descriptor));
 	if (ret < 0) {
 		err("Unable to get hub descriptor (err = %d)", ret);
 		kfree(hub->descriptor);
 		return -1;
+	} else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) {
+		err("Hub is too big! %d children", hub->descriptor->bNbrPorts);
+		kfree(hub->descriptor);
+		return -1;
 	}
 
 	dev->maxchild = hub->descriptor->bNbrPorts;
-	info("%d port%s detected", hub->descriptor->bNbrPorts, (hub->descriptor->bNbrPorts == 1) ? "" : "s");
+	info("%d port%s detected", dev->maxchild,
+		(dev->maxchild == 1) ? "" : "s");
 
 	le16_to_cpus(&hub->descriptor->wHubCharacteristics);
 
@@ -217,9 +234,12 @@
 			break;
 		case 1:
 			dbg("Single TT");
+			hub->tt.hub = dev;
 			break;
 		case 2:
-			dbg("Multiple TT");
+			dbg("TT per port");
+			hub->tt.hub = dev;
+			hub->tt.multi = 1;
 			break;
 		default:
 			dbg("Unrecognized hub protocol %d",
@@ -244,13 +264,18 @@
 	}
 
 	dbg("Port indicators are %s supported", 
-	    (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) ? "" : "not");
+	    (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND)
+	    	? "" : "not");
 
-	dbg("power on to power good time: %dms", hub->descriptor->bPwrOn2PwrGood * 2);
-	dbg("hub controller current requirement: %dmA", hub->descriptor->bHubContrCurrent);
+	dbg("power on to power good time: %dms",
+		hub->descriptor->bPwrOn2PwrGood * 2);
+	dbg("hub controller current requirement: %dmA",
+		hub->descriptor->bHubContrCurrent);
 
 	for (i = 0; i < dev->maxchild; i++)
-		portstr[i] = hub->descriptor->DeviceRemovable[((i + 1) / 8)] & (1 << ((i + 1) % 8)) ? 'F' : 'R';
+		portstr[i] = hub->descriptor->DeviceRemovable
+			    [((i + 1) / 8)] & (1 << ((i + 1) % 8))
+			? 'F' : 'R';
 	portstr[dev->maxchild] = 0;
 
 	dbg("port removable status: %s", portstr);
@@ -265,7 +290,8 @@
 	le16_to_cpus(&hubstatus.wHubStatus);
 
 	dbg("local power source is %s",
-		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) ? "lost (inactive)" : "good");
+		(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER)
+		? "lost (inactive)" : "good");
 
 	dbg("%sover-current condition exists",
 		(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
@@ -337,14 +363,15 @@
 	}
 
 	/* If it's not an interrupt endpoint, we'd better punt! */
-	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
-		err("Device #%d is hub class, but has endpoint other than interrupt?",
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+			!= USB_ENDPOINT_XFER_INT) {
+		err("Device #%d is hub class, but endpoint is not interrupt?",
 			dev->devnum);
 		return NULL;
 	}
 
 	/* We found a hub */
-	info("USB hub found");
+	info("USB hub found at %s", dev->devpath);
 
 	hub = kmalloc(sizeof(*hub), GFP_KERNEL);
 	if (!hub) {
@@ -367,7 +394,7 @@
 	if (usb_hub_configure(hub, endpoint) >= 0)
 		return hub;
 
-	err("hub configuration failed for device #%d", dev->devnum);
+	err("hub configuration failed for device at %s", dev->devpath);
 
 	/* free hub, but first clean up its list. */
 	spin_lock_irqsave(&hub_event_lock, flags);
@@ -436,7 +463,8 @@
 				if (hub->children[i] == NULL)
 					info->port[i] = 0;
 				else
-					info->port[i] = hub->children[i]->devnum;
+					info->port[i] =
+						hub->children[i]->devnum;
 			}
 		}
 		spin_unlock_irqrestore(&hub_event_lock, flags);
@@ -493,7 +521,7 @@
 		}
 	}
 
-	err("cannot disconnect hub %d", dev->devnum);
+	err("cannot disconnect hub %s", dev->devpath);
 }
 
 #define HUB_RESET_TRIES		5
@@ -510,14 +538,17 @@
 	struct usb_port_status portsts;
 	unsigned short portchange, portstatus;
 
-	for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) {
+	for (delay_time = 0;
+			delay_time < HUB_RESET_TIMEOUT;
+			delay_time += delay) {
 		/* wait to give the device a chance to reset */
 		wait_ms(delay);
 
 		/* read and decode port status */
 		ret = usb_get_port_status(hub, port + 1, &portsts);
 		if (ret < 0) {
-			err("get_port_status(%d) failed (err = %d)", port + 1, ret);
+			err("get_port_status(%d) failed (err = %d)",
+				port + 1, ret);
 			return -1;
 		}
 
@@ -546,8 +577,8 @@
 		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
 			delay = HUB_LONG_RESET_TIME;
 
-		dbg("port %d of hub %d not reset yet, waiting %dms", port + 1,
-			hub->devnum, delay);
+		dbg("port %d of hub %s not reset yet, waiting %dms", port + 1,
+			hub->devpath, delay);
 	}
 
 	return -1;
@@ -566,17 +597,18 @@
 		/* return on disconnect or reset */
 		status = usb_hub_port_wait_reset(hub, port, dev, delay);
 		if (status != -1) {
-			usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET);
+			usb_clear_port_feature(hub,
+				port + 1, USB_PORT_FEAT_C_RESET);
 			return status;
 		}
 
-		dbg("port %d of hub %d not enabled, trying reset again...",
-			port + 1, hub->devnum);
+		dbg("port %d of hub %s not enabled, trying reset again...",
+			port + 1, hub->devpath);
 		delay = HUB_LONG_RESET_TIME;
 	}
 
-	err("Cannot enable port %i of hub %d, disabling port.",
-		port + 1, hub->devnum);
+	err("Cannot enable port %i of hub %s, disabling port.",
+		port + 1, hub->devpath);
 	err("Maybe the USB cable is bad?");
 
 	return -1;
@@ -588,23 +620,24 @@
 
 	ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
 	if (ret)
-		err("cannot disable port %d of hub %d (err = %d)",
-			port + 1, hub->devnum, ret);
+		err("cannot disable port %d of hub %s (err = %d)",
+			port + 1, hub->devpath, ret);
 }
 
-static void usb_hub_port_connect_change(struct usb_device *hub, int port,
+static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
 					struct usb_port_status *portsts)
 {
+	struct usb_device *hub = hubstate->dev;
 	struct usb_device *dev;
 	unsigned short portstatus, portchange;
 	unsigned int delay = HUB_SHORT_RESET_TIME;
 	int i;
-	char *portstr, *tempstr;
 
 	portstatus = le16_to_cpu(portsts->wPortStatus);
 	portchange = le16_to_cpu(portsts->wPortChange);
-	dbg("port %d, portstatus %x, change %x, %s",
-		port + 1, portstatus, portchange, portspeed (portstatus));
+	dbg("hub %s port %d, portstatus %x, change %x, %s",
+		hub->devpath, port + 1,
+		portstatus, portchange, portspeed (portstatus));
 
 	/* Clear the connection change status */
 	usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
@@ -630,11 +663,9 @@
 
 	down(&usb_address0_sem);
 
-	tempstr = kmalloc(1024, GFP_KERNEL);
-	portstr = kmalloc(1024, GFP_KERNEL);
-
 	for (i = 0; i < HUB_PROBE_TRIES; i++) {
-		struct usb_device *pdev, *cdev;
+		struct usb_device *pdev;
+		int	len;
 
 		/* Allocate a new device struct */
 		dev = usb_alloc_dev(hub, hub->bus);
@@ -645,41 +676,46 @@
 
 		hub->children[port] = dev;
 
-		/* Reset the device */
+		/* Reset the device, and detect its speed */
 		if (usb_hub_port_reset(hub, port, dev, delay)) {
 			usb_free_dev(dev);
 			break;
 		}
 
-		/* Find a new device ID for it */
+		/* Find a new address for it */
 		usb_connect(dev);
 
-		/* Create a readable topology string */
-		cdev = dev;
-		pdev = dev->parent;
-		if (portstr && tempstr) {
-			portstr[0] = 0;
-			while (pdev) {
-				int port;
-
-				for (port = 0; port < pdev->maxchild; port++)
-					if (pdev->children[port] == cdev)
-						break;
-
-				strcpy(tempstr, portstr);
-				if (!strlen(tempstr))
-					sprintf(portstr, "%d", port + 1);
-				else
-					sprintf(portstr, "%d/%s", port + 1, tempstr);
+		/* Set up TT records, if needed  */
+		if (hub->tt) {
+			dev->tt = hub->tt;
+			dev->ttport = hub->ttport;
+		} else if (dev->speed != USB_SPEED_HIGH
+				&& hub->speed == USB_SPEED_HIGH) {
+			dev->tt = &hubstate->tt;
+			dev->ttport = port + 1;
+		}
 
-				cdev = pdev;
-				pdev = pdev->parent;
-			}
-			info("USB new device connect on bus%d/%s, assigned device number %d",
-				dev->bus->busnum, portstr, dev->devnum);
-		} else
-			info("USB new device connect on bus%d, assigned device number %d",
-				dev->bus->busnum, dev->devnum);
+		/* Save readable and stable topology id, distinguishing
+		 * devices by location for diagnostics, tools, etc.  The
+		 * string is a path along hub ports, from the root.  Each
+		 * device's id will be stable until USB is re-cabled, and
+		 * hubs are often labled with these port numbers.
+		 *
+		 * Initial size: "/NN" times five hubs + NUL = 16 bytes max
+		 * (quite rare, since most hubs have 4-6 ports).
+		 */
+		pdev = dev->parent;
+		if (pdev->devpath [1] != '\0')	/* parent not root */
+			len = snprintf (dev->devpath, sizeof dev->devpath,
+				"%s/%d", pdev->devpath, port + 1);
+		else	/* root == "/", root port 2 == "/2" */
+			len = snprintf (dev->devpath, sizeof dev->devpath,
+				"/%d", port + 1);
+		if (len == sizeof dev->devpath)
+			warn ("devpath size! usb/%03d/%03d path %s",
+				dev->bus->busnum, dev->devnum, dev->devpath);
+		info("new USB device on bus %d path %s, assigned address %d",
+			dev->bus->busnum, dev->devpath, dev->devnum);
 
 		/* Run it through the hoops (find a driver, etc) */
 		if (!usb_new_device(dev))
@@ -696,10 +732,6 @@
 	usb_hub_port_disable(hub, port);
 done:
 	up(&usb_address0_sem);
-	if (portstr)
-		kfree(portstr);
-	if (tempstr)
-		kfree(tempstr);
 }
 
 static void usb_hub_events(void)
@@ -737,10 +769,12 @@
 		spin_unlock_irqrestore(&hub_event_lock, flags);
 
 		if (hub->error) {
-			dbg("resetting hub %d for error %d", dev->devnum, hub->error);
+			dbg("resetting hub %s for error %d",
+				dev->devpath, hub->error);
 
 			if (usb_hub_reset(hub)) {
-				err("error resetting hub %d - disconnecting", dev->devnum);
+				err("error resetting hub %s - disconnecting",
+					dev->devpath);
 				up(&hub->khubd_sem);
 				usb_hub_disconnect(dev);
 				continue;
@@ -756,7 +790,8 @@
 
 			ret = usb_get_port_status(dev, i + 1, &portsts);
 			if (ret < 0) {
-				err("get_port_status failed (err = %d)", ret);
+				err("hub %s get_port_status failed (err = %d)",
+					dev->devpath, ret);
 				continue;
 			}
 
@@ -764,55 +799,68 @@
 			portchange = le16_to_cpu(portsts.wPortChange);
 
 			if (portchange & USB_PORT_STAT_C_CONNECTION) {
-				dbg("port %d connection change", i + 1);
-
-				usb_hub_port_connect_change(dev, i, &portsts);
+				dbg("hub %s port %d connection change",
+					dev->devpath, i + 1);
+				usb_hub_port_connect_change(hub, i, &portsts);
 			} else if (portchange & USB_PORT_STAT_C_ENABLE) {
-				dbg("port %d enable change, status %x", i + 1, portstatus);
-				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
+				dbg("hub %s port %d enable change, status %x",
+					dev->devpath, i + 1, portstatus);
+				usb_clear_port_feature(dev,
+					i + 1, USB_PORT_FEAT_C_ENABLE);
 
 				/*
-				 * EM interference sometimes causes bad shielded USB devices to 
-				 * be shutdown by the hub, this hack enables them again.
+				 * EM interference sometimes causes badly
+				 * shielded USB devices to be shutdown by
+				 * the hub, this hack enables them again.
 				 * Works at least with mouse driver. 
 				 */
-				if (!(portstatus & USB_PORT_STAT_ENABLE) && 
-				    (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) {
-					err("already running port %i disabled by hub (EMI?), re-enabling...",
-						i + 1);
-					usb_hub_port_connect_change(dev, i, &portsts);
+				if (!(portstatus & USB_PORT_STAT_ENABLE)
+				    && (portstatus & USB_PORT_STAT_CONNECTION)
+				    && (dev->children[i])) {
+					err("already running hub %s port %i "
+					    "disabled by hub (EMI?), "
+					    "re-enabling...",
+						dev->devpath, i + 1);
+					usb_hub_port_connect_change(hub,
+						i, &portsts);
 				}
 			}
 
 			if (portchange & USB_PORT_STAT_C_SUSPEND) {
-				dbg("port %d suspend change", i + 1);
-				usb_clear_port_feature(dev, i + 1,  USB_PORT_FEAT_C_SUSPEND);
+				dbg("hub %s port %d suspend change",
+					dev->devpath, i + 1);
+				usb_clear_port_feature(dev,
+					i + 1,  USB_PORT_FEAT_C_SUSPEND);
 			}
 			
 			if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
-				err("port %d over-current change", i + 1);
-				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
+				err("hub %s port %d over-current change",
+					dev->devpath, i + 1);
+				usb_clear_port_feature(dev,
+					i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
 				usb_hub_power_on(hub);
 			}
 
 			if (portchange & USB_PORT_STAT_C_RESET) {
-				dbg("port %d reset change", i + 1);
-				usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET);
+				dbg("hub %s port %d reset change",
+					dev->devpath, i + 1);
+				usb_clear_port_feature(dev,
+					i + 1, USB_PORT_FEAT_C_RESET);
 			}
 		} /* end for i */
 
 		/* deal with hub status changes */
 		if (usb_get_hub_status(dev, &hubsts) < 0)
-			err("get_hub_status failed");
+			err("get_hub_status %s failed", dev->devpath);
 		else {
 			hubstatus = le16_to_cpup(&hubsts.wHubStatus);
 			hubchange = le16_to_cpup(&hubsts.wHubChange);
 			if (hubchange & HUB_CHANGE_LOCAL_POWER) {
-				dbg("hub power change");
+				dbg("hub %s power change", dev->devpath);
 				usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
 			}
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
-				dbg("hub overcurrent change");
+				dbg("hub %s overcurrent change", dev->devpath);
 				wait_ms(500);	/* Cool down */
 				usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
                         	usb_hub_power_on(hub);
@@ -851,6 +899,8 @@
 }
 
 static struct usb_device_id hub_id_table [] = {
+    { match_flags: USB_DEVICE_ID_MATCH_DEV_CLASS,
+      bDeviceClass: USB_CLASS_HUB},
     { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
       bInterfaceClass: USB_CLASS_HUB},
     { }						/* Terminating entry */
@@ -989,9 +1039,13 @@
 		ret = usb_get_device_descriptor(dev);
 		if (ret < sizeof(dev->descriptor)) {
 			if (ret < 0)
-				err("unable to get device descriptor (error=%d)", ret);
+				err("unable to get device %s descriptor "
+					"(error=%d)", dev->devpath, ret);
 			else
-				err("USB device descriptor short read (expected %Zi, got %i)", sizeof(dev->descriptor), ret);
+				err("USB device %s descriptor short read "
+					"(expected %Zi, got %i)",
+					dev->devpath,
+					sizeof(dev->descriptor), ret);
         
 			clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
 			dev->devnum = -1;
@@ -1015,17 +1069,22 @@
 
 	ret = usb_set_configuration(dev, dev->actconfig->bConfigurationValue);
 	if (ret < 0) {
-		err("failed to set active configuration (error=%d)", ret);
+		err("failed to set dev %s active configuration (error=%d)",
+			dev->devpath, ret);
 		return ret;
 	}
 
 	for (i = 0; i < dev->actconfig->bNumInterfaces; i++) {
 		struct usb_interface *intf = &dev->actconfig->interface[i];
-		struct usb_interface_descriptor *as = &intf->altsetting[intf->act_altsetting];
+		struct usb_interface_descriptor *as;
 
-		ret = usb_set_interface(dev, as->bInterfaceNumber, as->bAlternateSetting);
+		as = &intf->altsetting[intf->act_altsetting];
+		ret = usb_set_interface(dev, as->bInterfaceNumber,
+			as->bAlternateSetting);
 		if (ret < 0) {
-			err("failed to set active alternate setting for interface %d (error=%d)", i, ret);
+			err("failed to set active alternate setting "
+				"for dev %s interface %d (error=%d)",
+				dev->devpath, i, ret);
 			return ret;
 		}
 	}
diff -urN linux-2.5.2-pre5/drivers/usb/hub.h linux/drivers/usb/hub.h
--- linux-2.5.2-pre5/drivers/usb/hub.h	Sun Dec 16 15:47:13 2001
+++ linux/drivers/usb/hub.h	Tue Jan  1 14:04:28 2002
@@ -1,6 +1,13 @@
 #ifndef __LINUX_HUB_H
 #define __LINUX_HUB_H
 
+/*
+ * Hub protocol and driver data structures.
+ *
+ * Some of these are known to the "virtual root hub" code
+ * in host controller drivers.
+ */
+
 #include <linux/list.h>
 
 /*
@@ -11,6 +18,15 @@
 #define USB_RT_PORT	(USB_TYPE_CLASS | USB_RECIP_OTHER)
 
 /*
+ * Hub class requests
+ * See USB 2.0 spec Table 11-16
+ */
+#define HUB_CLEAR_TT_BUFFER	8
+#define HUB_RESET_TT		9
+#define HUB_GET_TT_STATE	10
+#define HUB_STOP_TT		11
+
+/*
  * Hub Class feature numbers
  * See USB 2.0 spec Table 11-17
  */
@@ -55,7 +71,7 @@
 #define USB_PORT_STAT_SUSPEND		0x0004
 #define USB_PORT_STAT_OVERCURRENT	0x0008
 #define USB_PORT_STAT_RESET		0x0010
-/* bits 5 for 7 are reserved */
+/* bits 5 to 7 are reserved */
 #define USB_PORT_STAT_POWER		0x0100
 #define USB_PORT_STAT_LOW_SPEED		0x0200
 #define USB_PORT_STAT_HIGH_SPEED        0x0400
@@ -120,22 +136,21 @@
 struct usb_device;
 
 struct usb_hub {
-	struct usb_device *dev;
-
-	struct urb *urb;		/* Interrupt polling pipe */
-
-	char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */
-					/* and add 7 bits to round up to byte boundary */
-	int error;
-	int nerrors;
+	struct usb_device	*dev;		/* the "real" device */
+	struct urb		*urb;		/* for interrupt polling pipe */
 
-	struct list_head hub_list;
+	/* buffer for urb ... 1 bit each for hub and children, rounded up */
+	char			buffer[(USB_MAXCHILDREN + 1 + 7) / 8];
 
-	struct list_head event_list;
+	int			error;		/* last reported error */
+	int			nerrors;	/* track consecutive errors */
 
-	struct usb_hub_descriptor *descriptor;
+	struct list_head	hub_list;	/* all hubs */
+	struct list_head	event_list;	/* hubs w/data or errs ready */
 
-	struct semaphore khubd_sem;
+	struct usb_hub_descriptor *descriptor;	/* class descriptor */
+	struct semaphore	khubd_sem;
+	struct usb_tt		tt;		/* Transaction Translator */
 };
 
 #endif /* __LINUX_HUB_H */
diff -urN linux-2.5.2-pre5/drivers/usb/inode.c linux/drivers/usb/inode.c
--- linux-2.5.2-pre5/drivers/usb/inode.c	Sat Dec  8 20:28:44 2001
+++ linux/drivers/usb/inode.c	Tue Jan  1 14:04:28 2002
@@ -3,8 +3,8 @@
 /*
  *	inode.c  --  Inode/Dentry functions for the USB device file system.
  *
- *	Copyright (C) 2000
- *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *	Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
@@ -20,10 +20,9 @@
  *	along with this program; if not, write to the Free Software
  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *  $Id: inode.c,v 1.3 2000/01/11 13:58:25 tom Exp $
- *
  *  History:
  *   0.1  04.01.2000  Created
+ *   0.2  10.12.2001  converted to use the vfs layer better
  */
 
 /*****************************************************************************/
@@ -32,146 +31,40 @@
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/locks.h>
+#include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
-#include <asm/uaccess.h>
-
-/* --------------------------------------------------------------------- */
-
-/*
- * This list of superblocks is still used,
- * but since usbdevfs became FS_SINGLE
- * there is only one super_block.
- */
-static LIST_HEAD(superlist);
-
-struct special {
-	const char *name;
-	struct file_operations *fops;
-	struct inode *inode;
-	struct list_head inodes;
-};
-
-static struct special special[] = { 
-	{ "devices", &usbdevfs_devices_fops,  },
-	{ "drivers", &usbdevfs_drivers_fops,  }
-};
-
-#define NRSPECIAL (sizeof(special)/sizeof(special[0]))
-
-/* --------------------------------------------------------------------- */
-
-static int dnumber(struct dentry *dentry)
-{
-	const char *name;
-	unsigned int s;
-
-	if (dentry->d_name.len != 3)
-		return -1;
-	name = dentry->d_name.name;
-	if (name[0] < '0' || name[0] > '9' ||
-	    name[1] < '0' || name[1] > '9' ||
-	    name[2] < '0' || name[2] > '9')
-		return -1;
-	s = name[0] - '0';
-	s = s * 10 + name[1] - '0';
-	s = s * 10 + name[2] - '0';
-	return s;
-}
-
-/*
- * utility functions; should be called with the kernel lock held
- * to protect against busses/devices appearing/disappearing
- */
-
-static void new_dev_inode(struct usb_device *dev, struct super_block *sb)
-{
-	struct inode *inode;
-	unsigned int devnum = dev->devnum;
-	unsigned int busnum = dev->bus->busnum;
-
-	if (devnum < 1 || devnum > 127 || busnum > 255)
-		return;
-	inode = iget(sb, IDEVICE | (busnum << 8) | devnum);
-	if (!inode) {
-		printk(KERN_ERR "usbdevfs: cannot create inode for bus %u device %u\n", busnum, devnum);
-		return;
-	}
-	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_uid = sb->u.usbdevfs_sb.devuid;
-	inode->i_gid = sb->u.usbdevfs_sb.devgid;
-	inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG;
-	inode->i_fop = &usbdevfs_device_file_operations;
-	inode->i_size = sizeof(struct usb_device_descriptor);
-	inode->u.usbdev_i.p.dev = dev;
-	list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
-	list_add_tail(&inode->u.usbdev_i.dlist, &dev->inodes);
-}
 
-static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb)
-{
-	unsigned int i;
 
-	if (!dev)
-		return;
-	new_dev_inode(dev, sb);
-	for (i = 0; i < dev->maxchild; i++) {
-                if (!dev->children[i])
-                        continue;
-		recurse_new_dev_inode(dev->children[i], sb);
-	}
-}
-
-static void new_bus_inode(struct usb_bus *bus, struct super_block *sb)
-{
-	struct inode *inode;
-	unsigned int busnum = bus->busnum;
-
-	if (busnum > 255)
-		return;
-	inode = iget(sb, IBUS | (busnum << 8));
-	if (!inode) {
-		printk(KERN_ERR "usbdevfs: cannot create inode for bus %u\n", busnum);
-		return;
-	}
-	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_uid = sb->u.usbdevfs_sb.busuid;
-	inode->i_gid = sb->u.usbdevfs_sb.busgid;
-	inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR;
-	inode->i_op = &usbdevfs_bus_inode_operations;
-	inode->i_fop = &usbdevfs_bus_file_operations;
-	inode->u.usbdev_i.p.bus = bus;
-	list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist);
-	list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes);
-}
-
-static void free_inode(struct inode *inode)
-{
-	inode->u.usbdev_i.p.bus = NULL;
-	inode->u.usbdev_i.p.dev = NULL;
-	inode->i_mode &= ~S_IRWXUGO;
-	inode->i_uid = inode->i_gid = 0;
-	inode->i_size = 0;
-	list_del(&inode->u.usbdev_i.slist);
-	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
-	list_del(&inode->u.usbdev_i.dlist);
-	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
-	iput(inode);
-}
+static struct super_operations usbfs_ops;
+static struct address_space_operations usbfs_aops;
+static struct file_operations usbfs_dir_operations;
+static struct file_operations default_file_operations;
+static struct inode_operations usbfs_dir_inode_operations;
+static struct vfsmount *usbfs_mount;
+static spinlock_t mount_lock = SPIN_LOCK_UNLOCKED;
+static int mount_count;	/* = 0 */
+
+static struct dentry *devices_dentry;
+static struct dentry *drivers_dentry;
+static int num_buses;	/* = 0 */
+
+static uid_t devuid;	/* = 0 */
+static uid_t busuid;	/* = 0 */
+static uid_t listuid;	/* = 0 */
+static gid_t devgid;	/* = 0 */
+static gid_t busgid;	/* = 0 */
+static gid_t listgid;	/* = 0 */
+static umode_t devmode = S_IWUSR | S_IRUGO;
+static umode_t busmode = S_IXUGO | S_IRUGO;
+static umode_t listmode = S_IRUGO;
 
 static int parse_options(struct super_block *s, char *data)
 {
-	uid_t devuid = 0, busuid = 0, listuid = 0;
-	gid_t devgid = 0, busgid = 0, listgid = 0;
-	umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO;
 	char *curopt = NULL, *value;
 
-	/* parse options */
 	if (data)
 		curopt = strtok(data, ",");
 	for (; curopt; curopt = strtok(NULL, ",")) {
@@ -242,481 +135,572 @@
 		}
 	}
 
-	s->u.usbdevfs_sb.devuid = devuid;
-	s->u.usbdevfs_sb.devgid = devgid;
-	s->u.usbdevfs_sb.devmode = devmode;
-	s->u.usbdevfs_sb.busuid = busuid;
-	s->u.usbdevfs_sb.busgid = busgid;
-	s->u.usbdevfs_sb.busmode = busmode;
-	s->u.usbdevfs_sb.listuid = listuid;
-	s->u.usbdevfs_sb.listgid = listgid;
-	s->u.usbdevfs_sb.listmode = listmode;
+	return 0;
+}
+
+
+/* --------------------------------------------------------------------- */
 
+static struct dentry *usbfs_lookup (struct inode *dir, struct dentry *dentry)
+{
+	d_add(dentry, NULL);
+	return NULL;
+}
+
+static int usbfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	buf->f_type = USBDEVICE_SUPER_MAGIC;
+	buf->f_bsize = PAGE_CACHE_SIZE;
+	buf->f_namelen = NAME_MAX;
 	return 0;
 }
 
-static struct usb_bus *usbdevfs_findbus(int busnr)
+static struct inode *usbfs_get_inode (struct super_block *sb, int mode, int dev)
 {
-        struct list_head *list;
-        struct usb_bus *bus;
+	struct inode *inode = new_inode(sb);
 
-	down (&usb_bus_list_lock);
-        for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
-                bus = list_entry(list, struct usb_bus, bus_list);
-                if (bus->busnum == busnr) {
-			up (&usb_bus_list_lock);
-                        return bus;
+	if (inode) {
+		inode->i_mode = mode;
+		inode->i_uid = current->fsuid;
+		inode->i_gid = current->fsgid;
+		inode->i_blksize = PAGE_CACHE_SIZE;
+		inode->i_blocks = 0;
+		inode->i_rdev = NODEV;
+		inode->i_mapping->a_ops = &usbfs_aops;
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+		switch (mode & S_IFMT) {
+		default:
+			init_special_inode(inode, mode, dev);
+			break;
+		case S_IFREG:
+			inode->i_fop = &default_file_operations;
+			break;
+		case S_IFDIR:
+			inode->i_op = &usbfs_dir_inode_operations;
+			inode->i_fop = &usbfs_dir_operations;
+			break;
 		}
-        }
-	up (&usb_bus_list_lock);
-        return NULL;
+	}
+	return inode; 
 }
 
-#if 0
-static struct usb_device *finddev(struct usb_device *dev, int devnr)
+static int usbfs_mknod (struct inode *dir, struct dentry *dentry, int mode,
+			int dev)
 {
-        unsigned int i;
-        struct usb_device *d2;
+	struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev);
+	int error = -ENOSPC;
 
-        if (!dev)
-                return NULL;
-        if (dev->devnum == devnr)
-                return dev;
-        for (i = 0; i < dev->maxchild; i++) {
-                if (!dev->children[i])
-                        continue;
-                if ((d2 = finddev(dev->children[i], devnr)))
-                        return d2;
-        }
-        return NULL;
+	if (inode) {
+		d_instantiate(dentry, inode);
+		dget(dentry);
+		error = 0;
+	}
+	return error;
 }
 
-static struct usb_device *usbdevfs_finddevice(struct usb_bus *bus, int devnr)
+static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
 {
-        return finddev(bus->root_hub, devnr);
+	return usbfs_mknod (dir, dentry, mode | S_IFDIR, 0);
 }
-#endif
 
-/* --------------------------------------------------------------------- */
+static int usbfs_create (struct inode *dir, struct dentry *dentry, int mode)
+{
+ 	return usbfs_mknod (dir, dentry, mode | S_IFREG, 0);
+}
 
-static int usbdevfs_revalidate(struct dentry *dentry, int flags)
+static int usbfs_link (struct dentry *old_dentry, struct inode *dir,
+		       struct dentry *dentry)
 {
-	struct inode *inode = dentry->d_inode;
+	struct inode *inode = old_dentry->d_inode;
 
-        if (!inode)
-                return 0;
-	if (ITYPE(inode->i_ino) == IBUS && !inode->u.usbdev_i.p.bus)
-		return 0;
-	if (ITYPE(inode->i_ino) == IDEVICE && !inode->u.usbdev_i.p.dev)
-		return 0;
-	return 1;
+	if(S_ISDIR(inode->i_mode))
+		return -EPERM;
+
+	inode->i_nlink++;
+	atomic_inc(&inode->i_count);
+ 	dget(dentry);
+	d_instantiate(dentry, inode);
+	return 0;
 }
 
-static struct dentry_operations usbdevfs_dentry_operations = {
-	d_revalidate:	usbdevfs_revalidate,
-};
+static inline int usbfs_positive (struct dentry *dentry)
+{
+	return dentry->d_inode && !d_unhashed(dentry);
+}
 
-static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry)
+static int usbfs_empty (struct dentry *dentry)
 {
-	int busnr;
-	unsigned long ino = 0;
-	unsigned int i;
-	struct inode *inode;
+	struct list_head *list;
 
-	/* sanity check */
-	if (dir->i_ino != IROOT)
-		return ERR_PTR(-EINVAL);
-	dentry->d_op = &usbdevfs_dentry_operations;
-	busnr = dnumber(dentry);
-	if (busnr >= 0 && busnr <= 255)
-		ino = IBUS | (busnr << 8);
-	if (!ino) {
-		for (i = 0; i < NRSPECIAL; i++) {
-			if (strlen(special[i].name) == dentry->d_name.len && 
-			    !strncmp(special[i].name, dentry->d_name.name, dentry->d_name.len)) {
-				ino = ISPECIAL | (i + IROOT + 1);
-				break;
-			}
+	spin_lock(&dcache_lock);
+
+	list_for_each(list, &dentry->d_subdirs) {
+		struct dentry *de = list_entry(list, struct dentry, d_child);
+		if (usbfs_positive(de)) {
+			spin_unlock(&dcache_lock);
+			return 0;
 		}
 	}
-	if (!ino)
-		return ERR_PTR(-ENOENT);
-	inode = iget(dir->i_sb, ino);
-	if (!inode)
-		return ERR_PTR(-EINVAL);
-	if (inode && ITYPE(ino) == IBUS && inode->u.usbdev_i.p.bus == NULL) {
-		iput(inode);
-		inode = NULL;
-	}
-	d_add(dentry, inode);
-	return NULL;
+
+	spin_unlock(&dcache_lock);
+	return 1;
 }
 
-static struct dentry *usbdevfs_bus_lookup(struct inode *dir, struct dentry *dentry)
+static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
 {
-	struct inode *inode;
-	int devnr;
+	int error = -ENOTEMPTY;
 
-	/* sanity check */
-	if (ITYPE(dir->i_ino) != IBUS)
-		return ERR_PTR(-EINVAL);
-	dentry->d_op = &usbdevfs_dentry_operations;
-	devnr = dnumber(dentry);
-	if (devnr < 1 || devnr > 127)
-		return ERR_PTR(-ENOENT);
-	inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr);
-	if (!inode)
-		return ERR_PTR(-EINVAL);
-	if (inode && inode->u.usbdev_i.p.dev == NULL) {
-		iput(inode);
-		inode = NULL;
+	if (usbfs_empty(dentry)) {
+		struct inode *inode = dentry->d_inode;
+
+		inode->i_nlink--;
+		dput(dentry);
+		error = 0;
 	}
-	d_add(dentry, inode);
-	return NULL;
+	return error;
 }
 
-static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int usbfs_rename (struct inode *old_dir, struct dentry *old_dentry,
+			 struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct inode *inode = filp->f_dentry->d_inode;
-	unsigned long ino = inode->i_ino;
-	struct special *spec;
-	struct list_head *list;
-	struct usb_bus *bus;
-	char numbuf[8];
-	unsigned int i;
-
-	/* sanity check */
-	if (ino != IROOT)
-		return -EINVAL;
-	i = filp->f_pos;
-	switch (i) {
-	case 0:
-		if (filldir(dirent, ".", 1, i, IROOT, DT_DIR) < 0)
-			return 0;
-		filp->f_pos++;
-		i++;
-		/* fall through */
+	int error = -ENOTEMPTY;
 
-	case 1:
-		if (filldir(dirent, "..", 2, i, IROOT, DT_DIR) < 0)
-			return 0;
-		filp->f_pos++;
-		i++;
-		/* fall through */
-
-	default:
-		
-		while (i >= 2 && i < 2+NRSPECIAL) {
-			spec = &special[filp->f_pos-2];
-			if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT), DT_UNKNOWN) < 0)
-				return 0;
-			filp->f_pos++;
-			i++;
-		}
-		if (i < 2+NRSPECIAL)
-			return 0;
-		i -= 2+NRSPECIAL;
-		down (&usb_bus_list_lock);
-		for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
-			if (i > 0) {
-				i--;
-				continue;
-			}
-			bus = list_entry(list, struct usb_bus, bus_list);
-			sprintf(numbuf, "%03d", bus->busnum);
-			if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8), DT_UNKNOWN) < 0)
-				break;
-			filp->f_pos++;
+	if (usbfs_empty(new_dentry)) {
+		struct inode *inode = new_dentry->d_inode;
+		if (inode) {
+			inode->i_nlink--;
+			dput(new_dentry);
 		}
-		up (&usb_bus_list_lock);
-		return 0;
+		error = 0;
 	}
+	return error;
 }
 
-static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct file *filp, void *dirent, filldir_t filldir)
+#define usbfs_rmdir usbfs_unlink
+
+/* default file operations */
+static ssize_t default_read_file (struct file *file, char *buf,
+				  size_t count, loff_t *ppos)
 {
-	char numbuf[8];
-	unsigned int i;
+	return 0;
+}
 
-	if (!dev)
-		return pos;
-	sprintf(numbuf, "%03d", dev->devnum);
-	if (pos > 0)
-		pos--;
-	else {
-		if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff), DT_UNKNOWN) < 0)
-			return -1;
-		filp->f_pos++;
-	}
-	for (i = 0; i < dev->maxchild; i++) {
-		if (!dev->children[i])
-			continue;
-		pos = bus_readdir(dev->children[i], ino, pos, filp, dirent, filldir);
-		if (pos < 0)
-			return -1;
-	}
-	return pos;
+static ssize_t default_write_file (struct file *file, const char *buf,
+				   size_t count, loff_t *ppos)
+{
+	return count;
 }
 
-static int usbdevfs_bus_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
 {
-	struct inode *inode = filp->f_dentry->d_inode;
-	unsigned long ino = inode->i_ino;
-	struct usb_bus *bus;
+	loff_t retval = -EINVAL;
 
-	/* sanity check */
-	if (ITYPE(ino) != IBUS)
-		return -EINVAL;
-	switch ((unsigned int)filp->f_pos) {
+	switch(orig) {
 	case 0:
-		if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) < 0)
-			return 0;
-		filp->f_pos++;
-		/* fall through */
-
+		if (offset > 0) {
+			file->f_pos = offset;
+			retval = file->f_pos;
+		} 
+		break;
 	case 1:
-		if (filldir(dirent, "..", 2, filp->f_pos, IROOT, DT_DIR) < 0)
-			return 0;
-		filp->f_pos++;
-		/* fall through */
-
+		if ((offset + file->f_pos) > 0) {
+			file->f_pos += offset;
+			retval = file->f_pos;
+		} 
+		break;
 	default:
-		lock_kernel();
-		bus = usbdevfs_findbus(IBUSNR(ino));
-		bus_readdir(bus->root_hub, IDEVICE | ((bus->busnum & 0xff) << 8), filp->f_pos-2, filp, dirent, filldir);
-		unlock_kernel();
-		return 0;
+		break;
 	}
+	return retval;
+}
+
+static int default_open (struct inode *inode, struct file *filp)
+{
+	if (inode->u.generic_ip)
+		filp->private_data = inode->u.generic_ip;
+
+	return 0;
 }
 
-static struct file_operations usbdevfs_root_file_operations = {
-	readdir: usbdevfs_root_readdir,
+static int default_sync_file (struct file *file, struct dentry *dentry,
+			      int datasync)
+{
+	return 0;
+}
+
+static struct address_space_operations usbfs_aops = {
 };
 
-static struct inode_operations usbdevfs_root_inode_operations = {
-	lookup: usbdevfs_root_lookup,
+static struct file_operations usbfs_dir_operations = {
+	read:		generic_read_dir,
+	readdir:	dcache_readdir,
+	fsync:		default_sync_file,
 };
 
-static struct file_operations usbdevfs_bus_file_operations = {
-	readdir: usbdevfs_bus_readdir,
+static struct file_operations default_file_operations = {
+	read:		default_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+	fsync:		default_sync_file,
+	mmap:		generic_file_mmap,
 };
 
-static struct inode_operations usbdevfs_bus_inode_operations = {
-	lookup: usbdevfs_bus_lookup,
+static struct inode_operations usbfs_dir_inode_operations = {
+	create:		usbfs_create,
+	lookup:		usbfs_lookup,
+	link:		usbfs_link,
+	unlink:		usbfs_unlink,
+	mkdir:		usbfs_mkdir,
+	rmdir:		usbfs_rmdir,
+	mknod:		usbfs_mknod,
+	rename:		usbfs_rename,
 };
 
-static void usbdevfs_read_inode(struct inode *inode)
-{
-	struct special *spec;
+static struct super_operations usbfs_ops = {
+	statfs:		usbfs_statfs,
+	put_inode:	force_delete,
+};
 
-	inode->i_ctime = inode->i_mtime = inode->i_atime = CURRENT_TIME;
-	inode->i_mode = S_IFREG;
-	inode->i_gid = inode->i_uid = 0;
-	INIT_LIST_HEAD(&inode->u.usbdev_i.dlist);
-	INIT_LIST_HEAD(&inode->u.usbdev_i.slist);
-	inode->u.usbdev_i.p.dev = NULL;
-	inode->u.usbdev_i.p.bus = NULL;
-	switch (ITYPE(inode->i_ino)) {
-	case ISPECIAL:
-		if (inode->i_ino == IROOT) {
-			inode->i_op = &usbdevfs_root_inode_operations;
-			inode->i_fop = &usbdevfs_root_file_operations;
-			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
-			return;
-		}
-		if (inode->i_ino <= IROOT || inode->i_ino > IROOT+NRSPECIAL)
-			return;
-		spec = &special[inode->i_ino-(IROOT+1)];
-		inode->i_fop = spec->fops;
-		return;
+static struct super_block *usbfs_read_super (struct super_block *sb, void *data, 
+					     int silent)
+{
+	struct inode *inode;
+	struct dentry *root;
 
-	case IDEVICE:
-		return;
+	if (parse_options(sb, data)) {
+		warn("usbfs: mount parameter error:");
+		return NULL;
+	}
 
-	case IBUS:
-		return;
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	sb->s_magic = USBDEVICE_SUPER_MAGIC;
+	sb->s_op = &usbfs_ops;
+	inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
 
-	default:
-		return;
-        }
-}
+	if (!inode) {
+		dbg("%s: could not get inode!\n",__FUNCTION__);
+		return NULL;
+	}
 
-static void usbdevfs_put_super(struct super_block *sb)
-{
-	list_del(&sb->u.usbdevfs_sb.slist);
-	INIT_LIST_HEAD(&sb->u.usbdevfs_sb.slist);
-	while (!list_empty(&sb->u.usbdevfs_sb.ilist))
-		free_inode(list_entry(sb->u.usbdevfs_sb.ilist.next, struct inode, u.usbdev_i.slist));
+	root = d_alloc_root(inode);
+	if (!root) {
+		dbg("%s: could not get root dentry!\n",__FUNCTION__);
+		iput(inode);
+		return NULL;
+	}
+	sb->s_root = root;
+	return sb;
 }
 
-static int usbdevfs_statfs(struct super_block *sb, struct statfs *buf)
+/**
+ * fs_create_by_name - create a file, given a name
+ * @name:	name of file
+ * @mode:	type of file
+ * @parent:	dentry of directory to create it in
+ * @dentry:	resulting dentry of file
+ *
+ * There is a bit of overhead in creating a file - basically, we 
+ * have to hash the name of the file, then look it up. This will
+ * prevent files of the same name. 
+ * We then call the proper vfs_ function to take care of all the 
+ * file creation details. 
+ * This function handles both regular files and directories.
+ */
+static int fs_create_by_name (const char *name, mode_t mode,
+			      struct dentry *parent, struct dentry **dentry)
 {
-        buf->f_type = USBDEVICE_SUPER_MAGIC;
-        buf->f_bsize = PAGE_SIZE/sizeof(long);   /* ??? */
-        buf->f_bfree = 0;
-        buf->f_bavail = 0;
-        buf->f_ffree = 0;
-        buf->f_namelen = NAME_MAX;
-        return 0;
-}
+	struct dentry *d = NULL;
+	struct qstr qstr;
+	int error;
 
-static int usbdevfs_remount(struct super_block *s, int *flags, char *data)
-{
-	struct list_head *ilist = s->u.usbdevfs_sb.ilist.next;
-	struct inode *inode;
-	int ret;
+	/* If the parent is not specified, we create it in the root.
+	 * We need the root dentry to do this, which is in the super 
+	 * block. A pointer to that is in the struct vfsmount that we
+	 * have around.
+	 */
+	if (!parent ) {
+		if (usbfs_mount && usbfs_mount->mnt_sb) {
+			parent = usbfs_mount->mnt_sb->s_root;
+		}
+	}
 
-	if ((ret = parse_options(s, data))) {
-		printk(KERN_WARNING "usbdevfs: remount parameter error\n");
-		return ret;
+	if (!parent) {
+		dbg("Ah! can not find a parent!\n");
+		return -EFAULT;
 	}
 
-	for (; ilist != &s->u.usbdevfs_sb.ilist; ilist = ilist->next) {
-		inode = list_entry(ilist, struct inode, u.usbdev_i.slist);
+	*dentry = NULL;
+	qstr.name = name;
+	qstr.len = strlen(name);
+ 	qstr.hash = full_name_hash(name,qstr.len);
 
-		switch (ITYPE(inode->i_ino)) {
-			case ISPECIAL :
-				inode->i_uid = s->u.usbdevfs_sb.listuid;
-				inode->i_gid = s->u.usbdevfs_sb.listgid;
-				inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG;
-				break;
-			case IBUS :
-				inode->i_uid = s->u.usbdevfs_sb.busuid;
-				inode->i_gid = s->u.usbdevfs_sb.busgid;
-				inode->i_mode = s->u.usbdevfs_sb.busmode | S_IFDIR;
+	parent = dget(parent);
+
+	down(&parent->d_inode->i_sem);
+
+	d = lookup_hash(&qstr,parent);
+
+	error = PTR_ERR(d);
+	if (!IS_ERR(d)) {
+		switch(mode & S_IFMT) {
+			case 0: 
+			case S_IFREG:
+				error = vfs_create(parent->d_inode,d,mode);
 				break;
-			case IDEVICE :
-				inode->i_uid = s->u.usbdevfs_sb.devuid;
-				inode->i_gid = s->u.usbdevfs_sb.devgid;
-				inode->i_mode = s->u.usbdevfs_sb.devmode | S_IFREG;
+			case S_IFDIR:
+				error = vfs_mkdir(parent->d_inode,d,mode);
 				break;
+			default:
+				err("cannot create special files\n");
 		}
+		*dentry = d;
 	}
+	up(&parent->d_inode->i_sem);
 
-	return 0;
+	dput(parent);
+	return error;
 }
 
-static struct super_operations usbdevfs_sops = { 
-	read_inode:	usbdevfs_read_inode,
-	put_super:	usbdevfs_put_super,
-	statfs:		usbdevfs_statfs,
-	remount_fs:	usbdevfs_remount,
-};
-
-struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int silent)
+static struct dentry *fs_create_file (const char *name, mode_t mode,
+				      struct dentry *parent, void *data,
+				      struct file_operations *fops,
+				      uid_t uid, gid_t gid)
 {
-        struct inode *root_inode, *inode;
-	struct list_head *blist;
-	struct usb_bus *bus;
-	unsigned int i;
+	struct dentry *dentry;
+	int error;
 
-	if (parse_options(s, data)) {
-		printk(KERN_WARNING "usbdevfs: mount parameter error\n");
-		return NULL;
+	dbg("creating file '%s'\n",name);
+
+	error = fs_create_by_name(name,mode,parent,&dentry);
+	if (error) {
+		dentry = NULL;
+	} else {
+		if (dentry->d_inode) {
+			if (data)
+				dentry->d_inode->u.generic_ip = data;
+			if (fops)
+				dentry->d_inode->i_fop = fops;
+			dentry->d_inode->i_uid = uid;
+			dentry->d_inode->i_gid = gid;
+		}
 	}
 
-	/* fill superblock */
-        s->s_blocksize = 1024;
-        s->s_blocksize_bits = 10;
-        s->s_magic = USBDEVICE_SUPER_MAGIC;
-        s->s_op = &usbdevfs_sops;
-	INIT_LIST_HEAD(&s->u.usbdevfs_sb.slist);
-	INIT_LIST_HEAD(&s->u.usbdevfs_sb.ilist);
-	root_inode = iget(s, IROOT);
-        if (!root_inode)
-                goto out_no_root;
-        s->s_root = d_alloc_root(root_inode);
-        if (!s->s_root)
-                goto out_no_root;
-	list_add_tail(&s->u.usbdevfs_sb.slist, &superlist);
-	for (i = 0; i < NRSPECIAL; i++) {
-		if (!(inode = iget(s, IROOT+1+i)))
-			continue;
-		inode->i_uid = s->u.usbdevfs_sb.listuid;
-		inode->i_gid = s->u.usbdevfs_sb.listgid;
-		inode->i_mode = s->u.usbdevfs_sb.listmode | S_IFREG;
-		special[i].inode = inode;
-		list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
-		list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
-	}
-	down (&usb_bus_list_lock);
-	for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) {
-		bus = list_entry(blist, struct usb_bus, bus_list);
-		new_bus_inode(bus, s);
-		recurse_new_dev_inode(bus->root_hub, s);
-	}
-	up (&usb_bus_list_lock);
-        return s;
-
- out_no_root:
-        printk("usbdevfs_read_super: get root inode failed\n");
-        iput(root_inode);
-        return NULL;
+	return dentry;
 }
 
+static void fs_remove_file (struct dentry *dentry)
+{
+	struct dentry *parent = dentry->d_parent;
+	
+	if (!parent || !parent->d_inode)
+		return;
+
+	down(&parent->d_inode->i_sem);
+	if (usbfs_positive(dentry)) {
+		if (dentry->d_inode) {
+			if (S_ISDIR(dentry->d_inode->i_mode))
+				vfs_rmdir(parent->d_inode,dentry);
+			else
+				vfs_unlink(parent->d_inode,dentry);
+		}
+
+		dput(dentry);
+	}
+	up(&parent->d_inode->i_sem);
+}
+
+/* --------------------------------------------------------------------- */
+
+
+
 /*
- * The usbdevfs name is now depreciated (as of 2.5.1).
+ * The usbdevfs name is now deprecated (as of 2.5.1).
  * It will be removed when the 2.7.x development cycle is started.
  * You have been warned :)
  */
-static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbdevfs_read_super, FS_SINGLE);
-static DECLARE_FSTYPE(usb_fs_type, "usbfs", usbdevfs_read_super, FS_SINGLE);
+static DECLARE_FSTYPE(usbdevice_fs_type, "usbdevfs", usbfs_read_super, FS_SINGLE);
+static DECLARE_FSTYPE(usb_fs_type,       "usbfs",    usbfs_read_super, FS_SINGLE);
 
 /* --------------------------------------------------------------------- */
+static int get_mount (void)
+{
+	struct vfsmount *mnt;
 
-static void update_special_inodes (void)
+	spin_lock (&mount_lock);
+	if (usbfs_mount) {
+		mntget(usbfs_mount);
+		++mount_count;
+		spin_unlock (&mount_lock);
+		goto go_ahead;
+	}
+
+	spin_unlock (&mount_lock);
+	mnt = kern_mount (&usbdevice_fs_type);
+	if (IS_ERR(mnt)) {
+		err ("could not mount the fs...erroring out!\n");
+		return -ENODEV;
+	}
+	spin_lock (&mount_lock);
+	if (!usbfs_mount) {
+		usbfs_mount = mnt;
+		++mount_count;
+		spin_unlock (&mount_lock);
+		goto go_ahead;
+	}
+	mntget(usbfs_mount);
+	++mount_count;
+	spin_unlock (&mount_lock);
+	mntput(mnt);
+
+go_ahead:
+	dbg("mount_count = %d\n", mount_count);
+	return 0;
+}
+
+static void remove_mount (void)
+{
+	struct vfsmount *mnt;
+
+	spin_lock (&mount_lock);
+	mnt = usbfs_mount;
+	--mount_count;
+	if (!mount_count)
+		usbfs_mount = NULL;
+
+	spin_unlock (&mount_lock);
+	mntput(mnt);
+	dbg("mount_count = %d\n", mount_count);
+}
+
+static int create_special_files (void)
+{
+	int retval;
+
+	/* create the devices and drivers special files */
+	retval = get_mount ();
+	if (retval)
+		return retval;
+	devices_dentry = fs_create_file ("devices",
+					 listmode | S_IFREG,
+					 NULL, NULL,
+					 &usbdevfs_devices_fops,
+					 listuid, listgid);
+	if (devices_dentry == NULL) {
+		err ("Unable to create devices usbfs file");
+		return -ENODEV;
+	}
+
+	drivers_dentry = fs_create_file ("drivers",
+					 listmode | S_IFREG,
+					 NULL, NULL,
+					 &usbdevfs_drivers_fops,
+					 listuid, listgid);
+	if (drivers_dentry == NULL) {
+		err ("Unable to create drivers usbfs file");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void remove_special_files (void)
+{
+	if (devices_dentry)
+		fs_remove_file (devices_dentry);
+	if (drivers_dentry)
+		fs_remove_file (drivers_dentry);
+	devices_dentry = NULL;
+	drivers_dentry = NULL;
+	remove_mount();
+}
+
+void usbfs_update_special (void)
 {
-	int i;
-	for (i = 0; i < NRSPECIAL; i++) {
-		struct inode *inode = special[i].inode;
+	struct inode *inode;
+
+	if (devices_dentry) {
+		inode = devices_dentry->d_inode;
+		if (inode)
+			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	}
+	if (drivers_dentry) {
+		inode = devices_dentry->d_inode;
 		if (inode)
 			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	}
 }
 
-
-void usbdevfs_add_bus(struct usb_bus *bus)
+void usbfs_add_bus(struct usb_bus *bus)
 {
-	struct list_head *slist;
+	char name[8];
+	int retval;
+
+	/* create the special files if this is the first bus added */
+	if (num_buses == 0) {
+		retval = create_special_files();
+		if (retval)
+			return;
+	}
+	++num_buses;
+
+	sprintf (name, "%03d", bus->busnum);
+	bus->dentry = fs_create_file (name,
+				      busmode | S_IFDIR,
+				      NULL, bus, NULL,
+				      busuid, busgid);
+	if (bus->dentry == NULL)
+		return;
 
-	lock_kernel();
-	for (slist = superlist.next; slist != &superlist; slist = slist->next)
-		new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
-	update_special_inodes();
-	unlock_kernel();
+	usbfs_update_special();
 	usbdevfs_conn_disc_event();
 }
 
-void usbdevfs_remove_bus(struct usb_bus *bus)
+
+void usbfs_remove_bus(struct usb_bus *bus)
 {
-	lock_kernel();
-	while (!list_empty(&bus->inodes))
-		free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist));
-	update_special_inodes();
-	unlock_kernel();
+	if (bus->dentry) {
+		fs_remove_file (bus->dentry);
+		bus->dentry = NULL;
+	}
+
+	--num_buses;
+	if (num_buses <= 0) {
+		remove_special_files();
+		num_buses = 0;
+	}
+
+	usbfs_update_special();
 	usbdevfs_conn_disc_event();
 }
 
-void usbdevfs_add_device(struct usb_device *dev)
+void usbfs_add_device(struct usb_device *dev)
 {
-	struct list_head *slist;
+	char name[8];
 
-	lock_kernel();
-	for (slist = superlist.next; slist != &superlist; slist = slist->next)
-		new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
-	update_special_inodes();
-	unlock_kernel();
+	sprintf (name, "%03d", dev->devnum);
+	dev->dentry = fs_create_file (name,
+				      devmode | S_IFREG,
+				      dev->bus->dentry, dev,
+				      &usbdevfs_device_file_operations,
+				      devuid, devgid);
+	if (dev->dentry == NULL)
+		return;
+
+	usbfs_update_special();
 	usbdevfs_conn_disc_event();
 }
 
-void usbdevfs_remove_device(struct usb_device *dev)
+void usbfs_remove_device(struct usb_device *dev)
 {
 	struct dev_state *ds;
 	struct siginfo sinfo;
 
-	lock_kernel();
-	while (!list_empty(&dev->inodes))
-		free_inode(list_entry(dev->inodes.next, struct inode, u.usbdev_i.dlist));
+	if (dev->dentry) {
+		fs_remove_file (dev->dentry);
+		dev->dentry = NULL;
+	}
 	while (!list_empty(&dev->filelist)) {
 		ds = list_entry(dev->filelist.next, struct dev_state, list);
 		list_del(&ds->list);
@@ -732,9 +716,7 @@
 			send_sig_info(ds->discsignr, &sinfo, ds->disctask);
 		}
 	}
-
-	update_special_inodes();
-	unlock_kernel();
+	usbfs_update_special();
 	usbdevfs_conn_disc_event();
 }
 
@@ -744,39 +726,42 @@
 static struct proc_dir_entry *usbdir = NULL;
 #endif	
 
-int __init usbdevfs_init(void)
+int __init usbfs_init(void)
 {
-	int ret;
+	int retval;
 
-	for (ret = 0; ret < NRSPECIAL; ret++) {
-		INIT_LIST_HEAD(&special[ret].inodes);
-	}
-	if ((ret = usb_register(&usbdevfs_driver)))
-		return ret;
-	if ((ret = register_filesystem(&usb_fs_type))) {
+	retval = usb_register(&usbdevfs_driver);
+	if (retval)
+		return retval;
+
+	retval = register_filesystem(&usb_fs_type);
+	if (retval) {
 		usb_deregister(&usbdevfs_driver);
-		return ret;
+		return retval;
 	}
-	if ((ret = register_filesystem(&usbdevice_fs_type))) {
+	retval = register_filesystem(&usbdevice_fs_type);
+	if (retval) {
 		unregister_filesystem(&usb_fs_type);
 		usb_deregister(&usbdevfs_driver);
-		return ret;
+		return retval;
 	}
+
 #ifdef CONFIG_PROC_FS		
 	/* create mount point for usbdevfs */
 	usbdir = proc_mkdir("usb", proc_bus);
 #endif	
-	return ret;
+
+	return 0;
 }
 
-void __exit usbdevfs_cleanup(void)
+void __exit usbfs_cleanup(void)
 {
 	usb_deregister(&usbdevfs_driver);
 	unregister_filesystem(&usb_fs_type);
 	unregister_filesystem(&usbdevice_fs_type);
 #ifdef CONFIG_PROC_FS	
-        if (usbdir)
-                remove_proc_entry("usb", proc_bus);
+	if (usbdir)
+		remove_proc_entry("usb", proc_bus);
 #endif
 }
 
diff -urN linux-2.5.2-pre5/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c
--- linux-2.5.2-pre5/drivers/usb/mdc800.c	Sat Dec  8 20:28:44 2001
+++ linux/drivers/usb/mdc800.c	Tue Jan  1 14:04:28 2002
@@ -140,7 +140,7 @@
 
 	unsigned int		endpoint [4];
 
-	purb_t			irq_urb;
+	struct urb *		irq_urb;
 	wait_queue_head_t	irq_wait;
 	int			irq_woken;
 	char*			irq_urb_buffer;
@@ -149,13 +149,13 @@
 	int 			camera_request_ready; // Status to synchronize with irq
 	char 			camera_response [8];  // last Bytes send after busy
 
-	purb_t   		write_urb;
+	struct urb *   		write_urb;
 	char*			write_urb_buffer;
 	wait_queue_head_t	write_wait;
 	int			written;
 
 
-	purb_t	   		download_urb;
+	struct urb *   		download_urb;
 	char*			download_urb_buffer;
 	wait_queue_head_t	download_wait;
 	int			downloaded;
diff -urN linux-2.5.2-pre5/drivers/usb/pwc-if.c linux/drivers/usb/pwc-if.c
--- linux-2.5.2-pre5/drivers/usb/pwc-if.c	Mon Nov 26 17:09:10 2001
+++ linux/drivers/usb/pwc-if.c	Tue Jan  1 14:04:28 2002
@@ -624,7 +624,7 @@
 /* This gets called for the Isochronous pipe (video). This is done in
  * interrupt time, so it has to be fast, not crash, and not stall. Neat.
  */
-static void pwc_isoc_handler(purb_t urb)
+static void pwc_isoc_handler(struct urb *urb)
 {
 	struct pwc_device *pdev;
 	int i, fst, flen;
@@ -786,7 +786,7 @@
 static int pwc_isoc_init(struct pwc_device *pdev)
 {
 	struct usb_device *udev;
-	purb_t urb;
+	struct urb *urb;
 	int i, j, ret;
 
 	struct usb_interface_descriptor *idesc;
diff -urN linux-2.5.2-pre5/drivers/usb/pwc.h linux/drivers/usb/pwc.h
--- linux-2.5.2-pre5/drivers/usb/pwc.h	Mon Nov 26 17:09:10 2001
+++ linux/drivers/usb/pwc.h	Tue Jan  1 14:04:28 2002
@@ -96,7 +96,7 @@
 	void *data;
 	int  length;
 	int  read;
-	purb_t urb;
+	struct urb *urb;
 };
 
 /* intermediate buffers with raw data from the USB cam */
diff -urN linux-2.5.2-pre5/drivers/usb/serial/ipaq.c linux/drivers/usb/serial/ipaq.c
--- linux-2.5.2-pre5/drivers/usb/serial/ipaq.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/ipaq.c	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,525 @@
+/*
+ * USB Compaq iPAQ driver
+ *
+ *	Copyright (C) 2001
+ *	    Ganesh Varadarajan <ganesh@veritas.com>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	static int debug = 1;
+#else
+	static int debug = 0;
+#endif
+
+#include "usb-serial.h"
+#include "ipaq.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
+#define DRIVER_DESC "USB Compaq iPAQ driver"
+
+/* Function prototypes for an ipaq */
+static int  ipaq_open (struct usb_serial_port *port, struct file *filp);
+static void ipaq_close (struct usb_serial_port *port, struct file *filp);
+static int  ipaq_startup (struct usb_serial *serial);
+static void ipaq_shutdown (struct usb_serial *serial);
+static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+		       int count);
+static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+			   int count);
+static int ipaq_write_flush(struct usb_serial_port *port);
+static void ipaq_read_bulk_callback (struct urb *urb);
+static void ipaq_write_bulk_callback(struct urb *urb);
+static int ipaq_write_room(struct usb_serial_port *port);
+static int ipaq_chars_in_buffer(struct usb_serial_port *port);
+static void ipaq_destroy_lists(struct usb_serial_port *port);
+
+
+static __devinitdata struct usb_device_id ipaq_id_table [] = {
+	{ USB_DEVICE(IPAQ_VENDOR_ID, IPAQ_PRODUCT_ID) },
+	{ }					/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, ipaq_id_table);
+
+/* All of the device info needed for the Compaq iPAQ */
+struct usb_serial_device_type ipaq_device = {
+	owner:			THIS_MODULE,
+	name:			"Compaq iPAQ",
+	id_table:		ipaq_id_table,
+	num_interrupt_in:	0,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			ipaq_open,
+	close:			ipaq_close,
+	startup:		ipaq_startup,
+	shutdown:		ipaq_shutdown,
+	write:			ipaq_write,
+	write_room:		ipaq_write_room,
+	chars_in_buffer:	ipaq_chars_in_buffer,
+	read_bulk_callback:	ipaq_read_bulk_callback,
+	write_bulk_callback:	ipaq_write_bulk_callback,
+};
+
+static spinlock_t	write_list_lock;
+static int		bytes_in;
+static int		bytes_out;
+
+static int ipaq_open(struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial	*serial = port->serial;
+	struct ipaq_private	*priv;
+	struct ipaq_packet	*pkt;
+	int			i, result = 0;
+
+	if (port_paranoia_check(port, __FUNCTION__)) {
+		return -ENODEV;
+	}
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down(&port->sem);
+	
+	++port->open_count;
+	
+	if (port->open_count == 1) {
+		bytes_in = 0;
+		bytes_out = 0;
+		priv = (struct ipaq_private *)kmalloc(sizeof(struct ipaq_private), GFP_KERNEL);
+		if (priv == NULL) {
+			err(__FUNCTION__ " - Out of memory");
+			return -ENOMEM;
+		}
+		port->private = (void *)priv;
+		priv->active = 0;
+		priv->queue_len = 0;
+		INIT_LIST_HEAD(&priv->queue);
+		INIT_LIST_HEAD(&priv->freelist);
+
+		for (i = 0; i < URBDATA_QUEUE_MAX / PACKET_SIZE; i++) {
+			pkt = kmalloc(sizeof(struct ipaq_packet), GFP_KERNEL);
+			if (pkt == NULL) {
+				goto enomem;
+			}
+			pkt->data = kmalloc(PACKET_SIZE, GFP_KERNEL);
+			if (pkt->data == NULL) {
+				kfree(pkt);
+				goto enomem;
+			}
+			pkt->len = 0;
+			pkt->written = 0;
+			INIT_LIST_HEAD(&pkt->list);
+			list_add(&pkt->list, &priv->freelist);
+			priv->free_len += PACKET_SIZE;
+		}
+
+		/*
+		 * Force low latency on. This will immediately push data to the line
+		 * discipline instead of queueing.
+		 */
+
+		port->tty->low_latency = 1;
+
+		/*
+		 * Lose the small buffers usbserial provides. Make larger ones.
+		 */
+
+		kfree(port->bulk_in_buffer);
+		kfree(port->bulk_out_buffer);
+		port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+		if (port->bulk_in_buffer == NULL) {
+			goto enomem;
+		}
+		port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
+		if (port->bulk_out_buffer == NULL) {
+			kfree(port->bulk_in_buffer);
+			goto enomem;
+		}
+		port->read_urb->transfer_buffer = port->bulk_in_buffer;
+		port->write_urb->transfer_buffer = port->bulk_out_buffer;
+		port->read_urb->transfer_buffer_length = URBDATA_SIZE;
+		port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
+		
+		/* Start reading from the device */
+		FILL_BULK_URB(port->read_urb, serial->dev, 
+			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+			      ipaq_read_bulk_callback, port);
+		result = usb_submit_urb(port->read_urb);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+		}
+
+		/*
+		 * Send out two control messages observed in win98 sniffs. Not sure what
+		 * they do.
+		 */
+
+		result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+				0x1, 0, NULL, 0, 5 * HZ);
+		if (result < 0) {
+			err(__FUNCTION__ " - failed doing control urb, error %d", result);
+		}
+		result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
+				0x1, 0, NULL, 0, 5 * HZ);
+		if (result < 0) {
+			err(__FUNCTION__ " - failed doing control urb, error %d", result);
+		}
+	}
+	
+	up(&port->sem);
+	
+	return result;
+
+enomem:
+	ipaq_destroy_lists(port);
+	kfree(priv);
+	err(__FUNCTION__ " - Out of memory");
+	return -ENOMEM;
+}
+
+
+static void ipaq_close(struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial	*serial;
+	struct ipaq_private	*priv = port->private;
+
+	if (port_paranoia_check(port, __FUNCTION__)) {
+		return; 
+	}
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+			 
+	serial = get_usb_serial(port, __FUNCTION__);
+	if (!serial)
+		return;
+	
+	down (&port->sem);
+
+	--port->open_count;
+
+	if (port->open_count <= 0) {
+
+		/*
+		 * shut down bulk read and write
+		 */
+
+		usb_unlink_urb(port->write_urb);
+		usb_unlink_urb(port->read_urb);
+		ipaq_destroy_lists(port);
+		kfree(priv);
+		port->private = NULL;
+		port->open_count = 0;
+
+	}
+	up (&port->sem);
+
+	/* Uncomment the following line if you want to see some statistics in your syslog */
+	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
+}
+
+static void ipaq_read_bulk_callback(struct urb *urb)
+{
+	struct usb_serial_port	*port = (struct usb_serial_port *)urb->context;
+	struct usb_serial	*serial = get_usb_serial (port, __FUNCTION__);
+	struct tty_struct	*tty;
+	unsigned char		*data = urb->transfer_buffer;
+	int			i, result;
+
+	if (port_paranoia_check(port, __FUNCTION__))
+		return;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+	tty = port->tty;
+	if (urb->actual_length) {
+		for (i = 0; i < urb->actual_length ; ++i) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			/* this doesn't actually push the data through unless tty->low_latency is set */
+			tty_insert_flip_char(tty, data[i], 0);
+		}
+		tty_flip_buffer_push(tty);
+		bytes_in += urb->actual_length;
+	}
+
+	/* Continue trying to always read  */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      ipaq_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+	return;
+}
+
+static int ipaq_write(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+		       int count)
+{
+	const unsigned char	*current_position = buf;
+	int			bytes_sent = 0;
+	int			transfer_size;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	usb_serial_debug_data(__FILE__, __FUNCTION__, count, buf);
+	
+	while (count > 0) {
+		transfer_size = min(count, PACKET_SIZE);
+		if (ipaq_write_bulk(port, from_user, current_position, transfer_size)) {
+			break;
+		}
+		current_position += transfer_size;
+		bytes_sent += transfer_size;
+		count -= transfer_size;
+		bytes_out += transfer_size;
+	}
+
+	return bytes_sent;
+} 
+
+static int ipaq_write_bulk(struct usb_serial_port *port, int from_user, const unsigned char *buf,
+			   int count)
+{
+	struct ipaq_private	*priv = port->private;
+	struct ipaq_packet	*pkt = NULL;
+	int			result = 0;
+	unsigned long		flags;
+
+	if (priv->free_len <= 0) {
+		dbg(__FUNCTION__ " - we're stuffed");
+		return -EAGAIN;
+	}
+
+	spin_lock_irqsave(&write_list_lock, flags);
+	if (!list_empty(&priv->freelist)) {
+		pkt = list_entry(priv->freelist.next, struct ipaq_packet, list);
+		list_del(&pkt->list);
+		priv->free_len -= PACKET_SIZE;
+	}
+	spin_unlock_irqrestore(&write_list_lock, flags);
+	if (pkt == NULL) {
+		dbg(__FUNCTION__ " - we're stuffed");
+		return -EAGAIN;
+	}
+
+	if (from_user) {
+		copy_from_user(pkt->data, buf, count);
+	} else {
+		memcpy(pkt->data, buf, count);
+	}
+	usb_serial_debug_data(__FILE__, __FUNCTION__, count, pkt->data);
+
+	pkt->len = count;
+	pkt->written = 0;
+	spin_lock_irqsave(&write_list_lock, flags);
+	list_add_tail(&pkt->list, &priv->queue);
+	priv->queue_len += count;
+	if (priv->active == 0) {
+		priv->active = 1;
+		result = ipaq_write_flush(port);
+	}
+	spin_unlock_irqrestore(&write_list_lock, flags);
+	return result;
+}
+
+static int ipaq_write_flush(struct usb_serial_port *port)
+{
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+	struct usb_serial	*serial = port->serial;
+	int			count, room, result;
+	struct ipaq_packet	*pkt;
+	struct urb		*urb = port->write_urb;
+	struct list_head	*tmp;
+
+	if (urb->status == -EINPROGRESS) {
+		/* Should never happen */
+		err(__FUNCTION__ " - flushing while urb is active !");
+		return -EAGAIN;
+	}
+	room = URBDATA_SIZE;
+	for (tmp = priv->queue.next; tmp != &priv->queue;) {
+		pkt = list_entry(tmp, struct ipaq_packet, list);
+		tmp = tmp->next;
+		count = min(room, (int)(pkt->len - pkt->written));
+		memcpy(urb->transfer_buffer + (URBDATA_SIZE - room),
+		       pkt->data + pkt->written, count);
+		room -= count;
+		pkt->written += count;
+		priv->queue_len -= count;
+		if (pkt->written == pkt->len) {
+			list_del(&pkt->list);
+			list_add(&pkt->list, &priv->freelist);
+			priv->free_len += PACKET_SIZE;
+		}
+		if (room == 0) {
+			break;
+		}
+	}
+
+	count = URBDATA_SIZE - room;
+	FILL_BULK_URB(port->write_urb, serial->dev, 
+		      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+		      port->write_urb->transfer_buffer, count, ipaq_write_bulk_callback,
+		      port);
+	result = usb_submit_urb(urb);
+	if (result) {
+		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+	}
+	return result;
+}
+
+static void ipaq_write_bulk_callback(struct urb *urb)
+{
+	struct usb_serial_port	*port = (struct usb_serial_port *)urb->context;
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+	unsigned long		flags;
+
+	if (port_paranoia_check (port, __FUNCTION__)) {
+		return;
+	}
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+	}
+
+	spin_lock_irqsave(&write_list_lock, flags);
+	if (!list_empty(&priv->queue)) {
+		ipaq_write_flush(port);
+	} else {
+		priv->active = 0;
+	}
+	spin_unlock_irqrestore(&write_list_lock, flags);
+	queue_task(&port->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	
+	return;
+}
+
+static int ipaq_write_room(struct usb_serial_port *port)
+{
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+
+	dbg(__FUNCTION__ " - freelen %d", priv->free_len);
+	return priv->free_len;
+}
+
+static int ipaq_chars_in_buffer(struct usb_serial_port *port)
+{
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+
+	dbg(__FUNCTION__ " - queuelen %d", priv->queue_len);
+	return priv->queue_len;
+}
+
+static void ipaq_destroy_lists(struct usb_serial_port *port)
+{
+	struct ipaq_private	*priv = (struct ipaq_private *)port->private;
+	struct list_head	*tmp;
+	struct ipaq_packet	*pkt;
+
+	for (tmp = priv->queue.next; tmp != &priv->queue;) {
+		pkt = list_entry(tmp, struct ipaq_packet, list);
+		tmp = tmp->next;
+		kfree(pkt->data);
+		kfree(pkt);
+	}
+	for (tmp = priv->freelist.next; tmp != &priv->freelist;) {
+		pkt = list_entry(tmp, struct ipaq_packet, list);
+		tmp = tmp->next;
+		kfree(pkt->data);
+		kfree(pkt);
+	}
+	return;
+}
+
+
+static int ipaq_startup(struct usb_serial *serial)
+{
+	dbg(__FUNCTION__);
+	usb_set_configuration(serial->dev, 1);
+	return 0;
+}
+
+static void ipaq_shutdown(struct usb_serial *serial)
+{
+	int i;
+
+	dbg (__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			ipaq_close(&serial->port[i], NULL);
+		}
+	}
+}
+
+static int __init ipaq_init(void)
+{
+	usb_serial_register(&ipaq_device);
+	info(DRIVER_DESC " " DRIVER_VERSION);
+
+	return 0;
+}
+
+
+static void __exit ipaq_exit(void)
+{
+	usb_serial_deregister(&ipaq_device);
+}
+
+
+module_init(ipaq_init);
+module_exit(ipaq_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -urN linux-2.5.2-pre5/drivers/usb/serial/ipaq.h linux/drivers/usb/serial/ipaq.h
--- linux-2.5.2-pre5/drivers/usb/serial/ipaq.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/ipaq.h	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,60 @@
+/*
+ * USB Compaq iPAQ driver
+ *
+ *	Copyright (C) 2001
+ *	    Ganesh Varadarajan <ganesh@veritas.com>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ * 
+ */
+
+#ifndef __LINUX_USB_SERIAL_IPAQ_H
+#define __LINUX_USB_SERIAL_IPAQ_H
+
+
+#define IPAQ_VENDOR_ID			0x049f
+#define IPAQ_PRODUCT_ID			0x0003
+
+/*
+ * Since we can't queue our bulk write urbs (don't know why - it just
+ * doesn't work), we can send down only one write urb at a time. The simplistic
+ * approach taken by the generic usbserial driver will work, but it's not good
+ * for performance. Therefore, we buffer upto URBDATA_QUEUE_MAX bytes of write
+ * requests coming from the line discipline. This is done by chaining them
+ * in lists of struct ipaq_packet, each packet holding a maximum of
+ * PACKET_SIZE bytes.
+ *
+ * ipaq_write() can be called from bottom half context; hence we can't
+ * allocate memory for packets there. So we initialize a pool of packets at
+ * the first open and maintain a freelist.
+ *
+ * The value of PACKET_SIZE was empirically determined by
+ * checking the maximum write sizes sent down by the ppp ldisc.
+ * URBDATA_QUEUE_MAX is set to 64K, which is the maximum TCP window size
+ * supported by the iPAQ.
+ */
+
+struct ipaq_packet {
+	char			*data;
+	size_t			len;
+	size_t			written;
+	struct list_head	list;
+};
+
+struct ipaq_private {
+	int			active;
+	int			queue_len;
+	int			free_len;
+	struct list_head	queue;
+	struct list_head	freelist;
+};
+
+#define URBDATA_SIZE		4096
+#define URBDATA_QUEUE_MAX	(64 * 1024)
+#define PACKET_SIZE		256
+
+#endif
diff -urN linux-2.5.2-pre5/drivers/usb/serial/kl5kusb105.c linux/drivers/usb/serial/kl5kusb105.c
--- linux-2.5.2-pre5/drivers/usb/serial/kl5kusb105.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/kl5kusb105.c	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,1086 @@
+/*
+ * KLSI KL5KUSB105 chip RS232 converter driver
+ *
+ *   Copyright (C) 2001 Utz-Uwe Haus <haus@uuhaus.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ * All information about the device was acquired using SniffUSB ans snoopUSB
+ * on Windows98.
+ * It was written out of frustration with the PalmConnect USB Serial adapter
+ * sold by Palm Inc.
+ * Neither Palm, nor their contractor (MCCI) or their supplier (KLSI) provided
+ * information that was not already available.
+ *
+ * It seems that KLSI bought some silicon-design information from ScanLogic, 
+ * whose SL11R processor is at the core of the KL5KUSB chipset from KLSI.
+ * KLSI has firmware available for their devices; it is probable that the
+ * firmware differs from that used by KLSI in their products. If you have an
+ * original KLSI device and can provide some information on it, I would be 
+ * most interested in adding support for it here. If you have any information 
+ * on the protocol used (or find errors in my reverse-engineered stuff), please
+ * let me know.
+ *
+ * The code was only tested with a PalmConnect USB adapter; if you
+ * are adventurous, try it with any KLSI-based device and let me know how it
+ * breaks so that I can fix it!
+ */
+
+/* TODO:
+ *	check modem line signals
+ *	implement handshaking or decide that we do not support it
+ */
+
+/* History:
+ *   0.3a - implemented pools of write URBs
+ *   0.3  - alpha version for public testing
+ *   0.2  - TIOCMGET works, so autopilot(1) can be used!
+ *   0.1  - can be used to to pilot-xfer -p /dev/ttyUSB0 -l
+ *
+ *   The driver skeleton is mainly based on mct_u232.c and various other 
+ *   pieces of code shamelessly copied from the drivers/usb/serial/ directory.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ 	static int debug = 1;
+#else
+ 	static int debug;
+#endif
+
+#include "usb-serial.h"
+#include "kl5kusb105.h"
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v0.3a"
+#define DRIVER_AUTHOR "Utz-Uwe Haus <haus@uuhaus.de>"
+#define DRIVER_DESC "KLSI KL5KUSB105 chipset USB->Serial Converter driver"
+
+
+/*
+ * Function prototypes
+ */
+static int  klsi_105_startup	         (struct usb_serial *serial);
+static void klsi_105_shutdown	         (struct usb_serial *serial);
+static int  klsi_105_open	         (struct usb_serial_port *port,
+					  struct file *filp);
+static void klsi_105_close	         (struct usb_serial_port *port,
+					  struct file *filp);
+static int  klsi_105_write	         (struct usb_serial_port *port,
+					  int from_user,
+					  const unsigned char *buf,
+					  int count);
+static void klsi_105_write_bulk_callback (struct urb *urb);
+static int  klsi_105_chars_in_buffer     (struct usb_serial_port *port);
+static int  klsi_105_write_room          (struct usb_serial_port *port);
+
+static void klsi_105_read_bulk_callback  (struct urb *urb);
+static void klsi_105_set_termios         (struct usb_serial_port *port,
+					  struct termios * old);
+static int  klsi_105_ioctl	         (struct usb_serial_port *port,
+					  struct file * file,
+					  unsigned int cmd,
+					  unsigned long arg);
+static void klsi_105_throttle		 (struct usb_serial_port *port);
+static void klsi_105_unthrottle		 (struct usb_serial_port *port);
+/*
+static void klsi_105_break_ctl	         (struct usb_serial_port *port,
+					  int break_state );
+ */
+
+/*
+ * All of the device info needed for the KLSI converters.
+ */
+static __devinitdata struct usb_device_id id_table [] = {
+	{ USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
+	{ USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
+	{ }		/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+
+static struct usb_serial_device_type kl5kusb105d_device = {
+	owner:               THIS_MODULE,
+	name:		     "KL5KUSB105D / PalmConnect",
+	id_table:	     id_table,
+	num_interrupt_in:    1,
+	num_bulk_in:	     1,
+	num_bulk_out:	     1,
+	num_ports:	     1,
+	open:		     klsi_105_open,
+	close:		     klsi_105_close,
+	write:		     klsi_105_write,
+	write_bulk_callback: klsi_105_write_bulk_callback,
+	chars_in_buffer:     klsi_105_chars_in_buffer,
+	write_room:          klsi_105_write_room,
+	read_bulk_callback:  klsi_105_read_bulk_callback,
+	ioctl:		     klsi_105_ioctl,
+	set_termios:	     klsi_105_set_termios,
+	/*break_ctl:	     klsi_105_break_ctl,*/
+	startup:	     klsi_105_startup,
+	shutdown:	     klsi_105_shutdown,
+	throttle:	     klsi_105_throttle,
+	unthrottle:	     klsi_105_unthrottle,
+};
+
+struct klsi_105_port_settings {
+	__u8	pktlen;		/* always 5, it seems */
+	__u8	baudrate;
+	__u8	databits;
+	__u8	unknown1;
+	__u8	unknown2;
+} __attribute__ ((packed));
+
+/* we implement a pool of NUM_URBS urbs per usb_serial */
+#define NUM_URBS			1
+#define URB_TRANSFER_BUFFER_SIZE	64
+struct klsi_105_private {
+	struct klsi_105_port_settings	cfg;
+	struct termios			termios;
+	unsigned long			line_state; /* modem line settings */
+	/* write pool */
+	struct urb *			write_urb_pool[NUM_URBS];
+	spinlock_t			write_urb_pool_lock;
+	unsigned long			bytes_in;
+	unsigned long			bytes_out;
+};
+
+
+/*
+ * Handle vendor specific USB requests
+ */
+
+
+#define KLSI_TIMEOUT	 (HZ * 5 ) /* default urb timeout */
+
+static int klsi_105_chg_port_settings(struct usb_serial *serial,
+				      struct klsi_105_port_settings *settings)
+{
+	int rc;
+
+        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+			     KL5KUSB105A_SIO_SET_DATA,
+                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_INTERFACE,
+			     0, /* value */
+			     0, /* index */
+			     settings,
+			     sizeof(struct klsi_105_port_settings),
+			     KLSI_TIMEOUT);
+	if (rc < 0)
+		err("Change port settings failed (error = %d)", rc);
+	info(__FUNCTION__ " - %d byte block, baudrate %x, databits %d, u1 %d, u2 %d",
+	    settings->pktlen,
+	    settings->baudrate, settings->databits,
+	    settings->unknown1, settings->unknown2);
+        return rc;
+} /* klsi_105_chg_port_settings */
+
+/* translate a 16-bit status value from the device to linux's TIO bits */
+static unsigned long klsi_105_status2linestate(const __u16 status)
+{
+	unsigned long res = 0;
+
+	res =   ((status & KL5KUSB105A_DSR) ? TIOCM_DSR : 0)
+	      | ((status & KL5KUSB105A_CTS) ? TIOCM_CTS : 0)
+	      ;
+
+	return res;
+}
+/* 
+ * Read line control via vendor command and return result through
+ * *line_state_p 
+ */
+/* It seems that the status buffer has always only 2 bytes length */
+#define KLSI_STATUSBUF_LEN	2
+static int klsi_105_get_line_state(struct usb_serial *serial,
+				   unsigned long *line_state_p)
+{
+	int rc;
+	__u8 status_buf[KLSI_STATUSBUF_LEN] = { -1,-1};
+	__u16 status;
+
+	info(__FUNCTION__ " - sending SIO Poll request");
+        rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+			     KL5KUSB105A_SIO_POLL,
+                             USB_TYPE_VENDOR | USB_DIR_IN,
+			     0, /* value */
+			     0, /* index */
+			     status_buf, KLSI_STATUSBUF_LEN,
+			     10*HZ
+			     );
+	if (rc < 0)
+		err("Reading line status failed (error = %d)", rc);
+	else {
+		status = status_buf[0] + (status_buf[1]<<8);
+
+		info(__FUNCTION__ " - read status %x %x",
+		     status_buf[0], status_buf[1]);
+
+		*line_state_p = klsi_105_status2linestate(status);
+	}
+
+        return rc;
+}
+
+
+/*
+ * Driver's tty interface functions
+ */
+
+static int klsi_105_startup (struct usb_serial *serial)
+{
+	struct klsi_105_private *priv;
+	int i;
+
+	/* check if we support the product id (see keyspan.c)
+	 * FIXME
+	 */
+
+	/* allocate the private data structure */
+	for (i=0; i<serial->num_ports; i++) {
+		serial->port[i].private = kmalloc(sizeof(struct klsi_105_private),
+						   GFP_KERNEL);
+		if (!serial->port[i].private) {
+			dbg(__FUNCTION__ "kmalloc for klsi_105_private failed.");
+			return (-1); /* error */
+		}
+		priv = (struct klsi_105_private *)serial->port[i].private;
+		/* set initial values for control structures */
+		priv->cfg.pktlen    = 5;
+		priv->cfg.baudrate  = kl5kusb105a_sio_b9600;
+		priv->cfg.databits  = kl5kusb105a_dtb_8;
+		priv->cfg.unknown1  = 0;
+		priv->cfg.unknown2  = 1;
+
+		priv->line_state    = 0;
+
+		priv->bytes_in	    = 0;
+		priv->bytes_out	    = 0;
+
+		spin_lock_init (&priv->write_urb_pool_lock);
+		for (i=0; i<NUM_URBS; i++) {
+			struct urb* urb = usb_alloc_urb(0);
+
+			priv->write_urb_pool[i] = urb;
+			if (urb == NULL) {
+				err("No more urbs???");
+				continue;
+			}
+
+			urb->transfer_buffer = NULL;
+			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE,
+							GFP_KERNEL);
+			if (!urb->transfer_buffer) {
+				err (__FUNCTION__ 
+				     " - out of memory for urb buffers.");
+				continue;
+			}
+		}
+
+		/* priv->termios is left uninitalized until port opening */
+		init_waitqueue_head(&serial->port[i].write_wait);
+	}
+	
+	return (0);
+} /* klsi_105_startup */
+
+
+static void klsi_105_shutdown (struct usb_serial *serial)
+{
+	int i;
+	
+	dbg (__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		struct klsi_105_private *priv = 
+			(struct klsi_105_private*) serial->port[i].private;
+		unsigned long flags;
+		while (serial->port[i].open_count > 0) {
+			klsi_105_close (&serial->port[i], NULL);
+		}
+
+		if (priv) {
+			/* kill our write urb pool */
+			int j;
+			struct urb **write_urbs = priv->write_urb_pool;
+			spin_lock_irqsave(&priv->write_urb_pool_lock,flags);
+
+			for (j = 0; j < NUM_URBS; j++) {
+				if (write_urbs[j]) {
+					/* FIXME - uncomment the following
+					 * usb_unlink_urb call when the host
+					 * controllers get fixed to set
+					 * urb->dev = NULL after the urb is
+					 * finished.  Otherwise this call
+					 * oopses. */
+					/* usb_unlink_urb(write_urbs[j]); */
+					if (write_urbs[j]->transfer_buffer)
+						    kfree(write_urbs[j]->transfer_buffer);
+					usb_free_urb (write_urbs[j]);
+				}
+			}
+
+			spin_unlock_irqrestore (&priv->write_urb_pool_lock,
+					       	flags);
+
+			kfree(serial->port[i].private);
+		}
+	}
+} /* klsi_105_shutdown */
+
+static int  klsi_105_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
+	int retval = 0;
+
+	dbg(__FUNCTION__" port %d", port->number);
+
+	down (&port->sem);
+	
+	++port->open_count;
+
+	if (port->open_count == 1) {
+		int rc;
+		int i;
+		unsigned long line_state;
+
+		/* force low_latency on so that our tty_push actually forces
+		 * the data through
+		 * port->tty->low_latency = 1; */
+
+		/* Do a defined restart:
+		 * Set up sane default baud rate and send the 'READ_ON'
+		 * vendor command. 
+		 * FIXME: set modem line control (how?)
+		 * Then read the modem line control and store values in
+		 * priv->line_state.
+		 */
+		priv->cfg.pktlen   = 5;
+		priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+		priv->cfg.databits = kl5kusb105a_dtb_8;
+		priv->cfg.unknown1 = 0;
+		priv->cfg.unknown2 = 1;
+		klsi_105_chg_port_settings(serial, &(priv->cfg));
+		
+		/* set up termios structure */
+		priv->termios.c_iflag = port->tty->termios->c_iflag;
+		priv->termios.c_oflag = port->tty->termios->c_oflag;
+		priv->termios.c_cflag = port->tty->termios->c_cflag;
+		priv->termios.c_lflag = port->tty->termios->c_lflag;
+		for (i=0; i<NCCS; i++)
+			priv->termios.c_cc[i] = port->tty->termios->c_cc[i];
+
+
+		/* READ_ON and urb submission */
+		FILL_BULK_URB(port->read_urb, serial->dev, 
+			      usb_rcvbulkpipe(serial->dev,
+					      port->bulk_in_endpointAddress),
+			      port->read_urb->transfer_buffer,
+			      port->read_urb->transfer_buffer_length,
+			      klsi_105_read_bulk_callback,
+			      port);
+		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+		rc = usb_submit_urb(port->read_urb);
+		if (rc) {
+			err(__FUNCTION__ 
+			    " - failed submitting read urb, error %d", rc);
+			retval = rc;
+			goto exit;
+		}
+
+		rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev,0),
+				     KL5KUSB105A_SIO_CONFIGURE,
+				     USB_TYPE_VENDOR|USB_DIR_OUT|USB_RECIP_INTERFACE,
+				     KL5KUSB105A_SIO_CONFIGURE_READ_ON,
+				     0, /* index */
+				     NULL,
+				     0,
+				     KLSI_TIMEOUT);
+		if (rc < 0) {
+			err("Enabling read failed (error = %d)", rc);
+			retval = rc;
+		} else 
+			dbg(__FUNCTION__ " - enabled reading");
+
+		rc = klsi_105_get_line_state(serial, &line_state);
+		if (rc >= 0) {
+			priv->line_state = line_state;
+			dbg(__FUNCTION__ 
+			    " - read line state 0x%lx", line_state);
+			retval = 0;
+		} else
+			retval = rc;
+	}
+
+exit:
+	up (&port->sem);
+	
+	return retval;
+} /* klsi_105_open */
+
+
+static void klsi_105_close (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial;
+	struct klsi_105_private *priv 
+		= (struct klsi_105_private *)port->private;
+	dbg(__FUNCTION__" port %d", port->number);
+
+	serial = get_usb_serial (port, __FUNCTION__);
+
+	if(!serial)
+		return;
+
+	down (&port->sem);
+
+	--port->open_count;
+
+	if (port->open_count <= 0) {
+		/* send READ_OFF */
+		int rc = usb_control_msg(serial->dev,
+					 usb_sndctrlpipe(serial->dev, 0),
+					 KL5KUSB105A_SIO_CONFIGURE,
+					 USB_TYPE_VENDOR | USB_DIR_OUT,
+					 KL5KUSB105A_SIO_CONFIGURE_READ_OFF,
+					 0, /* index */
+					 NULL, 0,
+					 KLSI_TIMEOUT);
+		if (rc < 0)
+			    err("Disabling read failed (error = %d)", rc);
+
+		/* shutdown our bulk reads and writes */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		/* unlink our write pool */
+		/* FIXME */
+		/* wgg - do I need this? I think so. */
+		usb_unlink_urb (port->interrupt_in_urb);
+		port->open_count = 0;
+		info("kl5kusb105 port stats: %ld bytes in, %ld bytes out", priv->bytes_in, priv->bytes_out);
+	}
+	
+	up (&port->sem);
+} /* klsi_105_close */
+
+
+/* We need to write a complete 64-byte data block and encode the
+ * number actually sent in the first double-byte, LSB-order. That 
+ * leaves at most 62 bytes of payload.
+ */
+#define KLSI_105_DATA_OFFSET	2   /* in the bulk urb data block */
+
+
+static int klsi_105_write (struct usb_serial_port *port, int from_user,
+			   const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = 
+		(struct klsi_105_private*) port->private;
+	int result, size;
+	int bytes_sent=0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down (&port->sem);	/* to lock against someone else trying to
+				   take an URB we just selected from the pool */
+
+	while (count > 0) {
+		/* try to find a free urb (write 0 bytes if none) */
+		struct urb *urb = NULL;
+		unsigned long flags;
+		int i;
+		/* since the pool is per-port we might not need the spin lock !? */
+		spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+		for (i=0; i<NUM_URBS; i++) {
+			if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
+				urb = priv->write_urb_pool[i];
+				dbg(__FUNCTION__ " - using pool URB %d", i);
+				break;
+			}
+		}
+		spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+		if (urb==NULL) {
+			dbg (__FUNCTION__ " - no more free urbs");
+			goto exit;
+		}
+
+		if (urb->transfer_buffer == NULL) {
+			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+			if (urb->transfer_buffer == NULL) {
+				err(__FUNCTION__ " - no more kernel memory...");
+				goto exit;
+			}
+		}
+
+		size = min (count, port->bulk_out_size - KLSI_105_DATA_OFFSET);
+		size = min (size, URB_TRANSFER_BUFFER_SIZE - KLSI_105_DATA_OFFSET);
+
+		if (from_user) {
+			if (copy_from_user(urb->transfer_buffer
+					   + KLSI_105_DATA_OFFSET, buf, size)) {
+				up (&port->sem);
+				return -EFAULT;
+			}
+		} else {
+			memcpy (urb->transfer_buffer + KLSI_105_DATA_OFFSET,
+			       	buf, size);
+		}
+
+		/* write payload size into transfer buffer */
+		((__u8 *)urb->transfer_buffer)[0] = (__u8) (size & 0xFF);
+		((__u8 *)urb->transfer_buffer)[1] = (__u8) ((size & 0xFF00)>>8);
+
+		/* set up our urb */
+		FILL_BULK_URB(urb, serial->dev,
+			      usb_sndbulkpipe(serial->dev,
+					      port->bulk_out_endpointAddress),
+			      urb->transfer_buffer,
+			      URB_TRANSFER_BUFFER_SIZE,
+			      klsi_105_write_bulk_callback,
+			      port);
+		urb->transfer_flags |= USB_QUEUE_BULK;
+
+
+		/* send the data out the bulk port */
+		result = usb_submit_urb(urb);
+		if (result) {
+			err(__FUNCTION__
+			    " - failed submitting write urb, error %d", result);
+			goto exit;
+		}
+		buf += size;
+		bytes_sent += size;
+		count -= size;
+	}
+exit:
+	up (&port->sem);
+	priv->bytes_out+=bytes_sent;
+
+	return bytes_sent;	/* that's how much we wrote */
+} /* klsi_105_write */
+
+static void klsi_105_write_bulk_callback ( struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = port->serial;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d",
+		    urb->status);
+		return;
+	}
+
+	/* from generic_write_bulk_callback */
+	queue_task(&port->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	return;
+} /* klsi_105_write_bulk_completion_callback */
+
+
+/* return number of characters currently in the writing process */
+static int klsi_105_chars_in_buffer (struct usb_serial_port *port)
+{
+	int chars = 0;
+	int i;
+	unsigned long flags;
+	struct klsi_105_private *priv = 
+		(struct klsi_105_private*) port->private;
+
+	spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (priv->write_urb_pool[i]->status == -EINPROGRESS) {
+			chars += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+
+	spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+	dbg (__FUNCTION__ " - returns %d", chars);
+	return (chars);
+}
+
+static int klsi_105_write_room (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int room = 0;
+	struct klsi_105_private *priv = 
+		(struct klsi_105_private*) port->private;
+
+	spin_lock_irqsave (&priv->write_urb_pool_lock, flags);
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (priv->write_urb_pool[i]->status != -EINPROGRESS) {
+			room += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+
+	spin_unlock_irqrestore (&priv->write_urb_pool_lock, flags);
+
+	dbg(__FUNCTION__ " - returns %d", room);
+	return (room);
+}
+
+
+
+static void klsi_105_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = 
+		(struct klsi_105_private*) port->private;
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int rc;
+
+        dbg(__FUNCTION__ " - port %d", port->number);
+
+	/* The urb might have been killed. */
+        if (urb->status) {
+                dbg(__FUNCTION__ " - nonzero read bulk status received: %d",
+		    urb->status);
+                return;
+        }
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+	
+	/* The data received is again preceded by a length double-byte in LSB-
+	 * first order (see klsi_105_write() )
+	 */
+	if (urb->actual_length == 0) {
+		/* empty urbs seem to happen, we ignore them */
+		/* dbg(__FUNCTION__ " - emtpy URB"); */
+	       ;
+	} else if (urb->actual_length <= 2) {
+		dbg(__FUNCTION__ " - size %d URB not understood",
+		    urb->actual_length);
+		usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+	} else {
+		int i;
+		int bytes_sent = ((__u8 *) data)[0] +
+				 ((unsigned int) ((__u8 *) data)[1] << 8);
+		tty = port->tty;
+		/* we should immediately resubmit the URB, before attempting
+		 * to pass the data on to the tty layer. But that needs locking
+		 * against re-entry an then mixed-up data because of
+		 * intermixed tty_flip_buffer_push()s
+		 * FIXME
+		 */ 
+		usb_serial_debug_data (__FILE__, __FUNCTION__,
+				       urb->actual_length, data);
+
+		if (bytes_sent + 2 > urb->actual_length) {
+			dbg(__FUNCTION__ 
+			    " - trying to read more data than available"
+			    " (%d vs. %d)",
+			    bytes_sent+2, urb->actual_length);
+			/* cap at implied limit */
+			bytes_sent = urb->actual_length - 2;
+		}
+
+		for (i = 2; i < 2+bytes_sent; i++) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters,
+			 * we drop them. */
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			/* this doesn't actually push the data through unless 
+			 * tty->low_latency is set */
+			tty_insert_flip_char(tty, ((__u8*) data)[i], 0);
+		}
+		tty_flip_buffer_push(tty);
+		priv->bytes_in += bytes_sent;
+	}
+	/* Continue trying to always read  */
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev,
+				      port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer,
+		      port->read_urb->transfer_buffer_length,
+		      klsi_105_read_bulk_callback,
+		      port);
+	rc = usb_submit_urb(port->read_urb);
+	if (rc)
+		err(__FUNCTION__ 
+		    " - failed resubmitting read urb, error %d", rc);
+} /* klsi_105_read_bulk_callback */
+
+
+static void klsi_105_set_termios (struct usb_serial_port *port,
+				  struct termios *old_termios)
+{
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
+	unsigned int iflag = port->tty->termios->c_iflag;
+	unsigned int old_iflag = old_termios->c_iflag;
+	unsigned int cflag = port->tty->termios->c_cflag;
+	unsigned int old_cflag = old_termios->c_cflag;
+	
+	/*
+	 * Update baud rate
+	 */
+	if( (cflag & CBAUD) != (old_cflag & CBAUD) ) {
+	        /* reassert DTR and (maybe) RTS on transition from B0 */
+		if( (old_cflag & CBAUD) == B0 ) {
+			dbg(__FUNCTION__ ": baud was B0");
+#if 0
+			priv->control_state |= TIOCM_DTR;
+			/* don't set RTS if using hardware flow control */
+			if (!(old_cflag & CRTSCTS)) {
+				priv->control_state |= TIOCM_RTS;
+			}
+			mct_u232_set_modem_ctrl(serial, priv->control_state);
+#endif
+		}
+		
+		switch(cflag & CBAUD) {
+		case B0: /* handled below */
+			break;
+		case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+			break;
+		case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+			break;
+		case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+			break;
+		case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+			break;
+		case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+			break;
+		case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+			break;
+		case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+			break;
+		case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+			break;
+		default:
+			err("KLSI USB->Serial converter:"
+			    " unsupported baudrate request, using default"
+			    " of 9600");
+			priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+			break;
+		}
+		if ((cflag & CBAUD) == B0 ) {
+			dbg(__FUNCTION__ ": baud is B0");
+			/* Drop RTS and DTR */
+			/* maybe this should be simulated by sending read
+			 * disable and read enable messages?
+			 */
+			;
+#if 0
+			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+        		mct_u232_set_modem_ctrl(serial, priv->control_state);
+#endif
+		}
+	}
+
+	if ((cflag & CSIZE) != (old_cflag & CSIZE)) {
+		/* set the number of data bits */
+		switch (cflag & CSIZE) {
+		case CS5:
+			dbg(__FUNCTION__ " - 5 bits/byte not supported");
+			return ;
+		case CS6:
+			dbg(__FUNCTION__ " - 6 bits/byte not supported");
+			return ;
+		case CS7:
+			priv->cfg.databits = kl5kusb105a_dtb_7;
+			break;
+		case CS8:
+			priv->cfg.databits = kl5kusb105a_dtb_8;
+			break;
+		default:
+			err("CSIZE was not CS5-CS8, using default of 8");
+			priv->cfg.databits = kl5kusb105a_dtb_8;
+			break;
+		}
+	}
+
+	/*
+	 * Update line control register (LCR)
+	 */
+	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
+	    || (cflag & CSTOPB) != (old_cflag & CSTOPB) ) {
+		
+#if 0
+		priv->last_lcr = 0;
+
+		/* set the parity */
+		if (cflag & PARENB)
+			priv->last_lcr |= (cflag & PARODD) ?
+				MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
+		else
+			priv->last_lcr |= MCT_U232_PARITY_NONE;
+
+		/* set the number of stop bits */
+		priv->last_lcr |= (cflag & CSTOPB) ?
+			MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
+
+		mct_u232_set_line_ctrl(serial, priv->last_lcr);
+#endif
+		;
+	}
+	
+	/*
+	 * Set flow control: well, I do not really now how to handle DTR/RTS.
+	 * Just do what we have seen with SniffUSB on Win98.
+	 */
+	if( (iflag & IXOFF) != (old_iflag & IXOFF)
+	    || (iflag & IXON) != (old_iflag & IXON)
+	    ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS) ) {
+		
+		/* Drop DTR/RTS if no flow control otherwise assert */
+#if 0
+		if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) )
+			priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+		else
+			priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+		mct_u232_set_modem_ctrl(serial, priv->control_state);
+#endif
+		;
+	}
+
+	/* now commit changes to device */
+	klsi_105_chg_port_settings(serial, &(priv->cfg));
+} /* klsi_105_set_termios */
+
+
+#if 0
+static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
+{
+	struct usb_serial *serial = port->serial;
+	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+	unsigned char lcr = priv->last_lcr;
+
+	dbg (__FUNCTION__ "state=%d", break_state);
+
+	if (break_state)
+		lcr |= MCT_U232_SET_BREAK;
+
+	mct_u232_set_line_ctrl(serial, lcr);
+} /* mct_u232_break_ctl */
+#endif
+
+static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file,
+			   unsigned int cmd, unsigned long arg)
+{
+	struct usb_serial *serial = port->serial;
+	struct klsi_105_private *priv = (struct klsi_105_private *)port->private;
+	int mask;
+	
+	dbg (__FUNCTION__ "cmd=0x%x", cmd);
+
+	/* Based on code from acm.c and others */
+	switch (cmd) {
+	case TIOCMGET: {
+		int rc;
+		unsigned long line_state;
+		dbg (__FUNCTION__ " - TIOCMGET request, just guessing");
+
+		rc = klsi_105_get_line_state(serial, &line_state);
+		if (rc < 0) {
+			err("Reading line control failed (error = %d)", rc);
+			/* better return value? EAGAIN? */
+			return -ENOIOCTLCMD;
+		} else {
+			priv->line_state = line_state;
+			dbg(__FUNCTION__ " - read line state 0x%lx", line_state);
+		}
+		return put_user(priv->line_state, (unsigned long *) arg); 
+	       };
+
+	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+		if (get_user(mask, (unsigned long *) arg))
+			return -EFAULT;
+
+		if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
+			/* RTS needs set */
+			if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
+			    (cmd == TIOCMBIS) )
+				dbg (__FUNCTION__ " - set RTS not handled");
+				/* priv->control_state |=  TIOCM_RTS; */
+			else
+				dbg (__FUNCTION__ " - clear RTS not handled");
+				/* priv->control_state &= ~TIOCM_RTS; */
+		}
+
+		if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
+			/* DTR needs set */
+			if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
+			    (cmd == TIOCMBIS) )
+				dbg (__FUNCTION__ " - set DTR not handled");
+			/*	priv->control_state |=  TIOCM_DTR; */
+			else
+				dbg (__FUNCTION__ " - clear DTR not handled");
+				/* priv->control_state &= ~TIOCM_DTR; */
+		}
+		/*
+		mct_u232_set_modem_ctrl(serial, priv->control_state);
+		*/
+		break;
+					
+	case TIOCMIWAIT:
+		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+		/* TODO */
+		dbg (__FUNCTION__ " - TIOCMIWAIT not handled");
+		return -ENOIOCTLCMD;
+
+	case TIOCGICOUNT:
+		/* return count of modemline transitions */
+		/* TODO */
+		dbg (__FUNCTION__ " - TIOCGICOUNT not handled");
+		return -ENOIOCTLCMD;
+	case TCGETS: {
+	     /* return current info to caller */
+	     int retval;
+
+	     dbg (__FUNCTION__ " - TCGETS data faked/incomplete");
+
+	     retval = verify_area(VERIFY_WRITE, (void *)arg,
+				  sizeof(struct termios));
+
+	     if (retval)
+			 return(retval);
+
+	     kernel_termios_to_user_termios((struct termios *)arg,  
+					    &priv->termios);
+	     return(0);
+	     }
+	case TCSETS: {
+		/* set port termios to the one given by the user */
+		int retval;
+
+		dbg (__FUNCTION__ " - TCSETS not handled");
+
+		retval = verify_area(VERIFY_READ, (void *)arg,
+				     sizeof(struct termios));
+
+		if (retval)
+			    return(retval);
+
+		user_termios_to_kernel_termios(&priv->termios,
+					       (struct termios *)arg);
+		klsi_105_set_termios(port, &priv->termios);
+		return(0);
+	     }
+	case TCSETSW: {
+		/* set port termios and try to wait for completion of last
+		 * write operation */
+		/* We guess here. If there are not too many write urbs
+		 * outstanding, we lie. */
+		/* what is the right way to wait here? schedule() ? */
+	        /*
+		while (klsi_105_chars_in_buffer(port) > (NUM_URBS / 4 ) * URB_TRANSFER_BUFFER_SIZE)
+			    schedule();
+		 */
+		return -ENOIOCTLCMD;
+		      }
+	default:
+		dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd);
+		return(-ENOIOCTLCMD);
+		break;
+	}
+	return 0;
+} /* klsi_105_ioctl */
+
+static void klsi_105_throttle (struct usb_serial_port *port)
+{
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down (&port->sem);
+
+	usb_unlink_urb (port->read_urb);
+
+	up (&port->sem);
+
+	return;
+}
+static void klsi_105_unthrottle (struct usb_serial_port *port)
+{
+	int result;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	down (&port->sem);
+
+	port->read_urb->dev = port->serial->dev;
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err(__FUNCTION__ " - failed submitting read urb, error %d",
+		    result);
+
+	up (&port->sem);
+
+	return;
+}
+
+
+
+static int __init klsi_105_init (void)
+{
+	usb_serial_register (&kl5kusb105d_device);
+
+	info(DRIVER_DESC " " DRIVER_VERSION);
+	return 0;
+}
+
+
+static void __exit klsi_105_exit (void)
+{
+	usb_serial_deregister (&kl5kusb105d_device);
+}
+
+
+module_init (klsi_105_init);
+module_exit (klsi_105_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL"); 
+
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "enable extensive debugging messages");
+/* FIXME: implement
+MODULE_PARM(num_urbs, "i");
+MODULE_PARM_DESC(num_urbs, "number of URBs to use in write pool");
+*/
+
+/* vim: set sts=8 ts=8 sw=8: */
diff -urN linux-2.5.2-pre5/drivers/usb/serial/kl5kusb105.h linux/drivers/usb/serial/kl5kusb105.h
--- linux-2.5.2-pre5/drivers/usb/serial/kl5kusb105.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/serial/kl5kusb105.h	Tue Jan  1 14:04:28 2002
@@ -0,0 +1,69 @@
+/*
+ * Definitions for the KLSI KL5KUSB105 serial port adapter
+ */
+
+/* vendor/product pairs that are known to contain this chipset */
+#define PALMCONNECT_VID		0x0830
+#define PALMCONNECT_PID		0x0080
+
+#define KLSI_VID		0x05e9
+#define KLSI_KL5KUSB105D_PID	0x00c0
+
+/* Vendor commands: */
+
+
+/* port table -- the chip supports up to 4 channels */
+
+/* baud rates */
+
+typedef enum {
+  kl5kusb105a_sio_b115200 = 0,
+  kl5kusb105a_sio_b57600  = 1,
+  kl5kusb105a_sio_b38400  = 2,
+  kl5kusb105a_sio_b19200  = 4,
+  kl5kusb105a_sio_b14400  = 5,
+  kl5kusb105a_sio_b9600   = 6,
+  kl5kusb105a_sio_b4800   = 8,   /* unchecked */
+  kl5kusb105a_sio_b2400   = 9,   /* unchecked */
+  kl5kusb105a_sio_b1200   = 0xa,  /* unchecked */
+  kl5kusb105a_sio_b600    = 0xb   /* unchecked */
+} KL5KUSB105A_SIO_baudrate_t;
+
+/* data bits */
+#define kl5kusb105a_dtb_7   7
+#define kl5kusb105a_dtb_8   8
+
+
+
+/* requests: */
+#define KL5KUSB105A_SIO_SET_DATA  1
+#define KL5KUSB105A_SIO_POLL      2
+#define KL5KUSB105A_SIO_CONFIGURE      3
+/* values used for request KL5KUSB105A_SIO_CONFIGURE */
+#define KL5KUSB105A_SIO_CONFIGURE_READ_ON      3
+#define KL5KUSB105A_SIO_CONFIGURE_READ_OFF     2
+
+/* Interpretation of modem status lines */
+/* These need sorting out by individually connecting pins and checking
+ * results. FIXME!
+ * When data is being sent we see 0x30 in the lower byte; this must
+ * contain DSR and CTS ...
+ */
+#define KL5KUSB105A_DSR			((1<<4) | (1<<5))
+#define KL5KUSB105A_CTS			((1<<5) | (1<<4))
+
+#define KL5KUSB105A_WANTS_TO_SEND	0x30
+//#define KL5KUSB105A_DTR			/* Data Terminal Ready */
+//#define KL5KUSB105A_CTS			/* Clear To Send */
+//#define KL5KUSB105A_CD			/* Carrier Detect */
+//#define KL5KUSB105A_DSR			/* Data Set Ready */
+//#define KL5KUSB105A_RxD			/* Receive pin */
+
+//#define KL5KUSB105A_LE
+//#define KL5KUSB105A_RTS		
+//#define KL5KUSB105A_ST		
+//#define KL5KUSB105A_SR		
+//#define KL5KUSB105A_RI			/* Ring Indicator */
+
+/* vim: set ts=8 sts=8: */
+
diff -urN linux-2.5.2-pre5/drivers/usb/usb-debug.c linux/drivers/usb/usb-debug.c
--- linux-2.5.2-pre5/drivers/usb/usb-debug.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/usb/usb-debug.c	Tue Jan  1 14:04:28 2002
@@ -181,23 +181,23 @@
 	kfree(buf);
 }
 
-void usb_dump_urb (purb_t purb)
+void usb_dump_urb (struct urb *urb)
 {
-	printk ("urb                   :%p\n", purb);
-	printk ("next                  :%p\n", purb->next);
-	printk ("dev                   :%p\n", purb->dev);
-	printk ("pipe                  :%08X\n", purb->pipe);
-	printk ("status                :%d\n", purb->status);
-	printk ("transfer_flags        :%08X\n", purb->transfer_flags);
-	printk ("transfer_buffer       :%p\n", purb->transfer_buffer);
-	printk ("transfer_buffer_length:%d\n", purb->transfer_buffer_length);
-	printk ("actual_length         :%d\n", purb->actual_length);
-	printk ("setup_packet          :%p\n", purb->setup_packet);
-	printk ("start_frame           :%d\n", purb->start_frame);
-	printk ("number_of_packets     :%d\n", purb->number_of_packets);
-	printk ("interval              :%d\n", purb->interval);
-	printk ("error_count           :%d\n", purb->error_count);
-	printk ("context               :%p\n", purb->context);
-	printk ("complete              :%p\n", purb->complete);
+	printk ("urb                   :%p\n", urb);
+	printk ("next                  :%p\n", urb->next);
+	printk ("dev                   :%p\n", urb->dev);
+	printk ("pipe                  :%08X\n", urb->pipe);
+	printk ("status                :%d\n", urb->status);
+	printk ("transfer_flags        :%08X\n", urb->transfer_flags);
+	printk ("transfer_buffer       :%p\n", urb->transfer_buffer);
+	printk ("transfer_buffer_length:%d\n", urb->transfer_buffer_length);
+	printk ("actual_length         :%d\n", urb->actual_length);
+	printk ("setup_packet          :%p\n", urb->setup_packet);
+	printk ("start_frame           :%d\n", urb->start_frame);
+	printk ("number_of_packets     :%d\n", urb->number_of_packets);
+	printk ("interval              :%d\n", urb->interval);
+	printk ("error_count           :%d\n", urb->error_count);
+	printk ("context               :%p\n", urb->context);
+	printk ("complete              :%p\n", urb->complete);
 }
 
diff -urN linux-2.5.2-pre5/drivers/usb/usb.c linux/drivers/usb/usb.c
--- linux-2.5.2-pre5/drivers/usb/usb.c	Sat Dec  8 20:28:45 2001
+++ linux/drivers/usb/usb.c	Tue Jan  1 14:04:28 2002
@@ -97,6 +97,8 @@
 
 	usb_scan_devices();
 
+	usbfs_update_special();
+
 	return 0;
 }
 
@@ -192,6 +194,8 @@
 		usb_drivers_purge(driver, bus->root_hub);
 	}
 	up (&usb_bus_list_lock);
+
+	usbfs_update_special();
 }
 
 /**
@@ -421,7 +425,6 @@
 	bus->bandwidth_isoc_reqs = 0;
 
 	INIT_LIST_HEAD(&bus->bus_list);
-	INIT_LIST_HEAD(&bus->inodes);
 
 	atomic_set(&bus->refcnt, 1);
 
@@ -468,7 +471,7 @@
 	list_add(&bus->bus_list, &usb_bus_list);
 	up (&usb_bus_list_lock);
 
-	usbdevfs_add_bus(bus);
+	usbfs_add_bus(bus);
 
 	info("new USB bus registered, assigned bus number %d", bus->busnum);
 }
@@ -494,7 +497,7 @@
 	list_del(&bus->bus_list);
 	up (&usb_bus_list_lock);
 
-	usbdevfs_remove_bus(bus);
+	usbfs_remove_bus(bus);
 
 	clear_bit(bus->busnum, busmap.busmap);
 
@@ -923,7 +926,7 @@
 
 		/* a simple/common case: one config, one interface, one driver
 		 * with current altsetting being a reasonable setting.
-		 * everything needs a smart agent and usbdevfs; or can rely on
+		 * everything needs a smart agent and usbfs; or can rely on
 		 * device-specific binding policies.
 		 */
 		envp [i++] = scratch;
@@ -1013,10 +1016,11 @@
 
 	usb_bus_get(bus);
 
+	if (!parent)
+		dev->devpath [0] = '/';
 	dev->bus = bus;
 	dev->parent = parent;
 	atomic_set(&dev->refcnt, 1);
-	INIT_LIST_HEAD(&dev->inodes);
 	INIT_LIST_HEAD(&dev->filelist);
 
 	init_MUTEX(&dev->serialize);
@@ -1906,7 +1910,7 @@
 	/* Free the device number and remove the /proc/bus/usb entry */
 	if (dev->devnum > 0) {
 		clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
-		usbdevfs_remove_device(dev);
+		usbfs_remove_device(dev);
 	}
 
 	/* Free up the device itself */
@@ -2579,7 +2583,7 @@
 #endif
 
 	/* now that the basic setup is over, add a /proc/bus/usb entry */
-	usbdevfs_add_device(dev);
+	usbfs_add_device(dev);
 
 	/* find drivers willing to handle this device */
 	usb_find_drivers(dev);
@@ -2592,7 +2596,7 @@
 
 static int usb_open(struct inode * inode, struct file * file)
 {
-	int minor = MINOR(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct usb_driver *c = usb_minors[minor/16];
 	int err = -ENODEV;
 	struct file_operations *old_fops, *new_fops = NULL;
@@ -2660,7 +2664,7 @@
 {
 	init_MUTEX(&usb_bus_list_lock);
 	usb_major_init();
-	usbdevfs_init();
+	usbfs_init();
 	usb_hub_init();
 
 	return 0;
@@ -2672,7 +2676,7 @@
 static void __exit usb_exit(void)
 {
 	usb_major_cleanup();
-	usbdevfs_cleanup();
+	usbfs_cleanup();
 	usb_hub_cleanup();
 }
 
diff -urN linux-2.5.2-pre5/fs/autofs4/inode.c linux/fs/autofs4/inode.c
--- linux-2.5.2-pre5/fs/autofs4/inode.c	Fri Nov  9 14:11:14 2001
+++ linux/fs/autofs4/inode.c	Tue Jan  1 14:04:28 2002
@@ -308,7 +308,7 @@
 	}
 	inode->i_blksize = PAGE_CACHE_SIZE;
 	inode->i_blocks = 0;
-	inode->i_rdev = 0;
+	inode->i_rdev = NODEV;
 	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 
 	if (S_ISDIR(inf->mode)) {
diff -urN linux-2.5.2-pre5/fs/block_dev.c linux/fs/block_dev.c
--- linux-2.5.2-pre5/fs/block_dev.c	Tue Jan  1 14:04:25 2002
+++ linux/fs/block_dev.c	Tue Jan  1 14:04:28 2002
@@ -27,10 +27,10 @@
 static unsigned long max_block(kdev_t dev)
 {
 	unsigned int retval = ~0U;
-	int major = MAJOR(dev);
+	int major = major(dev);
 
 	if (blk_size[major]) {
-		int minor = MINOR(dev);
+		int minor = minor(dev);
 		unsigned int blocks = blk_size[major][minor];
 		if (blocks) {
 			unsigned int size = block_size(dev);
@@ -47,10 +47,10 @@
 static loff_t blkdev_size(kdev_t dev)
 {
 	unsigned int blocks = ~0U;
-	int major = MAJOR(dev);
+	int major = major(dev);
 
 	if (blk_size[major]) {
-		int minor = MINOR(dev);
+		int minor = minor(dev);
 		blocks = blk_size[major][minor];
 	}
 	return (loff_t) blocks << BLOCK_SIZE_BITS;
@@ -77,25 +77,25 @@
 		return -EINVAL;
 
 	/* No blocksize array? Implies hardcoded BLOCK_SIZE */
-	if (!blksize_size[MAJOR(dev)]) {
+	if (!blksize_size[major(dev)]) {
 		if (size == BLOCK_SIZE)
 			return 0;
 		return -EINVAL;
 	}
 
-	oldsize = blksize_size[MAJOR(dev)][MINOR(dev)];
+	oldsize = blksize_size[major(dev)][minor(dev)];
 	if (oldsize == size)
 		return 0;
 
 	if (!oldsize && size == BLOCK_SIZE) {
-		blksize_size[MAJOR(dev)][MINOR(dev)] = size;
+		blksize_size[major(dev)][minor(dev)] = size;
 		return 0;
 	}
 
 	/* Ok, we're actually changing the blocksize.. */
-	bdev = bdget(dev);
+	bdev = bdget(kdev_t_to_nr(dev));
 	sync_buffers(dev, 2);
-	blksize_size[MAJOR(dev)][MINOR(dev)] = size;
+	blksize_size[major(dev)][minor(dev)] = size;
 	bdev->bd_inode->i_blkbits = blksize_bits(size);
 	kill_bdev(bdev);
 	bdput(bdev);
@@ -511,13 +511,13 @@
 	int i;
 	const struct block_device_operations * bdops = NULL;
 
-	i = MAJOR(dev);
+	i = major(dev);
 	if (i < MAX_BLKDEV)
 		bdops = blkdevs[i].bdops;
 	if (bdops == NULL) {
 		devfs_handle_t de;
 
-		de = devfs_find_handle (NULL, NULL, i, MINOR (dev),
+		de = devfs_find_handle (NULL, NULL, i, minor(dev),
 					DEVFS_SPECIAL_BLK, 0);
 		if (de) {
 			bdops = devfs_get_ops (de);
@@ -563,7 +563,7 @@
 	down(&bdev->bd_sem);
 	lock_kernel();
 	if (!bdev->bd_op)
-		bdev->bd_op = get_blkfops(MAJOR(dev));
+		bdev->bd_op = get_blkfops(major(dev));
 	if (bdev->bd_op) {
 		ret = 0;
 		if (bdev->bd_op->owner)
@@ -686,11 +686,11 @@
 const char * bdevname(kdev_t dev)
 {
 	static char buffer[32];
-	const char * name = blkdevs[MAJOR(dev)].name;
+	const char * name = blkdevs[major(dev)].name;
 
 	if (!name)
 		name = "unknown-block";
 
-	sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
+	sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev));
 	return buffer;
 }
diff -urN linux-2.5.2-pre5/fs/buffer.c linux/fs/buffer.c
--- linux-2.5.2-pre5/fs/buffer.c	Tue Jan  1 14:04:25 2002
+++ linux/fs/buffer.c	Tue Jan  1 14:04:28 2002
@@ -203,7 +203,7 @@
 		struct buffer_head * bh = next;
 		next = bh->b_next_free;
 
-		if (dev && bh->b_dev != dev)
+		if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev))
 			continue;
 		if (test_and_set_bit(BH_Lock, &bh->b_state))
 			continue;
@@ -261,7 +261,7 @@
 				__refile_buffer(bh);
 			continue;
 		}
-		if (dev && bh->b_dev != dev)
+		if (!kdev_none(dev) && !kdev_same(bh->b_dev, dev))
 			continue;
 
 		get_bh(bh);
@@ -346,7 +346,7 @@
 
 	lock_kernel();
 	sync_inodes(dev);
-	if (dev) {
+	if (!kdev_none(dev)) {
 		struct super_block *sb = get_super(dev);
 		if (sb) {
 			DQUOT_SYNC(sb);
@@ -371,7 +371,7 @@
 
 asmlinkage long sys_sync(void)
 {
-	fsync_dev(0);
+	fsync_dev(NODEV);
 	return 0;
 }
 
@@ -571,7 +571,7 @@
 			continue;
 		if (bh->b_size != size)
 			continue;
-		if (bh->b_dev != dev)
+		if (!kdev_same(bh->b_dev, dev))
 			continue;
 		get_bh(bh);
 		break;
@@ -675,7 +675,7 @@
 			bh_next = bh->b_next_free;
 
 			/* Another device? */
-			if (bh->b_dev != dev)
+			if (!kdev_same(bh->b_dev, dev))
 				continue;
 			/* Not hashed? */
 			if (!bh->b_pprev)
@@ -718,7 +718,7 @@
 
 void __invalidate_buffers(kdev_t dev, int destroy_dirty_buffers)
 {
-	struct block_device *bdev = bdget(dev);
+	struct block_device *bdev = bdget(kdev_t_to_nr(dev));
 	if (bdev) {
 		invalidate_bdev(bdev, destroy_dirty_buffers);
 		bdput(bdev);
@@ -2396,7 +2396,7 @@
 		struct buffer_head * p = tmp;
 		tmp = tmp->b_this_page;
 
-		if (p->b_dev == B_FREE) BUG();
+		if (kdev_same(p->b_dev, B_FREE)) BUG();
 
 		remove_inode_queue(p);
 		__remove_from_queues(p);
@@ -2562,7 +2562,7 @@
 {
 	lock_kernel();
 	sync_unlocked_inodes();
-	sync_supers(0);
+	sync_supers(NODEV);
 	unlock_kernel();
 
 	for (;;) {
diff -urN linux-2.5.2-pre5/fs/devices.c linux/fs/devices.c
--- linux-2.5.2-pre5/fs/devices.c	Sat Sep 22 20:35:43 2001
+++ linux/fs/devices.c	Tue Jan  1 14:04:28 2002
@@ -27,7 +27,7 @@
 /* serial module kmod load support */
 struct tty_driver *get_tty_driver(kdev_t device);
 #define isa_tty_dev(ma)	(ma == TTY_MAJOR || ma == TTYAUX_MAJOR)
-#define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL)
+#define need_serial(ma,mi) (get_tty_driver(mk_kdev(ma,mi)) == NULL)
 #endif
 
 struct device_struct {
@@ -145,7 +145,7 @@
 {
 	int ret = -ENODEV;
 
-	filp->f_op = get_chrfops(MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
+	filp->f_op = get_chrfops(major(inode->i_rdev), minor(inode->i_rdev));
 	if (filp->f_op) {
 		ret = 0;
 		if (filp->f_op->open != NULL) {
@@ -173,18 +173,18 @@
 const char * kdevname(kdev_t dev)
 {
 	static char buffer[32];
-	sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
+	sprintf(buffer, "%02x:%02x", major(dev), minor(dev));
 	return buffer;
 }
 
 const char * cdevname(kdev_t dev)
 {
 	static char buffer[32];
-	const char * name = chrdevs[MAJOR(dev)].name;
+	const char * name = chrdevs[major(dev)].name;
 
 	if (!name)
 		name = "unknown-char";
-	sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
+	sprintf(buffer, "%s(%d,%d)", name, major(dev), minor(dev));
 	return buffer;
 }
   
diff -urN linux-2.5.2-pre5/fs/inode.c linux/fs/inode.c
--- linux-2.5.2-pre5/fs/inode.c	Mon Dec 10 14:13:25 2001
+++ linux/fs/inode.c	Tue Jan  1 14:04:28 2002
@@ -382,7 +382,7 @@
 	/*
 	 * Search the super_blocks array for the device(s) to sync.
 	 */
-	if (dev) {
+	if (!kdev_none(dev)) {
 		if ((s = get_super(dev)) != NULL) {
 			sync_inodes_sb(s);
 			drop_super(s);
@@ -826,7 +826,7 @@
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
 		inode->i_sb = NULL;
-		inode->i_dev = 0;
+		inode->i_dev = NODEV;
 		inode->i_blkbits = 0;
 		inode->i_ino = ++last_ino;
 		inode->i_flags = 0;
diff -urN linux-2.5.2-pre5/fs/isofs/rock.c linux/fs/isofs/rock.c
--- linux-2.5.2-pre5/fs/isofs/rock.c	Sun Dec 16 12:23:05 2001
+++ linux/fs/isofs/rock.c	Tue Jan  1 14:04:28 2002
@@ -297,9 +297,9 @@
 	   * stored in the low field, and use that.
 	   */
 	  if((low & ~0xff) && high == 0) {
-	    inode->i_rdev = MKDEV(low >> 8, low & 0xff);
+	    inode->i_rdev = mk_kdev(low >> 8, low & 0xff);
 	  } else {
-	    inode->i_rdev = MKDEV(high, low);
+	    inode->i_rdev = mk_kdev(high, low);
 	  }
 	}
 	break;
diff -urN linux-2.5.2-pre5/fs/lockd/svclock.c linux/fs/lockd/svclock.c
--- linux-2.5.2-pre5/fs/lockd/svclock.c	Thu Oct 11 07:52:18 2001
+++ linux/fs/lockd/svclock.c	Tue Jan  1 14:04:28 2002
@@ -306,8 +306,9 @@
 	struct nlm_block	*block;
 	int			error;
 
-	dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
-				file->f_file.f_dentry->d_inode->i_dev,
+	dprintk("lockd: nlmsvc_lock(%02x:%02x/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
+				major(file->f_file.f_dentry->d_inode->i_dev),
+				minor(file->f_file.f_dentry->d_inode->i_dev),
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type, lock->fl.fl_pid,
 				(long long)lock->fl.fl_start,
@@ -385,8 +386,9 @@
 {
 	struct file_lock	*fl;
 
-	dprintk("lockd: nlmsvc_testlock(%04x/%ld, ty=%d, %Ld-%Ld)\n",
-				file->f_file.f_dentry->d_inode->i_dev,
+	dprintk("lockd: nlmsvc_testlock(%02x:%02x/%ld, ty=%d, %Ld-%Ld)\n",
+				major(file->f_file.f_dentry->d_inode->i_dev),
+				minor(file->f_file.f_dentry->d_inode->i_dev),
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type,
 				(long long)lock->fl.fl_start,
@@ -417,8 +419,9 @@
 {
 	int	error;
 
-	dprintk("lockd: nlmsvc_unlock(%04x/%ld, pi=%d, %Ld-%Ld)\n",
-				file->f_file.f_dentry->d_inode->i_dev,
+	dprintk("lockd: nlmsvc_unlock(%02x:%02x/%ld, pi=%d, %Ld-%Ld)\n",
+				major(file->f_file.f_dentry->d_inode->i_dev),
+				minor(file->f_file.f_dentry->d_inode->i_dev),
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
 				(long long)lock->fl.fl_start,
@@ -445,8 +448,9 @@
 {
 	struct nlm_block	*block;
 
-	dprintk("lockd: nlmsvc_cancel(%04x/%ld, pi=%d, %Ld-%Ld)\n",
-				file->f_file.f_dentry->d_inode->i_dev,
+	dprintk("lockd: nlmsvc_cancel(%02x:%02x/%ld, pi=%d, %Ld-%Ld)\n",
+				major(file->f_file.f_dentry->d_inode->i_dev),
+				minor(file->f_file.f_dentry->d_inode->i_dev),
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
 				(long long)lock->fl.fl_start,
diff -urN linux-2.5.2-pre5/fs/namei.c linux/fs/namei.c
--- linux-2.5.2-pre5/fs/namei.c	Fri Nov 30 08:41:52 2001
+++ linux/fs/namei.c	Tue Jan  1 14:04:29 2002
@@ -1589,7 +1589,7 @@
 		goto exit_lock;
 
 	error = -EXDEV;
-	if (dir->i_dev != inode->i_dev)
+	if (!kdev_same(dir->i_dev, inode->i_dev))
 		goto exit_lock;
 
 	/*
@@ -1707,7 +1707,7 @@
 	if (error)
 		return error;
 
-	if (new_dir->i_dev != old_dir->i_dev)
+	if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
 		return -EXDEV;
 
 	if (!new_dentry->d_inode)
@@ -1787,7 +1787,7 @@
 	if (error)
 		return error;
 
-	if (new_dir->i_dev != old_dir->i_dev)
+	if (!kdev_same(new_dir->i_dev, old_dir->i_dev))
 		return -EXDEV;
 
 	if (!new_dentry->d_inode)
diff -urN linux-2.5.2-pre5/fs/nfs/dir.c linux/fs/nfs/dir.c
--- linux-2.5.2-pre5/fs/nfs/dir.c	Tue Jun 12 11:15:08 2001
+++ linux/fs/nfs/dir.c	Tue Jan  1 14:04:29 2002
@@ -643,8 +643,8 @@
 	struct nfs_fh fhandle;
 	int error;
 
-	dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: create(%x:%x/%ld, %s\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	attr.ia_mode = mode;
 	attr.ia_valid = ATTR_MODE;
@@ -675,8 +675,8 @@
 	struct nfs_fh fhandle;
 	int error;
 
-	dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: mknod(%x:%x/%ld, %s\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	attr.ia_mode = mode;
 	attr.ia_valid = ATTR_MODE;
@@ -701,8 +701,8 @@
 	struct nfs_fh fhandle;
 	int error;
 
-	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: mkdir(%x:%x/%ld, %s\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	attr.ia_valid = ATTR_MODE;
 	attr.ia_mode = mode | S_IFDIR;
@@ -730,8 +730,8 @@
 {
 	int error;
 
-	dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: rmdir(%x:%x/%ld, %s\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	nfs_zap_caches(dir);
 	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
@@ -877,8 +877,8 @@
 {
 	int error;
 
-	dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+	dfprintk(VFS, "NFS: unlink(%x:%x/%ld, %s)\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name);
 
 	error = nfs_sillyrename(dir, dentry);
 	if (error && error != -EBUSY) {
@@ -900,8 +900,8 @@
 	unsigned int maxlen;
 	int error;
 
-	dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
+	dfprintk(VFS, "NFS: symlink(%x:%x/%ld, %s, %s)\n",
+		major(dir->i_dev), minor(dir->i_dev), dir->i_ino, dentry->d_name.name, symname);
 
 	error = -ENAMETOOLONG;
 	maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
diff -urN linux-2.5.2-pre5/fs/nfs/file.c linux/fs/nfs/file.c
--- linux-2.5.2-pre5/fs/nfs/file.c	Tue Jan  1 14:04:25 2002
+++ linux/fs/nfs/file.c	Tue Jan  1 14:04:29 2002
@@ -73,7 +73,8 @@
 	struct inode	*inode = file->f_dentry->d_inode;
 	int		status;
 
-	dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino);
+	dfprintk(VFS, "nfs: flush(%02x:%02x/%ld)\n",
+		major(inode->i_dev), minor(inode->i_dev), inode->i_ino);
 
 	/* Make sure all async reads have been sent off. We don't bother
 	 * waiting on them though... */
@@ -132,7 +133,8 @@
 	struct inode *inode = dentry->d_inode;
 	int status;
 
-	dfprintk(VFS, "nfs: fsync(%x/%ld)\n", inode->i_dev, inode->i_ino);
+	dfprintk(VFS, "nfs: fsync(%02x:%02x/%ld)\n",
+		major(inode->i_dev), minor(inode->i_dev), inode->i_ino);
 
 	lock_kernel();
 	status = nfs_wb_file(inode, file);
@@ -245,8 +247,8 @@
 	struct inode * inode = filp->f_dentry->d_inode;
 	int	status = 0;
 
-	dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
-			inode->i_dev, inode->i_ino,
+	dprintk("NFS: nfs_lock(f=%02x:%02x/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
+			major(inode->i_dev), minor(inode->i_dev), inode->i_ino,
 			fl->fl_type, fl->fl_flags,
 			(long long)fl->fl_start, (long long)fl->fl_end);
 
diff -urN linux-2.5.2-pre5/fs/nfs/inode.c linux/fs/nfs/inode.c
--- linux-2.5.2-pre5/fs/nfs/inode.c	Tue Jan  1 14:04:25 2002
+++ linux/fs/nfs/inode.c	Tue Jan  1 14:04:29 2002
@@ -104,7 +104,7 @@
 {
 	inode->i_blksize = inode->i_sb->s_blocksize;
 	inode->i_mode = 0;
-	inode->i_rdev = 0;
+	inode->i_rdev = NODEV;
 	/* We can't support UPDATE_ATIME(), since the server will reset it */
 	inode->i_flags |= S_NOATIME;
 	INIT_LIST_HEAD(&inode->u.nfs_i.read);
@@ -127,7 +127,7 @@
 static void
 nfs_delete_inode(struct inode * inode)
 {
-	dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+	dprintk("NFS: delete_inode(%x:%x/%ld)\n", major(inode->i_dev), minor(inode->i_dev), inode->i_ino);
 
 	/*
 	 * The following can never actually happen...
@@ -747,8 +747,9 @@
 		goto out_no_inode;
 
 	nfs_fill_inode(inode, fh, fattr);
-	dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n",
-		inode->i_dev, (long long)NFS_FILEID(inode),
+	dprintk("NFS: __nfs_fhget(%x:%x/%Ld ct=%d)\n",
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode),
 		atomic_read(&inode->i_count));
 
 out:
@@ -902,8 +903,9 @@
 	int		 status = -ESTALE;
 	struct nfs_fattr fattr;
 
-	dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n",
-		inode->i_dev, (long long)NFS_FILEID(inode));
+	dfprintk(PAGECACHE, "NFS: revalidating (%x:%x/%Ld)\n",
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode));
 
 	lock_kernel();
 	if (!inode || is_bad_inode(inode))
@@ -924,8 +926,9 @@
 
 	status = NFS_PROTO(inode)->getattr(inode, &fattr);
 	if (status) {
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
-			 inode->i_dev, (long long)NFS_FILEID(inode), status);
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x:%x/%Ld) getattr failed, error=%d\n",
+			 major(inode->i_dev), minor(inode->i_dev),
+			 (long long)NFS_FILEID(inode), status);
 		if (status == -ESTALE) {
 			NFS_FLAGS(inode) |= NFS_INO_STALE;
 			if (inode != inode->i_sb->s_root->d_inode)
@@ -936,12 +939,14 @@
 
 	status = nfs_refresh_inode(inode, &fattr);
 	if (status) {
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n",
-			 inode->i_dev, (long long)NFS_FILEID(inode), status);
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x:%x/%Ld) refresh failed, error=%d\n",
+			 major(inode->i_dev), minor(inode->i_dev),
+			 (long long)NFS_FILEID(inode), status);
 		goto out;
 	}
-	dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n",
-		inode->i_dev, (long long)NFS_FILEID(inode));
+	dfprintk(PAGECACHE, "NFS: (%x:%x/%Ld) revalidation complete\n",
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode));
 
 	NFS_FLAGS(inode) &= ~NFS_INO_STALE;
 out:
@@ -1000,8 +1005,8 @@
 	time_t		new_atime;
 	int		invalid = 0;
 
-	dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n",
-			inode->i_dev, inode->i_ino,
+	dfprintk(VFS, "NFS: refresh_inode(%x:%x/%ld ct=%d info=0x%x)\n",
+			major(inode->i_dev), minor(inode->i_dev), inode->i_ino,
 			atomic_read(&inode->i_count), fattr->valid);
 
 	if (NFS_FSID(inode) != fattr->fsid ||
@@ -1100,7 +1105,7 @@
  		inode->i_blocks = fattr->du.nfs2.blocks;
  		inode->i_blksize = fattr->du.nfs2.blocksize;
  	}
- 	inode->i_rdev = 0;
+ 	inode->i_rdev = NODEV;
  	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
  		inode->i_rdev = to_kdev_t(fattr->rdev);
  
diff -urN linux-2.5.2-pre5/fs/nfs/read.c linux/fs/nfs/read.c
--- linux-2.5.2-pre5/fs/nfs/read.c	Tue Jan  1 14:04:25 2002
+++ linux/fs/nfs/read.c	Tue Jan  1 14:04:29 2002
@@ -108,9 +108,10 @@
 		if (count < rsize)
 			rsize = count;
 
-		dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %Ld, %d, %p)\n",
+		dprintk("NFS: nfs_proc_read(%s, (%x:%x/%Ld), %Ld, %d, %p)\n",
 			NFS_SERVER(inode)->hostname,
-			inode->i_dev, (long long)NFS_FILEID(inode),
+			major(inode->i_dev), minor(inode->i_dev),
+			(long long)NFS_FILEID(inode),
 			(long long)offset, rsize, buffer);
 
 		lock_kernel();
@@ -265,9 +266,10 @@
 	msg.rpc_cred = data->cred;
 
 	/* Start the async call */
-	dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n",
+	dprintk("NFS: %4d initiated read call (req %x:%x/%Ld count %d nriov %d.\n",
 		task->tk_pid,
-		inode->i_dev, (long long)NFS_FILEID(inode),
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode),
 		data->args.count, data->args.nriov);
 
 	rpc_clnt_sigmask(clnt, &oldset);
@@ -423,8 +425,9 @@
 		kunmap(page);
 		UnlockPage(page);
 
-		dprintk("NFS: read (%x/%Ld %d@%Ld)\n",
-                        req->wb_inode->i_dev,
+		dprintk("NFS: read (%x:%x/%Ld %d@%Ld)\n",
+                        major(req->wb_inode->i_dev),
+                        minor(req->wb_inode->i_dev),
                         (long long)NFS_FILEID(req->wb_inode),
                         req->wb_bytes,
                         (long long)(page_offset(page) + req->wb_offset));
diff -urN linux-2.5.2-pre5/fs/nfs/write.c linux/fs/nfs/write.c
--- linux-2.5.2-pre5/fs/nfs/write.c	Tue Jan  1 14:04:25 2002
+++ linux/fs/nfs/write.c	Tue Jan  1 14:04:29 2002
@@ -159,8 +159,9 @@
 	if (!cred)
 		cred = get_rpccred(NFS_I(inode)->mm_cred);
 
-	dprintk("NFS:      nfs_writepage_sync(%x/%Ld %d@%Ld)\n",
-		inode->i_dev, (long long)NFS_FILEID(inode),
+	dprintk("NFS:      nfs_writepage_sync(%x:%x/%Ld %d@%Ld)\n",
+		major(inode->i_dev), minor(inode->i_dev),
+		(long long)NFS_FILEID(inode),
 		count, (long long)(page_offset(page) + offset));
 
 	buffer = kmap(page) + offset;
@@ -934,9 +935,9 @@
 	msg.rpc_resp = &data->res;
 	msg.rpc_cred = data->cred;
 
-	dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",
+	dprintk("NFS: %4d initiated write call (req %x:%x/%Ld count %d nriov %d)\n",
 		task->tk_pid, 
-		inode->i_dev,
+		major(inode->i_dev), minor(inode->i_dev),
 		(long long)NFS_FILEID(inode),
 		data->args.count, data->args.nriov);
 
@@ -1049,8 +1050,9 @@
 
 		kunmap(page);
 
-		dprintk("NFS: write (%x/%Ld %d@%Ld)",
-			req->wb_inode->i_dev,
+		dprintk("NFS: write (%x:%x/%Ld %d@%Ld)",
+			major(req->wb_inode->i_dev),
+			minor(req->wb_inode->i_dev),
 			(long long)NFS_FILEID(req->wb_inode),
 			req->wb_bytes,
 			(long long)(page_offset(page) + req->wb_offset));
diff -urN linux-2.5.2-pre5/fs/nfsd/export.c linux/fs/nfsd/export.c
--- linux-2.5.2-pre5/fs/nfsd/export.c	Tue Jan  1 14:04:25 2002
+++ linux/fs/nfsd/export.c	Tue Jan  1 14:04:29 2002
@@ -50,7 +50,7 @@
 #define CLIENT_HASH(a) \
 		((((a)>>24) ^ ((a)>>16) ^ ((a)>>8) ^(a)) & CLIENT_HASHMASK)
 /* XXX: is this adequate for 32bit kdev_t ? */
-#define EXPORT_HASH(dev)	((dev) & (NFSCLNT_EXPMAX - 1))
+#define EXPORT_HASH(dev)	(minor(dev) & (NFSCLNT_EXPMAX - 1))
 
 struct svc_clnthash {
 	struct svc_clnthash *	h_next;
@@ -76,7 +76,7 @@
 	svc_export *	exp;
 
 	exp = clp->cl_export[EXPORT_HASH(dev)];
-	while (exp && exp->ex_dev != dev)
+	while (exp && !kdev_same(exp->ex_dev, dev))
 		exp = exp->ex_next;
 	return exp;
 }
@@ -95,7 +95,7 @@
 	exp = clp->cl_export[EXPORT_HASH(dev)];
 	if (exp)
 		do {
-			if (exp->ex_ino == ino && exp->ex_dev == dev)
+			if (exp->ex_ino == ino && kdev_same(exp->ex_dev, dev))
 				goto out;
 		} while (NULL != (exp = exp->ex_next));
 	exp = NULL;
@@ -198,9 +198,10 @@
 
 	inode = nd.dentry->d_inode;
 	err = -EINVAL;
-	if (inode->i_dev != dev || inode->i_ino != nxp->ex_ino) {
-		printk(KERN_DEBUG "exp_export: i_dev = %x, dev = %x\n",
-			inode->i_dev, dev); 
+	if (!kdev_same(inode->i_dev, dev) || inode->i_ino != nxp->ex_ino) {
+		printk(KERN_DEBUG "exp_export: i_dev = %02x:%02x, dev = %02x:%02x\n",
+			major(inode->i_dev), minor(inode->i_dev),
+			major(dev), minor(dev)); 
 		/* I'm just being paranoid... */
 		goto finish;
 	}
@@ -302,7 +303,7 @@
 	dentry = unexp->ex_dentry;
 	mnt = unexp->ex_mnt;
 	inode = dentry->d_inode;
-	if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
+	if (!kdev_same(unexp->ex_dev, inode->i_dev) || unexp->ex_ino != inode->i_ino)
 		printk(KERN_WARNING "nfsd: bad dentry in unexport!\n");
 	dput(dentry);
 	mntput(mnt);
@@ -353,9 +354,10 @@
 	err = -EINVAL;
 	clp = exp_getclientbyname(nxp->ex_client);
 	if (clp) {
-		expp = clp->cl_export + EXPORT_HASH(nxp->ex_dev);
+		kdev_t ex_dev = to_kdev_t(nxp->ex_dev);
+		expp = clp->cl_export + EXPORT_HASH(ex_dev);
 		while ((exp = *expp) != NULL) {
-			if (exp->ex_dev == nxp->ex_dev) {
+			if (kdev_same(exp->ex_dev, ex_dev)) {
 				if (exp->ex_ino == nxp->ex_ino) {
 					*expp = exp->ex_next;
 					exp_do_unexport(exp);
@@ -397,12 +399,13 @@
 		dev = nd.dentry->d_inode->i_dev;
 		ino = nd.dentry->d_inode->i_ino;
 	
-		dprintk("nfsd: exp_rootfh(%s [%p] %s:%x/%ld)\n",
-		         path, nd.dentry, clp->cl_ident, dev, (long) ino);
+		dprintk("nfsd: exp_rootfh(%s [%p] %s:%02x:%02x/%ld)\n",
+		         path, nd.dentry, clp->cl_ident,
+		         major(dev), minor(dev), (long) ino);
 		exp = exp_parent(clp, dev, nd.dentry);
 	} else {
-		dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n",
-		         clp->cl_ident, dev, (long) ino);
+		dprintk("nfsd: exp_rootfh(%s:%02x:%02x/%ld)\n",
+		         clp->cl_ident, major(dev), minor(dev), (long) ino);
 		if ((exp = exp_get(clp, dev, ino))) {
 			nd.mnt = mntget(exp->ex_mnt);
 			nd.dentry = dget(exp->ex_dentry);
@@ -418,11 +421,12 @@
 		printk("exp_rootfh: Aieee, NULL d_inode\n");
 		goto out;
 	}
-	if (inode->i_dev != dev || inode->i_ino != ino) {
+	if (!kdev_same(inode->i_dev, dev) || inode->i_ino != ino) {
 		printk("exp_rootfh: Aieee, ino/dev mismatch\n");
-		printk("exp_rootfh: arg[dev(%x):ino(%ld)]"
-		       " inode[dev(%x):ino(%ld)]\n",
-		       dev, (long) ino, inode->i_dev, (long) inode->i_ino);
+		printk("exp_rootfh: arg[dev(%02x:%02x):ino(%ld)]"
+		       " inode[dev(%02x:%02x):ino(%ld)]\n",
+		       major(dev), minor(dev), (long) ino,
+		       major(inode->i_dev), minor(inode->i_dev), (long) inode->i_ino);
 	}
 
 	/*
diff -urN linux-2.5.2-pre5/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c
--- linux-2.5.2-pre5/fs/nfsd/nfsctl.c	Sun Oct 21 10:32:33 2001
+++ linux/fs/nfsd/nfsctl.c	Tue Jan  1 14:04:29 2002
@@ -125,7 +125,7 @@
 	if (!(clp = exp_getclient(sin)))
 		err = -EPERM;
 	else
-		err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen);
+		err = exp_rootfh(clp, NODEV, 0, data->gd_path, res, data->gd_maxlen);
 	exp_unlock();
 	return err;
 }
@@ -148,7 +148,7 @@
 	if (!(clp = exp_getclient(sin)))
 		err = -EPERM;
 	else
-		err = exp_rootfh(clp, 0, 0, data->gd_path, &fh, NFS_FHSIZE);
+		err = exp_rootfh(clp, NODEV, 0, data->gd_path, &fh, NFS_FHSIZE);
 	exp_unlock();
 
 	if (err == 0) {
diff -urN linux-2.5.2-pre5/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- linux-2.5.2-pre5/fs/nfsd/nfsfh.c	Wed Oct  3 22:59:22 2001
+++ linux/fs/nfsd/nfsfh.c	Tue Jan  1 14:04:29 2002
@@ -424,7 +424,8 @@
 	/* It's a directory, or we are required to confirm the file's
 	 * location in the tree.
 	 */
-	dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,datap[0]);
+	dprintk("nfs_fh: need to look harder for %02x:%02x/%d\n",
+		major(sb->s_dev), minor(sb->s_dev), datap[0]);
 
 	if (!S_ISDIR(result->d_inode->i_mode)) {
 		nfsdstats.fh_nocache_nondir++;
@@ -556,7 +557,7 @@
 			case 0:
 				if ((data_left-=2)<0) goto out;
 				nfsdev = ntohl(*datap++);
-				xdev = MKDEV(nfsdev>>16, nfsdev&0xFFFF);
+				xdev = mk_kdev(nfsdev>>16, nfsdev&0xFFFF);
 				xino = *datap++;
 				break;
 			default:
@@ -788,8 +789,8 @@
 	struct dentry *parent = dentry->d_parent;
 	__u32 *datap;
 
-	dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
-		exp->ex_dev, (long) exp->ex_ino,
+	dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n",
+		major(exp->ex_dev), minor(exp->ex_dev), (long) exp->ex_ino,
 		parent->d_name.name, dentry->d_name.name,
 		(inode ? inode->i_ino : 0));
 
@@ -811,7 +812,7 @@
 		memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE);
 		fhp->fh_handle.fh_size = NFS_FHSIZE;
 		fhp->fh_handle.ofh_dcookie = 0xfeebbaca;
-		fhp->fh_handle.ofh_dev =  htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+		fhp->fh_handle.ofh_dev =  htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev));
 		fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev;
 		fhp->fh_handle.ofh_xino = ino_t_to_u32(exp->ex_ino);
 		fhp->fh_handle.ofh_dirino = ino_t_to_u32(dentry->d_parent->d_inode->i_ino);
@@ -823,7 +824,7 @@
 		fhp->fh_handle.fh_fsid_type = 0;
 		datap = fhp->fh_handle.fh_auth+0;
 		/* fsid_type 0 == 2byte major, 2byte minor, 4byte inode */
-		*datap++ = htonl((MAJOR(exp->ex_dev)<<16)| MINOR(exp->ex_dev));
+		*datap++ = htonl((major(exp->ex_dev)<<16)| minor(exp->ex_dev));
 		*datap++ = ino_t_to_u32(exp->ex_ino);
 		fhp->fh_handle.fh_size = 3*4;
 		if (inode) {
diff -urN linux-2.5.2-pre5/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- linux-2.5.2-pre5/fs/nfsd/nfsproc.c	Sun Oct 21 10:40:36 2001
+++ linux/fs/nfsd/nfsproc.c	Tue Jan  1 14:04:29 2002
@@ -197,7 +197,7 @@
 	struct inode	*inode;
 	struct dentry	*dchild;
 	int		nfserr, type, mode;
-	dev_t		rdev = NODEV;
+	dev_t		rdev = 0;
 
 	dprintk("nfsd: CREATE   %s %.*s\n",
 		SVCFH_fmt(dirfhp), argp->len, argp->name);
@@ -255,7 +255,7 @@
 				case S_IFCHR:
 				case S_IFBLK:
 					/* reserve rdev for later checking */
-					attr->ia_size = inode->i_rdev;
+					attr->ia_size = kdev_t_to_nr(inode->i_rdev);
 					attr->ia_valid |= ATTR_SIZE;
 
 					/* FALLTHROUGH */
@@ -313,7 +313,7 @@
 		/* Make sure the type and device matches */
 		nfserr = nfserr_exist;
 		if (inode && (type != (inode->i_mode & S_IFMT) || 
-		    (is_borc && inode->i_rdev != rdev)))
+		    (is_borc && kdev_t_to_nr(inode->i_rdev) != rdev)))
 			goto out_unlock;
 	}
 	
diff -urN linux-2.5.2-pre5/fs/nfsd/nfsxdr.c linux/fs/nfsd/nfsxdr.c
--- linux-2.5.2-pre5/fs/nfsd/nfsxdr.c	Wed Oct 17 14:16:34 2001
+++ linux/fs/nfsd/nfsxdr.c	Tue Jan  1 14:04:29 2002
@@ -149,11 +149,11 @@
 	}
 	*p++ = htonl((u32) inode->i_blksize);
 	if (S_ISCHR(type) || S_ISBLK(type))
-		*p++ = htonl((u32) inode->i_rdev);
+		*p++ = htonl((u32) kdev_t_to_nr(inode->i_rdev));
 	else
 		*p++ = htonl(0xffffffff);
 	*p++ = htonl((u32) inode->i_blocks);
-	*p++ = htonl((u32) inode->i_dev);
+	*p++ = htonl((u32) kdev_t_to_nr(inode->i_dev));
 	*p++ = htonl((u32) inode->i_ino);
 	*p++ = htonl((u32) inode->i_atime);
 	*p++ = 0;
diff -urN linux-2.5.2-pre5/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- linux-2.5.2-pre5/fs/nfsd/vfs.c	Fri Oct  5 12:23:53 2001
+++ linux/fs/nfsd/vfs.c	Tue Jan  1 14:04:29 2002
@@ -66,7 +66,7 @@
 	struct raparms		*p_next;
 	unsigned int		p_count;
 	ino_t			p_ino;
-	dev_t			p_dev;
+	kdev_t			p_dev;
 	unsigned long		p_reada,
 				p_ramax,
 				p_raend,
@@ -543,13 +543,13 @@
  * specified by (dev, ino).
  */
 static inline struct raparms *
-nfsd_get_raparms(dev_t dev, ino_t ino)
+nfsd_get_raparms(kdev_t dev, ino_t ino)
 {
 	struct raparms	*ra, **rap, **frap = NULL;
 	int depth = 0;
 	
 	for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
-		if (ra->p_ino == ino && ra->p_dev == dev)
+		if (ra->p_ino == ino && kdev_same(ra->p_dev, dev))
 			goto found;
 		depth++;
 		if (ra->p_count == 0)
@@ -730,7 +730,7 @@
 		 */
 		if (EX_WGATHER(exp)) {
 			if (atomic_read(&inode->i_writecount) > 1
-			    || (last_ino == inode->i_ino && last_dev == inode->i_dev)) {
+			    || (last_ino == inode->i_ino && kdev_same(last_dev, inode->i_dev))) {
 				dprintk("nfsd: write defer %d\n", current->pid);
 				set_current_state(TASK_UNINTERRUPTIBLE);
 				schedule_timeout((HZ+99)/100);
@@ -1245,7 +1245,7 @@
 	tdir = tdentry->d_inode;
 
 	err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
-	if (fdir->i_dev != tdir->i_dev)
+	if (!kdev_same(fdir->i_dev, tdir->i_dev))
 		goto out;
 
 	err = nfserr_perm;
diff -urN linux-2.5.2-pre5/fs/partitions/atari.c linux/fs/partitions/atari.c
--- linux-2.5.2-pre5/fs/partitions/atari.c	Mon Oct  1 20:03:26 2001
+++ linux/fs/partitions/atari.c	Tue Jan  1 14:04:29 2002
@@ -43,7 +43,7 @@
 int atari_partition (struct gendisk *hd, struct block_device *bdev,
 		     unsigned long first_sector, int minor)
 {
-	int m_lim = minor + hd->max_p;
+	int m_lim = minor + (1 << hd->minor_shift);
 	Sector sect;
 	struct rootsector *rs;
 	struct partition_info *pi;
diff -urN linux-2.5.2-pre5/fs/partitions/check.c linux/fs/partitions/check.c
--- linux-2.5.2-pre5/fs/partitions/check.c	Tue Nov 27 09:23:27 2001
+++ linux/fs/partitions/check.c	Tue Jan  1 14:04:29 2002
@@ -38,7 +38,8 @@
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
 
-static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = {
+static int (*check_part[])(struct gendisk *hd, struct block_device *bdev,
+			   unsigned long first_sect, int first_minor) = {
 #ifdef CONFIG_ACORN_PARTITION
 	acorn_partition,
 #endif
@@ -227,26 +228,26 @@
 	if (first_time)
 		printk(KERN_INFO "Partition check:\n");
 	first_time = 0;
-	first_sector = hd->part[MINOR(dev)].start_sect;
+	first_sector = hd->part[minor(dev)].start_sect;
 
 	/*
 	 * This is a kludge to allow the partition check to be
 	 * skipped for specific drives (e.g. IDE CD-ROM drives)
 	 */
 	if ((int)first_sector == -1) {
-		hd->part[MINOR(dev)].start_sect = 0;
+		hd->part[minor(dev)].start_sect = 0;
 		return;
 	}
 
 	if (hd->de_arr)
-		de = hd->de_arr[MINOR(dev) >> hd->minor_shift];
+		de = hd->de_arr[minor(dev) >> hd->minor_shift];
 	i = devfs_generate_path (de, buf, sizeof buf);
 	if (i >= 0)
 		printk(KERN_INFO " /dev/%s:", buf + i);
 	else
-		printk(KERN_INFO " %s:", disk_name(hd, MINOR(dev), buf));
+		printk(KERN_INFO " %s:", disk_name(hd, minor(dev), buf));
 	bdev = bdget(kdev_t_to_nr(dev));
-	bdev->bd_inode->i_size = (loff_t)hd->part[MINOR(dev)].nr_sects << 9;
+	bdev->bd_inode->i_size = (loff_t)hd->part[minor(dev)].nr_sects << 9;
 	bdev->bd_inode->i_blkbits = blksize_bits(block_size(dev));
 	for (i = 0; check_part[i]; i++) {
 		int res;
@@ -333,11 +334,12 @@
 void devfs_register_partitions (struct gendisk *dev, int minor, int unregister)
 {
 #ifdef CONFIG_DEVFS_FS
-	int part;
+	int part, max_p;
 
 	if (!unregister)
 		devfs_register_disc (dev, minor);
-	for (part = 1; part < dev->max_p; part++) {
+	max_p = (1 << dev->minor_shift);
+	for (part = 1; part < max_p; part++) {
 		if ( unregister || (dev->part[part + minor].nr_sects < 1) ) {
 			devfs_unregister (dev->part[part + minor].de);
 			dev->part[part + minor].de = NULL;
@@ -381,10 +383,10 @@
 		return;
 
 	minors = 1 << g->minor_shift;
-	first_minor = MINOR(dev);
+	first_minor = minor(dev);
 	if (first_minor & (minors-1)) {
 		printk("grok_partitions: bad device 0x%02x:%02x\n",
-		       MAJOR(dev), first_minor);
+		       major(dev), first_minor);
 		first_minor &= ~(minors-1);
 	}
 	end_minor = first_minor + minors;
@@ -404,7 +406,7 @@
 			g->sizes[i] = 0;
 	}
 	blk_size[g->major] = g->sizes;
-	check_partition(g, MKDEV(g->major, first_minor), 1 + first_minor);
+	check_partition(g, mk_kdev(g->major, first_minor), 1 + first_minor);
 
  	/*
  	 * We need to set the sizes array before we will be able to access
@@ -450,8 +452,8 @@
 		return -EINVAL;
 
 	max_p = 1 << g->minor_shift;
-	major = MAJOR(dev);
-	minor = MINOR(dev);
+	major = major(dev);
+	minor = minor(dev);
 	minor0 = minor & ~(max_p - 1);
 	if (minor0 != minor)		/* for now only whole-disk reread */
 		return -EINVAL;		/* %%% later.. */
@@ -459,7 +461,7 @@
 	/* invalidate stuff */
 	for (p = max_p - 1; p >= 0; p--) {
 		minor = minor0 + p;
-		devp = MKDEV(major,minor);
+		devp = mk_kdev(major,minor);
 #if 0					/* %%% superfluous? */
 		if (g->part[minor].nr_sects == 0)
 			continue;
diff -urN linux-2.5.2-pre5/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.5.2-pre5/fs/proc/array.c	Tue Jan  1 14:04:25 2002
+++ linux/fs/proc/array.c	Tue Jan  1 14:04:29 2002
@@ -555,7 +555,7 @@
 	str[3] = flags & VM_MAYSHARE ? 's' : 'p';
 	str[4] = 0;
 
-	dev = 0;
+	dev = NODEV;
 	ino = 0;
 	if (map->vm_file != NULL) {
 		dev = map->vm_file->f_dentry->d_inode->i_dev;
diff -urN linux-2.5.2-pre5/fs/super.c linux/fs/super.c
--- linux-2.5.2-pre5/fs/super.c	Tue Jan  1 14:04:25 2002
+++ linux/fs/super.c	Tue Jan  1 14:04:29 2002
@@ -418,7 +418,7 @@
 
 	list_for_each(p, &super_blocks) {
 		struct super_block * s = sb_entry(p);
-		if (s->s_dev == dev) {
+		if (kdev_same(s->s_dev, dev)) {
 			s->s_count++;
 			return s;
 		}
@@ -450,7 +450,7 @@
 {
 	struct super_block * sb;
 
-	if (dev) {
+	if (!kdev_none(dev)) {
 		sb = get_super(dev);
 		if (sb) {
 			if (sb->s_dirt)
@@ -487,7 +487,7 @@
 {
 	struct super_block * s;
 
-	if (!dev)
+	if (kdev_none(dev))
 		return NULL;
 
 	while (1) {
@@ -540,7 +540,7 @@
 {
 	int retval;
 	
-	if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
+	if (!(flags & MS_RDONLY) && !kdev_none(sb->s_dev) && is_read_only(sb->s_dev))
 		return -EACCES;
 		/*flags |= MS_RDONLY;*/
 	if (flags & MS_RDONLY)
@@ -578,7 +578,7 @@
 static void put_anon_dev(kdev_t dev)
 {
 	spin_lock(&unnamed_dev_lock);
-	clear_bit(MINOR(dev), unnamed_dev_in_use);
+	clear_bit(minor(dev), unnamed_dev_in_use);
 	spin_unlock(&unnamed_dev_lock);
 }
 
@@ -608,7 +608,7 @@
 	int (*compare)(struct super_block *,void *), void *data)
 {
 	struct super_block *s = alloc_super();
-	kdev_t dev;
+	int dev;
 	struct list_head *p;
 
 	if (!s)
@@ -637,7 +637,7 @@
 		return old;
 	}
 
-	s->s_dev = dev;
+	s->s_dev = mk_kdev(0, dev);
 	insert_super(s, type);
 	return s;
 }
@@ -699,7 +699,7 @@
 
 	list_for_each(p, &super_blocks) {
 		struct super_block *old = sb_entry(p);
-		if (old->s_dev != dev)
+		if (!kdev_same(old->s_dev, dev))
 			continue;
 		if (old->s_type != fs_type ||
 		    ((flags ^ old->s_flags) & MS_RDONLY)) {
diff -urN linux-2.5.2-pre5/include/linux/blk.h linux/include/linux/blk.h
--- linux-2.5.2-pre5/include/linux/blk.h	Tue Jan  1 14:04:26 2002
+++ linux/include/linux/blk.h	Tue Jan  1 14:04:29 2002
@@ -106,14 +106,14 @@
 
 #ifdef IDE_DRIVER
 
-#define DEVICE_NR(device)	(MINOR(device) >> PARTN_BITS)
+#define DEVICE_NR(device)	(minor(device) >> PARTN_BITS)
 #define DEVICE_NAME "ide"
 
 #elif (MAJOR_NR == RAMDISK_MAJOR)
 
 /* ram disk */
 #define DEVICE_NAME "ramdisk"
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 #define DEVICE_NO_RANDOM
 
 #elif (MAJOR_NR == Z2RAM_MAJOR)
@@ -121,7 +121,7 @@
 /* Zorro II Ram */
 #define DEVICE_NAME "Z2RAM"
 #define DEVICE_REQUEST do_z2_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == FLOPPY_MAJOR)
 
@@ -130,7 +130,7 @@
 #define DEVICE_NAME "floppy"
 #define DEVICE_INTR do_floppy
 #define DEVICE_REQUEST do_fd_request
-#define DEVICE_NR(device) ( (MINOR(device) & 3) | ((MINOR(device) & 0x80 ) >> 5 ))
+#define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 ))
 #define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
 
 #elif (MAJOR_NR == HD_MAJOR)
@@ -140,188 +140,188 @@
 #define DEVICE_INTR do_hd
 #define TIMEOUT_VALUE (6*HZ)
 #define DEVICE_REQUEST do_hd_request
-#define DEVICE_NR(device) (MINOR(device)>>6)
+#define DEVICE_NR(device) (minor(device)>>6)
 
 #elif (SCSI_DISK_MAJOR(MAJOR_NR))
 
 #define DEVICE_NAME "scsidisk"
 #define TIMEOUT_VALUE (2*HZ)
-#define DEVICE_NR(device) (((MAJOR(device) & SD_MAJOR_MASK) << (8 - 4)) + (MINOR(device) >> 4))
+#define DEVICE_NR(device) (((major(device) & SD_MAJOR_MASK) << (8 - 4)) + (minor(device) >> 4))
 
 /* Kludge to use the same number for both char and block major numbers */
 #elif  (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER)
 
 #define DEVICE_NAME "Multiple devices driver"
 #define DEVICE_REQUEST do_md_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == SCSI_TAPE_MAJOR)
 
 #define DEVICE_NAME "scsitape"
 #define DEVICE_INTR do_st  
-#define DEVICE_NR(device) (MINOR(device) & 0x7f)
+#define DEVICE_NR(device) (minor(device) & 0x7f)
 
 #elif (MAJOR_NR == OSST_MAJOR)
 
 #define DEVICE_NAME "onstream" 
 #define DEVICE_INTR do_osst
-#define DEVICE_NR(device) (MINOR(device) & 0x7f) 
+#define DEVICE_NR(device) (minor(device) & 0x7f) 
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device) 
 
 #elif (MAJOR_NR == SCSI_CDROM_MAJOR)
 
 #define DEVICE_NAME "CD-ROM"
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == XT_DISK_MAJOR)
 
 #define DEVICE_NAME "xt disk"
 #define DEVICE_REQUEST do_xd_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_NR(device) (minor(device) >> 6)
 
 #elif (MAJOR_NR == PS2ESDI_MAJOR)
 
 #define DEVICE_NAME "PS/2 ESDI"
 #define DEVICE_REQUEST do_ps2esdi_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_NR(device) (minor(device) >> 6)
 
 #elif (MAJOR_NR == CDU31A_CDROM_MAJOR)
 
 #define DEVICE_NAME "CDU31A"
 #define DEVICE_REQUEST do_cdu31a_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == ACSI_MAJOR) && (defined(CONFIG_ATARI_ACSI) || defined(CONFIG_ATARI_ACSI_MODULE))
 
 #define DEVICE_NAME "ACSI"
 #define DEVICE_INTR do_acsi
 #define DEVICE_REQUEST do_acsi_request
-#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_NR(device) (minor(device) >> 4)
 
 #elif (MAJOR_NR == MITSUMI_CDROM_MAJOR)
 
 #define DEVICE_NAME "Mitsumi CD-ROM"
 /* #define DEVICE_INTR do_mcd */
 #define DEVICE_REQUEST do_mcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR)
 
 #define DEVICE_NAME "Mitsumi CD-ROM"
 /* #define DEVICE_INTR do_mcdx */
 #define DEVICE_REQUEST do_mcdx_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #1"
 #define DEVICE_REQUEST do_sbpcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM2_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #2"
 #define DEVICE_REQUEST do_sbpcd2_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM3_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #3"
 #define DEVICE_REQUEST do_sbpcd3_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MATSUSHITA_CDROM4_MAJOR)
 
 #define DEVICE_NAME "Matsushita CD-ROM controller #4"
 #define DEVICE_REQUEST do_sbpcd4_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == AZTECH_CDROM_MAJOR)
 
 #define DEVICE_NAME "Aztech CD-ROM"
 #define DEVICE_REQUEST do_aztcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == CDU535_CDROM_MAJOR)
 
 #define DEVICE_NAME "SONY-CDU535"
 #define DEVICE_INTR do_cdu535
 #define DEVICE_REQUEST do_cdu535_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR)
 
 #define DEVICE_NAME "Goldstar R420"
 #define DEVICE_REQUEST do_gscd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == CM206_CDROM_MAJOR)
 #define DEVICE_NAME "Philips/LMS CD-ROM cm206"
 #define DEVICE_REQUEST do_cm206_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == OPTICS_CDROM_MAJOR)
 
 #define DEVICE_NAME "DOLPHIN 8000AT CD-ROM"
 #define DEVICE_REQUEST do_optcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == SANYO_CDROM_MAJOR)
 
 #define DEVICE_NAME "Sanyo H94A CD-ROM"
 #define DEVICE_REQUEST do_sjcd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == APBLOCK_MAJOR)
 
 #define DEVICE_NAME "apblock"
 #define DEVICE_REQUEST ap_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == DDV_MAJOR)
 
 #define DEVICE_NAME "ddv"
 #define DEVICE_REQUEST ddv_request
-#define DEVICE_NR(device) (MINOR(device)>>PARTN_BITS)
+#define DEVICE_NR(device) (minor(device)>>PARTN_BITS)
 
 #elif (MAJOR_NR == MFM_ACORN_MAJOR)
 
 #define DEVICE_NAME "mfm disk"
 #define DEVICE_INTR do_mfm
 #define DEVICE_REQUEST do_mfm_request
-#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_NR(device) (minor(device) >> 6)
 
 #elif (MAJOR_NR == NBD_MAJOR)
 
 #define DEVICE_NAME "nbd"
 #define DEVICE_REQUEST do_nbd_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == MDISK_MAJOR)
 
 #define DEVICE_NAME "mdisk"
 #define DEVICE_REQUEST mdisk_request
-#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_NR(device) (minor(device))
 
 #elif (MAJOR_NR == DASD_MAJOR)
 
 #define DEVICE_NAME "dasd"
 #define DEVICE_REQUEST do_dasd_request
-#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
+#define DEVICE_NR(device) (minor(device) >> PARTN_BITS)
 
 #elif (MAJOR_NR == I2O_MAJOR)
 
 #define DEVICE_NAME "I2O block"
 #define DEVICE_REQUEST i2ob_request
-#define DEVICE_NR(device) (MINOR(device)>>4)
+#define DEVICE_NR(device) (minor(device)>>4)
 
 #elif (MAJOR_NR == COMPAQ_SMART2_MAJOR)
 
 #define DEVICE_NAME "ida"
 #define TIMEOUT_VALUE (25*HZ)
 #define DEVICE_REQUEST do_ida_request
-#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_NR(device) (minor(device) >> 4)
 
 #endif /* MAJOR_NR == whatever */
 
@@ -375,7 +375,7 @@
 		CLEAR_INTR;					\
 		return;						\
 	}							\
-	if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) 		\
+	if (major(CURRENT->rq_dev) != MAJOR_NR) 			\
 		panic(DEVICE_NAME ": request list destroyed");	\
 	if (!CURRENT->bio)					\
 		panic(DEVICE_NAME ": no bio");			\
@@ -395,7 +395,7 @@
 		return;
 
 #ifndef DEVICE_NO_RANDOM
-	add_blkdev_randomness(MAJOR(req->rq_dev));
+	add_blkdev_randomness(major(req->rq_dev));
 #endif
 	DEVICE_OFF(req->rq_dev);
 	blkdev_dequeue_request(req);
diff -urN linux-2.5.2-pre5/include/linux/blkdev.h linux/include/linux/blkdev.h
--- linux-2.5.2-pre5/include/linux/blkdev.h	Tue Jan  1 14:04:26 2002
+++ linux/include/linux/blkdev.h	Tue Jan  1 14:04:29 2002
@@ -371,10 +371,10 @@
 extern inline unsigned int block_size(kdev_t dev)
 {
 	int retval = BLOCK_SIZE;
-	int major = MAJOR(dev);
+	int major = major(dev);
 
 	if (blksize_size[major]) {
-		int minor = MINOR(dev);
+		int minor = minor(dev);
 		if (blksize_size[major][minor])
 			retval = blksize_size[major][minor];
 	}
diff -urN linux-2.5.2-pre5/include/linux/cdrom.h linux/include/linux/cdrom.h
--- linux-2.5.2-pre5/include/linux/cdrom.h	Sun Dec 16 15:43:25 2001
+++ linux/include/linux/cdrom.h	Tue Jan  1 14:04:29 2002
@@ -792,7 +792,7 @@
 
 	sprintf (vname, "cdroms/cdrom%d", cdi->number);
 	cdi->de = devfs_register (NULL, vname, DEVFS_FL_DEFAULT,
-				    MAJOR (cdi->dev), MINOR (cdi->dev),
+				    major(cdi->dev), minor(cdi->dev),
 				    S_IFBLK | S_IRUGO | S_IWUGO,
 				    ops, NULL);
 }
diff -urN linux-2.5.2-pre5/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.5.2-pre5/include/linux/fs.h	Tue Jan  1 14:04:26 2002
+++ linux/include/linux/fs.h	Tue Jan  1 14:04:29 2002
@@ -311,7 +311,6 @@
 #include <linux/udf_fs_i.h>
 #include <linux/ncp_fs_i.h>
 #include <linux/proc_fs_i.h>
-#include <linux/usbdev_fs_i.h>
 #include <linux/jffs2_fs_i.h>
 #include <linux/cramfs_fs_sb.h>
 
@@ -502,7 +501,6 @@
 		struct ncp_inode_info		ncpfs_i;
 		struct proc_inode_info		proc_i;
 		struct socket			socket_i;
-		struct usbdev_inode_info        usbdev_i;
 		struct jffs2_inode_info		jffs2_i;
 		void				*generic_ip;
 	} u;
@@ -686,7 +684,6 @@
 #include <linux/bfs_fs_sb.h>
 #include <linux/udf_fs_sb.h>
 #include <linux/ncp_fs_sb.h>
-#include <linux/usbdev_fs_sb.h>
 #include <linux/cramfs_fs_sb.h>
 #include <linux/jffs2_fs_sb.h>
 
@@ -744,7 +741,6 @@
 		struct bfs_sb_info	bfs_sb;
 		struct udf_sb_info	udf_sb;
 		struct ncp_sb_info	ncpfs_sb;
-		struct usbdev_sb_info   usbdevfs_sb;
 		struct jffs2_sb_info	jffs2_sb;
 		struct cramfs_sb_info	cramfs_sb;
 		void			*generic_sbp;
diff -urN linux-2.5.2-pre5/include/linux/genhd.h linux/include/linux/genhd.h
--- linux-2.5.2-pre5/include/linux/genhd.h	Sun Dec 16 15:43:25 2001
+++ linux/include/linux/genhd.h	Tue Jan  1 14:04:29 2002
@@ -71,13 +71,11 @@
 	const char *major_name;		/* name of major driver */
 	int minor_shift;		/* number of times minor is shifted to
 					   get real minor */
-	int max_p;			/* maximum partitions per device */
 
 	struct hd_struct *part;		/* [indexed by minor] */
 	int *sizes;			/* [idem], device size in blocks */
 	int nr_real;			/* number of real devices */
 
-	void *real_devices;		/* internal use */
 	struct gendisk *next;
 	struct block_device_operations *fops;
 
@@ -247,7 +245,7 @@
 static inline unsigned int disk_index (kdev_t dev)
 {
 	struct gendisk *g = get_gendisk(dev);
-	return g ? (MINOR(dev) >> g->minor_shift) : 0;
+	return g ? (minor(dev) >> g->minor_shift) : 0;
 }
 
 #endif
diff -urN linux-2.5.2-pre5/include/linux/ide.h linux/include/linux/ide.h
--- linux-2.5.2-pre5/include/linux/ide.h	Sun Dec 16 15:45:06 2001
+++ linux/include/linux/ide.h	Tue Jan  1 14:04:29 2002
@@ -18,13 +18,13 @@
 
 /*
  * This is the multiple IDE interface driver, as evolved from hd.c.
- * It supports up to four IDE interfaces, on one or more IRQs (usually 14 & 15).
+ * It supports up to four IDE interfaces, on one or more IRQs (usually 14, 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
- * Primary i/f:    ide0: major=3;  (hda)         minor=0; (hdb)         minor=64
- * Secondary i/f:  ide1: major=22; (hdc or hd1a) minor=0; (hdd or hd1b) minor=64
- * Tertiary i/f:   ide2: major=33; (hde)         minor=0; (hdf)         minor=64
- * Quaternary i/f: ide3: major=34; (hdg)         minor=0; (hdh)         minor=64
+ * Primary i/f:    ide0: major=3;  (hda) minor=0; (hdb) minor=64
+ * Secondary i/f:  ide1: major=22; (hdc) minor=0; (hdd) minor=64
+ * Tertiary i/f:   ide2: major=33; (hde) minor=0; (hdf) minor=64
+ * Quaternary i/f: ide3: major=34; (hdg) minor=0; (hdh) minor=64
  */
 
 /******************************************************************************
diff -urN linux-2.5.2-pre5/include/linux/kdev_t.h linux/include/linux/kdev_t.h
--- linux-2.5.2-pre5/include/linux/kdev_t.h	Fri Feb 16 16:06:17 2001
+++ linux/include/linux/kdev_t.h	Tue Jan  1 14:04:29 2002
@@ -57,48 +57,84 @@
 aeb - 950811
 */
 
-/* Since MINOR(dev) is used as index in static arrays,
-   the kernel is not quite ready yet for larger minors.
-   However, everything runs fine with an arbitrary kdev_t type. */
 
+/*
+ * NOTE NOTE NOTE!
+ *
+ * The kernel-internal "kdev_t" will eventually have
+ * 20 bits for minor numbers, and 12 bits for majors.
+ *
+ * HOWEVER, the external representation is still 8+8
+ * bits, and there is no way to generate the extended
+ * "kdev_t" format yet. Which is just as well, since
+ * we still use "minor" as an index into various
+ * static arrays, and they are sized for a 8-bit index.
+ */
+typedef struct {
+	unsigned short value;
+} kdev_t;
+
+#define KDEV_MINOR_BITS		8
+#define KDEV_MAJOR_BITS		8
+
+#define __mkdev(major,minor)	(((major) << KDEV_MINOR_BITS) + (minor))
+
+#define mk_kdev(major, minor)	((kdev_t) { __mkdev(major,minor) } )
+
+/*
+ * The "values" are just _cookies_, usable for 
+ * internal equality comparisons and for things
+ * like NFS filehandle conversion.
+ */
+static inline unsigned int kdev_val(kdev_t dev)
+{
+	return dev.value;
+}
+
+static inline kdev_t val_to_kdev(unsigned int val)
+{
+	kdev_t dev;
+	dev.value = val;
+	return dev;
+}
+
+#define HASHDEV(dev)	(kdev_val(dev))
+#define NODEV		(mk_kdev(0,0))
+#define B_FREE		(mk_kdev(0xff,0xff))
+
+extern const char * kdevname(kdev_t);	/* note: returns pointer to static data! */
+
+static inline int kdev_same(kdev_t dev1, kdev_t dev2)
+{
+	return dev1.value == dev2.value;
+}
+
+#define kdev_none(d1)	(!kdev_val(d1))
+
+/* Mask off the high bits for now.. */
+#define minor(dev)	((dev).value & 0xff)
+#define major(dev)	(((dev).value >> KDEV_MINOR_BITS) & 0xff)
+
+/* These are for user-level "dev_t" */
 #define MINORBITS	8
 #define MINORMASK	((1U << MINORBITS) - 1)
 
-typedef unsigned short kdev_t;
-
 #define MAJOR(dev)	((unsigned int) ((dev) >> MINORBITS))
 #define MINOR(dev)	((unsigned int) ((dev) & MINORMASK))
-#define HASHDEV(dev)	((unsigned int) (dev))
-#define NODEV		0
 #define MKDEV(ma,mi)	(((ma) << MINORBITS) | (mi))
-#define B_FREE		0xffff		/* yuk */
-
-extern const char * kdevname(kdev_t);	/* note: returns pointer to static data! */
 
 /*
-As long as device numbers in the outside world have 16 bits only,
-we use these conversions.
-*/
+ * Conversion functions
+ */
 
-static inline unsigned int kdev_t_to_nr(kdev_t dev) {
-	return (MAJOR(dev)<<8) | MINOR(dev);
+static inline int kdev_t_to_nr(kdev_t dev)
+{
+	return MKDEV(major(dev), minor(dev));
 }
 
 static inline kdev_t to_kdev_t(int dev)
 {
-	int major, minor;
-#if 0
-	major = (dev >> 16);
-	if (!major) {
-		major = (dev >> 8);
-		minor = (dev & 0xff);
-	} else
-		minor = (dev & 0xffff);
-#else
-	major = (dev >> 8);
-	minor = (dev & 0xff);
-#endif
-	return MKDEV(major, minor);
+	return mk_kdev(MAJOR(dev),MINOR(dev));
 }
 
 #else /* __KERNEL__ || _LVM_H_INCLUDE */
diff -urN linux-2.5.2-pre5/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h
--- linux-2.5.2-pre5/include/linux/nfsd/nfsfh.h	Sun Dec 16 15:44:19 2001
+++ linux/include/linux/nfsd/nfsfh.h	Tue Jan  1 14:04:29 2002
@@ -119,15 +119,37 @@
 
 /*
  * Conversion macros for the filehandle fields.
+ *
+ * Keep the device numbers in "backwards compatible
+ * format", ie the low 16 bits contain the low 8 bits
+ * of the 20-bit minor and the 12-bit major number.
+ *
+ * The high 16 bits contain the rest (4 bits major
+ * and 12 bits minor),
  */
 static inline __u32 kdev_t_to_u32(kdev_t dev)
 {
-	return (__u32) dev;
+	unsigned int minor = minor(dev);
+	unsigned int major = major(dev);
+	__u32 udev;
+
+	/* Create the low 16 bits.. */
+	udev = ((major & 0xff) << 8) + (minor & 0xff);
+
+	/* ..and then the rest. */
+	major >>= 8; minor >>= 8;
+	udev |= (major << 28) | (minor << 16);
+
+	return udev;
 }
 
 static inline kdev_t u32_to_kdev_t(__u32 udev)
 {
-	return (kdev_t) udev;
+	unsigned int minor, major;
+
+	minor = (udev & 0xff) | ((udev >> 8) & 0xfff00);
+	major = ((udev >> 8) & 0xff) | ((udev >> 20) & 0xf00);
+	return mk_kdev(major, minor);
 }
 
 static inline __u32 ino_t_to_u32(ino_t ino)
diff -urN linux-2.5.2-pre5/include/linux/raid/md_k.h linux/include/linux/raid/md_k.h
--- linux-2.5.2-pre5/include/linux/raid/md_k.h	Tue Jan  1 14:04:26 2002
+++ linux/include/linux/raid/md_k.h	Tue Jan  1 14:04:29 2002
@@ -77,9 +77,9 @@
 
 static inline mddev_t * kdev_to_mddev (kdev_t dev)
 {
-	if (MAJOR(dev) != MD_MAJOR)
+	if (major(dev) != MD_MAJOR)
 		BUG();
-        return mddev_map[MINOR(dev)].mddev;
+        return mddev_map[minor(dev)].mddev;
 }
 
 /*
@@ -256,7 +256,7 @@
 
 static inline kdev_t mddev_to_kdev(mddev_t * mddev)
 {
-	return MKDEV(MD_MAJOR, mdidx(mddev));
+	return mk_kdev(MD_MAJOR, mdidx(mddev));
 }
 
 extern mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev);
diff -urN linux-2.5.2-pre5/include/linux/usb.h linux/include/linux/usb.h
--- linux-2.5.2-pre5/include/linux/usb.h	Sun Dec 16 15:46:59 2001
+++ linux/include/linux/usb.h	Tue Jan  1 14:04:29 2002
@@ -521,7 +521,7 @@
 
 	struct semaphore serialize;
 
-	/* ioctl -- userspace apps can talk to drivers through usbdevfs */
+	/* ioctl -- userspace apps can talk to drivers through usbfs */
 	int (*ioctl)(struct usb_device *dev, unsigned int code, void *buf);
 
 	/* support for "new-style" USB hotplugging */
@@ -567,7 +567,7 @@
 	unsigned int length;		/* expected length */
 	unsigned int actual_length;
 	unsigned int status;
-} iso_packet_descriptor_t, *piso_packet_descriptor_t;
+} iso_packet_descriptor_t;
 
 struct urb;
 
@@ -629,7 +629,7 @@
  *
  * This structure identifies USB transfer requests.  URBs may be allocated
  * in any way, although usb_alloc_urb() is often convenient.  Initialization
- * may be done using various FILL_*_URB() macros.  URBs are submitted
+ * may be done using various usb_fill_*_urb() functions.  URBs are submitted
  * using usb_submit_urb(), and pending requests may be canceled using
  * usb_unlink_urb().
  *
@@ -729,87 +729,7 @@
 	iso_packet_descriptor_t iso_frame_desc[0];	/* (in) ISO ONLY */
 };
 
-typedef struct urb urb_t, *purb_t;
-
-/**
- * FILL_CONTROL_URB - macro to help initialize a control urb
- * @URB: pointer to the urb to initialize.
- * @DEV: pointer to the struct usb_device for this urb.
- * @PIPE: the endpoint pipe
- * @SETUP_PACKET: pointer to the setup_packet buffer
- * @TRANSFER_BUFFER: pointer to the transfer buffer
- * @BUFFER_LENGTH: length of the transfer buffer
- * @COMPLETE: pointer to the usb_complete_t function
- * @CONTEXT: what to set the urb context to.
- *
- * Initializes a control urb with the proper information needed to submit
- * it to a device.  This macro is depreciated, the usb_fill_control_urb()
- * function should be used instead.
- */
-#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
-    do {\
-	spin_lock_init(&(URB)->lock);\
-	(URB)->dev=DEV;\
-	(URB)->pipe=PIPE;\
-	(URB)->setup_packet=SETUP_PACKET;\
-	(URB)->transfer_buffer=TRANSFER_BUFFER;\
-	(URB)->transfer_buffer_length=BUFFER_LENGTH;\
-	(URB)->complete=COMPLETE;\
-	(URB)->context=CONTEXT;\
-    } while (0)
-
-/**
- * FILL_BULK_URB - macro to help initialize a bulk urb
- * @URB: pointer to the urb to initialize.
- * @DEV: pointer to the struct usb_device for this urb.
- * @PIPE: the endpoint pipe
- * @TRANSFER_BUFFER: pointer to the transfer buffer
- * @BUFFER_LENGTH: length of the transfer buffer
- * @COMPLETE: pointer to the usb_complete_t function
- * @CONTEXT: what to set the urb context to.
- *
- * Initializes a bulk urb with the proper information needed to submit it
- * to a device.  This macro is depreciated, the usb_fill_bulk_urb()
- * function should be used instead.
- */
-#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
-    do {\
-	spin_lock_init(&(URB)->lock);\
-	(URB)->dev=DEV;\
-	(URB)->pipe=PIPE;\
-	(URB)->transfer_buffer=TRANSFER_BUFFER;\
-	(URB)->transfer_buffer_length=BUFFER_LENGTH;\
-	(URB)->complete=COMPLETE;\
-	(URB)->context=CONTEXT;\
-    } while (0)
-    
-/**
- * FILL_INT_URB - macro to help initialize a interrupt urb
- * @URB: pointer to the urb to initialize.
- * @DEV: pointer to the struct usb_device for this urb.
- * @PIPE: the endpoint pipe
- * @TRANSFER_BUFFER: pointer to the transfer buffer
- * @BUFFER_LENGTH: length of the transfer buffer
- * @COMPLETE: pointer to the usb_complete_t function
- * @CONTEXT: what to set the urb context to.
- * @INTERVAL: what to set the urb interval to.
- *
- * Initializes a interrupt urb with the proper information needed to submit
- * it to a device.  This macro is depreciated, the usb_fill_int_urb()
- * function should be used instead.
- */
-#define FILL_INT_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL) \
-    do {\
-	spin_lock_init(&(URB)->lock);\
-	(URB)->dev=DEV;\
-	(URB)->pipe=PIPE;\
-	(URB)->transfer_buffer=TRANSFER_BUFFER;\
-	(URB)->transfer_buffer_length=BUFFER_LENGTH;\
-	(URB)->complete=COMPLETE;\
-	(URB)->context=CONTEXT;\
-	(URB)->interval=INTERVAL;\
-	(URB)->start_frame=-1;\
-    } while (0)
+typedef struct urb urb_t;
 
 /**
  * usb_fill_control_urb - initializes a control urb
@@ -908,11 +828,22 @@
 	urb->interval = interval;
 	urb->start_frame = -1;
 }
-    
+
+/*
+ * old style macros to enable 2.4 and 2.2 drivers to build
+ * properly.  Please do not use these for new USB drivers.
+ */
+#define FILL_CONTROL_URB(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
+    usb_fill_control_urb(URB,DEV,PIPE,SETUP_PACKET,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT)
+#define FILL_BULK_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT) \
+    usb_fill_bulk_urb(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT)
+#define FILL_INT_URB(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL) \
+    usb_fill_int_urb(URB,DEV,PIPE,TRANSFER_BUFFER,BUFFER_LENGTH,COMPLETE,CONTEXT,INTERVAL)
+
 extern struct urb *usb_alloc_urb(int iso_packets);
-extern void usb_free_urb(struct urb *purb);
-extern int usb_submit_urb(struct urb *purb);
-extern int usb_unlink_urb(struct urb *purb);
+extern void usb_free_urb(struct urb *urb);
+extern int usb_submit_urb(struct urb *urb);
+extern int usb_unlink_urb(struct urb *urb);
 
 /*-------------------------------------------------------------------*
  *                         SYNCHRONOUS CALL SUPPORT                  *
@@ -959,8 +890,8 @@
 	int (*allocate)(struct usb_device *);
 	int (*deallocate)(struct usb_device *);
 	int (*get_frame_number) (struct usb_device *usb_dev);
-	int (*submit_urb) (struct urb* purb);
-	int (*unlink_urb) (struct urb* purb);
+	int (*submit_urb) (struct urb *urb);
+	int (*unlink_urb) (struct urb *urb);
 };
 
 #define DEVNUM_ROUND_ROBIN	/***** OPTION *****/
@@ -989,8 +920,7 @@
 	int bandwidth_int_reqs;		/* number of Interrupt requesters */
 	int bandwidth_isoc_reqs;	/* number of Isoc. requesters */
 
-	/* usbdevfs inode list */
-	struct list_head inodes;
+	struct dentry *dentry;		/* usbfs dentry entry for the bus */
 
 	atomic_t refcnt;
 };
@@ -1028,6 +958,21 @@
 #define NS_TO_US(ns)	((ns + 500L) / 1000L)
 			/* convert & round nanoseconds to microseconds */
 
+/*
+ * As of USB 2.0, full/low speed devices are segregated into trees.
+ * One type grows from USB 1.1 host controllers (OHCI, UHCI etc).
+ * The other type grows from high speed hubs when they connect to
+ * full/low speed devices using "Transaction Translators" (TTs).
+ *
+ * TTs should only be known to the hub driver, and high speed bus
+ * drivers (only EHCI for now).  They affect periodic scheduling and
+ * sometimes control/bulk error recovery.
+ */
+struct usb_tt {
+	struct usb_device	*hub;	/* upstream highspeed hub */
+	int			multi;	/* true means one TT per port */
+};
+
 
 /* -------------------------------------------------------------------------- */
 
@@ -1056,7 +1001,8 @@
 #define USB_MAXCHILDREN		(16)
 
 struct usb_device {
-	int devnum;			/* Device number on USB bus */
+	int		devnum;		/* Address on USB bus */
+	char		devpath [16];	/* Use in messages: /port/port/... */
 
 	enum {
 		USB_SPEED_UNKNOWN = 0,			/* enumerating */
@@ -1064,8 +1010,8 @@
 		USB_SPEED_HIGH				/* usb 2.0 */
 	} speed;
 
-	struct usb_device *tt;		/* usb1.1 device on usb2.0 bus */
-	int ttport;			/* device/hub port on that tt */
+	struct usb_tt	*tt; 		/* low/full speed dev, highspeed hub */
+	int		ttport;		/* device port on that tt hub */
 
 	atomic_t refcnt;		/* Reference count */
 	struct semaphore serialize;
@@ -1090,9 +1036,8 @@
   
 	void *hcpriv;			/* Host Controller private data */
 	
-        /* usbdevfs inode list */
-	struct list_head inodes;
 	struct list_head filelist;
+	struct dentry *dentry;		/* usbfs dentry entry for the device */
 
 	/*
 	 * Child devices - these can be either new devices
@@ -1254,7 +1199,7 @@
 
 /*
  * bus and driver list
- * exported only for usbdevfs (not visible outside usbcore)
+ * exported only for usbfs (not visible outside usbcore)
  */
 
 extern struct list_head usb_driver_list;
@@ -1271,23 +1216,25 @@
  * these are expected to be called from the USB core/hub thread
  * with the kernel lock held
  */
-extern void usbdevfs_add_bus(struct usb_bus *bus);
-extern void usbdevfs_remove_bus(struct usb_bus *bus);
-extern void usbdevfs_add_device(struct usb_device *dev);
-extern void usbdevfs_remove_device(struct usb_device *dev);
+extern void usbfs_add_bus(struct usb_bus *bus);
+extern void usbfs_remove_bus(struct usb_bus *bus);
+extern void usbfs_add_device(struct usb_device *dev);
+extern void usbfs_remove_device(struct usb_device *dev);
+extern void usbfs_update_special (void);
 
-extern int usbdevfs_init(void);
-extern void usbdevfs_cleanup(void);
+extern int usbfs_init(void);
+extern void usbfs_cleanup(void);
 
 #else /* CONFIG_USB_DEVICEFS */
 
-static inline void usbdevfs_add_bus(struct usb_bus *bus) {}
-static inline void usbdevfs_remove_bus(struct usb_bus *bus) {}
-static inline void usbdevfs_add_device(struct usb_device *dev) {}
-static inline void usbdevfs_remove_device(struct usb_device *dev) {}
+static inline void usbfs_add_bus(struct usb_bus *bus) {}
+static inline void usbfs_remove_bus(struct usb_bus *bus) {}
+static inline void usbfs_add_device(struct usb_device *dev) {}
+static inline void usbfs_remove_device(struct usb_device *dev) {}
+static inline void usbfs_update_special (void) {}
 
-static inline int usbdevfs_init(void) { return 0; }
-static inline void usbdevfs_cleanup(void) { }
+static inline int usbfs_init(void) { return 0; }
+static inline void usbfs_cleanup(void) { }
 
 #endif /* CONFIG_USB_DEVICEFS */
 
diff -urN linux-2.5.2-pre5/include/linux/usbdevice_fs.h linux/include/linux/usbdevice_fs.h
--- linux-2.5.2-pre5/include/linux/usbdevice_fs.h	Sun Dec 16 15:47:13 2001
+++ linux/include/linux/usbdevice_fs.h	Tue Jan  1 14:04:29 2002
@@ -150,17 +150,6 @@
 #include <linux/list.h>
 #include <asm/semaphore.h>
 
-/*
- * inode number macros
- */
-#define ITYPE(x)   ((x)&(0xf<<28))
-#define ISPECIAL   (0<<28)
-#define IBUS       (1<<28)
-#define IDEVICE    (2<<28)
-#define IBUSNR(x)  (((x)>>8)&0xff)
-#define IDEVNR(x)  ((x)&0xff)
-
-#define IROOT      1
 
 struct dev_state {
 	struct list_head list;      /* state list */
diff -urN linux-2.5.2-pre5/init/do_mounts.c linux/init/do_mounts.c
--- linux-2.5.2-pre5/init/do_mounts.c	Tue Jan  1 14:04:26 2002
+++ linux/init/do_mounts.c	Tue Jan  1 14:04:29 2002
@@ -1,5 +1,7 @@
 #define __KERNEL_SYSCALLS__
 #include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/unistd.h>
@@ -7,6 +9,7 @@
 #include <linux/blk.h>
 #include <linux/fd.h>
 #include <linux/tty.h>
+#include <linux/init.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
@@ -351,8 +354,8 @@
 	if (!do_devfs)
 		return sys_mknod(name, S_IFBLK|0600, kdev_t_to_nr(dev));
 
-	handle = devfs_find_handle(NULL, dev ? NULL : devfs_name,
-				MAJOR(dev), MINOR(dev), DEVFS_SPECIAL_BLK, 1);
+	handle = devfs_find_handle(NULL, kdev_none(dev) ? devfs_name : NULL,
+				major(dev), minor(dev), DEVFS_SPECIAL_BLK, 1);
 	if (!handle)
 		return -1;
 	n = devfs_generate_path(handle, path + 5, sizeof (path) - 5);
@@ -707,11 +710,11 @@
 	devfs_make_root(root_device_name);
 	create_dev("/dev/root", ROOT_DEV, root_device_name);
 #ifdef CONFIG_BLK_DEV_FD
-	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+	if (major(ROOT_DEV) == FLOPPY_MAJOR) {
 		/* rd_doload is 2 for a dual initrd/ramload setup */
 		if (rd_doload==2) {
 			if (rd_load_disk(1)) {
-				ROOT_DEV = MKDEV(RAMDISK_MAJOR, 1);
+				ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 1);
 				create_dev("/dev/root", ROOT_DEV, NULL);
 			}
 		} else
@@ -809,7 +812,7 @@
  */
 void prepare_namespace(void)
 {
-	int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
+	int is_floppy = major(ROOT_DEV) == FLOPPY_MAJOR;
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (!initrd_start)
 		mount_initrd = 0;
@@ -825,12 +828,12 @@
 
 	create_dev("/dev/root", ROOT_DEV, NULL);
 	if (mount_initrd) {
-		if (initrd_load() && ROOT_DEV != MKDEV(RAMDISK_MAJOR, 0)) {
+		if (initrd_load() && kdev_same(ROOT_DEV, mk_kdev(RAMDISK_MAJOR, 0))) {
 			handle_initrd();
 			goto out;
 		}
 	} else if (is_floppy && rd_doload && rd_load_disk(0))
-		ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+		ROOT_DEV = mk_kdev(RAMDISK_MAJOR, 0);
 	mount_root();
 out:
 	sys_umount("/dev", 0);
diff -urN linux-2.5.2-pre5/kernel/sched.c linux/kernel/sched.c
--- linux-2.5.2-pre5/kernel/sched.c	Tue Jan  1 14:04:26 2002
+++ linux/kernel/sched.c	Tue Jan  1 14:04:29 2002
@@ -51,25 +51,16 @@
  * NOTE! The unix "nice" value influences how long a process
  * gets. The nice value ranges from -20 to +19, where a -20
  * is a "high-priority" task, and a "+10" is a low-priority
- * task.
- *
- * We want the time-slice to be around 50ms or so, so this
- * calculation depends on the value of HZ.
+ * task. The default time slice for zero-nice tasks will be 43ms.
  */
-#if HZ < 200
-#define TICK_SCALE(x)	((x) >> 2)
-#elif HZ < 400
-#define TICK_SCALE(x)	((x) >> 1)
-#elif HZ < 800
-#define TICK_SCALE(x)	(x)
-#elif HZ < 1600
-#define TICK_SCALE(x)	((x) << 1)
-#else
-#define TICK_SCALE(x)	((x) << 2)
-#endif
+#define NICE_RANGE	40
+#define MIN_NICE_TSLICE	10000
+#define MAX_NICE_TSLICE	80000
+#define TASK_TIMESLICE(p)	((int) ts_table[19 - (p)->nice])
 
-#define TASK_TIMESLICE(p)	(TICK_SCALE(20-(p)->nice)+1)
+static unsigned char ts_table[NICE_RANGE];
 
+#define MM_AFFINITY_BONUS	1
 
 /*
  *	Init task must be ok at boot for the ix86 as we will check its signals
@@ -181,7 +172,7 @@
 
 		/* .. and a slight advantage to the current MM */
 		if (p->mm == this_mm || !p->mm)
-			weight += 1;
+			weight += MM_AFFINITY_BONUS;
 		weight += 20 - p->nice;
 		goto out;
 	}
@@ -1328,6 +1319,15 @@
 
 extern void init_timervecs (void);
 
+static void fill_tslice_map(void)
+{
+	int i;
+
+	for (i = 0; i < NICE_RANGE; i++)
+		ts_table[i] = ((MIN_NICE_TSLICE +
+						((MAX_NICE_TSLICE - MIN_NICE_TSLICE) / NICE_RANGE) * i) * HZ) / 1000000;
+}
+
 void __init sched_init(void)
 {
 	/*
@@ -1341,6 +1341,8 @@
 
 	for(nr = 0; nr < PIDHASH_SZ; nr++)
 		pidhash[nr] = NULL;
+
+	fill_tslice_map();
 
 	init_timervecs();
 
diff -urN linux-2.5.2-pre5/mm/filemap.c linux/mm/filemap.c
--- linux-2.5.2-pre5/mm/filemap.c	Sun Dec 16 15:21:24 2001
+++ linux/mm/filemap.c	Tue Jan  1 14:04:29 2002
@@ -1132,9 +1132,9 @@
 
 static inline int get_max_readahead(struct inode * inode)
 {
-	if (!inode->i_dev || !max_readahead[MAJOR(inode->i_dev)])
+	if (kdev_none(inode->i_dev) || !max_readahead[major(inode->i_dev)])
 		return MAX_READAHEAD;
-	return max_readahead[MAJOR(inode->i_dev)][MINOR(inode->i_dev)];
+	return max_readahead[major(inode->i_dev)][minor(inode->i_dev)];
 }
 
 static void generic_file_readahead(int reada_ok,
diff -urN linux-2.5.2-pre5/mm/page_io.c linux/mm/page_io.c
--- linux-2.5.2-pre5/mm/page_io.c	Tue Nov 27 09:23:27 2001
+++ linux/mm/page_io.c	Tue Jan  1 14:04:29 2002
@@ -38,7 +38,7 @@
 	unsigned long offset;
 	sector_t zones[PAGE_SIZE/512];
 	int zones_used;
-	kdev_t dev = 0;
+	kdev_t dev = NODEV;
 	int block_size;
 	struct inode *swapf = 0;
 
@@ -49,7 +49,7 @@
 		kstat.pswpout++;
 
 	get_swaphandle_info(entry, &offset, &dev, &swapf);
-	if (dev) {
+	if (!kdev_none(dev)) {
 		zones[0] = offset;
 		zones_used = 1;
 		block_size = PAGE_SIZE;
diff -urN linux-2.5.2-pre5/mm/swapfile.c linux/mm/swapfile.c
--- linux-2.5.2-pre5/mm/swapfile.c	Tue Jan  1 14:04:26 2002
+++ linux/mm/swapfile.c	Tue Jan  1 14:04:29 2002
@@ -774,7 +774,7 @@
 		swap_list_unlock();
 		goto out_dput;
 	}
-	if (p->swap_device)
+	if (!kdev_none(p->swap_device))
 		blkdev_put(p->swap_file->d_inode->i_bdev, BDEV_SWAP);
 	path_release(&nd);
 
@@ -784,7 +784,7 @@
 	nd.dentry = p->swap_file;
 	p->swap_vfsmnt = NULL;
 	p->swap_file = NULL;
-	p->swap_device = 0;
+	p->swap_device = NODEV;
 	p->max = 0;
 	swap_map = p->swap_map;
 	p->swap_map = NULL;
@@ -826,7 +826,7 @@
 				}
 			len += sprintf(buf + len, "%-39s %s\t%d\t%d\t%d\n",
 				       path,
-				       ptr->swap_device ? "partition" : "file\t",
+				       kdev_none(ptr->swap_device) ? "file\t" : "partition",
 				       ptr->pages << (PAGE_SHIFT - 10),
 				       usedswap << (PAGE_SHIFT - 10),
 				       ptr->prio);
@@ -842,7 +842,7 @@
 
 	for (i = 0 ; i < nr_swapfiles ; i++, ptr++) {
 		if (ptr->flags & SWP_USED)
-			if (ptr->swap_device == dev)
+			if (kdev_same(ptr->swap_device, dev))
 				return 1;
 	}
 	return 0;
@@ -888,7 +888,7 @@
 	p->flags = SWP_USED;
 	p->swap_file = NULL;
 	p->swap_vfsmnt = NULL;
-	p->swap_device = 0;
+	p->swap_device = NODEV;
 	p->swap_map = NULL;
 	p->lowest_bit = 0;
 	p->highest_bit = 0;
@@ -931,12 +931,12 @@
 			goto bad_swap_2;
 		set_blocksize(dev, PAGE_SIZE);
 		error = -ENODEV;
-		if (!dev || (blk_size[MAJOR(dev)] &&
-		     !blk_size[MAJOR(dev)][MINOR(dev)]))
+		if (kdev_none(dev) || (blk_size[major(dev)] &&
+		     !blk_size[major(dev)][minor(dev)]))
 			goto bad_swap;
 		swapfilesize = 0;
-		if (blk_size[MAJOR(dev)])
-			swapfilesize = blk_size[MAJOR(dev)][MINOR(dev)]
+		if (blk_size[major(dev)])
+			swapfilesize = blk_size[major(dev)][minor(dev)]
 				>> (PAGE_SHIFT - 10);
 	} else if (S_ISREG(swap_inode->i_mode))
 		swapfilesize = swap_inode->i_size >> PAGE_SHIFT;
@@ -1092,7 +1092,7 @@
 	swap_map = p->swap_map;
 	nd.mnt = p->swap_vfsmnt;
 	nd.dentry = p->swap_file;
-	p->swap_device = 0;
+	p->swap_device = NODEV;
 	p->swap_file = NULL;
 	p->swap_vfsmnt = NULL;
 	p->swap_map = NULL;
@@ -1245,7 +1245,7 @@
 		return;
 	}
 
-	if (p->swap_device) {
+	if (!kdev_none(p->swap_device)) {
 		*dev = p->swap_device;
 	} else if (p->swap_file) {
 		*swapf = p->swap_file->d_inode;
