diff -u --recursive --new-file pre1/linux/Documentation/DocBook/kernel-hacking.tmpl linux/Documentation/DocBook/kernel-hacking.tmpl
--- pre1/linux/Documentation/DocBook/kernel-hacking.tmpl	Thu Dec 20 08:54:23 2001
+++ linux/Documentation/DocBook/kernel-hacking.tmpl	Tue Jan 15 13:53:50 2002
@@ -371,8 +371,7 @@
   </para>
 
   <programlisting>
-if (current-&gt;need_resched)
-        schedule(); /* Will sleep */ 
+cond_resched(); /* Will sleep */ 
   </programlisting>
 
   <para>
diff -u --recursive --new-file pre1/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- pre1/linux/Documentation/ioctl-number.txt	Wed Jul 11 16:35:37 2001
+++ linux/Documentation/ioctl-number.txt	Thu Jan 17 14:06:53 2002
@@ -101,7 +101,8 @@
 'S'	82-FF	scsi/scsi.h		conflict!
 'T'	all	linux/soundcard.h	conflict!
 'T'	all	asm-i386/ioctls.h	conflict!
-'U'	all	linux/drivers/usb/usb.h
+'U'	00-EF	linux/drivers/usb/usb.h
+'U'	F0-FF	drivers/usb/auerswald.c
 'V'	all	linux/vt.h
 'W'	00-1F	linux/watchdog.h	conflict!
 'W'	00-1F	linux/wanrouter.h	conflict!
diff -u --recursive --new-file pre1/linux/Makefile linux/Makefile
--- pre1/linux/Makefile	Wed Jan 16 11:16:28 2002
+++ linux/Makefile	Wed Jan 16 11:14:10 2002
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 3
-EXTRAVERSION =-pre1
+EXTRAVERSION =-pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file pre1/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- pre1/linux/arch/arm/kernel/ecard.c	Wed Jan 16 11:16:28 2002
+++ linux/arch/arm/kernel/ecard.c	Thu Jan 17 14:21:16 2002
@@ -1097,6 +1097,8 @@
 	ecard_proc_init();
 }
 
+subsys_initcall(ecard_init);
+
 EXPORT_SYMBOL(ecard_startfind);
 EXPORT_SYMBOL(ecard_find);
 EXPORT_SYMBOL(ecard_readchunk);
diff -u --recursive --new-file pre1/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- pre1/linux/arch/arm/kernel/process.c	Sat Jan  5 13:04:30 2002
+++ linux/arch/arm/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -91,7 +91,7 @@
 		if (!idle)
 			idle = arch_idle;
 		leds_event(led_idle_start);
-		while (!current->need_resched)
+		while (!need_resched())
 			idle();
 		leds_event(led_idle_end);
 		schedule();
diff -u --recursive --new-file pre1/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- pre1/linux/arch/i386/kernel/apm.c	Fri Nov 30 08:38:44 2001
+++ linux/arch/i386/kernel/apm.c	Tue Jan 15 13:53:50 2002
@@ -766,14 +766,14 @@
 
 	start_idle = jiffies;
 	while (1) {
-		if (!current->need_resched) {
+		if (!need_resched()) {
 			if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {
 				if (!current_cpu_data.hlt_works_ok)
 					continue;
 				if (hlt_counter)
 					continue;
 				__cli();
-				if (!current->need_resched)
+				if (!need_resched())
 					safe_halt();
 				else
 					__sti();
diff -u --recursive --new-file pre1/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- pre1/linux/arch/i386/kernel/mca.c	Thu Aug 24 12:52:32 2000
+++ linux/arch/i386/kernel/mca.c	Thu Jan 17 14:21:16 2002
@@ -311,6 +311,8 @@
 #endif
 }
 
+subsys_initcall(mca_init);
+
 /*--------------------------------------------------------------------*/
 
 static void mca_handle_nmi_slot(int slot, int check_flag)
diff -u --recursive --new-file pre1/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- pre1/linux/arch/i386/kernel/process.c	Mon Jan  7 12:55:17 2002
+++ linux/arch/i386/kernel/process.c	Tue Jan 15 14:33:55 2002
@@ -42,7 +42,6 @@
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/desc.h>
-#include <asm/mmu_context.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
@@ -81,7 +80,7 @@
 {
 	if (current_cpu_data.hlt_works_ok && !hlt_counter) {
 		__cli();
-		if (!current->need_resched)
+		if (!need_resched())
 			safe_halt();
 		else
 			__sti();
@@ -127,7 +126,7 @@
 		void (*idle)(void) = pm_idle;
 		if (!idle)
 			idle = default_idle;
-		while (!current->need_resched)
+		while (!need_resched())
 			idle();
 		schedule();
 		check_pgt_cache();
diff -u --recursive --new-file pre1/linux/arch/i386/math-emu/fpu_entry.c linux/arch/i386/math-emu/fpu_entry.c
--- pre1/linux/arch/i386/math-emu/fpu_entry.c	Fri Apr  6 10:42:47 2001
+++ linux/arch/i386/math-emu/fpu_entry.c	Tue Jan 15 13:53:50 2002
@@ -559,7 +559,7 @@
   RE_ENTRANT_CHECK_ON;
 #endif /* DEBUG */
 
-  if (FPU_lookahead && !current->need_resched)
+  if (FPU_lookahead && !need_resched())
     {
       FPU_ORIG_EIP = FPU_EIP - code_base;
       if ( valid_prefix(&byte1, (u_char **)&FPU_EIP,
diff -u --recursive --new-file pre1/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- pre1/linux/arch/i386/vmlinux.lds	Mon Jul  2 14:40:14 2001
+++ linux/arch/i386/vmlinux.lds	Thu Jan 17 14:21:16 2002
@@ -48,7 +48,15 @@
   .setup.init : { *(.setup.init) }
   __setup_end = .;
   __initcall_start = .;
-  .initcall.init : { *(.initcall.init) }
+  .initcall.init : {
+	*(.initcall1.init) 
+	*(.initcall2.init) 
+	*(.initcall3.init) 
+	*(.initcall4.init) 
+	*(.initcall5.init) 
+	*(.initcall6.init) 
+	*(.initcall7.init)
+  }
   __initcall_end = .;
   . = ALIGN(4096);
   __init_end = .;
diff -u --recursive --new-file pre1/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c
--- pre1/linux/arch/ia64/kernel/process.c	Thu Dec 27 08:21:28 2001
+++ linux/arch/ia64/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -117,10 +117,10 @@
 
 	while (1) {
 #ifdef CONFIG_SMP
-		if (!current->need_resched)
+		if (!need_resched())
 			min_xtp();
 #endif
-		while (!current->need_resched)
+		while (!need_resched())
 			continue;
 #ifdef CONFIG_SMP
 		normal_xtp();
diff -u --recursive --new-file pre1/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- pre1/linux/arch/m68k/kernel/process.c	Thu Dec 27 08:21:28 2001
+++ linux/arch/m68k/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -56,7 +56,7 @@
 static void default_idle(void)
 {
 	while(1) {
-		if (!current->need_resched)
+		if (!need_resched())
 #if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
 			/* block out HSYNC on the atari (falcon) */
 			__asm__("stop #0x2200" : : : "cc");
diff -u --recursive --new-file pre1/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
--- pre1/linux/arch/mips/kernel/process.c	Thu Dec 27 08:21:28 2001
+++ linux/arch/mips/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -39,7 +39,7 @@
 	init_idle();
 
 	while (1) {
-		while (!current->need_resched)
+		while (!need_resched())
 			if (cpu_wait)
 				(*cpu_wait)();
 		schedule();
diff -u --recursive --new-file pre1/linux/arch/mips/math-emu/cp1emu.c linux/arch/mips/math-emu/cp1emu.c
--- pre1/linux/arch/mips/math-emu/cp1emu.c	Sun Sep  9 10:43:01 2001
+++ linux/arch/mips/math-emu/cp1emu.c	Tue Jan 15 13:53:50 2002
@@ -1674,8 +1674,7 @@
 
 	oldepc = xcp->cp0_epc;
 	do {
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		prevepc = xcp->cp0_epc;
 		insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
diff -u --recursive --new-file pre1/linux/arch/mips64/kernel/process.c linux/arch/mips64/kernel/process.c
--- pre1/linux/arch/mips64/kernel/process.c	Thu Dec 27 08:21:28 2001
+++ linux/arch/mips64/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -35,7 +35,7 @@
 	init_idle();
 	current->nice = 20;
 	while (1) {
-		while (!current->need_resched)
+		while (!need_resched())
 			if (wait_available)
 				__asm__("wait");
 		schedule();
diff -u --recursive --new-file pre1/linux/arch/mips64/math-emu/cp1emu.c linux/arch/mips64/math-emu/cp1emu.c
--- pre1/linux/arch/mips64/math-emu/cp1emu.c	Sun Sep  9 10:43:02 2001
+++ linux/arch/mips64/math-emu/cp1emu.c	Tue Jan 15 13:53:50 2002
@@ -1707,8 +1707,7 @@
 
 	oldepc = xcp->cp0_epc;
 	do {
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		prevepc = xcp->cp0_epc;
 		insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
diff -u --recursive --new-file pre1/linux/arch/parisc/kernel/process.c linux/arch/parisc/kernel/process.c
--- pre1/linux/arch/parisc/kernel/process.c	Thu Dec 27 08:21:28 2001
+++ linux/arch/parisc/kernel/process.c	Tue Jan 15 13:57:50 2002
@@ -73,8 +73,8 @@
 	current->nice = 20;
 
 	while (1) {
-		while (!current->need_resched) {
-		}
+		while (!need_resched())
+			barrier();
 		schedule();
 		check_pgt_cache();
 	}
diff -u --recursive --new-file pre1/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- pre1/linux/arch/ppc/kernel/idle.c	Thu Dec 27 08:21:28 2001
+++ linux/arch/ppc/kernel/idle.c	Tue Jan 15 13:57:16 2002
@@ -66,15 +66,15 @@
 			int oldval = xchg(&current->need_resched, -1);
 
 			if (!oldval) {
-				while(current->need_resched == -1)
-					; /* Do Nothing */
+				while (need_resched())
+					barrier(); /* Do Nothing */
 			}
 		}
 #endif
-		if (do_power_save && !current->need_resched)
+		if (do_power_save && !need_resched())
 			power_save();
 
-		if (current->need_resched) {
+		if (need_resched()) {
 			schedule();
 			check_pgt_cache();
 		}
@@ -150,7 +150,7 @@
 
 	if ( atomic_read(&zero_cache_sz) >= zero_cache_water[0] )
 		return;
-	while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && (!current->need_resched) )
+	while ( (atomic_read(&zero_cache_sz) < zero_cache_water[1]) && !need_resched() )
 	{
 		/*
 		 * Mark a page as reserved so we can mess with it
@@ -161,8 +161,7 @@
 		if ( !pageptr )
 			return;
 		
-		if ( current->need_resched )
-			schedule();
+		cond_resched();
 		
 		/*
 		 * Make the page no cache so we don't blow our cache with 0's
@@ -181,8 +180,7 @@
 		 */
 		for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
 		{
-			if ( current->need_resched )
-				schedule();
+			cond_resched();
 			*(unsigned long *)(bytecount + pageptr) = 0;
 		}
 		
@@ -243,7 +241,7 @@
 	 *  -- Cort
 	 */
 	_nmask_and_or_msr(MSR_EE, 0);
-	if (!current->need_resched)
+	if (!need_resched())
 	{
 		asm("mfspr %0,1008" : "=r" (hid0) :);
 		hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
diff -u --recursive --new-file pre1/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- pre1/linux/arch/ppc/kernel/setup.c	Wed Jan 16 11:16:28 2002
+++ linux/arch/ppc/kernel/setup.c	Thu Jan 17 14:21:16 2002
@@ -535,6 +535,8 @@
 	}
 }
 
+subsys_initcall(ppc_init);
+
 /* Warning, IO base is not yet inited */
 void __init setup_arch(char **cmdline_p)
 {
diff -u --recursive --new-file pre1/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
--- pre1/linux/arch/s390/kernel/process.c	Thu Dec 27 08:21:28 2001
+++ linux/arch/s390/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -60,7 +60,7 @@
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
 	while(1) {
-                if (current->need_resched) {
+                if (need_resched()) {
                         schedule();
                         check_pgt_cache();
                         continue;
diff -u --recursive --new-file pre1/linux/arch/s390x/kernel/process.c linux/arch/s390x/kernel/process.c
--- pre1/linux/arch/s390x/kernel/process.c	Thu Dec 27 08:21:28 2001
+++ linux/arch/s390x/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -60,7 +60,7 @@
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup;
 	while(1) {
-                if (current->need_resched) {
+                if (need_resched()) {
                         schedule();
                         check_pgt_cache();
                         continue;
diff -u --recursive --new-file pre1/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- pre1/linux/arch/sh/kernel/process.c	Thu Dec 27 08:21:28 2001
+++ linux/arch/sh/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -44,11 +44,11 @@
 
 	while (1) {
 		if (hlt_counter) {
-			if (current->need_resched)
+			if (need_resched())
 				break;
 		} else {
 			__cli();
-			while (!current->need_resched) {
+			while (!need_resched()) {
 				__sti();
 				asm volatile("sleep" : : : "memory");
 				__cli();
diff -u --recursive --new-file pre1/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- pre1/linux/arch/sparc/kernel/process.c	Mon Jan 14 10:10:43 2002
+++ linux/arch/sparc/kernel/process.c	Tue Jan 15 13:53:50 2002
@@ -106,7 +106,7 @@
 {
 	/* endless idle loop with no priority at all */
 	while(1) {
-		if(current->need_resched) {
+		if(need_resched()) {
 			schedule();
 			check_pgt_cache();
 		}
diff -u --recursive --new-file pre1/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- pre1/linux/arch/sparc64/kernel/process.c	Mon Jan 14 10:10:44 2002
+++ linux/arch/sparc64/kernel/process.c	Tue Jan 15 13:53:51 2002
@@ -61,7 +61,7 @@
 		 * But this requires writing back the contents of the
 		 * L2 cache etc. so implement this later. -DaveM
 		 */
-		while (!current->need_resched)
+		while (!need_resched())
 			barrier();
 
 		schedule();
@@ -80,7 +80,7 @@
 int cpu_idle(void)
 {
 	while(1) {
-		if (current->need_resched != 0) {
+		if (need_resched()) {
 			unidle_me();
 			schedule();
 			check_pgt_cache();
diff -u --recursive --new-file pre1/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- pre1/linux/drivers/block/ll_rw_blk.c	Thu Jan 10 10:15:38 2002
+++ linux/drivers/block/ll_rw_blk.c	Thu Jan 17 13:59:33 2002
@@ -186,7 +186,8 @@
 	 * full 4GB zone, so we have to resort to low memory for any bounces.
 	 * ISA has its own < 16MB zone.
 	 */
-	if (dma_addr == BLK_BOUNCE_ISA) {
+	if (bounce_pfn < blk_max_low_pfn) {
+		BUG_ON(dma_addr < BLK_BOUNCE_ISA);
 		init_emergency_isa_pool();
 		q->bounce_gfp = GFP_NOIO | GFP_DMA;
 	} else
@@ -302,8 +303,8 @@
 static char *rq_flags[] = { "REQ_RW", "REQ_RW_AHEAD", "REQ_BARRIER",
 			   "REQ_CMD", "REQ_NOMERGE", "REQ_STARTED",
 			   "REQ_DONTPREP", "REQ_DRIVE_CMD", "REQ_DRIVE_TASK",
-			   "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE",
-			   "REQ_SPECIAL" };
+			   "REQ_DRIVE_ACB", "REQ_PC", "REQ_BLOCK_PC",
+			   "REQ_SENSE", "REQ_SPECIAL" };
 
 void blk_dump_rq_flags(struct request *rq, char *msg)
 {
@@ -1708,7 +1709,11 @@
 	printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests);
 
 	blk_max_low_pfn = max_low_pfn;
+#ifdef CONFIG_HIGHMEM
 	blk_max_pfn = max_pfn;
+#else
+	blk_max_pfn = max_low_pfn;
+#endif
 
 #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_IDE)
 	ide_init();		/* this MUST precede hd_init */
diff -u --recursive --new-file pre1/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- pre1/linux/drivers/char/lp.c	Fri Jan  4 21:19:50 2002
+++ linux/drivers/char/lp.c	Tue Jan 15 13:53:51 2002
@@ -367,7 +367,7 @@
 			  = lp_negotiate (port, 
 					  lp_table[minor].best_mode);
 
-		} else if (current->need_resched)
+		} else if (need_resched())
 			schedule ();
 
 		if (count) {
diff -u --recursive --new-file pre1/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- pre1/linux/drivers/char/mem.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/char/mem.c	Tue Jan 15 13:53:51 2002
@@ -381,8 +381,7 @@
 		unsigned long unwritten = clear_user(buf, PAGE_SIZE);
 		if (unwritten)
 			return size + unwritten - PAGE_SIZE;
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 		buf += PAGE_SIZE;
 		size -= PAGE_SIZE;
 	} while (size);
diff -u --recursive --new-file pre1/linux/drivers/char/mwave/3780i.c linux/drivers/char/mwave/3780i.c
--- pre1/linux/drivers/char/mwave/3780i.c	Sun Sep 30 12:26:05 2001
+++ linux/drivers/char/mwave/3780i.c	Tue Jan 15 13:53:51 2002
@@ -68,11 +68,9 @@
 
 static void PaceMsaAccess(unsigned short usDspBaseIO)
 {
-	if(current->need_resched)
-		schedule();
+	cond_resched();
 	udelay(100);
-	if(current->need_resched)
-		schedule();
+	cond_resched();
 }
 
 unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
diff -u --recursive --new-file pre1/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- pre1/linux/drivers/char/ppdev.c	Tue Jan  1 18:55:31 2002
+++ linux/drivers/char/ppdev.c	Tue Jan 15 13:53:51 2002
@@ -170,9 +170,7 @@
 			break;
 		}
 
-		if (current->need_resched) {
-			schedule ();
-		}
+		cond_resched();
 	}
 
 	kfree (kbuffer);
@@ -242,9 +240,7 @@
 			break;
 		}
 
-		if (current->need_resched) {
-			schedule ();
-		}
+		cond_resched();
 	}
 
 	kfree (kbuffer);
diff -u --recursive --new-file pre1/linux/drivers/char/random.c linux/drivers/char/random.c
--- pre1/linux/drivers/char/random.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/char/random.c	Tue Jan 15 13:53:51 2002
@@ -1313,7 +1313,7 @@
 		/*
 		 * Check if we need to break out or reschedule....
 		 */
-		if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) {
+		if ((flags & EXTRACT_ENTROPY_USER) && need_resched()) {
 			if (signal_pending(current)) {
 				if (ret == 0)
 					ret = -ERESTARTSYS;
diff -u --recursive --new-file pre1/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- pre1/linux/drivers/char/tty_io.c	Thu Jan  3 13:22:21 2002
+++ linux/drivers/char/tty_io.c	Tue Jan 15 13:53:51 2002
@@ -712,8 +712,7 @@
 			ret = -ERESTARTSYS;
 			if (signal_pending(current))
 				break;
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		}
 	}
 	if (written) {
diff -u --recursive --new-file pre1/linux/drivers/dio/dio.c linux/drivers/dio/dio.c
--- pre1/linux/drivers/dio/dio.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/dio/dio.c	Thu Jan 17 14:21:16 2002
@@ -208,6 +208,8 @@
         }
 }
 
+subsys_initcall(dio_init);
+
 /* Bear in mind that this is called in the very early stages of initialisation
  * in order to get the virtual address of the serial port for the console...
  */
diff -u --recursive --new-file pre1/linux/drivers/hotplug/cpqphp_core.c linux/drivers/hotplug/cpqphp_core.c
--- pre1/linux/drivers/hotplug/cpqphp_core.c	Fri Nov  9 14:01:21 2001
+++ linux/drivers/hotplug/cpqphp_core.c	Thu Jan 17 14:06:53 2002
@@ -404,6 +404,10 @@
 		result = pci_hp_register (new_slot->hotplug_slot);
 		if (result) {
 			err ("pci_hp_register failed with error %d\n", result);
+			kfree (new_slot->hotplug_slot->info);
+			kfree (new_slot->hotplug_slot->name);
+			kfree (new_slot->hotplug_slot);
+			kfree (new_slot);
 			return result;
 		}
 		
@@ -429,6 +433,8 @@
 	while (old_slot) {
 		next_slot = old_slot->next;
 		pci_hp_deregister (old_slot->hotplug_slot);
+		kfree(old_slot->hotplug_slot->info);
+		kfree(old_slot->hotplug_slot->name);
 		kfree(old_slot->hotplug_slot);
 		kfree(old_slot);
 		old_slot = next_slot;
diff -u --recursive --new-file pre1/linux/drivers/i2c/i2c-algo-bit.c linux/drivers/i2c/i2c-algo-bit.c
--- pre1/linux/drivers/i2c/i2c-algo-bit.c	Thu Oct 11 08:05:47 2001
+++ linux/drivers/i2c/i2c-algo-bit.c	Tue Jan 15 13:53:51 2002
@@ -50,7 +50,7 @@
 /* might not like this, as they have an internal timeout of some mils	*/
 /*
 #define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
-                        if (need_resched) schedule();
+                        cond_resched();
 */
 
 
@@ -120,8 +120,7 @@
 		if (start+adap->timeout <= jiffies) {
 			return -ETIMEDOUT;
 		}
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 	}
 	DEBSTAT(printk("needed %ld jiffies\n", jiffies-start));
 #ifdef SLO_IO
diff -u --recursive --new-file pre1/linux/drivers/i2c/i2c-algo-ite.c linux/drivers/i2c/i2c-algo-ite.c
--- pre1/linux/drivers/i2c/i2c-algo-ite.c	Thu Oct 11 08:05:47 2001
+++ linux/drivers/i2c/i2c-algo-ite.c	Tue Jan 15 13:53:51 2002
@@ -67,7 +67,7 @@
 /* might not like this, as they have an internal timeout of some mils	*/
 /*
 #define SLO_IO      jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\
-                        if (need_resched) schedule();
+                        cond_resched();
 */
 
 
diff -u --recursive --new-file pre1/linux/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- pre1/linux/drivers/ide/ide-disk.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/ide/ide-disk.c	Thu Jan 17 13:58:35 2002
@@ -123,12 +123,10 @@
  */
 static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
 {
-	if (rq_data_dir(rq) == READ)
-		goto good_command;
-	if (rq_data_dir(rq) == WRITE)
+	if (rq->flags & REQ_CMD)
 		goto good_command;
 
-	printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
+	blk_dump_rq_flags(rq, "do_rw_disk, bad command");
 	ide_end_request(0, HWGROUP(drive));
 	return ide_stopped;
 
@@ -179,8 +177,10 @@
 	struct hd_drive_task_hdr	taskfile;
 	struct hd_drive_hob_hdr		hobfile;
 	ide_task_t			args;
+	int				sectors;
 
 	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
+
 	unsigned int track	= (block / drive->sect);
 	unsigned int sect	= (block % drive->sect) + 1;
 	unsigned int head	= (track % drive->head);
@@ -189,7 +189,16 @@
 	memset(&taskfile, 0, sizeof(task_struct_t));
 	memset(&hobfile, 0, sizeof(hob_struct_t));
 
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+	sectors = rq->nr_sectors;
+	if (sectors == 256)
+		sectors = 0;
+	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+		sectors = drive->mult_count;
+		if (sectors > rq->current_nr_sectors)
+			sectors = rq->current_nr_sectors;
+	}
+
+	taskfile.sector_count	= sectors;
 	taskfile.sector_number	= sect;
 	taskfile.low_cylinder	= cyl;
 	taskfile.high_cylinder	= (cyl>>8);
@@ -225,13 +234,23 @@
 	struct hd_drive_task_hdr	taskfile;
 	struct hd_drive_hob_hdr		hobfile;
 	ide_task_t			args;
+	int				sectors;
 
 	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 
+	sectors = rq->nr_sectors;
+	if (sectors == 256)
+		sectors = 0;
+	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+		sectors = drive->mult_count;
+		if (sectors > rq->current_nr_sectors)
+			sectors = rq->current_nr_sectors;
+	}
+
 	memset(&taskfile, 0, sizeof(task_struct_t));
 	memset(&hobfile, 0, sizeof(hob_struct_t));
 
-	taskfile.sector_count	= (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+	taskfile.sector_count	= sectors;
 	taskfile.sector_number	= block;
 	taskfile.low_cylinder	= (block>>=8);
 	taskfile.high_cylinder	= (block>>=8);
@@ -273,14 +292,24 @@
 	struct hd_drive_task_hdr	taskfile;
 	struct hd_drive_hob_hdr		hobfile;
 	ide_task_t			args;
+	int				sectors;
 
 	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));
 
 	memset(&taskfile, 0, sizeof(task_struct_t));
 	memset(&hobfile, 0, sizeof(hob_struct_t));
 
-	taskfile.sector_count	= rq->nr_sectors;
-	hobfile.sector_count	= (rq->nr_sectors>>8);
+	sectors = rq->nr_sectors;
+	if (sectors == 256)
+		sectors = 0;
+	if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+		sectors = drive->mult_count;
+		if (sectors > rq->current_nr_sectors)
+			sectors = rq->current_nr_sectors;
+	}
+
+	taskfile.sector_count	= sectors;
+	hobfile.sector_count	= sectors >> 8;
 
 	if (rq->nr_sectors == 65536) {
 		taskfile.sector_count	= 0x00;
@@ -652,7 +681,7 @@
 			memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
 			taskfile.sector_count	= drive->mult_req;
 			taskfile.command	= WIN_SETMULT;
-			do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+			do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr);
 		}
 	} else if (s->all) {
 		int special = s->all;
@@ -789,23 +818,12 @@
 
 #endif	/* CONFIG_PROC_FS */
 
+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
 static int set_multcount(ide_drive_t *drive, int arg)
 {
-#if 1
-	struct hd_drive_task_hdr taskfile;
-	struct hd_drive_hob_hdr hobfile;
-
-	if (drive->special.b.set_multmode)
-		return -EBUSY;
-
-	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
-	memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
-	taskfile.sector_count	= drive->mult_req;
-	taskfile.command	= WIN_SETMULT;
-	drive->mult_req		= arg;
-	drive->special.b.set_multmode = 1;
-	ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-#else
 	struct request rq;
 
 	if (drive->special.b.set_multmode)
@@ -814,7 +832,6 @@
 	drive->mult_req = arg;
 	drive->special.b.set_multmode = 1;
 	(void) ide_do_drive_cmd (drive, &rq, ide_wait);
-#endif
 	return (drive->mult_count == arg) ? 0 : -EIO;
 }
 
diff -u --recursive --new-file pre1/linux/drivers/ide/ide-floppy.c linux/drivers/ide/ide-floppy.c
--- pre1/linux/drivers/ide/ide-floppy.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/ide/ide-floppy.c	Tue Jan 15 12:32:36 2002
@@ -688,7 +688,7 @@
 	/* Why does this happen? */
 	if (!rq)
 		return;
-	if (rq->flags & IDEFLOPPY_RQ) {
+	if (!(rq->flags & IDEFLOPPY_RQ)) {
 		ide_end_request (uptodate, hwgroup);
 		return;
 	}
diff -u --recursive --new-file pre1/linux/drivers/ide/ide-tape.c linux/drivers/ide/ide-tape.c
--- pre1/linux/drivers/ide/ide-tape.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/ide/ide-tape.c	Tue Jan 15 18:57:07 2002
@@ -721,7 +721,7 @@
 	int request_transfer;			/* Bytes to transfer */
 	int actually_transferred;		/* Bytes actually transferred */
 	int buffer_size;			/* Size of our data buffer */
-	struct buffer_head *bh;
+	struct bio *bio;
 	char *b_data;
 	int b_count;
 	byte *buffer;				/* Data buffer */
@@ -805,7 +805,7 @@
  */
 typedef struct idetape_stage_s {
 	struct request rq;			/* The corresponding request */
-	struct buffer_head *bh;			/* The data buffers */
+	struct bio *bio;			/* The data buffers */
 	struct idetape_stage_s *next;		/* Pointer to the next stage */
 	os_aux_t *aux;				/* OnStream aux ptr */
 } idetape_stage_t;
@@ -929,7 +929,7 @@
 	int stage_size;				/* Data buffer size (chosen based on the tape's recommendation */
 	idetape_stage_t *merge_stage;
 	int merge_stage_size;
-	struct buffer_head *bh;
+	struct bio *bio;
 	char *b_data;
 	int b_count;
 	
@@ -1013,7 +1013,7 @@
 	 * Measures number of frames:
 	 *
 	 * 1. written/read to/from the driver pipeline (pipeline_head).
-	 * 2. written/read to/from the tape buffers (buffer_head).
+	 * 2. written/read to/from the tape buffers (bio).
 	 * 3. written/read by the tape to/from the media (tape_head).
 	 */
 	int pipeline_head;
@@ -1493,52 +1493,52 @@
 
 static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
-	struct buffer_head *bh = pc->bh;
+	struct bio *bio = pc->bio;
 	int count;
 
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_input_buffers\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_input_buffers\n");
 			idetape_discard_data (drive, bcount);
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
-		atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+		count = IDE_MIN (bio->bi_size - pc->b_count, bcount);
+		atapi_input_bytes (drive, bio_data(bio) + pc->b_count, count);
 		bcount -= count;
-		atomic_add(count, &bh->b_count);
-		if (atomic_read(&bh->b_count) == bh->b_size) {
-			bh = bh->b_reqnext;
-			if (bh)
-				atomic_set(&bh->b_count, 0);
+		pc->b_count += bio->bi_size;
+		if (pc->b_count == bio->bi_size) {
+			bio = bio->bi_next;
+			if (bio)
+				pc->b_count = 0;
 		}
 	}
-	pc->bh = bh;
+	pc->bio = bio;
 }
 
 static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount)
 {
-	struct buffer_head *bh = pc->bh;
+	struct bio *bio = pc->bio;
 	int count;
 
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_output_buffers\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_output_buffers\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = IDE_MIN (pc->b_count, bcount);
-		atapi_output_bytes (drive, pc->b_data, count);
+		atapi_output_bytes (drive, bio_data(bio), count);
 		bcount -= count;
 		pc->b_data += count;
 		pc->b_count -= count;
 		if (!pc->b_count) {
-			pc->bh = bh = bh->b_reqnext;
-			if (bh) {
-				pc->b_data = bh->b_data;
-				pc->b_count = atomic_read(&bh->b_count);
+			pc->bio = bio = bio->bi_next;
+			if (bio) {
+				pc->b_data = bio_data(bio);
+				pc->b_count = bio->bi_size;
 			}
 		}
 	}
@@ -1547,25 +1547,25 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 static void idetape_update_buffers (idetape_pc_t *pc)
 {
-	struct buffer_head *bh = pc->bh;
+	struct bio *bio = pc->bio;
 	int count, bcount = pc->actually_transferred;
 
 	if (test_bit (PC_WRITING, &pc->flags))
 		return;
 	while (bcount) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_update_buffers\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_update_buffers\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size, bcount);
-		atomic_set(&bh->b_count, count);
-		if (atomic_read(&bh->b_count) == bh->b_size)
-			bh = bh->b_reqnext;
+		count = IDE_MIN (bio->bi_size, bcount);
+		pc->b_count = count;
+		if (pc->b_count == bio->bi_size)
+			bio = bio->bi_next;
 		bcount -= count;
 	}
-	pc->bh = bh;
+	pc->bio = bio;
 }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
 
@@ -1625,7 +1625,7 @@
 	pc->request_transfer = 0;
 	pc->buffer = pc->pc_buffer;
 	pc->buffer_size = IDETAPE_PC_BUFFER_SIZE;
-	pc->bh = NULL;
+	pc->bio = NULL;
 	pc->b_data = NULL;
 }
 
@@ -1706,10 +1706,10 @@
 		printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name);
 #endif
 	while (stage) {
-		if (stage->rq.cmd == IDETAPE_WRITE_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_WRITE_RQ;
-		else if (stage->rq.cmd == IDETAPE_READ_RQ)
-			stage->rq.cmd = IDETAPE_ABORTED_READ_RQ;
+		if (stage->rq.flags == IDETAPE_WRITE_RQ)
+			stage->rq.flags = IDETAPE_ABORTED_WRITE_RQ;
+		else if (stage->rq.flags == IDETAPE_READ_RQ)
+			stage->rq.flags = IDETAPE_ABORTED_READ_RQ;
 		stage = stage->next;
 	}
 }
@@ -1735,7 +1735,7 @@
 #endif /* IDETAPE_DEBUG_BUGS */	
 
 	rq->buffer = NULL;
-	rq->bh = stage->bh;
+	rq->bio = stage->bio;
 	tape->active_data_request = rq;
 	tape->active_stage = stage;
 	tape->next_stage = stage->next;
@@ -1769,21 +1769,21 @@
  */
 static void __idetape_kfree_stage (idetape_stage_t *stage)
 {
-	struct buffer_head *prev_bh, *bh = stage->bh;
+	struct bio *prev_bio, *bio = stage->bio;
 	int size;
 
-	while (bh != NULL) {
-		if (bh->b_data != NULL) {
-			size = (int) bh->b_size;
+	while (bio != NULL) {
+		if (bio_data(bio) != NULL) {
+			size = (int) bio->bi_size;
 			while (size > 0) {
-				free_page ((unsigned long) bh->b_data);
+				free_page ((unsigned long) bio_data(bio));
 				size -= PAGE_SIZE;
-				bh->b_data += PAGE_SIZE;
+				bio->bi_size += PAGE_SIZE;
 			}
 		}
-		prev_bh = bh;
-		bh = bh->b_reqnext;
-		kfree (prev_bh);
+		prev_bio = bio;
+		bio = bio->bi_next;
+		kfree (prev_bio);
 	}
 	kfree (stage);
 }
@@ -1868,13 +1868,13 @@
 		tape->active_stage = NULL;
 		tape->active_data_request = NULL;
 		tape->nr_pending_stages--;
-		if (rq->cmd == IDETAPE_WRITE_RQ) {
+		if (rq->flags == IDETAPE_WRITE_RQ) {
 #if ONSTREAM_DEBUG
 			if (tape->debug_level >= 2) {
 				if (tape->onstream) {
 					stage = tape->first_stage;
 					aux = stage->aux;
-					p = stage->bh->b_data;
+					p = bio_data(stage->bio);
 					if (ntohl(aux->logical_blk_num) < 11300 && ntohl(aux->logical_blk_num) > 11100)
 						printk(KERN_INFO "ide-tape: finished writing logical blk %u (data %x %x %x %x)\n", ntohl(aux->logical_blk_num), *p++, *p++, *p++, *p++);
 				}
@@ -1908,7 +1908,7 @@
 						complete(tape->waiting);
 				}
 			}
-		} else if (rq->cmd == IDETAPE_READ_RQ) {
+		} else if (rq->flags == IDETAPE_READ_RQ) {
 			if (error == IDETAPE_ERROR_EOD) {
 				set_bit (IDETAPE_PIPELINE_ERROR, &tape->flags);
 				idetape_abort_pipeline(drive);
@@ -1984,7 +1984,7 @@
 {
 	ide_init_drive_cmd (rq);
 	rq->buffer = (char *) pc;
-	rq->cmd = IDETAPE_PC_RQ1;
+	rq->flags = IDETAPE_PC_RQ1;
 	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
 }
 
@@ -2164,12 +2164,12 @@
 		}
 	}
 	if (test_bit (PC_WRITING, &pc->flags)) {
-		if (pc->bh != NULL)
+		if (pc->bio != NULL)
 			idetape_output_buffers (drive, pc, bcount.all);
 		else
 			atapi_output_bytes (drive,pc->current_position,bcount.all);	/* Write the current buffer */
 	} else {
-		if (pc->bh != NULL)
+		if (pc->bio != NULL)
 			idetape_input_buffers (drive, pc, bcount.all);
 		else
 			atapi_input_bytes (drive,pc->current_position,bcount.all);	/* Read the current buffer */
@@ -2523,21 +2523,22 @@
 	return ide_stopped;
 }
 
-static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
-	struct buffer_head *p = bh;
+	struct bio *p = bio;
+	struct bio_vec *bv = bio_iovec(p);
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_CMD;
 	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
-	pc->bh = bh;
-	atomic_set(&bh->b_count, 0);
+	pc->bio = bio;
+	bv->bv_len = 0;
 	pc->buffer = NULL;
 	if (tape->onstream) {
 		while (p) {
-			atomic_set(&p->b_count, 0);
-			p = p->b_reqnext;
+			bv->bv_len = 0;
+			p = p->bi_next;
 		}
 	}
 	if (!tape->onstream) {
@@ -2553,30 +2554,31 @@
 	}
 }
 
-static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
 	int size = 32768;
 
-	struct buffer_head *p = bh;
+	struct bio *p = bio;
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_READ_BUFFER_CMD;
 	pc->c[1] = IDETAPE_RETRIEVE_FAULTY_BLOCK;
 	pc->c[7] = size >> 8;
 	pc->c[8] = size & 0xff;
 	pc->callback = &idetape_pc_callback;
-	pc->bh = bh;
-	atomic_set(&bh->b_count, 0);
+	pc->bio = bio;
+	atomic_set(&bio->bi_cnt, 0);
 	pc->buffer = NULL;
 	while (p) {
-		atomic_set(&p->b_count, 0);
-		p = p->b_reqnext;
+		p->bi_size = 0;
+		p = p->bi_next;
 	}
 	pc->request_transfer = pc->buffer_size = size;
 }
 
-static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct buffer_head *bh)
+static void idetape_create_write_cmd (idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct bio *bio)
 {
-	struct buffer_head *p = bh;
+	struct bio *p = bio;
+	struct bio_vec *bv= bio_iovec(p);
 	idetape_init_pc (pc);
 	pc->c[0] = IDETAPE_WRITE_CMD;
 	put_unaligned (htonl (length), (unsigned int *) &pc->c[1]);
@@ -2585,13 +2587,13 @@
 	set_bit (PC_WRITING, &pc->flags);
 	if (tape->onstream) {
 		while (p) {
-			atomic_set(&p->b_count, p->b_size);
-			p = p->b_reqnext;
+			bv->bv_len = p->bi_size;
+			p = p->bi_next;
 		}
 	}
-	pc->bh = bh;
-	pc->b_data = bh->b_data;
-	pc->b_count = atomic_read(&bh->b_count);
+	pc->bio = bio;
+	pc->b_data = bio_data(bio);
+	pc->b_count = bio->bi_size;
 	pc->buffer = NULL;
 	if (!tape->onstream) {
 		pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
@@ -2618,16 +2620,16 @@
 
 #if IDETAPE_DEBUG_LOG
 	if (tape->debug_level >= 5)
-		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
+/*		printk (KERN_INFO "ide-tape: rq_status: %d, rq_dev: %u, cmd: %ld, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->flags,rq->errors); */
 	if (tape->debug_level >= 2)
-		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+		printk (KERN_INFO "ide-tape: sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
 #endif /* IDETAPE_DEBUG_LOG */
 
-	if (!IDETAPE_RQ_CMD (rq->cmd)) {
+	if (!IDETAPE_RQ_CMD (rq->flags)) {
 		/*
 		 *	We do not support buffer cache originated requests.
 		 */
-		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%d)\n", drive->name, rq->cmd);
+		printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags);
 		ide_end_request (0, HWGROUP (drive));			/* Let the common code handle it */
 		return ide_stopped;
 	}
@@ -2661,7 +2663,7 @@
 	 */
 	if (tape->onstream)
 		status.b.dsc = 1;
-	if (!drive->dsc_overlap && rq->cmd != IDETAPE_PC_RQ2)
+	if (!drive->dsc_overlap && rq->flags != IDETAPE_PC_RQ2)
 		set_bit (IDETAPE_IGNORE_DSC, &tape->flags);
 
 	/*
@@ -2674,7 +2676,7 @@
 	 */
 	if (tape->tape_still_time > 100 && tape->tape_still_time < 200)
 		tape->measure_insert_time = 1;
-	if (tape->req_buffer_fill && (rq->cmd == IDETAPE_WRITE_RQ || rq->cmd == IDETAPE_READ_RQ)) {
+	if (tape->req_buffer_fill && (rq->flags == IDETAPE_WRITE_RQ || rq->flags == IDETAPE_READ_RQ)) {
 		tape->req_buffer_fill = 0;
 		tape->writes_since_buffer_fill = 0;
 		tape->reads_since_buffer_fill = 0;
@@ -2688,19 +2690,19 @@
 		tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time);
 	calculate_speeds(drive);
 	if (tape->onstream && tape->max_frames &&
-	    ((rq->cmd == IDETAPE_WRITE_RQ &&
+	    ((rq->flags == IDETAPE_WRITE_RQ &&
               ( tape->cur_frames == tape->max_frames ||
                 ( tape->speed_control && tape->cur_frames > 5 &&
                        (tape->insert_speed > tape->max_insert_speed ||
                         (0 /* tape->cur_frames > 30 && tape->tape_still_time > 200 */) ) ) ) ) ||
-	     (rq->cmd == IDETAPE_READ_RQ &&
+	     (rq->flags == IDETAPE_READ_RQ &&
 	      ( tape->cur_frames == 0 ||
 		( tape->speed_control && (tape->cur_frames < tape->max_frames - 5) &&
 			tape->insert_speed > tape->max_insert_speed ) ) && rq->nr_sectors) ) ) {
 #if IDETAPE_DEBUG_LOG
 		if (tape->debug_level >= 4)
-			printk(KERN_INFO "ide-tape: postponing request, cmd %d, cur %d, max %d\n",
-				rq->cmd, tape->cur_frames, tape->max_frames);
+			printk(KERN_INFO "ide-tape: postponing request, cmd %ld, cur %d, max %d\n",
+				rq->flags, tape->cur_frames, tape->max_frames);
 #endif
 		if (tape->postpone_cnt++ < 500) {
 			status.b.dsc = 0;
@@ -2718,7 +2720,7 @@
 			tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT;
 		} else if ((signed long) (jiffies - tape->dsc_timeout) > 0) {
 			printk (KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name);
-			if (rq->cmd == IDETAPE_PC_RQ2) {
+			if (rq->flags == IDETAPE_PC_RQ2) {
 				idetape_media_access_finished (drive);
 				return ide_stopped;
 			} else {
@@ -2729,7 +2731,7 @@
 		idetape_postpone_request (drive);
 		return ide_stopped;
 	}
-	switch (rq->cmd) {
+	switch (rq->flags) {
 		case IDETAPE_READ_RQ:
 			tape->buffer_head++;
 #if USE_IOTRACE
@@ -2744,7 +2746,7 @@
 					tape->req_buffer_fill = 1;
 			}
 			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			idetape_create_read_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_WRITE_RQ:
 			tape->buffer_head++;
@@ -2761,15 +2763,15 @@
 				calculate_speeds(drive);
 			}
 			pc = idetape_next_pc_storage (drive);
-			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			idetape_create_write_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_READ_BUFFER_RQ:
 			tape->postpone_cnt = 0;
 			pc = idetape_next_pc_storage (drive);
-			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bh);
+			idetape_create_read_buffer_cmd (tape, pc, rq->current_nr_sectors, rq->bio);
 			break;
 		case IDETAPE_ABORTED_WRITE_RQ:
-			rq->cmd = IDETAPE_WRITE_RQ;
+			rq->flags = IDETAPE_WRITE_RQ;
 			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
 			return ide_stopped;
 		case IDETAPE_ABORTED_READ_RQ:
@@ -2777,12 +2779,12 @@
 			if (tape->debug_level >= 2)
 				printk(KERN_INFO "ide-tape: %s: detected aborted read rq\n", tape->name);
 #endif
-			rq->cmd = IDETAPE_READ_RQ;
+			rq->flags = IDETAPE_READ_RQ;
 			idetape_end_request (IDETAPE_ERROR_EOD, HWGROUP(drive));
 			return ide_stopped;
 		case IDETAPE_PC_RQ1:
 			pc = (idetape_pc_t *) rq->buffer;
-			rq->cmd = IDETAPE_PC_RQ2;
+			rq->flags = IDETAPE_PC_RQ2;
 			break;
 		case IDETAPE_PC_RQ2:
 			idetape_media_access_finished (drive);
@@ -2822,61 +2824,65 @@
 static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear)
 {
 	idetape_stage_t *stage;
-	struct buffer_head *prev_bh, *bh;
+	struct bio *prev_bio, *bio;
 	int pages = tape->pages_per_stage;
-	char *b_data;
+	char *b_data = NULL;
+	struct bio_vec *bv; 
 
 	if ((stage = (idetape_stage_t *) kmalloc (sizeof (idetape_stage_t),GFP_KERNEL)) == NULL)
 		return NULL;
 	stage->next = NULL;
 
-	bh = stage->bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL);
-	if (bh == NULL)
+	bio = stage->bio = bio_alloc(GFP_KERNEL,1);
+	bv = bio_iovec(bio);	
+	bv->bv_len = 0;
+	if (bio == NULL)
 		goto abort;
-	bh->b_reqnext = NULL;
-	if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+	bio->bi_next = NULL;
+	if ((bio->bi_io_vec[0].bv_page = alloc_page(GFP_KERNEL)) == NULL)
 		goto abort;
 	if (clear)
-		memset(bh->b_data, 0, PAGE_SIZE);
-	bh->b_size = PAGE_SIZE;
-	atomic_set(&bh->b_count, full ? bh->b_size : 0);
-	set_bit (BH_Lock, &bh->b_state);
+		memset(bio_data(bio), 0, PAGE_SIZE);
+	bio->bi_size = PAGE_SIZE;
+	if(bv->bv_len == full) bv->bv_len = bio->bi_size;
+	set_bit (BH_Lock, &bio->bi_flags);
 
 	while (--pages) {
-		if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL)
+		if ((bio->bi_io_vec[pages].bv_page = alloc_page(GFP_KERNEL)) == NULL)
 			goto abort;
 		if (clear)
-			memset(b_data, 0, PAGE_SIZE);
-		if (bh->b_data == b_data + PAGE_SIZE) {
-			bh->b_size += PAGE_SIZE;
-			bh->b_data -= PAGE_SIZE;
+			memset(bio_data(bio), 0, PAGE_SIZE);
+		if (bio->bi_size == bv->bv_len + PAGE_SIZE) {
+			bio->bi_size += PAGE_SIZE;
+			bv->bv_len += PAGE_SIZE;
+			bv->bv_offset -= PAGE_SIZE;
 			if (full)
-				atomic_add(PAGE_SIZE, &bh->b_count);
+				bio->bi_size += PAGE_SIZE;
 			continue;
 		}
-		if (b_data == bh->b_data + bh->b_size) {
-			bh->b_size += PAGE_SIZE;
+		if (b_data == bio_data(bio) + bio->bi_size) {
+			bio->bi_size += PAGE_SIZE;
 			if (full)
-				atomic_add(PAGE_SIZE, &bh->b_count);
+				bio->bi_size += PAGE_SIZE;
 			continue;
 		}
-		prev_bh = bh;
-		if ((bh = (struct buffer_head *) kmalloc (sizeof (struct buffer_head), GFP_KERNEL)) == NULL) {
-			free_page ((unsigned long) b_data);
+		prev_bio = bio;
+		if ((bio = bio_alloc(GFP_KERNEL,1)) == NULL) {
+			free_page ((unsigned long) bio_data(bio));
 			goto abort;
 		}
-		bh->b_reqnext = NULL;
-		bh->b_data = b_data;
-		bh->b_size = PAGE_SIZE;
-		atomic_set(&bh->b_count, full ? bh->b_size : 0);
-		set_bit (BH_Lock, &bh->b_state);
-		prev_bh->b_reqnext = bh;
+		bio->bi_next = NULL;
+		//bio->bi_io_vec[0].bv_offset = b_data;
+		bio->bi_size = PAGE_SIZE;
+		atomic_set(&bio->bi_cnt, full ? bio->bi_size : 0);
+		set_bit (BH_Lock, &bio->bi_flags);
+		prev_bio->bi_next = bio;
 	}
-	bh->b_size -= tape->excess_bh_size;
+	bio->bi_size -= tape->excess_bh_size;
 	if (full)
-		atomic_sub(tape->excess_bh_size, &bh->b_count);
+		atomic_sub(tape->excess_bh_size, &bio->bi_cnt);
 	if (tape->onstream)
-		stage->aux = (os_aux_t *) (bh->b_data + bh->b_size - OS_AUX_SIZE);
+		stage->aux = (os_aux_t *) (bio_data(bio) + bio->bi_size - OS_AUX_SIZE);
 	return stage;
 abort:
 	__idetape_kfree_stage (stage);
@@ -2903,39 +2909,39 @@
 
 static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char *buf, int n)
 {
-	struct buffer_head *bh = tape->bh;
+	struct bio *bio = tape->bio;
 	int count;
 
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_from_user\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_from_user\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
-		copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+		count = IDE_MIN (bio->bi_size - tape->b_count, n);
+		copy_from_user (bio_data(bio) + tape->b_count, buf, count);
 		n -= count;
-		atomic_add(count, &bh->b_count);
+		bio->bi_size += count;
 		buf += count;
-		if (atomic_read(&bh->b_count) == bh->b_size) {
-			bh = bh->b_reqnext;
-			if (bh)
-				atomic_set(&bh->b_count, 0);
+		if (tape->b_count == bio->bi_size) {
+			bio = bio->bi_next;
+			if (bio)
+				tape->b_count = 0;
 		}
 	}
-	tape->bh = bh;
+	tape->bio = bio;
 }
 
 static void idetape_copy_stage_to_user (idetape_tape_t *tape, char *buf, idetape_stage_t *stage, int n)
 {
-	struct buffer_head *bh = tape->bh;
+	struct bio *bio = tape->bio;
 	int count;
 
 	while (n) {
 #if IDETAPE_DEBUG_BUGS
-		if (bh == NULL) {
-			printk (KERN_ERR "ide-tape: bh == NULL in idetape_copy_stage_to_user\n");
+		if (bio == NULL) {
+			printk (KERN_ERR "ide-tape: bio == NULL in idetape_copy_stage_to_user\n");
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
@@ -2946,10 +2952,10 @@
 		tape->b_count -= count;
 		buf += count;
 		if (!tape->b_count) {
-			tape->bh = bh = bh->b_reqnext;
-			if (bh) {
-				tape->b_data = bh->b_data;
-				tape->b_count = atomic_read(&bh->b_count);
+			tape->bio = bio = bio->bi_next;
+			if (bio) {
+				tape->b_data = bio_data(bio);
+				tape->b_count = bio->bi_size;
 			}
 		}
 	}
@@ -2957,25 +2963,25 @@
 
 static void idetape_init_merge_stage (idetape_tape_t *tape)
 {
-	struct buffer_head *bh = tape->merge_stage->bh;
+	struct bio *bio = tape->merge_stage->bio;
 	
-	tape->bh = bh;
+	tape->bio = bio;
 	if (tape->chrdev_direction == idetape_direction_write)
-		atomic_set(&bh->b_count, 0);
+		atomic_set(&bio->bi_cnt, 0);
 	else {
-		tape->b_data = bh->b_data;
-		tape->b_count = atomic_read(&bh->b_count);
+		tape->b_data = bio_data(bio);
+		tape->b_count = atomic_read(&bio->bi_cnt);
 	}
 }
 
 static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage)
 {
-	struct buffer_head *tmp;
+	struct bio *tmp;
 	os_aux_t *tmp_aux;
 
-	tmp = stage->bh; tmp_aux = stage->aux;
-	stage->bh = tape->merge_stage->bh; stage->aux = tape->merge_stage->aux;
-	tape->merge_stage->bh = tmp; tape->merge_stage->aux = tmp_aux;
+	tmp = stage->bio; tmp_aux = stage->aux;
+	stage->bio = tape->merge_stage->bio; stage->aux = tape->merge_stage->aux;
+	tape->merge_stage->bio = tmp; tape->merge_stage->aux = tmp_aux;
 	idetape_init_merge_stage (tape);
 }
 
@@ -3077,7 +3083,7 @@
 	idetape_tape_t *tape = drive->driver_data;
 
 #if IDETAPE_DEBUG_BUGS
-	if (rq == NULL || !IDETAPE_RQ_CMD (rq->cmd)) {
+	if (rq == NULL || !IDETAPE_RQ_CMD (rq->flags)) {
 		printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
 		return;
 	}
@@ -3185,7 +3191,7 @@
 
 	ide_init_drive_cmd (&rq);
 	rq.buffer = (char *) pc;
-	rq.cmd = IDETAPE_PC_RQ1;
+	rq.flags = IDETAPE_PC_RQ1;
 	return ide_do_drive_cmd (drive, &rq, ide_wait);
 }
 
@@ -3430,7 +3436,7 @@
  *	idetape_queue_rw_tail generates a read/write request for the block
  *	device interface and wait for it to be serviced.
  */
-static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct buffer_head *bh)
+static int idetape_queue_rw_tail (ide_drive_t *drive, int cmd, int blocks, struct bio *bio)
 {
 	idetape_tape_t *tape = drive->driver_data;
 	struct request rq;
@@ -3447,8 +3453,8 @@
 #endif /* IDETAPE_DEBUG_BUGS */	
 
 	ide_init_drive_cmd (&rq);
-	rq.bh = bh;
-	rq.cmd = cmd;
+	rq.bio = bio;
+	rq.flags = cmd;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (tape->onstream)
@@ -3489,15 +3495,15 @@
 		if (!first)
 			first = stage;
 		aux = stage->aux;
-		p = stage->bh->b_data;
-		idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bh);
+		p = bio_data(stage->bio);
+		idetape_queue_rw_tail(drive, IDETAPE_READ_BUFFER_RQ, tape->capabilities.ctl, stage->bio);
 #if ONSTREAM_DEBUG
 		if (tape->debug_level >= 2)
 			printk(KERN_INFO "ide-tape: %s: read back logical block %d, data %x %x %x %x\n", tape->name, logical_blk_num, *p++, *p++, *p++, *p++);
 #endif
 		rq = &stage->rq;
 		ide_init_drive_cmd (rq);
-		rq->cmd = IDETAPE_WRITE_RQ;
+		rq->flags = IDETAPE_WRITE_RQ;
 		rq->sector = tape->first_frame_position;
 		rq->nr_sectors = rq->current_nr_sectors = tape->capabilities.ctl;
 		idetape_init_stage(drive, stage, OS_FRAME_TYPE_DATA, logical_blk_num++);
@@ -3646,18 +3652,18 @@
 	os_aux_t *aux = stage->aux;
 	os_partition_t *par = &aux->partition;
 	struct request *rq = &stage->rq;
-	struct buffer_head *bh;
+	struct bio *bio;
 
 	if (!tape->onstream)
 		return 1;
 	if (tape->raw) {
 		if (rq->errors) {
-			bh = stage->bh;
-			while (bh) {
-				memset(bh->b_data, 0, bh->b_size);
-				bh = bh->b_reqnext;
+			bio = stage->bio;
+			while (bio) {
+				memset(bio_data(bio), 0, bio->bi_size);
+				bio = bio->bi_next;
 			}
-			strcpy(stage->bh->b_data, "READ ERROR ON FRAME");
+			strcpy(bio_data(stage->bio), "READ ERROR ON FRAME");
 		}
 		return 1;
 	}
@@ -3767,12 +3773,12 @@
 			 *	Linux is short on memory. Fallback to
 			 *	non-pipelined operation mode for this request.
 			 */
-			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+			return idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
 		}
 	}
 	rq = &new_stage->rq;
 	ide_init_drive_cmd (rq);
-	rq->cmd = IDETAPE_WRITE_RQ;
+	rq->flags = IDETAPE_WRITE_RQ;
 	rq->sector = tape->first_frame_position;	/* Doesn't actually matter - We always assume sequential access */
 	rq->nr_sectors = rq->current_nr_sectors = blocks;
 
@@ -3843,7 +3849,7 @@
 {
 	idetape_tape_t *tape = drive->driver_data;
 	int blocks, i, min;
-	struct buffer_head *bh;
+	struct bio *bio;
 	
 #if IDETAPE_DEBUG_BUGS
 	if (tape->chrdev_direction != idetape_direction_write) {
@@ -3860,22 +3866,22 @@
 		if (tape->merge_stage_size % tape->tape_block_size) {
 			blocks++;
 			i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
-			bh = tape->bh->b_reqnext;
-			while (bh) {
-				atomic_set(&bh->b_count, 0);
-				bh = bh->b_reqnext;
+			bio = tape->bio->bi_next;
+			while (bio) {
+				atomic_set(&bio->bi_cnt, 0);
+				bio = bio->bi_next;
 			}
-			bh = tape->bh;
+			bio = tape->bio;
 			while (i) {
-				if (bh == NULL) {
-					printk(KERN_INFO "ide-tape: bug, bh NULL\n");
+				if (bio == NULL) {
+					printk(KERN_INFO "ide-tape: bug, bio NULL\n");
 					break;
 				}
-				min = IDE_MIN(i, bh->b_size - atomic_read(&bh->b_count));
-				memset(bh->b_data + atomic_read(&bh->b_count), 0, min);
-				atomic_add(min, &bh->b_count);
+				min = IDE_MIN(i, bio->bi_size - atomic_read(&bio->bi_cnt));
+				memset(bio_data(bio) + bio->bi_size, 0, min);
+				atomic_add(min, &bio->bi_cnt);
 				i -= min;
-				bh = bh->b_reqnext;
+				bio = bio->bi_next;
 			}
 		}
 		(void) idetape_add_chrdev_write_request (drive, blocks);
@@ -3949,7 +3955,7 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bh);
+		bytes_read = idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 0, tape->merge_stage->bio);
 		if (bytes_read < 0) {
 			kfree (tape->merge_stage);
 			tape->merge_stage = NULL;
@@ -3960,7 +3966,7 @@
 	if (tape->restart_speed_control_req)
 		idetape_restart_speed_control(drive);
 	ide_init_drive_cmd (&rq);
-	rq.cmd = IDETAPE_READ_RQ;
+	rq.flags = IDETAPE_READ_RQ;
 	rq.sector = tape->first_frame_position;
 	rq.nr_sectors = rq.current_nr_sectors = blocks;
 	if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages <= max_stages) {
@@ -4083,7 +4089,7 @@
 		}
 		if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags))
 		 	return 0;
-		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bh);
+		return idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, blocks, tape->merge_stage->bio);
 	}
 	rq_ptr = &tape->first_stage->rq;
 	bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors);
@@ -4137,21 +4143,21 @@
 static void idetape_pad_zeros (ide_drive_t *drive, int bcount)
 {
 	idetape_tape_t *tape = drive->driver_data;
-	struct buffer_head *bh;
+	struct bio *bio;
 	int count, blocks;
 	
 	while (bcount) {
-		bh = tape->merge_stage->bh;
+		bio = tape->merge_stage->bio;
 		count = IDE_MIN (tape->stage_size, bcount);
 		bcount -= count;
 		blocks = count / tape->tape_block_size;
 		while (count) {
-			atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
-			memset (bh->b_data, 0, atomic_read(&bh->b_count));
-			count -= atomic_read(&bh->b_count);
-			bh = bh->b_reqnext;
+			atomic_set(&bio->bi_cnt, IDE_MIN (count, bio->bi_size));
+			memset (bio_data(bio), 0, bio->bi_size);
+			count -= atomic_read(&bio->bi_cnt);
+			bio = bio->bi_next;
 		}
-		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
+		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bio);
 	}
 }
 
@@ -4276,7 +4282,7 @@
  */
 static ide_drive_t *get_drive_ptr (kdev_t i_rdev)
 {
-	unsigned int i = MINOR(i_rdev) & ~0xc0;
+	unsigned int i = minor(i_rdev) & ~0xc0;
 
 	if (i >= MAX_HWIFS * MAX_DRIVES)
 		return NULL;
@@ -4654,7 +4660,7 @@
 		printk(KERN_INFO "ide-tape: current position (2) tape block %d\n", tape->last_frame_position);
 #endif
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
 		printk(KERN_INFO "ide-tape: %s: couldn't read last marker\n", tape->name);
 		__idetape_kfree_stage (stage);
 		idetape_position_tape(drive, position, 0, 0);
@@ -4673,7 +4679,7 @@
 #endif
 	aux->next_mark_addr = htonl(next_mark_addr);
 	idetape_position_tape(drive, last_mark_addr, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+	if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
 		printk(KERN_INFO "ide-tape: %s: couldn't write back marker frame at %d\n", tape->name, last_mark_addr);
 		__idetape_kfree_stage (stage);
 		idetape_position_tape(drive, position, 0, 0);
@@ -4705,9 +4711,9 @@
 	if (rc != 0) 
 		return;	/* don't write fillers if we cannot position the tape. */
 
-	strcpy(stage->bh->b_data, "Filler");
+	strcpy(bio_data(stage->bio), "Filler");
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
 			printk(KERN_INFO "ide-tape: %s: write_filler: couldn't write header frame\n", tape->name);
 			__idetape_kfree_stage (stage);
 			return;
@@ -4739,9 +4745,9 @@
 	header.partition.last_frame_addr = htonl(tape->capacity);
 	header.partition.wrt_pass_cntr = htons(tape->wrt_pass_cntr);
 	header.partition.eod_frame_addr = htonl(tape->eod_frame_addr);
-	memcpy(stage->bh->b_data, &header, sizeof(header));
+	memcpy(bio_data(stage->bio), &header, sizeof(header));
 	while (cnt--) {
-		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bh)) {
+		if (!idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 1, stage->bio)) {
 			printk(KERN_INFO "ide-tape: %s: couldn't write header frame\n", tape->name);
 			__idetape_kfree_stage (stage);
 			return;
@@ -4860,7 +4866,7 @@
 		 *	is switched from completion mode to buffer available
 		 *	mode.
 		 */
-		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bh);
+		retval = idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, 0, tape->merge_stage->bio);
 		if (retval < 0) {
 			kfree (tape->merge_stage);
 			tape->merge_stage = NULL;
@@ -5326,12 +5332,12 @@
 		printk(KERN_INFO "ide-tape: %s: reading header\n", tape->name);
 #endif
 	idetape_position_tape(drive, block, 0, 0);
-	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bh)) {
+	if (!idetape_queue_rw_tail (drive, IDETAPE_READ_RQ, 1, stage->bio)) {
 		printk(KERN_INFO "ide-tape: %s: couldn't read header frame\n", tape->name);
 		__idetape_kfree_stage (stage);
 		return 0;
 	}
-	header = (os_header_t *) stage->bh->b_data;
+	header = (os_header_t *) bio_data(stage->bio);
 	aux = stage->aux;
 	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0) {
 		printk(KERN_INFO "ide-tape: %s: invalid header identification string\n", tape->name);
@@ -5403,7 +5409,7 @@
 	ide_drive_t *drive;
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor=minor(inode->i_rdev);
 			
 #if IDETAPE_DEBUG_LOG
 	printk (KERN_INFO "ide-tape: Reached idetape_chrdev_open\n");
@@ -5460,7 +5466,7 @@
 {
 	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
 	idetape_tape_t *tape = drive->driver_data;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor=minor(inode->i_rdev);
 
 	idetape_empty_write_pipeline (drive);
 	tape->merge_stage = __idetape_kmalloc_stage (tape, 1, 0);
@@ -5486,7 +5492,7 @@
 	ide_drive_t *drive = get_drive_ptr (inode->i_rdev);
 	idetape_tape_t *tape;
 	idetape_pc_t pc;
-	unsigned int minor=MINOR (inode->i_rdev);
+	unsigned int minor=minor(inode->i_rdev);
 
 	tape = drive->driver_data;
 #if IDETAPE_DEBUG_LOG
diff -u --recursive --new-file pre1/linux/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- pre1/linux/drivers/ide/ide-taskfile.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/ide/ide-taskfile.c	Thu Jan 17 13:58:35 2002
@@ -706,8 +706,8 @@
 	ide__sti();	/* local CPU only */
 
 	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
-		return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */
-
+		return ide_error(drive, "task_no_data_intr", stat);
+		/* calls ide_end_drive_cmd */
 	if (args)
 		ide_end_drive_cmd (drive, stat, GET_ERR());
 
@@ -723,6 +723,7 @@
 	byte io_32bit		= drive->io_32bit;
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned long flags;
 
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
@@ -735,17 +736,21 @@
 		}
 	}
 	DTF("stat: %02x\n", stat);
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	pBuf = ide_map_rq(rq, &flags);
 	DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
 
 	drive->io_32bit = 0;
 	taskfile_input_data(drive, pBuf, SECTOR_WORDS);
+	ide_unmap_rq(rq, pBuf, &flags);
 	drive->io_32bit = io_32bit;
 
 	if (--rq->current_nr_sectors <= 0) {
 		/* (hs): swapped next 2 lines */
 		DTF("Request Ended stat: %02x\n", GET_STAT());
-		ide_end_request(1, HWGROUP(drive));
+		if (ide_end_request(1, HWGROUP(drive))) {
+			ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
+			return ide_started;
+		}
 	} else {
 		ide_set_handler(drive, &task_in_intr,  WAIT_CMD, NULL);
 		return ide_started;
@@ -809,13 +814,14 @@
 	byte io_32bit		= drive->io_32bit;
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned long flags;
 
 	if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
 		if (stat & (ERR_STAT|DRQ_STAT)) {
 			return ide_error(drive, "task_mulin_intr", stat);
 		}
 		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
+		ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
 		return ide_started;
 	}
 
@@ -834,10 +840,11 @@
 		 */
 		nsect = 1;
 		while (rq->current_nr_sectors) {
-			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+			pBuf = ide_map_rq(rq, &flags);
 			DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
 			drive->io_32bit = 0;
 			taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+			ide_unmap_rq(rq, pBuf, &flags);
 			drive->io_32bit = io_32bit;
 			rq->errors = 0;
 			rq->current_nr_sectors -= nsect;
@@ -848,22 +855,34 @@
 	}
 #endif /* ALTSTAT_SCREW_UP */
 
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
 
-	DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
-		pBuf, nsect, rq->current_nr_sectors);
-	drive->io_32bit = 0;
-	taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
-	drive->io_32bit = io_32bit;
-	rq->errors = 0;
-	rq->current_nr_sectors -= nsect;
-	if (rq->current_nr_sectors != 0) {
-		ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-	ide_end_request(1, HWGROUP(drive));
-	return ide_stopped;
+		pBuf = ide_map_rq(rq, &flags);
+
+		DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+			pBuf, nsect, rq->current_nr_sectors);
+		drive->io_32bit = 0;
+		taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+		ide_unmap_rq(rq, pBuf, &flags);
+		drive->io_32bit = io_32bit;
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
+		if (!rq->current_nr_sectors) {
+			if (!ide_end_request(1, HWGROUP(drive)))
+				return ide_stopped;
+		}
+	} while (msect);
+
+
+	/*
+	 * more data left
+	 */
+	ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+	return ide_started;
 }
 
 ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
@@ -879,10 +898,12 @@
 	/* (ks/hs): Fixed Multi Write */
 	if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) &&
 	    (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) {
+		unsigned long flags;
+		char *buf = ide_map_rq(rq, &flags);
 		/* For Write_sectors we need to stuff the first sector */
-		taskfile_output_data(drive, rq->buffer, SECTOR_WORDS);
+		taskfile_output_data(drive, buf, SECTOR_WORDS);
 		rq->current_nr_sectors--;
-		return ide_started;
+		ide_unmap_rq(rq, buf, &flags);
 	} else {
 		/*
 		 * (ks/hs): Stuff the first sector(s)
@@ -913,8 +934,10 @@
 	byte io_32bit		= drive->io_32bit;
 	struct request *rq	= HWGROUP(drive)->rq;
 	char *pBuf		= NULL;
+	unsigned long flags;
 
 	if (!rq->current_nr_sectors) { 
+		printk("task_out_intr: should not trigger\n");
 		ide_end_request(1, HWGROUP(drive));
 		return ide_stopped;
 	}
@@ -922,19 +945,24 @@
 	if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
 		return ide_error(drive, "task_out_intr", stat);
 	}
+
 	if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
 		rq = HWGROUP(drive)->rq;
-		pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+		pBuf = ide_map_rq(rq, &flags);
 		DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);
 		drive->io_32bit = 0;
 		taskfile_output_data(drive, pBuf, SECTOR_WORDS);
+		ide_unmap_rq(rq, pBuf, &flags);
 		drive->io_32bit = io_32bit;
 		rq->errors = 0;
 		rq->current_nr_sectors--;
 	}
 
 	if (rq->current_nr_sectors <= 0) {
-		ide_end_request(1, HWGROUP(drive));
+		if (ide_end_request(1, HWGROUP(drive))) {
+			ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+			return ide_started;
+		}
 	} else {
 		ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
 		return ide_started;
@@ -961,14 +989,20 @@
 	struct request *rq	= HWGROUP(drive)->rq;
 	ide_hwgroup_t *hwgroup	= HWGROUP(drive);
 	char *pBuf		= NULL;
+	unsigned long flags;
 
 	/*
 	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent
+	 * occurs after all data was sent in this chunk
 	 */
 	if (rq->current_nr_sectors == 0) {
 		if (stat & (ERR_STAT|DRQ_STAT))
 			return ide_error(drive, "task_mulout_intr", stat);
+
+		/*
+		 * there may be more, ide_do_request will restart it if
+		 * necessary
+		 */
 		ide_end_request(1, HWGROUP(drive));
 		return ide_stopped;
 	}
@@ -994,10 +1028,11 @@
 	if (!msect) {
 		nsect = 1;
 		while (rq->current_nr_sectors) {
-			pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+			pBuf = ide_map_rq(rq, &flags);
 			DTF("Multiwrite: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
 			drive->io_32bit = 0;
 			taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+			ide_unmap_rq(pBuf, &flags);
 			drive->io_32bit = io_32bit;
 			rq->errors = 0;
 			rq->current_nr_sectors -= nsect;
@@ -1008,12 +1043,16 @@
 	}
 #endif /* ALTSTAT_SCREW_UP */
 
-	nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
-	pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+	nsect = rq->current_nr_sectors;
+	if (nsect > msect)
+		nsect = msect;
+
+	pBuf = ide_map_rq(rq, &flags);
 	DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
 		pBuf, nsect, rq->current_nr_sectors);
 	drive->io_32bit = 0;
 	taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS);
+	ide_unmap_rq(rq, pBuf, &flags);
 	drive->io_32bit = io_32bit;
 	rq->errors = 0;
 	rq->current_nr_sectors -= nsect;
diff -u --recursive --new-file pre1/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- pre1/linux/drivers/ide/ide.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/ide/ide.c	Thu Jan 17 13:58:35 2002
@@ -1458,14 +1458,11 @@
 	HWGROUP(drive)->rq = NULL;
 
 	rq->errors = 0;
-	rq->sector = rq->bio->bi_sector;
-	rq->current_nr_sectors = bio_sectors(rq->bio);
-
-	/*
-	 * just to make sure...
-	 */
-	if (rq->bio)
+	if (rq->bio) {
+		rq->sector = rq->bio->bi_sector;
+		rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
 		rq->buffer = NULL;
+	}
 }
 
 /*
diff -u --recursive --new-file pre1/linux/drivers/isdn/avmb1/b1pci.c linux/drivers/isdn/avmb1/b1pci.c
--- pre1/linux/drivers/isdn/avmb1/b1pci.c	Sun Jan  6 12:23:35 2002
+++ linux/drivers/isdn/avmb1/b1pci.c	Thu Jan 17 14:04:15 2002
@@ -67,26 +67,6 @@
 
 	card->interrupt = 0;
 }
-/* ------------------------------------------------------------- */
-
-static void b1pci_remove_ctr(struct capi_ctr *ctrl)
-{
-	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-	avmcard *card = cinfo->card;
-	unsigned int port = card->port;
-
-	b1_reset(port);
-	b1_reset(port);
-
-	di->detach_ctr(ctrl);
-	free_irq(card->irq, card);
-	release_region(card->port, AVMB1_PORTLEN);
-	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-	kfree(card);
-
-	MOD_DEC_USE_COUNT;
-}
 
 /* ------------------------------------------------------------- */
 
@@ -118,20 +98,18 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
 	card->ctrlinfo = cinfo;
@@ -140,51 +118,38 @@
 	card->port = p->port;
 	card->irq = p->irq;
 	card->cardtype = avm_b1pci;
-
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 	b1_reset(card->port);
-	if ((retval = b1_detect(card->port, card->cardtype)) != 0) {
+	retval = b1_detect(card->port, card->cardtype);
+	if (retval) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
-					driver->name, card->port, retval);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		       driver->name, card->port, retval);
+		retval = -EIO;
+		goto err_release_region;
 	}
 	b1_reset(card->port);
 	b1_getrevision(card);
-
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
+	
 	retval = request_irq(card->irq, b1pci_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
-				driver->name, card->irq);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		       driver->name, card->irq);
+		retval = -EBUSY;
+		goto err_release_region;
 	}
-
+	
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n",
-				driver->name);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		       driver->name);
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 
 	if (card->revision >= 4) {
@@ -198,6 +163,37 @@
 	}
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+static void b1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+	unsigned int port = card->port;
+
+	b1_reset(port);
+	b1_reset(port);
+
+	di->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
@@ -226,25 +222,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
-{
-	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-	avmcard *card = cinfo->card;
-
- 	b1dma_reset(card);
-
-	div4->detach_ctr(ctrl);
-	free_irq(card->irq, card);
-	iounmap(card->mbase);
-	release_region(card->port, AVMB1_PORTLEN);
-	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-        avmcard_dma_free(card->dma);
-	kfree(card);
-
-	MOD_DEC_USE_COUNT;
-}
-
 static char *b1pciv4_procinfo(struct capi_ctr *ctrl)
 {
 	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
@@ -274,28 +251,23 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
+
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: dma alloc.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_dma_free;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
 	card->ctrlinfo = cinfo;
@@ -306,69 +278,47 @@
 	card->membase = p->membase;
 	card->cardtype = avm_b1pci;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 64);
 	if (!card->mbase) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_release_region;
 	}
 
 	b1dma_reset(card);
 
-	if ((retval = b1pciv4_detect(card)) != 0) {
+	retval = b1pciv4_detect(card);
+	if (retval) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
-                iounmap(card->mbase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_unmap;
 	}
 	b1dma_reset(card);
 	b1_getrevision(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap(card->mbase);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_unmap;
 	}
 
 	cinfo->capi_ctrl = div4->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap(card->mbase);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 	card->cardnr = cinfo->capi_ctrl->cnr;
 
@@ -378,6 +328,42 @@
 		card->membase, card->revision);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_dma_free:
+	avmcard_dma_free(card->dma);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
+
+}
+
+static void b1pciv4_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+
+ 	b1dma_reset(card);
+
+	div4->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	iounmap(card->mbase);
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+        avmcard_dma_free(card->dma);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
@@ -402,8 +388,6 @@
 
 #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
 
-static int ncards = 0;
-
 static int __devinit b1pci_probe(struct pci_dev *dev,
 				 const struct pci_device_id *ent)
 {
@@ -470,6 +454,7 @@
 	struct capi_driver *driverv4 = &b1pciv4_driver;
 #endif
 	char *p;
+	int ncards;
 
 	MOD_INC_USE_COUNT;
 
diff -u --recursive --new-file pre1/linux/drivers/isdn/avmb1/c4.c linux/drivers/isdn/avmb1/c4.c
--- pre1/linux/drivers/isdn/avmb1/c4.c	Sun Jan  6 12:23:35 2002
+++ linux/drivers/isdn/avmb1/c4.c	Thu Jan 17 14:04:15 2002
@@ -1133,28 +1133,23 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_ATOMIC);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
+
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
         cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_dma_free;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info)*4);
 	card->ctrlinfo = cinfo;
@@ -1168,53 +1163,37 @@
 	card->membase = p->membase;
 	card->cardtype = nr == 4 ? avm_c4 : avm_c2;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 128);
 	if (card->mbase == 0) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_release_region;
 	}
 
-	if ((retval = c4_detect(card)) != 0) {
+	retval = c4_detect(card);
+	if (retval != 0) {
 		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
-                iounmap(card->mbase);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_unmap;
 	}
 	c4_reset(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap(card->mbase);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-                avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_unmap;
 	}
 
 	for (i=0; i < nr ; i++) {
@@ -1228,14 +1207,7 @@
 				cinfo = &card->ctrlinfo[i];
 				di->detach_ctr(cinfo->capi_ctrl);
 			}
-                	iounmap(card->mbase);
-			free_irq(card->irq, card);
-			release_region(card->port, AVMB1_PORTLEN);
-                        avmcard_dma_free(card->dma);
-	        	kfree(card->ctrlinfo);
-			kfree(card);
-	        	MOD_DEC_USE_COUNT;
-			return -EBUSY;
+			goto err_free_irq;
 		}
 		if (i == 0)
 			card->cardnr = cinfo->capi_ctrl->cnr;
@@ -1246,6 +1218,22 @@
 		driver->name, nr, card->port, card->irq, card->membase);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_dma_free:
+	avmcard_dma_free(card->dma);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 /* ------------------------------------------------------------- */
diff -u --recursive --new-file pre1/linux/drivers/isdn/avmb1/t1pci.c linux/drivers/isdn/avmb1/t1pci.c
--- pre1/linux/drivers/isdn/avmb1/t1pci.c	Sun Jan  6 12:23:35 2002
+++ linux/drivers/isdn/avmb1/t1pci.c	Thu Jan 17 14:04:15 2002
@@ -49,27 +49,6 @@
 
 /* ------------------------------------------------------------- */
 
-static void t1pci_remove_ctr(struct capi_ctr *ctrl)
-{
-	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
-	avmcard *card = cinfo->card;
-
- 	b1dma_reset(card);
-
-	di->detach_ctr(ctrl);
-	free_irq(card->irq, card);
-	iounmap(card->mbase);
-	release_region(card->port, AVMB1_PORTLEN);
-	ctrl->driverdata = 0;
-	kfree(card->ctrlinfo);
-	avmcard_dma_free(card->dma);
-	kfree(card);
-
-	MOD_DEC_USE_COUNT;
-}
-
-/* ------------------------------------------------------------- */
-
 static int t1pci_add_card(struct capi_driver *driver,
                           struct capicardparams *p,
 	                  struct pci_dev *dev)
@@ -80,28 +59,22 @@
 
 	MOD_INC_USE_COUNT;
 
-	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
-
+	retval = -ENOMEM;
+	card = kmalloc(sizeof(avmcard), GFP_KERNEL);
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err;
 	}
 	memset(card, 0, sizeof(avmcard));
         card->dma = avmcard_dma_alloc(driver->name, dev, 2048+128, 2048+128);
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_kfree;
 	}
-        cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info), GFP_ATOMIC);
+        cinfo = kmalloc(sizeof(avmctrl_info), GFP_KERNEL);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -ENOMEM;
+		goto err_dma_free;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
 	card->ctrlinfo = cinfo;
@@ -112,72 +85,50 @@
 	card->membase = p->membase;
 	card->cardtype = avm_t1pci;
 
-	if (check_region(card->port, AVMB1_PORTLEN)) {
+	if (!request_region(card->port, AVMB1_PORTLEN, card->name)) {
 		printk(KERN_WARNING
 		       "%s: ports 0x%03x-0x%03x in use.\n",
 		       driver->name, card->port, card->port + AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_kfree_ctrlinfo;
 	}
 
 	card->mbase = ioremap_nocache(card->membase, 64);
 	if (!card->mbase) {
 		printk(KERN_NOTICE "%s: can't remap memory at 0x%lx\n",
 					driver->name, card->membase);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_release_region;
 	}
 
 	b1dma_reset(card);
 
-	if ((retval = t1pci_detect(card)) != 0) {
+	retval = t1pci_detect(card);
+	if (retval != 0) {
 		if (retval < 6)
 			printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
 					driver->name, card->port, retval);
 		else
 			printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n",
 					driver->name, card->port, retval);
-                iounmap(card->mbase);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EIO;
+		retval = -EIO;
+		goto err_unmap;
 	}
 	b1dma_reset(card);
 
-	request_region(p->port, AVMB1_PORTLEN, card->name);
-
 	retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
 	if (retval) {
 		printk(KERN_ERR "%s: unable to get IRQ %d.\n",
 				driver->name, card->irq);
-                iounmap(card->mbase);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_unmap;
 	}
 
 	cinfo->capi_ctrl = di->attach_ctr(driver, card->name, cinfo);
 	if (!cinfo->capi_ctrl) {
 		printk(KERN_ERR "%s: attach controller failed.\n", driver->name);
-                iounmap(card->mbase);
-		free_irq(card->irq, card);
-		release_region(card->port, AVMB1_PORTLEN);
-	        kfree(card->ctrlinfo);
-		avmcard_dma_free(card->dma);
-		kfree(card);
-	        MOD_DEC_USE_COUNT;
-		return -EBUSY;
+		retval = -EBUSY;
+		goto err_free_irq;
 	}
 	card->cardnr = cinfo->capi_ctrl->cnr;
 
@@ -186,6 +137,43 @@
 		driver->name, card->port, card->irq, card->membase);
 
 	return 0;
+
+ err_free_irq:
+	free_irq(card->irq, card);
+ err_unmap:
+	iounmap(card->mbase);
+ err_release_region:
+	release_region(card->port, AVMB1_PORTLEN);
+ err_kfree_ctrlinfo:
+	kfree(card->ctrlinfo);
+ err_dma_free:
+	avmcard_dma_free(card->dma);
+ err_kfree:
+	kfree(card);
+ err:
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+/* ------------------------------------------------------------- */
+
+static void t1pci_remove_ctr(struct capi_ctr *ctrl)
+{
+	avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
+	avmcard *card = cinfo->card;
+
+ 	b1dma_reset(card);
+
+	di->detach_ctr(ctrl);
+	free_irq(card->irq, card);
+	iounmap(card->mbase);
+	release_region(card->port, AVMB1_PORTLEN);
+	ctrl->driverdata = 0;
+	kfree(card->ctrlinfo);
+	avmcard_dma_free(card->dma);
+	kfree(card);
+
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
diff -u --recursive --new-file pre1/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c
--- pre1/linux/drivers/isdn/isdn_common.c	Thu Jan  3 12:20:10 2002
+++ linux/drivers/isdn/isdn_common.c	Thu Jan 17 14:04:15 2002
@@ -65,7 +65,6 @@
 #endif /* CONFIG_ISDN_DIVERSION */
 
 
-static int isdn_writebuf_stub(int, int, const u_char *, int, int);
 static void set_global_features(void);
 static void isdn_register_devfs(int);
 static void isdn_unregister_devfs(int);
@@ -946,7 +945,9 @@
 	return istatbuf;
 }
 
-/* Module interface-code */
+/* 
+ * /dev/isdninfo
+ */
 
 void
 isdn_info_update(void)
@@ -960,234 +961,309 @@
 	wake_up_interruptible(&(dev->info_waitq));
 }
 
+static int
+isdn_status_open(struct inode *ino, struct file *filep)
+{
+	infostruct *p;
+	
+	p = kmalloc(sizeof(infostruct), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	p->next = (char *) dev->infochain;
+	p->private = (char *) &(filep->private_data);
+	dev->infochain = p;
+	/* At opening we allow a single update */
+	filep->private_data = (char *) 1;
+
+	return 0;
+}
+
+static int
+isdn_status_release(struct inode *ino, struct file *filep)
+{
+	infostruct *p = dev->infochain;
+	infostruct *q = NULL;
+	
+	lock_kernel();
+
+	while (p) {
+		if (p->private == (char *) &(filep->private_data)) {
+			if (q)
+				q->next = p->next;
+			else
+				dev->infochain = (infostruct *) (p->next);
+			kfree(p);
+			goto out;
+		}
+		q = p;
+		p = (infostruct *) (p->next);
+	}
+	printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
+
+ out:
+	unlock_kernel();
+	return 0;
+}
+
 static ssize_t
-isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
+isdn_status_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
-	uint minor = minor(file->f_dentry->d_inode->i_rdev);
-	int len = 0;
-	ulong flags;
-	int drvidx;
-	int chidx;
 	int retval;
+	int len = 0;
 	char *p;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
 
 	lock_kernel();
-	if (minor == ISDN_MINOR_STATUS) {
-		if (!file->private_data) {
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				goto out;
-			}
-			interruptible_sleep_on(&(dev->info_waitq));
-		}
-		p = isdn_statstr();
-		file->private_data = 0;
-		if ((len = strlen(p)) <= count) {
-			if (copy_to_user(buf, p, len)) {
-				retval = -EFAULT;
-				goto out;
-			}
-			*off += len;
-			retval = len;
+	if (!file->private_data) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
 			goto out;
 		}
-		retval = 0;
-		goto out;
-	}
-	if (!dev->drivers) {
-		retval = -ENODEV;
-		goto out;
+		interruptible_sleep_on(&(dev->info_waitq));
 	}
-	if (minor <= ISDN_MINOR_BMAX) {
-		printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0) {
-			retval = -ENODEV;
-			goto out;
-		}
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
-			retval = -ENODEV;
+	p = isdn_statstr();
+	file->private_data = 0;
+	if ((len = strlen(p)) <= count) {
+		if (copy_to_user(buf, p, len)) {
+			retval = -EFAULT;
 			goto out;
 		}
-		chidx = isdn_minor2chan(minor);
-		if (!(p = kmalloc(count, GFP_KERNEL))) {
-			retval = -ENOMEM;
-			goto out;
-		}
-		save_flags(flags);
-		cli();
-		len = isdn_readbchan(drvidx, chidx, p, 0, count,
-				     &dev->drv[drvidx]->rcv_waitq[chidx]);
-		*off += len;
-		restore_flags(flags);
-		if (copy_to_user(buf,p,len)) 
-			len = -EFAULT;
-		kfree(p);
-		retval = len;
-		goto out;
-	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0) {
-			retval = -ENODEV;
-			goto out;
-		}
-		if (!dev->drv[drvidx]->stavail) {
-			if (file->f_flags & O_NONBLOCK) {
-				retval = -EAGAIN;
-				goto out;
-			}
-			interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
-		}
-		if (dev->drv[drvidx]->interface->readstat) {
-			if (count > dev->drv[drvidx]->stavail)
-				count = dev->drv[drvidx]->stavail;
-			len = dev->drv[drvidx]->interface->
-				readstat(buf, count, 1, drvidx,
-					 isdn_minor2chan(minor));
-		} else {
-			len = 0;
-		}
-		save_flags(flags);
-		cli();
-		if (len)
-			dev->drv[drvidx]->stavail -= len;
-		else
-			dev->drv[drvidx]->stavail = 0;
-		restore_flags(flags);
 		*off += len;
 		retval = len;
 		goto out;
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
-		goto out;
-	}
-#endif
-	retval = -ENODEV;
+	retval = 0;
+	goto out;
+
  out:
 	unlock_kernel();
 	return retval;
 }
 
 static ssize_t
-isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
+isdn_status_write(struct file *file, const char *buf, size_t count, loff_t *off)
+{
+	return -EPERM;
+}
+
+static unsigned int
+isdn_status_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+
+	lock_kernel();
+
+	poll_wait(file, &(dev->info_waitq), wait);
+	if (file->private_data)
+		mask |= POLLIN | POLLRDNORM;
+
+	unlock_kernel();
+	return mask;
+}
+
+static int
+isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+	int ret;
+	union iocpar {
+		char name[10];
+		char bname[22];
+		isdn_ioctl_struct iocts;
+		isdn_net_ioctl_phone phone;
+		isdn_net_ioctl_cfg cfg;
+	} iocpar;
+
+#define name  iocpar.name
+#define bname iocpar.bname
+#define iocts iocpar.iocts
+#define phone iocpar.phone
+#define cfg   iocpar.cfg
+
+	switch (cmd) {
+	case IIOCGETDVR:
+		return (TTY_DV +
+			(NET_DV << 8) +
+			(INF_DV << 16));
+	case IIOCGETCPS:
+		if (arg) {
+			ulong *p = (ulong *) arg;
+			int i;
+			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
+				return ret;
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+				put_user(dev->ibytes[i], p++);
+				put_user(dev->obytes[i], p++);
+			}
+			return 0;
+		} else
+			return -EINVAL;
+		break;
+#ifdef CONFIG_NETDEVICES
+	case IIOCNETGPN:
+		/* Get peer phone number of a connected 
+		 * isdn network interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
+		} else
+			return -EINVAL;
+#endif
+	default:
+		return -EINVAL;
+	}
+
+#undef name
+#undef bname
+#undef iocts
+#undef phone
+#undef cfg
+}
+
+/*
+ * /dev/isdnctrlX
+ */
+
+static int
+isdn_ctrl_open(struct inode *ino, struct file *filep)
+{
+	uint minor = minor(ino->i_rdev);
+	int drvidx;
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0)
+		return -ENODEV;
+
+	isdn_lock_drivers();
+	return 0;
+}
+
+static int
+isdn_ctrl_release(struct inode *ino, struct file *filep)
+{
+	lock_kernel();
+
+	if (dev->profd == current)
+		dev->profd = NULL;
+
+	isdn_unlock_drivers();
+
+	unlock_kernel();
+	return 0;
+}
+
+static ssize_t
+isdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off)
 {
 	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+	ulong flags;
+	int len = 0;
 	int drvidx;
-	int chidx;
 	int retval;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
 
-	if (minor == ISDN_MINOR_STATUS)
-		return -EPERM;
-	if (!dev->drivers)
-		return -ENODEV;
-
 	lock_kernel();
-	if (minor <= ISDN_MINOR_BMAX) {
-		printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0) {
-			retval = -ENODEV;
-			goto out;
-		}
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
-			retval = -ENODEV;
-			goto out;
-		}
-		chidx = isdn_minor2chan(minor);
-		while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
-			interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
-		retval = count;
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0) {
+		retval = -ENODEV;
 		goto out;
 	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0) {
-			retval = -ENODEV;
+	if (!dev->drv[drvidx]->stavail) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
 			goto out;
 		}
-		/*
-		 * We want to use the isdnctrl device to load the firmware
-		 *
-		 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-		 return -ENODEV;
-		 */
-		if (dev->drv[drvidx]->interface->writecmd)
-			retval = dev->drv[drvidx]->interface->
-				writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor));
-		else
-			retval = count;
-		goto out;
+		interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
-		goto out;
+	if (dev->drv[drvidx]->interface->readstat) {
+		if (count > dev->drv[drvidx]->stavail)
+			count = dev->drv[drvidx]->stavail;
+		len = dev->drv[drvidx]->interface->
+			readstat(buf, count, 1, drvidx,
+				 isdn_minor2chan(minor));
+	} else {
+		len = 0;
 	}
-#endif
-	retval = -ENODEV;
+	save_flags(flags);
+	cli();
+	if (len)
+		dev->drv[drvidx]->stavail -= len;
+	else
+		dev->drv[drvidx]->stavail = 0;
+	restore_flags(flags);
+	*off += len;
+	retval = len;
+	
  out:
 	unlock_kernel();
 	return retval;
 }
 
-static unsigned int
-isdn_poll(struct file *file, poll_table * wait)
+static ssize_t
+isdn_ctrl_write(struct file *file, const char *buf, size_t count, loff_t *off)
 {
-	unsigned int mask = 0;
-	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
-	int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+	int drvidx;
+	int retval;
+
+	if (off != &file->f_pos)
+		return -ESPIPE;
 
 	lock_kernel();
-	if (minor == ISDN_MINOR_STATUS) {
-		poll_wait(file, &(dev->info_waitq), wait);
-		/* mask = POLLOUT | POLLWRNORM; */
-		if (file->private_data) {
-			mask |= POLLIN | POLLRDNORM;
-		}
-		goto out;
-	}
-	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
-		if (drvidx < 0) {
-			/* driver deregistered while file open */
-			mask = POLLHUP;
-			goto out;
-		}
-		poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
-		mask = POLLOUT | POLLWRNORM;
-		if (dev->drv[drvidx]->stavail) {
-			mask |= POLLIN | POLLRDNORM;
-		}
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0) {
+		retval = -ENODEV;
 		goto out;
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		mask = isdn_ppp_poll(file, wait);
+	if (!dev->drv[drvidx]->interface->writecmd) {
+		retval = -EINVAL;
 		goto out;
 	}
-#endif
-	mask = POLLERR;
+	retval = dev->drv[drvidx]->interface->
+		writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
+
  out:
 	unlock_kernel();
+	return retval;
+}
+
+static unsigned int
+isdn_ctrl_poll(struct file *file, poll_table *wait)
+{
+	unsigned int mask = 0;
+	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
+	int drvidx;
+
+	drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+	if (drvidx < 0)
+		/* driver deregistered while file open */
+		return POLLHUP;
+
+	lock_kernel();
+
+	poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
+	mask = POLLOUT | POLLWRNORM;
+	if (dev->drv[drvidx]->stavail)
+		mask |= POLLIN | POLLRDNORM;
+
+	unlock_kernel();
 	return mask;
 }
 
 
 static int
-isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
 {
-	uint minor = minor(inode->i_rdev);
 	isdn_ctrl c;
 	int drvidx;
-	int chidx;
 	int ret;
 	int i;
 	char *p;
@@ -1205,55 +1281,6 @@
 #define iocts iocpar.iocts
 #define phone iocpar.phone
 #define cfg   iocpar.cfg
-
-	if (minor == ISDN_MINOR_STATUS) {
-		switch (cmd) {
-			case IIOCGETDVR:
-				return (TTY_DV +
-					(NET_DV << 8) +
-					(INF_DV << 16));
-			case IIOCGETCPS:
-				if (arg) {
-					ulong *p = (ulong *) arg;
-					int i;
-					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-							       sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
-						return ret;
-					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-						put_user(dev->ibytes[i], p++);
-						put_user(dev->obytes[i], p++);
-					}
-					return 0;
-				} else
-					return -EINVAL;
-				break;
-#ifdef CONFIG_NETDEVICES
-			case IIOCNETGPN:
-				/* Get peer phone number of a connected 
-				 * isdn network interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					return isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
-				} else
-					return -EINVAL;
-#endif
-			default:
-				return -EINVAL;
-		}
-	}
-	if (!dev->drivers)
-		return -ENODEV;
-	if (minor <= ISDN_MINOR_BMAX) {
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			return -ENODEV;
-		chidx = isdn_minor2chan(minor);
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			return -ENODEV;
-		return 0;
-	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
 /*
  * isdn net devices manage lots of configuration variables as linked lists.
  * Those lists must only be manipulated from user space. Some of the ioctl's
@@ -1261,366 +1288,360 @@
  * manipulating the lists and ioctl's sleeping while accessing the lists
  * are serialized by means of a semaphore.
  */
-		switch (cmd) {
-			case IIOCNETDWRSET:
-				printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
-				return(-EINVAL);
-			case IIOCNETLCR:
-				printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
-				return -ENODEV;
+	switch (cmd) {
+	case IIOCNETDWRSET:
+		printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n");
+		return(-EINVAL);
+	case IIOCNETLCR:
+		printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n");
+		return -ENODEV;
 #ifdef CONFIG_NETDEVICES
-			case IIOCNETAIF:
-				/* Add a network-interface */
-				if (arg) {
-					if (copy_from_user(name, (char *) arg, sizeof(name)))
-						return -EFAULT;
-					s = name;
-				} else {
-					s = NULL;
-				}
-				ret = down_interruptible(&dev->sem);
-				if( ret ) return ret;
-				if ((s = isdn_net_new(s, NULL))) {
-					if (copy_to_user((char *) arg, s, strlen(s) + 1)){
-						ret = -EFAULT;
-					} else {
-						ret = 0;
+	case IIOCNETAIF:
+		/* Add a network-interface */
+		if (arg) {
+			if (copy_from_user(name, (char *) arg, sizeof(name)))
+				return -EFAULT;
+			s = name;
+		} else {
+			s = NULL;
+		}
+		ret = down_interruptible(&dev->sem);
+		if( ret ) return ret;
+		if ((s = isdn_net_new(s, NULL))) {
+			if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+				ret = -EFAULT;
+			} else {
+				ret = 0;
+			}
+		} else
+			ret = -ENODEV;
+		up(&dev->sem);
+		return ret;
+	case IIOCNETASL:
+		/* Add a slave to a network-interface */
+		if (arg) {
+			if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
+				return -EFAULT;
+		} else
+			return -EINVAL;
+		ret = down_interruptible(&dev->sem);
+		if( ret ) return ret;
+		if ((s = isdn_net_newslave(bname))) {
+			if (copy_to_user((char *) arg, s, strlen(s) + 1)){
+				ret = -EFAULT;
+			} else {
+				ret = 0;
+			}
+		} else
+			ret = -ENODEV;
+		up(&dev->sem);
+		return ret;
+	case IIOCNETDIF:
+		/* Delete a network-interface */
+		if (arg) {
+			if (copy_from_user(name, (char *) arg, sizeof(name)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_rm(name);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETSCF:
+		/* Set configurable parameters of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+				return -EFAULT;
+			return isdn_net_setcfg(&cfg);
+		} else
+			return -EINVAL;
+	case IIOCNETGCF:
+		/* Get configurable parameters of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
+				return -EFAULT;
+			if (!(ret = isdn_net_getcfg(&cfg))) {
+				if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
+					return -EFAULT;
+			}
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETANM:
+		/* Add a phone-number to a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_addphone(&phone);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETGNM:
+		/* Get list of phone-numbers of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_getphones(&phone, (char *) arg);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETDNM:
+		/* Delete a phone-number of a network-interface */
+		if (arg) {
+			if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
+				return -EFAULT;
+			ret = down_interruptible(&dev->sem);
+			if( ret ) return ret;
+			ret = isdn_net_delphone(&phone);
+			up(&dev->sem);
+			return ret;
+		} else
+			return -EINVAL;
+	case IIOCNETDIL:
+		/* Force dialing of a network-interface */
+		if (arg) {
+			if (copy_from_user(name, (char *) arg, sizeof(name)))
+				return -EFAULT;
+			return isdn_net_force_dial(name);
+		} else
+			return -EINVAL;
+#ifdef CONFIG_ISDN_PPP
+	case IIOCNETALN:
+		if (!arg)
+			return -EINVAL;
+		if (copy_from_user(name, (char *) arg, sizeof(name)))
+			return -EFAULT;
+		return isdn_ppp_dial_slave(name);
+	case IIOCNETDLN:
+		if (!arg)
+			return -EINVAL;
+		if (copy_from_user(name, (char *) arg, sizeof(name)))
+			return -EFAULT;
+		return isdn_ppp_hangup_slave(name);
+#endif
+	case IIOCNETHUP:
+		/* Force hangup of a network-interface */
+		if (!arg)
+			return -EINVAL;
+		if (copy_from_user(name, (char *) arg, sizeof(name)))
+			return -EFAULT;
+		return isdn_net_force_hangup(name);
+		break;
+#endif                          /* CONFIG_NETDEVICES */
+	case IIOCSETVER:
+		dev->net_verbose = arg;
+		printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
+		return 0;
+	case IIOCSETGST:
+		if (arg)
+			dev->global_flags |= ISDN_GLOBAL_STOPPED;
+		else
+			dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
+		printk(KERN_INFO "isdn: Global Mode %s\n",
+		       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
+		return 0;
+	case IIOCSETBRJ:
+		drvidx = -1;
+		if (arg) {
+			int i;
+			char *p;
+			if (copy_from_user((char *) &iocts, (char *) arg,
+					   sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			if (strlen(iocts.drvid)) {
+				if ((p = strchr(iocts.drvid, ',')))
+					*p = 0;
+				drvidx = -1;
+				for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+					if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+						drvidx = i;
+						break;
 					}
-				} else
-					ret = -ENODEV;
-				up(&dev->sem);
+			}
+		}
+		if (drvidx == -1)
+			return -ENODEV;
+		if (iocts.arg)
+			dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
+		else
+			dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
+		return 0;
+	case IIOCSIGPRF:
+		dev->profd = current;
+		return 0;
+		break;
+	case IIOCGETPRF:
+		/* Get all Modem-Profiles */
+		if (arg) {
+			char *p = (char *) arg;
+			int i;
+
+			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					       (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+					       * ISDN_MAX_CHANNELS)))
 				return ret;
-			case IIOCNETASL:
-				/* Add a slave to a network-interface */
-				if (arg) {
-					if (copy_from_user(bname, (char *) arg, sizeof(bname) - 1))
-						return -EFAULT;
-				} else
-					return -EINVAL;
-				ret = down_interruptible(&dev->sem);
-				if( ret ) return ret;
-				if ((s = isdn_net_newslave(bname))) {
-					if (copy_to_user((char *) arg, s, strlen(s) + 1)){
-						ret = -EFAULT;
-					} else {
-						ret = 0;
-					}
-				} else
-					ret = -ENODEV;
-				up(&dev->sem);
+
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+				if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+						 ISDN_MODEM_NUMREG))
+					return -EFAULT;
+				p += ISDN_MODEM_NUMREG;
+				if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+					return -EFAULT;
+				p += ISDN_MSNLEN;
+				if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
+					return -EFAULT;
+				p += ISDN_LMSNLEN;
+			}
+			return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
+		} else
+			return -EINVAL;
+		break;
+	case IIOCSETPRF:
+		/* Set all Modem-Profiles */
+		if (arg) {
+			char *p = (char *) arg;
+			int i;
+
+			if ((ret = verify_area(VERIFY_READ, (void *) arg,
+					       (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
+					       * ISDN_MAX_CHANNELS)))
 				return ret;
-			case IIOCNETDIF:
-				/* Delete a network-interface */
-				if (arg) {
-					if (copy_from_user(name, (char *) arg, sizeof(name)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_rm(name);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETSCF:
-				/* Set configurable parameters of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
-						return -EFAULT;
-					return isdn_net_setcfg(&cfg);
-				} else
-					return -EINVAL;
-			case IIOCNETGCF:
-				/* Get configurable parameters of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &cfg, (char *) arg, sizeof(cfg)))
-						return -EFAULT;
-					if (!(ret = isdn_net_getcfg(&cfg))) {
-						if (copy_to_user((char *) arg, (char *) &cfg, sizeof(cfg)))
-							return -EFAULT;
-					}
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETANM:
-				/* Add a phone-number to a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_addphone(&phone);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETGNM:
-				/* Get list of phone-numbers of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_getphones(&phone, (char *) arg);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETDNM:
-				/* Delete a phone-number of a network-interface */
-				if (arg) {
-					if (copy_from_user((char *) &phone, (char *) arg, sizeof(phone)))
-						return -EFAULT;
-					ret = down_interruptible(&dev->sem);
-					if( ret ) return ret;
-					ret = isdn_net_delphone(&phone);
-					up(&dev->sem);
-					return ret;
-				} else
-					return -EINVAL;
-			case IIOCNETDIL:
-				/* Force dialing of a network-interface */
-				if (arg) {
-					if (copy_from_user(name, (char *) arg, sizeof(name)))
-						return -EFAULT;
-					return isdn_net_force_dial(name);
-				} else
-					return -EINVAL;
-#ifdef CONFIG_ISDN_PPP
-			case IIOCNETALN:
-				if (!arg)
-					return -EINVAL;
-				if (copy_from_user(name, (char *) arg, sizeof(name)))
+
+			for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+				if (copy_from_user(dev->mdm.info[i].emu.profile, p,
+						   ISDN_MODEM_NUMREG))
 					return -EFAULT;
-				return isdn_ppp_dial_slave(name);
-			case IIOCNETDLN:
-				if (!arg)
-					return -EINVAL;
-				if (copy_from_user(name, (char *) arg, sizeof(name)))
+				p += ISDN_MODEM_NUMREG;
+				if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
 					return -EFAULT;
-				return isdn_ppp_hangup_slave(name);
-#endif
-			case IIOCNETHUP:
-				/* Force hangup of a network-interface */
-				if (!arg)
-					return -EINVAL;
-				if (copy_from_user(name, (char *) arg, sizeof(name)))
+				p += ISDN_LMSNLEN;
+				if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
 					return -EFAULT;
-				return isdn_net_force_hangup(name);
-				break;
-#endif                          /* CONFIG_NETDEVICES */
-			case IIOCSETVER:
-				dev->net_verbose = arg;
-				printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose);
-				return 0;
-			case IIOCSETGST:
-				if (arg)
-					dev->global_flags |= ISDN_GLOBAL_STOPPED;
-				else
-					dev->global_flags &= ~ISDN_GLOBAL_STOPPED;
-				printk(KERN_INFO "isdn: Global Mode %s\n",
-				       (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running");
-				return 0;
-			case IIOCSETBRJ:
+				p += ISDN_MSNLEN;
+			}
+			return 0;
+		} else
+			return -EINVAL;
+		break;
+	case IIOCSETMAP:
+	case IIOCGETMAP:
+		/* Set/Get MSN->EAZ-Mapping for a driver */
+		if (arg) {
+
+			if (copy_from_user((char *) &iocts,
+					   (char *) arg,
+					   sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			if (strlen(iocts.drvid)) {
 				drvidx = -1;
-				if (arg) {
-					int i;
-					char *p;
-					if (copy_from_user((char *) &iocts, (char *) arg,
-					     sizeof(isdn_ioctl_struct)))
-						return -EFAULT;
-					if (strlen(iocts.drvid)) {
-						if ((p = strchr(iocts.drvid, ',')))
-							*p = 0;
-						drvidx = -1;
-						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-								drvidx = i;
-								break;
-							}
-					}
-				}
-				if (drvidx == -1)
-					return -ENODEV;
-				if (iocts.arg)
-					dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
-				else
-					dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
-				return 0;
-			case IIOCSIGPRF:
-				dev->profd = current;
-				return 0;
-				break;
-			case IIOCGETPRF:
-				/* Get all Modem-Profiles */
-				if (arg) {
-					char *p = (char *) arg;
-					int i;
-
-					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-						   * ISDN_MAX_CHANNELS)))
-						return ret;
-
-					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-						if (copy_to_user(p, dev->mdm.info[i].emu.profile,
-						      ISDN_MODEM_NUMREG))
-							return -EFAULT;
-						p += ISDN_MODEM_NUMREG;
-						if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
-							return -EFAULT;
-						p += ISDN_MSNLEN;
-						if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
-							return -EFAULT;
-						p += ISDN_LMSNLEN;
-					}
-					return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS;
-				} else
-					return -EINVAL;
-				break;
-			case IIOCSETPRF:
-				/* Set all Modem-Profiles */
-				if (arg) {
-					char *p = (char *) arg;
-					int i;
-
-					if ((ret = verify_area(VERIFY_READ, (void *) arg,
-					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
-						   * ISDN_MAX_CHANNELS)))
-						return ret;
-
-					for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-						if (copy_from_user(dev->mdm.info[i].emu.profile, p,
-						     ISDN_MODEM_NUMREG))
-							return -EFAULT;
-						p += ISDN_MODEM_NUMREG;
-						if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
-							return -EFAULT;
-						p += ISDN_LMSNLEN;
-						if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
-							return -EFAULT;
-						p += ISDN_MSNLEN;
+				for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+					if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+						drvidx = i;
+						break;
 					}
-					return 0;
-				} else
-					return -EINVAL;
-				break;
-			case IIOCSETMAP:
-			case IIOCGETMAP:
-				/* Set/Get MSN->EAZ-Mapping for a driver */
-				if (arg) {
-
-					if (copy_from_user((char *) &iocts,
-							    (char *) arg,
-					     sizeof(isdn_ioctl_struct)))
-						return -EFAULT;
-					if (strlen(iocts.drvid)) {
-						drvidx = -1;
-						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-								drvidx = i;
-								break;
-							}
-					} else
-						drvidx = 0;
-					if (drvidx == -1)
-						return -ENODEV;
-					if (cmd == IIOCSETMAP) {
-						int loop = 1;
-
-						p = (char *) iocts.arg;
-						i = 0;
-						while (loop) {
-							int j = 0;
-
-							while (1) {
-								if ((ret = verify_area(VERIFY_READ, p, 1)))
-									return ret;
-								get_user(bname[j], p++);
-								switch (bname[j]) {
-									case '\0':
-										loop = 0;
-										/* Fall through */
-									case ',':
-										bname[j] = '\0';
-										strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
-										j = ISDN_MSNLEN;
-										break;
-									default:
-										j++;
-								}
-								if (j >= ISDN_MSNLEN)
-									break;
-							}
-							if (++i > 9)
-								break;
-						}
-					} else {
-						p = (char *) iocts.arg;
-						for (i = 0; i < 10; i++) {
-							sprintf(bname, "%s%s",
-								strlen(dev->drv[drvidx]->msn2eaz[i]) ?
-								dev->drv[drvidx]->msn2eaz[i] : "_",
-								(i < 9) ? "," : "\0");
-							if (copy_to_user(p, bname, strlen(bname) + 1))
-								return -EFAULT;
-							p += strlen(bname);
+			} else
+				drvidx = 0;
+			if (drvidx == -1)
+				return -ENODEV;
+			if (cmd == IIOCSETMAP) {
+				int loop = 1;
+
+				p = (char *) iocts.arg;
+				i = 0;
+				while (loop) {
+					int j = 0;
+
+					while (1) {
+						if ((ret = verify_area(VERIFY_READ, p, 1)))
+							return ret;
+						get_user(bname[j], p++);
+						switch (bname[j]) {
+						case '\0':
+							loop = 0;
+							/* Fall through */
+						case ',':
+							bname[j] = '\0';
+							strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+							j = ISDN_MSNLEN;
+							break;
+						default:
+							j++;
 						}
+						if (j >= ISDN_MSNLEN)
+							break;
 					}
-					return 0;
-				} else
-					return -EINVAL;
-			case IIOCDBGVAR:
-				if (arg) {
-					if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
-						return -EFAULT;
-					return 0;
-				} else
-					return -EINVAL;
-				break;
-			default:
-				if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
-					cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
-				else
-					return -EINVAL;
-				if (arg) {
-					int i;
-					char *p;
-					if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
-						return -EFAULT;
-					if (strlen(iocts.drvid)) {
-						if ((p = strchr(iocts.drvid, ',')))
-							*p = 0;
-						drvidx = -1;
-						for (i = 0; i < ISDN_MAX_DRIVERS; i++)
-							if (!(strcmp(dev->drvid[i], iocts.drvid))) {
-								drvidx = i;
-								break;
-							}
-					} else
-						drvidx = 0;
-					if (drvidx == -1)
-						return -ENODEV;
-					if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
-					     sizeof(isdn_ioctl_struct))))
-						return ret;
-					c.driver = drvidx;
-					c.command = ISDN_CMD_IOCTL;
-					c.arg = cmd;
-					memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
-					ret = isdn_command(&c);
-					memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
-					if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+					if (++i > 9)
+						break;
+				}
+			} else {
+				p = (char *) iocts.arg;
+				for (i = 0; i < 10; i++) {
+					sprintf(bname, "%s%s",
+						strlen(dev->drv[drvidx]->msn2eaz[i]) ?
+						dev->drv[drvidx]->msn2eaz[i] : "_",
+						(i < 9) ? "," : "\0");
+					if (copy_to_user(p, bname, strlen(bname) + 1))
 						return -EFAULT;
-					return ret;
-				} else
-					return -EINVAL;
-		}
+					p += strlen(bname);
+				}
+			}
+			return 0;
+		} else
+			return -EINVAL;
+	case IIOCDBGVAR:
+		if (arg) {
+			if (copy_to_user((char *) arg, (char *) &dev, sizeof(ulong)))
+				return -EFAULT;
+			return 0;
+		} else
+			return -EINVAL;
+		break;
+	default:
+		if ((cmd & IIOCDRVCTL) == IIOCDRVCTL)
+			cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK;
+		else
+			return -EINVAL;
+		if (arg) {
+			int i;
+			char *p;
+			if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			if (strlen(iocts.drvid)) {
+				if ((p = strchr(iocts.drvid, ',')))
+					*p = 0;
+				drvidx = -1;
+				for (i = 0; i < ISDN_MAX_DRIVERS; i++)
+					if (!(strcmp(dev->drvid[i], iocts.drvid))) {
+						drvidx = i;
+						break;
+					}
+			} else
+				drvidx = 0;
+			if (drvidx == -1)
+				return -ENODEV;
+			if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
+					       sizeof(isdn_ioctl_struct))))
+				return ret;
+			c.driver = drvidx;
+			c.command = ISDN_CMD_IOCTL;
+			c.arg = cmd;
+			memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
+			ret = isdn_command(&c);
+			memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
+			if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
+				return -EFAULT;
+			return ret;
+		} else
+			return -EINVAL;
 	}
-#ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg));
-#endif
-	return -ENODEV;
 
 #undef name
 #undef bname
@@ -1630,67 +1651,120 @@
 }
 
 /*
+ *
+ */
+
+static ssize_t
+isdn_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
+	
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_read(file, buf, count, off);
+
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_read(file, buf, count, off);
+#endif
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_read(file, buf, count, off);
+
+	return -ENODEV;
+}
+
+static ssize_t
+isdn_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+	uint minor = minor(file->f_dentry->d_inode->i_rdev);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
+
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_write(file, buf, count, off);
+
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_write(file, buf, count, off);
+#endif
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_write(file, buf, count, off);
+
+	return -ENODEV;
+}
+
+static unsigned int
+isdn_poll(struct file *file, poll_table * wait)
+{
+	unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return POLLERR;
+
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_poll(file, wait);
+
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_poll(file, wait);
+#endif
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_poll(file, wait);
+
+	return POLLERR;
+}
+
+static int
+isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
+{
+	uint minor = minor(inode->i_rdev);
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_ioctl(inode, file, cmd, arg);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
+
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_ioctl(inode, file, cmd, arg);
+
+#ifdef CONFIG_ISDN_PPP
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_ioctl(inode, file, cmd, arg);
+#endif
+
+	return -ENODEV;
+}
+
+/*
  * Open the device code.
  */
 static int
 isdn_open(struct inode *ino, struct file *filep)
 {
 	uint minor = minor(ino->i_rdev);
-	int drvidx;
-	int chidx;
-	int retval = -ENODEV;
 
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
 
-	if (minor == ISDN_MINOR_STATUS) {
-		infostruct *p;
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_open(ino, filep);
+
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_open(ino, filep);
 
-		if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) {
-			p->next = (char *) dev->infochain;
-			p->private = (char *) &(filep->private_data);
-			dev->infochain = p;
-			/* At opening we allow a single update */
-			filep->private_data = (char *) 1;
-			retval = 0;
-			goto out;
-		} else {
-			retval = -ENOMEM;
-			goto out;
-		}
-	}
-	if (!dev->channels)
-		goto out;
-	if (minor <= ISDN_MINOR_BMAX) {
-		printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
-		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			goto out;
-		chidx = isdn_minor2chan(minor);
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			goto out;
-		if (!(dev->drv[drvidx]->online & (1 << chidx)))
-			goto out;
-		isdn_lock_drivers();
-		retval = 0;
-		goto out;
-	}
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0)
-			goto out;
-		isdn_lock_drivers();
-		retval = 0;
-		goto out;
-	}
 #ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX) {
-		retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
-		if (retval == 0)
-			isdn_lock_drivers();
-		goto out;
-	}
+	if (minor <= ISDN_MINOR_PPPMAX)
+		return isdn_ppp_open(ino, filep);
 #endif
- out:
-	return retval;
+
+	return -ENODEV;
 }
 
 static int
@@ -1698,42 +1772,21 @@
 {
 	uint minor = minor(ino->i_rdev);
 
-	lock_kernel();
-	if (minor == ISDN_MINOR_STATUS) {
-		infostruct *p = dev->infochain;
-		infostruct *q = NULL;
-
-		while (p) {
-			if (p->private == (char *) &(filep->private_data)) {
-				if (q)
-					q->next = p->next;
-				else
-					dev->infochain = (infostruct *) (p->next);
-				kfree(p);
-				goto out;
-			}
-			q = p;
-			p = (infostruct *) (p->next);
-		}
-		printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
-		goto out;
-	}
-	isdn_unlock_drivers();
-	if (minor <= ISDN_MINOR_BMAX)
-		goto out;
-	if (minor <= ISDN_MINOR_CTRLMAX) {
-		if (dev->profd == current)
-			dev->profd = NULL;
-		goto out;
-	}
+	if (minor == ISDN_MINOR_STATUS)
+		return isdn_status_release(ino, filep);
+
+	if (minor < ISDN_MINOR_CTRL)
+		return -ENODEV;
+
+	if (minor <= ISDN_MINOR_CTRLMAX)
+		return isdn_ctrl_release(ino, filep);
+
 #ifdef CONFIG_ISDN_PPP
 	if (minor <= ISDN_MINOR_PPPMAX)
-		isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
+		return isdn_ppp_release(ino, filep);
 #endif
 
- out:
-	unlock_kernel();
-	return 0;
+	return -ENODEV;
 }
 
 static struct file_operations isdn_fops =
@@ -1875,32 +1928,6 @@
 			return;
 		}
 	restore_flags(flags);
-}
-
-/*
- *  writebuf replacement for SKB_ABLE drivers
- */
-static int
-isdn_writebuf_stub(int drvidx, int chan, const u_char * buf, int len,
-		   int user)
-{
-	int ret;
-	int hl = dev->drv[drvidx]->interface->hl_hdrlen;
-	struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC);
-
-	if (!skb)
-		return 0;
-	skb_reserve(skb, hl);
-	if (user)
-		copy_from_user(skb_put(skb, len), buf, len);
-	else
-		memcpy(skb_put(skb, len), buf, len);
-	ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb);
-	if (ret <= 0)
-		dev_kfree_skb(skb);
-	if (ret > 0)
-		dev->obytes[isdn_dc2minor(drvidx, chan)] += ret;
-	return ret;
 }
 
 /*
diff -u --recursive --new-file pre1/linux/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h
--- pre1/linux/drivers/isdn/isdn_common.h	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/isdn_common.h	Thu Jan 17 14:04:15 2002
@@ -27,6 +27,8 @@
 /* Prototypes */
 extern void isdn_MOD_INC_USE_COUNT(void);
 extern void isdn_MOD_DEC_USE_COUNT(void);
+extern void isdn_lock_drivers(void);
+extern void isdn_unlock_drivers(void);
 extern void isdn_free_channel(int di, int ch, int usage);
 extern void isdn_all_eaz(int di, int ch);
 extern int isdn_command(isdn_ctrl *);
diff -u --recursive --new-file pre1/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c
--- pre1/linux/drivers/isdn/isdn_ppp.c	Thu Jan  3 12:20:10 2002
+++ linux/drivers/isdn/isdn_ppp.c	Thu Jan 17 14:04:15 2002
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/isdn.h>
+#include <linux/smp_lock.h>
 #include <linux/poll.h>
 #include <linux/ppp-comp.h>
 
@@ -269,21 +270,19 @@
  */
 
 int
-isdn_ppp_open(int min, struct file *file)
+isdn_ppp_open(struct inode *ino, struct file *file)
 {
+	uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
 	int slot;
 	struct ippp_struct *is;
 
-	if (min < 0 || min > ISDN_MAX_CHANNELS)
-		return -ENODEV;
-
 	slot = isdn_ppp_get_slot();
 	if (slot < 0) {
 		return -EBUSY;
 	}
 	is = file->private_data = ippp_table[slot];
 
-		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, min, is->state);
+		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state);
 
 	/* compression stuff */
 	is->link_compressor   = is->compressor = NULL;
@@ -306,7 +305,7 @@
 	init_waitqueue_head(&is->wq);
 	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
 	is->last = is->rq;
-	is->minor = min;
+	is->minor = minor;
 #ifdef CONFIG_ISDN_PPP_VJ
 	/*
 	 * VJ header compression init
@@ -315,6 +314,7 @@
 #endif
 
 	is->state = IPPP_OPEN;
+	isdn_lock_drivers();
 
 	return 0;
 }
@@ -322,18 +322,19 @@
 /*
  * release ippp device
  */
-void
-isdn_ppp_release(int min, struct file *file)
+int
+isdn_ppp_release(struct inode *ino, struct file *file)
 {
+	uint minor = minor(ino->i_rdev) - ISDN_MINOR_PPP;
 	int i;
 	struct ippp_struct *is;
 
-	if (min < 0 || min >= ISDN_MAX_CHANNELS)
-		return;
+	lock_kernel();
+
 	is = file->private_data;
 
 	if (is->debug & 0x1)
-		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp);
+		printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) is->lp);
 
 	if (is->lp) {           /* a lp address says: this link is still up */
 		isdn_net_dev *p = is->lp->netdev;
@@ -381,6 +382,11 @@
 
 	/* this slot is ready for new connections */
 	is->state = 0;
+
+	isdn_unlock_drivers();
+	
+	unlock_kernel();
+	return 0;
 }
 
 /*
@@ -413,7 +419,7 @@
  * ippp device ioctl
  */
 int
-isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg)
+isdn_ppp_ioctl(struct inode *ino, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	unsigned long val;
 	int r,i,j;
@@ -425,7 +431,7 @@
 	lp = is->lp;
 
 	if (is->debug & 0x1)
-		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state);
+		printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", is->minor, cmd, is->state);
 
 	if (!(is->state & IPPP_OPEN))
 		return -EINVAL;
@@ -438,7 +444,7 @@
 			if ((r = get_arg((void *) arg, &val, sizeof(val) )))
 				return r;
 			printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
-			       (int) min, (int) is->unit, (int) val);
+			       (int) is->minor, (int) is->unit, (int) val);
 			return isdn_ppp_bundle(is, val);
 #else
 			return -1;
@@ -582,6 +588,7 @@
 	unsigned long flags;
 	struct ippp_struct *is;
 
+	lock_kernel();
 	is = file->private_data;
 
 	if (is->debug & 0x2)
@@ -592,10 +599,13 @@
 	poll_wait(file, &is->wq, wait);
 
 	if (!(is->state & IPPP_OPEN)) {
-		if(is->state == IPPP_CLOSEWAIT)
-			return POLLHUP;
+		if(is->state == IPPP_CLOSEWAIT) {
+			mask = POLLHUP;
+			goto out;
+		}
 		printk(KERN_DEBUG "isdn_ppp: device not open\n");
-		return POLLERR;
+		mask = POLLERR;
+		goto out;
 	}
 	/* we're always ready to send .. */
 	mask = POLLOUT | POLLWRNORM;
@@ -612,6 +622,9 @@
 		mask |= POLLIN | POLLRDNORM;
 	}
 	restore_flags(flags);
+
+ out:
+	unlock_kernel();
 	return mask;
 }
 
@@ -678,21 +691,28 @@
  */
 
 int
-isdn_ppp_read(int min, struct file *file, char *buf, int count)
+isdn_ppp_read(struct file *file, char *buf, int count, loff_t *off)
 {
 	struct ippp_struct *is;
 	struct ippp_buf_queue *b;
-	int r;
 	unsigned long flags;
 	unsigned char *save_buf;
+	int retval;
 
-	is = file->private_data;
+	if (off != &file->f_pos)
+		return -ESPIPE;
+	
+	lock_kernel();
 
-	if (!(is->state & IPPP_OPEN))
-		return 0;
+	is = file->private_data;
 
-	if ((r = verify_area(VERIFY_WRITE, (void *) buf, count)))
-		return r;
+	if (!(is->state & IPPP_OPEN)) {
+		retval = 0;
+		goto out;
+	}
+	retval = verify_area(VERIFY_WRITE, (void *) buf, count);
+	if (retval)
+		goto out;
 
 	save_flags(flags);
 	cli();
@@ -701,7 +721,8 @@
 	save_buf = b->buf;
 	if (!save_buf) {
 		restore_flags(flags);
-		return -EAGAIN;
+		retval = -EAGAIN;
+		goto out;
 	}
 	if (b->len < count)
 		count = b->len;
@@ -713,7 +734,11 @@
 	copy_to_user(buf, save_buf, count);
 	kfree(save_buf);
 
-	return count;
+	retval = count;
+
+ out:
+	unlock_kernel();
+	return retval;
 }
 
 /*
@@ -721,17 +746,25 @@
  */
 
 int
-isdn_ppp_write(int min, struct file *file, const char *buf, int count)
+isdn_ppp_write(struct file *file, const char *buf, int count, loff_t *off)
 {
 	isdn_net_local *lp;
 	struct ippp_struct *is;
 	int proto;
 	unsigned char protobuf[4];
+	int retval;
+
+	if (off != &file->f_pos)
+		return -ESPIPE;
+
+	lock_kernel();
 
 	is = file->private_data;
 
-	if (!(is->state & IPPP_CONNECT))
-		return 0;
+	if (!(is->state & IPPP_CONNECT)) {
+		retval = 0;
+		goto out;
+	}
 
 	lp = is->lp;
 
@@ -744,15 +777,18 @@
 		 * Don't reset huptimer for
 		 * LCP packets. (Echo requests).
 		 */
-		if (copy_from_user(protobuf, buf, 4))
-			return -EFAULT;
+		if (copy_from_user(protobuf, buf, 4)) {
+			retval = -EFAULT;
+			goto out;
+		}
 		proto = PPP_PROTOCOL(protobuf);
 		if (proto != PPP_LCP)
 			lp->huptimer = 0;
 
-		if (lp->isdn_device < 0 || lp->isdn_channel < 0)
-			return 0;
-
+		if (lp->isdn_device < 0 || lp->isdn_channel < 0) {
+			retval = 0;
+			goto out;
+		}
 		if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) &&
 			lp->dialstate == 0 &&
 		    (lp->flags & ISDN_NET_CONNECTED)) {
@@ -767,13 +803,15 @@
 			skb = alloc_skb(hl+count, GFP_ATOMIC);
 			if (!skb) {
 				printk(KERN_WARNING "isdn_ppp_write: out of memory!\n");
-				return count;
+				retval = count;
+				goto out;
 			}
 			skb_reserve(skb, hl);
 			if (copy_from_user(skb_put(skb, count), buf, count))
 			{
 				kfree_skb(skb);
-				return -EFAULT;
+				retval = -EFAULT;
+				goto out;
 			}
 			if (is->debug & 0x40) {
 				printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len);
@@ -785,7 +823,11 @@
 			isdn_net_write_super(lp, skb);
 		}
 	}
-	return count;
+	retval = count;
+	
+ out:
+	unlock_kernel();
+	return retval;
 }
 
 /*
diff -u --recursive --new-file pre1/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h
--- pre1/linux/drivers/isdn/isdn_ppp.h	Sun Sep 30 12:26:06 2001
+++ linux/drivers/isdn/isdn_ppp.h	Thu Jan 17 14:04:15 2002
@@ -12,9 +12,13 @@
 #include <linux/ppp_defs.h>     /* for PPP_PROTOCOL */
 #include <linux/isdn_ppp.h>	/* for isdn_ppp info */
 
-extern int isdn_ppp_read(int, struct file *, char *, int);
-extern int isdn_ppp_write(int, struct file *, const char *, int);
-extern int isdn_ppp_open(int, struct file *);
+extern int isdn_ppp_open(struct inode *, struct file *);
+extern int isdn_ppp_release(struct inode *, struct file *);
+extern int isdn_ppp_read(struct file *, char *, int, loff_t *off);
+extern int isdn_ppp_write(struct file *, const char *, int, loff_t *off);
+extern int isdn_ppp_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
+
 extern int isdn_ppp_init(void);
 extern void isdn_ppp_cleanup(void);
 extern int isdn_ppp_free(isdn_net_local *);
@@ -22,9 +26,6 @@
 extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *);
 extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *);
 extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int);
-extern unsigned int isdn_ppp_poll(struct file *, struct poll_table_struct *);
-extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
-extern void isdn_ppp_release(int, struct file *);
 extern int isdn_ppp_dial_slave(char *);
 extern void isdn_ppp_wakeup_daemon(isdn_net_local *);
 
diff -u --recursive --new-file pre1/linux/drivers/md/md.c linux/drivers/md/md.c
--- pre1/linux/drivers/md/md.c	Thu Jan 10 10:15:38 2002
+++ linux/drivers/md/md.c	Tue Jan 15 13:53:51 2002
@@ -3458,8 +3458,7 @@
 		 * about not overloading the IO subsystem. (things like an
 		 * e2fsck being done on the RAID array should execute fast)
 		 */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		currspeed = (j-mddev->resync_mark_cnt)/2/((jiffies-mddev->resync_mark)/HZ +1) +1;
 
diff -u --recursive --new-file pre1/linux/drivers/media/radio/radio-sf16fmi.c linux/drivers/media/radio/radio-sf16fmi.c
--- pre1/linux/drivers/media/radio/radio-sf16fmi.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/radio/radio-sf16fmi.c	Tue Jan 15 13:53:51 2002
@@ -94,8 +94,7 @@
 	for(i=0; i< 100; i++)
 	{
 		udelay(1400);
-		if(current->need_resched)
-			schedule();
+		cond_resched();
 	}
 /* If this becomes allowed use it ... 	
 	current->state = TASK_UNINTERRUPTIBLE;
@@ -121,8 +120,7 @@
 	for(i=0; i< 100; i++)
 	{
 		udelay(1400);
-		if(current->need_resched)
-			schedule();
+		cond_resched();
 	}
 /* If this becomes allowed use it ... 	
 	current->state = TASK_UNINTERRUPTIBLE;
diff -u --recursive --new-file pre1/linux/drivers/media/video/c-qcam.c linux/drivers/media/video/c-qcam.c
--- pre1/linux/drivers/media/video/c-qcam.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/video/c-qcam.c	Tue Jan 15 13:53:51 2002
@@ -425,8 +425,7 @@
 		wantlen -= t;
 		if (t < s)
 			break;
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 	}
 
 	len = outptr;
@@ -445,8 +444,7 @@
 		int l;
 		do {
 			l = qcam_read_bytes(q, tmpbuf, 3);
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
 		if (force_rgb) {
 			if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
@@ -478,8 +476,7 @@
 		int l;
 		do {
 			l = qcam_read_bytes(q, tmpbuf, 1);
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		} while (l && tmpbuf[0] == 0x7e);
 		l = qcam_read_bytes(q, tmpbuf+1, 2);
 		if (force_rgb) {
diff -u --recursive --new-file pre1/linux/drivers/media/video/cpia.c linux/drivers/media/video/cpia.c
--- pre1/linux/drivers/media/video/cpia.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/media/video/cpia.c	Tue Jan 15 13:53:51 2002
@@ -2147,8 +2147,7 @@
 			/* loop until image ready */
 			do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
 			while (cam->params.status.streamState != STREAM_READY) {
-				if (current->need_resched)
-					schedule();
+				cond_resched();
 
 				current->state = TASK_INTERRUPTIBLE;
 
@@ -2163,8 +2162,7 @@
 		}
 
 		/* grab image from camera */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		oldjif = jiffies;
 		image_size = cam->ops->streamRead(cam->lowlevel_data,
@@ -2189,8 +2187,7 @@
 		/* decompress and convert image to by copying it from
 		 * raw_image to decompressed_frame
 		 */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
 		cam->image_size = parse_picture(cam, image_size);
 		if (cam->image_size <= 0)
diff -u --recursive --new-file pre1/linux/drivers/media/video/cpia_pp.c linux/drivers/media/video/cpia_pp.c
--- pre1/linux/drivers/media/video/cpia_pp.c	Thu Oct 25 13:53:47 2001
+++ linux/drivers/media/video/cpia_pp.c	Tue Jan 15 13:53:51 2002
@@ -392,7 +392,7 @@
 	endseen = 0;
 	block_size = PARPORT_CHUNK_SIZE;
 	while( !cam->image_complete ) {
-		if(current->need_resched)  schedule();
+		cond_resched();
 		
 		new_bytes = cpia_pp_read(cam->port, buffer, block_size );
 		if( new_bytes <= 0 ) {
diff -u --recursive --new-file pre1/linux/drivers/media/video/saa5249.c linux/drivers/media/video/saa5249.c
--- pre1/linux/drivers/media/video/saa5249.c	Sun Sep 30 12:26:06 2001
+++ linux/drivers/media/video/saa5249.c	Tue Jan 15 13:53:51 2002
@@ -127,11 +127,7 @@
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 #endif
 
-#define RESCHED \
-        do { \
-          if (current->need_resched) \
-            schedule(); \
-        } while (0)
+#define RESCHED do { cond_resched(); } while(0)
 
 static struct video_device saa_template;	/* Declared near bottom */
 
diff -u --recursive --new-file pre1/linux/drivers/mtd/chips/amd_flash.c linux/drivers/mtd/chips/amd_flash.c
--- pre1/linux/drivers/mtd/chips/amd_flash.c	Thu Oct  4 15:14:59 2001
+++ linux/drivers/mtd/chips/amd_flash.c	Tue Jan 15 13:53:51 2002
@@ -889,7 +889,7 @@
 
 	times_left = 500000;
 	while (times_left-- && flash_is_busy(map, adr, private->interleave)) { 
-		if (current->need_resched) {
+		if (need_resched()) {
 			spin_unlock_bh(chip->mutex);
 			schedule();
 			spin_lock_bh(chip->mutex);
@@ -1126,7 +1126,7 @@
 		/* Latency issues. Drop the lock, wait a while and retry */
 		spin_unlock_bh(chip->mutex);
 
-		if (current->need_resched)
+		if (need_resched())
 			schedule();
 		else
 			udelay(1);
diff -u --recursive --new-file pre1/linux/drivers/mtd/devices/doc2000.c linux/drivers/mtd/devices/doc2000.c
--- pre1/linux/drivers/mtd/devices/doc2000.c	Thu Oct  4 15:14:59 2001
+++ linux/drivers/mtd/devices/doc2000.c	Tue Jan 15 13:53:51 2002
@@ -97,7 +97,7 @@
 			DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
 			return -EIO;
 		}
-		if (current->need_resched) {
+		if (need_resched()) {
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout(1);
 		}
diff -u --recursive --new-file pre1/linux/drivers/net/acenic.h linux/drivers/net/acenic.h
--- pre1/linux/drivers/net/acenic.h	Mon Nov 19 15:19:42 2001
+++ linux/drivers/net/acenic.h	Tue Jan 15 14:34:38 2002
@@ -585,7 +585,7 @@
 
 struct ring_info {
 	struct sk_buff		*skb;
-	dma_addr_t		mapping;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
 };
 
 
@@ -596,8 +596,8 @@
  */
 struct tx_ring_info {
 	struct sk_buff		*skb;
-	dma_addr_t		mapping;
-	int			maplen;
+	DECLARE_PCI_UNMAP_ADDR(mapping)
+	DECLARE_PCI_UNMAP_LEN(maplen)
 };
 
 
diff -u --recursive --new-file pre1/linux/drivers/net/pcmcia/wavelan.h linux/drivers/net/pcmcia/wavelan.h
--- pre1/linux/drivers/net/pcmcia/wavelan.h	Fri Mar  2 11:02:15 2001
+++ linux/drivers/net/pcmcia/wavelan.h	Tue Jan 15 18:54:35 2002
@@ -88,6 +88,7 @@
  */
 const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
 
+
 /*************************** PC INTERFACE ****************************/
 
 /* WaveLAN host interface definitions */
@@ -316,6 +317,7 @@
 /* Calculate offset of a field in the above structure */
 #define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
 
+
 /*
  * Modem Management Controller (MMC) read structure.
  */
@@ -372,6 +374,7 @@
 
 /* Calculate offset of a field in the above structure */
 #define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
+
 
 /* Make the two above structures one */
 typedef union mm_t
diff -u --recursive --new-file pre1/linux/drivers/net/pcmcia/wavelan_cs.c linux/drivers/net/pcmcia/wavelan_cs.c
--- pre1/linux/drivers/net/pcmcia/wavelan_cs.c	Fri Nov  9 15:22:54 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.c	Tue Jan 15 18:54:35 2002
@@ -22,7 +22,7 @@
 #ifdef WAVELAN_ROAMING	
  * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu)
  * based on patch by Joe Finney from Lancaster University.
-#endif :-)
+#endif
  *
  * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An
  * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor.
@@ -37,12 +37,6 @@
  * Apr 2 '98  made changes to bring the i82593 control/int handling in line
  *             with offical specs...
  *
- * Changes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
- * - reorganize kmallocs in wavelan_attach, checking all for failure
- *   and releasing the previous allocations if one fails
- *
- *
  ****************************************************************************
  *   Copyright 1995
  *   Anthony D. Joseph
@@ -72,6 +66,34 @@
 
 /*------------------------------------------------------------------*/
 /*
+ * Wrapper for disabling interrupts.
+ * (note : inline, so optimised away)
+ */
+static inline void
+wv_splhi(net_local *		lp,
+	 unsigned long *	pflags)
+{
+  spin_lock_irqsave(&lp->spinlock, *pflags);
+  /* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(net_local *		lp,
+	unsigned long *		pflags)
+{
+  spin_unlock_irqrestore(&lp->spinlock, *pflags);
+
+  /* Note : enabling interrupts on the hardware is done in wv_ru_start()
+   * via : outb(OP1_INT_ENABLE, LCCR(base));
+   */
+}
+
+/*------------------------------------------------------------------*/
+/*
  * Wrapper for reporting error to cardservices
  */
 static void cs_error(client_handle_t handle, int func, int ret)
@@ -103,7 +125,7 @@
 
 /******************* MODEM MANAGEMENT SUBROUTINES *******************/
 /*
- * Usefull subroutines to manage the modem of the wavelan
+ * Useful subroutines to manage the modem of the wavelan
  */
 
 /*------------------------------------------------------------------*/
@@ -138,7 +160,7 @@
 {
   hacr_write(base, hacr);
   /* delay might only be needed sometimes */
-  mdelay(1L);
+  mdelay(1);
 } /* hacr_write_slow */
 
 /*------------------------------------------------------------------*/
@@ -529,7 +551,7 @@
   lp->curr_point=NULL;                        /* No default WavePoint */
   lp->cell_search=0;
   
-  lp->cell_timer.data=(int)lp;                /* Start cell expiry timer */
+  lp->cell_timer.data=(long)lp;               /* Start cell expiry timer */
   lp->cell_timer.function=wl_cell_expiry;
   lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
   add_timer(&lp->cell_timer);
@@ -569,18 +591,18 @@
 #endif
   
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
   
   m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
   mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
   
-  /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
   if(mode==NWID_PROMISC)
     lp->cell_search=1;
   else
-	lp->cell_search=0;
+    lp->cell_search=0;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
 }
 
 /* Find a record in the WavePoint table matching a given NWID */
@@ -737,7 +759,7 @@
   ioaddr_t              base = lp->dev->base_addr;  
   mm_t                  m;
   unsigned long         flags;
-  
+
   if(wavepoint==lp->curr_point)          /* Sanity check... */
     {
       wv_nwid_filter(!NWID_PROMISC,lp);
@@ -749,16 +771,16 @@
 #endif
  	
   /* Disable interrupts & save flags */
-  spin_lock_irqsave(&lp->lock, flags);
-  
+  wv_splhi(lp, &flags);
+
   m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
   m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
   
   mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
   
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
-  
+  wv_splx(lp, &flags);
+
   wv_nwid_filter(!NWID_PROMISC,lp);
   lp->curr_point=wavepoint;
 }
@@ -775,6 +797,11 @@
   wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
   net_local *lp=(net_local *)dev->priv;              /* Device info */
 
+#if 0
+  /* Some people don't need this, some other may need it */
+  nwid=nwid^ntohs(beacon->domain_id);
+#endif
+
 #if WAVELAN_ROAMING_DEBUG > 1
   printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
   printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
@@ -832,7 +859,9 @@
 /*------------------------------------------------------------------*/
 /*
  * Routine to synchronously send a command to the i82593 chip. 
- * Should be called with interrupts enabled.
+ * Should be called with interrupts disabled.
+ * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(),
+ *  wv_82593_config() & wv_diag())
  */
 static int
 wv_82593_cmd(device *	dev,
@@ -841,74 +870,98 @@
 	     int	result)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
   int		status;
+  int		wait_completed;
   long		spin;
-  u_long	flags;
 
   /* Spin until the chip finishes executing its current command (if any) */
+  spin = 1000;
   do
     {
-      spin_lock_irqsave (&lp->lock, flags);
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  /* If the interrupt hasn't be posted */
+  if(spin <= 0)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
 
   /* Issue the command to the controller */
   outb(cmd, LCCR(base));
 
-  /* If we don't have to check the result of the command */
+  /* If we don't have to check the result of the command
+   * Note : this mean that the irq handler will deal with that */
   if(result == SR0_NO_RESULT)
-    {
-      wv_wait_completed = FALSE;
-      return(TRUE);
-    }
+    return(TRUE);
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 1000))
-    udelay(10);
+  /* We are waiting for command completion */
+  wait_completed = TRUE;
 
-  /* If the interrupt handler hasn't be called */
-  if(wv_wait_completed)
+  /* Busy wait while the LAN controller executes the command. */
+  spin = 1000;
+  do
     {
-      outb(OP0_NOP, LCCR(base));
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
       status = inb(LCSR(base));
-      if(status & SR0_INTERRUPT)
+
+      /* Check if there was an interrupt posted */
+      if((status & SR0_INTERRUPT))
 	{
-	  /* There was an interrupt : call the interrupt handler */
-#ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_WARNING "wv_82593_cmd: interrupt handler not installed or interrupt disabled\n");
-#endif
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
 
-	  wavelan_interrupt(dev->irq, (void *) dev,
-			    (struct pt_regs *) NULL);
+	  /* Check if interrupt is a command completion */
+	  if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) &&
+	     ((status & SR0_BOTH_RX_TX) != 0x0) &&
+	     !(status & SR0_RECEPTION))
+	    {
+	      /* Signal command completion */
+	      wait_completed = FALSE;
+	    }
+	  else
+	    {
+	      /* Note : Rx interrupts will be handled later, because we can
+	       * handle multiple Rx packets at once */
+#ifdef DEBUG_INTERRUPT_INFO
+	      printk(KERN_INFO "wv_82593_cmd: not our interrupt\n");
+#endif
+	    }
 	}
-      else
-	{
-	  wv_wait_completed = 0; /* XXX */
+    }
+  while(wait_completed && (spin-- > 0));
+
+  /* If the interrupt hasn't be posted */
+  if(wait_completed)
+    {
 #ifdef DEBUG_INTERRUPT_ERROR
-	  printk(KERN_INFO "wv_82593_cmd: %s timeout, status0 0x%02x\n",
-		 str, status);
+      printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n",
+	     str, status);
 #endif
-	  /* We probably should reset the controller here */
-	  return(FALSE);
-	}
+      return(FALSE);
     }
 
-  /* Check the return code provided by the interrupt handler against
+  /* Check the return code returned by the card (see above) against
    * the expected return code provided by the caller */
-  if((lp->status & SR0_EVENT_MASK) != result)
+  if((status & SR0_EVENT_MASK) != result)
     {
 #ifdef DEBUG_INTERRUPT_ERROR
-      printk(KERN_INFO "wv_82593_cmd: %s failed, status0 = 0x%x\n",
-	     str, lp->status);
+      printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n",
+	     str, status);
 #endif
       return(FALSE);
     }
@@ -924,14 +977,16 @@
 static inline int
 wv_diag(device *	dev)
 {
+  int		ret = FALSE;
+
   if(wv_82593_cmd(dev, "wv_diag(): diagnose",
 		  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
-    return(TRUE);
+    ret = TRUE;
 
 #ifdef DEBUG_CONFIG_ERROR
   printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
 #endif
-  return(FALSE);
+  return(ret);
 } /* wv_diag */
 
 /*------------------------------------------------------------------*/
@@ -951,15 +1006,6 @@
   int		chunk_len;
   char *	buf_ptr = buf;
 
-#ifdef OLDIES
-  /* After having check skb_put (net/core/skbuff.c) in the kernel, it seem
-   * quite safe to remove this... */
-
-  /* If buf is NULL, just increment the ring buffer pointer */
-  if(buf == NULL)
-    return((ring_ptr - RX_BASE + len) % RX_SIZE + RX_BASE);
-#endif
-
   /* Get all the buffer */
   while(len > 0)
     {
@@ -990,70 +1036,32 @@
  * wavelan_interrupt is not an option...), so you may experience
  * some delay sometime...
  */
-static inline void wv_82593_reconfig (device * dev)
+static inline void
+wv_82593_reconfig(device *	dev)
 {
-	net_local *lp = (net_local *) dev->priv;
-	dev_link_t *link = ((net_local *) dev->priv)->link;
+  net_local *		lp = (net_local *)dev->priv;
+  dev_link_t *		link = ((net_local *) dev->priv)->link;
+  unsigned long		flags;
+
+  /* Arm the flag, will be cleard in wv_82593_config() */
+  lp->reconfig_82593 = TRUE;
 
-	/* Check if we can do it now ! */
-	if (!(link->open)) {
-		lp->reconfig_82593 = TRUE;
+  /* Check if we can do it now ! */
+  if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+    }
+  else
+    {
 #ifdef DEBUG_IOCTL_INFO
-		printk (KERN_DEBUG "%s: wv_82593_reconfig(): delayed (link = %d)\n",
-			dev->name, link->open);
+      printk(KERN_DEBUG
+	     "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n",
+	     dev->name, dev->state, link->open);
 #endif
-	} else {
-		netif_stop_queue (dev);
-
-		lp->reconfig_82593 = FALSE;
-		wv_82593_config (dev);
-		netif_wake_queue (dev);
-	}
-}
-
-#ifdef OLDIES
-/*------------------------------------------------------------------*/
-/*
- * Dumps the current i82593 receive buffer to the console.
- */
-static void wavelan_dump(device *dev)
-{
-  ioaddr_t base = dev->base_addr;
-  int i, c;
-
-  /* disable receiver so we can use channel 1 */
-  outb(OP0_RCV_DISABLE, LCCR(base));
-
-  /* reset receive DMA pointer */
-  hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
-  hacr_write(base, HACR_DEFAULT);
-
-  /* dump into receive buffer */
-  wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
-
-  /* set read pointer to start of receive buffer */
-  outb(0, PIORL(base));
-  outb(0, PIORH(base));
-
-  printk(KERN_DEBUG "wavelan_cs: dump:\n");
-  printk(KERN_DEBUG "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
-  for(i = 0; i < 73; i++){
-    if((i % 16) == 0) {
-      printk("\n0x%02x:", i);
-      if (!i) {
-	printk("   ");
-	continue;
-      }
     }
-    c = inb(PIOP(base));
-    printk("%02x ", c);
-  }
-  printk("\n");
-
-  /* enable the receiver again */
-  wv_ru_start(dev);
 }
-#endif
 
 /********************* DEBUG & INFO SUBROUTINES *********************/
 /*
@@ -1171,6 +1179,8 @@
       return;
     }
 
+  wv_splhi(lp, &flags);
+
   /* Read the mmc */
   mmc_out(base, mmwoff(0, mmw_freeze), 1);
   mmc_read(base, 0, (u_char *)&m, sizeof(m));
@@ -1181,6 +1191,8 @@
   lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
 #endif	/* WIRELESS_EXT */
 
+  wv_splx(lp, &flags);
+
   printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
 #ifdef DEBUG_SHOW_UNUSED
   printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -1265,6 +1277,7 @@
 wv_dev_show(device *	dev)
 {
   printk(KERN_DEBUG "dev:");
+  printk(" state=%lX,", dev->state);
   printk(" trans_start=%ld,", dev->trans_start);
   printk(" flags=0x%x,", dev->flags);
   printk("\n");
@@ -1404,7 +1417,7 @@
 	  printk("2430.5");
 	  break;
 	default:
-	  printk("unknown");
+	  printk("???");
 	}
     }
 
@@ -1719,7 +1732,7 @@
 	 memcmp(dac, dac_verify, 2 * 2))
 	{
 #ifdef DEBUG_IOCTL_ERROR
-	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (?)\n");
+	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
 #endif
 	  return -EOPNOTSUPP;
 	}
@@ -1892,7 +1905,7 @@
 #endif
 
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Look what is the request */
   switch(cmd)
@@ -1968,7 +1981,7 @@
 
     case SIOCGIWFREQ:
       /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-       * (does it work for everybody XXX - especially old cards...) */
+       * (does it work for everybody ??? - especially old cards...) */
       if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
 	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
 	{
@@ -2239,15 +2252,17 @@
 	{
 	  struct iw_range	range;
 
-	  /* Set the length (very important for backward compatibility) */
-	  wrq->u.data.length = sizeof(struct iw_range);
+	   /* Set the length (very important for backward compatibility) */
+	   wrq->u.data.length = sizeof(struct iw_range);
 
-	  /* Set all the info we don't care or don't know about to zero */
-	  memset(&range, 0, sizeof(range));
+	   /* Set all the info we don't care or don't know about to zero */
+	   memset(&range, 0, sizeof(range));
 
-	  /* Set the Wireless Extension versions */
-	  range.we_version_compiled = WIRELESS_EXT;
-	  range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#if WIRELESS_EXT > 10
+	   /* Set the Wireless Extension versions */
+	   range.we_version_compiled = WIRELESS_EXT;
+	   range.we_version_source = 9;	/* Nothing for us in v10 and v11 */
+#endif /* WIRELESS_EXT > 10 */
 
 	  /* Set information in the range struct */
 	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
@@ -2517,7 +2532,7 @@
     }
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
@@ -2543,11 +2558,8 @@
   printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
 #endif
 
-  if (lp == NULL) /* XXX will this ever occur? */
-    return NULL;
-
   /* Disable interrupts & save flags */
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   wstats = &lp->wstats;
 
@@ -2573,7 +2585,7 @@
   wstats->discard.misc = 0L;
 
   /* ReEnable interrupts & restore flags */
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
@@ -2692,12 +2704,6 @@
   skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef DEBUG_RX_INFO
-  /* Another glitch : Due to the way the GET_PACKET macro is written,
-   * we are not sure to have the same thing in skb->data. On the other
-   * hand, skb->mac.raw is not defined everywhere...
-   * For versions between 1.2.13 and those where skb->mac.raw appear,
-   * I don't have a clue...
-   */
   wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
 #endif	/* DEBUG_RX_INFO */
      
@@ -2731,9 +2737,7 @@
 	  wl_roam_gather(dev, skb->data, stats);
 #endif	/* WAVELAN_ROAMING */
 	  
-      /* Spying stuff */
 #ifdef WIRELESS_SPY
-      /* Same as above */
       wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
 #endif	/* WIRELESS_SPY */
 #ifdef HISTOGRAM
@@ -2766,6 +2770,7 @@
  * called to do the actual transfer of the card's data including the
  * ethernet header into a packet consisting of an sk_buff chain.
  * (called by wavelan_interrupt())
+ * Note : the spinlock is already grabbed for us and irq are disabled.
  */
 static inline void
 wv_packet_rcv(device *	dev)
@@ -2916,7 +2921,7 @@
   printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
 #endif
 
-  spin_lock_irqsave (&lp->lock, flags);
+  wv_splhi(lp, &flags);
 
   /* Check if we need some padding */
   if(clen < ETH_ZLEN)
@@ -2946,15 +2951,7 @@
   /* Keep stats up to date */
   lp->stats.tx_bytes += length;
 
-  /* If watchdog not already active, activate it... */
-  if (!timer_pending(&lp->watchdog))
-    {
-      /* set timer to expire in WATCHDOG_JIFFIES */
-      lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES;
-      add_timer(&lp->watchdog);
-    }
-
-  spin_unlock_irqrestore (&lp->lock, flags);
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_TX_INFO
   wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
@@ -2963,56 +2960,57 @@
 #ifdef DEBUG_TX_TRACE
   printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
 #endif
-
-  netif_start_queue (dev);
 }
 
 /*------------------------------------------------------------------*/
 /*
  * This routine is called when we want to send a packet (NET3 callback)
- * In this routine, we check if the hardware is ready to accept
+ * In this routine, we check if the harware is ready to accept
  * the packet. We also prevent reentrance. Then, we call the function
  * to send the packet...
  */
-static int wavelan_packet_xmit (struct sk_buff *skb,
-				device * dev)
+static int
+wavelan_packet_xmit(struct sk_buff *	skb,
+		    device *		dev)
 {
-	net_local *lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *)dev->priv;
+  unsigned long		flags;
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
-		(unsigned) skb);
+  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	 (unsigned) skb);
 #endif
 
-	/*
-	 * For ethernet, fill in the header.
-	 */
+  /*
+   * Block a timer-based transmit from overlapping a previous transmit.
+   * In other words, prevent reentering this routine.
+   */
+  netif_stop_queue(dev);
 
-	netif_stop_queue (dev);
+  /* If somebody has asked to reconfigure the controller,
+   * we can do it now */
+  if(lp->reconfig_82593)
+    {
+      wv_splhi(lp, &flags);	/* Disable interrupts */
+      wv_82593_config(dev);
+      wv_splx(lp, &flags);	/* Re-enable interrupts */
+      /* Note : the configure procedure was totally synchronous,
+       * so the Tx buffer is now free */
+    }
 
-	/*
-	 * Block a timer-based transmit from overlapping a previous transmit.
-	 * In other words, prevent reentering this routine.
-	 */
-	if (1) {
-		/* If somebody has asked to reconfigure the controller, we can do it now */
-		if (lp->reconfig_82593) {
-			lp->reconfig_82593 = FALSE;
-			wv_82593_config (dev);
-		}
 #ifdef DEBUG_TX_ERROR
-		if (skb->next)
-			printk (KERN_INFO "skb has next\n");
+	if (skb->next)
+		printk(KERN_INFO "skb has next\n");
 #endif
 
-		wv_packet_write (dev, skb->data, skb->len);
-	}
-	dev_kfree_skb (skb);
+  wv_packet_write(dev, skb->data, skb->len);
+
+  dev_kfree_skb(skb);
 
 #ifdef DEBUG_TX_TRACE
-	printk (KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
 #endif
-	return (0);
+  return(0);
 }
 
 /********************** HARDWARE CONFIGURATION **********************/
@@ -3165,7 +3163,7 @@
    */
 
   /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
-   * (does it work for everybody XXX - especially old cards...) */
+   * (does it work for everybody ??? - especially old cards...) */
   /* Note : WFREQSEL verify that it is able to read from EEprom
    * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
    * is 0xA (Xilinx version) or 0xB (Ariadne version).
@@ -3223,7 +3221,7 @@
 wv_ru_stop(device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *lp = (net_local *) dev->priv;
+  net_local *	lp = (net_local *) dev->priv;
   unsigned long	flags;
   int		status;
   int		spin;
@@ -3232,35 +3230,35 @@
   printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
 #endif
 
+  wv_splhi(lp, &flags);
+
   /* First, send the LAN controller a stop receive command */
   wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
 	       OP0_STOP_RCV, SR0_NO_RESULT);
 
   /* Then, spin until the receive unit goes idle */
-  spin = 0;
+  spin = 300;
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin++ < 300));
+  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0));
 
   /* Now, spin until the chip finishes executing its current command */
   do
     {
       udelay(10);
-      spin_lock_irqsave (&lp->lock, flags);
       outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
       status = inb(LCSR(base));
-      spin_unlock_irqrestore (&lp->lock, flags);
     }
-  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin++ < 300));
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+  wv_splx(lp, &flags);
 
   /* If there was a problem */
-  if(spin > 300)
+  if(spin <= 0)
     {
 #ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
@@ -3287,6 +3285,7 @@
 {
   ioaddr_t	base = dev->base_addr;
   net_local *	lp = (net_local *) dev->priv;
+  unsigned long	flags;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
@@ -3300,6 +3299,8 @@
   if(!wv_ru_stop(dev))
     return FALSE;
 
+  wv_splhi(lp, &flags);
+
   /* Now we know that no command is being executed. */
 
   /* Set the receive frame pointer and stop pointer */
@@ -3309,8 +3310,17 @@
   /* Reset ring management.  This sets the receive frame pointer to 1 */
   outb(OP1_RESET_RING_MNGMT, LCCR(base));
 
+#if 0
+  /* XXX the i82593 manual page 6-4 seems to indicate that the stop register
+     should be set as below */
+  /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/
+#elif 0
+  /* but I set it 0 instead */
+  lp->stop = 0;
+#else
   /* but I set it to 3 bytes per packet less than 8K */
   lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+#endif
   outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
   outb(OP1_INT_ENABLE, LCCR(base));
   outb(OP1_SWIT_TO_PORT_0, LCCR(base));
@@ -3326,17 +3336,15 @@
 #ifdef DEBUG_I82593_SHOW
   {
     int	status;
-    unsigned long flags;
-    int	i = 0;
+    int	opri;
+    int	spin = 10000;
 
     /* spin until the chip starts receiving */
     do
       {
-	spin_lock_irqsave (&lp->lock, flags);
 	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
 	status = inb(LCSR(base));
-	spin_unlock_irqrestore (&lp->lock, flags);
-	if(i++ > 10000)
+	if(spin-- <= 0)
 	  break;
       }
     while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
@@ -3345,6 +3353,9 @@
 	   (status & SR3_RCV_STATE_MASK), i);
   }
 #endif
+
+  wv_splx(lp, &flags);
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
 #endif
@@ -3363,6 +3374,7 @@
   ioaddr_t			base = dev->base_addr;
   net_local *			lp = (net_local *) dev->priv;
   struct i82593_conf_block	cfblk;
+  int				ret = TRUE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
@@ -3457,7 +3469,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
 		   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
-    return(FALSE);
+    ret = FALSE;
 
   /* Initialize adapter's ethernet MAC address */
   outb(TX_BASE & 0xff, PIORL(base));
@@ -3471,7 +3483,7 @@
   hacr_write(base, HACR_DEFAULT);
   if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
 		   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
-    return(FALSE);
+    ret = FALSE;
 
 #ifdef WAVELAN_ROAMING
     /* If roaming is enabled, join the "Beacon Request" multicast group... */
@@ -3508,14 +3520,17 @@
       hacr_write(base, HACR_DEFAULT);
       if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
 		       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
-	return(FALSE);
+	ret = FALSE;
       lp->mc_count = dev->mc_count;	/* remember to avoid repeated reset */
     }
 
+  /* Job done, clear the flag */
+  lp->reconfig_82593 = FALSE;
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
 #endif
-  return(TRUE);
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3594,6 +3609,8 @@
 {
   net_local *		lp = (net_local *) dev->priv;
   ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			ret = FALSE;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
@@ -3612,50 +3629,78 @@
   if(wv_pcmcia_reset(dev) == FALSE)
     return FALSE;
 
-  /* Power UP the module + reset the modem + reset host adapter
-   * (in fact, reset DMA channels) */
-  hacr_write_slow(base, HACR_RESET);
-  hacr_write(base, HACR_DEFAULT);
+  /* Disable interrupts */
+  wv_splhi(lp, &flags);
 
-  /* Check if the module has been powered up... */
-  if(hasr_read(base) & HASR_NO_CLK)
+  /* Disguised goto ;-) */
+  do
     {
+      /* Power UP the module + reset the modem + reset host adapter
+       * (in fact, reset DMA channels) */
+      hacr_write_slow(base, HACR_RESET);
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
-	     dev->name);
+	  printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* initialize the modem */
-  if(wv_mmc_init(dev) == FALSE)
-    return FALSE;
+      /* initialize the modem */
+      if(wv_mmc_init(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wv_hw_config(): Can't configure the modem\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* reset the LAN controller (i82593) */
-  outb(OP0_RESET, LCCR(base));
-  mdelay(1);	/* A bit crude ! */
-
-  /* Initialize the LAN controller */
-  if((wv_82593_config(dev) == FALSE) ||
-     (wv_diag(dev) == FALSE))
-    {
+      /* reset the LAN controller (i82593) */
+      outb(OP0_RESET, LCCR(base));
+      mdelay(1);	/* A bit crude ! */
+
+      /* Initialize the LAN controller */
+      if(wv_82593_config(dev) == FALSE)
+	{
 #ifdef DEBUG_CONFIG_ERRORS
-      printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n",
+		 dev->name);
 #endif
-      return FALSE;
-    }
+	  break;
+	}
 
-  /* 
-   * insert code for loopback test here
-   */
+      /* Diagnostic */
+      if(wv_diag(dev) == FALSE)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "%s: wv_hw_config(): i82593 diagnostic failed\n",
+		 dev->name);
+#endif
+	  break;
+	}
 
-  /* The device is now configured */
-  lp->configured = 1;
+      /* 
+       * insert code for loopback test here
+       */
+
+      /* The device is now configured */
+      lp->configured = 1;
+      ret = TRUE;
+    }
+  while(0);
+
+  /* Re-enable interrupts */
+  wv_splx(lp, &flags);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
 #endif
-  return TRUE;
+  return(ret);
 }
 
 /*------------------------------------------------------------------*/
@@ -3675,10 +3720,6 @@
   printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
 #endif
 
-  /* If watchdog was activated, kill it ! */
-  if (timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   lp->nresets++;
   lp->configured = 0;
   
@@ -3786,13 +3827,13 @@
 	}
 
       /*
-       * Allocate a 4K memory window.  Note that the dev_link_t
+       * Allocate a small memory window.  Note that the dev_link_t
        * structure provides space for one window handle -- if your
        * device needs several windows, you'll need to keep track of
        * the handles in your private data structure, link->priv.
        */
       req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-      req.Base = 0; req.Size = 0x1000;
+      req.Base = req.Size = 0;
       req.AccessSpeed = mem_speed;
       link->win = (window_handle_t)link->handle;
       i = CardServices(RequestWindow, &link->win, &req);
@@ -3803,7 +3844,7 @@
 	}
 
       dev->rmem_start = dev->mem_start =
-	  (u_long)ioremap(req.Base, 0x1000);
+	  (u_long)ioremap(req.Base, req.Size);
       dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
 
       mem.CardOffset = 0; mem.Page = 0;
@@ -3817,7 +3858,7 @@
       /* Feed device with this info... */
       dev->irq = link->irq.AssignedIRQ;
       dev->base_addr = link->io.BasePort1;
-      netif_start_queue (dev);
+      netif_start_queue(dev);
 
 #ifdef DEBUG_CONFIG_INFO
       printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
@@ -3843,7 +3884,7 @@
       return FALSE;
     }
 
-  /* XXX Could you explain me this, Dave ? */
+  strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
   link->dev = &((net_local *) dev->priv)->node;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3887,7 +3928,7 @@
   CardServices(ReleaseIO, link->handle, &link->io);
   CardServices(ReleaseIRQ, link->handle, &link->irq);
 
-  link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING | DEV_STALE_CONFIG);
+  link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
@@ -3896,7 +3937,7 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Sometimes, netwave_detach can't be performed following a call from
+ * Sometimes, wavelan_detach can't be performed following a call from
  * cardmgr (device still open, pcmcia_release not done) and the device
  * is put in a STALE_LINK state and remains in memory.
  *
@@ -3970,7 +4011,19 @@
   lp = (net_local *) dev->priv;
   base = dev->base_addr;
 
-  spin_lock (&lp->lock);
+#ifdef DEBUG_INTERRUPT_INFO
+  /* Check state of our spinlock (it should be cleared) */
+  if(spin_is_locked(&lp->spinlock))
+    printk(KERN_DEBUG
+	   "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+	   dev->name);
+#endif
+
+  /* Prevent reentrancy. We need to do that because we may have
+   * multiple interrupt handler running concurently.
+   * It is safe because wv_splhi() disable interrupts before aquiring
+   * the spinlock. */
+  spin_lock(&lp->spinlock);
 
   /* Treat all pending interrupts */
   while(1)
@@ -4015,8 +4068,6 @@
 	  break;
 	}
 
-      lp->status = status0;	/* Save current status (for commands) */
-
       /* ----------------- RECEIVING PACKET ----------------- */
       /*
        * When the wavelan signal the reception of a new packet,
@@ -4054,22 +4105,6 @@
        * Most likely : transmission done
        */
 
-      /* If we are already waiting elsewhere for the command to complete */
-      if(wv_wait_completed)
-	{
-#ifdef DEBUG_INTERRUPT_INFO
-	  printk(KERN_DEBUG "%s: wv_interrupt(): command completed\n",
-		 dev->name);
-#endif
-
-	  /* Signal command completion */
-	  wv_wait_completed = 0;
-
-	  /* Acknowledge the interrupt */
-	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
-	  continue;
-    	}
-
       /* If a transmission has been done */
       if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
 	 (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
@@ -4081,10 +4116,6 @@
 		   dev->name);
 #endif
 
-	  /* If watchdog was activated, kill it ! */
-	  if(timer_pending(&lp->watchdog))
-	    del_timer(&lp->watchdog);
-
 	  /* Get transmission status */
 	  tx_status = inb(LCSR(base));
 	  tx_status |= (inb(LCSR(base)) << 8);
@@ -4174,7 +4205,7 @@
 	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
 	  lp->stats.tx_packets++;
 
-	  netif_wake_queue (dev);
+	  netif_wake_queue(dev);
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	} 
       else	/* if interrupt = transmit done or retransmit done */
@@ -4185,9 +4216,9 @@
 #endif
 	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
     	}
-    }
+    }	/* while(1) */
 
-  spin_unlock_irq (&lp->lock);
+  spin_unlock(&lp->spinlock);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
@@ -4196,30 +4227,23 @@
 
 /*------------------------------------------------------------------*/
 /*
- * Watchdog : when we start a transmission, we set a timer in the
- * kernel.  If the transmission complete, this timer is disabled. If
- * it expire, it try to unlock the hardware.
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
  *
- * Note : this watchdog doesn't work on the same principle as the
- * watchdog in the ISA driver. I make it this way because the overhead
- * of add_timer() and del_timer() is nothing and that it avoid calling
- * the watchdog, saving some CPU... If you want to apply the same
- * watchdog to the ISA driver, you should be a bit carefull, because
- * of the many transmit buffers...
- * This watchdog is also move clever, it try to abort the current
- * command before reseting everything...
+ * Note : This watchdog is move clever than the one in the ISA driver,
+ * because it try to abort the current command before reseting
+ * everything...
+ * On the other hand, it's a bit simpler, because we don't have to
+ * deal with the multiple Tx buffers...
  */
 static void
-wavelan_watchdog(u_long		a)
+wavelan_watchdog(device *	dev)
 {
-  device *		dev;
-  net_local *		lp;
-  ioaddr_t		base;
-  int			spin;
-
-  dev = (device *) a;
-  base = dev->base_addr;
-  lp = (net_local *) dev->priv;
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			aborted = FALSE;
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
@@ -4230,21 +4254,21 @@
 	 dev->name);
 #endif
 
-  /* We are waiting for command completion */
-  wv_wait_completed = TRUE;
+  wv_splhi(lp, &flags);
 
   /* Ask to abort the current command */
   outb(OP0_ABORT, LCCR(base));
 
-  /* Busy wait while the LAN controller executes the command.
-   * Note : wv_wait_completed should be volatile */
-  spin = 0;
-  while(wv_wait_completed && (spin++ < 250))
-    udelay(10);
-
-  /* If the interrupt handler hasn't be called or invalid status */
-  if((wv_wait_completed) ||
-     ((lp->status & SR0_EVENT_MASK) != SR0_EXECUTION_ABORTED))
+  /* Wait for the end of the command (a bit hackish) */
+  if(wv_82593_cmd(dev, "wavelan_watchdog(): abort",
+		  OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED))
+    aborted = TRUE;
+
+  /* Release spinlock here so that wv_hw_reset() can grab it */
+  wv_splx(lp, &flags);
+
+  /* Check if we were successful in aborting it */
+  if(!aborted)
     {
       /* It seem that it wasn't enough */
 #ifdef DEBUG_INTERRUPT_ERROR
@@ -4269,7 +4293,7 @@
 #endif
 
   /* We are no more waiting for something... */
-  netif_start_queue (dev);
+  netif_wake_queue(dev);
 
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
@@ -4322,7 +4346,7 @@
     return FALSE;
   if(!wv_ru_start(dev))
     wv_hw_reset(dev);		/* If problem : reset */
-  netif_start_queue (dev);
+  netif_start_queue(dev);
 
   /* Mark the device as used */
   link->open++;
@@ -4348,7 +4372,6 @@
 wavelan_close(device *	dev)
 {
   dev_link_t *	link = ((net_local *) dev->priv)->link;
-  net_local *	lp = (net_local *)dev->priv;
   ioaddr_t	base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4356,8 +4379,6 @@
 	 (unsigned int) dev);
 #endif
 
-  netif_stop_queue (dev);
-
   /* If the device isn't open, then nothing to do */
   if(!link->open)
     {
@@ -4373,17 +4394,13 @@
     wv_roam_cleanup(dev);
 #endif	/* WAVELAN_ROAMING */
 
-  /* If watchdog was activated, kill it ! */
-  if(timer_pending(&lp->watchdog))
-    del_timer(&lp->watchdog);
-
   link->open--;
   MOD_DEC_USE_COUNT;
 
   /* If the card is still present */
-  if (netif_device_present(dev))
+  if(netif_running(dev))
     {
-      netif_stop_queue (dev);
+      netif_stop_queue(dev);
 
       /* Stop receiving new messages and wait end of transmission */
       wv_ru_stop(dev);
@@ -4404,21 +4421,6 @@
 
 /*------------------------------------------------------------------*/
 /*
- * We never need to do anything when a wavelan device is "initialized"
- * by the net software, because we only register already-found cards.
- */
-static int
-wavelan_init(device *	dev)
-{
-#ifdef DEBUG_CALLBACK_TRACE
-  printk(KERN_DEBUG "<>wavelan_init()\n");
-#endif
-
-  return(0);
-}
-
-/*------------------------------------------------------------------*/
-/*
  * wavelan_attach() creates an "instance" of the driver, allocating
  * local data structures for one device (one interface).  The device
  * is registered with Card Services.
@@ -4445,24 +4447,8 @@
 
   /* Initialize the dev_link_t structure */
   link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
-  if (!link)
-	  return NULL;
-  
-  /* Allocate the generic data structure */
-  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
-  if (!dev)
-	  goto fail_alloc_dev;
-  
-  /* Allocate the wavelan-specific data structure. */
-  lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
-  if (!lp)
-	  goto fail_alloc_dev_priv;
-  
-  memset(lp, 0, sizeof(net_local));
+  if (!link) return NULL;
   memset(link, 0, sizeof(struct dev_link_t));
-  memset(dev, 0, sizeof(struct net_device));
-
-  dev->priv = lp;
 
   /* Unused for the Wavelan */
   link->release.function = &wv_pcmcia_release;
@@ -4492,18 +4478,35 @@
   link->next = dev_list;
   dev_list = link;
 
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  if (!dev) {
+      kfree(link);
+      return NULL;
+  }
+  memset(dev, 0x00, sizeof(struct net_device));
   link->priv = link->irq.Instance = dev;
 
+  /* Allocate the wavelan-specific data structure. */
+  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  if (!lp) {
+      kfree(link);
+      kfree(dev);
+      return NULL;
+  }
+  memset(lp, 0x00, sizeof(net_local));
+
   /* Init specific data */
-  wv_wait_completed = 0;
-  lp->status = FALSE;
   lp->configured = 0;
   lp->reconfig_82593 = FALSE;
   lp->nresets = 0;
+  /* Multicast stuff */
+  lp->promiscuous = 0;
+  lp->allmulticast = 0;
+  lp->mc_count = 0;
 
-  /* Set the watchdog timer */
-  lp->watchdog.function = wavelan_watchdog;
-  lp->watchdog.data = (unsigned long) dev;
+  /* Init spinlock */
+  spin_lock_init(&lp->spinlock);
 
   /* back links */
   lp->link = link;
@@ -4513,7 +4516,6 @@
   ether_setup(dev);
 
   /* wavelan NET3 callbacks */
-  dev->init = &wavelan_init;
   dev->open = &wavelan_open;
   dev->stop = &wavelan_close;
   dev->hard_start_xmit = &wavelan_packet_xmit;
@@ -4523,14 +4525,16 @@
   dev->set_mac_address = &wavelan_set_mac_address;
 #endif	/* SET_MAC_ADDRESS */
 
+  /* Set the watchdog timer */
+  dev->tx_timeout	= &wavelan_watchdog;
+  dev->watchdog_timeo	= WATCHDOG_JIFFIES;
+
 #ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
   dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
 
   /* Other specific data */
-  strcpy(dev->name, ((net_local *)dev->priv)->node.dev_name);
-  netif_start_queue (dev);
   dev->mtu = WAVELAN_MTU;
 
   /* Register with Card Services */
@@ -4562,12 +4566,6 @@
 #endif
 
   return link;
-
-fail_alloc_dev_priv:
-  kfree(dev);
-fail_alloc_dev:
-  kfree(link);
-  return NULL;
 }
 
 /*------------------------------------------------------------------*/
@@ -4698,7 +4696,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
 	    /* Accept no more transmissions */
-      	    netif_device_detach(dev);
+	    netif_device_detach(dev);
 
 	    /* Release the card */
 	    wv_pcmcia_release((u_long) link);
@@ -4720,7 +4718,7 @@
 	 * obliged to close nicely the wavelan here. David, could you
 	 * close the device before suspending them ? And, by the way,
 	 * could you, on resume, add a "route add -net ..." after the
-	 * ifconfig up XXX Thanks... */
+	 * ifconfig up ??? Thanks... */
 
 	/* Stop receiving new messages and wait end of transmission */
 	wv_ru_stop(dev);
@@ -4735,8 +4733,7 @@
     	if(link->state & DEV_CONFIG)
 	  {
       	    if(link->open)
-	      	netif_device_detach(dev);
-
+	      netif_device_detach(dev);
       	    CardServices(ReleaseConfiguration, link->handle);
 	  }
 	break;
@@ -4748,7 +4745,7 @@
 	if(link->state & DEV_CONFIG)
 	  {
       	    CardServices(RequestConfiguration, link->handle, &link->conf);
-      	    if(link->open)	/* If RESET -> True, If RESUME -> False XXX */
+      	    if(link->open)	/* If RESET -> True, If RESUME -> False ??? */
 	      {
 		wv_hw_reset(dev);
 		netif_device_attach(dev);
@@ -4838,4 +4835,3 @@
 
 module_init(init_wavelan_cs);
 module_exit(exit_wavelan_cs);
-MODULE_LICENSE("Dual BSD/GPL");
diff -u --recursive --new-file pre1/linux/drivers/net/pcmcia/wavelan_cs.h linux/drivers/net/pcmcia/wavelan_cs.h
--- pre1/linux/drivers/net/pcmcia/wavelan_cs.h	Fri Oct 12 14:21:18 2001
+++ linux/drivers/net/pcmcia/wavelan_cs.h	Tue Jan 15 18:54:35 2002
@@ -34,6 +34,25 @@
  *	I try to maintain a web page with the Wireless LAN Howto at :
  *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
  *
+ * SMP
+ * ---
+ *	We now are SMP compliant (I eventually fixed the remaining bugs).
+ *	The driver has been tested on a dual P6-150 and survived my usual
+ *	set of torture tests.
+ *	Anyway, I spent enough time chasing interrupt re-entrancy during
+ *	errors or reconfigure, and I designed the locked/unlocked sections
+ *	of the driver with great care, and with the recent addition of
+ *	the spinlock (thanks to the new API), we should be quite close to
+ *	the truth.
+ *	The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ *	but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ *	I have also looked into disabling only our interrupt on the card
+ *	(via HACR) instead of all interrupts in the processor (via cli),
+ *	so that other driver are not impacted, and it look like it's
+ *	possible, but it's very tricky to do right (full of races). As
+ *	the gain would be mostly for SMP systems, it can wait...
+ *
  * Debugging and options
  * ---------------------
  *	You will find below a set of '#define" allowing a very fine control
@@ -122,7 +141,7 @@
  * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
  * correctly 2.00 cards (2.4 GHz with frequency selection).
- * David Hinds <dhinds@pcmcia.sourceforge.org> integrated the whole in his
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
  * Pcmcia package (+ bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
@@ -158,8 +177,8 @@
  *
  *    This software was originally developed under Linux 1.2.3
  *	(Slackware 2.0 distribution).
- *    And then under Linux 2.0.x (Debian 1.1 - pcmcia 2.8.18-23) with
- *	HP OmniBook 4000 & 5500.
+ *    And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+)
+ *	with an HP OmniBook 4000 and then a 5500.
  *
  *    It is based on other device drivers and information either written
  *    or supplied by:
@@ -174,7 +193,7 @@
  *	Matthew Geier (matthew@cs.su.oz.au),
  *	Remo di Giovanni (remo@cs.su.oz.au),
  *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
- *	David Hinds <dhinds@pcmcia.sourceforge.org>,
+ *	David Hinds <dahinds@users.sourceforge.net>,
  *	Jan Hoogendoorn (c/o marteijn@lucent.com),
  *      Bruce Janson <bruce@cs.usyd.edu.au>,
  *	Anthony D. Joseph <adj@lcs.mit.edu>,
@@ -349,6 +368,32 @@
  *	- Fix check for root permission (break instead of exit)
  *	- New nwid & encoding setting (Wireless Extension 9)
  *
+ * Changes made for release in 3.1.12 :
+ * ----------------------------------
+ *	- reworked wv_82593_cmd to avoid using the IRQ handler and doing
+ *	  ugly things with interrupts.
+ *	- Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog
+ *	- Update to new network API (softnet - 2.3.43) :
+ *		o replace dev->tbusy (David + me)
+ *		o replace dev->tstart (David + me)
+ *		o remove dev->interrupt (David)
+ *		o add SMP locking via spinlock in splxx (me)
+ *		o add spinlock in interrupt handler (me)
+ *		o use kernel watchdog instead of ours (me)
+ *		o verify that all the changes make sense and work (me)
+ *	- Re-sync kernel/pcmcia versions (not much actually)
+ *	- A few other cleanups (David & me)...
+ *
+ * Changes made for release in 3.1.22 :
+ * ----------------------------------
+ *	- Check that SMP works, remove annoying log message
+ *
+ * Changes made for release in 3.1.24 :
+ * ----------------------------------
+ *	- Fix unfrequent card lockup when watchdog was reseting the hardware :
+ *		o control first busy loop in wv_82593_cmd()
+ *		o Extend spinlock protection in wv_hw_config()
+ *
  * Wishes & dreams:
  * ----------------
  *	- Cleanup and integrate the roaming code
@@ -368,6 +413,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
+#include <linux/spinlock.h>
 #include <linux/in.h>
 #include <linux/delay.h>
 #include <asm/uaccess.h>
@@ -384,7 +430,7 @@
 
 #ifdef CONFIG_NET_PCMCIA_RADIO
 #include <linux/wireless.h>		/* Wireless extensions */
-#endif	/* CONFIG_NET_PCMCIA_RADIO */
+#endif
 
 /* Pcmcia headers that we need */
 #include <pcmcia/cs_types.h>
@@ -437,7 +483,7 @@
 #undef DEBUG_RX_INFO		/* Header of the transmitted packet */
 #undef DEBUG_RX_FAIL		/* Normal failure conditions */
 #define DEBUG_RX_ERROR		/* Unexpected conditions */
-#undef DEBUG_PACKET_DUMP	/* Dump packet on the screen */
+#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen */
 #undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
 #undef DEBUG_IOCTL_INFO		/* Various debug info */
 #define DEBUG_IOCTL_ERROR	/* What's going wrong */
@@ -452,7 +498,7 @@
 /************************ CONSTANTS & MACROS ************************/
 
 #ifdef DEBUG_VERSION_SHOW
-static const char *version = "wavelan_cs.c : v21 (wireless extensions) 18/10/99\n";
+static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n";
 #endif
 
 /* Watchdog temporisation */
@@ -557,9 +603,9 @@
  */
 struct net_local
 {
-  spinlock_t	lock;
   dev_node_t 	node;		/* ???? What is this stuff ???? */
   device *	dev;		/* Reverse link... */
+  spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
   dev_link_t *	link;		/* pcmcia structure */
   en_stats	stats;		/* Ethernet interface statistics */
   int		nresets;	/* Number of hw resets */
@@ -568,9 +614,7 @@
   u_char	promiscuous;	/* Promiscuous mode */
   u_char	allmulticast;	/* All Multicast mode */
   int		mc_count;	/* Number of multicast addresses */
-  timer_list	watchdog;	/* To avoid blocking state */
 
-  u_char        status;		/* Current i82593 status */
   int   	stop;		/* Current i82593 Stop Hit Register */
   int   	rfp;		/* Last DMA machine receive pointer */
   int		overrunning;	/* Receiver overrun flag */
@@ -617,8 +661,14 @@
 #endif	/* WAVELAN_ROAMING */
 
 /* ----------------------- MISC SUBROUTINES ------------------------ */
+static inline void
+	wv_splhi(net_local *,		/* Disable interrupts */
+		 unsigned long *);	/* flags */
+static inline void
+	wv_splx(net_local *,		/* ReEnable interrupts */
+		unsigned long *);	/* flags */
 static void
-	cs_error(client_handle_t, /* Report error to cardmgr */
+	cs_error(client_handle_t,	/* Report error to cardmgr */
 		 int,
 		 int);
 /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
@@ -722,16 +772,15 @@
 	wv_flush_stale_links(void);	/* "detach" all possible devices */
 /* ---------------------- INTERRUPT HANDLING ---------------------- */
 static void
-wavelan_interrupt(int,	/* Interrupt handler */
-		  void *,
-		  struct pt_regs *);
+	wavelan_interrupt(int,	/* Interrupt handler */
+			  void *,
+			  struct pt_regs *);
 static void
-	wavelan_watchdog(u_long);	/* Transmission watchdog */
+	wavelan_watchdog(device *);	/* Transmission watchdog */
 /* ------------------- CONFIGURATION CALLBACKS ------------------- */
 static int
 	wavelan_open(device *),		/* Open the device */
-	wavelan_close(device *),	/* Close the device */
-	wavelan_init(device *);		/* Do nothing */
+	wavelan_close(device *);	/* Close the device */
 static dev_link_t *
 	wavelan_attach(void);		/* Create a new device */
 static void
@@ -744,11 +793,7 @@
 /**************************** VARIABLES ****************************/
 
 static dev_info_t dev_info = "wavelan_cs";
-static dev_link_t *dev_list;		/* Linked list of devices */
-
-/* WARNING : the following variable MUST be volatile
- * It is used by wv_82593_cmd to syncronise with wavelan_interrupt */ 
-static volatile int	wv_wait_completed;
+static dev_link_t *dev_list = NULL;	/* Linked list of devices */
 
 /*
  * Parameters that can be set with 'insmod'
@@ -761,7 +806,7 @@
 static int 	irq_list[4] = { -1 };
 
 /* Shared memory speed, in ns */
-static int	mem_speed;
+static int	mem_speed = 0;
 
 /* New module interface */
 MODULE_PARM(irq_mask, "i");
@@ -770,9 +815,11 @@
 
 #ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
 /* Enable roaming mode ? No ! Please keep this to 0 */
-static int	do_roaming;
+static int	do_roaming = 0;
 MODULE_PARM(do_roaming, "i");
 #endif	/* WAVELAN_ROAMING */
+
+MODULE_LICENSE("GPL");
 
 #endif	/* WAVELAN_CS_H */
 
diff -u --recursive --new-file pre1/linux/drivers/nubus/nubus.c linux/drivers/nubus/nubus.c
--- pre1/linux/drivers/nubus/nubus.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/nubus/nubus.c	Thu Jan 17 14:21:16 2002
@@ -1039,3 +1039,5 @@
 	nubus_proc_init();
 #endif
 }
+
+subsys_initcall(nubus_init);
diff -u --recursive --new-file pre1/linux/drivers/parport/ChangeLog linux/drivers/parport/ChangeLog
--- pre1/linux/drivers/parport/ChangeLog	Wed Jan 16 11:16:28 2002
+++ linux/drivers/parport/ChangeLog	Thu Jan 17 14:07:57 2002
@@ -1,3 +1,23 @@
+2001-12-07  Tim Waugh  <twaugh@redhat.com>
+
+	* ieee1284_ops.c (parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr): Actually do something useful.
+
+2001-12-07  Tim Waugh  <twaugh@redhat.com>
+
+	* parport_pc.c (dmaval): Don't use DMA by default.  It seems to be
+	too buggy at the moment.  Use 'dma=auto' to restore the previous
+	behaviour.
+
+2001-12-03  Rich Liu  <Rich.Liu@ite.com.tw>
+
+	* parport_pc.c (sio_ite_8872_probe): ITE8873 is a single-port
+	serial board, not a serial+parallel.
+
+2001-11-30  Niels Kristian Bech Jensen  <nkbj@image.dk>
+
+	* parport_pc.c: Fix compiler warning.
+
 2001-12-06  Tim Waugh  <twaugh@redhat.com>
 
 	* ieee1284_ops.c (parport_ieee1284_ecp_read_data): Mask off
diff -u --recursive --new-file pre1/linux/drivers/parport/ieee1284.c linux/drivers/parport/ieee1284.c
--- pre1/linux/drivers/parport/ieee1284.c	Thu Oct 25 00:07:39 2001
+++ linux/drivers/parport/ieee1284.c	Tue Jan 15 13:53:51 2002
@@ -128,7 +128,7 @@
 			return 0;
 		if (signal_pending (current))
 			return -EINTR;
-		if (current->need_resched)
+		if (need_resched())
 			break;
 		if (i >= 2)
 			udelay (5);
diff -u --recursive --new-file pre1/linux/drivers/parport/ieee1284_ops.c linux/drivers/parport/ieee1284_ops.c
--- pre1/linux/drivers/parport/ieee1284_ops.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/parport/ieee1284_ops.c	Thu Jan 17 14:07:57 2002
@@ -136,7 +136,7 @@
                 /* Let another process run if it needs to. */
 		if (time_before (jiffies, expire))
 			if (!parport_yield_blocking (dev)
-			    && current->need_resched)
+			    && need_resched())
 				schedule ();
 	}
  stop:
@@ -824,35 +824,40 @@
 					const void *buffer, size_t len,
 					int flags)
 {
-	/* This is untested */
 	unsigned char *bp = (unsigned char *) buffer;
 	size_t ret = 0;
 
+	/* set EPP idle state (just to make sure) with strobe low */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_STROBE |
+			      PARPORT_CONTROL_AUTOFD |
 			      PARPORT_CONTROL_SELECT |
-			      PARPORT_CONTROL_AUTOFD,
+			      PARPORT_CONTROL_INIT,
 			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_SELECT);
+			      PARPORT_CONTROL_INIT);
 	port->ops->data_forward (port);
 	for (; len > 0; len--, bp++) {
-		/* Write data and assert nAStrb. */
+		/* Event 56: Write data and set nAStrb low. */
 		parport_write_data (port, *bp);
 		parport_frob_control (port, PARPORT_CONTROL_SELECT,
 				      PARPORT_CONTROL_SELECT);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY, 10))
+		/* Event 58: wait for busy (nWait) to go high */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
 			break;
 
+		/* Event 59: set nAStrb high */
 		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+		/* Event 60: wait for busy (nWait) to go low */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
+					     PARPORT_STATUS_BUSY, 5))
 			break;
 
 		ret++;
 	}
 
+	/* Event 61: set strobe (nWrite) high */
 	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
 
 	return ret;
@@ -863,28 +868,36 @@
 				       void *buffer, size_t len,
 				       int flags)
 {
-	/* This is untested. */
 	unsigned char *bp = (unsigned char *) buffer;
 	unsigned ret = 0;
 
+	/* Set EPP idle state (just to make sure) with strobe high */
 	parport_frob_control (port,
 			      PARPORT_CONTROL_STROBE |
-			      PARPORT_CONTROL_AUTOFD, 0);
+			      PARPORT_CONTROL_AUTOFD |
+			      PARPORT_CONTROL_SELECT |
+			      PARPORT_CONTROL_INIT,
+			      PARPORT_CONTROL_INIT);
 	port->ops->data_reverse (port);
 	for (; len > 0; len--, bp++) {
-		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+		/* Event 64: set nSelectIn (nAStrb) low */
+		parport_frob_control (port, PARPORT_CONTROL_SELECT,
+				      PARPORT_CONTROL_SELECT);
 
-		/* Event 58 */
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
-					     PARPORT_STATUS_BUSY, 10))
+		/* Event 58: wait for Busy to go high */
+		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
 			break;
+		}
 
 		*bp = parport_read_data (port);
 
+		/* Event 59: set nSelectIn (nAStrb) high */
 		parport_frob_control (port, PARPORT_CONTROL_SELECT,
 				      PARPORT_CONTROL_SELECT);
 
-		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5))
+		/* Event 60: wait for Busy to go low */
+		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 
+					     PARPORT_STATUS_BUSY, 5))
 			break;
 
 		ret++;
diff -u --recursive --new-file pre1/linux/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- pre1/linux/drivers/parport/parport_pc.c	Mon Nov 12 09:44:58 2001
+++ linux/drivers/parport/parport_pc.c	Thu Jan 17 14:07:57 2002
@@ -91,7 +91,9 @@
 } superios[NR_SUPERIOS] __devinitdata = { {0,},};
 
 static int user_specified __devinitdata = 0;
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
 static int verbose_probing;
+#endif
 static int registered_parport;
 
 /* frob_control, but for ECR */
@@ -596,7 +598,7 @@
 		unsigned char ecrval = inb (ECONTROL (port));
 		int i = 0;
 
-		if (current->need_resched && time_before (jiffies, expire))
+		if (need_resched() && time_before (jiffies, expire))
 			/* Can't yield the port. */
 			schedule ();
 
@@ -622,7 +624,7 @@
 			}
 			ecrval = inb (ECONTROL (port));
 			if (!(ecrval & (1<<2))) {
-				if (current->need_resched &&
+				if (need_resched() &&
 				    time_before (jiffies, expire))
 					schedule ();
 
@@ -746,8 +748,7 @@
 		}
 		/* Is serviceIntr set? */
 		if (!(inb (ECONTROL (port)) & (1<<2))) {
-			if (current->need_resched)
-				schedule ();
+			cond_resched();
 
 			goto false_alarm;
 		}
@@ -758,9 +759,7 @@
 		count = get_dma_residue(port->dma);
 		release_dma_lock(dmaflag);
 
-		if (current->need_resched)
-			/* Can't yield the port. */
-			schedule ();
+		cond_resched(); /* Can't yield the port. */
 
 		/* Anyone else waiting for the port? */
 		if (port->waithead) {
@@ -1093,7 +1092,7 @@
 		long int expire = jiffies + port->cad->timeout;
 		unsigned char ecrval = inb (ECONTROL (port));
 
-		if (current->need_resched && time_before (jiffies, expire))
+		if (need_resched() && time_before (jiffies, expire))
 			/* Can't yield the port. */
 			schedule ();
 
@@ -1130,7 +1129,7 @@
 			}
 			ecrval = inb (ECONTROL (port));
 			if (!(ecrval & (1<<2))) {
-				if (current->need_resched &&
+				if (need_resched() &&
 				    time_before (jiffies, expire)) {
 					schedule ();
 				}
@@ -1780,6 +1779,7 @@
 	return ok;
 }
 
+#ifdef CONFIG_PARPORT_PC_FIFO
 static int __devinit parport_ECP_supported(struct parport *pb)
 {
 	int i;
@@ -1905,6 +1905,7 @@
 
 	return 1;
 }
+#endif
 
 static int __devinit parport_ECPPS2_supported(struct parport *pb)
 {
@@ -2004,7 +2005,9 @@
 
 /* Don't bother probing for modes we know we won't use. */
 static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
+#ifdef CONFIG_PARPORT_PC_FIFO
 static int __devinit parport_ECP_supported(struct parport *pb) { return 0; }
+#endif
 static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
 static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
 static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
@@ -2453,9 +2456,8 @@
 		ite8872set = 0x64e00000;
 		break;
 	case 0x6:
-		printk (KERN_INFO "parport_pc: ITE8873 found (1S1P)\n");
-		ite8872set = 0x64a00000;
-		break;
+		printk (KERN_INFO "parport_pc: ITE8873 found (1S)\n");
+		return 0;
 	case 0x8:
 		DPRINTK (KERN_DEBUG "parport_pc: ITE8874 found (2S)\n");
 		return 0;
@@ -3007,7 +3009,7 @@
 static int io[PARPORT_PC_MAX_PORTS+1] = { [0 ... PARPORT_PC_MAX_PORTS] = 0 };
 static int io_hi[PARPORT_PC_MAX_PORTS+1] =
 	{ [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO };
-static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_AUTO };
+static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE };
 static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
 static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
 static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
@@ -3024,8 +3026,10 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM_DESC(dma, "DMA channel");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-MODULE_PARM(verbose_probing, "i");
+#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
 MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation");
+MODULE_PARM(verbose_probing, "i");
+#endif
 
 int init_module(void)
 {	
diff -u --recursive --new-file pre1/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- pre1/linux/drivers/pci/pci.c	Tue Nov 20 21:53:29 2001
+++ linux/drivers/pci/pci.c	Thu Jan 17 14:21:16 2002
@@ -1929,7 +1929,7 @@
 }
 
 
-void __devinit  pci_init(void)
+static int __devinit pci_init(void)
 {
 	struct pci_dev *dev;
 
@@ -1942,6 +1942,7 @@
 #ifdef CONFIG_PM
 	pm_register(PM_PCI_DEV, 0, pci_pm_callback);
 #endif
+	return 0;
 }
 
 static int __devinit  pci_setup(char *str)
@@ -1958,6 +1959,8 @@
 	}
 	return 1;
 }
+
+subsys_initcall(pci_init);
 
 __setup("pci=", pci_setup);
 
diff -u --recursive --new-file pre1/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- pre1/linux/drivers/pcmcia/ds.c	Tue Jan  1 11:51:31 2002
+++ linux/drivers/pcmcia/ds.c	Thu Jan 17 14:21:16 2002
@@ -966,12 +966,9 @@
     return 0;
 }
 
-#ifdef MODULE
+late_initcall(init_pcmcia_ds);
 
-int __init init_module(void)
-{
-    return init_pcmcia_ds();
-}
+#ifdef MODULE
 
 void __exit cleanup_module(void)
 {
diff -u --recursive --new-file pre1/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- pre1/linux/drivers/pnp/isapnp.c	Mon Nov 12 10:02:54 2001
+++ linux/drivers/pnp/isapnp.c	Thu Jan 17 14:21:16 2002
@@ -2356,12 +2356,9 @@
 	return 0;
 }
 
-#ifdef MODULE
+subsys_initcall(isapnp_init);
 
-int init_module(void)
-{
-	return isapnp_init();
-}
+#ifdef MODULE
 
 void cleanup_module(void)
 {
diff -u --recursive --new-file pre1/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- pre1/linux/drivers/sbus/sbus.c	Mon Jan 14 10:10:44 2002
+++ linux/drivers/sbus/sbus.c	Thu Jan 17 14:21:16 2002
@@ -509,3 +509,5 @@
 	}
 #endif
 }
+
+subsys_initcall(sbus_init);
diff -u --recursive --new-file pre1/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- pre1/linux/drivers/scsi/advansys.c	Thu Jan 10 10:15:38 2002
+++ linux/drivers/scsi/advansys.c	Thu Jan 17 13:59:33 2002
@@ -1,4 +1,4 @@
-#define ASC_VERSION "3.3G"    /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3GG"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -670,6 +670,9 @@
          1. Return an error from narrow boards if passed a 16 byte
             CDB. The wide board can already handle 16 byte CDBs.
 
+     3.3GG (01/02/02):
+	 1. hacks for lk 2.5 series (D. Gilbert)
+
   I. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -3610,6 +3613,23 @@
 #define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b))
 #endif /* CONFIG_PROC_FS */
 
+/*
+ * XXX - Release and acquire the io_request_lock. These macros are needed
+ * because the 2.4 kernel SCSI mid-level driver holds the 'io_request_lock'
+ * on entry to SCSI low-level drivers.
+ *
+ * These definitions and all code that uses code should be removed when the
+ * SCSI mid-level driver no longer holds the 'io_request_lock' on entry to
+ * SCSI low-level driver detect, queuecommand, and reset entrypoints.
+ *
+ * The interrupt flags values doesn't matter in the macros because the
+ * SCSI mid-level will save and restore the flags values before and after
+ * calling advansys_detect, advansys_queuecommand, and advansys_reset where
+ * these macros are used. We do want interrupts enabled after the lock is
+ * released so an explicit sti() is done. The driver only needs interrupts
+ * disabled when it acquires the per board lock.
+ */
+
 /* Asc Library return codes */
 #define ASC_TRUE        1
 #define ASC_FALSE       0
@@ -4054,6 +4074,7 @@
         ADVEEP_38C1600_CONFIG adv_38C1600_eep;  /* 38C1600 EEPROM config. */
     } eep_config;
     ulong                last_reset;            /* Saved last reset time */
+    spinlock_t lock;                            /* Board spinlock */
 #ifdef CONFIG_PROC_FS
     /* /proc/scsi/advansys/[0...] */
     char                 *prtbuf;               /* /proc print buffer */
@@ -4206,7 +4227,7 @@
 STATIC void       advansys_interrupt(int, void *, struct pt_regs *);
 STATIC void       advansys_select_queue_depths(struct Scsi_Host *,
                                                Scsi_Device *);
-STATIC void       asc_scsi_done_list(Scsi_Cmnd *);
+STATIC void       asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
 STATIC int        asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int        asc_build_req(asc_board_t *, Scsi_Cmnd *);
 STATIC int        adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
@@ -4799,6 +4820,9 @@
             memset(boardp, 0, sizeof(asc_board_t));
             boardp->id = asc_board_count - 1;
 
+            /* Initialize spinlock. */
+            boardp->lock = SPIN_LOCK_UNLOCKED; /* replaced by host_lock dpg */
+
             /*
              * Handle both narrow and wide boards.
              *
@@ -5511,7 +5535,7 @@
                 }
             } else {
                 ADV_CARR_T      *carrp;
-                int             req_cnt;
+                int             req_cnt = 0;
                 adv_req_t       *reqp = NULL;
                 int             sg_cnt = 0;
 
@@ -5845,7 +5869,9 @@
     boardp = ASC_BOARDP(shp);
     ASC_STATS(shp, queuecommand);
 
-    spin_lock_irqsave(&shp->host_lock, flags);
+    /* host_lock taken by mid-level prior to call but need to protect */
+    /* against own ISR */
+    spin_lock_irqsave(&boardp->lock, flags);
 
     /*
      * Block new commands while handling a reset or abort request.
@@ -5862,7 +5888,7 @@
          * handling.
          */
         asc_enqueue(&boardp->done, scp, ASC_BACK);
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+	spin_unlock_irqrestore(&boardp->lock, flags);
         return 0;
     }
 
@@ -5902,11 +5928,11 @@
     default:
         done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
         /* Interrupts could be enabled here. */
-        asc_scsi_done_list(done_scp);
+        asc_scsi_done_list(done_scp, 0);
         break;
     }
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
-    spin_unlock_irqrestore(&shp->host_lock, flags);
     return 0;
 }
 
@@ -5952,13 +5978,13 @@
     /*
      * Check for re-entrancy.
      */
-    spin_lock_irqsave(&shp->host_lock, flags);
+    spin_lock_irqsave(&boardp->lock, flags);
     if (boardp->flags & ASC_HOST_IN_RESET) {
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+	spin_unlock_irqrestore(&boardp->lock, flags);
         return FAILED;
     }
     boardp->flags |= ASC_HOST_IN_RESET;
-    spin_unlock_irqrestore(&shp->host_lock, flags);
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
     if (ASC_NARROW_BOARD(boardp)) {
         /*
@@ -5989,11 +6015,7 @@
         }
 
         ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
-
-        /*
-         * Acquire the board lock.
-         */
-        spin_lock_irqsave(&shp->host_lock, flags);
+	spin_lock_irqsave(&boardp->lock, flags);
 
     } else {
         /*
@@ -6020,14 +6042,9 @@
             ret = FAILED;
             break;
         }
-        /*
-         * Acquire the board lock and ensure all requests completed by the
-         * microcode have been processed by calling AdvISR().
-         */
-        spin_lock_irqsave(&shp->host_lock, flags);
+	spin_lock_irqsave(&boardp->lock, flags);
         (void) AdvISR(adv_dvc_varp);
     }
-
     /* Board lock is held. */
 
     /*
@@ -6088,15 +6105,13 @@
 
     /* Clear reset flag. */
     boardp->flags &= ~ASC_HOST_IN_RESET;
-
-    /* Release the board. */
-    spin_unlock_irqrestore(&shp->host_lock, flags);
+    spin_unlock_irqrestore(&boardp->lock, flags);
 
     /*
      * Complete all the 'done_scp' requests.
      */
     if (done_scp != NULL) {
-        asc_scsi_done_list(done_scp);
+        asc_scsi_done_list(done_scp, 0);
     }
 
     ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
@@ -6259,6 +6274,7 @@
     asc_board_t     *boardp;
     Scsi_Cmnd       *done_scp = NULL, *last_scp = NULL;
     Scsi_Cmnd       *new_last_scp;
+    struct Scsi_Host *shp;
 
     ASC_DBG(1, "advansys_interrupt: begin\n");
 
@@ -6267,17 +6283,17 @@
      * AscISR() will call asc_isr_callback().
      */
     for (i = 0; i < asc_board_count; i++) {
-	struct Scsi_Host *shp = asc_host[i];
+	shp = asc_host[i];
         boardp = ASC_BOARDP(shp);
         ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
             i, (ulong) boardp);
-        spin_lock_irqsave(&shp->host_lock, flags);
+        spin_lock_irqsave(&boardp->lock, flags);
         if (ASC_NARROW_BOARD(boardp)) {
             /*
              * Narrow Board
              */
-            if (AscIsIntPending(asc_host[i]->io_port)) {
-                ASC_STATS(asc_host[i], interrupt);
+            if (AscIsIntPending(shp->io_port)) {
+                ASC_STATS(shp, interrupt);
                 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
                 AscISR(&boardp->dvc_var.asc_dvc_var);
             }
@@ -6287,7 +6303,7 @@
              */
             ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
             if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
-                ASC_STATS(asc_host[i], interrupt);
+                ASC_STATS(shp, interrupt);
             }
         }
 
@@ -6327,7 +6343,7 @@
                 }
             }
         }
-        spin_unlock_irqrestore(&shp->host_lock, flags);
+        spin_unlock_irqrestore(&boardp->lock, flags);
     }
 
     /*
@@ -6336,7 +6352,8 @@
      *
      * Complete all requests on the done list.
      */
-    asc_scsi_done_list(done_scp);
+
+    asc_scsi_done_list(done_scp, 1);
 
     ASC_DBG(1, "advansys_interrupt: end\n");
     return;
@@ -6383,9 +6400,10 @@
  * Interrupts can be enabled on entry.
  */
 STATIC void
-asc_scsi_done_list(Scsi_Cmnd *scp)
+asc_scsi_done_list(Scsi_Cmnd *scp, int from_isr)
 {
     Scsi_Cmnd    *tscp;
+    ulong	  flags = 0;
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
@@ -6394,7 +6412,11 @@
         REQPNEXT(scp) = NULL;
         ASC_STATS(scp->host, done);
         ASC_ASSERT(scp->scsi_done != NULL);
+	if (from_isr)
+	    spin_lock_irqsave(&scp->host->host_lock, flags);
         scp->scsi_done(scp);
+	if (from_isr)
+	    spin_unlock_irqrestore(&scp->host->host_lock, flags);
         scp = tscp;
     }
     ASC_DBG(2, "asc_scsi_done_list: done\n");
@@ -6728,7 +6750,9 @@
         slp = (struct scatterlist *) scp->request_buffer;
         for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
             asc_sg_head.sg_list[sgcnt].addr =
-                cpu_to_le32(virt_to_bus(slp->address));
+                cpu_to_le32(virt_to_bus(slp->address ? 
+		(unsigned char *)slp->address :
+		(unsigned char *)page_address(slp->page) + slp->offset));
             asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
         }
@@ -6986,7 +7010,9 @@
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
-                cpu_to_le32(virt_to_bus(slp->address));
+                cpu_to_le32(virt_to_bus(slp->address ? 
+		(unsigned char *)slp->address :
+                (unsigned char *)page_address(slp->page) + slp->offset));
             sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 
diff -u --recursive --new-file pre1/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c linux/drivers/scsi/aic7xxx/aic7xxx_linux.c
--- pre1/linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Thu Jan 10 10:15:38 2002
+++ linux/drivers/scsi/aic7xxx/aic7xxx_linux.c	Thu Jan 17 13:59:33 2002
@@ -1700,6 +1700,7 @@
 			       cmd->request_buffer,
 			       cmd->request_bufflen,
 			       scsi_to_pci_dma_dir(cmd->sc_data_direction));
+			scb->sg_count = 0;
 			scb->sg_count = ahc_linux_map_seg(ahc, scb,
 							  sg, addr,
 							  cmd->request_bufflen);
diff -u --recursive --new-file pre1/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- pre1/linux/drivers/scsi/scsi_debug.c	Sun Dec 16 12:20:20 2001
+++ linux/drivers/scsi/scsi_debug.c	Thu Jan 17 13:59:33 2002
@@ -3,8 +3,19 @@
  *
  *  Copyright (C) 1992  Eric Youngdale
  *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
- *  to make sure that we are not getting blocks mixed up, and panic if
+ *  to make sure that we are not getting blocks mixed up, and PANIC if
  *  anything out of the ordinary is seen.
+ *
+ *  This version is more generic, simulating a variable number of disk 
+ *  (or disk like devices) sharing a common amount of RAM (default 8 MB
+ *  but can be set at driver/module load time).
+ *
+ *  For documentation see http://www.torque.net/sg/sdebug.html
+ *
+ *   D. Gilbert (dpg) work for MOD device test [20010421]
+ *   dpg, work for devfs large number of disks [20010809]
+ *   dpg, make more generic [20011123]
+ *   dpg, forked for lk 2.5 series [20011216, 20020101]
  */
 
 #include <linux/config.h>
@@ -18,7 +29,9 @@
 #include <linux/string.h>
 #include <linux/genhd.h>
 #include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -27,201 +40,187 @@
 #include "scsi.h"
 #include "hosts.h"
 
-#include "sd.h"
-
 #include<linux/stat.h>
 
-/* A few options that we want selected */
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+static char scsi_debug_version_str[] = "Version: 1.57 (20011216)";
 
-#define NR_HOSTS_PRESENT 1
-#define NR_FAKE_DISKS   3
-#define N_HEAD          255
-#define N_SECTOR        63
-#define N_CYLINDER      524
+#ifndef SCSI_CMD_READ_16
+#define SCSI_CMD_READ_16 0x88
+#endif
+#ifndef SCSI_CMD_WRITE_16
+#define SCSI_CMD_WRITE_16 0x8a
+#endif
+
+/* A few options that we want selected */
+#define DEF_NR_FAKE_DEVS   1
+#define DEF_DEV_SIZE_MB   8
+#define DEF_FAKE_BLK0   0
+
+static int scsi_debug_num_devs = DEF_NR_FAKE_DEVS;
+
+#define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
+#define N_HEAD          8
+#define N_SECTOR        32
 #define DISK_READONLY(TGT)      (0)
-#define DISK_REMOVEABLE(TGT)    (1)
-#define DEVICE_TYPE(TGT) (TGT == 2 ? TYPE_TAPE : TYPE_DISK);
+#define DISK_REMOVEABLE(TGT)    (0)
+#define DEVICE_TYPE(TGT) (TYPE_DISK);
+
+#define SCSI_DEBUG_MAILBOXES (scsi_debug_num_devs + 1)
+
+static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
+#define STORE_SIZE (scsi_debug_dev_size_mb * 1024 * 1024)
+#define STORE_ELEM_ORDER 1
+#define STORE_ELEM_SIZE (PAGE_SIZE * (1 << STORE_ELEM_ORDER))
+#define STORE_ELEMENTS ((STORE_SIZE / STORE_ELEM_SIZE) + 1)
+
+/* default sector size is 512 bytes, 2**9 bytes */
+#define POW2_SECT_SIZE 9
+#define SECT_SIZE (1 << POW2_SECT_SIZE)
+
+#define N_CYLINDER (STORE_SIZE / (SECT_SIZE * N_SECTOR * N_HEAD))
+
+static int scsi_debug_fake_blk0 = DEF_FAKE_BLK0;
 
 /* Do not attempt to use a timer to simulate a real disk with latency */
 /* Only use this in the actual kernel, not in the simulator. */
 #define IMMEDIATE
 
-/* Skip some consistency checking.  Good for benchmarking */
-#define SPEEDY
-/* Read return zeros. Undefine for benchmarking */
-#define CLEAR
-
-/* Number of real scsi disks that will be detected ahead of time */
-static int NR_REAL = -1;
-
-#define NR_BLK_DEV  12
-#ifndef MAJOR_NR
-#define MAJOR_NR 8
-#endif
+#define SDEBUG_SG_ADDRESS
+
 #define START_PARTITION 4
 
 /* Time to wait before completing a command */
 #define DISK_SPEED     (HZ/10)	/* 100ms */
 #define CAPACITY (N_HEAD * N_SECTOR * N_CYLINDER)
-#define SIZE(TGT) (TGT == 2 ? 2248 : 512)
+#define SECT_SIZE_PER(TGT) SECT_SIZE
+#define SECT_PER_ELEM (STORE_ELEM_SIZE / SECT_SIZE)
 
 static int starts[] =
 {N_SECTOR,
  N_HEAD * N_SECTOR,		/* Single cylinder */
  N_HEAD * N_SECTOR * 4,
- CAPACITY, 0};
+ 0 /* CAPACITY */, 0};
 static int npart = 0;
 
-#include "scsi_debug.h"
-#ifdef DEBUG
-#define DEB(x) x
-#else
-#define DEB(x)
-#endif
+typedef struct scsi_debug_store_elem {
+	unsigned char * p;
+} Sd_store_elem;
+
+static Sd_store_elem * store_arr = 0;
+
+typedef struct sdebug_dev_info {
+	Scsi_Device * sdp;
+	unsigned short host_no;
+	unsigned short id;
+	char reset;
+	char sb_index;
+} Sdebug_dev_info;
+static Sdebug_dev_info * devInfop;
+
+static int num_aborts = 0;
+static int num_dev_resets = 0;
+static int num_bus_resets = 0;
+static int num_host_resets = 0;
 
-#ifdef SPEEDY
-#define VERIFY1_DEBUG(RW)
-#define VERIFY_DEBUG(RW)
-#else
+static spinlock_t mailbox_lock = SPIN_LOCK_UNLOCKED;
+static rwlock_t sdebug_atomic_rw = RW_LOCK_UNLOCKED;
 
-#define VERIFY1_DEBUG(RW)                           \
-    if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");};         \
-    start = 0;                          \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1];        \
-    if (bh){                            \
-	if (bh->b_size != 1024) panic ("Wrong bh size");    \
-	if ((bh->b_blocknr << 1) + start != block)          \
-	{   printk("Wrong bh block# %d %d ",bh->b_blocknr, block);  \
-	    panic ("Wrong bh block#"); \
-	};  \
-	if (bh->b_dev != SCpnt->request.rq_dev)  \
-	    panic ("Bad bh target"); \
-    };
-
-#define VERIFY_DEBUG(RW)                            \
-    if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");};    \
-    start = 0;                          \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) > npart) panic ("Bad partition");    \
-    if ((MINOR(SCpnt->request.rq_dev) & 0xf) != 0) start = starts[(MINOR(SCpnt->request.rq_dev) & 0xf) - 1];        \
-    if (SCpnt->request.cmd != RW) panic ("Wrong  operation");       \
-    if (SCpnt->request.sector + start != block) panic("Wrong block.");  \
-    if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks");   \
-    if (SCpnt->request.bh){                         \
-	if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
-	if ((SCpnt->request.bh->b_blocknr << 1) + start != block)           \
-	{   printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block);  \
-	    panic ("Wrong bh block#"); \
-	};  \
-	if (SCpnt->request.bh->b_dev != SCpnt->request.rq_dev) \
-	    panic ("Bad bh target");\
-    };
-#endif
+#include "scsi_debug.h"
 
 typedef void (*done_fct_t) (Scsi_Cmnd *);
 
-static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
+static volatile done_fct_t * do_done = 0;
 
 struct Scsi_Host * SHpnt = NULL;
 
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			   int num, int * errstsp, Sdebug_dev_info * devip);
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			    int num, int * errstsp, Sdebug_dev_info * devip);
 static void scsi_debug_send_self_command(struct Scsi_Host * shpnt);
 static void scsi_debug_intr_handle(unsigned long);
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp);
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+			    int asc, int asq, int inbandLen);
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip);
 
-static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
-
-Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES] =
-{NULL,};
-static char SCrst[SCSI_DEBUG_MAILBOXES] =
-{0,};
+static struct timer_list * timeout = 0;
+static Scsi_Cmnd ** SCint = 0;
 
 /*
  * Semaphore used to simulate bus lockups.
  */
 static int scsi_debug_lockup = 0;
 
-static char sense_buffer[128] =
-{0,};
+#define NUM_SENSE_BUFFS 4
+#define SENSE_BUFF_LEN 32
+static char sense_buffers[NUM_SENSE_BUFFS][SENSE_BUFF_LEN];
 
-static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
+static int made_block0 = 0;
+
+static void scsi_debug_mkblock0(unsigned char * buff, int bufflen,
+				Scsi_Cmnd * SCpnt)
 {
 	int i;
-#if 0
-	unsigned char *pnt;
-#endif
-	unsigned int *lpnt;
-	struct scatterlist *sgpnt = NULL;
-	printk("use_sg: %d", SCpnt->use_sg);
-	if (SCpnt->use_sg) {
-		sgpnt = (struct scatterlist *) SCpnt->buffer;
-		for (i = 0; i < SCpnt->use_sg; i++) {
-			printk(":%p %d\n", sgpnt[i].address, sgpnt[i].length);
-		};
-	} else {
-		printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
-		       SCpnt->bufflen);
-		lpnt = (int *) SCpnt->request.buffer;
-		if (lpnt)
-			printk(" (Alt %x) ", lpnt[15]);
-	};
-	lpnt = (unsigned int *) SCpnt;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	};
-	printk("\n");
-	if (flag == 0)
-		return;
-#if 0
-	printk("\n");
-	lpnt = (unsigned int *) sgpnt[0].address;
-	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
-		if ((i & 7) == 0)
-			printk("\n");
-		printk("%x ", *lpnt++);
-	};
-	printk("\n");
-#endif
+	struct partition *p;
+
+	memset(buff, 0, bufflen);
+	*((unsigned short *) (buff + 510)) = 0xAA55;
+	p = (struct partition *) (buff + 0x1be);
+	i = 0;
+	while (starts[i + 1]) {
+		int start_cyl, end_cyl;
+
+		start_cyl = starts[i] / N_HEAD / N_SECTOR;
+		end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
+		p->boot_ind = 0;
+
+		p->head = (i == 0 ? 1 : 0);
+		p->sector = 1 | ((start_cyl >> 8) << 6);
+		p->cyl = (start_cyl & 0xff);
+
+		p->end_head = N_HEAD - 1;
+		p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
+		p->end_cyl = (end_cyl & 0xff);
+
+		p->start_sect = starts[i];
+		p->nr_sects = starts[i + 1] - starts[i];
+		p->sys_ind = 0x83;	/* Linux ext2 partition */
+		p++;
+		i++;
+	}
+	if (!npart)
+		npart = i;
+	made_block0 = 1;
+	i = (bufflen > STORE_ELEM_SIZE) ? STORE_ELEM_SIZE : bufflen;
+	memcpy(store_arr[0].p, buff, i);
 }
 
 int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
 	unchar *cmd = (unchar *) SCpnt->cmnd;
-	struct partition *p;
 	int block;
-	struct buffer_head *bh = NULL;
+	int upper_blk;
 	unsigned char *buff;
-	int nbytes, sgcount;
 	int scsi_debug_errsts;
-	struct scatterlist *sgpnt;
 	int target = SCpnt->target;
 	int bufflen = SCpnt->request_bufflen;
-	unsigned long flags;
-	int i;
-	sgcount = 0;
-	sgpnt = NULL;
-
-#ifdef CONFIG_SMP
-        /*
-         * The io_request_lock *must* be held at this point.
-         */
-        if( io_request_lock.lock == 0 )
-        {
-                printk("Warning - io_request_lock is not held in queuecommand\n");
-        }
-#endif
+	unsigned long iflags;
+	int i, num, capac;
+	Sdebug_dev_info * devip = NULL;
+	char * sbuff;
 
 	/*
-	 * If we are being notified of the mid-level reposessing a command due to timeout,
-	 * just return.
+	 * If we are being notified of the mid-level reposessing a command
+	 * due to timeout, just return.
 	 */
 	if (done == NULL) {
 		return 0;
 	}
-	DEB(if (target >= NR_FAKE_DISKS) {
-	    SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0;
-	    }
-	);
 
 	buff = (unsigned char *) SCpnt->request_buffer;
 
@@ -229,249 +228,201 @@
          * If a command comes for the ID of the host itself, just print
          * a silly message and return.
          */
-        if( target == 7 ) {
+        if(target == 7) {
                 printk("How do you do!\n");
                 SCpnt->result = 0;
                 done(SCpnt);
                 return 0;
         }
 
-	if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) {
+	if ((target > 7) || (SCpnt->lun != 0)) {
 		SCpnt->result = DID_NO_CONNECT << 16;
 		done(SCpnt);
 		return 0;
 	}
-	if (SCrst[target] != 0 && !scsi_debug_lockup) {
-		SCrst[target] = 0;
-		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-		SCpnt->sense_buffer[0] = 0x70;
-		SCpnt->sense_buffer[2] = UNIT_ATTENTION;
-		SCpnt->result = (CHECK_CONDITION << 1);
-		done(SCpnt);
+#if 0
+	printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
+	       (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
+	       SCpnt->device, (int)(unsigned char)*cmd);
+#endif
+	if (NULL == SCpnt->device->hostdata) {
+		devip = devInfoReg(SCpnt->device);
+		if (NULL == devip) {
+			SCpnt->result = DID_NO_CONNECT << 16;
+			done(SCpnt);
+			return 0;
+		}
+		SCpnt->device->hostdata = devip;
 	}
+	devip = SCpnt->device->hostdata;
+
 	switch (*cmd) {
-	case REQUEST_SENSE:
+	case REQUEST_SENSE:	/* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
-#ifndef DEBUG
-		{
-			int i;
-			printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
-			for (i = 0; i < 12; i++)
-				printk("%d ", sense_buffer[i]);
-			printk("\n");
-		};
-#endif
-		memset(buff, 0, bufflen);
-		memcpy(buff, sense_buffer, bufflen);
-		memset(sense_buffer, 0, sizeof(sense_buffer));
+		if (devip) {
+			sbuff = &sense_buffers[(int)devip->sb_index][0];
+			devip->sb_index = 0; 
+		}
+		else
+		    sbuff = &sense_buffers[0][0]; 
+		memcpy(buff, sbuff, (bufflen < SENSE_BUFF_LEN) ? 
+				     bufflen : SENSE_BUFF_LEN);
+		memset(sbuff, 0, SENSE_BUFF_LEN);
+		sbuff[0] = 0x70;
 		SCpnt->result = 0;
 		done(SCpnt);
 		return 0;
 	case START_STOP:
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
 		SCSI_LOG_LLQUEUE(3, printk("START_STOP\n"));
 		scsi_debug_errsts = 0;
 		break;
 	case ALLOW_MEDIUM_REMOVAL:
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
 		if (cmd[4]) {
-			SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
+			SCSI_LOG_LLQUEUE(2, printk(
+					"Medium removal inhibited..."));
 		} else {
-			SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled..."));
+			SCSI_LOG_LLQUEUE(2, 
+					printk("Medium removal enabled..."));
 		}
 		scsi_debug_errsts = 0;
 		break;
-	case INQUIRY:
+	case INQUIRY:     /* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
 		memset(buff, 0, bufflen);
 		buff[0] = DEVICE_TYPE(target);
-		buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
-		buff[2] = 1;
-		buff[4] = 33 - 5;
-		memcpy(&buff[8], "Foo Inc", 7);
-		memcpy(&buff[16], "XYZZY", 5);
-		memcpy(&buff[32], "1", 1);
+		buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;	
+				/* Removable disk */
+		buff[2] = 2;	/* claim SCSI 2 */
+		buff[4] = 36 - 5;
+		memcpy(&buff[8], "Linux   ", 8);
+		memcpy(&buff[16], "scsi_debug      ", 16);
+		memcpy(&buff[32], "0002", 4);
+		scsi_debug_errsts = 0;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)
+		if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+			SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+#endif
+		break;
+	case SEND_DIAGNOSTIC:     /* mandatory */
+		SCSI_LOG_LLQUEUE(3, printk("Send Diagnostic\n"));
+		if (buff)
+			memset(buff, 0, bufflen);
 		scsi_debug_errsts = 0;
 		break;
-	case TEST_UNIT_READY:
+	case TEST_UNIT_READY:     /* mandatory */
 		SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen));
 		if (buff)
 			memset(buff, 0, bufflen);
 		scsi_debug_errsts = 0;
 		break;
 	case READ_CAPACITY:
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
 		SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
                 SHpnt = SCpnt->host;
-		if (NR_REAL < 0)
-			NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
 		memset(buff, 0, bufflen);
-		buff[0] = (CAPACITY >> 24);
-		buff[1] = (CAPACITY >> 16) & 0xff;
-		buff[2] = (CAPACITY >> 8) & 0xff;
-		buff[3] = CAPACITY & 0xff;
+		capac = CAPACITY - 1;
+		buff[0] = (capac >> 24);
+		buff[1] = (capac >> 16) & 0xff;
+		buff[2] = (capac >> 8) & 0xff;
+		buff[3] = capac & 0xff;
 		buff[4] = 0;
 		buff[5] = 0;
-		buff[6] = (SIZE(target) >> 8) & 0xff;	/* 512 byte sectors */
-		buff[7] = SIZE(target) & 0xff;
+		buff[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+		buff[7] = SECT_SIZE_PER(target) & 0xff;
 
 		scsi_debug_errsts = 0;
 		break;
+	case SCSI_CMD_READ_16:	/* SBC-2 */
+	case READ_12:
 	case READ_10:
 	case READ_6:
-#ifdef DEBUG
-		printk("Read...");
-#endif
-		if ((*cmd) == READ_10)
-			block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-		else
-			block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-		VERIFY_DEBUG(READ);
-#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
-		{
-			int delay = SCSI_SETUP_LATENCY;
-
-			delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
-			if (delay)
-				usleep(delay);
-		};
-#endif
-
-#ifdef DEBUG
-		printk("(r%d)", SCpnt->request.nr_sectors);
-#endif
-		nbytes = bufflen;
-		if (SCpnt->use_sg) {
-			sgcount = 0;
-			sgpnt = (struct scatterlist *) buff;
-			buff = sgpnt[sgcount].address;
-			bufflen = sgpnt[sgcount].length;
-			bh = SCpnt->request.bh;
-		};
-		scsi_debug_errsts = 0;
-		do {
-			VERIFY1_DEBUG(READ);
-			/* For the speedy test, we do not even want to fill the buffer with anything */
-#ifdef CLEAR
-			memset(buff, 0, bufflen);
-#endif
-			/* If this is block 0, then we want to read the partition table for this
-			 * device.  Let's make one up */
-			if (block == 0) {
-				int i;
-				memset(buff, 0, bufflen);
-				*((unsigned short *) (buff + 510)) = 0xAA55;
-				p = (struct partition *) (buff + 0x1be);
-				i = 0;
-				while (starts[i + 1]) {
-					int start_cyl, end_cyl;
-
-					start_cyl = starts[i] / N_HEAD / N_SECTOR;
-					end_cyl = (starts[i + 1] - 1) / N_HEAD / N_SECTOR;
-					p->boot_ind = 0;
-
-					p->head = (i == 0 ? 1 : 0);
-					p->sector = 1 | ((start_cyl >> 8) << 6);
-					p->cyl = (start_cyl & 0xff);
-
-					p->end_head = N_HEAD - 1;
-					p->end_sector = N_SECTOR | ((end_cyl >> 8) << 6);
-					p->end_cyl = (end_cyl & 0xff);
-
-					p->start_sect = starts[i];
-					p->nr_sects = starts[i + 1] - starts[i];
-					p->sys_ind = 0x81;	/* Linux partition */
-					p++;
-					i++;
-				};
-				if (!npart)
-					npart = i;
-				scsi_debug_errsts = 0;
-				break;
-			};
-#ifdef DEBUG
-			if (SCpnt->use_sg)
-				printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors,
-				       SCpnt->request.current_nr_sectors);
-#endif
-
-#if 0
-			/* Simulate a disk change */
-			if (block == 0xfff0) {
-				sense_buffer[0] = 0x70;
-				sense_buffer[2] = UNIT_ATTENTION;
-				starts[0] += 10;
-				starts[1] += 10;
-				starts[2] += 10;
-
-#ifdef DEBUG
-				{
-					int i;
-					printk("scsi_debug: Filling sense buffer:");
-					for (i = 0; i < 12; i++)
-						printk("%d ", sense_buffer[i]);
-					printk("\n");
-				};
-#endif
-				scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
-				break;
-			}	/* End phony disk change code */
-#endif
-
-#ifdef CLEAR
-			memcpy(buff, &target, sizeof(target));
-			memcpy(buff + sizeof(target), cmd, 24);
-			memcpy(buff + 60, &block, sizeof(block));
-			memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd));
-#endif
-			nbytes -= bufflen;
-			if (SCpnt->use_sg) {
-#ifdef CLEAR
-				memcpy(buff + 128, bh, sizeof(struct buffer_head));
-#endif
-				block += bufflen >> 9;
-				bh = bh->b_reqnext;
-				sgcount++;
-				if (nbytes) {
-					if (!bh)
-						panic("Too few blocks for linked request.");
-					buff = sgpnt[sgcount].address;
-					bufflen = sgpnt[sgcount].length;
-				};
-			}
-		} while (nbytes);
-
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
+		upper_blk = 0;
+		if ((*cmd) == SCSI_CMD_READ_16) {
+			upper_blk = cmd[5] + (cmd[4] << 8) + 
+				    (cmd[3] << 16) + (cmd[2] << 24);
+			block = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+			num = cmd[13] + (cmd[12] << 8) + 
+				(cmd[11] << 16) + (cmd[10] << 24);
+		}
+		else if ((*cmd) == READ_12) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+		}
+		else if ((*cmd) == READ_10) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[8] + (cmd[7] << 8);
+		}
+		else {
+			block = cmd[3] + (cmd[2] << 8) + 
+				((cmd[1] & 0x1f) << 16);
+			num = cmd[4];
+		}
+		if (scsi_debug_read(SCpnt, upper_blk, block, num, 
+				    &scsi_debug_errsts, devip))
+			break;
 		SCpnt->result = 0;
-		(done) (SCpnt);
+/* calls bottom half in upper layers before return from scsi_do_...() */
+		(done) (SCpnt);	
 		return 0;
-
-		if (SCpnt->use_sg && !scsi_debug_errsts)
-			if (bh)
-				scsi_dump(SCpnt, 0);
-		break;
+	case SCSI_CMD_WRITE_16:	/* SBC-2 */
+	case WRITE_12:
 	case WRITE_10:
 	case WRITE_6:
-#ifdef DEBUG
-		printk("Write\n");
-#endif
-		if ((*cmd) == WRITE_10)
-			block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
-		else
-			block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-		VERIFY_DEBUG(WRITE);
-		/*      printk("(w%d)",SCpnt->request.nr_sectors); */
-		if (SCpnt->use_sg) {
-			if ((bufflen >> 9) != SCpnt->request.nr_sectors)
-				panic("Trying to write wrong number of blocks\n");
-			sgpnt = (struct scatterlist *) buff;
-			buff = sgpnt[sgcount].address;
-		};
-#if 0
-		if (block != *((unsigned long *) (buff + 60))) {
-			printk("%x %x :", block, *((unsigned long *) (buff + 60)));
-			scsi_dump(SCpnt, 1);
-			panic("Bad block written.\n");
-		};
-#endif
-		scsi_debug_errsts = 0;
-		break;
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
+		upper_blk = 0;
+		if ((*cmd) == SCSI_CMD_WRITE_16) {
+			upper_blk = cmd[5] + (cmd[4] << 8) + 
+				    (cmd[3] << 16) + (cmd[2] << 24);
+			block = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+			num = cmd[13] + (cmd[12] << 8) + 
+				(cmd[11] << 16) + (cmd[10] << 24);
+		}
+		else if ((*cmd) == WRITE_12) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[9] + (cmd[8] << 8) + 
+				(cmd[7] << 16) + (cmd[6] << 24);
+		}
+		else if ((*cmd) == WRITE_10) {
+			block = cmd[5] + (cmd[4] << 8) + 
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[8] + (cmd[7] << 8);
+		}
+		else {
+			block = cmd[3] + (cmd[2] << 8) + 
+				((cmd[1] & 0x1f) << 16);
+			num = cmd[4];
+		}
+		if (scsi_debug_write(SCpnt, upper_blk, block, num, 
+				     &scsi_debug_errsts, devip))
+			break;
+		SCpnt->result = 0;
+/* calls bottom half in upper layers before return from scsi_do_...() */
+		(done) (SCpnt);	
+		return 0;
 	case MODE_SENSE:
 		/*
 		 * Used to detect write protected status.
@@ -480,26 +431,36 @@
 		memset(buff, 0, 6);
 		break;
 	default:
+#if 0
 		SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd));
 		SCpnt->result = DID_NO_CONNECT << 16;
 		done(SCpnt);
 		return 0;
-	};
+#else
+		if (check_reset(SCpnt, devip)) {
+			done(SCpnt);
+			return 0;
+		}
+		scsi_debug_errsts = (COMMAND_COMPLETE << 8) |
+				    (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 2, ILLEGAL_REQUEST, 0x20, 0, 14);
+		break;
+#endif
+	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&mailbox_lock, iflags);
 	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
 		if (timeout[i].function == NULL)
 			break;
-	};
+	}
 
 	/*
-	 * If all of the slots are full, just return 1.  The new error handling scheme
-	 * allows this, and the mid-level should queue things.
+	 * If all of the slots are full, just return 1.  The new error 
+	 * handling scheme allows this, and the mid-level should queue things.
 	 */
 	if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) {
 		SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
-		restore_flags(flags);
+		spin_unlock_irqrestore(&mailbox_lock, iflags);
 		return 1;
 	}
 	SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
@@ -511,7 +472,7 @@
 		do_done[i] = done;
 		scsi_debug_intr_handle(i);	/* No timer - do this one right away */
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&mailbox_lock, iflags);
 #else
 
 	SCpnt->result = scsi_debug_errsts;
@@ -521,19 +482,200 @@
 	SCint[i] = SCpnt;
 	do_done[i] = done;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&mailbox_lock, iflags);
 	add_timer(&timeout[i]);
 	if (!done)
-		panic("scsi_debug_queuecommand: done can't be NULL\n");
+		printk("scsi_debug_queuecommand: done can't be NULL\n");
 
 #if 0
-	printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies);
+	printk("Sending command (%d %x %d %d)...", i, done, 
+	       timeout[i].expires, jiffies);
 #endif
 #endif
 
 	return 0;
 }
 
+static int check_reset(Scsi_Cmnd * SCpnt, Sdebug_dev_info * devip)
+{
+	if (devip->reset) {
+		devip->reset = 0;
+		mk_sense_buffer(devip, 3, UNIT_ATTENTION, 0x29, 0, 14);
+		SCpnt->result = (COMMAND_COMPLETE << 8) | 
+				(CHECK_CONDITION << 1);
+                return 1;
+	}
+	return 0;
+}
+
+static inline 
+unsigned char * sdebug_scatg2virt(const struct scatterlist * sclp)
+{
+	if (NULL == sclp)
+		return NULL;
+	else if (sclp->page)
+		return (unsigned char *)page_address(sclp->page) + 
+		       sclp->offset;
+	else {
+#ifdef SDEBUG_SG_ADDRESS
+		return sclp->address;
+#else
+		return NULL;
+#endif
+	}
+}
+
+static int scsi_debug_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			   int num, int * errstsp, Sdebug_dev_info * devip)
+{
+        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+        int nbytes, sgcount;
+        struct scatterlist *sgpnt = NULL;
+        int bufflen = SCpnt->request_bufflen;
+	unsigned long iflags;
+
+	if (upper_blk || (block + num > CAPACITY)) {
+		*errstsp = (COMMAND_COMPLETE << 8) |
+			   (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return 1;
+	}
+#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
+	{
+		int delay = SCSI_SETUP_LATENCY;
+
+		delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
+		if (delay)
+			usleep(delay);
+	}
+#endif
+
+	read_lock_irqsave(&sdebug_atomic_rw, iflags);
+        sgcount = 0;
+	nbytes = bufflen;
+	/* printk("scsi_debug_read: block=%d, tot_bufflen=%d\n", 
+	       block, bufflen); */
+	if (SCpnt->use_sg) {
+		sgcount = 0;
+		sgpnt = (struct scatterlist *) buff;
+		buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+		bufflen = sgpnt[sgcount].length;
+	}
+	*errstsp = 0;
+	do {
+		int resid, k, off, len, rem, blk;
+		unsigned char * bp;
+
+		/* If this is block 0, then we want to read the partition
+		 * table for this device.  Let's make one up */
+		if (scsi_debug_fake_blk0 && (block == 0) && (! made_block0)) {
+			scsi_debug_mkblock0(buff, bufflen, SCpnt);
+			*errstsp = 0;
+			break;
+		}
+		bp = buff;
+		blk = block;
+		for (resid = bufflen; resid > 0; resid -= len) {
+			k = blk / SECT_PER_ELEM; 
+			off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+			rem = STORE_ELEM_SIZE - off;
+			len = (resid > rem) ? rem : resid;
+/* printk("sdr: blk=%d k=%d off=%d rem=%d resid"
+			       "=%d len=%d  sgcount=%d\n", blk, k, 
+				off, rem, resid, len, sgcount); */
+			memcpy(bp, store_arr[k].p + off, len);
+			bp += len;
+			blk += len / SECT_SIZE;
+		}
+#if 0
+		/* Simulate a disk change */
+		if (block == 0xfff0) {
+			sense_buffer[0] = 0x70;
+			sense_buffer[2] = UNIT_ATTENTION;
+			starts[0] += 10;
+			starts[1] += 10;
+			starts[2] += 10;
+
+			*errstsp = (COMMAND_COMPLETE << 8) | 
+				   (CHECK_CONDITION << 1);
+			read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+			return 1;
+		}	/* End phony disk change code */
+#endif
+		nbytes -= bufflen;
+		if (SCpnt->use_sg) {
+			block += bufflen >> POW2_SECT_SIZE;
+			sgcount++;
+			if (nbytes) {
+				buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+				bufflen = sgpnt[sgcount].length;
+			}
+		}
+		else if (nbytes > 0)
+			printk("sdebug_read: unexpected nbytes=%d\n", nbytes);
+	} while (nbytes);
+	read_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	return 0;
+}
+
+static int scsi_debug_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+			    int num, int * errstsp, Sdebug_dev_info * devip)
+{
+        unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
+        int nbytes, sgcount;
+        struct scatterlist *sgpnt = NULL;
+        int bufflen = SCpnt->request_bufflen;
+	unsigned long iflags;
+
+	if (upper_blk || (block + num > CAPACITY)) {
+		*errstsp = (COMMAND_COMPLETE << 8) |
+			   (CHECK_CONDITION << 1);
+		mk_sense_buffer(devip, 1, ILLEGAL_REQUEST, 0x21, 0, 14);
+		return 1;
+	}
+
+	write_lock_irqsave(&sdebug_atomic_rw, iflags);
+        sgcount = 0;
+	nbytes = bufflen;
+	if (SCpnt->use_sg) {
+		sgcount = 0;
+		sgpnt = (struct scatterlist *) buff;
+		buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+		bufflen = sgpnt[sgcount].length;
+	}
+	*errstsp = 0;
+	do {
+		int resid, k, off, len, rem, blk;
+		unsigned char * bp;
+
+		bp = buff;
+		blk = block;
+		for (resid = bufflen; resid > 0; resid -= len) {
+			k = blk / SECT_PER_ELEM; 
+			off = (blk % SECT_PER_ELEM) * SECT_SIZE;
+			rem = STORE_ELEM_SIZE - off;
+			len = (resid > rem) ? rem : resid;
+			memcpy(store_arr[k].p + off, bp, len);
+			bp += len;
+			blk += len / SECT_SIZE;
+		}
+
+		nbytes -= bufflen;
+		if (SCpnt->use_sg) {
+			block += bufflen >> POW2_SECT_SIZE;
+			sgcount++;
+			if (nbytes) {
+				buff = sdebug_scatg2virt(&sgpnt[sgcount]);
+				bufflen = sgpnt[sgcount].length;
+			}
+		}
+		else if (nbytes > 0)
+			printk("sdebug_write: unexpected nbytes=%d\n", nbytes);
+	} while (nbytes);
+	write_unlock_irqrestore(&sdebug_atomic_rw, iflags);
+	return 0;
+}
+
 static void scsi_debug_send_self_command(struct Scsi_Host * shpnt)
 {
 	static unsigned char cmd[6] =
@@ -581,10 +723,6 @@
 {
 	Scsi_Cmnd *SCtmp;
 	void (*my_done) (Scsi_Cmnd *);
-#ifdef DEBUG
-	int to;
-#endif
-
 #if 0
 	del_timer(&timeout[indx]);
 #endif
@@ -599,59 +737,219 @@
 		printk("scsi_debug_intr_handle: Unexpected interrupt\n");
 		return;
 	}
-#ifdef DEBUG
+#if 0
 	printk("In intr_handle...");
 	printk("...done %d %x %d %d\n", i, my_done, to, jiffies);
 	printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done);
 #endif
 
 	my_done(SCtmp);
-#ifdef DEBUG
+#if 0
 	printk("Called done.\n");
 #endif
 }
 
+static int initialized = 0;
+
+static int do_init(void)
+{
+	int sz;
+
+	starts[3] = CAPACITY;
+	sz = sizeof(Sd_store_elem) * STORE_ELEMENTS;
+	store_arr = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == store_arr)
+		return 1;
+	memset(store_arr, 0, sz);
+
+	sz = sizeof(done_fct_t) * SCSI_DEBUG_MAILBOXES;
+	do_done = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == do_done)
+		goto out;
+	memset((void *)do_done, 0, sz);
+
+	sz = sizeof(struct timer_list) * SCSI_DEBUG_MAILBOXES;
+	timeout = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == timeout)
+		goto out;
+	memset(timeout, 0, sz);
+
+	sz = sizeof(Scsi_Cmnd *) * SCSI_DEBUG_MAILBOXES;
+	SCint = kmalloc(sz, GFP_ATOMIC);
+	if (NULL == SCint)
+		goto out;
+	memset(SCint, 0, sz);
+
+	return 0;
+
+out:
+	if (store_arr)
+		kfree(store_arr);
+	if (do_done)
+		kfree((void *)do_done);
+	if (timeout)
+		kfree(timeout);
+	if (SCint)
+		kfree(SCint);
+	return 1;
+}
+
+static void do_end(void)
+{
+	kfree(SCint);
+	kfree(timeout);
+	kfree((void *)do_done);
+	kfree(store_arr);
+}
+
 
 int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
-	int i;
+	int k, num, sz;
+
+	if (0 == initialized) {
+		++initialized;
+		sz = sizeof(Sdebug_dev_info) * scsi_debug_num_devs;
+		devInfop = kmalloc(sz, GFP_ATOMIC);
+		if (NULL == devInfop) {
+			printk("scsi_debug_detect: out of memory, 0.5\n");
+			return 0;
+		}
+		memset(devInfop, 0, sz);
+		if (do_init()) {
+			printk("scsi_debug_detect: out of memory, 0\n");
+			return 0;
+		}
+		for (k = 0; k < STORE_ELEMENTS; ++k) {
+			store_arr[k].p = (unsigned char *)
+				__get_free_pages(GFP_ATOMIC, STORE_ELEM_ORDER);
+			if (0 == store_arr[k].p)
+				goto detect_err;
+			memset(store_arr[k].p, 0, STORE_ELEM_SIZE);
+		}
+		for (k = 0; k < NUM_SENSE_BUFFS; ++k)
+			sense_buffers[k][0] = 0x70;
+		for (k = 0; k < NR_HOSTS_PRESENT; k++) {
+			tpnt->proc_name = "scsi_debug";	/* In the loop??? */
+			scsi_register(tpnt, 0);
+		}
+		return NR_HOSTS_PRESENT;
+	}
+	else {
+		printk("scsi_debug_detect: called again\n");
+		return 0;
+	}
 
-	for (i = 0; i < NR_HOSTS_PRESENT; i++) {
-		tpnt->proc_name = "scsi_debug";	/* Huh? In the loop??? */
-		scsi_register(tpnt, 0);
+detect_err:
+	num = k;
+	for (k = 0; k < STORE_ELEMENTS; ++k) {
+		if (0 != store_arr[k].p) {
+			free_pages((unsigned long)store_arr[k].p, 
+				   STORE_ELEM_ORDER);
+			store_arr[k].p = NULL;
+		}
 	}
-	return NR_HOSTS_PRESENT;
+	printk("scsi_debug_detect: out of memory: %d out of %d bytes\n",
+	       (int)(num * STORE_ELEM_SIZE), 
+	       (int)(scsi_debug_dev_size_mb * 1024 * 1024));
+	return 0;
+}
+
+
+static int num_releases = 0;
+
+int scsi_debug_release(struct Scsi_Host * hpnt)
+{
+	int k;
+	
+	scsi_unregister(hpnt);
+	if (++num_releases != NR_HOSTS_PRESENT)
+		return 0;
+
+	for (k = 0; k < STORE_ELEMENTS; ++k) {
+		if (0 != store_arr[k].p) {
+			free_pages((unsigned long)store_arr[k].p, 
+				   STORE_ELEM_ORDER);
+			store_arr[k].p = NULL;
+		}
+	}
+	do_end();
+	kfree(devInfop);
+	return 0;
+}
+
+static Sdebug_dev_info * devInfoReg(Scsi_Device * sdp)
+{
+	int k;
+	unsigned short host_no, id;
+	Sdebug_dev_info * devip;
+
+	host_no = sdp->host->host_no;
+	id = (unsigned short)sdp->id;
+	for (k = 0; k < scsi_debug_num_devs; ++k) {
+		devip = &devInfop[k];
+		if (devip->sdp && (host_no == devip->host_no) &&
+		    (id == devip->id)) {
+			devip->sdp = sdp; /* overwrite previous sdp */
+			return devip;
+		}
+		if (NULL == devip->sdp) {
+			devip->sdp = sdp;
+			devip->host_no = host_no;
+			devip->id = id;
+			devip->reset = 1;
+			devip->sb_index = 0;
+			return devip;
+		}
+	}
+	return NULL;
+}
+
+static void mk_sense_buffer(Sdebug_dev_info * devip, int index, int key, 
+			    int asc, int asq, int inbandLen)
+{
+	char * sbuff;
+	if ((index < 0) || (index >= NUM_SENSE_BUFFS))
+		return;
+	if (devip)
+		devip->sb_index = index;
+	sbuff = &sense_buffers[index][0];
+	memset(sbuff, 0, SENSE_BUFF_LEN);
+	sbuff[0] = 0x70;
+	sbuff[2] = key;
+	sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;
+	sbuff[12] = asc;
+	sbuff[13] = asq;
 }
 
 int scsi_debug_abort(Scsi_Cmnd * SCpnt)
 {
-#if 0
+#if 1
+	++num_aborts;
+	return SUCCESS;
+#else
 	int j;
 	void (*my_done) (Scsi_Cmnd *);
-	unsigned long flags;
-#endif
-
-	DEB(printk("scsi_debug_abort\n"));
-#if 0
+	unsigned long iflags;
 	SCpnt->result = SCpnt->abort_reason << 16;
 	for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
 		if (SCpnt == SCint[j]) {
 			my_done = do_done[j];
 			my_done(SCpnt);
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&mailbox_lock, iflags);
 			timeout[j] = 0;
 			SCint[j] = NULL;
 			do_done[j] = NULL;
-			restore_flags(flags);
-		};
-	};
-#endif
+			spin_unlock_irqrestore(&mailbox_lock, iflags);
+		}
+	}
 	return SCSI_ABORT_SNOOZE;
+#endif
 }
 
 int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
 {
+	/* int size = disk->capacity; */
 	info[0] = N_HEAD;
 	info[1] = N_SECTOR;
 	info[2] = N_CYLINDER;
@@ -660,35 +958,130 @@
 	return 0;
 }
 
+#if 0
 int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
 {
 	int i;
-	unsigned long flags;
+	unsigned long iflags;
 
 	void (*my_done) (Scsi_Cmnd *);
 	printk("Bus unlocked by reset - %d\n", why);
 	scsi_debug_lockup = 0;
-	DEB(printk("scsi_debug_reset called\n"));
 	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
 		if (SCint[i] == NULL)
 			continue;
 		SCint[i]->result = DID_RESET << 16;
 		my_done = do_done[i];
 		my_done(SCint[i]);
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&mailbox_lock, iflags);
 		SCint[i] = NULL;
 		do_done[i] = NULL;
 		timeout[i].function = NULL;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&mailbox_lock, iflags);
 	}
 	return SCSI_RESET_SUCCESS;
 }
+#endif
+
+int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
+{
+	Scsi_Device * sdp;
+	int k;
+
+	++num_dev_resets;
+	if (SCpnt && ((sdp = SCpnt->device))) {
+		for (k = 0; k < scsi_debug_num_devs; ++k) {
+			if (sdp->hostdata == (devInfop + k))
+				break;
+		}
+		if (k < scsi_debug_num_devs)
+			devInfop[k].reset = 1;
+	}
+	return SUCCESS;
+}
 
-const char *scsi_debug_info(void)
+int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
 {
-	static char buffer[] = " ";	/* looks nicer without anything here */
-	return buffer;
+	Scsi_Device * sdp;
+	struct Scsi_Host * hp;
+	int k;
+
+	++num_bus_resets;
+	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
+		for (k = 0; k < scsi_debug_num_devs; ++k) {
+			if (hp == devInfop[k].sdp->host)
+				devInfop[k].reset = 1;
+		}
+	}
+	return SUCCESS;
+}
+
+int scsi_debug_host_reset(Scsi_Cmnd * SCpnt)
+{
+	int k;
+
+	++num_host_resets;
+	for (k = 0; k < scsi_debug_num_devs; ++k)
+		devInfop[k].reset = 1;
+
+	return SUCCESS;
+}
+
+#ifndef MODULE
+static int __init scsi_debug_num_devs_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_num_devs = tmp;
+        return 1;
+    } else {
+        printk("scsi_debug_num_devs: usage scsi_debug_num_devs=<n> "
+               "(<n> can be from 1 to around 2000)\n");
+        return 0;
+    }
+}
+
+__setup("scsi_debug_num_devs=", scsi_debug_num_devs_setup);
+
+static int __init scsi_debug_dev_size_mb_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_dev_size_mb = tmp;
+        return 1;
+    } else {
+        printk("scsi_debug_dev_size_mb: usage scsi_debug_dev_size_mb=<n>\n"
+               "    (<n> is number of MB ram shared by all devs\n");
+        return 0;
+    }
+}
+
+__setup("scsi_debug_dev_size_mb=", scsi_debug_dev_size_mb_setup);
+#endif
+
+MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
+MODULE_DESCRIPTION("SCSI debug adapter driver");
+MODULE_PARM(scsi_debug_num_devs, "i");
+MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");
+MODULE_PARM(scsi_debug_dev_size_mb, "i");
+MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
+
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+static char sdebug_info[256];
+
+const char * scsi_debug_info(struct Scsi_Host * shp)
+{
+	sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, "
+		"dev_size_mb=%d\n", scsi_debug_version_str,
+		scsi_debug_num_devs, scsi_debug_dev_size_mb);
+	return sdebug_info;
 }
 
 /* scsi_debug_proc_info
@@ -738,10 +1131,20 @@
 
 	}
 	begin = 0;
-	pos = len = sprintf(buffer,
-	"This driver is not a real scsi driver, but it plays one on TV.\n"
+	pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
+	    "num_devs=%d, shared (ram) size=%d MB, sector_size=%d bytes\n" 
+	    "cylinders=%d, heads=%d, sectors=%d\n"
+	    "number of aborts=%d, device_reset=%d, bus_resets=%d, " 
+	    "host_resets=%d\n",
+	    scsi_debug_version_str, scsi_debug_num_devs, 
+	    scsi_debug_dev_size_mb, SECT_SIZE,
+	    N_CYLINDER, N_HEAD, N_SECTOR,
+	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
+#if 0
+	 "This driver is not a real scsi driver, but it plays one on TV.\n"
 	 "It is very handy for debugging specific problems because you\n"
 			 "can simulate a variety of error conditions\n");
+#endif
 	if (pos < offset) {
 		len = 0;
 		begin = pos;
@@ -754,44 +1157,8 @@
 	return (len);
 }
 
-#ifdef CONFIG_USER_DEBUG
-/*
- * This is a hack for the user space emulator.  It allows us to
- * "insert" arbitrary numbers of additional drivers.
- */
-void *scsi_debug_get_handle(void)
-{
-	static Scsi_Host_Template driver_copy = SCSI_DEBUG;
-	void *rtn;
-	rtn = kmalloc(sizeof(driver_copy), GFP_ATOMIC);
-	if(rtn==NULL)
-		return NULL;
-	memcpy(rtn, (void *) &driver_copy, sizeof(driver_copy));
-	return rtn;
-}
-#endif
-
 /* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SCSI_DEBUG;
+static Scsi_Host_Template driver_template = SCSI_DEBUG_TEMPLATE;
 
 #include "scsi_module.c"
 
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
-MODULE_LICENSE("GPL");
diff -u --recursive --new-file pre1/linux/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h
--- pre1/linux/drivers/scsi/scsi_debug.h	Wed Nov 28 10:22:27 2001
+++ linux/drivers/scsi/scsi_debug.h	Thu Jan 17 13:59:33 2002
@@ -8,34 +8,41 @@
 int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int scsi_debug_abort(Scsi_Cmnd *);
 int scsi_debug_biosparam(Disk *, kdev_t, int[]);
-int scsi_debug_reset(Scsi_Cmnd *, unsigned int);
+int scsi_debug_bus_reset(Scsi_Cmnd *);
+int scsi_debug_dev_reset(Scsi_Cmnd *);
+int scsi_debug_host_reset(Scsi_Cmnd *);
 int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
+const char * scsi_debug_info(struct Scsi_Host *);
 
 #ifndef NULL
 #define NULL 0
 #endif
 
-
-#define SCSI_DEBUG_MAILBOXES 1
-
 /*
- * Allow the driver to reject commands.  Thus we accept only one, but
- * and the mid-level will queue the remainder.
+ * This driver is written for the lk 2.5 series
  */
 #define SCSI_DEBUG_CANQUEUE  255
 
-#define SCSI_DEBUG {proc_info:         scsi_debug_proc_info,	\
+#define SCSI_DEBUG_MAX_CMD_LEN 16
+
+#define SCSI_DEBUG_TEMPLATE \
+		   {proc_info:         scsi_debug_proc_info,	\
 		    name:              "SCSI DEBUG",		\
+		    info:              scsi_debug_info,		\
 		    detect:            scsi_debug_detect,	\
+		    release:           scsi_debug_release,	\
 		    queuecommand:      scsi_debug_queuecommand, \
-		    abort:             scsi_debug_abort,	\
-		    reset:             scsi_debug_reset,	\
+		    eh_abort_handler:  scsi_debug_abort,	\
+		    eh_bus_reset_handler: scsi_debug_bus_reset,	\
+		    eh_device_reset_handler: scsi_debug_device_reset,	\
+		    eh_host_reset_handler: scsi_debug_host_reset,	\
 		    bios_param:        scsi_debug_biosparam,	\
 		    can_queue:         SCSI_DEBUG_CANQUEUE,	\
 		    this_id:           7,			\
-		    sg_tablesize:      16,			\
+		    sg_tablesize:      64,			\
 		    cmd_per_lun:       3,			\
 		    unchecked_isa_dma: 0,			\
 		    use_clustering:    ENABLE_CLUSTERING,	\
 }
+
 #endif
diff -u --recursive --new-file pre1/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- pre1/linux/drivers/scsi/sg.c	Thu Jan  3 11:35:33 2002
+++ linux/drivers/scsi/sg.c	Thu Jan 17 13:59:33 2002
@@ -19,9 +19,9 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_PROC_FS
- static char sg_version_str[] = "Version: 3.1.20 (20010814)";
+ static char sg_version_str[] = "Version: 3.5.23 (20020103)";
 #endif
- static int sg_version_num = 30120; /* 2 digits for each component */
+ static int sg_version_num = 30523; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -76,12 +76,18 @@
 #include <linux/version.h>
 #endif /* LINUX_VERSION_CODE */
 
+#define SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
+
 #define SG_ALLOW_DIO_DEF 0
 #define SG_ALLOW_DIO_CODE	/* compile out be commenting this define */
 #ifdef SG_ALLOW_DIO_CODE
 #include <linux/iobuf.h>
 #endif
 
+#define SG_NEW_KIOVEC 0	/* use alloc_kiovec(), not alloc_kiovec_sz() */
+
+#define SG_MAX_DEVS_MASK ((1U << KDEV_MINOR_BITS) - 1)
+
 int sg_big_buff = SG_DEF_RESERVED_SIZE;
 /* N.B. This variable is readable and writeable via
    /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
@@ -95,14 +101,8 @@
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
 
-#define SG_LOW_POOL_THRESHHOLD 30
-#define SG_MAX_POOL_SECTORS 320  /* Max. number of pool sectors to take */
-
-static int sg_pool_secs_avail = SG_MAX_POOL_SECTORS;
-
 #define SG_HEAP_PAGE 1  /* heap from kernel via get_free_pages() */
 #define SG_HEAP_KMAL 2  /* heap from kernel via kmalloc() */
-#define SG_HEAP_POOL 3  /* heap from scsi dma pool (mid-level) */
 #define SG_USER_MEM 4   /* memory belongs to user space */
 
 #define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */
@@ -136,10 +136,10 @@
 typedef struct sg_scatter_hold  /* holding area for scsi scatter gather info */
 {
     unsigned short k_use_sg;    /* Count of kernel scatter-gather pieces */
-    unsigned short sglist_len;  /* size of malloc'd scatter-gather list */
+    unsigned short sglist_len;  /* size of malloc'd scatter-gather list ++ */
     unsigned bufflen;           /* Size of (aggregate) data buffer */
     unsigned b_malloc_len;      /* actual len malloc'ed in buffer */
-    void * buffer;              /* Data buffer or scatter list,12 bytes each*/
+    void * buffer;              /* Data buffer or scatter list + mem_src_arr */
     struct kiobuf * kiobp;      /* for direct IO information */
     char mapped;                /* indicates kiobp has locked pages */
     char buffer_mem_src;        /* heap whereabouts of 'buffer' */
@@ -182,6 +182,7 @@
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
     char next_cmd_len;  /* 0 -> automatic (def), >0 -> use on next write() */
     char keep_orphan;   /* 0 -> drop orphan (def), 1 -> keep for read() */
+    char mmap_called;   /* 0 -> mmap() never called on this fd */
 } Sg_fd; /* 2760 bytes long on i386 */
 
 typedef struct sg_device /* holds the state of each scsi generic device */
@@ -203,7 +204,8 @@
 static int sg_start_req(Sg_request * srp);
 static void sg_finish_rem_req(Sg_request * srp);
 static int sg_build_indi(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp);
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+			 int tablesize);
 static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count,
 			   Sg_request * srp);
 static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count,
@@ -233,13 +235,15 @@
 static Sg_request * sg_add_request(Sg_fd * sfp);
 static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
 static int sg_res_in_use(Sg_fd * sfp);
-static void sg_clr_srpnt(Scsi_Request * SRpnt);
 static int sg_ms_to_jif(unsigned int msecs);
-static unsigned sg_jif_to_ms(int jifs);
+static inline unsigned sg_jif_to_ms(int jifs);
 static int sg_allow_access(unsigned char opcode, char dev_type);
 static int sg_build_dir(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also);
 static Sg_device * sg_get_dev(int dev);
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp);
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp);
 #ifdef CONFIG_PROC_FS
 static int sg_last_dev(void);
 #endif
@@ -337,9 +341,8 @@
     Sg_device * sdp;
     Sg_fd * sfp;
 
-    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) {
+    if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp)))
         return -ENXIO;
-    }
     SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", minor(sdp->i_rdev)));
     sg_fasync(-1, filp, 0);   /* remove filp from async notification list */
     if (0 == sg_remove_sfp(sdp, sfp)) { /* Returns 1 when sdp gone */
@@ -615,6 +618,20 @@
 	sg_remove_request(sfp, srp);
 	return -ENOSYS;
     }
+    if (hp->flags & SG_FLAG_MMAP_IO) {
+    	if (hp->dxfer_len > sfp->reserve.bufflen) {
+	    sg_remove_request(sfp, srp);
+	    return -ENOMEM;	/* MMAP_IO size must fit in reserve buffer */
+	}
+	if (hp->flags & SG_FLAG_DIRECT_IO) {
+	    sg_remove_request(sfp, srp);
+	    return -EINVAL;	/* either MMAP_IO or DIRECT_IO (not both) */
+	}
+	if (sg_res_in_use(sfp)) {
+	    sg_remove_request(sfp, srp);
+	    return -EBUSY;	/* reserve buffer already being used */
+	}
+    }
     timeout = sg_ms_to_jif(srp->header.timeout);
     if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) {
 	sg_remove_request(sfp, srp);
@@ -681,7 +698,6 @@
     srp->my_cmdp = SRpnt;
     q = &SRpnt->sr_device->request_queue;
     SRpnt->sr_request.rq_dev = sdp->i_rdev;
-    SRpnt->sr_request.rq_status = RQ_ACTIVE;
     SRpnt->sr_sense_buffer[0] = 0;
     SRpnt->sr_cmd_len = hp->cmd_len;
     if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) {
@@ -849,7 +865,7 @@
         result = get_user(val, (int *)arg);
         if (result) return result;
         if (val != sfp->reserve.bufflen) {
-            if (sg_res_in_use(sfp))
+            if (sg_res_in_use(sfp) || sfp->mmap_called)
                 return -EBUSY;
             sg_remove_scat(&sfp->reserve);
             sg_build_reserve(sfp, val);
@@ -1030,6 +1046,146 @@
     return (retval < 0) ? retval : 0;
 }
 
+static inline unsigned char * sg_scatg2virt(const struct scatterlist * sclp)
+{
+    return (sclp && sclp->page) ? 
+    		(unsigned char *)page_address(sclp->page) + sclp->offset :
+		NULL;
+}
+
+static void sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish)
+{
+    void * page_ptr;
+    struct page * page;
+    int k, m;
+
+    SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, "
+			   "scatg=%d\n", startFinish, rsv_schp->k_use_sg)); 
+    /* N.B. correction _not_ applied to base page of aech allocation */
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+        struct scatterlist * sclp = rsv_schp->buffer;
+
+        for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
+	    for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) {
+		page_ptr = sg_scatg2virt(sclp) + m;
+		page = virt_to_page(page_ptr);
+		if (startFinish)
+		    get_page(page);	/* increment page count */
+		else {
+		    if (page_count(page) > 0)
+			put_page_testzero(page); /* decrement page count */
+		}
+	    }
+        }
+    }
+    else { /* reserve buffer is just a single allocation */
+	for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) {
+	    page_ptr = (unsigned char *)rsv_schp->buffer + m;
+	    page = virt_to_page(page_ptr);
+	    if (startFinish)
+		get_page(page);	/* increment page count */
+	    else {
+		if (page_count(page) > 0)
+		    put_page_testzero(page); /* decrement page count */
+	    }
+	}
+    }
+}
+
+static struct page * sg_vma_nopage(struct vm_area_struct *vma, 
+				   unsigned long addr, int unused)
+{
+    Sg_fd * sfp;
+    struct page * page = NOPAGE_SIGBUS;
+    void * page_ptr = NULL;
+    unsigned long offset;
+    Sg_scatter_hold * rsv_schp;
+
+    if ((NULL == vma) || (! (sfp = (Sg_fd *)vma->vm_private_data)))
+	return page;
+    rsv_schp = &sfp->reserve;
+    offset = addr - vma->vm_start;
+    if (offset >= rsv_schp->bufflen)
+	return page;
+    SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n", 
+			       offset, rsv_schp->k_use_sg));
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+        int k;
+        unsigned long sa = vma->vm_start;
+        unsigned long len;
+        struct scatterlist * sclp = rsv_schp->buffer;
+
+        for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+             ++k, ++sclp) {
+            len = vma->vm_end - sa;
+            len = (len < sclp->length) ? len : sclp->length;
+	    if (offset < len) {
+		page_ptr = sg_scatg2virt(sclp) + offset;
+		page = virt_to_page(page_ptr);
+		get_page(page);	/* increment page count */
+		break;
+	    }
+            sa += len;
+	    offset -= len;
+        }
+    }
+    else { /* reserve buffer is just a single allocation */
+        page_ptr = (unsigned char *)rsv_schp->buffer + offset;
+	page = virt_to_page(page_ptr);
+	get_page(page);	/* increment page count */
+    }
+    return page;
+}
+
+static struct vm_operations_struct sg_mmap_vm_ops = {
+    nopage : sg_vma_nopage,
+};
+
+static int sg_mmap(struct file * filp, struct vm_area_struct *vma)
+{
+    Sg_fd * sfp;
+    unsigned long req_sz = vma->vm_end - vma->vm_start;
+    Sg_scatter_hold * rsv_schp;
+
+    if ((! filp) || (! vma) || (! (sfp = (Sg_fd *)filp->private_data)))
+        return -ENXIO;
+    SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", 
+			       (void *)vma->vm_start, (int)req_sz));
+    if (vma->vm_pgoff)
+    	return -EINVAL;		/* want no offset */
+    rsv_schp = &sfp->reserve;
+    if (req_sz > rsv_schp->bufflen)
+    	return -ENOMEM;		/* cannot map more than reserved buffer */
+
+    if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+    	int k;
+	unsigned long sa = vma->vm_start;
+	unsigned long len;
+	struct scatterlist * sclp = rsv_schp->buffer;
+
+	for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end); 
+	     ++k, ++sclp) {
+	    if (0 != sclp->offset)
+	    	return -EFAULT;     /* non page aligned memory ?? */
+	    len = vma->vm_end - sa;
+	    len = (len < sclp->length) ? len : sclp->length;
+	    sa += len;
+	}
+    }
+    else { /* reserve buffer is just a single allocation */
+    	if ((unsigned long)rsv_schp->buffer & (PAGE_SIZE - 1))
+	    return -EFAULT;	/* non page aligned memory ?? */
+    }
+    if (0 == sfp->mmap_called) {
+    	sg_rb_correct4mmap(rsv_schp, 1);  /* do only once per fd lifetime */
+	sfp->mmap_called = 1;
+    }
+    vma->vm_flags |= (VM_RESERVED | VM_IO);
+    vma->vm_private_data = sfp;
+    vma->vm_ops = &sg_mmap_vm_ops;
+    return 0;
+}
+
 /* This function is a "bottom half" handler that is called by the
  * mid level when a command is completed (or has failed). */
 static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt)
@@ -1076,7 +1232,14 @@
     srp->data.sglist_len = SRpnt->sr_sglist_len;
     srp->data.bufflen = SRpnt->sr_bufflen;
     srp->data.buffer = SRpnt->sr_buffer;
-    sg_clr_srpnt(SRpnt);
+    /* now clear out request structure */
+    SRpnt->sr_use_sg = 0;
+    SRpnt->sr_sglist_len = 0;
+    SRpnt->sr_bufflen = 0;
+    SRpnt->sr_buffer = NULL;
+    SRpnt->sr_underflow = 0;
+    SRpnt->sr_request.rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ request blk */
+
     srp->my_cmdp = NULL;
     srp->done = 1;
     read_unlock(&sg_dev_arr_lock);
@@ -1121,14 +1284,15 @@
 	if (NULL == sfp->headrp) {
             SCSI_LOG_TIMEOUT(1,
 		printk("sg...bh: already closed, final cleanup\n"));
-            sg_remove_sfp(sdp, sfp);
+            if (0 == sg_remove_sfp(sdp, sfp)) { /* device still present */
+		sdp->device->access_count--;
+		if (sdp->device->host->hostt->module)
+		    __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
+	    }
+	    if (sg_template.module)
+		    __MOD_DEC_USE_COUNT(sg_template.module);
 	    sfp = NULL;
         }
-	sdp->device->access_count--;
-	if (sg_template.module)
-		__MOD_DEC_USE_COUNT(sg_template.module);
-	if (sdp->device->host->hostt->module)
-	    __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module);
     }
     else if (srp && srp->orphan) {
 	if (sfp->keep_orphan)
@@ -1152,6 +1316,7 @@
 	poll:		sg_poll,
 	ioctl:		sg_ioctl,
 	open:		sg_open,
+	mmap:		sg_mmap,
 	release:	sg_release,
 	fasync:		sg_fasync,
 };
@@ -1176,7 +1341,7 @@
     if(!sg_registered) {
 	if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
         {
-            printk("Unable to get major %d for generic SCSI device\n",
+            printk(KERN_ERR "Unable to get major %d for generic SCSI device\n",
                    SCSI_GENERIC_MAJOR);
 	    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
             return 1;
@@ -1189,7 +1354,7 @@
     sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * 
     					sizeof(Sg_device *), GFP_ATOMIC);
     if (NULL == sg_dev_arr) {
-        printk("sg_init: no space for sg_dev_arr\n");
+        printk(KERN_ERR "sg_init: no space for sg_dev_arr\n");
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
         return 1;
     }
@@ -1212,8 +1377,8 @@
 	    sg_big_buff = tmp;
 	return 1;
     } else {
-	printk("sg_def_reserved_size : usage sg_def_reserved_size=n "
-	       "(n could be 65536, 131072 or 262144)\n");
+	printk(KERN_WARNING "sg_def_reserved_size : usage "
+	    "sg_def_reserved_size=n (n could be 65536, 131072 or 262144)\n");
 	return 0;
     }
 }
@@ -1238,7 +1403,7 @@
 	if (NULL == tmp_da) {
 	    scsidp->attached--;
 	    write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	    printk("sg_attach: device array cannot be resized\n");
+	    printk(KERN_ERR "sg_attach: device array cannot be resized\n");
 	    return 1;
 	}
 	memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
@@ -1250,13 +1415,13 @@
 
     for(k = 0; k < sg_template.dev_max; k++)
         if(! sg_dev_arr[k]) break;
-    if (k > MINORMASK) {
+    if (k > SG_MAX_DEVS_MASK) {
 	scsidp->attached--;
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	printk("Unable to attach sg device <%d, %d, %d, %d>"
+	printk(KERN_WARNING "Unable to attach sg device <%d, %d, %d, %d>"
 	       " type=%d, minor number exceed %d\n", scsidp->host->host_no, 
 	       scsidp->channel, scsidp->id, scsidp->lun, scsidp->type,
-	       MINORMASK);
+	       SG_MAX_DEVS_MASK);
 	return 1;
     }
     if(k < sg_template.dev_max)
@@ -1266,7 +1431,7 @@
     if (NULL == sdp) {
 	scsidp->attached--;
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-	printk("sg_attach: Sg_device cannot be allocated\n");
+	printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
 	return 1;
     }
 
@@ -1293,8 +1458,8 @@
 	case TYPE_WORM:
 	case TYPE_TAPE: break;
 	default:
-	    printk("Attached scsi generic sg%d at scsi%d, channel %d, id %d,"
-		   " lun %d,  type %d\n", k, scsidp->host->host_no, 
+	    printk(KERN_NOTICE "Attached scsi generic sg%d at scsi%d, channel"
+	    	   " %d, id %d, lun %d,  type %d\n", k, scsidp->host->host_no, 
 		   scsidp->channel, scsidp->id, scsidp->lun, scsidp->type);
     }
     return 0;
@@ -1371,7 +1536,10 @@
 
 MODULE_AUTHOR("Douglas Gilbert");
 MODULE_DESCRIPTION("SCSI generic (sg) driver");
+
+#ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
+#endif
 
 MODULE_PARM(def_reserved_size, "i");
 MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
@@ -1417,9 +1585,8 @@
 	if (res <= 0)   /* -ve -> error, 0 -> done, 1 -> try indirect */
 	    return res;
     }
-    if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen)) {
+    if ((! sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
 	sg_link_reserve(sfp, srp, dxfer_len);
-    }
     else {
 	res = sg_build_indi(req_schp, sfp, dxfer_len);
         if (res) {
@@ -1445,23 +1612,24 @@
     sg_remove_request(sfp, srp);
 }
 
-static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp)
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+			 int tablesize)
 {
     int mem_src, ret_sz;
-    int sg_bufflen = PAGE_SIZE;
     int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    int mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+    /* scatter gather array, followed by mem_src_arr (array of chars) */
+    int sg_bufflen = tablesize * elem_sz;
+    int mx_sc_elems = tablesize;
 
     mem_src = SG_HEAP_KMAL;
-    schp->buffer = (struct scatterlist *)sg_malloc(sfp, sg_bufflen,
-						   &ret_sz, &mem_src);
-    schp->buffer_mem_src = (char)mem_src;
+    schp->buffer = sg_malloc(sfp, sg_bufflen, &ret_sz, &mem_src);
     if (! schp->buffer)
 	return -ENOMEM;
     else if (ret_sz != sg_bufflen) {
 	sg_bufflen = ret_sz;
-	mx_sc_elems = (sg_bufflen / elem_sz) - 1;
+	mx_sc_elems = sg_bufflen / elem_sz;
     }
+    schp->buffer_mem_src = (char)mem_src;
     schp->sglist_len = sg_bufflen;
     memset(schp->buffer, 0, sg_bufflen);
     return mx_sc_elems; /* number of scat_gath elements allocated */
@@ -1470,13 +1638,15 @@
 static void sg_unmap_and(Sg_scatter_hold * schp, int free_also)
 {
 #ifdef SG_ALLOW_DIO_CODE
+    int nbhs = 0;
+
     if (schp && schp->kiobp) {
 	if (schp->mapped) {
 	    unmap_kiobuf(schp->kiobp);
 	    schp->mapped = 0;
 	}
 	if (free_also) {
-	    free_kiovec(1, &schp->kiobp);
+	    sg_free_kiovec(1, &schp->kiobp, &nbhs);
 	    schp->kiobp = NULL;
 	}
     }
@@ -1494,10 +1664,12 @@
     sg_io_hdr_t * hp = &srp->header;
     Sg_scatter_hold * schp = &srp->data;
     int sg_tablesize = sfp->parentdp->sg_tablesize;
+    int nbhs = 0;
 
-    res = alloc_kiovec(1, &schp->kiobp);
+    res = sg_alloc_kiovec(1, &schp->kiobp, &nbhs);
     if (0 != res) {
-	SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: alloc_kiovec res=%d\n", res));
+	SCSI_LOG_TIMEOUT(5, printk("sg_build_dir: sg_alloc_kiovec res=%d\n", 
+			 res));
 	return 1;
     }
     res = map_user_kiobuf((SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0,
@@ -1527,7 +1699,7 @@
 	hp->info |= SG_INFO_DIRECT_IO;
 	return 0;
     }
-    mx_sc_elems = sg_build_sgat(schp, sfp);
+    mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
     if (mx_sc_elems <= 1) {
 	sg_unmap_and(schp, 1);
 	sg_remove_scat(schp);
@@ -1535,19 +1707,22 @@
     }
     mem_src_arr = schp->buffer + (mx_sc_elems * sizeof(struct scatterlist));
     for (k = 0, sclp = schp->buffer, rem_sz = dxfer_len;
-	 (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+	 (rem_sz > 0) && (k < mx_sc_elems);
 	 ++k, ++sclp) {
 	offset = (0 == k) ? kp->offset : 0;
 	num = (rem_sz > (PAGE_SIZE - offset)) ? (PAGE_SIZE - offset) :
 						rem_sz;
+	sclp->page = kp->maplist[k];
+	sclp->offset = offset;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
 	sclp->address = page_address(kp->maplist[k]) + offset;
-	sclp->page = NULL;
+#endif
 	sclp->length = num;
 	mem_src_arr[k] = SG_USER_MEM;
 	rem_sz -= num;
 	SCSI_LOG_TIMEOUT(5,
 	    printk("sg_build_dir: k=%d, a=0x%p, len=%d, ms=%d\n",
-	    k, sclp->address, num, mem_src_arr[k]));
+	    k, sg_scatg2virt(sclp), num, mem_src_arr[k]));
     }
     schp->k_use_sg = k;
     SCSI_LOG_TIMEOUT(5,
@@ -1569,7 +1744,7 @@
 {
     int ret_sz, mem_src;
     int blk_size = buff_size;
-    char * p = NULL;
+    unsigned char * p = NULL;
 
     if ((blk_size < 0) || (! sfp))
         return -EFAULT;
@@ -1609,14 +1784,14 @@
 	char * mem_src_arr;
 
         /* N.B. ret_sz and mem_src carried into this block ... */
-	mx_sc_elems = sg_build_sgat(schp, sfp);
+	mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
 	if (mx_sc_elems < 0)
 	    return mx_sc_elems; /* most likely -ENOMEM */
 	mem_src_arr = schp->buffer +
 		      (mx_sc_elems * sizeof(struct scatterlist));
 
 	for (k = 0, sclp = schp->buffer, rem_sz = blk_size;
-	     (k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
+	     (rem_sz > 0) && (k < mx_sc_elems);
              ++k, rem_sz -= ret_sz, ++sclp) {
 	    if (first)
                 first = 0;
@@ -1627,14 +1802,17 @@
                 if (! p)
                     break;
             }
+            sclp->page = virt_to_page(p);
+            sclp->offset = (unsigned long)p & ~PAGE_MASK;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
             sclp->address = p;
-	    sclp->page = NULL;
+#endif
             sclp->length = ret_sz;
 	    mem_src_arr[k] = mem_src;
 
 	    SCSI_LOG_TIMEOUT(5,
 		printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n",
-                k, sclp->address, ret_sz, mem_src));
+                k, sg_scatg2virt(sclp), ret_sz, mem_src));
         } /* end of for loop */
 	schp->k_use_sg = k;
 	SCSI_LOG_TIMEOUT(5,
@@ -1664,7 +1842,8 @@
 	if (schp->bufflen < num_xfer)
 	    num_xfer = schp->bufflen;
     }
-    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+    if ((num_xfer <= 0) || 
+    	(new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
 	return 0;
 
     SCSI_LOG_TIMEOUT(4,
@@ -1698,14 +1877,15 @@
 	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
 	ksglen = (int)sclp->length;
-	p = sclp->address;
+	p = sg_scatg2virt(sclp);
 
 	for (j = 0, k = 0; j < onum; ++j) {
 	    res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
 	    if (res) return res;
 
 	    for (; (k < schp->k_use_sg) && p;
-		 ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {
+		 ++k, ++sclp, ksglen = (int)sclp->length, 
+		 	p = sg_scatg2virt(sclp)) {
 		ok = (SG_USER_MEM != mem_src_arr[k]);
 		if (usglen <= 0)
 		    break;
@@ -1766,7 +1946,7 @@
 static char * sg_get_sgat_msa(Sg_scatter_hold * schp)
 {
     int elem_sz = sizeof(struct scatterlist) + sizeof(char);
-    int mx_sc_elems = (schp->sglist_len / elem_sz) - 1;
+    int mx_sc_elems = schp->sglist_len / elem_sz;
     return schp->buffer + (sizeof(struct scatterlist) * mx_sc_elems);
 }
 
@@ -1779,14 +1959,17 @@
         struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
 
-	for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {
+	for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
 	    mem_src = mem_src_arr[k];
 	    SCSI_LOG_TIMEOUT(5,
 		printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n",
-                       k, sclp->address, sclp->length, mem_src));
-            sg_free(sclp->address, sclp->length, mem_src);
-            sclp->address = NULL;
+                       k, sg_scatg2virt(sclp), sclp->length, mem_src));
+            sg_free(sg_scatg2virt(sclp), sclp->length, mem_src);
 	    sclp->page = NULL;
+            sclp->offset = 0;
+#ifdef SG_STILL_HAVE_ADDRESS_IN_SCATTERLIST
+	    sclp->address = 0;
+#endif
             sclp->length = 0;
         }
 	sg_free(schp->buffer, schp->sglist_len, schp->buffer_mem_src);
@@ -1814,7 +1997,8 @@
 	if (schp->bufflen < num_xfer)
 	    num_xfer = schp->bufflen;
     }
-    if ((num_xfer <= 0) || (new_interface && (SG_FLAG_NO_DXFER & hp->flags)))
+    if ((num_xfer <= 0) || 
+    	(new_interface && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
 	return 0;
 
     SCSI_LOG_TIMEOUT(4,
@@ -1848,14 +2032,15 @@
 	struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 	char * mem_src_arr = sg_get_sgat_msa(schp);
 	ksglen = (int)sclp->length;
-	p = sclp->address;
+	p = sg_scatg2virt(sclp);
 
 	for (j = 0, k = 0; j < onum; ++j) {
 	    res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
 	    if (res) return res;
 
 	    for (; (k < schp->k_use_sg) && p;
-		 ++k, ++sclp, ksglen = (int)sclp->length, p = sclp->address) {
+		 ++k, ++sclp, ksglen = (int)sclp->length, 
+		 	p = sg_scatg2virt(sclp)) {
 		ok = (SG_USER_MEM != mem_src_arr[k]);
 		if (usglen <= 0)
 		    break;
@@ -1896,14 +2081,14 @@
         int k, num;
         struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
 
-	for (k = 0; (k < schp->k_use_sg) && sclp->address; ++k, ++sclp) {
+	for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp); ++k, ++sclp) {
             num = (int)sclp->length;
             if (num > num_read_xfer) {
-                __copy_to_user(outp, sclp->address, num_read_xfer);
+                __copy_to_user(outp, sg_scatg2virt(sclp), num_read_xfer);
                 break;
             }
             else {
-                __copy_to_user(outp, sclp->address, num);
+                __copy_to_user(outp, sg_scatg2virt(sclp), num);
                 num_read_xfer -= num;
                 if (num_read_xfer <= 0)
                     break;
@@ -1949,7 +2134,7 @@
             if (rem <= num) {
 		if (0 == k) {
 		    req_schp->k_use_sg = 0;
-		    req_schp->buffer = sclp->address;
+		    req_schp->buffer = sg_scatg2virt(sclp);
 		}
 		else {
     		    sfp->save_scat_len = num;
@@ -2189,6 +2374,8 @@
     if (sfp->reserve.bufflen > 0) {
     SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
 	     (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg));
+	if (sfp->mmap_called)
+	    sg_rb_correct4mmap(&sfp->reserve, 0); /* undo correction */
 	sg_remove_scat(&sfp->reserve);
     }
     sfp->parentdp = NULL;
@@ -2237,7 +2424,7 @@
 	/* MOD_INC's to inhibit unloading sg and associated adapter driver */
 	if (sg_template.module)
 	    __MOD_INC_USE_COUNT(sg_template.module);
-	 if (sdp->device->host->hostt->module)
+	if (sdp->device->host->hostt->module)
 	    __MOD_INC_USE_COUNT(sdp->device->host->hostt->module);
         SCSI_LOG_TIMEOUT(1, printk(
           "sg_remove_sfp: worrisome, %d writes pending\n", dirty));
@@ -2270,30 +2457,6 @@
         if (resp && retSzp) *retSzp = rqSz;
         return resp;
     }
-    if (SG_HEAP_POOL == mem_src) {
-        int num_sect = rqSz / SG_SECTOR_SZ;
-
-        if (0 != (rqSz & SG_SECTOR_MSK)) {
-            if (! retSzp)
-                return resp;
-            ++num_sect;
-            rqSz = num_sect * SG_SECTOR_SZ;
-        }
-        while (num_sect > 0) {
-            if ((num_sect <= sg_pool_secs_avail)) {
-                resp = kmalloc(rqSz, page_mask);
-                if (resp) {
-                    if (retSzp) *retSzp = rqSz;
-                    sg_pool_secs_avail -= num_sect;
-                    return resp;
-                }
-            }
-            if (! retSzp)
-                return resp;
-            num_sect /= 2;      /* try half as many */
-            rqSz = num_sect * SG_SECTOR_SZ;
-        }
-    }
     else if (SG_HEAP_PAGE == mem_src) {
         int order, a_size;
         int resSz = rqSz;
@@ -2311,7 +2474,8 @@
         if (retSzp) *retSzp = resSz;
     }
     else
-        printk("sg_low_malloc: bad mem_src=%d, rqSz=%df\n", mem_src, rqSz);
+        printk(KERN_ERR "sg_low_malloc: bad mem_src=%d, rqSz=%df\n", 
+	       mem_src, rqSz);
     return resp;
 }
 
@@ -2330,29 +2494,20 @@
 	switch (*mem_srcp)
         {
         case SG_HEAP_PAGE:
-            l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE;
+            l_ms = (size < PAGE_SIZE) ? SG_HEAP_KMAL : SG_HEAP_PAGE;
             resp = sg_low_malloc(size, low_dma, l_ms, 0);
             if (resp)
                 break;
             resp = sg_low_malloc(size, low_dma, l_ms, &size);
             if (! resp) {
-                l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL;
+                l_ms = (SG_HEAP_KMAL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_KMAL;
                 resp = sg_low_malloc(size, low_dma, l_ms, &size);
-                if (! resp) {
-                    l_ms = SG_HEAP_KMAL;
-                    resp = sg_low_malloc(size, low_dma, l_ms, &size);
-                }
             }
             if (resp && retSzp) *retSzp = size;
             break;
         case SG_HEAP_KMAL:
-            l_ms = SG_HEAP_PAGE;
+            l_ms = SG_HEAP_KMAL; /* was SG_HEAP_PAGE */
             resp = sg_low_malloc(size, low_dma, l_ms, 0);
-            if (resp)
-                break;
-            l_ms = SG_HEAP_POOL;
-            resp = sg_low_malloc(size, low_dma, l_ms, &size);
-            if (resp && retSzp) *retSzp = size;
             break;
         default:
             SCSI_LOG_TIMEOUT(1, printk("sg_malloc: bad ms=%d\n", *mem_srcp));
@@ -2365,18 +2520,19 @@
     return resp;
 }
 
+static inline int sg_alloc_kiovec(int nr, struct kiobuf **bufp, int *szp)
+{
+#if SG_NEW_KIOVEC
+    return alloc_kiovec_sz(nr, bufp, szp);
+#else
+    return alloc_kiovec(nr, bufp);
+#endif
+}
+
 static void sg_low_free(char * buff, int size, int mem_src)
 {
     if (! buff) return;
     switch (mem_src) {
-    case SG_HEAP_POOL:
-	{
-	    int num_sect = size / SG_SECTOR_SZ;
-
-	    kfree(buff);
-	    sg_pool_secs_avail += num_sect;
-	}
-	break;
     case SG_HEAP_KMAL:
 	kfree(buff);    /* size not used */
 	break;
@@ -2392,7 +2548,7 @@
     case SG_USER_MEM:
 	break; /* nothing to do */
     default:
-	printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
+	printk(KERN_ERR "sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%d\n",
                mem_src, buff, size);
 	break;
     }
@@ -2408,14 +2564,13 @@
         sg_low_free(buff, size, mem_src);
 }
 
-static void sg_clr_srpnt(Scsi_Request * SRpnt)
+static inline void sg_free_kiovec(int nr, struct kiobuf **bufp, int *szp)
 {
-    SRpnt->sr_use_sg = 0;
-    SRpnt->sr_sglist_len = 0;
-    SRpnt->sr_bufflen = 0;
-    SRpnt->sr_buffer = NULL;
-    SRpnt->sr_underflow = 0;
-    SRpnt->sr_request.rq_dev = mk_kdev(0, 0);  /* "sg" _disowns_ command blk */
+#if SG_NEW_KIOVEC
+    free_kiovec_sz(nr, bufp, szp);
+#else
+    free_kiovec(nr, bufp);
+#endif
 }
 
 static int sg_ms_to_jif(unsigned int msecs)
@@ -2427,7 +2582,7 @@
 					       : (((int)msecs / 1000) * HZ);
 }
 
-static unsigned sg_jif_to_ms(int jifs)
+static inline unsigned sg_jif_to_ms(int jifs)
 {
     if (jifs <= 0)
 	return 0U;
@@ -2477,8 +2632,8 @@
     if (sg_dev_arr && (dev >= 0))
     {
 	read_lock_irqsave(&sg_dev_arr_lock, iflags);
-    if (dev < sg_template.dev_max)
-    	sdp = sg_dev_arr[dev];
+	if (dev < sg_template.dev_max)
+	    sdp = sg_dev_arr[dev];
 	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
     }
     return sdp;
@@ -2671,7 +2826,7 @@
 {
     Sg_device * sdp;
     const sg_io_hdr_t * hp;
-    int j, max_dev;
+    int j, max_dev, new_interface;
 
     if (NULL == sg_dev_arr) {
 	PRINT_PROC("sg_dev_arr NULL, driver not initialized\n");
@@ -2680,8 +2835,7 @@
     max_dev = sg_last_dev();
     PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
 	       sg_template.dev_max, max_dev);
-    PRINT_PROC(" sg_pool_secs_aval=%d def_reserved_size=%d\n",
-	       sg_pool_secs_avail, sg_big_buff);
+    PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
     for (j = 0; j < max_dev; ++j) {
 	if ((sdp = sg_get_dev(j))) {
 	    Sg_fd * fp;
@@ -2717,8 +2871,10 @@
 			   (int)fp->keep_orphan, (int)fp->closed);
 		for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) {
 		    hp = &srp->header;
+		    new_interface = (hp->interface_id == '\0') ? 0 : 1;
 /* stop indenting so far ... */
-	PRINT_PROC(srp->res_used ? "     rb>> " :
+	PRINT_PROC(srp->res_used ? ((new_interface && 
+	    (SG_FLAG_MMAP_IO & hp->flags)) ? "     mmap>> " : "     rb>> ") :
 	    ((SG_INFO_DIRECT_IO_MASK & hp->info) ? "     dio>> " : "     "));
 	blen = srp->my_cmdp ? srp->my_cmdp->sr_bufflen : srp->data.bufflen;
 	usg = srp->my_cmdp ? srp->my_cmdp->sr_use_sg : srp->data.k_use_sg;
@@ -2728,8 +2884,8 @@
 	if (srp->done)
 	    PRINT_PROC(" dur=%d", hp->duration);
 	else
-	    PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ?
-			sg_jif_to_ms(fp->timeout) : hp->timeout),
+	    PRINT_PROC(" t_o/elap=%d/%d", new_interface ? hp->timeout :
+			sg_jif_to_ms(fp->timeout),
 		  sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0));
 	PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode);
 /* reset indenting */
diff -u --recursive --new-file pre1/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- pre1/linux/drivers/scsi/sr.c	Thu Jan  3 11:35:33 2002
+++ linux/drivers/scsi/sr.c	Thu Jan 17 13:59:33 2002
@@ -331,7 +331,7 @@
 
 	SCSI_LOG_HLQUEUE(2, printk("sr%d : %s %d/%ld 512 byte blocks.\n",
                                    devm,
-		   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+		   (rq_data_dir(&SCpnt->request) == WRITE) ? "writing" : "reading",
 				 this_count, SCpnt->request.nr_sectors));
 
 	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?
diff -u --recursive --new-file pre1/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- pre1/linux/drivers/sound/via82cxxx_audio.c	Mon Dec 10 10:39:20 2001
+++ linux/drivers/sound/via82cxxx_audio.c	Tue Jan 15 13:53:51 2002
@@ -1995,7 +1995,7 @@
 	/* just to be a nice neighbor */
 	/* Thomas Sailer:
 	 * But also to ourselves, release semaphore if we do so */
-	if (current->need_resched) {
+	if (need_resched()) {
 		up(&card->syscall_sem);
 		schedule ();
 		ret = via_syscall_down (card, nonblock);
@@ -2171,7 +2171,7 @@
 	/* just to be a nice neighbor */
 	/* Thomas Sailer:
 	 * But also to ourselves, release semaphore if we do so */
-	if (current->need_resched) {
+	if (need_resched()) {
 		up(&card->syscall_sem);
 		schedule ();
 		ret = via_syscall_down (card, nonblock);
diff -u --recursive --new-file pre1/linux/drivers/tc/tc.c linux/drivers/tc/tc.c
--- pre1/linux/drivers/tc/tc.c	Thu Oct 11 09:43:30 2001
+++ linux/drivers/tc/tc.c	Thu Jan 17 14:21:16 2002
@@ -236,6 +236,8 @@
 	}
 }
 
+subsys_initcall(tc_init);
+
 EXPORT_SYMBOL(search_tc_card);
 EXPORT_SYMBOL(claim_tc_card);
 EXPORT_SYMBOL(release_tc_card);
diff -u --recursive --new-file pre1/linux/drivers/usb/hcd/ehci-hcd.c linux/drivers/usb/hcd/ehci-hcd.c
--- pre1/linux/drivers/usb/hcd/ehci-hcd.c	Mon Jan 14 10:10:43 2002
+++ linux/drivers/usb/hcd/ehci-hcd.c	Thu Jan 17 14:06:53 2002
@@ -70,9 +70,15 @@
  *	Brad Hards
  *	Rory Bolt
  *	...
+ *
+ * HISTORY:
+ * 2002-01-14	Minor cleanup; version synch.
+ * 2002-01-08	Fix roothub handoff of FS/LS to companion controllers.
+ * 2002-01-04	Control/Bulk queuing behaves.
+ * 2001-12-12	Initial patch version for Linux 2.5.1 kernel.
  */
 
-#define DRIVER_VERSION "$Revision: 0.25 $"
+#define DRIVER_VERSION "$Revision: 0.26 $"
 #define DRIVER_AUTHOR "David Brownell"
 #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
 
@@ -97,9 +103,6 @@
 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)
 
diff -u --recursive --new-file pre1/linux/drivers/usb/hcd/ehci-hub.c linux/drivers/usb/hcd/ehci-hub.c
--- pre1/linux/drivers/usb/hcd/ehci-hub.c	Tue Jan  1 13:52:10 2002
+++ linux/drivers/usb/hcd/ehci-hub.c	Thu Jan 17 14:06:53 2002
@@ -82,11 +82,12 @@
 	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]);
+			/* don't report this in GetPortStatus */
+			if (temp & PORT_CSC) {
+				temp &= ~PORT_CSC;
+				writel (temp, &ehci->regs->port_status [i]);
+			}
+			continue;
 		}
 		if (!(temp & PORT_CONNECT))
 			ehci->reset_done [i] = 0;
diff -u --recursive --new-file pre1/linux/drivers/usb/hcd/ehci-q.c linux/drivers/usb/hcd/ehci-q.c
--- pre1/linux/drivers/usb/hcd/ehci-q.c	Tue Jan  8 13:15:52 2002
+++ linux/drivers/usb/hcd/ehci-q.c	Thu Jan 17 14:06:53 2002
@@ -883,11 +883,10 @@
 		/* 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);
+				writel (cmd & ~CMD_ASE, &ehci->regs->command);
 			else {
 				ehci_ready (ehci);
-				while (!(readl (&ehci->regs->status) & STS_ASS))
+				while (readl (&ehci->regs->status) & STS_ASS)
 					udelay (100);
 			}
 		}
diff -u --recursive --new-file pre1/linux/drivers/usb/hcd/ehci-sched.c linux/drivers/usb/hcd/ehci-sched.c
--- pre1/linux/drivers/usb/hcd/ehci-sched.c	Mon Jan 14 10:10:43 2002
+++ linux/drivers/usb/hcd/ehci-sched.c	Thu Jan 17 14:06:53 2002
@@ -381,7 +381,7 @@
 			vdbg ("qh %p usecs %d period %d starting frame %d.%d",
 				qh, qh->usecs, period, frame, uframe);
 			do {
-				if (unlikely ((long)ehci->pshadow [frame].ptr)) {
+				if (unlikely (ehci->pshadow [frame].ptr != 0)) {
 // FIXME -- just link to the end, before any qh with a shorter period,
 // AND handle it already being (implicitly) linked into this frame
 					BUG ();
diff -u --recursive --new-file pre1/linux/drivers/usb/hcd.c linux/drivers/usb/hcd.c
--- pre1/linux/drivers/usb/hcd.c	Mon Jan 14 10:10:43 2002
+++ linux/drivers/usb/hcd.c	Thu Jan 17 14:06:53 2002
@@ -1081,20 +1081,20 @@
 	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.
+	 *
+	 * Caller guaranteed that the urb pointer hasn't been freed, and
+	 * that it was submitted.  But as a rule it can't know whether or
+	 * not it's already been unlinked ... so we respect the reversed
+	 * lock sequence needed for the usb_hcd_giveback_urb() code paths
+	 * (urb lock, then hcd_data_lock) in case some other CPU is now
+	 * unlinking it.
 	 */
 	spin_lock_irqsave (&urb->lock, flags);
-	if (!urb->hcpriv
-			|| urb->status != -EINPROGRESS
-			|| urb->transfer_flags & USB_TIMEOUT_KILLED) {
+	spin_lock (&hcd_data_lock);
+	if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) {
 		retval = -EINVAL;
 		goto done;
 	}
@@ -1103,6 +1103,8 @@
 		retval = -ENODEV;
 		goto done;
 	}
+
+	/* giveback clears dev; non-null means it's linked at this level */
 	dev = urb->dev->hcpriv;
 	hcd = urb->dev->bus->hcpriv;
 	if (!dev || !hcd) {
@@ -1110,6 +1112,27 @@
 		goto done;
 	}
 
+	/* For non-periodic transfers, any status except -EINPROGRESS means
+	 * the HCD has already started to unlink this URB from the hardware.
+	 * In that case, there's no more work to do.
+	 *
+	 * For periodic transfers, this is the only way to trigger unlinking
+	 * from the hardware.  Since we (currently) overload urb->status to
+	 * tell the driver to unlink, error status might get clobbered ...
+	 * unless that transfer hasn't yet restarted.  One such case is when
+	 * the URB gets unlinked from its completion handler.
+	 *
+	 * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
+	 */
+	switch (usb_pipetype (urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		if (urb->status != -EINPROGRESS) {
+			retval = 0;
+			goto done;
+		}
+	}
+
 	/* maybe set up to block on completion notification */
 	if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
 		urb->status = -ETIMEDOUT;
@@ -1130,6 +1153,7 @@
 		/* asynchronous unlink */
 		urb->status = -ECONNRESET;
 	}
+	spin_unlock (&hcd_data_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 
 	if (urb == (struct urb *) hcd->rh_timer.data) {
@@ -1154,6 +1178,7 @@
 	}
 	goto bye;
 done:
+	spin_unlock (&hcd_data_lock);
 	spin_unlock_irqrestore (&urb->lock, flags);
 bye:
 	if (retval)
diff -u --recursive --new-file pre1/linux/drivers/usb/hpusbscsi.c linux/drivers/usb/hpusbscsi.c
--- pre1/linux/drivers/usb/hpusbscsi.c	Tue Dec 25 17:04:40 2001
+++ linux/drivers/usb/hpusbscsi.c	Thu Jan 17 14:06:53 2002
@@ -272,7 +272,7 @@
 	if (!srb->bufflen) {
 		usb_callback = simple_command_callback;
 	} else {
-        	if (srb->use_sg) {
+        	if (likely(srb->use_sg)) {
 			usb_callback = scatter_gather_callback;
 			hpusbscsi->fragment = 0;
 		} else {
@@ -288,10 +288,6 @@
 
 
 	TRACE_STATE;
-	if (hpusbscsi->state != HP_STATE_FREE) {
-		printk(KERN_CRIT"hpusbscsi - Ouch: queueing violation!\n");
-		return 1; /* This must not happen */
-	}
 
         /* We zero the sense buffer to avoid confusing user space */
         memset(srb->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
@@ -313,10 +309,10 @@
 	hpusbscsi->srb = srb;
 
 	res = usb_submit_urb(&hpusbscsi->dataurb);
-	if (res) {
+	if (unlikely(res)) {
 		hpusbscsi->state = HP_STATE_FREE;
 		TRACE_STATE;
-		if (callback) {
+		if (likely(callback != NULL)) {
 			srb->result = DID_ERROR;
 			callback(srb);
 		}
@@ -355,7 +351,7 @@
 
 static void handle_usb_error (struct hpusbscsi *hpusbscsi)
 {
-	if (hpusbscsi->scallback != NULL) {
+	if (likely(hpusbscsi->scallback != NULL)) {
 		hpusbscsi->srb->result = DID_ERROR;
 		hpusbscsi->scallback(hpusbscsi->srb);
 	}
@@ -367,8 +363,8 @@
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 
 DEBUG("Getting status byte %d \n",hpusbscsi->scsi_state_byte);
-	if(u->status < 0) {
-                if (hpusbscsi->state != HP_STATE_FREE)
+	if(unlikely(u->status < 0)) {
+                if (likely(hpusbscsi->state != HP_STATE_FREE))
                         handle_usb_error(hpusbscsi);
 		return;
 	}
@@ -402,7 +398,7 @@
 static void simple_command_callback(struct urb *u)
 {
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
-	if (u->status<0) {
+	if (unlikely(u->status<0)) {
 		handle_usb_error(hpusbscsi);
 		return;
         }
@@ -411,7 +407,7 @@
 	        TRACE_STATE;
 		hpusbscsi->state = HP_STATE_WAIT;
 	} else {
-		if (hpusbscsi->scallback != NULL)
+		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
 	TRACE_STATE;
@@ -426,7 +422,7 @@
         int res;
 
         DEBUG("Going through scatter/gather\n");
-        if (u->status < 0) {
+        if (unlikely(u->status < 0)) {
                 handle_usb_error(hpusbscsi);
                 return;
         }
@@ -452,7 +448,7 @@
         );
 
         res = usb_submit_urb(u);
-        if (res)
+        if (unlikely(res))
                 hpusbscsi->state = HP_STATE_ERROR;
 	TRACE_STATE;
 }
@@ -461,20 +457,20 @@
 {
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 
-        if (u->status < 0) {
+        if (unlikely(u->status < 0)) {
                 handle_usb_error(hpusbscsi);
                 return;
         }
         DEBUG("Data transfer done\n");
 	TRACE_STATE;
 	if (hpusbscsi->state != HP_STATE_PREMATURE) {
-		if (u->status < 0)
+		if (unlikely(u->status < 0))
 			hpusbscsi->state = HP_STATE_ERROR;
 		else
 			hpusbscsi->state = HP_STATE_WAIT;
 		TRACE_STATE;
 	} else {
-		if (hpusbscsi->scallback != NULL)
+		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
 	}
@@ -485,7 +481,7 @@
 	struct hpusbscsi * hpusbscsi = (struct hpusbscsi *)u->context;
 	int res;
 
-	if (u->status<0) {
+	if (unlikely(u->status<0)) {
                 handle_usb_error(hpusbscsi);
 		return;
         }
@@ -501,7 +497,7 @@
 	);
 
 	res = usb_submit_urb(u);
-	if (res) {
+	if (unlikely(res)) {
                 handle_usb_error(hpusbscsi);
 		return;
         }
@@ -510,10 +506,11 @@
 		hpusbscsi->state = HP_STATE_WORKING;
 	TRACE_STATE;
 	} else {
-		if (hpusbscsi->scallback != NULL)
+		if (likely(hpusbscsi->scallback != NULL))
 			hpusbscsi->scallback(hpusbscsi->srb);
 		hpusbscsi->state = HP_STATE_FREE;
 	TRACE_STATE;
 	}
 }
+
 
diff -u --recursive --new-file pre1/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- pre1/linux/drivers/usb/hub.c	Tue Jan  1 13:52:10 2002
+++ linux/drivers/usb/hub.c	Thu Jan 17 14:06:53 2002
@@ -557,6 +557,10 @@
 		dbg("port %d, portstatus %x, change %x, %s", port + 1,
 			portstatus, portchange, portspeed (portstatus));
 
+		/* Device went away? */
+		if (!(portstatus & USB_PORT_STAT_CONNECTION))
+			return 1;
+
 		/* bomb out completely if something weird happened */
 		if ((portchange & USB_PORT_STAT_C_CONNECTION))
 			return -1;
diff -u --recursive --new-file pre1/linux/drivers/usb/microtek.c linux/drivers/usb/microtek.c
--- pre1/linux/drivers/usb/microtek.c	Tue Dec 25 17:04:40 2001
+++ linux/drivers/usb/microtek.c	Thu Jan 17 14:06:53 2002
@@ -320,11 +320,6 @@
 
 #endif
 
-
-/* static inline int mts_is_aborting(struct mts_desc* desc) {
-	return (atomic_read(&desc->context.do_abort));
-}  */
-
 static inline void mts_urb_abort(struct mts_desc* desc) {
 	MTS_DEBUG_GOT_HERE();
 	mts_debug_dump(desc);
@@ -504,7 +499,7 @@
 	transfer->status = 0;
 
 	res = usb_submit_urb( transfer );
-	if ( res ) {
+	if ( unlikely(res) ) {
 		MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
 		context->srb->result = DID_ERROR << 16;
 		mts_transfer_cleanup(transfer);
@@ -518,7 +513,7 @@
 {
 	MTS_INT_INIT();
 
-	if ( context->final_callback )
+	if ( likely(context->final_callback != NULL) )
 		context->final_callback(context->srb);
 
 }
@@ -556,7 +551,7 @@
 
 	if ( context->data_length != transfer->actual_length ) {
 		context->srb->resid = context->data_length - transfer->actual_length;
-	} else if ( transfer->status ) {
+	} else if ( unlikely(transfer->status) ) {
 		context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 	}
 
@@ -571,7 +566,7 @@
 {
 	MTS_INT_INIT();
 
-	if ( transfer->status ) {
+	if ( unlikely(transfer->status) ) {
 	        if (transfer->status == -ENOENT) {
 		        /* We are being killed */
 			MTS_DEBUG_GOT_HERE();
@@ -605,7 +600,7 @@
 	
 	MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
 
-	if (transfer->status) {
+	if (unlikely(transfer->status)) {
                 context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 		mts_transfer_cleanup(transfer);
         }
@@ -703,7 +698,7 @@
 
 		srb->result = DID_BAD_TARGET << 16;
 
-		if(callback)
+		if(likely(callback != NULL))
 			callback(srb);
 
 		goto out;
@@ -725,11 +720,11 @@
 	
 	res=usb_submit_urb(&desc->urb);
 
-	if(res){
+	if(unlikely(res)){
 		MTS_ERROR("error %d submitting URB\n",(int)res);
 		srb->result = DID_ERROR << 16;
 
-		if(callback)
+		if(likely(callback != NULL))
 			callback(srb);
 
 	}
@@ -1061,4 +1056,5 @@
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
 MODULE_LICENSE("GPL");
+
 
diff -u --recursive --new-file pre1/linux/drivers/usb/serial/ir-usb.c linux/drivers/usb/serial/ir-usb.c
--- pre1/linux/drivers/usb/serial/ir-usb.c	Sun Jan  6 18:49:21 2002
+++ linux/drivers/usb/serial/ir-usb.c	Thu Jan 17 14:06:53 2002
@@ -2,6 +2,7 @@
  * USB IR Dongle driver
  *
  *	Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *	Copyright (C) 2002 Gary Brubaker (xavyer@ix.netcom.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,6 +21,12 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * 2002_Jan_14  gb
+ *	Added module parameter to force specific number of XBOFs.
+ *	Added ir_xbof_change().
+ *	Reorganized read_bulk_callback error handling.
+ *	Switched from FILL_BULK_URB() to usb_fill_bulk_urb().
+ *
  * 2001_Nov_08  greg kh
  *	Changed the irda_usb_find_class_desc() function based on comments and
  *	code from Martin Diehl.
@@ -62,13 +69,15 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.3"
+#define DRIVER_VERSION "v0.4"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB IR Dongle driver"
 
 /* if overridden by the user, then use their value for the size of the read and
  * write urbs */
 static int buffer_size = 0;
+/* if overridden by the user, then use the specified number of XBOFs */
+static int xbof = -1;
 
 static int  ir_startup (struct usb_serial *serial);
 static int  ir_open (struct usb_serial_port *port, struct file *filep);
@@ -78,6 +87,9 @@
 static void ir_read_bulk_callback (struct urb *urb);
 static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios);
 
+static u8 ir_baud = 0;
+static u8 ir_xbof = 0;
+static u8 ir_add_bof = 0;
 
 static __devinitdata struct usb_device_id id_table [] = {
 	{ USB_DEVICE(0x050f, 0x0180) },		/* KC Technology, KC-180 */
@@ -148,14 +160,16 @@
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 			0, ifnum, desc, sizeof(*desc), MSECS_TO_JIFFIES(500));
 	
-	dbg(__FUNCTION__ " -  ret=%d", ret);
+	dbg("%s -  ret=%d", __FUNCTION__, ret);
 	if (ret < sizeof(*desc)) {
-		dbg(__FUNCTION__ " - class descriptor read %s (%d)",
-				(ret<0) ? "failed" : "too short", ret);
+		dbg("%s - class descriptor read %s (%d)",
+				__FUNCTION__, 
+				(ret<0) ? "failed" : "too short",
+				ret);
 		goto error;
 	}
 	if (desc->bDescriptorType != USB_DT_IRDA) {
-		dbg(__FUNCTION__ " - bad class descriptor type");
+		dbg("%s - bad class descriptor type", __FUNCTION__);
 		goto error;
 	}
 	
@@ -166,6 +180,28 @@
 	return NULL;
 }
 
+
+static u8 ir_xbof_change(u8 xbof)
+{
+	u8 result;
+	/* reference irda-usb.c */
+	switch(xbof) {
+		case 48: result = 0x10; break;
+		case 28:
+		case 24: result = 0x20; break;
+		default:
+		case 12: result = 0x30; break;
+		case  5:
+		case  6: result = 0x40; break;
+		case  3: result = 0x50; break;
+		case  2: result = 0x60; break;
+		case  1: result = 0x70; break;
+		case  0: result = 0x80; break;
+	}
+	return(result);
+}
+
+
 static int ir_startup (struct usb_serial *serial)
 {
 	struct irda_class_desc *irda_desc;
@@ -175,16 +211,30 @@
 		err ("IRDA class descriptor not found, device not bound");
 		return -ENODEV;
 	}
-	dbg (__FUNCTION__" - Baud rates supported: %s%s%s%s%s%s%s%s%s",
-	     (irda_desc->wBaudRate & 0x0001) ? "2400 " : "",
-	     irda_desc->wBaudRate & 0x0002 ? "9600 " : "",
-	     irda_desc->wBaudRate & 0x0004 ? "19200 " : "",
-	     irda_desc->wBaudRate & 0x0008 ? "38400 " : "",
-	     irda_desc->wBaudRate & 0x0010 ? "57600 " : "",
-	     irda_desc->wBaudRate & 0x0020 ? "115200 " : "",
-	     irda_desc->wBaudRate & 0x0040 ? "576000 " : "",
-	     irda_desc->wBaudRate & 0x0080 ? "1152000 " : "",
-	     irda_desc->wBaudRate & 0x0100 ? "4000000 " : "");
+
+	dbg ("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s",
+		__FUNCTION__,
+		(irda_desc->wBaudRate & 0x0001) ? " 2400"    : "",
+		(irda_desc->wBaudRate & 0x0002) ? " 9600"    : "",
+		(irda_desc->wBaudRate & 0x0004) ? " 19200"   : "",
+		(irda_desc->wBaudRate & 0x0008) ? " 38400"   : "",
+		(irda_desc->wBaudRate & 0x0010) ? " 57600"   : "",
+		(irda_desc->wBaudRate & 0x0020) ? " 115200"  : "",
+		(irda_desc->wBaudRate & 0x0040) ? " 576000"  : "",
+		(irda_desc->wBaudRate & 0x0080) ? " 1152000" : "",
+		(irda_desc->wBaudRate & 0x0100) ? " 4000000" : "");
+
+	switch( irda_desc->bmAdditionalBOFs ) {
+		case 0x01: ir_add_bof = 48; break;
+		case 0x02: ir_add_bof = 24; break;
+		case 0x04: ir_add_bof = 12; break;
+		case 0x08: ir_add_bof =  6; break;
+		case 0x10: ir_add_bof =  3; break;
+		case 0x20: ir_add_bof =  2; break;
+		case 0x40: ir_add_bof =  1; break;
+		case 0x80: ir_add_bof =  0; break;
+		default:
+	}
 
 	kfree (irda_desc);
 
@@ -200,7 +250,7 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	down (&port->sem);
 	
@@ -211,7 +261,7 @@
 			/* override the default buffer sizes */
 			buffer = kmalloc (buffer_size, GFP_KERNEL);
 			if (!buffer) {
-				err (__FUNCTION__ " - out of memory.");
+				err ("%s - out of memory.", __FUNCTION__);
 				return -ENOMEM;
 			}
 			kfree (port->read_urb->transfer_buffer);
@@ -220,7 +270,7 @@
 
 			buffer = kmalloc (buffer_size, GFP_KERNEL);
 			if (!buffer) {
-				err (__FUNCTION__ " - out of memory.");
+				err ("%s - out of memory.", __FUNCTION__);
 				return -ENOMEM;
 			}
 			kfree (port->write_urb->transfer_buffer);
@@ -230,13 +280,18 @@
 		}
 
 		/* 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,
-			      ir_read_bulk_callback, port);
+		usb_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,
+			ir_read_bulk_callback,
+			port);
+		port->read_urb->transfer_flags = USB_QUEUE_BULK;
 		result = usb_submit_urb(port->read_urb);
 		if (result)
-			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+			err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
 	}
 	
 	up (&port->sem);
@@ -251,7 +306,7 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 			 
 	serial = get_usb_serial (port, __FUNCTION__);
 	if (!serial)
@@ -276,11 +331,12 @@
 {
 	unsigned char *transfer_buffer;
 	int result;
+	int transfer_size;
 
-	dbg(__FUNCTION__ " - port = %d, count = %d", port->number, count);
+	dbg("%s - port = %d, count = %d", __FUNCTION__, port->number, count);
 
 	if (!port->tty) {
-		err (__FUNCTION__ " - no tty???");
+		err ("%s - no tty???", __FUNCTION__);
 		return 0;
 	}
 
@@ -288,37 +344,49 @@
 		return 0;
 
 	if (port->write_urb->status == -EINPROGRESS) {
-		dbg (__FUNCTION__ " - already writing");
+		dbg ("%s - already writing", __FUNCTION__);
 		return 0;
 	}
 
+	transfer_buffer = port->write_urb->transfer_buffer;
+	transfer_size = min(count, port->bulk_out_size - 1);
+
 	/*
-	 * The first byte of the packet we send to the device contains a BOD
-	 * and baud rate change.  So we set it to 0.
+	 * The first byte of the packet we send to the device contains an
+	 * inband header which indicates an additional number of BOFs and
+	 * a baud rate change.
+	 *
 	 * See section 5.4.2.2 of the USB IrDA spec.
 	 */
-	transfer_buffer = port->write_urb->transfer_buffer;
-	count = min (port->bulk_out_size-1, count);
+	*transfer_buffer = ir_xbof | ir_baud;
+	++transfer_buffer;
+
 	if (from_user) {
-		if (copy_from_user (&transfer_buffer[1], buf, count))
+		if (copy_from_user (transfer_buffer, buf, transfer_size))
 			return -EFAULT;
 	} else {
-		memcpy (&transfer_buffer[1], buf, count);
+		memcpy (transfer_buffer, buf, transfer_size);
 	}
 
-	/* use 12 XBOF's as default */
-	transfer_buffer[0] = 0x30;
-
-	usb_serial_debug_data (__FILE__, __FUNCTION__, count+1, transfer_buffer);
+	usb_fill_bulk_urb (
+		port->write_urb,
+		port->serial->dev,
+		usb_sndbulkpipe(port->serial->dev,
+			port->bulk_out_endpointAddress),
+		port->write_urb->transfer_buffer,
+		transfer_size + 1,
+		ir_write_bulk_callback,
+		port);
+
+	port->write_urb->transfer_flags
+		= USB_QUEUE_BULK
+		| USB_ZERO_PACKET;
 
-	port->write_urb->transfer_buffer_length = count + 1;
-	port->write_urb->dev = port->serial->dev;
-	port->write_urb->transfer_flags |= USB_ZERO_PACKET;
 	result = usb_submit_urb (port->write_urb);
 	if (result)
-		err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+		err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	else
-		result = count;
+		result = transfer_size;
 
 	return result;
 }
@@ -330,13 +398,19 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 	
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 	
 	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
 		return;
 	}
 
+	usb_serial_debug_data (
+		__FILE__,
+		__FUNCTION__,
+		urb->actual_length,
+		urb->transfer_buffer);
+
 	queue_task(&port->tqueue, &tq_immediate);
 	mark_bh(IMMEDIATE_BH);
 	
@@ -354,34 +428,87 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if (!serial) {
-		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		dbg("%s - bad serial pointer, exiting", __FUNCTION__);
 		return;
 	}
 
-	if (urb->status) {
-		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+	if (!port->open_count) {
+		dbg("%s - port closed.", __FUNCTION__);
 		return;
 	}
 
-	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+	switch (urb->status) {
+
+		case 0: /* Successful */
+
+			/*
+			 * The first byte of the packet we get from the device
+			 * contains a busy indicator and baud rate change.
+			 * See section 5.4.1.2 of the USB IrDA spec.
+			 */
+			if((*data & 0x0f) > 0) ir_baud = *data & 0x0f;
+
+			usb_serial_debug_data (
+				__FILE__,
+				__FUNCTION__,
+				urb->actual_length,
+				data);
+
+			/*
+			 * Bypass flip-buffers, and feed the ldisc directly
+			 * due to our potentally large buffer size.  Since we
+			 * used to set low_latency, this is exactly what the
+			 * tty layer did anyway :)
+			 */
+			tty = port->tty;
+
+			tty->ldisc.receive_buf(
+				tty,
+				data+1,
+				NULL,
+				urb->actual_length-1);
+
+			/*
+			 * No break here.
+			 * We want to resubmit the urb so we can read
+			 * again.
+			 */
+
+		case -EPROTO: /* taking inspiration from pl2303.c */
+
+			/* Continue trying to always read */
+			usb_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,
+				ir_read_bulk_callback,
+				port);
+
+			port->read_urb->transfer_flags = USB_QUEUE_BULK;
+
+			result = usb_submit_urb(port->read_urb);
+
+			if (result)
+				err("%s - failed resubmitting read urb, error %d",
+					__FUNCTION__, 
+					result);
+
+			break ;
+
+		default:
+			dbg("%s - nonzero read bulk status received: %d",
+				__FUNCTION__, 
+				urb->status);
+			break ;
+
+	}
 
-	/* Bypass flip-buffers, and feed the ldisc directly due to our 
-	 * potentally large buffer size.  Since we used to set low_latency,
-	 * this is exactly what the tty layer did anyway :) */
-	tty = port->tty;
-	tty->ldisc.receive_buf(tty, data+1, NULL, urb->actual_length-1);
-
-	/* 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,
-		      ir_read_bulk_callback, port);
-	result = usb_submit_urb(port->read_urb);
-	if (result)
-		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 	return;
 }
 
@@ -390,12 +517,11 @@
 	unsigned char *transfer_buffer;
 	unsigned int cflag;
 	int result;
-	u8 baud;
 
-	dbg(__FUNCTION__ " - port %d", port->number);
+	dbg("%s - port %d", __FUNCTION__, port->number);
 
 	if ((!port->tty) || (!port->tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
+		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
 
@@ -404,44 +530,70 @@
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
 		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg(__FUNCTION__ " - nothing to change...");
+			dbg("%s - nothing to change...", __FUNCTION__);
 			return;
 		}
 	}
 
 	/* All we can change is the baud rate */
 	if (cflag & CBAUD) {
-		dbg (__FUNCTION__ " - asking for baud %d", tty_get_baud_rate(port->tty));
+
+		dbg ("%s - asking for baud %d",
+			__FUNCTION__,
+			tty_get_baud_rate(port->tty));
+
 		/* 
 		 * FIXME, we should compare the baud request against the
 		 * capability stated in the IR header that we got in the
 		 * startup funtion.
 		 */
 		switch (cflag & CBAUD) {
-			case B2400:	baud = SPEED_2400;	break;
-			case B9600:	baud = SPEED_9600;	break;
-			case B19200:	baud = SPEED_19200;	break;
-			case B38400:	baud = SPEED_38400;	break;
-			case B57600:	baud = SPEED_57600;	break;
-			case B115200:	baud = SPEED_115200;	break;
-			case B576000:	baud = SPEED_576000;	break;
-			case B1152000:	baud = SPEED_1152000;	break;
-			case B4000000:	baud = SPEED_4000000;	break;
+			case B2400:    ir_baud = SPEED_2400;    break;
 			default:
-				err ("ir-usb driver does not support the baudrate (%d) requested", tty_get_baud_rate(port->tty));
-				return;
+			case B9600:    ir_baud = SPEED_9600;    break;
+			case B19200:   ir_baud = SPEED_19200;   break;
+			case B38400:   ir_baud = SPEED_38400;   break;
+			case B57600:   ir_baud = SPEED_57600;   break;
+			case B115200:  ir_baud = SPEED_115200;  break;
+			case B576000:  ir_baud = SPEED_576000;  break;
+			case B1152000: ir_baud = SPEED_1152000; break;
+			case B4000000: ir_baud = SPEED_4000000; break;
 		}
-		
+
+		if (xbof == -1) {
+			ir_xbof = ir_xbof_change(ir_add_bof);
+		} else {
+			ir_xbof = ir_xbof_change(xbof) ;
+		}
+
+		/* Notify the tty driver that the termios have changed. */
+		port->tty->ldisc.set_termios(port->tty, NULL);
+
 		/* FIXME need to check to see if our write urb is busy right
-		 * now, or use a urb pool. */
-		/* send the baud change out on an "empty" data packet */
+		 * now, or use a urb pool.
+		 *
+		 * send the baud change out on an "empty" data packet
+		 */
 		transfer_buffer = port->write_urb->transfer_buffer;
-		transfer_buffer[0] = baud;
-		port->write_urb->transfer_buffer_length = 1;
-		port->write_urb->dev = port->serial->dev;
+		*transfer_buffer = ir_xbof | ir_baud;
+
+		usb_fill_bulk_urb (
+			port->write_urb,
+			port->serial->dev,
+			usb_sndbulkpipe(port->serial->dev,
+				port->bulk_out_endpointAddress),
+			port->write_urb->transfer_buffer,
+			1,
+			ir_write_bulk_callback,
+			port);
+
+		port->write_urb->transfer_flags
+			= USB_QUEUE_BULK
+			| USB_ZERO_PACKET;
+
 		result = usb_submit_urb (port->write_urb);
 		if (result)
-			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
 	}
 	return;
 }
@@ -470,6 +622,8 @@
 
 MODULE_PARM(debug, "i");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
+MODULE_PARM(xbof, "i");
+MODULE_PARM_DESC(xbof, "Force specific number of XBOFs");
 MODULE_PARM(buffer_size, "i");
 MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");
 
diff -u --recursive --new-file pre1/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- pre1/linux/drivers/usb/serial/keyspan.c	Sun Jan  6 18:49:21 2002
+++ linux/drivers/usb/serial/keyspan.c	Thu Jan 17 14:06:53 2002
@@ -178,15 +178,7 @@
 /* Functions used by new usb-serial code. */
 static int __init keyspan_init (void)
 {
-	usb_serial_register (&keyspan_usa18x_pre_device);
-	usb_serial_register (&keyspan_usa19_pre_device);
-	usb_serial_register (&keyspan_usa19w_pre_device);
-	usb_serial_register (&keyspan_usa28_pre_device);
-	usb_serial_register (&keyspan_usa28x_pre_device);
-	usb_serial_register (&keyspan_usa28xa_pre_device);
-	usb_serial_register (&keyspan_usa28xb_pre_device);
-	usb_serial_register (&keyspan_usa49w_pre_device);
-
+	usb_serial_register (&keyspan_pre_device);
 	usb_serial_register (&keyspan_usa18x_device);
 	usb_serial_register (&keyspan_usa19_device);
 	usb_serial_register (&keyspan_usa19w_device);
@@ -203,15 +195,7 @@
 
 static void __exit keyspan_exit (void)
 {
-	usb_serial_deregister (&keyspan_usa18x_pre_device);
-	usb_serial_deregister (&keyspan_usa19_pre_device);
-	usb_serial_deregister (&keyspan_usa19w_pre_device);
-	usb_serial_deregister (&keyspan_usa28_pre_device);
-	usb_serial_deregister (&keyspan_usa28x_pre_device);
-	usb_serial_deregister (&keyspan_usa28xa_pre_device);
-	usb_serial_deregister (&keyspan_usa28xb_pre_device);
-	usb_serial_deregister (&keyspan_usa49w_pre_device);
-
+	usb_serial_deregister (&keyspan_pre_device);
 	usb_serial_deregister (&keyspan_usa18x_device);
 	usb_serial_deregister (&keyspan_usa19_device);
 	usb_serial_deregister (&keyspan_usa19w_device);
diff -u --recursive --new-file pre1/linux/drivers/usb/serial/keyspan.h linux/drivers/usb/serial/keyspan.h
--- pre1/linux/drivers/usb/serial/keyspan.h	Sun Jan  6 18:49:21 2002
+++ linux/drivers/usb/serial/keyspan.h	Thu Jan 17 14:06:53 2002
@@ -372,42 +372,15 @@
    ID pattern.  But, for now, it looks like we need slightly different
    behavior for each match. */
 
-static __devinitdata struct usb_device_id keyspan_usa18x_pre_ids[] = {
+/* usb_device_id table for the pre-firmware download keyspan devices */
+static __devinitdata struct usb_device_id keyspan_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
-	{ }	/* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa19w_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28x_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xa_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa28xb_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) },
-	{ } /* Terminating entry */
-};
-
-static __devinitdata struct usb_device_id keyspan_usa49w_pre_ids[] = {
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) },
 	{ } /* Terminating entry */
 };
@@ -448,10 +421,10 @@
 };
 
     /* Structs for the devices, pre and post renumeration. */
-static struct usb_serial_device_type keyspan_usa18x_pre_device = {
+static struct usb_serial_device_type keyspan_pre_device = {
 	owner:			THIS_MODULE,
-	name:			"Keyspan USA18X - (without firmware)",
-	id_table:		keyspan_usa18x_pre_ids,
+	name:			"Keyspan - (without firmware)",
+	id_table:		keyspan_pre_ids,
 	num_interrupt_in:	NUM_DONT_CARE,
 	num_bulk_in:		NUM_DONT_CARE,
 	num_bulk_out:		NUM_DONT_CARE,
@@ -459,84 +432,6 @@
 	startup:		keyspan_fake_startup	
 };
 
-static struct usb_serial_device_type keyspan_usa19_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA19 - (without firmware)",
-	id_table:		keyspan_usa19_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_fake_startup	
-};
-
-
-static struct usb_serial_device_type keyspan_usa19w_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA19W - (without firmware)",
-	id_table:		keyspan_usa19w_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		1,
-	startup:		keyspan_fake_startup	
-};
-
-
-static struct usb_serial_device_type keyspan_usa28_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28 - (without firmware)",
-	id_table:		keyspan_usa28_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28x_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28X - (without firmware)",
-	id_table:		keyspan_usa28x_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28xa_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28XA - (without firmware)",
-	id_table:		keyspan_usa28xa_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa28xb_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA28XB - (without firmware)",
-	id_table:		keyspan_usa28xb_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		2,
-	startup:		keyspan_fake_startup	
-};
-
-static struct usb_serial_device_type keyspan_usa49w_pre_device = {
-	owner:			THIS_MODULE,
-	name:			"Keyspan USA49W - (without firmware)",
-	id_table:		keyspan_usa49w_pre_ids,
-	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
-	num_ports:		4,
-	startup:		keyspan_fake_startup	
-};
 
 static struct usb_serial_device_type keyspan_usa18x_device = {
 	owner:			THIS_MODULE,
@@ -550,8 +445,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -574,8 +467,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa28_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -599,8 +490,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -640,8 +529,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -665,8 +552,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-//	write_bulk_callback: 	keyspan_write_bulk_callback,
-//	read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -690,8 +575,6 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	//write_bulk_callback: 	Not used - we define our own herbs
-	//read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
diff -u --recursive --new-file pre1/linux/drivers/usb/storage/protocol.c linux/drivers/usb/storage/protocol.c
--- pre1/linux/drivers/usb/storage/protocol.c	Sun Jul 29 21:11:50 2001
+++ linux/drivers/usb/storage/protocol.c	Thu Jan 17 14:06:53 2002
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: protocol.c,v 1.10 2001/07/30 00:27:59 mdharm Exp $
+ * $Id: protocol.c,v 1.11 2002/01/13 06:40:25 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -76,7 +76,7 @@
 		data_ptr = (unsigned char *)srb->request_buffer;
 
 	/* Change the SCSI revision number */
-	data_ptr[2] |= 0x2;
+	data_ptr[2] = (data_ptr[2] & ~7) | 2;
 }
 
 /***********************************************************************
diff -u --recursive --new-file pre1/linux/drivers/usb/storage/unusual_devs.h linux/drivers/usb/storage/unusual_devs.h
--- pre1/linux/drivers/usb/storage/unusual_devs.h	Mon Jan 14 13:30:20 2002
+++ linux/drivers/usb/storage/unusual_devs.h	Thu Jan 17 17:14:09 2002
@@ -1,7 +1,7 @@
 /* Driver for USB Mass Storage compliant devices
  * Ununsual Devices File
  *
- * $Id: unusual_devs.h,v 1.24 2001/12/29 03:12:45 mdharm Exp $
+ * $Id: unusual_devs.h,v 1.25 2002/01/13 06:39:17 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -458,6 +458,14 @@
                 US_SC_ISD200, US_PR_BULK, isd200_Initialization,
                 0 ),
 #endif
+
+/* Submitted by Brian Hall <brihall@bigfoot.com>
+ * Needed for START_STOP flag */
+UNUSUAL_DEV(  0x0c76, 0x0003, 0x0100, 0x0100,
+		"JMTek",
+		"USBDrive",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP ),
 
 /* Reported by Dan Pilone <pilone@slac.com>
  * The device needs the flags only.
diff -u --recursive --new-file pre1/linux/drivers/usb/storage/usb.c linux/drivers/usb/storage/usb.c
--- pre1/linux/drivers/usb/storage/usb.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/usb/storage/usb.c	Thu Jan 17 14:06:53 2002
@@ -1,6 +1,6 @@
 /* Driver for USB Mass Storage compliant devices
  *
- * $Id: usb.c,v 1.69 2001/11/11 03:33:03 mdharm Exp $
+ * $Id: usb.c,v 1.70 2002/01/06 07:14:12 mdharm Exp $
  *
  * Current development and maintenance by:
  *   (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
@@ -315,6 +315,13 @@
 	 * so get rid of all our resources..
 	 */
 	daemonize();
+
+	/* avoid getting signals */
+	spin_lock_irq(&current->sigmask_lock);
+	flush_signals(current);
+	sigfillset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
 
 	/* set our name for identification purposes */
 	sprintf(current->comm, "usb-storage-%d", us->host_number);
diff -u --recursive --new-file pre1/linux/drivers/usb/stv680.c linux/drivers/usb/stv680.c
--- pre1/linux/drivers/usb/stv680.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/usb/stv680.c	Thu Jan 17 14:06:53 2002
@@ -43,6 +43,13 @@
  * 			   Took out sharpen function, ran code through
  * 			   Lindent, and did other minor tweaks to get
  * 			   things to work properly with 2.5.1
+ *
+ * ver 0.24 Jan, 2002 (kjs) 
+ *                         Fixed the problem with webcam crashing after
+ *                         two pictures. Changed the way pic is halved to 
+ *                         improve quality. Got rid of green line around 
+ *                         frame. Fix brightness reset when changing size 
+ *                         bug. Adjusted gamma filters slightly.
  */
 
 #include <linux/config.h>
@@ -65,7 +72,8 @@
 #include "stv680.h"
 
 static int video_nr = -1;
-static int swapRGB = 0;
+static int swapRGB = 0;   /* default for auto sleect */
+static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
 
 static unsigned int debug = 0;
 
@@ -79,7 +87,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.23"
+#define DRIVER_VERSION "v0.24"
 #define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
 #define DRIVER_DESC "STV0680 USB Camera Driver"
 
@@ -88,8 +96,8 @@
 MODULE_LICENSE ("GPL");
 MODULE_PARM (debug, "i");
 MODULE_PARM_DESC (debug, "Debug enabled or not");
-MODULE_PARM (swapRGB, "i");
-MODULE_PARM_DESC (swapRGB, "Swap red and blue, e.g., for xawtv");
+MODULE_PARM (swapRGB_on, "i");
+MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
 MODULE_PARM (video_nr, "i");
 EXPORT_NO_SYMBOLS;
 
@@ -521,8 +529,15 @@
 	stv680->palette = STV_VIDEO_PALETTE;
 	stv680->depth = 24;	/* rgb24 bits */
 	swapRGB = 0;
-	PDEBUG (1, "STV(i): swapRGB is OFF");
-
+	if ((swapRGB_on == 0) && (swapRGB == 0))
+		PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
+	else if ((swapRGB_on == 1) && (swapRGB == 1))
+		PDEBUG (1, "STV(i): swapRGB is (auto) ON");
+	else if (swapRGB_on == 1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) ON");
+	else if (swapRGB_on == -1)
+		PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
+	
 	if (stv_set_video_mode (stv680) < 0) {
 		PDEBUG (0, "STV(e): Could not set video mode in stv_init");
 		return -1;
@@ -543,6 +558,7 @@
 extern struct proc_dir_entry *video_proc_entry;
 
 #define YES_NO(x) ((x) ? "yes" : "no")
+#define ON_OFF(x) ((x) ? "(auto) on" : "(auto) off")
 
 static int stv680_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
@@ -559,7 +575,13 @@
 	out += sprintf (out, "num_frames      : %d\n", STV680_NUMFRAMES);
 
 	out += sprintf (out, "Current size    : %ix%i\n", stv680->vwidth, stv680->vheight);
-	out += sprintf (out, "swapRGB         : %s\n", YES_NO (swapRGB));
+	if (swapRGB_on == 0)
+		out += sprintf (out, "swapRGB         : %s\n", ON_OFF (swapRGB));
+	else if (swapRGB_on == 1)
+		out += sprintf (out, "swapRGB         : (forced) on\n");
+	else if (swapRGB_on == -1)
+		out += sprintf (out, "swapRGB         : (forced) off\n");
+
 	out += sprintf (out, "Palette         : %i", stv680->palette);
 
 	out += sprintf (out, "\n");
@@ -671,9 +693,7 @@
 	if (stv680->brightness != p->brightness) {
 		stv680->chgbright = 1;
 		stv680->brightness = p->brightness;
-	} else {
-		stv680->chgbright = 0;
-	}
+	} 
 
 	stv680->whiteness = p->whiteness;	/* greyscale */
 	stv680->colour = p->colour;
@@ -888,7 +908,7 @@
 {
 	int x, y, i;
 	int w = stv680->cwidth;
-	int vw = stv680->cwidth, vh = stv680->cheight, vstep = 1;
+	int vw = stv680->cwidth, vh = stv680->cheight;
 	unsigned int p = 0;
 	int colour = 0, bayer = 0;
 	unsigned char *raw = buffer->data;
@@ -908,46 +928,23 @@
 		return;
 	}
 
-	if ((stv680->vwidth == 322) || (stv680->vwidth == 320)) {
+	if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
 		vw = 320;
 		vh = 240;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 352)) {
+	if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
 		vw = 352;
 		vh = 288;
-		vstep = 1;
 	}
-	if ((stv680->vwidth == 160)) {
-		vw = 160;
-		vh = 120;
-		vstep = 2;
-	}
-	if ((stv680->vwidth == 176)) {
-		vw = 176;
-		vh = 144;
-		vstep = 2;
-	}
-	memset (output, 0, 3 * vw * vh);	/* clear output matrix. Maybe not necessary. */
+
+	memset (output, 0, 3 * vw * vh);	/* clear output matrix. */
 
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
-
-			switch (vstep) {
-			case 1:
-				if (x & 1)
-					p = *(raw + y * w + (x >> 1));
-				else
-					p = *(raw + y * w + (x >> 1) + (w >> 1));
-				break;
-
-			case 2:
-				if (x & 1)
-					p = *(raw + ((y * w) << 1) + x);
-				else
-					p = *(raw + ((y * w) << 1) + x + (w >> 1));
-				break;
-			}
+			if (x & 1)
+				p = *(raw + y * w + (x >> 1));
+			else
+				p = *(raw + y * w + (x >> 1) + (w >> 1));
 
 			if (y & 1)
 				bayer = 2;
@@ -968,9 +965,10 @@
 				colour = 2;
 				break;
 			}
-			i = (y * vw + x) * 3;	/* output already zeroed out with memset */
+			i = (y * vw + x) * 3;	
 			*(output + i + colour) = (unsigned char) p;
 		}		/* for x */
+
 	}			/* for y */
 
 	/****** gamma correction plus hardcoded white balance */
@@ -979,6 +977,7 @@
 	   (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255. 
 	   White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and 
 	   converted to unsigned char. Values are in stv680.h  */
+
 	for (y = 0; y < vh; y++) {
 		for (x = 0; x < vw; x++) {
 			i = (y * vw + x) * 3;
@@ -1022,8 +1021,47 @@
 		}		/* for x */
 	}			/* for y  - end demosaic  */
 
+	/* fix top and bottom row, left and right side */
+	i = vw * 3;
+	memcpy (output, (output + i), i);
+	memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
+	for (y = 0; y < vh; y++) {
+		i = y * vw * 3;
+		memcpy ((output + i), (output + i + 3), 3);
+		memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
+	}
+
+	/*  process all raw data, then trim to size if necessary */
+	if ((stv680->vwidth == 160) || (stv680->vwidth == 176))  {
+		i = 0;
+		for (y = 0; y < vh; y++) {
+			if (!(y & 1)) {
+				for (x = 0; x < vw; x++) {
+					p = (y * vw + x) * 3;
+					if (!(x & 1)) {
+						*(output + i) = *(output + p);
+						*(output + i + 1) = *(output + p + 1);
+						*(output + i + 2) = *(output + p + 2);
+						i += 3;
+					}
+				}  /* for x */
+			}
+		}  /* for y */
+	}
+	/* reset to proper width */
+	if ((stv680->vwidth == 160)) {
+		vw = 160;
+		vh = 120;
+	}
+	if ((stv680->vwidth == 176)) {
+		vw = 176;
+		vh = 144;
+	}
+
 	/* output is RGB; some programs want BGR  */
-	if (swapRGB == 1) {
+	/* swapRGB_on=0 -> program decides;  swapRGB_on=1, always swap */
+	/* swapRGB_on=-1, never swap */
+	if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
 		for (y = 0; y < vh; y++) {
 			for (x = 0; x < vw; x++) {
 				i = (y * vw + x) * 3;
@@ -1242,7 +1280,7 @@
 				return -EFAULT;
 			}
 			copy_from_user (&p, arg, sizeof (p));
-			PDEBUG (2, "STV(i): palette set to RGB in VIDIOSPICT");
+			PDEBUG (2, "STV(i): palette set to %i in VIDIOSPICT", p.palette);
 
 			if (stv680_set_pict (stv680, &p))
 				return -EINVAL;
@@ -1309,8 +1347,8 @@
 			if (vm.format != STV_VIDEO_PALETTE) {
 				PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
 					vm.format, STV_VIDEO_PALETTE);
-				if (vm.format == 3) {
-					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is ON");
+				if ((vm.format == 3) && (swapRGB_on == 0))  {
+					PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
 					/* this may fix those apps (e.g., xawtv) that want BGR */
 					swapRGB = 1;
 				}
@@ -1320,8 +1358,10 @@
 				PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
 				return -EINVAL;
 			}
-			if (stv680->frame[vm.frame].grabstate != FRAME_UNUSED) {
-				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate != FRAME_UNUSED");
+			if ((stv680->frame[vm.frame].grabstate == FRAME_ERROR)
+			    || (stv680->frame[vm.frame].grabstate == FRAME_GRABBING)) {
+				PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
+					stv680->frame[vm.frame].grabstate);
 				return -EBUSY;
 			}
 			/* Is this according to the v4l spec??? */
diff -u --recursive --new-file pre1/linux/drivers/usb/stv680.h linux/drivers/usb/stv680.h
--- pre1/linux/drivers/usb/stv680.h	Thu Jan  3 13:21:28 2002
+++ linux/drivers/usb/stv680.h	Thu Jan 17 14:06:53 2002
@@ -43,7 +43,7 @@
 #define USB_PENCAM_PRODUCT_ID	0x0202
 #define PENCAM_TIMEOUT          1000
 /* fmt 4 */
-#define STV_VIDEO_PALETTE    VIDEO_PALETTE_RGB24
+#define STV_VIDEO_PALETTE       VIDEO_PALETTE_RGB24
 
 static __devinitdata struct usb_device_id device_table[] = {
 	{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
@@ -146,77 +146,78 @@
 	int nullpackets;
 };
 
-unsigned char red[256] = {
-	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
-	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
-	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
-	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
-	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
-	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
-	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
-	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
-	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
-	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
-	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
-	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
-	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
-	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
-	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
-	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
-	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
-	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
-	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
-	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
-	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
-	245, 245, 246, 246
-};
+
+unsigned char red[256] = { 
+	0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42, 
+	44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69, 
+	71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87, 
+	88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101, 
+	102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 
+	114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124, 
+	125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 
+	134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143, 
+	143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151, 
+	152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159, 
+	159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166, 
+	167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173, 
+	173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179, 
+	180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186, 
+	187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192, 
+	192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197, 
+	198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204, 
+	204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209, 
+	209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215, 
+	215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219, 
+	220, 220, 221, 221 
+}; 
 
 unsigned char green[256] = {
-	0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
-	24, 24, 24, 24, 24, 24, 24, 32, 39, 45, 50, 54,
-	58, 62, 65, 69, 71, 74, 77, 79, 83, 85, 87, 90,
-	92, 93, 95, 98, 100, 101, 104, 106, 107, 109, 111, 113,
-	114, 116, 118, 119, 121, 122, 124, 126, 127, 128, 129, 132,
-	133, 134, 135, 136, 138, 140, 141, 142, 143, 145, 146, 147,
-	148, 149, 150, 152, 153, 154, 155, 156, 157, 159, 160, 161,
-	162, 163, 164, 166, 167, 168, 168, 169, 170, 171, 173, 174,
-	175, 176, 176, 177, 179, 180, 181, 182, 182, 183, 184, 186,
-	187, 187, 188, 189, 190, 191, 191, 193, 194, 195, 195, 196,
-	197, 198, 198, 200, 201, 201, 202, 203, 204, 204, 205, 207,
-	207, 208, 209, 209, 210, 211, 212, 212, 214, 215, 215, 216,
-	217, 217, 218, 218, 219, 221, 221, 222, 223, 223, 224, 225,
-	225, 226, 226, 228, 229, 229, 230, 231, 231, 232, 232, 233,
-	235, 235, 236, 236, 237, 238, 238, 239, 239, 241, 241, 242,
-	243, 243, 244, 244, 245, 245, 246, 248, 248, 249, 249, 250,
-	250, 251, 251, 252, 253, 253, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 
+	21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47, 
+	50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77, 
+	79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97, 
+	98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113, 
+	114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126, 
+	127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 
+	150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159, 
+	160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 
+	169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177, 
+	177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185, 
+	186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 
+	193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 
+	201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207, 
+	208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214, 
+	214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 
+	233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 
+	239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 
+	245, 245, 246, 246 
+}; 
 
 unsigned char blue[256] = {
-	0, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
-	31, 31, 31, 31, 31, 31, 31, 41, 50, 57, 63, 69,
-	74, 78, 82, 87, 90, 94, 97, 100, 105, 108, 111, 113,
-	116, 118, 121, 124, 127, 128, 131, 134, 136, 139, 140, 143,
-	145, 148, 149, 150, 153, 155, 156, 159, 161, 162, 164, 167,
-	168, 170, 171, 173, 174, 177, 179, 180, 182, 183, 185, 186,
-	187, 189, 190, 192, 193, 195, 196, 198, 199, 201, 202, 204,
-	205, 207, 208, 210, 211, 213, 213, 214, 216, 217, 219, 220,
-	222, 223, 223, 224, 226, 227, 229, 230, 230, 232, 233, 235,
-	236, 236, 238, 239, 241, 242, 242, 244, 245, 247, 247, 248,
-	250, 251, 251, 253, 254, 254, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-	255, 255, 255, 255
-};
+	0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51, 
+	55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84, 
+	86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106, 
+	107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124, 
+	125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138, 
+	139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151, 
+	152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163, 
+	165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174, 
+	176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184, 
+	185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194, 
+	194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203, 
+	204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212, 
+	212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220, 
+	221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 
+	228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235, 
+	235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242, 
+	243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249, 
+	249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
+	255, 255, 255, 255 
+}; 
diff -u --recursive --new-file pre1/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- pre1/linux/drivers/usb/usb.c	Sun Jan  6 18:49:21 2002
+++ linux/drivers/usb/usb.c	Thu Jan 17 14:06:53 2002
@@ -2252,6 +2252,14 @@
 		return -EINVAL;
 	}
 
+	/* 9.4.10 says devices don't need this, if the interface
+	   only has one alternate setting */
+	if (iface->num_altsetting == 1) {
+		warn("ignoring set_interface for dev %d, iface %d, alt %d",
+			dev->devnum, interface, alternate);
+		return 0;
+	}
+
 	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 	    USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, alternate,
 	    interface, NULL, 0, HZ * 5)) < 0)
diff -u --recursive --new-file pre1/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- pre1/linux/drivers/video/vesafb.c	Wed Jan 16 11:16:28 2002
+++ linux/drivers/video/vesafb.c	Tue Jan 15 18:47:23 2002
@@ -550,7 +550,7 @@
 		ypan = pmi_setpal = 0; /* not available or some DOS TSR ... */
 
 	if (ypan || pmi_setpal) {
-		pmi_base  = (unsigned short*)isa_bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
+		pmi_base  = (unsigned short*)bus_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off);
 		pmi_start = (void*)((char*)pmi_base + pmi_base[1]);
 		pmi_pal   = (void*)((char*)pmi_base + pmi_base[2]);
 		printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal);
diff -u --recursive --new-file pre1/linux/drivers/zorro/zorro.c linux/drivers/zorro/zorro.c
--- pre1/linux/drivers/zorro/zorro.c	Fri Sep  7 09:28:38 2001
+++ linux/drivers/zorro/zorro.c	Thu Jan 17 14:21:16 2002
@@ -170,6 +170,7 @@
 			m68k_memory[i].addr+m68k_memory[i].size, 0);
 }
 
+subsys_initcall(zorro_init);
 
 EXPORT_SYMBOL(zorro_find_device);
 EXPORT_SYMBOL(zorro_unused_z2ram);
diff -u --recursive --new-file pre1/linux/fs/Makefile.lib linux/fs/Makefile.lib
--- pre1/linux/fs/Makefile.lib	Thu Jan 10 16:23:46 2002
+++ linux/fs/Makefile.lib	Tue Jan 15 14:15:53 2002
@@ -1,2 +1,2 @@
-obj-$(CONFIG_FS_JFFS2)		+= crc32.o
+obj-$(CONFIG_JFFS2_FS)		+= crc32.o
 obj-$(CONFIG_EFI_PARTITION)	+= crc32.o
diff -u --recursive --new-file pre1/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- pre1/linux/fs/binfmt_misc.c	Sat Oct 20 19:14:42 2001
+++ linux/fs/binfmt_misc.c	Thu Jan 17 14:25:43 2002
@@ -49,6 +49,8 @@
 } Node;
 
 static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
+static struct vfsmount *bm_mnt;
+static int entry_count = 0;
 
 /* 
  * Check if we support the binfmt
@@ -390,10 +392,15 @@
 	Node *e = inode->u.generic_ip;
 
 	if (e) {
+		struct vfsmount *mnt;
 		write_lock(&entries_lock);
 		list_del(&e->list);
+		mnt = bm_mnt;
+		if (!--entry_count)
+			bm_mnt = NULL;
 		write_unlock(&entries_lock);
 		kfree(e);
+		mntput(mnt);
 	}
 }
 
@@ -404,8 +411,7 @@
 	write_lock(&entries_lock);
 	dentry = e->dentry;
 	if (dentry) {
-		list_del(&e->list);
-		INIT_LIST_HEAD(&e->list);
+		list_del_init(&e->list);
 		e->dentry = NULL;
 	}
 	write_unlock(&entries_lock);
@@ -484,12 +490,16 @@
 	write:		bm_entry_write,
 };
 
+static struct file_system_type bm_fs_type;
+
 /* /register */
 
 static ssize_t bm_register_write(struct file *file, const char *buffer,
 			       size_t count, loff_t *ppos)
 {
 	Node *e;
+	struct inode *inode;
+	struct vfsmount *mnt = NULL;
 	struct dentry *root, *dentry;
 	struct super_block *sb = file->f_vfsmnt->mnt_sb;
 	int err = 0;
@@ -503,31 +513,52 @@
 	down(&root->d_inode->i_sem);
 	dentry = lookup_one_len(e->name, root, strlen(e->name));
 	err = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		down(&root->d_inode->i_zombie);
-		if (dentry->d_inode) {
-			err = -EEXIST;
-		} else {
-			struct inode * inode = bm_get_inode(sb, S_IFREG | 0644);
-			err = -ENOMEM;
+	if (IS_ERR(dentry))
+		goto out;
 
-			if (inode) {
-				write_lock(&entries_lock);
+	down(&root->d_inode->i_zombie);
 
-				e->dentry = dget(dentry);
-				inode->u.generic_ip = e;
-				inode->i_fop = &bm_entry_operations;
-				d_instantiate(dentry, inode);
+	err = -EEXIST;
+	if (dentry->d_inode)
+		goto out2;
 
-				list_add(&e->list, &entries);
-				write_unlock(&entries_lock);
+	inode = bm_get_inode(sb, S_IFREG | 0644);
 
-				err = 0;
-			}
+	err = -ENOMEM;
+	if (!inode)
+		goto out2;
+
+	write_lock(&entries_lock);
+	if (!bm_mnt) {
+		write_unlock(&entries_lock);
+		mnt = kern_mount(&bm_fs_type);
+		if (IS_ERR(mnt)) {
+			err = PTR_ERR(mnt);
+			iput(inode);
+			inode = NULL;
+			goto out2;
 		}
-		up(&root->d_inode->i_zombie);
-		dput(dentry);
+		write_lock(&entries_lock);
+		if (!bm_mnt)
+			bm_mnt = mnt;
 	}
+	mntget(bm_mnt);
+	entry_count++;
+
+	e->dentry = dget(dentry);
+	inode->u.generic_ip = e;
+	inode->i_fop = &bm_entry_operations;
+	d_instantiate(dentry, inode);
+
+	list_add(&e->list, &entries);
+	write_unlock(&entries_lock);
+
+	mntput(mnt);
+	err = 0;
+out2:
+	up(&root->d_inode->i_zombie);
+	dput(dentry);
+out:
 	up(&root->d_inode->i_sem);
 	dput(root);
 
@@ -687,23 +718,13 @@
 
 static DECLARE_FSTYPE(bm_fs_type, "binfmt_misc", bm_read_super, FS_SINGLE|FS_LITTER);
 
-static struct vfsmount *bm_mnt;
-
 static int __init init_misc_binfmt(void)
 {
 	int err = register_filesystem(&bm_fs_type);
 	if (!err) {
-		bm_mnt = kern_mount(&bm_fs_type);
-		err = PTR_ERR(bm_mnt);
-		if (IS_ERR(bm_mnt))
+		err = register_binfmt(&misc_format);
+		if (err)
 			unregister_filesystem(&bm_fs_type);
-		else {
-			err = register_binfmt(&misc_format);
-			if (err) {
-				unregister_filesystem(&bm_fs_type);
-				kern_umount(bm_mnt);
-			}
-		}
 	}
 	return err;
 }
@@ -712,7 +733,6 @@
 {
 	unregister_binfmt(&misc_format);
 	unregister_filesystem(&bm_fs_type);
-	kern_umount(bm_mnt);
 }
 
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file pre1/linux/fs/buffer.c linux/fs/buffer.c
--- pre1/linux/fs/buffer.c	Mon Jan 14 09:38:37 2002
+++ linux/fs/buffer.c	Thu Jan 17 14:29:59 2002
@@ -582,23 +582,13 @@
 	return bh;
 }
 
-void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+void buffer_insert_list(struct buffer_head *bh, struct list_head *list)
 {
 	spin_lock(&lru_list_lock);
 	if (bh->b_inode)
 		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_buffers);
-	spin_unlock(&lru_list_lock);
-}
-
-void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
-{
-	spin_lock(&lru_list_lock);
-	if (bh->b_inode)
-		list_del(&bh->b_inode_buffers);
-	bh->b_inode = inode;
-	list_add(&bh->b_inode_buffers, &inode->i_dirty_data_buffers);
+	bh->b_inode = 1;
+	list_add(&bh->b_inode_buffers, list);
 	spin_unlock(&lru_list_lock);
 }
 
@@ -606,7 +596,7 @@
    remove_inode_queue functions.  */
 static void __remove_inode_queue(struct buffer_head *bh)
 {
-	bh->b_inode = NULL;
+	bh->b_inode = 0;
 	list_del(&bh->b_inode_buffers);
 }
 
@@ -826,73 +816,24 @@
  * any newly dirty buffers for write.
  */
 
-int fsync_inode_buffers(struct inode *inode)
-{
-	struct buffer_head *bh;
-	struct inode tmp;
-	int err = 0, err2;
-	
-	INIT_LIST_HEAD(&tmp.i_dirty_buffers);
-	
-	spin_lock(&lru_list_lock);
-
-	while (!list_empty(&inode->i_dirty_buffers)) {
-		bh = BH_ENTRY(inode->i_dirty_buffers.next);
-		list_del(&bh->b_inode_buffers);
-		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = NULL;
-		else {
-			bh->b_inode = &tmp;
-			list_add(&bh->b_inode_buffers, &tmp.i_dirty_buffers);
-			if (buffer_dirty(bh)) {
-				get_bh(bh);
-				spin_unlock(&lru_list_lock);
-				ll_rw_block(WRITE, 1, &bh);
-				brelse(bh);
-				spin_lock(&lru_list_lock);
-			}
-		}
-	}
-
-	while (!list_empty(&tmp.i_dirty_buffers)) {
-		bh = BH_ENTRY(tmp.i_dirty_buffers.prev);
-		remove_inode_queue(bh);
-		get_bh(bh);
-		spin_unlock(&lru_list_lock);
-		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh))
-			err = -EIO;
-		brelse(bh);
-		spin_lock(&lru_list_lock);
-	}
-	
-	spin_unlock(&lru_list_lock);
-	err2 = osync_inode_buffers(inode);
-
-	if (err)
-		return err;
-	else
-		return err2;
-}
-
-int fsync_inode_data_buffers(struct inode *inode)
+int fsync_buffers_list(struct list_head *list)
 {
 	struct buffer_head *bh;
-	struct inode tmp;
+	struct list_head tmp;
 	int err = 0, err2;
 	
-	INIT_LIST_HEAD(&tmp.i_dirty_data_buffers);
+	INIT_LIST_HEAD(&tmp);
 	
 	spin_lock(&lru_list_lock);
 
-	while (!list_empty(&inode->i_dirty_data_buffers)) {
-		bh = BH_ENTRY(inode->i_dirty_data_buffers.next);
+	while (!list_empty(list)) {
+		bh = BH_ENTRY(list->next);
 		list_del(&bh->b_inode_buffers);
 		if (!buffer_dirty(bh) && !buffer_locked(bh))
-			bh->b_inode = NULL;
+			bh->b_inode = 0;
 		else {
-			bh->b_inode = &tmp;
-			list_add(&bh->b_inode_buffers, &tmp.i_dirty_data_buffers);
+			bh->b_inode = 1;
+			list_add(&bh->b_inode_buffers, &tmp);
 			if (buffer_dirty(bh)) {
 				get_bh(bh);
 				spin_unlock(&lru_list_lock);
@@ -903,8 +844,8 @@
 		}
 	}
 
-	while (!list_empty(&tmp.i_dirty_data_buffers)) {
-		bh = BH_ENTRY(tmp.i_dirty_data_buffers.prev);
+	while (!list_empty(&tmp)) {
+		bh = BH_ENTRY(tmp.prev);
 		remove_inode_queue(bh);
 		get_bh(bh);
 		spin_unlock(&lru_list_lock);
@@ -916,7 +857,7 @@
 	}
 	
 	spin_unlock(&lru_list_lock);
-	err2 = osync_inode_data_buffers(inode);
+	err2 = osync_buffers_list(list);
 
 	if (err)
 		return err;
@@ -935,19 +876,19 @@
  * write will not be flushed to disk by the osync.
  */
 
-int osync_inode_buffers(struct inode *inode)
+int osync_buffers_list(struct list_head *list)
 {
 	struct buffer_head *bh;
-	struct list_head *list;
+	struct list_head *p;
 	int err = 0;
 
 	spin_lock(&lru_list_lock);
 	
  repeat:
 	
-	for (list = inode->i_dirty_buffers.prev; 
-	     bh = BH_ENTRY(list), list != &inode->i_dirty_buffers;
-	     list = bh->b_inode_buffers.prev) {
+	for (p = list->prev; 
+	     bh = BH_ENTRY(p), p != list;
+	     p = bh->b_inode_buffers.prev) {
 		if (buffer_locked(bh)) {
 			get_bh(bh);
 			spin_unlock(&lru_list_lock);
@@ -963,36 +904,6 @@
 	spin_unlock(&lru_list_lock);
 	return err;
 }
-
-int osync_inode_data_buffers(struct inode *inode)
-{
-	struct buffer_head *bh;
-	struct list_head *list;
-	int err = 0;
-
-	spin_lock(&lru_list_lock);
-	
- repeat:
-
-	for (list = inode->i_dirty_data_buffers.prev; 
-	     bh = BH_ENTRY(list), list != &inode->i_dirty_data_buffers;
-	     list = bh->b_inode_buffers.prev) {
-		if (buffer_locked(bh)) {
-			get_bh(bh);
-			spin_unlock(&lru_list_lock);
-			wait_on_buffer(bh);
-			if (!buffer_uptodate(bh))
-				err = -EIO;
-			brelse(bh);
-			spin_lock(&lru_list_lock);
-			goto repeat;
-		}
-	}
-
-	spin_unlock(&lru_list_lock);
-	return err;
-}
-
 
 /*
  * Invalidate any and all dirty buffers on a given inode.  We are
diff -u --recursive --new-file pre1/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- pre1/linux/fs/ext2/balloc.c	Sun Dec 16 12:23:00 2001
+++ linux/fs/ext2/balloc.c	Thu Jan 17 14:24:50 2002
@@ -42,19 +42,20 @@
 	unsigned long group_desc;
 	unsigned long desc;
 	struct ext2_group_desc * gdp;
+	struct ext2_sb_info *sbi = &sb->u.ext2_sb;
 
-	if (block_group >= sb->u.ext2_sb.s_groups_count) {
+	if (block_group >= sbi->s_groups_count) {
 		ext2_error (sb, "ext2_get_group_desc",
 			    "block_group >= groups_count - "
 			    "block_group = %d, groups_count = %lu",
-			    block_group, sb->u.ext2_sb.s_groups_count);
+			    block_group, sbi->s_groups_count);
 
 		return NULL;
 	}
 	
 	group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
 	desc = block_group % EXT2_DESC_PER_BLOCK(sb);
-	if (!sb->u.ext2_sb.s_group_desc[group_desc]) {
+	if (!sbi->s_group_desc[group_desc]) {
 		ext2_error (sb, "ext2_get_group_desc",
 			    "Group descriptor not loaded - "
 			    "block_group = %d, group_desc = %lu, desc = %lu",
@@ -62,10 +63,9 @@
 		return NULL;
 	}
 	
-	gdp = (struct ext2_group_desc *) 
-	      sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
+	gdp = (struct ext2_group_desc *) sbi->s_group_desc[group_desc]->b_data;
 	if (bh)
-		*bh = sb->u.ext2_sb.s_group_desc[group_desc];
+		*bh = sbi->s_group_desc[group_desc];
 	return gdp + desc;
 }
 
@@ -73,37 +73,26 @@
  * Read the bitmap for a given block_group, reading into the specified 
  * slot in the superblock's bitmap cache.
  *
- * Return >=0 on success or a -ve error code.
+ * Return buffer_head on success or NULL in case of failure.
  */
 
-static int read_block_bitmap (struct super_block * sb,
-			       unsigned int block_group,
-			       unsigned long bitmap_nr)
+static struct buffer_head *read_block_bitmap(struct super_block *sb,
+						unsigned int block_group)
 {
 	struct ext2_group_desc * gdp;
 	struct buffer_head * bh = NULL;
-	int retval = -EIO;
 	
 	gdp = ext2_get_group_desc (sb, block_group, NULL);
 	if (!gdp)
 		goto error_out;
-	retval = 0;
 	bh = sb_bread(sb, le32_to_cpu(gdp->bg_block_bitmap));
-	if (!bh) {
+	if (!bh)
 		ext2_error (sb, "read_block_bitmap",
 			    "Cannot read block bitmap - "
 			    "block_group = %d, block_bitmap = %lu",
 			    block_group, (unsigned long) gdp->bg_block_bitmap);
-		retval = -EIO;
-	}
-	/*
-	 * On IO error, just leave a zero in the superblock's block pointer for
-	 * this group.  The IO will be retried next time.
-	 */
 error_out:
-	sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group;
-	sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh;
-	return retval;
+	return bh;
 }
 
 /*
@@ -117,134 +106,65 @@
  * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
  *    this function reads the bitmap without maintaining a LRU cache.
  * 
- * Return the slot used to store the bitmap, or a -ve error code.
+ * Return the buffer_head of the bitmap or ERR_PTR(-ve).
  */
-static int __load_block_bitmap (struct super_block * sb,
-			        unsigned int block_group)
+static struct buffer_head *load_block_bitmap(struct super_block * sb,
+						unsigned int block_group)
 {
-	int i, j, retval = 0;
-	unsigned long block_bitmap_number;
-	struct buffer_head * block_bitmap;
+	struct ext2_sb_info *sbi = &sb->u.ext2_sb;
+	int i, slot = 0;
+	struct buffer_head *bh = sbi->s_block_bitmap[0];
 
-	if (block_group >= sb->u.ext2_sb.s_groups_count)
+	if (block_group >= sbi->s_groups_count)
 		ext2_panic (sb, "load_block_bitmap",
 			    "block_group >= groups_count - "
 			    "block_group = %d, groups_count = %lu",
-			    block_group, sb->u.ext2_sb.s_groups_count);
-
-	if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
-		if (sb->u.ext2_sb.s_block_bitmap[block_group]) {
-			if (sb->u.ext2_sb.s_block_bitmap_number[block_group] ==
-			    block_group)
-				return block_group;
-			ext2_error (sb, "__load_block_bitmap",
-				    "block_group != block_bitmap_number");
-		}
-		retval = read_block_bitmap (sb, block_group, block_group);
-		if (retval < 0)
-			return retval;
-		return block_group;
-	}
-
-	for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
-		    sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++)
-		;
-	if (i < sb->u.ext2_sb.s_loaded_block_bitmaps &&
-  	    sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) {
-		block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i];
-		block_bitmap = sb->u.ext2_sb.s_block_bitmap[i];
-		for (j = i; j > 0; j--) {
-			sb->u.ext2_sb.s_block_bitmap_number[j] =
-				sb->u.ext2_sb.s_block_bitmap_number[j - 1];
-			sb->u.ext2_sb.s_block_bitmap[j] =
-				sb->u.ext2_sb.s_block_bitmap[j - 1];
-		}
-		sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number;
-		sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap;
-
-		/*
-		 * There's still one special case here --- if block_bitmap == 0
-		 * then our last attempt to read the bitmap failed and we have
-		 * just ended up caching that failure.  Try again to read it.
-		 */
-		if (!block_bitmap)
-			retval = read_block_bitmap (sb, block_group, 0);
-	} else {
-		if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
-			sb->u.ext2_sb.s_loaded_block_bitmaps++;
-		else
-			brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
-		for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) {
-			sb->u.ext2_sb.s_block_bitmap_number[j] =
-				sb->u.ext2_sb.s_block_bitmap_number[j - 1];
-			sb->u.ext2_sb.s_block_bitmap[j] =
-				sb->u.ext2_sb.s_block_bitmap[j - 1];
-		}
-		retval = read_block_bitmap (sb, block_group, 0);
-	}
-	return retval;
-}
-
-/*
- * Load the block bitmap for a given block group.  First of all do a couple
- * of fast lookups for common cases and then pass the request onto the guts
- * of the bitmap loader.
- *
- * Return the slot number of the group in the superblock bitmap cache's on
- * success, or a -ve error code.
- *
- * There is still one inconsistency here --- if the number of groups in this
- * filesystems is <= EXT2_MAX_GROUP_LOADED, then we have no way of 
- * differentiating between a group for which we have never performed a bitmap
- * IO request, and a group for which the last bitmap read request failed.
- */
-static inline int load_block_bitmap (struct super_block * sb,
-				     unsigned int block_group)
-{
-	int slot;
+			    block_group, sbi->s_groups_count);
 	
 	/*
 	 * Do the lookup for the slot.  First of all, check if we're asking
 	 * for the same slot as last time, and did we succeed that last time?
 	 */
-	if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 &&
-	    sb->u.ext2_sb.s_block_bitmap_number[0] == block_group &&
-	    sb->u.ext2_sb.s_block_bitmap[0]) {
-		return 0;
-	}
-	/*
-	 * Or can we do a fast lookup based on a loaded group on a filesystem
-	 * small enough to be mapped directly into the superblock?
-	 */
-	else if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && 
-		 sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group &&
-		 sb->u.ext2_sb.s_block_bitmap[block_group]) {
+	if (sbi->s_loaded_block_bitmaps > 0 &&
+	    sbi->s_block_bitmap_number[0] == block_group && bh)
+		goto found;
+
+	if (sbi->s_groups_count <= EXT2_MAX_GROUP_LOADED) {
 		slot = block_group;
-	}
-	/*
-	 * If not, then do a full lookup for this block group.
-	 */
-	else {
-		slot = __load_block_bitmap (sb, block_group);
+		bh = sbi->s_block_bitmap[slot];
+		if (!bh)
+			goto read_it;
+		if (sbi->s_block_bitmap_number[slot] == slot)
+			goto found;
+		ext2_panic (sb, "__load_block_bitmap",
+			    "block_group != block_bitmap_number");
 	}
 
-	/*
-	 * <0 means we just got an error
-	 */
-	if (slot < 0)
-		return slot;
-	
-	/*
-	 * If it's a valid slot, we may still have cached a previous IO error,
-	 * in which case the bh in the superblock cache will be zero.
-	 */
-	if (!sb->u.ext2_sb.s_block_bitmap[slot])
-		return -EIO;
-	
-	/*
-	 * Must have been read in OK to get this far.
-	 */
-	return slot;
+	bh = NULL;
+	for (i = 0; i < sbi->s_loaded_block_bitmaps &&
+		    sbi->s_block_bitmap_number[i] != block_group; i++)
+		;
+	if (i < sbi->s_loaded_block_bitmaps)
+		bh = sbi->s_block_bitmap[i];
+	else if (sbi->s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED)
+		sbi->s_loaded_block_bitmaps++;
+	else
+		brelse (sbi->s_block_bitmap[--i]);
+
+	while (i--) {
+		sbi->s_block_bitmap_number[i+1] = sbi->s_block_bitmap_number[i];
+		sbi->s_block_bitmap[i+1] = sbi->s_block_bitmap[i];
+	}
+
+read_it:
+	if (!bh)
+		bh = read_block_bitmap(sb, block_group);
+	sbi->s_block_bitmap_number[slot] = block_group;
+	sbi->s_block_bitmap[slot] = bh;
+	if (!bh)
+		return ERR_PTR(-EIO);
+found:
+	return bh;
 }
 
 /* Free given blocks, update quota and i_blocks field */
@@ -256,7 +176,6 @@
 	unsigned long block_group;
 	unsigned long bit;
 	unsigned long i;
-	int bitmap_nr;
 	unsigned long overflow;
 	struct super_block * sb;
 	struct ext2_group_desc * gdp;
@@ -293,11 +212,10 @@
 		overflow = bit + count - EXT2_BLOCKS_PER_GROUP(sb);
 		count -= overflow;
 	}
-	bitmap_nr = load_block_bitmap (sb, block_group);
-	if (bitmap_nr < 0)
+	bh = load_block_bitmap (sb, block_group);
+	if (IS_ERR(bh))
 		goto error_return;
 	
-	bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 	gdp = ext2_get_group_desc (sb, block_group, &bh2);
 	if (!gdp)
 		goto error_return;
@@ -361,7 +279,6 @@
 	struct buffer_head * bh2;
 	char * p, * r;
 	int i, j, k, tmp;
-	int bitmap_nr;
 	struct super_block * sb;
 	struct ext2_group_desc * gdp;
 	struct ext2_super_block * es;
@@ -404,12 +321,10 @@
 		if (j)
 			goal_attempts++;
 #endif
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bh = load_block_bitmap (sb, i);
+		if (IS_ERR(bh))
 			goto io_error;
 		
-		bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
-
 		ext2_debug ("goal is at %d:%d.\n", i, j);
 
 		if (!ext2_test_bit(j, bh->b_data)) {
@@ -477,11 +392,10 @@
 	}
 	if (k >= sb->u.ext2_sb.s_groups_count)
 		goto out;
-	bitmap_nr = load_block_bitmap (sb, i);
-	if (bitmap_nr < 0)
+	bh = load_block_bitmap (sb, i);
+	if (IS_ERR(bh))
 		goto io_error;
 	
-	bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 	r = memscan(bh->b_data, 0, EXT2_BLOCKS_PER_GROUP(sb) >> 3);
 	j = (r - bh->b_data) << 3;
 	if (j < EXT2_BLOCKS_PER_GROUP(sb))
@@ -619,7 +533,6 @@
 #ifdef EXT2FS_DEBUG
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
-	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i;
 	
@@ -629,16 +542,16 @@
 	bitmap_count = 0;
 	gdp = NULL;
 	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
+		struct buffer_head *bh;
 		gdp = ext2_get_group_desc (sb, i, NULL);
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bh = load_block_bitmap (sb, i);
+		if (IS_ERR(bh))
 			continue;
 		
-		x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr],
-				     sb->s_blocksize);
+		x = ext2_count_free (bh, sb->s_blocksize);
 		printk ("group %d: stored = %d, counted = %lu\n",
 			i, le16_to_cpu(gdp->bg_free_blocks_count), x);
 		bitmap_count += x;
@@ -720,7 +633,6 @@
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x, j;
 	unsigned long desc_blocks;
-	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i;
 
@@ -733,11 +645,9 @@
 		if (!gdp)
 			continue;
 		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
-		bitmap_nr = load_block_bitmap (sb, i);
-		if (bitmap_nr < 0)
+		bh = load_block_bitmap (sb, i);
+		if (IS_ERR(bh))
 			continue;
-
-		bh = EXT2_SB(sb)->s_block_bitmap[bitmap_nr];
 
 		if (ext2_bg_has_super(sb, i) && !ext2_test_bit(0, bh->b_data))
 			ext2_error(sb, __FUNCTION__,
diff -u --recursive --new-file pre1/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- pre1/linux/fs/fat/inode.c	Wed Jan 16 11:16:28 2002
+++ linux/fs/fat/inode.c	Wed Jan 16 10:20:23 2002
@@ -559,9 +559,9 @@
 	struct buffer_head *bh;
 	struct fat_boot_sector *b;
 	struct msdos_sb_info *sbi = MSDOS_SB(sb);
-	int logical_sector_size, fat_clusters;
+	int logical_sector_size, fat_clusters, debug, cp;
 	unsigned int total_sectors, rootdir_sectors;
-	int debug, cp;
+	long error = -EIO;
 	char buf[50];
 	int i;
 	char cvf_format[21];
@@ -786,9 +786,8 @@
 	return sb;
 
 out_invalid:
-	if (!silent)
-		printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
-			sb->s_id);
+	error = 0;
+
 out_fail:
 	if (sbi->nls_io)
 		unload_nls(sbi->nls_io);
@@ -799,8 +798,8 @@
 	if (sbi->private_data)
 		kfree(sbi->private_data);
 	sbi->private_data = NULL;
- 
-	return NULL;
+
+	return ERR_PTR(error);
 }
 
 int fat_statfs(struct super_block *sb,struct statfs *buf)
diff -u --recursive --new-file pre1/linux/fs/inode.c linux/fs/inode.c
--- pre1/linux/fs/inode.c	Mon Jan 14 10:10:43 2002
+++ linux/fs/inode.c	Thu Jan 17 14:30:00 2002
@@ -75,13 +75,53 @@
 
 static kmem_cache_t * inode_cachep;
 
-#define alloc_inode() \
-	 ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+static struct inode *alloc_inode(struct super_block *sb)
+{
+	static struct address_space_operations empty_aops;
+	static struct inode_operations empty_iops;
+	static struct file_operations empty_fops;
+	struct inode *inode;
+
+	if (sb->s_op->alloc_inode)
+		inode = sb->s_op->alloc_inode(sb);
+	else
+		inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
+
+	if (inode) {
+		inode->i_sb = sb;
+		inode->i_dev = sb->s_dev;
+		inode->i_blkbits = sb->s_blocksize_bits;
+		inode->i_flags = 0;
+		atomic_set(&inode->i_count, 1);
+		inode->i_sock = 0;
+		inode->i_op = &empty_iops;
+		inode->i_fop = &empty_fops;
+		inode->i_nlink = 1;
+		atomic_set(&inode->i_writecount, 0);
+		inode->i_size = 0;
+		inode->i_blocks = 0;
+		inode->i_generation = 0;
+		memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
+		inode->i_pipe = NULL;
+		inode->i_bdev = NULL;
+		inode->i_cdev = NULL;
+		inode->i_data.a_ops = &empty_aops;
+		inode->i_data.host = inode;
+		inode->i_data.gfp_mask = GFP_HIGHUSER;
+		inode->i_mapping = &inode->i_data;
+		memset(&inode->u, 0, sizeof(inode->u));
+	}
+	return inode;
+}
+
 static void destroy_inode(struct inode *inode) 
 {
 	if (inode_has_buffers(inode))
 		BUG();
-	kmem_cache_free(inode_cachep, (inode));
+	if (inode->i_sb->s_op->destroy_inode)
+		inode->i_sb->s_op->destroy_inode(inode);
+	else
+		kmem_cache_free(inode_cachep, (inode));
 }
 
 
@@ -90,27 +130,30 @@
  * once, because the fields are idempotent across use
  * of the inode, so let the slab aware of that.
  */
+void inode_init_once(struct inode *inode)
+{
+	memset(inode, 0, sizeof(*inode));
+	init_waitqueue_head(&inode->i_wait);
+	INIT_LIST_HEAD(&inode->i_hash);
+	INIT_LIST_HEAD(&inode->i_data.clean_pages);
+	INIT_LIST_HEAD(&inode->i_data.dirty_pages);
+	INIT_LIST_HEAD(&inode->i_data.locked_pages);
+	INIT_LIST_HEAD(&inode->i_dentry);
+	INIT_LIST_HEAD(&inode->i_dirty_buffers);
+	INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
+	INIT_LIST_HEAD(&inode->i_devices);
+	sema_init(&inode->i_sem, 1);
+	sema_init(&inode->i_zombie, 1);
+	spin_lock_init(&inode->i_data.i_shared_lock);
+}
+
 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
 {
 	struct inode * inode = (struct inode *) foo;
 
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR)
-	{
-		memset(inode, 0, sizeof(*inode));
-		init_waitqueue_head(&inode->i_wait);
-		INIT_LIST_HEAD(&inode->i_hash);
-		INIT_LIST_HEAD(&inode->i_data.clean_pages);
-		INIT_LIST_HEAD(&inode->i_data.dirty_pages);
-		INIT_LIST_HEAD(&inode->i_data.locked_pages);
-		INIT_LIST_HEAD(&inode->i_dentry);
-		INIT_LIST_HEAD(&inode->i_dirty_buffers);
-		INIT_LIST_HEAD(&inode->i_dirty_data_buffers);
-		INIT_LIST_HEAD(&inode->i_devices);
-		sema_init(&inode->i_sem, 1);
-		sema_init(&inode->i_zombie, 1);
-		spin_lock_init(&inode->i_data.i_shared_lock);
-	}
+		inode_init_once(inode);
 }
 
 /*
@@ -768,72 +811,28 @@
 	return inode;
 }
 
-/*
- * This just initializes the inode fields
- * to known values before returning the inode..
- *
- * i_sb, i_ino, i_count, i_state and the lists have
- * been initialized elsewhere..
- */
-static void clean_inode(struct inode *inode)
-{
-	static struct address_space_operations empty_aops;
-	static struct inode_operations empty_iops;
-	static struct file_operations empty_fops;
-	memset(&inode->u, 0, sizeof(inode->u));
-	inode->i_sock = 0;
-	inode->i_op = &empty_iops;
-	inode->i_fop = &empty_fops;
-	inode->i_nlink = 1;
-	atomic_set(&inode->i_writecount, 0);
-	inode->i_size = 0;
-	inode->i_blocks = 0;
-	inode->i_generation = 0;
-	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
-	inode->i_pipe = NULL;
-	inode->i_bdev = NULL;
-	inode->i_cdev = NULL;
-	inode->i_data.a_ops = &empty_aops;
-	inode->i_data.host = inode;
-	inode->i_data.gfp_mask = GFP_HIGHUSER;
-	inode->i_mapping = &inode->i_data;
-}
-
 /**
- * get_empty_inode 	- obtain an inode
+ *	new_inode 	- obtain an inode
+ *	@sb: superblock
  *
- * This is called by things like the networking layer
- * etc that want to get an inode without any inode
- * number, or filesystems that allocate new inodes with
- * no pre-existing information.
- *
- * On a successful return the inode pointer is returned. On a failure
- * a %NULL pointer is returned. The returned inode is not on any superblock
- * lists.
+ *	Allocates a new inode for given superblock.
  */
  
-struct inode * get_empty_inode(void)
+struct inode *new_inode(struct super_block *sb)
 {
 	static unsigned long last_ino;
 	struct inode * inode;
 
 	spin_lock_prefetch(&inode_lock);
 	
-	inode = alloc_inode();
-	if (inode)
-	{
+	inode = alloc_inode(sb);
+	if (inode) {
 		spin_lock(&inode_lock);
 		inodes_stat.nr_inodes++;
 		list_add(&inode->i_list, &inode_in_use);
-		inode->i_sb = NULL;
-		inode->i_dev = NODEV;
-		inode->i_blkbits = 0;
 		inode->i_ino = ++last_ino;
-		inode->i_flags = 0;
-		atomic_set(&inode->i_count, 1);
 		inode->i_state = 0;
 		spin_unlock(&inode_lock);
-		clean_inode(inode);
 	}
 	return inode;
 }
@@ -848,7 +847,7 @@
 {
 	struct inode * inode;
 
-	inode = alloc_inode();
+	inode = alloc_inode(sb);
 	if (inode) {
 		struct inode * old;
 
@@ -859,16 +858,9 @@
 			inodes_stat.nr_inodes++;
 			list_add(&inode->i_list, &inode_in_use);
 			list_add(&inode->i_hash, head);
-			inode->i_sb = sb;
-			inode->i_dev = sb->s_dev;
-			inode->i_blkbits = sb->s_blocksize_bits;
 			inode->i_ino = ino;
-			inode->i_flags = 0;
-			atomic_set(&inode->i_count, 1);
 			inode->i_state = I_LOCK;
 			spin_unlock(&inode_lock);
-
-			clean_inode(inode);
 
 			/* reiserfs specific hack right here.  We don't
 			** want this to last, and are looking for VFS changes
diff -u --recursive --new-file pre1/linux/fs/intermezzo/kml_reint.c linux/fs/intermezzo/kml_reint.c
--- pre1/linux/fs/intermezzo/kml_reint.c	Sun Nov 11 10:20:21 2001
+++ linux/fs/intermezzo/kml_reint.c	Tue Jan 15 14:33:55 2002
@@ -17,7 +17,6 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-#include <asm/mmu_context.h>
 #include <linux/intermezzo_fs.h>
 #include <linux/intermezzo_kml.h>
 #include <linux/intermezzo_psdev.h>
diff -u --recursive --new-file pre1/linux/fs/jbd/commit.c linux/fs/jbd/commit.c
--- pre1/linux/fs/jbd/commit.c	Sun Dec 30 16:59:00 2001
+++ linux/fs/jbd/commit.c	Tue Jan 15 13:53:51 2002
@@ -224,14 +224,13 @@
 		}
 	} while (jh != last_jh);
 
-	if (bufs || current->need_resched) {
+	if (bufs || need_resched()) {
 		jbd_debug(2, "submit %d writes\n", bufs);
 		spin_unlock(&journal_datalist_lock);
 		unlock_journal(journal);
 		if (bufs)
 			ll_rw_block(WRITE, bufs, wbuf);
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 		journal_brelse_array(wbuf, bufs);
 		lock_journal(journal);
 		spin_lock(&journal_datalist_lock);
@@ -458,8 +457,7 @@
 				bh->b_end_io = journal_end_buffer_io_sync;
 				submit_bh(WRITE, bh);
 			}
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 			lock_journal(journal);
 
 			/* Force a new descriptor to be generated next
diff -u --recursive --new-file pre1/linux/fs/jffs2/background.c linux/fs/jffs2/background.c
--- pre1/linux/fs/jffs2/background.c	Mon Jan  7 12:55:16 2002
+++ linux/fs/jffs2/background.c	Tue Jan 15 13:53:51 2002
@@ -127,8 +127,7 @@
 			schedule();
 		}
                 
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 
                 /* Put_super will send a SIGKILL and then wait on the sem. 
                  */
diff -u --recursive --new-file pre1/linux/fs/jffs2/erase.c linux/fs/jffs2/erase.c
--- pre1/linux/fs/jffs2/erase.c	Thu Jan 10 16:23:46 2002
+++ linux/fs/jffs2/erase.c	Tue Jan 15 13:53:51 2002
@@ -131,8 +131,7 @@
 		
 		jffs2_erase_block(c, jeb);
 		/* Be nice */
-		if (current->need_resched)
-			schedule();
+		cond_resched();
 		spin_lock_bh(&c->erase_completion_lock);
 	}
 	spin_unlock_bh(&c->erase_completion_lock);
diff -u --recursive --new-file pre1/linux/fs/jffs2/nodemgmt.c linux/fs/jffs2/nodemgmt.c
--- pre1/linux/fs/jffs2/nodemgmt.c	Thu Oct  4 15:13:18 2001
+++ linux/fs/jffs2/nodemgmt.c	Tue Jan 15 13:53:51 2002
@@ -101,8 +101,7 @@
 			if (ret)
 				return ret;
 
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 
 			if (signal_pending(current))
 				return -EINTR;
diff -u --recursive --new-file pre1/linux/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c
--- pre1/linux/fs/msdos/msdosfs_syms.c	Sun Dec 30 16:58:58 2001
+++ linux/fs/msdos/msdosfs_syms.c	Wed Jan 16 10:20:23 2002
@@ -23,7 +23,6 @@
 EXPORT_SYMBOL(msdos_rename);
 EXPORT_SYMBOL(msdos_rmdir);
 EXPORT_SYMBOL(msdos_unlink);
-EXPORT_SYMBOL(msdos_read_super);
 EXPORT_SYMBOL(msdos_put_super);
 
 static DECLARE_FSTYPE_DEV(msdos_fs_type, "msdos", msdos_read_super);
diff -u --recursive --new-file pre1/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- pre1/linux/fs/msdos/namei.c	Sun Dec 30 10:53:53 2001
+++ linux/fs/msdos/namei.c	Wed Jan 16 10:20:23 2002
@@ -589,7 +589,15 @@
 
 	MSDOS_SB(sb)->options.isvfat = 0;
 	res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
-	if (res)
-		sb->s_root->d_op = &msdos_dentry_operations;
+	if (IS_ERR(res))
+		return NULL;
+	if (res == NULL) {
+		if (!silent)
+			printk(KERN_INFO "VFS: Can't find a valid"
+			       " MSDOS filesystem on dev %s.\n", sb->s_id);
+		return NULL;
+	}
+
+	sb->s_root->d_op = &msdos_dentry_operations;
 	return res;
 }
diff -u --recursive --new-file pre1/linux/fs/namei.c linux/fs/namei.c
--- pre1/linux/fs/namei.c	Mon Jan 14 09:41:57 2002
+++ linux/fs/namei.c	Tue Jan 15 13:53:51 2002
@@ -339,7 +339,7 @@
 		goto loop;
 	if (current->total_link_count >= 40)
 		goto loop;
-	if (current->need_resched) {
+	if (need_resched()) {
 		current->state = TASK_RUNNING;
 		schedule();
 	}
diff -u --recursive --new-file pre1/linux/fs/reiserfs/inode.c linux/fs/reiserfs/inode.c
--- pre1/linux/fs/reiserfs/inode.c	Fri Jan  4 09:42:12 2002
+++ linux/fs/reiserfs/inode.c	Thu Jan 17 14:29:59 2002
@@ -101,9 +101,9 @@
 }
 
 static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
-    struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ;
+    struct list_head *list = &(SB_JOURNAL(inode->i_sb)->j_dirty_buffers) ;
 
-    buffer_insert_inode_queue(bh, jinode) ;
+    buffer_insert_list(bh, list) ;
 }
 
 //
@@ -808,8 +808,7 @@
 	/* inserting indirect pointers for a hole can take a 
 	** long time.  reschedule if needed
 	*/
-	if (current->need_resched)
-	    schedule() ;
+	cond_resched();
 
 	retval = search_for_position_by_key (inode->i_sb, &key, &path);
 	if (retval == IO_ERROR) {
diff -u --recursive --new-file pre1/linux/fs/reiserfs/journal.c linux/fs/reiserfs/journal.c
--- pre1/linux/fs/reiserfs/journal.c	Mon Jan 14 09:38:46 2002
+++ linux/fs/reiserfs/journal.c	Thu Jan 17 14:29:59 2002
@@ -1897,7 +1897,7 @@
   memset(journal_writers, 0, sizeof(char *) * 512) ; /* debug code */
 
   INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_bitmap_nodes) ;
-  INIT_LIST_HEAD(&(SB_JOURNAL(p_s_sb)->j_dummy_inode.i_dirty_buffers)) ;
+  INIT_LIST_HEAD(&SB_JOURNAL(p_s_sb)->j_dirty_buffers) ;
   reiserfs_allocate_list_bitmaps(p_s_sb, SB_JOURNAL(p_s_sb)->j_list_bitmap, 
                                  SB_BMAP_NR(p_s_sb)) ;
   allocate_bitmap_nodes(p_s_sb) ;
@@ -2902,7 +2902,7 @@
   SB_JOURNAL_LIST_INDEX(p_s_sb) = jindex ;
 
   /* write any buffers that must hit disk before this commit is done */
-  fsync_inode_buffers(&(SB_JOURNAL(p_s_sb)->j_dummy_inode)) ;
+  fsync_buffers_list(&(SB_JOURNAL(p_s_sb)->j_dirty_buffers)) ;
 
   /* honor the flush and async wishes from the caller */
   if (flush) {
diff -u --recursive --new-file pre1/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- pre1/linux/fs/umsdos/inode.c	Tue Jan  1 18:55:00 2002
+++ linux/fs/umsdos/inode.c	Wed Jan 16 10:20:23 2002
@@ -363,10 +363,17 @@
 	 * Call msdos-fs to mount the disk.
 	 * Note: this returns res == sb or NULL
 	 */
-	res = msdos_read_super (sb, data, silent);
+	MSDOS_SB(sb)->options.isvfat = 0;
+	res = fat_read_super(sb, data, silent, &umsdos_rdir_inode_operations);
 
-	if (!res)
-		goto out_fail;
+	if (IS_ERR(res))
+		return NULL;
+	if (res == NULL) {
+		if (!silent)
+			printk(KERN_INFO "VFS: Can't find a valid "
+			       "UMSDOS filesystem on dev %s.\n", sb->s_id);
+		return NULL;
+	}
 
 	printk (KERN_INFO "UMSDOS 0.86k "
 		"(compatibility level %d.%d, fast msdos)\n", 
@@ -394,10 +401,6 @@
 		dget (sb->s_root); sb->s_root = dget(new_root);
 	}
 	return sb;
-
-out_fail:
-	printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
-	return NULL;
 }
 
 /*
diff -u --recursive --new-file pre1/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- pre1/linux/fs/vfat/namei.c	Wed Jan 16 11:16:28 2002
+++ linux/fs/vfat/namei.c	Wed Jan 16 10:20:23 2002
@@ -1266,10 +1266,15 @@
 	struct super_block *res;
   
 	MSDOS_SB(sb)->options.isvfat = 1;
-
 	res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations);
-	if (res == NULL)
+	if (IS_ERR(res))
 		return NULL;
+	if (res == NULL) {
+		if (!silent)
+			printk(KERN_INFO "VFS: Can't find a valid"
+			       " VFAT filesystem on dev %s.\n", sb->s_id);
+		return NULL;
+	}
 
 	if (parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
 		MSDOS_SB(sb)->options.dotsOK = 0;
diff -u --recursive --new-file pre1/linux/include/asm-arm/arch-arc/system.h linux/include/asm-arm/arch-arc/system.h
--- pre1/linux/include/asm-arm/arch-arc/system.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/arch-arc/system.h	Tue Jan 15 13:53:51 2002
@@ -10,7 +10,7 @@
 
 static void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter);
+	while (!need_resched() && !hlt_counter);
 }
 
 static inline void arch_reset(char mode)
diff -u --recursive --new-file pre1/linux/include/asm-arm/arch-cl7500/system.h linux/include/asm-arm/arch-cl7500/system.h
--- pre1/linux/include/asm-arm/arch-cl7500/system.h	Thu Apr 12 12:20:31 2001
+++ linux/include/asm-arm/arch-cl7500/system.h	Tue Jan 15 13:53:51 2002
@@ -10,7 +10,7 @@
 
 static void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter)
+	while (!need_resched() && !hlt_counter)
 		iomd_writeb(0, IOMD_SUSMODE);
 }
 
diff -u --recursive --new-file pre1/linux/include/asm-arm/arch-ebsa110/system.h linux/include/asm-arm/arch-ebsa110/system.h
--- pre1/linux/include/asm-arm/arch-ebsa110/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-ebsa110/system.h	Tue Jan 15 13:53:51 2002
@@ -17,7 +17,7 @@
  * will stop our MCLK signal (which provides the clock for the glue
  * logic, and therefore the timer interrupt).
  *
- * Instead, we spin, waiting for either hlt_counter or need_resched
+ * Instead, we spin, waiting for either hlt_counter or need_resched()
  * to be set.  If we have been spinning for 2cs, then we drop the
  * core clock down to the memory clock.
  */
@@ -28,13 +28,13 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		/* do nothing slowly */
 	}
 
diff -u --recursive --new-file pre1/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h
--- pre1/linux/include/asm-arm/arch-ebsa285/system.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/arch-ebsa285/system.h	Tue Jan 15 13:53:51 2002
@@ -20,14 +20,14 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 		cpu_do_idle(IDLE_WAIT_FAST);
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		cpu_do_idle(IDLE_WAIT_SLOW);
 	}
 
diff -u --recursive --new-file pre1/linux/include/asm-arm/arch-nexuspci/system.h linux/include/asm-arm/arch-nexuspci/system.h
--- pre1/linux/include/asm-arm/arch-nexuspci/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-nexuspci/system.h	Tue Jan 15 13:53:51 2002
@@ -16,7 +16,7 @@
 
 static void arch_idle(void)
 {
-	while (!current->need_resched && !hlt_counter)
+	while (!need_resched() && !hlt_counter)
 		cpu_do_idle(IDLE_WAIT_SLOW);
 }
 
diff -u --recursive --new-file pre1/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h
--- pre1/linux/include/asm-arm/arch-rpc/system.h	Sun Aug 12 11:14:00 2001
+++ linux/include/asm-arm/arch-rpc/system.h	Tue Jan 15 13:53:51 2002
@@ -18,14 +18,14 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 		cpu_do_idle(IDLE_WAIT_FAST);
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		cpu_do_idle(IDLE_WAIT_SLOW);
 	}
 
diff -u --recursive --new-file pre1/linux/include/asm-arm/arch-sa1100/system.h linux/include/asm-arm/arch-sa1100/system.h
--- pre1/linux/include/asm-arm/arch-sa1100/system.h	Thu Oct 25 13:53:54 2001
+++ linux/include/asm-arm/arch-sa1100/system.h	Tue Jan 15 13:53:51 2002
@@ -10,7 +10,7 @@
 	if (!hlt_counter) {
 		int flags;
 		local_irq_save(flags);
-		if (!current->need_resched)
+		if (!need_resched())
 			cpu_do_idle(0);
 		local_irq_restore(flags);
 	}
diff -u --recursive --new-file pre1/linux/include/asm-arm/arch-tbox/system.h linux/include/asm-arm/arch-tbox/system.h
--- pre1/linux/include/asm-arm/arch-tbox/system.h	Mon Sep 18 15:15:23 2000
+++ linux/include/asm-arm/arch-tbox/system.h	Tue Jan 15 13:53:51 2002
@@ -13,14 +13,14 @@
 	start_idle = jiffies;
 
 	do {
-		if (current->need_resched || hlt_counter)
+		if (need_resched() || hlt_counter)
 			goto slow_out;
 		cpu_do_idle(IDLE_WAIT_FAST);
 	} while (time_before(jiffies, start_idle + HZ/50));
 
 	cpu_do_idle(IDLE_CLOCK_SLOW);
 
-	while (!current->need_resched && !hlt_counter) {
+	while (!need_resched() && !hlt_counter) {
 		cpu_do_idle(IDLE_WAIT_SLOW);
 	}
 
diff -u --recursive --new-file pre1/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h
--- pre1/linux/include/asm-i386/mmu_context.h	Mon Jan 14 13:27:07 2002
+++ linux/include/asm-i386/mmu_context.h	Thu Jan 17 17:13:00 2002
@@ -1,5 +1,5 @@
-#ifndef __I386_MMU_CONTEXT_H
-#define __I386_MMU_CONTEXT_H
+#ifndef __I386_SCHED_H
+#define __I386_SCHED_H
 
 #include <linux/config.h>
 #include <asm/desc.h>
@@ -16,14 +16,13 @@
 # error update this function.
 #endif
 
-static inline int sched_find_first_zero_bit(char *bitmap)
+static inline int sched_find_first_zero_bit(unsigned long *b)
 {
-	unsigned int *b = (unsigned int *)bitmap;
 	unsigned int rt;
 
 	rt = b[0] & b[1] & b[2] & b[3];
 	if (unlikely(rt != 0xffffffff))
-		return find_first_zero_bit(bitmap, MAX_RT_PRIO);
+		return find_first_zero_bit(b, MAX_RT_PRIO);
 
 	if (b[4] != ~0)
 		return ffz(b[4]) + MAX_RT_PRIO;
diff -u --recursive --new-file pre1/linux/include/asm-i386/smplock.h linux/include/asm-i386/smplock.h
--- pre1/linux/include/asm-i386/smplock.h	Mon Jan 14 13:27:16 2002
+++ linux/include/asm-i386/smplock.h	Thu Jan 17 17:10:31 2002
@@ -19,8 +19,8 @@
 do {						\
 	if (unlikely(task->lock_depth >= 0)) {	\
 		spin_unlock(&kernel_flag);	\
-		release_irqlock(cpu);		\
-		__sti();			\
+		if (global_irq_holder == (cpu))	\
+			BUG();			\
 	}					\
 } while (0)
 
diff -u --recursive --new-file pre1/linux/include/linux/blk.h linux/include/linux/blk.h
--- pre1/linux/include/linux/blk.h	Mon Jan 14 13:28:11 2002
+++ linux/include/linux/blk.h	Thu Jan 17 17:11:37 2002
@@ -90,9 +90,9 @@
 
 #define _elv_add_request(q, rq, back, p) do {				      \
 	if ((back))							      \
-		_elv_add_request_core((q), (rq), (q)->queue_head.prev, (p)); \
+		_elv_add_request_core((q), (rq), (q)->queue_head.prev, (p));  \
 	else								      \
-		_elv_add_request_core((q), (rq), &(q)->queue_head, 0);	      \
+		_elv_add_request_core((q), (rq), &(q)->queue_head, (p));      \
 } while (0)
 
 #define elv_add_request(q, rq, back) _elv_add_request((q), (rq), (back), 1)
diff -u --recursive --new-file pre1/linux/include/linux/file.h linux/include/linux/file.h
--- pre1/linux/include/linux/file.h	Wed Jan 16 11:16:28 2002
+++ linux/include/linux/file.h	Thu Jan 17 17:10:22 2002
@@ -5,12 +5,9 @@
 #ifndef __LINUX_FILE_H
 #define __LINUX_FILE_H
 
-#ifndef _LINUX_POSIX_TYPES_H	/* __FD_CLR */
+#include <asm/atomic.h>
 #include <linux/posix_types.h>
-#endif
-#ifndef __LINUX_COMPILER_H	/* unlikely */
 #include <linux/compiler.h>
-#endif
 
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
diff -u --recursive --new-file pre1/linux/include/linux/fs.h linux/include/linux/fs.h
--- pre1/linux/include/linux/fs.h	Mon Jan 14 13:27:08 2002
+++ linux/include/linux/fs.h	Thu Jan 17 17:10:23 2002
@@ -262,7 +262,7 @@
 
 	wait_queue_head_t b_wait;
 
-	struct inode *	     b_inode;
+	int b_inode;				/* will go away */
 	struct list_head     b_inode_buffers;	/* doubly linked list of inode dirty buffers */
 };
 
@@ -859,6 +859,9 @@
  * without the big kernel lock held in all filesystems.
  */
 struct super_operations {
+   	struct inode *(*alloc_inode)(struct super_block *sb);
+	void (*destroy_inode)(struct inode *);
+
 	void (*read_inode) (struct inode *);
   
   	/* reiserfs kludge.  reiserfs needs 64 bits of information to
@@ -1151,7 +1154,16 @@
 extern void FASTCALL(__mark_dirty(struct buffer_head *bh));
 extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh));
 extern void FASTCALL(mark_buffer_dirty(struct buffer_head *bh));
-extern void FASTCALL(buffer_insert_inode_data_queue(struct buffer_head *, struct inode *));
+extern void FASTCALL(buffer_insert_list(struct buffer_head *, struct list_head *));
+
+static inline void buffer_insert_inode_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_buffers);
+}
+static inline void buffer_insert_inode_data_queue(struct buffer_head *bh, struct inode *inode)
+{
+	buffer_insert_list(bh, &inode->i_dirty_data_buffers);
+}
 
 #define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
 
@@ -1219,10 +1231,16 @@
 extern int fsync_super(struct super_block *);
 extern int fsync_no_super(struct block_device *);
 extern void sync_inodes_sb(struct super_block *);
-extern int osync_inode_buffers(struct inode *);
-extern int osync_inode_data_buffers(struct inode *);
-extern int fsync_inode_buffers(struct inode *);
-extern int fsync_inode_data_buffers(struct inode *);
+extern int osync_buffers_list(struct list_head *);
+extern int fsync_buffers_list(struct list_head *);
+static inline int fsync_inode_buffers(struct inode *inode)
+{
+	return fsync_buffers_list(&inode->i_dirty_buffers);
+}
+static inline int fsync_inode_data_buffers(struct inode *inode)
+{
+	return fsync_buffers_list(&inode->i_dirty_data_buffers);
+}
 extern int inode_has_buffers(struct inode *);
 extern void filemap_fdatasync(struct address_space *);
 extern void filemap_fdatawait(struct address_space *);
@@ -1327,6 +1345,7 @@
 #define user_path_walk(name,nd)	 __user_walk(name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, nd)
 #define user_path_walk_link(name,nd) __user_walk(name, LOOKUP_POSITIVE, nd)
 
+extern void inode_init_once(struct inode *);
 extern void iput(struct inode *);
 extern void force_delete(struct inode *);
 extern struct inode * igrab(struct inode *);
@@ -1340,20 +1359,8 @@
 }
 
 extern void clear_inode(struct inode *);
-extern struct inode * get_empty_inode(void);
-
-static inline struct inode * new_inode(struct super_block *sb)
-{
-	struct inode *inode = get_empty_inode();
-	if (inode) {
-		inode->i_sb = sb;
-		inode->i_dev = sb->s_dev;
-		inode->i_blkbits = sb->s_blocksize_bits;
-	}
-	return inode;
-}
+extern struct inode *new_inode(struct super_block *);
 extern void remove_suid(struct inode *inode);
-
 extern void insert_inode_hash(struct inode *);
 extern void remove_inode_hash(struct inode *);
 extern struct file * get_empty_filp(void);
diff -u --recursive --new-file pre1/linux/include/linux/ide.h linux/include/linux/ide.h
--- pre1/linux/include/linux/ide.h	Wed Jan 16 11:16:28 2002
+++ linux/include/linux/ide.h	Thu Jan 17 17:11:37 2002
@@ -884,6 +884,9 @@
  */
 #define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
 
+#define task_rq_offset(rq) \
+	(((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
 extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
 {
 	return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
@@ -892,6 +895,24 @@
 extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
 {
 	bio_kunmap_irq(buffer, flags);
+}
+
+/*
+ * for now, taskfile requests are special :/
+ */
+extern inline char *ide_map_rq(struct request *rq, unsigned long *flags)
+{
+	if (rq->bio)
+		return ide_map_buffer(rq, flags);
+	else
+		return rq->buffer + task_rq_offset(rq);
+}
+
+extern inline void ide_unmap_rq(struct request *rq, char *buf,
+				unsigned long *flags)
+{
+	if (rq->bio)
+		ide_unmap_buffer(buf, flags);
 }
 
 /*
diff -u --recursive --new-file pre1/linux/include/linux/init.h linux/include/linux/init.h
--- pre1/linux/include/linux/init.h	Mon Jan 14 13:27:05 2002
+++ linux/include/linux/init.h	Thu Jan 17 17:10:21 2002
@@ -50,8 +50,26 @@
 
 extern initcall_t __initcall_start, __initcall_end;
 
-#define __initcall(fn)								\
-	static initcall_t __initcall_##fn __init_call = fn
+/* initcalls are now grouped by functionality into separate 
+ * subsections. Ordering inside the subsections is determined
+ * by link order. 
+ * For backwards compatability, initcall() puts the call in 
+ * the device init subsection.
+ */
+
+#define __define_initcall(level,fn) \
+	static initcall_t __initcall_##fn __attribute__ ((unused,__section__ (".initcall" level ".init"))) = fn
+
+#define early_arch_initcall(fn)		__define_initcall("1",fn)
+#define mem_initcall(fn)		__define_initcall("2",fn)
+#define subsys_initcall(fn)		__define_initcall("3",fn)
+#define arch_initcall(fn)		__define_initcall("4",fn)
+#define fs_initcall(fn)			__define_initcall("5",fn)
+#define device_initcall(fn)		__define_initcall("6",fn)
+#define late_initcall(fn)		__define_initcall("7",fn)
+
+#define __initcall(fn) device_initcall(fn)
+
 #define __exitcall(fn)								\
 	static exitcall_t __exitcall_##fn __exit_call = fn
 
@@ -80,7 +98,7 @@
 #define __initdata	__attribute__ ((__section__ (".data.init")))
 #define __exitdata	__attribute__ ((unused, __section__ (".data.exit")))
 #define __initsetup	__attribute__ ((unused,__section__ (".setup.init")))
-#define __init_call	__attribute__ ((unused,__section__ (".initcall.init")))
+#define __init_call(level)  __attribute__ ((unused,__section__ (".initcall" level ".init")))
 #define __exit_call	__attribute__ ((unused,__section__ (".exitcall.exit")))
 
 /* For assembly routines */
@@ -140,6 +158,14 @@
 	{ return x; }
 
 #define __setup(str,func) /* nothing */
+
+#define early_arch_initcall(fn)		module_init(fn)
+#define mem_initcall(fn)		module_init(fn)
+#define subsys_initcall(fn)		module_init(fn)
+#define arch_initcall(fn)		module_init(fn)
+#define fs_initcall(fn)			module_init(fn)
+#define device_initcall(fn)		module_init(fn)
+#define late_initcall(fn)		module_init(fn)
 
 #endif
 
diff -u --recursive --new-file pre1/linux/include/linux/init_task.h linux/include/linux/init_task.h
--- pre1/linux/include/linux/init_task.h	Wed Jan 16 11:16:28 2002
+++ linux/include/linux/init_task.h	Thu Jan 17 17:14:50 2002
@@ -1,9 +1,7 @@
 #ifndef _LINUX__INIT_TASK_H
 #define _LINUX__INIT_TASK_H
 
-#ifndef __LINUX_FILE_H
 #include <linux/file.h>
-#endif
 
 #define INIT_FILES \
 { 							\
diff -u --recursive --new-file pre1/linux/include/linux/isdn.h linux/include/linux/isdn.h
--- pre1/linux/include/linux/isdn.h	Sun Dec 30 10:31:51 2001
+++ linux/include/linux/isdn.h	Thu Jan 17 14:04:15 2002
@@ -178,8 +178,6 @@
  * the correspondent code in isdn.c
  */
 
-#define ISDN_MINOR_B        0
-#define ISDN_MINOR_BMAX     (ISDN_MAX_CHANNELS-1)
 #define ISDN_MINOR_CTRL     64
 #define ISDN_MINOR_CTRLMAX  (64 + (ISDN_MAX_CHANNELS-1))
 #define ISDN_MINOR_PPP      128
diff -u --recursive --new-file pre1/linux/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h
--- pre1/linux/include/linux/mtd/cfi.h	Thu Oct  4 15:13:18 2001
+++ linux/include/linux/mtd/cfi.h	Tue Jan 15 13:53:51 2002
@@ -368,7 +368,7 @@
 static inline void cfi_udelay(int us)
 {
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	if (current->need_resched) {
+	if (need_resched()) {
 		unsigned long t = us * HZ / 1000000;
 		if (t < 1)
 			t = 1;
diff -u --recursive --new-file pre1/linux/include/linux/pci.h linux/include/linux/pci.h
--- pre1/linux/include/linux/pci.h	Mon Jan 14 13:28:08 2002
+++ linux/include/linux/pci.h	Thu Jan 17 17:11:07 2002
@@ -525,7 +525,6 @@
 
 /* Generic PCI functions used internally */
 
-void pci_init(void);
 int pci_bus_exists(const struct list_head *list, int nr);
 struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata);
 struct pci_bus *pci_alloc_primary_bus(int bus);
diff -u --recursive --new-file pre1/linux/include/linux/reiserfs_fs_sb.h linux/include/linux/reiserfs_fs_sb.h
--- pre1/linux/include/linux/reiserfs_fs_sb.h	Mon Jan 14 13:27:06 2002
+++ linux/include/linux/reiserfs_fs_sb.h	Thu Jan 17 17:10:23 2002
@@ -300,7 +300,7 @@
   int j_free_bitmap_nodes ;
   int j_used_bitmap_nodes ;
   struct list_head j_bitmap_nodes ;
-  struct inode j_dummy_inode ;
+  struct list_head j_dirty_buffers ;
   struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ;	/* array of bitmaps to record the deleted blocks */
   struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ;	    /* array of all the journal lists */
   struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; 	    /* hash table for real buffer heads in current trans */ 
diff -u --recursive --new-file pre1/linux/include/linux/sched.h linux/include/linux/sched.h
--- pre1/linux/include/linux/sched.h	Wed Jan 16 11:16:28 2002
+++ linux/include/linux/sched.h	Thu Jan 17 17:10:23 2002
@@ -25,6 +25,7 @@
 #include <linux/signal.h>
 #include <linux/securebits.h>
 #include <linux/fs_struct.h>
+#include <linux/compiler.h>
 
 struct exec_domain;
 
@@ -136,6 +137,8 @@
 extern rwlock_t tasklist_lock;
 extern spinlock_t mmlist_lock;
 
+typedef struct task_struct task_t;
+
 extern void sched_init(void);
 extern void init_idle(void);
 extern void show_state(void);
@@ -144,8 +147,7 @@
 extern void update_process_times(int user);
 extern void update_one_process(struct task_struct *p, unsigned long user,
 			       unsigned long system, int cpu);
-extern void expire_task(struct task_struct *p);
-extern void idle_tick(void);
+extern void scheduler_tick(struct task_struct *p);
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
@@ -221,7 +223,6 @@
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
 
-typedef struct task_struct task_t;
 typedef struct prio_array prio_array_t;
 
 struct task_struct {
@@ -251,7 +252,10 @@
 	prio_array_t *array;
 
 	unsigned int time_slice;
-	unsigned long sleep_jtime;
+
+	#define MAX_SLEEP_AVG (2*HZ)
+	unsigned long sleep_avg;
+	unsigned long sleep_timestamp;
 
 	unsigned long policy;
 	unsigned long cpus_allowed;
@@ -390,30 +394,47 @@
  * them out at 128 to make it easier to search the
  * scheduler bitmap.
  */
-#define MAX_RT_PRIO	128
+#define MAX_RT_PRIO		128
 /*
  * The lower the priority of a process, the more likely it is
  * to run. Priority of a process goes from 0 to 167. The 0-99
  * priority range is allocated to RT tasks, the 128-167 range
  * is for SCHED_OTHER tasks.
  */
-#define MAX_PRIO	(MAX_RT_PRIO+40)
-#define DEF_USER_NICE	0
+#define MAX_PRIO		(MAX_RT_PRIO + 40)
 
 /*
- * Default timeslice is 80 msecs, maximum is 160 msecs.
+ * Scales user-nice values [ -20 ... 0 ... 19 ]
+ * to static priority [ 128 ... 167 (MAX_PRIO-1) ]
+ *
+ * User-nice value of -20 == static priority 128, and
+ * user-nice value 19 == static priority 167. The lower
+ * the priority value, the higher the task's priority.
+ */
+#define NICE_TO_PRIO(n)		(MAX_RT_PRIO + (n) + 20)
+#define DEF_USER_NICE		0
+
+/*
+ * Default timeslice is 90 msecs, maximum is 180 msecs.
  * Minimum timeslice is 10 msecs.
  */
-#define MIN_TIMESLICE	(10 * HZ / 1000)
-#define MAX_TIMESLICE	(160 * HZ / 1000)
+#define MIN_TIMESLICE		( 10 * HZ / 1000)
+#define MAX_TIMESLICE		(180 * HZ / 1000)
 
-#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
-#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
-#define DEF_PRIO	(MAX_RT_PRIO + MAX_USER_PRIO / 3)
-#define NICE_TO_PRIO(n) (MAX_PRIO-1 + (n) - 19)
+#define USER_PRIO(p)		((p)-MAX_RT_PRIO)
+#define MAX_USER_PRIO		(USER_PRIO(MAX_PRIO))
 
-#define NICE_TO_TIMESLICE(n)   (MIN_TIMESLICE + \
-	((MAX_TIMESLICE - MIN_TIMESLICE) * (19 - (n))) / 39)
+/*
+ * NICE_TO_TIMESLICE scales nice values [ -20 ... 19 ]
+ * to time slice values.
+ *
+ * The higher a process's priority, the bigger timeslices
+ * it gets during one round of execution. But even the lowest
+ * priority process gets MIN_TIMESLICE worth of execution time.
+ */
+
+#define NICE_TO_TIMESLICE(n) (MIN_TIMESLICE + \
+	((MAX_TIMESLICE - MIN_TIMESLICE) * (19-(n))) / 39)
 
 extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
 extern void set_user_nice(task_t *p, long nice);
@@ -541,6 +562,17 @@
 static inline int signal_pending(struct task_struct *p)
 {
 	return (p->sigpending != 0);
+}
+  
+static inline int need_resched(void)
+{
+	return unlikely(current->need_resched != 0);
+}
+
+static inline void cond_resched(void)
+{
+	if (need_resched())
+		schedule();
 }
 
 /*
diff -u --recursive --new-file pre1/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- pre1/linux/include/scsi/sg.h	Fri Sep  7 09:28:37 2001
+++ linux/include/scsi/sg.h	Thu Jan 17 13:59:33 2002
@@ -11,78 +11,71 @@
 Version 2 and 3 extensions to driver:
 *       Copyright (C) 1998 - 2001 Douglas Gilbert
 
-    Version: 3.1.20 (20010814)
-    This version is for 2.4 series kernels.
+    Version: 3.5.23 (20011231)
+    This version is for 2.5 series kernels.
 
-    Changes since 3.1.19 (20010623)
-	- add SG_GET_ACCESS_COUNT ioctl 
-	- make open() increment and close() decrement access_count
-	- only register first 256 devices, reject subsequent devices
-    Changes since 3.1.18 (20010505)
-	- fix bug that caused long wait when large buffer requested
-	- fix leak in error case of sg_new_read() [report: Eric Barton]
-	- add 'online' column to /proc/scsi/sg/devices
-    Changes since 3.1.17 (20000921)
-    	- add CAP_SYS_RAWIO capability for sensitive stuff
-    	- compile in dio stuff, procfs 'allow_dio' defaulted off (0)
-	- make premature close and detach more robust
-	- lun masked into commands <= SCSI_2
-	- poll() and async notification now yield POLL_HUP on detach
-	- various 3rd party tweaks tracking lk 2.4 internal changes
+    Changes since 3.1.22 (20011208)
+    	- branch sg driver for lk 2.5 series
+    	- remove lock_kernel() from sg_close()
+    	- remove code based on scsi mid level dma pool
+    	- change scatterlist 'address' to use page + offset
+    	- add SG_INTERFACE_ID_ORIG
 
 Map of SG verions to the Linux kernels in which they appear:
        ----------        ----------------------------------
        original          all kernels < 2.2.6
-       2.1.38            2.2.16
-       2.1.39            2.2.17 - 2.2.19
+       2.1.40            2.2.20
        3.0.x             optional version 3 sg driver for 2.2 series
-       3.1.17            2.4.0 ++
+       3.1.17++          2.4.0++
+       3.5.23++          2.5.0++
 
 Major new features in SG 3.x driver (cf SG 2.x drivers)
 	- SG_IO ioctl() combines function if write() and read()
 	- new interface (sg_io_hdr_t) but still supports old interface
-	- scatter/gather in user space and direct IO supported
+	- scatter/gather in user space, direct IO, and mmap supported
 
- The term "indirect IO" refers a method by which data is DMAed into kernel
- buffers from the hardware and afterwards is transferred into the user
- space (or vice versa if you are writing). Transfer speeds of up to 20 to
- 30MBytes/sec have been measured using indirect IO. For faster throughputs
- "direct IO" which cuts out the double handling of data is required.
- Direct IO is supported by the SG 3.x drivers on 2.4 series Linux kernels
- and requires the use of the new interface.
-
- Requests for direct IO with the new interface will automatically fall back
- to indirect IO mode if they cannot be fulfilled. An example of such a case
- is an ISA SCSI adapter which is only capable of DMAing to the lower 16MB of
- memory due to the architecture of ISA. The 'info' field in the new
- interface indicates whether a direct or indirect data transfer took place.
-
- Obtaining memory for the kernel buffers used in indirect IO is done by
- first checking if the "reserved buffer" for the current file descriptor
- is available and large enough. If these conditions are _not_ met then
- kernel memory is obtained on a per SCSI command basis. This corresponds
- to a write(), read() sequence or a SG_IO ioctl() call. Further, the
- kernel memory that is suitable for DMA may be constrained by the
- architecture of the SCSI adapter (e.g. ISA adapters).
+ The normal action of this driver is to use the adapter (HBA) driver to DMA
+ data into kernel buffers and then use the CPU to copy the data into the 
+ user space (vice versa for writes). That is called "indirect" IO due to 
+ the double handling of data. There are two methods offered to remove the
+ redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and 
+ 2) using the mmap() system call to map the reserve buffer (this driver has 
+ one reserve buffer per fd) into the user space. Both have their advantages.
+ In terms of absolute speed mmap() is faster. If speed is not a concern, 
+ indirect IO should be fine. Read the documentation for more information.
 
  ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
          needed. That pseudo file's content is defaulted to 0. **
+ 
+ Historical note: this SCSI pass-through driver has been known as "sg" for 
+ a decade. In broader kernel discussions "sg" is used to refer to scatter
+ gather techniques. The context should clarify which "sg" is referred to.
 
  Documentation
  =============
- A web site for SG device drivers can be found at:
+ A web site for the SG device driver can be found at:
 	http://www.torque.net/sg  [alternatively check the MAINTAINERS file]
- The main documents are still based on 2.x versions:
+ The documentation for the sg version 3 driver can be found at:
+ 	http://www.torque.net/sg/p/sg_v3_ho.html
+ This is a rendering from DocBook source [change the extension to "sgml"
+ or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
+
+ The older, version 2 documents discuss the original sg interface in detail:
 	http://www.torque.net/sg/p/scsi-generic.txt
 	http://www.torque.net/sg/p/scsi-generic_long.txt
- Documentation on the changes and additions in 3.x version of the sg driver
- can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
  A version of this document (potentially out of date) may also be found in
  the kernel source tree, probably at:
         /usr/src/linux/Documentation/scsi-generic.txt .
- Utility and test programs are available at the sg web site.
+
+ Utility and test programs are available at the sg web site. They are 
+ bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the
+ lk 2.4 series).
+
+ There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at:
+ 	http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO
 */
 
+
 /* New interface introduced in the 3.x SG drivers follows */
 
 typedef struct sg_iovec /* same structure as used by readv() Linux system */
@@ -119,20 +112,23 @@
     unsigned int info;          /* [o] auxiliary information */
 } sg_io_hdr_t;  /* 64 bytes long (on i386) */
 
+#define SG_INTERFACE_ID_ORIG 'S'
+
 /* Use negative values to flag difference from original sg_header structure */
-#define SG_DXFER_NONE -1        /* e.g. a SCSI Test Unit Ready command */
-#define SG_DXFER_TO_DEV -2      /* e.g. a SCSI WRITE command */
-#define SG_DXFER_FROM_DEV -3    /* e.g. a SCSI READ command */
-#define SG_DXFER_TO_FROM_DEV -4 /* treated like SG_DXFER_FROM_DEV with the
+#define SG_DXFER_NONE (-1)      /* e.g. a SCSI Test Unit Ready command */
+#define SG_DXFER_TO_DEV (-2)    /* e.g. a SCSI WRITE command */
+#define SG_DXFER_FROM_DEV (-3)  /* e.g. a SCSI READ command */
+#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the
 				   additional property than during indirect
 				   IO the user buffer is copied into the
 				   kernel buffers before the transfer */
-#define SG_DXFER_UNKNOWN -5     /* Unknown data direction */
+#define SG_DXFER_UNKNOWN (-5)   /* Unknown data direction */
 
 /* following flag values can be "or"-ed together */
 #define SG_FLAG_DIRECT_IO 1     /* default is indirect IO */
-#define SG_FLAG_LUN_INHIBIT 2   /* default is to put device's lun into */
-				/* the 2nd byte of SCSI command */
+#define SG_FLAG_LUN_INHIBIT 2   /* default is overwrite lun in SCSI */
+				/* command block (when <= SCSI_2) */
+#define SG_FLAG_MMAP_IO 4       /* request memory mapped IO */
 #define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */
 				/* user space (debug indirect IO) */
 
diff -u --recursive --new-file pre1/linux/init/main.c linux/init/main.c
--- pre1/linux/init/main.c	Wed Jan  9 09:45:17 2002
+++ linux/init/main.c	Thu Jan 17 14:21:16 2002
@@ -38,35 +38,10 @@
 #include <asm/ccwcache.h>
 #endif
 
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-
-#ifdef CONFIG_DIO
-#include <linux/dio.h>
-#endif
-
-#ifdef CONFIG_ZORRO
-#include <linux/zorro.h>
-#endif
-
 #ifdef CONFIG_MTRR
 #  include <asm/mtrr.h>
 #endif
 
-#ifdef CONFIG_NUBUS
-#include <linux/nubus.h>
-#endif
-
-#ifdef CONFIG_ISAPNP
-#include <linux/isapnp.h>
-#endif
-
-#ifdef CONFIG_IRDA
-extern int irda_proto_init(void);
-extern int irda_device_init(void);
-#endif
-
 #ifdef CONFIG_X86_LOCAL_APIC
 #include <asm/smp.h>
 #endif
@@ -92,10 +67,8 @@
 extern void fork_init(unsigned long);
 extern void mca_init(void);
 extern void sbus_init(void);
-extern void ppc_init(void);
 extern void sysctl_init(void);
 extern void signals_init(void);
-extern int init_pcmcia_ds(void);
 
 extern void free_initmem(void);
 
@@ -103,8 +76,6 @@
 extern void tc_init(void);
 #endif
 
-extern void ecard_init(void);
-
 #if defined(CONFIG_SYSVIPC)
 extern void ipc_init(void);
 #endif
@@ -490,50 +461,11 @@
 	/* bring up the device tree */
 	device_driver_init();
 
-#ifdef CONFIG_PCI
-	pci_init();
-#endif
-#ifdef CONFIG_SBUS
-	sbus_init();
-#endif
-#if defined(CONFIG_PPC)
-	ppc_init();
-#endif
-#ifdef CONFIG_MCA
-	mca_init();
-#endif
-#ifdef CONFIG_ARCH_ACORN
-	ecard_init();
-#endif
-#ifdef CONFIG_ZORRO
-	zorro_init();
-#endif
-#ifdef CONFIG_DIO
-	dio_init();
-#endif
-#ifdef CONFIG_NUBUS
-	nubus_init();
-#endif
-#ifdef CONFIG_ISAPNP
-	isapnp_init();
-#endif
-#ifdef CONFIG_TC
-	tc_init();
-#endif
-
 	/* Networking initialization needs a process context */ 
 	sock_init();
 
 	start_context_thread();
 	do_initcalls();
-
-#ifdef CONFIG_IRDA
-	irda_proto_init();
-	irda_device_init(); /* Must be done after protocol initialization */
-#endif
-#ifdef CONFIG_PCMCIA
-	init_pcmcia_ds();		/* Do this last */
-#endif
 }
 
 extern void prepare_namespace(void);
diff -u --recursive --new-file pre1/linux/kernel/fork.c linux/kernel/fork.c
--- pre1/linux/kernel/fork.c	Wed Jan 16 11:16:28 2002
+++ linux/kernel/fork.c	Tue Jan 15 14:33:55 2002
@@ -704,8 +704,9 @@
 		 * runqueue lock is not a problem.
 		 */
 		current->time_slice = 1;
-		expire_task(current);
+		scheduler_tick(current);
 	}
+	p->sleep_timestamp = jiffies;
 	__restore_flags(flags);
 
 	if (p->policy == SCHED_OTHER)
diff -u --recursive --new-file pre1/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- pre1/linux/kernel/ksyms.c	Wed Jan 16 11:16:28 2002
+++ linux/kernel/ksyms.c	Thu Jan 17 14:30:00 2002
@@ -137,6 +137,7 @@
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(inode_init_once);
 EXPORT_SYMBOL(force_delete);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
@@ -502,17 +503,16 @@
 /* Added to make file system as module */
 EXPORT_SYMBOL(sys_tz);
 EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(fsync_inode_buffers);
-EXPORT_SYMBOL(fsync_inode_data_buffers);
+EXPORT_SYMBOL(fsync_buffers_list);
 EXPORT_SYMBOL(clear_inode);
 EXPORT_SYMBOL(___strtok);
 EXPORT_SYMBOL(init_special_inode);
 EXPORT_SYMBOL(read_ahead);
 EXPORT_SYMBOL(__get_hash_table);
-EXPORT_SYMBOL(get_empty_inode);
+EXPORT_SYMBOL(new_inode);
 EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(remove_inode_hash);
-EXPORT_SYMBOL(buffer_insert_inode_queue);
+EXPORT_SYMBOL(buffer_insert_list);
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
diff -u --recursive --new-file pre1/linux/kernel/printk.c linux/kernel/printk.c
--- pre1/linux/kernel/printk.c	Mon Jan  7 12:55:16 2002
+++ linux/kernel/printk.c	Tue Jan 15 13:53:51 2002
@@ -524,7 +524,7 @@
  */
 void console_conditional_schedule(void)
 {
-	if (console_may_schedule && current->need_resched) {
+	if (console_may_schedule && need_resched()) {
 		set_current_state(TASK_RUNNING);
 		schedule();
 	}
diff -u --recursive --new-file pre1/linux/kernel/sched.c linux/kernel/sched.c
--- pre1/linux/kernel/sched.c	Wed Jan 16 11:16:28 2002
+++ linux/kernel/sched.c	Tue Jan 15 14:33:55 2002
@@ -20,10 +20,7 @@
 #include <linux/interrupt.h>
 #include <asm/mmu_context.h>
 
-#define BITMAP_SIZE ((MAX_PRIO+7)/8)
-#define PRIO_INTERACTIVE	(MAX_RT_PRIO + (MAX_PRIO - MAX_RT_PRIO) / 3)
-#define TASK_INTERACTIVE(p)	((p)->prio >= MAX_RT_PRIO && (p)->prio <= PRIO_INTERACTIVE)
-#define JSLEEP_TO_PRIO(t)	(((t) * 20) / HZ)
+#define BITMAP_SIZE ((((MAX_PRIO+7)/8)+sizeof(long)-1)/sizeof(long))
 
 typedef struct runqueue runqueue_t;
 
@@ -31,7 +28,7 @@
 	int nr_active;
 	spinlock_t *lock;
 	runqueue_t *rq;
-	char bitmap[BITMAP_SIZE];
+	unsigned long bitmap[BITMAP_SIZE];
 	list_t queue[MAX_PRIO];
 };
 
@@ -40,33 +37,36 @@
  *
  * Locking rule: those places that want to lock multiple runqueues
  * (such as the load balancing or the process migration code), lock
- * acquire operations must be ordered by rq->cpu.
+ * acquire operations must be ordered by the runqueue's cpu id.
  *
  * The RT event id is used to avoid calling into the the RT scheduler
  * if there is a RT task active in an SMP system but there is no
  * RT scheduling activity otherwise.
  */
-static struct runqueue {
-	int cpu;
+struct runqueue {
 	spinlock_t lock;
 	unsigned long nr_running, nr_switches;
 	task_t *curr, *idle;
 	prio_array_t *active, *expired, arrays[2];
-	char __pad [SMP_CACHE_BYTES];
-} runqueues [NR_CPUS] __cacheline_aligned;
+	int prev_nr_running[NR_CPUS];
+} ____cacheline_aligned;
+
+static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;
 
-#define this_rq()		(runqueues + smp_processor_id())
-#define task_rq(p)		(runqueues + (p)->cpu)
 #define cpu_rq(cpu)		(runqueues + (cpu))
-#define cpu_curr(cpu)		(runqueues[(cpu)].curr)
+#define this_rq()		cpu_rq(smp_processor_id())
+#define task_rq(p)		cpu_rq((p)->cpu)
+#define cpu_curr(cpu)		(cpu_rq(cpu)->curr)
+#define rq_cpu(rq)		((rq) - runqueues)
 #define rt_task(p)		((p)->policy != SCHED_OTHER)
 
+
 #define lock_task_rq(rq,p,flags)				\
 do {								\
 repeat_lock_task:						\
 	rq = task_rq(p);					\
 	spin_lock_irqsave(&rq->lock, flags);			\
-	if (unlikely((rq)->cpu != (p)->cpu)) {			\
+	if (unlikely(rq_cpu(rq) != (p)->cpu)) {			\
 		spin_unlock_irqrestore(&rq->lock, flags);	\
 		goto repeat_lock_task;				\
 	}							\
@@ -94,18 +94,56 @@
 	p->array = array;
 }
 
+/*
+ * A task is 'heavily interactive' if it has reached the
+ * bottom 25% of the SCHED_OTHER priority range - in this
+ * case we favor it by reinserting it on the active array,
+ * even after it expired its current timeslice.
+ *
+ * A task can get a priority bonus by being 'somewhat
+ * interactive' - and it will get a priority penalty for
+ * being a CPU hog.
+ *
+ * CPU-hog penalties cannot go more than 5 above the default
+ * priority level. Priority bonus cannot go below the minimum
+ * priority level.
+ */
+#define PRIO_INTERACTIVE (MAX_RT_PRIO + MAX_USER_PRIO/3)
+#define TASK_INTERACTIVE(p) ((p)->prio <= PRIO_INTERACTIVE)
+
+static inline int effective_prio(task_t *p)
+{
+	int bonus, prio;
+
+	/*
+	 * Here we scale the actual sleep average [0 .... MAX_SLEEP_AVG]
+	 * into the 20 ... -20 bonus/penalty range.
+	 */
+	bonus = MAX_USER_PRIO * p->sleep_avg / MAX_SLEEP_AVG - MAX_USER_PRIO/2;
+	prio = NICE_TO_PRIO(p->__nice) - bonus;
+	if (prio < MAX_RT_PRIO)
+		prio = MAX_RT_PRIO;
+	if (prio > MAX_PRIO-1)
+		prio = MAX_PRIO-1;
+	return prio;
+}
+
 static inline void activate_task(task_t *p, runqueue_t *rq)
 {
 	prio_array_t *array = rq->active;
 
 	if (!rt_task(p)) {
-		unsigned long prio_bonus = JSLEEP_TO_PRIO(jiffies - p->sleep_jtime);
-
-		if (prio_bonus > MAX_PRIO)
-			prio_bonus = MAX_PRIO;
-		p->prio -= prio_bonus;
-		if (p->prio < MAX_RT_PRIO)
-			p->prio = MAX_RT_PRIO;
+		/*
+		 * This code gives a bonus to interactive tasks. We update
+		 * an 'average sleep time' value here, based on
+		 * sleep_timestamp. The more time a task spends sleeping,
+		 * the higher the average gets - and the higher the priority
+		 * boost gets as well.
+		 */
+		p->sleep_avg += jiffies - p->sleep_timestamp;
+		if (p->sleep_avg > MAX_SLEEP_AVG)
+			p->sleep_avg = MAX_SLEEP_AVG;
+		p->prio = effective_prio(p);
 	}
 	enqueue_task(p, array);
 	rq->nr_running++;
@@ -116,7 +154,7 @@
 	rq->nr_running--;
 	dequeue_task(p, p->array);
 	p->array = NULL;
-	p->sleep_jtime = jiffies;
+	p->sleep_timestamp = jiffies;
 }
 
 static inline void resched_task(task_t *p)
@@ -206,13 +244,13 @@
 {
 	runqueue_t *rq = this_rq();
 
-	spin_lock_irq(&rq->lock);
 	p->state = TASK_RUNNING;
 	if (!rt_task(p)) {
 		p->prio += MAX_USER_PRIO/10;
 		if (p->prio > MAX_PRIO-1)
 			p->prio = MAX_PRIO-1;
 	}
+	spin_lock_irq(&rq->lock);
 	activate_task(p, rq);
 	spin_unlock_irq(&rq->lock);
 }
@@ -287,59 +325,98 @@
 }
 
 /*
- * Current runqueue is empty, try to find work on
- * other runqueues.
+ * Current runqueue is empty, or rebalance tick: if there is an
+ * inbalance (current runqueue is too short) then pull from
+ * busiest runqueue(s).
  *
  * We call this with the current runqueue locked,
  * irqs disabled.
  */
-static void load_balance(runqueue_t *this_rq)
+static void load_balance(runqueue_t *this_rq, int idle)
 {
-	int nr_tasks, load, prev_max_load, max_load, idx, i;
+	int imbalance, nr_running, load, prev_max_load,
+		max_load, idx, i, this_cpu = smp_processor_id();
 	task_t *next = this_rq->idle, *tmp;
-	runqueue_t *busiest, *rq_tmp;
+	runqueue_t *busiest, *rq_src;
 	prio_array_t *array;
 	list_t *head, *curr;
 
-	prev_max_load = max_rq_len();
-	nr_tasks = prev_max_load - this_rq->nr_running;
-	/*
-	 * It needs an at least ~10% imbalance to trigger balancing:
-	 */
-	if (nr_tasks <= 1 + prev_max_load/8)
-		return;
-	prev_max_load++;
-
-repeat_search:
 	/*
 	 * We search all runqueues to find the most busy one.
 	 * We do this lockless to reduce cache-bouncing overhead,
-	 * we re-check the source CPU with the lock held.
+	 * we re-check the 'best' source CPU later on again, with
+	 * the lock held.
+	 *
+	 * We fend off statistical fluctuations in runqueue lengths by
+	 * saving the runqueue length during the previous load-balancing
+	 * operation and using the smaller one the current and saved lengths.
+	 * If a runqueue is long enough for a longer amount of time then
+	 * we recognize it and pull tasks from it.
+	 *
+	 * The 'current runqueue length' is a statistical maximum variable,
+	 * for that one we take the longer one - to avoid fluctuations in
+	 * the other direction. So for a load-balance to happen it needs
+	 * stable long runqueue on the target CPU and stable short runqueue
+	 * on the local runqueue.
+	 *
+	 * We make an exception if this CPU is about to become idle - in
+	 * that case we are less picky about moving a task across CPUs and
+	 * take what can be taken.
 	 */
+	if (idle || (this_rq->nr_running > this_rq->prev_nr_running[this_cpu]))
+		nr_running = this_rq->nr_running;
+	else
+		nr_running = this_rq->prev_nr_running[this_cpu];
+	prev_max_load = 1000000000;
+
 	busiest = NULL;
 	max_load = 0;
 	for (i = 0; i < smp_num_cpus; i++) {
-		rq_tmp = cpu_rq(i);
-		load = rq_tmp->nr_running;
+		rq_src = cpu_rq(i);
+		if (idle || (rq_src->nr_running < this_rq->prev_nr_running[i]))
+			load = rq_src->nr_running;
+		else
+			load = this_rq->prev_nr_running[i];
+		this_rq->prev_nr_running[i] = rq_src->nr_running;
+
 		if ((load > max_load) && (load < prev_max_load) &&
-						(rq_tmp != this_rq)) {
-			busiest = rq_tmp;
+						(rq_src != this_rq)) {
+			busiest = rq_src;
 			max_load = load;
 		}
 	}
 
 	if (likely(!busiest))
 		return;
-	if (max_load <= this_rq->nr_running)
+
+	imbalance = (max_load - nr_running) / 2;
+
+	/*
+	 * It needs an at least ~25% imbalance to trigger balancing.
+	 *
+	 * prev_max_load makes sure that we do not try to balance
+	 * ad infinitum - certain tasks might be impossible to be
+	 * pulled into this runqueue.
+	 */
+	if (!idle && (imbalance < (max_load + 3)/4))
 		return;
 	prev_max_load = max_load;
-	if (busiest->cpu < this_rq->cpu) {
+
+	/*
+	 * Ok, lets do some actual balancing:
+	 */
+
+	if (rq_cpu(busiest) < this_cpu) {
 		spin_unlock(&this_rq->lock);
 		spin_lock(&busiest->lock);
 		spin_lock(&this_rq->lock);
 	} else
 		spin_lock(&busiest->lock);
-	if (busiest->nr_running <= this_rq->nr_running + 1)
+	/*
+	 * Make sure nothing changed since we checked the
+	 * runqueue length.
+	 */
+	if (busiest->nr_running <= nr_running + 1)
 		goto out_unlock;
 
 	/*
@@ -365,15 +442,14 @@
 			array = busiest->active;
 			goto new_array;
 		}
-		spin_unlock(&busiest->lock);
-		goto repeat_search;
+		goto out_unlock;
 	}
 
 	head = array->queue + idx;
 	curr = head->next;
 skip_queue:
 	tmp = list_entry(curr, task_t, run_list);
-	if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << smp_processor_id()))) {
+	if ((tmp == busiest->curr) || !(tmp->cpus_allowed & (1 << this_cpu))) {
 		curr = curr->next;
 		if (curr != head)
 			goto skip_queue;
@@ -387,64 +463,96 @@
 	 */
 	dequeue_task(next, array);
 	busiest->nr_running--;
-	next->cpu = smp_processor_id();
+	next->cpu = this_cpu;
 	this_rq->nr_running++;
 	enqueue_task(next, this_rq->active);
 	if (next->prio < current->prio)
 		current->need_resched = 1;
-	if (--nr_tasks) {
+	if (!idle && --imbalance) {
 		if (array == busiest->expired) {
 			array = busiest->active;
 			goto new_array;
 		}
-		spin_unlock(&busiest->lock);
-		goto repeat_search;
 	}
 out_unlock:
 	spin_unlock(&busiest->lock);
 }
 
-/* Rebalance every 250 msecs */
-#define REBALANCE_TICK (HZ/4)
+/*
+ * One of the idle_cpu_tick() or the busy_cpu_tick() function will
+ * gets called every timer tick, on every CPU. Our balancing action
+ * frequency and balancing agressivity depends on whether the CPU is
+ * idle or not.
+ *
+ * busy-rebalance every 250 msecs. idle-rebalance every 1 msec. (or on
+ * systems with HZ=100, every 10 msecs.)
+ */
+#define BUSY_REBALANCE_TICK (HZ/4 ?: 1)
+#define IDLE_REBALANCE_TICK (HZ/1000 ?: 1)
 
-void idle_tick(void)
+static inline void idle_tick(void)
 {
-	unsigned long flags;
-
-	if (!(jiffies % REBALANCE_TICK) && likely(this_rq()->curr != NULL)) {
-		spin_lock_irqsave(&this_rq()->lock, flags);
-		load_balance(this_rq());
-		spin_unlock_irqrestore(&this_rq()->lock, flags);
-	}
+	if ((jiffies % IDLE_REBALANCE_TICK) ||
+			likely(this_rq()->curr == NULL))
+		return;
+	spin_lock(&this_rq()->lock);
+	load_balance(this_rq(), 1);
+	spin_unlock(&this_rq()->lock);
 }
 
-void expire_task(task_t *p)
+/*
+ * This function gets called by the timer code, with HZ frequency.
+ * We call it with interrupts disabled.
+ */
+void scheduler_tick(task_t *p)
 {
+	unsigned long now = jiffies;
 	runqueue_t *rq = this_rq();
-	unsigned long flags;
 
+	if (p == rq->idle || !rq->idle)
+		return idle_tick();
+	/* Task might have expired already, but not scheduled off yet */
 	if (p->array != rq->active) {
 		p->need_resched = 1;
 		return;
 	}
+	spin_lock(&rq->lock);
+	if (unlikely(rt_task(p))) {
+		/*
+		 * RR tasks need a special form of timeslice management.
+		 * FIFO tasks have no timeslices.
+		 */
+		if ((p->policy == SCHED_RR) && !--p->time_slice) {
+			p->time_slice = NICE_TO_TIMESLICE(p->__nice);
+			p->need_resched = 1;
+
+			/* put it at the end of the queue: */
+			dequeue_task(p, rq->active);
+			enqueue_task(p, rq->active);
+		}
+		goto out;
+	}
 	/*
-	 * The task cannot change CPUs because it's the current task.
+	 * The task was running during this tick - update the
+	 * time slice counter and the sleep average. Note: we
+	 * do not update a process's priority until it either
+	 * goes to sleep or uses up its timeslice. This makes
+	 * it possible for interactive tasks to use up their
+	 * timeslices at their high priority levels.
 	 */
-	spin_lock_irqsave(&rq->lock, flags);
-	if ((p->policy != SCHED_FIFO) && !--p->time_slice) {
-		prio_array_t *array = rq->active;
-		p->need_resched = 1;
+	if (p->sleep_avg)
+		p->sleep_avg--;
+	if (!--p->time_slice) {
 		dequeue_task(p, rq->active);
-		if (!rt_task(p)) {
-			if (++p->prio >= MAX_PRIO)
-				p->prio = MAX_PRIO - 1;
-			if (!TASK_INTERACTIVE(p))
-				array = rq->expired;
-		}
-		enqueue_task(p, array);
+		p->need_resched = 1;
+		p->prio = effective_prio(p);
 		p->time_slice = NICE_TO_TIMESLICE(p->__nice);
+		enqueue_task(p, TASK_INTERACTIVE(p) ? rq->active : rq->expired);
 	}
-	spin_unlock_irqrestore(&rq->lock, flags);
+out:
+	if (!(now % BUSY_REBALANCE_TICK))
+		load_balance(rq, 0);
+	spin_unlock(&rq->lock);
 }
 
 void scheduling_functions_start_here(void) { }
@@ -469,18 +577,18 @@
 	spin_lock_irq(&rq->lock);
 
 	switch (prev->state) {
-	case TASK_INTERRUPTIBLE:
-		if (unlikely(signal_pending(prev))) {
-			prev->state = TASK_RUNNING;
-			break;
-		}
-	default:
-		deactivate_task(prev, rq);
-	case TASK_RUNNING:
+		case TASK_INTERRUPTIBLE:
+			if (unlikely(signal_pending(prev))) {
+				prev->state = TASK_RUNNING;
+				break;
+			}
+		default:
+			deactivate_task(prev, rq);
+		case TASK_RUNNING:
 	}
 pick_next_task:
 	if (unlikely(!rq->nr_running)) {
-		load_balance(rq);
+		load_balance(rq, 1);
 		if (rq->nr_running)
 			goto pick_next_task;
 		next = rq->idle;
@@ -520,7 +628,7 @@
 	spin_unlock_irq(&rq->lock);
 
 	reacquire_kernel_lock(current);
-	if (unlikely(current->need_resched))
+	if (need_resched())
 		goto need_resched_back;
 	return;
 }
@@ -1015,7 +1123,7 @@
 	p = find_process_by_pid(pid);
 	if (p)
 		jiffies_to_timespec(p->policy & SCHED_FIFO ?
-					 0 : NICE_TO_TIMESLICE(p->__nice), &t);
+					 0 : NICE_TO_TIMESLICE(p->prio), &t);
 	read_unlock(&tasklist_lock);
 	if (p)
 		retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
@@ -1123,7 +1231,7 @@
 	if (rq1 == rq2)
 		spin_lock(&rq1->lock);
 	else {
-		if (rq1->cpu < rq2->cpu) {
+		if (rq_cpu(rq1) < rq_cpu(rq2)) {
 			spin_lock(&rq1->lock);
 			spin_lock(&rq2->lock);
 		} else {
@@ -1152,7 +1260,7 @@
 	this_rq->curr = this_rq->idle = current;
 	deactivate_task(current, rq);
 	current->array = NULL;
-	current->prio = MAX_PRIO;
+	current->prio = MAX_PRIO-1;
 	current->state = TASK_RUNNING;
 	clear_bit(smp_processor_id(), &wait_init_idle);
 	double_rq_unlock(this_rq, rq);
@@ -1181,17 +1289,17 @@
 		rq->active = rq->arrays + 0;
 		rq->expired = rq->arrays + 1;
 		spin_lock_init(&rq->lock);
-		rq->cpu = i;
 
 		for (j = 0; j < 2; j++) {
 			array = rq->arrays + j;
 			array->rq = rq;
 			array->lock = &rq->lock;
-			for (k = 0; k < MAX_PRIO; k++)
+			for (k = 0; k < MAX_PRIO; k++) {
 				INIT_LIST_HEAD(array->queue + k);
-			memset(array->bitmap, 0xff, BITMAP_SIZE);
+				__set_bit(k, array->bitmap);
+			}
 			// zero delimiter for bitsearch
-			clear_bit(MAX_PRIO, array->bitmap);
+			__clear_bit(MAX_PRIO, array->bitmap);
 		}
 	}
 	/*
@@ -1202,9 +1310,6 @@
 	rq->curr = current;
 	rq->idle = NULL;
 	wake_up_process(current);
-
-	for (i = 0; i < PIDHASH_SZ; i++)
-		pidhash[i] = NULL;
 
 	init_timervecs();
 	init_bh(TIMER_BH, timer_bh);
diff -u --recursive --new-file pre1/linux/kernel/softirq.c linux/kernel/softirq.c
--- pre1/linux/kernel/softirq.c	Mon Jan  7 12:55:16 2002
+++ linux/kernel/softirq.c	Tue Jan 15 13:53:51 2002
@@ -387,8 +387,7 @@
 
 		while (softirq_pending(cpu)) {
 			do_softirq();
-			if (current->need_resched)
-				schedule();
+			cond_resched();
 		}
 
 		__set_current_state(TASK_INTERRUPTIBLE);
diff -u --recursive --new-file pre1/linux/kernel/timer.c linux/kernel/timer.c
--- pre1/linux/kernel/timer.c	Mon Jan  7 12:55:16 2002
+++ linux/kernel/timer.c	Tue Jan 15 14:33:55 2002
@@ -585,17 +585,16 @@
 
 	update_one_process(p, user_tick, system, cpu);
 	if (p->pid) {
-		expire_task(p);
 		if (p->__nice > 0)
 			kstat.per_cpu_nice[cpu] += user_tick;
 		else
 			kstat.per_cpu_user[cpu] += user_tick;
 		kstat.per_cpu_system[cpu] += system;
 	} else {
-		idle_tick();
 		if (local_bh_count(cpu) || local_irq_count(cpu) > 1)
 			kstat.per_cpu_system[cpu] += system;
 	}
+	scheduler_tick(p);
 }
 
 /*
diff -u --recursive --new-file pre1/linux/mm/filemap.c linux/mm/filemap.c
--- pre1/linux/mm/filemap.c	Wed Jan 16 11:16:28 2002
+++ linux/mm/filemap.c	Tue Jan 15 13:53:51 2002
@@ -290,7 +290,7 @@
 
 			page_cache_release(page);
 
-			if (current->need_resched) {
+			if (need_resched()) {
 				__set_current_state(TASK_RUNNING);
 				schedule();
 			}
@@ -400,7 +400,7 @@
 		}
 
 		page_cache_release(page);
-		if (current->need_resched) {
+		if (need_resched()) {
 			__set_current_state(TASK_RUNNING);
 			schedule();
 		}
diff -u --recursive --new-file pre1/linux/mm/highmem.c linux/mm/highmem.c
--- pre1/linux/mm/highmem.c	Mon Jan 14 10:10:43 2002
+++ linux/mm/highmem.c	Thu Jan 17 13:59:33 2002
@@ -367,12 +367,6 @@
 		if (pfn >= blk_max_pfn)
 			return;
 
-#ifndef CONFIG_HIGHMEM
-		/*
-		 * should not hit for non-highmem case
-		 */
-		BUG();
-#endif
 		bio_gfp = GFP_NOHIGHIO;
 		pool = page_pool;
 	} else {
diff -u --recursive --new-file pre1/linux/mm/swapfile.c linux/mm/swapfile.c
--- pre1/linux/mm/swapfile.c	Wed Jan 16 11:16:28 2002
+++ linux/mm/swapfile.c	Tue Jan 15 13:53:51 2002
@@ -696,7 +696,7 @@
 		 * interactive performance.  Interruptible check on
 		 * signal_pending() would be nice, but changes the spec?
 		 */
-		if (current->need_resched)
+		if (need_resched())
 			schedule();
 	}
 
diff -u --recursive --new-file pre1/linux/mm/vmscan.c linux/mm/vmscan.c
--- pre1/linux/mm/vmscan.c	Sat Dec 29 17:30:07 2001
+++ linux/mm/vmscan.c	Tue Jan 15 13:53:51 2002
@@ -300,7 +300,7 @@
 
 	counter = mmlist_nr;
 	do {
-		if (unlikely(current->need_resched)) {
+		if (need_resched()) {
 			__set_current_state(TASK_RUNNING);
 			schedule();
 		}
@@ -345,7 +345,7 @@
 	while (--max_scan >= 0 && (entry = inactive_list.prev) != &inactive_list) {
 		struct page * page;
 
-		if (unlikely(current->need_resched)) {
+		if (need_resched()) {
 			spin_unlock(&pagemap_lru_lock);
 			__set_current_state(TASK_RUNNING);
 			schedule();
@@ -625,8 +625,7 @@
 
 	for (i = pgdat->nr_zones-1; i >= 0; i--) {
 		zone = pgdat->node_zones + i;
-		if (unlikely(current->need_resched))
-			schedule();
+		cond_resched();
 		if (!zone->need_balance)
 			continue;
 		if (!try_to_free_pages(zone, GFP_KSWAPD, 0)) {
diff -u --recursive --new-file pre1/linux/net/ipv4/netfilter/ip_fw_compat_redir.c linux/net/ipv4/netfilter/ip_fw_compat_redir.c
--- pre1/linux/net/ipv4/netfilter/ip_fw_compat_redir.c	Wed Jan 16 11:16:28 2002
+++ linux/net/ipv4/netfilter/ip_fw_compat_redir.c	Wed Jan 16 10:29:38 2002
@@ -270,8 +270,10 @@
 	if (redir) {
 		DEBUGP("Doing tcp redirect again.\n");
 		do_tcp_redir(skb, redir);
-		if (del_timer(&redir->destroyme))
-			add_timer(&redir->destroyme, jiffies + REDIR_TIMEOUT);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
+		}
 	}
 	UNLOCK_BH(&redir_lock);
 }
@@ -296,8 +298,10 @@
 	if (redir) {
 		DEBUGP("Doing tcp unredirect.\n");
 		do_tcp_unredir(skb, redir);
-		if (del_timer(&redir->destroyme))
-			add_timer(&redir->destroyme, jiffies + REDIR_TIMEOUT);
+		if (del_timer(&redir->destroyme)) {
+			redir->destroyme.expires = jiffies + REDIR_TIMEOUT;
+			add_timer(&redir->destroyme);
+		}
 	}
 	UNLOCK_BH(&redir_lock);
 }
diff -u --recursive --new-file pre1/linux/net/irda/af_irda.c linux/net/irda/af_irda.c
--- pre1/linux/net/irda/af_irda.c	Fri Nov 30 13:25:10 2001
+++ linux/net/irda/af_irda.c	Thu Jan 17 14:21:16 2002
@@ -2590,14 +2590,11 @@
 	register_netdevice_notifier(&irda_dev_notifier);
 
 	irda_init();
-#ifdef MODULE
- 	irda_device_init();  /* Called by init/main.c when non-modular */
-#endif
+ 	irda_device_init();
 	return 0;
 }
-#ifdef MODULE
-module_init(irda_proto_init);	/* If non-module, called from init/main.c */
-#endif
+
+late_initcall(irda_proto_init);
 
 /*
  * Function irda_proto_cleanup (void)
diff -u --recursive --new-file pre1/linux/net/socket.c linux/net/socket.c
--- pre1/linux/net/socket.c	Wed Jan 16 11:16:29 2002
+++ linux/net/socket.c	Thu Jan 17 14:29:59 2002
@@ -437,11 +437,11 @@
 	struct inode * inode;
 	struct socket * sock;
 
-	inode = get_empty_inode();
+	inode = new_inode(sock_mnt->mnt_sb);
 	if (!inode)
 		return NULL;
 
-	inode->i_sb = sock_mnt->mnt_sb;
+	inode->i_dev = NODEV;
 	sock = socki_lookup(inode);
 
 	inode->i_mode = S_IFSOCK|S_IRWXUGO;
diff -u --recursive --new-file pre1/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- pre1/linux/net/sunrpc/sched.c	Mon Jan 14 10:10:43 2002
+++ linux/net/sunrpc/sched.c	Tue Jan 15 13:53:51 2002
@@ -721,7 +721,7 @@
 
 		__rpc_execute(task);
 
-		if (++count >= 200 || current->need_resched) {
+		if (++count >= 200 || need_resched()) {
 			count = 0;
 			schedule();
 		}
