diff -u --recursive --new-file v2.3.10/linux/CREDITS linux/CREDITS
--- v2.3.10/linux/CREDITS	Thu Jul  8 15:42:19 1999
+++ linux/CREDITS	Sun Jul 18 14:08:53 1999
@@ -1714,12 +1714,13 @@
 S: France
 
 N: Rik van Riel
-E: H.H.vanRiel@humbolt.geo.uu.nl
-W: http://humbolt.geo.uu.nl/
-D: Maintainer of the mm-patches page (see www.linuxhq.com)
-D: Documentation/sysctl/*, kswapd fixes, random kernel hacker
-S: Vorenkampsweg 1
-S: NL-9488 TG  Zeijerveld
+E: riel@nl.linux.org
+W: http://www.nl.linux.org/~riel/
+D: Linux-MM site, Documentation/sysctl/*, swap/mm readaround
+D: clustering contributor, kswapd fixes, random kernel hacker,
+D: nl.linux.org maintainer, minor scheduler additions
+S: IJsselstraat 23a
+S: 9725 GA  Groningen
 S: The Netherlands
 
 N: William E. Roadcap
diff -u --recursive --new-file v2.3.10/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.10/linux/Documentation/Configure.help	Thu Jul  8 15:42:19 1999
+++ linux/Documentation/Configure.help	Wed Jul 21 12:54:07 1999
@@ -11945,13 +11945,15 @@
 
 Support for user-space parallel port device drivers
 CONFIG_PPDEV
-  Saying Y to this adds support for /dev/parport device nodes.
-  NB. You have to make them before you can use them:
-    mknod /dev/parport00 c 99 0
-    mknod /dev/parport01 c 99 1
-    mknod /dev/parport10 c 99 16
-    mknod /dev/parport11 c 99 17
-    etc..
+  Saying Y to this adds support for /dev/parport device nodes.  This
+  is needed for programs that want portable access to the parallel
+  port, for instance deviceid (which displays Plug-and-Play device
+  IDs) and vlp (which makes a Linux computer act as though it's a
+  printer).
+
+  This is the parallel port equivalent of SCSI generic support (sg).
+  It is safe to say N to this -- it is not needed for normal printing
+  or parallel port CD-ROM/disk support.
 
 #
 # A couple of things I keep forgetting:
diff -u --recursive --new-file v2.3.10/linux/Documentation/kernel-parameters.txt linux/Documentation/kernel-parameters.txt
--- v2.3.10/linux/Documentation/kernel-parameters.txt	Thu Jul  8 15:42:19 1999
+++ linux/Documentation/kernel-parameters.txt	Wed Jul 21 12:54:07 1999
@@ -19,7 +19,7 @@
     HW		Appropriate hardware is enabled.
     ISDN	Appropriate ISDN support is enabled.
     JOY 	Appropriate joystick support is enabled.
-    LPT 	Printer support is enabled.
+    LP		Printer support is enabled.
     MCA 	MCA bus support is enabled.
     MDA 	The MDA console is enabled.
     MOUSE	Appropriate mouse support is enabled.
@@ -29,6 +29,7 @@
     PCI 	PCI bus support is enabled.
     PCMCIA	The PCMCIA subsystem is enabled.
     PNP 	Plug & Play support is enabled.
+    PPT		Parallel port support is enabled.
     PS2 	Appropriate PS/2 support is enabled.
     RAM 	RAMdisc support is enabled.
     SCSI	Appropriate SCSI support is enabled.
@@ -187,7 +188,21 @@
 
     load_ramdisk=	[RAM]
 
-    lp= 		[LPT] Parallel Printer.
+    lp=0 		[LP] Specify parallel ports to use, e.g,
+or  lp=port[,port...]	lp=none,parport0 (lp0 not configured, lp1 uses
+or  lp=reset		first parallel port).  'lp=0' disables the printer
+or  lp=auto		driver.  'lp=reset' (which can be specified in
+			addition to the ports) causes attached
+			printers to be reset.  Using
+			lp=port1,port2,... specifies the parallel
+			ports to associate lp devices with, starting
+			with lp0.  A port specification may be 'none'
+			to skip that lp device, or a parport name such
+			as 'parport0'.  Specifying 'lp=auto' instead
+			of a port specification list means that device
+			IDs from each port should be examined, to see
+			if an IEEE 1284-compliant printer is attached;
+			if so, the driver will manage that printer.
 
     ltpc=		[HW]
 
@@ -244,7 +259,19 @@
 
     panic=		
 
-    parport=		[HW,LP]
+    parport=0			[HW,PPT] Specify parallel ports.  0
+or  parport=auto		disables.  Use 'auto' to force the driver
+or  parport=0xBBB[,IRQ[,DMA]]	to use any IRQ/DMA settings detected
+				(the default is to ignore detected
+				IRQ/DMA settings because of possible
+				conflicts).  You can specify the base
+				address, IRQ, and DMA settings; IRQ
+				and DMA should be numbers or 'auto'
+				(for using detected settings on that
+				particular port).  Parallel ports are
+				assigned in the order they are
+				specified on the command line,
+				starting with parport0.
 
     pas16=		[HW,SCSI]
 
@@ -262,7 +289,7 @@
 
     pirq=		[SMP,APIC]
 
-    plip=		[LP,NET] Parallel port network link.
+    plip=		[PPT,NET] Parallel port network link.
 
     profile=
 
diff -u --recursive --new-file v2.3.10/linux/Makefile linux/Makefile
--- v2.3.10/linux/Makefile	Thu Jul  8 15:42:19 1999
+++ linux/Makefile	Tue Jul 13 12:26:46 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 10
+SUBLEVEL = 11
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -87,6 +87,9 @@
 #
 
 CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+
+# use '-fno-strict-aliasing', but only if the compiler can take it
+CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi)
 
 ifdef CONFIG_SMP
 CFLAGS += -D__SMP__
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v2.3.10/linux/arch/alpha/kernel/Makefile	Sun Jan 10 09:59:54 1999
+++ linux/arch/alpha/kernel/Makefile	Mon Jul 12 07:49:36 1999
@@ -105,7 +105,7 @@
 endif
 
 # Device support
-ifdef CONFIG_ALPHA_MIATA
+ifneq ($(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_DP264),)
 O_OBJS   += es1888.o
 endif
 ifneq ($(CONFIG_ALPHA_SX164)$(CONFIG_ALPHA_MIATA)$(CONFIG_ALPHA_DP264),)
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.3.10/linux/arch/alpha/kernel/alpha_ksyms.c	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Mon Jul 12 07:49:36 1999
@@ -48,8 +48,6 @@
 extern void __remqu (void);
 
 EXPORT_SYMBOL(alpha_mv);
-EXPORT_SYMBOL(local_bh_count);
-EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
 EXPORT_SYMBOL(disable_irq_nosync);
@@ -178,6 +176,9 @@
 EXPORT_SYMBOL(write_lock);
 EXPORT_SYMBOL(read_lock);
 #endif
+#else /* __SMP__ */
+EXPORT_SYMBOL(__local_bh_count);
+EXPORT_SYMBOL(__local_irq_count);
 #endif /* __SMP__ */
 
 /*
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c
--- v2.3.10/linux/arch/alpha/kernel/core_pyxis.c	Mon Oct 12 11:40:12 1998
+++ linux/arch/alpha/kernel/core_pyxis.c	Mon Jul 12 07:49:36 1999
@@ -425,19 +425,24 @@
 {
 	/*
 	 * Set up the PCI->physical memory translation windows.
-	 * For now, windows 1,2 and 3 are disabled.  In the future, we may
+	 * For now, windows 2 and 3 are disabled.  In the future, we may
 	 * want to use them to do scatter/gather DMA. 
 	 *
-	 * Window 0 goes at 1 GB and is 1 GB large.
+	 * Window 0 goes at 2 GB and is 1 GB large.
+	 * Window 1 goes at 3 GB and is 1 GB large.
 	 */
 
-	*(vuip)PYXIS_W0_BASE = 1U | (PYXIS_DMA_WIN_BASE_DEFAULT & 0xfff00000U);
+	*(vuip)PYXIS_W0_BASE = PYXIS_DMA_WIN_BASE_DEFAULT | 1UL;
 	*(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U;
 	*(vuip)PYXIS_T0_BASE = 0;
 
-	*(vuip)PYXIS_W1_BASE = 0x0 ;
-	*(vuip)PYXIS_W2_BASE = 0x0 ;
-	*(vuip)PYXIS_W3_BASE = 0x0 ;
+	*(vuip)PYXIS_W1_BASE = (PYXIS_DMA_WIN_BASE_DEFAULT +
+				PYXIS_DMA_WIN_SIZE_DEFAULT) | 1U;
+	*(vuip)PYXIS_W1_MASK = (PYXIS_DMA_WIN_SIZE_DEFAULT - 1) & 0xfff00000U;
+	*(vuip)PYXIS_T1_BASE = PYXIS_DMA_WIN_SIZE_DEFAULT;
+
+	*(vuip)PYXIS_W2_BASE = 0x0;
+	*(vuip)PYXIS_W3_BASE = 0x0;
 	mb();
 }
 
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/es1888.c linux/arch/alpha/kernel/es1888.c
--- v2.3.10/linux/arch/alpha/kernel/es1888.c	Sun Aug  9 12:09:05 1998
+++ linux/arch/alpha/kernel/es1888.c	Mon Jul 12 07:49:36 1999
@@ -32,6 +32,7 @@
 		continue;
 	inb(0x022a);			/* pause */
 	outb(0xc6, 0x022c);		/* enable extended mode */
+	inb(0x022a);			/* pause, also forces the write */
 	while (inb(0x022c) & 0x80)	/* wait for bit 7 to deassert */
 		continue;
 	outb(0xb1, 0x022c);		/* setup for write to Interrupt CR */
@@ -44,4 +45,5 @@
 	while (inb(0x022c) & 0x80)	/* wait for bit 7 to deassert */
 		continue;
 	outb(0x18, 0x022c);		/* set DMA channel 1 */
+	inb(0x022c);			/* force the write */
 }
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.3.10/linux/arch/alpha/kernel/irq.c	Fri May 14 12:41:22 1999
+++ linux/arch/alpha/kernel/irq.c	Mon Jul 12 07:49:36 1999
@@ -35,9 +35,12 @@
 #define vulp	volatile unsigned long *
 #define vuip	volatile unsigned int *
 
-unsigned int local_irq_count[NR_CPUS];
-unsigned int local_bh_count[NR_CPUS];
-unsigned long hardirq_no[NR_CPUS];
+/* Only uniprocessor needs this IRQ/BH locking depth, on SMP it lives
+   in the per-cpu structure for cache reasons.  */
+#ifndef __SMP__
+int __local_irq_count;
+int __local_bh_count;
+#endif
 
 #if NR_IRQS > 64
 #  error Unable to handle more than 64 irq levels.
@@ -384,6 +387,8 @@
 
 static void show(char * str, void *where);
 
+#define SYNC_OTHER_CPUS(x)	udelay((x)+1);
+
 static inline void
 wait_on_irq(int cpu, void *where)
 {
@@ -397,8 +402,8 @@
 		 * already executing in one..
 		 */
 		if (!atomic_read(&global_irq_count)) {
-			if (local_bh_count[cpu] ||
-			    !atomic_read(&global_bh_count))
+			if (local_bh_count(cpu)
+			    || !atomic_read(&global_bh_count))
 				break;
 		}
 
@@ -412,19 +417,15 @@
 				count = MAXCOUNT;
 			}
 			__sti();
-#if 0
-			SYNC_OTHER_CORES(cpu);
-#else
-			udelay(cpu+1);
-#endif
+			SYNC_OTHER_CPUS(cpu);
 			__cli();
 
 			if (atomic_read(&global_irq_count))
 				continue;
-			if (global_irq_lock.lock)
+			if (spin_is_locked(&global_irq_lock))
 				continue;
-			if (!local_bh_count[cpu] &&
-			    atomic_read(&global_bh_count))
+			if (!local_bh_count(cpu)
+			    && atomic_read(&global_bh_count))
 				continue;
 			if (spin_trylock(&global_irq_lock))
 				break;
@@ -469,14 +470,14 @@
 void
 __global_cli(void)
 {
-	int cpu;
+	int cpu = smp_processor_id();
 	void *where = __builtin_return_address(0);
 
 	/*
 	 * Maximize ipl.  If ipl was previously 0 and if this thread
 	 * is not in an irq, then take global_irq_lock.
 	 */
-	if ((swpipl(7) == 0) && !local_irq_count[cpu = smp_processor_id()])
+	if (swpipl(7) == 0 && !local_irq_count(cpu))
 		get_irqlock(cpu, where);
 }
 
@@ -485,9 +486,8 @@
 {
         int cpu = smp_processor_id();
 
-        if (!local_irq_count[cpu]) {
+        if (!local_irq_count(cpu))
 		release_irqlock(cpu);
-	}
 	__sti();
 }
 
@@ -512,7 +512,7 @@
         retval = 2 + local_enabled;
 
         /* Check for global flags if we're not in an interrupt.  */
-        if (!local_irq_count[cpu]) {
+        if (!local_irq_count(cpu)) {
                 if (local_enabled)
                         retval = 1;
                 if (global_irq_holder == cpu)
@@ -550,7 +550,7 @@
 #define STUCK							\
   if (!--stuck) {						\
     printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",	\
-	   irq, cpu,global_irq_holder);				\
+	   irq, cpu, global_irq_holder);			\
     stuck = INIT_STUCK;						\
   }
 
@@ -566,11 +566,11 @@
 
 	hardirq_enter(cpu, irq);
 	barrier();
-	while (global_irq_lock.lock) {
+	while (spin_is_locked(&global_irq_lock)) {
 		if (cpu == global_irq_holder) {
-			int globl_locked = global_irq_lock.lock;
+			int globl_locked = spin_is_locked(&global_irq_lock);
 			int globl_icount = atomic_read(&global_irq_count);
-			int local_count = local_irq_count[cpu];
+			int local_count = local_irq_count(cpu);
 
 			/* It is very important that we load the state
 			   variables before we do the first call to
@@ -609,19 +609,16 @@
 #endif
         int cpu = smp_processor_id();
 
-	int global_count = atomic_read(&global_irq_count);
-        int local_count0 = local_irq_count[0];
-        int local_count1 = local_irq_count[1];
-        long hardirq_no0 = hardirq_no[0];
-        long hardirq_no1 = hardirq_no[1];
-
         printk("\n%s, CPU %d: %p\n", str, cpu, where);
-        printk("irq:  %d [%d(0x%016lx) %d(0x%016lx)]\n", global_count,
-               local_count0, hardirq_no0, local_count1, hardirq_no1);
+        printk("irq:  %d [%d %d]\n",
+	       atomic_read(&global_irq_count),
+               cpu_data[0].irq_count,
+	       cpu_data[1].irq_count);
 
         printk("bh:   %d [%d %d]\n",
-	       atomic_read(&global_bh_count), local_bh_count[0],
-	       local_bh_count[1]);
+	       atomic_read(&global_bh_count),
+	       cpu_data[0].bh_count,
+	       cpu_data[1].bh_count);
 #if 0
         stack = (unsigned long *) &str;
         for (i = 40; i ; i--) {
@@ -644,6 +641,7 @@
                         count = ~0;
                 }
                 /* nothing .. wait for the other bh's to go away */
+		barrier();
         } while (atomic_read(&global_bh_count) != 0);
 }
 
@@ -658,12 +656,8 @@
 void
 synchronize_bh(void)
 {
-	if (atomic_read(&global_bh_count)) {
-		int cpu = smp_processor_id();
-                if (!local_irq_count[cpu] && !local_bh_count[cpu]) {
-			wait_on_bh();
-		}
-        }
+	if (atomic_read(&global_bh_count) && !in_interrupt())
+		wait_on_bh();
 }
 
 /*
@@ -680,6 +674,8 @@
 void
 synchronize_irq(void)
 {
+#if 0
+	/* Joe's version.  */
 	int cpu = smp_processor_id();
 	int local_count;
 	int global_count;
@@ -688,7 +684,7 @@
 
 	mb();
 	do {
-		local_count = local_irq_count[cpu];
+		local_count = local_irq_count(cpu);
 		global_count = atomic_read(&global_irq_count);
 		if (DEBUG_SYNCHRONIZE_IRQ && (--countdown == 0)) {
 			printk("%d:%d/%d\n", cpu, local_count, global_count);
@@ -696,12 +692,19 @@
 			break;
 		}
 	} while (global_count != local_count);
+#else
+	/* Jay's version.  */
+	if (atomic_read(&global_irq_count)) {
+		cli();
+		sti();
+	}
+#endif
 }
 
 #else /* !__SMP__ */
 
-#define irq_enter(cpu, irq)	(++local_irq_count[cpu])
-#define irq_exit(cpu, irq)	(--local_irq_count[cpu])
+#define irq_enter(cpu, irq)	(++local_irq_count(cpu))
+#define irq_exit(cpu, irq)	(--local_irq_count(cpu))
 
 #endif /* __SMP__ */
 
@@ -868,31 +871,23 @@
 	  unsigned long a3, unsigned long a4, unsigned long a5,
 	  struct pt_regs regs)
 {
-	unsigned long flags;
-
 	switch (type) {
 	case 0:
 #ifdef __SMP__
-		__save_and_cli(flags);
 		handle_ipi(&regs);
-		__restore_flags(flags);
 		return;
 #else
 		printk("Interprocessor interrupt? You must be kidding\n");
 #endif
 		break;
 	case 1:
-		__save_and_cli(flags);
 		handle_irq(RTC_IRQ, -1, &regs);
-		__restore_flags(flags);
 		return;
 	case 2:
 		alpha_mv.machine_check(vector, la_ptr, &regs);
 		return;
 	case 3:
-		__save_and_cli(flags);
 		alpha_mv.device_interrupt(vector, &regs);
-		__restore_flags(flags);
 		return;
 	case 4:
 		perf_irq(vector, &regs);
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/irq.h linux/arch/alpha/kernel/irq.h
--- v2.3.10/linux/arch/alpha/kernel/irq.h	Wed Dec 30 15:06:22 1998
+++ linux/arch/alpha/kernel/irq.h	Mon Jul 12 07:49:36 1999
@@ -31,3 +31,19 @@
 #define TIMER_IRQ  RTC_IRQ		 /* timer is the rtc */
 #endif
 
+extern char _stext;
+static inline void alpha_do_profile (unsigned long pc)
+{
+	if (prof_buffer && current->pid) {
+		pc -= (unsigned long) &_stext;
+		pc >>= prof_shift;
+		/*
+		 * Don't ignore out-of-bounds PC values silently,
+		 * put them into the last histogram slot, so if
+		 * present, they will show up as a sharp peak.
+		 */
+		if (pc > prof_len - 1)
+			pc = prof_len - 1;
+		atomic_inc((atomic_t *)&prof_buffer[pc]);
+	}
+}
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.3.10/linux/arch/alpha/kernel/osf_sys.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/alpha/kernel/osf_sys.c	Mon Jul 12 07:49:36 1999
@@ -927,6 +927,7 @@
 			return -EINVAL;
 		cpu = (struct percpu_struct*)
 		  ((char*)hwrpb + hwrpb->processor_offset);
+		w = cpu->type;
 		if (put_user(w, (unsigned long *)buffer))
 			return -EFAULT;
 		return 1;
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.3.10/linux/arch/alpha/kernel/process.c	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/kernel/process.c	Mon Jul 12 07:49:36 1999
@@ -76,7 +76,7 @@
 }
 
 #ifdef __SMP__
-void
+int
 cpu_idle(void *unused)
 {
 	/* An endless idle loop with no priority at all.  */
@@ -329,7 +329,6 @@
 	p->tss.ksp = (unsigned long) childstack;
 	p->tss.pal_flags = 1;	/* set FEN, clear everything else */
 	p->tss.flags = current->tss.flags;
-	p->tss.mm_context = p->tss.asn = 0;
 
 	return 0;
 }
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h
--- v2.3.10/linux/arch/alpha/kernel/proto.h	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/kernel/proto.h	Mon Jul 12 07:49:36 1999
@@ -193,7 +193,7 @@
 
 /* process.c */
 extern void generic_kill_arch (int mode, char *reboot_cmd);
-extern void cpu_idle(void *) __attribute__((noreturn));
+extern int cpu_idle(void *) __attribute__((noreturn));
 
 /* ptrace.c */
 extern int ptrace_set_bpt (struct task_struct *child);
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v2.3.10/linux/arch/alpha/kernel/ptrace.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/alpha/kernel/ptrace.c	Mon Jul 12 07:49:36 1999
@@ -231,7 +231,6 @@
 	   int a4, int a5, struct pt_regs regs)
 {
 	struct task_struct *child;
-	unsigned long tmp;
 	long ret;
 
 	lock_kernel();
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.3.10/linux/arch/alpha/kernel/smp.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/alpha/kernel/smp.c	Mon Jul 12 07:49:36 1999
@@ -97,6 +97,8 @@
 	cpu_data[cpuid].loops_per_sec = loops_per_sec;
 	cpu_data[cpuid].last_asn
 	  = (cpuid << WIDTH_HARDWARE_ASN) + ASN_FIRST_VERSION;
+	cpu_data[cpuid].irq_count = 0;
+	cpu_data[cpuid].bh_count = 0;
 }
 
 /*
@@ -107,12 +109,6 @@
 {
 	cpu_data[cpuid].prof_counter = 1;
 	cpu_data[cpuid].prof_multiplier = 1;
-
-#ifdef NOT_YET_PROFILING
-	load_profile_irq(mid_xlate[cpu], lvl14_resolution);
-	if (cpu == smp_boot_cpuid)
-		enable_pil_irq(14);
-#endif
 }
 
 /*
@@ -586,14 +582,12 @@
 smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
-	int user = user_mode(regs);
+	unsigned long user = user_mode(regs);
 	struct cpuinfo_alpha *data = &cpu_data[cpu];
 
-#ifdef NOT_YET_PROFILING
-	clear_profile_irq(mid_xlate[cpu]);
+	/* Record kernel PC.  */
 	if (!user)
 		alpha_do_profile(regs->pc);
-#endif
 
 	if (!--data->prof_counter) {
 		/* We need to make like a normal interrupt -- otherwise
@@ -630,28 +624,7 @@
 int __init
 setup_profiling_timer(unsigned int multiplier)
 {
-#ifdef NOT_YET_PROFILING
-	int i;
-	unsigned long flags;
-
-	/* Prevent level14 ticker IRQ flooding. */
-	if((!multiplier) || (lvl14_resolution / multiplier) < 500)
-	        return -EINVAL;
-
-	save_and_cli(flags);
-	for (i = 0; i < NR_CPUS; i++) {
-	        if (cpu_present_mask & (1L << i)) {
-	                load_profile_irq(mid_xlate[i],
-					 lvl14_resolution / multiplier);
-	                prof_multiplier[i] = multiplier;
-	        }
-	}
-	restore_flags(flags);
-
-	return 0;
-#else
 	return -EINVAL;
-#endif
 }
 
 
@@ -893,9 +866,11 @@
 void
 flush_tlb_mm(struct mm_struct *mm)
 {
-	if (mm == current->mm)
+	if (mm == current->mm) {
 		flush_tlb_current(mm);
-	else
+		if (atomic_read(&mm->count) == 1)
+			return;
+	} else
 		flush_tlb_other(mm);
 
 	if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) {
@@ -923,15 +898,17 @@
 	struct flush_tlb_page_struct data;
 	struct mm_struct *mm = vma->vm_mm;
 
+	if (mm == current->mm) {
+		flush_tlb_current_page(mm, vma, addr);
+		if (atomic_read(&mm->count) == 1)
+			return;
+	} else
+		flush_tlb_other(mm);
+
 	data.vma = vma;
 	data.mm = mm;
 	data.addr = addr;
 
-	if (mm == current->mm)
-		flush_tlb_current_page(mm, vma, addr);
-	else
-		flush_tlb_other(mm);
-	
 	if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) {
 		printk(KERN_CRIT "flush_tlb_page: timed out\n");
 	}
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/sys_dp264.c linux/arch/alpha/kernel/sys_dp264.c
--- v2.3.10/linux/arch/alpha/kernel/sys_dp264.c	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/kernel/sys_dp264.c	Mon Jul 12 07:49:36 1999
@@ -393,8 +393,8 @@
 {
 	layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
 	common_pci_fixup(monet_map_irq, monet_swizzle);
-	/* es1888_init(); */ /* later? */
 	SMC669_Init(1);
+	es1888_init();
 }
 
 static void __init
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.3.10/linux/arch/alpha/kernel/time.c	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/kernel/time.c	Mon Jul 12 07:49:36 1999
@@ -94,6 +94,10 @@
 	smp_percpu_timer_interrupt(regs);
 	if (smp_processor_id() != smp_boot_cpuid)
 		return;
+#else
+	/* Not SMP, do kernel PC profiling here.  */
+	if (!user_mode(regs))
+		alpha_do_profile(regs->pc);
 #endif
 
 	write_lock(&xtime_lock);
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/math-emu/ieee-math.c linux/arch/alpha/math-emu/ieee-math.c
--- v2.3.10/linux/arch/alpha/math-emu/ieee-math.c	Mon May 10 09:55:21 1999
+++ linux/arch/alpha/math-emu/ieee-math.c	Mon Jul 12 07:49:36 1999
@@ -704,20 +704,21 @@
  *       FPCR_INV if invalid operation occurred, etc.
  */
 unsigned long
-ieee_CVTQT (int f, unsigned long a, unsigned long *b)
+ieee_CVTQT (int f, long a, unsigned long *b)
 {
 	EXTENDED op_b;
 
-	op_b.s    = 0;
-	op_b.f[0] = a;
-	op_b.f[1] = 0;
-	if (sign(a) < 0) {
-		op_b.s = 1;
-		op_b.f[0] = -a;
+	if (a != 0) {
+		op_b.s = (a < 0 ? 1 : 0);
+		op_b.f[0] = (a < 0 ? -a : a);
+		op_b.f[1] = 0;
+		op_b.e = 55;
+		normalize(&op_b);
+		return round_t_ieee(f, &op_b, b);
+	} else {
+		*b = 0;
+		return 0;
 	}
-	op_b.e = 55;
-	normalize(&op_b);
-	return round_t_ieee(f, &op_b, b);
 }
 
 
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/math-emu/ieee-math.h linux/arch/alpha/math-emu/ieee-math.h
--- v2.3.10/linux/arch/alpha/math-emu/ieee-math.h	Mon May 10 09:55:21 1999
+++ linux/arch/alpha/math-emu/ieee-math.h	Mon Jul 12 07:49:36 1999
@@ -20,7 +20,7 @@
 extern unsigned long ieee_CVTST (int rm, unsigned long a, unsigned long *b);
 extern unsigned long ieee_CVTTS (int rm, unsigned long a, unsigned long *b);
 extern unsigned long ieee_CVTQS (int rm, unsigned long a, unsigned long *b);
-extern unsigned long ieee_CVTQT (int rm, unsigned long a, unsigned long *b);
+extern unsigned long ieee_CVTQT (int rm, long a, unsigned long *b);
 extern unsigned long ieee_CVTTQ (int rm, unsigned long a, unsigned long *b);
 
 extern unsigned long ieee_CMPTEQ (unsigned long a, unsigned long b,
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v2.3.10/linux/arch/alpha/mm/fault.c	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/mm/fault.c	Mon Jul 12 07:49:36 1999
@@ -41,7 +41,7 @@
 get_new_mmu_context(struct task_struct *p, struct mm_struct *mm)
 {
 	unsigned long new = __get_new_mmu_context(p, mm);
-	p->tss.mm_context = new;
+	mm->context = new;
 	p->tss.asn = new & HARDWARE_ASN_MASK;
 }
 
diff -u --recursive --new-file v2.3.10/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.3.10/linux/arch/alpha/mm/init.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/alpha/mm/init.c	Mon Jul 12 07:49:36 1999
@@ -173,7 +173,7 @@
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
 
-static inline struct thread_struct *
+static inline unsigned long
 load_PCB(struct thread_struct * pcb)
 {
 	register unsigned long sp __asm__("$30");
@@ -192,7 +192,7 @@
 	unsigned long newptbr;
 	struct memclust_struct * cluster;
 	struct memdesc_struct * memdesc;
-	struct thread_struct *original_pcb_ptr;
+	unsigned long original_pcb_ptr;
 
 	/* initialize mem_map[] */
 	start_mem = free_area_init(start_mem, end_mem);
@@ -246,11 +246,11 @@
 	   since KSEG values also happen to work, folks get confused.
 	   Check this here.  */
 
-	if ((unsigned long)original_pcb_ptr < PAGE_OFFSET) {
-		original_pcb_ptr = (struct thread_struct *)
-		  phys_to_virt((unsigned long) original_pcb_ptr);
+	if (original_pcb_ptr < PAGE_OFFSET) {
+		original_pcb_ptr = (unsigned long)
+			phys_to_virt(original_pcb_ptr);
 	}
-	original_pcb = *original_pcb_ptr;
+	original_pcb = *(struct thread_struct *) original_pcb_ptr;
 
 	return start_mem;
 }
diff -u --recursive --new-file v2.3.10/linux/arch/arm/def-configs/a5k linux/arch/arm/def-configs/a5k
--- v2.3.10/linux/arch/arm/def-configs/a5k	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/def-configs/a5k	Mon Jul 19 09:52:57 1999
@@ -0,0 +1,425 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+CONFIG_ARCH_A5K=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_FOOTBRIDGE is not set
+CONFIG_ARCH_ACORN=y
+# CONFIG_ISA_DMA is not set
+# CONFIG_CPU_32 is not set
+CONFIG_CPU_26=y
+# CONFIG_CPU_ARM2 is not set
+CONFIG_CPU_ARM3=y
+# CONFIG_CPU_ARM6 is not set
+# CONFIG_CPU_ARM7 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_PAGESIZE_32=y
+# CONFIG_PAGESIZE_16 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_TEXT_SECTIONS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_NWFPE is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=m
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Acorn-specific block devices
+#
+CONFIG_BLK_DEV_IDE_CARDS=y
+CONFIG_BLK_DEV_IDE_ICSIDE=y
+# CONFIG_BLK_DEV_IDE_RAPIDE is not set
+# CONFIG_BLK_DEV_FD1772 is not set
+CONFIG_BLK_DEV_MFM=m
+CONFIG_BLK_DEV_MFM_AUTODETECT=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_ATOMWIDE_SERIAL=y
+CONFIG_DUALSP_SERIAL=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_PRINTER=y
+CONFIG_PRINTER_READBACK=y
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_KBDMOUSE=y
+
+#
+# Console drivers
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_ACORN=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_MFB=y
+CONFIG_FBCON_CFB2=y
+CONFIG_FBCON_CFB4=y
+CONFIG_FBCON_CFB8=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_FONT_ACORN_8x8=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_RARP is not set
+# CONFIG_SKB_LARGE is not set
+# CONFIG_IPV6 is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA subsystem support
+#
+# CONFIG_IRDA is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_ARM_ETHER1=y
+CONFIG_ARM_ETHER3=y
+# CONFIG_ARM_ETHERH is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+CONFIG_SCSI_PPA=m
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_ACORNSCSI_3=y
+CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y
+CONFIG_SCSI_ACORNSCSI_SYNC=y
+CONFIG_SCSI_ARXESCSI=m
+# CONFIG_SCSI_CUMANA_2 is not set
+CONFIG_SCSI_EESOXSCSI=y
+# CONFIG_SCSI_POWERTECSCSI is not set
+
+#
+# The following drivers are not fully supported
+#
+# CONFIG_SCSI_CUMANA_1 is not set
+# CONFIG_SCSI_ECOSCSI is not set
+# CONFIG_SCSI_OAK1 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_ADFS_FS=y
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_SUN is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ADFS=y
+CONFIG_ACORN_PARTITION_ICS=y
+CONFIG_ACORN_PARTITION_POWERTEC=y
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_NO_PGT_CACHE=y
+# CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.10/linux/arch/arm/def-configs/ebsa110 linux/arch/arm/def-configs/ebsa110
--- v2.3.10/linux/arch/arm/def-configs/ebsa110	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/def-configs/ebsa110	Mon Jul 19 09:52:57 1999
@@ -0,0 +1,308 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_EBSA110=y
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_ISA_DMA is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM2 is not set
+# CONFIG_CPU_ARM3 is not set
+# CONFIG_CPU_ARM6 is not set
+# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_SA110=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_TEXT_SECTIONS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_NWFPE is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=m
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_CMDLINE="root=/dev/nfs rw mem=16M console=ttyS1,38400n8"
+CONFIG_LEDS=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_IDE is not set
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_ONLY is not set
+
+#
+# Additional Block Devices
+#
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_DETECT_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_PRINTER=m
+CONFIG_PRINTER_READBACK=y
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_QIC02_TAPE is not set
+CONFIG_WATCHDOG=y
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_WDT is not set
+CONFIG_SOFT_WATCHDOG=y
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+# CONFIG_NETLINK is not set
+CONFIG_FIREWALL=y
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_IP_FIREWALL=y
+CONFIG_IP_ALWAYS_DEFRAG=y
+# CONFIG_IP_TRANSPARENT_PROXY is not set
+CONFIG_IP_MASQUERADE=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+CONFIG_IP_MASQUERADE_ICMP=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+# CONFIG_IP_MASQUERADE_MOD is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_RARP is not set
+# CONFIG_SKB_LARGE is not set
+# CONFIG_IPV6 is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA subsystem support
+#
+# CONFIG_IRDA is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_ARM_AM79C961A=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=m
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+CONFIG_MINIX_FS=y
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_EXT2_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_ARTHUR is not set
+# CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.10/linux/arch/arm/def-configs/footbridge linux/arch/arm/def-configs/footbridge
--- v2.3.10/linux/arch/arm/def-configs/footbridge	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/def-configs/footbridge	Mon Jul 19 09:52:57 1999
@@ -0,0 +1,493 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_EBSA110 is not set
+CONFIG_FOOTBRIDGE=y
+CONFIG_HOST_FOOTBRIDGE=y
+# CONFIG_ADDIN_FOOTBRIDGE is not set
+CONFIG_ARCH_EBSA285=y
+# CONFIG_CATS is not set
+CONFIG_ARCH_NETWINDER=y
+# CONFIG_ARCH_ACORN is not set
+CONFIG_PCI=y
+CONFIG_ISA_DMA=y
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM2 is not set
+# CONFIG_CPU_ARM3 is not set
+# CONFIG_CPU_ARM6 is not set
+# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_SA110=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ALIGNMENT_TRAP is not set
+# CONFIG_TEXT_SECTIONS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_NWFPE=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_CMDLINE="root=/dev/hda2 ro mem=32M parport=0x378,7 ide0=autotune"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+# CONFIG_LEDS_CPU is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_BLK_DEV_IDEDMA=y
+CONFIG_BLK_DEV_OFFBOARD=y
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_CMD646 is not set
+CONFIG_BLK_DEV_SL82C105=y
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
+CONFIG_MD_MIRRORING=m
+CONFIG_MD_RAID5=m
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_PRINTER=m
+CONFIG_PRINTER_READBACK=y
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_QIC02_TAPE is not set
+CONFIG_WATCHDOG=y
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_WDT is not set
+CONFIG_SOFT_WATCHDOG=y
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_ACQUIRE_WDT is not set
+CONFIG_DS1620=y
+CONFIG_NWBUTTON=y
+CONFIG_NWBUTTON_REBOOT=y
+CONFIG_NWFLASH=m
+# CONFIG_NVRAM is not set
+CONFIG_RTC=y
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
+CONFIG_FB_CYBER2000=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+CONFIG_FBCON_VGA=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+CONFIG_FONT_ACORN_8x8=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_RARP is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA subsystem support
+#
+# CONFIG_IRDA is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+# CONFIG_EL3 is not set
+# CONFIG_3C515 is not set
+CONFIG_VORTEX=y
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_DE4X5 is not set
+CONFIG_DEC_ELCP=m
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_NE3210 is not set
+CONFIG_NE2K_PCI=y
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_ES3210 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_PAS is not set
+CONFIG_SOUND_SB=m
+CONFIG_SOUND_ADLIB=m
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_VIDC is not set
+CONFIG_SOUND_WAVEARTIST=m
+CONFIG_WAVEARTIST_BASE=250
+CONFIG_WAVEARTIST_IRQ=12
+CONFIG_WAVEARTIST_DMA=3
+CONFIG_WAVEARTIST_DMA2=7
+
+#
+# Additional low level sound drivers
+#
+# CONFIG_LOWLEVEL_SOUND is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_ADFS_FS=y
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+# CONFIG_NFSD_SUN is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ADFS=y
+# CONFIG_ACORN_PARTITION_ICS is not set
+# CONFIG_ACORN_PARTITION_POWERTEC is not set
+# CONFIG_ACORN_PARTITION_RISCIX is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.10/linux/arch/arm/def-configs/rpc linux/arch/arm/def-configs/rpc
--- v2.3.10/linux/arch/arm/def-configs/rpc	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/def-configs/rpc	Mon Jul 19 09:52:57 1999
@@ -0,0 +1,471 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+
+#
+# System and processor type
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+CONFIG_ARCH_RPC=y
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_FOOTBRIDGE is not set
+CONFIG_ARCH_ACORN=y
+# CONFIG_ISA_DMA is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM2 is not set
+# CONFIG_CPU_ARM3 is not set
+# CONFIG_CPU_ARM6 is not set
+# CONFIG_CPU_ARM7 is not set
+CONFIG_CPU_SA110=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ALIGNMENT_TRAP is not set
+# CONFIG_TEXT_SECTIONS is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_NWFPE is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=y
+CONFIG_BLK_DEV_IDEFLOPPY=y
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# Acorn-specific block devices
+#
+CONFIG_BLK_DEV_IDE_CARDS=y
+CONFIG_BLK_DEV_IDE_ICSIDE=y
+CONFIG_BLK_DEV_IDE_RAPIDE=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_ATOMWIDE_SERIAL=y
+CONFIG_DUALSP_SERIAL=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_PRINTER=m
+CONFIG_PRINTER_READBACK=y
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Joystick support
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+CONFIG_RPCMOUSE=y
+
+#
+# Console drivers
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_ACORN=y
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+CONFIG_FBCON_MFB=y
+CONFIG_FBCON_CFB2=y
+CONFIG_FBCON_CFB4=y
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+CONFIG_FONT_ACORN_8x8=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_ALIAS is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_RARP is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA subsystem support
+#
+# CONFIG_IRDA is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_ARM_ETHER1=m
+CONFIG_ARM_ETHER3=m
+CONFIG_ARM_ETHERH=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_ACENIC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+# CONFIG_SLIP is not set
+# CONFIG_NET_RADIO is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_SCSI_ACORNSCSI_3=m
+CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y
+CONFIG_SCSI_ACORNSCSI_SYNC=y
+CONFIG_SCSI_ARXESCSI=m
+CONFIG_SCSI_CUMANA_2=m
+CONFIG_SCSI_EESOXSCSI=m
+CONFIG_SCSI_POWERTECSCSI=m
+
+#
+# The following drivers are not fully supported
+#
+CONFIG_SCSI_CUMANA_1=m
+CONFIG_SCSI_OAK1=m
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_PAS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_SOFTOSS is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_UART6850 is not set
+CONFIG_SOUND_VIDC=m
+# CONFIG_SOUND_WAVEARTIST is not set
+
+#
+# Additional low level sound drivers
+#
+# CONFIG_LOWLEVEL_SOUND is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_ADFS_FS=y
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+CONFIG_NFS_FS=y
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ADFS=y
+CONFIG_ACORN_PARTITION_ICS=y
+CONFIG_ACORN_PARTITION_POWERTEC=y
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_ISO8859_9=m
+# CONFIG_NLS_ISO8859_15 is not set
+CONFIG_NLS_KOI8_R=m
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_ARTHUR is not set
+# CONFIG_DEBUG_LL is not set
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/Makefile linux/arch/arm/kernel/Makefile
--- v2.3.10/linux/arch/arm/kernel/Makefile	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/Makefile	Mon Jul 19 09:52:57 1999
@@ -20,7 +20,7 @@
 O_OBJS_a5k        = dma-a5k.o iic.o fiq.o
 O_OBJS_rpc        = dma-rpc.o iic.o fiq.o
 O_OBJS_ebsa110    = dma-dummy.o
-O_OBJS_footbridge = dma-footbridge.o $(ISA_DMA_OBJS)
+O_OBJS_footbridge = dma-footbridge.o $(ISA_DMA_OBJS) isa.o
 O_OBJS_nexuspci   = dma-dummy.o
 
 OX_OBJS_arc	  = dma.o
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/armksyms.c linux/arch/arm/kernel/armksyms.c
--- v2.3.10/linux/arch/arm/kernel/armksyms.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/armksyms.c	Mon Jul 19 09:52:57 1999
@@ -116,10 +116,6 @@
 EXPORT_SYMBOL(insw);
 EXPORT_SYMBOL(insl);
 
-EXPORT_SYMBOL(_memcpy_fromio);
-EXPORT_SYMBOL(_memcpy_toio);
-EXPORT_SYMBOL(_memset_io);
-
 	/* address translation */
 #ifndef __virt_to_phys__is_a_macro
 EXPORT_SYMBOL(__virt_to_phys);
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/calls.S linux/arch/arm/kernel/calls.S
--- v2.3.10/linux/arch/arm/kernel/calls.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/calls.S	Mon Jul 19 09:52:57 1999
@@ -157,8 +157,8 @@
 /* 145 */	.long	SYMBOL_NAME(sys_readv)
 		.long	SYMBOL_NAME(sys_writev)
 		.long	SYMBOL_NAME(sys_getsid)
-		.long	SYMBOL_NAME(sys_ni_syscall)
-		.long	SYMBOL_NAME(sys_ni_syscall)
+		.long	SYMBOL_NAME(sys_fdatasync)
+		.long	SYMBOL_NAME(sys_sysctl)
 /* 150 */	.long	SYMBOL_NAME(sys_mlock)
 		.long	SYMBOL_NAME(sys_munlock)
 		.long	SYMBOL_NAME(sys_mlockall)
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/dma-arc.c linux/arch/arm/kernel/dma-arc.c
--- v2.3.10/linux/arch/arm/kernel/dma-arc.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/dma-arc.c	Mon Jul 19 09:52:57 1999
@@ -100,7 +100,7 @@
 int arch_get_dma_residue(dmach_t channel, dma_t *dma)
 {
   switch (channel) {
-#ifdef CONFIG_BLK_DEV_FD
+#ifdef CONFIG_BLK_DEV_FD1772
     case DMA_VIRTUAL_FLOPPY0: { /* Data DMA */
         extern unsigned int fdc1772_bytestogo;
 
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/entry-armv.S linux/arch/arm/kernel/entry-armv.S
--- v2.3.10/linux/arch/arm/kernel/entry-armv.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/entry-armv.S	Mon Jul 19 09:52:57 1999
@@ -244,6 +244,10 @@
 		movne	\irqnr, #IRQ_PCI
 		bne	1001f
 
+		tst	\irqstat, #IRQ_MASK_DOORBELLHOST
+		movne	\irqnr, #IRQ_DOORBELLHOST
+		bne     1001f
+	
 		tst	\irqstat, #IRQ_MASK_I2OINPOST
 		movne	\irqnr, #IRQ_I2OINPOST
 		bne	1001f
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.3.10/linux/arch/arm/kernel/entry-common.S	Wed Jun 30 13:38:18 1999
+++ linux/arch/arm/kernel/entry-common.S	Mon Jul 19 09:52:57 1999
@@ -132,7 +132,8 @@
 SYMBOL_NAME(sys_syscall):
 		eor	r6, r0, #OS_NUMBER << 20
 		cmp	r6, #NR_syscalls	@ check range
-		ldmleib	sp, {r0 - r4}		@ get our args
+		add	ip, sp, #4
+		ldmleib	ip, {r0 - r4}		@ get our args
 		strle	r4, [sp]		@ Put our arg on the stack
 		ldrle	pc, [r5, r6, lsl #2]
 		mov	r0, #-ENOSYS
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/head-armv.S linux/arch/arm/kernel/head-armv.S
--- v2.3.10/linux/arch/arm/kernel/head-armv.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/head-armv.S	Mon Jul 19 09:52:57 1999
@@ -72,6 +72,8 @@
  *  r1 = 6 -> CATS
  *  r1 = 7 -> tbox
  *  r1 = 8 -> SA110/21285 as co-processor
+ *  r1 = 9 -> CL-PS7110 system
+ *  r1 = 12 -> SA1100 based system
  */
 
 __entry:	teq	r0, #0					@ check for illegal entry...
@@ -245,6 +247,12 @@
 		.long	DC21285_ARMCSR_BASE			@ Physical I/O base address
 		.long	0x7cf00000 >> 18			@ Virtual I/O base address
 
+		@ SA1100
+		.long	SYMBOL_NAME(swapper_pg_dir) - 0xc0000000 + 0xc0000000
+		.long	0xc0000000
+		.long	0x80000000				@ IO mapping will change when kernel gets on its feet
+		.long	0x3800
+
 .LCProcTypes:	@ ARM6 / 610
 		.long	0x41560600
 		.long	0xffffff00
@@ -266,9 +274,9 @@
 		b	.Larmv3_flush_late			@ arm v3 flush & ctrl late setup
 		mov	pc, lr
 
-		@ StrongARM
-		.long	0x4401a100
-		.long	0xfffffff0
+		@ StrongARM-110 and StrongARM-1100
+		.long	0x4401a100				@ 4401a100 and 4401a110
+		.long	0xffffffe0
 		.long	0x00000c02
 		b	.Larmv4_flush_early
 		b	.Lsa_fastclock
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/hw-footbridge.c linux/arch/arm/kernel/hw-footbridge.c
--- v2.3.10/linux/arch/arm/kernel/hw-footbridge.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/hw-footbridge.c	Mon Jul 19 09:52:57 1999
@@ -866,8 +866,63 @@
 #define DEFAULT_LEDS	GPIO_GREEN_LED
 #endif
 
+/*
+ * CATS stuff
+ */
+#ifdef CONFIG_CATS
+
+#define CONFIG_PORT	0x370
+#define INDEX_PORT	(CONFIG_PORT)
+#define DATA_PORT	(CONFIG_PORT + 1)
+
+static void __init cats_hw_init(void)
+{
+	/* Set Aladdin to CONFIGURE mode */
+	outb(0x51, CONFIG_PORT);
+	outb(0x23, CONFIG_PORT);
+
+	/* Select logical device 3 */
+	outb(0x07, INDEX_PORT);
+	outb(0x03, DATA_PORT);
+
+	/* Set parallel port to DMA channel 3, ECP+EPP1.9, 
+	   enable EPP timeout */
+	outb(0x74, INDEX_PORT);
+	outb(0x03, DATA_PORT);
+	
+	outb(0xf0, INDEX_PORT);
+	outb(0x0f, DATA_PORT);
+
+	outb(0xf1, INDEX_PORT);
+	outb(0x07, DATA_PORT);
+
+	/* Select logical device 4 */
+	outb(0x07, INDEX_PORT);
+	outb(0x04, DATA_PORT);
+
+	/* UART1 high speed mode */
+	outb(0xf0, INDEX_PORT);
+	outb(0x02, DATA_PORT);
+
+	/* Select logical device 5 */
+	outb(0x07, INDEX_PORT);
+	outb(0x05, DATA_PORT);
+
+	/* UART2 high speed mode */
+	outb(0xf0, INDEX_PORT);
+	outb(0x02, DATA_PORT);
+
+	/* Set Aladdin to RUN mode */
+	outb(0xbb, CONFIG_PORT);
+}
+
+#endif
+
 __initfunc(void hw_init(void))
 {
+	extern void register_isa_ports(unsigned int, unsigned int, 
+				       unsigned int);
+	register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0);
 #ifdef CONFIG_ARCH_NETWINDER
 	/*
 	 * this ought to have a better home...
@@ -888,6 +943,9 @@
 		spin_unlock_irqrestore(&gpio_lock, flags);
 	}
 #endif
+
+	if (machine_is_cats())
+		cats_hw_init();
 
 	leds_event(led_start);
 }
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/isa.c linux/arch/arm/kernel/isa.c
--- v2.3.10/linux/arch/arm/kernel/isa.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/kernel/isa.c	Mon Jul 19 09:52:57 1999
@@ -0,0 +1,47 @@
+/*
+ * arch/arm/kernel/isa.c
+ *
+ * ISA shared memory and I/O port support
+ *
+ * Copyright (C) 1999 Phil Blundell
+ */
+
+/* 
+ * Nothing about this is actually ARM specific.  One day we could move
+ * it into kernel/resource.c or some place like that.  
+ */
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/linkage.h>
+#include <linux/fs.h>
+#include <linux/sysctl.h>
+#include <linux/init.h>
+
+static unsigned int isa_membase, isa_portbase, isa_portshift;
+
+static ctl_table ctl_isa_vars[4] = {
+	{BUS_ISA_MEM_BASE, "membase", &isa_membase, 
+	 sizeof(isa_membase), 0444, NULL, &proc_dointvec},
+	{BUS_ISA_PORT_BASE, "portbase", &isa_portbase, 
+	 sizeof(isa_portbase), 0444, NULL, &proc_dointvec},
+	{BUS_ISA_PORT_SHIFT, "portshift", &isa_portshift, 
+	 sizeof(isa_portshift), 0444, NULL, &proc_dointvec},
+	{0}
+};
+
+static struct ctl_table_header *isa_sysctl_header;
+
+static ctl_table ctl_isa[2] = {{BUS_ISA, "isa", NULL, 0, 0555, ctl_isa_vars},
+			       {0}};
+static ctl_table ctl_bus[2] = {{CTL_BUS, "bus", NULL, 0, 0555, ctl_isa},
+			       {0}};
+
+__initfunc(void
+register_isa_ports(unsigned int membase, unsigned int portbase, unsigned int portshift))
+{
+	isa_membase = membase;
+	isa_portbase = portbase;
+	isa_portshift = portshift;
+	isa_sysctl_header = register_sysctl_table(ctl_bus, 0);
+}
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/leds-footbridge.c linux/arch/arm/kernel/leds-footbridge.c
--- v2.3.10/linux/arch/arm/kernel/leds-footbridge.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/leds-footbridge.c	Mon Jul 19 09:52:57 1999
@@ -33,8 +33,9 @@
 static char hw_led_state;
 
 static spinlock_t leds_lock = SPIN_LOCK_UNLOCKED;
+extern spinlock_t gpio_lock;
 
-#ifdef CONFIG_ARCH_EBSA285
+#ifdef CONFIG_FOOTBRIDGE
 
 static void __ebsa285_text ebsa285_leds_event(led_event_t evt)
 {
@@ -226,8 +227,9 @@
 init_leds_event(led_event_t evt))
 {
 	switch (machine_arch_type) {
-#ifdef CONFIG_ARCH_EBSA285
+#ifdef CONFIG_FOOTBRIDGE
 	case MACH_TYPE_EBSA285:
+	case MACH_TYPE_CO285:
 		leds_event = ebsa285_leds_event;
 		break;
 #endif
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/process.c linux/arch/arm/kernel/process.c
--- v2.3.10/linux/arch/arm/kernel/process.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/arm/kernel/process.c	Mon Jul 19 09:52:57 1999
@@ -209,8 +209,7 @@
 {
 	int i;
 
-	for (i = 0; i < NR_DEBUGS; i++)
-		current->tss.debug[i] = 0;
+	memset(&current->tss.debug, 0, sizeof(current->tss.debug));
 	current->used_math = 0;
 	current->flags &= ~PF_USEDFPU;
 }
@@ -255,8 +254,6 @@
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
-	int i;
-
 	dump->magic = CMAGIC;
 	dump->start_code = current->mm->start_code;
 	dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1);
@@ -265,8 +262,11 @@
 	dump->u_dsize = (current->mm->brk - current->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	dump->u_ssize = 0;
 
-	for (i = 0; i < NR_DEBUGS; i++)
-		dump->u_debugreg[i] = current->tss.debug[i];  
+	dump->u_debugreg[0] = current->tss.debug.bp[0].address;
+	dump->u_debugreg[1] = current->tss.debug.bp[1].address;
+	dump->u_debugreg[2] = current->tss.debug.bp[0].insn;
+	dump->u_debugreg[3] = current->tss.debug.bp[1].insn;
+	dump->u_debugreg[4] = current->tss.debug.nsaved;
 
 	if (dump->start_stack < 0x04000000)
 		dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT;
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/ptrace.c linux/arch/arm/kernel/ptrace.c
--- v2.3.10/linux/arch/arm/kernel/ptrace.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/ptrace.c	Mon Jul 19 09:52:57 1999
@@ -59,209 +59,24 @@
 	return 0;
 }
 
-/*
- * This routine gets a long from any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- */
-static unsigned long get_long(struct task_struct * tsk,
-	struct vm_area_struct * vma, unsigned long addr)
+static int
+read_long(struct task_struct *child, unsigned long addr, unsigned long *res)
 {
-	pgd_t *pgdir;
-	pmd_t *pgmiddle;
-	pte_t *pgtable;
-	unsigned long page;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (pgd_none(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return 0;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return 0;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 0);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
- 
-	if(MAP_NR(page) >= max_mapnr)
-		return 0;
-	page += addr & ~PAGE_MASK;
-	return *(unsigned long *)page;
-}
+	int copied;
 
-/*
- * This routine puts a long into any process space by following the page
- * tables. NOTE! You should check that the long isn't on a page boundary,
- * and that it is in the task area before calling this: this routine does
- * no checking.
- *
- * Now keeps R/W state of the page so that a text page stays readonly
- * even if a debugger scribbles breakpoints into it.  -M.U-
- */
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
-	unsigned long data)
-{
-	pgd_t *pgdir;
-	pmd_t *pgmiddle;
-	pte_t *pgtable;
-	unsigned long page;
-
-repeat:
-	pgdir = pgd_offset(vma->vm_mm, addr);
-	if (!pgd_present(*pgdir)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pgd_bad(*pgdir)) {
-		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
-		pgd_clear(pgdir);
-		return;
-	}
-	pgmiddle = pmd_offset(pgdir, addr);
-	if (pmd_none(*pgmiddle)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	if (pmd_bad(*pgmiddle)) {
-		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
-		pmd_clear(pgmiddle);
-		return;
-	}
-	pgtable = pte_offset(pgmiddle, addr);
-	if (!pte_present(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	page = pte_page(*pgtable);
-	if (!pte_write(*pgtable)) {
-		handle_mm_fault(tsk, vma, addr, 1);
-		goto repeat;
-	}
-	
-	if (MAP_NR(page) < max_mapnr) {
-		page += addr & ~PAGE_MASK;
-
-		flush_cache_range(vma->vm_mm, addr, addr + sizeof(unsigned long));
-
-		*(unsigned long *)page = data;
-
-		clean_cache_area(page, sizeof(unsigned long));
+	copied = access_process_vm(child, addr, res, sizeof(*res), 0);
 
-		set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
-		flush_tlb_page(vma, addr & PAGE_MASK);
-	}
+	return copied != sizeof(*res) ? -EIO : 0;
 }
 
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls get_long() to read a long.
- */
-static int read_long(struct task_struct * tsk, unsigned long addr,
-	unsigned long * result)
+static int
+write_long(struct task_struct *child, unsigned long addr, unsigned long val)
 {
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+	int copied;
 
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-		unsigned long low,high;
-		struct vm_area_struct * vma_high = vma;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_high = vma->vm_next;
-			if (!vma_high || vma_high->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-		high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & (sizeof(long)-1)) {
-			case 1:
-				low >>= 8;
-				low |= high << 24;
-				break;
-			case 2:
-				low >>= 16;
-				low |= high << 16;
-				break;
-			case 3:
-				low >>= 24;
-				low |= high << 8;
-				break;
-		}
-		*result = low;
-	} else
-		*result = get_long(tsk, vma, addr);
-	return 0;
-}
-
-/*
- * This routine checks the page boundaries, and that the offset is
- * within the task area. It then calls put_long() to write a long.
- */
-static int write_long(struct task_struct * tsk, unsigned long addr,
-	unsigned long data)
-{
-	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+	copied = access_process_vm(child, addr, &val, sizeof(val), 1);
 
-	if (!vma)
-		return -EIO;
-	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-		unsigned long low,high;
-		struct vm_area_struct * vma_high = vma;
-
-		if (addr + sizeof(long) >= vma->vm_end) {
-			vma_high = vma->vm_next;
-			if (!vma_high || vma_high->vm_start != vma->vm_end)
-				return -EIO;
-		}
-		low = get_long(tsk, vma, addr & ~(sizeof(long)-1));
-		high = get_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
-		switch (addr & (sizeof(long)-1)) {
-			case 0: /* shouldn't happen, but safety first */
-				low = data;
-				break;
-			case 1:
-				low &= 0x000000ff;
-				low |= data << 8;
-				high &= ~0xff;
-				high |= data >> 24;
-				break;
-			case 2:
-				low &= 0x0000ffff;
-				low |= data << 16;
-				high &= ~0xffff;
-				high |= data >> 16;
-				break;
-			case 3:
-				low &= 0x00ffffff;
-				low |= data << 24;
-				high &= ~0xffffff;
-				high |= data >> 8;
-				break;
-		}
-		put_long(tsk, vma, addr & ~(sizeof(long)-1),low);
-		put_long(tsk, vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
-	} else
-		put_long(tsk, vma, addr, data);
-	return 0;
+	return copied != sizeof(val) ? -EIO : 0;
 }
 
 /*
@@ -350,19 +165,12 @@
 	return val;
 }
 
-int ptrace_set_bpt (struct task_struct *child)
+static unsigned long
+get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn)
 {
-	unsigned long insn, pc, alt;
-	int i, nsaved = 0, res;
-
-	pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/));
-
-	res = read_long (child, pc, &insn);
-	if (res < 0)
-		return res;
+	unsigned long alt = 0;
 
-	child->tss.debug[nsaved++] = alt = pc + 4;
-printk ("ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc);
+printk(KERN_DEBUG "ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc);
 	switch (insn & 0x0e100000) {
 	case 0x00000000:
 	case 0x00100000:
@@ -423,7 +231,7 @@
 					alt -= ptrace_getldrop2 (child, insn);
 			}
 			if (read_long (child, alt, &alt) < 0)
-				alt = pc + 4; /* not valid */
+				alt = 0; /* not valid */
 			else
 				alt = pc_pointer (alt);
 		}
@@ -440,7 +248,7 @@
 					alt -= insn & 0xfff;
 			}
 			if (read_long (child, alt, &alt) < 0)
-				alt = pc + 4; /* not valid */
+				alt = 0; /* not valid */
 			else
 				alt = pc_pointer (alt);
 		}
@@ -473,7 +281,7 @@
 			base = ptrace_getrn (child, insn);
 
 			if (read_long (child, base + nr_regs, &alt) < 0)
-				alt = pc + 4; /* not valid */
+				alt = 0; /* not valid */
 			else
 				alt = pc_pointer (alt);
 			break;
@@ -499,22 +307,55 @@
 	    break;
 	}
 printk ("=%08lX\n", alt);
-	if (alt != pc + 4)
-		child->tss.debug[nsaved++] = alt;
 
-	for (i = 0; i < nsaved; i++) {
-		res = read_long (child, child->tss.debug[i], &insn);
-		if (res >= 0) {
-			child->tss.debug[i + 2] = insn;
-			res = write_long (child, child->tss.debug[i], BREAKINST);
+	return alt;
+}
+
+static int
+add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long addr)
+{
+	int nr = dbg->nsaved;
+	int res = -EINVAL;
+
+	if (nr < 2) {
+		res = read_long(child, addr, &dbg->bp[nr].insn);
+		if (res == 0)
+			res = write_long(child, addr, BREAKINST);
+
+		if (res == 0) {
+			dbg->bp[nr].address = addr;
+			dbg->nsaved += 1;
 		}
-		if (res < 0) {
-			child->tss.debug[4] = 0;
-			return res;
+	} else
+		printk(KERN_DEBUG "add_breakpoint: too many breakpoints\n");
+
+	return res;
+}
+
+int ptrace_set_bpt (struct task_struct *child)
+{
+	struct debug_info *dbg = &child->tss.debug;
+	unsigned long insn, pc, alt;
+	int res;
+
+	pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/));
+
+	res = read_long(child, pc, &insn);
+	if (res >= 0) {
+		res = 0;
+
+		dbg->nsaved = 0;
+
+		res = add_breakpoint(child, dbg, pc + 4);
+
+		if (res == 0) {
+			alt = get_branch_address(child, pc, insn);
+			if (alt)
+				res = add_breakpoint(child, dbg, alt);
 		}
 	}
-	child->tss.debug[4] = nsaved;
-	return 0;
+
+	return res;
 }
 
 /* Ensure no single-step breakpoint is pending.  Returns non-zero
@@ -522,16 +363,24 @@
  */
 int ptrace_cancel_bpt (struct task_struct *child)
 {
-	int i, nsaved = child->tss.debug[4];
+	struct debug_info *dbg = &child->tss.debug;
+	unsigned long tmp;
+	int i, nsaved = dbg->nsaved;
 
-	child->tss.debug[4] = 0;
+	dbg->nsaved = 0;
 
 	if (nsaved > 2) {
 		printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
 		nsaved = 2;
 	}
-	for (i = 0; i < nsaved; i++)
-		write_long (child, child->tss.debug[i], child->tss.debug[i + 2]);
+
+	for (i = 0; i < nsaved; i++) {
+		read_long(child, dbg->bp[i].address, &tmp);
+		if (tmp != BREAKINST)
+			printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n");
+		write_long(child, dbg->bp[i].address, dbg->bp[i].insn);
+	}
+
 	return nsaved != 0;
 }
 
@@ -598,8 +447,8 @@
 			unsigned long tmp;
 
 			ret = read_long(child, addr, &tmp);
-			if (ret >= 0)
-				ret = put_user(tmp, (unsigned long *)data);
+			if (ret)
+				put_user(tmp, (unsigned long *) data);
 			goto out;
 		}
 
@@ -619,7 +468,7 @@
 
 		case PTRACE_POKETEXT:				/* write the word at location addr. */
 		case PTRACE_POKEDATA:
-			ret = write_long(child,addr,data);
+			ret = write_long(child, addr, data);
 			goto out;
 
 		case PTRACE_POKEUSR:				/* write the word at location addr in the USER area */
@@ -665,7 +514,7 @@
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
 				goto out;
-			child->tss.debug[4] = -1;
+			child->tss.debug.nsaved = -1;
 			child->flags &= ~PF_TRACESYS;
 			wake_up_process(child);
 			child->exit_code = data;
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/setup.c linux/arch/arm/kernel/setup.c
--- v2.3.10/linux/arch/arm/kernel/setup.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/setup.c	Mon Jul 19 09:52:57 1999
@@ -309,7 +309,8 @@
 	case MACH_TYPE_EBSA110:
 		/* EBSA110 locks if we execute 'wait for interrupt' */
 		disable_hlt();
-		params = NULL;
+		if (params && params->u1.s.page_size != 4096)
+			params = NULL;
 		break;
 
 	case MACH_TYPE_EBSA285:
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/time.c linux/arch/arm/kernel/time.c
--- v2.3.10/linux/arch/arm/kernel/time.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/arm/kernel/time.c	Mon Jul 19 09:52:57 1999
@@ -76,6 +76,25 @@
 		  )*60 + sec; /* finally seconds */
 }
 
+/*
+ * Handle profile stuff...
+ */
+static void do_profile(unsigned long pc)
+{
+	if (prof_buffer && current->pid) {
+		extern int _stext;
+
+		pc -= (unsigned long)&_stext;
+
+		pc >>= prof_shift;
+
+		if (pc >= prof_len)
+			pc = prof_len - 1;
+
+		prof_buffer[pc] += 1;
+	}
+}
+
 #include <asm/arch/time.h>
 
 static unsigned long do_gettimeoffset(void)
diff -u --recursive --new-file v2.3.10/linux/arch/arm/kernel/traps.c linux/arch/arm/kernel/traps.c
--- v2.3.10/linux/arch/arm/kernel/traps.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/traps.c	Mon Jul 19 09:52:57 1999
@@ -387,3 +387,9 @@
 		code, regs->ARM_pc, instr, regs->ARM_lr, regs->ARM_sp);
 }
 #endif
+
+asmlinkage void __div0(void)
+{
+	printk("Awooga, division by zero in kernel.\n");
+	__backtrace();
+}
diff -u --recursive --new-file v2.3.10/linux/arch/arm/lib/Makefile linux/arch/arm/lib/Makefile
--- v2.3.10/linux/arch/arm/lib/Makefile	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/lib/Makefile	Mon Jul 19 09:52:57 1999
@@ -5,7 +5,7 @@
 #
 
 L_TARGET := lib.a
-L_OBJS   := backtrace.o bitops.o checksum.o delay.o io.o memcpy.o \
+L_OBJS   := backtrace.o bitops.o checksum.o delay.o memcpy.o \
 	    semaphore.o string.o system.o uaccess.o
 
 ifeq ($(PROCESSOR),armo)
@@ -24,6 +24,8 @@
 
 ifeq ($(MACHINE),ebsa110)
   L_OBJS += io-ebsa110.o
+else
+  LX_OBJS += io.o
 endif
 
 ifeq ($(MACHINE),footbridge)
diff -u --recursive --new-file v2.3.10/linux/arch/arm/lib/io.c linux/arch/arm/lib/io.c
--- v2.3.10/linux/arch/arm/lib/io.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/lib/io.c	Mon Jul 19 09:52:57 1999
@@ -1,3 +1,5 @@
+#include <linux/module.h>
+
 #include <asm/io.h>
 
 /*
@@ -40,3 +42,8 @@
 		dst++;
 	}
 }
+
+EXPORT_SYMBOL(_memcpy_fromio);
+EXPORT_SYMBOL(_memcpy_toio);
+EXPORT_SYMBOL(_memset_io);
+
diff -u --recursive --new-file v2.3.10/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.3.10/linux/arch/arm/mm/init.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/arm/mm/init.c	Mon Jul 19 09:52:57 1999
@@ -247,7 +247,7 @@
 			  (unsigned long)(&__netwinder_end),
 			  "netwinder");
 
-	if (!machine_is_ebsa285() && !machine_is_cats())
+	if (!machine_is_ebsa285() && !machine_is_cats() && !machine_is_co285())
 		free_area((unsigned long)(&__ebsa285_begin),
 			  (unsigned long)(&__ebsa285_end),
 			  "ebsa285/cats");
diff -u --recursive --new-file v2.3.10/linux/arch/i386/Makefile linux/arch/i386/Makefile
--- v2.3.10/linux/arch/i386/Makefile	Mon Jun  7 17:02:23 1999
+++ linux/arch/i386/Makefile	Tue Jul 13 12:26:46 1999
@@ -12,6 +12,9 @@
 #
 # Copyright (C) 1994 by Linus Torvalds
 #
+# 19990713  Artur Skawina <skawina@geocities.com>
+#           Added '-march' and '-mpreferred-stack-boundary' support
+#
 
 LD=$(CROSS_COMPILE)ld -m elf_i386
 CPP=$(CC) -E
@@ -23,6 +26,9 @@
 CFLAGS_NSR  := -fno-strength-reduce
 CFLAGS := $(CFLAGS) $(CFLAGS_PIPE) $(CFLAGS_NSR)
 
+# prevent gcc from keeping the stack 16 byte aligned
+CFLAGS += $(shell if $(CC) -mpreferred-stack-boundary=2 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-mpreferred-stack-boundary=2"; fi)
+
 ifdef CONFIG_M386
 CFLAGS := $(CFLAGS) -m386 -DCPU=386
 AFLAGS := $(AFLAGS) -DCPU=386
@@ -30,21 +36,25 @@
 
 ifdef CONFIG_M486
 CFLAGS := $(CFLAGS) -m486 -DCPU=486
+CFLAGS += $(shell if $(CC) -march=i486 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i486"; fi)
 AFLAGS := $(AFLAGS) -DCPU=486
 endif
 
 ifdef CONFIG_M586
 CFLAGS := $(CFLAGS) -DCPU=586
+CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi)
 AFLAGS := $(AFLAGS) -DCPU=586
 endif
 
 ifdef CONFIG_M586TSC
 CFLAGS := $(CFLAGS) -DCPU=586
+CFLAGS += $(shell if $(CC) -march=i586 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i586"; fi)
 AFLAGS := $(AFLAGS) -DCPU=586
 endif
 
 ifdef CONFIG_M686
 CFLAGS := $(CFLAGS) -DCPU=686
+CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi)
 AFLAGS := $(AFLAGS) -DCPU=686
 endif
 
diff -u --recursive --new-file v2.3.10/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- v2.3.10/linux/arch/i386/boot/compressed/Makefile	Mon Jul 20 10:05:15 1998
+++ linux/arch/i386/boot/compressed/Makefile	Sun Jul 11 09:48:05 1999
@@ -30,7 +30,7 @@
 bvmlinux: piggy.o $(OBJECTS)
 	$(LD) $(BZLINKFLAGS) -o bvmlinux $(OBJECTS) piggy.o
 
-head.o: head.S $(TOPDIR)/include/linux/tasks.h
+head.o: head.S
 	$(CC) $(AFLAGS) -traditional -c head.S
 
 piggy.o:	$(SYSTEM)
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.3.10/linux/arch/i386/kernel/Makefile	Wed Jan 20 10:18:53 1999
+++ linux/arch/i386/kernel/Makefile	Sun Jul 11 09:48:05 1999
@@ -50,7 +50,7 @@
 O_OBJS += visws_apic.o
 endif
 
-head.o: head.S $(TOPDIR)/include/linux/tasks.h
+head.o: head.S
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $*.S -o $*.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.3.10/linux/arch/i386/kernel/entry.S	Fri Apr 30 08:13:37 1999
+++ linux/arch/i386/kernel/entry.S	Sun Jul 18 12:13:30 1999
@@ -153,11 +153,9 @@
 	ALIGN
 	.globl	ret_from_fork
 ret_from_fork:
-#ifdef __SMP__
 	pushl %ebx
 	call SYMBOL_NAME(schedule_tail)
 	addl $4, %esp
-#endif /* __SMP__ */
 	GET_CURRENT(%ebx)
 	jmp	ret_from_sys_call
 
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.3.10/linux/arch/i386/kernel/head.S	Thu Jan 14 22:57:25 1999
+++ linux/arch/i386/kernel/head.S	Sun Jul 11 09:11:46 1999
@@ -8,11 +8,12 @@
  */
 
 .text
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/desc.h>
 
 
 #define CL_MAGIC_ADDR	0x90020
@@ -330,7 +331,7 @@
  * of tasks we can have..
  */
 #define IDT_ENTRIES	256
-#define GDT_ENTRIES	(12+2*NR_TASKS)
+#define GDT_ENTRIES	(__TSS(NR_CPUS))
 
 
 .globl SYMBOL_NAME(idt)
@@ -519,8 +520,7 @@
 
 ALIGN
 /*
- * This contains up to 8192 quadwords depending on NR_TASKS - 64kB of
- * gdt entries.  Ugh. 
+ * This contains typically 140 quadwords, depending on NR_CPUS.
  *
  * NOTE! Make sure the gdt descriptor in head.S matches this if you
  * change anything.
@@ -542,7 +542,7 @@
 	.quad 0x00409a0000000000	/* 0x48 APM CS    code */
 	.quad 0x00009a0000000000	/* 0x50 APM CS 16 code (16 bit) */
 	.quad 0x0040920000000000	/* 0x58 APM DS    data */
-	.fill 2*NR_TASKS,8,0		/* space for LDT's and TSS's etc */
+	.fill NR_CPUS*4,8,0		/* space for TSS's and LDT's */
 
 /*
  * This is to aid debugging, the various locking macros will be putting
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/init_task.c linux/arch/i386/kernel/init_task.c
--- v2.3.10/linux/arch/i386/kernel/init_task.c	Tue May 11 14:37:40 1999
+++ linux/arch/i386/kernel/init_task.c	Mon Jul 19 15:23:49 1999
@@ -4,6 +4,7 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/desc.h>
+#include <asm/init.h>
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
@@ -22,4 +23,13 @@
 union task_union init_task_union 
 	__attribute__((__section__(".data.init_task"))) =
 		{ INIT_TASK(init_task_union.task) };
- 
+
+/*
+ * per-CPU TSS segments. Threads are completely 'soft' on Linux,
+ * no more per-task TSS's. The TSS size is kept cacheline-aligned
+ * so they are allowed to end up in the .data.cacheline_aligned
+ * section. Since TSS's are completely CPU-local, we want them
+ * on exact cacheline boundaries, to eliminate cacheline ping-pong.
+ */ 
+struct tss_struct init_tss[NR_CPUS] __cacheline_aligned = { [0 ... NR_CPUS-1] = INIT_TSS };
+
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/ioport.c linux/arch/i386/kernel/ioport.c
--- v2.3.10/linux/arch/i386/kernel/ioport.c	Mon Jan 11 15:02:52 1999
+++ linux/arch/i386/kernel/ioport.c	Mon Jul 19 15:22:48 1999
@@ -54,7 +54,8 @@
  */
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
 {
-	struct thread_struct * t = &current->tss;
+	struct thread_struct * t = &current->thread;
+	struct tss_struct * tss = init_tss + smp_processor_id();
 
 	if ((from + num <= from) || (from + num > IO_BITMAP_SIZE*32))
 		return -EINVAL;
@@ -65,14 +66,24 @@
 	 * IO bitmap up. ioperm() is much less timing critical than clone(),
 	 * this is why we delay this operation until now:
 	 */
-#define IO_BITMAP_OFFSET offsetof(struct thread_struct,io_bitmap)
-
-	if (t->bitmap != IO_BITMAP_OFFSET) {
-		t->bitmap = IO_BITMAP_OFFSET;
+	if (!t->ioperm) {
+		/*
+		 * just in case ...
+		 */
 		memset(t->io_bitmap,0xff,(IO_BITMAP_SIZE+1)*4);
+		t->ioperm = 1;
+		/*
+		 * this activates it in the TSS
+		 */
+		tss->bitmap = IO_BITMAP_OFFSET;
 	}
-		
-	set_bitmap((unsigned long *)t->io_bitmap, from, num, !turn_on);
+
+	/*
+	 * do it in the per-thread copy and in the TSS ...
+	 */
+	set_bitmap(t->io_bitmap, from, num, !turn_on);
+	set_bitmap(tss->io_bitmap, from, num, !turn_on);
+
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.3.10/linux/arch/i386/kernel/irq.c	Mon May 10 10:32:45 1999
+++ linux/arch/i386/kernel/irq.c	Thu Jul 15 15:50:47 1999
@@ -27,7 +27,6 @@
 #include <linux/malloc.h>
 #include <linux/random.h>
 #include <linux/smp.h>
-#include <linux/tasks.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
@@ -931,17 +930,21 @@
 		if (action->dev_id != dev_id)
 			continue;
 
-		/* Found it - now free it */
+		/* Found it - now remove it from the list of entries */
 		*p = action->next;
-		kfree(action);
 		if (!irq_desc[irq].action) {
 			irq_desc[irq].status |= IRQ_DISABLED;
 			irq_desc[irq].handler->shutdown(irq);
 		}
-		goto out;
+		spin_unlock_irqrestore(&irq_controller_lock,flags);
+
+		/* Wait to make sure it's not being used on another CPU */
+		while (irq_desc[irq].status & IRQ_INPROGRESS)
+			barrier();
+		kfree(action);
+		return;
 	}
 	printk("Trying to free free IRQ%d\n",irq);
-out:
 	spin_unlock_irqrestore(&irq_controller_lock,flags);
 }
 
@@ -1099,9 +1102,7 @@
 
 	/* IPI vector for APIC spurious interrupts */
 	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
-#endif	
-	request_region(0x20,0x20,"pic1");
-	request_region(0xa0,0x20,"pic2");
+#endif
 
 	/*
 	 * Set the clock to 100 Hz, we already have a valid
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c
--- v2.3.10/linux/arch/i386/kernel/ldt.c	Sun Sep 13 12:16:22 1998
+++ linux/arch/i386/kernel/ldt.c	Wed Jul 21 09:50:25 1999
@@ -2,6 +2,7 @@
  * linux/kernel/ldt.c
  *
  * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
+ * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
  */
 
 #include <linux/errno.h>
@@ -17,19 +18,31 @@
 #include <asm/ldt.h>
 #include <asm/desc.h>
 
+/*
+ * read_ldt() is not really atomic - this is not a problem since
+ * synchronization of reads and writes done to the LDT has to be
+ * assured by user-space anyway. Writes are atomic, to protect
+ * the security checks done on new descriptors.
+ */
 static int read_ldt(void * ptr, unsigned long bytecount)
 {
-	void * address = current->mm->segments;
+	int err;
 	unsigned long size;
+	struct mm_struct * mm = current->mm;
+
+	err = 0;
+	if (!mm->segments)
+		goto out;
 
-	if (!ptr)
-		return -EINVAL;
-	if (!address)
-		return 0;
 	size = LDT_ENTRIES*LDT_ENTRY_SIZE;
 	if (size > bytecount)
 		size = bytecount;
-	return copy_to_user(ptr, address, size) ? -EFAULT : size;
+
+	err = size;
+	if (copy_to_user(ptr, mm->segments, size))
+		err = -EFAULT;
+out:
+	return err;
 }
 
 static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
@@ -64,31 +77,29 @@
 	 * you get strange behaviour (the kernel is safe, it's just user
 	 * space strangeness).
 	 *
-	 * For no good reason except historical, the GDT index of the LDT
-	 * is chosen to follow the index number in the task[] array.
+	 * we have two choices: either we preallocate the LDT descriptor
+	 * and can do a shared modify_ldt(), or we postallocate it and do
+	 * an smp message pass to update it. Currently we are a bit
+	 * un-nice to user-space and reload the LDT only on the next
+	 * schedule. (only an issue on SMP)
+	 *
+	 * the GDT index of the LDT is allocated dynamically, and is
+	 * limited by MAX_LDT_DESCRIPTORS.
 	 */
+	down(&mm->mmap_sem);
 	if (!mm->segments) {
-		void * ldt;
+		
 		error = -ENOMEM;
-		ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-		if (!ldt)
-			goto out;
-		memset(ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+		mm->segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+		if (!mm->segments)
+			goto out_unlock;
+		
+		if (atomic_read(&mm->mm_users) > 1)
+			printk(KERN_WARNING "LDT allocated for cloned task!\n");
 		/*
-		 * Make sure someone else hasn't allocated it for us ...
+		 * Possibly do an SMP cross-call to other CPUs to reload
+		 * their LDTs
 		 */
-		if (!mm->segments) {
-			int i = current->tarray_ptr - &task[0];
-			mm->segments = ldt;
-			set_ldt_desc(i, ldt, LDT_ENTRIES);
-			current->tss.ldt = _LDT(i);
-			load_ldt(i);
-			if (atomic_read(&mm->count) > 1)
-				printk(KERN_WARNING
-					"LDT allocated for cloned task!\n");
-		} else {
-			vfree(ldt);
-		}
 	}
 
 	lp = (__u32 *) ((ldt_info.entry_number << 3) + (char *) mm->segments);
@@ -127,6 +138,9 @@
 	*lp	= entry_1;
 	*(lp+1)	= entry_2;
 	error = 0;
+
+out_unlock:
+	up(&mm->mmap_sem);
 out:
 	return error;
 }
@@ -135,7 +149,6 @@
 {
 	int ret = -ENOSYS;
 
-	lock_kernel();
 	switch (func) {
 	case 0:
 		ret = read_ldt(ptr, bytecount);
@@ -147,6 +160,5 @@
 		ret = write_ldt(ptr, bytecount, 0);
 		break;
 	}
-	unlock_kernel();
 	return ret;
 }
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- v2.3.10/linux/arch/i386/kernel/mca.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/i386/kernel/mca.c	Mon Jul 19 12:32:54 1999
@@ -210,6 +210,18 @@
 
 /*--------------------------------------------------------------------*/
 
+struct resource mca_standard_resources[] = {
+	{ "system control port B (MCA)", 0x60, 0x60 },
+	{ "arbitration (MCA)", 0x90, 0x90 },
+	{ "card Select Feedback (MCA)", 0x91, 0x91 },
+	{ "system Control port A (MCA)", 0x92, 0x92 },
+	{ "system board setup (MCA)", 0x94, 0x94 },
+	{ "POS (MCA)", 0x96, 0x97 },
+	{ "POS (MCA)", 0x100, 0x107 }
+};
+
+#define MCA_STANDARD_RESOURCES	(sizeof(mca_standard_resources)/sizeof(struct resource))
+
 __initfunc(void mca_init(void))
 {
 	unsigned int i, j;
@@ -319,13 +331,8 @@
 
 	restore_flags(flags);
 
-	request_region(0x60,0x01,"system control port B (MCA)");
-	request_region(0x90,0x01,"arbitration (MCA)");
-	request_region(0x91,0x01,"card Select Feedback (MCA)");
-	request_region(0x92,0x01,"system Control port A (MCA)");
-	request_region(0x94,0x01,"system board setup (MCA)");
-	request_region(0x96,0x02,"POS (MCA)");
-	request_region(0x100,0x08,"POS (MCA)");
+	for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
+		request_resource(&ioport_resource, mca_standard_resources + i);
 
 #ifdef CONFIG_PROC_FS
 	mca_do_proc_init();
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.3.10/linux/arch/i386/kernel/process.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/i386/kernel/process.c	Mon Jul 19 23:08:41 1999
@@ -405,6 +405,7 @@
 		regs->esi, regs->edi, regs->ebp);
 	printk(" DS: %04x ES: %04x\n",
 		0xffff & regs->xds,0xffff & regs->xes);
+
 	__asm__("movl %%cr0, %0": "=r" (cr0));
 	__asm__("movl %%cr2, %0": "=r" (cr2));
 	__asm__("movl %%cr3, %0": "=r" (cr3));
@@ -475,11 +476,28 @@
 		free_pages((unsigned long) p, 1);
 }
 
+/*
+ * No need to lock the MM as we are the last user
+ */
 void release_segments(struct mm_struct *mm)
 {
-	if (mm->segments) {
-		void * ldt = mm->segments;
+	void * ldt = mm->segments;
+
+	/*
+	 * free the LDT
+	 */
+	if (ldt) {
 		mm->segments = NULL;
+		/*
+		 * special case, when we release the LDT from under
+		 * the running CPU. Other CPUs cannot possibly use
+		 * this LDT as we were getting here through mmput() ...
+		 */
+		if (mm == current->mm)
+			load_LDT(mm);
+		/*
+		 * Nobody anymore uses the LDT, we can free it:
+		 */
 		vfree(ldt);
 	}
 }
@@ -492,10 +510,9 @@
 		: "r" (0));
 
 	/*
-	 * Get the LDT entry from init_task.
+	 * Load the LDT entry of init_task.
 	 */
-	current->tss.ldt = _LDT(0);
-	load_ldt(0);
+	load_LDT(&init_mm);
 }
 
 /*
@@ -537,12 +554,9 @@
 
 void flush_thread(void)
 {
-	int i;
 	struct task_struct *tsk = current;
 
-	for (i=0 ; i<8 ; i++)
-		tsk->tss.debugreg[i] = 0;
-
+	memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8);
 	/*
 	 * Forget coprocessor state..
 	 */
@@ -552,33 +566,52 @@
 
 void release_thread(struct task_struct *dead_task)
 {
+	if (dead_task->mm) {
+		void * ldt = dead_task->mm->segments;
+
+		// temporary debugging check
+		if (ldt) {
+			printk("WARNING: dead process %8s still has LDT? <%p>\n",
+					dead_task->comm, ldt);
+			BUG();
+		}
+	}
 }
 
 /*
- * If new_mm is NULL, we're being called to set up the LDT descriptor
- * for a clone task. Each clone must have a separate entry in the GDT.
+ * If new_mm is NULL, we're being called to set up the LDT for
+ * a clone task: this is easy since the clone is not running yet.
+ * otherwise we copy the old segment into a new segment.
+ *
+ * we do not have to muck with descriptors here, that is
+ * done in __switch_to() and get_mmu_context().
  */
-void copy_segments(int nr, struct task_struct *p, struct mm_struct *new_mm)
+void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
 {
 	struct mm_struct * old_mm = current->mm;
 	void * old_ldt = old_mm->segments, * ldt = old_ldt;
 
-	/* default LDT - use the one from init_task */
-	p->tss.ldt = _LDT(0);
-	if (old_ldt) {
-		if (new_mm) {
-			ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-			new_mm->segments = ldt;
-			if (!ldt) {
-				printk(KERN_WARNING "ldt allocation failed\n");
-				return;
-			}
-			memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
-		}
-		p->tss.ldt = _LDT(nr);
-		set_ldt_desc(nr, ldt, LDT_ENTRIES);
+	if (!old_mm->segments) {
+		/*
+		 * default LDT - use the one from init_task
+		 */
+		if (new_mm)
+			new_mm->segments = NULL;
 		return;
 	}
+
+	if (new_mm) {
+		/*
+		 * Completely new LDT, we initialize it from the parent:
+		 */
+		ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+		if (!ldt)
+			printk(KERN_WARNING "ldt allocation failed\n");
+		else
+			memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
+		new_mm->segments = ldt;
+	}
+	return;
 }
 
 /*
@@ -592,31 +625,21 @@
 {
 	struct pt_regs * childregs;
 
-	childregs = ((struct pt_regs *) (2*PAGE_SIZE + (unsigned long) p)) - 1;
+	childregs = ((struct pt_regs *) (THREAD_SIZE + (unsigned long) p)) - 1;
 	*childregs = *regs;
 	childregs->eax = 0;
 	childregs->esp = esp;
 
-	p->tss.esp = (unsigned long) childregs;
-	p->tss.esp0 = (unsigned long) (childregs+1);
-	p->tss.ss0 = __KERNEL_DS;
-
-	p->tss.tr = _TSS(nr);
-	set_tss_desc(nr,&(p->tss));
-	p->tss.eip = (unsigned long) ret_from_fork;
+	p->thread.esp = (unsigned long) childregs;
+	p->thread.esp0 = (unsigned long) (childregs+1);
 
-	savesegment(fs,p->tss.fs);
-	savesegment(gs,p->tss.gs);
+	p->thread.eip = (unsigned long) ret_from_fork;
 
-	/*
-	 * a bitmap offset pointing outside of the TSS limit causes a nicely
-	 * controllable SIGSEGV. The first sys_ioperm() call sets up the
-	 * bitmap properly.
-	 */
-	p->tss.bitmap = sizeof(struct thread_struct);
+	savesegment(fs,p->thread.fs);
+	savesegment(gs,p->thread.gs);
 
 	unlazy_fpu(current);
-	p->tss.i387 = current->tss.i387;
+	p->thread.i387 = current->thread.i387;
 
 	return 0;
 }
@@ -632,7 +655,7 @@
 	fpvalid = tsk->used_math;
 	if (fpvalid) {
 		unlazy_fpu(tsk);
-		memcpy(fpu,&tsk->tss.i387.hard,sizeof(*fpu));
+		memcpy(fpu,&tsk->thread.i387.hard,sizeof(*fpu));
 	}
 
 	return fpvalid;
@@ -654,7 +677,7 @@
 	dump->u_dsize -= dump->u_tsize;
 	dump->u_ssize = 0;
 	for (i = 0; i < 8; i++)
-		dump->u_debugreg[i] = current->tss.debugreg[i];  
+		dump->u_debugreg[i] = current->thread.debugreg[i];  
 
 	if (dump->start_stack < TASK_SIZE)
 		dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
@@ -683,11 +706,10 @@
 /*
  * This special macro can be used to load a debugging register
  */
-#define loaddebug(tsk,register) \
+#define loaddebug(thread,register) \
 		__asm__("movl %0,%%db" #register  \
 			: /* no output */ \
-			:"r" (tsk->tss.debugreg[register]))
-
+			:"r" (thread->debugreg[register]))
 
 /*
  *	switch_to(x,yn) should switch tasks from x to y.
@@ -712,60 +734,82 @@
  * More important, however, is the fact that this allows us much
  * more flexibility.
  */
-void __switch_to(struct task_struct *prev, struct task_struct *next)
+extern int cpus_initialized;
+void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 {
-	/* Do the FPU save and set TS if it wasn't set before.. */
-	unlazy_fpu(prev);
+	struct thread_struct *prev = &prev_p->thread,
+				 *next = &next_p->thread;
+	struct tss_struct *tss = init_tss + smp_processor_id();
+
+	unlazy_fpu(prev_p);
 
 	/*
-	 * Reload TR, LDT and the page table pointers..
-	 *
-	 * We need TR for the IO permission bitmask (and
-	 * the vm86 bitmasks in case we ever use enhanced
-	 * v86 mode properly).
-	 *
-	 * We may want to get rid of the TR register some
-	 * day, and copy the bitmaps around by hand. Oh,
-	 * well. In the meantime we have to clear the busy
-	 * bit in the TSS entry, ugh.
+	 * Reload esp0, LDT and the page table pointer:
 	 */
-	gdt_table[next->tss.tr >> 3].b &= 0xfffffdff;
-	asm volatile("ltr %0": :"g" (*(unsigned short *)&next->tss.tr));
+	tss->esp0 = next->esp0;
 
 	/*
 	 * Save away %fs and %gs. No need to save %es and %ds, as
 	 * those are always kernel segments while inside the kernel.
 	 */
-	asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->tss.fs));
-	asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->tss.gs));
+	asm volatile("movl %%fs,%0":"=m" (*(int *)&prev->fs));
+	asm volatile("movl %%gs,%0":"=m" (*(int *)&prev->gs));
 
-	/* Re-load LDT if necessary */
-	if (next->mm->segments != prev->mm->segments)
-		asm volatile("lldt %0": :"g" (*(unsigned short *)&next->tss.ldt));
+	/*
+	 * Re-load LDT if necessary
+	 */
+	if (prev_p->active_mm->segments != next_p->active_mm->segments)
+		load_LDT(next_p->mm);
 
 	/* Re-load page tables */
 	{
-		unsigned long new_cr3 = next->tss.cr3;
-		if (new_cr3 != prev->tss.cr3) 
+		unsigned long new_cr3 = next->cr3;
+
+		tss->cr3 = new_cr3;
+		if (new_cr3 != prev->cr3)
 			asm volatile("movl %0,%%cr3": :"r" (new_cr3));
 	}
 
 	/*
 	 * Restore %fs and %gs.
 	 */
-	loadsegment(fs,next->tss.fs);
-	loadsegment(gs,next->tss.gs);
+	loadsegment(fs, next->fs);
+	loadsegment(gs, next->gs);
 
 	/*
 	 * Now maybe reload the debug registers
 	 */
-	if (next->tss.debugreg[7]){
-		loaddebug(next,0);
-		loaddebug(next,1);
-		loaddebug(next,2);
-		loaddebug(next,3);
-		loaddebug(next,6);
-		loaddebug(next,7);
+	if (next->debugreg[7]){
+		loaddebug(next, 0);
+		loaddebug(next, 1);
+		loaddebug(next, 2);
+		loaddebug(next, 3);
+		/* no 4 and 5 */
+		loaddebug(next, 6);
+		loaddebug(next, 7);
+	}
+
+	if (prev->ioperm || next->ioperm) {
+		if (next->ioperm) {
+			/*
+			 * 4 cachelines copy ... not good, but not that
+			 * bad either. Anyone got something better?
+			 * This only affects processes which use ioperm().
+			 * [Putting the TSSs into 4k-tlb mapped regions
+			 * and playing VM tricks to switch the IO bitmap
+			 * is not really acceptable.]
+			 */
+			memcpy(tss->io_bitmap, next->io_bitmap,
+				 IO_BITMAP_SIZE*sizeof(unsigned long));
+			tss->bitmap = IO_BITMAP_OFFSET;
+		} else
+			/*
+			 * a bitmap offset pointing outside of the TSS limit
+			 * causes a nicely controllable SIGSEGV if a process
+			 * tries to use a port IO instruction. The first
+			 * sys_ioperm() call sets up the bitmap properly.
+			 */
+			tss->bitmap = INVALID_IO_BITMAP_OFFSET;
 	}
 }
 
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v2.3.10/linux/arch/i386/kernel/ptrace.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/i386/kernel/ptrace.c	Sun Jul 11 09:11:46 1999
@@ -45,7 +45,7 @@
 {
 	unsigned char *stack;
 
-	stack = (unsigned char *)task->tss.esp0;
+	stack = (unsigned char *)task->thread.esp0;
 	stack += offset;
 	return (*((int *)stack));
 }
@@ -61,7 +61,7 @@
 {
 	unsigned char * stack;
 
-	stack = (unsigned char *) task->tss.esp0;
+	stack = (unsigned char *) task->thread.esp0;
 	stack += offset;
 	*(unsigned long *) stack = data;
 	return 0;
@@ -76,12 +76,12 @@
 		case FS:
 			if (value && (value & 3) != 3)
 				return -EIO;
-			child->tss.fs = value;
+			child->thread.fs = value;
 			return 0;
 		case GS:
 			if (value && (value & 3) != 3)
 				return -EIO;
-			child->tss.gs = value;
+			child->thread.gs = value;
 			return 0;
 		case DS:
 		case ES:
@@ -112,10 +112,10 @@
 
 	switch (regno >> 2) {
 		case FS:
-			retval = child->tss.fs;
+			retval = child->thread.fs;
 			break;
 		case GS:
-			retval = child->tss.gs;
+			retval = child->thread.gs;
 			break;
 		case DS:
 		case ES:
@@ -229,7 +229,7 @@
 			   addr <= (long) &dummy->u_debugreg[7]){
 				addr -= (long) &dummy->u_debugreg[0];
 				addr = addr >> 2;
-				tmp = child->tss.debugreg[addr];
+				tmp = child->thread.debugreg[addr];
 			};
 			ret = put_user(tmp,(unsigned long *) data);
 			goto out;
@@ -278,7 +278,7 @@
 
 			  addr -= (long) &dummy->u_debugreg;
 			  addr = addr >> 2;
-			  child->tss.debugreg[addr] = data;
+			  child->thread.debugreg[addr] = data;
 			  ret = 0;
 			  goto out;
 		  };
@@ -409,18 +409,18 @@
 			ret = 0;
 			if ( !child->used_math ) {
 			  /* Simulate an empty FPU. */
-			  child->tss.i387.hard.cwd = 0xffff037f;
-			  child->tss.i387.hard.swd = 0xffff0000;
-			  child->tss.i387.hard.twd = 0xffffffff;
+			  child->thread.i387.hard.cwd = 0xffff037f;
+			  child->thread.i387.hard.swd = 0xffff0000;
+			  child->thread.i387.hard.twd = 0xffffffff;
 			}
 #ifdef CONFIG_MATH_EMULATION
 			if ( boot_cpu_data.hard_math ) {
 #endif
-				__copy_to_user((void *)data, &child->tss.i387.hard,
+				__copy_to_user((void *)data, &child->thread.i387.hard,
 						sizeof(struct user_i387_struct));
 #ifdef CONFIG_MATH_EMULATION
 			} else {
-			  save_i387_soft(&child->tss.i387.soft,
+			  save_i387_soft(&child->thread.i387.soft,
 					 (struct _fpstate *)data);
 			}
 #endif
@@ -438,11 +438,11 @@
 #ifdef CONFIG_MATH_EMULATION
 			if ( boot_cpu_data.hard_math ) {
 #endif
-			  __copy_from_user(&child->tss.i387.hard, (void *)data,
+			  __copy_from_user(&child->thread.i387.hard, (void *)data,
 					   sizeof(struct user_i387_struct));
 #ifdef CONFIG_MATH_EMULATION
 			} else {
-			  restore_i387_soft(&child->tss.i387.soft,
+			  restore_i387_soft(&child->thread.i387.soft,
 					    (struct _fpstate *)data);
 			}
 #endif
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.10/linux/arch/i386/kernel/setup.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/i386/kernel/setup.c	Wed Jul 21 10:07:16 1999
@@ -49,6 +49,7 @@
 #include <asm/smp.h>
 #include <asm/cobalt.h>
 #include <asm/msr.h>
+#include <asm/desc.h>
 
 /*
  * Machine setup..
@@ -57,6 +58,8 @@
 char ignore_irq13 = 0;		/* set if exception 16 works */
 struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 };
 
+unsigned long mmu_cr4_features __initdata = 0;
+
 /*
  * Bus types ..
  */
@@ -249,12 +252,30 @@
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
 
+struct resource standard_resources[] = {
+	{ "dma1", 0x00, 0x1f },
+	{ "pic1", 0x20, 0x3f },
+	{ "timer", 0x40, 0x5f },
+	{ "keyboard", 0x60, 0x6f },
+	{ "dma page reg", 0x80, 0x8f },
+	{ "pic2", 0xa0, 0xbf },
+	{ "dma2", 0xc0, 0xdf },
+	{ "fpu", 0xf0, 0xff }
+};
+
+/* For demonstration purposes only.. */
+#define keyboard_resources (standard_resources+3)
+struct resource kbd_status_resource = { "status", 0x60, 0x60 };
+
+#define STANDARD_RESOURCES (sizeof(standard_resources)/sizeof(struct resource))
+
 __initfunc(void setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	unsigned long memory_start, memory_end;
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
+	int i;
 
 #ifdef CONFIG_VISWS
 	visws_get_board_type_and_rev();
@@ -368,11 +389,9 @@
 #endif
 
 	/* request I/O space for devices used on all i[345]86 PCs */
-	request_region(0x00,0x20,"dma1");
-	request_region(0x40,0x20,"timer");
-	request_region(0x80,0x10,"dma page reg");
-	request_region(0xc0,0x20,"dma2");
-	request_region(0xf0,0x10,"fpu");
+	for (i = 0; i < STANDARD_RESOURCES; i++)
+		request_resource(&ioport_resource, standard_resources+i);
+	request_resource(keyboard_resources, &kbd_status_resource);
 
 #ifdef CONFIG_VT
 #if defined(CONFIG_VGA_CONSOLE)
@@ -381,10 +400,6 @@
 	conswitchp = &dummy_con;
 #endif
 #endif
-	/*
-	 *	Check the bugs that will bite us before we get booting
-	 */
-
 }
 
 __initfunc(static int get_model_name(struct cpuinfo_x86 *c))
@@ -977,4 +992,65 @@
 			     ((c->loops_per_sec+2500)/5000) % 100);
 	}
 	return p - buffer;
+}
+
+int cpus_initialized = 0;
+unsigned long cpu_initialized = 0;
+
+/*
+ * cpu_init() initializes state that is per-CPU. Some data is already
+ * initialized (naturally) in the bootstrap process, such as the GDT
+ * and IDT. We reload them nevertheless, this function acts as a
+ * 'CPU state barrier', nothing should get across.
+ */
+void cpu_init (void)
+{
+	int nr = smp_processor_id();
+	struct tss_struct * t = &init_tss[nr];
+
+	if (test_and_set_bit(nr,&cpu_initialized)) {
+		printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr);
+		for (;;) __sti();
+	}
+	cpus_initialized++;
+	printk("INITIALIZING CPU#%d\n", nr);
+
+	if (boot_cpu_data.x86_capability & X86_FEATURE_PSE)
+		clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
+
+	__asm__ __volatile__("lgdt %0": "=m" (gdt_descr));
+	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
+
+	/*
+	 * Delete NT
+	 */
+	__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
+
+	/*
+	 * set up and load the per-CPU TSS and LDT
+	 */
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+	t->esp0 = current->thread.esp0;
+	set_tss_desc(nr,t);
+	gdt_table[__TSS(nr)].b &= 0xfffffdff;
+	load_TR(nr);
+	load_LDT(&init_mm);
+
+	/*
+	 * Clear all 6 debug registers:
+	 */
+
+#define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) );
+
+	CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
+
+#undef CD
+
+	/*
+	 * Force FPU initialization:
+	 */
+	current->flags &= ~PF_USEDFPU;
+	current->used_math = 0;
+	stts();
 }
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- v2.3.10/linux/arch/i386/kernel/signal.c	Mon Jun  7 16:14:06 1999
+++ linux/arch/i386/kernel/signal.c	Sun Jul 11 09:11:46 1999
@@ -155,7 +155,7 @@
 {
 	struct task_struct *tsk = current;
 	clear_fpu(tsk);
-	return __copy_from_user(&tsk->tss.i387.hard, buf, sizeof(*buf));
+	return __copy_from_user(&tsk->thread.i387.hard, buf, sizeof(*buf));
 }
 
 static inline int restore_i387(struct _fpstate *buf)
@@ -167,7 +167,7 @@
 	if (boot_cpu_data.hard_math)
 		err = restore_i387_hard(buf);
 	else
-		err = restore_i387_soft(&current->tss.i387.soft, buf);
+		err = restore_i387_soft(&current->thread.i387.soft, buf);
 #endif
 	current->used_math = 1;
 	return err;
@@ -308,8 +308,8 @@
 	struct task_struct *tsk = current;
 
 	unlazy_fpu(tsk);
-	tsk->tss.i387.hard.status = tsk->tss.i387.hard.swd;
-	if (__copy_to_user(buf, &tsk->tss.i387.hard, sizeof(*buf)))
+	tsk->thread.i387.hard.status = tsk->thread.i387.hard.swd;
+	if (__copy_to_user(buf, &tsk->thread.i387.hard, sizeof(*buf)))
 		return -1;
 	return 1;
 }
@@ -328,7 +328,7 @@
 	return save_i387_hard(buf);
 #else
 	return boot_cpu_data.hard_math ? save_i387_hard(buf)
-	  : save_i387_soft(&current->tss.i387.soft, buf);
+	  : save_i387_soft(&current->thread.i387.soft, buf);
 #endif
 }
 
@@ -354,8 +354,8 @@
 	err |= __put_user(regs->edx, &sc->edx);
 	err |= __put_user(regs->ecx, &sc->ecx);
 	err |= __put_user(regs->eax, &sc->eax);
-	err |= __put_user(current->tss.trap_no, &sc->trapno);
-	err |= __put_user(current->tss.error_code, &sc->err);
+	err |= __put_user(current->thread.trap_no, &sc->trapno);
+	err |= __put_user(current->thread.error_code, &sc->err);
 	err |= __put_user(regs->eip, &sc->eip);
 	err |= __put_user(regs->xcs, (unsigned int *)&sc->cs);
 	err |= __put_user(regs->eflags, &sc->eflags);
@@ -370,7 +370,7 @@
 
 	/* non-iBCS2 extensions.. */
 	err |= __put_user(mask, &sc->oldmask);
-	err |= __put_user(current->tss.cr2, &sc->cr2);
+	err |= __put_user(current->thread.cr2, &sc->cr2);
 
 	return err;
 }
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.3.10/linux/arch/i386/kernel/smp.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/i386/kernel/smp.c	Sun Jul 11 22:50:27 1999
@@ -104,7 +104,7 @@
 
 unsigned long cpu_present_map = 0;			/* Bitmask of physically existing CPUs 				*/
 unsigned long cpu_online_map = 0;			/* Bitmask of currently online CPUs 				*/
-int smp_num_cpus = 1;					/* Total count of live CPUs 				*/
+int smp_num_cpus = 0;					/* Total count of live CPUs 				*/
 int smp_threads_ready=0;				/* Set when the idlers are all forked 			*/
 volatile int cpu_number_map[NR_CPUS];			/* which CPU maps to which logical number		*/
 volatile int __cpu_logical_map[NR_CPUS];			/* which logical number maps to which CPU		*/
@@ -225,6 +225,7 @@
 	return n;
 }
 
+
 /*
  *	Read the MPC
  */
@@ -637,6 +638,8 @@
 #endif
 }
 
+
+
 /*
  *	Trampoline 80x86 program as an array.
  */
@@ -882,6 +885,7 @@
 	 * booting is too fragile that we want to limit the
 	 * things done here to the most necessary things.
 	 */
+	cpu_init();
 	smp_callin();
 	while (!atomic_read(&smp_commenced))
 		/* nothing */ ;
@@ -896,15 +900,6 @@
  */
 void __init initialize_secondary(void)
 {
-	struct thread_struct * p = &current->tss;
-
-	/*
-	 * Load up the LDT and the task register.
-	 */
-	asm volatile("lldt %%ax": :"a" (p->ldt));
-	asm volatile("ltr %%ax": :"a" (p->tr));
-	stts();
-
 	/*
 	 * We don't actually need to load the full TSS,
 	 * basically just the stack pointer and the eip.
@@ -914,7 +909,7 @@
 		"movl %0,%%esp\n\t"
 		"jmp *%1"
 		:
-		:"r" (p->esp),"r" (p->eip));
+		:"r" (current->thread.esp),"r" (current->thread.eip));
 }
 
 extern struct {
@@ -937,7 +932,13 @@
 	kernel_thread(start_secondary, NULL, CLONE_PID);
 	cpucount++;
 
-	idle = task[cpucount];
+	/*
+	 * We remove it from the pidhash and the runqueue
+	 * once we got the process:
+	 */
+	idle = init_task.prev_task;
+
+	init_tasks[cpucount] = idle;
 	if (!idle)
 		panic("No idle process for CPU %d", i);
 
@@ -945,7 +946,10 @@
 	__cpu_logical_map[cpucount] = i;
 	cpu_number_map[i] = cpucount;
 	idle->has_cpu = 1; /* we schedule the first task manually */
-	idle->tss.eip = (unsigned long) start_secondary;
+	idle->thread.eip = (unsigned long) start_secondary;
+
+	del_from_runqueue(idle);
+	unhash_process(idle);
 
 	/* start_eip had better be page-aligned! */
 	start_eip = setup_trampoline();
@@ -1179,7 +1183,6 @@
 	/*  Must be done before other processors booted  */
 	mtrr_init_boot_cpu ();
 #endif
-	init_idle();
 	/*
 	 *	Initialize the logical to physical CPU number mapping
 	 *	and the per-CPU profiling counter/multiplier
@@ -1210,6 +1213,8 @@
 
 	cpu_number_map[boot_cpu_id] = 0;
 
+	init_idle();
+
 	/*
 	 * If we couldnt find an SMP configuration at boot time,
 	 * get out of here now!
@@ -1356,30 +1361,32 @@
 	 */
 
 	SMP_PRINTK(("Before bogomips.\n"));
-	if (cpucount==0)
-	{
+	if (!cpucount) {
 		printk(KERN_ERR "Error: only one processor found.\n");
 		cpu_online_map = (1<<hard_smp_processor_id());
-	}
-	else
-	{
-		unsigned long bogosum=0;
-		for(i=0;i<32;i++)
-		{
+	} else {
+		unsigned long bogosum = 0;
+		for(i = 0; i < 32; i++)
 			if (cpu_online_map&(1<<i))
 				bogosum+=cpu_data[i].loops_per_sec;
-		}
 		printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
 			cpucount+1,
 			(bogosum+2500)/500000,
 			((bogosum+2500)/5000)%100);
 		SMP_PRINTK(("Before bogocount - setting activated=1.\n"));
-		smp_activated=1;
-		smp_num_cpus=cpucount+1;
+		smp_activated = 1;
 	}
+	smp_num_cpus = cpucount + 1;
+
 	if (smp_b_stepping)
 		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
 	SMP_PRINTK(("Boot done.\n"));
+
+	/*
+	 * now we know the other CPUs have fired off and we know our
+	 * APIC ID, so we can go init the TSS and stuff:
+	 */
+	cpu_init();
 
 	cache_APIC_registers();
 #ifndef CONFIG_VISWS
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.3.10/linux/arch/i386/kernel/traps.c	Tue May 11 17:11:26 1999
+++ linux/arch/i386/kernel/traps.c	Mon Jul 19 17:40:12 1999
@@ -65,8 +65,8 @@
 #define DO_ERROR(trapnr, signr, str, name, tsk) \
 asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 { \
-	tsk->tss.error_code = error_code; \
-	tsk->tss.trap_no = trapnr; \
+	tsk->thread.error_code = error_code; \
+	tsk->thread.trap_no = trapnr; \
 	force_sig(signr, tsk); \
 	die_if_no_fixup(str,regs,error_code); \
 }
@@ -80,8 +80,8 @@
 			goto out; \
 		/* else fall through */ \
 	} \
-	tsk->tss.error_code = error_code; \
-	tsk->tss.trap_no = trapnr; \
+	tsk->thread.error_code = error_code; \
+	tsk->thread.trap_no = trapnr; \
 	force_sig(signr, tsk); \
 	die_if_kernel(str,regs,error_code); \
 out: \
@@ -143,10 +143,8 @@
 		regs->esi, regs->edi, regs->ebp, esp);
 	printk("ds: %04x   es: %04x   ss: %04x\n",
 		regs->xds & 0xffff, regs->xes & 0xffff, ss);
-	store_TR(i);
-	printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)",
-		current->comm, current->pid, 0xffff & i, 4096+(unsigned long)current);
-
+	printk("Process %s (pid: %d, stackpage=%08lx)",
+		current->comm, current->pid, 4096+(unsigned long)current);
 	/*
 	 * When in-kernel, we also print out the stack and code at the
 	 * time of the fault..
@@ -201,6 +199,9 @@
 	spin_lock_irq(&die_lock);
 	printk("%s: %04lx\n", str, err & 0xffff);
 	show_registers(regs);
+
+spin_lock_irq(&die_lock);
+
 	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
 }
@@ -249,8 +250,8 @@
 		return;
 	}
 	die_if_kernel("cache flush denied",regs,error_code);
-	current->tss.error_code = error_code;
-	current->tss.trap_no = 19;
+	current->thread.error_code = error_code;
+	current->thread.trap_no = 19;
 	force_sig(SIGSEGV, current);
 }
 
@@ -262,8 +263,8 @@
 	if (!(regs->xcs & 3))
 		goto gp_in_kernel;
 
-	current->tss.error_code = error_code;
-	current->tss.trap_no = 13;
+	current->thread.error_code = error_code;
+	current->thread.trap_no = 13;
 	force_sig(SIGSEGV, current);
 	return;
 
@@ -374,9 +375,9 @@
 			goto clear_TF;
 	}
 
-	/* Mast out spurious debug traps due to lazy DR7 setting */
+	/* Mask out spurious debug traps due to lazy DR7 setting */
 	if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) {
-		if (!tsk->tss.debugreg[7])
+		if (!tsk->thread.debugreg[7])
 			goto clear_dr7;
 	}
 
@@ -385,8 +386,8 @@
 		goto clear_dr7;
 
 	/* Ok, finally something we can handle */
-	tsk->tss.trap_no = 1;
-	tsk->tss.error_code = error_code;
+	tsk->thread.trap_no = 1;
+	tsk->thread.error_code = error_code;
 	force_sig(SIGTRAP, tsk);
 	return;
 
@@ -422,8 +423,8 @@
 	 */
 	task = current;
 	save_fpu(task);
-	task->tss.trap_no = 16;
-	task->tss.error_code = 0;
+	task->thread.trap_no = 16;
+	task->thread.error_code = 0;
 	force_sig(SIGFPE, task);
 }
 
@@ -453,7 +454,7 @@
 {
 	__asm__ __volatile__("clts");		/* Allow maths ops (or we recurse) */
 	if(current->used_math)
-		__asm__("frstor %0": :"m" (current->tss.i387));
+		__asm__("frstor %0": :"m" (current->thread.i387));
 	else
 	{
 		/*
@@ -486,6 +487,7 @@
 	pmd_t * pmd;
 	pte_t * pte;
 
+return;
 	/*
 	 * Allocate a new page in virtual address space, 
 	 * move the IDT into it and write protect this page.
@@ -570,12 +572,12 @@
 
 void set_tss_desc(unsigned int n, void *addr)
 {
-	_set_tssldt_desc(gdt_table+FIRST_TSS_ENTRY+(n<<1), (int)addr, 235, 0x89);
+	_set_tssldt_desc(gdt_table+__TSS(n), (int)addr, 235, 0x89);
 }
 
 void set_ldt_desc(unsigned int n, void *addr, unsigned int size)
 {
-	_set_tssldt_desc(gdt_table+FIRST_LDT_ENTRY+(n<<1), (int)addr, ((size << 3) - 1), 0x82);
+	_set_tssldt_desc(gdt_table+__LDT(n), (int)addr, ((size << 3)-1), 0x82);
 }
 
 #ifdef CONFIG_X86_VISWS_APIC
@@ -672,7 +674,7 @@
 {
 	if (readl(0x0FFFD9) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
 		EISA_bus = 1;
-	set_call_gate(&default_ldt,lcall7);
+
 	set_trap_gate(0,&divide_error);
 	set_trap_gate(1,&debug);
 	set_trap_gate(2,&nmi);
@@ -693,14 +695,20 @@
 	set_trap_gate(17,&alignment_check);
 	set_system_gate(SYSCALL_VECTOR,&system_call);
 
-	/* set up GDT task & ldt entries */
-	set_tss_desc(0, &init_task.tss);
-	set_ldt_desc(0, &default_ldt, 1);
-
-	/* Clear NT, so that we won't have troubles with that later on */
-	__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
-	load_TR(0);
-	load_ldt(0);
+	/*
+	 * default LDT is a single-entry callgate to lcall7
+	 */
+	set_call_gate(&default_ldt,lcall7);
+
+	/*
+	 * on SMP we do not yet know which CPU is on which TSS,
+	 * so we delay this until smp_init(). (the CPU is already
+	 * in a reasonable state, otherwise we wouldnt have gotten so far :)
+	 */
+#ifndef __SMP__
+	cpu_init();
+#endif
+
 #ifdef CONFIG_X86_VISWS_APIC
 	superio_init();
 	lithium_init();
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/visws_apic.c linux/arch/i386/kernel/visws_apic.c
--- v2.3.10/linux/arch/i386/kernel/visws_apic.c	Thu May  6 16:12:23 1999
+++ linux/arch/i386/kernel/visws_apic.c	Sun Jul 11 15:09:29 1999
@@ -23,7 +23,6 @@
 #include <linux/malloc.h>
 #include <linux/random.h>
 #include <linux/smp.h>
-#include <linux/tasks.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
diff -u --recursive --new-file v2.3.10/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c
--- v2.3.10/linux/arch/i386/kernel/vm86.c	Tue Dec  1 11:28:24 1998
+++ linux/arch/i386/kernel/vm86.c	Mon Jul 19 15:23:49 1999
@@ -48,8 +48,8 @@
 /*
  * virtual flags (16 and 32-bit versions)
  */
-#define VFLAGS	(*(unsigned short *)&(current->tss.v86flags))
-#define VEFLAGS	(current->tss.v86flags)
+#define VFLAGS	(*(unsigned short *)&(current->thread.v86flags))
+#define VEFLAGS	(current->thread.v86flags)
 
 #define set_flags(X,new,mask) \
 ((X) = ((X) & ~(mask)) | ((new) & (mask)))
@@ -65,25 +65,27 @@
 asmlinkage struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs));
 struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs)
 {
+	struct tss_struct *tss;
 	struct pt_regs *ret;
 	unsigned long tmp;
 
 	lock_kernel();
-	if (!current->tss.vm86_info) {
+	if (!current->thread.vm86_info) {
 		printk("no vm86_info: BAD\n");
 		do_exit(SIGSEGV);
 	}
-	set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->tss.v86mask);
-	tmp = copy_to_user(&current->tss.vm86_info->regs,regs, VM86_REGS_SIZE1);
-	tmp += copy_to_user(&current->tss.vm86_info->regs.VM86_REGS_PART2,
+	set_flags(regs->eflags, VEFLAGS, VIF_MASK | current->thread.v86mask);
+	tmp = copy_to_user(&current->thread.vm86_info->regs,regs, VM86_REGS_SIZE1);
+	tmp += copy_to_user(&current->thread.vm86_info->regs.VM86_REGS_PART2,
 		&regs->VM86_REGS_PART2, VM86_REGS_SIZE2);
-	tmp += put_user(current->tss.screen_bitmap,&current->tss.vm86_info->screen_bitmap);
+	tmp += put_user(current->thread.screen_bitmap,&current->thread.vm86_info->screen_bitmap);
 	if (tmp) {
 		printk("vm86: could not access userspace vm86_info\n");
 		do_exit(SIGSEGV);
 	}
-	current->tss.esp0 = current->tss.saved_esp0;
-	current->tss.saved_esp0 = 0;
+	tss = init_tss + smp_processor_id();
+	tss->esp0 = current->thread.esp0 = current->thread.saved_esp0;
+	current->thread.saved_esp0 = 0;
 	ret = KVM86->regs32;
 	unlock_kernel();
 	return ret;
@@ -138,7 +140,7 @@
 
 	lock_kernel();
 	tsk = current;
-	if (tsk->tss.saved_esp0)
+	if (tsk->thread.saved_esp0)
 		goto out;
 	tmp  = copy_from_user(&info, v86, VM86_REGS_SIZE1);
 	tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -148,7 +150,7 @@
 		goto out;
 	memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
 	info.regs32 = (struct pt_regs *) &v86;
-	tsk->tss.vm86_info = v86;
+	tsk->thread.vm86_info = v86;
 	do_sys_vm86(&info, tsk);
 	ret = 0;	/* we never return here */
 out:
@@ -188,7 +190,7 @@
 
 	/* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */
 	ret = -EPERM;
-	if (tsk->tss.saved_esp0)
+	if (tsk->thread.saved_esp0)
 		goto out;
 	tmp  = copy_from_user(&info, v86, VM86_REGS_SIZE1);
 	tmp += copy_from_user(&info.regs.VM86_REGS_PART2, &v86->regs.VM86_REGS_PART2,
@@ -198,7 +200,7 @@
 		goto out;
 	info.regs32 = (struct pt_regs *) &subfunction;
 	info.vm86plus.is_vm86pus = 1;
-	tsk->tss.vm86_info = (struct vm86_struct *)v86;
+	tsk->thread.vm86_info = (struct vm86_struct *)v86;
 	do_sys_vm86(&info, tsk);
 	ret = 0;	/* we never return here */
 out:
@@ -209,6 +211,7 @@
 
 static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk)
 {
+	struct tss_struct *tss;
 /*
  * make sure the vm86() system call doesn't try to do anything silly
  */
@@ -231,16 +234,16 @@
 
 	switch (info->cpu_type) {
 		case CPU_286:
-			tsk->tss.v86mask = 0;
+			tsk->thread.v86mask = 0;
 			break;
 		case CPU_386:
-			tsk->tss.v86mask = NT_MASK | IOPL_MASK;
+			tsk->thread.v86mask = NT_MASK | IOPL_MASK;
 			break;
 		case CPU_486:
-			tsk->tss.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
+			tsk->thread.v86mask = AC_MASK | NT_MASK | IOPL_MASK;
 			break;
 		default:
-			tsk->tss.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
+			tsk->thread.v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
 			break;
 	}
 
@@ -248,10 +251,11 @@
  * Save old state, set default return value (%eax) to 0
  */
 	info->regs32->eax = 0;
-	tsk->tss.saved_esp0 = tsk->tss.esp0;
-	tsk->tss.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
+	tsk->thread.saved_esp0 = tsk->thread.esp0;
+	tss = init_tss + smp_processor_id();
+	tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0;
 
-	tsk->tss.screen_bitmap = info->screen_bitmap;
+	tsk->thread.screen_bitmap = info->screen_bitmap;
 	if (info->flags & VM86_SCREEN_BITMAP)
 		mark_screen_rdonly(tsk);
 	unlock_kernel();
@@ -295,7 +299,7 @@
 
 static inline void set_vflags_long(unsigned long eflags, struct kernel_vm86_regs * regs)
 {
-	set_flags(VEFLAGS, eflags, current->tss.v86mask);
+	set_flags(VEFLAGS, eflags, current->thread.v86mask);
 	set_flags(regs->eflags, eflags, SAFE_MASK);
 	if (eflags & IF_MASK)
 		set_IF(regs);
@@ -303,7 +307,7 @@
 
 static inline void set_vflags_short(unsigned short flags, struct kernel_vm86_regs * regs)
 {
-	set_flags(VFLAGS, flags, current->tss.v86mask);
+	set_flags(VFLAGS, flags, current->thread.v86mask);
 	set_flags(regs->eflags, flags, SAFE_MASK);
 	if (flags & IF_MASK)
 		set_IF(regs);
@@ -315,7 +319,7 @@
 
 	if (VEFLAGS & VIF_MASK)
 		flags |= IF_MASK;
-	return flags | (VEFLAGS & current->tss.v86mask);
+	return flags | (VEFLAGS & current->thread.v86mask);
 }
 
 static inline int is_revectored(int nr, struct revectored_struct * bitmap)
@@ -447,8 +451,8 @@
 		spin_unlock_irqrestore(&current->sigmask_lock, flags);
 	}
 	send_sig(SIGTRAP, current, 1);
-	current->tss.trap_no = trapno;
-	current->tss.error_code = error_code;
+	current->thread.trap_no = trapno;
+	current->thread.error_code = error_code;
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.10/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.3.10/linux/arch/i386/mm/fault.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/i386/mm/fault.c	Mon Jul 19 16:09:11 1999
@@ -109,7 +109,7 @@
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
 	 */
-	if (in_interrupt() || mm == &init_mm)
+	if (in_interrupt() || !mm)
 		goto no_context;
 
 	down(&mm->mmap_sem);
@@ -177,7 +177,7 @@
 	if (regs->eflags & VM_MASK) {
 		unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
 		if (bit < 32)
-			tsk->tss.screen_bitmap |= 1 << bit;
+			tsk->thread.screen_bitmap |= 1 << bit;
 	}
 	up(&mm->mmap_sem);
 	return;
@@ -191,9 +191,9 @@
 
 	/* User mode accesses just cause a SIGSEGV */
 	if (error_code & 4) {
-		tsk->tss.cr2 = address;
-		tsk->tss.error_code = error_code;
-		tsk->tss.trap_no = 14;
+		tsk->thread.cr2 = address;
+		tsk->thread.error_code = error_code;
+		tsk->thread.trap_no = 14;
 		force_sig(SIGSEGV, tsk);
 		return;
 	}
@@ -243,9 +243,11 @@
 	else
 		printk(KERN_ALERT "Unable to handle kernel paging request");
 	printk(" at virtual address %08lx\n",address);
+	printk(" printing eip:\n");
+	printk("%08lx\n", regs->eip);
 	__asm__("movl %%cr3,%0" : "=r" (page));
-	printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
-		tsk->tss.cr3, page);
+	printk(KERN_ALERT "current->thread.cr3 = %08lx, %%cr3 = %08lx\n",
+		tsk->thread.cr3, page);
 	page = ((unsigned long *) __va(page))[address >> 22];
 	printk(KERN_ALERT "*pde = %08lx\n", page);
 	if (page & 1) {
@@ -275,9 +277,9 @@
 	 * Send a sigbus, regardless of whether we were in kernel
 	 * or user mode.
 	 */
-	tsk->tss.cr2 = address;
-	tsk->tss.error_code = error_code;
-	tsk->tss.trap_no = 14;
+	tsk->thread.cr2 = address;
+	tsk->thread.error_code = error_code;
+	tsk->thread.trap_no = 14;
 	force_sig(SIGBUS, tsk);
 
 	/* Kernel mode? Handle exceptions or die */
diff -u --recursive --new-file v2.3.10/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.3.10/linux/arch/i386/mm/init.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/i386/mm/init.c	Mon Jul 19 23:08:41 1999
@@ -181,34 +181,6 @@
 extern char _text, _etext, _edata, __bss_start, _end;
 extern char __init_begin, __init_end;
 
-#define X86_CR4_VME		0x0001		/* enable vm86 extensions */
-#define X86_CR4_PVI		0x0002		/* virtual interrupts flag enable */
-#define X86_CR4_TSD		0x0004		/* disable time stamp at ipl 3 */
-#define X86_CR4_DE		0x0008		/* enable debugging extensions */
-#define X86_CR4_PSE		0x0010		/* enable page size extensions */
-#define X86_CR4_PAE		0x0020		/* enable physical address extensions */
-#define X86_CR4_MCE		0x0040		/* Machine check enable */
-#define X86_CR4_PGE		0x0080		/* enable global pages */
-#define X86_CR4_PCE		0x0100		/* enable performance counters at ipl 3 */
-
-/*
- * Save the cr4 feature set we're using (ie
- * Pentium 4MB enable and PPro Global page
- * enable), so that any CPU's that boot up
- * after us can get the correct flags.
- */
-unsigned long mmu_cr4_features __initdata = 0;
-
-static inline void set_in_cr4(unsigned long mask)
-{
-	mmu_cr4_features |= mask;
-	__asm__("movl %%cr4,%%eax\n\t"
-		"orl %0,%%eax\n\t"
-		"movl %%eax,%%cr4\n"
-		: : "irg" (mask)
-		:"ax");
-}
-
 /*
  * allocate page table(s) for compile-time fixed mappings
  */
@@ -358,7 +330,6 @@
 	printk("Checking if this processor honours the WP bit even in supervisor mode... ");
 	pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY));
 	local_flush_tlb();
-	current->mm->mmap->vm_start += PAGE_SIZE;
 	__asm__ __volatile__(
 		"jmp 1f; 1:\n"
 		"movb %0,%1\n"
@@ -370,7 +341,6 @@
 		:"memory");
 	pg0[0] = old;
 	local_flush_tlb();
-	current->mm->mmap->vm_start -= PAGE_SIZE;
 	if (boot_cpu_data.wp_works_ok < 0) {
 		boot_cpu_data.wp_works_ok = 0;
 		printk("No.\n");
diff -u --recursive --new-file v2.3.10/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c
--- v2.3.10/linux/arch/mips/kernel/irixelf.c	Wed Jun 30 13:38:18 1999
+++ linux/arch/mips/kernel/irixelf.c	Fri Jul 16 09:27:46 1999
@@ -732,9 +732,9 @@
 		if(retval) {
 			set_fs(old_fs);
 			printk("Unable to load IRIX ELF interpreter\n");
-			kfree(elf_phdata);
 			send_sig(SIGSEGV, current, 0);
-			return 0;
+			retval = 0;
+			goto out_file;
 		}
 	}
 
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.3.10/linux/arch/ppc/Makefile	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/Makefile	Mon Jul 12 15:12:55 1999
@@ -65,8 +65,7 @@
 checks:
 	@$(MAKE) -C arch/$(ARCH)/kernel checks
 
-BOOT_TARGETS = netboot znetboot zImage floppy install \
-	vmlinux.coff znetboot.initrd zImage.initrd vmlinux.coff.initrd
+BOOT_TARGETS = zImage znetboot.initrd zImage.initrd
 
 ifdef CONFIG_MBX
 $(BOOT_TARGETS): $(CHECKS) vmlinux
@@ -74,6 +73,24 @@
 	@$(MAKEMBXBOOT) $@
 else
 $(BOOT_TARGETS): $(CHECKS) vmlinux
+	@$(MAKECOFFBOOT) $@
+	@$(MAKEBOOT) $@
+	@$(MAKECHRPBOOT) $@
+
+znetboot: $(CHECKS) vmlinux
+ifdef CONFIG_SMP
+ifdef CONFIG_PPC64
+	cp -f vmlinux /tftpboot/vmlinux.smp.64
+else
+	cp -f vmlinux /tftpboot/vmlinux.smp
+endif
+else
+ifdef CONFIG_PPC64
+	cp -f vmlinux /tftpboot/vmlinux.64
+else
+	cp -f vmlinux /tftpboot/vmlinux
+endif
+endif
 	@$(MAKECOFFBOOT) $@
 	@$(MAKEBOOT) $@
 	@$(MAKECHRPBOOT) $@
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/amiga/amiints.c linux/arch/ppc/amiga/amiints.c
--- v2.3.10/linux/arch/ppc/amiga/amiints.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/ppc/amiga/amiints.c	Mon Jul 12 15:12:55 1999
@@ -108,7 +108,7 @@
 	custom.intreq = 0x7fff;
 
 #ifdef CONFIG_APUS
-	/* Clear any inter-CPU interrupt requests. Circumvents bug in
+	/* Clear any inter-CPU interupt requests. Circumvents bug in
            Blizzard IPL emulation HW (or so it appears). */
 	APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK);
 
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c
--- v2.3.10/linux/arch/ppc/chrpboot/main.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/chrpboot/main.c	Mon Jul 12 15:12:55 1999
@@ -71,7 +71,7 @@
     sa = *(unsigned long *)PROG_START+PROG_START;
     printf("start address = 0x%x\n\r", sa);
 
-    (*(void (*)())sa)(a1, a2, prom, 0, 0);
+    (*(void (*)())sa)(0, 0, prom, a1, a2);
 
     printf("returned?\n\r");
 
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.10/linux/arch/ppc/config.in	Thu Jul  8 15:42:19 1999
+++ linux/arch/ppc/config.in	Mon Jul 12 15:12:55 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.94 1999/06/25 11:00:07 davem Exp $
+# $Id: config.in,v 1.95 1999/07/03 08:57:06 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.3.10/linux/arch/ppc/kernel/chrp_pci.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/chrp_pci.c	Mon Jul 12 15:12:55 1999
@@ -97,7 +97,7 @@
 #define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000))
 #define PYTHON_CFA(b, d, o)	(0x80 | ((b<<6) << 8) | ((d) << 16) \
 				 | (((o) & ~3) << 24))
-unsigned int python_busnr = 1;
+unsigned int python_busnr = 0;
 
 int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
 				    unsigned char offset, unsigned char *val)
@@ -347,7 +347,7 @@
 			} else if ( !strncmp("IBM,7043-260",
 			   get_property(find_path_device("/"), "name", NULL),12) )
 			{
-				pci_dram_offset = 0x80000000;
+				pci_dram_offset = 0x0;
 				isa_mem_base = 0xc0000000;
 				isa_io_base = 0xf8000000;
 			}
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.3.10/linux/arch/ppc/kernel/chrp_setup.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/chrp_setup.c	Mon Jul 12 15:12:55 1999
@@ -71,6 +71,8 @@
 void chrp_time_init(void);
 
 void chrp_setup_pci_ptrs(void);
+extern void chrp_progress(char *, unsigned short);
+void chrp_event_scan(void);
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
@@ -589,10 +591,10 @@
 	chrp_setup_pci_ptrs();
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* take care of initrd if we have one */
-	if ( r3 )
+	if ( r6 )
 	{
-		initrd_start = r3 + KERNELBASE;
-		initrd_end = r3 + r4 + KERNELBASE;
+		initrd_start = r6 + KERNELBASE;
+		initrd_end = r6 + r7 + KERNELBASE;
 	}
 #endif /* CONFIG_BLK_DEV_INITRD */
 
@@ -658,6 +660,8 @@
 	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
 	SYSRQ_KEY = 0x54;
 #endif
+	if ( rtas_data )
+		ppc_md.progress = chrp_progress;
 #endif
 #endif
 
@@ -678,16 +682,33 @@
 	 * Print the banner, then scroll down so boot progress
 	 * can be printed.  -- Cort 
 	 */
-	chrp_progress("Linux/PPC "UTS_RELEASE"\n");
+	if ( ppc_md.progress ) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0);
 }
 
-void chrp_progress(char *s)
+void chrp_progress(char *s, unsigned short hex)
 {
 	extern unsigned int rtas_data;
+	unsigned long width;
+	struct device_node *root;
+	char *os = s;
 	
+	if ( (root = find_path_device("/rtas")) )
+		width = *(unsigned long *)get_property(root, "ibm,display-line-length", NULL);
+	else
+		width = 0x10;
+
 	if ( (_machine != _MACH_chrp) || !rtas_data )
 		return;
-	call_rtas( "display-character", 1, 1, NULL, '\r' );
-	while ( *s )
-		call_rtas( "display-character", 1, 1, NULL, *s++ );
+	if ( call_rtas( "display-character", 1, 1, NULL, '\r' ) )
+	{
+		/* assume no display-character RTAS method - use hex display */
+		return;
+	}
+	while ( *os )
+		call_rtas( "display-character", 1, 1, NULL, *os++ );
+	/* scan back for the last newline or carriage return */
+	for ( os-- ; (*os != '\n') && (*os != '\r') && (os > s) ; os--, width-- )
+		/* nothing */ ;
+	/*while ( width-- )*/
+	call_rtas( "display-character", 1, 1, NULL, ' ' );
 }
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.3.10/linux/arch/ppc/kernel/head.S	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/head.S	Mon Jul 12 15:12:55 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.133 1999/05/20 05:13:08 cort Exp $
+ *  $Id: head.S,v 1.134 1999/06/30 05:05:52 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -300,7 +300,7 @@
 	oris	r21,r11,(KERNELBASE+0x20000000)@h
 	mtspr	DBAT2L,r18		/* N.B. 6xx (not 601) have valid */
 	mtspr	DBAT2U,r21		/* bit in upper BAT register */
-	mtspr	IBAT2L,r28
+	mtspr	IBAT2L,r18
 	mtspr	IBAT2U,r21
 #endif /* CONFIG_PPC64 */
 #endif
@@ -1978,7 +1978,13 @@
 	lwz	r6,GPR4(r1)
 	lwz	r7,GPR5(r1)
 	lwz	r8,GPR6(r1)
-	mr	r9,r2
+	lwz	r9,GPR7(r1)
+	bl	printk
+	lis	r3,77f@ha
+	addi	r3,r3,77f@l
+	lwz	r4,GPR8(r1)
+	lwz	r5,GPR9(r1)
+	mr	r6,r2
 	bl	printk
 	lwz	r0,GPR0(r1)
 	lwz	r3,GPR3(r1)
@@ -2081,7 +2087,8 @@
 66:	li	r3,ENOSYS
 	b	52b
 #ifdef SHOW_SYSCALLS
-7:	.string	"syscall %d(%x, %x, %x, %x), current=%p\n"
+7:	.string	"syscall %d(%x, %x, %x, %x, %x, "
+77:	.string	"%x, %x), current=%p\n"
 79:	.string	" -> %x\n"
 	.align	2
 #endif
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c
--- v2.3.10/linux/arch/ppc/kernel/openpic.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/openpic.c	Mon Jul 12 15:12:55 1999
@@ -182,6 +182,8 @@
     if (!OpenPIC)
 	panic("No OpenPIC found");
 
+    if ( ppc_md.progress ) ppc_md.progress("openpic enter",0x122);
+
     t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
     switch (t & OPENPIC_FEATURE_VERSION_MASK) {
 	case 1:
@@ -201,6 +203,7 @@
 		     OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
     NumSources = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
 		  OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1;
+
     printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n", version,
 	   NumProcessors, NumSources, OpenPIC);
     timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
@@ -212,6 +215,8 @@
 
     if ( main_pic )
     {
+	    if ( ppc_md.progress ) ppc_md.progress("openpic main",0x3ff);
+      
 	    /* Initialize timer interrupts */
 	    for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
 		    /* Disabled, Priority 0 */
@@ -226,9 +231,12 @@
 		    openpic_initipi(i, 0, OPENPIC_VEC_IPI+i);
 	    }
 	    
+	    if ( ppc_md.progress ) ppc_md.progress("openpic initirq",0x3bb);
 	    /* Initialize external interrupts */
 	    /* SIOint (8259 cascade) is special */
 	    openpic_initirq(0, 8, OPENPIC_VEC_SOURCE, 1, 1);
+	    
+	    if ( ppc_md.progress ) ppc_md.progress("openpic map",0x3cc);
 	    /* Processor 0 */
 	    openpic_mapirq(0, 1<<0);
 	    for (i = 1; i < NumSources; i++) {
@@ -248,6 +256,7 @@
 	    openpic_set_priority(0, 0);
 	    openpic_disable_8259_pass_through();
     }
+    if ( ppc_md.progress ) ppc_md.progress("openpic exit",0x222);
 }
 
 
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.3.10/linux/arch/ppc/kernel/pmac_setup.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/pmac_setup.c	Mon Jul 12 15:12:55 1999
@@ -58,6 +58,7 @@
 #include <asm/ide.h>
 #include <asm/machdep.h>
 #include <asm/keyboard.h>
+#include <asm/dma.h>
 
 #include "time.h"
 #include "local_irq.h"
@@ -204,11 +205,12 @@
 {
     Scsi_Disk *dp;
     int i;
-
+#ifdef CONFIG_BLK_DEV_SD
     for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp)
         if (dp->device != NULL && dp->device->host == host
             && dp->device->id == tgt)
             return MKDEV_SD(i);
+#endif /* CONFIG_BLK_DEV_SD */
     return 0;
 }
 #endif
@@ -517,13 +519,13 @@
 void
 pmac_ide_insw(ide_ioreg_t port, void *buf, int ns)
 {
-	_insw_ns(port+_IO_BASE, buf, ns);
+	_insw_ns((unsigned short *)(port+_IO_BASE), buf, ns);
 }
 
 void
 pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns)
 {
-	_outsw_ns(port+_IO_BASE, buf, ns);
+	_outsw_ns((unsigned short *)(port+_IO_BASE), buf, ns);
 }
 
 int
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.3.10/linux/arch/ppc/kernel/process.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/ppc/kernel/process.c	Mon Jul 12 15:12:55 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: process.c,v 1.86 1999/06/17 21:53:46 cort Exp $
+ * $Id: process.c,v 1.87 1999/07/03 08:57:07 davem Exp $
  *
  *  linux/arch/ppc/kernel/process.c
  *
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.3.10/linux/arch/ppc/kernel/prom.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/kernel/prom.c	Mon Jul 12 15:12:55 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.61 1999/06/17 06:05:52 paulus Exp $
+ * $Id: prom.c,v 1.62 1999/07/02 19:59:31 cort Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -502,8 +502,8 @@
 			return;
 		
 		/* copy the holding pattern code to someplace safe (8M) */
-		memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x10000 );
-		for (i = 8<<20; i < ((8<<20)+0x10000); i += 32)
+		memcpy( (void *)(8<<20), RELOC(__secondary_hold), 0x100 );
+		for (i = 8<<20; i < ((8<<20)+0x100); i += 32)
 		{
 			asm volatile("dcbf 0,%0" : : "r" (i) : "memory");
 			asm volatile("icbi 0,%0" : : "r" (i) : "memory");
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.3.10/linux/arch/ppc/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
+++ linux/arch/ppc/kernel/ptrace.c	Mon Jul 12 15:12:55 1999
@@ -81,6 +81,7 @@
 	regs->msr &= ~MSR_SE;
 }
 
+#if 0
 /*
  * This routine gets a long from any process space by following the page
  * tables. NOTE! You should check that the long isn't on a page boundary,
@@ -283,11 +284,13 @@
 		put_long(tsk, vma,addr,data);
 	return 0;
 }
+#endif
 
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
 	int ret = -EPERM;
+	unsigned long flags;
 
 	lock_kernel();
 	if (request == PTRACE_TRACEME) {
@@ -302,7 +305,10 @@
 	if (pid == 1)		/* you may not mess with init */
 		goto out;
 	ret = -ESRCH;
-	if (!(child = find_task_by_pid(pid)))
+	read_lock(&tasklist_lock);
+	child = find_task_by_pid(pid);
+	read_unlock(&tasklist_lock);	/* FIXME!!! */
+	if ( !child )
 		goto out;
 	ret = -EPERM;
 	if (request == PTRACE_ATTACH) {
@@ -322,11 +328,15 @@
 		if (child->flags & PF_PTRACED)
 			goto out;
 		child->flags |= PF_PTRACED;
+		
+		write_lock_irqsave(&tasklist_lock, flags);
 		if (child->p_pptr != current) {
 			REMOVE_LINKS(child);
 			child->p_pptr = current;
 			SET_LINKS(child);
 		}
+		write_unlock_irqrestore(&tasklist_lock, flags);
+
 		send_sig(SIGSTOP, child, 1);
 		ret = 0;
 		goto out;
@@ -342,22 +352,19 @@
 		goto out;
 
 	switch (request) {
-	/* If I and D space are separate, these will need to be fixed. */
+	/* when I and D space are separate, these will need to be fixed. */
 		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 		case PTRACE_PEEKDATA: {
 			unsigned long tmp;
+			int copied;
 
-			down(&child->mm->mmap_sem);
-			ret = read_long(child, addr, &tmp);
-			up(&child->mm->mmap_sem);
-			if (ret < 0)
+			copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+			ret = -EIO;
+			if (copied != sizeof(tmp))
 				goto out;
-			ret = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
-			if (!ret)
-				put_user(tmp, (unsigned long *) data);
+			ret = put_user(tmp,(unsigned long *) data);
 			goto out;
 		}
-
 	/* read the word at location addr in the USER area. */
 		case PTRACE_PEEKUSR: {
 			unsigned long tmp;
@@ -391,11 +398,11 @@
       /* If I and D space are separate, this will have to be fixed. */
 		case PTRACE_POKETEXT: /* write the word at location addr. */
 		case PTRACE_POKEDATA:
-			down(&child->mm->mmap_sem);
-			ret = write_long(child,addr,data);
-			up(&child->mm->mmap_sem);
+			ret = 0;
+			if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
+				goto out;
+			ret = -EIO;
 			goto out;
-
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 			ret = -EIO;
 			if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2))
@@ -459,9 +466,9 @@
 				goto out;
 			child->flags &= ~PF_TRACESYS;
 			set_single_step(child);
-			wake_up_process(child);
 			child->exit_code = data;
 			/* give it a chance to run. */
+			wake_up_process(child);
 			ret = 0;
 			goto out;
 		}
@@ -473,9 +480,11 @@
 			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
 			wake_up_process(child);
 			child->exit_code = data;
+			write_lock_irqsave(&tasklist_lock, flags);
 			REMOVE_LINKS(child);
 			child->p_pptr = child->p_opptr;
 			SET_LINKS(child);
+			write_unlock_irqrestore(&tasklist_lock, flags);
 			/* make sure the single step bit is not set. */
 			clear_single_step(child);
 			ret = 0;
@@ -493,7 +502,6 @@
 
 asmlinkage void syscall_trace(void)
 {
-	lock_kernel();
 	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
 			!= (PF_PTRACED|PF_TRACESYS))
 		goto out;
@@ -511,5 +519,4 @@
 		current->exit_code = 0;
 	}
 out:
-	unlock_kernel();
 }
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.10/linux/arch/ppc/kernel/setup.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/ppc/kernel/setup.c	Tue Jul 13 02:29:35 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.136 1999/06/18 07:11:35 cort Exp $
+ * $Id: setup.c,v 1.138 1999/07/11 16:32:21 cort Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -331,6 +331,7 @@
 #ifdef __SMP__
 	if ( first_cpu_booted ) return 0;
 #endif /* __SMP__ */
+	if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100);
 	
 #ifndef CONFIG_MACH_SPECIFIC
 	/* boot loader will tell us if we're APUS */
@@ -477,13 +478,13 @@
 	default:
 		printk("Unknown machine type in identify_machine!\n");
 	}
-
 	/* Check for nobats option (used in mapin_ram). */
 	if (strstr(cmd_line, "nobats")) {
 		extern int __map_without_bats;
 		__map_without_bats = 1;
 	}
-	
+
+	if ( ppc_md.progress ) ppc_md.progress("id mach(): done", 0x200);
 	return 0;
 }
 
@@ -539,6 +540,8 @@
 	*memory_end_p = (unsigned long) end_of_DRAM;
 
 	ppc_md.setup_arch(memory_start_p, memory_end_p);
+	/* clear the progress line */
+	if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff);
 }
 
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.3.10/linux/arch/ppc/kernel/smp.c	Thu Jul  8 15:42:19 1999
+++ linux/arch/ppc/kernel/smp.c	Mon Jul 12 15:12:55 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: smp.c,v 1.54 1999/06/24 17:13:34 cort Exp $
+ * $Id: smp.c,v 1.55 1999/07/03 08:57:09 davem Exp $
  *
  * Smp support for ppc.
  *
diff -u --recursive --new-file v2.3.10/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.10/linux/arch/ppc/mm/init.c	Wed Jun 30 13:38:19 1999
+++ linux/arch/ppc/mm/init.c	Mon Jul 12 15:12:55 1999
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.170 1999/06/29 12:33:51 davem Exp $
+ *  $Id: init.c,v 1.171 1999/07/08 23:20:14 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -50,6 +50,7 @@
 #include <asm/mbx.h>
 #include <asm/smp.h>
 #include <asm/bootx.h>
+#include <asm/machdep.h>
 /* APUS includes */
 #include <asm/setup.h>
 #include <asm/amigahw.h>
@@ -961,7 +962,6 @@
 	} else {
 		p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
 	}
-	/*memset(p, 0, PAGE_SIZE);*/
 	__clear_user(p, PAGE_SIZE);
 	return p;
 }
@@ -1027,7 +1027,7 @@
 #ifdef __SMP__
 	if ( first_cpu_booted ) return;
 #endif /* __SMP__ */
-	
+	if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111);
 #ifndef CONFIG_8xx
 	if (have_of)
 		end_of_DRAM = pmac_find_end_of_memory();
@@ -1038,10 +1038,12 @@
 	else /* prep */
 		end_of_DRAM = prep_find_end_of_memory();
 
+	if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300);
         hash_init();
         _SDR1 = __pa(Hash) | (Hash_mask >> 10);
 	ioremap_base = 0xf8000000;
 
+	if ( ppc_md.progress ) ppc_md.progress("MMU:mapin", 0x301);
 	/* Map in all of RAM starting at KERNELBASE */
 	mapin_ram();
 
@@ -1050,6 +1052,7 @@
 	 * the io areas.  RAM was mapped by mapin_ram().
 	 * -- Cort
 	 */
+	if ( ppc_md.progress ) ppc_md.progress("MMU:setbat", 0x302);
 	switch (_machine) {
 	case _MACH_prep:
 		setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
@@ -1102,6 +1105,7 @@
         ioremap(0x80000000, 0x4000);
         ioremap(0x81000000, 0x4000);
 #endif /* CONFIG_8xx */
+	if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211);
 }
 
 /*
@@ -1310,7 +1314,7 @@
 	int i;
 	
 	/* max amount of RAM we allow -- Cort */
-#define RAM_LIMIT (768<<20)
+#define RAM_LIMIT (256<<20)
 
 	memory_node = find_devices("memory");
 	if (memory_node == NULL) {
@@ -1509,6 +1513,7 @@
 	extern unsigned int hash_page_patch_A[], hash_page_patch_B[],
 		hash_page_patch_C[], hash_page[];
 
+	if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
 	/*
 	 * Allow 64k of hash table for every 16MB of memory,
 	 * up to a maximum of 2MB.
@@ -1542,6 +1547,7 @@
  	}
 #endif /* NO_RELOAD_HTAB */
 	
+	if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
 	/* Find some memory for the hash table. */
 	if ( Hash_size )
 		Hash = find_mem_piece(Hash_size, Hash_size);
@@ -1557,11 +1563,11 @@
 #else
 #define b(x) (x)
 #endif
-		/*memset(Hash, 0, Hash_size);*/
-		__clear_user(Hash, Hash_size);
 		
 		Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
-
+		__clear_user(Hash, Hash_size);
+		
+		if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
 		/*
 		 * Patch up the instructions in head.S:hash_page
 		 */
@@ -1601,5 +1607,6 @@
 		flush_icache_range((unsigned long) b(hash_page),
 				   (unsigned long) b(hash_page + 1));
 	}
+	if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
 }
 #endif /* ndef CONFIG_8xx */
diff -u --recursive --new-file v2.3.10/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.3.10/linux/drivers/block/ide-cd.c	Fri May 28 09:34:41 1999
+++ linux/drivers/block/ide-cd.c	Thu Jul 15 13:55:24 1999
@@ -2124,20 +2124,23 @@
 				 msf.cdmsf_frame0);
 
 		/* Make sure the TOC is up to date. */
-		stat = cdrom_read_toc (drive, NULL);
-		if (stat) return stat;
+		if (cmd != CDROMREADRAW) {
+			stat = cdrom_read_toc (drive, NULL);
+			if (stat) 
+				return stat;
 
-		toc = info->toc;
+			toc = info->toc;
 
-		if (lba < 0 || lba >= toc->capacity)
-			return -EINVAL;
+			if (lba < 0 || lba >= toc->capacity)
+				return -EINVAL;
+		}
 
 		buf = (char *) kmalloc (blocksize, GFP_KERNEL);
 		if (buf == NULL)
 			return -ENOMEM;
 
-		stat = cdrom_read_block (drive, format, lba, 1, buf, blocksize,
-					 NULL);
+		stat = cdrom_read_block (drive, format, lba, 1, buf,
+					 blocksize, NULL);
 
 		if (stat == 0) {
 			if (cmd == CDROMREADMODE2) {
diff -u --recursive --new-file v2.3.10/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- v2.3.10/linux/drivers/block/ide-pmac.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/block/ide-pmac.c	Mon Jul 12 16:21:25 1999
@@ -60,35 +60,44 @@
  * N.B. this can't be an initfunc, because the media-bay task can
  * call ide_[un]register at any time.
  */
-void pmac_ide_init_hwif_ports (	hw_regs_t *hw,
-				ide_ioreg_t data_port,
-				ide_ioreg_t ctrl_port,
-				int *irq)
+void pmac_ide_init_hwif_ports(hw_regs_t *hw,
+			      ide_ioreg_t data_port, ide_ioreg_t ctrl_port,
+			      int *irq)
 {
-	int i, r;
+	int i, ix;
 
 	if (data_port == 0)
 		return;
+
+	for (ix = 0; ix < MAX_HWIFS; ++ix)
+		if (data_port == pmac_ide_regbase[ix])
+			break;
+
+	if (ix >= MAX_HWIFS) {
+		/* Probably a PCI interface... */
+		for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
+			hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
+		/* XXX is this right? */
+		hw->io_ports[IDE_CONTROL_OFFSET] = 0;
+		if (irq != 0)
+			*irq = 0;
+		return;
+	}
+
 	/* we check only for -EINVAL meaning that we have found a matching
 	   bay but with the wrong device type */ 
-
-	r = check_media_bay_by_base(data_port, MB_CD);
-	if (r == -EINVAL)
+	i = check_media_bay_by_base(data_port, MB_CD);
+	if (i == -EINVAL) {
+		hw->io_ports[IDE_DATA_OFFSET] = 0;
 		return;
-	
-	for ( i = 0; i < 8 ; ++i )
+	}
+
+	for (i = 0; i < 8; ++i)
 		hw->io_ports[i] = data_port + i * 0x10;
 	hw->io_ports[8] = data_port + 0x160;
 
-	if (irq != NULL) {
-		*irq = 0;
-		for (i = 0; i < MAX_HWIFS; ++i) {
-			if (data_port == pmac_ide_regbase[i]) {
-				*irq = pmac_ide_irq[i];
-				break;
-			}
-		}
-	}
+	if (irq != NULL)
+		*irq = pmac_ide_irq[ix];
 }
 
 void pmac_ide_tuneproc(ide_drive_t *drive, byte pio)
@@ -100,10 +109,10 @@
 	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
 	switch (pio) {
 	case 4:
-		out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x211025);
+		out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x211025);
 		break;
 	default:
-		out_le32((unsigned *)(IDE_DATA_REG + 0x200), 0x2f8526);
+		out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), 0x2f8526);
 		break;
 	}
 }
@@ -145,14 +154,36 @@
 	*pp = removables;
 
 	for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) {
+		struct device_node *tp;
+
+		/*
+		 * If this node is not under a mac-io or dbdma node,
+		 * leave it to the generic PCI driver.
+		 */
+		for (tp = np->parent; tp != 0; tp = tp->parent)
+			if (tp->type && (strcmp(tp->type, "mac-io") == 0
+					 || strcmp(tp->type, "dbdma") == 0))
+				break;
+		if (tp == 0)
+			continue;
+
 		if (np->n_addrs == 0) {
 			printk(KERN_WARNING "ide: no address for device %s\n",
 			       np->full_name);
 			continue;
 		}
 
-		base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
-		
+		/*
+		 * If this slot is taken (e.g. by ide-pci.c) try the next one.
+		 */
+		while (i < MAX_HWIFS
+		       && ide_hwifs[i].io_ports[IDE_DATA_OFFSET] != 0)
+			++i;
+		if (i >= MAX_HWIFS)
+			break;
+
+		base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE;
+
 		/* XXX This is bogus. Should be fixed in the registry by checking
 		   the kind of host interrupt controller, a bit like gatwick
 		   fixes in irq.c
diff -u --recursive --new-file v2.3.10/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.3.10/linux/drivers/block/loop.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/block/loop.c	Mon Jul 12 07:49:36 1999
@@ -375,7 +375,7 @@
 		   a file structure */
 		lo->lo_backing_file = NULL;
 	} else if (S_ISREG(inode->i_mode)) {
-		if (!inode->i_op->bmap) { 
+		if (!inode->i_op->get_block) { 
 			printk(KERN_ERR "loop: device has no block access/not implemented\n");
 			goto out_putf;
 		}
diff -u --recursive --new-file v2.3.10/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.3.10/linux/drivers/cdrom/cdrom.c	Thu Apr 29 11:53:41 1999
+++ linux/drivers/cdrom/cdrom.c	Thu Jul 15 13:49:33 1999
@@ -1145,7 +1145,9 @@
 		   ((cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)!=0));
 
         strcpy(cdrom_drive_info+pos,"\n\n");
-	*lenp=pos+3;
+        pos += 3;
+        if (*lenp > pos)
+        	*lenp = pos;
 
         return proc_dostring(ctl, write, filp, buffer, lenp);
 }
diff -u --recursive --new-file v2.3.10/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.3.10/linux/drivers/char/adbmouse.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/adbmouse.c	Mon Jul 12 16:21:25 1999
@@ -38,7 +38,9 @@
 #ifdef __powerpc__
 #include <asm/processor.h>
 #endif
+#ifdef __mc68000__
 #include <asm/setup.h>
+#endif
 
 static struct mouse_status mouse;
 static unsigned char adb_mouse_buttons[16];
@@ -242,7 +244,7 @@
     ADB_MOUSE_MINOR, "adbmouse", &adb_mouse_fops
 };
 
-int __init adb_mouse_init(void)
+__initfunc(int adb_mouse_init(void))
 {
     mouse.active = 0;
     mouse.ready = 0;
@@ -268,7 +270,7 @@
  * option, which is about using ADB keyboard buttons to emulate
  * mouse buttons. -- paulus
  */
-void __init adb_mouse_setup(char *str, int *ints)
+__initfunc(void adb_mouse_setup(char *str, int *ints))
 {
 	if (ints[0] >= 1) {
 		adb_emulate_buttons = ints[1] > 0;
@@ -280,6 +282,7 @@
 }
 
 #ifdef MODULE
+#include <asm/setup.h>
 
 int init_module(void)
 {
diff -u --recursive --new-file v2.3.10/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c
--- v2.3.10/linux/drivers/char/cyclades.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/cyclades.c	Fri Jul 16 14:57:41 1999
@@ -1,7 +1,7 @@
 #define BLOCKMOVE
 #define	Z_WAKE
 static char rcsid[] =
-"$Revision: 2.2.2.3 $$Date: 1999/06/28 11:13:29 $";
+"$Revision: 2.3.1.1 $$Date: 1999/07/15 16:45:53 $";
 
 /*
  *  linux/drivers/char/cyclades.c
@@ -31,6 +31,20 @@
  *   void cleanup_module(void);
  *
  * $Log: cyclades.c,v $
+ * Revision 2.3.1.1   1999/07/15 16:45:53 ivan
+ * Removed CY_PROC conditional compilation;
+ * Implemented SMP-awareness for the driver;
+ * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off] 
+ * functions;
+ * The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs
+ * (irq=NN) as parameters (only for ISA boards);
+ * Fixed bug in set_line_char that would prevent the Cyclades-Z 
+ * ports from being configured at speeds above 115.2Kbps;
+ * Fixed bug in cy_set_termios that would prevent XON/XOFF flow control
+ * switching from working properly;
+ * The driver now only prints IRQ info for the Cyclades-Z if it's 
+ * configured to work in interrupt mode;
+ *
  * Revision 2.2.2.3   1999/06/28 11:13:29 ivan
  * Added support for interrupt mode operation for the Z cards;
  * Removed the driver inactivity control for the Z;
@@ -557,7 +571,6 @@
 #undef	CY_16Y_HACK
 #undef	CY_ENABLE_MONITORING
 #undef	CY_PCI_DEBUG
-#undef	CY_PROC
 
 #if 0
 #define PAUSE __asm__("nop");
@@ -613,6 +626,18 @@
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 
+#include <asm/spinlock.h>
+
+#define	CY_LOCK(info,flags)					\
+		do {						\
+		spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \
+		} while (0)
+		
+#define	CY_UNLOCK(info,flags)					\
+		do {						\
+		spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \
+		} while (0)
+
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -668,11 +693,6 @@
 static int serial_refcount;
 
 #ifndef CONFIG_COBALT_27
-static volatile int cy_irq_triggered;
-static volatile int cy_triggered;
-static int cy_wild_int_mask;
-static volatile ucchar *intr_base_addr;
-
 /* This is the address lookup table. The driver will probe for
    Cyclom-Y/ISA boards at all addresses in here. If you want the
    driver to probe addresses at a different address, add it to
@@ -695,6 +715,14 @@
 };
 #define NR_ISA_ADDRS (sizeof(cy_isa_addresses)/sizeof(unsigned char*))
 
+#ifdef MODULE
+static int maddr[NR_CARDS] = { 0, };
+static int irq[NR_CARDS]  = { 0, };
+
+MODULE_PARM(maddr, "1-" __MODULE_STRING(NR_CARDS) "l");
+MODULE_PARM(irq, "1-" __MODULE_STRING(NR_CARDS) "i");
+#endif
+
 #endif /* CONFIG_COBALT_27 */
 
 /* This is the per-card data structure containing address, irq, number of
@@ -818,7 +846,7 @@
 static void cy_start(struct tty_struct *);
 static void set_line_char(struct cyclades_port *);
 #ifndef CONFIG_COBALT_27
-static void cy_probe(int, void *, struct pt_regs *);
+static unsigned detect_isa_irq (volatile ucchar *);
 #endif /* CONFIG_COBALT_27 */
 #ifdef CYCLOM_SHOW_STATUS
 static void show_status(int);
@@ -963,226 +991,79 @@
    command to the Cirrus chip to complete and then issues the
    new command.  An error is returned if the previous command
    didn't finish within the time limit.
+
+   This function is only called from inside spinlock-protected code.
  */
 static int
 cyy_issue_cmd(volatile ucchar *base_addr, u_char cmd, int index)
 {
-  unsigned long flags;
   volatile int  i;
 
-    save_flags(flags); cli();
-        /* Check to see that the previous command has completed */
-        for(i = 0 ; i < 100 ; i++){
-            if (cy_readb(base_addr+(CyCCR<<index)) == 0){
-                break;
-            }
-            udelay(10L);
-        }
-        /* if the CCR never cleared, the previous command
-            didn't finish within the "reasonable time" */
-        if ( i == 100 ) {
-            restore_flags(flags);
-            return (-1);
-        }
+    /* Check to see that the previous command has completed */
+    for(i = 0 ; i < 100 ; i++){
+	if (cy_readb(base_addr+(CyCCR<<index)) == 0){
+	    break;
+	}
+	udelay(10L);
+    }
+    /* if the CCR never cleared, the previous command
+       didn't finish within the "reasonable time" */
+    if (i == 100)	return (-1);
+
+    /* Issue the new command */
+    cy_writeb((u_long)base_addr+(CyCCR<<index), cmd);
 
-        /* Issue the new command */
-        cy_writeb((u_long)base_addr+(CyCCR<<index), cmd);
-    restore_flags(flags);
     return(0);
 } /* cyy_issue_cmd */
 
 #ifndef CONFIG_COBALT_27	/* ISA interrupt detection code */
-
-static int probe_ready;
-
-/*
- * Grab all interrupts in preparation for doing an automatic irq
- * detection.  dontgrab is a mask of irq's _not_ to grab.  Returns a
- * mask of irq's which were grabbed and should therefore be freed
- * using free_all_interrupts().
- */
-static int
-grab_all_interrupts(int dontgrab)
+static unsigned detect_isa_irq (volatile ucchar *address)
 {
-  int irq_lines = 0;
-  int i, mask;
-    
-    for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
-        if (!(mask & dontgrab)
-        && !request_irq(i, cy_probe,
-	             SA_INTERRUPT, "serial probe", NULL)) {
-            irq_lines |= mask;
-        }
-    }
-    return irq_lines;
-} /* grab_all_interrupts */
+  int irq;
+  unsigned long irqs, flags;
+  int save_xir, save_car;
+  int index = 0; /* IRQ probing is only for ISA */
 
-/*
- * Release all interrupts grabbed by grab_all_interrupts
- */
-static void
-free_all_interrupts(int irq_lines)
-{
-  int i;
-    
-    for (i = 0; i < 16; i++) {
-        if (irq_lines & (1 << i)) {
-            free_irq(i,NULL);
-	}
-    }
-} /* free_all_interrupts */
+    /* forget possible initially masked and pending IRQ */
+    irq = probe_irq_off(probe_irq_on());
 
-/*
- * This routine returns a bitfield of "wild interrupts".  Basically,
- * any unclaimed interrupts which is flapping around.
- */
-static int
-check_wild_interrupts(void)
-{
-  int   i, mask;
-  int   wild_interrupts = 0;
-  int   irq_lines;
-  unsigned long timeout;
-  unsigned long flags;
-        
-    /*Turn on interrupts (they may be off) */
-    save_flags(flags); sti();
+    /* Clear interrupts on the board first */
+    cy_writeb((u_long)address + (Cy_ClrIntr<<index), 0);
+			      /* Cy_ClrIntr is 0x1800 */
 
-        irq_lines = grab_all_interrupts(0);
-       
-        /*
-         * Delay for 0.1 seconds -- we use a busy loop since this may 
-         * occur during the bootup sequence
-         */
-        timeout = jiffies+(HZ/10);
-        while (time_after_eq(timeout, jiffies))
-            ;
-        
-        cy_triggered = 0;       /* Reset after letting things settle */
+    irqs = probe_irq_on();
+    /* Wait ... */
+    udelay(5000L);
 
-        timeout = jiffies+(HZ/10);
-        while (time_after_eq(timeout, jiffies))
-                ;
-        
-        for (i = 0, mask = 1; i < 16; i++, mask <<= 1) {
-            if ((cy_triggered & (1 << i)) &&
-                (irq_lines & (1 << i))) {
-                    wild_interrupts |= mask;
-            }
-        }
-        free_all_interrupts(irq_lines);
-    restore_flags(flags);
-    return wild_interrupts;
-} /* check_wild_interrupts */
-
-/*
- * This routine is called by do_auto_irq(); it attempts to determine
- * which interrupt a serial port is configured to use.  It is not
- * fool-proof, but it works a large part of the time.
- */
-static int
-get_auto_irq(volatile ucchar *address)
-{
-  unsigned long   	timeout;
-  volatile ucchar 	*base_addr;
-  int           	index;
-  unsigned long		flags;
-
-    index = 0;  /* IRQ probing is only for ISA */
-    base_addr = address;
-    intr_base_addr = address;
-        
-    /*
-     * Enable interrupts and see who answers
-     */
-    cy_irq_triggered = 0;
+    /* Enable the Tx interrupts on the CD1400 */
     save_flags(flags); cli();
-        cy_writeb((u_long)base_addr+(CyCAR<<index), 0);
-        cyy_issue_cmd(base_addr,CyCHAN_CTL|CyENB_XMTR,index);
-        cy_writeb((u_long)base_addr+(CySRER<<index), 
-             cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
-        probe_ready = 1;
-    restore_flags(flags);
-    
-    timeout = jiffies+(HZ/50);
-    while (time_after_eq(timeout, jiffies)) {
-        if (cy_irq_triggered)
-            break;
-    }
-    probe_ready = 0;
-    return(cy_irq_triggered);
-} /* get_auto_irq */
+	cy_writeb((u_long)address + (CyCAR<<index), 0);
+	cyy_issue_cmd(address, CyCHAN_CTL|CyENB_XMTR, index);
 
-/*
- * Calls get_auto_irq() multiple times, to make sure we don't get
- * faked out by random interrupts
- */
-static int
-do_auto_irq(volatile ucchar *address)
-{
-  int                   irq_lines = 0;
-  int                   irq_try_1 = 0, irq_try_2 = 0;
-  int                   retries;
-  unsigned long		flags;
-
-    /* Turn on interrupts (they may be off) */
-    save_flags(flags); sti();
-
-        probe_ready = 0;
-
-        cy_wild_int_mask = check_wild_interrupts();
-
-        irq_lines = grab_all_interrupts(cy_wild_int_mask);
-        
-        for (retries = 0; retries < 5; retries++) {
-            if (!irq_try_1)
-                irq_try_1 = get_auto_irq(address);
-            if (!irq_try_2)
-                irq_try_2 = get_auto_irq(address);
-            if (irq_try_1 && irq_try_2) {
-                if (irq_try_1 == irq_try_2)
-                    break;
-                irq_try_1 = irq_try_2 = 0;
-            }
-        }
+	cy_writeb((u_long)address + (CyCAR<<index), 0);
+	cy_writeb((u_long)address + (CySRER<<index), 
+		cy_readb(address + (CySRER<<index)) | CyTxMpty);
     restore_flags(flags);
-    free_all_interrupts(irq_lines);
-    return (irq_try_1 == irq_try_2) ? irq_try_1 : 0;
-} /* do_auto_irq */
 
+    /* Wait ... */
+    udelay(5000L);
 
-/*
- * This interrupt routine is used
- * while we are probing for submarines.
- */
-static void
-cy_probe(int irq, void *dev_id, struct pt_regs *regs)
-{
-  int save_xir, save_car;
-  int index = 0;        /* probing interrupts is only for ISA */
-
-    if (!probe_ready) {
-        cy_writeb((u_long)intr_base_addr+(Cy_ClrIntr<<index), 0);
-        return;
-    }
-
-    cy_irq_triggered = irq;
-    cy_triggered |= 1 << irq;
+    /* Check which interrupt is in use */
+    irq = probe_irq_off(irqs);
 
-        if(cy_readb(intr_base_addr+(CySVRR<<index)) != 0) {
-            save_xir = (u_char) cy_readb(intr_base_addr+(CyTIR<<index));
-            save_car = cy_readb(intr_base_addr+(CyCAR<<index));
-            cy_writeb((u_long)intr_base_addr+(CyCAR<<index), (save_xir & 0x3));
-            cy_writeb((u_long)intr_base_addr+(CySRER<<index),
-                cy_readb(intr_base_addr+(CySRER<<index)) & ~CyTxMpty);
-            cy_writeb((u_long)intr_base_addr+(CyTIR<<index), (save_xir & 0x3f));
-            cy_writeb((u_long)intr_base_addr+(CyCAR<<index), (save_car));
-        }
-        cy_writeb((u_long)intr_base_addr+(Cy_ClrIntr<<index), 0);
-	                          /* Cy_ClrIntr is 0x1800 */
-    return;
-} /* cy_probe */
+    /* Clean up */
+    save_xir = (u_char) cy_readb(address + (CyTIR<<index));
+    save_car = cy_readb(address + (CyCAR<<index));
+    cy_writeb((u_long)address + (CyCAR<<index), (save_xir & 0x3));
+    cy_writeb((u_long)address + (CySRER<<index),
+	cy_readb(address + (CySRER<<index)) & ~CyTxMpty);
+    cy_writeb((u_long)address + (CyTIR<<index), (save_xir & 0x3f));
+    cy_writeb((u_long)address + (CyCAR<<index), (save_car));
+    cy_writeb((u_long)address + (Cy_ClrIntr<<index), 0);
+			      /* Cy_ClrIntr is 0x1800 */
 
+    return (irq > 0)? irq : 0;
+}
 #endif /* CONFIG_COBALT_27 */
 
 /* The real interrupt service routine is called
@@ -1245,6 +1126,7 @@
 		    printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
 #endif
                     /* determine the channel & change to that context */
+		    spin_lock(&cinfo->card_lock);
                     save_xir = (u_char) cy_readb(base_addr+(CyRIR<<index));
                     channel = (u_short ) (save_xir & CyIRChannel);
                     i = channel + chip * 4 + cinfo->first_line;
@@ -1252,6 +1134,7 @@
                     info->last_active = jiffies;
                     save_car = cy_readb(base_addr+(CyCAR<<index));
                     cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir);
+		    spin_unlock(&cinfo->card_lock);
 
                     /* if there is nowhere to put the data, discard it */
                     if(info->tty == 0){
@@ -1359,8 +1242,10 @@
                         queue_task(&tty->flip.tqueue, &tq_timer);
                     }
                     /* end of service */
+		    spin_lock(&cinfo->card_lock);
                     cy_writeb((u_long)base_addr+(CyRIR<<index), (save_xir & 0x3f));
                     cy_writeb((u_long)base_addr+(CyCAR<<index), (save_car));
+		    spin_unlock(&cinfo->card_lock);
                 }
 
 
@@ -1373,23 +1258,29 @@
 #endif
 
                     /* determine the channel & change to that context */
+		    spin_lock(&cinfo->card_lock);
                     save_xir = (u_char) cy_readb(base_addr+(CyTIR<<index));
                     channel = (u_short ) (save_xir & CyIRChannel);
                     i = channel + chip * 4 + cinfo->first_line;
                     save_car = cy_readb(base_addr+(CyCAR<<index));
                     cy_writeb((u_long)base_addr+(CyCAR<<index), save_xir);
+		    spin_unlock(&cinfo->card_lock);
 
                     /* validate the port# (as configured and open) */
                     if( (i < 0) || (NR_PORTS <= i) ){
+			spin_lock(&cinfo->card_lock);
                         cy_writeb((u_long)base_addr+(CySRER<<index),
                              cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+			spin_unlock(&cinfo->card_lock);
                         goto txend;
                     }
                     info = &cy_port[i];
                     info->last_active = jiffies;
                     if(info->tty == 0){
+			spin_lock(&cinfo->card_lock);
                         cy_writeb((u_long)base_addr+(CySRER<<index),
                              cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
+			spin_unlock(&cinfo->card_lock);
                         goto txdone;
                     }
 
@@ -1421,21 +1312,27 @@
 
                     while (char_count-- > 0){
 			if (!info->xmit_cnt){
+			    spin_lock(&cinfo->card_lock);
                             cy_writeb((u_long)base_addr+(CySRER<<index),
 				cy_readb(base_addr+(CySRER<<index)) & 
 					~CyTxMpty);
+			    spin_unlock(&cinfo->card_lock);
 			    goto txdone;
 			}
 			if (info->xmit_buf == 0){
+			    spin_lock(&cinfo->card_lock);
                             cy_writeb((u_long)base_addr+(CySRER<<index),
 				cy_readb(base_addr+(CySRER<<index)) & 
 					~CyTxMpty);
+			    spin_unlock(&cinfo->card_lock);
                             goto txdone;
 			}
 			if (info->tty->stopped || info->tty->hw_stopped){
+			    spin_lock(&cinfo->card_lock);
                             cy_writeb((u_long)base_addr+(CySRER<<index),
 				cy_readb(base_addr+(CySRER<<index)) & 
 					~CyTxMpty);
+			    spin_unlock(&cinfo->card_lock);
                             goto txdone;
 			}
                         /* Because the Embedded Transmit Commands have
@@ -1475,14 +1372,17 @@
                     }
         txend:
                     /* end of service */
+		    spin_lock(&cinfo->card_lock);
                     cy_writeb((u_long)base_addr+(CyTIR<<index), 
 			      (save_xir & 0x3f));
                     cy_writeb((u_long)base_addr+(CyCAR<<index), (save_car));
+		    spin_unlock(&cinfo->card_lock);
                 }
 
                 if (status & CySRModem) {        /* modem interrupt */
 
                     /* determine the channel & change to that context */
+		    spin_lock(&cinfo->card_lock);
                     save_xir = (u_char) cy_readb(base_addr+(CyMIR<<index));
                     channel = (u_short ) (save_xir & CyIRChannel);
                     info = &cy_port[channel + chip * 4
@@ -1493,6 +1393,7 @@
 
                     mdm_change = cy_readb(base_addr+(CyMISR<<index));
                     mdm_status = cy_readb(base_addr+(CyMSVR1<<index));
+		    spin_unlock(&cinfo->card_lock);
 
                     if(info->tty == 0){/* no place for data, ignore it*/
                         ;
@@ -1517,9 +1418,11 @@
                                     /* cy_start isn't used
 				         because... !!! */
                                     info->tty->hw_stopped = 0;
+				  spin_lock(&cinfo->card_lock);
                                   cy_writeb((u_long)base_addr+(CySRER<<index),
                                        cy_readb(base_addr+(CySRER<<index)) | 
                                        CyTxMpty);
+				  spin_unlock(&cinfo->card_lock);
                                     cy_sched_event(info,
 				        Cy_EVENT_WRITE_WAKEUP);
                                 }
@@ -1528,9 +1431,11 @@
                                     /* cy_stop isn't used
 				         because ... !!! */
                                     info->tty->hw_stopped = 1;
+				  spin_lock(&cinfo->card_lock);
                                   cy_writeb((u_long)base_addr+(CySRER<<index),
                                        cy_readb(base_addr+(CySRER<<index)) & 
                                        ~CyTxMpty);
+				  spin_unlock(&cinfo->card_lock);
                                 }
                             }
                         }
@@ -1540,17 +1445,21 @@
                         }
                     }
                     /* end of service */
+		    spin_lock(&cinfo->card_lock);
                     cy_writeb((u_long)base_addr+(CyMIR<<index), 
 			      (save_xir & 0x3f));
                     cy_writeb((u_long)base_addr+(CyCAR<<index), save_car);
+		    spin_unlock(&cinfo->card_lock);
                 }
             }          /* end while status != 0 */
         }            /* end loop for chips... */
     } while(had_work);
 
    /* clear interrupts */
+   spin_lock(&cinfo->card_lock);
    cy_writeb((u_long)card_base_addr + (Cy_ClrIntr<<index), 0);
                                 /* Cy_ClrIntr is 0x1800 */
+   spin_unlock(&cinfo->card_lock);
 } /* cyy_interrupt */
 
 /***********************************************************/
@@ -1624,31 +1533,6 @@
     return(0);
 } /* cyz_issue_cmd */
 
-
-#if 0
-static int
-cyz_update_channel( struct cyclades_card *cinfo,
-	    u_long channel, u_char mode, u_char cmd)
-{ 
-  struct FIRM_ID *firm_id =
-      (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS);
-  struct ZFW_CTRL *zfw_ctrl;
-  struct CH_CTRL *ch_ctrl;
-
-    if (!ISZLOADED(*cinfo)){
-	return (-1);
-    }
-    zfw_ctrl = (struct ZFW_CTRL *)
-	       (cinfo->base_addr + cy_readl(&firm_id->zfwctrl_addr));
-    ch_ctrl = zfw_ctrl->ch_ctrl;
-
-    cy_writel(&ch_ctrl[channel].op_mode, (uclong)mode);
-
-    return cyz_issue_cmd(cinfo, channel, cmd, 0L);
-
-} /* cyz_update_channel */
-#endif
-
 #ifdef CONFIG_CYZ_INTR
 static void
 cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -2225,11 +2109,14 @@
   int card,chip,channel,index;
   unsigned long page;
 
+    card = info->card;
+    channel = (info->line) - (cy_card[card].first_line);
+
     page = get_free_page(GFP_KERNEL);
     if (!page)
 	return -ENOMEM;
 
-    save_flags(flags); cli();
+    CY_LOCK(info, flags);
 
     if (info->flags & ASYNC_INITIALIZED){
 	free_page(page);
@@ -2249,10 +2136,10 @@
     else
 	info->xmit_buf = (unsigned char *) page;
 
+    CY_UNLOCK(info, flags);
+
     set_line_char(info);
 
-    card = info->card;
-    channel = (info->line) - (cy_card[card].first_line);
     if (!IS_CYC_Z(cy_card[card])) {
 	chip = channel>>2;
 	channel &= 0x03;
@@ -2265,6 +2152,8 @@
 	     card, chip, channel, (long)base_addr);/**/
 #endif
 
+	CY_LOCK(info, flags);
+
 	cy_writeb((ulong)base_addr+(CyCAR<<index), (u_char)channel);
 
 	cy_writeb((ulong)base_addr+(CyRTPR<<index), (info->default_timeout
@@ -2297,7 +2186,7 @@
 	info->idle_stats.recv_idle =
 	info->idle_stats.xmit_idle = jiffies;
 
-	restore_flags(flags);
+	CY_UNLOCK(info, flags);
 
     } else {
       struct FIRM_ID *firm_id;
@@ -2306,8 +2195,6 @@
       struct CH_CTRL *ch_ctrl;
       int retval;
 
-	restore_flags(flags);
-
 	base_addr = (unsigned char*) (cy_card[card].base_addr);
 
         firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS);
@@ -2326,6 +2213,8 @@
 	     card, channel, (long)base_addr);/**/
 #endif
 
+	CY_LOCK(info, flags);
+
 	cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
 #ifdef Z_WAKE
 #ifdef CONFIG_CYZ_INTR
@@ -2380,6 +2269,8 @@
 	info->idle_stats.in_use    =
 	info->idle_stats.recv_idle =
 	info->idle_stats.xmit_idle = jiffies;
+
+	CY_UNLOCK(info, flags);
     }
 
 #ifdef CY_DEBUG_OPEN
@@ -2388,7 +2279,7 @@
 	return 0;
 
 errout:
-	restore_flags(flags);
+	CY_UNLOCK(info, flags);
 	return retval;
 } /* startup */
 
@@ -2410,21 +2301,21 @@
 		       (cy_card[card].base_addr
 		       + (cy_chip_offset[chip]<<index));
 
-	save_flags(flags); cli();
+	CY_LOCK(info, flags);
 	    cy_writeb((u_long)base_addr+(CyCAR<<index), channel);
 	    cy_writeb((u_long)base_addr+(CySRER<<index), 
                cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
-	restore_flags(flags);
+	CY_UNLOCK(info, flags);
     } else {
 #ifdef CONFIG_CYZ_INTR
       int retval;
 
-	save_flags(flags); cli();
+	CY_LOCK(info, flags);
 	    retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK, 0L);
 	    if (retval != 0){
 		printk("cyc:start_xmit retval was %x\n", retval);
 	    }
-	restore_flags(flags);
+	CY_UNLOCK(info, flags);
 #else /* CONFIG_CYZ_INTR */
 	/* Don't have to do anything at this time */
 #endif /* CONFIG_CYZ_INTR */
@@ -2461,7 +2352,7 @@
 		card, chip, channel, (long)base_addr);
 #endif
 
-	save_flags(flags); cli();
+	CY_LOCK(info, flags);
 
 	    if (info->xmit_buf){
 		unsigned char * temp;
@@ -2488,7 +2379,7 @@
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
 	    }
 	    info->flags &= ~ASYNC_INITIALIZED;
-	restore_flags(flags);
+	CY_UNLOCK(info, flags);
     } else {
       struct FIRM_ID *firm_id;
       struct ZFW_CTRL *zfw_ctrl;
@@ -2513,7 +2404,7 @@
 	board_ctrl = &(zfw_ctrl->board_ctrl);
 	ch_ctrl = zfw_ctrl->ch_ctrl;
 
-	save_flags(flags); cli();
+	CY_LOCK(info, flags);
 
 	    if (info->xmit_buf){
 		unsigned char * temp;
@@ -2541,7 +2432,7 @@
 	    }
 	    info->flags &= ~ASYNC_INITIALIZED;
 
-	restore_flags(flags);
+	CY_UNLOCK(info, flags);
     }
 
 #ifdef CY_DEBUG_OPEN
@@ -2568,6 +2459,9 @@
   int retval;
   char *base_addr;
 
+    cinfo = &cy_card[info->card];
+    channel = info->line - cinfo->first_line;
+
     /*
      * If the device is in the middle of being closed, then block
      * until it's done, and then try again.
@@ -2627,18 +2521,16 @@
     printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
            info->line, info->count);/**/
 #endif
-    save_flags(flags); cli();
+    CY_LOCK(info, flags);
     if (!tty_hung_up_p(filp))
 	info->count--;
-    restore_flags(flags);
+    CY_UNLOCK(info, flags);
 #ifdef CY_DEBUG_COUNT
     printk("cyc block_til_ready: (%d): decrementing count to %d\n",
         current->pid, info->count);
 #endif
     info->blocked_open++;
 
-    cinfo = &cy_card[info->card];
-    channel = info->line - cinfo->first_line;
     if (!IS_CYC_Z(*cinfo)) {
 	chip = channel>>2;
 	channel &= 0x03;
@@ -2647,7 +2539,7 @@
 			    + (cy_chip_offset[chip]<<index));
 
 	while (1) {
-	    save_flags(flags); cli();
+	    CY_LOCK(info, flags);
 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
 		    (tty->termios->c_cflag & CBAUD)){
 		    cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
@@ -2660,7 +2552,8 @@
                         cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
 		}
-	    restore_flags(flags);
+	    CY_UNLOCK(info, flags);
+
 	    current->state = TASK_INTERRUPTIBLE;
 	    if (tty_hung_up_p(filp)
 	    || !(info->flags & ASYNC_INITIALIZED) ){
@@ -2668,16 +2561,18 @@
 		    -EAGAIN : -ERESTARTSYS);
 		break;
 	    }
-	    save_flags(flags); cli();
+
+	    CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
 		if (!(info->flags & ASYNC_CALLOUT_ACTIVE)
 		&& !(info->flags & ASYNC_CLOSING)
 		&& (C_CLOCAL(tty)
 		    || (cy_readb(base_addr+(CyMSVR1<<index)) & CyDCD))) {
-			restore_flags(flags);
+			CY_UNLOCK(info, flags);
 			break;
 		}
-	    restore_flags(flags);
+	    CY_UNLOCK(info, flags);
+
 	    if (signal_pending(current)) {
 		retval = -ERESTARTSYS;
 		break;
@@ -2956,6 +2851,7 @@
 	    printk("Not clean (jiff=%lu)...", jiffies);
 #endif
 	    current->state = TASK_INTERRUPTIBLE;
+	    current->counter = 0;	/* make us low-priority */
 	    schedule_timeout(char_time);
 	    if (signal_pending(current))
 		break;
@@ -2968,6 +2864,7 @@
     }
     /* Run one more char cycle */
     current->state = TASK_INTERRUPTIBLE;
+    current->counter = 0;	/* make us low-priority */
     schedule_timeout(char_time * 5);
     current->state = TASK_RUNNING;
 #ifdef CY_DEBUG_WAIT_UNTIL_SENT
@@ -2992,12 +2889,11 @@
         return;
     }
 
-    save_flags(flags); cli();
-
+    CY_LOCK(info, flags);
     /* If the TTY is being hung up, nothing to do */
     if (tty_hung_up_p(filp)) {
 	MOD_DEC_USE_COUNT;
-        restore_flags(flags);
+	CY_UNLOCK(info, flags);
         return;
     }
         
@@ -3028,7 +2924,7 @@
     }
     if (info->count) {
 	MOD_DEC_USE_COUNT;
-        restore_flags(flags);
+	CY_UNLOCK(info, flags);
         return;
     }
     info->flags |= ASYNC_CLOSING;
@@ -3046,9 +2942,11 @@
     * the line discipline to only process XON/XOFF characters.
     */
     tty->closing = 1;
+    CY_UNLOCK(info, flags);
     if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
 	tty_wait_until_sent(tty, info->closing_wait);
     }
+    CY_LOCK(info, flags);
 
     if (!IS_CYC_Z(cy_card[info->card])) {
 	int channel = info->line - cy_card[info->card].first_line;
@@ -3064,7 +2962,9 @@
 	if (info->flags & ASYNC_INITIALIZED) {
 	    /* Waiting for on-board buffers to be empty before closing 
 	       the port */
+	    CY_UNLOCK(info, flags);
 	    cy_wait_until_sent(tty, info->timeout);
+	    CY_LOCK(info, flags);
 	}
     } else {
 #ifdef Z_WAKE
@@ -3084,16 +2984,21 @@
 	    if (retval != 0){
 		printk("cyc:shutdown retval (1) was %x\n", retval);
 	    }
+	    CY_UNLOCK(info, flags);
 	    interruptible_sleep_on(&info->shutdown_wait);
+	    CY_LOCK(info, flags);
 	}
 #endif
     }
 
+    CY_UNLOCK(info, flags);
     shutdown(info);
     if (tty->driver.flush_buffer)
         tty->driver.flush_buffer(tty);
     if (tty->ldisc.flush_buffer)
         tty->ldisc.flush_buffer(tty);
+    CY_LOCK(info, flags);
+
     tty->closing = 0;
     info->event = 0;
     info->tty = 0;
@@ -3113,7 +3018,7 @@
 #endif
 
     MOD_DEC_USE_COUNT;
-    restore_flags(flags);
+    CY_UNLOCK(info, flags);
     return;
 } /* cy_close */
 
@@ -3151,8 +3056,7 @@
         return 0;
     }
 
-    save_flags(flags);               
-
+    CY_LOCK(info, flags);
     if (from_user) {
 	down(&tmp_buf_sem);
 	while (1) {
@@ -3168,13 +3072,11 @@
 		}
 		break;
 	    }
-	    cli();               
 	    c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 			SERIAL_XMIT_SIZE - info->xmit_head));
 	    memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
 	    info->xmit_head = ((info->xmit_head + c) & (SERIAL_XMIT_SIZE-1));
 	    info->xmit_cnt += c;
-	    restore_flags(flags);
 	    buf += c;
 	    count -= c;
 	    ret += c;
@@ -3182,22 +3084,20 @@
 	up(&tmp_buf_sem);
     } else {
 	while (1) {
-	    cli();
 	    c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, 
 			SERIAL_XMIT_SIZE - info->xmit_head));
 	    if (c <= 0) {
-		restore_flags(flags);
 		break;
 	    }
 	    memcpy(info->xmit_buf + info->xmit_head, buf, c);
 	    info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
 	    info->xmit_cnt += c;
-	    restore_flags(flags);
 	    buf += c;
 	    count -= c;
 	    ret += c;
 	}
     }
+    CY_UNLOCK(info, flags);
 
     info->idle_stats.xmit_bytes += ret;
     info->idle_stats.xmit_idle   = jiffies;
@@ -3232,9 +3132,9 @@
     if (!tty || !info->xmit_buf)
         return;
 
-    save_flags(flags); cli();
+    CY_LOCK(info, flags);
         if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
-            restore_flags(flags);
+	    CY_UNLOCK(info, flags);
             return;
         }
 
@@ -3243,7 +3143,7 @@
         info->xmit_cnt++;
 	info->idle_stats.xmit_bytes++;
 	info->idle_stats.xmit_idle = jiffies;
-    restore_flags(flags);
+    CY_UNLOCK(info, flags);
 } /* cy_put_char */
 
 
@@ -3255,9 +3155,6 @@
 cy_flush_chars(struct tty_struct *tty)
 {
   struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
-  unsigned long flags;
-  unsigned char *base_addr;
-  int card,chip,channel,index;
                                 
 #ifdef CY_DEBUG_IO
     printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
@@ -3270,25 +3167,7 @@
     || tty->hw_stopped || !info->xmit_buf)
         return;
 
-    card = info->card;
-    channel = info->line - cy_card[card].first_line;
-    if (!IS_CYC_Z(cy_card[card])) {
-	chip = channel>>2;
-	channel &= 0x03;
-	index = cy_card[card].bus_index;
-	base_addr = (unsigned char*)
-		       (cy_card[card].base_addr
-		       + (cy_chip_offset[chip]<<index));
-
-	save_flags(flags); cli();
-	    cy_writeb((u_long)base_addr+(CyCAR<<index), channel);
-	    cy_writeb((u_long)base_addr+(CySRER<<index),
-               cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
-	restore_flags(flags);
-    } else {
-	/* Since polling is already in place,
-	    nothing further need be done.  */
-    }
+    start_xmit(info);
 } /* cy_flush_chars */
 
 
@@ -3509,7 +3388,7 @@
 		       (cy_card[card].base_addr
 		       + (cy_chip_offset[chip]<<index));
 
-	save_flags(flags); cli();
+	CY_LOCK(info, flags);
 	    cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
 
 	   /* tx and rx baud rate */
@@ -3599,8 +3478,8 @@
 	    if (info->tty){
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
 	    }
+	CY_UNLOCK(info, flags);
 
-	restore_flags(flags);
     } else {
       struct FIRM_ID *firm_id;
       struct ZFW_CTRL *zfw_ctrl;
@@ -3623,8 +3502,8 @@
 
 	/* baud rate */
 	baud = tty_get_baud_rate(info->tty);
-	if (baud > CD1400_MAX_SPEED) {
-	    baud = CD1400_MAX_SPEED;
+	if (baud > CYZ_MAX_SPEED) {
+	    baud = CYZ_MAX_SPEED;
 	}
 	cy_writel(&ch_ctrl->comm_baud , baud);
 
@@ -3829,12 +3708,11 @@
 		       (cy_card[card].base_addr
 		       + (cy_chip_offset[chip]<<index));
 
-	save_flags(flags); cli();
+	CY_LOCK(info, flags);
 	    cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
 	    status = cy_readb(base_addr+(CyMSVR1<<index));
 	    status |= cy_readb(base_addr+(CyMSVR2<<index));
-	restore_flags(flags);
-
+	CY_UNLOCK(info, flags);
 
         if (info->rtsdtr_inv) {
 	    result =  ((status  & CyRTS) ? TIOCM_DTR : 0)
@@ -3905,17 +3783,17 @@
 	switch (cmd) {
 	case TIOCMBIS:
 	    if (arg & TIOCM_RTS){
-		save_flags(flags); cli();
+		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
 		    cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
                 } else {
 		    cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
                 }
-		restore_flags(flags);
+		CY_UNLOCK(info, flags);
 	    }
 	    if (arg & TIOCM_DTR){
-		save_flags(flags); cli();
+		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
 		    cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
@@ -3928,12 +3806,12 @@
 		    cy_readb(base_addr+(CyMSVR1<<index)), 
                     cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
-		restore_flags(flags);
+		CY_UNLOCK(info, flags);
 	    }
 	    break;
 	case TIOCMBIC:
 	    if (arg & TIOCM_RTS){
-		save_flags(flags); cli();
+		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), 
                           (u_char)channel);
                 if (info->rtsdtr_inv) {
@@ -3941,10 +3819,10 @@
                 } else {
 		    	cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
                 }
-		restore_flags(flags);
+		CY_UNLOCK(info, flags);
 	    }
 	    if (arg & TIOCM_DTR){
-		save_flags(flags); cli();
+		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
 			cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
@@ -3957,31 +3835,31 @@
 		    cy_readb(base_addr+(CyMSVR1<<index)), 
                     cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
-		restore_flags(flags);
+		CY_UNLOCK(info, flags);
 	    }
 	    break;
 	case TIOCMSET:
 	    if (arg & TIOCM_RTS){
-		save_flags(flags); cli();
+		CY_LOCK(info, flags);
 	        cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
 			cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
                 } else {
 			cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
                 }
-		restore_flags(flags);
+		CY_UNLOCK(info, flags);
 	    }else{
-		save_flags(flags); cli();
+		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
 			cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
                 } else {
 			cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
                 }
-		restore_flags(flags);
+		CY_UNLOCK(info, flags);
 	    }
 	    if (arg & TIOCM_DTR){
-		save_flags(flags); cli();
+		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
 			cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
@@ -3994,9 +3872,9 @@
 		    cy_readb(base_addr+(CyMSVR1<<index)), 
                     cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
-		restore_flags(flags);
+		CY_UNLOCK(info, flags);
 	    }else{
-		save_flags(flags); cli();
+		CY_LOCK(info, flags);
 		cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
                 if (info->rtsdtr_inv) {
 			cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
@@ -4010,7 +3888,7 @@
 		    cy_readb(base_addr+(CyMSVR1<<index)), 
                     cy_readb(base_addr+(CyMSVR2<<index)));
 #endif
-		restore_flags(flags);
+		CY_UNLOCK(info, flags);
 	    }
 	    break;
 	default:
@@ -4030,50 +3908,66 @@
 	    switch (cmd) {
 	    case TIOCMBIS:
 		if (arg & TIOCM_RTS){
+		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
+		    CY_UNLOCK(info, flags);
 		}
 		if (arg & TIOCM_DTR){
+		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
 #ifdef CY_DEBUG_DTR
 		    printk("cyc:set_modem_info raising Z DTR\n");
 #endif
+		    CY_UNLOCK(info, flags);
 		}
 		break;
 	    case TIOCMBIC:
 		if (arg & TIOCM_RTS){
+		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
+		    CY_UNLOCK(info, flags);
 		}
 		if (arg & TIOCM_DTR){
+		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
 #ifdef CY_DEBUG_DTR
 		    printk("cyc:set_modem_info clearing Z DTR\n");
 #endif
+		    CY_UNLOCK(info, flags);
 		}
 		break;
 	    case TIOCMSET:
 		if (arg & TIOCM_RTS){
+		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS);
+		    CY_UNLOCK(info, flags);
 		}else{
+		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_RTS);
+		    CY_UNLOCK(info, flags);
 		}
 		if (arg & TIOCM_DTR){
+		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) | C_RS_DTR);
 #ifdef CY_DEBUG_DTR
 		    printk("cyc:set_modem_info raising Z DTR\n");
 #endif
+		    CY_UNLOCK(info, flags);
 		}else{
+		    CY_LOCK(info, flags);
 		    cy_writel(&ch_ctrl[channel].rs_control,
                        cy_readl(&ch_ctrl[channel].rs_control) & ~C_RS_DTR);
 #ifdef CY_DEBUG_DTR
 		    printk("cyc:set_modem_info clearing Z DTR\n");
 #endif
+		    CY_UNLOCK(info, flags);
 		}
 		break;
 	    default:
@@ -4082,12 +3976,14 @@
 	}else{
 	    return -ENODEV;
 	}
+	CY_LOCK(info, flags);
         retval = cyz_issue_cmd(&cy_card[info->card],
 				    channel, C_CM_IOCTLM,0L);
 	if (retval != 0){
 	    printk("cyc:set_modem_info retval at %d was %x\n",
 	        __LINE__, retval);
 	}
+	CY_UNLOCK(info, flags);
     }
     return 0;
 } /* set_modem_info */
@@ -4104,7 +4000,7 @@
     if (serial_paranoia_check(info, tty->device, "cy_break"))
 	return;
 
-    save_flags(flags); cli();
+    CY_LOCK(info, flags);
     if (!IS_CYC_Z(cy_card[info->card])) {
         /* Let the transmit ISR take care of this (since it
 	   requires stuffing characters into the output stream).
@@ -4113,14 +4009,18 @@
 	    if (!info->breakon) {
 		info->breakon = 1;
 		if (!info->xmit_cnt) {
+		    CY_UNLOCK(info, flags);
 		    start_xmit(info);
+		    CY_LOCK(info, flags);
 		}
 	    }
 	} else {
 	    if (!info->breakoff) {
 		info->breakoff = 1;
 		if (!info->xmit_cnt) {
+		    CY_UNLOCK(info, flags);
 		    start_xmit(info);
+		    CY_LOCK(info, flags);
 		}
 	    }
 	}
@@ -4145,8 +4045,7 @@
 	    }
 	}
     }
-    restore_flags(flags);
-
+    CY_UNLOCK(info, flags);
 } /* cy_break */
 
 static int
@@ -4168,6 +4067,7 @@
 {
   unsigned char *base_addr;
   int card,channel,chip,index;
+  unsigned long flags;
    
     card = info->card;
     channel = info->line - cy_card[card].first_line;
@@ -4181,8 +4081,11 @@
 
 	info->cor3 &= ~CyREC_FIFO;
 	info->cor3 |= value & CyREC_FIFO;
-	cy_writeb((u_long)base_addr+(CyCOR3<<index), info->cor3);
-	cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
+
+	CY_LOCK(info, flags);
+	    cy_writeb((u_long)base_addr+(CyCOR3<<index), info->cor3);
+	    cyy_issue_cmd(base_addr,CyCOR_CHANGE|CyCOR3ch,index);
+	CY_UNLOCK(info, flags);
     } else {
 	// Nothing to do!
     }
@@ -4236,6 +4139,7 @@
 {
   unsigned char *base_addr;
   int card,channel,chip,index;
+  unsigned long flags;
    
     card = info->card;
     channel = info->line - cy_card[card].first_line;
@@ -4247,7 +4151,9 @@
 		       (cy_card[card].base_addr
 		       + (cy_chip_offset[chip]<<index));
 
-	cy_writeb((u_long)base_addr+(CyRTPR<<index), value & 0xff);
+	CY_LOCK(info, flags);
+	    cy_writeb((u_long)base_addr+(CyRTPR<<index), value & 0xff);
+	CY_UNLOCK(info, flags);
     } else {
 	// Nothing to do!
     }
@@ -4424,7 +4330,8 @@
     printk("cyc:cy_set_termios ttyC%d\n", info->line);
 #endif
 
-    if (tty->termios->c_cflag == old_termios->c_cflag)
+    if ((tty->termios->c_cflag == old_termios->c_cflag) &&
+	((tty->termios->c_iflag & IXON) == (old_termios->c_iflag & IXON)))
         return;
     set_line_char(info);
 
@@ -4487,14 +4394,14 @@
 		       (cy_card[card].base_addr
 		       + (cy_chip_offset[chip]<<index));
 
-	save_flags(flags); cli();
+	CY_LOCK(info, flags);
 	cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
 	if (info->rtsdtr_inv) {
 		cy_writeb((u_long)base_addr+(CyMSVR2<<index), ~CyDTR);
 	} else {
 		cy_writeb((u_long)base_addr+(CyMSVR1<<index), ~CyRTS);
 	}
-	restore_flags(flags);
+	CY_UNLOCK(info, flags);
     } else {
 	// Nothing to do!
     }
@@ -4546,14 +4453,14 @@
 		       (cy_card[card].base_addr
 		       + (cy_chip_offset[chip]<<index));
 
-	save_flags(flags); cli();
+	CY_LOCK(info, flags);
 	cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel);
 	if (info->rtsdtr_inv) {
 		cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR);
 	} else {
 		cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS);
 	}
-	restore_flags(flags);
+	CY_UNLOCK(info, flags);
     }else{
 	// Nothing to do!
     }
@@ -4591,12 +4498,12 @@
                    (cy_card[info->card].base_addr
                            + (cy_chip_offset[chip]<<index));
 
-        save_flags(flags); cli();
+	CY_LOCK(info, flags);
             cy_writeb((u_long)base_addr+(CyCAR<<index),
 	       (u_char)(channel & 0x0003)); /* index channel */
             cy_writeb((u_long)base_addr+(CySRER<<index), 
                cy_readb(base_addr+(CySRER<<index)) & ~CyTxMpty);
-        restore_flags(flags);
+	CY_UNLOCK(info, flags);
     } else {
 	// Nothing to do!
     }
@@ -4631,12 +4538,12 @@
                        (cy_card[info->card].base_addr
 		       + (cy_chip_offset[chip]<<index));
 
-        save_flags(flags); cli();
+	CY_LOCK(info, flags);
             cy_writeb((u_long)base_addr+(CyCAR<<index),
 	       (u_char)(channel & 0x0003)); /* index channel */
             cy_writeb((u_long)base_addr+(CySRER<<index), 
                cy_readb(base_addr+(CySRER<<index)) | CyTxMpty);
-        restore_flags(flags);
+	CY_UNLOCK(info, flags);
     } else {
 	// Nothing to do!
     }
@@ -4658,19 +4565,22 @@
 
     if (serial_paranoia_check(info, tty->device, "cy_flush_buffer"))
         return;
-    save_flags(flags); cli();
-    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-    restore_flags(flags);
 
     card = info->card;
     channel = (info->line) - (cy_card[card].first_line);
 
+    CY_LOCK(info, flags);
+    info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+    CY_UNLOCK(info, flags);
+
     if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board 
 				      buffers as well */
+	CY_LOCK(info, flags);
 	retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
 	if (retval != 0) {
 	    printk("cyc: flush_buffer retval was %x\n", retval);
 	}
+	CY_UNLOCK(info, flags);
     }
     wake_up_interruptible(&tty->write_wait);
     if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
@@ -4717,8 +4627,8 @@
 
 /* initialize chips on Cyclom-Y card -- return number of valid
    chips (which is number of ports/4) */
-static unsigned short __init 
-cyy_init_card(volatile ucchar *true_base_addr,int index)
+__initfunc(static unsigned short
+cyy_init_card(volatile ucchar *true_base_addr,int index))
 {
   unsigned int chip_number;
   volatile ucchar* base_addr;
@@ -4803,14 +4713,30 @@
  * sets global variables and return the number of ISA boards found.
  * ---------------------------------------------------------------------
  */
-static int __init cy_detect_isa(void)
+__initfunc(static int
+cy_detect_isa(void))
 {
   unsigned short	cy_isa_irq,nboard;
   volatile ucchar	*cy_isa_address;
   unsigned short	i,j,cy_isa_nchan;
+#ifdef MODULE
+  int isparam = 0;
+#endif
 
         nboard = 0;
 
+#ifdef MODULE
+	/* Check for module parameters */
+	for(i = 0 ; i < NR_CARDS; i++) {
+	    if (maddr[i] || i) {
+		isparam = 1;
+		cy_isa_addresses[i] = (ucchar *)maddr[i];
+	    }
+	    if (!maddr[i])
+		break;
+	}
+#endif
+
         /* scan the address table probing for Cyclom-Y/ISA boards */
         for (i = 0 ; i < NR_ISA_ADDRS ; i++) {
                 cy_isa_address = cy_isa_addresses[i];
@@ -4829,8 +4755,13 @@
                         continue;
                 }
 
+#ifdef MODULE
+		if (isparam && irq[i])
+		    cy_isa_irq = irq[i];
+		else
+#endif
                 /* find out the board's irq by probing */
-                cy_isa_irq = do_auto_irq(cy_isa_address);
+                cy_isa_irq = detect_isa_irq(cy_isa_address);
                 if (cy_isa_irq == 0) {
                         printk("Cyclom-Y/ISA found at 0x%lx ",
                                 (unsigned long) cy_isa_address);
@@ -4910,8 +4841,8 @@
  * sets global variables and return the number of PCI boards found.
  * ---------------------------------------------------------------------
  */
-static int __init 
-cy_detect_pci(void)
+__initfunc(static int
+cy_detect_pci(void))
 {
 #ifdef CONFIG_PCI
 
@@ -5054,6 +4985,11 @@
 		    default: /* Old boards, use PLX_9060 */
 
 		    plx_init(cy_pci_addr0, 0x6c);
+		    /* For some yet unknown reason, once the PLX9060 reloads
+		       the EEPROM, the IRQ is lost and, thus, we have to
+		       re-write it to the PCI config. registers.
+		       This will remain here until we find a permanent fix. */
+		    pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, cy_pci_irq);
 
 		    cy_writew(cy_pci_addr0+0x68, 
 			cy_readw(cy_pci_addr0+0x68)|0x0900);
@@ -5095,6 +5031,11 @@
 #endif
 
 		plx_init(cy_pci_addr0, 0x6c);
+		/* For some yet unknown reason, once the PLX9060 reloads
+		   the EEPROM, the IRQ is lost and, thus, we have to
+		   re-write it to the PCI config. registers.
+		   This will remain here until we find a permanent fix. */
+		pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, cy_pci_irq);
 
 		mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 *) 
 			   cy_pci_addr0)->mail_box_0);
@@ -5203,17 +5144,19 @@
                 cy_card[j].num_chips = -1;
 
                 /* print message */
+#ifdef CONFIG_CYZ_INTR
 		/* don't report IRQ if board is no IRQ */
-		if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
+		if( (cy_pci_irq != 0) && (cy_pci_irq != 255) )
 		    printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
 			j+1,(ulong)cy_pci_addr2,
 			(ulong)(cy_pci_addr2 + CyPCI_Zwin - 1),
 			(int)cy_pci_irq);
-		}else{
+		else
+#endif /* CONFIG_CYZ_INTR */
 		    printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
 			j+1,(ulong)cy_pci_addr2,
 			(ulong)(cy_pci_addr2 + CyPCI_Zwin - 1));
-		}
+
                 printk("%d channels starting from port %d.\n",
 		    cy_pci_nchan,cy_next_channel);
 #ifdef CONFIG_CYZ_INTR
@@ -5288,17 +5231,19 @@
                 cy_card[j].num_chips = -1;
 
                 /* print message */
+#ifdef CONFIG_CYZ_INTR
 		/* don't report IRQ if board is no IRQ */
-		if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
+		if( (cy_pci_irq != 0) && (cy_pci_irq != 255) )
 		    printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
 			j+1,(ulong)cy_pci_addr2,
 			(ulong)(cy_pci_addr2 + CyPCI_Ze_win - 1),
 			(int)cy_pci_irq);
-		}else{
+		else
+#endif /* CONFIG_CYZ_INTR */
 		    printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
 			j+1,(ulong)cy_pci_addr2,
 			(ulong)(cy_pci_addr2 + CyPCI_Ze_win - 1));
-		}
+
                 printk("%d channels starting from port %d.\n",
 		    cy_pci_nchan,cy_next_channel);
 #ifdef CONFIG_CYZ_INTR
@@ -5414,8 +5359,8 @@
     extra ports are ignored.
  */
 
-int __init 
-cy_init(void)
+__initfunc(int
+cy_init(void))
 {
   struct cyclades_port  *info;
   struct cyclades_card *cinfo;
@@ -5424,9 +5369,6 @@
   unsigned long mailbox;
   unsigned short chip_number;
   int nports;
-#ifdef CY_PROC
-  struct proc_dir_entry *ent;
-#endif
 
     init_bh(CYCLADES_BH, do_cyclades_bh);
 
@@ -5530,12 +5472,13 @@
     /* initialize per-port data structures for each valid board found */
     for (board = 0 ; board < cy_nboard ; board++) {
             cinfo = &cy_card[board];
-            if (cinfo->num_chips == -1){ /* Cyclades-Z */
+            if (cinfo->num_chips == -1) { /* Cyclades-Z */
 		number_z_boards++;
 		mailbox = cy_readl(&((struct RUNTIME_9060 *)
 			     cy_card[board].ctl_addr)->mail_box_0);
 		nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
 		cinfo->intr_enabled = 0;
+		spin_lock_init(&cinfo->card_lock);
                 for (port = cinfo->first_line ;
                      port < cinfo->first_line + nports;
                      port++)
@@ -5578,9 +5521,9 @@
 		                cy_callout_driver.init_termios;
                     info->normal_termios =
 		                cy_serial_driver.init_termios;
-                    init_waitqueue_head(&info->open_wait);
-                    init_waitqueue_head(&info->close_wait);
-                    init_waitqueue_head(&info->shutdown_wait);
+		    init_waitqueue_head(&info->open_wait);
+		    init_waitqueue_head(&info->close_wait);
+		    init_waitqueue_head(&info->shutdown_wait);
                     /* info->session */
                     /* info->pgrp */
                     info->read_status_mask = 0;
@@ -5594,6 +5537,7 @@
                 continue;
             }else{ /* Cyclom-Y of some kind*/
                 index = cinfo->bus_index;
+		spin_lock_init(&cinfo->card_lock);
                 for (port = cinfo->first_line ;
                      port < cinfo->first_line + 4*cinfo->num_chips ;
                      port++)
@@ -5647,9 +5591,9 @@
 		               cy_callout_driver.init_termios;
                     info->normal_termios =
 		               cy_serial_driver.init_termios;
-                    init_waitqueue_head(&info->open_wait);
-                    init_waitqueue_head(&info->close_wait);
-                    init_waitqueue_head(&info->shutdown_wait);
+		    init_waitqueue_head(&info->open_wait);
+		    init_waitqueue_head(&info->close_wait);
+		    init_waitqueue_head(&info->shutdown_wait);
                     /* info->session */
                     /* info->pgrp */
                     info->read_status_mask =
@@ -5671,11 +5615,6 @@
     }
 #endif /* CONFIG_CYZ_INTR */
 
-#ifdef CY_PROC
-        ent = create_proc_entry("cyclades", S_IFREG | S_IRUGO, 0);
-        ent->read_proc = cyclades_get_proc_info;
-#endif
-
     return 0;
     
 } /* cy_init */
@@ -5729,10 +5668,6 @@
 	free_page((unsigned long) tmp_buf);
 	tmp_buf = NULL;
     }
-#ifdef CY_PROC
-    remove_proc_entry("cyclades", 0);
-#endif
-
 } /* cleanup_module */
 #else
 /* called by linux/init/main.c to parse command line options */
@@ -5796,8 +5731,7 @@
     printk("  session pgrp open_wait = %lx %lx %lx\n",
              info->session, info->pgrp, (long)info->open_wait);
 
-
-    save_flags(flags); cli();
+    CY_LOCK(info, flags);
 
         base_addr = (unsigned char*)
                        (cy_card[card].base_addr
@@ -5854,7 +5788,7 @@
         printk(" CyTBPR %x\n", cy_readb(base_addr + CyTBPR<<index));
         printk(" CyTCOR %x\n", cy_readb(base_addr + CyTCOR<<index));
 
-    restore_flags(flags);
+    CY_UNLOCK(info, flags);
 } /* show_status */
 #endif
 
diff -u --recursive --new-file v2.3.10/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.3.10/linux/drivers/char/lp.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/lp.c	Wed Jul 21 12:54:07 1999
@@ -333,6 +333,9 @@
 	if (copy_from_user (kbuf, buf, copy_size))
 		return -EFAULT;
 
+	if (down_interruptible (&lp_table[minor].port_mutex))
+		return -EINTR;
+
  	/* Claim Parport or sleep until it becomes available
  	 */
  	lp_parport_claim (minor);
@@ -341,10 +344,6 @@
 	parport_negotiate (port, IEEE1284_MODE_COMPAT);
 
 	do {
-		/* Wait until lp_read has finished. */
-		if (down_interruptible (&lp_table[minor].port_mutex))
-			break;
-
 		/* Write the data. */
 		written = parport_write (port, kbuf, copy_size);
 		if (written >= 0) {
@@ -354,8 +353,6 @@
 			retv += written;
 		}
 
-		up (&lp_table[minor].port_mutex);
-
 		if (signal_pending (current)) {
 			if (retv == 0)
 				retv = -EINTR;
@@ -392,6 +389,8 @@
 
  	lp_parport_release (minor);
 
+	up (&lp_table[minor].port_mutex);
+
  	return retv;
 }
 
@@ -414,35 +413,36 @@
 	if (count > LP_BUFFER_SIZE)
 		count = LP_BUFFER_SIZE;
 
+	if (down_interruptible (&lp_table[minor].port_mutex))
+		return -EINTR;
+
 	lp_parport_claim (minor);
 
-	if (!down_interruptible (&lp_table[minor].port_mutex)) {
-		for (;;) {
-			retval = parport_read (port, kbuf, count);
+	for (;;) {
+		retval = parport_read (port, kbuf, count);
 
-			if (retval)
-				break;
+		if (retval)
+			break;
 
-			if (file->f_flags & O_NONBLOCK)
-				break;
+		if (file->f_flags & O_NONBLOCK)
+			break;
 
-			/* Wait for an interrupt. */
-			interruptible_sleep_on_timeout (&lp_table[minor].waitq,
-							LP_TIMEOUT_POLLED);
+		/* Wait for an interrupt. */
+		interruptible_sleep_on_timeout (&lp_table[minor].waitq,
+						LP_TIMEOUT_POLLED);
 
-			if (signal_pending (current)) {
-				retval = -EINTR;
-				break;
-			}
+		if (signal_pending (current)) {
+			retval = -EINTR;
+			break;
 		}
-
-		up (&lp_table[minor].port_mutex);
 	}
 
 	lp_parport_release (minor);
 
 	if (retval > 0 && copy_to_user (buf, kbuf, retval))
 		retval = -EFAULT;
+
+	up (&lp_table[minor].port_mutex);
 
 	return retval;
 }
diff -u --recursive --new-file v2.3.10/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.3.10/linux/drivers/char/pc_keyb.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/pc_keyb.c	Fri Jul  9 17:03:24 1999
@@ -690,9 +690,6 @@
 
 void __init pckbd_init_hw(void)
 {
-	/* Get the keyboard controller registers (incomplete decode) */
-	request_region(0x60, 16, "keyboard");
-
 	/* Flush any pending input. */
 	kbd_clear_input();
 
diff -u --recursive --new-file v2.3.10/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- v2.3.10/linux/drivers/char/ppdev.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/ppdev.c	Sat Jul 17 21:17:21 1999
@@ -50,14 +50,10 @@
 #define min(a,b) ((a) < (b) ? (a) : (b))
 #endif
 
-/* The device minor encodes the parport number and (arbitrary) 
- * pardevice number as (port << 4) | dev. */
-#define PP_PORT(minor) ((minor >> 4) & 0xf)
-#define PP_DEV(minor) ((minor) & 0xf)
-
 struct pp_struct {
 	struct pardevice * pdev;
 	wait_queue_head_t irq_wait;
+	int got_irq;
 	int mode;
 	unsigned int flags;
 };
@@ -71,7 +67,11 @@
 #define PP_BUFFER_SIZE 256
 #define PARDEVICE_MAX 8
 
-static struct pp_struct pp_table[PARPORT_MAX][PARDEVICE_MAX];
+static inline void enable_irq (struct pp_struct *pp)
+{
+	struct parport *port = pp->pdev->port;
+	port->ops->enable_irq (port);
+}
 
 static loff_t pp_lseek (struct file * file, long long offset, int origin)
 {
@@ -165,17 +165,16 @@
 			loff_t * ppos)
 {
 	unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
-	unsigned int portnum = PP_PORT (minor);
-	unsigned int dev = PP_DEV (minor);
+	struct pp_struct *pp = file->private_data;
 	char * kbuffer;
 	ssize_t bytes_read = 0;
 	ssize_t got = 0;
 
-	if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+	if (!(pp->flags & PP_CLAIMED)) {
 		/* Don't have the port claimed */
-		printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+		printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
 			minor);
-		return -EPERM;
+		return -EINVAL;
 	}
 
 	kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
@@ -185,16 +184,16 @@
 	while (bytes_read < count) {
 		ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE);
 
-		got = do_read (&pp_table[portnum][dev], kbuffer, need);
+		got = do_read (pp, kbuffer, need);
 
-		if (got < 0) {
+		if (got <= 0) {
 			if (!bytes_read)
 				bytes_read = got;
 
 			break;
 		}
 
-		if (copy_to_user (kbuffer, buf + bytes_read, got)) {
+		if (copy_to_user (buf + bytes_read, kbuffer, got)) {
 			bytes_read = -EFAULT;
 			break;
 		}
@@ -212,6 +211,7 @@
 	}
 
 	kfree (kbuffer);
+	enable_irq (pp);
 	return bytes_read;
 }
 
@@ -219,17 +219,16 @@
 			 loff_t * ppos)
 {
 	unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
-	unsigned int portnum = PP_PORT (minor);
-	unsigned int dev = PP_DEV (minor);
+	struct pp_struct *pp = file->private_data;
 	char * kbuffer;
 	ssize_t bytes_written = 0;
 	ssize_t wrote;
 
-	if (!(pp_table[portnum][dev].flags & PP_CLAIMED)) {
+	if (!(pp->flags & PP_CLAIMED)) {
 		/* Don't have the port claimed */
-		printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+		printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
 			minor);
-		return -EPERM;
+		return -EINVAL;
 	}
 
 	kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL);
@@ -244,7 +243,7 @@
 			break;
 		}
 
-		wrote = do_write (&pp_table[portnum][dev], kbuffer, n);
+		wrote = do_write (pp, kbuffer, n);
 
 		if (wrote < 0) {
 			if (!bytes_written)
@@ -265,19 +264,19 @@
 	}
 
 	kfree (kbuffer);
+	enable_irq (pp);
 	return bytes_written;
 }
 
 static void pp_irq (int irq, void * private, struct pt_regs * unused)
 {
 	struct pp_struct * pp = (struct pp_struct *) private;
+	pp->got_irq = 1;
 	wake_up_interruptible (&pp->irq_wait);
 }
 
-static int register_device (int minor)
+static int register_device (int minor, struct pp_struct *pp)
 {
-	unsigned int portnum = PP_PORT (minor);
-	unsigned int dev = PP_DEV (minor);
 	struct parport * port;
 	struct pardevice * pdev = NULL;
 	char *name;
@@ -287,10 +286,10 @@
 	if (name == NULL)
 		return -ENOMEM;
 
-	sprintf (name, CHRDEV "%02x", minor);
+	sprintf (name, CHRDEV "%x", minor);
 	port = parport_enumerate (); /* FIXME: use attach/detach */
 
-	while (port && port->number != portnum)
+	while (port && port->number != minor)
 		port = port->next;
 
 	if (!port) {
@@ -299,9 +298,9 @@
 		return -ENXIO;
 	}
 
-	fl = (pp_table[portnum][dev].flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+	fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
 	pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl,
-					&pp_table[portnum][dev]);
+					pp);
 
 	if (!pdev) {
 		printk (KERN_WARNING "%s: failed to register device!\n", name);
@@ -309,7 +308,7 @@
 		return -ENXIO;
 	}
 
-	pp_table[portnum][dev].pdev = pdev;
+	pp->pdev = pdev;
 	printk (KERN_DEBUG "%s: registered pardevice\n", name);
 	return 0;
 }
@@ -318,36 +317,38 @@
 		    unsigned int cmd, unsigned long arg)
 {
 	unsigned int minor = MINOR(inode->i_rdev);
-	unsigned int portnum = PP_PORT (minor);
-	unsigned int dev = PP_DEV (minor);
+	struct pp_struct *pp = file->private_data;
 	struct parport * port;
 
 	/* First handle the cases that don't take arguments. */
 	if (cmd == PPCLAIM) {
-		if (pp_table[portnum][dev].flags & PP_CLAIMED) {
+		if (pp->flags & PP_CLAIMED) {
 			printk (KERN_DEBUG CHRDEV
-				"%02x: you've already got it!\n", minor);
+				"%x: you've already got it!\n", minor);
 			return -EINVAL;
 		}
 
 		/* Deferred device registration. */
-		if (!pp_table[portnum][dev].pdev) {
-			int err = register_device (minor);
+		if (!pp->pdev) {
+			int err = register_device (minor, pp);
 			if (err)
 				return err;
 		}
 
-		parport_claim_or_block (pp_table[portnum][dev].pdev);
-		pp_table[portnum][dev].flags |= PP_CLAIMED;
+		parport_claim_or_block (pp->pdev);
+		pp->flags |= PP_CLAIMED;
+
+		/* For interrupt-reporting to work, we need to be
+		 * informed of each interrupt. */
+		enable_irq (pp);
 		return 0;
 	}
 
-	port = pp_table[portnum][dev].pdev->port;
 	if (cmd == PPEXCL) {
-		if (pp_table[portnum][dev].pdev) {
-			printk (KERN_DEBUG CHRDEV "%02x: too late for PPEXCL; "
+		if (pp->pdev) {
+			printk (KERN_DEBUG CHRDEV "%x: too late for PPEXCL; "
 				"already registered\n", minor);
-			if (pp_table[portnum][dev].flags & PP_EXCL)
+			if (pp->flags & PP_EXCL)
 				/* But it's not really an error. */
 				return 0;
 			/* There's no chance of making the driver happy. */
@@ -356,22 +357,33 @@
 
 		/* Just remember to register the device exclusively
 		 * when we finally do the registration. */
-		pp_table[portnum][dev].flags |= PP_EXCL;
+		pp->flags |= PP_EXCL;
+		return 0;
+	}
+
+	if (cmd == PPSETMODE) {
+		int mode;
+		if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+			return -EFAULT;
+		/* FIXME: validate mode */
+		pp->mode = mode;
 		return 0;
 	}
 
 	/* Everything else requires the port to be claimed, so check
 	 * that now. */
-	if ((pp_table[portnum][dev].flags & PP_CLAIMED) == 0) {
-		printk (KERN_DEBUG CHRDEV "%02x: claim the port first\n",
+	if ((pp->flags & PP_CLAIMED) == 0) {
+		printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
 			minor);
-		return -EPERM;
+		return -EINVAL;
 	}
 
+	port = pp->pdev->port;
 	switch (cmd) {
 		unsigned char reg;
 		unsigned char mask;
 		int mode;
+		int ret;
 
 	case PPRSTATUS:
 		reg = parport_read_status (port);
@@ -389,19 +401,12 @@
 				     sizeof (reg));
 
 	case PPYIELD:
-		parport_yield_blocking (pp_table[portnum][dev].pdev);
+		parport_yield_blocking (pp->pdev);
 		return 0;
 
 	case PPRELEASE:
-		parport_release (pp_table[portnum][dev].pdev);
-		pp_table[portnum][dev].flags &= ~PP_CLAIMED;
-		return 0;
-
-	case PPSETMODE:
-		if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
-			return -EFAULT;
-		/* FIXME: validate mode */
-		pp_table[portnum][dev].mode = mode;
+		parport_release (pp->pdev);
+		pp->flags &= ~PP_CLAIMED;
 		return 0;
 
 	case PPWCONTROL:
@@ -439,10 +444,12 @@
 		if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
 			return -EFAULT;
 		/* FIXME: validate mode */
-		return parport_negotiate (port, mode);
+		ret = parport_negotiate (port, mode);
+		enable_irq (pp);
+		return ret;
 
 	default:
-		printk (KERN_DEBUG CHRDEV "%02x: What? (cmd=0x%x\n", minor,
+		printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor,
 			cmd);
 		return -EINVAL;
 	}
@@ -454,24 +461,26 @@
 static int pp_open (struct inode * inode, struct file * file)
 {
 	unsigned int minor = MINOR (inode->i_rdev);
-	unsigned int portnum = PP_PORT (minor);
-	unsigned int dev = PP_DEV (minor);
+	struct pp_struct *pp;
 
-	if (portnum >= PARPORT_MAX)
+	if (minor >= PARPORT_MAX)
 		return -ENXIO;
 
-	if (pp_table[portnum][dev].pdev)
-		return -EBUSY;
+	pp = kmalloc (GFP_KERNEL, sizeof (struct pp_struct));
+	if (!pp)
+		return -ENOMEM;
 
-	pp_table[portnum][dev].mode = IEEE1284_MODE_COMPAT;
-	pp_table[portnum][dev].flags = 0;
-	init_waitqueue_head (&pp_table[portnum][dev].irq_wait);
+	pp->mode = IEEE1284_MODE_COMPAT;
+	pp->flags = 0;
+	pp->got_irq = 0;
+	init_waitqueue_head (&pp->irq_wait);
 
 	/* Defer the actual device registration until the first claim.
 	 * That way, we know whether or not the driver wants to have
 	 * exclusive access to the port (PPEXCL).
 	 */
-	pp_table[portnum][dev].pdev = NULL;
+	pp->pdev = NULL;
+	file->private_data = pp;
 
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -480,42 +489,46 @@
 static int pp_release (struct inode * inode, struct file * file)
 {
 	unsigned int minor = MINOR (inode->i_rdev);
-	unsigned int portnum = PP_PORT (minor);
-	unsigned int dev = PP_DEV (minor);
+	struct pp_struct *pp = file->private_data;
 
-	if (pp_table[portnum][dev].flags & PP_CLAIMED) {
-		parport_release (pp_table[portnum][dev].pdev);
-		printk (KERN_DEBUG CHRDEV "%02x: released pardevice because "
+	if (pp->flags & PP_CLAIMED) {
+		parport_release (pp->pdev);
+		printk (KERN_DEBUG CHRDEV "%x: released pardevice because "
 			"user-space forgot\n", minor);
 	}
 
-	if (pp_table[portnum][dev].pdev) {
-		kfree (pp_table[portnum][dev].pdev->name);
-		parport_unregister_device (pp_table[portnum][dev].pdev);
-		pp_table[portnum][dev].pdev = NULL;
-		printk (KERN_DEBUG CHRDEV "%02x: unregistered pardevice\n",
+	if (pp->pdev) {
+		kfree (pp->pdev->name);
+		parport_unregister_device (pp->pdev);
+		pp->pdev = NULL;
+		printk (KERN_DEBUG CHRDEV "%x: unregistered pardevice\n",
 			minor);
 	}
 
+	kfree (pp);
+
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-#if 0
 static unsigned int pp_poll (struct file * file, poll_table * wait)
 {
-	unsigned int minor = MINOR (file->f_dentry->d_inode->i_rdev);
-	poll_wait (file, &pp_table[minor].irq_wait, wait);
-	return 0; /* FIXME! Return value is wrong here */
+	struct pp_struct *pp = file->private_data;
+	unsigned int mask = 0;
+	if (pp->got_irq) {
+		pp->got_irq = 0;
+		mask |= POLLIN | POLLRDNORM;
+	}
+	poll_wait (file, &pp->irq_wait, wait);
+	return mask;
 }
-#endif
 
 static struct file_operations pp_fops = {
 	pp_lseek,
 	pp_read,
 	pp_write,
 	NULL,	/* pp_readdir */
-	NULL,   /* pp_poll */
+	pp_poll,
 	pp_ioctl,
 	NULL,	/* pp_mmap */
 	pp_open,
diff -u --recursive --new-file v2.3.10/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- v2.3.10/linux/drivers/char/sysrq.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/char/sysrq.c	Mon Jul 19 23:08:41 1999
@@ -40,7 +40,7 @@
 	struct task_struct *p;
 
 	for_each_task(p) {
-		if (p->pid && p->mm != &init_mm) {	    /* Not swapper nor kernel thread */
+		if (p->mm) {				    /* Not swapper nor kernel thread */
 			if (p->pid == 1 && even_init)	    /* Ugly hack to kill init */
 				p->pid = 0x8000;
 			force_sig(sig, p);
diff -u --recursive --new-file v2.3.10/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.3.10/linux/drivers/char/vt.c	Wed Jun 30 13:38:19 1999
+++ linux/drivers/char/vt.c	Fri Jul  9 15:05:41 1999
@@ -670,7 +670,7 @@
 	case KDSIGACCEPT:
 	{
 		extern int spawnpid, spawnsig;
-		if (!perm)
+		if (!perm || !capable(CAP_KILL))
 		  return -EPERM;
 		if (arg < 1 || arg > _NSIG || arg == SIGKILL)
 		  return -EINVAL;
diff -u --recursive --new-file v2.3.10/linux/drivers/misc/parport_arc.c linux/drivers/misc/parport_arc.c
--- v2.3.10/linux/drivers/misc/parport_arc.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_arc.c	Tue Jul 13 09:29:34 1999
@@ -14,7 +14,7 @@
  * a subset of the standard printer control lines connected.
  */
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.3.10/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c
--- v2.3.10/linux/drivers/misc/parport_ieee1284.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_ieee1284.c	Wed Jul 21 15:38:39 1999
@@ -11,7 +11,7 @@
  */
 
 #include <linux/config.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/parport.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
@@ -220,7 +220,7 @@
 	printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
 	return -1;
 #else
-	int m = mode;
+	int m = mode & ~IEEE1284_ADDR;
 	unsigned char xflag;
 
 	port = port->physport;
@@ -229,6 +229,12 @@
 	if (port->ieee1284.mode == mode)
 		return 0;
 
+	/* Is the difference just an address-or-not bit? */
+	if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){
+		port->ieee1284.mode = mode;
+		return 0;
+	}
+
 	/* Go to compability forward idle mode */
 	if (port->ieee1284.mode != IEEE1284_MODE_COMPAT)
 		parport_ieee1284_terminate (port);
@@ -409,10 +415,11 @@
 #else
 	ssize_t retval;
 	int mode = port->ieee1284.mode;
+	int addr = mode & IEEE1284_ADDR;
 	size_t (*fn) (struct parport *, const void *, size_t, int);
 
-	/* Ignore the device-ID-request bit. */
-	mode &= ~IEEE1284_DEVICEID;
+	/* Ignore the device-ID-request bit and the address bit. */
+	mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
 
 	/* Use the mode we're in. */
 	switch (mode) {
@@ -426,13 +433,19 @@
 
 	case IEEE1284_MODE_EPP:
 		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
-		fn = port->ops->epp_write_data;
+		if (addr)
+			fn = port->ops->epp_write_addr;
+		else
+			fn = port->ops->epp_write_data;
 		break;
 
 	case IEEE1284_MODE_ECP:
 	case IEEE1284_MODE_ECPRLE:
 		DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
-		fn = port->ops->ecp_write_data;
+		if (addr)
+			fn = port->ops->ecp_write_addr;
+		else
+			fn = port->ops->ecp_write_data;
 		break;
 
 	case IEEE1284_MODE_ECPSWE:
@@ -440,7 +453,10 @@
 			 port->name);
 		/* The caller has specified that it must be emulated,
 		 * even if we have ECP hardware! */
-		fn = parport_ieee1284_ecp_write_data;
+		if (addr)
+			fn = parport_ieee1284_ecp_write_addr;
+		else
+			fn = parport_ieee1284_ecp_write_data;
 		break;
 
 	default:
@@ -464,10 +480,11 @@
 	return -ENODEV;
 #else
 	int mode = port->physport->ieee1284.mode;
+	int addr = mode & IEEE1284_ADDR;
 	size_t (*fn) (struct parport *, void *, size_t, int);
 
-	/* Ignore the device-ID-request bit. */
-	mode &= ~IEEE1284_DEVICEID;
+	/* Ignore the device-ID-request bit and the address bit. */
+	mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
 
 	/* Use the mode we're in. */
 	switch (mode) {
@@ -486,7 +503,10 @@
 
 	case IEEE1284_MODE_EPP:
 		DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
-		fn = port->ops->epp_read_data;
+		if (addr)
+			fn = port->ops->epp_read_addr;
+		else
+			fn = port->ops->epp_read_data;
 		break;
 
 	case IEEE1284_MODE_ECP:
diff -u --recursive --new-file v2.3.10/linux/drivers/misc/parport_init.c linux/drivers/misc/parport_init.c
--- v2.3.10/linux/drivers/misc/parport_init.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_init.c	Tue Jul 13 09:29:34 1999
@@ -10,7 +10,7 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 #include <linux/parport.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.10/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.3.10/linux/drivers/misc/parport_pc.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_pc.c	Thu Jul 15 14:36:27 1999
@@ -314,8 +314,7 @@
 
 void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
 {
-	struct parport_pc_private *priv = dev->port->physport->private_data;
-	priv->ctr = s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+	s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
 	s->u.pc.ecr = 0x24;
 }
 
@@ -1377,7 +1376,8 @@
 
 static int __init irq_probe_ECP(struct parport *pb)
 {
-	int irqs, i;
+	int i;
+	unsigned long irqs;
 
 	sti();
 	irqs = probe_irq_on();
diff -u --recursive --new-file v2.3.10/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- v2.3.10/linux/drivers/misc/parport_share.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/misc/parport_share.c	Tue Jul 13 09:29:34 1999
@@ -15,7 +15,7 @@
 
 #include <linux/config.h>
 #include <linux/string.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/parport.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.3.10/linux/drivers/net/hp100.c linux/drivers/net/hp100.c
--- v2.3.10/linux/drivers/net/hp100.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/hp100.c	Tue Jul 13 02:29:35 1999
@@ -121,8 +121,6 @@
 
 #ifndef __initfunc
 #define __initfunc(__initarg) __initarg
-#else
-#include <linux/init.h>
 #endif
 
 #include "hp100.h"
diff -u --recursive --new-file v2.3.10/linux/drivers/net/mace.c linux/drivers/net/mace.c
--- v2.3.10/linux/drivers/net/mace.c	Wed Mar 10 21:48:46 1999
+++ linux/drivers/net/mace.c	Mon Jul 12 16:21:25 1999
@@ -682,8 +682,10 @@
 		++mp->stats.tx_carrier_errors;
 	    if (fs & (UFLO|LCOL|RTRY))
 		++mp->stats.tx_aborted_errors;
-	} else
+	} else {
+	    mp->stats.tx_bytes += mp->tx_bufs[i]->len;
 	    ++mp->stats.tx_packets;
+	}
 	dev_kfree_skb(mp->tx_bufs[i]);
 	--mp->tx_active;
 	if (++i >= N_TX_RING)
@@ -848,6 +850,7 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 		mp->rx_bufs[i] = 0;
+		mp->stats.rx_bytes += skb->len;
 		++mp->stats.rx_packets;
 	    }
 	} else {
diff -u --recursive --new-file v2.3.10/linux/drivers/net/pcnet32.c linux/drivers/net/pcnet32.c
--- v2.3.10/linux/drivers/net/pcnet32.c	Sat Apr 24 17:51:48 1999
+++ linux/drivers/net/pcnet32.c	Mon Jul 12 14:58:46 1999
@@ -13,7 +13,7 @@
  * 	This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
-static const char *version = "pcnet32.c:v1.21 31.3.99 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.23 6.7.1999 tsbogend@alpha.franken.de\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -149,6 +149,13 @@
  *         rewritten PCI card detection
  *         added dwio mode to get driver working on some PPC machines
  * v1.21:  added mii selection and mii ioctl
+ * v1.22:  changed pci scanning code to make PPC people happy
+ *         fixed switching to 32bit mode in pcnet32_open() (thanks
+ *         to Michael Richard <mcr@solidum.com> for noticing this one)
+ *	   added sub vendor/device id matching (thanks again to 
+ *	   Michael Richard <mcr@solidum.com>)
+ *         added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>)
+ * v1.23   fixed small bug, when manual selecting MII speed/duplex
  */
 
 
@@ -185,6 +192,16 @@
 
 #define PCNET32_TOTAL_SIZE 0x20
 
+/* some PCI ids */
+#ifndef PCI_DEVICE_ID_AMD_LANCE
+#define PCI_VENDOR_ID_AMD	      0x1022
+#define PCI_DEVICE_ID_AMD_LANCE	      0x2000
+#endif
+#ifndef PCI_DEVICE_ID_AMD_PCNETHOME
+#define PCI_DEVICE_ID_AMD_PCNETHOME   0x2001
+#endif
+
+
 #define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
 
 /* The PCNET32 Rx and Tx ring descriptors. */
@@ -272,14 +289,19 @@
 
 struct pcnet32_pci_id_info {
     const char *name;
-    u16 vendor_id, device_id, device_id_mask, flags;
+    u16 vendor_id, device_id, svid, sdid, flags;
     int io_size;
     int (*probe1) (struct device *, unsigned long, unsigned char, int, int);
 };
 
 static struct pcnet32_pci_id_info pcnet32_tbl[] = {
     { "AMD PCnetPCI series",
-	0x1022, 0x2000, 0xfffe, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0,
+	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+	pcnet32_probe1},
+    { "AMD PCnetHome series",
+	PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0,
+	PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
 	pcnet32_probe1},
     {0,}
 };
@@ -418,30 +440,27 @@
     
 #if defined(CONFIG_PCI)
     if (pci_present()) {
-	struct pci_dev *pdev;
-	unsigned char pci_bus, pci_device_fn;
-	int pci_index;
+	struct pci_dev *pdev = NULL;
 	
 	printk("pcnet32.c: PCI bios is present, checking for devices...\n");
-	for (pci_index = 0; pci_index < 0xff; pci_index++) {
-	    u16 vendor, device, pci_command;
+	while ((pdev = pci_find_class (PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) {
+	    u16 pci_command;
 	    int chip_idx;
+	    u16 sdid,svid;
 
-	    if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
-				    pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
-		break;
-	    
-	    pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor);
-	    pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device);
-
+	    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &sdid);
+	    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &svid);
 	    for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
-		if (vendor == pcnet32_tbl[chip_idx].vendor_id &&
-		    (device & pcnet32_tbl[chip_idx].device_id_mask) == pcnet32_tbl[chip_idx].device_id)
+		if ((pdev->vendor == pcnet32_tbl[chip_idx].vendor_id) &&
+		    (pdev->device == pcnet32_tbl[chip_idx].device_id) &&
+		    (pcnet32_tbl[chip_idx].svid == 0 || 
+		     (svid == pcnet32_tbl[chip_idx].svid)) &&
+		    (pcnet32_tbl[chip_idx].sdid == 0 || 
+		     (sdid == pcnet32_tbl[chip_idx].sdid)))
 		    break;
 	    if (pcnet32_tbl[chip_idx].vendor_id == 0)
 		continue;
 	    
-	    pdev = pci_find_slot(pci_bus, pci_device_fn);
 	    ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
 #if defined(ADDR_64BITS) && defined(__alpha__)
 	    ioaddr |= ((long)pdev->base_address[1]) << 32;
@@ -541,6 +560,10 @@
 	chipname = "PCnet/FAST+ 79C972";
 	fdx = 1; mii = 1;
 	break;
+     case 0x2625:
+	chipname = "PCnet/FAST III 79C973";
+	fdx = 1; mii = 1;
+	break;
      case 0x2626:
 	chipname = "PCnet/Home 79C978";
 	fdx = 1;
@@ -561,6 +584,9 @@
 	    printk("pcnet32: pcnet32 media reset to %#x.\n",  media);
 	a->write_bcr (ioaddr, 49, media);
 	break;
+     case 0x2627:
+	chipname = "PCnet/FAST III 79C975";
+	fdx = 1; mii = 1;
      default:
 	printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
 	return ENODEV;
@@ -693,7 +719,7 @@
     lp->a.reset (ioaddr);
 
     /* switch pcnet32 to 32bit mode */
-    lp->a.write_csr (ioaddr, 20, 2);
+    lp->a.write_bcr (ioaddr, 20, 2);
 
     if (pcnet32_debug > 1)
 	printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
@@ -725,7 +751,7 @@
 	val |= 0x10;
     lp->a.write_csr (ioaddr, 124, val);
     
-    if (lp->mii & (lp->options & PORT_ASEL)) {
+    if (lp->mii & !(lp->options & PORT_ASEL)) {
 	val = lp->a.read_bcr (ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */
 	if (lp->options & PORT_FD)
 	    val |= 0x10;
@@ -952,7 +978,7 @@
     struct device *dev = (struct device *)dev_id;
     struct pcnet32_private *lp;
     unsigned long ioaddr;
-    u16 csr0;
+    u16 csr0,rap;
     int boguscnt =  max_interrupt_work;
     int must_restart;
 
@@ -968,6 +994,7 @@
 
     dev->interrupt = 1;
 
+    rap = lp->a.read_rap(ioaddr);
     while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) {
 	/* Acknowledge all of the current interrupt sources ASAP. */
 	lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f);
@@ -1069,6 +1096,7 @@
 
     /* Clear any other interrupt, and set interrupt enable. */
     lp->a.write_csr (ioaddr, 0, 0x7940);
+    lp->a.write_rap(ioaddr,rap);
 
     if (pcnet32_debug > 4)
 	printk("%s: exiting interrupt, csr0=%#4.4x.\n",
diff -u --recursive --new-file v2.3.10/linux/drivers/net/rcpci45.c linux/drivers/net/rcpci45.c
--- v2.3.10/linux/drivers/net/rcpci45.c	Mon Apr 12 16:18:27 1999
+++ linux/drivers/net/rcpci45.c	Tue Jul 20 16:40:30 1999
@@ -63,7 +63,6 @@
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#include <linux/bios32.h>
 #include <linux/timer.h>
 #include <asm/irq.h>            /* For NR_IRQS only. */
 #include <asm/bitops.h>
@@ -211,9 +210,8 @@
         int scan_status;
         int board_index = 0;
         unsigned char pci_irq_line;
-        unsigned short pci_command, vendor, device, class;
         unsigned int pci_ioaddr;
-
+	struct pci_dev *pdev;
 
         scan_status =  
             (pcibios_find_device (RC_PCI45_VENDOR_ID, 
@@ -224,75 +222,22 @@
 #ifdef RCDEBUG
         printk("rc scan_status = 0x%X\n", scan_status);
 #endif
-        if (scan_status != PCIBIOS_SUCCESSFUL)
+        if (scan_status != PCIBIOS_SUCCESSFUL ||
+	    !((pdev = pci_find_slot(pci_bus, pci_device_fn))))
             break;
-        pcibios_read_config_word(pci_bus, 
-                                 pci_device_fn, 
-                                 PCI_VENDOR_ID, &vendor);
-        pcibios_read_config_word(pci_bus, 
-                                 pci_device_fn,
-                                 PCI_DEVICE_ID, &device);
-        pcibios_read_config_byte(pci_bus, 
-                                 pci_device_fn,
-                                 PCI_INTERRUPT_LINE, &pci_irq_line);
-        pcibios_read_config_dword(pci_bus, 
-                                  pci_device_fn,
-                                  PCI_BASE_ADDRESS_0, &pci_ioaddr);
-        pcibios_read_config_word(pci_bus, 
-                                 pci_device_fn,
-                                 PCI_CLASS_DEVICE, &class);
-
-        pci_ioaddr &= ~0xf;
+	pci_irq_line = pdev->irq;
+	pci_ioaddr = pdev->base_address[0];
+        pci_ioaddr &= PCI_BASE_ADDRESS_MEM_MASK;
 
 #ifdef RCDEBUG
         printk("rc: Found RedCreek PCI adapter\n");
-        printk("rc: pci class = 0x%x  0x%x \n", class, class>>8);
         printk("rc: pci_bus = %d,  pci_device_fn = %d\n", pci_bus, pci_device_fn);
         printk("rc: pci_irq_line = 0x%x \n", pci_irq_line);
         printk("rc: pci_ioaddr = 0x%x\n", pci_ioaddr);
 #endif
 
-        if (check_region(pci_ioaddr, 2*32768))
-        {
-            printk("rc: check_region failed\n");
-            continue;
-        }
-#ifdef RCDEBUG
-        else
-        {
-            printk("rc: check_region passed\n");
-        }
-#endif
-           
-        /*
-         * Get and check the bus-master and latency values.
-         * Some PCI BIOSes fail to set the master-enable bit.
-         */
-
-        pcibios_read_config_word(pci_bus, 
-                                 pci_device_fn,
-                                 PCI_COMMAND, 
-                                 &pci_command);
-        if ( ! (pci_command & PCI_COMMAND_MASTER)) {
-            printk("rc: PCI Master Bit has not been set!\n");
-                        
-            pci_command |= PCI_COMMAND_MASTER;
-            pcibios_write_config_word(pci_bus, 
-                                      pci_device_fn,
-                                      PCI_COMMAND, 
-                                      pci_command);
-        }
-        if ( ! (pci_command & PCI_COMMAND_MEMORY)) {
-            /*
-             * If the BIOS did not set the memory enable bit, what else
-             * did it not initialize?  Skip this adapter.
-             */
-            printk("rc: Adapter %d, PCI Memory Bit has not been set!\n",
-                   cards_found);
-            printk("rc: Bios problem? \n");
-            continue;
-        }
-                
+	pci_set_master(pdev);
+
         if (!RCfound_device(dev, pci_ioaddr, pci_irq_line,
                           pci_bus, pci_device_fn,
                           board_index++, cards_found))
diff -u --recursive --new-file v2.3.10/linux/drivers/net/rtl8139.c linux/drivers/net/rtl8139.c
--- v2.3.10/linux/drivers/net/rtl8139.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/net/rtl8139.c	Wed Jul 14 10:18:12 1999
@@ -680,6 +680,7 @@
 	tp->tx_bufs = kmalloc(TX_BUF_SIZE * NUM_TX_DESC, GFP_KERNEL);
 	tp->rx_ring = kmalloc(RX_BUF_LEN + 16, GFP_KERNEL);
 	if (tp->tx_bufs == NULL ||  tp->rx_ring == NULL) {
+		free_irq(dev->irq, dev);
 		if (tp->tx_bufs)
 			kfree(tp->tx_bufs);
 		if (rtl8129_debug > 0)
diff -u --recursive --new-file v2.3.10/linux/drivers/nubus/nubus.c linux/drivers/nubus/nubus.c
--- v2.3.10/linux/drivers/nubus/nubus.c	Tue Dec 29 11:32:06 1998
+++ linux/drivers/nubus/nubus.c	Tue Jul 20 16:40:30 1999
@@ -6,7 +6,6 @@
 #include <linux/ptrace.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/string.h>
 #include <linux/nubus.h>
diff -u --recursive --new-file v2.3.10/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.3.10/linux/drivers/pci/oldproc.c	Thu Jul  8 15:42:20 1999
+++ linux/drivers/pci/oldproc.c	Tue Jul 20 16:40:55 1999
@@ -903,11 +903,11 @@
 			       vendor, device);
 	}
 
-	str = 0;	/* to keep gcc shut... */
 	switch (status & PCI_STATUS_DEVSEL_MASK) {
 	      case PCI_STATUS_DEVSEL_FAST:   str = "Fast devsel.  "; break;
 	      case PCI_STATUS_DEVSEL_MEDIUM: str = "Medium devsel.  "; break;
 	      case PCI_STATUS_DEVSEL_SLOW:   str = "Slow devsel.  "; break;
+	      default:			     str = "Unknown devsel.  ";
 	}
 	if (len + strlen(str) > size) {
 		return -1;
diff -u --recursive --new-file v2.3.10/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c
--- v2.3.10/linux/drivers/scsi/aic7xxx.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/scsi/aic7xxx.c	Sun Jul 18 21:15:13 1999
@@ -242,7 +242,6 @@
 #include <linux/proc_fs.h>
 #include <linux/blk.h>
 #include <linux/tqueue.h>
-#include <linux/tasks.h>
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
@@ -270,7 +269,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.18"
+#define AIC7XXX_C_VERSION  "5.1.19"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -7186,7 +7185,7 @@
 static int
 acquire_seeprom(struct aic7xxx_host *p)
 {
-  int count=0;
+  int wait;
 
   /*
    * Request access of the memory port.  When access is
@@ -7196,10 +7195,11 @@
    * should be no contention.
    */
   aic_outb(p, SEEMS, SEECTL);
-  while( ((aic_inb(p, SEECTL) & SEERDY) == 0) && count < 1000) {
-    mb();
-    udelay(1);
-    count++;
+  wait = 1000;  /* 1000 msec = 1 second */
+  while ((wait > 0) && ((aic_inb(p, SEECTL) & SEERDY) == 0))
+  {
+    wait--;
+    mdelay(1);  /* 1 msec */
   }
   if ((aic_inb(p, SEECTL) & SEERDY) == 0)
   {
@@ -7419,21 +7419,27 @@
 static unsigned char
 read_brdctl(struct aic7xxx_host *p)
 {
-  unsigned char brdctl;
+  unsigned char brdctl, value;
 
-  if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
+  if (p->features & AHC_ULTRA2)
   {
-    brdctl = BRDRW;
-    if (p->flags & AHC_CHNLB)
-      brdctl |= BRDCS;
-  }
-  else if (p->features & AHC_ULTRA2)
     brdctl = BRDRW_ULTRA2;
-  else
-    brdctl = BRDRW | BRDCS;
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(4);
+    return(aic_inb(p, BRDCTL));
+  }
+  brdctl = BRDRW;
+  if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
+        (p->flags & AHC_CHNLB) )
+  {
+    brdctl |= BRDCS;
+  }
   aic_outb(p, brdctl, BRDCTL);
-  udelay(10);
-  return (aic_inb(p, BRDCTL));
+  udelay(1);
+  value = aic_inb(p, BRDCTL);
+  aic_outb(p, 0, BRDCTL);
+  udelay(1);
+  return (value);
 }
 
 /*+F*************************************************************************
@@ -7448,41 +7454,40 @@
 {
   unsigned char brdctl;
 
-  if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
+  if (p->features & AHC_ULTRA2)
   {
-    brdctl = BRDSTB;
-    if (p->flags & AHC_CHNLB)
-      brdctl |= BRDCS;
+    brdctl = value;
     aic_outb(p, brdctl, BRDCTL);
     udelay(4);
-    brdctl |= value;
-  }
-  else if (p->features & AHC_ULTRA2)
-  {
-    brdctl = value;
+    brdctl |= BRDSTB_ULTRA2;
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(4);
+    brdctl &= ~BRDSTB_ULTRA2;
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(4);
+    read_brdctl(p);
   }
   else
   {
+    brdctl = BRDSTB;
+    if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
+          (p->flags & AHC_CHNLB) )
+    {
+      brdctl |= BRDCS;
+    }
     brdctl = BRDSTB | BRDCS;
     aic_outb(p, brdctl, BRDCTL);
-    udelay(4);
+    udelay(1);
     brdctl |= value;
-  }
-  aic_outb(p, brdctl, BRDCTL);
-  udelay(4);
-  if (p->features & AHC_ULTRA2)
-    brdctl |= BRDSTB_ULTRA2;
-  else
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(1);
     brdctl &= ~BRDSTB;
-  aic_outb(p, brdctl, BRDCTL);
-  udelay(4);
-  if (p->features & AHC_ULTRA2)
-    brdctl &= ~BRDSTB_ULTRA2;
-  else
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(1);
     brdctl &= ~BRDCS;
-  aic_outb(p, brdctl, BRDCTL);
-  udelay(4);
-  read_brdctl(p);
+    aic_outb(p, brdctl, BRDCTL);
+    udelay(1);
+  }
 }
 
 /*+F*************************************************************************
@@ -7499,10 +7504,11 @@
   unsigned char brdctl;
 
   aic_outb(p, BRDRW | BRDCS, BRDCTL);
-  udelay(4);
+  udelay(1);
   aic_outb(p, 0, BRDCTL);
-  udelay(4);
+  udelay(1);
   brdctl = aic_inb(p, BRDCTL);
+  udelay(1);
   *int_50 = !(brdctl & BRDDAT5);
   *ext_present = !(brdctl & BRDDAT6);
   *eeprom = (aic_inb(p, SPIOCAP) & EEPROM);
@@ -7611,7 +7617,6 @@
     else
       max_target = 8;
     aic_outb(p, SEEMS | SEECS, SEECTL);
-    udelay(4);
     sxfrctl1 &= ~STPWEN;
     if ( (p->adapter_control & CFAUTOTERM) ||
          (p->features & AHC_ULTRA2) )
@@ -7736,14 +7741,6 @@
                  p->host_no);
       }
 
-      if (enableLVD_high != 0)
-      {
-        brddat |= BRDDAT4;
-        if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n",
-                 p->host_no);
-      }
-          
       if (enableLVD_low != 0)
       {
         sxfrctl1 |= STPWEN;
@@ -7752,17 +7749,17 @@
           printk(KERN_INFO "(scsi%d) LVD Low byte termination Enabled\n",
                  p->host_no);
       }
-    }
-    else
-    {
-      if (p->adapter_control & CFWSTERM)
+          
+      if (enableLVD_high != 0)
       {
-        brddat |= BRDDAT6;
+        brddat |= BRDDAT4;
         if (aic7xxx_verbose & VERBOSE_PROBE2)
-          printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+          printk(KERN_INFO "(scsi%d) LVD High byte termination Enabled\n",
                  p->host_no);
       }
-
+    }
+    else
+    {
       if (p->adapter_control & CFSTERM)
       {
         if (p->features & AHC_ULTRA2)
@@ -7773,6 +7770,14 @@
           printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
                  p->host_no);
       }
+
+      if (p->adapter_control & CFWSTERM)
+      {
+        brddat |= BRDDAT6;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+                 p->host_no);
+      }
     }
     aic_outb(p, sxfrctl1, SXFRCTL1);
     write_brdctl(p, brddat);
@@ -8090,7 +8095,11 @@
     /* Select channel B */
     aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
 
-    term = (aic_inb(p, SXFRCTL1) & STPWEN);
+    if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
+      term = (aic_inb(p, SXFRCTL1) & STPWEN);
+    else
+      term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0);
+
     aic_outb(p, p->scsi_id_b, SCSIID);
     scsi_conf = aic_inb(p, SCSICONF + 1);
     aic_outb(p, DFON | SPIOEN, SXFRCTL0);
@@ -8112,7 +8121,10 @@
   {
     aic_outb(p, p->scsi_id, SCSIID);
   }
-  term = (aic_inb(p, SXFRCTL1) & STPWEN);
+  if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
+    term = (aic_inb(p, SXFRCTL1) & STPWEN);
+  else
+    term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0);
   scsi_conf = aic_inb(p, SCSICONF);
   aic_outb(p, DFON | SPIOEN, SXFRCTL0);
   aic_outb(p, (scsi_conf & ENSPCHK) | STIMESEL | term | 
@@ -9049,11 +9061,44 @@
 
 
 #if defined(__i386__) || defined(__alpha__)
+#ifdef CONFIG_PCI
+  /*
+   * PCI-bus chipset probe.
+   */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+  if (pci_present())
+  {
+    if (pci_find_device(PCI_VENDOR_ID_INTEL,
+                        PCI_DEVICE_ID_INTEL_82450GX,
+                        NULL))
+      aic7xxx_no_probe = 1;
+    if (pci_find_device(PCI_VENDOR_ID_INTEL,
+                        PCI_DEVICE_ID_INTEL_82451NX,
+                        NULL))
+      aic7xxx_no_probe = 1;
+  }
+#else
+#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca
+  if (pcibios_present())
+  {
+    unsigned char pci_bus, pci_devfn;
+    if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL,
+                              PCI_DEVICE_ID_INTEL_82450GX,
+                              0, &pci_bus, &pci_devfn)) )
+      aic7xxx_no_probe = 1;
+    if (!(pcibios_find_device(PCI_VENDOR_ID_INTEL,
+                              PCI_DEVICE_ID_INTEL_82451NX,
+                              0, &pci_bus, &pci_devfn)) )
+      aic7xxx_no_probe = 1;
+  }
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_PCI */
   /*
    * EISA/VL-bus card signature probe.
    */
   slot = MINSLOT;
-  while ( (slot <= MAXSLOT) && !(aic7xxx_no_probe) )
+  while ( (slot <= MAXSLOT) && 
+         !(aic7xxx_no_probe) )
   {
     base = SLOTBASE(slot) + MINREG;
 
@@ -9311,6 +9356,10 @@
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7860_FE,                                       7,
        32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
        AHC_AIC7860_FE,                                       7,
@@ -9489,6 +9538,23 @@
           temp_p->pci_device_fn = pdev->devfn;
           temp_p->base = pdev->base_address[0];
           temp_p->mbase = pdev->base_address[1];
+          temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
+          temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
+          current_p = list_p;
+	  while(current_p)
+	  {
+	    if ( ((current_p->pci_bus == temp_p->pci_bus) &&
+	          (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
+                  (current_p->base == temp_p->base) )
+	    {
+              /* duplicate PCI entry, skip it */
+	      kfree(temp_p);
+	      temp_p = NULL;
+	    }
+	    current_p = current_p->next;
+	  }
+	  if ( temp_p == NULL )
+            continue;
           if (aic7xxx_verbose & VERBOSE_PROBE2)
             printk("aic7xxx: <%s> at PCI %d/%d\n", 
               board_names[aic_pdevs[i].board_name_index],
@@ -9522,11 +9588,6 @@
 #else  /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
           temp_p->pci_bus = pci_bus;
           temp_p->pci_device_fn = pci_devfn;
-          if (aic7xxx_verbose & VERBOSE_PROBE2)
-            printk("aic7xxx: <%s> at PCI %d/%d\n", 
-              board_names[aic_pdevs[i].board_name_index],
-              PCI_SLOT(temp_p->pci_device_fn),
-              PCI_FUNC(temp_p->pci_device_fn));
           pcibios_read_config_byte(pci_bus, pci_devfn, PCI_INTERRUPT_LINE,
             &pci_irq);
           temp_p->irq = pci_irq;
@@ -9536,6 +9597,28 @@
           pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_1,
             &mmapbase);
           temp_p->mbase = mmapbase;
+          temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
+          temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
+          current_p = list_p;
+	  while(current_p)
+	  {
+	    if ( ((current_p->pci_bus == temp_p->pci_bus) &&
+	          (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
+                  (current_p->base == temp_p->base) )
+	    {
+              /* duplicate PCI entry, skip it */
+	      kfree(temp_p);
+	      temp_p = NULL;
+	    }
+	    current_p = current_p->next;
+	  }
+	  if ( temp_p == NULL )
+            continue;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
           pcibios_read_config_word(pci_bus, pci_devfn, PCI_COMMAND, &command);
           if (aic7xxx_verbose & VERBOSE_PROBE2)
           {
@@ -9563,12 +9646,6 @@
 #endif /* AIC7XXX_STRICT_PCI_SETUP */
 #endif /* LINUIX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
 
-          /*
-           * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
-           * we mask it off.
-           */
-          temp_p->base &= PCI_BASE_ADDRESS_IO_MASK;
-          temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
           temp_p->unpause = INTEN;
           temp_p->pause = temp_p->unpause | PAUSE;
           if ( ((temp_p->base == 0) &&
@@ -9586,6 +9663,9 @@
           }
 
 #ifdef MMAPIO
+          if ( !(temp_p->flags & AHC_MULTI_CHANNEL) ||
+               ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) &&
+                (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) )
           {
             unsigned long page_offset, base;
 
diff -u --recursive --new-file v2.3.10/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c
--- v2.3.10/linux/drivers/scsi/eata_dma.c	Tue Dec 29 11:35:48 1998
+++ linux/drivers/scsi/eata_dma.c	Tue Jul 20 16:40:30 1999
@@ -70,7 +70,6 @@
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/in.h>
-#include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <linux/delay.h>
@@ -1404,116 +1403,64 @@
 
 void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
 {
-
 #ifndef CONFIG_PCI
     printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
 #else
-    
-    u8 pci_bus, pci_device_fn;
-    static s16 pci_index = 0;	/* Device index to PCI BIOS calls */
-    u32 base = 0;
-    u16 com_adr;
-    u16 rev_device;
-    u32 error, i, x;
+    struct pci_dev *dev; 
+    u32 base, x;
     u8 pal1, pal2, pal3;
 
-    if (pci_present()) {
-	for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
-	    if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, 
-				    pci_index, &pci_bus, &pci_device_fn))
-		break;
+    for(dev=NULL; dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev);) {
 	    DBG(DBG_PROBE && DBG_PCI, 
-		printk("eata_dma: find_PCI, HBA at bus %d, device %d,"
-		       " function %d, index %d\n", (s32)pci_bus, 
-		       (s32)((pci_device_fn & 0xf8) >> 3),
-		       (s32)(pci_device_fn & 7), pci_index));
-	    
-	    if (!(error = pcibios_read_config_word(pci_bus, pci_device_fn, 
-				       PCI_CLASS_DEVICE, &rev_device))) {
-		if (rev_device == PCI_CLASS_STORAGE_SCSI) {
-		    if (!(error = pcibios_read_config_word(pci_bus, 
-					       pci_device_fn, PCI_COMMAND, 
-					       (u16 *) & com_adr))) {
-			if (!((com_adr & PCI_COMMAND_IO) && 
-			      (com_adr & PCI_COMMAND_MASTER))) {
-			    printk("eata_dma: find_PCI, HBA has IO or"
-				   " BUSMASTER mode disabled\n");
-			    continue;
-			}
-		    } else
-			printk("eata_dma: find_PCI, error %x while reading "
-			       "PCI_COMMAND\n", error);
-		} else
-		    printk("eata_dma: find_PCI, DEVICECLASSID %x didn't match\n", 
-			   rev_device);
-	    } else {
-		printk("eata_dma: find_PCI, error %x while reading "
-		       "PCI_CLASS_BASE\n", 
-		       error);
+		printk("eata_dma: find_PCI, HBA at %s\n", dev->name));
+	    pci_set_master(dev);
+	    base = dev->base_address[0];
+	    if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) {
+		printk("eata_dma: invalid base address of device %s\n", dev->name);
 		continue;
 	    }
-	    
-	    if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn,
-				       PCI_BASE_ADDRESS_0, (int *) &base))){
-		
-		/* Check if the address is valid */
-		if (base & 0x01) {
-		    base &= 0xfffffffe;
-                    /* EISA tag there ? */
-		    pal1 = inb(base);
-		    pal2 = inb(base + 1);
-		    pal3 = inb(base + 2);
-		    if (((pal1 == DPT_ID1) && (pal2 == DPT_ID2)) ||
-			((pal1 == NEC_ID1) && (pal2 == NEC_ID2) && 
-			 (pal3 == NEC_ID3)) ||
-			((pal1 == ATT_ID1) && (pal2 == ATT_ID2) && 
-			 (pal3 == ATT_ID3)))
-			base += 0x08;
-		    else
-			base += 0x10;   /* Now, THIS is the real address */
-
-		    if (base != 0x1f8) {
-			/* We didn't find it in the primary search */
-			if (get_conf_PIO(base, buf) == TRUE) {
-
-			    /* OK. We made it till here, so we can go now  
-			     * and register it. We  only have to check and 
-			     * eventually remove it from the EISA and ISA list 
-			     */
-			    DBG(DBG_PCI, printk("Registering PCI HBA\n"));
-			    register_HBA(base, buf, tpnt, IS_PCI);
-			    
-			    if (base < 0x1000) {
-				for (x = 0; x < MAXISA; ++x) {
-				    if (ISAbases[x] == base) {
-					ISAbases[x] = 0;
-					break;
-				    }
-				}
-			    } else if ((base & 0x0fff) == 0x0c88) 
-				EISAbases[(base >> 12) & 0x0f] = 0;
-			    continue;  /* break; */
-			} 
-#if CHECK_BLINK
-			else if (check_blink_state(base) == TRUE) {
-			    printk("eata_dma: HBA is in BLINK state.\n"
-				   "Consult your HBAs manual to correct this.\n");
+	    base &= PCI_BASE_ADDRESS_IO_MASK;
+            /* EISA tag there ? */
+	    pal1 = inb(base);
+	    pal2 = inb(base + 1);
+	    pal3 = inb(base + 2);
+	    if (((pal1 == DPT_ID1) && (pal2 == DPT_ID2)) ||
+		((pal1 == NEC_ID1) && (pal2 == NEC_ID2) && 
+		(pal3 == NEC_ID3)) ||
+		((pal1 == ATT_ID1) && (pal2 == ATT_ID2) && 
+		(pal3 == ATT_ID3)))
+		base += 0x08;
+	    else
+		base += 0x10;   /* Now, THIS is the real address */
+	    if (base != 0x1f8) {
+		/* We didn't find it in the primary search */
+		if (get_conf_PIO(base, buf) == TRUE) {
+		    /* OK. We made it till here, so we can go now  
+		     * and register it. We only have to check and 
+		     * eventually remove it from the EISA and ISA list 
+		     */
+		    DBG(DBG_PCI, printk("Registering PCI HBA\n"));
+		    register_HBA(base, buf, tpnt, IS_PCI);
+		    
+		    if (base < 0x1000) {
+			for (x = 0; x < MAXISA; ++x) {
+			    if (ISAbases[x] == base) {
+				ISAbases[x] = 0;
+				break;
+			    }
 			}
-#endif
-		    }
+		    } else if ((base & 0x0fff) == 0x0c88) 
+			EISAbases[(base >> 12) & 0x0f] = 0;
+		} 
+#if CHECK_BLINK
+		else if (check_blink_state(base) == TRUE) {
+		    printk("eata_dma: HBA is in BLINK state.\n"
+			   "Consult your HBAs manual to correct this.\n");
 		}
-	    } else {
-		printk("eata_dma: error %x while reading "
-		       "PCI_BASE_ADDRESS_0\n", error);
+#endif
 	    }
 	}
-    } else {
-	printk("eata_dma: No BIOS32 extensions present. This driver release "
-	       "still depends on it.\n"
-	       "	  Skipping scan for PCI HBAs. \n");
-    }
 #endif /* #ifndef CONFIG_PCI */
-    return;
 }
 
 int eata_detect(Scsi_Host_Template * tpnt)
diff -u --recursive --new-file v2.3.10/linux/drivers/scsi/eata_pio.c linux/drivers/scsi/eata_pio.c
--- v2.3.10/linux/drivers/scsi/eata_pio.c	Tue Dec 29 11:35:48 1998
+++ linux/drivers/scsi/eata_pio.c	Tue Jul 20 16:40:30 1999
@@ -45,7 +45,6 @@
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/in.h>
-#include <linux/bios32.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
 #include <asm/io.h>
@@ -881,100 +880,60 @@
 
 void find_pio_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
 {
-
 #ifndef CONFIG_PCI
-    printk(KERN_ERR "eata_pio: kernel PCI support not enabled. Skipping scan "
-           "for PCI HBAs.\n");
+    printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
 #else
-    
-    u8 pci_bus, pci_device_fn;
-    static s16 pci_index = 0;   /* Device index to PCI BIOS calls */
-    u32 base = 0;
-    u16 com_adr;
-    u16 rev_device;
-    u32 error, i, x;
-
-    if (pci_present()) {
-	for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
-	    if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, 
-				    pci_index, &pci_bus, &pci_device_fn))
-		break;
+    struct pci_dev *dev; 
+    u32 base, x;
+
+    for(dev=NULL; dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev);) {
 	    DBG(DBG_PROBE && DBG_PCI, 
-		printk("eata_pio: HBA at bus %d, device %d,"
-		       " function %d, index %d\n", (s32)pci_bus, 
-		       (s32)((pci_device_fn & 0xf8) >> 3),
-		       (s32)(pci_device_fn & 7), pci_index));
-	    
-	    if (!(error = pcibios_read_config_word(pci_bus, pci_device_fn, 
-				       PCI_CLASS_DEVICE, &rev_device))) {
-		if (rev_device == PCI_CLASS_STORAGE_SCSI) {
-		    if (!(error = pcibios_read_config_word(pci_bus, 
-					       pci_device_fn, PCI_COMMAND, 
-					       (u16 *) & com_adr))) {
-			if (!((com_adr & PCI_COMMAND_IO) && 
-			      (com_adr & PCI_COMMAND_MASTER))) {
-			    printk("HBA has IO or BUSMASTER mode disabled\n");
-			    continue;
-			}
-		    } else
-			printk("eata_pio: error %x while reading "
-			       "PCI_COMMAND\n", error);
-		} else
-		    printk("DEVICECLASSID %x didn't match\n", rev_device);
-	    } else {
-		printk("eata_pio: error %x while reading PCI_CLASS_BASE\n", 
-		       error);
+		printk("eata_pio: find_PCI, HBA at %s\n", dev->name));
+	    pci_set_master(dev);
+	    base = dev->base_address[0];
+	    if (!(base & PCI_BASE_ADDRESS_SPACE_IO)) {
+		printk("eata_pio: invalid base address of device %s\n", dev->name);
 		continue;
 	    }
-	    
-	    if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn,
-				       PCI_BASE_ADDRESS_0, (int *) &base))){
-		
-		/* Check if the address is valid */
-		if (base & 0x01) {
-		    base &= 0xfffffffe;
-		    /* EISA tag there ? */
-		    if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
-			continue;   /* Jep, it's forced, so move on  */
-		    base += 0x10;   /* Now, THIS is the real address */
-		    if (base != 0x1f8) {
-			/* We didn't find it in the primary search */
-			if (get_pio_conf_PIO(base, buf) == TRUE) {
-			    if (buf->FORCADR)   /* If the address is forced */
-				continue;       /* we'll find it later      */
-			    
-			    /* OK. We made it till here, so we can go now  
-			     * and register it. We  only have to check and 
-			     * eventually remove it from the EISA and ISA list 
-			     */
-			    
-			    register_pio_HBA(base, buf, tpnt);
-			    
-			    if (base < 0x1000) {
-				for (x = 0; x < MAXISA; ++x) {
-				    if (ISAbases[x] == base) {
-					ISAbases[x] = 0;
-					break;
-				    }
-				}
-			    } else if ((base & 0x0fff) == 0x0c88) {
-				x = (base >> 12) & 0x0f;
-				EISAbases[x] = 0;
+	    base &= PCI_BASE_ADDRESS_IO_MASK;
+            /* EISA tag there ? */
+	    if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
+		continue;   /* Jep, it's forced, so move on  */
+	    base += 0x10;   /* Now, THIS is the real address */
+	    if (base != 0x1f8) {
+		/* We didn't find it in the primary search */
+		if (get_pio_conf_PIO(base, buf) == TRUE) {
+		    if (buf->FORCADR)   /* If the address is forced */
+			continue;       /* we'll find it later      */
+		    
+		    /* OK. We made it till here, so we can go now  
+		     * and register it. We  only have to check and 
+		     * eventually remove it from the EISA and ISA list 
+		     */
+		    
+		    register_pio_HBA(base, buf, tpnt);
+		    
+		    if (base < 0x1000) {
+			for (x = 0; x < MAXISA; ++x) {
+			    if (ISAbases[x] == base) {
+				ISAbases[x] = 0;
+				break;
 			    }
-			    continue;  /* break; */
 			}
+		    } else if ((base & 0x0fff) == 0x0c88) {
+			x = (base >> 12) & 0x0f;
+			EISAbases[x] = 0;
 		    }
+		} 
+#if CHECK_BLINK
+		else if (check_blink_state(base) == TRUE) {
+		    printk("eata_pio: HBA is in BLINK state.\n"
+			   "Consult your HBAs manual to correct this.\n");
 		}
-	    } else
-		printk("eata_pio: error %x while reading "
-		       "PCI_BASE_ADDRESS_0\n", error);
+#endif
+	    }
 	}
-    } else
-	printk("eata_pio: No BIOS32 extensions present. This driver release "
-	       "still depends on it.\n"
-	       "          Skipping scan for PCI HBAs.\n");
 #endif /* #ifndef CONFIG_PCI */
-    return;
 }
 
 
diff -u --recursive --new-file v2.3.10/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.3.10/linux/drivers/sgi/char/shmiq.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/sgi/char/shmiq.c	Fri Jul 16 09:27:46 1999
@@ -214,6 +214,8 @@
 			goto bad_file;
 
 		v = shmiq_manage_file (file);
+		if (v<0)
+			fput(file);
 		return v;
 
 		/*
diff -u --recursive --new-file v2.3.10/linux/drivers/sound/awacs_defs.h linux/drivers/sound/awacs_defs.h
--- v2.3.10/linux/drivers/sound/awacs_defs.h	Wed Mar 10 21:48:46 1999
+++ linux/drivers/sound/awacs_defs.h	Mon Jul 12 16:21:25 1999
@@ -70,8 +70,8 @@
 #define MASK_GAINMIC	(0x0 << 8)	/* Change Gain for Mic??? */
 
 #define MASK_MUX_CD	(0x1 << 9)	/* Select CD in MUX */
-#define MASK_MUX_MIC	(0x1 << 10)	/* Select Mic in MUX */
-#define MASK_MUX_AUDIN	(0x1 << 11)	/* Select Audio In in MUX */
+#define MASK_MUX_AUDIN	(0x1 << 10)	/* Select Audio In in MUX */
+#define MASK_MUX_MIC	(0x1 << 11)	/* Select Mic in MUX */
 #define MASK_MUX_LINE	MASK_MUX_AUDIN
 
 #define GAINRIGHT(x)	((x) & MASK_GAINRIGHT)
diff -u --recursive --new-file v2.3.10/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.3.10/linux/drivers/sound/dmasound.c	Mon Jun  7 12:12:22 1999
+++ linux/drivers/sound/dmasound.c	Mon Jul 12 16:21:25 1999
@@ -131,7 +131,7 @@
 static int irq_installed = 0;
 #endif /* MODULE */
 static char **sound_buffers = NULL;
-
+static char **sound_read_buffers = NULL;
 
 #ifdef CONFIG_ATARI
 extern void atari_microwire_cmd(int cmd);
@@ -184,6 +184,9 @@
 static void *awacs_tx_cmd_space;
 static volatile struct dbdma_cmd *awacs_tx_cmds;
 
+static void *awacs_rx_cmd_space;
+static volatile struct dbdma_cmd *awacs_rx_cmds;
+
 /*
  * Cached values of AWACS registers (we can't read them).
  * Except on the burgundy. XXX
@@ -239,6 +242,7 @@
 
 static int beep_volume = BEEP_VOLUME;
 static int beep_playing = 0;
+static int awacs_beep_state = 0;
 static short *beep_buf;
 static volatile struct dbdma_cmd *beep_dbdma_cmd;
 static void (*orig_mksound)(unsigned int, unsigned int);
@@ -276,10 +280,15 @@
 #define MIN_BUFSIZE 		4
 #define MAX_BUFSIZE		128	/* Limit for Amiga */
 
-static int catchRadius = 0, numBufs = 4, bufSize = 32;
+static int catchRadius = 0;
+static int numBufs = 4, bufSize = 32;
+static int numReadBufs = 4, readbufSize = 32;
+
 MODULE_PARM(catchRadius, "i");
 MODULE_PARM(numBufs, "i");
 MODULE_PARM(bufSize, "i");
+MODULE_PARM(numreadBufs, "i");
+MODULE_PARM(readbufSize, "i");
 
 #define arraysize(x)	(sizeof(x)/sizeof(*(x)))
 #define min(x, y)	((x) < (y) ? (x) : (y))
@@ -630,6 +639,12 @@
 static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount,
 			    u_char frame[], ssize_t *frameUsed,
 			    ssize_t frameLeft);
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft);
 #endif /* CONFIG_PPC */
 
 /*** Machine definitions *****************************************************/
@@ -681,6 +696,9 @@
 	SETTINGS soft;		/* software settings */
 	SETTINGS dsp;		/* /dev/dsp default settings */
 	TRANS *trans;		/* supported translations */
+#if defined(CONFIG_PPC)
+	TRANS *read_trans;	/* supported translations */
+#endif
 	int volume_left;	/* volume (range is machine dependent) */
 	int volume_right;
 	int bass;		/* tone (range is machine dependent) */
@@ -746,9 +764,11 @@
 static void PMacSilence(void);
 static void PMacInit(void);
 static void PMacPlay(void);
+static void PMacRecord(void);
 static int PMacSetFormat(int format);
 static int PMacSetVolume(int volume);
 static void pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
+static void pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
 static void pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
 static void awacs_write(int val);
 static int awacs_get_volume(int reg, int lshift);
@@ -776,6 +796,10 @@
 				    size_t userCount,
 				    u_char frame[], ssize_t *frameUsed,
 				    ssize_t frameLeft);
+static ssize_t sound_copy_translate_read(const u_char *userPtr,
+				    size_t userCount,
+				    u_char frame[], ssize_t *frameUsed,
+				    ssize_t frameLeft);
 
 
 /*
@@ -809,8 +833,8 @@
 	 *	Amiga: Bit 0 is set: a frame is loaded
 	 *	       Bit 1 is set: a frame is playing
 	 */
-	int playing;
-	wait_queue_head_t write_queue, open_queue, sync_queue;
+	int active;
+	wait_queue_head_t action_queue, open_queue, sync_queue;
 	int open_mode;
 	int busy, syncing;
 #ifdef CONFIG_ATARI
@@ -822,6 +846,7 @@
 };
 
 static struct sound_queue sq;
+static struct sound_queue read_sq;
 
 #define sq_block_address(i)	(sq.buffers[i])
 #define SIGNAL_RECEIVED	(signal_pending(current))
@@ -2172,6 +2197,135 @@
 	return stereo? utotal * 4: utotal * 2;
 }
 
+static ssize_t pmac_ct_s8_read(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = sound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+
+		val = *p++;
+		data = val >> 8;
+		if (put_user(data, (u_char *)userPtr++))
+			return -EFAULT;
+		if (stereo) {
+			val = *p;
+			data = val >> 8;
+			if (put_user(data, (u_char *)userPtr++))
+				return -EFAULT;
+		}
+		p++;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_u8_read(const u_char *userPtr, size_t userCount,
+			  u_char frame[], ssize_t *frameUsed,
+			  ssize_t frameLeft)
+{
+	ssize_t count, used;
+	short *p = (short *) &frame[*frameUsed];
+	int val, stereo = sound.soft.stereo;
+
+	frameLeft >>= 2;
+	if (stereo)
+		userCount >>= 1;
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		u_char data;
+
+		val = *p++;
+		data = (val >> 8) ^ 0x80;
+		if (put_user(data, (u_char *)userPtr++))
+			return -EFAULT;
+		if (stereo) {
+			val = *p;
+			data = (val >> 8) ^ 0x80;
+			if (put_user(data, (u_char *)userPtr++))
+				return -EFAULT;
+		}
+		p++;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 2: used;
+}
+
+
+static ssize_t pmac_ct_s16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	ssize_t count, used;
+	int stereo = sound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	used = count = min(userCount, frameLeft);
+	if (!stereo) {
+		short *up = (short *) userPtr;
+		while (count > 0) {
+			short data;
+			data = *fp;
+			if (put_user(data, up++))
+				return -EFAULT;
+			fp+=2;
+			count--;
+		}
+	} else {
+		if (copy_to_user((u_char *)userPtr, fp, count * 4))
+			return -EFAULT;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 4: used * 2;
+}
+
+static ssize_t pmac_ct_u16_read(const u_char *userPtr, size_t userCount,
+			   u_char frame[], ssize_t *frameUsed,
+			   ssize_t frameLeft)
+{
+	ssize_t count, used;
+	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+	int stereo = sound.soft.stereo;
+	short *fp = (short *) &frame[*frameUsed];
+	short *up = (short *) userPtr;
+
+	frameLeft >>= 2;
+	userCount >>= (stereo? 2: 1);
+	used = count = min(userCount, frameLeft);
+	while (count > 0) {
+		int data;
+
+		data = *fp++;
+		data ^= mask;
+		if (put_user(data, up++))
+			return -EFAULT;
+		if (stereo) {
+			data = *fp;
+			data ^= mask;
+			if (put_user(data, up++))
+				return -EFAULT;
+		}
+		fp++;
+		count--;
+	}
+	*frameUsed += used * 4;
+	return stereo? used * 4: used * 2;
+}
+
+
 #endif /* CONFIG_PPC */
 
 
@@ -2212,6 +2366,11 @@
 	pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8,
 	pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16
 };
+
+static TRANS transAwacsNormalRead = {
+	NULL, NULL, pmac_ct_s8_read, pmac_ct_u8_read,
+	pmac_ct_s16_read, pmac_ct_u16_read, pmac_ct_s16_read, pmac_ct_u16_read
+};
 #endif /* CONFIG_PPC */
 
 /*** Low level stuff *********************************************************/
@@ -2574,18 +2733,18 @@
 	/* Since only an even number of samples per frame can
 	   be played, we might lose one byte here. (TO DO) */
 	sq.front = (sq.front+1) % sq.max_count;
-	sq.playing++;
+	sq.active++;
 	tt_dmasnd.ctrl = DMASND_CTRL_ON | DMASND_CTRL_REPEAT;
 }
 
 
 static void AtaPlay(void)
 {
-	/* ++TeSche: Note that sq.playing is no longer just a flag but holds
+	/* ++TeSche: Note that sq.active is no longer just a flag but holds
 	 * the number of frames the DMA is currently programmed for instead,
 	 * may be 0, 1 (currently being played) or 2 (pre-programmed).
 	 *
-	 * Changes done to sq.count and sq.playing are a bit more subtle again
+	 * Changes done to sq.count and sq.active are a bit more subtle again
 	 * so now I must admit I also prefer disabling the irq here rather
 	 * than considering all possible situations. But the point is that
 	 * disabling the irq doesn't have any bad influence on this version of
@@ -2596,13 +2755,13 @@
 	 */
 	atari_disable_irq(IRQ_MFP_TIMA);
 
-	if (sq.playing == 2 ||	/* DMA is 'full' */
+	if (sq.active == 2 ||	/* DMA is 'full' */
 	    sq.count <= 0) {	/* nothing to do */
 		atari_enable_irq(IRQ_MFP_TIMA);
 		return;
 	}
 
-	if (sq.playing == 0) {
+	if (sq.active == 0) {
 		/* looks like there's nothing 'in' the DMA yet, so try
 		 * to put two frames into it (at least one is available).
 		 */
@@ -2650,7 +2809,7 @@
 #if 0
 	/* ++TeSche: if you should want to test this... */
 	static int cnt = 0;
-	if (sq.playing == 2)
+	if (sq.active == 2)
 		if (++cnt == 10) {
 			/* simulate losing an interrupt */
 			cnt = 0;
@@ -2667,7 +2826,7 @@
 		return;
 	}
 
-	if (!sq.playing) {
+	if (!sq.active) {
 		/* playing was interrupted and sq_reset() has already cleared
 		 * the sq variables, so better don't do anything here.
 		 */
@@ -2683,29 +2842,29 @@
 	 * as soon as the irq gets through.
 	 */
 	sq.count--;
-	sq.playing--;
+	sq.active--;
 
-	if (!sq.playing) {
+	if (!sq.active) {
 		tt_dmasnd.ctrl = DMASND_CTRL_OFF;
 		sq.ignore_int = 1;
 	}
 
-	WAKE_UP(sq.write_queue);
+	WAKE_UP(sq.action_queue);
 	/* At least one block of the queue is free now
 	   so wake up a writing process blocked because
 	   of a full queue. */
 
-	if ((sq.playing != 1) || (sq.count != 1))
+	if ((sq.active != 1) || (sq.count != 1))
 		/* We must be a bit carefully here: sq.count indicates the
 		 * number of buffers used and not the number of frames to
-		 * be played. If sq.count==1 and sq.playing==1 that means
+		 * be played. If sq.count==1 and sq.active==1 that means
 		 * the only remaining frame was already programmed earlier
 		 * (and is currently running) so we mustn't call AtaPlay()
 		 * here, otherwise we'll play one frame too much.
 		 */
 		AtaPlay();
 
-	if (!sq.playing) WAKE_UP(sq.sync_queue);
+	if (!sq.active) WAKE_UP(sq.sync_queue);
 	/* We are not playing after AtaPlay(), so there
 	   is nothing to play any more. Wake up a process
 	   waiting for audio output to drain. */
@@ -2902,7 +3061,7 @@
 			custom.dmacon = AMI_AUDIO_8;
 	}
 	sq.front = (sq.front+1) % sq.max_count;
-	sq.playing |= AMI_PLAY_LOADED;
+	sq.active |= AMI_PLAY_LOADED;
 }
 
 
@@ -2912,13 +3071,13 @@
 
 	custom.intena = IF_AUD0;
 
-	if (sq.playing & AMI_PLAY_LOADED) {
+	if (sq.active & AMI_PLAY_LOADED) {
 		/* There's already a frame loaded */
 		custom.intena = IF_SETCLR | IF_AUD0;
 		return;
 	}
 
-	if (sq.playing & AMI_PLAY_PLAYING)
+	if (sq.active & AMI_PLAY_PLAYING)
 		/* Increase threshold: frame 1 is already being played */
 		minframes = 2;
 
@@ -2946,7 +3105,7 @@
 {
 	int minframes = 1;
 
-	if (!sq.playing) {
+	if (!sq.active) {
 		/* Playing was interrupted and sq_reset() has already cleared
 		 * the sq variables, so better don't do anything here.
 		 */
@@ -2954,20 +3113,20 @@
 		return;
 	}
 
-	if (sq.playing & AMI_PLAY_PLAYING) {
+	if (sq.active & AMI_PLAY_PLAYING) {
 		/* We've just finished a frame */
 		sq.count--;
-		WAKE_UP(sq.write_queue);
+		WAKE_UP(sq.action_queue);
 	}
 
-	if (sq.playing & AMI_PLAY_LOADED)
+	if (sq.active & AMI_PLAY_LOADED)
 		/* Increase threshold: frame 1 is already being played */
 		minframes = 2;
 
 	/* Shift the flags */
-	sq.playing = (sq.playing<<1) & AMI_PLAY_MASK;
+	sq.active = (sq.active<<1) & AMI_PLAY_MASK;
 
-	if (!sq.playing)
+	if (!sq.active)
 		/* No frame is playing, disable audio DMA */
 		custom.dmacon = AMI_AUDIO_OFF;
 
@@ -2975,7 +3134,7 @@
 		/* Try to play the next frame */
 		AmiPlay();
 
-	if (!sq.playing)
+	if (!sq.active)
 		/* Nothing to play anymore.
 		   Wake up a process waiting for audio output to drain. */
 		WAKE_UP(sq.sync_queue);
@@ -3001,7 +3160,8 @@
 static int __init PMacIrqInit(void)
 {
 	if (request_irq(awacs_irq, pmac_awacs_intr, 0, "AWACS", 0)
-	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0))
+	    || request_irq(awacs_tx_irq, pmac_awacs_tx_intr, 0, "AWACS out", 0)
+	    || request_irq(awacs_rx_irq, pmac_awacs_rx_intr, 0, "AWACS in", 0))
 		return 0;
 	return 1;
 }
@@ -3015,7 +3175,10 @@
 	out_le32(&awacs->control, in_le32(&awacs->control) & 0xfff);
 	free_irq(awacs_irq, pmac_awacs_intr);
 	free_irq(awacs_tx_irq, pmac_awacs_tx_intr);
+	free_irq(awacs_rx_irq, pmac_awacs_rx_intr);
 	kfree(awacs_tx_cmd_space);
+	if (awacs_rx_cmd_space)
+		kfree(awacs_rx_cmd_space);
 	if (beep_buf)
 		kfree(beep_buf);
 	kd_mksound = orig_mksound;
@@ -3065,10 +3228,10 @@
 		sound.trans = &transAwacsNormal;
 	else
 		sound.trans = &transAwacsExpand;
+	sound.read_trans = &transAwacsNormalRead;
 	sound.hard.speed = awacs_freqs[i];
 	awacs_rate_index = i;
 
-	PMacSilence();
 	/* XXX disable error interrupt on burgundy for now */
 	out_le32(&awacs->control, MASK_IEPC | (i << 8) | 0x11
 		 | (awacs_revision < AWACS_BURGUNDY? MASK_IEE: 0));
@@ -3076,6 +3239,18 @@
 	awacs_write(awacs_reg[1] | MASK_ADDR1);
 	out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
 
+	/* We really want to execute a DMA stop command, after the AWACS
+	 * is initialized.
+	 * For reasons I don't understand, it stops the hissing noise
+	 * common to many PowerBook G3 systems (like mine :-).  Maybe it
+	 * is just the AWACS control register change......
+	 */
+	out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
+	st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
+	out_le32(&awacs->control, (in_le32(&awacs->control) & ~0x1f00));
+	out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
+	out_le32(&awacs_txdma->control, RUN | (RUN << 16));
+
 	sound.bal = -sound.soft.speed;
 }
 
@@ -3163,20 +3338,23 @@
 	unsigned long flags;
 
 	save_flags(flags); cli();
-	if (beep_playing) {
+	if (awacs_beep_state) {
 		/* sound takes precedence over beeps */
 		out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
 		out_le32(&awacs->control,
 			 (in_le32(&awacs->control) & ~0x1f00)
-			 || (awacs_rate_index << 8));
+			 | (awacs_rate_index << 8));
 		out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
+		out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));
+
 		beep_playing = 0;
+		awacs_beep_state = 0;
 	}
-	i = sq.front + sq.playing;
+	i = sq.front + sq.active;
 	if (i >= sq.max_count)
 		i -= sq.max_count;
-	while (sq.playing < 2 && sq.playing < sq.count) {
-		count = (sq.count == sq.playing + 1)? sq.rear_size: sq.block_size;
+	while (sq.active < 2 && sq.active < sq.count) {
+		count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;
 		if (count < sq.block_size && !sq.syncing)
 			/* last block not yet filled, and we're not syncing. */
 			break;
@@ -3187,14 +3365,33 @@
 			i = 0;
 		out_le16(&awacs_tx_cmds[i].command, DBDMA_STOP);
 		out_le16(&cp->command, OUTPUT_MORE + INTR_ALWAYS);
-		if (sq.playing == 0)
+		if (sq.active == 0)
 			out_le32(&awacs_txdma->cmdptr, virt_to_bus(cp));
 		out_le32(&awacs_txdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
-		++sq.playing;
+		++sq.active;
 	}
 	restore_flags(flags);
 }
 
+
+static void PMacRecord(void)
+{
+	unsigned long flags;
+
+	if (read_sq.active)
+		return;
+
+	save_flags(flags); cli();
+
+	/* This is all we have to do......Just start it up.
+	*/
+	out_le32(&awacs_rxdma->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+	read_sq.active = 1;
+
+        restore_flags(flags);
+}
+
+
 static void
 pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
 {
@@ -3202,26 +3399,78 @@
 	int stat;
 	volatile struct dbdma_cmd *cp;
 
-	while (sq.playing > 0) {
+	while (sq.active > 0) {
 		cp = &awacs_tx_cmds[i];
 		stat = ld_le16(&cp->xfer_status);
 		if ((stat & ACTIVE) == 0)
 			break;	/* this frame is still going */
 		--sq.count;
-		--sq.playing;
+		--sq.active;
 		if (++i >= sq.max_count)
 			i = 0;
 	}
 	if (i != sq.front)
-		WAKE_UP(sq.write_queue);
+		WAKE_UP(sq.action_queue);
 	sq.front = i;
 
 	PMacPlay();
 
-	if (!sq.playing)
+	if (!sq.active)
 		WAKE_UP(sq.sync_queue);
 }
 
+
+static void
+pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
+{
+
+	/* For some reason on my PowerBook G3, I get one interrupt
+	 * when the interrupt vector is installed (like something is
+	 * pending).  This happens before the dbdma is initialize by
+	 * us, so I just check the command pointer and if it is zero,
+	 * just blow it off.
+	 */
+	if (in_le32(&awacs_rxdma->cmdptr) == 0)
+		return;
+	
+	/* We also want to blow 'em off when shutting down.
+	*/
+	if (read_sq.active == 0)
+		return;
+
+	/* Check multiple buffers in case we were held off from
+	 * interrupt processing for a long time.  Geeze, I really hope
+	 * this doesn't happen.
+	 */
+	while (awacs_rx_cmds[read_sq.rear].xfer_status) {
+
+		/* Clear status and move on to next buffer.
+		*/
+		awacs_rx_cmds[read_sq.rear].xfer_status = 0;
+		read_sq.rear++;
+
+		/* Wrap the buffer ring.
+		*/
+		if (read_sq.rear >= read_sq.max_active)
+			read_sq.rear = 0;
+
+		/* If we have caught up to the front buffer, bump it.
+		 * This will cause weird (but not fatal) results if the
+		 * read loop is currently using this buffer.  The user is
+		 * behind in this case anyway, so weird things are going
+		 * to happen.
+		 */
+		if (read_sq.rear == read_sq.front) {
+			read_sq.front++;
+			if (read_sq.front >= read_sq.max_active)
+				read_sq.front = 0;
+		}
+	}
+
+	WAKE_UP(read_sq.action_queue);
+}
+
+
 static void
 pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
 {
@@ -3294,7 +3543,7 @@
 		beep_timer.expires = jiffies + ticks;
 		add_timer(&beep_timer);
 	}
-	if (beep_playing || sq.playing || beep_buf == NULL) {
+	if (beep_playing || sq.active || beep_buf == NULL) {
 		restore_flags(flags);
 		return;		/* too hard, sorry :-( */
 	}
@@ -3324,6 +3573,7 @@
 	st_le16(&beep_dbdma_cmd->xfer_status, 0);
 	st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
 	st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
+	awacs_beep_state = 1;
 
 	save_flags(flags); cli();
 	if (beep_playing) {	/* i.e. haven't been terminated already */
@@ -3781,6 +4031,45 @@
 		return 0;
 }
 
+static ssize_t sound_copy_translate_read(const u_char *userPtr,
+				    size_t userCount,
+				    u_char frame[], ssize_t *frameUsed,
+				    ssize_t frameLeft)
+{
+	ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
+
+	switch (sound.soft.format) {
+	case AFMT_MU_LAW:
+		ct_func = sound.read_trans->ct_ulaw;
+		break;
+	case AFMT_A_LAW:
+		ct_func = sound.read_trans->ct_alaw;
+		break;
+	case AFMT_S8:
+		ct_func = sound.read_trans->ct_s8;
+		break;
+	case AFMT_U8:
+		ct_func = sound.read_trans->ct_u8;
+		break;
+	case AFMT_S16_BE:
+		ct_func = sound.read_trans->ct_s16be;
+		break;
+	case AFMT_U16_BE:
+		ct_func = sound.read_trans->ct_u16be;
+		break;
+	case AFMT_S16_LE:
+		ct_func = sound.read_trans->ct_s16le;
+		break;
+	case AFMT_U16_LE:
+		ct_func = sound.read_trans->ct_u16le;
+		break;
+	}
+	if (ct_func)
+		return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
+	else
+		return 0;
+}
+
 
 /*
  * /dev/mixer abstraction
@@ -3999,7 +4288,8 @@
 				data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
 					| SOUND_MASK_LINE | SOUND_MASK_MIC
 					| SOUND_MASK_CD | SOUND_MASK_RECLEV
-					| SOUND_MASK_ALTPCM;
+					| SOUND_MASK_ALTPCM
+					| SOUND_MASK_MONITOR;
 				return IOCTL_OUT(arg, data);
 			case SOUND_MIXER_READ_RECMASK:
 				data = SOUND_MASK_LINE | SOUND_MASK_MIC
@@ -4013,20 +4303,27 @@
 					data |= SOUND_MASK_MIC;
 				if (awacs_reg[0] & MASK_MUX_CD)
 					data |= SOUND_MASK_CD;
+				if (awacs_reg[1] & MASK_LOOPTHRU)
+					data |= SOUND_MASK_MONITOR;
 				return IOCTL_OUT(arg, data);
 			case SOUND_MIXER_WRITE_RECSRC:
 				IOCTL_IN(arg, data);
 				data &= (SOUND_MASK_LINE
-					 | SOUND_MASK_MIC | SOUND_MASK_CD);
+					 | SOUND_MASK_MIC | SOUND_MASK_CD
+					 | SOUND_MASK_MONITOR);
 				awacs_reg[0] &= ~(MASK_MUX_CD | MASK_MUX_MIC
 						  | MASK_MUX_AUDIN);
+				awacs_reg[1] &= ~MASK_LOOPTHRU;
 				if (data & SOUND_MASK_LINE)
 					awacs_reg[0] |= MASK_MUX_AUDIN;
 				if (data & SOUND_MASK_MIC)
 					awacs_reg[0] |= MASK_MUX_MIC;
 				if (data & SOUND_MASK_CD)
 					awacs_reg[0] |= MASK_MUX_CD;
+				if (data & SOUND_MASK_MONITOR)
+					awacs_reg[1] |= MASK_LOOPTHRU;
 				awacs_write(awacs_reg[0] | MASK_ADDR0);
+				awacs_write(awacs_reg[1] | MASK_ADDR1);
 				return IOCTL_OUT(arg, data);
 			case SOUND_MIXER_READ_STEREODEVS:
 				data = SOUND_MASK_VOLUME | SOUND_MASK_SPEAKER
@@ -4347,7 +4644,61 @@
 }
 
 
-static void sq_setup(int numBufs, int bufSize, char **buffers)
+static int sq_allocate_read_buffers(void)
+{
+	int i;
+	int j;
+
+	if (sound_read_buffers)
+		return 0;
+	sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL);
+	if (!sound_read_buffers)
+		return -ENOMEM;
+	for (i = 0; i < numBufs; i++) {
+		sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10,
+							      GFP_KERNEL);
+		if (!sound_read_buffers[i]) {
+			while (i--)
+				sound.mach.dma_free (sound_read_buffers[i],
+						     readbufSize << 10);
+			kfree (sound_read_buffers);
+			sound_read_buffers = 0;
+			return -ENOMEM;
+		}
+		/* XXXX debugging code */
+		for (j=0; j<readbufSize; j++) {
+			sound_read_buffers[i][j] = 0xef;
+		}
+	}
+	return 0;
+}
+
+static void sq_release_read_buffers(void)
+{
+	int i;
+	volatile struct dbdma_cmd *cp;
+	
+
+	if (sound_read_buffers) {
+
+#if CONFIG_PPC
+		cp = awacs_rx_cmds;
+		for (i = 0; i < numReadBufs; i++,cp++) {
+			st_le16(&cp->command, DBDMA_STOP);
+		}
+		/* We should probably wait for the thing to stop before we
+		   release the memory */
+#endif
+		for (i = 0; i < numBufs; i++)
+			sound.mach.dma_free (sound_read_buffers[i],
+					     bufSize << 10);
+		kfree (sound_read_buffers);
+		sound_read_buffers = 0;
+	}
+}
+
+
+static void sq_setup(int numBufs, int bufSize, char **write_buffers)
 {
 #ifdef CONFIG_PPC
 	int i;
@@ -4357,12 +4708,12 @@
 	sq.max_count = numBufs;
 	sq.max_active = numBufs;
 	sq.block_size = bufSize;
-	sq.buffers = buffers;
+	sq.buffers = write_buffers;
 
 	sq.front = sq.count = 0;
 	sq.rear = -1;
 	sq.syncing = 0;
-	sq.playing = 0;
+	sq.active = 0;
 
 #ifdef CONFIG_ATARI
 	sq.ignore_int = 0;
@@ -4375,7 +4726,7 @@
 	cp = awacs_tx_cmds;
 	memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
 	for (i = 0; i < numBufs; ++i, ++cp) {
-		st_le32(&cp->phy_addr, virt_to_bus(buffers[i]));
+		st_le32(&cp->phy_addr, virt_to_bus(write_buffers[i]));
 	}
 	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
 	st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds));
@@ -4384,6 +4735,59 @@
 #endif /* CONFIG_PPC */
 }
 
+static void read_sq_setup(int numBufs, int bufSize, char **read_buffers)
+{
+#ifdef CONFIG_PPC
+	int i;
+	volatile struct dbdma_cmd *cp;
+#endif /* CONFIG_PPC */
+
+	read_sq.max_count = numBufs;
+	read_sq.max_active = numBufs;
+	read_sq.block_size = bufSize;
+	read_sq.buffers = read_buffers;
+
+	read_sq.front = read_sq.count = 0;
+	read_sq.rear = 0;
+	read_sq.rear_size = 0;
+	read_sq.syncing = 0;
+	read_sq.active = 0;
+
+#ifdef CONFIG_ATARI
+	read_sq.ignore_int = 0;
+#endif /* CONFIG_ATARI */
+#ifdef CONFIG_AMIGA
+	read_sq.block_size_half = read_sq.block_size>>1;
+	read_sq.block_size_quarter = read_sq.block_size_half>>1;
+#endif /* CONFIG_AMIGA */
+#ifdef CONFIG_PPC
+	cp = awacs_rx_cmds;
+	memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd));
+
+	/* Set dma buffers up in a loop */
+	for (i = 0; i < numBufs; i++,cp++) {
+		st_le32(&cp->phy_addr, virt_to_bus(read_buffers[i]));
+		st_le16(&cp->command, INPUT_MORE + INTR_ALWAYS);
+		st_le16(&cp->req_count, read_sq.block_size);
+		st_le16(&cp->xfer_status, 0);
+	}
+
+	/* The next two lines make the thing loop around.
+	*/
+	st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+	st_le32(&cp->cmd_dep, virt_to_bus(awacs_rx_cmds));
+
+	/* Don't start until the first read is done.
+	 * This will also abort any operations in progress if the DMA
+	 * happens to be running (and it shouldn't).
+	 */
+	out_le32(&awacs_rxdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	out_le32(&awacs_rxdma->cmdptr, virt_to_bus(awacs_rx_cmds));
+
+#endif /* CONFIG_PPC */
+}
+
+
 static void sq_play(void)
 {
 	(*sound.mach.play)();
@@ -4428,7 +4832,7 @@
 			sq_play();
 			if (NON_BLOCKING(sq.open_mode))
 				return uWritten > 0 ? uWritten : -EAGAIN;
-			SLEEP(sq.write_queue, ONE_SECOND);
+			SLEEP(sq.action_queue, ONE_SECOND);
 			if (SIGNAL_RECEIVED)
 				return uWritten > 0 ? uWritten : -EINTR;
 		}
@@ -4462,29 +4866,117 @@
 }
 
 
+/***********/
+
+/* Here is how the values are used for reading.
+ * The value 'active' simply indicates the DMA is running.  This is
+ * done so the driver semantics are DMA starts when the first read is
+ * posted.  The value 'front' indicates the buffer we should next
+ * send to the user.  The value 'rear' indicates the buffer the DMA is
+ * currently filling.  When 'front' == 'rear' the buffer "ring" is
+ * empty (we always have an empty available).  The 'rear_size' is used
+ * to track partial offsets into the current buffer.  Right now, I just keep
+ * the DMA running.  If the reader can't keep up, the interrupt tosses
+ * the oldest buffer.  We could also shut down the DMA in this case.
+ */
+static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
+                       loff_t *ppos)
+{
+
+	ssize_t	uRead, bLeft, bUsed, uUsed;
+
+	if (uLeft == 0)
+		return 0;
+
+	if (!read_sq.active)
+		PMacRecord();	/* Kick off the record process. */
+
+	uRead = 0;
+
+	/* Move what the user requests, depending upon other options.
+	*/
+	while (uLeft > 0) {
+
+		/* When front == rear, the DMA is not done yet.
+		*/
+		while (read_sq.front == read_sq.rear) {
+			if (NON_BLOCKING(read_sq.open_mode)) {
+			       return uRead > 0 ? uRead : -EAGAIN;
+			}
+			SLEEP(read_sq.action_queue, ONE_SECOND);
+			if (SIGNAL_RECEIVED)
+				return uRead > 0 ? uRead : -EINTR;
+		}
+
+		/* The amount we move is either what is left in the
+		 * current buffer or what the user wants.
+		 */
+		bLeft = read_sq.block_size - read_sq.rear_size;
+		bUsed = read_sq.rear_size;
+		uUsed = sound_copy_translate_read(dst, uLeft,
+			read_sq.buffers[read_sq.front], &bUsed, bLeft);
+		if (uUsed <= 0)
+			return uUsed;
+		dst += uUsed;
+		uRead += uUsed;
+		uLeft -= uUsed;
+		read_sq.rear_size += bUsed;
+		if (read_sq.rear_size >= read_sq.block_size) {
+			read_sq.rear_size = 0;
+			read_sq.front++;
+			if (read_sq.front >= read_sq.max_active)
+				read_sq.front = 0;
+		}
+	}
+	return uRead;
+}
+
 static int sq_open(struct inode *inode, struct file *file)
 {
 	int rc = 0;
 
 	MOD_INC_USE_COUNT;
-	if (sq.busy) {
-		rc = -EBUSY;
-		if (NON_BLOCKING(file->f_flags))
-			goto err_out;
-		rc = -EINTR;
-		while (sq.busy) {
-			SLEEP(sq.open_queue, ONE_SECOND);
-			if (SIGNAL_RECEIVED)
+	if (file->f_mode & FMODE_WRITE) {
+		if (sq.busy) {
+			rc = -EBUSY;
+			if (NON_BLOCKING(file->f_flags))
 				goto err_out;
+			rc = -EINTR;
+			while (sq.busy) {
+				SLEEP(sq.open_queue, ONE_SECOND);
+				if (SIGNAL_RECEIVED)
+					goto err_out;
+			}
 		}
-		rc = 0;
+		sq.busy = 1; /* Let's play spot-the-race-condition */
+
+		if (sq_allocate_buffers()) goto err_out_nobusy;
+
+		sq_setup(numBufs, bufSize<<10,sound_buffers);
+		sq.open_mode = file->f_mode;
 	}
-	sq.busy = 1;
-	rc = sq_allocate_buffers();
-	if (rc)
-		goto err_out_nobusy;
-	sq_setup(numBufs, bufSize << 10, sound_buffers);
-	sq.open_mode = file->f_flags;
+
+
+	if (file->f_mode & FMODE_READ) {
+		if (read_sq.busy) {
+			rc = -EBUSY;
+			if (NON_BLOCKING(file->f_flags))
+				goto err_out;
+			rc = -EINTR;
+			while (read_sq.busy) {
+				SLEEP(read_sq.open_queue, ONE_SECOND);
+				if (SIGNAL_RECEIVED)
+					goto err_out;
+			}
+			rc = 0;
+		}
+		read_sq.busy = 1;
+		if (sq_allocate_read_buffers()) goto err_out_nobusy;
+
+		read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);
+		read_sq.open_mode = file->f_mode;
+	}                                                                      
+
 #ifdef CONFIG_ATARI
 	sq.ignore_int = 1;
 #endif /* CONFIG_ATARI */
@@ -4497,10 +4989,25 @@
 		sound_set_stereo(0);
 		sound_set_format(AFMT_MU_LAW);
 	}
+
+#if 0
+	if (file->f_mode == FMODE_READ) {
+		/* Start dma'ing straight away */
+		PMacRecord();
+	}
+#endif
+
 	return 0;
+
 err_out_nobusy:
-	sq.busy = 0;
-	WAKE_UP(sq.open_queue);
+	if (file->f_mode & FMODE_WRITE) {
+		sq.busy = 0;
+		WAKE_UP(sq.open_queue);
+	}
+	if (file->f_mode & FMODE_READ) {
+		read_sq.busy = 0;
+		WAKE_UP(read_sq.open_queue);
+	}
 err_out:
 	MOD_DEC_USE_COUNT;
 	return rc;
@@ -4510,7 +5017,7 @@
 static void sq_reset(void)
 {
 	sound_silence();
-	sq.playing = 0;
+	sq.active = 0;
 	sq.count = 0;
 	sq.front = (sq.rear+1) % sq.max_count;
 }
@@ -4523,7 +5030,7 @@
 	sq.syncing = 1;
 	sq_play();	/* there may be an incomplete frame waiting */
 
-	while (sq.playing) {
+	while (sq.active) {
 		SLEEP(sq.sync_queue, ONE_SECOND);
 		if (SIGNAL_RECEIVED) {
 			/* While waiting for audio output to drain, an
@@ -4548,11 +5055,23 @@
 	sound.soft = sound.dsp;
 	sound.hard = sound.dsp;
 	sound_silence();
+
+	sq_release_read_buffers();
 	sq_release_buffers();
 	MOD_DEC_USE_COUNT;
 
-	sq.busy = 0;
-	WAKE_UP(sq.open_queue);
+	/* There is probably a DOS atack here. They change the mode flag. */
+	/* XXX add check here */
+	if (file->f_mode & FMODE_READ) {
+		read_sq.busy = 0;
+		WAKE_UP(read_sq.open_queue);
+	}
+
+	if (file->f_mode & FMODE_WRITE) {
+		sq.busy = 0;
+		WAKE_UP(sq.open_queue);
+	}
+
 	/* Wake up a process waiting for the queue being released.
 	 * Note: There may be several processes waiting for a call
 	 * to open() returning. */
@@ -4624,7 +5143,7 @@
 	case SNDCTL_DSP_SUBDIVIDE:
 		break;
 	case SNDCTL_DSP_SETFRAGMENT:
-		if (sq.count || sq.playing || sq.syncing)
+		if (sq.count || sq.active || sq.syncing)
 			return -EINVAL;
 		IOCTL_IN(arg, size);
 		nbufs = size >> 16;
@@ -4654,7 +5173,7 @@
 static struct file_operations sq_fops =
 {
 	sound_lseek,
-	NULL,			/* sq_read */
+	sq_read,			/* sq_read */
 	sq_write,
 	NULL,			/* sq_readdir */
 	NULL,			/* sq_poll */
@@ -4675,10 +5194,16 @@
 	if (sq_unit < 0)
 		return;
 
-	init_waitqueue_head(&sq.write_queue);
+	init_waitqueue_head(&sq.action_queue);
 	init_waitqueue_head(&sq.open_queue);
 	init_waitqueue_head(&sq.sync_queue);
+
+	init_waitqueue_head(&read_sq.action_queue);
+	init_waitqueue_head(&read_sq.open_queue);
+	init_waitqueue_head(&read_sq.sync_queue);
+
 	sq.busy = 0;
+	read_sq.busy = 0;
 
 	/* whatever you like as startup mode for /dev/dsp,
 	 * (/dev/audio hasn't got a startup mode). note that
@@ -4726,7 +5251,7 @@
 
 static int state_open(struct inode *inode, struct file *file)
 {
-	char *buffer = state.buf, *mach = "";
+	char *buffer = state.buf, *mach = "", awacs_buf[50];
 	int len = 0;
 
 	if (state.busy)
@@ -4750,7 +5275,8 @@
 #endif /* CONFIG_AMIGA */
 #ifdef CONFIG_PPC
 	case DMASND_AWACS:
-		sprintf(mach, "PowerMac (AWACS rev %d) ", awacs_revision);
+		sprintf(awacs_buf, "PowerMac (AWACS rev %d) ", awacs_revision);
+		mach = awacs_buf;
 		break;
 #endif /* CONFIG_PPC */
 	}
@@ -4821,8 +5347,8 @@
 		       sq.block_size, sq.max_count, sq.max_active);
 	len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
 		       sq.rear_size);
-	len += sprintf(buffer+len, "\tsq.playing = %d sq.syncing = %d\n",
-		       sq.playing, sq.syncing);
+	len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
+		       sq.active, sq.syncing);
 	state.len = len;
 	return 0;
 }
@@ -4951,15 +5477,18 @@
 		int vol;
 		sound.mach = machPMac;
 		has_sound = 1;
+
 		awacs = (volatile struct awacs_regs *)
 			ioremap(np->addrs[0].address, 0x80);
 		awacs_txdma = (volatile struct dbdma_regs *)
 			ioremap(np->addrs[1].address, 0x100);
 		awacs_rxdma = (volatile struct dbdma_regs *)
 			ioremap(np->addrs[2].address, 0x100);
+
 		awacs_irq = np->intrs[0].line;
 		awacs_tx_irq = np->intrs[1].line;
 		awacs_rx_irq = np->intrs[2].line;
+
 		awacs_tx_cmd_space = kmalloc((numBufs + 4) * sizeof(struct dbdma_cmd),
 					     GFP_KERNEL);
 		if (awacs_tx_cmd_space == NULL) {
@@ -4968,6 +5497,18 @@
 		}
 		awacs_tx_cmds = (volatile struct dbdma_cmd *)
 			DBDMA_ALIGN(awacs_tx_cmd_space);
+
+
+		awacs_rx_cmd_space = kmalloc((numReadBufs + 4) * sizeof(struct dbdma_cmd),
+					     GFP_KERNEL);
+		if (awacs_rx_cmd_space == NULL) {
+		  printk("DMA sound driver: No memory for input");
+		}
+		awacs_rx_cmds = (volatile struct dbdma_cmd *)
+		  DBDMA_ALIGN(awacs_rx_cmd_space);
+
+
+
 		awacs_reg[0] = MASK_MUX_CD;
 		awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT;
 		/* get default volume from nvram */
@@ -5083,6 +5624,7 @@
 		sound.mach.irqcleanup();
 	}
 
+	sq_release_read_buffers();
 	sq_release_buffers();
 
 	if (mixer_unit >= 0)
diff -u --recursive --new-file v2.3.10/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.3.10/linux/drivers/sound/es1370.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/sound/es1370.c	Sat Jul 10 10:58:40 1999
@@ -100,6 +100,7 @@
  *                     Guenter Geiger <geiger@epy.co.at>
  *    15.06.99   0.23  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
+ *    28.06.99   0.24  Add pci_set_master
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -2320,7 +2321,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.23 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.24 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
@@ -2384,6 +2385,7 @@
 		/* initialize the chips */
 		outl(s->ctrl, s->io+ES1370_REG_CONTROL);
 		outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
+		pci_set_master(pcidev);  /* enable bus mastering */
 		wrcodec(s, 0x16, 3); /* no RST, PD */
 		wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!!  */
 		wrcodec(s, 0x18, 0); /* recording source is mixer */
diff -u --recursive --new-file v2.3.10/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.3.10/linux/drivers/sound/es1371.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/sound/es1371.c	Sat Jul 10 10:58:40 1999
@@ -67,6 +67,7 @@
  *                     other than i386
  *    15.06.99   0.12  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
+ *    28.06.99   0.13  Add pci_set_master
  *
  */
 
@@ -2735,7 +2736,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1371: version v0.12 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1371: version v0.13 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
@@ -2792,6 +2793,7 @@
 		outl(s->ctrl, s->io+ES1371_REG_CONTROL);
 		outl(s->sctrl, s->io+ES1371_REG_SERIAL_CONTROL);
 		outl(0, s->io+ES1371_REG_LEGACY);
+		pci_set_master(pcidev);  /* enable bus mastering */
 		/* AC97 warm reset to start the bitclk */
 		outl(s->ctrl | CTRL_SYNCRES, s->io+ES1371_REG_CONTROL);
 		udelay(2);
diff -u --recursive --new-file v2.3.10/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.3.10/linux/drivers/sound/sonicvibes.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/sound/sonicvibes.c	Sat Jul 10 10:58:40 1999
@@ -70,6 +70,7 @@
  *                     Note: dmaio hack might still be wrong on archs other than i386
  *    15.06.99   0.15  Fix bad allocation bug.
  *                     Thanks to Deti Fliegl <fliegl@in.tum.de>
+ *    28.06.99   0.16  Add pci_set_master
  *
  */
 
@@ -2324,7 +2325,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "sv: version v0.15 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "sv: version v0.16 time " __TIME__ " " __DATE__ "\n");
 #if 0
 	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
 		printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
@@ -2450,6 +2451,7 @@
 			goto err_dev3;
 		if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0)
 			goto err_dev4;
+		pci_set_master(pcidev);  /* enable bus mastering */
 		/* initialize the chips */
 		fs = get_fs();
 		set_fs(KERNEL_DS);
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.10/linux/drivers/usb/Config.in	Mon Jun  7 20:04:01 1999
+++ linux/drivers/usb/Config.in	Wed Jul 14 10:30:36 1999
@@ -34,6 +34,7 @@
   if [ "$CONFIG_USB_SCSI" != "n" ]; then
 	  dep_tristate '  USB SCSI verbose debug' CONFIG_USB_SCSI_DEBUG $CONFIG_USB_SCSI
   fi
+  dep_tristate 'EZUSB Firmware downloader' CONFIG_USB_EZUSB $CONFIG_USB
 fi
 
 endmenu
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.10/linux/drivers/usb/Makefile	Tue Jun  8 10:52:26 1999
+++ linux/drivers/usb/Makefile	Wed Jul 14 10:30:36 1999
@@ -116,6 +116,15 @@
   endif
 endif
 
+ifeq ($(CONFIG_USB_EZUSB),y)
+  L_OBJS += ezusb.o
+endif
+
+ifeq ($(CONFIG_USB_EZUSB),m)
+  M_OBJS += ezusb.o
+  MIX_OBJS += ezusb.o
+endif
+
 include $(TOPDIR)/Rules.make
 
 keymap.o: keymap.c
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.10/linux/drivers/usb/acm.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/acm.c	Mon Jul 19 11:17:32 1999
@@ -231,7 +231,10 @@
 			continue;
 
 		printk("USB ACM found\n");
-		usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue);
+		if (usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue)) {
+			printk (KERN_INFO " Failed usb_set_configuration: ACM\n");
+			continue;
+		}
 		acm->dev=dev;
 		acm->readendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[0].bEndpointAddress;
 		acm->writeendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].bEndpointAddress;
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.10/linux/drivers/usb/audio.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/audio.c	Mon Jul 19 11:17:32 1999
@@ -81,7 +81,10 @@
 
 		endpoint = &interface->endpoint[0];
 
-//        	usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+//        	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+//			printk (KERN_INFO " Failed usb_set_configuration: Audio\n");
+//			break;
+//		}
 //        	usb_set_protocol(dev, 0);
 //        	usb_set_idle(dev, 0, 0);
         
@@ -92,8 +95,13 @@
                         aud);
 
 		list_add(&aud->list, &usb_audio_list);
+		
+		return 0;
 	}
-	return 0;
+	
+	if (aud)
+		kfree (aud);
+	return -1;
 }
 
 static void usb_audio_disconnect(struct usb_device *dev)
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.10/linux/drivers/usb/cpia.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/cpia.c	Mon Jul 19 11:17:32 1999
@@ -23,7 +23,6 @@
 #include <asm/io.h>
 
 #include "usb.h"
-#include "uhci.h"
 #include "cpia.h"
 
 #define MAX_FRAME_SIZE (384 * 288 * 3)
@@ -478,10 +477,10 @@
 
 	sbuf = &cpia->sbuf[cpia->receivesbuf];
 
-	uhci_unsched_isochronous(dev, sbuf->isodesc);
+	usb_unschedule_isochronous(dev, sbuf->isodesc);
 
 	/* Do something to it now */
-	sbuf->len = uhci_compress_isochronous(dev, sbuf->isodesc);
+	sbuf->len = usb_compress_isochronous(dev, sbuf->isodesc);
 
 	if (sbuf->len)
 	printk("%d bytes received\n", sbuf->len);
@@ -498,7 +497,7 @@
 	}
 
 	/* Reschedule this block of Isochronous desc */
-	uhci_sched_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc);
+	usb_schedule_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc);
 
 	/* Move to the next one */
 	cpia->receivesbuf = (cpia->receivesbuf + 1) % 3;
@@ -521,18 +520,18 @@
 	cpia->state = STATE_SCANNING;
 
 	/* Allocate all of the memory necessary */
-	cpia->sbuf[0].isodesc = uhci_alloc_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
-	cpia->sbuf[1].isodesc = uhci_alloc_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
-	cpia->sbuf[2].isodesc = uhci_alloc_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
+	cpia->sbuf[0].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
+	cpia->sbuf[1].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
+	cpia->sbuf[2].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia);
 
 	printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc);
 	printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc);
 	printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc);
 
 	/* Schedule the queues */
-	uhci_sched_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
-	uhci_sched_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
-	uhci_sched_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc);
+	usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
+	usb_schedule_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
+	usb_schedule_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc);
 
 	if (usb_set_interface(cpia->dev, 1, 3)) {
 		printk("cpia_set_interface error\n");
@@ -561,18 +560,18 @@
 	/* Set packet size to 0 */
 	if (usb_set_interface(cpia->dev, 1, 0)) {
 		printk("cpia_set_interface error\n");
-		return -EINVAL;
+		return /* -EINVAL */;
 	}
 
 	/* Unschedule all of the iso td's */
-	uhci_unsched_isochronous(dev, cpia->sbuf[2].isodesc);
-	uhci_unsched_isochronous(dev, cpia->sbuf[1].isodesc);
-	uhci_unsched_isochronous(dev, cpia->sbuf[0].isodesc);
+	usb_unschedule_isochronous(dev, cpia->sbuf[2].isodesc);
+	usb_unschedule_isochronous(dev, cpia->sbuf[1].isodesc);
+	usb_unschedule_isochronous(dev, cpia->sbuf[0].isodesc);
 
 	/* Delete them all */
-	uhci_delete_isochronous(dev, cpia->sbuf[2].isodesc);
-	uhci_delete_isochronous(dev, cpia->sbuf[1].isodesc);
-	uhci_delete_isochronous(dev, cpia->sbuf[0].isodesc);
+	usb_delete_isochronous(dev, cpia->sbuf[2].isodesc);
+	usb_delete_isochronous(dev, cpia->sbuf[1].isodesc);
+	usb_delete_isochronous(dev, cpia->sbuf[0].isodesc);
 }
 
 /* Video 4 Linux API */
@@ -980,7 +979,7 @@
 	struct usb_cpia *cpia = (struct usb_cpia *)dev;
 	int len;
 
-	printk("cpia_read: %d bytes\n", count);
+	printk("cpia_read: %ld bytes\n", count);
 #if 0
 	len = cpia_capture(cpia, buf, count);
 
@@ -995,7 +994,7 @@
 	unsigned long start = (unsigned long)adr;
 	unsigned long page, pos;
 
-	printk("mmap: %d (%X) bytes\n", size, size);
+	printk("mmap: %ld (%lX) bytes\n", size, size);
 	if (size > (((2 * MAX_FRAME_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
 		return -EINVAL;
 
@@ -1048,7 +1047,10 @@
 	unsigned char camerastat[8];
 	unsigned char *buf;
 
-	usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+		printk (KERN_INFO " Failed usb_set_configuration: CPIA\n");
+		return;
+	}
 
 	if (usb_cpia_get_version(dev, version)) {
 		printk("cpia_get_version error\n");
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/ezusb.c linux/drivers/usb/ezusb.c
--- v2.3.10/linux/drivers/usb/ezusb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ezusb.c	Wed Jul 14 10:30:36 1999
@@ -0,0 +1,473 @@
+/*****************************************************************************/
+
+/*
+ *	ezusb.c  --  Firmware download miscdevice for Anchorchips EZUSB microcontrollers.
+ *
+ *	Copyright (C) 1999
+ *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  History:
+ *   0.1  26.05.99  Created
+ *
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/socket.h>
+#include <asm/uaccess.h>
+#include <linux/miscdevice.h>
+
+#include "usb.h"
+#include "ezusb.h"
+
+/* --------------------------------------------------------------------- */
+
+#define NREZUSB 1
+
+static struct ezusb {
+	struct semaphore mutex;
+	struct usb_device *usbdev;
+	unsigned int irqep;
+	unsigned int intlen;
+	unsigned char intdata[64];
+} ezusb[NREZUSB];
+
+/* --------------------------------------------------------------------- */
+
+static int ezusb_irq(int state, void *__buffer, int len, void *dev_id)
+{
+	struct ezusb *ez = (struct ezusb *)dev_id;
+	
+	if (len > sizeof(ez->intdata))
+		len = sizeof(ez->intdata);
+	ez->intlen = len;
+	memcpy(ez->intdata, __buffer, len);
+	return 1;
+}
+
+/* --------------------------------------------------------------------- */
+
+static loff_t ezusb_llseek(struct file *file, loff_t offset, int origin)
+{
+	struct ezusb *ez = (struct ezusb *)file->private_data;
+
+	switch(origin) {
+	case 1:
+		offset += file->f_pos;
+		break;
+	case 2:
+		offset += 0x10000;
+		break;
+	}
+	if (offset < 0 || offset >= 0x10000)
+		return -EINVAL;
+	return (file->f_pos = offset);
+}
+
+static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos)
+{
+	struct ezusb *ez = (struct ezusb *)file->private_data;
+	unsigned pos = *ppos;
+	unsigned ret = 0;
+	unsigned len;
+	unsigned char b[64];
+        devrequest dr;
+	int i;
+
+	if (*ppos < 0 || *ppos >= 0x10000)
+		return -EINVAL;
+	down(&ez->mutex);
+	if (!ez->usbdev) {
+		up(&ez->mutex);
+		return -EIO;
+	}
+	while (sz > 0 && pos < 0x10000) {
+		len = sz;
+		if (len > sizeof(b))
+			len = sizeof(b);
+		if (pos + len > 0x10000)
+			len = 0x10000 - pos;
+		dr.requesttype = 0xc0;
+		dr.request = 0xa0;
+		dr.value = pos;
+		dr.index = 0;
+		dr.length = len;
+		i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), &dr, b, len);
+		if (i) {
+			up(&ez->mutex);
+			printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", dr.value, dr.length, i);
+			*ppos = pos;
+			if (ret)
+				return ret;
+			return -ENXIO;
+		}
+		if (copy_to_user(buf, b, len)) {
+			up(&ez->mutex);
+			*ppos = pos;
+			if (ret)
+				return ret;
+			return -EFAULT;
+		}
+		pos += len;
+		buf += len;
+		sz -= len;
+		ret += len;
+	}
+	up(&ez->mutex);
+	*ppos = pos;
+	return ret;
+}
+
+static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t *ppos)
+{
+	struct ezusb *ez = (struct ezusb *)file->private_data;
+	unsigned pos = *ppos;
+	unsigned ret = 0;
+	unsigned len;
+	unsigned char b[64];
+        devrequest dr;
+	int i;
+
+	if (*ppos < 0 || *ppos >= 0x10000)
+		return -EINVAL;
+	down(&ez->mutex);
+	if (!ez->usbdev) {
+		up(&ez->mutex);
+		return -EIO;
+	}
+	while (sz > 0 && pos < 0x10000) {
+		len = sz;
+		if (len > sizeof(b))
+			len = sizeof(b);
+		if (pos + len > 0x10000)
+			len = 0x10000 - pos;
+		if (copy_from_user(b, buf, len)) {
+			up(&ez->mutex);
+			*ppos = pos;
+			if (ret)
+				return ret;
+			return -EFAULT;
+		}
+		dr.requesttype = 0x40;
+		dr.request = 0xa0;
+		dr.value = pos;
+		dr.index = 0;
+		dr.length = len;
+		i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), &dr, b, len);
+		if (i) {
+			up(&ez->mutex);
+			printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", dr.value, dr.length, i);
+			*ppos = pos;
+			if (ret)
+				return ret;
+			return -ENXIO;
+		}
+		pos += len;
+		buf += len;
+		sz -= len;
+		ret += len;
+	}
+	up(&ez->mutex);
+	*ppos = pos;
+	return ret;
+}
+
+static int ezusb_open(struct inode *inode, struct file *file)
+{
+	struct ezusb *ez = &ezusb[0];
+
+	down(&ez->mutex);
+	while (!ez->usbdev) {
+		up(&ez->mutex);
+		if (!(file->f_flags & O_NONBLOCK)) {
+			return -EIO;
+		}
+		schedule_timeout(HZ/2);
+		if (signal_pending(current))
+			return -EAGAIN;
+		down(&ez->mutex);
+	}
+	up(&ez->mutex);
+	file->f_pos = 0;
+	file->private_data = ez;
+	return 0;
+}
+
+static int ezusb_release(struct inode *inode, struct file *file)
+{
+	struct ezusb *ez = (struct ezusb *)file->private_data;
+	return 0;
+}
+
+static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct ezusb *ez = (struct ezusb *)file->private_data;
+	struct ezusb_ctrltransfer ctrl;
+	struct ezusb_bulktransfer bulk;
+	unsigned int len1, ep;
+	unsigned long len2;
+	unsigned int irqep;
+	unsigned char tbuf[1024];
+	int i;
+
+	switch (cmd) {
+	case EZUSB_CONTROL:
+		copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
+		if (ctrl.dlen > sizeof(tbuf) || ctrl.dlen > 1024)
+			return -EINVAL;
+		if (ctrl.requesttype & 0x80) {
+			if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen))
+				return -EINVAL;
+			down(&ez->mutex);
+			if (!ez->usbdev) {
+				up(&ez->mutex);
+				return -EIO;
+			}
+			i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0),
+							     (devrequest *)&ctrl, tbuf, ctrl.dlen);
+			up(&ez->mutex);
+			if (!i && ctrl.dlen) {
+				copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT);
+			}
+		} else {
+			if (ctrl.dlen) {
+				copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT);
+			}
+			down(&ez->mutex);
+			if (!ez->usbdev) {
+				up(&ez->mutex);
+				return -EIO;
+			}
+			i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0),
+							     (devrequest *)&ctrl, tbuf, ctrl.dlen);
+			up(&ez->mutex);
+		}
+		if (i) {
+			printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", 
+			       ctrl.requesttype, ctrl.request, ctrl.length, i);
+			return -ENXIO;
+		}
+		return 0;
+
+	case EZUSB_INTERRUPT:
+		get_user_ret(irqep, (unsigned int *)arg, -EFAULT);
+		if (irqep != ez->irqep) {
+			if (ez->irqep)
+				return -EIO;
+			ez->irqep = irqep;
+			usb_request_irq(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, ez->irqep),
+					ezusb_irq, 2 /* interval */, ez);
+			ez->intlen = 0;
+			return -EAGAIN;
+		}
+		copy_to_user_ret((&((struct ezusb_interrupttransfer *)0)->data) + arg, 
+				 ez->intdata, 64, -EFAULT);
+		return ez->intlen;
+
+	case EZUSB_BULK:
+		copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT);
+		len1 = bulk.len;
+		if (len1 > sizeof(tbuf))
+			len1 = sizeof(tbuf);
+		if (bulk.ep & 0x80) {
+			if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1))
+				return -EINVAL;
+			down(&ez->mutex);
+			if (!ez->usbdev) {
+				up(&ez->mutex);
+				return -EIO;
+			}
+			i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, usb_rcvbulkpipe(ez->usbdev, bulk.ep & 0x7f),
+							  tbuf, len1, &len2);
+			up(&ez->mutex);
+			if (!i && len2) {
+				copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
+			}
+		} else {
+			if (len1) {
+				copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
+			}
+			down(&ez->mutex);
+			if (!ez->usbdev) {
+				up(&ez->mutex);
+				return -EIO;
+			}
+			i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, usb_sndbulkpipe(ez->usbdev, bulk.ep & 0x7f),
+							  tbuf, len1, &len2);
+			up(&ez->mutex);
+		}
+		if (i) {
+			printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", 
+			       bulk.ep, bulk.len, i);
+			return -ENXIO;
+		}
+		return len2;
+
+	case EZUSB_RESETEP:
+		get_user_ret(ep, (unsigned int *)arg, -EFAULT);
+		if ((ep & ~0x80) >= 16)
+			return -EINVAL;
+		usb_settoggle(ez->usbdev, ep & 0xf, !(ep & 0x80), 0);
+		return 0;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static struct file_operations ezusb_fops = {
+	ezusb_llseek,
+	ezusb_read,
+	ezusb_write,
+	NULL,  /* readdir */
+	NULL,  /* poll */
+	ezusb_ioctl,
+	NULL,  /* mmap */
+	ezusb_open,
+	NULL,  /* flush */
+	ezusb_release,
+	NULL,  /* fsync */
+	NULL,  /* fasync */
+	NULL,  /* check_media_change */
+	NULL,  /* revalidate */
+	NULL   /* lock */
+};
+
+static struct miscdevice ezusb_misc = {
+	192, "ezusb", &ezusb_fops
+};
+
+/* --------------------------------------------------------------------- */
+
+static int ezusb_probe(struct usb_device *usbdev)
+{
+	struct ezusb *ez = &ezusb[0];
+        struct usb_interface_descriptor *interface;
+        struct usb_endpoint_descriptor *endpoint;
+
+#undef KERN_DEBUG
+#define KERN_DEBUG ""
+        printk(KERN_DEBUG "ezusb: probe: vendor id 0x%x, device id 0x%x\n",
+               usbdev->descriptor.idVendor, usbdev->descriptor.idProduct);
+
+	/* the 1234:5678 is just a self assigned test ID */
+        if ((usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x2131) &&
+	    (usbdev->descriptor.idVendor != 0x1234 || usbdev->descriptor.idProduct != 0x5678))
+                return -1;
+
+        /* We don't handle multiple configurations */
+        if (usbdev->descriptor.bNumConfigurations != 1)
+                return -1;
+
+        /* We don't handle multiple interfaces */
+        if (usbdev->config[0].bNumInterfaces != 1)
+                return -1;
+
+	down(&ez->mutex);
+	if (ez->usbdev) {
+		up(&ez->mutex);
+		printk(KERN_INFO "ezusb: device already used\n");
+		return -1;
+	}
+	ez->usbdev = usbdev;
+	usbdev->private = ez;
+        if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue)) {
+		printk(KERN_ERR "ezusb: set_configuration failed\n");
+		goto err;
+	}
+        interface = &usbdev->config[0].altsetting[1].interface[0];
+	if (usb_set_interface(usbdev, 0, 1)) {
+		printk(KERN_ERR "ezusb: set_interface failed\n");
+		goto err;
+	}
+	up(&ez->mutex);
+	MOD_INC_USE_COUNT;
+        return 0;
+
+ err:
+	up(&ez->mutex);
+	ez->usbdev = NULL;
+	usbdev->private = NULL;
+	return -1;
+}
+
+static void ezusb_disconnect(struct usb_device *usbdev)
+{
+	struct ezusb *ez = (struct ezusb *)usbdev->private;
+
+	down(&ez->mutex);
+	ez->usbdev = NULL;
+	up(&ez->mutex);
+        usbdev->private = NULL;
+	MOD_DEC_USE_COUNT;
+}
+
+static struct usb_driver ezusb_driver = {
+        "ezusb",
+        ezusb_probe,
+        ezusb_disconnect,
+        { NULL, NULL }
+};
+
+/* --------------------------------------------------------------------- */
+
+int ezusb_init(void)
+{
+	unsigned u;
+
+	/* initialize struct */
+	for (u = 0; u < NREZUSB; u++) {
+		init_MUTEX(&ezusb[u].mutex);
+		ezusb[u].usbdev = NULL;
+		ezusb[u].irqep = 0;
+	}
+	/* register misc device */
+	if (misc_register(&ezusb_misc)) {
+		printk(KERN_WARNING "ezusb: cannot register minor %d\n", ezusb_misc.minor);
+		return -1;
+	}
+	usb_register(&ezusb_driver);
+        printk(KERN_INFO "ezusb: Anchorchip firmware download driver registered\n");
+	return 0;
+}
+
+void ezusb_cleanup(void)
+{
+	usb_deregister(&ezusb_driver);
+	misc_deregister(&ezusb_misc);
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+
+int minor = 192;
+
+int init_module(void)
+{
+	ezusb_misc.minor = minor;
+	return ezusb_init();
+}
+
+void cleanup_module(void)
+{
+	ezusb_cleanup();
+}
+
+#endif
+
+/* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/ezusb.h linux/drivers/usb/ezusb.h
--- v2.3.10/linux/drivers/usb/ezusb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ezusb.h	Wed Jul 14 10:30:36 1999
@@ -0,0 +1,67 @@
+/*****************************************************************************/
+
+/*
+ *	ezusb.h  --  Firmware download miscdevice for Anchorchips EZUSB microcontrollers.
+ *
+ *	Copyright (C) 1999
+ *          Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*****************************************************************************/
+
+#ifndef _LINUX_EZUSB_H
+#define _LINUX_EZUSB_H
+
+#include <linux/ioctl.h>
+
+/* --------------------------------------------------------------------- */
+
+struct ezusb_ctrltransfer {
+	/* keep in sync with usb.h:devrequest */
+	unsigned char requesttype;
+	unsigned char request;
+	unsigned short value;
+	unsigned short index;
+	unsigned short length;
+	/* pointer to data */
+	unsigned dlen;
+	void *data;
+};
+
+#define EZUSB_CONTROL        _IOWR('E', 0, struct ezusb_ctrltransfer)
+
+struct ezusb_interrupttransfer {
+	unsigned int ep;
+	unsigned char data[64];
+};
+
+#define EZUSB_INTERRUPT      _IOWR('E', 1, struct ezusb_interrupttransfer)
+
+struct ezusb_bulktransfer {
+	unsigned int ep;
+	unsigned int len;
+	void *data;
+};
+
+#define EZUSB_BULK           _IOWR('E', 2, struct ezusb_bulktransfer)
+
+#define EZUSB_RESETEP        _IOR('E', 3, unsigned int)
+
+
+/* --------------------------------------------------------------------- */
+#endif /* _LINUX_EZUSB_H */
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.10/linux/drivers/usb/hub.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/hub.c	Mon Jul 19 15:25:27 1999
@@ -3,6 +3,7 @@
  *
  * (C) Copyright 1999 Linus Torvalds
  * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Gregory P. Smith
  */
 
 #include <linux/kernel.h>
@@ -20,10 +21,14 @@
 /* Wakes up khubd */
 static DECLARE_WAIT_QUEUE_HEAD(usb_hub_wait);
 static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t hub_list_lock = SPIN_LOCK_UNLOCKED;
 
 /* List of hubs needing servicing */
 static struct list_head hub_event_list;
 
+/* List containing all of the hubs (for cleanup) */
+static struct list_head all_hubs_list;
+
 /* PID of khubd */
 static int khubd_pid = 0;
 
@@ -149,6 +154,7 @@
 	struct usb_interface_descriptor *interface;
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_hub *hub;
+	unsigned long flags;
 
 	/* We don't handle multi-config hubs */
 	if (dev->descriptor.bNumConfigurations != 1)
@@ -196,9 +202,15 @@
 	INIT_LIST_HEAD(&hub->event_list);
 	hub->dev = dev;
 
+	/* Record the new hub's existence */
+	spin_lock_irqsave(&hub_list_lock, flags);
+	INIT_LIST_HEAD(&hub->hub_list);
+	list_add(&hub->hub_list, &all_hubs_list);
+	spin_unlock_irqrestore(&hub_list_lock, flags);
+
 	usb_hub_configure(hub);
 
-	usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
+	hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
 
 	/* Wake up khubd */
 	wake_up(&usb_hub_wait);
@@ -216,9 +228,14 @@
 	/* Delete it and then reset it */
 	list_del(&hub->event_list);
 	INIT_LIST_HEAD(&hub->event_list);
+	list_del(&hub->hub_list);
+	INIT_LIST_HEAD(&hub->hub_list);
 
 	spin_unlock_irqrestore(&hub_event_lock, flags);
 
+	usb_release_irq(hub->dev, hub->irq_handle);
+	hub->irq_handle = NULL;
+
 	/* Free the memory */
 	kfree(hub);
 }
@@ -353,13 +370,16 @@
 
 static int usb_hub_thread(void *__hub)
 {
+	MOD_INC_USE_COUNT;
+	
+	printk(KERN_INFO "USB hub driver registered\n");
+
 	lock_kernel();
 
 	/*
 	 * This thread doesn't need any user-level access,
 	 * so get rid of all our resources
 	 */
-	printk("usb_hub_thread at %p\n", &usb_hub_thread);
 	exit_mm(current);
 	exit_files(current);
 	exit_fs(current);
@@ -373,6 +393,8 @@
 		usb_hub_events();
 	} while (!signal_pending(current));
 
+	MOD_DEC_USE_COUNT;
+
 	printk("usb_hub_thread exiting\n");
 
 	return 0;
@@ -393,6 +415,7 @@
 	int pid;
 
 	INIT_LIST_HEAD(&hub_event_list);
+	INIT_LIST_HEAD(&all_hubs_list);
 
 	usb_register(&hub_driver);
 	pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
@@ -409,11 +432,39 @@
 
 void usb_hub_cleanup(void)
 {
-	if (khubd_pid >= 0)
-		kill_proc(khubd_pid, SIGINT, 1);
+	struct list_head *next, *tmp, *head = &all_hubs_list;
+	struct usb_hub *hub;
+	unsigned long flags, flags2;
+
+	/* Free the resources allocated by each hub */
+	spin_lock_irqsave(&hub_list_lock, flags);
+	spin_lock_irqsave(&hub_event_lock, flags2);
+
+	tmp = head->next;
+	while (tmp != head) {
+		hub = list_entry(tmp, struct usb_hub, hub_list);
+
+		next = tmp->next;
+
+		list_del(&hub->event_list);
+		INIT_LIST_HEAD(&hub->event_list);
+		list_del(tmp);         /* &hub->hub_list */
+		INIT_LIST_HEAD(tmp);   /* &hub->hub_list */
+
+		/* XXX we should disconnect each connected port here */
+
+		usb_release_irq(hub->dev, hub->irq_handle);
+		hub->irq_handle = NULL;
+		kfree(hub);
+
+		tmp = next;
+	}
 
 	usb_deregister(&hub_driver);
-}
+
+	spin_unlock_irqrestore(&hub_event_lock, flags2);
+	spin_unlock_irqrestore(&hub_list_lock, flags);
+} /* usb_hub_cleanup() */
 
 #ifdef MODULE
 int init_module(void){
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/hub.h linux/drivers/usb/hub.h
--- v2.3.10/linux/drivers/usb/hub.h	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/hub.h	Tue Jul 13 10:09:01 1999
@@ -68,6 +68,12 @@
 	/* Device structure */
 	struct usb_device *dev;
 
+	/* Reference to the hub's polling IRQ */
+	void* irq_handle;
+
+	/* List of hubs */
+	struct list_head hub_list;
+
 	/* Temporary event list */
 	struct list_head event_list;
 
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/keyboard.c linux/drivers/usb/keyboard.c
--- v2.3.10/linux/drivers/usb/keyboard.c	Sun Jun 20 18:51:52 1999
+++ linux/drivers/usb/keyboard.c	Mon Jul 19 11:17:32 1999
@@ -195,7 +195,10 @@
         kbd->dev = dev;
         dev->private = kbd;
 
-        usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+        if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+		printk (KERN_INFO " Failed usb_set_configuration: kbd\n");
+		goto probe_err;
+	}
         usb_set_protocol(dev, 0);
         usb_set_idle(dev, 0, 0);
         
@@ -206,9 +209,14 @@
                         kbd);
 
         list_add(&kbd->list, &usb_kbd_list);
+	
+	return 0;
     }
 
-    return 0;
+probe_err:
+    if (kbd)
+    	kfree (kbd);
+    return -1;
 }
 
 static void
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
--- v2.3.10/linux/drivers/usb/mouse.c	Wed Jun 30 13:38:20 1999
+++ linux/drivers/usb/mouse.c	Mon Jul 19 11:17:32 1999
@@ -53,6 +53,12 @@
 	struct fasync_struct *fasync;
 	/* later, add a list here to support multiple mice */
 	/* but we will also need a list of file pointers to identify it */
+
+	/* FIXME: move these to a per-mouse structure */
+	struct usb_device *dev;  /* host controller this mouse is on */
+	void* irq_handle;  /* host controller's IRQ transfer handle */
+	__u8 bEndpointAddress;  /* these are from the endpoint descriptor */
+	__u8 bInterval;		/* ...  used when calling usb_request_irq */
 };
 
 static struct mouse_state static_mouse_state;
@@ -103,8 +109,16 @@
 	struct mouse_state *mouse = &static_mouse_state;
 
 	fasync_mouse(-1, file, 0);
-	if (--mouse->active)
-		return 0;
+
+	MOD_DEC_USE_COUNT;
+
+	if (--mouse->active == 0) {
+		/* stop polling the mouse while its not in use */
+	    	usb_release_irq(mouse->dev, mouse->irq_handle);
+		/* never keep a reference to a released IRQ! */
+		mouse->irq_handle = NULL;
+	}
+
 	return 0;
 }
 
@@ -118,6 +132,13 @@
 		return 0;
 	/* flush state */
 	mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0;
+
+	/* prevent the driver from being unloaded while its in use */
+	MOD_INC_USE_COUNT;
+
+	/* start the usb controller's polling of the mouse */
+	mouse->irq_handle = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), mouse_irq, mouse->bInterval, NULL);
+
 	return 0;
 }
 
@@ -272,9 +293,15 @@
 
 	printk("USB mouse found\n");
 
-	usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+		printk (KERN_INFO " Failed usb_set_configuration: mouse\n");
+		return -1;
+	}
 
-	usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), mouse_irq, endpoint->bInterval, NULL);
+	/* these are used to request the irq when the mouse is opened */
+	mouse->dev = dev;
+	mouse->bEndpointAddress = endpoint->bEndpointAddress;
+	mouse->bInterval = endpoint->bInterval;
 
 	mouse->present = 1;
 	return 0;
@@ -284,6 +311,15 @@
 {
 	struct mouse_state *mouse = &static_mouse_state;
 
+	/* stop the usb interrupt transfer */
+	if (mouse->present) {
+	    	usb_release_irq(mouse->dev, mouse->irq_handle);
+		/* never keep a reference to a released IRQ! */
+		mouse->irq_handle = NULL;
+	}
+
+	mouse->irq_handle = NULL;
+
 	/* this might need work */
 	mouse->present = 0;
 	printk("Mouse disconnected\n");
@@ -303,6 +339,7 @@
 	misc_register(&usb_mouse);
 
 	mouse->present = mouse->active = 0;
+	mouse->irq_handle = NULL;
 	init_waitqueue_head(&mouse->wait);
 	mouse->fasync = NULL;
 
@@ -313,6 +350,15 @@
 
 void usb_mouse_cleanup(void)
 {
+	struct mouse_state *mouse = &static_mouse_state;
+
+	/* stop the usb interrupt transfer */
+	if (mouse->present) {
+	    	usb_release_irq(mouse->dev, mouse->irq_handle);
+		/* never keep a reference to a released IRQ! */
+		mouse->irq_handle = NULL;
+	}
+
 	/* this, too, probably needs work */
 	usb_deregister(&mouse_driver);
 	misc_deregister(&usb_mouse);
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
--- v2.3.10/linux/drivers/usb/ohci-hcd.c	Sun Jun 20 18:51:52 1999
+++ linux/drivers/usb/ohci-hcd.c	Mon Jul 19 11:17:32 1999
@@ -280,12 +280,44 @@
 }
 
 
+static void *sohci_alloc_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
+{
+	return NULL;
+}
+
+static void sohci_delete_isochronous (struct usb_device *dev, void *_isodesc)
+{
+	return;
+}
+
+static int sohci_sched_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
+{
+	return USB_ST_NOTSUPPORTED;
+}
+
+static int sohci_unsched_isochronous (struct usb_device *usb_dev, void *_isodesc)
+{
+	return USB_ST_NOTSUPPORTED;
+}
+
+static int sohci_compress_isochronous (struct usb_device *usb_dev, void *_isodesc)
+{
+	return USB_ST_NOTSUPPORTED;
+}
+
+
 struct usb_operations sohci_device_operations = {
 	sohci_usb_allocate,
 	sohci_usb_deallocate,
 	sohci_control_msg,
 	sohci_bulk_msg,
 	sohci_request_irq,
+	NULL,	/* FIXME: should be release_irq/remove_irq */
+	sohci_alloc_isochronous,
+	sohci_delete_isochronous,
+	sohci_sched_isochronous,
+	sohci_unsched_isochronous,
+	sohci_compress_isochronous
 };
 
  
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.10/linux/drivers/usb/ohci.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/ohci.c	Mon Jul 19 11:18:10 1999
@@ -437,6 +437,59 @@
 	ohci_remove_norm_ed_from_hw(ohci, ed, HCD_ED_BULK);
 }
 
+
+/*
+ *  Remove a periodic ED from the host controller
+ */
+void ohci_remove_periodic_ed(struct ohci *ohci, struct ohci_ed *ed)
+{
+	struct ohci_device *root_hub = usb_to_ohci(ohci->bus->root_hub);
+	struct ohci_ed *cur_ed = NULL, *prev_ed;
+	unsigned long flags;
+
+	/* FIXME: this will need to up fixed when add_periodic_ed()
+	 * is updated to spread similar polling rate EDs out over
+	 * multiple periodic queues.  Currently this assumes that the
+	 * 32ms (slowest) polling queue links to all others... */
+
+	/* search the periodic EDs, skipping the first one which is
+	 * only a placeholder. */
+	prev_ed = &root_hub->ed[ED_INT_32];
+	if (prev_ed->next_ed)
+		cur_ed = bus_to_virt(le32_to_cpup(&prev_ed->next_ed));
+
+	while (cur_ed) {
+		if (ed == cur_ed) {		/* remove the ED */
+			/* set its SKIP bit and be sure its not in use */
+			ohci_wait_for_ed_safe(ohci->regs, ed, HCD_ED_INT);
+
+			/* unlink it */
+			spin_lock_irqsave(&ohci_edtd_lock, flags);
+			prev_ed->next_ed = ed->next_ed;
+			spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+			ed->next_ed = 0;
+
+			break;
+		}
+
+		spin_lock_irqsave(&ohci_edtd_lock, flags);
+		if (cur_ed->next_ed) {
+			prev_ed = cur_ed;
+			cur_ed = bus_to_virt(le32_to_cpup(&cur_ed->next_ed));
+			spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+		} else {
+			spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+
+			/* if multiple polling queues need to be checked,
+			 * here is where you'd advance to the next one */
+
+			printk("usb-ohci: ed %p not found on periodic queue\n", ed);
+			break;
+		}
+	}
+} /* ohci_remove_periodic_ed() */
+
+
 /*
  * Remove all the EDs which have a given device address from a list.
  * Used when the device is unplugged.
@@ -584,6 +637,8 @@
 			new_td->info = cpu_to_le32(OHCI_TD_CC_NEW);
 			/* mark it as allocated */
 			allocate_td(new_td);
+			/* record the device that its on */
+			new_td->usb_dev = ohci_to_usb(dev);
 			return new_td;
 		}
 	}
@@ -879,8 +934,11 @@
  *
  * Period is desired polling interval in ms.  The closest, shorter
  * match will be used.  Powers of two from 1-32 are supported by OHCI.
+ *
+ * Returns: a "handle pointer" that release_irq can use to stop this
+ * interrupt.  (It's really a pointer to the TD).  NULL = error.
  */
-static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
+static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe,
 	usb_device_irq handler, int period, void *dev_id)
 {
 	struct ohci_device *dev = usb_to_ohci(usb);
@@ -892,14 +950,14 @@
 	interrupt_ed = ohci_get_free_ed(dev);
 	if (!interrupt_ed) {
 		printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
-		return -1;
+		return NULL;
 	}
 
 	td = ohci_get_free_td(dev);
 	if (!td) {
 		printk(KERN_ERR "Out of TDs in ohci_request_irq\n");
 		ohci_free_ed(interrupt_ed);
-		return -1;
+		return NULL;
 	}
 
 	/*
@@ -917,10 +975,6 @@
 			OHCI_TD_ROUND,
 			dev->data, maxps,
 			dev_id, handler);
-	/*
-	 * TODO: be aware of how the OHCI controller deals with DMA
-	 * spanning more than one page.
-	 */
 
 	/*
 	 *  Put the TD onto our ED and make sure its ready to run
@@ -936,17 +990,54 @@
 	/* Assimilate the new ED into the collective */
 	ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
 
-	/* FIXME: return a request handle that can be used by the
-	 * caller to cancel this request.  Be sure its guaranteed not
-	 * to be re-used until the caller is guaranteed to know that
-	 * the transfer has ended or been cancelled */
-	return 0;
+	return (void*)td;
 } /* ohci_request_irq() */
 
-
 /*
- * Control thread operations:
+ * Release an interrupt handler previously allocated using
+ * ohci_request_irq.  This function does no validity checking, so make
+ * sure you're not releasing an already released handle as it may be
+ * in use by something else..
+ *
+ * This function can NOT be called from an interrupt.
  */
+int ohci_release_irq(void* handle)
+{
+	struct ohci_device *dev;
+	struct ohci_td *int_td;
+	struct ohci_ed *int_ed;
+
+#ifdef OHCI_DEBUG
+	if (handle)
+		printk("usb-ohci: Releasing irq handle %p\n", handle);
+#endif
+
+	int_td = (struct ohci_td*)handle;
+	if (int_td == NULL)
+		return USB_ST_INTERNALERROR;
+
+	dev = usb_to_ohci(int_td->usb_dev);
+	int_ed = int_td->ed;
+
+	ohci_remove_periodic_ed(dev->ohci, int_ed);
+
+	/* Tell the driver that the IRQ has been killed. */
+	/* Passing NULL in the "buffer" void* along with the
+	 * USB_ST_REMOVED status is the signal. */
+	if (int_td->completed != NULL)
+		int_td->completed(USB_ST_REMOVED, NULL, 0, int_td->dev_id);
+
+	/* Free the ED (& TD) */
+	ohci_free_ed(int_ed);
+
+	return USB_ST_NOERROR;
+} /* ohci_release_irq() */
+
+
+/************************************
+ * OHCI control transfer operations *
+ ************************************/
+
 static DECLARE_WAIT_QUEUE_HEAD(control_wakeup);
 
 /*
@@ -1134,7 +1225,7 @@
 
 #ifdef OHCI_DEBUG
 	if (completion_status != 0) {
-		char *what = (completion_status < 0)? "timed out":
+		const char *what = (completion_status < 0)? "timed out":
 			cc_names[completion_status & 0xf];
 		printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x\n",
 		       what, pipe, cmd->requesttype, cmd->request,
@@ -1407,6 +1498,7 @@
 /* .......... */
 
 
+
 /*
  * Allocate a new USB device to be attached to an OHCI controller
  */
@@ -1479,6 +1571,32 @@
 }
 
 
+static void *ohci_alloc_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
+{
+	return NULL;
+}
+
+static void ohci_delete_isochronous (struct usb_device *dev, void *_isodesc)
+{
+	return;
+}
+
+static int ohci_sched_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
+{
+	return USB_ST_NOTSUPPORTED;
+}
+
+static int ohci_unsched_isochronous (struct usb_device *usb_dev, void *_isodesc)
+{
+	return USB_ST_NOTSUPPORTED;
+}
+
+static int ohci_compress_isochronous (struct usb_device *usb_dev, void *_isodesc)
+{
+	return USB_ST_NOTSUPPORTED;
+}
+
+
 /*
  * functions for the generic USB driver
  */
@@ -1488,6 +1606,12 @@
 	ohci_control_msg,
 	ohci_bulk_msg,
 	ohci_request_irq,
+	ohci_release_irq,
+	ohci_alloc_isochronous,
+	ohci_delete_isochronous,
+	ohci_sched_isochronous,
+	ohci_unsched_isochronous,
+	ohci_compress_isochronous
 };
 
 
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h
--- v2.3.10/linux/drivers/usb/ohci.h	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/ohci.h	Tue Jul 13 10:09:01 1999
@@ -44,8 +44,10 @@
 		/* bit3: this is NOT the last TD in a contiguious TD chain
 		 *       on the indicated ED.  (0 means it is the last) */
 
+	struct usb_device *usb_dev;	/* the owning device */
+
 	void *dev_id;	/* user defined pointer passed to irq handler */
-} __attribute((aligned(16)));
+} __attribute((aligned(32)));
 
 #define OHCI_TD_ROUND	(1 << 18)	/* buffer rounding bit */
 #define OHCI_TD_D	(3 << 19)	/* direction of xfer: */
@@ -210,7 +212,7 @@
 	struct ohci_td		td[NUM_TDS];	/* Transfer Descriptors */
 
 	unsigned long		data[DATA_BUF_LEN];
-};
+} __attribute((aligned(32)));
 
 /* .... */
 
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.10/linux/drivers/usb/printer.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/printer.c	Mon Jul 19 11:17:32 1999
@@ -318,7 +318,7 @@
 	}
 
         if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
-		printk(KERN_INFO "  Failed to set configuration\n");
+		printk(KERN_INFO "  Failed usb_set_configuration: printer\n");
 		return -1;
 	}
 #if 0
@@ -414,8 +414,6 @@
 
 void cleanup_module(void)
 {
-	unsigned int offset;
-
 	usb_deregister(&printer_driver);
 	unregister_chrdev(mymajor, "usblp");
 }
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/stopusb linux/drivers/usb/stopusb
--- v2.3.10/linux/drivers/usb/stopusb	Fri Jun  4 13:33:43 1999
+++ linux/drivers/usb/stopusb	Tue Jul 13 10:09:01 1999
@@ -1,7 +1,11 @@
 #!/bin/sh
 
+killall khubd
+killall ohci-control
 killall uhci-control
 
 sleep 2
 
+rmmod hub
+rmmod usb-ohci
 rmmod usb-uhci
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/uhci-debug.c linux/drivers/usb/uhci-debug.c
--- v2.3.10/linux/drivers/usb/uhci-debug.c	Sun Jun 20 11:43:42 1999
+++ linux/drivers/usb/uhci-debug.c	Mon Jul 19 11:17:32 1999
@@ -43,9 +43,9 @@
 		spid = "?";
 		break;
 	}
-	printk("MaxLen=%x %sEndPt=%x Dev=%x, PID=%x(%s) ",
+	printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
 		td->info >> 21,
-		 ((td->info >> 19) & 1) ? "DT " : "",
+		 ((td->info >> 19) & 1),
 		 (td->info >> 15) & 15,
 		 (td->info >> 8) & 127,
 		 (td->info & 0xff),
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.10/linux/drivers/usb/uhci.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/uhci.c	Mon Jul 19 11:18:42 1999
@@ -344,10 +344,14 @@
 	spin_unlock_irqrestore(&irqlist_lock, flags);
 }
 
+
 /*
  * Request a interrupt handler..
+ *
+ * Returns: a "handle pointer" that release_irq can use to stop this
+ * interrupt.  (It's really a pointer to the TD).
  */
-static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+static void* uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	struct uhci_device *root_hub=usb_to_uhci(dev->uhci->bus->root_hub);
@@ -357,7 +361,7 @@
 	unsigned int destination, status;
 
 	/* Destination: pipe destination with INPUT */
-	destination = (pipe & 0x0007ff00) | 0x69;
+	destination = (pipe & PIPE_DEVEP_MASK) | 0x69;
 
 	/* Status:    slow/fast,      Interrupt,   Active,    Short Packet Detect     Infinite Errors */
 	status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23)   |   (1 << 29)       |    (0 << 27);
@@ -368,7 +372,8 @@
 
 	td->link = 1;
 	td->status = status;			/* In */
-	td->info = destination | (7 << 21) | (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19);	/* 8 bytes of data */
+	td->info = destination | ((usb_maxpacket(usb_dev, pipe) - 1) << 21) |
+		(usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19);
 	td->buffer = virt_to_bus(dev->data);
 	td->first = td;
 	td->qh = interrupt_qh;
@@ -388,13 +393,16 @@
 
 	/* Add it into the skeleton */
 	uhci_insert_qh(interrupt_qh->skel, interrupt_qh);
-	return 0;
+
+	return (void*)td;
 }
 
 /*
  * Remove running irq td from queues
+ *
+ * This function is not used anymore.
  */
-
+#if 0
 static int uhci_remove_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
 {
     struct uhci_device *dev = usb_to_uhci(usb_dev);
@@ -435,11 +443,56 @@
     spin_unlock_irqrestore(&irqlist_lock, flags);
     return USB_ST_INTERNALERROR;
 }
+#endif
+
+/*
+ * Release an interrupt handler previously allocated using
+ * uhci_request_irq.  This function does no validity checking, so make
+ * sure you're not releasing an already released handle as it may be
+ * in use by something else..
+ *
+ * This function can NOT be called from an interrupt.
+ */
+int uhci_release_irq(void* handle)
+{
+	struct uhci_td *td;
+	struct uhci_qh *interrupt_qh;
+	unsigned long flags;
+
+#ifdef UHCI_DEBUG
+	printk("usb-uhci: Releasing irq handle %p\n", handle);
+#endif
+
+	td = (struct uhci_td*)handle;
+	if (td == NULL)
+		return USB_ST_INTERNALERROR;
+
+	/* Remove it from the internal irq_list */
+	spin_lock_irqsave(&irqlist_lock, flags);
+	list_del(&td->irq_list);
+	spin_unlock_irqrestore(&irqlist_lock, flags);
+
+	/* Remove the interrupt TD and QH */
+	uhci_remove_td(td);
+	interrupt_qh = td->qh;
+	uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
+
+	if (td->completed != NULL)
+		td->completed(USB_ST_REMOVED, NULL, 0, td->dev_id);
+
+	/* Free the TD and QH */
+	uhci_td_deallocate(td);
+	uhci_qh_deallocate(interrupt_qh);
+
+	return USB_ST_NOERROR;
+} /* uhci_release_irq() */
+
+
 /*
  * Isochronous thread operations
  */
 
-int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc)
+static int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc)
 {
 	struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
 	char *data = isodesc->data;
@@ -466,7 +519,7 @@
 	return totlen;
 }
 
-int uhci_unsched_isochronous(struct usb_device *usb_dev, void *_isodesc)
+static int uhci_unschedule_isochronous(struct usb_device *usb_dev, void *_isodesc)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	struct uhci *uhci = dev->uhci;
@@ -489,7 +542,7 @@
 }
 	
 /* td points to the one td we allocated for isochronous transfers */
-int uhci_sched_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
+static int uhci_schedule_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	struct uhci *uhci = dev->uhci;
@@ -499,7 +552,7 @@
 
 	if (isodesc->frame != -1) {
 		printk("isoc queue not removed\n");
-		uhci_unsched_isochronous(usb_dev, isodesc);
+		uhci_unschedule_isochronous(usb_dev, isodesc);
 	}
 
 	/* Insert TD into list */
@@ -541,7 +594,7 @@
 /*
  * Initialize isochronous queue
  */
-void *uhci_alloc_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
+static void *uhci_allocate_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	unsigned long destination, status;
@@ -580,7 +633,7 @@
 		td = &isodesc->td[i];
 
 		/* The "pipe" thing contains the destination in bits 8--18 */
-		destination = (pipe & 0x0007ff00);
+		destination = (pipe & PIPE_DEVEP_MASK);
 
 		if (usb_pipeout(pipe))
 			destination |= 0xE1;	/* OUT */
@@ -616,13 +669,13 @@
 	return isodesc;
 }
 
-void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc)
+static void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc)
 {
 	struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc;
 
 	/* If it's still scheduled, unschedule them */
 	if (isodesc->frame)
-		uhci_unsched_isochronous(usb_dev, isodesc);
+		uhci_unschedule_isochronous(usb_dev, isodesc);
 
 	/* Remove it from the IRQ list */
 	uhci_remove_irq_list(&isodesc->td[isodesc->num - 1]);
@@ -732,7 +785,7 @@
  * information, that's just ridiculously high. Most
  * control messages have just a few bytes of data.
  */
-static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
+static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len)
 {
 	struct uhci_device *dev = usb_to_uhci(usb_dev);
 	struct uhci_td *first, *td, *prevtd;
@@ -746,7 +799,7 @@
 	first = td = uhci_td_allocate(dev);
 
 	/* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */
-	destination = (pipe & 0x0007ff00) | 0x2D;
+	destination = (pipe & PIPE_DEVEP_MASK) | 0x2D;
 
 	/* Status:    slow/fast,       Active,    Short Packet Detect     Three Errors */
 	status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 29)       |    (3 << 27);
@@ -807,7 +860,7 @@
 
 	td->backptr = &prevtd->link;
 	td->status = (status /* & ~(3 << 27) */) | (1 << 24);	/* no limit on final packet */
-	td->info = destination | (0x7ff << 21);		/* 0 bytes of data */
+	td->info = destination | (UHCI_NULL_DATA_SIZE << 21);	/* 0 bytes of data */
 	td->buffer = 0;
 	td->first = first;
 	td->link = 1;					/* Terminate */
@@ -837,7 +890,7 @@
 	}
 
 	if (uhci_debug && ret) {
-		__u8 *p = cmd;
+		__u8 *p = (__u8 *)cmd;
 
 		printk("Failed cmd - %02X %02X %02X %02X %02X %02X %02X %02X\n",
 		       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
@@ -964,10 +1017,10 @@
 	  I FORGOT WHAT IT EXACTLY DOES
 	*/
 	if (usb_pipeout(pipe)) {
-		destination = (pipe & 0x0007ff00) | 0xE1;
+		destination = (pipe & PIPE_DEVEP_MASK) | 0xE1;
 	}
 	else {
-		destination = (pipe & 0x0007ff00) | 0x69;
+		destination = (pipe & PIPE_DEVEP_MASK) | 0x69;
 	}
 
 	/* Status:    slow/fast,       Active,    Short Packet Detect     Three Errors */
@@ -1124,7 +1177,12 @@
 	uhci_control_msg,
 	uhci_bulk_msg,
 	uhci_request_irq,
-	uhci_remove_irq,
+	uhci_release_irq,
+	uhci_allocate_isochronous,
+	uhci_delete_isochronous,
+	uhci_schedule_isochronous,
+	uhci_unschedule_isochronous,
+	uhci_compress_isochronous
 };
 
 /*
@@ -1192,6 +1250,9 @@
 	 * and find out what it wants to do..
 	 */
 	usb_dev = uhci_usb_allocate(root_hub->usb);
+	if (!usb_dev)
+		return;
+	
 	dev = usb_dev->hcpriv;
 
 	dev->uhci = uhci;
@@ -1622,8 +1683,8 @@
 				printk("UHCI queue dump:\n");
 				show_queues(uhci);
 			} else if (signr == SIGUSR2) {
-				printk("UHCI debug toggle\n");
 				uhci_debug = !uhci_debug;
+				printk("UHCI debug toggle = %x\n", uhci_debug);
 			} else {
 				break;
 			}
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- v2.3.10/linux/drivers/usb/uhci.h	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/uhci.h	Mon Jul 19 11:17:32 1999
@@ -53,6 +53,8 @@
 #define   USBPORTSC_PR		0x0200	/* Port Reset */
 #define   USBPORTSC_SUSP	0x1000	/* Suspend */
 
+#define UHCI_NULL_DATA_SIZE	0x7ff	/* for UHCI controller TD */
+
 struct uhci_qh {
 	unsigned int link;	/* Next queue */
 	unsigned int element;	/* Queue element pointer */
@@ -237,12 +239,6 @@
 void show_td(struct uhci_td * td);
 void show_status(struct uhci *uhci);
 void show_queues(struct uhci *uhci);
-
-int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc);
-int uhci_unsched_isochronous(struct usb_device *usb_dev, void *_isodesc);
-int uhci_sched_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc);
-void *uhci_alloc_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id);
-void uhci_delete_isochronous(struct usb_device *dev, void *_isodesc);
 
 #endif
 
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/usb-debug.c linux/drivers/usb/usb-debug.c
--- v2.3.10/linux/drivers/usb/usb-debug.c	Fri Jun  4 13:33:43 1999
+++ linux/drivers/usb/usb-debug.c	Mon Jul 19 11:17:32 1999
@@ -53,12 +53,21 @@
  */
 void usb_show_device_descriptor(struct usb_device_descriptor *desc)
 {
-	printk("  USB version %x.%02x\n", desc->bcdUSB >> 8, desc->bcdUSB & 0xff);
-	printk("  Vendor:  %04x\n", desc->idVendor);
-	printk("  Product: %04x\n", desc->idProduct);
-	printk("  Configurations: %d\n", desc->bNumConfigurations);
+	printk("  Length              = %2d%s\n", desc->bLength,
+		desc->bLength == USB_DT_DEVICE_SIZE ? "" : " (!!!)");
+	printk("  DescriptorType      = %02x\n", desc->bDescriptorType);
+
+	printk("  USB version         = %x.%02x\n",
+		desc->bcdUSB >> 8, desc->bcdUSB & 0xff);
+	printk("  Vendor:Product      = %04x:%04x\n",
+		desc->idVendor, desc->idProduct);
+	printk("  MaxPacketSize0      = %d\n", desc->bMaxPacketSize0);
+	printk("  NumConfigurations   = %d\n", desc->bNumConfigurations);
+	printk("  Device version      = %x.%02x\n",
+		desc->bcdDevice >> 8, desc->bcdDevice & 0xff);
 
-	printk("  Device Class: %d\n", desc->bDeviceClass);
+	printk("  Device Class:SubClass:Protocol = %02x:%02x:%02x\n",
+		desc->bDeviceClass, desc->bDeviceSubClass, desc->bDeviceProtocol);
 	switch (desc->bDeviceClass) {
 	case 0:
 		printk("    Per-interface classes\n");
@@ -78,7 +87,7 @@
 {
 	printk("Configuration:\n");
 	printk("  bLength             = %4d%s\n", desc->bLength,
-		desc->bLength == 9 ? "" : " (!!!)");
+		desc->bLength == USB_DT_CONFIG_SIZE ? "" : " (!!!)");
 	printk("  bDescriptorType     =   %02x\n", desc->bDescriptorType);
 	printk("  wTotalLength        = %04x\n", desc->wTotalLength);
 	printk("  bNumInterfaces      =   %02x\n", desc->bNumInterfaces);
@@ -92,14 +101,13 @@
 {
 	printk("  Interface:\n");
 	printk("    bLength             = %4d%s\n", desc->bLength,
-		desc->bLength == 9 ? "" : " (!!!)");
+		desc->bLength == USB_DT_INTERFACE_SIZE ? "" : " (!!!)");
 	printk("    bDescriptorType     =   %02x\n", desc->bDescriptorType);
 	printk("    bInterfaceNumber    =   %02x\n", desc->bInterfaceNumber);
 	printk("    bAlternateSetting   =   %02x\n", desc->bAlternateSetting);
 	printk("    bNumEndpoints       =   %02x\n", desc->bNumEndpoints);
-	printk("    bInterfaceClass     =   %02x\n", desc->bInterfaceClass);
-	printk("    bInterfaceSubClass  =   %02x\n", desc->bInterfaceSubClass);
-	printk("    bInterfaceProtocol  =   %02x\n", desc->bInterfaceProtocol);
+	printk("    bInterface Class:SubClass:Protocol =   %02x:%02x:%02x\n",
+		desc->bInterfaceClass, desc->bInterfaceSubClass, desc->bInterfaceProtocol);
 	printk("    iInterface          =   %02x\n", desc->iInterface);
 }
 
@@ -108,7 +116,7 @@
 	char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };
 	printk("    Endpoint:\n");
 	printk("      bLength             = %4d%s\n", desc->bLength,
-		desc->bLength == 7 ? "" : " (!!!)");
+		desc->bLength == USB_DT_ENDPOINT_SIZE ? "" : " (!!!)");
 	printk("      bDescriptorType     =   %02x\n", desc->bDescriptorType);
 	printk("      bEndpointAddress    =   %02x (%s)\n", desc->bEndpointAddress,
 		(desc->bEndpointAddress & 0x80) ? "in" : "out");
@@ -133,6 +141,8 @@
 
 void usb_show_string(struct usb_device* dev, char *id, int index)
 {
-	if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
-		printk("%s: %s\n", id, dev->stringindex[index]);
+	char *p = usb_string(dev, index);
+
+	if (p != 0)
+		printk(KERN_INFO "%s: %s\n", id, p);
 }
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.10/linux/drivers/usb/usb.c	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/usb.c	Mon Jul 19 11:17:32 1999
@@ -1,5 +1,5 @@
 /*
- * driver/usb/usb.c
+ * drivers/usb/usb.c
  *
  * (C) Copyright Linus Torvalds 1999
  *
@@ -476,10 +476,18 @@
 	}
 	kfree(dev->config);
 
+	for (i = 1; i < USB_MAXSTRINGS; ++i) {
+		if (dev->stringindex[i]) {
+			kfree(dev->stringindex[i]);
+			dev->stringindex[i] = 0;
+		}
+	}
+#if 0
 	if (dev->stringindex)
 		kfree(dev->stringindex);
 	if (dev->stringtable)
 		kfree(dev->stringtable);
+#endif
 }
 			
 void usb_init_root_hub(struct usb_device *dev)
@@ -567,7 +575,8 @@
 	dr.length = size;
 
 	while (i--) {
-		if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size)))
+		if (!(result = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size))
+		    || result == USB_ST_STALL)
 			break;
 	}
 	return result;
@@ -588,11 +597,15 @@
 
 int usb_get_device_descriptor(struct usb_device *dev)
 {
-	return usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor));
-	le16_to_cpus(&dev->descriptor.bcdUSB);
-	le16_to_cpus(&dev->descriptor.idVendor);
-	le16_to_cpus(&dev->descriptor.idProduct);
-	le16_to_cpus(&dev->descriptor.bcdDevice);
+	int ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor,
+				     sizeof(dev->descriptor));
+	if (ret == 0) {
+		le16_to_cpus(&dev->descriptor.bcdUSB);
+		le16_to_cpus(&dev->descriptor.idVendor);
+		le16_to_cpus(&dev->descriptor.idProduct);
+		le16_to_cpus(&dev->descriptor.bcdDevice);
+	}
+	return ret;
 }
 
 int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
@@ -634,6 +647,19 @@
 	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
 }
 
+int usb_get_status (struct usb_device *dev, int type, int target, void *data)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_DIR_IN | type;	/* USB_RECIP_DEVICE, _INTERFACE, or _ENDPOINT */
+	dr.request = USB_REQ_GET_STATUS;
+	dr.value = 0;
+	dr.index = target;
+	dr.length = 2;
+
+	return dev->bus->op->control_msg (dev, usb_rcvctrlpipe (dev,0), &dr, data, 2);
+}
+
 int usb_get_hub_status(struct usb_device *dev, void *data)
 {
 	devrequest dr;
@@ -884,6 +910,7 @@
 	return parse;
 }
 
+#if 0
 int usb_get_stringtable(struct usb_device *dev)
 {
 	int i;
@@ -914,7 +941,7 @@
 		return -1;
 
 	/* get space for strings and index */
-	dev->stringindex = kmalloc(sizeof(char *)*maxindex, GFP_KERNEL);
+	dev->stringindex = kmalloc(sizeof(char *) * (maxindex+1), GFP_KERNEL);
 	if (!dev->stringindex)
 		return -1;
 	dev->stringtable = kmalloc(totalchars, GFP_KERNEL);
@@ -925,7 +952,7 @@
 	}
 
 	/* fill them in */
-	memset(dev->stringindex, 0, sizeof(char *)*maxindex);
+	memset(dev->stringindex, 0, sizeof(char *) * (maxindex+1));
 	for (i=1, string = dev->stringtable; i <= maxindex; i++) {
 		if (usb_get_string(dev, langid, i, buffer, bLengths[i]))
 			continue;
@@ -938,6 +965,48 @@
 	dev->maxstring = maxindex;
 	return 0;
 }
+#endif
+
+char *usb_string(struct usb_device *dev, int index)
+{
+	int len, i;
+	char *ptr;
+	union {
+		unsigned char buffer[256];
+		struct usb_string_descriptor desc;
+	} u;
+
+	if (index <= 0 || index >= USB_MAXSTRINGS)
+		return 0;
+	if (dev->stringindex[index] != 0)
+		return dev->stringindex[index];
+
+	if (dev->string_langid == 0) {
+		/* read string descriptor 0 */
+		if (usb_get_string(dev, 0, 0, u.buffer, 2) == 0
+		    && u.desc.bLength >= 4
+		    && usb_get_string(dev, 0, 0, u.buffer, 4) == 0)
+			dev->string_langid = le16_to_cpup(&u.desc.wData[0]);
+		dev->string_langid |= 0x10000;	/* so it's non-zero */
+	}
+
+	if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2)
+	    || usb_get_string(dev, dev->string_langid, index, u.buffer,
+			      u.desc.bLength))
+		return 0;
+
+	len = u.desc.bLength / 2;	/* includes terminating null */
+	ptr = kmalloc(len, GFP_KERNEL);
+	if (ptr == 0)
+		return 0;
+
+	for (i = 0; i < len - 1; ++i)
+		ptr[i] = le16_to_cpup(&u.desc.wData[i]);
+	ptr[i] = 0;
+
+	dev->stringindex[index] = ptr;
+	return ptr;
+}
 
 /*
  * By the time we get here, the device has gotten a new device ID
@@ -1010,7 +1079,7 @@
 		return;
 	}
 
-	usb_get_stringtable(dev);
+	/* usb_get_stringtable(dev); */
 
 	dev->actconfig = dev->config;
 	dev->ifnum = 0;
@@ -1036,7 +1105,38 @@
 	}
 }
 
-int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+void* usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
 {
 	return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
+}
+
+
+void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id)
+{
+	return usb_dev->bus->op->alloc_isoc (usb_dev, pipe, data, len, maxsze, completed, dev_id);
+}
+
+void usb_delete_isochronous (struct usb_device *dev, void *_isodesc)
+{
+	return dev->bus->op->delete_isoc (dev, _isodesc);
+}
+
+int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc)
+{
+	return usb_dev->bus->op->sched_isoc (usb_dev, _isodesc, _pisodesc);
+}
+
+int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc)
+{
+	return usb_dev->bus->op->unsched_isoc (usb_dev, _isodesc);
+}
+
+int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc)
+{
+	return usb_dev->bus->op->compress_isoc (usb_dev, _isodesc);
+}
+
+int usb_release_irq(struct usb_device *dev, void* handle)
+{
+	return dev->bus->op->release_irq(handle);
 }
diff -u --recursive --new-file v2.3.10/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.10/linux/drivers/usb/usb.h	Thu Jul  8 15:42:21 1999
+++ linux/drivers/usb/usb.h	Mon Jul 19 11:19:28 1999
@@ -149,6 +149,7 @@
 #define USB_ST_REMOVED		0x100
 #define USB_ST_TIMEOUT		0x110
 #define USB_ST_INTERNALERROR	-1
+#define USB_ST_NOTSUPPORTED	-2
 
 /*
  * USB device number allocation bitmap. There's one bitmap
@@ -169,7 +170,7 @@
 #define USB_MAXALTSETTING       5
 #define USB_MAXINTERFACES	32
 #define USB_MAXENDPOINTS	32
-#define USB_MAXSTRINGS		16
+#define USB_MAXSTRINGS		32
 
 struct usb_device_descriptor {
 	__u8  bLength;
@@ -276,6 +277,9 @@
  *         of the buffer by this transfer.  (-1 = unknown/unsupported)
  *     void *dev_id - This is a user defined pointer set when the IRQ
  *         is requested that is passed back.
+ *
+ *   Special Cases:
+ *     if (status == USB_ST_REMOVED), don't trust buffer or len.
  */
 typedef int (*usb_device_irq)(int, void *, int, void *);
 
@@ -284,8 +288,13 @@
 	int (*deallocate)(struct usb_device *);
 	int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int);
 	int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *);
-	int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
-	int (*remove_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
+	void* (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
+	int (*release_irq)(void* handle);
+	void *(*alloc_isoc)(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id);
+	void (*delete_isoc)(struct usb_device *dev, void *_isodesc);
+	int (*sched_isoc)(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc);
+	int (*unsched_isoc)(struct usb_device *usb_dev, void *_isodesc);
+	int (*compress_isoc)(struct usb_device *usb_dev, void *_isodesc);
 };
 
 /*
@@ -306,8 +315,8 @@
 	int devnum;			/* Device number on USB bus */
 	int slow;			/* Slow device? */
 	int maxpacketsize;		/* Maximum packet size; encoded as 0,1,2,3 = 8,16,32,64 */
-	int toggle[2];			/* one bit for each endpoint ([0] = IN, [1] = OUT) */
-	int halted;			/* endpoint halts */
+	unsigned int toggle[2];		/* one bit for each endpoint ([0] = IN, [1] = OUT) */
+	unsigned int halted;		/* endpoint halts */
 	struct usb_config_descriptor *actconfig;/* the active configuration */
 	int epmaxpacket[16];		/* endpoint specific maximums */
 	int ifnum;			/* active interface number */
@@ -316,10 +325,9 @@
 	struct usb_device_descriptor descriptor;/* Descriptor */
 	struct usb_config_descriptor *config;	/* All of the configs */
 	struct usb_device *parent;
-	char *stringtable;		/* Strings (multiple, null term) */
-	char **stringindex;		/* pointers to strings */
-	int maxstring;			/* max valid index */
-
+	char *stringindex[USB_MAXSTRINGS];	/* pointers to strings */
+	int string_langid;		/* language ID for strings */
+  
 	/*
 	 * Child devices - these can be either new devices
 	 * (if this is a hub device), or different instances
@@ -341,7 +349,8 @@
 extern void usb_register_bus(struct usb_bus *);
 extern void usb_deregister_bus(struct usb_bus *);
 
-extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
+extern void* usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
+extern int usb_release_irq(struct usb_device *dev, void *handle);
 
 extern void usb_init_root_hub(struct usb_device *dev);
 extern void usb_connect(struct usb_device *dev);
@@ -353,6 +362,13 @@
 extern int  usb_parse_configuration(struct usb_device *dev, void *buf, int len);
 extern void usb_destroy_configuration(struct usb_device *dev);
 
+extern void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len,
+					int maxsze, usb_device_irq completed, void *dev_id);
+extern void usb_delete_isochronous (struct usb_device *dev, void *_isodesc);
+extern int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc);
+extern int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc);
+extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc);
+
 /*
  * Calling this entity a "pipe" is glorifying it. A USB pipe
  * is something embarrassingly simple: it basically consists
@@ -377,7 +393,7 @@
  *  - device:		bits 8-14
  *  - endpoint:		bits 15-18
  *  - Data0/1:		bit 19
- *  - speed:		bit 26		(00 = Full, 01 = Low Speed)
+ *  - speed:		bit 26		(0 = Full, 1 = Low Speed)
  *  - pipe type:	bits 30-31	(00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk)
  *
  * Why? Because it's arbitrary, and whatever encoding we select is really
@@ -389,19 +405,18 @@
 #define usb_maxpacket(dev,pipe)	((dev)->epmaxpacket[usb_pipeendpoint(pipe)])
 #define usb_packetid(pipe)	(((pipe) & 0x80) ? 0x69 : 0xE1)
 
+#define usb_pipeout(pipe)	((((pipe) >> 7) & 1) ^ 1)
 #define usb_pipedevice(pipe)	(((pipe) >> 8) & 0x7f)
+#define usb_pipe_endpdev(pipe)	(((pipe) >> 8) & 0x7ff)
 #define usb_pipeendpoint(pipe)	(((pipe) >> 15) & 0xf)
 #define usb_pipedata(pipe)	(((pipe) >> 19) & 1)
-#define usb_pipeout(pipe)	((((pipe) >> 7) & 1) ^ 1)
 #define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
-
 #define usb_pipetype(pipe)	(((pipe) >> 30) & 3)
 #define usb_pipeisoc(pipe)	(usb_pipetype((pipe)) == 0)
 #define usb_pipeint(pipe)	(usb_pipetype((pipe)) == 1)
 #define usb_pipecontrol(pipe)	(usb_pipetype((pipe)) == 2)
 #define usb_pipebulk(pipe)	(usb_pipetype((pipe)) == 3)
 
-#define usb_pipe_endpdev(pipe)	(((pipe) >> 8) & 0x7ff)
 #define PIPE_DEVEP_MASK		0x0007ff00
 
 /* The D0/D1 toggle bits */
@@ -445,21 +460,18 @@
 int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size);
 int usb_clear_port_feature(struct usb_device *dev, int port, int feature);
 int usb_set_port_feature(struct usb_device *dev, int port, int feature);
+int usb_get_status (struct usb_device *dev, int type, int target, void *data);
 int usb_get_hub_status(struct usb_device *dev, void *data);
 int usb_get_port_status(struct usb_device *dev, int port, void *data);
 int usb_get_protocol(struct usb_device *dev);
 int usb_set_protocol(struct usb_device *dev, int protocol);
+int usb_set_interface(struct usb_device *dev, int interface, int alternate);
 int usb_set_idle(struct usb_device *dev, int duration, int report_id);
+int usb_set_interface(struct usb_device *dev, int interface, int alternate);
 int usb_set_configuration(struct usb_device *dev, int configuration);
 int usb_get_report(struct usb_device *dev);
+char *usb_string(struct usb_device *dev, int index);
 int usb_clear_halt(struct usb_device *dev, int endp);
-static inline char * usb_string(struct usb_device* dev, int index)
-{
-	if (index <= dev->maxstring && dev->stringindex && dev->stringindex[index])
-		return dev->stringindex[index];
-	else
-		return NULL;
-}
 
 /*
  * Debugging helpers..
diff -u --recursive --new-file v2.3.10/linux/drivers/video/vgacon.c linux/drivers/video/vgacon.c
--- v2.3.10/linux/drivers/video/vgacon.c	Wed Jun 16 19:26:27 1999
+++ linux/drivers/video/vgacon.c	Mon Jul 19 12:30:06 1999
@@ -186,18 +186,21 @@
 		vga_video_port_val = 0x3b5;
 		if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
 		{
+			static struct resource ega_console_resource = { "ega", 0x3B0, 0x3BF };
 			vga_video_type = VIDEO_TYPE_EGAM;
 			vga_vram_end = 0xb8000;
 			display_desc = "EGA+";
-			request_region(0x3b0,16,"ega");
+			request_resource(&ioport_resource, &ega_console_resource);
 		}
 		else
 		{
+			static struct resource mda1_console_resource = { "mda", 0x3B0, 0x3BB };
+			static struct resource mda2_console_resource = { "mda", 0x3BF, 0x3BF };
 			vga_video_type = VIDEO_TYPE_MDA;
 			vga_vram_end = 0xb2000;
 			display_desc = "*MDA";
-			request_region(0x3b0,12,"mda");
-			request_region(0x3bf, 1,"mda");
+			request_resource(&ioport_resource, &mda1_console_resource);
+			request_resource(&ioport_resource, &mda2_console_resource);
 			vga_video_font_height = 14;
 		}
 	}
@@ -214,13 +217,15 @@
 			vga_vram_end = 0xc0000;
 
 			if (!ORIG_VIDEO_ISVGA) {
+				static struct resource ega_console_resource = { "ega", 0x3C0, 0x3DF };
 				vga_video_type = VIDEO_TYPE_EGAC;
 				display_desc = "EGA";
-				request_region(0x3c0,32,"ega");
+				request_resource(&ioport_resource, &ega_console_resource);
 			} else {
+				static struct resource vga_console_resource = { "vga+", 0x3C0, 0x3DF };
 				vga_video_type = VIDEO_TYPE_VGAC;
 				display_desc = "VGA+";
-				request_region(0x3c0,32,"vga+");
+				request_resource(&ioport_resource, &vga_console_resource);
 
 #ifdef VGA_CAN_DO_64KB
 				/*
@@ -261,10 +266,11 @@
 		}
 		else
 		{
+			static struct resource cga_console_resource = { "cga", 0x3D4, 0x3D5 };
 			vga_video_type = VIDEO_TYPE_CGA;
 			vga_vram_end = 0xba000;
 			display_desc = "*CGA";
-			request_region(0x3d4,2,"cga");
+			request_resource(&ioport_resource, &cga_console_resource);
 			vga_video_font_height = 8;
 		}
 	}
diff -u --recursive --new-file v2.3.10/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.3.10/linux/fs/binfmt_aout.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/binfmt_aout.c	Wed Jul 21 09:47:15 1999
@@ -106,7 +106,7 @@
 #       define START_STACK(u)   (u.start_stack)
 #endif
 
-	if (!current->dumpable || atomic_read(&current->mm->count) != 1)
+	if (!current->dumpable || atomic_read(&current->mm->mm_users) != 1)
 		return 0;
 	current->dumpable = 0;
 
diff -u --recursive --new-file v2.3.10/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.3.10/linux/fs/binfmt_elf.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/binfmt_elf.c	Wed Jul 21 09:47:01 1999
@@ -1060,7 +1060,7 @@
 
 	if (!current->dumpable ||
 	    limit < ELF_EXEC_PAGESIZE ||
-	    atomic_read(&current->mm->count) != 1)
+	    atomic_read(&current->mm->mm_users) != 1)
 		return 0;
 	current->dumpable = 0;
 
diff -u --recursive --new-file v2.3.10/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.10/linux/fs/buffer.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/buffer.c	Wed Jul 21 10:05:13 1999
@@ -757,9 +757,9 @@
 
 	free = test_and_clear_bit(PG_free_after, &page->flags);
 
-	if (page->owner != -1)
+	if (page->owner != (void *)-1)
 		PAGE_BUG(page);
-	page->owner = (int)current;
+	page->owner = current;
 	UnlockPage(page);
 
 	if (free)
@@ -1195,7 +1195,7 @@
 
 	if (!PageLocked(page))
 		BUG();
-	if (page->owner != (int)current)
+	if (page->owner != current)
 		PAGE_BUG(page);
 	/*
 	 * Allocate async buffer heads pointing to this page, just for I/O.
@@ -1270,6 +1270,7 @@
 				mark_buffer_clean(bh);
 				clear_bit(BH_Uptodate, &bh->b_state);
 				clear_bit(BH_Mapped, &bh->b_state);
+				clear_bit(BH_Req, &bh->b_state);
 				bh->b_blocknr = 0;
 				atomic_dec(&bh->b_count);
 			}
@@ -1556,7 +1557,7 @@
 	}
 	if (!page->buffers)
 		BUG();
-	page->owner = -1;
+	page->owner = (void *)-1;
 
 	head = page->buffers;
 	bh = head;
@@ -1605,7 +1606,7 @@
 	} else {
 		if (!nr && rw == READ) {
 			SetPageUptodate(page);
-			page->owner = (int)current;
+			page->owner = current;
 			UnlockPage(page);
 		}
 		if (nr && (rw == WRITE))
@@ -1639,7 +1640,7 @@
 
 	blocks = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
 	iblock = page->offset >> inode->i_sb->s_blocksize_bits;
-	page->owner = -1;
+	page->owner = (void *)-1;
 	head = page->buffers;
 	bh = head;
 	nr = 0;
@@ -1674,7 +1675,7 @@
 		 * uptodate as well.
 		 */
 		SetPageUptodate(page);
-		page->owner = (int)current;
+		page->owner = current;
 		UnlockPage(page);
 	}
 	return 0;
@@ -1968,8 +1969,25 @@
 		goto out;
 
 	if (func == 1) {
-		 error = sync_old_buffers();
-		 goto out;
+		struct mm_struct *user_mm;
+		/*
+		 * bdflush will spend all of it's time in kernel-space,
+		 * without touching user-space, so we can switch it into
+		 * 'lazy TLB mode' to reduce the cost of context-switches
+		 * to and from bdflush.
+		 */
+		user_mm = current->mm;
+		atomic_inc(&user_mm->mm_count);
+		current->mm = NULL;
+		/* active_mm is still 'user_mm' */
+
+		error = sync_old_buffers();
+
+		current->mm = user_mm;
+		mmdrop(current->active_mm);
+		current->active_mm = user_mm;
+
+		goto out;
 	}
 
 	/* Basically func 1 means read param 1, 2 means write param 1, etc */
diff -u --recursive --new-file v2.3.10/linux/fs/exec.c linux/fs/exec.c
--- v2.3.10/linux/fs/exec.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/exec.c	Wed Jul 21 13:57:56 1999
@@ -366,54 +366,41 @@
 static int exec_mmap(void)
 {
 	struct mm_struct * mm, * old_mm;
-	int retval, nr;
 
-	if (atomic_read(&current->mm->count) == 1) {
-		flush_cache_mm(current->mm);
+	old_mm = current->mm;
+	if (old_mm && atomic_read(&old_mm->mm_users) == 1) {
+		flush_cache_mm(old_mm);
 		mm_release();
-		release_segments(current->mm);
-		exit_mmap(current->mm);
-		flush_tlb_mm(current->mm);
+		release_segments(old_mm);
+		exit_mmap(old_mm);
+		flush_tlb_mm(old_mm);
 		return 0;
 	}
 
-	retval = -ENOMEM;
 	mm = mm_alloc();
-	if (!mm)
-		goto fail_nomem;
-
-	mm->cpu_vm_mask = (1UL << smp_processor_id());
-	mm->total_vm = 0;
-	mm->rss = 0;
-	/*
-	 * Make sure we have a private ldt if needed ...
-	 */
-	nr = current->tarray_ptr - &task[0]; 
-	copy_segments(nr, current, mm);
-
-	old_mm = current->mm;
-	current->mm = mm;
-	retval = new_page_tables(current);
-	if (retval)
-		goto fail_restore;
-	activate_context(current);
-	up(&mm->mmap_sem);
-	mm_release();
-	mmput(old_mm);
-	return 0;
-
-	/*
-	 * Failure ... restore the prior mm_struct.
-	 */
-fail_restore:
-	current->mm = old_mm;
-	/* restore the ldt for this task */
-	copy_segments(nr, current, NULL);
-	release_segments(mm);
-	kmem_cache_free(mm_cachep, mm);
-
-fail_nomem:
-	return retval;
+	if (mm) {
+		mm->cpu_vm_mask = (1UL << smp_processor_id());
+		mm->total_vm = 0;
+		mm->rss = 0;
+		mm->pgd = pgd_alloc();
+		if (mm->pgd) {
+			struct mm_struct *active_mm = current->active_mm;
+
+			current->mm = mm;
+			current->active_mm = mm;
+			SET_PAGE_DIR(current, mm->pgd);
+			activate_context(current);
+			mm_release();
+			if (old_mm) {
+				mmput(old_mm);
+				return 0;
+			}
+			mmdrop(active_mm);
+			return 0;
+		}
+		kmem_cache_free(mm_cachep, mm);
+	}
+	return -ENOMEM;
 }
 
 /*
@@ -632,7 +619,7 @@
 	if (id_change || cap_raised) {
 		/* We can't suid-execute if we're sharing parts of the executable */
 		/* or if we're being traced (or if suid execs are not allowed)    */
-		/* (current->mm->count > 1 is ok, as we'll get a new mm anyway)   */
+		/* (current->mm->mm_users > 1 is ok, as we'll get a new mm anyway)   */
 		if (IS_NOSUID(inode)
 		    || must_not_trace_exec(current)
 		    || (atomic_read(&current->fs->count) > 1)
diff -u --recursive --new-file v2.3.10/linux/fs/fcntl.c linux/fs/fcntl.c
--- v2.3.10/linux/fs/fcntl.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/fcntl.c	Mon Jul 12 10:15:18 1999
@@ -31,6 +31,7 @@
 	return error;
 
 out_putf:
+	write_unlock(&files->file_lock);
 	fput(file);
 	goto out;
 }
diff -u --recursive --new-file v2.3.10/linux/fs/file_table.c linux/fs/file_table.c
--- v2.3.10/linux/fs/file_table.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/file_table.c	Wed Jul 14 13:30:36 1999
@@ -116,16 +116,29 @@
 		return 0;
 }
 
-void _fput(struct file *file)
+/*
+ * Called when retiring the last use of a file pointer.
+ */
+static void __fput(struct file *filp)
 {
-	atomic_inc(&file->f_count);
+	struct dentry * dentry = filp->f_dentry;
+	struct inode * inode = dentry->d_inode;
+
+	if (filp->f_op && filp->f_op->release)
+		filp->f_op->release(inode, filp);
+	filp->f_dentry = NULL;
+	if (filp->f_mode & FMODE_WRITE)
+		put_write_access(inode);
+	dput(dentry);
+}
 
+void _fput(struct file *file)
+{
 	lock_kernel();
 	locks_remove_flock(file);	/* Still need the */
 	__fput(file);			/* big lock here. */
 	unlock_kernel();
 
-	atomic_set(&file->f_count, 0);
 	file_list_lock();
 	list_del(&file->f_list);
 	list_add(&file->f_list, &free_list);
@@ -182,7 +195,7 @@
 
 		/* Writable file? */
 		if (S_ISREG(inode->i_mode) && (file->f_mode & FMODE_WRITE))
-			return 0;
+			goto too_bad;
 	}
 	file_list_unlock();
 	return 1; /* Tis' cool bro. */
diff -u --recursive --new-file v2.3.10/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.3.10/linux/fs/ncpfs/dir.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/ncpfs/dir.c	Fri Jul 16 10:57:40 1999
@@ -349,6 +349,9 @@
 	int len = dentry->d_name.len;      
 	struct ncpfs_inode_info finfo;
 	__u8 __name[dentry->d_name.len + 1];
+
+	if (!dir)
+		return 0;
         
 	server = NCP_SERVER(dir);
 
diff -u --recursive --new-file v2.3.10/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.3.10/linux/fs/nfs/read.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/nfs/read.c	Mon Jul 19 12:29:29 1999
@@ -152,7 +152,7 @@
 		fail++;
 		dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
 	}
-	page->owner = (int)current; // HACK, FIXME, will go away.
+	page->owner = current; // HACK, FIXME, will go away.
 	UnlockPage(page);
 	free_page(address);
 
diff -u --recursive --new-file v2.3.10/linux/fs/open.c linux/fs/open.c
--- v2.3.10/linux/fs/open.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/open.c	Wed Jul 14 13:28:04 1999
@@ -765,22 +765,6 @@
 #endif
 
 /*
- * Called when retiring the last use of a file pointer.
- */
-void __fput(struct file *filp)
-{
-	struct dentry * dentry = filp->f_dentry;
-	struct inode * inode = dentry->d_inode;
-
-	if (filp->f_op && filp->f_op->release)
-		filp->f_op->release(inode, filp);
-	filp->f_dentry = NULL;
-	if (filp->f_mode & FMODE_WRITE)
-		put_write_access(inode);
-	dput(dentry);
-}
-
-/*
  * "id" is the POSIX thread ID. We use the
  * files pointer for this..
  */
diff -u --recursive --new-file v2.3.10/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.3.10/linux/fs/proc/array.c	Wed Jun 30 13:38:20 1999
+++ linux/fs/proc/array.c	Wed Jul 21 09:45:56 1999
@@ -223,7 +223,7 @@
 		LOAD_INT(a), LOAD_FRAC(a),
 		LOAD_INT(b), LOAD_FRAC(b),
 		LOAD_INT(c), LOAD_FRAC(c),
-		nr_running, nr_tasks, last_pid);
+		nr_running, nr_threads, last_pid);
 }
 
 static int get_kstat(char * buffer)
@@ -312,7 +312,7 @@
 	unsigned long idle;
 
 	uptime = jiffies;
-	idle = task[0]->times.tms_utime + task[0]->times.tms_stime;
+	idle = init_tasks[0]->times.tms_utime + init_tasks[0]->times.tms_stime;
 
 	/* The formula for the fraction parts really is ((t * 100) / HZ) % 100, but
 	   that would overflow about every five days at HZ == 100.
@@ -495,7 +495,7 @@
 		int count = 0;
 
 		stack_page = (unsigned long)p;
-		esp = p->tss.esp;
+		esp = p->thread.esp;
 		if (!stack_page || esp < stack_page || esp >= 8188+stack_page)
 			return 0;
 		/* include/asm-i386/system.h:switch_to() pushes ebp last. */
@@ -742,7 +742,7 @@
 {
 	struct mm_struct * mm = p->mm;
 
-	if (mm && mm != &init_mm) {
+	if (mm) {
 		struct vm_area_struct * vma = mm->mmap;
 		unsigned long data = 0, stack = 0;
 		unsigned long exec = 0, lib = 0;
@@ -868,7 +868,7 @@
 		return 0;
 	state = *get_task_state(tsk);
 	vsize = eip = esp = 0;
-	if (tsk->mm && tsk->mm != &init_mm) {
+	if (tsk->mm) {
 		struct vm_area_struct *vma = tsk->mm->mmap;
 		while (vma) {
 			vsize += vma->vm_end - vma->vm_start;
@@ -1025,7 +1025,7 @@
 	read_unlock(&tasklist_lock);	/* FIXME!! This should be done after the last use */
 	if (!tsk)
 		return 0;
-	if (tsk->mm && tsk->mm != &init_mm) {
+	if (tsk->mm) {
 		struct vm_area_struct * vma = tsk->mm->mmap;
 
 		while (vma) {
@@ -1111,11 +1111,11 @@
 	if (!p)
 		goto freepage_out;
 
-	if (!p->mm || p->mm == &init_mm || count == 0)
+	if (!p->mm || count == 0)
 		goto getlen_out;
 
 	/* Check whether the mmaps could change if we sleep */
-	volatile_task = (p != current || atomic_read(&p->mm->count) > 1);
+	volatile_task = (p != current || atomic_read(&p->mm->mm_users) > 1);
 
 	/* decode f_pos */
 	lineno = *ppos >> MAPS_LINE_SHIFT;
@@ -1378,8 +1378,6 @@
 		ok = p->dumpable;
 		if(!cap_issubset(p->cap_permitted, current->cap_permitted))
 			ok=0;			
-		if(!p->mm)	/* Scooby scooby doo where are you ? */
-			p=NULL;
 	}
 		
 	read_unlock(&tasklist_lock);
diff -u --recursive --new-file v2.3.10/linux/fs/proc/fd.c linux/fs/proc/fd.c
--- v2.3.10/linux/fs/proc/fd.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/proc/fd.c	Sun Jul 11 09:11:46 1999
@@ -133,7 +133,7 @@
 static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
-	struct task_struct * p, **tarrayp;
+	struct task_struct *p, *tmp;
 	unsigned int fd, pid, ino;
 	int retval;
 	char buf[NUMBUF];
@@ -157,7 +157,6 @@
 	p = find_task_by_pid(pid);
 	if (!p)
 		goto out_unlock;
-	tarrayp = p->tarray_ptr;
 
 	for (fd -= 2 ; p->files && fd < p->files->max_fds; fd++, filp->f_pos++)
 	{
@@ -182,8 +181,13 @@
 			goto out;
 
 		read_lock(&tasklist_lock);
-		/* filldir() might have slept, so we must re-validate "p" */
-		if (p != *tarrayp || p->pid != pid)
+		/*
+		 * filldir() might have slept, so we must
+		 * re-validate "p". This is fast enough due
+		 * to the pidhash
+		 */
+		tmp = find_task_by_pid(pid);
+		if (p != tmp)
 			break;
 	}
 out_unlock:
diff -u --recursive --new-file v2.3.10/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.3.10/linux/fs/proc/root.c	Thu Jul  8 15:42:21 1999
+++ linux/fs/proc/root.c	Sun Jul 11 09:11:46 1999
@@ -849,14 +849,29 @@
 	int len;
 
 	if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
-		dir->i_nlink = proc_root.nlink;
+		extern unsigned long total_forks;
+		static int last_timestamp = 0;
 
-		read_lock(&tasklist_lock);
-		for_each_task(p) {
-			if (p->pid)
-				dir->i_nlink++;
+		/*
+		 * this one can be a serious 'ps' performance problem if
+		 * there are many threads running - thus we do 'lazy'
+		 * link-recalculation - we change it only if the number
+		 * of threads has increased.
+		 */
+		if (total_forks != last_timestamp) {
+			int nlink = proc_root.nlink;
+
+			read_lock(&tasklist_lock);
+			last_timestamp = total_forks;
+			for_each_task(p)
+				nlink++;
+			read_unlock(&tasklist_lock);
+			/*
+			 * subtract the # of idle threads which
+			 * do not show up in /proc:
+			 */
+			dir->i_nlink = nlink - smp_num_cpus;
 		}
-		read_unlock(&tasklist_lock);
 	}
 
 	if (!proc_lookup(dir, dentry))
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/core_pyxis.h linux/include/asm-alpha/core_pyxis.h
--- v2.3.10/linux/include/asm-alpha/core_pyxis.h	Sun Dec 27 15:21:50 1998
+++ linux/include/asm-alpha/core_pyxis.h	Mon Jul 12 07:49:36 1999
@@ -74,8 +74,8 @@
 #define PYXIS_MEM_R2_MASK 0x07ffffff  /* SPARSE Mem region 2 mask is 27 bits */
 #define PYXIS_MEM_R3_MASK 0x03ffffff  /* SPARSE Mem region 3 mask is 26 bits */
 
-#define PYXIS_DMA_WIN_BASE_DEFAULT	(1024*1024*1024)
-#define PYXIS_DMA_WIN_SIZE_DEFAULT	(1024*1024*1024)
+#define PYXIS_DMA_WIN_BASE_DEFAULT	(2UL*1024*1024*1024)
+#define PYXIS_DMA_WIN_SIZE_DEFAULT	(1UL*1024*1024*1024)
 
 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM_SETUP)
 #define PYXIS_DMA_WIN_BASE		alpha_mv.dma_win_base
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/hardirq.h linux/include/asm-alpha/hardirq.h
--- v2.3.10/linux/include/asm-alpha/hardirq.h	Mon Oct 12 11:40:13 1998
+++ linux/include/asm-alpha/hardirq.h	Mon Jul 19 13:12:47 1999
@@ -5,8 +5,12 @@
 
 #include <linux/tasks.h>
 
-extern unsigned int local_irq_count[NR_CPUS];
-extern unsigned long hardirq_no[NR_CPUS];
+#ifndef __SMP__
+extern int __local_irq_count;
+#define local_irq_count(cpu)  ((void)(cpu), __local_irq_count)
+#else
+#define local_irq_count(cpu)  (cpu_data[cpu].irq_count)
+#endif
 
 /*
  * Are we in an interrupt context? Either doing bottom half
@@ -16,16 +20,16 @@
 #define in_interrupt()						\
 ({								\
 	int __cpu = smp_processor_id();				\
-	(local_irq_count[__cpu] + local_bh_count[__cpu]) != 0;	\
+	(local_irq_count(__cpu) + local_bh_count(__cpu)) != 0;	\
 })
 
 #ifndef __SMP__
 
-#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu)	(local_irq_count(cpu) == 0)
 #define hardirq_endlock(cpu)	((void) 0)
 
-#define hardirq_enter(cpu, irq)	(local_irq_count[cpu]++)
-#define hardirq_exit(cpu, irq)	(local_irq_count[cpu]--)
+#define hardirq_enter(cpu, irq)	(local_irq_count(cpu)++)
+#define hardirq_exit(cpu, irq)	(local_irq_count(cpu)--)
 
 #define synchronize_irq()	barrier()
 
@@ -50,21 +54,20 @@
 
 static inline void hardirq_enter(int cpu, int irq)
 {
-	++local_irq_count[cpu];
+	++local_irq_count(cpu);
         atomic_inc(&global_irq_count);
-	hardirq_no[cpu] |= 1L << irq;		/* debugging only */
 }
 
 static inline void hardirq_exit(int cpu, int irq)
 {
-	hardirq_no[cpu] &= ~(1L << irq);	/* debugging only */
 	atomic_dec(&global_irq_count);
-        --local_irq_count[cpu];
+        --local_irq_count(cpu);
 }
 
 static inline int hardirq_trylock(int cpu)
 {
-	return !atomic_read(&global_irq_count) && !global_irq_lock.lock;
+	return (!atomic_read(&global_irq_count)
+		&& !spin_is_locked(&global_irq_lock));
 }
 
 #define hardirq_endlock(cpu)  ((void)0)
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/mmu_context.h linux/include/asm-alpha/mmu_context.h
--- v2.3.10/linux/include/asm-alpha/mmu_context.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/mmu_context.h	Mon Jul 19 13:12:47 1999
@@ -66,7 +66,11 @@
 #endif /* __SMP__ */
 
 #define WIDTH_HARDWARE_ASN	8
+#ifdef __SMP__
 #define WIDTH_THIS_PROCESSOR	5
+#else
+#define WIDTH_THIS_PROCESSOR	0
+#endif
 #define ASN_FIRST_VERSION (1UL << (WIDTH_THIS_PROCESSOR + WIDTH_HARDWARE_ASN))
 #define HARDWARE_ASN_MASK ((1UL << WIDTH_HARDWARE_ASN) - 1)
 
@@ -95,12 +99,11 @@
 	unsigned long asn = cpu_last_asn(smp_processor_id());
 	unsigned long next = asn + 1;
 
-	if ((next ^ asn) & ~MAX_ASN) {
+	if ((asn & HARDWARE_ASN_MASK) >= MAX_ASN) {
 		tbiap();
 		next = (asn & ~HARDWARE_ASN_MASK) + ASN_FIRST_VERSION;
 	}
 	cpu_last_asn(smp_processor_id()) = next;
-	mm->context = next;                      /* full version + asn */
 	return next;
 }
 
@@ -110,6 +113,12 @@
 	/* As described, ASN's are broken.  But we can optimize for
 	   switching between threads -- if the mm is unchanged from
 	   current we needn't flush.  */
+	/* ??? May not be needed because EV4 PALcode recognizes that
+	   ASN's are broken and does a tbiap itself on swpctx, under
+	   the "Must set ASN or flush" rule.  At least this is true
+	   for a 1992 SRM, reports Joseph Martin (jmartin@hlo.dec.com).
+	   I'm going to leave this here anyway, just to Be Sure.  -- r~  */
+
 	if (current->mm != p->mm)
 		tbiap();
 }
@@ -119,17 +128,23 @@
 {
 	/* Check if our ASN is of an older version, or on a different CPU,
 	   and thus invalid.  */
+	/* ??? If we have two threads on different cpus, we'll continually
+	   fight over the context.  Find a way to record a per-mm, per-cpu
+	   value for the asn.  */
 
-	long asn = cpu_last_asn(smp_processor_id());
+	unsigned long asn = cpu_last_asn(smp_processor_id());
 	struct mm_struct *mm = p->mm;
-	long mmc = mm->context;
+	unsigned long mmc = mm->context;
 	
-	if ((p->tss.mm_context ^ asn) & ~HARDWARE_ASN_MASK) {
-		if ((mmc ^ asn) & ~HARDWARE_ASN_MASK)
-			mmc = __get_new_mmu_context(p, mm);
-		p->tss.mm_context = mmc;
-		p->tss.asn = mmc & HARDWARE_ASN_MASK;
+	if ((mmc ^ asn) & ~HARDWARE_ASN_MASK) {
+		mmc = __get_new_mmu_context(p, mm);
+		mm->context = mmc;
 	}
+
+	/* Always update the PCB ASN.  Another thread may have allocated
+	   a new mm->context (via flush_tlb_mm) without the ASN serial
+	   number wrapping.  We have no way to detect when this is needed.  */
+	p->tss.asn = mmc & HARDWARE_ASN_MASK;
 }
 
 #ifdef CONFIG_ALPHA_GENERIC
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/param.h linux/include/asm-alpha/param.h
--- v2.3.10/linux/include/asm-alpha/param.h	Sun Mar 24 02:09:37 1996
+++ linux/include/asm-alpha/param.h	Tue Jul 13 02:29:35 1999
@@ -1,8 +1,18 @@
 #ifndef _ASM_ALPHA_PARAM_H
 #define _ASM_ALPHA_PARAM_H
 
+/* ??? Gross.  I don't want to parameterize this, and supposedly the
+   hardware ignores reprogramming.  We also need userland buy-in to the 
+   change in HZ, since this is visible in the wait4 resources etc.  */
+
+#include <linux/config.h>
+
 #ifndef HZ
-# define HZ	1024
+# ifndef CONFIG_ALPHA_RAWHIDE
+#  define HZ	1024
+# else
+#  define HZ	1200
+# endif
 #endif
 
 #define EXEC_PAGESIZE	8192
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.3.10/linux/include/asm-alpha/pgtable.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-alpha/pgtable.h	Mon Jul 19 13:12:47 1999
@@ -49,7 +49,6 @@
 __EXTERN_INLINE void
 ev5_flush_tlb_current(struct mm_struct *mm)
 {
-	mm->context = 0;
 	get_new_mmu_context(current, mm);
 	reload_context(current);
 }
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
--- v2.3.10/linux/include/asm-alpha/processor.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/processor.h	Mon Jul 12 07:49:36 1999
@@ -61,15 +61,6 @@
 	 */
 	unsigned long flags;
 
-	/* The full version of the ASN including serial number.
-
-	   Two threads running on two different processors must of necessity
-	   have different serial numbers.  Having this duplicated from
-	   mm->context allows them to be slightly out of sync preventing 
-	   the asn from incrementing each and every time the two threads
-	   are scheduled.  */
-	unsigned long mm_context;
-
 	/* Perform syscall argument validation (get/set_fs). */
 	mm_segment_t fs;
 
@@ -86,7 +77,7 @@
 	0, 0, 0, \
 	0, 0, 0, \
 	0, 0, 0, \
-	0, 0, \
+	0, \
 	KERNEL_DS \
 }
 
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/ptrace.h linux/include/asm-alpha/ptrace.h
--- v2.3.10/linux/include/asm-alpha/ptrace.h	Mon Apr  7 11:35:31 1997
+++ linux/include/asm-alpha/ptrace.h	Mon Jul 12 07:49:36 1999
@@ -67,7 +67,7 @@
 };
 
 #ifdef __KERNEL__
-#define user_mode(regs) ((regs)->ps & 8)
+#define user_mode(regs) (((regs)->ps & 8) != 0)
 #define instruction_pointer(regs) ((regs)->pc)
 extern void show_regs(struct pt_regs *);
 #endif
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h
--- v2.3.10/linux/include/asm-alpha/smp.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/smp.h	Mon Jul 19 13:12:47 1999
@@ -4,7 +4,6 @@
 #ifdef __SMP__
 
 #include <linux/tasks.h>
-#include <asm/init.h>
 #include <asm/pal.h>
 
 struct cpuinfo_alpha {
@@ -16,7 +15,8 @@
 	unsigned long ipi_count;
 	unsigned long prof_multiplier;
 	unsigned long prof_counter;
-} __cacheline_aligned;
+	int irq_count, bh_count;
+} __attribute__((aligned(64)));
 
 extern struct cpuinfo_alpha cpu_data[NR_CPUS];
 
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h
--- v2.3.10/linux/include/asm-alpha/softirq.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/softirq.h	Mon Jul 19 13:12:47 1999
@@ -5,28 +5,33 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-extern unsigned int local_bh_count[NR_CPUS];
+#ifndef __SMP__
+extern int __local_bh_count;
+#define local_bh_count(cpu)	((void)(cpu), __local_bh_count)
+#else
+#define local_bh_count(cpu)	(cpu_data[cpu].bh_count)
+#endif
 
 extern inline void cpu_bh_disable(int cpu)
 {
-	local_bh_count[cpu]++;
+	local_bh_count(cpu)++;
 	mb();
 }
 
 extern inline void cpu_bh_enable(int cpu)
 {
 	mb();
-	local_bh_count[cpu]--;
+	local_bh_count(cpu)--;
 }
 
 extern inline int cpu_bh_trylock(int cpu)
 {
-	return local_bh_count[cpu] ? 0 : (local_bh_count[cpu] = 1);
+	return local_bh_count(cpu) ? 0 : (local_bh_count(cpu) = 1);
 }
 
 extern inline void cpu_bh_endlock(int cpu)
 {
-	local_bh_count[cpu] = 0;
+	local_bh_count(cpu) = 0;
 }
 
 #define local_bh_enable()	cpu_bh_enable(smp_processor_id())
diff -u --recursive --new-file v2.3.10/linux/include/asm-alpha/spinlock.h linux/include/asm-alpha/spinlock.h
--- v2.3.10/linux/include/asm-alpha/spinlock.h	Tue Jun 22 10:46:52 1999
+++ linux/include/asm-alpha/spinlock.h	Mon Jul 19 13:12:47 1999
@@ -65,11 +65,12 @@
   #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 #endif
 
-#define spin_lock_init(lock)			((void) 0)
-#define spin_lock(lock)				((void) 0)
-#define spin_trylock(lock)			(1)
-#define spin_unlock_wait(lock)			((void) 0)
-#define spin_unlock(lock)			((void) 0)
+#define spin_lock_init(lock)			((void)(lock))
+#define spin_lock(lock)				((void)(lock))
+#define spin_trylock(lock)			((void)(lock), 1)
+#define spin_unlock_wait(lock)			((void)(lock))
+#define spin_unlock(lock)			((void)(lock))
+#define spin_is_locked(lock)			((void)(lock), 0)
 
 /*
  * Read-write spinlocks, allowing multiple readers
@@ -91,10 +92,10 @@
   #define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
 #endif
 
-#define read_lock(lock)				((void) 0)
-#define read_unlock(lock)			((void) 0)
-#define write_lock(lock)			((void) 0)
-#define write_unlock(lock)			((void) 0)
+#define read_lock(lock)				((void)(lock))
+#define read_unlock(lock)			((void)(lock))
+#define write_lock(lock)			((void)(lock))
+#define write_unlock(lock)			((void)(lock))
 
 #else /* __SMP__ */
 
@@ -131,8 +132,8 @@
 #define spin_lock_init(x)	((x)->lock = 0)
 #endif
 
-#define spin_unlock_wait(x) \
-	({ do { barrier(); } while(((volatile spinlock_t *)x)->lock); })
+#define spin_is_locked(x)	((x)->lock != 0)
+#define spin_unlock_wait(x)	({ do { barrier(); } while ((x)->lock); })
 
 typedef struct { unsigned long a[100]; } __dummy_lock_t;
 #define __dummy_lock(lock) (*(__dummy_lock_t *)(lock))
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/arch-arc/time.h linux/include/asm-arm/arch-arc/time.h
--- v2.3.10/linux/include/asm-arm/arch-arc/time.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-arc/time.h	Mon Jul 19 09:52:57 1999
@@ -167,6 +167,9 @@
 		else
 			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
 	}
+
+	if (!user_mode(regs))
+		do_profile(instruction_pointer(regs));
 }
 
 static struct irqaction timerirq = {
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h
--- v2.3.10/linux/include/asm-arm/arch-ebsa110/hardware.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa110/hardware.h	Mon Jul 19 09:52:57 1999
@@ -40,5 +40,7 @@
 #define FLUSH_BASE		0xdf000000
 #define PCIO_BASE		0xf0000000
 
+#define PARAMS_BASE		(PAGE_OFFSET + 0x400)
+
 #endif
 
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h
--- v2.3.10/linux/include/asm-arm/arch-ebsa285/io.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-ebsa285/io.h	Mon Jul 19 09:52:57 1999
@@ -1,10 +1,11 @@
 /*
  * linux/include/asm-arm/arch-ebsa285/io.h
  *
- * Copyright (C) 1997,1998 Russell King
+ * Copyright (C) 1997-1999 Russell King
  *
  * Modifications:
- *  06-Dec-1997	RMK	Created.
+ *  06-12-1997	RMK	Created.
+ *  07-04-1999	RMK	Major cleanup
  */
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
@@ -18,132 +19,33 @@
 #undef	ARCH_IO_DELAY
 #define ARCH_READWRITE
 
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-#define DECLARE_DYN_OUT(fnsuffix,instr,typ)				\
-extern __inline__ void							\
-__out##fnsuffix (unsigned int value, unsigned int port)			\
-{									\
-	__asm__ __volatile__(						\
-	"str%?" ##instr## "	%0, [%1, %2]	@ out"###fnsuffix	\
-	: 								\
-	: "r" (value), "r" (PCIO_BASE), typ (port));			\
-}
+#define __pci_io_addr(x)	(PCIO_BASE + (unsigned int)(x))
 
-#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ)				\
-extern __inline__ unsigned sz						\
-__in##fnsuffix (unsigned int port)					\
-{									\
-	unsigned long value;						\
-	__asm__ __volatile__(						\
-	"ldr%?" ##instr## "	%0, [%1, %2]	@ in"###fnsuffix	\
-	: "=&r" (value)							\
-	: "r" (PCIO_BASE), typ (port));					\
-	return (unsigned sz)value;					\
-}
+#define __inb(p)		(*(volatile unsigned char *)__pci_io_addr(p))
+#define __inl(p)		(*(volatile unsigned long *)__pci_io_addr(p))
 
-extern __inline__ unsigned int __ioaddr (unsigned int port)		\
-{									\
-	return (unsigned int)(PCIO_BASE + port);			\
+extern __inline__ unsigned int __inw(unsigned int port)
+{
+	unsigned int value;
+	__asm__ __volatile__(
+	"ldr%?h	%0, [%1, %2]	@ inw"
+	: "=&r" (value)
+	: "r" (PCIO_BASE), "r" (port));
+	return value;
 }
 
-#define DECLARE_IO(sz,fnsuffix,instr,typ)	\
-	DECLARE_DYN_OUT(fnsuffix,instr,typ)	\
-	DECLARE_DYN_IN(sz,fnsuffix,instr,typ)
-
-DECLARE_IO(char,b,"b","Jr")
-DECLARE_IO(short,w,"h","r")
-DECLARE_IO(long,l,"","Jr")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_OUT
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)						\
-({									\
-	__asm__ __volatile__(						\
-	"str%?b	%0, [%1, %2]				@ outbc"	\
-	:								\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));			\
-})
-
-#define __inbc(port)							\
-({									\
-	unsigned char result;						\
-	__asm__ __volatile__(						\
-	"ldr%?b	%0, [%1, %2]				@ inbc"		\
-	: "=r" (result)							\
-	: "r" (PCIO_BASE), "Jr" (port));				\
-	result;								\
-})
-
-#define __outwc(value,port)						\
-({									\
-	__asm__ __volatile__(						\
-	"str%?h	%0, [%1, %2]				@ outwc"	\
-	:								\
-	: "r" (value), "r" (PCIO_BASE), "r" (port));			\
-})
-
-#define __inwc(port)							\
-({									\
-	unsigned short result;						\
-	__asm__ __volatile__(						\
-	"ldr%?h	%0, [%1, %2]				@ inwc"		\
-	: "=r" (result)							\
-	: "r" (PCIO_BASE), "r" (port));					\
-	result & 0xffff;						\
-})
-
-#define __outlc(value,port)						\
-({									\
-	__asm__ __volatile__(						\
-	"str%?	%0, [%1, %2]				@ outlc"	\
-	:								\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));			\
-})
-
-#define __inlc(port)							\
-({									\
-	unsigned long result;						\
-	__asm__ __volatile__(						\
-	"ldr%?	%0, [%1, %2]				@ inlc"		\
-	: "=r" (result)							\
-	: "r" (PCIO_BASE), "Jr" (port));				\
-	result;								\
-})
 
-#define __ioaddrc(port)							\
-({									\
-	unsigned long addr;						\
-	addr = PCIO_BASE + port;					\
-	addr;								\
-})
+#define __outb(v,p)		(*(volatile unsigned char *)__pci_io_addr(p) = (v))
+#define __outl(v,p)		(*(volatile unsigned long *)__pci_io_addr(p) = (v))
 
-/*
- * Translated address IO functions
- *
- * IO address has already been translated to a virtual address
- */
-#define outb_t(v,p)							\
-	(*(volatile unsigned char *)(p) = (v))
-
-#define inb_t(p)							\
-	(*(volatile unsigned char *)(p))
-
-#define outl_t(v,p)							\
-	(*(volatile unsigned long *)(p) = (v))
+extern __inline__ void __outw(unsigned int value, unsigned int port)
+{
+	__asm__ __volatile__(
+	"str%?h	%0, [%1, %2]	@ outw"
+	: : "r" (value), "r" (PCIO_BASE), "r" (port));
+}
 
-#define inl_t(p)							\
-	(*(volatile unsigned long *)(p))
+#define __ioaddr(p)	__pci_io_addr(p)
 
 /*
  * ioremap support - validate a PCI memory address,
@@ -151,7 +53,7 @@
  * address for the page tables.
  */
 #define valid_ioaddr(iomem,size) ((iomem) < 0x80000000 && (iomem) + (size) <= 0x80000000)
-#define io_to_phys(iomem)	((iomem) + DC21285_PCI_MEM)
+#define io_to_phys(iomem)	 ((iomem) + DC21285_PCI_MEM)
 
 /*
  * Fudge up IO addresses by this much.  Once we're confident that nobody
@@ -178,28 +80,20 @@
 
 extern void iounmap(void *addr);
 
-#define DECLARE_PCI_WRITE(typ,fnsuffix)					\
-static inline void write##fnsuffix(unsigned typ val, unsigned int addr)	\
-{									\
-	*(volatile unsigned typ *)(IO_FUDGE_FACTOR + addr) = val;	\
-}
+#define __pci_mem_addr(x)	((void *)(IO_FUDGE_FACTOR + (unsigned long)(x)))
 
-#define DECLARE_PCI_READ(typ,fnsuffix)					\
-static inline unsigned typ read##fnsuffix (unsigned int addr)		\
-{									\
-	return *(volatile unsigned typ *)(IO_FUDGE_FACTOR + addr);	\
-}
+#define readb(addr)	(*(volatile unsigned char *)__pci_mem_addr(addr))
+#define readw(addr)	(*(volatile unsigned short *)__pci_mem_addr(addr))
+#define readl(addr)	(*(volatile unsigned long *)__pci_mem_addr(addr))
+
+#define writeb(b,addr)	(*(volatile unsigned char *)__pci_mem_addr(addr) = (b))
+#define writew(b,addr)	(*(volatile unsigned short *)__pci_mem_addr(addr) = (b))
+#define writel(b,addr)	(*(volatile unsigned long *)__pci_mem_addr(addr) = (b))
+
+#define memset_io(a,b,c)	memset(__pci_mem_addr(a),(b),(c))
+#define memcpy_fromio(a,b,c)	memcpy((a),__pci_mem_addr(b),(c))
+#define memcpy_toio(a,b,c)	memcpy(__pci_mem_addr(a),(b),(c))
 
-#define DECLARE_PCI(typ,fnsuffix)					\
-	DECLARE_PCI_WRITE(typ,fnsuffix)					\
-	DECLARE_PCI_READ(typ,fnsuffix)
-
-DECLARE_PCI(char,b)
-DECLARE_PCI(short,w)
-DECLARE_PCI(long,l)
-
-#undef DECLARE_PCI
-#undef DECLARE_PCI_READ
-#undef DECLARE_PCI_WRITE
+#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__pci_mem_addr(b),(c),(d))
 
 #endif
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.3.10/linux/include/asm-arm/arch-ebsa285/irq.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Mon Jul 19 09:52:57 1999
@@ -159,6 +159,8 @@
 	if (isa_irq != -1) {
 		/*
 		 * Setup, and then probe for an ISA PIC
+		 * If the PIC is not there, then we
+		 * ignore the PIC.
 		 */
 		outb(0x11, PIC_LO);
 		outb(_ISA_IRQ(0), PIC_MASK_LO);	/* IRQ number		*/
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/arch-ebsa285/time.h linux/include/asm-arm/arch-ebsa285/time.h
--- v2.3.10/linux/include/asm-arm/arch-ebsa285/time.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/arch-ebsa285/time.h	Mon Jul 19 09:52:57 1999
@@ -115,6 +115,9 @@
 		else
 			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
 	}
+
+	if (!user_mode(regs))
+		do_profile(instruction_pointer(regs));
 }
 
 static struct irqaction isa_timer_irq = {
@@ -257,6 +260,9 @@
 		else
 			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
 	}
+
+	if (!user_mode(regs))
+		do_profile(instruction_pointer(regs));
 }
 
 static struct irqaction __ebsa285_data timer1_irq = {
@@ -279,22 +285,20 @@
  */
 extern __inline__ void setup_timer(void)
 {
-	switch(machine_arch_type) {
-	case MACH_TYPE_CO285:
+	if (machine_arch_type == MACH_TYPE_CO285)
 		/*
 		 * Add-in 21285s shouldn't access the RTC
 		 */
 		rtc_base = 0;
-		break;
-
-	default:
+	else
 		rtc_base = 0x70;
-		break;
-	}
 
 	if (rtc_base) {
 		int reg_d, reg_b;
 
+		/*
+		 * Probe for the RTC.
+		 */
 		reg_d = CMOS_READ(RTC_REG_D);
 
 		/*
@@ -314,7 +318,7 @@
 		    CMOS_READ(RTC_REG_B) == reg_b) {
 
 			/*
-			 * Check the battery
+			 * We have a RTC.  Check the battery
 			 */
 			if ((reg_d & 0x80) == 0)
 				printk(KERN_WARNING "RTC: *** warning: CMOS battery bad\n");
@@ -332,7 +336,6 @@
 		xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0);
 		set_rtc_mmss = set_dummy_time;
 	}
-
 	if (machine_is_ebsa285() || machine_is_co285()) {
 		gettimeoffset = timer1_gettimeoffset;
 
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/arch-rpc/time.h linux/include/asm-arm/arch-rpc/time.h
--- v2.3.10/linux/include/asm-arm/arch-rpc/time.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/arch-rpc/time.h	Mon Jul 19 09:52:57 1999
@@ -151,7 +151,7 @@
 	 */
 	buf[4] &= 0x1f;
 	buf[3] &= 0x3f;
-printk("Year %4d mon %02X day %02X hour %02X min %02X sec %02X\n", year, buf[4], buf[3], buf[2], buf[1], buf[0]);
+
 	for (i = 0; i < 5; i++)
 		BCD_TO_BIN(buf[i]);
 
@@ -175,6 +175,9 @@
 		else
 			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
 	}
+
+	if (!user_mode(regs))
+		do_profile(instruction_pointer(regs));
 }
 
 static struct irqaction timerirq = {
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.3.10/linux/include/asm-arm/io.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/io.h	Mon Jul 19 09:52:57 1999
@@ -22,17 +22,6 @@
 
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
-/*
- * String version of IO memory access ops:
- */
-extern void _memcpy_fromio(void *, unsigned long, unsigned long);
-extern void _memcpy_toio(unsigned long, const void *, unsigned long);
-extern void _memset_io(unsigned long, int, unsigned long);
-
-#define memcpy_fromio(to,from,len)	_memcpy_fromio((to),(unsigned long)(from),(len))
-#define memcpy_toio(to,from,len)	_memcpy_toio((unsigned long)(to),(from),(len))
-#define memset_io(addr,c,len)		_memset_io((unsigned long)(addr),(c),(len))
-
 #endif
 
 #include <asm/hardware.h>
@@ -121,8 +110,12 @@
  * This macro will give you the translated IO address for this particular
  * architecture, which can be used with the out_t... functions.
  */
+#ifdef __ioaddrc
 #define ioaddr(port)	\
   (__builtin_constant_p((port)) ? __ioaddrc((port)) : __ioaddr((port)))
+#else
+#define ioaddr(port) __ioaddr((port))
+#endif
 
 #ifndef ARCH_IO_DELAY
 /*
@@ -203,6 +196,19 @@
 #define writew(v,p)	panic("writew called, but not implemented")
 #define writel(v,p)	panic("writel called, but not implemented")
 
+#endif
+
+#ifndef memcpy_fromio
+/*
+ * String version of IO memory access ops:
+ */
+extern void _memcpy_fromio(void *, unsigned long, unsigned long);
+extern void _memcpy_toio(unsigned long, const void *, unsigned long);
+extern void _memset_io(unsigned long, int, unsigned long);
+
+#define memcpy_fromio(to,from,len)	_memcpy_fromio((to),(unsigned long)(from),(len))
+#define memcpy_toio(to,from,len)	_memcpy_toio((unsigned long)(to),(from),(len))
+#define memset_io(addr,c,len)		_memset_io((unsigned long)(addr),(c),(len))
 #endif
 
 /*
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/page.h linux/include/asm-arm/page.h
--- v2.3.10/linux/include/asm-arm/page.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/page.h	Mon Jul 19 09:52:57 1999
@@ -6,6 +6,19 @@
 
 #ifdef __KERNEL__
 
+#ifndef __ASSEMBLY__
+
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	*(int *)0 = 0; \
+} while (0)
+
+#define PAGE_BUG(page) do { \
+	BUG(); \
+} while (0)
+
+#endif /* __ASSEMBLY__ */
+
 #define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
 #define free_user_page(page, addr)	free_page(addr)
 #define clear_page(page)		memzero((void *)(page), PAGE_SIZE)
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h
--- v2.3.10/linux/include/asm-arm/processor.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/processor.h	Mon Jul 19 09:52:57 1999
@@ -40,12 +40,20 @@
 #include <asm/arch/processor.h>
 #include <asm/proc/processor.h>
 
+struct debug_info {
+	int				nsaved;
+	struct {
+		unsigned long		address;
+		unsigned long		insn;
+	} bp[2];
+};
+
 struct thread_struct {
 	unsigned long			address;	  /* Address of fault	*/
 	unsigned long			trap_no;	  /* Trap number	*/
 	unsigned long			error_code;	  /* Error code of trap	*/
 	union fp_state			fpstate;	  /* FPE save state	*/
-	unsigned long			debug[NR_DEBUGS]; /* Debug/ptrace	*/
+	struct debug_info		debug;		  /* Debug/ptrace	*/
 	struct context_save_struct	*save;		  /* context save	*/
 	unsigned long			memmap;		  /* page tables	*/
 	EXTRA_THREAD_STRUCT
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/spinlock.h linux/include/asm-arm/spinlock.h
--- v2.3.10/linux/include/asm-arm/spinlock.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/spinlock.h	Mon Jul 19 13:12:47 1999
@@ -54,7 +54,7 @@
 #define SPIN_LOCK_UNLOCKED EMPTY_STRUCT_INIT(spinlock_t)
 
 #define spin_lock_init(lock)	do { } while(0)
-#define spin_lock(lock)		do { } while(0)
+#define spin_lock(lock)		(void)(lock) /* Not "unused variable". */
 #define spin_trylock(lock)	(1)
 #define spin_unlock_wait(lock)	do { } while(0)
 #define spin_unlock(lock)	do { } while(0)
@@ -105,9 +105,9 @@
 typedef EMPTY_STRUCT rwlock_t;
 #define RW_LOCK_UNLOCKED EMPTY_STRUCT_INIT(rwlock_t)
 
-#define read_lock(lock)		do { } while(0)
+#define read_lock(lock)		(void)(lock) /* Not "unused variable". */
 #define read_unlock(lock)	do { } while(0)
-#define write_lock(lock)	do { } while(0)
+#define write_lock(lock)	(void)(lock) /* Not "unused variable". */
 #define write_unlock(lock)	do { } while(0)
 
 #else
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/string.h linux/include/asm-arm/string.h
--- v2.3.10/linux/include/asm-arm/string.h	Tue Jan 20 16:39:43 1998
+++ linux/include/asm-arm/string.h	Mon Jul 19 09:52:57 1999
@@ -14,6 +14,7 @@
 #define __HAVE_ARCH_MEMCPY
 #define __HAVE_ARCH_MEMMOVE
 #define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_MEMCHR
 
 #define __HAVE_ARCH_MEMZERO
 extern void memzero(void *ptr, int n);
diff -u --recursive --new-file v2.3.10/linux/include/asm-arm/system.h linux/include/asm-arm/system.h
--- v2.3.10/linux/include/asm-arm/system.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/system.h	Mon Jul 19 09:52:57 1999
@@ -32,6 +32,7 @@
 #define MACH_TYPE_CLPS7110	9
 #define MACH_TYPE_ARCHIMEDES	10
 #define MACH_TYPE_A5K		11
+#define MACH_TYPE_SA1100	12	/* not allocated!!! */
 
 /*
  * Sort out a definition for machine_arch_type
diff -u --recursive --new-file v2.3.10/linux/include/asm-i386/desc.h linux/include/asm-i386/desc.h
--- v2.3.10/linux/include/asm-i386/desc.h	Wed Sep  9 08:56:58 1998
+++ linux/include/asm-i386/desc.h	Sun Jul 11 09:11:46 1999
@@ -1,6 +1,46 @@
 #ifndef __ARCH_DESC_H
 #define __ARCH_DESC_H
 
+#include <asm/ldt.h>
+
+/*
+ * The layout of the GDT under Linux:
+ *
+ *   0 - null
+ *   1 - not used
+ *   2 - kernel code segment
+ *   3 - kernel data segment
+ *   4 - user code segment                  <-- new cacheline 
+ *   5 - user data segment
+ *   6 - not used
+ *   7 - not used
+ *   8 - APM BIOS support                   <-- new cacheline 
+ *   9 - APM BIOS support
+ *  10 - APM BIOS support
+ *  11 - APM BIOS support
+ *
+ * The TSS+LDT descriptors are spread out a bit so that every CPU
+ * has an exclusive cacheline for the per-CPU TSS and LDT:
+ *
+ *  12 - CPU#0 TSS                          <-- new cacheline 
+ *  13 - CPU#0 LDT
+ *  14 - not used 
+ *  15 - not used 
+ *  16 - CPU#1 TSS                          <-- new cacheline 
+ *  17 - CPU#1 LDT
+ *  18 - not used 
+ *  19 - not used 
+ *  ... NR_CPUS per-CPU TSS+LDT's if on SMP
+ *
+ * Entry into gdt where to find first TSS.
+ */
+#define __FIRST_TSS_ENTRY 12
+#define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1)
+
+#define __TSS(n) (((n)<<2) + __FIRST_TSS_ENTRY)
+#define __LDT(n) (((n)<<2) + __FIRST_LDT_ENTRY)
+
+#ifndef __ASSEMBLY__
 struct desc_struct {
 	unsigned long a,b;
 };
@@ -16,46 +56,33 @@
 #define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
 #define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
 
+#define load_TR(n) __asm__ __volatile__("ltr %%ax"::"a" (__TSS(n)<<3))
+
+#define __load_LDT(n) __asm__ __volatile__("lldt %%ax"::"a" (__LDT(n)<<3))
+
 /*
- * Entry into gdt where to find first TSS. GDT layout:
- *   0 - null
- *   1 - not used
- *   2 - kernel code segment
- *   3 - kernel data segment
- *   4 - user code segment
- *   5 - user data segment
- *   6 - not used
- *   7 - not used
- *   8 - APM BIOS support
- *   9 - APM BIOS support
- *  10 - APM BIOS support
- *  11 - APM BIOS support
- *  12 - TSS #0
- *  13 - LDT #0
- *  14 - TSS #1
- *  15 - LDT #1
+ * This is the ldt that every process will get unless we need
+ * something other than this.
  */
-#define FIRST_TSS_ENTRY 12
-#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
-#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
-#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
-#define load_TR(n) __asm__ __volatile__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
-#define load_ldt(n) __asm__ __volatile__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
-#define store_TR(n) \
-__asm__("str %%ax\n\t" \
-	"subl %2,%%eax\n\t" \
-	"shrl $4,%%eax" \
-	:"=a" (n) \
-	:"0" (0),"i" (FIRST_TSS_ENTRY<<3))
-
+extern struct desc_struct default_ldt;
 extern void set_intr_gate(unsigned int irq, void * addr);
 extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
 extern void set_tss_desc(unsigned int n, void *addr);
 
 /*
- * This is the ldt that every process will get unless we need
- * something other than this.
+ * load one particular LDT into the current CPU
  */
-extern struct desc_struct default_ldt;
+extern inline void load_LDT (struct mm_struct *mm)
+{
+	int cpu = smp_processor_id();
+
+	if (mm->segments)
+		set_ldt_desc(cpu, mm->segments, LDT_ENTRIES);
+	else
+		set_ldt_desc(cpu, &default_ldt, 1);
+	__load_LDT(cpu);
+}
+
+#endif /* !__ASSEMBLY__ */
 
 #endif
diff -u --recursive --new-file v2.3.10/linux/include/asm-i386/hardirq.h linux/include/asm-i386/hardirq.h
--- v2.3.10/linux/include/asm-i386/hardirq.h	Tue Jun 22 14:41:40 1999
+++ linux/include/asm-i386/hardirq.h	Wed Jul 21 14:52:45 1999
@@ -1,7 +1,7 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
 
diff -u --recursive --new-file v2.3.10/linux/include/asm-i386/ldt.h linux/include/asm-i386/ldt.h
--- v2.3.10/linux/include/asm-i386/ldt.h	Wed Dec 11 06:41:23 1996
+++ linux/include/asm-i386/ldt.h	Sun Jul 11 09:11:46 1999
@@ -11,6 +11,7 @@
 /* The size of each LDT entry. */
 #define LDT_ENTRY_SIZE	8
 
+#ifndef __ASSEMBLY__
 struct modify_ldt_ldt_s {
 	unsigned int  entry_number;
 	unsigned long base_addr;
@@ -27,4 +28,5 @@
 #define MODIFY_LDT_CONTENTS_STACK	1
 #define MODIFY_LDT_CONTENTS_CODE	2
 
+#endif /* !__ASSEMBLY__ */
 #endif
diff -u --recursive --new-file v2.3.10/linux/include/asm-i386/mmu_context.h linux/include/asm-i386/mmu_context.h
--- v2.3.10/linux/include/asm-i386/mmu_context.h	Tue May  5 21:33:33 1998
+++ linux/include/asm-i386/mmu_context.h	Mon Jul 19 16:18:57 1999
@@ -1,13 +1,27 @@
 #ifndef __I386_MMU_CONTEXT_H
 #define __I386_MMU_CONTEXT_H
 
+#include <asm/desc.h>
+
 /*
- * get a new mmu context.. x86's don't know about contexts.
+ * get a new mmu context.. x86's don't know much about contexts,
+ * but we have to reload the new LDT in exec().
+ *
+ * We implement lazy MMU context-switching on x86 to optimize context
+ * switches done to/from kernel threads. Kernel threads 'inherit' the
+ * previous MM, so Linux doesnt have to flush the TLB. In most cases
+ * we switch back to the same process so we preserve the TLB cache.
+ * This all means that kernel threads have about as much overhead as
+ * a function call ...
  */
-#define get_mmu_context(x) do { } while (0)
+#define get_mmu_context(next) do { } while (0)
+#define set_mmu_context(prev,next) do { next->thread.cr3 = prev->thread.cr3; } while(0)
 
 #define init_new_context(mm)	do { } while(0)
+/*
+ * possibly do the LDT unload here?
+ */
 #define destroy_context(mm)	do { } while(0)
-#define activate_context(tsk)	do { } while(0)
+#define activate_context(x)	load_LDT((x)->mm)
 
 #endif
diff -u --recursive --new-file v2.3.10/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.3.10/linux/include/asm-i386/pgtable.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-i386/pgtable.h	Wed Jul 21 14:52:46 1999
@@ -15,7 +15,7 @@
 #ifndef __ASSEMBLY__
 #include <asm/processor.h>
 #include <asm/fixmap.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 /* Caches aren't brain-dead on the intel. */
 #define flush_cache_all()			do { } while (0)
@@ -101,7 +101,7 @@
 static inline void flush_tlb_current_task(void)
 {
 	/* just one copy of this mm? */
-	if (atomic_read(&current->mm->count) == 1)
+	if (atomic_read(&current->mm->mm_users) == 1)
 		local_flush_tlb();	/* and that's us, so.. */
 	else
 		smp_flush_tlb();
@@ -113,7 +113,7 @@
 
 static inline void flush_tlb_mm(struct mm_struct * mm)
 {
-	if (mm == current->mm && atomic_read(&mm->count) == 1)
+	if (mm == current->mm && atomic_read(&mm->mm_users) == 1)
 		local_flush_tlb();
 	else
 		smp_flush_tlb();
@@ -122,7 +122,7 @@
 static inline void flush_tlb_page(struct vm_area_struct * vma,
 	unsigned long va)
 {
-	if (vma->vm_mm == current->mm && atomic_read(&current->mm->count) == 1)
+	if (vma->vm_mm == current->mm && atomic_read(&current->mm->mm_users) == 1)
 		__flush_tlb_one(va);
 	else
 		smp_flush_tlb();
@@ -306,7 +306,7 @@
 #define SET_PAGE_DIR(tsk,pgdir) \
 do { \
 	unsigned long __pgdir = __pa(pgdir); \
-	(tsk)->tss.cr3 = __pgdir; \
+	(tsk)->thread.cr3 = __pgdir; \
 	if ((tsk) == current) \
 		__asm__ __volatile__("movl %0,%%cr3": :"r" (__pgdir)); \
 } while (0)
@@ -481,9 +481,9 @@
 extern void __bad_pte(pmd_t *pmd);
 extern void __bad_pte_kernel(pmd_t *pmd);
 
-#define pte_free_kernel(pte)    free_pte_fast(pte)
-#define pte_free(pte)           free_pte_fast(pte)
-#define pgd_free(pgd)           free_pgd_fast(pgd)
+#define pte_free_kernel(pte)    free_pte_slow(pte)
+#define pte_free(pte)           free_pte_slow(pte)
+#define pgd_free(pgd)           free_pgd_slow(pgd)
 #define pgd_alloc()             get_pgd_fast()
 
 extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
diff -u --recursive --new-file v2.3.10/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.3.10/linux/include/asm-i386/processor.h	Tue Jun 22 14:41:40 1999
+++ linux/include/asm-i386/processor.h	Wed Jul 21 14:52:46 1999
@@ -12,6 +12,7 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 #include <asm/types.h>
+#include <linux/threads.h>
 
 /*
  * Default implementation of macro that returns current
@@ -95,6 +96,7 @@
 #define X86_FEATURE_AMD3D	0x80000000
 
 extern struct cpuinfo_x86 boot_cpu_data;
+extern struct tss_struct init_tss[NR_CPUS];
 
 #ifdef __SMP__
 extern struct cpuinfo_x86 cpu_data[];
@@ -124,6 +126,48 @@
 		: "cc");
 }
 
+
+/*
+ * Intel CPU features in CR4
+ */
+#define X86_CR4_VME	0x0001	/* enable vm86 extensions */
+#define X86_CR4_PVI	0x0002	/* virtual interrupts flag enable */
+#define X86_CR4_TSD	0x0004	/* disable time stamp at ipl 3 */
+#define X86_CR4_DE	0x0008	/* enable debugging extensions */
+#define X86_CR4_PSE	0x0010	/* enable page size extensions */
+#define X86_CR4_PAE	0x0020	/* enable physical address extensions */
+#define X86_CR4_MCE	0x0040	/* Machine check enable */
+#define X86_CR4_PGE	0x0080	/* enable global pages */
+#define X86_CR4_PCE	0x0100	/* enable performance counters at ipl 3 */
+
+/*
+ * Save the cr4 feature set we're using (ie
+ * Pentium 4MB enable and PPro Global page
+ * enable), so that any CPU's that boot up
+ * after us can get the correct flags.
+ */
+extern unsigned long mmu_cr4_features;
+
+static inline void set_in_cr4 (unsigned long mask)
+{
+	mmu_cr4_features |= mask;
+	__asm__("movl %%cr4,%%eax\n\t"
+		"orl %0,%%eax\n\t"
+		"movl %%eax,%%cr4\n"
+		: : "irg" (mask)
+		:"ax");
+}
+
+static inline void clear_in_cr4 (unsigned long mask)
+{
+	mmu_cr4_features &= ~mask;
+	__asm__("movl %%cr4,%%eax\n\t"
+		"andl %0,%%eax\n\t"
+		"movl %%eax,%%cr4\n"
+		: : "irg" (~mask)
+		:"ax");
+}
+
 /*
  *      Cyrix CPU configuration register indexes
  */
@@ -177,6 +221,8 @@
  * Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
  */
 #define IO_BITMAP_SIZE	32
+#define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap)
+#define INVALID_IO_BITMAP_OFFSET 0x8000
 
 struct i387_hard_struct {
 	long	cwd;
@@ -213,7 +259,7 @@
 	unsigned long seg;
 } mm_segment_t;
 
-struct thread_struct {
+struct tss_struct {
 	unsigned short	back_link,__blh;
 	unsigned long	esp0;
 	unsigned short	ss0,__ss0h;
@@ -238,19 +284,44 @@
 	unsigned short	ldt, __ldth;
 	unsigned short	trace, bitmap;
 	unsigned long	io_bitmap[IO_BITMAP_SIZE+1];
-	unsigned long	tr;
+	/*
+	 * pads the TSS to be cacheline-aligned (size is 0x100)
+	 */
+	unsigned long __cacheline_filler[5];
+};
+
+struct thread_struct {
+	unsigned long	esp0;
+	unsigned long	cr3;
+	unsigned long	eip;
+	unsigned long	esp;
+	unsigned long	fs;
+	unsigned long	gs;
+/* Hardware debugging registers */
+	unsigned long	debugreg[8];  /* %%db0-7 debug registers */
+/* fault info */
 	unsigned long	cr2, trap_no, error_code;
-	mm_segment_t	segment;
-/* debug registers */
-	long debugreg[8];  /* Hardware debugging registers */
 /* floating point info */
-	union i387_union i387;
+	union i387_union	i387;
 /* virtual 86 mode info */
-	struct vm86_struct * vm86_info;
-	unsigned long screen_bitmap;
-	unsigned long v86flags, v86mask, v86mode, saved_esp0;
+	struct vm86_struct	* vm86_info;
+	unsigned long		screen_bitmap;
+	unsigned long		v86flags, v86mask, v86mode, saved_esp0;
+/* IO permissions */
+	int		ioperm;
+	unsigned long	io_bitmap[IO_BITMAP_SIZE+1];
 };
 
+#define INIT_THREAD  {						\
+	0,(long) &swapper_pg_dir - PAGE_OFFSET,			\
+	0, 0, 0, 0, 						\
+	{ [0 ... 7] = 0 },	/* debugging registers */	\
+	0, 0, 0,						\
+	{ { 0, }, },		/* 387 state */			\
+	0,0,0,0,0,0,						\
+	0,{~0,}			/* io permissions */		\
+}
+
 #define INIT_MMAP \
 { &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
 
@@ -265,13 +336,9 @@
 	0,0,0,0, /* esp,ebp,esi,edi */				\
 	0,0,0,0,0,0, /* es,cs,ss */				\
 	0,0,0,0,0,0, /* ds,fs,gs */				\
-	_LDT(0),0, /* ldt */					\
-	0, 0x8000, /* tace, bitmap */				\
-	{~0, }, /* ioperm */					\
-	_TSS(0), 0, 0, 0, (mm_segment_t) { 0 }, /* obsolete */	\
-	{ 0, },							\
-	{ { 0, }, },  /* 387 state */				\
-	NULL, 0, 0, 0, 0, 0, /* vm86_info */			\
+	__LDT(0),0, /* ldt */					\
+	0, INVALID_IO_BITMAP_OFFSET, /* tace, bitmap */		\
+	{~0, } /* ioperm */					\
 }
 
 #define start_thread(regs, new_eip, new_esp) do {		\
@@ -291,10 +358,13 @@
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
+/*
+ * create a kernel thread without removing it from tasklists
+ */
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /* Copy and release all segment info associated with a VM */
-extern void copy_segments(int nr, struct task_struct *p, struct mm_struct * mm);
+extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
 extern void release_segments(struct mm_struct * mm);
 extern void forget_segments(void);
 
@@ -302,7 +372,7 @@
  * FPU lazy state save handling..
  */
 #define save_fpu(tsk) do { \
-	asm volatile("fnsave %0\n\tfwait":"=m" (tsk->tss.i387)); \
+	asm volatile("fnsave %0\n\tfwait":"=m" (tsk->thread.i387)); \
 	tsk->flags &= ~PF_USEDFPU; \
 	stts(); \
 } while (0)
@@ -327,6 +397,7 @@
 	return ((unsigned long *)t->esp)[3];
 }
 
+#define THREAD_SIZE (2*PAGE_SIZE)
 extern struct task_struct * alloc_task_struct(void);
 extern void free_task_struct(struct task_struct *);
 
diff -u --recursive --new-file v2.3.10/linux/include/asm-i386/resource.h linux/include/asm-i386/resource.h
--- v2.3.10/linux/include/asm-i386/resource.h	Wed Nov 18 21:06:56 1998
+++ linux/include/asm-i386/resource.h	Sun Jul 11 09:11:46 1999
@@ -28,7 +28,7 @@
 	{ _STK_LIM, LONG_MAX },				\
 	{        0, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
-	{ MAX_TASKS_PER_USER, MAX_TASKS_PER_USER },	\
+	{ 0, 0 },					\
 	{ NR_OPEN, NR_OPEN },				\
 	{ LONG_MAX, LONG_MAX },				\
 	{ LONG_MAX, LONG_MAX },				\
diff -u --recursive --new-file v2.3.10/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.3.10/linux/include/asm-i386/smp.h	Tue Jun 22 14:41:41 1999
+++ linux/include/asm-i386/smp.h	Wed Jul 21 14:52:46 1999
@@ -16,7 +16,7 @@
 #ifdef __SMP__
 #ifndef ASSEMBLY
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/ptrace.h>
 
 /*
diff -u --recursive --new-file v2.3.10/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.3.10/linux/include/asm-i386/system.h	Tue Jun 22 14:41:38 1999
+++ linux/include/asm-i386/system.h	Wed Jul 21 14:52:45 1999
@@ -22,9 +22,9 @@
 		     "popl %%ebp\n\t"					\
 		     "popl %%edi\n\t"					\
 		     "popl %%esi\n\t"					\
-		     :"=m" (prev->tss.esp),"=m" (prev->tss.eip),	\
+		     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),	\
 		      "=b" (last)					\
-		     :"m" (next->tss.esp),"m" (next->tss.eip),		\
+		     :"m" (next->thread.esp),"m" (next->thread.eip),	\
 		      "a" (prev), "d" (next),				\
 		      "b" (prev));					\
 } while (0)
diff -u --recursive --new-file v2.3.10/linux/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- v2.3.10/linux/include/asm-ppc/machdep.h	Wed Jun 30 13:38:20 1999
+++ linux/include/asm-ppc/machdep.h	Mon Jul 12 15:12:55 1999
@@ -39,6 +39,8 @@
 	unsigned long	heartbeat_reset;
 	unsigned long	heartbeat_count;
 
+  	void		(*progress)(char *, unsigned short);
+
 	unsigned char 	(*nvram_read_val)(int addr);
 	void		(*nvram_write_val)(int addr, unsigned char val);
 
diff -u --recursive --new-file v2.3.10/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.3.10/linux/include/asm-ppc/system.h	Mon Jun  7 12:11:51 1999
+++ linux/include/asm-ppc/system.h	Mon Jul 19 13:12:47 1999
@@ -75,8 +75,6 @@
 extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
 extern int call_rtas(const char *, int, int, unsigned long *, ...);
-extern void chrp_progress(char *);
-void chrp_event_scan(void);
 
 struct device_node;
 extern void note_scsi_host(struct device_node *, void *);
diff -u --recursive --new-file v2.3.10/linux/include/linux/bios32.h linux/include/linux/bios32.h
--- v2.3.10/linux/include/linux/bios32.h	Tue Jun 22 14:43:01 1999
+++ linux/include/linux/bios32.h	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-/*
- *	This is only a stub file to make drivers not yet converted to the new
- *	PCI probing mechanism work. [mj]
- */
-
-#ifndef BIOS32_H
-#define BIOS32_H
-
-#include <linux/pci.h>
-
-#warning This driver uses the old PCI interface, please fix it (see Documentation/pci.txt)
-
-extern inline int __pcibios_read_irq(unsigned char bus, unsigned char dev_fn, unsigned char *to)
-{
-	struct pci_dev *pdev = pci_find_slot(bus, dev_fn);
-	if (!pdev) {
-		*to = 0;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else {
-		*to = pdev->irq;
-		return PCIBIOS_SUCCESSFUL;
-	}
-}
-
-extern inline int __pcibios_read_config_byte(unsigned char bus,
-	unsigned char dev_fn, unsigned char where, unsigned char *to)
-{
-	return pcibios_read_config_byte(bus, dev_fn, where, to);
-}
-
-#define pcibios_read_config_byte(b,d,w,p) \
-	(((w) == PCI_INTERRUPT_LINE) ? __pcibios_read_irq(b,d,p) : __pcibios_read_config_byte(b,d,w,p))
-
-#endif
diff -u --recursive --new-file v2.3.10/linux/include/linux/cyclades.h linux/include/linux/cyclades.h
--- v2.3.10/linux/include/linux/cyclades.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/cyclades.h	Fri Jul 16 14:57:41 1999
@@ -490,7 +490,26 @@
 /****************** ****************** *******************/
 #endif
 
+/* Per card data structure */
+struct cyclades_card {
+    long base_addr;
+    long ctl_addr;
+    int irq;
+    int num_chips;	/* 0 if card absent, -1 if Z/PCI, else Y */
+    int first_line;	/* minor number of first channel on card */
+    int bus_index;	/* address shift - 0 for ISA, 1 for PCI */
+    int	intr_enabled;	/* FW Interrupt flag - 0 disabled, 1 enabled */
+#ifdef __KERNEL__
+    spinlock_t card_lock;
+#else
+    uclong filler;
+#endif
 
+};
+
+struct cyclades_chip {
+  int filler;
+};
 
 
 #ifdef __KERNEL__
@@ -508,22 +527,6 @@
 #define cy_readw(port)  readw(port)
 #define cy_readl(port)  readl(port)
 
-/* Per card data structure */
-
-struct cyclades_card {
-    long base_addr;
-    long ctl_addr;
-    int irq;
-    int num_chips;	/* 0 if card absent, -1 if Z/PCI, else Y */
-    int first_line;	/* minor number of first channel on card */
-    int bus_index;	/* address shift - 0 for ISA, 1 for PCI */
-    int	intr_enabled;	/* FW Interrupt flag - 0 disabled, 1 enabled */
-};
-
-struct cyclades_chip {
-  int filler;
-};
-
 /*
  * This is our internal structure for each serial port's state.
  * 
@@ -568,16 +571,16 @@
 	int			xmit_cnt;
         int                     default_threshold;
         int                     default_timeout;
-	struct tq_struct	tqueue;
+	unsigned long		jiffies[3];
+	unsigned long		rflush_count;
 	struct termios		normal_termios;
 	struct termios		callout_termios;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-	wait_queue_head_t	shutdown_wait;
         struct cyclades_monitor mon;
-	unsigned long		jiffies[3];
-	unsigned long		rflush_count;
 	struct cyclades_idle_stats   idle_stats;
+	struct tq_struct	tqueue;
+	wait_queue_head_t       open_wait;
+	wait_queue_head_t       close_wait;
+	wait_queue_head_t       shutdown_wait;
 };
 
 /*
diff -u --recursive --new-file v2.3.10/linux/include/linux/file.h linux/include/linux/file.h
--- v2.3.10/linux/include/linux/file.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/file.h	Wed Jul 14 13:25:51 1999
@@ -5,7 +5,6 @@
 #ifndef __LINUX_FILE_H
 #define __LINUX_FILE_H
 
-extern void __fput(struct file *);	/* goner? */
 extern void _fput(struct file *);
 
 /*
diff -u --recursive --new-file v2.3.10/linux/include/linux/ioport.h linux/include/linux/ioport.h
--- v2.3.10/linux/include/linux/ioport.h	Fri Jun 18 12:43:41 1999
+++ linux/include/linux/ioport.h	Sat Jul 17 02:04:28 1999
@@ -2,56 +2,45 @@
  * ioport.h	Definitions of routines for detecting, reserving and
  *		allocating system resources.
  *
- * Authors:	Donald Becker (becker@cesdis.gsfc.nasa.gov)
- *		David Hinds (dhinds@zen.stanford.edu)
+ * Authors:	Linus Torvalds
  */
 
 #ifndef _LINUX_IOPORT_H
 #define _LINUX_IOPORT_H
 
-#define RES_IO		0
-#define RES_MEM		1
+/*
+ * Resources are tree-like, allowing
+ * nesting etc..
+ */
+struct resource {
+	const char *name;
+	unsigned long start, end;
+	unsigned long flags;
+	struct resource *parent, *sibling, *child;
+};
+
+/* PC/ISA/whatever - the normal PC address spaces: IO and memory */
+extern struct resource ioport_resource;
+extern struct resource iomem_resource;
 
 extern void reserve_setup(char *str, int *ints);
+extern int get_resource_list(struct resource *, char *buf, int size);
 
-extern struct resource_entry *iolist, *memlist;
-
-extern int get_resource_list(int class, char *buf);
-extern int check_resource(int class,
-			  unsigned long from, unsigned long extent);
-extern void request_resource(int class,
-			     unsigned long from, unsigned long extent,
-			     const char *name);
-extern void release_resource(int class,
-			     unsigned long from, unsigned long extent);
-extern unsigned long occupy_resource(int class,
-				     unsigned long base, unsigned long end,
-				     unsigned long num, unsigned long align,
-				     const char *name);
-extern void vacate_resource(int class,
-			    unsigned long from, unsigned long extent);
+extern int request_resource(struct resource *root, struct resource *new);
+extern int release_resource(struct resource *new);
 
-#define get_ioport_list(buf)	get_resource_list(RES_IO, buf)
-#define get_mem_list(buf)	get_resource_list(RES_MEM, buf)
+/* Convenience shorthand with allocation */
+#define request_region(start,n,name)	__request_region(&ioport_resource, (start), (n), (name))
+extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name);
+
+/* Compatibility cruft */
+#define check_region(start,n)	__check_region(&ioport_resource, (start), (n))
+#define release_region(start,n)	__release_region(&ioport_resource, (start), (n))
+extern int __check_region(struct resource *, unsigned long, unsigned long);
+extern void __release_region(struct resource *, unsigned long, unsigned long);
 
-#define HAVE_PORTRESERVE
-/*
- * Call check_region() before probing for your hardware.
- * Once you have found you hardware, register it with request_region().
- * If you unload the driver, use release_region to free ports.
- */
-#define check_region(f,e)		check_resource(RES_IO,f,e)
-#define request_region(f,e,n)		request_resource(RES_IO,f,e,n)
-#define release_region(f,e)		release_resource(RES_IO,f,e)
-#define occupy_region(b,e,n,a,s)	occupy_resource(RES_IO,b,e,n,a,s)
-#define vacate_region(f,e)		vacate_resource(RES_IO,f,e)
-
-#define HAVE_MEMRESERVE
-#define check_mem_region(f,e)		check_resource(RES_MEM,f,e)
-#define request_mem_region(f,e,n)	request_resource(RES_MEM,f,e,n)
-#define release_mem_region(f,e)		release_resource(RES_MEM,f,e)
-#define occupy_mem_region(b,e,n,a,s)	occupy_resource(RES_MEM,b,e,n,a,s)
-#define vacate_mem_region(f,e)		vacate_resource(RES_MEM,f,e)
+#define get_ioport_list(buf)	get_resource_list(&ioport_resource, buf, PAGE_SIZE)
+#define get_mem_list(buf)	get_resource_list(&iomem_resource, buf, PAGE_SIZE)
 
 #define HAVE_AUTOIRQ
 extern void autoirq_setup(int waittime);
diff -u --recursive --new-file v2.3.10/linux/include/linux/kernel_stat.h linux/include/linux/kernel_stat.h
--- v2.3.10/linux/include/linux/kernel_stat.h	Tue Jun 22 14:41:43 1999
+++ linux/include/linux/kernel_stat.h	Wed Jul 21 14:52:47 1999
@@ -3,7 +3,7 @@
 
 #include <asm/irq.h>
 #include <linux/smp.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 /*
  * 'kernel_stat.h' contains the definitions needed for doing
diff -u --recursive --new-file v2.3.10/linux/include/linux/list.h linux/include/linux/list.h
--- v2.3.10/linux/include/linux/list.h	Mon Dec  1 11:16:57 1997
+++ linux/include/linux/list.h	Sun Jul 11 22:50:27 1999
@@ -17,8 +17,10 @@
 	struct list_head *next, *prev;
 };
 
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
 #define LIST_HEAD(name) \
-	struct list_head name = { &name, &name }
+	struct list_head name = LIST_HEAD_INIT(name)
 
 #define INIT_LIST_HEAD(ptr) do { \
 	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
@@ -46,6 +48,14 @@
 static __inline__ void list_add(struct list_head *new, struct list_head *head)
 {
 	__list_add(new, head, head->next);
+}
+
+/*
+ * Insert a new entry before the specified head..
+ */
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
 }
 
 /*
diff -u --recursive --new-file v2.3.10/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.10/linux/include/linux/mm.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/mm.h	Wed Jul 21 14:52:49 1999
@@ -128,7 +128,7 @@
 	wait_queue_head_t wait;
 	struct page **pprev_hash;
 	struct buffer_head * buffers;
-	int owner; /* temporary debugging check */
+	void *owner; /* temporary debugging check */
 } mem_map_t;
 
 #define get_page(p) do { atomic_inc(&(p)->count); \
@@ -167,11 +167,11 @@
 	do { int _ret = test_and_set_bit(PG_locked, &(page)->flags); \
 	if (_ret) PAGE_BUG(page); \
 	if (page->owner) PAGE_BUG(page); \
-	page->owner = (int)current; } while (0)
+	page->owner = current; } while (0)
 #define TryLockPage(page)	({ int _ret = test_and_set_bit(PG_locked, &(page)->flags); \
-				if (!_ret) page->owner = (int)current; _ret; })
+				if (!_ret) page->owner = current; _ret; })
 #define UnlockPage(page)	do { \
-					if (page->owner != (int)current) { \
+					if (page->owner != current) { \
 BUG(); } page->owner = 0; \
 if (!test_and_clear_bit(PG_locked, &(page)->flags)) { \
 			PAGE_BUG(page); } wake_up(&page->wait); } while (0)
@@ -306,7 +306,6 @@
 
 extern void free_page_tables(struct mm_struct * mm);
 extern void clear_page_tables(struct mm_struct *, unsigned long, int);
-extern int new_page_tables(struct task_struct * tsk);
 
 extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size);
 extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma);
@@ -328,6 +327,7 @@
 extern void show_mem(void);
 extern void oom(struct task_struct * tsk);
 extern void si_meminfo(struct sysinfo * val);
+extern void swapin_readahead(unsigned long);
 
 /* mmap.c */
 extern void vma_init(void);
diff -u --recursive --new-file v2.3.10/linux/include/linux/parport.h linux/include/linux/parport.h
--- v2.3.10/linux/include/linux/parport.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/parport.h	Wed Jul 21 15:38:39 1999
@@ -70,6 +70,11 @@
 #define IEEE1284_MODE_EPPSWE            (1<<12) /* Software-emulated */
 #define IEEE1284_DEVICEID               (1<<2)  /* This is a flag */
 
+/* For the benefit of parport_read/write, you can use these with
+ * parport_negotiate to use address operations.  They have no effect
+ * other than to make parport_read/write use address transfers. */
+#define IEEE1284_ADDR			(1<<13)	/* This is a flag */
+
 /* The rest is for the kernel only */
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.3.10/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.10/linux/include/linux/sched.h	Thu Jul  8 15:42:21 1999
+++ linux/include/linux/sched.h	Wed Jul 21 14:52:48 1999
@@ -7,7 +7,7 @@
 
 #include <linux/binfmts.h>
 #include <linux/personality.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/times.h>
@@ -63,7 +63,7 @@
 #define CT_TO_SECS(x)	((x) / HZ)
 #define CT_TO_USECS(x)	(((x) % HZ) * 1000000/HZ)
 
-extern int nr_running, nr_tasks;
+extern int nr_running, nr_threads;
 extern int last_pid;
 
 #include <linux/fs.h>
@@ -119,6 +119,7 @@
 extern void sched_init(void);
 extern void init_idle(void);
 extern void show_state(void);
+extern void cpu_init (void);
 extern void trap_init(void);
 
 #define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
@@ -169,7 +170,8 @@
 	struct vm_area_struct * mmap_avl;	/* tree of VMAs */
 	struct vm_area_struct * mmap_cache;	/* last find_vma result */
 	pgd_t * pgd;
-	atomic_t count;
+	atomic_t mm_users;			/* How many users with user space? */
+	atomic_t mm_count;			/* How many references to "struct mm_struct" (users count as 1) */
 	int map_count;				/* number of VMAs */
 	struct semaphore mmap_sem;
 	spinlock_t page_table_lock;
@@ -192,7 +194,7 @@
 #define INIT_MM(name) {					\
 		&init_mmap, NULL, NULL,			\
 		swapper_pg_dir, 			\
-		ATOMIC_INIT(1), 1,			\
+		ATOMIC_INIT(2), ATOMIC_INIT(1), 1,	\
 		__MUTEX_INITIALIZER(name.mmap_sem),	\
 		SPIN_LOCK_UNLOCKED,			\
 		0,					\
@@ -243,7 +245,7 @@
 	int last_processor;
 	int lock_depth;		/* Lock depth. We can context switch in and out of holding a syscall kernel lock... */	
 	struct task_struct *next_task, *prev_task;
-	struct task_struct *next_run,  *prev_run;
+	struct list_head run_list;
 
 /* task state */
 	struct linux_binfmt *binfmt;
@@ -270,9 +272,6 @@
 	struct task_struct *pidhash_next;
 	struct task_struct **pidhash_pprev;
 
-	/* Pointer to task[] array linkage. */
-	struct task_struct **tarray_ptr;
-
 	wait_queue_head_t wait_chldexit;	/* for wait4() */
 	struct semaphore *vfork_sem;		/* for vfork() */
 	unsigned long policy, rt_priority;
@@ -302,14 +301,15 @@
 /* ipc stuff */
 	struct sem_undo *semundo;
 	struct sem_queue *semsleeping;
-/* tss for this task */
-	struct thread_struct tss;
+/* CPU-specific state of this task */
+	struct thread_struct thread;
 /* filesystem information */
 	struct fs_struct *fs;
 /* open file information */
 	struct files_struct *files;
+
 /* memory management info */
-	struct mm_struct *mm;
+	struct mm_struct *mm, *active_mm;
 
 /* signal handlers */
 	spinlock_t sigmask_lock;	/* Protects signal and blocked */
@@ -355,13 +355,12 @@
 /* state etc */	{ 0,0,0,KERNEL_DS,&default_exec_domain,0, \
 /* counter */	DEF_PRIORITY,DEF_PRIORITY,0, \
 /* SMP */	0,0,0,-1, \
-/* schedlink */	&init_task,&init_task, &init_task, &init_task, \
+/* schedlink */	&init_task,&init_task, LIST_HEAD_INIT(init_task.run_list), \
 /* binfmt */	NULL, \
 /* ec,brk... */	0,0,0,0,0,0, \
 /* pid etc.. */	0,0,0,0,0, \
 /* proc links*/ &init_task,&init_task,NULL,NULL,NULL, \
 /* pidhash */	NULL, NULL, \
-/* tarray */	&task[0], \
 /* chld wait */	__WAIT_QUEUE_HEAD_INITIALIZER(name.wait_chldexit), NULL, \
 /* timeout */	SCHED_OTHER,0,0,0,0,0,0,0, \
 /* timer */	{ NULL, NULL, 0, 0, it_real_fn }, \
@@ -379,10 +378,10 @@
 /* comm */	"swapper", \
 /* fs info */	0,NULL, \
 /* ipc */	NULL, NULL, \
-/* tss */	INIT_TSS, \
+/* thread */	INIT_THREAD, \
 /* fs */	&init_fs, \
 /* files */	&init_files, \
-/* mm */	&init_mm, \
+/* mm */	NULL, &init_mm, \
 /* signals */	SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
 }
 
@@ -398,33 +397,10 @@
 extern union task_union init_task_union;
 
 extern struct   mm_struct init_mm;
-extern struct task_struct *task[NR_TASKS];
-
-extern struct task_struct **tarray_freelist;
-extern spinlock_t taskslot_lock;
-
-extern __inline__ void add_free_taskslot(struct task_struct **t)
-{
-	spin_lock(&taskslot_lock);
-	*t = (struct task_struct *) tarray_freelist;
-	tarray_freelist = t;
-	spin_unlock(&taskslot_lock);
-}
-
-extern __inline__ struct task_struct **get_free_taskslot(void)
-{
-	struct task_struct **tslot;
-
-	spin_lock(&taskslot_lock);
-	if((tslot = tarray_freelist) != NULL)
-		tarray_freelist = (struct task_struct **) *tslot;
-	spin_unlock(&taskslot_lock);
-
-	return tslot;
-}
+extern struct task_struct *init_tasks[NR_CPUS];
 
-/* PID hashing. */
-#define PIDHASH_SZ (NR_TASKS >> 2)
+/* PID hashing. (shouldnt this be dynamic?) */
+#define PIDHASH_SZ (4096 >> 2)
 extern struct task_struct *pidhash[PIDHASH_SZ];
 
 #define pid_hashfn(x)	((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
@@ -616,10 +592,16 @@
  * Routines for handling mm_structs
  */
 extern struct mm_struct * mm_alloc(void);
-static inline void mmget(struct mm_struct * mm)
+
+/* mmdrop drops the mm and the page tables */
+extern inline void FASTCALL(__mmdrop(struct mm_struct *));
+static inline void mmdrop(struct mm_struct * mm)
 {
-	atomic_inc(&mm->count);
+	if (atomic_dec_and_test(&mm->mm_count))
+		__mmdrop(mm);
 }
+
+/* mmput gets rid of the mappings and all user-space */
 extern void mmput(struct mm_struct *);
 /* Remove the current tasks stale references to the old mm_struct */
 extern void mm_release(void);
@@ -740,6 +722,29 @@
 
 #define for_each_task(p) \
 	for (p = &init_task ; (p = p->next_task) != &init_task ; )
+
+
+static inline void del_from_runqueue(struct task_struct * p)
+{
+	nr_running--;
+	list_del(&p->run_list);
+	p->run_list.next = NULL;
+}
+
+extern inline int task_on_runqueue(struct task_struct *p)
+{
+	return (p->run_list.next != NULL);
+}
+
+extern inline void unhash_process(struct task_struct *p)
+{
+	if (task_on_runqueue(p)) BUG();
+	nr_threads--;
+	write_lock_irq(&tasklist_lock);
+	unhash_pid(p);
+	REMOVE_LINKS(p);
+	write_unlock_irq(&tasklist_lock);
+}
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.3.10/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.3.10/linux/include/linux/sysctl.h	Wed Jun 30 13:38:20 1999
+++ linux/include/linux/sysctl.h	Sun Jul 11 09:11:46 1999
@@ -100,7 +100,8 @@
 	KERN_SHMMAX=34,         /* int: Maximum shared memory segment */
 	KERN_MSGMAX=35,         /* int: Maximum size of a messege */
 	KERN_MSGMNB=36,         /* int: Maximum message queue size */
-	KERN_MSGPOOL=37         /* int: Maximum system message pool size */
+	KERN_MSGPOOL=37,        /* int: Maximum system message pool size */
+	KERN_MAX_THREADS=38     /* int: Maximum nr of threads in the system */
 };
 
 
diff -u --recursive --new-file v2.3.10/linux/include/linux/tasks.h linux/include/linux/tasks.h
--- v2.3.10/linux/include/linux/tasks.h	Tue Jun 22 14:41:38 1999
+++ linux/include/linux/tasks.h	Wed Dec 31 16:00:00 1969
@@ -1,25 +0,0 @@
-#ifndef _LINUX_TASKS_H
-#define _LINUX_TASKS_H
-
-/*
- * This is the maximum nr of tasks - change it if you need to
- */
- 
-#ifdef __SMP__
-#define NR_CPUS	32		/* Max processors that can be running in SMP */
-#else
-#define NR_CPUS 1
-#endif
-
-#define NR_TASKS	512	/* On x86 Max 4092, or 4090 w/APM configured. */
-
-#define MAX_TASKS_PER_USER (NR_TASKS/2)
-#define MIN_TASKS_LEFT_FOR_ROOT 4
-
-
-/*
- * This controls the maximum pid allocated to a process
- */
-#define PID_MAX 0x8000
-
-#endif
diff -u --recursive --new-file v2.3.10/linux/include/linux/threads.h linux/include/linux/threads.h
--- v2.3.10/linux/include/linux/threads.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/threads.h	Wed Jul 21 14:52:45 1999
@@ -0,0 +1,22 @@
+#ifndef _LINUX_THREADS_H
+#define _LINUX_THREADS_H
+
+/*
+ * The default limit for the nr of threads is now in
+ * /proc/sys/kernel/max-threads.
+ */
+ 
+#ifdef __SMP__
+#define NR_CPUS	32		/* Max processors that can be running in SMP */
+#else
+#define NR_CPUS 1
+#endif
+
+#define MIN_THREADS_LEFT_FOR_ROOT 4
+
+/*
+ * This controls the maximum pid allocated to a process
+ */
+#define PID_MAX 0x8000
+
+#endif
diff -u --recursive --new-file v2.3.10/linux/init/main.c linux/init/main.c
--- v2.3.10/linux/init/main.c	Thu Jul  8 15:42:21 1999
+++ linux/init/main.c	Mon Jul 12 15:04:50 1999
@@ -75,7 +75,7 @@
 extern void init_modules(void);
 extern long console_init(long, long);
 extern void sock_init(void);
-extern void uidcache_init(void);
+extern void fork_init(unsigned long);
 extern void mca_init(void);
 extern void sbus_init(void);
 extern void ppc_init(void);
@@ -1187,7 +1187,7 @@
 #ifdef CONFIG_PROC_FS
 	proc_root_init();
 #endif
-	uidcache_init();
+	fork_init(memory_end-memory_start);
 	filescache_init();
 	dcache_init();
 	vma_init();
diff -u --recursive --new-file v2.3.10/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.10/linux/ipc/shm.c	Thu Jul  8 15:42:21 1999
+++ linux/ipc/shm.c	Tue Jul 13 09:25:59 1999
@@ -15,6 +15,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/vmalloc.h>
+#include <linux/pagemap.h>
 #include <linux/proc_fs.h>
 
 #include <asm/uaccess.h>
@@ -626,6 +627,8 @@
 	pte_t pte;
 	struct shmid_kernel *shp;
 	unsigned int id, idx;
+	unsigned long page;
+	struct page * page_map;
 
 	id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
 	idx = (address - shmd->vm_start + shmd->vm_offset) >> PAGE_SHIFT;
@@ -649,26 +652,32 @@
 	}
 #endif
 
+	lock_kernel();
+ again:
 	pte = __pte(shp->shm_pages[idx]);
 	if (!pte_present(pte)) {
-		unsigned long page = get_free_page(GFP_USER);
-		if (!page) {
-			oom(current);
-			return 0;
-		}
-		pte = __pte(shp->shm_pages[idx]);
-		if (pte_present(pte)) {
-			free_page (page); /* doesn't sleep */
-			goto done;
-		}
-		if (!pte_none(pte)) {
-			rw_swap_page_nocache(READ, pte_val(pte), (char *)page);
-			pte = __pte(shp->shm_pages[idx]);
-			if (pte_present(pte))  {
-				free_page (page); /* doesn't sleep */
-				goto done;
+		if (pte_none(pte)) {
+			page = get_free_page(GFP_USER);
+			if (!page)
+				goto oom;
+			if (pte_val(pte) != shp->shm_pages[idx])
+				goto changed;
+		} else {
+			unsigned long entry = pte_val(pte);
+
+			page_map = lookup_swap_cache(entry);
+			if (!page_map) {
+				swapin_readahead(entry);
+				page_map = read_swap_cache(entry);
 			}
-			swap_free(pte_val(pte));
+			pte = __pte(shp->shm_pages[idx]);
+			page = page_address(page_map);
+			if (pte_present(pte))
+				goto present;
+			if (!page_map)
+				goto oom;
+			delete_from_swap_cache(page_map);
+			swap_free(entry);
 			shm_swp--;
 		}
 		shm_rss++;
@@ -678,9 +687,21 @@
 		--current->maj_flt;  /* was incremented in do_no_page */
 
 done:	/* pte_val(pte) == shp->shm_pages[idx] */
+	unlock_kernel();
 	current->min_flt++;
 	get_page(mem_map + MAP_NR(pte_page(pte)));
 	return pte_page(pte);
+
+changed:
+	free_page(page);
+	goto again;
+present:
+	if (page_map)
+		free_page_and_swap_cache(page);
+	goto done;
+oom:
+	unlock_kernel();
+	return -1;
 }
 
 /*
@@ -697,6 +718,7 @@
 	unsigned long id, idx;
 	int loop = 0;
 	int counter;
+	struct page * page_map;
 	
 	counter = shm_rss >> prio;
 	if (!counter || !(swap_nr = get_swap_page()))
@@ -725,7 +747,8 @@
 	page = __pte(shp->shm_pages[idx]);
 	if (!pte_present(page))
 		goto check_table;
-	if ((gfp_mask & __GFP_DMA) && !PageDMA(&mem_map[MAP_NR(pte_page(page))]))
+	page_map = &mem_map[MAP_NR(pte_page(page))];
+	if ((gfp_mask & __GFP_DMA) && !PageDMA(page_map))
 		goto check_table;
 	swap_attempts++;
 
@@ -737,8 +760,11 @@
 	if (page_count(mem_map + MAP_NR(pte_page(page))) != 1)
 		goto check_table;
 	shp->shm_pages[idx] = swap_nr;
-	rw_swap_page_nocache (WRITE, swap_nr, (char *) pte_page(page));
-	free_page(pte_page(page));
+	swap_duplicate(swap_nr);
+	add_to_swap_cache(page_map, swap_nr);
+	rw_swap_page(WRITE, page_map, 0);
+
+	__free_page(page_map);
 	swap_successes++;
 	shm_swp++;
 	shm_rss--;
diff -u --recursive --new-file v2.3.10/linux/kernel/exit.c linux/kernel/exit.c
--- v2.3.10/linux/kernel/exit.c	Thu Jul  8 15:42:21 1999
+++ linux/kernel/exit.c	Wed Jul 21 13:14:41 1999
@@ -27,29 +27,15 @@
 	if (p != current) {
 #ifdef __SMP__
 		/*
-		 * Wait to make sure the process isn't active on any
-		 * other CPU
+		 * Wait to make sure the process isn't on the
+		 * runqueue (active on some other CPU still)
 		 */
-		for (;;)  {
-			int has_cpu;
-			spin_lock_irq(&runqueue_lock);
-			has_cpu = p->has_cpu;
-			spin_unlock_irq(&runqueue_lock);
-			if (!has_cpu)
-				break;
-			do {
-				barrier();
-			} while (p->has_cpu);
-		}
+		do {
+			barrier();
+		} while (p->has_cpu);
 #endif
 		free_uid(p);
-		nr_tasks--;
-		add_free_taskslot(p->tarray_ptr);
-
-		write_lock_irq(&tasklist_lock);
-		unhash_pid(p);
-		REMOVE_LINKS(p);
-		write_unlock_irq(&tasklist_lock);
+		unhash_process(p);
 
 		release_thread(p);
 		current->cmin_flt += p->min_flt + p->cmin_flt;
@@ -243,19 +229,18 @@
 	__exit_sighand(tsk);
 }
 
+/*
+ * Turn us into a lazy TLB process if we
+ * aren't already..
+ */
 static inline void __exit_mm(struct task_struct * tsk)
 {
 	struct mm_struct * mm = tsk->mm;
 
-	/* Set us up to use the kernel mm state */
-	if (mm != &init_mm) {
-		flush_cache_mm(mm);
-		flush_tlb_mm(mm);
-		destroy_context(mm);
-		tsk->mm = &init_mm;
-		tsk->swappable = 0;
-		SET_PAGE_DIR(tsk, swapper_pg_dir);
+	if (mm) {
 		mm_release();
+		atomic_inc(&mm->mm_count);
+		tsk->mm = NULL;
 		mmput(mm);
 	}
 }
diff -u --recursive --new-file v2.3.10/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.10/linux/kernel/fork.c	Thu Jul  8 15:42:21 1999
+++ linux/kernel/fork.c	Wed Jul 21 11:22:04 1999
@@ -22,11 +22,12 @@
 #include <asm/mmu_context.h>
 #include <asm/uaccess.h>
 
-/* The idle tasks do not count.. */
-int nr_tasks=0;
+/* The idle threads do not count.. */
+int nr_threads=0;
 int nr_running=0;
 
-unsigned long int total_forks=0;	/* Handle normal Linux uptimes. */
+int max_threads;
+unsigned long total_forks = 0;	/* Handle normal Linux uptimes. */
 int last_pid=0;
 
 /* SLAB cache for mm_struct's. */
@@ -37,9 +38,6 @@
 
 struct task_struct *pidhash[PIDHASH_SZ];
 
-struct task_struct **tarray_freelist = NULL;
-spinlock_t taskslot_lock = SPIN_LOCK_UNLOCKED;
-
 /* UID task count cache, to prevent walking entire process list every
  * single fork() operation.
  */
@@ -159,7 +157,7 @@
 	return 0;
 }
 
-void __init uidcache_init(void)
+void __init fork_init(unsigned long memsize)
 {
 	int i;
 
@@ -171,15 +169,16 @@
 
 	for(i = 0; i < UIDHASH_SZ; i++)
 		uidhash[i] = 0;
-}
 
-static inline struct task_struct ** find_empty_process(void)
-{
-	struct task_struct **tslot = NULL;
+	/*
+	 * The default maximum number of threads is set to a safe
+	 * value: the thread structures can take up at most half
+	 * of memory.
+	 */
+	max_threads = memsize / THREAD_SIZE / 2;
 
-	if ((nr_tasks < NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) || !current->uid)
-		tslot = get_free_taskslot();
-	return tslot;
+	init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
+	init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
 }
 
 /* Protects next_safe and last_pid. */
@@ -233,6 +232,9 @@
 	struct vm_area_struct * mpnt, *tmp, **pprev;
 	int retval;
 
+	/* Kill me slowly. UGLY! FIXME! */
+	memcpy(&mm->start_code, &current->mm->start_code, 15*sizeof(unsigned long));
+
 	flush_cache_mm(current->mm);
 	pprev = &mm->mmap;
 	for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
@@ -290,9 +292,6 @@
 
 /*
  * Allocate and initialize an mm_struct.
- *
- * NOTE! The mm mutex will be locked until the
- * caller decides that all systems are go..
  */
 struct mm_struct * mm_alloc(void)
 {
@@ -300,23 +299,12 @@
 
 	mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
 	if (mm) {
-		*mm = *current->mm;
+		memset(mm, 0, sizeof(*mm));
 		init_new_context(mm);
-		atomic_set(&mm->count, 1);
-		mm->map_count = 0;
-		mm->def_flags = 0;
-		init_MUTEX_LOCKED(&mm->mmap_sem);
+		atomic_set(&mm->mm_users, 1);
+		atomic_set(&mm->mm_count, 1);
+		init_MUTEX(&mm->mmap_sem);
 		mm->page_table_lock = SPIN_LOCK_UNLOCKED;
-		/*
-		 * Leave mm->pgd set to the parent's pgd
-		 * so that pgd_offset() is always valid.
-		 */
-		mm->mmap = mm->mmap_avl = mm->mmap_cache = NULL;
-
-		/* It has not run yet, so cannot be present in anyone's
-		 * cache or tlb.
-		 */
-		mm->cpu_vm_mask = 0;
 	}
 	return mm;
 }
@@ -346,19 +334,30 @@
 }
 
 /*
+ * Called when the last reference to the mm
+ * is dropped: either by a lazy thread or by
+ * mmput
+ */
+inline void __mmdrop(struct mm_struct *mm)
+{
+	if (mm == &init_mm) BUG();
+	free_page_tables(mm);
+	kmem_cache_free(mm_cachep, mm);
+}
+
+/*
  * Decrement the use count and release all resources for an mm.
  */
 void mmput(struct mm_struct *mm)
 {
-	if (atomic_dec_and_test(&mm->count)) {
+	if (atomic_dec_and_test(&mm->mm_users)) {
 		release_segments(mm);
 		exit_mmap(mm);
-		free_page_tables(mm);
-		kmem_cache_free(mm_cachep, mm);
+		mmdrop(mm);
 	}
 }
 
-static inline int copy_mm(int nr, unsigned long clone_flags, struct task_struct * tsk)
+static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct mm_struct * mm;
 	int retval;
@@ -367,14 +366,21 @@
 	tsk->cmin_flt = tsk->cmaj_flt = 0;
 	tsk->nswap = tsk->cnswap = 0;
 
-	if (clone_flags & CLONE_VM) {
-		mmget(current->mm);
-		/*
-		 * Set up the LDT descriptor for the clone task.
-		 */
-		copy_segments(nr, tsk, NULL);
-		SET_PAGE_DIR(tsk, current->mm->pgd);
+	tsk->mm = NULL;
+	tsk->active_mm = NULL;
+
+	/*
+	 * Are we cloning a kernel thread?
+	 *
+	 * We need to steal a active VM for that..
+	 */
+	mm = current->mm;
+	if (!mm)
 		return 0;
+
+	if (clone_flags & CLONE_VM) {
+		atomic_inc(&mm->mm_users);
+		goto good_mm;
 	}
 
 	retval = -ENOMEM;
@@ -383,23 +389,33 @@
 		goto fail_nomem;
 
 	tsk->mm = mm;
-	copy_segments(nr, tsk, mm);
-	retval = new_page_tables(tsk);
-	if (retval)
+	tsk->active_mm = mm;
+
+	mm->pgd = pgd_alloc();
+	if (!mm->pgd)
 		goto free_mm;
+
+	/*
+	 * child gets a private LDT (if there was an LDT in the parent)
+	 */
+	copy_segments(tsk, mm);
+
+	down(&current->mm->mmap_sem);
 	retval = dup_mmap(mm);
+	up(&current->mm->mmap_sem);
 	if (retval)
 		goto free_pt;
-	up(&mm->mmap_sem);
+
+good_mm:
+	tsk->mm = mm;
+	tsk->active_mm = mm;
+	SET_PAGE_DIR(tsk, mm->pgd);
 	return 0;
 
 free_mm:
-	tsk->mm = NULL;
-	release_segments(mm);
 	kmem_cache_free(mm_cachep, mm);
 	return retval;
 free_pt:
-	tsk->mm = NULL;
 	mmput(mm);
 fail_nomem:
 	return retval;
@@ -542,7 +558,6 @@
  */
 int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
 {
-	int nr;
 	int retval = -ENOMEM;
 	struct task_struct *p;
 	DECLARE_MUTEX_LOCKED(sem);
@@ -555,7 +570,6 @@
 
 	*p = *current;
 
-	down(&current->mm->mmap_sem);
 	lock_kernel();
 
 	retval = -EAGAIN;
@@ -565,15 +579,12 @@
 		atomic_inc(&p->user->count);
 	}
 
-	{
-		struct task_struct **tslot;
-		tslot = find_empty_process();
-		if (!tslot)
-			goto bad_fork_cleanup_count;
-		p->tarray_ptr = tslot;
-		*tslot = p;
-		nr = tslot - &task[0];
-	}
+	/*
+	 * Counter atomicity is protected by
+	 * the kernel lock
+	 */
+	if (nr_threads >= max_threads)
+		goto bad_fork_cleanup_count;
 
 	if (p->exec_domain && p->exec_domain->module)
 		__MOD_INC_USE_COUNT(p->exec_domain->module);
@@ -594,8 +605,8 @@
 	 * very end).
 	 */
 	p->state = TASK_RUNNING;
-	p->next_run = p;
-	p->prev_run = p;
+	p->run_list.next = NULL;
+	p->run_list.prev = NULL;
 
 	p->p_pptr = p->p_opptr = current;
 	p->p_cptr = NULL;
@@ -638,9 +649,9 @@
 		goto bad_fork_cleanup_files;
 	if (copy_sighand(clone_flags, p))
 		goto bad_fork_cleanup_fs;
-	if (copy_mm(nr, clone_flags, p))
+	if (copy_mm(clone_flags, p))
 		goto bad_fork_cleanup_sighand;
-	retval = copy_thread(nr, clone_flags, usp, p, regs);
+	retval = copy_thread(0, clone_flags, usp, p, regs);
 	if (retval)
 		goto bad_fork_cleanup_sighand;
 	p->semundo = NULL;
@@ -666,22 +677,17 @@
 	 * Let it rip!
 	 */
 	retval = p->pid;
-	if (retval) {
-		write_lock_irq(&tasklist_lock);
-		SET_LINKS(p);
-		hash_pid(p);
-		write_unlock_irq(&tasklist_lock);
-
-		nr_tasks++;
-
-		p->next_run = NULL;
-		p->prev_run = NULL;
-		wake_up_process(p);		/* do this last */
-	}
+	write_lock_irq(&tasklist_lock);
+	SET_LINKS(p);
+	hash_pid(p);
+	write_unlock_irq(&tasklist_lock);
+
+	nr_threads++;
+	wake_up_process(p);		/* do this last */
 	++total_forks;
+
 bad_fork:
 	unlock_kernel();
-	up(&current->mm->mmap_sem);
 fork_out:
 	if ((clone_flags & CLONE_VFORK) && (retval > 0)) 
 		down(&sem);
@@ -699,7 +705,7 @@
 	if (p->binfmt && p->binfmt->module)
 		__MOD_DEC_USE_COUNT(p->binfmt->module);
 
-	add_free_taskslot(p->tarray_ptr);
+	nr_threads--;
 bad_fork_cleanup_count:
 	if (p->user)
 		free_uid(p);
diff -u --recursive --new-file v2.3.10/linux/kernel/info.c linux/kernel/info.c
--- v2.3.10/linux/kernel/info.c	Fri Nov 20 11:43:19 1998
+++ linux/kernel/info.c	Sun Jul 11 09:11:46 1999
@@ -26,7 +26,7 @@
 	val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
 	val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
 
-	val.procs = nr_tasks-1;
+	val.procs = nr_threads-1;
 	sti();
 
 	si_meminfo(&val);
diff -u --recursive --new-file v2.3.10/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.10/linux/kernel/ksyms.c	Thu Jul  8 15:42:21 1999
+++ linux/kernel/ksyms.c	Mon Jul 19 12:31:25 1999
@@ -116,7 +116,6 @@
 EXPORT_SYMBOL(get_super);
 EXPORT_SYMBOL(get_fs_type);
 EXPORT_SYMBOL(getname);
-EXPORT_SYMBOL(__fput);	/* goner? */
 EXPORT_SYMBOL(_fput);
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
@@ -193,7 +192,10 @@
 EXPORT_SYMBOL(vfs_rename);
 EXPORT_SYMBOL(__pollwait);
 EXPORT_SYMBOL(ROOT_DEV);
-
+EXPORT_SYMBOL(add_to_page_cache_unique);
+EXPORT_SYMBOL(__find_get_page);
+EXPORT_SYMBOL(__find_lock_page);
+                        
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
 #endif
@@ -308,11 +310,13 @@
 #endif
 
 /* resource handling */
-EXPORT_SYMBOL(check_resource);
 EXPORT_SYMBOL(request_resource);
 EXPORT_SYMBOL(release_resource);
-EXPORT_SYMBOL(occupy_resource);
-EXPORT_SYMBOL(vacate_resource);
+EXPORT_SYMBOL(__request_region);
+EXPORT_SYMBOL(__check_region);
+EXPORT_SYMBOL(__release_region);
+EXPORT_SYMBOL(ioport_resource);
+EXPORT_SYMBOL(iomem_resource);
 
 /* process management */
 EXPORT_SYMBOL(__wake_up);
diff -u --recursive --new-file v2.3.10/linux/kernel/panic.c linux/kernel/panic.c
--- v2.3.10/linux/kernel/panic.c	Sun Dec 27 22:45:13 1998
+++ linux/kernel/panic.c	Sun Jul 11 09:11:46 1999
@@ -40,7 +40,7 @@
 	vsprintf(buf, fmt, args);
 	va_end(args);
 	printk(KERN_EMERG "Kernel panic: %s\n",buf);
-	if (current == task[0])
+	if (current == init_tasks[0])
 		printk(KERN_EMERG "In swapper task - not syncing\n");
 	else if (in_interrupt())
 		printk(KERN_EMERG "In interrupt handler - not syncing\n");
diff -u --recursive --new-file v2.3.10/linux/kernel/ptrace.c linux/kernel/ptrace.c
--- v2.3.10/linux/kernel/ptrace.c	Thu Jul  8 15:42:21 1999
+++ linux/kernel/ptrace.c	Mon Jul 19 12:29:05 1999
@@ -39,6 +39,8 @@
 	if (!pte_present(*pgtable))
 		goto fault_in_page;
 	page = pte_page(*pgtable);
+	if (write && (!pte_write(*pgtable) || !pte_dirty(*pgtable)))
+		goto fault_in_page;
 	if (MAP_NR(page) >= max_mapnr)
 		return 0;
 	flush_cache_page(vma, addr);
diff -u --recursive --new-file v2.3.10/linux/kernel/resource.c linux/kernel/resource.c
--- v2.3.10/linux/kernel/resource.c	Fri Jun 18 12:43:41 1999
+++ linux/kernel/resource.c	Mon Jul 19 12:56:18 1999
@@ -1,232 +1,186 @@
 /*
  *	linux/kernel/resource.c
  *
- * Copyright (C) 1995, 1999	Linus Torvalds
- *				David Hinds
+ * Copyright (C) 1999	Linus Torvalds
  *
- * Kernel resource management
- *
- * We now distinguish between claiming space for devices (using the
- * 'occupy' and 'vacate' calls), and associating a resource with a
- * device driver (with the 'request', 'release', and 'check' calls).
- * A resource can be claimed even if there is no associated driver
- * (by occupying with name=NULL).  Vacating a resource makes it
- * available for other dynamically configured devices.
+ * Arbitrary resource management.
  */
 
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/malloc.h>
 
-#define RSRC_TABLE_SIZE 128
-
-struct resource_entry {
-	u_long from, num;
-	const char *name;
-	struct resource_entry *next;
-};
-
-struct resource_entry res_list[] = {
-    { 0, 0, NULL, NULL }, /* IO */
-    { 0, 0, NULL, NULL }  /* mem */
-};
-
-static struct resource_entry rsrc_table[RSRC_TABLE_SIZE];
+struct resource ioport_resource = { "PCI IO", 0x0000, 0xFFFF };
+struct resource iomem_resource = { "PCI mem", 0x00000000, 0xFFFFFFFF };
 
 /*
  * This generates reports for /proc/ioports and /proc/memory
  */
-int get_resource_list(int class, char *buf)
+static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end)
 {
-	struct resource_entry *root = &res_list[class];
-	struct resource_entry *p;
-	int len = 0;
-	char *fmt = (class == RES_IO) ?
-		"%04lx-%04lx : %s\n" : "%08lx-%08lx : %s\n";
-	
-	for (p = root->next; (p) && (len < 4000); p = p->next)
-		len += sprintf(buf+len, fmt, p->from, p->from+p->num-1,
-			       (p->name ? p->name : "occupied"));
-	if (p)
-		len += sprintf(buf+len, "4K limit reached!\n");
-	return len;
+	if (offset < 0)
+		offset = 0;
+
+	while (entry) {
+		const char *name = entry->name;
+		unsigned long from, to;
+
+		if ((int) (end-buf) < 80)
+			return buf;
+
+		from = entry->start;
+		to = entry->end;
+		if (!name)
+			name = "<BAD>";
+
+		buf += sprintf(buf, fmt + offset, from, to, name);
+		if (entry->child)
+			buf = do_resource_list(entry->child, fmt, offset-2, buf, end);
+		entry = entry->sibling;
+	}
+
+	return buf;
 }
 
-/*
- * Basics: find a matching resource entry, or find an insertion point
- */
-static struct resource_entry *
-find_match(struct resource_entry *root, u_long from, u_long num)
+int get_resource_list(struct resource *root, char *buf, int size)
 {
-	struct resource_entry *p;
-	for (p = root; p; p = p->next)
-		if ((p->from == from) && (p->num == num))
-			return p;
-	return NULL;
-}
-
-static struct resource_entry *
-find_gap(struct resource_entry *root, u_long from, u_long num)
-{
-	struct resource_entry *p;
-	if (from > from+num-1)
-		return NULL;
-	for (p = root; ; p = p->next) {
-		if ((p != root) && (p->from+p->num-1 >= from)) {
-			p = NULL;
-			break;
+	char *fmt;
+
+	fmt = "        %08lx-%08lx : %s\n";
+	if (root == &ioport_resource)
+		fmt = "        %04lx-%04lx : %s\n";
+	return do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
+}	
+
+int request_resource(struct resource *root, struct resource *new)
+{
+	unsigned long start = new->start;
+	unsigned long end = new->end;
+	struct resource *tmp, **p;
+
+	if (end < start)
+		return -EINVAL;
+	if (start < root->start)
+		return -EINVAL;
+	if (end > root->end)
+		return -EINVAL;
+	p = &root->child;
+	for (;;) {
+		tmp = *p;
+		if (!tmp || tmp->start > end) {
+			new->sibling = tmp;
+			*p = new;
+			new->parent = root;
+			return 0;
 		}
-		if ((p->next == NULL) || (p->next->from > from+num-1))
-			break;
+		p = &tmp->sibling;
+		if (tmp->end < start)
+			continue;
+		return -EBUSY;
 	}
-	return p;
 }
 
-/*
- * Call this from a driver to assert ownership of a resource
- */
-void request_resource(int class, unsigned long from,
-		      unsigned long num, const char *name)
+int release_resource(struct resource *old)
 {
-	struct resource_entry *root = &res_list[class];
-	struct resource_entry *p;
-	long flags;
-	int i;
-
-	p = find_match(root, from, num);
-	if (p) {
-		p->name = name;
-		return;
-	}
+	struct resource *tmp, **p;
 
-	save_flags(flags);
-	cli();
-	for (i = 0; i < RSRC_TABLE_SIZE; i++)
-		if (rsrc_table[i].num == 0)
-			break;
-	if (i == RSRC_TABLE_SIZE)
-		printk("warning: resource table is full\n");
-	else {
-		p = find_gap(root, from, num);
-		if (p == NULL) {
-			restore_flags(flags);
-			return;
+	p = &old->parent->child;
+	for (;;) {
+		tmp = *p;
+		if (!tmp)
+			break;
+		if (tmp == old) {
+			*p = tmp->sibling;
+			old->parent = NULL;
+			return 0;
 		}
-		rsrc_table[i].name = name;
-		rsrc_table[i].from = from;
-		rsrc_table[i].num = num;
-		rsrc_table[i].next = p->next;
-		p->next = &rsrc_table[i];
+		p = &tmp->sibling;
 	}
-	restore_flags(flags);
+	return -EINVAL;
 }
 
-/* 
- * Call these when a driver is unloaded but the device remains
- */
-void release_resource(int class, unsigned long from, unsigned long num)
+struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
 {
-	struct resource_entry *root = &res_list[class];
-	struct resource_entry *p;
-	p = find_match(root, from, num);
-	if (p) p->name = NULL;
-}
+	struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
 
-/*
- * Call these to check a region for conflicts before probing
- */
-int check_resource(int class, unsigned long from, unsigned long num)
-{
-	struct resource_entry *root = &res_list[class];
-	struct resource_entry *p;
-	p = find_match(root, from, num);
-	if (p != NULL)
-		return (p->name != NULL) ? -EBUSY : 0;
-	return (find_gap(root, from, num) == NULL) ? -EBUSY : 0;
+	if (res) {
+		memset(res, 0, sizeof(*res));
+		res->name = name;
+		res->start = start;
+		res->end = start + n - 1;
+		if (request_resource(parent, res) != 0) {
+			kfree(res);
+			res = NULL;
+		}
+	}
+	return res;
 }
 
 /*
- * Call this to claim a resource for a piece of hardware
+ * Compatibility cruft.
+ *
+ * Check-region returns non-zero if something already exists.
+ *
+ * Release-region releases an anonymous region that matches
+ * the IO port range.
  */
-unsigned long occupy_resource(int class, unsigned long base,
-			      unsigned long end, unsigned long num,
-			      unsigned long align, const char *name)
-{
-	struct resource_entry *root = &res_list[class];
-	unsigned long from = 0, till;
-	unsigned long flags;
-	int i;
-	struct resource_entry *p, *q;
+int __check_region(struct resource *parent, unsigned long start, unsigned long n)
+{
+	struct resource * res;
 
-	if ((base > end-1) || (num > end - base))
-		return 0;
+	res = __request_region(parent, start, n, "check-region");
+	if (!res)
+		return -EBUSY;
 
-	for (i = 0; i < RSRC_TABLE_SIZE; i++)
-		if (rsrc_table[i].num == 0)
-			break;
-	if (i == RSRC_TABLE_SIZE)
-		return 0;
+	release_resource(res);
+	kfree(res);
+	return 0;
+}
 
-	save_flags(flags);
-	cli();
-	/* printk("occupy: search in %08lx[%08lx] ", base, end - base); */
-	for (p = root; p != NULL; p = q) {
-		q = p->next;
-		/* Find window in list */
-		from = (p->from+p->num + align-1) & ~(align-1);
-		till = (q == NULL) ? (0 - align) : q->from;
-		/* printk(" %08lx:%08lx", from, till); */
-		/* Clip window with base and end */
-		if (from < base) from = base;
-		if (till > end) till = end;
-		/* See if result is large enougth */
-		if ((from < till) && (from + num < till))
-			break;
-	}
-	/* printk("\r\n"); */
-	restore_flags(flags);
+void __release_region(struct resource *parent, unsigned long start, unsigned long n)
+{
+	struct resource **p;
+	unsigned long end;
 
-	if (p == NULL)
-		return 0;
+	p = &parent->child;
+	end = start + n - 1;
 
-	rsrc_table[i].name = name;
-	rsrc_table[i].from = from;
-	rsrc_table[i].num = num;
-	rsrc_table[i].next = p->next;
-	p->next = &rsrc_table[i];
-	return from;
-}
+	for (;;) {
+		struct resource *res = *p;
 
-/*
- * Call this when a resource becomes available for other hardware
- */
-void vacate_resource(int class, unsigned long from, unsigned long num)
-{
-	struct resource_entry *root = &res_list[class];
-	struct resource_entry *p, *q;
-	long flags;
-
-	save_flags(flags);
-	cli();
-	for (p = root; ; p = q) {
-		q = p->next;
-		if (q == NULL)
+		if (!res)
 			break;
-		if ((q->from == from) && (q->num == num)) {
-			q->num = 0;
-			p->next = q->next;
+		if (res->start == start && res->end == end) {
+			*p = res->sibling;
+			kfree(res);
 			break;
 		}
+		p = &res->sibling;
 	}
-	restore_flags(flags);
 }
 
-/* Called from init/main.c to reserve IO ports. */
+/*
+ * Called from init/main.c to reserve IO ports.
+ */
+#define MAXRESERVE 4
 void __init reserve_setup(char *str, int *ints)
 {
 	int i;
+	static int reserved = 0;
+	static struct resource reserve[MAXRESERVE];
 
-	for (i = 1; i < ints[0]; i += 2)
-		request_region(ints[i], ints[i+1], "reserved");
+	for (i = 1; i < ints[0]; i += 2) {
+		int x = reserved;
+		if (x < MAXRESERVE) {
+			struct resource *res = reserve + x;
+			res->name = "reserved";
+			res->start = ints[i];
+			res->end = res->start + ints[i] - 1;
+			res->child = NULL;
+			if (request_resource(&ioport_resource, res) == 0)
+				reserved = x+1;
+		}
+	}
 }
diff -u --recursive --new-file v2.3.10/linux/kernel/sched.c linux/kernel/sched.c
--- v2.3.10/linux/kernel/sched.c	Thu Jul  8 15:42:21 1999
+++ linux/kernel/sched.c	Wed Jul 21 10:38:11 1999
@@ -94,7 +94,23 @@
  *	via the SMP irq return path.
  */
  
-struct task_struct * task[NR_TASKS] = {&init_task, };
+struct task_struct * init_tasks[NR_CPUS] = {&init_task, };
+
+/*
+ * The tasklist_lock protects the linked list of processes.
+ *
+ * The scheduler lock is protecting against multiple entry
+ * into the scheduling code, and doesn't need to worry
+ * about interrupts (because interrupts cannot call the
+ * scheduler).
+ *
+ * The run-queue lock locks the parts that actually access
+ * and change the run-queues, and have to be interrupt-safe.
+ */
+spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED;  /* second */
+rwlock_t tasklist_lock = RW_LOCK_UNLOCKED;	/* third */
+
+static LIST_HEAD(runqueue_head);
 
 /*
  * We align per-CPU scheduling data on cacheline boundaries,
@@ -114,7 +130,7 @@
 
 #ifdef __SMP__
 
-#define idle_task(cpu) (task[cpu_number_map[(cpu)]])
+#define idle_task(cpu) (init_tasks[cpu_number_map[(cpu)]])
 #define can_schedule(p)	(!(p)->has_cpu)
 
 #else
@@ -140,8 +156,7 @@
  *	 +1000: realtime process, select this.
  */
 
-static inline int goodness (struct task_struct * prev,
-				 struct task_struct * p, int this_cpu)
+static inline int goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm)
 {
 	int weight;
 
@@ -174,7 +189,7 @@
 #endif
 
 	/* .. and a slight advantage to the current MM */
-	if (p->mm == prev->mm)
+	if (p->mm == this_mm)
 		weight += 1;
 	weight += p->priority;
 
@@ -191,24 +206,22 @@
  * to care about SCHED_YIELD is when we calculate the previous process'
  * goodness ...
  */
-static inline int prev_goodness (struct task_struct * prev,
-					struct task_struct * p, int this_cpu)
+static inline int prev_goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm)
 {
 	if (p->policy & SCHED_YIELD) {
 		p->policy &= ~SCHED_YIELD;
 		return 0;
 	}
-	return goodness(prev, p, this_cpu);
+	return goodness(p, this_cpu, this_mm);
 }
 
 /*
  * the 'goodness value' of replacing a process on a given CPU.
  * positive value means 'replace', zero or negative means 'dont'.
  */
-static inline int preemption_goodness (struct task_struct * prev,
-				struct task_struct * p, int cpu)
+static inline int preemption_goodness(struct task_struct * prev, struct task_struct * p, int cpu)
 {
-	return goodness(prev, p, cpu) - goodness(prev, prev, cpu);
+	return goodness(p, cpu, prev->mm) - goodness(prev, cpu, prev->mm);
 }
 
 /*
@@ -366,74 +379,23 @@
  */
 static inline void add_to_runqueue(struct task_struct * p)
 {
-	struct task_struct *next = init_task.next_run;
-
-	p->prev_run = &init_task;
-	init_task.next_run = p;
-	p->next_run = next;
-	next->prev_run = p;
+	list_add(&p->run_list, &runqueue_head);
 	nr_running++;
 }
 
-static inline void del_from_runqueue(struct task_struct * p)
-{
-	struct task_struct *next = p->next_run;
-	struct task_struct *prev = p->prev_run;
-
-	nr_running--;
-	next->prev_run = prev;
-	prev->next_run = next;
-	p->next_run = NULL;
-	p->prev_run = NULL;
-}
-
 static inline void move_last_runqueue(struct task_struct * p)
 {
-	struct task_struct *next = p->next_run;
-	struct task_struct *prev = p->prev_run;
-
-	/* remove from list */
-	next->prev_run = prev;
-	prev->next_run = next;
-	/* add back to list */
-	p->next_run = &init_task;
-	prev = init_task.prev_run;
-	init_task.prev_run = p;
-	p->prev_run = prev;
-	prev->next_run = p;
+	list_del(&p->run_list);
+	list_add_tail(&p->run_list, &runqueue_head);
 }
 
 static inline void move_first_runqueue(struct task_struct * p)
 {
-	struct task_struct *next = p->next_run;
-	struct task_struct *prev = p->prev_run;
-
-	/* remove from list */
-	next->prev_run = prev;
-	prev->next_run = next;
-	/* add back to list */
-	p->prev_run = &init_task;
-	next = init_task.next_run;
-	init_task.next_run = p;
-	p->next_run = next;
-	next->prev_run = p;
+	list_del(&p->run_list);
+	list_add(&p->run_list, &runqueue_head);
 }
 
 /*
- * The tasklist_lock protects the linked list of processes.
- *
- * The scheduler lock is protecting against multiple entry
- * into the scheduling code, and doesn't need to worry
- * about interrupts (because interrupts cannot call the
- * scheduler).
- *
- * The run-queue lock locks the parts that actually access
- * and change the run-queues, and have to be interrupt-safe.
- */
-spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED;  /* second */
-rwlock_t tasklist_lock = RW_LOCK_UNLOCKED;	/* third */
-
-/*
  * Wake up a process. Put it on the run-queue if it's not
  * already there.  The "current" process is always on the
  * run-queue (except when the actual re-schedule is in
@@ -450,7 +412,7 @@
 	 */
 	spin_lock_irqsave(&runqueue_lock, flags);
 	p->state = TASK_RUNNING;
-	if (p->next_run)
+	if (task_on_runqueue(p))
 		goto out;
 	add_to_runqueue(p);
 	spin_unlock_irqrestore(&runqueue_lock, flags);
@@ -657,8 +619,17 @@
  * cleans up all remaining scheduler things, without impacting the
  * common case.
  */
-static inline void __schedule_tail (struct task_struct *prev)
+static inline void __schedule_tail(struct task_struct *prev)
 {
+	if (!current->active_mm) BUG();
+
+	if (!prev->mm) {
+		struct mm_struct *mm = prev->active_mm;
+		if (mm) {
+			prev->active_mm = NULL;
+			mmdrop(mm);
+		}
+	}
 #ifdef __SMP__
 	if ((prev->state == TASK_RUNNING) &&
 			(prev != idle_task(smp_processor_id())))
@@ -668,7 +639,7 @@
 #endif /* __SMP__ */
 }
 
-void schedule_tail (struct task_struct *prev)
+void schedule_tail(struct task_struct *prev)
 {
 	__schedule_tail(prev);
 }
@@ -687,8 +658,10 @@
 {
 	struct schedule_data * sched_data;
 	struct task_struct *prev, *next, *p;
+	struct list_head *tmp;
 	int this_cpu, c;
 
+	if (!current->active_mm) BUG();
 	if (tq_scheduler)
 		goto handle_tq_scheduler;
 tq_scheduler_back:
@@ -731,42 +704,29 @@
 	}
 	prev->need_resched = 0;
 
-repeat_schedule:
-
 	/*
 	 * this is the scheduler proper:
 	 */
 
-	p = init_task.next_run;
-	/* Default process to select.. */
+repeat_schedule:
+	/*
+	 * Default process to select..
+	 */
 	next = idle_task(this_cpu);
 	c = -1000;
 	if (prev->state == TASK_RUNNING)
 		goto still_running;
 still_running_back:
 
-	/*
-	 * This is subtle.
-	 * Note how we can enable interrupts here, even
-	 * though interrupts can add processes to the run-
-	 * queue. This is because any new processes will
-	 * be added to the front of the queue, so "p" above
-	 * is a safe starting point.
-	 * run-queue deletion and re-ordering is protected by
-	 * the scheduler lock
-	 */
-/*
- * Note! there may appear new tasks on the run-queue during this, as
- * interrupts are enabled. However, they will be put on front of the
- * list, so our list starting at "p" is essentially fixed.
- */
-	while (p != &init_task) {
+	tmp = runqueue_head.next;
+	while (tmp != &runqueue_head) {
+		p = list_entry(tmp, struct task_struct, run_list);
 		if (can_schedule(p)) {
-			int weight = goodness(prev, p, this_cpu);
+			int weight = goodness(p, this_cpu, prev->active_mm);
 			if (weight > c)
 				c = weight, next = p;
 		}
-		p = p->next_run;
+		tmp = tmp->next;
 	}
 
 	/* Do we need to re-calculate counters? */
@@ -819,12 +779,31 @@
 #endif /* __SMP__ */
 
 	kstat.context_swtch++;
+	/*
+	 * there are 3 processes which are affected by a context switch:
+	 *
+	 * prev == .... ==> (last => next)
+	 *
+	 * It's the 'much more previous' 'prev' that is on next's stack,
+	 * but prev is set to (the just run) 'last' process by switch_to().
+	 * This might sound slightly confusing but makes tons of sense.
+	 */
+	{
+		struct mm_struct *mm = next->mm;
+		if (!mm) {
+			mm = prev->active_mm;
+			set_mmu_context(prev,next);
+			if (next->active_mm) BUG();
+			next->active_mm = mm;
+			atomic_inc(&mm->mm_count);
+		}
+	}
+
 	get_mmu_context(next);
 	switch_to(prev, next, prev);
 	__schedule_tail(prev);
 
 same_process:
-  
 	reacquire_kernel_lock(current);
 	return;
 
@@ -837,11 +816,11 @@
 			p->counter = (p->counter >> 1) + p->priority;
 		read_unlock(&tasklist_lock);
 		spin_lock_irq(&runqueue_lock);
-		goto repeat_schedule;
 	}
+	goto repeat_schedule;
 
 still_running:
-	c = prev_goodness(prev, prev, this_cpu);
+	c = prev_goodness(prev, this_cpu, prev->active_mm);
 	next = prev;
 	goto still_running_back;
 
@@ -1760,7 +1739,7 @@
 	retval = 0;
 	p->policy = policy;
 	p->rt_priority = lp.sched_priority;
-	if (p->next_run)
+	if (task_on_runqueue(p))
 		move_first_runqueue(p);
 
 	current->need_resched = 1;
@@ -1934,13 +1913,13 @@
 	return 0;
 }
 
-static void show_task(int nr,struct task_struct * p)
+static void show_task(struct task_struct * p)
 {
 	unsigned long free = 0;
 	int state;
 	static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
 
-	printk("%-8s %3d ", p->comm, (p == current) ? -nr : nr);
+	printk("%-8s  ", p->comm);
 	state = p->state ? ffz(~p->state) + 1 : 0;
 	if (((unsigned) state) < sizeof(stat_nam)/sizeof(char *))
 		printk(stat_nam[state]);
@@ -1950,12 +1929,12 @@
 	if (p == current)
 		printk(" current  ");
 	else
-		printk(" %08lX ", thread_saved_pc(&p->tss));
+		printk(" %08lX ", thread_saved_pc(&p->thread));
 #else
 	if (p == current)
 		printk("   current task   ");
 	else
-		printk(" %016lx ", thread_saved_pc(&p->tss));
+		printk(" %016lx ", thread_saved_pc(&p->thread));
 #endif
 	{
 		unsigned long * n = (unsigned long *) (p+1);
@@ -1968,6 +1947,10 @@
 		printk("%5d ", p->p_cptr->pid);
 	else
 		printk("      ");
+	if (!p->mm)
+		printk(" (L-TLB) ");
+	else
+		printk(" (NOTLB) ");
 	if (p->p_ysptr)
 		printk("%7d", p->p_ysptr->pid);
 	else
@@ -2020,7 +2003,7 @@
 #endif
 	read_lock(&tasklist_lock);
 	for_each_task(p)
-		show_task((p->tarray_ptr - &task[0]),p);
+		show_task(p);
 	read_unlock(&tasklist_lock);
 }
 
@@ -2030,6 +2013,11 @@
 	struct schedule_data * sched_data;
 	sched_data = &aligned_data[smp_processor_id()].schedule_data;
 
+	if (current != &init_task && task_on_runqueue(current)) {
+		printk("UGH! (%d:%d) was on the runqueue, removing.\n",
+			smp_processor_id(), current->pid);
+		del_from_runqueue(current);
+	}
 	t = get_cycles();
 	sched_data->curr = current;
 	sched_data->last_schedule = t;
@@ -2042,18 +2030,20 @@
 	 * process right in SMP mode.
 	 */
 	int cpu=hard_smp_processor_id();
-	int nr = NR_TASKS;
+	int nr;
 
 	init_task.processor=cpu;
 
-	/* Init task array free list and pidhash table. */
-	while(--nr > 0)
-		add_free_taskslot(&task[nr]);
-
 	for(nr = 0; nr < PIDHASH_SZ; nr++)
 		pidhash[nr] = NULL;
 
 	init_bh(TIMER_BH, timer_bh);
 	init_bh(TQUEUE_BH, tqueue_bh);
 	init_bh(IMMEDIATE_BH, immediate_bh);
+
+	/*
+	 * The boot idle thread does lazy MMU switching as well:
+	 */
+	atomic_inc(&init_mm.mm_count);
 }
+
diff -u --recursive --new-file v2.3.10/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.3.10/linux/kernel/sysctl.c	Thu Jul  8 15:42:21 1999
+++ linux/kernel/sysctl.c	Sun Jul 11 09:11:46 1999
@@ -34,6 +34,7 @@
 extern int console_loglevel, C_A_D;
 extern int bdf_prm[], bdflush_min[], bdflush_max[];
 extern int sysctl_overcommit_memory;
+extern int max_threads;
 extern int nr_queued_signals, max_queued_signals;
 
 #ifdef CONFIG_KMOD
@@ -207,6 +208,8 @@
 	{KERN_SHMMAX, "shmmax", &shmmax, sizeof (int),
 	 0644, NULL, &proc_dointvec},
 #endif
+	{KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int),
+	 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -u --recursive --new-file v2.3.10/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.10/linux/mm/filemap.c	Thu Jul  8 15:42:21 1999
+++ linux/mm/filemap.c	Mon Jul 12 07:49:36 1999
@@ -463,7 +463,7 @@
 
 	flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error));
 	page->flags = flags |  ((1 << PG_locked) | (1 << PG_referenced));
-	page->owner = (int)current;	/* REMOVEME */
+	page->owner = current;	/* REMOVEME */
 	get_page(page);
 	page->offset = offset;
 	add_page_to_inode_queue(inode, page);
@@ -1855,7 +1855,7 @@
 		if (!PageLocked(page)) {
 			PAGE_BUG(page);
 		} else {
-			if (page->owner != (int)current) {
+			if (page->owner != current) {
 				PAGE_BUG(page);
 			}
 		}
diff -u --recursive --new-file v2.3.10/linux/mm/memory.c linux/mm/memory.c
--- v2.3.10/linux/mm/memory.c	Thu Jul  8 15:42:21 1999
+++ linux/mm/memory.c	Tue Jul 20 22:58:05 1999
@@ -164,17 +164,6 @@
 	return;
 }
 
-int new_page_tables(struct task_struct * tsk)
-{
-	pgd_t * new_pg;
-
-	if (!(new_pg = pgd_alloc()))
-		return -ENOMEM;
-	SET_PAGE_DIR(tsk, new_pg);
-	tsk->mm->pgd = new_pg;
-	return 0;
-}
-
 #define PTE_TABLE_MASK	((PTRS_PER_PTE-1) * sizeof(pte_t))
 #define PMD_TABLE_MASK	((PTRS_PER_PMD-1) * sizeof(pmd_t))
 
@@ -781,7 +770,7 @@
  * because it doesn't cost us any seek time.  We also make sure to queue
  * the 'original' request together with the readahead ones...  
  */
-static void swapin_readahead(unsigned long entry)
+void swapin_readahead(unsigned long entry)
 {
 	int i;
 	struct page *new_page;
@@ -898,6 +887,8 @@
 	page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access);
 	if (!page)
 		return 0;	/* SIGBUS - but we _really_ should know whether it is OOM or SIGBUS */
+	if (page == -1)
+		return -1;	/* OOM */
 
 	++tsk->maj_flt;
 	++vma->vm_mm->rss;
diff -u --recursive --new-file v2.3.10/linux/mm/mremap.c linux/mm/mremap.c
--- v2.3.10/linux/mm/mremap.c	Thu Jul  8 15:42:21 1999
+++ linux/mm/mremap.c	Mon Jul 12 07:51:42 1999
@@ -118,7 +118,7 @@
 	flush_cache_range(mm, new_addr, new_addr + len);
 	while ((offset += PAGE_SIZE) < len)
 		move_one_page(mm, new_addr + offset, old_addr + offset);
-	zap_page_range(mm, new_addr, new_addr + len);
+	zap_page_range(mm, new_addr, len);
 	flush_tlb_range(mm, new_addr, new_addr + len);
 	return -1;
 }
diff -u --recursive --new-file v2.3.10/linux/mm/slab.c linux/mm/slab.c
--- v2.3.10/linux/mm/slab.c	Fri May 28 10:13:37 1999
+++ linux/mm/slab.c	Tue Jul 20 14:29:38 1999
@@ -1577,7 +1577,7 @@
 
 #if 1
 /* FORCE A KERNEL DUMP WHEN THIS HAPPENS. SPEAK IN ALL CAPS. GET THE CALL CHAIN. */
-*(int *) 0 = 0;
+	BUG();
 #endif
 
 	return;
diff -u --recursive --new-file v2.3.10/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.10/linux/mm/swapfile.c	Wed Jun 30 13:38:20 1999
+++ linux/mm/swapfile.c	Mon Jul 19 23:08:41 1999
@@ -266,7 +266,7 @@
 	/*
 	 * Go through process' page directory.
 	 */
-	if (!mm || mm == &init_mm)
+	if (!mm)
 		return;
 	for (vma = mm->mmap; vma; vma = vma->vm_next) {
 		pgd_t * pgd = pgd_offset(mm, vma->vm_start);
@@ -661,7 +661,9 @@
 			else
 				p->swap_map[page] = SWAP_MAP_BAD;
 		}
-		nr_good_pages = swap_header->info.last_page - i;
+		nr_good_pages = swap_header->info.last_page -
+				swap_header->info.nr_badpages -
+				1 /* header page */;
 		lock_map_size = (p->max + 7) / 8;
 		if (error) 
 			goto bad_swap;
diff -u --recursive --new-file v2.3.10/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.3.10/linux/mm/vmscan.c	Thu Jul  8 15:42:21 1999
+++ linux/mm/vmscan.c	Tue Jul 20 13:27:53 1999
@@ -338,11 +338,11 @@
 	 * Think of swap_cnt as a "shadow rss" - it tells us which process
 	 * we want to page out (always try largest first).
 	 */
-	counter = nr_tasks / (priority+1);
+	counter = nr_threads / (priority+1);
 	if (counter < 1)
 		counter = 1;
-	if (counter > nr_tasks)
-		counter = nr_tasks;
+	if (counter > nr_threads)
+		counter = nr_threads;
 
 	for (; counter >= 0; counter--) {
 		assign = 0;
@@ -352,7 +352,7 @@
 		read_lock(&tasklist_lock);
 		p = init_task.next_task;
 		for (; p != &init_task; p = p->next_task) {
-			if (!p->swappable)
+			if (!p->swappable || !p->mm)
 				continue;
 	 		if (p->mm->rss <= 0)
 				continue;
