diff -u --recursive --new-file v2.3.8/linux/CREDITS linux/CREDITS
--- v2.3.8/linux/CREDITS	Wed Jun 16 19:26:27 1999
+++ linux/CREDITS	Tue Jun 29 09:12:32 1999
@@ -337,6 +337,10 @@
 S: 75252 Paris Cedex 05
 S: France
 
+N: Ulf Carlsson
+D: SGI Indy audio (HAL2) drivers
+E: ulfc@bun.falkenberg.se
+
 N: Ed Carp
 E: ecarp@netcom.com
 D: uucp, elm, pine, pico port
@@ -466,6 +470,14 @@
 S: Warrendale, Pennsylvania 15086
 S: USA
 
+N: Alex deVries
+E: puffin@redhat.com
+D: Various SGI parts, bits of HAL2 and Newport
+S: 18 Bernier Terrace
+S: Kanata, Ontario
+S: K2L 2V@
+S: CANADA
+
 N: Eddie C. Dost
 E: ecd@skynet.be
 D: Linux/Sparc kernel hacker
@@ -971,18 +983,20 @@
 E: nkbj@image.dk
 W: http://www.image.dk/~nkbj
 D: 4.4BSD and NeXTstep filesystem support in the old ufs.
-D: Openstep filesystem support in the new ufs.
+D: Openstep filesystem and NeXTstep CDROM support in the new ufs.
 D: Danish HOWTO, Linux+FreeBSD mini-HOWTO.
 S: Dr. Holsts Vej 34, lejl. 164
 S: DK-8230 Åbyhøj
 S: Denmark
 
-N: Andrzej Krzysztofowicz
-E: ankry@green.mif.pg.gda.pl
+N: Andrzej M. Krzysztofowicz
+E: ankry@mif.pg.gda.pl
+D: XT disk driver
 D: Aladdin 1533/1543(C) chipset IDE
 D: PIIX chipset IDE
-S: Faculty of Applied Phys. & Math.
-S: Technical University of Gdansk
+S: ul. Matemblewska 1B/10
+S: 80-283 Gdansk
+S: Poland
 
 N: Michael K. Johnson
 E: johnsonm@redhat.com
diff -u --recursive --new-file v2.3.8/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.8/linux/Documentation/Configure.help	Thu Jun 17 01:11:35 1999
+++ linux/Documentation/Configure.help	Fri Jun 25 17:36:12 1999
@@ -1527,8 +1527,8 @@
   If you want to use your SGI's built-in serial ports under Linux,
   answer Y.
 
-SGI graphics support
-CONFIG_SGI_GRAPHICS
+SGI Newport Graphics support
+CONFIG_SGI_NEWPORT_GFX
   If you have an SGI machine and you want to compile the graphics
   drivers, say Y here. This will include the code for the
   /dev/graphics and /dev/gfx drivers into the kernel for supporting
@@ -1704,44 +1704,6 @@
   called binfmt_aout.o. Saying M or N here is dangerous though,
   because some crucial programs on your system might still be in A.OUT
   format.
-
-Kernel support for JAVA binaries (obsolete)
-CONFIG_BINFMT_JAVA
-  JAVA(tm) is an object oriented programming language developed by
-  SUN; JAVA programs are compiled into "JAVA bytecode" binaries which
-  can then be interpreted by run time systems on many different
-  architectures and operating systems. These JAVA binaries are
-  becoming a universal executable format.
-
-  If you want to execute JAVA binaries, read the Java on Linux HOWTO,
-  available via FTP (user: anonymous) at
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You will then need to
-  install the run time system contained in the Java Developers Kit
-  (JDK) as described in the HOWTO. This is completely independent of
-  the Linux kernel and you do NOT need to say Y here for this to work.
-
-  Saying Y here allows you to execute a JAVA bytecode binary just like
-  any other Linux program: by simply typing in its name. (You also
-  need to have the JDK installed for this to work). As more and more
-  Java programs become available, the use for this will gradually
-  increase. You can even execute HTML files containing JAVA applets
-  (little embedded JAVA binaries) if those files start with the string
-  "<!--applet-->". If you want to use this, say Y here and read
-  Documentation/java.txt.
-
-  If you disable this option it will reduce your kernel by about 4 KB.
-  This is not much and by itself does not warrant removing support.
-  However its removal is a good idea if you do not have the JDK
-  installed. You may answer M for module support and later load the
-  module when you install the JDK or find an interesting Java program
-  that you can't live without. The module will be called
-  binfmt_java.o.
-
-  The complete functionality of this Java support is also provided by
-  the more general option "Kernel support for MISC binaries",
-  below. This option is therefore considered obsolete and you should
-  say N here and Y to "Kernel support for MISC binaries" if you're 
-  interested in transparently executing Java programs.
 
 Kernel support for Linux/Intel ELF binaries
 CONFIG_BINFMT_EM86
diff -u --recursive --new-file v2.3.8/linux/Documentation/filesystems/ufs.txt linux/Documentation/filesystems/ufs.txt
--- v2.3.8/linux/Documentation/filesystems/ufs.txt	Fri Apr 16 08:20:23 1999
+++ linux/Documentation/filesystems/ufs.txt	Tue Jun 29 09:12:32 1999
@@ -30,6 +30,10 @@
 		used in NextStep
 		supported as read-only
 
+	nextstep-cd
+		used for NextStep CDROMs (block_size == 2048)
+		supported as read-only
+
 	openstep
 		used in OpenStep
 		supported as read-only
diff -u --recursive --new-file v2.3.8/linux/Documentation/powerpc/sound.txt linux/Documentation/powerpc/sound.txt
--- v2.3.8/linux/Documentation/powerpc/sound.txt	Sat Oct 10 09:53:24 1998
+++ linux/Documentation/powerpc/sound.txt	Mon Jun 28 13:40:39 1999
@@ -4,7 +4,7 @@
 Please mail me (Cort Dougan, cort@cs.nmt.edu) if you have questions,
 comments or corrections.
 
-Last Change: 3.24.98
+Last Change: 6.16.99
 
 This just covers sound on the PReP and CHRP systems for now and later
 will contain information on the PowerMac's.
@@ -51,7 +51,7 @@
 
   Midi is not supported since the cs4232 driver doesn't support midi yet.
 
-2. IBM PowerPersonal PReP machines and IBM LongTrail CHRP
+2. IBM PowerPersonal PReP machines
 
   I've only tested sound on the Power Personal Series of IBM workstations
   so if you try it on others please let me know the result.  I'm especially
@@ -74,3 +74,8 @@
   This setup does _NOT_ allow for recording yet.
 
   Midi is not supported since the cs4232 driver doesn't support midi yet.
+
+2. IBM CHRP
+
+  I have only tested this on the 43P-150.  Build the kernel with the cs4232
+  set as a module and load the module with irq=9 dma=1 dma2=2 io=0x550
diff -u --recursive --new-file v2.3.8/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.8/linux/MAINTAINERS	Thu Jun  3 08:26:42 1999
+++ linux/MAINTAINERS	Sat Jun 26 13:16:54 1999
@@ -170,6 +170,12 @@
 W:	http://www.dandelion.com/Linux/
 S:	Maintained
 
+CIRRUS LOGIC GENERIC FBDEV DRIVER
+P:	Jeff Garzik
+M:	jgarzik@pobox.com
+L:	linux-fbdev@vuser.vu.union.edu
+S:	Maintained
+
 CONFIGURE, MENUCONFIG, XCONFIG
 P:	Michael Elizabeth Chastain
 M:	mec@shout.net
@@ -234,9 +240,9 @@
 S:	Maintained
 
 DIGI INTL. EPCA DRIVER
-P:      Daniel Taylor
+P:	 Chad Schwartz
 M:      support@dgii.com
-M:      danielt@dgii.com
+M:      chads@dgii.com
 L:      digilnux@dgii.com
 S:      Maintained
 
diff -u --recursive --new-file v2.3.8/linux/Makefile linux/Makefile
--- v2.3.8/linux/Makefile	Tue Jun 22 10:45:40 1999
+++ linux/Makefile	Tue Jun 29 09:12:32 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 8
+SUBLEVEL = 9
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -162,6 +162,10 @@
 DRIVERS := $(DRIVERS) drivers/pnp/pnp.a
 endif
 
+ifdef CONFIG_SGI
+DRIVERS := $(DRIVERS) drivers/sgi/sgi.a
+endif
+
 ifdef CONFIG_VT
 DRIVERS := $(DRIVERS) drivers/video/video.a
 endif
@@ -174,6 +178,10 @@
 DRIVERS := $(DRIVERS) drivers/net/hamradio/hamradio.a
 endif
 
+ifeq ($(CONFIG_TC),y)
+DRIVERS := $(DRIVERS) drivers/tc/tc.a
+endif
+
 ifeq ($(CONFIG_USB),y)
 DRIVERS := $(DRIVERS) drivers/usb/usb.a
 endif
@@ -394,8 +402,6 @@
 dep-files: scripts/mkdep archdep include/linux/version.h
 	scripts/mkdep init/*.c > .depend
 	scripts/mkdep `find $(FINDHPATH) -follow -name \*.h ! -name modversions.h -print` > .hdepend
-#	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i fastdep ;done
-# let this be made through the fastdep rule in Rules.make
 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
 
 MODVERFILE :=
diff -u --recursive --new-file v2.3.8/linux/arch/alpha/boot/bootp.c linux/arch/alpha/boot/bootp.c
--- v2.3.8/linux/arch/alpha/boot/bootp.c	Mon Oct 12 11:40:12 1998
+++ linux/arch/alpha/boot/bootp.c	Fri Jun 25 17:36:13 1999
@@ -200,11 +200,11 @@
         load(START_ADDR+(4*KERNEL_SIZE), KERNEL_ORIGIN, KERNEL_SIZE);
         load(START_ADDR, START_ADDR+(4*KERNEL_SIZE), KERNEL_SIZE);
 
-	memset((char*)ZERO_PAGE, 0, PAGE_SIZE);
-	strcpy((char*)ZERO_PAGE, envval);
+	memset((char*)ZERO_PAGE(0), 0, PAGE_SIZE);
+	strcpy((char*)ZERO_PAGE(0), envval);
 #ifdef INITRD_SIZE
-	((long *)(ZERO_PAGE+256))[0] = initrd_start;
-	((long *)(ZERO_PAGE+256))[1] = INITRD_SIZE;
+	((long *)(ZERO_PAGE(0)+256))[0] = initrd_start;
+	((long *)(ZERO_PAGE(0)+256))[1] = INITRD_SIZE;
 #endif
 
 	runkernel();
diff -u --recursive --new-file v2.3.8/linux/arch/alpha/boot/main.c linux/arch/alpha/boot/main.c
--- v2.3.8/linux/arch/alpha/boot/main.c	Thu Feb 25 10:46:51 1999
+++ linux/arch/alpha/boot/main.c	Fri Jun 25 17:36:13 1999
@@ -182,7 +182,7 @@
 		nbytes = 0;
 	}
 	envval[nbytes] = '\0';
-	strcpy((char*)ZERO_PAGE, envval);
+	strcpy((char*)ZERO_PAGE(0), envval);
 
 	srm_printk(" Ok\nNow booting the kernel\n");
 	runkernel();
diff -u --recursive --new-file v2.3.8/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.3.8/linux/arch/alpha/config.in	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/config.in	Fri Jun 25 01:05:12 1999
@@ -187,9 +187,6 @@
 tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
-fi
 tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
diff -u --recursive --new-file v2.3.8/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.3.8/linux/arch/alpha/kernel/osf_sys.c	Mon May 10 09:55:21 1999
+++ linux/arch/alpha/kernel/osf_sys.c	Thu Jun 24 23:56:23 1999
@@ -255,6 +255,7 @@
 	struct file *file = NULL;
 	unsigned long ret = -EBADF;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 #if 0
 	if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
@@ -272,6 +273,7 @@
 		fput(file);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return ret;
 }
 
diff -u --recursive --new-file v2.3.8/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c
--- v2.3.8/linux/arch/alpha/kernel/setup.c	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/kernel/setup.c	Fri Jun 25 17:36:13 1999
@@ -66,7 +66,7 @@
  * initialized, we need to copy things out into a more permanent
  * place.
  */
-#define PARAM			ZERO_PAGE
+#define PARAM			ZERO_PAGE(0)
 #define COMMAND_LINE		((char*)(PARAM + 0x0000))
 #define COMMAND_LINE_SIZE	256
 #define INITRD_START		(*(unsigned long *) (PARAM+0x100))
diff -u --recursive --new-file v2.3.8/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c
--- v2.3.8/linux/arch/alpha/mm/init.c	Tue Jun 22 10:46:52 1999
+++ linux/arch/alpha/mm/init.c	Tue Jun 29 09:22:08 1999
@@ -166,7 +166,6 @@
 	printk("%ld pages shared\n",shared);
 	printk("%ld pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
-	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
@@ -219,7 +218,7 @@
 
 	/* Initialize the kernel's page tables.  Linux puts the vptb in
 	   the last slot of the L1 page table.  */
-	memset((void *) ZERO_PAGE, 0, PAGE_SIZE);
+	memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE);
 	memset(swapper_pg_dir, 0, PAGE_SIZE);
 	newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
 	pgd_val(swapper_pg_dir[1023]) =
@@ -359,7 +358,7 @@
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
-	val->bufferram = buffermem;
+	val->bufferram = atomic_read(&buffermem);
 	while (i-- > 0)  {
 		if (PageReserved(mem_map+i))
 			continue;
diff -u --recursive --new-file v2.3.8/linux/arch/arm/defconfig linux/arch/arm/defconfig
--- v2.3.8/linux/arch/arm/defconfig	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/defconfig	Sat Jun 26 08:34:19 1999
@@ -85,7 +85,7 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_BLK_DEV_OFFBOARD=y
-CONFIG_IDEDMA_AUTO=y
+CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_NS87415 is not set
diff -u --recursive --new-file v2.3.8/linux/arch/arm/kernel/dec21285.c linux/arch/arm/kernel/dec21285.c
--- v2.3.8/linux/arch/arm/kernel/dec21285.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/dec21285.c	Wed Jun 30 11:24:54 1999
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1998 Russell King, Phil Blundell
  */
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.8/linux/arch/arm/kernel/entry-common.S linux/arch/arm/kernel/entry-common.S
--- v2.3.8/linux/arch/arm/kernel/entry-common.S	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/entry-common.S	Wed Jun 30 11:24:54 1999
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 /*============================================================================
  * All exits to user mode from the kernel go through this code.
  */
diff -u --recursive --new-file v2.3.8/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c
--- v2.3.8/linux/arch/arm/kernel/sys_arm.c	Thu Jun 17 01:11:35 1999
+++ linux/arch/arm/kernel/sys_arm.c	Thu Jun 24 23:56:23 1999
@@ -72,6 +72,7 @@
 	struct file * file = NULL;
 	struct mmap_arg_struct a;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (copy_from_user(&a, arg, sizeof(a)))
 		goto out;
@@ -87,6 +88,7 @@
 		fput(file);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return error;
 }
 
diff -u --recursive --new-file v2.3.8/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.3.8/linux/arch/arm/mm/init.c	Sat May  8 11:06:56 1999
+++ linux/arch/arm/mm/init.c	Tue Jun 29 09:22:08 1999
@@ -115,7 +115,6 @@
 	printk("%d free pages\n",free);
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
-	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
@@ -266,7 +265,7 @@
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
-	val->bufferram = buffermem;
+	val->bufferram = atomic_read(&buffermem);
 	while (i-- > 0)  {
 		if (PageReserved(mem_map+i))
 			continue;
diff -u --recursive --new-file v2.3.8/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.8/linux/arch/i386/config.in	Mon Jun  7 17:02:23 1999
+++ linux/arch/i386/config.in	Fri Jun 25 01:05:12 1999
@@ -91,9 +91,6 @@
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
-fi
 
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
diff -u --recursive --new-file v2.3.8/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.8/linux/arch/i386/defconfig	Thu Jun 17 01:27:19 1999
+++ linux/arch/i386/defconfig	Fri Jun 25 10:08:27 1999
@@ -314,17 +314,7 @@
 #
 # USB drivers - not for the faint of heart
 #
-CONFIG_USB=y
-CONFIG_USB_UHCI=y
-# CONFIG_USB_OHCI is not set
-# CONFIG_USB_OHCI_HCD is not set
-CONFIG_USB_HUB=y
-CONFIG_USB_MOUSE=y
-CONFIG_USB_KBD=y
-# CONFIG_USB_AUDIO is not set
-# CONFIG_USB_ACM is not set
-# CONFIG_USB_PRINTER is not set
-# CONFIG_USB_SCSI is not set
+# CONFIG_USB is not set
 
 #
 # Filesystems
diff -u --recursive --new-file v2.3.8/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.3.8/linux/arch/i386/kernel/i386_ksyms.c	Mon May 10 10:32:45 1999
+++ linux/arch/i386/kernel/i386_ksyms.c	Tue Jun 29 09:59:26 1999
@@ -48,6 +48,7 @@
 EXPORT_SYMBOL_NOVERS(__up_wakeup);
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
+EXPORT_SYMBOL(csum_partial_copy_generic);
 /* Delay loops */
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__delay);
diff -u --recursive --new-file v2.3.8/linux/arch/i386/kernel/mca.c linux/arch/i386/kernel/mca.c
--- v2.3.8/linux/arch/i386/kernel/mca.c	Sat Jun 19 11:45:28 1999
+++ linux/arch/i386/kernel/mca.c	Sun Jun 27 10:10:41 1999
@@ -142,9 +142,10 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.3.8/linux/arch/i386/kernel/mtrr.c	Fri May 14 08:59:54 1999
+++ linux/arch/i386/kernel/mtrr.c	Sun Jun 27 10:10:41 1999
@@ -1459,11 +1459,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static struct proc_dir_entry proc_root_mtrr = {
diff -u --recursive --new-file v2.3.8/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.3.8/linux/arch/i386/mm/init.c	Wed Jun 16 19:26:27 1999
+++ linux/arch/i386/mm/init.c	Tue Jun 29 09:22:08 1999
@@ -169,7 +169,6 @@
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
-	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
@@ -489,7 +488,7 @@
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
-	val->bufferram = buffermem;
+	val->bufferram = atomic_read(&buffermem);
 	while (i-- > 0)  {
 		if (PageReserved(mem_map+i))
 			continue;
diff -u --recursive --new-file v2.3.8/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.3.8/linux/arch/m68k/mm/init.c	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/mm/init.c	Tue Jun 29 09:22:08 1999
@@ -108,7 +108,6 @@
     printk("%d pages shared\n",shared);
     printk("%d pages swap cached\n",cached);
     printk("%ld pages in page table cache\n",pgtable_cache_size);
-    show_buffers();
 #ifdef CONFIG_NET
     show_net_buffers();
 #endif
@@ -479,7 +478,7 @@
     val->totalram = 0;
     val->sharedram = 0;
     val->freeram = nr_free_pages << PAGE_SHIFT;
-    val->bufferram = buffermem;
+    val->bufferram = atomic_read(&buffermem);
     while (i-- > 0) {
 	if (PageReserved(mem_map+i))
 	    continue;
diff -u --recursive --new-file v2.3.8/linux/arch/mips/Makefile linux/arch/mips/Makefile
--- v2.3.8/linux/arch/mips/Makefile	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/Makefile	Fri Jun 25 17:40:12 1999
@@ -36,7 +36,7 @@
 CROSS_COMPILE  = $(tool-prefix)
 endif
 
-LINKFLAGS	= -static #-N
+LINKFLAGS	= -static -N
 MODFLAGS	+= -mlong-calls
 
 #
@@ -97,22 +97,37 @@
 SUBDIRS       += arch/mips/algor
 #LOADADDR      += 0x80000000
 endif
+
+#
+# DECstation family
+#
+ifdef CONFIG_DECSTATION
+CORE_FILES    += arch/mips/dec/dec.o
+SUBDIRS       += arch/mips/dec arch/mips/dec/prom
+LIBS          += arch/mips/dec/prom/rexlib.a
+LOADADDR      += 0x80040000
+endif
+
 #
 # Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
 #
 ifdef CONFIG_MIPS_JAZZ
 CORE_FILES    += arch/mips/jazz/jazz.o
-SUBDIRS       += arch/mips/jazz
-LOADADDR      += 0x80000000
+SUBDIRS       += arch/mips/jazz arch/mips/arc
+LIBS          += arch/mips/arc/arclib.a
+LOADADDR      += 0x80080000
 endif
+
 ifdef CONFIG_SNI_RM200_PCI
 CORE_FILES    += arch/mips/sni/sni.o
-SUBDIRS       += arch/mips/sni
-LOADADDR      += 0x80000000
+SUBDIRS       += arch/mips/sni arch/mips/arc
+LIBS          += arch/mips/arc/arclib.a
+LOADADDR      += 0x80080000
 endif
+
 ifdef CONFIG_SGI
-LIBS          += arch/mips/sgi/kernel/sgikern.a arch/mips/sgi/prom/promlib.a
-SUBDIRS       += arch/mips/sgi/kernel arch/mips/sgi/prom
+LIBS          += arch/mips/sgi/kernel/sgikern.a arch/mips/arc/arclib.a
+SUBDIRS       += arch/mips/sgi/kernel arch/mips/arc
 #
 # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon,
 # 0x88002000 for production kernels.  Note that the value must be
@@ -123,6 +138,14 @@
 endif
 
 #
+# Baget/MIPS
+#
+ifdef CONFIG_BAGET_MIPS
+SUBDIRS       += arch/mips/baget arch/mips/baget/prom
+LIBS          += arch/mips/baget/baget.a arch/mips/baget/prom/bagetlib.a
+endif
+
+#
 # Choosing incompatible machines durings configuration will result in
 # error messages during linking.  Select a default linkscript if
 # none has been choosen above.
@@ -150,7 +173,16 @@
 
 SUBDIRS := $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib tools)
 CORE_FILES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(CORE_FILES)
-LIBS := arch/mips/lib/lib.a $(LIBS) arch/mips/lib/lib.a
+LIBS := arch/mips/lib/lib.a $(LIBS)
+
+ifdef CONFIG_BAGET_MIPS
+
+BAGETBOOT = $(MAKE) -C arch/$(ARCH)/baget
+
+balo:  vmlinux
+	$(BAGETBOOT) balo
+
+endif
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/algor/README linux/arch/mips/algor/README
--- v2.3.8/linux/arch/mips/algor/README	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/algor/README	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,5 @@
+The code for the Algorithmics P4032 evaluation board is currently under
+development.  I'll release it when it's up to the same strength as
+the other ports.
+
+  Ralf
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/Makefile linux/arch/mips/arc/Makefile
--- v2.3.8/linux/arch/mips/arc/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/Makefile	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,23 @@
+# $Id: Makefile,v 1.1 1998/10/18 13:32:08 tsbogend Exp $
+# Makefile for the SGI arcs prom monitor library routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+OBJS  = console.o init.o printf.o memory.o tree.o env.o \
+      cmdline.o misc.o time.o file.o identify.o
+
+all: arclib.a
+
+arclib.a: $(OBJS)
+	$(AR) rcs arclib.a $(OBJS)
+	sync
+
+dep:
+	$(CPP) -M *.c > .depend
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/cmdline.c linux/arch/mips/arc/cmdline.c
--- v2.3.8/linux/arch/mips/arc/cmdline.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/cmdline.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,64 @@
+/*
+ * cmdline.c: Kernel command line creation using ARCS argc/argv.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: cmdline.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/sgialib.h>
+#include <asm/bootinfo.h>
+
+/* #define DEBUG_CMDLINE */
+
+char arcs_cmdline[CL_SIZE];
+
+__initfunc(char *prom_getcmdline(void))
+{
+	return &(arcs_cmdline[0]);
+}
+
+static char *ignored[] = {
+	"ConsoleIn=",
+	"ConsoleOut=",
+	"SystemPartition=",
+	"OSLoader=",
+	"OSLoadPartition=",
+	"OSLoadFilename="
+};
+#define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0])))))
+
+__initfunc(void prom_init_cmdline(void))
+{
+	char *cp;
+	int actr, i;
+
+	actr = 1; /* Always ignore argv[0] */
+
+	cp = &(arcs_cmdline[0]);
+	while(actr < prom_argc) {
+		for(i = 0; i < NENTS(ignored); i++) {
+			int len = strlen(ignored[i]);
+
+			if(!strncmp(prom_argv[actr], ignored[i], len))
+				goto pic_cont;
+		}
+		/* Ok, we want it. */
+		strcpy(cp, prom_argv[actr]);
+		cp += strlen(prom_argv[actr]);
+		*cp++ = ' ';
+
+	pic_cont:
+		actr++;
+	}
+	if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+		--cp;
+	*cp = '\0';
+
+#ifdef DEBUG_CMDLINE
+	prom_printf("prom_init_cmdline: %s\n", &(arcs_cmdline[0]));
+#endif
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/console.c linux/arch/mips/arc/console.c
--- v2.3.8/linux/arch/mips/arc/console.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/console.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,50 @@
+/*
+ * console.c: SGI arcs console code.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@sgi.com)
+ * Compability with board caches, Ulf Carlsson
+ *
+ * $Id: console.c,v 1.2 1999/06/12 18:42:38 ulfc Exp $
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <asm/sgialib.h>
+#include <asm/bcache.h>
+
+/* The romvec is not compatible with board caches.  Thus we disable it during
+ * romvec action.  Since r4xx0.c is always compiled and linked with your kernel,
+ * this shouldn't cause any harm regardless what MIPS processor you have.
+ *
+ * The romvec write and read functions seem to interfere with the serial lines
+ * in some way. You should be careful with them.
+ */
+extern struct bcache_ops *bcops;
+
+#ifdef CONFIG_SGI_PROM_CONSOLE
+void prom_putchar(char c)
+#else
+__initfunc(void prom_putchar(char c))
+#endif
+{
+	long cnt;
+	char it = c;
+
+	bcops->bc_disable();
+	romvec->write(1, &it, 1, &cnt);
+	bcops->bc_enable();
+}
+
+#ifdef CONFIG_SGI_PROM_CONSOLE
+char prom_getchar(void)
+#else
+__initfunc(char prom_getchar(void))
+#endif
+{
+	long cnt;
+	char c;
+
+	bcops->bc_disable();
+	romvec->read(0, &c, 1, &cnt);
+	bcops->bc_enable();
+	return c;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/env.c linux/arch/mips/arc/env.c
--- v2.3.8/linux/arch/mips/arc/env.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/env.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,22 @@
+/*
+ * env.c: ARCS environment variable routines.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: env.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/sgialib.h>
+
+__initfunc(char *prom_getenv(char *name))
+{
+	return romvec->get_evar(name);
+}
+
+__initfunc(long prom_setenv(char *name, char *value))
+{
+	return romvec->set_evar(name, value);
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/file.c linux/arch/mips/arc/file.c
--- v2.3.8/linux/arch/mips/arc/file.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/file.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,59 @@
+/*
+ * file.c: ARCS firmware interface to files.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: file.c,v 1.1 1998/10/18 13:32:08 tsbogend Exp $
+ */
+#include <linux/init.h>
+#include <asm/sgialib.h>
+
+__initfunc(long prom_getvdirent(unsigned long fd, struct linux_vdirent *ent, unsigned long num, unsigned long *cnt))
+{
+	return romvec->get_vdirent(fd, ent, num, cnt);
+}
+
+__initfunc(long prom_open(char *name, enum linux_omode md, unsigned long *fd))
+{
+	return romvec->open(name, md, fd);
+}
+
+__initfunc(long prom_close(unsigned long fd))
+{
+	return romvec->close(fd);
+}
+
+__initfunc(long prom_read(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt))
+{
+	return romvec->read(fd, buf, num, cnt);
+}
+
+__initfunc(long prom_getrstatus(unsigned long fd))
+{
+	return romvec->get_rstatus(fd);
+}
+
+__initfunc(long prom_write(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt))
+{
+	return romvec->write(fd, buf, num, cnt);
+}
+
+__initfunc(long prom_seek(unsigned long fd, struct linux_bigint *off, enum linux_seekmode sm))
+{
+	return romvec->seek(fd, off, sm);
+}
+
+__initfunc(long prom_mount(char *name, enum linux_mountops op))
+{
+	return romvec->mount(name, op);
+}
+
+__initfunc(long prom_getfinfo(unsigned long fd, struct linux_finfo *buf))
+{
+	return romvec->get_finfo(fd, buf);
+}
+
+__initfunc(long prom_setfinfo(unsigned long fd, unsigned long flags, unsigned long msk))
+{
+	return romvec->set_finfo(fd, flags, msk);
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/identify.c linux/arch/mips/arc/identify.c
--- v2.3.8/linux/arch/mips/arc/identify.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/identify.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,68 @@
+/*
+ * identify.c: identify machine by looking up system identifier
+ *
+ * Copyright (C) 1998 Thomas Bogendoerfer
+ * 
+ * This code is based on arch/mips/sgi/kernel/system.c, which is
+ * 
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: identify.c,v 1.2 1999/02/25 21:04:13 tsbogend Exp $
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/sgi.h>
+#include <asm/sgialib.h>
+#include <asm/bootinfo.h>
+
+struct smatch {
+    char *name;
+    int group;
+    int type;
+    int flags;
+};
+
+static struct smatch mach_table[] = {
+    { "SGI-IP22", MACH_GROUP_SGI, MACH_SGI_INDY, PROM_FLAG_ARCS },
+    { "Microsoft-Jazz", MACH_GROUP_JAZZ, MACH_MIPS_MAGNUM_4000, 0 },
+    { "PICA-61", MACH_GROUP_JAZZ, MACH_ACER_PICA_61, 0 },
+    { "RM200PCI", MACH_GROUP_SNI_RM, MACH_SNI_RM200_PCI, 0 }
+};
+
+int prom_flags;
+
+static struct smatch * __init string_to_mach(char *s)
+{
+    int i;
+    
+    for (i = 0; i < sizeof (mach_table); i++) {
+	if(!strcmp(s, mach_table[i].name))
+	    return &mach_table[i];
+    }
+    prom_printf("\nYeee, could not determine architecture type <%s>\n", s);
+    prom_printf("press a key to reboot\n");
+    prom_getchar();
+    romvec->imode();
+    return NULL;
+}
+
+void __init prom_identify_arch(void)
+{
+    pcomponent *p;
+    struct smatch *mach;
+    
+    /* The root component tells us what machine architecture we
+     * have here.
+     */
+    p = prom_getchild(PROM_NULL_COMPONENT);
+    printk("ARCH: %s\n", p->iname);
+    mach = string_to_mach(p->iname);
+
+    mips_machgroup = mach->group;
+    mips_machtype = mach->type;
+    prom_flags = mach->flags;
+}
+
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/init.c linux/arch/mips/arc/init.c
--- v2.3.8/linux/arch/mips/arc/init.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/init.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,67 @@
+/*
+ * init.c: PROM library initialisation code.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: init.c,v 1.2 1999/02/25 21:22:49 tsbogend Exp $
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+
+#include <asm/sgialib.h>
+
+/* #define DEBUG_PROM_INIT */
+
+/* Master romvec interface. */
+struct linux_romvec *romvec;
+struct linux_promblock *sgi_pblock;
+int prom_argc;
+char **prom_argv, **prom_envp;
+unsigned short prom_vers, prom_rev;
+
+extern void prom_testtree(void);
+
+__initfunc(int prom_init(int argc, char **argv, char **envp))
+{
+	struct linux_promblock *pb;
+
+	romvec = ROMVECTOR;
+	pb = sgi_pblock = PROMBLOCK;
+	prom_argc = argc;
+	prom_argv = argv;
+	prom_envp = envp;
+
+	if(pb->magic != 0x53435241) {
+		prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic);
+		while(1)
+			;
+	}
+
+	prom_init_cmdline();
+
+	prom_vers = pb->ver;
+	prom_rev = pb->rev;
+	prom_identify_arch();
+#ifdef CONFIG_SGI
+	printk("PROMLIB: SGI ARCS firmware Version %d Revision %d\n",
+		    prom_vers, prom_rev);
+#else
+	printk("PROMLIB: ARC firmware Version %d Revision %d\n",
+		    prom_vers, prom_rev);
+#endif
+	prom_meminit();
+
+#if 0
+	prom_testtree();
+#endif
+
+#ifdef DEBUG_PROM_INIT
+	{
+		prom_printf("Press a key to reboot\n");
+		(void) prom_getchar();
+		romvec->imode();
+	}
+#endif
+	return 0;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/memory.c linux/arch/mips/arc/memory.c
--- v2.3.8/linux/arch/mips/arc/memory.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/memory.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,208 @@
+/*
+ * memory.c: PROM library functions for acquiring/using memory descriptors
+ *           given to us from the ARCS firmware.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: memory.c,v 1.5 1999/04/14 21:25:02 tsbogend Exp $
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+
+#include <asm/sgialib.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bootinfo.h>
+
+/* #define DEBUG */
+
+__initfunc(struct linux_mdesc *prom_getmdesc(struct linux_mdesc *curr))
+{
+	return romvec->get_mdesc(curr);
+}
+
+#ifdef DEBUG /* convenient for debugging */
+static char *arcs_mtypes[8] = {
+	"Exception Block",
+	"ARCS Romvec Page",
+	"Free/Contig RAM",
+	"Generic Free RAM",
+	"Bad Memory",
+	"Standlong Program Pages",
+	"ARCS Temp Storage Area",
+	"ARCS Permanent Storage Area"
+};
+
+static char *arc_mtypes[8] = {
+	"Exception Block",
+	"SystemParameterBlock",
+	"FreeMemory",
+	"Bad Memory",
+	"LoadedProgram",
+	"FirmwareTemporary",
+	"FirmwarePermanent",
+	"FreeContigiuous"
+};
+#define mtypes(a) (prom_flags & PROM_FLAG_ARCS) ? arcs_mtypes[a.arcs] : arc_mtypes[a.arc]
+#endif
+
+static struct prom_pmemblock prom_pblocks[PROM_MAX_PMEMBLOCKS];
+
+__initfunc(struct prom_pmemblock *prom_getpblock_array(void))
+{
+	return &prom_pblocks[0];
+}
+
+#define MEMTYPE_DONTUSE   0
+#define MEMTYPE_PROM      1
+#define MEMTYPE_FREE      2
+
+static int __init prom_memtype_classify (union linux_memtypes type)
+{
+    if (prom_flags & PROM_FLAG_ARCS) {
+	switch (type.arcs) {
+	 case arcs_free:
+	 case arcs_fcontig:
+	    return MEMTYPE_FREE;
+	 case arcs_atmp:
+	 case arcs_aperm:
+	    return MEMTYPE_PROM;
+	 default:
+	    return MEMTYPE_DONTUSE;
+	}
+    } else {
+	switch (type.arc) {
+	 case arc_free:
+	 case arc_fcontig:
+	    return MEMTYPE_FREE;
+	 case arc_rvpage:
+	 case arc_atmp:
+	 case arc_aperm:
+	    return MEMTYPE_PROM;
+	 default:
+	    return MEMTYPE_DONTUSE;
+	}
+    }
+}
+
+__initfunc(static void prom_setup_memupper(void))
+{
+	struct prom_pmemblock *p, *highest;
+
+	for(p = prom_getpblock_array(), highest = 0; p->size != 0; p++) {
+		if(p->base == 0xdeadbeef)
+			prom_printf("WHEEE, bogus pmemblock\n");
+		if(!highest || p->base > highest->base)
+			highest = p;
+	}
+	mips_memory_upper = highest->base + highest->size;
+#ifdef DEBUG
+	prom_printf("prom_setup_memupper: mips_memory_upper = %08lx\n",
+		    mips_memory_upper);
+#endif
+}
+
+__initfunc(void prom_meminit(void))
+{
+	struct linux_mdesc *p;
+	int totram;
+	int i = 0;
+
+	p = prom_getmdesc(PROM_NULL_MDESC);
+#ifdef DEBUG
+	prom_printf("ARCS MEMORY DESCRIPTOR dump:\n");
+	while(p) {
+		prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n",
+			    i, p, p->base, p->pages, mtypes(p->type));
+		p = prom_getmdesc(p);
+		i++;
+	}
+#endif
+	p = prom_getmdesc(PROM_NULL_MDESC);
+	totram = 0;
+	i = 0;
+	while(p) {
+	    prom_pblocks[i].type = prom_memtype_classify (p->type);
+	    prom_pblocks[i].base = ((p->base<<PAGE_SHIFT) + 0x80000000);
+	    prom_pblocks[i].size = p->pages << PAGE_SHIFT;
+	    switch (prom_pblocks[i].type) {
+	     case MEMTYPE_FREE:
+		totram += prom_pblocks[i].size;
+#ifdef DEBUG
+		prom_printf("free_chunk[%d]: base=%08lx size=%d\n",
+			    i, prom_pblocks[i].base,
+			    prom_pblocks[i].size);
+#endif
+		i++;
+		break;
+	     case MEMTYPE_PROM:
+#ifdef DEBUG
+		prom_printf("prom_chunk[%d]: base=%08lx size=%d\n",
+			    i, prom_pblocks[i].base,
+			    prom_pblocks[i].size);
+#endif
+		i++;
+		break;
+	     default:
+		break;
+	    }
+	    p = prom_getmdesc(p);
+	}
+	prom_pblocks[i].base = 0xdeadbeef;
+	prom_pblocks[i].size = 0; /* indicates last elem. of array */
+	printk("PROMLIB: Total free ram %d bytes (%dK,%dMB)\n",
+		    totram, (totram/1024), (totram/1024/1024));
+
+	/* Setup upper physical memory bound. */
+	prom_setup_memupper();
+}
+
+/* Called from mem_init() to fixup the mem_map page settings. */
+__initfunc(void prom_fixup_mem_map(unsigned long start, unsigned long end))
+{
+	struct prom_pmemblock *p;
+	int i, nents;
+
+	/* Determine number of pblockarray entries. */
+	p = prom_getpblock_array();
+	for(i = 0; p[i].size; i++)
+		;
+	nents = i;
+restart:
+	while(start < end) {
+		for(i = 0; i < nents; i++) {
+			if((p[i].type == MEMTYPE_FREE) &&
+			   (start >= (p[i].base)) &&
+			   (start < (p[i].base + p[i].size))) {
+				start = p[i].base + p[i].size;
+				start &= PAGE_MASK;
+				goto restart;
+			}
+		}
+		set_bit(PG_reserved, &mem_map[MAP_NR(start)].flags);
+		start += PAGE_SIZE;
+	}
+}
+
+void prom_free_prom_memory (void)
+{
+    struct prom_pmemblock *p;
+    unsigned long addr;
+    unsigned long num_pages = 0;
+
+    for(p = prom_getpblock_array(); p->size != 0; p++) {
+	if (p->type == MEMTYPE_PROM) {
+	    for (addr = p->base; addr < p->base + p->size; addr += PAGE_SIZE) {
+		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+		free_page(addr);
+		num_pages++;
+	    }
+	}
+    }
+    printk ("Freeing prom memory: %dk freed\n",num_pages << (PAGE_SHIFT - 10));
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/misc.c linux/arch/mips/arc/misc.c
--- v2.3.8/linux/arch/mips/arc/misc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/misc.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,84 @@
+/* $Id: misc.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $
+ *
+ * misc.c: Miscellaneous ARCS PROM routines.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <asm/bcache.h>
+#include <asm/sgialib.h>
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+
+extern unsigned long mips_cputype;
+extern void *sgiwd93_host;
+extern void reset_wd33c93(void *instance);
+
+void prom_halt(void)
+{
+	bcops->bc_disable();
+	cli();
+#if CONFIG_SCSI_SGIWD93
+	reset_wd33c93(sgiwd93_host);
+#endif
+	romvec->halt();
+}
+
+void prom_powerdown(void)
+{
+	bcops->bc_disable();
+	cli();
+#if CONFIG_SCSI_SGIWD93
+	reset_wd33c93(sgiwd93_host);
+#endif
+	romvec->pdown();
+}
+
+/* XXX is this a soft reset basically? XXX */
+void prom_restart(void)
+{
+	bcops->bc_disable();
+	cli();
+#if CONFIG_SCSI_SGIWD93
+	reset_wd33c93(sgiwd93_host);
+#endif
+	romvec->restart();
+}
+
+void prom_reboot(void)
+{
+	bcops->bc_disable();
+	cli();
+#if CONFIG_SCSI_SGIWD93
+	reset_wd33c93(sgiwd93_host);
+#endif
+	romvec->reboot();
+}
+
+void prom_imode(void)
+{
+	bcops->bc_disable();
+	cli();
+#if CONFIG_SCSI_SGIWD93
+	reset_wd33c93(sgiwd93_host);
+#endif
+	romvec->imode();
+}
+
+long prom_cfgsave(void)
+{
+	return romvec->cfg_save();
+}
+
+struct linux_sysid *prom_getsysid(void)
+{
+	return romvec->get_sysid();
+}
+
+__initfunc(void prom_cacheflush(void))
+{
+	romvec->cache_flush();
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/printf.c linux/arch/mips/arc/printf.c
--- v2.3.8/linux/arch/mips/arc/printf.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/printf.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,40 @@
+/*
+ * printf.c: Putting things on the screen using SGI arcs
+ *           PROM facilities.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@sgi.com)
+ *
+ * $Id: printf.c,v 1.2 1999/06/12 18:42:38 ulfc Exp $
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <asm/sgialib.h>
+
+static char ppbuf[1024];
+
+#ifdef CONFIG_SGI_PROM_CONSOLE
+void prom_printf(char *fmt, ...)
+#else
+__initfunc(void prom_printf(char *fmt, ...))
+#endif
+{
+	va_list args;
+	char ch, *bptr;
+	int i;
+
+	va_start(args, fmt);
+	i = vsprintf(ppbuf, fmt, args);
+
+	bptr = ppbuf;
+
+	while((ch = *(bptr++)) != 0) {
+		if(ch == '\n')
+			prom_putchar('\r');
+
+		prom_putchar(ch);
+	}
+	va_end(args);
+	return;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/salone.c linux/arch/mips/arc/salone.c
--- v2.3.8/linux/arch/mips/arc/salone.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/salone.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,25 @@
+/*
+ * salone.c: Routines to load into memory and execute stand-along
+ *           program images using ARCS PROM firmware.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: salone.c,v 1.1 1998/10/18 13:32:09 tsbogend Exp $
+ */
+#include <linux/init.h>
+#include <asm/sgialib.h>
+
+__initfunc(long prom_load(char *name, unsigned long end, unsigned long *pc, unsigned long *eaddr))
+{
+	return romvec->load(name, end, pc, eaddr);
+}
+
+__initfunc(long prom_invoke(unsigned long pc, unsigned long sp, long argc, char **argv, char **envp))
+{
+	return romvec->invoke(pc, sp, argc, argv, envp);
+}
+
+__initfunc(long prom_exec(char *name, long argc, char **argv, char **envp))
+{
+	return romvec->exec(name, argc, argv, envp);
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/time.c linux/arch/mips/arc/time.c
--- v2.3.8/linux/arch/mips/arc/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/time.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,19 @@
+/*
+ * time.c: Extracting time information from ARCS prom.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: time.c,v 1.1 1998/10/18 13:32:10 tsbogend Exp $
+ */
+#include <linux/init.h>
+#include <asm/sgialib.h>
+
+__initfunc(struct linux_tinfo *prom_gettinfo(void))
+{
+	return romvec->get_tinfo();
+}
+
+__initfunc(unsigned long prom_getrtime(void))
+{
+	return romvec->get_rtime();
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/arc/tree.c linux/arch/mips/arc/tree.c
--- v2.3.8/linux/arch/mips/arc/tree.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/arc/tree.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,109 @@
+/*
+ * tree.c: PROM component device tree code.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: tree.c,v 1.1 1998/10/18 13:32:10 tsbogend Exp $
+ */
+#include <linux/init.h>
+#include <asm/sgialib.h>
+
+#define DEBUG_PROM_TREE
+
+__initfunc(pcomponent *prom_getsibling(pcomponent *this))
+{
+	if(this == PROM_NULL_COMPONENT)
+		return PROM_NULL_COMPONENT;
+	return romvec->next_component(this);
+}
+
+__initfunc(pcomponent *prom_getchild(pcomponent *this))
+{
+	return romvec->child_component(this);
+}
+
+__initfunc(pcomponent *prom_getparent(pcomponent *child))
+{
+	if(child == PROM_NULL_COMPONENT)
+		return PROM_NULL_COMPONENT;
+	return romvec->parent_component(child);
+}
+
+__initfunc(long prom_getcdata(void *buffer, pcomponent *this))
+{
+	return romvec->component_data(buffer, this);
+}
+
+__initfunc(pcomponent *prom_childadd(pcomponent *this, pcomponent *tmp, void *data))
+{
+	return romvec->child_add(this, tmp, data);
+}
+
+__initfunc(long prom_delcomponent(pcomponent *this))
+{
+	return romvec->comp_del(this);
+}
+
+__initfunc(pcomponent *prom_componentbypath(char *path))
+{
+	return romvec->component_by_path(path);
+}
+
+#ifdef DEBUG_PROM_TREE
+static char *classes[] = {
+	"system", "processor", "cache", "adapter", "controller", "peripheral",
+	"memory"
+};
+
+static char *types[] = {
+	"arc", "cpu", "fpu", "picache", "pdcache", "sicache", "sdcache", "sccache",
+	"memdev", "eisa adapter", "tc adapter", "scsi adapter", "dti adapter",
+	"multi-func adapter", "disk controller", "tp controller",
+	"cdrom controller", "worm controller", "serial controller",
+	"net controller", "display controller", "parallel controller",
+	"pointer controller", "keyboard controller", "audio controller",
+	"misc controller", "disk peripheral", "floppy peripheral",
+	"tp peripheral", "modem peripheral", "monitor peripheral",
+	"printer peripheral", "pointer peripheral", "keyboard peripheral",
+	"terminal peripheral", "line peripheral", "net peripheral",
+	"misc peripheral", "anonymous"
+};
+
+static char *iflags[] = {
+	"bogus", "read only", "removable", "console in", "console out",
+	"input", "output"
+};
+
+__initfunc(static void dump_component(pcomponent *p))
+{
+	prom_printf("[%p]:class<%s>type<%s>flags<%s>ver<%d>rev<%d>",
+		    p, classes[p->class], types[p->type],
+		    iflags[p->iflags], p->vers, p->rev);
+	prom_printf("key<%08lx>\n\tamask<%08lx>cdsize<%d>ilen<%d>iname<%s>\n",
+		    p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname);
+}
+
+__initfunc(static void traverse(pcomponent *p, int op))
+{
+	dump_component(p);
+	if(prom_getchild(p))
+		traverse(prom_getchild(p), 1);
+	if(prom_getsibling(p) && op)
+		traverse(prom_getsibling(p), 1);
+}
+
+__initfunc(void prom_testtree(void))
+{
+	pcomponent *p;
+
+	p = prom_getchild(PROM_NULL_COMPONENT);
+	dump_component(p);
+	p = prom_getchild(p);
+	while(p) {
+		dump_component(p);
+		p = prom_getsibling(p);
+	}
+	prom_printf("press a key\n");
+	prom_getchar();
+}
+#endif
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/Makefile linux/arch/mips/baget/Makefile
--- v2.3.8/linux/arch/mips/baget/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/Makefile	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,75 @@
+# $Id$
+#
+# Makefile for the Baget specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+all: baget.a 
+
+image:	../../../vmlinux
+	cp -f $< $@
+
+O_TARGET := baget.a
+O_OBJS   := baget.o print.o setup.o time.o irq.o bagetIRQ.o reset.o wbflush.o
+
+ifeq ($(CONFIG_SERIAL),y)
+	OX_OBJS += vacserial.o
+else
+	ifeq ($(CONFIG_SERIAL),m)
+		MX_OBJS += vacserial.o
+	endif
+endif
+ifeq ($(CONFIG_VAC_RTC),y)
+	OX_OBJS += vacrtc.o
+else
+	ifeq ($(CONFIG_VAC_RTC),m)
+		MX_OBJS += vacrtc.o
+	endif
+endif
+
+bagetIRQ.o : bagetIRQ.S
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+
+##################### Baget Loader stuff ########################
+
+dummy.c:
+	touch $@
+
+image.bin: image
+	$(OBJCOPY) -O binary $< $@
+
+ramdisk.bin:
+	echo "Dummy ramdisk used. Provide your own if needed !" > $@
+
+dummy.o: dummy.c image.bin ramdisk.bin
+	$(CC) $(CFLAGS) -c -o $@ $<
+	$(OBJCOPY) --add-section=.vmlinux=image.bin \
+                   --add-section=.ramdisk=ramdisk.bin   $@ 
+
+balo.h: image
+	$(NM) $< | awk ' \
+            BEGIN               { printf "/* DO NOT EDIT THIS FILE */\n" }    \
+	    /kernel_entry/      { printf "#define START 0x%s\n", $$1 }        \
+            /balo_ramdisk_base/ { printf "#define RAMDISK_BASE 0x%s\n", $$1 } \
+	    /balo_ramdisk_size/ { printf "#define RAMDISK_SIZE 0x%s\n", $$1 } \
+                       ' > $@
+balo.o:   balo.c balo.h
+	$(CC) $(CFLAGS) -c $< 
+
+balo_supp.o: balo_supp.S
+	$(CC) $(CFLAGS) -c $<
+
+balo:   balo.o dummy.o balo_supp.o print.o
+	$(LD) $(LDFLAGS) -T ld.script.balo -o $@ $^ 
+
+clean:
+	rm -f balo.o balo.h dummy.o dummy.c hello.o image.bin image balo_supp.o
+	rm -f $(O_OBJS) $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/baget.c linux/arch/mips/baget/baget.c
--- v2.3.8/linux/arch/mips/baget/baget.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/baget.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,104 @@
+/* $Id$
+ *
+ * baget.c: Baget low level stuff
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ *
+ */
+#include <stdarg.h>
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/system.h>
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/pgtable.h>
+
+#include <asm/baget/baget.h>
+
+/* 
+ * Following values are set by BALO into RAM disk buffer parameters
+ */
+unsigned long balo_ramdisk_base = 0xBA;  /* Signature for BALO ! */
+unsigned long balo_ramdisk_size = 0;
+
+
+/*
+ *  Following code is based on routines from 'mm/vmalloc.c'
+ *  Additional parameters  ioaddr  is needed to iterate across real I/O address.
+ */
+static inline int alloc_area_pte(pte_t * pte, unsigned long address, 
+				 unsigned long size, unsigned long ioaddr)
+{
+        unsigned long end;
+
+        address &= ~PMD_MASK;
+        end = address + size;
+        if (end > PMD_SIZE)
+                end = PMD_SIZE;
+        while (address < end) {
+                unsigned long page;
+                if (!pte_none(*pte))
+                        printk("kseg2_alloc_io: page already exists\n");
+		/*
+		 *  For MIPS looks pretty to have transparent mapping
+		 *  for KSEG2 areas  -- user can't access one, and no 
+		 *  problems with  virtual <--> physical  translation.
+		 */
+                page = ioaddr & PAGE_MASK;
+
+                set_pte(pte, __pte(page | pgprot_val(PAGE_USERIO) |
+				  _PAGE_GLOBAL | __READABLE | __WRITEABLE));
+                address += PAGE_SIZE;
+		ioaddr  += PAGE_SIZE;
+                pte++;
+        }
+        return 0;
+}
+
+static inline int alloc_area_pmd(pmd_t * pmd, unsigned long address, 
+				 unsigned long size, unsigned long ioaddr)
+{
+        unsigned long end;
+
+        address &= ~PGDIR_MASK;
+        end = address + size;
+        if (end > PGDIR_SIZE)
+                end = PGDIR_SIZE;
+        while (address < end) {
+                pte_t * pte = pte_alloc_kernel(pmd, address);
+                if (!pte)
+                        return -ENOMEM;
+                if (alloc_area_pte(pte, address, end - address, ioaddr))
+                        return -ENOMEM;
+                address = (address + PMD_SIZE) & PMD_MASK;
+		ioaddr  += PMD_SIZE;
+                pmd++;
+        }
+        return 0;
+}
+
+int kseg2_alloc_io (unsigned long address, unsigned long size)
+{
+        pgd_t * dir;
+        unsigned long end = address + size;
+
+        dir = pgd_offset_k(address);
+        flush_cache_all();
+        while (address < end) {
+                pmd_t *pmd;
+                pgd_t olddir = *dir;
+
+                pmd = pmd_alloc_kernel(dir, address);
+                if (!pmd)
+                        return -ENOMEM;
+                if (alloc_area_pmd(pmd, address, end - address, address))
+                        return -ENOMEM;
+                if (pgd_val(olddir) != pgd_val(*dir))
+                        set_pgdir(address, *dir);
+                address = (address + PGDIR_SIZE) & PGDIR_MASK;
+                dir++;
+        }
+        flush_tlb_all();
+        return 0;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/bagetIRQ.S linux/arch/mips/baget/bagetIRQ.S
--- v2.3.8/linux/arch/mips/baget/bagetIRQ.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/bagetIRQ.S	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,98 @@
+/* $Id$
+ * bagetIRQ.S: Interrupt exception dispatch code for Baget/MIPS
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+
+#include <asm/asm.h>
+#include <asm/mipsconfig.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/addrspace.h>
+
+	.text
+	.set    mips1
+	.set    reorder
+	.set    macro
+	.set    noat
+	.align	5
+
+NESTED(bagetIRQ, PT_SIZE, sp)
+	SAVE_ALL
+	CLI				# Important: mark KERNEL mode !
+
+	la      a1, baget_interrupt
+	.set	push
+	.set    noreorder
+	jal	a1
+	.set    pop 
+	move	a0, sp                                          
+
+	la      a1, ret_from_irq
+	jr	a1
+END(bagetIRQ)
+	
+#define DBE_HANDLER       0x1C
+	
+NESTED(try_read, PT_SIZE, sp)
+	mfc0	t3, CP0_STATUS		# save flags and
+	CLI				#  disable interrupts
+
+	li	t0, KSEG2
+	sltu    t1, t0, a0              # Is it KSEG2 address ?               
+	beqz	t1, mapped              # No - already mapped !    
+					 
+	move    t0, a0		        
+	ori	t0, 0xfff
+	xori    t0, 0xfff               # round address to page
+
+	ori     t1, t0, 0xf00           # prepare EntryLo (N,V,D,G) 
+
+	mfc0    t2,   CP0_ENTRYHI       # save ASID value
+	mtc0	zero, CP0_INDEX
+	mtc0	t0,   CP0_ENTRYHI       # Load MMU values ...
+	mtc0    t1,   CP0_ENTRYLO0
+	nop                             # let it understand
+	nop
+	tlbwi				# ... and write ones
+	nop
+	nop
+	mtc0    t2,  CP0_ENTRYHI           
+	
+mapped:		
+	la	t0, exception_handlers
+	lw	t1, DBE_HANDLER(t0)	# save real handler
+	la	t2, dbe_handler			
+	sw	t2, DBE_HANDLER(t0)	# set temporary local handler
+	li	v0, -1			# default (failure) value
+	
+	li	t2, 1
+	beq	t2, a1, 1f
+	li	t2, 2
+	beq	t2, a1, 2f
+	li	t2, 4
+	beq	t2, a1, 4f
+	b	out
+
+1:	lbu	v0, (a0)		# byte
+	b	out
+
+2:	lhu	v0, (a0)		# short
+	b	out
+
+4:	lw	v0, (a0)		# word
+	
+out:		
+	sw	t1, DBE_HANDLER(t0)	# restore real handler
+	mtc0	t3, CP0_STATUS		# restore CPU flags
+	jr	ra			
+	
+dbe_handler:	
+	li	v0, -1			# mark our failure
+	.set	push
+	.set	noreorder
+	b	out			# "no problems !"
+	rfe				#   return from trap
+	.set	pop
+END(try_read)
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/balo.c linux/arch/mips/baget/balo.c
--- v2.3.8/linux/arch/mips/baget/balo.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/balo.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,190 @@
+/* $Id$
+ *
+ * balo.c: BAget LOader
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ *
+ */
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/addrspace.h>
+
+#include <asm/baget/baget.h>
+
+#include "balo.h"  /* Includes some kernel symbol values */
+
+static char *banner = "\nBaget Linux Loader v0.2\n";
+
+static void mem_move (long *to, long *from, long size)
+{
+	while (size > 0) { 
+		*to++ = *from++;
+		size -= sizeof(long);
+	}
+}
+
+static volatile int *mem_limit     = (volatile int*)KSEG1;
+static volatile int *mem_limit_dbe = (volatile int*)KSEG1;
+
+static int can_write (volatile int* p) {
+        return p <  (int*)(KSEG1+BALO_OFFSET) ||
+               p >= (int*)(KSEG1+BALO_OFFSET+BALO_SIZE);
+}
+
+static volatile enum balo_state_enum {
+	BALO_INIT,
+	MEM_INIT,
+	MEM_PROBE,
+	START_KERNEL
+} balo_state = BALO_INIT;
+
+
+static __inline__ void reset_and_jump(int start, int mem_upper)
+{
+	__asm__ __volatile__(
+                ".set\tnoreorder\n\t"
+                ".set\tnoat\n\t"
+                "mfc0\t$1,$12\n\t"
+                "nop\n\t"
+                "nop\n\t"
+                "nop\n\t"
+                "ori\t$1,$1,0xff00\n\t"
+                "xori\t$1,$1,0xff00\n\t"
+                "mtc0\t$1,$12\n\t"
+                "nop\n\t"
+                "nop\n\t"
+                "nop\n\t"
+		"move\t$4,%1\n\t"
+		"jr\t%0\n\t"
+		"nop\n\t"
+                ".set\tat\n\t"
+                ".set\treorder"           
+                : /* no outputs */
+                :"Ir" (start), "Ir" (mem_upper)
+                :"$1", "$4", "memory");
+}
+
+static void start_kernel(void)
+{
+	extern char _vmlinux_start, _vmlinux_end;
+	extern char _ramdisk_start, _ramdisk_end;
+
+        outs( "Relocating Linux... " );
+	mem_move((long*)KSEG0, (long*)&_vmlinux_start, 
+                 &_vmlinux_end-&_vmlinux_start);
+	outs("done.\n");
+
+	if (&_ramdisk_start != &_ramdisk_end) {
+		outs("Setting up RAMDISK... ");
+		if (*(unsigned long*)RAMDISK_BASE != 0xBA) {
+			outs("Bad RAMDISK_BASE signature in system image.\n");
+                        balo_hungup();
+		}
+		*(unsigned long*)RAMDISK_BASE = (unsigned long)&_ramdisk_start;
+		*(unsigned long*)RAMDISK_SIZE = &_ramdisk_end -&_ramdisk_start;
+		outs("done.\n");
+	}
+
+	{ 
+		extern void flush_cache_low(int isize, int dsize);
+		flush_cache_low(256*1024,256*1024);
+	}
+
+        balo_printf( "Kernel entry: %x\n\n", START);
+	balo_state = START_KERNEL;
+	reset_and_jump(START, (int)mem_limit-KSEG1+KSEG0);
+}
+
+
+static void mem_probe(void)
+{
+	balo_state = MEM_PROBE;
+	outs("RAM: <");
+	while(mem_limit < mem_limit_dbe) {
+                if (can_write(mem_limit) && *mem_limit != 0) 
+                        break; /* cycle found */
+		outc('.');
+		if (can_write(mem_limit)) 
+                        *mem_limit = -1; /* mark */
+                mem_limit += 0x40000;
+	}
+	outs(">\n");
+	start_kernel();
+}
+
+volatile unsigned int int_cause;
+volatile unsigned int epc;
+volatile unsigned int badvaddr;
+
+static void print_regs(void)
+{
+        balo_printf("CAUSE=%x EPC=%x BADVADDR=%x\n",
+                    int_cause, epc, badvaddr);
+}
+
+void int_handler(struct pt_regs *regs)
+{ 
+        switch (balo_state) {
+	case BALO_INIT:
+                balo_printf("\nBALO: trap in balo itself.\n");
+		print_regs();
+                balo_hungup();
+		break;
+	case MEM_INIT:
+                if ((int_cause & CAUSE_MASK) != CAUSE_DBE) {
+                        balo_printf("\nBALO: unexpected trap during memory init.\n");
+			print_regs();
+                        balo_hungup();
+		} else {
+			mem_probe();
+		}
+		break;
+	case MEM_PROBE:
+                balo_printf("\nBALO: unexpected trap during memory probe.\n");
+		print_regs();
+                balo_hungup();
+		break;
+	case START_KERNEL:
+                balo_printf("\nBALO: unexpected kernel trap.\n");
+		print_regs();
+                balo_hungup();
+		break;
+	}
+        balo_printf("\nBALO: unexpected return from handler.\n");
+	print_regs();
+        balo_hungup();
+}
+
+static void mem_init(void)
+{
+	balo_state = MEM_INIT;
+
+	while(1) {
+		*mem_limit_dbe;
+		if (can_write(mem_limit_dbe)) 
+			*mem_limit_dbe = 0;
+
+		mem_limit_dbe += 0x40000; /* +1M */
+	}
+        /*  no return: must go to int_handler */
+}
+
+void balo_entry(void)
+{
+        extern void except_vec3_generic(void);
+
+	cli(); 
+	outs(banner);
+        memcpy((void *)(KSEG0 + 0x80), &except_vec3_generic, 0x80);
+	mem_init();
+}
+
+/* Needed for linking */
+
+int vsprintf(char *buf, const char *fmt, va_list arg)
+{
+	outs("BALO: vsprintf called.\n");
+	balo_hungup();
+	return 0;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/balo_supp.S linux/arch/mips/baget/balo_supp.S
--- v2.3.8/linux/arch/mips/baget/balo_supp.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/balo_supp.S	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,143 @@
+/* $Id$
+ * balo_supp.S: BAget Loader supplement
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+	
+	.text
+	.set    mips1
+	
+	/* General exception vector. */
+NESTED(except_vec3_generic, 0, sp)
+	.set    noat
+	la	k0, except_vec3_generic_code
+	jr	k0
+END(except_vec3_generic)
+
+NESTED(except_vec3_generic_code, 0, sp)
+	SAVE_ALL 
+	mfc0	k1, CP0_CAUSE
+	la	k0, int_cause
+	sw      k1, (k0)
+
+        mfc0    k1, CP0_EPC
+        la      k0, epc
+        sw      k1, (k0)
+
+        mfc0    k1, CP0_BADVADDR
+        la      k0, badvaddr
+        sw      k1, (k0)
+
+	la	k0, int_handler 
+        .set    noreorder
+	jal	k0
+        .set    reorder
+	move	a0, sp
+
+        RESTORE_ALL_AND_RET
+END(except_vec3_generic_code)
+
+        .align  5
+NESTED(flush_cache_low, PT_SIZE, sp)
+        .set    at
+        .set    macro
+        .set    noreorder
+        
+        move    t1, a0  # ISIZE
+        move    t2, a1  # DSIZE
+
+        mfc0    t3, CP0_STATUS       # Save the status register.
+        mtc0    zero, CP0_STATUS     # Disable interrupts.
+        la      v0, 1f
+        or      v0, KSEG1            # Run uncached.
+        j       v0
+        nop
+/*
+ * Flush the instruction cache.
+ */
+1:
+        li      v0, ST0_DE | ST0_CE
+        mtc0    v0, CP0_STATUS       # Isolate and swap caches.
+        li      t0, KSEG1
+        subu    t0, t0, t1
+        li      t1, KSEG1
+        la      v0, 1f                          # Run cached
+        j       v0
+        nop
+1:
+        addu    t0, t0, 64
+        sb      zero, -64(t0)
+        sb      zero, -60(t0)
+        sb      zero, -56(t0)
+        sb      zero, -52(t0)
+        sb      zero, -48(t0)
+        sb      zero, -44(t0)
+        sb      zero, -40(t0)
+        sb      zero, -36(t0)
+        sb      zero, -32(t0)
+        sb      zero, -28(t0)
+        sb      zero, -24(t0)
+        sb      zero, -20(t0)
+        sb      zero, -16(t0)
+        sb      zero, -12(t0)
+        sb      zero, -8(t0)
+        bne     t0, t1, 1b
+        sb      zero, -4(t0)
+        
+        la      v0, 1f
+        or      v0, KSEG1
+        j       v0                              # Run uncached
+        nop
+/*
+ * Flush the data cache.
+ */
+1:
+        li      v0, ST0_DE
+        mtc0    v0, CP0_STATUS       # Isolate and swap back caches
+        li      t0, KSEG1
+        subu    t0, t0, t2
+        la      v0, 1f
+        j       v0                              # Back to cached mode
+        nop
+1:
+        addu    t0, t0, 64
+        sb      zero, -64(t0)
+        sb      zero, -60(t0)
+        sb      zero, -56(t0)
+        sb      zero, -52(t0)
+        sb      zero, -48(t0)
+        sb      zero, -44(t0)
+        sb      zero, -40(t0)
+        sb      zero, -36(t0)
+        sb      zero, -32(t0)
+        sb      zero, -28(t0)
+        sb      zero, -24(t0)
+        sb      zero, -20(t0)
+        sb      zero, -16(t0)
+        sb      zero, -12(t0)
+        sb      zero, -8(t0)
+        bne     t0, t1, 1b
+        sb      zero, -4(t0)
+
+        nop                                     # Insure isolated stores
+        nop                                     #   out of pipe.
+        nop
+        nop
+        mtc0    t3, CP0_STATUS                 # Restore status reg.
+        nop                                    # Insure cache unisolated.
+        nop
+        nop
+        nop
+        j       ra
+        nop
+END(flush_cache_low)
+
+/* To satisfy macros only */
+EXPORT(kernelsp)
+	PTR	0x80001000
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/irq.c linux/arch/mips/baget/irq.c
--- v2.3.8/linux/arch/mips/baget/irq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/irq.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,438 @@
+/*
+ * Code to handle Baget/MIPS IRQs plus some generic interrupt stuff.
+ *
+ * Copyright (C) 1998 Vladimir Roganov & Gleb Raiko
+ *      Code (mostly sleleton and comments) derived from DECstation IRQ
+ *      handling.
+ *
+ * $Id$
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+#include <asm/baget/baget.h>
+
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+unsigned long spurious_count = 0;
+
+atomic_t __mips_bh_counter;
+
+/*
+ * This table is a correspondence between IRQ numbers and CPU PILs
+ */
+ 
+static int irq_to_pil_map[BAGET_IRQ_NR] = { 
+	7/*fixme: dma_err -1*/,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 0x00 - 0x0f */
+	-1,-1,-1,-1, 3,-1,-1,-1, 2, 2, 2,-1, 3,-1,-1,3/*fixme: lance*/, /* 0x10 - 0x1f */
+        -1,-1,-1,-1,-1,-1, 5,-1,-1,-1,-1,-1, 7,-1,-1,-1, /* 0x20 - 0x2f */
+	-1, 3, 2/*fixme systimer:3*/, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3  /* 0x30 - 0x3f */
+};
+
+static inline int irq_to_pil(int irq_nr) 
+{
+	int pil = -1;
+
+	if (irq_nr >= BAGET_IRQ_NR) 
+		baget_printk("irq_to_pil: too large irq_nr = 0x%x\n", irq_nr);
+	else {
+		pil = irq_to_pil_map[irq_nr];
+		if (pil == -1)
+			baget_printk("irq_to_pil: unknown irq = 0x%x\n", irq_nr);
+	}
+
+	return pil;
+}
+
+/* Function for careful CP0 interrupt mask access */
+
+static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
+{
+	unsigned long status = read_32bit_cp0_register(CP0_STATUS);
+	status &= ~((clr_mask & 0xFF) << 8);
+	status |=   (set_mask & 0xFF) << 8;
+	write_32bit_cp0_register(CP0_STATUS, status);
+}
+
+/* 
+ *  These two functions may be used for unconditional IRQ
+ *  masking via their PIL protection.
+ */
+
+static inline void mask_irq(unsigned int irq_nr)
+{
+        modify_cp0_intmask(irq_to_pil(irq_nr), 0);
+}
+
+static inline void unmask_irq(unsigned int irq_nr)
+{
+	modify_cp0_intmask(0, irq_to_pil(irq_nr));
+}
+
+/*
+ * The following section is introduced for masking/unasking IRQ
+ * only while no more IRQs uses same CPU PIL.
+ *
+ * These functions are used in request_irq, free_irq, but it looks
+ * they cannot change something: CP0_STATUS is private for any
+ * process, and their action is invisible for system.
+ */
+
+static volatile unsigned int pil_in_use[BAGET_PIL_NR] = { 0, };
+
+void mask_irq_count(int irq_nr) 
+{
+	unsigned long flags;
+	int pil = irq_to_pil(irq_nr);
+	
+	save_and_cli(flags);
+	if (!--pil_in_use[pil])
+		mask_irq(irq_nr);
+	restore_flags(flags);
+}
+
+void unmask_irq_count(int irq_nr) 
+{
+	unsigned long flags;
+	int pil = irq_to_pil(irq_nr);
+	
+	save_and_cli(flags);
+	if (!pil_in_use[pil]++)
+		unmask_irq(irq_nr);
+	restore_flags(flags);
+}
+
+/*
+ * Two functions below are exported versions of mask/unmask IRQ
+ */
+
+void disable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	save_and_cli(flags);
+	mask_irq(irq_nr);
+	restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	save_and_cli(flags);
+	unmask_irq(irq_nr);
+	restore_flags(flags);
+}
+
+/*
+ * Data definition for static irqaction allocation.
+ * It is used while SLAB module is not initialized.
+ */
+
+#define MAX_STATIC_ALLOC 4 
+struct irqaction static_irqaction[MAX_STATIC_ALLOC];
+int static_irq_count = 0;
+ 
+/*
+ * Pointers to the low-level handlers: first the general ones, then the
+ * fast ones, then the bad ones.
+ */
+static struct irqaction *irq_action[BAGET_IRQ_NR] = { NULL, };
+
+int get_irq_list(char *buf)
+{
+	int i, len = 0;
+	struct irqaction * action;
+
+	for (i = 0 ; i < BAGET_IRQ_NR ; i++) {
+		action = irq_action[i];
+		if (!action) 
+			continue;
+		len += sprintf(buf+len, "%2d: %8d %c %s",
+			i, kstat.irqs[0][i],
+			(action->flags & SA_INTERRUPT) ? '+' : ' ',
+			action->name);
+		for (action=action->next; action; action = action->next) {
+			len += sprintf(buf+len, ",%s %s",
+				(action->flags & SA_INTERRUPT) ? " +" : "",
+				action->name);
+		}
+		len += sprintf(buf+len, "\n");
+	}
+	return len;
+}
+
+
+/*
+ * do_IRQ handles IRQ's that have been installed without the
+ * SA_INTERRUPT flag: it uses the full signal-handling return
+ * and runs with other interrupts enabled. All relatively slow
+ * IRQ's should use this format: notably the keyboard/timer
+ * routines.
+ */
+static void do_IRQ(int irq, struct pt_regs * regs)
+{
+	struct irqaction *action;
+	int do_random, cpu;
+
+	cpu = smp_processor_id();
+	hardirq_enter(cpu);
+	kstat.irqs[cpu][irq]++;
+
+	mask_irq(irq);  
+	action = *(irq + irq_action);
+	if (action) {
+		if (!(action->flags & SA_INTERRUPT))
+			__sti();
+		action = *(irq + irq_action);
+		do_random = 0;
+        	do {
+			do_random |= action->flags;
+			action->handler(irq, action->dev_id, regs);
+			action = action->next;
+        	} while (action);
+		if (do_random & SA_SAMPLE_RANDOM)
+			add_interrupt_randomness(irq);
+		__cli();
+	} else {
+		printk("do_IRQ: Unregistered IRQ (0x%X) occured\n", irq);
+	}
+	unmask_irq(irq);
+	hardirq_exit(cpu);
+
+	/* unmasking and bottom half handling is done magically for us. */
+}
+
+/*
+ *  What to do in case of 'no VIC register available' for current interrupt
+ */
+static void vic_reg_error(unsigned long address, unsigned char active_pils) 
+{
+	printk("\nNo VIC register found: reg=%08lx active_pils=%02x\n"
+	       "Current interrupt mask from CP0_CAUSE: %02x\n", 
+	       address, 0xff & active_pils, 
+	       0xff & (read_32bit_cp0_register(CP0_CAUSE)>>8));
+	{ int i; for (i=0; i<10000; i++) udelay(1000); }
+}	
+
+static char baget_fpu_irq = BAGET_FPU_IRQ;
+#define BAGET_INT_FPU {(unsigned long)&baget_fpu_irq, 1}
+
+/*
+ *  Main interrupt handler: interrupt demultiplexer
+ */
+asmlinkage void baget_interrupt(struct pt_regs *regs)
+{
+	static struct baget_int_reg int_reg[BAGET_PIL_NR] = { 
+		BAGET_INT_NONE, BAGET_INT_NONE, BAGET_INT0_ACK, BAGET_INT1_ACK,
+		BAGET_INT_NONE, BAGET_INT_FPU,  BAGET_INT_NONE, BAGET_INT5_ACK 
+	};
+	unsigned char active_pils;
+	while ((active_pils = read_32bit_cp0_register(CP0_CAUSE)>>8)) {
+		int pil;
+		struct baget_int_reg* reg;
+
+                for (pil = 0; pil < BAGET_PIL_NR; pil++) {
+                        if (!(active_pils & (1<<pil))) continue;
+ 			
+			reg = &int_reg[pil];
+
+			if (reg->address) {
+                                extern int try_read(unsigned long,int);
+				int irq  = try_read(reg->address, reg->size);
+
+				if (irq != -1) 
+				      do_IRQ(BAGET_IRQ_MASK(irq), regs);
+				else 
+				      vic_reg_error(reg->address, active_pils);
+			} else {
+				printk("baget_interrupt: unknown interrupt "
+				       "(pil = %d)\n", pil);
+			}
+		}
+	}
+}
+
+/*
+ * Idea is to put all interrupts
+ * in a single table and differenciate them just by number.
+ */
+int setup_baget_irq(int irq, struct irqaction * new)
+{
+	int shared = 0;
+	struct irqaction *old, **p;
+	unsigned long flags;
+
+	p = irq_action + irq;
+	if ((old = *p) != NULL) {
+		/* Can't share interrupts unless both agree to */
+		if (!(old->flags & new->flags & SA_SHIRQ))
+			return -EBUSY;
+
+		/* Can't share interrupts unless both are same type */
+		if ((old->flags ^ new->flags) & SA_INTERRUPT)
+			return -EBUSY;
+
+		/* add new interrupt at end of irq queue */
+		do {
+			p = &old->next;
+			old = *p;
+		} while (old);
+		shared = 1;
+	}
+
+	if (new->flags & SA_SAMPLE_RANDOM)
+		rand_initialize_irq(irq);
+
+	save_and_cli(flags);
+	*p = new;
+	restore_flags(flags);
+
+	if (!shared) {
+		unmask_irq_count(irq);
+	}
+
+	return 0;
+}
+
+int request_irq(unsigned int irq, 
+		void (*handler)(int, void *, struct pt_regs *),
+		unsigned long irqflags, 
+		const char * devname,
+		void *dev_id)
+{
+	int retval;
+	struct irqaction * action = NULL;
+
+	if (irq >= BAGET_IRQ_NR)
+		return -EINVAL;
+	if (!handler)
+		return -EINVAL;
+	if (irq_to_pil_map[irq] < 0) 
+		return -EINVAL;
+
+        if (irqflags & SA_STATIC_ALLOC) {
+		unsigned long flags;
+
+		save_and_cli(flags);
+		if (static_irq_count < MAX_STATIC_ALLOC)
+			action = &static_irqaction[static_irq_count++];
+		else 
+			printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
+			       "using kmalloc\n", irq, devname);
+		restore_flags(flags);
+	}
+  
+	if (action == NULL)
+		action = (struct irqaction *)
+			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+
+	if (!action) 
+		return -ENOMEM;
+
+	action->handler = handler;
+	action->flags = irqflags;
+	action->mask = 0;
+	action->name = devname;
+	action->next = NULL;
+	action->dev_id = dev_id;
+
+	retval = setup_baget_irq(irq, action);
+
+	if (retval)
+		kfree(action);
+
+	return retval;
+}
+		
+void free_irq(unsigned int irq, void *dev_id)
+{
+	struct irqaction * action, **p;
+	unsigned long flags;
+
+	if (irq >= BAGET_IRQ_NR) 
+		printk("Trying to free IRQ%d\n",irq);
+
+	for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+		if (action->dev_id != dev_id)
+			continue;
+
+		/* Found it - now free it */
+		save_and_cli(flags);
+		*p = action->next;
+		if (!irq[irq_action])
+			unmask_irq_count(irq);
+		restore_flags(flags);
+
+		if (action->flags & SA_STATIC_ALLOC)
+		{
+			/* This interrupt is marked as specially allocated
+			 * so it is a bad idea to free it.
+			 */
+			printk("Attempt to free statically allocated "
+			       "IRQ%d (%s)\n", irq, action->name);
+			return;
+		}
+ 
+		kfree(action);
+		return;
+	}
+	printk("Trying to free free IRQ%d\n",irq);
+}
+
+static int baget_irq_canonicalize(int irq) 
+{
+	return irq;
+}
+
+int (*irq_cannonicalize)(int irq) = baget_irq_canonicalize; 
+
+unsigned long probe_irq_on (void)
+{
+	/* TODO */
+	return 0;
+}
+
+int probe_irq_off (unsigned long irqs)
+{
+	/* TODO */
+	return 0;
+}
+
+
+static void write_err_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	*(volatile char*) BAGET_WRERR_ACK = 0;
+}
+
+__initfunc(void init_IRQ(void))
+{
+	irq_setup();
+
+	/* Enable access to VIC interrupt registers */
+	vac_outw(0xacef | 0x8200, VAC_PIO_FUNC);
+
+	/* Enable interrupts for pils 2 and 3 (lines 0 and 1) */
+	modify_cp0_intmask(0, (1<<2)|(1<<3));
+
+	if (request_irq(0/*fixme*/, write_err_interrupt, 
+			SA_INTERRUPT|SA_STATIC_ALLOC, "write_err", NULL) < 0) 
+		printk("init_IRQ: unable to register write_err irq\n");
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/ld.script.balo linux/arch/mips/baget/ld.script.balo
--- v2.3.8/linux/arch/mips/baget/ld.script.balo	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/ld.script.balo	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,124 @@
+OUTPUT_FORMAT("elf32-bigmips")
+OUTPUT_ARCH(mips)
+ENTRY(balo_entry)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x80400000;
+  .rel.text      : { *(.rel.text)	}
+  .rela.text     : { *(.rela.text) 	}
+  .rel.data      : { *(.rel.data)	}
+  .rela.data     : { *(.rela.data) 	}
+  .rel.rodata    : { *(.rel.rodata) 	}
+  .rela.rodata   : { *(.rela.rodata) 	}
+  .rel.got       : { *(.rel.got)	}
+  .rela.got      : { *(.rela.got)	}
+  .rel.ctors     : { *(.rel.ctors)	}
+  .rela.ctors    : { *(.rela.ctors)	}
+  .rel.dtors     : { *(.rel.dtors)	}
+  .rela.dtors    : { *(.rela.dtors)	}
+  .rel.init      : { *(.rel.init)	}
+  .rela.init     : { *(.rela.init)	}
+  .rel.fini      : { *(.rel.fini)	}
+  .rela.fini     : { *(.rela.fini)	}
+  .rel.bss       : { *(.rel.bss)	}
+  .rela.bss      : { *(.rela.bss)	}
+  .rel.plt       : { *(.rel.plt)	}
+  .rela.plt      : { *(.rela.plt)	}
+  .init          : { *(.init)		} =0
+  .text      :
+  {
+    _ftext = . ;
+    *(.text)
+    *(.rodata)
+    *(.rodata1)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+
+  _etext = .;
+  PROVIDE (etext = .);
+
+  /* Startup code */
+  . = ALIGN(4096);
+  __init_begin = .;
+  *(.text.init) 
+  *(.data.init) 
+  . = ALIGN(4096);	/* Align double page for init_task_union */
+  __init_end = .;
+
+   *(.fini)    
+  *(.reginfo) 
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  It would
+     be more correct to do this:
+       . = .;
+     The current expression does not correctly handle the case of a
+     text segment ending precisely at the end of a page; it causes the
+     data segment to skip a page.  The above expression does not have
+     this problem, but it will currently (2/95) cause BFD to allocate
+     a single segment, combining both text and data, for this case.
+     This will prevent the text segment from being shared among
+     multiple executions of the program; I think that is more
+     important than losing a page of the virtual address space (note
+     that no actual memory is lost; the page which is skipped can not
+     be referenced).  */
+  . = .;
+    _fdata = . ;
+    *(.data)
+    CONSTRUCTORS
+
+  *(.data1) 
+  _gp = . + 0x8000;
+  *(.lit8) 
+  *(.lit4) 
+  *(.ctors)   
+  *(.dtors)   
+  *(.got.plt) *(.got) 
+  *(.dynamic) 
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  *(.sdata) 
+  _edata  =  .;
+  PROVIDE (edata = .);
+
+  __bss_start = .;
+  _fbss = .;
+
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  _end = . ;
+  PROVIDE (end = .);
+   *(.sbss)
+   *(.scommon)
+
+  /* These are needed for ELF backends which have not yet been
+     converted to the new style linker.  */
+  *(.stab) 
+  *(.stabstr) 
+  /* DWARF debug sections.
+     Symbols in the .debug DWARF section are relative to the beginning of the
+     section so we begin .debug at 0.  It's not clear yet what needs to happen
+     for the others.   */
+  *(.debug) 
+  *(.debug_srcinfo) 
+  *(.debug_aranges) 
+  *(.debug_pubnames) 
+  *(.debug_sfnames) 
+  *(.line) 
+  /* These must appear regardless of  .  */
+  *(.gptab.data) *(.gptab.sdata) 
+  *(.gptab.bss) *(.gptab.sbss) 
+
+  _vmlinux_start = .;
+  *(.vmlinux)
+  _vmlinux_end = .;
+
+  _ramdisk_start = .;
+  *(.ramdisk)
+  _ramdisk_end = .;
+
+} =0
+
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/print.c linux/arch/mips/baget/print.c
--- v2.3.8/linux/arch/mips/baget/print.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/print.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,118 @@
+/* $Id$
+ *
+ * print.c: Simple print fascility
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ *
+ */
+#include <stdarg.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/baget/baget.h>
+
+/*
+ *  Define this to see 'baget_printk' (debug) messages
+ */
+// #define BAGET_PRINTK
+
+/* 
+ *  This function is same for BALO and Linux baget_printk,
+ *  and normally prints characted to second (UART A) console.
+ */
+
+static void delay(void) {}
+
+static void outc_low(char c)
+{
+        int i;
+        vac_outb(c, VAC_UART_B_TX);
+        for (i=0; i<10000; i++) 
+                delay();
+}
+
+void outc(char c)
+{
+        if (c == '\n')
+                outc_low('\r');
+        outc_low(c);
+}
+
+void outs(char *s) 
+{
+        while(*s) outc(*s++);
+}
+
+void baget_write(char *s, int l)
+{
+        while(l--)
+                outc(*s++);
+}
+
+int baget_printk(const char *fmt, ...)
+{
+#ifdef BAGET_PRINTK
+        va_list args;
+        int i;
+        static char buf[1024];
+
+        va_start(args, fmt);
+        i = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf)-4 */
+        va_end(args);
+        baget_write(buf, i);
+        return i;
+#else
+	return 0;
+#endif
+}
+
+static __inline__ void puthex( int a )
+{
+        static char s[9];
+        static char e[] = "0123456789ABCDEF";
+        int i;
+        for( i = 7; i >= 0; i--, a >>= 4 ) s[i] = e[a & 0x0F];
+        s[8] = '\0';
+        outs( s );
+}
+
+__initfunc(void balo_printf( char *f, ... )) 
+{
+        int *arg = (int*)&f + 1;
+        char c; 
+        int format = 0;
+
+        while((c = *f++) != 0) {
+                switch(c) {
+                default:
+                        if(format) {
+                                outc('%');
+                                format = 0;
+                        }
+                        outc( c );
+                        break;
+                case '%':
+                        if( format ){
+                                format = 0;
+                                outc(c);
+                        } else format = 1;
+                        break;
+                case 'x':
+                        if(format) puthex( *arg++ );
+                        else outc(c);
+                        format = 0;
+                        break;
+                case 's':
+                        if( format ) outs((char *)*arg++);
+                        else outc(c);
+                        format = 0;
+                        break;
+                }
+        }
+}
+
+__initfunc(void balo_hungup(void))
+{ 
+        outs("Hunging up.\n");
+        while(1); 
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/prom/Makefile linux/arch/mips/baget/prom/Makefile
--- v2.3.8/linux/arch/mips/baget/prom/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/prom/Makefile	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,15 @@
+# $Id$
+# Makefile for the Baget/MIPS prom emulator library routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := bagetlib.a
+O_OBJS   := init.o
+
+all: 	$(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/prom/init.c linux/arch/mips/baget/prom/init.c
--- v2.3.8/linux/arch/mips/baget/prom/init.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/prom/init.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,20 @@
+/*
+ * init.c: PROM library initialisation code.
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov 
+ *
+ * $Id$
+ */
+#include <linux/init.h>
+#include <asm/bootinfo.h>
+
+char arcs_cmdline[CL_SIZE];
+
+__initfunc(int prom_init(unsigned int mem_upper))
+{
+	mips_memory_upper = mem_upper;
+	mips_machgroup  = MACH_GROUP_UNKNOWN;
+	mips_machtype   = MACH_UNKNOWN;
+	arcs_cmdline[0] = 0;
+	return 0;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/reset.c linux/arch/mips/baget/reset.c
--- v2.3.8/linux/arch/mips/baget/reset.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/reset.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,32 @@
+#include <linux/kernel.h>
+#include <asm/system.h>
+#include <asm/baget/baget.h>
+
+
+#define R3000_RESET_VEC  0xbfc00000
+typedef void vector(void);
+
+
+static void baget_reboot(char *from_fun)
+{
+	cli();
+	baget_printk("\n%s: jumping to RESET code...\n", from_fun);
+	(*(vector*)R3000_RESET_VEC)();
+}
+
+/* fixme: proper functionality */
+
+void baget_machine_restart(char *command)
+{
+	baget_reboot("restart");
+}
+
+void baget_machine_halt(void)
+{
+	baget_reboot("halt");
+}
+
+void baget_machine_power_off(void)
+{
+	baget_reboot("power off");
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/setup.c linux/arch/mips/baget/setup.c
--- v2.3.8/linux/arch/mips/baget/setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/setup.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,494 @@
+/* $Id$
+ *
+ * setup.c: Baget/MIPS specific setup, including init of the feature struct.
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/irq.h>
+#include <asm/addrspace.h>
+#include <asm/reboot.h>
+
+#include <asm/baget/baget.h>
+
+extern long mips_memory_upper;
+
+extern void wbflush_setup(void);
+
+#define CACHEABLE_STR(val) ((val) ? "not cached" : "cached")
+#define MIN(a,b)           (((a)<(b)) ? (a):(b)) 
+		
+__initfunc(static void vac_show(void))
+{ 
+	int i;
+	unsigned short val, decode = vac_inw(VAC_DECODE_CTRL);
+	unsigned short a24_base = vac_inw(VAC_A24_BASE);
+	unsigned long  a24_addr = ((unsigned long)
+					   (a24_base & VAC_A24_MASK)) << 16;
+	char *decode_mode[]  = { "eprom", "vsb", "shared", "dram" };
+	char *address_mode[] = { "", ", A16", ", A32/A24", ", A32/A24/A16" };
+	char *state[] = { "", " on write", " on read", " on read/write", };
+	char *region_mode[] = { "inactive", "shared", "vsb", "vme" };
+	char *asiz[]        = { "user", "A32", "A16", "A24" };
+	unsigned short regs[] = { VAC_REG1,     VAC_REG2, VAC_REG3  };
+	unsigned short bndr[] = { VAC_DRAM_MASK,VAC_BNDR2,VAC_BNDR3 };
+	unsigned short io_sels[] = { VAC_IOSEL0_CTRL,
+				     VAC_IOSEL1_CTRL,
+				     VAC_IOSEL2_CTRL,
+				     VAC_IOSEL3_CTRL,
+				     VAC_IOSEL4_CTRL,
+				     VAC_IOSEL5_CTRL };
+	
+	printk("[DSACKi %s, DRAMCS%s qualified, boundary%s qualified%s]\n",
+	       (decode & VAC_DECODE_DSACKI)     ? "on" : "off",
+	       (decode & VAC_DECODE_QFY_DRAMCS) ? ""   : " not",
+	       (decode & VAC_DECODE_QFY_BNDR)   ? ""   : " not",
+	       (decode & VAC_DECODE_FPUCS)      ? ", fpu" : "");
+
+	printk("slave0 ");
+	if (decode & VAC_DECODE_RDR_SLSEL0)
+		printk("at %08lx (%d MB)\t[dram %s]\n",
+		       ((unsigned long)vac_inw(VAC_SLSEL0_BASE))<<16,
+		       ((0xffff ^ vac_inw(VAC_SLSEL0_MASK)) + 1) >> 4,
+		       (decode & VAC_DECODE_QFY_SLSEL0) ? "qualified" : "");
+	else
+		printk("off\n");
+
+	printk("slave1 ");
+	if (decode & VAC_DECODE_RDR_SLSEL1)
+		printk("at %08lx (%d MB)\t[%s%s, %s]\n",
+		       ((unsigned long)vac_inw(VAC_SLSEL1_BASE))<<16,
+		       ((0xffff ^ vac_inw(VAC_SLSEL1_MASK)) + 1) >> 4,
+		       decode_mode[VAC_DECODE_MODE_VAL(decode)],
+		       address_mode[VAC_DECODE_CMP_SLSEL1_VAL(decode)],
+		       (decode & VAC_DECODE_QFY_SLSEL1) ? "qualified" : "");
+	else
+		printk("off\n");
+
+	printk("icf global at %04x, module at %04x [%s]\n",
+		       ((unsigned int)
+			VAC_ICFSEL_GLOBAL_VAL(vac_inw(VAC_ICFSEL_BASE)))<<4,
+		       ((unsigned int)
+			VAC_ICFSEL_MODULE_VAL(vac_inw(VAC_ICFSEL_BASE)))<<4,
+		       (decode & VAC_DECODE_QFY_ICFSEL) ? "qualified" : "");
+
+	
+	printk("region0 at 00000000 (%dMB)\t[dram, %s, delay %d cpuclk"
+	       ", cached]\n",
+	       (vac_inw(VAC_DRAM_MASK)+1)>>4,
+	       (decode & VAC_DECODE_DSACK) ? "D32" : "3state",
+	       VAC_DECODE_CPUCLK_VAL(decode));
+	
+	for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) {
+		unsigned long from = 
+			((unsigned long)vac_inw(bndr[i]))<<16;
+		unsigned long to   = 
+			((unsigned long)
+			 ((i+1 == sizeof(bndr)/sizeof(bndr[0])) ? 
+			  0xff00 : vac_inw(bndr[i+1])))<<16;
+		
+		
+		val = vac_inw(regs[i]);
+		printk("region%d at %08lx (%dMB)\t[%s %s/%s, %s]\n", 
+		       i+1,
+		       from,
+		       (unsigned int)((to - from) >> 20),
+		       region_mode[VAC_REG_MODE(val)],
+		       asiz[VAC_REG_ASIZ_VAL(val)],
+		       ((val & VAC_REG_WORD) ?  "D16" : "D32"),
+		       CACHEABLE_STR(val&VAC_A24_A24_CACHINH));
+		
+		if (a24_addr >= from && a24_addr < to)
+			printk("\ta24 at %08lx (%dMB)\t[vme, A24/%s, %s]\n",
+			       a24_addr,
+			       MIN((unsigned int)(a24_addr - from)>>20, 32),
+			       (a24_base & VAC_A24_DATAPATH) ?  "user" :
+			       ((a24_base & VAC_A24_D32_ENABLE)  ?  
+				"D32" : "D16"),
+			       CACHEABLE_STR(a24_base & VAC_A24_A24_CACHINH));
+	}
+
+	printk("region4 at ff000000 (15MB)\t[eprom]\n");
+	val = vac_inw(VAC_EPROMCS_CTRL);
+	printk("\t[ack %d cpuclk%s, %s%srecovery %d cpuclk, "
+	       "read %d%s, write %d%s, assert %d%s]\n",
+	       VAC_CTRL_DELAY_DSACKI_VAL(val),
+	       state[val & (VAC_CTRL_IORD|VAC_CTRL_IOWR)],
+	       (val & VAC_CTRL_DSACK0) ? "dsack0*, " : "",
+	       (val & VAC_CTRL_DSACK1) ? "dsack1*, " : "",
+	       VAC_CTRL_RECOVERY_IOSELI_VAL(val),
+	       VAC_CTRL_DELAY_IORD_VAL(val)/2,
+	       (VAC_CTRL_DELAY_IORD_VAL(val)&1) ? ".5" : "",
+	       VAC_CTRL_DELAY_IOWR_VAL(val)/2,
+	       (VAC_CTRL_DELAY_IOWR_VAL(val)&1) ? ".5" : "",
+	       VAC_CTRL_DELAY_IOSELI_VAL(val)/2,
+	       (VAC_CTRL_DELAY_IOSELI_VAL(val)&1) ? ".5" : "");
+	
+	printk("region5 at fff00000 (896KB)\t[local io, %s]\n",
+	       CACHEABLE_STR(vac_inw(VAC_A24_BASE) & VAC_A24_IO_CACHINH));
+
+	for (i = 0; i < sizeof(io_sels)/sizeof(io_sels[0]); i++) {
+		val = vac_inw(io_sels[i]);
+		printk("\tio%d[ack %d cpuclk%s, %s%srecovery %d cpuclk, "
+		       "\n\t read %d%s cpuclk, write %d%s cpuclk, "
+		       "assert %d%s%s cpuclk]\n",
+		       i, 
+		       VAC_CTRL_DELAY_DSACKI_VAL(val),
+		       state[val & (VAC_CTRL_IORD|VAC_CTRL_IOWR)],
+		       (val & VAC_CTRL_DSACK0) ? "dsack0*, " : "",
+		       (val & VAC_CTRL_DSACK1) ? "dsack1*, " : "",
+		       VAC_CTRL_RECOVERY_IOSELI_VAL(val),
+		       VAC_CTRL_DELAY_IORD_VAL(val)/2,
+		       (VAC_CTRL_DELAY_IORD_VAL(val)&1) ? ".5" : "",
+		       VAC_CTRL_DELAY_IOWR_VAL(val)/2,
+		       (VAC_CTRL_DELAY_IOWR_VAL(val)&1) ? ".5" : "",
+		       VAC_CTRL_DELAY_IOSELI_VAL(val)/2,
+		       (VAC_CTRL_DELAY_IOSELI_VAL(val)&1) ? ".5" : "",
+		       (vac_inw(VAC_DEV_LOC) & VAC_DEV_LOC_IOSEL(i)) ? 
+		          ", id" : "");
+	}
+		
+	printk("region6 at fffe0000 (128KB)\t[vme, A16/%s, "
+	       "not cached]\n",
+	       (a24_base & VAC_A24_A16D32_ENABLE) ? 
+	       ((a24_base & VAC_A24_A16D32) ? "D32" : "D16") : "user");
+		       
+	val = vac_inw(VAC_SHRCS_CTRL);
+	printk("shared[ack %d cpuclk%s, %s%srecovery %d cpuclk, "
+	       "read %d%s, write %d%s, assert %d%s]\n",
+	       VAC_CTRL_DELAY_DSACKI_VAL(val),
+	       state[val & (VAC_CTRL_IORD|VAC_CTRL_IOWR)],
+	       (val & VAC_CTRL_DSACK0) ? "dsack0*, " : "",
+	       (val & VAC_CTRL_DSACK1) ? "dsack1*, " : "",
+	       VAC_CTRL_RECOVERY_IOSELI_VAL(val),
+	       VAC_CTRL_DELAY_IORD_VAL(val)/2,
+	       (VAC_CTRL_DELAY_IORD_VAL(val)&1) ? ".5" : "",
+	       VAC_CTRL_DELAY_IOWR_VAL(val)/2,
+	       (VAC_CTRL_DELAY_IOWR_VAL(val)&1) ? ".5" : "",
+	       VAC_CTRL_DELAY_IOSELI_VAL(val)/2,
+	       (VAC_CTRL_DELAY_IOSELI_VAL(val)&1) ? ".5" : "");
+}
+
+__initfunc(static void vac_init(void))
+{
+	unsigned short mem_limit = ((mips_memory_upper-KSEG0) >> 16);
+
+	switch(vac_inw(VAC_ID)) {
+	case 0x1AC0:
+		printk("VAC068-F5: ");
+		break;
+	case 0x1AC1:
+		printk("VAC068A: ");
+		break;
+	default:
+		panic("Unknown VAC revision number");
+	}
+	
+	vac_outw(mem_limit-1, VAC_DRAM_MASK); 
+	vac_outw(mem_limit, VAC_BNDR2);
+	vac_outw(mem_limit, VAC_BNDR3);
+	vac_outw(((BAGET_A24M_BASE>>16)&~VAC_A24_D32_ENABLE)|VAC_A24_DATAPATH,
+		 VAC_A24_BASE);
+	vac_outw(VAC_REG_INACTIVE|VAC_REG_ASIZ0,VAC_REG1);
+	vac_outw(VAC_REG_INACTIVE|VAC_REG_ASIZ0,VAC_REG2);
+	vac_outw(VAC_REG_MWB|VAC_REG_ASIZ1,VAC_REG3);
+	vac_outw(BAGET_A24S_BASE>>16,VAC_SLSEL0_BASE);
+	vac_outw(BAGET_A24S_MASK>>16,VAC_SLSEL0_MASK);
+	vac_outw(BAGET_A24S_BASE>>16,VAC_SLSEL1_BASE);
+	vac_outw(BAGET_A24S_MASK>>16,VAC_SLSEL1_MASK);
+	vac_outw(BAGET_GSW_BASE|BAGET_MSW_BASE(0),VAC_ICFSEL_BASE);
+	vac_outw(VAC_DECODE_FPUCS|
+		 VAC_DECODE_CPUCLK(3)|
+		 VAC_DECODE_RDR_SLSEL0|VAC_DECODE_RDR_SLSEL1|
+		 VAC_DECODE_DSACK|
+		 VAC_DECODE_QFY_BNDR|
+		 VAC_DECODE_QFY_ICFSEL|
+		 VAC_DECODE_QFY_SLSEL1|VAC_DECODE_QFY_SLSEL0|
+		 VAC_DECODE_CMP_SLSEL1_HI|
+		 VAC_DECODE_DRAMCS|
+		 VAC_DECODE_QFY_DRAMCS|
+		 VAC_DECODE_DSACKI,VAC_DECODE_CTRL);
+	vac_outw(VAC_PIO_FUNC_UART_A_TX|VAC_PIO_FUNC_UART_A_RX|
+		 VAC_PIO_FUNC_UART_B_TX|VAC_PIO_FUNC_UART_B_RX|
+		 VAC_PIO_FUNC_IOWR|
+		 VAC_PIO_FUNC_IOSEL3|
+		 VAC_PIO_FUNC_IRQ7|VAC_PIO_FUNC_IRQ10|VAC_PIO_FUNC_IRQ11|
+		 VAC_PIO_FUNC_IOSEL2|
+		 VAC_PIO_FUNC_FCIACK,VAC_PIO_FUNC);
+	vac_outw(VAC_PIO_DIR_FCIACK |
+		 VAC_PIO_DIR_OUT(0) |
+		 VAC_PIO_DIR_OUT(1) |
+		 VAC_PIO_DIR_OUT(2) |
+		 VAC_PIO_DIR_OUT(3) |
+		 VAC_PIO_DIR_IN(4)  |
+		 VAC_PIO_DIR_OUT(5) |
+		 VAC_PIO_DIR_OUT(6) |
+		 VAC_PIO_DIR_OUT(7) |
+		 VAC_PIO_DIR_OUT(8) |
+		 VAC_PIO_DIR_IN(9)  |
+		 VAC_PIO_DIR_OUT(10)|
+		 VAC_PIO_DIR_OUT(11)|
+		 VAC_PIO_DIR_OUT(12)|
+		 VAC_PIO_DIR_OUT(13),VAC_PIO_DIRECTION);
+	vac_outw(VAC_DEV_LOC_IOSEL(2),VAC_DEV_LOC);
+	vac_outw(VAC_CTRL_IOWR|
+		 VAC_CTRL_DELAY_IOWR(3)|
+		 VAC_CTRL_DELAY_IORD(3)|
+		 VAC_CTRL_RECOVERY_IOSELI(1)|
+		 VAC_CTRL_DELAY_DSACKI(8),VAC_SHRCS_CTRL);
+	vac_outw(VAC_CTRL_IOWR|
+		 VAC_CTRL_DELAY_IOWR(3)|
+		 VAC_CTRL_DELAY_IORD(3)|
+		 VAC_CTRL_RECOVERY_IOSELI(1)|
+		 VAC_CTRL_DSACK0|VAC_CTRL_DSACK1|
+		 VAC_CTRL_DELAY_DSACKI(8),VAC_EPROMCS_CTRL);
+	vac_outw(VAC_CTRL_IOWR|
+		 VAC_CTRL_DELAY_IOWR(3)|
+		 VAC_CTRL_DELAY_IORD(3)|
+		 VAC_CTRL_RECOVERY_IOSELI(2)|
+		 VAC_CTRL_DSACK0|VAC_CTRL_DSACK1|
+		 VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL0_CTRL);
+	vac_outw(VAC_CTRL_IOWR|
+		 VAC_CTRL_DELAY_IOWR(3)|
+		 VAC_CTRL_DELAY_IORD(3)|
+		 VAC_CTRL_RECOVERY_IOSELI(2)|
+		 VAC_CTRL_DSACK0|VAC_CTRL_DSACK1|
+		 VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL1_CTRL);
+	vac_outw(VAC_CTRL_IOWR|
+		 VAC_CTRL_DELAY_IOWR(3)|
+		 VAC_CTRL_DELAY_IORD(3)|
+		 VAC_CTRL_RECOVERY_IOSELI(2)|
+		 VAC_CTRL_DSACK0|VAC_CTRL_DSACK1|
+		 VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL2_CTRL);
+	vac_outw(VAC_CTRL_IOWR|
+		 VAC_CTRL_DELAY_IOWR(3)|
+		 VAC_CTRL_DELAY_IORD(3)|
+		 VAC_CTRL_RECOVERY_IOSELI(2)|
+		 VAC_CTRL_DSACK0|VAC_CTRL_DSACK1|
+		 VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL3_CTRL);
+	vac_outw(VAC_CTRL_IOWR|
+		 VAC_CTRL_DELAY_IOWR(3)|
+		 VAC_CTRL_DELAY_IORD(3)|
+		 VAC_CTRL_RECOVERY_IOSELI(2)|
+		 VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL4_CTRL);
+	vac_outw(VAC_CTRL_IOWR|
+		 VAC_CTRL_DELAY_IOWR(3)|
+		 VAC_CTRL_DELAY_IORD(3)|
+		 VAC_CTRL_RECOVERY_IOSELI(2)|
+		 VAC_CTRL_DELAY_DSACKI(8),VAC_IOSEL5_CTRL);
+
+        vac_show();
+}
+
+__initfunc(static void vac_start(void))
+{
+	vac_outw(0, VAC_ID);
+	vac_outw(VAC_INT_CTRL_TIMER_DISABLE|
+		 VAC_INT_CTRL_UART_B_DISABLE|
+		 VAC_INT_CTRL_UART_A_DISABLE|
+		 VAC_INT_CTRL_MBOX_DISABLE|
+		 VAC_INT_CTRL_PIO4_DISABLE|
+		 VAC_INT_CTRL_PIO7_DISABLE|
+		 VAC_INT_CTRL_PIO8_DISABLE|
+		 VAC_INT_CTRL_PIO9_DISABLE,VAC_INT_CTRL);
+	vac_outw(VAC_INT_CTRL_TIMER_PIO10|
+		 VAC_INT_CTRL_UART_B_PIO7|
+		 VAC_INT_CTRL_UART_A_PIO7,VAC_INT_CTRL);
+	/* 
+	 *  Set quadro speed for both UARTs.
+	 *  To do it we need use formulae from VIC/VAC manual,
+	 *  keeping in mind Baget's 50MHz frequency...
+	 */
+	vac_outw((500000/(384*16))<<8,VAC_CPU_CLK_DIV); 
+}
+
+__initfunc(static void vic_show(void))
+{
+	unsigned char val;
+	char *timeout[]  = { "4", "16", "32", "64", "128", "256", "disabled" };
+	char *deadlock[] = { "[dedlk only]", "[dedlk only]", 
+			     "[dedlk], [halt w/ rmc], [lberr]",
+			     "[dedlk], [halt w/o rmc], [lberr]" };
+
+	val = vic_inb(VIC_IFACE_CFG);
+	if (val & VIC_IFACE_CFG_VME)
+		printk("VMEbus controller ");
+	if (val & VIC_IFACE_CFG_TURBO)
+		printk("turbo ");
+	if (val & VIC_IFACE_CFG_MSTAB)
+		printk("metastability delay ");
+	printk("%s ",
+	       deadlock[VIC_IFACE_CFG_DEADLOCK_VAL(val)]);
+	
+
+	printk("interrupts: ");
+	val = vic_inb(VIC_ERR_INT);
+	if (!(val & VIC_ERR_INT_SYSFAIL))
+		printk("[sysfail]");
+	if (!(val & VIC_ERR_INT_TIMO))
+		printk("[timeout]");
+	if (!(val & VIC_ERR_INT_WRPOST))
+		printk("[write post]");
+	if (!(val & VIC_ERR_INT_ACFAIL))
+		printk("[acfail] ");
+	printk("\n");
+	
+	printk("timeouts: ");
+	val = vic_inb(VIC_XFER_TIMO);
+	printk("local %s, vme %s ",
+	       timeout[VIC_XFER_TIMO_LOCAL_PERIOD_VAL(val)],
+	       timeout[VIC_XFER_TIMO_VME_PERIOD_VAL(val)]);
+	if (val & VIC_XFER_TIMO_VME)
+		printk("acquisition ");
+	if (val & VIC_XFER_TIMO_ARB)
+		printk("arbitration ");
+	printk("\n");
+
+	val = vic_inb(VIC_LOCAL_TIM);
+	printk("pas time: (%d,%d), ds time: %d\n",
+	       VIC_LOCAL_TIM_PAS_ASSERT_VAL(val),
+	       VIC_LOCAL_TIM_PAS_DEASSERT_VAL(val),
+	       VIC_LOCAT_TIM_DS_DEASSERT_VAL(val));
+
+	val = vic_inb(VIC_BXFER_DEF);
+	printk("dma: ");
+	if (val & VIC_BXFER_DEF_DUAL)
+		printk("[dual path]");
+	if (val & VIC_BXFER_DEF_LOCAL_CROSS)
+		printk("[local boundary cross]");
+	if (val & VIC_BXFER_DEF_VME_CROSS)
+		printk("[vme boundary cross]");
+	
+}
+
+__initfunc(static void vic_init(void))
+{
+	 unsigned char id = vic_inb(VIC_ID);
+	 if ((id & 0xf0) != 0xf0)
+		 panic("VIC not found");
+	 printk(" VIC068A Rev. %X: ", id & 0x0f);
+
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_II);
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_INT1);
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_INT2);
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_INT3);
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE,VIC_VME_INT4);
+/*	 
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE, VIC_VME_INT5);
+*/
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE, VIC_VME_INT6);
+
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE, VIC_VME_INT7);
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_DISABLE, VIC_DMA_INT);
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_EDGE|
+		  VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT1);
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_EDGE|
+		  VIC_INT_HIGH|VIC_INT_DISABLE, VIC_LINT2);
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_EDGE|
+		  VIC_INT_HIGH|VIC_INT_DISABLE, VIC_LINT3);
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_EDGE|
+		  VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT4);
+/*	 
+	 vic_outb(VIC_INT_IPL(3)|VIC_INT_NOAUTO|VIC_INT_LEVEL|
+		  VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT5);
+*/
+	 vic_outb(VIC_INT_IPL(6)|VIC_INT_NOAUTO|VIC_INT_EDGE|
+		  VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT6);
+	 vic_outb(VIC_INT_IPL(6)|VIC_INT_NOAUTO|VIC_INT_EDGE|
+		  VIC_INT_LOW|VIC_INT_DISABLE, VIC_LINT7);
+
+	 vic_outb(VIC_INT_IPL(3)|
+		  VIC_INT_SWITCH(0)|
+		  VIC_INT_SWITCH(1)|
+		  VIC_INT_SWITCH(2)|
+		  VIC_INT_SWITCH(3), VIC_ICGS_INT);
+	 vic_outb(VIC_INT_IPL(3)|
+		  VIC_INT_SWITCH(0)|
+		  VIC_INT_SWITCH(1)|
+		  VIC_INT_SWITCH(2)|
+		  VIC_INT_SWITCH(3), VIC_ICMS_INT);
+	 vic_outb(VIC_INT_IPL(6)|
+		  VIC_ERR_INT_SYSFAIL|
+		  VIC_ERR_INT_TIMO|
+		  VIC_ERR_INT_WRPOST|
+		  VIC_ERR_INT_ACFAIL, VIC_ERR_INT);
+	 vic_outb(VIC_ICxS_BASE_ID(0xf), VIC_ICGS_BASE);
+	 vic_outb(VIC_ICxS_BASE_ID(0xe), VIC_ICMS_BASE);
+	 vic_outb(VIC_LOCAL_BASE_ID(0x6), VIC_LOCAL_BASE);
+	 vic_outb(VIC_ERR_BASE_ID(0x3), VIC_ERR_BASE);
+	 vic_outb(VIC_XFER_TIMO_VME_PERIOD_32|
+		  VIC_XFER_TIMO_LOCAL_PERIOD_32, VIC_XFER_TIMO);
+	 vic_outb(VIC_LOCAL_TIM_PAS_ASSERT(2)|
+		  VIC_LOCAT_TIM_DS_DEASSERT(1)|
+		  VIC_LOCAL_TIM_PAS_DEASSERT(1), VIC_LOCAL_TIM);
+	 vic_outb(VIC_BXFER_DEF_VME_CROSS|
+		  VIC_BXFER_DEF_LOCAL_CROSS|
+		  VIC_BXFER_DEF_AMSR|
+		  VIC_BXFER_DEF_DUAL, VIC_BXFER_DEF);
+	 vic_outb(VIC_SSxCR0_LOCAL_XFER_SINGLE|
+		  VIC_SSxCR0_A32|VIC_SSxCR0_D32|
+		  VIC_SS0CR0_TIMER_FREQ_NONE, VIC_SS0CR0);
+	 vic_outb(VIC_SSxCR1_TF1(0xf)|
+		  VIC_SSxCR1_TF2(0xf), VIC_SS0CR1);
+	 vic_outb(VIC_SSxCR0_LOCAL_XFER_SINGLE|
+		  VIC_SSxCR0_A24|VIC_SSxCR0_D32, VIC_SS1CR0);
+	 vic_outb(VIC_SSxCR1_TF1(0xf)|
+		  VIC_SSxCR1_TF2(0xf), VIC_SS1CR1);
+         vic_outb(VIC_IFACE_CFG_NOHALT|
+		  VIC_IFACE_CFG_NOTURBO, VIC_IFACE_CFG);
+	 vic_outb(VIC_AMS_CODE(0), VIC_AMS);
+	 vic_outb(VIC_BXFER_CTRL_INTERLEAVE(0), VIC_BXFER_CTRL);
+	 vic_outb(0, VIC_BXFER_LEN_LO);
+	 vic_outb(0, VIC_BXFER_LEN_HI);
+	 vic_outb(VIC_REQ_CFG_FAIRNESS_DISABLED|
+		  VIC_REQ_CFG_LEVEL(3)|
+		  VIC_REQ_CFG_RR_ARBITRATION, VIC_REQ_CFG);
+	 vic_outb(VIC_RELEASE_BLKXFER_BLEN(0)|
+		  VIC_RELEASE_RWD, VIC_RELEASE);
+	 vic_outb(VIC_IC6_RUN, VIC_IC6);
+	 vic_outb(0, VIC_IC7);
+	 
+	 vic_show();
+}
+
+static void vic_start(void)
+{
+	vic_outb(VIC_INT_IPL(3)|
+		 VIC_INT_NOAUTO|
+		 VIC_INT_EDGE|
+		 VIC_INT_HIGH|
+		 VIC_INT_ENABLE, VIC_LINT7);
+}
+
+__initfunc(void baget_irq_setup(void))
+{
+	extern void bagetIRQ(void);
+
+        /* Now, it's safe to set the exception vector. */
+	set_except_vector(0, bagetIRQ);
+}
+
+extern void baget_machine_restart(char *command);
+extern void baget_machine_halt(void);
+extern void baget_machine_power_off(void);
+ 
+__initfunc(void baget_setup(void))
+{
+	printk("BT23/63-201n found.\n");
+	*BAGET_WRERR_ACK = 0;
+	irq_setup = baget_irq_setup;
+
+	wbflush_setup();
+
+        _machine_restart   = baget_machine_restart;
+        _machine_halt      = baget_machine_halt;
+        _machine_power_off = baget_machine_power_off;
+
+	vac_init();
+	vic_init();
+	vac_start();
+	vic_start();
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/time.c linux/arch/mips/baget/time.c
--- v2.3.8/linux/arch/mips/baget/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/time.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,96 @@
+/* $Id$
+ * time.c: Baget/MIPS specific time handling details
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>  
+
+#include <asm/baget/baget.h>
+
+/* 
+ *  To have precision clock, we need to fix available clock frequency
+ */
+#define FREQ_NOM  79125  /* Baget frequency ratio */
+#define FREQ_DEN  10000
+static inline int timer_intr_valid(void) 
+{
+	static unsigned long long ticks, valid_ticks;
+
+	if (ticks++ * FREQ_DEN >= valid_ticks * FREQ_NOM) {
+		/* 
+		 *  We need no overflow checks, 
+		 *  due baget unable to work 3000 years...
+		 *  At least without reboot...
+		 */
+		valid_ticks++;
+		return 1;
+	}
+	return 0;
+}
+
+void static timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	if (timer_intr_valid()) {
+	sti();
+	do_timer(regs);
+	}
+}
+
+__initfunc(static void timer_enable(void))
+{
+	unsigned char ss0cr0 = vic_inb(VIC_SS0CR0);
+	ss0cr0 &= ~VIC_SS0CR0_TIMER_FREQ_MASK;
+	ss0cr0 |= VIC_SS0CR0_TIMER_FREQ_1000HZ;
+	vic_outb(ss0cr0, VIC_SS0CR0);
+
+	vic_outb(VIC_INT_IPL(6)|VIC_INT_NOAUTO|VIC_INT_EDGE|
+		 VIC_INT_LOW|VIC_INT_ENABLE, VIC_LINT2); 
+}
+
+__initfunc(void time_init(void))
+{
+	if (request_irq(BAGET_VIC_TIMER_IRQ, timer_interrupt, 
+			SA_INTERRUPT|SA_STATIC_ALLOC, "timer", NULL) < 0) 
+		printk("time_init: unable request irq for system timer\n");
+
+	timer_enable();
+
+	/* We don't call sti() here, because it is too early for baget */
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+        unsigned long flags;
+
+        save_and_cli(flags);
+        *tv = xtime;
+        restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+        unsigned long flags;
+  
+        save_and_cli(flags);
+        xtime = *tv;
+        time_state = TIME_BAD;
+        time_maxerror = MAXPHASE;
+        time_esterror = MAXPHASE;
+        restore_flags(flags);
+} 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/vacserial.c linux/arch/mips/baget/vacserial.c
--- v2.3.8/linux/arch/mips/baget/vacserial.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/vacserial.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,2943 @@
+/* $Id$
+ * vacserial.c: VAC UART serial driver
+ *              This code stealed and adopted from linux/drivers/char/serial.c
+ *              See that for author info
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+
+#undef  SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+#define CONFIG_SERIAL_SHARE_IRQ
+
+/* Set of debugging defines */
+
+#undef  SERIAL_DEBUG_INTR
+#undef  SERIAL_DEBUG_OPEN
+#undef  SERIAL_DEBUG_FLOW
+#undef  SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+
+#define RS_STROBE_TIME (10*HZ)
+#define RS_ISR_PASS_LIMIT  2 /* Beget is not a super-computer (old=256) */
+
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+
+#define SERIAL_INLINE
+  
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) baget_printk("(%s):[%x] refc=%d, serc=%d, ttyc=%d-> %s\n", \
+  kdevname(tty->device),(info->flags),serial_refcount,info->count,tty->count,s)
+#else
+#define DBG_CNT(s)
+#endif
+
+#define  QUAD_UART_SPEED  /* Useful for Baget */
+
+/*
+ * End of serial driver configuration section.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/serial.h>
+#include <asm/baget/baget.h>
+
+#define BAGET_VAC_UART_IRQ 0x35
+
+/*
+ *  Implementation note:
+ *  It was descovered by means of advanced electronic tools,
+ *  if the driver works via TX_READY interrupts then VIC generates
+ *  strange self-eliminating traps. Thus, the driver is rewritten to work
+ *  via TX_EMPTY
+ */
+
+/* VAC-specific check/debug switches */
+
+#undef CHECK_REG_INDEX
+#undef DEBUG_IO_PORT_A
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+	
+static char *serial_name = "VAC Serial driver";
+static char *serial_version = "4.26";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+ 
+/*
+ * IRQ_timeout		- How long the timeout should be for each IRQ
+ * 				should be after the IRQ has been active.
+ */
+
+static struct async_struct *IRQ_ports[NR_IRQS];
+static int IRQ_timeout[NR_IRQS];
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+#endif
+
+static void autoconfig(struct serial_state * info);
+static void change_speed(struct async_struct *info);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+
+/*
+ * Here we define the default xmit fifo size used for each type of
+ * UART
+ */
+static struct serial_uart_config uart_config[] = {
+        { "unknown",  1, 0 },  /* Must go first  --  used as unasigned */
+        { "VAC UART", 1, 0 }
+}; 
+#define VAC_UART_TYPE 1   /* Just index in above array */
+
+static struct serial_state rs_table[] = {
+/*
+ * VAC has tricky layout for pair of his SIO registers,
+ *  so we need special function to access ones.
+ *  To identify port we use their TX offset
+ */
+        { 0, 9600, VAC_UART_B_TX, BAGET_VAC_UART_IRQ, 
+          STD_COM_FLAGS }, /* VAC UART B */
+        { 0, 9600, VAC_UART_A_TX, BAGET_VAC_UART_IRQ, 
+          STD_COM_FLAGS }  /* VAC UART A */
+};
+
+#define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct async_struct *info,
+					kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null async_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+  To unify UART A/B access we will use following function 
+  to compute register offsets by register index.
+ */
+
+#define VAC_UART_MODE       0
+#define VAC_UART_TX         1
+#define VAC_UART_RX         2
+#define VAC_UART_INT_MASK   3
+#define VAC_UART_INT_STATUS 4
+
+#define VAC_UART_REG_NR     5
+
+static inline int uart_offset_map(unsigned long port, int reg_index) 
+{
+	static const unsigned int ind_to_reg[VAC_UART_REG_NR][NR_PORTS] = {
+		{ VAC_UART_B_MODE,       VAC_UART_A_MODE       },
+		{ VAC_UART_B_TX,         VAC_UART_A_TX         },
+		{ VAC_UART_B_RX,         VAC_UART_A_RX         },
+		{ VAC_UART_B_INT_MASK,   VAC_UART_A_INT_MASK   },
+		{ VAC_UART_B_INT_STATUS, VAC_UART_A_INT_STATUS }
+	};
+#ifdef CHECK_REG_INDEX
+	if (reg_index > VAC_UART_REG_NR) panic("vacserial: bad reg_index");
+#endif
+        return ind_to_reg[reg_index][port == VAC_UART_B_TX ? 0 : 1];
+}
+
+static inline unsigned int serial_inw(struct async_struct *info, int offset)
+{
+	int val = vac_inw(uart_offset_map(info->port,offset));
+#ifdef DEBUG_IO_PORT_A
+	if (info->port == VAC_UART_A_TX)
+		printk("UART_A_IN: reg = 0x%04x, val = 0x%04x\n", 
+		       uart_offset_map(info->port,offset), val);
+#endif
+	return val;
+}
+
+static inline unsigned int serial_inp(struct async_struct *info, int offset)
+{
+	return serial_inw(info, offset);
+}
+
+static inline unsigned int serial_in(struct async_struct *info, int offset)
+{
+	return serial_inw(info, offset);
+}
+
+static inline void serial_outw(struct async_struct *info,int offset, int value)
+{
+#ifdef DEBUG_IO_PORT_A
+	if (info->port == VAC_UART_A_TX)
+		printk("UART_A_OUT: offset = 0x%04x, val = 0x%04x\n", 
+		       uart_offset_map(info->port,offset), value);
+#endif
+	vac_outw(value, uart_offset_map(info->port,offset));
+}
+
+static inline void serial_outp(struct async_struct *info,int offset, int value)
+{
+	serial_outw(info,offset,value);
+}
+
+static inline void serial_out(struct async_struct *info,int offset, int value)
+{
+	serial_outw(info,offset,value);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	save_flags(flags); cli();
+        if (info->IER & VAC_UART_INT_TX_EMPTY) {
+                info->IER &= ~VAC_UART_INT_TX_EMPTY;
+		serial_out(info, VAC_UART_INT_MASK, info->IER);
+	}
+	restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_start"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->xmit_cnt && info->xmit_buf 
+            && !(info->IER & VAC_UART_INT_TX_EMPTY)) {
+                info->IER |= VAC_UART_INT_TX_EMPTY;
+		serial_out(info, VAC_UART_INT_MASK, info->IER);
+	}
+	restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct async_struct *info,
+				  int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_serial);
+	mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(struct async_struct *info,
+				   int *status)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned short rx;
+	unsigned char ch;
+	int ignored = 0;
+	struct	async_icount *icount;
+
+	icount = &info->state->icount;
+	do {
+		rx = serial_inw(info, VAC_UART_RX);
+		ch = VAC_UART_RX_DATA_MASK & rx;
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			break;
+		*tty->flip.char_buf_ptr = ch;
+		icount->rx++;
+		
+#ifdef SERIAL_DEBUG_INTR
+		baget_printk("DR%02x:%02x...", rx, *status);
+#endif
+		*tty->flip.flag_buf_ptr = 0;
+		if (*status & (VAC_UART_STATUS_RX_BREAK_CHANGE 
+			       | VAC_UART_STATUS_RX_ERR_PARITY 
+			       | VAC_UART_STATUS_RX_ERR_FRAME 
+			       | VAC_UART_STATUS_RX_ERR_OVERRUN)) {
+			/*
+			 * For statistics only
+			 */
+			if (*status & VAC_UART_STATUS_RX_BREAK_CHANGE) {
+				*status &= ~(VAC_UART_STATUS_RX_ERR_FRAME 
+					     | VAC_UART_STATUS_RX_ERR_PARITY);
+				icount->brk++;
+			} else if (*status & VAC_UART_STATUS_RX_ERR_PARITY)
+				icount->parity++;
+			else if (*status & VAC_UART_STATUS_RX_ERR_FRAME)
+				icount->frame++;
+			if (*status & VAC_UART_STATUS_RX_ERR_OVERRUN)
+				icount->overrun++;
+
+			/*
+			 * Now check to see if character should be
+			 * ignored, and mask off conditions which
+			 * should be ignored.
+			 */
+			if (*status & info->ignore_status_mask) {
+				if (++ignored > 100)
+					break;
+				goto ignore_char;
+			}
+			*status &= info->read_status_mask;
+		
+			if (*status & (VAC_UART_STATUS_RX_BREAK_CHANGE)) {
+#ifdef SERIAL_DEBUG_INTR
+				baget_printk("handling break....");
+#endif
+				*tty->flip.flag_buf_ptr = TTY_BREAK;
+				if (info->flags & ASYNC_SAK)
+					do_SAK(tty);
+			} else if (*status & VAC_UART_STATUS_RX_ERR_PARITY)
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+			else if (*status & VAC_UART_STATUS_RX_ERR_FRAME)
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+			if (*status & VAC_UART_STATUS_RX_ERR_OVERRUN) {
+				/*
+				 * Overrun is special, since it's
+				 * reported immediately, and doesn't
+				 * affect the current character
+				 */
+				if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+					tty->flip.count++;
+					tty->flip.flag_buf_ptr++;
+					tty->flip.char_buf_ptr++;
+					*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+				}
+			}
+		}
+		tty->flip.flag_buf_ptr++;
+		tty->flip.char_buf_ptr++;
+		tty->flip.count++;
+	ignore_char:
+		*status = serial_inw(info, VAC_UART_INT_STATUS);
+	} while ((*status & VAC_UART_STATUS_RX_READY));
+	tty_flip_buffer_push(tty);
+}
+
+static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
+{
+	int count;
+	
+	if (info->x_char) {
+		serial_outw(info, VAC_UART_TX, 
+			    (((unsigned short)info->x_char)<<8));
+		info->state->icount.tx++;
+		info->x_char = 0;
+		if (intr_done)
+			*intr_done = 0;
+		return;
+	}
+	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+	    info->tty->hw_stopped) {
+                info->IER &= ~VAC_UART_INT_TX_EMPTY;
+		serial_outw(info, VAC_UART_INT_MASK, info->IER);
+		return;
+	}
+	count = info->xmit_fifo_size;
+	do {
+		serial_out(info, VAC_UART_TX, 
+			   (unsigned short)info->xmit_buf[info->xmit_tail++] \
+			   << 8);
+		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		info->state->icount.tx++;
+		if (--info->xmit_cnt <= 0)
+			break;
+	} while (--count > 0);
+	
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+#ifdef SERIAL_DEBUG_INTR
+	baget_printk("THRE...");
+#endif
+	if (intr_done)
+		*intr_done = 0;
+
+	if (info->xmit_cnt <= 0) {
+                info->IER &= ~VAC_UART_INT_TX_EMPTY;
+		serial_outw(info, VAC_UART_INT_MASK, info->IER);
+	}
+}
+
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+#if 0 /* VAC hasn't modem control */
+	wake_up_interruptible(&info->open_wait);
+	rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); 
+#endif
+}
+
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+
+
+/*
+ *  Specific functions needed for VAC UART interrupt enter/leave
+ */
+
+#define VAC_INT_CTRL_UART_ENABLE  \
+   (VAC_INT_CTRL_TIMER_PIO10|VAC_INT_CTRL_UART_B_PIO7|VAC_INT_CTRL_UART_A_PIO7)
+
+#define VAC_INT_CTRL_UART_DISABLE(info) \
+   (VAC_INT_CTRL_TIMER_PIO10 | \
+    ((info->port == VAC_UART_A_TX) ? \
+     (VAC_INT_CTRL_UART_A_DISABLE|VAC_INT_CTRL_UART_B_PIO7) : \
+     (VAC_INT_CTRL_UART_A_PIO7|VAC_INT_CTRL_UART_B_DISABLE)))
+
+/*
+ *  Following two functions were proposed by Pavel Osipenko 
+ *  to make VAC/VIC behaviour more regular.
+ */
+static void intr_begin(struct async_struct* info) 
+{
+	serial_outw(info, VAC_UART_INT_MASK, 0);
+}
+
+static void intr_end(struct async_struct* info)
+{
+	vac_outw(VAC_INT_CTRL_UART_DISABLE(info), VAC_INT_CTRL);
+	vac_outw(VAC_INT_CTRL_UART_ENABLE,        VAC_INT_CTRL); 
+
+	serial_outw(info, VAC_UART_INT_MASK, info->IER);
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	int status;
+	struct async_struct * info;
+	int pass_counter = 0;
+	struct async_struct *end_mark = 0;
+
+#ifdef SERIAL_DEBUG_INTR
+	baget_printk("rs_interrupt(%d)...", irq);
+#endif
+
+	info = IRQ_ports[irq];
+	if (!info)
+		return;
+
+	do {
+	        intr_begin(info);  /* Mark we begin port handling */
+
+		if (!info->tty ||
+		     (serial_inw (info, VAC_UART_INT_STATUS) 
+		      & VAC_UART_STATUS_INTS) == 0) 
+		    {
+			if (!end_mark)
+				end_mark = info;
+			goto next;
+		    }
+		end_mark = 0;
+
+		info->last_active = jiffies;
+
+		status = serial_inw(info, VAC_UART_INT_STATUS);
+#ifdef SERIAL_DEBUG_INTR
+		baget_printk("status = %x...", status);
+#endif
+		if (status & VAC_UART_STATUS_RX_READY) {
+			receive_chars(info, &status);
+		}
+		check_modem_status(info);
+                if (status & VAC_UART_STATUS_TX_EMPTY)
+			transmit_chars(info, 0);
+
+	next:
+		intr_end(info);   /* Mark this port handled */
+
+		info = info->next_port;
+		if (!info) {
+			info = IRQ_ports[irq];
+			if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+				break; 	/* Prevent infinite loops */
+			}
+			continue;
+		}
+	} while (end_mark != info);
+#ifdef SERIAL_DEBUG_INTR
+	baget_printk("end.\n");
+#endif
+
+
+}
+#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
+
+
+/* The original driver was simplified here: 
+   two functions were joined to reduce code */
+
+#define rs_interrupt_single rs_interrupt
+
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+	run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+	struct async_struct	*info = (struct async_struct *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+/*
+ * ---------------------------------------------------------------
+ * Low level utility subroutines for the serial driver:  routines to
+ * figure out the appropriate timeout for an interrupt chain, routines
+ * to initialize and startup a serial port, and routines to shutdown a
+ * serial port.  Useful stuff like that.
+ * ---------------------------------------------------------------
+ */
+
+/*
+ * This routine figures out the correct timeout for a particular IRQ.
+ * It uses the smallest timeout of all of the serial ports in a
+ * particular interrupt chain.  Now only used for IRQ 0....
+ */
+static void figure_IRQ_timeout(int irq)
+{
+	struct	async_struct	*info;
+	int	timeout = 60*HZ;	/* 60 seconds === a long time :-) */
+
+	info = IRQ_ports[irq];
+	if (!info) {
+		IRQ_timeout[irq] = 60*HZ;
+		return;
+	}
+	while (info) {
+		if (info->timeout < timeout)
+			timeout = info->timeout;
+		info = info->next_port;
+	}
+	if (!irq)
+		timeout = timeout / 2;
+	IRQ_timeout[irq] = timeout ? timeout : 1;
+}
+
+static int startup(struct async_struct * info)
+{
+	unsigned long flags;
+	int	retval=0;
+	void (*handler)(int, void *, struct pt_regs *);
+	struct serial_state *state= info->state;
+	unsigned long page;
+
+	page = get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	save_flags(flags); cli();
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		free_page(page);
+		goto errout;
+	}
+	if (!state->port || !state->type) {
+		if (info->tty)
+			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		free_page(page);
+		goto errout;
+	}
+	if (info->xmit_buf)
+		free_page(page);
+	else
+		info->xmit_buf = (unsigned char *) page;
+
+#ifdef SERIAL_DEBUG_OPEN
+	baget_printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+	if (uart_config[info->state->type].flags & UART_STARTECH) {
+		/* Wake up UART */
+		serial_outp(info, VAC_UART_MODE, 0);
+		serial_outp(info, VAC_UART_INT_MASK, 0);
+	}
+
+	/*
+	 * Allocate the IRQ if necessary
+	 */
+	if (state->irq && (!IRQ_ports[state->irq] ||
+			  !IRQ_ports[state->irq]->next_port)) {
+
+		if (IRQ_ports[state->irq]) {
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+			free_irq(state->irq, NULL);
+				handler = rs_interrupt;
+#else
+			retval = -EBUSY;
+			goto errout;
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+		} else 
+			handler = rs_interrupt_single;
+
+
+		retval = request_irq(state->irq, handler, IRQ_T(info),
+				     "serial", NULL);
+		if (retval) {
+			if (capable(CAP_SYS_ADMIN)) {
+				if (info->tty)
+					set_bit(TTY_IO_ERROR,
+						&info->tty->flags);
+				retval = 0;
+			}
+			goto errout;
+		}
+	}
+
+	/*
+	 * Insert serial port into IRQ chain.
+	 */
+	info->prev_port = 0;
+	info->next_port = IRQ_ports[state->irq];
+	if (info->next_port)
+		info->next_port->prev_port = info;
+	IRQ_ports[state->irq] = info;
+	figure_IRQ_timeout(state->irq);
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+     /* (void) serial_inw(info, VAC_UART_INT_STATUS); */   /* (see above) */
+	(void) serial_inw(info, VAC_UART_RX);
+
+	/*
+	 * Now, initialize the UART 
+	 */
+	serial_outp(info, VAC_UART_MODE, VAC_UART_MODE_INITIAL); /*reset DLAB*/
+
+	/*
+	 * Finally, enable interrupts
+	 */
+	info->IER = VAC_UART_INT_RX_BREAK_CHANGE | VAC_UART_INT_RX_ERRS | \
+                        VAC_UART_INT_RX_READY;
+	serial_outp(info, VAC_UART_INT_MASK, info->IER); /*enable interrupts*/
+	
+	/*
+	 * And clear the interrupt registers again for luck.
+	 */
+	(void)serial_inp(info, VAC_UART_INT_STATUS);
+	(void)serial_inp(info, VAC_UART_RX);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * Set up serial timers...
+	 */
+	timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
+	timer_active |= 1 << RS_TIMER;
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	change_speed(info);
+
+	info->flags |= ASYNC_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+	
+errout:
+	restore_flags(flags);
+	return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct async_struct * info)
+{
+	unsigned long	flags;
+	struct serial_state *state;
+	int		retval;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+	baget_printk("Shutting down serial port %d (irq %d)....", info->line,
+	       state->irq);
+#endif
+	
+	save_flags(flags); cli(); /* Disable interrupts */
+
+	/*
+	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+	 * here so the queue might never be waken up
+	 */
+	wake_up_interruptible(&info->delta_msr_wait);
+	
+	/*
+	 * First unlink the serial port from the IRQ chain...
+	 */
+	if (info->next_port)
+		info->next_port->prev_port = info->prev_port;
+	if (info->prev_port)
+		info->prev_port->next_port = info->next_port;
+	else
+		IRQ_ports[state->irq] = info->next_port;
+	figure_IRQ_timeout(state->irq);
+	
+	/*
+	 * Free the IRQ, if necessary
+	 */
+	if (state->irq && (!IRQ_ports[state->irq] ||
+			  !IRQ_ports[state->irq]->next_port)) {
+		if (IRQ_ports[state->irq]) {
+			free_irq(state->irq, NULL);
+			retval = request_irq(state->irq, rs_interrupt_single,
+					     IRQ_T(info), "serial", NULL);
+			
+			if (retval)
+				printk("serial shutdown: request_irq: error %d"
+				       "  Couldn't reacquire IRQ.\n", retval);
+		} else
+			free_irq(state->irq, NULL);
+	}
+
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
+	}
+
+	info->IER = 0;
+	serial_outp(info, VAC_UART_INT_MASK, 0x00);	/* disable all intrs */
+	
+	/* disable break condition */
+	serial_out(info, VAC_UART_MODE, serial_inp(info, VAC_UART_MODE) & \
+		   ~VAC_UART_MODE_SEND_BREAK);
+	
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+	restore_flags(flags);
+}
+
+/*
+ *  When we set line mode, we call this function 
+ *  for Baget-specific adjustments.
+ */
+
+static inline unsigned short vac_uart_mode_fixup (unsigned short cval)
+{
+#ifdef QUAD_UART_SPEED
+	/* 
+	 *  When we are using 4-x advantage in speed:
+	 *
+	 *  Disadvantage : can't support 75, 150 bauds
+	 *  Advantage    : can support 19200, 38400 bauds
+	 */
+	char speed = 7 & (cval >> 10);
+	cval &= ~(7 << 10);
+	cval |= VAC_UART_MODE_BAUD(speed-2);
+#endif
+
+	/* 
+	 *  In general, we have Tx and Rx ON all time
+	 *  and use int mask flag for their disabling.
+	 */
+	cval |= VAC_UART_MODE_RX_ENABLE;
+	cval |= VAC_UART_MODE_TX_ENABLE;
+	cval |= VAC_UART_MODE_CHAR_RX_ENABLE;
+	cval |= VAC_UART_MODE_CHAR_TX_ENABLE;
+
+        /* Low 4 bits are not used in UART */	
+	cval &= ~0xf; 
+
+	return cval; 
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct async_struct *info)
+{
+	unsigned short port;
+	int	quot = 0, baud_base, baud;
+	unsigned cflag, cval;
+	int	bits;
+	unsigned long	flags;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!(port = info->port))
+		return;
+
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	      case CS7: cval = 0x0;  bits = 9; break;
+	      case CS8: cval = VAC_UART_MODE_8BIT_CHAR; bits = 10; break;
+	      /* Never happens, but GCC is too dumb to figure it out */
+	      case CS5: 
+	      case CS6: 
+	      default:  cval = 0x0; bits = 9; break;
+	      }
+	cval &= ~VAC_UART_MODE_PARITY_ENABLE;
+	if (cflag & PARENB) {
+		cval |= VAC_UART_MODE_PARITY_ENABLE;
+		bits++;
+	}
+	if (cflag & PARODD)
+		cval |= VAC_UART_MODE_PARITY_ODD;
+
+	/* Determine divisor based on baud rate */
+	baud = tty_get_baud_rate(info->tty);
+	baud_base = info->state->baud_base;
+	if (baud == 38400 &&
+	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+		quot = info->state->custom_divisor;
+	else {
+		if (baud == 134)
+			/* Special case since 134 is really 134.5 */
+			quot = (2*baud_base / 269);
+		else if (baud)
+			quot = baud_base / baud;
+	}
+	/* If the quotient is ever zero, default to 9600 bps */
+	if (!quot)
+		quot = baud_base / 9600;
+	info->quot = quot;
+	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+
+	serial_out(info, VAC_UART_INT_MASK, info->IER);
+
+	/*
+	 * Set up parity check flag
+	 */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+	info->read_status_mask = VAC_UART_STATUS_RX_ERR_OVERRUN | \
+                VAC_UART_STATUS_TX_EMPTY | VAC_UART_STATUS_RX_READY;
+	if (I_INPCK(info->tty))
+		info->read_status_mask |= VAC_UART_STATUS_RX_ERR_FRAME | \
+			VAC_UART_STATUS_RX_ERR_PARITY;
+	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+		info->read_status_mask |= VAC_UART_STATUS_RX_BREAK_CHANGE;
+	
+	/*
+	 * Characters to ignore
+	 */
+	info->ignore_status_mask = 0;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask |= VAC_UART_STATUS_RX_ERR_PARITY | \
+			VAC_UART_STATUS_RX_ERR_FRAME;
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask |= VAC_UART_STATUS_RX_BREAK_CHANGE;
+		/*
+		 * If we're ignore parity and break indicators, ignore 
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask |= \
+				VAC_UART_STATUS_RX_ERR_OVERRUN;
+	}
+	/*
+	 * !!! ignore all characters if CREAD is not set
+	 */
+	if ((cflag & CREAD) == 0)
+		info->ignore_status_mask |= VAC_UART_STATUS_RX_READY;
+	save_flags(flags); cli();
+
+
+	switch (baud) {
+	default:
+	case 9600:
+		cval |= VAC_UART_MODE_BAUD(7);
+		break;
+	case 4800:
+		cval |= VAC_UART_MODE_BAUD(6);
+		break;
+	case 2400:
+		cval |= VAC_UART_MODE_BAUD(5);
+		break;
+	case 1200:
+		cval |= VAC_UART_MODE_BAUD(4);
+		break;
+	case 600:
+		cval |= VAC_UART_MODE_BAUD(3);
+		break;
+	case 300:
+		cval |= VAC_UART_MODE_BAUD(2);
+		break;
+#ifndef QUAD_UART_SPEED
+	case 150:
+#else
+	case 38400:
+#endif
+		cval |= VAC_UART_MODE_BAUD(1);
+		break;
+#ifndef QUAD_UART_SPEED
+	case 75:
+#else
+	case 19200:
+#endif
+		cval |= VAC_UART_MODE_BAUD(0);
+		break;
+	}
+
+	/* Baget VAC need some adjustments for computed value */
+	cval = vac_uart_mode_fixup(cval);
+
+	serial_outp(info, VAC_UART_MODE, cval);
+	restore_flags(flags);
+}
+
+static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+		return;
+
+	if (!tty || !info->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+		restore_flags(flags);
+		return;
+	}
+
+	info->xmit_buf[info->xmit_head++] = ch;
+	info->xmit_head &= SERIAL_XMIT_SIZE-1;
+	info->xmit_cnt++;
+	restore_flags(flags);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	save_flags(flags); cli();
+        info->IER |= VAC_UART_INT_TX_EMPTY;
+	serial_out(info, VAC_UART_INT_MASK, info->IER);
+	restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, ret = 0;
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+		
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty || !info->xmit_buf || !tmp_buf)
+		return 0;
+
+	save_flags(flags);
+	if (from_user) {
+		down(&tmp_buf_sem);
+		while (1) {
+			c = MIN(count,
+				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				    SERIAL_XMIT_SIZE - info->xmit_head));
+			if (c <= 0)
+				break;
+
+			c -= copy_from_user(tmp_buf, buf, c);
+			if (!c) {
+				if (!ret)
+					ret = -EFAULT;
+				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;
+		}
+		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;
+		}
+	}
+	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+            !(info->IER & VAC_UART_INT_TX_EMPTY)) {
+                info->IER |= VAC_UART_INT_TX_EMPTY;
+		serial_out(info, VAC_UART_INT_MASK, info->IER);
+	}
+	return ret;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	int	ret;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	unsigned long flags; 
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+
+	save_flags(flags); cli();
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	restore_flags(flags); 
+
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+		return;
+
+	info->x_char = ch;
+	if (ch) {
+		/* Make sure transmit interrupts are on */
+                info->IER |= VAC_UART_INT_TX_EMPTY;
+		serial_out(info, VAC_UART_INT_MASK, info->IER);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	baget_printk("throttle %s: %d....\n", tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		rs_send_xchar(tty, STOP_CHAR(tty));
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	baget_printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			rs_send_xchar(tty, START_CHAR(tty));
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct async_struct * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+	struct serial_state *state = info->state;
+   
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = state->type;
+	tmp.line = state->line;
+	tmp.port = state->port;
+	tmp.irq = state->irq;
+	tmp.flags = state->flags;
+	tmp.xmit_fifo_size = state->xmit_fifo_size;
+	tmp.baud_base = state->baud_base;
+	tmp.close_delay = state->close_delay;
+	tmp.closing_wait = state->closing_wait;
+	tmp.custom_divisor = state->custom_divisor;
+	tmp.hub6 = state->hub6;
+	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_serial_info(struct async_struct * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+ 	struct serial_state old_state, *state;
+	unsigned int		i,change_irq,change_port;
+	int 			retval = 0;
+
+	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+		return -EFAULT;
+	state = info->state;
+	old_state = *state;
+  
+	change_irq = new_serial.irq != state->irq;
+	change_port = (new_serial.port != state->port) ||
+		(new_serial.hub6 != state->hub6);
+  
+	if (!capable(CAP_SYS_ADMIN)) {
+		if (change_irq || change_port ||
+		    (new_serial.baud_base != state->baud_base) ||
+		    (new_serial.type != state->type) ||
+		    (new_serial.close_delay != state->close_delay) ||
+		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (state->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+		info->flags = ((state->flags & ~ASYNC_USR_MASK) |
+			       (info->flags & ASYNC_USR_MASK));
+		state->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	new_serial.irq = irq_cannonicalize(new_serial.irq);
+
+	if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
+	    (new_serial.baud_base == 0) || (new_serial.type < PORT_UNKNOWN) ||
+	    (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
+	    (new_serial.type == PORT_STARTECH)) {
+		return -EINVAL;
+	}
+
+	if ((new_serial.type != state->type) ||
+	    (new_serial.xmit_fifo_size <= 0))
+		new_serial.xmit_fifo_size =
+			uart_config[state->type].dfl_xmit_fifo_size;
+
+	/* Make sure address is not already in use */
+	if (new_serial.type) {
+		for (i = 0 ; i < NR_PORTS; i++)
+			if ((state != &rs_table[i]) &&
+			    (rs_table[i].port == new_serial.port) &&
+			    rs_table[i].type)
+				return -EADDRINUSE;
+	}
+
+	if ((change_port || change_irq) && (state->count > 1))
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	state->baud_base = new_serial.baud_base;
+	state->flags = ((state->flags & ~ASYNC_FLAGS) |
+			(new_serial.flags & ASYNC_FLAGS));
+	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+		       (info->flags & ASYNC_INTERNAL_FLAGS));
+	state->custom_divisor = new_serial.custom_divisor;
+	state->type = new_serial.type;
+	state->close_delay = new_serial.close_delay * HZ/100;
+	state->closing_wait = new_serial.closing_wait * HZ/100;
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+	info->xmit_fifo_size = state->xmit_fifo_size =
+		new_serial.xmit_fifo_size;
+
+	release_region(state->port,8); 
+	if (change_port || change_irq) {
+		/*
+		 * We need to shutdown the serial port at the old
+		 * port/irq combination.
+		 */
+		shutdown(info);
+		state->irq = new_serial.irq;
+		info->port = state->port = new_serial.port;
+		info->hub6 = state->hub6 = new_serial.hub6;
+	}
+	if (state->type != PORT_UNKNOWN)
+		request_region(state->port,8,"serial(set)");
+
+	
+check_and_exit:
+	if (!state->port || !state->type)
+		return 0;
+	if (state->flags & ASYNC_INITIALIZED) {
+		if (((old_state.flags & ASYNC_SPD_MASK) !=
+		     (state->flags & ASYNC_SPD_MASK)) ||
+		    (old_state.custom_divisor != state->custom_divisor)) {
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+				info->tty->alt_speed = 57600;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+				info->tty->alt_speed = 115200;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+				info->tty->alt_speed = 230400;
+			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+				info->tty->alt_speed = 460800;
+			change_speed(info);
+		}
+	} else
+		retval = startup(info);
+	return retval;
+}
+
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned short status;
+	unsigned int result;
+	unsigned long flags; 
+
+	save_flags(flags); cli();
+	status = serial_inw(info, VAC_UART_INT_STATUS);
+	restore_flags(flags);
+	result = ((status & VAC_UART_STATUS_TX_EMPTY) ? TIOCSER_TEMT : 0);
+	return put_user(result,value);
+}
+
+
+static int get_modem_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned int result;
+
+	result = TIOCM_CAR | TIOCM_DSR;
+	return put_user(result,value);
+}
+
+static int set_modem_info(struct async_struct * info, unsigned int cmd,
+			  unsigned int *value)
+{
+	int error;
+	unsigned int arg;
+
+	error = get_user(arg, value);
+	if (error)
+		return error;
+	switch (cmd) {
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int do_autoconfig(struct async_struct * info)
+{
+	int			retval;
+	
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	
+	if (info->state->count > 1)
+		return -EBUSY;
+	
+	shutdown(info);
+
+	autoconfig(info->state);
+
+	retval = startup(info);
+	if (retval)
+		return retval;
+	return 0;
+}
+
+/*
+ * rs_break() --- routine which turns the break handling on or off
+ */
+static void rs_break(struct tty_struct *tty, int break_state)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_break"))
+		return;
+
+	if (!info->port)
+		return;
+	save_flags(flags); cli();
+	if (break_state == -1)
+		serial_outp(info, VAC_UART_MODE,
+			   serial_inp(info, VAC_UART_MODE) | \
+			    VAC_UART_MODE_SEND_BREAK);
+	else
+		serial_outp(info, VAC_UART_MODE,
+			   serial_inp(info, VAC_UART_MODE) & \
+			    ~VAC_UART_MODE_SEND_BREAK);
+	restore_flags(flags);
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error;
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct async_icount cprev, cnow;	/* kernel counter temps */
+	struct serial_icounter_struct *p_cuser;	/* user space */
+	unsigned long flags; 
+
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+		case TIOCGSERIAL:
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSERCONFIG:
+			return do_autoconfig(info);
+
+		case TIOCSERGETLSR: /* Get line status register */
+			return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			if (copy_to_user((struct async_struct *) arg,
+					 info, sizeof(struct async_struct)))
+				return -EFAULT;
+			return 0;
+				
+		/*
+		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)to change
+		 * - mask passed in arg for lines of interest
+ 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 * Caller should use TIOCGICOUNT to see which one it was
+		 */
+		case TIOCMIWAIT:
+			save_flags(flags); cli();
+			/* note the counters on entry */
+			cprev = info->state->icount;
+			restore_flags(flags);
+			while (1) {
+				interruptible_sleep_on(&info->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+				save_flags(flags); cli(); 
+				cnow = info->state->icount; /* atomic copy */
+				restore_flags(flags); 
+				if (cnow.rng == cprev.rng && 
+				    cnow.dsr == cprev.dsr && 
+				    cnow.dcd == cprev.dcd && 
+				    cnow.cts == cprev.cts)
+					return -EIO; /* no change => error */
+				if ( ((arg & TIOCM_RNG) && 
+				      (cnow.rng != cprev.rng)) ||
+				     ((arg & TIOCM_DSR) && 
+				      (cnow.dsr != cprev.dsr)) ||
+				     ((arg & TIOCM_CD)  && 
+				      (cnow.dcd != cprev.dcd)) ||
+				     ((arg & TIOCM_CTS) && 
+				      (cnow.cts != cprev.cts)) ) {
+					return 0;
+				}
+				cprev = cnow;
+			}
+			/* NOTREACHED */
+
+		/* 
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+		case TIOCGICOUNT:
+			save_flags(flags); cli(); 
+			cnow = info->state->icount;
+			restore_flags(flags);
+			p_cuser = (struct serial_icounter_struct *) arg;
+			error = put_user(cnow.cts, &p_cuser->cts);
+			if (error) return error;
+			error = put_user(cnow.dsr, &p_cuser->dsr);
+			if (error) return error;
+			error = put_user(cnow.rng, &p_cuser->rng);
+			if (error) return error;
+			error = put_user(cnow.dcd, &p_cuser->dcd);
+			if (error) return error;
+                        error = put_user(cnow.rx, &p_cuser->rx);
+                        if (error) return error;
+                        error = put_user(cnow.tx, &p_cuser->tx);
+                        if (error) return error;
+                        error = put_user(cnow.frame, &p_cuser->frame);
+                        if (error) return error;
+                        error = put_user(cnow.overrun, &p_cuser->overrun);
+                        if (error) return error;
+                        error = put_user(cnow.parity, &p_cuser->parity);
+                        if (error) return error;
+                        error = put_user(cnow.brk, &p_cuser->brk);
+                        if (error) return error;
+                        error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
+
+			if (error) return error;
+			return 0;
+
+                case TIOCSERGWILD:
+                case TIOCSERSWILD:
+                       /* "setserial -W" is called in Debian boot */
+                        printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
+                        return 0;
+ 
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct async_struct *info = (struct async_struct *)tty->driver_data;
+	
+	if (   (tty->termios->c_cflag == old_termios->c_cflag)
+	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_speed(info);
+
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rs_start(tty);
+	}
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state;
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+
+	state = info->state;
+	
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		DBG_CNT("before DEC-hung");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	baget_printk("rs_close ttys%d, count = %d\n", 
+		     info->line, state->count);
+#endif
+	if ((tty->count == 1) && (state->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  state->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		baget_printk("rs_close: bad serial port count; "
+			     "tty->count is 1, "
+			     "state->count is %d\n", state->count);
+		state->count = 1;
+	}
+	if (--state->count < 0) {
+		baget_printk("rs_close: bad serial port count for "
+			     "ttys%d: %d\n",
+			     info->line, state->count);
+		state->count = 0;
+	}
+	if (state->count) {
+		DBG_CNT("before DEC-2");
+		MOD_DEC_USE_COUNT;
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->IER &= ~(VAC_UART_INT_RX_BREAK_CHANGE | VAC_UART_INT_RX_ERRS);
+	info->read_status_mask &= ~VAC_UART_STATUS_RX_READY;
+	if (info->flags & ASYNC_INITIALIZED) {
+		serial_outw(info, VAC_UART_INT_MASK, info->IER);
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		rs_wait_until_sent(tty, info->timeout);
+	}
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+	restore_flags(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+	int lsr;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+		return;
+
+	if (info->state->type == PORT_UNKNOWN)
+		return;
+
+        if (info->xmit_fifo_size == 0)
+                return; /* Just in case.... */
+
+	orig_jiffies = jiffies;
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 * 
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	if (timeout)
+	  char_time = MIN(char_time, timeout);
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	baget_printk("In rs_wait_until_sent(%d) check=%lu...", 
+		     timeout, char_time);
+	baget_printk("jiff=%lu...", jiffies);
+#endif
+	while (!((lsr = serial_inp(info, VAC_UART_INT_STATUS)) & \
+		 VAC_UART_STATUS_TX_EMPTY)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+		baget_printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+		current->state = TASK_INTERRUPTIBLE;
+		current->counter = 0;	/* make us low-priority */
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && ((orig_jiffies + timeout) < jiffies))
+			break;
+	}
+	current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	baget_printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_hangup(struct tty_struct *tty)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	struct serial_state *state = info->state;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+
+	state = info->state;
+	
+	rs_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	state->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct async_struct *info)
+{
+	struct wait_queue wait = { current, NULL };
+	struct serial_state *state = info->state;
+	int		retval;
+	int		do_clocal = 0,  extra_count = 0;  
+	unsigned long   flags; 
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (state->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, state->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	baget_printk("block_til_ready before block: ttys%d, count = %d\n",
+	       state->line, state->count);
+#endif
+	save_flags(flags); cli(); 
+	if (!tty_hung_up_p(filp)) {
+		extra_count = 1; 
+		state->count--;
+	}
+	restore_flags(flags); 
+	info->blocked_open++;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(info->flags & ASYNC_CLOSING))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		baget_printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, state->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (extra_count)
+		state->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	baget_printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, state->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+
+static int get_async_struct(int line, struct async_struct **ret_info)
+{
+	struct async_struct *info;
+	struct serial_state *sstate;
+
+	sstate = rs_table + line;
+	sstate->count++;
+	if (sstate->info) {
+		*ret_info = sstate->info;
+		return 0;
+	}
+	info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+	if (!info) {
+		sstate->count--;
+		return -ENOMEM;
+	}
+	memset(info, 0, sizeof(struct async_struct));
+	info->magic = SERIAL_MAGIC;
+	info->port = sstate->port;
+	info->flags = sstate->flags;
+	info->xmit_fifo_size = sstate->xmit_fifo_size;
+	info->line = line;
+	info->tqueue.routine = do_softint;
+	info->tqueue.data = info;
+	info->state = sstate;
+	if (sstate->info) {
+		kfree_s(info, sizeof(struct async_struct));
+		*ret_info = sstate->info;
+		return 0;
+	}
+	*ret_info = sstate->info = info;
+	return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct async_struct	*info;
+	int 			retval, line;
+	unsigned long		page;
+
+	MOD_INC_USE_COUNT; 
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS)) {
+		MOD_DEC_USE_COUNT; 
+		return -ENODEV;
+	}
+	retval = get_async_struct(line, &info);
+	if (retval) {
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+        tty->driver_data = info;
+        info->tty = tty;
+	if (serial_paranoia_check(info, tty->device, "rs_open")) {
+	        /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ 
+		return -ENODEV;
+	}
+
+#ifdef SERIAL_DEBUG_OPEN
+	baget_printk("rs_open %s%d, count = %d\n", 
+		     tty->driver.name, info->line,
+		     info->state->count);
+#endif
+	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+	if (!tmp_buf) {
+		page = get_free_page(GFP_KERNEL);
+		if (!page) {
+			/* MOD_DEC_USE_COUNT; "info->tty" will cause this */
+			return -ENOMEM;
+		}
+		if (tmp_buf)
+			free_page(page);
+		else
+			tmp_buf = (unsigned char *) page;
+	}
+
+	/*
+	 * If the port is the middle of closing, bail out now
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+		/* MOD_DEC_USE_COUNT; "info->tty" will cause this */
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ASYNC_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval) {
+		/* MOD_DEC_USE_COUNT; "info->tty" will cause this */
+		return retval;
+	}
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+		 /* MOD_DEC_USE_COUNT; "info->tty" will cause this */
+#ifdef SERIAL_DEBUG_OPEN
+		 baget_printk("rs_open returning after block_til_ready "
+			      "with %d\n",
+			      retval);
+#endif
+		 return retval;
+	}
+
+	if ((info->state->count == 1) &&
+	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->state->normal_termios;
+		else 
+			*tty->termios = info->state->callout_termios;
+		change_speed(info);
+	}
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (sercons.cflag && sercons.index == line) {
+		tty->termios->c_cflag = sercons.cflag;
+		sercons.cflag = 0;
+		change_speed(info);
+	}
+#endif
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	baget_printk("rs_open ttys%d successful...", info->line);
+#endif
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct serial_state *state)
+{
+	struct async_struct *info = state->info, scr_info;
+	int	ret;
+
+	ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+		      state->line, uart_config[state->type].name, 
+		      state->port, state->irq);
+
+	if (!state->port || (state->type == PORT_UNKNOWN)) {
+		ret += sprintf(buf+ret, "\n");
+		return ret;
+	}
+
+	/*
+	 * Figure out the current RS-232 lines
+	 */
+	if (!info) {
+		info = &scr_info;	/* This is just for serial_{in,out} */
+
+		info->magic = SERIAL_MAGIC;
+		info->port = state->port;
+		info->flags = state->flags;
+		info->quot = 0;
+		info->tty = 0;
+	}
+	
+	if (info->quot) {
+		ret += sprintf(buf+ret, " baud:%d",
+			       state->baud_base / info->quot);
+	}
+
+	ret += sprintf(buf+ret, " tx:%d rx:%d",
+		      state->icount.tx, state->icount.rx);
+
+	if (state->icount.frame)
+		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+	
+	if (state->icount.parity)
+		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+	
+	if (state->icount.brk)
+		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);	
+
+	if (state->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+	return ret;
+}
+
+int rs_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	int i, len = 0, l;
+	off_t	begin = 0;
+
+	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+	for (i = 0; i < NR_PORTS && len < 4000; i++) {
+                l = line_info(page + len, &rs_table[i]);
+                len += l;
+ 		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (begin-off);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_serial_version(void)
+{
+ 	printk(KERN_INFO "%s version %s with", serial_name, serial_version);
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+	printk(" SHARE_IRQ");
+#endif
+#define SERIAL_OPT
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+	printk(" DETECT_IRQ");
+#endif
+#ifdef SERIAL_OPT
+	printk(" enabled\n");
+#else
+	printk(" no serial options enabled\n");
+#endif
+#undef SERIAL_OPT
+}
+
+
+/*
+ * This routine is called by rs_init() to initialize a specific serial
+ * port.  It determines what type of UART chip this serial port is
+ * using: 8250, 16450, 16550, 16550A.  The important question is
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
+ */
+
+/*
+ *  Functionality of this function is reduced: we already know we have a VAC,
+ *  but still need to perform some important actions (see code :-).
+ */
+static void autoconfig(struct serial_state * state)
+{
+	struct async_struct *info, scr_info; 
+	unsigned long flags;
+
+	/* Setting up important parameters */
+	state->type = VAC_UART_TYPE;
+	state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;
+
+	info = &scr_info;       /* This is just for serial_{in,out} */   
+
+	info->magic = SERIAL_MAGIC;
+        info->port  = state->port;
+        info->flags = state->flags;
+
+        save_flags(flags); cli();
+
+	/* + Flush VAC input fifo */ 
+        (void)serial_in(info, VAC_UART_RX);
+        (void)serial_in(info, VAC_UART_RX);
+        (void)serial_in(info, VAC_UART_RX);
+        (void)serial_in(info, VAC_UART_RX);
+
+	/* Disable interrupts */
+        serial_outp(info, VAC_UART_INT_MASK, 0);
+
+        restore_flags(flags);
+}
+
+int register_serial(struct serial_struct *req);
+void unregister_serial(int line);
+
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
+
+/*
+ *  Important function for VAC UART check and reanimation.
+ */
+
+static void rs_timer(void)
+{
+        static unsigned long last_strobe = 0;
+        struct async_struct *info;
+        unsigned int    i;
+        unsigned long flags;
+
+        if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
+                for (i=1; i < NR_IRQS; i++) {
+                        info = IRQ_ports[i];
+                        if (!info)
+                                continue;
+                        save_flags(flags); cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+                        if (info->next_port) {
+                                do {
+                                        serial_out(info, VAC_UART_INT_MASK, 0);
+                                        info->IER |= VAC_UART_INT_TX_EMPTY;
+                                        serial_out(info, VAC_UART_INT_MASK, 
+						   info->IER);
+                                        info = info->next_port;
+                                } while (info);
+				rs_interrupt(i, NULL, NULL);
+                        } else
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+                                rs_interrupt_single(i, NULL, NULL);
+                        restore_flags(flags);
+                }
+        }
+        last_strobe = jiffies;
+        timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME;
+        timer_active |= 1 << RS_TIMER;
+
+	/*
+	 *  It looks this code for case we share IRQ with console...
+	 */
+
+        if (IRQ_ports[0]) {
+                save_flags(flags); cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+                rs_interrupt(0, NULL, NULL);
+#else
+                rs_interrupt_single(0, NULL, NULL);
+#endif
+                restore_flags(flags);
+
+                timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
+        }
+}
+ 
+/*
+ * The serial driver boot-time initialization code!
+ */
+__initfunc(int rs_init(void))
+{
+	int i;
+	struct serial_state * state;
+	extern void atomwide_serial_init (void);
+	extern void dualsp_serial_init (void);
+
+#ifdef CONFIG_ATOMWIDE_SERIAL
+	atomwide_serial_init ();
+#endif
+#ifdef CONFIG_DUALSP_SERIAL
+	dualsp_serial_init ();
+#endif
+
+	init_bh(SERIAL_BH, do_serial_bh);
+	timer_table[RS_TIMER].fn = rs_timer;
+	timer_table[RS_TIMER].expires = 0;
+
+	for (i = 0; i < NR_IRQS; i++) {
+		IRQ_ports[i] = 0;
+		IRQ_timeout[i] = 0;
+	}
+
+
+/*
+ *  It is not a good idea to share interrupts with console,
+ *  but it looks we cannot avoid it.
+ */
+#if 0 
+
+#ifdef CONFIG_SERIAL_CONSOLE
+	/*
+	 *	The interrupt of the serial console port
+	 *	can't be shared.
+	 */
+	if (sercons.flags & CON_CONSDEV) {
+		for(i = 0; i < NR_PORTS; i++)
+			if (i != sercons.index &&
+			    rs_table[i].irq == rs_table[sercons.index].irq)
+				rs_table[i].irq = 0;
+	}
+#endif
+
+#endif
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.driver_name = "serial";
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = NR_PORTS;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_open;
+	serial_driver.close = rs_close;
+	serial_driver.write = rs_write;
+	serial_driver.put_char = rs_put_char;
+	serial_driver.flush_chars = rs_flush_chars;
+	serial_driver.write_room = rs_write_room;
+	serial_driver.chars_in_buffer = rs_chars_in_buffer;
+	serial_driver.flush_buffer = rs_flush_buffer;
+	serial_driver.ioctl = rs_ioctl;
+	serial_driver.throttle = rs_throttle;
+	serial_driver.unthrottle = rs_unthrottle;
+	serial_driver.send_xchar = rs_send_xchar;
+	serial_driver.set_termios = rs_set_termios;
+	serial_driver.stop = rs_stop;
+	serial_driver.start = rs_start;
+	serial_driver.hangup = rs_hangup;
+	serial_driver.break_ctl = rs_break;
+	serial_driver.wait_until_sent = rs_wait_until_sent;
+	serial_driver.read_proc = rs_read_proc;
+	
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	callout_driver.read_proc = 0;
+	callout_driver.proc_entry = 0;
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+	
+	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+		state->magic = SSTATE_MAGIC;
+		state->line = i;
+		state->type = PORT_UNKNOWN;
+		state->custom_divisor = 0;
+		state->close_delay = 5*HZ/10;
+		state->closing_wait = 30*HZ;
+		state->callout_termios = callout_driver.init_termios;
+		state->normal_termios = serial_driver.init_termios;
+		state->icount.cts = state->icount.dsr = 
+			state->icount.rng = state->icount.dcd = 0;
+		state->icount.rx = state->icount.tx = 0;
+		state->icount.frame = state->icount.parity = 0;
+		state->icount.overrun = state->icount.brk = 0;
+		state->irq = irq_cannonicalize(state->irq);
+		if (check_region(state->port,8))
+			continue;
+	        if (state->flags & ASYNC_BOOT_AUTOCONF)
+ 			autoconfig(state);
+	}
+
+	/*
+	 * Detect the IRQ only once every port is initialised,
+	 * because some 16450 do not reset to 0 the MCR register.
+	 */
+	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+		if (state->type == PORT_UNKNOWN)
+			continue;
+		printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n",
+		       state->line,
+		       (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
+		       state->port, state->irq,
+		       uart_config[state->type].name);
+	}
+	return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+int register_serial(struct serial_struct *req)
+{
+	int i;
+	unsigned long flags;
+	struct serial_state *state;
+
+	save_flags(flags);
+	cli();
+	for (i = 0; i < NR_PORTS; i++) {
+		if (rs_table[i].port == req->port)
+			break;
+	}
+	if (i == NR_PORTS) {
+		for (i = 0; i < NR_PORTS; i++)
+			if ((rs_table[i].type == PORT_UNKNOWN) &&
+			    (rs_table[i].count == 0))
+				break;
+	}
+	if (i == NR_PORTS) {
+		restore_flags(flags);
+		return -1;
+	}
+	state = &rs_table[i];
+	if (rs_table[i].count) {
+		restore_flags(flags);
+		printk("Couldn't configure serial #%d (port=%d,irq=%d): "
+		       "device already open\n", i, req->port, req->irq);
+		return -1;
+	}
+	state->irq = req->irq;
+	state->port = req->port;
+	state->flags = req->flags;
+
+	autoconfig(state);
+	if (state->type == PORT_UNKNOWN) {
+		restore_flags(flags);
+		printk("register_serial(): autoconfig failed\n");
+		return -1;
+	}
+	restore_flags(flags);
+
+	printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n",
+	       state->line, state->port, state->irq,
+	       uart_config[state->type].name);
+	return state->line;
+}
+
+void unregister_serial(int line)
+{
+	unsigned long flags;
+	struct serial_state *state = &rs_table[line];
+
+	save_flags(flags);
+	cli();
+	if (state->info && state->info->tty)
+		tty_hangup(state->info->tty);
+	state->type = PORT_UNKNOWN;
+	printk(KERN_INFO "tty%02d unloaded\n", state->line);
+	restore_flags(flags);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return rs_init();
+}
+
+void cleanup_module(void) 
+{
+	unsigned long flags;
+	int e1, e2;
+	int i;
+
+	printk("Unloading %s: version %s\n", serial_name, serial_version); 
+	save_flags(flags);
+	cli();
+
+	timer_active &= ~(1 << RS_TIMER);
+	timer_table[RS_TIMER].fn = NULL;
+	timer_table[RS_TIMER].expires = 0;
+        remove_bh(SERIAL_BH);
+
+	if ((e1 = tty_unregister_driver(&serial_driver)))
+		printk("SERIAL: failed to unregister serial driver (%d)\n",
+		       e1);
+	if ((e2 = tty_unregister_driver(&callout_driver)))
+		printk("SERIAL: failed to unregister callout driver (%d)\n", 
+		       e2);
+	restore_flags(flags);
+
+	for (i = 0; i < NR_PORTS; i++) {
+		if (rs_table[i].type != PORT_UNKNOWN)
+			release_region(rs_table[i].port, 8);
+	}
+	if (tmp_buf) {
+		free_page((unsigned long) tmp_buf);
+		tmp_buf = NULL;
+	}
+}
+#endif /* MODULE */
+
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+#define BOTH_EMPTY (VAC_UART_STATUS_TX_EMPTY | VAC_UART_STATUS_TX_EMPTY)
+
+/*
+ *	Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct async_struct *info)
+{
+	int lsr;
+	unsigned int tmout = 1000000;
+
+	do {
+		lsr = serial_inp(info, VAC_UART_INT_STATUS);
+		if (--tmout == 0) break;
+	} while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
+}
+
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ */
+static void serial_console_write(struct console *co, const char *s,
+				unsigned count)
+{
+	struct serial_state *ser;
+	int ier;
+	unsigned i;
+	struct async_struct scr_info; /* serial_{in,out} because HUB6 */
+
+	ser = rs_table + co->index;
+	scr_info.magic = SERIAL_MAGIC;
+	scr_info.port = ser->port;
+	scr_info.flags = ser->flags;
+
+	/*
+	 *	First save the IER then disable the interrupts
+	 */
+	ier = serial_inp(&scr_info, VAC_UART_INT_MASK);
+	serial_outw(&scr_info, VAC_UART_INT_MASK, 0x00);
+
+	/*
+	 *	Now, do each character
+	 */
+	for (i = 0; i < count; i++, s++) {
+		wait_for_xmitr(&scr_info);
+
+		/*
+		 *	Send the character out.
+		 *	If a LF, also do CR...
+		 */
+		serial_outp(&scr_info, VAC_UART_TX, (unsigned short)*s << 8);
+		if (*s == 10) {
+			wait_for_xmitr(&scr_info);
+			serial_outp(&scr_info, VAC_UART_TX, 13 << 8);
+		}
+	}
+
+	/*
+	 *	Finally, Wait for transmitter & holding register to empty
+	 * 	and restore the IER
+	 */
+	wait_for_xmitr(&scr_info);
+	serial_outp(&scr_info, VAC_UART_INT_MASK, ier);
+}
+
+/*
+ *	Receive character from the serial port
+ */
+static int serial_console_wait_key(struct console *co)
+{
+	struct serial_state *ser;
+	int ier;
+	int lsr;
+	int c;
+	struct async_struct scr_info; /* serial_{in,out} because HUB6 */
+
+	ser = rs_table + co->index;
+	scr_info.magic = SERIAL_MAGIC;
+	scr_info.port = ser->port;
+	scr_info.flags = ser->flags;
+
+	/*
+	 *	First save the IER then disable the interrupts so
+	 *	that the real driver for the port does not get the
+	 *	character.
+	 */
+	ier = serial_inp(&scr_info, VAC_UART_INT_MASK);
+	serial_outp(&scr_info, VAC_UART_INT_MASK, 0x00);
+
+	do {
+		lsr = serial_inp(&scr_info, VAC_UART_INT_STATUS);
+	} while (!(lsr & VAC_UART_STATUS_RX_READY));
+	c = serial_inp(&scr_info, VAC_UART_RX);
+
+	/*
+	 *	Restore the interrupts
+	 */
+	serial_outp(&scr_info, VAC_UART_INT_MASK, ier);
+
+	return c;
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ *	Setup initial baud/bits/parity. We do two things here:
+ *	- construct a cflag setting for the first rs_open()
+ *	- initialize the serial port
+ *	Return non-zero if we didn't find a serial port.
+ */
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+	struct serial_state *ser;
+	unsigned cval;
+	int	baud = 9600;
+	int	bits = 8;
+	int	parity = 'n';
+	int	cflag = CREAD | HUPCL | CLOCAL;
+	int	quot = 0;
+	char	*s;
+	struct async_struct scr_info; /* serial_{in,out} because HUB6 */
+
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) parity = *s++;
+		if (*s) bits   = *s - '0';
+	}
+
+	/*
+	 *	Now construct a cflag setting.
+	 */
+	switch(baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 2400:
+			cflag |= B2400;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 57600:
+			cflag |= B57600;
+			break;
+		case 115200:
+			cflag |= B115200;
+			break;
+		case 9600:
+		default:
+			cflag |= B9600;
+			break;
+	}
+	switch(bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch(parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+	co->cflag = cflag;
+
+	/*
+	 *	Divisor, bytesize and parity
+	 */
+	ser = rs_table + co->index;
+	scr_info.magic = SERIAL_MAGIC;
+	scr_info.port = ser->port;
+	scr_info.flags = ser->flags;
+
+	quot = ser->baud_base / baud;
+	cval = cflag & (CSIZE | CSTOPB);
+
+	cval >>= 4;
+
+	cval &= ~VAC_UART_MODE_PARITY_ENABLE;
+	if (cflag & PARENB)
+		cval |= VAC_UART_MODE_PARITY_ENABLE;
+	if (cflag & PARODD)
+		cval |= VAC_UART_MODE_PARITY_ODD;
+
+	/*
+	 *	Disable UART interrupts, set DTR and RTS high
+	 *	and set speed.
+	 */
+	switch (baud) {
+	default:
+	case 9600:
+		cval |= VAC_UART_MODE_BAUD(7);
+		break;
+	case 4800:
+		cval |= VAC_UART_MODE_BAUD(6);
+		break;
+	case 2400:
+		cval |= VAC_UART_MODE_BAUD(5);
+		break;
+	case 1200:
+		cval |= VAC_UART_MODE_BAUD(4);
+		break;
+	case 600:
+		cval |= VAC_UART_MODE_BAUD(3);
+		break;
+	case 300:
+		cval |= VAC_UART_MODE_BAUD(2);
+		break;
+#ifndef QUAD_UART_SPEED
+	case 150:
+#else
+	case 38400:
+#endif
+		cval |= VAC_UART_MODE_BAUD(1);
+		break;
+#ifndef QUAD_UART_SPEED
+	case 75:
+#else
+	case 19200:
+#endif
+		cval |= VAC_UART_MODE_BAUD(0);
+		break;
+	}
+
+	/* Baget VAC need some adjustments for computed value */
+	cval = vac_uart_mode_fixup(cval);
+
+        serial_outp(&scr_info, VAC_UART_MODE, cval);  
+	serial_outp(&scr_info, VAC_UART_INT_MASK, 0);
+
+	return 0;
+}
+
+static struct console sercons = {
+	"ttyS",
+	serial_console_write,
+	NULL,
+	serial_console_device,
+	serial_console_wait_key,
+	NULL,
+	serial_console_setup,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+/*
+ *	Register console.
+ */
+__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+{
+	register_console(&sercons);
+	return kmem_start;
+}
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+#undef PRINT_DEBUG_PORT_INFO
+
+/*
+ * This is the interface to the remote debugger stub.
+ * I've put that here to be able to control the serial
+ * device more directly.
+ */
+
+static int initialized = 0;
+
+static int rs_debug_init(struct async_struct *info)
+{
+	int quot;
+
+	autoconfig(info);	/* autoconfigure ttyS0, whatever that is */
+
+#ifdef PRINT_DEBUG_PORT_INFO
+	baget_printk("kgdb debug interface:: tty%02d at 0x%04x", 
+		     info->line, info->port);
+	switch (info->type) {
+		case PORT_8250:
+			baget_printk(" is a 8250\n");
+			break;
+		case PORT_16450:
+			baget_printk(" is a 16450\n");
+			break;
+		case PORT_16550:
+			baget_printk(" is a 16550\n");
+			break;
+		case PORT_16550A:
+			baget_printk(" is a 16550A\n");
+			break;
+		case PORT_16650:
+			baget_printk(" is a 16650\n");
+			break;
+		default:
+			baget_printk(" is of unknown type -- unusable\n");
+			break;
+	}
+#endif
+	
+	if (info->port == PORT_UNKNOWN)
+		return -1;
+
+	/*
+	 * Clear all interrupts
+	 */
+
+	(void)serial_inp(info, VAC_UART_INT_STATUS);
+	(void)serial_inp(info, VAC_UART_RX);
+
+	/*
+	 * Now, initialize the UART 
+	 */
+	serial_outp(info,VAC_UART_MODE,VAC_UART_MODE_INITIAL); /* reset DLAB */
+	if (info->flags & ASYNC_FOURPORT) {
+		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+		info->MCR_noint = UART_MCR_DTR | UART_MCR_OUT1;
+	} else {
+		info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
+		info->MCR_noint = UART_MCR_DTR | UART_MCR_RTS;
+	}
+
+	info->MCR = info->MCR_noint;	     /* no interrupts, please */
+	/*
+	 * and set the speed of the serial port
+	 * (currently hardwired to 9600 8N1
+	 */
+
+	quot = info->baud_base / 9600;	     /* baud rate is fixed to 9600 */
+	/* FIXME: if rs_debug interface is needed, we need to set speed here */
+
+	return 0;
+}
+
+int putDebugChar(char c)
+{
+	struct async_struct *info = rs_table;
+
+	if (!initialized) { 		/* need to init device first */
+		if (rs_debug_init(info) == 0)
+			initialized = 1;
+		else
+			return 0;
+	}
+
+	while ((serial_inw(info, VAC_UART_INT_STATUS) & \
+                VAC_UART_STATUS_TX_EMPTY) == 0)
+		;
+	serial_out(info, VAC_UART_TX, (unsigned short)c << 8);
+
+	return 1;
+}
+
+char getDebugChar(void)
+{
+	struct async_struct *info = rs_table;
+
+	if (!initialized) { 		/* need to init device first */
+		if (rs_debug_init(info) == 0)
+			initialized = 1;
+		else
+			return 0;
+	}
+	while (!(serial_inw(info, VAC_UART_INT_STATUS) & \
+		 VAC_UART_STATUS_RX_READY))
+		;
+
+	return(serial_inp(info, VAC_UART_RX));
+}
+
+#endif /* CONFIG_REMOTE_DEBUG */
diff -u --recursive --new-file v2.3.8/linux/arch/mips/baget/wbflush.c linux/arch/mips/baget/wbflush.c
--- v2.3.8/linux/arch/mips/baget/wbflush.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/baget/wbflush.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,24 @@
+/*
+ * Setup the right wbflush routine for Baget/MIPS.
+ *
+ * Copyright (C) 1999 Gleb Raiko & Vladimir Roganov
+ */
+
+#include <asm/bootinfo.h>
+#include <asm/init.h>
+
+void (*__wbflush) (void);
+
+static void wbflush_baget(void);
+
+__initfunc(void wbflush_setup(void))
+{
+	__wbflush = wbflush_baget;
+}
+
+/*
+ * Baget/MIPS doesnt need to write back the WB.
+ */
+static void wbflush_baget(void)
+{
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/boot/Makefile linux/arch/mips/boot/Makefile
--- v2.3.8/linux/arch/mips/boot/Makefile	Tue Aug  4 16:06:56 1998
+++ linux/arch/mips/boot/Makefile	Fri Jun 25 17:40:12 1999
@@ -1,11 +1,10 @@
-#
-# arch/mips/boot/Makefile
+# $Id: Makefile,v 1.9 1999/04/07 18:45:23 harald Exp $
 #
 # This file is subject to the terms and conditions of the GNU General Public
 # License.  See the file "COPYING" in the main directory of this archive
 # for more details.
 #
-# Copyright (C) 1995 by Ralf Baechle
+# Copyright (C) 1995, 1998 by Ralf Baechle
 #
 
 .S.s:
@@ -16,35 +15,37 @@
 OBJS  = milo.o a.out.o
 
 #
+# Some DECstations need all possible sections of an ECOFF executable
+#
+ifdef CONFIG_DECSTATION
+  E2EFLAGS = -a
+else
+  E2EFLAGS =
+endif
+
+#
 # Drop some uninteresting sections in the kernel.
 # This is only relevant for ELF kernels but doesn't hurt a.out
 #
 drop-sections	= .reginfo .mdebug
 strip-flags	= $(addprefix --remove-section=,$(drop-sections))
 
-#
-# Fake compressed boot
-#
-zImage:	$(CONFIGURE) mkboot $(TOPDIR)/vmlinux
-	$(OBJCOPY) $(strip-flags) $(TOPDIR)/vmlinux zImage.tmp
-	./mkboot zImage.tmp zImage
-	rm -f zImage.tmp
+all: vmlinux.ecoff addinitrd
 
-mkboot: mkboot.c
+vmlinux.ecoff:	$(CONFIGURE) elf2ecoff $(TOPDIR)/vmlinux
+	./elf2ecoff $(TOPDIR)/vmlinux vmlinux.ecoff $(E2EFLAGS)
+
+elf2ecoff: elf2ecoff.c
 	$(HOSTCC) -o $@ $^
 
-zdisk:	zImage
-	if [ -f /etc/remote-mcopy ]; then \
-		ssh rio mcopy -o - a:vmlinux <zImage; \
-	else \
-		mcopy -o zImage a:vmlinux; \
-	fi
+addinitrd: addinitrd.c
+	$(HOSTCC) -o $@ $^
 
 # Don't build dependencies, this may die if $(CC) isn't gcc
 dep:
 
 clean:
-	rm -f zImage zImage.tmp mkboot
+	rm -f vmlinux.ecoff
 
 dummy:
 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/boot/addinitrd.c linux/arch/mips/boot/addinitrd.c
--- v2.3.8/linux/arch/mips/boot/addinitrd.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/boot/addinitrd.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,112 @@
+/*
+ * addinitrd - program to add a initrd image to an ecoff kernel
+ *
+ * (C) 1999 Thomas Bogendoerfer
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "ecoff.h"
+
+#define MIPS_PAGE_SIZE	4096
+#define MIPS_PAGE_MASK	(MIPS_PAGE_SIZE-1)
+
+#define swab16(x) \
+        ((unsigned short)( \
+                (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \
+                (((unsigned short)(x) & (unsigned short)0xff00U) >> 8) ))
+
+#define swab32(x) \
+        ((unsigned int)( \
+                (((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
+                (((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
+                (((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
+                (((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
+
+#define SWAB(a)	(swab ? swab32(a) : (a))
+
+void die (char *s)
+{
+	perror (s);
+	exit (1);
+}
+
+int main (int argc, char *argv[])
+{
+	int fd_vmlinux,fd_initrd,fd_outfile;
+	FILHDR efile;
+	AOUTHDR eaout;
+	SCNHDR esecs[3];
+	struct stat st;
+	char buf[1024];
+	unsigned long loadaddr;
+	unsigned long initrd_header[2];
+	int i;
+	int swab = 0;
+
+	if (argc != 4) {
+		printf ("Usage: %s <vmlinux> <initrd> <outfile>\n",argv[0]);
+		exit (1);
+	}
+
+	if ((fd_vmlinux = open (argv[1],O_RDWR)) < 0)
+		 die ("open vmlinux");
+	if (read (fd_vmlinux, &efile, sizeof efile) != sizeof efile)
+		die ("read file header");
+	if (read (fd_vmlinux, &eaout, sizeof eaout) != sizeof eaout)
+		die ("read aout header");
+	if (read (fd_vmlinux, esecs, sizeof esecs) != sizeof esecs)
+		die ("read section headers");
+
+	/*
+	 * check whether the file is good for us
+	 */
+	/* TBD */
+
+	/*
+	 * check, if we have to swab words
+	 */
+	if (ntohs(0xaa55) == 0xaa55) {
+		if (efile.f_magic == swab16(MIPSELMAGIC))
+			swab = 1;
+	} else {
+		if (efile.f_magic == swab16(MIPSEBMAGIC))
+			swab = 1;
+	}
+
+	if ((fd_initrd = open (argv[2], O_RDONLY)) < 0)
+		die ("open initrd");
+	if (fstat (fd_initrd, &st) < 0)
+		die ("fstat initrd");
+	loadaddr = ((SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size) 
+			+ MIPS_PAGE_SIZE-1) & ~MIPS_PAGE_MASK) - 8;
+	if (loadaddr < (SWAB(esecs[2].s_vaddr) + SWAB(esecs[2].s_size)))
+		loadaddr += MIPS_PAGE_SIZE;
+	initrd_header[0] = SWAB(0x494E5244);
+	initrd_header[1] = SWAB(st.st_size);
+	eaout.dsize = esecs[1].s_size = initrd_header[1] = SWAB(st.st_size+8);
+	eaout.data_start = esecs[1].s_vaddr = esecs[1].s_paddr = SWAB(loadaddr);
+
+	if ((fd_outfile = open (argv[3], O_RDWR|O_CREAT|O_TRUNC,0666)) < 0)
+		die ("open outfile");
+	if (write (fd_outfile, &efile, sizeof efile) != sizeof efile)
+		die ("write file header");
+	if (write (fd_outfile, &eaout, sizeof eaout) != sizeof eaout)
+		die ("write aout header");
+	if (write (fd_outfile, esecs, sizeof esecs) != sizeof esecs)
+		die ("write section headers");
+	while ((i = read (fd_vmlinux, buf, sizeof buf)) > 0)
+		if (write (fd_outfile, buf, i) != i)
+			die ("write vmlinux");
+	if (write (fd_outfile, initrd_header, sizeof initrd_header) != sizeof initrd_header)
+		die ("write initrd header");
+	while ((i = read (fd_initrd, buf, sizeof buf)) > 0)
+		if (write (fd_outfile, buf, i) != i)
+			die ("write initrd");
+	close (fd_vmlinux);
+	close (fd_initrd);
+	return 0;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/boot/ecoff.h linux/arch/mips/boot/ecoff.h
--- v2.3.8/linux/arch/mips/boot/ecoff.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/boot/ecoff.h	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,62 @@
+/*
+ * Some ECOFF definitions.
+ */
+typedef struct filehdr {
+        unsigned short  f_magic;        /* magic number */
+        unsigned short  f_nscns;        /* number of sections */
+        long            f_timdat;       /* time & date stamp */
+        long            f_symptr;       /* file pointer to symbolic header */
+        long            f_nsyms;        /* sizeof(symbolic hdr) */
+        unsigned short  f_opthdr;       /* sizeof(optional hdr) */
+        unsigned short  f_flags;        /* flags */
+} FILHDR;
+#define FILHSZ  sizeof(FILHDR)
+
+#define OMAGIC		0407
+#define MIPSEBMAGIC	0x160
+#define MIPSELMAGIC	0x162
+
+typedef struct scnhdr {
+        char            s_name[8];      /* section name */
+        long            s_paddr;        /* physical address, aliased s_nlib */
+        long            s_vaddr;        /* virtual address */
+        long            s_size;         /* section size */
+        long            s_scnptr;       /* file ptr to raw data for section */
+        long            s_relptr;       /* file ptr to relocation */
+        long            s_lnnoptr;      /* file ptr to gp histogram */
+        unsigned short  s_nreloc;       /* number of relocation entries */
+        unsigned short  s_nlnno;        /* number of gp histogram entries */
+        long            s_flags;        /* flags */
+} SCNHDR;
+#define SCNHSZ		sizeof(SCNHDR)
+#define SCNROUND	((long)16)
+
+typedef struct aouthdr {
+        short   magic;          /* see above                            */
+        short   vstamp;         /* version stamp                        */
+        long    tsize;          /* text size in bytes, padded to DW bdry*/
+        long    dsize;          /* initialized data "  "                */
+        long    bsize;          /* uninitialized data "   "             */
+        long    entry;          /* entry pt.                            */
+        long    text_start;     /* base of text used for this file      */
+        long    data_start;     /* base of data used for this file      */
+        long    bss_start;      /* base of bss used for this file       */
+        long    gprmask;        /* general purpose register mask        */
+        long    cprmask[4];     /* co-processor register masks          */
+        long    gp_value;       /* the gp value used for this object    */
+} AOUTHDR;
+#define AOUTHSZ sizeof(AOUTHDR)
+
+#define OMAGIC		0407
+#define NMAGIC		0410
+#define ZMAGIC		0413
+#define SMAGIC		0411
+#define LIBMAGIC        0443
+
+#define N_TXTOFF(f, a) \
+ ((a).magic == ZMAGIC || (a).magic == LIBMAGIC ? 0 : \
+  ((a).vstamp < 23 ? \
+   ((FILHSZ + AOUTHSZ + (f).f_nscns * SCNHSZ + 7) & 0xfffffff8) : \
+   ((FILHSZ + AOUTHSZ + (f).f_nscns * SCNHSZ + SCNROUND-1) & ~(SCNROUND-1)) ) )
+#define N_DATOFF(f, a) \
+  N_TXTOFF(f, a) + (a).tsize;
diff -u --recursive --new-file v2.3.8/linux/arch/mips/boot/elf2ecoff.c linux/arch/mips/boot/elf2ecoff.c
--- v2.3.8/linux/arch/mips/boot/elf2ecoff.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/boot/elf2ecoff.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,637 @@
+/*
+ * Copyright (c) 1995
+ *	Ted Lemon (hereinafter referred to as the author)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* elf2ecoff.c
+
+   This program converts an elf executable to an ECOFF executable.
+   No symbol table is retained.   This is useful primarily in building
+   net-bootable kernels for machines (e.g., DECstation and Alpha) which
+   only support the ECOFF object file format. */
+
+#include <stdio.h>
+#include <string.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <elf.h>
+#include <limits.h>
+
+#include "ecoff.h"
+
+/*
+ * Some extra ELF definitions
+ */
+#define PT_MIPS_REGINFO 0x70000000      /* Register usage information */
+
+/* -------------------------------------------------------------------- */
+
+struct sect {
+  unsigned long vaddr;
+  unsigned long len;
+};
+
+int phcmp ();
+char *saveRead (int file, off_t offset, off_t len, char *name);
+int copy (int, int, off_t, off_t);
+int translate_syms (int, int, off_t, off_t, off_t, off_t);
+void convert_elf_hdr (Elf32_Ehdr *);
+void convert_elf_phdrs (Elf32_Phdr *, int);
+void convert_elf_shdrs (Elf32_Shdr *, int);
+void convert_ecoff_filehdr(struct filehdr *);
+void convert_ecoff_aouthdr(struct aouthdr *);
+void convert_ecoff_esecs(struct scnhdr *, int);
+extern int errno;
+int *symTypeTable;
+int must_convert_endian = 0;
+int format_bigendian = 0;
+
+main (int argc, char **argv, char **envp)
+{
+  Elf32_Ehdr ex;
+  Elf32_Phdr *ph;
+  Elf32_Shdr *sh;
+  Elf32_Sym *symtab;
+  char *shstrtab;
+  int strtabix, symtabix;
+  int i, pad;
+  struct sect text, data, bss;
+  struct filehdr efh;
+  struct aouthdr eah;
+  struct scnhdr esecs [6];
+  int infile, outfile;
+  unsigned long cur_vma = ULONG_MAX;
+  int addflag = 0;
+  int nosecs;
+
+  text.len = data.len = bss.len = 0;
+  text.vaddr = data.vaddr = bss.vaddr = 0;
+
+  /* Check args... */
+  if (argc < 3 || argc > 4)
+    {
+    usage:
+      fprintf (stderr,
+	       "usage: elf2aout <elf executable> <a.out executable> [-a]\n");
+      exit (1);
+    }
+  if (argc == 4)
+    {
+      if (strcmp (argv [3], "-a"))
+	goto usage;
+      addflag = 1;
+    }
+
+  /* Try the input file... */
+  if ((infile = open (argv [1], O_RDONLY)) < 0)
+    {
+      fprintf (stderr, "Can't open %s for read: %s\n",
+	       argv [1], strerror (errno));
+      exit (1);
+    }
+
+  /* Read the header, which is at the beginning of the file... */
+  i = read (infile, &ex, sizeof ex);
+  if (i != sizeof ex)
+    {
+      fprintf (stderr, "ex: %s: %s.\n",
+	       argv [1], i ? strerror (errno) : "End of file reached");
+      exit (1);
+    }
+
+  if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
+	format_bigendian = 1;
+
+  if (ntohs (0xaa55) == 0xaa55) {
+	if (!format_bigendian)
+		must_convert_endian = 1;
+  } else {
+	if (format_bigendian)
+		must_convert_endian = 1;
+  }
+  if (must_convert_endian)
+	convert_elf_hdr (&ex);
+
+  /* Read the program headers... */
+  ph = (Elf32_Phdr *)saveRead (infile, ex.e_phoff,
+				ex.e_phnum * sizeof (Elf32_Phdr), "ph");
+  if (must_convert_endian)
+	convert_elf_phdrs (ph, ex.e_phnum);
+  /* Read the section headers... */
+  sh = (Elf32_Shdr *)saveRead (infile, ex.e_shoff,
+				ex.e_shnum * sizeof (Elf32_Shdr), "sh");
+  if (must_convert_endian)
+	convert_elf_shdrs (sh, ex.e_shnum);
+  /* Read in the section string table. */
+  shstrtab = saveRead (infile, sh [ex.e_shstrndx].sh_offset,
+		       sh [ex.e_shstrndx].sh_size, "shstrtab");
+
+  /* Figure out if we can cram the program header into an ECOFF
+     header...  Basically, we can't handle anything but loadable
+     segments, but we can ignore some kinds of segments.  We can't
+     handle holes in the address space.  Segments may be out of order,
+     so we sort them first. */
+
+  qsort (ph, ex.e_phnum, sizeof (Elf32_Phdr), phcmp);
+
+  for (i = 0; i < ex.e_phnum; i++)
+    {
+      /* Section types we can ignore... */
+      if (ph [i].p_type == PT_NULL || ph [i].p_type == PT_NOTE ||
+	  ph [i].p_type == PT_PHDR || ph [i].p_type == PT_MIPS_REGINFO)
+	continue;
+      /* Section types we can't handle... */
+      else if (ph [i].p_type != PT_LOAD)
+        {
+	  fprintf (stderr, "Program header %d type %d can't be converted.\n");
+	  exit (1);
+	}
+      /* Writable (data) segment? */
+      if (ph [i].p_flags & PF_W)
+	{
+	  struct sect ndata, nbss;
+
+	  ndata.vaddr = ph [i].p_vaddr;
+	  ndata.len = ph [i].p_filesz;
+	  nbss.vaddr = ph [i].p_vaddr + ph [i].p_filesz;
+	  nbss.len = ph [i].p_memsz - ph [i].p_filesz;
+
+	  combine (&data, &ndata, 0);
+	  combine (&bss, &nbss, 1);
+	}
+      else
+	{
+	  struct sect ntxt;
+
+	  ntxt.vaddr = ph [i].p_vaddr;
+	  ntxt.len = ph [i].p_filesz;
+
+	  combine (&text, &ntxt, 0);
+	}
+      /* Remember the lowest segment start address. */
+      if (ph [i].p_vaddr < cur_vma)
+	cur_vma = ph [i].p_vaddr;
+    }
+
+  /* Sections must be in order to be converted... */
+  if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
+      text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr)
+    {
+      fprintf (stderr, "Sections ordering prevents a.out conversion.\n");
+      exit (1);
+    }
+
+  /* If there's a data section but no text section, then the loader
+     combined everything into one section.   That needs to be the
+     text section, so just make the data section zero length following
+     text. */
+  if (data.len && !text.len)
+    {
+      text = data;
+      data.vaddr = text.vaddr + text.len;
+      data.len = 0;
+    }
+
+  /* If there is a gap between text and data, we'll fill it when we copy
+     the data, so update the length of the text segment as represented in
+     a.out to reflect that, since a.out doesn't allow gaps in the program
+     address space. */
+  if (text.vaddr + text.len < data.vaddr)
+    text.len = data.vaddr - text.vaddr;
+
+  /* We now have enough information to cons up an a.out header... */
+  eah.magic = OMAGIC;
+  eah.vstamp = 200;
+  eah.tsize = text.len;
+  eah.dsize = data.len;
+  eah.bsize = bss.len;
+  eah.entry = ex.e_entry;
+  eah.text_start = text.vaddr;
+  eah.data_start = data.vaddr;
+  eah.bss_start = bss.vaddr;
+  eah.gprmask = 0xf3fffffe;
+  memset (&eah.cprmask, '\0', sizeof eah.cprmask);
+  eah.gp_value = 0; /* unused. */
+
+  if (format_bigendian)
+    efh.f_magic = MIPSEBMAGIC;
+  else
+    efh.f_magic = MIPSELMAGIC;
+  if (addflag)
+    nosecs = 6;
+  else
+    nosecs = 3;
+  efh.f_nscns = nosecs;
+  efh.f_timdat = 0;	/* bogus */
+  efh.f_symptr = 0;
+  efh.f_nsyms = 0;
+  efh.f_opthdr = sizeof eah;
+  efh.f_flags = 0x100f; /* Stripped, not sharable. */
+
+  memset (esecs, 0, sizeof esecs);
+  strcpy (esecs [0].s_name, ".text");
+  strcpy (esecs [1].s_name, ".data");
+  strcpy (esecs [2].s_name, ".bss");
+  if (addflag) {
+    strcpy (esecs [3].s_name, ".rdata");
+    strcpy (esecs [4].s_name, ".sdata");
+    strcpy (esecs [5].s_name, ".sbss");
+  }
+  esecs [0].s_paddr = esecs [0].s_vaddr = eah.text_start;
+  esecs [1].s_paddr = esecs [1].s_vaddr = eah.data_start;
+  esecs [2].s_paddr = esecs [2].s_vaddr = eah.bss_start;
+  if (addflag) {
+    esecs [3].s_paddr = esecs [3].s_vaddr = 0;
+    esecs [4].s_paddr = esecs [4].s_vaddr = 0;
+    esecs [5].s_paddr = esecs [5].s_vaddr = 0;
+  }
+  esecs [0].s_size = eah.tsize;
+  esecs [1].s_size = eah.dsize;
+  esecs [2].s_size = eah.bsize;
+  if (addflag) {
+    esecs [3].s_size = 0;
+    esecs [4].s_size = 0;
+    esecs [5].s_size = 0;
+  }
+  esecs [0].s_scnptr = N_TXTOFF (efh, eah);
+  esecs [1].s_scnptr = N_DATOFF (efh, eah);
+#define ECOFF_SEGMENT_ALIGNMENT(a) 0x10
+#define ECOFF_ROUND(s,a) (((s)+(a)-1)&~((a)-1))
+  esecs [2].s_scnptr = esecs [1].s_scnptr +
+	  ECOFF_ROUND (esecs [1].s_size, ECOFF_SEGMENT_ALIGNMENT (&eah));
+  if (addflag) {
+    esecs [3].s_scnptr = 0;
+    esecs [4].s_scnptr = 0;
+    esecs [5].s_scnptr = 0;
+  }
+  esecs [0].s_relptr = esecs [1].s_relptr
+	  = esecs [2].s_relptr = 0;
+  esecs [0].s_lnnoptr = esecs [1].s_lnnoptr
+	  = esecs [2].s_lnnoptr = 0;
+  esecs [0].s_nreloc = esecs [1].s_nreloc = esecs [2].s_nreloc = 0;
+  esecs [0].s_nlnno = esecs [1].s_nlnno = esecs [2].s_nlnno = 0;
+  if (addflag) {
+    esecs [3].s_relptr = esecs [4].s_relptr 
+  	  = esecs [5].s_relptr = 0;
+    esecs [3].s_lnnoptr = esecs [4].s_lnnoptr
+	  = esecs [5].s_lnnoptr = 0;
+    esecs [3].s_nreloc = esecs [4].s_nreloc = esecs [5].s_nreloc = 0;
+    esecs [3].s_nlnno = esecs [4].s_nlnno = esecs [5].s_nlnno = 0;
+  }
+  esecs [0].s_flags = 0x20;
+  esecs [1].s_flags = 0x40;
+  esecs [2].s_flags = 0x82;
+  if (addflag) {
+    esecs [3].s_flags = 0x100;
+    esecs [4].s_flags = 0x200;
+    esecs [5].s_flags = 0x400;
+  }
+
+  /* Make the output file... */
+  if ((outfile = open (argv [2], O_WRONLY | O_CREAT, 0777)) < 0)
+    {
+      fprintf (stderr, "Unable to create %s: %s\n", argv [2], strerror (errno));
+      exit (1);
+    }
+
+  if (must_convert_endian)
+	convert_ecoff_filehdr (&efh);
+  /* Write the headers... */
+  i = write (outfile, &efh, sizeof efh);
+  if (i != sizeof efh)
+    {
+      perror ("efh: write");
+      exit (1);
+
+    for (i = 0; i < nosecs; i++)
+      {
+        printf ("Section %d: %s phys %x  size %x  file offset %x\n", 
+	      i, esecs [i].s_name, esecs [i].s_paddr,
+	      esecs [i].s_size, esecs [i].s_scnptr);
+      }
+    }
+  fprintf (stderr, "wrote %d byte file header.\n", i);
+
+  if (must_convert_endian)
+	convert_ecoff_aouthdr (&eah);
+  i = write (outfile, &eah, sizeof eah);
+  if (i != sizeof eah)
+    {
+      perror ("eah: write");
+      exit (1);
+    }
+  fprintf (stderr, "wrote %d byte a.out header.\n", i);
+
+  if (must_convert_endian)
+	convert_ecoff_esecs (&esecs[0], nosecs);
+  i = write (outfile, &esecs, nosecs * sizeof(struct scnhdr));
+  if (i != nosecs * sizeof(struct scnhdr))
+    {
+      perror ("esecs: write");
+      exit (1);
+    }
+  fprintf (stderr, "wrote %d bytes of section headers.\n", i);
+
+  if (pad = ((sizeof efh + sizeof eah + nosecs * sizeof(struct scnhdr)) & 15))
+    {
+      pad = 16 - pad;
+      i = write (outfile, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", pad);
+      if (i < 0)
+	{
+	  perror ("ipad: write");
+	  exit (1);
+	}
+      fprintf (stderr, "wrote %d byte pad.\n", i);
+    }
+
+  /* Copy the loadable sections.   Zero-fill any gaps less than 64k;
+     complain about any zero-filling, and die if we're asked to zero-fill
+     more than 64k. */
+  for (i = 0; i < ex.e_phnum; i++)
+    {
+      /* Unprocessable sections were handled above, so just verify that
+	 the section can be loaded before copying. */
+      if (ph [i].p_type == PT_LOAD && ph [i].p_filesz)
+	{
+	  if (cur_vma != ph [i].p_vaddr)
+	    {
+	      unsigned long gap = ph [i].p_vaddr - cur_vma;
+	      char obuf [1024];
+	      if (gap > 65536)
+		{
+		  fprintf (stderr, "Intersegment gap (%d bytes) too large.\n",
+			   gap);
+		  exit (1);
+		}
+	      fprintf (stderr, "Warning: %d byte intersegment gap.\n", gap);
+	      memset (obuf, 0, sizeof obuf);
+	      while (gap)
+		{
+		  int count = write (outfile, obuf, (gap > sizeof obuf
+						     ? sizeof obuf : gap));
+		  if (count < 0)
+		    {
+		      fprintf (stderr, "Error writing gap: %s\n",
+			       strerror (errno));
+		      exit (1);
+		    }
+		  gap -= count;
+		}
+	    }
+fprintf (stderr, "writing %d bytes...\n", ph [i].p_filesz);
+	  copy (outfile, infile, ph [i].p_offset, ph [i].p_filesz);
+	  cur_vma = ph [i].p_vaddr + ph [i].p_filesz;
+	}
+    }
+
+   /*
+     * Write a page of padding for boot PROMS that read entire pages.
+     * Without this, they may attempt to read past the end of the
+     * data section, incur an error, and refuse to boot.
+     */
+    {
+	char obuf[4096];
+	memset(obuf, 0, sizeof obuf);
+	if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
+	    fprintf(stderr, "Error writing PROM padding: %s\n",
+		    strerror(errno));
+	    exit(1);
+	}
+    }
+
+  /* Looks like we won... */
+  exit (0);
+}
+
+copy (out, in, offset, size)
+     int out, in;
+     off_t offset, size;
+{
+  char ibuf [4096];
+  int remaining, cur, count;
+
+  /* Go the the start of the ELF symbol table... */
+  if (lseek (in, offset, SEEK_SET) < 0)
+    {
+      perror ("copy: lseek");
+      exit (1);
+    }
+
+  remaining = size;
+  while (remaining)
+    {
+      cur = remaining;
+      if (cur > sizeof ibuf)
+	cur = sizeof ibuf;
+      remaining -= cur;
+      if ((count = read (in, ibuf, cur)) != cur)
+	{
+	  fprintf (stderr, "copy: read: %s\n",
+		   count ? strerror (errno) : "premature end of file");
+	  exit (1);
+	}
+      if ((count = write (out, ibuf, cur)) != cur)
+	{
+	  perror ("copy: write");
+	  exit (1);
+	}
+    }
+}
+
+/* Combine two segments, which must be contiguous.   If pad is true, it's
+   okay for there to be padding between. */
+combine (base, new, pad)
+     struct sect *base, *new;
+     int pad;
+{
+  if (!base -> len)
+    *base = *new;
+  else if (new -> len)
+    {
+      if (base -> vaddr + base -> len != new -> vaddr)
+	{
+	  if (pad)
+	    base -> len = new -> vaddr - base -> vaddr;
+	  else
+	    {
+	      fprintf (stderr,
+		       "Non-contiguous data can't be converted.\n");
+	      exit (1);
+	    }
+	}
+      base -> len += new -> len;
+    }
+}
+
+phcmp (h1, h2)
+     Elf32_Phdr *h1, *h2;
+{
+  if (h1 -> p_vaddr > h2 -> p_vaddr)
+    return 1;
+  else if (h1 -> p_vaddr < h2 -> p_vaddr)
+    return -1;
+  else
+    return 0;
+}
+
+char *saveRead (int file, off_t offset, off_t len, char *name)
+{
+  char *tmp;
+  int count;
+  off_t off;
+  if ((off = lseek (file, offset, SEEK_SET)) < 0)
+    {
+      fprintf (stderr, "%s: fseek: %s\n", name, strerror (errno));
+      exit (1);
+    }
+  if (!(tmp = (char *)malloc (len)))
+    {
+      fprintf (stderr, "%s: Can't allocate %d bytes.\n", name, len);
+      exit (1);
+    }
+  count = read (file, tmp, len);
+  if (count != len)
+    {
+      fprintf (stderr, "%s: read: %s.\n",
+	       name, count ? strerror (errno) : "End of file reached");
+      exit (1);
+    }
+  return tmp;
+}
+
+#define swab16(x) \
+	((unsigned short)( \
+		(((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \
+		(((unsigned short)(x) & (unsigned short)0xff00U) >> 8) ))
+
+#define swab32(x) \
+	((unsigned int)( \
+		(((unsigned int)(x) & (unsigned int)0x000000ffUL) << 24) | \
+		(((unsigned int)(x) & (unsigned int)0x0000ff00UL) <<  8) | \
+		(((unsigned int)(x) & (unsigned int)0x00ff0000UL) >>  8) | \
+		(((unsigned int)(x) & (unsigned int)0xff000000UL) >> 24) ))
+
+void convert_elf_hdr (Elf32_Ehdr *e)
+{
+	e->e_type      = swab16(e->e_type);
+	e->e_machine   = swab16(e->e_machine);
+	e->e_version   = swab32(e->e_version);
+	e->e_entry     = swab32(e->e_entry);
+	e->e_phoff     = swab32(e->e_phoff);
+	e->e_shoff     = swab32(e->e_shoff);
+	e->e_flags     = swab32(e->e_flags);
+	e->e_ehsize    = swab16(e->e_ehsize);
+	e->e_phentsize = swab16(e->e_phentsize);
+	e->e_phnum     = swab16(e->e_phnum);
+	e->e_shentsize = swab16(e->e_shentsize);
+	e->e_shnum     = swab16(e->e_shnum);
+	e->e_shstrndx  = swab16(e->e_shstrndx);
+}
+
+void convert_elf_phdrs (Elf32_Phdr *p, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++,p++) {
+		p->p_type   = swab32(p->p_type);
+		p->p_offset = swab32(p->p_offset);
+		p->p_vaddr  = swab32(p->p_vaddr);
+		p->p_paddr  = swab32(p->p_paddr);
+		p->p_filesz = swab32(p->p_filesz);
+		p->p_memsz  = swab32(p->p_memsz);
+		p->p_flags  = swab32(p->p_flags);
+		p->p_align  = swab32(p->p_align);
+	}
+
+}
+
+void convert_elf_shdrs (Elf32_Shdr *s, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++,s++) {
+		s->sh_name      = swab32(s->sh_name);
+		s->sh_type      = swab32(s->sh_type);
+		s->sh_flags     = swab32(s->sh_flags);
+		s->sh_addr      = swab32(s->sh_addr);
+		s->sh_offset    = swab32(s->sh_offset);
+		s->sh_size      = swab32(s->sh_size);
+		s->sh_link      = swab32(s->sh_link);
+		s->sh_info      = swab32(s->sh_info);
+		s->sh_addralign = swab32(s->sh_addralign);
+		s->sh_entsize   = swab32(s->sh_entsize);
+	}
+}
+
+void convert_ecoff_filehdr(struct filehdr *f)
+{
+	f->f_magic  = swab16(f->f_magic);
+	f->f_nscns  = swab16(f->f_nscns);
+	f->f_timdat = swab32(f->f_timdat);
+	f->f_symptr = swab32(f->f_symptr);
+	f->f_nsyms  = swab32(f->f_nsyms);
+	f->f_opthdr = swab16(f->f_opthdr);
+	f->f_flags  = swab16(f->f_flags);
+}
+
+void convert_ecoff_aouthdr(struct aouthdr *a)
+{
+	a->magic      = swab16(a->magic);
+	a->vstamp     = swab16(a->vstamp);
+	a->tsize      = swab32(a->tsize);
+	a->dsize      = swab32(a->dsize);
+	a->bsize      = swab32(a->bsize);
+	a->entry      = swab32(a->entry);
+	a->text_start = swab32(a->text_start);
+	a->data_start = swab32(a->data_start);
+	a->bss_start  = swab32(a->bss_start);
+	a->gprmask    = swab32(a->gprmask);
+	a->cprmask[0] = swab32(a->cprmask[0]);
+	a->cprmask[1] = swab32(a->cprmask[1]);
+	a->cprmask[2] = swab32(a->cprmask[2]);
+	a->cprmask[3] = swab32(a->cprmask[3]);
+	a->gp_value   = swab32(a->gp_value);
+}
+
+void convert_ecoff_esecs(struct scnhdr *s, int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++, s++) {
+		s->s_paddr   = swab32(s->s_paddr);
+		s->s_vaddr   = swab32(s->s_vaddr);
+		s->s_size    = swab32(s->s_size);
+		s->s_scnptr  = swab32(s->s_scnptr);
+		s->s_relptr  = swab32(s->s_relptr);
+		s->s_lnnoptr = swab32(s->s_lnnoptr);
+		s->s_nreloc  = swab16(s->s_nreloc);
+		s->s_nlnno   = swab16(s->s_nlnno);
+		s->s_flags   = swab32(s->s_flags);
+	}
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.3.8/linux/arch/mips/config.in	Mon Feb  1 12:03:20 1999
+++ linux/arch/mips/config.in	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-#
+# $Id: config.in,v 1.27 1999/06/17 13:25:44 ralf Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -14,6 +14,8 @@
 bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool 'Support for Algorithmics P4032' CONFIG_ALGOR_P4032
+  bool 'Support for BAGET MIPS series' CONFIG_BAGET_MIPS
+  bool 'Support for DECstations' CONFIG_DECSTATION
 fi
 bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000
 bool 'Support for Olivetti M700-10' CONFIG_OLIVETTI_M700
@@ -33,14 +35,13 @@
 if [ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
      "$CONFIG_OLIVETTI_M700" = "y" ]; then
 	define_bool CONFIG_MIPS_JAZZ y
-	define_bool CONFIG_VIDEO_G364 y
-	define_bool CONFIG_VGA_CONSOLE y
+	define_bool CONFIG_FB y
+	define_bool CONFIG_FB_G364 y	
 fi
 if [ "$CONFIG_ACER_PICA_61" = "y" ]; then
 	define_bool CONFIG_MIPS_JAZZ y
 fi
 if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then
-	define_bool CONFIG_VGA_CONSOLE y
 	define_bool CONFIG_PCI y
 fi
 endmenu
@@ -61,14 +62,23 @@
 
 mainmenu_option next_comment
 comment 'General setup'
+
+if [ "$CONFIG_PCI" = "y" ]; then
+  bool '   PCI quirks' CONFIG_PCI_QUIRKS
+  if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool '   PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+  fi
+  bool '   Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
+fi
+
 if [ "$CONFIG_DECSTATION" = "y" ]; then
-  bool 'Compile the kernel into the ECOFF object format' CONFIG_ECOFF_KERNEL
   define_bool CONFIG_CPU_LITTLE_ENDIAN y
 else
-  define_bool CONFIG_ELF_KERNEL y
   bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
 fi
 
+define_bool CONFIG_ELF_KERNEL y
+
 if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
   define_bool CONFIG_BINFMT_IRIX y
   define_bool CONFIG_FORWARD_KEYBOARD y
@@ -76,17 +86,13 @@
 define_bool CONFIG_BINFMT_AOUT n
 define_bool CONFIG_BINFMT_ELF y
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
-fi
 
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
 bool 'Sysctl support' CONFIG_SYSCTL
 
-if [ "$CONFIG_SGI" != "y" ]; then
+if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
   tristate 'Parallel port support' CONFIG_PARPORT
 fi
 endmenu
@@ -105,6 +111,20 @@
 
 endmenu
 
+if [ "$CONFIG_DECSTATION" = "y" ]; then
+	mainmenu_option next_comment
+	comment 'TURBOchannel support'
+		bool 'TURBOchannel support' CONFIG_TC
+#		if [ "$CONFIG_TC" = "y" ]; then
+# 			tristate 'MAGMA Parallel port support' CONFIG_PARPORT
+#		fi
+	endmenu
+fi
+
+source drivers/i2o/Config.in
+
+source drivers/pnp/Config.in
+
 source drivers/block/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
@@ -117,7 +137,7 @@
 tristate 'SCSI support' CONFIG_SCSI
 
 if [ "$CONFIG_SCSI" != "n" ]; then
-	if [ "$CONFIG_SGI" = "y" ]; then
+	if [ "$CONFIG_SGI" = "y" -o "$CONFIG_DECSTATION" = "y" ]; then
 		comment 'SCSI support type (disk, tape, CDrom)'
 
 		dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
@@ -133,9 +153,15 @@
 
 		#mainmenu_option next_comment
 		comment 'SCSI low-level drivers'
-
+		if [ "$CONFIG_SGI" = "y" ]; then
 		dep_tristate 'SGI wd93 Scsi Driver' CONFIG_SCSI_SGIWD93 $CONFIG_SCSI
 	else
+			if [ "$CONFIG_TC" = "y" ]; then
+				dep_tristate 'DEC NCR53C94 Scsi Driver' CONFIG_SCSI_DECNCR $CONFIG_SCSI
+			fi
+			dep_tristate 'DEC SII Scsi Driver' CONFIG_SCSI_DECSII $CONFIG_SCSI
+		fi
+	else
 		source drivers/scsi/Config.in
 	fi
 fi
@@ -147,7 +173,7 @@
 
   bool 'Network device support' CONFIG_NETDEVICES
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    if [ "$CONFIG_SGI" != "y" ]; then
+    if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
 	source drivers/net/Config.in
     else
 	tristate 'Dummy net driver support' CONFIG_DUMMY
@@ -160,52 +186,113 @@
 	if [ ! "$CONFIG_PPP" = "n" ]; then
 	  comment 'CCP compressors for PPP are only built as modules.'
 	fi
+        if [ "$CONFIG_SGI" = "y" ]; then
 	bool 'SGI Seeq ethernet controller support' CONFIG_SGISEEQ
     fi
+	if [ "$CONFIG_DECSTATION" = "y" ]; then
+          bool 'DEC LANCE ethernet controller support' CONFIG_DECLANCE
+        fi
+	if [ "$CONFIG_BAGET_MIPS" = "y" ]; then
+	  tristate 'Baget AMD LANCE support' CONFIG_BAGETLANCE
+	  tristate 'Baget Backplane Shared Memory support' CONFIG_BAGETBSM
+	fi
+    fi
   fi
   endmenu
 fi
 
-if [ "$CONFIG_SGI" != "y" ]; then
-	source drivers/net/hamradio/Config.in
+if [ "$CONFIG_SGI" != "y" -a "$CONFIG_DECSTATION" != "y" -a "$CONFIG_BAGET_MIPS" != "y" ]; then
+  source drivers/net/hamradio/Config.in
 
-	mainmenu_option next_comment
-	comment 'ISDN subsystem'
 
-	tristate 'ISDN support' CONFIG_ISDN
-	if [ "$CONFIG_ISDN" != "n" ]; then
-	  source drivers/isdn/Config.in
-	fi
-	endmenu
+  mainmenu_option next_comment
+  comment 'ISDN subsystem'
 
-	mainmenu_option next_comment
-	comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+  if [ "$CONFIG_NET" != "n" ]; then
+    tristate 'ISDN support' CONFIG_ISDN
+    if [ "$CONFIG_ISDN" != "n" ]; then
+      source drivers/isdn/Config.in
+    fi
+  fi
+  endmenu
 
-	bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
-	if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-	  source drivers/cdrom/Config.in
-	fi
-	endmenu
+
+  mainmenu_option next_comment
+  comment comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+
+  bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
+  if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+    source drivers/cdrom/Config.in
+  fi
+  endmenu
+fi
+
+if [ "$CONFIG_DECSTATION" != "y" ]; then
+  source drivers/char/Config.in
+else
+  mainmenu_option next_comment
+  comment 'DECstation Character devices'
+
+  bool 'Virtual terminal' CONFIG_VT
+  if [ "$CONFIG_VT" = "y" ]; then
+    bool 'Support for console on virtual terminal' CONFIG_VT_CONSOLE
+  fi
+  tristate 'Standard/generic (dumb) serial support' CONFIG_SERIAL
+  if [ "$CONFIG_SGI" = "y" ]; then
+    bool 'SGI PROM Console Support' CONFIG_SGI_PROM_CONSOLE
+  fi
+  if [ "$CONFIG_SERIAL" = "y" ]; then
+    bool 'DZ11 Serial Support' CONFIG_DZ
+    if [ "$CONFIG_TC" = "y" ]; then
+      bool 'Z85C30 Serial Support' CONFIG_ZS
+    fi
+    bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+  fi
+  bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+  if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+    int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+  fi
+  bool 'Keyboard Support' CONFIG_KEYBOARD
+  bool 'Mouse Support' CONFIG_MOUSE
+#    bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+  endmenu
 fi
 
-source drivers/char/Config.in
+source drivers/usb/Config.in
 
 source fs/Config.in
 
-comment 'Console drivers'
-source drivers/video/Config.in
+if [ "$CONFIG_VT" = "y" ]; then
+  mainmenu_option next_comment
+  comment 'Console drivers'
+  if [ "$CONFIG_SGI" = "y" ]; then
+    tristate 'SGI Newport Console support' CONFIG_SGI_NEWPORT_CONSOLE
+    if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then
+      define_bool CONFIG_DUMMY_CONSOLE y
+    fi
+  else
+    if [ "$CONFIG_DECSTATION" != "y" ]; then
+    bool 'VGA text console' CONFIG_VGA_CONSOLE
+    fi
+    bool 'Support for frame buffer devices' CONFIG_FB
+    source drivers/video/Config.in
+  fi
+  endmenu
+fi
 
-mainmenu_option next_comment
-comment 'Sound'
+if [ "$CONFIG_DECSTATION" != "y" ]; then
+  mainmenu_option next_comment
+  comment 'Sound'
 
-tristate 'Sound card support' CONFIG_SOUND
-if [ "$CONFIG_SOUND" != "n" ]; then
+  tristate 'Sound card support' CONFIG_SOUND
+  if [ "$CONFIG_SOUND" != "n" ]; then
   source drivers/sound/Config.in
+  fi
+  endmenu
 fi
-endmenu
 
 if [ "$CONFIG_SGI" = "y" ]; then
-  source drivers/sgi/char/Config.in
+  source drivers/sgi/Config.in
 fi
 
 mainmenu_option next_comment
@@ -216,6 +303,8 @@
 if [ "$CONFIG_MODULES" = "y" ]; then
   bool ' Build fp execption handler module' CONFIG_MIPS_FPE_MODULE
 fi
-bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
+if [ "$CONFIG_SERIAL" = "y" ]; then
+  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
+fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/Makefile linux/arch/mips/dec/Makefile
--- v2.3.8/linux/arch/mips/dec/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/Makefile	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,30 @@
+#
+# Makefile for the DECstation family specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+all: dec.o
+O_TARGET := dec.o
+O_OBJS	 := int-handler.o setup.o irq.o time.o reset.o rtc-dec.o wbflush.o
+
+ifdef CONFIG_PROM_CONSOLE
+O_OBJS   += promcon.o
+endif
+
+ifdef CONFIG_SERIAL
+O_OBJS   += serial.o
+endif
+
+int-handler.o:	int-handler.S
+
+clean:
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/boot/Makefile linux/arch/mips/dec/boot/Makefile
--- v2.3.8/linux/arch/mips/dec/boot/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/boot/Makefile	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,26 @@
+#
+# Makefile for the DECstation family specific parts of the kernel
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+netboot: all
+	mipsel-linux-ld -N -G 0 -T ld.ecoff ../../boot/zImage \
+		dec_boot.o ramdisk.img -o nbImage
+
+all: dec_boot.o
+
+O_TARGET := dec_boot.o
+O_OBJS	 := decstation.o
+
+clean:
+	rm -f nbImage
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/boot/decstation.c linux/arch/mips/dec/boot/decstation.c
--- v2.3.8/linux/arch/mips/dec/boot/decstation.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/boot/decstation.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,91 @@
+/*
+ * arch/mips/dec/decstation.c
+ */
+#include <linux/config.h>
+
+#define RELOC
+#define INITRD
+#define DEBUG_BOOT
+
+/*
+ * Magic number indicating REX PROM available on DECSTATION.
+ */
+#define	REX_PROM_MAGIC		0x30464354
+
+#define REX_PROM_CLEARCACHE	0x7c/4
+#define REX_PROM_PRINTF		0x30/4
+
+#define VEC_RESET		0xBFC00000		/* Prom base address */
+#define	PMAX_PROM_ENTRY(x)	(VEC_RESET+((x)*8))	/* Prom jump table */
+#define	PMAX_PROM_PRINTF	PMAX_PROM_ENTRY(17)
+
+#define PARAM	(k_start + 0x2000)
+
+#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
+#define INITRD_START (*(unsigned long *) (PARAM+0x218))
+#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
+
+extern int _ftext, _end;		/* begin and end of kernel image */
+extern void *__rd_start, *__rd_end;	/* begin and end of ramdisk image */
+extern void kernel_entry(int, char **, unsigned long, int *);
+
+void * memcpy(void * dest, const void *src, unsigned int count)
+{
+	unsigned long *tmp = (unsigned long *) dest, *s = (unsigned long *) src;
+
+	count >>= 2;
+	while (count--)
+		*tmp++ = *s++;
+
+	return dest;
+}
+
+void dec_entry(int argc, char **argv,
+	       unsigned long magic, int *prom_vec)
+{
+	void (*rex_clear_cache)(void);
+	int (*prom_printf)(char *, ...);
+	unsigned long k_start, len;
+
+	/*
+	 * The DS5100 leaves cpu with BEV enabled, clear it.
+	 */
+	asm(	"lui\t$8,0x3000\n\t"
+		"mtc0\t$8,$12\n\t"
+		".section\t.sdata\n\t"
+		".section\t.sbss\n\t"
+		".section\t.text"
+		: : : "$8");
+
+#ifdef DEBUG_BOOT
+	if (magic == REX_PROM_MAGIC) {
+	prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF);
+	} else {
+		prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF;
+	}
+	prom_printf("Launching kernel...\n");
+#endif
+
+	k_start = (unsigned long) (&kernel_entry) & 0xffff0000;
+
+#ifdef RELOC
+	/*
+	 * Now copy kernel image to it's destination.
+	 */
+	len = ((unsigned long) (&_end) - k_start);
+	memcpy((void *)k_start, &_ftext, len);
+#endif
+
+	if (magic == REX_PROM_MAGIC) {
+		rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE);
+		rex_clear_cache();
+	}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	LOADER_TYPE = 1;
+	INITRD_START = (long)&__rd_start;
+	INITRD_SIZE = (long)&__rd_end - (long)&__rd_start;
+#endif
+
+	kernel_entry(argc, argv, magic, prom_vec);
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/boot/ld.ecoff linux/arch/mips/dec/boot/ld.ecoff
--- v2.3.8/linux/arch/mips/dec/boot/ld.ecoff	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/boot/ld.ecoff	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,43 @@
+OUTPUT_FORMAT("ecoff-littlemips")
+OUTPUT_ARCH(mips)
+ENTRY(dec_entry)
+SECTIONS
+{
+  . = 0x80200000;
+
+  .text :
+  {
+    _ftext = .;
+    *(.text)
+    *(.fixup)
+  }
+  .rdata :
+  {
+    *(.rodata .rdata)
+  }
+  .data :
+  {
+    . = ALIGN(0x1000);
+    ramdisk.img (.data)
+    *(.data)
+  }
+  .sdata :
+  {
+    *(.sdata)
+  }
+  _gp = .;
+  .sbss :
+  {
+    *(.sbss)
+    *(.scommon)
+  }
+  .bss :
+  {
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  /DISCARD/ : {
+    *(.reginfo .mdebug .note)
+  }
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/int-handler.S linux/arch/mips/dec/int-handler.S
--- v2.3.8/linux/arch/mips/dec/int-handler.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/int-handler.S	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,362 @@
+/*
+ * arch/mips/dec/int-handler.S
+ *
+ * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen
+ *
+ * Written by Ralf Baechle and Andreas Busse, modified for DECStation
+ * support by Paul Antoine and Harald Koerfgen.
+ *
+ * completly rewritten:
+ * Copyright (C) 1998 Harald Koerfgen
+ *
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+#include <asm/addrspace.h>
+
+#include <asm/dec/interrupts.h>
+
+
+		.text
+		.set	noreorder
+/*
+ * decstation_handle_int: Interrupt handler for DECStations
+ *
+ * FIXME: Detection of spurious interrupts not yet implemented!
+ *
+ * We follow the model in the Indy interrupt code by David Miller, where he
+ * says: a lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop
+ *    and moving across all the pending IRQ bits in the cause
+ *    register is _NOT_ the answer, the common case is one
+ *    pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register
+ *    IRQ mask, that would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs
+ *    off, nothing in between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the DECStations look basically (barring
+ * software IRQs which we don't use at all) like...
+ *
+ * DS2100/3100's, aka kn01, aka Pmax:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        SCSI
+ *             3        Lance Ethernet
+ *             4        DZ11 serial
+ *             5        RTC
+ *             6        Memory Controller
+ *             7        FPU
+ *
+ * DS5000/200, aka kn02, aka 3max:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        TurboChannel
+ *             3        RTC
+ *             4        Reserved
+ *             5        Memory Controller
+ *             6        Reserved
+ *             7        FPU
+ *
+ * DS5000/1xx's, aka kn02ba, aka 3min:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        TurboChannel Slot 0
+ *             3        TurboChannel Slot 1
+ *             4        TurboChannel Slot 2
+ *             5        TurboChannel Slot 3 (ASIC)
+ *             6        Halt button
+ *             7        FPU
+ *
+ * DS5000/2x's, aka kn02ca, aka maxine:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        Periodic Interrupt (100usec)
+ *             3        RTC
+ *             4        I/O write timeout
+ *             5        TurboChannel (ASIC)
+ *             6        Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER)
+ *             7        FPU
+ *
+ * DS5000/2xx's, aka kn03, aka 3maxplus:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        System Board (ASIC)
+ *             3        RTC
+ *             4        Reserved
+ *             5        Memory
+ *             6        Halt Button
+ *             7        FPU
+ *
+ * We handle the IRQ according to _our_ priority.
+ * Priority is:
+ *
+ * Highest ----     RTC
+ *                  SCSI (if separate from TC)
+ *                  Ethernet (if separate from TC)
+ *		    Serial (if separate from TC)
+ *                  TurboChannel (if there is one!)
+ *                  Memory Controller (execept kmin)
+ * Lowest  ----     Halt (if there is one!)
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ *
+ */
+		.align	5
+		NESTED(decstation_handle_int, PT_SIZE, ra)
+		.set	noat
+		SAVE_ALL
+		CLI				# TEST: interrupts should be off
+		.set	at
+		.set	noreorder
+
+		/*
+		 * Get pending Interrupts
+		 */
+		mfc0	t0,CP0_CAUSE		# get pending interrupts
+		mfc0	t2,CP0_STATUS
+		la	t1,cpu_mask_tbl
+		and	t0,t2			# isolate allowed ones
+
+		/* insert detection of spurious interrupts here */
+
+		/*
+		 * Find irq with highest priority
+		 */
+1:		lw	t2,(t1)
+		move	t3,t0
+		and	t3,t2
+		beq	t3,zero,1b
+		 addu	t1,PTRSIZE		# delay slot
+
+		/*
+		 * Do the low-level stuff
+		 */
+		lw	a0,%lo(cpu_irq_nr-cpu_mask_tbl-PTRSIZE)(t1)
+		lw	t0,%lo(cpu_ivec_tbl-cpu_mask_tbl-PTRSIZE)(t1)
+		bgez	a0, handle_it		# irq_nr >= 0?
+						# irq_nr < 0: a0 contains an address
+		nop
+		jr	t0
+		 nop				# delay slot
+
+/*
+ * Handle "IRQ Controller" Interrupts
+ * Masked Interrupts are still visible and have to be masked "by hand".
+ * %hi(KN02_CSR_ADDR) does not work so all addresses are hardcoded :-(.
+ */
+		EXPORT(kn02_io_int)
+kn02_io_int:	lui	t0,0xbff0		# get interrupt status and mask
+		lw	t0,(t0)
+		la	t1,asic_mask_tbl
+		move	t3,t0
+		sll	t3,16			# shift interrupt status
+		b	find_int
+		 and	t0,t3			# mask out allowed ones
+
+		EXPORT(kn03_io_int)
+kn03_io_int:	lui	t2,0xbf84		# upper part of IOASIC Address
+		lw	t0,0x0110(t2)		# get status: IOASIC isr
+		lw	t3,0x0120(t2)		# get mask:   IOASIC isrm
+		la	t1,asic_mask_tbl
+		b	find_int
+		 and	t0,t3			# mask out allowed ones
+
+		EXPORT(kn02ba_io_int)
+kn02ba_io_int:	lui	t2,0xbc04		
+		lw	t0,0x0110(t2)		# IOASIC isr, works for maxine also
+		lw	t3,0x0120(t2)		# IOASIC isrm
+		la	t1,asic_mask_tbl
+		and	t0,t3
+
+		/*
+		 * Find irq with highest priority
+		 */
+find_int:	lw	t2,(t1)
+		move	t3,t0
+		and	t3,t2
+		beq	zero,t3,find_int
+		 addu	t1,PTRSIZE		# delay slot
+
+		/*
+		 * Do the low-level stuff
+		 */
+		lw	a0,%lo(asic_irq_nr-asic_mask_tbl-PTRSIZE)(t1)
+                nop
+
+handle_it:	jal	do_IRQ
+		 move	a1,sp
+		j	ret_from_irq
+		 nop
+		
+		END(decstation_handle_int)
+/*
+  * Interrupt routines common to all DECStations first.
+ */
+		EXPORT(dec_intr_fpu)
+dec_intr_fpu:	PANIC("Unimplemented FPU interrupt handler")
+
+/*
+ * Halt interrupt
+ */
+		EXPORT(intr_halt)
+intr_halt:	la	k0,0xbc000000
+		jr	k0
+		 nop
+
+/*
+ * Generic unimplemented interrupt routines - ivec_tbl is initialised to
+ * point all interrupts here.  The table is then filled in by machine-specific
+ * initialisation in dec_setup().
+ */
+		EXPORT(dec_intr_unimplemented)
+dec_intr_unimplemented:
+		mfc0	a1,CP0_CAUSE		# cheats way of printing an arg!
+		nop				# to be sure...
+		PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%x");
+
+		EXPORT(asic_intr_unimplemented)
+asic_intr_unimplemented:
+		move	a1,t0			# cheats way of printing an arg!
+		PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%x");
+
+/*
+ * FIXME: This interrupt vector table is experimental.  It is initialised with 
+ *	  *_intr_unimplemented and filled in with the addresses of
+ *	  machine-specific interrupt routines in dec_setup()  Paul 10/5/97.
+ *
+ *	  The mask_tbls contain the interrupt masks which are used. It is 
+ *	  initialised with all possible interrupt status bits set, so that 
+ * 	  unused Interrupts are catched.				Harald
+ */
+		.data
+		EXPORT(cpu_mask_tbl)
+cpu_mask_tbl:
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000		# these two are unlikely 
+		.word	0x00000000		# to be used
+		.word	0x0000ff00		# End of list
+
+		EXPORT(cpu_irq_nr)
+cpu_irq_nr:
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000
+		.word	0x00000000		# these two are unlikely 
+		.word	0x00000000		# to be used
+		.word	0x00ffffff		# End of list
+
+		EXPORT(cpu_ivec_tbl)
+cpu_ivec_tbl:
+		PTR	dec_intr_unimplemented
+		PTR	dec_intr_unimplemented
+		PTR	dec_intr_unimplemented
+		PTR	dec_intr_unimplemented
+		PTR	dec_intr_unimplemented
+		PTR	dec_intr_unimplemented
+		PTR	dec_intr_unimplemented	# these two are unlikely
+		PTR	dec_intr_unimplemented	# to be used
+		PTR	dec_intr_unimplemented	# EOL
+
+		EXPORT(asic_mask_tbl)
+asic_mask_tbl:
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0xffffffff			# EOL
+
+		EXPORT(asic_irq_nr)
+asic_irq_nr:
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0
+		.word	0xffffffff		# EOL
+
+
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/irq.c linux/arch/mips/dec/irq.c
--- v2.3.8/linux/arch/mips/dec/irq.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/irq.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,269 @@
+/*
+ * Code to handle DECstation IRQs plus some generic interrupt stuff.
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1994, 1995, 1996, 1997 Ralf Baechle
+ *
+ * $Id: irq.c,v 1.3 1999/04/11 17:06:16 harald Exp $
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timex.h>
+#include <linux/malloc.h>
+#include <linux/random.h>
+
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+
+extern volatile unsigned int *isr;	/* address of the interrupt status register     */
+extern volatile unsigned int *imr;	/* address of the interrupt mask register       */
+extern decint_t dec_interrupt[NR_INTS];
+
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+unsigned long spurious_count = 0;
+
+static inline void mask_irq(unsigned int irq_nr)
+{
+    unsigned int dummy;
+
+    if (dec_interrupt[irq_nr].iemask) {		/* This is an ASIC interrupt    */
+	*imr &= ~dec_interrupt[irq_nr].iemask;
+	dummy = *imr;
+	dummy = *imr;
+    } else			/* This is a cpu interrupt        */
+	set_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) & ~dec_interrupt[irq_nr].cpu_mask);
+}
+
+static inline void unmask_irq(unsigned int irq_nr)
+{
+    unsigned int dummy;
+
+    if (dec_interrupt[irq_nr].iemask) {		/* This is an ASIC interrupt    */
+	*imr |= dec_interrupt[irq_nr].iemask;
+	dummy = *imr;
+	dummy = *imr;
+    }
+    set_cp0_status(ST0_IM, read_32bit_cp0_register(CP0_STATUS) | dec_interrupt[irq_nr].cpu_mask);
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+    unsigned long flags;
+
+    save_and_cli(flags);
+    mask_irq(irq_nr);
+    restore_flags(flags);
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+    unsigned long flags;
+
+    save_and_cli(flags);
+    unmask_irq(irq_nr);
+    restore_flags(flags);
+}
+
+/*
+ * Pointers to the low-level handlers: first the general ones, then the
+ * fast ones, then the bad ones.
+ */
+extern void interrupt(void);
+
+static struct irqaction *irq_action[32] =
+{
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+int get_irq_list(char *buf)
+{
+    int i, len = 0;
+    struct irqaction *action;
+
+    for (i = 0; i < 32; i++) {
+	action = irq_action[i];
+	if (!action)
+	    continue;
+	len += sprintf(buf + len, "%2d: %8d %c %s",
+		       i, kstat.irqs[0][i],
+		       (action->flags & SA_INTERRUPT) ? '+' : ' ',
+		       action->name);
+	for (action = action->next; action; action = action->next) {
+	    len += sprintf(buf + len, ",%s %s",
+			   (action->flags & SA_INTERRUPT) ? " +" : "",
+			   action->name);
+	}
+	len += sprintf(buf + len, "\n");
+    }
+    return len;
+}
+
+atomic_t __mips_bh_counter;
+
+/*
+ * do_IRQ handles IRQ's that have been installed without the
+ * SA_INTERRUPT flag: it uses the full signal-handling return
+ * and runs with other interrupts enabled. All relatively slow
+ * IRQ's should use this format: notably the keyboard/timer
+ * routines.
+ */
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+{
+    struct irqaction *action;
+    int do_random, cpu;
+
+    cpu = smp_processor_id();
+    hardirq_enter(cpu);
+    kstat.irqs[cpu][irq]++;
+
+    mask_irq(irq);
+    action = *(irq + irq_action);
+    if (action) {
+	if (!(action->flags & SA_INTERRUPT))
+	    __sti();
+	action = *(irq + irq_action);
+	do_random = 0;
+	do {
+	    do_random |= action->flags;
+	    action->handler(irq, action->dev_id, regs);
+	    action = action->next;
+	} while (action);
+	if (do_random & SA_SAMPLE_RANDOM)
+	    add_interrupt_randomness(irq);
+	unmask_irq(irq);
+	__cli();
+    }
+    hardirq_exit(cpu);
+
+    /* unmasking and bottom half handling is done magically for us. */
+}
+
+/*
+ * Idea is to put all interrupts
+ * in a single table and differenciate them just by number.
+ */
+int setup_dec_irq(int irq, struct irqaction *new)
+{
+    int shared = 0;
+    struct irqaction *old, **p;
+    unsigned long flags;
+
+    p = irq_action + irq;
+    if ((old = *p) != NULL) {
+	/* Can't share interrupts unless both agree to */
+	if (!(old->flags & new->flags & SA_SHIRQ))
+	    return -EBUSY;
+
+	/* Can't share interrupts unless both are same type */
+	if ((old->flags ^ new->flags) & SA_INTERRUPT)
+	    return -EBUSY;
+
+	/* add new interrupt at end of irq queue */
+	do {
+	    p = &old->next;
+	    old = *p;
+	} while (old);
+	shared = 1;
+    }
+    if (new->flags & SA_SAMPLE_RANDOM)
+	rand_initialize_irq(irq);
+
+    save_and_cli(flags);
+    *p = new;
+
+    if (!shared) {
+	unmask_irq(irq);
+    }
+    restore_flags(flags);
+    return 0;
+}
+
+int request_irq(unsigned int irq,
+		void (*handler) (int, void *, struct pt_regs *),
+		unsigned long irqflags,
+		const char *devname,
+		void *dev_id)
+{
+    int retval;
+    struct irqaction *action;
+
+    if (irq >= 32)
+	return -EINVAL;
+    if (!handler)
+	return -EINVAL;
+
+    action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+    if (!action)
+	return -ENOMEM;
+
+    action->handler = handler;
+    action->flags = irqflags;
+    action->mask = 0;
+    action->name = devname;
+    action->next = NULL;
+    action->dev_id = dev_id;
+
+    retval = setup_dec_irq(irq, action);
+
+    if (retval)
+	kfree(action);
+    return retval;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+    struct irqaction *action, **p;
+    unsigned long flags;
+
+    if (irq > 39) {
+	printk("Trying to free IRQ%d\n", irq);
+	return;
+    }
+    for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
+	if (action->dev_id != dev_id)
+	    continue;
+
+	/* Found it - now free it */
+	save_and_cli(flags);
+	*p = action->next;
+	if (!irq[irq_action])
+	    mask_irq(irq);
+	restore_flags(flags);
+	kfree(action);
+	return;
+    }
+    printk("Trying to free free IRQ%d\n", irq);
+}
+
+unsigned long probe_irq_on(void)
+{
+    /* TODO */
+    return 0;
+}
+
+int probe_irq_off(unsigned long irqs)
+{
+    /* TODO */
+    return 0;
+}
+
+__initfunc(void init_IRQ(void))
+{
+    irq_setup();
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/prom/Makefile linux/arch/mips/dec/prom/Makefile
--- v2.3.8/linux/arch/mips/dec/prom/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/prom/Makefile	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,29 @@
+# $Id: $
+# Makefile for the DECstation prom monitor library routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.s:
+	$(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+	$(CC) $(CFLAGS) -c $< -o $*.o
+
+OBJS  = init.o memory.o cmdline.o identify.o locore.o
+
+all: 	rexlib.a
+
+rexlib.a: $(OBJS)
+	$(AR) rcs rexlib.a $(OBJS)
+	sync
+
+locore.o: locore.S
+
+dep:
+	$(CPP) -M *.c > .depend
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/prom/cmdline.c linux/arch/mips/dec/prom/cmdline.c
--- v2.3.8/linux/arch/mips/dec/prom/cmdline.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/prom/cmdline.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,46 @@
+/*
+ * cmdline.c: read the command line passed to us by the PROM.
+ *
+ * Copyright (C) 1998 Harald Koerfgen
+ *
+ * $Id: $
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+#include "prom.h"
+
+#undef PROM_DEBUG
+
+#ifdef PROM_DEBUG
+extern int (*prom_printf)(char *, ...);
+#endif
+
+char arcs_cmdline[CL_SIZE];
+
+__initfunc(void prom_init_cmdline(int argc, char **argv, unsigned long magic))
+{
+	int start_arg, i;
+
+	/*
+	 * collect args and prepare cmd_line
+	 */
+	if (magic != REX_PROM_MAGIC)
+		start_arg = 1;
+	else
+		start_arg = 2;
+	for (i = start_arg; i < argc; i++) {
+		strcat(arcs_cmdline, argv[i]);
+		if (i < (argc - 1))
+			strcat(arcs_cmdline, " ");
+	}
+
+#ifdef PROM_DEBUG
+	prom_printf("arcs_cmdline: %s\n", &(arcs_cmdline[0]));
+#endif
+
+}
+
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/prom/dectypes.h linux/arch/mips/dec/prom/dectypes.h
--- v2.3.8/linux/arch/mips/dec/prom/dectypes.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/prom/dectypes.h	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,14 @@
+#ifndef DECTYPES
+#define	DECTYPES
+
+#define DS2100_3100	1	/* DS2100/3100	Pmax		*/
+#define DS5000_200	2	/* DS5000/200	3max		*/
+#define DS5000_1XX	3	/* DS5000/1xx	kmin		*/
+#define DS5000_2X0	4	/* DS5000/2x0	3max+		*/
+#define DS5800		5	/* DS5800	Isis		*/
+#define DS5400		6	/* DS5400	MIPSfair	*/
+#define DS5000_XX	7	/* DS5000/xx	maxine		*/
+#define DS5500		11	/* DS5500	MIPSfair-2	*/
+#define DS5100		12	/* DS5100	MIPSmate	*/
+
+#endif
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/prom/identify.c linux/arch/mips/dec/prom/identify.c
--- v2.3.8/linux/arch/mips/dec/prom/identify.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/prom/identify.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,98 @@
+/*
+ * identify.c: machine identification code.
+ *
+ * Copyright (C) 1998 Harald Koerfgen and Paul M. Antoine
+ *
+ * $Id: $
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+#include "dectypes.h"
+#include "prom.h"
+
+extern char *(*prom_getenv)(char *);
+extern int (*prom_printf)(char *, ...);
+extern int (*rex_getsysid)(void);
+
+extern unsigned long mips_machgroup;
+extern unsigned long mips_machtype;
+
+__initfunc(void prom_identify_arch (unsigned int magic))
+{
+	unsigned char dec_cpunum, dec_firmrev, dec_etc;
+	int dec_systype;
+	unsigned long dec_sysid;
+
+	if (magic != REX_PROM_MAGIC) {
+		dec_sysid = simple_strtoul(prom_getenv("systype"), (char **)0, 0);
+	} else {
+		dec_sysid = rex_getsysid();
+		if (dec_sysid == 0) {
+			prom_printf("Zero sysid returned from PROMs! Assuming PMAX-like machine.\n");
+			dec_sysid = 1;
+		}
+	}
+
+	dec_cpunum = (dec_sysid & 0xff000000) >> 24;
+	dec_systype = (dec_sysid & 0xff0000) >> 16;
+	dec_firmrev = (dec_sysid & 0xff00) >> 8;
+	dec_etc = dec_sysid & 0xff;
+
+	/* We're obviously one of the DEC machines */
+	mips_machgroup = MACH_GROUP_DEC;
+
+	/*
+	 * FIXME: This may not be an exhaustive list of DECStations/Servers!
+	 * Put all model-specific initialisation calls here.
+	 */
+	prom_printf("This DECstation is a ");
+
+	switch (dec_systype) {
+	case DS2100_3100:
+		prom_printf("DS2100/3100\n");
+		mips_machtype = MACH_DS23100;
+		break;
+	case DS5100:		/* DS5100 MIPSMATE */
+		prom_printf("DS5100\n");
+		mips_machtype = MACH_DS5100;
+		break;
+	case DS5000_200:	/* DS5000 3max */
+		prom_printf("DS5000/200\n");
+		mips_machtype = MACH_DS5000_200;
+		break;
+	case DS5000_1XX:	/* DS5000/100 3min */
+		prom_printf("DS5000/1xx\n");
+		mips_machtype = MACH_DS5000_1XX;
+		break;
+	case DS5000_2X0:	/* DS5000/240 3max+ */
+		prom_printf("DS5000/2x0\n");
+		mips_machtype = MACH_DS5000_2X0;
+		break;
+	case DS5000_XX:	/* Personal DS5000/2x */
+		prom_printf("Personal DS5000/xx\n");
+		mips_machtype = MACH_DS5000_XX;
+		break;
+	case DS5800:		/* DS5800 Isis */
+		prom_printf("DS5800\n");
+		mips_machtype = MACH_DS5800;
+		break;
+	case DS5400:		/* DS5400 MIPSfair */
+		prom_printf("DS5400\n");
+		mips_machtype = MACH_DS5400;
+		break;
+	case DS5500:		/* DS5500 MIPSfair-2 */
+		prom_printf("DS5500\n");
+		mips_machtype = MACH_DS5500;
+		break;
+	default:
+		prom_printf("unknown, id is %x", dec_systype);
+		mips_machtype = MACH_DSUNKNOWN;
+		break;
+	}
+}
+
+
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/prom/init.c linux/arch/mips/dec/prom/init.c
--- v2.3.8/linux/arch/mips/dec/prom/init.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/prom/init.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,95 @@
+/*
+ * init.c: PROM library initialisation code.
+ *
+ * Copyright (C) 1998 Harald Koerfgen
+ *
+ * $Id: $
+ */
+#include <linux/init.h>
+#include "prom.h"
+
+/*
+ * PROM Interface (whichprom.c)
+ */
+typedef struct {
+	int pagesize;
+	unsigned char bitmap[0];
+} memmap;
+
+int (*rex_bootinit)(void);
+int (*rex_bootread)(void);
+int (*rex_getbitmap)(memmap *);
+unsigned long *(*rex_slot_address)(int);
+void *(*rex_gettcinfo)(void);
+int (*rex_getsysid)(void);
+void (*rex_clear_cache)(void);
+
+int (*prom_getchar)(void);
+char *(*prom_getenv)(char *);
+int (*prom_printf)(char *, ...);
+
+int (*pmax_open)(char*, int);
+int (*pmax_lseek)(int, long, int);
+int (*pmax_read)(int, void *, int);
+int (*pmax_close)(int);
+
+extern void prom_meminit(unsigned int);
+extern void prom_identify_arch(unsigned int);
+extern void prom_init_cmdline(int, char **, unsigned long);
+
+/*
+ * Detect which PROM's the DECSTATION has, and set the callback vectors
+ * appropriately.
+ */
+__initfunc(void which_prom(unsigned long magic, int *prom_vec))
+{
+	/*
+	 * No sign of the REX PROM's magic number means we assume a non-REX
+	 * machine (i.e. we're on a DS2100/3100, DS5100 or DS5000/2xx)
+	 */
+	if (magic == REX_PROM_MAGIC)
+	{
+		/*
+		 * Set up prom abstraction structure with REX entry points.
+		 */
+		rex_bootinit = (int (*)(void)) *(prom_vec + REX_PROM_BOOTINIT);
+		rex_bootread = (int (*)(void)) *(prom_vec + REX_PROM_BOOTREAD);
+		rex_getbitmap = (int (*)(memmap *)) *(prom_vec + REX_PROM_GETBITMAP);
+		prom_getchar = (int (*)(void)) *(prom_vec + REX_PROM_GETCHAR);
+		prom_getenv = (char *(*)(char *)) *(prom_vec + REX_PROM_GETENV);
+		rex_getsysid = (int (*)(void)) *(prom_vec + REX_PROM_GETSYSID);
+		rex_gettcinfo = (void *(*)(void)) *(prom_vec + REX_PROM_GETTCINFO);
+		prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF);
+		rex_slot_address = (unsigned long *(*)(int)) *(prom_vec + REX_PROM_SLOTADDR);
+		rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE);
+	}
+	else
+	{
+		/*
+		 * Set up prom abstraction structure with non-REX entry points.
+		 */
+		prom_getchar = (int (*)(void)) PMAX_PROM_GETCHAR;
+		prom_getenv = (char *(*)(char *)) PMAX_PROM_GETENV;
+		prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF;
+		pmax_open = (int (*)(char *, int)) PMAX_PROM_OPEN;
+		pmax_lseek = (int (*)(int, long, int)) PMAX_PROM_LSEEK;
+		pmax_read = (int (*)(int, void *, int)) PMAX_PROM_READ;
+		pmax_close = (int (*)(int)) PMAX_PROM_CLOSE;
+	}
+} 
+
+__initfunc(int prom_init(int argc, char **argv,
+	       unsigned long magic, int *prom_vec))
+{
+	/* Determine which PROM's we have (and therefore which machine we're on!) */
+	which_prom(magic, prom_vec);
+
+	if (magic == REX_PROM_MAGIC)
+		rex_clear_cache();
+
+	prom_meminit(magic);
+	prom_identify_arch(magic);
+	prom_init_cmdline(argc, argv, magic);
+
+	return 0;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/prom/locore.S linux/arch/mips/dec/prom/locore.S
--- v2.3.8/linux/arch/mips/dec/prom/locore.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/prom/locore.S	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,30 @@
+/*
+ * locore.S
+ */
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+
+	.text
+
+/*
+ * Simple general exception handling routine. This one is used for the
+ * Memory sizing routine for pmax machines. HK
+ */
+
+NESTED(genexcept_early, 0, sp)
+	.set	noat
+	.set	noreorder
+
+	mfc0	k0, CP0_STATUS
+	la	k1, mem_err
+
+	sw	k0,0(k1)
+
+	mfc0	k0, CP0_EPC
+	nop
+	addiu	k0,4		# skip the causing instruction
+	jr	k0
+	 rfe
+END(genexcept_early)
+
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/prom/memory.c linux/arch/mips/dec/prom/memory.c
--- v2.3.8/linux/arch/mips/dec/prom/memory.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/prom/memory.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,103 @@
+/*
+ * memory.c: memory initialisation code.
+ *
+ * Copyright (C) 1998 Harald Koerfgen, Frieder Streffer and Paul M. Antoine
+ *
+ * $Id: $
+ */
+#include <asm/addrspace.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include "prom.h"
+
+typedef struct {
+	int pagesize;
+	unsigned char bitmap[0];
+} memmap;
+
+extern int (*rex_getbitmap)(memmap *);
+
+#undef PROM_DEBUG
+
+#ifdef PROM_DEBUG
+extern int (*prom_printf)(char *, ...);
+#endif
+
+extern unsigned long mips_memory_upper;
+
+volatile unsigned long mem_err = 0;	/* So we know an error occured */
+
+/*
+ * Probe memory in 4MB chunks, waiting for an error to tell us we've fallen
+ * off the end of real memory.  Only suitable for the 2100/3100's (PMAX).
+ */
+
+#define CHUNK_SIZE 0x400000
+
+__initfunc(unsigned long pmax_get_memory_size(void))
+{
+	volatile unsigned char *memory_page, dummy;
+	char	old_handler[0x80];
+	extern char genexcept_early;
+
+	/* Install exception handler */
+	memcpy(&old_handler, (void *)(KSEG0 + 0x80), 0x80);
+	memcpy((void *)(KSEG0 + 0x80), &genexcept_early, 0x80);
+
+	/* read unmapped and uncached (KSEG1)
+	 * DECstations have at least 4MB RAM
+	 * Assume less than 480MB of RAM, as this is max for 5000/2xx
+	 * FIXME this should be replaced by the first free page!
+	 */
+	for (memory_page = (unsigned char *) KSEG1 + CHUNK_SIZE;
+	     (mem_err== 0) && (memory_page < ((unsigned char *) KSEG1+0x1E000000));
+  	     memory_page += CHUNK_SIZE) {
+		dummy = *memory_page;
+	}
+	memcpy((void *)(KSEG0 + 0x80), &old_handler, 0x80);
+	return (unsigned long)memory_page - KSEG1 - CHUNK_SIZE;
+}
+
+/*
+ * Use the REX prom calls to get hold of the memory bitmap, and thence
+ * determine memory size.
+ */
+__initfunc(unsigned long rex_get_memory_size(void))
+{
+	int i, bitmap_size;
+	unsigned long mem_size = 0;
+	memmap *bm;
+
+	/* some free 64k */
+	bm = (memmap *) 0x80028000;
+
+	bitmap_size = rex_getbitmap(bm);
+
+	for (i = 0; i < bitmap_size; i++) {
+		/* FIXME: very simplistically only add full sets of pages */
+		if (bm->bitmap[i] == 0xff)
+			mem_size += (8 * bm->pagesize);
+	}
+	return (mem_size);
+}
+
+__initfunc(void prom_meminit(unsigned int magic))
+{
+	if (magic != REX_PROM_MAGIC)
+		mips_memory_upper = KSEG0 + pmax_get_memory_size();
+	else
+		mips_memory_upper = KSEG0 + rex_get_memory_size();
+
+#ifdef PROM_DEBUG
+	prom_printf("mips_memory_upper: 0x%08x\n", mips_memory_upper);
+#endif
+}
+
+/* Called from mem_init() to fixup the mem_map page settings. */
+__initfunc(void prom_fixup_mem_map(unsigned long start, unsigned long end))
+{
+}
+
+void prom_free_prom_memory (void)
+{
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/prom/prom.h linux/arch/mips/dec/prom/prom.h
--- v2.3.8/linux/arch/mips/dec/prom/prom.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/prom/prom.h	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,51 @@
+/*  
+ * Miscellaneous definitions used to call the routines contained in the boot
+ * PROMs on various models of DECSTATION's.
+ * the rights to redistribute these changes.
+ */
+
+#ifndef __ASM_DEC_PROM_H 
+#define __ASM_DEC_PROM_H 
+
+/*
+ * PMAX/3MAX PROM entry points for DS2100/3100's and DS5000/2xx's.  Many of
+ * these will work for MIPSen as well!
+ */
+#define VEC_RESET		0xBFC00000		/* Prom base address */
+#define	PMAX_PROM_ENTRY(x)	(VEC_RESET+((x)*8))	/* Prom jump table */
+
+#define	PMAX_PROM_HALT		PMAX_PROM_ENTRY(2)	/* valid on MIPSen */
+#define	PMAX_PROM_AUTOBOOT	PMAX_PROM_ENTRY(5)	/* valid on MIPSen */
+#define	PMAX_PROM_OPEN		PMAX_PROM_ENTRY(6)
+#define	PMAX_PROM_READ		PMAX_PROM_ENTRY(7)
+#define	PMAX_PROM_CLOSE		PMAX_PROM_ENTRY(10)
+#define	PMAX_PROM_LSEEK		PMAX_PROM_ENTRY(11)
+#define PMAX_PROM_GETCHAR       PMAX_PROM_ENTRY(12)
+#define	PMAX_PROM_PUTCHAR	PMAX_PROM_ENTRY(13)	/* 12 on MIPSen */
+#define	PMAX_PROM_GETS		PMAX_PROM_ENTRY(15)
+#define	PMAX_PROM_PRINTF	PMAX_PROM_ENTRY(17)
+#define	PMAX_PROM_GETENV	PMAX_PROM_ENTRY(33)	/* valid on MIPSen */
+
+/*
+ * Magic number indicating REX PROM available on DECSTATION.  Found in
+ * register a2 on transfer of control to program from PROM.
+ */
+#define	REX_PROM_MAGIC		0x30464354
+
+/*
+ * 3MIN/MAXINE PROM entry points for DS5000/1xx's, DS5000/xx's, and
+ * DS5000/2x0.
+ */
+#define REX_PROM_GETBITMAP	0x84/4	/* get mem bitmap */
+#define REX_PROM_GETCHAR	0x24/4	/* getch() */
+#define REX_PROM_GETENV		0x64/4	/* get env. variable */
+#define REX_PROM_GETSYSID	0x80/4	/* get system id */
+#define REX_PROM_GETTCINFO	0xa4/4
+#define REX_PROM_PRINTF		0x30/4	/* printf() */
+#define REX_PROM_SLOTADDR	0x6c/4	/* slotaddr */
+#define REX_PROM_BOOTINIT	0x54/4	/* open() */
+#define REX_PROM_BOOTREAD	0x58/4	/* read() */
+#define REX_PROM_CLEARCACHE	0x7c/4
+
+#endif /* __ASM_DEC_PROM_H */
+
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/promcon.c linux/arch/mips/dec/promcon.c
--- v2.3.8/linux/arch/mips/dec/promcon.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/promcon.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,71 @@
+/*
+ * Wrap-around code for a console using the
+ * DECstation PROM io-routines.
+ *
+ * Copyright (c) 1998 Harald Koerfgen 
+ */
+
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+
+extern int (*prom_getchar) (void);
+extern int (*prom_printf) (char *,...);
+
+static void prom_console_write(struct console *co, const char *s,
+			       unsigned count)
+{
+    unsigned i;
+
+    /*
+     *    Now, do each character
+     */
+    for (i = 0; i < count; i++) {
+	if (*s == 10)
+	    prom_printf("%c", 13);
+	prom_printf("%c", *s++);
+    }
+}
+
+static int prom_console_wait_key(struct console *co)
+{
+    return prom_getchar();
+}
+
+__initfunc(static int prom_console_setup(struct console *co, char *options))
+{
+    return 0;
+}
+
+static kdev_t prom_console_device(struct console *c)
+{
+    return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static struct console sercons =
+{
+    "ttyS",
+    prom_console_write,
+    NULL,
+    prom_console_device,
+    prom_console_wait_key,
+    NULL,
+    prom_console_setup,
+    CON_PRINTBUFFER,
+    -1,
+    0,
+    NULL
+};
+
+/*
+ *    Register console.
+ */
+
+__initfunc(long prom_console_init(long kmem_start, long kmem_end))
+{
+    register_console(&sercons);
+    return kmem_start;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/reset.c linux/arch/mips/dec/reset.c
--- v2.3.8/linux/arch/mips/dec/reset.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/reset.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,25 @@
+/*
+ *  $Id: reset.c,v 1.4 1999/04/11 17:06:16 harald Exp $
+ *
+ *  Reset a DECstation machine.
+ *
+ */
+
+void (*back_to_prom)(void) = (void (*)(void))0xBFC00000;
+
+void dec_machine_restart(char *command)
+{
+	back_to_prom();
+}
+
+void dec_machine_halt(void)
+{
+	back_to_prom();
+}
+
+void dec_machine_power_off(void)
+{
+    /* DECstations don't have a software power switch */
+	back_to_prom();
+}
+
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/rtc-dec.c linux/arch/mips/dec/rtc-dec.c
--- v2.3.8/linux/arch/mips/dec/rtc-dec.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/rtc-dec.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,36 @@
+
+/* $Id: rtc-jazz.c,v 1.2 1998/06/25 20:19:14 ralf Exp $
+
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * RTC routines for DECstation style attached Dallas chip.
+ *
+ * Copyright (C) 1998 by Ralf Baechle, Harald Koerfgen
+ */
+#include <linux/mc146818rtc.h>
+
+extern char *dec_rtc_base;
+
+static unsigned char dec_rtc_read_data(unsigned long addr)
+{
+    return (dec_rtc_base[addr * 4]);
+}
+
+static void dec_rtc_write_data(unsigned char data, unsigned long addr)
+{
+    dec_rtc_base[addr * 4] = data;
+}
+
+static int dec_rtc_bcd_mode(void)
+{
+    return 0;
+}
+
+struct rtc_ops dec_rtc_ops =
+{
+    &dec_rtc_read_data,
+    &dec_rtc_write_data,
+    &dec_rtc_bcd_mode
+};
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/serial.c linux/arch/mips/dec/serial.c
--- v2.3.8/linux/arch/mips/dec/serial.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/serial.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,98 @@
+/*
+ * sercons.c
+ *      choose the right serial device at boot time
+ *
+ * triemer 6-SEP-1998
+ *      sercons.c is designed to allow the three different kinds 
+ *      of serial devices under the decstation world to co-exist
+ *      in the same kernel.  The idea here is to abstract 
+ *      the pieces of the drivers that are common to this file
+ *      so that they do not clash at compile time and runtime.
+ *
+ * HK 16-SEP-1998 v0.002
+ *      removed the PROM console as this is not a real serial
+ *      device. Added support for PROM console in drivers/char/tty_io.c
+ *      instead. Although it may work to enable more than one 
+ *      console device I strongly recommend to use only one.
+ */
+
+#include <linux/config.h>
+#include <asm/init.h>
+#include <asm/dec/machtype.h>
+
+#ifdef CONFIG_ZS
+extern int zs_init(void);
+#endif
+
+#ifdef CONFIG_DZ
+extern int dz_init(void);
+#endif
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+#ifdef CONFIG_ZS
+extern long zs_serial_console_init(long, long);
+#endif
+
+#ifdef CONFIG_DZ
+extern long dz_serial_console_init(long, long);
+#endif
+
+#endif
+
+/* rs_init - starts up the serial interface -
+   handle normal case of starting up the serial interface */
+
+#ifdef CONFIG_SERIAL
+
+__initfunc(int rs_init(void))
+{
+
+#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+    if (IOASIC)
+	return zs_init();
+    else
+	return dz_init();
+#else
+
+#ifdef CONFIG_ZS
+    return zs_init();
+#endif
+
+#ifdef CONFIG_DZ
+    return dz_init();
+#endif
+
+#endif
+}
+
+#endif
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/* serial_console_init handles the special case of starting
+ *   up the console on the serial port
+ */
+__initfunc(long serial_console_init(long kmem_start, long kmem_end))
+{
+#if defined(CONFIG_ZS) && defined(CONFIG_DZ)
+    if (IOASIC)
+	kmem_start = zs_serial_console_init(kmem_start, kmem_end);
+    else
+	kmem_start = dz_serial_console_init(kmem_start, kmem_end);
+#else
+
+#ifdef CONFIG_ZS
+    kmem_start = zs_serial_console_init(kmem_start, kmem_end);
+#endif
+
+#ifdef CONFIG_DZ
+    kmem_start = dz_serial_console_init(kmem_start, kmem_end);
+#endif
+
+#endif
+
+    return kmem_start;
+}
+
+#endif
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/setup.c linux/arch/mips/dec/setup.c
--- v2.3.8/linux/arch/mips/dec/setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/setup.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,503 @@
+/*
+ * Setup the interrupt stuff.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1998 Harald Koerfgen
+ */
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/param.h>
+#include <asm/mipsregs.h>
+#include <asm/bootinfo.h>
+#include <asm/init.h>
+#include <asm/irq.h>
+#include <asm/reboot.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/kn01.h>
+#include <asm/dec/kn02.h>
+#include <asm/dec/kn02xa.h>
+#include <asm/dec/kn03.h>
+#include <asm/dec/ioasic_ints.h>
+
+extern asmlinkage void decstation_handle_int(void);
+
+void dec_init_kn01(void);
+void dec_init_kn230(void);
+void dec_init_kn02(void);
+void dec_init_kn02ba(void);
+void dec_init_kn02ca(void);
+void dec_init_kn03(void);
+
+char *dec_rtc_base = (char *) KN01_RTC_BASE;	/* Assume DS2100/3100 initially */
+
+decint_t dec_interrupt[NR_INTS];
+
+/* 
+ * Information regarding the IRQ Controller
+ *
+ * isr and imr are also hardcoded for different machines in int_handler.S
+ */
+
+volatile unsigned int *isr = 0L;	/* address of the interrupt status register     */
+volatile unsigned int *imr = 0L;	/* address of the interrupt mask register       */
+
+extern void dec_machine_restart(char *command);
+extern void dec_machine_halt(void);
+extern void dec_machine_power_off(void);
+
+extern void wbflush_setup(void);
+
+extern struct rtc_ops dec_rtc_ops;
+
+extern void intr_halt(void);
+
+extern int setup_dec_irq(int, struct irqaction *);
+
+void (*board_time_init) (struct irqaction * irq);
+
+__initfunc(static void dec_irq_setup(void))
+{
+    switch (mips_machtype) {
+    case MACH_DS23100:
+	dec_init_kn01();
+	break;
+    case MACH_DS5100:		/*  DS5100 MIPSMATE */
+	dec_init_kn230();
+	break;
+    case MACH_DS5000_200:	/* DS5000 3max */
+	dec_init_kn02();
+	break;
+    case MACH_DS5000_1XX:	/* DS5000/100 3min */
+	dec_init_kn02ba();
+	break;
+    case MACH_DS5000_2X0:	/* DS5000/240 3max+ */
+	dec_init_kn03();
+	break;
+    case MACH_DS5000_XX:	/* Personal DS5000/2x */
+	dec_init_kn02ca();
+	break;
+    case MACH_DS5800:		/* DS5800 Isis */
+	panic("Don't know how to set this up!");
+	break;
+    case MACH_DS5400:		/* DS5400 MIPSfair */
+	panic("Don't know how to set this up!");
+	break;
+    case MACH_DS5500:		/* DS5500 MIPSfair-2 */
+	panic("Don't know how to set this up!");
+	break;
+    }
+    set_except_vector(0, decstation_handle_int);
+}
+
+/*
+ * enable the periodic interrupts
+ */
+__initfunc(static void dec_time_init(struct irqaction *irq))
+{
+    /*
+     * Here we go, enable periodic rtc interrupts.
+     */
+
+#ifndef LOG_2_HZ
+#  define LOG_2_HZ 7
+#endif
+
+    CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - LOG_2_HZ), RTC_REG_A);
+    CMOS_WRITE(CMOS_READ(RTC_REG_B) | RTC_PIE, RTC_REG_B);
+    setup_dec_irq(CLOCK, irq);
+}
+
+__initfunc(void decstation_setup(void))
+{
+    irq_setup = dec_irq_setup;
+    board_time_init = dec_time_init;
+
+    wbflush_setup();
+
+    _machine_restart = dec_machine_restart;
+    _machine_halt = dec_machine_halt;
+    _machine_power_off = dec_machine_power_off;
+
+    rtc_ops = &dec_rtc_ops;
+}
+
+/*
+ * Machine-specific initialisation for kn01, aka Pmax, aka DS2100, DS3100,
+ * and possibly also the DS5100.
+ */
+__initfunc(void dec_init_kn01(void))
+{
+    /*
+     * Setup some memory addresses.
+     */
+    dec_rtc_base = (char *) KN01_RTC_BASE;
+
+    /*
+     * Setup interrupt structure
+     */
+    dec_interrupt[CLOCK].cpu_mask = IE_IRQ3;
+    dec_interrupt[CLOCK].iemask = 0;
+    cpu_mask_tbl[0] = IE_IRQ3;
+    cpu_irq_nr[0] = CLOCK;
+
+    dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ0;
+    dec_interrupt[SCSI_INT].iemask = 0;
+    cpu_mask_tbl[1] = IE_IRQ0;
+    cpu_irq_nr[1] = SCSI_INT;
+
+    dec_interrupt[ETHER].cpu_mask = IE_IRQ1;
+    dec_interrupt[ETHER].iemask = 0;
+    cpu_mask_tbl[2] = IE_IRQ1;
+    cpu_irq_nr[2] = ETHER;
+
+    dec_interrupt[SERIAL].cpu_mask = IE_IRQ2;
+    dec_interrupt[SERIAL].iemask = 0;
+    cpu_mask_tbl[3] = IE_IRQ2;
+    cpu_irq_nr[3] = SERIAL;
+
+    dec_interrupt[MEMORY].cpu_mask = IE_IRQ4;
+    dec_interrupt[MEMORY].iemask = 0;
+    cpu_mask_tbl[4] = IE_IRQ4;
+    cpu_irq_nr[4] = MEMORY;
+
+    dec_interrupt[FPU].cpu_mask = IE_IRQ5;
+    dec_interrupt[FPU].iemask = 0;
+    cpu_mask_tbl[5] = IE_IRQ5;
+    cpu_irq_nr[5] = FPU;
+}				/* dec_init_kn01 */
+
+/*
+ * Machine-specific initialisation for kn230, aka MIPSmate, aka DS5100
+ *
+ * There are a lot of experiments to do, this is definitely incomplete.
+ */
+__initfunc(void dec_init_kn230(void))
+{
+    /*
+     * Setup some memory addresses.
+     */
+    dec_rtc_base = (char *) KN01_RTC_BASE;
+
+    /*
+     * Setup interrupt structure
+     */
+    dec_interrupt[CLOCK].cpu_mask = IE_IRQ2;
+    dec_interrupt[CLOCK].iemask = 0;
+    cpu_mask_tbl[0] = IE_IRQ2;
+    cpu_irq_nr[0] = CLOCK;
+
+    dec_interrupt[FPU].cpu_mask = IE_IRQ5;
+    dec_interrupt[FPU].iemask = 0;
+    cpu_mask_tbl[5] = IE_IRQ5;
+    cpu_irq_nr[5] = FPU;
+}				/* dec_init_kn230 */
+
+/*
+ * Machine-specific initialisation for kn02, aka 3max, aka DS5000/2xx.
+ */
+__initfunc(void dec_init_kn02(void))
+{
+    /*
+     * Setup some memory addresses. FIXME: probably incomplete!
+     */
+    dec_rtc_base = (char *) KN02_RTC_BASE;
+    isr = (volatile unsigned int *) KN02_CSR_ADDR;
+    imr = (volatile unsigned int *) KN02_CSR_ADDR;
+
+    /*
+     * Setup IOASIC interrupt
+     */
+    cpu_ivec_tbl[1] = kn02_io_int;
+    cpu_mask_tbl[1] = IE_IRQ0;
+    cpu_irq_nr[1] = -1;
+    *imr = *imr & 0xff00ff00;
+
+    /*
+     * Setup interrupt structure
+     */
+    dec_interrupt[CLOCK].cpu_mask = IE_IRQ1;
+    dec_interrupt[CLOCK].iemask = 0;
+    cpu_mask_tbl[0] = IE_IRQ1;
+    cpu_irq_nr[0] = CLOCK;
+
+    dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ0;
+    dec_interrupt[SCSI_INT].iemask = KN02_SLOT5;
+    asic_mask_tbl[0] = KN02_SLOT5;
+    asic_irq_nr[0] = SCSI_INT;
+
+    dec_interrupt[ETHER].cpu_mask = IE_IRQ0;
+    dec_interrupt[ETHER].iemask = KN02_SLOT6;
+    asic_mask_tbl[1] = KN02_SLOT6;
+    asic_irq_nr[1] = ETHER;
+
+    dec_interrupt[SERIAL].cpu_mask = IE_IRQ0;
+    dec_interrupt[SERIAL].iemask = KN02_SLOT7;
+    asic_mask_tbl[2] = KN02_SLOT7;
+    asic_irq_nr[2] = SERIAL;
+
+    dec_interrupt[TC0].cpu_mask = IE_IRQ0;
+    dec_interrupt[TC0].iemask = KN02_SLOT0;
+    asic_mask_tbl[3] = KN02_SLOT0;
+    asic_irq_nr[3] = TC0;
+
+    dec_interrupt[TC1].cpu_mask = IE_IRQ0;
+    dec_interrupt[TC1].iemask = KN02_SLOT1;
+    asic_mask_tbl[4] = KN02_SLOT1;
+    asic_irq_nr[4] = TC1;
+
+    dec_interrupt[TC2].cpu_mask = IE_IRQ0;
+    dec_interrupt[TC2].iemask = KN02_SLOT2;
+    asic_mask_tbl[5] = KN02_SLOT2;
+    asic_irq_nr[5] = TC2;
+
+    dec_interrupt[MEMORY].cpu_mask = IE_IRQ3;
+    dec_interrupt[MEMORY].iemask = 0;
+    cpu_mask_tbl[2] = IE_IRQ3;
+    cpu_irq_nr[2] = MEMORY;
+
+    dec_interrupt[FPU].cpu_mask = IE_IRQ5;
+    dec_interrupt[FPU].iemask = 0;
+    cpu_mask_tbl[3] = IE_IRQ5;
+    cpu_irq_nr[3] = FPU;
+
+}				/* dec_init_kn02 */
+
+/*
+ * Machine-specific initialisation for kn02ba, aka 3min, aka DS5000/1xx.
+ */
+__initfunc(void dec_init_kn02ba(void))
+{
+    /*
+     * Setup some memory addresses.
+     */
+    dec_rtc_base = (char *) KN02XA_RTC_BASE;
+    isr = (volatile unsigned int *) KN02XA_SIR_ADDR;
+    imr = (volatile unsigned int *) KN02XA_SIRM_ADDR;
+
+    /*
+     * Setup IOASIC interrupt
+     */
+    cpu_mask_tbl[0] = IE_IRQ3;
+    cpu_irq_nr[0] = -1;
+    cpu_ivec_tbl[0] = kn02ba_io_int;
+    *imr = 0;
+
+    /*
+     * Setup interrupt structure
+     */
+    dec_interrupt[CLOCK].cpu_mask = IE_IRQ3;
+    dec_interrupt[CLOCK].iemask = KMIN_CLOCK;
+    asic_mask_tbl[0] = KMIN_CLOCK;
+    asic_irq_nr[0] = CLOCK;
+
+    dec_interrupt[SCSI_DMA_INT].cpu_mask = IE_IRQ3;
+    dec_interrupt[SCSI_DMA_INT].iemask = SCSI_DMA_INTS;
+    asic_mask_tbl[1] = SCSI_DMA_INTS;
+    asic_irq_nr[1] = SCSI_DMA_INT;
+
+    dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ3;
+    dec_interrupt[SCSI_INT].iemask = SCSI_CHIP;
+    asic_mask_tbl[2] = SCSI_CHIP;
+    asic_irq_nr[2] = SCSI_INT;
+
+    dec_interrupt[ETHER].cpu_mask = IE_IRQ3;
+    dec_interrupt[ETHER].iemask = LANCE_INTS;
+    asic_mask_tbl[3] = LANCE_INTS;
+    asic_irq_nr[3] = ETHER;
+
+    dec_interrupt[SERIAL].cpu_mask = IE_IRQ3;
+    dec_interrupt[SERIAL].iemask = SERIAL_INTS;
+    asic_mask_tbl[4] = SERIAL_INTS;
+    asic_irq_nr[4] = SERIAL;
+
+    dec_interrupt[MEMORY].cpu_mask = IE_IRQ3;
+    dec_interrupt[MEMORY].iemask = KMIN_TIMEOUT;
+    asic_mask_tbl[5] = KMIN_TIMEOUT;
+    asic_irq_nr[5] = MEMORY;
+
+    dec_interrupt[TC0].cpu_mask = IE_IRQ0;
+    dec_interrupt[TC0].iemask = 0;
+    cpu_mask_tbl[1] = IE_IRQ0;
+    cpu_irq_nr[1] = TC0;
+
+    dec_interrupt[TC1].cpu_mask = IE_IRQ1;
+    dec_interrupt[TC1].iemask = 0;
+    cpu_mask_tbl[2] = IE_IRQ1;
+    cpu_irq_nr[2] = TC1;
+
+    dec_interrupt[TC2].cpu_mask = IE_IRQ2;
+    dec_interrupt[TC2].iemask = 0;
+    cpu_mask_tbl[3] = IE_IRQ2;
+    cpu_irq_nr[3] = TC2;
+
+    dec_interrupt[HALT].cpu_mask = IE_IRQ4;
+    dec_interrupt[HALT].iemask = 0;
+    cpu_mask_tbl[4] = IE_IRQ4;
+    cpu_irq_nr[4] = HALT;
+
+    dec_interrupt[FPU].cpu_mask = IE_IRQ5;
+    dec_interrupt[FPU].iemask = 0;
+    cpu_mask_tbl[5] = IE_IRQ5;
+    cpu_irq_nr[5] = FPU;
+
+}				/* dec_init_kn02ba */
+
+/*
+ * Machine-specific initialisation for kn02ca, aka maxine, aka DS5000/2x.
+ */
+__initfunc(void dec_init_kn02ca(void))
+{
+    /*
+     * Setup some memory addresses. FIXME: probably incomplete!
+     */
+    dec_rtc_base = (char *) KN02XA_RTC_BASE;
+    isr = (volatile unsigned int *) KN02XA_SIR_ADDR;
+    imr = (volatile unsigned int *) KN02XA_SIRM_ADDR;
+
+    /*
+     * Setup IOASIC interrupt
+     */
+    cpu_ivec_tbl[1] = kn02ba_io_int;
+    cpu_irq_nr[1] = -1;
+    cpu_mask_tbl[1] = IE_IRQ3;
+    *imr = 0;
+
+    /*
+     * Setup interrupt structure
+     */
+    dec_interrupt[CLOCK].cpu_mask = IE_IRQ1;
+    dec_interrupt[CLOCK].iemask = 0;
+    cpu_mask_tbl[0] = IE_IRQ1;
+    cpu_irq_nr[0] = CLOCK;
+
+    dec_interrupt[SCSI_DMA_INT].cpu_mask = IE_IRQ3;
+    dec_interrupt[SCSI_DMA_INT].iemask = SCSI_DMA_INTS;
+    asic_mask_tbl[0] = SCSI_DMA_INTS;
+    asic_irq_nr[0] = SCSI_DMA_INT;
+
+    dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ3;
+    dec_interrupt[SCSI_INT].iemask = SCSI_CHIP;
+    asic_mask_tbl[1] = SCSI_CHIP;
+    asic_irq_nr[1] = SCSI_INT;
+
+    dec_interrupt[ETHER].cpu_mask = IE_IRQ3;
+    dec_interrupt[ETHER].iemask = LANCE_INTS;
+    asic_mask_tbl[2] = LANCE_INTS;
+    asic_irq_nr[2] = ETHER;
+
+    dec_interrupt[SERIAL].cpu_mask = IE_IRQ3;
+    dec_interrupt[SERIAL].iemask = XINE_SERIAL_INTS;
+    asic_mask_tbl[3] = XINE_SERIAL_INTS;
+    asic_irq_nr[3] = SERIAL;
+
+    dec_interrupt[TC0].cpu_mask = IE_IRQ3;
+    dec_interrupt[TC0].iemask = MAXINE_TC0;
+    asic_mask_tbl[4] = MAXINE_TC0;
+    asic_irq_nr[4] = TC0;
+
+    dec_interrupt[TC1].cpu_mask = IE_IRQ3;
+    dec_interrupt[TC1].iemask = MAXINE_TC1;
+    asic_mask_tbl[5] = MAXINE_TC1;
+    asic_irq_nr[5] = TC1;
+
+    dec_interrupt[MEMORY].cpu_mask = IE_IRQ2;
+    dec_interrupt[MEMORY].iemask = 0;
+    cpu_mask_tbl[2] = IE_IRQ2;
+    cpu_irq_nr[2] = MEMORY;
+
+    dec_interrupt[HALT].cpu_mask = IE_IRQ4;
+    dec_interrupt[HALT].iemask = 0;
+    cpu_mask_tbl[3] = IE_IRQ4;
+    cpu_irq_nr[3] = HALT;
+
+    dec_interrupt[FPU].cpu_mask = IE_IRQ5;
+    dec_interrupt[FPU].iemask = 0;
+    cpu_mask_tbl[4] = IE_IRQ5;
+    cpu_irq_nr[4] = FPU;
+
+}				/* dec_init_kn02ca */
+
+/*
+ * Machine-specific initialisation for kn03, aka 3max+, aka DS5000/240.
+ */
+__initfunc(void dec_init_kn03(void))
+{
+    /*
+     * Setup some memory addresses. FIXME: probably incomplete!
+     */
+    dec_rtc_base = (char *) KN03_RTC_BASE;
+    isr = (volatile unsigned int *) KN03_SIR_ADDR;
+    imr = (volatile unsigned int *) KN03_SIRM_ADDR;
+
+    /*
+     * Setup IOASIC interrupt
+     */
+    cpu_ivec_tbl[1] = kn03_io_int;
+    cpu_mask_tbl[1] = IE_IRQ0;
+    cpu_irq_nr[1] = -1;
+    *imr = 0;
+
+    /*
+     * Setup interrupt structure
+     */
+    dec_interrupt[CLOCK].cpu_mask = IE_IRQ1;
+    dec_interrupt[CLOCK].iemask = 0;
+    cpu_mask_tbl[0] = IE_IRQ1;
+    cpu_irq_nr[0] = CLOCK;
+
+    dec_interrupt[SCSI_DMA_INT].cpu_mask = IE_IRQ0;
+    dec_interrupt[SCSI_DMA_INT].iemask = SCSI_DMA_INTS;
+    asic_mask_tbl[0] = SCSI_DMA_INTS;
+    asic_irq_nr[0] = SCSI_DMA_INT;
+
+    dec_interrupt[SCSI_INT].cpu_mask = IE_IRQ0;
+    dec_interrupt[SCSI_INT].iemask = SCSI_CHIP;
+    asic_mask_tbl[1] = SCSI_CHIP;
+    asic_irq_nr[1] = SCSI_INT;
+
+    dec_interrupt[ETHER].cpu_mask = IE_IRQ0;
+    dec_interrupt[ETHER].iemask = LANCE_INTS;
+    asic_mask_tbl[2] = LANCE_INTS;
+    asic_irq_nr[2] = ETHER;
+
+    dec_interrupt[SERIAL].cpu_mask = IE_IRQ0;
+    dec_interrupt[SERIAL].iemask = SERIAL_INTS;
+    asic_mask_tbl[3] = SERIAL_INTS;
+    asic_irq_nr[3] = SERIAL;
+
+    dec_interrupt[TC0].cpu_mask = IE_IRQ0;
+    dec_interrupt[TC0].iemask = KN03_TC0;
+    asic_mask_tbl[4] = KN03_TC0;
+    asic_irq_nr[4] = TC0;
+
+    dec_interrupt[TC1].cpu_mask = IE_IRQ0;
+    dec_interrupt[TC1].iemask = KN03_TC1;
+    asic_mask_tbl[5] = KN03_TC1;
+    asic_irq_nr[5] = TC1;
+
+    dec_interrupt[TC2].cpu_mask = IE_IRQ0;
+    dec_interrupt[TC2].iemask = KN03_TC2;
+    asic_mask_tbl[6] = KN03_TC2;
+    asic_irq_nr[6] = TC2;
+
+    dec_interrupt[MEMORY].cpu_mask = IE_IRQ3;
+    dec_interrupt[MEMORY].iemask = 0;
+    cpu_mask_tbl[2] = IE_IRQ3;
+    cpu_irq_nr[2] = MEMORY;
+
+    dec_interrupt[HALT].cpu_mask = IE_IRQ4;
+    dec_interrupt[HALT].iemask = 0;
+    cpu_mask_tbl[3] = IE_IRQ4;
+    cpu_irq_nr[3] = HALT;
+
+    dec_interrupt[FPU].cpu_mask = IE_IRQ5;
+    dec_interrupt[FPU].iemask = 0;
+    cpu_mask_tbl[4] = IE_IRQ5;
+    cpu_irq_nr[4] = FPU;
+
+}				/* dec_init_kn03 */
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/time.c linux/arch/mips/dec/time.c
--- v2.3.8/linux/arch/mips/dec/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/time.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,439 @@
+
+/*
+ *  linux/arch/mips/kernel/time.c
+ *
+ *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *
+ * This file contains the time handling details for PC-style clocks as
+ * found in some MIPS systems.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+
+#include <asm/bootinfo.h>
+#include <asm/mipsregs.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+
+extern volatile unsigned long lost_ticks;
+
+/*
+ * Change this if you have some constant time drift
+ */
+/* This is the value for the PC-style PICs. */
+/* #define USECS_PER_JIFFY (1000020/HZ) */
+
+/* This is for machines which generate the exact clock. */
+#define USECS_PER_JIFFY (1000000/HZ)
+
+/* Cycle counter value at the previous timer interrupt.. */
+
+static unsigned int timerhi = 0, timerlo = 0;
+
+/*
+ * On MIPS only R4000 and better have a cycle counter.
+ *
+ * FIXME: Does playing with the RP bit in c0_status interfere with this code?
+ */
+static unsigned long do_fast_gettimeoffset(void)
+{
+    u32 count;
+    unsigned long res, tmp;
+
+    /* Last jiffy when do_fast_gettimeoffset() was called. */
+    static unsigned long last_jiffies = 0;
+    unsigned long quotient;
+
+    /*
+     * Cached "1/(clocks per usec)*2^32" value.
+     * It has to be recalculated once each jiffy.
+     */
+    static unsigned long cached_quotient = 0;
+
+    tmp = jiffies;
+
+    quotient = cached_quotient;
+
+    if (last_jiffies != tmp) {
+	last_jiffies = tmp;
+	__asm__(".set\tnoreorder\n\t"
+		".set\tnoat\n\t"
+		".set\tmips3\n\t"
+		"lwu\t%0,%2\n\t"
+		"dsll32\t$1,%1,0\n\t"
+		"or\t$1,$1,%0\n\t"
+		"ddivu\t$0,$1,%3\n\t"
+		"mflo\t$1\n\t"
+		"dsll32\t%0,%4,0\n\t"
+		"nop\n\t"
+		"ddivu\t$0,%0,$1\n\t"
+		"mflo\t%0\n\t"
+		".set\tmips0\n\t"
+		".set\tat\n\t"
+		".set\treorder"
+      :	"=&r"(quotient)
+      :	"r"(timerhi),
+		"m"(timerlo),
+		"r"(tmp),
+		"r"(USECS_PER_JIFFY)
+      :	"$1");
+	cached_quotient = quotient;
+    }
+    /* Get last timer tick in absolute kernel time */
+    count = read_32bit_cp0_register(CP0_COUNT);
+
+    /* .. relative to previous jiffy (32 bits is enough) */
+    count -= timerlo;
+//printk("count: %08lx, %08lx:%08lx\n", count, timerhi, timerlo);
+
+    __asm__("multu\t%1,%2\n\t"
+	    "mfhi\t%0"
+  :	    "=r"(res)
+  :	    "r"(count),
+	    "r"(quotient));
+
+    /*
+     * Due to possible jiffies inconsistencies, we need to check 
+     * the result so that we'll get a timer that is monotonic.
+     */
+    if (res >= USECS_PER_JIFFY)
+	res = USECS_PER_JIFFY - 1;
+
+    return res;
+}
+
+/* This function must be called with interrupts disabled 
+ * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
+ * 
+ * However, the pc-audio speaker driver changes the divisor so that
+ * it gets interrupted rather more often - it loads 64 into the
+ * counter rather than 11932! This has an adverse impact on
+ * do_gettimeoffset() -- it stops working! What is also not
+ * good is that the interval that our timer function gets called
+ * is no longer 10.0002 ms, but 9.9767 ms. To get around this
+ * would require using a different timing source. Maybe someone
+ * could use the RTC - I know that this can interrupt at frequencies
+ * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
+ * it so that at startup, the timer code in sched.c would select
+ * using either the RTC or the 8253 timer. The decision would be
+ * based on whether there was any other device around that needed
+ * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
+ * and then do some jiggery to have a version of do_timer that 
+ * advanced the clock by 1/1024 s. Every time that reached over 1/100
+ * of a second, then do all the old code. If the time was kept correct
+ * then do_gettimeoffset could just return 0 - there is no low order
+ * divider that can be accessed.
+ *
+ * Ideally, you would be able to use the RTC for the speaker driver,
+ * but it appears that the speaker driver really needs interrupt more
+ * often than every 120 us or so.
+ *
+ * Anyway, this needs more thought....          pjsg (1993-08-28)
+ * 
+ * If you are really that interested, you should be reading
+ * comp.protocols.time.ntp!
+ */
+
+#define TICK_SIZE tick
+
+static unsigned long do_slow_gettimeoffset(void)
+{
+    /*
+     * This is a kludge until I find a way for the
+     * DECstations without bus cycle counter. HK
+     */
+    return 0;
+}
+
+static unsigned long (*do_gettimeoffset) (void) = do_slow_gettimeoffset;
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+    unsigned long flags;
+
+    save_and_cli(flags);
+    *tv = xtime;
+    tv->tv_usec += do_gettimeoffset();
+
+    /*
+     * xtime is atomically updated in timer_bh. lost_ticks is
+     * nonzero if the timer bottom half hasnt executed yet.
+     */
+    if (lost_ticks)
+	tv->tv_usec += USECS_PER_JIFFY;
+
+    restore_flags(flags);
+
+    if (tv->tv_usec >= 1000000) {
+	tv->tv_usec -= 1000000;
+	tv->tv_sec++;
+    }
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+    cli();
+    /* This is revolting. We need to set the xtime.tv_usec
+     * correctly. However, the value in this location is
+     * is value at the last tick.
+     * Discover what correction gettimeofday
+     * would have done, and then undo it!
+     */
+    tv->tv_usec -= do_gettimeoffset();
+
+    if (tv->tv_usec < 0) {
+	tv->tv_usec += 1000000;
+	tv->tv_sec--;
+    }
+    xtime = *tv;
+    time_state = TIME_BAD;
+    time_maxerror = MAXPHASE;
+    time_esterror = MAXPHASE;
+    sti();
+}
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+    int retval = 0;
+    int real_seconds, real_minutes, cmos_minutes;
+    unsigned char save_control, save_freq_select;
+
+    save_control = CMOS_READ(RTC_CONTROL);	/* tell the clock it's being set */
+    CMOS_WRITE((save_control | RTC_SET), RTC_CONTROL);
+
+    save_freq_select = CMOS_READ(RTC_FREQ_SELECT);	/* stop and reset prescaler */
+    CMOS_WRITE((save_freq_select | RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+    cmos_minutes = CMOS_READ(RTC_MINUTES);
+    if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+	BCD_TO_BIN(cmos_minutes);
+
+    /*
+     * since we're only adjusting minutes and seconds,
+     * don't interfere with hour overflow. This avoids
+     * messing with unknown time zones but requires your
+     * RTC not to be off by more than 15 minutes
+     */
+    real_seconds = nowtime % 60;
+    real_minutes = nowtime / 60;
+    if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
+	real_minutes += 30;	/* correct for half hour time zone */
+    real_minutes %= 60;
+
+    if (abs(real_minutes - cmos_minutes) < 30) {
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+	    BIN_TO_BCD(real_seconds);
+	    BIN_TO_BCD(real_minutes);
+	}
+	CMOS_WRITE(real_seconds, RTC_SECONDS);
+	CMOS_WRITE(real_minutes, RTC_MINUTES);
+    } else
+	retval = -1;
+
+    /* The following flags have to be released exactly in this order,
+     * otherwise the DS12887 (popular MC146818A clone with integrated
+     * battery and quartz) will not reset the oscillator and will not
+     * update precisely 500 ms later. You won't find this mentioned in
+     * the Dallas Semiconductor data sheets, but who believes data
+     * sheets anyway ...                           -- Markus Kuhn
+     */
+    CMOS_WRITE(save_control, RTC_CONTROL);
+    CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+    return retval;
+}
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static void inline
+ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    volatile unsigned char dummy;
+
+    dummy = CMOS_READ(RTC_REG_C);	/* ACK RTC Interrupt */
+    do_timer(regs);
+
+    /*
+     * If we have an externally synchronized Linux clock, then update
+     * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+     * called as close as possible to 500 ms before the new second starts.
+     */
+    if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+	xtime.tv_usec > 500000 - (tick >> 1) &&
+	xtime.tv_usec < 500000 + (tick >> 1))
+	if (set_rtc_mmss(xtime.tv_sec) == 0)
+	    last_rtc_update = xtime.tv_sec;
+	else
+	    last_rtc_update = xtime.tv_sec - 600;	/* do it again in 60 s */
+}
+
+static void r4k_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned int count;
+
+    /*
+     * The cycle counter is only 32 bit which is good for about
+     * a minute at current count rates of upto 150MHz or so.
+     */
+    count = read_32bit_cp0_register(CP0_COUNT);
+    timerhi += (count < timerlo);	/* Wrap around */
+    timerlo = count;
+
+    timer_interrupt(irq, dev_id, regs);
+}
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+				   unsigned int day, unsigned int hour,
+				   unsigned int min, unsigned int sec)
+{
+    if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+	mon += 12;		/* Puts Feb last since it has leap day */
+	year -= 1;
+    }
+    return (((
+		 (unsigned long) (year / 4 - year / 100 + year / 400 + 367 * mon / 12 + day) +
+		 year * 365 - 719499
+	     ) * 24 + hour	/* now have hours */
+	    ) * 60 + min	/* now have minutes */
+	) * 60 + sec;		/* finally seconds */
+}
+
+char cyclecounter_available;
+
+static inline void init_cycle_counter(void)
+{
+    switch (mips_cputype) {
+    case CPU_UNKNOWN:
+    case CPU_R2000:
+    case CPU_R3000:
+    case CPU_R3000A:
+    case CPU_R3041:
+    case CPU_R3051:
+    case CPU_R3052:
+    case CPU_R3081:
+    case CPU_R3081E:
+    case CPU_R6000:
+    case CPU_R6000A:
+    case CPU_R8000:		/* Not shure about that one, play safe */
+	cyclecounter_available = 0;
+	break;
+    case CPU_R4000PC:
+    case CPU_R4000SC:
+    case CPU_R4000MC:
+    case CPU_R4200:
+    case CPU_R4400PC:
+    case CPU_R4400SC:
+    case CPU_R4400MC:
+    case CPU_R4600:
+    case CPU_R10000:
+    case CPU_R4300:
+    case CPU_R4650:
+    case CPU_R4700:
+    case CPU_R5000:
+    case CPU_R5000A:
+    case CPU_R4640:
+    case CPU_NEVADA:
+	cyclecounter_available = 1;
+	break;
+    }
+}
+
+struct irqaction irq0 =
+{timer_interrupt, SA_INTERRUPT, 0,
+ "timer", NULL, NULL};
+
+
+void (*board_time_init) (struct irqaction * irq);
+
+__initfunc(void time_init(void))
+{
+    unsigned int year, mon, day, hour, min, sec;
+    int i;
+
+    /* The Linux interpretation of the CMOS clock register contents:
+     * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+     * RTC registers show the second which has precisely just started.
+     * Let's hope other operating systems interpret the RTC the same way.
+     */
+    /* read RTC exactly on falling edge of update flag */
+    for (i = 0; i < 1000000; i++)	/* may take up to 1 second... */
+	if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+	    break;
+    for (i = 0; i < 1000000; i++)	/* must try at least 2.228 ms */
+	if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+	    break;
+    do {			/* Isn't this overkill ? UIP above should guarantee consistency */
+	sec = CMOS_READ(RTC_SECONDS);
+	min = CMOS_READ(RTC_MINUTES);
+	hour = CMOS_READ(RTC_HOURS);
+	day = CMOS_READ(RTC_DAY_OF_MONTH);
+	mon = CMOS_READ(RTC_MONTH);
+	year = CMOS_READ(RTC_YEAR);
+    } while (sec != CMOS_READ(RTC_SECONDS));
+    if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+    }
+    /*
+     * The DECstation RTC is used as a TOY (Time Of Year).
+     * The PROM will reset the year to either '70, '71 or '72.
+     * This hack will only work until Dec 31 2001.
+     */
+    year += 1927;
+
+    xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+    xtime.tv_usec = 0;
+
+    init_cycle_counter();
+
+    if (cyclecounter_available) {
+	write_32bit_cp0_register(CP0_COUNT, 0);
+	do_gettimeoffset = do_fast_gettimeoffset;
+	irq0.handler = r4k_timer_interrupt;
+    }
+    board_time_init(&irq0);
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/dec/wbflush.c linux/arch/mips/dec/wbflush.c
--- v2.3.8/linux/arch/mips/dec/wbflush.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/dec/wbflush.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,104 @@
+/*
+ * Setup the right wbflush routine for the different DECstations.
+ *
+ * Created with information from:
+ *      DECstation 3100 Desktop Workstation Functional Specification
+ *      DECstation 5000/200 KN02 System Module Functional Specification
+ *      mipsel-linux-objdump --disassemble vmunix | grep "wbflush" :-)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1998 Harald Koerfgen
+ */
+
+#include <asm/bootinfo.h>
+#include <asm/init.h>
+
+static void wbflush_kn01(void);
+static void wbflush_kn210(void);
+static void wbflush_kn02ba(void);
+static void wbflush_kn03(void);
+
+void (*__wbflush) (void);
+
+__initfunc(void wbflush_setup(void))
+{
+	switch (mips_machtype) {
+	case MACH_DS23100:
+	    __wbflush = wbflush_kn01;
+	    break;
+	case MACH_DS5100:	/*  DS5100 MIPSMATE */
+	    __wbflush = wbflush_kn210;
+	    break;
+	case MACH_DS5000_200:	/* DS5000 3max */
+	    __wbflush = wbflush_kn01;
+	    break;
+	case MACH_DS5000_1XX:	/* DS5000/100 3min */
+	    __wbflush = wbflush_kn02ba;
+	    break;
+	case MACH_DS5000_2X0:	/* DS5000/240 3max+ */
+	    __wbflush = wbflush_kn03;
+	    break;
+	case MACH_DS5000_XX:	/* Personal DS5000/2x */
+	    __wbflush = wbflush_kn02ba;
+	    break;
+	}
+}
+
+/*
+ * For the DS3100 and DS5000/200 the writeback buffer functions
+ * as part of Coprocessor 0.
+ */
+static void wbflush_kn01(void)
+{
+    asm(".set\tpush\n\t"
+	".set\tnoreorder\n\t"
+	"1:\tbc0f\t1b\n\t"
+	"nop\n\t"
+	".set\tpop");
+}
+
+/*
+ * For the DS5100 the writeback buffer seems to be a part of Coprocessor 3.
+ * But CP3 has to enabled first.
+ */
+static void wbflush_kn210(void)
+{
+    asm(".set\tpush\n\t"
+	".set\tnoreorder\n\t"
+	"mfc0\t$2,$12\n\t"
+	"lui\t$3,0x8000\n\t"
+	"or\t$3,$2,$3\n\t"
+	"mtc0\t$3,$12\n\t"
+	"nop\n"
+	"1:\tbc3f\t1b\n\t"
+	"nop\n\t"
+	"mtc0\t$2,$12\n\t"
+	"nop\n\t"
+	".set\tpop"
+  : : :"$2", "$3");
+}
+
+/*
+ * Looks like some magic with the System Interrupt Mask Register
+ * in the famous IOASIC for kmins and maxines.
+ */
+static void wbflush_kn02ba(void)
+{
+    asm(".set\tpush\n\t"
+	".set\tnoreorder\n\t"
+	"lui\t$2,0xbc04\n\t"
+	"lw\t$3,0x120($2)\n\t"
+	"lw\t$3,0x120($2)\n\t"
+	".set\tpop"
+  : : :"$2", "$3");
+}
+
+/*
+ * The DS500/2x0 doesnt need to write back the WB.
+ */
+static void wbflush_kn03(void)
+{
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/defconfig linux/arch/mips/defconfig
--- v2.3.8/linux/arch/mips/defconfig	Thu Feb 25 10:46:47 1999
+++ linux/arch/mips/defconfig	Fri Jun 25 17:40:12 1999
@@ -10,13 +10,11 @@
 #
 # Machine selection
 #
-CONFIG_ACER_PICA_61=y
+# CONFIG_ACER_PICA_61 is not set
 # CONFIG_MIPS_MAGNUM_4000 is not set
 # CONFIG_OLIVETTI_M700 is not set
 # CONFIG_SGI is not set
 CONFIG_SNI_RM200_PCI=y
-CONFIG_MIPS_JAZZ=y
-CONFIG_VGA_CONSOLE=y
 CONFIG_PCI=y
 
 #
@@ -34,8 +32,10 @@
 #
 # General setup
 #
-CONFIG_ELF_KERNEL=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_PCI_OLD_PROC=y
 CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_ELF_KERNEL=y
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
@@ -49,21 +49,37 @@
 # Loadable module support
 #
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 
 #
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
 # Block devices
 #
-CONFIG_BLK_DEV_FD=y
-CONFIG_BLK_DEV_IDE=y
+CONFIG_BLK_DEV_FD=m
+CONFIG_BLK_DEV_IDE=m
 
 #
 # 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_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECD=m
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
@@ -75,13 +91,14 @@
 #
 # Additional Block Devices
 #
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_MD is not set
-# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM=m
 # CONFIG_BLK_DEV_XD is not set
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -106,7 +123,6 @@
 # (it is safe to leave these untouched)
 #
 # CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
 # CONFIG_SKB_LARGE is not set
 
 #
@@ -124,8 +140,8 @@
 # SCSI support type (disk, tape, CD-ROM)
 #
 CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=m
 # CONFIG_BLK_DEV_SR_VENDOR is not set
 # CONFIG_CHR_DEV_SG is not set
 
@@ -134,12 +150,13 @@
 #
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_LOGGING is not set
 
 #
 # 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
@@ -147,20 +164,25 @@
 # 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_EATA 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_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
-CONFIG_SCSI_NCR53C8XX_MAX_TAGS=4
-CONFIG_SCSI_NCR53C8XX_SYNC=5
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=20
 # CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_PAS16 is not set
@@ -169,13 +191,12 @@
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
-CONFIG_JAZZ_ESP=y
-CONFIG_JAZZ_ESP=y
 
 #
 # Network device support
@@ -185,7 +206,6 @@
 # CONFIG_DUMMY is not set
 # CONFIG_EQUALIZER is not set
 CONFIG_NET_ETHERNET=y
-CONFIG_MIPS_JAZZ_SONIC=y
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
@@ -211,6 +231,8 @@
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
 # CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
@@ -235,7 +257,7 @@
 # CONFIG_ISDN is not set
 
 #
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# comment
 #
 # CONFIG_CD_NO_IDESCSI is not set
 
@@ -244,18 +266,26 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
+CONFIG_SERIAL=m
 # CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_UNIX98_PTYS is not set
 # CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-# CONFIG_VIDEO_DEV is not set
 # 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
@@ -263,71 +293,93 @@
 # CONFIG_FTAPE is not set
 
 #
+# USB drivers - not for the faint of heart
+#
+# CONFIG_USB is not set
+
+#
 # Filesystems
 #
-# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
-CONFIG_VFAT_FS=y
-CONFIG_PROC_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFSD=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
+CONFIG_QUOTA=y
+CONFIG_AUTOFS_FS=m
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_UMSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_MINIX_FS=m
+# CONFIG_NTFS_FS is not set
+CONFIG_HPFS_FS=m
+CONFIG_PROC_FS=y
+CONFIG_ROMFS_FS=m
+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=m
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
 # CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
 # CONFIG_SMD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
+# CONFIG_SGI_DISKLABEL is not set
 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=y
-# 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=y
-# 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_KOI8_R is not set
+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=m
+CONFIG_NLS_KOI8_R=m
 
 #
 # Console drivers
 #
+CONFIG_VGA_CONSOLE=y
+# CONFIG_FB is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
 
 #
 # Sound
@@ -337,7 +389,6 @@
 #
 # Kernel hacking
 #
-CONFIG_CROSSCOMPILE=y
+# CONFIG_CROSSCOMPILE is not set
 # CONFIG_MIPS_FPE_MODULE is not set
-# CONFIG_REMOTE_DEBUG is not set
 # CONFIG_MAGIC_SYSRQ is not set
diff -u --recursive --new-file v2.3.8/linux/arch/mips/jazz/Makefile linux/arch/mips/jazz/Makefile
--- v2.3.8/linux/arch/mips/jazz/Makefile	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/jazz/Makefile	Fri Jun 25 17:40:12 1999
@@ -1,3 +1,4 @@
+# $Id: Makefile,v 1.6 1999/02/25 21:57:01 tsbogend Exp $
 #
 # Makefile for the Jazz family specific parts of the kernel
 #
@@ -13,7 +14,8 @@
 
 all: jazz.o
 O_TARGET := jazz.o
-O_OBJS	 := hw-access.o int-handler.o jazzdma.o reset.o rtc-jazz.o setup.o
+O_OBJS	 := int-handler.o jazzdma.o reset.o rtc-jazz.o setup.o floppy-jazz.o \
+	    kbd-jazz.o
 
 int-handler.o: int-handler.S
 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/jazz/floppy-jazz.c linux/arch/mips/jazz/floppy-jazz.c
--- v2.3.8/linux/arch/mips/jazz/floppy-jazz.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/jazz/floppy-jazz.c	Fri Jun 25 17:40:12 1999
@@ -14,11 +14,11 @@
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <asm/addrspace.h>
-#include <asm/vector.h>
 #include <asm/jazz.h>
 #include <asm/jazzdma.h>
 #include <asm/keyboard.h>
 #include <asm/pgtable.h>
+#include <asm/floppy.h>
 
 static unsigned char jazz_fd_inb(unsigned int port)
 {
@@ -108,7 +108,7 @@
 	return order;
 }
 
-extern inline unsigned long jazz_fd_dma_mem_alloc(unsigned long size)
+static unsigned long jazz_fd_dma_mem_alloc(unsigned long size)
 {
 	int order = __get_order(size);
 	unsigned long mem;
@@ -121,14 +121,14 @@
 	return mem;
 }
 
-extern inline void jazz_fd_dma_mem_free(unsigned long addr,
+static void jazz_fd_dma_mem_free(unsigned long addr,
                                         unsigned long size)
 {       
-	vdma_free(PHYSADDR(addr));
+	vdma_free(vdma_phys2log(PHYSADDR(addr)));
 	free_pages(addr, __get_order(size));	
 }
 
-static void std_fd_drive_type(unsigned long n)
+static unsigned long jazz_fd_drive_type(unsigned long n)
 {
 	/* XXX This is wrong for machines with ED 2.88mb disk drives like the
 	   Olivetti M700.  Anyway, we should suck this from the ARC
diff -u --recursive --new-file v2.3.8/linux/arch/mips/jazz/hw-access.c linux/arch/mips/jazz/hw-access.c
--- v2.3.8/linux/arch/mips/jazz/hw-access.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/jazz/hw-access.c	Wed Dec 31 16:00:00 1969
@@ -1,90 +0,0 @@
-/* $Id: hw-access.c,v 1.11 1998/09/16 22:50:39 ralf Exp $
- *
- * Low-level hardware access stuff for Jazz family machines.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle
- */
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/linkage.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <asm/addrspace.h>
-#include <asm/jazz.h>
-#include <asm/jazzdma.h>
-#include <asm/keyboard.h>
-#include <asm/pgtable.h>
-
-static volatile keyboard_hardware *jazz_kh = 
-	(keyboard_hardware *) JAZZ_KEYBOARD_ADDRESS;
-
-#define KBD_STAT_IBF		0x02	/* Keyboard input buffer full */
-
-static unsigned char jazz_read_input(void)
-{
-	return jazz_kh->data;
-}
-
-static void jazz_write_output(unsigned char val)
-{
-	int status;
-
-	do {
-		status = jazz_kh->command;
-	} while (status & KBD_STAT_IBF);
-	jazz_kh->data = val;
-}
-
-static void jazz_write_command(unsigned char val)
-{
-	int status;
-
-	do {
-		status = jazz_kh->command;
-	} while (status & KBD_STAT_IBF);
-	jazz_kh->command = val;
-}
-
-static unsigned char jazz_read_status(void)
-{
-	return jazz_kh->command;
-}
-
-__initfunc(void jazz_keyboard_setup(void))
-{
-	kbd_read_input = jazz_read_input;
-	kbd_write_output = jazz_write_output;
-	kbd_write_command = jazz_write_command;
-	kbd_read_status = jazz_read_status;
-	request_irq(JAZZ_KEYBOARD_IRQ, keyboard_interrupt,
-	            0, "keyboard", NULL);
-	request_region(0x60, 16, "keyboard");
-	r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
-	                  r4030_read_reg16(JAZZ_IO_IRQ_ENABLE)
-	                  | JAZZ_IE_KEYBOARD);
-}
-
-int jazz_ps2_request_irq(void)
-{
-    extern void aux_interrupt(int, void *, struct pt_regs *);
-    int ret;
-    
-    ret = request_irq(JAZZ_MOUSE_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL);
-    if (!ret)
-	r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 
-			  r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | 
-			  JAZZ_IE_MOUSE);
-    return ret;
-}
-
-void jazz_ps2_free_irq(void)
-{
-    r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 
-		      r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | 
-		      JAZZ_IE_MOUSE);
-    free_irq(JAZZ_MOUSE_IRQ, NULL);
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/jazz/int-handler.S linux/arch/mips/jazz/int-handler.S
--- v2.3.8/linux/arch/mips/jazz/int-handler.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/jazz/int-handler.S	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: int-handler.S,v 1.6 1998/08/28 15:55:19 ralf Exp $
+/* $Id: int-handler.S,v 1.14 1999/05/01 22:40:34 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -91,51 +91,8 @@
  * whistles and bells and we're aware of the problem.
  */
 ll_isa_irq:	lw	a0,JAZZ_EISA_IRQ_ACK
-		lui	s0,%hi(JAZZ_PORT_BASE)
-		li	s1,1
-		andi	t0,a0,8				# which pic?
-		bnez	t0,ack_second
-		andi	a0,7				# delay slot
 
-		/*
-		 * Acknowledge first pic
-		 */
-		lb	t2,%lo(JAZZ_PORT_BASE)+0x21(s0)
-		lui	s4,%hi(cache_21)
-		lb	t0,%lo(cache_21)(s4)
-		sllv	s1,s1,a0
-		or	t0,s1
-		sb	t0,%lo(cache_21)(s4)
-		sb	t0,%lo(JAZZ_PORT_BASE)+0x21(s0)
-		li	t2,0x20
-		sb	t2,%lo(JAZZ_PORT_BASE)+0x20(s0)
-		/*
-		 * Now call the real handler
-		 */
-		jal	do_IRQ
-		 move	a1,sp
-		j	ret_from_irq
-		nop
-
-		.align	5
-ack_second:	/*
-		 * Acknowledge second pic
-		 */
-		lbu	t2,%lo(JAZZ_PORT_BASE)+0xa1(s0)
-		lui	s4,%hi(cache_A1)
-		lb	t3,%lo(cache_A1)(s4)
-		sllv	s1,s1,a0
-		or	t3,s1
-		sb	t3,%lo(cache_A1)(s4)
-		sb	t3,%lo(JAZZ_PORT_BASE)+0xa1(s0)
-		li	t3,0x20
-		sb	t3,%lo(JAZZ_PORT_BASE)+0xa0(s0)
-		sb	t3,%lo(JAZZ_PORT_BASE)+0x20(s0)
-		/*
-		 * Now call the real handler
-		 */
-		or      a0, 8
-		jal	do_IRQ
+		jal	i8259_do_irq
 		 move	a1,sp
 
 		j	ret_from_irq
@@ -144,7 +101,7 @@
 /*
  * Hmm...  This is not just a plain PC clone so the question is
  * which devices on Jazz machines can generate an (E)ISA NMI?
- * (Writing to nonexistant memory?)
+ * (Writing to nonexistent memory?)
  */
 ll_isa_nmi:	li	s1,~IE_IRQ3
 		PANIC("Unimplemented isa_nmi handler")
@@ -152,7 +109,7 @@
 /*
  * Timer IRQ - remapped to be more similar to an IBM compatible.
  *
- * The timer interrupt is handled specially to insure that the jiffies
+ * The timer interrupt is handled specially to ensure that the jiffies
  * variable is updated at all times.  Specifically, the timer interrupt is
  * just like the complete handlers except that it is invoked with interrupts
  * disabled and should never re-enable them.  If other interrupts were
@@ -163,7 +120,7 @@
 ll_timer:	lw	zero,JAZZ_TIMER_REGISTER # timer irq cleared on read
 		li	s1,~IE_IRQ4
 
-		li	a0,0
+		li	a0, JAZZ_TIMER_IRQ
 		jal	do_IRQ
 		 move	a1,sp
 
@@ -228,14 +185,14 @@
 		b	loc_call
 
 /*
- * Floppy IRQ, remapped to level 6
+ * Floppy IRQ
  */
 loc_floppy:	li	s1,~JAZZ_IE_FLOPPY
 		li	a0,JAZZ_FLOPPY_IRQ
 		b	loc_call
 
 /*
- * Sound? What sound hardware (whistle) ???
+ * Sound IRQ
  */
 loc_sound:	PANIC("Unimplemented loc_sound handler")
 loc_video:	PANIC("Unimplemented loc_video handler")
diff -u --recursive --new-file v2.3.8/linux/arch/mips/jazz/jazzdma.c linux/arch/mips/jazz/jazzdma.c
--- v2.3.8/linux/arch/mips/jazz/jazzdma.c	Fri May  8 00:13:23 1998
+++ linux/arch/mips/jazz/jazzdma.c	Fri Jun 25 17:40:12 1999
@@ -97,6 +97,7 @@
     unsigned int frame;
     unsigned long laddr;
     int i;
+    unsigned long flags;
 
     /* check arguments */
   
@@ -113,6 +114,7 @@
         return VDMA_ERROR;	/* invalid physical address */
     }
   
+    save_and_cli (flags);
     /*
      * Find free chunk
      */
@@ -123,8 +125,10 @@
         while (entry[first].owner != VDMA_PAGE_EMPTY &&
                first < VDMA_PGTBL_ENTRIES)
             first++;
-        if (first+pages > VDMA_PGTBL_ENTRIES) /* nothing free */
+        if (first+pages > VDMA_PGTBL_ENTRIES) { /* nothing free */
+	    restore_flags (flags);
             return VDMA_ERROR;
+	}
 
         last = first+1;
         while (entry[last].owner == VDMA_PAGE_EMPTY && last-first < pages)
@@ -170,6 +174,7 @@
         printk("\n");
     }
   
+    restore_flags(flags);
     return laddr;
 }
 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/jazz/kbd-jazz.c linux/arch/mips/jazz/kbd-jazz.c
--- v2.3.8/linux/arch/mips/jazz/kbd-jazz.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/jazz/kbd-jazz.c	Fri Jun 25 17:40:12 1999
@@ -0,0 +1,102 @@
+/* $Id: kbd-jazz.c,v 1.1 1998/10/28 12:38:10 ralf Exp $
+ *
+ * Low-level hardware access stuff for Jazz family machines.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle
+ */
+#include <linux/sched.h>
+#include <linux/pc_keyb.h>
+#include <asm/keyboard.h>
+#include <asm/jazz.h>
+
+#define jazz_kh ((keyboard_hardware *) JAZZ_KEYBOARD_ADDRESS)
+
+static void jazz_request_region(void)
+{
+	/* No I/O ports are being used on Jazz.  */
+}
+
+static int jazz_request_irq(void (*handler)(int, void *, struct pt_regs *))
+{
+	int res;
+
+	res = request_irq(JAZZ_KEYBOARD_IRQ, handler, 0, "keyboard", NULL);
+	if (res != 0)
+		return res;
+
+	/* jazz_request_irq() should do this ...  */
+	r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
+	                  r4030_read_reg16(JAZZ_IO_IRQ_ENABLE)
+	                  | JAZZ_IE_KEYBOARD);
+
+	return 0;
+}
+
+static int jazz_aux_request_irq(void (*handler)(int, void *, struct pt_regs *))
+{
+	int ret;
+    
+	ret = request_irq(JAZZ_MOUSE_IRQ, handler, 0, "PS/2 Mouse", NULL);
+	if (ret != 0)
+		return ret;
+
+		r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 
+				  r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | 
+				  JAZZ_IE_MOUSE);
+	return 0;
+}
+
+static void jazz_aux_free_irq(void)
+{
+	r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, 
+	                  r4030_read_reg16(JAZZ_IO_IRQ_ENABLE)
+	                  | JAZZ_IE_MOUSE);
+	free_irq(JAZZ_MOUSE_IRQ, NULL);
+}
+
+static unsigned char jazz_read_input(void)
+{
+	return jazz_kh->data;
+}
+
+static void jazz_write_output(unsigned char val)
+{
+	int status;
+
+	do {
+		status = jazz_kh->command;
+	} while (status & KBD_STAT_IBF);
+	jazz_kh->data = val;
+}
+
+static void jazz_write_command(unsigned char val)
+{
+	int status;
+
+	do {
+		status = jazz_kh->command;
+	} while (status & KBD_STAT_IBF);
+	jazz_kh->command = val;
+}
+
+static unsigned char jazz_read_status(void)
+{
+	return jazz_kh->command;
+}
+
+struct kbd_ops jazz_kbd_ops = {
+	jazz_request_region,
+	jazz_request_irq,
+
+	jazz_aux_request_irq,
+	jazz_aux_free_irq,
+
+	jazz_read_input,
+	jazz_write_output,
+	jazz_write_command,
+	jazz_read_status
+};
diff -u --recursive --new-file v2.3.8/linux/arch/mips/jazz/reset.c linux/arch/mips/jazz/reset.c
--- v2.3.8/linux/arch/mips/jazz/reset.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/jazz/reset.c	Fri Jun 25 17:40:12 1999
@@ -3,7 +3,7 @@
  *
  *  Reset a Jazz machine.
  *
- *  $Id: reset.c,v 1.2 1998/03/04 12:17:40 ralf Exp $
+ *  $Id: reset.c,v 1.3 1998/03/04 08:29:10 ralf Exp $
  */
 
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/jazz/rtc-jazz.c linux/arch/mips/jazz/rtc-jazz.c
--- v2.3.8/linux/arch/mips/jazz/rtc-jazz.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/jazz/rtc-jazz.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: rtc-jazz.c,v 1.3 1998/08/28 15:55:19 ralf Exp $
+/* $Id: rtc-jazz.c,v 1.2 1998/06/25 20:19:14 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
diff -u --recursive --new-file v2.3.8/linux/arch/mips/jazz/setup.c linux/arch/mips/jazz/setup.c
--- v2.3.8/linux/arch/mips/jazz/setup.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/jazz/setup.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.14 1998/09/16 22:50:40 ralf Exp $
+/* $Id: setup.c,v 1.20 1999/02/25 21:57:47 tsbogend Exp $
  *
  * Setup pointers to hardware-dependent routines.
  *
@@ -12,7 +12,6 @@
 #include <linux/hdreg.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/kbd_ll.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/mm.h>
@@ -40,7 +39,6 @@
 static struct irqaction irq2  = { no_action, 0, 0, "cascade", NULL, NULL};
 
 extern asmlinkage void jazz_handle_int(void);
-extern void jazz_keyboard_setup(void);
 
 extern void jazz_machine_restart(char *command);
 extern void jazz_machine_halt(void);
@@ -48,6 +46,9 @@
 
 extern struct ide_ops std_ide_ops;
 extern struct rtc_ops jazz_rtc_ops;
+extern struct kbd_ops jazz_kbd_ops;
+extern struct fd_ops *fd_ops;
+extern struct fd_ops jazz_fd_ops;
 
 void (*board_time_init)(struct irqaction *irq);
 
@@ -55,7 +56,7 @@
 {
         /* set the clock to 100 Hz */
         r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
-        setup_x86_irq(0, irq);
+        i8259_setup_irq(JAZZ_TIMER_IRQ, irq);
 }
 
 __initfunc(static void jazz_irq_setup(void))
@@ -75,43 +76,16 @@
 	r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
 	request_region(0x20, 0x20, "pic1");
 	request_region(0xa0, 0x20, "pic2");
-	setup_x86_irq(2, &irq2);
+	i8259_setup_irq(2, &irq2);
 }
 
 __initfunc(void jazz_setup(void))
 {
-    tag *atag;
-
-    /*
-     * we just check if a tag_screen_info can be gathered
-     * in setup_arch(), if yes we don't proceed futher...
-     */
-    atag = bi_TagFind(tag_screen_info);
-    if (!atag) {
-	/*
-	 * If no, we try to find the tag_arc_displayinfo which is
-	 * always created by Milo for an ARC box (for now Milo only
-	 * works on ARC boxes :) -Stoned.
-	 */
-	atag = bi_TagFind(tag_arcdisplayinfo);
-	if (atag) {
-	    screen_info.orig_x = 
-		((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x;
-	    screen_info.orig_y = 
-		((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y;
-	    screen_info.orig_video_cols  = 
-		((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns;
-	    screen_info.orig_video_lines  = 
-		((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines;
-	}
-    }
-
 	add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K);
 	add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M);
 	add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M);
 
 	irq_setup = jazz_irq_setup;
-	keyboard_setup = jazz_keyboard_setup;
 	mips_io_port_base = JAZZ_PORT_BASE;
 	isa_slot_offset = 0xe3000000;
 	request_region(0x00,0x20,"dma1");
@@ -128,6 +102,8 @@
 #ifdef CONFIG_BLK_DEV_IDE
 	ide_ops = &std_ide_ops;
 #endif
-	conswitchp = &fb_con;
+	conswitchp = &dummy_con;
 	rtc_ops = &jazz_rtc_ops;
+	kbd_ops = &jazz_kbd_ops;
+	fd_ops = &jazz_fd_ops;
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/Makefile linux/arch/mips/kernel/Makefile
--- v2.3.8/linux/arch/mips/kernel/Makefile	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/Makefile	Fri Jun 25 17:40:12 1999
@@ -23,10 +23,14 @@
 endif
 
 #
-# SGI's have very different interrupt/timer hardware.
+# SGIs have very different interrupt/timer hardware.
 #
 ifndef CONFIG_SGI
-O_OBJS += irq.o time.o
+  ifndef CONFIG_DECSTATION
+    ifndef CONFIG_BAGET_MIPS
+      O_OBJS += irq.o time.o
+    endif
+  endif
 endif
 
 #
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/entry.S linux/arch/mips/kernel/entry.S
--- v2.3.8/linux/arch/mips/kernel/entry.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/entry.S	Fri Jun 25 17:40:12 1999
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1994, 1995 by Ralf Baechle
  *
- * $Id: entry.S,v 1.15 1998/10/14 20:26:26 ralf Exp $
+ * $Id: entry.S,v 1.14 1999/04/12 19:13:21 harald Exp $
  */
 
 /*
@@ -146,7 +146,7 @@
 		BUILD_HANDLER(adel,ade,ade,silent)		/* #4  */
 		BUILD_HANDLER(ades,ade,ade,silent)		/* #5  */
 		BUILD_HANDLER(ibe,ibe,cli,verbose)		/* #6  */
-		BUILD_HANDLER(dbe,dbe,cli,verbose)		/* #7  */
+		BUILD_HANDLER(dbe,dbe,cli,silent)		/* #7  */
 		BUILD_HANDLER(bp,bp,sti,silent)			/* #9  */
 		BUILD_HANDLER(ri,ri,sti,silent)			/* #10 */
 		BUILD_HANDLER(cpu,cpu,sti,silent)		/* #11 */
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/fpe.c linux/arch/mips/kernel/fpe.c
--- v2.3.8/linux/arch/mips/kernel/fpe.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/fpe.c	Fri Jun 25 17:40:12 1999
@@ -6,7 +6,7 @@
  *
  * Copyright (C) 1997 Ralf Baechle
  *
- * $Id: fpe.c,v 1.2 1998/03/27 08:53:39 ralf Exp $
+ * $Id: fpe.c,v 1.4 1999/05/01 22:40:35 ralf Exp $
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -39,7 +39,7 @@
 
 /*
  * For easier experimentation we never increment/decrement
- * the module useable counter.
+ * the module usable counter.
  */
 int register_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
 int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/gdb-low.S linux/arch/mips/kernel/gdb-low.S
--- v2.3.8/linux/arch/mips/kernel/gdb-low.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/gdb-low.S	Fri Jun 25 17:40:12 1999
@@ -5,7 +5,7 @@
  *
  * Copyright (C) 1995 Andreas Busse
  *
- * $Id: gdb-low.S,v 1.3 1997/12/02 05:51:05 ralf Exp $
+ * $Id: gdb-low.S,v 1.4 1997/12/01 17:57:26 ralf Exp $
  */
 
 #include <linux/sys.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/gdb-stub.c linux/arch/mips/kernel/gdb-stub.c
--- v2.3.8/linux/arch/mips/kernel/gdb-stub.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/gdb-stub.c	Fri Jun 25 17:40:12 1999
@@ -12,7 +12,7 @@
  *
  *  Copyright (C) 1995 Andreas Busse
  *
- * $Id: gdb-stub.c,v 1.4 1997/12/02 05:51:06 ralf Exp $
+ * $Id: gdb-stub.c,v 1.7 1999/06/12 18:39:28 ulfc Exp $
  */
 
 /*
@@ -326,7 +326,7 @@
 	{ 7, SIGBUS },			/* data bus error */
 	{ 9, SIGTRAP },			/* break */
 	{ 10, SIGILL },			/* reserved instruction */
-/*	{ 11, SIGILL },		*/	/* cpu unusable */
+/*	{ 11, SIGILL },		*/	/* CPU unusable */
 	{ 12, SIGFPE },			/* overflow */
 	{ 13, SIGTRAP },		/* trap */
 	{ 14, SIGSEGV },		/* virtual instruction cache coherency */
@@ -362,8 +362,6 @@
 
 	initialized = 1;
 	restore_flags(flags);
-
-	breakpoint();
 }
 
 
@@ -379,7 +377,7 @@
 }
 
 /*
- * Convert the MIPS hardware trap type code to a unix signal number.
+ * Convert the MIPS hardware trap type code to a Unix signal number.
  */
 static int computeSignal(int tt)
 {
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/head.S linux/arch/mips/kernel/head.S
--- v2.3.8/linux/arch/mips/kernel/head.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/head.S	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.13 1998/10/14 20:26:27 ralf Exp $
+/* $Id: head.S,v 1.11 1998/10/18 13:27:12 tsbogend Exp $
  *
  * arch/mips/kernel/head.S
  *
@@ -408,15 +408,7 @@
 
 probe_done:
 
-#ifndef CONFIG_SGI
-	/* Get the memory upper limit the bootloader passed to us
-	 * in a0
-	 */
-	la	t0, mips_memory_upper
-	nop
-	sw	a0, (t0)		
-#else
-	/* On SGI's the firmware/bootloader passes argc/argp/envp
+	/* The firmware/bootloader passes argc/argp/envp
 	 * to us as arguments.  But clear bss first because
 	 * the romvec and other important info is stored there
 	 * by prom_init().
@@ -431,6 +423,7 @@
 
 	jal	prom_init /* prom_init(argc, argv, envp); */
 	 nop
+#ifdef CONFIG_SGI
 	jal	sgi_sysinit
 	 nop
 #endif
@@ -440,18 +433,6 @@
 	 nop
 #endif
 
-	/* Get the very one tags we need early in the boot process */
-	nop
-	jal	bi_EarlySnarf
-	 nop
-#ifndef CONFIG_SGI
-	/* Clear BSS first so that there are no surprises... */
-	la	t0, _edata
-	la	t1, _end
-1:	addiu	t0, 1
-	bne	t0, t1, 1b
-	sb	zero, -1(t0)
-#endif
 	/*
 	 * Determine the mmu/cache attached to this machine,
 	 * then flush the tlb and caches.  On the r4xx0
@@ -460,34 +441,10 @@
 	jal	loadmmu
 	 nop
 
-	la	t2, mips_cputype
-	lw	t4, (t2)
-	li	t1, CPU_R2000
-	li	t2, CPU_R3000
-	li	t3, CPU_R3000A
-	beq	t4,t1,2f
-	 nop		
-
-	beq	t4,t2,2f
-	 nop		
-
-	beq	t4,t3,2f
-	 nop		
-
-	jal	wire_mappings_r4xx0
-	 nop	
-
-	b	9f
-	 nop
-
-2:
-	jal	wire_mappings_r3000
-	 nop	
-
 	/*
 	 * Stack for kernel and init, current variable
 	 */
-9:	la	$28, init_task_union
+	la	$28, init_task_union
 	addiu	t0, $28, KERNEL_STACK_SIZE-32
 	sw	t0, kernelsp
 	subu	sp, t0, 4*SZREG
@@ -509,81 +466,6 @@
 	 nop					# delay slot
 	END(kernel_entry)
 
-/*
- * wire_mappings - used to map hardware registers, r4xx0 version.
- */
-LEAF(wire_mappings_r4xx0)
-	mtc0	zero, CP0_WIRED
-	nop
-	nop
-	nop
-	j	ra
-	 nop
-	END(wire_mappings_r4xx0)
-
-/*
- * R3000 version of wire_mappings.
- */
-LEAF(wire_mappings_r3000)
-	/*
-	 * Get base address of map0 table for the
-	 * the board we're running on
-	 */
-	lw	t1, mips_machtype
-	la	t0, map0table
-	sll	t1, PTRLOG		# machtype used as index
-	addu	t0, t1
-	lw	t0, (t0)		# get base address
-	nop
-	/* Get number of wired TLB entries and
-	 * loop over selected map0 table.
-	 */
-	lw	t1, (t0)		# number of wired TLB entries
-	move	t2, zero		# TLB entry counter
-	addiu	t3, t1, 1		# wire one additional entry
-	beqz	t1, 2f			# null, exit
-	 nop
-
-	addiu	t0, 8
-1:
-	lw	t4, 24(t0)		# PageMask
-	ld	t5,  0(t0)		# entryHi
-	ld	t6,  8(t0)		# entryLo0
-	addiu	t2, 1			# increment ctr
-	mtc0	t2, CP0_INDEX		# set TLB entry
-	nop
-	mtc0	t5, CP0_ENTRYHI
-	nop
-	mtc0	t6, CP0_ENTRYLO0
-	addiu	t0, 32
-	bne	t1, t2, 1b		# next TLB entry
-	 tlbwi
-
-	/* We use only 4k pages. Therefore the PageMask register
-	 * is expected to be setup for 4k pages.
-	 */
-2:
-	/* Now map the pagetables */
-	mtc0	zero, CP0_INDEX
-	la	t0, TLB_ROOT
-	mtc0	t0, CP0_ENTRYHI
-	nop
-	la	t0, swapper_pg_dir
-	srl	t0, 12
-	ori	t0, (0x00e0|0x0100)	# uncachable, dirty, valid
-	mtc0	t0, CP0_ENTRYLO0
-	nop
-	tlbwi				# delayed
-
-	/* Load the context register with zero.  To see why, look
-	 * at how the tlb refill code above works.
-	 */
-	mtc0	zero, CP0_CONTEXT
-
-	jr	ra
-	 nop
-	END(wire_mappings_r3000)
-
 	/* CPU type probing code, called at Kernel entry. */
 	LEAF(cpu_probe)
 	mfc0	t0, CP0_PRID
@@ -707,115 +589,6 @@
 	b	probe_done
 	 nop
 	END(cpu_probe)
-
-	.data
-/*
- * Build an entry for table of wired entries
- */
-#define MAPDATA(q1,q2,q3,w1)                                    \
-		.quad	q1;                                     \
-		.quad	q2;                                     \
-		.quad	q3;                                     \
-		.word	w1;                                     \
-		.word	0
-
-/*
- * Initial mapping tables for supported Mips boards.
- * First item is always the number of wired TLB entries,
- * following by EntryHi/EntryLo pairs and page mask.
- * Since everything must be quad-aligned (8) we insert
- * some dummy zeros.
- *
- * Keep in mind that the PFN does not depend on the page size in the
- * TLB page mask register.  See milo's lib/dumptlb.c for how to decode
- * and encode these entries.  Don't see the same routine in the linux
- * kernel distribution, since it is older and unreliable.
- */
-
-/*
- * Address table of mapping tables for supported Mips boards.
- * Add your own stuff here but don't forget to define your
- * target system in bootinfo.h
- */
-
-map0table:	PTR	map0_dummy		# machtype = unknown
-		PTR	map0_rpc		# Deskstation rPC44
-		PTR	map0_tyne		# Deskstation Tyne
-		PTR	map0_pica61		# Acer Pica-61
-		PTR	map0_magnum4000		# MIPS Magnum 4000PC (RC4030)
-		PTR	map0_dummy
-		PTR	map0_dummy		# DEC Personal DECStation 5000/2x (for now)
-		PTR	map0_sni_rm200_pci	# SNI RM200 PCI
-		PTR	map0_dummy		# SGI INDY
-
-map0_dummy:	.word	0			# 0 entries
-
-		.align  3
-/*
- * Deskstation rpc44 mappings.  This machine has its EISA bus at physical
- * address 0xa0000000 which we map for 32M, but that doesn't match EISA
- * spec.  Not sure what to do about this.  Its I/O ports are memory mapped
- * at physical memory location 0xb0000000.
- */
-map0_rpc: 	.word   2			# no. of wired TLB entries
-		.word	0			# pad for alignment
-
-MAPDATA(0xffffffffe0000000, 0x02800017, 0x00000001, PM_16M)	# ISA Memory space
-MAPDATA(0xffffffffe2000000, 0x02c00017, 0x00000001, PM_64K)	# ISA I/O Space
-
-/*
- * Initial mappings for Deskstation Tyne boards.
- */
-map0_tyne: 	.word   2			# no. of wired TLB entries
-		.word	0			# pad for alignment
-
-MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000001, PM_1M)	# VESA DMA cache
-MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M)	# VESA I/O and memory space
-
-/*
- * Initial mapping for ACER PICA-61 boards.
- * FIXME: These are rather preliminary since many drivers, such as serial,
- * parallel, scsi and ethernet need some changes to distinguish between "local"
- * (built-in) and "optional" (ISA/PCI) I/O hardware. Local video ram is mapped
- * to the same location as the bios maps it to. Console driver has been changed
- * accordingly (new video type: VIDEO_TYPE_PICA_S3).
- * FIXME: Remove or merge some of the mappings.
- */
-map0_pica61:	.word  	7			# no. wired TLB entries
-		.word	0			# dummy
-
-MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, PM_64K)	# Local I/O space
-MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, PM_4K)	# Interrupt source register
-MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M)	# Local video control
-MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M)	# Extended video control
-MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M)	# Local video memory (BIOS mapping)
-MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M)	# ISA I/O and ISA memory space (both 16M)
-MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K)	# PCR (???)
-
-/*
- * Initial mapping for Mips Magnum 4000PC systems.
- * Do you believe me now that the Acer and Mips boxes are nearly the same ? :-)
- * FIXME: Remove or merge some of the mappings.
- */
-map0_magnum4000:
-		.word  	8			# no. wired TLB entries
-		.word	0			# dummy
-
-MAPDATA(0xffffffffe1000000, 0x03ffc013, 0x00000001, PM_256K)	# 0
-MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, PM_64K)	# 1 local I/O
-MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, PM_4K)	# 2 IRQ source
-MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M)	# 3 local video ctrl
-MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M)	# 4 ext. video ctrl
-MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M)	# 5 local video mem.
-MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M)	# 6 ISA I/O and mem.
-MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K)	# 7 PCR
-
-/*
- * The RM200 doesn't need any wired entries.
- */
-map0_sni_rm200_pci:
-		.word  	0			# no. wired TLB entries
-		.word	0			# dummy
 
 /*
  * This buffer is reserved for the use of the cache error handler.
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/init_task.c linux/arch/mips/kernel/init_task.c
--- v2.3.8/linux/arch/mips/kernel/init_task.c	Fri May  8 00:13:23 1998
+++ linux/arch/mips/kernel/init_task.c	Fri Jun 25 17:40:12 1999
@@ -9,7 +9,7 @@
 static struct files * init_fd_array[NR_OPEN] = { NULL, };
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
-struct mm_struct init_mm = INIT_MM;
+struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
  * Initial task structure.
@@ -21,4 +21,6 @@
  *
  * The things we do for performance..
  */
-union task_union init_task_union __attribute__((__section__(".text"))) = { INIT_TASK };
+union task_union init_task_union
+	__attribute__((__section__(".text"))) =
+		{ INIT_TASK(init_task_union.task) };
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/irix5sys.h linux/arch/mips/kernel/irix5sys.h
--- v2.3.8/linux/arch/mips/kernel/irix5sys.h	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/irix5sys.h	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: irix5sys.h,v 1.2 1998/08/17 10:16:25 ralf Exp $
+/* $Id: irix5sys.h,v 1.2 1998/08/25 09:14:39 ralf Exp $
  *
  * irix5sys.h: 32-bit IRIX5 ABI system call table.
  *
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/irixelf.c linux/arch/mips/kernel/irixelf.c
--- v2.3.8/linux/arch/mips/kernel/irixelf.c	Thu Jun  3 23:15:29 1999
+++ linux/arch/mips/kernel/irixelf.c	Sat Jun 26 18:03:31 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: irixelf.c,v 1.17 1999/06/17 13:25:45 ralf Exp $
+ *
  * irixelf.c: Code to load IRIX ELF executables which conform to
  *            the MIPS ABI.
  *
@@ -307,7 +308,7 @@
 		return 0xffffffff;
 	}
 
-	file = current->files->fd[elf_exec_fileno];
+	file = fget(elf_exec_fileno);
 
 	eppnt = elf_phdata;
 	for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
@@ -365,6 +366,7 @@
 	}
 
 	/* Now use mmap to map the library into memory. */
+	fput(file);
 	sys_close(elf_exec_fileno);
 	if(error < 0 && error > -1024) {
 #ifdef DEBUG_ELF
@@ -612,8 +614,9 @@
 	unsigned int load_addr, elf_bss, elf_brk;
 	unsigned int elf_entry, interp_load_addr = 0;
 	unsigned int start_code, end_code, end_data, elf_stack;
-	int elf_exec_fileno, retval, has_interp, has_ephdr, i;
+	int elf_exec_fileno, retval, has_interp, has_ephdr, size, i;
 	char *elf_interpreter;
+	struct file *file;
 	mm_segment_t old_fs;
 	
 	load_addr = 0;
@@ -629,17 +632,15 @@
 #endif
 
 	/* Now read in all of the header information */
-	elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * 
-						 elf_ex.e_phnum, GFP_KERNEL);
+	size = elf_ex.e_phentsize * elf_ex.e_phnum;
+	elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
 	if (elf_phdata == NULL)
 		return -ENOMEM;
 	
-	retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata,
-			   elf_ex.e_phentsize * elf_ex.e_phnum, 1);
-	if (retval < 0) {
-		kfree (elf_phdata);
-		return retval;
-	}
+	retval = read_exec(bprm->dentry, elf_ex.e_phoff,
+	                   (char *) elf_phdata, size, 1);
+	if (retval < 0)
+		goto out_phdata;
 	
 #ifdef DEBUG_ELF
 	dump_phdrs(elf_phdata, elf_ex.e_phnum);
@@ -664,12 +665,10 @@
 
 	elf_bss = 0;
 	elf_brk = 0;
-	elf_exec_fileno = open_dentry(bprm->dentry, O_RDONLY);
-
-	if (elf_exec_fileno < 0) {
-		kfree (elf_phdata);
-		return elf_exec_fileno;
-	}
+	retval = open_dentry(bprm->dentry, O_RDONLY);
+	if (retval < 0)
+		goto out_phdata;
+	file = fget(elf_exec_fileno = retval);
 	
 	elf_stack = 0xffffffff;
 	elf_interpreter = NULL;
@@ -681,40 +680,26 @@
 	                                   &interpreter_dentry,
 					   &interp_elf_ex, elf_phdata, bprm,
 					   elf_ex.e_phnum);
-	if(retval) {
-		kfree(elf_phdata);
-		sys_close(elf_exec_fileno);
-		return retval;
-	}
+	if(retval)
+		goto out_file;
 	
 	if(elf_interpreter) {
 		retval = verify_irix_interpreter(&interp_elf_ex);
-		if(retval) {
-			kfree(elf_interpreter);
-			kfree(elf_phdata);
-			sys_close(elf_exec_fileno);
-			return retval;
-		}
+		if(retval)
+			goto out_interp;
 	}
 	
 	/* OK, we are done with that, now set up the arg stuff,
 	 * and then start this sucker up.
 	 */
-	if (!bprm->sh_bang) {
-		if (!bprm->p) {
-			if(elf_interpreter) {
-			      kfree(elf_interpreter);
-			}
-			kfree (elf_phdata);
-			sys_close(elf_exec_fileno);
-			return -E2BIG;
-		}
-	}
+	retval = -E2BIG;
+	if (!bprm->sh_bang && !bprm->p)
+		goto out_interp;
 	
 	/* Flush all traces of the currently running executable */
 	retval = flush_old_exec(bprm);
 	if (retval)
-		return retval;
+		goto out_interp;
 
 	/* OK, This is the point of no return */
 	current->mm->end_data = 0;
@@ -727,7 +712,7 @@
 	 * change some of these later.
 	 */
 	current->mm->rss = 0;
-	bprm->p = setup_arg_pages(bprm->p, bprm);
+	setup_arg_pages(bprm);
 	current->mm->start_stack = bprm->p;
 	
 	/* At this point, we assume that the image should be loaded at
@@ -736,8 +721,7 @@
 	old_fs = get_fs();
 	set_fs(get_ds());
 	
-	map_executable(current->files->fd[elf_exec_fileno], elf_phdata,
-		       elf_ex.e_phnum, &elf_stack, &load_addr,
+	map_executable(file, elf_phdata, elf_ex.e_phnum, &elf_stack, &load_addr,
 		       &start_code, &elf_bss, &end_code, &end_data, &elf_brk);
 
 	if(elf_interpreter) {
@@ -757,6 +741,7 @@
 	set_fs(old_fs);
 	
 	kfree(elf_phdata);
+	fput(file);
 	sys_close(elf_exec_fileno);
 	current->personality = PER_IRIX32;
 
@@ -797,12 +782,12 @@
 	padzero(elf_bss);
 
 #ifdef DEBUG_ELF
-	printk("(start_brk) %08lx\n" , current->mm->start_brk);
-	printk("(end_code) %08lx\n" , current->mm->end_code);
-	printk("(start_code) %08lx\n" , current->mm->start_code);
-	printk("(end_data) %08lx\n" , current->mm->end_data);
-	printk("(start_stack) %08lx\n" , current->mm->start_stack);
-	printk("(brk) %08lx\n" , current->mm->brk);
+	printk("(start_brk) %lx\n" , (long) current->mm->start_brk);
+	printk("(end_code) %lx\n" , (long) current->mm->end_code);
+	printk("(start_code) %lx\n" , (long) current->mm->start_code);
+	printk("(end_data) %lx\n" , (long) current->mm->end_data);
+	printk("(start_stack) %lx\n" , (long) current->mm->start_stack);
+	printk("(brk) %lx\n" , (long) current->mm->brk);
 #endif
 
 #if 0 /* XXX No fucking way dude... */
@@ -819,6 +804,17 @@
 	if (current->flags & PF_PTRACED)
 		send_sig(SIGTRAP, current, 0);
 	return 0;
+
+out_interp:
+	if(elf_interpreter) {
+	      kfree(elf_interpreter);
+	}
+out_file:
+	fput(file);
+	sys_close(elf_exec_fileno);
+out_phdata:
+	kfree (elf_phdata);
+	return retval;
 }
 
 static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
@@ -834,9 +830,8 @@
 /* This is really simpleminded and specialized - we are loading an
  * a.out library that is given an ELF header.
  */
-static inline int do_load_irix_library(int fd)
+static inline int do_load_irix_library(struct file *file)
 {
-	struct file * file;
 	struct elfhdr elf_ex;
 	struct elf_phdr *elf_phdata  =  NULL;
 	struct dentry *dentry;
@@ -849,14 +844,12 @@
 	int i,j, k;
 
 	len = 0;
-	file = current->files->fd[fd];
+	if (!file->f_op)
+		return -EACCES;
 	dentry = file->f_dentry;
 	inode = dentry->d_inode;
 	elf_bss = 0;
 	
-	if (!file || !file->f_op)
-		return -EACCES;
-
 	/* Seek to the beginning of the file. */
 	if (file->f_op->llseek) {
 		if ((error = file->f_op->llseek(file, 0, 0)) != 0)
@@ -933,10 +926,15 @@
 
 static int load_irix_library(int fd)
 {
-	int retval;
+	int retval = -EACCES;
+	struct file *file;
 
 	MOD_INC_USE_COUNT;
-	retval = do_load_irix_library(fd);
+	file = fget(fd);
+	if (file) {
+		retval = do_load_irix_library(file);
+		fput(file);
+	}
 	MOD_DEC_USE_COUNT;
 	return retval;
 }
@@ -977,9 +975,12 @@
 			return -ENOEXEC;
 		}
 
-	filp = current->files->fd[fd];
-	if(!filp || !filp->f_op) {
+	filp = fget(fd);
+	if (!filp)
+		return -EACCES;
+	if(!filp->f_op) {
 		printk("irix_mapelf: Bogon filp!\n");
+		fput(file);
 		return -EACCES;
 	}
 
@@ -997,6 +998,7 @@
 
 		if(retval != (hp->p_vaddr & 0xfffff000)) {
 			printk("irix_mapelf: do_mmap fails with %d!\n", retval);
+			fput(file);
 			return retval;
 		}
 	}
@@ -1004,6 +1006,7 @@
 #ifdef DEBUG_ELF
 	printk("irix_mapelf: Success, returning %08lx\n", user_phdrp->p_vaddr);
 #endif
+	fput(file);
 	return user_phdrp->p_vaddr;
 }
 
@@ -1101,10 +1104,10 @@
 #undef DUMP_SEEK
 
 #define DUMP_WRITE(addr, nr)	\
-	if (!dump_write(&file, (addr), (nr))) \
+	if (!dump_write(file, (addr), (nr))) \
 		goto close_coredump;
 #define DUMP_SEEK(off)	\
-	if (!dump_seek(&file, (off))) \
+	if (!dump_seek(file, (off))) \
 		goto close_coredump;
 /* Actual dumper.
  *
@@ -1115,7 +1118,7 @@
 static int irix_core_dump(long signr, struct pt_regs * regs)
 {
 	int has_dumped = 0;
-	struct file file;
+	struct file *file;
 	struct dentry *dentry;
 	struct inode *inode;
 	mm_segment_t fs;
@@ -1184,26 +1187,28 @@
 	
 	fs = get_fs();
 	set_fs(KERNEL_DS);
+
 	memcpy(corefile,"core.", 5);
 #if 0
 	memcpy(corefile+5,current->comm,sizeof(current->comm));
 #else
 	corefile[4] = '\0';
 #endif
-	dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
-	if (IS_ERR(dentry)) {
-		inode = NULL;
+	file = filp_open(corefile, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600);
+	if (IS_ERR(file))
 		goto end_coredump;
-	}
+	dentry = file->f_dentry;
 	inode = dentry->d_inode;
+	if (inode->i_nlink > 1)
+		goto close_coredump;	/* multiple links - don't dump */
+
 	if (!S_ISREG(inode->i_mode))
-		goto end_coredump;
+		goto close_coredump;
 	if (!inode->i_op || !inode->i_op->default_file_ops)
-		goto end_coredump;
-	if (init_private_file(&file, dentry, 3))
-		goto end_coredump;
-	if (!file.f_op->write)
 		goto close_coredump;
+	if (!file->f_op->write)
+		goto close_coredump;
+
 	has_dumped = 1;
 	current->flags |= PF_DUMPCORE;
 
@@ -1339,7 +1344,7 @@
 	}
 
 	for(i = 0; i < numnote; i++)
-		if (!writenote(&notes[i], &file))
+		if (!writenote(&notes[i], file))
 			goto close_coredump;
 	
 	set_fs(fs);
@@ -1361,19 +1366,17 @@
 		DUMP_WRITE((void *)addr, len);
 	}
 
-	if ((off_t) file.f_pos != offset) {
+	if ((off_t) file->f_pos != offset) {
 		/* Sanity check. */
-		printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
-		       (off_t) file.f_pos, offset);
+		printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
+		       (off_t) file->f_pos, offset);
 	}
 
  close_coredump:
-	if (file.f_op->release)
-		file.f_op->release(inode, &file);
+	filp_close(file, NULL);
 
  end_coredump:
 	set_fs(fs);
-	dput(dentry);
 #ifndef CONFIG_BINFMT_ELF
 	MOD_DEC_USE_COUNT;
 #endif
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/irixinv.c linux/arch/mips/kernel/irixinv.c
--- v2.3.8/linux/arch/mips/kernel/irixinv.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/irixinv.c	Fri Jun 25 17:40:12 1999
@@ -5,7 +5,7 @@
  *
  * Miguel de Icaza, 1997.
  *
- * $Id: irixinv.c,v 1.3 1998/03/27 08:53:40 ralf Exp $
+ * $Id: irixinv.c,v 1.3 1998/04/05 11:23:51 ralf Exp $
  */
 #include <linux/mm.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/irixioctl.c linux/arch/mips/kernel/irixioctl.c
--- v2.3.8/linux/arch/mips/kernel/irixioctl.c	Sat May  8 11:14:01 1999
+++ linux/arch/mips/kernel/irixioctl.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: irixioctl.c,v 1.4 1998/03/04 12:17:41 ralf Exp $
+/* $Id: irixioctl.c,v 1.6 1999/02/06 05:12:56 adevries Exp $
  * irixioctl.c: A fucking mess...
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -11,6 +11,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/tty.h>
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctl.h>
@@ -33,15 +34,13 @@
 {
 	struct file *filp;
 
-	file = fcheck(fd);
-	if(!file)
+	if(!(filp = fcheck(fd)))
 		return ((struct tty_struct *) 0);
 	if(filp->private_data) {
 		struct tty_struct *ttyp = (struct tty_struct *) filp->private_data;
 
-		if(ttyp->magic == TTY_MAGIC) {
+		if(ttyp->magic == TTY_MAGIC)
 			return ttyp;
-		}
 	}
 	return ((struct tty_struct *) 0);
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c
--- v2.3.8/linux/arch/mips/kernel/irixsig.c	Sat May 15 15:05:35 1999
+++ linux/arch/mips/kernel/irixsig.c	Fri Jun 25 17:40:12 1999
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: irixsig.c,v 1.11 1998/03/26 07:39:09 ralf Exp $
+ * $Id: irixsig.c,v 1.11 1999/06/17 13:25:46 ralf Exp $
  */
 
 #include <linux/kernel.h>
@@ -666,7 +666,7 @@
 			    int options, struct rusage *ru)
 {
 	int flag, retval;
-	DECLARE_WAITQUEUE(wait,current);
+	DECLARE_WAITQUEUE(wait, current);
 	struct task_struct *p;
 
 	lock_kernel();
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c
--- v2.3.8/linux/arch/mips/kernel/irq.c	Wed Dec 23 09:44:40 1998
+++ linux/arch/mips/kernel/irq.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.13 1998/05/28 03:17:55 ralf Exp $
+/* $Id: irq.c,v 1.15 1999/02/25 21:50:49 tsbogend Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/kernel_stat.h>
+#include <linux/module.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -27,9 +28,21 @@
 #include <asm/irq.h>
 #include <asm/mipsregs.h>
 #include <asm/system.h>
+#include <asm/sni.h>
 
-unsigned char cache_21 = 0xff;
-unsigned char cache_A1 = 0xff;
+/*
+ * This contains the irq mask for both 8259A irq controllers, it's an
+ * int so we can deal with the third PIC in some systems like the RM300.
+ * (XXX This is broken for big endian.)
+ */
+static unsigned int cached_irq_mask = 0xffff;
+
+#define __byte(x,y) (((unsigned char *)&(y))[x])
+#define __word(x,y) (((unsigned short *)&(y))[x])
+#define __long(x,y) (((unsigned int *)&(y))[x])
+
+#define cached_21       (__byte(0,cached_irq_mask))
+#define cached_A1       (__byte(1,cached_irq_mask))
 
 unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
@@ -39,31 +52,23 @@
  * (un)mask_irq, disable_irq() and enable_irq() only handle (E)ISA and
  * PCI devices.  Other onboard hardware needs specific routines.
  */
-static inline void mask_irq(unsigned int irq_nr)
+static inline void mask_irq(unsigned int irq)
 {
-	unsigned char mask;
-
-	mask = 1 << (irq_nr & 7);
-	if (irq_nr < 8) {
-		cache_21 |= mask;
-		outb(cache_21,0x21);
+	cached_irq_mask |= 1 << irq;
+	if (irq & 8) {
+		outb(cached_A1, 0xa1);
 	} else {
-		cache_A1 |= mask;
-		outb(cache_A1,0xA1);
+		outb(cached_21, 0x21);
 	}
 }
 
-static inline void unmask_irq(unsigned int irq_nr)
+static inline void unmask_irq(unsigned int irq)
 {
-	unsigned char mask;
-
-	mask = ~(1 << (irq_nr & 7));
-	if (irq_nr < 8) {
-		cache_21 &= mask;
-		outb(cache_21,0x21);
+	cached_irq_mask &= ~(1 << irq);
+	if (irq & 8) {
+		outb(cached_A1, 0xa1);
 	} else {
-		cache_A1 &= mask;
-		outb(cache_A1,0xA1);
+		outb(cached_21, 0x21);
 	}
 }
 
@@ -84,13 +89,11 @@
 	restore_flags(flags);
 }
 
-/*
- * Pointers to the low-level handlers: first the general ones, then the
- * fast ones, then the bad ones.
- */
-extern void interrupt(void);
-
-static struct irqaction *irq_action[32] = {
+static struct irqaction *irq_action[NR_IRQS] = {
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
 	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -122,6 +125,59 @@
 
 atomic_t __mips_bh_counter;
 
+static inline void i8259_mask_and_ack_irq(int irq)
+{
+	cached_irq_mask |= 1 << irq;
+
+	if (irq & 8) {
+		inb(0xa1);
+		outb(cached_A1, 0xa1);
+		outb(0x62, 0x20);		/* Specific EOI to cascade */
+                outb(0x20, 0xa0);
+        } else {
+		inb(0x21);
+		outb(cached_21, 0x21);
+		outb(0x20, 0x20);
+        }
+}
+
+asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs)
+{
+	struct irqaction *action;
+	int do_random, cpu;
+
+	cpu = smp_processor_id();
+	hardirq_enter(cpu);
+
+	if (irq >= 16)
+		goto out;
+
+	i8259_mask_and_ack_irq(irq);
+
+	kstat.irqs[cpu][irq]++;
+
+	action = *(irq + irq_action);
+	if (!action)
+		goto out;
+
+	if (!(action->flags & SA_INTERRUPT))
+		__sti();
+	action = *(irq + irq_action);
+	do_random = 0;
+       	do {
+		do_random |= action->flags;
+		action->handler(irq, action->dev_id, regs);
+		action = action->next;
+       	} while (action);
+	if (do_random & SA_SAMPLE_RANDOM)
+		add_interrupt_randomness(irq);
+	__cli();
+	unmask_irq (irq);
+
+out:
+	hardirq_exit(cpu);
+}
+
 /*
  * do_IRQ handles IRQ's that have been installed without the
  * SA_INTERRUPT flag: it uses the full signal-handling return
@@ -135,23 +191,9 @@
 	int do_random, cpu;
 
 	cpu = smp_processor_id();
-	irq_enter(cpu, irq);
+	hardirq_enter(cpu);
 	kstat.irqs[cpu][irq]++;
 
-	/*
-	 * mask and ack quickly, we don't want the irq controller
-	 * thinking we're snobs just because some other CPU has
-	 * disabled global interrupts (we have already done the
-	 * INT_ACK cycles, it's too late to try to pretend to the
-	 * controller that we aren't taking the interrupt).
-	 *
-	 * Commented out because we've already done this in the
-	 * machinespecific part of the handler.  It's reasonable to
-	 * do this here in a highlevel language though because that way
-	 * we could get rid of a good part of duplicated code ...
-	 */
-        /* mask_and_ack_irq(irq); */
-
 	action = *(irq + irq_action);
 	if (action) {
 		if (!(action->flags & SA_INTERRUPT))
@@ -165,21 +207,14 @@
         	} while (action);
 		if (do_random & SA_SAMPLE_RANDOM)
 			add_interrupt_randomness(irq);
-		unmask_irq (irq);
 		__cli();
 	}
-	irq_exit(cpu, irq);
+	hardirq_exit(cpu);
 
 	/* unmasking and bottom half handling is done magically for us. */
 }
 
-/*
- * Used only for setup of PC style interrupts and therefore still
- * called setup_x86_irq.  Later on I'll provide a machine specific
- * function with similar purpose.  Idea is to put all interrupts
- * in a single table and differenciate them just by number.
- */
-int setup_x86_irq(int irq, struct irqaction * new)
+int i8259_setup_irq(int irq, struct irqaction * new)
 {
 	int shared = 0;
 	struct irqaction *old, **p;
@@ -216,11 +251,15 @@
 	return 0;
 }
 
+/*
+ * Request_interrupt and free_interrupt ``sort of'' handle interrupts of
+ * non i8259 devices.  They will have to be replaced by architecture
+ * specific variants.  For now we still use this as broken as it is because
+ * it used to work ...
+ */
 int request_irq(unsigned int irq, 
 		void (*handler)(int, void *, struct pt_regs *),
-		unsigned long irqflags, 
-		const char * devname,
-		void *dev_id)
+		unsigned long irqflags, const char * devname, void *dev_id)
 {
 	int retval;
 	struct irqaction * action;
@@ -241,7 +280,7 @@
 	action->next = NULL;
 	action->dev_id = dev_id;
 
-	retval = setup_x86_irq(irq, action);
+	retval = i8259_setup_irq(irq, action);
 
 	if (retval)
 		kfree(action);
@@ -275,7 +314,7 @@
 
 unsigned long probe_irq_on (void)
 {
-	unsigned int i, irqs = 0, irqmask;
+	unsigned int i, irqs = 0;
 	unsigned long delay;
 
 	/* first, enable any unassigned (E)ISA irqs */
@@ -291,19 +330,17 @@
 		/* about 100ms delay */;
 
 	/* now filter out any obviously spurious interrupts */
-	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
-	return irqs & ~irqmask;
+	return irqs & ~cached_irq_mask;
 }
 
 int probe_irq_off (unsigned long irqs)
 {
-	unsigned int i, irqmask;
+	unsigned int i;
 
-	irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
 #ifdef DEBUG
 	printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
 #endif
-	irqs &= irqmask;
+	irqs &= cached_irq_mask;
 	if (!irqs)
 		return 0;
 	i = ffz(~irqs);
@@ -314,13 +351,36 @@
 
 int (*irq_cannonicalize)(int irq);
 
-static int i8259a_irq_cannonicalize(int irq)
+static int i8259_irq_cannonicalize(int irq)
 {
 	return ((irq == 2) ? 9 : irq);
 }
 
+__initfunc(static void i8259_init(void))
+{
+	/* Init master interrupt controller */
+	outb(0x11, 0x20); /* Start init sequence */
+	outb(0x00, 0x21); /* Vector base */
+	outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
+	outb(0x01, 0x21); /* Select 8086 mode */
+	outb(0xff, 0x21); /* Mask all */
+        
+	/* Init slave interrupt controller */
+	outb(0x11, 0xa0); /* Start init sequence */
+	outb(0x08, 0xa1); /* Vector base */
+	outb(0x02, 0xa1); /* edge triggered, Cascade (slave) on IRQ2 */
+	outb(0x01, 0xa1); /* Select 8086 mode */
+	outb(0xff, 0xa1); /* Mask all */
+
+	outb(cached_A1, 0xa1);
+	outb(cached_21, 0x21);
+}
+
 __initfunc(void init_IRQ(void))
 {
-	irq_cannonicalize = i8259a_irq_cannonicalize;
+	irq_cannonicalize = i8259_irq_cannonicalize;
+	/* i8259_init(); */
 	irq_setup();
 }
+
+EXPORT_SYMBOL(irq_cannonicalize);
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/mips_ksyms.c linux/arch/mips/kernel/mips_ksyms.c
--- v2.3.8/linux/arch/mips/kernel/mips_ksyms.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/mips_ksyms.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: mips_ksyms.c,v 1.12 1998/09/16 22:50:41 ralf Exp $
+/* $Id: mips_ksyms.c,v 1.19 1999/04/11 18:37:55 harald Exp $
  *
  * Export MIPS-specific functions needed for loadable modules.
  *
@@ -13,6 +13,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <asm/irq.h>
 #include <linux/in6.h>
 #include <linux/pci.h>
 
@@ -50,23 +51,25 @@
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strtok);
+EXPORT_SYMBOL_NOVERS(strpbrk);
 
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(__mips_bh_counter);
 EXPORT_SYMBOL(local_bh_count);
 EXPORT_SYMBOL(local_irq_count);
-//EXPORT_SYMBOL(enable_irq);
-//EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(kernel_thread);
 
 /*
  * Userspace access stuff.
  */
-EXPORT_SYMBOL(__copy_user);
-EXPORT_SYMBOL(__bzero);
-EXPORT_SYMBOL(__strncpy_from_user_nocheck_asm);
-EXPORT_SYMBOL(__strncpy_from_user_asm);
-EXPORT_SYMBOL(__strlen_user_nocheck_asm);
-EXPORT_SYMBOL(__strlen_user_asm);
+EXPORT_SYMBOL_NOVERS(__copy_user);
+EXPORT_SYMBOL_NOVERS(__bzero);
+EXPORT_SYMBOL_NOVERS(__strncpy_from_user_nocheck_asm);
+EXPORT_SYMBOL_NOVERS(__strncpy_from_user_asm);
+EXPORT_SYMBOL_NOVERS(__strlen_user_nocheck_asm);
+EXPORT_SYMBOL_NOVERS(__strlen_user_asm);
 
 
 /* Networking helper routines. */
@@ -77,6 +80,10 @@
  */
 EXPORT_SYMBOL(flush_page_to_ram);
 EXPORT_SYMBOL(flush_cache_all);
+EXPORT_SYMBOL(dma_cache_wback_inv);
+EXPORT_SYMBOL(dma_cache_inv);
+
+EXPORT_SYMBOL(invalid_pte_table);
 
 /*
  * Base address of ports for Intel style I/O.
@@ -106,12 +113,12 @@
 int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31));
 
 #ifdef CONFIG_MIPS_FPE_MODULE
-EXPORT_SYMBOL(force_sig);
 EXPORT_SYMBOL(__compute_return_epc);
 EXPORT_SYMBOL(register_fpe);
 EXPORT_SYMBOL(unregister_fpe);
 #endif
 
-#if CONFIG_PCI
-EXPORT_SYMBOL(pci_devices);
+#ifdef CONFIG_VT
+EXPORT_SYMBOL(screen_info);
 #endif
+
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/pci.c linux/arch/mips/kernel/pci.c
--- v2.3.8/linux/arch/mips/kernel/pci.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/pci.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.6 1998/08/19 21:53:50 ralf Exp $
+/* $Id: pci.c,v 1.8 1999/05/01 22:40:36 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -36,13 +36,13 @@
 }
 
 /*
- * The functions below are machine specific and must be reimplented for
+ * The functions below are machine specific and must be reimplimented for
  * each PCI chipset configuration.  We just run the hook to the machine
  * specific implementation.
  */
 void pcibios_fixup (void)
 {
-	return pci_ops->pcibios_fixup();
+	pci_ops->pcibios_fixup();
 }
 
 int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn,
@@ -88,11 +88,6 @@
 
 __initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
 {
-}
-
-__initfunc(char *pcibios_setup(char *str))
-{
-	return str;
 }
 
 #endif /* defined(CONFIG_PCI) */
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/process.c linux/arch/mips/kernel/process.c
--- v2.3.8/linux/arch/mips/kernel/process.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/process.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.11 1998/08/17 12:14:53 ralf Exp $
+/* $Id: process.c,v 1.12 1999/06/17 13:25:46 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -144,4 +144,41 @@
 		(current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	memcpy(&dump->regs[0], regs, sizeof(struct pt_regs));
 	memcpy(&dump->regs[EF_SIZE/4], &current->tss.fpu, sizeof(current->tss.fpu));
+}
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	long retval;
+
+	__asm__ __volatile__(
+		".set\tnoreorder\n\t"
+		"move\t$6,$sp\n\t"
+		"move\t$4,%5\n\t"
+		"li\t$2,%1\n\t"
+		"syscall\n\t"
+		"beq\t$6,$sp,1f\n\t"
+		"subu\t$sp,32\n\t"	/* delay slot */
+		"jalr\t%4\n\t"
+		"move\t$4,%3\n\t"	/* delay slot */
+		"move\t$4,$2\n\t"
+		"li\t$2,%2\n\t"
+		"syscall\n"
+		"1:\taddiu\t$sp,32\n\t"
+		"move\t%0,$2\n\t"
+		".set\treorder"
+		:"=r" (retval)
+		:"i" (__NR_clone), "i" (__NR_exit),
+		 "r" (arg), "r" (fn),
+		 "r" (flags | CLONE_VM)
+		 /*
+		  * The called subroutine might have destroyed any of the
+		  * at, result, argument or temporary registers ...
+		  */
+		:"$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+		 "$9","$10","$11","$12","$13","$14","$15","$24","$25");
+
+	return retval;
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
--- v2.3.8/linux/arch/mips/kernel/ptrace.c	Mon Jun  7 11:15:33 1999
+++ linux/arch/mips/kernel/ptrace.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: ptrace.c,v 1.11 1998/10/19 16:26:31 ralf Exp $
+/* $Id: ptrace.c,v 1.13 1999/06/17 13:25:46 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -240,6 +240,7 @@
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
+	unsigned int flags;
 	int res;
 
 	lock_kernel();
@@ -278,23 +279,26 @@
 		    (current->uid != child->uid) ||
 	 	    (current->gid != child->egid) ||
 		    (current->gid != child->sgid) ||
-		    (!cap_issubset(child->cap_permitted, current->cap_permitted)) ||
-	 	    (current->gid != child->gid)) && 
-		    !capable(CAP_SYS_PTRACE)) {
+	 	    (current->gid != child->gid) ||
+		    (!cap_issubset(child->cap_permitted,
+		                  current->cap_permitted)) ||
+                    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE)){
 			res = -EPERM;
 			goto out;
 		}
 		/* the same process cannot be attached many times */
-		if (child->flags & PF_PTRACED) {
-			res = -EPERM;
+		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);
 		res = 0;
 		goto out;
@@ -319,15 +323,16 @@
 	case PTRACE_PEEKDATA: {
 		unsigned long tmp;
 
+		down(&child->mm->mmap_sem);
 		res = read_long(child, addr, &tmp);
+		up(&child->mm->mmap_sem);
 		if (res < 0)
 			goto out;
 		res = put_user(tmp,(unsigned long *) data);
 		goto out;
 		}
 
-	/* read the word at location addr in the USER area. */
-/* #define DEBUG_PEEKUSR */
+	/* Read the word at location addr in the USER area.  */
 	case PTRACE_PEEKUSR: {
 		struct pt_regs *regs;
 		unsigned long tmp;
@@ -335,12 +340,15 @@
 		regs = (struct pt_regs *) ((unsigned long) child +
 		       KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
 		tmp = 0;  /* Default return value. */
-		if (addr < 32 && addr >= 0)
-			tmp = regs->regs[addr];
-		else if (addr >= 32 && addr < 64) {
-			unsigned long long *fregs;
 
+		switch(addr) {
+		case 0 ... 31:
+			tmp = regs->regs[addr];
+			break;
+		case FPR_BASE ... FPR_BASE + 31:
 			if (child->used_math) {
+				unsigned long long *fregs;
+
 				if (last_task_used_math == child) {
 					enable_cp1();
 					r4xx0_save_fp(child);
@@ -353,35 +361,32 @@
 			} else {
 				tmp = -1;	/* FP not yet used  */
 			}
-		} else {
-			addr -= 64;
-			switch(addr) {
-			case 0:
-				tmp = regs->cp0_epc;
-				break;
-			case 1:
-				tmp = regs->cp0_cause;
-				break;
-			case 2:
-				tmp = regs->cp0_badvaddr;
-				break;
-			case 3:
-				tmp = regs->lo;
-				break;
-			case 4:
-				tmp = regs->hi;
-				break;
-			case 5:
-				tmp = child->tss.fpu.hard.control;
-				break;
-			case 6:	/* implementation / version register */
-				tmp = 0;	/* XXX */
-				break;
-			default:
-				tmp = 0;
-				res = -EIO;
-				goto out;
-			}
+			break;
+		case PC:
+			tmp = regs->cp0_epc;
+			break;
+		case CAUSE:
+			tmp = regs->cp0_cause;
+			break;
+		case BADVADDR:
+			tmp = regs->cp0_badvaddr;
+			break;
+		case MMHI:
+			tmp = regs->hi;
+			break;
+		case MMLO:
+			tmp = regs->lo;
+			break;
+		case FPC_CSR:
+			tmp = child->tss.fpu.hard.control;
+			break;
+		case FPC_EIR:	/* implementation / version register */
+			tmp = 0;	/* XXX */
+			break;
+		default:
+			tmp = 0;
+			res = -EIO;
+			goto out;
 		}
 		res = put_user(tmp, (unsigned long *) data);
 		goto out;
@@ -389,20 +394,22 @@
 
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
+		down(&child->mm->mmap_sem);
 		res = write_long(child,addr,data);
+		up(&child->mm->mmap_sem);
 		goto out;
 
 	case PTRACE_POKEUSR: {
+		unsigned long long *fregs;
 		struct pt_regs *regs;
 		int res = 0;
 
-		regs = (struct pt_regs *) ((unsigned long) child +
-		       KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
-		if (addr < 32 && addr >= 0)
-			regs->regs[addr] = data;
-		else if (addr >= 32 && addr < 64) {
-			unsigned long long *fregs;
-
+		switch (addr) {
+		case 0 ... 31:
+			regs = (struct pt_regs *) ((unsigned long) child +
+			       KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
+			break;
+		case FPR_BASE ... FPR_BASE + 31:
 			if (child->used_math) {
 				if (last_task_used_math == child) {
 					enable_cp1();
@@ -419,26 +426,23 @@
 			fregs = (unsigned long long *)
 				&child->tss.fpu.hard.fp_regs[0];
 			fregs[(addr - 32)] = (unsigned long long) data;
-		} else {
-			addr -= 64;
-			switch (addr) {
-			case 0:
-				regs->cp0_epc = data;
-				break;
-			case 3:
-				regs->lo = data;
-				break;
-			case 4:
-				regs->hi = data;
-				break;
-			case 5:
-				child->tss.fpu.hard.control = data;
-				break;
-			default:
-				/* The rest are not allowed. */
-				res = -EIO;
-				break;
-			};
+			break;
+		case PC:
+			regs->cp0_epc = data;
+			break;
+		case MMHI:
+			regs->hi = data;
+			break;
+		case MMLO:
+			regs->lo = data;
+			break;
+		case FPC_CSR:
+			child->tss.fpu.hard.control = data;
+			break;
+		default:
+			/* The rest are not allowed. */
+			res = -EIO;
+			break;
 		}
 		goto out;
 		}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/r2300_fpu.S linux/arch/mips/kernel/r2300_fpu.S
--- v2.3.8/linux/arch/mips/kernel/r2300_fpu.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/r2300_fpu.S	Fri Jun 25 17:40:12 1999
@@ -1,16 +1,17 @@
-/*
+/* $Id: r2300_fpu.S,v 1.5 1999/05/01 22:40:36 ralf Exp $
  * r2300_fpu.S: Save/restore floating point context for signal handlers.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1998 by Ralf Baechle
  *
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r2300_fpu.S,v 1.3 1997/12/01 16:54:20 ralf Exp $
+ * Further modifications to make this work:
+ * Copyright (c) 1998 Harald Koerfgen
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
@@ -18,123 +19,101 @@
 #include <asm/offset.h>
 #include <asm/regdef.h>
 
-	.set	mips3
+#define EX(a,b)							\
+9:	a,##b;							\
+	.section __ex_table,"a";				\
+	PTR	9b,bad_stack;					\
+	.previous
+
 	.set	noreorder
+	.set	mips1
 	/* Save floating point context */
-	.align	5
-	LEAF(r2300_save_fp_context)
-	mfc0	t0,CP0_STATUS
-	sll	t0,t0,2
+LEAF(r2300_save_fp_context)
 
-	bgez	t0,1f
-	 nop
-
-	cfc1	t0,fcr31
-	/* Store the 32 single precision registers */
-	swc1	$f0,(SC_FPREGS+0)(a0)
-	swc1	$f1,(SC_FPREGS+8)(a0)
-	swc1	$f2,(SC_FPREGS+16)(a0)
-	swc1	$f3,(SC_FPREGS+24)(a0)
-	swc1	$f4,(SC_FPREGS+32)(a0)
-	swc1	$f5,(SC_FPREGS+40)(a0)
-	swc1	$f6,(SC_FPREGS+48)(a0)
-	swc1	$f7,(SC_FPREGS+56)(a0)
-	swc1	$f8,(SC_FPREGS+64)(a0)
-	swc1	$f9,(SC_FPREGS+72)(a0)
-	swc1	$f10,(SC_FPREGS+80)(a0)
-	swc1	$f11,(SC_FPREGS+88)(a0)
-	swc1	$f12,(SC_FPREGS+96)(a0)
-	swc1	$f13,(SC_FPREGS+104)(a0)
-	swc1	$f14,(SC_FPREGS+112)(a0)
-	swc1	$f15,(SC_FPREGS+120)(a0)
-	swc1	$f16,(SC_FPREGS+128)(a0)
-	swc1	$f17,(SC_FPREGS+136)(a0)
-	swc1	$f18,(SC_FPREGS+144)(a0)
-	swc1	$f19,(SC_FPREGS+152)(a0)
-	swc1	$f20,(SC_FPREGS+160)(a0)
-	swc1	$f21,(SC_FPREGS+168)(a0)
-	swc1	$f22,(SC_FPREGS+176)(a0)
-	swc1	$f23,(SC_FPREGS+184)(a0)
-	swc1	$f24,(SC_FPREGS+192)(a0)
-	swc1	$f25,(SC_FPREGS+200)(a0)
-	swc1	$f26,(SC_FPREGS+208)(a0)
-	swc1	$f27,(SC_FPREGS+216)(a0)
-	swc1	$f28,(SC_FPREGS+224)(a0)
-	swc1	$f29,(SC_FPREGS+232)(a0)
-	swc1	$f30,(SC_FPREGS+240)(a0)
-	swc1	$f31,(SC_FPREGS+248)(a0)
-	sw	t0,SC_FPC_CSR(a0)
+	cfc1	t1,fcr31
+	EX(swc1	$f0,(SC_FPREGS+0)(a0))
+	EX(swc1	$f1,(SC_FPREGS+8)(a0))
+	EX(swc1	$f2,(SC_FPREGS+16)(a0))
+	EX(swc1	$f3,(SC_FPREGS+24)(a0))
+	EX(swc1	$f4,(SC_FPREGS+32)(a0))
+	EX(swc1	$f5,(SC_FPREGS+40)(a0))
+	EX(swc1	$f6,(SC_FPREGS+48)(a0))
+	EX(swc1	$f7,(SC_FPREGS+56)(a0))
+	EX(swc1	$f8,(SC_FPREGS+64)(a0))
+	EX(swc1	$f9,(SC_FPREGS+72)(a0))
+	EX(swc1	$f10,(SC_FPREGS+80)(a0))
+	EX(swc1	$f11,(SC_FPREGS+88)(a0))
+	EX(swc1	$f12,(SC_FPREGS+96)(a0))
+	EX(swc1	$f13,(SC_FPREGS+104)(a0))
+	EX(swc1	$f14,(SC_FPREGS+112)(a0))
+	EX(swc1	$f15,(SC_FPREGS+120)(a0))
+	EX(swc1	$f16,(SC_FPREGS+128)(a0))
+	EX(swc1	$f17,(SC_FPREGS+136)(a0))
+	EX(swc1	$f18,(SC_FPREGS+144)(a0))
+	EX(swc1	$f19,(SC_FPREGS+152)(a0))
+	EX(swc1	$f20,(SC_FPREGS+160)(a0))
+	EX(swc1	$f21,(SC_FPREGS+168)(a0))
+	EX(swc1	$f22,(SC_FPREGS+176)(a0))
+	EX(swc1	$f23,(SC_FPREGS+184)(a0))
+	EX(swc1	$f24,(SC_FPREGS+192)(a0))
+	EX(swc1	$f25,(SC_FPREGS+200)(a0))
+	EX(swc1	$f26,(SC_FPREGS+208)(a0))
+	EX(swc1	$f27,(SC_FPREGS+216)(a0))
+	EX(swc1	$f28,(SC_FPREGS+224)(a0))
+	EX(swc1	$f29,(SC_FPREGS+232)(a0))
+	EX(swc1	$f30,(SC_FPREGS+240)(a0))
+	EX(swc1	$f31,(SC_FPREGS+248)(a0))
+	EX(sw	t1,SC_FPC_CSR(a0))
 	cfc1	t0,$0				# implementation/version
 	jr	ra
 	.set	nomacro
-	 sw	t0,SC_FPC_EIR(a0)
-	.set	macro
-1:
-	jr	ra
-	.set	nomacro
-	 nop
+	 EX(sw	t0,SC_FPC_EIR(a0))
 	.set	macro
 	END(r2300_save_fp_context)
 
 /*
- * Restore fpu state:
+ * Restore FPU state:
  *  - fp gp registers
  *  - cp1 status/control register
  *
- * We base the decission which registers to restore from the signal stack
+ * We base the decision which registers to restore from the signal stack
  * frame on the current content of c0_status, not on the content of the
  * stack frame which might have been changed by the user.
  */
-	LEAF(r2300_restore_fp_context)
-	mfc0	t0,CP0_STATUS
-	sll	t0,t0,2
-
-	bgez	t0,1f
-	 nop
-
-	 lw	t0,SC_FPC_CSR(a0)
-	/* Restore the 16 odd double precision registers only
-	 * when enabled in the cp0 status register.
-	 */
-	ldc1	$f0,(SC_FPREGS+0)(a0)
-	ldc1	$f1,(SC_FPREGS+8)(a0)
-	ldc1	$f2,(SC_FPREGS+16)(a0)
-	ldc1	$f3,(SC_FPREGS+24)(a0)
-	ldc1	$f4,(SC_FPREGS+32)(a0)
-	ldc1	$f5,(SC_FPREGS+40)(a0)
-	ldc1	$f6,(SC_FPREGS+48)(a0)
-	ldc1	$f7,(SC_FPREGS+56)(a0)
-	ldc1	$f8,(SC_FPREGS+64)(a0)
-	ldc1	$f9,(SC_FPREGS+72)(a0)
-	ldc1	$f10,(SC_FPREGS+80)(a0)
-	ldc1	$f11,(SC_FPREGS+88)(a0)
-	ldc1	$f12,(SC_FPREGS+96)(a0)
-	ldc1	$f13,(SC_FPREGS+104)(a0)
-	ldc1	$f14,(SC_FPREGS+112)(a0)
-	ldc1	$f15,(SC_FPREGS+120)(a0)
-	ldc1	$f16,(SC_FPREGS+128)(a0)
-	ldc1	$f17,(SC_FPREGS+136)(a0)
-	ldc1	$f18,(SC_FPREGS+144)(a0)
-	ldc1	$f19,(SC_FPREGS+152)(a0)
-	ldc1	$f20,(SC_FPREGS+160)(a0)
-	ldc1	$f21,(SC_FPREGS+168)(a0)
-	ldc1	$f22,(SC_FPREGS+176)(a0)
-	ldc1	$f23,(SC_FPREGS+184)(a0)
-	ldc1	$f24,(SC_FPREGS+192)(a0)
-	ldc1	$f25,(SC_FPREGS+200)(a0)
-	ldc1	$f26,(SC_FPREGS+208)(a0)
-	ldc1	$f27,(SC_FPREGS+216)(a0)
-	ldc1	$f28,(SC_FPREGS+224)(a0)
-	ldc1	$f29,(SC_FPREGS+232)(a0)
-	ldc1	$f30,(SC_FPREGS+240)(a0)
-	ldc1	$f31,(SC_FPREGS+248)(a0)
+LEAF(r2300_restore_fp_context)
+	EX(lw t0,SC_FPC_CSR(a0))
+	EX(lwc1	$f0,(SC_FPREGS+0)(a0))
+	EX(lwc1	$f1,(SC_FPREGS+8)(a0))
+	EX(lwc1	$f2,(SC_FPREGS+16)(a0))
+	EX(lwc1	$f3,(SC_FPREGS+24)(a0))
+	EX(lwc1	$f4,(SC_FPREGS+32)(a0))
+	EX(lwc1	$f5,(SC_FPREGS+40)(a0))
+	EX(lwc1	$f6,(SC_FPREGS+48)(a0))
+	EX(lwc1	$f7,(SC_FPREGS+56)(a0))
+	EX(lwc1	$f8,(SC_FPREGS+64)(a0))
+	EX(lwc1	$f9,(SC_FPREGS+72)(a0))
+	EX(lwc1	$f10,(SC_FPREGS+80)(a0))
+	EX(lwc1	$f11,(SC_FPREGS+88)(a0))
+	EX(lwc1	$f12,(SC_FPREGS+96)(a0))
+	EX(lwc1	$f13,(SC_FPREGS+104)(a0))
+	EX(lwc1	$f14,(SC_FPREGS+112)(a0))
+	EX(lwc1	$f15,(SC_FPREGS+120)(a0))
+	EX(lwc1	$f16,(SC_FPREGS+128)(a0))
+	EX(lwc1	$f17,(SC_FPREGS+136)(a0))
+	EX(lwc1	$f18,(SC_FPREGS+144)(a0))
+	EX(lwc1	$f19,(SC_FPREGS+152)(a0))
+	EX(lwc1	$f20,(SC_FPREGS+160)(a0))
+	EX(lwc1	$f21,(SC_FPREGS+168)(a0))
+	EX(lwc1	$f22,(SC_FPREGS+176)(a0))
+	EX(lwc1	$f23,(SC_FPREGS+184)(a0))
+	EX(lwc1	$f24,(SC_FPREGS+192)(a0))
+	EX(lwc1	$f25,(SC_FPREGS+200)(a0))
+	EX(lwc1	$f26,(SC_FPREGS+208)(a0))
+	EX(lwc1	$f27,(SC_FPREGS+216)(a0))
+	EX(lwc1	$f28,(SC_FPREGS+224)(a0))
+	EX(lwc1	$f29,(SC_FPREGS+232)(a0))
+	EX(lwc1	$f30,(SC_FPREGS+240)(a0))
+	EX(lwc1	$f31,(SC_FPREGS+248)(a0))
 	jr	ra
-	.set	nomacro
 	 ctc1	t0,fcr31
-	.set	macro
-1:
-	jr	ra
-	.set	nomacro
-	 nop
-	.set	macro
 	END(r2300_restore_fp_context)
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/r2300_misc.S linux/arch/mips/kernel/r2300_misc.S
--- v2.3.8/linux/arch/mips/kernel/r2300_misc.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/r2300_misc.S	Wed Jun 30 11:24:54 1999
@@ -1,14 +1,17 @@
-/* $Id: r2300_misc.S,v 1.1.1.1 1997/06/01 03:16:42 ralf Exp $
+/* $Id: r2300_misc.S,v 1.3 1999/05/01 22:40:36 ralf Exp $
  * r2300_misc.S: Misc. exception handling code for R3000/R2000.
  *
  * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
  *
- * Multi-cpu abstraction reworking:
+ * Multi-CPU abstraction reworking:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * Further modifications to make this work:
+ * Copyright (c) 1998 Harald Koerfgen
+ * Copyright (c) 1998 Gleb Raiko & Vladimir Roganov
  */
-#include <linux/config.h>
-
 #include <asm/asm.h>
+#include <asm/current.h>
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
 #include <asm/fpregdef.h>
@@ -18,380 +21,175 @@
 #include <asm/pgtable.h>
 #include <asm/processor.h>
 #include <asm/regdef.h>
+#include <asm/segment.h>
 #include <asm/stackframe.h>
 
 	.text
 	.set	mips1
 	.set	noreorder
 
-	.align	5
-	NESTED(r2300_handle_tlbl, PT_SIZE, sp)
-	.set	noat
-	/* Check whether this is a refill or an invalid exception */
-	mfc0	k0,CP0_BADVADDR
-	mfc0	k1,CP0_ENTRYHI
-	ori	k0,0xfff			# clear ASID...
-	xori	k0,0xfff			# in BadVAddr
-	andi	k1,0xfc0			# get current ASID
-	or	k0,k1				# make new entryhi
-	mfc0	k1,CP0_ENTRYHI
-	mtc0	k0,CP0_ENTRYHI
-	nop					# for pipeline
-	nop
-	nop
-	tlbp
-	nop					# for pipeline
-	nop
-	mfc0	k0,CP0_INDEX
-
-	bgez	k0,invalid_tlbl			# bad addr in c0_badvaddr
-	 mtc0	k1,CP0_ENTRYHI
-
-	/* Damn... The next nop is required on the R4400PC V5.0, but
-	 * I don't know why - at least there is no documented
-	 * reason as for the others :-(
-	 * And I haven't tested it as being necessary on R3000 - PMA.
-	 * (The R3000 pipeline has only 5 stages, so it's probably not
-	 * required -- Ralf)
-	 */
-	nop
-
-#ifdef CONF_DEBUG_TLB
-	/* OK, this is a double fault. Let's see whether this is
-	 * due to an invalid entry in the page_table.
-	 */
-	/* used to be dmfc0 */
-	mfc0	k0,CP0_BADVADDR
-	/* FIXME: This srl/sll sequence is as it is for the R4xx0,
-	 *        and I suspect that it should be different for
-	 *	  the R[23]000.  PMA
-	 *        (No, it's the assembler way to do
-	 *            k0 = k0 / PAGE_SIZE;
-	 *            k0 = k0 * sizeof(pte_t)
-	 *        Acutally the R4xx0 code will have to change when
-	 *        switching to 64 bit ... -- Ralf)
-	 */
-	srl	k0,12				# get PFN?
-	sll	k0,2
-	lui	k1,%HI(TLBMAP)
-	addu	k0,k1
-	lw	k1,(k0)
-	andi	k1,(_PAGE_PRESENT|_PAGE_ACCESSED)
-	bnez	k1,reload_pgd_entries
-	 nop
-
-	.set	noat
-	SAVE_ALL
-	.set	at
-	PRINT("Double fault caused by invalid entries in pgd:\n")
-	mfc0	a1,CP0_BADVADDR
-	PRINT("Double fault address     : %08lx\n")
-	mfc0	a1,CP0_EPC
-	PRINT("c0_epc                   : %08lx\n")
-
-	jal	show_regs
-	 move	a0,sp
+#undef NOTLB_OPTIMIZE /* If you are paranoid, define this. */
 
-	jal	dump_tlb_nonwired
-	 nop
+	/* ABUSE of CPP macros 101. */
 
-	mfc0	a0,CP0_BADVADDR
+	/* After this macro runs, the pte faulted on is
+	 * in register PTE, a ptr into the table in which
+	 * the pte belongs is in PTR.
+	 */
+#define LOAD_PTE(pte, ptr) \
+	mfc0	pte, CP0_BADVADDR; \
+	_GET_CURRENT(ptr); \
+	srl	pte, pte, 22; \
+	lw	ptr, THREAD_PGDIR(ptr); \
+	sll	pte, pte, 2; \
+	addu	ptr, pte, ptr; \
+	mfc0	pte, CP0_CONTEXT; \
+	lw	ptr, (ptr); \
+	andi	pte, pte, 0xffc; \
+	addu	ptr, ptr, pte; \
+	lw	pte, (ptr); \
+	nop;
+
+	/* This places the even/odd pte pair in the page
+	 * table at PTR into ENTRYLO0 and ENTRYLO1 using
+	 * TMP as a scratch register.
+	 */
+#define PTE_RELOAD(ptr) \
+	lw	ptr, (ptr)	; \
+	nop			; \
+	mtc0	ptr, CP0_ENTRYLO0; \
+	nop;
+
+#define DO_FAULT(write) \
+	.set	noat; \
+	.set	macro; \
+	SAVE_ALL; \
+	mfc0	a2, CP0_BADVADDR; \
+	STI; \
+	.set	at; \
+	move	a0, sp; \
+	jal	do_page_fault; \
+	 li	a1, write; \
+	j	ret_from_sys_call; \
+	 nop; \
+	.set	noat; \
+	.set	nomacro;
+
+	/* Check is PTE is present, if not then jump to LABEL.
+	 * PTR points to the page table where this PTE is located,
+	 * when the macro is done executing PTE will be restored
+	 * with it's original value.
+	 */
+#define PTE_PRESENT(pte, ptr, label) \
+	andi	pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
+	xori	pte, pte, (_PAGE_PRESENT | _PAGE_READ); \
+	bnez	pte, label; \
+	.set	push;       \
+	.set	reorder;    \
+	 lw	pte, (ptr); \
+	.set	pop; 
+
+	/* Make PTE valid, store result in PTR. */
+#define PTE_MAKEVALID(pte, ptr) \
+	ori	pte, pte, (_PAGE_VALID | _PAGE_ACCESSED); \
+	sw	pte, (ptr);
+
+	/* Check if PTE can be written to, if not branch to LABEL.
+	 * Regardless restore PTE with value from PTR when done.
+	 */
+#define PTE_WRITABLE(pte, ptr, label) \
+	andi	pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
+	xori	pte, pte, (_PAGE_PRESENT | _PAGE_WRITE); \
+	bnez	pte, label; \
+	.set    push;       \
+	.set    reorder;    \
+	lw      pte, (ptr); \
+	.set    pop;
+ 
+
+	/* Make PTE writable, update software status bits as well,
+	 * then store at PTR.
+	 */
+#define PTE_MAKEWRITE(pte, ptr) \
+	ori	pte, pte, (_PAGE_ACCESSED | _PAGE_MODIFIED | \
+			   _PAGE_VALID | _PAGE_DIRTY); \
+	sw	pte, (ptr);
 
-	jal	dump_list_current
-	 nop
+	.set	noreorder
 
+	.align	5
+NESTED(r2300_handle_tlbl, PT_SIZE, sp)
 	.set	noat
-	STI
-	.set	at
-	PANIC("Corrupted pagedir")
-	.set	noat
-
-reload_pgd_entries:
-#endif /* CONF_DEBUG_TLB */
 
-	/* Load missing pair of entries from the pgd and return. */
-	mfc0	k1,CP0_CONTEXT
-	lw	k0,(k1)			# Never causes nested exception
-	mfc0	k1,CP0_EPC		# get the return PC
-	srl	k0,12			# Convert to EntryLo format
-	mtc0	k0,CP0_ENTRYLO0
-	nop				# for pipeline
-	tlbwr
-	nop				# for pipeline
+#ifndef NOTLB_OPTIMIZE
+	/* Test present bit in entry. */
+	LOAD_PTE(k0, k1)
+        tlbp
 	nop
+        PTE_PRESENT(k0, k1, nopage_tlbl)
+        PTE_MAKEVALID(k0, k1)
+        PTE_RELOAD(k1)
+	tlbwi
 	nop
-	/* We don't know whether the original access was read or
-	 * write, so return and see what happens...
-	 */
-	jr	k1
-	 rfe
-
-	/* Handle invalid exception
-	 *
-	 * There are two possible causes for an invalid (tlbl)
-	 * exception:
-	 * 1) pages with present bit set but the valid bit clear
-	 * 2) nonexistant pages
-	 * Case one needs fast handling, therefore don't save
-	 * registers yet.
-	 *
-	 * k0 contains c0_index.
-	 */
-invalid_tlbl:	
-#ifdef CONFIG_TLB_SHUTDOWN
-	/* Remove entry so we don't need to care later
-	 * For sake of the pipeline the tlbwi insn has been moved down.
-	 * Moving it around is juggling with explosives...
-	 */
-	/* FIXME: Why is Ralf setting bit 3 of k1?  This may need to
-	 *	  be changed for R[236]000! PMA
-	 *        (The new ENTRYHI value will then point represent a
-	 *        inique virtual address outside the 32 bit address
-	 *        limit.  This is just paranoia to avoid a tlb
-	 *        shutdown.  This whole part of the routine is probably
-	 *        no longer required and can be removed -- Ralf)
-	 */
-	lui	k1,0x0008
-	or	k0,k1
-	sll	k0,12				# make it EntryHi format
-	mtc0	k0,CP0_ENTRYHI
-	mtc0	zero,CP0_ENTRYLO0
-#endif
-	/* Test present bit in entry */
-	mfc0	k0,CP0_BADVADDR
-	/* FIXME: This srl/sll sequence is as it is for the R4xx0,
-	 *        and I suspect that it should be different for
-	 *	  the R[23]000.  PMA
-	 *        (No, it's the assembler way to do
-	 *            k0 = k0 / PAGE_SIZE;
-	 *            k0 = k0 * sizeof(pte_t)
-	 *        Acutally the R4xx0 code will have to change when
-	 *        switching to 64 bit ... -- Ralf)
-	 */
-	srl	k0,12
-	sll	k0,2
-#ifdef CONFIG_TLB_SHUTDOWN
-	tlbwi						# do not move!
-#endif
-	lui	k1,%HI(TLBMAP)
-	addu	k0,k1
-	lw	k1,(k0)
-	andi	k1,(_PAGE_PRESENT|_PAGE_READ)
-	xori	k1,(_PAGE_PRESENT|_PAGE_READ)
-
-	bnez	k1,nopage_tlbl
-	 lw	k1,(k0)
-
-	/* Present and read bits are set -> set valid and accessed bits */
-	ori	k1,(_PAGE_VALID|_PAGE_ACCESSED)
-	sw	k1,(k0)
-	mfc0	k1,CP0_EPC
+	mfc0	k0, CP0_EPC
 	nop
-
-	jr	k1
+	jr	k0
 	 rfe
-
-	/* Page doesn't exist. Lots of work which is less important
-	 * for speed needs to be done, so hand it all over to the
-	 * kernel memory management routines.
-	 */
 nopage_tlbl:
-	SAVE_ALL
-	mfc0	a2,CP0_BADVADDR
-	STI
-	.set	at
-	/* a0 (struct pt_regs *) regs
-	 * a1 (unsigned long)    0 for read access
-	 * a2 (unsigned long)    faulting virtual address
-	 */
-	move	a0,sp
-	jal	do_page_fault
-	 li	a1,0
-
-	j	ret_from_sys_call
-	 nop
-	END(r2300_handle_tlbl)
+#endif
 
+	DO_FAULT(0)
+END(r2300_handle_tlbl)
 
-	.text
-	.align	5
-	NESTED(r2300_handle_tlbs, PT_SIZE, sp)
+NESTED(r2300_handle_tlbs, PT_SIZE, sp)
 	.set	noat
-	/* It is impossible that is a nested reload exception.
-	 * Therefore this must be a invalid exception.
-	 * Two possible cases:
-	 * 1) Page exists but not dirty.
-	 * 2) Page doesn't exist yet. Hand over to the kernel.
-	 *
-	 * Test whether present bit in entry is set
-	 */
-	/* used to be dmfc0 */
-	mfc0	k0,CP0_BADVADDR
-	/* FIXME: This srl/sll sequence is as it is for the R4xx0,
-	 *        and I suspect that it should be different for
-	 *	  the R[23]000.  PMA
-	 */
-	srl	k0,12
-	sll	k0,2
-	lui	k1,%HI(TLBMAP)
-	addu	k0,k1
-	lw	k1,(k0)
-	tlbp					# find faulting entry
-	andi	k1,(_PAGE_PRESENT|_PAGE_WRITE)
-	xori	k1,(_PAGE_PRESENT|_PAGE_WRITE)
 
-	bnez	k1,nopage_tlbs
-	 lw	k1,(k0)
-
-	/* Present and writable bits set: set accessed and dirty bits. */
-	ori	k1,k1,(_PAGE_ACCESSED|_PAGE_MODIFIED| \
-		       _PAGE_VALID|_PAGE_DIRTY)
-	sw	k1,(k0)
-	/* Now reload the entry into the TLB */
-	/* FIXME: Why has Ralf set bit 2?  Should it be different for
-	 *	  R[23]000?  PMA
-	 *        (The ori/xori combination actually _clears_ bit 2.
-	 *        This is required for the R4xx0 these CPUs always
-	 *        map page pairs; a page pair of 4k pages therfore
-	 *        has always an address with bit 2 set to zero. -- Ralf)
-	 */
-	ori	k0,0x0004
-	xori	k0,0x0004
-	lw	k0,(k0)
-	srl	k0,12
-	mtc0	k0,CP0_ENTRYLO0
-	mfc0	k1,CP0_EPC
-	nop				# for pipeline
+#ifndef NOTLB_OPTIMIZE
+	LOAD_PTE(k0, k1)
+	tlbp                            # find faulting entry
+	nop
+	PTE_WRITABLE(k0, k1, nopage_tlbs)
+	PTE_MAKEWRITE(k0, k1)
+	PTE_RELOAD(k1)
 	tlbwi
-	nop				# for pipeline
 	nop
+	mfc0	k0, CP0_EPC
 	nop
-
-	jr	k1
+	jr	k0
 	 rfe
-
-	/* Page doesn't exist. Lots of work which is less important
-	 * for speed needs to be done, so hand it all over to the
-	 * kernel memory management routines.
-	 */
 nopage_tlbs:
-nowrite_mod:
-#ifdef CONFIG_TLB_SHUTDOWN
-	/* Remove entry so we don't need to care later */
-	mfc0	k0,CP0_INDEX
-#ifdef CONF_DEBUG_TLB
-	bgez	k0,2f
-	 nop
-	/* We got a tlbs exception but found no matching entry in
-	 * the tlb.  This should never happen.  Paranoia makes us
-	 * check it, though.
-	 */
-	SAVE_ALL
-	jal	show_regs
-	 move	a0,sp
-	.set	at
-	mfc0	a1,CP0_BADVADDR
-	PRINT("c0_badvaddr == %08lx\n")
-	mfc0	a1,CP0_INDEX
-	PRINT("c0_index    == %08x\n")
-	mfc0	a1,CP0_ENTRYHI
-	PRINT("c0_entryhi  == %08x\n")
-	.set	noat
-	STI
-	.set	at
-	PANIC("Tlbs or tlbm exception with no matching entry in tlb")
-1:
-	j	1b
-	 nop
-2:
-#endif /* CONF_DEBUG_TLB */
-	/* FIXME: Why is Ralf setting bit 3 of k1?  This may need to
-	 *	  be changed for R[236]000! PMA
-	 *        (The new ENTRYHI value will then point represent a
-	 *        inique virtual address outside the 32 bit address
-	 *        limit.  This is just paranoia to avoid a tlb
-	 *        shutdown.  This whole part of the routine is probably
-	 *        no longer required and can be removed -- Ralf)
-	 */
-	lui	k1,0x0008
-	or	k0,k1
-	sll	k0,12
-	mtc0	k0,CP0_ENTRYHI
-	mtc0	zero,CP0_ENTRYLO0
-	nop				# for pipeline
-	nop				# R4000 V2.2 requires 4 NOPs
-	nop
-	nop
-	tlbwi
-#endif /* CONFIG_TLB_SHUTDOWN */
-	.set	noat
-	SAVE_ALL
-	mfc0	a2,CP0_BADVADDR
-	STI
-	.set	at
-	/* a0 (struct pt_regs *) regs
-	 * a1 (unsigned long)    1 for write access
-	 * a2 (unsigned long)    faulting virtual address
-	 */
-	move	a0,sp
-	jal	do_page_fault
-	 li	a1,1
-
-	j	ret_from_sys_call
-	 nop
-	END(r2300_handle_tlbs)
+#endif
 
+	DO_FAULT(1)
+END(r2300_handle_tlbs)
 
 	.align	5
-	NESTED(r2300_handle_mod, PT_SIZE, sp)
+NESTED(r2300_handle_mod, PT_SIZE, sp)
 	.set	noat
-	/* Two possible cases:
-	 * 1) Page is writable but not dirty -> set dirty and return
-	 * 2) Page is not writable -> call C handler
-	 */
-	/* used to be dmfc0 */
-	mfc0	k0,CP0_BADVADDR
-	/* FIXME: This srl/sll sequence is as it is for the R4xx0,
-	 *        and I suspect that it should be different for
-	 *	  the R[23]000.  PMA
-	 */
-	srl	k0,12
-	sll	k0,2
-	lui	k1,%HI(TLBMAP)
-	addu	k0,k1
-	lw	k1,(k0)
+#ifndef NOTLB_OPTIMIZE
+	LOAD_PTE(k0, k1)
 	tlbp					# find faulting entry
-	andi	k1,_PAGE_WRITE
+	andi	k0, k0, _PAGE_WRITE
+	beqz	k0, nowrite_mod
+	.set	push
+	.set    reorder
+	lw	k0, (k1)
+	.set    pop
 
-	beqz	k1,nowrite_mod
-	 lw	k1,(k0)
+	/* Present and writable bits set, set accessed and dirty bits. */
+	PTE_MAKEWRITE(k0, k1)
 
-	/* Present and writable bits set: set accessed and dirty bits. */
-	ori	k1,(_PAGE_ACCESSED|_PAGE_DIRTY)
-	sw	k1,(k0)
-	/* Now reload the entry into the tlb */
-	/* FIXME: Why has Ralf set bit 2?  Should it be different for
-	 *	  R[23]000?  PMA
-	 *        (The ori/xori combination actually _clears_ bit 2.
-	 *        This is required for the R4xx0 these CPUs always
-	 *        map page pairs; a page pair of 4k pages therfore
-	 *        has always an address with bit 2 set to zero. -- Ralf)
-	 */
-	ori	k0,0x0004
-	xori	k0,0x0004
-	lw	k0,(k0)
-	srl	k0,12
-	mtc0	k0,CP0_ENTRYLO0
-	mfc0	k1,CP0_EPC
-	nop				# for pipeline
-	nop
+	/* Now reload the entry into the tlb. */
+	PTE_RELOAD(k1)
 	nop
 	tlbwi
-	nop				# for pipeline
 	nop
+	mfc0	k0, CP0_EPC
 	nop
-
-	jr	k1
+	jr	k0
 	 rfe
-	END(r2300_handle_mod)
-	.set	at
+#endif
+
+nowrite_mod:
+	DO_FAULT(1)
+END(r2300_handle_mod)
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/r2300_switch.S linux/arch/mips/kernel/r2300_switch.S
--- v2.3.8/linux/arch/mips/kernel/r2300_switch.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/r2300_switch.S	Fri Jun 25 17:40:12 1999
@@ -1,12 +1,15 @@
-/*
- * r2300_switch.S: R3000/R2000 specific task switching code.
+/* $Id: r2300_switch.S,v 1.6 1999/06/13 16:30:32 ralf Exp $
+ *
+ * r2300_switch.S: R2300 specific task switching code.
  *
- * Copyright (C) 1994, 1995, 1996 by Ralf Baechle and Andreas Busse
+ * Copyright (C) 1994, 1995, 1996, 1999 by Ralf Baechle
+ * Copyright (C) 1994, 1995, 1996 by Andreas Busse
  *
  * Multi-cpu abstraction and macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r2300_switch.S,v 1.4 1998/04/04 13:59:38 ralf Exp $
+ * Further modifications to make this work:
+ * Copyright (c) 1998 Harald Koerfgen
  */
 #include <asm/asm.h>
 #include <asm/bootinfo.h>
@@ -15,6 +18,7 @@
 #include <asm/fpregdef.h>
 #include <asm/mipsconfig.h>
 #include <asm/mipsregs.h>
+#include <asm/offset.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
@@ -23,68 +27,137 @@
 
 #include <asm/asmmacro.h>
 
-/* XXX The following is fucking losing... find a better way dave. */
-MODE_ALIAS	=	0x00e0			# uncachable, dirty, valid
-
-	.text
 	.set	mips1
-	.set	noreorder
+	.align	5
+
 /*
- * Code necessary to switch tasks on an Linux/MIPS machine.
- * FIXME: We don't need to disable interrupts anymore.
+ * task_struct *r4xx0_resume(task_struct *prev,
+ *                           task_struct *next)
  */
-	.align	5
-	LEAF(r2300_resume)
-	mfc0	t1,CP0_STATUS		# Save status register
-	sw	t1,THREAD_STATUS($28)
-	ori	t2,t1,0x1f		# Disable interrupts
-	xori	t2,0x1e
-	mtc0	t2,CP0_STATUS
-	CPU_SAVE_NONSCRATCH($28)
-	sll	t2,t1,2			# Save floating point state
-	bgez	t2,1f
-	 sw	ra,THREAD_REG31($28)
-	FPU_SAVE($28, t0)
-1:
-	move	$28, a0
-	lw	t0,THREAD_PGDIR($28)	# Switch the root pointer
-	li	t1,TLB_ROOT		# get PFN
-	mtc0	t1,CP0_ENTRYHI
-	mtc0	zero,CP0_INDEX
-	srl	t0,12			# PFN is 12 bits west
-	ori	t0,MODE_ALIAS		# want uncachable, dirty, valid
-	mtc0	t0,CP0_ENTRYLO0
-	lw	a2,THREAD_STATUS($28)
-	tlbwi
-
-	/* Flush TLB. */
-	mfc0	t3,CP0_STATUS		# disable interrupts...
-	ori	t4,t3,1
-	xori	t4,1
-	mtc0	t4,CP0_STATUS
-	lw      t0,mips_tlb_entries
-	mtc0	zero,CP0_ENTRYLO0
-1:
-	subu	t0,1
-	mtc0	t0,CP0_INDEX
-	lui	t1,0x0008
-	or	t1,t0,t1
-	sll	t1,12
-	mtc0	t1,CP0_ENTRYHI
-	bne	t2,t0,1b
-	 tlbwi
-
-	ori	t1,a2,1			# Restore FPU, pipeline magic
-	xori	t1,1
-	mtc0	t1,CP0_STATUS
-	sll	t0,a2,2
-	bgez	t0,1f
-	 lw	ra,THREAD_REG31($28)
-	FPU_RESTORE($28, t0)
-1:
+LEAF(r2300_resume)
+	.set	reorder
+	mfc0	t1, CP0_STATUS
+	.set	noreorder
+	sw	t1, THREAD_STATUS(a0)
+	CPU_SAVE_NONSCRATCH(a0)
+	sw	ra, THREAD_REG31(a0)
+
+	/*
+	 * The order of restoring the registers takes care of the race
+	 * updating $28, $29 and kernelsp without disabling ints.
+	 */
+	move	$28, a1
 	CPU_RESTORE_NONSCRATCH($28)
 	addiu	t0, $28, KERNEL_STACK_SIZE-32
-	sw	t0,kernelsp
+	sw	t0, kernelsp
+	mfc0	t1, CP0_STATUS		/* Do we really need this? */
+	li	a3, 0xff00
+	and	t1, a3
+	lw	a2, THREAD_STATUS($28)
+	nor	a3, $0, a3
+	and	a2, a3
+	lw	a3, TASK_MM($28)
+	or	a2, t1
+	lw	a3, MM_CONTEXT(a3)
+	mtc0	a2, CP0_STATUS
+	andi	a3, 0xfc0
+	mtc0	a3, CP0_ENTRYHI
 	jr	ra
-	 mtc0	a2,CP0_STATUS			# Restore status register
+	 move	v0, a0
 	END(r2300_resume)
+
+/*
+ * Do lazy fpu context switch.  Saves FPU context to the process in a0
+ * and loads the new context of the current process.
+ */
+
+#define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS)
+
+LEAF(r2300_lazy_fpu_switch)
+	mfc0	t0, CP0_STATUS			# enable cp1
+	li	t3, 0x20000000
+	or	t0, t3
+	mtc0	t0, CP0_STATUS
+
+	beqz	a0, 2f				# Save floating point state
+	 nor	t3, zero, t3
+	.set	reorder
+	lw	t1, ST_OFF(a0)			# last thread looses fpu
+	.set	noreorder
+	and	t1, t3
+	sw	t1, ST_OFF(a0)
+	swc1	$f0, (THREAD_FPU + 0x00)(a0)
+	FPU_SAVE(a0, t1)			# clobbers t1
+
+2:
+	lwc1	$f0, (THREAD_FPU + 0x00)($28)
+	.set	reorder
+	FPU_RESTORE($28, t0)		# clobbers t0
+	jr	ra
+	END(r2300_lazy_fpu_switch)
+
+/*
+ * Save a thread's fp context.
+ */
+	.set	noreorder
+LEAF(r2300_save_fp)
+	FPU_SAVE(a0, t1)			# clobbers t1
+	jr	ra
+	 swc1	$f0, (THREAD_FPU + 0x00)(a0)
+	END(r2300_save_fp)
+
+/*
+ * Load the FPU with signalling NANS.  This bit pattern we're using has
+ * the property that no matter wether considered as single or as double
+ * precission represents signaling NANS.
+ *
+ * We initialize fcr31 to rounding to nearest, no exceptions.
+ */
+
+#define FPU_DEFAULT  0x00000000
+
+LEAF(r2300_init_fpu)
+	mfc0	t0, CP0_STATUS
+	li	t1, 0x20000000
+	or	t0, t1
+	mtc0	t0, CP0_STATUS
+
+	li	t1, FPU_DEFAULT
+	ctc1	t1, fcr31
+
+	li	t0, -1
+
+	mtc1	t0, $f0
+	mtc1	t0, $f1
+	mtc1	t0, $f2
+	mtc1	t0, $f3
+	mtc1	t0, $f4
+	mtc1	t0, $f5
+	mtc1	t0, $f6
+	mtc1	t0, $f7
+	mtc1	t0, $f8
+	mtc1	t0, $f9
+	mtc1	t0, $f10
+	mtc1	t0, $f11
+	mtc1	t0, $f12
+	mtc1	t0, $f13
+	mtc1	t0, $f14
+	mtc1	t0, $f15
+	mtc1	t0, $f16
+	mtc1	t0, $f17
+	mtc1	t0, $f18
+	mtc1	t0, $f19
+	mtc1	t0, $f20
+	mtc1	t0, $f21
+	mtc1	t0, $f22
+	mtc1	t0, $f23
+	mtc1	t0, $f24
+	mtc1	t0, $f25
+	mtc1	t0, $f26
+	mtc1	t0, $f27
+	mtc1	t0, $f28
+	mtc1	t0, $f29
+	mtc1	t0, $f30
+	jr	ra
+	 mtc1	t0, $f31
+	END(r2300_init_fpu)
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/r4k_fpu.S linux/arch/mips/kernel/r4k_fpu.S
--- v2.3.8/linux/arch/mips/kernel/r4k_fpu.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/r4k_fpu.S	Fri Jun 25 17:40:12 1999
@@ -10,7 +10,7 @@
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r4k_fpu.S,v 1.4 1998/04/04 13:59:38 ralf Exp $
+ * $Id: r4k_fpu.S,v 1.5 1999/05/01 22:40:36 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
@@ -79,11 +79,11 @@
 	END(r4k_save_fp_context)
 
 /*
- * Restore fpu state:
+ * Restore FPU state:
  *  - fp gp registers
  *  - cp1 status/control register
  *
- * We base the decission which registers to restore from the signal stack
+ * We base the decision which registers to restore from the signal stack
  * frame on the current content of c0_status, not on the content of the
  * stack frame which might have been changed by the user.
  */
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/r4k_misc.S linux/arch/mips/kernel/r4k_misc.S
--- v2.3.8/linux/arch/mips/kernel/r4k_misc.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/r4k_misc.S	Fri Jun 25 17:40:12 1999
@@ -6,7 +6,7 @@
  * Multi-cpu abstraction and reworking:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r4k_misc.S,v 1.3 1997/09/07 04:51:07 ralf Exp $
+ * $Id: r4k_misc.S,v 1.4 1997/12/01 17:57:30 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/current.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/r4k_switch.S linux/arch/mips/kernel/r4k_switch.S
--- v2.3.8/linux/arch/mips/kernel/r4k_switch.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/r4k_switch.S	Fri Jun 25 17:40:12 1999
@@ -1,10 +1,10 @@
-/* $Id: r4k_switch.S,v 1.4 1998/07/14 09:15:33 ralf Exp $
+/* $Id: r4k_switch.S,v 1.7 1999/06/13 16:30:32 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1994, 1995, 1996, 1998 by Ralf Baechle
+ * Copyright (C) 1994, 1995, 1996, 1998, 1999 by Ralf Baechle
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1994, 1995, 1996, by Andreas Busse
  */
@@ -24,30 +24,41 @@
 
 #include <asm/asmmacro.h>
 
+/*
+ * task_struct *r4xx0_resume(task_struct *prev,
+ *                           task_struct *next)
+ */
 	.set	noreorder
 	.set	mips3
 	.align	5
 	LEAF(r4xx0_resume)
 	mfc0	t1, CP0_STATUS
-	sw	t1, THREAD_STATUS($28)
-	CPU_SAVE_NONSCRATCH($28)
-	sw	ra, THREAD_REG31($28)
+	sw	t1, THREAD_STATUS(a0)
+	CPU_SAVE_NONSCRATCH(a0)
+	sw	ra, THREAD_REG31(a0)
 
 	/*
 	 * The order of restoring the registers takes care of the race
 	 * updating $28, $29 and kernelsp without disabling ints.
 	 */
-	move	$28, a0
+	move	$28, a1
 	CPU_RESTORE_NONSCRATCH($28)
 	addiu	t0, $28, KERNEL_STACK_SIZE-32
 	sw	t0, kernelsp
-	lw	a3, TASK_MM($28)
+	mfc0	t1, CP0_STATUS		/* Do we really need this? */
+	li	a3, 0xff00
+	and	t1, a3
 	lw	a2, THREAD_STATUS($28)
+	nor	a3, $0, a3
+	and	a2, a3
+	lw	a3, TASK_MM($28)
+	or	a2, t1
 	lw	a3, MM_CONTEXT(a3)
 	mtc0	a2, CP0_STATUS
 	andi	a3, a3, 0xff
+	mtc0	a3, CP0_ENTRYHI
 	jr	ra
-	 mtc0	a3, CP0_ENTRYHI
+	 move	v0, a0
 	END(r4xx0_resume)
 
 /*
@@ -104,8 +115,8 @@
 
 /*
  * Load the FPU with signalling NANS.  This bit pattern we're using has
- * the property that no matter wether considered as single or as double
- * precission represents signaling NANS.
+ * the property that no matter whether considered as single or as double
+ * precision represents signaling NANS.
  *
  * We initialize fcr31 to rounding to nearest, no exceptions.
  */
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/r6000_fpu.S linux/arch/mips/kernel/r6000_fpu.S
--- v2.3.8/linux/arch/mips/kernel/r6000_fpu.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/r6000_fpu.S	Fri Jun 25 17:40:12 1999
@@ -10,7 +10,7 @@
  * Multi-arch abstraction and asm macros for easier reading:
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r6000_fpu.S,v 1.3 1997/12/01 16:56:56 ralf Exp $
+ * $Id: r6000_fpu.S,v 1.5 1999/05/01 22:40:37 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/fpregdef.h>
@@ -19,6 +19,7 @@
 #include <asm/regdef.h>
 
 	.set	noreorder
+	.set	mips2
 	/* Save floating point context */
 	LEAF(r6000_save_fp_context)
 	mfc0	t0,CP0_STATUS
@@ -50,11 +51,11 @@
 	 nop
 	END(r6000_save_fp_context)
 
-/* Restore fpu state:
+/* Restore FPU state:
  *  - fp gp registers
  *  - cp1 status/control register
  *
- * We base the decission which registers to restore from the signal stack
+ * We base the decision which registers to restore from the signal stack
  * frame on the current content of c0_status, not on the content of the
  * stack frame which might have been changed by the user.
  */
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/scall_o32.S linux/arch/mips/kernel/scall_o32.S
--- v2.3.8/linux/arch/mips/kernel/scall_o32.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/scall_o32.S	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: scall_o32.S,v 1.5 1998/08/19 21:53:50 ralf Exp $
+/* $Id: scall_o32.S,v 1.4 1998/06/25 20:01:01 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -44,6 +44,7 @@
 	beqz	t2, illegal_syscall;
 
 	subu	t0, t3, 5		# 5 or more arguments?
+	sw	a3, PT_R26(sp)		# save a3 for syscall restarting
 	bgez	t0, stackargs
 
 stack_done:
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/setup.c linux/arch/mips/kernel/setup.c
--- v2.3.8/linux/arch/mips/kernel/setup.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/setup.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.12 1998/08/18 20:45:06 ralf Exp $
+/* $Id: setup.c,v 1.16 1999/06/17 13:25:47 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -28,6 +28,7 @@
 #ifdef CONFIG_BLK_DEV_RAM
 #include <linux/blk.h>
 #endif
+#include <linux/ide.h>
 #ifdef CONFIG_RTC
 #include <linux/ioport.h>
 #include <linux/timex.h>
@@ -36,7 +37,6 @@
 #include <asm/asm.h>
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
-#include <asm/ide.h>
 #include <asm/io.h>
 #include <asm/stackframe.h>
 #include <asm/system.h>
@@ -76,7 +76,6 @@
  * information is being use to continue the screen output just below
  * the BIOS printed text and with the same text resolution.
  */
-struct drive_info_struct drive_info = DEFAULT_DRIVE_INFO;
 struct screen_info screen_info = DEFAULT_SCREEN_INFO;
 
 #ifdef CONFIG_BLK_DEV_FD
@@ -92,20 +91,20 @@
 extern struct rtc_ops no_rtc_ops;
 struct rtc_ops *rtc_ops;
 
+extern struct kbd_ops no_kbd_ops;
+struct kbd_ops *kbd_ops;
+
 /*
  * Setup information
  *
- * These are intialized so they are in the .data section
+ * These are initialized so they are in the .data section
  */
 unsigned long mips_memory_upper = KSEG0; /* this is set by kernel_entry() */
 unsigned long mips_cputype = CPU_UNKNOWN;
 unsigned long mips_machtype = MACH_UNKNOWN;
 unsigned long mips_machgroup = MACH_GROUP_UNKNOWN;
-unsigned long mips_tlb_entries = 48; /* Guess which CPU I've got :) */
-unsigned long mips_vram_base = KSEG0;
 
 unsigned char aux_device_present;
-extern int root_mountflags;
 extern int _end;
 
 extern char empty_zero_page[PAGE_SIZE];
@@ -114,17 +113,10 @@
  * This is set up by the setup-routine at boot-time
  */
 #define PARAM	empty_zero_page
-#if 0
-#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
-#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
-#endif
-#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
-#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
-#define INITRD_START (*(unsigned long *) (PARAM+0x218))
-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
 
 static char command_line[CL_SIZE] = { 0, };
        char saved_command_line[CL_SIZE];
+extern char arcs_cmdline[CL_SIZE];
 
 /*
  * The board specific setup routine sets irq_setup to point to a board
@@ -153,7 +145,11 @@
            unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	unsigned long memory_end;
-	tag* atag;
+#ifdef CONFIG_BLK_DEV_INITRD
+	unsigned long tmp;
+	unsigned long *initrd_header;
+#endif
+	void baget_setup(void);
 	void cobalt_setup(void);
 	void decstation_setup(void);
 	void deskstation_setup(void);
@@ -161,18 +157,6 @@
 	void sni_rm200_pci_setup(void);
 	void sgi_setup(void);
 
-	/* Perhaps a lot of tags are not getting 'snarfed' - */
-	/* please help yourself */
-
-	atag = bi_TagFind(tag_machtype);
-	memcpy(&mips_machtype, TAGVALPTR(atag), atag->size);
-
-	atag = bi_TagFind(tag_machgroup);
-	memcpy(&mips_machgroup, TAGVALPTR(atag), atag->size);
-
-	atag = bi_TagFind(tag_vram_base);
-	memcpy(&mips_vram_base, TAGVALPTR(atag), atag->size);
-
 	/* Save defaults for configuration-dependent routines.  */
 	irq_setup = default_irq_setup;
 
@@ -185,14 +169,25 @@
 #endif
 
 	rtc_ops = &no_rtc_ops;
+	kbd_ops = &no_kbd_ops;
 
 	switch(mips_machgroup)
 	{
+#ifdef CONFIG_BAGET_MIPS
+	case MACH_GROUP_UNKNOWN: 
+		baget_setup();
+		break;
+#endif
 #ifdef CONFIG_COBALT_MICRO_SERVER
 	case MACH_GROUP_COBALT:
 		cobalt_setup();
 		break;
 #endif
+#ifdef CONFIG_DECSTATION
+	case MACH_GROUP_DEC:
+		decstation_setup();
+		break;
+#endif
 #ifdef CONFIG_MIPS_JAZZ
 	case MACH_GROUP_JAZZ:
 		jazz_setup();
@@ -212,9 +207,6 @@
 		panic("Unsupported architecture");
 	}
 
-	atag = bi_TagFind(tag_drive_info);
-	memcpy(&drive_info, TAGVALPTR(atag), atag->size);
-
 	memory_end = mips_memory_upper;
 	/*
 	 * Due to prefetching and similar mechanism the CPU sometimes
@@ -225,20 +217,7 @@
 	memory_end -= 128;
 	memory_end &= PAGE_MASK;
 
-#ifdef CONFIG_BLK_DEV_RAM
-	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
-	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-
-	atag = bi_TagFind(tag_mount_root_rdonly);
-	if (atag)
-	  root_mountflags |= MS_RDONLY;
-
-	atag = bi_TagFind(tag_command_line);
-	if (atag)
-		memcpy(&command_line, TAGVALPTR(atag), atag->size);	  
-
+        strncpy (command_line, arcs_cmdline, CL_SIZE);
 	memcpy(saved_command_line, command_line, CL_SIZE);
 	saved_command_line[CL_SIZE-1] = '\0';
 
@@ -247,15 +226,21 @@
 	*memory_end_p = memory_end;
 
 #ifdef CONFIG_BLK_DEV_INITRD
-	if (LOADER_TYPE) {
-		initrd_start = INITRD_START;
-		initrd_end = INITRD_START+INITRD_SIZE;
+	tmp = (((unsigned long)&_end + PAGE_SIZE-1) & PAGE_MASK) - 8;
+	if (tmp < (unsigned long)&_end)
+		tmp += PAGE_SIZE;
+	initrd_header = (unsigned long *)tmp;
+	if (initrd_header[0] == 0x494E5244) {
+		initrd_start = (unsigned long)&initrd_header[2];
+		initrd_end = initrd_start + initrd_header[1];
+		initrd_below_start_ok = 1;
 		if (initrd_end > memory_end) {
 			printk("initrd extends beyond end of memory "
 			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
 			       initrd_end,memory_end);
-		initrd_start = 0;
-		}
+			initrd_start = 0;
+		} else
+			*memory_start_p = initrd_end;
 	}
 #endif
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c
--- v2.3.8/linux/arch/mips/kernel/signal.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/signal.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: signal.c,v 1.24 1998/09/16 22:50:42 ralf Exp $
+/* $Id: signal.c,v 1.19 1999/06/17 13:25:47 ralf Exp $
  *
  *  linux/arch/mips/kernel/signal.c
  *
@@ -392,6 +392,7 @@
 		}
 	/* fallthrough */
 	case ERESTARTNOINTR:		/* Userland will reload $v0.  */
+		regs->regs[7] = regs->regs[26];
 		regs->cp0_epc -= 8;
 	}
 
@@ -491,6 +492,7 @@
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
 			case SIGABRT: case SIGFPE: case SIGSEGV:
+			case SIGBUS:
 				lock_kernel();
 				if (current->binfmt
 				    && current->binfmt->core_dump
@@ -502,6 +504,7 @@
 			default:
 				lock_kernel();
 				sigaddset(&current->signal, signr);
+				recalc_sigpending(current);
 				current->flags |= PF_SIGNALED;
 				do_exit(exit_code);
 				/* NOTREACHED */
@@ -524,6 +527,7 @@
 		if (regs->regs[2] == ERESTARTNOHAND ||
 		    regs->regs[2] == ERESTARTSYS ||
 		    regs->regs[2] == ERESTARTNOINTR) {
+			regs->regs[7] = regs->regs[26];
 			regs->cp0_epc -= 8;
 		}
 	}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/softfp.S linux/arch/mips/kernel/softfp.S
--- v2.3.8/linux/arch/mips/kernel/softfp.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/softfp.S	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: softfp.S,v 1.1 1998/07/14 09:33:48 ralf Exp $
+/* $Id: softfp.S,v 1.1 1998/07/16 19:10:02 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c
--- v2.3.8/linux/arch/mips/kernel/syscall.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/syscall.c	Fri Jun 25 17:40:12 1999
@@ -1,10 +1,10 @@
-/* $Id: syscall.c,v 1.10 1998/08/20 14:38:40 ralf Exp $
+/* $Id: syscall.c,v 1.10 1999/02/15 02:16:52 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995 - 1998 by Ralf Baechle
+ * Copyright (C) 1995 - 1999 by Ralf Baechle
  *
  * TODO:  Implement the compatibility syscalls.
  *        Don't waste that much memory for empty entries in the syscall
@@ -61,6 +61,7 @@
 	struct file * file = NULL;
 	unsigned long error = -EFAULT;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
 		error = -EBADF;
@@ -74,17 +75,17 @@
                 fput(file);
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return error;
 }
 
 asmlinkage int sys_idle(void)
 {
 	unsigned long start_idle = 0;
-        int ret = -EPERM;
 
-	lock_kernel();
 	if (current->pid != 0)
-		goto out;
+		return -EPERM;
+
 	/* endless idle loop with no priority at all */
 	current->priority = 0;
 	current->counter = 0;
@@ -110,10 +111,8 @@
 			start_idle = 0;
 		schedule();
 	}
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
+
+	return 0;
 }
 
 asmlinkage int sys_fork(struct pt_regs regs)
@@ -121,9 +120,7 @@
 	int res;
 
 	save_static(&regs);
-	lock_kernel();
 	res = do_fork(SIGCHLD, regs.regs[29], &regs);
-	unlock_kernel();
 	return res;
 }
 
@@ -134,13 +131,11 @@
 	int res;
 
 	save_static(&regs);
-	lock_kernel();
 	clone_flags = regs.regs[4];
 	newsp = regs.regs[5];
 	if (!newsp)
 		newsp = regs.regs[29];
 	res = do_fork(clone_flags, newsp, &regs);
-	unlock_kernel();
 	return res;
 }
 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/syscalls.h linux/arch/mips/kernel/syscalls.h
--- v2.3.8/linux/arch/mips/kernel/syscalls.h	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/syscalls.h	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: syscalls.h,v 1.16 1998/09/16 22:50:43 ralf Exp $
+/* $Id: syscalls.h,v 1.15 1998/09/19 19:16:17 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.3.8/linux/arch/mips/kernel/sysirix.c	Thu Jun  3 23:15:29 1999
+++ linux/arch/mips/kernel/sysirix.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.12 1998/08/17 10:16:27 ralf Exp $
+/* $Id: sysirix.c,v 1.20 1999/06/17 13:25:48 ralf Exp $
  *
  * sysirix.c: IRIX system call emulation.
  *
@@ -172,7 +172,7 @@
 	case PR_RESIDENT:
 		printk("irix_prctl[%s:%ld]: Wants PR_RESIDENT\n",
 		       current->comm, current->pid);
-		error = 0; /* Compatability indeed. */
+		error = 0; /* Compatibility indeed. */
 		break;
 
 	case PR_ATTACHADDR:
@@ -731,8 +731,9 @@
 	struct statfs kbuf;
 	int error, i;
 
-	/* We don't support this feature yet. */
 	lock_kernel();
+
+	/* We don't support this feature yet. */
 	if(fs_type) {
 		error = -EINVAL;
 		goto out;
@@ -1103,6 +1104,7 @@
 	struct file *file = NULL;
 	unsigned long retval;
 
+	down(&current->mm->mmap_sem);
 	lock_kernel();
 	if(!(flags & MAP_ANONYMOUS)) {
 		if(!(file = fget(fd))) {
@@ -1130,6 +1132,7 @@
 
 out:
 	unlock_kernel();
+	up(&current->mm->mmap_sem);
 	return retval;
 }
 
@@ -1619,8 +1622,7 @@
 		__put_user(0, &buf->f_basetype[i]);
 	__put_user(0, &buf->f_flag);
 	__put_user(kbuf.f_namelen, &buf->f_namemax);
-	for(i = 0; i < 32; i++)
-		__put_user(0, &buf->f_fstr[i]);
+	__clear_user(&buf->f_fstr, sizeof(buf->f_fstr));
 
 out_f:
 	fput(file);
@@ -1914,8 +1916,8 @@
 		__put_user(0, &buf->f_basetype[i]);
 	__put_user(0, &buf->f_flag);
 	__put_user(kbuf.f_namelen, &buf->f_namemax);
-	for(i = 0; i < 32; i++)
-		__put_user(0, &buf->f_fstr[i]);
+	__clear_user(buf->f_fstr, sizeof(buf->f_fstr[i]));
+
 out_f:
 	fput(file);
 out:
@@ -1980,22 +1982,21 @@
 #define NAME_OFFSET32(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
 
-static int irix_filldir32(void *__buf, const char *name, int namlen, off_t offset, ino_t ino)
+static int irix_filldir32(void *__buf, const char *name, int namlen,
+                          off_t offset, ino_t ino)
 {
 	struct irix_dirent32 *dirent;
-	struct irix_dirent32_callback *buf = (struct irix_dirent32_callback *)__buf;
+	struct irix_dirent32_callback *buf =
+		 (struct irix_dirent32_callback *)__buf;
 	unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1);
-	int retval;
 
 #ifdef DEBUG_GETDENTS
 	printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]",
 	       reclen, namlen, buf->count);
 #endif
 	buf->error = -EINVAL;	/* only used if we fail.. */
-	if (reclen > buf->count) {
-		retval = -EINVAL;
-		goto out;
-	}
+	if (reclen > buf->count)
+		return -EINVAL;
 	dirent = buf->previous;
 	if (dirent)
 		__put_user(offset, &dirent->d_off);
@@ -2009,10 +2010,7 @@
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 
-	retval = 0;
-
-out:
-	return retval;
+	return 0;
 }
 
 asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob)
@@ -2037,10 +2035,6 @@
 	if (!inode)
 		goto out_putf;
 
-	inode = dentry->d_inode;
-	if (!inode)
-		goto out_putf;
-
 	buf.current_dir = (struct irix_dirent32 *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
@@ -2108,13 +2102,10 @@
 	struct irix_dirent64_callback * buf =
 		(struct irix_dirent64_callback *) __buf;
 	unsigned short reclen = ROUND_UP64(NAME_OFFSET64(dirent) + namlen + 1);
-	int retval;
 
 	buf->error = -EINVAL;	/* only used if we fail.. */
-	if (reclen > buf->count) {
-		retval = -EINVAL;
-		goto out;
-	}
+	if (reclen > buf->count)
+		return -EINVAL;
 	dirent = buf->previous;
 	if (dirent)
 		__put_user(offset, &dirent->d_off);
@@ -2122,15 +2113,13 @@
 	buf->previous = dirent;
 	__put_user(ino, &dirent->d_ino);
 	__put_user(reclen, &dirent->d_reclen);
-	copy_to_user(dirent->d_name, name, namlen);
+	__copy_to_user(dirent->d_name, name, namlen);
 	__put_user(0, &dirent->d_name[namlen]);
 	((char *) dirent) += reclen;
 	buf->curr = dirent;
 	buf->count -= reclen;
 
-	retval = 0;
-out:
-	return retval;
+	return 0;
 }
 
 asmlinkage int irix_getdents64(int fd, void *dirent, int cnt)
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/sysmips.c linux/arch/mips/kernel/sysmips.c
--- v2.3.8/linux/arch/mips/kernel/sysmips.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/sysmips.c	Fri Jun 25 17:40:12 1999
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: sysmips.c,v 1.4 1998/05/07 15:20:05 ralf Exp $
+ * $Id: sysmips.c,v 1.6 1998/08/25 09:14:42 ralf Exp $
  */
 #include <linux/errno.h>
 #include <linux/linkage.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/time.c linux/arch/mips/kernel/time.c
--- v2.3.8/linux/arch/mips/kernel/time.c	Thu Mar 11 23:25:19 1999
+++ linux/arch/mips/kernel/time.c	Wed Jun 30 11:24:54 1999
@@ -1,16 +1,12 @@
-/*
- *  linux/arch/mips/kernel/time.c
+/* $Id: time.c,v 1.12 1999/06/13 16:30:34 ralf Exp $
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
+ *  Copyright (C) 1996, 1997, 1998  Ralf Baechle
  *
  * This file contains the time handling details for PC-style clocks as
  * found in some MIPS systems.
- *
- * 1997-09-10	Updated NTP code according to technical memorandum Jan '96
- *		"A Kernel Model for Precision Timekeeping" by Dave Mills
- *
- * $Id: time.c,v 1.6 1998/08/17 13:57:44 ralf Exp $
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -67,7 +63,7 @@
 
 	quotient = cached_quotient;
 
-	if (last_jiffies != tmp) {
+	if (tmp && last_jiffies != tmp) {
 		last_jiffies = tmp;
 		__asm__(".set\tnoreorder\n\t"
 			".set\tnoat\n\t"
@@ -340,6 +336,25 @@
 static void inline
 timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
+#ifdef CONFIG_PROFILE
+	if(!user_mode(regs)) {
+		if (prof_buffer && current->pid) {
+			extern int _stext;
+			unsigned long pc = regs->cp0_epc;
+
+			pc -= (unsigned long) &_stext;
+			pc >>= prof_shift;
+			/*
+			 * Dont 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]);
+		}
+	}
+#endif
 	do_timer(regs);
 
 	/*
@@ -375,6 +390,16 @@
 	timerlo = count;
 
 	timer_interrupt(irq, dev_id, regs);
+
+	if (!jiffies)
+	{
+		/*
+		 * If jiffies has overflowed in this timer_interrupt we must
+		 * update the timer[hi]/[lo] to make do_fast_gettimeoffset()
+		 * quotient calc still valid. -arca
+		 */
+		timerhi = timerlo = 0;
+	}
 }
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -456,7 +481,7 @@
 
 __initfunc(void time_init(void))
 {
-	unsigned int year, mon, day, hour, min, sec;
+	unsigned int epoch, year, mon, day, hour, min, sec;
 	int i;
 
 	/* The Linux interpretation of the CMOS clock register contents:
@@ -488,13 +513,17 @@
 	    BCD_TO_BIN(mon);
 	    BCD_TO_BIN(year);
 	  }
-#if 0	/* the IBM way */
-	if ((year += 1900) < 1970)
-		year += 100;
-#else
-	/* Acer PICA clock starts from 1980.  True for all MIPS machines?  */
-	year += 1980;
-#endif
+
+	/* Attempt to guess the epoch.  This is the same heuristic as in rtc.c so
+	   no stupid things will happen to timekeeping.  Who knows, maybe Ultrix
+  	   also uses 1952 as epoch ...  */
+	if (year > 10 && year < 44) {
+		epoch = 1980;
+	} else if (year < 96) {
+		epoch = 1952;
+	}
+	year += epoch;
+
 	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
 	xtime.tv_usec = 0;
 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c
--- v2.3.8/linux/arch/mips/kernel/traps.c	Tue Jan  5 11:13:56 1999
+++ linux/arch/mips/kernel/traps.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.20 1998/10/14 20:26:26 ralf Exp $
+/* $Id: traps.c,v 1.20 1999/06/13 16:30:34 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -202,17 +202,16 @@
 	 * Assume it would be too dangerous to continue ...
 	 */
 	force_sig(SIGBUS, current);
+show_regs(regs); while(1);
 }
 
 void do_ibe(struct pt_regs *regs)
 {
-show_regs(regs); while(1);
 	ibe_board_handler(regs);
 }
 
 void do_dbe(struct pt_regs *regs)
 {
-show_regs(regs); while(1);
 	dbe_board_handler(regs);
 }
 
@@ -325,7 +324,7 @@
 	/*
 	 * (A short test says that IRIX 5.3 sends SIGTRAP for all break
 	 * insns, even for break codes that indicate arithmetic failures.
-	 * Wiered ...)
+	 * Weird ...)
 	 */
 	force_sig(SIGTRAP, current);
 }
@@ -465,8 +464,8 @@
 extern asmlinkage void r2300_restore_fp_context(struct sigcontext *sc);
 extern asmlinkage void r6000_restore_fp_context(struct sigcontext *sc);
 
-extern asmlinkage void r4xx0_resume(void *tsk);
-extern asmlinkage void r2300_resume(void *tsk);
+extern asmlinkage void *r4xx0_resume(void *last, void *next);
+extern asmlinkage void *r2300_resume(void *last, void *next);
 
 __initfunc(void trap_init(void))
 {
diff -u --recursive --new-file v2.3.8/linux/arch/mips/kernel/unaligned.c linux/arch/mips/kernel/unaligned.c
--- v2.3.8/linux/arch/mips/kernel/unaligned.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/kernel/unaligned.c	Fri Jun 25 17:40:12 1999
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1996, 1998 by Ralf Baechle
  *
- * $Id: unaligned.c,v 1.5 1998/08/17 13:57:44 ralf Exp $
+ * $Id: unaligned.c,v 1.5 1999/05/01 22:40:39 ralf Exp $
  *
  * This file contains exception handler for address error exception with the
  * special capability to execute faulting instructions in software.  The
@@ -17,7 +17,7 @@
  * Putting data to unaligned addresses is a bad practice even on Intel where
  * only the performance is affected.  Much worse is that such code is non-
  * portable.  Due to several programs that die on MIPS due to alignment
- * problems I decieded to implement this handler anyway though I originally
+ * problems I decided to implement this handler anyway though I originally
  * didn't intend to do this at all for user code.
  *
  * For now I enable fixing of address errors by default to make life easier.
@@ -140,7 +140,7 @@
 		goto sigbus;
 
 	/*
-	 * The remaining opcodes are the ones that are really of interrest.
+	 * The remaining opcodes are the ones that are really of interest.
 	 */
 	case lh_op:
 		check_axs(pc, addr, 2);
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/Makefile linux/arch/mips/lib/Makefile
--- v2.3.8/linux/arch/mips/lib/Makefile	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/lib/Makefile	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.12 1998/05/28 03:17:57 ralf Exp $
+# $Id: Makefile,v 1.9 1999/01/04 16:03:50 ralf Exp $
 #
 # Makefile for MIPS-specific library files..
 #
@@ -10,7 +10,7 @@
 
 L_TARGET = lib.a
 L_OBJS	= csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \
-	  floppy-no.o ide-std.o ide-no.o rtc-std.o rtc-no.o memset.o memcpy.o \
-	  strlen_user.o strncpy_user.o tags.o watch.o
+	  floppy-no.o ide-std.o ide-no.o kbd-std.o kbd-no.o rtc-std.o \
+	  rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o watch.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/csum_partial.S linux/arch/mips/lib/csum_partial.S
--- v2.3.8/linux/arch/mips/lib/csum_partial.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/lib/csum_partial.S	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: csum_partial.S,v 1.3 1998/05/07 14:17:45 ralf Exp $
+/* $Id: csum_partial.S,v 1.2 1998/05/07 23:44:01 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/csum_partial_copy.c linux/arch/mips/lib/csum_partial_copy.c
--- v2.3.8/linux/arch/mips/lib/csum_partial_copy.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/lib/csum_partial_copy.c	Fri Jun 25 17:40:12 1999
@@ -14,7 +14,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * $Id: csum_partial_copy.c,v 1.2 1998/09/16 13:29:32 ralf Exp $
+ * $Id: csum_partial_copy.c,v 1.2 1998/09/19 19:16:17 ralf Exp $
  */
 #include <net/checksum.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/floppy-std.c linux/arch/mips/lib/floppy-std.c
--- v2.3.8/linux/arch/mips/lib/floppy-std.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/lib/floppy-std.c	Fri Jun 25 17:40:12 1999
@@ -1,4 +1,4 @@
-/* $Id: floppy-std.c,v 1.2 1998/05/28 03:17:57 ralf Exp $
+/* $Id: floppy-std.c,v 1.3 1998/10/28 12:38:13 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
-#include <linux/kbdcntrlr.h>
 #include <linux/kernel.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/ide-no.c linux/arch/mips/lib/ide-no.c
--- v2.3.8/linux/arch/mips/lib/ide-no.c	Thu May 13 11:00:08 1999
+++ linux/arch/mips/lib/ide-no.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: ide-no.c,v 1.2 1998/05/28 03:17:57 ralf Exp $
+/* $Id: ide-no.c,v 1.3 1999/06/17 13:25:49 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -7,13 +7,13 @@
  * Stub IDE routines to keep Linux from crashing on machine which don't
  * have IDE like the Indy.
  *
- * Copyright (C) 1998 by Ralf Baechle
+ * Copyright (C) 1998, 1999 by Ralf Baechle
  */
 #include <linux/hdreg.h>
 #include <linux/kernel.h>
+#include <linux/ide.h>
 #include <asm/hdreg.h>
 #include <asm/ptrace.h>
-#include <asm/ide.h>
 
 static int no_ide_default_irq(ide_ioreg_t base)
 {
@@ -25,17 +25,15 @@
 	return 0;
 }
 
-static void no_ide_init_hwif_ports (	hw_regs_t *hw,
-					ide_ioreg_t data_port,
-					ide_ioreg_t ctrl_port,
-					int *irq)
+static void no_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
+                                    ide_ioreg_t ctrl_port, int *irq)
 {
 }
 
 static int no_ide_request_irq(unsigned int irq,
-                                void (*handler)(int,void *, struct pt_regs *),
-                                unsigned long flags, const char *device,
-                                void *dev_id)
+                              void (*handler)(int,void *, struct pt_regs *),
+                              unsigned long flags, const char *device,
+                              void *dev_id)
 {
 	panic("no_no_ide_request_irq called - shouldn't happen");
 }			
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/ide-std.c linux/arch/mips/lib/ide-std.c
--- v2.3.8/linux/arch/mips/lib/ide-std.c	Thu May 13 11:00:08 1999
+++ linux/arch/mips/lib/ide-std.c	Fri Jun 25 17:40:13 1999
@@ -1,5 +1,4 @@
-/*
- * include/asm-mips/types.h
+/* $Id: ide-std.c,v 1.4 1999/06/17 13:25:49 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -7,12 +6,14 @@
  *
  * IDE routines for typical pc-like standard configurations.
  *
- * Copyright (C) 1998 by Ralf Baechle
+ * Copyright (C) 1998, 1999 by Ralf Baechle
  */
+#include <linux/sched.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
 #include <linux/hdreg.h>
 #include <asm/ptrace.h>
 #include <asm/hdreg.h>
-#include <asm/ide.h>
 
 static int std_ide_default_irq(ide_ioreg_t base)
 {
@@ -42,10 +43,8 @@
 	}
 }
 
-static void std_ide_init_hwif_ports (	hw_regs_t *hw,
-					ide_ioreg_t data_port,
-					ide_ioreg_t ctrl_port,
-					int *irq)
+static void std_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port,
+                                     ide_ioreg_t ctrl_port, int *irq)
 {
 	ide_ioreg_t reg = data_port;
 	int i;
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/kbd-no.c linux/arch/mips/lib/kbd-no.c
--- v2.3.8/linux/arch/mips/lib/kbd-no.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/lib/kbd-no.c	Fri Jun 25 17:40:13 1999
@@ -0,0 +1,63 @@
+/* $Id: kbd-no.c,v 1.1 1998/10/28 12:38:14 ralf Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Stub keyboard and psaux routines to keep Linux from crashing on machines
+ * without a keyboard.
+ *
+ * Copyright (C) 1998 by Ralf Baechle
+ */
+#include <linux/sched.h>
+#include <asm/keyboard.h>
+
+static void no_kbd_request_region(void)
+{
+	/* No I/O ports are being used on the Indy.  */
+}
+
+static int no_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *))
+{
+	return -ENODEV;
+}
+
+static int no_aux_request_irq(void (*handler)(int, void *, struct pt_regs *))
+{
+	return -ENODEV;
+}
+
+static void no_aux_free_irq(void)
+{
+}
+
+static unsigned char no_kbd_read_input(void)
+{
+	return 0;
+}
+
+static void no_kbd_write_output(unsigned char val)
+{
+}
+
+static void no_kbd_write_command(unsigned char val)
+{
+}
+
+static unsigned char no_kbd_read_status(void)
+{
+	return 0;
+}
+
+struct kbd_ops no_kbd_ops = {
+	no_kbd_request_region,
+	no_kbd_request_irq,
+
+	no_aux_request_irq,
+	no_aux_free_irq,
+
+	no_kbd_read_input,
+	no_kbd_write_output,
+	no_kbd_write_command,
+	no_kbd_read_status
+};
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/kbd-std.c linux/arch/mips/lib/kbd-std.c
--- v2.3.8/linux/arch/mips/lib/kbd-std.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/lib/kbd-std.c	Fri Jun 25 17:40:13 1999
@@ -0,0 +1,81 @@
+/* $Id: kbd-std.c,v 1.2 1999/06/11 14:29:45 ralf Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Routines for standard PC style keyboards accessible via I/O ports.
+ *
+ * Copyright (C) 1998, 1999 by Ralf Baechle
+ */
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/pc_keyb.h>
+#include <asm/keyboard.h>
+#include <asm/io.h>
+
+#define KEYBOARD_IRQ 1
+#define AUX_IRQ 12
+
+static void std_kbd_request_region(void)
+{
+	request_region(0x60, 16, "keyboard");
+}
+
+static int std_kbd_request_irq(void (*handler)(int, void *, struct pt_regs *))
+{
+	return request_irq(KEYBOARD_IRQ, handler, 0, "keyboard", NULL);
+}
+
+static int std_aux_request_irq(void (*handler)(int, void *, struct pt_regs *))
+{
+	return request_irq(AUX_IRQ, handler, 0, "PS/2 Mouse", NULL);
+}
+
+static void std_aux_free_irq(void)
+{
+	free_irq(AUX_IRQ, NULL);
+}
+
+static unsigned char std_kbd_read_input(void)
+{
+	return inb(KBD_DATA_REG);
+}
+
+static void std_kbd_write_output(unsigned char val)
+{
+	int status;
+
+	do {
+		status = inb(KBD_CNTL_REG);
+	} while (status & KBD_STAT_IBF);
+	outb(val, KBD_DATA_REG);
+}
+
+static void std_kbd_write_command(unsigned char val)
+{
+	int status;
+
+	do {
+		status = inb(KBD_CNTL_REG);
+	} while (status & KBD_STAT_IBF);
+	outb(val, KBD_CNTL_REG);
+}
+
+static unsigned char std_kbd_read_status(void)
+{
+	return inb(KBD_STATUS_REG);
+}
+
+struct kbd_ops std_kbd_ops = {
+	std_kbd_request_region,
+	std_kbd_request_irq,
+
+	std_aux_request_irq,
+	std_aux_free_irq,
+
+	std_kbd_read_input,
+	std_kbd_write_output,
+	std_kbd_write_command,
+	std_kbd_read_status
+};
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/memcpy.S linux/arch/mips/lib/memcpy.S
--- v2.3.8/linux/arch/mips/lib/memcpy.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/lib/memcpy.S	Fri Jun 25 17:40:13 1999
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * $Id: memcpy.S,v 1.4 1998/07/03 14:05:33 ralf Exp $
+ * $Id: memcpy.S,v 1.3 1998/07/10 01:14:49 ralf Exp $
  *
  * Unified implementation of memcpy, memmove and the __copy_user backend.
  * For __rmemcpy and memmove an exception is always a kernel bug, therefore
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/memset.S linux/arch/mips/lib/memset.S
--- v2.3.8/linux/arch/mips/lib/memset.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/lib/memset.S	Fri Jun 25 17:40:13 1999
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1998 by Ralf Baechle
  *
- * $Id: memset.S,v 1.2 1998/04/25 17:01:45 ralf Exp $
+ * $Id: memset.S,v 1.1 1998/05/04 09:12:54 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/offset.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/strlen_user.S linux/arch/mips/lib/strlen_user.S
--- v2.3.8/linux/arch/mips/lib/strlen_user.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/lib/strlen_user.S	Fri Jun 25 17:40:13 1999
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1996, 1998 by Ralf Baechle
  *
- * $Id: strlen_user.S,v 1.3 1998/05/03 11:13:45 ralf Exp $
+ * $Id: strlen_user.S,v 1.2 1998/05/04 09:12:54 ralf Exp $
  */
 #include <asm/asm.h>
 #include <asm/offset.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/strncpy_user.S linux/arch/mips/lib/strncpy_user.S
--- v2.3.8/linux/arch/mips/lib/strncpy_user.S	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/lib/strncpy_user.S	Fri Jun 25 17:40:13 1999
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 1996 by Ralf Baechle
  *
- * $Id: strncpy_user.S,v 1.3 1998/05/03 11:13:45 ralf Exp $
+ * $Id: strncpy_user.S,v 1.2 1998/05/04 09:12:54 ralf Exp $
  */
 #include <linux/errno.h>
 #include <asm/asm.h>
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/tags.c linux/arch/mips/lib/tags.c
--- v2.3.8/linux/arch/mips/lib/tags.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/lib/tags.c	Wed Dec 31 16:00:00 1969
@@ -1,75 +0,0 @@
-/*
- *  linux/arch/mips/lib/tags.c
- *
- *  Copyright (C) 1996  Stoned Elipot
- */
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
-
-/*
- * Parse the tags present in upper memory to find out
- * a pecular one.
- *
- * Parameter: type - tag type to find
- * 
- * returns  : NULL  - failure
- *            !NULL - pointer on the tag structure found 
- */
-tag *
-bi_TagFind(enum bi_tag type)
-{
-	tag* t = (tag*)(mips_memory_upper - sizeof(tag));
-
-	while((t->tag != tag_dummy) && (t->tag != type))
-		t = (tag*)(NEXTTAGPTR(t));
-
-	if (t->tag == tag_dummy)		/* tag not found */
-		return (tag*)NULL;
-
-	return t;
-}
-
-/*
- * Snarf from the tag list in memory end some tags needed
- * before the kernel reachs setup_arch()
- *
- * add yours here if you want to, but *beware*: the kernel var
- * that will hold the values you want to snarf have to be
- * in .data section of the kernel, so initialized in to whatever
- * value in the kernel's sources.
- */
-void bi_EarlySnarf(void)
-{
-	tag* atag;
-  
-	/* for wire_mappings() */
-	atag = bi_TagFind(tag_machgroup);
-	if (atag)
-		memcpy(&mips_machgroup, TAGVALPTR(atag), atag->size);
-	else {
-		/* useless for boxes without text video mode but....*/
-		panic("machine group not specified by bootloader");
-	}
-
-	atag = bi_TagFind(tag_machtype);
-	if (atag)
-		memcpy(&mips_machtype, TAGVALPTR(atag), atag->size);
-	else {
-		/* useless for boxes without text video mode but....*/
-		panic("machine type not specified by bootloader");
-	}
-
-	/* for tlbflush() */
-	atag = bi_TagFind(tag_tlb_entries);
-	if (atag)
-		memcpy(&mips_tlb_entries, TAGVALPTR(atag), atag->size);
-	else {
-		/* useless for boxes without text video mode but....*/
-		panic("number of TLB entries not specified by bootloader");
-	}
-
-	return;
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/lib/watch.S linux/arch/mips/lib/watch.S
--- v2.3.8/linux/arch/mips/lib/watch.S	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/lib/watch.S	Fri Jun 25 17:40:13 1999
@@ -1,6 +1,6 @@
 /*
  * Kernel debug stuff to use the Watch registers.
- * Usefull to find stack overflows, dangeling pointers etc.
+ * Useful to find stack overflows, dangling pointers etc.
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
diff -u --recursive --new-file v2.3.8/linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile
--- v2.3.8/linux/arch/mips/mm/Makefile	Sat Aug 16 09:51:07 1997
+++ linux/arch/mips/mm/Makefile	Fri Jun 25 17:40:13 1999
@@ -15,4 +15,8 @@
 O_OBJS   += umap.o
 endif
 
+ifdef CONFIG_BAGET_MIPS
+O_OBJS   += umap.o
+endif
+
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c
--- v2.3.8/linux/arch/mips/mm/andes.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/mm/andes.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: andes.c,v 1.6 1998/10/16 19:22:42 ralf Exp $
+/* $Id: andes.c,v 1.6 1999/01/04 16:03:52 ralf Exp $
  *
  * andes.c: MMU and cache operations for the R10000 (ANDES).
  *
diff -u --recursive --new-file v2.3.8/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
--- v2.3.8/linux/arch/mips/mm/fault.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/mm/fault.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.12 1998/10/19 21:27:37 ralf Exp $
+/* $Id: fault.c,v 1.9 1999/01/04 16:03:53 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
diff -u --recursive --new-file v2.3.8/linux/arch/mips/mm/init.c linux/arch/mips/mm/init.c
--- v2.3.8/linux/arch/mips/mm/init.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/mm/init.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.13 1998/10/16 19:22:42 ralf Exp $
+/* $Id: init.c,v 1.13 1999/05/01 22:40:40 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -35,12 +35,6 @@
 #endif
 #include <asm/mmu_context.h>
 
-/*
- * Define this to effectivly disable the userpage colouring shit.
- */
-#define CONF_GIVE_A_SHIT_ABOUT_COLOURS
-
-extern void deskstation_tyne_dma_init(void);
 extern void show_net_buffers(void);
 
 void __bad_pte_kernel(pmd_t *pmd)
@@ -59,7 +53,7 @@
 {
 	pte_t *page;
 
-	page = (pte_t *) __get_free_page(GFP_KERNEL);
+	page = (pte_t *) __get_free_page(GFP_USER);
 	if (pmd_none(*pmd)) {
 		if (page) {
 			clear_page((unsigned long)page);
@@ -126,6 +120,7 @@
 	case CPU_R4400SC:
 	case CPU_R4400MC:
 		order = 3;
+		break;
 	default:
 		order = 0;
 	}
@@ -137,6 +132,7 @@
 	pg = MAP_NR(empty_zero_page);
 	while(pg < MAP_NR(empty_zero_page) + (1 << order)) {
 		set_bit(PG_reserved, &mem_map[pg].flags);
+		atomic_set(&mem_map[pg].count, 0);
 		pg++;
 	}
 
@@ -243,83 +239,6 @@
 	return pte_mkdirty(mk_pte(page, PAGE_SHARED));
 }
 
-#ifdef __SMP__
-spinlock_t user_page_lock = SPIN_LOCK_UNLOCKED;
-#endif
-struct upcache user_page_cache[8] __attribute__((aligned(32)));
-static unsigned long user_page_order;
-unsigned long user_page_colours;
-
-unsigned long get_user_page_slow(int which)
-{
-	unsigned long chunk;
-	struct upcache *up = &user_page_cache[0];
-	struct page *p, *res;
-	int i;
-
-	do {
-		chunk = __get_free_pages(GFP_KERNEL, user_page_order);
-	} while(chunk==0);
-
-	p = mem_map + MAP_NR(chunk);
-	res = p + which;
-	spin_lock(&user_page_lock);
-	for (i=user_page_colours; i>=0; i--,p++,up++,chunk+=PAGE_SIZE) {
-		atomic_set(&p->count, 1);
-		p->age = PAGE_INITIAL_AGE;
-
-		if (p != res) {
-			if(up->count < USER_PAGE_WATER) {
-				p->next = up->list;
-				up->list = p;
-				up->count++;
-			} else
-				free_pages(chunk, 0);
-		}
-	}
-	spin_unlock(&user_page_lock);
-
-	return page_address(res);
-}
-
-static inline void user_page_setup(void)
-{
-	unsigned long assoc = 0;
-	unsigned long dcache_log, icache_log, cache_log;
-	unsigned long config = read_32bit_cp0_register(CP0_CONFIG);
-
-	switch(mips_cputype) {
-	case CPU_R4000SC:
-	case CPU_R4000MC:
-	case CPU_R4400SC:
-	case CPU_R4400MC:
-		cache_log = 3;	/* => 32k, sucks  */
-		break;
-
-        case CPU_R4600:                 /* two way set associative caches?  */
-        case CPU_R4700:
-        case CPU_R5000:
-        case CPU_NEVADA:
-		assoc = 1;
-		/* fall through */
-	default:
-		/* use bigger cache  */
-		icache_log = (config >> 9) & 7;
-		dcache_log = (config >> 6) & 7;
-		if (dcache_log > icache_log)
-			cache_log = dcache_log;
-		else
-			cache_log = icache_log;
-	}
-
-#ifdef CONF_GIVE_A_SHIT_ABOUT_COLOURS
-	cache_log = assoc = 0;
-#endif
-
-	user_page_order = cache_log - assoc;
-	user_page_colours = (1 << (cache_log - assoc)) - 1;
-}
-
 void show_mem(void)
 {
 	int i, free = 0, total = 0, reserved = 0;
@@ -346,7 +265,6 @@
 	printk("%d pages swap cached\n",cached);
 	printk("%ld pages in page table cache\n",pgtable_cache_size);
 	printk("%d free pages\n", free);
-	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
@@ -375,8 +293,9 @@
 #endif
 
 	end_mem &= PAGE_MASK;
-	max_mapnr = num_physpages = MAP_NR(end_mem);
+	max_mapnr = MAP_NR(end_mem);
 	high_memory = (void *)end_mem;
+	num_physpages = 0;
 
 	/* mark usable pages in the mem_map[] */
 	start_mem = PAGE_ALIGN(start_mem);
@@ -384,15 +303,12 @@
 	for(tmp = MAP_NR(start_mem);tmp < max_mapnr;tmp++)
 		clear_bit(PG_reserved, &mem_map[tmp].flags);
 
-
-#ifdef CONFIG_SGI
 	prom_fixup_mem_map(start_mem, (unsigned long)high_memory);
-#endif
 
 	for (tmp = PAGE_OFFSET; tmp < end_mem; tmp += PAGE_SIZE) {
 		/*
 		 * This is only for PC-style DMA.  The onboard DMA
-		 * of Jazz and Tyne machines is completly different and
+		 * of Jazz and Tyne machines is completely different and
 		 * not handled via a flag in mem_map_t.
 		 */
 		if (tmp >= MAX_DMA_ADDRESS)
@@ -406,6 +322,7 @@
 				datapages++;
 			continue;
 		}
+		num_physpages++;
 		atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (!initrd_start || (tmp < initrd_start || tmp >=
@@ -423,9 +340,6 @@
 		max_mapnr << (PAGE_SHIFT-10),
 		codepages << (PAGE_SHIFT-10),
 		datapages << (PAGE_SHIFT-10));
-
-	/* Initialize allocator for colour matched mapped pages.  */
-	user_page_setup();
 }
 
 extern char __init_begin, __init_end;
@@ -433,7 +347,9 @@
 void free_initmem(void)
 {
 	unsigned long addr;
-        
+
+	prom_free_prom_memory ();
+    
 	addr = (unsigned long)(&__init_begin);
 	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
 		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
@@ -452,7 +368,7 @@
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
-	val->bufferram = buffermem;
+	val->bufferram = atomic_read(&buffermem);
 	while (i-- > 0)  {
 		if (PageReserved(mem_map+i))
 			continue;
diff -u --recursive --new-file v2.3.8/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c
--- v2.3.8/linux/arch/mips/mm/loadmmu.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/mm/loadmmu.c	Fri Jun 25 17:40:13 1999
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: loadmmu.c,v 1.7 1998/03/27 08:53:41 ralf Exp $
+ * $Id: loadmmu.c,v 1.10 1999/06/17 13:25:51 ralf Exp $
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -31,6 +31,7 @@
 
 /* DMA cache operations. */
 void (*dma_cache_wback_inv)(unsigned long start, unsigned long size);
+void (*dma_cache_wback)(unsigned long start, unsigned long size);
 void (*dma_cache_inv)(unsigned long start, unsigned long size);
 
 /* TLB operations. */
@@ -53,7 +54,7 @@
 
 int (*user_mode)(struct pt_regs *);
 
-asmlinkage void (*resume)(void *tsk);
+asmlinkage void *(*resume)(void *last, void *next);
 
 extern void ld_mmu_r2300(void);
 extern void ld_mmu_r4xx0(void);
@@ -66,6 +67,7 @@
 	switch(mips_cputype) {
 	case CPU_R2000:
 	case CPU_R3000:
+	case CPU_R3000A:
 		printk("Loading R[23]00 MMU routines.\n");
 		ld_mmu_r2300();
 		break;
diff -u --recursive --new-file v2.3.8/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c
--- v2.3.8/linux/arch/mips/mm/r2300.c	Tue Oct 20 13:52:54 1998
+++ linux/arch/mips/mm/r2300.c	Fri Jun 25 17:40:13 1999
@@ -1,8 +1,13 @@
-/* $Id: r2300.c,v 1.7 1998/10/16 19:22:43 ralf Exp $
- *
+/*
  * r2300.c: R2000 and R3000 specific mmu/cache code.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * with a lot of changes to make this thing work for R3000s
+ * Copyright (C) 1998 Harald Koerfgen
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ *
+ * $Id: r2300.c,v 1.8 1999/04/11 17:13:56 harald Exp $
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -11,12 +16,40 @@
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/mmu_context.h>
 #include <asm/system.h>
 #include <asm/sgialib.h>
-#include <asm/mmu_context.h>
+#include <asm/mipsregs.h>
+#include <asm/io.h>
+/*
+ * Temporarily disabled
+ *
+#include <asm/wbflush.h>
+ */
+
+/*
+ * According to the paper written by D. Miller about Linux cache & TLB
+ * flush implementation, DMA/Driver coherence should be done at the 
+ * driver layer.  Thus, normally, we don't need flush dcache for R3000.
+ * Define this if driver does not handle cache consistency during DMA ops.
+ */
+#undef DO_DCACHE_FLUSH
+
+/*
+ *  Unified cache space description structure
+ */
+static struct cache_space {
+	unsigned long ca_flags;  /* Cache space access flags */
+	int           size;      /* Cache space size */
+} icache, dcache;
+
+#undef DEBUG_TLB
+#undef DEBUG_CACHE
 
 extern unsigned long mips_tlb_entries;
 
+#define NTLB_ENTRIES       64  /* Fixed on all R23000 variants... */
+
 /* page functions */
 void r2300_clear_page(unsigned long page)
 {
@@ -94,80 +127,425 @@
 		 "I" (PAGE_SIZE));
 }
 
-/* Cache operations. */
-static inline void r2300_flush_cache_all(void) { }
-static void r2300_flush_cache_mm(struct mm_struct *mm) { }
+__initfunc(static unsigned long size_cache(unsigned long ca_flags))
+{
+	unsigned long flags, status, dummy, size;
+	volatile unsigned long *p;
+
+	p = (volatile unsigned long *) KSEG0;
+
+	save_and_cli(flags);
+
+	/* isolate cache space */
+	write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC);
+
+	*p = 0xa5a55a5a;
+	dummy = *p;
+	status = read_32bit_cp0_register(CP0_STATUS);
+
+	if (dummy != 0xa5a55a5a || (status & (1<<19))) {
+		size = 0;
+	} else {
+		for (size = 512; size <= 0x40000; size <<= 1)
+			*(p + size) = 0;
+		*p = -1;
+		for (size = 512; 
+		     (size <= 0x40000) && (*(p + size) == 0); 
+		     size <<= 1)
+			;
+		if (size > 0x40000)
+			size = 0;
+	}
+	restore_flags(flags);
+
+	return size * sizeof(*p);
+}
+
+__initfunc(static void probe_dcache(void))
+{
+	dcache.size = size_cache(dcache.ca_flags = ST0_DE);
+	printk("Data cache %dkb\n", dcache.size >> 10);
+}
+
+__initfunc(static void probe_icache(void))
+{
+	icache.size = size_cache(icache.ca_flags = ST0_DE|ST0_CE);
+	printk("Instruction cache %dkb\n", icache.size >> 10);
+}
+
+static inline unsigned long get_phys_page (unsigned long page,
+					   struct mm_struct *mm)
+{
+        page &= PAGE_MASK;
+	if (page >= KSEG0 && page < KSEG1) {
+		/*
+		 *  We already have physical address
+		 */
+		return page;
+	} else {
+		if (!mm) {
+			printk ("get_phys_page: vaddr without mm\n");
+			return 0;
+		} else {
+			/* 
+			 *  Find a physical page using mm_struct
+			 */
+			pgd_t *page_dir;
+			pmd_t *page_middle;
+			pte_t *page_table, pte;
+
+			unsigned long address = page;
+
+			page_dir = pgd_offset(mm, address);
+			if (pgd_none(*page_dir))
+				return 0; 
+			page_middle = pmd_offset(page_dir, address);
+			if (pmd_none(*page_middle))
+				return 0; 
+			page_table = pte_offset(page_middle, address);
+			pte = *page_table;
+			if (!pte_present(pte))
+				return 0; 
+			return pte_page(pte);
+	}
+	}
+}
+
+static inline void flush_cache_space_page(struct cache_space *space,
+					  unsigned long page)
+{
+	register unsigned long i, flags, size = space->size;
+	register volatile unsigned char *p = (volatile unsigned char*) page;
+
+#ifndef DO_DCACHE_FLUSH
+	if (space == &dcache)
+		return;
+#endif
+	if (size > PAGE_SIZE)
+		size = PAGE_SIZE;
+
+	save_and_cli(flags);
+
+	/* isolate cache space */
+	write_32bit_cp0_register(CP0_STATUS, (space->ca_flags|flags)&~ST0_IEC);
+
+	for (i = 0; i < size; i += 64) {
+		asm ( 	"sb\t$0,(%0)\n\t"
+			"sb\t$0,4(%0)\n\t"
+			"sb\t$0,8(%0)\n\t"
+			"sb\t$0,12(%0)\n\t"
+			"sb\t$0,16(%0)\n\t"
+			"sb\t$0,20(%0)\n\t"
+			"sb\t$0,24(%0)\n\t"
+			"sb\t$0,28(%0)\n\t"
+ 		        "sb\t$0,32(%0)\n\t"
+ 			"sb\t$0,36(%0)\n\t"
+ 			"sb\t$0,40(%0)\n\t"
+ 			"sb\t$0,44(%0)\n\t"
+ 			"sb\t$0,48(%0)\n\t"
+ 			"sb\t$0,52(%0)\n\t"
+ 			"sb\t$0,56(%0)\n\t"
+ 			"sb\t$0,60(%0)\n\t"
+			: : "r" (p) );
+		p += 64;
+	}
+
+	restore_flags(flags);
+}
+
+static inline void flush_cache_space_all(struct cache_space *space)
+{
+	unsigned long page = KSEG0;
+	int size = space->size;
+
+#ifndef DO_DCACHE_FLUSH
+	if (space == &dcache)
+		return;
+#endif
+	while(size > 0) { 
+		flush_cache_space_page(space, page);
+		page += PAGE_SIZE; size -= PAGE_SIZE;
+        }
+}
+
+static inline void r2300_flush_cache_all(void)
+{
+	flush_cache_space_all(&dcache);
+	flush_cache_space_all(&icache);
+}
+ 
+static void r2300_flush_cache_mm(struct mm_struct *mm)
+{
+	if(mm->context == 0) 
+		return;
+#ifdef DEBUG_CACHE
+		printk("cmm[%d]", (int)mm->context);
+#endif
+	/*
+	 *  This function is called not offen, so it looks
+	 *  enough good to flush all caches than scan mm_struct,
+	 *  count pages to flush (and, very probably, flush more
+	 *  than cache space size :-)
+ */
+	flush_cache_all();
+}
+
 static void r2300_flush_cache_range(struct mm_struct *mm,
 				    unsigned long start,
 				    unsigned long end)
 {
+	/*
+	 *  In general, we need to flush both i- & d- caches here.
+	 *  Optimization: if cache space is less than given range,
+	 *  it is more quickly to flush all cache than all pages in range.
+	 */
+
+	unsigned long page;
+	int icache_done = 0, dcache_done = 0;
+
+	if(mm->context == 0) 
+		return;
+#ifdef DEBUG_CACHE
+	printk("crange[%d]", (int)mm->context);
+#endif
+	if (end - start >= icache.size) {
+		flush_cache_space_all(&icache);
+		icache_done = 1;
+	}
+	if (end - start >= dcache.size) {
+		flush_cache_space_all(&dcache);
+		dcache_done = 1;
+	}
+	if (icache_done && dcache_done)
+		return;
+
+	for (page = start; page < end; page += PAGE_SIZE) {
+		unsigned long phys_page = get_phys_page(page, mm);
+		
+		if (phys_page) {
+			if (!icache_done) 
+				flush_cache_space_page(&icache, phys_page);
+			if (!dcache_done) 
+				flush_cache_space_page(&dcache, phys_page);
+		}
+	}
 }
 
 static void r2300_flush_cache_page(struct vm_area_struct *vma,
 				   unsigned long page)
 {
+	struct mm_struct *mm = vma->vm_mm;
+
+	if(mm->context == 0)
+		return;
+#ifdef DEBUG_CACHE
+	printk("cpage[%d,%08lx]", (int)mm->context, page);
+#endif
+	/*
+	 *  User changes page, so we need to check:
+         *     is icache page flush needed ?
+	 *  It looks we don't need to flush dcache,
+	 *  due it is write-transparent on R3000
+	 */
+	if (vma->vm_flags & VM_EXEC) {
+		unsigned long phys_page = get_phys_page(page, vma->vm_mm);
+		if (phys_page)
+			flush_cache_space_page(&icache, phys_page); 
+	}
 }
 
 static void r2300_flush_page_to_ram(unsigned long page)
 {
-	/* XXX What we want to do here is perform a displacement
-	 * XXX flush because there are circumstances where you do
-	 * XXX indeed want to remove stale data from the cache.
-	 * XXX (DMA operations for example, where the cache cannot
-	 * XXX  "see" this data get changed.)
+	/*
+	 *  We need to flush both i- & d- caches :-(
 	 */
+	unsigned long phys_page = get_phys_page(page, NULL);
+#ifdef DEBUG_CACHE
+	printk("cram[%08lx]", page);
+#endif
+	if (phys_page) {
+		flush_cache_space_page(&icache, phys_page);
+		flush_cache_space_page(&dcache, phys_page);
+	}
+}
+
+static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size)
+{
+	register unsigned long i, flags;
+	register volatile unsigned char *p = (volatile unsigned char*) start;
+
+/*
+ * Temporarily disabled
+	wbflush();
+	 */
+
+	/*
+	 * Invalidate dcache
+	 */
+	if (size < 64)
+		size = 64;
+
+	if (size > dcache.size)
+		size = dcache.size;
+
+	save_and_cli(flags);
+
+	/* isolate cache space */
+	write_32bit_cp0_register(CP0_STATUS, (ST0_DE|flags)&~ST0_IEC);
+
+	for (i = 0; i < size; i += 64) {
+		asm ( 	"sb\t$0,(%0)\n\t"
+			"sb\t$0,4(%0)\n\t"
+			"sb\t$0,8(%0)\n\t"
+			"sb\t$0,12(%0)\n\t"
+			"sb\t$0,16(%0)\n\t"
+			"sb\t$0,20(%0)\n\t"
+			"sb\t$0,24(%0)\n\t"
+			"sb\t$0,28(%0)\n\t"
+ 		        "sb\t$0,32(%0)\n\t"
+ 			"sb\t$0,36(%0)\n\t"
+ 			"sb\t$0,40(%0)\n\t"
+ 			"sb\t$0,44(%0)\n\t"
+ 			"sb\t$0,48(%0)\n\t"
+ 			"sb\t$0,52(%0)\n\t"
+ 			"sb\t$0,56(%0)\n\t"
+ 			"sb\t$0,60(%0)\n\t"
+			: : "r" (p) );
+		p += 64;
+	}
+
+	restore_flags(flags);
 }
 
 static void r2300_flush_cache_sigtramp(unsigned long page)
 {
+	/*
+	 *  We need only flush i-cache here
+	 *
+	 *  This function receives virtual address (from signal.c),
+	 *  but this moment we have needed mm_struct in 'current'
+	 */
+	unsigned long phys_page = get_phys_page(page, current->mm);
+#ifdef DEBUG_CACHE
+		printk("csigtramp[%08lx]", page);
+#endif
+	if (phys_page)
+		flush_cache_space_page(&icache, phys_page);  
 }
 
 /* TLB operations. */
 static inline void r2300_flush_tlb_all(void)
 {
 	unsigned long flags;
+	unsigned long old_ctx;
 	int entry;
 
+#ifdef DEBUG_TLB
+	printk("[tlball]");
+#endif
+
 	save_and_cli(flags);
+	old_ctx = (get_entryhi() & 0xfc0);
 	write_32bit_cp0_register(CP0_ENTRYLO0, 0);
-	for(entry = 0; entry < mips_tlb_entries; entry++) {
-		write_32bit_cp0_register(CP0_INDEX, entry);
-		write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x8) << 12));
+	for(entry = 0; entry < NTLB_ENTRIES; entry++) {
+		write_32bit_cp0_register(CP0_INDEX, entry << 8);
+		write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x80000) << 12));
 		__asm__ __volatile__("tlbwi");
 	}
+	set_entryhi(old_ctx);
 	restore_flags(flags);
 }
 
 static void r2300_flush_tlb_mm(struct mm_struct *mm)
 {
+	if(mm->context != 0) {
+		unsigned long flags;
+
+#ifdef DEBUG_TLB
+		printk("[tlbmm<%d>]", mm->context);
+#endif
+		save_and_cli(flags);
+		get_new_mmu_context(mm, asid_cache);
 	if(mm == current->mm)
-		r2300_flush_tlb_all();
+			set_entryhi(mm->context & 0xfc0);
+		restore_flags(flags);
+	}
 }
 
 static void r2300_flush_tlb_range(struct mm_struct *mm, unsigned long start,
 				  unsigned long end)
 {
+	if(mm->context != 0) {
+		unsigned long flags;
+		int size;
+
+#ifdef DEBUG_TLB
+		printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xfc0),
+		       start, end);
+#endif
+		save_and_cli(flags);
+		size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+		if(size <= NTLB_ENTRIES) {
+			int oldpid = (get_entryhi() & 0xfc0);
+			int newpid = (mm->context & 0xfc0);
+
+			start &= PAGE_MASK;
+			end += (PAGE_SIZE - 1);
+			end &= PAGE_MASK;
+			while(start < end) {
+				int idx;
+
+				set_entryhi(start | newpid);
+				start += PAGE_SIZE;
+				tlb_probe();
+				idx = get_index();
+				set_entrylo0(0);
+				set_entryhi(KSEG0);
+				if(idx < 0)
+					continue;
+				tlb_write_indexed();
+			}
+			set_entryhi(oldpid);
+		} else {
+			get_new_mmu_context(mm, asid_cache);
 	if(mm == current->mm)
-		r2300_flush_tlb_all();
+				set_entryhi(mm->context & 0xfc0);
+		}
+		restore_flags(flags);
+	}
 }
 
 static void r2300_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
-	if(vma->vm_mm == current->mm)
-		r2300_flush_tlb_all();
+	if(vma->vm_mm->context != 0) {
+		unsigned long flags;
+		int oldpid, newpid, idx;
+
+#ifdef DEBUG_TLB
+		printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+#endif
+		newpid = (vma->vm_mm->context & 0xfc0);
+		page &= PAGE_MASK;
+		save_and_cli(flags);
+		oldpid = (get_entryhi() & 0xfc0);
+		set_entryhi(page | newpid);
+		tlb_probe();
+		idx = get_index();
+		set_entrylo0(0);
+		set_entryhi(KSEG0);
+		if(idx < 0)
+			goto finish;
+		tlb_write_indexed();
+
+finish:
+		set_entryhi(oldpid);
+		restore_flags(flags);
+	}
 }
 
 /* Load a new root pointer into the TLB. */
 static void r2300_load_pgd(unsigned long pg_dir)
 {
-	unsigned long flags;
-
-	save_and_cli(flags);
-	write_32bit_cp0_register(CP0_ENTRYHI, TLB_ROOT);
-	write_32bit_cp0_register(CP0_INDEX, 0);
-	write_32bit_cp0_register(CP0_ENTRYLO0, ((pg_dir >> 6) | 0x00e0));
-	__asm__ __volatile__("tlbwi");
-	restore_flags(flags);
 }
 
 /*
@@ -199,17 +577,63 @@
 		 "=r" (dummy2)
 		:"r" ((unsigned long) invalid_pte_table),
 		 "0" (page),
-		 "1" (USER_PTRS_PER_PGD/8));
+		 "1" (PAGE_SIZE/(sizeof(pmd_t)*8)));
 }
 
 static void r2300_update_mmu_cache(struct vm_area_struct * vma,
 				   unsigned long address, pte_t pte)
 {
-	r2300_flush_tlb_page(vma, address);
-	/*
-	 * FIXME: We should also reload a new entry into the TLB to
-	 * avoid unnecessary exceptions.
-	 */
+	unsigned long flags;
+	pgd_t *pgdp;
+	pmd_t *pmdp;
+	pte_t *ptep;
+	int idx, pid;
+
+	pid = (get_entryhi() & 0xfc0);
+
+#ifdef DEBUG_TLB
+	if((pid != (vma->vm_mm->context & 0xfc0)) || (vma->vm_mm->context == 0)) {
+		printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%d\n",
+		       (int) (vma->vm_mm->context & 0xfc0), pid);
+	}
+#endif
+
+	save_and_cli(flags);
+	address &= PAGE_MASK;
+	set_entryhi(address | (pid));
+	pgdp = pgd_offset(vma->vm_mm, address);
+	tlb_probe();
+	pmdp = pmd_offset(pgdp, address);
+	idx = get_index();
+	ptep = pte_offset(pmdp, address);
+	set_entrylo0(pte_val(*ptep));
+	set_entryhi(address | (pid));
+	if(idx < 0) {
+		tlb_write_random();
+#if 0
+		printk("[MISS]");
+#endif
+	} else {
+		tlb_write_indexed();
+#if 0
+		printk("[HIT]");
+#endif
+	}
+#if 0
+	if(!strcmp(current->comm, "args")) {
+		printk("<");
+		for(idx = 0; idx < NTLB_ENTRIES; idx++) {
+			set_index(idx);
+			tlb_read();
+			address = get_entryhi();
+			if((address & 0xfc0) != 0)
+				printk("[%08lx]", address);
+		}
+		printk(">\n");
+	}
+#endif
+	set_entryhi(pid);
+	restore_flags(flags);
 }
 
 static void r2300_show_regs(struct pt_regs * regs)
@@ -248,6 +672,7 @@
 static void r2300_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
 				  unsigned long entryhi, unsigned long pagemask)
 {
+printk("r2300_add_wired_entry");
         /*
 	 * FIXME, to be done
 	 */
@@ -255,14 +680,19 @@
 
 static int r2300_user_mode(struct pt_regs *regs)
 {
-	return !(regs->cp0_status & 0x4);
+	return !(regs->cp0_status & ST0_KUP);
 }
 
 __initfunc(void ld_mmu_r2300(void))
 {
+	printk("CPU revision is: %08x\n", read_32bit_cp0_register(CP0_PRID));
+
 	clear_page = r2300_clear_page;
 	copy_page = r2300_copy_page;
 
+	probe_icache();
+	probe_dcache();
+
 	flush_cache_all = r2300_flush_cache_all;
 	flush_cache_mm = r2300_flush_cache_mm;
 	flush_cache_range = r2300_flush_cache_range;
@@ -274,16 +704,19 @@
 	flush_tlb_mm = r2300_flush_tlb_mm;
 	flush_tlb_range = r2300_flush_tlb_range;
 	flush_tlb_page = r2300_flush_tlb_page;
-	r3000_asid_setup();
+
+        dma_cache_wback_inv = r3k_dma_cache_wback_inv;
 
 	load_pgd = r2300_load_pgd;
 	pgd_init = r2300_pgd_init;
 	update_mmu_cache = r2300_update_mmu_cache;
+	r3000_asid_setup();
 
 	show_regs = r2300_show_regs;
     
         add_wired_entry = r2300_add_wired_entry;
 
 	user_mode = r2300_user_mode;
+
 	flush_tlb_all();
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c
--- v2.3.8/linux/arch/mips/mm/r4xx0.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/mm/r4xx0.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: r4xx0.c,v 1.30 1998/10/16 19:22:43 ralf Exp $
+/* $Id: r4xx0.c,v 1.22 1999/06/17 13:25:51 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -2172,6 +2172,12 @@
 	}
 }
 
+static void
+r4k_dma_cache_wback(unsigned long addr, unsigned long size)
+{
+	panic("r4k_dma_cache called - should not happen.\n");
+}
+
 /*
  * While we're protected against bad userland addresses we don't care
  * very much about what happens in that case.  Usually a segmentation
@@ -2652,6 +2658,7 @@
 		break;
 	}
 	dma_cache_wback_inv = r4k_dma_cache_wback_inv_pc;
+	dma_cache_wback = r4k_dma_cache_wback;
 	dma_cache_inv = r4k_dma_cache_inv_pc;
 }
 
@@ -2735,6 +2742,7 @@
 		break;
 	}
 	dma_cache_wback_inv = r4k_dma_cache_wback_inv_sc;
+	dma_cache_wback = r4k_dma_cache_wback;
 	dma_cache_inv = r4k_dma_cache_inv_sc;
 }
 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/mm/r6000.c linux/arch/mips/mm/r6000.c
--- v2.3.8/linux/arch/mips/mm/r6000.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/mm/r6000.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: r6000.c,v 1.6 1998/10/16 19:22:44 ralf Exp $
+/* $Id: r6000.c,v 1.6 1999/01/04 16:03:54 ralf Exp $
  *
  * r6000.c: MMU and cache routines for the R6000 processors.
  *
diff -u --recursive --new-file v2.3.8/linux/arch/mips/mm/tfp.c linux/arch/mips/mm/tfp.c
--- v2.3.8/linux/arch/mips/mm/tfp.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/mm/tfp.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: tfp.c,v 1.6 1998/10/16 19:22:44 ralf Exp $
+/* $Id: tfp.c,v 1.6 1999/01/04 16:03:55 ralf Exp $
  *
  * tfp.c: MMU and cache routines specific to the r8000 (TFP).
  *
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/Makefile linux/arch/mips/sgi/kernel/Makefile
--- v2.3.8/linux/arch/mips/sgi/kernel/Makefile	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/kernel/Makefile	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.3 1998/06/25 20:19:17 ralf Exp $
+# $Id: Makefile,v 1.7 1999/05/07 18:00:16 ulfc Exp $
 # Makefile for the SGI specific kernel interface routines
 # under Linux.
 #
@@ -13,8 +13,11 @@
 .S.o:
 	$(CC) $(CFLAGS) -c $< -o $*.o
 
-OBJS  = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o system.o \
-	indy_timer.o indyIRQ.o reset.o setup.o time.o
+OBJS  = indy_mc.o indy_sc.o indy_hpc.o indy_int.o indy_rtc.o \
+        system.o indy_timer.o indyIRQ.o reset.o setup.o time.o
+ifdef CONFIG_SGI_PROM_CONSOLE
+OBJS += promcon.o
+endif
 
 all: sgikern.a
 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/indyIRQ.S linux/arch/mips/sgi/kernel/indyIRQ.S
--- v2.3.8/linux/arch/mips/sgi/kernel/indyIRQ.S	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/kernel/indyIRQ.S	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: indyIRQ.S,v 1.3 1998/03/21 22:39:53 ralf Exp $
+/* $Id: indyIRQ.S,v 1.3 1998/03/22 23:27:17 ralf Exp $
  * indyIRQ.S: Interrupt exception dispatch code for FullHouse and
  *            Guiness.
  *
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/indy_hpc.c linux/arch/mips/sgi/kernel/indy_hpc.c
--- v2.3.8/linux/arch/mips/sgi/kernel/indy_hpc.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/kernel/indy_hpc.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: indy_hpc.c,v 1.4 1998/07/14 09:12:27 ralf Exp $
+/* $Id: indy_hpc.c,v 1.6 1999/05/07 22:34:31 ulfc Exp $
  *
  * indy_hpc.c: Routines for generic manipulation of the HPC controllers.
  *
@@ -43,7 +43,8 @@
 	prom_printf("sgihpc_init: ");
 #endif
 
-	if(sid & 1) {
+	/* This test works now thanks to William J. Earl */
+	if ((sid & 1) == 0 ) {
 #ifdef DEBUG_SGIHPC
 		prom_printf("GUINESS ");
 #endif
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/indy_int.c linux/arch/mips/sgi/kernel/indy_int.c
--- v2.3.8/linux/arch/mips/sgi/kernel/indy_int.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/kernel/indy_int.c	Wed Jun 30 11:24:54 1999
@@ -1,14 +1,15 @@
-/* $Id: indy_int.c,v 1.9 1998/05/28 03:18:00 ralf Exp $
+/* $Id: indy_int.c,v 1.13 1999/06/12 17:26:15 ulfc Exp $
  *
  * indy_int.c: Routines for generic manipulation of the INT[23] ASIC
  *             found on INDY workstations..
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
+ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) 
+ *                    - Indigo2 changes
+ *                    - Interrupt handling fixes
  */
-#include <linux/config.h>
 #include <linux/init.h>
-
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
@@ -35,6 +36,7 @@
 #include <asm/sgihpc.h>
 #include <asm/sgint23.h>
 #include <asm/sgialib.h>
+#include <asm/gdb-stub.h>
 
 /* #define DEBUG_SGINT */
 
@@ -51,10 +53,6 @@
 
 extern asmlinkage void indyIRQ(void);
 
-#ifdef CONFIG_REMOTE_DEBUG
-extern void rs_kgdb_hook(int);
-#endif
-
 unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
 unsigned long spurious_count = 0;
@@ -274,7 +272,7 @@
 	int do_random, cpu;
 
 	cpu = smp_processor_id();
-	irq_enter(cpu, irq);
+	hardirq_enter(cpu);
 	kstat.irqs[0][irq]++;
 
 	printk("Got irq %d, press a key.", irq);
@@ -310,7 +308,7 @@
 			add_interrupt_randomness(irq);
 		__cli();
 	}
-	irq_exit(cpu, irq);
+	hardirq_exit(cpu);
 
 	/* unmasking and bottom half handling is done magically for us. */
 }
@@ -448,10 +446,23 @@
 		action = local_irq_action[irq];
 	}
 
-	irq_enter(cpu, irq);
+	/* if irq == 0, then the interrupt has already been cleared */
+	if ( irq == 0 ) { goto end; }
+	/* if action == NULL, then we do have a handler for the irq */
+	if ( action == NULL ) { goto no_handler; }
+	
+	hardirq_enter(cpu);
 	kstat.irqs[0][irq + 16]++;
 	action->handler(irq, action->dev_id, regs);
-	irq_exit(cpu, irq);
+	hardirq_exit(cpu);
+	goto end;
+
+no_handler:
+	printk("No handler for local0 irq: %i\n", irq);
+
+end:	
+	return;	
+	
 }
 
 void indy_local1_irqdispatch(struct pt_regs *regs)
@@ -472,10 +483,23 @@
 		irq = lc1msk_to_irqnr[mask];
 		action = local_irq_action[irq];
 	}
-	irq_enter(cpu, irq);
+	/* if irq == 0, then the interrupt has already been cleared */
+	/* not sure if it is needed here, but it is needed for local0 */
+	if ( irq == 0 ) { goto end; }
+	/* if action == NULL, then we do have a handler for the irq */
+	if ( action == NULL ) { goto no_handler; }
+	
+	hardirq_enter(cpu);
 	kstat.irqs[0][irq + 24]++;
 	action->handler(irq, action->dev_id, regs);
-	irq_exit(cpu, irq);
+	hardirq_exit(cpu);
+	goto end;
+	
+no_handler:
+	printk("No handler for local1 irq: %i\n", irq);
+
+end:	
+	return;	
 }
 
 void indy_buserror_irq(struct pt_regs *regs)
@@ -483,13 +507,13 @@
 	int cpu = smp_processor_id();
 	int irq = 6;
 
-	irq_enter(cpu, irq);
+	hardirq_enter(cpu);
 	kstat.irqs[0][irq]++;
 	printk("Got a bus error IRQ, shouldn't happen yet\n");
 	show_regs(regs);
 	printk("Spinning...\n");
 	while(1);
-	irq_exit(cpu, irq);
+	hardirq_exit(cpu);
 }
 
 /* Misc. crap just to keep the kernel linking... */
@@ -506,9 +530,6 @@
 __initfunc(void sgint_init(void))
 {
 	int i;
-#ifdef CONFIG_REMOTE_DEBUG
-	char *ctype;
-#endif
 
 	sgi_i2regs = (struct sgi_int2_regs *) (KSEG1 + SGI_INT2_BASE);
 	sgi_i3regs = (struct sgi_int3_regs *) (KSEG1 + SGI_INT3_BASE);
@@ -563,9 +584,16 @@
 		}
 	}
 
-	ioc_icontrol = &sgi_i3regs->ints;
-	ioc_timers = &sgi_i3regs->timers;
-	ioc_tclear = &sgi_i3regs->tclear;
+	/* Indy uses an INT3, Indigo2 uses an INT2 */
+	if (sgi_guiness) {
+		ioc_icontrol = &sgi_i3regs->ints;
+		ioc_timers = &sgi_i3regs->timers;
+		ioc_tclear = &sgi_i3regs->tclear;
+	} else {
+		ioc_icontrol = &sgi_i2regs->ints;
+		ioc_timers = &sgi_i2regs->timers;
+		ioc_tclear = &sgi_i2regs->tclear;
+	}
 
 	/* Mask out all interrupts. */
 	ioc_icontrol->imask0 = 0;
@@ -575,28 +603,4 @@
 
 	/* Now safe to set the exception vector. */
 	set_except_vector(0, indyIRQ);
-
-#ifdef CONFIG_REMOTE_DEBUG
-	ctype = prom_getcmdline();
-	for(i = 0; i < strlen(ctype); i++) {
-		if(ctype[i]=='k' && ctype[i+1]=='g' &&
-		   ctype[i+2]=='d' && ctype[i+3]=='b' &&
-		   ctype[i+4]=='=' && ctype[i+5]=='t' &&
-		   ctype[i+6]=='t' && ctype[i+7]=='y' &&
-		   ctype[i+8]=='d' &&
-		   (ctype[i+9] == '1' || ctype[i+9] == '2')) {
-			printk("KGDB: Using serial line /dev/ttyd%d for "
-			       "session\n", (ctype[i+9] - '0'));
-				if(ctype[i+9]=='1')
-					rs_kgdb_hook(1);
-				else if(ctype[i+9]=='2')
-					rs_kgdb_hook(0);
-				else {
-					printk("KGDB: whoops bogon tty line "
-					       "requested, disabling session\n");
-				}
-
-		}
-	}
-#endif
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/indy_mc.c linux/arch/mips/sgi/kernel/indy_mc.c
--- v2.3.8/linux/arch/mips/sgi/kernel/indy_mc.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/kernel/indy_mc.c	Fri Jun 25 17:40:13 1999
@@ -2,8 +2,9 @@
  * indy_mc.c: Routines for manipulating the INDY memory controller.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes
  *
- * $Id: indy_mc.c,v 1.3 1998/04/25 15:43:32 ralf Exp $
+ * $Id: indy_mc.c,v 1.4 1999/05/07 22:34:32 ulfc Exp $
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -150,6 +151,8 @@
 			tmpreg |= SGIMC_GIOPARM_PLINEEXP0; /* exp[01] pipelined */
 			tmpreg |= SGIMC_GIOPARM_PLINEEXP1;
 			tmpreg |= SGIMC_GIOPARM_MASTEREISA;/* EISA masters */
+			/* someone forgot this poor little guy... */
+			tmpreg |= SGIMC_GIOPARM_GFX64; 	/* GFX at 64 bits */
 		}
 	}
 	mcmisc_regs->gioparm = tmpreg; /* poof */
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c
--- v2.3.8/linux/arch/mips/sgi/kernel/indy_sc.c	Mon Oct 26 09:57:55 1998
+++ linux/arch/mips/sgi/kernel/indy_sc.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: indy_sc.c,v 1.9 1998/08/17 12:14:55 ralf Exp $
+/* $Id: indy_sc.c,v 1.9 1999/05/12 21:57:49 ulfc Exp $
  *
  * indy_sc.c: Indy cache managment functions.
  *
@@ -38,6 +38,7 @@
 		.set	noreorder
 		.set	mips3
 		.set	noat
+		mfc0	$2, $12
 		li	$1, 0x80	# Go 64 bit
 		mtc0	$1, $12
 
@@ -50,12 +51,12 @@
 		bne	%0, %1, 1b
 		daddu	%0, 32
 
-		mtc0	$0, $12		# Back to 32 bit
+		mtc0	$2, $12		# Back to 32 bit
 		nop; nop; nop; nop;
 		.set mips0
 		.set reorder"
-		: "=r" (first), "=r" (last)
-		: "0" (first), "1" (last)
+		: /* no output */
+		: "r" (first), "r" (last)
 		: "$1");
 }
 
@@ -69,7 +70,10 @@
 #endif
 	/* Which lines to flush?  */
 	first_line = SC_INDEX(addr);
-	last_line = SC_INDEX(SC_ROUND(addr + size));
+	if (size <= SC_LINE)
+		last_line = SC_INDEX(addr);
+	else
+		last_line = SC_INDEX(addr + size - 1);
 
 	__save_and_cli(flags);
 	if (first_line <= last_line) {
@@ -80,8 +84,8 @@
 	/* Cache index wrap around.  Due to the way the buddy system works
 	   this case should not happen.  We're prepared to handle it,
 	   though. */
-	indy_sc_wipe(last_line, SC_SIZE);
-	indy_sc_wipe(0, first_line);
+	indy_sc_wipe(first_line, SC_SIZE - SC_LINE);
+	indy_sc_wipe(0, last_line);
 out:
 	__restore_flags(flags);
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/indy_timer.c linux/arch/mips/sgi/kernel/indy_timer.c
--- v2.3.8/linux/arch/mips/sgi/kernel/indy_timer.c	Thu Mar 11 23:25:24 1999
+++ linux/arch/mips/sgi/kernel/indy_timer.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: indy_timer.c,v 1.9 1998/06/25 20:15:02 ralf Exp $
+/* $Id: indy_timer.c,v 1.12 1999/06/13 16:30:36 ralf Exp $
  *
  * indy_timer.c: Setting up the clock on the INDY 8254 controller.
  *
@@ -262,12 +262,12 @@
 	int cpu = smp_processor_id();
 	int irq = 4;
 
-	irq_enter(cpu, irq);
+	hardirq_enter(cpu);
 	kstat.irqs[0][irq]++;
 	printk("indy_8254timer_irq: Whoops, should not have gotten this IRQ\n");
 	prom_getchar();
 	prom_imode();
-	irq_exit(cpu, irq);
+	hardirq_exit(cpu);
 }
 
 void do_gettimeofday(struct timeval *tv)
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/promcon.c linux/arch/mips/sgi/kernel/promcon.c
--- v2.3.8/linux/arch/mips/sgi/kernel/promcon.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/sgi/kernel/promcon.c	Fri Jun 25 17:40:13 1999
@@ -0,0 +1,73 @@
+/*
+ * Wrap-around code for a console using the
+ * SGI PROM io-routines.
+ *
+ * Copyright (c) 1999 Ulf Carlsson
+ *
+ * Derived from DECstation promcon.c
+ * Copyright (c) 1998 Harald Koerfgen 
+ */
+
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+
+#include <asm/sgialib.h>
+
+static void prom_console_write(struct console *co, const char *s,
+			       unsigned count)
+{
+    unsigned i;
+
+    /*
+     *    Now, do each character
+     */
+    for (i = 0; i < count; i++) {
+	if (*s == 10)
+	    prom_printf("%c", 13);
+	prom_printf("%c", *s++);
+    }
+}
+
+static int prom_console_wait_key(struct console *co)
+{
+    return prom_getchar();
+}
+
+__initfunc(static int prom_console_setup(struct console *co, char *options))
+{
+    return 0;
+}
+
+static kdev_t prom_console_device(struct console *c)
+{
+    return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+static struct console sercons =
+{
+    "ttyS",
+    prom_console_write,
+    NULL,
+    prom_console_device,
+    prom_console_wait_key,
+    NULL,
+    prom_console_setup,
+    CON_PRINTBUFFER,
+    -1,
+    0,
+    NULL
+};
+
+/*
+ *    Register console.
+ */
+
+__initfunc(long sgi_prom_console_init(long kmem_start, long kmem_end))
+{
+    register_console(&sercons);
+    return kmem_start;
+}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/reset.c linux/arch/mips/sgi/kernel/reset.c
--- v2.3.8/linux/arch/mips/sgi/kernel/reset.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/kernel/reset.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: reset.c,v 1.6 1998/07/09 19:57:47 ralf Exp $
+/* $Id: reset.c,v 1.6 1999/04/10 12:21:30 ulfc Exp $
  *
  * Reset a SGI.
  *
@@ -33,7 +33,9 @@
 #define POWERDOWN_FREQ		(HZ / 4)
 #define PANIC_FREQ		(HZ / 8)
 
-static struct timer_list power_timer, blink_timer, debounce_timer;
+static unsigned char sgi_volume;
+
+static struct timer_list power_timer, blink_timer, debounce_timer, volume_timer;
 static int shuting_down, has_paniced;
 
 static void sgi_machine_restart(char *command) __attribute__((noreturn));
@@ -129,14 +131,50 @@
 	add_timer(&power_timer);
 }
 
-static inline void volume_up_button(void)
+void inline sgi_volume_set(unsigned char volume)
+{
+	sgi_volume = volume;
+
+	hpc3c0->pbus_extregs[2][0] = sgi_volume;
+	hpc3c0->pbus_extregs[2][1] = sgi_volume;
+}
+
+void inline sgi_volume_get(unsigned char *volume)
 {
-	/* Later when we have sound support ... */
+	*volume = sgi_volume;
 }
 
-static inline void volume_down_button(void)
+static inline void volume_up_button(unsigned long data)
 {
-	/* Later when we have sound support ... */
+	del_timer(&volume_timer);
+
+	if (sgi_volume < 0xff)
+		sgi_volume++;
+
+	hpc3c0->pbus_extregs[2][0] = sgi_volume;
+	hpc3c0->pbus_extregs[2][1] = sgi_volume;
+
+	if (ioc_icontrol->istat1 & 2) {
+		volume_timer.expires = jiffies + 1;
+		add_timer(&volume_timer);
+	}
+
+}
+
+static inline void volume_down_button(unsigned long data)
+{
+	del_timer(&volume_timer);
+
+	if (sgi_volume > 0)
+		sgi_volume--;
+
+	hpc3c0->pbus_extregs[2][0] = sgi_volume;
+	hpc3c0->pbus_extregs[2][1] = sgi_volume;
+
+	if (ioc_icontrol->istat1 & 2) {
+		volume_timer.expires = jiffies + 1;
+		add_timer(&volume_timer);
+	}
 }
 
 static void panel_int(int irq, void *dev_id, struct pt_regs *regs)
@@ -156,10 +194,18 @@
 
 	if (!(buttons & 2))		/* Power button was pressed */
 		power_button();
-	if (!(buttons & 0x40))		/* Volume up button was pressed */
-		volume_up_button();
-	if (!(buttons & 0x10))		/* Volume down button was pressed */
-		volume_down_button();
+	if (!(buttons & 0x40)) {	/* Volume up button was pressed */
+		init_timer(&volume_timer);
+		volume_timer.function = volume_up_button;
+		volume_timer.expires = jiffies + 1;
+		add_timer(&volume_timer);
+	}
+	if (!(buttons & 0x10)) {	/* Volume down button was pressed */
+		init_timer(&volume_timer);
+		volume_timer.function = volume_down_button;
+		volume_timer.expires = jiffies + 1;
+		add_timer(&volume_timer);
+	}
 }
 
 static int panic_event(struct notifier_block *this, unsigned long event,
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c
--- v2.3.8/linux/arch/mips/sgi/kernel/setup.c	Mon Oct 26 09:57:55 1998
+++ linux/arch/mips/sgi/kernel/setup.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.13 1998/09/16 22:50:46 ralf Exp $
+/* $Id: setup.c,v 1.24 1999/06/12 17:26:15 ulfc Exp $
  *
  * setup.c: SGI specific setup, including init of the feature struct.
  *
@@ -14,6 +14,7 @@
 #include <linux/console.h>
 #include <linux/sched.h>
 #include <linux/mc146818rtc.h>
+#include <linux/pc_keyb.h>
 
 #include <asm/addrspace.h>
 #include <asm/bcache.h>
@@ -25,16 +26,55 @@
 #include <asm/sgimc.h>
 #include <asm/sgihpc.h>
 #include <asm/sgint23.h>
+#include <asm/gdb-stub.h>
 
-extern int serial_console; /* in sgiserial.c  */
+#ifdef CONFIG_REMOTE_DEBUG
+extern void rs_kgdb_hook(int);
+extern void breakpoint(void);
+#endif
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+#endif
 
 extern struct rtc_ops indy_rtc_ops;
 void indy_reboot_setup(void);
+void sgi_volume_set(unsigned char);
 
-static volatile struct hpc_keyb *sgi_kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
+static int remote_debug = 0;
+
+#define sgi_kh ((struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64))
 
 #define KBD_STAT_IBF		0x02	/* Keyboard input buffer full */
 
+static void sgi_request_region(void)
+{
+	/* No I/O ports are being used on the Indy.  */
+}
+
+static int sgi_request_irq(void (*handler)(int, void *, struct pt_regs *))
+{
+	/* Dirty hack, this get's called as a callback from the keyboard
+	   driver.  We piggyback the initialization of the front panel
+	   button handling on it even though they're technically not
+	   related with the keyboard driver in any way.  Doing it from
+	   indy_setup wouldn't work since kmalloc isn't initialized yet.  */
+	indy_reboot_setup();
+
+	return request_irq(SGI_KEYBOARD_IRQ, handler, 0, "keyboard", NULL);
+}
+
+static int sgi_aux_request_irq(void (*handler)(int, void *, struct pt_regs *))
+{
+	/* Nothing to do, interrupt is shared with the keyboard hw  */
+	return 0;
+}
+
+static void sgi_aux_free_irq(void)
+{
+	/* Nothing to do, interrupt is shared with the keyboard hw  */
+}
+
 static unsigned char sgi_read_input(void)
 {
 	return sgi_kh->data;
@@ -65,27 +105,28 @@
 	return sgi_kh->command;
 }
 
-__initfunc(static void sgi_keyboard_setup(void))
-{
-	kbd_read_input = sgi_read_input;
-	kbd_write_output = sgi_write_output;
-	kbd_write_command = sgi_write_command;
-	kbd_read_status = sgi_read_status;
-
-	request_irq(SGI_KEYBOARD_IRQ, keyboard_interrupt,
-	            0, "keyboard", NULL);
-
-	/* Dirty hack, this get's called as a callback from the keyboard
-	   driver.  We piggyback the initialization of the front panel
-	   button handling on it even though they're technically not
-	   related with the keyboard driver in any way.  Doing it from
-	   indy_setup wouldn't work since kmalloc isn't initialized yet.  */
-	indy_reboot_setup();
-}
+struct kbd_ops sgi_kbd_ops = {
+	sgi_request_region,
+	sgi_request_irq,
+
+	sgi_aux_request_irq,
+	sgi_aux_free_irq,
+
+	sgi_read_input,
+	sgi_write_output,
+	sgi_write_command,
+	sgi_read_status
+};
 
 __initfunc(static void sgi_irq_setup(void))
 {
 	sgint_init();
+
+#ifdef CONFIG_REMOTE_DEBUG
+	if (remote_debug)
+		set_debug_traps();
+	breakpoint(); /* you may move this line to whereever you want :-) */
+#endif
 }
 
 __initfunc(void sgi_setup(void))
@@ -93,9 +134,12 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 	char *ctype;
 #endif
+#ifdef CONFIG_REMOTE_DEBUG
+	char *kgdb_ttyd;
+#endif
+
 
 	irq_setup = sgi_irq_setup;
-	keyboard_setup = sgi_keyboard_setup;
 
 	/* Init the INDY HPC I/O controller.  Need to call this before
 	 * fucking with the memory controller because it needs to know the
@@ -115,23 +159,55 @@
 	 * line and "d2" for the second serial line.
 	 */
 	ctype = prom_getenv("console");
-	serial_console = 0;
 	if(*ctype == 'd') {
 		if(*(ctype+1)=='2')
-			serial_console = 1;
+			console_setup ("ttyS1", NULL);
 		else
-			serial_console = 2;
-		if(!serial_console) {
-			prom_printf("Weird console env setting %s\n", ctype);
-			prom_printf("Press a key to reboot.\n");
-			prom_getchar();
-			prom_imode();
-		}
+			console_setup ("ttyS0", NULL);
+	}
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+	kgdb_ttyd = prom_getcmdline();
+	if ((kgdb_ttyd = strstr(kgdb_ttyd, "kgdb=ttyd")) != NULL) {
+		int line;
+		kgdb_ttyd += strlen("kgdb=ttyd");
+		if (*kgdb_ttyd != '1' && *kgdb_ttyd != '2')
+			printk("KGDB: Uknown serial line /dev/ttyd%c, "
+			       "falling back to /dev/ttyd1\n", *kgdb_ttyd);
+		line = *kgdb_ttyd == '2' ? 0 : 1;
+		printk("KGDB: Using serial line /dev/ttyd%d for session\n",
+		       line ? 1 : 2);
+		rs_kgdb_hook(line);
+
+		prom_printf("KGDB: Using serial line /dev/ttyd%d for session, "
+			    "please connect your debugger\n", line ? 1 : 2);
+
+		remote_debug = 1;
+		/* Breakpoints and stuff are in sgi_irq_setup() */
 	}
 #endif
 
+#ifdef CONFIG_SGI_PROM_CONSOLE
+	console_setup("ttyS0", NULL);
+#endif
+	  
+	sgi_volume_set(simple_strtoul(prom_getenv("volume"), NULL, 10));
+
 #ifdef CONFIG_VT
+#ifdef CONFIG_SGI_NEWPORT_CONSOLE
 	conswitchp = &newport_con;
+#else
+	conswitchp = &dummy_con;
+#endif
 #endif
+
 	rtc_ops = &indy_rtc_ops;
+	kbd_ops = &sgi_kbd_ops;
+#ifdef CONFIG_PSMOUSE
+	aux_device_present = 0xaa;
+#endif
+#ifdef CONFIG_VIDEO_VINO
+	init_vino();
+#endif
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/system.c linux/arch/mips/sgi/kernel/system.c
--- v2.3.8/linux/arch/mips/sgi/kernel/system.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/kernel/system.c	Fri Jun 25 17:40:13 1999
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: system.c,v 1.4 1998/03/27 08:53:45 ralf Exp $
+ * $Id: system.c,v 1.7 1998/10/18 22:55:34 tsbogend Exp $
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -21,28 +21,6 @@
 	int type;
 };
 
-static struct smatch sgi_mtable[] = {
-	{ "SGI-IP4", ip4 },
-	{ "SGI-IP5", ip5 },
-	{ "SGI-IP6", ip6 },
-	{ "SGI-IP7", ip7 },
-	{ "SGI-IP9", ip9 },
-	{ "SGI-IP12", ip12 },
-	{ "SGI-IP15", ip15 },
-	{ "SGI-IP17", ip17 },
-	{ "SGI-IP19", ip19 },
-	{ "SGI-IP20", ip20 },
-	{ "SGI-IP21", ip21 },
-	{ "SGI-IP22", ip22 },
-	{ "SGI-IP25", ip25 },
-	{ "SGI-IP26", ip26 },
-	{ "SGI-IP28", ip28 },
-	{ "SGI-IP30", ip30 },
-	{ "SGI-IP32", ip32 }
-};
-
-#define NUM_MACHS 17 /* for now */
-
 static struct smatch sgi_cputable[] = {
 	{ "MIPS-R2000", CPU_R2000 },
 	{ "MIPS-R3000", CPU_R3000 },
@@ -57,28 +35,13 @@
 
 #define NUM_CPUS 9 /* for now */
 
-__initfunc(static enum sgi_mach string_to_mach(char *s))
-{
-	int i;
-
-	for(i = 0; i < NUM_MACHS; i++) {
-		if(!strcmp(s, sgi_mtable[i].name))
-			return (enum sgi_mach) sgi_mtable[i].type;
-	}
-	prom_printf("\nYeee, could not determine SGI architecture type <%s>\n", s);
-	prom_printf("press a key to reboot\n");
-	prom_getchar();
-	romvec->imode();
-	return (enum sgi_mach) 0;
-}
-
 __initfunc(static int string_to_cpu(char *s))
 {
 	int i;
 
 	for(i = 0; i < NUM_CPUS; i++) {
 		if(!strcmp(s, sgi_cputable[i].name))
-			return sgi_mtable[i].type;
+			return sgi_cputable[i].type;
 	}
 	prom_printf("\nYeee, could not determine MIPS cpu type <%s>\n", s);
 	prom_printf("press a key to reboot\n");
@@ -101,8 +64,6 @@
 	 * have here.
 	 */
 	p = prom_getchild(PROM_NULL_COMPONENT);
-	printk("ARCH: %s\n", p->iname);
-	sgimach = string_to_mach(p->iname);
 
 	/* Now scan for cpu(s). */
 	toplev = p = prom_getchild(p);
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/kernel/time.c linux/arch/mips/sgi/kernel/time.c
--- v2.3.8/linux/arch/mips/sgi/kernel/time.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/kernel/time.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.2 1998/03/27 08:53:45 ralf Exp $
+/* $Id: time.c,v 1.2 1998/04/05 11:24:00 ralf Exp $
  * time.c: Generic SGI time_init() code, this will dispatch to the
  *         appropriate per-architecture time/counter init code.
  *
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/Makefile linux/arch/mips/sgi/prom/Makefile
--- v2.3.8/linux/arch/mips/sgi/prom/Makefile	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/Makefile	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-# $Id: Makefile,v 1.1.1.1 1997/06/01 03:16:40 ralf Exp $
-# Makefile for the SGI arcs prom monitor library routines
-# under Linux.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-OBJS  = console.o init.o printf.o memory.o tree.o tags.o env.o \
-      cmdline.o misc.o time.o file.o
-
-all: promlib.a
-
-promlib.a: $(OBJS)
-	$(AR) rcs promlib.a $(OBJS)
-	sync
-
-dep:
-	$(CPP) -M *.c > .depend
-
-include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/cmdline.c linux/arch/mips/sgi/prom/cmdline.c
--- v2.3.8/linux/arch/mips/sgi/prom/cmdline.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/cmdline.c	Wed Dec 31 16:00:00 1969
@@ -1,64 +0,0 @@
-/*
- * cmdline.c: Kernel command line creation using ARCS argc/argv.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: cmdline.c,v 1.3 1998/03/27 08:53:46 ralf Exp $
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/sgialib.h>
-#include <asm/bootinfo.h>
-
-/* #define DEBUG_CMDLINE */
-
-extern char arcs_cmdline[CL_SIZE];
-
-__initfunc(char *prom_getcmdline(void))
-{
-	return &(arcs_cmdline[0]);
-}
-
-static char *ignored[] = {
-	"ConsoleIn=",
-	"ConsoleOut=",
-	"SystemPartition=",
-	"OSLoader=",
-	"OSLoadPartition=",
-	"OSLoadFilename="
-};
-#define NENTS(foo) ((sizeof((foo)) / (sizeof((foo[0])))))
-
-__initfunc(void prom_init_cmdline(void))
-{
-	char *cp;
-	int actr, i;
-
-	actr = 1; /* Always ignore argv[0] */
-
-	cp = &(arcs_cmdline[0]);
-	while(actr < prom_argc) {
-		for(i = 0; i < NENTS(ignored); i++) {
-			int len = strlen(ignored[i]);
-
-			if(!strncmp(prom_argv[actr], ignored[i], len))
-				goto pic_cont;
-		}
-		/* Ok, we want it. */
-		strcpy(cp, prom_argv[actr]);
-		cp += strlen(prom_argv[actr]);
-		*cp++ = ' ';
-
-	pic_cont:
-		actr++;
-	}
-	if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
-		--cp;
-	*cp = '\0';
-
-#ifdef DEBUG_CMDLINE
-	prom_printf("prom_init_cmdline: %s\n", &(arcs_cmdline[0]));
-#endif
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/console.c linux/arch/mips/sgi/prom/console.c
--- v2.3.8/linux/arch/mips/sgi/prom/console.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/console.c	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-/*
- * console.c: SGI arcs console code.
- *
- * Copyright (C) 1996 David S. Miller (dm@sgi.com)
- *
- * $Id: console.c,v 1.2 1998/03/27 08:53:46 ralf Exp $
- */
-#include <linux/init.h>
-#include <asm/sgialib.h>
-
-__initfunc(void prom_putchar(char c))
-{
-	long cnt;
-	char it = c;
-
-	romvec->write(1, &it, 1, &cnt);
-}
-
-__initfunc(char prom_getchar(void))
-{
-	long cnt;
-	char c;
-
-	romvec->read(0, &c, 1, &cnt);
-	return c;
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/env.c linux/arch/mips/sgi/prom/env.c
--- v2.3.8/linux/arch/mips/sgi/prom/env.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/env.c	Wed Dec 31 16:00:00 1969
@@ -1,22 +0,0 @@
-/*
- * env.c: ARCS environment variable routines.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: env.c,v 1.2 1998/03/27 08:53:46 ralf Exp $
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/sgialib.h>
-
-__initfunc(char *prom_getenv(char *name))
-{
-	return romvec->get_evar(name);
-}
-
-__initfunc(long prom_setenv(char *name, char *value))
-{
-	return romvec->set_evar(name, value);
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/file.c linux/arch/mips/sgi/prom/file.c
--- v2.3.8/linux/arch/mips/sgi/prom/file.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/file.c	Wed Dec 31 16:00:00 1969
@@ -1,59 +0,0 @@
-/*
- * file.c: ARCS firmware interface to files.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: file.c,v 1.2 1998/03/27 08:53:47 ralf Exp $
- */
-#include <linux/init.h>
-#include <asm/sgialib.h>
-
-__initfunc(long prom_getvdirent(unsigned long fd, struct linux_vdirent *ent, unsigned long num, unsigned long *cnt))
-{
-	return romvec->get_vdirent(fd, ent, num, cnt);
-}
-
-__initfunc(long prom_open(char *name, enum linux_omode md, unsigned long *fd))
-{
-	return romvec->open(name, md, fd);
-}
-
-__initfunc(long prom_close(unsigned long fd))
-{
-	return romvec->close(fd);
-}
-
-__initfunc(long prom_read(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt))
-{
-	return romvec->read(fd, buf, num, cnt);
-}
-
-__initfunc(long prom_getrstatus(unsigned long fd))
-{
-	return romvec->get_rstatus(fd);
-}
-
-__initfunc(long prom_write(unsigned long fd, void *buf, unsigned long num, unsigned long *cnt))
-{
-	return romvec->write(fd, buf, num, cnt);
-}
-
-__initfunc(long prom_seek(unsigned long fd, struct linux_bigint *off, enum linux_seekmode sm))
-{
-	return romvec->seek(fd, off, sm);
-}
-
-__initfunc(long prom_mount(char *name, enum linux_mountops op))
-{
-	return romvec->mount(name, op);
-}
-
-__initfunc(long prom_getfinfo(unsigned long fd, struct linux_finfo *buf))
-{
-	return romvec->get_finfo(fd, buf);
-}
-
-__initfunc(long prom_setfinfo(unsigned long fd, unsigned long flags, unsigned long msk))
-{
-	return romvec->set_finfo(fd, flags, msk);
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/init.c linux/arch/mips/sgi/prom/init.c
--- v2.3.8/linux/arch/mips/sgi/prom/init.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/init.c	Wed Dec 31 16:00:00 1969
@@ -1,61 +0,0 @@
-/*
- * init.c: PROM library initialisation code.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: init.c,v 1.2 1998/03/27 08:53:47 ralf Exp $
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/sgialib.h>
-
-/* #define DEBUG_PROM_INIT */
-
-/* Master romvec interface. */
-struct linux_romvec *romvec;
-struct linux_promblock *sgi_pblock;
-int prom_argc;
-char **prom_argv, **prom_envp;
-unsigned short prom_vers, prom_rev;
-
-extern void prom_testtree(void);
-
-__initfunc(int prom_init(int argc, char **argv, char **envp))
-{
-	struct linux_promblock *pb;
-
-	romvec = ROMVECTOR;
-	pb = sgi_pblock = PROMBLOCK;
-	prom_argc = argc;
-	prom_argv = argv;
-	prom_envp = envp;
-
-	if(pb->magic != 0x53435241) {
-		prom_printf("Aieee, bad prom vector magic %08lx\n", pb->magic);
-		while(1)
-			;
-	}
-
-	prom_init_cmdline();
-
-	prom_vers = pb->ver;
-	prom_rev = pb->rev;
-	printk("PROMLIB: SGI ARCS firmware Version %d Revision %d\n",
-		    prom_vers, prom_rev);
-	prom_meminit();
-	prom_setup_archtags();
-
-#if 0
-	prom_testtree();
-#endif
-
-#ifdef DEBUG_PROM_INIT
-	{
-		prom_printf("Press a key to reboot\n");
-		(void) prom_getchar();
-		romvec->imode();
-	}
-#endif
-	return 0;
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/memory.c linux/arch/mips/sgi/prom/memory.c
--- v2.3.8/linux/arch/mips/sgi/prom/memory.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/memory.c	Wed Dec 31 16:00:00 1969
@@ -1,131 +0,0 @@
-/*
- * memory.c: PROM library functions for acquiring/using memory descriptors
- *           given to us from the ARCS firmware.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: memory.c,v 1.2 1998/03/27 08:53:47 ralf Exp $
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-
-#include <asm/sgialib.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/bootinfo.h>
-
-/* #define DEBUG */
-
-__initfunc(struct linux_mdesc *prom_getmdesc(struct linux_mdesc *curr))
-{
-	return romvec->get_mdesc(curr);
-}
-
-#ifdef DEBUG /* convenient for debugging */
-static char *mtypes[8] = {
-	"Exception Block",
-	"ARCS Romvec Page",
-	"Free/Contig RAM",
-	"Generic Free RAM",
-	"Bad Memory",
-	"Standlong Program Pages",
-	"ARCS Temp Storage Area",
-	"ARCS Permanent Storage Area"
-};
-#endif
-
-static struct prom_pmemblock prom_pblocks[PROM_MAX_PMEMBLOCKS];
-
-__initfunc(struct prom_pmemblock *prom_getpblock_array(void))
-{
-	return &prom_pblocks[0];
-}
-
-__initfunc(static void prom_setup_memupper(void))
-{
-	struct prom_pmemblock *p, *highest;
-
-	for(p = prom_getpblock_array(), highest = 0; p->size != 0; p++) {
-		if(p->base == 0xdeadbeef)
-			prom_printf("WHEEE, bogus pmemblock\n");
-		if(!highest || p->base > highest->base)
-			highest = p;
-	}
-	mips_memory_upper = highest->base + highest->size;
-#ifdef DEBUG
-	prom_printf("prom_setup_memupper: mips_memory_upper = %08lx\n",
-		    mips_memory_upper);
-#endif
-}
-
-__initfunc(void prom_meminit(void))
-{
-	struct linux_mdesc *p;
-	int totram;
-	int i = 0;
-
-	p = prom_getmdesc(PROM_NULL_MDESC);
-#ifdef DEBUG
-	prom_printf("ARCS MEMORY DESCRIPTOR dump:\n");
-	while(p) {
-		prom_printf("[%d,%p]: base<%08lx> pages<%08lx> type<%s>\n",
-			    i, p, p->base, p->pages, mtypes[p->type]);
-		p = prom_getmdesc(p);
-		i++;
-	}
-#endif
-	p = prom_getmdesc(PROM_NULL_MDESC);
-	totram = 0;
-	i = 0;
-	while(p) {
-		if(p->type == free || p->type == fcontig) {
-			prom_pblocks[i].base =
-				((p->base<<PAGE_SHIFT) + 0x80000000);
-			prom_pblocks[i].size = p->pages << PAGE_SHIFT;
-			totram += prom_pblocks[i].size;
-#ifdef DEBUG
-			prom_printf("free_chunk[%d]: base=%08lx size=%d\n",
-				    i, prom_pblocks[i].base,
-				    prom_pblocks[i].size);
-#endif
-			i++;
-		}
-		p = prom_getmdesc(p);
-	}
-	prom_pblocks[i].base = 0xdeadbeef;
-	prom_pblocks[i].size = 0; /* indicates last elem. of array */
-	printk("PROMLIB: Total free ram %d bytes (%dK,%dMB)\n",
-		    totram, (totram/1024), (totram/1024/1024));
-
-	/* Setup upper physical memory bound. */
-	prom_setup_memupper();
-}
-
-/* Called from mem_init() to fixup the mem_map page settings. */
-__initfunc(void prom_fixup_mem_map(unsigned long start, unsigned long end))
-{
-	struct prom_pmemblock *p;
-	int i, nents;
-
-	/* Determine number of pblockarray entries. */
-	p = prom_getpblock_array();
-	for(i = 0; p[i].size; i++)
-		;
-	nents = i;
-	while(start < end) {
-		for(i = 0; i < nents; i++) {
-			if((start >= (p[i].base)) &&
-			   (start < (p[i].base + p[i].size))) {
-				start = p[i].base + p[i].size;
-				start &= PAGE_MASK;
-				continue;
-			}
-		}
-		set_bit(PG_reserved, &mem_map[MAP_NR(start)].flags);
-		start += PAGE_SIZE;
-	}
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/misc.c linux/arch/mips/sgi/prom/misc.c
--- v2.3.8/linux/arch/mips/sgi/prom/misc.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/misc.c	Wed Dec 31 16:00:00 1969
@@ -1,84 +0,0 @@
-/* $Id: misc.c,v 1.6 1998/07/08 15:59:13 ralf Exp $
- *
- * misc.c: Miscellaneous ARCS PROM routines.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- */
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/bcache.h>
-#include <asm/sgialib.h>
-#include <asm/bootinfo.h>
-#include <asm/system.h>
-
-extern unsigned long mips_cputype;
-extern void *sgiwd93_host;
-extern void reset_wd33c93(void *instance);
-
-void prom_halt(void)
-{
-	bcops->bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	romvec->halt();
-}
-
-void prom_powerdown(void)
-{
-	bcops->bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	romvec->pdown();
-}
-
-/* XXX is this a soft reset basically? XXX */
-void prom_restart(void)
-{
-	bcops->bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	romvec->restart();
-}
-
-void prom_reboot(void)
-{
-	bcops->bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	romvec->reboot();
-}
-
-void prom_imode(void)
-{
-	bcops->bc_disable();
-	cli();
-#if CONFIG_SCSI_SGIWD93
-	reset_wd33c93(sgiwd93_host);
-#endif
-	romvec->imode();
-}
-
-long prom_cfgsave(void)
-{
-	return romvec->cfg_save();
-}
-
-struct linux_sysid *prom_getsysid(void)
-{
-	return romvec->get_sysid();
-}
-
-__initfunc(void prom_cacheflush(void))
-{
-	romvec->cache_flush();
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/printf.c linux/arch/mips/sgi/prom/printf.c
--- v2.3.8/linux/arch/mips/sgi/prom/printf.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/printf.c	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-/*
- * printf.c: Putting things on the screen using SGI arcs
- *           PROM facilities.
- *
- * Copyright (C) 1996 David S. Miller (dm@sgi.com)
- *
- * $Id: printf.c,v 1.2 1998/03/27 08:53:48 ralf Exp $
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <asm/sgialib.h>
-
-static char ppbuf[1024];
-
-__initfunc(void prom_printf(char *fmt, ...))
-{
-	va_list args;
-	char ch, *bptr;
-	int i;
-
-	va_start(args, fmt);
-	i = vsprintf(ppbuf, fmt, args);
-
-	bptr = ppbuf;
-
-	while((ch = *(bptr++)) != 0) {
-		if(ch == '\n')
-			prom_putchar('\r');
-
-		prom_putchar(ch);
-	}
-	va_end(args);
-	return;
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/salone.c linux/arch/mips/sgi/prom/salone.c
--- v2.3.8/linux/arch/mips/sgi/prom/salone.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/salone.c	Wed Dec 31 16:00:00 1969
@@ -1,25 +0,0 @@
-/*
- * salone.c: Routines to load into memory and execute stand-along
- *           program images using ARCS PROM firmware.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: salone.c,v 1.2 1998/03/27 08:53:48 ralf Exp $
- */
-#include <linux/init.h>
-#include <asm/sgialib.h>
-
-__initfunc(long prom_load(char *name, unsigned long end, unsigned long *pc, unsigned long *eaddr))
-{
-	return romvec->load(name, end, pc, eaddr);
-}
-
-__initfunc(long prom_invoke(unsigned long pc, unsigned long sp, long argc, char **argv, char **envp))
-{
-	return romvec->invoke(pc, sp, argc, argv, envp);
-}
-
-__initfunc(long prom_exec(char *name, long argc, char **argv, char **envp))
-{
-	return romvec->exec(name, argc, argv, envp);
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/tags.c linux/arch/mips/sgi/prom/tags.c
--- v2.3.8/linux/arch/mips/sgi/prom/tags.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/tags.c	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-/*
- * tags.c: Initialize the arch tags the way the MIPS kernel setup
- *         expects.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: tags.c,v 1.2 1998/03/27 08:53:48 ralf Exp $
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-#include <asm/addrspace.h>
-#include <asm/sgialib.h>
-#include <asm/bootinfo.h>
-#include <asm/sgimc.h>
-
-/* XXX This tag thing is a fucking rats nest, I'm very inclined to completely
- * XXX rework the MIPS people's multi-arch code _NOW_.
- */
-
-static unsigned long machtype_SGI_INDY = MACH_SGI_INDY;
-static unsigned long machgroup_SGI = MACH_GROUP_SGI;
-static unsigned long memlower_SGI_INDY = (KSEG0 + SGIMC_SEG0_BADDR);
-static unsigned long cputype_SGI_INDY = CPU_R4400SC;
-static unsigned long tlb_entries_SGI_INDY = 48;
-static unsigned long dummy_SGI_INDY = 0;
-static struct drive_info_struct dummy_dinfo_SGI_INDY = { { 0, }, };
-char arcs_cmdline[CL_SIZE];
-
-#define TAG(t,l)   {tag_##t,(l)} /* XXX RATS NEST CODE!!! XXX */
-#define TAGVAL(v)  (void*)&(v)   /* XXX FUCKING LOSING!!! XXX */
-
-tag_def taglist_sgi_indy[] = {
-	{TAG(machtype, ULONGSIZE), TAGVAL(machtype_SGI_INDY)},
-	{TAG(machgroup, ULONGSIZE), TAGVAL(machgroup_SGI)},
-	{TAG(memlower, ULONGSIZE), TAGVAL(memlower_SGI_INDY)},
-	{TAG(cputype, ULONGSIZE), TAGVAL(cputype_SGI_INDY)},
-	{TAG(tlb_entries, ULONGSIZE), TAGVAL(tlb_entries_SGI_INDY)},
-	{TAG(vram_base, ULONGSIZE), TAGVAL(dummy_SGI_INDY)},
-	{TAG(drive_info, DRVINFOSIZE), TAGVAL(dummy_dinfo_SGI_INDY)},
-	{TAG(mount_root_rdonly, ULONGSIZE), TAGVAL(dummy_SGI_INDY)},
-	{TAG(command_line, CL_SIZE), TAGVAL(arcs_cmdline[0])},
-	{TAG(dummy, 0), NULL}
-	/* XXX COLOSTOMY BAG!!!! XXX */
-};
-
-__initfunc(void prom_setup_archtags(void))
-{
-	tag_def *tdp = &taglist_sgi_indy[0];
-	tag *tp;
-
-	tp = (tag *) (mips_memory_upper - sizeof(tag));
-	while(tdp->t.tag != tag_dummy) {
-		unsigned long size;
-		char *d;
-
-		*tp = tdp->t;
-		size = tp->size;
-		d = (char *) tdp->d;
-		tp = (tag *)(((unsigned long)tp) - (tp->size));
-		if(size)
-			memcpy(tp, d, size);
-
-		tp--;
-		tdp++;
-	}
-	*tp = tdp->t; /* copy last dummy element over */
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/time.c linux/arch/mips/sgi/prom/time.c
--- v2.3.8/linux/arch/mips/sgi/prom/time.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/time.c	Wed Dec 31 16:00:00 1969
@@ -1,19 +0,0 @@
-/*
- * time.c: Extracting time information from ARCS prom.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: time.c,v 1.2 1998/03/27 08:53:49 ralf Exp $
- */
-#include <linux/init.h>
-#include <asm/sgialib.h>
-
-__initfunc(struct linux_tinfo *prom_gettinfo(void))
-{
-	return romvec->get_tinfo();
-}
-
-__initfunc(unsigned long prom_getrtime(void))
-{
-	return romvec->get_rtime();
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sgi/prom/tree.c linux/arch/mips/sgi/prom/tree.c
--- v2.3.8/linux/arch/mips/sgi/prom/tree.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sgi/prom/tree.c	Wed Dec 31 16:00:00 1969
@@ -1,109 +0,0 @@
-/*
- * tree.c: PROM component device tree code.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: tree.c,v 1.2 1998/03/27 08:53:49 ralf Exp $
- */
-#include <linux/init.h>
-#include <asm/sgialib.h>
-
-#define DEBUG_PROM_TREE
-
-__initfunc(pcomponent *prom_getsibling(pcomponent *this))
-{
-	if(this == PROM_NULL_COMPONENT)
-		return PROM_NULL_COMPONENT;
-	return romvec->next_component(this);
-}
-
-__initfunc(pcomponent *prom_getchild(pcomponent *this))
-{
-	return romvec->child_component(this);
-}
-
-__initfunc(pcomponent *prom_getparent(pcomponent *child))
-{
-	if(child == PROM_NULL_COMPONENT)
-		return PROM_NULL_COMPONENT;
-	return romvec->parent_component(child);
-}
-
-__initfunc(long prom_getcdata(void *buffer, pcomponent *this))
-{
-	return romvec->component_data(buffer, this);
-}
-
-__initfunc(pcomponent *prom_childadd(pcomponent *this, pcomponent *tmp, void *data))
-{
-	return romvec->child_add(this, tmp, data);
-}
-
-__initfunc(long prom_delcomponent(pcomponent *this))
-{
-	return romvec->comp_del(this);
-}
-
-__initfunc(pcomponent *prom_componentbypath(char *path))
-{
-	return romvec->component_by_path(path);
-}
-
-#ifdef DEBUG_PROM_TREE
-static char *classes[] = {
-	"system", "processor", "cache", "adapter", "controller", "peripheral",
-	"memory"
-};
-
-static char *types[] = {
-	"arc", "cpu", "fpu", "picache", "pdcache", "sicache", "sdcache", "sccache",
-	"memdev", "eisa adapter", "tc adapter", "scsi adapter", "dti adapter",
-	"multi-func adapter", "disk controller", "tp controller",
-	"cdrom controller", "worm controller", "serial controller",
-	"net controller", "display controller", "parallel controller",
-	"pointer controller", "keyboard controller", "audio controller",
-	"misc controller", "disk peripheral", "floppy peripheral",
-	"tp peripheral", "modem peripheral", "monitor peripheral",
-	"printer peripheral", "pointer peripheral", "keyboard peripheral",
-	"terminal peripheral", "line peripheral", "net peripheral",
-	"misc peripheral", "anonymous"
-};
-
-static char *iflags[] = {
-	"bogus", "read only", "removable", "console in", "console out",
-	"input", "output"
-};
-
-__initfunc(static void dump_component(pcomponent *p))
-{
-	prom_printf("[%p]:class<%s>type<%s>flags<%s>ver<%d>rev<%d>",
-		    p, classes[p->class], types[p->type],
-		    iflags[p->iflags], p->vers, p->rev);
-	prom_printf("key<%08lx>\n\tamask<%08lx>cdsize<%d>ilen<%d>iname<%s>\n",
-		    p->key, p->amask, (int)p->cdsize, (int)p->ilen, p->iname);
-}
-
-__initfunc(static void traverse(pcomponent *p, int op))
-{
-	dump_component(p);
-	if(prom_getchild(p))
-		traverse(prom_getchild(p), 1);
-	if(prom_getsibling(p) && op)
-		traverse(prom_getsibling(p), 1);
-}
-
-__initfunc(void prom_testtree(void))
-{
-	pcomponent *p;
-
-	p = prom_getchild(PROM_NULL_COMPONENT);
-	dump_component(p);
-	p = prom_getchild(p);
-	while(p) {
-		dump_component(p);
-		p = prom_getsibling(p);
-	}
-	prom_printf("press a key\n");
-	prom_getchar();
-}
-#endif
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sni/Makefile linux/arch/mips/sni/Makefile
--- v2.3.8/linux/arch/mips/sni/Makefile	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sni/Makefile	Fri Jun 25 17:40:13 1999
@@ -1,3 +1,4 @@
+# $Id: Makefile,v 1.3 1999/01/04 16:03:57 ralf Exp $
 #
 # Makefile for the SNI specific part of the kernel
 #
@@ -5,8 +6,6 @@
 # removes any old dependencies. DON'T put your own dependencies here
 # unless it's something special (ie not a .c file).
 #
-# $Id: Makefile,v 1.2 1997/12/20 13:27:14 ralf Exp $
-#
 
 .S.s:
 	$(CPP) $(CFLAGS) $< -o $*.s
@@ -15,7 +14,7 @@
 
 all: sni.o
 O_TARGET := sni.o
-O_OBJS	 := hw-access.o int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o
+O_OBJS	 := int-handler.o io.o pci.o pcimt_scache.o reset.o setup.o
 
 int-handler.o: int-handler.S
 
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sni/hw-access.c linux/arch/mips/sni/hw-access.c
--- v2.3.8/linux/arch/mips/sni/hw-access.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sni/hw-access.c	Wed Dec 31 16:00:00 1969
@@ -1,70 +0,0 @@
-/* $Id: hw-access.c,v 1.8 1998/09/16 22:50:46 ralf Exp $
- *
- * Low-level hardware access stuff for SNI RM200 PCI
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1996, 1997, 1998 by Ralf Baechle
- */
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/kbdcntrlr.h>
-#include <linux/kernel.h>
-#include <linux/linkage.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <asm/bootinfo.h>
-#include <asm/cachectl.h>
-#include <asm/dma.h>
-#include <asm/keyboard.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mc146818rtc.h>
-#include <asm/pgtable.h>
-#include <asm/sni.h>
-
-#define KBD_STAT_IBF		0x02	/* Keyboard input buffer full */
-
-static unsigned char sni_read_input(void)
-{
-	return inb(KBD_DATA_REG);
-}
-
-static void sni_write_output(unsigned char val)
-{
-	int status;
-
-	do {
-		status = inb(KBD_CNTL_REG);
-	} while (status & KBD_STAT_IBF);
-	outb(val, KBD_DATA_REG);
-}
-
-static void sni_write_command(unsigned char val)
-{
-	int status;
-
-	do {
-		status = inb(KBD_CNTL_REG);
-	} while (status & KBD_STAT_IBF);
-	outb(val, KBD_CNTL_REG);
-}
-
-static unsigned char sni_read_status(void)
-{
-	return inb(KBD_STATUS_REG);
-}
-
-__initfunc(void sni_rm200_keyboard_setup(void))
-{
-	kbd_read_input = sni_read_input;
-	kbd_write_output = sni_write_output;
-	kbd_write_command = sni_write_command;
-	kbd_read_status = sni_read_status;
-	request_irq(PCIMT_KEYBOARD_IRQ, keyboard_interrupt,
-	            0, "keyboard", NULL);
-	request_region(0x60, 16, "keyboard");
-}
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sni/int-handler.S linux/arch/mips/sni/int-handler.S
--- v2.3.8/linux/arch/mips/sni/int-handler.S	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sni/int-handler.S	Fri Jun 25 17:40:13 1999
@@ -1,17 +1,22 @@
-/* $Id: int-handler.S,v 1.4 1998/05/07 14:17:47 ralf Exp $
+/* $Id: int-handler.S,v 1.4 1999/01/04 16:03:58 ralf Exp $
  *
  * SNI RM200 PCI specific interrupt handler code.
  *
  * Copyright (C) 1994 - 1997 by Ralf Baechle
  */
 #include <asm/asm.h>
-#include <linux/config.h>
 #include <asm/mipsconfig.h>
 #include <asm/mipsregs.h>
 #include <asm/regdef.h>
 #include <asm/sni.h>
 #include <asm/stackframe.h>
 
+/* The PCI ASIC has the nasty property that it may delay writes if it is busy.
+   As a consequence from writes that have not graduated when we exit from the
+   interrupt handler we might catch a spurious interrupt.  To avoid this we
+   force the PCI ASIC to graduate all writes by executing a read from the
+   PCI bus.  */
+
 		.set	noreorder
 		.set	noat
 		.align	5
@@ -20,34 +25,38 @@
 		CLI
 		.set	at
 
-		lb	t0,led_cache
-		addiu	t0,1
-		sb	t0,led_cache
-		sb	t0,PCIMT_CSLED
+		/* Blinken light ...  */
+		lb	t0, led_cache
+		addiu	t0, 1
+		sb	t0, led_cache
+		sb	t0, PCIMT_CSLED			# write only register
 		.data
 led_cache:	.byte	0
 		.text
 
-		mfc0	t0,CP0_STATUS
-		mfc0	t1,CP0_CAUSE
-		and	t0,t1
-
-		 andi	t1,t0,0x0800			# hardware interrupt 1
-		bnez	t1,hwint1
-		 andi	t1,t0,0x4000			# hardware interrupt 4
-		bnez	t1,eth_int
-
-		 andi	t1,t0,0x1000			# hardware interrupt 2
-		bnez	t1,hwint2
-		 andi	t1,t0,0x2000			# hardware interrupt 3
-		bnez	t1,hwint3
-		 andi	t1,t0,0x8000			# hardware interrupt 5
-		bnez	t1,hwint5
-		 andi	t1,t0,0x0400			# hardware interrupt 0
-		bnez	t1,hwint0
+		mfc0	t0, CP0_STATUS
+		mfc0	t1, CP0_CAUSE
+		and	t0, t1
+
+		/* The following interrupt dispatch tests for hwint 1 /
+		   EISA bridge first such that the timer interrupt get the
+		   highest priority.  */
+		 andi	t1, t0, 0x0800			# hardware interrupt 1
+		bnez	t1, hwint1
+		 andi	t1, t0, 0x4000			# hardware interrupt 4
+		bnez	t1, hwint4
+
+		 andi	t1, t0, 0x1000			# hardware interrupt 2
+		bnez	t1, hwint2
+		 andi	t1, t0, 0x2000			# hardware interrupt 3
+		bnez	t1, hwint3
+		 andi	t1, t0, 0x8000			# hardware interrupt 5
+		bnez	t1, hwint5
+		 andi	t1, t0, 0x0400			# hardware interrupt 0
+		bnez	t1, hwint0
 		 nop
 
-		j	spurious_interrupt		# Nothing up ...
+		j	return				# spurious interrupt
 		 nop
 
  ##############################################################################
@@ -57,146 +66,61 @@
 
  /* ------------------------------------------------------------------------ */
 
-hwint1:		lbu	t0,PCIMT_CSITPEND
-
-		 andi	t1,t0,0x20
-		bnez	t1,eisa_int
-
-#ifdef CONFIG_SCSI_NCR53C8XX
-		 andi	t1,t0,0x40
-		beqz	t1,scsi_int
-#endif
-		 nop
-
-		j	spurious_interrupt
-		 nop
-
- /* ------------------------------------------------------------------------ */
-
-hwint0:		lbu	t0,PCIMT_CSITPEND
-
-		 andi	t1,t0,0x01
-		beqz	t1,int2
+/* hwint1 deals with EISA and SCSI interrupts.  */
+hwint1:		lbu	s0, PCIMT_CSITPEND
 
-go_spurious:	j	spurious_interrupt		# we got fooled
+		andi	t1, s0, 0x20
+		beqz	t1, 1f
+		 andi	s1, s0, 0x40
+		lbu	a0, PCIMT_INT_ACKNOWLEDGE	# IACK cycle
+		xori	t0, a0, 0xff
+		beqz	t0, 1f				# spurious interrupt?
 		 nop
+		jal	i8259_do_irq			# call real handler
+		 move	a1, sp
 
-eisa_int:	lui	s0,%hi(SNI_PORT_BASE)
-		li	a0,0x0f
-		sb	a0,%lo(SNI_PORT_BASE+0x20)(s0)	# poll command
-		lb	a0,%lo(SNI_PORT_BASE+0x20)(s0)	# read result
-		bgtz	a0,poll_second
-		 andi	a0,7
-		beq	a0,2,poll_second		# cascade?
-		 li	s1,1
-		/*
-		 * Acknowledge first pic
-		 */
-		lb	t2,%lo(SNI_PORT_BASE+0x21)(s0)
-		lui	s4,%hi(cache_21)
-		lb	t0,%lo(cache_21)(s4)
-		sllv	s1,s1,a0
-		or	t0,s1
-		sb	t0,%lo(cache_21)(s4)
-		sb	t0,%lo(SNI_PORT_BASE+0x21)(s0)
-		li	t2,0x20
-		sb	t2,%lo(SNI_PORT_BASE+0x20)(s0)
-		/*
-		 * Now call the real handler
-		 */
+1:		bnez	s1, 1f
+		 li	a0, PCIMT_IRQ_SCSI
 		jal	do_IRQ
-		 move	a1,sp
-		/*
-		 * Unblock first pic
-		 */
-		lbu	t1,%lo(SNI_PORT_BASE+0x21)(s0)
-		lb	t1,%lo(cache_21)(s4)
-		nor	s1,zero,s1
-		and	t1,s1
-		sb	t1,%lo(cache_21)(s4)
-		j	ret_from_irq
-		 sb	t1,%lo(SNI_PORT_BASE+0x21)(s0)
+		 move	a1, sp
 
-		/*
-		 * Cascade interrupt from second PIC
-		 */
-		.align	5
-poll_second:	li	a0,0x0f
-		sb	a0,%lo(SNI_PORT_BASE+0xa0)(s0)	# poll command
-		lb	a0,%lo(SNI_PORT_BASE+0xa0)(s0)	# read result
-		bgtz	a0,go_spurious
-		 andi	a0,7
-		/*
-		 * Acknowledge second pic
-		 */
-		lbu	t2,%lo(SNI_PORT_BASE+0xa1)(s0)
-		lui	s4,%hi(cache_A1)
-		lb	t3,%lo(cache_A1)(s4)
-		sllv	s1,s1,a0
-		or	t3,s1
-		sb	t3,%lo(cache_A1)(s4)
-		sb	t3,%lo(SNI_PORT_BASE+0xa1)(s0)
-		li	t3,0x20
-		sb	t3,%lo(SNI_PORT_BASE+0xa0)(s0)
-		sb	t3,%lo(SNI_PORT_BASE+0x20)(s0)
-		/*
-		 * Now call the real handler
-		 */
-		addiu	a0,8
-		jal	do_IRQ
-		 move	a1,sp
-		/*
-		 * Unblock second pic
-		 */
-		lb	t1,%lo(SNI_PORT_BASE+0xa1)(s0)
-		lb	t1,%lo(cache_A1)(s4)
-		subu	t0,1
-		nor	s1,zero,s1
-		and	t1,t1,s1
-		sb	t1,%lo(cache_A1)(s4)
+1:		lui	t0, %hi(PCIMT_CSITPEND)
 		j	ret_from_irq
-		 sb	t1,%lo(SNI_PORT_BASE+0xa1)(s0)
-
-/*
- * ... check if we were interrupted by the Lance ...
- */
-eth_int:	mfc0	s0,CP0_STATUS
-		ori	t0,s0,0x4000
-		xori	t0,0x4000
-		mtc0	t0,CP0_STATUS
+		 lbu	zero, %lo(PCIMT_CSITPEND)(t0)
 
-		li	a0,PCIMT_IRQ_ETHERNET
-		jal	do_IRQ
-		 move	a1,sp
+ /* ------------------------------------------------------------------------ */
 
-		mtc0	s0,CP0_STATUS
+/* hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
+   button interrupts.  */
+hwint0:		PANIC("Received int0 but no handler yet ...\n")
+1:		j	1b
+		 nop
 
-		j	ret_from_irq
+go_spurious:	j	spurious_interrupt		# we got fooled
 		 nop
 
-#ifdef CONFIG_SCSI_NCR53C8XX
+/* hwint4 is used for only the onboard PCnet 32.  */
+hwint4:		mfc0	s0, CP0_STATUS
+		ori	t0, s0, 0x4000
+		xori	t0, 0x4000
+		mtc0	t0, CP0_STATUS
 
-/*
- * ... check if we were interrupted by the NCR ...
- */
-scsi_int:	li	a0,PCIMT_IRQ_SCSI
+		li	a0, PCIMT_IRQ_ETHERNET
 		jal	do_IRQ
-		 move	a1,sp
-		j	ret_from_irq
-		 nop
-
-#endif /* CONFIG_SCSI_NCR53C8XX */
+		 move	a1, sp
 
-pci_int:	PANIC("Received PCI interrupt but no handler yet ...\n")
-1:		j	1b
-		 nop
+		mtc0	s0, CP0_STATUS
 
-int2:		PANIC("Received int2 but no handler yet ...\n")
-1:		j	1b
+		j	ret_from_irq
 		 nop
 
+/* This interrupt was used for the com1 console on the first prototypes.  */
 hwint2:		PANIC("hwint2 and no handler yet")
+
+/* hwint3 should deal with the PCI A - D interrupts.  */
 hwint3:		PANIC("hwint3 and no handler yet")
+
+/* hwint5 is the r4k count / compare interrupt  */
 hwint5:		PANIC("hwint5 and no handler yet")
 
 		END(sni_rm200_pci_handle_int)
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sni/io.c linux/arch/mips/sni/io.c
--- v2.3.8/linux/arch/mips/sni/io.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sni/io.c	Fri Jun 25 17:40:13 1999
@@ -1,11 +1,10 @@
-/*
+/* $Id: io.c,v 1.3 1999/01/04 16:03:58 ralf Exp $
+ *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
  * Low level I/O functions for SNI.
- *
- * $Id: io.c,v 1.2 1998/03/27 08:53:50 ralf Exp $
  */
 #include <linux/string.h>
 #include <asm/mipsconfig.h>
@@ -14,46 +13,42 @@
 #include <asm/spinlock.h>
 #include <asm/sni.h>
 
-unsigned char sni_map_isa_cache;
-
-#define unused __attribute__((unused))
-
-/*
- * The PCIMT_CSMAPISA is shared by all processors; we need locking.
- *
- * XXX It's legal to use all the I/O memory access functions in interrupt
- * code, so we need to use the _irq locking stuff which may result in
- * significant IRQ latencies.
- */
-static spinlock_t csmapisa_lock unused = SPIN_LOCK_UNLOCKED;
-
 /*
  * Urgs...  We only can see a 16mb window of the 4gb EISA address space
  * at PCIMT_EISA_BASE.  Maladia segmentitis ...
  *
- * XXX Check out if accessing PCIMT_CSMAPISA really is slow.
- * For now assume so.
+ * To avoid locking and all the related headacke we implement this such
+ * that accessing the bus address space nests, so we're treating this
+ * correctly even for interrupts.  This is going to suck seriously for
+ * the SMP members of the RM family.
+ *
+ * Making things worse the PCIMT_CSMAPISA register resides on the X bus with
+ * it's unbeatable 1.4 mb/s transfer rate.
  */
-static inline void update_isa_cache(unsigned long address)
+
+static inline void eisa_map(unsigned long address)
 {
 	unsigned char upper;
 
 	upper = address >> 24;
-	if (sni_map_isa_cache != upper) {
-		sni_map_isa_cache = upper;
-		*(volatile unsigned char *)PCIMT_CSMAPISA = ~upper;
-	}
+	*(volatile unsigned char *)PCIMT_CSMAPISA = ~upper;
 }
 
+#define save_eisa_map()							\
+	(*(volatile unsigned char *)PCIMT_CSMAPISA)
+#define restore_eisa_map(val)						\
+	do { (*(volatile unsigned char *)PCIMT_CSMAPISA) = val; } while(0)
+
 static unsigned char sni_readb(unsigned long addr)
 {
 	unsigned char res;
+	unsigned int save_map;
 
-	spin_lock_irq(&csmapisa_lock);
-	update_isa_cache(addr);
+	save_map = save_eisa_map();
+	eisa_map(addr);
 	addr &= 0xffffff;
 	res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
-	spin_unlock_irq(&csmapisa_lock);
+	restore_eisa_map(save_map);
 
 	return res;
 }
@@ -61,12 +56,13 @@
 static unsigned short sni_readw(unsigned long addr)
 {
 	unsigned short res;
+	unsigned int save_map;
 
-	spin_lock_irq(&csmapisa_lock);
-	update_isa_cache(addr);
+	save_map = save_eisa_map();
+	eisa_map(addr);
 	addr &= 0xffffff;
 	res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
-	spin_unlock_irq(&csmapisa_lock);
+	restore_eisa_map(save_map);
 
 	return res;
 }
@@ -74,101 +70,111 @@
 static unsigned int sni_readl(unsigned long addr)
 {
 	unsigned int res;
+	unsigned int save_map;
 
-	spin_lock_irq(&csmapisa_lock);
-	update_isa_cache(addr);
+	save_map = save_eisa_map();
+	eisa_map(addr);
 	addr &= 0xffffff;
 	res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
-	spin_unlock_irq(&csmapisa_lock);
+	restore_eisa_map(save_map);
 
 	return res;
 }
 
 static void sni_writeb(unsigned char val, unsigned long addr)
 {
-	spin_lock_irq(&csmapisa_lock);
-	update_isa_cache(addr);
+	unsigned int save_map;
+
+	save_map = save_eisa_map();
+	eisa_map(addr);
 	addr &= 0xffffff;
 	*(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
-	spin_unlock_irq(&csmapisa_lock);
+	restore_eisa_map(save_map);
 }
 
 static void sni_writew(unsigned short val, unsigned long addr)
 {
-	spin_lock_irq(&csmapisa_lock);
-	update_isa_cache(addr);
+	unsigned int save_map;
+
+	save_map = save_eisa_map();
+	eisa_map(addr);
 	addr &= 0xffffff;
 	*(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
-	spin_unlock_irq(&csmapisa_lock);
+	restore_eisa_map(save_map);
 }
 
 static void sni_writel(unsigned int val, unsigned long addr)
 {
-	spin_lock_irq(&csmapisa_lock);
-	update_isa_cache(addr);
+	unsigned int save_map;
+
+	save_map = save_eisa_map();
+	eisa_map(addr);
 	addr &= 0xffffff;
 	*(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
-	spin_unlock_irq(&csmapisa_lock);
+	restore_eisa_map(save_map);
 }
 
 static void sni_memset_io(unsigned long addr, int val, unsigned long len)
 {
 	unsigned long waddr;
+	unsigned int save_map;
 
+	save_map = save_eisa_map();
 	waddr = PCIMT_EISA_BASE | (addr & 0xffffff);
-	spin_lock_irq(&csmapisa_lock);
 	while(len) {
 		unsigned long fraglen;
 
 		fraglen = (~addr + 1) & 0xffffff;
 		fraglen = (fraglen < len) ? fraglen : len;
-		update_isa_cache(addr);
+		eisa_map(addr);
 		memset((char *)waddr, val, fraglen);
 		addr += fraglen;
 		waddr = waddr + fraglen - 0x1000000;
 		len -= fraglen;
 	}
-	spin_unlock_irq(&csmapisa_lock);
+	restore_eisa_map(save_map);
 }
 
 static void sni_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len)
 {
 	unsigned long waddr;
+	unsigned int save_map;
 
+	save_map = save_eisa_map();
 	waddr = PCIMT_EISA_BASE | (from & 0xffffff);
-	spin_lock_irq(&csmapisa_lock);
 	while(len) {
 		unsigned long fraglen;
 
 		fraglen = (~from + 1) & 0xffffff;
 		fraglen = (fraglen < len) ? fraglen : len;
-		update_isa_cache(from);
+		eisa_map(from);
 		memcpy((void *)to, (void *)waddr, fraglen);
 		to += fraglen;
 		from += fraglen;
 		waddr = waddr + fraglen - 0x1000000;
 		len -= fraglen;
 	}
-	spin_unlock_irq(&csmapisa_lock);
+	restore_eisa_map(save_map);
 }
 
 static void sni_memcpy_toio(unsigned long to, unsigned long from, unsigned long len)
 {
 	unsigned long waddr;
+	unsigned int save_map;
 
+	save_map = save_eisa_map();
 	waddr = PCIMT_EISA_BASE | (to & 0xffffff);
-	spin_lock_irq(&csmapisa_lock);
 	while(len) {
 		unsigned long fraglen;
 
 		fraglen = (~to + 1) & 0xffffff;
 		fraglen = (fraglen < len) ? fraglen : len;
-		update_isa_cache(to);
+		eisa_map(to);
 		memcpy((char *)to + PCIMT_EISA_BASE, (void *)from, fraglen);
 		to += fraglen;
 		from += fraglen;
 		waddr = waddr + fraglen - 0x1000000;
 		len -= fraglen;
 	}
-	spin_unlock_irq(&csmapisa_lock);
+	restore_eisa_map(save_map);
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sni/pci.c linux/arch/mips/sni/pci.c
--- v2.3.8/linux/arch/mips/sni/pci.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sni/pci.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: pci.c,v 1.6 1998/05/07 14:17:48 ralf Exp $
+/* $Id: pci.c,v 1.7 1999/01/04 16:03:58 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -9,6 +9,7 @@
  * Copyright (C) 1997, 1998 Ralf Baechle
  */
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/types.h>
 #include <asm/byteorder.h>
@@ -28,13 +29,37 @@
 
 static void sni_rm200_pcibios_fixup (void)
 {
-	/*
-	 * TODO: Fix PCI_INTERRUPT_LINE register for onboard cards.
-	 * Take care of RM300 revision D boards for where the network
-	 * slot became an ordinary PCI slot.
-	 */
-	pcibios_write_config_byte(0, PCI_DEVFN(1, 0), PCI_INTERRUPT_LINE,
-	                          PCIMT_IRQ_SCSI);
+	struct pci_dev *dev;
+
+	for (dev=pci_devices; dev; dev=dev->next) {
+		/*
+		 * TODO: Take care of RM300 revision D boards for where the
+		 * network slot became an ordinary PCI slot.
+		 */
+		if (dev->devfn == PCI_DEVFN(1, 0)) {
+			/* Evil hack ...  */
+			set_cp0_config(CONF_CM_CMASK, CONF_CM_CACHABLE_NO_WA);
+			dev->irq = PCIMT_IRQ_SCSI;
+			continue;
+		}
+		if (dev->devfn == PCI_DEVFN(2, 0)) {
+			dev->irq = PCIMT_IRQ_ETHERNET;
+			continue;
+		}
+
+		switch(dev->irq) {
+		case 1 ... 4:
+			dev->irq += PCIMT_IRQ_INTA - 1;
+			break;
+		case 0:
+			break;
+		default:
+			printk("PCI device on bus %d, dev %d, function %d "
+			       "impossible interrupt configured.\n",
+			       dev->bus->number, PCI_SLOT(dev->devfn),
+			       PCI_SLOT(dev->devfn));
+		}
+	}
 }
 
 /*
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sni/pcimt_scache.c linux/arch/mips/sni/pcimt_scache.c
--- v2.3.8/linux/arch/mips/sni/pcimt_scache.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sni/pcimt_scache.c	Fri Jun 25 17:40:13 1999
@@ -1,35 +1,38 @@
-/*
+/* $Id: pcimt_scache.c,v 1.4 1999/01/04 16:03:59 ralf Exp $
+ *
  * arch/mips/sni/pcimt_scache.c
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 1997 by Ralf Baechle
- *
- * $Id: pcimt_scache.c,v 1.2 1998/05/28 03:18:02 ralf Exp $
+ * Copyright (c) 1997, 1998 by Ralf Baechle
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <asm/bcache.h>
 #include <asm/sni.h>
 
+#define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF)
+#define invspace (*(volatile unsigned int *)PCIMT_INVSPACE)
+
 __initfunc(void sni_pcimt_sc_init(void))
 {
-	unsigned int cacheconf, sc_size;
+	unsigned int scsiz, sc_size;
 
-	cacheconf = *(volatile unsigned int *)PCIMT_CACHECONF;
-	if ((cacheconf & 7) == 0) {
-		printk("No second level cache detected\n");
-		printk("WARNING: not activating second level cache, "
-		       "tell ralf@gnu.org\n");
+	scsiz = cacheconf & 7;
+	if (scsiz == 0) {
+		printk("Second level cache is deactived.\n");
 		return;
 	}
-	if ((cacheconf & 7) >= 6) {
-		printk("Invalid second level cache size detected\n");
+	if (scsiz >= 6) {
+		printk("Invalid second level cache size configured, "
+		       "deactivating second level cache.\n");
+		cacheconf = 0;
 		return;
 	}
-	
-	sc_size = 128 << (cacheconf & 7);
-	printk("%dkb second level cache detected.\n", sc_size);
+
+	sc_size = 128 << scsiz;
+	printk("%dkb second level cache detected, deactivating.\n", sc_size);
+	cacheconf = 0;
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/sni/setup.c linux/arch/mips/sni/setup.c
--- v2.3.8/linux/arch/mips/sni/setup.c	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/sni/setup.c	Fri Jun 25 17:40:13 1999
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.13 1998/08/17 13:57:45 ralf Exp $
+/* $Id: setup.c,v 1.10 1999/01/04 16:03:59 ralf Exp $
  *
  * Setup pointers to hardware-dependent routines.
  *
@@ -17,6 +17,11 @@
 #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/pci.h>
+#include <linux/mc146818rtc.h>
+#include <linux/console.h>
+#include <linux/fb.h>
+#include <linux/pc_keyb.h>
+
 #include <asm/bcache.h>
 #include <asm/bootinfo.h>
 #include <asm/keyboard.h>
@@ -39,7 +44,6 @@
 static struct irqaction irq2  = { no_action, 0, 0, "cascade", NULL, NULL};
 
 extern asmlinkage void sni_rm200_pci_handle_int(void);
-extern void sni_rm200_keyboard_setup(void);
 
 extern void sni_machine_restart(char *command);
 extern void sni_machine_halt(void);
@@ -47,19 +51,20 @@
 
 extern struct ide_ops std_ide_ops;
 extern struct rtc_ops std_rtc_ops;
+extern struct kbd_ops std_kbd_ops;
 
 __initfunc(static void sni_irq_setup(void))
 {
 	set_except_vector(0, sni_rm200_pci_handle_int);
 	request_region(0x20,0x20, "pic1");
 	request_region(0xa0,0x20, "pic2");	
-	setup_x86_irq(2, &irq2);
+	i8259_setup_irq(2, &irq2);
 	/*
 	 * IRQ0 seems to be the irq for PC style stuff.
 	 * I don't know how to handle the debug button interrupt, so
 	 * don't use this button yet or bad things happen ...
 	 */
-	set_cp0_status(ST0_IM, IE_IRQ1 | IE_IRQ4);
+	set_cp0_status(ST0_IM, IE_IRQ1 | IE_IRQ3 | IE_IRQ4);
 }
 
 void (*board_time_init)(struct irqaction *irq);
@@ -70,7 +75,7 @@
 	outb_p(0x34,0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
 	outb_p(LATCH & 0xff , 0x40);	/* LSB */
 	outb(LATCH >> 8 , 0x40);	/* MSB */
-	setup_x86_irq(0, irq);
+	i8259_setup_irq(0, irq);
 }
 
 unsigned char aux_device_present;
@@ -132,7 +137,6 @@
 
 	irq_setup = sni_irq_setup;
 	mips_io_port_base = SNI_PORT_BASE;
-	keyboard_setup = sni_rm200_keyboard_setup;
 
 	/*
 	 * Setup (E)ISA I/O memory access stuff
@@ -165,6 +169,10 @@
 #ifdef CONFIG_BLK_DEV_IDE
 	ide_ops = &std_ide_ops;
 #endif
-
+	conswitchp = &vga_con;
 	rtc_ops = &std_rtc_ops;
+	kbd_ops = &std_kbd_ops;
+#ifdef CONFIG_PSMOUSE
+	aux_device_present = 0xaa;
+#endif
 }
diff -u --recursive --new-file v2.3.8/linux/arch/mips/tools/Makefile linux/arch/mips/tools/Makefile
--- v2.3.8/linux/arch/mips/tools/Makefile	Tue Oct 20 13:52:55 1998
+++ linux/arch/mips/tools/Makefile	Fri Jun 25 17:40:13 1999
@@ -3,7 +3,7 @@
 # Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
 # Copyright (C) 1997 Ralf Baechle (ralf@gnu.ai.mit.edu)
 #
-# $Id: Makefile,v 1.2 1997/09/23 06:23:49 ralf Exp $
+# $Id: Makefile,v 1.2 1997/12/01 17:57:41 ralf Exp $
 #
 TARGET	:= $(TOPDIR)/include/asm-$(ARCH)/offset.h
 
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.3.8/linux/arch/ppc/Makefile	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/Makefile	Mon Jun 28 13:40:39 1999
@@ -22,7 +22,8 @@
 LINKFLAGS	= -T arch/ppc/vmlinux.lds -Ttext $(KERNELLOAD) -Bstatic
 CFLAGSINC	= -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
 CFLAGS		:= $(CFLAGS) -D__powerpc__ -fsigned-char -msoft-float -pipe \
-		-fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple -mstring
+		-fno-builtin -ffixed-r2 -Wno-uninitialized -mmultiple \
+		-mstring
 CPP		= $(CC) -E $(CFLAGS)
 
 ifdef CONFIG_8xx
@@ -30,8 +31,7 @@
 endif
 
 ifdef CONFIG_PPC64
-CFLAGS := $(CFLAGS) -Wa,-mppc64bridge #-Wa,-mppc64
-#CFLAGS := $(CFLAGS) -Wa,-mppc64 -mpowerpc64
+CFLAGS := $(CFLAGS) -Wa,-mppc64bridge #-mpowerpc64
 endif
 
 HEAD := arch/ppc/kernel/head.o
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/apus_defconfig linux/arch/ppc/apus_defconfig
--- v2.3.8/linux/arch/ppc/apus_defconfig	Thu Feb 25 10:46:47 1999
+++ linux/arch/ppc/apus_defconfig	Sat Jun 26 08:34:19 1999
@@ -76,7 +76,7 @@
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_PMAC_IDEDMA_AUTO=y
+CONFIG_IDEDMA_PMAC_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/chrpboot/Makefile linux/arch/ppc/chrpboot/Makefile
--- v2.3.8/linux/arch/ppc/chrpboot/Makefile	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/chrpboot/Makefile	Mon Jun 28 13:40:39 1999
@@ -70,6 +70,9 @@
 	./mknote > note
 	$(OBJCOPY) $@ $@ --add-section=.note=note -R .comment
 
+mknote: mknote.c
+	$(HOSTCC) $(HOSTCFLAGS) -o $@ mknote.c
+
 zImage.initrd: $(OBJS) initrd.o
 	$(LD) $(LD_ARGS) -o $@ $(OBJS) initrd.o $(LIBS)
 
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/chrpboot/main.c linux/arch/ppc/chrpboot/main.c
--- v2.3.8/linux/arch/ppc/chrpboot/main.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/chrpboot/main.c	Mon Jun 28 13:40:39 1999
@@ -19,12 +19,13 @@
 #define RAM_START	0x00000000
 #define RAM_END		(8<<20)
 
-#define RAM_FREE	(6<<20)		/* after image of chrpboot */
+#define RAM_FREE	((unsigned long)(_end+0x1000)&~0xFFF)
 #define PROG_START	0x00010000
 
 char *avail_ram;
 char *end_avail;
 
+extern char _end[];
 extern char image_data[];
 extern int image_len;
 extern char initrd_data[];
@@ -47,8 +48,8 @@
 	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
 	a1 = initrd_start;
 	a2 = initrd_size;
-	printf("initial ramdisk at 0x%x (%u bytes)\n\r", initrd_start,
-	       initrd_size);
+	printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n\r", initrd_start,
+	       initrd_data,initrd_size);
 	memcpy((char *)initrd_start, initrd_data, initrd_size);
 	end_avail = (char *)initrd_start;
     } else
@@ -56,7 +57,6 @@
     im = image_data;
     len = image_len;
     dst = (void *) PROG_START;
-
     if (im[0] == 0x1f && im[1] == 0x8b) {
 	avail_ram = (char *)RAM_FREE;
 	printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile
--- v2.3.8/linux/arch/ppc/coffboot/Makefile	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/coffboot/Makefile	Mon Jun 28 13:40:39 1999
@@ -3,7 +3,6 @@
 #
 # Paul Mackerras	January 1997
 
-HOSTCC	= gcc
 HOSTCFLAGS = -O -I$(TOPDIR)/include
 
 CC	= $(CROSS_COMPILE)gcc
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- v2.3.8/linux/arch/ppc/common_defconfig	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/common_defconfig	Mon Jun 28 13:40:39 1999
@@ -81,13 +81,13 @@
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_PMAC_IDEDMA_AUTO=y
+CONFIG_IDEDMA_PMAC_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -131,6 +131,7 @@
 #
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
+# CONFIG_DECNET is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
@@ -176,7 +177,8 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_OVERRIDE_CMDS is not set
+# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_ADVANSYS is not set
@@ -311,7 +313,7 @@
 CONFIG_FB_MATROX=y
 # CONFIG_FB_MATROX_MILLENIUM is not set
 CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G100 is not set
+CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 # CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
@@ -425,6 +427,7 @@
 CONFIG_MAC_PARTITION=y
 # CONFIG_SMD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_SGI_DISKLABEL is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_NLS=y
 
@@ -464,6 +467,7 @@
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
+# CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_ES1370 is not set
 # CONFIG_SOUND_ES1371 is not set
 # CONFIG_SOUND_SONICVIBES is not set
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.3.8/linux/arch/ppc/config.in	Tue Jun  8 10:52:26 1999
+++ linux/arch/ppc/config.in	Mon Jun 28 13:40:39 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.93 1999/05/14 22:36:58 cort Exp $
+# $Id: config.in,v 1.94 1999/06/25 11:00:07 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -65,7 +65,6 @@
 define_bool CONFIG_BINFMT_ELF y
 define_bool CONFIG_KERNEL_ELF y
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
 
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
@@ -176,7 +175,6 @@
 endmenu
 
 source drivers/char/Config.in
-source drivers/usb/Config.in
 source fs/Config.in
 
 mainmenu_option next_comment
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.3.8/linux/arch/ppc/defconfig	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/defconfig	Mon Jun 28 13:40:39 1999
@@ -35,7 +35,6 @@
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
 # CONFIG_BINFMT_MISC is not set
-# CONFIG_BINFMT_JAVA is not set
 # CONFIG_PARPORT is not set
 CONFIG_VGA_CONSOLE=y
 CONFIG_FB=y
@@ -81,13 +80,13 @@
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_PMAC_IDEDMA_AUTO=y
+CONFIG_IDEDMA_PMAC_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -131,6 +130,7 @@
 #
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
+# CONFIG_DECNET is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_BRIDGE is not set
@@ -176,7 +176,8 @@
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_OVERRIDE_CMDS is not set
+# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=15
 # CONFIG_SCSI_ADVANSYS is not set
@@ -311,7 +312,7 @@
 CONFIG_FB_MATROX=y
 # CONFIG_FB_MATROX_MILLENIUM is not set
 CONFIG_FB_MATROX_MYSTIQUE=y
-# CONFIG_FB_MATROX_G100 is not set
+CONFIG_FB_MATROX_G100=y
 # CONFIG_FB_MATROX_MULTIHEAD is not set
 # CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
@@ -425,6 +426,7 @@
 CONFIG_MAC_PARTITION=y
 # CONFIG_SMD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_SGI_DISKLABEL is not set
 # CONFIG_UNIXWARE_DISKLABEL is not set
 CONFIG_NLS=y
 
@@ -464,12 +466,40 @@
 #
 CONFIG_SOUND=y
 CONFIG_DMASOUND=y
+# CONFIG_SOUND_CMPCI is not set
 # 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 is not set
+CONFIG_SOUND_OSS=y
+# CONFIG_SOUND_DMAP is not set
+# 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=m
+# 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
+
+#
+# Additional low level sound drivers
+#
+# CONFIG_LOWLEVEL_SOUND is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.3.8/linux/arch/ppc/kernel/Makefile	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/kernel/Makefile	Mon Jun 28 13:40:39 1999
@@ -56,16 +56,16 @@
 		$(TOPDIR)/include/asm/processor.h \
 		$(TOPDIR)/include/asm/pgtable.h \
 		$(TOPDIR)/include/asm/ptrace.h
-	$(CC) ${CFLAGS} -S mk_defs.c
+	$(CC) $(CFLAGS) -S mk_defs.c
 	cp ppc_defs.head ppc_defs.h
 	grep '^#define' mk_defs.s >>ppc_defs.h
 	rm mk_defs.s
 
 find_name : find_name.c
-	$(HOSTCC) -o find_name find_name.c
+	$(HOSTCC) $(HOSTCFLAGS) -o find_name find_name.c
 
 checks: checks.c
-	$(HOSTCC) ${CFLAGS} -D__KERNEL__ -o checks checks.c
+	$(HOSTCC) $(HOSTCFLAGS) -D__KERNEL__ -o checks checks.c
 	./checks
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.3.8/linux/arch/ppc/kernel/chrp_pci.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/chrp_pci.c	Mon Jun 28 13:40:39 1999
@@ -354,7 +354,8 @@
                 }
                 else
                 {
-			if ( !strncmp("IBM,7043-150", get_property(find_path_device("/"), "name", NULL),12) )
+			if ( !strncmp("IBM,7043-150", get_property(find_path_device("/"), "name", NULL),12) ||
+			     !strncmp("IBM,7046-155", get_property(find_path_device("/"), "name", NULL),12) )
 			{
 				pci_dram_offset = 0;
 				isa_mem_base = 0x80000000;
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.3.8/linux/arch/ppc/kernel/chrp_setup.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/chrp_setup.c	Mon Jun 28 13:40:39 1999
@@ -48,6 +48,7 @@
 #include <asm/irq.h>
 #include <asm/adb.h>
 #include <asm/hydra.h>
+#include <asm/keyboard.h>
 
 #include "time.h"
 #include "local_irq.h"
@@ -66,7 +67,6 @@
 
 unsigned long chrp_get_rtc_time(void);
 int chrp_set_rtc_time(unsigned long nowtime);
-unsigned long rtas_event_scan_rate = 0, rtas_event_scan_ct = 0;
 void chrp_calibrate_decr(void);
 void chrp_time_init(void);
 
@@ -281,7 +281,7 @@
 	/*
 	 *  Fix the Super I/O configuration
 	 */
-	/*sio_init();*/
+	sio_init();
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
@@ -295,15 +295,16 @@
 		struct property *p;
 		device = find_devices("rtas");
 		for ( p = device->properties;
-		      strncmp(p->name, "rtas-event-scan-rate", 20) && p ;
+		      p && strncmp(p->name, "rtas-event-scan-rate", 20);
 		      p = p->next )
 			/* nothing */ ;
 		if ( p && *(unsigned long *)p->value )
 		{
-			rtas_event_scan_rate = (HZ/(*(unsigned long *)p->value)*30)-1;
-			rtas_event_scan_ct = 1;
+			ppc_md.heartbeat = chrp_event_scan;
+			ppc_md.heartbeat_reset = (HZ/(*(unsigned long *)p->value)*30)-1;
+			ppc_md.heartbeat_count = 1;
 			printk("RTAS Event Scan Rate: %lu (%lu jiffies)\n",
-			       *(unsigned long *)p->value, rtas_event_scan_rate );
+			       *(unsigned long *)p->value, ppc_md.heartbeat_reset );
 		}
 	}
 }
@@ -312,11 +313,8 @@
 chrp_event_scan(void)
 {
 	unsigned char log[1024];
-	if ( rtas_event_scan_rate && (rtas_event_scan_ct-- <= 0) )
-	{
-		call_rtas( "event-scan", 4, 1, NULL, 0x0, 1, __pa(log), 1024 );
-		rtas_event_scan_ct = rtas_event_scan_rate;
-	}
+	call_rtas( "event-scan", 4, 1, NULL, 0x0, 1, __pa(log), 1024 );
+	ppc_md.heartbeat_count = ppc_md.heartbeat_reset;
 }
 	
 void
@@ -331,7 +329,7 @@
 chrp_power_off(void)
 {
 	/* allow power on only with power button press */
-#define	PWR_FIELD(x) (0x8000000000000000 >> ((x)-96))
+#define	PWR_FIELD(x) (0x8000000000000000ULL >> ((x)-96))
 	printk("RTAS power-off returned %d\n",
 	       call_rtas("power-off", 2, 1, NULL,
 			 ((PWR_FIELD(96)|PWR_FIELD(97))>>32)&0xffffffff,
@@ -632,7 +630,8 @@
 		ppc_md.kbd_leds          = pckbd_leds;
 		ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-		ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+		ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+		SYSRQ_KEY = 0x54;
 #endif		
 	}
 	else
@@ -644,7 +643,8 @@
 		ppc_md.kbd_leds          = mackbd_leds;
 		ppc_md.kbd_init_hw       = mackbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-		ppc_md.kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
+		ppc_md.ppc_kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
+		SYSRQ_KEY = 0x69;
 #endif		
 	}
 #else
@@ -655,7 +655,8 @@
 	ppc_md.kbd_leds          = pckbd_leds;
 	ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x54;
 #endif
 #endif
 #endif
@@ -665,9 +666,9 @@
         ppc_ide_md.outsw = chrp_ide_outsw;
         ppc_ide_md.default_irq = chrp_ide_default_irq;
         ppc_ide_md.default_io_base = chrp_ide_default_io_base;
-        ppc_ide_md.check_region = chrp_ide_check_region;
-        ppc_ide_md.request_region = chrp_ide_request_region;
-        ppc_ide_md.release_region = chrp_ide_release_region;
+        ppc_ide_md.ide_check_region = chrp_ide_check_region;
+        ppc_ide_md.ide_request_region = chrp_ide_request_region;
+        ppc_ide_md.ide_release_region = chrp_ide_release_region;
         ppc_ide_md.fix_driveid = chrp_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
 
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.3.8/linux/arch/ppc/kernel/idle.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/idle.c	Mon Jun 28 13:40:39 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: idle.c,v 1.62 1999/05/24 05:43:18 cort Exp $
+ * $Id: idle.c,v 1.63 1999/06/10 22:55:35 geert Exp $
  *
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
@@ -298,7 +298,7 @@
 	case 7:			/* 603ev */
 	case 8:			/* 750 */
 		save_flags(msr);
-		cli();
+		__cli();
 		if (!current->need_resched) {
 			asm("mfspr %0,1008" : "=r" (hid0) :);
 			hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.3.8/linux/arch/ppc/kernel/irq.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/irq.c	Mon Jun 28 13:40:39 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: irq.c,v 1.106 1999/05/25 21:16:04 cort Exp $
+ * $Id: irq.c,v 1.107 1999/06/17 05:39:12 paulus Exp $
  *
  *  arch/ppc/kernel/irq.c
  *
@@ -187,6 +187,12 @@
 void free_irq(unsigned int irq, void *dev_id)
 {
 	request_irq(irq, NULL, 0, NULL, dev_id);
+}
+
+/* XXX should implement irq disable depth like on intel */
+void disable_irq_nosync(unsigned int irq_nr)
+{
+	mask_irq(irq_nr);
 }
 
 void disable_irq(unsigned int irq_nr)
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c
--- v2.3.8/linux/arch/ppc/kernel/mbx_setup.c	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/kernel/mbx_setup.c	Mon Jun 28 13:40:39 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: mbx_setup.c,v 1.10 1999/05/14 07:24:19 davem Exp $
+ * $Id: mbx_setup.c,v 1.11 1999/06/28 17:59:43 cort Exp $
  *
  *  linux/arch/ppc/kernel/setup.c
  *
@@ -473,9 +473,9 @@
         ppc_ide_md.outsw = mbx_ide_outsw;
         ppc_ide_md.default_irq = mbx_ide_default_irq;
         ppc_ide_md.default_io_base = mbx_ide_default_io_base;
-        ppc_ide_md.check_region = mbx_ide_check_region;
-        ppc_ide_md.request_region = mbx_ide_request_region;
-        ppc_ide_md.release_region = mbx_ide_release_region;
+        ppc_ide_md.ide_check_region = mbx_ide_check_region;
+        ppc_ide_md.ide_request_region = mbx_ide_request_region;
+        ppc_ide_md.ide_release_region = mbx_ide_release_region;
         ppc_ide_md.fix_driveid = mbx_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = mbx_ide_init_hwif_ports;
 
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.3.8/linux/arch/ppc/kernel/misc.S	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/misc.S	Mon Jun 28 13:40:39 1999
@@ -650,17 +650,19 @@
 
 /*
  * Create a kernel thread
- *   __kernel_thread(flags, fn, arg)
+ *   kernel_thread(fn, arg, flags)
  */
-_GLOBAL(__kernel_thread)
+_GLOBAL(kernel_thread)
+	mr	r6,r3		/* function */
+	ori	r3,r5,CLONE_VM	/* flags */
 	li	r0,__NR_clone
 	sc
 	cmpi	0,r3,0		/* parent or child? */
 	bnelr			/* return if parent */
 	li	r0,0		/* clear out p->tss.regs */
 	stw	r0,TSS+PT_REGS(r2)	/* since we don't have user ctx */
-	mtlr	r4              /* fn addr in lr */
-	mr	r3,r5	        /* load arg and call fn */
+	mtlr	r6              /* fn addr in lr */
+	mr	r3,r4	        /* load arg and call fn */
 	blrl
 	li	r0,__NR_exit	/* exit after child exits */
         li	r3,0
@@ -866,7 +868,7 @@
 	.long sys_getresuid	/* 165 */
 	.long sys_query_module
 	.long sys_poll
-#ifdef CONFIG_NFS	
+#ifdef CONFIG_NFSD	
 	.long sys_nfsservctl
 #else
 	.long sys_ni_syscall
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.3.8/linux/arch/ppc/kernel/mk_defs.c	Tue May 11 08:24:32 1999
+++ linux/arch/ppc/kernel/mk_defs.c	Mon Jun 28 13:40:39 1999
@@ -97,5 +97,6 @@
 	DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
 	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
 	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
+	DEFINE(CLONE_VM, CLONE_VM);
 	return 0;
 }
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.3.8/linux/arch/ppc/kernel/pmac_setup.c	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/kernel/pmac_setup.c	Mon Jun 28 13:40:39 1999
@@ -42,6 +42,7 @@
 #include <linux/vt_kern.h>
 #include <linux/console.h>
 #include <linux/ide.h>
+#include <linux/pci.h>
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
@@ -56,6 +57,7 @@
 #include <asm/feature.h>
 #include <asm/ide.h>
 #include <asm/machdep.h>
+#include <asm/keyboard.h>
 
 #include "time.h"
 #include "local_irq.h"
@@ -98,6 +100,7 @@
 
 extern void zs_kgdb_hook(int tty_num);
 static void ohare_init(void);
+static void init_p2pbridge(void);
 
 __pmac
 int
@@ -255,6 +258,7 @@
 	ohare_init();
 
 	*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+	init_p2pbridge();
 
 	/* Checks "l2cr-value" property in the registry */
 	if ( (_get_PVR() >> 16) == 8) {
@@ -299,6 +303,31 @@
 		ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
 }
 
+/*
+ * Tweak the PCI-PCI bridge chip on the blue & white G3s.
+ */
+__initfunc(static void init_p2pbridge(void))
+{
+	struct device_node *p2pbridge;
+	unsigned char bus, devfn;
+	unsigned short val;
+
+	/* XXX it would be better here to identify the specific
+	   PCI-PCI bridge chip we have. */
+	if ((p2pbridge = find_devices("pci-bridge")) == 0
+	    || p2pbridge->parent == NULL
+	    || strcmp(p2pbridge->parent->name, "pci") != 0)
+		return;
+
+	if (pci_device_loc(p2pbridge, &bus, &devfn) < 0)
+		return;
+
+	pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val);
+	val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
+	pcibios_write_config_word(bus, devfn, PCI_BRIDGE_CONTROL, val);
+	pcibios_read_config_word(bus, devfn, PCI_BRIDGE_CONTROL, &val);
+}
+
 __initfunc(static void ohare_init(void))
 {
 	/*
@@ -488,13 +517,13 @@
 void
 pmac_ide_insw(ide_ioreg_t port, void *buf, int ns)
 {
-	ide_insw(port, buf, ns);
+	_insw_ns(port+_IO_BASE, buf, ns);
 }
 
 void
 pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns)
 {
-	ide_outsw(port, buf, ns);
+	_outsw_ns(port+_IO_BASE, buf, ns);
 }
 
 int
@@ -596,7 +625,8 @@
 	ppc_md.kbd_leds          = mackbd_leds;
 	ppc_md.kbd_init_hw       = mackbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
+	ppc_md.ppc_kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
+	SYSRQ_KEY = 0x69;
 #endif
 #endif
 
@@ -605,13 +635,13 @@
         ppc_ide_md.outsw = pmac_ide_outsw;
         ppc_ide_md.default_irq = pmac_ide_default_irq;
         ppc_ide_md.default_io_base = pmac_ide_default_io_base;
-        ppc_ide_md.check_region = pmac_ide_check_region;
-        ppc_ide_md.request_region = pmac_ide_request_region;
-        ppc_ide_md.release_region = pmac_ide_release_region;
+        ppc_ide_md.ide_check_region = pmac_ide_check_region;
+        ppc_ide_md.ide_request_region = pmac_ide_request_region;
+        ppc_ide_md.ide_release_region = pmac_ide_release_region;
         ppc_ide_md.fix_driveid = pmac_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
 
-        ppc_ide_md.io_base = 0;
+        ppc_ide_md.io_base = _IO_BASE;	/* actually too early for this :-( */
 #endif		
 }
 
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c
--- v2.3.8/linux/arch/ppc/kernel/ppc_htab.c	Mon Dec 21 08:37:20 1998
+++ linux/arch/ppc/kernel/ppc_htab.c	Mon Jun 28 13:40:39 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: ppc_htab.c,v 1.26 1998/12/10 00:24:23 cort Exp $
+ * $Id: ppc_htab.c,v 1.28 1999/06/27 10:53:32 davem Exp $
  *
  * PowerPC hash table management proc entry.  Will show information
  * about the current hash table and will allow changes to it.
@@ -74,11 +74,14 @@
     NULL,	    /* rename	   */
     NULL,	    /* readlink	   */
     NULL,	    /* follow_link */
+    NULL,	    /* get_block   */
     NULL,	    /* readpage	   */
     NULL,	    /* writepage   */
-    NULL,	    /* bmap	   */
+    NULL,	    /* flushpage   */
     NULL,	    /* truncate	   */
-    NULL	    /* permission  */
+    NULL,	    /* permission  */
+    NULL,	    /* smap        */
+    NULL	    /* revalidate  */
 };
 
 /* these will go into processor.h when I'm done debugging -- Cort */
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.3.8/linux/arch/ppc/kernel/ppc_ksyms.c	Thu May 13 11:00:08 1999
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Mon Jun 28 13:40:39 1999
@@ -31,8 +31,8 @@
 #include <asm/dma.h>
 #include <asm/machdep.h>
 
-#define __KERNEL_SYSCALLS__
-#include <linux/unistd.h>
+/* Tell string.h we don't want memcpy etc. as cpp defines */
+#define EXPORT_SYMTAB_STROPS
 
 extern void transfer_to_handler(void);
 extern void int_return(void);
@@ -47,7 +47,6 @@
 extern void do_lost_interrupts(unsigned long);
 extern int do_signal(sigset_t *, struct pt_regs *);
 
-asmlinkage long long __ashrdi3(long long, int);
 asmlinkage int abs(int);
 
 EXPORT_SYMBOL(clear_page);
@@ -66,6 +65,7 @@
 EXPORT_SYMBOL(do_lost_interrupts);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
 EXPORT_SYMBOL(ppc_local_irq_count);
 EXPORT_SYMBOL(ppc_local_bh_count);
 
@@ -112,11 +112,6 @@
 EXPORT_SYMBOL(strspn);
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strncmp);
-EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(memscan);
-EXPORT_SYMBOL(memcmp);
 
 /* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
 EXPORT_SYMBOL(csum_partial_copy_generic);
@@ -153,9 +148,10 @@
 
 EXPORT_SYMBOL(ide_insw);
 EXPORT_SYMBOL(ide_outsw);
+EXPORT_SYMBOL(ppc_ide_md);
 
 EXPORT_SYMBOL(start_thread);
-EXPORT_SYMBOL(__kernel_thread);
+EXPORT_SYMBOL(kernel_thread);
 
 EXPORT_SYMBOL(__cli);
 EXPORT_SYMBOL(__sti);
@@ -215,11 +211,11 @@
 EXPORT_SYMBOL(nvram_write_byte);
 #endif /* CONFIG_PMAC */
 
+EXPORT_SYMBOL_NOVERS(memcpy);
+EXPORT_SYMBOL_NOVERS(memset);
+EXPORT_SYMBOL_NOVERS(memmove);
+EXPORT_SYMBOL_NOVERS(memscan);
+EXPORT_SYMBOL_NOVERS(memcmp);
+
 EXPORT_SYMBOL(abs);
 EXPORT_SYMBOL(device_is_compatible);
-
-/* The following are special because they're not called
-   explicitly (the C compiler generates them).  Fortunately,
-   their interface isn't gonna change any time soon now, so
-   it's OK to leave it out of version control.  */
-EXPORT_SYMBOL_NOVERS(__ashrdi3);
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.3.8/linux/arch/ppc/kernel/prep_setup.c	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/kernel/prep_setup.c	Mon Jun 28 13:40:39 1999
@@ -48,7 +48,7 @@
 #include <asm/mk48t59.h>
 #include <asm/prep_nvram.h>
 #include <asm/raven.h>
-
+#include <asm/keyboard.h>
 
 #include "time.h"
 #include "local_irq.h"
@@ -825,9 +825,9 @@
         ppc_ide_md.outsw = prep_ide_outsw;
         ppc_ide_md.default_irq = prep_ide_default_irq;
         ppc_ide_md.default_io_base = prep_ide_default_io_base;
-        ppc_ide_md.check_region = prep_ide_check_region;
-        ppc_ide_md.request_region = prep_ide_request_region;
-        ppc_ide_md.release_region = prep_ide_release_region;
+        ppc_ide_md.ide_check_region = prep_ide_check_region;
+        ppc_ide_md.ide_request_region = prep_ide_request_region;
+        ppc_ide_md.ide_release_region = prep_ide_release_region;
         ppc_ide_md.fix_driveid = prep_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
 #endif		
@@ -841,7 +841,8 @@
 	ppc_md.kbd_leds          = pckbd_leds;
 	ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
-	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+	SYSRQ_KEY = 0x54;
 #endif
 #endif
 }
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.3.8/linux/arch/ppc/kernel/process.c	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/kernel/process.c	Mon Jun 28 13:40:39 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: process.c,v 1.85 1999/05/16 21:27:08 cort Exp $
+ * $Id: process.c,v 1.86 1999/06/17 21:53:46 cort Exp $
  *
  *  linux/arch/ppc/kernel/process.c
  *
@@ -306,6 +306,7 @@
 	p->tss.fpscr = current->tss.fpscr;
 	childregs->msr &= ~MSR_FP;
 
+	p->processor = 0;
 #ifdef __SMP__
 	p->last_processor = NO_PROC_ID;
 #endif /* __SMP__ */
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.3.8/linux/arch/ppc/kernel/prom.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/prom.c	Mon Jun 28 13:40:39 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.60 1999/05/25 01:42:41 cort Exp $
+ * $Id: prom.c,v 1.61 1999/06/17 06:05:52 paulus Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -338,7 +338,9 @@
 			 */
 			model = (char *) early_get_property
 				(r4 + bi->deviceTreeOffset, 4, RELOC("model"));
-			if (model && strcmp(model, RELOC("iMac,1")) == 0) {
+			if (model
+			    && (strcmp(model, RELOC("iMac,1")) == 0
+				|| strcmp(model, RELOC("PowerMac1,1")) == 0)) {
 				out_le32((unsigned *)0x80880008, 1);	/* XXX */
 			}
 		}
@@ -887,11 +889,11 @@
 	    && (imp = (struct pci_intr_map *)
 		get_property(np->parent, "interrupt-map", &ml)) != 0
 	    && (ip = (int *) get_property(np, "interrupts", &l)) != 0) {
-		unsigned int busdevfn = pci_addrs[0].addr.a_hi & 0xffff00;
+		unsigned int devfn = pci_addrs[0].addr.a_hi & 0xff00;
 		np->n_intrs = 0;
 		np->intrs = (struct interrupt_info *) mem_start;
 		for (i = 0; (ml -= sizeof(struct pci_intr_map)) >= 0; ++i) {
-			if (imp[i].addr.a_hi == busdevfn) {
+			if (imp[i].addr.a_hi == devfn) {
 				np->intrs[np->n_intrs].line = imp[i].intr;
 				np->intrs[np->n_intrs].sense = 0;
 				++np->n_intrs;
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.3.8/linux/arch/ppc/kernel/setup.c	Sat May 22 13:03:00 1999
+++ linux/arch/ppc/kernel/setup.c	Mon Jun 28 13:40:39 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.133 1999/05/14 07:24:30 davem Exp $
+ * $Id: setup.c,v 1.136 1999/06/18 07:11:35 cort Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -80,6 +80,9 @@
 int have_of = 0;
 int is_prep = 0;
 int is_chrp = 0;
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned long SYSRQ_KEY;
+#endif /* CONFIG_MAGIC_SYSRQ */
 /* For MTX/MVME boards.. with Raven/Falcon Chipset
       Real close to CHRP, but boot like PReP (via PPCbug)
       There's probably a nicer way to do this.. --Troy */
@@ -160,15 +163,6 @@
 	ppc_md.halt();
 }
   
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-void ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
-{
-	if (ppc_ide_md.ide_init_hwif != NULL) {
-		ppc_ide_md.ide_init_hwif(hw, data_port, ctrl_port, irq);
-	}
-}
-#endif
-
 unsigned long cpu_temp(void)
 {
 	unsigned char thres = 0;
@@ -376,7 +370,6 @@
 			else
 			{
 				_machine = _MACH_Pmac;
-				is_prep = 1;
 			}
 		}
 
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v2.3.8/linux/arch/ppc/kernel/signal.c	Thu Apr 29 12:39:01 1999
+++ linux/arch/ppc/kernel/signal.c	Mon Jun 28 13:40:39 1999
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/ppc/kernel/signal.c
  *
- *  $Id: signal.c,v 1.24 1999/04/03 11:25:16 paulus Exp $
+ *  $Id: signal.c,v 1.25 1999/06/17 05:40:20 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -455,6 +455,7 @@
 			default:
 				lock_kernel();
 				sigaddset(&current->signal, signr);
+				recalc_sigpending(current);
 				current->flags |= PF_SIGNALED;
 				do_exit(exit_code);
 				/* NOTREACHED */
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.3.8/linux/arch/ppc/kernel/smp.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/smp.c	Mon Jun 28 13:40:39 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: smp.c,v 1.52 1999/05/23 22:43:51 cort Exp $
+ * $Id: smp.c,v 1.54 1999/06/24 17:13:34 cort Exp $
  *
  * Smp support for ppc.
  *
@@ -243,20 +243,21 @@
 {
 	extern struct task_struct *current_set[NR_CPUS];
 	extern void __secondary_start_psurge(void);
-	int i;
+	extern void __secondary_start_chrp(void);
+	int i, cpu_nr;
 	struct task_struct *p;
 	unsigned long a;
 
         printk("Entering SMP Mode...\n");
 	/* let other processors know to not do certain initialization */
 	first_cpu_booted = 1;
+	smp_num_cpus = 1;
 	
 	/*
 	 * assume for now that the first cpu booted is
 	 * cpu 0, the master -- Cort
 	 */
 	cpu_callin_map[0] = 1;
-	cpu_callin_map[1] = 0;
         smp_store_cpu_info(0);
         active_kernel_processor = 0;
 	current->processor = 0;
@@ -282,16 +283,12 @@
 	{
 	case _MACH_Pmac:
 		/* assume powersurge board - 2 processors -- Cort */
-		smp_num_cpus = 2; 
+		cpu_nr = 2; 
 		break;
 	case _MACH_chrp:
-		smp_num_cpus = ((openpic_read(&OpenPIC->Global.Feature_Reporting0)
+		cpu_nr = ((openpic_read(&OpenPIC->Global.Feature_Reporting0)
 				 & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
 				OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1;
-		/* get our processor # - we may not be cpu 0 */
-		printk("SMP %d processors, boot CPU is %d (should be 0)\n",
-		       smp_num_cpus,
-		       10/*openpic_read(&OpenPIC->Processor[0]._Who_Am_I)*/);
 		break;
 	}
 
@@ -299,7 +296,7 @@
 	 * only check for cpus we know exist.  We keep the callin map
 	 * with cpus at the bottom -- Cort
 	 */
-	for ( i = 1 ; i < smp_num_cpus; i++ )
+	for ( i = 1 ; i < cpu_nr; i++ )
 	{
 		int c;
 		
@@ -332,6 +329,19 @@
 		case _MACH_chrp:
 			*(unsigned long *)KERNELBASE = i;
 			asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+#if 0
+			device = find_type_devices("cpu");
+			/* assume cpu device list is in order, find the ith cpu */
+			for ( a = i; device && a; device = device->next, a-- )
+				;
+			if ( !device )
+				break;
+			printk( "Starting %s (%lu): ", device->full_name,
+				*(ulong *)get_property(device, "reg", NULL) );
+			call_rtas( "start-cpu", 3, 1, NULL,
+				   *(ulong *)get_property(device, "reg", NULL),
+				   __pa(__secondary_start_chrp), i);
+#endif			
 			break;
 		}
 		
@@ -349,6 +359,7 @@
 			/* this sync's the decr's -- Cort */
 			if ( _machine == _MACH_Pmac )
 				set_dec(decrementer_count);
+			smp_num_cpus++;
 		} else {
 			printk("Processor %d is stuck.\n", i);
 		}
@@ -366,7 +377,6 @@
 
 void __init smp_commence(void)
 {
-	printk("SMP %d: smp_commence()\n",current->processor);
 	/*
 	 *	Lets the callin's below out of their loop.
 	 */
@@ -381,16 +391,12 @@
 /* Activate a secondary processor. */
 asmlinkage int __init start_secondary(void *unused)
 {
-	printk("SMP %d: start_secondary()\n",current->processor);
 	smp_callin();
 	return cpu_idle(NULL);
 }
 
 void __init smp_callin(void)
 {
-	int i;
-	
-	printk("SMP %d: smp_callin()\n",current->processor);
         smp_store_cpu_info(current->processor);
 	set_dec(decrementer_count);
 	
@@ -407,7 +413,6 @@
 
 void __init smp_setup(char *str, int *ints)
 {
-	printk("SMP %d: smp_setup()\n",current->processor);
 }
 
 int __init setup_profiling_timer(unsigned int multiplier)
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.3.8/linux/arch/ppc/kernel/syscalls.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/syscalls.c	Mon Jun 28 13:40:39 1999
@@ -33,6 +33,7 @@
 #include <linux/sys.h>
 #include <linux/ipc.h>
 #include <linux/utsname.h>
+#include <linux/file.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -201,12 +202,16 @@
 
 	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
-		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+		if (!(file = fget(fd)))
 			goto out;
 	}
 	
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+	down(&current->mm->mmap_sem);
 	ret = do_mmap(file, addr, len, prot, flags, offset);
+	up(&current->mm->mmap_sem);
+	if (file)
+		fput(file);
 out:
 	unlock_kernel();
 	return ret;
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.3.8/linux/arch/ppc/kernel/time.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/kernel/time.c	Mon Jun 28 13:40:39 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: time.c,v 1.48 1999/05/22 19:35:57 cort Exp $
+ * $Id: time.c,v 1.50 1999/06/05 00:23:20 cort Exp $
  * Common time routines among all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -126,17 +126,9 @@
 	smp_local_timer_interrupt(regs);
 #endif		
 
-#ifdef CONFIG_APUS
-	{
-		extern void apus_heartbeat (void);
-		apus_heartbeat ();
-	}
-#endif
-#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP)
-	if ( _machine == _MACH_chrp )
-		chrp_event_scan();
-#endif	
-
+	if ( ppc_md.heartbeat && !ppc_md.heartbeat_count--)
+		ppc_md.heartbeat();
+	
 	hardirq_exit(cpu);
 }
 
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/mbx_defconfig linux/arch/ppc/mbx_defconfig
--- v2.3.8/linux/arch/ppc/mbx_defconfig	Wed Mar 10 21:30:32 1999
+++ linux/arch/ppc/mbx_defconfig	Sat Jun 26 08:34:19 1999
@@ -70,7 +70,7 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
-CONFIG_IDEDMA_AUTO=y
+CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
 # CONFIG_BLK_DEV_NS87415 is not set
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.3.8/linux/arch/ppc/mm/init.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/mm/init.c	Tue Jun 29 09:22:08 1999
@@ -1,5 +1,5 @@
 /*
- *  $Id: init.c,v 1.166 1999/05/22 18:18:30 cort Exp $
+ *  $Id: init.c,v 1.170 1999/06/29 12:33:51 davem Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -254,7 +254,6 @@
 	printk("%d pages shared\n",shared);
 	printk("%d pages swap cached\n",cached);
 	printk("%d pages in page table cache\n",(int)pgtable_cache_size);
-	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
@@ -265,12 +264,15 @@
 #endif /* __SMP__ */
 	printk("\n");
 	for_each_task(p)
-	{	
+	{
 		printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ",
 		       p->comm,p->pid,
-		       atomic_read(&p->mm->count),p->mm->context,
-		       p->mm->context<<4, p->tss.last_syscall,
-		       user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
+		       (p->mm)?atomic_read(&p->mm->count):0,
+		       (p->mm)?p->mm->context:0,
+		       (p->mm)?(p->mm->context<<4):0,
+		       p->tss.last_syscall,
+		       (p->tss.regs)?user_mode(p->tss.regs) ? 'u' : 'k' : '?',
+		       (p->tss.regs)?p->tss.regs->nip:0,
 		       (ulong)p);
 		{
 			int iscur = 0;
@@ -282,7 +284,7 @@
 				iscur = 1;
 				printk("current");
 			}
-#else		
+#else
 			if ( p == current )
 			{
 				iscur = 1;
@@ -309,7 +311,7 @@
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
-	val->bufferram = buffermem;
+	val->bufferram = atomic_read(&buffermem);
 	while (i-- > 0)  {
 		if (PageReserved(mem_map+i))
 			continue;
@@ -346,6 +348,13 @@
 	size = PAGE_ALIGN(addr + size) - p;
 
 	/*
+	 * If the address lies within the first 16 MB, assume it's in ISA
+	 * memory space
+	 */
+	if (p < 16*1024*1024)
+	    p += _ISA_MEM_BASE;
+
+	/*
 	 * Don't allow anybody to remap normal RAM that we're using.
 	 * mem_init() sets high_memory so only do the check after that.
 	 */
@@ -371,7 +380,7 @@
 	 * same virt address (and this is contiguous).
 	 *  -- Cort
 	 */
-	if ( (v = p_mapped_by_bats(addr)) /*&& p_mapped_by_bats(addr+(size-1))*/ )
+	if ( (v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ )
 		goto out;
 #endif /* CONFIG_8xx */
 	
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig
--- v2.3.8/linux/arch/ppc/pmac_defconfig	Wed Mar 10 21:30:32 1999
+++ linux/arch/ppc/pmac_defconfig	Sat Jun 26 08:34:19 1999
@@ -78,7 +78,7 @@
 CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_BLK_DEV_IDEDMA_PMAC=y
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_PMAC_IDEDMA_AUTO=y
+CONFIG_IDEDMA_PMAC_AUTO=y
 # CONFIG_IDE_CHIPSETS is not set
 
 #
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c
--- v2.3.8/linux/arch/ppc/xmon/start.c	Wed May 26 16:55:40 1999
+++ linux/arch/ppc/xmon/start.c	Mon Jun 28 13:40:39 1999
@@ -32,7 +32,7 @@
 #ifdef CHRP_ESCC
 		unsigned long addr = 0xc1013020;
 #else
-		unsigned long addr = 0xf3013030;
+		unsigned long addr = 0xf3013020;
 #endif
 		TXRDY = 4;
 		RXRDY = 1;
diff -u --recursive --new-file v2.3.8/linux/arch/ppc/xmon/xmon.c linux/arch/ppc/xmon/xmon.c
--- v2.3.8/linux/arch/ppc/xmon/xmon.c	Mon Jun  7 12:11:51 1999
+++ linux/arch/ppc/xmon/xmon.c	Mon Jun 28 13:40:39 1999
@@ -91,7 +91,6 @@
 static char *help_string = "\
 Commands:\n\
   d	dump bytes\n\
-  dc	dump characters\n\
   di	dump instructions\n\
   df	dump float values\n\
   dd	dump double values\n\
@@ -518,7 +517,7 @@
 {
 	printf("vector: %x at pc = %x, msr = %x, sp = %x [%x]\n",
 	       fp->trap, fp->nip, fp->msr, fp->gpr[1], fp);
-	if ((fp->trap == 0x300) || (fp->trap == 0x600) || (fp->trap == 0x200))
+	if (fp->trap == 0x300 || fp->trap == 0x600)
 		printf("dar = %x, dsisr = %x\n", fp->dar, fp->dsisr);
 	if (current)
 		printf("current = %x, pid = %d, comm = %s\n",
@@ -991,15 +990,16 @@
 	return c;
 }
 
-#define isxdigit(c)	('0' <= (c) && (c) <= '9' || 'a' <= (c) && (c) <= 'f' \
-			 || 'A' <= (c) && (c) <= 'F')
+#define isxdigit(c)	(('0' <= (c) && (c) <= '9') \
+			 || ('a' <= (c) && (c) <= 'f') \
+			 || ('A' <= (c) && (c) <= 'F'))
 void
 dump()
 {
 	int c;
 
 	c = inchar();
-	if ((isxdigit(c) && (c != 'f') && (c != 'd')) || (c == '\n'))
+	if ((isxdigit(c) && c != 'f' && c != 'd') || c == '\n')
 		termch = c;
 	scanhex(&adrs);
 	if( termch != '\n')
diff -u --recursive --new-file v2.3.8/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.3.8/linux/arch/sparc/config.in	Mon Mar 15 16:10:43 1999
+++ linux/arch/sparc/config.in	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.68 1999/03/14 03:12:42 anton Exp $
+# $Id: config.in,v 1.69 1999/06/25 11:00:20 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -72,9 +72,6 @@
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
-fi
 endmenu
 
 mainmenu_option next_comment
diff -u --recursive --new-file v2.3.8/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.3.8/linux/arch/sparc/defconfig	Thu Jun 17 01:08:50 1999
+++ linux/arch/sparc/defconfig	Fri Jun 25 01:05:12 1999
@@ -80,7 +80,6 @@
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
-CONFIG_BINFMT_JAVA=m
 
 #
 # Floppy, IDE, and other block devices
diff -u --recursive --new-file v2.3.8/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.3.8/linux/arch/sparc/kernel/sys_sunos.c	Thu Jun 17 01:08:50 1999
+++ linux/arch/sparc/kernel/sys_sunos.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.99 1999/06/11 11:40:39 davem Exp $
+/* $Id: sys_sunos.c,v 1.101 1999/06/29 12:33:54 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -196,7 +196,7 @@
 	 * simple, it hopefully works in most obvious cases.. Easy to
 	 * fool it, but this should catch most mistakes.
 	 */
-	freepages = buffermem >> PAGE_SHIFT;
+	freepages = atomic_read(&buffermem) >> PAGE_SHIFT;
 	freepages += atomic_read(&page_cache_size);
 	freepages >>= 1;
 	freepages += nr_free_pages;
diff -u --recursive --new-file v2.3.8/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.3.8/linux/arch/sparc/mm/init.c	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc/mm/init.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.65 1999/04/09 16:28:03 davem Exp $
+/*  $Id: init.c,v 1.67 1999/06/29 12:33:59 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -106,7 +106,6 @@
 	printk("%ld page tables cached\n",pgtable_cache_size);
 	if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d)
 		printk("%ld page dirs cached\n", pgd_cache_size);
-	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
@@ -245,7 +244,7 @@
 	struct page *page, *end;
 
 	/* Saves us work later. */
-	memset((void *) ZERO_PAGE, 0, PAGE_SIZE);
+	memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE);
 
 	end_mem &= PAGE_MASK;
 	max_mapnr = MAP_NR(end_mem);
@@ -363,7 +362,7 @@
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = nr_free_pages << PAGE_SHIFT;
-	val->bufferram = buffermem;
+	val->bufferram = atomic_read(&buffermem);
 	for (page = mem_map, end = mem_map + max_mapnr;
 	     page < end; page++) {
 		if (PageSkip(page)) {
diff -u --recursive --new-file v2.3.8/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.3.8/linux/arch/sparc64/config.in	Thu Apr 22 19:24:51 1999
+++ linux/arch/sparc64/config.in	Sat Jun 26 08:34:19 1999
@@ -62,10 +62,7 @@
   tristate 'Kernel support for 32-bit ELF binaries' CONFIG_BINFMT_ELF32
   bool 'Kernel support for 32-bit (ie. SunOS) a.out binaries' CONFIG_BINFMT_AOUT32
 fi
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-  tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
-fi
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL
 fi
@@ -120,7 +117,7 @@
 	  dep_tristate '   SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE
 	  define_bool CONFIG_BLK_DEV_IDEPCI y
 	  define_bool CONFIG_BLK_DEV_IDEDMA y
-	  define_bool CONFIG_IDEDMA_AUTO y
+	  define_bool CONFIG_IDEDMA_PCI_AUTO y
 	  define_bool CONFIG_BLK_DEV_NS87415 y
 	  define_bool CONFIG_BLK_DEV_CMD646 y
 	fi
diff -u --recursive --new-file v2.3.8/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.3.8/linux/arch/sparc64/defconfig	Thu Jun 17 01:08:50 1999
+++ linux/arch/sparc64/defconfig	Sat Jun 26 08:34:19 1999
@@ -91,7 +91,6 @@
 CONFIG_BINFMT_ELF32=y
 # CONFIG_BINFMT_AOUT32 is not set
 CONFIG_BINFMT_MISC=m
-CONFIG_BINFMT_JAVA=m
 CONFIG_SOLARIS_EMUL=m
 CONFIG_PARPORT=m
 CONFIG_PARPORT_AX=m
@@ -122,7 +121,7 @@
 # CONFIG_BLK_DEV_IDESCSI is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_BLK_DEV_IDEDMA=y
-CONFIG_IDEDMA_AUTO=y
+CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_NS87415=y
 CONFIG_BLK_DEV_CMD646=y
 
diff -u --recursive --new-file v2.3.8/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c
--- v2.3.8/linux/arch/sparc64/kernel/binfmt_aout32.c	Wed Jun  9 14:44:25 1999
+++ linux/arch/sparc64/kernel/binfmt_aout32.c	Tue Jun 22 20:25:28 1999
@@ -55,8 +55,15 @@
  * These are the only things you should do on a core-file: use only these
  * macros to write out all the necessary info.
  */
-#define DUMP_WRITE(addr,nr) \
-while (file->f_op->write(file,(char *)(addr),(nr),&file->f_pos) != (nr)) goto close_coredump
+
+static int dump_write(struct file *file, const void *addr, int nr)
+{
+	return file->f_op->write(file, addr, nr, &file->f_pos) == nr;
+}
+
+#define DUMP_WRITE(addr, nr)	\
+	if (!dump_write(file, (void *)(addr), (nr))) \
+		goto close_coredump;
 
 #define DUMP_SEEK(offset) \
 if (file->f_op->llseek) { \
diff -u --recursive --new-file v2.3.8/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.3.8/linux/arch/sparc64/kernel/process.c	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/kernel/process.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.94 1999/05/27 04:49:30 davem Exp $
+/*  $Id: process.c,v 1.95 1999/06/28 08:48:51 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -392,7 +392,7 @@
 	}
 
 	printk("flags:             0x%08x\n", tss->flags);
-	printk("current_ds:        0x%016lx\n", tss->current_ds.seg);
+	printk("current_ds:        0x%x\n", tss->current_ds.seg);
 }
 
 /* Free current thread data structures etc.. */
diff -u --recursive --new-file v2.3.8/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.3.8/linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue May 11 08:24:32 1999
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.58 1999/05/08 03:00:31 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.59 1999/06/28 11:28:50 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -206,6 +206,7 @@
 
 /* Kernel thread creation. */
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(init_mm);
 
 /* prom symbols */
 EXPORT_SYMBOL(idprom);
diff -u --recursive --new-file v2.3.8/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.3.8/linux/arch/sparc64/kernel/sys_sparc32.c	Wed Jun  9 14:44:25 1999
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.109 1999/06/03 07:11:31 davem Exp $
+/* $Id: sys_sparc32.c,v 1.112 1999/06/29 12:34:02 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -855,17 +855,15 @@
 	long ret = -EBADF;
 
 	lock_kernel();
+
 	file = fget(fd);
 	if(!file)
 		goto bad_file;
 
-	if(!(file->f_mode & 1))
-		goto out;
-
-	ret = do_readv_writev32(VERIFY_WRITE, file,
-				vector, count);
-out:
+	if (file->f_op && file->f_op->read && (file->f_mode & FMODE_READ))
+		ret = do_readv_writev32(VERIFY_WRITE, file, vector, count);
 	fput(file);
+
 bad_file:
 	unlock_kernel();
 	return ret;
@@ -877,19 +875,14 @@
 	int ret = -EBADF;
 
 	lock_kernel();
+
 	file = fget(fd);
 	if(!file)
 		goto bad_file;
-
-	if(!(file->f_mode & 2))
-		goto out;
-
-	down(&file->f_dentry->d_inode->i_sem);
-	ret = do_readv_writev32(VERIFY_READ, file,
-				vector, count);
-	up(&file->f_dentry->d_inode->i_sem);
-out:
+	if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE))
+		ret = do_readv_writev32(VERIFY_READ, file, vector, count);
 	fput(file);
+
 bad_file:
 	unlock_kernel();
 	return ret;
@@ -2335,7 +2328,7 @@
 			break;
 		}
 		/* Bump the usage count and install the file. */
-		fp[i]->f_count++;
+		atomic_inc(&fp[i]->f_count);
 		current->files->fd[new_fd] = fp[i];
 	}
 
@@ -2841,7 +2834,6 @@
 	bprm.dentry = dentry;
 	bprm.filename = filename;
 	bprm.sh_bang = 0;
-	bprm.java = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
 	if ((bprm.argc = count32(argv)) < 0) {
diff -u --recursive --new-file v2.3.8/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c
--- v2.3.8/linux/arch/sparc64/kernel/sys_sunos32.c	Thu Jun 17 01:08:50 1999
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.26 1999/06/09 08:23:54 davem Exp $
+/* $Id: sys_sunos32.c,v 1.28 1999/06/29 12:34:04 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -163,7 +163,7 @@
 	 * simple, it hopefully works in most obvious cases.. Easy to
 	 * fool it, but this should catch most mistakes.
 	 */
-	freepages = buffermem >> PAGE_SHIFT;
+	freepages = atomic_read(&buffermem) >> PAGE_SHIFT;
 	freepages += atomic_read(&page_cache_size);
 	freepages >>= 1;
 	freepages += nr_free_pages;
diff -u --recursive --new-file v2.3.8/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.3.8/linux/arch/sparc64/mm/init.c	Thu May 27 09:55:21 1999
+++ linux/arch/sparc64/mm/init.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.128 1999/05/25 16:53:24 jj Exp $
+/*  $Id: init.c,v 1.130 1999/06/29 12:34:06 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -147,7 +147,6 @@
 #ifndef __SMP__
 	printk("%d entries in page dir cache\n",pgd_cache_size);
 #endif	
-	show_buffers();
 #ifdef CONFIG_NET
 	show_net_buffers();
 #endif
@@ -419,10 +418,12 @@
 	}
 
 	if (iommu->strbuf_enabled) {
+		volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
+
 		spin_lock_irqsave(&iommu->iommu_lock, flags);
 		iommu->flushflag = 0;
 		while(start < end) {
-			sregs->sbuf_pflush = start;
+			*sbuf_pflush = start;
 			start += PAGE_SIZE;
 		}
 		sregs->sbuf_fsync = __pa(&(iommu->flushflag));
@@ -447,6 +448,8 @@
 	start &= PAGE_MASK;
 
 	if (iommu->strbuf_enabled) {
+		volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
+
 		spin_lock_irqsave(&iommu->iommu_lock, flags);
 
 		/* 1) Clear the flush flag word */
@@ -456,7 +459,7 @@
 		 *    we want flushed.
 		 */
 		while(start < end) {
-			sregs->sbuf_pflush = start;
+			*sbuf_pflush = start;
 			start += PAGE_SIZE;
 		}
 
@@ -484,6 +487,8 @@
 	volatile u64 *sbctrl = (volatile u64 *) &sregs->sbus_control;
 
 	if (iommu->strbuf_enabled) {
+		volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
+
 		spin_lock_irqsave(&iommu->iommu_lock, flags);
 		iommu->flushflag = 0;
 
@@ -500,7 +505,7 @@
 			sg[sz--].dvma_addr = sbus_dvma_addr(start);
 			start &= PAGE_MASK;
 			while(start < end) {
-				sregs->sbuf_pflush = start;
+				*sbuf_pflush = start;
 				start += PAGE_SIZE;
 			}
 		}
@@ -535,6 +540,8 @@
 	unsigned long flags, tmp;
 
 	if (iommu->strbuf_enabled) {
+		volatile u64 *sbuf_pflush = (volatile u64 *) &sregs->sbuf_pflush;
+
 		spin_lock_irqsave(&iommu->iommu_lock, flags);
 
 		/* 1) Clear the flush flag word */
@@ -549,7 +556,7 @@
 
 			start &= PAGE_MASK;
 			while(start < end) {
-				sregs->sbuf_pflush = start;
+				*sbuf_pflush = start;
 				start += PAGE_SIZE;
 			}
 			sz--;
@@ -1448,7 +1455,7 @@
 	val->totalram = 0;
 	val->sharedram = 0;
 	val->freeram = ((unsigned long)nr_free_pages) << PAGE_SHIFT;
-	val->bufferram = buffermem;
+	val->bufferram = atomic_read(&buffermem);
 	for (page = mem_map, end = mem_map + max_mapnr;
 	     page < end; page++) {
 		if (PageSkip(page)) {
diff -u --recursive --new-file v2.3.8/linux/arch/sparc64/solaris/misc.c linux/arch/sparc64/solaris/misc.c
--- v2.3.8/linux/arch/sparc64/solaris/misc.c	Mon Nov 16 10:37:28 1998
+++ linux/arch/sparc64/solaris/misc.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.13 1998/10/28 08:11:58 jj Exp $
+/* $Id: misc.c,v 1.14 1999/06/25 11:00:53 davem Exp $
  * misc.c: Miscelaneous syscall emulation for Solaris
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -83,6 +83,7 @@
 		}
 	}
 
+	down(&current->mm->mmap_sem);
 	retval = -ENOMEM;
 	if(!(flags & MAP_FIXED) && !addr) {
 		unsigned long attempt = get_unmapped_area(addr, len);
@@ -102,6 +103,7 @@
 	if(!ret_type)
 		retval = ((retval < 0xf0000000) ? 0 : retval);
 out_putf:
+	up(&current->mm->mmap_sem);
 	if (file)
 		fput(file);
 out:
diff -u --recursive --new-file v2.3.8/linux/drivers/Makefile linux/drivers/Makefile
--- v2.3.8/linux/drivers/Makefile	Wed Jun  2 14:40:22 1999
+++ linux/drivers/Makefile	Tue Jun 29 09:12:32 1999
@@ -9,8 +9,9 @@
 
 SUB_DIRS     := block char net misc sound
 MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp \
-				 macintosh video dio zorro fc4 usb
+ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sbus cdrom isdn pnp i2o \
+				macintosh video dio zorro fc4 usb \
+				nubus tc ap1000
 
 ifdef CONFIG_DIO
 SUB_DIRS += dio
@@ -34,6 +35,10 @@
 SUB_DIRS += nubus
 endif
 
+ifdef CONFIG_TC
+SUB_DIRS += tc
+endif
+
 ifdef CONFIG_VT
 SUB_DIRS += video
 MOD_SUB_DIRS += video
@@ -52,6 +57,11 @@
   MOD_SUB_DIRS += usb
   endif
 endif 
+
+ifdef CONFIG_SGI
+SUB_DIRS += sgi
+MOD_SUB_DIRS += sgi
+endif
 
 ifeq ($(CONFIG_I2O),y)
 SUB_DIRS += i2o
diff -u --recursive --new-file v2.3.8/linux/drivers/ap1000/ringbuf.c linux/drivers/ap1000/ringbuf.c
--- v2.3.8/linux/drivers/ap1000/ringbuf.c	Wed Mar 10 16:51:35 1999
+++ linux/drivers/ap1000/ringbuf.c	Sun Jun 27 10:10:41 1999
@@ -318,9 +318,12 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.3.8/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.8/linux/drivers/block/Config.in	Thu Jun 17 01:11:35 1999
+++ linux/drivers/block/Config.in	Sat Jun 26 08:34:19 1999
@@ -75,7 +75,7 @@
         if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
           bool '     PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
           if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
-            bool '     Use DMA by default' CONFIG_PMAC_IDEDMA_AUTO
+            bool '     Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO
           fi
        fi
     fi
@@ -93,6 +93,11 @@
          "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" -o \
          "$CONFIG_BLK_DEV_IDEDMA_ICS" = "y" ]; then
       define_bool CONFIG_BLK_DEV_IDEDMA y
+      if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \
+           "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \
+           "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then
+        define_bool CONFIG_IDEDMA_AUTO y
+      fi
     fi
     bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
     if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
diff -u --recursive --new-file v2.3.8/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.3.8/linux/drivers/block/genhd.c	Sat May 15 23:43:04 1999
+++ linux/drivers/block/genhd.c	Sat Jun 26 18:23:36 1999
@@ -221,11 +221,6 @@
 			return;
 		if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
 			return;
-	  /*
-	   * This block is from a device that we're about to stomp on.
-	   * So make sure nobody thinks this block is usable.
-	   */
-		bh->b_state = 0;
 
 		if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
 			goto done;
@@ -285,10 +280,12 @@
 		hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size;
 		this_sector = first_sector + START_SECT(p) * sector_size;
 		dev = MKDEV(hd->major, current_minor);
-		brelse(bh);
+
+		/* Use bforget(), as we have changed the disk geometry */
+		bforget(bh);
 	}
 done:
-	brelse(bh);
+	bforget(bh);
 }
 
 #ifdef CONFIG_SOLARIS_X86_PARTITION
@@ -386,7 +383,6 @@
 
 	if (!(bh = bread(dev,0,get_ptable_blocksize(dev))))
 		return;
-	bh->b_state = 0;
 	l = (struct bsd_disklabel *) (bh->b_data+512);
 	if (l->d_magic != BSD_DISKMAGIC) {
 		brelse(bh);
@@ -402,7 +398,9 @@
 		if (p->p_fstype != BSD_FS_UNUSED) 
 			check_and_add_bsd_partition(hd, p, dev);
 	}
-	brelse(bh);
+
+	/* Use bforget(), as we have changed the disk setup */
+	bforget(bh);
 
 }
 #endif
@@ -421,7 +419,6 @@
 
 	if (!(bh = bread(dev, 14, get_ptable_blocksize(dev))))
 		return;
-	bh->b_state = 0;
 	l = (struct unixware_disklabel *) (bh->b_data+512);
 	if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
 	    le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
@@ -441,7 +438,8 @@
 		}
 		p++;
 	}
-	brelse(bh);
+	/* Use bforget, as we have changed the disk setup */
+	bforget(bh);
 	printk(" >");
 }
 #endif
@@ -469,15 +467,12 @@
 		return -1;
 	}
 	data = bh->b_data;
-	/* In some cases we modify the geometry    */
-	/*  of the drive (below), so ensure that   */
-	/*  nobody else tries to re-use this data. */
-	bh->b_state = 0;
 #ifdef CONFIG_BLK_DEV_IDE
 check_table:
 #endif
+	/* Use bforget(), because we have potentially changed the disk geometry */
 	if (*(unsigned short *)  (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
-		brelse(bh);
+		bforget(bh);
 		return 0;
 	}
 	p = (struct partition *) (0x1be + data);
@@ -515,7 +510,7 @@
 			 * adjustments to fool fdisk/LILO and partition check.
 			 */
 			if (ide_xlate_1024(dev, 1, " [DM6:DDO]")) {
-				brelse(bh);
+				bforget(bh);
 				goto read_mbr;	/* start over with new MBR */
 			}
 		} else if (sig <= 0x1ae &&
@@ -627,7 +622,7 @@
 		}
 	}
 	printk("\n");
-	brelse(bh);
+	bforget(bh);
 	return 1;
 }
 
diff -u --recursive --new-file v2.3.8/linux/drivers/block/icside.c linux/drivers/block/icside.c
--- v2.3.8/linux/drivers/block/icside.c	Thu Jun 17 01:11:35 1999
+++ linux/drivers/block/icside.c	Wed Jun 30 11:24:54 1999
@@ -10,6 +10,7 @@
  *  22-May-1999	RMK	Added support for V6 DMA
  */
 
+#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.3.8/linux/drivers/block/ide-disk.c	Fri May 28 09:34:41 1999
+++ linux/drivers/block/ide-disk.c	Sat Jun 26 08:34:19 1999
@@ -856,11 +856,16 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL)
+	while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) {
 		if (idedisk_cleanup (drive)) {
 			printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name);
 			failed++;
 		}
+		/* We must remove proc entries defined in this module.
+		   Otherwise we oops while accessing these entries */
+		if (drive->proc)
+			ide_remove_proc_entries(drive->proc, idedisk_proc);
+	}
 	ide_unregister_module(&idedisk_module);
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.3.8/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.3.8/linux/drivers/block/ide-floppy.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/ide-floppy.c	Sat Jun 26 08:34:19 1999
@@ -1630,11 +1630,16 @@
 	ide_drive_t *drive;
 	int failed = 0;
 
-	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL)
+	while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) {
 		if (idefloppy_cleanup (drive)) {
 			printk ("%s: cleanup_module() called while still busy\n", drive->name);
 			failed++;
 		}
+		/* We must remove proc entries defined in this module.
+		   Otherwise we oops while accessing these entries */
+		if (drive->proc)
+			ide_remove_proc_entries(drive->proc, idefloppy_proc);
+	}
 	ide_unregister_module(&idefloppy_module);
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.3.8/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c
--- v2.3.8/linux/drivers/block/ide-pci.c	Fri May 14 18:50:32 1999
+++ linux/drivers/block/ide-pci.c	Sat Jun 26 08:34:19 1999
@@ -29,6 +29,7 @@
 #define DEVID_PIIXb	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371FB_1})
 #define DEVID_PIIX3	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371SB_1})
 #define DEVID_PIIX4	((ide_pci_devid_t){PCI_VENDOR_ID_INTEL,   PCI_DEVICE_ID_INTEL_82371AB})
+#define DEVID_VIA_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C561})
 #define DEVID_VP_IDE	((ide_pci_devid_t){PCI_VENDOR_ID_VIA,     PCI_DEVICE_ID_VIA_82C586_1})
 #define DEVID_PDC20246	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246})
 #define DEVID_PDC20262	((ide_pci_devid_t){PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262})
@@ -190,6 +191,7 @@
 	{DEVID_PIIXb,	"PIIX",		NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
 	{DEVID_PIIX3,	"PIIX3",	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
 	{DEVID_PIIX4,	"PIIX4",	NULL,		INIT_PIIX,	NULL,		{{0x41,0x80,0x80}, {0x43,0x80,0x80}}, 	ON_BOARD,	0 },
+	{DEVID_VIA_IDE,	"VIA_IDE",	NULL,		NULL,		NULL,		{{0x00,0x00,0x00}, {0x00,0x00,0x00}},	ON_BOARD,	0 },
 	{DEVID_VP_IDE,	"VP_IDE",	NULL,		INIT_VIA82C586,	DMA_VIA82C586,	{{0x40,0x02,0x02}, {0x40,0x01,0x01}}, 	ON_BOARD,	0 },
 	{DEVID_PDC20246,"PDC20246",	PCI_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}}, 	OFF_BOARD,	16 },
 	{DEVID_PDC20262,"PDC20262",	PCI_PDC202XX,	INIT_PDC202XX,	NULL,		{{0x50,0x02,0x02}, {0x50,0x04,0x04}},	OFF_BOARD,	48 },
@@ -548,6 +550,8 @@
 			continue;	/* OPTI Viper-M uses same devid for functions 0 and 1 */
 		else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_CY82C693) && (!(PCI_FUNC(dev->devfn) & 1) || !((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)))
 			continue;	/* CY82C693 is more than only a IDE controller */
+		else if (IDE_PCI_DEVID_EQ(d->devid, DEVID_UM8886A) && !(PCI_FUNC(dev->devfn) & 1))
+			continue;	/* UM8886A/BF pair */
 		else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
 			if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
 				printk("%s: unknown IDE controller on PCI bus %02x device %02x, VID=%04x, DID=%04x\n",
diff -u --recursive --new-file v2.3.8/linux/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- v2.3.8/linux/drivers/block/ide-pmac.c	Mon Jun  7 12:12:22 1999
+++ linux/drivers/block/ide-pmac.c	Sat Jun 26 08:34:19 1999
@@ -218,9 +218,9 @@
 	}
 
 	hwif->dmaproc = &pmac_ide_dmaproc;
-#ifdef CONFIG_PMAC_IDEDMA_AUTO
+#ifdef CONFIG_IDEDMA_PMAC_AUTO
 	hwif->autodma = 1;
-#endif
+#endif /* CONFIG_IDEDMA_PMAC_AUTO */
 }
 
 /*
diff -u --recursive --new-file v2.3.8/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.3.8/linux/drivers/block/ide-probe.c	Fri May 28 09:34:41 1999
+++ linux/drivers/block/ide-probe.c	Sat Jun 26 08:34:19 1999
@@ -845,7 +845,9 @@
 	
 	for (index = 0; index < MAX_HWIFS; ++index)
 		ide_unregister(index);
-	return ideprobe_init();
+	ideprobe_init();
+	create_proc_ide_interfaces();
+	return 0;
 }
 
 void cleanup_module (void)
diff -u --recursive --new-file v2.3.8/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c
--- v2.3.8/linux/drivers/block/ide-proc.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/ide-proc.c	Tue Jun 29 09:12:32 1999
@@ -112,6 +112,8 @@
 	return -EINVAL;
 }
 
+static struct proc_dir_entry * proc_ide_root = NULL;
+
 static int proc_ide_write_config
 	(struct file *file, const char *buffer, unsigned long count, void *data)
 {
@@ -384,7 +386,7 @@
 	ide_drive_t	*drive = (ide_drive_t *)data;
 	int		len = 0, i = 0;
 
-	if (!proc_ide_get_identify(drive, page)) {
+	if (drive && !proc_ide_get_identify(drive, page)) {
 		unsigned short *val = ((unsigned short *)page) + 2;
 		char *out = ((char *)val) + (SECTOR_WORDS * 4);
 		page = out;
@@ -394,6 +396,8 @@
 		} while (i < (SECTOR_WORDS * 2));
 		len = out - page;
 	}
+	else
+		len = sprintf(page, "\n");
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
@@ -525,8 +529,8 @@
 	char		*out = page;
 	int		len;
 
-	out += sprintf(out,"physical     %hi/%hi/%hi\n", drive->cyl, drive->head, drive->sect);
-	out += sprintf(out,"logical      %hi/%hi/%hi\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
+	out += sprintf(out,"physical     %d/%d/%d\n", drive->cyl, drive->head, drive->sect);
+	out += sprintf(out,"logical      %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect);
 	len = out - page;
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
@@ -634,21 +638,30 @@
 	return sprintf(page, "ide%d/%s", n, de->name);
 }
 
-static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent, struct proc_dir_entry *root)
+static void create_proc_ide_drives(ide_hwif_t *hwif)
 {
 	int	d;
 	struct proc_dir_entry *ent;
+	struct proc_dir_entry *parent = hwif->proc;
 
 	for (d = 0; d < MAX_DRIVES; d++) {
 		ide_drive_t *drive = &hwif->drives[d];
+		ide_driver_t *driver = drive->driver;
 
 		if (!drive->present)
 			continue;
-		drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
 		if (drive->proc)
-			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+			continue;
 
-		ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, root);
+		drive->proc = create_proc_entry(drive->name, S_IFDIR, parent);
+		if (drive->proc) {
+			ide_add_proc_entries(drive->proc, generic_drive_entries, drive);
+			if (driver) {
+				ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive);
+				ide_add_proc_entries(drive->proc, driver->proc, drive);
+			}
+		}
+		ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, proc_ide_root);
 		if (!ent) return;
 		ent->data = drive;
 		ent->readlink_proc = proc_ide_readlink;
@@ -656,6 +669,25 @@
 	}
 }
 
+void destroy_proc_ide_drives(ide_hwif_t *hwif)
+{
+	int	d;
+
+	for (d = 0; d < MAX_DRIVES; d++) {
+		ide_drive_t *drive = &hwif->drives[d];
+		ide_driver_t *driver = drive->driver;
+
+		if (!drive->proc)
+			continue;
+		if (driver)
+			ide_remove_proc_entries(drive->proc, driver->proc);
+		ide_remove_proc_entries(drive->proc, generic_drive_entries);
+		remove_proc_entry(drive->name, proc_ide_root);
+		remove_proc_entry(drive->name, hwif->proc);
+		drive->proc = NULL;
+	}
+}
+
 static ide_proc_entry_t hwif_entries[] = {
 	{ "channel",	S_IFREG|S_IRUGO,	proc_ide_read_channel,	NULL },
 	{ "config",	S_IFREG|S_IRUGO|S_IWUSR,proc_ide_read_config,	proc_ide_write_config },
@@ -664,42 +696,67 @@
 	{ NULL,	0, NULL, NULL }
 };
 
-static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
+void create_proc_ide_interfaces(void)
 {
 	int	h;
-	struct proc_dir_entry *hwif_ent;
 
 	for (h = 0; h < MAX_HWIFS; h++) {
 		ide_hwif_t *hwif = &ide_hwifs[h];
+		int exist = (hwif->proc != NULL);
 
 		if (!hwif->present)
 			continue;
-		hwif_ent = create_proc_entry(hwif->name, S_IFDIR, parent);
-		if (!hwif_ent) return;
-		ide_add_proc_entries(hwif_ent, hwif_entries, hwif);
-		create_proc_ide_drives(hwif, hwif_ent, parent);
+		if (!exist)
+			hwif->proc = create_proc_entry(hwif->name, S_IFDIR, proc_ide_root);
+		if (!hwif->proc)
+			return;
+		if (!exist)
+			ide_add_proc_entries(hwif->proc, hwif_entries, hwif);
+		create_proc_ide_drives(hwif);
+	}
+}
+
+static void destroy_proc_ide_interfaces(void)
+{
+	int	h;
+
+	for (h = 0; h < MAX_HWIFS; h++) {
+		ide_hwif_t *hwif = &ide_hwifs[h];
+		int exist = (hwif->proc != NULL);
+
+#if 0
+		if (!hwif->present)
+			continue;
+#endif
+		if (exist) {
+			destroy_proc_ide_drives(hwif);
+			ide_remove_proc_entries(hwif->proc, hwif_entries);
+			remove_proc_entry(hwif->name, proc_ide_root);
+			hwif->proc = NULL;
+		} else
+			continue;
 	}
 }
 
 void proc_ide_create(void)
 {
-	struct proc_dir_entry *root, *ent;
-	root = create_proc_entry("ide", S_IFDIR, 0);
-	if (!root) return;
-	create_proc_ide_interfaces(root);
+	struct proc_dir_entry *ent;
+	proc_ide_root = create_proc_entry("ide", S_IFDIR, 0);
+	if (!proc_ide_root) return;
+	create_proc_ide_interfaces();
 
-	ent = create_proc_entry("drivers", 0, root);
+	ent = create_proc_entry("drivers", 0, proc_ide_root);
 	if (!ent) return;
 	ent->read_proc  = proc_ide_read_drivers;
 #ifdef CONFIG_BLK_DEV_VIA82C586
 	if (via_display_info) {
-		ent = create_proc_entry("via", 0, root);
+		ent = create_proc_entry("via", 0, proc_ide_root);
 		ent->get_info = via_display_info;
 	}
 #endif /* CONFIG_BLK_DEV_VIA82C586 */
 #ifdef CONFIG_BLK_DEV_ALI15X3
 	if (ali_display_info) {
-		ent = create_proc_entry("ali", 0, root);
+		ent = create_proc_entry("ali", 0, proc_ide_root);
 		ent->get_info = ali_display_info;
 	}
 #endif /* CONFIG_BLK_DEV_ALI15X3 */
@@ -720,5 +777,6 @@
 		remove_proc_entry("ide/ali",0);
 #endif /* CONFIG_BLK_DEV_ALI15X3 */
 	remove_proc_entry("ide/drivers", 0);
+	destroy_proc_ide_interfaces();
 	remove_proc_entry("ide", 0);
 }
diff -u --recursive --new-file v2.3.8/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c
--- v2.3.8/linux/drivers/block/ide-tape.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/ide-tape.c	Tue Jun 29 09:22:08 1999
@@ -1073,13 +1073,13 @@
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - bh->b_count, bcount);
-		atapi_input_bytes (drive, bh->b_data + bh->b_count, count);
-		bcount -= count; bh->b_count += count;
-		if (bh->b_count == bh->b_size) {
+		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), bcount);
+		atapi_input_bytes (drive, bh->b_data + atomic_read(&bh->b_count), count);
+		bcount -= count; atomic_add(count, &bh->b_count);
+		if (atomic_read(&bh->b_count) == bh->b_size) {
 			bh = bh->b_reqnext;
 			if (bh)
-				bh->b_count = 0;
+				atomic_set(&bh->b_count, 0);
 		}
 	}
 	pc->bh = bh;
@@ -1104,7 +1104,7 @@
 			pc->bh = bh = bh->b_reqnext;
 			if (bh) {
 				pc->b_data = bh->b_data;
-				pc->b_count = bh->b_count;
+				pc->b_count = atomic_read(&bh->b_count);
 			}
 		}
 	}
@@ -1126,8 +1126,8 @@
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
 		count = IDE_MIN (bh->b_size, bcount);
-		bh->b_count = count;
-		if (bh->b_count == bh->b_size)
+		atomic_set(&bh->b_count, count);
+		if (atomic_read(&bh->b_count) == bh->b_size)
 			bh = bh->b_reqnext;
 		bcount -= count;
 	}
@@ -1351,13 +1351,13 @@
 			return;
 		}
 #endif /* IDETAPE_DEBUG_BUGS */
-		count = IDE_MIN (bh->b_size - bh->b_count, n);
-		copy_from_user (bh->b_data + bh->b_count, buf, count);
-		n -= count; bh->b_count += count; buf += count;
-		if (bh->b_count == bh->b_size) {
+		count = IDE_MIN (bh->b_size - atomic_read(&bh->b_count), n);
+		copy_from_user (bh->b_data + atomic_read(&bh->b_count), buf, count);
+		n -= count; atomic_add(count, &bh->b_count); buf += count;
+		if (atomic_read(&bh->b_count) == bh->b_size) {
 			bh = bh->b_reqnext;
 			if (bh)
-				bh->b_count = 0;
+				atomic_set(&bh->b_count, 0);
 		}
 	}
 	tape->bh = bh;
@@ -1382,7 +1382,7 @@
 			tape->bh = bh = bh->b_reqnext;
 			if (bh) {
 				tape->b_data = bh->b_data;
-				tape->b_count = bh->b_count;
+				tape->b_count = atomic_read(&bh->b_count);
 			}
 		}
 	}
@@ -1394,10 +1394,10 @@
 	
 	tape->bh = bh;
 	if (tape->chrdev_direction == idetape_direction_write)
-		bh->b_count = 0;
+		atomic_set(&bh->b_count, 0);
 	else {
 		tape->b_data = bh->b_data;
-		tape->b_count = bh->b_count;
+		tape->b_count = atomic_read(&bh->b_count);
 	}
 }
 
@@ -2131,7 +2131,7 @@
 	pc->c[1] = 1;
 	pc->callback = &idetape_rw_callback;
 	pc->bh = bh;
-	bh->b_count = 0;
+	atomic_set(&bh->b_count, 0);
 	pc->buffer = NULL;
 	pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
 	if (pc->request_transfer == tape->stage_size)
@@ -2158,7 +2158,7 @@
 	set_bit (PC_WRITING, &pc->flags);
 	pc->bh = bh;
 	pc->b_data = bh->b_data;
-	pc->b_count = bh->b_count;
+	pc->b_count = atomic_read(&bh->b_count);
 	pc->buffer = NULL;
 	pc->request_transfer = pc->buffer_size = length * tape->tape_block_size;
 	if (pc->request_transfer == tape->stage_size)
@@ -2587,9 +2587,9 @@
 		bcount -= count;
 		blocks = count / tape->tape_block_size;
 		while (count) {
-			bh->b_count = IDE_MIN (count, bh->b_size);
-			memset (bh->b_data, 0, bh->b_count);
-			count -= bh->b_count;
+			atomic_set(&bh->b_count, IDE_MIN (count, bh->b_size));
+			memset (bh->b_data, 0, atomic_read(&bh->b_count));
+			count -= atomic_read(&bh->b_count);
 			bh = bh->b_reqnext;
 		}
 		idetape_queue_rw_tail (drive, IDETAPE_WRITE_RQ, blocks, tape->merge_stage->bh);
@@ -2616,8 +2616,8 @@
 		if (tape->merge_stage_size % tape->tape_block_size) {
 			blocks++;
 			i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size;
-			memset (tape->bh->b_data + tape->bh->b_count, 0, i);
-			tape->bh->b_count += i;
+			memset (tape->bh->b_data + atomic_read(&tape->bh->b_count), 0, i);
+			atomic_add(i, &tape->bh->b_count);
 		}
 		(void) idetape_add_chrdev_write_request (drive, blocks);
 		tape->merge_stage_size = 0;
@@ -3814,8 +3814,14 @@
 
 	for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++) {
 		drive = idetape_chrdevs[minor].drive;
-		if (drive != NULL && idetape_cleanup (drive))
-			printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
+		if (drive) {
+			if (idetape_cleanup (drive))
+				printk (KERN_ERR "ide-tape: %s: cleanup_module() called while still busy\n", drive->name);
+			/* We must remove proc entries defined in this module.
+			   Otherwise we oops while accessing these entries */
+			if (drive->proc)
+				ide_remove_proc_entries(drive->proc, idetape_proc);
+		}
 	}
 	ide_unregister_module(&idetape_module);
 }
diff -u --recursive --new-file v2.3.8/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.3.8/linux/drivers/block/ide.c	Fri May 28 09:34:41 1999
+++ linux/drivers/block/ide.c	Sat Jun 26 08:34:20 1999
@@ -1748,6 +1748,13 @@
 	return 1;
 }
 
+#ifdef CONFIG_PROC_FS
+ide_proc_entry_t generic_subdriver_entries[] = {
+	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
+	{ NULL, 0, NULL, NULL }
+};
+#endif
+
 void ide_unregister (unsigned int index)
 {
 	struct gendisk *gd, **gdp;
@@ -1757,6 +1764,7 @@
 	int irq_count = 0, unit, i;
 	unsigned long flags;
 	unsigned int p, minor;
+	ide_hwif_t old_hwif;
 
 	if (index >= MAX_HWIFS)
 		return;
@@ -1793,6 +1801,9 @@
 				invalidate_buffers (devp);
 			}
 		}
+#ifdef CONFIG_PROC_FS
+		destroy_proc_ide_drives(hwif);
+#endif
 	}
 	cli();
 	hwgroup = hwif->hwgroup;
@@ -1875,7 +1886,21 @@
 		kfree(gd->part);
 		kfree(gd);
 	}
+	old_hwif = *hwif;
 	init_hwif_data (index);	/* restore hwif data to pristine status */
+	hwif->hwgroup = old_hwif.hwgroup;
+	hwif->tuneproc = old_hwif.tuneproc;
+	hwif->dmaproc = old_hwif.dmaproc;
+	hwif->dma_base = old_hwif.dma_base;
+	hwif->dma_extra = old_hwif.dma_extra;
+	hwif->config_data = old_hwif.config_data;
+	hwif->select_data = old_hwif.select_data;
+	hwif->irq = old_hwif.irq;
+	hwif->major = old_hwif.major;
+	hwif->proc = old_hwif.proc;
+	hwif->chipset = old_hwif.chipset;
+	hwif->pci_dev = old_hwif.pci_dev;
+	hwif->pci_devid = old_hwif.pci_devid;
 abort:
 	restore_flags(flags);	/* all CPUs */
 }
@@ -1950,6 +1975,9 @@
 
 	if (!initializing) {
 		ide_init_module(IDE_PROBE_MODULE);
+#ifdef CONFIG_PROC_FS
+		create_proc_ide_interfaces();
+#endif
 		ide_init_module(IDE_DRIVER_MODULE);
 	}
 
@@ -1966,7 +1994,6 @@
 int ide_register (int arg1, int arg2, int irq)
 {
 	hw_regs_t hw;
-
 	ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
 	hw.irq = irq;
 	return ide_register_hw(&hw, NULL);
@@ -3239,13 +3266,6 @@
 	return NULL;
 }
 
-#ifdef CONFIG_PROC_FS
-static ide_proc_entry_t generic_subdriver_entries[] = {
-	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },
-	{ NULL, 0, NULL, NULL }
-};
-#endif
-
 int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version)
 {
 	unsigned long flags;
@@ -3401,6 +3421,7 @@
 EXPORT_SYMBOL(ide_add_proc_entries);
 EXPORT_SYMBOL(ide_remove_proc_entries);
 EXPORT_SYMBOL(proc_ide_read_geometry);
+EXPORT_SYMBOL(create_proc_ide_interfaces);
 #endif
 EXPORT_SYMBOL(ide_add_setting);
 EXPORT_SYMBOL(ide_remove_setting);
diff -u --recursive --new-file v2.3.8/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.8/linux/drivers/block/ll_rw_blk.c	Wed Jun 16 19:26:27 1999
+++ linux/drivers/block/ll_rw_blk.c	Tue Jun 29 09:22:08 1999
@@ -17,6 +17,7 @@
 #include <linux/locks.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -322,8 +323,6 @@
 	spin_lock_irqsave(&io_request_lock,flags);
 	current_request = get_queue(req->rq_dev);
 
-	if (req->bh)
-		mark_buffer_clean(req->bh);
 	if (!(tmp = *current_request)) {
 		*current_request = req;
 		if (dev->current_request != &dev->plug)
@@ -385,12 +384,17 @@
 	count = bh->b_size >> 9;
 	sector = bh->b_rsector;
 
-	/* Uhhuh.. Nasty dead-lock possible here.. */
-	if (buffer_locked(bh))
-		return;
-	/* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */
+	/* We'd better have a real physical mapping! */
+	if (!buffer_mapped(bh))
+		BUG();
+
+	/* It had better not be a new buffer by the time we see it */
+	if (buffer_new(bh))
+		BUG();
 
-	lock_buffer(bh);
+	/* Only one thread can actually submit the I/O. */
+	if (test_and_set_bit(BH_Lock, &bh->b_state))
+		return;
 
 	if (blk_size[major]) {
 		unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1;
@@ -425,9 +429,11 @@
 			rw_ahead = 1;
 			rw = WRITE;	/* drop into WRITE */
 		case WRITE:
-			if (!buffer_dirty(bh))   /* Hmmph! Nothing to write */
-				goto end_io;
-			/* We don't allow the write-requests to fill up the
+			if (!test_and_clear_bit(BH_Dirty, &bh->b_state))
+				goto end_io;	/* Hmmph! Nothing to write */
+			refile_buffer(bh);
+			/*
+			 * We don't allow the write-requests to fill up the
 			 * queue completely:  we want some room for reads,
 			 * as they take precedence. The last third of the
 			 * requests are only for reads.
@@ -528,7 +534,6 @@
 			} else
 				continue;
 
-			mark_buffer_clean(bh);
 			spin_unlock_irqrestore(&io_request_lock,flags);
 		    	return;
 
@@ -605,7 +610,7 @@
 	for (i = 0; i < nr; i++) {
 		if (bh[i]->b_size != correct_size) {
 			printk(KERN_NOTICE "ll_rw_block: device %s: "
-			       "only %d-char blocks implemented (%lu)\n",
+			       "only %d-char blocks implemented (%u)\n",
 			       kdevname(bh[0]->b_dev),
 			       correct_size, bh[i]->b_size);
 			goto sorry;
diff -u --recursive --new-file v2.3.8/linux/drivers/block/pdc4030.c linux/drivers/block/pdc4030.c
--- v2.3.8/linux/drivers/block/pdc4030.c	Fri May 28 09:34:41 1999
+++ linux/drivers/block/pdc4030.c	Sat Jun 26 08:34:20 1999
@@ -1,5 +1,5 @@
 /*  -*- linux-c -*-
- *  linux/drivers/block/pdc4030.c	Version 0.11  May 17, 1999
+ *  linux/drivers/block/pdc4030.c	Version 0.90  May 27, 1999
  *
  *  Copyright (C) 1995-1999  Linus Torvalds & authors (see below)
  */
@@ -35,6 +35,8 @@
  *  Version 0.10	Updated for 2.1 series of kernels
  *  Version 0.11	Updated for 2.3 series of kernels
  *			Autodetection code added.
+ *
+ *  Version 0.90	Transition to BETA code. No lost/unexpected interrupts
  */
 
 /*
@@ -68,8 +70,8 @@
  * because I still don't understand what the card is doing with interrupts.
  */
 
-#undef DEBUG_READ
-#undef DEBUG_WRITE
+#define DEBUG_READ
+#define DEBUG_WRITE
 
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -100,7 +102,8 @@
 
 /*
  * pdc4030_cmd handles the set of vendor specific commands that are initiated
- * by command F0. They all have the same success/failure notification.
+ * by command F0. They all have the same success/failure notification -
+ * 'P' (=0x50) on success, 'p' (=0x70) on failure.
  */
 int pdc4030_cmd(ide_drive_t *drive, byte cmd)
 {
@@ -358,11 +361,11 @@
 		if (stat & DRQ_STAT)
 			goto read_again;
 		if (stat & BUSY_STAT) {
+			ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
 #ifdef DEBUG_READ
 			printk(KERN_DEBUG "%s: promise_read: waiting for"
 			       "interrupt\n", drive->name);
 #endif 
-			ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
 			return;
 		}
 		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "
@@ -372,37 +375,39 @@
 }
 
 /*
- * promise_finish_write()
- * called at the end of all writes
+ * promise_complete_pollfunc()
+ * This is the polling function for waiting (nicely!) until drive stops
+ * being busy. It is invoked at the end of a write, after the previous poll
+ * has finished.
+ *
+ * Once not busy, the end request is called.
  */
-static void promise_finish_write(ide_drive_t *drive)
+static void promise_complete_pollfunc(ide_drive_t *drive)
 {
-	struct request *rq = HWGROUP(drive)->rq;
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+	struct request *rq = hwgroup->rq;
 	int i;
 
-	for (i = rq->nr_sectors; i > 0; ) {
-		i -= rq->current_nr_sectors;
-		ide_end_request(1, HWGROUP(drive));
-	}
-}
-
-/*
- * promise_write_intr()
- * This interrupt is called after the particularly odd polling for completion
- * of the write request, once all the data has been sent.
- */ 
-static void promise_write_intr(ide_drive_t *drive)
-{
-	byte stat;
-
-	if (!OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {
-		ide_error(drive, "promise_write_intr", stat);
+	if (GET_STAT() & BUSY_STAT) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
+			ide_set_handler(drive, &promise_complete_pollfunc, 1);
+			return; /* continue polling... */
+		}
+		hwgroup->poll_timeout = 0;
+		printk(KERN_ERR "%s: completion timeout - still busy!\n",
+		       drive->name);
+		ide_error(drive, "busy timeout", GET_STAT());
+		return;
 	}
 
+	hwgroup->poll_timeout = 0;
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);
 #endif
-	promise_finish_write(drive);
+	for (i = rq->nr_sectors; i > 0; ) {
+		i -= rq->current_nr_sectors;
+		ide_end_request(1, hwgroup);
+	}
 }
 
 /*
@@ -410,22 +415,29 @@
  */
 static void promise_write_pollfunc (ide_drive_t *drive)
 {
+	ide_hwgroup_t *hwgroup = HWGROUP(drive);
+
 	if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
-		if (time_before(jiffies, HWGROUP(drive)->poll_timeout)) {
+		if (time_before(jiffies, hwgroup->poll_timeout)) {
 			ide_set_handler (drive, &promise_write_pollfunc, 1);
 			return; /* continue polling... */
 		}
+		hwgroup->poll_timeout = 0;
 		printk(KERN_ERR "%s: write timed-out!\n",drive->name);
 		ide_error (drive, "write timeout", GET_STAT());
 		return;
 	}
 
+	/*
+	 * Now write out last 4 sectors and poll for not BUSY
+	 */
 	ide_multwrite(drive, 4);
+	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+	ide_set_handler(drive, &promise_complete_pollfunc, 1);
 #ifdef DEBUG_WRITE
 	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",
 		drive->name, GET_STAT());
 #endif
-	ide_set_handler(drive, &promise_write_intr, WAIT_CMD);
 	return;
 }
 
@@ -433,8 +445,8 @@
  * promise_write() transfers a block of one or more sectors of data to a
  * drive as part of a disk write operation. All but 4 sectors are transfered
  * in the first attempt, then the interface is polled (nicely!) for completion
- * before the final 4 sectors are transfered. The interrupt generated on 
- * writes occurs after this process, which is why I got it wrong for so long!
+ * before the final 4 sectors are transfered. There is no interrupt generated
+ * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY.
  */
 static void promise_write (ide_drive_t *drive)
 {
@@ -446,18 +458,27 @@
 	       "buffer=0x%08x\n", drive->name, rq->sector,
 	       rq->sector + rq->nr_sectors - 1, (unsigned int)rq->buffer);
 #endif
+
+	/*
+	 * If there are more than 4 sectors to transfer, do n-4 then go into
+	 * the polling strategy as defined above.
+	 */
 	if (rq->nr_sectors > 4) {
 		ide_multwrite(drive, rq->nr_sectors - 4);
 		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 		ide_set_handler (drive, &promise_write_pollfunc, 1);
-		return;
 	} else {
+	/*
+	 * There are 4 or fewer sectors to transfer, do them all in one go
+	 * and wait for NOT BUSY.
+	 */
 		ide_multwrite(drive, rq->nr_sectors);
+		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
+		ide_set_handler(drive, &promise_complete_pollfunc, 1);
 #ifdef DEBUG_WRITE
 		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "
 			"status = %02x\n", drive->name, GET_STAT());
 #endif
-		promise_finish_write(drive);
 	}
 }
 
diff -u --recursive --new-file v2.3.8/linux/drivers/block/raid1.c linux/drivers/block/raid1.c
--- v2.3.8/linux/drivers/block/raid1.c	Tue Dec 22 08:12:38 1998
+++ linux/drivers/block/raid1.c	Tue Jun 29 09:22:08 1999
@@ -310,7 +310,7 @@
 		mirror_bh [i]->b_rdev 	    = raid_conf->mirrors [i].dev;
 		mirror_bh [i]->b_rsector    = bh->b_rsector;
 		mirror_bh [i]->b_state      = (1<<BH_Req) | (1<<BH_Dirty);
-		mirror_bh [i]->b_count      = 1;
+		atomic_set(&mirror_bh [i]->b_count, 1);
 		mirror_bh [i]->b_size       = bh->b_size;
 		mirror_bh [i]->b_data       = bh->b_data;
 		mirror_bh [i]->b_list       = BUF_LOCKED;
diff -u --recursive --new-file v2.3.8/linux/drivers/block/raid5.c linux/drivers/block/raid5.c
--- v2.3.8/linux/drivers/block/raid5.c	Tue May 11 23:37:51 1999
+++ linux/drivers/block/raid5.c	Tue Jun 29 09:22:08 1999
@@ -586,13 +586,15 @@
 
 	b_data = ((volatile struct buffer_head *) bh)->b_data;
 	memset (bh, 0, sizeof (struct buffer_head));
-	init_buffer(bh, dev, block, raid5_end_request, sh);
+	init_buffer(bh, raid5_end_request, sh);
+	bh->b_dev = dev;
+	bh->b_blocknr = block;
 	((volatile struct buffer_head *) bh)->b_data = b_data;
 
 	bh->b_rdev	= raid_conf->disks[i].dev;
 	bh->b_rsector   = sh->sector;
 
-	bh->b_state	= (1 << BH_Req);
+	bh->b_state	= (1 << BH_Req) | (1 << BH_Mapped);
 	bh->b_size	= sh->size;
 	bh->b_list	= BUF_LOCKED;
 }
@@ -1030,19 +1032,24 @@
 				if (sh->bh_new[i])
 					continue;
 				block = (int) compute_blocknr(sh, i);
-				bh = find_buffer(MKDEV(MD_MAJOR, minor), block, sh->size);
-				if (bh && bh->b_count == 0 && buffer_dirty(bh) && !buffer_locked(bh)) {
-					PRINTK(("Whee.. sector %lu, index %d (%d) found in the buffer cache!\n", sh->sector, i, block));
-					add_stripe_bh(sh, bh, i, WRITE);
-					sh->new[i] = 0;
-					nr++; nr_write++;
-					if (sh->bh_old[i]) {
-						nr_cache_overwrite++;
-						nr_cache_other--;
-					} else if (!operational[i]) {
-						nr_failed_overwrite++;
-						nr_failed_other--;
+				bh = get_hash_table(MKDEV(MD_MAJOR, minor), block, sh->size);
+				if (bh) {
+					if (atomic_read(&bh->b_count) == 1 &&
+					    buffer_dirty(bh) &&
+					    !buffer_locked(bh)) {
+						PRINTK(("Whee.. sector %lu, index %d (%d) found in the buffer cache!\n", sh->sector, i, block));
+						add_stripe_bh(sh, bh, i, WRITE);
+						sh->new[i] = 0;
+						nr++; nr_write++;
+						if (sh->bh_old[i]) {
+							nr_cache_overwrite++;
+							nr_cache_other--;
+						} else if (!operational[i]) {
+							nr_failed_overwrite++;
+							nr_failed_other--;
+						}
 					}
+					atomic_dec(&bh->b_count);
 				}
 			}
 		}
diff -u --recursive --new-file v2.3.8/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.3.8/linux/drivers/block/rd.c	Fri Jun  4 01:03:28 1999
+++ linux/drivers/block/rd.c	Fri Jun 25 13:52:10 1999
@@ -173,7 +173,7 @@
 
 	if (CURRENT->cmd == READ) 
 		memset(CURRENT->buffer, 0, len); 
-	else	
+	else
 		set_bit(BH_Protected, &CURRENT->bh->b_state);
 
 	end_request(1);
diff -u --recursive --new-file v2.3.8/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.8/linux/drivers/char/Config.in	Sat May 22 15:02:48 1999
+++ linux/drivers/char/Config.in	Fri Jun 25 17:39:14 1999
@@ -136,6 +136,11 @@
     dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
     dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
   fi
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    if [ "$CONFIG_SGI" = "y" ]; then
+      dep_tristate 'SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV
+    fi
+  fi
   dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
   if [ "$CONFIG_PMAC" = "y" ]; then
     dep_tristate 'PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
diff -u --recursive --new-file v2.3.8/linux/drivers/char/dz.c linux/drivers/char/dz.c
--- v2.3.8/linux/drivers/char/dz.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/dz.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,1602 @@
+/*
+ * dz.c: Serial port driver for DECStations equiped 
+ *       with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif 
+ *             
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ * [31-AUG-98] triemer
+ * Changed IRQ to use Harald's dec internals interrupts.h
+ * removed base_addr code - moving address assignment to setup.c
+ * Changed name of dz_init to rs_init to be consistent with tc code
+ * [13-NOV-98] triemer fixed code to receive characters
+ *    after patches by harald to irq code.  
+ * [09-JAN-99] triemer minor fix for schedule - due to removal of timeout
+ *            field from "current" - somewhere between 2.1.121 and 2.1.131
+ */
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h> 
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/major.h>
+#include <linux/param.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <asm-mips/wbflush.h>
+/* for definition of SERIAL */
+#include <asm/dec/interrupts.h>
+
+/* for definition of struct console */
+#ifdef CONFIG_SERIAL_CONSOLE
+#define CONSOLE_LINE (3)
+#include <linux/console.h>
+#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/kn01.h>
+#include <asm/dec/kn02.h>
+
+#define DEBUG_DZ 1
+#ifdef DEBUG_DZ
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/fs.h>
+#include <asm/bootinfo.h>
+
+extern int (*prom_printf) (char *,...);
+#endif
+
+
+
+#include "dz.h"
+
+#define DZ_INTR_DEBUG 1
+
+DECLARE_TASK_QUEUE(tq_serial);
+
+extern struct wait_queue *keypress_wait;
+static struct dz_serial *lines[4];
+static unsigned char tmp_buffer[256];
+
+
+
+#ifdef DEBUG_DZ
+/*
+ * debugging code to send out chars via prom 
+ */
+static void debug_console( const char *s,int count)
+{
+    unsigned i;
+
+    for (i = 0; i < count; i++) {
+       if (*s == 10)
+           prom_printf("%c", 13);
+       prom_printf("%c", *s++);
+    }
+}
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * dz_in () and dz_out ()
+ *
+ * These routines are used to access the registers of the DZ 
+ * chip, hiding relocation differences between implementation.
+ * ------------------------------------------------------------
+ */
+
+static inline unsigned short dz_in (struct dz_serial *info, unsigned offset)
+{
+  volatile unsigned short *addr = (volatile unsigned short *)(info->port + offset);
+  return *addr;
+}
+
+static inline void dz_out (struct dz_serial *info, unsigned offset, unsigned short value)
+{
+
+    volatile unsigned short *addr = (volatile unsigned short *)(info->port + offset);
+  *addr = value;
+
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop () and rs_start ()
+ *
+ * These routines are called before setting or resetting 
+ * tty->stopped. They enable or disable transmitter interrupts, 
+ * as necessary.
+ * ------------------------------------------------------------
+ */
+
+static void dz_stop (struct tty_struct *tty)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+  unsigned short mask, tmp;
+
+         
+  mask = 1 << info->line;
+  tmp = dz_in (info, DZ_TCR);       /* read the TX flag */
+
+    tmp &= ~mask;                   /* clear the TX flag */
+    dz_out (info, DZ_TCR, tmp);
+}  
+
+static void dz_start (struct tty_struct *tty)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+  unsigned short mask, tmp;
+
+  mask = 1 << info->line;
+  tmp = dz_in (info, DZ_TCR);      /* read the TX flag */
+
+    tmp |= mask;                   /* set the TX flag */
+    dz_out (info, DZ_TCR, tmp);
+
+}  
+
+/*
+ * ------------------------------------------------------------
+ * Here starts the interrupt handling routines.  All of the 
+ * following subroutines are declared as inline and are folded 
+ * into dz_interrupt.  They were separated out for readability's 
+ * sake. 
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer dz.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * ------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * dz_sched_event ()
+ *
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ * ------------------------------------------------------------
+ */
+static inline void dz_sched_event (struct dz_serial *info, int event)
+{
+  info->event |= 1 << event;
+  queue_task (&info->tqueue, &tq_serial);
+  mark_bh (SERIAL_BH);
+}
+
+/*
+ * ------------------------------------------------------------
+ * receive_char ()
+ *
+ * This routine deals with inputs from any lines.
+ * ------------------------------------------------------------
+ */
+static inline void receive_chars (struct dz_serial *info_in)
+{
+
+  struct dz_serial *info;
+  struct tty_struct *tty = 0;
+  struct async_icount *icount;
+  int ignore = 0;
+  unsigned short status, tmp;
+  unsigned char ch;
+
+  /* this code is going to be a problem...
+     the call to tty_flip_buffer is going to need
+     to be rethought...
+   */
+  do
+    {
+      status = dz_in (info_in, DZ_RBUF);
+      info = lines[LINE(status)];
+
+      /* punt so we don't get duplicate characters */
+      if (!(status & DZ_DVAL))
+        goto ignore_char;
+
+
+    ch = UCHAR(status);                /* grab the char */
+
+#ifdef 0
+    if (info->is_console) {
+      if (ch == 0) return;            /* it's a break ... */
+
+      wake_up (&keypress_wait);       /* It is a 'keyboard interrupt' ;-) */
+    }
+#endif
+
+    tty = info->tty;                  /* now tty points to the proper dev */
+    icount = &info->icount;
+
+    if (!tty) break;
+    if (tty->flip.count >= TTY_FLIPBUF_SIZE) break;
+
+    *tty->flip.char_buf_ptr = ch;
+    *tty->flip.flag_buf_ptr = 0;
+    icount->rx++;
+
+    /* keep track of the statistics */
+    if (status & (DZ_OERR | DZ_FERR | DZ_PERR)) {
+      if (status & DZ_PERR)                /* parity error */
+        icount->parity++;
+      else if (status & DZ_FERR)           /* frame error */
+        icount->frame++;
+      if (status & DZ_OERR)                /* overrun error */
+        icount->overrun++;
+
+      /*  check to see if we should ignore the character
+	 and mask off conditions that should be ignored
+      */
+
+      if (status & info->ignore_status_mask) {
+        if (++ignore > 100 ) break;
+        goto ignore_char;
+      }
+
+      /* mask off the error conditions we want to ignore */
+      tmp = status & info->read_status_mask;
+
+      if (tmp & DZ_PERR)
+	{
+        *tty->flip.flag_buf_ptr = TTY_PARITY;
+	  debug_console("PERR\n",5);
+	}
+      else if (tmp & DZ_FERR)
+	{
+        *tty->flip.flag_buf_ptr = TTY_FRAME;
+	  debug_console("FERR\n",5);
+	}
+      if (tmp & DZ_OERR) 
+	{ 
+	  debug_console("OERR\n",5);
+	if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+          tty->flip.count++;
+          tty->flip.flag_buf_ptr++;
+          tty->flip.char_buf_ptr++;
+          *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+        }
+      }
+    }
+    tty->flip.flag_buf_ptr++;
+    tty->flip.char_buf_ptr++;
+    tty->flip.count++;
+  ignore_char:
+  } while (status & DZ_DVAL);
+
+  if (tty)
+    tty_flip_buffer_push(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * transmit_char ()
+ *
+ * This routine deals with outputs to any lines.
+ * ------------------------------------------------------------
+ */
+static inline void transmit_chars (struct dz_serial *info)
+{
+  unsigned char tmp;
+
+
+
+  if (info->x_char) {           /* XON/XOFF chars */
+    dz_out (info, DZ_TDR, info->x_char);
+    info->icount.tx++;
+    info->x_char = 0;
+    return;
+  }
+
+  /* if nothing to do or stopped or hardware stopped */
+  if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tty->hw_stopped) {
+    dz_stop (info->tty);
+    return;
+  }
+
+  /* if something to do ... (rember the dz has no output fifo so we go one char at a time :-< */
+  tmp = (unsigned short)info->xmit_buf[info->xmit_tail++];
+  dz_out (info, DZ_TDR, tmp);
+  info->xmit_tail = info->xmit_tail & (DZ_XMIT_SIZE - 1);
+  info->icount.tx++;
+
+  if (--info->xmit_cnt < WAKEUP_CHARS)
+    dz_sched_event (info, DZ_EVENT_WRITE_WAKEUP);
+
+
+  /* Are we done */
+  if (info->xmit_cnt <= 0) dz_stop (info->tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * check_modem_status ()
+ *
+ * Only valid for the MODEM line duh !
+ * ------------------------------------------------------------
+ */
+static inline void check_modem_status (struct dz_serial *info)
+{
+  unsigned short status;
+
+  /* if not ne modem line just return */
+  if (info->line != DZ_MODEM) return;
+
+  status = dz_in (info, DZ_MSR);
+  
+  /* it's easy, since DSR2 is the only bit in the register */
+  if (status) info->icount.dsr++;
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_interrupt ()
+ *
+ * this is the main interrupt routine for the DZ chip.
+ * It deals with the multiple ports.
+ * ------------------------------------------------------------
+ */
+static void dz_interrupt (int irq, void *dev, struct pt_regs *regs)
+{
+  struct dz_serial *info;
+  unsigned short status;
+
+  status = dz_in ((struct dz_serial *)dev, DZ_CSR); /* get the reason why we just got an irq */
+  info = lines[LINE(status)];     /* re-arrange info the proper port */
+
+  if (status & DZ_RDONE) 
+      receive_chars (info);          /* the receive function */
+
+  if (status & DZ_TRDY) 
+    transmit_chars (info);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the DZ interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh (void)
+{
+        run_task_queue (&tq_serial);
+}
+
+static void do_softint (void *private_data)
+{
+  struct dz_serial *info = (struct dz_serial *)private_data;
+  struct tty_struct *tty = info->tty;
+
+  if (!tty) return;
+
+  if (test_and_clear_bit (DZ_EVENT_WRITE_WAKEUP, &info->event)) {
+    if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+      (tty->ldisc.write_wakeup) (tty);
+    wake_up_interruptible (&tty->write_wait);
+  }
+}
+
+/*
+ * -------------------------------------------------------------------
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ *      serial interrupt routine -> (scheduler tqueue) ->
+ *      do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * ------------------------------------------------------------------- 
+ */
+static void do_serial_hangup (void *private_data)
+{
+  struct dz_serial *info = (struct dz_serial *)private_data;
+  struct tty_struct *tty = info->tty;;
+        
+  if (!tty) return;
+
+  tty_hangup (tty);
+}
+
+/*
+ * -------------------------------------------------------------------
+ * startup ()
+ *
+ * various initialization tasks
+ * ------------------------------------------------------------------- 
+ */
+static int startup (struct dz_serial *info)
+{
+  unsigned long page, flags;
+  unsigned short tmp;
+
+  if (info->is_initialized) return 0;
+  
+  save_flags (flags);
+  cli ();
+
+  if (!info->port) {
+    if (info->tty) set_bit (TTY_IO_ERROR, &info->tty->flags);
+    restore_flags (flags);
+    return -ENODEV;
+  }
+
+  if (!info->xmit_buf) {
+    page = get_free_page (GFP_KERNEL);
+    if (!page) {
+      restore_flags (flags);
+      return -ENOMEM;
+    }
+    info->xmit_buf = (unsigned char *)page;
+  }
+
+  if (info->tty) clear_bit (TTY_IO_ERROR, &info->tty->flags);
+
+  /* enable the interrupt and the scanning */
+  tmp = dz_in (info, DZ_CSR);
+  tmp |= (DZ_RIE | DZ_TIE | DZ_MSE);
+  dz_out (info, DZ_CSR, tmp);
+
+  info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+  /* set up the speed */
+  change_speed (info);
+
+  /* clear the line transmitter buffer 
+     I can't figure out why I need to do this - but
+     its necessary - in order for the console portion
+     and the interrupt portion to live happily side by side.
+  */
+
+  /* clear the line transmitter buffer 
+     I can't figure out why I need to do this - but
+     its necessary - in order for the console portion
+     and the interrupt portion to live happily side by side.
+  */
+
+  info->is_initialized = 1;
+
+  restore_flags (flags);
+  return 0;
+}
+
+/* 
+ * -------------------------------------------------------------------
+ * shutdown ()
+ *
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ * ------------------------------------------------------------------- 
+ */
+static void shutdown (struct dz_serial *info)
+{
+  unsigned long flags;
+  unsigned short tmp;
+
+  if (!info->is_initialized) return;
+
+  save_flags (flags);
+  cli ();
+
+  dz_stop (info->tty);
+
+
+
+  info->cflags &= ~DZ_CREAD;          /* turn off receive enable flag */
+  dz_out (info, DZ_LPR, info->cflags);
+
+  if (info->xmit_buf) {               /* free Tx buffer */
+    free_page ((unsigned long)info->xmit_buf);
+    info->xmit_buf = 0;
+  }
+
+  if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+    tmp = dz_in (info, DZ_TCR);
+    if (tmp & DZ_MODEM_DTR) {
+      tmp &= ~DZ_MODEM_DTR;
+      dz_out (info, DZ_TCR, tmp);
+    }
+  }
+
+  if (info->tty) set_bit (TTY_IO_ERROR, &info->tty->flags);
+
+  info->is_initialized = 0;
+  restore_flags (flags);
+}
+
+/* 
+ * -------------------------------------------------------------------
+ * change_speed ()
+ *
+ * set the baud rate.
+ * ------------------------------------------------------------------- 
+ */
+static void change_speed (struct dz_serial *info)
+{
+  unsigned long flags;
+  unsigned cflag;
+  int baud;
+
+  if (!info->tty || !info->tty->termios) return;
+  
+  save_flags (flags);
+  cli ();
+  
+  info->cflags = info->line;
+
+  cflag = info->tty->termios->c_cflag;
+
+  switch (cflag & CSIZE) {
+  case CS5: info->cflags |= DZ_CS5; break;
+  case CS6: info->cflags |= DZ_CS6; break;
+  case CS7: info->cflags |= DZ_CS7; break;
+  case CS8: 
+  default:  info->cflags |= DZ_CS8;
+  }
+
+  if (cflag & CSTOPB) info->cflags |= DZ_CSTOPB;
+  if (cflag & PARENB) info->cflags |= DZ_PARENB;
+  if (cflag & PARODD) info->cflags |= DZ_PARODD;
+  
+  baud = tty_get_baud_rate (info->tty);
+  switch (baud) {
+  case 50  :  info->cflags |= DZ_B50;   break;
+  case 75  :  info->cflags |= DZ_B75;   break;
+  case 110 :  info->cflags |= DZ_B110;  break;
+  case 134 :  info->cflags |= DZ_B134;  break; 
+  case 150 :  info->cflags |= DZ_B150;  break;
+  case 300 :  info->cflags |= DZ_B300;  break; 
+  case 600 :  info->cflags |= DZ_B600;  break;
+  case 1200:  info->cflags |= DZ_B1200; break; 
+  case 1800:  info->cflags |= DZ_B1800; break;
+  case 2000:  info->cflags |= DZ_B2000; break;
+  case 2400:  info->cflags |= DZ_B2400; break;
+  case 3600:  info->cflags |= DZ_B3600; break; 
+  case 4800:  info->cflags |= DZ_B4800; break;
+  case 7200:  info->cflags |= DZ_B7200; break; 
+  case 9600: 
+  default  :  info->cflags |= DZ_B9600; 
+  }
+
+  info->cflags |= DZ_RXENAB;
+  dz_out (info, DZ_LPR, info->cflags);
+
+  /* setup accept flag */
+  info->read_status_mask = DZ_OERR;
+  if (I_INPCK(info->tty))
+   info->read_status_mask |= (DZ_FERR | DZ_PERR); 
+  
+  /* characters to ignore */
+  info->ignore_status_mask = 0;
+  if (I_IGNPAR(info->tty))
+    info->ignore_status_mask |= (DZ_FERR | DZ_PERR);
+
+  restore_flags (flags);
+}
+
+/* 
+ * -------------------------------------------------------------------
+ * dz_flush_char ()
+ *
+ * Flush the buffer.
+ * ------------------------------------------------------------------- 
+ */
+static void dz_flush_chars (struct tty_struct *tty)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+  unsigned long flags;
+
+ if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !info->xmit_buf)
+    return;
+
+ save_flags (flags);
+ cli ();  
+
+ dz_start (info->tty);
+
+ restore_flags (flags);
+}
+
+
+/* 
+ * -------------------------------------------------------------------
+ * dz_write ()
+ *
+ * main output routine.
+ * ------------------------------------------------------------------- 
+ */
+static int dz_write (struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+  unsigned long flags;
+  int c, ret = 0;
+
+  if (!tty ) return ret;
+  if (!info->xmit_buf) return ret;
+  if (!tmp_buf) tmp_buf = tmp_buffer;
+
+
+
+  if (from_user) {
+
+    down (&tmp_buf_sem);
+    while (1) {
+      c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
+      if (c <= 0) break;
+
+      c -= copy_from_user (tmp_buf, buf, c);
+      if (!c) {
+        if (!ret) ret = -EFAULT;
+        break;
+      }
+
+      save_flags (flags);
+      cli ();
+
+      c = MIN(c, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_XMIT_SIZE - info->xmit_head));
+      memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+      info->xmit_head = ((info->xmit_head + c) & (DZ_XMIT_SIZE-1));
+      info->xmit_cnt += c;
+
+      restore_flags(flags);
+
+      buf += c;
+      count -= c;
+      ret += c;
+    }
+    
+    up (&tmp_buf_sem);
+  } else {
+
+
+    while (1) {
+      save_flags (flags);
+      cli ();     
+
+      c = MIN(count, MIN(DZ_XMIT_SIZE - info->xmit_cnt - 1, DZ_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) & (DZ_XMIT_SIZE-1));
+      info->xmit_cnt += c;
+
+      restore_flags (flags);
+
+      buf += c;
+      count -= c;
+      ret += c;
+    }
+  }
+
+
+  if (info->xmit_cnt)
+    {
+      if (!tty->stopped) 
+	{
+	  if (!tty->hw_stopped)
+	    {
+	      dz_start (info->tty);
+	    }
+	}
+    }
+  return ret;
+}
+
+/* 
+ * -------------------------------------------------------------------
+ * dz_write_room ()
+ *
+ * compute the amount of space available for writing.
+ * ------------------------------------------------------------------- 
+ */
+static int dz_write_room (struct tty_struct *tty)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+  int ret;
+                                
+  ret = DZ_XMIT_SIZE - info->xmit_cnt - 1;
+  if (ret < 0) ret = 0;
+  return ret;
+}
+
+/* 
+ * -------------------------------------------------------------------
+ * dz_chars_in_buffer ()
+ *
+ * compute the amount of char left to be transmitted
+ * ------------------------------------------------------------------- 
+ */
+static int dz_chars_in_buffer (struct tty_struct *tty)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+  
+  return info->xmit_cnt;
+}
+
+/* 
+ * -------------------------------------------------------------------
+ * dz_flush_buffer ()
+ *
+ * Empty the output buffer
+ * ------------------------------------------------------------------- 
+ */
+static void dz_flush_buffer (struct tty_struct *tty)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+                                
+  cli ();
+  info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+  sti ();
+
+  wake_up_interruptible (&tty->write_wait);
+
+  if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
+    (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_throttle () and dz_unthrottle ()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled (or not).
+ * ------------------------------------------------------------
+ */
+static void dz_throttle (struct tty_struct *tty)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;  
+
+  if (I_IXOFF(tty))
+    info->x_char = STOP_CHAR(tty);
+}
+
+static void dz_unthrottle (struct tty_struct *tty)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;  
+
+  if (I_IXOFF(tty)) {
+    if (info->x_char)
+      info->x_char = 0;
+    else
+      info->x_char = START_CHAR(tty);
+  }
+}
+
+static void dz_send_xchar (struct tty_struct *tty, char ch)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+  info->x_char = ch;
+
+  if (ch) dz_start (info->tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl () and friends
+ * ------------------------------------------------------------
+ */
+static int get_serial_info (struct dz_serial *info, struct serial_struct *retinfo)
+{
+  struct serial_struct tmp;
+  
+  if (!retinfo)
+    return -EFAULT;
+
+  memset (&tmp, 0, sizeof(tmp));
+
+  tmp.type = info->type;
+  tmp.line = info->line;
+  tmp.port = info->port;
+  tmp.irq = SERIAL;
+  tmp.flags = info->flags;
+  tmp.baud_base = info->baud_base;
+  tmp.close_delay = info->close_delay;
+  tmp.closing_wait = info->closing_wait;
+  
+  return copy_to_user (retinfo, &tmp, sizeof(*retinfo));
+}
+
+static int set_serial_info (struct dz_serial *info, struct serial_struct *new_info)
+{
+  struct serial_struct new_serial;
+  struct dz_serial old_info;
+  int retval = 0;
+
+  if (!new_info)
+    return -EFAULT;
+
+  copy_from_user (&new_serial, new_info, sizeof(new_serial));
+  old_info = *info;
+
+  if (!suser())
+    return -EPERM;
+
+  if (info->count > 1)
+    return -EBUSY;
+
+  /*
+   * OK, past this point, all the error checking has been done.
+   * At this point, we start making changes.....
+   */
+  
+  info->baud_base = new_serial.baud_base;
+  info->type = new_serial.type;
+  info->close_delay = new_serial.close_delay;
+  info->closing_wait = new_serial.closing_wait;
+
+  retval = startup (info);
+  return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *          is emptied.  On bus types like RS485, the transmitter must
+ *          release the bus after transmitting. This must be done when
+ *          the transmit shift register is empty, not be done when the
+ *          transmit holding register is empty.  This functionality
+ *          allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info (struct dz_serial *info, unsigned int *value)
+{
+  unsigned short status = dz_in (info, DZ_LPR);
+
+  return put_user (status, value);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break (struct dz_serial *info, int duration)
+{
+  unsigned long flags;
+  unsigned short tmp, mask;
+
+  if (!info->port)
+    return;
+
+  mask = 1 << info->line;
+  tmp = dz_in (info, DZ_TCR);
+  tmp |= mask;
+
+  current->state = TASK_INTERRUPTIBLE;
+
+  save_flags (flags);
+  cli();
+  
+  dz_out (info, DZ_TCR, tmp);
+  
+  schedule_timeout(jiffies + duration);
+  
+  tmp &= ~mask;
+  dz_out (info, DZ_TCR, tmp);
+  
+  restore_flags (flags);
+}
+
+static int dz_ioctl (struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+{
+  int error;
+  struct dz_serial * info = (struct dz_serial *)tty->driver_data;
+  int retval;
+
+  if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+      (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+      (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+    if (tty->flags & (1 << TTY_IO_ERROR))
+      return -EIO;
+  }
+
+  switch (cmd) {
+  case TCSBRK:    /* SVID version: non-zero arg --> no break */
+    retval = tty_check_change (tty);
+    if (retval)
+      return retval;
+    tty_wait_until_sent (tty, 0);
+    if (!arg)
+      send_break (info, HZ/4); /* 1/4 second */
+    return 0;
+
+  case TCSBRKP:   /* support for POSIX tcsendbreak() */
+    retval = tty_check_change (tty);
+    if (retval)
+      return retval;
+    tty_wait_until_sent (tty, 0);
+    send_break (info, arg ? arg*(HZ/10) : HZ/4);
+    return 0;
+
+  case TIOCGSOFTCAR:
+    error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(long));
+    if (error)
+      return error;
+    put_user (C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);
+    return 0;
+
+  case TIOCSSOFTCAR:
+    error = get_user (arg, (unsigned long *)arg);
+    if (error)
+      return error;
+    tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
+    return 0;
+
+  case TIOCGSERIAL:
+    error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct serial_struct));
+    if (error)
+      return error;
+    return get_serial_info (info, (struct serial_struct *)arg);
+
+  case TIOCSSERIAL:
+    return set_serial_info (info, (struct serial_struct *) arg);
+
+  case TIOCSERGETLSR: /* Get line status register */
+    error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(unsigned int));
+    if (error)
+      return error;
+    else
+      return get_lsr_info (info, (unsigned int *)arg);
+
+  case TIOCSERGSTRUCT:
+    error = verify_area (VERIFY_WRITE, (void *)arg, sizeof(struct dz_serial));
+    if (error)
+      return error;
+    copy_to_user((struct dz_serial *)arg, info, sizeof(struct dz_serial));
+    return 0;
+    
+  default:
+    return -ENOIOCTLCMD;
+  }
+
+  return 0;
+}
+
+static void dz_set_termios (struct tty_struct *tty,
+			    struct termios *old_termios)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+
+  if (tty->termios->c_cflag == old_termios->c_cflag)
+    return;
+
+  change_speed (info);
+
+  if ((old_termios->c_cflag & CRTSCTS) &&
+      !(tty->termios->c_cflag & CRTSCTS)) {
+    tty->hw_stopped = 0;
+    dz_start (tty);
+  }
+}
+
+/*
+ * ------------------------------------------------------------
+ * dz_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we turn off
+ * the transmit enable and receive enable flags.
+ * ------------------------------------------------------------
+ */
+static void dz_close (struct tty_struct *tty, struct file *filp)
+{
+  struct dz_serial * info = (struct dz_serial *)tty->driver_data;
+  unsigned long flags;
+
+  if (!info) return;
+        
+  save_flags (flags); 
+  cli();
+        
+  if (tty_hung_up_p (filp)) {
+    restore_flags (flags);
+    return;
+  }
+
+  if ((tty->count == 1) && (info->count != 1)) {
+    /*
+     * Uh, oh.  tty->count is 1, which means that the tty
+     * structure will be freed.  Info->count should always
+     * be one in these conditions.  If it's greater than
+     * one, we've got real problems, since it means the
+     * serial port won't be shutdown.
+     */
+    printk("dz_close: bad serial port count; tty->count is 1, "
+                       "info->count is %d\n", info->count);
+                info->count = 1;
+  }
+
+  if (--info->count < 0) {
+    printk("rs_close: bad serial port count for ttys%d: %d\n",
+	   info->line, info->count);
+    info->count = 0;
+  }
+
+  if (info->count) {
+    restore_flags (flags);
+    return;
+  }
+  info->flags |= DZ_CLOSING;
+  /*
+   * Save the termios structure, since this port may have
+   * separate termios for callout and dialin.
+   */
+  if (info->flags & DZ_NORMAL_ACTIVE)
+    info->normal_termios = *tty->termios;
+  if (info->flags & DZ_CALLOUT_ACTIVE)
+    info->callout_termios = *tty->termios;
+  /*
+   * Now we wait for the transmit buffer to clear; and we notify 
+   * the line discipline to only process XON/XOFF characters.
+   */
+  tty->closing = 1;
+
+  if (info->closing_wait != DZ_CLOSING_WAIT_NONE)
+    tty_wait_until_sent (tty, info->closing_wait);
+
+  /*
+   * At this point we stop accepting input.  To do this, we
+   * disable the receive line status interrupts.
+   */
+
+  shutdown (info);
+
+  if (tty->driver.flush_buffer)
+    tty->driver.flush_buffer (tty);
+  if (tty->ldisc.flush_buffer)
+    tty->ldisc.flush_buffer (tty);
+  tty->closing = 0;
+  info->event = 0;
+  info->tty = 0;
+
+  if (tty->ldisc.num != ldiscs[N_TTY].num) {
+    if (tty->ldisc.close)
+      (tty->ldisc.close)(tty);
+    tty->ldisc = ldiscs[N_TTY];
+    tty->termios->c_line = N_TTY;
+    if (tty->ldisc.open)
+      (tty->ldisc.open)(tty);
+  }
+  if (info->blocked_open) {
+    if (info->close_delay) {
+      current->state = TASK_INTERRUPTIBLE;
+      schedule_timeout(jiffies + info->close_delay);
+    }
+    wake_up_interruptible (&info->open_wait);
+  }
+
+  info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING);
+  wake_up_interruptible (&info->close_wait);
+
+  restore_flags (flags);
+}
+
+/*
+ * dz_hangup () --- called by tty_hangup() when a hangup is signaled.
+ */
+static void dz_hangup (struct tty_struct *tty)
+{
+  struct dz_serial *info = (struct dz_serial *)tty->driver_data;
+  
+  dz_flush_buffer (tty);
+  shutdown (info);
+  info->event = 0;
+  info->count = 0;
+  info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE);
+  info->tty = 0;
+  wake_up_interruptible (&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready (struct tty_struct *tty, struct file *filp, struct dz_serial *info)
+{
+  struct wait_queue wait = { current, NULL };
+  int retval;
+  int do_clocal = 0;
+
+  /*
+   * If the device is in the middle of being closed, then block
+   * until it's done, and then try again.
+   */
+  if (info->flags & DZ_CLOSING) {
+    interruptible_sleep_on (&info->close_wait);
+    return -EAGAIN;
+  }
+
+  /*
+   * If this is a callout device, then just make sure the normal
+   * device isn't being used.
+   */
+  if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+    if (info->flags & DZ_NORMAL_ACTIVE)
+      return -EBUSY;
+    
+    if ((info->flags & DZ_CALLOUT_ACTIVE) &&
+	(info->flags & DZ_SESSION_LOCKOUT) &&
+	(info->session != current->session))
+      return -EBUSY;
+    
+    if ((info->flags & DZ_CALLOUT_ACTIVE) &&
+	(info->flags & DZ_PGRP_LOCKOUT) &&
+	(info->pgrp != current->pgrp))
+      return -EBUSY;
+    info->flags |= DZ_CALLOUT_ACTIVE;
+    return 0;
+  }
+
+  /*
+   * If non-blocking mode is set, or the port is not enabled,
+   * then make the check up front and then exit.
+   */
+  if ((filp->f_flags & O_NONBLOCK) ||
+      (tty->flags & (1 << TTY_IO_ERROR))) {
+    if (info->flags & DZ_CALLOUT_ACTIVE)
+      return -EBUSY;
+    info->flags |= DZ_NORMAL_ACTIVE;
+    return 0;
+  }
+
+  if (info->flags & DZ_CALLOUT_ACTIVE) {
+    if (info->normal_termios.c_cflag & CLOCAL)
+      do_clocal = 1;
+  } else {
+    if (tty->termios->c_cflag & CLOCAL)
+      do_clocal = 1;
+  }
+
+  /*
+   * Block waiting for the carrier detect and the line to become
+   * free (i.e., not in use by the callout).  While we are in
+   * this loop, info->count is dropped by one, so that
+   * dz_close() knows when to free things.  We restore it upon
+   * exit, either normal or abnormal.
+   */
+  retval = 0;
+  add_wait_queue (&info->open_wait, &wait);
+
+  info->count--;
+  info->blocked_open++;
+  while (1) {
+    current->state = TASK_INTERRUPTIBLE;
+    if (tty_hung_up_p (filp) || !(info->is_initialized)) {
+      retval = -EAGAIN;
+      break;
+    }
+    if (!(info->flags & DZ_CALLOUT_ACTIVE) &&
+	!(info->flags & DZ_CLOSING) && do_clocal)
+      break;
+    if (signal_pending (current)) {
+      retval = -ERESTARTSYS;
+      break;
+    }
+    schedule();
+  }
+		
+  current->state = TASK_RUNNING;
+  remove_wait_queue (&info->open_wait, &wait);
+  if (!tty_hung_up_p(filp))
+    info->count++;
+  info->blocked_open--;
+
+  if (retval)
+    return retval;
+  info->flags |= DZ_NORMAL_ACTIVE;
+  return 0;
+}       
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port. It also performs the 
+ * serial-specific initialization for the tty structure.
+ */
+static int dz_open (struct tty_struct *tty, struct file *filp)
+{
+  struct dz_serial *info;
+  int retval, line;
+
+  line = MINOR(tty->device) - tty->driver.minor_start;
+
+  /* The dz lines for the mouse/keyboard must be
+   * opened using their respective drivers.
+   */
+  if ((line < 0) || (line >= DZ_NB_PORT))
+    return -ENODEV;
+
+  if ((line == DZ_KEYBOARD) || (line == DZ_MOUSE))
+    return -ENODEV;
+
+  info = lines[line];
+  info->count++;
+
+  tty->driver_data = info;
+  info->tty = tty;
+
+  /*
+   * Start up serial port
+   */
+  retval = startup (info);
+  if (retval)
+    return retval;
+
+
+
+  retval = block_til_ready (tty, filp, info);
+  if (retval)
+    return retval;
+
+  if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) {
+    if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+      *tty->termios = info->normal_termios;
+    else 
+      *tty->termios = info->callout_termios;
+    change_speed (info);
+
+  }
+
+  info->session = current->session;
+  info->pgrp = current->pgrp;
+  return 0;
+}
+
+static void show_serial_version (void)
+{
+  printk("%s%s\n", dz_name, dz_version);
+}
+
+
+__initfunc(int dz_init(void))
+{
+  int i, flags;
+  struct dz_serial *info;
+
+  /* Setup base handler, and timer table. */
+  init_bh (SERIAL_BH, do_serial_bh);
+
+  show_serial_version ();
+
+  memset(&serial_driver, 0, sizeof(struct tty_driver));
+  serial_driver.magic = TTY_DRIVER_MAGIC;
+  serial_driver.name = "ttyS";
+  serial_driver.major = TTY_MAJOR;
+  serial_driver.minor_start = 64;
+  serial_driver.num = DZ_NB_PORT;
+  serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+  serial_driver.subtype = SERIAL_TYPE_NORMAL;
+  serial_driver.init_termios = tty_std_termios;
+
+  serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+  serial_driver.flags = TTY_DRIVER_REAL_RAW;
+  serial_driver.refcount = &serial_refcount;
+  serial_driver.table = serial_table;
+  serial_driver.termios = serial_termios;
+  serial_driver.termios_locked = serial_termios_locked;
+
+  serial_driver.open = dz_open;
+  serial_driver.close = dz_close;
+  serial_driver.write = dz_write;
+  serial_driver.flush_chars = dz_flush_chars;
+  serial_driver.write_room = dz_write_room;
+  serial_driver.chars_in_buffer = dz_chars_in_buffer;
+  serial_driver.flush_buffer = dz_flush_buffer;
+  serial_driver.ioctl = dz_ioctl;
+  serial_driver.throttle = dz_throttle;
+  serial_driver.unthrottle = dz_unthrottle;
+  serial_driver.send_xchar = dz_send_xchar;
+  serial_driver.set_termios = dz_set_termios;
+  serial_driver.stop = dz_stop;
+  serial_driver.start = dz_start;
+  serial_driver.hangup = dz_hangup;
+
+  /*
+   * The callout device is just like normal device except for
+   * major number and the subtype code.
+   */
+  callout_driver = serial_driver;
+  callout_driver.name = "cua";
+  callout_driver.major = TTYAUX_MAJOR;
+  callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+  if (tty_register_driver (&serial_driver))
+    panic("Couldn't register serial driver\n");
+  if (tty_register_driver (&callout_driver))
+    panic("Couldn't register callout driver\n");
+  save_flags(flags); cli();
+ 
+  i = 0;
+  for (info = &multi[i]; i < DZ_NB_PORT;  i++) 
+    {
+      lines[i] = info;
+    info->magic = SERIAL_MAGIC;
+
+      if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) 
+      info->port = (unsigned long) KN01_DZ11_BASE;
+      else 
+      info->port = (unsigned long) KN02_DZ11_BASE;
+
+    info->line = i;
+    info->tty = 0;
+    info->close_delay = 50;
+    info->closing_wait = 3000;
+    info->x_char = 0;
+    info->event = 0;
+    info->count = 0;
+    info->blocked_open = 0;
+    info->tqueue.routine = do_softint;
+    info->tqueue.data = info;
+    info->tqueue_hangup.routine = do_serial_hangup;
+    info->tqueue_hangup.data = info;
+    info->callout_termios = callout_driver.init_termios;
+    info->normal_termios = serial_driver.init_termios;
+    info->open_wait = 0;
+    info->close_wait = 0;
+
+    /* If we are pointing to address zero then punt - not correctly
+       set up in setup.c to handle this. */
+    if (! info->port)
+      return 0;
+
+    printk("ttyS%02d at 0x%04x (irq = %d)\n", info->line, info->port, SERIAL);
+  }
+
+  /* reset the chip */
+#ifndef CONFIG_SERIAL_CONSOLE
+  dz_out(info, DZ_CSR, DZ_CLR);
+  while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR) ;
+  wbflush();
+  
+  /* enable scanning */
+   dz_out(info, DZ_CSR, DZ_MSE); 
+#endif
+  
+  /* order matters here... the trick is that flags
+     is updated... in request_irq - to immediatedly obliterate
+     it is unwise. */
+  restore_flags(flags);
+ 
+
+  if (request_irq (SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0]))
+    panic ("Unable to register DZ interrupt\n");
+ 
+  return 0;
+}
+
+#ifdef CONFIG_SERIAL_CONSOLE
+static void dz_console_put_char (unsigned char ch)
+{
+  long flags;
+  int  loops = 2500;
+  unsigned short tmp = ch;
+  /* this code sends stuff out to serial device - spinning its
+      wheels and waiting. */
+
+  /* force the issue - point it at lines[3]*/
+  dz_console=&multi[CONSOLE_LINE];
+
+  save_flags(flags);
+  cli();
+  
+
+  /* spin our wheels */
+  while (((dz_in(dz_console,DZ_TCR) & DZ_TRDY) != DZ_TRDY) &&  loops--)
+    ;
+  
+  /* Actually transmit the character. */
+  dz_out (dz_console, DZ_TDR, tmp);
+
+  restore_flags(flags); 
+}
+/* 
+ * -------------------------------------------------------------------
+ * dz_console_print ()
+ *
+ * dz_console_print is registered for printk.
+ * ------------------------------------------------------------------- 
+ */
+static void dz_console_print (struct console *cons, 
+			      const char *str, 
+			      unsigned int count)
+{
+#ifdef DEBUG_DZ
+  prom_printf((char *)str);
+#endif
+  while (count--) 
+    {
+    if (*str == '\n')
+	dz_console_put_char ('\r');
+      dz_console_put_char (*str++);
+  }
+}
+
+static int dz_console_wait_key(struct console *co)
+{
+    return 0;
+}
+
+static kdev_t dz_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+__initfunc(static int dz_console_setup(struct console *co, char *options))
+{
+  	int	baud = 9600;
+	int	bits = 8;
+	int	parity = 'n';
+	int	cflag = CREAD | HUPCL | CLOCAL;
+	char	*s;
+	unsigned short mask,tmp;
+
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s)
+			parity = *s++;
+		if (*s)
+			bits   = *s - '0';
+	}
+
+	/*
+	 *	Now construct a cflag setting.
+	 */
+	switch(baud) {
+	case 1200:
+		cflag |= DZ_B1200;
+		break;
+	case 2400:
+		cflag |= DZ_B2400;
+		break;
+	case 4800:
+		cflag |= DZ_B4800;
+		break;
+	case 9600:
+	default:
+		cflag |= DZ_B9600;
+		break;
+	}
+	switch(bits) {
+	case 7:
+		cflag |= DZ_CS7;
+		break;
+	default:
+	case 8:
+		cflag |= DZ_CS8;
+		break;
+	}
+	switch(parity) {
+	case 'o': case 'O':
+		cflag |= DZ_PARODD;
+		break;
+	case 'e': case 'E':
+		cflag |= DZ_PARENB;
+		break;
+	}
+	co->cflag = cflag;
+
+	/* TOFIX: force to console line */
+	dz_console = &multi[CONSOLE_LINE];
+    	if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) 
+	dz_console->port = KN01_DZ11_BASE;
+       	else 
+       		dz_console->port = KN02_DZ11_BASE; 
+	dz_console->line = CONSOLE_LINE;
+
+	dz_out(dz_console, DZ_CSR, DZ_CLR);
+	while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR)
+	  ;
+
+	/* enable scanning */
+	dz_out(dz_console, DZ_CSR, DZ_MSE); 
+
+        /*  Set up flags... */
+	dz_console->cflags = 0;
+	dz_console->cflags |= DZ_B9600;
+	dz_console->cflags |= DZ_CS8;
+	dz_console->cflags |= DZ_PARENB;
+	dz_out (dz_console, DZ_LPR, dz_console->cflags);
+
+
+	mask = 1 << dz_console->line;
+	tmp = dz_in (dz_console, DZ_TCR);       /* read the TX flag */
+	if (!(tmp & mask)) {
+	  tmp |= mask;                   /* set the TX flag */
+	  dz_out (dz_console, DZ_TCR, tmp); 
+	}
+	
+
+	/* TOFIX: force to console line */
+	dz_console = &multi[CONSOLE_LINE];
+    	if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) 
+	dz_console->port = KN01_DZ11_BASE;
+       	else 
+       		dz_console->port = KN02_DZ11_BASE; 
+	dz_console->line = CONSOLE_LINE;
+
+	dz_out(dz_console, DZ_CSR, DZ_CLR);
+	while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR)
+	  ;
+
+	/* enable scanning */
+	dz_out(dz_console, DZ_CSR, DZ_MSE); 
+
+        /*  Set up flags... */
+	dz_console->cflags = 0;
+	dz_console->cflags |= DZ_B9600;
+	dz_console->cflags |= DZ_CS8;
+	dz_console->cflags |= DZ_PARENB;
+	dz_out (dz_console, DZ_LPR, dz_console->cflags);
+
+
+	mask = 1 << dz_console->line;
+	tmp = dz_in (dz_console, DZ_TCR);       /* read the TX flag */
+	if (!(tmp & mask)) {
+	  tmp |= mask;                   /* set the TX flag */
+	  dz_out (dz_console, DZ_TCR, tmp); 
+	}
+	
+
+	return 0;
+}
+
+static struct console dz_sercons = {
+	"ttyS",
+	dz_console_print,
+	NULL,
+	dz_console_device,
+	dz_console_wait_key,
+	NULL,
+	dz_console_setup,
+	CON_CONSDEV | CON_PRINTBUFFER,
+	CONSOLE_LINE,
+	0,
+	NULL
+};
+
+__initfunc (long dz_serial_console_init(long kmem_start, long kmem_end))
+{
+	register_console(&dz_sercons);
+
+	return kmem_start;
+}
+
+#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+
diff -u --recursive --new-file v2.3.8/linux/drivers/char/dz.h linux/drivers/char/dz.h
--- v2.3.8/linux/drivers/char/dz.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/dz.h	Fri Jun 25 17:39:14 1999
@@ -0,0 +1,242 @@
+/*
+ * dz.h: Serial port driver for DECStations equiped 
+ *       with the DZ chipset.
+ *
+ * Copyright (C) 1998 Olivier A. D. Lebaillif 
+ *             
+ * Email: olivier.lebaillif@ifrsys.com
+ *
+ */
+#ifndef DZ_SERIAL_H
+#define DZ_SERIAL_H
+
+/*
+ * Definitions for the Control and Status Received.
+ */
+#define DZ_TRDY        0x8000                 /* Transmitter empty */
+#define DZ_TIE         0x4000                 /* Transmitter Interrupt Enable */
+#define DZ_RDONE       0x0080                 /* Receiver data ready */
+#define DZ_RIE         0x0040                 /* Receive Interrupt Enable */
+#define DZ_MSE         0x0020                 /* Master Scan Enable */
+#define DZ_CLR         0x0010                 /* Master reset */
+#define DZ_MAINT       0x0008                 /* Loop Back Mode */
+
+/*
+ * Definitions for the Received buffer. 
+ */
+#define DZ_RBUF_MASK   0x00FF                 /* Data Mask in the Receive Buffer */
+#define DZ_LINE_MASK   0x0300                 /* Line Mask in the Receive Buffer */
+#define DZ_DVAL        0x8000                 /* Valid Data indicator */
+#define DZ_OERR        0x4000                 /* Overrun error indicator */
+#define DZ_FERR        0x2000                 /* Frame error indicator */
+#define DZ_PERR        0x1000                 /* Parity error indicator */
+
+#define LINE(x) (x & DZ_LINE_MASK) >> 8       /* Get the line number from the input buffer */
+#define UCHAR(x) (unsigned char)(x & DZ_RBUF_MASK)
+
+/*
+ * Definitions for the Transmit Register.
+ */
+#define DZ_LINE_KEYBOARD 0x0001
+#define DZ_LINE_MOUSE    0x0002
+#define DZ_LINE_MODEM    0x0004
+#define DZ_LINE_PRINTER  0x0008
+
+#define DZ_MODEM_DTR     0x0400               /* DTR for the modem line (2) */
+
+/*
+ * Definitions for the Modem Status Register.
+ */
+#define DZ_MODEM_DSR     0x0200               /* DSR for the modem line (2) */
+
+/*
+ * Definitions for the Transmit Data Register.
+ */
+#define DZ_BRK0          0x0100               /* Break assertion for line 0 */
+#define DZ_BRK1          0x0200               /* Break assertion for line 1 */
+#define DZ_BRK2          0x0400               /* Break assertion for line 2 */
+#define DZ_BRK3          0x0800               /* Break assertion for line 3 */
+
+/*
+ * Definitions for the Line Parameter Register.
+ */
+#define DZ_KEYBOARD      0x0000               /* line 0 = keyboard */
+#define DZ_MOUSE         0x0001               /* line 1 = mouse */
+#define DZ_MODEM         0x0002               /* line 2 = modem */
+#define DZ_PRINTER       0x0003               /* line 3 = printer */
+
+#define DZ_CSIZE         0x0018               /* Number of bits per byte (mask) */
+#define DZ_CS5           0x0000               /* 5 bits per byte */
+#define DZ_CS6           0x0008               /* 6 bits per byte */
+#define DZ_CS7           0x0010               /* 7 bits per byte */
+#define DZ_CS8           0x0018               /* 8 bits per byte */
+
+#define DZ_CSTOPB        0x0020               /* 2 stop bits instead of one */ 
+
+#define DZ_PARENB        0x0040               /* Parity enable */
+#define DZ_PARODD        0x0080               /* Odd parity instead of even */
+
+#define DZ_CBAUD         0x0E00               /* Baud Rate (mask) */
+#define DZ_B50           0x0000
+#define DZ_B75           0x0100
+#define DZ_B110          0x0200
+#define DZ_B134          0x0300
+#define DZ_B150          0x0400
+#define DZ_B300          0x0500
+#define DZ_B600          0x0600
+#define DZ_B1200         0x0700 
+#define DZ_B1800         0x0800
+#define DZ_B2000         0x0900
+#define DZ_B2400         0x0A00
+#define DZ_B3600         0x0B00
+#define DZ_B4800         0x0C00
+#define DZ_B7200         0x0D00
+#define DZ_B9600         0x0E00
+
+#define DZ_CREAD         0x1000               /* Enable receiver */
+#define DZ_RXENAB        0x1000               /* enable receive char */
+/*
+ * Addresses for the DZ registers
+ */
+#define DZ_CSR       0x00            /* Control and Status Register */
+#define DZ_RBUF      0x08            /* Receive Buffer */
+#define DZ_LPR       0x08            /* Line Parameters Register */
+#define DZ_TCR       0x10            /* Transmitter Control Register */
+#define DZ_MSR       0x18            /* Modem Status Register */
+#define DZ_TDR       0x18            /* Transmit Data Register */
+
+
+#define DZ_NB_PORT 4
+
+#define DZ_XMIT_SIZE   4096                 /* buffer size */
+#define WAKEUP_CHARS   DZ_XMIT_SIZE/4
+
+#define DZ_EVENT_WRITE_WAKEUP   0
+
+#ifndef MIN
+#define MIN(a,b)        ((a) < (b) ? (a) : (b))
+
+#define DZ_INITIALIZED       0x80000000 /* Serial port was initialized */
+#define DZ_CALLOUT_ACTIVE    0x40000000 /* Call out device is active */
+#define DZ_NORMAL_ACTIVE     0x20000000 /* Normal device is active */
+#define DZ_BOOT_AUTOCONF     0x10000000 /* Autoconfigure port on bootup */
+#define DZ_CLOSING           0x08000000 /* Serial port is closing */
+#define DZ_CTS_FLOW          0x04000000 /* Do CTS flow control */
+#define DZ_CHECK_CD          0x02000000 /* i.e., CLOCAL */
+
+#define DZ_CLOSING_WAIT_INF  0
+#define DZ_CLOSING_WAIT_NONE 65535
+
+#define DZ_SPLIT_TERMIOS   0x0008 /* Separate termios for dialin/callout */
+#define DZ_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define DZ_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+
+struct dz_serial {
+  unsigned                port;                /* base address for the port */
+  int                     type;
+  int                     flags; 
+  int                     baud_base;
+  int                     blocked_open;
+  unsigned short          close_delay;
+  unsigned short          closing_wait;
+  unsigned short          line;                /* port/line number */
+  unsigned short          cflags;              /* line configuration flag */
+  unsigned short          x_char;              /* xon/xoff character */
+  unsigned short          read_status_mask;    /* mask for read condition */
+  unsigned short          ignore_status_mask;  /* mask for ignore condition */
+  unsigned long           event;               /* mask used in BH */
+  unsigned char           *xmit_buf;           /* Transmit buffer */
+  int                     xmit_head;           /* Position of the head */
+  int                     xmit_tail;           /* Position of the tail */
+  int                     xmit_cnt;            /* Count of the chars in the buffer */
+  int                     count;               /* indicates how many times it has been opened */
+  int                     magic;
+
+  struct async_icount     icount;              /* keep track of things ... */
+  struct tty_struct       *tty;                /* tty associated */
+  struct tq_struct        tqueue;              /* Queue for BH */
+  struct tq_struct        tqueue_hangup;
+  struct termios          normal_termios;
+  struct termios          callout_termios;
+  struct wait_queue       *open_wait;
+  struct wait_queue       *close_wait;
+
+  long                    session;             /* Session of opening process */
+  long                    pgrp;                /* pgrp of opening process */
+
+  unsigned char           is_console;          /* flag indicating a serial console */
+  unsigned char           is_initialized;
+};
+
+static struct dz_serial multi[DZ_NB_PORT];    /* Four serial lines in the DZ chip */
+static struct dz_serial *dz_console;
+static struct tty_driver serial_driver, callout_driver;
+
+static struct tty_struct *serial_table[DZ_NB_PORT];
+static struct termios *serial_termios[DZ_NB_PORT];
+static struct termios *serial_termios_locked[DZ_NB_PORT];
+
+static int serial_refcount;
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static char *dz_name = "DECstation DZ serial driver version ";
+static char *dz_version = "1.02";
+
+static inline unsigned short dz_in (struct dz_serial *, unsigned);
+static inline void dz_out (struct dz_serial *, unsigned, unsigned short);
+
+static inline void dz_sched_event (struct dz_serial *, int);
+static inline void receive_chars (struct dz_serial *);
+static inline void transmit_chars (struct dz_serial *);
+static inline void check_modem_status (struct dz_serial *);
+
+static void dz_stop (struct tty_struct *);
+static void dz_start (struct tty_struct *);
+static void dz_interrupt (int, void *, struct pt_regs *);
+static void do_serial_bh (void);
+static void do_softint (void *);
+static void do_serial_hangup (void *);
+static void change_speed (struct dz_serial *);
+static void dz_flush_chars (struct tty_struct *);
+static void dz_console_print (struct console *, const char *, unsigned int);
+static void dz_flush_buffer (struct tty_struct *);
+static void dz_throttle (struct tty_struct *);
+static void dz_unthrottle (struct tty_struct *);
+static void dz_send_xchar (struct tty_struct *, char);
+static void shutdown (struct dz_serial *);
+static void send_break (struct dz_serial *, int);
+static void dz_set_termios (struct tty_struct *, struct termios *);
+static void dz_close (struct tty_struct *, struct file *);
+static void dz_hangup (struct tty_struct *);
+static void show_serial_version (void);
+
+static int dz_write (struct tty_struct *, int, const unsigned char *, int);
+static int dz_write_room (struct tty_struct *);
+static int dz_chars_in_buffer (struct tty_struct *);
+static int startup (struct dz_serial *);
+static int get_serial_info (struct dz_serial *, struct serial_struct *);
+static int set_serial_info (struct dz_serial *, struct serial_struct *);
+static int get_lsr_info (struct dz_serial *, unsigned int *);
+static int dz_ioctl (struct tty_struct *, struct file *, unsigned int, unsigned long);
+static int block_til_ready (struct tty_struct *, struct file *, struct dz_serial *);
+static int dz_open (struct tty_struct *, struct file *);
+
+#ifdef MODULE
+int init_module (void)
+void cleanup_module (void)
+#endif
+
+#endif
+
+#endif /* DZ_SERIAL_H */
diff -u --recursive --new-file v2.3.8/linux/drivers/char/ftape/lowlevel/ftape-proc.c linux/drivers/char/ftape/lowlevel/ftape-proc.c
--- v2.3.8/linux/drivers/char/ftape/lowlevel/ftape-proc.c	Mon Aug 24 13:02:44 1998
+++ linux/drivers/char/ftape/lowlevel/ftape-proc.c	Sun Jun 27 10:10:41 1999
@@ -112,11 +112,14 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL,			/* revalidate */
 };
 
 /*
diff -u --recursive --new-file v2.3.8/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.3.8/linux/drivers/char/misc.c	Wed Jun  9 14:44:25 1999
+++ linux/drivers/char/misc.c	Fri Jun 25 17:39:14 1999
@@ -70,6 +70,10 @@
 extern int atari_mouse_init(void);
 extern int sun_mouse_init(void);
 extern int adb_mouse_init(void);
+#ifdef CONFIG_SGI_NEWPORT_GFX
+extern void gfx_register(void);
+#endif
+extern void streamable_init(void);
 extern void watchdog_init(void);
 extern void wdt_init(void);
 extern void acq_init(void);
@@ -271,6 +275,12 @@
 #endif
 #ifdef CONFIG_PMAC_PBOOK
 	pmu_device_init();
+#endif
+#ifdef CONFIG_SGI_NEWPORT_GFX
+	gfx_register ();
+#endif
+#ifdef CONFIG_SGI
+	streamable_init ();
 #endif
 	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 		printk("unable to get major %d for misc devices\n",
diff -u --recursive --new-file v2.3.8/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.3.8/linux/drivers/char/serial.c	Thu May 13 14:52:15 1999
+++ linux/drivers/char/serial.c	Tue Jun 22 20:15:10 1999
@@ -103,7 +103,8 @@
 #define RS_STROBE_TIME (10*HZ)
 #define RS_ISR_PASS_LIMIT 256
 
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+#define IRQ_T(state) \
+ ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
 
 #define SERIAL_INLINE
   
@@ -1003,7 +1004,7 @@
 		} else 
 			handler = rs_interrupt_single;
 
-		retval = request_irq(state->irq, handler, IRQ_T(info),
+		retval = request_irq(state->irq, handler, IRQ_T(state),
 				     "serial", NULL);
 		if (retval) {
 			if (capable(CAP_SYS_ADMIN)) {
@@ -1168,7 +1169,7 @@
 		if (IRQ_ports[state->irq]) {
 			free_irq(state->irq, NULL);
 			retval = request_irq(state->irq, rs_interrupt_single,
-					     IRQ_T(info), "serial", NULL);
+					     IRQ_T(state), "serial", NULL);
 			
 			if (retval)
 				printk("serial shutdown: request_irq: error %d"
@@ -2017,7 +2018,7 @@
 		else
 			handler = rs_interrupt;
 
-		retval = request_irq(state->irq, handler, IRQ_T(info),
+		retval = request_irq(state->irq, handler, IRQ_T(state),
 				     "serial", NULL);
 		if (retval) {
 			printk("Couldn't reallocate serial interrupt "
diff -u --recursive --new-file v2.3.8/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- v2.3.8/linux/drivers/char/sysrq.c	Wed Nov 25 17:25:17 1998
+++ linux/drivers/char/sysrq.c	Tue Jun 29 09:22:08 1999
@@ -155,7 +155,7 @@
 	struct file *file;
 
 	for (file = inuse_filps; file; file = file->f_next)
-		if (file->f_dentry && file->f_count && S_ISREG(file->f_dentry->d_inode->i_mode))
+		if (file->f_dentry && atomic_read(&file->f_count) && S_ISREG(file->f_dentry->d_inode->i_mode))
 			file->f_mode &= ~2;
 }
 
diff -u --recursive --new-file v2.3.8/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v2.3.8/linux/drivers/char/tpqic02.c	Wed May 12 13:27:37 1999
+++ linux/drivers/char/tpqic02.c	Tue Jun 29 09:22:08 1999
@@ -2216,7 +2216,7 @@
     }
     
 	/* Only one at a time from here on... */
-    if (filp->f_count>1) 	/* filp->f_count==1 for the first open() */
+    if (atomic_read(&filp->f_count)>1) 	/* filp->f_count==1 for the first open() */
     {
 	return -EBUSY;
     }
diff -u --recursive --new-file v2.3.8/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.3.8/linux/drivers/char/tty_io.c	Wed Jun 16 19:26:27 1999
+++ linux/drivers/char/tty_io.c	Mon Jun 28 21:35:08 1999
@@ -628,10 +628,12 @@
 			return -ERESTARTSYS;
 		}
 #endif
+	lock_kernel();
 	if (tty->ldisc.read)
 		i = (tty->ldisc.read)(tty,file,buf,count);
 	else
 		i = -EIO;
+	unlock_kernel();
 	if (i > 0)
 		inode->i_atime = CURRENT_TIME;
 	return i;
@@ -658,7 +660,9 @@
 		unsigned long size = PAGE_SIZE*2;
 		if (size > count)
 			size = count;
+		lock_kernel();
 		ret = write(tty, file, buf, size);
+		unlock_kernel();
 		if (ret <= 0)
 			break;
 		written += ret;
diff -u --recursive --new-file v2.3.8/linux/drivers/char/vino.c linux/drivers/char/vino.c
--- v2.3.8/linux/drivers/char/vino.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/vino.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,275 @@
+/* $Id: vino.c,v 1.4 1999/02/09 23:59:36 ulfc Exp $
+ * drivers/char/vino.c
+ *
+ * (incomplete) Driver for the Vino Video input system found in SGI Indys.
+ *
+ * Copyright (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se)
+ *
+ * This isn't complete yet, please don't expect any video until I've written
+ * some more code.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/videodev.h>
+
+#include <asm/addrspace.h>
+#include <asm/system.h>
+
+#include "vino.h"
+
+struct vino_device {
+	struct video_device vdev;
+
+	unsigned long chan;
+#define VINO_CHAN_A		0
+#define VINO_CHAN_B		1
+
+	unsigned long flags;
+#define VINO_DMA_ACTIVE		(1<<0)
+};
+
+/* We can actually receive TV and IndyCam input at the same time. Believe it or
+ * not..
+ */
+static struct vino_device vino[2];
+
+/* Those registers have to be accessed by either *one* 64 bit write or *one* 64
+ * bit read. We need some asm to fix this. We can't use mips3 as standard
+ * because we just save 32 bits at context switch.
+ */
+
+static __inline__ unsigned long long vino_reg_read(unsigned long addr)
+{
+	unsigned long long ret __attribute__ ((aligned (64)));
+	unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE);
+	unsigned long flags;
+
+	save_and_cli(flags);
+	__asm__ __volatile__(
+		".set\tmips3\n\t"
+		".set\tnoat\n\t"
+		"ld\t$1,(%0)\n\t"
+		"sd\t$1,(%1)\n\t"
+		".set\tat\n\t"
+		".set\tmips0"
+		:
+		:"r" (virt_addr),
+		 "r" (&ret)
+		:"$1");
+	restore_flags(flags);
+
+	return ret;
+}
+
+static __inline__ void vino_reg_write(unsigned long long value,
+				      unsigned long addr)
+{
+	unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE);
+	unsigned long flags;
+
+	/* we might lose the upper parts of the registers which are not saved
+	 * if there comes an interrupt in our way, play safe */
+
+	save_and_cli(flags);
+	__asm__ __volatile__(
+		".set\tmips3\n\t"
+		".set\tnoat\n\t"
+		"ld\t$1,(%0)\n\t"
+		"sd\t$1,(%1)\n\t"
+		".set\tat\n\t"
+		".set\tmips0"
+		:
+		:"r" (&value),
+		 "r" (virt_addr)
+		:"$1");
+	restore_flags(flags);
+}
+
+static __inline__ void vino_reg_and(unsigned long long value,
+				    unsigned long addr)
+{
+	unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE);
+	unsigned long flags;
+
+	save_and_cli(flags);
+	__asm__ __volatile__(
+		".set\tmips3\n\t"
+		".set\tnoat\n\t"
+		"ld\t$1,(%0)\n\t"
+		"ld\t$2,(%1)\n\t"
+		"and\t$1,$1,$2\n\t"
+		"sd\t$1,(%0)\n\t"
+		".set\tat\n\t"
+		".set\tmips0"
+		:
+		:"r" (virt_addr),
+		 "r" (&value)
+		:"$1","$2");
+	restore_flags(flags);
+}
+
+static __inline__ void vino_reg_or(unsigned long long value,
+				   unsigned long addr)
+{
+	unsigned long virt_addr = KSEG1ADDR(addr + VINO_BASE);
+	unsigned long flags;
+
+	save_and_cli(flags);
+	__asm__ __volatile__(
+		".set\tmips3\n\t"
+		".set\tnoat\n\t"
+		"ld\t$1,(%0)\n\t"
+		"ld\t$2,(%1)\n\t"
+		"or\t$1,$1,$2\n\t"
+		"sd\t$1,(%0)\n\t"
+		".set\tat\n\t"
+		".set\tmips0"
+		:
+		:"r" (virt_addr),
+		 "r" (&value)
+		:"$1","$2");
+	restore_flags(flags);
+}
+
+static int vino_dma_setup(void)
+{
+	return 0;
+}
+
+static void vino_dma_stop(void)
+{
+
+}
+
+static int vino_init(void)
+{
+	unsigned long ret;
+	unsigned short rev, id;
+	unsigned long long foo;
+	unsigned long *bar;
+
+	bar = (unsigned long *) &foo;
+
+	ret = vino_reg_read(VINO_REVID);
+
+	rev = (ret & VINO_REVID_REV_MASK);
+	id = (ret & VINO_REVID_ID_MASK) >> 4;
+
+	printk("Vino: ID:%02hx Rev:%02hx\n", id, rev);
+
+	foo = vino_reg_read(VINO_A_DESC_DATA0);
+	printk("0x%lx", bar[0]);
+	printk("%lx ", bar[1]);
+	foo = vino_reg_read(VINO_A_DESC_DATA1);
+	printk("0x%lx", bar[0]);
+	printk("%lx ", bar[1]);
+	foo = vino_reg_read(VINO_A_DESC_DATA2);
+	printk("0x%lx", bar[0]);
+	printk("%lx ", bar[1]);
+	foo = vino_reg_read(VINO_A_DESC_DATA3);
+	printk("0x%lx", bar[0]);
+	printk("%lx\n", bar[1]);
+	foo = vino_reg_read(VINO_B_DESC_DATA0);
+	printk("0x%lx", bar[0]);
+	printk("%lx ", bar[1]);
+	foo = vino_reg_read(VINO_B_DESC_DATA1);
+	printk("0x%lx", bar[0]);
+	printk("%lx ", bar[1]);
+	foo = vino_reg_read(VINO_B_DESC_DATA2);
+	printk("0x%lx", bar[0]);
+	printk("%lx ", bar[1]);
+	foo = vino_reg_read(VINO_B_DESC_DATA3);
+	printk("0x%lx", bar[0]);
+	printk("%lx\n", bar[1]);
+
+	return 0;
+}
+
+static void vino_dma_go(struct vino_device *v)
+{
+	
+}
+
+/* Reset the vino back to default state */
+
+static void vino_setup(struct vino_device *v)
+{
+	
+}
+
+static int vino_open(struct video_device *dev, int flags)
+{
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static void vino_close(struct video_device *dev)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static int vino_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	return 0;
+}
+
+static int vino_mmap(struct video_device *dev, const char *adr,
+		     unsigned long size)
+{
+	return 0;
+}
+
+static struct video_device vino_dev = {
+	"Vino IndyCam/TV",
+	VID_TYPE_CAPTURE,
+	VID_HARDWARE_VINO,
+	vino_open,
+	vino_close,
+	NULL,		/* vino_read */
+	NULL,		/* vino_write */
+	NULL,		/* vino_poll */
+	vino_ioctl,
+	vino_mmap,
+	NULL,		/* vino_init */
+	NULL,
+	0,
+	0
+};
+
+__initfunc(int init_vino(struct video_device *dev))
+{
+	int err;
+
+	err = vino_init();
+	if (err)
+		return err;
+
+#if 0
+	if (video_register_device(&vinodev, VFL_TYPE_GRABBER) == -1) {
+		return -ENODEV;
+	}
+#endif
+
+	return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	int err;
+
+	err = vino_init();
+	if (err)
+		return err;
+
+	return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif
diff -u --recursive --new-file v2.3.8/linux/drivers/char/vino.h linux/drivers/char/vino.h
--- v2.3.8/linux/drivers/char/vino.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/vino.h	Fri Jun 25 17:39:14 1999
@@ -0,0 +1,118 @@
+/* $Id: vino.h,v 1.2 1999/02/09 23:03:53 ulfc Exp $
+ * drivers/sgi/vino.h
+ *
+ * Copyright (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se)
+ */
+
+#define VINO_BASE		0x0008000
+
+#define VINO_REVID		0x0000
+#define VINO_CTRL		0x0008
+#define VINO_INTSTAT		0x0010	/* Interrupt status */
+#define VINO_I2C_CTRL		0x0018
+#define VINO_I2C_DATA		0x0020
+#define VINO_A_ALPHA		0x0028	/* Channel A ... */
+#define VINO_A_CLIPS		0x0030	/* Clipping start */
+#define VINO_A_CLIPE		0x0038	/* Clipping end */
+#define VINO_A_FRAMERT		0x0040	/* Framerate */
+#define VINO_A_FLDCNT		0x0048	/* Field counter */
+#define VINO_A_LNSZ		0x0050
+#define VINO_A_LNCNT		0x0058
+#define VINO_A_PGIX		0x0060	/* Page index */
+#define VINO_A_DESC_PTR		0x0068	/* Ptr to next four descriptors */
+#define VINO_A_DESC_TLB_PTR	0x0070	/* Ptr to start of descriptor table */
+#define VINO_A_DESC_DATA0	0x0078	/* Descriptor data 0 */
+#define VINO_A_DESC_DATA1	0x0080	/* ... */
+#define VINO_A_DESC_DATA2	0x0088
+#define VINO_A_DESC_DATA3	0x0090
+#define VINO_A_FIFO_THRESHOLD	0x0098	/* FIFO threshold */
+#define VINO_A_FIFO_RP		0x00a0
+#define VINO_A_FIFO_WP		0x00a8
+#define VINO_B_ALPHA		0x00b0	/* Channel B ... */
+#define VINO_B_CLIPS		0x00b8
+#define VINO_B_CLIPE		0x00c0
+#define VINO_B_FRAMERT		0x00c8
+#define VINO_B_FLDCNT		0x00d0
+#define VINO_B_LNSZ		0x00d8
+#define VINO_B_LNCNT		0x00e0
+#define VINO_B_PGIX		0x00e8
+#define VINO_B_DESC_PTR		0x00f0
+#define VINO_B_DESC_TLB_PTR	0x00f8
+#define VINO_B_DESC_DATA0	0x0100
+#define VINO_B_DESC_DATA1	0x0108
+#define VINO_B_DESC_DATA2	0x0110
+#define VINO_B_DESC_DATA3	0x0118
+#define VINO_B_FIFO_THRESHOLD	0x0120
+#define VINO_B_FIFO_RP		0x0128
+#define VINO_B_FIFO_WP		0x0130
+
+/* Bits in the VINO_REVID register */
+
+#define VINO_REVID_REV_MASK		0x000f	/* bits 0:3 */
+#define VINO_REVID_ID_MASK		0x00f0	/* bits 4:7 */
+
+/* Bits in the VINO_CTRL register */
+
+#define VINO_CTRL_LITTLE_ENDIAN		(1<<0)
+#define VINO_CTRL_A_FIELD_TRANS_INT	(1<<1)	/* Field transferred int */
+#define VINO_CTRL_A_FIFO_OF_INT		(1<<2)	/* FIFO overflow int */
+#define VINO_CTRL_A_END_DESC_TBL_INT	(1<<3)	/* End of desc table int */
+#define VINO_CTRL_B_FIELD_TRANS_INT	(1<<4)	/* Field transferred int */
+#define VINO_CTRL_B_FIFO_OF_INT		(1<<5)	/* FIFO overflow int */
+#define VINO_CTRL_B_END_DESC_TLB_INT	(1<<6)	/* End of desc table int */
+#define VINO_CTRL_A_DMA_ENBL		(1<<7)
+#define VINO_CTRL_A_INTERLEAVE_ENBL	(1<<8)
+#define VINO_CTRL_A_SYNC_ENBL		(1<<9)
+#define VINO_CTRL_A_SELECT		(1<<10)	/* 1=D1 0=Philips */
+#define VINO_CTRL_A_RGB			(1<<11)	/* 1=RGB 0=YUV */
+#define VINO_CTRL_A_LUMA_ONLY		(1<<12)
+#define VINO_CTRL_A_DEC_ENBL		(1<<13)	/* Decimation */
+#define VINO_CTRL_A_DEC_SCALE_MASK	0x1c000	/* bits 14:17 */
+#define VINO_CTRL_A_DEC_HOR_ONLY	(1<<17)	/* Horizontal only */
+#define VINO_CTRL_A_DITHER		(1<<18)	/* 24 -> 8 bit dither */
+#define VINO_CTRL_B_DMA_ENBL		(1<<19)
+#define VINO_CTRL_B_INTERLEAVE_ENBL	(1<<20)
+#define VINO_CTRL_B_SYNC_ENBL		(1<<21)
+#define VINO_CTRL_B_SELECT		(1<<22)	/* 1=D1 0=Philips */
+#define VINO_CTRL_B_RGB			(1<<22)	/* 1=RGB 0=YUV */
+#define VINO_CTRL_B_LUMA_ONLY		(1<<23)
+#define VINO_CTRL_B_DEC_ENBL		(1<<24)	/* Decimation */
+#define VINO_CTRL_B_DEC_SCALE_MASK	0x1c000000	/* bits 25:28 */
+#define VINO_CTRL_B_DEC_HOR_ONLY	(1<<29)	/* Decimation horizontal only */
+#define VINO_CTRL_B_DITHER		(1<<30)	/* ChanB 24 -> 8 bit dither */
+
+/* Bits in the Interrupt and Status register */
+
+#define VINO_INTSTAT_A_FIELD_TRANS	(1<<0)	/* Field transferred int */
+#define VINO_INTSTAT_A_FIFO_OF		(1<<1)	/* FIFO overflow int */
+#define VINO_INTSTAT_A_END_DESC_TBL	(1<<2)	/* End of desc table int */
+#define VINO_INTSTAT_B_FIELD_TRANS	(1<<3)	/* Field transferred int */
+#define VINO_INTSTAT_B_FIFO_OF		(1<<4)	/* FIFO overflow int */
+#define VINO_INTSTAT_B_END_DESC_TBL	(1<<5)	/* End of desc table int */
+
+/* Bits in the Clipping Start register */
+
+#define VINO_CLIPS_START		0x3ff		/* bits 0:9 */
+#define VINO_CLIPS_ODD_MASK		0x7fc00		/* bits 10:18 */
+#define VINO_CLIPS_EVEN_MASK		0xff80000	/* bits 19:27 */
+
+/* Bits in the Clipping End register */
+
+#define VINO_CLIPE_END			0x3ff		/* bits 0:9 */
+#define VINO_CLIPE_ODD_MASK		0x7fc00		/* bits 10:18 */
+#define VINO_CLIPE_EVEN_MASK		0xff80000	/* bits 19:27 */
+
+/* Bits in the Frame Rate register */
+
+#define VINO_FRAMERT_PAL		(1<<0)	/* 0=NTSC 1=PAL */
+#define VINO_FRAMERT_RT_MASK		0x1ffe		/* bits 1:12 */
+
+/* Bits in the VINO_I2C_CTRL */
+
+#define VINO_CTRL_I2C_IDLE		(1<<0)	/* write: 0=force idle
+						 * read: 0=idle 1=not idle */
+#define VINO_CTRL_I2C_DIR		(1<<1)	/* 0=read 1=write */
+#define VINO_CTRL_I2C_MORE_BYTES	(1<<2)	/* 0=last byte 1=more bytes */
+#define VINO_CTRL_I2C_TRANS_BUSY	(1<<4)	/* 0=trans done 1=trans busy */
+#define VINO_CTRL_I2C_ACK		(1<<5)	/* 0=ack received 1=ack not */
+#define VINO_CTRL_I2C_BUS_ERROR		(1<<7)	/* 0=no bus err 1=bus err */
diff -u --recursive --new-file v2.3.8/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.3.8/linux/drivers/char/vt.c	Tue May 11 14:37:40 1999
+++ linux/drivers/char/vt.c	Fri Jun 25 17:39:14 1999
@@ -88,7 +88,8 @@
  * comments - KDMKTONE doesn't put the process to sleep.
  */
 
-#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) || defined(__mips__)
+#if defined(__i386__) || defined(__alpha__) || defined(__powerpc__) \
+    || (defined(__mips__) && !defined(CONFIG_SGI))
 
 static void
 kd_nosound(unsigned long ignored)
diff -u --recursive --new-file v2.3.8/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- v2.3.8/linux/drivers/i2o/i2o_config.c	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_config.c	Wed Jun 30 11:24:54 1999
@@ -14,7 +14,6 @@
  *	2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.3.8/linux/drivers/i2o/i2o_core.c	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_core.c	Wed Jun 30 11:24:54 1999
@@ -19,7 +19,6 @@
  *	
  */
  
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/i2o/i2o_lan.c linux/drivers/i2o/i2o_lan.c
--- v2.3.8/linux/drivers/i2o/i2o_lan.c	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_lan.c	Wed Jun 30 11:24:54 1999
@@ -25,6 +25,7 @@
  *			- code/test for other LAN classes
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/netdevice.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.3.8/linux/drivers/i2o/i2o_pci.c	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_pci.c	Wed Jun 30 11:24:54 1999
@@ -12,7 +12,6 @@
  *	2 of the License, or (at your option) any later version.
  */
  
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c
--- v2.3.8/linux/drivers/i2o/i2o_proc.c	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_proc.c	Wed Jun 30 11:24:54 1999
@@ -38,7 +38,6 @@
 #define FMT_U64_HEX "0x%08x%08x"
 #define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64))
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/i2o.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.8/linux/drivers/net/Config.in	Mon Jun  7 14:35:09 1999
+++ linux/drivers/net/Config.in	Fri Jun 25 17:39:52 1999
@@ -42,7 +42,7 @@
     tristate 'Hydra support' CONFIG_HYDRA
   fi
   if [ "$CONFIG_MIPS_JAZZ" = "y" ]; then
-    bool 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
+    tristate 'MIPS JAZZ onboard SONIC Ethernet support' CONFIG_MIPS_JAZZ_SONIC
   fi
   bool '3COM cards' CONFIG_NET_VENDOR_3COM
   if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
diff -u --recursive --new-file v2.3.8/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.8/linux/drivers/net/Makefile	Thu Jun 17 01:11:35 1999
+++ linux/drivers/net/Makefile	Fri Jun 25 17:39:52 1999
@@ -876,10 +876,26 @@
 endif
 
 ifeq ($(CONFIG_MIPS_JAZZ_SONIC),y)
-L_OBJS += sonic.o
+L_OBJS += jazzsonic.o
 else
   ifeq ($(CONFIG_MIPS_JAZZ_SONIC),m)
-    M_OBJS += sonic.o
+  M_OBJS += jazzsonic.o
+  endif
+endif
+
+ifeq ($(CONFIG_BAGETLANCE),y)
+L_OBJS += bagetlance.o
+else
+  ifeq ($(CONFIG_BAGETLANCE),m)
+  M_OBJS += bagetlance.o
+  endif
+endif
+
+ifeq ($(CONFIG_DECLANCE),y)
+L_OBJS += declance.o
+else
+  ifeq ($(CONFIG_DECLANCE),m)
+  M_OBJS += declance.o
   endif
 endif
 
diff -u --recursive --new-file v2.3.8/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.8/linux/drivers/net/Space.c	Mon Jun  7 14:35:09 1999
+++ linux/drivers/net/Space.c	Fri Jun 25 17:39:52 1999
@@ -111,6 +111,8 @@
 extern int epic100_probe(struct device *dev);
 extern int rtl8139_probe(struct device *dev);
 extern int hplance_probe(struct device *dev);
+extern int bagetlance_probe(struct device *);
+extern int dec_lance_probe(struct device *);
 extern int via_rhine_probe(struct device *dev);
 extern int tc515_probe(struct device *dev);
 extern int lance_probe(struct device *dev);
@@ -442,6 +444,12 @@
 struct devprobe mips_probes[] __initdata = {
 #ifdef CONFIG_MIPS_JAZZ_SONIC
 	{sonic_probe, 0},
+#endif
+#ifdef CONFIG_DECLANCE		/* DECstation on-board controller */
+	{dec_lance_probe, 0},   /* and maybe TURBOchannel option boards */
+#endif
+#ifdef CONFIG_BAGETLANCE        /* Lance-based Baget ethernet boards */
+        {bagetlance_probe, 0},
 #endif
 	{NULL, 0},
 };
diff -u --recursive --new-file v2.3.8/linux/drivers/net/bagetlance.c linux/drivers/net/bagetlance.c
--- v2.3.8/linux/drivers/net/bagetlance.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/bagetlance.c	Fri Jun 25 17:39:52 1999
@@ -0,0 +1,1363 @@
+/* $Id$
+ * vmelance.c: Ethernet driver for VME Lance cards on Baget/MIPS
+ *      This code stealed and adopted from linux/drivers/net/atarilance.c
+ *      See that for author info
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+
+/* 
+ * Driver code for Baget/Lance taken from atarilance.c, which also
+ * works well in case of Besta. Most significant changes made here
+ * related with 16BIT-only access to A24 space.
+ */
+
+static char *version = "bagetlance.c: v1.1 11/10/98\n";
+
+#include <linux/module.h>
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/baget/baget.h>
+
+#define BAGET_LANCE_IRQ  BAGET_IRQ_MASK(0xdf)
+
+/*
+ *  Define following if you don't need 16BIT-only access to Lance memory
+ *  (Normally BAGET needs it)
+ */
+#undef NORMAL_MEM_ACCESS 
+
+/* Debug level:
+ *  0 = silent, print only serious errors
+ *  1 = normal, print error messages
+ *  2 = debug, print debug infos
+ *  3 = debug, print even more debug infos (packet data)
+ */
+
+#define	LANCE_DEBUG	1  
+
+#ifdef LANCE_DEBUG
+static int lance_debug = LANCE_DEBUG;
+#else
+static int lance_debug = 1;
+#endif
+MODULE_PARM(lance_debug, "i");
+
+/* Print debug messages on probing? */
+#undef LANCE_DEBUG_PROBE
+
+#define	DPRINTK(n,a)							\
+	do {										\
+		if (lance_debug >= n)					\
+			printk a;							\
+	} while( 0 )
+
+#ifdef LANCE_DEBUG_PROBE
+# define PROBE_PRINT(a)	printk a
+#else
+# define PROBE_PRINT(a)
+#endif
+
+/* These define the number of Rx and Tx buffers as log2. (Only powers
+ * of two are valid)
+ * Much more rx buffers (32) are reserved than tx buffers (8), since receiving
+ * is more time critical then sending and packets may have to remain in the
+ * board's memory when main memory is low.
+ */
+
+/* Baget Lance has 64K on-board memory, so it looks we can't increase
+   buffer quantity (40*1.5K is about 64K) */
+
+#define TX_LOG_RING_SIZE			3
+#define RX_LOG_RING_SIZE			5
+
+/* These are the derived values */
+
+#define TX_RING_SIZE			(1 << TX_LOG_RING_SIZE)
+#define TX_RING_LEN_BITS		(TX_LOG_RING_SIZE << 5)
+#define	TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
+
+#define RX_RING_SIZE			(1 << RX_LOG_RING_SIZE)
+#define RX_RING_LEN_BITS		(RX_LOG_RING_SIZE << 5)
+#define	RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
+
+/* The LANCE Rx and Tx ring descriptors. */
+struct lance_rx_head {
+	volatile unsigned short	base;		/* Low word of base addr */
+#ifdef NORMAL_MEM_ACCESS
+       /* Following two fields are joined into one short to guarantee
+		  16BIT access to Baget lance registers */
+	volatile unsigned char	flag;
+	unsigned char			base_hi;	/* High word of base addr (unused) */
+#else
+/* Following macros are used as replecements to 8BIT fields */
+#define GET_FLAG(h)    (((h)->flag_base_hi >> 8) & 0xff)
+#define SET_FLAG(h,f)  (h)->flag_base_hi = ((h)->flag_base_hi & 0xff) | \
+		                                                (((unsigned)(f)) << 8)
+	volatile unsigned short flag_base_hi; 
+#endif
+	volatile short			buf_length;	/* This length is 2s complement! */
+	volatile short			msg_length;	/* This length is "normal". */
+};
+
+
+struct lance_tx_head {
+	volatile unsigned short	base;		/* Low word of base addr */
+#ifdef NORMAL_MEM_ACCESS 
+/* See comments above about 8BIT-access Baget A24-space problems */
+	volatile unsigned char	flag;
+	unsigned char			base_hi;	/* High word of base addr (unused) */
+#else
+	volatile unsigned short  flag_base_hi;
+#endif
+	volatile short			length;		/* Length is 2s complement! */
+	volatile short			misc;
+};
+
+struct ringdesc {
+	volatile unsigned short	adr_lo;		/* Low 16 bits of address */
+#ifdef NORMAL_MEM_ACCESS 
+/* See comments above about 8BIT-access Bage A24-space problems */
+	unsigned char	len;		/* Length bits */
+	unsigned char	adr_hi;		/* High 8 bits of address (unused) */
+#else
+	volatile unsigned short  len_adr_hi;
+#endif
+};
+
+/* The LANCE initialization block, described in databook. */
+struct lance_init_block {
+	unsigned short	mode;		/* Pre-set mode */
+	unsigned char	hwaddr[6];	/* Physical ethernet address */
+	unsigned		filter[2];	/* Multicast filter (unused). */
+	/* Receive and transmit ring base, along with length bits. */
+	struct ringdesc	rx_ring;
+	struct ringdesc	tx_ring;
+};
+
+/* The whole layout of the Lance shared memory */
+struct lance_memory {
+	struct lance_init_block	init;
+	struct lance_tx_head	tx_head[TX_RING_SIZE];
+	struct lance_rx_head	rx_head[RX_RING_SIZE];
+	char					packet_area[0];	/* packet data follow after the
+											 * init block and the ring
+											 * descriptors and are located
+											 * at runtime */
+};
+
+/* RieblCard specifics:
+ * The original TOS driver for these cards reserves the area from offset
+ * 0xee70 to 0xeebb for storing configuration data. Of interest to us is the
+ * Ethernet address there, and the magic for verifying the data's validity.
+ * The reserved area isn't touch by packet buffers. Furthermore, offset 0xfffe
+ * is reserved for the interrupt vector number.
+ */
+#define	RIEBL_RSVD_START	0xee70
+#define	RIEBL_RSVD_END		0xeec0
+#define RIEBL_MAGIC			0x09051990
+#define RIEBL_MAGIC_ADDR	((unsigned long *)(((char *)MEM) + 0xee8a))
+#define RIEBL_HWADDR_ADDR	((unsigned char *)(((char *)MEM) + 0xee8e))
+#define RIEBL_IVEC_ADDR		((unsigned short *)(((char *)MEM) + 0xfffe))
+
+/* This is a default address for the old RieblCards without a battery
+ * that have no ethernet address at boot time. 00:00:36:04 is the
+ * prefix for Riebl cards, the 00:00 at the end is arbitrary.
+ */
+
+static unsigned char OldRieblDefHwaddr[6] = {
+	0x00, 0x00, 0x36, 0x04, 0x00, 0x00
+};
+
+/* I/O registers of the Lance chip */
+
+struct lance_ioreg {
+/* base+0x0 */	volatile unsigned short	data;
+/* base+0x2 */	volatile unsigned short	addr;
+				unsigned char			_dummy1[3];
+/* base+0x7 */	volatile unsigned char	ivec;
+				unsigned char			_dummy2[5];
+/* base+0xd */	volatile unsigned char	eeprom;
+				unsigned char			_dummy3;
+/* base+0xf */	volatile unsigned char	mem;
+};
+
+/* Types of boards this driver supports */
+
+enum lance_type {
+	OLD_RIEBL,		/* old Riebl card without battery */
+	NEW_RIEBL,		/* new Riebl card with battery */
+	PAM_CARD		/* PAM card with EEPROM */
+};
+
+static char *lance_names[] = {
+	"Riebl-Card (without battery)",
+	"Riebl-Card (with battery)",
+	"PAM intern card"
+};
+
+/* The driver's private device structure */
+
+struct lance_private {
+	enum lance_type		cardtype;
+	struct lance_ioreg	*iobase;
+	struct lance_memory	*mem;
+	int					cur_rx, cur_tx;	/* The next free ring entry */
+	int					dirty_tx;		/* Ring entries to be freed. */
+						/* copy function */
+	void				*(*memcpy_f)( void *, const void *, size_t );
+	struct net_device_stats stats;
+/* These two must be ints for set_bit() */
+	int					tx_full;
+	int					lock;
+};
+
+/* I/O register access macros */
+
+#define	MEM		lp->mem
+#define	DREG	IO->data
+#define	AREG	IO->addr
+#define	REGA(a)	( AREG = (a), DREG )
+
+/* Definitions for packet buffer access: */
+#define PKT_BUF_SZ		1544
+/* Get the address of a packet buffer corresponding to a given buffer head */
+#define	PKTBUF_ADDR(head)	(((unsigned char *)(MEM)) + (head)->base)
+
+/* Possible memory/IO addresses for probing */
+
+struct lance_addr {
+	unsigned long	memaddr;
+	unsigned long	ioaddr;
+	int				slow_flag;
+} lance_addr_list[] = {
+	{ BAGET_LANCE_MEM_BASE, BAGET_LANCE_IO_BASE, 1 }	/* Baget Lance */
+};
+
+#define	N_LANCE_ADDR	(sizeof(lance_addr_list)/sizeof(*lance_addr_list))
+
+
+#define LANCE_HI_BASE (0xff & (BAGET_LANCE_MEM_BASE >> 16))
+
+/* Definitions for the Lance */
+
+/* tx_head flags */
+#define TMD1_ENP		0x01	/* end of packet */
+#define TMD1_STP		0x02	/* start of packet */
+#define TMD1_DEF		0x04	/* deferred */
+#define TMD1_ONE		0x08	/* one retry needed */
+#define TMD1_MORE		0x10	/* more than one retry needed */
+#define TMD1_ERR		0x40	/* error summary */
+#define TMD1_OWN 		0x80	/* ownership (set: chip owns) */
+
+#define TMD1_OWN_CHIP	TMD1_OWN
+#define TMD1_OWN_HOST	0
+
+/* tx_head misc field */
+#define TMD3_TDR		0x03FF	/* Time Domain Reflectometry counter */
+#define TMD3_RTRY		0x0400	/* failed after 16 retries */
+#define TMD3_LCAR		0x0800	/* carrier lost */
+#define TMD3_LCOL		0x1000	/* late collision */
+#define TMD3_UFLO		0x4000	/* underflow (late memory) */
+#define TMD3_BUFF		0x8000	/* buffering error (no ENP) */
+
+/* rx_head flags */
+#define RMD1_ENP		0x01	/* end of packet */
+#define RMD1_STP		0x02	/* start of packet */
+#define RMD1_BUFF		0x04	/* buffer error */
+#define RMD1_CRC		0x08	/* CRC error */
+#define RMD1_OFLO		0x10	/* overflow */
+#define RMD1_FRAM		0x20	/* framing error */
+#define RMD1_ERR		0x40	/* error summary */
+#define RMD1_OWN 		0x80	/* ownership (set: ship owns) */
+
+#define RMD1_OWN_CHIP	RMD1_OWN
+#define RMD1_OWN_HOST	0
+
+/* register names */
+#define CSR0	0		/* mode/status */
+#define CSR1	1		/* init block addr (low) */
+#define CSR2	2		/* init block addr (high) */
+#define CSR3	3		/* misc */
+#define CSR8	8	  	/* address filter */
+#define CSR15	15		/* promiscuous mode */
+
+/* CSR0 */
+/* (R=readable, W=writeable, S=set on write, C=clear on write) */
+#define CSR0_INIT	0x0001		/* initialize (RS) */
+#define CSR0_STRT	0x0002		/* start (RS) */
+#define CSR0_STOP	0x0004		/* stop (RS) */
+#define CSR0_TDMD	0x0008		/* transmit demand (RS) */
+#define CSR0_TXON	0x0010		/* transmitter on (R) */
+#define CSR0_RXON	0x0020		/* receiver on (R) */
+#define CSR0_INEA	0x0040		/* interrupt enable (RW) */
+#define CSR0_INTR	0x0080		/* interrupt active (R) */
+#define CSR0_IDON	0x0100		/* initialization done (RC) */
+#define CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
+#define CSR0_RINT	0x0400		/* receiver interrupt (RC) */
+#define CSR0_MERR	0x0800		/* memory error (RC) */
+#define CSR0_MISS	0x1000		/* missed frame (RC) */
+#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) (RC) */
+#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits (RC) */
+#define CSR0_ERR	0x8000		/* error (RC) */
+
+/* CSR3 */
+#define CSR3_BCON	0x0001		/* byte control */
+#define CSR3_ACON	0 // fixme: 0x0002		/* ALE control */
+#define CSR3_BSWP	0x0004		/* byte swap (1=big endian) */
+
+
+
+/***************************** Prototypes *****************************/
+
+static int addr_accessible( volatile void *regp, int wordflag, int
+                            writeflag );
+static unsigned long lance_probe1( struct device *dev, struct lance_addr
+                                   *init_rec );
+static int lance_open( struct device *dev );
+static void lance_init_ring( struct device *dev );
+static int lance_start_xmit( struct sk_buff *skb, struct device *dev );
+static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
+static int lance_rx( struct device *dev );
+static int lance_close( struct device *dev );
+static struct net_device_stats *lance_get_stats( struct device *dev );
+static void set_multicast_list( struct device *dev );
+static int lance_set_mac_address( struct device *dev, void *addr );
+
+/************************* End of Prototypes **************************/
+
+/* Network traffic statistic (bytes) */
+
+int lance_stat = 0;
+
+static void update_lance_stat (int len) {
+		lance_stat += len;
+}
+
+/* 
+   This function is used to access Baget/Lance memory to avoid 
+   8/32BIT access to VAC A24 space 
+   ALL memcpy calls was chenged to this function to avoid dbe problems
+   Don't confuse with function name -- it stays from original code
+*/
+
+void *slow_memcpy( void *dst, const void *src, size_t len )
+
+{	
+	unsigned long to     = (unsigned long)dst;
+	unsigned long from   = (unsigned long)src;
+	unsigned long to_end = to +len;
+	
+	/* Unaligned flags */
+
+	int odd_from   = from   & 1;
+	int odd_to     = to     & 1;
+	int odd_to_end = to_end & 1;
+
+	/* Align for 16BIT-access first */
+
+	register unsigned short *from_a   = (unsigned short*) (from   & ~1);
+	register unsigned short *to_a     = (unsigned short*) (to     & ~1); 
+	register unsigned short *to_end_a = (unsigned short*) (to_end & ~1);
+
+	/* Caching values -- not in loop invariant */
+
+	register unsigned short from_v; 
+	register unsigned short to_v;
+
+	/* Invariant is: from_a and to_a are pointers before or exactly to
+	   currently copying byte */
+
+	if (odd_to) { 
+			/* First byte unaligned case */
+			from_v = *from_a;
+			to_v   = *to_a;
+
+			to_v &= ~0xff;
+			to_v |=  0xff & (from_v >> (odd_from ? 0 : 8));
+			*to_a++ = to_v;
+
+			if (odd_from) from_a++;
+	}
+    if (odd_from == odd_to) {
+			/* Same parity */
+			while (to_a + 7 < to_end_a) {
+					unsigned long dummy1, dummy2;
+					unsigned long reg1, reg2, reg3, reg4;
+
+					__asm__ __volatile__(
+					".set\tnoreorder\n\t"
+					".set\tnoat\n\t"
+					"lh\t%2,0(%1)\n\t"
+					"nop\n\t"
+					 "lh\t%3,2(%1)\n\t"
+					"sh\t%2,0(%0)\n\t"
+					   "lh\t%4,4(%1)\n\t"
+					 "sh\t%3,2(%0)\n\t"
+					    "lh\t%5,6(%1)\n\t"
+					   "sh\t%4,4(%0)\n\t"
+					"lh\t%2,8(%1)\n\t"
+					    "sh\t%5,6(%0)\n\t"
+					 "lh\t%3,10(%1)\n\t"
+					"sh\t%2,8(%0)\n\t"
+					  "lh\t%4,12(%1)\n\t"
+					 "sh\t%3,10(%0)\n\t"
+					    "lh\t%5,14(%1)\n\t"
+					  "sh\t%4,12(%0)\n\t"
+					 "nop\n\t"
+					    "sh\t%5,14(%0)\n\t"
+					".set\tat\n\t"
+					".set\treorder"
+					:"=r" (dummy1), "=r" (dummy2),
+					"=&r" (reg1), "=&r" (reg2), "=&r" (reg3), "=&r" (reg4)
+					:"0" (to_a), "1" (from_a)
+					:"memory");
+
+					to_a   += 8;
+					from_a += 8;
+
+			}
+			while (to_a < to_end_a) {
+					*to_a++ = *from_a++;
+			}
+	} else {
+			/* Different parity */
+			from_v = *from_a;
+			while (to_a < to_end_a) {
+					unsigned short from_v_next;
+					from_v_next = *++from_a;
+					*to_a++ = ((from_v & 0xff)<<8) | ((from_v_next>>8) & 0xff);
+					from_v = from_v_next; 
+			}
+
+	}
+	if (odd_to_end) {
+			/* Last byte unaligned case */
+			to_v = *to_a;
+			from_v = *from_a;
+
+			to_v &= ~0xff00;
+			if (odd_from == odd_to) {
+					to_v |= from_v & 0xff00;
+			} else {
+					to_v |= (from_v<<8) & 0xff00;
+			}
+
+			*to_a = to_v;
+	}
+
+	update_lance_stat( len );
+
+	return( dst );
+}
+
+
+__initfunc(int bagetlance_probe( struct device *dev ))
+
+{	int i;
+	static int found = 0;
+
+	if (found)
+		/* Assume there's only one board possible... That seems true, since
+		 * the Riebl/PAM board's address cannot be changed. */
+		return( ENODEV );
+
+	for( i = 0; i < N_LANCE_ADDR; ++i ) {
+		if (lance_probe1( dev, &lance_addr_list[i] )) {
+			found = 1;
+			return( 0 );
+		}
+	}
+
+	return( ENODEV );
+}
+
+
+
+/* Derived from hwreg_present() in vme/config.c: */
+
+__initfunc(static int addr_accessible( volatile void *regp, 
+									   int wordflag, 
+									   int writeflag ))
+{	
+		/* We have a fine function to do it */
+		extern int try_read(unsigned long, int);
+		return try_read((unsigned long)regp, sizeof(short)) != -1;   
+}
+
+
+
+/* Original atari driver uses it */
+#define IRQ_TYPE_PRIO SA_INTERRUPT
+#define IRQ_SOURCE_TO_VECTOR(x) (x)
+
+__initfunc(static unsigned long lance_probe1( struct device *dev,
+								   struct lance_addr *init_rec ))
+
+{	volatile unsigned short *memaddr =
+		(volatile unsigned short *)init_rec->memaddr;
+	volatile unsigned short *ioaddr =
+		(volatile unsigned short *)init_rec->ioaddr;
+	struct lance_private	*lp;
+	struct lance_ioreg		*IO;
+	int 					i;
+	static int 				did_version = 0;
+	unsigned short			save1, save2;
+
+	PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
+				  (long)memaddr, (long)ioaddr ));
+
+	/* Test whether memory readable and writable */
+	PROBE_PRINT(( "lance_probe1: testing memory to be accessible\n" ));
+	if (!addr_accessible( memaddr, 1, 1 )) goto probe_fail;
+
+	if ((unsigned long)memaddr >= KSEG2) {
+			extern int kseg2_alloc_io (unsigned long addr, unsigned long size);
+			if (kseg2_alloc_io((unsigned long)memaddr, BAGET_LANCE_MEM_SIZE)) {
+					printk("bagetlance: unable map lance memory\n");
+					goto probe_fail;
+			}
+	}
+
+	/* Written values should come back... */
+	PROBE_PRINT(( "lance_probe1: testing memory to be writable (1)\n" ));
+	save1 = *memaddr;
+	*memaddr = 0x0001;
+	if (*memaddr != 0x0001) goto probe_fail;
+	PROBE_PRINT(( "lance_probe1: testing memory to be writable (2)\n" ));
+	*memaddr = 0x0000;
+	if (*memaddr != 0x0000) goto probe_fail;
+	*memaddr = save1;
+
+	/* First port should be readable and writable */
+	PROBE_PRINT(( "lance_probe1: testing ioport to be accessible\n" ));
+	if (!addr_accessible( ioaddr, 1, 1 )) goto probe_fail;
+
+	/* and written values should be readable */
+	PROBE_PRINT(( "lance_probe1: testing ioport to be writeable\n" ));
+	save2 = ioaddr[1];
+	ioaddr[1] = 0x0001;
+	if (ioaddr[1] != 0x0001) goto probe_fail;
+
+	/* The CSR0_INIT bit should not be readable */
+	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (1)\n" ));
+	save1 = ioaddr[0];
+	ioaddr[1] = CSR0;
+	ioaddr[0] = CSR0_INIT | CSR0_STOP;
+	if (ioaddr[0] != CSR0_STOP) {
+		ioaddr[0] = save1;
+		ioaddr[1] = save2;
+		goto probe_fail;
+	}
+	PROBE_PRINT(( "lance_probe1: testing CSR0 register function (2)\n" ));
+	ioaddr[0] = CSR0_STOP;
+	if (ioaddr[0] != CSR0_STOP) {
+		ioaddr[0] = save1;
+		ioaddr[1] = save2;
+		goto probe_fail;
+	}
+
+	/* Now ok... */
+	PROBE_PRINT(( "lance_probe1: Lance card detected\n" ));
+	goto probe_ok;
+
+  probe_fail:
+	return( 0 );
+
+  probe_ok:
+	init_etherdev( dev, sizeof(struct lance_private) );
+	if (!dev->priv)
+		dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL );
+	lp = (struct lance_private *)dev->priv;
+	MEM = (struct lance_memory *)memaddr;
+	IO = lp->iobase = (struct lance_ioreg *)ioaddr;
+	dev->base_addr = (unsigned long)ioaddr; /* informational only */
+	lp->memcpy_f = init_rec->slow_flag ? slow_memcpy : memcpy;
+
+	REGA( CSR0 ) = CSR0_STOP;
+
+	/* Now test for type: If the eeprom I/O port is readable, it is a
+	 * PAM card */
+	if (addr_accessible( &(IO->eeprom), 0, 0 )) {
+		/* Switch back to Ram */
+		i = IO->mem;
+		lp->cardtype = PAM_CARD;
+	}
+#ifdef NORMAL_MEM_ACCESS
+	else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
+#else
+	else if (({
+			unsigned short *a = (unsigned short*)RIEBL_MAGIC_ADDR;
+		    (((int)a[0]) << 16) + ((int)a[1]) == RIEBL_MAGIC;
+	})) {
+#endif
+		lp->cardtype = NEW_RIEBL;
+	}
+	else
+		lp->cardtype = OLD_RIEBL;
+
+	if (lp->cardtype == PAM_CARD ||
+		memaddr == (unsigned short *)0xffe00000) {
+		/* PAMs card and Riebl on ST use level 5 autovector */
+		request_irq(BAGET_LANCE_IRQ, lance_interrupt, IRQ_TYPE_PRIO,
+		            "PAM/Riebl-ST Ethernet", dev);
+		dev->irq = (unsigned short)BAGET_LANCE_IRQ;
+	}
+	else {
+		/* For VME-RieblCards, request a free VME int;
+		 * (This must be unsigned long, since dev->irq is short and the
+		 * IRQ_MACHSPEC bit would be cut off...)
+		 */
+		unsigned long irq = BAGET_LANCE_IRQ; 
+		if (!irq) {
+			printk( "Lance: request for VME interrupt failed\n" );
+			return( 0 );
+		}
+		request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
+		            "Riebl-VME Ethernet", dev);
+		dev->irq = irq;
+	}
+
+	printk("%s: %s at io %#lx, mem %#lx, irq %d%s, hwaddr ",
+		   dev->name, lance_names[lp->cardtype],
+		   (unsigned long)ioaddr,
+		   (unsigned long)memaddr,
+		   dev->irq,
+		   init_rec->slow_flag ? " (slow memcpy)" : "" );
+
+	/* Get the ethernet address */
+	switch( lp->cardtype ) {
+	  case OLD_RIEBL:
+		/* No ethernet address! (Set some default address) */
+		slow_memcpy( dev->dev_addr, OldRieblDefHwaddr, 6 );
+		break;
+	  case NEW_RIEBL:
+		lp->memcpy_f( dev->dev_addr, RIEBL_HWADDR_ADDR, 6 );
+		break;
+	  case PAM_CARD:
+		i = IO->eeprom;
+		for( i = 0; i < 6; ++i )
+			dev->dev_addr[i] =
+				((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
+				((((unsigned short *)MEM)[i*2+1] & 0x0f));
+		i = IO->mem;
+		break;
+	}
+	for( i = 0; i < 6; ++i )
+		printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+	if (lp->cardtype == OLD_RIEBL) {
+		printk( "%s: Warning: This is a default ethernet address!\n",
+				dev->name );
+		printk( "      Use \"ifconfig hw ether ...\" to set the address.\n" );
+	}
+
+	MEM->init.mode = 0x0000;		/* Disable Rx and Tx. */
+
+	{
+			unsigned char hwaddr[6];
+			for( i = 0; i < 6; i++ ) 
+					hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
+			slow_memcpy(MEM->init.hwaddr, hwaddr, sizeof(hwaddr));
+	}
+
+	MEM->init.filter[0] = 0x00000000;
+	MEM->init.filter[1] = 0x00000000;
+	MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
+
+#ifdef NORMAL_MEM_ACCESS
+	MEM->init.rx_ring.adr_hi = LANCE_HI_BASE; 
+	MEM->init.rx_ring.len    = RX_RING_LEN_BITS;
+#else
+	MEM->init.rx_ring.len_adr_hi = 
+			((unsigned)RX_RING_LEN_BITS << 8) | LANCE_HI_BASE;
+#endif
+
+
+	MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
+
+#ifdef NORMAL_MEM_ACCESS
+	MEM->init.tx_ring.adr_hi = LANCE_HI_BASE; 
+	MEM->init.tx_ring.len    = TX_RING_LEN_BITS;
+#else
+	MEM->init.tx_ring.len_adr_hi = 
+			((unsigned)TX_RING_LEN_BITS<<8) | LANCE_HI_BASE;
+#endif
+
+	if (lp->cardtype == PAM_CARD)
+		IO->ivec = IRQ_SOURCE_TO_VECTOR(dev->irq);
+	else
+		*RIEBL_IVEC_ADDR = IRQ_SOURCE_TO_VECTOR(dev->irq);
+
+	if (did_version++ == 0)
+		DPRINTK( 1, ( version ));
+
+	/* The LANCE-specific entries in the device structure. */
+	dev->open = &lance_open;
+	dev->hard_start_xmit = &lance_start_xmit;
+	dev->stop = &lance_close;
+	dev->get_stats = &lance_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->set_mac_address = &lance_set_mac_address;
+	dev->start = 0;
+
+	memset( &lp->stats, 0, sizeof(lp->stats) );
+
+	return( 1 );
+}
+
+
+static int lance_open( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_ioreg	 *IO = lp->iobase;
+	int i;
+
+	DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
+
+	lance_init_ring(dev);
+	/* Re-initialize the LANCE, and start it when done. */
+
+	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
+	REGA( CSR2 ) = 0;
+	REGA( CSR1 ) = 0;
+	REGA( CSR0 ) = CSR0_INIT;
+	/* From now on, AREG is kept to point to CSR0 */
+
+	i = 1000000;
+	while (--i > 0)
+		if (DREG & CSR0_IDON)
+			break;
+	if (i < 0 || (DREG & CSR0_ERR)) {
+		DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
+					  dev->name, i, DREG ));
+		DREG = CSR0_STOP;
+		return( -EIO );
+	}
+	DREG = CSR0_IDON;
+	DREG = CSR0_STRT;
+	DREG = CSR0_INEA;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
+	MOD_INC_USE_COUNT;
+
+	return( 0 );
+}
+
+
+/* Initialize the LANCE Rx and Tx rings. */
+
+static void lance_init_ring( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int i;
+	unsigned offset;
+
+	lp->lock = 0;
+	lp->tx_full = 0;
+	lp->cur_rx = lp->cur_tx = 0;
+	lp->dirty_tx = 0;
+
+	offset = offsetof( struct lance_memory, packet_area );
+
+/* If the packet buffer at offset 'o' would conflict with the reserved area
+ * of RieblCards, advance it */
+#define	CHECK_OFFSET(o)														 \
+	do {																	 \
+		if (lp->cardtype == OLD_RIEBL || lp->cardtype == NEW_RIEBL) {		 \
+			if (((o) < RIEBL_RSVD_START) ? (o)+PKT_BUF_SZ > RIEBL_RSVD_START \
+										 : (o) < RIEBL_RSVD_END)			 \
+				(o) = RIEBL_RSVD_END;										 \
+		}																	 \
+	} while(0)
+
+	for( i = 0; i < TX_RING_SIZE; i++ ) {
+		CHECK_OFFSET(offset);
+		MEM->tx_head[i].base = offset;
+#ifdef NORMAL_MEM_ACCESS
+		MEM->tx_head[i].flag = TMD1_OWN_HOST;
+ 		MEM->tx_head[i].base_hi = LANCE_HI_BASE;
+#else
+		MEM->tx_head[i].flag_base_hi = 
+				(TMD1_OWN_HOST<<8) | LANCE_HI_BASE;
+#endif
+		MEM->tx_head[i].length = 0;
+		MEM->tx_head[i].misc = 0;
+		offset += PKT_BUF_SZ;
+	}
+
+	for( i = 0; i < RX_RING_SIZE; i++ ) {
+		CHECK_OFFSET(offset);
+		MEM->rx_head[i].base = offset;
+#ifdef NORMAL_MEM_ACCESS
+		MEM->rx_head[i].flag = TMD1_OWN_CHIP;
+		MEM->rx_head[i].base_hi = LANCE_HI_BASE; 
+#else
+		MEM->rx_head[i].flag_base_hi = 
+				(TMD1_OWN_CHIP<<8) | LANCE_HI_BASE;
+#endif
+		MEM->rx_head[i].buf_length = -PKT_BUF_SZ;
+		MEM->rx_head[i].msg_length = 0;
+		offset += PKT_BUF_SZ;
+	}
+}
+
+
+static int lance_start_xmit( struct sk_buff *skb, struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_ioreg	 *IO = lp->iobase;
+	int entry, len;
+	struct lance_tx_head *head;
+	unsigned long flags;
+
+	/* Transmitter timeout, serious problems. */
+	if (dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 20)
+			return( 1 );
+		AREG = CSR0;
+		DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
+					  dev->name, DREG ));
+		DREG = CSR0_STOP;
+		/*
+		 * Always set BSWP after a STOP as STOP puts it back into
+		 * little endian mode.
+		 */
+		REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
+		lp->stats.tx_errors++;
+#ifndef final_version
+		{	int i;
+			DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n",
+						  lp->dirty_tx, lp->cur_tx,
+						  lp->tx_full ? " (full)" : "",
+						  lp->cur_rx ));
+			for( i = 0 ; i < RX_RING_SIZE; i++ )
+				DPRINTK( 2, ( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
+							  i, MEM->rx_head[i].base,
+							  -MEM->rx_head[i].buf_length,
+							  MEM->rx_head[i].msg_length ));
+			for( i = 0 ; i < TX_RING_SIZE; i++ )
+				DPRINTK( 2, ( "tx #%d: base=%04x len=%04x misc=%04x\n",
+							  i, MEM->tx_head[i].base,
+							  -MEM->tx_head[i].length,
+							  MEM->tx_head[i].misc ));
+		}
+#endif
+		lance_init_ring(dev);
+		REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
+
+		dev->tbusy = 0;
+		dev->trans_start = jiffies;
+
+		return( 0 );
+	}
+
+	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
+				  dev->name, DREG ));
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) {
+		DPRINTK( 0, ( "%s: Transmitter access conflict.\n", dev->name ));
+		return 1;
+	}
+
+	if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
+		DPRINTK( 0, ( "%s: tx queue lock!.\n", dev->name ));
+		/* don't clear dev->tbusy flag. */
+		return 1;
+	}
+
+	/* Fill in a Tx ring entry */
+	if (lance_debug >= 3) {
+		u_char *p;
+		int i;
+		printk( "%s: TX pkt type 0x%04x from ", dev->name,
+				((u_short *)skb->data)[6]);
+		for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
+			printk("%02x%s", *p++, i != 5 ? ":" : "" );
+		printk(" to ");
+		for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
+			printk("%02x%s", *p++, i != 5 ? ":" : "" );
+		printk(" data at 0x%08x len %d\n", (int)skb->data,
+			   (int)skb->len );
+	}
+
+	/* We're not prepared for the int until the last flags are set/reset. And
+	 * the int may happen already after setting the OWN_CHIP... */
+	save_flags(flags);
+	cli();
+
+	/* Mask to ring buffer boundary. */
+	entry = lp->cur_tx & TX_RING_MOD_MASK;
+	head  = &(MEM->tx_head[entry]);
+
+	/* Caution: the write order is important here, set the "ownership" bits
+	 * last.
+	 */
+
+	/* The old LANCE chips doesn't automatically pad buffers to min. size. */
+	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	/* PAM-Card has a bug: Can only send packets with even number of bytes! */
+	if (lp->cardtype == PAM_CARD && (len & 1))
+		++len;
+
+	head->length = -len;
+	head->misc = 0;
+	lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
+#ifdef NORMAL_MEM_ACCESS
+	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
+#else
+    SET_FLAG(head,(TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP));
+#endif
+	dev_kfree_skb( skb );
+	lp->cur_tx++;
+	lp->stats.tx_bytes += skb->len;
+	while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
+		lp->cur_tx -= TX_RING_SIZE;
+		lp->dirty_tx -= TX_RING_SIZE;
+	}
+
+	/* Trigger an immediate send poll. */
+	DREG = CSR0_INEA | CSR0_TDMD;
+	dev->trans_start = jiffies;
+
+	lp->lock = 0;
+#ifdef NORMAL_MEM_ACCESS
+	if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
+#else
+	if ((GET_FLAG(&MEM->tx_head[(entry+1) & TX_RING_MOD_MASK]) & TMD1_OWN) ==
+#endif
+		TMD1_OWN_HOST)
+		dev->tbusy = 0;
+	else
+		lp->tx_full = 1;
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* The LANCE interrupt handler. */
+
+static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
+{
+	struct device *dev = dev_id;
+	struct lance_private *lp;
+	struct lance_ioreg	 *IO;
+	int csr0, boguscnt = 10;
+
+	if (dev == NULL) {
+		DPRINTK( 1, ( "lance_interrupt(): interrupt for unknown device.\n" ));
+		return;
+	}
+
+	lp = (struct lance_private *)dev->priv;
+	IO = lp->iobase;
+	AREG = CSR0;
+
+	if (dev->interrupt) {
+			DPRINTK( 1, ( "Re-entering CAUSE=%08x STATUS=%08x\n",  
+						  read_32bit_cp0_register(CP0_CAUSE),  
+						  read_32bit_cp0_register(CP0_STATUS) ));
+			panic("lance: interrupt handler reentered !");
+	}
+
+	dev->interrupt = 1;
+
+	while( ((csr0 = DREG) & (CSR0_ERR | CSR0_TINT | CSR0_RINT)) &&
+		   --boguscnt >= 0) {
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		DREG = csr0 & ~(CSR0_INIT | CSR0_STRT | CSR0_STOP |
+									CSR0_TDMD | CSR0_INEA);
+
+		DPRINTK( 2, ( "%s: interrupt  csr0=%04x new csr=%04x.\n",
+					  dev->name, csr0, DREG ));
+
+		if (csr0 & CSR0_RINT)			/* Rx interrupt */
+			lance_rx( dev );
+
+		if (csr0 & CSR0_TINT) {			/* Tx-done interrupt */
+			int dirty_tx = lp->dirty_tx;
+
+			while( dirty_tx < lp->cur_tx) {
+				int entry = dirty_tx & TX_RING_MOD_MASK;
+#ifdef NORMAL_MEM_ACCESS
+				int status = MEM->tx_head[entry].flag;
+#else
+				int status = GET_FLAG(&MEM->tx_head[entry]);
+#endif
+				if (status & TMD1_OWN_CHIP)
+					break;			/* It still hasn't been Txed */
+
+#ifdef NORMAL_MEM_ACCESS
+				MEM->tx_head[entry].flag = 0;
+#else
+				SET_FLAG(&MEM->tx_head[entry],0);
+#endif
+
+				if (status & TMD1_ERR) {
+					/* There was an major error, log it. */
+					int err_status = MEM->tx_head[entry].misc;
+					lp->stats.tx_errors++;
+					if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+					if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+					if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
+					if (err_status & TMD3_UFLO) {
+						/* Ackk!  On FIFO errors the Tx unit is turned off! */
+						lp->stats.tx_fifo_errors++;
+						/* Remove this verbosity later! */
+						DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
+									  dev->name, csr0 ));
+						/* Restart the chip. */
+						DREG = CSR0_STRT;
+					}
+				} else {
+					if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
+						lp->stats.collisions++;
+					lp->stats.tx_packets++;
+				}
+				dirty_tx++;
+			}
+
+#ifndef final_version
+			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+				DPRINTK( 0, ( "out-of-sync dirty pointer,"
+							  " %d vs. %d, full=%d.\n",
+							  dirty_tx, lp->cur_tx, lp->tx_full ));
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (lp->tx_full && dev->tbusy
+				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+				/* The ring is no longer full, clear tbusy. */
+				lp->tx_full = 0;
+				dev->tbusy = 0;
+				mark_bh( NET_BH );
+			}
+
+			lp->dirty_tx = dirty_tx;
+		}
+
+		/* Log misc errors. */
+		if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
+		if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+		if (csr0 & CSR0_MERR) {
+			DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
+						  "status %04x.\n", dev->name, csr0 ));
+			/* Restart the chip. */
+			DREG = CSR0_STRT;
+		}
+	}
+
+    /* Clear any other interrupt, and set interrupt enable. */
+	DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
+		   CSR0_IDON | CSR0_INEA;
+
+	DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
+				  dev->name, DREG ));
+	dev->interrupt = 0;
+	return;
+}
+
+
+static int lance_rx( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int entry = lp->cur_rx & RX_RING_MOD_MASK;
+	int i;
+
+#ifdef NORMAL_MEM_ACCESS
+	DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name,
+				  MEM->rx_head[entry].flag ));
+#else
+	DPRINTK( 2, ( "%s: rx int, flag=%04x\n", dev->name,
+				  GET_FLAG(&MEM->rx_head[entry]) ));
+#endif
+
+	/* If we own the next entry, it's a new packet. Send it up. */
+#ifdef NORMAL_MEM_ACCESS
+	while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
+#else
+	while( (GET_FLAG(&MEM->rx_head[entry]) & RMD1_OWN) == RMD1_OWN_HOST ) {
+#endif
+		struct lance_rx_head *head = &(MEM->rx_head[entry]);
+#ifdef NORMAL_MEM_ACCESS
+		int status = head->flag;
+#else
+		int status = GET_FLAG(head);
+#endif
+
+		if (status != (RMD1_ENP|RMD1_STP)) {		/* There was an error. */
+			/* There is a tricky error noted by John Murphy,
+			   <murf@perftech.com> to Russ Nelson: Even with full-sized
+			   buffers it's possible for a jabber packet to use two
+			   buffers, with only the last correctly noting the error. */
+			if (status & RMD1_ENP)	/* Only count a general error at the */
+				lp->stats.rx_errors++; /* end of a packet.*/
+			if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
+			if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
+			if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
+			if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+#ifdef NORMAL_MEM_ACCESS
+			head->flag &= (RMD1_ENP|RMD1_STP);
+#else
+			SET_FLAG(head,GET_FLAG(head) & (RMD1_ENP|RMD1_STP));
+#endif
+		} else {
+			/* Malloc up new buffer, compatible with net-3. */
+			short pkt_len = head->msg_length & 0xfff;
+			struct sk_buff *skb;
+
+			if (pkt_len < 60) {
+				printk( "%s: Runt packet!\n", dev->name );
+				lp->stats.rx_errors++;
+			}
+			else {
+				skb = dev_alloc_skb( pkt_len+2 );
+				if (skb == NULL) {
+					DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
+								  dev->name ));
+                          for( i = 0; i < RX_RING_SIZE; i++ )
+#ifdef NORMAL_MEM_ACCESS
+                        if (MEM->rx_head[(entry+i) & RX_RING_MOD_MASK].flag &
+#else
+						if (GET_FLAG(&MEM->rx_head[(entry+i) & \
+												  RX_RING_MOD_MASK]) &
+#endif
+							RMD1_OWN_CHIP)
+							break;
+
+					if (i > RX_RING_SIZE - 2) {
+						lp->stats.rx_dropped++;
+#ifdef NORMAL_MEM_ACCESS
+                        head->flag |= RMD1_OWN_CHIP;
+#else
+                        SET_FLAG(head,GET_FLAG(head) | RMD1_OWN_CHIP);
+#endif
+						lp->cur_rx++;
+					}
+					break;
+				}
+
+				if (lance_debug >= 3) {
+					u_char *data = PKTBUF_ADDR(head), *p;
+					printk( "%s: RX pkt type 0x%04x from ", dev->name,
+							((u_short *)data)[6]);
+					for( p = &data[6], i = 0; i < 6; i++ )
+						printk("%02x%s", *p++, i != 5 ? ":" : "" );
+					printk(" to ");
+					for( p = data, i = 0; i < 6; i++ )
+						printk("%02x%s", *p++, i != 5 ? ":" : "" );
+					printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
+						   "len %d\n",
+						   data[15], data[16], data[17], data[18],
+						   data[19], data[20], data[21], data[22],
+						   pkt_len );
+				}
+
+				skb->dev = dev;
+				skb_reserve( skb, 2 );	/* 16 byte align */
+				skb_put( skb, pkt_len );	/* Make room */
+				lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len );
+				skb->protocol = eth_type_trans( skb, dev );
+				netif_rx( skb );
+				lp->stats.rx_packets++;
+				lp->stats.rx_bytes += skb->len;
+			}
+		}
+
+#ifdef NORMAL_MEM_ACCESS
+		head->flag |= RMD1_OWN_CHIP;
+#else
+		SET_FLAG(head,GET_FLAG(head) | RMD1_OWN_CHIP);
+#endif
+		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+	}
+	lp->cur_rx &= RX_RING_MOD_MASK;
+
+	/* From lance.c (Donald Becker): */
+	/* We should check that at least two ring entries are free.	 If not,
+	   we should free one and mark stats->rx_dropped++. */
+
+	return 0;
+}
+
+
+static int lance_close( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_ioreg	 *IO = lp->iobase;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	AREG = CSR0;
+
+	DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
+				  dev->name, DREG ));
+
+	/* We stop the LANCE here -- it occasionally polls
+	   memory if we don't. */
+	DREG = CSR0_STOP;
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+static struct net_device_stats *lance_get_stats( struct device *dev )
+
+{	
+	struct lance_private *lp = (struct lance_private *)dev->priv;
+	return &lp->stats;
+}
+
+
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1		Promiscuous mode, receive all packets
+   num_addrs == 0		Normal mode, clear multicast list
+   num_addrs > 0		Multicast mode, receive normal and MC packets, and do
+						best-effort filtering.
+ */
+
+static void set_multicast_list( struct device *dev )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct lance_ioreg	 *IO = lp->iobase;
+
+	if (!dev->start)
+		/* Only possible if board is already started */
+		return;
+
+	/* We take the simple way out and always enable promiscuous mode. */
+	DREG = CSR0_STOP; /* Temporarily stop the lance. */
+
+	if (dev->flags & IFF_PROMISC) {
+		/* Log any net taps. */
+		DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name ));
+		REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
+	} else {
+		short multicast_table[4];
+		int num_addrs = dev->mc_count;
+		int i;
+		/* We don't use the multicast table, but rely on upper-layer
+		 * filtering. */
+		memset( multicast_table, (num_addrs == 0) ? 0 : -1,
+				sizeof(multicast_table) );
+		for( i = 0; i < 4; i++ )
+			REGA( CSR8+i ) = multicast_table[i];
+		REGA( CSR15 ) = 0; /* Unset promiscuous mode */
+	}
+
+	/*
+	 * Always set BSWP after a STOP as STOP puts it back into
+	 * little endian mode.
+	 */
+	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
+
+	/* Resume normal operation and reset AREG to CSR0 */
+	REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
+}
+
+
+/* This is needed for old RieblCards and possible for new RieblCards */
+
+static int lance_set_mac_address( struct device *dev, void *addr )
+
+{	struct lance_private *lp = (struct lance_private *)dev->priv;
+	struct sockaddr *saddr = addr;
+	int i;
+
+	if (lp->cardtype != OLD_RIEBL && lp->cardtype != NEW_RIEBL)
+		return( -EOPNOTSUPP );
+
+	if (dev->start) {
+		/* Only possible while card isn't started */
+		DPRINTK( 1, ( "%s: hwaddr can be set only while card isn't open.\n",
+					  dev->name ));
+		return( -EIO );
+	}
+
+	slow_memcpy( dev->dev_addr, saddr->sa_data, dev->addr_len );
+
+	{
+			unsigned char hwaddr[6];
+			for( i = 0; i < 6; i++ ) 
+					hwaddr[i] = dev->dev_addr[i^1]; /* <- 16 bit swap! */
+			slow_memcpy(MEM->init.hwaddr, hwaddr, sizeof(hwaddr));
+	}
+
+	lp->memcpy_f( RIEBL_HWADDR_ADDR, dev->dev_addr, 6 );
+	/* set also the magic for future sessions */
+#ifdef NORMAL_MEM_ACCESS
+	*RIEBL_MAGIC_ADDR = RIEBL_MAGIC;
+#else
+	{
+			unsigned long magic = RIEBL_MAGIC;
+			slow_memcpy(RIEBL_MAGIC_ADDR, &magic, sizeof(*RIEBL_MAGIC_ADDR));
+	}
+#endif
+	return( 0 );
+}
+
+
+#ifdef MODULE
+static char devicename[9] = { 0, };
+
+static struct device bagetlance_dev =
+{
+	devicename,	/* filled in by register_netdev() */
+	0, 0, 0, 0,	/* memory */
+	0, 0,		/* base, irq */
+	0, 0, 0, NULL, bagetlance_probe,
+};
+
+int init_module(void)
+
+{	int err;
+
+	if ((err = register_netdev( &bagetlance_dev ))) {
+		if (err == -EIO)  {
+			printk( "No Vme Lance board found. Module not loaded.\n");
+		}
+		return( err );
+	}
+	return( 0 );
+}
+
+void cleanup_module(void)
+
+{
+	unregister_netdev( &bagetlance_dev );
+}
+
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v2.3.8/linux/drivers/net/cycx_drv.c linux/drivers/net/cycx_drv.c
--- v2.3.8/linux/drivers/net/cycx_drv.c	Wed Jun  2 14:40:22 1999
+++ linux/drivers/net/cycx_drv.c	Wed Jun 30 11:24:54 1999
@@ -39,7 +39,6 @@
 * Aug  8, 1998	Arnaldo		Initial version.
 */
 
-#include <linux/config.h>
 #ifdef MODULE
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/net/declance.c linux/drivers/net/declance.c
--- v2.3.8/linux/drivers/net/declance.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/declance.c	Fri Jun 25 17:39:52 1999
@@ -0,0 +1,1259 @@
+/*     
+ *    Lance ethernet driver for the MIPS processor based
+ *      DECstation family
+ *
+ *
+ *      adopted from sunlance.c by Richard van den Berg
+ *
+ *      additional sources:
+ *      - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
+ *        Revision 1.2
+ *
+ *      History:
+ *
+ *      v0.001: The kernel accepts the code and it shows the hardware address.
+ *
+ *      v0.002: Removed most sparc stuff, left only some module and dma stuff.
+ *
+ *      v0.003: Enhanced base address calculation from proposals by
+ *      Harald Koerfgen and Thomas Riemer.
+ *
+ *      v0.004: lance-regs is pointing at the right addresses, added prom
+ *      check. First start of address mapping and DMA.
+ *
+ *      v0.005: started to play around with LANCE-DMA. This driver will not work
+ *      for non IOASIC lances. HK
+ *
+ *      v0.006: added pointer arrays to lance_private and setup routine for them
+ *      in dec_lance_init. HK
+ *
+ *      v0.007: Big shit. The LANCE seems to use a different DMA mechanism to access
+ *      the init block. This looks like one (short) word at a time, but the smallest
+ *      amount the IOASIC can transfer is a (long) word. So we have a 2-2 padding here.
+ *      Changed lance_init_block accordingly. The 16-16 padding for the buffers
+ *      seems to be correct. HK
+ *
+ *     v0.008 - mods to make PMAX_LANCE work. 01/09/1999 triemer
+ */
+
+#undef DEBUG_DRIVER
+
+static char *version =
+"declance.c: v0.008 by Linux Mips DECstation task force\n";
+
+static char *lancestr = "LANCE";
+
+/*
+ * card types
+ */
+#define ASIC_LANCE 1
+#define PMAD_LANCE 2
+#define PMAX_LANCE 3
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_ints.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+#include <asm/dec/kn01.h>
+#include <asm/addrspace.h>
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/utsname.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/etherdevice.h>
+
+#ifndef CONFIG_TC
+unsigned long system_base = 0;
+unsigned long dmaptr;
+#endif
+static int type;
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL	/* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL	/* Ethernet CRC, little endian */
+
+#define LE_CSR0 0
+#define LE_CSR1 1
+#define LE_CSR2 2
+#define LE_CSR3 3
+
+#define LE_MO_PROM      0x8000	/* Enable promiscuous mode */
+
+#define	LE_C0_ERR	0x8000	/* Error: set if BAB, SQE, MISS or ME is set */
+#define	LE_C0_BABL	0x4000	/* BAB:  Babble: tx timeout. */
+#define	LE_C0_CERR	0x2000	/* SQE:  Signal quality error */
+#define	LE_C0_MISS	0x1000	/* MISS: Missed a packet */
+#define	LE_C0_MERR	0x0800	/* ME:   Memory error */
+#define	LE_C0_RINT	0x0400	/* Received interrupt */
+#define	LE_C0_TINT	0x0200	/* Transmitter Interrupt */
+#define	LE_C0_IDON	0x0100	/* IFIN: Init finished. */
+#define	LE_C0_INTR	0x0080	/* Interrupt or error */
+#define	LE_C0_INEA	0x0040	/* Interrupt enable */
+#define	LE_C0_RXON	0x0020	/* Receiver on */
+#define	LE_C0_TXON	0x0010	/* Transmitter on */
+#define	LE_C0_TDMD	0x0008	/* Transmitter demand */
+#define	LE_C0_STOP	0x0004	/* Stop the card */
+#define	LE_C0_STRT	0x0002	/* Start the card */
+#define	LE_C0_INIT	0x0001	/* Init the card */
+
+#define	LE_C3_BSWP	0x4	/* SWAP */
+#define	LE_C3_ACON	0x2	/* ALE Control */
+#define	LE_C3_BCON	0x1	/* Byte control */
+
+/* Receive message descriptor 1 */
+#define LE_R1_OWN       0x80	/* Who owns the entry */
+#define LE_R1_ERR       0x40	/* Error: if FRA, OFL, CRC or BUF is set */
+#define LE_R1_FRA       0x20	/* FRA: Frame error */
+#define LE_R1_OFL       0x10	/* OFL: Frame overflow */
+#define LE_R1_CRC       0x08	/* CRC error */
+#define LE_R1_BUF       0x04	/* BUF: Buffer error */
+#define LE_R1_SOP       0x02	/* Start of packet */
+#define LE_R1_EOP       0x01	/* End of packet */
+#define LE_R1_POK       0x03	/* Packet is complete: SOP + EOP */
+
+#define LE_T1_OWN       0x80	/* Lance owns the packet */
+#define LE_T1_ERR       0x40	/* Error summary */
+#define LE_T1_EMORE     0x10	/* Error: more than one retry needed */
+#define LE_T1_EONE      0x08	/* Error: one retry needed */
+#define LE_T1_EDEF      0x04	/* Error: deferred */
+#define LE_T1_SOP       0x02	/* Start of packet */
+#define LE_T1_EOP       0x01	/* End of packet */
+#define LE_T1_POK	0x03	/* Packet is complete: SOP + EOP */
+
+#define LE_T3_BUF       0x8000	/* Buffer error */
+#define LE_T3_UFL       0x4000	/* Error underflow */
+#define LE_T3_LCOL      0x1000	/* Error late collision */
+#define LE_T3_CLOS      0x0800	/* Error carrier loss */
+#define LE_T3_RTY       0x0400	/* Error retry */
+#define LE_T3_TDR       0x03ff	/* Time Domain Reflectometry counter */
+
+/* Define: 2^4 Tx buffers and 2^4 Rx buffers */
+
+#ifndef LANCE_LOG_TX_BUFFERS
+#define LANCE_LOG_TX_BUFFERS 4
+#define LANCE_LOG_RX_BUFFERS 4
+#endif
+
+#define TX_RING_SIZE			(1 << (LANCE_LOG_TX_BUFFERS))
+#define TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
+
+#define RX_RING_SIZE			(1 << (LANCE_LOG_RX_BUFFERS))
+#define RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
+
+#define PKT_BUF_SZ		1536
+#define RX_BUFF_SIZE            PKT_BUF_SZ
+#define TX_BUFF_SIZE            PKT_BUF_SZ
+
+#undef TEST_HITS
+#define DEBUG_DRIVER 1
+
+#define ZERO 0
+
+/* The DS2000/3000 have a linear 64 KB buffer.
+
+ * The PMAD-AA has 128 kb buffer on-board. 
+ *
+ * The IOASIC LANCE devices use a shared memory region. This region as seen 
+ * from the CPU is (max) 128 KB long and has to be on an 128 KB boundary.
+ * The LANCE sees this as a 64 KB long continuous memory region.
+ *
+ * The LANCE's DMA address is used as an index in this buffer and DMA takes
+ * place in bursts of eight 16-Bit words which are packed into four 32-Bit words
+ * by the IOASIC. This leads to a strange padding: 16 bytes of valid data followed
+ * by a 16 byte gap :-(.
+ */
+
+struct lance_rx_desc {
+	unsigned short rmd0;	/* low address of packet */
+	short gap0;
+	unsigned char rmd1_hadr;	/* high address of packet */
+	unsigned char rmd1_bits;	/* descriptor bits */
+	short gap1;
+	short length;		/* This length is 2s complement (negative)!
+				   * Buffer length
+				 */
+	short gap2;
+	unsigned short mblength;	/* This is the actual number of bytes received */
+	short gap3;
+};
+
+struct lance_tx_desc {
+	unsigned short tmd0;	/* low address of packet */
+	short gap0;
+	unsigned char tmd1_hadr;	/* high address of packet */
+	unsigned char tmd1_bits;	/* descriptor bits */
+	short gap1;
+	short length;		/* Length is 2s complement (negative)! */
+	short gap2;
+	unsigned short misc;
+	short gap3;
+};
+
+
+/* First part of the LANCE initialization block, described in databook. */
+struct lance_init_block {
+	unsigned short mode;	/* Pre-set mode (reg. 15) */
+	short gap0;
+
+	unsigned char phys_addr[12];	/* Physical ethernet address
+					   * only 0, 1, 4, 5, 8, 9 are valid
+					   * 2, 3, 6, 7, 10, 11 are gaps
+					 */
+	unsigned short filter[8];	/* Multicast filter.
+					   * only 0, 2, 4, 6 are valid
+					   * 1, 3, 5, 7 are gaps
+					 */
+
+	/* Receive and transmit ring base, along with extra bits. */
+	unsigned short rx_ptr;	/* receive descriptor addr */
+	short gap1;
+	unsigned short rx_len;	/* receive len and high addr */
+	short gap2;
+	unsigned short tx_ptr;	/* transmit descriptor addr */
+	short gap3;
+	unsigned short tx_len;	/* transmit len and high addr */
+	short gap4;
+	char gap5[16];
+
+	/* The buffer descriptors */
+	struct lance_rx_desc brx_ring[RX_RING_SIZE];
+	struct lance_tx_desc btx_ring[TX_RING_SIZE];
+};
+
+#define BUF_OFFSET_CPU sizeof(struct lance_init_block)
+#define BUF_OFFSET_LNC (sizeof(struct lance_init_block)>>1)
+
+#define libdesc_offset(rt, elem) \
+((__u32)(((unsigned long)(&(((struct lance_init_block *)0)->rt[elem])))))
+
+/*
+ * This works *only* for the ring descriptors
+ */
+#define LANCE_ADDR(x) (PHYSADDR(x) >> 1)
+
+struct lance_private {
+	char *name;
+	volatile struct lance_regs *ll;
+	volatile struct lance_init_block *init_block;
+	volatile unsigned long *dma_ptr_reg;
+
+	int rx_new, tx_new;
+	int rx_old, tx_old;
+
+	struct net_device_stats stats;
+
+	unsigned short busmaster_regval;
+
+	struct device *dev;	/* Backpointer        */
+	struct lance_private *next_module;
+
+	/* Pointers to the ring buffers as seen from the CPU */
+	char *rx_buf_ptr_cpu[RX_RING_SIZE];
+	char *tx_buf_ptr_cpu[TX_RING_SIZE];
+
+	/* Pointers to the ring buffers as seen from the LANCE */
+	char *rx_buf_ptr_lnc[RX_RING_SIZE];
+	char *tx_buf_ptr_lnc[TX_RING_SIZE];
+};
+
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+			lp->tx_old+TX_RING_MOD_MASK-lp->tx_new:\
+			lp->tx_old - lp->tx_new-1)
+
+/* The lance control ports are at an absolute address, machine and tc-slot
+ * dependant.
+ * DECstations do only 32-bit access and the LANCE uses 16 bit addresses,
+ * so we have to give the structure an extra member making rap pointing
+ * at the right address
+ */
+struct lance_regs {
+	volatile unsigned short rdp;	/* register data port */
+	unsigned short pad;
+	volatile unsigned short rap;	/* register address port */
+};
+
+int dec_lance_debug = 2;
+
+/*
+   #ifdef MODULE
+   static struct lance_private *root_lance_dev = NULL;
+   #endif
+ */
+
+static inline void writereg(volatile unsigned short *regptr, short value)
+{
+	*regptr = value;
+}
+
+/* Load the CSR registers */
+static void load_csrs(struct lance_private *lp)
+{
+	volatile struct lance_regs *ll = lp->ll;
+	int leptr;
+
+	/* The address space as seen from the LANCE
+	 * begins at address 0. HK
+	 */
+	leptr = 0;
+
+	writereg(&ll->rap, LE_CSR1);
+	writereg(&ll->rdp, (leptr & 0xFFFF));
+	writereg(&ll->rap, LE_CSR2);
+	writereg(&ll->rdp, leptr >> 16);
+	writereg(&ll->rap, LE_CSR3);
+	writereg(&ll->rdp, lp->busmaster_regval);
+
+	/* Point back to csr0 */
+	writereg(&ll->rap, LE_CSR0);
+}
+
+/*
+ * Our specialized copy routines
+ *
+ */
+void cp_to_buf(void *to, const void *from, __kernel_size_t len)
+{
+	unsigned short *tp, *fp, clen;
+	unsigned char *rtp, *rfp;
+
+	if (type == PMAX_LANCE) {
+		clen = len >> 1;
+		tp = (unsigned short *) to;
+		fp = (unsigned short *) from;
+
+		while (clen--) {
+			*tp++ = *fp++;
+			tp++;
+		}
+
+		clen = len & 1;
+		rtp = (unsigned char *) tp;
+		rfp = (unsigned char *) fp;
+		while (clen--) {
+			*rtp++ = *rfp++;
+		}
+	} else {
+		/*
+		 * copy 16 Byte chunks
+		 */
+		clen = len >> 4;
+		tp = (unsigned short *) to;
+		fp = (unsigned short *) from;
+		while (clen--) {
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			tp += 8;
+		}
+
+		/*
+		 * do the rest, if any.
+		 */
+		clen = len & 15;
+		rtp = (unsigned char *) tp;
+		rfp = (unsigned char *) fp;
+		while (clen--) {
+			*rtp++ = *rfp++;
+		}
+	}
+
+}
+
+void cp_from_buf(void *to, unsigned char *from, int len)
+{
+	unsigned short *tp, *fp, clen;
+	unsigned char *rtp, *rfp;
+
+	if (type == PMAX_LANCE) {
+		clen = len >> 1;
+		tp = (unsigned short *) to;
+		fp = (unsigned short *) from;
+		while (clen--) {
+			*tp++ = *fp++;
+			fp++;
+		}
+
+		clen = len & 1;
+
+		rtp = (unsigned char *) tp;
+		rfp = (unsigned char *) fp;
+
+		while (clen--) {
+			*rtp++ = *rfp++;
+		}
+	} else {
+
+		/*
+		 * copy 16 Byte chunks
+		 */
+		clen = len >> 4;
+		tp = (unsigned short *) to;
+		fp = (unsigned short *) from;
+		while (clen--) {
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			*tp++ = *fp++;
+			fp += 8;
+		}
+
+		/*
+		 * do the rest, if any.
+		 */
+		clen = len & 15;
+		rtp = (unsigned char *) tp;
+		rfp = (unsigned char *) fp;
+		while (clen--) {
+			*rtp++ = *rfp++;
+		}
+
+
+	}
+
+}
+
+/* Setup the Lance Rx and Tx rings */
+/* Sets dev->tbusy */
+static void lance_init_ring(struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_init_block *ib;
+	int leptr;
+	int i;
+
+	ib = (struct lance_init_block *) (dev->mem_start);
+
+	/* Lock out other processes while setting up hardware */
+	dev->tbusy = 1;
+	lp->rx_new = lp->tx_new = 0;
+	lp->rx_old = lp->tx_old = 0;
+
+	ib->mode = 0;
+
+	/* Copy the ethernet address to the lance init block.
+	 * XXX bit 0 of the physical address registers has to be zero
+	 */
+	ib->phys_addr[0] = dev->dev_addr[0];
+	ib->phys_addr[1] = dev->dev_addr[1];
+	ib->phys_addr[4] = dev->dev_addr[2];
+	ib->phys_addr[5] = dev->dev_addr[3];
+	ib->phys_addr[8] = dev->dev_addr[4];
+	ib->phys_addr[9] = dev->dev_addr[5];
+	/* Setup the initialization block */
+
+	/* Setup rx descriptor pointer */
+	leptr = LANCE_ADDR(libdesc_offset(brx_ring, 0));
+	ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16);
+	ib->rx_ptr = leptr;
+	if (ZERO)
+		printk("RX ptr: %8.8x(%8.8x)\n", leptr, libdesc_offset(brx_ring, 0));
+
+	/* Setup tx descriptor pointer */
+	leptr = LANCE_ADDR(libdesc_offset(btx_ring, 0));
+	ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16);
+	ib->tx_ptr = leptr;
+	if (ZERO)
+		printk("TX ptr: %8.8x(%8.8x)\n", leptr, libdesc_offset(btx_ring, 0));
+
+	/* Clear the multicast filter */
+	ib->filter[0] = 0;
+	ib->filter[2] = 0;
+	ib->filter[4] = 0;
+	ib->filter[6] = 0;
+	if (ZERO)
+		printk("TX rings:\n");
+
+	/* Setup the Tx ring entries */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		leptr = (int) lp->tx_buf_ptr_lnc[i];
+		ib->btx_ring[i].tmd0 = leptr;
+		ib->btx_ring[i].tmd1_hadr = leptr >> 16;
+		ib->btx_ring[i].tmd1_bits = 0;
+		ib->btx_ring[i].length = 0xf000;	/* The ones required by tmd2 */
+		ib->btx_ring[i].misc = 0;
+		if (i < 3 && ZERO)
+			printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->tx_buf_ptr_cpu[i]);
+	}
+
+	/* Setup the Rx ring entries */
+	if (ZERO)
+		printk("RX rings:\n");
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		leptr = (int) lp->rx_buf_ptr_lnc[i];
+		ib->brx_ring[i].rmd0 = leptr;
+		ib->brx_ring[i].rmd1_hadr = leptr >> 16;
+		ib->brx_ring[i].rmd1_bits = LE_R1_OWN;
+		ib->brx_ring[i].length = -RX_BUFF_SIZE | 0xf000;
+		ib->brx_ring[i].mblength = 0;
+		if (i < 3 && ZERO)
+			printk("%d: 0x%8.8x(0x%8.8x)\n", i, leptr, (int) lp->rx_buf_ptr_cpu[i]);
+	}
+}
+
+static int init_restart_lance(struct lance_private *lp)
+{
+	volatile struct lance_regs *ll = lp->ll;
+	int i;
+
+	writereg(&ll->rap, LE_CSR0);
+	writereg(&ll->rdp, LE_C0_INIT);
+
+	/* Wait for the lance to complete initialization */
+	for (i = 0; (i < 100) && !(ll->rdp & LE_C0_IDON); i++) {
+		udelay(10);
+	}
+	if ((i == 100) || (ll->rdp & LE_C0_ERR)) {
+		printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
+		return -1;
+	}
+	if ((ll->rdp & LE_C0_ERR)) {
+		printk("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp);
+		return -1;
+	}
+	writereg(&ll->rdp, LE_C0_IDON);
+	writereg(&ll->rdp, LE_C0_STRT);
+	writereg(&ll->rdp, LE_C0_INEA);
+
+	return 0;
+}
+
+static int lance_rx(struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_init_block *ib;
+	volatile struct lance_rx_desc *rd = 0;
+	unsigned char bits;
+	int len = 0;
+	struct sk_buff *skb = 0;
+	ib = (struct lance_init_block *) (dev->mem_start);
+
+#ifdef TEST_HITS
+	int i;
+
+	printk("[");
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		if (i == lp->rx_new)
+			printk("%s",
+			       ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "_" : "X");
+		else
+			printk("%s",
+			       ib->brx_ring[i].rmd1_bits & LE_R1_OWN ? "." : "1");
+	}
+	printk("]");
+#endif
+
+	for (rd = &ib->brx_ring[lp->rx_new];
+	     !((bits = rd->rmd1_bits) & LE_R1_OWN);
+	     rd = &ib->brx_ring[lp->rx_new]) {
+
+		/* We got an incomplete frame? */
+		if ((bits & LE_R1_POK) != LE_R1_POK) {
+			lp->stats.rx_over_errors++;
+			lp->stats.rx_errors++;
+		} else if (bits & LE_R1_ERR) {
+			/* Count only the end frame as a rx error,
+			 * not the beginning
+			 */
+			if (bits & LE_R1_BUF)
+				lp->stats.rx_fifo_errors++;
+			if (bits & LE_R1_CRC)
+				lp->stats.rx_crc_errors++;
+			if (bits & LE_R1_OFL)
+				lp->stats.rx_over_errors++;
+			if (bits & LE_R1_FRA)
+				lp->stats.rx_frame_errors++;
+			if (bits & LE_R1_EOP)
+				lp->stats.rx_errors++;
+		} else {
+			len = (rd->mblength & 0xfff) - 4;
+			skb = dev_alloc_skb(len + 2);
+
+			if (skb == 0) {
+				printk("%s: Memory squeeze, deferring packet.\n",
+				       dev->name);
+				lp->stats.rx_dropped++;
+				rd->mblength = 0;
+				rd->rmd1_bits = LE_R1_OWN;
+				lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK;
+				return 0;
+			}
+			lp->stats.rx_bytes += len;
+
+			skb->dev = dev;
+			skb_reserve(skb, 2);	/* 16 byte align */
+			skb_put(skb, len);	/* make room */
+			cp_from_buf(skb->data,
+				 (char *) lp->rx_buf_ptr_cpu[lp->rx_new],
+				    len);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			lp->stats.rx_packets++;
+		}
+
+		/* Return the packet to the pool */
+		rd->mblength = 0;
+		rd->length = -RX_BUFF_SIZE | 0xf000;
+		rd->rmd1_bits = LE_R1_OWN;
+		lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK;
+	}
+	return 0;
+}
+
+static int lance_tx(struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_init_block *ib;
+	volatile struct lance_regs *ll = lp->ll;
+	volatile struct lance_tx_desc *td;
+	int i, j;
+	int status;
+	ib = (struct lance_init_block *) (dev->mem_start);
+	j = lp->tx_old;
+
+	for (i = j; i != lp->tx_new; i = j) {
+		td = &ib->btx_ring[i];
+		/* If we hit a packet not owned by us, stop */
+		if (td->tmd1_bits & LE_T1_OWN)
+			break;
+
+		if (td->tmd1_bits & LE_T1_ERR) {
+			status = td->misc;
+
+			lp->stats.tx_errors++;
+			if (status & LE_T3_RTY)
+				lp->stats.tx_aborted_errors++;
+			if (status & LE_T3_LCOL)
+				lp->stats.tx_window_errors++;
+
+			if (status & LE_T3_CLOS) {
+				lp->stats.tx_carrier_errors++;
+				printk("%s: Carrier Lost", dev->name);
+				/* Stop the lance */
+				writereg(&ll->rap, LE_CSR0);
+				writereg(&ll->rdp, LE_C0_STOP);
+				lance_init_ring(dev);
+				load_csrs(lp);
+				init_restart_lance(lp);
+				return 0;
+			}
+			/* Buffer errors and underflows turn off the
+			 * transmitter, restart the adapter.
+			 */
+			if (status & (LE_T3_BUF | LE_T3_UFL)) {
+				lp->stats.tx_fifo_errors++;
+
+				printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
+				       dev->name);
+				/* Stop the lance */
+				writereg(&ll->rap, LE_CSR0);
+				writereg(&ll->rdp, LE_C0_STOP);
+				lance_init_ring(dev);
+				load_csrs(lp);
+				init_restart_lance(lp);
+				return 0;
+			}
+		} else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) {
+			/*
+			 * So we don't count the packet more than once.
+			 */
+			td->tmd1_bits &= ~(LE_T1_POK);
+
+			/* One collision before packet was sent. */
+			if (td->tmd1_bits & LE_T1_EONE)
+				lp->stats.collisions++;
+
+			/* More than one collision, be optimistic. */
+			if (td->tmd1_bits & LE_T1_EMORE)
+				lp->stats.collisions += 2;
+
+			lp->stats.tx_packets++;
+		}
+		j = (j + 1) & TX_RING_MOD_MASK;
+	}
+	lp->tx_old = j;
+	return 0;
+}
+
+static void lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *) dev_id;
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_regs *ll = lp->ll;
+	int csr0;
+
+	if (dev->interrupt)
+		printk("%s: again\n", dev->name);
+
+	dev->interrupt = 1;
+
+	writereg(&ll->rap, LE_CSR0);
+	csr0 = ll->rdp;
+
+	/* Acknowledge all the interrupt sources ASAP */
+	writereg(&ll->rdp, csr0 & (LE_C0_INTR | LE_C0_TINT | LE_C0_RINT));
+
+	if ((csr0 & LE_C0_ERR)) {
+		/* Clear the error condition */
+		writereg(&ll->rdp, LE_C0_BABL | LE_C0_ERR | LE_C0_MISS |
+			 LE_C0_CERR | LE_C0_MERR);
+	}
+	if (csr0 & LE_C0_RINT)
+		lance_rx(dev);
+
+	if (csr0 & LE_C0_TINT)
+		lance_tx(dev);
+
+	if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) {
+		dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+	if (csr0 & LE_C0_BABL)
+		lp->stats.tx_errors++;
+
+	if (csr0 & LE_C0_MISS)
+		lp->stats.rx_errors++;
+
+	if (csr0 & LE_C0_MERR) {
+		volatile unsigned long int_stat = *(unsigned long *) (system_base + IOCTL + SIR);
+
+		printk("%s: Memory error, status %04x", dev->name, csr0);
+
+		if (int_stat & LANCE_DMA_MEMRDERR) {
+			printk("%s: DMA error\n", dev->name);
+			int_stat |= LANCE_DMA_MEMRDERR;
+			/*
+			 * re-enable LANCE DMA
+			 */
+			*(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16);
+		}
+		writereg(&ll->rdp, LE_C0_STOP);
+
+		lance_init_ring(dev);
+		load_csrs(lp);
+		init_restart_lance(lp);
+		dev->tbusy = 0;
+	}
+	writereg(&ll->rdp, LE_C0_INEA);
+	writereg(&ll->rdp, LE_C0_INEA);
+	dev->interrupt = 0;
+}
+
+struct device *last_dev = 0;
+
+static int lance_open(struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_regs *ll = lp->ll;
+	int status = 0;
+
+	last_dev = dev;
+
+	/* Associate IRQ with lance_interrupt */
+	if (request_irq(dev->irq, &lance_interrupt, 0, lp->name, dev)) {
+		printk("Lance: Can't get irq %d\n", dev->irq);
+		return -EAGAIN;
+	}
+	/* Stop the Lance */
+	writereg(&ll->rap, LE_CSR0);
+	writereg(&ll->rdp, LE_C0_STOP);
+
+	lance_init_ring(dev);
+	load_csrs(lp);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	status = init_restart_lance(lp);
+
+	/*
+	 * if (!status)
+	 *      MOD_INC_USE_COUNT;
+	 */
+
+	return status;
+}
+
+static int lance_close(struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_regs *ll = lp->ll;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	/* Stop the card */
+	writereg(&ll->rap, LE_CSR0);
+	writereg(&ll->rdp, LE_C0_STOP);
+
+	free_irq(dev->irq, (void *) dev);
+	/*
+	   MOD_DEC_USE_COUNT;
+	 */
+	return 0;
+}
+
+static inline int lance_reset(struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_regs *ll = lp->ll;
+	int status;
+
+	/* Stop the lance */
+	writereg(&ll->rap, LE_CSR0);
+	writereg(&ll->rdp, LE_C0_STOP);
+
+	lance_init_ring(dev);
+	load_csrs(lp);
+	dev->trans_start = jiffies;
+	dev->interrupt = 0;
+	dev->start = 1;
+	dev->tbusy = 0;
+	status = init_restart_lance(lp);
+#ifdef DEBUG_DRIVER
+	printk("Lance restart=%d\n", status);
+#endif
+	return status;
+}
+
+static int lance_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_regs *ll = lp->ll;
+	volatile struct lance_init_block *ib;
+	unsigned long flags;
+	int entry, skblen, len;
+	int status = 0;
+	static int outs;
+	ib = (struct lance_init_block *) (dev->mem_start);
+
+	/* Transmitter timeout, serious problems */
+	if (dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+
+		if (tickssofar < 100) {
+			status = -1;
+		} else {
+			printk("%s: transmit timed out, status %04x, reset\n",
+			       dev->name, ll->rdp);
+			lance_reset(dev);
+		}
+		return status;
+	}
+	/* Block a timer-based transmit from overlapping. */
+	if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
+		printk("Transmitter access conflict.\n");
+		return -1;
+	}
+	skblen = skb->len;
+	save_and_cli(flags);
+	if (!TX_BUFFS_AVAIL) {
+		restore_flags(flags);
+		return -1;
+	}
+	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
+
+	lp->stats.tx_bytes += len;
+
+	entry = lp->tx_new & TX_RING_MOD_MASK;
+	ib->btx_ring[entry].length = (-len);
+	ib->btx_ring[entry].misc = 0;
+
+	cp_to_buf((char *) lp->tx_buf_ptr_cpu[entry], skb->data, skblen);
+
+	/* Clear the slack of the packet, do I need this? */
+	/* For a firewall its a good idea - AC */
+/*
+   if (len != skblen)
+   memset ((char *) &ib->tx_buf [entry][skblen], 0, (len - skblen) << 1);
+ */
+
+	/* Now, give the packet to the lance */
+	ib->btx_ring[entry].tmd1_bits = (LE_T1_POK | LE_T1_OWN);
+	lp->tx_new = (lp->tx_new + 1) & TX_RING_MOD_MASK;
+
+	outs++;
+	/* Kick the lance: transmit now */
+	writereg(&ll->rdp, LE_C0_INEA | LE_C0_TDMD);
+	dev->trans_start = jiffies;
+	dev_kfree_skb(skb);
+
+	if (TX_BUFFS_AVAIL)
+		dev->tbusy = 0;
+
+	restore_flags(flags);
+	return status;
+}
+
+static struct net_device_stats *lance_get_stats(struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+
+	return &lp->stats;
+}
+
+static void lance_load_multicast(struct device *dev)
+{
+	volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start);
+	volatile u16 *mcast_table = (u16 *) & ib->filter;
+	struct dev_mc_list *dmi = dev->mc_list;
+	char *addrs;
+	int i, j, bit, byte;
+	u32 crc, poly = CRC_POLYNOMIAL_BE;
+
+	/* set all multicast bits */
+	if (dev->flags & IFF_ALLMULTI) {
+		ib->filter[0] = 0xffff;
+		ib->filter[2] = 0xffff;
+		ib->filter[4] = 0xffff;
+		ib->filter[6] = 0xffff;
+		return;
+	}
+	/* clear the multicast filter */
+	ib->filter[0] = 0;
+	ib->filter[2] = 0;
+	ib->filter[4] = 0;
+	ib->filter[6] = 0;
+
+	/* Add addresses */
+	for (i = 0; i < dev->mc_count; i++) {
+		addrs = dmi->dmi_addr;
+		dmi = dmi->next;
+
+		/* multicast address? */
+		if (!(*addrs & 1))
+			continue;
+
+		crc = 0xffffffff;
+		for (byte = 0; byte < 6; byte++)
+			for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
+				int test;
+
+				test = ((bit ^ crc) & 0x01);
+				crc >>= 1;
+
+				if (test) {
+					crc = crc ^ poly;
+				}
+			}
+
+		crc = crc >> 26;
+		mcast_table[crc >> 3] |= 1 << (crc & 0xf);
+	}
+	return;
+}
+
+static void lance_set_multicast(struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_init_block *ib;
+	volatile struct lance_regs *ll = lp->ll;
+
+	ib = (struct lance_init_block *) (dev->mem_start);
+
+	while (dev->tbusy)
+		schedule();
+	set_bit(0, (void *) &dev->tbusy);
+	while (lp->tx_old != lp->tx_new)
+		schedule();
+
+	writereg(&ll->rap, LE_CSR0);
+	writereg(&ll->rdp, LE_C0_STOP);
+
+	lance_init_ring(dev);
+
+	if (dev->flags & IFF_PROMISC) {
+		ib->mode |= LE_MO_PROM;
+	} else {
+		ib->mode &= ~LE_MO_PROM;
+		lance_load_multicast(dev);
+	}
+	load_csrs(lp);
+	init_restart_lance(lp);
+	dev->tbusy = 0;
+}
+
+__initfunc(static int dec_lance_init(struct device *dev, const int type))
+{
+	static unsigned version_printed = 0;
+	struct lance_private *lp;
+	volatile struct lance_regs *ll;
+	int i;
+	unsigned long esar_base;
+	unsigned char *esar;
+
+#ifndef CONFIG_TC
+	system_base = KN01_LANCE_BASE;
+#else
+	int slot;
+#endif
+
+	if (dec_lance_debug && version_printed++ == 0)
+		printk(version);
+
+	if (dev == NULL) {
+		dev = init_etherdev(0, sizeof(struct lance_private) + 8);
+	} else {
+		dev->priv = kmalloc(sizeof(struct lance_private) + 8,
+				    GFP_KERNEL);
+		if (dev->priv == NULL)
+			return -ENOMEM;
+		memset(dev->priv, 0, sizeof(struct lance_private) + 8);
+
+	}
+
+	/* Make certain the data structures used by the LANCE are aligned. */
+	dev->priv = (void *) (((unsigned long) dev->priv + 7) & ~7);
+	lp = (struct lance_private *) dev->priv;
+
+	switch (type) {
+#ifdef CONFIG_TC
+	case ASIC_LANCE:
+		dev->base_addr = system_base + LANCE;
+
+		/* buffer space for the on-board LANCE shared memory */
+		/*
+		 * FIXME: ugly hack!
+		 */
+		dev->mem_start = KSEG1ADDR(0x0020000);
+		dev->mem_end = dev->mem_start + 0x00020000;
+		dev->irq = ETHER;
+		esar_base = system_base + ESAR;
+
+		/*
+		 * setup the pointer arrays, this sucks [tm] :-(
+		 */
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			lp->rx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU
+						 + 2 * i * RX_BUFF_SIZE);
+			lp->rx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC
+						     + i * RX_BUFF_SIZE);
+		}
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			lp->tx_buf_ptr_cpu[i] = (char *) (dev->mem_start + BUF_OFFSET_CPU
+					+ 2 * RX_RING_SIZE * RX_BUFF_SIZE
+						 + 2 * i * TX_BUFF_SIZE);
+			lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC
+					    + RX_RING_SIZE * RX_BUFF_SIZE
+						     + i * TX_BUFF_SIZE);
+		}
+
+		/*
+		 * setup and enable IOASIC LANCE DMA
+		 */
+		lp->dma_ptr_reg = (unsigned long *) (system_base + IOCTL + LANCE_DMA_P);
+		*(lp->dma_ptr_reg) = PHYSADDR(dev->mem_start) << 3;
+		*(unsigned long *) (system_base + IOCTL + SSR) |= (1 << 16);
+
+		break;
+	case PMAD_LANCE:
+		slot = search_tc_card("PMAD-AA");
+		claim_tc_card(slot);
+
+		dev->mem_start = get_tc_base_addr(slot);
+		dev->base_addr = dev->mem_start + 0x100000;
+		dev->irq = get_tc_irq_nr(slot);
+		esar_base = dev->mem_start + 0x1c0002;
+		break;
+#endif
+	case PMAX_LANCE:
+		dev->irq = ETHER;
+		dev->base_addr = KN01_LANCE_BASE;
+		dev->mem_start = KN01_LANCE_BASE + 0x01000000;
+		esar_base = KN01_RTC_BASE + 1;
+		/*
+		 * setup the pointer arrays, this sucks [tm] :-(
+		 */
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			lp->rx_buf_ptr_cpu[i] =
+			    (char *) (dev->mem_start + BUF_OFFSET_CPU
+				      + 2 * i * RX_BUFF_SIZE);
+
+			lp->rx_buf_ptr_lnc[i] =
+			    (char *) (BUF_OFFSET_LNC
+				      + i * RX_BUFF_SIZE);
+
+		}
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			lp->tx_buf_ptr_cpu[i] =
+			    (char *) (dev->mem_start + BUF_OFFSET_CPU
+				      + 2 * RX_RING_SIZE * RX_BUFF_SIZE
+				      + 2 * i * TX_BUFF_SIZE);
+			lp->tx_buf_ptr_lnc[i] = (char *) (BUF_OFFSET_LNC
+					    + RX_RING_SIZE * RX_BUFF_SIZE
+						     + i * TX_BUFF_SIZE);
+
+		}
+		break;
+	default:
+		printk("declance_init called with unknown type\n");
+		return -ENODEV;
+		break;
+	}
+
+	ll = (struct lance_regs *) dev->base_addr;
+	esar = (unsigned char *) esar_base;
+
+	/* prom checks */
+	/* First, check for test pattern */
+	if (esar[0x60] != 0xff && esar[0x64] != 0x00 &&
+	    esar[0x68] != 0x55 && esar[0x6c] != 0xaa) {
+		printk("Ethernet station address prom not found!\n");
+		return -ENODEV;
+	}
+	/* Check the prom contents */
+	for (i = 0; i < 8; i++) {
+		if (esar[i * 4] != esar[0x3c - i * 4] &&
+		    esar[i * 4] != esar[0x40 + i * 4] &&
+		    esar[0x3c - i * 4] != esar[0x40 + i * 4]) {
+			printk("Something is wrong with the ethernet "
+			       "station address prom!\n");
+			return -ENODEV;
+		}
+	}
+
+	/* Copy the ethernet address to the device structure, later to the
+	 * lance initialization block so the lance gets it every time it's
+	 * (re)initialized.
+	 */
+	switch (type) {
+	case ASIC_LANCE:
+		printk("%s: IOASIC onboard LANCE, addr = ", dev->name);
+		break;
+	case PMAD_LANCE:
+		printk("%s: PMAD-AA, addr = ", dev->name);
+		break;
+	case PMAX_LANCE:
+		printk("%s: PMAX onboard LANCE, addr = ", dev->name);
+		break;
+	}
+	for (i = 0; i < 6; i++) {
+		dev->dev_addr[i] = esar[i * 4];
+		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ',' : ':');
+	}
+
+	printk(" irq = %d\n", dev->irq);
+
+	/* Fill the dev fields */
+
+	dev->open = lance_open;
+	dev->stop = lance_close;
+	dev->hard_start_xmit = lance_start_xmit;
+	dev->get_stats = lance_get_stats;
+	dev->set_multicast_list = lance_set_multicast;
+	dev->dma = 0;
+
+	/* lp->ll is the location of the registers for lance card */
+	lp->ll = ll;
+
+	lp->name = lancestr;
+
+	/* busmaster_regval (CSR3) should be zero according to the PMAD-AA
+	 * specification.
+	 */
+	lp->busmaster_regval = 0;
+	lp->dev = dev;
+
+	ether_setup(dev);
+/*
+   #ifdef MODULE
+   dev->ifindex = dev_new_index();
+   lp->next_module = root_lance_dev;
+   root_lance_dev = lp;
+   #endif
+ */
+	return 0;
+}
+
+
+/* Find all the lance cards on the system and initialize them */
+__initfunc(int dec_lance_probe(struct device *dev))
+{
+	static int called = 0;
+
+#ifdef CONFIG_TC
+	int slot = -1;
+
+	if (TURBOCHANNEL) {
+		if (IOASIC && !called) {
+			called = 1;
+			type = ASIC_LANCE;
+		} else {
+			if ((slot = search_tc_card("PMAD-AA")) >= 0) {
+				type = PMAD_LANCE;
+			} else {
+				return -ENODEV;
+			}
+		}
+	} else {
+		if (!called) {
+			called = 1;
+			type = PMAX_LANCE;
+		} else {
+			return -ENODEV;
+		}
+	}
+#else
+	if (!called && !TURBOCHANNEL) {
+		called = 1;
+		type = PMAX_LANCE;
+	} else {
+		return -ENODEV;
+	}
+#endif
+
+	return dec_lance_init(dev, type);
+}
+
+/*
+   #ifdef MODULE
+
+   int
+   init_module(void)
+   {
+   root_lance_dev = NULL;
+   return dec_lance_probe(NULL);
+   }
+
+   void
+   cleanup_module(void)
+   {
+   struct lance_private *lp;
+
+   while (root_lance_dev) {
+   lp = root_lance_dev->next_module;
+
+   unregister_netdev(root_lance_dev->dev);
+   kfree(root_lance_dev->dev);
+   root_lance_dev = lp;
+   }
+   }
+
+   #endif -* MODULE */
diff -u --recursive --new-file v2.3.8/linux/drivers/net/depca.c linux/drivers/net/depca.c
--- v2.3.8/linux/drivers/net/depca.c	Tue Nov 24 09:21:11 1998
+++ linux/drivers/net/depca.c	Mon Jun 28 08:11:52 1999
@@ -221,11 +221,13 @@
                            by <tymm@computer.org> 
       0.451    5-Nov-98   Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
       0.5     14-Nov-98   Re-spin for 2.1.x kernels.
+      0.51    27-Jun-99   Correct received packet length for CRC from
+                           report by <worm@dkik.dk>
 
     =========================================================================
 */
 
-static const char *version = "depca.c:v0.5 1998/11/14 davies@maniac.ultranet.com\n";
+static const char *version = "depca.c:v0.51 1999/6/27 davies@maniac.ultranet.com\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -947,7 +949,7 @@
 	if (status & R_CRC)  lp->stats.rx_crc_errors++;
 	if (status & R_BUFF) lp->stats.rx_fifo_errors++;
       } else {	
-	short len, pkt_len = readw(&lp->rx_ring[entry].msg_length);
+	short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
 	struct sk_buff *skb;
 
 	skb = dev_alloc_skb(pkt_len+2);
diff -u --recursive --new-file v2.3.8/linux/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- v2.3.8/linux/drivers/net/irda/irtty.c	Sun May 30 10:27:04 1999
+++ linux/drivers/net/irda/irtty.c	Wed Jun 30 11:24:54 1999
@@ -24,7 +24,6 @@
  *     
  ********************************************************************/    
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <asm/uaccess.h>
 #include <linux/kernel.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/net/jazzsonic.c linux/drivers/net/jazzsonic.c
--- v2.3.8/linux/drivers/net/jazzsonic.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/jazzsonic.c	Fri Jun 25 17:39:52 1999
@@ -0,0 +1,266 @@
+/*
+ * sonic.c
+ *
+ * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ * 
+ * This driver is based on work from Andreas Busse, but most of
+ * the code is rewritten.
+ * 
+ * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
+ *
+ * A driver for the onboard Sonic ethernet controller on Mips Jazz
+ * systems (Acer Pica-61, Mips Magnum 4000, Olivetti M700 and
+ * perhaps others, too)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/jazz.h>
+#include <asm/jazzdma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#define SREGS_PAD(n)    u16 n;
+
+#include "sonic.h"
+
+/*
+ * Macros to access SONIC registers
+ */
+#define SONIC_READ(reg) \
+	*((volatile unsigned int *)base_addr+reg)
+
+#define SONIC_WRITE(reg,val) \
+	*((volatile unsigned int *)base_addr+reg) = val
+
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifdef SONIC_DEBUG
+static unsigned int sonic_debug = SONIC_DEBUG;
+#else 
+static unsigned int sonic_debug = 1;
+#endif
+
+/*
+ * Base address and interupt of the SONIC controller on JAZZ boards
+ */
+static struct {
+    unsigned int port;
+    unsigned int irq;
+} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};
+
+/*
+ * We cannot use station (ethernet) address prefixes to detect the
+ * sonic controller since these are board manufacturer depended.
+ * So we check for known Silicon Revision IDs instead. 
+ */
+static unsigned short known_revisions[] =
+{
+  0x04,				/* Mips Magnum 4000 */
+  0xffff			/* end of list */
+};
+
+/* Index to functions, as function prototypes. */
+
+extern int sonic_probe(struct device *dev);
+static int sonic_probe1(struct device *dev, unsigned int base_addr, unsigned int irq);
+
+
+/*
+ * Probe for a SONIC ethernet controller on a Mips Jazz board.
+ * Actually probing is superfluous but we're paranoid.
+ */
+__initfunc(int sonic_probe(struct device *dev))
+{
+    unsigned int base_addr = dev ? dev->base_addr : 0;
+    int i;
+
+    /*
+     * Don't probe if we're not running on a Jazz board.
+     */
+    if (mips_machgroup != MACH_GROUP_JAZZ)
+	return -ENODEV;
+    if (base_addr >= KSEG0)	/* Check a single specified location. */
+	return sonic_probe1(dev, base_addr, dev->irq);
+    else if (base_addr != 0)	/* Don't probe at all. */
+	return -ENXIO;
+    
+    for (i = 0; sonic_portlist[i].port; i++) {
+	int base_addr = sonic_portlist[i].port;
+	if (check_region(base_addr, 0x100))
+	    continue;
+	if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0)
+	    return 0;
+    }
+    return -ENODEV;
+}
+
+__initfunc(static int sonic_probe1(struct device *dev,
+                                   unsigned int base_addr, unsigned int irq))
+{
+    static unsigned version_printed = 0;
+    unsigned int silicon_revision;
+    unsigned int val;
+    struct sonic_local *lp;
+    int i;
+    
+    /*
+     * get the Silicon Revision ID. If this is one of the known
+     * one assume that we found a SONIC ethernet controller at
+     * the expected location.
+     */
+    silicon_revision = SONIC_READ(SONIC_SR);
+    if (sonic_debug > 1)
+      printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
+
+    i = 0;
+    while ((known_revisions[i] != 0xffff) &&
+	   (known_revisions[i] != silicon_revision))
+      i++;
+	
+    if (known_revisions[i] == 0xffff) {
+	printk("SONIC ethernet controller not found (0x%4x)\n",
+	       silicon_revision);
+	return -ENODEV;
+    }
+    
+    request_region(base_addr, 0x100, "SONIC");
+    
+    /* Allocate a new 'dev' if needed. */
+    if (dev == NULL)
+      dev = init_etherdev(0, sizeof(struct sonic_local));
+
+    if (sonic_debug  &&  version_printed++ == 0)
+      printk(version);
+
+    printk("%s: %s found at 0x%08x, ",
+	   dev->name, "SONIC ethernet", base_addr);
+
+    /* Fill in the 'dev' fields. */
+    dev->base_addr = base_addr;
+    dev->irq = irq;
+
+    /*
+     * Put the sonic into software reset, then
+     * retrieve and print the ethernet address.
+     */
+    SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
+    SONIC_WRITE(SONIC_CEP,0);
+    for (i=0; i<3; i++) {
+	val = SONIC_READ(SONIC_CAP0-i);
+	dev->dev_addr[i*2] = val;
+	dev->dev_addr[i*2+1] = val >> 8;
+    }
+
+    printk("HW Address ");
+    for (i = 0; i < 6; i++) {
+	printk("%2.2x", dev->dev_addr[i]);
+	if (i<5)
+	  printk(":");
+    }
+    
+    printk(" IRQ %d\n", irq);
+    
+    /* Initialize the device structure. */
+    if (dev->priv == NULL) {
+	/*
+	 * the memory be located in the same 64kb segment
+	 */
+	lp = NULL;
+	i = 0;
+	do {
+	    lp = (struct sonic_local *)kmalloc(sizeof(*lp), GFP_KERNEL);
+	    if ((unsigned long)lp >> 16 != ((unsigned long)lp + sizeof(*lp) ) >> 16) {
+		/* FIXME, free the memory later */
+		kfree (lp);
+		lp = NULL;
+	    }
+	} while (lp == NULL && i++ < 20);
+	
+	if (lp == NULL) {
+	    printk ("%s: couldn't allocate memory for descriptors\n",
+	            dev->name);
+	    return -ENOMEM;
+	}
+	
+	memset(lp, 0, sizeof(struct sonic_local));
+	
+	/* get the virtual dma address */
+	lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp));
+	if (lp->cda_laddr == ~0UL) {
+	    printk ("%s: couldn't get DMA page entry for descriptors\n",
+	            dev->name);
+	    return -ENOMEM;
+	}
+
+	lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
+	lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
+	lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
+	
+	/* allocate receive buffer area */
+	/* FIXME, maybe we should use skbs */
+	if ((lp->rba = (char *)kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) {
+	    printk ("%s: couldn't allocate receive buffers\n",dev->name);
+	    return -ENOMEM;
+	}
+	
+	/* get virtual dma address */
+	if ((lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),SONIC_NUM_RRS * SONIC_RBSIZE)) == ~0UL) {
+	    printk ("%s: couldn't get DMA page entry for receive buffers\n",dev->name);
+	    return -ENOMEM;
+	}
+	
+	/* now convert pointer to KSEG1 pointer */
+	lp->rba = (char *)KSEG1ADDR(lp->rba);
+	flush_cache_all();
+	dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
+    }
+
+    lp = (struct sonic_local *)dev->priv;
+    dev->open = sonic_open;
+    dev->stop = sonic_close;
+    dev->hard_start_xmit = sonic_send_packet;
+    dev->get_stats	= sonic_get_stats;
+    dev->set_multicast_list = &sonic_multicast_list;
+
+    /*
+     * clear tally counter
+     */
+    SONIC_WRITE(SONIC_CRCT,0xffff);
+    SONIC_WRITE(SONIC_FAET,0xffff);
+    SONIC_WRITE(SONIC_MPT,0xffff);
+
+    /* Fill in the fields of the device structure with ethernet values. */
+    ether_setup(dev);
+    return 0;
+}
+
+/*
+ *      SONIC uses a normal IRQ
+ */
+#define sonic_request_irq       request_irq
+#define sonic_free_irq          free_irq
+
+#define sonic_chiptomem(x)      KSEG1ADDR(vdma_log2phys(x))
+
+#include "sonic.c"
diff -u --recursive --new-file v2.3.8/linux/drivers/net/sgiseeq.c linux/drivers/net/sgiseeq.c
--- v2.3.8/linux/drivers/net/sgiseeq.c	Mon Nov 16 10:39:27 1998
+++ linux/drivers/net/sgiseeq.c	Fri Jun 25 17:39:52 1999
@@ -1,11 +1,9 @@
-/*
+/* $Id: sgiseeq.c,v 1.9 1998/10/14 23:40:46 ralf Exp $
+ *
  * sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: sgiseeq.c,v 1.6 1998/10/14 17:29:44 ralf Exp $
  */
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -695,6 +693,7 @@
 	dev->irq                  = irq;
 	dev->dma                  = 0;
 	ether_setup(dev);
+
 	return 0;
 }
 
@@ -724,15 +723,20 @@
 
 int sgiseeq_probe(struct device *dev)
 {
+	static int initialized;
 	char *ep;
 
+	if (initialized)	/* Already initialized? */
+		return 0;
+	initialized++;
+
 	/* First get the ethernet address of the onboard
 	 * interface from ARCS.
+	 * (This is fragile; PROM doesn't like running from cache.)
 	 */
 	ep = romvec->get_evar("eaddr");
 	str2eaddr(onboard_eth_addr, ep);
 	return sgiseeq_init(dev,
 			    (struct sgiseeq_regs *) (KSEG1ADDR(0x1fbd4000)),
 			    &hpc3c0->ethregs, 3);
-
 }
diff -u --recursive --new-file v2.3.8/linux/drivers/net/sonic.c linux/drivers/net/sonic.c
--- v2.3.8/linux/drivers/net/sonic.c	Thu Jan  7 08:46:59 1999
+++ linux/drivers/net/sonic.c	Fri Jun 25 17:39:52 1999
@@ -1,290 +1,23 @@
 /*
  * sonic.c
  *
- * (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.franken.de)
+ * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
  * 
  * This driver is based on work from Andreas Busse, but most of
  * the code is rewritten.
  * 
  * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
  *
- * A driver for the onboard Sonic ethernet controller on Mips Jazz
- * systems (Acer Pica-61, Mips Magnum 4000, Olivetti M700 and
- * perhaps others, too)
+ *    Core code included by system sonic drivers
  */
 
-static const char *version =
-	"sonic.c:v0.10 6.7.96 tsbogend@bigbug.franken.de\n";
-
 /*
  * Sources: Olivetti M700-10 Risc Personal Computer hardware handbook,
  * National Semiconductors data sheet for the DP83932B Sonic Ethernet
  * controller, and the files "8390.c" and "skeleton.c" in this directory.
  */
 
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <asm/bootinfo.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/pgtable.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/jazz.h>
-#include <asm/jazzdma.h>
-#include <linux/errno.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "sonic.h"
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifdef SONIC_DEBUG
-static unsigned int sonic_debug = SONIC_DEBUG;
-#else 
-static unsigned int sonic_debug = 2;
-#endif
-
-/*
- * Some tunables for the buffer areas. Power of 2 is required
- * the current driver uses one receive buffer for each descriptor.
- */
-#define SONIC_NUM_RRS    16             /* number of receive resources */
-#define SONIC_NUM_RDS    SONIC_NUM_RRS  /* number of receive descriptors */
-#define SONIC_NUM_TDS    16      /* number of transmit descriptors */
-#define SONIC_RBSIZE   1520      /* size of one resource buffer */
-
-#define SONIC_RDS_MASK   (SONIC_NUM_RDS-1)
-#define SONIC_TDS_MASK   (SONIC_NUM_TDS-1)
 
-/*
- * Base address and interupt of the SONIC controller on JAZZ boards
- */
-static struct {
-    unsigned int port;
-    unsigned int irq;
-    } sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};
-
-
-/* Information that need to be kept for each board. */
-struct sonic_local {
-    sonic_cda_t   cda;                     /* virtual CPU address of CDA */
-    sonic_td_t    tda[SONIC_NUM_TDS];      /* transmit descriptor area */
-    sonic_rr_t    rra[SONIC_NUM_RRS];      /* receive resource arrea */
-    sonic_rd_t    rda[SONIC_NUM_RDS];      /* receive descriptor area */
-    struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */
-    unsigned int  tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */
-    unsigned char *rba;                    /* start of receive buffer areas */    
-    unsigned int  cda_laddr;               /* logical DMA address of CDA */    
-    unsigned int  tda_laddr;               /* logical DMA address of TDA */
-    unsigned int  rra_laddr;               /* logical DMA address of RRA */    
-    unsigned int  rda_laddr;               /* logical DMA address of RDA */
-    unsigned int  rba_laddr;               /* logical DMA address of RBA */
-    unsigned int  cur_tx, cur_rx;          /* current indexes to resource areas */
-    unsigned int  dirty_tx,cur_rra;        /* last unacked transmit packet */
-    char tx_full;
-    struct enet_statistics stats;
-};
-
-/*
- * We cannot use station (ethernet) address prefixes to detect the
- * sonic controller since these are board manufacturer depended.
- * So we check for known Silicon Revision IDs instead. 
- */
-static unsigned short known_revisions[] =
-{
-  0x04,				/* Mips Magnum 4000 */
-  0xffff			/* end of list */
-};
-
-/* Index to functions, as function prototypes. */
-
-extern int sonic_probe(struct device *dev);
-static int sonic_probe1(struct device *dev, unsigned int base_addr, unsigned int irq);
-static int sonic_open(struct device *dev);
-static int sonic_send_packet(struct sk_buff *skb, struct device *dev);
-static void sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void sonic_rx(struct device *dev);
-static int sonic_close(struct device *dev);
-static struct enet_statistics *sonic_get_stats(struct device *dev);
-static void sonic_multicast_list(struct device *dev);
-static int sonic_init(struct device *dev);
-
-
-/*
- * Probe for a SONIC ethernet controller on a Mips Jazz board.
- * Actually probing is superfluous but we're paranoid.
- */
-__initfunc(int sonic_probe(struct device *dev))
-{
-    unsigned int base_addr = dev ? dev->base_addr : 0;
-    int i;
-
-    /*
-     * Don't probe if we're not running on a Jazz board.
-     */
-    if (mips_machgroup != MACH_GROUP_JAZZ)
-	return -ENODEV;
-    if (base_addr > 0x1ff)	/* Check a single specified location. */
-	return sonic_probe1(dev, base_addr, dev->irq);
-    else if (base_addr != 0)	/* Don't probe at all. */
-	return -ENXIO;
-    
-    for (i = 0; sonic_portlist[i].port; i++) {
-	int base_addr = sonic_portlist[i].port;
-	if (check_region(base_addr, 0x100))
-	    continue;
-	if (sonic_probe1(dev, base_addr, sonic_portlist[i].irq) == 0)
-	    return 0;
-    }
-    return -ENODEV;
-}
-
-__initfunc(static int sonic_probe1(struct device *dev,
-                                   unsigned int base_addr, unsigned int irq))
-{
-    static unsigned version_printed = 0;
-    unsigned int silicon_revision;
-    unsigned int val;
-    struct sonic_local *lp;
-    int i;
-    
-    /*
-     * get the Silicon Revision ID. If this is one of the known
-     * one assume that we found a SONIC ethernet controller at
-     * the expected location.
-     */
-    silicon_revision = SONIC_READ(SONIC_SR);
-    if (sonic_debug > 1)
-      printk("SONIC Silicon Revision = 0x%04x\n",silicon_revision);
-
-    i = 0;
-    while ((known_revisions[i] != 0xffff) &&
-	   (known_revisions[i] != silicon_revision))
-      i++;
-	
-    if (known_revisions[i] == 0xffff) {
-	printk("SONIC ethernet controller not found (0x%4x)\n",
-	       silicon_revision);
-	return -ENODEV;
-    }
-    
-    request_region(base_addr, 0x100, "SONIC");
-    
-    /* Allocate a new 'dev' if needed. */
-    if (dev == NULL)
-      dev = init_etherdev(0, sizeof(struct sonic_local));
-
-    if (sonic_debug  &&  version_printed++ == 0)
-      printk(version);
-
-    printk("%s: %s found at 0x%08x, ",
-	   dev->name, "SONIC ethernet", base_addr);
-
-    /* Fill in the 'dev' fields. */
-    dev->base_addr = base_addr;
-    dev->irq = irq;
-
-    /*
-     * Put the sonic into software reset, then
-     * retrieve and print the ethernet address.
-     */
-    SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
-    SONIC_WRITE(SONIC_CEP,0);
-    for (i=0; i<3; i++) {
-	val = SONIC_READ(SONIC_CAP0-i);
-	dev->dev_addr[i*2] = val;
-	dev->dev_addr[i*2+1] = val >> 8;
-    }
-
-    printk("HW Address ");
-    for (i = 0; i < 6; i++) {
-	printk("%2.2x", dev->dev_addr[i]);
-	if (i<5)
-	  printk(":");
-    }
-    
-    printk(" IRQ %d\n", irq);
-    
-    /* Initialize the device structure. */
-    if (dev->priv == NULL) {
-	/*
-	 * the memory be located in the same 64kb segment
-	 */
-	lp = NULL;
-	i = 0;
-	do {
-	    lp = (struct sonic_local *)kmalloc(sizeof(*lp), GFP_KERNEL);
-	    if ((unsigned long)lp >> 16 != ((unsigned long)lp + sizeof(*lp) ) >> 16) {
-		/* FIXME, free the memory later */
-		kfree (lp);
-		lp = NULL;
-	    }
-	} while (lp == NULL && i++ < 20);
-	
-	if (lp == NULL) {
-	    printk ("%s: couldn't allocate memory for descriptors\n",
-	            dev->name);
-	    return -ENOMEM;
-	}
-	
-	memset(lp, 0, sizeof(struct sonic_local));
-	
-	/* get the virtual dma address */
-	lp->cda_laddr = vdma_alloc(PHYSADDR(lp),sizeof(*lp));
-	if (lp->cda_laddr == ~0UL) {
-	    printk ("%s: couldn't get DMA page entry for descriptors\n",
-	            dev->name);
-	    return -ENOMEM;
-	}
-
-	lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda);
-	lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda);
-	lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra);
-	
-	/* allocate receive buffer area */
-	/* FIXME, maybe we should use skbs */
-	if ((lp->rba = (char *)kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL)) == NULL) {
-	    printk ("%s: couldn't allocate receive buffers\n",dev->name);
-	    return -ENOMEM;
-	}
-	
-	/* get virtual dma address */
-	if ((lp->rba_laddr = vdma_alloc(PHYSADDR(lp->rba),SONIC_NUM_RRS * SONIC_RBSIZE)) == ~0UL) {
-	    printk ("%s: couldn't get DMA page entry for receive buffers\n",dev->name);
-	    return -ENOMEM;
-	}
-	
-	/* now convert pointer to KSEG1 pointer */
-	lp->rba = (char *)KSEG1ADDR(lp->rba);
-	flush_cache_all();
-	dev->priv = (struct sonic_local *)KSEG1ADDR(lp);
-    }
-
-    lp = (struct sonic_local *)dev->priv;
-    dev->open = sonic_open;
-    dev->stop = sonic_close;
-    dev->hard_start_xmit = sonic_send_packet;
-    dev->get_stats	= sonic_get_stats;
-    dev->set_multicast_list = &sonic_multicast_list;
-
-    /* Fill in the fields of the device structure with ethernet values. */
-    ether_setup(dev);
-    return 0;
-}
 
 /*
  * Open/initialize the SONIC controller.
@@ -308,8 +41,8 @@
  * covering another bug otherwise corrupting data.  This doesn't mean
  * this glue works ok under all situations.
  */
-//    if (request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) {
-    if (request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, "sonic", dev)) {
+//    if (sonic_request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) {
+    if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, "sonic", dev)) {
 	printk ("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
 	return EAGAIN;
     }
@@ -351,7 +84,7 @@
     SONIC_WRITE(SONIC_IMR,0);
     SONIC_WRITE(SONIC_CMD,SONIC_CR_RST);
 
-    free_irq(dev->irq, dev);			/* release the IRQ */
+    sonic_free_irq(dev->irq, dev);		/* release the IRQ */
 
     return 0;
 }
@@ -424,11 +157,6 @@
     lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff;
     lp->tda[entry].tx_frag_ptr_h = laddr >> 16;
     lp->tda[entry].tx_frag_size  = length;
-    
-    /* if there are already packets queued, allow sending several packets at once */
-    if (lp->dirty_tx != lp->cur_tx)
-	lp->tda[(lp->cur_tx-1) % SONIC_TDS_MASK].link &= ~SONIC_END_OF_LINKS;
-    
     lp->cur_tx++;
     lp->stats.tx_bytes += length;
     
@@ -479,20 +207,23 @@
     
     if (status & SONIC_INT_TXDN) {
 	int dirty_tx = lp->dirty_tx;
-	
+
 	while (dirty_tx < lp->cur_tx) {
 	    int entry = dirty_tx & SONIC_TDS_MASK;
 	    int status = lp->tda[entry].tx_status;
-	    
+
 	    if (sonic_debug > 3)
 	      printk ("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n",
 		      status,lp->cur_tx,lp->dirty_tx);
-	    
-	    if (status == 0)
-	      break;			/* It still hasn't been Txed */
+
+	    if (status == 0) {
+		/* It still hasn't been Txed, kick the sonic again */
+		SONIC_WRITE(SONIC_CMD,SONIC_CR_TXP);		
+		break;
+	    }
 
 	    /* put back EOL and free descriptor */
-	    lp->tda[entry].link |= SONIC_END_OF_LINKS;
+	    lp->tda[entry].tx_frag_count = 0;
 	    lp->tda[entry].tx_status = 0;
 
 	    if (status & 0x0001)
@@ -574,27 +305,25 @@
 {
     unsigned int base_addr = dev->base_addr;
     struct sonic_local *lp = (struct sonic_local *)dev->priv;
-    int entry = lp->cur_rx & SONIC_RDS_MASK;
+    sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK];
     int status;
 
-    while(lp->rda[entry].in_use == 0)
-    {
+    while (rd->in_use == 0) {
 	struct sk_buff *skb;
 	int pkt_len;
 	unsigned char *pkt_ptr;
 	
-	status = lp->rda[entry].rx_status;
+	status = rd->rx_status;
 	if (sonic_debug > 3)
-	  printk ("status %x, cur_rx %d, cur_rra %d\n",status,lp->cur_rx,lp->cur_rra);
+	  printk ("status %x, cur_rx %d, cur_rra %x\n",status,lp->cur_rx,lp->cur_rra);
 	if (status & SONIC_RCR_PRX) {	    
-	    pkt_len = lp->rda[entry].rx_pktlen;
-	    pkt_ptr = (char *)KSEG1ADDR(vdma_log2phys((lp->rda[entry].rx_pktptr_h << 16) +
-						      lp->rda[entry].rx_pktptr_l));
+	    pkt_len = rd->rx_pktlen;
+	    pkt_ptr = (char *)sonic_chiptomem((rd->rx_pktptr_h << 16) +
+						      rd->rx_pktptr_l);
 	    
 	    if (sonic_debug > 3)
-	      printk ("pktptr %p (rba %p) h:%x l:%x, rra h:%x l:%x bsize h:%x l:%x\n", pkt_ptr,lp->rba,
-		      lp->rda[entry].rx_pktptr_h,lp->rda[entry].rx_pktptr_l,
-		      lp->rra[lp->cur_rra & 15].rx_bufadr_h,lp->rra[lp->cur_rra & 15].rx_bufadr_l,
+	      printk ("pktptr %p (rba %p) h:%x l:%x, bsize h:%x l:%x\n", pkt_ptr,lp->rba,
+		      rd->rx_pktptr_h,rd->rx_pktptr_l,
 		      SONIC_READ(SONIC_RBWC1),SONIC_READ(SONIC_RBWC0));
 	
 	    /* Malloc up new buffer. */
@@ -620,21 +349,26 @@
 	    if (status & SONIC_RCR_CRCR) lp->stats.rx_crc_errors++;
 	}
 	
-	lp->rda[entry].in_use = 1;
-	entry = (++lp->cur_rx) & SONIC_RDS_MASK;
+	rd->in_use = 1;
+	rd = &lp->rda[(++lp->cur_rx) & SONIC_RDS_MASK];
 	/* now give back the buffer to the receive buffer area */
 	if (status & SONIC_RCR_LPKT) {
 	    /*
 	     * this was the last packet out of the current receice buffer
 	     * give the buffer back to the SONIC
 	     */
-	    SONIC_WRITE(SONIC_RWP,(lp->rra_laddr + (++lp->cur_rra & 15) * sizeof(sonic_rr_t)) & 0xffff);
-	}
+	    lp->cur_rra += sizeof(sonic_rr_t);
+	    if (lp->cur_rra > (lp->rra_laddr + (SONIC_NUM_RRS-1) * sizeof(sonic_rr_t)))
+		lp->cur_rra = lp->rra_laddr;
+	    SONIC_WRITE(SONIC_RWP, lp->cur_rra & 0xffff);
+	} else
+	    printk ("%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",dev->name);
     }
-  
-    /* If any worth-while packets have been received, dev_rint()
-     has done a mark_bh(NET_BH) for us and will work on them
-     when we get to the bottom-half routine. */
+    /*
+     * If any worth-while packets have been received, dev_rint()
+     * has done a mark_bh(NET_BH) for us and will work on them
+     * when we get to the bottom-half routine.
+     */
     return;
 }
 
@@ -689,16 +423,15 @@
 	    for (i = 1; i <= dev->mc_count; i++) {
 		addr = dmi->dmi_addr;
 		dmi = dmi->next;
-		lp->cda.cam_desc[i].cam_frag2 = addr[1] << 8 | addr[0];
-		lp->cda.cam_desc[i].cam_frag1 = addr[3] << 8 | addr[2];
-		lp->cda.cam_desc[i].cam_frag0 = addr[5] << 8 | addr[4];
+		lp->cda.cam_desc[i].cam_cap0 = addr[1] << 8 | addr[0];
+		lp->cda.cam_desc[i].cam_cap1 = addr[3] << 8 | addr[2];
+		lp->cda.cam_desc[i].cam_cap2 = addr[5] << 8 | addr[4];
 		lp->cda.cam_enable |= (1 << i);
 	    }
-	    /* number of CAM entries to load */
-	    SONIC_WRITE(SONIC_CDC,dev->mc_count+1);
+	    SONIC_WRITE(SONIC_CDC,16);
 	    /* issue Load CAM command */
 	    SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);	    
-	    SONIC_WRITE(SONIC_CMD,SONIC_CR_LCAM);	    
+	    SONIC_WRITE(SONIC_CMD,SONIC_CR_LCAM);
 	}
     }
     
@@ -736,7 +469,6 @@
     SONIC_WRITE(SONIC_CMD,0);
     SONIC_WRITE(SONIC_CMD,SONIC_CR_RXDIS);
 
-
     /*
      * initialize the receive resource area
      */
@@ -761,7 +493,7 @@
     SONIC_WRITE(SONIC_URRA,lp->rra_laddr >> 16);
     SONIC_WRITE(SONIC_EOBC,(SONIC_RBSIZE-2) >> 1);
     
-    lp->cur_rra = SONIC_NUM_RRS - 2;
+    lp->cur_rra = lp->rra_laddr + (SONIC_NUM_RRS-1) * sizeof(sonic_rr_t);
 
     /* load the resource pointers */
     if (sonic_debug > 3)
@@ -796,7 +528,6 @@
     /* fix last descriptor */
     lp->rda[SONIC_NUM_RDS-1].link = lp->rda_laddr;
     lp->cur_rx = 0;
-    
     SONIC_WRITE(SONIC_URDA,lp->rda_laddr >> 16);
     SONIC_WRITE(SONIC_CRDA,lp->rda_laddr & 0xffff);
     
@@ -816,13 +547,14 @@
 
     SONIC_WRITE(SONIC_UTDA,lp->tda_laddr >> 16);
     SONIC_WRITE(SONIC_CTDA,lp->tda_laddr & 0xffff);
+    lp->cur_tx = lp->dirty_tx = 0;
     
     /*
      * put our own address to CAM desc[0]
      */
-    lp->cda.cam_desc[0].cam_frag2 = dev->dev_addr[1] << 8 | dev->dev_addr[0];
-    lp->cda.cam_desc[0].cam_frag1 = dev->dev_addr[3] << 8 | dev->dev_addr[2];
-    lp->cda.cam_desc[0].cam_frag0 = dev->dev_addr[5] << 8 | dev->dev_addr[4];
+    lp->cda.cam_desc[0].cam_cap0 = dev->dev_addr[1] << 8 | dev->dev_addr[0];
+    lp->cda.cam_desc[0].cam_cap1 = dev->dev_addr[3] << 8 | dev->dev_addr[2];
+    lp->cda.cam_desc[0].cam_cap2 = dev->dev_addr[5] << 8 | dev->dev_addr[4];
     lp->cda.cam_enable = 1;
     
     for (i=0; i < 16; i++)
@@ -832,7 +564,7 @@
      * initialize CAM registers
      */
     SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);
-    SONIC_WRITE(SONIC_CDC,1);
+    SONIC_WRITE(SONIC_CDC,16);
     
     /*
      * load the CAM
diff -u --recursive --new-file v2.3.8/linux/drivers/net/sonic.h linux/drivers/net/sonic.h
--- v2.3.8/linux/drivers/net/sonic.h	Thu Jun 26 12:33:39 1997
+++ linux/drivers/net/sonic.h	Fri Jun 25 17:39:52 1999
@@ -15,16 +15,6 @@
 #define SONIC_H
 
 /*
- * Macros to access SONIC registers
- */
-#define SONIC_READ(reg) \
-	*((volatile unsigned int *)base_addr+reg)
-
-#define SONIC_WRITE(reg,val) \
-	*((volatile unsigned int *)base_addr+reg) = val
-
-
-/*
  * SONIC register offsets
  */
  
@@ -242,9 +232,9 @@
 
 typedef struct {
   u16 rx_status;	/* status after reception of a packet */
-  u16 pad0;
+  SREGS_PAD(pad0);
   u16 rx_pktlen;	/* length of the packet incl. CRC */
-  u16 pad1;
+  SREGS_PAD(pad1);
   
   /*
    * Pointers to the location in the receive buffer area (RBA)
@@ -252,22 +242,22 @@
    * a contiguous piece of memory.
    */
   u16 rx_pktptr_l;
-  u16 pad2;
+  SREGS_PAD(pad2);
   u16 rx_pktptr_h;
-  u16 pad3;
+  SREGS_PAD(pad3);
 
   u16 rx_seqno;	/* sequence no. */
-  u16 pad4;
+  SREGS_PAD(pad4);
 
   u16 link;		/* link to next RDD (end if EOL bit set) */
-  u16 pad5;
+  SREGS_PAD(pad5);
 
   /*
    * Owner of this descriptor, 0= driver, 1=sonic
    */
   
   u16 in_use;	
-  u16 pad6;
+  SREGS_PAD(pad6);
 
   caddr_t rda_next;		/* pointer to next RD */
 } sonic_rd_t;
@@ -278,23 +268,23 @@
  */
 typedef struct {
   u16 tx_status;	/* status after transmission of a packet */
-  u16 pad0;		
+  SREGS_PAD(pad0);
   u16 tx_config;	/* transmit configuration for this packet */
-  u16 pad1;		
+  SREGS_PAD(pad1);
   u16 tx_pktsize;	/* size of the packet to be transmitted */
-  u16 pad2;		
+  SREGS_PAD(pad2);
   u16 tx_frag_count;	/* no. of fragments */
-  u16 pad3;		
+  SREGS_PAD(pad3);
 
   u16 tx_frag_ptr_l;
-  u16 pad4;		
+  SREGS_PAD(pad4);
   u16 tx_frag_ptr_h;
-  u16 pad5;		
+  SREGS_PAD(pad5);
   u16 tx_frag_size;
-  u16 pad6;		
+  SREGS_PAD(pad6);
   
   u16 link;		/* ptr to next descriptor */
-  u16 pad7;		
+  SREGS_PAD(pad7);
 } sonic_td_t;
 
 
@@ -304,13 +294,13 @@
 
 typedef struct {
   u16 cam_entry_pointer;
-  u16 pad;
-  u16 cam_frag2;
-  u16 pad2;
-  u16 cam_frag1;
-  u16 pad1;
-  u16 cam_frag0;
-  u16 pad0;
+  SREGS_PAD(pad0);
+  u16 cam_cap0;
+  SREGS_PAD(pad1);
+  u16 cam_cap1;
+  SREGS_PAD(pad2);
+  u16 cam_cap2;
+  SREGS_PAD(pad3);
 } sonic_cd_t;
 
 #define CAM_DESCRIPTORS 16
@@ -319,8 +309,56 @@
 typedef struct {
   sonic_cd_t cam_desc[CAM_DESCRIPTORS];
   u16 cam_enable;
-  u16 pad;
+  SREGS_PAD(pad);
 } sonic_cda_t;
 
+/*
+ * Some tunables for the buffer areas. Power of 2 is required
+ * the current driver uses one receive buffer for each descriptor.
+ */
+#define SONIC_NUM_RRS    16             /* number of receive resources */
+#define SONIC_NUM_RDS    SONIC_NUM_RRS  /* number of receive descriptors */
+#define SONIC_NUM_TDS    16      /* number of transmit descriptors */
+#define SONIC_RBSIZE   1520      /* size of one resource buffer */
+
+#define SONIC_RDS_MASK   (SONIC_NUM_RDS-1)
+#define SONIC_TDS_MASK   (SONIC_NUM_TDS-1)
+
+
+/* Information that need to be kept for each board. */
+struct sonic_local {
+    sonic_cda_t   cda;                     /* virtual CPU address of CDA */
+    sonic_td_t    tda[SONIC_NUM_TDS];      /* transmit descriptor area */
+    sonic_rr_t    rra[SONIC_NUM_RRS];      /* receive resource arrea */
+    sonic_rd_t    rda[SONIC_NUM_RDS];      /* receive descriptor area */
+    struct sk_buff* tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */
+    unsigned int  tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */
+    unsigned char *rba;                    /* start of receive buffer areas */    
+    unsigned int  cda_laddr;               /* logical DMA address of CDA */    
+    unsigned int  tda_laddr;               /* logical DMA address of TDA */
+    unsigned int  rra_laddr;               /* logical DMA address of RRA */    
+    unsigned int  rda_laddr;               /* logical DMA address of RDA */
+    unsigned int  rba_laddr;               /* logical DMA address of RBA */
+    unsigned int  cur_rra;                 /* current indexes to resource areas */
+    unsigned int  cur_rx;
+    unsigned int  cur_tx;
+    unsigned int  dirty_tx;                /* last unacked transmit packet */
+    char tx_full;
+    struct enet_statistics stats;
+};
+
+/* Index to functions, as function prototypes. */
+
+static int sonic_open(struct device *dev);
+static int sonic_send_packet(struct sk_buff *skb, struct device *dev);
+static void sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void sonic_rx(struct device *dev);
+static int sonic_close(struct device *dev);
+static struct enet_statistics *sonic_get_stats(struct device *dev);
+static void sonic_multicast_list(struct device *dev);
+static int sonic_init(struct device *dev);
+
+static const char *version =
+	"sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n";
 
 #endif /* SONIC_H */
diff -u --recursive --new-file v2.3.8/linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- v2.3.8/linux/drivers/net/yellowfin.c	Fri Dec 18 09:45:17 1998
+++ linux/drivers/net/yellowfin.c	Tue Jun 29 09:02:35 1999
@@ -76,6 +76,7 @@
 #include <linux/pci.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
+#include <asm/unaligned.h>
 #include <asm/io.h>
 
 #include <linux/netdevice.h>
@@ -1054,7 +1055,7 @@
 		u16 desc_status = desc->status;
 		int data_size = desc->request_cnt - desc->result_cnt;
 		u8 *buf_addr = bus_to_virt(desc->addr);
-		s16 frame_status = *(s16*)&(buf_addr[data_size - 2]); /* ?Alpha safe on 885? */
+		s16 frame_status = get_unaligned((s16*)(buf_addr+data_size-2));
 
 		if (yellowfin_debug > 4)
 			printk(KERN_DEBUG "  yellowfin_rx() status was %4.4x.\n",
diff -u --recursive --new-file v2.3.8/linux/drivers/pci/proc.c linux/drivers/pci/proc.c
--- v2.3.8/linux/drivers/pci/proc.c	Mon Aug 24 13:14:10 1998
+++ linux/drivers/pci/proc.c	Sun Jun 27 10:10:41 1999
@@ -222,11 +222,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 int
diff -u --recursive --new-file v2.3.8/linux/drivers/sbus/char/aurora.c linux/drivers/sbus/char/aurora.c
--- v2.3.8/linux/drivers/sbus/char/aurora.c	Wed Jun  9 14:44:25 1999
+++ linux/drivers/sbus/char/aurora.c	Wed Jun 30 11:24:54 1999
@@ -45,7 +45,6 @@
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/config.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/scsi/aic7xxx_proc.c linux/drivers/scsi/aic7xxx_proc.c
--- v2.3.8/linux/drivers/scsi/aic7xxx_proc.c	Wed Jun  9 16:59:15 1999
+++ linux/drivers/scsi/aic7xxx_proc.c	Wed Jun 30 11:24:54 1999
@@ -29,6 +29,8 @@
  *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
  *-M*************************************************************************/
 
+#include <linux/config.h>
+
 #define	BLS	(&aic7xxx_buffer[size])
 #define HDRB \
 "             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
diff -u --recursive --new-file v2.3.8/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.3.8/linux/drivers/scsi/sd.c	Mon Jun  7 16:50:56 1999
+++ linux/drivers/scsi/sd.c	Tue Jun 29 09:22:08 1999
@@ -945,7 +945,7 @@
 		printk("maxsg = %x, counted = %d this_count = %d\n",
 		       max_sg, counted, this_count);
 		while(bh){
-		    printk("[%p %lx] ", bh->b_data, bh->b_size);
+		    printk("[%p %x] ", bh->b_data, bh->b_size);
 		    bh = bh->b_reqnext;
 		}
 		if(SCpnt->use_sg < 16)
diff -u --recursive --new-file v2.3.8/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.3.8/linux/drivers/scsi/st.c	Sat May 22 14:50:22 1999
+++ linux/drivers/scsi/st.c	Tue Jun 29 09:22:08 1999
@@ -890,7 +890,7 @@
     kdev_t devt = inode->i_rdev;
     int dev;
 
-    if (filp->f_count > 1)
+    if (atomic_read(&filp->f_count) > 1)
 	return 0;
 
     dev = TAPE_NR(devt);
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/Config.in linux/drivers/sgi/Config.in
--- v2.3.8/linux/drivers/sgi/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/Config.in	Fri Jun 25 17:39:34 1999
@@ -0,0 +1,18 @@
+#
+# Character device configuration
+#
+mainmenu_option next_comment
+comment 'SGI devices'
+
+bool 'SGI Zilog85C30 serial support' CONFIG_SGI_SERIAL
+if [ "$CONFIG_SGI_SERIAL" != "n" ]; then
+  define_bool CONFIG_SERIAL y
+fi
+
+bool 'SGI DS1286  RTC support' CONFIG_SGI_DS1286
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then  
+  tristate 'SGI Newport Graphics support' CONFIG_SGI_NEWPORT_GFX
+fi
+
+endmenu
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/Makefile linux/drivers/sgi/Makefile
--- v2.3.8/linux/drivers/sgi/Makefile	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/Makefile	Fri Jun 25 17:39:34 1999
@@ -8,13 +8,15 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 SUB_DIRS     :=
-MOD_SUB_DIRS := $(SUB_DIRS)
+MOD_SUB_DIRS := $(SUB_DIRS) char
 ALL_SUB_DIRS := $(SUB_DIRS) char
 
+
 L_OBJS   := 
 L_TARGET := sgi.a
+MOD_LIST_NAME := SGI_MODULES
 
-# Character devices for SGI machines.
+# Character and Audio devices for SGI machines.
 #
 SUB_DIRS += char
 L_OBJS += char/sgichar.o
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/Makefile linux/drivers/sgi/char/Makefile
--- v2.3.8/linux/drivers/sgi/char/Makefile	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/char/Makefile	Fri Jun 25 17:39:34 1999
@@ -8,11 +8,25 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := sgichar.o
-O_OBJS   := graphics.o streamable.o newport.o cons_newport.o sgicons.o \
-	vga_font.o rrm.o shmiq.o usema.o
+OX_OBJS := newport.o
+O_OBJS   := sgicons.o \
+	usema.o shmiq.o streamable.o
 
 ifeq ($(CONFIG_SGI_SERIAL),y)
   O_OBJS += sgiserial.o
+endif
+
+ifeq ($(CONFIG_SGI_DS1286),y)
+  O_OBJS += ds1286.o
+endif
+
+ifeq ($(CONFIG_SGI_NEWPORT_GFX),y)
+  O_OBJS +=  graphics.o rrm.o
+else 
+ifeq ($(CONFIG_SGI_NEWPORT_GFX),m)
+  OX_OBJS  +=  graphics_syms.o
+  MX_OBJS +=  graphics.o rrm.o
+endif
 endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/cons_newport.c linux/drivers/sgi/char/cons_newport.c
--- v2.3.8/linux/drivers/sgi/char/cons_newport.c	Fri May  8 00:23:41 1998
+++ linux/drivers/sgi/char/cons_newport.c	Wed Dec 31 16:00:00 1969
@@ -1,611 +0,0 @@
-/*
- * cons_newport.c: Newport graphics console code for the SGI.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- *
- * $Id: cons_newport.c,v 1.1 1998/01/10 19:05:47 ecd Exp $
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/errno.h>
-#include <linux/kd.h>
-#include <linux/tty.h>
-#include <linux/malloc.h>
-#include <linux/major.h>
-#include <linux/mm.h>
-#include <linux/version.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/sgialib.h>
-#include <asm/ptrace.h>
-
-#include <linux/kbd_kern.h>
-#include <linux/vt_kern.h>
-#include <linux/consolemap.h>
-#include <linux/selection.h>
-#include <linux/console_struct.h>
-
-#include "gconsole.h"
-#include "newport.h"
-#include "graphics.h" /* Just for now */
-#include <asm/gfx.h>
-#include <asm/ng1.h>
-
-#if 0
-#include "linux_logo.h"
-#endif
-
-#define BMASK(c) (c << 24)
-
-#define RENDER(regs, cp) do { \
-(regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \
-(regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \
-(regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \
-(regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \
-(regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \
-(regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \
-(regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \
-(regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \
-} while(0)        
-
-#define REVERSE_RENDER(regs, cp) do { \
-(regs)->go.zpattern = BMASK((~(cp)[0x0])); (regs)->go.zpattern = BMASK((~(cp)[0x1])); \
-(regs)->go.zpattern = BMASK((~(cp)[0x2])); (regs)->go.zpattern = BMASK((~(cp)[0x3])); \
-(regs)->go.zpattern = BMASK((~(cp)[0x4])); (regs)->go.zpattern = BMASK((~(cp)[0x5])); \
-(regs)->go.zpattern = BMASK((~(cp)[0x6])); (regs)->go.zpattern = BMASK((~(cp)[0x7])); \
-(regs)->go.zpattern = BMASK((~(cp)[0x8])); (regs)->go.zpattern = BMASK((~(cp)[0x9])); \
-(regs)->go.zpattern = BMASK((~(cp)[0xa])); (regs)->go.zpattern = BMASK((~(cp)[0xb])); \
-(regs)->go.zpattern = BMASK((~(cp)[0xc])); (regs)->go.zpattern = BMASK((~(cp)[0xd])); \
-(regs)->go.zpattern = BMASK((~(cp)[0xe])); (regs)->go.zpattern = BMASK((~(cp)[0xf])); \
-} while(0)        
-
-extern int default_red[16], default_grn[16], default_blu[16];
-extern unsigned char video_type;
-
-static int cursor_pos = -1;
-struct newport_regs *npregs;
-
-#define TESTVAL 0xdeadbeef
-#define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11)
-
-static inline void
-newport_disable_video(void)
-{
-	unsigned short treg;
-
-	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_EVIDEO)));
-}
-
-static inline void
-newport_enable_video(void)
-{
-	unsigned short treg;
-
-	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_EVIDEO));
-}
-
-static inline void
-newport_disable_cursor(void)
-{
-	unsigned short treg;
-
-	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg & ~(VC2_CTRL_ECDISP)));
-}
-
-#if 0
-static inline void
-newport_enable_cursor(void)
-{
-	unsigned short treg;
-
-	treg = newport_vc2_get(npregs, VC2_IREG_CONTROL);
-	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_ECDISP));
-}
-#endif
-
-static inline void
-newport_init_cmap(void)
-{
-	unsigned short i;
-
-	for(i = 0; i < 16; i++) {
-		newport_bfwait();
-		newport_cmap_setaddr(npregs, color_table[i]);
-		newport_cmap_setrgb(npregs,
-				    default_red[i],
-				    default_grn[i],
-				    default_blu[i]);
-	}
-}
-
-#if 0
-static inline void
-newport_init_cursor(void)
-{
-	unsigned char cursor[256];
-	unsigned short *cookie;
-	int i;
-
-	for(i = 0; i < 256; i++)
-		cursor[i] = 0x0;
-	for(i = 211; i < 256; i+=4) {
-		cursor[i] = 0xff;
-#if 0
-		cursor[(i + 128) << 2] = 0xff;
-		cursor[((i + 128) << 2) + 1] = 0xff;
-#endif
-	}
-
-	/* Load the SRAM on the VC2 for this new GLYPH. */
-	cookie = (unsigned short *) cursor;
-	newport_vc2_set(npregs, VC2_IREG_RADDR, VC2_CGLYPH_ADDR);
-	npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
-			       NPORT_DMODE_W2 | VC2_PROTOCOL);
-	for(i = 0; i < 128; i++) {
-		newport_bfwait();
-		npregs->set.dcbdata0.hwords.s1 = *cookie++;
-	}
-
-	/* Place the cursor at origin. */
-	newport_vc2_set(npregs, VC2_IREG_CURSX, 0);
-	newport_vc2_set(npregs, VC2_IREG_CURSY, 0);
-	newport_enable_cursor();
-}
-#endif
-
-static inline void
-newport_clear_screen(void)
-{
-	newport_wait();
-	npregs->set.wrmask = 0xffffffff;
-	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			      NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
-			      NPORT_DMODE0_STOPY);
-	npregs->set.colori = 0;
-	npregs->set.xystarti = 0;
-	npregs->go.xyendi = (((1280 + 63) << 16)|(1024));
-	newport_bfwait();
-}
-
-static inline void
-newport_render_version(void)
-{
-#if 0
-	unsigned short *ush;
-	int currcons = 0;
-	char *p;
-
-	ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20;
-	for (p = "SGI/Linux version " UTS_RELEASE; *p; p++, ush++) {
-		*ush = (attr << 8) + *p;
-		newport_blitc (*ush, (unsigned long) ush);
-	}
-#endif
-}
-
-#if 0
-static inline void
-newport_render_logo(void)
-{
-	int i, xpos, ypos;
-	unsigned char *bmap;
-
-	xpos = 8;
-	ypos = 18;
-
-	newport_wait();
-	npregs->set.colori = 9;
-	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			      NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
-			      NPORT_DMODE0_L32);
-
-	for(i = 0; i < 80; i+=8) {
-		/* Set coordinates for bitmap operation. */
-		npregs->set.xystarti = ((xpos + i) << 16) | ypos;
-		npregs->set.xyendi = (((xpos + i) + 7) << 16);
-		newport_wait();
-
-		bmap = linux_logo + (i * 80);
-		RENDER(npregs, bmap); bmap += 0x10;
-		RENDER(npregs, bmap); bmap += 0x10;
-		RENDER(npregs, bmap); bmap += 0x10;
-		RENDER(npregs, bmap); bmap += 0x10;
-		RENDER(npregs, bmap);
-	}
-	prom_getchar();
-	prom_imode();
-}
-#endif
-
-static inline void
-newport_render_background(int xpos, int ypos, int ci)
-{
-	newport_wait();
-	npregs->set.wrmask = 0xffffffff;
-	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			      NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
-			      NPORT_DMODE0_STOPY);
-	npregs->set.colori = ci;
-	npregs->set.xystarti = (xpos << 16) | ypos;
-	npregs->go.xyendi = ((xpos + 7) << 16) | (ypos + 15);
-}
-
-void
-newport_set_origin(unsigned short offset)
-{
-	/* maybe this works... */
-	__origin = offset;
-}
-
-void
-newport_hide_cursor(void)
-{
-	int xpos, ypos, idx;
-	unsigned long flags;
-
-	if(vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
-		return;
-	save_and_cli(flags);
-
-	idx = cursor_pos;
-	if(idx == -1) {
-		restore_flags(flags);
-		return;
-	}
-	xpos = 8 + ((idx % video_num_columns) << 3);
-	ypos = 18 + ((idx / video_num_columns) << 4);
-	newport_render_background(xpos, ypos, 0);
-	restore_flags(flags);
-}
-
-void
-newport_set_cursor(int currcons)
-{
-	int xpos, ypos, idx, oldpos;
-	unsigned short *sp, *osp, cattr;
-	unsigned long flags;
-	unsigned char *p;
-
-	if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
-		return;
-
-	if (__real_origin != __origin)
-		__set_origin(__real_origin);
-
-	save_and_cli(flags);
-
-	idx = (pos - video_mem_base) >> 1;
-	sp = (unsigned short *) pos;
-	oldpos = cursor_pos;
-	cursor_pos = idx;
-	if(!deccm) {
-		hide_cursor();
-		restore_flags(flags);
-		return;
-	}
-	xpos = 8 + ((idx % video_num_columns) << 3);
-	ypos = 18 + ((idx / video_num_columns) << 4);
-	if(oldpos != -1) {
-		int oxpos, oypos;
-
-		/* Restore old location. */
-		osp = (unsigned short *) ((oldpos << 1) + video_mem_base);
-		oxpos = 8 + ((oldpos % video_num_columns) << 3);
-		oypos = 18 + ((oldpos / video_num_columns) << 4);
-		cattr = *osp;
-		newport_render_background(oxpos, oypos, (cattr & 0xf000) >> 12);
-		p = &vga_font[(cattr & 0xff) << 4];
-		newport_wait();
-		npregs->set.colori = (cattr & 0x0f00) >> 8;
-		npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-				      NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
-				      NPORT_DMODE0_L32);
-		npregs->set.xystarti = (oxpos << 16) | oypos;
-		npregs->set.xyendi = ((oxpos + 7) << 16);
-		newport_wait();
-		RENDER(npregs, p);
-	}
-	cattr = *sp;
-	newport_render_background(xpos, ypos, (cattr & 0xf000) >> 12);
-	p = &vga_font[(cattr & 0xff) << 4];
-	newport_wait();
-	npregs->set.colori = (cattr & 0x0f00) >> 8;
-	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			      NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
-			      NPORT_DMODE0_L32);
-	npregs->set.xystarti = (xpos << 16) | ypos;
-	npregs->set.xyendi = ((xpos + 7) << 16);
-	newport_wait();
-	REVERSE_RENDER(npregs, p);
-	restore_flags (flags);
-	return;
-}
-
-void
-newport_get_scrmem(int currcons)
-{
-	memcpyw((unsigned short *)vc_scrbuf[currcons],
-		(unsigned short *)origin, video_screen_size);
-	origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
-	scr_end = video_mem_end = video_mem_start + video_screen_size;
-	pos = origin + y*video_size_row + (x<<1);
-}
-
-void
-newport_set_scrmem(int currcons, long offset)
-{
-	if (video_mem_term - video_mem_base < offset + video_screen_size)
-		offset = 0;
-	memcpyw((unsigned short *)(video_mem_base + offset),
-		(unsigned short *) origin, video_screen_size);
-	video_mem_start = video_mem_base;
-	video_mem_end = video_mem_term;
-	origin = video_mem_base + offset;
-	scr_end = origin + video_screen_size;
-	pos = origin + y*video_size_row + (x<<1);
-	has_wrapped = 0;
-}
-
-int
-newport_set_get_cmap(unsigned char * arg, int set)
-{
-	unsigned short ent;
-	int i;
-
-	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
-	if (i)
-		return i;
-
-	for (i=0; i<16; i++) {
-		if (set) {
-			__get_user(default_red[i], arg++);
-			__get_user(default_grn[i], arg++);
-			__get_user(default_blu[i], arg++);
-		} else {
-			__put_user (default_red[i], arg++);
-			__put_user (default_grn[i], arg++);
-			__put_user (default_blu[i], arg++);
-		}
-	}
-	if (set) {
-		for (i=0; i<MAX_NR_CONSOLES; i++) {
-			if (vc_cons_allocated(i)) {
-				int j, k;
-				for (j = k = 0; j<16; j++) {
-					vc_cons[i].d->vc_palette[k++] =
-						default_red[j];
-					vc_cons[i].d->vc_palette[k++] =
-						default_grn[j];
-					vc_cons[i].d->vc_palette[k++] =
-						default_blu[j];
-				}
-			}
-		}
-		if(console_blanked || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
-			return 0;
-		for(ent = 0; ent < 16; ent++) {
-			newport_bfwait();
-			newport_cmap_setaddr(npregs, ent);
-			newport_cmap_setrgb(npregs,
-					    default_red[ent],
-					    default_grn[ent],
-					    default_blu[ent]);
-		}
-	}
-
-	return 0;
-}
-
-void
-newport_blitc(unsigned short charattr, unsigned long addr)
-{
-	int idx, xpos, ypos;
-	unsigned char *p;
-
-	idx = (addr - (video_mem_base + (__origin<<1))) >> 1;
-	xpos = 8 + ((idx % video_num_columns) << 3);
-	ypos = 18 + ((idx / video_num_columns) << 4);
-
-	p = &vga_font[(charattr & 0xff) << 4];
-	charattr = (charattr >> 8) & 0xff;
-
-	newport_render_background(xpos, ypos, (charattr & 0xf0) >> 4);
-
-	/* Set the color and drawing mode. */
-	newport_wait();
-	npregs->set.colori = charattr & 0xf;
-	npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
-			      NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
-			      NPORT_DMODE0_L32);
-
-	/* Set coordinates for bitmap operation. */
-	npregs->set.xystarti = (xpos << 16) | ypos;
-	npregs->set.xyendi = ((xpos + 7) << 16);
-	newport_wait();
-
-	/* Go, baby, go... */
-	RENDER(npregs, p);
-}
-
-void
-newport_memsetw(void * s, unsigned short c, unsigned int count)
-{
-	unsigned short * addr = (unsigned short *) s;
-
-	count /= 2;
-	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
-		while (count) {
-			count--;
-			*addr++ = c;
-		}
-		return;
-	}
-	if ((unsigned long) addr + count > video_mem_term ||
-	    (unsigned long) addr < video_mem_base) {
-	    	if ((unsigned long) addr + count <= video_mem_term ||
-	    	    (unsigned long) addr > video_mem_base) {
-			while (count) {
-				count--;
-				*addr++ = c;
-			}
-			return;
-	    	} else {
-			while (count) {
-				count--;
-				scr_writew(c, addr++);
-			}
-		}
-	} else {
-		while (count) {
-			count--;
-			if (*addr != c) {
-				newport_blitc(c, (unsigned long)addr);
-				*addr++ = c;
-			} else
-				addr++;
-		}
-	}
-}
-
-void
-newport_memcpyw(unsigned short *to, unsigned short *from, unsigned int count)
-{
-	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
-		memcpy(to, from, count);
-		return;
-	}
-	if ((unsigned long) to + count > video_mem_term ||
-	    (unsigned long) to < video_mem_base) {
-	    	if ((unsigned long) to + count <= video_mem_term ||
-	    	    (unsigned long) to > video_mem_base)
-	    	    	memcpy(to, from, count);
-	    	else {
-	    		count /= 2;
-			while (count) {
-				count--;
-				scr_writew(scr_readw(from++), to++);
-			}
-		}
-	} else {
-		count /= 2;
-		while (count) {
-			count--;
-			if (*to != *from) {
-				newport_blitc(*from, (unsigned long)to);
-				*to++ = *from++;
-			} else {
-				from++;
-				to++;
-			}
-		}
-	}
-}
-
-struct console_ops newport_console = {
-	newport_set_origin,
-	newport_hide_cursor,
-	newport_set_cursor,
-	newport_get_scrmem,
-	newport_set_scrmem,
-	newport_set_get_cmap,
-	newport_blitc,
-	newport_memsetw,
-	newport_memcpyw
-};
-
-/* Currently hard-coded values that are the same as those found on my system */
-struct ng1_info newport_board_info = {
-	{ "NG1", "" /* what is the label? */, 1280, 1024, sizeof (struct ng1_info) },
-	6,			/* boardrev */
-	1,			/* rex3rev */
-	0,			/* vc2rev */
-	2,			/* monitor type */
-        0,			/* videoinstalled */
-	3,			/* mcrev */
-	24,			/* bitplanes */
-	0,			/* xmap9rev */
-	2,			/* cmaprev */
-	{ 256, 1280, 1024, 76},	/* ng1_vof_info */
-	13,			/* paneltype */
-	0
-};
-
-void
-newport_reset (void)
-{
-	newport_wait();
-	newport_enable_video();
-
-	/* Init the cursor disappear. */
-	newport_wait();
-#if 0
-	newport_init_cursor();
-#else
-	newport_disable_cursor();
-#endif
-
-	newport_init_cmap();
-
-	/* Clear the screen. */
-	newport_clear_screen();
-}
-
-/* right now the newport does not do anything at all */
-struct graphics_ops newport_graphic_ops = {
-	0,			      /* owner */
-	0,			      /* current user */
-	(void *) &newport_board_info, /* board info */
-	sizeof (struct ng1_info),     /* size of our data structure */
-	0, 0,			      /* g_regs, g_regs_size */
-	newport_save, newport_restore, /* g_save_context, g_restore_context */
-	newport_reset, newport_ioctl /* g_reset_console, g_ioctl */
-};
-
-struct graphics_ops *
-newport_probe (int slot, const char **name)
-{
-	struct newport_regs *p;
-
-	npregs = (struct newport_regs *) (KSEG1 + 0x1f0f0000);
-	
-	p = npregs;
-	p->cset.config = NPORT_CFG_GD0;
-
-	if(newport_wait()) {
-		prom_printf("whoops, timeout, no NEWPORT there?");
-		return 0;
-	}
-
-	p->set.xstarti = TESTVAL; if(p->set._xstart.i != XSTI_TO_FXSTART(TESTVAL)) {
-		prom_printf("newport_probe: read back wrong value ;-(\n");
-		return 0;
-	}
-
-	if (slot == 0){
-		register_gconsole (&newport_console);
-		video_type = VIDEO_TYPE_SGI;
-		can_do_color = 1;
-		*name = "NEWPORT";
-	}
-
-	newport_reset ();
-	newport_render_version();
-#if 0
-	newport_render_logo();
-#endif
-	newport_graphic_ops.g_regs = 0x1f0f0000;
-	newport_graphic_ops.g_regs_size = sizeof (struct newport_regs);
-	return &newport_graphic_ops;
-}
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/ds1286.c linux/drivers/sgi/char/ds1286.c
--- v2.3.8/linux/drivers/sgi/char/ds1286.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/ds1286.c	Fri Jun 25 17:39:34 1999
@@ -0,0 +1,568 @@
+/* $Id: ds1286.c,v 1.4 1999/06/17 13:29:03 ralf Exp $
+ *
+ *	Real Time Clock interface for Linux	
+ *
+ *	Copyright (C) 1998, 1999 Ralf Baechle
+ *	
+ *	Based on code written by Paul Gortmaker.
+ *
+ *	This driver allows use of the real time clock (built into
+ *	nearly all computers) from user space. It exports the /dev/rtc
+ *	interface supporting various ioctl() and also the /proc/rtc
+ *	pseudo-file for status information.
+ *
+ *	The ioctls can be used to set the interrupt behaviour and
+ *	generation rate from the RTC via IRQ 8. Then the /dev/rtc
+ *	interface can be used to make use of these timer interrupts,
+ *	be they interval or alarm based.
+ *
+ *	The /dev/rtc interface will block on reads until an interrupt
+ *	has been received. If a RTC interrupt has already happened,
+ *	it will output an unsigned long and then block. The output value
+ *	contains the interrupt status in the low byte and the number of
+ *	interrupts since the last read in the remaining high bytes. The 
+ *	/dev/rtc interface can also be used with the select(2) call.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/rtc.h>
+
+#include <asm/ds1286.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+#include <asm/system.h>
+
+#define DS1286_VERSION		"1.0"
+
+/*
+ *	We sponge a minor off of the misc major. No need slurping
+ *	up another valuable major dev number for this. If you add
+ *	an ioctl, make sure you don't conflict with SPARC's RTC
+ *	ioctls.
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(ds1286_wait);
+
+static long long ds1286_llseek(struct file *file, loff_t offset, int origin);
+
+static ssize_t ds1286_read(struct file *file, char *buf,
+			size_t count, loff_t *ppos);
+
+static int ds1286_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg);
+
+static unsigned int ds1286_poll(struct file *file, poll_table *wait);
+
+void get_rtc_time (struct rtc_time *rtc_tm);
+void get_rtc_alm_time (struct rtc_time *alm_tm);
+
+void set_rtc_irq_bit(unsigned char bit);
+void clear_rtc_irq_bit(unsigned char bit);
+
+static inline unsigned char ds1286_is_updating(void);
+
+#ifdef __SMP__
+static spinlock_t ds1286_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+/*
+ *	Bits in rtc_status. (7 bits of room for future expansion)
+ */
+
+#define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
+#define RTC_TIMER_ON		0x02	/* missed irq timer active	*/
+
+unsigned char ds1286_status = 0;	/* bitmapped status byte.	*/
+unsigned long ds1286_freq = 0;		/* Current periodic IRQ rate	*/
+unsigned long ds1286_irq_data = 0;	/* our output to the world	*/
+
+unsigned char days_in_mo[] = 
+{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/*
+ *	A very tiny interrupt handler. It runs with SA_INTERRUPT set,
+ *	so that there is no possibility of conflicting with the
+ *	set_rtc_mmss() call that happens during some timer interrupts.
+ *	(See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
+ */
+
+/*
+ *	Now all the various file operations that we export.
+ */
+
+static long long ds1286_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static ssize_t ds1286_read(struct file *file, char *buf,
+                           size_t count, loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long data;
+	ssize_t retval;
+	
+	if (count < sizeof(unsigned long))
+		return -EINVAL;
+
+	add_wait_queue(&ds1286_wait, &wait);
+
+	current->state = TASK_INTERRUPTIBLE;
+		
+	while ((data = xchg(&ds1286_irq_data, 0)) == 0) {
+		if (file->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto out;
+		}
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			goto out;
+		}
+		schedule();
+	}
+
+	retval = put_user(data, (unsigned long *)buf); 
+	if (!retval)
+		retval = sizeof(unsigned long); 
+ out:
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&ds1286_wait, &wait);
+
+	return retval;
+}
+
+static int ds1286_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+
+	struct rtc_time wtime; 
+
+	switch (cmd) {
+	case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/
+	{
+		unsigned int flags;
+		unsigned char val;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		spin_lock_irqsave(&ds1286_lock, flags);
+		val = CMOS_READ(RTC_CMD);
+		val |=  RTC_TDM;
+		CMOS_WRITE(val, RTC_CMD);
+		spin_unlock_irqrestore(&ds1286_lock, flags);
+
+		return 0;
+	}
+	case RTC_AIE_ON:	/* Allow alarm interrupts.	*/
+	{
+		unsigned int flags;
+		unsigned char val;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		spin_lock_irqsave(&ds1286_lock, flags);
+		val = CMOS_READ(RTC_CMD);
+		val &=  ~RTC_TDM;
+		CMOS_WRITE(val, RTC_CMD);
+		spin_unlock_irqrestore(&ds1286_lock, flags);
+
+		return 0;
+	}
+	case RTC_WIE_OFF:	/* Mask watchdog int. enab. bit	*/
+	{
+		unsigned int flags;
+		unsigned char val;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		spin_lock_irqsave(&ds1286_lock, flags);
+		val = CMOS_READ(RTC_CMD);
+		val |= RTC_WAM;
+		CMOS_WRITE(val, RTC_CMD);
+		spin_unlock_irqrestore(&ds1286_lock, flags);
+
+		return 0;
+	}
+	case RTC_WIE_ON:	/* Allow watchdog interrupts.	*/
+	{
+		unsigned int flags;
+		unsigned char val;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		spin_lock_irqsave(&ds1286_lock, flags);
+		val = CMOS_READ(RTC_CMD);
+		val &= ~RTC_WAM;
+		CMOS_WRITE(val, RTC_CMD);
+		spin_unlock_irqrestore(&ds1286_lock, flags);
+
+		return 0;
+	}
+	case RTC_ALM_READ:	/* Read the present alarm time */
+	{
+		/*
+		 * This returns a struct rtc_time. Reading >= 0xc0
+		 * means "don't care" or "match all". Only the tm_hour,
+		 * tm_min, and tm_sec values are filled in.
+		 */
+
+		get_rtc_alm_time(&wtime);
+		break; 
+	}
+	case RTC_ALM_SET:	/* Store a time into the alarm */
+	{
+		/*
+		 * This expects a struct rtc_time. Writing 0xff means
+		 * "don't care" or "match all". Only the tm_hour,
+		 * tm_min and tm_sec are used.
+		 */
+		unsigned char hrs, min, sec;
+		struct rtc_time alm_tm;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&alm_tm, (struct rtc_time*)arg,
+				   sizeof(struct rtc_time)))
+			return -EFAULT;
+
+		hrs = alm_tm.tm_hour;
+		min = alm_tm.tm_min;
+
+		if (hrs >= 24)
+			hrs = 0xff;
+
+		if (min >= 60)
+			min = 0xff;
+
+		BIN_TO_BCD(sec);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(hrs);
+
+		spin_lock(&ds1286_lock);
+		CMOS_WRITE(hrs, RTC_HOURS_ALARM);
+		CMOS_WRITE(min, RTC_MINUTES_ALARM);
+		spin_unlock(&ds1286_lock);
+
+		return 0;
+	}
+	case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+	{
+		get_rtc_time(&wtime);
+		break;
+	}
+	case RTC_SET_TIME:	/* Set the RTC */
+	{
+		struct rtc_time rtc_tm;
+		unsigned char mon, day, hrs, min, sec, leap_yr;
+		unsigned char save_control;
+		unsigned int yrs, flags;
+
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
+				   sizeof(struct rtc_time)))
+			return -EFAULT;
+
+		yrs = rtc_tm.tm_year + 1900;
+		mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
+		day = rtc_tm.tm_mday;
+		hrs = rtc_tm.tm_hour;
+		min = rtc_tm.tm_min;
+		sec = rtc_tm.tm_sec;
+
+		if (yrs < 1970)
+			return -EINVAL;
+
+		leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
+
+		if ((mon > 12) || (day == 0))
+			return -EINVAL;
+
+		if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
+			return -EINVAL;
+
+		if ((hrs >= 24) || (min >= 60) || (sec >= 60))
+			return -EINVAL;
+
+		if ((yrs -= 1940) > 255)    /* They are unsigned */
+			return -EINVAL;
+
+		if (yrs >= 100)
+			yrs -= 100;
+
+		BIN_TO_BCD(sec);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(hrs);
+		BIN_TO_BCD(day);
+		BIN_TO_BCD(mon);
+		BIN_TO_BCD(yrs);
+
+		spin_lock_irqsave(&ds1286_lock, flags);
+		save_control = CMOS_READ(RTC_CMD);
+		CMOS_WRITE((save_control|RTC_TE), RTC_CMD);
+
+		CMOS_WRITE(yrs, RTC_YEAR);
+		CMOS_WRITE(mon, RTC_MONTH);
+		CMOS_WRITE(day, RTC_DATE);
+		CMOS_WRITE(hrs, RTC_HOURS);
+		CMOS_WRITE(min, RTC_MINUTES);
+		CMOS_WRITE(sec, RTC_SECONDS);
+		CMOS_WRITE(0, RTC_HUNDREDTH_SECOND);
+
+		CMOS_WRITE(save_control, RTC_CMD);
+		spin_unlock_irqrestore(&ds1286_lock, flags);
+
+		return 0;
+	}
+	default:
+		return -EINVAL;
+	}
+	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
+}
+
+/*
+ *	We enforce only one user at a time here with the open/close.
+ *	Also clear the previous interrupt data on an open, and clean
+ *	up things on a close.
+ */
+
+static int ds1286_open(struct inode *inode, struct file *file)
+{
+	if(ds1286_status & RTC_IS_OPEN)
+		return -EBUSY;
+
+	ds1286_status |= RTC_IS_OPEN;
+	ds1286_irq_data = 0;
+	return 0;
+}
+
+static int ds1286_release(struct inode *inode, struct file *file)
+{
+	ds1286_status &= ~RTC_IS_OPEN;
+	return 0;
+}
+
+static unsigned int ds1286_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &ds1286_wait, wait);
+	if (ds1286_irq_data != 0)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations ds1286_fops = {
+	ds1286_llseek,
+	ds1286_read,
+	NULL,		/* No write */
+	NULL,		/* No readdir */
+	ds1286_poll,
+	ds1286_ioctl,
+	NULL,		/* No mmap */
+	ds1286_open,
+	NULL,
+	ds1286_release
+};
+
+static struct miscdevice ds1286_dev=
+{
+	RTC_MINOR,
+	"rtc",
+	&ds1286_fops
+};
+
+__initfunc(int ds1286_init(void))
+{
+	printk(KERN_INFO "DS1286 Real Time Clock Driver v%s\n", DS1286_VERSION);
+	misc_register(&ds1286_dev);
+
+	return 0;
+}
+
+static char *days[] = {
+	"***", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+/*
+ *	Info exported via "/proc/rtc".
+ */
+int get_ds1286_status(char *buf)
+{
+	char *p, *s;
+	struct rtc_time tm;
+	unsigned char hundredth, month, cmd, amode;
+
+	p = buf;
+
+	get_rtc_time(&tm);
+	hundredth = CMOS_READ(RTC_HUNDREDTH_SECOND);
+	hundredth = BCD_TO_BIN(hundredth);
+
+	p += sprintf(p,
+	             "rtc_time\t: %02d:%02d:%02d.%02d\n"
+	             "rtc_date\t: %04d-%02d-%02d\n",
+		     tm.tm_hour, tm.tm_min, tm.tm_sec, hundredth,
+		     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+
+	/*
+	 * We implicitly assume 24hr mode here. Alarm values >= 0xc0 will
+	 * match any value for that particular field. Values that are
+	 * greater than a valid time, but less than 0xc0 shouldn't appear.
+	 */
+	get_rtc_alm_time(&tm);
+	p += sprintf(p, "alarm\t\t: %s ", days[tm.tm_wday]);
+	if (tm.tm_hour <= 24)
+		p += sprintf(p, "%02d:", tm.tm_hour);
+	else
+		p += sprintf(p, "**:");
+
+	if (tm.tm_min <= 59)
+		p += sprintf(p, "%02d\n", tm.tm_min);
+	else
+		p += sprintf(p, "**\n");
+
+	month = CMOS_READ(RTC_MONTH);
+	p += sprintf(p,
+	             "oscillator\t: %s\n"
+	             "square_wave\t: %s\n",
+	             (month & RTC_EOSC) ? "disabled" : "enabled",
+	             (month & RTC_ESQW) ? "disabled" : "enabled");
+
+	amode = ((CMOS_READ(RTC_MINUTES_ALARM) & 0x80) >> 5) |
+	        ((CMOS_READ(RTC_HOURS_ALARM) & 0x80) >> 6) |
+	        ((CMOS_READ(RTC_DAY_ALARM) & 0x80) >> 7);
+	if (amode == 7)      s = "each minute";
+	else if (amode == 3) s = "minutes match";
+	else if (amode == 1) s = "hours and minutes match";
+	else if (amode == 0) s = "days, hours and minutes match";
+	else                 s = "invalid";
+	p += sprintf(p, "alarm_mode\t: %s\n", s);
+
+	cmd = CMOS_READ(RTC_CMD);
+	p += sprintf(p,
+	             "alarm_enable\t: %s\n"
+	             "wdog_alarm\t: %s\n"
+	             "alarm_mask\t: %s\n"
+	             "wdog_alarm_mask\t: %s\n"
+	             "interrupt_mode\t: %s\n"
+	             "INTB_mode\t: %s_active\n"
+	             "interrupt_pins\t: %s\n",
+		     (cmd & RTC_TDF) ? "yes" : "no",
+		     (cmd & RTC_WAF) ? "yes" : "no",
+		     (cmd & RTC_TDM) ? "disabled" : "enabled",
+		     (cmd & RTC_WAM) ? "disabled" : "enabled",
+		     (cmd & RTC_PU_LVL) ? "pulse" : "level",
+		     (cmd & RTC_IBH_LO) ? "low" : "high",
+	             (cmd & RTC_IPSW) ? "unswapped" : "swapped");
+
+	return  p - buf;
+}
+
+/*
+ * Returns true if a clock update is in progress
+ */
+static inline unsigned char ds1286_is_updating(void)
+{
+	return CMOS_READ(RTC_CMD) & RTC_TE;
+}
+
+void get_rtc_time(struct rtc_time *rtc_tm)
+{
+	unsigned long uip_watchdog = jiffies;
+	unsigned char save_control;
+	unsigned int flags;
+
+	/*
+	 * read RTC once any update in progress is done. The update
+	 * can take just over 2ms. We wait 10 to 20ms. There is no need to
+	 * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
+	 * If you need to know *exactly* when a second has started, enable
+	 * periodic update complete interrupts, (via ioctl) and then 
+	 * immediately read /dev/rtc which will block until you get the IRQ.
+	 * Once the read clears, read the RTC time (again via ioctl). Easy.
+	 */
+
+	if (ds1286_is_updating() != 0)
+		while (jiffies - uip_watchdog < 2*HZ/100)
+			barrier();
+
+	/*
+	 * Only the values that we read from the RTC are set. We leave
+	 * tm_wday, tm_yday and tm_isdst untouched. Even though the
+	 * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+	 * by the RTC when initially set to a non-zero value.
+	 */
+	spin_lock_irqsave(&ds1286_lock, flags);
+	save_control = CMOS_READ(RTC_CMD);
+	CMOS_WRITE((save_control|RTC_TE), RTC_CMD);
+
+	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS) & 0x1f;
+	rtc_tm->tm_mday = CMOS_READ(RTC_DATE);
+	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH) & 0x1f;
+	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+
+	CMOS_WRITE(save_control, RTC_CMD);
+	spin_unlock_irqrestore(&ds1286_lock, flags);
+
+	BCD_TO_BIN(rtc_tm->tm_sec);
+	BCD_TO_BIN(rtc_tm->tm_min);
+	BCD_TO_BIN(rtc_tm->tm_hour);
+	BCD_TO_BIN(rtc_tm->tm_mday);
+	BCD_TO_BIN(rtc_tm->tm_mon);
+	BCD_TO_BIN(rtc_tm->tm_year);
+
+	/*
+	 * Account for differences between how the RTC uses the values
+	 * and how they are defined in a struct rtc_time;
+	 */
+	if (rtc_tm->tm_year < 45)
+		rtc_tm->tm_year += 30;
+	if ((rtc_tm->tm_year += 40) < 70)
+		rtc_tm->tm_year += 100;
+
+	rtc_tm->tm_mon--;
+}
+
+void get_rtc_alm_time(struct rtc_time *alm_tm)
+{
+	unsigned char cmd;
+	unsigned int flags;
+
+	/*
+	 * Only the values that we read from the RTC are set. That
+	 * means only tm_wday, tm_hour, tm_min.
+	 */
+	spin_lock_irqsave(&ds1286_lock, flags);
+	alm_tm->tm_min = CMOS_READ(RTC_MINUTES_ALARM) & 0x7f;
+	alm_tm->tm_hour = CMOS_READ(RTC_HOURS_ALARM)  & 0x1f;
+	alm_tm->tm_wday = CMOS_READ(RTC_DAY_ALARM)    & 0x07;
+	cmd = CMOS_READ(RTC_CMD);
+	spin_unlock_irqrestore(&ds1286_lock, flags);
+
+	BCD_TO_BIN(alm_tm->tm_min);
+	BCD_TO_BIN(alm_tm->tm_hour);
+	alm_tm->tm_sec = 0;
+}
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c
--- v2.3.8/linux/drivers/sgi/char/graphics.c	Mon Aug 24 13:02:44 1998
+++ linux/drivers/sgi/char/graphics.c	Fri Jun 25 17:39:34 1999
@@ -1,7 +1,10 @@
-/*
+/* $Id: graphics.c,v 1.16 1999/04/01 23:45:00 ulfc Exp $
+ *
  * gfx.c: support for SGI's /dev/graphics, /dev/opengl
  *
  * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *         Ralf Baechle (ralf@gnu.org)
+ *         Ulf Carlsson (ulfc@bun.falkenberg.se)
  *
  * On IRIX, /dev/graphics is [10, 146]
  *          /dev/opengl   is [10, 147]
@@ -21,35 +24,56 @@
  * We implement those misterious things, and tried not to think about
  * the reasons behind them.
  */
+#include <linux/kernel.h>
 #include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/malloc.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
 #include "gconsole.h"
 #include "graphics.h"
+#include "usema.h"
 #include <asm/gfx.h>
 #include <asm/rrm.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/newport.h>
 
-/* The boards */
-#include "newport.h"
+#define DEBUG
 
-#ifdef PRODUCTION_DRIVER
-#define enable_gconsole()
-#define disable_gconsole()
-#endif
+/* The boards */
+extern struct graphics_ops *newport_probe (int, const char **);
 
 static struct graphics_ops cards [MAXCARDS];
 static int boards;
 
 #define GRAPHICS_CARD(inode) 0
 
+/*
+void enable_gconsole(void) {};
+void disable_gconsole(void) {};
+*/
+
+
 int
 sgi_graphics_open (struct inode *inode, struct file *file)
 {
+	struct newport_regs *nregs =
+		(struct newport_regs *) KSEG1ADDR(cards[0].g_regs);
+
+	newport_wait();
+	nregs->set.wrmask = 0xffffffff;
+	nregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+			     NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
+			     NPORT_DMODE0_STOPY);
+	nregs->set.colori = 1;
+	nregs->set.xystarti = (0 << 16) | 0;
+	nregs->go.xyendi = (1280 << 16) | 1024;
+
 	return 0;
 }
 
@@ -59,10 +83,10 @@
 	unsigned int board;
 	unsigned int devnum = GRAPHICS_CARD (inode->i_rdev);
 	int i;
-	
+
 	if ((cmd >= RRM_BASE) && (cmd <= RRM_CMD_LIMIT))
 		return rrm_command (cmd-RRM_BASE, (void *) arg);
-	
+
 	switch (cmd){
 	case GFX_GETNUM_BOARDS:
 		return boards;
@@ -113,7 +137,7 @@
 			printk ("Parameter board does not match the current board\n");
 			return -EINVAL;
 		}
-		
+
 		if (board >= boards)
 			return -EINVAL;
 
@@ -126,11 +150,11 @@
 		 * sgi_graphics_mmap
 		 */
 		disable_gconsole ();
-		r = do_mmap (file, (unsigned long)vaddr, cards [board].g_regs_size,
-			 PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0);
+		r = do_mmap (file, (unsigned long)vaddr,
+			     cards[board].g_regs_size, PROT_READ|PROT_WRITE,
+			     MAP_FIXED|MAP_PRIVATE, 0);
 		if (r)
 			return r;
-
 	}
 
 	/* Strange, the real mapping seems to be done at GFX_ATTACH_BOARD,
@@ -141,13 +165,13 @@
 
 	case GFX_LABEL:
 		return 0;
-			
+
 		/* Version check
 		 * for my IRIX 6.2 X server, this is what the kernel returns
 		 */
 	case 1:
 		return 3;
-		
+
 	/* Xsgi does not use this one, I assume minor is the board being queried */
 	case GFX_IS_MANAGED:
 		if (devnum > boards)
@@ -166,14 +190,15 @@
 sgi_graphics_close (struct inode *inode, struct file *file)
 {
 	int board = GRAPHICS_CARD (inode->i_rdev);
-	
+
 	/* Tell the rendering manager that one client is going away */
 	rrm_close (inode, file);
 
 	/* Was this file handle from the board owner?, clear it */
 	if (current == cards [board].g_owner){
 		cards [board].g_owner = 0;
-		(*cards [board].g_reset_console)();
+		if (cards [board].g_reset_console)
+			(*cards [board].g_reset_console)();
 		enable_gconsole ();
 	}
 	return 0;
@@ -184,37 +209,42 @@
  */
 
 unsigned long
-sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int write_access)
+sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int
+		     no_share)
 {
-	unsigned long page;
+	pgd_t *pgd; pmd_t *pmd; pte_t *pte; 
 	int board = GRAPHICS_CARD (vma->vm_dentry->d_inode->i_rdev);
 
-#ifdef DEBUG_GRAPHICS
-	printk ("Got a page fault for board %d address=%lx guser=%lx\n", board, address,
-		cards [board].g_user);
+	unsigned long virt_add, phys_add;
+
+#ifdef DEBUG
+	printk ("Got a page fault for board %d address=%lx guser=%lx\n", board,
+		address, (unsigned long) cards[board].g_user);
 #endif
 	
-	/* 1. figure out if another process has this mapped,
-	 * and revoke the mapping in that case.
-	 */
-	if (cards [board].g_user && cards [board].g_user != current){
-		/* FIXME: save graphics context here, dump it to rendering node? */
-		remove_mapping (cards [board].g_user, vma->vm_start, vma->vm_end);
+	/* Figure out if another process has this mapped, and revoke the mapping
+	 * in that case. */
+	if (cards[board].g_user && cards[board].g_user != current) {
+		/* FIXME: save graphics context here, dump it to rendering
+		 * node? */
+
+		remove_mapping(cards[board].g_user, vma->vm_start, vma->vm_end);
 	}
+
 	cards [board].g_user = current;
-#if DEBUG_GRAPHICS
-	printk ("Registers: 0x%lx\n", cards [board].g_regs);
-	printk ("vm_start:  0x%lx\n", vma->vm_start);
-	printk ("address:   0x%lx\n", address);
-	printk ("diff:      0x%lx\n", (address - vma->vm_start));
 
-	printk ("page/pfn:  0x%lx\n", page);
-	printk ("TLB entry: %lx\n", pte_val (mk_pte (page + PAGE_OFFSET, PAGE_USERIO)));
-#endif
-	
-	/* 2. Map this into the current process address space */
-	page = ((cards [board].g_regs) + (address - vma->vm_start));
-	return page + PAGE_OFFSET;
+	/* Map the physical address of the newport registers into the address
+	 * space of this process */
+
+	virt_add = address & PAGE_MASK;
+	phys_add = cards[board].g_regs + virt_add - vma->vm_start;
+	remap_page_range(virt_add, phys_add, PAGE_SIZE, vma->vm_page_prot);
+
+	pgd = pgd_offset(current->mm, address);
+	pmd = pmd_offset(pgd, address);
+	pte = pte_offset(pmd, address);
+	printk("page: %08lx\n", pte_page(*pte));
+	return pte_page(*pte);
 }
 
 /*
@@ -237,7 +267,7 @@
 };
 	
 int
-sgi_graphics_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+sgi_graphics_mmap (struct file *file, struct vm_area_struct *vma)
 {
 	uint size;
 
@@ -250,12 +280,13 @@
 
 	/* 2. Set the special tlb permission bits */
 	vma->vm_page_prot = PAGE_USERIO;
-		
+
 	/* final setup */
-	vma->vm_dentry = dget (file->f_dentry);
+	vma->vm_file = file;
 	return 0;
 }
-	
+
+#if 0
 /* Do any post card-detection setup on graphics_ops */
 static void
 graphics_ops_post_init (int slot)
@@ -264,6 +295,7 @@
 	cards [slot].g_owner = (struct task_struct *) 0;
 	cards [slot].g_user  = (struct task_struct *) 0;
 }
+#endif
 
 struct file_operations sgi_graphics_fops = {
 	NULL,			/* llseek */
@@ -284,33 +316,36 @@
 
 /* /dev/graphics */
 static struct miscdevice dev_graphics = {
-        SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops
+	SGI_GRAPHICS_MINOR, "sgi-graphics", &sgi_graphics_fops
 };
 
 /* /dev/opengl */
 static struct miscdevice dev_opengl = {
-        SGI_OPENGL_MINOR, "sgi-opengl", &sgi_graphics_fops
+	SGI_OPENGL_MINOR, "sgi-opengl", &sgi_graphics_fops
 };
 
 /* This is called later from the misc-init routine */
-void
-gfx_register (void)
+__initfunc(void gfx_register (void))
 {
 	misc_register (&dev_graphics);
 	misc_register (&dev_opengl);
 }
 
-void 
-gfx_init (const char **name)
+__initfunc(void gfx_init (const char **name))
 {
+#if 0
 	struct console_ops *console;
 	struct graphics_ops *g;
+#endif
 
 	printk ("GFX INIT: ");
 	shmiq_init ();
 	usema_init ();
-	
-	if ((g = newport_probe (boards, name)) != 0){
+
+	boards++;
+
+#if 0
+	if ((g = newport_probe (boards, name)) != 0) {
 		cards [boards] = *g;
 		graphics_ops_post_init (boards);
 		boards++;
@@ -318,11 +353,39 @@
 	}
 	/* Add more graphic drivers here */
 	/* Keep passing console around */
-	
-	if (boards > MAXCARDS){
-		printk ("Too many cards found on the system\n");
-		prom_halt ();
+#endif
+
+	if (boards > MAXCARDS)
+		printk (KERN_WARNING "Too many cards found on the system\n");
+}
+
+#ifdef MODULE
+int init_module(void) {
+	static int initiated = 0;
+
+	printk("SGI Newport Graphics version %i.%i.%i\n",42,54,69);
+
+	if (!initiated++) {
+		shmiq_init();
+		usema_init();
+		printk("Adding first board\n");
+		boards++;
+		cards[0].g_regs = 0x1f0f0000;
+		cards[0].g_regs_size = sizeof (struct newport_regs);
 	}
+
+	printk("Boards: %d\n", boards);
+
+	misc_register (&dev_graphics);
+	misc_register (&dev_opengl);
+
+	return 0;
 }
 
+void cleanup_module(void) {
+	printk("Shutting down SGI Newport Graphics\n");
 
+	misc_deregister (&dev_graphics);
+	misc_deregister (&dev_opengl);
+}
+#endif
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/graphics.h linux/drivers/sgi/char/graphics.h
--- v2.3.8/linux/drivers/sgi/char/graphics.h	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/char/graphics.h	Fri Jun 25 17:39:34 1999
@@ -25,4 +25,3 @@
 
 void shmiq_init (void);
 void streamable_init (void);
-void usema_init (void);
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/graphics_syms.c linux/drivers/sgi/char/graphics_syms.c
--- v2.3.8/linux/drivers/sgi/char/graphics_syms.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/graphics_syms.c	Wed Jun 30 11:24:54 1999
@@ -0,0 +1,36 @@
+/*
+ * graphics_syms.c: interfaces for SGI Indy newport graphics
+ *
+ * Copyright (C) 1999 Alex deVries <puffin@redhat.com>
+ *
+ * We should not even be trying to compile this if we are not doing
+ * a module.
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+/* extern int rrm_command (unsigned int cmd, void *arg);
+extern int rrm_close (struct inode *inode, struct file *file);
+EXPORT_SYMBOL(rrm_command);
+EXPORT_SYMBOL(rrm_close);
+
+
+*/
+extern void shmiq_init (void);
+extern void usema_init(void);
+
+EXPORT_SYMBOL(shmiq_init);
+EXPORT_SYMBOL(usema_init);
+
+extern void disable_gconsole(void);
+extern void enable_gconsole(void);
+extern void remove_mapping (struct task_struct *task, unsigned long start,
+      unsigned long end);
+
+EXPORT_SYMBOL(disable_gconsole);
+EXPORT_SYMBOL(enable_gconsole);
+EXPORT_SYMBOL(remove_mapping);
+
+
+
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/newport.c linux/drivers/sgi/char/newport.c
--- v2.3.8/linux/drivers/sgi/char/newport.c	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/char/newport.c	Wed Jun 30 11:24:55 1999
@@ -4,13 +4,19 @@
  *
  * Author: Miguel de Icaza
  */
+
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <asm/types.h>
 #include <asm/gfx.h>
 #include <asm/ng1.h>
 #include <asm/uaccess.h>
-#include "newport.h"
+#include <asm/newport.h>
+#include <linux/module.h>
+
+struct newport_regs *npregs;
+
+EXPORT_SYMBOL(npregs);
 
 /* Kernel routines for supporting graphics context switching */
 
@@ -167,7 +173,6 @@
 {
 	switch (cmd){
 	case NG1_SETDISPLAYMODE: {
-		int i;
 		struct ng1_setdisplaymode_args request;
 		
 		if (copy_from_user (&request, (void *) arg, sizeof (request)))
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/newport.h linux/drivers/sgi/char/newport.h
--- v2.3.8/linux/drivers/sgi/char/newport.h	Fri May  8 00:23:41 1998
+++ linux/drivers/sgi/char/newport.h	Wed Dec 31 16:00:00 1969
@@ -1,585 +0,0 @@
-/* $Id: newport.h,v 1.1 1998/01/10 19:05:58 ecd Exp $
- * newport.h: Defines and register layout for NEWPORT graphics
- *            hardware.
- *
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- */
-
-#ifndef _SGI_NEWPORT_H
-#define _SGI_NEWPORT_H
-
-
-typedef volatile unsigned long npireg_t;
-
-union npfloat {
-	volatile float f;
-	npireg_t       i;
-};
-
-typedef union npfloat npfreg_t;
-
-union np_dcb {
-	npireg_t all;
-	struct { volatile unsigned short s0, s1; } hwords;
-	struct { volatile unsigned char b0, b1, b2, b3; } bytes;
-};
-
-struct newport_rexregs {
-	npireg_t drawmode1;      /* GL extra mode bits */
-	
-#define DM1_PLANES         0x00000007
-#define    DM1_NOPLANES    0x00000000
-#define    DM1_RGBPLANES   0x00000001
-#define    DM1_RGBAPLANES  0x00000002
-#define    DM1_OLAYPLANES  0x00000004
-#define    DM1_PUPPLANES   0x00000005
-#define    DM1_CIDPLANES   0x00000006
-	
-#define NPORT_DMODE1_DDMASK      0x00000018
-#define NPORT_DMODE1_DD4         0x00000000
-#define NPORT_DMODE1_DD8         0x00000008
-#define NPORT_DMODE1_DD12        0x00000010
-#define NPORT_DMODE1_DD24        0x00000018
-#define NPORT_DMODE1_DSRC        0x00000020
-#define NPORT_DMODE1_YFLIP       0x00000040
-#define NPORT_DMODE1_RWPCKD      0x00000080
-#define NPORT_DMODE1_HDMASK      0x00000300
-#define NPORT_DMODE1_HD4         0x00000000
-#define NPORT_DMODE1_HD8         0x00000100
-#define NPORT_DMODE1_HD12        0x00000200
-#define NPORT_DMODE1_HD32        0x00000300
-#define NPORT_DMODE1_RWDBL       0x00000400
-#define NPORT_DMODE1_ESWAP       0x00000800 /* Endian swap */
-#define NPORT_DMODE1_CCMASK      0x00007000
-#define NPORT_DMODE1_CCLT        0x00001000
-#define NPORT_DMODE1_CCEQ        0x00002000
-#define NPORT_DMODE1_CCGT        0x00004000
-#define NPORT_DMODE1_RGBMD       0x00008000
-#define NPORT_DMODE1_DENAB       0x00010000 /* Dither enable */
-#define NPORT_DMODE1_FCLR        0x00020000 /* Fast clear */
-#define NPORT_DMODE1_BENAB       0x00040000 /* Blend enable */
-#define NPORT_DMODE1_SFMASK      0x00380000
-#define NPORT_DMODE1_SF0         0x00000000
-#define NPORT_DMODE1_SF1         0x00080000
-#define NPORT_DMODE1_SFDC        0x00100000
-#define NPORT_DMODE1_SFMDC       0x00180000
-#define NPORT_DMODE1_SFSA        0x00200000
-#define NPORT_DMODE1_SFMSA       0x00280000
-#define NPORT_DMODE1_DFMASK      0x01c00000
-#define NPORT_DMODE1_DF0         0x00000000
-#define NPORT_DMODE1_DF1         0x00400000
-#define NPORT_DMODE1_DFSC        0x00800000
-#define NPORT_DMODE1_DFMSC       0x00c00000
-#define NPORT_DMODE1_DFSA        0x01000000
-#define NPORT_DMODE1_DFMSA       0x01400000
-#define NPORT_DMODE1_BBENAB      0x02000000 /* Back blend enable */
-#define NPORT_DMODE1_PFENAB      0x04000000 /* Pre-fetch enable */
-#define NPORT_DMODE1_ABLEND      0x08000000 /* Alpha blend */
-#define NPORT_DMODE1_LOMASK      0xf0000000
-#define NPORT_DMODE1_LOZERO      0x00000000
-#define NPORT_DMODE1_LOAND       0x10000000
-#define NPORT_DMODE1_LOANDR      0x20000000
-#define NPORT_DMODE1_LOSRC       0x30000000
-#define NPORT_DMODE1_LOANDI      0x40000000
-#define NPORT_DMODE1_LODST       0x50000000
-#define NPORT_DMODE1_LOXOR       0x60000000
-#define NPORT_DMODE1_LOOR        0x70000000
-#define NPORT_DMODE1_LONOR       0x80000000
-#define NPORT_DMODE1_LOXNOR      0x90000000
-#define NPORT_DMODE1_LONDST      0xa0000000
-#define NPORT_DMODE1_LOORR       0xb0000000
-#define NPORT_DMODE1_LONSRC      0xc0000000
-#define NPORT_DMODE1_LOORI       0xd0000000
-#define NPORT_DMODE1_LONAND      0xe0000000
-#define NPORT_DMODE1_LOONE       0xf0000000
-
-	npireg_t drawmode0;      /* REX command register */
-
-	/* These bits define the graphics opcode being performed. */
-#define NPORT_DMODE0_OPMASK   0x00000003 /* Opcode mask */
-#define NPORT_DMODE0_NOP      0x00000000 /* No operation */
-#define NPORT_DMODE0_RD       0x00000001 /* Read operation */
-#define NPORT_DMODE0_DRAW     0x00000002 /* Draw operation */
-#define NPORT_DMODE0_S2S      0x00000003 /* Screen to screen operation */
-
-	/* The following decide what addressing mode(s) are to be used */
-#define NPORT_DMODE0_AMMASK   0x0000001c /* Address mode mask */
-#define NPORT_DMODE0_SPAN     0x00000000 /* Spanning address mode */
-#define NPORT_DMODE0_BLOCK    0x00000004 /* Block address mode */
-#define NPORT_DMODE0_ILINE    0x00000008 /* Iline address mode */
-#define NPORT_DMODE0_FLINE    0x0000000c /* Fline address mode */
-#define NPORT_DMODE0_ALINE    0x00000010 /* Aline address mode */
-#define NPORT_DMODE0_TLINE    0x00000014 /* Tline address mode */
-#define NPORT_DMODE0_BLINE    0x00000018 /* Bline address mode */
-
-	/* And now some misc. operation control bits. */
-#define NPORT_DMODE0_DOSETUP  0x00000020
-#define NPORT_DMODE0_CHOST    0x00000040
-#define NPORT_DMODE0_AHOST    0x00000080
-#define NPORT_DMODE0_STOPX    0x00000100
-#define NPORT_DMODE0_STOPY    0x00000200
-#define NPORT_DMODE0_SK1ST    0x00000400
-#define NPORT_DMODE0_SKLST    0x00000800
-#define NPORT_DMODE0_ZPENAB   0x00001000
-#define NPORT_DMODE0_LISPENAB 0x00002000
-#define NPORT_DMODE0_LISLST   0x00004000
-#define NPORT_DMODE0_L32      0x00008000
-#define NPORT_DMODE0_ZOPQ     0x00010000
-#define NPORT_DMODE0_LISOPQ   0x00020000
-#define NPORT_DMODE0_SHADE    0x00040000
-#define NPORT_DMODE0_LRONLY   0x00080000
-#define NPORT_DMODE0_XYOFF    0x00100000
-#define NPORT_DMODE0_CLAMP    0x00200000
-#define NPORT_DMODE0_ENDPF    0x00400000
-#define NPORT_DMODE0_YSTR     0x00800000
-
-	npireg_t lsmode;      /* Mode for line stipple ops */
-	npireg_t lspattern;   /* Pattern for line stipple ops */
-	npireg_t lspatsave;   /* Backup save pattern */
-	npireg_t zpattern;    /* Pixel zpattern */
-	npireg_t colorback;   /* Background color */
-	npireg_t colorvram;   /* Clear color for fast vram */
-	npireg_t alpharef;    /* Reference value for afunctions */
-	unsigned long pad0;
-	npireg_t smask0x;     /* Window GL relative screen mask 0 */
-	npireg_t smask0y;     /* Window GL relative screen mask 0 */
-	npireg_t _setup;
-	npireg_t _stepz;
-	npireg_t _lsrestore;
-	npireg_t _lssave;
-
-	unsigned long _pad1[0x30];
-
-	/* Iterators, full state for context switch */
-	npfreg_t _xstart;	/* X-start point (current) */
-	npfreg_t _ystart;	/* Y-start point (current) */
-	npfreg_t _xend;		/* x-end point */
-	npfreg_t _yend;		/* y-end point */
-	npireg_t xsave;		/* copy of xstart integer value for BLOCk addressing MODE */
-	npireg_t xymove;	/* x.y offset from xstart, ystart for relative operations */
-	npfreg_t bresd;
-	npfreg_t bress1;;
-	npireg_t bresoctinc1;
-	volatile int bresrndinc2;
-	npireg_t brese1;
-	npireg_t bress2;
-	npireg_t aweight0;
-	npireg_t aweight1;
-	npfreg_t xstartf;
-	npfreg_t ystartf;
-	npfreg_t xendf;
-	npfreg_t yendf;
-	npireg_t xstarti;
-	npfreg_t xendf1;
-	npireg_t xystarti;
-	npireg_t xyendi;
-	npireg_t xstartendi;
-
-	unsigned long _unused2[0x29];
-
-	npfreg_t colorred;
-	npfreg_t coloralpha;
-	npfreg_t colorgrn;
-	npfreg_t colorblue;
-	npfreg_t slopered;
-	npfreg_t slopealpha;
-	npfreg_t slopegrn;
-	npfreg_t slopeblue;
-	npireg_t wrmask;
-	npireg_t colori;
-	npfreg_t colorx;
-	npfreg_t slopered1;
-	npireg_t hostrw0;
-	npireg_t hostrw1;
-	npireg_t dcbmode;
-#define NPORT_DMODE_WMASK   0x00000003
-#define NPORT_DMODE_W4      0x00000000
-#define NPORT_DMODE_W1      0x00000001
-#define NPORT_DMODE_W2      0x00000002
-#define NPORT_DMODE_W3      0x00000003
-#define NPORT_DMODE_EDPACK  0x00000004
-#define NPORT_DMODE_ECINC   0x00000008
-#define NPORT_DMODE_CMASK   0x00000070
-#define NPORT_DMODE_AMASK   0x00000780
-#define NPORT_DMODE_AVC2    0x00000000
-#define NPORT_DMODE_ACMALL  0x00000080
-#define NPORT_DMODE_ACM0    0x00000100
-#define NPORT_DMODE_ACM1    0x00000180
-#define NPORT_DMODE_AXMALL  0x00000200
-#define NPORT_DMODE_AXM0    0x00000280
-#define NPORT_DMODE_AXM1    0x00000300
-#define NPORT_DMODE_ABT     0x00000380
-#define NPORT_DMODE_AVCC1   0x00000400
-#define NPORT_DMODE_AVAB1   0x00000480
-#define NPORT_DMODE_ALG3V0  0x00000500
-#define NPORT_DMODE_A1562   0x00000580
-#define NPORT_DMODE_ESACK   0x00000800
-#define NPORT_DMODE_EASACK  0x00001000
-#define NPORT_DMODE_CWMASK  0x0003e000
-#define NPORT_DMODE_CHMASK  0x007c0000
-#define NPORT_DMODE_CSMASK  0x0f800000
-#define NPORT_DMODE_SENDIAN 0x10000000
-
-	unsigned long _unused3;
-
-	union np_dcb dcbdata0;
-	npireg_t dcbdata1;
-};
-
-struct newport_cregs {
-	npireg_t smask1x;
-	npireg_t smask1y;
-	npireg_t smask2x;
-	npireg_t smask2y;
-	npireg_t smask3x;
-	npireg_t smask3y;
-	npireg_t smask4x;
-	npireg_t smask4y;
-	npireg_t topscan;
-	npireg_t xywin;
-	npireg_t clipmode;
-#define NPORT_CMODE_SM0   0x00000001
-#define NPORT_CMODE_SM1   0x00000002
-#define NPORT_CMODE_SM2   0x00000004
-#define NPORT_CMODE_SM3   0x00000008
-#define NPORT_CMODE_SM4   0x00000010
-#define NPORT_CMODE_CMSK  0x00001e00
-
-	unsigned long _unused0;
-	unsigned long config;
-#define NPORT_CFG_G32MD   0x00000001
-#define NPORT_CFG_BWIDTH  0x00000002
-#define NPORT_CFG_ERCVR   0x00000004
-#define NPORT_CFG_BDMSK   0x00000078
-#define NPORT_CFG_GDMSK   0x00000f80
-#define NPORT_CFG_GD0     0x00000080
-#define NPORT_CFG_GD1     0x00000100
-#define NPORT_CFG_GD2     0x00000200
-#define NPORT_CFG_GD3     0x00000400
-#define NPORT_CFG_GD4     0x00000800
-#define NPORT_CFG_GFAINT  0x00001000
-#define NPORT_CFG_TOMSK   0x0000e000
-#define NPORT_CFG_VRMSK   0x00070000
-#define NPORT_CFG_FBTYP   0x00080000
-
-	npireg_t _unused1;
-	npireg_t stat;
-#define NPORT_STAT_VERS   0x00000007
-#define NPORT_STAT_GBUSY  0x00000008
-#define NPORT_STAT_BBUSY  0x00000010
-#define NPORT_STAT_VRINT  0x00000020
-#define NPORT_STAT_VIDINT 0x00000040
-#define NPORT_STAT_GLMSK  0x00001f80
-#define NPORT_STAT_BLMSK  0x0007e000
-#define NPORT_STAT_BFIRQ  0x00080000
-#define NPORT_STAT_GFIRQ  0x00100000
-
-	npireg_t ustat;
-	npireg_t dreset;
-};
-
-struct newport_regs {
-	struct newport_rexregs set;
-	unsigned long _unused0[0x16e];
-	struct newport_rexregs go;
-	unsigned long _unused1[0x22e];
-	struct newport_cregs cset;
-	unsigned long _unused2[0x1ef];
-	struct newport_cregs cgo;
-};
-extern struct newport_regs *npregs;
-
-
-typedef struct {
-	unsigned int drawmode1;
-	unsigned int drawmode0;
-	unsigned int lsmode;   
-	unsigned int lspattern;
-	unsigned int lspatsave;
-	unsigned int zpattern; 
-	unsigned int colorback;
-	unsigned int colorvram;
-	unsigned int alpharef; 
-	unsigned int smask0x;  
-	unsigned int smask0y;  
-	unsigned int _xstart;  
-	unsigned int _ystart;  
-	unsigned int _xend;    
-	unsigned int _yend;    
-	unsigned int xsave;    
-	unsigned int xymove;   
-	unsigned int bresd;    
-	unsigned int bress1;   
-	unsigned int bresoctinc1;
-	unsigned int bresrndinc2;
-	unsigned int brese1;     
-	unsigned int bress2;     
-	
-	unsigned int aweight0;    
-	unsigned int aweight1;    
-	unsigned int colorred;    
-	unsigned int coloralpha;  
-	unsigned int colorgrn;    
-	unsigned int colorblue;   
-	unsigned int slopered;    
-	unsigned int slopealpha;  
-	unsigned int slopegrn;    
-	unsigned int slopeblue;   
-	unsigned int wrmask;      
-	unsigned int hostrw0;     
-	unsigned int hostrw1;     
-	
-        /* configregs */
-	
-	unsigned int smask1x;    
-	unsigned int smask1y;    
-	unsigned int smask2x;    
-	unsigned int smask2y;    
-	unsigned int smask3x;    
-	unsigned int smask3y;    
-	unsigned int smask4x;    
-	unsigned int smask4y;    
-	unsigned int topscan;    
-	unsigned int xywin;      
-	unsigned int clipmode;   
-	unsigned int config;     
-	
-        /* dcb registers */
-	unsigned int dcbmode;   
-	unsigned int dcbdata0;  
-	unsigned int dcbdata1;
-} newport_ctx;
-
-/* Reading/writing VC2 registers. */
-#define VC2_REGADDR_INDEX      0x00000000
-#define VC2_REGADDR_IREG       0x00000010
-#define VC2_REGADDR_RAM        0x00000030
-#define VC2_PROTOCOL           (NPORT_DMODE_EASACK | 0x00800000 | 0x00040000)
-
-#define VC2_VLINET_ADDR        0x000
-#define VC2_VFRAMET_ADDR       0x400
-#define VC2_CGLYPH_ADDR        0x500
-
-/* Now the Indexed registers of the VC2. */
-#define VC2_IREG_VENTRY        0x00
-#define VC2_IREG_CENTRY        0x01
-#define VC2_IREG_CURSX         0x02
-#define VC2_IREG_CURSY         0x03
-#define VC2_IREG_CCURSX        0x04
-#define VC2_IREG_DENTRY        0x05
-#define VC2_IREG_SLEN          0x06
-#define VC2_IREG_RADDR         0x07
-#define VC2_IREG_VFPTR         0x08
-#define VC2_IREG_VLSPTR        0x09
-#define VC2_IREG_VLIR          0x0a
-#define VC2_IREG_VLCTR         0x0b
-#define VC2_IREG_CTPTR         0x0c
-#define VC2_IREG_WCURSY        0x0d
-#define VC2_IREG_DFPTR         0x0e
-#define VC2_IREG_DLTPTR        0x0f
-#define VC2_IREG_CONTROL       0x10
-#define VC2_IREG_CONFIG        0x20
-
-extern inline void newport_vc2_set(struct newport_regs *regs, unsigned char vc2ireg,
-				   unsigned short val)
-{
-	regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX | NPORT_DMODE_W3 |
-			   NPORT_DMODE_ECINC | VC2_PROTOCOL);
-	regs->set.dcbdata0.all = (vc2ireg << 24) | (val << 8);
-}
-
-extern inline unsigned short newport_vc2_get(struct newport_regs *regs,
-					     unsigned char vc2ireg)
-{
-	regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_INDEX | NPORT_DMODE_W1 |
-			   NPORT_DMODE_ECINC | VC2_PROTOCOL);
-	regs->set.dcbdata0.bytes.b3 = vc2ireg;
-	regs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_IREG | NPORT_DMODE_W2 |
-			   NPORT_DMODE_ECINC | VC2_PROTOCOL);
-	return regs->set.dcbdata0.hwords.s1;
-}
-
-/* VC2 Control register bits */
-#define VC2_CTRL_EVIRQ     0x0001
-#define VC2_CTRL_EDISP     0x0002
-#define VC2_CTRL_EVIDEO    0x0004
-#define VC2_CTRL_EDIDS     0x0008
-#define VC2_CTRL_ECURS     0x0010
-#define VC2_CTRL_EGSYNC    0x0020
-#define VC2_CTRL_EILACE    0x0040
-#define VC2_CTRL_ECDISP    0x0080
-#define VC2_CTRL_ECCURS    0x0100
-#define VC2_CTRL_ECG64     0x0200
-#define VC2_CTRL_GLSEL     0x0400
-
-/* Controlling the color map on NEWPORT. */
-#define NCMAP_REGADDR_AREG   0x00000000
-#define NCMAP_REGADDR_ALO    0x00000000
-#define NCMAP_REGADDR_AHI    0x00000010
-#define NCMAP_REGADDR_PBUF   0x00000020
-#define NCMAP_REGADDR_CREG   0x00000030
-#define NCMAP_REGADDR_SREG   0x00000040
-#define NCMAP_REGADDR_RREG   0x00000060
-#define NCMAP_PROTOCOL       (0x00008000 | 0x00040000 | 0x00800000)
-
-static inline void newport_cmap_setaddr(struct newport_regs *regs,
-					unsigned short addr)
-{
-	regs->set.dcbmode = (NPORT_DMODE_ACMALL | NCMAP_PROTOCOL |
-			   NPORT_DMODE_SENDIAN | NPORT_DMODE_ECINC |
-			   NCMAP_REGADDR_AREG | NPORT_DMODE_W2);
-	regs->set.dcbdata0.hwords.s1 = addr;
-	regs->set.dcbmode = (NPORT_DMODE_ACMALL | NCMAP_PROTOCOL |
-			   NCMAP_REGADDR_PBUF | NPORT_DMODE_W3);
-}
-
-static inline void newport_cmap_setrgb(struct newport_regs *regs,
-				       unsigned char red,
-				       unsigned char green,
-				       unsigned char blue)
-{
-	regs->set.dcbdata0.all =
-		(red << 24) |
-		(green << 16) |
-		(blue << 8);
-}
-
-/* Miscellaneous NEWPORT routines. */
-#define BUSY_TIMEOUT 100000
-static inline int newport_wait(void)
-{
-	int i = 0;
-
-	while(i < BUSY_TIMEOUT)
-		if(!(npregs->cset.stat & NPORT_STAT_GBUSY))
-			break;
-	if(i == BUSY_TIMEOUT)
-		return 1;
-	return 0;
-}
-
-static inline int newport_bfwait(void)
-{
-	int i = 0;
-
-	while(i < BUSY_TIMEOUT)
-		if(!(npregs->cset.stat & NPORT_STAT_BBUSY))
-			break;
-	if(i == BUSY_TIMEOUT)
-		return 1;
-	return 0;
-}
-
-/* newport.c and cons_newport.c routines */
-extern struct graphics_ops *newport_probe (int, const char **);
-
-void newport_save    (void *);
-void newport_restore (void *);
-void newport_reset   (void);
-int  newport_ioctl   (int card, int cmd, unsigned long arg);
-
-/*
- * DCBMODE register defines:
- */
-
-/* Widht of the data being transfered for each DCBDATA[01] word */
-#define DCB_DATAWIDTH_4 0x0
-#define DCB_DATAWIDTH_1 0x1
-#define DCB_DATAWIDTH_2 0x2
-#define DCB_DATAWIDTH_3 0x3
-
-/* If set, all of DCBDATA will be moved, otherwise only DATAWIDTH bytes */
-#define DCB_ENDATAPACK   (1 << 2)
-
-/* Enables DCBCRS auto increment after each DCB transfer */
-#define DCB_ENCRSINC     (1 << 3)
-
-/* shift for accessing the control register select address (DBCCRS, 3 bits) */
-#define DCB_CRS_SHIFT    4
-
-/* DCBADDR (4 bits): display bus slave address */
-#define DCB_ADDR_SHIFT   7
-#define DCB_VC2          (0 <<  DCB_ADDR_SHIFT)
-#define DCB_CMAP_ALL     (1 <<  DCB_ADDR_SHIFT)
-#define DCB_CMAP0        (2 <<  DCB_ADDR_SHIFT)
-#define DCB_CMAP1        (3 <<  DCB_ADDR_SHIFT)
-#define DCB_XMAP_ALL     (4 <<  DCB_ADDR_SHIFT)
-#define DCB_XMAP0        (5 <<  DCB_ADDR_SHIFT)
-#define DCB_XMAP1        (6 <<  DCB_ADDR_SHIFT)
-#define DCB_BT445        (7 <<  DCB_ADDR_SHIFT)
-#define DCB_VCC1         (8 <<  DCB_ADDR_SHIFT)
-#define DCB_VAB1         (9 <<  DCB_ADDR_SHIFT)
-#define DCB_LG3_BDVERS0  (10 << DCB_ADDR_SHIFT)
-#define DCB_LG3_ICS1562  (11 << DCB_ADDR_SHIFT)
-#define DCB_RESERVED     (15 << DCB_ADDR_SHIFT)
-
-/* DCB protocol ack types */
-#define DCB_ENSYNCACK    (1 << 11)
-#define DCB_ENASYNCACK   (1 << 12)
-
-#define DCB_CSWIDTH_SHIFT 13
-#define DCB_CSHOLD_SHIFT  18
-#define DCB_CSSETUP_SHIFT 23
-
-/* XMAP9 specific defines */
-/*   XMAP9 -- registers as seen on the DCBMODE register*/
-#   define XM9_CRS_CONFIG            (0 << DCB_CRS_SHIFT)
-#       define XM9_PUPMODE           (1 << 0)
-#       define XM9_ODD_PIXEL         (1 << 1)
-#       define XM9_8_BITPLANES       (1 << 2)
-#       define XM9_SLOW_DCB          (1 << 3)
-#       define XM9_VIDEO_RGBMAP_MASK (3 << 4)
-#       define XM9_EXPRESS_VIDEO     (1 << 6)
-#       define XM9_VIDEO_OPTION      (1 << 7)
-#   define XM9_CRS_REVISION          (1 << DCB_CRS_SHIFT)
-#   define XM9_CRS_FIFO_AVAIL        (2 << DCB_CRS_SHIFT)
-#       define XM9_FIFO_0_AVAIL      0
-#       define XM9_FIFO_1_AVAIL      1
-#       define XM9_FIFO_2_AVAIL      3
-#       define XM9_FIFO_3_AVAIL      2
-#       define XM9_FIFO_FULL         XM9_FIFO_0_AVAIL
-#       define XM9_FIFO_EMPTY        XM9_FIFO_3_AVAIL
-#   define XM9_CRS_CURS_CMAP_MSB     (3 << DCB_CRS_SHIFT)
-#   define XM9_CRS_PUP_CMAP_MSB      (4 << DCB_CRS_SHIFT)
-#   define XM9_CRS_MODE_REG_DATA     (5 << DCB_CRS_SHIFT)
-#   define XM9_CRS_MODE_REG_INDEX    (7 << DCB_CRS_SHIFT)
-
-
-#define DCB_CYCLES(setup,hold,width)                \
-                  ((hold << DCB_CSHOLD_SHIFT)  |    \
-		   (setup << DCB_CSSETUP_SHIFT)|    \
-		   (width << DCB_CSWIDTH_SHIFT))
-
-#define W_DCB_XMAP9_PROTOCOL       DCB_CYCLES (2, 1, 0)
-#define WSLOW_DCB_XMAP9_PROTOCOL   DCB_CYCLES (5, 5, 0)
-#define WAYSLOW_DCB_XMAP9_PROTOCOL DCB_CYCLES (12, 12, 0)
-#define R_DCB_XMAP9_PROTOCOL       DCB_CYCLES (2, 1, 3)
-
-static inline void
-xmap9FIFOWait (struct newport_regs *rex)
-{
-        rex->set.dcbmode = DCB_XMAP0 | XM9_CRS_FIFO_AVAIL |
-		DCB_DATAWIDTH_1 | R_DCB_XMAP9_PROTOCOL;
-        newport_bfwait ();
-	
-        while ((rex->set.dcbdata0.bytes.b3 & 3) != XM9_FIFO_EMPTY)
-		;
-}
-
-static inline void
-xmap9SetModeReg (struct newport_regs *rex, unsigned int modereg, unsigned int data24, int cfreq)
-{
-        if (cfreq > 119)
-            rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA |
-                        DCB_DATAWIDTH_4 | W_DCB_XMAP9_PROTOCOL;
-        else if (cfreq > 59)
-            rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA |
-		    DCB_DATAWIDTH_4 | WSLOW_DCB_XMAP9_PROTOCOL;    
-        else
-            rex->set.dcbmode = DCB_XMAP_ALL | XM9_CRS_MODE_REG_DATA |
-                        DCB_DATAWIDTH_4 | WAYSLOW_DCB_XMAP9_PROTOCOL; 
-        rex->set.dcbdata0.all = ((modereg) << 24) | (data24 & 0xffffff);
-}
-
-#endif /* !(_SGI_NEWPORT_H) */
-
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/rrm.c linux/drivers/sgi/char/rrm.c
--- v2.3.8/linux/drivers/sgi/char/rrm.c	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/char/rrm.c	Fri Jun 25 17:39:34 1999
@@ -12,6 +12,10 @@
 #include <asm/uaccess.h>
 #include <asm/rrm.h>
 
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
 int
 rrm_open_rn (int rnid, void *arg)
 {
@@ -66,4 +70,3 @@
 	/* This routine is invoked when the device is closed */
 	return 0;
 }
-
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/sgicons.c linux/drivers/sgi/char/sgicons.c
--- v2.3.8/linux/drivers/sgi/char/sgicons.c	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/char/sgicons.c	Fri Jun 25 17:39:34 1999
@@ -1,14 +1,11 @@
-/*
+/* $Id: sgicons.c,v 1.11 1999/01/04 16:07:19 ralf Exp $
+ *
  * sgicons.c: Setting up and registering console I/O on the SGI.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
  *
  * This implement a virtual console interface.
- *
- * This should be replaced with Gert's all-singing all-dancing
- * graphics console code in the future
- *
  */
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -17,7 +14,7 @@
 #include "gconsole.h"
 
 /* To make psaux code cleaner */
-int aux_device_present = 0xaa;
+unsigned char aux_device_present = 0xaa;
 
 /* This is the system graphics console (the first adapter found) */
 struct console_ops *gconsole = 0;
@@ -45,139 +42,4 @@
 	if (gconsole)
 		return;
 	gconsole = gc;
-}
-
-void
-__set_origin (unsigned short offset)
-{
-	if (gconsole)
-		(*gconsole->set_origin)(offset);
-}
-
-void
-hide_cursor (void)
-{
-
-	if (gconsole)
-		(*gconsole->hide_cursor)();
-}
-
-void
-set_cursor (int currcons)
-{
-	if (gconsole)
-		(*gconsole->set_cursor)(currcons);
-}
-
-void
-get_scrmem (int currcons)
-{
-	if (gconsole)
-		(*gconsole->get_scrmem)(currcons);
-}
-
-void
-set_scrmem (int currcons, long offset)
-{
-	if (gconsole)
-		(*gconsole->set_scrmem)(currcons, offset);
-}
-
-int
-set_get_cmap (unsigned char *arg, int set)
-{
-	if (gconsole)
-		return (*gconsole->set_get_cmap)(arg, set);
-	return 0;
-}
-
-void
-blitc (unsigned short charattr, unsigned long addr)
-{
-	if (gconsole)
-		(*gconsole->blitc)(charattr, addr);
-}
-
-void
-memsetw (void *s, unsigned short c, unsigned int count)
-{
-	if (gconsole)
-		(*gconsole->memsetw)(s, c, count);
-}
-
-void
-memcpyw (unsigned short *to, unsigned short *from, unsigned int count)
-{
-	if (gconsole)
-		(*gconsole->memcpyw)(to, from, count);
-}
-
-int
-con_adjust_height (unsigned long fontheight)
-{
-	return -EINVAL;
-}
-
-int
-set_get_font (char *arg, int set, int ch512)
-{
-	int error, i, line;
-
-	if (!arg)
-		return -EINVAL;
-	error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg,
-			     ch512 ? 2* cmapsz : cmapsz);
-	if (error)
-		return error;
-
-	/* download the current font */
-	if (!set) {
-		memset (arg, 0, cmapsz);
-		for (i = 0; i < 256; i++) {
-			for (line = 0; line < CHAR_HEIGHT; line++)
-				__put_user (vga_font [i], arg+(i*32+line));
-		}
-		return 0;
-	}
-	
-        /* set the font */
-	for (i = 0; i < 256; i++) {
-		for (line = 0; line < CHAR_HEIGHT; line++) {
-			__get_user(vga_font [i*CHAR_HEIGHT + line],
-			           arg + (i * 32 + line));
-		}
-	}
-	return 0;
-}
-
-/*
- * dummy routines for the VESA blanking code, which is VGA only,
- * so we don't have to carry that stuff around for the Sparc...  */
-void vesa_blank(void) { }
-void vesa_unblank(void) { }
-void set_vesa_blanking(const unsigned long arg) { }
-void vesa_powerdown(void) { }
-void set_palette (void) { }
-
-extern unsigned long video_mem_base, video_screen_size, video_mem_term;
-
-__initfunc(unsigned long con_type_init(unsigned long start_mem, const char **name))
-{
-	extern int serial_console;
-
-	if (serial_console)
-		*name = "NONE";
-	else {
-		gfx_init (name);
-		printk("Video screen size is %08lx at %08lx\n",
-		       video_screen_size, start_mem);
-		video_mem_base = start_mem;
-		start_mem += (video_screen_size * 2);
-		video_mem_term = start_mem;
-	}
-	return start_mem;
-}
-
-__initfunc(void con_type_init_finish(void))
-{
 }
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c
--- v2.3.8/linux/drivers/sgi/char/sgiserial.c	Sat May 15 15:05:36 1999
+++ linux/drivers/sgi/char/sgiserial.c	Tue Jun 29 09:22:08 1999
@@ -1,6 +1,7 @@
 /* sgiserial.c: Serial port driver for SGI machines.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
  */
 
 #include <linux/config.h> /* for CONFIG_REMOTE_DEBUG */
@@ -18,6 +19,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/console.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -33,39 +35,22 @@
 #define NUM_SERIAL 1     /* One chip on board. */
 #define NUM_CHANNELS (NUM_SERIAL * 2)
 
-extern struct wait_queue_head_t keypress_wait;
+extern wait_queue_head_t keypress_wait;
 
 struct sgi_zslayout *zs_chips[NUM_SERIAL] = { 0, };
 struct sgi_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, };
 struct sgi_zschannel *zs_conschan;
 struct sgi_zschannel *zs_kgdbchan;
-int zs_nodes[NUM_SERIAL] = { 0, };
 
 struct sgi_serial zs_soft[NUM_CHANNELS];
 struct sgi_serial *zs_chain;  /* IRQ servicing chain */
 static int zilog_irq = 21;
 
-struct tty_struct zs_ttys[NUM_CHANNELS];
-/** struct tty_struct *zs_constty; **/
-
 /* Console hooks... */
 static int zs_cons_chanout = 0;
 static int zs_cons_chanin = 0;
 struct sgi_serial *zs_consinfo = 0;
 
-static struct console sgi_console_driver = {
-        "debug",
-        NULL,                   /* write */
-        NULL,                   /* read */
-        NULL,                   /* device */
-        NULL,                   /* wait_key */
-        NULL,                   /* unblank */
-        NULL,                   /* setup */
-        CON_PRINTBUFFER,
-        -1,
-        0,
-        NULL
-};
 static unsigned char kgdb_regs[16] = {
 	0, 0, 0,                     /* write 0, 1, 2 */
 	(Rx8 | RxENABLE),            /* write 3 */
@@ -80,6 +65,22 @@
 	(DCDIE)                      /* write 15 */
 };
 
+static unsigned char zscons_regs[16] = {
+	0,                           /* write 0 */
+	(EXT_INT_ENAB | INT_ALL_Rx), /* write 1 */
+	0,                           /* write 2 */
+	(Rx8 | RxENABLE),            /* write 3 */
+	(X16CLK),                    /* write 4 */
+	(DTR | Tx8 | TxENAB),        /* write 5 */
+	0, 0, 0,                     /* write 6, 7, 8 */
+	(NV | MIE),                  /* write 9 */
+	(NRZ),                       /* write 10 */
+	(TCBR | RCBR),               /* write 11 */
+	0, 0,                        /* BRG time constant, write 12 + 13 */
+	(BRENABL),                   /* write 14 */
+	(DCDIE | CTSIE | TxUIE | BRKIE) /* write 15 */
+};
+
 #define ZS_CLOCK         3672000   /* Zilog input clock rate */
 
 DECLARE_TASK_QUEUE(tq_serial);
@@ -126,7 +127,7 @@
  * memory if large numbers of serial ports are open.
  */
 static unsigned char tmp_buf[4096]; /* This is cheating */
-static struct semaphore tmp_buf_sem = MUTEX;
+static DECLARE_MUTEX(tmp_buf_sem);
 
 static inline int serial_paranoia_check(struct sgi_serial *info,
 					dev_t device, const char *routine)
@@ -161,6 +162,10 @@
  * driver work on the Sun4 which needs a settling delay after each chip
  * register access, other machines handle this in hardware via auxiliary
  * flip-flops which implement the settle time we do in software.
+ *
+ * read_zsreg() and write_zsreg() may get called from rs_kgdb_hook() before
+ * interrupts are enabled. Therefore we have to check ioc_iocontrol before we
+ * access it.
  */
 static inline unsigned char read_zsreg(struct sgi_zschannel *channel, unsigned char reg)
 {
@@ -169,7 +174,8 @@
 
 	udelay(2);
 	channel->control = reg;
-	junk = ioc_icontrol->istat0;
+	if (ioc_icontrol)
+		junk = ioc_icontrol->istat0;
 	udelay(1);
 	retval = channel->control;
 	return retval;
@@ -181,10 +187,12 @@
 
 	udelay(2);
 	channel->control = reg;
-	junk = ioc_icontrol->istat0;
+	if (ioc_icontrol)
+		junk = ioc_icontrol->istat0;
 	udelay(1);
 	channel->control = value;
-	junk = ioc_icontrol->istat0;
+	if (ioc_icontrol)
+		junk = ioc_icontrol->istat0;
 	return;
 }
 
@@ -235,7 +243,7 @@
 		kgdb_regs[R1] = 0;
 		kgdb_regs[R9] &= ~MIE;
 	}
-	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+	brg = BPS_TO_BRG(bps, ZS_CLOCK/ss->clk_divisor);
 	kgdb_regs[R12] = (brg & 255);
 	kgdb_regs[R13] = ((brg >> 8) & 255);
 	load_zsregs(ss->zs_channel, kgdb_regs);
@@ -400,7 +408,6 @@
 			show_state();
 			return;
 		} else if (ch == 2) {
-			show_buffers();
 			return;
 		}
 		/* It is a 'keyboard interrupt' ;-) */
@@ -552,7 +559,7 @@
 	struct sgi_serial * info = (struct sgi_serial *) dev_id;
 	unsigned char zs_intreg;
 
-	zs_intreg = read_zsreg(info->zs_channel, 3);
+	zs_intreg = read_zsreg(info->zs_next->zs_channel, 3);
 
 	/* NOTE: The read register 3, which holds the irq status,
 	 *       does so for both channels on each chip.  Although
@@ -564,25 +571,25 @@
 #define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
 
 	/* *** Chip 1 *** */
-	/* Channel A -- /dev/ttya, could be the console */
-	if(zs_intreg & CHAN_A_IRQMASK) {
-		if (zs_intreg & CHARxIP)
+	/* Channel B -- /dev/ttyb, could be the console */
+	if(zs_intreg & CHAN_B_IRQMASK) {
+		if (zs_intreg & CHBRxIP)
 			receive_chars(info, regs);
-		if (zs_intreg & CHATxIP)
+		if (zs_intreg & CHBTxIP)
 			transmit_chars(info);
-		if (zs_intreg & CHAEXT)
+		if (zs_intreg & CHBEXT)
 			status_handle(info);
 	}
 
 	info=info->zs_next;
 
-	/* Channel B -- /dev/ttyb, could be the console */
-	if(zs_intreg & CHAN_B_IRQMASK) {
-		if (zs_intreg & CHBRxIP)
+	/* Channel A -- /dev/ttya, could be the console */
+	if(zs_intreg & CHAN_A_IRQMASK) {
+		if (zs_intreg & CHARxIP)
 			receive_chars(info, regs);
-		if (zs_intreg & CHBTxIP)
+		if (zs_intreg & CHATxIP)
 			transmit_chars(info);
-		if (zs_intreg & CHBEXT)
+		if (zs_intreg & CHAEXT)
 			status_handle(info);
 	}
 }
@@ -904,7 +911,7 @@
 /* These are for receiving and sending characters under the kgdb
  * source level kernel debugger.
  */
-void putDebugChar(char kgdb_char)
+int putDebugChar(char kgdb_char)
 {
 	struct sgi_zschannel *chan = zs_kgdbchan;
 	volatile unsigned char junk;
@@ -919,6 +926,8 @@
 	chan->data = kgdb_char;
 	junk = ioc_icontrol->istat0;
 	restore_flags(flags);
+
+	return 1;
 }
 
 char getDebugChar(void)
@@ -971,63 +980,6 @@
 	return;
 }
 
-/*
- * zs_console_print is registered for printk.
- */
-
-static void zs_console_print(struct console *co, const char *str, unsigned int count)
-{
-
-	while(count--) {
-		if(*str == '\n')
-			rs_put_char('\r');
-		rs_put_char(*str++);
-	}
-
-	/* Comment this if you want to have a strict interrupt-driven output */
-	rs_fair_output();
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
-	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
-		return;
-
-	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-	    !info->xmit_buf)
-		return;
-
-	/* Enable transmitter */
-	save_flags(flags); cli();
-	info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
-	info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
-	write_zsreg(info->zs_channel, 1, info->curregs[1]);
-	info->curregs[5] |= TxENAB;
-	info->pendregs[5] |= TxENAB;
-	write_zsreg(info->zs_channel, 5, info->curregs[5]);
-
-	/*
-	 * Send a first (bootstrapping) character. A best solution is
-	 * to call transmit_chars() here which handles output in a
-	 * generic way. Current transmit_chars() not only transmits,
-	 * but resets interrupts also what we do not desire here.
-	 * XXX Discuss with David.
-	 */
-	if (info->zs_channel->control & Tx_BUF_EMP) {
-		volatile unsigned char junk;
-
-		/* Send char */
-		udelay(2);
-		info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
-		junk = ioc_icontrol->istat0;
-		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-		info->xmit_cnt--;
-	}
-	restore_flags(flags);
-}
 
 static int rs_write(struct tty_struct * tty, int from_user,
 		    const unsigned char *buf, int count)
@@ -1117,6 +1069,47 @@
 		(tty->ldisc.write_wakeup)(tty);
 }
 
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct sgi_serial *info = (struct sgi_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	/* Enable transmitter */
+	save_flags(flags); cli();
+	info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+	info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
+	write_zsreg(info->zs_channel, 1, info->curregs[1]);
+	info->curregs[5] |= TxENAB;
+	info->pendregs[5] |= TxENAB;
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+
+	/*
+	 * Send a first (bootstrapping) character. A best solution is
+	 * to call transmit_chars() here which handles output in a
+	 * generic way. Current transmit_chars() not only transmits,
+	 * but resets interrupts also what we do not desire here.
+	 * XXX Discuss with David.
+	 */
+	if (info->zs_channel->control & Tx_BUF_EMP) {
+		volatile unsigned char junk;
+
+		/* Send char */
+		udelay(2);
+		info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
+		junk = ioc_icontrol->istat0;
+		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt--;
+	}
+	restore_flags(flags);
+}
+
 /*
  * ------------------------------------------------------------
  * rs_throttle()
@@ -1614,7 +1607,7 @@
 		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
 		    !(info->flags & ZILOG_CLOSING) && do_clocal)
 			break;
-		if (current->signal & ~current->blocked) {
+		if (signal_pending(current)) {
 			retval = -ERESTARTSYS;
 			break;
 		}
@@ -1725,17 +1718,14 @@
 }
 
 
-
 static inline void
 rs_cons_check(struct sgi_serial *ss, int channel)
 {
 	int i, o, io;
-	static consout_registered = 0;
-	static msg_printed = 0;
+	static int msg_printed = 0;
 
 	i = o = io = 0;
 
-
 	/* Is this one of the serial console lines? */
 	if((zs_cons_chanout != channel) &&
 	   (zs_cons_chanin != channel))
@@ -1744,18 +1734,6 @@
 	zs_consinfo = ss;
 
 
-	/* Register the console output putchar, if necessary */
-	if((zs_cons_chanout == channel)) {
-		o = 1;
-		/* double whee.. */
-
-		if(!consout_registered) {
-		  sgi_console_driver.write = zs_console_print;
-			register_console(&sgi_console_driver);
-			consout_registered = 1;
-		}
-	}
-
 
 	/* If this is console input, we handle the break received
 	 * status interrupt on this line to mean prom_halt().
@@ -1873,8 +1851,8 @@
 		if(!zs_chips[chip]) {
 			zs_chips[chip] = get_zs(chip);
 			/* Two channels per chip */
-			zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
-			zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+			zs_channels[(chip*2)] = &zs_chips[chip]->channelB;
+			zs_channels[(chip*2)+1] = &zs_chips[chip]->channelA;
 			zs_soft[(chip*2)].kgdb_channel = 0;
 			zs_soft[(chip*2)+1].kgdb_channel = 0;
 		}
@@ -1946,8 +1924,8 @@
 		info->tqueue_hangup.data = info;
 		info->callout_termios =callout_driver.init_termios;
 		info->normal_termios = serial_driver.init_termios;
-		info->open_wait = 0;
-		info->close_wait = 0;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
 		printk("tty%02d at 0x%04x (irq = %d)", info->line, 
 		       info->port, info->irq);
 		printk(" is a Zilog8530\n");
@@ -1990,14 +1968,14 @@
 	
 	if(chip)
 		panic("rs_cons_hook called with chip not zero");
-	if(line != 1 && line != 2)
+	if(line != 0 && line != 1)
 		panic("rs_cons_hook called with line not ttya or ttyb");
-	channel = line - 1;
+	channel = line;
 	if(!zs_chips[chip]) {
 		zs_chips[chip] = get_zs(chip);
 		/* Two channels per chip */
-		zs_channels[(chip*2)] = &zs_chips[chip]->channelA;
-		zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB;
+		zs_channels[(chip*2)] = &zs_chips[chip]->channelB;
+		zs_channels[(chip*2)+1] = &zs_chips[chip]->channelA;
 	}
 	zs_soft[channel].zs_channel = zs_channels[channel];
 	zs_soft[channel].change_needed = 0;
@@ -2041,3 +2019,176 @@
 	udelay(5);
 	ZS_CLEARFIFO(zs_kgdbchan);
 }
+
+static void zs_console_write(struct console *co, const char *str, unsigned int count)
+{
+
+	while(count--) {
+		if(*str == '\n')
+			rs_put_char('\r');
+		rs_put_char(*str++);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	rs_fair_output();
+}
+
+static int zs_console_wait_key(struct console *con)
+{
+	sleep_on(&keypress_wait);
+	return 0;
+}
+
+static kdev_t zs_console_device(struct console *con)
+{
+	return MKDEV(TTY_MAJOR, 64 + con->index);
+}
+
+
+__initfunc(static int zs_console_setup(struct console *con, char *options))
+{
+	struct sgi_serial *info;
+	int	baud = 9600;
+	int	bits = 8;
+	int	parity = 'n';
+	int	cflag = CREAD | HUPCL | CLOCAL;
+	char	*s;
+	int     i, brg;
+    
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s) parity = *s++;
+		if (*s) bits   = *s - '0';
+	}
+
+	/*
+	 *	Now construct a cflag setting.
+	 */
+	switch(baud) {
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 2400:
+			cflag |= B2400;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+		case 57600:
+			cflag |= B57600;
+			break;
+		case 115200:
+			cflag |= B115200;
+			break;
+		case 9600:
+		default:
+			cflag |= B9600;
+			break;
+	}
+	switch(bits) {
+		case 7:
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			cflag |= CS8;
+			break;
+	}
+	switch(parity) {
+		case 'o': case 'O':
+			cflag |= PARODD;
+			break;
+		case 'e': case 'E':
+			cflag |= PARENB;
+			break;
+	}
+	con->cflag = cflag;
+
+        rs_cons_hook(0, 0, con->index);
+	info = zs_soft + con->index;
+	info->is_cons = 1;
+    
+	printk("Console: ttyS%d (Zilog8530)\n", info->line);
+
+	i = con->cflag & CBAUD;
+	if (con->cflag & CBAUDEX) {
+		i &= ~CBAUDEX;
+		con->cflag &= ~CBAUDEX;
+	}
+	info->zs_baud = baud;
+
+	switch (con->cflag & CSIZE) {
+		case CS5:
+			zscons_regs[3] = Rx5 | RxENABLE;
+			zscons_regs[5] = Tx5 | TxENAB;
+			break;
+		case CS6:
+			zscons_regs[3] = Rx6 | RxENABLE;
+			zscons_regs[5] = Tx6 | TxENAB;
+			break;
+		case CS7:
+			zscons_regs[3] = Rx7 | RxENABLE;
+			zscons_regs[5] = Tx7 | TxENAB;
+			break;
+		default:
+		case CS8:
+			zscons_regs[3] = Rx8 | RxENABLE;
+			zscons_regs[5] = Tx8 | TxENAB;
+			break;
+	}
+	zscons_regs[5] |= DTR;
+
+	if (con->cflag & PARENB)
+		zscons_regs[4] |= PAR_ENA;
+	if (!(con->cflag & PARODD))
+		zscons_regs[4] |= PAR_EVEN;
+
+	if (con->cflag & CSTOPB)
+		zscons_regs[4] |= SB2;
+	else
+		zscons_regs[4] |= SB1;
+
+	brg = BPS_TO_BRG(baud, ZS_CLOCK / info->clk_divisor);
+	zscons_regs[12] = brg & 0xff;
+	zscons_regs[13] = (brg >> 8) & 0xff;
+	memcpy(info->curregs, zscons_regs, sizeof(zscons_regs));
+	memcpy(info->pendregs, zscons_regs, sizeof(zscons_regs));    
+	load_zsregs(info->zs_channel, zscons_regs);
+	ZS_CLEARERR(info->zs_channel);
+	ZS_CLEARFIFO(info->zs_channel);
+	return 0;
+}
+
+static struct console sgi_console_driver = {
+        "ttyS",
+        zs_console_write,       /* write */
+        NULL,                   /* read */
+        zs_console_device,      /* device */
+        zs_console_wait_key,    /* wait_key */
+        NULL,                   /* unblank */
+        zs_console_setup,       /* setup */
+        CON_PRINTBUFFER,
+        -1,
+        0,
+        NULL
+};
+
+/*
+ *	Register console.
+ */
+__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+{
+	register_console(&sgi_console_driver);
+	return kmem_start;
+}
+
+
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/sgiserial.h linux/drivers/sgi/char/sgiserial.h
--- v2.3.8/linux/drivers/sgi/char/sgiserial.h	Sat May 15 15:05:36 1999
+++ linux/drivers/sgi/char/sgiserial.h	Fri Jun 25 17:39:34 1999
@@ -412,7 +412,8 @@
 
 	udelay(2);
 	channel->control = ERR_RES;
-	junk = ioc_icontrol->istat0;
+	if (ioc_icontrol)
+		junk = ioc_icontrol->istat0;
 }
 
 extern inline void ZS_CLEARFIFO(struct sgi_zschannel *channel)
@@ -421,11 +422,17 @@
 
 	udelay(2);
 	junk = channel->data;
-	udelay(2); junk = ioc_icontrol->istat0;
+	udelay(2);
+	if (ioc_icontrol)
+		junk = ioc_icontrol->istat0;
 	junk = channel->data;
-	udelay(2); junk = ioc_icontrol->istat0;
+	udelay(2);
+	if (ioc_icontrol)
+		junk = ioc_icontrol->istat0;
 	junk = channel->data;
-	udelay(2); junk = ioc_icontrol->istat0;
+	udelay(2);
+	if (ioc_icontrol)
+		junk = ioc_icontrol->istat0;
 }
 
 #if 0
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.3.8/linux/drivers/sgi/char/shmiq.c	Sat May 15 15:05:36 1999
+++ linux/drivers/sgi/char/shmiq.c	Fri Jun 25 17:39:34 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: shmiq.c,v 1.12 1999/06/17 13:29:04 ralf Exp $
+ *
  * shmiq.c: shared memory input queue driver
  * written 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
  *
@@ -47,6 +48,7 @@
 #include <linux/sched.h>
 #include <linux/file.h>
 #include <linux/interrupt.h>
+#include <linux/poll.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/major.h>
@@ -82,7 +84,7 @@
 	int    events;
 	int    mapped;
 	
-	wait_queue_head_t     proc_list;
+	wait_queue_head_t    proc_list;
 	struct fasync_struct *fasync;
 } shmiqs [MAX_SHMI_QUEUES];
 
@@ -237,7 +239,7 @@
 	return -EBADF;
 }
 
-extern sys_munmap(unsigned long addr, size_t len);
+extern int sys_munmap(unsigned long addr, size_t len);
 
 static int
 qcntl_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg, int minor)
@@ -394,12 +396,12 @@
 }
 
 static int
-shmiq_qcntl_fasync (struct file *file, int on)
+shmiq_qcntl_fasync (int fd, struct file *file, int on)
 {
 	int retval;
 	int minor = MINOR (file->f_dentry->d_inode->i_rdev);
 
-	retval = fasync_helper (file, on, &shmiqs [minor].fasync);
+	retval = fasync_helper (fd, file, on, &shmiqs [minor].fasync);
 	if (retval < 0)
 		return retval;
 	return 0;
@@ -422,7 +424,7 @@
 		return -EINVAL;
 
 	lock_kernel ();
-	shmiq_qcntl_fasync (filp, 0);
+	shmiq_qcntl_fasync (-1, filp, 0);
 	shmiqs [minor].opened      = 0;
 	shmiqs [minor].mapped      = 0;
 	shmiqs [minor].events      = 0;
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/streamable.c linux/drivers/sgi/char/streamable.c
--- v2.3.8/linux/drivers/sgi/char/streamable.c	Mon Aug 24 13:14:10 1998
+++ linux/drivers/sgi/char/streamable.c	Fri Jun 25 17:39:34 1999
@@ -1,4 +1,5 @@
-/*
+/* $Id: streamable.c,v 1.9 1998/09/19 19:17:50 ralf Exp $
+ *
  * streamable.c: streamable devices. /dev/gfx
  * (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
  *
@@ -51,14 +52,14 @@
 static int
 sgi_gfx_open (struct inode *inode, struct file *file)
 {
-	printk ("GFX: Opened by %d\n", current->pid);
+	printk ("GFX: Opened by %ld\n", current->pid);
 	return 0;
 }
 
 static int
 sgi_gfx_close (struct inode *inode, struct file *file)
 {
-	printk ("GFX: Closed by %d\n", current->pid);
+	printk ("GFX: Closed by %ld\n", current->pid);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/usema.c linux/drivers/sgi/char/usema.c
--- v2.3.8/linux/drivers/sgi/char/usema.c	Sat May 15 15:05:36 1999
+++ linux/drivers/sgi/char/usema.c	Tue Jun 29 09:22:08 1999
@@ -27,11 +27,13 @@
 #include <linux/sched.h>
 #include <linux/file.h>
 #include <linux/major.h>
+#include <linux/poll.h>
 #include <linux/string.h>
 #include <linux/dcache.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
+#include "usema.h"
 
 #include <asm/usioctl.h>
 #include <asm/mman.h>
@@ -42,6 +44,7 @@
 	wait_queue_head_t proc_list;
 };
 
+
 static int
 sgi_usema_attach (usattach_t * attach, struct irix_usema *usema)
 {
@@ -51,7 +54,7 @@
 		return newfd;
 	
 	current->files->fd [newfd] = usema->filp;
-	usema->filp->f_count++;
+	atomic_inc(&usema->filp->f_count);
 	/* Is that it? */
 	printk("UIOCATTACHSEMA: new usema fd is %d", newfd);
 	return newfd;
@@ -64,7 +67,7 @@
 	struct irix_usema *usema = file->private_data;
 	int retval;
 	
-	printk("[%s:%d] wants ioctl 0x%xd (arg 0x%lx)",
+	printk("[%s:%ld] wants ioctl 0x%xd (arg 0x%lx)",
 	       current->comm, current->pid, cmd, arg);
 
 	switch(cmd) {
@@ -76,7 +79,7 @@
 		usattach_t *attach = (usattach_t *)arg;
 		retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
 		if (retval) {
-			printk("[%s:%d] sgi_usema_ioctl(UIOCATTACHSEMA): "
+			printk("[%s:%ld] sgi_usema_ioctl(UIOCATTACHSEMA): "
 			       "verify_area failure",
 			       current->comm, current->pid);
 			return retval;
@@ -84,7 +87,8 @@
 		if (usema == 0)
 			return -EINVAL;
 
-		printk("UIOCATTACHSEMA: attaching usema %p to process %d\n", usema, current->pid);
+		printk("UIOCATTACHSEMA: attaching usema %p to process %ld\n",
+		       usema, current->pid);
 		/* XXX what is attach->us_handle for? */
 		return sgi_usema_attach(attach, usema);
 		break;
@@ -97,12 +101,12 @@
 
 		retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
 		if (retval) {
-			printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
+			printk("[%s:%ld] sgi_usema_ioctl(UIOC*BLOCK): "
 			       "verify_area failure",
 			       current->comm, current->pid);
 			return retval;
 		}
-		printk("UIOC*BLOCK: putting process %d to sleep on usema %p",
+		printk("UIOC*BLOCK: putting process %ld to sleep on usema %p",
 		       current->pid, usema);
 		if (cmd == UIOCNOIBLOCK)
 			interruptible_sleep_on(&usema->proc_list);
@@ -117,13 +121,13 @@
 
 		retval = verify_area(VERIFY_READ, attach, sizeof(usattach_t));
 		if (retval) {
-			printk("[%s:%d] sgi_usema_ioctl(UIOC*BLOCK): "
+			printk("[%s:%ld] sgi_usema_ioctl(UIOC*BLOCK): "
 			       "verify_area failure",
 			       current->comm, current->pid);
 			return retval;
 		}
 
-		printk("[%s:%d] releasing usema %p",
+		printk("[%s:%ld] releasing usema %p",
 		       current->comm, current->pid, usema);
 		wake_up(&usema->proc_list);
 		return 0;
@@ -137,7 +141,8 @@
 {
 	struct irix_usema *usema = filp->private_data;
 	
-	printk("[%s:%d] wants to poll usema %p", current->comm, current->pid, usema);
+	printk("[%s:%ld] wants to poll usema %p",
+	       current->comm, current->pid, usema);
 	
 	return 0;
 }
@@ -152,10 +157,11 @@
 		return -ENOMEM;
 	
 	usema->filp        = filp;
-	usema->proc_list   = NULL;
+	init_waitqueue_head(&usema->proc_list);
 	filp->private_data = usema;
+
 	return 0;
-}	
+}
 
 static int
 sgi_usemaclone_release(struct inode *inode, struct file *filp)
@@ -187,6 +193,7 @@
 void
 usema_init(void)
 {
-	printk("usemaclone misc device registered (minor: %d)\n", SGI_USEMACLONE);
+	printk("usemaclone misc device registered (minor: %d)\n",
+	       SGI_USEMACLONE);
 	misc_register(&dev_usemaclone);
 }
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/usema.h linux/drivers/sgi/char/usema.h
--- v2.3.8/linux/drivers/sgi/char/usema.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sgi/char/usema.h	Fri Jun 25 17:39:35 1999
@@ -0,0 +1,10 @@
+/* usema.h
+ *
+ * Copyright (C) 1996 Alex deVries <puffin@redhat.com>
+ */
+#ifndef _SGI_USEMA_H
+#define _SGI_USEMA_H
+
+void usema_init (void); 
+
+#endif
diff -u --recursive --new-file v2.3.8/linux/drivers/sgi/char/vga_font.c linux/drivers/sgi/char/vga_font.c
--- v2.3.8/linux/drivers/sgi/char/vga_font.c	Wed Dec 10 10:31:11 1997
+++ linux/drivers/sgi/char/vga_font.c	Wed Dec 31 16:00:00 1969
@@ -1,346 +0,0 @@
-#include "gconsole.h"
-
-unsigned char vga_font[cmapsz] = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
-0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
-0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
-0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
-0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
-0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
-0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
-0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
-0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
-0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
-0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
-0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
-0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
-0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
-0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
-0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
-0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
-0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
-0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
-0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
-0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
-0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
-0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
-0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
-0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
-0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
-0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
-0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
-0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
-0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
-0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
-0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
-0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
-0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
-0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
-0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
-0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
-0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
-0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
-0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
-0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
-0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
-0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
-0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
-0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
-0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
-0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
-0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
-0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
-0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
-0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
-0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
-0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
-0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
-0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
-0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
-0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
-0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
-0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
-0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
-0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
-0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
-0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
-0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
-0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
-0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
-0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
-0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
-0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
-0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
-0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-};
diff -u --recursive --new-file v2.3.8/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- v2.3.8/linux/drivers/sound/cmpci.c	Wed May 26 09:35:00 1999
+++ linux/drivers/sound/cmpci.c	Wed Jun 30 11:24:55 1999
@@ -62,6 +62,7 @@
 
 /*****************************************************************************/
       
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/sound/sb_ess.c linux/drivers/sound/sb_ess.c
--- v2.3.8/linux/drivers/sound/sb_ess.c	Wed May 26 09:35:00 1999
+++ linux/drivers/sound/sb_ess.c	Wed Jun 30 11:24:55 1999
@@ -183,6 +183,7 @@
  * ES1946	yes		This is a PCI chip; not handled by this driver
  */
 
+#include <linux/config.h>
 #include <linux/delay.h>
 
 #include "sound_config.h"
diff -u --recursive --new-file v2.3.8/linux/drivers/tc/Makefile linux/drivers/tc/Makefile
--- v2.3.8/linux/drivers/tc/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/tc/Makefile	Fri Jun 25 17:38:40 1999
@@ -0,0 +1,33 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := 
+ALL_SUB_DIRS := 
+
+L_TARGET := tc.a
+L_OBJS   := tc.o
+
+# Nasty trick as nobody references tcsyms.o, but we still want it linked.
+# Stolen from pci Makefile
+ifeq ($(CONFIG_MODULES),y)
+O_TARGET = tc_syms.o
+OX_OBJS  = tcsyms.o
+O_OBJS   = tc.o
+L_OBJS   := tc_syms.o
+else
+L_OBJS   := tc.o
+endif
+
+ifdef CONFIG_ZS
+L_OBJS   += zs.o
+endif
+
+include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.3.8/linux/drivers/tc/tc.c linux/drivers/tc/tc.c
--- v2.3.8/linux/drivers/tc/tc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/tc/tc.c	Fri Jun 25 17:38:40 1999
@@ -0,0 +1,236 @@
+/* $Id: $
+ * tc-init: We assume the TURBOchannel to be up and running so
+ * just probe for Modules and fill in the global data structure
+ * tc_bus.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) Harald Koerfgen, 1998
+ *
+ */
+
+#include <linux/string.h>
+#include <asm/init.h>
+#include <asm/addrspace.h>
+#include <asm/errno.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tcinfo.h>
+#include <asm/dec/tcmodule.h>
+#include <asm/dec/interrupts.h>
+
+#include <asm/ptrace.h>
+#include <linux/kernel.h>
+
+#define TC_DEBUG
+
+slot_info tc_bus[MAX_SLOT];
+static int max_tcslot = 0;
+static tcinfo *info = (tcinfo *)0;
+
+unsigned long system_base = 0;
+
+extern void (*dbe_board_handler)(struct pt_regs *regs);
+extern unsigned long *(*rex_slot_address)(int);
+extern void *(*rex_gettcinfo)(void);
+
+/*
+ * Interface to the world. Read comment in include/asm-mips/tc.h.
+ */
+
+int search_tc_card(char *name)
+{
+	int slot;
+	slot_info *sip;
+
+	for (slot = 0; slot <= max_tcslot; slot++) {
+		sip = &tc_bus[slot];
+		if ((sip->flags & FREE) && (strncmp(sip->name, name, strlen(name)) == 0)) {
+			return slot;
+		}
+	}
+
+	return -ENODEV;
+}
+
+void claim_tc_card(int slot)
+{
+	if (tc_bus[slot].flags & IN_USE) {
+		printk("claim_tc_card: attempting to claim a card already in use\n");
+		return;
+	}
+	tc_bus[slot].flags &= ~FREE;
+	tc_bus[slot].flags |= IN_USE;
+}
+
+void release_tc_card(int slot)
+{
+	if (tc_bus[slot].flags & FREE) {
+		printk("release_tc_card: attempting to release a card already free\n");
+		return;
+	}
+	tc_bus[slot].flags &= ~IN_USE;
+	tc_bus[slot].flags |= FREE;
+}
+
+unsigned long get_tc_base_addr(int slot)
+{
+	return tc_bus[slot].base_addr;
+}
+
+unsigned long get_tc_irq_nr(int slot)
+{
+	return tc_bus[slot].interrupt;
+}
+
+unsigned long get_tc_speed(void)
+{
+	return 100000 * (10000 / (unsigned long)info->clk_period);
+}
+
+/*
+ * Probing for TURBOchannel modules
+ */
+__initfunc(static void my_dbe_handler(struct pt_regs *regs))
+{
+	regs->cp0_epc += 4;
+}
+
+__initfunc(static void tc_probe(unsigned long startaddr, unsigned long size, int max_slot))
+{
+	int i, slot;
+	long offset;
+	unsigned char *module;
+	void (*old_be_handler)(struct pt_regs *regs);
+
+	/* Install our exception handler temporarily */
+
+	old_be_handler = dbe_board_handler;
+	dbe_board_handler = my_dbe_handler;
+	for (slot = 0; slot <= max_slot; slot++) {
+		module = (char *)(startaddr + slot * size);
+		offset = -1;
+		if (module[OLDCARD + PATTERN0] == 0x55 && module[OLDCARD + PATTERN1] == 0x00
+		  && module[OLDCARD + PATTERN2] == 0xaa && module[OLDCARD + PATTERN3] == 0xff)
+			offset = OLDCARD;
+		if (module[PATTERN0] == 0x55 && module[PATTERN1] == 0x00
+		  && module[PATTERN2] == 0xaa && module[PATTERN3] == 0xff)
+			offset = 0;
+
+		if (offset != -1) {
+			tc_bus[slot].base_addr = (unsigned long)module;
+			for(i = 0; i < 8; i++) {
+				tc_bus[slot].firmware[i] = module[FIRM_VER + offset + 4 * i];
+				tc_bus[slot].vendor[i] = module[VENDOR + offset + 4 * i];
+				tc_bus[slot].name[i] = module[MODULE + offset + 4 * i];
+			}
+			tc_bus[slot].firmware[8] = 0;
+			tc_bus[slot].vendor[8] = 0;
+			tc_bus[slot].name[8] = 0;
+			/*
+			 * Looks unneccesary, but we may change
+			 * TC? in the future
+			 */
+			switch (slot) {
+			case 0:
+				tc_bus[slot].interrupt = TC0;
+				break;
+			case 1:
+				tc_bus[slot].interrupt = TC1;
+				break;
+			case 2:
+				tc_bus[slot].interrupt = TC2;
+				break;
+			/*
+			 * Yuck! DS5000/200 onboard devices
+			 */
+			case 5:
+				tc_bus[slot].interrupt = SCSI_INT;
+				break;
+			case 6:
+				tc_bus[slot].interrupt = ETHER;
+				break;
+			default:
+				tc_bus[slot].interrupt = -1;
+				break;
+			}	
+		}
+	}
+
+	dbe_board_handler = old_be_handler;
+}
+
+/*
+ * the main entry
+ */
+__initfunc(void tc_init(void))
+{
+	int tc_clock;
+	int i;
+	unsigned long slot0addr;
+	unsigned long slot_size;
+
+	if (!TURBOCHANNEL)
+		return;
+
+	for (i = 0; i < MAX_SLOT; i++) {
+		tc_bus[i].base_addr = 0;
+		tc_bus[i].name[0] = 0;
+		tc_bus[i].vendor[0] = 0;
+		tc_bus[i].firmware[0] = 0;
+		tc_bus[i].interrupt = -1;
+		tc_bus[i].flags = FREE;
+	}
+
+	info = (tcinfo *) rex_gettcinfo();
+	slot0addr = (unsigned long)KSEG1ADDR(rex_slot_address(0));
+
+	switch (mips_machtype) {
+	case MACH_DS5000_200:
+		max_tcslot = 6;
+		break;
+	case MACH_DS5000_1XX:
+	case MACH_DS5000_2X0:
+		max_tcslot = 2;
+		break;
+	case MACH_DS5000_XX:
+	default:
+		max_tcslot = 1;
+		break;
+	}
+
+	tc_clock = 10000 / info->clk_period;
+
+	if (TURBOCHANNEL && info->slot_size && slot0addr) {
+		printk("TURBOchannel rev. %1d at %2d.%1d MHz ", info->revision,
+			tc_clock / 10, tc_clock % 10);
+		printk("(%sparity)\n", info->parity ? "" : "no ");
+
+		slot_size = info->slot_size << 20;
+
+		tc_probe(slot0addr, slot_size, max_tcslot);
+
+  		/*
+  		 * All TURBOchannel DECstations have the onboard devices
+ 		 * where the (max_tcslot + 1 or 2 on DS5k/xx) Option Module
+ 		 * would be.
+ 		 */
+ 		if(mips_machtype == MACH_DS5000_XX)
+ 			i = 2;
+		else
+ 			i = 1;
+ 		
+ 	        system_base = slot0addr + slot_size * (max_tcslot + i);
+
+#ifdef TC_DEBUG
+		for (i = 0; i <= max_tcslot; i++)
+			if (tc_bus[i].base_addr) {
+				printk("    slot %d: ", i);
+				printk("%s %s %s\n", tc_bus[i].vendor,
+					tc_bus[i].name, tc_bus[i].firmware);
+			}
+#endif
+	}
+
+}
diff -u --recursive --new-file v2.3.8/linux/drivers/tc/tcsyms.c linux/drivers/tc/tcsyms.c
--- v2.3.8/linux/drivers/tc/tcsyms.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/tc/tcsyms.c	Wed Jun 30 11:24:55 1999
@@ -0,0 +1,13 @@
+/*
+ *	Turbo Channel Services -- Exported Symbols
+ *
+ */
+
+#include <linux/module.h>
+#include <asm/dec/tc.h>
+
+EXPORT_SYMBOL(get_tc_irq_nr);
+EXPORT_SYMBOL(claim_tc_card);
+EXPORT_SYMBOL(search_tc_card);
+EXPORT_SYMBOL(get_tc_speed);
+EXPORT_SYMBOL(get_tc_base_addr);
diff -u --recursive --new-file v2.3.8/linux/drivers/tc/zs.c linux/drivers/tc/zs.c
--- v2.3.8/linux/drivers/tc/zs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/tc/zs.c	Fri Jun 25 17:38:40 1999
@@ -0,0 +1,2107 @@
+/*
+ * decserial.c: Serial port driver for IOASIC DECsatations.
+ *
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ *
+ * DECstation changes
+ * Copyright (C) 1998 Harald Koerfgen (Harald.Koerfgen@home.ivm.de)
+ *
+ * For the rest of the code the original Copyright applies:
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Keyboard and mouse are not supported right now. If you want to change this,
+ * you might want to have a look at drivers/sbus/char/sunserial.c to see
+ * how this might be done. HK
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/dec/interrupts.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+#include <asm/dec/ioasic_addrs.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
+
+#include "zs.h"
+
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on NUM_SERIAL, so we could support any number of
+ * Z8530s, but for now...
+ */
+#define NUM_SERIAL	2		/* Max number of ZS chips supported */
+#define NUM_CHANNELS	(NUM_SERIAL * 2)	/* 2 channels per chip */
+
+#define RECOVERY_DELAY  udelay(2)
+
+struct dec_zschannel zs_channels[NUM_CHANNELS];
+
+struct dec_serial zs_soft[NUM_CHANNELS];
+int zs_channels_found;
+struct dec_serial *zs_chain;	/* list of all channels */
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+#endif
+
+#ifdef CONFIG_KGDB
+struct dec_zschannel *zs_kgdbchan;
+static unsigned char scc_inittab[] = {
+	9,  0x80,	/* reset A side (CHRA) */
+	13, 0,		/* set baud rate divisor */
+	12, 1,
+	14, 1,		/* baud rate gen enable, src=rtxc (BRENABL) */
+	11, 0x50,	/* clocks = br gen (RCBR | TCBR) */
+	5,  0x6a,	/* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
+	4,  0x44,	/* x16 clock, 1 stop (SB1 | X16CLK)*/
+	3,  0xc1,	/* rx enable, 8 bits (RxENABLE | Rx8)*/
+};
+#endif
+
+static unsigned char zs_init_regs[16] __initdata = {
+	0,                           /* write 0 */
+	0,			     /* write 1 */
+	0xf0,                        /* write 2 */
+	(Rx8),                       /* write 3 */
+	(X16CLK | SB1),              /* write 4 */
+	(Tx8),                       /* write 5 */
+	0, 0, 0,                     /* write 6, 7, 8 */
+	(VIS),                       /* write 9 */
+	(NRZ),                       /* write 10 */
+	(TCBR | RCBR),               /* write 11 */
+	0, 0,                        /* BRG time constant, write 12 + 13 */
+	(BRSRC | BRENABL),           /* write 14 */
+	0 			     /* write 15 */
+};
+
+#define ZS_CLOCK         7372800 	/* Z8530 RTxC input clock rate */
+
+DECLARE_TASK_QUEUE(tq_zs_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/*
+ * Debugging.
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_THROTTLE
+#undef SERIAL_PARANOIA_CHECK
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void probe_sccs(void);
+static void change_speed(struct dec_serial *info);
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static struct tty_struct *serial_table[NUM_CHANNELS];
+static struct termios *serial_termios[NUM_CHANNELS];
+static struct termios *serial_termios_locked[NUM_CHANNELS];
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct dec_serial *info,
+					dev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%d, %d) in %s\n";
+	static const char *badinfo =
+		"Warning: null mac_serial for (%d, %d) in %s\n";
+
+	if (!info) {
+		printk(badinfo, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 0, 0 };
+
+/* 
+ * Reading and writing Z8530 registers.
+ */
+static inline unsigned char read_zsreg(struct dec_zschannel *channel,
+				       unsigned char reg)
+{
+	unsigned char retval;
+
+	if (reg != 0) {
+		*channel->control = reg & 0xf;
+		RECOVERY_DELAY;
+	}
+	retval = *channel->control;
+	RECOVERY_DELAY;
+	return retval;
+}
+
+static inline void write_zsreg(struct dec_zschannel *channel,
+			       unsigned char reg, unsigned char value)
+{
+	if (reg != 0) {
+		*channel->control = reg & 0xf;
+		RECOVERY_DELAY;
+	}
+	*channel->control = value;
+	RECOVERY_DELAY;
+	return;
+}
+
+static inline unsigned char read_zsdata(struct dec_zschannel *channel)
+{
+	unsigned char retval;
+
+	retval = *channel->data;
+	RECOVERY_DELAY;
+	return retval;
+}
+
+static inline void write_zsdata(struct dec_zschannel *channel,
+				unsigned char value)
+{
+	*channel->data = value;
+	RECOVERY_DELAY;
+	return;
+}
+
+static inline void load_zsregs(struct dec_zschannel *channel,
+			       unsigned char *regs)
+{
+/*	ZS_CLEARERR(channel);
+	ZS_CLEARFIFO(channel); */
+	/* Load 'em up */
+	write_zsreg(channel, R4, regs[R4]);
+	write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+	write_zsreg(channel, R9, regs[R9]);
+	write_zsreg(channel, R1, regs[R1]);
+	write_zsreg(channel, R2, regs[R2]);
+	write_zsreg(channel, R10, regs[R10]);
+	write_zsreg(channel, R11, regs[R11]);
+	write_zsreg(channel, R12, regs[R12]);
+	write_zsreg(channel, R13, regs[R13]);
+	write_zsreg(channel, R14, regs[R14]);
+	write_zsreg(channel, R15, regs[R15]);
+	write_zsreg(channel, R3, regs[R3]);
+	write_zsreg(channel, R5, regs[R5]);
+	return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct dec_serial *ss, int set)
+{
+	if (ss->zs_channel != ss->zs_chan_a) {
+		if (set)
+			ss->zs_chan_a->curregs[5] |= (RTS | DTR);
+		else
+			ss->zs_chan_a->curregs[5] &= ~(RTS | DTR);
+		write_zsreg(ss->zs_chan_a, 5, ss->zs_chan_a->curregs[5]);
+	}
+	return;
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct dec_serial *ss)
+{
+	struct dec_zschannel *channel = ss->zs_channel;
+	int brg;
+
+	/* The baud rate is split up between two 8-bit registers in
+	 * what is termed 'BRG time constant' format in my docs for
+	 * the chip, it is a function of the clk rate the chip is
+	 * receiving which happens to be constant.
+	 */
+	brg = (read_zsreg(channel, 13) << 8);
+	brg |= read_zsreg(channel, 12);
+	return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void rs_recv_clear(struct dec_zschannel *zsc)
+{
+	write_zsreg(zsc, 0, ERR_RES);
+	write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct dec_serial *info,
+				  int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_zs_serial);
+	mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(struct dec_serial *info,
+				   struct pt_regs *regs)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch, stat, flag;
+
+	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
+
+		stat = read_zsreg(info->zs_channel, R1);
+		ch = read_zsdata(info->zs_channel);
+
+#ifdef CONFIG_KGDB
+		if (info->kgdb_channel) {
+			if (ch == 0x03 || ch == '$')
+				breakpoint();
+			if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
+				write_zsreg(info->zs_channel, 0, ERR_RES);
+			return;
+		}
+#endif
+		if (!tty)
+			continue;
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			static int flip_buf_ovf;
+			++flip_buf_ovf;
+			continue;
+		}
+		tty->flip.count++;
+		{
+			static int flip_max_cnt;
+			if (flip_max_cnt < tty->flip.count)
+				flip_max_cnt = tty->flip.count;
+		}
+		if (stat & Rx_OVR) {
+			flag = TTY_OVERRUN;
+		} else if (stat & FRM_ERR) {
+			flag = TTY_FRAME;
+		} else if (stat & PAR_ERR) {
+			flag = TTY_PARITY;
+		} else
+			flag = 0;
+		if (flag)
+			/* reset the error indication */
+			write_zsreg(info->zs_channel, 0, ERR_RES);
+		*tty->flip.flag_buf_ptr++ = flag;
+		*tty->flip.char_buf_ptr++ = ch;
+	}
+	tty_flip_buffer_push(tty);
+}
+
+static void transmit_chars(struct dec_serial *info)
+{
+	if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
+		return;
+	info->tx_active = 0;
+
+	if (info->x_char) {
+		/* Send next char */
+		write_zsdata(info->zs_channel, info->x_char);
+		info->x_char = 0;
+		info->tx_active = 1;
+		return;
+	}
+
+	if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
+		write_zsreg(info->zs_channel, 0, RES_Tx_P);
+		return;
+	}
+	/* Send char */
+	write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
+	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+	info->xmit_cnt--;
+	info->tx_active = 1;
+
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+}
+
+static _INLINE_ void status_handle(struct dec_serial *info)
+{
+	unsigned char status;
+
+	/* Get status from Read Register 0 */
+	status = read_zsreg(info->zs_channel, 0);
+
+	/* FIXEM: Check for DCD transitions */
+	if (((status ^ info->read_reg_zero) & DCD) != 0
+	    && info->tty && !C_CLOCAL(info->tty)) {
+		if (status & DCD) {
+			wake_up_interruptible(&info->open_wait);
+		} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+			if (info->tty)
+				tty_hangup(info->tty);
+		}
+	}
+
+	/* Check for CTS transitions */
+	if (info->tty && C_CRTSCTS(info->tty)) {
+		/*
+		 * For some reason, on the Power Macintosh,
+		 * it seems that the CTS bit is 1 when CTS is
+		 * *negated* and 0 when it is asserted.
+		 * The DCD bit doesn't seem to be inverted
+		 * like this.
+		 */
+		if ((status & CTS) != 0) {
+			if (info->tx_stopped) {
+				info->tx_stopped = 0;
+				if (!info->tx_active)
+					transmit_chars(info);
+			}
+		} else {
+			info->tx_stopped = 1;
+		}
+	}
+
+	/* Clear status condition... */
+	write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+	info->read_reg_zero = status;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct dec_serial *info = (struct dec_serial *) dev_id;
+	unsigned char zs_intreg;
+	int shift;
+
+	/* NOTE: The read register 3, which holds the irq status,
+	 *       does so for both channels on each chip.  Although
+	 *       the status value itself must be read from the A
+	 *       channel and is only valid when read from channel A.
+	 *       Yes... broken hardware...
+	 */
+#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+	if (info->zs_chan_a == info->zs_channel)
+		shift = 3;	/* Channel A */
+	else
+		shift = 0;	/* Channel B */
+
+	for (;;) {
+		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; 
+		if ((zs_intreg & CHAN_IRQMASK) == 0)
+			break;
+
+		if (zs_intreg & CHBRxIP) {
+			receive_chars(info, regs);
+		}
+		if (zs_intreg & CHBTxIP) {
+			transmit_chars(info);
+		}
+		if (zs_intreg & CHBEXT) {
+			status_handle(info);
+		}
+	}
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+#if 1
+	save_flags(flags); cli();
+	if (info->zs_channel->curregs[5] & TxENAB) {
+		info->zs_channel->curregs[5] &= ~TxENAB;
+		write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+	}
+	restore_flags(flags);
+#endif
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_start"))
+		return;
+	
+	save_flags(flags); cli();
+#if 1
+	if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
+		info->zs_channel->curregs[5] |= TxENAB;
+		write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+	}
+#else
+	if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
+		transmit_chars(info);
+	}
+#endif
+	restore_flags(flags);
+}
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+	run_task_queue(&tq_zs_serial);
+}
+
+static void do_softint(void *private_)
+{
+	struct dec_serial	*info = (struct dec_serial *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+static void rs_timer(void)
+{
+}
+
+static int startup(struct dec_serial * info)
+{
+	unsigned long flags;
+
+	if (info->flags & ZILOG_INITIALIZED)
+		return 0;
+
+	if (!info->xmit_buf) {
+		info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		if (!info->xmit_buf)
+			return -ENOMEM;
+	}
+
+	save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+#endif
+
+	/*
+	 * Clear the receive FIFO.
+	 */
+	ZS_CLEARFIFO(info->zs_channel);
+	info->xmit_fifo_size = 1;
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	write_zsreg(info->zs_channel, 0, ERR_RES);
+	write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+	/*
+	 * Turn on RTS and DTR.
+	 */
+	zs_rtsdtr(info, 1);
+
+	/*
+	 * Finally, enable sequencing and interrupts
+	 */
+	info->zs_channel->curregs[1] = (info->zs_channel->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
+	info->zs_channel->curregs[5] |= (TxENAB | Tx8);
+	info->zs_channel->curregs[15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
+	info->zs_channel->curregs[9] |= (VIS | MIE);
+	write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
+	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
+	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+	write_zsreg(info->zs_channel, 15, info->zs_channel->curregs[15]);
+	write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+
+	/*
+	 * And clear the interrupt registers again for luck.
+	 */
+	write_zsreg(info->zs_channel, 0, ERR_RES);
+	write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * Set the speed of the serial port
+	 */
+	change_speed(info);
+
+	/* Save the current value of RR0 */
+	info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+
+	info->flags |= ZILOG_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct dec_serial * info)
+{
+	unsigned long	flags;
+
+	if (!(info->flags & ZILOG_INITIALIZED))
+		return;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....", info->line,
+	       info->irq);
+#endif
+	
+	save_flags(flags); cli(); /* Disable interrupts */
+	
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
+	}
+
+	info->zs_channel->curregs[1] = 0;
+	write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);	/* no interrupts */
+
+	info->zs_channel->curregs[3] &= ~RxENABLE;
+	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
+
+	info->zs_channel->curregs[5] &= ~TxENAB;
+	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+	if (!info->tty || C_HUPCL(info->tty)) {
+		info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
+		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+	}
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ZILOG_INITIALIZED;
+	restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct dec_serial *info)
+{
+	unsigned short port;
+	unsigned cflag;
+	int	i;
+	int	brg;
+	unsigned long flags;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!(port = info->port))
+		return;
+	i = cflag & CBAUD;
+
+	save_flags(flags); cli();
+	info->zs_baud = baud_table[i];
+	info->clk_divisor = 16;
+
+	switch (info->zs_baud) {
+	default:
+		info->zs_channel->curregs[4] = X16CLK;
+		brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+		info->zs_channel->curregs[12] = (brg & 255);
+		info->zs_channel->curregs[13] = ((brg >> 8) & 255);
+	}
+
+	/* byte size and parity */
+	info->zs_channel->curregs[3] &= ~RxNBITS_MASK;
+	info->zs_channel->curregs[5] &= ~TxNBITS_MASK;
+	switch (cflag & CSIZE) {
+	case CS5:
+		info->zs_channel->curregs[3] |= Rx5;
+		info->zs_channel->curregs[5] |= Tx5;
+		break;
+	case CS6:
+		info->zs_channel->curregs[3] |= Rx6;
+		info->zs_channel->curregs[5] |= Tx6;
+		break;
+	case CS7:
+		info->zs_channel->curregs[3] |= Rx7;
+		info->zs_channel->curregs[5] |= Tx7;
+		break;
+	case CS8:
+	default: /* defaults to 8 bits */
+		info->zs_channel->curregs[3] |= Rx8;
+		info->zs_channel->curregs[5] |= Tx8;
+		break;
+	}
+
+	info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+	if (cflag & CSTOPB) {
+		info->zs_channel->curregs[4] |= SB2;
+	} else {
+		info->zs_channel->curregs[4] |= SB1;
+	}
+	if (cflag & PARENB) {
+		info->zs_channel->curregs[4] |= PAR_ENA;
+	}
+	if (!(cflag & PARODD)) {
+		info->zs_channel->curregs[4] |= PAR_EVEN;
+	}
+
+	if (!(cflag & CLOCAL)) {
+		if (!(info->zs_channel->curregs[15] & DCDIE))
+			info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+		info->zs_channel->curregs[15] |= DCDIE;
+	} else
+		info->zs_channel->curregs[15] &= ~DCDIE;
+	if (cflag & CRTSCTS) {
+		info->zs_channel->curregs[15] |= CTSIE;
+		if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
+			info->tx_stopped = 1;
+	} else {
+		info->zs_channel->curregs[15] &= ~CTSIE;
+		info->tx_stopped = 0;
+	}
+
+	/* Load up the new values */
+	load_zsregs(info->zs_channel, info->zs_channel->curregs);
+
+	restore_flags(flags);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	/* Enable transmitter */
+	save_flags(flags); cli();
+	transmit_chars(info);
+	restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, total = 0;
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty || !info->xmit_buf)
+		return 0;
+
+	save_flags(flags);
+	while (1) {
+		cli();		
+		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - info->xmit_head));
+		if (c <= 0)
+			break;
+
+		if (from_user) {
+			down(&tmp_buf_sem);
+			copy_from_user(tmp_buf, buf, c);
+			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);
+			up(&tmp_buf_sem);
+		} else
+			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;
+		total += c;
+	}
+
+	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
+	    && !info->tx_active)
+		transmit_chars(info);
+	restore_flags(flags);
+	return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+	int	ret;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+			
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+	cli();
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	sti();
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+	unsigned long flags;
+
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		save_flags(flags); cli();
+		info->x_char = STOP_CHAR(tty);
+		if (!info->tx_active)
+			transmit_chars(info);
+		restore_flags(flags);
+	}
+
+	if (C_CRTSCTS(tty)) {
+		/*
+		 * Here we want to turn off the RTS line.  On Macintoshes,
+		 * we only get the DTR line, which goes to both DTR and
+		 * RTS on the modem.  RTS doesn't go out to the serial
+		 * port socket.  So you should make sure your modem is
+		 * set to ignore DTR if you're using CRTSCTS.
+		 */
+		save_flags(flags); cli();
+		info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
+		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+		restore_flags(flags);
+	}
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+	unsigned long flags;
+
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		save_flags(flags); cli();
+		if (info->x_char)
+			info->x_char = 0;
+		else {
+			info->x_char = START_CHAR(tty);
+			if (!info->tx_active)
+				transmit_chars(info);
+		}
+		restore_flags(flags);
+	}
+
+	if (C_CRTSCTS(tty)) {
+		/* Assert RTS and DTR lines */
+		save_flags(flags); cli();
+		info->zs_chan_a->curregs[5] |= DTR | RTS;
+		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+		restore_flags(flags);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct dec_serial * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = info->type;
+	tmp.line = info->line;
+	tmp.port = info->port;
+	tmp.irq = info->irq;
+	tmp.flags = info->flags;
+	tmp.baud_base = info->baud_base;
+	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.custom_divisor = info->custom_divisor;
+	return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+}
+
+static int set_serial_info(struct dec_serial * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+	struct dec_serial old_info;
+	int 			retval = 0;
+
+	if (!new_info)
+		return -EFAULT;
+	copy_from_user(&new_serial,new_info,sizeof(new_serial));
+	old_info = *info;
+
+	if (!suser()) {
+		if ((new_serial.baud_base != info->baud_base) ||
+		    (new_serial.type != info->type) ||
+		    (new_serial.close_delay != info->close_delay) ||
+		    ((new_serial.flags & ~ZILOG_USR_MASK) !=
+		     (info->flags & ~ZILOG_USR_MASK)))
+			return -EPERM;
+		info->flags = ((info->flags & ~ZILOG_USR_MASK) |
+			       (new_serial.flags & ZILOG_USR_MASK));
+		info->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	if (info->count > 1)
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	info->baud_base = new_serial.baud_base;
+	info->flags = ((info->flags & ~ZILOG_FLAGS) |
+			(new_serial.flags & ZILOG_FLAGS));
+	info->type = new_serial.type;
+	info->close_delay = new_serial.close_delay;
+	info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+	retval = startup(info);
+	return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct dec_serial * info, unsigned int *value)
+{
+	unsigned char status;
+
+	cli();
+	status = read_zsreg(info->zs_channel, 0);
+	sti();
+	put_user(status,value);
+	return 0;
+}
+
+static int get_modem_info(struct dec_serial *info, unsigned int *value)
+{
+	unsigned char control, status;
+	unsigned int result;
+
+	cli();
+	control = info->zs_chan_a->curregs[5];
+	status = read_zsreg(info->zs_channel, 0);
+	sti();
+	result =  ((control & RTS) ? TIOCM_RTS: 0)
+		| ((control & DTR) ? TIOCM_DTR: 0)
+		| ((status  & DCD) ? TIOCM_CAR: 0)
+		| ((status  & CTS) ? 0: TIOCM_CTS);
+	put_user(result,value);
+	return 0;
+}
+
+static int set_modem_info(struct dec_serial *info, unsigned int cmd,
+			  unsigned int *value)
+{
+	int error;
+	unsigned int arg, bits;
+
+	error = verify_area(VERIFY_READ, value, sizeof(int));
+	if (error)
+		return error;
+	get_user(arg, value);
+	bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
+	cli();
+	switch (cmd) {
+	case TIOCMBIS:
+		info->zs_chan_a->curregs[5] |= bits;
+		break;
+	case TIOCMBIC:
+		info->zs_chan_a->curregs[5] &= ~bits;
+		break;
+	case TIOCMSET:
+		info->zs_chan_a->curregs[5] = (info->zs_chan_a->curregs[5] & ~(DTR | RTS)) | bits;
+		break;
+	default:
+		sti();
+		return -EINVAL;
+	}
+	write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+	sti();
+	return 0;
+}
+
+/*
+ * rs_break - turn transmit break condition on/off
+ */
+static void rs_break(struct tty_struct *tty, int break_state)
+{
+	struct dec_serial *info = (struct dec_serial *) tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_break"))
+		return;
+	if (!info->port)
+		return;
+
+	save_flags(flags); cli();
+	if (break_state == -1)
+		info->zs_channel->curregs[5] |= SND_BRK;
+	else
+		info->zs_channel->curregs[5] &= ~SND_BRK;
+	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+	restore_flags(flags);
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error;
+	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
+
+#ifdef CONFIG_KGDB
+	if (info->kgdb_channel)
+		return -ENODEV;
+#endif
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TIOCMGET:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned int));
+			if (error)
+				return error;
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+		case TIOCGSERIAL:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct serial_struct));
+			if (error)
+				return error;
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSERGETLSR: /* Get line status register */
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned int));
+			if (error)
+				return error;
+			else
+			    return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct dec_serial));
+			if (error)
+				return error;
+			copy_from_user((struct dec_serial *) arg,
+				       info, sizeof(struct dec_serial));
+			return 0;
+			
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
+	int was_stopped;
+
+	if (tty->termios->c_cflag == old_termios->c_cflag)
+		return;
+	was_stopped = info->tx_stopped;
+
+	change_speed(info);
+
+	if (was_stopped && !info->tx_stopped)
+		rs_start(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.
+ * Wait for the last remaining data to be sent.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+	
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		restore_flags(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  Info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk("rs_close: bad serial port count for ttys%d: %d\n",
+		       info->line, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ZILOG_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ZILOG_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ZILOG_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receiver and receive interrupts.
+	 */
+	info->zs_channel->curregs[3] &= ~RxENABLE;
+	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
+	info->zs_channel->curregs[1] = 0;	/* disable any rx ints */
+	write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
+	ZS_CLEARFIFO(info->zs_channel);
+	if (info->flags & ZILOG_INITIALIZED) {
+		/*
+		 * Before we drop DTR, make sure the SCC transmitter
+		 * has completely drained.
+		 */
+		rs_wait_until_sent(tty, info->timeout);
+	}
+
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
+			 ZILOG_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	restore_flags(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct dec_serial *info = (struct dec_serial *) tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+
+	if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+		return;
+
+	orig_jiffies = jiffies;
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 */
+	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+	char_time = char_time / 5;
+	if (char_time == 0)
+		char_time = 1;
+	if (timeout)
+		char_time = MIN(char_time, timeout);
+	while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
+		current->state = TASK_INTERRUPTIBLE;
+		current->counter = 0;	/* make us low-priority */
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && ((orig_jiffies + timeout) < jiffies))
+			break;
+	}
+	current->state = TASK_RUNNING;
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+
+	rs_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	info->count = 0;
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct dec_serial *info)
+{
+	struct wait_queue wait = { current, NULL };
+	int		retval;
+	int		do_clocal = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (info->flags & ZILOG_CLOSING) {
+		interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ZILOG_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ZILOG_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (info->flags & ZILOG_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (info->flags & ZILOG_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ZILOG_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ZILOG_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ZILOG_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ZILOG_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	cli();
+	if (!tty_hung_up_p(filp)) 
+		info->count--;
+	sti();
+	info->blocked_open++;
+	while (1) {
+		cli();
+		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (tty->termios->c_cflag & CBAUD))
+			zs_rtsdtr(info, 1);
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ZILOG_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    !(info->flags & ZILOG_CLOSING) &&
+		    (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, info->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		info->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ZILOG_NORMAL_ACTIVE;
+	return 0;
+}	
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its ZILOG structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct dec_serial	*info;
+	int 			retval, line;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= zs_channels_found))
+		return -ENODEV;
+	info = zs_soft + line;
+
+#ifdef CONFIG_KGDB
+	if (info->kgdb_channel)
+		return -ENODEV;
+#endif
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
+		return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->count);
+#endif
+
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	/*
+	 * If the port is the middle of closing, bail out now
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ZILOG_CLOSING)) {
+		if (info->flags & ZILOG_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		return ((info->flags & ZILOG_HUP_NOTIFY) ?
+			-EAGAIN : -ERESTARTSYS);
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("rs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
+
+	if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else 
+			*tty->termios = info->callout_termios;
+		change_speed(info);
+	}
+#ifdef CONFIG_SERIAL_CONSOLE
+	if (sercons.cflag && sercons.index == line) {
+		tty->termios->c_cflag = sercons.cflag;
+		sercons.cflag = 0;
+		change_speed(info);
+	}
+#endif
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open ttys%d successful...", info->line);
+#endif
+/* tty->low_latency = 1; */
+	return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+__initfunc(static void show_serial_version(void))
+{
+	printk("DECstation Z8530 serial driver version 0.03\n");
+}
+
+/*  Initialize Z8530s zs_channels
+ */
+
+__initfunc(static void probe_sccs(void))
+{
+	struct dec_serial **pp;
+	int i, n, n_chips = 0, n_channels, chip, channel;
+	unsigned long flags;
+
+	/*
+	 * did we get here by accident?
+	 */
+	if(!IOASIC) {
+		printk("Not on JUNKIO machine, skipping probe_sccs\n");
+		return;
+	}
+	
+	/*
+	 * When serial console is activated, tc_init has not been called yet
+	 * and system_base is undefined. Unfortunately we have to hardcode
+	 * system_base for this case :-(. HK
+	 */
+	switch(mips_machtype) {
+	case MACH_DS5000_2X0:
+		system_base = 0xbf800000;
+		n_chips = 2;
+		break;
+	case MACH_DS5000_1XX:
+		system_base = 0xbc000000;
+		n_chips = 2;
+		break;
+	case MACH_DS5000_XX:
+		system_base = 0xbc000000;
+		n_chips = 1;
+		break;
+	}
+
+	pp = &zs_chain;
+
+	n_channels = 0;
+
+	for (chip = 0; chip < n_chips; chip++) {
+		for (channel = 0; channel <= 1; channel++) {
+			/*
+			 * The sccs reside on the high byte of the 16 bit IOBUS
+			 */
+			zs_channels[n_channels].control = (volatile unsigned char *)
+				system_base + (0 == chip ? SCC0 : SCC1) + (0 == channel ? 1 : 9);
+			zs_channels[n_channels].data = zs_channels[n_channels].control + 4;
+			zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
+			zs_soft[n_channels].irq = SERIAL;
+
+			if (0 == channel)
+				zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels+1];
+			else
+				zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels];
+
+			*pp = &zs_soft[n_channels];
+			pp = &zs_soft[n_channels].zs_next;
+			n_channels++;
+		}
+	}
+
+	*pp = 0;
+	zs_channels_found = n_channels;
+
+	for (n = 0; n < zs_channels_found; n++) {
+		for (i = 0; i < 16; i++) {
+			zs_soft[n].zs_channel->curregs[i] = zs_init_regs[i];
+		}
+	}
+
+/*	save_and_cli(flags);
+	for (n = 0; n < zs_channels_found; n++) {
+		if (((int)zs_channels[n].control & 0xf) == 1) {
+			write_zsreg(zs_soft[channel].zs_chan_a, R9, FHWRES);
+			udelay(10000);
+			write_zsreg(zs_soft[channel].zs_chan_a, R9, 0);
+		}
+		load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs);
+	} 
+	restore_flags(flags); */
+}
+
+/* zs_init inits the driver */
+__initfunc(int zs_init(void))
+{
+	int channel, i;
+	unsigned long flags;
+	struct dec_serial *info;
+
+	if(!IOASIC)
+		return -ENODEV;
+
+	/* Setup base handler, and timer table. */
+	init_bh(SERIAL_BH, do_serial_bh);
+	timer_table[RS_TIMER].fn = rs_timer;
+	timer_table[RS_TIMER].expires = 0;
+
+	/* Find out how many Z8530 SCCs we have */
+	if (zs_chain == 0)
+		probe_sccs();
+
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	/* Not all of this is exactly right for us. */
+
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = zs_channels_found;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+
+	serial_driver.init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_open;
+	serial_driver.close = rs_close;
+	serial_driver.write = rs_write;
+	serial_driver.flush_chars = rs_flush_chars;
+	serial_driver.write_room = rs_write_room;
+	serial_driver.chars_in_buffer = rs_chars_in_buffer;
+	serial_driver.flush_buffer = rs_flush_buffer;
+	serial_driver.ioctl = rs_ioctl;
+	serial_driver.throttle = rs_throttle;
+	serial_driver.unthrottle = rs_unthrottle;
+	serial_driver.set_termios = rs_set_termios;
+	serial_driver.stop = rs_stop;
+	serial_driver.start = rs_start;
+	serial_driver.hangup = rs_hangup;
+	serial_driver.break_ctl = rs_break;
+	serial_driver.wait_until_sent = rs_wait_until_sent;
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+
+	save_flags(flags); cli();
+
+	for (channel = 0; channel < zs_channels_found; ++channel) {
+#ifdef CONFIG_KGDB
+		if (zs_soft[channel].kgdb_channel) {
+			continue;
+		}
+#endif
+		zs_soft[channel].clk_divisor = 16;
+		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+
+		if (request_irq(SERIAL, rs_interrupt, SA_SHIRQ,
+				"SCC", &zs_soft[channel]))
+			printk(KERN_ERR "decserial: can't get irq %d\n",
+			       SERIAL);
+
+		/* If console serial line, then enable interrupts. */
+/*		if (zs_soft[channel].is_cons) {
+			write_zsreg(zs_soft[channel].zs_channel, R1,
+				    (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
+			write_zsreg(zs_soft[channel].zs_channel, R9,
+				    (VIS | MIE));
+		}
+*/
+	}
+
+	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
+	{
+#ifdef CONFIG_KGDB
+		if (info->kgdb_channel) {
+			continue;
+		}
+#endif
+		info->magic = SERIAL_MAGIC;
+		info->port = (int) info->zs_channel->control;
+		info->line = i;
+		info->tty = 0;
+		info->custom_divisor = 16;
+		info->close_delay = 50;
+		info->closing_wait = 3000;
+		info->x_char = 0;
+		info->event = 0;
+		info->count = 0;
+		info->blocked_open = 0;
+		info->tqueue.routine = do_softint;
+		info->tqueue.data = info;
+		info->callout_termios =callout_driver.init_termios;
+		info->normal_termios = serial_driver.init_termios;
+		info->open_wait = 0;
+		info->close_wait = 0;
+		printk("tty%02d at 0x%08x (irq = %d)", info->line, 
+		       info->port, info->irq);
+		printk(" is a Z85C30 SCC\n");
+	}
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* PowerMac: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+	return -1;
+}
+
+void unregister_serial(int line)
+{
+	return;
+}
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ */
+
+/* This is for console output */
+static void
+zs_console_putchar(struct dec_serial *info, char ch)
+{
+	int loops = 10000;
+	unsigned long flags;
+
+	if(!info->zs_channel)
+		return;
+
+	save_flags(flags); cli();
+
+	while (!(*(info->zs_channel->control) & Tx_BUF_EMP) && --loops)
+		RECOVERY_DELAY;
+	*(info->zs_channel->data) = ch;
+	RECOVERY_DELAY;
+
+	restore_flags(flags);
+}
+
+static void serial_console_write(struct console *co, const char *s,
+				 unsigned count)
+{
+	struct dec_serial *info;
+	int i;
+	unsigned char nine;
+
+	info = zs_soft + co->index;
+
+#if 0
+	/*
+	 * disable master interrupt if necessary
+	 */
+	nine = info->zs_channel->curregs[9];
+	if(nine & MIE)
+		write_zsreg(info->zs_channel, R9, nine & ~MIE);
+#endif
+	/*
+	 * do it
+	 */
+	for (i = 0; i < count; i++, s++) {
+		if(*s == '\n')
+			zs_console_putchar(info, '\r');
+		zs_console_putchar(info, *s);
+	}
+	/*
+	 * restore master interrupt enable
+	 */
+#if 0
+	write_zsreg(info->zs_channel, R9, nine);
+#endif
+}
+
+/*
+ *	Receive character from the serial port
+ */
+static int serial_console_wait_key(struct console *co)
+{
+	return 0;
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ *	Setup initial baud/bits/parity. We do two things here:
+ *	- construct a cflag setting for the first rs_open()
+ *	- initialize the serial port
+ *	Return non-zero if we didn't find a serial port.
+ */
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+	struct dec_serial *info;
+	int	baud = 9600;
+	int	bits = 8;
+	int	parity = 'n';
+	int	cflag = CREAD | HUPCL | CLOCAL;
+	char	*s;
+	unsigned long flags;
+
+	if(!IOASIC)
+		return -ENODEV;
+
+	info = zs_soft + co->index;
+
+	if (zs_chain == 0)
+		probe_sccs();
+
+	info->is_cons = 1;
+
+	if (options) {
+		baud = simple_strtoul(options, NULL, 10);
+		s = options;
+		while(*s >= '0' && *s <= '9')
+			s++;
+		if (*s)
+			parity = *s++;
+		if (*s)
+			bits   = *s - '0';
+	}
+
+	/*
+	 *	Now construct a cflag setting.
+	 */
+	switch(baud) {
+	case 1200:
+		cflag |= B1200;
+		break;
+	case 2400:
+		cflag |= B2400;
+		break;
+	case 4800:
+		cflag |= B4800;
+		break;
+	case 19200:
+		cflag |= B19200;
+		break;
+	case 38400:
+		cflag |= B38400;
+		break;
+	case 57600:
+		cflag |= B57600;
+		break;
+	case 115200:
+		cflag |= B115200;
+		break;
+	case 9600:
+	default:
+		cflag |= B9600;
+		break;
+	}
+	switch(bits) {
+	case 7:
+		cflag |= CS7;
+		break;
+	default:
+	case 8:
+		cflag |= CS8;
+		break;
+	}
+	switch(parity) {
+	case 'o': case 'O':
+		cflag |= PARODD;
+		break;
+	case 'e': case 'E':
+		cflag |= PARENB;
+		break;
+	}
+	co->cflag = cflag;
+#if 1 
+	save_and_cli(flags);
+
+	/*
+	 * Turn on RTS and DTR.
+	 */
+	zs_rtsdtr(info, 1);
+
+	/*
+	 * Finally, enable sequencing
+	 */
+	info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
+	info->zs_channel->curregs[5] |= (TxENAB | Tx8);
+	info->zs_channel->curregs[9] |= (VIS);
+	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
+	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
+	write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	write_zsreg(info->zs_channel, 0, ERR_RES);
+	write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+	/*
+	 * Set the speed of the serial port
+	 */
+	change_speed(info);
+
+	/* Save the current value of RR0 */
+	info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+
+	zs_soft[co->index].clk_divisor = 16;
+	zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
+
+	restore_flags(flags);
+#endif
+	return 0;
+}
+
+static struct console sercons = {
+	"ttyS",
+	serial_console_write,
+	NULL,
+	serial_console_device,
+	serial_console_wait_key,
+	NULL,
+	serial_console_setup,
+	CON_PRINTBUFFER,
+	-1,
+	0,
+	NULL
+};
+
+/*
+ *	Register console.
+ */
+__initfunc (long zs_serial_console_init(long kmem_start, long kmem_end))
+{
+	register_console(&sercons);
+	return kmem_start;
+}
+#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+
+#ifdef CONFIG_KGDB
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+	struct dec_zschannel *chan = zs_kgdbchan;
+	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+		RECOVERY_DELAY;
+	write_zsdata(chan, kgdb_char);
+}
+char getDebugChar(void)
+{
+	struct dec_zschannel *chan = zs_kgdbchan;
+	while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+		eieio(); /*barrier();*/
+	return read_zsdata(chan);
+}
+void kgdb_interruptible(int yes)
+{
+	struct dec_zschannel *chan = zs_kgdbchan;
+	int one, nine;
+	nine = read_zsreg(chan, 9);
+	if (yes == 1) {
+		one = EXT_INT_ENAB|INT_ALL_Rx;
+		nine |= MIE;
+		printk("turning serial ints on\n");
+	} else {
+		one = RxINT_DISAB;
+		nine &= ~MIE;
+		printk("turning serial ints off\n");
+	}
+	write_zsreg(chan, 1, one);
+	write_zsreg(chan, 9, nine);
+}
+/* This sets up the serial port we're using, and turns on
+ * interrupts for that channel, so kgdb is usable once we're done.
+ */
+static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps)
+{
+	int brg;
+	int i, x;
+	volatile char *sccc = ms->control;
+	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+	printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
+	for (i = 20000; i != 0; --i) {
+		x = *sccc; eieio();
+	}
+	for (i = 0; i < sizeof(scc_inittab); ++i) {
+		write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
+		i++;
+	}
+}
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line.  The 'tty_num' argument is 0 for /dev/ttya and 1
+ * for /dev/ttyb which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+__initfunc(void zs_kgdb_hook(int tty_num))
+{
+	/* Find out how many Z8530 SCCs we have */
+	if (zs_chain == 0)
+		probe_sccs();
+	zs_soft[tty_num].zs_channel = &zs_channels[tty_num];
+	zs_kgdbchan = zs_soft[tty_num].zs_channel;
+	zs_soft[tty_num].change_needed = 0;
+	zs_soft[tty_num].clk_divisor = 16;
+	zs_soft[tty_num].zs_baud = 38400;
+	zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
+	zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+	/* Turn on transmitter/receiver at 8-bits/char */
+        kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
+	printk("KGDB: on channel %d initialized\n", tty_num);
+	set_debug_traps(); /* init stub */
+}
+#endif /* ifdef CONFIG_KGDB */
diff -u --recursive --new-file v2.3.8/linux/drivers/tc/zs.h linux/drivers/tc/zs.h
--- v2.3.8/linux/drivers/tc/zs.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/tc/zs.h	Fri Jun 25 17:38:40 1999
@@ -0,0 +1,405 @@
+/*
+ * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _DECSERIAL_H
+#define _DECSERIAL_H
+
+#define NUM_ZSREGS    16
+
+struct serial_struct {
+	int	type;
+	int	line;
+	int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	reserved_char[2];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	int	reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF	0
+#define ZILOG_CLOSING_WAIT_NONE	65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+				   on the callout port */
+#define ZILOG_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK	0x0004	/* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK	0x0030
+#define ZILOG_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST	0x0030  /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS	0x0FFF	/* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430	/* Legal flags that non-privileged
+				 * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED	0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct dec_zschannel {
+	volatile unsigned char *control;
+	volatile unsigned char *data;
+
+	/* Current write register values */
+	unsigned char curregs[NUM_ZSREGS];
+};
+
+struct dec_serial {
+	struct dec_serial *zs_next;	/* For IRQ servicing chain */
+	struct dec_zschannel *zs_channel; /* Channel registers */
+	struct dec_zschannel *zs_chan_a;	/* A side registers */
+	unsigned char read_reg_zero;
+
+	char soft_carrier;  /* Use soft carrier on this channel */
+	char break_abort;   /* Is serial console in, so process brk/abrt */
+	char kgdb_channel;  /* Kgdb is running on this channel */
+	char is_cons;       /* Is this our console. */
+	unsigned char tx_active; /* character is being xmitted */
+	unsigned char tx_stopped; /* output is suspended */
+
+	/* We need to know the current clock divisor
+	 * to read the bps rate the chip has currently
+	 * loaded.
+	 */
+	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+	int zs_baud;
+
+	char change_needed;
+
+	int			magic;
+	int			baud_base;
+	int			port;
+	int			irq;
+	int			flags; 		/* defined in tty.h */
+	int			type; 		/* UART type */
+	struct tty_struct 	*tty;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			timeout;
+	int			xmit_fifo_size;
+	int			custom_divisor;
+	int			x_char;	/* xon/xoff character */
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
+	unsigned long		last_active;
+	int			line;
+	int			count;	    /* # of fd on device */
+	int			blocked_open; /* # of blocked opens */
+	long			session; /* Session of opening process */
+	long			pgrp; /* pgrp of opening process */
+	unsigned char 		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct tq_struct	tqueue;
+	struct tq_struct	tqueue_hangup;
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP	0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define	FLAG	0x7e
+
+/* Write Register 0 */
+#define	R0	0		/* Register selects */
+#define	R1	1
+#define	R2	2
+#define	R3	3
+#define	R4	4
+#define	R5	5
+#define	R6	6
+#define	R7	7
+#define	R8	8
+#define	R9	9
+#define	R10	10
+#define	R11	11
+#define	R12	12
+#define	R13	13
+#define	R14	14
+#define	R15	15
+
+#define	NULLCODE	0	/* Null Code */
+#define	POINT_HIGH	0x8	/* Select upper half of registers */
+#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
+#define	SEND_ABORT	0x18	/* HDLC Abort */
+#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
+#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
+#define	ERR_RES		0x30	/* Error Reset */
+#define	RES_H_IUS	0x38	/* Reset highest IUS */
+
+#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
+#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
+#define	RES_EOM_L	0xC0	/* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
+#define	TxINT_ENAB	0x2	/* Tx Int Enable */
+#define	PAR_SPEC	0x4	/* Parity is special condition */
+
+#define	RxINT_DISAB	0	/* Rx Int Disable */
+#define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
+#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
+#define	INT_ERR_Rx	0x18	/* Int on error only */
+
+#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
+#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
+#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define	RxENABLE	0x1	/* Rx Enable */
+#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
+#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
+#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
+#define	ENT_HM		0x10	/* Enter Hunt Mode */
+#define	AUTO_ENAB	0x20	/* Auto Enables */
+#define	Rx5		0x0	/* Rx 5 Bits/Character */
+#define	Rx7		0x40	/* Rx 7 Bits/Character */
+#define	Rx6		0x80	/* Rx 6 Bits/Character */
+#define	Rx8		0xc0	/* Rx 8 Bits/Character */
+#define RxNBITS_MASK	0xc0
+
+/* Write Register 4 */
+
+#define	PAR_ENA		0x1	/* Parity Enable */
+#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
+
+#define	SYNC_ENAB	0	/* Sync Modes Enable */
+#define	SB1		0x4	/* 1 stop bit/char */
+#define	SB15		0x8	/* 1.5 stop bits/char */
+#define	SB2		0xc	/* 2 stop bits/char */
+#define SB_MASK		0xc
+
+#define	MONSYNC		0	/* 8 Bit Sync character */
+#define	BISYNC		0x10	/* 16 bit sync character */
+#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
+#define	EXTSYNC		0x30	/* External Sync Mode */
+
+#define	X1CLK		0x0	/* x1 clock mode */
+#define	X16CLK		0x40	/* x16 clock mode */
+#define	X32CLK		0x80	/* x32 clock mode */
+#define	X64CLK		0xC0	/* x64 clock mode */
+#define XCLK_MASK	0xC0
+
+/* Write Register 5 */
+
+#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
+#define	RTS		0x2	/* RTS */
+#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
+#define	TxENAB		0x8	/* Tx Enable */
+#define	SND_BRK		0x10	/* Send Break */
+#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
+#define	Tx7		0x20	/* Tx 7 bits/character */
+#define	Tx6		0x40	/* Tx 6 bits/character */
+#define	Tx8		0x60	/* Tx 8 bits/character */
+#define TxNBITS_MASK	0x60
+#define	DTR		0x80	/* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define	VIS	1	/* Vector Includes Status */
+#define	NV	2	/* No Vector */
+#define	DLC	4	/* Disable Lower Chain */
+#define	MIE	8	/* Master Interrupt Enable */
+#define	STATHI	0x10	/* Status high */
+#define SOFTACK 0x20    /* Software Interrupt Acknowledge */
+#define	NORESET	0	/* No reset on write to R9 */
+#define	CHRB	0x40	/* Reset channel B */
+#define	CHRA	0x80	/* Reset channel A */
+#define	FHWRES	0xc0	/* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define	BIT6	1	/* 6 bit/8bit sync */
+#define	LOOPMODE 2	/* SDLC Loop mode */
+#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
+#define	MARKIDLE 8	/* Mark/flag on idle */
+#define	GAOP	0x10	/* Go active on poll */
+#define	NRZ	0	/* NRZ mode */
+#define	NRZI	0x20	/* NRZI mode */
+#define	FM1	0x40	/* FM1 (transition = 1) */
+#define	FM0	0x60	/* FM0 (transition = 0) */
+#define	CRCPS	0x80	/* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define	TRxCXT	0	/* TRxC = Xtal output */
+#define	TRxCTC	1	/* TRxC = Transmit clock */
+#define	TRxCBR	2	/* TRxC = BR Generator Output */
+#define	TRxCDP	3	/* TRxC = DPLL output */
+#define	TRxCOI	4	/* TRxC O/I */
+#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
+#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
+#define	TCBR	0x10	/* Transmit clock = BR Generator output */
+#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
+#define	RCRTxCP	0	/* Receive clock = RTxC pin */
+#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
+#define	RCBR	0x40	/* Receive clock = BR Generator output */
+#define	RCDPLL	0x60	/* Receive clock = DPLL output */
+#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* Write Register 13 (upper byte of baud rate generator time constant) */
+
+/* Write Register 14 (Misc control bits) */
+#define	BRENABL	1	/* Baud rate generator enable */
+#define	BRSRC	2	/* Baud rate generator source */
+#define	DTRREQ	4	/* DTR/Request function */
+#define	AUTOECHO 8	/* Auto Echo */
+#define	LOOPBAK	0x10	/* Local loopback */
+#define	SEARCH	0x20	/* Enter search mode */
+#define	RMC	0x40	/* Reset missing clock */
+#define	DISDPLL	0x60	/* Disable DPLL */
+#define	SSBR	0x80	/* Set DPLL source = BR generator */
+#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
+#define	SFMM	0xc0	/* Set FM mode */
+#define	SNRZI	0xe0	/* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define	ZCIE	2	/* Zero count IE */
+#define	DCDIE	8	/* DCD IE */
+#define	SYNCIE	0x10	/* Sync/hunt IE */
+#define	CTSIE	0x20	/* CTS IE */
+#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
+#define	BRKIE	0x80	/* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define	Rx_CH_AV	0x1	/* Rx Character Available */
+#define	ZCOUNT		0x2	/* Zero count */
+#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
+#define	DCD		0x8	/* DCD */
+#define	SYNC_HUNT	0x10	/* Sync/hunt */
+#define	CTS		0x20	/* CTS */
+#define	TxEOM		0x40	/* Tx underrun */
+#define	BRK_ABRT	0x80	/* Break/Abort */
+
+/* Read Register 1 */
+#define	ALL_SNT		0x1	/* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define	RES3		0x8	/* 0/3 */
+#define	RES4		0x4	/* 0/4 */
+#define	RES5		0xc	/* 0/5 */
+#define	RES6		0x2	/* 0/6 */
+#define	RES7		0xa	/* 0/7 */
+#define	RES8		0x6	/* 0/8 */
+#define	RES18		0xe	/* 1/8 */
+#define	RES28		0x0	/* 2/8 */
+/* Special Rx Condition Interrupts */
+#define	PAR_ERR		0x10	/* Parity error */
+#define	Rx_OVR		0x20	/* Rx Overrun Error */
+#define	FRM_ERR		0x40	/* CRC/Framing Error */
+#define	END_FR		0x80	/* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
+#define	CHBTxIP	0x2		/* Channel B Tx IP */
+#define	CHBRxIP	0x4		/* Channel B Rx IP */
+#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
+#define	CHATxIP	0x10		/* Channel A Tx IP */
+#define	CHARxIP	0x20		/* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define	ONLOOP	2		/* On loop */
+#define	LOOPSEND 0x10		/* Loop sending */
+#define	CLK2MIS	0x40		/* Two clocks missing */
+#define	CLK1MIS	0x80		/* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    (write_zsreg(channel, 0, ERR_RES))
+#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
+				     garbage = read_zsdata(channel); \
+				     garbage = read_zsdata(channel); \
+				     garbage = read_zsdata(channel); \
+				} while(0)
+
+#endif /* !(_DECSERIAL_H) */
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/README.ohci linux/drivers/usb/README.ohci
--- v2.3.8/linux/drivers/usb/README.ohci	Tue Jun  8 10:52:26 1999
+++ linux/drivers/usb/README.ohci	Fri Jun 25 14:30:28 1999
@@ -1,3 +1,21 @@
+[This is the readme for ohci.c, ohci-debug.c and ohci.h]
+
+June 23, 1999 00:31:20 PST
+
+I now have bulk support in a reasonably working state.  The only
+device I have tested it with at the moment is my Epson Stylus 740
+printer.  I can print both small and large files.
+
+I have included code to support transfers of large amounts of data in
+either control or bulk transfers.  Check out the build_td_chain() and
+add_td_chain_to_ed() functions.
+
+TODO:
+
+~ Get Michael Gee's mass storage driver working with my donated
+  YE-Data floppy drive over OHCI.
+~ Drool on the Epson printer because its the new toy around the house.
+
 June 08, 1999 01:23:34
 
 Paul Mackerras went through the OHCI (& USB code) to fix most of the
@@ -12,12 +30,6 @@
 
 TODO:
 
-~ Add the concept of a td_group to lump TDs associated with a single
-  data transfer request from the higher layers.  This will be needed
-  for bulk and all larger transfers that will span multiple TDs but
-  which need to allocate/free them as a group as things happen.  I
-  am thinking about create_td_group and free_td_group functions...
-~ Add bulk transfer support.
 ~ Add Isochronous transfer support.  These have their own special
   format TDs to allow for several DMA data pointers.  Kinda neat, but
   likely harder to use through a generic interface in practice.
@@ -32,7 +44,7 @@
   called using the "IRQ handle" that should be returned by
   usb_request_irq().
 
-May 09, 1999 16:25:58
+May 09, 1999 16:25:58 PST
 
 Cool, things are working "well" now.  (I'm not getting oops's from the
 OHCI code anyways.. ;).  I can attach a usb hub and mouse in any
@@ -42,19 +54,6 @@
 acknowledged because /proc/interrupts usb-ohci goes up accordingly with
 mouse movements/events.  That means the TD at least returns some data
 and requeues itself.
-
-Device attach/detach from the root hub is not working well.  Currently
-every interrupt checks for root hub status changes and frame number
-overflow interrupts are enabled.  This means you shouldn't have to
-wait more than 32-33 seconds for the change to occur, less if there is
-other activity.  (due to checking in the WDH caused interrupts)
-My OHCI controller [SiS 5598 motherboard] doesn't seem to play well
-with the RHSC interrupt so it has been disabled.  The ohci_timer
-should be polling but it not currently working, I haven't had time to
-look into that problem.
-
-However, when I tried telling X to use /dev/psaux for the mouse my
-machine locked up...
 
 - greg@electricrain.com
 
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/acm.c linux/drivers/usb/acm.c
--- v2.3.8/linux/drivers/usb/acm.c	Sun Jun 20 18:51:52 1999
+++ linux/drivers/usb/acm.c	Wed Jun 30 11:24:55 1999
@@ -26,7 +26,6 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <asm/spinlock.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/audio.c linux/drivers/usb/audio.c
--- v2.3.8/linux/drivers/usb/audio.c	Sun Jun 20 18:51:52 1999
+++ linux/drivers/usb/audio.c	Wed Jun 30 11:24:55 1999
@@ -3,7 +3,6 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include "usb.h"
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.8/linux/drivers/usb/cpia.c	Sun Jun 20 18:51:52 1999
+++ linux/drivers/usb/cpia.c	Wed Jun 30 11:24:55 1999
@@ -17,7 +17,6 @@
 #include <linux/videodev.h>
 #include <linux/vmalloc.h>
 #include <linux/wrapper.h>
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <asm/spinlock.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.3.8/linux/drivers/usb/hub.c	Sun Jun 20 18:51:52 1999
+++ linux/drivers/usb/hub.c	Wed Jun 30 11:24:55 1999
@@ -10,7 +10,6 @@
 #include <linux/list.h>
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <asm/spinlock.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
--- v2.3.8/linux/drivers/usb/mouse.c	Sun Jun 20 18:51:52 1999
+++ linux/drivers/usb/mouse.c	Wed Jun 30 11:24:55 1999
@@ -33,7 +33,6 @@
 #include <linux/poll.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
-#include <linux/config.h>
 #include <linux/module.h>
 
 #include <asm/spinlock.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/ohci-debug.c linux/drivers/usb/ohci-debug.c
--- v2.3.8/linux/drivers/usb/ohci-debug.c	Tue Jun  8 10:52:26 1999
+++ linux/drivers/usb/ohci-debug.c	Fri Jun 25 14:30:28 1999
@@ -124,7 +124,9 @@
 		td_cc_accessed(*td) ? "" : "Not ",
 		td_active(*td) ? "" : "Not ");
 
-	printk(KERN_DEBUG "        %s\n", td_allocated(*td) ? "Allocated" : "Free");
+	printk(KERN_DEBUG "        %s%s\n",
+		td_allocated(*td) ? "Allocated" : "Free",
+		td_dummy(*td) ? " DUMMY" : "");
 
 	printk(KERN_DEBUG "      cur_buf  =  0x%x\n", le32_to_cpup(&td->cur_buf));
 	printk(KERN_DEBUG "      next_td  =  0x%x\n", le32_to_cpup(&td->next_td));
@@ -139,6 +141,26 @@
 			d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7] );
 	}
 } /* show_ohci_td() */
+
+
+void show_ohci_td_chain(struct ohci_td *td)
+{
+	struct ohci_td *cur_td;
+	if (td == NULL) return;
+
+	printk(KERN_DEBUG "+++ OHCI TD Chain %lx: +++\n", virt_to_bus(td));
+
+	cur_td = td;
+	for (;;) {
+		show_ohci_td(cur_td);
+		if (!cur_td->next_td) break;
+		cur_td = bus_to_virt(le32_to_cpup(&cur_td->next_td));
+		/* we can't trust -anything- we find inside of a dummy TD */
+		if (td_dummy(*cur_td)) break;
+	}
+
+	printk(KERN_DEBUG "--- End  TD Chain %lx: ---\n", virt_to_bus(td));
+} /* show_ohci_td_chain () */
 
 
 void show_ohci_device(struct ohci_device *dev)
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.8/linux/drivers/usb/ohci.c	Sun Jun 20 18:55:52 1999
+++ linux/drivers/usb/ohci.c	Fri Jun 25 14:30:28 1999
@@ -2,19 +2,14 @@
  * Open Host Controller Interface driver for USB.
  *
  * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
+ * Significant code from the following individuals has also been used:
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> [ohci-hcd.c]
+ * (C) Copyright 1999 Linus Torvalds [uhci.c]
  *
  * This is the "other" host controller interface for USB.  You will
  * find this on many non-Intel based motherboards, and of course the
- * Mac.  As Linus hacked his UHCI driver together first, I modeled
- * this after his.. (it should be obvious)
- *
- * From the programming standpoint the OHCI interface seems a little
- * prettier and potentially less CPU intensive.  This remains to be
- * proven.  In reality, I don't believe it'll make one darn bit of
- * difference.  USB v1.1 is a slow bus by today's standards.
- *
- * OHCI hardware takes care of most of the scheduling of different
- * transfer types with the correct prioritization for us.
+ * Mac.  As Linus hacked his UHCI driver together first, I originally
+ * modeled this after his.. (it should be obvious)
  *
  * To get started in USB, I used the "Universal Serial Bus System
  * Architecture" book by Mindshare, Inc.  It was a reasonable introduction
@@ -76,6 +71,7 @@
 #define FIELDS_OF_TD(t)	le32_to_cpup(&t->info), le32_to_cpup(&t->cur_buf), \
 			le32_to_cpup(&t->next_td), le32_to_cpup(&t->buf_end)
 
+#ifdef OHCI_DEBUG
 static const char *cc_names[16] = {
 	"no error",
 	"CRC error",
@@ -94,6 +90,7 @@
 	"not accessed (14)",
 	"not accessed"
 };
+#endif
 
 /*
  * Add a chain of TDs to the end of the TD list on a given ED.
@@ -152,6 +149,36 @@
 } /* ohci_add_td_to_ed() */
 
 
+/*
+ * Add a whole chain of TDs to an ED using the above function.
+ * The same restrictions apply.
+ *
+ * XXX This function is being removed in the future! XXX
+ */
+static struct ohci_td *ohci_add_td_chain_to_ed(struct ohci_td *td, struct ohci_ed *ed)
+{
+	struct ohci_td *cur_td;
+	if (!td)
+		return NULL;
+
+	/* Find the last TD in this chain, storing its pointer in cur_td */
+	cur_td = td;
+	for (;;) {
+		__u32 next_td = cur_td->next_td;
+
+		/* advance to the next td, exit if there isn't one */
+		if (!next_td)
+			break;
+		cur_td = bus_to_virt(le32_to_cpup(&next_td));
+	}
+
+	return td = ohci_add_td_to_ed(td, cur_td, ed);
+} /* ohci_add_td_chain_to_ed() */
+
+
+/* .......... */
+
+
 inline void ohci_start_control(struct ohci *ohci)
 {
 	/* tell the HC to start processing the control list */
@@ -474,7 +501,7 @@
 }
 
 /*
- *  Remove a TD from the given EDs TD list.
+ *  Remove a TD from the given EDs TD list.  The TD is freed as well.
  */
 static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
 {
@@ -484,11 +511,11 @@
 	if ((td == NULL) || (ed == NULL))
 		return;
 
-	spin_lock_irqsave(&ohci_edtd_lock, flags);
-
 	if (ed_head_td(ed) == 0)
 		return;
 
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+
 	/* set the "skip me bit" in this ED */
 	ed->status |= cpu_to_le32(OHCI_ED_SKIP);
 
@@ -569,6 +596,10 @@
 /*
  * Get a pointer (virtual) to an available TD from the given device's
  * pool.  Return NULL if none are left.
+ *
+ * NOTE: This function does not allocate and attach the dummy_td.
+ * That is done in ohci_fill_ed().  FIXME: it should probably be moved
+ * into here.
  */
 static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
 {
@@ -593,6 +624,11 @@
 } /* ohci_get_free_ed() */
 
 
+/*
+ * Free an OHCI ED and all of the TDs on its list.  It is assumed that
+ * this ED is not active.  You should call ohci_wait_for_ed_safe()
+ * beforehand if you can't guarantee that.
+ */
 void ohci_free_ed(struct ohci_ed *ed)
 {
 	if (!ed)
@@ -692,6 +728,140 @@
 } /* ohci_fill_ed() */
 
 
+/*
+ *  Create a chain of Normal TDs to be used for a large data transfer
+ *  (bulk or control).
+ *
+ *  Returns the head TD in the chain.
+ */
+struct ohci_td *ohci_build_td_chain(struct ohci_device *dev, void *data, unsigned int len, int dir, __u32 toggle, int round, int auto_free, void* dev_id, usb_device_irq handler, __u32 next_td)
+{
+	struct ohci_td *head, *cur_td;
+	__u32 bus_data_start, bus_data_end;
+	unsigned short max_page0_len;
+
+	if (!data || (len == 0))
+		return NULL;
+
+	/* Setup the first TD, leaving buf_end = 0 */
+	head = ohci_get_free_td(dev);
+	if (head == NULL) {
+		printk(KERN_ERR "usb-ohci: out of TDs\n");
+		return NULL;
+	}
+
+	ohci_fill_new_td(head,
+		td_set_dir_out(dir),
+		toggle & OHCI_TD_DT,
+		(round ? OHCI_TD_ROUND : 0),
+		data, 0,
+		dev_id, handler);
+	if (!auto_free)
+		noauto_free_td(head);
+
+	cur_td = head;
+
+	/* AFICT, that the OHCI controller takes care of the innards of
+	 * bulk & control data transfers by sending zero length
+	 * packets as necessary if the transfer falls on an even packet
+	 * size boundary, we don't need a special TD for that. */
+
+	while (len > 0) {
+		bus_data_start = virt_to_bus(data);
+		bus_data_end = virt_to_bus(data+(len-1));
+
+		/* check the 4096 byte alignment of the start of the data */
+		max_page0_len = 0x1000 - (bus_data_start & 0xfff);
+
+		/* check if the remaining data occupies more than two pages */
+		if ((max_page0_len < len) && (len - max_page0_len > 0x1000)) {
+			struct ohci_td *new_td;
+
+			/* Point this TD to data up through the end of
+			 * the second page */
+			cur_td->buf_end = bus_data_start +
+				(max_page0_len + 0xfff);
+
+			/* adjust the data pointer & remaining length */
+			data += (max_page0_len + 0x1000);
+			len  -= (max_page0_len + 0x1000);
+
+			/* TODO lookup effect of rounding bit on
+			 * individual TDs vs. whole TD chain transfers;
+			 * disable cur_td's rounding bit here if needed. */
+
+			/* mark that this is not the last TD... */
+			clear_td_endofchain(cur_td);
+
+			/* allocate another td */
+			new_td = ohci_get_free_td(dev);
+			if (new_td == NULL) {
+				printk(KERN_ERR "usb-ohci: out of TDs\n");
+				/* FIXME: free any allocated TDs */
+				return NULL;
+			}
+
+			ohci_fill_new_td(new_td,
+				td_set_dir_out(dir),
+				TOGGLE_AUTO,  /* toggle Data0/1 via the ED */
+				round ? OHCI_TD_ROUND : 0,
+				data, 0,
+				dev_id, handler);
+			if (!auto_free)
+				noauto_free_td(new_td);
+
+			/* Link the new TD to the chain & advance */
+			cur_td->next_td = virt_to_bus(new_td);
+			cur_td = new_td;
+		} else {
+			/* Last TD in this chain, normal buf_end is fine */
+			cur_td->buf_end = bus_data_end;
+
+			set_td_endofchain(cur_td);
+
+			len = 0;
+			break;
+		}
+	} /* while */
+
+	/* link the given next_td to the end of this chain */
+	cur_td->next_td = next_td;
+
+	return head;
+} /* ohci_build_td_chain() */
+
+
+/*
+ * Compute the number of bytes that have been transferred on a given
+ * TD.  Do not call this on TDs that are active on the host
+ * controller.
+ */
+static __u16 ohci_td_bytes_done(struct ohci_td *td)
+{
+	__u16 result;
+	__u32 bus_data_start, bus_data_end;
+
+	bus_data_start = virt_to_bus(td->data);
+	if (!td->data || !bus_data_start)
+		return 0;
+
+	/* if cur_buf is 0, all data has been transferred */
+	bus_data_end = td->cur_buf ? td->cur_buf : td->buf_end;
+
+	/* is it on the same page? */
+	if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) {
+		result = bus_data_end - bus_data_start + 1;
+	} else {
+		/* compute the amount transferred on the first page */
+		result = 0x1000 - (bus_data_start & 0xfff);
+		/* add the amount done in the second page */
+		result += (bus_data_end & 0xfff) + 1;
+	}
+
+	return result;
+} /* ohci_td_bytes_done() */
+
+
 /**********************************
  * OHCI interrupt list operations *
  **********************************/
@@ -762,6 +932,10 @@
 	/* 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;
 } /* ohci_request_irq() */
 
@@ -794,8 +968,7 @@
  * Send or receive a control message on a "pipe"
  *
  * The cmd parameter is a pointer to the 8 byte setup command to be
- * sent.  FIXME:  This is a devrequest in usb.h.  The function
- * should be updated to accept a devrequest* instead of void*..
+ * sent.
  *
  * A control message contains:
  *   - The command itself
@@ -811,7 +984,6 @@
 	struct ohci_ed *control_ed = ohci_get_free_ed(dev);
 	struct ohci_td *setup_td, *data_td, *status_td;
 	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
 	int completion_status = -1;
 	devrequest our_cmd;
 
@@ -861,57 +1033,17 @@
 	ohci_fill_new_td(setup_td, OHCI_TD_D_SETUP, TOGGLE_DATA0,
 			OHCI_TD_IOC_OFF,
 			&our_cmd, 8,	/* cmd is always 8 bytes long */
-			NULL, NULL);
+			&completion_status, NULL);
 
-	/* allocate the next TD */
-	data_td = ohci_get_free_td(dev);
-	if (!data_td) {
-		printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl data]\n", dev);
+	/* Allocate a TD for the control xfer status */
+	status_td = ohci_get_free_td(dev);
+	if (!status_td) {
+		printk("usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev);
 		ohci_free_td(setup_td);
 		ohci_free_ed(control_ed);
 		return -1;
 	}
 
-	/* link to the next TD */
-	setup_td->next_td = cpu_to_le32(virt_to_bus(data_td));
-
-	if (len > 0) {
-
-		/* build the Control DATA TD, it starts with a DATA1. */
-		ohci_fill_new_td(data_td, td_set_dir_out(usb_pipeout(pipe)),
-				TOGGLE_DATA1,
-				OHCI_TD_ROUND | OHCI_TD_IOC_OFF,
-				data, len,
-				NULL, NULL);
-
-		/*
-		 * TODO: Normal TDs can transfer up to 8192 bytes on OHCI.
-		 * However, for that to happen, the data must -start-
-		 * on a nice 4kb page.  We need to check for data
-		 * sizes > 4096 and, if they cross more than two 4096
-		 * byte pages of memory one or more additional TDs
-		 * will need to be created.  (repeat doing this in a
-		 * loop until all of the DATA is on a TD)
-		 *
-		 * Control transfers are -highly unlikely- to need to
-		 * transfer this much data.. but who knows.. sadistic
-		 * hardware is sure to exist.
-		 */
-
-		status_td = ohci_get_free_td(dev);  /* TODO check for NULL */
-		if (!status_td) {
-			printk(KERN_ERR "usb-ohci: couldn't get TD for dev %p [cntl status]\n", dev);
-			ohci_free_td(setup_td);
-			ohci_free_td(data_td);
-			ohci_free_ed(control_ed);
-			return -1;
-		}
-
-		data_td->next_td = cpu_to_le32(virt_to_bus(status_td));
-	} else {
-		status_td = data_td; /* no data_td, use it for status */
-	}
-
 	/* The control status packet always uses a DATA1
 	 * Give "dev_id" the address of completion_status so that the
 	 * TDs status can be passed back to us from the IRQ. */
@@ -923,27 +1055,44 @@
 			&completion_status, ohci_control_completed);
 	status_td->next_td = 0; /* end of TDs */
 
+	/* If there is data to transfer, create the chain of data TDs
+	 * followed by the status TD. */
+	if (len > 0) {
+		data_td = ohci_build_td_chain( dev, data, len,
+				usb_pipeout(pipe), TOGGLE_DATA1,
+				1 /* round */, 1 /* autofree */,
+				&completion_status, NULL /* no handler here */,
+				virt_to_bus(status_td) );
+		if (!data_td) {
+			printk(KERN_ERR "usb-ohci: couldn't allocate control data TDs for dev %p\n", dev);
+			ohci_free_td(setup_td);
+			ohci_free_td(status_td);
+			ohci_free_ed(control_ed);
+			return -1;
+		}
+
+		/* link the to the data & status TDs */
+		setup_td->next_td = virt_to_bus(data_td);
+	} else {
+		/* no data TDs, link to the status TD */
+		setup_td->next_td = virt_to_bus(status_td);
+	}
+
 	/*
-	 * Add the chain of 2-3 control TDs to the control ED's TD list
+	 * Add the control TDs to the control ED (setup_td is the first)
 	 */
-	spin_lock_irqsave(&ohci_edtd_lock, flags);
-	setup_td = ohci_add_td_to_ed(setup_td, status_td, control_ed);
-	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+	setup_td = ohci_add_td_chain_to_ed(setup_td, control_ed);
+  	control_ed->status &= ~OHCI_ED_SKIP;
+  	ohci_unhalt_ed(control_ed);
 
 #ifdef OHCI_DEBUG
 	if (MegaDebug) {
 	/* complete transaction debugging output (before) */
 	printk(KERN_DEBUG " Control ED %lx:\n", virt_to_bus(control_ed));
 	show_ohci_ed(control_ed);
-	printk(KERN_DEBUG " Setup TD %lx:\n", virt_to_bus(setup_td));
-	show_ohci_td(setup_td);
-	if (data_td != status_td) {
-		printk(KERN_DEBUG " Data TD %lx:\n", virt_to_bus(data_td));
-		show_ohci_td(data_td);
-	}
-	printk(KERN_DEBUG " Status TD %lx:\n", virt_to_bus(status_td));
-	show_ohci_td(status_td);
-	printk(KERN_DEBUG " Controller Status:\n");
+	printk(KERN_DEBUG " Control TD chain:\n");
+	show_ohci_td_chain(setup_td);
+	printk(KERN_DEBUG " OHCI Controller Status:\n");
 	show_ohci_status(dev->ohci);
 	}
 #endif
@@ -966,19 +1115,15 @@
 	/* complete transaction debugging output (after) */
 	printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed));
 	show_ohci_ed(control_ed);
-	printk(KERN_DEBUG " *after* Setup TD %lx:\n", virt_to_bus(setup_td));
-	show_ohci_td(setup_td);
-	if (data_td != status_td) {
-		printk(KERN_DEBUG " *after* Data TD %lx:\n", virt_to_bus(data_td));
-		show_ohci_td(data_td);
-	}
-	printk(KERN_DEBUG " *after* Status TD %lx:\n", virt_to_bus(status_td));
-	show_ohci_td(status_td);
-	printk(KERN_DEBUG " *after* Controller Status:\n");
+	printk(KERN_DEBUG " *after* Control TD chain:\n");
+	show_ohci_td_chain(setup_td);
+	printk(KERN_DEBUG " *after* OHCI Controller Status:\n");
 	show_ohci_status(dev->ohci);
 	}
 #endif
 
+	/* no TD cleanup, the TDs were auto-freed as they finished */
+
 	/* remove the control ED from the HC */
 	ohci_remove_control_ed(dev->ohci, control_ed);
 	ohci_free_ed(control_ed);	 /* return it to the pool */
@@ -1008,6 +1153,219 @@
 } /* ohci_control_msg() */
 
 
+/**********************************************************************
+ *  Bulk transfer processing
+ **********************************************************************/
+
+/*
+ * Internal state for an ohci_bulk_request
+ */
+struct ohci_bulk_request_state {
+	struct usb_device *usb_dev;
+	unsigned int	pipe;		/* usb "pipe" */
+	void		*data;		/* ptr to data */
+	int		length;		/* length to transfer */
+	int		_bytes_done;	/* bytes transferred so far */
+	unsigned long	*bytes_transferred_p;	/* where to increment */
+	void		*dev_id;	/* pass to the completion handler */
+	usb_device_irq	completion;	/* completion handler */
+};
+
+/*
+ * this handles the individual TDs of a (possibly) larger bulk
+ * request.  It keeps track of the total bytes transferred, calls the
+ * final completion handler, etc.
+ */
+static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id)
+{
+	struct ohci_bulk_request_state *req;
+
+	req = (struct ohci_bulk_request_state *) dev_id;
+
+#ifdef OHCI_DEBUG
+	printk(KERN_DEBUG "ohci_bulk_td_handler stats %x, buffer %p, len %d, req %p\n", stats, buffer, len, req);
+#endif
+
+	/* only count TDs that were completed successfully */
+	if (stats == USB_ST_NOERROR)
+		req->_bytes_done += len;
+
+#ifdef OHCI_DEBUG
+	printk(KERN_DEBUG "ohci_bulk_td_handler %d bytes done\n", req->_bytes_done);
+#endif
+
+	/* call the real completion handler when done or on an error */
+	if ((stats != USB_ST_NOERROR) ||
+	    (req->_bytes_done >= req->length && req->completion != NULL)) {
+		*req->bytes_transferred_p += req->_bytes_done;
+#ifdef OHCI_DEBUG
+		printk(KERN_DEBUG "usb-ohci: bulk request %p ending after %d bytes\n", req, req->_bytes_done);
+#endif
+		req->completion(stats, buffer, req->_bytes_done, req->dev_id);
+	}
+
+	return 0;	/* do not re-queue the TD */
+} /* ohci_bulk_td_handler() */
+
+
+/*
+ * Request to send or receive bulk data.  The completion() function
+ * will be called when the transfer has completed or been aborted due
+ * to an error.
+ *
+ * bytes_transferred_p is a pointer to an integer that will be
+ * -incremented- by the number of bytes that have been successfully
+ * transferred.  The interrupt handler will update it after each
+ * internal TD completes successfully.
+ *
+ * This function can NOT be called from an interrupt (?)
+ * (TODO: verify & fix this if needed).
+ *
+ * Returns: a pointer to the ED being used for this request.  At the
+ * moment, removing & freeing it is the responsibilty of the caller.
+ */
+static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_request)
+{
+	/* local names for the readonly fields */
+	struct usb_device *usb_dev = bulk_request->usb_dev;
+	unsigned int pipe = bulk_request->pipe;
+	void *data = bulk_request->data;
+	int len = bulk_request->length;
+
+	struct ohci_device *dev = usb_to_ohci(usb_dev);
+	struct ohci_ed *bulk_ed;
+	struct ohci_td *head_td;
+	unsigned long flags;
+
+#ifdef OHCI_DEBUG 
+	printk(KERN_DEBUG "ohci_request_bulk(%p) ohci_dev %p, completion %p, pipe %x, data %p, len %d\n", bulk_request, dev, bulk_request->completion, pipe, data, len);
+#endif
+
+	bulk_ed = ohci_get_free_ed(dev);
+	if (!bulk_ed) {
+		printk("usb-ohci: couldn't get ED for dev %p\n", dev);
+		return NULL;
+	}
+
+	/* allocate & fill in the TDs for this request */
+	head_td = ohci_build_td_chain(dev, data, len, usb_pipeout(pipe),
+			TOGGLE_AUTO,
+			0 /* round not required */, 1 /* autofree */,
+			bulk_request,  /* dev_id: the bulk_request  */
+			ohci_bulk_td_handler,
+			0 /* no additional TDs */);
+	if (!head_td) {
+		printk("usb-ohci: couldn't get TDs for dev %p\n", dev);
+		ohci_free_ed(bulk_ed);
+		return NULL;
+	}
+
+	/* Set the max packet size, device speed, endpoint number, usb
+	 * device number (function address), and type of TD. */
+	ohci_fill_ed(dev, bulk_ed,
+		usb_maxpacket(usb_dev, pipe),
+		usb_pipeslow(pipe),
+		usb_pipe_endpdev(pipe), 0 /* bulk uses normal TDs */);
+
+	/* initialize the internal counter */
+	bulk_request->_bytes_done = 0;
+
+	/*
+	 * Add the TDs to the ED
+	 */
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+	bulk_ed->status |= OHCI_ED_SKIP;
+	head_td = ohci_add_td_chain_to_ed(head_td, bulk_ed);
+	bulk_ed->status &= ~OHCI_ED_SKIP;
+	ohci_unhalt_ed(bulk_ed);
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+
+
+#ifdef OHCI_DEBUG
+/*	if (MegaDebug) { */
+	/* complete transaction debugging output (before) */
+	printk(KERN_DEBUG " Bulk ED %lx:\n", virt_to_bus(bulk_ed));
+	show_ohci_ed(bulk_ed);
+	printk(KERN_DEBUG " Bulk TDs %lx:\n", virt_to_bus(head_td));
+	show_ohci_td_chain(head_td);
+/*	} */
+#endif
+
+	/* Give the ED to the HC */
+	ohci_add_bulk_ed(dev->ohci, bulk_ed);
+
+	return bulk_ed;
+} /* ohci_request_bulk() */
+
+
+static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup);
+
+
+static int ohci_bulk_msg_completed(int stats, void *buffer, int len, void *dev_id)
+{
+	if (dev_id != NULL) {
+		int *completion_status = (int *)dev_id;
+		*completion_status = stats;
+	}
+
+	wake_up(&bulk_wakeup);
+	return 0;	/* don't requeue the TD */
+} /* ohci_bulk_msg_completed() */
+
+
+static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, unsigned long *bytes_transferred_p)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int completion_status = USB_ST_INTERNALERROR;
+	struct ohci_bulk_request_state req;
+	struct ohci_ed *req_ed;
+
+	/* ....... */
+
+#ifdef OHCI_DEBUG 
+	printk(KERN_DEBUG "ohci_bulk_msg %p pipe %x, data %p, len %d, bytes_transferred %p\n", usb_dev, pipe, data, len, bytes_transferred_p);
+#endif
+
+	req.usb_dev = usb_dev;
+	req.pipe = pipe;
+	req.data = data;
+	req.length = len;
+	req.bytes_transferred_p = bytes_transferred_p;
+	req.dev_id = &completion_status;
+	req.completion = ohci_bulk_msg_completed;
+
+	/*
+	 * Start the transaction..
+	 */
+	current->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue(&bulk_wakeup, &wait);
+
+	req_ed = ohci_request_bulk(&req);
+
+	/* FIXME this should to wait for a caller specified time... */
+	schedule_timeout(HZ*5);
+
+#ifdef OHCI_DEBUG
+	printk(KERN_DEBUG "ohci_bulk_msg request completed or timed out w/ status %x\n", completion_status);
+#endif
+
+	remove_wait_queue(&bulk_wakeup, &wait);
+
+	/* remove the ED from the HC */
+	ohci_remove_bulk_ed(usb_to_ohci(usb_dev)->ohci, req_ed);
+	ohci_free_ed(req_ed);	 /* return it to the pool */
+
+#ifdef OHCI_DEBUG
+	printk(KERN_DEBUG "ohci_bulk_msg done.\n");
+#endif
+
+	return completion_status;
+} /* ohci_bulk_msg() */
+
+
+/* .......... */
+
+
 /*
  * Allocate a new USB device to be attached to an OHCI controller
  */
@@ -1079,8 +1437,6 @@
 	return 0;
 }
 
-/* FIXME! */
-#define ohci_bulk_msg NULL
 
 /*
  * functions for the generic USB driver
@@ -1404,6 +1760,7 @@
 {
 	struct ohci_td *td;		/* used for walking the list */
 
+	/* um... isn't this dangerous to do in an interrupt handler? -greg */
 	spin_lock(&ohci_edtd_lock);
 
 	/* create the FIFO ordered donelist */
@@ -1416,18 +1773,12 @@
 		if (td_dummy(*td))
 			printk(KERN_ERR "yikes! reaping a dummy TD\n");
 
-		/* FIXME: munge td->info into a future standard status format */
-
-		if (cc != 0 && ohci_ed_halted(td->ed) && td->completed == 0) {
+		if (cc != 0 && ohci_ed_halted(td->ed) && !td_endofchain(*td)) {
 			/*
 			 * There was an error on this TD and the ED
 			 * is halted, and this was not the last TD
 			 * of the transaction, so there will be TDs
 			 * to clean off the ED.
-			 * (We assume that a TD with a non-NULL completed
-			 * field is the last one of a transaction.
-			 * Ultimately we should have a flag in the TD
-			 * to say that it is the last one.)
 			 */
 			struct ohci_ed *ed = td->ed;
 			struct ohci_td *tail_td = bus_to_virt(ed_tail_td(ed));
@@ -1437,17 +1788,27 @@
 			td = ntd = bus_to_virt(ed_head_td(ed));
 			while (td != tail_td) {
 				ntd = bus_to_virt(le32_to_cpup(&td->next_td));
-				if (td->completed != 0)
-					break;
-				ohci_free_td(td);
+
+				/* only deal with TDs from this ED,
+				 * the host controller could have
+				 * processed other endpoints at the
+				 * same time as this one.. */
+				if (td->ed == ed) {
+					if (td_endofchain(*td))
+						break;
+
+					/* FIXME: unlink this TD from the
+					 * reverse donelist! */
+					ohci_free_td(td);
+				}
+
 				td = ntd;
 			}
 			/* Set the ED head past the ones we cleaned
 			   off, and clear the halted flag */
 			set_ed_head_td(ed, virt_to_bus(ntd));
 			ohci_unhalt_ed(ed);
-			/* If we didn't find a TD with a completion
-			   routine, give up */
+			/* If we didn't find an endofchain TD, give up */
 			if (td == tail_td) {
 				td = next_td;
 				continue;
@@ -1456,7 +1817,7 @@
 
 		/* Check if TD should be re-queued */
 		if ((td->completed != NULL) &&
-		    (td->completed(cc, td->data, -1 /* XXX */, td->dev_id))) {
+		    (td->completed(cc, td->data, ohci_td_bytes_done(td), td->dev_id))) {
 			/* Mark the TD as active again:
 			 * Set the not accessed condition code
 			 * Reset the Error count
@@ -1473,7 +1834,8 @@
 			ohci_add_td_to_ed(td, td, td->ed);
 		} else {
 			/* return it to the pool of free TDs */
-			ohci_free_td(td);
+			if (can_auto_free(*td))
+				ohci_free_td(td);
 		}
 
 		td = next_td;
@@ -1516,6 +1878,13 @@
 	/* Disable HC interrupts */ /* why? - paulus */
 	writel(OHCI_INTR_MIE, &regs->intrdisable);
 
+#if 0
+	/* Only do this for SERIOUS debugging, be sure kern.debug logs
+	 * are not going to the console as this can cause your
+	 * machine to lock up if so... -greg */
+	show_ohci_status(ohci);
+#endif
+
 	/* Process the done list */
 	if (context & OHCI_INTR_WDH) {
 		/* See which TD's completed.. */
@@ -1856,9 +2225,11 @@
 				show_ohci_status(ohci);
 			} else if (signr == SIGUSR2) {
 				/* toggle mega TD/ED debugging output */
+#ifdef OHCI_DEBUG
 				MegaDebug = !MegaDebug;
 				printk(KERN_DEBUG "usb-ohci: Mega debugging %sabled.\n",
 						MegaDebug ? "en" : "dis");
+#endif
 			} else {
 				/* unknown signal, exit the thread */
 				break;
@@ -2084,9 +2455,6 @@
 } /* ohci_init */
 
 
-/* vim:sw=8
- */
-
 #ifdef MODULE
 /*
  *  Clean up when unloading the module
@@ -2103,4 +2471,5 @@
 }
 #endif //MODULE
 
-
+/* vim:sw=8
+ */
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h
--- v2.3.8/linux/drivers/usb/ohci.h	Tue Jun  8 10:52:26 1999
+++ linux/drivers/usb/ohci.h	Fri Jun 25 14:30:28 1999
@@ -38,10 +38,12 @@
 	void *data;			/* virt. address of the the buffer */
 	usb_device_irq completed;	/* Completion handler routine */
 	int hcd_flags;			/* Flags for the HCD: */
-		/* bit0 = boolean: Is this TD allocated? */
-		/* bit1 = boolean: Is this a dummy (end of list) TD? */
+		/* bit0: Is this TD allocated? */
+		/* bit1: Is this a dummy (end of list) TD? */
+		/* bit2: do NOT automatically free this TD on completion */
+		/* bit3: this is NOT the last TD in a contiguious TD chain
+		 *       on the indicated ED.  (0 means it is the last) */
 
-	/* User or Device class driver specific fields */
 	void *dev_id;	/* user defined pointer passed to irq handler */
 } __attribute((aligned(16)));
 
@@ -54,6 +56,7 @@
 #define td_set_dir_out(d)	((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN )
 #define OHCI_TD_IOC_DELAY (7 << 21)	/* frame delay allowed before int. */
 #define OHCI_TD_IOC_OFF	(OHCI_TD_IOC_DELAY)	/* no interrupt on complete */
+#define td_set_ioc_delay(frames)	(((frames) & 7) << 21)
 #define OHCI_TD_DT	(3 << 24)	/* data toggle bits */
 #define TOGGLE_AUTO	(0 << 24)	/* automatic (from the ED) */
 #define TOGGLE_DATA0	(2 << 24)	/* force Data0 */
@@ -82,6 +85,19 @@
 #define make_dumb_td(td)	((td)->hcd_flags |= 2)
 #define clear_dumb_td(td)	((td)->hcd_flags &= ~(__u32)2)
 
+#define td_endofchain(td)	(!((td).hcd_flags & (1 << 3)))
+#define set_td_endofchain(td)	((td)->hcd_flags &= ~(1 << 3))
+#define clear_td_endofchain(td)	((td)->hcd_flags |= (1 << 3))
+
+/*
+ * These control if the IRQ will call ohci_free_td after taking the TDs
+ * off of the donelist (assuming the completion function does not ask
+ * for the TD to be requeued).
+ */
+#define can_auto_free(td)	(!((td).hcd_flags & 4))
+#define noauto_free_td(td)	((td)->hcd_flags |= 4)
+#define auto_free_td(td)	((td)->hcd_flags &= ~(__u32)4)
+
 
 /*
  * The endpoint descriptors also requires 16-byte alignment
@@ -369,6 +385,7 @@
     	int irq;
 	struct ohci_regs *regs;			/* OHCI controller's memory */
 	struct usb_bus *bus;
+	struct ohci_device *root_hub;		/* Root hub & controller */
 	struct list_head interrupt_list;	/* List of interrupt active TDs for this OHCI */
 };
 
@@ -380,6 +397,7 @@
 /* Debugging code [ohci-debug.c] */
 void show_ohci_ed(struct ohci_ed *ed);
 void show_ohci_td(struct ohci_td *td);
+void show_ohci_td_chain(struct ohci_td *td);
 void show_ohci_status(struct ohci *ohci);
 void show_ohci_device(struct ohci_device *dev);
 void show_ohci_hcca(struct ohci_hcca *hcca);
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.3.8/linux/drivers/usb/printer.c	Mon Jun  7 20:04:01 1999
+++ linux/drivers/usb/printer.c	Fri Jun 25 14:30:28 1999
@@ -25,7 +25,7 @@
 #define MAX_RETRY_COUNT ((60*60*HZ)/NAK_TIMEOUT)	/* should not take 1 minute a page! */
 
 #ifndef USB_PRINTER_MAJOR
-#define USB_PRINTER_MAJOR 0
+#define USB_PRINTER_MAJOR 63
 #endif
 
 static int mymajor = USB_PRINTER_MAJOR;
@@ -166,6 +166,7 @@
 	do {
 		char *obuf = p->obuf;
 		unsigned long thistime;
+		partial = 0;
 
 		thistime = copy_size = (count > p->maxout) ? p->maxout : count;
 		if (copy_from_user(p->obuf, buffer, copy_size))
@@ -179,16 +180,19 @@
 			}
 			result = p->pusb_dev->bus->op->bulk_msg(p->pusb_dev,
 					 usb_sndbulkpipe(p->pusb_dev, 1), obuf, thistime, &partial);
+			if (partial) {
+				obuf += partial;
+				thistime -= partial;
+				maxretry = MAX_RETRY_COUNT;
+			}
 			if (result == USB_ST_TIMEOUT) {	/* NAK - so hold for a while */
 				if(!maxretry--)
 					return -ETIME;
                                 interruptible_sleep_on_timeout(&p->wait_q, NAK_TIMEOUT);
 				continue;
-			} else if (!result & partial) {
-				obuf += partial;
-				thistime -= partial;
-			} else
+			} else if (!result && !partial) {
 				break;
+			}
 		};
 		if (result) {
 			/* whoops - let's reset and fail the request */
@@ -255,7 +259,8 @@
 	/*
 	 * FIXME - this will not cope with combined printer/scanners
 	 */
-	if (dev->descriptor.bDeviceClass != 7 ||
+	if ((dev->descriptor.bDeviceClass != 7 &&
+	     dev->descriptor.bDeviceClass != 0) ||
 	    dev->descriptor.bNumConfigurations != 1 ||
 	    dev->config[0].bNumInterfaces != 1) {
 		return -1;
@@ -408,6 +413,6 @@
 	unsigned int offset;
 
 	usb_deregister(&printer_driver);
-	unregister_chrdev(mymajor, "usblplp");
+	unregister_chrdev(mymajor, "usblp");
 }
 #endif
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.8/linux/drivers/usb/uhci.c	Sun Jun 20 18:54:01 1999
+++ linux/drivers/usb/uhci.c	Mon Jun 28 10:59:14 1999
@@ -20,6 +20,7 @@
 
 /* 4/4/1999 added data toggle for interrupt pipes -keryan */
 /* 5/16/1999 added global toggles for bulk and control */
+/* 6/25/1999 added fix for data toggles on bidirectional bulk endpoints */ 
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -105,7 +106,7 @@
     			if (uhci_debug) {
 			    printk("Set toggle from %x rval %d\n", (unsigned int)tmp, rval ? *rval : 0);
 			}
-			usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), (tmp->info >> 19) & 1);
+			usb_settoggle(dev->usb, usb_pipeendpoint(tmp->info), usb_pipeout(tmp->info), (tmp->info >> 19) & 1);
 			break;
 		} else {
 		    if(rval)
@@ -372,7 +373,7 @@
 
 	td->link = 1;
 	td->status = status;			/* In */
-	td->info = destination | (7 << 21) | (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe)) << 19);	/* 8 bytes of data */
+	td->info = destination | (7 << 21) | (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19);	/* 8 bytes of data */
 	td->buffer = virt_to_bus(dev->data);
 	td->first = td;
 	td->qh = interrupt_qh;
@@ -991,7 +992,7 @@
 
 		td->status = status;					/* Status */
 		td->info = destination | ((pktsze-1) << 21) |
-			 (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe)) << 19); /* pktsze bytes of data */
+			 (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << 19); /* pktsze bytes of data */
 		td->buffer = virt_to_bus(data);
 		td->backptr = &prevtd->link;
 		td->first = first;
@@ -1006,7 +1007,7 @@
 		}
 
 		/* Alternate Data0/1 (start with Data0) */
-		usb_dotoggle(usb_dev, usb_pipeendpoint(pipe));
+		usb_dotoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
 	}
 	td->link = 1;				/* Terminate */
 	td->status |= (1 << 24);		/* IOC */
@@ -1267,9 +1268,9 @@
 				if (!(td->status & (1 << 25))) {
 					struct uhci_qh *interrupt_qh = td->qh;
 
-					usb_dotoggle(td->dev, usb_pipeendpoint(td->info));
+					usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
 					td->info &= ~(1 << 19); /* clear data toggle */
-					td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info)) << 19; /* toggle between data0 and data1 */
+					td->info |= usb_gettoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info)) << 19; /* toggle between data0 and data1 */
 					td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24);	/* active */
 
 					/* Remove then readd? Is that necessary */
@@ -1280,7 +1281,7 @@
 				struct uhci_qh *interrupt_qh = td->qh;
 				/* marked for removal */
 				td->inuse &= ~2;
-				usb_dotoggle(td->dev, usb_pipeendpoint(td->info));
+				usb_dotoggle(td->dev, usb_pipeendpoint(td->info), usb_pipeout(td->info));
 				uhci_remove_qh(interrupt_qh->skel, interrupt_qh);
 				uhci_qh_deallocate(interrupt_qh);
 				uhci_td_deallocate(td);
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.3.8/linux/drivers/usb/usb.c	Tue Jun  8 10:52:26 1999
+++ linux/drivers/usb/usb.c	Wed Jun 30 11:24:55 1999
@@ -36,7 +36,6 @@
  * 6		wLength		2	Count		Bytes for data
  */
 
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/bitops.h>
 #include <linux/malloc.h>
@@ -773,7 +772,7 @@
 
 	/* toggle is reset on clear */
 
-	usb_settoggle(dev, endp & 0x0f, 0);
+	usb_settoggle(dev, endp & 0x0f, ((endp >> 7) & 1) ^ 1, 0);
 
 	return 0;
 }
@@ -823,7 +822,8 @@
 		return -1;
 
 	dev->actconfig = cp;
-	dev->toggle = 0;
+	dev->toggle[0] = 0;
+	dev->toggle[1] = 0;
 	usb_set_maxpacket(dev);
 	return 0;
 }
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.8/linux/drivers/usb/usb.h	Tue Jun 22 14:42:23 1999
+++ linux/drivers/usb/usb.h	Mon Jun 28 10:59:14 1999
@@ -276,7 +276,7 @@
 	int devnum;			/* Device number on USB bus */
 	int slow;			/* Slow device? */
 	int maxpacketsize;		/* Maximum packet size */
-	int toggle;			/* one bit for each endpoint */
+	int toggle[2];			/* one bit for each endpoint ([0] = IN, [1] = OUT) */
 	int halted;			/* endpoint halts */
 	struct usb_config_descriptor *actconfig;/* the active configuration */
 	int epmaxpacket[16];		/* endpoint specific maximums */
@@ -362,7 +362,7 @@
 #define usb_pipedevice(pipe)	(((pipe) >> 8) & 0x7f)
 #define usb_pipeendpoint(pipe)	(((pipe) >> 15) & 0xf)
 #define usb_pipedata(pipe)	(((pipe) >> 19) & 1)
-#define usb_pipeout(pipe)	(((pipe) & 0x80) == 0)
+#define usb_pipeout(pipe)	((((pipe) >> 7) & 1) ^ 1)
 #define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
 
 #define usb_pipetype(pipe)	(((pipe) >> 30) & 3)
@@ -374,9 +374,9 @@
 #define usb_pipe_endpdev(pipe)	(((pipe) >> 8) & 0x7ff)
 
 /* The D0/D1 toggle bits */
-#define usb_gettoggle(dev, ep) (((dev)->toggle >> ep) & 1)
-#define	usb_dotoggle(dev, ep)	((dev)->toggle ^= (1 <<	ep))
-#define usb_settoggle(dev, ep, bit) ((dev)->toggle = ((dev)->toggle & ~(1 << ep)) | ((bit) << ep))
+#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> ep) & 1)
+#define	usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << ep))
+#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << ep)) | ((bit) << ep))
 
 /* Endpoint halt */
 #define usb_endpoint_halt(dev, ep) ((dev)->halted |= (1 << (ep)))
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
--- v2.3.8/linux/drivers/usb/usb_scsi.c	Sun Jun 20 18:51:52 1999
+++ linux/drivers/usb/usb_scsi.c	Wed Jun 30 11:24:55 1999
@@ -25,6 +25,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.8/linux/drivers/usb/usb_scsi.h linux/drivers/usb/usb_scsi.h
--- v2.3.8/linux/drivers/usb/usb_scsi.h	Mon Jun  7 20:04:01 1999
+++ linux/drivers/usb/usb_scsi.h	Wed Jun 30 11:24:55 1999
@@ -11,6 +11,8 @@
  *
  */
 
+#include <linux/config.h>
+
 #define USB_SCSI "usbscsi: "
 
 extern int usbscsi_debug;
diff -u --recursive --new-file v2.3.8/linux/drivers/video/Makefile linux/drivers/video/Makefile
--- v2.3.8/linux/drivers/video/Makefile	Thu May 13 23:48:20 1999
+++ linux/drivers/video/Makefile	Fri Jun 25 17:37:52 1999
@@ -498,6 +498,16 @@
   endif
 endif
 
+# Newport Text Console
+
+ifeq ($(CONFIG_SGI_NEWPORT_CONSOLE),y)
+L_OBJS += newport_con.o vga_font.o
+else
+  ifeq ($(CONFIG_SGI_NEWPORT_CONSOLE),m)
+  M_OBJS += newport_con.o vga_font.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 promcon_tbl.c: prom.uni ../char/conmakehash
diff -u --recursive --new-file v2.3.8/linux/drivers/video/g364fb.c linux/drivers/video/g364fb.c
--- v2.3.8/linux/drivers/video/g364fb.c	Thu Oct  1 10:02:21 1998
+++ linux/drivers/video/g364fb.c	Fri Jun 25 17:37:52 1999
@@ -144,7 +144,7 @@
      case CM_MOVE:
      case CM_DRAW:
 	*(unsigned int *) CTLA_REG &= ~CURS_TOGGLE;
-	*(unsigned int *) CURS_POS_REG = ((x * p->fontwidth) << 12) | ((y * p->fontheight)-p->var.yoffset);
+	*(unsigned int *) CURS_POS_REG = ((x * fontwidth(p)) << 12) | ((y * fontheight(p))-p->var.yoffset);
 	break;
     }
 }
@@ -485,7 +485,7 @@
     if (regno > 255)
 	return 1;
 
-    red >> = 8;
+    red >>= 8;
     green >>= 8;
     blue >>=8;
     palette[regno].red = red;
diff -u --recursive --new-file v2.3.8/linux/drivers/video/newport_con.c linux/drivers/video/newport_con.c
--- v2.3.8/linux/drivers/video/newport_con.c	Thu Feb 25 10:02:12 1999
+++ linux/drivers/video/newport_con.c	Fri Jun 25 17:37:52 1999
@@ -1,8 +1,9 @@
-/* $Id: newport_con.c,v 1.3 1998/09/01 21:43:18 tsbogend Exp $
+/* $Id: newport_con.c,v 1.13 1999/04/11 10:37:08 ulfc Exp $
  *
  * newport_con.c: Abscon for newport hardware
  * 
  * (C) 1998 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ * (C) 1999 Ulf Carlsson (ulfc@bun.falkenberg.se)
  * 
  * This driver is based on sgicons.c and cons_newport.
  * 
@@ -19,19 +20,27 @@
 #include <linux/console_struct.h>
 #include <linux/vt_kern.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/newport.h>
+#define INCLUDE_LINUX_LOGO_DATA
+#include <asm/linux_logo.h>
 
-struct newport_regs *npregs;
-int newport_num_lines;
-int newport_num_columns;
-int topscan;
+#define LOGO_W		80
+#define LOGO_H		80
 
 extern unsigned char vga_font[];
+extern struct newport_regs *npregs;
+
+static int logo_active;
+static int topscan;
+static int xcurs_correction = 29;
+static int newport_xsize;
+static int newport_ysize;
 
 #define BMASK(c) (c << 24)
 
@@ -49,7 +58,8 @@
 #define TESTVAL 0xdeadbeef
 #define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11)
 
-static inline void newport_render_background(int xpos, int ypos, int ci)
+static inline void newport_render_background(int xstart, int ystart,
+					     int xend, int yend, int ci)
 {
     newport_wait();
     npregs->set.wrmask = 0xffffffff;
@@ -57,8 +67,8 @@
 			     NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
 			     NPORT_DMODE0_STOPY);
     npregs->set.colori = ci;
-    npregs->set.xystarti = (xpos << 16) | ((ypos + topscan) & 0x3ff);
-    npregs->go.xyendi = ((xpos + 7) << 16) | ((ypos + topscan + 15) & 0x3ff);
+    npregs->set.xystarti = (xstart << 16) | ((ystart + topscan) & 0x3ff);
+    npregs->go.xyendi = ((xend + 7) << 16) | ((yend + topscan + 15) & 0x3ff);
 }
 
 static inline void newport_init_cmap(void)
@@ -75,23 +85,51 @@
     }
 }
 
-static inline void newport_clear_screen(int xstart, int ystart, int xend, int yend)
+static inline void newport_show_logo(void)
 {
+    unsigned long i;
+
+    for(i = 0; i < LINUX_LOGO_COLORS; i++) {
+	newport_bfwait();
+	newport_cmap_setaddr(npregs, i + 0x20);
+	newport_cmap_setrgb(npregs,
+			    linux_logo_red[i],
+			    linux_logo_green[i],
+			    linux_logo_blue[i]);
+    }
+
+    newport_wait();
+    npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+			     NPORT_DMODE0_CHOST);
+    
+    npregs->set.xystarti = ((newport_xsize - LOGO_W) << 16) | (0);
+    npregs->set.xyendi = ((newport_xsize - 1) << 16);
+    newport_wait();
+
+    for (i = 0; i < LOGO_W * LOGO_H; i++)
+	npregs->go.hostrw0 = linux_logo[i] << 24;
+}
+
+static inline void newport_clear_screen(int xstart, int ystart, int xend,
+					int yend, int ci) {
+    if (logo_active)
+	return;
+
     newport_wait();
     npregs->set.wrmask = 0xffffffff;
     npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
 			     NPORT_DMODE0_DOSETUP | NPORT_DMODE0_STOPX |
 			     NPORT_DMODE0_STOPY);
-    npregs->set.colori = 0;
+    npregs->set.colori = ci;
     npregs->set.xystarti = (xstart << 16) | ystart;
     npregs->go.xyendi = (xend << 16) | yend;
 }
 
-static inline void newport_clear_lines(int ystart, int yend)
+static inline void newport_clear_lines(int ystart, int yend, int ci)
 {
     ystart = ((ystart << 4) + topscan) & 0x3ff;
     yend = ((yend << 4) + topscan + 15) & 0x3ff;    
-    newport_clear_screen (0, ystart, 1279, yend);
+    newport_clear_screen (0, ystart, 1280+63, yend, ci);
 }
 
 void newport_reset (void)
@@ -116,13 +154,121 @@
     }
 
     newport_init_cmap();
-    npregs->cset.topscan = topscan = 0;
+
+    /* turn off popup plane */
+    npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
+                           XM9_CRS_CONFIG | NPORT_DMODE_W1);
+    npregs->set.dcbdata0.bytes.b3 &= ~XM9_PUPMODE;
+    npregs->set.dcbmode = (DCB_XMAP1 | R_DCB_XMAP9_PROTOCOL |
+                           XM9_CRS_CONFIG | NPORT_DMODE_W1);
+    npregs->set.dcbdata0.bytes.b3 &= ~XM9_PUPMODE;
+    
+    topscan = 0;
+    npregs->cset.topscan = 0x3ff;
     npregs->cset.xywin = (4096 << 16) | 4096;
+
     /* Clear the screen. */
-    newport_clear_screen(0,0,1280+63,1024);
+    newport_clear_screen(0,0,1280+63,1024,0);
 }
 
+/*
+ * calculate the actual screen size by reading
+ * the video timing out of the VC2
+ */
+void newport_get_screensize(void)
+{
+    int i,cols;
+    unsigned short ventry,treg;
+    unsigned short linetable[128]; /* should be enough */
+
+    ventry = newport_vc2_get (npregs, VC2_IREG_VENTRY);
+    newport_vc2_set(npregs, VC2_IREG_RADDR, ventry);
+    npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+			   NPORT_DMODE_W2 | VC2_PROTOCOL);
+    for(i = 0; i < 128; i++) {
+	newport_bfwait();
+	linetable[i] = npregs->set.dcbdata0.hwords.s1;
+    }
+
+    newport_xsize = newport_ysize = 0;
+    for (i = 0; linetable[i+1] && (i < sizeof(linetable)); i+=2) {
+	cols = 0;
+        newport_vc2_set(npregs, VC2_IREG_RADDR, linetable[i]);
+        npregs->set.dcbmode = (NPORT_DMODE_AVC2 | VC2_REGADDR_RAM |
+			       NPORT_DMODE_W2 | VC2_PROTOCOL);
+	do {
+	    newport_bfwait();
+	    treg = npregs->set.dcbdata0.hwords.s1;
+	    if ((treg & 1) == 0)
+		cols += (treg >> 7) & 0xfe;
+	    if ((treg & 0x80) == 0) {
+		newport_bfwait();
+		treg = npregs->set.dcbdata0.hwords.s1;
+	    } 
+	} while ((treg & 0x8000) == 0);
+	if (cols) {
+	    if (cols > newport_xsize)
+		newport_xsize = cols;
+	    newport_ysize += linetable[i+1];
+	}
+    }
+    printk ("NG1: Screensize %dx%d\n",newport_xsize,newport_ysize);
+}
+
+static void newport_get_revisions(void)
+{
+    unsigned int tmp;
+    unsigned int board_rev;
+    unsigned int rex3_rev;
+    unsigned int vc2_rev;
+    unsigned int cmap_rev;
+    unsigned int xmap9_rev;
+    unsigned int bt445_rev;
+    unsigned int bitplanes;
+
+    rex3_rev = npregs->cset.stat & NPORT_STAT_VERS;
+
+    npregs->set.dcbmode = (DCB_CMAP0 | NCMAP_PROTOCOL |
+                           NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
+    tmp = npregs->set.dcbdata0.bytes.b3;
+    cmap_rev = tmp & 7;
+    board_rev = (tmp >> 4) & 7;
+    bitplanes = ((board_rev > 1) && (tmp & 0x80)) ? 8 : 24; 
+
+    npregs->set.dcbmode = (DCB_CMAP1 | NCMAP_PROTOCOL |
+                           NCMAP_REGADDR_RREG | NPORT_DMODE_W1);
+    tmp = npregs->set.dcbdata0.bytes.b3;
+    if ((tmp & 7) < cmap_rev)
+	cmap_rev = (tmp & 7);
+
+    vc2_rev = (newport_vc2_get(npregs, VC2_IREG_CONFIG) >> 5) & 7;
+
+    npregs->set.dcbmode = (DCB_XMAP0 | R_DCB_XMAP9_PROTOCOL |
+                           XM9_CRS_REVISION | NPORT_DMODE_W1);
+    xmap9_rev = npregs->set.dcbdata0.bytes.b3 & 7;
+
+    npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
+                           BT445_CSR_ADDR_REG | NPORT_DMODE_W1);
+    npregs->set.dcbdata0.bytes.b3 = BT445_REVISION_REG;
+    npregs->set.dcbmode = (DCB_BT445 | BT445_PROTOCOL |
+                           BT445_CSR_REVISION | NPORT_DMODE_W1);
+    bt445_rev = (npregs->set.dcbdata0.bytes.b3 >> 4) - 0x0a;
+
+#define L(a)     (char)('A'+(a))
+    printk ("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n",
+	    board_rev,bitplanes,L(rex3_rev),L(vc2_rev), L(xmap9_rev),
+	    L(cmap_rev ? (cmap_rev+1):0),L(bt445_rev));
+#undef L
+
+    if (board_rev == 3) /* I don't know all affected revisions */
+	xcurs_correction = 21;
+}
+
+#ifdef MODULE
+static const char *newport_startup(void)
+#else
 __initfunc(static const char *newport_startup(void))
+#endif
 {
     struct newport_regs *p;
 
@@ -140,18 +286,18 @@
     }
 
     newport_reset ();
+    newport_get_revisions();
+    newport_get_screensize();
 
     // gfx_init (display_desc);
-    newport_num_lines = ORIG_VIDEO_LINES;
-    newport_num_columns = ORIG_VIDEO_COLS;
     
     return "SGI Newport";
 }
 
 static void newport_init(struct vc_data *vc, int init)
 {
-    vc->vc_cols = newport_num_columns;
-    vc->vc_rows = newport_num_lines;
+    vc->vc_cols = newport_xsize / 8;
+    vc->vc_rows = newport_ysize / 16;
     vc->vc_can_do_color = 1;
 }
 
@@ -160,12 +306,18 @@
     int xend = ((sx + width) << 3) - 1;
     int ystart = ((sy << 4) + topscan) & 0x3ff;
     int yend = (((sy + height) << 4) + topscan - 1) & 0x3ff;
+
+    if (logo_active)
+	return;
     
     if (ystart < yend) {
-	newport_clear_screen(sx << 3, ystart, xend, yend);
+	newport_clear_screen(sx << 3, ystart, xend, yend,
+			     (vc->vc_color & 0xf0) >> 4);
     } else {
-	newport_clear_screen(sx << 3, ystart, xend, 1023);
-	newport_clear_screen(sx << 3, 0, xend, yend);
+	newport_clear_screen(sx << 3, ystart, xend, 1023,
+			     (vc->vc_color & 0xf0) >> 4);
+	newport_clear_screen(sx << 3, 0, xend, yend,
+			     (vc->vc_color & 0xf0) >> 4);
     }
 }
 
@@ -178,7 +330,7 @@
     xpos <<= 3;
     ypos <<= 4;
 
-    newport_render_background(xpos, ypos, (charattr & 0xf0) >> 4);
+    newport_render_background(xpos, ypos, xpos, ypos, (charattr & 0xf0) >> 4);
     
     /* Set the color and drawing mode. */
     newport_wait();
@@ -196,11 +348,43 @@
     RENDER(npregs, p);
 }
 
-static void newport_putcs(struct vc_data *vc, const unsigned short *s, int count,
-			  int ypos, int xpos)
+static void newport_putcs(struct vc_data *vc, const unsigned short *s,
+			  int count, int ypos, int xpos)
 {
-    while (count--)
-	newport_putc (vc, scr_readw(s++), ypos, xpos++);
+    int i;
+    int charattr;
+    unsigned char *p; 
+
+    charattr = (*s >> 8) & 0xff;
+
+    xpos <<= 3;
+    ypos <<= 4;
+
+    if (!logo_active)
+	/* Clear the area behing the string */
+	newport_render_background(xpos, ypos, xpos + ((count-1) << 3), ypos,
+				  (charattr & 0xf0) >> 4);
+
+    newport_wait();
+
+    /* Set the color and drawing mode. */
+    npregs->set.colori = charattr & 0xf;
+    npregs->set.drawmode0 = (NPORT_DMODE0_DRAW | NPORT_DMODE0_BLOCK |
+			     NPORT_DMODE0_STOPX | NPORT_DMODE0_ZPENAB |
+			     NPORT_DMODE0_L32);
+    
+    for (i = 0; i < count; i++, xpos += 8) {
+	p = &vga_font[(s[i] & 0xff) << 4];
+
+	newport_wait();
+
+	/* Set coordinates for bitmap operation. */
+	npregs->set.xystarti = (xpos << 16) | ((ypos + topscan) & 0x3ff);
+	npregs->set.xyendi = ((xpos + 7) << 16);
+
+	/* Go, baby, go... */
+	RENDER(npregs, p);
+    }
 }
 
 static void newport_cursor(struct vc_data *vc, int mode)
@@ -220,7 +404,7 @@
 	newport_vc2_set(npregs, VC2_IREG_CONTROL, (treg | VC2_CTRL_ECDISP));
 	xcurs = (vc->vc_pos - vc->vc_visible_origin) / 2;
 	ycurs = ((xcurs / vc->vc_cols) << 4) + 31;
-	xcurs = ((xcurs % vc->vc_cols) << 3) + 21;
+	xcurs = ((xcurs % vc->vc_cols) << 3) + xcurs_correction;
 	newport_vc2_set(npregs, VC2_IREG_CURSX, xcurs);
 	newport_vc2_set(npregs, VC2_IREG_CURSY, ycurs);
     }
@@ -228,7 +412,17 @@
 
 static int newport_switch(struct vc_data *vc)
 {
-    npregs->cset.topscan = topscan = 0;
+    static int logo_drawn = 0;
+
+    topscan = 0;
+    npregs->cset.topscan = 0x3ff;
+
+    if (!logo_drawn) {
+	newport_show_logo();
+	logo_drawn = 1;
+	logo_active = 1;
+    }
+
     return 1;
 }
 
@@ -270,14 +464,18 @@
     unsigned short *s, *d;
     unsigned short chattr;
 
+    logo_active = 0;	/* it's time to disable the logo now.. */
+
     if (t == 0 && b == vc->vc_rows) {
 	if (dir == SM_UP) {
-	    npregs->cset.topscan = topscan = (topscan + (lines << 4)) & 0x3ff;
-	    newport_clear_lines (vc->vc_rows-lines,vc->vc_rows-1);		
+	    topscan = (topscan + (lines << 4)) & 0x3ff;
+	    newport_clear_lines (vc->vc_rows-lines,vc->vc_rows-1,
+				 (vc->vc_color & 0xf0) >> 4);
 	} else {
-	    npregs->cset.topscan = topscan = (topscan + (-lines << 4)) & 0x3ff;
-	    newport_clear_lines (0,lines-1);
+	    topscan = (topscan + (-lines << 4)) & 0x3ff;
+	    newport_clear_lines (0,lines-1, (vc->vc_color & 0xf0) >> 4);
 	}
+	npregs->cset.topscan = (topscan - 1) & 0x3ff;
 	return 0;
     }
     
@@ -392,3 +590,23 @@
     NULL, /* newport_build_attr */
     NULL  /* newport_invert_region */
 };
+
+#ifdef MODULE
+
+int init_module(void) {
+    if (!newport_startup()) 
+       printk("Error loading SGI Newport Console driver\n");
+    else 
+       printk("Loading SGI Newport Console Driver\n");
+
+    take_over_console(&newport_con,0,MAX_NR_CONSOLES-1,1);
+
+    return 0;
+}
+
+int cleanup_module(void) {
+    printk("Unloading SGI Newport Console Driver\n");
+    return 0;
+}
+
+#endif
diff -u --recursive --new-file v2.3.8/linux/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- v2.3.8/linux/drivers/video/sbusfb.c	Thu Apr 22 19:30:08 1999
+++ linux/drivers/video/sbusfb.c	Tue Jun 29 09:22:08 1999
@@ -364,9 +364,29 @@
      */
 
 static int sbusfb_set_var(struct fb_var_screeninfo *var, int con,
-			struct fb_info *info)
+			  struct fb_info *info)
 {
-	return -EINVAL;
+       struct display *display;
+       int activate = var->activate;
+
+       if(con >= 0)
+               display = &fb_display[con];
+       else
+               display = info->disp;
+
+       /* simple check for equality until fully implemented -E */
+       if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+               if (display->var.xres != var->xres ||
+                       display->var.yres != var->yres ||
+                       display->var.xres_virtual != var->xres_virtual ||
+                       display->var.yres_virtual != var->yres_virtual ||
+                       display->var.bits_per_pixel != var->bits_per_pixel ||
+                       display->var.accel_flags != var->accel_flags) {
+                       return -EINVAL;
+               }
+       }
+       return 0;
+
 }
 
     /*
diff -u --recursive --new-file v2.3.8/linux/drivers/video/vga_font.c linux/drivers/video/vga_font.c
--- v2.3.8/linux/drivers/video/vga_font.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/video/vga_font.c	Fri Jun 25 17:37:52 1999
@@ -0,0 +1,352 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/modversions.h>
+
+
+#define cmapsz 8192
+
+unsigned char vga_font[cmapsz] = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+};
+
diff -u --recursive --new-file v2.3.8/linux/drivers/zorro/proc.c linux/drivers/zorro/proc.c
--- v2.3.8/linux/drivers/zorro/proc.c	Mon Aug 24 13:14:10 1998
+++ linux/drivers/zorro/proc.c	Sun Jun 27 10:10:41 1999
@@ -89,11 +89,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 int
diff -u --recursive --new-file v2.3.8/linux/fs/Makefile linux/fs/Makefile
--- v2.3.8/linux/fs/Makefile	Thu May 13 23:50:15 1999
+++ linux/fs/Makefile	Fri Jun 25 01:05:12 1999
@@ -263,14 +263,6 @@
   endif
 endif
 
-ifeq ($(CONFIG_BINFMT_JAVA),y)
-BINFMTS += binfmt_java.o
-else
-  ifeq ($(CONFIG_BINFMT_JAVA),m)
-  M_OBJS += binfmt_java.o
-  endif
-endif
-
 ifeq ($(CONFIG_BINFMT_EM86),y)
 BINFMTS += binfmt_em86.o
 else
diff -u --recursive --new-file v2.3.8/linux/fs/adfs/dir.c linux/fs/adfs/dir.c
--- v2.3.8/linux/fs/adfs/dir.c	Thu May 13 10:53:59 1999
+++ linux/fs/adfs/dir.c	Sun Jun 27 10:10:41 1999
@@ -51,12 +51,14 @@
 	NULL,			/* rename */
 	NULL,			/* read link */
 	NULL,			/* follow link */
+	NULL,			/* get_block */
 	NULL,			/* read page */
 	NULL,			/* write page */
-	NULL,			/* bmap */
+	NULL,			/* flush page */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 unsigned int adfs_val (unsigned char *p, int len)
diff -u --recursive --new-file v2.3.8/linux/fs/adfs/file.c linux/fs/adfs/file.c
--- v2.3.8/linux/fs/adfs/file.c	Mon Aug 24 13:02:44 1998
+++ linux/fs/adfs/file.c	Sun Jun 27 10:10:41 1999
@@ -61,10 +61,12 @@
 	NULL,			/* rename			*/
 	NULL,			/* readlink			*/
 	NULL,			/* follow_link			*/
-	generic_readpage,	/* readpage			*/
+	adfs_bmap,		/* get_block			*/
+	block_read_full_page,	/* readpage			*/
 	NULL,			/* writepage			*/
-	adfs_bmap,		/* bmap				*/
+	NULL,			/* flushpage			*/
 	NULL,			/* truncate			*/
 	NULL,			/* permission			*/
-	NULL			/* smap				*/
+	NULL,			/* smap				*/
+	NULL			/* revalidate			*/
 };
diff -u --recursive --new-file v2.3.8/linux/fs/affs/dir.c linux/fs/affs/dir.c
--- v2.3.8/linux/fs/affs/dir.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/affs/dir.c	Sun Jun 27 10:10:41 1999
@@ -57,9 +57,10 @@
 	affs_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permissions */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.3.8/linux/fs/affs/file.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/affs/file.c	Sun Jun 27 10:10:41 1999
@@ -74,9 +74,10 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
+	affs_bmap,		/* get_block */
+	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
-	affs_bmap,		/* bmap */
+	NULL,			/* flushpage */
 	affs_truncate,		/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
@@ -114,9 +115,10 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	affs_truncate,		/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/affs/symlink.c linux/fs/affs/symlink.c
--- v2.3.8/linux/fs/affs/symlink.c	Sat Sep 19 13:39:45 1998
+++ linux/fs/affs/symlink.c	Sun Jun 27 10:10:41 1999
@@ -35,12 +35,14 @@
 	NULL,			/* rename */
 	affs_readlink,		/* readlink */
 	affs_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static int
diff -u --recursive --new-file v2.3.8/linux/fs/autofs/dir.c linux/fs/autofs/dir.c
--- v2.3.8/linux/fs/autofs/dir.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/autofs/dir.c	Sun Jun 27 10:10:41 1999
@@ -73,9 +73,10 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.3.8/linux/fs/autofs/root.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/autofs/root.c	Sun Jun 27 10:10:41 1999
@@ -54,9 +54,10 @@
         NULL,                   /* rename */
         NULL,                   /* readlink */
         NULL,                   /* follow_link */
+        NULL,                   /* get_block */
         NULL,                   /* readpage */
         NULL,                   /* writepage */
-        NULL,                   /* bmap */
+        NULL,                   /* flushpage */
         NULL,                   /* truncate */
         NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c
--- v2.3.8/linux/fs/autofs/symlink.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/autofs/symlink.c	Sun Jun 27 10:10:41 1999
@@ -49,9 +49,10 @@
 	NULL,			/* rename */
 	autofs_readlink,	/* readlink */
 	autofs_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/bad_inode.c linux/fs/bad_inode.c
--- v2.3.8/linux/fs/bad_inode.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/bad_inode.c	Sat Jun 26 12:04:39 1999
@@ -60,7 +60,7 @@
 	EIO_ERROR,		/* rename */
 	EIO_ERROR,		/* readlink */
 	bad_follow_link,	/* follow_link */
-	EIO_ERROR,		/* bmap */
+	EIO_ERROR,		/* get_block */
 	EIO_ERROR,		/* readpage */
 	EIO_ERROR,		/* writepage */
 	EIO_ERROR,		/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.3.8/linux/fs/binfmt_aout.c	Fri Jun 18 08:00:52 1999
+++ linux/fs/binfmt_aout.c	Sat Jun 26 12:04:39 1999
@@ -323,7 +323,7 @@
 
 	if (N_MAGIC(ex) == ZMAGIC && ex.a_text &&
 	    bprm->dentry->d_inode->i_op &&
-	    bprm->dentry->d_inode->i_op->bmap &&
+	    bprm->dentry->d_inode->i_op->get_block &&
 	    (fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) {
 		printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n");
 		return -ENOEXEC;
@@ -396,7 +396,7 @@
 		fd = open_dentry(bprm->dentry, O_RDONLY);
 		if (fd < 0)
 			return fd;
-		file = fcheck(fd);
+		file = fget(fd);
 
 		if ((fd_offset & ~PAGE_MASK) != 0) {
 			printk(KERN_WARNING 
@@ -406,6 +406,7 @@
 		}
 
 		if (!file->f_op || !file->f_op->mmap || ((fd_offset & ~PAGE_MASK) != 0)) {
+			fput(file);
 			sys_close(fd);
 			do_brk(0, ex.a_text+ex.a_data);
 			read_exec(bprm->dentry, fd_offset,
@@ -422,6 +423,7 @@
 			fd_offset);
 
 		if (error != N_TXTADDR(ex)) {
+			fput(file);
 			sys_close(fd);
 			send_sig(SIGKILL, current, 0);
 			return error;
@@ -431,6 +433,7 @@
 				PROT_READ | PROT_WRITE | PROT_EXEC,
 				MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE,
 				fd_offset + ex.a_text);
+		fput(file);
 		sys_close(fd);
 		if (error != N_DATADDR(ex)) {
 			send_sig(SIGKILL, current, 0);
diff -u --recursive --new-file v2.3.8/linux/fs/binfmt_java.c linux/fs/binfmt_java.c
--- v2.3.8/linux/fs/binfmt_java.c	Wed Jun  2 13:49:58 1999
+++ linux/fs/binfmt_java.c	Wed Dec 31 16:00:00 1969
@@ -1,196 +0,0 @@
-/*
- *  linux/fs/binfmt_java.c
- *
- *  Copyright (C) 1996  Brian A. Lantz
- *  derived from binfmt_script.c
- *
- *  Simplified and modified to support binary java interpreters
- *  by Tom May <ftom@netcom.com>.
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/stat.h>
-#include <linux/malloc.h>
-#include <linux/binfmts.h>
-#include <linux/init.h>
-
-#define _PATH_JAVA	"/usr/bin/java"
-#define _PATH_APPLET	"/usr/bin/appletviewer"
-
-/*  These paths can be modified with sysctl().  */
-
-char binfmt_java_interpreter[65] = _PATH_JAVA;
-char binfmt_java_appletviewer[65] = _PATH_APPLET;
-
-static int do_load_java(struct linux_binprm *bprm,struct pt_regs *regs)
-{
-	char *i_name;
-	int len;
-	int retval;
-	struct dentry * dentry;
-	unsigned char *ucp = (unsigned char *) bprm->buf;
-
-	if ((ucp[0] != 0xca) || (ucp[1] != 0xfe) || (ucp[2] != 0xba) || (ucp[3] != 0xbe)) 
-		return -ENOEXEC;
-
-	/*
-	 * Fail if we're called recursively, e.g., the Java interpreter
-	 * is a java binary.
-	 */
-
-	if (bprm->java)
-		return -ENOEXEC;
-
-	bprm->java = 1;
-
-	dput(bprm->dentry);
-	bprm->dentry = NULL;
-
-	/*
-	 * Set args: [0] the name of the java interpreter
-	 *           [1] name of java class to execute, which is the
-	 *		 filename without the path and without trailing
-	 *		 ".class".  Note that the interpreter will use
-	 *		 its own way to found the class file (typically using
-	 *		 environment variable CLASSPATH), and may in fact
-	 *		 execute a different file from the one we want.
-	 *
-	 * This is done in reverse order, because of how the
-	 * user environment and arguments are stored.
-	 */
-	remove_arg_zero(bprm);
-	len = strlen (bprm->filename);
-	if (len >= 6 && !strcmp (bprm->filename + len - 6, ".class"))
-		bprm->filename[len - 6] = 0;
-	if ((i_name = strrchr (bprm->filename, '/')) != NULL)
-		i_name++;
-	else
-		i_name = bprm->filename;
-
-	retval = copy_strings_kernel(1, &i_name, bprm); 
-	if (retval < 0) 
-		return retval; 
-	bprm->argc++;
-
-	i_name = binfmt_java_interpreter;
-	retval = copy_strings_kernel(1, &i_name, bprm); 
-	if (retval < 0) 
-		return retval; 
-	bprm->argc++;
-
-	/*
-	 * OK, now restart the process with the interpreter's dentry.
-	 */
-	bprm->filename = binfmt_java_interpreter;
-	dentry = open_namei(binfmt_java_interpreter, 0, 0);
-	retval = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		return retval;
-
-	bprm->dentry = dentry;
-	retval = prepare_binprm(bprm);
-	if (retval < 0)
-		return retval;
-
-	return search_binary_handler(bprm,regs);
-}
-
-static int do_load_applet(struct linux_binprm *bprm,struct pt_regs *regs)
-{
-	char *i_name;
-	struct dentry * dentry;
-	int retval;
-
-	if (strncmp (bprm->buf, "<!--applet", 10))
-		return -ENOEXEC;
-
-	dput(bprm->dentry);
-	bprm->dentry = NULL;
-
-	/*
-	 * Set args: [0] the name of the appletviewer
-	 *           [1] filename of html file
-	 *
-	 * This is done in reverse order, because of how the
-	 * user environment and arguments are stored.
-	 */
-	remove_arg_zero(bprm);
-	i_name = bprm->filename;
-	retval = copy_strings_kernel(1, &i_name, bprm);
-	if (retval < 0) return retval; 
-	bprm->argc++;
-
-	i_name = binfmt_java_appletviewer;
-	retval = copy_strings_kernel(1, &i_name, bprm);
-	if (retval < 0) return retval; 
-	bprm->argc++;
-
-	/*
-	 * OK, now restart the process with the interpreter's dentry.
-	 */
-	bprm->filename = binfmt_java_appletviewer;
-	dentry = open_namei(binfmt_java_appletviewer, 0, 0);
-	retval = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		return retval;
-
-	bprm->dentry = dentry;
-	retval = prepare_binprm(bprm);
-	if (retval < 0)
-		return retval;
-
-	return search_binary_handler(bprm,regs);
-}
-
-static int load_java(struct linux_binprm *bprm,struct pt_regs *regs)
-{
-	int retval;
-	MOD_INC_USE_COUNT;
-	retval = do_load_java(bprm,regs);
-	MOD_DEC_USE_COUNT;
-	return retval;
-}
-
-static struct linux_binfmt java_format = {
-#ifndef MODULE
-	NULL, 0, load_java, NULL, NULL
-#else
-	NULL, &__this_module, load_java, NULL, NULL
-#endif
-};
-
-static int load_applet(struct linux_binprm *bprm,struct pt_regs *regs)
-{
-	int retval;
-	MOD_INC_USE_COUNT;
-	retval = do_load_applet(bprm,regs);
-	MOD_DEC_USE_COUNT;
-	return retval;
-}
-
-static struct linux_binfmt applet_format = {
-#ifndef MODULE
-	NULL, 0, load_applet, NULL, NULL
-#else
-	NULL, &__this_module, load_applet, NULL, NULL
-#endif
-};
-
-int __init init_java_binfmt(void)
-{
-	register_binfmt(&java_format);
-	return register_binfmt(&applet_format);
-}
-
-#ifdef MODULE
-int init_module(void)
-{
-	return init_java_binfmt();
-}
-
-void cleanup_module( void) {
-	unregister_binfmt(&java_format);
-	unregister_binfmt(&applet_format);
-}
-#endif
diff -u --recursive --new-file v2.3.8/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.8/linux/fs/buffer.c	Tue Jun 22 14:21:33 1999
+++ linux/fs/buffer.c	Wed Jun 30 10:25:46 1999
@@ -24,6 +24,8 @@
  * - RMK
  */
 
+/* Thread it... -DaveM */
+
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/malloc.h>
@@ -57,31 +59,39 @@
 #define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this 
 					     number of unused buffer heads */
 
-/*
- * Hash table mask..
+/* Anti-deadlock ordering:
+ *	lru_list_lock > hash_table_lock > free_list_lock > unused_list_lock
  */
-static unsigned long bh_hash_mask = 0;
-
-static int grow_buffers(int size);
 
-static struct buffer_head ** hash_table;
-static struct buffer_head * lru_list[NR_LIST] = {NULL, };
-static struct buffer_head * free_list[NR_SIZES] = {NULL, };
+/*
+ * Hash table gook..
+ */
+static unsigned int bh_hash_mask = 0;
+static unsigned int bh_hash_shift = 0;
+static struct buffer_head **hash_table;
+static rwlock_t hash_table_lock = RW_LOCK_UNLOCKED;
 
-static kmem_cache_t *bh_cachep;
+static struct buffer_head *lru_list[NR_LIST];
+static spinlock_t lru_list_lock = SPIN_LOCK_UNLOCKED;
+static int nr_buffers_type[NR_LIST] = {0,};
 
 static struct buffer_head * unused_list = NULL;
-static struct buffer_head * reuse_list = NULL;
+static int nr_unused_buffer_heads = 0;
+static spinlock_t unused_list_lock = SPIN_LOCK_UNLOCKED;
 static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
 
-static int nr_buffers = 0;
-static int nr_buffers_type[NR_LIST] = {0,};
-static int nr_buffer_heads = 0;
-static int nr_unused_buffer_heads = 0;
-static int nr_hashed_buffers = 0;
+struct bh_free_head {
+	struct buffer_head *list;
+	spinlock_t lock;
+};
+static struct bh_free_head free_list[NR_SIZES];
+
+static kmem_cache_t *bh_cachep;
+
+static int grow_buffers(int size);
 
 /* This is used by some architectures to estimate available memory. */
-int buffermem = 0;
+atomic_t buffermem = ATOMIC_INIT(0);
 
 /* Here is the parameter block for the bdflush process. If you add or
  * remove any of the parameters, make sure to update kernel/sysctl.c.
@@ -131,7 +141,7 @@
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
 
-	bh->b_count++;
+	atomic_inc(&bh->b_count);
 	add_wait_queue(&bh->b_wait, &wait);
 repeat:
 	tsk->state = TASK_UNINTERRUPTIBLE;
@@ -142,7 +152,7 @@
 	}
 	tsk->state = TASK_RUNNING;
 	remove_wait_queue(&bh->b_wait, &wait);
-	bh->b_count--;
+	atomic_dec(&bh->b_count);
 }
 
 /* Call sync_buffers with wait!=0 to ensure that the call does not
@@ -167,17 +177,19 @@
 	 */
 	do {
 		retry = 0;
-repeat:
+
 		/* We search all lists as a failsafe mechanism, not because we expect
 		 * there to be dirty buffers on any of the other lists.
 		 */
+repeat:
+		spin_lock(&lru_list_lock);
 		bh = lru_list[BUF_DIRTY];
 		if (!bh)
 			goto repeat2;
+
 		for (i = nr_buffers_type[BUF_DIRTY]*2 ; i-- > 0 ; bh = next) {
-			if (bh->b_list != BUF_DIRTY)
-				goto repeat;
 			next = bh->b_next_free;
+
 			if (!lru_list[BUF_DIRTY])
 				break;
 			if (dev && bh->b_dev != dev)
@@ -190,7 +202,10 @@
 					retry = 1;
 					continue;
 				}
+				atomic_inc(&bh->b_count);
+				spin_unlock(&lru_list_lock);
 				wait_on_buffer (bh);
+				atomic_dec(&bh->b_count);
 				goto repeat;
 			}
 
@@ -209,30 +224,24 @@
 			if (!buffer_dirty(bh) || pass >= 2)
 				continue;
 
-			/* Don't bother about locked buffers.
-			 *
-			 * XXX We checked if it was locked above and there is no
-			 * XXX way we could have slept in between. -DaveM
-			 */
-			if (buffer_locked(bh))
-				continue;
-			bh->b_count++;
-			next->b_count++;
+			atomic_inc(&bh->b_count);
 			bh->b_flushtime = 0;
+			spin_unlock(&lru_list_lock);
 			ll_rw_block(WRITE, 1, &bh);
-			bh->b_count--;
-			next->b_count--;
+			atomic_dec(&bh->b_count);
 			retry = 1;
+			goto repeat;
 		}
 
     repeat2:
 		bh = lru_list[BUF_LOCKED];
-		if (!bh)
+		if (!bh) {
+			spin_unlock(&lru_list_lock);
 			break;
+		}
 		for (i = nr_buffers_type[BUF_LOCKED]*2 ; i-- > 0 ; bh = next) {
-			if (bh->b_list != BUF_LOCKED)
-				goto repeat2;
 			next = bh->b_next_free;
+
 			if (!lru_list[BUF_LOCKED])
 				break;
 			if (dev && bh->b_dev != dev)
@@ -245,10 +254,15 @@
 					retry = 1;
 					continue;
 				}
+				atomic_inc(&bh->b_count);
+				spin_unlock(&lru_list_lock);
 				wait_on_buffer (bh);
+				spin_lock(&lru_list_lock);
+				atomic_dec(&bh->b_count);
 				goto repeat2;
 			}
 		}
+		spin_unlock(&lru_list_lock);
 
 		/* If we are waiting for the sync to succeed, and if any dirty
 		 * blocks were written, then repeat; on the second pass, only
@@ -282,17 +296,19 @@
 int fsync_dev(kdev_t dev)
 {
 	sync_buffers(dev, 0);
+
+	lock_kernel();
 	sync_supers(dev);
 	sync_inodes(dev);
 	DQUOT_SYNC(dev);
+	unlock_kernel();
+
 	return sync_buffers(dev, 1);
 }
 
 asmlinkage int sys_sync(void)
 {
-	lock_kernel();
 	fsync_dev(0);
-	unlock_kernel();
 	return 0;
 }
 
@@ -396,19 +412,28 @@
 
 void invalidate_buffers(kdev_t dev)
 {
-	int i;
 	int nlist;
-	struct buffer_head * bh;
 
+	spin_lock(&lru_list_lock);
 	for(nlist = 0; nlist < NR_LIST; nlist++) {
+		struct buffer_head * bh;
+		int i;
+	retry:
 		bh = lru_list[nlist];
+		if (!bh)
+			continue;
 		for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bh->b_next_free) {
 			if (bh->b_dev != dev)
 				continue;
-			wait_on_buffer(bh);
-			if (bh->b_dev != dev)
-				continue;
-			if (bh->b_count)
+			if (buffer_locked(bh)) {
+				atomic_inc(&bh->b_count);
+				spin_unlock(&lru_list_lock);
+				wait_on_buffer(bh);
+				spin_lock(&lru_list_lock);
+				atomic_dec(&bh->b_count);
+				goto retry;
+			}
+			if (atomic_read(&bh->b_count))
 				continue;
 			bh->b_flushtime = 0;
 			clear_bit(BH_Protected, &bh->b_state);
@@ -417,157 +442,119 @@
 			clear_bit(BH_Req, &bh->b_state);
 		}
 	}
+	spin_unlock(&lru_list_lock);
 }
 
-#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block)) & bh_hash_mask)
-#define hash(dev,block) hash_table[_hashfn(dev,block)]
+/* After several hours of tedious analysis, the following hash
+ * function won.  Do not mess with it... -DaveM
+ */
+#define _hashfn(dev,block)	\
+	((((dev)<<(bh_hash_shift - 6)) ^ ((dev)<<(bh_hash_shift - 9))) ^ \
+	 (((block)<<(bh_hash_shift - 6)) ^ ((block) >> 13) ^ ((block) << (bh_hash_shift - 12))))
+#define hash(dev,block) hash_table[(_hashfn(dev,block) & bh_hash_mask)]
 
-static void insert_into_hash_list(struct buffer_head * bh)
+static __inline__ void __hash_link(struct buffer_head *bh, struct buffer_head **head)
 {
-	bh->b_next = NULL;
-	bh->b_pprev = NULL;
-	if (bh->b_dev) {
-		struct buffer_head **bhp = &hash(bh->b_dev, bh->b_blocknr);
-		struct buffer_head *next = *bhp;
-
-		if (next) {
-			bh->b_next = next;
-			next->b_pprev = &bh->b_next;
-		}
-		*bhp = bh;
-		bh->b_pprev = bhp;
-		nr_hashed_buffers++;
-	}
+	if ((bh->b_next = *head) != NULL)
+		bh->b_next->b_pprev = &bh->b_next;
+	*head = bh;
+	bh->b_pprev = head;
 }
 
-static void remove_from_hash_queue(struct buffer_head * bh)
+static __inline__ void __hash_unlink(struct buffer_head *bh)
 {
-	struct buffer_head **pprev = bh->b_pprev;
-	if (pprev) {
-		struct buffer_head * next = bh->b_next;
-		if (next) {
-			next->b_pprev = pprev;
-			bh->b_next = NULL;
-		}
-		*pprev = next;
-		bh->b_pprev = NULL;
-		nr_hashed_buffers--;
-	}
+	if (bh->b_next)
+		bh->b_next->b_pprev = bh->b_pprev;
+	*(bh->b_pprev) = bh->b_next;
+	bh->b_pprev = NULL;
 }
 
-static void insert_into_lru_list(struct buffer_head * bh)
+static void __insert_into_lru_list(struct buffer_head * bh, int blist)
 {
-	struct buffer_head **bhp = &lru_list[bh->b_list];
-
-	if (bh->b_dev == B_FREE)
-		BUG();
+	struct buffer_head **bhp = &lru_list[blist];
 
 	if(!*bhp) {
 		*bhp = bh;
 		bh->b_prev_free = bh;
 	}
-
-	if (bh->b_next_free)
-		panic("VFS: buffer LRU pointers corrupted");
-
 	bh->b_next_free = *bhp;
 	bh->b_prev_free = (*bhp)->b_prev_free;
 	(*bhp)->b_prev_free->b_next_free = bh;
 	(*bhp)->b_prev_free = bh;
-
-	nr_buffers++;
-	nr_buffers_type[bh->b_list]++;
+	nr_buffers_type[blist]++;
 }
 
-static void remove_from_lru_list(struct buffer_head * bh)
+static void __remove_from_lru_list(struct buffer_head * bh, int blist)
 {
-	if (!(bh->b_prev_free) || !(bh->b_next_free))
-		return;
-
-	if (bh->b_dev == B_FREE) {
-		printk("LRU list corrupted");
-		*(int*)0 = 0;
-	}
-	bh->b_prev_free->b_next_free = bh->b_next_free;
-	bh->b_next_free->b_prev_free = bh->b_prev_free;
-
-	if (lru_list[bh->b_list] == bh)
-		 lru_list[bh->b_list] = bh->b_next_free;
-	if (lru_list[bh->b_list] == bh)
-		 lru_list[bh->b_list] = NULL;
-	bh->b_next_free = bh->b_prev_free = NULL;
-
-	nr_buffers--;
-	nr_buffers_type[bh->b_list]--;
+	if (bh->b_prev_free || bh->b_next_free) {
+		bh->b_prev_free->b_next_free = bh->b_next_free;
+		bh->b_next_free->b_prev_free = bh->b_prev_free;
+		if (lru_list[blist] == bh)
+			lru_list[blist] = bh->b_next_free;
+		if (lru_list[blist] == bh)
+			lru_list[blist] = NULL;
+		bh->b_next_free = bh->b_prev_free = NULL;
+		nr_buffers_type[blist]--;
+	}
 }
 
-static void remove_from_free_list(struct buffer_head * bh)
+static void __remove_from_free_list(struct buffer_head * bh, int index)
 {
-	int isize = BUFSIZE_INDEX(bh->b_size);
-	if (!(bh->b_prev_free) || !(bh->b_next_free))
-		panic("VFS: Free block list corrupted");
-	if(bh->b_dev != B_FREE)
-		panic("Free list corrupted");
-	if(!free_list[isize])
-		panic("Free list empty");
 	if(bh->b_next_free == bh)
-		 free_list[isize] = NULL;
+		 free_list[index].list = NULL;
 	else {
 		bh->b_prev_free->b_next_free = bh->b_next_free;
 		bh->b_next_free->b_prev_free = bh->b_prev_free;
-		if (free_list[isize] == bh)
-			 free_list[isize] = bh->b_next_free;
+		if (free_list[index].list == bh)
+			 free_list[index].list = bh->b_next_free;
 	}
 	bh->b_next_free = bh->b_prev_free = NULL;
 }
 
-static void remove_from_queues(struct buffer_head * bh)
+/* The following two functions must operate atomically
+ * because they control the visibility of a buffer head
+ * to the rest of the kernel.
+ */
+static __inline__ void __remove_from_queues(struct buffer_head *bh)
 {
-	if (bh->b_dev == B_FREE)
-		BUG();
-	remove_from_hash_queue(bh);
-	remove_from_lru_list(bh);
+	write_lock(&hash_table_lock);
+	if (bh->b_pprev)
+		__hash_unlink(bh);
+	__remove_from_lru_list(bh, bh->b_list);
+	write_unlock(&hash_table_lock);
 }
 
-static void put_last_free(struct buffer_head * bh)
+static void insert_into_queues(struct buffer_head *bh)
 {
-	if (bh) {
-		struct buffer_head **bhp = &free_list[BUFSIZE_INDEX(bh->b_size)];
+	struct buffer_head **head = &hash(bh->b_dev, bh->b_blocknr);
 
-		if (bh->b_count)
-			BUG();
-
-		bh->b_dev = B_FREE;  /* So it is obvious we are on the free list. */
-
-		/* Add to back of free list. */
-		if(!*bhp) {
-			*bhp = bh;
-			bh->b_prev_free = bh;
-		}
-
-		bh->b_next_free = *bhp;
-		bh->b_prev_free = (*bhp)->b_prev_free;
-		(*bhp)->b_prev_free->b_next_free = bh;
-		(*bhp)->b_prev_free = bh;
-	}
+	spin_lock(&lru_list_lock);
+	write_lock(&hash_table_lock);
+	__hash_link(bh, head);
+	__insert_into_lru_list(bh, bh->b_list);
+	write_unlock(&hash_table_lock);
+	spin_unlock(&lru_list_lock);
 }
 
-struct buffer_head * find_buffer(kdev_t dev, int block, int size)
-{		
-	struct buffer_head * next;
+/* This function must only run if there are no other
+ * references _anywhere_ to this buffer head.
+ */
+static void put_last_free(struct buffer_head * bh)
+{
+	struct bh_free_head *head = &free_list[BUFSIZE_INDEX(bh->b_size)];
+	struct buffer_head **bhp = &head->list;
 
-	next = hash(dev,block);
-	for (;;) {
-		struct buffer_head *tmp = next;
-		if (!next)
-			break;
-		next = tmp->b_next;
-		if (tmp->b_blocknr != block || tmp->b_size != size || tmp->b_dev != dev)
-			continue;
-		next = tmp;
-		break;
+	spin_lock(&head->lock);
+	bh->b_dev = B_FREE;
+	if(!*bhp) {
+		*bhp = bh;
+		bh->b_prev_free = bh;
 	}
-	return next;
+	bh->b_next_free = *bhp;
+	bh->b_prev_free = (*bhp)->b_prev_free;
+	(*bhp)->b_prev_free->b_next_free = bh;
+	(*bhp)->b_prev_free = bh;
+	spin_unlock(&head->lock);
 }
 
 /*
@@ -579,10 +566,19 @@
  */
 struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
 {
-	struct buffer_head * bh;
-	bh = find_buffer(dev,block,size);
+	struct buffer_head **head = &hash(dev, block);
+	struct buffer_head *bh;
+
+	read_lock(&hash_table_lock);
+	for(bh = *head; bh; bh = bh->b_next)
+		if (bh->b_blocknr == block	&&
+		    bh->b_size    == size	&&
+		    bh->b_dev     == dev)
+			break;
 	if (bh)
-		bh->b_count++;
+		atomic_inc(&bh->b_count);
+	read_unlock(&hash_table_lock);
+
 	return bh;
 }
 
@@ -631,6 +627,8 @@
 	 * around on the free list, and we can get in a loop if we are not careful.
 	 */
 	for(nlist = 0; nlist < NR_LIST; nlist++) {
+	repeat:
+		spin_lock(&lru_list_lock);
 		bh = lru_list[nlist];
 		for (i = nr_buffers_type[nlist]*2 ; --i > 0 ; bh = bhnext) {
 			if(!bh)
@@ -641,21 +639,25 @@
 				 continue;
 			if (bh->b_size == size)
 				 continue;
-			bhnext->b_count++;
-			bh->b_count++;
-			wait_on_buffer(bh);
-			bhnext->b_count--;
+			if (buffer_locked(bh)) {
+				atomic_inc(&bh->b_count);
+				spin_unlock(&lru_list_lock);
+				wait_on_buffer(bh);
+				atomic_dec(&bh->b_count);
+				goto repeat;
+			}
 			if (bh->b_dev == dev && bh->b_size != size) {
 				clear_bit(BH_Dirty, &bh->b_state);
 				clear_bit(BH_Uptodate, &bh->b_state);
 				clear_bit(BH_Req, &bh->b_state);
 				bh->b_flushtime = 0;
 			}
-			if (--bh->b_count)
-				continue;
-			remove_from_queues(bh);
-			put_last_free(bh);
+			if (atomic_read(&bh->b_count) == 0) {
+				__remove_from_queues(bh);
+				put_last_free(bh);
+			}
 		}
+		spin_unlock(&lru_list_lock);
 	}
 }
 
@@ -671,13 +673,10 @@
 	}
 }
 
-void init_buffer(struct buffer_head *bh, kdev_t dev, int block,
-		 bh_end_io_t *handler, void *dev_id)
+void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *dev_id)
 {
 	bh->b_list = BUF_CLEAN;
 	bh->b_flushtime = 0;
-	bh->b_dev = dev;
-	bh->b_blocknr = block;
 	bh->b_end_io = handler;
 	bh->b_dev_id = dev_id;
 }
@@ -688,6 +687,92 @@
 	unlock_buffer(bh);
 }
 
+static void end_buffer_io_bad(struct buffer_head *bh, int uptodate)
+{
+	mark_buffer_uptodate(bh, uptodate);
+	unlock_buffer(bh);
+	BUG();
+}
+
+static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
+{
+	static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
+	unsigned long flags;
+	struct buffer_head *tmp;
+	struct page *page;
+	int free;
+
+	mark_buffer_uptodate(bh, uptodate);
+
+	/* This is a temporary buffer used for page I/O. */
+	page = mem_map + MAP_NR(bh->b_data);
+
+	if (!uptodate)
+		SetPageError(page);
+
+	/*
+	 * Be _very_ careful from here on. Bad things can happen if
+	 * two buffer heads end IO at almost the same time and both
+	 * decide that the page is now completely done.
+	 *
+	 * Async buffer_heads are here only as labels for IO, and get
+	 * thrown away once the IO for this page is complete.  IO is
+	 * deemed complete once all buffers have been visited
+	 * (b_count==0) and are now unlocked. We must make sure that
+	 * only the _last_ buffer that decrements its count is the one
+	 * that free's the page..
+	 */
+	spin_lock_irqsave(&page_uptodate_lock, flags);
+	unlock_buffer(bh);
+	atomic_dec(&bh->b_count);
+	tmp = bh->b_this_page;
+	while (tmp != bh) {
+		if (atomic_read(&tmp->b_count) &&
+		    (tmp->b_end_io == end_buffer_io_async))
+			goto still_busy;
+		tmp = tmp->b_this_page;
+	}
+
+	/* OK, the async IO on this page is complete. */
+	spin_unlock_irqrestore(&page_uptodate_lock, flags);
+
+	/*
+	 * if none of the buffers had errors then we can set the
+	 * page uptodate:
+	 */
+	if (!PageError(page))
+		SetPageUptodate(page);
+
+	/*
+	 * Run the hooks that have to be done when a page I/O has completed.
+	 *
+	 * Note - we need to test the flags before we unlock the page, but
+	 * we must not actually free the page until after the unlock!
+	 */
+	if (test_and_clear_bit(PG_decr_after, &page->flags))
+		atomic_dec(&nr_async_pages);
+
+	if (test_and_clear_bit(PG_free_swap_after, &page->flags))
+		swap_free(page->offset);
+
+	free = test_and_clear_bit(PG_free_after, &page->flags);
+
+	if (page->owner != -1)
+		PAGE_BUG(page);
+	page->owner = (int)current;
+	UnlockPage(page);
+
+	if (free)
+		__free_page(page);
+
+	return;
+
+still_busy:
+	spin_unlock_irqrestore(&page_uptodate_lock, flags);
+	return;
+}
+
+
 /*
  * Ok, this is getblk, and it isn't very clear, again to hinder
  * race-conditions. Most of the code is seldom used, (ie repeating),
@@ -713,22 +798,26 @@
 	}
 
 	isize = BUFSIZE_INDEX(size);
-get_free:
-	bh = free_list[isize];
+	spin_lock(&free_list[isize].lock);
+	bh = free_list[isize].list;
+	if (bh) {
+		__remove_from_free_list(bh, isize);
+		atomic_set(&bh->b_count, 1);
+	}
+	spin_unlock(&free_list[isize].lock);
 	if (!bh)
 		goto refill;
-	remove_from_free_list(bh);
 
 	/* OK, FINALLY we know that this buffer is the only one of its kind,
-	 * and that it's unused (b_count=0), unlocked, and clean.
+	 * we hold a reference (b_count>0), it is unlocked, and it is clean.
 	 */
-	init_buffer(bh, dev, block, end_buffer_io_sync, NULL);
-	bh->b_count = 1;
-	bh->b_state = 0;
+	init_buffer(bh, end_buffer_io_sync, NULL);
+	bh->b_dev = dev;
+	bh->b_blocknr = block;
+	bh->b_state = 1 << BH_Mapped;
 
 	/* Insert the buffer into the regular lists */
-	insert_into_lru_list(bh);
-	insert_into_hash_list(bh);
+	insert_into_queues(bh);
 	goto out;
 
 	/*
@@ -737,24 +826,12 @@
 	 */
 refill:
 	refill_freelist(size);
-	if (!find_buffer(dev,block,size))
-		goto get_free;
 	goto repeat;
 out:
 	return bh;
 }
 
 /*
- * Put a buffer into the appropriate list, without side-effects.
- */
-static void file_buffer(struct buffer_head *bh, int list)
-{
-	remove_from_lru_list(bh);
-	bh->b_list = list;
-	insert_into_lru_list(bh);
-}
-
-/*
  * if a new dirty buffer is created we need to balance bdflush.
  *
  * in the future we might want to make bdflush aware of different
@@ -783,6 +860,7 @@
 static inline void __mark_dirty(struct buffer_head *bh, int flag)
 {
 	bh->b_flushtime = jiffies + (flag ? bdf_prm.b_un.age_super : bdf_prm.b_un.age_buffer);
+	clear_bit(BH_New, &bh->b_state);
 	refile_buffer(bh);
 }
 
@@ -791,34 +869,29 @@
 	__mark_dirty(bh, flag);
 }
 
-void __atomic_mark_buffer_dirty(struct buffer_head *bh, int flag)
-{
-	lock_kernel();
-	__mark_dirty(bh, flag);
-	unlock_kernel();
-}
-
 /*
  * A buffer may need to be moved from one buffer list to another
  * (e.g. in case it is not shared any more). Handle this.
  */
-void refile_buffer(struct buffer_head * buf)
+static __inline__ void __refile_buffer(struct buffer_head *bh)
 {
-	int dispose;
-
-	if (buf->b_dev == B_FREE) {
-		printk("Attempt to refile free buffer\n");
-		return;
-	}
-
-	dispose = BUF_CLEAN;
-	if (buffer_locked(buf))
+	int dispose = BUF_CLEAN;
+	if (buffer_locked(bh))
 		dispose = BUF_LOCKED;
-	if (buffer_dirty(buf))
+	if (buffer_dirty(bh))
 		dispose = BUF_DIRTY;
+	if (dispose != bh->b_list) {
+		__remove_from_lru_list(bh, bh->b_list);
+		bh->b_list = dispose;
+		__insert_into_lru_list(bh, dispose);
+	}
+}
 
-	if (dispose != buf->b_list)
-		file_buffer(buf, dispose);
+void refile_buffer(struct buffer_head *bh)
+{
+	spin_lock(&lru_list_lock);
+	__refile_buffer(bh);
+	spin_unlock(&lru_list_lock);
 }
 
 /*
@@ -828,9 +901,8 @@
 {
 	touch_buffer(buf);
 
-	if (buf->b_count) {
-		buf->b_count--;
-		wake_up(&buffer_wait);
+	if (atomic_read(&buf->b_count)) {
+		atomic_dec(&buf->b_count);
 		return;
 	}
 	printk("VFS: brelse: Trying to free free buffer\n");
@@ -844,14 +916,21 @@
  */
 void __bforget(struct buffer_head * buf)
 {
-	if (buf->b_count != 1 || buffer_locked(buf)) {
-		__brelse(buf);
-		return;
+	spin_lock(&lru_list_lock);
+	write_lock(&hash_table_lock);
+	if (atomic_read(&buf->b_count) != 1 || buffer_locked(buf)) {
+		touch_buffer(buf);
+		atomic_dec(&buf->b_count);
+	} else {
+		atomic_set(&buf->b_count, 0);
+		buf->b_state = 0;
+		if (buf->b_pprev)
+			__hash_unlink(buf);
+		__remove_from_lru_list(buf, buf->b_list);
+		put_last_free(buf);
 	}
-	buf->b_count = 0;
-	buf->b_state = 0;
-	remove_from_queues(buf);
-	put_last_free(buf);
+	write_unlock(&hash_table_lock);
+	spin_unlock(&lru_list_lock);
 }
 
 /*
@@ -941,49 +1020,25 @@
 /*
  * Note: the caller should wake up the buffer_wait list if needed.
  */
-static void put_unused_buffer_head(struct buffer_head * bh)
+static __inline__ void __put_unused_buffer_head(struct buffer_head * bh)
 {
 	if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
-		nr_buffer_heads--;
 		kmem_cache_free(bh_cachep, bh);
-		return;
+	} else {
+		bh->b_blocknr = -1;
+		init_waitqueue_head(&bh->b_wait);
+		nr_unused_buffer_heads++;
+		bh->b_next_free = unused_list;
+		bh->b_this_page = NULL;
+		unused_list = bh;
 	}
-
-//	memset(bh, 0, sizeof(*bh));
-	bh->b_blocknr = -1;
-	init_waitqueue_head(&bh->b_wait);
-	nr_unused_buffer_heads++;
-	bh->b_next_free = unused_list;
-	unused_list = bh;
 }
 
-/* 
- * We can't put completed temporary IO buffer_heads directly onto the
- * unused_list when they become unlocked, since the device driver
- * end_request routines still expect access to the buffer_head's
- * fields after the final unlock.  So, the device driver puts them on
- * the reuse_list instead once IO completes, and we recover these to
- * the unused_list here.
- *
- * Note that we don't do a wakeup here, but return a flag indicating
- * whether we got any buffer heads. A task ready to sleep can check
- * the returned value, and any tasks already sleeping will have been
- * awakened when the buffer heads were added to the reuse list.
- */
-static inline int recover_reusable_buffer_heads(void)
-{
-	struct buffer_head *head = xchg(&reuse_list, NULL);
-	int found = 0;
-	
-	if (head) {
-		do {
-			struct buffer_head *bh = head;
-			head = head->b_next_free;
-			put_unused_buffer_head(bh);
-		} while (head);
-		found = 1;
-	}
-	return found;
+static void put_unused_buffer_head(struct buffer_head *bh)
+{
+	spin_lock(&unused_list_lock);
+	__put_unused_buffer_head(bh);
+	spin_unlock(&unused_list_lock);
 }
 
 /*
@@ -995,13 +1050,15 @@
 {
 	struct buffer_head * bh;
 
-	recover_reusable_buffer_heads();
+	spin_lock(&unused_list_lock);
 	if (nr_unused_buffer_heads > NR_RESERVED) {
 		bh = unused_list;
 		unused_list = bh->b_next_free;
 		nr_unused_buffer_heads--;
+		spin_unlock(&unused_list_lock);
 		return bh;
 	}
+	spin_unlock(&unused_list_lock);
 
 	/* This is critical.  We can't swap out pages to get
 	 * more buffer heads, because the swap-out may need
@@ -1010,20 +1067,23 @@
 	if((bh = kmem_cache_alloc(bh_cachep, SLAB_BUFFER)) != NULL) {
 		memset(bh, 0, sizeof(*bh));
 		init_waitqueue_head(&bh->b_wait);
-		nr_buffer_heads++;
 		return bh;
 	}
 
 	/*
 	 * If we need an async buffer, use the reserved buffer heads.
 	 */
-	if (async && unused_list) {
-		bh = unused_list;
-		unused_list = bh->b_next_free;
-		nr_unused_buffer_heads--;
-		return bh;
+	if (async) {
+		spin_lock(&unused_list_lock);
+		if (unused_list) {
+			bh = unused_list;
+			unused_list = bh->b_next_free;
+			nr_unused_buffer_heads--;
+			spin_unlock(&unused_list_lock);
+			return bh;
+		}
+		spin_unlock(&unused_list_lock);
 	}
-
 #if 0
 	/*
 	 * (Pending further analysis ...)
@@ -1035,7 +1095,6 @@
 	   (bh = kmem_cache_alloc(bh_cachep, SLAB_KERNEL)) != NULL) {
 		memset(bh, 0, sizeof(*bh));
 		init_waitqueue_head(&bh->b_wait);
-		nr_buffer_heads++;
 		return bh;
 	}
 #endif
@@ -1052,8 +1111,7 @@
  * from ordinary buffer allocations, and only async requests are allowed
  * to sleep waiting for buffer heads. 
  */
-static struct buffer_head * create_buffers(unsigned long page, 
-						unsigned long size, int async)
+static struct buffer_head * create_buffers(unsigned long page, unsigned long size, int async)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	struct buffer_head *bh, *head;
@@ -1073,11 +1131,14 @@
 
 		bh->b_state = 0;
 		bh->b_next_free = NULL;
-		bh->b_count = 0;
+		bh->b_pprev = NULL;
+		atomic_set(&bh->b_count, 0);
 		bh->b_size = size;
 
 		bh->b_data = (char *) (page+offset);
-		bh->b_list = 0;
+		bh->b_list = BUF_CLEAN;
+		bh->b_flushtime = 0;
+		bh->b_end_io = end_buffer_io_bad;
 	}
 	return head;
 /*
@@ -1118,115 +1179,16 @@
 	 */
 	add_wait_queue(&buffer_wait, &wait);
 	current->state = TASK_UNINTERRUPTIBLE;
-	if (!recover_reusable_buffer_heads())
+	if (nr_unused_buffer_heads < MAX_BUF_PER_PAGE) {
+		current->policy |= SCHED_YIELD;
 		schedule();
+	}
 	remove_wait_queue(&buffer_wait, &wait);
 	current->state = TASK_RUNNING;
 	goto try_again;
 }
 
-/* Run the hooks that have to be done when a page I/O has completed. */
-static inline void after_unlock_page (struct page * page)
-{
-	if (test_and_clear_bit(PG_decr_after, &page->flags)) {
-		atomic_dec(&nr_async_pages);
-#ifdef DEBUG_SWAP
-		printk ("DebugVM: Finished IO on page %p, nr_async_pages %d\n",
-			(char *) page_address(page), 
-			atomic_read(&nr_async_pages));
-#endif
-	}
-	if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
-		swap_after_unlock_page(page->offset);
-	if (test_and_clear_bit(PG_free_after, &page->flags))
-		__free_page(page);
-}
-
-/*
- * Free all temporary buffers belonging to a page.
- * This needs to be called with interrupts disabled.
- */
-static inline void free_async_buffers (struct buffer_head * bh)
-{
-	struct buffer_head *tmp, *tail;
-
-	/*
-	 * Link all the buffers into the b_next_free list,
-	 * so we only have to do one xchg() operation ...
-	 */
-	tail = bh;
-	while ((tmp = tail->b_this_page) != bh) {
-		tail->b_next_free = tmp;
-		tail = tmp;
-	};
-
-	/* Update the reuse list */
-	tail->b_next_free = xchg(&reuse_list, NULL);
-	reuse_list = bh;
-
-	/* Wake up any waiters ... */
-	wake_up(&buffer_wait);
-}
-
-static void end_buffer_io_async(struct buffer_head * bh, int uptodate)
-{
-	unsigned long flags;
-	struct buffer_head *tmp;
-	struct page *page;
-
-	mark_buffer_uptodate(bh, uptodate);
-
-	/* This is a temporary buffer used for page I/O. */
-	page = mem_map + MAP_NR(bh->b_data);
-
-	if (!uptodate)
-		SetPageError(page);
-
-	/*
-	 * Be _very_ careful from here on. Bad things can happen if
-	 * two buffer heads end IO at almost the same time and both
-	 * decide that the page is now completely done.
-	 *
-	 * Async buffer_heads are here only as labels for IO, and get
-	 * thrown away once the IO for this page is complete.  IO is
-	 * deemed complete once all buffers have been visited
-	 * (b_count==0) and are now unlocked. We must make sure that
-	 * only the _last_ buffer that decrements its count is the one
-	 * that free's the page..
-	 */
-	save_flags(flags);
-	cli();
-	unlock_buffer(bh);
-	tmp = bh->b_this_page;
-	while (tmp != bh) {
-		if (buffer_locked(tmp))
-			goto still_busy;
-		tmp = tmp->b_this_page;
-	}
-
-	/* OK, the async IO on this page is complete. */
-	restore_flags(flags);
-
-	after_unlock_page(page);
-	/*
-	 * if none of the buffers had errors then we can set the
-	 * page uptodate:
-	 */
-	if (!PageError(page))
-		SetPageUptodate(page);
-	if (page->owner != -1)
-		PAGE_BUG(page);
-	page->owner = (int)current;
-	UnlockPage(page);
-
-	return;
-
-still_busy:
-	restore_flags(flags);
-	return;
-}
-
-static int create_page_buffers (int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
+static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
 {
 	struct buffer_head *head, *bh, *tail;
 	int block;
@@ -1240,9 +1202,7 @@
 	 * They show up in the buffer hash table and are registered in
 	 * page->buffers.
 	 */
-	lock_kernel();
 	head = create_buffers(page_address(page), size, 1);
-	unlock_kernel();
 	if (page->buffers)
 		BUG();
 	if (!head)
@@ -1252,7 +1212,9 @@
 		block = *(b++);
 
 		tail = bh;
-		init_buffer(bh, dev, block, end_buffer_io_async, NULL);
+		init_buffer(bh, end_buffer_io_async, NULL);
+		bh->b_dev = dev;
+		bh->b_blocknr = block;
 
 		/*
 		 * When we use bmap, we define block zero to represent
@@ -1261,9 +1223,11 @@
 		 * two cases.
 		 */
 		if (bmap && !block) {
-			set_bit(BH_Uptodate, &bh->b_state);
 			memset(bh->b_data, 0, size);
+			set_bit(BH_Uptodate, &bh->b_state);
+			continue;
 		}
+		set_bit(BH_Mapped, &bh->b_state);
 	}
 	tail->b_this_page = head;
 	get_page(page);
@@ -1287,7 +1251,6 @@
 		BUG();
 	if (!page->buffers)
 		return 0;
-	lock_kernel();
 
 	head = page->buffers;
 	bh = head;
@@ -1299,14 +1262,16 @@
 		 * is this block fully flushed?
 		 */
 		if (offset <= curr_off) {
-			if (bh->b_blocknr) {
-				bh->b_count++;
+			if (buffer_mapped(bh)) {
+				atomic_inc(&bh->b_count);
 				wait_on_buffer(bh);
 				if (bh->b_dev == B_FREE)
 					BUG();
 				mark_buffer_clean(bh);
+				clear_bit(BH_Uptodate, &bh->b_state);
+				clear_bit(BH_Mapped, &bh->b_state);
 				bh->b_blocknr = 0;
-				bh->b_count--;
+				atomic_dec(&bh->b_count);
 			}
 		}
 		curr_off = next_off;
@@ -1318,22 +1283,24 @@
 	 * the 'final' flushpage. We have invalidated the bmap
 	 * cached value unconditionally, so real IO is not
 	 * possible anymore.
-	 */
-	if (!offset)
-		try_to_free_buffers(page);
+	 *
+	 * If the free doesn't work out, the buffers can be
+	 * left around - they just turn into anonymous buffers
+	 * instead.
+	 */
+	if (!offset) {
+		if (!try_to_free_buffers(page))
+			atomic_add(PAGE_CACHE_SIZE, &buffermem);
+	}
 
-	unlock_kernel();
 	return 0;
 }
 
-static void create_empty_buffers (struct page *page,
-			struct inode *inode, unsigned long blocksize)
+static void create_empty_buffers(struct page *page, struct inode *inode, unsigned long blocksize)
 {
 	struct buffer_head *bh, *head, *tail;
 
-	lock_kernel();
 	head = create_buffers(page_address(page), blocksize, 1);
-	unlock_kernel();
 	if (page->buffers)
 		BUG();
 
@@ -1341,6 +1308,7 @@
 	do {
 		bh->b_dev = inode->i_dev;
 		bh->b_blocknr = 0;
+		bh->b_end_io = end_buffer_io_bad;
 		tail = bh;
 		bh = bh->b_this_page;
 	} while (bh);
@@ -1353,12 +1321,12 @@
  * block_write_full_page() is SMP-safe - currently it's still
  * being called with the kernel lock held, but the code is ready.
  */
-int block_write_full_page (struct file *file, struct page *page, fs_getblock_t fs_get_block)
+int block_write_full_page(struct file *file, struct page *page)
 {
 	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
-	int err, created, i;
-	unsigned long block, phys, offset;
+	int err, i;
+	unsigned long block, offset;
 	struct buffer_head *bh, *head;
 
 	if (!PageLocked(page))
@@ -1381,23 +1349,22 @@
 		if (!bh)
 			BUG();
 
-		if (!bh->b_blocknr) {
-			err = -EIO;
-			phys = fs_get_block (inode, block, 1, &err, &created);
-			if (!phys)
+		/*
+		 * If the buffer isn't up-to-date, we can't be sure
+		 * that the buffer has been initialized with the proper
+		 * block number information etc..
+		 *
+		 * Leave it to the low-level FS to make all those
+		 * decisions (block #0 may actually be a valid block)
+		 */
+		bh->b_end_io = end_buffer_io_sync;
+		if (!buffer_mapped(bh)) {
+			err = inode->i_op->get_block(inode, block, bh, 1);
+			if (err)
 				goto out;
-
-			init_buffer(bh, inode->i_dev, phys, end_buffer_io_sync, NULL);
-			bh->b_state = (1<<BH_Uptodate);
-		} else {
-			/*
-			 * block already exists, just mark it uptodate and
-			 * dirty:
-			 */
-			bh->b_end_io = end_buffer_io_sync;
-			set_bit(BH_Uptodate, &bh->b_state);
 		}
-		atomic_mark_buffer_dirty(bh,0);
+		set_bit(BH_Uptodate, &bh->b_state);
+		mark_buffer_dirty(bh,0);
 
 		bh = bh->b_this_page;
 		block++;
@@ -1410,15 +1377,15 @@
 	return err;
 }
 
-int block_write_partial_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf, fs_getblock_t fs_get_block)
+int block_write_partial_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
 {
 	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	unsigned long block;
-	int err, created, partial;
+	int err, partial;
 	unsigned long blocksize, start_block, end_block;
 	unsigned long start_offset, start_bytes, end_bytes;
-	unsigned long bbits, phys, blocks, i, len;
+	unsigned long bbits, blocks, i, len;
 	struct buffer_head *bh, *head;
 	char * target_buf;
 
@@ -1469,46 +1436,35 @@
 				partial = 1;
 			goto skip;
 		}
-		if (!bh->b_blocknr) {
-			err = -EIO;
-			phys = fs_get_block (inode, block, 1, &err, &created);
-			if (!phys)
-				goto out;
 
-			init_buffer(bh, inode->i_dev, phys, end_buffer_io_sync, NULL);
+		/*
+		 * If the buffer is not up-to-date, we need to ask the low-level
+		 * FS to do something for us (we used to have assumptions about
+		 * the meaning of b_blocknr etc, that's bad).
+		 *
+		 * If "update" is set, that means that the low-level FS should
+		 * try to make sure that the block is up-to-date because we're
+		 * not going to fill it completely.
+		 */
+		bh->b_end_io = end_buffer_io_sync;
+		if (!buffer_mapped(bh)) {
+			err = inode->i_op->get_block(inode, block, bh, 1);
+			if (err)
+				goto out;
+		}
 
-			/*
-			 * if partially written block which has contents on
-			 * disk, then we have to read it first.
-			 * We also rely on the fact that filesystem holes
-			 * cannot be written.
-			 */
-			if (start_offset || (end_bytes && (i == end_block))) {
-				if (created) {
-					memset(bh->b_data, 0, bh->b_size);
-				} else {
-					bh->b_state = 0;
-					ll_rw_block(READ, 1, &bh);
-					lock_kernel();
-					wait_on_buffer(bh);
-					unlock_kernel();
-					err = -EIO;
-					if (!buffer_uptodate(bh))
-						goto out;
-				}
+		if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
+			if (buffer_new(bh)) {
+				memset(bh->b_data, 0, bh->b_size);
+			} else {
+				ll_rw_block(READ, 1, &bh);
+				wait_on_buffer(bh);
+				err = -EIO;
+				if (!buffer_uptodate(bh))
+					goto out;
 			}
-
-			bh->b_state = (1<<BH_Uptodate);
-		} else {
-			/*
-			 * block already exists, just mark it uptodate:
-			 */
-			bh->b_end_io = end_buffer_io_sync;
-			set_bit(BH_Uptodate, &bh->b_state);
-			created = 0;
 		}
 
-		err = -EFAULT;
 		len = blocksize;
 		if (start_offset) {
 			len = start_bytes;
@@ -1517,8 +1473,7 @@
 			len = end_bytes;
 			end_bytes = 0;
 		}
-		if (copy_from_user(target_buf, buf, len))
-			goto out;
+		err = copy_from_user(target_buf, buf, len);
 		target_buf += len;
 		buf += len;
 
@@ -1538,12 +1493,18 @@
 		 * should not penalize them for somebody else writing
 		 * lots of dirty pages.
 		 */
+		set_bit(BH_Uptodate, &bh->b_state);
 		if (!test_and_set_bit(BH_Dirty, &bh->b_state)) {
-			__atomic_mark_buffer_dirty(bh, bdf_prm.b_un.age_buffer);
+			__mark_dirty(bh, 0);
 			if (too_many_dirty_buffers)
 				balance_dirty(bh->b_dev);
 		}
 
+		if (err) {
+			err = -EFAULT;
+			goto out;
+		}
+
 skip:
 		i++;
 		block++;
@@ -1572,6 +1533,9 @@
  *
  * brw_page() is SMP-safe, although it's being called with the
  * kernel lock held - but the code is ready.
+ *
+ * FIXME: we need a swapper_inode->get_block function to remove
+ *        some of the bmap kludges and interface ugliness here.
  */
 int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
 {
@@ -1600,7 +1564,7 @@
 	do {
 		block = *(b++);
 
-		if (fresh && (bh->b_count != 0))
+		if (fresh && (atomic_read(&bh->b_count) != 0))
 			BUG();
 		if (rw == READ) {
 			if (!fresh)
@@ -1613,6 +1577,7 @@
 					BUG();
 				if (!buffer_uptodate(bh)) {
 					arr[nr++] = bh;
+					atomic_inc(&bh->b_count);
 				}
 			}
 		} else { /* WRITE */
@@ -1625,8 +1590,9 @@
 					BUG();
 			}
 			set_bit(BH_Uptodate, &bh->b_state);
-			atomic_mark_buffer_dirty(bh, 0);
+			set_bit(BH_Dirty, &bh->b_state);
 			arr[nr++] = bh;
+			atomic_inc(&bh->b_count);
 		}
 		bh = bh->b_this_page;
 	} while (bh != head);
@@ -1649,30 +1615,7 @@
 }
 
 /*
- * This is called by end_request() when I/O has completed.
- */
-void mark_buffer_uptodate(struct buffer_head * bh, int on)
-{
-	if (on) {
-		struct buffer_head *tmp = bh;
-		struct page *page;
-		set_bit(BH_Uptodate, &bh->b_state);
-		/* If a page has buffers and all these buffers are uptodate,
-		 * then the page is uptodate. */
-		do {
-			if (!test_bit(BH_Uptodate, &tmp->b_state))
-				return;
-			tmp=tmp->b_this_page;
-		} while (tmp && tmp != bh);
-		page = mem_map + MAP_NR(bh->b_data);
-		SetPageUptodate(page);
-		return;
-	}
-	clear_bit(BH_Uptodate, &bh->b_state);
-}
-
-/*
- * Generic "readpage" function for block devices that have the normal
+ * Generic "read page" function for block devices that have the normal
  * bmap functionality. This is most of the block device filesystems.
  * Reads the page asynchronously --- the unlock_buffer() and
  * mark_buffer_uptodate() functions propagate buffer state into the
@@ -1682,7 +1625,7 @@
 {
 	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
-	unsigned long iblock, phys_block;
+	unsigned long iblock;
 	struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
 	unsigned int blocksize, blocks;
 	int nr;
@@ -1700,33 +1643,25 @@
 	head = page->buffers;
 	bh = head;
 	nr = 0;
+
 	do {
-		phys_block = bh->b_blocknr;
-		/*
-		 * important, we have to retry buffers that already have
-		 * their bnr cached but had an IO error!
-		 */
-		if (!buffer_uptodate(bh)) {
-			phys_block = inode->i_op->bmap(inode, iblock);
-			/*
-			 * this is safe to do because we hold the page lock:
-			 */
-			if (phys_block) {
-				init_buffer(bh, inode->i_dev, phys_block,
-						end_buffer_io_async, NULL);
-				arr[nr] = bh;
-				nr++;
-			} else {
-				/*
-				 * filesystem 'hole' represents zero-contents:
-				 */
+		if (buffer_uptodate(bh))
+			continue;
+
+		if (!buffer_mapped(bh)) {
+			inode->i_op->get_block(inode, iblock, bh, 0);
+			if (!buffer_mapped(bh)) {
 				memset(bh->b_data, 0, blocksize);
 				set_bit(BH_Uptodate, &bh->b_state);
+				continue;
 			}
 		}
-		iblock++;
-		bh = bh->b_this_page;
-	} while (bh != head);
+
+		init_buffer(bh, end_buffer_io_async, NULL);
+		atomic_inc(&bh->b_count);
+		arr[nr] = bh;
+		nr++;
+	} while (iblock++, (bh = bh->b_this_page) != head);
 
 	++current->maj_flt;
 	if (nr) {
@@ -1770,8 +1705,9 @@
 	}
 
 	isize = BUFSIZE_INDEX(size);
-	insert_point = free_list[isize];
 
+	spin_lock(&free_list[isize].lock);
+	insert_point = free_list[isize].list;
 	tmp = bh;
 	while (1) {
 		if (insert_point) {
@@ -1790,9 +1726,11 @@
 			break;
 	}
 	tmp->b_this_page = bh;
-	free_list[isize] = bh;
+	free_list[isize].list = bh;
+	spin_unlock(&free_list[isize].lock);
+
 	mem_map[MAP_NR(page)].buffers = bh;
-	buffermem += PAGE_SIZE;
+	atomic_add(PAGE_SIZE, &buffermem);
 	return 1;
 }
 
@@ -1800,7 +1738,7 @@
  * Can the buffer be thrown out?
  */
 #define BUFFER_BUSY_BITS	((1<<BH_Dirty) | (1<<BH_Lock) | (1<<BH_Protected))
-#define buffer_busy(bh)	((bh)->b_count || ((bh)->b_state & BUFFER_BUSY_BITS))
+#define buffer_busy(bh)		(atomic_read(&(bh)->b_count) | ((bh)->b_state & BUFFER_BUSY_BITS))
 
 /*
  * try_to_free_buffers() checks if all the buffers on this particular page
@@ -1808,90 +1746,70 @@
  *
  * Wake up bdflush() if this fails - if we're running low on memory due
  * to dirty buffers, we need to flush them out as quickly as possible.
+ *
+ * NOTE: There are quite a number of ways that threads of control can
+ *       obtain a reference to a buffer head within a page.  So we must
+ *	 lock out all of these paths to cleanly toss the page.
  */
 int try_to_free_buffers(struct page * page)
 {
 	struct buffer_head * tmp, * bh = page->buffers;
+	int index = BUFSIZE_INDEX(bh->b_size);
+	int ret;
 
+	spin_lock(&lru_list_lock);
+	write_lock(&hash_table_lock);
+	spin_lock(&free_list[index].lock);
 	tmp = bh;
 	do {
 		struct buffer_head * p = tmp;
 
 		tmp = tmp->b_this_page;
-		if (!buffer_busy(p))
-			continue;
-
-		too_many_dirty_buffers = 1;
-		wakeup_bdflush(0);
-		return 0;
+		if (buffer_busy(p))
+			goto busy_buffer_page;
 	} while (tmp != bh);
 
+	spin_lock(&unused_list_lock);
 	tmp = bh;
 	do {
 		struct buffer_head * p = tmp;
 		tmp = tmp->b_this_page;
 
-		/* The buffer can be either on the regular queues or on the free list.. */		
-		if (p->b_dev == B_FREE)
-			remove_from_free_list(p);
-		else
-			remove_from_queues(p);
-
-		put_unused_buffer_head(p);
+		/* The buffer can be either on the regular
+		 * queues or on the free list..
+		 */
+		if (p->b_dev == B_FREE) {
+			__remove_from_free_list(p, index);
+		} else {
+			if (p->b_pprev)
+				__hash_unlink(p);
+			__remove_from_lru_list(p, p->b_list);
+		}
+		__put_unused_buffer_head(p);
 	} while (tmp != bh);
+	spin_unlock(&unused_list_lock);
 
 	/* Wake up anyone waiting for buffer heads */
 	wake_up(&buffer_wait);
 
 	/* And free the page */
 	page->buffers = NULL;
-	if (__free_page(page)) {
-		buffermem -= PAGE_SIZE;
-		return 1;
-	}
-	return 0;
-}
-
-/* ================== Debugging =================== */
-
-void show_buffers(void)
-{
-	struct buffer_head * bh;
-	int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
-	int protected = 0;
-	int nlist;
-	static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY"};
-
-	printk("Buffer memory:   %6dkB\n",buffermem>>10);
-	printk("Buffer heads:    %6d\n",nr_buffer_heads);
-	printk("Buffer blocks:   %6d\n",nr_buffers);
-	printk("Buffer hashed:   %6d\n",nr_hashed_buffers);
-
-	for(nlist = 0; nlist < NR_LIST; nlist++) {
-	  found = locked = dirty = used = lastused = protected = 0;
-	  bh = lru_list[nlist];
-	  if(!bh) continue;
-
-	  do {
-		found++;
-		if (buffer_locked(bh))
-			locked++;
-		if (buffer_protected(bh))
-			protected++;
-		if (buffer_dirty(bh))
-			dirty++;
-		if (bh->b_count)
-			used++, lastused = found;
-		bh = bh->b_next_free;
-	  } while (bh != lru_list[nlist]);
-	  printk("%8s: %d buffers, %d used (last=%d), "
-		 "%d locked, %d protected, %d dirty\n",
-		 buf_types[nlist], found, used, lastused,
-		 locked, protected, dirty);
-	};
+	__free_page(page);
+	ret = 1;
+out:
+	spin_unlock(&free_list[index].lock);
+	write_unlock(&hash_table_lock);
+	spin_unlock(&lru_list_lock);
+	return ret;
+
+busy_buffer_page:
+	/* Uhhuh, start writeback so that we don't end up with all dirty pages */
+	too_many_dirty_buffers = 1;
+	wakeup_bdflush(0);
+	ret = 0;
+	goto out;
 }
 
-
 /* ===================== Init ======================= */
 
 /*
@@ -1901,31 +1819,53 @@
  */
 void __init buffer_init(unsigned long memory_size)
 {
-	int order;
+	int order, i;
 	unsigned int nr_hash;
 
-	/* we need to guess at the right sort of size for a buffer cache.
-	   the heuristic from working with large databases and getting
-	   fsync times (ext2) manageable, is the following */
-
-	memory_size >>= 22;
-	for (order = 5; (1UL << order) < memory_size; order++);
+	/* The buffer cache hash table is less important these days,
+	 * trim it a bit.
+	 */
+	memory_size >>= 14;
+	memory_size *= sizeof(struct buffer_head *);
+	for (order = 0; (PAGE_SIZE << order) < memory_size; order++)
+		;
 
 	/* try to allocate something until we get it or we're asking
 	   for something that is really too small */
 
 	do {
-		nr_hash = (1UL << order) * PAGE_SIZE /
-		    sizeof(struct buffer_head *);
+		unsigned long tmp;
+
+		nr_hash = (PAGE_SIZE << order) / sizeof(struct buffer_head *);
+		bh_hash_mask = (nr_hash - 1);
+
+		tmp = nr_hash;
+		bh_hash_shift = 0;
+		while((tmp >>= 1UL) != 0UL)
+			bh_hash_shift++;
+
 		hash_table = (struct buffer_head **)
 		    __get_free_pages(GFP_ATOMIC, order);
-	} while (hash_table == NULL && --order > 4);
-	printk("buffer-cache hash table entries: %d (order: %d, %ld bytes)\n", nr_hash, order, (1UL<<order) * PAGE_SIZE);
-	
+	} while (hash_table == NULL && --order > 0);
+	printk("Buffer-cache hash table entries: %d (order: %d, %ld bytes)\n",
+	       nr_hash, order, (1UL<<order) * PAGE_SIZE);
+
 	if (!hash_table)
 		panic("Failed to allocate buffer hash table\n");
-	memset(hash_table, 0, nr_hash * sizeof(struct buffer_head *));
-	bh_hash_mask = nr_hash-1;
+
+	/* Setup hash chains. */
+	for(i = 0; i < nr_hash; i++)
+		hash_table[i] = NULL;
+
+	/* Setup free lists. */
+	for(i = 0; i < NR_SIZES; i++) {
+		free_list[i].list = NULL;
+		free_list[i].lock = SPIN_LOCK_UNLOCKED;
+	}
+
+	/* Setup lru lists. */
+	for(i = 0; i < NR_LIST; i++)
+		lru_list[i] = NULL;
 
 	bh_cachep = kmem_cache_create("buffer_head",
 				      sizeof(struct buffer_head),
@@ -1933,21 +1873,6 @@
 				      SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if(!bh_cachep)
 		panic("Cannot create buffer head SLAB cache\n");
-	/*
-	 * Allocate the reserved buffer heads.
-	 */
-	while (nr_buffer_heads < NR_RESERVED) {
-		struct buffer_head * bh;
-
-		bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC);
-		if (!bh)
-			break;
-		put_unused_buffer_head(bh);
-		nr_buffer_heads++;
-	}
-
-	lru_list[BUF_CLEAN] = 0;
-	grow_buffers(BLOCK_SIZE);
 }
 
 
@@ -1983,70 +1908,49 @@
 
 static int sync_old_buffers(void)
 {
-	int i;
-	int ndirty, nwritten;
 	int nlist;
-	int ncount;
-	struct buffer_head * bh, *next;
 
+	lock_kernel();
 	sync_supers(0);
 	sync_inodes(0);
+	unlock_kernel();
 
-	ncount = 0;
-#ifdef DEBUG
-	for(nlist = 0; nlist < NR_LIST; nlist++)
-#else
-	for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
-#endif
-	{
-		ndirty = 0;
-		nwritten = 0;
+	for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++) {
+		struct buffer_head *bh;
 	repeat:
-
+		spin_lock(&lru_list_lock);
 		bh = lru_list[nlist];
-		if(bh) 
-			 for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
-				 /* We may have stalled while waiting for I/O to complete. */
-				 if(bh->b_list != nlist) goto repeat;
-				 next = bh->b_next_free;
-				 if(!lru_list[nlist]) {
-					 printk("Dirty list empty %d\n", i);
-					 break;
-				 }
-				 
-				 /* Clean buffer on dirty list?  Refile it */
-				 if (nlist == BUF_DIRTY && !buffer_dirty(bh) && !buffer_locked(bh)) {
-					 refile_buffer(bh);
-					 continue;
-				 }
-				  
-				  /* Unlocked buffer on locked list?  Refile it */
-				  if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
-					  refile_buffer(bh);
-					  continue;
-				  }
+		if(bh) {
+			struct buffer_head *next;
+			int i;
+			for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
+				next = bh->b_next_free;
+
+				/* If the buffer is not on the proper list,
+				 * then refile it.
+				 */
+				if ((nlist == BUF_DIRTY &&
+				     (!buffer_dirty(bh) && !buffer_locked(bh))) ||
+				    (nlist == BUF_LOCKED && !buffer_locked(bh))) {
+					__refile_buffer(bh);
+					continue;
+				}
 				 
-				 if (buffer_locked(bh) || !buffer_dirty(bh))
-					  continue;
-				 ndirty++;
-				 nwritten++;
-				 next->b_count++;
-				 bh->b_count++;
-				 bh->b_flushtime = 0;
-#ifdef DEBUG
-				 if(nlist != BUF_DIRTY) ncount++;
-#endif
-				 ll_rw_block(WRITE, 1, &bh);
-				 bh->b_count--;
-				 next->b_count--;
-			 }
+				if (buffer_locked(bh) || !buffer_dirty(bh))
+					continue;
+
+				/* OK, now we are committed to write it out. */
+				bh->b_flushtime = 0;
+				atomic_inc(&bh->b_count);
+				spin_unlock(&lru_list_lock);
+				ll_rw_block(WRITE, 1, &bh);
+				atomic_dec(&bh->b_count);
+				goto repeat;
+			}
+		}
+		spin_unlock(&lru_list_lock);
 	}
 	run_task_queue(&tq_disk);
-#ifdef DEBUG
-	if (ncount) printk("sync_old_buffers: %d dirty buffers not on dirty list\n", ncount);
-	printk("Wrote %d/%d buffers\n", nwritten, ndirty);
-#endif
-	run_task_queue(&tq_disk);
 	return 0;
 }
 
@@ -2060,7 +1964,6 @@
 {
 	int i, error = -EPERM;
 
-	lock_kernel();
 	if (!capable(CAP_SYS_ADMIN))
 		goto out;
 
@@ -2092,7 +1995,6 @@
 	 */
 	error = 0;
 out:
-	unlock_kernel();
 	return error;
 }
 
@@ -2114,52 +2016,37 @@
 	sprintf(current->comm, "kflushd");
 	bdflush_tsk = current;
 
-	/*
-	 *	As a kernel thread we want to tamper with system buffers
-	 *	and other internals and thus be subject to the SMP locking
-	 *	rules. (On a uniprocessor box this does nothing).
-	 */
-	lock_kernel();
-		 
 	for (;;) {
 		int nlist;
 
 		CHECK_EMERGENCY_SYNC
 
-		for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
-		{
-			int nr;
-			int written = 0;
+		for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++) {
+			int nr, major, written = 0;
 			struct buffer_head *next;
-			int major;
 
 		repeat:
+			spin_lock(&lru_list_lock);
 			next = lru_list[nlist];
 			nr = nr_buffers_type[nlist];
-
 			while (nr-- > 0) {
 				struct buffer_head *bh = next;
-				/* We may have stalled while waiting for I/O to complete. */
-				if (next->b_list != nlist)
-					goto repeat;
+
 				next = next->b_next_free;
 					
-				/* Clean buffer on dirty list?  Refile it */
-				if (nlist == BUF_DIRTY && !buffer_dirty(bh)) {
-					refile_buffer(bh);
-					continue;
-				}
-					
-				/* Unlocked buffer on locked list?  Refile it */
-				if (nlist == BUF_LOCKED && !buffer_locked(bh)) {
-					refile_buffer(bh);
+				/* If the buffer is not on the correct list,
+				 * then refile it.
+				 */
+				if ((nlist == BUF_DIRTY &&
+				     (!buffer_dirty(bh) && !buffer_locked(bh))) ||
+				    (nlist == BUF_LOCKED && !buffer_locked(bh))) {
+					__refile_buffer(bh);
 					continue;
 				}
 
-				/*
-				 * If we aren't in panic mode, don't write out too much
-				 * at a time. Also, don't write out buffers we don't really
-				 * have to write out yet..
+				/* If we aren't in panic mode, don't write out too much
+				 * at a time. Also, don't write out buffers we don't
+				 * really have to write out yet..
 				 */
 				if (!too_many_dirty_buffers) {
 					if (written > bdf_prm.b_un.ndirty)
@@ -2172,9 +2059,6 @@
 					 continue;
 
 				major = MAJOR(bh->b_dev);
-				if (next)
-					next->b_count++;
-				bh->b_count++;
 				written++;
 				bh->b_flushtime = 0;
 
@@ -2182,18 +2066,18 @@
 				 * For the loop major we can try to do asynchronous writes,
 				 * but we have to guarantee that we're making some progress..
 				 */
+				atomic_inc(&bh->b_count);
+				spin_unlock(&lru_list_lock);
 				if (major == LOOP_MAJOR && written > 1) {
 					ll_rw_block(WRITEA, 1, &bh);
 					if (buffer_dirty(bh))
 						--written;
 				} else
 					ll_rw_block(WRITE, 1, &bh);
-
-				bh->b_count--;
-				if (next)
-					next->b_count--;
-				wake_up(&buffer_wait);
+				atomic_dec(&bh->b_count);
+				goto repeat;
 			}
+			spin_unlock(&lru_list_lock);
 		}
 		run_task_queue(&tq_disk);
 		wake_up(&bdflush_done);
@@ -2206,7 +2090,10 @@
 		 */
 		if (!too_many_dirty_buffers || nr_buffers_type[BUF_DIRTY] < bdf_prm.b_un.ndirty) {
 			too_many_dirty_buffers = 0;
-			sleep_on_timeout(&bdflush_wait, 5*HZ);
+			spin_lock_irq(&current->sigmask_lock);
+			flush_signals(current);
+			spin_unlock_irq(&current->sigmask_lock);
+			interruptible_sleep_on_timeout(&bdflush_wait, 5*HZ);
 		}
 	}
 }
diff -u --recursive --new-file v2.3.8/linux/fs/coda/dir.c linux/fs/coda/dir.c
--- v2.3.8/linux/fs/coda/dir.c	Sat May  8 17:56:37 1999
+++ linux/fs/coda/dir.c	Sun Jun 27 10:10:41 1999
@@ -77,9 +77,10 @@
 	coda_rename,	        /* rename */
 	NULL,	                /* readlink */
 	NULL,	                /* follow_link */
+	NULL,		        /* get_block */
 	NULL,	                /* readpage */
 	NULL,		        /* writepage */
-	NULL,		        /* bmap */
+	NULL,		        /* flushpage */
 	NULL,	                /* truncate */
 	coda_permission,        /* permission */
 	NULL,                   /* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/coda/file.c linux/fs/coda/file.c
--- v2.3.8/linux/fs/coda/file.c	Mon Aug 31 15:46:10 1998
+++ linux/fs/coda/file.c	Tue Jun 29 09:22:08 1999
@@ -47,13 +47,13 @@
 	NULL,		        /* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	coda_readpage,    	/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
         coda_permission,        /* permission */
 	NULL,                   /* smap */
-	NULL,                   /* update page */
         coda_revalidate_inode   /* revalidate */
 };
 
@@ -101,7 +101,7 @@
         CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", 
 	       coda_inode->i_ino, cii->c_ovp->i_ino, page->offset);
 
-        generic_readpage(&cont_file, page);
+        block_read_full_page(&cont_file, page);
         EXIT;
         return 0;
 }
@@ -256,7 +256,7 @@
         cont_file->f_pos = coda_file->f_pos;
         cont_file->f_mode = coda_file->f_mode;
         cont_file->f_flags = coda_file->f_flags;
-        cont_file->f_count  = coda_file->f_count;
+        atomic_set(&cont_file->f_count, atomic_read(&coda_file->f_count));
         cont_file->f_owner  = coda_file->f_owner;
 	cont_file->f_op = cont_inode->i_op->default_file_ops;
 	cont_file->f_dentry = cont_dentry;
diff -u --recursive --new-file v2.3.8/linux/fs/coda/pioctl.c linux/fs/coda/pioctl.c
--- v2.3.8/linux/fs/coda/pioctl.c	Mon Aug 31 15:46:10 1998
+++ linux/fs/coda/pioctl.c	Sun Jun 27 10:10:41 1999
@@ -46,13 +46,13 @@
 	NULL,		        /* rename */
 	NULL,	                /* readlink */
 	NULL,	                /* follow_link */
+	NULL,		        /* get_block */
 	NULL,	                /* readpage */
 	NULL,		        /* writepage */
-	NULL,		        /* bmap */
+	NULL,		        /* flushpage */
 	NULL,	                /* truncate */
 	coda_ioctl_permission,  /* permission */
 	NULL,                   /* smap */
-	NULL,                   /* update page */
         NULL                    /* revalidate */
 };
 
diff -u --recursive --new-file v2.3.8/linux/fs/coda/symlink.c linux/fs/coda/symlink.c
--- v2.3.8/linux/fs/coda/symlink.c	Fri Dec 18 12:45:00 1998
+++ linux/fs/coda/symlink.c	Sun Jun 27 10:10:41 1999
@@ -42,13 +42,13 @@
 	NULL,			/* rename */
 	coda_readlink,		/* readlink */
 	coda_follow_link,     	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,            	/* permission */
 	NULL,                   /* smap */
-	NULL,                   /* update page */
         NULL                    /* revalidate */
 };
 
diff -u --recursive --new-file v2.3.8/linux/fs/devices.c linux/fs/devices.c
--- v2.3.8/linux/fs/devices.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/devices.c	Sat Jun 26 12:04:39 1999
@@ -277,7 +277,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
@@ -333,11 +333,14 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 /*
diff -u --recursive --new-file v2.3.8/linux/fs/devpts/root.c linux/fs/devpts/root.c
--- v2.3.8/linux/fs/devpts/root.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/devpts/root.c	Sun Jun 27 10:10:41 1999
@@ -51,9 +51,10 @@
 	NULL,                   /* rename */
 	NULL,                   /* readlink */
 	NULL,                   /* follow_link */
+	NULL,                   /* get_block */
 	NULL,                   /* readpage */
 	NULL,                   /* writepage */
-	NULL,                   /* bmap */
+	NULL,                   /* flushpage */
 	NULL,                   /* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/efs/dir.c linux/fs/efs/dir.c
--- v2.3.8/linux/fs/efs/dir.c	Thu May 13 23:50:15 1999
+++ linux/fs/efs/dir.c	Sun Jun 27 10:10:41 1999
@@ -25,6 +25,8 @@
 	NULL			/* revalidate */
 };
 
+extern int efs_get_block(struct inode *, long, struct buffer_head *, int);
+
 struct inode_operations efs_dir_inode_operations = {
 	&efs_dir_operations,	/* default directory file-ops */
 	NULL,			/* create */
@@ -38,12 +40,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	efs_get_block,		/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	efs_bmap,		/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static int efs_readdir(struct file *filp, void *dirent, filldir_t filldir) {
diff -u --recursive --new-file v2.3.8/linux/fs/efs/file.c linux/fs/efs/file.c
--- v2.3.8/linux/fs/efs/file.c	Thu May 13 23:50:15 1999
+++ linux/fs/efs/file.c	Sun Jun 27 10:10:41 1999
@@ -8,6 +8,59 @@
 
 #include <linux/efs_fs.h>
 
+int efs_get_block(struct inode *inode, long iblock,
+		  struct buffer_head *bh_result, int create)
+{
+	int error = -EROFS;
+	long phys;
+
+	if (create)
+		return error;
+	if (iblock >= inode->i_blocks) {
+#ifdef DEBUG
+		/*
+		 * i have no idea why this happens as often as it does
+		 */
+		printk(KERN_WARNING "EFS: bmap(): block %d >= %ld (filesize %ld)\n",
+			block,
+			inode->i_blocks,
+			inode->i_size);
+#endif
+		return 0;
+	}
+	phys = efs_map_block(inode, iblock);
+	if (phys) {
+		bh_result->b_dev = inode->i_dev;
+		bh_result->b_blocknr = phys;
+		bh_result->b_state |= (1UL << BH_Mapped);
+	}
+	return 0;
+}
+
+int efs_bmap(struct inode *inode, efs_block_t block) {
+
+	if (block < 0) {
+		printk(KERN_WARNING "EFS: bmap(): block < 0\n");
+		return 0;
+	}
+
+	/* are we about to read past the end of a file ? */
+	if (!(block < inode->i_blocks)) {
+#ifdef DEBUG
+		/*
+		 * i have no idea why this happens as often as it does
+		 */
+		printk(KERN_WARNING "EFS: bmap(): block %d >= %ld (filesize %ld)\n",
+			block,
+			inode->i_blocks,
+			inode->i_size);
+#endif
+		return 0;
+	}
+
+	return efs_map_block(inode, block);
+}
+
 static struct file_operations efs_file_operations = {
 	NULL,			/* lseek */
 	generic_file_read,	/* read */
@@ -38,35 +91,12 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
+	efs_get_block,		/* get_block */
+	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
-	efs_bmap,		/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
- 
-int efs_bmap(struct inode *inode, efs_block_t block) {
-
-	if (block < 0) {
-		printk(KERN_WARNING "EFS: bmap(): block < 0\n");
-		return 0;
-	}
-
-	/* are we about to read past the end of a file ? */
-	if (!(block < inode->i_blocks)) {
-#ifdef DEBUG
-		/*
-		 * i have no idea why this happens as often as it does
-		 */
-		printk(KERN_WARNING "EFS: bmap(): block %d >= %ld (filesize %ld)\n",
-			block,
-			inode->i_blocks,
-			inode->i_size);
-#endif
-		return 0;
-	}
-
-	return efs_map_block(inode, block);
-}
-
diff -u --recursive --new-file v2.3.8/linux/fs/efs/symlink.c linux/fs/efs/symlink.c
--- v2.3.8/linux/fs/efs/symlink.c	Tue Jun  1 23:25:48 1999
+++ linux/fs/efs/symlink.c	Sun Jun 27 10:10:41 1999
@@ -26,12 +26,14 @@
 	NULL,			/* rename */
 	efs_readlink,		/* readlink */
 	efs_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static char *efs_linktarget(struct inode *in, int *len) {
diff -u --recursive --new-file v2.3.8/linux/fs/exec.c linux/fs/exec.c
--- v2.3.8/linux/fs/exec.c	Wed Jun  2 13:50:07 1999
+++ linux/fs/exec.c	Sat Jun 26 12:04:39 1999
@@ -72,10 +72,6 @@
 	init_aout32_binfmt();
 #endif
 
-#ifdef CONFIG_BINFMT_JAVA
-	init_java_binfmt();
-#endif
-
 #ifdef CONFIG_BINFMT_EM86
 	init_em86_binfmt();
 #endif
@@ -324,7 +320,7 @@
 /*
  * Read in the complete executable. This is used for "-N" files
  * that aren't on a block boundary, and for files on filesystems
- * without bmap support.
+ * without get_block support.
  */
 int read_exec(struct dentry *dentry, unsigned long offset,
 	char * addr, unsigned long count, int to_kmem)
@@ -804,7 +800,6 @@
 	bprm.dentry = dentry;
 	bprm.filename = filename;
 	bprm.sh_bang = 0;
-	bprm.java = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
 	if ((bprm.argc = count(argv)) < 0) {
diff -u --recursive --new-file v2.3.8/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v2.3.8/linux/fs/ext2/dir.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/ext2/dir.c	Sat Jun 26 12:04:39 1999
@@ -67,7 +67,7 @@
 	ext2_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v2.3.8/linux/fs/ext2/file.c	Sun Jun 20 01:09:22 1999
+++ linux/fs/ext2/file.c	Sat Jun 26 12:04:39 1999
@@ -37,7 +37,6 @@
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #define MAX(a,b) (((a)>(b))?(a):(b))
 
-static int ext2_writepage (struct file * file, struct page * page);
 static long long ext2_file_lseek(struct file *, long long, int);
 #if BITS_PER_LONG < 64
 static int ext2_open_file (struct inode *, struct file *);
@@ -106,23 +105,16 @@
 	}
 }
 
-static int ext2_writepage (struct file * file, struct page * page)
-{
-	return block_write_full_page(file, page, ext2_getblk_block);
-}
-
-static long ext2_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
-{
-	return block_write_partial_page(file, page, offset, bytes, buf, ext2_getblk_block);
-}
-
 /*
  * Write to a file (through the page cache).
  */
 static ssize_t
 ext2_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-	ssize_t retval = generic_file_write(file, buf, count, ppos, ext2_write_one_page);
+	ssize_t retval;
+
+	retval = generic_file_write(file, buf, count,
+						 ppos, block_write_partial_page);
 	if (retval > 0) {
 		struct inode *inode = file->f_dentry->d_inode;
 		remove_suid(inode);
@@ -195,9 +187,9 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	ext2_bmap,		/* bmap */
+	ext2_get_block,		/* get_block */
 	block_read_full_page,	/* readpage */
-	ext2_writepage,		/* writepage */
+	block_write_full_page,	/* writepage */
 	block_flushpage,	/* flushpage */
 	ext2_truncate,		/* truncate */
 	ext2_permission,	/* permission */
diff -u --recursive --new-file v2.3.8/linux/fs/ext2/fsync.c linux/fs/ext2/fsync.c
--- v2.3.8/linux/fs/ext2/fsync.c	Fri Jun 18 12:58:30 1999
+++ linux/fs/ext2/fsync.c	Tue Jun 29 09:22:08 1999
@@ -56,7 +56,7 @@
 		return 0;
 	}
 	ll_rw_block(WRITE, 1, &bh);
-	bh->b_count--;
+	atomic_dec(&bh->b_count);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.8/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.3.8/linux/fs/ext2/inode.c	Sun Jun 20 15:58:20 1999
+++ linux/fs/ext2/inode.c	Sat Jun 26 12:04:39 1999
@@ -129,23 +129,22 @@
 	return result;
 }
 
-
-int ext2_bmap (struct inode * inode, int block)
+static inline long ext2_block_map (struct inode * inode, long block)
 {
 	int i, ret;
-	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
-	int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+	int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
 
 	ret = 0;
 	lock_kernel();
 	if (block < 0) {
-		ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
+		ext2_warning (inode->i_sb, "ext2_block_map", "block < 0");
 		goto out;
 	}
-	if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
-		(1 << (addr_per_block_bits * 2)) +
-		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
-		ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
+	if (block >= EXT2_NDIR_BLOCKS + ptrs +
+		(1 << (ptrs_bits * 2)) +
+		((1 << (ptrs_bits * 2)) << ptrs_bits)) {
+		ext2_warning (inode->i_sb, "ext2_block_map", "block > big");
 		goto out;
 	}
 	if (block < EXT2_NDIR_BLOCKS) {
@@ -153,7 +152,7 @@
 		goto out;
 	}
 	block -= EXT2_NDIR_BLOCKS;
-	if (block < addr_per_block) {
+	if (block < ptrs) {
 		i = inode_bmap (inode, EXT2_IND_BLOCK);
 		if (!i)
 			goto out;
@@ -161,122 +160,64 @@
 					  inode->i_sb->s_blocksize), block);
 		goto out;
 	}
-	block -= addr_per_block;
-	if (block < (1 << (addr_per_block_bits * 2))) {
+	block -= ptrs;
+	if (block < (1 << (ptrs_bits * 2))) {
 		i = inode_bmap (inode, EXT2_DIND_BLOCK);
 		if (!i)
 			goto out;
 		i = block_bmap (bread (inode->i_dev, i,
 				       inode->i_sb->s_blocksize),
-				block >> addr_per_block_bits);
+				block >> ptrs_bits);
 		if (!i)
 			goto out;
 		ret = block_bmap (bread (inode->i_dev, i,
 					  inode->i_sb->s_blocksize),
-				block & (addr_per_block - 1));
+				block & (ptrs - 1));
+		goto out;
 	}
-	block -= (1 << (addr_per_block_bits * 2));
+	block -= (1 << (ptrs_bits * 2));
 	i = inode_bmap (inode, EXT2_TIND_BLOCK);
 	if (!i)
 		goto out;
 	i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
-			block >> (addr_per_block_bits * 2));
+			block >> (ptrs_bits * 2));
 	if (!i)
 		goto out;
 	i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
-			(block >> addr_per_block_bits) & (addr_per_block - 1));
+			(block >> ptrs_bits) & (ptrs - 1));
 	if (!i)
 		goto out;
 	ret = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
-			   block & (addr_per_block - 1));
+			   block & (ptrs - 1));
 out:
 	unlock_kernel();
 	return ret;
 }
 
-int ext2_bmap_create (struct inode * inode, int block)
-{
-	int i;
-	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
-	int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
-
-	if (block < 0) {
-		ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
-		return 0;
-	}
-	if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
-		(1 << (addr_per_block_bits * 2)) +
-		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
-		ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
-		return 0;
-	}
-	if (block < EXT2_NDIR_BLOCKS)
-		return inode_bmap (inode, block);
-	block -= EXT2_NDIR_BLOCKS;
-	if (block < addr_per_block) {
-		i = inode_bmap (inode, EXT2_IND_BLOCK);
-		if (!i)
-			return 0;
-		return block_bmap (bread (inode->i_dev, i,
-					  inode->i_sb->s_blocksize), block);
-	}
-	block -= addr_per_block;
-	if (block < (1 << (addr_per_block_bits * 2))) {
-		i = inode_bmap (inode, EXT2_DIND_BLOCK);
-		if (!i)
-			return 0;
-		i = block_bmap (bread (inode->i_dev, i,
-				       inode->i_sb->s_blocksize),
-				block >> addr_per_block_bits);
-		if (!i)
-			return 0;
-		return block_bmap (bread (inode->i_dev, i,
-					  inode->i_sb->s_blocksize),
-				   block & (addr_per_block - 1));
-	}
-	block -= (1 << (addr_per_block_bits * 2));
-	i = inode_bmap (inode, EXT2_TIND_BLOCK);
-	if (!i)
-		return 0;
-	i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
-			block >> (addr_per_block_bits * 2));
-	if (!i)
-		return 0;
-	i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
-			(block >> addr_per_block_bits) & (addr_per_block - 1));
-	if (!i)
-		return 0;
-	return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
-			   block & (addr_per_block - 1));
-}
-
 static struct buffer_head * inode_getblk (struct inode * inode, int nr,
-	int create, int new_block, int * err, int metadata,
-	int *phys_block, int *created)
+	int new_block, int * err, int metadata, long *phys, int *new)
 {
 	u32 * p;
 	int tmp, goal = 0;
 	struct buffer_head * result;
-	int blocks = inode->i_sb->s_blocksize / 512;
+	int blocksize = inode->i_sb->s_blocksize;
 
 	p = inode->u.ext2_i.i_data + nr;
 repeat:
 	tmp = le32_to_cpu(*p);
 	if (tmp) {
 		if (metadata) {
-			struct buffer_head * result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+			result = getblk (inode->i_dev, tmp, blocksize);
 			if (tmp == le32_to_cpu(*p))
 				return result;
 			brelse (result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
+			*phys = tmp;
 			return NULL;
 		}
 	}
 	*err = -EFBIG;
-	if (!create)
-		goto dont_create;
 
 	/* Check file limits.. */
 	{
@@ -285,7 +226,6 @@
 			limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
 			if (new_block >= limit) {
 				send_sig(SIGXFSZ, current, 0);
-dont_create:
 				*err = -EFBIG;
 				return NULL;
 			}
@@ -313,34 +253,41 @@
 	ext2_debug ("goal = %d.\n", goal);
 
 	tmp = ext2_alloc_block (inode, goal, err);
-	if (!tmp)
+	if (!tmp) {
+		*err = -ENOSPC;
 		return NULL;
+	}
 	if (metadata) {
-		result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+		result = getblk (inode->i_dev, tmp, blocksize);
 		if (*p) {
 			ext2_free_blocks (inode, tmp, 1);
 			brelse (result);
 			goto repeat;
 		}
-		memset(result->b_data, 0, inode->i_sb->s_blocksize);
+		memset(result->b_data, 0, blocksize);
 		mark_buffer_uptodate(result, 1);
 		mark_buffer_dirty(result, 1);
 	} else {
 		if (*p) {
+			/*
+			 * Nobody is allowed to change block allocation
+			 * state from under us:
+			 */
+			BUG();
 			ext2_free_blocks (inode, tmp, 1);
 			goto repeat;
 		}
-		*phys_block = tmp;
+		*phys = tmp;
 		result = NULL;
 		*err = 0;
-		*created = 1;
+		*new = 1;
 	}
 	*p = cpu_to_le32(tmp);
 
 	inode->u.ext2_i.i_next_alloc_block = new_block;
 	inode->u.ext2_i.i_next_alloc_goal = tmp;
 	inode->i_ctime = CURRENT_TIME;
-	inode->i_blocks += blocks;
+	inode->i_blocks += blocksize/512;
 	if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
 		ext2_sync_inode (inode);
 	else
@@ -357,24 +304,23 @@
  *   NULL return in the data case is mandatory.
  */
 static struct buffer_head * block_getblk (struct inode * inode,
-	  struct buffer_head * bh, int nr, int create, int blocksize, 
-	  int new_block, int * err, int metadata, int *phys_block, int *created)
+	  struct buffer_head * bh, int nr,
+	  int new_block, int * err, int metadata, long *phys, int *new)
 {
 	int tmp, goal = 0;
 	u32 * p;
 	struct buffer_head * result;
-	int blocks = inode->i_sb->s_blocksize / 512;
+	int blocksize = inode->i_sb->s_blocksize;
 	unsigned long limit;
-	
+
+	result = NULL;	
 	if (!bh)
-		return NULL;
+		goto out;
 	if (!buffer_uptodate(bh)) {
 		ll_rw_block (READ, 1, &bh);
 		wait_on_buffer (bh);
-		if (!buffer_uptodate(bh)) {
-			brelse (bh);
-			return NULL;
-		}
+		if (!buffer_uptodate(bh))
+			goto out;
 	}
 	p = (u32 *) bh->b_data + nr;
 repeat:
@@ -382,31 +328,24 @@
 	if (tmp) {
 		if (metadata) {
 			result = getblk (bh->b_dev, tmp, blocksize);
-			if (tmp == le32_to_cpu(*p)) {
-				brelse (bh);
-				return result;
-			}
+			if (tmp == le32_to_cpu(*p))
+				goto out;
 			brelse (result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
-			brelse (bh);
-			return NULL;
+			*phys = tmp;
+			/* result == NULL */
+			goto out;
 		}
 	}
 	*err = -EFBIG;
-	if (!create) {
-		brelse (bh);
-		return NULL;
-	}
 
 	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	if (limit < RLIM_INFINITY) {
 		limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
 		if (new_block >= limit) {
-			brelse (bh);
 			send_sig(SIGXFSZ, current, 0);
-			return NULL;
+			goto out;
 		}
 	}
 
@@ -423,10 +362,8 @@
 			goal = bh->b_blocknr;
 	}
 	tmp = ext2_alloc_block (inode, goal, err);
-	if (!tmp) {
-		brelse (bh);
-		return NULL;
-	}
+	if (!tmp)
+		goto out;
 	if (metadata) {
 		result = getblk (bh->b_dev, tmp, blocksize);
 		if (*p) {
@@ -438,12 +375,10 @@
 		mark_buffer_uptodate(result, 1);
 		mark_buffer_dirty(result, 1);
 	} else {
-		*phys_block = tmp;
-		result = NULL;
-		*err = 0;
-		*created = 1;
+		*phys = tmp;
+		*new = 1;
 	}
-	if (le32_to_cpu(*p)) {
+	if (*p) {
 		ext2_free_blocks (inode, tmp, 1);
 		brelse (result);
 		goto repeat;
@@ -455,117 +390,162 @@
 		wait_on_buffer (bh);
 	}
 	inode->i_ctime = CURRENT_TIME;
-	inode->i_blocks += blocks;
+	inode->i_blocks += blocksize/512;
 	mark_inode_dirty(inode);
 	inode->u.ext2_i.i_next_alloc_block = new_block;
 	inode->u.ext2_i.i_next_alloc_goal = tmp;
+	*err = 0;
+out:
 	brelse (bh);
 	return result;
 }
 
-int ext2_getblk_block (struct inode * inode, long block,
-				  int create, int * err, int * created)
+int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
 {
-	struct buffer_head * bh, *tmp;
-	unsigned long b;
-	unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
-	int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
-	int phys_block, ret;
+	int ret, err, new;
+	struct buffer_head *bh;
+	unsigned long ptr, phys;
+	/*
+	 * block pointers per block
+	 */
+	unsigned long ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+	const int direct_blocks = EXT2_NDIR_BLOCKS,
+		indirect_blocks = ptrs,
+		double_blocks = (1 << (ptrs_bits * 2)),
+		triple_blocks = (1 << (ptrs_bits * 3));
 
-	lock_kernel();
-	ret = 0;
-	*err = -EIO;
-	if (block < 0) {
-		ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
-		goto abort;
-	}
-	if (block > EXT2_NDIR_BLOCKS + addr_per_block +
-		(1 << (addr_per_block_bits * 2)) +
-		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
-		ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
-		goto abort;
+	if (!create) {
+		/*
+		 * Will clean this up further, ext2_block_map() should use the
+		 * bh instead of an integer block-number interface.
+		 */
+		phys = ext2_block_map(inode, iblock);
+		if (phys) {
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_blocknr = phys;
+			bh_result->b_state |= (1UL << BH_Mapped);
+		}
+		return 0;
 	}
+
+	err = -EIO;
+	new = 0;
+	ret = 0;
+	bh = NULL;
+
+	lock_kernel();
+
+	if (iblock < 0)
+		goto abort_negative;
+	if (iblock > direct_blocks + indirect_blocks +
+					 double_blocks + triple_blocks)
+		goto abort_too_big;
+
 	/*
 	 * If this is a sequential block allocation, set the next_alloc_block
 	 * to this block now so that all the indblock and data block
 	 * allocations use the same goal zone
 	 */
 
-	ext2_debug ("block %lu, next %lu, goal %lu.\n", block, 
+	ext2_debug ("block %lu, next %lu, goal %lu.\n", iblock, 
 		    inode->u.ext2_i.i_next_alloc_block,
 		    inode->u.ext2_i.i_next_alloc_goal);
 
-	if (block == inode->u.ext2_i.i_next_alloc_block + 1) {
+	if (iblock == inode->u.ext2_i.i_next_alloc_block + 1) {
 		inode->u.ext2_i.i_next_alloc_block++;
 		inode->u.ext2_i.i_next_alloc_goal++;
 	}
 
-	*err = 0; // -ENOSPC;
-	b = block;
-	*created = 0;
-	if (block < EXT2_NDIR_BLOCKS) {
-		/*
-		 * data page.
-		 */
-		tmp = inode_getblk (inode, block, create, b,
-					err, 0, &phys_block, created);
+	err = 0;
+	ptr = iblock;
+
+	/*
+	 * ok, these macros clean the logic up a bit and make
+	 * it much more readable:
+	 */
+#define GET_INODE_DATABLOCK(x) \
+		inode_getblk(inode, x, iblock, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+		inode_getblk(inode, x, iblock, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+		block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new);
+#define GET_INDIRECT_PTR(x) \
+		block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
+
+	if (ptr < direct_blocks) {
+		bh = GET_INODE_DATABLOCK(ptr);
 		goto out;
 	}
-	block -= EXT2_NDIR_BLOCKS;
-	if (block < addr_per_block) {
-		bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err, 1, NULL, NULL);
-		tmp = block_getblk (inode, bh, block, create,
-		     inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
-		goto out;
-	}
-	block -= addr_per_block;
-	if (block < (1 << (addr_per_block_bits * 2))) {
-		bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err, 1, NULL, NULL);
-		bh = block_getblk (inode, bh, block >> addr_per_block_bits,
-				   create, inode->i_sb->s_blocksize, b, err, 1, NULL, NULL);
-		tmp = block_getblk (inode, bh, block & (addr_per_block - 1),
-		     create, inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
-		goto out;
-	}
-	block -= (1 << (addr_per_block_bits * 2));
-	bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err, 1, NULL,NULL);
-	bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2),
-			   create, inode->i_sb->s_blocksize, b, err, 1, NULL,NULL);
-	bh = block_getblk (inode, bh, (block >> addr_per_block_bits) &
-		(addr_per_block - 1), create, inode->i_sb->s_blocksize,
-		b, err, 1, NULL,NULL);
-	tmp = block_getblk (inode, bh, block & (addr_per_block - 1), create,
-		inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
+	ptr -= direct_blocks;
+	if (ptr < indirect_blocks) {
+		bh = GET_INODE_PTR(EXT2_IND_BLOCK);
+		goto get_indirect;
+	}
+	ptr -= indirect_blocks;
+	if (ptr < double_blocks) {
+		bh = GET_INODE_PTR(EXT2_DIND_BLOCK);
+		goto get_double;
+	}
+	ptr -= double_blocks;
+	bh = GET_INODE_PTR(EXT2_TIND_BLOCK);
+	bh = GET_INDIRECT_PTR(ptr >> (ptrs_bits * 2));
+get_double:
+	bh = GET_INDIRECT_PTR((ptr >> ptrs_bits) & (ptrs - 1));
+get_indirect:
+	bh = GET_INDIRECT_DATABLOCK(ptr & (ptrs - 1));
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
 
 out:
-	if (!phys_block)
+	if (bh)
+		BUG();	// temporary debugging check
+	if (err)
 		goto abort;
-	if (*err)
-		goto abort;
-	ret = phys_block;
+	if (!phys)
+		BUG();	// must not happen either
+
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = phys;
+	bh_result->b_state |= (1UL << BH_Mapped); /* safe */
+	if (new)
+		bh_result->b_state |= (1UL << BH_New);
 abort:
 	unlock_kernel();
-	return ret;
+	return err;
+
+abort_negative:
+	ext2_warning (inode->i_sb, "ext2_get_block", "block < 0");
+	goto abort;
+
+abort_too_big:
+	ext2_warning (inode->i_sb, "ext2_get_block", "block > big");
+	goto abort;
 }
 
-struct buffer_head * ext2_getblk (struct inode * inode, long block,
-				  int create, int * err)
+struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err)
 {
-	struct buffer_head *tmp = NULL;
-	int phys_block;
-	int created;
-
-	phys_block = ext2_getblk_block (inode, block, create, err, &created);
+	struct buffer_head dummy;
+	int error;
 
-	if (phys_block) {
-		tmp = getblk (inode->i_dev, phys_block, inode->i_sb->s_blocksize);
-		if (created) {
-			memset(tmp->b_data, 0, inode->i_sb->s_blocksize);
-			mark_buffer_uptodate(tmp, 1);
-			mark_buffer_dirty(tmp, 1);
+	dummy.b_state = 0;
+	dummy.b_blocknr = -1000;
+	error = ext2_get_block(inode, block, &dummy, create);
+	*err = error;
+	if (!error && buffer_mapped(&dummy)) {
+		struct buffer_head *bh;
+		bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+		if (buffer_new(&dummy)) {
+			memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+			mark_buffer_uptodate(bh, 1);
+			mark_buffer_dirty(bh, 1);
 		}
+		return bh;
 	}
-	return tmp;
+	return NULL;
 }
 
 struct buffer_head * ext2_bread (struct inode * inode, int block, 
diff -u --recursive --new-file v2.3.8/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.3.8/linux/fs/ext2/namei.c	Sat May 15 23:43:05 1999
+++ linux/fs/ext2/namei.c	Thu Jun 24 11:26:43 1999
@@ -555,7 +555,7 @@
 	while (offset < inode->i_size ) {
 		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
 			brelse (bh);
-			bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err);
+			bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 0, &err);
 			if (!bh) {
 #if 0
 				ext2_error (sb, "empty_dir",
diff -u --recursive --new-file v2.3.8/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v2.3.8/linux/fs/ext2/symlink.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/ext2/symlink.c	Sat Jun 26 12:04:39 1999
@@ -43,7 +43,7 @@
 	NULL,			/* rename */
 	ext2_readlink,		/* readlink */
 	ext2_follow_link,	/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c
--- v2.3.8/linux/fs/ext2/truncate.c	Tue Jun 22 13:56:06 1999
+++ linux/fs/ext2/truncate.c	Tue Jun 29 09:22:08 1999
@@ -129,7 +129,7 @@
 		if (*(ind++))
 			goto in_use;
 
-	if (bh->b_count == 1) {
+	if (atomic_read(&bh->b_count) == 1) {
 		int tmp;
 		tmp = le32_to_cpu(*p);
 		*p = 0;
@@ -141,7 +141,7 @@
 		bforget(bh);
 		if (ind_bh)
 			mark_buffer_dirty(ind_bh, 1);
-		ext2_free_blocks (inode, tmp, 1);
+		ext2_free_blocks(inode, tmp, 1);
 		goto out;
 	}
 	retry = 1;
@@ -158,11 +158,10 @@
 }
 
 #define DATA_BUFFER_USED(bh) \
-	(bh->b_count || buffer_locked(bh))
+	(atomic_read(&bh->b_count) || buffer_locked(bh))
 
 static int trunc_direct (struct inode * inode)
 {
-	struct buffer_head * bh;
 	int i, retry = 0;
 	unsigned long block_to_free = 0, free_count = 0;
 	int blocks = inode->i_sb->s_blocksize / 512;
@@ -175,19 +174,9 @@
 		if (!tmp)
 			continue;
 
-		bh = find_buffer(inode->i_dev, tmp, inode->i_sb->s_blocksize);
-		if (bh) {
-			if (DATA_BUFFER_USED(bh)) {
-				retry = 1;
-				continue;
-			}
-			bh->b_count++;
-		}
-
 		*p = 0;
 		inode->i_blocks -= blocks;
 		mark_inode_dirty(inode);
-		bforget(bh);
 
 		/* accumulate blocks to free if they're contiguous */
 		if (free_count == 0)
@@ -206,8 +195,7 @@
 	return retry;
 }
 
-static int trunc_indirect (struct inode * inode, int offset, u32 * p,
-			struct buffer_head *dind_bh)
+static int trunc_indirect (struct inode * inode, int offset, u32 * p, struct buffer_head *dind_bh)
 {
 	struct buffer_head * ind_bh;
 	int i, tmp, retry = 0;
@@ -242,28 +230,15 @@
 		indirect_block = 0;
 	for (i = indirect_block ; i < addr_per_block ; i++) {
 		u32 * ind = i + (u32 *) ind_bh->b_data;
-		struct buffer_head * bh;
 
 		wait_on_buffer(ind_bh);
 		tmp = le32_to_cpu(*ind);
 		if (!tmp)
 			continue;
-		/*
-		 * Use find_buffer so we don't block here.
-		 */
-		bh = find_buffer(inode->i_dev, tmp, inode->i_sb->s_blocksize);
-		if (bh) {
-			if (DATA_BUFFER_USED(bh)) {
-				retry = 1;
-				continue;
-			}
-			bh->b_count++;
-		}
 
 		*ind = 0;
 		inode->i_blocks -= blocks;
 		mark_inode_dirty(inode);
-		bforget(bh);
 		mark_buffer_dirty(ind_bh, 1);
 
 		/* accumulate blocks to free if they're contiguous */
diff -u --recursive --new-file v2.3.8/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.3.8/linux/fs/fat/file.c	Sun Feb 28 09:47:37 1999
+++ linux/fs/fat/file.c	Sun Jun 27 10:10:41 1999
@@ -57,12 +57,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
+	fat_bmap,		/* get_block */
+	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
-	fat_bmap,		/* bmap */
+	NULL,			/* flushpage */
 	fat_truncate,		/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 /* #Specification: msdos / special devices / mmap	
@@ -107,12 +109,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
+	NULL,			/* get_block */
+	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	fat_truncate,		/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static struct file_operations fat_file_operations_readpage = {
@@ -142,12 +146,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	fat_readpage,		/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	fat_truncate,		/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 #define MSDOS_PREFETCH	32
diff -u --recursive --new-file v2.3.8/linux/fs/fifo.c linux/fs/fifo.c
--- v2.3.8/linux/fs/fifo.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/fifo.c	Sat Jun 26 12:04:39 1999
@@ -179,7 +179,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/file_table.c linux/fs/file_table.c
--- v2.3.8/linux/fs/file_table.c	Tue Jun  1 23:25:48 1999
+++ linux/fs/file_table.c	Mon Jun 28 11:43:43 1999
@@ -80,7 +80,7 @@
 		nr_free_files--;
 	new_one:
 		memset(f, 0, sizeof(*f));
-		f->f_count = 1;
+		atomic_set(&f->f_count, 1);
 		f->f_version = ++event;
 		f->f_uid = current->fsuid;
 		f->f_gid = current->fsgid;
@@ -120,7 +120,7 @@
 {
 	memset(filp, 0, sizeof(*filp));
 	filp->f_mode   = mode;
-	filp->f_count  = 1;
+	atomic_set(&filp->f_count, 1);
 	filp->f_dentry = dentry;
 	filp->f_uid    = current->fsuid;
 	filp->f_gid    = current->fsgid;
@@ -133,21 +133,17 @@
 
 void fput(struct file *file)
 {
-	int count = file->f_count-1;
-
-	if (!count) {
+	if (atomic_dec_and_test(&file->f_count)) {
 		locks_remove_flock(file);
 		__fput(file);
-		file->f_count = 0;
 		remove_filp(file);
 		insert_file_free(file);
-	} else
-		file->f_count = count;
+	}
 }
 
 void put_filp(struct file *file)
 {
-	if(--file->f_count == 0) {
+	if (atomic_dec_and_test(&file->f_count)) {
 		remove_filp(file);
 		insert_file_free(file);
 	}
diff -u --recursive --new-file v2.3.8/linux/fs/hfs/dir_cap.c linux/fs/hfs/dir_cap.c
--- v2.3.8/linux/fs/hfs/dir_cap.c	Thu May 13 10:53:59 1999
+++ linux/fs/hfs/dir_cap.c	Sun Jun 27 10:10:41 1999
@@ -87,12 +87,14 @@
 	hfs_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 struct inode_operations hfs_cap_fdir_inode_operations = {
@@ -108,12 +110,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 struct inode_operations hfs_cap_rdir_inode_operations = {
@@ -129,12 +133,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 /*================ File-local functions ================*/
diff -u --recursive --new-file v2.3.8/linux/fs/hfs/dir_dbl.c linux/fs/hfs/dir_dbl.c
--- v2.3.8/linux/fs/hfs/dir_dbl.c	Thu May 13 10:53:59 1999
+++ linux/fs/hfs/dir_dbl.c	Sun Jun 27 10:10:41 1999
@@ -86,12 +86,14 @@
 	dbl_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 
diff -u --recursive --new-file v2.3.8/linux/fs/hfs/dir_nat.c linux/fs/hfs/dir_nat.c
--- v2.3.8/linux/fs/hfs/dir_nat.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/hfs/dir_nat.c	Sun Jun 27 10:10:41 1999
@@ -93,9 +93,10 @@
 	hfs_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
@@ -115,9 +116,10 @@
 	nat_hdr_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/hfs/file.c linux/fs/hfs/file.c
--- v2.3.8/linux/fs/hfs/file.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/hfs/file.c	Sun Jun 27 10:10:41 1999
@@ -63,9 +63,10 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
+	hfs_bmap,		/* get_block */
+	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
-	hfs_bmap,		/* bmap */
+	NULL,			/* flushpage */
 	hfs_file_truncate,	/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/hfs/file_cap.c linux/fs/hfs/file_cap.c
--- v2.3.8/linux/fs/hfs/file_cap.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/hfs/file_cap.c	Sun Jun 27 10:10:41 1999
@@ -77,9 +77,10 @@
 	NULL,				/* rename */
 	NULL,				/* readlink */
 	NULL,				/* follow_link */
+	NULL,				/* get_block - none */
 	NULL,				/* readpage */
 	NULL,				/* writepage */
-	NULL,				/* bmap - none */
+	NULL,				/* flushpage */
 	cap_info_truncate,		/* truncate */
 	NULL,				/* permission */
 	NULL,				/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/hfs/file_hdr.c linux/fs/hfs/file_hdr.c
--- v2.3.8/linux/fs/hfs/file_hdr.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/hfs/file_hdr.c	Sun Jun 27 10:10:41 1999
@@ -78,10 +78,11 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block - XXX: not available since
+				   header part has no disk block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap - XXX: not available since
-				   header part has no disk block */
+	NULL,			/* flushpage */
 	hdr_truncate,		/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/hpfs/Makefile linux/fs/hpfs/Makefile
--- v2.3.8/linux/fs/hpfs/Makefile	Thu May 13 23:48:20 1999
+++ linux/fs/hpfs/Makefile	Fri Jun 25 09:42:19 1999
@@ -1,5 +1,5 @@
 O_TARGET := hpfs.o
-O_OBJS := alloc.o anode.o buffer.o dentry.o dir.o dnode.o ea.o file.o inode.o map.o mmap.o name.o namei.o super.o
+O_OBJS := alloc.o anode.o buffer.o dentry.o dir.o dnode.o ea.o file.o inode.o map.o name.o namei.o super.o
 M_OBJS := $(O_TARGET)
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.8/linux/fs/hpfs/anode.c linux/fs/hpfs/anode.c
--- v2.3.8/linux/fs/hpfs/anode.c	Thu May 13 23:48:20 1999
+++ linux/fs/hpfs/anode.c	Sun Jun 27 10:10:41 1999
@@ -301,13 +301,20 @@
 		anode = hpfs_map_anode(s, ano, &bh);
 		btree1 = &anode->btree;
 	} else btree1 = btree;
-	for (i = 0; i < btree1->n_used_nodes; i++)
-		if (btree1->u.internal[i].down == oano)
-			if ((pos = i + 1) < btree1->n_used_nodes) goto go_down;
-			else goto go_up;
-	hpfs_error(s, "reference to anode %08x not found in anode %08x (probably bad up pointer)",
-		oano, level ? ano : -1);
-	if (level) brelse(bh);
+	for (i = 0; i < btree1->n_used_nodes; i++) {
+		if (btree1->u.internal[i].down == oano) {
+			if ((pos = i + 1) < btree1->n_used_nodes)
+				goto go_down;
+			else
+				goto go_up;
+		}
+	}
+	hpfs_error(s,
+		   "reference to anode %08x not found in anode %08x "
+		   "(probably bad up pointer)",
+		   oano, level ? ano : -1);
+	if (level)
+		brelse(bh);
 }
 
 /* Just a wrapper around hpfs_bplus_lookup .. used for reading eas */
diff -u --recursive --new-file v2.3.8/linux/fs/hpfs/ea.c linux/fs/hpfs/ea.c
--- v2.3.8/linux/fs/hpfs/ea.c	Tue Jun  1 23:25:47 1999
+++ linux/fs/hpfs/ea.c	Sun Jun 27 10:10:41 1999
@@ -233,10 +233,10 @@
 				goto bail;
 			fnode->ea_anode = 0;
 			len++;
-		}
-		else if (!fnode->ea_anode)
-			if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) len++;
-			else {
+		} else if (!fnode->ea_anode) {
+			if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) {
+				len++;
+			} else {
 				/* Aargh... don't know how to create ea anodes :-( */
 				/*struct buffer_head *bh;
 				struct anode *anode;
@@ -280,10 +280,15 @@
 				fnode->ea_secno = new_sec;
 				len = (pos + 511) >> 9;
 			}
-		if (fnode->ea_anode)
-			if (hpfs_add_sector_to_btree(s, fnode->ea_secno, 0, len) != -1)
+		}
+		if (fnode->ea_anode) {
+			if (hpfs_add_sector_to_btree(s, fnode->ea_secno,
+						     0, len) != -1) {
 				len++;
-			else goto bail;
+			} else {
+				goto bail;
+			}
+		}
 	}
 	h[0] = 0;
 	h[1] = strlen(key);
diff -u --recursive --new-file v2.3.8/linux/fs/hpfs/file.c linux/fs/hpfs/file.c
--- v2.3.8/linux/fs/hpfs/file.c	Tue Jun  1 23:25:47 1999
+++ linux/fs/hpfs/file.c	Sun Jun 27 10:10:41 1999
@@ -53,143 +53,101 @@
 {
 	if (IS_IMMUTABLE(i)) return /*-EPERM*/;
 	i->i_hpfs_n_secs = 0;
-	hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
 	i->i_blocks = 1 + ((i->i_size + 511) >> 9);
+	hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9));
 	hpfs_write_inode(i);
 }
 
-ssize_t hpfs_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+int hpfs_getblk_block(struct inode *inode, long block, int create, int *err, int *created)
 {
-	struct inode *inode = filp->f_dentry->d_inode;
-	int i,j;
-	int a = generic_file_read(filp, buf, count, ppos);
-	if (inode->i_hpfs_conv != CONV_TEXT || a < 0) {
-		return a;
-	}	
-	for (i = 0, j = 0; i < a; i++) {
-		char c;
-		int error;
-		if ((error = get_user(c, buf + i))) return error;
-		if (c != '\r') {
-			if (i != j) put_user(c, buf + j);
-			j++;
+	int add;
+	int sec = 0;
+	down(&inode->i_sem);
+	if (err) *err = 0;
+	if (created) *created = 0;
+	if (!inode->i_blocks) {
+		hpfs_error(inode->i_sb, "hpfs_get_block: inode %08x has no blocks", inode->i_ino);
+		if (err) *err = -EFSERROR;
+		up(&inode->i_sem);
+		return 0;
+	}
+	if (block < ((add = inode->i_blocks - 1))) {
+		int bm;
+		if (!(bm = hpfs_bmap(inode, block))) {
+			hpfs_error(inode->i_sb, "hpfs_get_block: cound not bmap block %08x, inode %08x, size %08x", (int)block, inode->i_ino, (int)inode->i_size);
+			*err = -EFSERROR;
 		}
+		up(&inode->i_sem);
+		return bm;
 	}
-	return j;
+	if (!create) {
+		if (err) *err = -EFBIG;
+		up(&inode->i_sem);
+		return 0;
+	}
+	if (created) *created = 1;
+	while (add <= block) {
+		if ((sec = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, add)) == -1) {
+			if (err) *err = -ENOSPC;
+			hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1);
+			return 0;
+		} /* FIXME: clear block */
+		add++;
+	}
+	inode->i_blocks = add + 1;
+	up(&inode->i_sem);
+	return sec;
 }
 
-ssize_t hpfs_file_write(struct file *filp, const char *buf, size_t count,
-			loff_t *ppos)
+/* copied from ext2fs */
+static int hpfs_get_block(struct inode *inode, unsigned long block, struct buffer_head *bh, int update)
 {
-	struct inode *i = filp->f_dentry->d_inode;
-	int carry, error = 0;
-	const char *start = buf;
-	if (!i) return -EINVAL;
-	if (!S_ISREG(i->i_mode)) return -EINVAL;
-	if (IS_IMMUTABLE(i)) return -EPERM;
-	if (filp->f_flags & O_APPEND) *ppos = i->i_size;
-	if (count <= 0) return 0;
-	if ((unsigned)(*ppos+count) >= 0x80000000U || (unsigned)count >= 0x80000000U) return -EFBIG;
-	carry = 0;
-	while (count || carry) {
-		int ii, add = 0;
-		secno sec = 0; /* Go away, uninitialized variable warning */
-		int offset, size, written;
-		char ch;
-		struct buffer_head *bh;
-		char *data;
-		offset = *ppos & 0x1ff;
-		size = count > 0x200 - offset ? 0x200 - offset : count;
-		if ((*ppos >> 9) < ((i->i_size + 0x1ff) >> 9)) {
-			i->i_hpfs_n_secs = 0;
-			if (!(sec = hpfs_bmap(i, *ppos >> 9))) {
-				hpfs_error(i->i_sb, "bmap failed, file %08x, fsec %08x",
-					i->i_ino, *ppos >> 9);
-				error =- EFSERROR;
-				break;
-			}
-		} else for (ii = (i->i_size + 0x1ff) >> 9, add = 1; ii <= *ppos >> 9; ii++) {
-			if ((sec = hpfs_add_sector_to_btree(i->i_sb, i->i_ino, 1, ii)) == -1) {
-				hpfs_truncate(i);
-				return -ENOSPC;
-			}
-			if (*ppos != i->i_size)
-				if ((data = hpfs_get_sector(i->i_sb, sec, &bh))) {
-					memset(data, 0, 512);
-					mark_buffer_dirty(bh, 0);
-					brelse(bh);
-				}
-			i->i_size = 0x200 * ii + 1;
-			i->i_blocks++;
-			/*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
-			if (i->i_sb->s_hpfs_chk >= 2) {
-				secno bsec;
-				bsec = hpfs_bmap(i, ii);
-				if (sec != bsec) {
-					hpfs_error(i->i_sb, "sec == %08x, bmap returns %08x", sec, bsec);
-					error = -EFSERROR;
-					break;
-				}
-			}	
-			PRINTK(("file_write: added %08x\n", sec));
-		}
-		if (!sec || sec == 15) {
-			hpfs_error(i->i_sb, "bmap returned empty sector");
-			error = -EFSERROR;
-			break;
-		}
-		if (i->i_sb->s_hpfs_chk)
-			if (hpfs_chk_sectors(i->i_sb, sec, 1, "data")) {
-				error = -EFSERROR;
-				break;
-			}
-		if ((!offset && size == 0x200) || add)
-			data = hpfs_get_sector(i->i_sb, sec, &bh);
-		else data = hpfs_map_sector(i->i_sb, sec, &bh, 0);
-		if (!data) {
-			error = -EIO;
-			break;
-		}
-		if (i->i_hpfs_conv != CONV_TEXT) {
-			memcpy_fromfs(data + offset, buf, written = size);
-			buf += size;
-		} else {
-			int left;
-			char *to;
-			/* LF->CR/LF conversion, stolen from fat fs */
-			written = left = 0x200 - offset;
-			to = (char *) bh->b_data + (*ppos & 0x1ff);
-			if (carry) {
-				*to++ = '\n';
-				left--;
-				carry = 0;
-			}
-			for (size = 0; size < count && left; size++) {
-				if ((error = get_user(ch, buf++))) break;
-				if (ch == '\n') {
-					*to++ = '\r';
-					left--;
-				}
-				if (!left) carry = 1;
-				else {
-					*to++ = ch;
-					left--;
-				}
-			}
-			written -= left;
+	if (!bh->b_blocknr) {
+		int error, created;
+		unsigned long blocknr;
+
+		blocknr = hpfs_getblk_block(inode, block, 1, &error, &created);
+		if (!blocknr) {
+			if (!error)
+				error = -ENOSPC;
+			return error;
 		}
-		update_vm_cache(i, *ppos, bh->b_data + (*ppos & 0x1ff), written);
-		*ppos += written;
-		if (*ppos > i->i_size) {
-			i->i_size = *ppos;
-			/*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
+
+		bh->b_dev = inode->i_dev;
+		bh->b_blocknr = blocknr;
+
+		if (!update)
+			return 0;
+
+		if (created) {
+			memset(bh->b_data, 0, bh->b_size);
+			set_bit(BH_Uptodate, &bh->b_state);
+			return 0;
 		}
-		mark_buffer_dirty(bh, 0);
-		brelse(bh);
-		count -= size;
-	}
-	if (start == buf) return error;
-	i->i_mtime = CURRENT_TIME;
-	/*mark_inode_dirty(i);*/i->i_hpfs_dirty = 1;
-	return buf - start;
+	}
+
+	if (!update)
+		return 0;
+
+	lock_kernel();
+	ll_rw_block(READ, 1, &bh);
+	wait_on_buffer(bh);
+	unlock_kernel();
+
+	return buffer_uptodate(bh) ? 0 : -EIO;
 }
+
+ssize_t hpfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	ssize_t retval;
+
+	retval = generic_file_write(file, buf, count,
+				    ppos, block_write_partial_page);
+	if (retval > 0) {
+		struct inode *inode = file->f_dentry->d_inode;
+		inode->i_mtime = CURRENT_TIME;
+		inode->i_hpfs_dirty = 1;
+	}
+	return retval;
+}
+
diff -u --recursive --new-file v2.3.8/linux/fs/hpfs/hpfs_fn.h linux/fs/hpfs/hpfs_fn.h
--- v2.3.8/linux/fs/hpfs/hpfs_fn.h	Fri Jun  4 01:06:29 1999
+++ linux/fs/hpfs/hpfs_fn.h	Fri Jun 25 09:42:19 1999
@@ -21,6 +21,7 @@
 #include <asm/bitops.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
+#include <linux/smp_lock.h>
 
 #include <stdarg.h>
 
@@ -259,6 +260,7 @@
 void hpfs_truncate(struct inode *);
 ssize_t hpfs_file_read(struct file *, char *, size_t, loff_t *);
 ssize_t hpfs_file_write(struct file *, const char *, size_t, loff_t *);
+int hpfs_writepage (struct file *, struct page *);
 
 /* inode.c */
 
diff -u --recursive --new-file v2.3.8/linux/fs/hpfs/inode.c linux/fs/hpfs/inode.c
--- v2.3.8/linux/fs/hpfs/inode.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/hpfs/inode.c	Sun Jun 27 10:10:41 1999
@@ -11,7 +11,7 @@
 static const struct file_operations hpfs_file_ops =
 {
 	NULL,				/* lseek - default */
-	hpfs_file_read,			/* read */
+	generic_file_read,		/* read */
 	hpfs_file_write,		/* write */
 	NULL,				/* readdir - bad */
 	NULL,				/* poll - default */
@@ -41,11 +41,13 @@
 	NULL,				/* rename */
 	NULL,				/* readlink */
 	NULL,				/* follow_link */
-	generic_readpage,		/* readpage */
-	NULL,				/* writepage */
 	(int (*)(struct inode *, int))
-	&hpfs_bmap,			/* bmap */
-	&hpfs_truncate,			/* truncate */
+#warning Someone needs to code up hpfs_get_block properly... -DaveM
+	&hpfs_bmap,			/* get_block */
+	block_read_full_page,		/* readpage */
+	hpfs_writepage,			/* writepage */
+	block_flushpage,		/* flushpage */
+	hpfs_truncate,			/* truncate */
 	NULL,				/* permission */
 	NULL,				/* smap */
 	NULL,				/* revalidate */
@@ -84,13 +86,14 @@
 	hpfs_rename,			/* rename */
 	NULL,				/* readlink */
 	NULL,				/* follow_link */
+	NULL,				/* get_block */
 	NULL,				/* readpage */
 	NULL,				/* writepage */
-	NULL,				/* bmap */
+	NULL,				/* flushpage */
 	NULL,				/* truncate */
 	NULL,				/* permission */
 	NULL,				/* smap */
-	NULL,				/* revalidate */
+	NULL				/* revalidate */
 };
 
 const struct inode_operations hpfs_symlink_iops =
@@ -107,13 +110,14 @@
 	NULL,				/* rename */
 	hpfs_readlink,			/* readlink */
 	hpfs_follow_link,		/* follow_link */
+	NULL,				/* get_block */
 	NULL,				/* readpage */
 	NULL,				/* writepage */
-	NULL,				/* bmap */
+	NULL,				/* flushpage */
 	NULL,				/* truncate */
 	NULL,				/* permission */
 	NULL,				/* smap */
-	NULL,				/* revalidate */
+	NULL				/* revalidate */
 };
 
 
@@ -125,7 +129,6 @@
 	unsigned char *ea;
 	int ea_size;
 	i->i_op = 0;
-	/*i->i_hpfs_sem = MUTEX;*/
 	init_MUTEX(&i->i_hpfs_sem);
 	i->i_uid = sb->s_hpfs_uid;
 	i->i_gid = sb->s_hpfs_gid;
diff -u --recursive --new-file v2.3.8/linux/fs/hpfs/mmap.c linux/fs/hpfs/mmap.c
--- v2.3.8/linux/fs/hpfs/mmap.c	Thu May 13 23:48:20 1999
+++ linux/fs/hpfs/mmap.c	Wed Dec 31 16:00:00 1969
@@ -1,128 +0,0 @@
-/*
- *  linux/fs/hpfs/mmap.c
- *
- *  taken from fat filesystem
- *
- *  Written by Jacques Gelinas (jacques@solucorp.qc.ca)
- *  Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993)
- *
- *  Modified for HPFS by Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz)
- *
- *  mmap handling for hpfs filesystem
- *	(generic_file_mmap may be used only on filesystems that keep zeros
- *	 in last file sector beyond end)
- */
-
-/*
- * generic_file_mmap doesn't erase the space beyond file end in last sector. :-(
- * Hpfs doesn't keep zeros in last sector. This causes problems with kernel
- * mkdep.c and probably other programs. Additionally this could be a security
- * hole - some interesting data, like pieces of /etc/shadow could be found
- * beyond file end.
- *
- * So, I can't use generic mmap. mmap from fat filesystem looks good, so I used
- * it.
- *
- * BTW. fat uses generic mmap on normal disks. Doesn't it also have above bugs?
- * I don't think Msdos erases space in last sector.
- *
- * If you fix generic_file_mmap, you can remove this file and use it.
- */
-
-#include "hpfs_fn.h"
-
-/*
- * Fill in the supplied page for mmap
- */
-
-static unsigned long hpfs_file_mmap_nopage(
-	struct vm_area_struct * area,
-	unsigned long address,
-	int error_code)
-{
-	/*struct inode * inode = area->vm_inode;*/
-	struct inode * inode = area->vm_file->f_dentry->d_inode;
-	unsigned long page;
-	unsigned int clear;
-	loff_t pos;
-	long gap;	/* distance from eof to pos */
-
-	page = __get_free_page(GFP_KERNEL);
-	if (!page)
-		return page;
-	address &= PAGE_MASK;
-	pos = address - area->vm_start + area->vm_offset;
-
-	clear = 0;
-	gap = inode->i_size - pos;
-	if (gap <= 0){
-		/* mmaping beyond end of file */
-		clear = PAGE_SIZE;
-	}else{
-		int cur_read;
-		int need_read;
-		/*struct file *filp = area->vm_file;*/
-		struct file filp;
-		if (gap < PAGE_SIZE){
-			clear = PAGE_SIZE - gap;
-		}
-		filp.f_reada = 0;
-		filp.f_pos = pos;
-		filp.f_dentry=area->vm_file->f_dentry;
-		need_read = PAGE_SIZE - clear;
-		{
-			mm_segment_t cur_fs = get_fs();
-			set_fs (KERNEL_DS);
-			cur_read = generic_file_read (&filp,(char*)page
-				,need_read,&pos);
-			set_fs (cur_fs);
-		}
-		if (cur_read != need_read){
-			hpfs_error(inode->i_sb, "Error while reading an mmap file %08x", inode->i_ino);
-		}
-	}
-	if (clear > 0){
-		memset ((char*)page+PAGE_SIZE-clear,0,clear);
-	}
-	return page;
-}
-
-struct vm_operations_struct hpfs_file_mmap = {
-	NULL,			/* open */
-	NULL,			/* close */
-	NULL,			/* unmap */
-	NULL,			/* protect */
-	NULL,			/* sync */
-	NULL,			/* advise */
-	hpfs_file_mmap_nopage,	/* nopage */
-	NULL,			/* wppage */
-	NULL,			/* swapout */
-	NULL,			/* swapin */
-};
-
-/*
- * This is used for a general mmap of an msdos file
- * Returns 0 if ok, or a negative error code if not.
- */
-int hpfs_mmap(struct file * file, struct vm_area_struct * vma)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	/*printk("start mmap\n");*/
-	if (vma->vm_flags & VM_SHARED)	/* only PAGE_COW or read-only supported now */
-		return -EINVAL;
-	if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
-		return -EINVAL;
-	if (!inode->i_sb || !S_ISREG(inode->i_mode))
-		return -EACCES;
-	/*if (!IS_RDONLY(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		mark_inode_dirty(inode);
-	}*/
-
-	vma->vm_file = file;
-	/*inode->i_count++;*/
-	file->f_count++;
-	vma->vm_ops = &hpfs_file_mmap;
-	/*printk("end mmap\n");*/
-	return 0;
-}
diff -u --recursive --new-file v2.3.8/linux/fs/hpfs/super.c linux/fs/hpfs/super.c
--- v2.3.8/linux/fs/hpfs/super.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/hpfs/super.c	Sun Jun 27 10:10:41 1999
@@ -283,7 +283,7 @@
 	return 1;
 }
 
-static inline void hpfs_help()
+static inline void hpfs_help(void)
 {
 	printk("\n\
 HPFS filesystem options:\n\
diff -u --recursive --new-file v2.3.8/linux/fs/inode.c linux/fs/inode.c
--- v2.3.8/linux/fs/inode.c	Thu Jun 17 23:11:01 1999
+++ linux/fs/inode.c	Tue Jun 29 14:03:05 1999
@@ -231,7 +231,7 @@
 void clear_inode(struct inode *inode)
 {
 	if (inode->i_nrpages)
-		truncate_inode_pages(inode, 0);
+		BUG();
 	wait_on_inode(inode);
 	if (IS_QUOTAINIT(inode))
 		DQUOT_DROP(inode);
@@ -261,6 +261,8 @@
 		if (tmp == head)
 			break;
 		inode = list_entry(tmp, struct inode, i_list);
+		if (inode->i_nrpages)
+			truncate_inode_pages(inode, 0);
 		clear_inode(inode);
 		count++;
 	}
@@ -735,6 +737,8 @@
 				if (op && op->delete_inode) {
 					void (*delete)(struct inode *) = op->delete_inode;
 					spin_unlock(&inode_lock);
+					if (inode->i_nrpages)
+						truncate_inode_pages(inode, 0);
 					delete(inode);
 					spin_lock(&inode_lock);
 				}
@@ -778,8 +782,14 @@
 
 int bmap(struct inode * inode, int block)
 {
-	if (inode->i_op && inode->i_op->bmap)
-		return inode->i_op->bmap(inode, block);
+	struct buffer_head tmp;
+
+	if (inode->i_op && inode->i_op->get_block) {
+		tmp.b_state = 0;
+		tmp.b_blocknr = 0;
+		inode->i_op->get_block(inode, block, &tmp, 0);
+		return tmp.b_blocknr;
+	}
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.8/linux/fs/ioctl.c linux/fs/ioctl.c
--- v2.3.8/linux/fs/ioctl.c	Wed Mar 24 08:08:53 1999
+++ linux/fs/ioctl.c	Sat Jun 26 12:04:39 1999
@@ -18,14 +18,21 @@
 
 	switch (cmd) {
 		case FIBMAP:
+		{
+			struct buffer_head tmp;
+
 			if (inode->i_op == NULL)
 				return -EBADF;
-		    	if (inode->i_op->bmap == NULL)
+		    	if (inode->i_op->get_block == NULL)
 				return -EINVAL;
 			if ((error = get_user(block, (int *) arg)) != 0)
 				return error;
-			block = inode->i_op->bmap(inode,block);
-			return put_user(block, (int *) arg);
+
+			tmp.b_state = 0;
+			tmp.b_blocknr = 0;
+			inode->i_op->get_block(inode, block, &tmp, 0);
+			return put_user(tmp.b_blocknr, (int *) arg);
+		}
 		case FIGETBSZ:
 			if (inode->i_sb == NULL)
 				return -EBADF;
diff -u --recursive --new-file v2.3.8/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v2.3.8/linux/fs/isofs/dir.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/isofs/dir.c	Sun Jun 27 10:10:41 1999
@@ -57,11 +57,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static int isofs_name_translate(char * old, int len, char * new)
diff -u --recursive --new-file v2.3.8/linux/fs/isofs/file.c linux/fs/isofs/file.c
--- v2.3.8/linux/fs/isofs/file.c	Sat Jun 19 18:20:13 1999
+++ linux/fs/isofs/file.c	Sun Jun 27 10:10:41 1999
@@ -48,10 +48,12 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	isofs_bmap,		/* bmap */
+	isofs_get_block,	/* get_block */
 	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
 	NULL,	       		/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.3.8/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.3.8/linux/fs/isofs/inode.c	Sat Jun 19 18:20:13 1999
+++ linux/fs/isofs/inode.c	Sun Jun 27 10:10:41 1999
@@ -55,7 +55,7 @@
 static int isofs_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
 #endif
 
-void isofs_put_super(struct super_block *sb)
+static void isofs_put_super(struct super_block *sb)
 {
 #ifdef CONFIG_JOLIET
 	if (sb->u.isofs_sb.s_nls_iocharset) {
@@ -73,6 +73,9 @@
 	return;
 }
 
+static void isofs_read_inode(struct inode *);
+static int isofs_statfs (struct super_block *, struct statfs *, int);
+
 static struct super_operations isofs_sops = {
 	isofs_read_inode,
 	NULL,			/* write_inode */
@@ -487,8 +490,8 @@
  * Note: a check_disk_change() has been done immediately prior
  * to this call, so we don't need to check again.
  */
-struct super_block *isofs_read_super(struct super_block *s, void *data,
-				     int silent)
+static struct super_block *isofs_read_super(struct super_block *s, void *data,
+					    int silent)
 {
 	kdev_t				dev = s->s_dev;
 	struct buffer_head	      * bh = NULL, *pri_bh = NULL;
@@ -894,7 +897,7 @@
 	return NULL;
 }
 
-int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
+static int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	struct statfs tmp;
 
@@ -910,96 +913,115 @@
 	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
-static int do_isofs_bmap(struct inode * inode,int block)
+/* Life is simpler than for other filesystem since we never
+ * have to create a new block, only find an existing one.
+ */
+int isofs_get_block(struct inode *inode, long iblock,
+		    struct buffer_head *bh_result, int create)
 {
-	off_t b_off, offset, size;
-	struct inode *ino;
+	off_t b_off, offset, sect_size;
 	unsigned int firstext;
 	unsigned long nextino;
-	int i;
+	int i, err;
 
-	if (block<0) {
-		printk("_isofs_bmap: block<0");
-		return 0;
-	}
+	lock_kernel();
 
-	b_off = block << ISOFS_BUFFER_BITS(inode);
+	err = -EROFS;
+	if (create)
+		goto abort_create_attempted;
 
-	/*
-	 * If we are beyond the end of this file, don't give out any
+	err = -EIO;
+	if (iblock < 0)
+		goto abort_negative;
+
+	b_off = iblock << ISOFS_BUFFER_BITS(inode);
+
+	/* If we are beyond the end of this file, don't give out any
 	 * blocks.
 	 */
-	if( b_off > inode->i_size )
-	  {
-	    off_t	max_legal_read_offset;
-
-	    /*
-	     * If we are *way* beyond the end of the file, print a message.
-	     * Access beyond the end of the file up to the next page boundary
-	     * is normal, however because of the way the page cache works.
-	     * In this case, we just return 0 so that we can properly fill
-	     * the page with useless information without generating any
-	     * I/O errors.
-	     */
-	    max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1)
-	      & ~(PAGE_SIZE - 1);
-	    if( b_off >= max_legal_read_offset )
-	      {
-
-		printk("_isofs_bmap: block>= EOF(%d, %ld)\n", block,
-		       inode->i_size);
-	      }
-	    return 0;
-	  }
+	if (b_off > inode->i_size) {
+		off_t max_legal_read_offset;
+
+		/* If we are *way* beyond the end of the file, print a message.
+		 * Access beyond the end of the file up to the next page boundary
+		 * is normal, however because of the way the page cache works.
+		 * In this case, we just return 0 so that we can properly fill
+		 * the page with useless information without generating any
+		 * I/O errors.
+		 */
+		max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1)
+			& ~(PAGE_SIZE - 1);
+		if (b_off >= max_legal_read_offset)
+			goto abort_beyond_end;
+	}
+
+	offset    = 0;
+	firstext  = inode->u.isofs_i.i_first_extent;
+	sect_size = inode->u.isofs_i.i_section_size;
+	nextino   = inode->u.isofs_i.i_next_section_ino;
 
-	offset = 0;
-	firstext = inode->u.isofs_i.i_first_extent;
-	size = inode->u.isofs_i.i_section_size;
-	nextino = inode->u.isofs_i.i_next_section_ino;
-#ifdef DEBUG
-	printk("first inode: inode=%x nextino=%x firstext=%u size=%lu\n",
-		inode->i_ino, nextino, firstext, size);
-#endif
 	i = 0;
 	if (nextino) {
-		while(b_off >= offset + size) {
-			offset += size;
+		while (b_off >= (offset + sect_size)) {
+			struct inode *ninode;
 
-			if(nextino == 0) return 0;
-			ino = iget(inode->i_sb, nextino);
-			if(!ino) return 0;
-			firstext = ino->u.isofs_i.i_first_extent;
-			size = ino->u.isofs_i.i_section_size;
-#ifdef DEBUG
-			printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n",
-			       inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size);
-#endif
-			nextino = ino->u.isofs_i.i_next_section_ino;
-			iput(ino);
-		
-			if(++i > 100) {
-				printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
-				printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
-				       inode->i_ino, block, firstext, (unsigned)size, nextino);
-				return 0;
-			}
+			offset += sect_size;
+			if (nextino == 0)
+				goto abort;
+			ninode = iget(inode->i_sb, nextino);
+			if (!ninode)
+				goto abort;
+			firstext  = ninode->u.isofs_i.i_first_extent;
+			sect_size = ninode->u.isofs_i.i_section_size;
+			nextino   = ninode->u.isofs_i.i_next_section_ino;
+			iput(ninode);
+
+			if (++i > 100)
+				goto abort_too_many_sections;
 		}
 	}
-#ifdef DEBUG
-	printk("isofs_bmap: mapped inode:block %x:%d to block %lu\n",
-		inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode));
-#endif
-	return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
-}
 
-int isofs_bmap(struct inode * inode,int block)
-{
-	int retval;
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr =
+		(b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
+	bh_result->b_state |= (1UL << BH_Mapped);
+	err = 0;
 
-	lock_kernel();
-	retval = do_isofs_bmap(inode, block);
+abort:
 	unlock_kernel();
-	return retval;
+	return err;
+
+abort_create_attempted:
+	printk("_isofs_bmap: Kernel tries to allocate a block\n");
+	goto abort;
+
+abort_negative:
+	printk("_isofs_bmap: block < 0\n");
+	goto abort;
+
+abort_beyond_end:
+	printk("_isofs_bmap: block >= EOF (%ld, %ld)\n",
+	       iblock, inode->i_size);
+	goto abort;
+
+abort_too_many_sections:
+	printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
+	printk("isofs_bmap: ino=%lu block=%ld firstext=%u sect_size=%u nextino=%lu\n",
+	       inode->i_ino, iblock, firstext, (unsigned) sect_size, nextino);
+	goto abort;
+}
+
+int isofs_bmap(struct inode *inode, int block)
+{
+	struct buffer_head dummy;
+	int error;
+
+	dummy.b_state = 0;
+	dummy.b_blocknr = -1000;
+	error = isofs_get_block(inode, block, &dummy, 0);
+	if (!error)
+		return dummy.b_blocknr;
+	return 0;
 }
 
 static void test_and_set_uid(uid_t *p, uid_t value)
@@ -1101,7 +1123,7 @@
 	goto out;
 }
 
-void isofs_read_inode(struct inode * inode)
+static void isofs_read_inode(struct inode * inode)
 {
 	struct super_block *sb = inode->i_sb;
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
diff -u --recursive --new-file v2.3.8/linux/fs/isofs/symlink.c linux/fs/isofs/symlink.c
--- v2.3.8/linux/fs/isofs/symlink.c	Tue Jun  1 23:25:47 1999
+++ linux/fs/isofs/symlink.c	Sun Jun 27 10:10:41 1999
@@ -38,11 +38,14 @@
 	NULL,			/* rename */
 	isofs_readlink,		/* readlink */
 	isofs_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static int isofs_readlink(struct dentry * dentry, char * buffer, int buflen)
diff -u --recursive --new-file v2.3.8/linux/fs/lockd/host.c linux/fs/lockd/host.c
--- v2.3.8/linux/fs/lockd/host.c	Tue May 11 14:37:40 1999
+++ linux/fs/lockd/host.c	Wed Jun 30 10:22:00 1999
@@ -140,6 +140,7 @@
 	host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 	host->h_expires    = jiffies + NLM_HOST_EXPIRE;
 	host->h_count      = 1;
+	init_waitqueue_head(&host->h_gracewait);
 	host->h_state      = 0;			/* pseudo NSM state */
 	host->h_nsmstate   = 0;			/* real NSM state */
 	host->h_exportent  = clnt;
diff -u --recursive --new-file v2.3.8/linux/fs/locks.c linux/fs/locks.c
--- v2.3.8/linux/fs/locks.c	Tue Jun 22 10:45:40 1999
+++ linux/fs/locks.c	Mon Jun 28 13:32:28 1999
@@ -563,11 +563,14 @@
 	/* Candidates for mandatory locking have the setgid bit set
 	 * but no group execute bit -  an otherwise meaningless combination.
 	 */
-	if (IS_MANDLOCK(inode) &&
-	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
-		return (locks_mandatory_area(read_write, inode, filp, offset,
-					     count));
-	return (0);
+	if (IS_MANDLOCK(inode) && (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
+		int retval;
+		lock_kernel();
+		retval = locks_mandatory_area(read_write, inode, filp, offset, count);
+		unlock_kernel();
+		return retval;
+	}
+	return 0;
 }
 
 int locks_mandatory_locked(struct inode *inode)
diff -u --recursive --new-file v2.3.8/linux/fs/minix/dir.c linux/fs/minix/dir.c
--- v2.3.8/linux/fs/minix/dir.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/minix/dir.c	Sun Jun 27 10:10:41 1999
@@ -52,11 +52,14 @@
 	minix_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static int minix_readdir(struct file * filp,
diff -u --recursive --new-file v2.3.8/linux/fs/minix/file.c linux/fs/minix/file.c
--- v2.3.8/linux/fs/minix/file.c	Sat Jun 19 12:15:14 1999
+++ linux/fs/minix/file.c	Sun Jun 27 10:10:41 1999
@@ -27,50 +27,14 @@
 #include <linux/fs.h>
 #include <linux/minix_fs.h>
 
-static int minix_writepage(struct file *file, struct page *page)
-{
-	struct dentry *dentry = file->f_dentry;
-	struct inode *inode = dentry->d_inode;
-	unsigned long block;
-	int *p, nr[PAGE_SIZE/BLOCK_SIZE];
-	int i, err, created;
-	struct buffer_head *bh;
-
-	i = PAGE_SIZE / BLOCK_SIZE;
-	block = page->offset / BLOCK_SIZE;
-	p = nr;
-	bh = page->buffers;
-	do {
-		if (bh && bh->b_blocknr)
-			*p = bh->b_blocknr;
-		else
-			*p = minix_getblk_block(inode, block, 1, &err, &created);
-		if (!*p)
-			return -EIO;
-		i--;
-		block++;
-		p++;
-		if (bh)
-			bh = bh->b_this_page;
-	} while(i > 0);
-
-	/* IO start */
-	brw_page(WRITE, page, inode->i_dev, nr, BLOCK_SIZE, 1);
-	return 0;
-}
-
-static long minix_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char *buf)
-{
-	return block_write_one_page(file, page, offset, bytes, buf, minix_getblk_block);
-}
-
 /*
  * Write to a file (through the page cache).
  */
 static ssize_t
 minix_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-	return generic_file_write(file, buf, count, ppos, minix_write_one_page);
+	return generic_file_write(file, buf, count,
+				  ppos, block_write_partial_page);
 }
 
 /*
@@ -88,7 +52,10 @@
 	NULL,			/* no special open is needed */
 	NULL,			/* flush */
 	NULL,			/* release */
-	minix_sync_file		/* fsync */
+	minix_sync_file,	/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL			/* revalidate */
 };
 
 struct inode_operations minix_file_inode_operations = {
@@ -104,12 +71,12 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
-	minix_writepage,	/* writepage */
-	minix_bmap,		/* bmap */
+	minix_get_block,	/* get_block */
+	block_read_full_page,	/* readpage */
+	block_write_full_page,	/* writepage */
+	block_flushpage,	/* flushpage */
 	minix_truncate,		/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
 	NULL,			/* revalidate */
-	block_flushpage,	/* flushpage */
 };
diff -u --recursive --new-file v2.3.8/linux/fs/minix/fsync.c linux/fs/minix/fsync.c
--- v2.3.8/linux/fs/minix/fsync.c	Thu Nov 12 11:44:09 1998
+++ linux/fs/minix/fsync.c	Tue Jun 29 09:22:08 1999
@@ -53,7 +53,7 @@
 		return 0;
 	}
 	ll_rw_block(WRITE, 1, &bh);
-	bh->b_count--;
+	atomic_dec(&bh->b_count);
 	return 0;
 }
 
@@ -190,7 +190,7 @@
 		return 0;
 	}
 	ll_rw_block(WRITE, 1, &bh);
-	bh->b_count--;
+	atomic_dec(&bh->b_count);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.8/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.3.8/linux/fs/minix/inode.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/minix/inode.c	Sun Jun 27 10:10:41 1999
@@ -19,6 +19,7 @@
 #include <linux/stat.h>
 #include <linux/locks.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -361,112 +362,127 @@
 	return tmp;
 }
 
-static int V1_minix_bmap(struct inode * inode,int block)
+static int V1_minix_block_map(struct inode * inode, long block)
 {
-	int i;
+	int i, ret;
 
-	if (block<0) {
+	ret = 0;
+	lock_kernel();
+	if (block < 0) {
 		printk("minix_bmap: block<0");
-		return 0;
+		goto out;
 	}
 	if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
 		printk("minix_bmap: block>big");
-		return 0;
+		goto out;
+	}
+	if (block < 7) {
+		ret = V1_inode_bmap(inode,block);
+		goto out;
 	}
-	if (block < 7)
-		return V1_inode_bmap(inode,block);
 	block -= 7;
 	if (block < 512) {
 		i = V1_inode_bmap(inode,7);
 		if (!i)
-			return 0;
-		return V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block);
+			goto out;
+		ret = V1_block_bmap(bread(inode->i_dev, i,
+					  BLOCK_SIZE), block);
+		goto out;
 	}
 	block -= 512;
 	i = V1_inode_bmap(inode,8);
 	if (!i)
-		return 0;
+		goto out;
 	i = V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>9);
 	if (!i)
-		return 0;
-	return V1_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 511);
+		goto out;
+	ret = V1_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+			    block & 511);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
  * The minix V2 fs bmap functions.
  */
-#define V2_inode_bmap(inode,nr) (((unsigned long  *)(inode)->u.minix_i.u.i2_data)[(nr)])
+#define V2_inode_bmap(inode,nr) (((unsigned int *)(inode)->u.minix_i.u.i2_data)[(nr)])
 static int V2_block_bmap(struct buffer_head * bh, int nr)
 {
 	int tmp;
 
 	if (!bh)
 		return 0;
-	tmp = ((unsigned long *) bh->b_data)[nr];
+	tmp = ((unsigned int *) bh->b_data)[nr];
 	brelse(bh);
 	return tmp;
 }
 
-static int V2_minix_bmap(struct inode * inode, int block)
+static int V2_minix_block_map(struct inode * inode, int block)
 {
-	int i;
+	int i, ret;
 
-	if (block<0) {
+	ret = 0;
+	lock_kernel();
+	if (block < 0) {
 		printk("minix_bmap: block<0");
-		return 0;
+		goto out;
 	}
 	if (block >= (inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)) {
 		printk("minix_bmap: block>big");
-		return 0;
+		goto out;
+	}
+	if (block < 7) {
+		ret = V2_inode_bmap(inode,block);
+		goto out;
 	}
-	if (block < 7)
-		return V2_inode_bmap(inode,block);
 	block -= 7;
 	if (block < 256) {
-		i = V2_inode_bmap(inode,7);
+		i = V2_inode_bmap(inode, 7);
 		if (!i)
-			return 0;
-		return V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block);
+			goto out;
+		ret = V2_block_bmap(bread(inode->i_dev, i,
+					  BLOCK_SIZE), block);
+		goto out;
 	}
 	block -= 256;
-	if (block < 256*256) {
-		i = V2_inode_bmap(inode,8);
+	if (block < (256 * 256)) {
+		i = V2_inode_bmap(inode, 8);
 		if (!i)
-			return 0;
-		i = V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block >> 8);
+			goto out;
+		i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+				  block >> 8);
 		if (!i)
-			return 0;
-		return V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 255);
+			goto out;
+		ret = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+				    block & 255);
+		goto out;
 	}
-	block -= 256*256;
-	i = V2_inode_bmap(inode,9);
+	block -= (256 * 256);
+	i = V2_inode_bmap(inode, 9);
 	if (!i)
-		return 0;
-	i = V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block >> 16);
+		goto out;
+	i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+			  block >> 16);
 	if (!i)
-		return 0;
-	i = V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),(block >> 8) & 255);
+		goto out;
+	i = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+			  (block >> 8) & 255);
 	if (!i)
-		return 0;
-	return V2_block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 255);
-}
-
-/*
- * The global minix fs bmap function.
- */
-int minix_bmap(struct inode * inode, int block)
-{
-	if (INODE_VERSION(inode) == MINIX_V1)
-		return V1_minix_bmap(inode, block);
-	else
-		return V2_minix_bmap(inode, block);
+		goto out;
+	ret = V2_block_bmap(bread(inode->i_dev, i, BLOCK_SIZE),
+			    block & 255);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /*
  * The minix V1 fs getblk functions.
  */
-static struct buffer_head * V1_inode_getblk(struct inode * inode, int nr, int create,
-					    int metadata, int *phys_block, int *created)
+static struct buffer_head * V1_inode_getblk(struct inode * inode, int nr,
+					    int new_block, int *err,
+					    int metadata, int *phys, int *new)
 {
 	int tmp;
 	unsigned short *p;
@@ -483,15 +499,30 @@
 			brelse(result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
+			*phys = tmp;
 			return NULL;
 		}
 	}
-	if (!create)
-		return NULL;
+	*err = -EFBIG;
+
+	/* Check file limits.. */
+	{
+		unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+		if (limit < RLIM_INFINITY) {
+			limit >>= BLOCK_SIZE_BITS;
+			if (new_block >= limit) {
+				send_sig(SIGXFSZ, current, 0);
+				*err = -EFBIG;
+				return NULL;
+			}
+		}
+	}
+
 	tmp = minix_new_block(inode->i_sb);
-	if (!tmp)
+	if (!tmp) {
+		*err = -ENOSPC;
 		return NULL;
+	}
 	if (metadata) {
 		result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
 		if (*p) {
@@ -504,12 +535,18 @@
 		mark_buffer_dirty(result, 1);
 	} else {
 		if (*p) {
+			/*
+			 * Nobody is allowed to change block allocation
+			 * state from under us:
+			 */
+			BUG();
 			minix_free_block(inode->i_sb, tmp);
 			goto repeat;
 		}
-		*phys_block = tmp;
+		*phys = tmp;
 		result = NULL;
-		*created = 1;
+		*err = 0;
+		*new = 1;
 	}
 	*p = tmp;
 
@@ -519,22 +556,22 @@
 }
 
 static struct buffer_head * V1_block_getblk(struct inode * inode,
-	struct buffer_head * bh, int nr, int create,
-	int metadata, int *phys_block, int *created)
+	struct buffer_head * bh, int nr, int new_block, int *err,
+	int metadata, int *phys, int *new)
 {
 	int tmp;
 	unsigned short *p;
 	struct buffer_head * result;
+	unsigned long limit;
 
+	result = NULL;
 	if (!bh)
-		return NULL;
+		goto out;
 	if (!buffer_uptodate(bh)) {
 		ll_rw_block(READ, 1, &bh);
 		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh)) {
-			brelse(bh);
-			return NULL;
-		}
+		if (!buffer_uptodate(bh))
+			goto out;
 	}
 	p = nr + (unsigned short *) bh->b_data;
 repeat:
@@ -542,27 +579,29 @@
 	if (tmp) {
 		if (metadata) {
 			result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
-			if (tmp == *p) {
-				brelse(bh);
-				return result;
-			}
+			if (tmp == *p)
+				goto out;
 			brelse(result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
-			brelse(bh);
-			return NULL;
+			*phys = tmp;
+			goto out;
 		}
 	}
-	if (!create) {
-		brelse(bh);
-		return NULL;
+	*err = -EFBIG;
+
+	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	if (limit < RLIM_INFINITY) {
+		limit >>= BLOCK_SIZE_BITS;
+		if (new_block >= limit) {
+			send_sig(SIGXFSZ, current, 0);
+			goto out;
+		}
 	}
+
 	tmp = minix_new_block(inode->i_sb);
-	if (!tmp) {
-		brelse(bh);
-		return NULL;
-	}
+	if (!tmp)
+		goto out;
 	if (metadata) {
 		result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
 		if (*p) {
@@ -574,69 +613,118 @@
 		mark_buffer_uptodate(result, 1);
 		mark_buffer_dirty(result, 1);
 	} else {
-		if (*p) {
-			minix_free_block(inode->i_sb, tmp);
-			goto repeat;
-		}
-		*phys_block = tmp;
-		result = NULL;
-		*created = 1;
+		*phys = tmp;
+		*new = 1;
+	}
+	if (*p) {
+		minix_free_block(inode->i_sb, tmp);
+		brelse(result);
+		goto repeat;
 	}
 
 	*p = tmp;
 	mark_buffer_dirty(bh, 1);
+	*err = 0;
+out:
 	brelse(bh);
 	return result;
 }
 
-int V1_getblk_block(struct inode * inode, long block, int create, int *err, int *created)
+static int V1_get_block(struct inode * inode, long block,
+			struct buffer_head *bh_result, int create)
 {
-	struct buffer_head *bh, *tmp;
-	int phys_block;
+	int ret, err, new, phys, ptr;
+	struct buffer_head *bh;
 
-	*err = -EIO;
-	if (block < 0) {
-		printk("minix_getblk: block<0");
-		return 0;
-	}
-	if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE) {
-		printk("minix_getblk: block>big");
+	if (!create) {
+		phys = V1_minix_block_map(inode, block);
+		if (phys) {
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_blocknr = phys;
+			bh_result->b_state |= (1UL << BH_Mapped);
+		}
 		return 0;
 	}
-	*created = 0;
-	if (block < 7) {
-		tmp = V1_inode_getblk(inode, block, create,
-				      0, &phys_block, created);
-		goto out;
-	}
-	block -= 7;
-	if (block < 512) {
-		bh = V1_inode_getblk(inode, 7, create, 1, NULL, NULL);
-		tmp = V1_block_getblk(inode, bh, block, create,
-				      0, &phys_block, created);
+
+	err = -EIO;
+	new = 0;
+	ret = 0;
+	bh = NULL;
+
+	lock_kernel();
+	if (block < 0)
+		goto abort_negative;
+	if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)
+		goto abort_too_big;
+
+	err = 0;
+	ptr = block;
+	/*
+	 * ok, these macros clean the logic up a bit and make
+	 * it much more readable:
+	 */
+#define GET_INODE_DATABLOCK(x) \
+		V1_inode_getblk(inode, x, block, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+		V1_inode_getblk(inode, x, block, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+		V1_block_getblk(inode, bh, x, block, &err, 0, &phys, &new)
+#define GET_INDIRECT_PTR(x) \
+		V1_block_getblk(inode, bh, x, block, &err, 1, NULL, NULL)
+
+	if (ptr < 7) {
+		bh = GET_INODE_DATABLOCK(ptr);
 		goto out;
 	}
-	block -= 512;
-	bh = V1_inode_getblk(inode, 8, create, 1, NULL, NULL);
-	bh = V1_block_getblk(inode, bh, (block>>9) & 511, create, 1, NULL, NULL);
-	tmp = V1_block_getblk(inode, bh, block & 511, create, 0, &phys_block, created);
+	ptr -= 7;
+	if (ptr < 512) {
+		bh = GET_INODE_PTR(7);
+		goto get_indirect;
+	}
+	ptr -= 512;
+	bh = GET_INODE_PTR(8);
+	bh = GET_INDIRECT_PTR((ptr >> 9) & 511);
+get_indirect:
+	bh = GET_INDIRECT_DATABLOCK(ptr & 511);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
 
 out:
-	*err = 0;
-	return phys_block;
+	if (err)
+		goto abort;
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = phys;
+	bh_result->b_state |= (1UL << BH_Mapped);
+	if (new)
+		bh_result->b_state |= (1UL << BH_New);
+abort:
+	unlock_kernel();
+	return err;
+
+abort_negative:
+	printk("minix_getblk: block<0");
+	goto abort;
+
+abort_too_big:
+	printk("minix_getblk: block>big");
+	goto abort;
 }
 
 /*
  * The minix V2 fs getblk functions.
  */
-static struct buffer_head * V2_inode_getblk(struct inode * inode, int nr, int create,
-					    int metadata, int *phys_block, int *created)
+static struct buffer_head * V2_inode_getblk(struct inode * inode, int nr,
+					    int new_block, int *err,
+					    int metadata, int *phys, int *new)
 {
 	int tmp;
-	unsigned long *p;
+	unsigned int *p;
 	struct buffer_head * result;
 
-	p = (unsigned long *) inode->u.minix_i.u.i2_data + nr;
+	p = (unsigned int *) inode->u.minix_i.u.i2_data + nr;
 repeat:
 	tmp = *p;
 	if (tmp) {
@@ -647,15 +735,30 @@
 			brelse(result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
+			*phys = tmp;
 			return NULL;
 		}
 	}
-	if (!create)
-		return NULL;
+	*err = -EFBIG;
+
+	/* Check file limits.. */
+	{
+		unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+		if (limit < RLIM_INFINITY) {
+			limit >>= BLOCK_SIZE_BITS;
+			if (new_block >= limit) {
+				send_sig(SIGXFSZ, current, 0);
+				*err = -EFBIG;
+				return NULL;
+			}
+		}
+	}
+
 	tmp = minix_new_block(inode->i_sb);
-	if (!tmp)
+	if (!tmp) {
+		*err = -ENOSPC;
 		return NULL;
+	}
 	if (metadata) {
 		result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
 		if (*p) {
@@ -668,12 +771,18 @@
 		mark_buffer_dirty(result, 1);
 	} else {
 		if (*p) {
+			/*
+			 * Nobody is allowed to change block allocation
+			 * state from under us:
+			 */
+			BUG();
 			minix_free_block(inode->i_sb, tmp);
 			goto repeat;
 		}
-		*phys_block = tmp;
+		*phys = tmp;
 		result = NULL;
-		*created = 1;
+		*err = 0;
+		*new = 1;
 	}
 	*p = tmp;
 
@@ -683,50 +792,52 @@
 }
 
 static struct buffer_head * V2_block_getblk(struct inode * inode,
-	struct buffer_head * bh, int nr, int create,
-	int metadata, int *phys_block, int *created)
+	struct buffer_head * bh, int nr, int new_block, int *err,
+	int metadata, int *phys, int *new)
 {
 	int tmp;
-	unsigned long *p;
+	unsigned int *p;
 	struct buffer_head * result;
+	unsigned long limit;
 
+	result = NULL;
 	if (!bh)
-		return NULL;
+		goto out;
 	if (!buffer_uptodate(bh)) {
 		ll_rw_block(READ, 1, &bh);
 		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh)) {
-			brelse(bh);
-			return NULL;
-		}
+		if (!buffer_uptodate(bh))
+			goto out;
 	}
-	p = nr + (unsigned long *) bh->b_data;
+	p = nr + (unsigned int *) bh->b_data;
 repeat:
 	tmp = *p;
 	if (tmp) {
 		if (metadata) {
 			result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
-			if (tmp == *p) {
-				brelse(bh);
-				return result;
-			}
+			if (tmp == *p)
+				goto out;
 			brelse(result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
-			brelse(bh);
-			return NULL;
+			*phys = tmp;
+			goto out;
 		}
 	}
-	if (!create) {
-		brelse(bh);
-		return NULL;
+	*err = -EFBIG;
+
+	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	if (limit < RLIM_INFINITY) {
+		limit >>= BLOCK_SIZE_BITS;
+		if (new_block >= limit) {
+			send_sig(SIGXFSZ, current, 0);
+			goto out;
+		}
 	}
+
 	tmp = minix_new_block(inode->i_sb);
-	if (!tmp) {
-		brelse(bh);
-		return NULL;
-	}
+	if (!tmp)
+		goto out;
 	if (metadata) {
 		result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
 		if (*p) {
@@ -738,103 +849,151 @@
 		mark_buffer_uptodate(result, 1);
 		mark_buffer_dirty(result, 1);
 	} else {
-		if (*p) {
-			minix_free_block(inode->i_sb, tmp);
-			goto repeat;
-		}
-		*phys_block = tmp;
-		result = NULL;
-		*created = 1;
+		*phys = tmp;
+		*new = 1;
+	}
+	if (*p) {
+		minix_free_block(inode->i_sb, tmp);
+		brelse(result);
+		goto repeat;
 	}
 
 	*p = tmp;
 	mark_buffer_dirty(bh, 1);
+	*err = 0;
+out:
 	brelse(bh);
 	return result;
 }
 
-int V2_getblk_block(struct inode * inode, int block, int create, int *err, int *created)
+static int V2_get_block(struct inode * inode, long block,
+			struct buffer_head *bh_result, int create)
 {
-	struct buffer_head * bh, *tmp;
-	int phys_block;
+	int ret, err, new, phys, ptr;
+	struct buffer_head * bh;
 
-	*err = -EIO;
-	if (block < 0) {
-		printk("minix_getblk: block<0");
-		return 0;
-	}
-	if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE) {
-		printk("minix_getblk: block>big");
+	if (!create) {
+		phys = V2_minix_block_map(inode, block);
+		if (phys) {
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_blocknr = phys;
+			bh_result->b_state |= (1UL << BH_Mapped);
+		}
 		return 0;
 	}
-	*created = 0;
-	if (block < 7) {
-		tmp = V2_inode_getblk(inode, block, create,
-				      0, &phys_block, created);
-		goto out;
-	}
-	block -= 7;
-	if (block < 256) {
-		bh = V2_inode_getblk(inode, 7, create, 1, NULL, NULL);
-		tmp = V2_block_getblk(inode, bh, block, create,
-				      0, &phys_block, created);
-		goto out;
-	}
-	block -= 256;
-	if (block < 256*256) {
-		bh = V2_inode_getblk(inode, 8, create, 1, NULL, NULL);
-		bh = V2_block_getblk(inode, bh, (block>>8) & 255, create,
-				     1, NULL, NULL);
-		tmp = V2_block_getblk(inode, bh, block & 255, create,
-				      0, &phys_block, created);
+
+	err = -EIO;
+	new = 0;
+	ret = 0;
+	bh = NULL;
+
+	lock_kernel();
+	if (block < 0)
+		goto abort_negative;
+	if (block >= inode->i_sb->u.minix_sb.s_max_size/BLOCK_SIZE)
+		goto abort_too_big;
+
+	err = 0;
+	ptr = block;
+	/*
+	 * ok, these macros clean the logic up a bit and make
+	 * it much more readable:
+	 */
+#define GET_INODE_DATABLOCK(x) \
+		V2_inode_getblk(inode, x, block, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+		V2_inode_getblk(inode, x, block, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+		V2_block_getblk(inode, bh, x, block, &err, 0, &phys, &new)
+#define GET_INDIRECT_PTR(x) \
+		V2_block_getblk(inode, bh, x, block, &err, 1, NULL, NULL)
+
+	if (ptr < 7) {
+		bh = GET_INODE_DATABLOCK(ptr);
 		goto out;
 	}
-	block -= 256*256;
-	bh = V2_inode_getblk(inode, 9, create, 1, NULL, NULL);
-	bh = V2_block_getblk(inode, bh, (block >> 16) & 255, create, 1, NULL, NULL);
-	bh = V2_block_getblk(inode, bh, (block >> 8) & 255, create, 1, NULL, NULL);
-	tmp = V2_block_getblk(inode, bh, block & 255, create, 0, &phys_block, created);
+	ptr -= 7;
+	if (ptr < 256) {
+		bh = GET_INODE_PTR(7);
+		goto get_indirect;
+	}
+	ptr -= 256;
+	if (ptr < 256*256) {
+		bh = GET_INODE_PTR(8);
+		goto get_double;
+	}
+	ptr -= 256*256;
+	bh = GET_INODE_PTR(9);
+	bh = GET_INDIRECT_PTR((ptr >> 16) & 255);
+get_double:
+	bh = GET_INDIRECT_PTR((ptr >> 8) & 255);
+get_indirect:
+	bh = GET_INDIRECT_DATABLOCK(ptr & 255);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
 
 out:
-	*err = 0;
-	return phys_block;
+	if (err)
+		goto abort;
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = phys;
+	bh_result->b_state |= (1UL << BH_Mapped);
+	if (new)
+		bh_result->b_state |= (1UL << BH_New);
+abort:
+	unlock_kernel();
+	return err;
+
+abort_negative:
+	printk("minix_getblk: block<0");
+	goto abort;
+
+abort_too_big:
+	printk("minix_getblk: block>big");
+	goto abort;
 }
 
-int minix_getblk_block (struct inode *inode, long block,
-			int create, int *err, int *created)
+int minix_get_block(struct inode *inode, long block,
+		    struct buffer_head *bh_result, int create)
 {
 	if (INODE_VERSION(inode) == MINIX_V1)
-		return V1_getblk_block(inode, block, create, err, created);
+		return V1_get_block(inode, block, bh_result, create);
 	else
-		return V2_getblk_block(inode, block, create, err, created);
+		return V2_get_block(inode, block, bh_result, create);
 }
 
 /*
  * the global minix fs getblk function.
  */
-struct buffer_head *minix_getblk (struct inode *inode, int block, int create)
+struct buffer_head *minix_getblk(struct inode *inode, int block, int create)
 {
-	struct buffer_head *tmp = NULL;
-	int phys_block;
-	int err, created;
-
-	phys_block = minix_getblk_block(inode, block, create, &err, &created);
-	if (phys_block) {
-		tmp = getblk(inode->i_dev, phys_block, BLOCK_SIZE);
-		if (created) {
-			memset(tmp->b_data, 0, BLOCK_SIZE);
-			mark_buffer_uptodate(tmp, 1);
-			mark_buffer_dirty(tmp, 1);
+	struct buffer_head dummy;
+	int error;
+
+	dummy.b_state = 0;
+	dummy.b_blocknr = -1000;
+	error = minix_get_block(inode, block, &dummy, create);
+	if (!error && buffer_mapped(&dummy)) {
+		struct buffer_head *bh;
+		bh = getblk(dummy.b_dev, dummy.b_blocknr, BLOCK_SIZE);
+		if (buffer_new(&dummy)) {
+			memset(bh->b_data, 0, BLOCK_SIZE);
+			mark_buffer_uptodate(bh, 1);
+			mark_buffer_dirty(bh, 1);
 		}
+		return bh;
 	}
-	return tmp;
+	return NULL;
 }
 
 struct buffer_head * minix_bread(struct inode * inode, int block, int create)
 {
 	struct buffer_head * bh;
 
-	bh = minix_getblk(inode,block,create);
+	bh = minix_getblk(inode, block, create);
 	if (!bh || buffer_uptodate(bh))
 		return bh;
 	ll_rw_block(READ, 1, &bh);
diff -u --recursive --new-file v2.3.8/linux/fs/minix/symlink.c linux/fs/minix/symlink.c
--- v2.3.8/linux/fs/minix/symlink.c	Sat Sep 19 13:42:44 1998
+++ linux/fs/minix/symlink.c	Sun Jun 27 10:10:41 1999
@@ -33,11 +33,14 @@
 	NULL,			/* rename */
 	minix_readlink,		/* readlink */
 	minix_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static struct dentry * minix_follow_link(struct dentry * dentry,
diff -u --recursive --new-file v2.3.8/linux/fs/minix/truncate.c linux/fs/minix/truncate.c
--- v2.3.8/linux/fs/minix/truncate.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/minix/truncate.c	Tue Jun 29 09:22:08 1999
@@ -33,7 +33,7 @@
  */
 
 #define DATA_BUFFER_USED(bh) \
-	((bh->b_count > 1) || buffer_locked(bh))
+	(atomic_read(&bh->b_count) || buffer_locked(bh))
 
 /*
  * The functions for minix V1 fs truncation.
@@ -121,7 +121,7 @@
 		if (*(ind++))
 			break;
 	if (i >= 512) {
-		if (ind_bh->b_count != 1)
+		if (atomic_read(&ind_bh->b_count) != 1)
 			retry = 1;
 		else {
 			tmp = *p;
@@ -166,7 +166,7 @@
 		if (*(dind++))
 			break;
 	if (i >= 512) {
-		if (dind_bh->b_count != 1)
+		if (atomic_read(&dind_bh->b_count) != 1)
 			retry = 1;
 		else {
 			tmp = *p;
@@ -285,7 +285,7 @@
 		if (*(ind++))
 			break;
 	if (i >= 256) {
-		if (ind_bh->b_count != 1)
+		if (atomic_read(&ind_bh->b_count) != 1)
 			retry = 1;
 		else {
 			tmp = *p;
@@ -330,7 +330,7 @@
 		if (*(dind++))
 			break;
 	if (i >= 256) {
-		if (dind_bh->b_count != 1)
+		if (atomic_read(&dind_bh->b_count) != 1)
 			retry = 1;
 		else {
 			tmp = *p;
@@ -376,7 +376,7 @@
                 if (*(tind++))
                         break;
         if (i >= 256) {
-                if (tind_bh->b_count != 1)
+                if (atomic_read(&tind_bh->b_count) != 1)
                         retry = 1;
                 else {
                         tmp = *p;
diff -u --recursive --new-file v2.3.8/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.3.8/linux/fs/msdos/namei.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/msdos/namei.c	Sun Jun 27 10:10:41 1999
@@ -627,9 +627,10 @@
 	msdos_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,                   /* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.3.8/linux/fs/ncpfs/dir.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/ncpfs/dir.c	Sun Jun 27 10:10:41 1999
@@ -92,9 +92,10 @@
 	ncp_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c
--- v2.3.8/linux/fs/ncpfs/file.c	Wed Jun  2 11:30:24 1999
+++ linux/fs/ncpfs/file.c	Sun Jun 27 10:10:41 1999
@@ -295,6 +295,13 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* bmap */
-	NULL			/* truncate */
+	NULL,			/* follow_link */
+	NULL,			/* get_block */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* flushpage */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.3.8/linux/fs/ncpfs/symlink.c linux/fs/ncpfs/symlink.c
--- v2.3.8/linux/fs/ncpfs/symlink.c	Tue Apr 20 15:17:20 1999
+++ linux/fs/ncpfs/symlink.c	Sun Jun 27 10:10:41 1999
@@ -59,12 +59,14 @@
 	NULL,			/* rename */
 	ncp_readlink,		/* readlink */
 	ncp_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 /* ----- follow a symbolic link ------------------------------------------ */
diff -u --recursive --new-file v2.3.8/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.3.8/linux/fs/nfs/dir.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/nfs/dir.c	Wed Jun 30 11:30:55 1999
@@ -78,7 +78,7 @@
 	nfs_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
@@ -884,6 +884,8 @@
 	nfs_flush_dircache(dir);
 	error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
 				dentry->d_name.name, &sattr, &fhandle, &fattr);
+	if (!error)
+		dir->i_nlink++;
 	return error;
 }
 
@@ -909,8 +911,8 @@
 	/* Update i_nlink and invalidate dentry. */
 	if (!error) {
 		d_drop(dentry);
-		if (dentry->d_inode->i_nlink)
-			dentry->d_inode->i_nlink --;
+		if (dir->i_nlink)
+			dir->i_nlink--;
 	}
 
 	return error;
diff -u --recursive --new-file v2.3.8/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.3.8/linux/fs/nfs/file.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/nfs/file.c	Sat Jun 26 12:04:39 1999
@@ -71,7 +71,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	nfs_readpage,		/* readpage */
 	nfs_writepage,		/* writepage */
 	NULL,			/* flushpage */
@@ -167,7 +167,7 @@
  * If the writer ends up delaying the write, the writer needs to
  * increment the page use counts until he is done with the page.
  */
-static long nfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+static int nfs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
 {
 	long status;
 
diff -u --recursive --new-file v2.3.8/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c
--- v2.3.8/linux/fs/nfs/symlink.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/nfs/symlink.c	Sat Jun 26 12:04:39 1999
@@ -43,7 +43,7 @@
 	NULL,			/* rename */
 	nfs_readlink,		/* readlink */
 	nfs_follow_link,	/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.3.8/linux/fs/nfs/write.c	Sat Jun 19 11:38:49 1999
+++ linux/fs/nfs/write.c	Mon Jun 28 13:18:22 1999
@@ -467,7 +467,7 @@
 	 * The IO completion will then free the page and the dentry.
 	 */
 	get_page(page);
-	file->f_count++;
+	atomic_inc(&file->f_count);
 
 	/* Schedule request */
 	synchronous = schedule_write_request(req, synchronous);
diff -u --recursive --new-file v2.3.8/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.8/linux/fs/nfsd/vfs.c	Sat May 15 23:43:05 1999
+++ linux/fs/nfsd/vfs.c	Tue Jun 29 09:22:08 1999
@@ -342,7 +342,7 @@
 
 	memset(filp, 0, sizeof(*filp));
 	filp->f_op    = inode->i_op->default_file_ops;
-	filp->f_count = 1;
+	atomic_set(&filp->f_count, 1);
 	filp->f_flags = wflag? O_WRONLY : O_RDONLY;
 	filp->f_mode  = wflag? FMODE_WRITE : FMODE_READ;
 	filp->f_dentry = dentry;
@@ -360,7 +360,7 @@
 			/* I nearly added put_filp() call here, but this filp
 			 * is really on callers stack frame. -DaveM
 			 */
-			filp->f_count--;
+			atomic_dec(&filp->f_count);
 		}
 	}
 out_nfserr:
diff -u --recursive --new-file v2.3.8/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- v2.3.8/linux/fs/ntfs/fs.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/ntfs/fs.c	Sun Jun 27 10:10:41 1999
@@ -439,9 +439,10 @@
 	NULL, /* rename */
 	NULL, /* readlink */
 	NULL, /* follow_link */
+	NULL, /* get_block */
 	NULL, /* readpage */
 	NULL, /* writepage */
-	NULL, /* bmap */
+	NULL, /* flushpage */
 	NULL, /* truncate */
 	NULL, /* permission */
 	NULL, /* smap */
@@ -621,9 +622,10 @@
 	NULL, /* rename */
 	NULL, /* readlink */
 	NULL, /* follow_link */
-	generic_readpage,
+	ntfs_bmap, /* get_block */
+	block_read_full_page, /* readpage */
 	NULL, /* writepage */
-	ntfs_bmap,
+	NULL, /* flushpage */
 	NULL, /* truncate */
 	NULL, /* permission */
 	NULL, /* smap */
@@ -669,9 +671,10 @@
 	NULL, /* rename */
 	NULL, /* readlink */
 	NULL, /* follow_link */
+	NULL, /* get_block */
 	NULL, /* readpage */
 	NULL, /* writepage */
-	NULL, /* bmap */
+	NULL, /* flushpage */
 	NULL, /* truncate */
 	NULL, /* permission */
 	NULL, /* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/open.c linux/fs/open.c
--- v2.3.8/linux/fs/open.c	Mon May 24 22:47:43 1999
+++ linux/fs/open.c	Mon Jun 28 11:44:52 1999
@@ -790,7 +790,7 @@
 	int retval;
 	struct dentry *dentry = filp->f_dentry;
 
-	if (filp->f_count == 0) {
+	if (!atomic_read(&filp->f_count)) {
 		printk("VFS: Close: file count is 0\n");
 		return 0;
 	}
diff -u --recursive --new-file v2.3.8/linux/fs/pipe.c linux/fs/pipe.c
--- v2.3.8/linux/fs/pipe.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/pipe.c	Mon Jun 28 14:56:19 1999
@@ -8,6 +8,7 @@
 #include <linux/file.h>
 #include <linux/poll.h>
 #include <linux/malloc.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -28,16 +29,12 @@
 /* in case of paging and multiple read/write on the same pipe. (FGC)         */
 
 
-static ssize_t pipe_read(struct file * filp, char * buf,
-			 size_t count, loff_t *ppos)
+static ssize_t do_pipe_read(struct file * filp, char * buf, size_t count)
 {
 	struct inode * inode = filp->f_dentry->d_inode;
 	ssize_t chars = 0, size = 0, read = 0;
         char *pipebuf;
 
-	if (ppos != &filp->f_pos)
-		return -ESPIPE;
-
 	if (filp->f_flags & O_NONBLOCK) {
 		if (PIPE_LOCK(*inode))
 			return -EAGAIN;
@@ -82,17 +79,13 @@
 		return -EAGAIN;
 	return 0;
 }
-	
-static ssize_t pipe_write(struct file * filp, const char * buf,
-			  size_t count, loff_t *ppos)
+
+static ssize_t do_pipe_write(struct file * filp, const char * buf, size_t count)
 {
 	struct inode * inode = filp->f_dentry->d_inode;
 	ssize_t chars = 0, free = 0, written = 0, err=0;
 	char *pipebuf;
 
-	if (ppos != &filp->f_pos)
-		return -ESPIPE;
-
 	if (!PIPE_READERS(*inode)) { /* no readers */
 		send_sig(SIGPIPE,current,0);
 		return -EPIPE;
@@ -147,6 +140,32 @@
 	return written ? written : err;
 }
 
+static ssize_t pipe_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
+{
+	ssize_t retval;
+
+	if (ppos != &filp->f_pos)
+		return -ESPIPE;
+
+	lock_kernel();
+	retval = do_pipe_read(filp, buf, count);
+	unlock_kernel();
+	return retval;
+}
+
+static ssize_t pipe_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
+{
+	ssize_t retval;
+
+	if (ppos != &filp->f_pos)
+		return -ESPIPE;
+
+	lock_kernel();
+	retval = do_pipe_write(filp, buf, count);
+	unlock_kernel();
+	return retval;
+}
+
 static long long pipe_lseek(struct file * file, long long offset, int orig)
 {
 	return -ESPIPE;
@@ -461,7 +480,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.3.8/linux/fs/proc/array.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/proc/array.c	Sat Jun 26 12:04:39 1999
@@ -1519,7 +1519,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
@@ -1570,7 +1570,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.3.8/linux/fs/proc/base.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/proc/base.c	Sat Jun 26 12:04:39 1999
@@ -45,7 +45,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/fd.c linux/fs/proc/fd.c
--- v2.3.8/linux/fs/proc/fd.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/proc/fd.c	Sat Jun 26 12:04:40 1999
@@ -51,7 +51,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/generic.c linux/fs/proc/generic.c
--- v2.3.8/linux/fs/proc/generic.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/proc/generic.c	Sat Jun 26 12:04:40 1999
@@ -60,7 +60,7 @@
 	NULL,		/* rename	*/
 	NULL,		/* readlink	*/
 	NULL,		/* follow_link 	*/
-	NULL,		/* bmap 	*/
+	NULL,		/* get_block 	*/
 	NULL,		/* readpage 	*/
 	NULL,		/* writepage 	*/
 	NULL,		/* flushpage 	*/
@@ -86,7 +86,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/kmsg.c linux/fs/proc/kmsg.c
--- v2.3.8/linux/fs/proc/kmsg.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/proc/kmsg.c	Sat Jun 26 12:04:40 1999
@@ -72,7 +72,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/link.c linux/fs/proc/link.c
--- v2.3.8/linux/fs/proc/link.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/proc/link.c	Sat Jun 26 12:04:40 1999
@@ -49,7 +49,7 @@
 	NULL,			/* rename */
 	proc_readlink,		/* readlink */
 	proc_follow_link,	/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v2.3.8/linux/fs/proc/mem.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/proc/mem.c	Sat Jun 26 12:04:40 1999
@@ -336,7 +336,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/net.c linux/fs/proc/net.c
--- v2.3.8/linux/fs/proc/net.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/proc/net.c	Sat Jun 26 12:04:40 1999
@@ -113,7 +113,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/omirr.c linux/fs/proc/omirr.c
--- v2.3.8/linux/fs/proc/omirr.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/proc/omirr.c	Sat Jun 26 12:04:40 1999
@@ -289,7 +289,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.3.8/linux/fs/proc/openpromfs.c	Wed Apr 28 08:47:39 1999
+++ linux/fs/proc/openpromfs.c	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.33 1999/04/28 11:57:33 davem Exp $
+/* $Id: openpromfs.c,v 1.35 1999/06/27 00:37:36 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996-1998 Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -577,11 +577,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static struct file_operations openpromfs_nodenum_ops = {
@@ -611,11 +614,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static struct file_operations openprom_alias_operations = {
@@ -645,11 +651,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static int lookup_children(u16 n, const char * name, int len)
diff -u --recursive --new-file v2.3.8/linux/fs/proc/proc_devtree.c linux/fs/proc/proc_devtree.c
--- v2.3.8/linux/fs/proc/proc_devtree.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/proc/proc_devtree.c	Sat Jun 26 12:04:40 1999
@@ -57,7 +57,7 @@
 	NULL,			/* rename */
 	devtree_readlink,	/* readlink */
 	devtree_follow_link,	/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.3.8/linux/fs/proc/root.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/proc/root.c	Sat Jun 26 12:04:40 1999
@@ -71,7 +71,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
@@ -97,7 +97,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
@@ -142,7 +142,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
@@ -302,7 +302,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
@@ -490,7 +490,7 @@
 	NULL,			/* rename */
 	proc_self_readlink,	/* readlink */
 	proc_self_follow_link,	/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
@@ -513,7 +513,7 @@
 	NULL,			/* rename */
 	proc_readlink,		/* readlink */
 	proc_follow_link,	/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/scsi.c linux/fs/proc/scsi.c
--- v2.3.8/linux/fs/proc/scsi.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/proc/scsi.c	Sat Jun 26 12:04:40 1999
@@ -71,7 +71,7 @@
 	NULL,	    		/* rename */
 	NULL,	    		/* readlink */
 	NULL,	    		/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/proc/sysvipc.c linux/fs/proc/sysvipc.c
--- v2.3.8/linux/fs/proc/sysvipc.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/proc/sysvipc.c	Sat Jun 26 12:04:40 1999
@@ -130,7 +130,7 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/fs/qnx4/dir.c linux/fs/qnx4/dir.c
--- v2.3.8/linux/fs/qnx4/dir.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/qnx4/dir.c	Sun Jun 27 10:10:41 1999
@@ -114,10 +114,12 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.3.8/linux/fs/qnx4/file.c linux/fs/qnx4/file.c
--- v2.3.8/linux/fs/qnx4/file.c	Fri Mar 26 13:57:41 1999
+++ linux/fs/qnx4/file.c	Sun Jun 27 10:10:41 1999
@@ -189,16 +189,18 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	qnx4_bmap,	        /* get_block */
 	qnx4_readpage,		/* readpage */
 	NULL,			/* writepage */
-	qnx4_bmap,	        /* bmap */
+	NULL,			/* flushpage */
 #ifdef CONFIG_QNX4FS_RW
 	qnx4_truncate,		/* truncate */
 #else
 	NULL,
 #endif
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static int qnx4_readpage(struct file *file, struct page *page)
diff -u --recursive --new-file v2.3.8/linux/fs/qnx4/fsync.c linux/fs/qnx4/fsync.c
--- v2.3.8/linux/fs/qnx4/fsync.c	Tue Sep  1 10:43:13 1998
+++ linux/fs/qnx4/fsync.c	Tue Jun 29 09:22:08 1999
@@ -55,7 +55,7 @@
 		return 0;
 	}
 	ll_rw_block(WRITE, 1, &bh);
-	bh->b_count--;
+	atomic_dec(&bh->b_count);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.8/linux/fs/qnx4/symlinks.c linux/fs/qnx4/symlinks.c
--- v2.3.8/linux/fs/qnx4/symlinks.c	Tue Jun  1 23:25:47 1999
+++ linux/fs/qnx4/symlinks.c	Sun Jun 27 10:10:41 1999
@@ -43,11 +43,14 @@
 	NULL,			/* rename */
 	qnx4_readlink,		/* readlink */
 	qnx4_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static struct dentry *qnx4_follow_link(struct dentry *dentry,
diff -u --recursive --new-file v2.3.8/linux/fs/read_write.c linux/fs/read_write.c
--- v2.3.8/linux/fs/read_write.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/read_write.c	Mon Jun 28 13:31:07 1999
@@ -117,28 +117,22 @@
 {
 	ssize_t ret;
 	struct file * file;
-	ssize_t (*read)(struct file *, char *, size_t, loff_t *);
-
-	lock_kernel();
 
 	ret = -EBADF;
 	file = fget(fd);
-	if (!file)
-		goto bad_file;
-	if (!(file->f_mode & FMODE_READ))
-		goto out;
-	ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
-				file, file->f_pos, count);
-	if (ret)
-		goto out;
-	ret = -EINVAL;
-	if (!file->f_op || !(read = file->f_op->read))
-		goto out;
-	ret = read(file, buf, count, &file->f_pos);
-out:
-	fput(file);
-bad_file:
-	unlock_kernel();
+	if (file) {
+		if (file->f_mode & FMODE_READ) {
+			ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+						file, file->f_pos, count);
+			if (!ret) {
+				ssize_t (*read)(struct file *, char *, size_t, loff_t *);
+				ret = -EINVAL;
+				if (file->f_op && (read = file->f_op->read) != NULL)
+					ret = read(file, buf, count, &file->f_pos);
+			}
+		}
+		fput(file);
+	}
 	return ret;
 }
 
@@ -146,31 +140,23 @@
 {
 	ssize_t ret;
 	struct file * file;
-	struct inode * inode;
-	ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
-
-	lock_kernel();
 
 	ret = -EBADF;
 	file = fget(fd);
-	if (!file)
-		goto bad_file;
-	if (!(file->f_mode & FMODE_WRITE))
-		goto out;
-	inode = file->f_dentry->d_inode;
-	ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
+	if (file) {
+		if (file->f_mode & FMODE_WRITE) {
+			struct inode *inode = file->f_dentry->d_inode;
+			ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
 				file->f_pos, count);
-	if (ret)
-		goto out;
-	ret = -EINVAL;
-	if (!file->f_op || !(write = file->f_op->write))
-		goto out;
-
-	ret = write(file, buf, count, &file->f_pos);
-out:
-	fput(file);
-bad_file:
-	unlock_kernel();
+			if (!ret) {
+				ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
+				ret = -EINVAL;
+				if (file->f_op && (write = file->f_op->write) != NULL)
+					ret = write(file, buf, count, &file->f_pos);
+			}
+		}
+		fput(file);
+	}
 	return ret;
 }
 
diff -u --recursive --new-file v2.3.8/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.3.8/linux/fs/romfs/inode.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/romfs/inode.c	Sun Jun 27 10:10:41 1999
@@ -1,7 +1,7 @@
 /*
  * ROMFS file system, Linux implementation
  *
- * Copyright (C) 1997  Janos Farkas <chexum@shadow.banki.hu>
+ * Copyright (C) 1997-1999  Janos Farkas <chexum@shadow.banki.hu>
  *
  * Using parts of the minix filesystem
  * Copyright (C) 1991, 1992  Linus Torvalds
@@ -57,6 +57,7 @@
 #include <linux/fs.h>
 #include <linux/locks.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
@@ -320,7 +321,7 @@
 	const char *name;		/* got from dentry */
 	int len;
 
-	res = 0;			/* instead of ENOENT */
+	res = -EACCES;			/* placeholder for "no data here" */
 	offset = dir->i_ino & ROMFH_MASK;
 	if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
 		goto out;
@@ -335,8 +336,9 @@
 	len = dentry->d_name.len;
 
 	for(;;) {
-		if (!offset || offset >= maxoff
-		    || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
+		if (!offset || offset >= maxoff)
+			goto out0;
+		if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
 			goto out;
 
 		/* try to match the first 16 bytes of name */
@@ -365,19 +367,28 @@
 	if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
 		offset = ntohl(ri.spec) & ROMFH_MASK;
 
-	if ((inode = iget(dir->i_sb, offset))==NULL) {
-		res = -EACCES;
-	} else {
-		d_add(dentry, inode);
-	}
+	if ((inode = iget(dir->i_sb, offset)))
+		goto outi;
 
-out:
-	return ERR_PTR(res);
+	/*
+	 * it's a bit funky, _lookup needs to return an error code
+	 * (negative) or a NULL, both as a dentry.  ENOENT should not
+	 * be returned, instead we need to create a negative dentry by
+	 * d_add(dentry, NULL); and return 0 as no error.
+	 * (Although as I see, it only matters on writable file
+	 * systems).
+	 */
+
+out0:	inode = NULL;
+outi:	res = 0;
+	d_add (dentry, inode);
+
+out:	return ERR_PTR(res);
 }
 
 /*
  * Ok, we do readpage, to be able to execute programs.  Unfortunately,
- * we can't use bmap, since we have looser alignments.
+ * we can't use bmap, since we may have looser alignments.
  */
 
 static int
@@ -389,12 +400,13 @@
 	unsigned long offset, avail, readlen;
 	int result = -EIO;
 
-	atomic_inc(&page->count);
-	set_bit(PG_locked, &page->flags);
-
+	lock_kernel();
+	get_page(page);
 	buf = page_address(page);
-	clear_bit(PG_uptodate, &page->flags);
-	clear_bit(PG_error, &page->flags);
+
+	/* hack? */
+	page->owner = (int)current;
+
 	offset = page->offset;
 	if (offset < inode->i_size) {
 		avail = inode->i_size-offset;
@@ -403,18 +415,19 @@
 			if (readlen < PAGE_SIZE) {
 				memset((void *)(buf+readlen),0,PAGE_SIZE-readlen);
 			}
-			set_bit(PG_uptodate, &page->flags);
+			SetPageUptodate(page);
 			result = 0;
 		}
 	}
 	if (result) {
-		set_bit(PG_error, &page->flags);
 		memset((void *)buf, 0, PAGE_SIZE);
+		SetPageError(page);
 	}
 
-	clear_bit(PG_locked, &page->flags);
-	wake_up(&page->wait);
+	UnlockPage(page);
+
 	free_page(buf);
+	unlock_kernel();
 
 	return result;
 }
@@ -508,12 +521,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block -- not really */
 	romfs_readpage,		/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap -- not really */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static struct file_operations romfs_dir_operations = {
@@ -550,12 +565,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static struct inode_operations romfs_link_inode_operations = {
@@ -571,18 +588,20 @@
 	NULL,			/* rename */
 	romfs_readlink,		/* readlink */
 	romfs_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static mode_t romfs_modemap[] =
 {
-	0, S_IFDIR, S_IFREG, S_IFLNK+0777,
-	S_IFBLK, S_IFCHR, S_IFSOCK, S_IFIFO
+	0, S_IFDIR+0644, S_IFREG+0644, S_IFLNK+0777,
+	S_IFBLK+0600, S_IFCHR+0600, S_IFSOCK+0644, S_IFIFO+0644
 };
 
 static struct inode_operations *romfs_inoops[] =
@@ -591,10 +610,10 @@
 	&romfs_dir_inode_operations,
 	&romfs_file_inode_operations,
 	&romfs_link_inode_operations,
-	&blkdev_inode_operations,	/* standard handlers */
-	&chrdev_inode_operations,
-	NULL,				/* socket */
-	NULL,				/* fifo */
+	NULL,				/* device/fifo/socket nodes, */
+	NULL,				/*   set by init_special_inode */
+	NULL,
+	NULL,
 };
 
 static void
@@ -627,34 +646,30 @@
 	i->i_mtime = i->i_atime = i->i_ctime = 0;
 	i->i_uid = i->i_gid = 0;
 
-	i->i_op = romfs_inoops[nextfh & ROMFH_TYPE];
-
-	/* Precalculate the data offset */
-	ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
-	if (ino >= 0)
-		ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
-	else
-		ino = 0;
-
-	i->u.romfs_i.i_metasize = ino;
-	i->u.romfs_i.i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
-
-	/* Compute permissions */
-	ino = S_IRUGO|S_IWUSR;
-	ino |= romfs_modemap[nextfh & ROMFH_TYPE];
-	if (nextfh & ROMFH_EXEC) {
-		ino |= S_IXUGO;
-	}
-	i->i_mode = ino;
-
-	if (S_ISFIFO(ino))
-		init_fifo(i);
-	else if (S_ISDIR(ino))
-		i->i_size = i->u.romfs_i.i_metasize;
-	else if (S_ISBLK(ino) || S_ISCHR(ino)) {
-		i->i_mode &= ~(S_IRWXG|S_IRWXO);
-		ino = ntohl(ri.spec);
-		i->i_rdev = MKDEV(ino>>16,ino&0xffff);
+        /* Precalculate the data offset */
+        ino = romfs_strnlen(i, ino+ROMFH_SIZE, ROMFS_MAXFN);
+        if (ino >= 0)
+                ino = ((ROMFH_SIZE+ino+1+ROMFH_PAD)&ROMFH_MASK);
+        else
+                ino = 0;
+
+        i->u.romfs_i.i_metasize = ino;
+        i->u.romfs_i.i_dataoffset = ino+(i->i_ino&ROMFH_MASK);
+
+        /* Compute permissions */
+        ino = romfs_modemap[nextfh & ROMFH_TYPE];
+	/* only "normal" files have ops */
+        if ((i->i_op = romfs_inoops[nextfh & ROMFH_TYPE])) {
+		if (nextfh & ROMFH_EXEC)
+			ino |= S_IXUGO;
+		i->i_mode = ino;
+		if (S_ISDIR(ino))
+			i->i_size = i->u.romfs_i.i_metasize;
+	} else {
+		/* depending on MBZ for sock/fifos */
+		nextfh = ntohl(ri.spec);
+		nextfh = kdev_t_to_nr(MKDEV(nextfh>>16,nextfh&0xffff));
+		init_special_inode(i, ino, nextfh);
 	}
 }
 
diff -u --recursive --new-file v2.3.8/linux/fs/select.c linux/fs/select.c
--- v2.3.8/linux/fs/select.c	Sun May 23 23:53:45 1999
+++ linux/fs/select.c	Mon Jun 28 13:20:36 1999
@@ -64,9 +64,9 @@
 		if (p->nr < __MAX_POLL_TABLE_ENTRIES) {
 			struct poll_table_entry * entry;
 ok_table:
-		 	entry = p->entry + p->nr;
-		 	entry->filp = filp;
-		 	filp->f_count++;
+			entry = p->entry + p->nr;
+			entry->filp = filp;
+			atomic_inc(&filp->f_count);
 			entry->wait_address = wait_address;
 			init_waitqueue_entry(&entry->wait, current);
 			add_wait_queue(wait_address,&entry->wait);
@@ -181,17 +181,13 @@
 			off = i / __NFDBITS;
 			if (!(bit & BITS(fds, off)))
 				continue;
-			/*
-			 * The poll_wait routine will increment f_count if
-			 * the file is added to the wait table, so we don't
-			 * need to increment it now.
-			 */
-			file = fcheck(i);
+			file = fget(i);
 			mask = POLLNVAL;
 			if (file) {
 				mask = DEFAULT_POLLMASK;
 				if (file->f_op && file->f_op->poll)
 					mask = file->f_op->poll(file, wait);
+				fput(file);
 			}
 			if ((mask & POLLIN_SET) && ISSET(bit, __IN(fds,off))) {
 				SET(bit, __RES_IN(fds,off));
@@ -347,14 +343,14 @@
 			mask = 0;
 			fd = fdpnt->fd;
 			if (fd >= 0) {
-				/* poll_wait increments f_count if needed */
-				struct file * file = fcheck(fd);
+				struct file * file = fget(fd);
 				mask = POLLNVAL;
 				if (file != NULL) {
 					mask = DEFAULT_POLLMASK;
 					if (file->f_op && file->f_op->poll)
 						mask = file->f_op->poll(file, wait);
 					mask &= fdpnt->events | POLLERR | POLLHUP;
+					fput(file);
 				}
 				if (mask) {
 					wait = NULL;
diff -u --recursive --new-file v2.3.8/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.3.8/linux/fs/smbfs/dir.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/smbfs/dir.c	Sun Jun 27 10:10:41 1999
@@ -59,9 +59,10 @@
 	smb_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.3.8/linux/fs/smbfs/file.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/smbfs/file.c	Sun Jun 27 10:10:41 1999
@@ -404,9 +404,10 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	smb_readpage,		/* readpage */
 	smb_writepage,		/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	smb_file_permission,	/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.3.8/linux/fs/smbfs/inode.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/smbfs/inode.c	Wed Jun 30 11:24:55 1999
@@ -6,9 +6,7 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
-
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.3.8/linux/fs/sysv/balloc.c linux/fs/sysv/balloc.c
--- v2.3.8/linux/fs/sysv/balloc.c	Sun Sep 13 10:27:07 1998
+++ linux/fs/sysv/balloc.c	Tue Jun 29 09:22:08 1999
@@ -201,7 +201,7 @@
 		unlock_super(sb);
 		return 0;
 	}
-	if (bh->b_count != 1) {
+	if (atomic_read(&bh->b_count) != 1) {
 		printk("sysv_new_block: block already in use\n");
 		unlock_super(sb);
 		return 0;
diff -u --recursive --new-file v2.3.8/linux/fs/sysv/dir.c linux/fs/sysv/dir.c
--- v2.3.8/linux/fs/sysv/dir.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/sysv/dir.c	Sun Jun 27 10:10:41 1999
@@ -59,11 +59,14 @@
 	sysv_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
diff -u --recursive --new-file v2.3.8/linux/fs/sysv/file.c linux/fs/sysv/file.c
--- v2.3.8/linux/fs/sysv/file.c	Sat Jun 19 12:15:14 1999
+++ linux/fs/sysv/file.c	Sun Jun 27 10:10:41 1999
@@ -33,50 +33,14 @@
 #include <linux/fs.h>
 #include <linux/sysv_fs.h>
 
-static int sysv_writepage (struct file * file, struct page * page)
-{
-	struct dentry *dentry = file->f_dentry;
-	struct inode *inode = dentry->d_inode;
-	unsigned long block;
-	int *p, nr[PAGE_SIZE/512];
-	int i, err, created;
-	struct buffer_head *bh;
-
-	i = PAGE_SIZE >> inode->i_sb->sv_block_size_bits;
-	block = page->offset >> inode->i_sb->sv_block_size_bits;
-	p = nr;
-	bh = page->buffers;
-	do {
-		if (bh && bh->b_blocknr)
-			*p = bh->b_blocknr;
-		else
-			*p = sysv_getblk_block (inode, block, 1, &err, &created);
-		if (!*p)
-			return -EIO;
-		i--;
-		block++;
-		p++;
-		if (bh)
-			bh = bh->b_this_page;
-	} while (i > 0);
-
-	/* IO start */
-	brw_page(WRITE, page, inode->i_dev, nr, inode->i_sb->sv_block_size, 1);
-	return 0;
-}
-
-static long sysv_write_one_page (struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
-{
-	return block_write_one_page(file, page, offset, bytes, buf, sysv_getblk_block);
-}
-
 /*
  * Write to a file (through the page cache).
  */
 static ssize_t
 sysv_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-	return generic_file_write(file, buf, count, ppos, sysv_write_one_page);
+	return generic_file_write(file, buf, count,
+				  ppos, block_write_partial_page);
 }
 
 /*
@@ -113,12 +77,12 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
-	sysv_writepage,		/* writepage */
-	sysv_bmap,		/* bmap */
+	sysv_get_block,		/* get_block */
+	block_read_full_page,	/* readpage */
+	block_write_full_page,	/* writepage */
+	block_flushpage,	/* flushpage */
 	sysv_truncate,		/* truncate */
 	NULL,   		/* permission */
 	NULL,			/* smap */
-	NULL,			/* revalidate */
-	block_flushpage,	/* flushpage */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.3.8/linux/fs/sysv/fsync.c linux/fs/sysv/fsync.c
--- v2.3.8/linux/fs/sysv/fsync.c	Sun Sep 13 12:12:34 1998
+++ linux/fs/sysv/fsync.c	Tue Jun 29 09:22:08 1999
@@ -54,7 +54,7 @@
 		return 0;
 	}
 	ll_rw_block(WRITE, 1, &bh);
-	bh->b_count--;
+	atomic_dec(&bh->b_count);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.8/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.3.8/linux/fs/sysv/inode.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/sysv/inode.c	Sun Jun 27 10:10:41 1999
@@ -31,6 +31,7 @@
 #include <linux/string.h>
 #include <linux/locks.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
@@ -62,6 +63,11 @@
 	sysv_free_inode(inode);
 }
 
+static void sysv_put_super(struct super_block *);
+static void sysv_write_super(struct super_block *);
+static void sysv_read_inode(struct inode *);
+static int sysv_notify_change(struct dentry *, struct iattr *);
+static int sysv_statfs(struct super_block *, struct statfs *, int);
 
 static struct super_operations sysv_sops = {
 	sysv_read_inode,
@@ -338,8 +344,8 @@
 	return sb;
 }
 
-struct super_block *sysv_read_super(struct super_block *sb,void *data,
-				     int silent)
+static struct super_block *sysv_read_super(struct super_block *sb,
+					   void *data, int silent)
 {
 	struct buffer_head *bh;
 	const char *found;
@@ -519,7 +525,7 @@
 }
 
 /* This is only called on sync() and umount(), when s_dirt=1. */
-void sysv_write_super (struct super_block *sb)
+static void sysv_write_super(struct super_block *sb)
 {
 	lock_super(sb);
 	if (buffer_dirty(sb->sv_bh1) || buffer_dirty(sb->sv_bh2)) {
@@ -542,7 +548,7 @@
 	unlock_super(sb);
 }
 
-void sysv_put_super(struct super_block *sb)
+static void sysv_put_super(struct super_block *sb)
 {
 	/* we can assume sysv_write_super() has already been called,
 	   and that the superblock is locked */
@@ -555,7 +561,7 @@
 	MOD_DEC_USE_COUNT;
 }
 
-int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+static int sysv_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
 	struct statfs tmp;
 
@@ -597,59 +603,72 @@
 	return tmp + sb->sv_block_base;
 }
 
-int sysv_bmap(struct inode * inode,int block_nr)
+static unsigned int sysv_block_map(struct inode *inode, unsigned int block)
 {
-	unsigned int block = block_nr;
-	struct super_block * sb = inode->i_sb;
-	int convert;
-	int i;
-	struct buffer_head * bh;
+	struct super_block *sb;
+	int i, ret, convert;
 
-	if (block < 10)
-		return inode_bmap(sb,inode,block);
+	ret = 0;
+	lock_kernel();
+	sb = inode->i_sb;
+	if (block < 10) {
+		ret = inode_bmap(sb, inode, block);
+		goto out;
+	}
 	block -= 10;
 	convert = sb->sv_convert;
 	if (block < sb->sv_ind_per_block) {
-		i = inode_bmap(sb,inode,10);
+		i = inode_bmap(sb, inode, 10);
 		if (!i)
-			return 0;
-		bh = bread(inode->i_dev,i,sb->sv_block_size);
-		return block_bmap(sb, bh, block, convert);
+			goto out;
+		ret = block_bmap(sb,
+				 bread(inode->i_dev, i, sb->sv_block_size),
+				 block, convert);
+		goto out;
 	}
 	block -= sb->sv_ind_per_block;
 	if (block < sb->sv_ind_per_block_2) {
-		i = inode_bmap(sb,inode,11);
+		i = inode_bmap(sb, inode, 11);
 		if (!i)
-			return 0;
-		bh = bread(inode->i_dev,i,sb->sv_block_size);
-		i = block_bmap(sb, bh, block >> sb->sv_ind_per_block_bits, convert);
+			goto out;
+		i = block_bmap(sb,
+			       bread(inode->i_dev, i, sb->sv_block_size),
+			       (block >> sb->sv_ind_per_block_bits), convert);
 		if (!i)
-			return 0;
-		bh = bread(inode->i_dev,i,sb->sv_block_size);
-		return block_bmap(sb, bh, block & sb->sv_ind_per_block_1, convert);
+			goto out;
+		ret = block_bmap(sb,
+				 bread(inode->i_dev, i, sb->sv_block_size),
+				 (block & sb->sv_ind_per_block_1), convert);
+		goto out;
 	}
 	block -= sb->sv_ind_per_block_2;
 	if (block < sb->sv_ind_per_block_3) {
-		i = inode_bmap(sb,inode,12);
+		i = inode_bmap(sb, inode, 12);
 		if (!i)
-			return 0;
-		bh = bread(inode->i_dev,i,sb->sv_block_size);
-		i = block_bmap(sb, bh, block >> sb->sv_ind_per_block_2_bits, convert);
+			goto out;
+		i = block_bmap(sb,
+			       bread(inode->i_dev, i, sb->sv_block_size),
+			       (block >> sb->sv_ind_per_block_2_bits), convert);
 		if (!i)
-			return 0;
-		bh = bread(inode->i_dev,i,sb->sv_block_size);
-		i = block_bmap(sb, bh, (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1,convert);
+			goto out;
+		ret = block_bmap(sb,
+				 bread(inode->i_dev, i, sb->sv_block_size),
+				 ((block >> sb->sv_ind_per_block_bits) &
+				  sb->sv_ind_per_block_1), convert);
 		if (!i)
-			return 0;
-		bh = bread(inode->i_dev,i,sb->sv_block_size);
-		return block_bmap(sb, bh, block & sb->sv_ind_per_block_1, convert);
-	}
-	if ((int)block<0) {
-		printk("sysv_bmap: block<0");
-		return 0;
+			goto out;
+		ret = block_bmap(sb,
+				 bread(inode->i_dev, i, sb->sv_block_size),
+				 (block & sb->sv_ind_per_block_1), convert);
+		goto out;
 	}
-	printk("sysv_bmap: block>big");
-	return 0;
+	if ((int)block < 0)
+		printk("sysv_block_map: block < 0\n");
+	else
+		printk("sysv_block_map: block > big\n");
+out:
+	unlock_kernel();
+	return ret;
 }
 
 /* End of bmap support. */
@@ -657,8 +676,8 @@
 
 /* Access selected blocks of regular files (or directories) */
 
-static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create,
-					 int metadata, int *phys_block, int *created)
+static struct buffer_head *inode_getblk(struct inode *inode, int nr, int new_block,
+	int *err, int metadata, long *phys, int *new)
 {
 	struct super_block *sb;
 	u32 tmp;
@@ -677,15 +696,30 @@
 			brelse(result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
+			*phys = tmp;
 			return NULL;
 		}
 	}
-	if (!create)
-		return NULL;
+	*err = -EFBIG;
+
+	/* Check file limits.. */
+	{
+		unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+		if (limit < RLIM_INFINITY) {
+			limit >>= sb->sv_block_size_bits;
+			if (new_block >= limit) {
+				send_sig(SIGXFSZ, current, 0);
+				*err = -EFBIG;
+				return NULL;
+			}
+		}
+	}
+
 	tmp = sysv_new_block(sb);
-	if (!tmp)
+	if (!tmp) {
+		*err = -ENOSPC;
 		return NULL;
+	}
 	if (metadata) {
 		result = sv_getblk(sb, inode->i_dev, tmp);
 		if (*p) {
@@ -695,12 +729,18 @@
 		}
 	} else {
 		if (*p) {
+			/*
+			 * Nobody is allowed to change block allocation
+			 * state from under us:
+			 */
+			BUG();
 			sysv_free_block(sb, tmp);
 			goto repeat;
 		}
-		*phys_block = tmp;
+		*phys = tmp;
 		result = NULL;
-		*created = 1;
+		*err = 0;
+		*new = 1;
 	}
 	*p = tmp;
 
@@ -709,24 +749,24 @@
 	return result;
 }
 
-static struct buffer_head * block_getblk(struct inode * inode,
-	struct buffer_head * bh, int nr, int create,
-	int metadata, int *phys_block, int *created)
+static struct buffer_head *block_getblk(struct inode *inode,
+	struct buffer_head *bh, int nr, int new_block, int *err,
+	int metadata, long *phys, int *new)
 {
 	struct super_block *sb;
 	u32 tmp, block;
 	sysv_zone_t *p;
 	struct buffer_head * result;
+	unsigned long limit;
 
+	result = NULL;
 	if (!bh)
-		return NULL;
+		goto out;
 	if (!buffer_uptodate(bh)) {
 		ll_rw_block(READ, 1, &bh);
 		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh)) {
-			brelse(bh);
-			return NULL;
-		}
+		if (!buffer_uptodate(bh))
+			goto out;
 	}
 	sb = inode->i_sb;
 	p = nr + (sysv_zone_t *) bh->b_data;
@@ -737,120 +777,175 @@
 	if (tmp) {
 		if (metadata) {
 			result = sv_getblk(sb, bh->b_dev, block);
-			if (tmp == *p) {
-				brelse(bh);
-				return result;
-			}
+			if (tmp == *p)
+				goto out;
 			brelse(result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
-			brelse(bh);
-			return NULL;
+			*phys = tmp;
+			goto out;
 		}
 	}
-	if (!create) {
-		brelse(bh);
-		return NULL;
+	*err = -EFBIG;
+
+	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	if (limit < RLIM_INFINITY) {
+		limit >>= sb->sv_block_size_bits;
+		if (new_block >= limit) {
+			send_sig(SIGXFSZ, current, 0);
+			goto out;
+		}
 	}
+
 	block = sysv_new_block(sb);
-	if (!block) {
-		brelse(bh);
-		return NULL;
-	}
+	if (!block)
+		goto out;
 	if (metadata) {
 		result = sv_getblk(sb, bh->b_dev, block);
 		if (*p) {
-			sysv_free_block(sb,block);
+			sysv_free_block(sb, block);
 			brelse(result);
 			goto repeat;
 		}
+		memset(result->b_data, 0, sb->sv_block_size);
+		mark_buffer_uptodate(result, 1);
+		mark_buffer_dirty(result, 1);
 	} else {
-		*phys_block = tmp;
-		result = NULL;
-		*created = 1;
+		*phys = tmp;
+		*new = 1;
+	}
+	if (*p) {
+		sysv_free_block(sb, block);
+		brelse(result);
+		goto repeat;
 	}
 	*p = (sb->sv_convert ? to_coh_ulong(block) : block);
 	mark_buffer_dirty(bh, 1);
+	*err = 0;
+out:
 	brelse(bh);
 	return result;
 }
 
-int sysv_getblk_block(struct inode *inode, long block, int create,
-		      int *err, int *created)
+int sysv_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
 {
-	struct super_block *sb = inode->i_sb;
-	struct buffer_head *bh, *tmp;
-	int phys_block;
-
-	*err = -EIO;
-	if (block < 0) {
-		printk("sysv_getblk: block<0");
-		return 0;
-	}
-	if (block > sb->sv_ind_per_block_3) {
-		printk("sysv_getblk: block>big");
+	struct super_block *sb;
+	int ret, err, new;
+	struct buffer_head *bh;
+	unsigned long ptr, phys;
+
+	if (!create) {
+		phys = sysv_block_map(inode, iblock);
+		if (phys) {
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_blocknr = phys;
+			bh_result->b_state |= (1UL << BH_Mapped);
+		}
 		return 0;
 	}
-	if (block < 10) {
-		tmp = inode_getblk(inode, block, create,
-				   0, &phys_block, created);
-		goto out;
-	}
-	block -= 10;
-	if (block < sb->sv_ind_per_block) {
-		bh = inode_getblk(inode, 10, create, 1, NULL, NULL);
-		tmp = block_getblk(inode, bh, block, create,
-				   0, &phys_block, created);
-		goto out;
-	}
-	block -= sb->sv_ind_per_block;
-	if (block < sb->sv_ind_per_block_2) {
-		bh = inode_getblk(inode, 11, create, 1, NULL, NULL);
-		bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_bits, create,
-				  1, NULL, NULL);
-		tmp = block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create,
-				   0, &phys_block, created);
+
+	err = -EIO;
+	new = 0;
+	ret = 0;
+	bh = NULL;
+
+	lock_kernel();
+	sb = inode->i_sb;
+	if (iblock < 0)
+		goto abort_negative;
+	if (iblock > sb->sv_ind_per_block_3)
+		goto abort_too_big;
+
+	err = 0;
+	ptr = iblock;
+
+	/*
+	 * ok, these macros clean the logic up a bit and make
+	 * it much more readable:
+	 */
+#define GET_INODE_DATABLOCK(x) \
+		inode_getblk(inode, x, iblock, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+		inode_getblk(inode, x, iblock, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+		block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new);
+#define GET_INDIRECT_PTR(x) \
+		block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
+
+	if (ptr < 10) {
+		bh = GET_INODE_DATABLOCK(ptr);
 		goto out;
 	}
-	block -= sb->sv_ind_per_block_2;
-	bh = inode_getblk(inode, 12, create, 1, NULL, NULL);
-	bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_2_bits, create,
-			  1, NULL, NULL);
-	bh = block_getblk(inode, bh,
-			  (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1,
-			  create, 1, NULL, NULL);
-	tmp = block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create,
-			   0, &phys_block, created);
+	ptr -= 10;
+	if (ptr < sb->sv_ind_per_block) {
+		bh = GET_INODE_PTR(10);
+		goto get_indirect;
+	}
+	ptr -= sb->sv_ind_per_block;
+	if (ptr < sb->sv_ind_per_block_2) {
+		bh = GET_INODE_PTR(11);
+		goto get_double;
+	}
+	ptr -= sb->sv_ind_per_block_2;
+	bh = GET_INODE_PTR(12);
+	bh = GET_INDIRECT_PTR(ptr >> sb->sv_ind_per_block_2_bits);
+get_double:
+	bh = GET_INDIRECT_PTR((ptr >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1);
+get_indirect:
+	bh = GET_INDIRECT_DATABLOCK(ptr & sb->sv_ind_per_block_1);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
 
 out:
-	*err = 0;
-	return phys_block;
-}
-
-struct buffer_head *sysv_getblk (struct inode *inode, unsigned int block, int create)
-{
-	struct buffer_head *tmp = NULL;
-	int phys_block;
-	int err, created;
-
-	phys_block = sysv_getblk_block(inode, block, create, &err, &created);
-	if (phys_block) {
-		tmp = getblk(inode->i_dev, phys_block, BLOCK_SIZE);
-		if (created) {
-			memset(tmp->b_data, 0, BLOCK_SIZE);
-			mark_buffer_uptodate(tmp, 1);
-			mark_buffer_dirty(tmp, 1);
+	if (err)
+		goto abort;
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = phys;
+	bh_result->b_state |= (1UL << BH_Mapped);
+	if (new)
+		bh_result->b_state |= (1UL << BH_New);
+abort:
+	unlock_kernel();
+	return err;
+
+abort_negative:
+	printk("sysv_getblk: block < 0\n");
+	goto abort;
+
+abort_too_big:
+	printk("sysv_getblk: block > big\n");
+	goto abort;
+}
+
+struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block, int create)
+{
+	struct buffer_head dummy;
+	int error;
+
+	dummy.b_state = 0;
+	dummy.b_blocknr = -1000;
+	error = sysv_get_block(inode, block, &dummy, create);
+	if (!error && buffer_mapped(&dummy)) {
+		struct buffer_head *bh;
+		bh = getblk(dummy.b_dev, dummy.b_blocknr, BLOCK_SIZE);
+		if (buffer_new(&dummy)) {
+			memset(bh->b_data, 0, BLOCK_SIZE);
+			mark_buffer_uptodate(bh, 1);
+			mark_buffer_dirty(bh, 1);
 		}
+		return bh;
 	}
-	return tmp;
+	return NULL;
 }
 
-struct buffer_head * sysv_file_bread(struct inode * inode, int block, int create)
+struct buffer_head *sysv_file_bread(struct inode *inode, int block, int create)
 {
-	struct buffer_head * bh;
+	struct buffer_head *bh;
 
-	bh = sysv_getblk(inode,block,create);
+	bh = sysv_getblk(inode, block, create);
 	if (!bh || buffer_uptodate(bh))
 		return bh;
 	ll_rw_block(READ, 1, &bh);
@@ -903,7 +998,7 @@
 	*(unsigned short *)(p+1) = (unsigned short) val;
 }
 
-void sysv_read_inode(struct inode * inode)
+static void sysv_read_inode(struct inode *inode)
 {
 	struct super_block * sb = inode->i_sb;
 	struct buffer_head * bh;
@@ -971,7 +1066,7 @@
 }
 
 /* To avoid inconsistencies between inodes in memory and inodes on disk. */
-int sysv_notify_change(struct dentry *dentry, struct iattr *attr)
+static int sysv_notify_change(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = dentry->d_inode;
 	int error;
diff -u --recursive --new-file v2.3.8/linux/fs/sysv/symlink.c linux/fs/sysv/symlink.c
--- v2.3.8/linux/fs/sysv/symlink.c	Sat Sep 19 13:45:42 1998
+++ linux/fs/sysv/symlink.c	Sun Jun 27 10:10:41 1999
@@ -39,11 +39,14 @@
 	NULL,			/* rename */
 	sysv_readlink,		/* readlink */
 	sysv_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 static struct dentry *sysv_follow_link(struct dentry * dentry,
diff -u --recursive --new-file v2.3.8/linux/fs/sysv/truncate.c linux/fs/sysv/truncate.c
--- v2.3.8/linux/fs/sysv/truncate.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/sysv/truncate.c	Tue Jun 29 09:22:08 1999
@@ -36,7 +36,7 @@
  */
 
 #define DATA_BUFFER_USED(bh) \
-	((bh->b_count > 1) || buffer_locked(bh))
+	(atomic_read(&bh->b_count) || buffer_locked(bh))
 
 /* We throw away any data beyond inode->i_size. */
 
diff -u --recursive --new-file v2.3.8/linux/fs/ufs/dir.c linux/fs/ufs/dir.c
--- v2.3.8/linux/fs/ufs/dir.c	Fri Apr 23 21:20:38 1999
+++ linux/fs/ufs/dir.c	Sun Jun 27 10:10:41 1999
@@ -55,10 +55,8 @@
 
 	while (!error && !stored && filp->f_pos < inode->i_size) {
 		lblk = (filp->f_pos) >> sb->s_blocksize_bits;
-		/* XXX - ufs_bmap() call needs error checking */
-		blk = ufs_bmap(inode, lblk);
-		bh = bread (sb->s_dev, blk, sb->s_blocksize);
-		if (!bh) {
+		blk = ufs_frag_map(inode, lblk);
+		if (!blk || !(bh = bread (sb->s_dev, blk, sb->s_blocksize))) {
 			/* XXX - error - skip to the next block */
 			printk("ufs_readdir: "
 			       "dir inode %lu has a hole at offset %lu\n",
@@ -209,10 +207,12 @@
 	ufs_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	ufs_permission,		/* permission */
 	NULL,			/* smap */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.3.8/linux/fs/ufs/file.c linux/fs/ufs/file.c
--- v2.3.8/linux/fs/ufs/file.c	Sat Jun 19 12:15:14 1999
+++ linux/fs/ufs/file.c	Sun Jun 27 10:10:41 1999
@@ -87,49 +87,23 @@
 	}
 }
 
-static int ufs_writepage (struct file *file, struct page *page)
-{
-	struct dentry *dentry = file->f_dentry;
-	struct inode *inode = dentry->d_inode;
-	unsigned long block;
-	int *p, nr[PAGE_SIZE/512];
-	int i, err, created;
-	struct buffer_head *bh;
-
-	i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
-	block = page->offset >> inode->i_sb->s_blocksize_bits;
-	p = nr;
-	bh = page->buffers;
-	do {
-		if (bh && bh->b_blocknr)
-			*p = bh->b_blocknr;
-		else
-			*p = ufs_getfrag_block(inode, block, 1, &err, &created);
-		if (!*p)
-			return -EIO;
-		i--;
-		block++;
-		p++;
-		if (bh)
-			bh = bh->b_this_page;
-	} while (i > 0);
-
-	brw_page(WRITE, page, inode->i_dev, nr, inode->i_sb->s_blocksize, 1);
-	return 0;
-}
-
-static long ufs_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char *buf)
-{
-	return block_write_one_page(file, page, offset, bytes, buf, ufs_getfrag_block);
-}
-
 /*
  * Write to a file (through the page cache).
  */
 static ssize_t
 ufs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-	return generic_file_write(file, buf, count, ppos, ufs_write_one_page);
+	ssize_t retval;
+
+	retval = generic_file_write(file, buf, count,
+				    ppos, block_write_partial_page);
+	if (retval > 0) {
+		struct inode *inode = file->f_dentry->d_inode;
+		remove_suid(inode);
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+		mark_inode_dirty(inode);
+	}
+	return retval;
 }
 
 /*
@@ -176,12 +150,12 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
-	ufs_writepage,		/* writepage */
-	ufs_bmap,		/* bmap */
+	ufs_getfrag_block,	/* get_block */
+	block_read_full_page,	/* readpage */
+	block_write_full_page,	/* writepage */
+	block_flushpage,	/* flushpage */
 	ufs_truncate,		/* truncate */
 	NULL, 			/* permission */
 	NULL,			/* smap */
-	NULL,			/* revalidate */
-	block_flushpage,	/* flushpage */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.3.8/linux/fs/ufs/inode.c linux/fs/ufs/inode.c
--- v2.3.8/linux/fs/ufs/inode.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/ufs/inode.c	Sun Jun 27 10:10:41 1999
@@ -36,6 +36,7 @@
 #include <linux/string.h>
 #include <linux/locks.h>
 #include <linux/mm.h>
+#include <linux/smp_lock.h>
 
 #include "swab.h"
 #include "util.h"
@@ -82,10 +83,10 @@
 #define ufs_inode_bmap(inode, nr) \
 	(SWAB32((inode)->u.ufs_i.i_u1.i_data[(nr) >> uspi->s_fpbshift]) + ((nr) & uspi->s_fpbmask))
 
-static inline unsigned ufs_block_bmap (struct buffer_head * bh, unsigned nr, 
+static inline unsigned int ufs_block_bmap (struct buffer_head * bh, unsigned nr, 
 	struct ufs_sb_private_info * uspi, unsigned swab)
 {
-	unsigned tmp;
+	unsigned int tmp;
 
 	UFSD(("ENTER, nr %u\n", nr))
 	if (!bh)
@@ -96,86 +97,90 @@
 	return tmp;
 }
 
-int ufs_bmap (struct inode * inode, int fragment)
+int ufs_frag_map(struct inode *inode, int frag)
 {
-	struct super_block * sb;
-	struct ufs_sb_private_info * uspi;
-	unsigned tmp;
-	unsigned swab;
+	struct super_block *sb;
+	struct ufs_sb_private_info *uspi;
+	unsigned int swab;
+	int i, ret;
+
+	ret = 0;
+	lock_kernel();
 	
 	sb = inode->i_sb;
 	uspi = sb->u.ufs_sb.s_uspi;
 	swab = sb->u.ufs_sb.s_swab;
-
-	UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
-	
-	if (fragment >= ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
-		ufs_warning (sb, "ufs_bmap", "block > big");
-		return 0;
+	if (frag < 0) {
+		ufs_warning(sb, "ufs_frag_map", "frag < 0");
+		goto out;
 	}
-
-	/*
-	 * direct fragment
-	 */
-	if (fragment < UFS_NDIR_FRAGMENT)
-		return (uspi->s_sbbase + ufs_inode_bmap (inode, fragment));
-
-	/*
-	 * indirect fragment
-	 */	
-	fragment -= UFS_NDIR_FRAGMENT;
-	if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
-		tmp = ufs_inode_bmap (inode, 
-			UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift));
-		if (!tmp)
-			return 0;
-		return (uspi->s_sbbase + 
-			ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
-			fragment & uspi->s_apbmask, uspi, swab));
+	if (frag >=
+	    ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb)
+	     << uspi->s_fpbshift)) {
+		ufs_warning(sb, "ufs_frag_map", "frag > big");
+		goto out;
 	}
 
-	/*
-	 * dindirect fragment
-	 */
-	fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
-	if (fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
-		tmp = ufs_inode_bmap (inode,
-			UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift));
-		if (!tmp)
-			return 0;
-		tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
-			(fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
-		if (!tmp)
-			return 0;
-		return (uspi->s_sbbase + 
-			ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
-			fragment & uspi->s_apbmask, uspi, swab));
+	if (frag < UFS_NDIR_FRAGMENT) {
+		ret = uspi->s_sbbase + ufs_inode_bmap(inode, frag);
+		goto out;
 	}
 
-	/*
-	 * tindirect fragment
-	 */
-	fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
-	tmp = ufs_inode_bmap (inode, 
-		UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift));
-	if (!tmp)
-		return 0;
-	tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
-		(fragment >> uspi->s_2apbshift) & uspi->s_apbmask, uspi, swab);
-	if (!tmp)
-		return 0;
-	tmp = ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
-		(fragment >> uspi->s_apbshift) & uspi->s_apbmask, uspi, swab);
-	if (!tmp)
-		return 0;
-	return (uspi->s_sbbase + 
-		ufs_block_bmap (bread (sb->s_dev, uspi->s_sbbase + tmp, sb->s_blocksize),
-		fragment & uspi->s_apbmask, uspi, swab));
+	frag -= UFS_NDIR_FRAGMENT;
+	if (frag < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+		i = ufs_inode_bmap(inode,
+				   UFS_IND_FRAGMENT + (frag >> uspi->s_apbshift));
+		if (!i)
+			goto out;
+		ret = (uspi->s_sbbase +
+		       ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
+					    sb->s_blocksize),
+				      frag & uspi->s_apbmask, uspi, swab));
+	}
+	frag -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+	if (frag < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+		i = ufs_inode_bmap (inode,
+				    UFS_DIND_FRAGMENT + (frag >> uspi->s_2apbshift));
+		if (!i)
+			goto out;
+		i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
+					 sb->s_blocksize),
+				   (frag >> uspi->s_apbshift) & uspi->s_apbmask,
+				   uspi, swab);
+		if (!i)
+			goto out;
+		ret = (uspi->s_sbbase +
+		       ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i,
+					    sb->s_blocksize),
+				      (frag & uspi->s_apbmask), uspi, swab));
+		goto out;
+	}
+	frag -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+	i = ufs_inode_bmap(inode,
+			   UFS_TIND_FRAGMENT + (frag >> uspi->s_3apbshift));
+	if (!i)
+		goto out;
+	i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
+			   (frag >> uspi->s_2apbshift) & uspi->s_apbmask,
+			   uspi, swab);
+	if (!i)
+		goto out;
+	i = ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
+			   (frag >> uspi->s_apbshift) & uspi->s_apbmask,
+			   uspi, swab);
+	if (!i)
+		goto out;
+	ret = (uspi->s_sbbase +
+	       ufs_block_bmap(bread(sb->s_dev, uspi->s_sbbase + i, sb->s_blocksize),
+			      (frag & uspi->s_apbmask), uspi, swab));
+out:
+	unlock_kernel();
+	return ret;
 }
 
-static struct buffer_head * ufs_inode_getfrag (struct inode * inode, 
-	unsigned fragment, unsigned new_fragment, int create, 
-	unsigned required, int *err, int metadata, int *phys_block, int *created)
+static struct buffer_head * ufs_inode_getfrag (struct inode *inode,
+	unsigned int fragment, unsigned int new_fragment,
+	unsigned int required, int *err, int metadata, long *phys, int *new)
 {
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
@@ -184,7 +189,7 @@
 	unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
 	unsigned tmp, goal;
 	u32 * p, * p2;
-	unsigned swab;
+	unsigned int swab;
 
 	UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
 		inode->i_ino, fragment, new_fragment, required))         
@@ -206,18 +211,17 @@
 					 sb->s_blocksize);
 			if (tmp == SWAB32(*p)) {
 				UFSD(("EXIT, result %u\n", tmp + blockoff))
-					return result;
+				return result;
 			}
 			brelse (result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
+			*phys = tmp;
 			return NULL;
 		}
 	}
 	*err = -EFBIG;
-	if (!create)
-		return NULL;
+
 	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	if (limit < RLIM_INFINITY) {
 		limit >>= sb->s_blocksize_bits;
@@ -226,6 +230,7 @@
 			return NULL;
 		}
 	}
+
 	lastblock = ufs_fragstoblks (lastfrag);
 	lastblockoff = ufs_fragnum (lastfrag);
 	/*
@@ -270,10 +275,10 @@
 	}
 	if (!tmp) {
 		if ((!blockoff && SWAB32(*p)) || 
-		(blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
+		    (blockoff && lastfrag != inode->u.ufs_i.i_lastfrag))
 			goto repeat;
-		else
-			return NULL;
+		*err = -ENOSPC;
+		return NULL;
 	}
 
 	/* The nullification of framgents done in ufs/balloc.c is
@@ -283,10 +288,10 @@
 	if (metadata) {
 		result = getblk (inode->i_dev, tmp + blockoff, sb->s_blocksize);
 	} else {
-		*phys_block = tmp;
+		*phys = tmp;
 		result = NULL;
 		*err = 0;
-		*created = 1;
+		*new = 1;
 	}
 
 	inode->i_ctime = CURRENT_TIME;
@@ -297,16 +302,16 @@
 	return result;
 }
 
-static struct buffer_head * ufs_block_getfrag (struct inode * inode,
-	struct buffer_head * bh, unsigned fragment, unsigned new_fragment, 
-	int create, unsigned blocksize, int * err, int metadata, int *phys_block, int *created)
+static struct buffer_head * ufs_block_getfrag (struct inode *inode,
+	struct buffer_head *bh, unsigned int fragment, unsigned int new_fragment, 
+	unsigned int blocksize, int * err, int metadata, long *phys, int *new)
 {
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct buffer_head * result;
 	unsigned tmp, goal, block, blockoff;
 	u32 * p;
-	unsigned swab;
+	unsigned int swab;
 
 	sb = inode->i_sb;
 	swab = sb->u.ufs_sb.s_swab;
@@ -316,15 +321,14 @@
 
 	UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u\n", inode->i_ino, fragment, new_fragment))	
 
+	result = NULL;
 	if (!bh)
-		return NULL;
+		goto out;
 	if (!buffer_uptodate(bh)) {
 		ll_rw_block (READ, 1, &bh);
 		wait_on_buffer (bh);
-		if (!buffer_uptodate(bh)) {
-			brelse (bh);
-			return NULL;
-		}
+		if (!buffer_uptodate(bh))
+			goto out;
 	}
 
 	p = (u32 *) bh->b_data + block;
@@ -334,24 +338,18 @@
 		if (metadata) {
 			result = getblk (bh->b_dev, uspi->s_sbbase + tmp + blockoff,
 					 sb->s_blocksize);
-			if (tmp == SWAB32(*p)) {
-				brelse (bh);
-				UFSD(("EXIT, result %u\n", tmp + blockoff))
-				return result;
-			}
+			if (tmp == SWAB32(*p))
+				goto out;
 			brelse (result);
 			goto repeat;
 		} else {
-			*phys_block = tmp;
-			brelse (bh);
-			return NULL;
+			*phys = tmp;
+			goto out;
 		}
 	}
 	*err = -EFBIG;
-	if (!create) {
-		brelse (bh);
-		return NULL;
-	} else {
+
+	{
 		unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 		if (limit < RLIM_INFINITY) {
 			limit >>= sb->s_blocksize_bits;
@@ -368,12 +366,9 @@
 		goal = bh->b_blocknr + uspi->s_fpb;
 	tmp = ufs_new_fragments (inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err);
 	if (!tmp) {
-		if (SWAB32(*p)) {
+		if (SWAB32(*p))
 			goto repeat;
-		} else {
-			brelse (bh);
-			return NULL;
-		}
+		goto out;
 	}		
 
 	/* The nullification of framgents done in ufs/balloc.c is
@@ -383,10 +378,8 @@
 	if (metadata) {
 		result = getblk (bh->b_dev, tmp + blockoff, sb->s_blocksize);
 	} else {
-		*phys_block = tmp;
-		result = NULL;
-		*err = 0;
-		*created = 1;
+		*phys = tmp;
+		*new = 1;
 	}
 
 	mark_buffer_dirty(bh, 1);
@@ -396,122 +389,137 @@
 	}
 	inode->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(inode);
+out:
 	brelse (bh);
 	UFSD(("EXIT, result %u\n", tmp + blockoff))
 	return result;
 }
 
-int ufs_getfrag_block (struct inode * inode, long fragment,
-		       int create, int * err, int *created)
+int ufs_getfrag_block (struct inode *inode, long fragment, struct buffer_head *bh_result, int create)
 {
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
-	struct buffer_head * bh, * tmp;
-	unsigned f;
-	unsigned swab;
-	int phys_block;
+	struct buffer_head * bh;
+	unsigned int swab;
+	int ret, err, new;
+	unsigned long ptr, phys;
 	
 	sb = inode->i_sb;
 	uspi = sb->u.ufs_sb.s_uspi;
 	swab = sb->u.ufs_sb.s_swab;
-	*err = -EIO;
 
-	UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
-	if (fragment < 0) {
-		ufs_warning (sb, "ufs_getblk", "block < 0");
-		return 0;
-	}
-	if (fragment > ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) {
-		ufs_warning (sb, "ufs_getblk", "block > big");
+	if (!create) {
+		phys = ufs_frag_map(inode, fragment);
+		if (phys) {
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_blocknr = phys;
+			bh_result->b_state |= (1UL << BH_Mapped);
+		}
 		return 0;
 	}
 
-	*err = -ENOSPC;
-	f = fragment;
-	*created = 0;
+	err = -EIO;
+	new = 0;
+	ret = 0;
+	bh = NULL;
+
+	lock_kernel();
+
+	UFSD(("ENTER, ino %lu, fragment %u\n", inode->i_ino, fragment))
+	if (fragment < 0)
+		goto abort_negative;
+	if (fragment >
+	    ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb)
+	     << uspi->s_fpbshift))
+		goto abort_too_big;
+
+	err = 0;
+	ptr = fragment;
 	  
 	/*
-	 * Direct fragment
+	 * ok, these macros clean the logic up a bit and make
+	 * it much more readable:
 	 */
-	if (fragment < UFS_NDIR_FRAGMENT) {
-		tmp = ufs_inode_getfrag (inode, fragment, fragment, create, 1,
-					 err, 0, &phys_block, created);
-		goto out;
-	}
-	/*
-	 * Indirect fragment
-	 */
-	fragment -= UFS_NDIR_FRAGMENT;
-	if (fragment < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
-		bh = ufs_inode_getfrag (inode, 
-			UFS_IND_FRAGMENT + (fragment >> uspi->s_apbshift),
-			f, create, uspi->s_fpb, err, 1, NULL, NULL);
-		tmp = ufs_block_getfrag (inode, bh, 
-					 fragment & uspi->s_apbmask,
-					 f, create, sb->s_blocksize,
-					 err, 0, &phys_block, created);
-		goto out;
-	}
-	/*
-	 * Dindirect fragment
-	 */
-	fragment -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
-	if ( fragment < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
-		bh = ufs_inode_getfrag (inode,
-			UFS_DIND_FRAGMENT + (fragment >> uspi->s_2apbshift),
-			f, create, uspi->s_fpb, err,
-			1, NULL, NULL);
-		bh = ufs_block_getfrag (inode, bh,
-			(fragment >> uspi->s_apbshift) & uspi->s_apbmask, 
-			f, create, sb->s_blocksize, err,
-			1, NULL, NULL);
-		tmp = ufs_block_getfrag (inode, bh, 
-			fragment & uspi->s_apbmask,
-			f, create, sb->s_blocksize, err,
-			0, &phys_block, created);
+#define GET_INODE_DATABLOCK(x) \
+		ufs_inode_getfrag(inode, x, fragment, 1, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+		ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+		ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
+				  &err, 0, &phys, &new);
+#define GET_INDIRECT_PTR(x) \
+		ufs_block_getfrag(inode, bh, x, fragment, sb->s_blocksize, \
+				  &err, 1, NULL, NULL);
+
+	if (ptr < UFS_NDIR_FRAGMENT) {
+		bh = GET_INODE_DATABLOCK(ptr);
 		goto out;
 	}
-	/*
-	 * Tindirect fragment
-	 */
-	fragment -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
-	bh = ufs_inode_getfrag (inode,
-		UFS_TIND_FRAGMENT + (fragment >> uspi->s_3apbshift), 
-		f, create, uspi->s_fpb, err, 1, NULL, NULL);
-	bh = ufs_block_getfrag (inode, bh,
-		(fragment >> uspi->s_2apbshift) & uspi->s_apbmask,
-		f, create, sb->s_blocksize, err, 1, NULL, NULL);
-	bh = ufs_block_getfrag (inode, bh,
-		(fragment >> uspi->s_apbshift) & uspi->s_apbmask, 
-		f, create, sb->s_blocksize, err, 1, NULL, NULL);
-	tmp = ufs_block_getfrag (inode, bh,
-		fragment & uspi->s_apbmask, 
-		f, create, sb->s_blocksize, err, 0, &phys_block, created);
+	ptr -= UFS_NDIR_FRAGMENT;
+	if (ptr < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
+		bh = GET_INODE_PTR(UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift));
+		goto get_indirect;
+	}
+	ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
+	if (ptr < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
+		bh = GET_INODE_PTR(UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift));
+		goto get_double;
+	}
+	ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
+	bh = GET_INODE_PTR(UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift));
+	bh = GET_INDIRECT_PTR((ptr >> uspi->s_2apbshift) & uspi->s_apbmask);
+get_double:
+	bh = GET_INDIRECT_PTR((ptr >> uspi->s_apbshift) & uspi->s_apbmask);
+get_indirect:
+	bh = GET_INDIRECT_DATABLOCK(ptr & uspi->s_apbmask);
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
 
 out:
-	if (!phys_block)
-		return 0;
-	if (*err)
-		return 0;
-	return phys_block;
+	if (err)
+		goto abort;
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = phys;
+	bh_result->b_state |= (1UL << BH_Mapped);
+	if (new)
+		bh_result->b_state |= (1UL << BH_New);
+abort:
+	unlock_kernel();
+	return err;
+
+abort_negative:
+	ufs_warning(sb, "ufs_get_block", "block < 0");
+	goto abort;
+
+abort_too_big:
+	ufs_warning(sb, "ufs_get_block", "block > big");
+	goto abort;
 }
 
 struct buffer_head *ufs_getfrag(struct inode *inode, unsigned int fragment,
 				int create, int *err)
 {
-	struct buffer_head *tmp = NULL;
-	int phys_block, created;
+	struct buffer_head dummy;
+	int error;
 
-	phys_block = ufs_getfrag_block(inode, fragment, create, err, &created);
-	if (phys_block) {
-		tmp = getblk(inode->i_dev, phys_block, inode->i_sb->s_blocksize);
-		if (created) {
-			memset(tmp->b_data, 0, inode->i_sb->s_blocksize);
-			mark_buffer_uptodate(tmp, 1);
-			mark_buffer_dirty(tmp, 1);
+	dummy.b_state = 0;
+	dummy.b_blocknr = -1000;
+	error = ufs_getfrag_block(inode, fragment, &dummy, create);
+	*err = error;
+	if (!error && buffer_mapped(&dummy)) {
+		struct buffer_head *bh;
+		bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+		if (buffer_new(&dummy)) {
+			memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+			mark_buffer_uptodate(bh, 1);
+			mark_buffer_dirty(bh, 1);
 		}
+		return bh;
 	}
-	return tmp;
+	return NULL;
 }
 
 struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment,
diff -u --recursive --new-file v2.3.8/linux/fs/ufs/super.c linux/fs/ufs/super.c
--- v2.3.8/linux/fs/ufs/super.c	Tue Jun  8 10:47:58 1999
+++ linux/fs/ufs/super.c	Tue Jun 29 09:12:32 1999
@@ -271,6 +271,8 @@
 				ufs_set_opt (*mount_options, UFSTYPE_44BSD);
 			else if (!strcmp (value, "nextstep"))
 				ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP);
+			else if (!strcmp (value, "nextstep-cd"))
+				ufs_set_opt (*mount_options, UFSTYPE_NEXTSTEP_CD);
 			else if (!strcmp (value, "openstep"))
 				ufs_set_opt (*mount_options, UFSTYPE_OPENSTEP);
 			else if (!strcmp (value, "sunx86"))
@@ -465,7 +467,7 @@
 	}
 	if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) {
 		printk("You didn't specify the type of your ufs filesystem\n\n"
-		"       mount -t ufs -o ufstype=sun|sunx86|44bsd|old|nextstep|openstep ....\n\n"
+		"       mount -t ufs -o ufstype=sun|sunx86|44bsd|old|nextstep|netxstep-cd|openstep ...\n\n"
 		">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
 		"default is ufstype=old\n");
 		ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD);
@@ -535,6 +537,20 @@
 		}
 		break;
 	
+	case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD:
+		UFSD(("ufstype=nextstep-cd\n"))
+		uspi->s_fsize = block_size = 2048;
+		uspi->s_fmask = ~(2048 - 1);
+		uspi->s_fshift = 11;
+		uspi->s_sbsize = super_block_size = 2048;
+		uspi->s_sbbase = 0;
+		flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
+		if (!(sb->s_flags & MS_RDONLY)) {
+			printk(KERN_INFO "ufstype=nextstep-cd is supported read-only\n");
+			sb->s_flags |= MS_RDONLY;
+		}
+		break;
+	
 	case UFS_MOUNT_UFSTYPE_OPENSTEP:
 		UFSD(("ufstype=openstep\n"))
 		uspi->s_fsize = block_size = 1024;
@@ -592,6 +608,7 @@
 #endif
 
 	if ((((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP) 
+	  || ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_NEXTSTEP_CD) 
 	  || ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == UFS_MOUNT_UFSTYPE_OPENSTEP)) 
 	  && uspi->s_sbbase < 256) {
 		ubh_brelse_uspi(uspi);
@@ -616,8 +633,8 @@
 		printk("ufs_read_super: fs_bsize %u != {4096, 8192}\n", uspi->s_bsize);
 		goto failed;
 	}
-	if (uspi->s_fsize != 512 && uspi->s_fsize != 1024) {
-		printk("ufs_read_super: fs_fsize %u != {512, 1024}\n", uspi->s_fsize);
+	if (uspi->s_fsize != 512 && uspi->s_fsize != 1024 && uspi->s_fsize != 2048) {
+		printk("ufs_read_super: fs_fsize %u != {512, 1024, 2048}\n", uspi->s_fsize);
 		goto failed;
 	}
 	if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) {
diff -u --recursive --new-file v2.3.8/linux/fs/ufs/symlink.c linux/fs/ufs/symlink.c
--- v2.3.8/linux/fs/ufs/symlink.c	Thu Jan 14 10:31:41 1999
+++ linux/fs/ufs/symlink.c	Sun Jun 27 10:10:41 1999
@@ -129,10 +129,12 @@
 	NULL,			/* rename */
 	ufs_readlink,		/* readlink */
 	ufs_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
-	NULL			/* smap */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.3.8/linux/fs/ufs/truncate.c linux/fs/ufs/truncate.c
--- v2.3.8/linux/fs/ufs/truncate.c	Wed Jun 16 19:26:27 1999
+++ linux/fs/ufs/truncate.c	Tue Jun 29 09:22:08 1999
@@ -63,7 +63,7 @@
 #define DIRECT_FRAGMENT howmany (inode->i_size, uspi->s_fsize)
 
 #define DATA_BUFFER_USED(bh) \
-	((bh->b_count > 1) || buffer_locked(bh))
+	(atomic_read(&bh->b_count) || buffer_locked(bh))
 
 static int ufs_trunc_direct (struct inode * inode)
 {
diff -u --recursive --new-file v2.3.8/linux/fs/ufs/util.c linux/fs/ufs/util.c
--- v2.3.8/linux/fs/ufs/util.c	Tue Jun  1 23:25:47 1999
+++ linux/fs/ufs/util.c	Tue Jun 29 09:22:08 1999
@@ -137,8 +137,8 @@
 	if (!ubh)
 		return 0;
 	for ( i = 0; i < ubh->count; i++ ) 
-		if ( ubh->bh[i]->b_count > max )
-			max = ubh->bh[i]->b_count;
+		if ( atomic_read(&ubh->bh[i]->b_count) > max )
+			max = atomic_read(&ubh->bh[i]->b_count);
 	return max;
 }
 
diff -u --recursive --new-file v2.3.8/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.3.8/linux/fs/umsdos/dir.c	Sat Jun 19 11:45:28 1999
+++ linux/fs/umsdos/dir.c	Sun Jun 27 10:10:41 1999
@@ -832,9 +832,10 @@
 	UMSDOS_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* followlink */
-	generic_readpage,	/* readpage */
+	fat_bmap,		/* get_block */
+	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
-	fat_bmap,		/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- v2.3.8/linux/fs/umsdos/file.c	Fri Sep 11 11:26:56 1998
+++ linux/fs/umsdos/file.c	Sun Jun 27 10:10:41 1999
@@ -99,12 +99,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow_link */
-	generic_readpage,	/* readpage */
+	fat_bmap,		/* get_block */
+	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
-	fat_bmap,		/* bmap */
+	NULL,			/* flushpage */
 	UMSDOS_truncate,	/* truncate */
 	NULL,			/* permission */
-	fat_smap		/* smap */
+	fat_smap,		/* smap */
+	NULL			/* revalidate */
 };
 
 /* For other with larger and unaligned file system */
@@ -137,12 +139,14 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	UMSDOS_truncate,	/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 /* For other with larger and unaligned file system with readpage */
@@ -175,10 +179,12 @@
 	NULL,			/* rename */
 	NULL,			/* readlink */
 	NULL,			/* follow link */
+	NULL,			/* get_block */
 	fat_readpage,		/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	UMSDOS_truncate,	/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
+	NULL			/* revalidate */
 };
diff -u --recursive --new-file v2.3.8/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.3.8/linux/fs/umsdos/rdir.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/umsdos/rdir.c	Sun Jun 27 10:10:41 1999
@@ -249,7 +249,7 @@
 	NULL,			/* followlink */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c
--- v2.3.8/linux/fs/umsdos/symlink.c	Sat Jun 19 11:45:29 1999
+++ linux/fs/umsdos/symlink.c	Sun Jun 27 10:10:41 1999
@@ -135,9 +135,10 @@
 	NULL,			/* rename */
 	UMSDOS_readlink,	/* readlink */
 	UMSDOS_followlink,	/* followlink */
-	generic_readpage,	/* readpage */
+	fat_bmap,		/* get_block */
+	block_read_full_page,	/* readpage */
 	NULL,			/* writepage */
-	fat_bmap,		/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
 	NULL,			/* permission */
 	NULL,			/* smap */
diff -u --recursive --new-file v2.3.8/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.3.8/linux/fs/vfat/namei.c	Thu May 13 23:18:21 1999
+++ linux/fs/vfat/namei.c	Sun Jun 27 10:10:41 1999
@@ -1232,11 +1232,14 @@
 	vfat_rename,		/* rename */
 	NULL,			/* readlink */
 	NULL,			/* followlink */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
 struct super_block *vfat_read_super(struct super_block *sb,void *data,
diff -u --recursive --new-file v2.3.8/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.3.8/linux/include/asm-alpha/pgtable.h	Mon May 10 09:55:21 1999
+++ linux/include/asm-alpha/pgtable.h	Fri Jun 25 17:36:12 1999
@@ -299,7 +299,7 @@
 
 #define BAD_PAGETABLE	__bad_pagetable()
 #define BAD_PAGE	__bad_page()
-#define ZERO_PAGE	(PAGE_OFFSET+0x30A000)
+#define ZERO_PAGE(vaddr)	(PAGE_OFFSET+0x30A000)
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR			(8*sizeof(unsigned long))
diff -u --recursive --new-file v2.3.8/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.3.8/linux/include/asm-arm/arch-ebsa285/irq.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Wed Jun 30 11:24:55 1999
@@ -10,6 +10,7 @@
  *  26-Jan-1999	PJB	Don't use IACK on CATS
  *  16-Mar-1999	RMK	Added autodetect of ISA PICs
  */
+#include <linux/config.h>
 #include <asm/hardware.h>
 #include <asm/dec21285.h>
 #include <asm/irq.h>
diff -u --recursive --new-file v2.3.8/linux/include/asm-arm/arch-ebsa285/memory.h linux/include/asm-arm/arch-ebsa285/memory.h
--- v2.3.8/linux/include/asm-arm/arch-ebsa285/memory.h	Thu Jun 17 01:11:35 1999
+++ linux/include/asm-arm/arch-ebsa285/memory.h	Wed Jun 30 11:24:55 1999
@@ -15,6 +15,8 @@
 #ifndef __ASM_ARCH_MMU_H
 #define __ASM_ARCH_MMU_H
 
+#include <linux/config.h>
+
 #if defined(CONFIG_HOST_FOOTBRIDGE)
 
 /*
diff -u --recursive --new-file v2.3.8/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h
--- v2.3.8/linux/include/asm-arm/proc-armo/pgtable.h	Sat May  8 11:06:57 1999
+++ linux/include/asm-arm/proc-armo/pgtable.h	Fri Jun 25 17:36:12 1999
@@ -173,7 +173,7 @@
 
 #define BAD_PAGETABLE __bad_pagetable()
 #define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
+#define ZERO_PAGE(vaddr) ((unsigned long) empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
 #define BYTES_PER_PTR			(sizeof(unsigned long))
diff -u --recursive --new-file v2.3.8/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.3.8/linux/include/asm-arm/proc-armv/pgtable.h	Sat May  8 11:06:58 1999
+++ linux/include/asm-arm/proc-armv/pgtable.h	Fri Jun 25 17:36:12 1999
@@ -187,7 +187,7 @@
 
 #define BAD_PAGETABLE	__bad_pagetable()
 #define BAD_PAGE	__bad_page()
-#define ZERO_PAGE	((unsigned long) empty_zero_page)
+#define ZERO_PAGE(vaddr)	((unsigned long) empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
 #define BYTES_PER_PTR	(sizeof(unsigned long))
diff -u --recursive --new-file v2.3.8/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.3.8/linux/include/asm-i386/pgtable.h	Tue Jun 22 14:41:43 1999
+++ linux/include/asm-i386/pgtable.h	Wed Jun 30 12:42:44 1999
@@ -286,7 +286,7 @@
 
 #define BAD_PAGETABLE __bad_pagetable()
 #define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
+#define ZERO_PAGE(vaddr) ((unsigned long) empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR			(8*sizeof(unsigned long))
diff -u --recursive --new-file v2.3.8/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.3.8/linux/include/asm-m68k/pgtable.h	Tue May 11 09:57:14 1999
+++ linux/include/asm-m68k/pgtable.h	Fri Jun 25 17:36:12 1999
@@ -398,7 +398,7 @@
 
 #define BAD_PAGETABLE __bad_pagetable()
 #define BAD_PAGE __bad_page()
-#define ZERO_PAGE empty_zero_page
+#define ZERO_PAGE(vaddr) empty_zero_page
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR			(8*sizeof(unsigned long))
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/baget/baget.h linux/include/asm-mips/baget/baget.h
--- v2.3.8/linux/include/asm-mips/baget/baget.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/baget/baget.h	Fri Jun 25 17:37:52 1999
@@ -0,0 +1,69 @@
+/* $Id$
+ * baget.h: Definitions specific to Baget/MIPS machines.
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+#ifndef _MIPS_BAGET_H
+#define _MIPS_BAGET_H
+
+#include "vic.h"
+#include "vac.h"
+
+#define VIC_BASE         0xBFFC0000 
+#define VAC_BASE         0xBFFD0000
+
+
+/* Baget interrupt registers and their sizes */
+
+struct  baget_int_reg { 
+	unsigned long address;
+	int size;  /* in bytes */
+};
+#define BAGET_INT_NONE   {0,0}
+
+#define BAGET_INT0_ACK   {0xbffa0003,1}
+#define BAGET_INT1_ACK   {0xbffa0008,4}
+#define BAGET_INT5_ACK   {0xbff00000,1}
+
+#define BAGET_WRERR_ACK  ((volatile char*)0xbff00000)
+
+
+/* Baget address spaces */
+
+#define BAGET_A24M_BASE       0xFC000000      /* VME-master A24 base address  */
+#define BAGET_A24S_BASE       0x00000000      /* VME-slave A24 base address   */
+#define BAGET_A24S_MASK       0x00c00000      /* VME-slave A24 address mask   */
+#define BAGET_GSW_BASE        0xf000          /* global switches address base */
+#define BAGET_MSW_BASE(P) (0xe000+(P)*0x100)  /* module switches address base */
+
+#define BAGET_LED_BASE  ((volatile short *)(0xbffd0000 + 0x00001800))
+
+#define BAGET_PIL_NR            8
+#define BAGET_IRQ_NR            NR_IRQS /* 64 */
+#define BAGET_IRQ_MASK(x)       ((NR_IRQS-1) & (x))
+
+#define BAGET_FPU_IRQ           0x26
+#define BAGET_VIC_TIMER_IRQ     0x32 
+#define BAGET_VAC_TIMER_IRQ     0x36 
+#define BAGET_BSM_IRQ           0x3C
+
+#define BAGET_LANCE_MEM_BASE    0xfcf10000
+#define BAGET_LANCE_MEM_SIZE    0x10000
+#define BAGET_LANCE_IO_BASE     0xbffeff00
+
+#define BALO_OFFSET     0x400000 /* sync with ld.script.balo  */
+#define BALO_SIZE       0x200000 /* sync with image segs size */
+
+/* move it to the right place, somehere in include/asm */
+#define CAUSE_DBE       0x1C
+#define CAUSE_MASK      0x7C
+
+/* Simple debug fascilities */
+extern void outc(char);
+extern void outs(char *);
+extern void baget_write(char *s, int l);
+extern int  baget_printk(const char *, ...);
+extern void balo_printf( char *f, ... );
+extern void balo_hungup(void);
+
+#endif /* !(_MIPS_BAGET_H) */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/baget/vac.h linux/include/asm-mips/baget/vac.h
--- v2.3.8/linux/include/asm-mips/baget/vac.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/baget/vac.h	Fri Jun 25 17:37:52 1999
@@ -0,0 +1,209 @@
+/* $Id$
+ *
+ * vac.h: Various VIC controller defines.  The VIC is a VME controller
+ *        used in Baget/MIPS series.
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+#ifndef _MIPS_VAC_H
+#define _MIPS_VAC_H
+
+#define VAC_SLSEL1_MASK      0x000
+#define VAC_SLSEL1_BASE      0x100
+#define VAC_SLSEL0_MASK      0x200
+#define VAC_SLSEL0_BASE      0x300
+#define VAC_ICFSEL_BASE      0x400
+#define VAC_ICFSEL_GLOBAL_VAL(x) (((x)>>8)&0xff)
+#define VAC_ICFSEL_MODULE_VAL(x) ((x)&0xff)
+#define VAC_DRAM_MASK        0x500
+#define VAC_BNDR2            0x600
+#define VAC_BNDR3            0x700
+#define VAC_A24_BASE         0x800
+#define    VAC_A24_MASK          (0x3f<<9)
+#define    VAC_A24_D32_ENABLE    (1<<8)
+#define    VAC_A24_A24_CACHINH   (1<<7)
+#define    VAC_A24_A16D32_ENABLE (1<<6)  
+#define    VAC_A24_A16D32        (1<<5)  
+#define    VAC_A24_DATAPATH      (1<<4)
+#define    VAC_A24_IO_CACHINH    (1<<3)
+#define VAC_REG1             0x900
+#define VAC_REG2             0xA00
+#define VAC_REG3             0xB00
+#define    VAC_REG_WORD      (1<<15)
+#define    VAC_REG_ASIZ1     (1<<14)
+#define    VAC_REG_ASIZ0     (1<<13)
+#define    VAC_REG_ASIZ_VAL(x) (((x)>>13)&3)
+#define    VAC_REG_CACHINH   (1<<12)
+#define    VAC_REG_INACTIVE  (0<<10)
+#define    VAC_REG_SHARED    (1<<10)
+#define    VAC_REG_VSB       (2<<10)
+#define    VAC_REG_MWB       (3<<10)
+#define    VAC_REG_MASK      (3<<10)
+#define    VAC_REG_MODE(x)   (((x)>>10)&3)
+#define VAC_IOSEL4_CTRL      0xC00
+#define VAC_IOSEL5_CTRL      0xD00
+#define VAC_SHRCS_CTRL       0xE00
+#define VAC_EPROMCS_CTRL     0xF00
+#define VAC_IOSEL0_CTRL      0x1000
+#define VAC_IOSEL1_CTRL      0x1100
+#define VAC_IOSEL2_CTRL      0x1200
+#define VAC_IOSEL3_CTRL      0x1300
+#define    VAC_CTRL_IOWR               (1<<0)
+#define    VAC_CTRL_IORD               (1<<1)
+#define    VAC_CTRL_DELAY_IOSELI(x)    (((x)&3)<<2)
+#define    VAC_CTRL_DELAY_IOSELI_VAL(x) (((x)>>2)&3)
+#define    VAC_CTRL_DELAY_IOWR(x)      (((x)&3)<<4)
+#define    VAC_CTRL_DELAY_IOWR_VAL(x)  (((x)>>4)&3)
+#define    VAC_CTRL_DELAY_IORD(x)      (((x)&3)<<6)
+#define    VAC_CTRL_DELAY_IORD_VAL(x)  (((x)>>6)&3)
+#define    VAC_CTRL_RECOVERY_IOSELI(x) ((((x)-1)&7)<<8)
+#define    VAC_CTRL_RECOVERY_IOSELI_VAL(x) ((((x)>>8)&7)+1)
+#define    VAC_CTRL_DSACK0             (1<<11)
+#define    VAC_CTRL_DSACK1             (1<<12)
+#define    VAC_CTRL_DELAY_DSACKI(x)    ((((x)-1)&7)<<13)
+#define    VAC_CTRL_DELAY_DSACKI_VAL(x) ((((x)>>13)&7)+1)
+#define VAC_DECODE_CTRL      0x1400
+#define    VAC_DECODE_FPUCS   (1<<0)
+#define    VAC_DECODE_CPUCLK(x)  (((x)&3)<<1)
+#define    VAC_DECODE_CPUCLK_VAL(x) (((x)>>1)&3)
+#define    VAC_DECODE_RDR_SLSEL0 (1<<3)
+#define    VAC_DECODE_RDR_SLSEL1 (1<<4)
+#define    VAC_DECODE_DSACK   (1<<5)
+#define    VAC_DECODE_QFY_BNDR    (1<<6)
+#define    VAC_DECODE_QFY_ICFSEL  (1<<7)
+#define    VAC_DECODE_QFY_SLSEL1  (1<<8)
+#define    VAC_DECODE_QFY_SLSEL0  (1<<9)
+#define    VAC_DECODE_CMP_SLSEL1_LO  (1<<10)
+#define    VAC_DECODE_CMP_SLSEL1_HI  (1<<11)
+#define    VAC_DECODE_CMP_SLSEL1_VAL(x) (((x)>>10)&3)
+#define    VAC_DECODE_DRAMCS  (3<<12)
+#define    VAC_DECODE_SHRCS   (2<<12)
+#define    VAC_DECODE_VSBSEL  (1<<12)
+#define    VAC_DECODE_EPROMCS (0<<12)
+#define    VAC_DECODE_MODE_VAL(x) (((x)>>12)&3)
+#define    VAC_DECODE_QFY_DRAMCS  (1<<14)
+#define    VAC_DECODE_DSACKI  (1<<15)
+#define VAC_INT_STATUS       0x1500
+#define VAC_INT_CTRL         0x1600
+#define    VAC_INT_CTRL_TIMER_PIO11    (3<<0)
+#define    VAC_INT_CTRL_TIMER_PIO10    (2<<0)
+#define    VAC_INT_CTRL_TIMER_PIO7     (1<<0)
+#define    VAC_INT_CTRL_TIMER_DISABLE  (0<<0)
+#define    VAC_INT_CTRL_TIMER_MASK     (3<<0)
+#define    VAC_INT_CTRL_UART_B_PIO11   (3<<2)
+#define    VAC_INT_CTRL_UART_B_PIO10   (2<<2)
+#define    VAC_INT_CTRL_UART_B_PIO7    (1<<2)
+#define    VAC_INT_CTRL_UART_B_DISABLE (0<<2)
+#define    VAC_INT_CTRL_UART_A_PIO11   (3<<4)
+#define    VAC_INT_CTRL_UART_A_PIO10   (2<<4)
+#define    VAC_INT_CTRL_UART_A_PIO7    (1<<4)
+#define    VAC_INT_CTRL_UART_A_DISABLE (0<<4)
+#define    VAC_INT_CTRL_MBOX_PIO11     (3<<6)
+#define    VAC_INT_CTRL_MBOX_PIO10     (2<<6)
+#define    VAC_INT_CTRL_MBOX_PIO7      (1<<6)
+#define    VAC_INT_CTRL_MBOX_DISABLE   (0<<6)
+#define    VAC_INT_CTRL_PIO4_PIO11     (3<<8)
+#define    VAC_INT_CTRL_PIO4_PIO10     (2<<8)
+#define    VAC_INT_CTRL_PIO4_PIO7      (1<<8)
+#define    VAC_INT_CTRL_PIO4_DISABLE   (0<<8)
+#define    VAC_INT_CTRL_PIO7_PIO11     (3<<10)
+#define    VAC_INT_CTRL_PIO7_PIO10     (2<<10)
+#define    VAC_INT_CTRL_PIO7_PIO7      (1<<10)
+#define    VAC_INT_CTRL_PIO7_DISABLE   (0<<10)
+#define    VAC_INT_CTRL_PIO8_PIO11     (3<<12)
+#define    VAC_INT_CTRL_PIO8_PIO10     (2<<12)
+#define    VAC_INT_CTRL_PIO8_PIO7      (1<<12)
+#define    VAC_INT_CTRL_PIO8_DISABLE   (0<<12)
+#define    VAC_INT_CTRL_PIO9_PIO11     (3<<14)
+#define    VAC_INT_CTRL_PIO9_PIO10     (2<<14)
+#define    VAC_INT_CTRL_PIO9_PIO7      (1<<14)
+#define    VAC_INT_CTRL_PIO9_DISABLE   (0<<14)
+#define VAC_DEV_LOC          0x1700
+#define    VAC_DEV_LOC_IOSEL(x)   (1<<(x))
+#define VAC_PIO_DATA_OUT     0x1800
+#define VAC_PIO_PIN          0x1900
+#define VAC_PIO_DIRECTION    0x1A00
+#define    VAC_PIO_DIR_OUT(x)     (1<<(x))
+#define    VAC_PIO_DIR_IN(x)      (0<<(x))
+#define    VAC_PIO_DIR_FCIACK     (1<<14)
+#define VAC_PIO_FUNC         0x1B00
+#define    VAC_PIO_FUNC_UART_A_TX (1<<0)
+#define    VAC_PIO_FUNC_UART_A_RX (1<<1)
+#define    VAC_PIO_FUNC_UART_B_TX (1<<2)
+#define    VAC_PIO_FUNC_UART_B_RX (1<<3)
+#define    VAC_PIO_FUNC_IORD      (1<<4)
+#define    VAC_PIO_FUNC_IOWR      (1<<5)
+#define    VAC_PIO_FUNC_IOSEL3    (1<<6)
+#define    VAC_PIO_FUNC_IRQ7      (1<<7)
+#define    VAC_PIO_FUNC_IOSEL4    (1<<8)
+#define    VAC_PIO_FUNC_IOSEL5    (1<<9)
+#define    VAC_PIO_FUNC_IRQ10     (1<<10)
+#define    VAC_PIO_FUNC_IRQ11     (1<<11)
+#define    VAC_PIO_FUNC_OUT       (1<<12)
+#define    VAC_PIO_FUNC_IOSEL2    (1<<13)
+#define    VAC_PIO_FUNC_DELAY     (1<<14)
+#define    VAC_PIO_FUNC_FCIACK    (1<<15)
+#define VAC_CPU_CLK_DIV      0x1C00
+#define VAC_UART_A_MODE      0x1D00
+#define    VAC_UART_MODE_PARITY_ENABLE  (1<<15) /* Inversed in manual ? */
+#define    VAC_UART_MODE_PARITY_ODD     (1<<14) /* Inversed in manual ? */
+#define    VAC_UART_MODE_8BIT_CHAR      (1<<13)
+#define    VAC_UART_MODE_BAUD(x)        (((x)&7)<<10)
+#define    VAC_UART_MODE_CHAR_RX_ENABLE (1<<9)
+#define    VAC_UART_MODE_CHAR_TX_ENABLE (1<<8)
+#define    VAC_UART_MODE_TX_ENABLE      (1<<7)
+#define    VAC_UART_MODE_RX_ENABLE      (1<<6)
+#define    VAC_UART_MODE_SEND_BREAK     (1<<5)
+#define    VAC_UART_MODE_LOOPBACK       (1<<4)
+#define    VAC_UART_MODE_INITIAL        (VAC_UART_MODE_8BIT_CHAR | \
+                                         VAC_UART_MODE_TX_ENABLE | \
+                                         VAC_UART_MODE_RX_ENABLE | \
+                                         VAC_UART_MODE_CHAR_TX_ENABLE | \
+                                         VAC_UART_MODE_CHAR_RX_ENABLE | \
+                                         VAC_UART_MODE_BAUD(5)) /* 9600/4 */
+#define VAC_UART_A_TX        0x1E00
+#define VAC_UART_B_MODE      0x1F00
+#define VAC_UART_A_RX        0x2000
+#define    VAC_UART_RX_ERR_BREAK        (1<<10)
+#define    VAC_UART_RX_ERR_FRAME        (1<<9)
+#define    VAC_UART_RX_ERR_PARITY       (1<<8)
+#define    VAC_UART_RX_DATA_MASK        (0xff)
+#define VAC_UART_B_RX        0x2100
+#define VAC_UART_B_TX        0x2200
+#define VAC_UART_A_INT_MASK  0x2300
+#define    VAC_UART_INT_RX_READY        (1<<15)
+#define    VAC_UART_INT_RX_FULL         (1<<14)
+#define    VAC_UART_INT_RX_BREAK_CHANGE (1<<13)
+#define    VAC_UART_INT_RX_ERRS         (1<<12)
+#define    VAC_UART_INT_TX_READY        (1<<11)
+#define    VAC_UART_INT_TX_EMPTY        (1<<10)
+#define VAC_UART_B_INT_MASK  0x2400
+#define VAC_UART_A_INT_STATUS  0x2500
+#define    VAC_UART_STATUS_RX_READY        (1<<15)
+#define    VAC_UART_STATUS_RX_FULL         (1<<14)
+#define    VAC_UART_STATUS_RX_BREAK_CHANGE (1<<13)
+#define    VAC_UART_STATUS_RX_ERR_PARITY   (1<<12)
+#define    VAC_UART_STATUS_RX_ERR_FRAME    (1<<11)
+#define    VAC_UART_STATUS_RX_ERR_OVERRUN  (1<<10)
+#define    VAC_UART_STATUS_TX_READY        (1<<9)
+#define    VAC_UART_STATUS_TX_EMPTY        (1<<8)
+#define    VAC_UART_STATUS_INTS            (0xff<<8)
+#define VAC_UART_B_INT_STATUS  0x2600
+#define VAC_TIMER_DATA       0x2700
+#define VAC_TIMER_CTRL       0x2800
+#define    VAC_TIMER_ONCE      (1<<15)
+#define    VAC_TIMER_ENABLE    (1<<14)
+#define    VAC_TIMER_PRESCALE(x) (((x)&0x3F)<<8)
+#define VAC_ID               0x2900
+
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+#define vac_inb(p)    (*(volatile unsigned char *)(VAC_BASE + (p)))
+#define vac_outb(v,p) (*((volatile unsigned char *)(VAC_BASE + (p))) = v)
+#define vac_inw(p)    (*(volatile unsigned short*)(VAC_BASE + (p)))
+#define vac_outw(v,p) (*((volatile unsigned short*)(VAC_BASE + (p))) = v)
+
+#endif /* __LANGUAGE_ASSEMBLY__ */
+
+#endif /* !(_MIPS_VAC_H) */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/baget/vic.h linux/include/asm-mips/baget/vic.h
--- v2.3.8/linux/include/asm-mips/baget/vic.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/baget/vic.h	Fri Jun 25 17:37:52 1999
@@ -0,0 +1,193 @@
+/* $Id$
+ *
+ * vic.h: Various VIC controller defines.  The VIC is an interrupt controller
+ *        used in Baget/MIPS series.
+ *
+ * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
+ */
+#ifndef _MIPS_VIC_H
+#define _MIPS_VIC_H
+
+#define VIC_VME_II       0x3
+#define VIC_VME_INT1     0x7
+#define VIC_VME_INT2     0xB
+#define VIC_VME_INT3     0xF
+#define VIC_VME_INT4     0x13
+#define VIC_VME_INT5     0x17
+#define VIC_VME_INT6     0x1B
+#define VIC_VME_INT7     0x1F
+#define VIC_DMA_INT      0x23
+#define VIC_LINT1        0x27
+#define VIC_LINT2        0x2B
+#define VIC_LINT3        0x2F
+#define VIC_LINT4        0x33
+#define VIC_LINT5        0x37
+#define VIC_LINT6        0x3B
+#define VIC_LINT7        0x3F
+#define VIC_ICGS_INT     0x43
+#define VIC_ICMS_INT     0x47
+#define    VIC_INT_IPL(lev)  ((~(lev))&0x7)
+#define    VIC_INT_ACTIVE    (1<<3)
+#define    VIC_INT_AUTO      (0<<4)
+#define    VIC_INT_NOAUTO    (1<<4)
+#define    VIC_INT_LEVEL     (0<<5)
+#define    VIC_INT_EDGE      (1<<5)
+#define    VIC_INT_LOW       (0<<6)
+#define    VIC_INT_HIGH      (1<<6)
+#define    VIC_INT_ENABLE    (0<<7)
+#define    VIC_INT_DISABLE   (1<<7)
+#define    VIC_INT_SWITCH(x) (1<<(((x)&0x3)+4))
+#define VIC_ERR_INT      0x4B
+#define    VIC_ERR_INT_SYSFAIL_ACTIVE  (1<<3)
+#define    VIC_ERR_INT_SYSFAIL  (1<<4)
+#define    VIC_ERR_INT_TIMO     (1<<5)
+#define    VIC_ERR_INT_WRPOST   (1<<6)
+#define    VIC_ERR_INT_ACFAIL   (1<<7)
+#define VIC_ICGS_BASE    0x4F
+#define VIC_ICMS_BASE    0x53
+#define    VIC_ICxS_BASE_GSWITCH_MASK 0x3
+#define    VIC_ICxS_BASE_ID(x)  (((x)&0x3f)<<2)
+#define VIC_LOCAL_BASE   0x57
+#define    VIC_LOCAL_BASE_LINT_MASK 0x7
+#define    VIC_LOCAL_BASE_ID(x)  (((x)&0x1f)<<3)
+#define VIC_ERR_BASE     0x5B
+#define    VIC_ERR_BASE_ACFAIL   0
+#define    VIC_ERR_BASE_WRPOST   1
+#define    VIC_ERR_BASE_TIMO     2
+#define    VIC_ERR_BASE_SYSFAIL  3
+#define    VIC_ERR_BASE_VMEACK   4
+#define    VIC_ERR_BASE_DMA      5
+#define    VIC_ERR_BASE_ID(x)  (((x)&0x1f)<<3)
+#define VIC_ICS          0x5F
+#define VIC_IC0          0x63
+#define VIC_IC1          0x67
+#define VIC_IC2          0x6B
+#define VIC_IC3          0x6F
+#define VIC_IC4          0x73
+#define VIC_ID           0x77
+#define VIC_IC6          0x7B
+#define    VIC_IC6_IRESET_STATUS (1<<7)
+#define    VIC_IC6_HALT_STATUS   (1<<6)
+#define    VIC_IC6_SYSRESET   (3<<0)
+#define    VIC_IC6_RESET      (2<<0)
+#define    VIC_IC6_HALT       (1<<0)
+#define    VIC_IC6_RUN        (0<<0)
+#define VIC_IC7          0x7F
+#define    VIC_IC7_SYSFAIL     (1<<7)
+#define    VIC_IC7_RESET       (1<<6)
+#define    VIC_IC7_VME_MASTER  (1<<5)
+#define    VIC_IC7_SEMSET(x)   ((1<<(x))&0x1f)
+#define VIC_VME_REQ      0x83
+#define VIC_VME_BASE1    0x87
+#define VIC_VME_BASE2    0x8B
+#define VIC_VME_BASE3    0x8F
+#define VIC_VME_BASE4    0x93
+#define VIC_VME_BASE5    0x97
+#define VIC_VME_BASE6    0x9B
+#define VIC_VME_BASE7    0x9F
+#define VIC_XFER_TIMO    0xA3
+#define    VIC_XFER_TIMO_VME_PERIOD_INF (7<<5)
+#define    VIC_XFER_TIMO_VME_PERIOD_512 (6<<5)
+#define    VIC_XFER_TIMO_VME_PERIOD_256 (5<<5)
+#define    VIC_XFER_TIMO_VME_PERIOD_128 (4<<5)
+#define    VIC_XFER_TIMO_VME_PERIOD_64 (3<<5)
+#define    VIC_XFER_TIMO_VME_PERIOD_32 (2<<5)
+#define    VIC_XFER_TIMO_VME_PERIOD_16 (1<<5)
+#define    VIC_XFER_TIMO_VME_PERIOD_4  (0<<5)
+#define    VIC_XFER_TIMO_VME_PERIOD_VAL(x) (((x)>>5)&7)
+#define    VIC_XFER_TIMO_LOCAL_PERIOD_INF (7<<2)
+#define    VIC_XFER_TIMO_LOCAL_PERIOD_512 (6<<2)
+#define    VIC_XFER_TIMO_LOCAL_PERIOD_256 (5<<2)
+#define    VIC_XFER_TIMO_LOCAL_PERIOD_128 (4<<2)
+#define    VIC_XFER_TIMO_LOCAL_PERIOD_64 (3<<2)
+#define    VIC_XFER_TIMO_LOCAL_PERIOD_32 (2<<2)
+#define    VIC_XFER_TIMO_LOCAL_PERIOD_16 (1<<2)
+#define    VIC_XFER_TIMO_LOCAL_PERIOD_4  (0<<2)
+#define    VIC_XFER_TIMO_LOCAL_PERIOD_VAL(x) (((x)>>2)&7)
+#define    VIC_XFER_TIMO_ARB  (1<<1)
+#define    VIC_XFER_TIMO_VME  (1<<0)
+#define VIC_LOCAL_TIM    0xA7
+#define    VIC_LOCAL_TIM_PAS_ASSERT(x)   (((x)-2)&0xf)
+#define    VIC_LOCAL_TIM_PAS_ASSERT_VAL(x) (((x)&0xf)+2)
+#define    VIC_LOCAT_TIM_DS_DEASSERT(x)  ((((x)-1)&1)<<4)
+#define    VIC_LOCAT_TIM_DS_DEASSERT_VAL(x)  ((((x)>>4)&1)+1)
+#define    VIC_LOCAL_TIM_PAS_DEASSERT(x) ((((x)-1)&0x7)<<5)
+#define    VIC_LOCAL_TIM_PAS_DEASSERT_VAL(x) ((((x)>>5)&0x7)+1)
+#define VIC_BXFER_DEF    0xAB
+#define    VIC_BXFER_DEF_VME_CROSS    (1<<3)
+#define    VIC_BXFER_DEF_LOCAL_CROSS  (1<<2)
+#define    VIC_BXFER_DEF_AMSR   (1<<1)
+#define    VIC_BXFER_DEF_DUAL   (1<<0)
+#define VIC_IFACE_CFG    0xAF
+#define    VIC_IFACE_CFG_RMC3    (1<<7)
+#define    VIC_IFACE_CFG_RMC2    (1<<6)
+#define    VIC_IFACE_CFG_RMC1    (1<<5)
+#define    VIC_IFACE_CFG_HALT    (1<<4)
+#define    VIC_IFACE_CFG_NOHALT  (0<<4)
+#define    VIC_IFACE_CFG_NORMC   (1<<3)
+#define    VIC_IFACE_CFG_DEADLOCK_VAL(x) (((x)>>3)&3)
+#define    VIC_IFACE_CFG_MSTAB   (1<<2)
+#define    VIC_IFACE_CFG_TURBO   (1<<1)
+#define    VIC_IFACE_CFG_NOTURBO (0<<1)
+#define    VIC_IFACE_CFG_VME     (1<<0)
+#define VIC_REQ_CFG      0xB3
+#define    VIC_REQ_CFG_FAIRNESS_DISABLED  0
+#define    VIC_REQ_CFG_FAIRNESS_ENABLED   1
+#define    VIC_REQ_CFG_TIMO_DISABLED      0xf
+#define    VIC_REQ_CFG_DRAM_REFRESH       (1<<4)
+#define    VIC_REQ_CFG_LEVEL(x)           (((x)&3)<<5)
+#define    VIC_REQ_CFG_PRIO_ARBITRATION   (1<<7)
+#define    VIC_REQ_CFG_RR_ARBITRATION     (0<<7)
+#define VIC_AMS          0xB7
+#define    VIC_AMS_AM_2_0   (1<<7)
+#define    VIC_AMS_AM_5_3   (1<<6)
+#define    VIC_AMS_CODE(x)  ((x)&0x1f)
+#define VIC_BERR_STATUS  0xBB
+#define VIC_DMA_STATUS   0xBF
+#define VIC_SS0CR0       0xC3
+#define VIC_SS1CR0       0xCB
+#define    VIC_SSxCR0_LOCAL_XFER_ACCEL  (2)
+#define    VIC_SSxCR0_LOCAL_XFER_SINGLE (1)
+#define    VIC_SSxCR0_LOCAL_XFER_NONE   (0)
+#define    VIC_SSxCR0_A32       (0<<2)
+#define    VIC_SSxCR0_A24       (1<<2)
+#define    VIC_SSxCR0_A16       (2<<2)
+#define    VIC_SSxCR0_USER      (3<<2)
+#define    VIC_SSxCR0_D32       (1<<4)
+#define    VIC_SSxCR0_SUPER     (1<<5)
+#define    VIC_SS0CR0_TIMER_FREQ_MASK   (3<<6)
+#define    VIC_SS0CR0_TIMER_FREQ_NONE   (0<<6)
+#define    VIC_SS0CR0_TIMER_FREQ_50HZ   (1<<6)
+#define    VIC_SS0CR0_TIMER_FREQ_1000HZ (2<<6)
+#define    VIC_SS0CR0_TIMER_FREQ_100HZ  (3<<6)
+#define    VIC_SS1CR0_MASTER_WRPOST (1<<6)
+#define    VIC_SS1CR0_SLAVE_WRPOST  (1<<7)
+#define VIC_SS0CR1       0xC7
+#define VIC_SS1CR1       0xCF
+#define    VIC_SSxCR1_TF2(x)  (((x)&0xf)<<4)
+#define    VIC_SSxCR1_TF1(x)  ((x)&0xf)
+#define VIC_RELEASE      0xD3
+#define    VIC_RELEASE_BLKXFER_BLEN(x) ((x)&0x1f)
+#define    VIC_RELEASE_ROR             (0<<6) 
+#define    VIC_RELEASE_RWD             (1<<6) 
+#define    VIC_RELEASE_ROC             (2<<6) 
+#define    VIC_RELEASE_BCAP            (3<<6) 
+#define VIC_BXFER_CTRL   0xD7
+#define    VIC_BXFER_CTRL_MODULE     (1<<7)
+#define    VIC_BXFER_CTRL_LOCAL      (1<<6)
+#define    VIC_BXFER_CTRL_MOVEM      (1<<5)
+#define    VIC_BXFER_CTRL_READ       (1<<4)
+#define    VIC_BXFER_CTRL_WRITE      (0<<4)
+#define    VIC_BXFER_CTRL_INTERLEAVE(x)  ((x)&0xf)
+#define VIC_BXFER_LEN_LO    0xDB
+#define VIC_BXFER_LEN_HI    0xDF
+#define VIC_SYS_RESET    0xE3
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+#define vic_inb(p)    (*(volatile unsigned char *)(VIC_BASE + (p)))
+#define vic_outb(v,p) (*((volatile unsigned char *)(VIC_BASE + (p))) = v)
+
+#endif /* __LANGUAGE_ASSEMBLY__ */
+
+#endif /* !(_MIPS_VIC_H) */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/bootinfo.h linux/include/asm-mips/bootinfo.h
--- v2.3.8/linux/include/asm-mips/bootinfo.h	Tue Oct 20 13:52:53 1998
+++ linux/include/asm-mips/bootinfo.h	Fri Jun 25 17:37:52 1999
@@ -25,10 +25,10 @@
 #define MACH_GROUP_SNI_RM	4 /* Siemens Nixdorf RM series                */
 #define MACH_GROUP_ACN		5
 #define MACH_GROUP_SGI          6 /* Silicon Graphics workstations and servers */
-#define MACH_GROUP_RESERVED     7 /* No Such Architecture	 	      */
+#define MACH_GROUP_COBALT       7 /* Cobalt servers		 	      */
 
 #define GROUP_NAMES { "unknown", "Jazz", "Digital", "ARC", \
-                      "SNI", "ACN", "SGI", "NSA" }
+                      "SNI", "ACN", "SGI", "Cobalt" }
 
 /*
  * Valid machtype values for group unknown (low order halfword of mips_machtype)
@@ -49,11 +49,21 @@
 /*
  * Valid machtype for group DEC 
  */
-/* FIXME: this is a very fuzzy name, and we got a big "name space now" */
-/* So otiginal DEC codes can be used -Stoned */
-#define MACH_DECSTATION		0	/* DECStation 5000/2x for now */
-
-#define GROUP_DEC_NAMES { "3min" }
+#define MACH_DSUNKNOWN		0
+#define MACH_DS23100		1	/* DECstation 2100 or 3100	*/
+#define MACH_DS5100		2	/* DECstation 5100		*/
+#define MACH_DS5000_200		3	/* DECstation 5000/200		*/
+#define MACH_DS5000_1XX		4	/* DECstation 5000/120, 125, 133, 150 */
+#define MACH_DS5000_XX		5	/* DECstation 5000/20, 25, 33, 50 */
+#define MACH_DS5000_2X0		6	/* DECstation 5000/240, 260	*/
+#define MACH_DS5400		7	/* DECstation 5400		*/
+#define MACH_DS5500		8	/* DECstation 5500		*/
+#define MACH_DS5800		9	/* DECstation 5800		*/
+
+#define GROUP_DEC_NAMES { "unknown", "DECstation 2100/3100", "DECstation 5100", \
+	"DECstation 5000/200", "DECstation 5000/1xx", "Personal DECstation 5000/xx", \
+	"DECstation 5000/2x0", "DECstation 5400", "DECstation 5500", \
+	"DECstation 5800" }
 
 /*
  * Valid machtype for group ARC
@@ -85,6 +95,13 @@
 #define GROUP_SGI_NAMES { "Indy" }
 
 /*
+ * Valid machtype for group COBALT
+ */
+#define MACH_COBALT_27 		 0	/* Proto "27" hardware */
+
+#define GROUP_COBALT_NAMES { "Microserver 27" }
+
+/*
  * Valid cputype values
  */
 #define CPU_UNKNOWN		0
@@ -144,134 +161,14 @@
 	unsigned short lines;
 } mips_arc_DisplayInfo;
 
-/*
- * New style bootinfo
- *
- * Add new tags only at the end of the enum; *never* remove any tags
- * or you'll break compatibility!
- */
-enum bi_tag {
- 	/*
- 	 * not a real tag
- 	 */
-	tag_dummy,
- 
- 	/*
- 	 * machine type
- 	 */
-	tag_machtype,
- 
- 	/*
- 	 * system CPU & FPU
- 	 */
-	tag_cputype,
- 
- 	/*
- 	 * Installed RAM
- 	 */
-	tag_memlower,
-	tag_memupper,
- 
- 	/*
- 	 * Cache Sizes (0xffffffff = unknown)
- 	 */
-	tag_icache_size,
-	tag_icache_linesize,
-	tag_dcache_size,
-	tag_dcache_linesize,
-	tag_scache_size,
-	tag_scache_linesize,
- 
- 	/*
- 	 * TLB Info
- 	 */
-	tag_tlb_entries,
- 
- 	/*
- 	 * DMA buffer size (Deskstation only)
- 	 */
-	tag_dma_cache_size,
-	tag_dma_cache_base,
- 
- 	/*
-	 * Ramdisk Info 
- 	 */
-	tag_ramdisk_size,		/* ramdisk size in 1024 byte blocks */
-	tag_ramdisk_base,		/* address of the ram disk in mem */
- 
- 	/*
- 	 * Boot flags for the kernel
- 	 */
-	tag_mount_root_rdonly,
-	tag_drive_info,
- 
- 	/*
- 	 * Video ram info (not in tty.h)
- 	 */
-	tag_vram_base,			/* video ram base address */
-       
-	tag_command_line,		/* kernel command line parameters */
-
-        /*
-         * machine group
-         */
-	tag_machgroup,
-
-	/*
-	 * info on the display from the ARC BIOS
-	 */
-	tag_arcdisplayinfo,
-
-	/*
-	 * tag to pass a complete struct screen_info
-	 */
-	tag_screen_info
-};
-
-/* struct defining a tag */
-typedef struct {
-	enum bi_tag tag;
-	unsigned long size;
-} tag;
-
-/* struct to define a tag and it's data */
-typedef struct {
-	tag t;
-	void* d;
-} tag_def;
-
-/* macros for parsing tag list */
-#define TAGVALPTR(t) ((void*)(((void*)(t)) - ((t)->size)))
-#define NEXTTAGPTR(t) ((void*)(TAGVALPTR(t) - (sizeof(tag))))
-
-/* size macros for tag size field */
-#define UCHARSIZE (sizeof(unsigned char))
-#define ULONGSIZE (sizeof(unsigned long))
-#define UINTSIZE  (sizeof(unsigned int))
-#define DRVINFOSIZE (sizeof(struct drive_info_struct))
-#define CMDLINESIZE (sizeof(char[CL_SIZE])
-
-/*
- * For tag readers aka the kernel
- */
-tag *bi_TagFind(enum bi_tag type);
-void bi_EarlySnarf(void);
-
-/* For tag creators aka bootloaders */
-/* Now implemented in Milo 0.26 */
-int bi_TagAdd(enum bi_tag type, unsigned long size, void *data);
-int bi_TagAddList(tag_def* taglist);
-void bi_TagWalk(void); 
-
-
 #ifdef CONFIG_SGI
 /* screen info will dissapear... soon */
 //#define DEFAULT_SCREEN_INFO {0, 0, 0, 0, 0, 158, 0, 0, 0, 62, 0, 16}
 #define DEFAULT_SCREEN_INFO {0, 0, 0, 0, 0, 160, 0, 0, 0, 64, 0, 16}
 #define DEFAULT_DRIVE_INFO { {0,}}
 #else
-/* default values for screen_info variable */
-#define DEFAULT_SCREEN_INFO {0, 0, 0, 52, 3, 80, 4626, 3, 9, 50}
+/* default values for screen_info variable (Colour VGA) */
+#define DEFAULT_SCREEN_INFO {0, 0, 0, 52, 3, 80, 4626, 3, 9, 50, 0x22, 16}
 #endif
 
 /* default values for drive info */
@@ -289,9 +186,6 @@
 extern unsigned long mips_machtype;
 extern unsigned long mips_machgroup;
 extern unsigned long mips_tlb_entries;
-extern unsigned long mips_vram_base;
-extern unsigned long mips_dma_cache_size;
-extern unsigned long mips_dma_cache_base;
 
 #endif /* _LANGUAGE_ASSEMBLY */
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/byteorder.h linux/include/asm-mips/byteorder.h
--- v2.3.8/linux/include/asm-mips/byteorder.h	Tue Dec 16 12:45:55 1997
+++ linux/include/asm-mips/byteorder.h	Fri Jun 25 17:37:52 1999
@@ -1,7 +1,24 @@
+/* $Id: byteorder.h,v 1.7 1999/01/04 16:09:20 ralf Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) by Ralf Baechle
+ */
 #ifndef _MIPS_BYTEORDER_H
 #define _MIPS_BYTEORDER_H
 
 #include <asm/types.h>
+
+#ifdef __GNUC__
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+#  define __BYTEORDER_HAS_U64__
+#  define __SWAB_64_THRU_32__
+#endif
+
+#endif /* __GNUC__ */
 
 #if defined (__MIPSEB__)
 #  include <linux/byteorder/big_endian.h>
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/interrupts.h linux/include/asm-mips/dec/interrupts.h
--- v2.3.8/linux/include/asm-mips/dec/interrupts.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/interrupts.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,80 @@
+/*  
+ * Miscellaneous definitions used to initialise the interrupt vector table
+ * with the machine-specific interrupt routines.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1997 by Paul M. Antoine.
+ * reworked 1998 by Harald Koerfgen.
+ */
+
+#ifndef __ASM_DEC_INTERRUPTS_H 
+#define __ASM_DEC_INTERRUPTS_H 
+
+/*
+ * DECstation Interrupts
+ */
+
+/*
+ * This list reflects the priority of the Interrupts.
+ * Exception: on kmins we have to handle Memory Error 
+ * Interrupts before the TC Interrupts.
+ */
+#define CLOCK 	0
+#define SCSI_DMA_INT 	1
+#define SCSI_INT	2
+#define ETHER		3
+#define SERIAL		4
+#define TC0		5
+#define TC1		6
+#define TC2		7
+#define MEMORY		8
+#define FPU		9
+#define HALT		10
+
+#define NR_INTS	11
+
+#ifndef _LANGUAGE_ASSEMBLY
+/*
+ * Data structure to hide the differences between the DECstation Interrupts
+ *
+ * If asic_mask == NULL, the interrupt is directly handled by the CPU.
+ * Otherwise this Interrupt is handled the IRQ Controller.
+ */
+
+typedef struct
+{
+	unsigned int	cpu_mask;	/* checking and enabling interrupts in CP0	*/
+	unsigned int	iemask;		/* enabling interrupts in IRQ Controller	*/
+} decint_t;
+
+/*
+ * Interrupt table structure to hide differences between different
+ * systems such.
+ */
+extern void *cpu_ivec_tbl[8];
+extern long cpu_mask_tbl[8];
+extern long cpu_irq_nr[8];
+extern long asic_irq_nr[32];
+extern long asic_mask_tbl[32];
+
+/*
+ * Common interrupt routine prototypes for all DECStations
+ */
+extern void	dec_intr_unimplemented(void);
+extern void	dec_intr_fpu(void);
+extern void	dec_intr_rtc(void);
+
+extern void	kn02_io_int(void);
+extern void	kn02ba_io_int(void);
+extern void	kn03_io_int(void);
+
+extern void	intr_halt(void);
+
+extern void	asic_intr_unimplemented(void);
+
+#endif
+#endif 
+
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/ioasic_addrs.h linux/include/asm-mips/dec/ioasic_addrs.h
--- v2.3.8/linux/include/asm-mips/dec/ioasic_addrs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/ioasic_addrs.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,82 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Definitions for the address map in the JUNKIO Asic
+ *
+ * Created with Information from:
+ *
+ * "DEC 3000 300/400/500/600/700/800/900 AXP Models System Programmer's Manual"
+ *
+ * and the Mach Sources
+ */
+
+#ifndef IOASIC_ADDRS_H
+#define IOASIC_ADDRS_H
+
+#define CHUNK_SIZE 0x00040000
+
+#define SYSTEM_ROM 	00*CHUNK_SIZE 		/* ??? */
+#define IOCTL 		01*CHUNK_SIZE 
+#define ESAR 		02*CHUNK_SIZE 
+#define LANCE 		03*CHUNK_SIZE 
+#define SCC0 		04*CHUNK_SIZE 
+#define VDAC_HI		05*CHUNK_SIZE		/* maxine only */
+#define SCC1 		06*CHUNK_SIZE 
+#define VDAC_LO		07*CHUNK_SIZE		/* maxine only */
+#define TOY 		08*CHUNK_SIZE 
+#define ISDN 		09*CHUNK_SIZE		/* maxine only */
+#define ERRADDR		09*CHUNK_SIZE 		/* 3maxplus only */
+#define CHKSYN 		10*CHUNK_SIZE 		/* 3maxplus only */
+#define ACCESS_BUS	10*CHUNK_SIZE 		/* maxine only */
+#define MCR 		11*CHUNK_SIZE 		/* 3maxplus only */
+#define FLOPPY 		11*CHUNK_SIZE 		/* maxine only */
+#define SCSI 		12*CHUNK_SIZE
+#define FLOPPY_DMA 	13*CHUNK_SIZE 		/* maxine only */
+#define SCSI_DMA 	14*CHUNK_SIZE 
+#define RESERVED_4 	15*CHUNK_SIZE 
+
+/*
+ * Offsets for IOCTL registers (relative to (system_base + IOCTL))
+ */
+#define SCSI_DMA_P	0x00			/* SCSI DMA Pointer */
+#define SCSI_DMA_BP	0x10			/* SCSI DMA Buffer Pointer */
+#define LANCE_DMA_P	0x20			/* LANCE DMA Pointer */
+#define SCC0_T_DMA_P	0x30			/* Communication Port 1 Transmit DMA Pointer */
+#define SCC0_R_DMA_P	0x40			/* Communication Port 1 Receive DMA Pointer */
+#define SCC1_T_DMA_P	0x50			/* Communication Port 2 Transmit DMA Pointer */
+#define SCC1_R_DMA_P	0x60			/* Communication Port 2 Receive DMA Pointer */
+#define FLOPPY_DMA_P	0x70			/* Floppy DMA Pointer */
+#define ISDN_T_DMA_P	0x80			/* ISDN Transmit DMA Pointer */
+#define ISDN_T_DMA_BP	0x90			/* ISDN Transmit DMA Buffer Pointer */
+#define ISDN_R_DMA_P	0xa0			/* ISDN Receive DMA Pointer */
+#define ISDN_R_DMA_BP	0xb0			/* ISDN Receive DMA Buffer Pointer */
+
+#define SSR		0x100			/* System Support Register */
+#define SIR		0x110			/* System Interrupt Register */
+#define SIMR		0x120			/* System Interrupt Mask Register */
+
+/*
+ * Handle partial word SCSI DMA transfers
+ */
+#define	SCSI_SCR	0x1b0
+#define	SCSI_SDR0	0x1c0
+#define	SCSI_SDR1	0x1d0
+
+/*
+ * DMA defines for the System Support Register
+ */
+#define LANCE_DMA_EN	(1UL<<16)			/* LANCE DMA enable */
+#define SCSI_DMA_EN	(1UL<<17)			/* SCSI DMA enable */
+#define SCSI_DMA_DIR	(1UL<<18)			/* SCSI DMA direction */
+#define ISDN_REC_DMA_EN (1UL<<19)			/* ISDN receive DMA enable */
+#define ISDN_TRN_DMA_EN (1UL<<20)			/* ISDN transmit DMA enable */
+#define FLOPPY_DMA_EN	(1UL<<21)			/* Floppy DMA enable */
+#define FLOPPY_DMA_DIR	(1UL<<22)			/* Floppy DMA direction */
+#define SCC1A_DMA_EN	(1UL<<28)			/* SCC1 Channel A DMA enable */
+#define SCC1B_DMA_EN	(1UL<<29)			/* SCC1 Channel B DMA enable */
+#define SCC0A_DMA_EN	(1UL<<30)			/* SCC0 Channel A DMA enable */
+#define SCC0B_DMA_EN	(1UL<<31)			/* Scc0 Channel B DMA enable */
+
+#endif
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/ioasic_ints.h linux/include/asm-mips/dec/ioasic_ints.h
--- v2.3.8/linux/include/asm-mips/dec/ioasic_ints.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/ioasic_ints.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,109 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Definitions for the interrupt related bits in the JUNKIO Asic
+ * interrupt status register (and the interrupt mask register, of course)
+ *
+ * Created with Information from:
+ *
+ * "DEC 3000 300/400/500/600/700/800/900 AXP Models System Programmer's Manual"
+ *
+ * and the Mach Sources
+ */
+
+/* 
+ * the upper 16 bits are common to all JUNKIO machines
+ * (except the FLOPPY and ISDN bits, which are Maxine sepcific)
+ */
+#define SCC0_TRANS_PAGEEND	0x80000000	/* Serial DMA Errors	*/
+#define SCC0_TRANS_MEMRDERR	0x40000000	/* see below		*/
+#define SCC0_RECV_HALFPAGE	0x20000000
+#define	SCC0_RECV_PAGOVRRUN	0x10000000
+#define SCC1_TRANS_PAGEEND	0x08000000	/* end of page reached	*/
+#define SCC1_TRANS_MEMRDERR	0x04000000	/* SCC1 DMA memory err	*/
+#define SCC1_RECV_HALFPAGE	0x02000000	/* SCC1 half page	*/
+#define	SCC1_RECV_PAGOVRRUN	0x01000000	/* SCC1 receive overrun	*/
+#define FLOPPY_DMA_ERROR	0x00800000	/* FDI DMA error	*/
+#define	ISDN_TRANS_PTR_LOADED	0x00400000	/* xmitbuf ptr loaded	*/
+#define ISDN_RECV_PTR_LOADED	0x00200000	/* rcvbuf ptr loaded	*/
+#define ISDN_DMA_MEMRDERR	0x00100000	/* read or ovrrun error	*/
+#define SCSI_PTR_LOADED		0x00080000
+#define SCSI_PAGOVRRUN		0x00040000	/* page overrun? */
+#define SCSI_DMA_MEMRDERR	0x00020000
+#define LANCE_DMA_MEMRDERR	0x00010000
+
+/*
+ * the lower 16 bits are system specific
+ */
+
+/*
+ * The following three seem to be in common
+ */
+#define SCSI_CHIP		0x00000200
+#define LANCE_CHIP		0x00000100
+#define SCC1_CHIP		0x00000080	/* NOT on maxine	*/
+#define SCC0_CHIP		0x00000040
+
+/*
+ * The rest is different
+ */
+
+/* kmin aka 3min aka kn02ba aka DS5000_1xx */
+#define KMIN_TIMEOUT		0x00001000	/* CPU IO-Write Timeout	*/
+#define KMIN_CLOCK		0x00000020
+#define KMIN_SCSI_FIFO		0x00000004	/* SCSI Data Ready	*/
+
+/* kn02ca aka maxine */
+#define MAXINE_FLOPPY		0x00008000	/* FDI Interrupt        */
+#define MAXINE_TC0		0x00001000	/* TC Option 0      	*/
+#define MAXINE_ISDN		0x00000800	/* ISDN	Chip		*/
+#define MAXINE_FLOPPY_HDS	0x00000080	/* Floppy Status      	*/
+#define MAXINE_TC1		0x00000020	/* TC Option 1		*/
+#define MAXINE_FLOPPY_XDS	0x00000010	/* Floppy Status      	*/
+#define MAXINE_VINT		0x00000008	/* Video Frame		*/
+#define MAXINE_N_VINT		0x00000004	/* Not Video frame	*/
+#define MAXINE_DTOP_TRANS	0x00000002	/* DTI Xmit-Rdy		*/
+#define MAXINE_DTOP_RECV	0x00000001	/* DTI Recv-Available	*/
+
+/* kn03 aka 3max+ aka DS5000_2x0 */
+#define KN03_TC2		0x00004000
+#define KN03_TC1		0x00002000
+#define KN03_TC0		0x00001000
+#define KN03_SCSI_FIFO		0x00000004	/* ??? Info from Mach	*/
+
+/*
+ * Now form groups, i.e. all serial interrupts, all SCSI interrupts and so on. 
+ */
+#define SERIAL_INTS	(SCC0_TRANS_PAGEEND | SCC0_TRANS_MEMRDERR | \
+			SCC0_RECV_HALFPAGE | SCC0_RECV_PAGOVRRUN | \
+			SCC1_TRANS_PAGEEND | SCC1_TRANS_MEMRDERR | \
+			SCC1_RECV_HALFPAGE | SCC1_RECV_PAGOVRRUN | \
+			SCC1_CHIP | SCC0_CHIP)
+
+#define XINE_SERIAL_INTS	(SCC0_TRANS_PAGEEND | SCC0_TRANS_MEMRDERR | \
+			SCC0_RECV_HALFPAGE | SCC0_RECV_PAGOVRRUN | \
+			SCC0_CHIP)
+
+#define SCSI_DMA_INTS	(/* SCSI_PTR_LOADED | */ SCSI_PAGOVRRUN | \
+			SCSI_DMA_MEMRDERR)
+
+#define KMIN_SCSI_INTS	(SCSI_PTR_LOADED | SCSI_PAGOVRRUN | \
+			SCSI_DMA_MEMRDERR | SCSI_CHIP | KMIN_SCSI_FIFO)
+
+#define LANCE_INTS	(LANCE_DMA_MEMRDERR | LANCE_CHIP)
+
+/*
+ * For future use ...
+ */
+#define XINE_FLOPPY_INTS (MAXINE_FLOPPY | MAXINE_FLOPPY_HDS | \
+			FLOPPY_DMA_ERROR | MAXINE_FLOPPY_XDS)
+
+#define XINE_ISDN_INTS	(MAXINE_ISDN | ISDN_TRANS_PTR_LOADED | \
+			ISDN_RECV_PTR_LOADED | ISDN_DMA_MEMRDERR)
+
+#define XINE_DTOP_INTS	(MAXINE_DTOP_TRANS | DTOP_RECV | \
+			ISDN_TRANS_PTR_LOADED | ISDN_RECV_PTR_LOADED | \
+			ISDN_DMA_MEMRDERR)
+
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/kn01.h linux/include/asm-mips/dec/kn01.h
--- v2.3.8/linux/include/asm-mips/dec/kn01.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/kn01.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,28 @@
+/*
+ * Hardware info about DEC DECstation DS2100/3100 systems (otherwise known
+ * as pmax or kn01.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
+ * are by curteousy of Chris Fraser.
+ *
+ * This file is under construction - you were warned!
+ */
+#ifndef __ASM_MIPS_DEC_KN01_H 
+#define __ASM_MIPS_DEC_KN01_H 
+
+#include <asm/addrspace.h>
+
+/*
+ * Some port addresses...
+ * FIXME: these addresses are incomplete and need tidying up!
+ */
+
+#define KN01_LANCE_BASE (KSEG1ADDR(0x18000000)) /* 0xB8000000 */
+#define KN01_DZ11_BASE	(KSEG1ADDR(0x1c000000)) /* 0xBC000000 */
+#define KN01_RTC_BASE	(KSEG1ADDR(0x1d000000)) /* 0xBD000000 */
+
+#endif /* __ASM_MIPS_DEC_KN01_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/kn02.h linux/include/asm-mips/dec/kn02.h
--- v2.3.8/linux/include/asm-mips/dec/kn02.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/kn02.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,41 @@
+/*
+ * Hardware info about DEC DECstation 5000/2xx systems (otherwise known
+ * as 3max or kn02.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
+ * are by curteousy of Chris Fraser.
+ *
+ * This file is under construction - you were warned!
+ */
+#ifndef __ASM_MIPS_DEC_KN02_H 
+#define __ASM_MIPS_DEC_KN02_H 
+
+#include <asm/addrspace.h>
+
+/*
+ * Motherboard regs (kseg1 addresses)
+ */
+#define KN02_CSR_ADDR	KSEG1ADDR(0x1ff00000)	/* system control & status reg */
+
+/*
+ * Some port addresses...
+ * FIXME: these addresses are incomplete and need tidying up!
+ */
+#define KN02_RTC_BASE	KSEG1ADDR(0x1fe80000)
+#define KN02_DZ11_BASE	KSEG1ADDR(0x1fe00000)
+
+/*
+ * Interrupt enable Bits
+ */
+#define KN02_SLOT0	(1<<16)
+#define KN02_SLOT1	(1<<17)
+#define KN02_SLOT2	(1<<18)
+#define KN02_SLOT5	(1<<21)
+#define KN02_SLOT6	(1<<22)
+#define KN02_SLOT7	(1<<23)
+
+#endif /* __ASM_MIPS_DEC_KN02_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/kn02xa.h linux/include/asm-mips/dec/kn02xa.h
--- v2.3.8/linux/include/asm-mips/dec/kn02xa.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/kn02xa.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,34 @@
+/*
+ * Hardware info about DEC DECstation 5000/1xx systems (otherwise known
+ * as 3min or kn02ba. Apllies to the Personal DECstations 5000/xx (otherwise known
+ * as maxine or kn02ca) as well.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
+ * are by curteousy of Chris Fraser.
+ *
+ * These are addresses which have to be known early in the boot process.
+ * For other addresses refer to tc.h ioasic_addrs.h and friends.
+ */
+#ifndef __ASM_MIPS_DEC_KN02XA_H 
+#define __ASM_MIPS_DEC_KN02XA_H 
+
+#include <asm/addrspace.h>
+
+/*
+ * Motherboard regs (kseg1 addresses)
+ */
+#define KN02XA_SSR_ADDR		KSEG1ADDR(0x1c040100)	/* system control & status reg */
+#define KN02XA_SIR_ADDR		KSEG1ADDR(0x1c040110)	/* system interrupt reg */
+#define KN02XA_SIRM_ADDR	KSEG1ADDR(0x1c040120)	/* system interrupt mask reg */
+
+/*
+ * Some port addresses...
+ * FIXME: these addresses are incomplete and need tidying up!
+ */
+#define KN02XA_RTC_BASE	(KSEG1ADDR(0x1c000000 + 0x200000)) /* ASIC + SL8 */
+
+#endif /* __ASM_MIPS_DEC_KN02XA_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/kn03.h linux/include/asm-mips/dec/kn03.h
--- v2.3.8/linux/include/asm-mips/dec/kn03.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/kn03.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,33 @@
+/*
+ * Hardware info about DEC DECstation 5000/2x0 systems (otherwise known
+ * as 3max+ or kn03.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1995,1996 by Paul M. Antoine, some code and definitions
+ * are by curteousy of Chris Fraser.
+ *
+ * These are addresses which have to be known early in the boot process.
+ * For other addresses refer to tc.h ioasic_addrs.h and friends.
+ */
+#ifndef __ASM_MIPS_DEC_KN03_H 
+#define __ASM_MIPS_DEC_KN03_H 
+
+#include <asm/addrspace.h>
+
+/*
+ * Motherboard regs (kseg1 addresses)
+ */
+#define KN03_SSR_ADDR	KSEG1ADDR(0x1f840100)	/* system control & status reg */
+#define KN03_SIR_ADDR	KSEG1ADDR(0x1f840110)	/* system interrupt reg */
+#define KN03_SIRM_ADDR	KSEG1ADDR(0x1f840120)	/* system interrupt mask reg */
+
+/*
+ * Some port addresses...
+ * FIXME: these addresses are incomplete and need tidying up!
+ */
+#define KN03_RTC_BASE	(KSEG1ADDR(0x1f800000 + 0x200000)) /* ASIC + SL8 */
+
+#endif /* __ASM_MIPS_DEC_KN03_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/machtype.h linux/include/asm-mips/dec/machtype.h
--- v2.3.8/linux/include/asm-mips/dec/machtype.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/machtype.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,20 @@
+/*
+ * Various machine type definitions
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ */
+#include <asm/bootinfo.h>
+
+#define TURBOCHANNEL	(mips_machtype == MACH_DS5000_200 || \
+			 mips_machtype == MACH_DS5000_1XX || \
+			 mips_machtype == MACH_DS5000_XX  || \
+			 mips_machtype == MACH_DS5000_2X0)
+		      
+#define IOASIC		(mips_machtype == MACH_DS5000_1XX || \
+			 mips_machtype == MACH_DS5000_XX  || \
+			 mips_machtype == MACH_DS5000_2X0)
+
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/tc.h linux/include/asm-mips/dec/tc.h
--- v2.3.8/linux/include/asm-mips/dec/tc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/tc.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,43 @@
+/*
+ * Interface to the TURBOchannel related routines
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ */
+#ifndef ASM_TC_H
+#define ASM_TC_H
+
+extern unsigned long system_base;
+
+/*
+ * Search for a TURBOchannel Option Module
+ * with a certain name. Returns slot number
+ * of the first card not in use or -ENODEV
+ * if none found.
+ */
+extern int search_tc_card(const char *);
+/*
+ * Marks the card in slot as used
+ */
+extern void claim_tc_card(int);
+/*
+ * Marks the card in slot as free
+ */
+extern void release_tc_card(int);
+/*
+ * Return base address of card in slot 
+ */
+extern unsigned long get_tc_base_addr(int);
+/*
+ * Return interrupt number of slot
+ */
+extern unsigned long get_tc_irq_nr(int);
+/*
+ * Return TURBOchannel clock frequency in hz
+ */
+extern unsigned long get_tc_speed(void);
+
+#endif
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/tcinfo.h linux/include/asm-mips/dec/tcinfo.h
--- v2.3.8/linux/include/asm-mips/dec/tcinfo.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/tcinfo.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,47 @@
+/* 
+ * Various TURBOchannel related stuff
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Information obtained through the get_tcinfo prom call
+ * created from:
+ *
+ * TURBOchannel Firmware Specification
+ *
+ * EK-TCAAD-FS-004
+ * from Digital Equipment Corporation
+ *
+ * Copyright (c) 1998 Harald Koerfgen
+ */
+
+typedef struct {
+	int revision;
+	int clk_period;
+	int slot_size;
+	int io_timeout;
+	int dma_range;
+	int max_dma_burst;
+	int parity;
+	int reserved[4];
+} tcinfo;
+
+#define MAX_SLOT 7
+
+typedef struct {
+	unsigned long base_addr;
+	unsigned char name[9];
+	unsigned char vendor[9];
+	unsigned char firmware[9];
+	int interrupt;
+	int flags;
+} slot_info;
+
+/*
+ * Values for flags
+ */
+#define FREE 	1<<0
+#define IN_USE	1<<1
+
+
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dec/tcmodule.h linux/include/asm-mips/dec/tcmodule.h
--- v2.3.8/linux/include/asm-mips/dec/tcmodule.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/dec/tcmodule.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,35 @@
+/* 
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Offsets for the ROM header locations for
+ * TURBOchannel cards
+ *
+ * created from:
+ *
+ * TURBOchannel Firmware Specification
+ *
+ * EK-TCAAD-FS-004
+ * from Digital Equipment Corporation
+ *
+ * Jan.1998 Harald Koerfgen
+ */
+ 
+#define OLDCARD 0x3c0000
+
+#define ROM_WIDTH 0x3e0
+#define ROM_STRIDE 0x3e4
+#define ROM_SIZE 0x3e8
+#define SLOT_SIZE 0x3ec
+#define PATTERN0 0x3f0
+#define PATTERN1 0x3f4
+#define PATTERN2 0x3f8
+#define PATTERN3 0x3fc
+#define FIRM_VER 0x400
+#define VENDOR 0x420
+#define MODULE 0x440
+#define FIRM_TYPE 0x460
+#define FLAGS 0x470
+
+#define ROM_OBJECTS 0x480
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/delay.h linux/include/asm-mips/delay.h
--- v2.3.8/linux/include/asm-mips/delay.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/delay.h	Fri Jun 25 17:37:53 1999
@@ -1,3 +1,12 @@
+/* $Id: delay.h,v 1.2 1999/01/04 16:09:20 ralf Exp $
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1994 by Waldorf Electronics
+ * Copyright (C) 1995 - 1998 by Ralf Baechle
+ */
 #ifndef __ASM_MIPS_DELAY_H
 #define __ASM_MIPS_DELAY_H
 
@@ -25,7 +34,7 @@
 extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
 {
 	usecs *= 0x000010c6;		/* 2**32 / 1000000 */
-	__asm__("multu\t%0,%1\n\t"
+	__asm__("multu\t%0,%2\n\t"
 		"mfhi\t%0"
 		:"=r" (usecs)
 		:"0" (usecs),"r" (lps));
@@ -39,14 +48,5 @@
 #endif
 
 #define udelay(usecs) __udelay((usecs),__udelay_val)
-
-/*
- * The different variants for 32/64 bit are pure paranoia. The typical
- * range of numbers that appears for MIPS machines avoids overflows.
- */
-extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
-{
-	return (a*b)/c;
-}
 
 #endif /* __ASM_MIPS_DELAY_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/dma.h linux/include/asm-mips/dma.h
--- v2.3.8/linux/include/asm-mips/dma.h	Tue Oct 20 13:52:53 1998
+++ linux/include/asm-mips/dma.h	Fri Jun 25 17:37:53 1999
@@ -16,6 +16,7 @@
 #include <asm/io.h>			/* need byte IO */
 #include <asm/spinlock.h>		/* And spinlocks */
 #include <linux/delay.h>
+#include <asm/system.h>
 
 
 #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
@@ -175,8 +176,6 @@
 		dma_outb(dmanr | 4,  DMA1_MASK_REG);
 	else
 		dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
-	/* I hate voodoo programming but .. */
-	udelay(20);
 }
 
 /* Clear the 'DMA Pointer Flip Flop'.
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/elf.h linux/include/asm-mips/elf.h
--- v2.3.8/linux/include/asm-mips/elf.h	Fri May  8 00:13:26 1998
+++ linux/include/asm-mips/elf.h	Fri Jun 25 17:37:53 1999
@@ -53,10 +53,20 @@
 
 #define ELF_PLATFORM  (NULL)
 
-/* See comments in asm-alpha/elf.h, this is the same thing
+/*
+ * See comments in asm-alpha/elf.h, this is the same thing
  * on the MIPS.
  */
-#define ELF_PLAT_INIT(_r)	_r->regs[2] = 0;
+#define ELF_PLAT_INIT(_r)	do { \
+	_r->regs[1] = _r->regs[2] = _r->regs[3] = _r->regs[4] = 0;	\
+	_r->regs[5] = _r->regs[6] = _r->regs[7] = _r->regs[8] = 0;	\
+	_r->regs[9] = _r->regs[10] = _r->regs[11] = _r->regs[12] = 0;	\
+	_r->regs[13] = _r->regs[14] = _r->regs[15] = _r->regs[16] = 0;	\
+	_r->regs[17] = _r->regs[18] = _r->regs[19] = _r->regs[20] = 0;	\
+	_r->regs[21] = _r->regs[22] = _r->regs[23] = _r->regs[24] = 0;	\
+	_r->regs[25] = _r->regs[26] = _r->regs[27] = _r->regs[28] = 0;	\
+	_r->regs[30] = _r->regs[31] = 0;				\
+} while (0)
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
    use of this is to invoke "./ld.so someprog" to test out a new version of
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/fcntl.h linux/include/asm-mips/fcntl.h
--- v2.3.8/linux/include/asm-mips/fcntl.h	Wed Oct 21 10:04:28 1998
+++ linux/include/asm-mips/fcntl.h	Fri Jun 25 17:37:53 1999
@@ -24,9 +24,9 @@
 #define O_NOCTTY	0x0800	/* not fcntl */
 #define FASYNC		0x1000	/* fcntl, for BSD compatibility */
 #define O_LARGEFILE	0x2000	/* allow large file opens - currently ignored */
-#define O_NOFOLLOW	0x4000	/* Don't follow symbolic links */
 #define O_DIRECT	0x8000	/* direct disk access hint - currently ignored */
 #define O_DIRECTORY	0x10000	/* must be a directory */
+#define O_NOFOLLOW	0x20000	/* don't follow links */
 
 #define O_NDELAY	O_NONBLOCK
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/ide.h linux/include/asm-mips/ide.h
--- v2.3.8/linux/include/asm-mips/ide.h	Thu May 13 11:00:09 1999
+++ linux/include/asm-mips/ide.h	Fri Jun 25 17:37:53 1999
@@ -23,7 +23,8 @@
 struct ide_ops {
 	int (*ide_default_irq)(ide_ioreg_t base);
 	ide_ioreg_t (*ide_default_io_base)(int index);
-	void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
+	void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port,
+	                            ide_ioreg_t ctrl_port, int *irq);
 	int (*ide_request_irq)(unsigned int irq, void (*handler)(int, void *,
 	                       struct pt_regs *), unsigned long flags,
 	                       const char *device, void *dev_id);
@@ -46,9 +47,11 @@
 	return ide_ops->ide_default_io_base(index);
 }
 
-static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw,
+                                           ide_ioreg_t data_port,
+                                           ide_ioreg_t ctrl_port, int *irq)
 {
-	ide_ops->ide_init_hwif_ports(hw->io_ports, data_port, ctrl_port, &hw->irq);
+	ide_ops->ide_init_hwif_ports(hw, data_port, ctrl_port, &hw->irq);
 
 	hw->irq = ide_ops->ide_default_irq(data_port);
 }
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/init.h linux/include/asm-mips/init.h
--- v2.3.8/linux/include/asm-mips/init.h	Fri May  8 00:13:26 1998
+++ linux/include/asm-mips/init.h	Fri Jun 25 17:37:53 1999
@@ -1,11 +1,10 @@
-/*
- * include/asm-mips/init.h
+/* $Id: init.h,v 1.3 1999/02/15 02:22:10 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * $Id: init.h,v 1.3 1998/05/01 01:35:53 ralf Exp $
+ * Copyright 1998, 1999 Ralf Baechle
  */
 #ifndef __MIPS_INIT_H
 #define __MIPS_INIT_H
@@ -26,5 +25,6 @@
 #define __INIT		.section	.text.init,"ax"
 #define __FINIT		.previous
 #define __INITDATA	.section	.data.init,"a"
+#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES)))
 
 #endif /* __MIPS_INIT_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/io.h linux/include/asm-mips/io.h
--- v2.3.8/linux/include/asm-mips/io.h	Thu May 13 11:00:09 1999
+++ linux/include/asm-mips/io.h	Wed Jun 30 11:24:55 1999
@@ -140,18 +140,21 @@
 /*
  * XXX We need system specific versions of these to handle EISA address bits
  * 24-31 on SNI.
+ * XXX more SNI hacks.
  */
-#define readb(addr) (*(volatile unsigned char *) (isa_slot_offset + (unsigned long)(addr)))
-#define readw(addr) (*(volatile unsigned short *) (isa_slot_offset + (unsigned long)(addr)))
-#define readl(addr) (*(volatile unsigned int *) (isa_slot_offset + (unsigned long)(addr)))
-
-#define writeb(b,addr) (*(volatile unsigned char *) (isa_slot_offset + (unsigned long)(addr)) = (b))
-#define writew(b,addr) (*(volatile unsigned short *) (isa_slot_offset + (unsigned long)(addr)) = (b))
-#define writel(b,addr) (*(volatile unsigned int *) (isa_slot_offset + (unsigned long)(addr)) = (b))
-
-#define memset_io(a,b,c)	memset((void *)(isa_slot_offset + (unsigned long)a),(b),(c))
-#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(isa_slot_offset + (unsigned long)(b)),(c))
-#define memcpy_toio(a,b,c)	memcpy((void *)(isa_slot_offset + (unsigned long)(a)),(b),(c))
+#define readb(addr) (*(volatile unsigned char *) (0xa0000000 + (unsigned long)(addr)))
+#define readw(addr) (*(volatile unsigned short *) (0xa0000000 + (unsigned long)(addr)))
+#define readl(addr) (*(volatile unsigned int *) (0xa0000000 + (unsigned long)(addr)))
+
+#define writeb(b,addr) (*(volatile unsigned char *) (0xa0000000 + (unsigned long)(addr)) = (b))
+#define writew(b,addr) (*(volatile unsigned short *) (0xa0000000 + (unsigned long)(addr)) = (b))
+#define writel(b,addr) (*(volatile unsigned int *) (0xa0000000 + (unsigned long)(addr)) = (b))
+
+#define memset_io(a,b,c)	memset((void *)(0xa0000000 + (unsigned long)a),(b),(c))
+#define memcpy_fromio(a,b,c)	memcpy((a),(void *)(0xa0000000 + (unsigned long)(b)),(c))
+#define memcpy_toio(a,b,c)	memcpy((void *)(0xa0000000 + (unsigned long)(a)),(b),(c))
+
+/* END SNI HACKS ... */
 
 /*
  * We don't have csum_partial_copy_fromio() yet, so we cheat here and
@@ -374,23 +377,24 @@
 
 /*
  * The caches on some architectures aren't dma-coherent and have need to
- * handle this in software.  There are two types of operations that
+ * handle this in software.  There are three types of operations that
  * can be applied to dma buffers.
  *
  *  - dma_cache_wback_inv(start, size) makes caches and coherent by
  *    writing the content of the caches back to memory, if necessary.
  *    The function also invalidates the affected part of the caches as
  *    necessary before DMA transfers from outside to memory.
+ *  - dma_cache_wback(start, size) makes caches and coherent by
+ *    writing the content of the caches back to memory, if necessary.
+ *    The function also invalidates the affected part of the caches as
+ *    necessary before DMA transfers from outside to memory.
  *  - dma_cache_inv(start, size) invalidates the affected parts of the
  *    caches.  Dirty lines of the caches may be written back or simply
  *    be discarded.  This operation is necessary before dma operations
  *    to the memory.
  */
 extern void (*dma_cache_wback_inv)(unsigned long start, unsigned long size);
+extern void (*dma_cache_wback)(unsigned long start, unsigned long size);
 extern void (*dma_cache_inv)(unsigned long start, unsigned long size);
-
-/* Nothing to do */
-
-#define dma_cache_wback(_start,_size)		do { } while (0)
 
 #endif /* __ASM_MIPS_IO_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/ipc.h linux/include/asm-mips/ipc.h
--- v2.3.8/linux/include/asm-mips/ipc.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/ipc.h	Fri Jun 25 17:37:53 1999
@@ -24,6 +24,9 @@
 #define SHMGET		23
 #define SHMCTL		24
 
+/* Used by the DIPC package, try and avoid reusing it */
+#define DIPC		25
+
 #define IPCCALL(version,op)	((version)<<16 | (op))
 
 #endif /* __ASM_MIPS_IPC_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/irq.h linux/include/asm-mips/irq.h
--- v2.3.8/linux/include/asm-mips/irq.h	Tue Oct 20 13:52:53 1998
+++ linux/include/asm-mips/irq.h	Fri Jun 25 17:37:53 1999
@@ -10,9 +10,6 @@
 #ifndef __ASM_MIPS_IRQ_H
 #define __ASM_MIPS_IRQ_H
 
-/*
- * Actually this is a lie but we hide the local device's interrupts ...
- */
 #define NR_IRQS 64
 
 #define TIMER_IRQ 0
@@ -20,18 +17,9 @@
 extern int (*irq_cannonicalize)(int irq);
 
 struct irqaction;
-extern int setup_x86_irq(int irq, struct irqaction * new);
+extern int i8259_setup_irq(int irq, struct irqaction * new);
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
-
-extern unsigned int local_irq_count[];
-
-#ifdef __SMP__
-#error Send superfluous SMP boxes to ralf@uni-koblenz.de
-#else
-#define irq_enter(cpu, irq)     (++local_irq_count[cpu])
-#define irq_exit(cpu, irq)      (--local_irq_count[cpu])
-#endif
 
 /* Machine specific interrupt initialization  */
 extern void (*irq_setup)(void);
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/jazz.h linux/include/asm-mips/jazz.h
--- v2.3.8/linux/include/asm-mips/jazz.h	Tue Oct 20 13:52:53 1998
+++ linux/include/asm-mips/jazz.h	Fri Jun 25 17:37:53 1999
@@ -203,15 +203,19 @@
  * This is somewhat broken.  For reasons which nobody can remember anymore
  * we remap the Jazz interrupts to the usual ISA style interrupt numbers.
  */
-#define JAZZ_TIMER_IRQ          0
-#define JAZZ_KEYBOARD_IRQ       1
-#define JAZZ_FLOPPY_IRQ         6 /* needs to be consistent with floppy driver! */
-#define JAZZ_SCSI_IRQ           16
-#define JAZZ_ETHERNET_IRQ       17
-#define JAZZ_SERIAL1_IRQ        18
-#define JAZZ_SERIAL2_IRQ        19
-#define JAZZ_PARALLEL_IRQ       20
-#define JAZZ_MOUSE_IRQ          21
+#define JAZZ_PARALLEL_IRQ       16
+#define JAZZ_FLOPPY_IRQ          6 /* needs to be consistent with floppy driver! */
+#define JAZZ_SOUND_IRQ          18
+#define JAZZ_VIDEO_IRQ          19
+#define JAZZ_ETHERNET_IRQ       20
+#define JAZZ_SCSI_IRQ           21
+#define JAZZ_KEYBOARD_IRQ       22
+#define JAZZ_MOUSE_IRQ          23
+#define JAZZ_SERIAL1_IRQ        24
+#define JAZZ_SERIAL2_IRQ        25
+
+#define JAZZ_TIMER_IRQ          31
+
 
 /*
  * JAZZ DMA Channels
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/keyboard.h linux/include/asm-mips/keyboard.h
--- v2.3.8/linux/include/asm-mips/keyboard.h	Mon Apr 26 10:54:13 1999
+++ linux/include/asm-mips/keyboard.h	Wed Jun 30 11:24:55 1999
@@ -12,11 +12,12 @@
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <asm/bootinfo.h>
 
+#define DISABLE_KBD_DURING_INTERRUPTS 0
+
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
@@ -39,60 +40,36 @@
 /* Some stoneage hardware needs delays after some operations.  */
 #define kbd_pause() do { } while(0)
 
-/* Pointers to keyboard hardware access and init functions.  */
-unsigned char (*kbd_read_input)(void);
-void (*kbd_write_output)(unsigned char val);
-void (*kbd_write_command)(unsigned char val);
-unsigned char (*kbd_read_status)(void);
-
-void (*keyboard_setup)(void);
-
-#ifdef CONFIG_MIPS_JAZZ
-
-extern int jazz_ps2_request_irq(void);
-extern void jazz_ps2_free_irq(void);
-
-#define ps2_request_irq()      jazz_ps2_request_irq()
-#define ps2_free_irq(inode)    jazz_ps2_free_irq()
-
-#endif /* CONFIG_MIPS_JAZZ */
-
-#ifdef CONFIG_SGI
-
-#define DISABLE_KBD_DURING_INTERRUPTS 1
-
-/*
- * Machine specific bits for the PS/2 driver.
- * Aux device and keyboard share the interrupt on the Indy.
- */
-#define ps2_request_irq() 0
-#define ps2_free_irq(void) do { } while(0);
-
-#endif /* CONFIG_SGI */
-
-#if defined(CONFIG_ACER_PICA_61) || defined(CONFIG_SNI_RM200_PCI)
-#define CONF_KEYBOARD_USES_IO_PORTS
-#endif
-
-#ifdef CONF_KEYBOARD_USES_IO_PORTS
-/*
- * Most other MIPS machines access the keyboard controller via
- * memory mapped I/O ports.
- */
-#include <asm/io.h>
-
-/*
- * Machine specific bits for the PS/2 driver
- */
-
-#define AUX_IRQ 12
-
-#define ps2_request_irq()						\
-	request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)
-
-#define ps2_free_irq(inode) free_irq(AUX_IRQ, NULL)
-
-#endif /* CONF_KEYBOARD_USES_IO_PORTS */
+struct kbd_ops {
+	/* Keyboard driver resource allocation  */
+	void (*kbd_request_region)(void);
+	int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *));
+
+	/* PSaux driver resource managment  */
+	int (*aux_request_irq)(void (*handler)(int, void *, struct pt_regs *));
+	void (*aux_free_irq)(void);
+
+	/* Methods to access the keyboard processor's I/O registers  */
+	unsigned char (*kbd_read_input)(void);
+	void (*kbd_write_output)(unsigned char val);
+	void (*kbd_write_command)(unsigned char val);
+	unsigned char (*kbd_read_status)(void);
+};
+
+extern struct kbd_ops *kbd_ops;
+
+/* Do the actual calls via kbd_ops vector  */
+#define kbd_request_region() kbd_ops->kbd_request_region()
+#define kbd_request_irq(handler) kbd_ops->kbd_request_irq(handler)
+
+#define aux_request_irq(hand, dev_id) kbd_ops->aux_request_irq(hand)
+#define aux_free_irq(dev_id) kbd_ops->aux_free_irq()
+
+#define kbd_read_input() kbd_ops->kbd_read_input()
+#define kbd_write_output(val) kbd_ops->kbd_write_output(val)
+#define kbd_write_command(val) kbd_ops->kbd_write_command(val)
+#define kbd_read_status() kbd_ops->kbd_read_status()
 
 #endif /* __KERNEL */
+
 #endif /* __ASM_MIPS_KEYBOARD_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/mipsregs.h linux/include/asm-mips/mipsregs.h
--- v2.3.8/linux/include/asm-mips/mipsregs.h	Tue Oct 20 13:52:53 1998
+++ linux/include/asm-mips/mipsregs.h	Fri Jun 25 17:37:53 1999
@@ -233,11 +233,12 @@
 /*
  * Bitfields in the R[23]000 cp0 status register.
  */
-#define ST0_KUC			0x00000001
-#define ST0_IEP			0x00000002
-#define ST0_KUP			0x00000004
-#define ST0_IEO			0x00000008
-#define ST0_KUO			0x00000010
+#define ST0_IEC                 0x00000001
+#define ST0_KUC			0x00000002
+#define ST0_IEP			0x00000004
+#define ST0_KUP			0x00000008
+#define ST0_IEO			0x00000010
+#define ST0_KUO			0x00000020
 /* bits 6 & 7 are reserved on R[23]000 */
 
 /*
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/newport.h linux/include/asm-mips/newport.h
--- v2.3.8/linux/include/asm-mips/newport.h	Wed Sep 30 10:19:10 1998
+++ linux/include/asm-mips/newport.h	Fri Jun 25 17:37:53 1999
@@ -582,5 +582,12 @@
         rex->set.dcbdata0.all = ((modereg) << 24) | (data24 & 0xffffff);
 }
 
+#define BT445_PROTOCOL		DCB_CYCLES(1,1,3)
+
+#define BT445_CSR_ADDR_REG	(0 << DCB_CRS_SHIFT)
+#define BT445_CSR_REVISION	(2 << DCB_CRS_SHIFT)
+
+#define BT445_REVISION_REG	0x01
+
 #endif /* !(_SGI_NEWPORT_H) */
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/ng1.h linux/include/asm-mips/ng1.h
--- v2.3.8/linux/include/asm-mips/ng1.h	Fri May  8 00:13:26 1998
+++ linux/include/asm-mips/ng1.h	Fri Jun 25 17:37:53 1999
@@ -5,24 +5,24 @@
 
 typedef struct {
         int flags;
-        u16 w, h;
-        u16 fields_sec;
+        __u16 w, h;
+        __u16 fields_sec;
 } ng1_vof_info_t;
 
 struct ng1_info {
 	struct gfx_info gfx_info;
-	u8 boardrev;
-        u8 rex3rev;
-        u8 vc2rev;
-        u8 monitortype;
-        u8 videoinstalled;
-        u8 mcrev;
-        u8 bitplanes;
-        u8 xmap9rev;
-        u8 cmaprev;
+	__u8 boardrev;
+        __u8 rex3rev;
+        __u8 vc2rev;
+        __u8 monitortype;
+        __u8 videoinstalled;
+        __u8 mcrev;
+        __u8 bitplanes;
+        __u8 xmap9rev;
+        __u8 cmaprev;
         ng1_vof_info_t ng1_vof_info;
-        u8 bt445rev;
-        u8 paneltype;
+        __u8 bt445rev;
+        __u8 paneltype;
 };
 
 #define GFX_NAME_NEWPORT "NG1"
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/ng1hw.h linux/include/asm-mips/ng1hw.h
--- v2.3.8/linux/include/asm-mips/ng1hw.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/ng1hw.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,572 @@
+/* This is the hardware interface for newport graphics.  It's taken from
+   IRIX.
+
+   Alex deVries <puffin@redhat.com>
+
+*/
+
+
+#ifndef __SYS_NG1HW_H__
+#define __SYS_NG1HW_H__
+
+#ident "$Revision: 1.1 $"
+
+#define BIT(n)	(0x1 << n)
+
+
+#ifndef REX_ASMCODE
+
+typedef union {
+    volatile float flt;
+    volatile unsigned int word;
+} float_long;
+
+typedef volatile unsigned int vol_ulong;
+typedef volatile unsigned int fixed16;
+
+typedef union {
+    vol_ulong   byword;
+    struct {
+	volatile unsigned short s0;
+	volatile unsigned short s1;
+    } byshort;
+    struct {
+	volatile unsigned char b0, b1, b2;
+	volatile unsigned char b3;
+    } bybyte;
+} DCB_reg;
+
+#ifndef REXSIM
+typedef struct rex3regs {	/* THE CHIP */
+    vol_ulong drawmode1;	/* extra mode bits for GL 	0x0000 */
+    vol_ulong drawmode0;	/* command register 		0x0004 */
+
+    vol_ulong lsmode;		/* line stipple mode		0x0008 */
+    vol_ulong lspattern;	/* 32 bit pixel lspattern	0x000c */
+    vol_ulong lspatsave;	/* save register for lspattern	0x0010 */
+    vol_ulong zpattern;		/* 32 bit pixel zpattern	0x0014 */
+
+    vol_ulong colorback;	/* background color		0x0018 */
+    vol_ulong colorvram;	/* fast vram clear color	0x001c */
+    vol_ulong alpharef;		/* afunction reference value	0x0020 */
+
+    vol_ulong pad0;		/* padding 			0x0024 */	
+
+    vol_ulong smask0x;		/* screen mask 0, window rel,	0x0028 */
+    vol_ulong smask0y;		/* exclusively for the GL	0x002c */
+    vol_ulong _setup;		/* do line/span setup, no iter  0x0030 */
+    vol_ulong _stepz;		/* Enable ZPATTERN for this pix 0x0034 */
+    vol_ulong _lsrestore;	/* Restore lspattern,count	0x0038 */
+    vol_ulong _lssave;		/* Backup lspattern,count	0x003c */
+
+    char _pad1[0x100-0x40];
+
+    float_long _xstart;		/* 16.4(7) current x		0x0100 */
+    float_long _ystart;		/* 16.4(7) current y		0x0104 */
+    float_long _xend;		/* 16.4(7)			0x0108 */
+    float_long _yend;		/* 16.4(7)			0x010c */
+    vol_ulong xsave;		/* 16	x save for blocks	0x0110 */
+    vol_ulong xymove;		/* x,y copy dest offset		0x0114 */
+    float_long bresd;		/* s19.8 bres d error term	0x0118 */
+    float_long bress1;		/* s2.15 bres s coverage term	0x011c */
+    vol_ulong bresoctinc1;	/* 3(4)17.3 octant+inc1 value	0x0120 */
+    volatile int bresrndinc2;	/* 8(3)18.3 bres inc2 value	0x0124 */
+    vol_ulong brese1;		/* 1.15 bres e1 (minor slope)	0x0128 */
+    vol_ulong bress2;           /* s18.8 bres s2 coverage term  0x012c */
+    vol_ulong aweight0;		/* antialiasing weights		0x0130 */
+    vol_ulong aweight1;		/* antialiasing weights		0x0134 */
+    float_long xstartf;		/* 12.4(7) GL version of _xstart0x0138 */
+    float_long ystartf;		/* 12.4(7)			0x013c */
+    float_long xendf;		/* 12.4(7)			0x0140 */
+    float_long yendf;		/* 12.4(7)			0x0144 */
+    fixed16 xstarti;		/* 16 integer format for xstart 0x0148 */
+    float_long xendf1;		/* 12.4(7) same as xend		0x014c */
+    fixed16 xystarti;		/* 16,16			0x0150 */
+    fixed16 xyendi;		/* 16,16			0x0154 */
+    fixed16 xstartendi;		/* 16,16			0x0158 */
+    char _pad2[0x200-0x15c];
+    float_long colorred;	/* o12.11 red (also foreground)	0x0200 */
+    float_long coloralpha;	/* o8.11 alpha			0x0204 */
+    float_long colorgrn;	/* o8.11 green			0x0208 */
+    float_long colorblue;	/* o8.11 blue			0x020c */
+    float_long slopered;	/* s9.11			0x0210 */
+    float_long slopealpha;	/* s9.11			0x0214 */
+    float_long slopegrn;	/* s9.11			0x0218 */
+    float_long slopeblue;	/* s9.11			0x021c */
+    vol_ulong wrmask;		/* writemask			0x0220 */
+    vol_ulong colori;		/* packed bgr/ci		0x0224 */
+    float_long colorx;		/* 12.11 red (no overflow)	0x0228 */
+    float_long slopered1;	/* same as slopered		0x022c */
+    vol_ulong hostrw0;		/* host PIO/DMA port (msw)	0x0230 */
+    vol_ulong hostrw1;		/* host PIO/DMA port (lsw)	0x0234 */
+    vol_ulong dcbmode;		/* display ctrl bus mode reg 	0x0238 */
+    volatile int pad3;						/* 0x023c */
+    DCB_reg dcbdata0;		/* display ctrl bus port (msw)	0x0240 */
+    vol_ulong dcbdata1;		/* display ctrl bus port (lsw)	0x0244 */
+} Rex3regs;
+	
+
+typedef struct configregs {
+    vol_ulong smask1x;		/* screenmask1 right,left edges 0x1300 */
+    vol_ulong smask1y;		/* screenmask1 bottom,top edges 0x1304 */
+    vol_ulong smask2x;		/* screenmask2 right,left edges 0x1308 */
+    vol_ulong smask2y;		/* screenmask2 bottom,top edges 0x130c */
+    vol_ulong smask3x;		/* screenmask3 right,left edges 0x1310 */
+    vol_ulong smask3y;		/* screenmask3 bottom,top edges 0x1314 */
+    vol_ulong smask4x;		/* screenmask4 right,left edges 0x1318 */
+    vol_ulong smask4y;		/* screenmask4 bottom,top edges 0x131c */
+    vol_ulong topscan;		/* y coord of top screen line	0x1320 */
+    vol_ulong xywin;		/* window offset 		0x1324 */
+    vol_ulong clipmode;		/* cid,smask settings 		0x1328 */
+    vol_ulong pad0;		/*				0x132c */
+    vol_ulong config;		/* miscellaneous  config bits 	0x1330 */
+    vol_ulong pad1;		/*				0x1334 */
+    vol_ulong status;		/* chip busy, FIFO, int status  0x1338 */
+				/* read clears interrupt status bits   */
+    vol_ulong ustatus;		/* padding on rex rev a, 'read-only' 0x133c */
+				/* copy of status on rex rev b.	       */
+    vol_ulong dcbreset;		/* resets DCB and flushes BFIFO 0x1340 */
+} Configregs;
+
+typedef struct rex3chip {
+		/* page 0 */    
+	struct rex3regs set;		/* 0x0000 */
+	char _pad0[0x7fc-sizeof(struct rex3regs)];
+	volatile unsigned int dummy; /* 0x7fc */
+	struct rex3regs go;		/* 0x0800 */
+
+	char _pad1[0x1300-0x800-sizeof(struct rex3regs)];
+
+		/* page 1 */
+	struct {
+	    struct configregs set; 	/* 0x1300 */
+	    char _pad0[0x800-sizeof(struct configregs)];
+	    struct configregs go; 	/* 0x1b00 */
+	} p1;
+} rex3Chip, Rex3chip;
+
+
+#endif /* REX_ASMCODE */
+#endif /* REXSIM */
+
+/* Since alot of flags went away, define here as null bits
+   and leave the code as it is for now, 
+   marking where we have to change stuff.
+
+   NONE of these should be defined !   - billt
+   */
+
+#define LSCONTINUE 0
+#define SHADECONTINUE 0
+#define XYCONTINUE 0
+#define XMAJOR 0
+#define YMAJOR 0
+#define QUADMODE 0
+#define LRQPOLY 0
+/* RGBMODE, DITHER now live in DM1 */
+#define RGBMODECMD 0
+#define DITHER 0
+#define DITHERRANGE 0
+/* BLOCK is a function of ADDRMODE */
+#define BLOCK 0
+#define STOPONX 0
+#define STOPONY 0
+/* COLORCOMPARE is a combo of 3 bits (<, = , >) */
+#define COLORCOMP 0
+/* FRACTIONS are gone... */
+#define INITFRAC 0
+#define FRACTION1 0
+
+/* -- some old AUX1 junk -- */
+#define DOUBLEBUF 0
+#define DBLDST0 0
+#define DBLDST1 0
+#define DBLSRC 0
+#define COLORAUX 0
+
+
+/* --- a couple of old cmds also only for conversion --- */
+#define REX_LDPIXEL 0x1
+#define REX_ANTIAUX 0
+#define REX_DRAW 0
+#define LOGICSRC 0
+/* --- Blech! locicops are in DM1 too! */
+#define REX_LO_ZERO REX_LO_ZERO 
+#define REX_LO_AND DM1_LO_AND
+#define REX_LO_ANDR DM1_LO_ANDR
+#define REX_LO_SRC DM1_LO_SRC
+#define REX_LO_ANDI DM1_LO_ANDI
+#define REX_LO_DST DM1_LO_DST
+#define REX_LO_XOR DM1_LO_XOR
+#define REX_LO_OR DM1_LO_OR
+#define REX_LO_NOR DM1_LO_NOR
+#define REX_LO_XNOR DM1_LO_XNOR
+#define REX_LO_NDST DM1_LO_NDST
+#define REX_LO_ORR DM1_LO_ORR
+#define REX_LO_NSRC DM1_LO_NSRC
+#define REX_LO_ORI DM1_LO_ORI
+#define REX_LO_NAND DM1_LO_NAND
+#define REX_LO_ONE DM1_LO_ONE
+
+
+/*
+ *  drawmode flags
+ */
+#define DM0_OPCODE	0x3		/* opcode(1:0)	*/
+#	define DM0_NOP		0x0
+#	define DM0_READ		0x1
+#	define DM0_DRAW		0x2
+#	define DM0_SCR2SCR	0x3
+#define DM0_ADRMODE_SHIFT	2	/* adrmode(2:0)	*/
+#	define DM0_ADRMODE	(0x7<<DM0_ADRMODE_SHIFT)
+#	define DM0_SPAN		(0x0<<DM0_ADRMODE_SHIFT)
+#	define DM0_BLOCK	(0x1<<DM0_ADRMODE_SHIFT)
+#	define DM0_ILINE	(0x2<<DM0_ADRMODE_SHIFT)
+#	define DM0_FLINE	(0x3<<DM0_ADRMODE_SHIFT)
+#	define DM0_ALINE	(0x4<<DM0_ADRMODE_SHIFT)
+#ifdef OLDJUNK
+
+/* XXX These definitions are obsolete */
+
+#	define DM0_AELINE	(0x5<<DM0_ADRMODE_SHIFT)
+#	define DM0_ACWEDGE	(0x6<<DM0_ADRMODE_SHIFT)
+#	define DM0_ACCWEDGE	(0x7<<DM0_ADRMODE_SHIFT)
+
+#else
+
+/* XXX These are according to 11/2/92 spec */
+
+#       define DM0_TLINE        (0x5<<DM0_ADRMODE_SHIFT)
+#       define DM0_BLINE        (0x6<<DM0_ADRMODE_SHIFT)
+
+#endif /* OLDJUNK */
+
+#define DM0_DOSETUP	BIT(5)
+#define DM0_COLORHOST	BIT(6)
+#define DM0_ALPHAHOST	BIT(7)
+#define DM0_STOPONX	BIT(8)
+#define DM0_STOPONY	BIT(9)
+#define DM0_STOPONXY	(DM0_STOPONX | DM0_STOPONY)
+#define DM0_SKIPFIRST	BIT(10)
+#define DM0_SKIPLAST	BIT(11)
+#define DM0_ENZPATTERN	BIT(12)
+#define DM0_ENLSPATTERN	BIT(13)
+#define DM0_LSADVLAST	BIT(14)
+#define DM0_LENGTH32	BIT(15)
+#define DM0_ZOPAQUE	BIT(16)
+#define DM0_LSOPAQUE	BIT(17)
+#define DM0_SHADE	BIT(18)
+#define DM0_LRONLY	BIT(19)
+
+#ifdef OLDJUNK
+
+/* XXX These definitions are obsolete */
+
+#define DM0_CICLAMP     BIT(20)
+#define DM0_ENDPTFILTER BIT(21)
+
+#else
+
+/* XXX These are according to 11/2/92 spec */
+
+#define DM0_XYOFFSET    BIT(20)
+#define DM0_CICLAMP     BIT(21)
+#define DM0_ENDPTFILTER BIT(22)
+
+#endif	/* OLDJUNK */
+/* New Feature in REX REV B */
+#define	DM0_YSTRIDE	BIT(23)
+
+#define DM1_PLANES_SHIFT	0
+#define DM1_PLANES	0x7		/* planes(2:0)	*/
+#	define DM1_NOPLANES	0x0
+#	define DM1_RGBPLANES	0x1
+#	define DM1_RGBAPLANES	0x2
+#	define DM1_OLAYPLANES	0x4
+#	define DM1_PUPPLANES	0x5
+#	define DM1_CIDPLANES	0x6
+#define DM1_DRAWDEPTH_SHIFT	3	/* drawdepth(1:0)	*/
+#define DM1_DRAWDEPTH_MASK      (3 << DM1_DRAWDEPTH_SHIFT)
+#	define DM1_DRAWDEPTH	(0x3 << DM1_DRAWDEPTH_SHIFT)	
+#	define DM1_DRAWDEPTH4	(0x0 << DM1_DRAWDEPTH_SHIFT)
+#	define DM1_DRAWDEPTH8	(0x1 << DM1_DRAWDEPTH_SHIFT)
+#	define DM1_DRAWDEPTH12	(0x2 << DM1_DRAWDEPTH_SHIFT)
+#	define DM1_DRAWDEPTH24	(0x3 << DM1_DRAWDEPTH_SHIFT)
+#define DM1_DBLSRC		BIT(5)
+#define DM1_YFLIP		BIT(6)
+#define DM1_RWPACKED		BIT(7)
+#define DM1_HOSTDEPTH_SHIFT 	8	/* hostdepth(1:0)	*/
+#define DM1_HOSTDEPTH_MASK      (3 << DM1_HOSTDEPTH_SHIFT)
+#	define DM1_HOSTDEPTH	(0x3 << DM1_HOSTDEPTH_SHIFT)
+#	define DM1_HOSTDEPTH4	(0x0 << DM1_HOSTDEPTH_SHIFT)
+#	define DM1_HOSTDEPTH8	(0x1 << DM1_HOSTDEPTH_SHIFT)
+#	define DM1_HOSTDEPTH12	(0x2 << DM1_HOSTDEPTH_SHIFT)
+#	define DM1_HOSTDEPTH32	(0x3 << DM1_HOSTDEPTH_SHIFT)
+#define DM1_RWDOUBLE		BIT(10)
+#define DM1_SWAPENDIAN		BIT(11)
+#define DM1_COLORCOMPARE_SHIFT  12	/* compare (2:0)	*/
+#define DM1_COLORCOMPARE_MASK  (7 << DM1_COLORCOMPARE_SHIFT)
+#	define DM1_COLORCOMPARE (0x7 << DM1_COLORCOMPARE_SHIFT)
+#	define DM1_COLORCOMPLT	BIT(12)
+#	define DM1_COLORCOMPEQ	BIT(13)
+#	define DM1_COLORCOMPGT	BIT(14)
+#define DM1_RGBMODE		BIT(15)
+#define DM1_ENDITHER		BIT(16)
+#define DM1_FASTCLEAR		BIT(17)
+#define DM1_ENBLEND		BIT(18)
+#define DM1_SF_SHIFT		19	/* sfactor(2:0)	*/
+#define DM1_SF_MASK   		(7 << DM1_SF_SHIFT)
+#	define DM1_SF		(0x7 << DM1_SF_SHIFT)
+#	define DM1_SF_ZERO	(0x0 << DM1_SF_SHIFT)
+#	define DM1_SF_ONE	(0x1 << DM1_SF_SHIFT)
+#	define DM1_SF_DC	(0x2 << DM1_SF_SHIFT)
+#	define DM1_SF_MDC	(0x3 << DM1_SF_SHIFT)
+#	define DM1_SF_SA	(0x4 << DM1_SF_SHIFT)
+#	define DM1_SF_MSA	(0x5 << DM1_SF_SHIFT)
+#define DM1_DF_SHIFT		22	/* dfactor(2:0)	*/
+#define DM1_DF_MASK     (7 << DM1_DF_SHIFT)
+#	define DM1_DF		(0x7 << DM1_DF_SHIFT)
+#	define DM1_DF_ZERO	(0x0 << DM1_DF_SHIFT)
+#	define DM1_DF_ONE	(0x1 << DM1_DF_SHIFT)
+#	define DM1_DF_SC	(0x2 << DM1_DF_SHIFT)
+#	define DM1_DF_MSC	(0x3 << DM1_DF_SHIFT)
+#	define DM1_DF_SA	(0x4 << DM1_DF_SHIFT)
+#	define DM1_DF_MSA	(0x5 << DM1_DF_SHIFT)
+#define DM1_ENBACKBLEND		BIT(25)
+#define DM1_ENPREFETCH		BIT(26)
+#define DM1_BLENDALPHA		BIT(27)
+#define DM1_LO_SHIFT		28	/* logicop(3:0)	*/
+#	define DM1_LO		(0xF << DM1_LO_SHIFT)
+#       define DM1_LO_MASK      DM1_LO
+#	define DM1_LO_ZERO	(0x0 << DM1_LO_SHIFT)
+#	define DM1_LO_AND	(0x1 << DM1_LO_SHIFT)
+#	define DM1_LO_ANDR	(0x2 << DM1_LO_SHIFT)
+#	define DM1_LO_SRC	(0x3 << DM1_LO_SHIFT)
+#	define DM1_LO_ANDI	(0x4 << DM1_LO_SHIFT)
+#	define DM1_LO_DST	(0x5 << DM1_LO_SHIFT)
+#	define DM1_LO_XOR	(0x6 << DM1_LO_SHIFT)
+#	define DM1_LO_OR	(0x7 << DM1_LO_SHIFT)
+#	define DM1_LO_NOR	(0x8 << DM1_LO_SHIFT)
+#	define DM1_LO_XNOR	(0x9 << DM1_LO_SHIFT)
+#	define DM1_LO_NDST	(0xa << DM1_LO_SHIFT)
+#	define DM1_LO_ORR	(0xb << DM1_LO_SHIFT)
+#	define DM1_LO_NSRC	(0xc << DM1_LO_SHIFT)
+#	define DM1_LO_ORI	(0xd << DM1_LO_SHIFT)
+#	define DM1_LO_NAND	(0xe << DM1_LO_SHIFT)
+#	define DM1_LO_ONE	(0xf << DM1_LO_SHIFT)
+
+
+
+/*
+ * Clipmode register bits
+ */
+
+#define SMASK0	BIT(0)
+#define SMASK1	BIT(1)
+#define SMASK2	BIT(2)
+#define SMASK3	BIT(3)
+#define SMASK4	BIT(4)
+#define ALL_SMASKS	31
+
+#define CM_CIDMATCH_SHIFT       9
+#define CM_CIDMATCH_MASK        (0xf << CM_CIDMATCH_SHIFT)
+
+
+/*
+ * Status register bits
+ */
+
+#define REX3VERSION_MASK 7
+#define GFXBUSY         BIT(3)
+#define BACKBUSY        BIT(4)
+#define VRINT           BIT(5)
+#define VIDEOINT        BIT(6)
+#define GFIFO_LEVEL_SHIFT       7
+#define GFIFO_LEVEL_MASK        (0x3f << GFIFO_LEVEL_SHIFT)
+#define BFIFO_LEVEL_SHIFT       13
+#define BFIFO_LEVEL_MASK        (0x1f << BFIFO_LEVEL_SHIFT)
+#define BFIFO_INT        BIT(18)
+#define GFIFO_INT        BIT(19)
+
+
+/*
+ * Config register bits
+ */
+
+#define GIO32MODE       BIT(0)
+#define BUSWIDTH        BIT(1)
+#define EXTREGXCVR      BIT(2)
+#define BFIFODEPTH_SHIFT        3
+#define BFIFODEPTH_MASK         (0xf << BFIFODEPTH_SHIFT)
+#define BFIFOABOVEINT   BIT(7)
+#define GFIFODEPTH_SHIFT        8
+#define GFIFODEPTH_MASK         (0x1f << GFIFODEPTH_SHIFT)
+#define GFIFOABOVEINT   BIT(13)
+#define TIMEOUT_SHIFT   14
+#define TIMEOUT_MASK    (7 << TIMEOUT_SHIFT)
+#define VREFRESH_SHIFT  17
+#define VREFRESH_MASK   (0x7 << VREFRESH_SHIFT)
+#define FB_TYPE         BIT(20)
+
+/*
+ * Display Control Bus (DCB) macros
+ */
+
+#define DCB_DATAWIDTH_MASK  (0x3)
+#define DCB_ENDATAPACK      BIT(2)
+#define DCB_ENCRSINC        BIT(3)
+#define DCB_CRS_SHIFT    4
+#define DCB_CRS_MASK     (0x7 << DCB_CRS_SHIFT)
+#define DCB_ADDR_SHIFT   7
+#define DCB_ADDR_MASK    (0xf << DCB_ADDR_SHIFT)
+#define DCB_ENSYNCACK       BIT(11)
+#define DCB_ENASYNCACK      BIT(12)
+#define DCB_CSWIDTH_SHIFT   13
+#define DCB_CSWIDTH_MASK    (0x1f << CSWIDTH_SHIFT)
+#define DCB_CSHOLD_SHIFT    18
+#define DCB_CSHOLD_MASK     (0x1f << CSHOLD_SHIFT)
+#define DCB_CSSETUP_SHIFT   23
+#define DCB_CSSETUP_MASK    (0x1f << CSSETUP_SHIFT)
+#define DCB_SWAPENDIAN      BIT(28)
+
+
+/*
+ * Some values for DCBMODE fields
+ */
+#define DCB_DATAWIDTH_4		0x0
+#define DCB_DATAWIDTH_1		0x1
+#define DCB_DATAWIDTH_2		0x2
+#define DCB_DATAWIDTH_3		0x3
+
+
+/*
+ * DCB_ADDR values to select the various dcb slave devices
+ */
+#define DCB_VC2          (0 << DCB_ADDR_SHIFT)
+#define DCB_CMAP_ALL     (1 << DCB_ADDR_SHIFT)
+#define DCB_CMAP0        (2 << DCB_ADDR_SHIFT)
+#define DCB_CMAP1        (3 << DCB_ADDR_SHIFT)
+#define DCB_XMAP_ALL     (4 << DCB_ADDR_SHIFT)
+#define DCB_XMAP0        (5 << DCB_ADDR_SHIFT)
+#define DCB_XMAP1        (6 << DCB_ADDR_SHIFT)
+#define DCB_BT445        (7 << DCB_ADDR_SHIFT)
+#define DCB_VCC1         (8 << DCB_ADDR_SHIFT)
+#define DCB_VAB1         (9 << DCB_ADDR_SHIFT)
+#define DCB_LG3_BDVERS0      (10 << DCB_ADDR_SHIFT)
+#define DCB_LG3_ICS1562      (11 << DCB_ADDR_SHIFT)
+#define DCB_RESERVED     (15 << DCB_ADDR_SHIFT)
+
+/*
+ * New DCB Addresses which are used in (new) Indigo2 Video and Galileo 1.5
+ * since these boards have to work with Mardi Gras also. Yet, these
+ * are not necessarily the MGRAS address, these translate to the Mardi Gras
+ * addresses when the lower 2 bits are swapped (which will happen on 
+ * the Newport to new video board flex cable).
+ */
+#define DCB_VAB1_NEW     (9 << DCB_ADDR_SHIFT)
+/*
+ * While the Presenter is currently using address 12 and
+ * conflicting with the CC1, it has been changed for Mardi Gras
+ * To use the new video boards with Newport (an unreleased product)
+ * the presenter probe must be disabled by changing the presenter
+ * DCB address in gfx/kern/sys/pcd.h (and possibly
+ * lotus/stand/arcs/lib/libsk/graphics/NEWPORT/pcd.h), so 
+ * it is probed at address 11.  This will of course not work with
+ * the presenter card but it will allow you to test new video
+ * boards will Newport
+ */
+
+#define DCB_VCC1_NEW     (12 << DCB_ADDR_SHIFT)
+/*#define DCB_VCC1_NEW     (8 << DCB_ADDR_SHIFT)*/
+
+/*
+ * Addresses being used for Galileo 1.5.
+ */
+#define DCB_VCC1_GAL     (8 << DCB_ADDR_SHIFT) /* was 12 and will return */
+#define DCB_VAB1_GAL     (9 << DCB_ADDR_SHIFT)
+#define DCB_TMI_CSC      (13 << DCB_ADDR_SHIFT)
+#define DCB_GAL          (14 << DCB_ADDR_SHIFT)
+
+/*
+ * LG3 - (Newport for Fullhouse) board defines
+ */
+/* Version 0 register */
+#define LG3_VC2_UNRESET BIT(0)
+#define	LG3_GFX_UNRESET	BIT(1)
+#define LG3_PLL_UNRESET BIT(2)
+#define LG3_DLHD_MASTER BIT(3)
+
+#define LG3_BDVERS_PROTOCOL ((2 << DCB_CSWIDTH_SHIFT) | (1 << DCB_CSHOLD_SHIFT) | (1 << DCB_CSSETUP_SHIFT))
+
+#define lg3BdVersGet(rex3, data)			 		\
+        rex3->set.dcbmode = DCB_LG3_BDVERS0 | \
+		LG3_BDVERS_PROTOCOL | DCB_DATAWIDTH_1 ;			\
+        data = rex3->set.dcbdata0.bybyte.b3
+
+#define lg3BdVersSet(rex3, data)			 		\
+        rex3->set.dcbmode = DCB_LG3_BDVERS0 | \
+		LG3_BDVERS_PROTOCOL | DCB_DATAWIDTH_1 ;		\
+	rex3->set.dcbdata0.bybyte.b3 = (data)
+
+#define Ics1562Set(rex3, data)			 		\
+        rex3->set.dcbmode = DCB_LG3_ICS1562 | LG3_BDVERS_PROTOCOL | DCB_DATAWIDTH_1 ; \
+	rex3->set.dcbdata0.bybyte.b3 = (data)
+
+#define	LG3_BD_001	0x7
+#define	LG3_BD_002	0x0
+/*
+ * Lsmode register bits
+ */
+#define LSRCOUNT_SHIFT  0
+#define LSRCOUNT_MASK   (0xff << LSRCOUNT_SHIFT)
+#define LSREPEAT_SHIFT  8
+#define LSREPEAT_MASK   (0xff << LSREPEAT_SHIFT)
+#define LSRCNTSAVE_SHIFT        16
+#define LSRCNTSAVE_MASK (0xff << LSRCNTSAVE_SHIFT)
+#define LSLENGTH_SHIFT  24
+#define LSLENGTH_MASK   (0xf << LSLENGTH_SHIFT)
+
+#if	defined ( _KERNEL ) && defined ( REX3_RUNTIME_REV_CHECK )
+
+extern void _newport_poll_status (register struct rex3chip *, register int);
+
+#define REX3WAIT(rex3)  _newport_poll_status (rex3, GFXBUSY)
+#define BFIFOWAIT(rex3)  _newport_poll_status (rex3, BACKBUSY)
+
+#else
+
+/* XXX  When we drop support for rex rev b,
+ * change status to ustatus in the macros below.
+ */
+#define REX3WAIT(rex3)  while ((rex3)->p1.set.status & GFXBUSY)
+#define BFIFOWAIT(rex3)  while ((rex3)->p1.set.status & BACKBUSY)
+
+#endif
+
+/*
+ * Legal GIO bus addresses for Newport graphics boards.
+ */
+#define REX3_GIO_ADDR_0         0x1f0f0000
+#define REX3_GIO_ADDR_1         0x1f4f0000
+#define REX3_GIO_ADDR_2         0x1f8f0000
+#define REX3_GIO_ADDR_3         0x1fcf0000
+
+#define NG1_XSIZE       1280    /* screen size in x */
+#define NG1_YSIZE       1024    /* screen size in y */
+
+/*
+ * XXX Correct values TBD.  Depends on video timing
+ */
+#define CURSOR_XOFF 29
+#define CURSOR_YOFF 31
+
+#ifdef _STANDALONE
+struct rex3chip;
+struct ng1_info;
+void Ng1RegisterInit(struct rex3chip *, struct ng1_info *);
+extern int ng1checkboard(void);
+extern void vc2LoadSRAM(struct rex3chip *, unsigned short *,
+		unsigned int , unsigned int);
+#endif
+
+#endif /* __SYS_NG1HW_H__ */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/offset.h linux/include/asm-mips/offset.h
--- v2.3.8/linux/include/asm-mips/offset.h	Tue Oct 20 13:52:53 1998
+++ linux/include/asm-mips/offset.h	Fri Jun 25 17:37:53 1999
@@ -78,9 +78,9 @@
 #define THREAD_OLDCTX  912
 
 /* Linux mm_struct offsets. */
-#define MM_COUNT      12
-#define MM_PGD        8
-#define MM_CONTEXT    32
+#define MM_COUNT      16
+#define MM_PGD        12
+#define MM_CONTEXT    52
 
 /* Linux sigcontext offsets. */
 #define SC_REGMASK    0
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/page.h linux/include/asm-mips/page.h
--- v2.3.8/linux/include/asm-mips/page.h	Fri May  8 00:13:26 1998
+++ linux/include/asm-mips/page.h	Fri Jun 25 17:37:53 1999
@@ -1,11 +1,12 @@
-/*
+/* $Id: page.h,v 1.6 1999/01/04 16:09:24 ralf Exp $
+ *
  * Definitions for page handling
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1994 - 1998 by Ralf Baechle
  */
 #ifndef __ASM_MIPS_PAGE_H
 #define __ASM_MIPS_PAGE_H
@@ -19,10 +20,8 @@
 
 #define STRICT_MM_TYPECHECKS
 
-#ifndef __LANGUAGE_ASSEMBLY__
+#ifndef _LANGUAGE_ASSEMBLY
 
-#define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
-#define free_user_page(page, addr)	free_page(addr)
 extern void (*clear_page)(unsigned long page);
 extern void (*copy_page)(unsigned long to, unsigned long from);
 
@@ -66,7 +65,7 @@
 
 #endif /* !defined (STRICT_MM_TYPECHECKS) */
 
-#endif /* __LANGUAGE_ASSEMBLY__ */
+#endif /* _LANGUAGE_ASSEMBLY */
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
@@ -78,8 +77,7 @@
 #define PAGE_OFFSET	0x80000000UL
 #define __pa(x)		((unsigned long) (x) - PAGE_OFFSET)
 #define __va(x)		((void *)((unsigned long) (x) + PAGE_OFFSET))
-#define MAP_MASK        0x1fffffffUL
-#define MAP_NR(addr)	((((unsigned long)(addr)) & MAP_MASK) >> PAGE_SHIFT)
+#define MAP_NR(addr)	(__pa(addr) >> PAGE_SHIFT)
 
 #endif /* defined (__KERNEL__) */
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/pci.h linux/include/asm-mips/pci.h
--- v2.3.8/linux/include/asm-mips/pci.h	Tue Aug  4 16:06:57 1998
+++ linux/include/asm-mips/pci.h	Fri Jun 25 17:37:53 1999
@@ -10,7 +10,7 @@
 #define __ASM_MIPS_PCI_H
 
 struct pci_ops {
-	unsigned long (*pcibios_fixup) (void);
+	void (*pcibios_fixup) (void);
 	int (*pcibios_read_config_byte) (unsigned char bus,
 	                                 unsigned char dev_fn,
 	                                 unsigned char where,
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/pgtable.h linux/include/asm-mips/pgtable.h
--- v2.3.8/linux/include/asm-mips/pgtable.h	Wed Mar 10 18:11:51 1999
+++ linux/include/asm-mips/pgtable.h	Fri Jun 25 17:37:53 1999
@@ -129,7 +129,7 @@
 #define __READABLE	(_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED)
 #define __WRITEABLE	(_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED)
 
-#define _PAGE_CHG_MASK  (PAGE_MASK | __READABLE | __WRITEABLE | _CACHE_MASK)
+#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED | _CACHE_MASK)
 
 #define PAGE_NONE	__pgprot(_PAGE_PRESENT | _CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
@@ -356,7 +356,7 @@
 
 extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 {
-	return __pte((physpage - PAGE_OFFSET) | pgprot_val(pgprot));
+	return __pte(physpage | pgprot_val(pgprot));
 }
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
@@ -580,9 +580,9 @@
 /*
  * Kernel with 32 bit address space
  */
-#define SWP_TYPE(entry) (((entry) >> 8) & 0x7f)
-#define SWP_OFFSET(entry) ((entry) >> 15)
-#define SWP_ENTRY(type,offset) (((type) << 8) | ((offset) << 15))
+#define SWP_TYPE(entry) (((entry) >> 1) & 0x3f)
+#define SWP_OFFSET(entry) ((entry) >> 8)
+#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
 
 #define module_map      vmalloc
 #define module_unmap    vfree
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/processor.h linux/include/asm-mips/processor.h
--- v2.3.8/linux/include/asm-mips/processor.h	Tue May 25 14:55:05 1999
+++ linux/include/asm-mips/processor.h	Fri Jun 25 17:37:53 1999
@@ -180,6 +180,7 @@
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
 /* Copy and release all segment info associated with a VM */
 #define copy_segments(nr, p, mm) do { } while(0)
@@ -200,6 +201,7 @@
 	return ((unsigned long*)t->reg29)[17];
 }
 
+struct pt_regs;
 extern int (*user_mode)(struct pt_regs *);
 
 /*
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/ptrace.h linux/include/asm-mips/ptrace.h
--- v2.3.8/linux/include/asm-mips/ptrace.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/ptrace.h	Fri Jun 25 17:37:53 1999
@@ -15,13 +15,14 @@
 #include <linux/types.h>
 
 /* 0 - 31 are integer registers, 32 - 63 are fp registers.  */
+#define FPR_BASE	32
 #define PC		64
 #define CAUSE		65
-#define MMLO		66
+#define BADVADDR	66
 #define MMHI		67
-#define FPC_CSR		68	/* XXX */
-#define FPC_EIR		69	/* XXX */
-#define FPR_BASE	70	/* XXX */
+#define MMLO		68
+#define FPC_CSR		69
+#define FPC_EIR		70
 
 #ifndef __ASSEMBLY__
 /*
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/resource.h linux/include/asm-mips/resource.h
--- v2.3.8/linux/include/asm-mips/resource.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/resource.h	Fri Jun 25 17:37:53 1999
@@ -1,11 +1,10 @@
-/*
- * Process resource limits
+/* $Id: resource.h,v 1.2 1999/01/04 16:09:25 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1998 by Ralf Baechle
  */
 #ifndef __ASM_MIPS_RESOURCE_H
 #define __ASM_MIPS_RESOURCE_H
@@ -30,15 +29,15 @@
 
 #define INIT_RLIMITS					\
 {							\
-	{LONG_MAX, LONG_MAX},				\
-	{LONG_MAX, LONG_MAX},				\
-	{LONG_MAX, LONG_MAX},				\
-	{_STK_LIM, _STK_LIM},				\
-	{       0, LONG_MAX},				\
-	{NR_OPEN, NR_OPEN},				\
-	{LONG_MAX, LONG_MAX},				\
-	{LONG_MAX, LONG_MAX},				\
-	{MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	\
+	{ LONG_MAX, LONG_MAX },				\
+	{ LONG_MAX, LONG_MAX },				\
+	{ LONG_MAX, LONG_MAX },				\
+	{ _STK_LIM, LONG_MAX },				\
+	{        0, LONG_MAX },				\
+	{ NR_OPEN, NR_OPEN },				\
+	{ LONG_MAX, LONG_MAX },				\
+	{ LONG_MAX, LONG_MAX },				\
+	{ MAX_TASKS_PER_USER, MAX_TASKS_PER_USER },	\
 	{ LONG_MAX, LONG_MAX },				\
 }
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/semaphore-helper.h linux/include/asm-mips/semaphore-helper.h
--- v2.3.8/linux/include/asm-mips/semaphore-helper.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/semaphore-helper.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,125 @@
+/* $Id: semaphore-helper.h,v 1.3 1999/06/11 14:30:15 ralf Exp $
+ *
+ * SMP- and interrupt-safe semaphores helper functions.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ * (C) Copyright 1999 Andrea Arcangeli
+ * (C) Copyright 1999 Ralf Baechle
+ */
+#ifndef __ASM_MIPS_SEMAPHORE_HELPER_H
+#define __ASM_MIPS_SEMAPHORE_HELPER_H
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+static inline void wake_one_more(struct semaphore * sem)
+{
+	atomic_inc(&sem->waking);
+}
+
+static inline int
+waking_non_zero(struct semaphore *sem)
+{
+	int ret, tmp;
+
+	__asm__ __volatile__(
+	"1:\tll\t%1,%2\n\t"
+	"blez\t%1,2f\n\t"
+	"subu\t%0,%1,1\n\t"
+	"sc\t%0,%2\n\t"
+	"beqz\t%0,1b\n\t"
+	"2:"
+	".text"
+	: "=r"(ret), "=r"(tmp), "=m"(__atomic_fool_gcc(&sem->waking))
+	: "0"(0));
+
+	return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ *	1	got the lock
+ *	0	go to sleep
+ *	-EINTR	interrupted
+ *
+ * We must undo the sem->count down_interruptible decrement
+ * simultaneously and atomicly with the sem->waking adjustment,
+ * otherwise we can race with wake_one_more.
+ *
+ * This is accomplished by doing a 64-bit ll/sc on the 2 32-bit words.
+ *
+ * This is crazy.  Normally it stricly forbidden to use 64-bit operation
+ * in the 32-bit MIPS kernel.  In this case it's however ok because if an
+ * interrupt has destroyed the upper half of registers sc will fail.
+ */
+static inline int
+waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk)
+{
+	long ret, tmp;
+
+#ifdef __MIPSEB__
+        __asm__ __volatile__("
+	.set	mips3
+	.set	push
+	.set	noat
+0:	lld	%1,%2
+	li	%0,0
+
+	bltz	%1, 1f
+	dli	$1, 0xffffffff00000000
+	daddu	%1, $1
+	li	%0, 1
+	b	2f
+1:
+
+	beqz	%3, 1f
+	addiu	$1, %1, 1
+	dsll32	$1, $1, 0
+	dsrl32	$1, $1, 0
+	dsrl32	%1, %1, 0
+	dsll32	%1, %1, 0
+	or	%1, $1
+	li	%0, %4
+	b	2f
+1:
+	scd	%1, %2
+2:
+	beqz	%1,0b
+	.set	pop
+	.set	mips0"
+	: "=&r"(ret), "=&r"(tmp), "=m"(*sem)
+	: "r"(signal_pending(tsk)), "i"(-EINTR));
+#endif
+
+#ifdef __MIPSEL__
+#error "FIXME: waking_non_zero_interruptible doesn't support little endian machines yet."
+#endif
+
+	return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ *	1	failed to lock
+ *	0	got the lock
+ *
+ * XXX SMP ALERT
+ */
+#ifdef __SMP__
+#error FIXME, waking_non_zero_trylock is broken for SMP.
+#endif
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+        int ret = 1;
+
+	if (atomic_read(&sem->waking) <= 0)
+		atomic_inc(&sem->count);
+	else {
+		atomic_dec(&sem->waking);
+		ret = 0;
+	}
+
+	return ret;
+}
+
+#endif /* __ASM_MIPS_SEMAPHORE_HELPER_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/semaphore.h linux/include/asm-mips/semaphore.h
--- v2.3.8/linux/include/asm-mips/semaphore.h	Sat May 15 15:05:37 1999
+++ linux/include/asm-mips/semaphore.h	Fri Jun 25 17:37:53 1999
@@ -1,11 +1,13 @@
-/*
+/* $Id: semaphore.h,v 1.6 1999/06/17 13:30:38 ralf Exp $
+ *
  * SMP- and interrupt-safe semaphores..
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * (C) Copyright 1996  Linus Torvalds, Ralf Baechle
+ * (C) Copyright 1996  Linus Torvalds
+ * (C) Copyright 1998, 1999  Ralf Baechle
  */
 #ifndef __ASM_MIPS_SEMAPHORE_H
 #define __ASM_MIPS_SEMAPHORE_H
@@ -13,56 +15,67 @@
 #include <asm/system.h>
 #include <asm/atomic.h>
 #include <asm/spinlock.h>
+#include <linux/wait.h>
 
 struct semaphore {
 	atomic_t count;
 	atomic_t waking;
 	wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+	long __magic;
+#endif
 };
 
-#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
-#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
-
-extern void __down(struct semaphore * sem);
-extern int  __down_interruptible(struct semaphore * sem);
-extern void __up(struct semaphore * sem);
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+		, (long)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name,count) \
+{ ATOMIC_INIT(count), ATOMIC_INIT(0), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+	__SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+	__SEMAPHORE_INITIALIZER(name,1)
 
-extern spinlock_t semaphore_wake_lock;
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+	struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
 
-#define sema_init(sem, val)	atomic_set(&((sem)->count), val)
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
 
-/*
- * These two _must_ execute atomically wrt each other.
- *
- * This is trivially done with load_locked/store_cond,
- * which we have.  Let the rest of the losers suck eggs.
- */
-
-static inline void wake_one_more(struct semaphore * sem)
+extern inline void sema_init (struct semaphore *sem, int val)
 {
-	atomic_inc(&sem->waking);
+	atomic_set(&sem->count, val);
+	atomic_set(&sem->waking, 0);
+	init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+	sem->__magic = (long)&sem->__magic;
+#endif
 }
 
-static inline int waking_non_zero(struct semaphore *sem, struct task_struct *tsk)
+static inline void init_MUTEX (struct semaphore *sem)
 {
-	int ret, tmp;
-
-	__asm__ __volatile__(
-	"1:\tll\t%1,%2\n"
-	"blez\t%1,2f\n\t"
-	"subu\t%0,%1,1\n\t"
-	"sc\t%0,%2\n\t"
-	"beqz\t%0,1b\n\t"
-	"2:"
-	".text"
-	: "=r"(ret), "=r"(tmp), "=m"(__atomic_fool_gcc(&sem->waking))
-	: "0"(0));
+	sema_init(sem, 1);
+}
 
-	return ret;
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+	sema_init(sem, 0);
 }
 
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int  __down_interruptible(struct semaphore * sem);
+asmlinkage int __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
+
 extern inline void down(struct semaphore * sem)
 {
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
 	if (atomic_dec_return(&sem->count) < 0)
 		__down(sem);
 }
@@ -70,17 +83,71 @@
 extern inline int down_interruptible(struct semaphore * sem)
 {
 	int ret = 0;
+
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
 	if (atomic_dec_return(&sem->count) < 0)
 		ret = __down_interruptible(sem);
 	return ret;
 }
 
 /*
+ * down_trylock returns 0 on success, 1 if we failed to get the lock.
+ *
+ * We must manipulate count and waking simultaneously and atomically.
+ * Do this by using ll/sc on the pair of 32-bit words.
+ */
+extern inline int down_trylock(struct semaphore * sem)
+{
+	long ret, tmp, tmp2, sub;
+
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
+#ifdef __MIPSEB__
+	__asm__ __volatile__("
+			.set	mips3
+		0:	lld	%1, %4
+			dli	%3, 0x0000000100000000
+			sltu	%0, %1, $0
+
+			bltz	%1, 1f
+			move	%3, $0
+		1:
+
+			sltu	%2, %1, $0
+			and	%0, %0, %2
+			bnez	%0, 2f
+
+			subu	%0, %3
+			scd	%1, %4
+
+			beqz	%1, 0b
+		2:
+
+			.set	mips0"
+		: "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
+		: "m"(*sem)
+		: "memory");
+#endif
+
+#ifdef __MIPSEL__
+#error "FIXME: down_trylock doesn't support little endian machines yet."
+#endif
+
+	return ret;
+}
+
+/*
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
  */
 extern inline void up(struct semaphore * sem)
 {
+#if WAITQUEUE_DEBUG
+	CHECK_MAGIC(sem->__magic);
+#endif
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
 }
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/sgialib.h linux/include/asm-mips/sgialib.h
--- v2.3.8/linux/include/asm-mips/sgialib.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/sgialib.h	Fri Jun 25 17:37:53 1999
@@ -14,6 +14,9 @@
 extern int prom_argc;
 extern char **prom_argv, **prom_envp;
 
+extern int prom_flags;
+#define PROM_FLAG_ARCS  1
+
 /* Init the PROM library and it's internal data structures.  Called
  * at boot time from head.S before start_kernel is invoked.
  */
@@ -31,6 +34,7 @@
 struct prom_pmemblock {
 	unsigned long base; /* Within KSEG0. */
 	unsigned int size;  /* In bytes. */
+        unsigned int type;  /* free or prom memory */
 };
 
 /* Get next memory descriptor after CURR, returns first descriptor
@@ -71,10 +75,10 @@
 extern long prom_delcomponent(pcomponent *this);
 extern pcomponent *prom_componentbypath(char *path);
 
-/* This is called at prom_init time to setup the tags which the
- * MIPS kernel setup code wants to diddle with. 
+/* This is called at prom_init time to identify the
+ * ARC architecture we are running on
  */
-extern void prom_setup_archtags(void);
+extern void prom_identify_arch(void);
 
 /* Environemt variable routines. */
 extern char *prom_getenv(char *name);
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/sgiarcs.h linux/include/asm-mips/sgiarcs.h
--- v2.3.8/linux/include/asm-mips/sgiarcs.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/sgiarcs.h	Fri Jun 25 17:37:53 1999
@@ -88,19 +88,36 @@
 };
 
 /* ARCS prom memory descriptors. */
-enum linux_memtypes {
-	eblock,  /* exception block */
-	rvpage,  /* ARCS romvec page */
-	fcontig, /* Contiguous and free */
-	free,    /* Generic free memory */
-	bmem,    /* Borken memory, don't use */
-	prog,    /* A loaded program resides here */
-	atmp,    /* ARCS temporary storage area, wish Sparc OpenBoot told this */
-	aperm,   /* ARCS permanent storage... */
+enum arcs_memtypes {
+	arcs_eblock,  /* exception block */
+	arcs_rvpage,  /* ARCS romvec page */
+	arcs_fcontig, /* Contiguous and free */
+	arcs_free,    /* Generic free memory */
+	arcs_bmem,    /* Borken memory, don't use */
+	arcs_prog,    /* A loaded program resides here */
+	arcs_atmp,    /* ARCS temporary storage area, wish Sparc OpenBoot told this */
+	arcs_aperm,   /* ARCS permanent storage... */
+};
+
+/* ARC has slightly different types than ARCS */
+enum arc_memtypes {
+	arc_eblock,  /* exception block */
+	arc_rvpage,  /* romvec page */
+	arc_free,    /* Generic free memory */
+	arc_bmem,    /* Borken memory, don't use */
+	arc_prog,    /* A loaded program resides here */
+	arc_atmp,    /* temporary storage area */
+	arc_aperm,   /* permanent storage */
+	arc_fcontig, /* Contiguous and free */    
+};
+
+union linux_memtypes {
+    enum arcs_memtypes arcs;
+    enum arc_memtypes arc;
 };
 
 struct linux_mdesc {
-	enum linux_memtypes type;
+        union linux_memtypes type;
 	unsigned long base;
 	unsigned long pages;
 };
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/sgihpc.h linux/include/asm-mips/sgihpc.h
--- v2.3.8/linux/include/asm-mips/sgihpc.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/sgihpc.h	Fri Jun 25 17:37:53 1999
@@ -178,8 +178,7 @@
 
 struct hpc3_regs {
 	/* First regs for the PBUS 8 dma channels. */
-	struct hpc3_pbus_dmacregs pbdma0, pbdma1, pbdma2, pbdma3;
-	struct hpc3_pbus_dmacregs pbdma4, pbdma5, pbdma6, pbdma7;
+	struct hpc3_pbus_dmacregs pbdma[8];
 
 	/* Now the HPC scsi registers, we get two scsi reg sets. */
 	struct hpc3_scsiregs scsi_chan0, scsi_chan1;
@@ -191,7 +190,7 @@
 	 * via PIO accesses.  Under normal operation we never stick
 	 * our grubby paws in here so it's just padding.
 	 */
-	char _unused1[PAGE_SIZE * 16];
+	char _unused1[PAGE_SIZE * 24];
 
 	/* HPC3 irq status regs.  Due to a peculiar bug you need to
 	 * look at two different register addresses to get at all of
@@ -223,15 +222,20 @@
 #define HPC3_GIOESTAT_PIDMSK  0x3f700  /* DMA channel parity identifier */
 
 	/* Now direct PIO per-HPC3 peripheral access to external regs. */
-	char _unused2[0x13ff0]; /* Trust me... */
+	char _unused2[0x13fec]; /* Trust me... */
 	hpcreg scsi0_ext[256];  /* SCSI channel 0 external regs */
 	char _unused3[0x07c00]; /* Trust me... */
 	hpcreg scsi1_ext[256];  /* SCSI channel 1 external regs */
 	char _unused4[0x07c00]; /* It'll only hurt a little... */
 
+	/* Did DaveM forget the ethernet external regs?
+	 * Anyhow, they're not here and we need some padding instead.
+	 */
+	char _unused5[0x04000]; /* It'll hurt a lot if you leave this out */
+
 	/* Per-peripheral device external registers and dma/pio control. */
-	hpcreg pbus_extregs[256][10]; /* 2nd indice indexes controller */
-	hpcreg pbus_dmacfgs[128][10]; /* 2nd indice indexes controller */
+	hpcreg pbus_extregs[16][256]; /* 2nd indice indexes controller */
+	hpcreg pbus_dmacfgs[8][128]; /* 2nd indice indexes controller */
 #define HPC3_PIODCFG_D3R    0x00000001 /* Cycles to spend in D3 for reads */
 #define HPC3_PIODCFG_D4R    0x0000001e /* Cycles to spend in D4 for reads */
 #define HPC3_PIODCFG_D5R    0x000001e0 /* Cycles to spend in D5 for reads */
@@ -258,15 +262,15 @@
 	hpcreg pbus_promwe;     /* PROM write enable register */
 #define HPC3_PROM_WENAB     0x1 /* Enable writes to the PROM */
 
-	char _unused5[0x800 - sizeof(hpcreg)];
+	char _unused6[0x800 - sizeof(hpcreg)];
 	hpcreg pbus_promswap;   /* Chip select swap reg */
 #define HPC3_PROM_SWAP      0x1 /* invert GIO addr bit to select prom0 or prom1 */
 
-	char _unused6[0x800 - sizeof(hpcreg)];
+	char _unused7[0x800 - sizeof(hpcreg)];
 	hpcreg pbus_gout;       /* PROM general purpose output reg */
 #define HPC3_PROM_STAT      0x1 /* General purpose status bit in gout */
 
-	char _unused7[0x1000 - sizeof(hpcreg)];
+	char _unused8[0x1000 - sizeof(hpcreg)];
 	hpcreg pbus_promram[16384]; /* 64k of PROM battery backed ram */
 };
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/sgint23.h linux/include/asm-mips/sgint23.h
--- v2.3.8/linux/include/asm-mips/sgint23.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/sgint23.h	Fri Jun 25 17:37:53 1999
@@ -1,7 +1,8 @@
-/* $Id: sgint23.h,v 1.2 1998/03/11 11:58:36 ralf Exp $
+/* $Id: sgint23.h,v 1.3 1999/05/07 22:35:37 ulfc Exp $
  * sgint23.h: Defines for the SGI INT2 and INT3 chipsets.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - INT2 corrections
  */
 #ifndef _MIPS_SGINT23_H
 #define _MIPS_SGINT23_H
@@ -20,7 +21,7 @@
 #define SGINT_END      52  /* End of 'spaces' */
 
 /* INT2 occupies HPC PBUS slot 4, INT3 uses slot 6. */
-#define SGI_INT2_BASE 0x1fb80100 /* physical */
+#define SGI_INT2_BASE 0x1fbd9000 /* physical */
 #define SGI_INT3_BASE 0x1fbd9880 /* physical */
 
 struct sgi_ioc_ints {
@@ -128,6 +129,10 @@
 
 #define SGINT_TCSAMP_COUNTER  10255
 
+/* FIXME: What does this really look like?  It was written to have
+ * 17 registers, but there are only 16 in my Indigo2.
+ * I guessed at which one to remove...  	- andrewb
+ */
 struct sgi_int2_regs {
 	struct sgi_ioc_ints ints;
 
@@ -147,8 +152,11 @@
 #endif
 #define INT2_TCLEAR_T0CLR      0x1        /* Clear timer0 IRQ */
 #define INT2_TCLEAR_T1CLR      0x2        /* Clear timer1 IRQ */
-
-	unsigned long _unused[3];
+/* I am guesing there are only two unused registers here 
+ * but I could be wrong...			- andrewb
+ */
+/*	unsigned long _unused[3]; */
+	unsigned long _unused[2];
 	struct sgi_ioc_timers timers;
 };
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/shmparam.h linux/include/asm-mips/shmparam.h
--- v2.3.8/linux/include/asm-mips/shmparam.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/shmparam.h	Fri Jun 25 17:37:53 1999
@@ -33,7 +33,9 @@
  * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS).
  */
 
-#define SHMMAX 0x1000000		/* max shared seg size (bytes) */
+#define SHMMAX 0x2000000		/* max shared seg size (bytes) */
+/* Try not to change the default shipped SHMMAX - people rely on it */
+
 #define SHMMIN 1 /* really PAGE_SIZE */	/* min shared seg size (bytes) */
 #define SHMMNI (1<<_SHM_ID_BITS)	/* max num of segs system wide */
 #define SHMALL				/* max shm system wide (pages) */ \
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/sni.h linux/include/asm-mips/sni.h
--- v2.3.8/linux/include/asm-mips/sni.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/sni.h	Fri Jun 25 17:37:53 1999
@@ -69,10 +69,10 @@
 #define PCIMT_PWDN		0xbfdf0000
 
 /*
- * Interrupt 0-16 are reserved for PCI and EISA interrupts.  The
- * interrupts from 16 are assigned to the other interrupts generated
- * by the PCI chipset.
+ * Interrupt 0-16 are EISA interrupts.  Interrupts from 16 on are assigned
+ * to the other interrupts generated by ASIC PCI.
  */
+#define PCIMT_KEYBOARD_IRQ	 1
 #define PCIMT_IRQ_ETHERNET	16
 #define PCIMT_IRQ_TEMPERATURE	17
 #define PCIMT_IRQ_EISA_NMI	18
@@ -89,9 +89,7 @@
  */
 #define PCIMT_EISA_BASE		0xb0000000
 
-/*
- * The keyboard interrupt is an ISA interrupt
- */
-#define SNI_KEYBOARD_IRQ 1
+/* PCI EISA Interrupt acknowledge  */
+#define PCIMT_INT_ACKNOWLEDGE	0xba000000
 
 #endif /* __ASM_MIPS_SNI_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/softirq.h linux/include/asm-mips/softirq.h
--- v2.3.8/linux/include/asm-mips/softirq.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/softirq.h	Fri Jun 25 17:37:53 1999
@@ -1,10 +1,10 @@
-/* $Id: softirq.h,v 1.5 1998/08/29 21:20:22 ralf Exp $
+/* $Id: softirq.h,v 1.6 1999/06/17 13:30:38 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1997, 1998 by Ralf Baechle
+ * Copyright (C) 1997, 1998, 1999 by Ralf Baechle
  */
 #ifndef __ASM_MIPS_SOFTIRQ_H
 #define __ASM_MIPS_SOFTIRQ_H
@@ -17,6 +17,15 @@
 
 extern unsigned int local_bh_count[NR_CPUS];
 
+#define cpu_bh_disable(cpu)    do { local_bh_count[(cpu)]++; barrier(); } while (0)
+#define cpu_bh_enable(cpu)     do { barrier(); local_bh_count[(cpu)]--; } while (0)
+
+#define cpu_bh_trylock(cpu)    (local_bh_count[(cpu)] ? 0 : (local_bh_count[(cpu)] = 1))
+#define cpu_bh_endlock(cpu)    (local_bh_count[(cpu)] = 0)
+
+#define local_bh_disable()     cpu_bh_disable(smp_processor_id())
+#define local_bh_enable()      cpu_bh_enable(smp_processor_id())
+
 #define get_active_bhs()	(bh_mask & bh_active)
 
 static inline void clear_active_bhs(unsigned long x)
@@ -37,14 +46,15 @@
 extern inline void init_bh(int nr, void (*routine)(void))
 {
 	bh_base[nr] = routine;
-	bh_mask_count[nr] = 0;
+	atomic_set(&bh_mask_count[nr], 0);
 	bh_mask |= 1 << nr;
 }
 
 extern inline void remove_bh(int nr)
 {
-	bh_base[nr] = NULL;
 	bh_mask &= ~(1 << nr);
+	mb();
+	bh_base[nr] = NULL;
 }
 
 extern inline void mark_bh(int nr)
@@ -59,30 +69,30 @@
 extern inline void disable_bh(int nr)
 {
 	bh_mask &= ~(1 << nr);
-	bh_mask_count[nr]++;
+	atomic_inc(&bh_mask_count[nr]);
 }
 
 extern inline void enable_bh(int nr)
 {
-	if (!--bh_mask_count[nr])
+	if (atomic_dec_and_test(&bh_mask_count[nr]))
 		bh_mask |= 1 << nr;
 }
 
 extern inline void start_bh_atomic(void)
 {
-	local_bh_count[smp_processor_id()]++;
+	local_bh_disable();
 	barrier();
 }
 
 extern inline void end_bh_atomic(void)
 {
 	barrier();
-	local_bh_count[smp_processor_id()]--;
+	local_bh_enable();
 }
 
 /* These are for the irq's testing the lock */
-#define softirq_trylock(cpu)	(local_bh_count[cpu] ? 0 : (local_bh_count[cpu] = 1))
-#define softirq_endlock(cpu)	(local_bh_count[cpu] = 0)
+#define softirq_trylock(cpu)   (cpu_bh_trylock(cpu))
+#define softirq_endlock(cpu)   (cpu_bh_endlock(cpu))
 #define synchronize_bh()	barrier()
 
 #endif /* __ASM_MIPS_SOFTIRQ_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/spinlock.h linux/include/asm-mips/spinlock.h
--- v2.3.8/linux/include/asm-mips/spinlock.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/spinlock.h	Fri Jun 25 17:37:53 1999
@@ -1,8 +1,37 @@
-/* $Id: spinlock.h,v 1.3 1998/08/28 15:55:39 ralf Exp $
+/* $Id: spinlock.h,v 1.5 1999/06/17 13:30:39 ralf Exp $
  */
 #ifndef __ASM_MIPS_SPINLOCK_H
 #define __ASM_MIPS_SPINLOCK_H
 
+/*
+ * These are the generic versions of the spinlocks
+ * and read-write locks.. We should actually do a
+ * <linux/spinlock.h> with all of this. Oh, well.
+ */
+#define spin_lock_irqsave(lock, flags)		do { local_irq_save(flags);       spin_lock(lock); } while (0)
+#define spin_lock_irq(lock)			do { local_irq_disable();         spin_lock(lock); } while (0)
+#define spin_lock_bh(lock)			do { local_bh_disable();          spin_lock(lock); } while (0)
+
+#define read_lock_irqsave(lock, flags)		do { local_irq_save(flags);       read_lock(lock); } while (0)
+#define read_lock_irq(lock)			do { local_irq_disable();         read_lock(lock); } while (0)
+#define read_lock_bh(lock)			do { local_bh_disable();          read_lock(lock); } while (0)
+
+#define write_lock_irqsave(lock, flags)		do { local_irq_save(flags);      write_lock(lock); } while (0)
+#define write_lock_irq(lock)			do { local_irq_disable();        write_lock(lock); } while (0)
+#define write_lock_bh(lock)			do { local_bh_disable();         write_lock(lock); } while (0)
+
+#define spin_unlock_irqrestore(lock, flags)	do { spin_unlock(lock);  local_irq_restore(flags); } while (0)
+#define spin_unlock_irq(lock)			do { spin_unlock(lock);  local_irq_enable();       } while (0)
+#define spin_unlock_bh(lock)			do { spin_unlock(lock);  local_bh_enable();        } while (0)
+
+#define read_unlock_irqrestore(lock, flags)	do { read_unlock(lock);  local_irq_restore(flags); } while (0)
+#define read_unlock_irq(lock)			do { read_unlock(lock);  local_irq_enable();       } while (0)
+#define read_unlock_bh(lock)			do { read_unlock(lock);  local_bh_enable();        } while (0)
+
+#define write_unlock_irqrestore(lock, flags)	do { write_unlock(lock); local_irq_restore(flags); } while (0)
+#define write_unlock_irq(lock)			do { write_unlock(lock); local_irq_enable();       } while (0)
+#define write_unlock_bh(lock)			do { write_unlock(lock); local_bh_enable();        } while (0)
+
 #ifndef __SMP__
 
 /*
@@ -10,10 +39,10 @@
  */
 #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
   typedef struct { } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { }
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
 #else
   typedef struct { int gcc_is_buggy; } spinlock_t;
-  #define SPIN_LOCK_UNLOCKED { 0 }
+  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
 #endif
 
 #define spin_lock_init(lock)	do { } while(0)
@@ -21,11 +50,6 @@
 #define spin_trylock(lock)	(1)
 #define spin_unlock_wait(lock)	do { } while(0)
 #define spin_unlock(lock)	do { } while(0)
-#define spin_lock_irq(lock)	cli()
-#define spin_unlock_irq(lock)	sti()
-
-#define spin_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define spin_unlock_irqrestore(lock, flags)	restore_flags(flags)
 
 /*
  * Read-write spinlocks, allowing multiple readers
@@ -38,21 +62,12 @@
  * read-locks.
  */
 typedef struct { } rwlock_t;
-#define RW_LOCK_UNLOCKED { }
+#define RW_LOCK_UNLOCKED (rwlock_t) { }
 
 #define read_lock(lock)		do { } while(0)
 #define read_unlock(lock)	do { } while(0)
 #define write_lock(lock)	do { } while(0)
 #define write_unlock(lock)	do { } while(0)
-#define read_lock_irq(lock)	cli()
-#define read_unlock_irq(lock)	sti()
-#define write_lock_irq(lock)	cli()
-#define write_unlock_irq(lock)	sti()
-
-#define read_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define read_unlock_irqrestore(lock, flags)	restore_flags(flags)
-#define write_lock_irqsave(lock, flags)		save_and_cli(flags)
-#define write_unlock_irqrestore(lock, flags)	restore_flags(flags)
 
 #else
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/stackframe.h linux/include/asm-mips/stackframe.h
--- v2.3.8/linux/include/asm-mips/stackframe.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/stackframe.h	Fri Jun 25 17:37:53 1999
@@ -139,7 +139,12 @@
 		ori	t0, 0x1f;                        \
 		xori	t0, 0x1f;                        \
 		mtc0	t0, CP0_STATUS;                  \
+		li	v1, 0xff00;                      \
+		and	t0, v1;				 \
 		lw	v0, PT_STATUS(sp);               \
+		nor	v1, $0, v1;			 \
+		and	v0, v1;				 \
+		or	v0, t0;				 \
 		mtc0	v0, CP0_STATUS;                  \
 		lw	v1, PT_EPC(sp);                  \
 		mtc0	v1, CP0_EPC;                     \
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/string.h linux/include/asm-mips/string.h
--- v2.3.8/linux/include/asm-mips/string.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/string.h	Fri Jun 25 17:37:53 1999
@@ -96,16 +96,16 @@
   __asm__ __volatile__(
 	".set\tnoreorder\n\t"
 	".set\tnoat\n"
-	"1:\tlbu\t%3,(%0)\n\t"
+	"1:\tlbu\t%3,(%1)\n\t"
 	"beqz\t%2,2f\n\t"
-	"lbu\t$1,(%1)\n\t"
-	"subu\t%2,1\n\t"
-	"bne\t$1,%3,3f\n\t"
+	"lbu\t$1,(%0)\n\t"
+	"addiu\t%1,1\n\t"
+	"subu\t%3,$1,%3\n\t"
+	"bnez\t%3,2f\n\t"
 	"addiu\t%0,1\n\t"
-	"bnez\t%3,1b\n\t"
-	"addiu\t%1,1\n"
-	"2:\tmove\t%3,$1\n"
-	"3:\tsubu\t%3,$1\n\t"
+	"bnez\t%1,1b\n"
+	"addiu\t%2,-1\n"
+	"2:\n\t"
 	".set\tat\n\t"
 	".set\treorder"
 	: "=r" (__cs), "=r" (__ct), "=r" (__count), "=r" (__res)
@@ -132,12 +132,14 @@
 {
 	char *__end = (char *)__addr + __size;
 
-	__asm__(".set\tnoat\n"
+	__asm__(".set\tpush\n\t"
+		".set\tnoat\n\t"
+		".set\treorder\n\t"
 		"1:\tbeq\t%0,%1,2f\n\t"
 		"addiu\t%0,1\n\t"
 		"lb\t$1,-1(%0)\n\t"
 		"bne\t$1,%4,1b\n"
-		"2:\t.set\tat"
+		"2:\t.set\tpop"
 		: "=r" (__addr), "=r" (__end)
 		: "0" (__addr), "1" (__end), "r" (__c)
 		: "$1");
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/system.h linux/include/asm-mips/system.h
--- v2.3.8/linux/include/asm-mips/system.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/system.h	Fri Jun 25 17:37:53 1999
@@ -88,6 +88,12 @@
 {
 	__asm__ __volatile__(
 		".set\tnoreorder\n\t"
+		"mfc0\t$8,$12\n\t"
+		"li\t$9,0xff00\n\t"
+		"and\t$8,$9\n\t"
+		"nor\t$9,$0,$9\n\t"
+		"and\t%0,$9\n\t"
+		"or\t%0,$8\n\t"
 		"mtc0\t%0,$12\n\t"
 		"nop\n\t"
 		"nop\n\t"
@@ -95,7 +101,7 @@
 		".set\treorder"
 		: /* no output */
 		: "r" (flags)
-		: "memory");
+		: "$8", "$9", "memory");
 }
 
 /*
@@ -107,6 +113,15 @@
 #define save_and_cli(x) __save_and_cli(x)
 #define restore_flags(x) __restore_flags(x)
 
+/* For spinlocks etc */
+#define local_irq_save(x)	__save_and_cli(x);
+#define local_irq_restore(x)	__restore_flags(x);
+#define local_irq_disable()	__cli();
+#define local_irq_enable()	__sti();
+
+/*
+ * These are probably defined overly paranoid ...
+ */
 #define mb()						\
 __asm__ __volatile__(					\
 	"# prevent instructions being moved around\n\t"	\
@@ -117,18 +132,20 @@
 	: /* no output */				\
 	: /* no input */				\
 	: "memory")
+#define rmb() mb()
+#define wmb() mb()
 
 #if !defined (_LANGUAGE_ASSEMBLY)
 /*
  * switch_to(n) should switch tasks to task nr n, first
  * checking that n isn't the current task, in which case it does nothing.
  */
-extern asmlinkage void (*resume)(void *tsk);
+extern asmlinkage void *(*resume)(void *last, void *next);
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
-#define switch_to(prev,next) \
+#define switch_to(prev,next,last) \
 do { \
-	resume(next); \
+	(last) = resume(prev, next); \
 } while(0)
 
 /*
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/timex.h linux/include/asm-mips/timex.h
--- v2.3.8/linux/include/asm-mips/timex.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/timex.h	Fri Jun 25 17:37:53 1999
@@ -1,10 +1,10 @@
-/* $Id: timex.h,v 1.1 1998/08/17 10:20:18 ralf Exp $
+/* $Id: timex.h,v 1.2 1999/02/15 02:22:14 ralf Exp $
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1998 by Ralf Baechle
+ * Copyright (C) 1998, 1999 by Ralf Baechle
  *
  * FIXME: For some of the supported machines this is dead wrong.
  */
@@ -16,5 +16,24 @@
 #define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
+
+/*
+ * Standard way to access the cycle counter.
+ * Currently only used on SMP for scheduling.
+ *
+ * Only the low 32 bits are available as a continuously counting entity. 
+ * But this only means we'll force a reschedule every 8 seconds or so,
+ * which isn't an evil thing.
+ *
+ * We know that all SMP capable CPUs have cycle counters.
+ */
+
+typedef unsigned int cycles_t;
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles (void)
+{
+	return read_32bit_cp0_register(CP0_COUNT);
+}
 
 #endif /*  __ASM_MIPS_TIMEX_H */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/uaccess.h linux/include/asm-mips/uaccess.h
--- v2.3.8/linux/include/asm-mips/uaccess.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/uaccess.h	Fri Jun 25 17:37:53 1999
@@ -265,6 +265,21 @@
 
 extern void __put_user_unknown(void);
 
+/*
+ * We're generating jump to subroutines which will be outside the range of
+ * jump instructions
+ */
+#ifdef MODULE
+#define __MODULE_JAL(destination) \
+	".set\tnoat\n\t" \
+	"la\t$1, " #destination "\n\t" \
+	"jalr\t$1\n\t" \
+	".set\tat\n\t"
+#else
+#define __MODULE_JAL(destination) \
+	"jal\t" #destination "\n\t"
+#endif
+
 #define copy_to_user_ret(to,from,n,retval) ({ \
 if (copy_to_user(to,from,n)) \
         return retval; \
@@ -289,7 +304,7 @@
 		"move\t$4, %1\n\t" \
 		"move\t$5, %2\n\t" \
 		"move\t$6, %3\n\t" \
-		"jal\t__copy_user\n\t" \
+		__MODULE_JAL(__copy_user) \
 		"move\t%0, $6" \
 		: "=r" (__cu_len) \
 		: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
@@ -313,7 +328,7 @@
 		".set\tnoat\n\t" \
 		"addu\t$1, %2, %3\n\t" \
 		".set\tat\n\t" \
-		"jal\t__copy_user\n\t" \
+		__MODULE_JAL(__copy_user) \
 		"move\t%0, $6" \
 		: "=r" (__cu_len) \
 		: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
@@ -335,7 +350,7 @@
 			"move\t$4, %1\n\t" \
 			"move\t$5, %2\n\t" \
 			"move\t$6, %3\n\t" \
-			"jal\t__copy_user\n\t" \
+			__MODULE_JAL(__copy_user) \
 			"move\t%0, $6" \
 			: "=r" (__cu_len) \
 			: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
@@ -360,7 +375,7 @@
 			".set\tnoat\n\t" \
 			"addu\t$1, %2, %3\n\t" \
 			".set\tat\n\t" \
-			"jal\t__copy_user\n\t" \
+			__MODULE_JAL(__copy_user) \
 			"move\t%0, $6" \
 			: "=r" (__cu_len) \
 			: "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
@@ -378,7 +393,7 @@
 		"move\t$4, %1\n\t"
 		"move\t$5, $0\n\t"
 		"move\t$6, %2\n\t"
-		"jal\t__bzero\n\t"
+		__MODULE_JAL(__bzero)
 		"move\t%0, $6"
 		: "=r" (res)
 		: "r" (addr), "r" (size)
@@ -407,7 +422,7 @@
 		"move\t$4, %1\n\t"
 		"move\t$5, %2\n\t"
 		"move\t$6, %3\n\t"
-		"jal\t__strncpy_from_user_nocheck_asm\n\t"
+		__MODULE_JAL(__strncpy_from_user_nocheck_asm)
 		"move\t%0, $2"
 		: "=r" (res)
 		: "r" (__to), "r" (__from), "r" (__len)
@@ -425,7 +440,7 @@
 		"move\t$4, %1\n\t"
 		"move\t$5, %2\n\t"
 		"move\t$6, %3\n\t"
-		"jal\t__strncpy_from_user_asm\n\t"
+		__MODULE_JAL(__strncpy_from_user_asm)
 		"move\t%0, $2"
 		: "=r" (res)
 		: "r" (__to), "r" (__from), "r" (__len)
@@ -442,7 +457,7 @@
 
 	__asm__ __volatile__(
 		"move\t$4, %1\n\t"
-		"jal\t__strlen_user_nocheck_asm\n\t"
+		__MODULE_JAL(__strlen_user_nocheck_asm)
 		"move\t%0, $2"
 		: "=r" (res)
 		: "r" (s)
@@ -457,7 +472,7 @@
 
 	__asm__ __volatile__(
 		"move\t$4, %1\n\t"
-		"jal\t__strlen_user_asm\n\t"
+		__MODULE_JAL(__strlen_user_asm)
 		"move\t%0, $2"
 		: "=r" (res)
 		: "r" (s)
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/umap.h linux/include/asm-mips/umap.h
--- v2.3.8/linux/include/asm-mips/umap.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/umap.h	Fri Jun 25 17:37:53 1999
@@ -0,0 +1,8 @@
+#ifndef __MIPS_UMAP_H
+#define __MIPS_UMAP_H
+
+void remove_mapping (struct task_struct *task, unsigned long start,
+unsigned long end);
+
+#endif 
+
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/unistd.h linux/include/asm-mips/unistd.h
--- v2.3.8/linux/include/asm-mips/unistd.h	Tue Oct 20 13:52:54 1998
+++ linux/include/asm-mips/unistd.h	Fri Jun 25 17:37:53 1999
@@ -1300,7 +1300,7 @@
                                       "r" ((long)(b)), \
                                       "r" ((long)(c)), \
                                       "r" ((long)(d)) \
-                  : "$4","$5","$6""$8","$9","$10","$11","$12","$13","$14", \
+                  : "$4","$5","$6","$8","$9","$10","$11","$12","$13","$14", \
                     "$15","$24"); \
 if (__err == 0) \
 	return (type) __res; \
@@ -1424,6 +1424,8 @@
 static inline _syscall0(int,sync)
 static inline _syscall0(pid_t,setsid)
 static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
+static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
 static inline _syscall1(int,dup,int,fd)
 static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
 static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
@@ -1435,48 +1437,6 @@
 static inline pid_t wait(int * wait_stat)
 {
 	return waitpid(-1,wait_stat,0);
-}
-
-/*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be free'd until both the parent and the child have exited.
- */
-static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-	long retval;
-
-	__asm__ __volatile__(
-		".set\tnoreorder\n\t"
-		"move\t$6,$sp\n\t"
-		"move\t$4,%5\n\t"
-		"li\t$2,%1\n\t"
-		"syscall\n\t"
-		"beq\t$6,$sp,1f\n\t"
-		"subu\t$sp,32\n\t"	/* delay slot */
-		"jalr\t%4\n\t"
-		"move\t$4,%3\n\t"	/* delay slot */
-		"move\t$4,$2\n\t"
-		"li\t$2,%2\n\t"
-		"syscall\n"
-		"1:\taddiu\t$sp,32\n\t"
-		"move\t%0,$2\n\t"
-		".set\treorder"
-		:"=r" (retval)
-		:"i" (__NR_clone), "i" (__NR_exit),
-		 "r" (arg), "r" (fn),
-		 "r" (flags | CLONE_VM)
-		 /*
-		  * The called subroutine might have destroyed any of the
-		  * at, result, argument or temporary registers ...
-		  */
-		:"$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
-		 "$9","$10","$11","$12","$13","$14","$15","$24","$25");
-
-	return retval;
 }
 
 #endif /* !defined (__KERNEL_SYSCALLS__) */
diff -u --recursive --new-file v2.3.8/linux/include/asm-mips/vga.h linux/include/asm-mips/vga.h
--- v2.3.8/linux/include/asm-mips/vga.h	Thu Feb 25 10:02:12 1999
+++ linux/include/asm-mips/vga.h	Fri Jun 25 17:37:53 1999
@@ -7,29 +7,14 @@
 #ifndef _LINUX_ASM_VGA_H_
 #define _LINUX_ASM_VGA_H_
 
-#include <asm/io.h>
+/*
+ *	On the PC, we can just recalculate addresses and then
+ *	access the videoram directly without any black magic.
+ */
 
-#define VT_BUF_HAVE_RW
+#define VGA_MAP_MEM(x) ((unsigned long)0xb0000000 + (unsigned long)(x))
 
-extern inline void scr_writew(u16 val, u16 *addr)
-{
-	if ((long) addr < 0)
-		*addr = val;
-	else
-		writew(val, (unsigned long) addr);
-}
-
-extern inline u16 scr_readw(const u16 *addr)
-{
-	if ((long) addr < 0)
-		return *addr;
-	else
-		return readw((unsigned long) addr);
-}
-
-#define vga_readb readb
-#define vga_writeb writeb
-
-#define VGA_MAP_MEM(x) (x)
+#define vga_readb(x) (*(x))
+#define vga_writeb(x,y) (*(y) = (x))
 
 #endif
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/hardirq.h linux/include/asm-ppc/hardirq.h
--- v2.3.8/linux/include/asm-ppc/hardirq.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/hardirq.h	Mon Jun 28 13:40:39 1999
@@ -1,6 +1,8 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
+#include <asm/smp.h>
+
 extern unsigned int ppc_local_irq_count[NR_CPUS];
 
 /*
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/hydra.h linux/include/asm-ppc/hydra.h
--- v2.3.8/linux/include/asm-ppc/hydra.h	Mon Jan 12 15:18:13 1998
+++ linux/include/asm-ppc/hydra.h	Mon Jun 28 13:40:39 1999
@@ -85,13 +85,13 @@
 #define HYDRA_INT_VIA		9
 #define HYDRA_INT_ADB		10
 #define HYDRA_INT_ADB_NMI	11
-#define HYDRA_INT_EXT1		12
-#define HYDRA_INT_EXT2		13
-#define HYDRA_INT_EXT3		14
-#define HYDRA_INT_EXT4		15
-#define HYDRA_INT_EXT5		16
-#define HYDRA_INT_EXT6		17
-#define HYDRA_INT_EXT7		18
+#define HYDRA_INT_EXT1		12	/* PCI IRQW */
+#define HYDRA_INT_EXT2		13	/* PCI IRQX */
+#define HYDRA_INT_EXT3		14	/* PCI IRQY */
+#define HYDRA_INT_EXT4		15	/* PCI IRQZ */
+#define HYDRA_INT_EXT5		16	/* IDE Primay/Secondary */
+#define HYDRA_INT_EXT6		17	/* IDE Secondary */
+#define HYDRA_INT_EXT7		18	/* Power Off Request */
 #define HYDRA_INT_SPARE		19
 
 extern int hydra_init(void);
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.3.8/linux/include/asm-ppc/ide.h	Sat May 22 13:03:00 1999
+++ linux/include/asm-ppc/ide.h	Mon Jun 28 13:40:39 1999
@@ -1,8 +1,7 @@
 /*
  *  linux/include/asm-ppc/ide.h
  *
- *  Copyright (C) 1994-1996  Linus Torvalds & authors
- */
+ *  Copyright (C) 1994-1996 Linus Torvalds & authors */
 
 /*
  *  This file contains the ppc architecture specific IDE code.
@@ -42,11 +41,11 @@
         void        (*outsw)(ide_ioreg_t port, void *buf, int ns);
         int         (*default_irq)(ide_ioreg_t base);
         ide_ioreg_t (*default_io_base)(int index);
-        int         (*check_region)(ide_ioreg_t from, unsigned int extent);
-        void        (*request_region)(ide_ioreg_t from,
+        int         (*ide_check_region)(ide_ioreg_t from, unsigned int extent);
+        void        (*ide_request_region)(ide_ioreg_t from,
                                       unsigned int extent,
                                       const char *name);
-        void        (*release_region)(ide_ioreg_t from,
+        void        (*ide_release_region)(ide_ioreg_t from,
                                       unsigned int extent);
         void        (*fix_driveid)(struct hd_driveid *id);
         void        (*ide_init_hwif)(hw_regs_t *hw,
@@ -59,7 +58,6 @@
 
 extern struct ide_machdep_calls ppc_ide_md;
 
-void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
 void ide_insw(ide_ioreg_t port, void *buf, int ns);
 void ide_outsw(ide_ioreg_t port, void *buf, int ns);
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
@@ -97,6 +95,14 @@
 		return -1;
 }
 
+static __inline__ void  ide_init_hwif_ports(hw_regs_t *hw,
+					   ide_ioreg_t data_port,
+					   ide_ioreg_t ctrl_port, int *irq)
+{
+	if (ppc_ide_md.ide_init_hwif != NULL)
+		ppc_ide_md.ide_init_hwif(hw, data_port, ctrl_port, irq);
+}
+
 static __inline__ void ide_init_default_hwifs(void)
 {
 #ifdef __DO_I_NEED_THIS
@@ -113,22 +119,22 @@
 
 static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 {
-	if ( ppc_ide_md.check_region )
-		return ppc_ide_md.check_region(from, extent);
+	if ( ppc_ide_md.ide_check_region )
+		return ppc_ide_md.ide_check_region(from, extent);
 	else
 		return -1;
 }
 
 static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
 {
-	if ( ppc_ide_md.request_region )
-		ppc_ide_md.request_region(from, extent, name);
+	if ( ppc_ide_md.ide_request_region )
+		ppc_ide_md.ide_request_region(from, extent, name);
 }
 
 static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
 {
-	if ( ppc_ide_md.release_region )
-		ppc_ide_md.release_region(from, extent);
+	if ( ppc_ide_md.ide_release_region )
+		ppc_ide_md.ide_release_region(from, extent);
 }
 
 static __inline__ void ide_fix_driveid (struct hd_driveid *id)
@@ -137,6 +143,7 @@
 		ppc_ide_md.fix_driveid(id);
 }
 
+#if 0	/* inb/outb from io.h is OK now -- paulus */
 #undef inb
 #define inb(port)	in_8((unsigned char *)((port) + ppc_ide_md.io_base))
 #undef inb_p
@@ -147,6 +154,7 @@
 	out_8((unsigned char *)((port) + ppc_ide_md.io_base), (val) )
 #undef outb_p
 #define outb_p(val, port)	outb(val, port)
+#endif
 
 typedef union {
 	unsigned all			: 8;	/* all of the bits together */
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.3.8/linux/include/asm-ppc/irq.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/irq.h	Mon Jun 28 13:40:39 1999
@@ -6,6 +6,7 @@
 #include <asm/machdep.h>		/* ppc_md */
 
 extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
 extern void enable_irq(unsigned int);
 
 #ifndef CONFIG_8xx
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.3.8/linux/include/asm-ppc/keyboard.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/keyboard.h	Mon Jun 28 13:40:39 1999
@@ -57,13 +57,9 @@
 	ppc_md.kbd_init_hw();
 }
 
-#define kbd_sysrq_xlate	(ppc_md.kbd_sysrq_xlate)
+#define kbd_sysrq_xlate	(ppc_md.ppc_kbd_sysrq_xlate)
 
-#ifdef CONFIG_MAC_KEYBOARD
-# define SYSRQ_KEY 0x69
-#else
-# define SYSRQ_KEY 0x54
-#endif
+extern unsigned long SYSRQ_KEY;
 
 #endif /* CONFIG_APUS */
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- v2.3.8/linux/include/asm-ppc/machdep.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/machdep.h	Mon Jun 28 13:40:39 1999
@@ -35,6 +35,10 @@
 	unsigned long	(*get_rtc_time)(void);
 	void		(*calibrate_decr)(void);
 
+	void		(*heartbeat)(void);
+	unsigned long	heartbeat_reset;
+	unsigned long	heartbeat_count;
+
 	unsigned char 	(*nvram_read_val)(int addr);
 	void		(*nvram_write_val)(int addr, unsigned char val);
 
@@ -49,7 +53,7 @@
 	void		(*kbd_leds)(unsigned char leds);
 	void		(*kbd_init_hw)(void);
 #ifdef CONFIG_MAGIC_SYSRQ
-	unsigned char 	*kbd_sysrq_xlate;
+	unsigned char 	*ppc_kbd_sysrq_xlate;
 #endif
 
 	/* PCI interfaces */
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- v2.3.8/linux/include/asm-ppc/page.h	Thu Apr 29 12:39:01 1999
+++ linux/include/asm-ppc/page.h	Mon Jun 28 13:40:39 1999
@@ -14,6 +14,19 @@
 #ifndef __ASSEMBLY__
 #ifdef __KERNEL__
 
+#ifdef CONFIG_XMON
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	xmon(0); \
+} while (0)
+#else
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	__asm__ __volatile__(".long 0x0"); \
+}
+#endif
+#define PAGE_BUG(page) do { BUG(); } while (0)
+
 #define STRICT_MM_TYPECHECKS
 
 #ifdef STRICT_MM_TYPECHECKS
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.3.8/linux/include/asm-ppc/pgtable.h	Sat May 22 13:03:00 1999
+++ linux/include/asm-ppc/pgtable.h	Fri Jun 25 17:36:12 1999
@@ -213,7 +213,7 @@
 #endif __ASSEMBLY__
 #define BAD_PAGETABLE	__bad_pagetable()
 #define BAD_PAGE	__bad_page()
-#define ZERO_PAGE	((unsigned long) empty_zero_page)
+#define ZERO_PAGE(vaddr)	((unsigned long) empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR	(8*sizeof(unsigned long))
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.3.8/linux/include/asm-ppc/processor.h	Tue May 25 14:55:05 1999
+++ linux/include/asm-ppc/processor.h	Mon Jun 28 13:40:39 1999
@@ -208,6 +208,11 @@
 void release_thread(struct task_struct *);
 
 /*
+ * Create a new kernel thread.
+ */
+extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+/*
  * Bus types
  */
 #define EISA_bus 0
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/ptrace.h linux/include/asm-ppc/ptrace.h
--- v2.3.8/linux/include/asm-ppc/ptrace.h	Wed May 26 16:55:40 1999
+++ linux/include/asm-ppc/ptrace.h	Wed Jun 30 11:24:55 1999
@@ -21,25 +21,25 @@
 
 #ifndef __ASSEMBLY__
 #ifdef CONFIG_PPC64
-#define REG unsigned long /*long*/
+#define PPC_REG unsigned long /*long*/
 #else
-#define REG unsigned long
+#define PPC_REG unsigned long
 #endif
 struct pt_regs {
-	REG gpr[32];
-	REG nip;
-	REG msr;
-	REG orig_gpr3;	/* Used for restarting system calls */
-	REG ctr;
-	REG link;
-	REG xer;
-	REG ccr;
-	REG mq;		/* 601 only (not used at present) */
-			/* Used on APUS to hold IPL value. */
-	REG trap;	/* Reason for being here */
-	REG dar;	/* Fault registers */
-	REG dsisr;
-	REG result;   	/* Result of a system call */
+	PPC_REG gpr[32];
+	PPC_REG nip;
+	PPC_REG msr;
+	PPC_REG orig_gpr3;	/* Used for restarting system calls */
+	PPC_REG ctr;
+	PPC_REG link;
+	PPC_REG xer;
+	PPC_REG ccr;
+	PPC_REG mq;		/* 601 only (not used at present) */
+				/* Used on APUS to hold IPL value. */
+	PPC_REG trap;		/* Reason for being here */
+	PPC_REG dar;		/* Fault registers */
+	PPC_REG dsisr;
+	PPC_REG result; 	/* Result of a system call */
 };
 #endif
 
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/softirq.h linux/include/asm-ppc/softirq.h
--- v2.3.8/linux/include/asm-ppc/softirq.h	Thu Apr 29 12:39:07 1999
+++ linux/include/asm-ppc/softirq.h	Mon Jun 28 13:40:39 1999
@@ -4,11 +4,11 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-extern unsigned int ppc_local_bh_count[NR_CPUS];
-
 #define get_active_bhs()	(bh_mask & bh_active)
 #define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
 
+extern unsigned int ppc_local_bh_count[NR_CPUS];
+
 extern inline void init_bh(int nr, void (*routine)(void))
 {
 	bh_base[nr] = routine;
@@ -20,7 +20,7 @@
 {
 	bh_mask &= ~(1 << nr);
 	wmb();
-	bh_base[nr] = NULL;
+	bh_base[nr] = 0;
 }
 
 extern inline void mark_bh(int nr)
@@ -55,7 +55,8 @@
 static inline int softirq_trylock(int cpu)
 {
 	if (!test_and_set_bit(0,&global_bh_count)) {
-		if (atomic_read(&global_bh_lock) == 0) {
+		if (atomic_read(&global_bh_lock) &&
+		    ppc_local_bh_count[cpu] == 0) {
 			++ppc_local_bh_count[cpu];
 			return 1;
 		}
@@ -90,6 +91,9 @@
 #define synchronize_bh()	barrier()
 
 #endif	/* SMP */
+
+#define local_bh_disable()	(ppc_local_bh_count[smp_processor_id()]++)
+#define local_bh_enable()	(ppc_local_bh_count[smp_processor_id()]--)
 
 /*
  * These use a mask count to correctly handle
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/spinlock.h linux/include/asm-ppc/spinlock.h
--- v2.3.8/linux/include/asm-ppc/spinlock.h	Wed Mar 10 21:30:32 1999
+++ linux/include/asm-ppc/spinlock.h	Mon Jun 28 13:40:39 1999
@@ -2,7 +2,6 @@
 #define __ASM_SPINLOCK_H
 
 #ifndef __SMP__
-
 /*
  * Your basic spinlocks, allowing only a single CPU anywhere
  *
@@ -18,14 +17,16 @@
 
 #define spin_lock_init(lock)	do { } while(0)
 #define spin_lock(lock)		do { } while(0)
-#define spin_trylock(lock)	do { } while(0)
+#define spin_trylock(lock)	(1)
 #define spin_unlock_wait(lock)	do { } while(0)
 #define spin_unlock(lock)	do { } while(0)
 #define spin_lock_irq(lock)	cli()
 #define spin_unlock_irq(lock)	sti()
-
+#define spin_lock_bh(lock)	local_bh_disable()
+#define spin_unlock_bh(lock)	local_bh_enable()
 #define spin_lock_irqsave(lock, flags) \
 	do { save_flags(flags); cli(); } while (0)
+
 #define spin_unlock_irqrestore(lock, flags) \
 	restore_flags(flags)
 
@@ -57,6 +58,10 @@
 #define read_unlock_irq(lock)	sti()
 #define write_lock_irq(lock)	cli()
 #define write_unlock_irq(lock)	sti()
+#define read_lock_bh(lock)	local_bh_disable()
+#define read_unlock_bh(lock)	local_bh_enable()
+#define write_lock_bh(lock)	local_bh_disable()
+#define write_unlock_bh(lock)	local_bh_enable()
 
 #define read_lock_irqsave(lock, flags)	\
 	do { save_flags(flags); cli(); } while (0)
@@ -94,8 +99,11 @@
 
 #define spin_lock_irq(lock) \
 	do { __cli(); spin_lock(lock); } while (0)
+#define spin_lock_bh(___lk) do { local_bh_disable(); spin_lock(___lk); } while(0)
+
 #define spin_unlock_irq(lock) \
 	do { spin_unlock(lock); __sti(); } while (0)
+#define spin_unlock_bh(___lk) do { spin_unlock(___lk); local_bh_enable(); } while(0)
 
 #define spin_lock_irqsave(lock, flags) \
 	do { __save_flags(flags); __cli(); spin_lock(lock); } while (0)
@@ -132,10 +140,13 @@
 #define read_unlock(rw)		_read_unlock(rw)
 
 #define read_lock_irq(lock)	do { __cli(); read_lock(lock); } while (0)
+#define read_lock_bh(lock)	do { local_bh_disable(); read_lock(lock); } while (0)
 #define read_unlock_irq(lock)	do { read_unlock(lock); __sti(); } while (0)
+#define read_unlock_bh(lock)	do { read_unlock(lock); local_bh_enable(); } while (0)
 #define write_lock_irq(lock)	do { __cli(); write_lock(lock); } while (0)
+#define write_lock_bh(lock)	do { local_bh_disable(); write_lock(lock); } while(0)
 #define write_unlock_irq(lock)	do { write_unlock(lock); __sti(); } while (0)
-
+#define write_unlock_bh(lock)	do { write_unlock(lock); local_bh_enable(); } while(0)
 #define read_lock_irqsave(lock, flags)	\
 	do { __save_flags(flags); __cli(); read_lock(lock); } while (0)
 #define read_unlock_irqrestore(lock, flags) \
@@ -147,12 +158,3 @@
 
 #endif /* SMP */
 #endif /* __ASM_SPINLOCK_H */
-
-
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.3.8/linux/include/asm-ppc/unistd.h linux/include/asm-ppc/unistd.h
--- v2.3.8/linux/include/asm-ppc/unistd.h	Wed Mar 10 21:30:32 1999
+++ linux/include/asm-ppc/unistd.h	Mon Jun 28 13:40:39 1999
@@ -378,16 +378,6 @@
  */
 
 /*
- * Create a new kernel thread.
- */
-extern long __kernel_thread(unsigned long, int (*)(void *), void *);
-
-static inline long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-	return __kernel_thread(flags | CLONE_VM, fn, arg);
-}
-
-/*
  * System call prototypes.
  */
 #define __NR__exit __NR_exit
diff -u --recursive --new-file v2.3.8/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v2.3.8/linux/include/asm-sparc/page.h	Thu Jun 17 01:08:50 1999
+++ linux/include/asm-sparc/page.h	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.43 1998/05/11 08:40:11 davem Exp $
+/* $Id: page.h,v 1.44 1999/06/23 03:53:11 davem Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
diff -u --recursive --new-file v2.3.8/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.3.8/linux/include/asm-sparc/pgtable.h	Thu May 27 09:55:21 1999
+++ linux/include/asm-sparc/pgtable.h	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.80 1999/05/27 04:52:40 davem Exp $ */
+/* $Id: pgtable.h,v 1.81 1999/06/27 00:38:28 davem Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -177,7 +177,7 @@
 
 #define BAD_PAGETABLE __bad_pagetable()
 #define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long)(&(empty_zero_page)))
+#define ZERO_PAGE(vaddr) ((unsigned long)(&(empty_zero_page)))
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR      (8*sizeof(unsigned long))
diff -u --recursive --new-file v2.3.8/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- v2.3.8/linux/include/asm-sparc64/page.h	Thu Jun 17 01:08:50 1999
+++ linux/include/asm-sparc64/page.h	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.24 1998/10/20 03:09:16 jj Exp $ */
+/* $Id: page.h,v 1.25 1999/06/23 03:53:15 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
diff -u --recursive --new-file v2.3.8/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.3.8/linux/include/asm-sparc64/pgtable.h	Thu May 27 09:55:22 1999
+++ linux/include/asm-sparc64/pgtable.h	Tue Jun 29 09:22:08 1999
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.105 1999/05/27 04:52:51 davem Exp $
+/* $Id: pgtable.h,v 1.106 1999/06/27 00:38:33 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -157,7 +157,7 @@
  * hit for all __pa()/__va() operations.
  */
 extern unsigned long phys_base;
-#define ZERO_PAGE	((unsigned long)__va(phys_base))
+#define ZERO_PAGE(vaddr)	((unsigned long)__va(phys_base))
 
 /* Allocate a block of RAM which is aligned to its size.
  * This procedure can be used until the call to mem_init().
diff -u --recursive --new-file v2.3.8/linux/include/linux/a.out.h linux/include/linux/a.out.h
--- v2.3.8/linux/include/linux/a.out.h	Tue Jun 22 14:41:40 1999
+++ linux/include/linux/a.out.h	Wed Jun 30 12:42:43 1999
@@ -34,7 +34,7 @@
   /* skip a bunch so we don't run into any of sun's numbers */
   M_386 = 100,
   M_MIPS1 = 151,	/* MIPS R3000/R3000 binary */
-  M_MIPS2 = 152,	/* MIPS R6000/R4000 binary */
+  M_MIPS2 = 152		/* MIPS R6000/R4000 binary */
 };
 
 #if !defined (N_MAGIC)
diff -u --recursive --new-file v2.3.8/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.3.8/linux/include/linux/binfmts.h	Tue Jun 22 14:41:46 1999
+++ linux/include/linux/binfmts.h	Wed Jun 30 12:42:44 1999
@@ -21,7 +21,6 @@
 	unsigned long page[MAX_ARG_PAGES];
 	unsigned long p; /* current top of mem */
 	int sh_bang;
-	int java;		/* Java binary, prevent recursive invocation */
 	struct dentry * dentry;
 	int e_uid, e_gid;
 	kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
@@ -52,10 +51,10 @@
 
 extern int init_elf_binfmt(void);
 extern int init_elf32_binfmt(void);
+extern int init_irix_binfmt(void);
 extern int init_aout_binfmt(void);
 extern int init_aout32_binfmt(void);
 extern int init_script_binfmt(void);
-extern int init_java_binfmt(void);
 extern int init_em86_binfmt(void);
 extern int init_misc_binfmt(void);
 
diff -u --recursive --new-file v2.3.8/linux/include/linux/cyclomx.h linux/include/linux/cyclomx.h
--- v2.3.8/linux/include/linux/cyclomx.h	Wed Jun  2 14:40:22 1999
+++ linux/include/linux/cyclomx.h	Wed Jun 30 11:24:55 1999
@@ -21,6 +21,7 @@
 #ifndef	_CYCLOMX_H
 #define	_CYCLOMX_H
 
+#include <linux/config.h>
 #include <linux/wanrouter.h>
 #include <asm/spinlock.h>
 
diff -u --recursive --new-file v2.3.8/linux/include/linux/epcaconfig.h linux/include/linux/epcaconfig.h
--- v2.3.8/linux/include/linux/epcaconfig.h	Tue May 13 22:41:18 1997
+++ linux/include/linux/epcaconfig.h	Thu Jun 24 12:04:12 1999
@@ -1,8 +1,7 @@
-#define NUMCARDS 1
-#define NBDEVS 2
+#define NUMCARDS 0
+#define NBDEVS 0
 
 struct board_info static_boards[NUMCARDS]={
-	{ ENABLED, 0, OFF, 2, (unchar*) 0x320, (unchar*) 0xd0000 },
 };
 
 /* DO NOT HAND EDIT THIS FILE! */
diff -u --recursive --new-file v2.3.8/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.3.8/linux/include/linux/ext2_fs.h	Wed Jun 16 19:26:27 1999
+++ linux/include/linux/ext2_fs.h	Sat Jun 26 12:04:40 1999
@@ -553,7 +553,8 @@
 extern void ext2_check_inodes_bitmap (struct super_block *);
 
 /* inode.c */
-extern int ext2_bmap (struct inode *, int);
+extern long ext2_bmap (struct inode *, long);
+extern int ext2_get_block (struct inode *, long, struct buffer_head *, int);
 
 extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
 extern int ext2_getblk_block (struct inode *, long, int, int *, int *);
diff -u --recursive --new-file v2.3.8/linux/include/linux/file.h linux/include/linux/file.h
--- v2.3.8/linux/include/linux/file.h	Tue Jun  8 10:47:58 1999
+++ linux/include/linux/file.h	Mon Jun 28 11:44:04 1999
@@ -26,18 +26,27 @@
 extern inline struct file * fcheck(unsigned int fd)
 {
 	struct file * file = NULL;
+	struct files_struct *files = current->files;
 
-	if (fd < current->files->max_fds)
-		file = current->files->fd[fd];
+	read_lock(&files->file_lock);
+	if (fd < files->max_fds)
+		file = files->fd[fd];
+	read_unlock(&files->file_lock);
 	return file;
 }
 
 extern inline struct file * fget(unsigned int fd)
 {
-	struct file * file = fcheck(fd);
+	struct file * file = NULL;
+	struct files_struct *files = current->files;
 
-	if (file)
-		file->f_count++;
+	read_lock(&files->file_lock);
+	if (fd < files->max_fds) {
+		file = files->fd[fd];
+		if (file)
+			atomic_inc(&file->f_count);
+	}
+	read_unlock(&files->file_lock);
 	return file;
 }
 
@@ -46,7 +55,11 @@
  */
 extern inline void fd_install(unsigned int fd, struct file * file)
 {
-	current->files->fd[fd] = file;
+	struct files_struct *files = current->files;
+
+	write_lock(&files->file_lock);
+	files->fd[fd] = file;
+	write_unlock(&files->file_lock);
 }
 
 /*
diff -u --recursive --new-file v2.3.8/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.8/linux/include/linux/fs.h	Tue Jun 22 14:41:43 1999
+++ linux/include/linux/fs.h	Wed Jun 30 12:42:44 1999
@@ -188,51 +188,50 @@
 #define BH_Dirty	1	/* 1 if the buffer is dirty */
 #define BH_Lock		2	/* 1 if the buffer is locked */
 #define BH_Req		3	/* 0 if the buffer has been invalidated */
+#define BH_Mapped	4	/* 1 if the buffer has a disk mapping */
+#define BH_New		5	/* 1 if the buffer is new and not yet written out */
 #define BH_Protected	6	/* 1 if the buffer is protected */
+
 /*
  * Try to keep the most commonly used fields in single cache lines (16
  * bytes) to improve performance.  This ordering should be
  * particularly beneficial on 32-bit processors.
  * 
  * We use the first 16 bytes for the data which is used in searches
- * over the block hash lists (ie. getblk(), find_buffer() and
- * friends).
+ * over the block hash lists (ie. getblk() and friends).
  * 
  * The second 16 bytes we use for lru buffer scans, as used by
  * sync_buffers() and refill_freelist().  -- sct
  */
 struct buffer_head {
 	/* First cache line: */
-	struct buffer_head * b_next;	/* Hash queue list */
+	struct buffer_head *b_next;	/* Hash queue list */
 	unsigned long b_blocknr;	/* block number */
-	unsigned long b_size;		/* block size */
+	unsigned short b_size;		/* block size */
+	unsigned short b_list;		/* List that this buffer appears */
 	kdev_t b_dev;			/* device (B_FREE = free) */
+
+	atomic_t b_count;		/* users using this block */
 	kdev_t b_rdev;			/* Real device */
-	unsigned long b_rsector;	/* Real buffer location on disk */
-	struct buffer_head * b_this_page;	/* circular list of buffers in one page */
 	unsigned long b_state;		/* buffer state bitmap (see above) */
-	struct buffer_head * b_next_free;
-	unsigned int b_count;		/* users using this block */
-
-	/* Non-performance-critical data follows. */
-	char * b_data;			/* pointer to data block (1024 bytes) */
-	unsigned int b_list;		/* List that this buffer appears */
-	unsigned long b_flushtime;	/* Time when this (dirty) buffer
-					 * should be written */
-	wait_queue_head_t b_wait;
-	struct buffer_head ** b_pprev;		/* doubly linked list of hash-queue */
-	struct buffer_head * b_prev_free;	/* doubly linked list of buffers */
-	struct buffer_head * b_reqnext;		/* request queue */
+	unsigned long b_flushtime;	/* Time when (dirty) buffer should be written */
 
-	/*
-	 * I/O completion
-	 */
-	void (*b_end_io)(struct buffer_head *bh, int uptodate);
+	struct buffer_head *b_next_free;/* lru/free list linkage */
+	struct buffer_head *b_prev_free;/* doubly linked list of buffers */
+	struct buffer_head *b_this_page;/* circular list of buffers in one page */
+	struct buffer_head *b_reqnext;	/* request queue */
+
+	struct buffer_head **b_pprev;	/* doubly linked list of hash-queue */
+	char *b_data;			/* pointer to data block (1024 bytes) */
+	void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
 	void *b_dev_id;
+
+	unsigned long b_rsector;	/* Real buffer location on disk */
+	wait_queue_head_t b_wait;
 };
 
 typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
-void init_buffer(struct buffer_head *, kdev_t, int, bh_end_io_t *, void *);
+void init_buffer(struct buffer_head *, bh_end_io_t *, void *);
 
 #define __buffer_state(bh, state)	(((bh)->b_state & (1UL << BH_##state)) != 0)
 
@@ -240,6 +239,8 @@
 #define buffer_dirty(bh)	__buffer_state(bh,Dirty)
 #define buffer_locked(bh)	__buffer_state(bh,Lock)
 #define buffer_req(bh)		__buffer_state(bh,Req)
+#define buffer_mapped(bh)	__buffer_state(bh,Mapped)
+#define buffer_new(bh)		__buffer_state(bh,New)
 #define buffer_protected(bh)	__buffer_state(bh,Protected)
 
 #define buffer_page(bh)		(mem_map + MAP_NR((bh)->b_data))
@@ -402,9 +403,10 @@
 	struct file		*f_next, **f_pprev;
 	struct dentry		*f_dentry;
 	struct file_operations	*f_op;
+	atomic_t		f_count;
+	unsigned int 		f_flags;
 	mode_t			f_mode;
 	loff_t			f_pos;
-	unsigned int 		f_count, f_flags;
 	unsigned long 		f_reada, f_ramax, f_raend, f_ralen, f_rawin;
 	struct fown_struct	f_owner;
 	unsigned int		f_uid, f_gid;
@@ -598,13 +600,19 @@
 	struct dentry * (*follow_link) (struct dentry *, struct dentry *, unsigned int);
 	/*
 	 * the order of these functions within the VFS template has been
-	 * changed because SMP locking has changed: from now on all bmap,
+	 * changed because SMP locking has changed: from now on all get_block,
 	 * readpage, writepage and flushpage functions are supposed to do
 	 * whatever locking they need to get proper SMP operation - for
 	 * now in most cases this means a lock/unlock_kernel at entry/exit.
 	 * [The new order is also slightly more logical :)]
 	 */
-	int (*bmap) (struct inode *,int);
+	/*
+	 * Generic block allocator exported by the lowlevel fs. All metadata
+	 * details are handled by the lowlevel fs, all 'logical data content'
+	 * details are handled by the highlevel block layer.
+	 */
+	int (*get_block) (struct inode *, long, struct buffer_head *, int);
+
 	int (*readpage) (struct file *, struct page *);
 	int (*writepage) (struct file *, struct page *);
 	int (*flushpage) (struct inode *, struct page *, unsigned long);
@@ -741,23 +749,38 @@
 extern int try_to_free_buffers(struct page *);
 extern void refile_buffer(struct buffer_head * buf);
 
-extern int buffermem;
+extern atomic_t buffermem;
 
 #define BUF_CLEAN	0
 #define BUF_LOCKED	1	/* Buffers scheduled for write */
 #define BUF_DIRTY	2	/* Dirty buffers, not yet scheduled for write */
 #define NR_LIST		3
 
-void mark_buffer_uptodate(struct buffer_head *, int);
+/*
+ * This is called by bh->b_end_io() handlers when I/O has completed.
+ */
+extern inline void mark_buffer_uptodate(struct buffer_head * bh, int on)
+{
+	if (on)
+		set_bit(BH_Uptodate, &bh->b_state);
+	else
+		clear_bit(BH_Uptodate, &bh->b_state);
+}
+
+#define atomic_set_buffer_clean(bh) test_and_clear_bit(BH_Dirty, &(bh)->b_state)
+
+extern inline void __mark_buffer_clean(struct buffer_head *bh)
+{
+	refile_buffer(bh);
+}
 
 extern inline void mark_buffer_clean(struct buffer_head * bh)
 {
-	if (test_and_clear_bit(BH_Dirty, &bh->b_state))
-		refile_buffer(bh);
+	if (atomic_set_buffer_clean(bh))
+		__mark_buffer_clean(bh);
 }
 
 extern void FASTCALL(__mark_buffer_dirty(struct buffer_head *bh, int flag));
-extern void FASTCALL(__atomic_mark_buffer_dirty(struct buffer_head *bh, int flag));
 
 #define atomic_set_buffer_dirty(bh) test_and_set_bit(BH_Dirty, &(bh)->b_state)
 
@@ -767,20 +790,6 @@
 		__mark_buffer_dirty(bh, flag);
 }
 
-/*
- * SMP-safe version of the above - does synchronization with
- * other users of buffer-cache data structures.
- *
- * since we test-set the dirty bit in a CPU-atomic way we also
- * have optimized the common 'redirtying' case away completely.
- */
-extern inline void atomic_mark_buffer_dirty(struct buffer_head * bh, int flag)
-{
-	if (!atomic_set_buffer_dirty(bh))
-		__atomic_mark_buffer_dirty(bh, flag);
-}
-
-
 extern void balance_dirty(kdev_t);
 extern int check_disk_change(kdev_t);
 extern int invalidate_inodes(struct super_block *);
@@ -847,7 +856,6 @@
 extern struct file * get_empty_filp(void);
 extern struct buffer_head * get_hash_table(kdev_t, int, int);
 extern struct buffer_head * getblk(kdev_t, int, int);
-extern struct buffer_head * find_buffer(kdev_t, int, int);
 extern void ll_rw_block(int, int, struct buffer_head * bh[]);
 extern int is_read_only(kdev_t);
 extern void __brelse(struct buffer_head *);
@@ -869,13 +877,12 @@
 
 extern int brw_page(int, struct page *, kdev_t, int [], int, int);
 
-typedef long (*writepage_t)(struct file *, struct page *, unsigned long, unsigned long, const char *);
-typedef int (*fs_getblock_t)(struct inode *, long, int, int *, int *);
+typedef int (*writepage_t)(struct file *, struct page *, unsigned long, unsigned long, const char *);
 
 /* Generic buffer handling for block filesystems.. */
 extern int block_read_full_page(struct file *, struct page *);
-extern int block_write_full_page (struct file *, struct page *, fs_getblock_t);
-extern int block_write_partial_page (struct file *, struct page *, unsigned long, unsigned long, const char *, fs_getblock_t);
+extern int block_write_full_page (struct file *, struct page *);
+extern int block_write_partial_page (struct file *, struct page *, unsigned long, unsigned long, const char *);
 extern int block_flushpage(struct inode *, struct page *, unsigned long);
 
 extern int generic_file_mmap(struct file *, struct vm_area_struct *);
@@ -889,7 +896,6 @@
 unsigned long generate_cluster_swab32(kdev_t, int b[], int);
 extern kdev_t ROOT_DEV;
 
-extern void show_buffers(void);
 extern void mount_root(void);
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff -u --recursive --new-file v2.3.8/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.3.8/linux/include/linux/ide.h	Tue Jun 22 14:41:45 1999
+++ linux/include/linux/ide.h	Wed Jun 30 12:42:48 1999
@@ -463,6 +463,8 @@
 #ifdef CONFIG_PROC_FS
 void proc_ide_create(void);
 void proc_ide_destroy(void);
+void destroy_proc_ide_drives(ide_hwif_t *);
+void create_proc_ide_interfaces(void);
 void ide_add_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p, void *data);
 void ide_remove_proc_entries(struct proc_dir_entry *dir, ide_proc_entry_t *p);
 read_proc_t proc_ide_read_capacity;
@@ -757,6 +759,7 @@
 
 #ifndef _IDE_C
 extern struct file_operations ide_fops[];
+extern ide_proc_entry_t generic_subdriver_entries[];
 #endif
 
 #ifdef _IDE_C
diff -u --recursive --new-file v2.3.8/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- v2.3.8/linux/include/linux/iso_fs.h	Fri Apr 23 21:20:38 1999
+++ linux/include/linux/iso_fs.h	Sun Jun 27 10:10:41 1999
@@ -184,26 +184,10 @@
 int get_joliet_filename(struct iso_directory_record *, struct inode *, unsigned char *);
 int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
 
-/* The stuff that follows may be totally unneeded. I have not checked to see 
- which prototypes we are still using.  */
-
-extern int isofs_open(struct inode * inode, struct file * filp);
-extern void isofs_release(struct inode * inode, struct file * filp);
-extern struct dentry *isofs_lookup(struct inode * dir, struct dentry *);
-extern unsigned long isofs_count_free_inodes(struct super_block *sb);
-extern int isofs_new_block(int dev);
-extern int isofs_free_block(int dev, int block);
-extern int isofs_bmap(struct inode *,int);
-
-extern void isofs_put_super(struct super_block *);
-extern struct super_block *isofs_read_super(struct super_block *,void *,int);
+extern struct dentry *isofs_lookup(struct inode *, struct dentry *);
+extern int isofs_get_block(struct inode *, long, struct buffer_head *, int);
+extern int isofs_bmap(struct inode *, int);
 extern int init_iso9660_fs(void);
-extern void isofs_read_inode(struct inode *);
-extern void isofs_put_inode(struct inode *);
-extern int isofs_statfs(struct super_block *, struct statfs *, int);
-
-extern int isofs_lseek(struct inode *, struct file *, off_t, int);
-extern int isofs_read(struct inode *, struct file *, char *, int);
 extern int isofs_lookup_grandparent(struct inode *, int);
 
 extern struct inode_operations isofs_file_inode_operations;
diff -u --recursive --new-file v2.3.8/linux/include/linux/major.h linux/include/linux/major.h
--- v2.3.8/linux/include/linux/major.h	Mon May 31 22:08:10 1999
+++ linux/include/linux/major.h	Fri Jun 25 17:37:52 1999
@@ -63,6 +63,8 @@
 #define ACSI_MAJOR	28
 #define AZTECH_CDROM_MAJOR 29
 #define GRAPHDEV_MAJOR	29	/* SparcLinux & Linux/68k /dev/fb */
+#define SHMIQ_MAJOR	85	/* Linux/mips, SGI /dev/shmiq */
+#define USEMA_MAJOR	86	/* Linux/MIPS, SGI /dev/usema */
 #define CM206_CDROM_MAJOR 32
 #define IDE2_MAJOR	33
 #define IDE3_MAJOR	34
diff -u --recursive --new-file v2.3.8/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- v2.3.8/linux/include/linux/minix_fs.h	Wed Jun 16 19:26:27 1999
+++ linux/include/linux/minix_fs.h	Sun Jun 27 10:10:41 1999
@@ -110,7 +110,7 @@
 extern int minix_bmap(struct inode *,int);
 
 extern struct buffer_head * minix_getblk(struct inode *, int, int);
-extern int minix_getblk_block (struct inode *, long, int, int *, int *);
+extern int minix_get_block(struct inode *, long, struct buffer_head *, int);
 extern struct buffer_head * minix_bread(struct inode *, int, int);
 
 extern void minix_truncate(struct inode *);
diff -u --recursive --new-file v2.3.8/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h
--- v2.3.8/linux/include/linux/miscdevice.h	Sun Mar  7 15:25:23 1999
+++ linux/include/linux/miscdevice.h	Fri Jun 25 17:37:52 1999
@@ -19,6 +19,14 @@
 #define I2O_MINOR 166
 #define MISC_DYNAMIC_MINOR 255
 
+#define SGI_GRAPHICS_MINOR   146
+#define SGI_OPENGL_MINOR     147
+#define SGI_GFX_MINOR        148
+#define SGI_STREAMS_MOUSE    149
+#define SGI_STREAMS_KEYBOARD 150
+/* drivers/sgi/char/usema.c */
+#define SGI_USEMACLONE	     151
+
 extern int misc_init(void);
 
 struct miscdevice 
diff -u --recursive --new-file v2.3.8/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.8/linux/include/linux/mm.h	Tue Jun 22 14:41:47 1999
+++ linux/include/linux/mm.h	Wed Jun 30 12:42:45 1999
@@ -148,7 +148,7 @@
 #define PG_uptodate		 3
 #define PG_free_after		 4
 #define PG_decr_after		 5
-#define PG_swap_unlock_after	 6
+#define PG_free_swap_after	 6
 #define PG_DMA			 7
 #define PG_Slab			 8
 #define PG_swap_cache		 9
@@ -182,7 +182,7 @@
 #define PageReferenced(page)	(test_bit(PG_referenced, &(page)->flags))
 #define PageFreeAfter(page)	(test_bit(PG_free_after, &(page)->flags))
 #define PageDecrAfter(page)	(test_bit(PG_decr_after, &(page)->flags))
-#define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
+#define PageSwapUnlockAfter(page) (test_bit(PG_free_swap_after, &(page)->flags))
 #define PageDMA(page)		(test_bit(PG_DMA, &(page)->flags))
 #define PageSlab(page)		(test_bit(PG_Slab, &(page)->flags))
 #define PageSwapCache(page)	(test_bit(PG_swap_cache, &(page)->flags))
@@ -409,7 +409,7 @@
 
 extern struct vm_area_struct *find_extend_vma(struct task_struct *tsk, unsigned long addr);
 
-#define buffer_under_min()	((buffermem >> PAGE_SHIFT) * 100 < \
+#define buffer_under_min()	((atomic_read(&buffermem) >> PAGE_SHIFT) * 100 < \
 				buffer_mem.min_percent * num_physpages)
 #define pgcache_under_min()	(atomic_read(&page_cache_size) * 100 < \
 				page_cache.min_percent * num_physpages)
diff -u --recursive --new-file v2.3.8/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.3.8/linux/include/linux/pagemap.h	Tue Jun 22 14:41:52 1999
+++ linux/include/linux/pagemap.h	Wed Jun 30 12:42:46 1999
@@ -39,11 +39,14 @@
  */
 #define page_cache_entry(x)	(mem_map + MAP_NR(x))
 
-#define PAGE_HASH_BITS 16
+extern unsigned int page_hash_bits;
+#define PAGE_HASH_BITS (page_hash_bits)
 #define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)
 
 extern atomic_t page_cache_size; /* # of pages currently in the hash table */
-extern struct page * page_hash_table[PAGE_HASH_SIZE];
+extern struct page **page_hash_table;
+
+extern void page_cache_init(unsigned long);
 
 /*
  * We use a power-of-two hash table to avoid a modulus,
diff -u --recursive --new-file v2.3.8/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.8/linux/include/linux/pci.h	Tue Jun 22 14:41:40 1999
+++ linux/include/linux/pci.h	Wed Jun 30 12:42:44 1999
@@ -865,6 +865,9 @@
 #define PCI_VENDOR_ID_OMEGA		0x119b
 #define PCI_DEVICE_ID_OMEGA_82C092G	0x1221
 
+#define PCI_VENDOR_ID_GALILEO		0x11ab
+#define PCI_DEVICE_ID_GALILEO_GT64011	0x4146
+
 #define PCI_VENDOR_ID_LITEON		0x11ad
 #define PCI_DEVICE_ID_LITEON_LNE100TX	0x0002
 
@@ -1024,6 +1027,9 @@
 
 #define PCI_VENDOR_ID_DCI       0x6666
 #define PCI_DEVICE_ID_DCI_PCCOM4    0x0001
+
+#define PCI_VENDOR_ID_GENROCO		0x5555
+#define PCI_DEVICE_ID_GENROCO_HFP832	0x0003
 
 #define PCI_VENDOR_ID_INTEL		0x8086
 #define PCI_DEVICE_ID_INTEL_82375	0x0482
diff -u --recursive --new-file v2.3.8/linux/include/linux/personality.h linux/include/linux/personality.h
--- v2.3.8/linux/include/linux/personality.h	Tue Dec  1 13:33:00 1998
+++ linux/include/linux/personality.h	Fri Jun 25 17:37:52 1999
@@ -24,6 +24,9 @@
 #define PER_BSD			(0x0006)
 #define PER_XENIX		(0x0007 | STICKY_TIMEOUTS)
 #define PER_LINUX32		(0x0008)
+#define PER_IRIX32              (0x0009 | STICKY_TIMEOUTS) /* IRIX5 32-bit     */
+#define PER_IRIXN32             (0x000a | STICKY_TIMEOUTS) /* IRIX6 new 32-bit */
+#define PER_IRIX64              (0x000b | STICKY_TIMEOUTS) /* IRIX6 64-bit     */
 
 /* Prototype for an lcall7 syscall handler. */
 typedef void (*lcall7_func)(struct pt_regs *);
diff -u --recursive --new-file v2.3.8/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.8/linux/include/linux/proc_fs.h	Tue Jun 22 14:41:59 1999
+++ linux/include/linux/proc_fs.h	Wed Jun 30 12:43:17 1999
@@ -202,6 +202,7 @@
 	PROC_SCSI_ATARI,
 	PROC_SCSI_MAC,
 	PROC_SCSI_IDESCSI,
+	PROC_SCSI_SGIWD93,
 	PROC_SCSI_MESH,
 	PROC_SCSI_53C94,
 	PROC_SCSI_PLUTO,
diff -u --recursive --new-file v2.3.8/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.3.8/linux/include/linux/sched.h	Tue Jun 22 14:41:47 1999
+++ linux/include/linux/sched.h	Wed Jun 30 12:42:45 1999
@@ -130,6 +130,7 @@
  */
 struct files_struct {
 	atomic_t count;
+	rwlock_t file_lock;
 	int max_fds;
 	struct file ** fd;	/* current fd array */
 	fd_set close_on_exec;
@@ -138,6 +139,7 @@
 
 #define INIT_FILES { \
 	ATOMIC_INIT(1), \
+	RW_LOCK_UNLOCKED, \
 	NR_OPEN, \
 	&init_fd_array[0], \
 	{ { 0, } }, \
diff -u --recursive --new-file v2.3.8/linux/include/linux/string.h linux/include/linux/string.h
--- v2.3.8/linux/include/linux/string.h	Fri Apr 23 09:36:09 1999
+++ linux/include/linux/string.h	Fri Jun 25 14:35:42 1999
@@ -20,6 +20,7 @@
 extern char * strrchr(const char *,int);
 extern char * strpbrk(const char *,const char *);
 extern char * strtok(char *,const char *);
+extern char * strsep(char **,const char *);
 extern char * strstr(const char *,const char *);
 extern __kernel_size_t strlen(const char *);
 extern __kernel_size_t strnlen(const char *,__kernel_size_t);
diff -u --recursive --new-file v2.3.8/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.3.8/linux/include/linux/swap.h	Tue Jun 22 14:41:41 1999
+++ linux/include/linux/swap.h	Wed Jun 30 12:42:44 1999
@@ -67,7 +67,7 @@
 extern atomic_t nr_async_pages;
 extern struct inode swapper_inode;
 extern atomic_t page_cache_size;
-extern int buffermem;
+extern atomic_t buffermem;
 
 /* Incomplete types for prototype declarations: */
 struct task_struct;
diff -u --recursive --new-file v2.3.8/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.3.8/linux/include/linux/sysctl.h	Thu Jun  3 16:21:47 1999
+++ linux/include/linux/sysctl.h	Fri Jun 25 01:05:12 1999
@@ -82,8 +82,6 @@
 	KERN_PANIC=15,		/* int: panic timeout */
 	KERN_REALROOTDEV=16,	/* real root device to mount after initrd */
 
-	KERN_JAVA_INTERPRETER=19, /* path to Java(tm) interpreter */
-	KERN_JAVA_APPLETVIEWER=20, /* path to Java(tm) appletviewer */
 	KERN_SPARC_REBOOT=21,	/* reboot command on Sparc */
 	KERN_CTLALTDEL=22,	/* int: allow ctl-alt-del to reboot */
 	KERN_PRINTK=23,		/* struct: control printk logging parameters */
diff -u --recursive --new-file v2.3.8/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- v2.3.8/linux/include/linux/sysv_fs.h	Tue Jun 22 14:43:20 1999
+++ linux/include/linux/sysv_fs.h	Wed Jun 30 12:44:24 1999
@@ -384,25 +384,15 @@
 extern void sysv_free_block(struct super_block * sb, unsigned int block);
 extern unsigned long sysv_count_free_blocks(struct super_block *sb);
 
-extern int sysv_bmap(struct inode *,int);
-
 extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int);
-extern int sysv_getblk_block(struct inode *, long, int, int *, int *);
+extern int sysv_get_block(struct inode *, long, struct buffer_head *, int);
 extern struct buffer_head * sysv_file_bread(struct inode *, int, int);
-extern ssize_t sysv_file_read(struct file *, char *, size_t, loff_t *);
 
 extern void sysv_truncate(struct inode *);
-extern void sysv_put_super(struct super_block *);
-extern struct super_block *sysv_read_super(struct super_block *,void *,int);
 extern int init_sysv_fs(void);
-extern void sysv_write_super(struct super_block *);
-extern void sysv_read_inode(struct inode *);
-extern int sysv_notify_change(struct dentry *, struct iattr *);
 extern void sysv_write_inode(struct inode *);
-extern int sysv_statfs(struct super_block *, struct statfs *, int);
 extern int sysv_sync_inode(struct inode *);
 extern int sysv_sync_file(struct file *, struct dentry *);
-extern int sysv_mmap(struct file *, struct vm_area_struct *);
 
 extern struct inode_operations sysv_file_inode_operations;
 extern struct inode_operations sysv_file_inode_operations_with_bmap;
diff -u --recursive --new-file v2.3.8/linux/include/linux/timer.h linux/include/linux/timer.h
--- v2.3.8/linux/include/linux/timer.h	Thu Nov 19 11:08:45 1998
+++ linux/include/linux/timer.h	Mon Jun 28 13:41:34 1999
@@ -71,7 +71,7 @@
 	timer->prev = NULL;
 }
 
-extern inline int timer_pending(struct timer_list * timer)
+extern inline int timer_pending(const struct timer_list * timer)
 {
 	return timer->prev != NULL;
 }
diff -u --recursive --new-file v2.3.8/linux/include/linux/ufs_fs.h linux/include/linux/ufs_fs.h
--- v2.3.8/linux/include/linux/ufs_fs.h	Wed Jun 16 19:26:27 1999
+++ linux/include/linux/ufs_fs.h	Tue Jun 29 09:12:32 1999
@@ -111,13 +111,14 @@
 #define UFS_MOUNT_ONERROR_UMOUNT	0x00000004
 #define UFS_MOUNT_ONERROR_REPAIR	0x00000008
 
-#define UFS_MOUNT_UFSTYPE		0x000003F0
+#define UFS_MOUNT_UFSTYPE		0x000007F0
 #define UFS_MOUNT_UFSTYPE_OLD		0x00000010
 #define UFS_MOUNT_UFSTYPE_44BSD		0x00000020
 #define UFS_MOUNT_UFSTYPE_SUN		0x00000040
 #define UFS_MOUNT_UFSTYPE_NEXTSTEP	0x00000080
-#define UFS_MOUNT_UFSTYPE_OPENSTEP	0x00000100
-#define UFS_MOUNT_UFSTYPE_SUNx86	0x00000200
+#define UFS_MOUNT_UFSTYPE_NEXTSTEP_CD	0x00000100
+#define UFS_MOUNT_UFSTYPE_OPENSTEP	0x00000200
+#define UFS_MOUNT_UFSTYPE_SUNx86	0x00000400
 
 #define ufs_clear_opt(o,opt)	o &= ~UFS_MOUNT_##opt
 #define ufs_set_opt(o,opt)	o |= UFS_MOUNT_##opt
@@ -529,7 +530,7 @@
 extern struct inode * ufs_new_inode (const struct inode *, int, int *);
 
 /* inode.c */
-extern int ufs_bmap (struct inode *, int);
+extern int ufs_frag_map (struct inode *, int);
 extern void ufs_read_inode (struct inode *);
 extern void ufs_put_inode (struct inode *);
 extern void ufs_write_inode (struct inode *);
@@ -537,7 +538,7 @@
 extern void ufs_write_inode (struct inode *);
 extern void ufs_delete_inode (struct inode *);
 extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
-extern int ufs_getfrag_block (struct inode *, long, int, int *, int *);
+extern int ufs_getfrag_block (struct inode *, long, struct buffer_head *, int);
 extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
 
 /* namei.c */
diff -u --recursive --new-file v2.3.8/linux/include/net/dn_fib.h linux/include/net/dn_fib.h
--- v2.3.8/linux/include/net/dn_fib.h	Wed May 26 09:36:35 1999
+++ linux/include/net/dn_fib.h	Wed Jun 30 11:24:55 1999
@@ -1,6 +1,8 @@
 #ifndef _NET_DN_FIB_H
 #define _NET_DN_FIB_H
 
+#include <linux/config.h>
+
 #ifdef CONFIG_DECNET_ROUTER
 
 
diff -u --recursive --new-file v2.3.8/linux/include/net/dn_raw.h linux/include/net/dn_raw.h
--- v2.3.8/linux/include/net/dn_raw.h	Wed May 26 09:36:35 1999
+++ linux/include/net/dn_raw.h	Wed Jun 30 11:24:55 1999
@@ -1,6 +1,8 @@
 #ifndef _NET_DN_RAW_H
 #define _NET_DN_RAW_H
 
+#include <linux/config.h>
+
 #ifdef CONFIG_DECNET_RAW
 
 extern struct proto_ops dn_raw_proto_ops;
diff -u --recursive --new-file v2.3.8/linux/init/main.c linux/init/main.c
--- v2.3.8/linux/init/main.c	Tue Jun 22 10:45:40 1999
+++ linux/init/main.c	Wed Jun 30 10:25:46 1999
@@ -1186,6 +1186,7 @@
 	dcache_init();
 	vma_init();
 	buffer_init(memory_end-memory_start);
+	page_cache_init(memory_end-memory_start);
 	signals_init();
 	inode_init();
 	file_table_init();
diff -u --recursive --new-file v2.3.8/linux/ipc/msg.c linux/ipc/msg.c
--- v2.3.8/linux/ipc/msg.c	Mon Jun  7 12:20:50 1999
+++ linux/ipc/msg.c	Wed Jun 30 11:24:55 1999
@@ -11,6 +11,7 @@
  * /proc/sysvipc/msg support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
  */
 
+#include <linux/config.h>
 #include <linux/malloc.h>
 #include <linux/msg.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.3.8/linux/ipc/sem.c linux/ipc/sem.c
--- v2.3.8/linux/ipc/sem.c	Mon Jun  7 12:20:50 1999
+++ linux/ipc/sem.c	Wed Jun 30 11:24:55 1999
@@ -52,6 +52,7 @@
  * /proc/sysvipc/sem support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
  */
 
+#include <linux/config.h>
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.3.8/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.8/linux/ipc/shm.c	Wed Jun 16 19:26:27 1999
+++ linux/ipc/shm.c	Wed Jun 30 11:24:55 1999
@@ -8,6 +8,7 @@
  * /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
  */
 
+#include <linux/config.h>
 #include <linux/malloc.h>
 #include <linux/shm.h>
 #include <linux/swap.h>
diff -u --recursive --new-file v2.3.8/linux/kernel/acct.c linux/kernel/acct.c
--- v2.3.8/linux/kernel/acct.c	Fri Jun 18 08:01:50 1999
+++ linux/kernel/acct.c	Tue Jun 29 09:22:08 1999
@@ -276,7 +276,7 @@
 	 */
 	if (!file)
 		return 0;
-	file->f_count++;
+	atomic_inc(&file->f_count);
 	if (!check_free_space(file)) {
 		fput(file);
 		return 0;
diff -u --recursive --new-file v2.3.8/linux/kernel/fork.c linux/kernel/fork.c
--- v2.3.8/linux/kernel/fork.c	Tue Jun 22 13:56:06 1999
+++ linux/kernel/fork.c	Mon Jun 28 14:19:46 1999
@@ -249,7 +249,7 @@
 		tmp->vm_next = NULL;
 		file = tmp->vm_file;
 		if (file) {
-			file->f_count++;
+			atomic_inc(&file->f_count);
 			if (tmp->vm_flags & VM_DENYWRITE)
 				file->f_dentry->d_inode->i_writecount--;
       
@@ -474,6 +474,7 @@
 	if (!new_fds)
 		goto out_release;
 
+	newf->file_lock = RW_LOCK_UNLOCKED;
 	atomic_set(&newf->count, 1);
 	newf->max_fds = NR_OPEN;
 	newf->fd = new_fds;
@@ -485,7 +486,7 @@
 		struct file *f = *old_fds++;
 		*new_fds = f;
 		if (f)
-			f->f_count++;
+			atomic_inc(&f->f_count);
 		new_fds++;
 	}
 	/* This is long word aligned thus could use a optimized version */ 
@@ -556,13 +557,14 @@
 	if (p->user) {
 		if (atomic_read(&p->user->count) >= p->rlim[RLIMIT_NPROC].rlim_cur)
 			goto bad_fork_free;
+		atomic_inc(&p->user->count);
 	}
 
 	{
 		struct task_struct **tslot;
 		tslot = find_empty_process();
 		if (!tslot)
-			goto bad_fork_free;
+			goto bad_fork_cleanup_count;
 		p->tarray_ptr = tslot;
 		*tslot = p;
 		nr = tslot - &task[0];
@@ -666,8 +668,6 @@
 		write_unlock_irq(&tasklist_lock);
 
 		nr_tasks++;
-		if (p->user)
-			atomic_inc(&p->user->count);
 
 		p->next_run = NULL;
 		p->prev_run = NULL;
@@ -695,6 +695,9 @@
 		__MOD_DEC_USE_COUNT(p->binfmt->module);
 
 	add_free_taskslot(p->tarray_ptr);
+bad_fork_cleanup_count:
+	if (p->user)
+		free_uid(p);
 bad_fork_free:
 	free_task_struct(p);
 	goto bad_fork;
diff -u --recursive --new-file v2.3.8/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.8/linux/kernel/ksyms.c	Tue Jun 22 14:08:14 1999
+++ linux/kernel/ksyms.c	Wed Jun 30 10:25:46 1999
@@ -135,6 +135,7 @@
 EXPORT_SYMBOL(d_alloc);
 EXPORT_SYMBOL(d_lookup);
 EXPORT_SYMBOL(d_path);
+EXPORT_SYMBOL(__mark_buffer_dirty);
 EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
@@ -162,11 +163,16 @@
 EXPORT_SYMBOL(__bforget);
 EXPORT_SYMBOL(ll_rw_block);
 EXPORT_SYMBOL(__wait_on_buffer);
-EXPORT_SYMBOL(mark_buffer_uptodate);
 EXPORT_SYMBOL(add_blkdev_randomness);
+EXPORT_SYMBOL(block_read_full_page);
+EXPORT_SYMBOL(block_write_full_page);
+EXPORT_SYMBOL(block_write_partial_page);
+EXPORT_SYMBOL(block_flushpage);
 EXPORT_SYMBOL(generic_file_read);
 EXPORT_SYMBOL(generic_file_write);
 EXPORT_SYMBOL(generic_file_mmap);
+EXPORT_SYMBOL(page_hash_bits);
+EXPORT_SYMBOL(page_hash_table);
 EXPORT_SYMBOL(file_lock_table);
 EXPORT_SYMBOL(posix_lock_file);
 EXPORT_SYMBOL(posix_test_lock);
@@ -221,8 +227,8 @@
 EXPORT_SYMBOL(unplug_device);
 EXPORT_SYMBOL(make_request);
 EXPORT_SYMBOL(tq_disk);
-EXPORT_SYMBOL(find_buffer);
 EXPORT_SYMBOL(init_buffer);
+EXPORT_SYMBOL(refile_buffer);
 EXPORT_SYMBOL(max_sectors);
 EXPORT_SYMBOL(max_readahead);
 
diff -u --recursive --new-file v2.3.8/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.3.8/linux/kernel/sysctl.c	Sat Jun 19 11:45:29 1999
+++ linux/kernel/sysctl.c	Sat Jun 26 12:04:40 1999
@@ -34,7 +34,6 @@
 extern int panic_timeout;
 extern int console_loglevel, C_A_D;
 extern int bdf_prm[], bdflush_min[], bdflush_max[];
-extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
 extern int sysctl_overcommit_memory;
 extern int nr_queued_signals, max_queued_signals;
 
@@ -121,7 +120,7 @@
 	NULL,		/* rename */
 	NULL,		/* readlink */
 	NULL,		/* follow_link */
-	NULL,		/* bmap */
+	NULL,		/* get_block */
 	NULL,		/* readpage */
 	NULL,		/* writepage */
 	NULL,		/* flushpage */
@@ -170,12 +169,6 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 	{KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int),
 	 0644, NULL, &proc_dointvec},
-#endif
-#ifdef CONFIG_BINFMT_JAVA
-	{KERN_JAVA_INTERPRETER, "java-interpreter", binfmt_java_interpreter,
-	 64, 0644, NULL, &proc_dostring, &sysctl_string },
-	{KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
-	 64, 0644, NULL, &proc_dostring, &sysctl_string },
 #endif
 #ifdef __sparc__
 	{KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
diff -u --recursive --new-file v2.3.8/linux/lib/string.c linux/lib/string.c
--- v2.3.8/linux/lib/string.c	Sun Sep  6 11:19:15 1998
+++ linux/lib/string.c	Fri Jun 25 14:35:42 1999
@@ -9,6 +9,10 @@
  * as inline code in <asm-xx/string.h>
  *
  * These are buggy as well..
+ *
+ * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
+ * -  Added strsep() which will replace strtok() soon (because strsep() is
+ *    reentrant and should be faster). Use only strsep() in new code, please.
  */
  
 #include <linux/types.h>
@@ -228,6 +232,25 @@
 	if (send && *send != '\0')
 		*send++ = '\0';
 	___strtok = send;
+	return (sbegin);
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSEP
+
+char * strsep(char **s, const char * ct)
+{
+	char *sbegin=*s;
+	if (!sbegin) 
+		return NULL;
+	
+	sbegin += strspn(sbegin,ct);
+	if (*sbegin == '\0') 
+		return NULL;
+	
+	*s = strpbrk( sbegin, ct);
+	if (*s && **s != '\0')
+		**s++ = '\0';
 	return (sbegin);
 }
 #endif
diff -u --recursive --new-file v2.3.8/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.8/linux/mm/filemap.c	Tue Jun 22 14:25:22 1999
+++ linux/mm/filemap.c	Wed Jun 30 10:25:46 1999
@@ -20,6 +20,7 @@
 #include <linux/file.h>
 #include <linux/swapctl.h>
 #include <linux/slab.h>
+#include <linux/init.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -35,7 +36,8 @@
  */
 
 atomic_t page_cache_size = ATOMIC_INIT(0);
-struct page * page_hash_table[PAGE_HASH_SIZE];
+unsigned int page_hash_bits;
+struct page **page_hash_table;
 
 spinlock_t pagecache_lock = SPIN_LOCK_UNLOCKED;
 
@@ -273,8 +275,8 @@
 			continue;
 		}
 		if (!page_count(page)) {
-//			BUG();
 			spin_unlock(&pagecache_lock);
+			BUG();
 			continue;
 		}
 		get_page(page);
@@ -292,13 +294,18 @@
 
 		/* Is it a buffer page? */
 		if (page->buffers) {
+			int mem = page->inode ? 0 : PAGE_CACHE_SIZE;
 			spin_unlock(&pagecache_lock);
-			if (try_to_free_buffers(page))
-				goto made_progress;
+			if (!try_to_free_buffers(page))
+				goto unlock_continue;
+			atomic_sub(mem, &buffermem);
 			spin_lock(&pagecache_lock);
 		}
 
-		/* We can't free pages unless there's just one user */
+		/*
+		 * We can't free pages unless there's just one user
+		 * (count == 2 because we added one ourselves above).
+		 */
 		if (page_count(page) != 2)
 			goto spin_unlock_continue;
 
@@ -354,6 +361,7 @@
 		if (page->offset == offset)
 			break;
 	}
+	set_bit(PG_referenced, &page->flags);
 not_found:
 	return page;
 }
@@ -1138,7 +1146,6 @@
 {
 	ssize_t retval;
 
-	unlock_kernel();
 	retval = -EFAULT;
 	if (access_ok(VERIFY_WRITE, buf, count)) {
 		retval = 0;
@@ -1156,7 +1163,6 @@
 				retval = desc.error;
 		}
 	}
-	lock_kernel();
 	return retval;
 }
 
@@ -1481,7 +1487,7 @@
 	 * If a task terminates while we're swapping the page, the vma and
 	 * and file could be released ... increment the count to be safe.
 	 */
-	file->f_count++;
+	atomic_inc(&file->f_count);
 	result = do_write_page(inode, file, (const char *) page, offset);
 	fput(file);
 	return result;
@@ -1829,8 +1835,6 @@
 		count = limit - pos;
 	}
 
-	unlock_kernel();
-
 	while (count) {
 		unsigned long bytes, pgpos, offset;
 		/*
@@ -1892,7 +1896,6 @@
 		page_cache_free(page_cache);
 
 	err = written ? written : status;
-	lock_kernel();
 out:
 	return err;
 }
@@ -1913,4 +1916,31 @@
 		panic("put_cached_page: page count=%d\n", 
 			page_count(page));
 	page_cache_release(page);
+}
+
+void __init page_cache_init(unsigned long memory_size)
+{
+	unsigned long htable_size, order;
+
+	htable_size = memory_size >> PAGE_SHIFT;
+	htable_size *= sizeof(struct page *);
+	for(order = 0; (PAGE_SIZE << order) < htable_size; order++)
+		;
+
+	do {
+		unsigned long tmp = (PAGE_SIZE << order) / sizeof(struct page *);
+
+		page_hash_bits = 0;
+		while((tmp >>= 1UL) != 0UL)
+			page_hash_bits++;
+
+		page_hash_table = (struct page **)
+			__get_free_pages(GFP_ATOMIC, order);
+	} while(page_hash_table == NULL && --order > 0);
+
+	printk("Page-cache hash table entries: %d (order: %ld, %ld bytes)\n",
+	       (1 << page_hash_bits), order, (PAGE_SIZE << order));
+	if (!page_hash_table)
+		panic("Failed to allocate page hash table\n");
+	memset(page_hash_table, 0, PAGE_HASH_SIZE * sizeof(struct page *));
 }
diff -u --recursive --new-file v2.3.8/linux/mm/memory.c linux/mm/memory.c
--- v2.3.8/linux/mm/memory.c	Wed Jun 16 19:26:27 1999
+++ linux/mm/memory.c	Fri Jun 25 17:36:12 1999
@@ -52,7 +52,7 @@
  */
 static inline void copy_cow_page(unsigned long from, unsigned long to)
 {
-	if (from == ZERO_PAGE) {
+	if (from == ZERO_PAGE(to)) {
 		clear_page(to);
 		return;
 	}
@@ -405,7 +405,8 @@
 	}
 }
 
-static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pte_t zero_pte)
+static inline void zeromap_pte_range(pte_t * pte, unsigned long address,
+                                     unsigned long size, pgprot_t prot)
 {
 	unsigned long end;
 
@@ -414,6 +415,8 @@
 	if (end > PMD_SIZE)
 		end = PMD_SIZE;
 	do {
+		pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(address),
+		                               prot));
 		pte_t oldpage = *pte;
 		set_pte(pte, zero_pte);
 		forget_pte(oldpage);
@@ -422,7 +425,8 @@
 	} while (address < end);
 }
 
-static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size, pte_t zero_pte)
+static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address,
+                                    unsigned long size, pgprot_t prot)
 {
 	unsigned long end;
 
@@ -434,7 +438,7 @@
 		pte_t * pte = pte_alloc(pmd, address);
 		if (!pte)
 			return -ENOMEM;
-		zeromap_pte_range(pte, address, end - address, zero_pte);
+		zeromap_pte_range(pte, address, end - address, prot);
 		address = (address + PMD_SIZE) & PMD_MASK;
 		pmd++;
 	} while (address < end);
@@ -447,9 +451,7 @@
 	pgd_t * dir;
 	unsigned long beg = address;
 	unsigned long end = address + size;
-	pte_t zero_pte;
 
-	zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE, prot));
 	dir = pgd_offset(current->mm, address);
 	flush_cache_range(current->mm, beg, end);
 	while (address < end) {
@@ -457,7 +459,7 @@
 		error = -ENOMEM;
 		if (!pmd)
 			break;
-		error = zeromap_pmd_range(pmd, address, end - address, zero_pte);
+		error = zeromap_pmd_range(pmd, address, end - address, prot);
 		if (error)
 			break;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
@@ -790,9 +792,9 @@
 /*
  * This only needs the MM semaphore
  */
-static int do_anonymous_page(struct task_struct * tsk, struct vm_area_struct * vma, pte_t *page_table, int write_access)
+static int do_anonymous_page(struct task_struct * tsk, struct vm_area_struct * vma, pte_t *page_table, int write_access, unsigned long addr)
 {
-	pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE, vma->vm_page_prot));
+	pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE(addr), vma->vm_page_prot));
 	if (write_access) {
 		unsigned long page = __get_free_page(GFP_USER);
 		if (!page)
@@ -827,7 +829,8 @@
 
 	if (!vma->vm_ops || !vma->vm_ops->nopage) {
 		unlock_kernel();
-		return do_anonymous_page(tsk, vma, page_table, write_access);
+		return do_anonymous_page(tsk, vma, page_table, write_access,
+		                         address);
 	}
 
 	/*
diff -u --recursive --new-file v2.3.8/linux/mm/mlock.c linux/mm/mlock.c
--- v2.3.8/linux/mm/mlock.c	Sun May 16 21:45:23 1999
+++ linux/mm/mlock.c	Mon Jun 28 13:52:39 1999
@@ -31,7 +31,7 @@
 	vma->vm_offset += vma->vm_start - n->vm_start;
 	n->vm_flags = newflags;
 	if (n->vm_file)
-		n->vm_file->f_count++;
+		atomic_inc(&n->vm_file->f_count);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -52,7 +52,7 @@
 	n->vm_offset += n->vm_start - vma->vm_start;
 	n->vm_flags = newflags;
 	if (n->vm_file)
-		n->vm_file->f_count++;
+		atomic_inc(&n->vm_file->f_count);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -82,7 +82,7 @@
 	right->vm_offset += right->vm_start - left->vm_start;
 	vma->vm_flags = newflags;
 	if (vma->vm_file)
-		vma->vm_file->f_count += 2;
+		atomic_add(2, &vma->vm_file->f_count);
 
 	if (vma->vm_ops && vma->vm_ops->open) {
 		vma->vm_ops->open(left);
diff -u --recursive --new-file v2.3.8/linux/mm/mmap.c linux/mm/mmap.c
--- v2.3.8/linux/mm/mmap.c	Wed Jun 16 19:26:27 1999
+++ linux/mm/mmap.c	Tue Jun 29 09:22:08 1999
@@ -62,7 +62,7 @@
 	if (sysctl_overcommit_memory)
 	    return 1;
 
-	free = buffermem >> PAGE_SHIFT;
+	free = atomic_read(&buffermem) >> PAGE_SHIFT;
 	free += atomic_read(&page_cache_size);
 	free += nr_free_pages;
 	free += nr_swap_pages;
@@ -313,7 +313,7 @@
 		if (error)
 			goto unmap_and_free_vma;
 		vma->vm_file = file;
-		file->f_count++;
+		atomic_inc(&file->f_count);
 	}
 
 	/*
@@ -547,7 +547,7 @@
 		mpnt->vm_file = area->vm_file;
 		mpnt->vm_pte = area->vm_pte;
 		if (mpnt->vm_file)
-			mpnt->vm_file->f_count++;
+			atomic_inc(&mpnt->vm_file->f_count);
 		if (mpnt->vm_ops && mpnt->vm_ops->open)
 			mpnt->vm_ops->open(mpnt);
 		area->vm_end = addr;	/* Truncate area */
@@ -786,8 +786,11 @@
 	 */
 	flags = vma->vm_flags;
 	addr = vma->vm_start;
+
+	lock_kernel();		/* kswapd, ugh */
 	insert_vm_struct(mm, vma);
 	merge_segments(mm, vma->vm_start, vma->vm_end);
+	unlock_kernel();
 	
 	mm->total_vm += len >> PAGE_SHIFT;
 	if (flags & VM_LOCKED) {
diff -u --recursive --new-file v2.3.8/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.3.8/linux/mm/mprotect.c	Fri Nov 20 11:43:19 1998
+++ linux/mm/mprotect.c	Mon Jun 28 13:52:05 1999
@@ -103,7 +103,7 @@
 	n->vm_flags = newflags;
 	n->vm_page_prot = prot;
 	if (n->vm_file)
-		n->vm_file->f_count++;
+		atomic_inc(&n->vm_file->f_count);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -126,7 +126,7 @@
 	n->vm_flags = newflags;
 	n->vm_page_prot = prot;
 	if (n->vm_file)
-		n->vm_file->f_count++;
+		atomic_inc(&n->vm_file->f_count);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -158,7 +158,7 @@
 	vma->vm_flags = newflags;
 	vma->vm_page_prot = prot;
 	if (vma->vm_file)
-		vma->vm_file->f_count += 2;
+		atomic_add(2,&vma->vm_file->f_count);
 	if (vma->vm_ops && vma->vm_ops->open) {
 		vma->vm_ops->open(left);
 		vma->vm_ops->open(right);
diff -u --recursive --new-file v2.3.8/linux/mm/mremap.c linux/mm/mremap.c
--- v2.3.8/linux/mm/mremap.c	Thu Jun  3 23:15:29 1999
+++ linux/mm/mremap.c	Mon Jun 28 13:53:22 1999
@@ -136,7 +136,7 @@
 			new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
 			lock_kernel();
 			if (new_vma->vm_file)
-				new_vma->vm_file->f_count++;
+				atomic_inc(&new_vma->vm_file->f_count);
 			if (new_vma->vm_ops && new_vma->vm_ops->open)
 				new_vma->vm_ops->open(new_vma);
 			insert_vm_struct(current->mm, new_vma);
diff -u --recursive --new-file v2.3.8/linux/mm/page_io.c linux/mm/page_io.c
--- v2.3.8/linux/mm/page_io.c	Tue Jun 22 12:24:29 1999
+++ linux/mm/page_io.c	Sat Jun 26 12:04:40 1999
@@ -99,7 +99,7 @@
 	} else if (p->swap_file) {
 		struct inode *swapf = p->swap_file->d_inode;
 		int i;
-		if (swapf->i_op->bmap == NULL
+		if (swapf->i_op->get_block == NULL
 			&& swapf->i_op->smap != NULL){
 			/*
 				With MS-DOS, we use msdos_smap which returns
@@ -110,7 +110,7 @@
 				It sounds like ll_rw_swap_file defined
 				its operation size (sector size) based on
 				PAGE_SIZE and the number of blocks to read.
-				So using bmap or smap should work even if
+				So using get_block or smap should work even if
 				smap will require more blocks.
 			*/
 			int j;
@@ -147,8 +147,7 @@
  		atomic_inc(&nr_async_pages);
  	}
  	if (dolock) {
- 		/* only lock/unlock swap cache pages! */
- 		set_bit(PG_swap_unlock_after, &page->flags);
+ 		set_bit(PG_free_swap_after, &page->flags);
 		p->swap_map[offset]++;
  	}
  	set_bit(PG_free_after, &page->flags);
@@ -174,15 +173,6 @@
 		(char *) page_address(page), 
 		page_count(page));
 #endif
-}
-
-/*
- * This is run when asynchronous page I/O has completed.
- * It decrements the swap bitmap counter
- */
-void swap_after_unlock_page(unsigned long entry)
-{
-	swap_free(entry);
 }
 
 /*
diff -u --recursive --new-file v2.3.8/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.3.8/linux/mm/swap_state.c	Tue Jun 22 14:24:34 1999
+++ linux/mm/swap_state.c	Sat Jun 26 12:04:40 1999
@@ -39,7 +39,7 @@
 	NULL,				/* rename */
 	NULL,				/* readlink */
 	NULL,				/* follow_link */
-	NULL,				/* bmap */
+	NULL,				/* get_block */
 	NULL,				/* readpage */
 	NULL,				/* writepage */
 	block_flushpage,		/* flushpage */
diff -u --recursive --new-file v2.3.8/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.3.8/linux/mm/swapfile.c	Tue Jun 22 12:17:05 1999
+++ linux/mm/swapfile.c	Wed Jun 30 11:24:55 1999
@@ -5,7 +5,6 @@
  *  Swap reorganised 29.12.95, Stephen Tweedie
  */
 
-#include <linux/config.h>
 #include <linux/malloc.h>
 #include <linux/smp_lock.h>
 #include <linux/kernel_stat.h>
diff -u --recursive --new-file v2.3.8/linux/net/core/scm.c linux/net/core/scm.c
--- v2.3.8/linux/net/core/scm.c	Thu Apr 22 19:45:19 1999
+++ linux/net/core/scm.c	Mon Jun 28 13:55:22 1999
@@ -232,7 +232,7 @@
 			break;
 		}
 		/* Bump the usage count and install the file. */
-		fp[i]->f_count++;
+		atomic_inc(&fp[i]->f_count);
 		current->files->fd[new_fd] = fp[i];
 	}
 
@@ -274,7 +274,7 @@
 		memcpy(new_fpl, fpl, sizeof(*fpl));
 
 		for (i=fpl->count-1; i>=0; i--)
-			fpl->fp[i]->f_count++;
+			atomic_inc(&fpl->fp[i]->f_count);
 	}
 	return new_fpl;
 }
diff -u --recursive --new-file v2.3.8/linux/net/decnet/dn_nsp_out.c linux/net/decnet/dn_nsp_out.c
--- v2.3.8/linux/net/decnet/dn_nsp_out.c	Wed May 26 09:36:36 1999
+++ linux/net/decnet/dn_nsp_out.c	Wed Jun 30 11:24:55 1999
@@ -34,7 +34,6 @@
     GNU General Public License for more details.
 *******************************************************************************/
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
diff -u --recursive --new-file v2.3.8/linux/net/decnet/dn_timer.c linux/net/decnet/dn_timer.c
--- v2.3.8/linux/net/decnet/dn_timer.c	Sat May 29 11:09:54 1999
+++ linux/net/decnet/dn_timer.c	Wed Jun 30 11:24:55 1999
@@ -13,7 +13,6 @@
  *                               timer idea.
  *       Steve Whitehouse      : Added checks for sk->sock_readers
  */
-#include <linux/config.h>
 #include <linux/net.h>
 #include <linux/socket.h>
 #include <linux/skbuff.h>
diff -u --recursive --new-file v2.3.8/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- v2.3.8/linux/net/ipv4/ip_masq.c	Tue Mar 16 21:52:05 1999
+++ linux/net/ipv4/ip_masq.c	Tue Jun 29 09:22:08 1999
@@ -4,7 +4,7 @@
  *
  * 	Copyright (c) 1994 Pauline Middelink
  *
- *	$Id: ip_masq.c,v 1.34 1999/03/17 01:53:51 davem Exp $
+ *	$Id: ip_masq.c,v 1.35 1999/06/29 12:35:46 davem Exp $
  *
  *
  *	See ip_fw.c for original log
@@ -315,9 +315,7 @@
  *	Will cycle in MASQ_PORT boundaries.
  */
 static __u16 masq_port = PORT_MASQ_BEGIN;
-#ifdef __SMP__
 static spinlock_t masq_port_lock = SPIN_LOCK_UNLOCKED;
-#endif
 
 /*
  *	free ports counters (UDP & TCP)
diff -u --recursive --new-file v2.3.8/linux/net/ipv4/ip_masq_mfw.c linux/net/ipv4/ip_masq_mfw.c
--- v2.3.8/linux/net/ipv4/ip_masq_mfw.c	Wed May 26 18:14:37 1999
+++ linux/net/ipv4/ip_masq_mfw.c	Tue Jun 29 09:22:08 1999
@@ -3,7 +3,7 @@
  *
  *	Does (reverse-masq) forwarding based on skb->fwmark value
  *
- *	$Id: ip_masq_mfw.c,v 1.4 1999/05/13 23:25:07 davem Exp $
+ *	$Id: ip_masq_mfw.c,v 1.5 1999/06/29 12:35:49 davem Exp $
  *
  * Author:	Juan Jose Ciarlante   <jjciarla@raiz.uncu.edu.ar>
  *		  based on Steven Clarke's portfw
@@ -73,16 +73,12 @@
 	__u32 fwmark;			/* key: firewall mark */
 	struct list_head hosts;		/* list of forward-to hosts */
 	atomic_t nhosts;		/* number of "" */
-#ifdef __SMP__
 	rwlock_t lock;
-#endif
 };
 
 
 static DECLARE_MUTEX(mfw_sema);
-#ifdef __SMP__
 static rwlock_t mfw_lock = RW_LOCK_UNLOCKED;
-#endif
 
 static struct ip_masq_mfw *ip_masq_mfw_table[IP_MASQ_MFW_HSIZE];
 
@@ -143,9 +139,7 @@
 	MOD_INC_USE_COUNT;
 	memset(mfw, 0, sizeof(*mfw));
 	mfw->fwmark = fwmark;
-#ifdef __SMP__
 	mfw->lock = (rwlock_t) RW_LOCK_UNLOCKED;
-#endif
 
 	INIT_LIST_HEAD(&mfw->hosts);
 out:
diff -u --recursive --new-file v2.3.8/linux/net/ipv4/ip_masq_mod.c linux/net/ipv4/ip_masq_mod.c
--- v2.3.8/linux/net/ipv4/ip_masq_mod.c	Sun Oct  4 10:21:45 1998
+++ linux/net/ipv4/ip_masq_mod.c	Tue Jun 29 09:22:08 1999
@@ -4,7 +4,7 @@
  *
  * Author:	Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
  *
- * 	$Id: ip_masq_mod.c,v 1.5 1998/08/29 23:51:09 davem Exp $
+ * 	$Id: ip_masq_mod.c,v 1.6 1999/06/29 12:35:51 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -33,9 +33,7 @@
 EXPORT_SYMBOL(ip_masq_mod_lkp_link);
 EXPORT_SYMBOL(ip_masq_mod_lkp_unlink);
 
-#ifdef __SMP__
 static spinlock_t masq_mod_lock = SPIN_LOCK_UNLOCKED;
-#endif
 
 /*
  *	Base pointer for registered modules
diff -u --recursive --new-file v2.3.8/linux/net/ipv4/ip_masq_portfw.c linux/net/ipv4/ip_masq_portfw.c
--- v2.3.8/linux/net/ipv4/ip_masq_portfw.c	Mon Jan  4 15:31:35 1999
+++ linux/net/ipv4/ip_masq_portfw.c	Tue Jun 29 09:22:08 1999
@@ -2,7 +2,7 @@
  *		IP_MASQ_PORTFW masquerading module
  *
  *
- *	$Id: ip_masq_portfw.c,v 1.3 1998/12/08 05:42:12 davem Exp $
+ *	$Id: ip_masq_portfw.c,v 1.4 1999/06/29 12:35:53 davem Exp $
  *
  * Author:	Steven Clarke <steven.clarke@monmouth.demon.co.uk>
  *
@@ -51,9 +51,7 @@
 /*
  *	Lock
  */
-#ifdef __SMP__
 static spinlock_t portfw_lock = SPIN_LOCK_UNLOCKED;
-#endif
 
 static struct list_head portfw_list[2];
 static __inline__ int portfw_idx(int protocol)
diff -u --recursive --new-file v2.3.8/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c
--- v2.3.8/linux/net/ipv4/ipconfig.c	Wed Jun  9 14:45:37 1999
+++ linux/net/ipv4/ipconfig.c	Tue Jun 29 09:22:08 1999
@@ -1,5 +1,5 @@
 /*
- *  $Id: ipconfig.c,v 1.22 1999/06/09 10:10:57 davem Exp $
+ *  $Id: ipconfig.c,v 1.23 1999/06/28 11:35:07 davem Exp $
  *
  *  Automatic Configuration of IP -- use BOOTP or RARP or user-supplied
  *  information to configure own IP address and routes.
@@ -666,7 +666,7 @@
 	    b->vendor_area[2] == 83 &&
 	    b->vendor_area[3] == 99) {
 		u8 *ext = &b->vendor_area[4];
-		u8 *end = (u8 *) b + len;
+                u8 *end = (u8 *) b + ntohs(b->iph.tot_len);
 		while (ext < end && *ext != 0xff) {
 			if (*ext == 0)		/* Padding */
 				ext++;
diff -u --recursive --new-file v2.3.8/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.3.8/linux/net/ipv4/tcp.c	Wed May 26 18:14:37 1999
+++ linux/net/ipv4/tcp.c	Tue Jun 29 09:22:08 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.144 1999/05/27 01:03:37 davem Exp $
+ * Version:	$Id: tcp.c,v 1.145 1999/06/29 12:35:56 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -749,7 +749,6 @@
 	int mss_now;
 	int err, copied;
 
-	unlock_kernel();
 	lock_sock(sk);
 
 	err = 0;
@@ -976,7 +975,6 @@
 out:
 	tcp_push_pending_frames(sk, tp);
 	release_sock(sk);
-	lock_kernel();
 	return err;
 }
 
@@ -1156,7 +1154,6 @@
 	if (flags & MSG_WAITALL)
 		target=len;
 
-	unlock_kernel();
 	add_wait_queue(sk->sleep, &wait);
 	lock_sock(sk);
 	
@@ -1355,7 +1352,6 @@
 	/* Clean up data we have read: This will do ACK frames. */
 	cleanup_rbuf(sk, copied);
 	release_sock(sk);
-	lock_kernel();
 	return copied;
 }
 
diff -u --recursive --new-file v2.3.8/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.3.8/linux/net/ipv4/udp.c	Wed Jun 16 19:26:27 1999
+++ linux/net/ipv4/udp.c	Tue Jun 29 09:22:08 1999
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.69 1999/06/09 11:15:31 davem Exp $
+ * Version:	$Id: udp.c,v 1.70 1999/06/13 05:55:16 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -654,9 +654,9 @@
 		struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name;
 		if (msg->msg_namelen < sizeof(*usin))
 			return(-EINVAL);
-		if (usin->sin_family != AF_INET) {
+		if (usin->sin_family != AF_INET)
 			return -EINVAL;
-		}
+
 		ufh.daddr = usin->sin_addr.s_addr;
 		ufh.uh.dest = usin->sin_port;
 		if (ufh.uh.dest == 0)
diff -u --recursive --new-file v2.3.8/linux/net/socket.c linux/net/socket.c
--- v2.3.8/linux/net/socket.c	Tue Jun  8 10:47:58 1999
+++ linux/net/socket.c	Wed Jun 30 12:41:40 1999
@@ -950,7 +950,6 @@
 	struct msghdr msg;
 	struct iovec iov;
 	
-	lock_kernel();
 	sock = sockfd_lookup(fd, &err);
 	if (!sock)
 		goto out;
@@ -977,7 +976,6 @@
 out_put:		
 	sockfd_put(sock);
 out:
-	unlock_kernel();
 	return err;
 }
 
@@ -1005,7 +1003,6 @@
 	char address[MAX_SOCK_ADDR];
 	int err,err2;
 
-	lock_kernel();
 	sock = sockfd_lookup(fd, &err);
 	if (!sock)
 		goto out;
@@ -1030,7 +1027,6 @@
 	}
 	sockfd_put(sock);			
 out:
-	unlock_kernel();
 	return err;
 }
 
@@ -1123,8 +1119,6 @@
 	struct msghdr msg_sys;
 	int err, ctl_len, iov_size, total_len;
 	
-	lock_kernel();
-
 	err = -EFAULT;
 	if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
 		goto out; 
@@ -1194,7 +1188,6 @@
 out_put:
 	sockfd_put(sock);
 out:       
-	unlock_kernel();
 	return err;
 }
 
@@ -1218,7 +1211,6 @@
 	struct sockaddr *uaddr;
 	int *uaddr_len;
 	
-	lock_kernel();
 	err=-EFAULT;
 	if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
 		goto out;
@@ -1282,7 +1274,6 @@
 out_put:
 	sockfd_put(sock);
 out:
-	unlock_kernel();
 	return err;
 }
 
diff -u --recursive --new-file v2.3.8/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.3.8/linux/net/sunrpc/xprt.c	Tue Jun  8 17:58:03 1999
+++ linux/net/sunrpc/xprt.c	Wed Jun 30 11:24:55 1999
@@ -42,7 +42,6 @@
 #define __KERNEL_SYSCALLS__
 
 #include <linux/version.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/malloc.h>
 #include <linux/sched.h>
@@ -1456,7 +1455,7 @@
 	proto = (sock->type == SOCK_DGRAM)? IPPROTO_UDP : IPPROTO_TCP;
 	if ((xprt = xprt_setup(sock, proto, ap, to)) != NULL) {
 		xprt->file = file;
-		file->f_count++;
+		atomic_inc(&file->f_count);
 	}
 
 	return xprt;
diff -u --recursive --new-file v2.3.8/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.3.8/linux/net/unix/af_unix.c	Wed May 26 18:14:38 1999
+++ linux/net/unix/af_unix.c	Tue Jun 29 09:22:08 1999
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.78 1999/05/27 00:38:41 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.79 1999/06/29 12:36:07 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -103,6 +103,7 @@
 #include <net/scm.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/smp_lock.h>
 
 #include <asm/checksum.h>
 
@@ -943,7 +944,7 @@
  *	Send AF_UNIX data.
  */
 
-static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+static int do_unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 			      struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -1040,6 +1041,7 @@
 	
 	if (!unix_peer(sk))
 		unix_unlock(other);
+
 	return len;
 
 out_unlock:
@@ -1050,8 +1052,18 @@
 	return err;
 }
 
+static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+			      struct scm_cookie *scm)
+{
+	int retval;
+
+	lock_kernel();
+	retval = do_unix_dgram_sendmsg(sock, msg, len, scm);
+	unlock_kernel();
+	return retval;
+}
 		
-static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+static int do_unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 			       struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -1120,9 +1132,9 @@
 		
 		if (skb==NULL)
 		{
-			if (sent)
-				goto out;
-			return err;
+			if (!sent)
+				sent = err;
+			goto out;
 		}
 
 		/*
@@ -1141,9 +1153,9 @@
 
 		if (memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) {
 			kfree_skb(skb);
-			if (sent)
-				goto out;
-			return -EFAULT;
+			if (!sent)
+				sent = -EFAULT;
+			goto out;
 		}
 
 		other=unix_peer(sk);
@@ -1155,7 +1167,8 @@
 				goto out;
 			if (!(msg->msg_flags&MSG_NOSIGNAL))
 				send_sig(SIGPIPE,current,0);
-			return -EPIPE;
+			sent = -EPIPE;
+			goto out;
 		}
 
 		skb_queue_tail(&other->receive_queue, skb);
@@ -1166,6 +1179,17 @@
 	return sent;
 }
 
+static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+			       struct scm_cookie *scm)
+{
+	int retval;
+
+	lock_kernel();
+	retval = do_unix_stream_sendmsg(sock, msg, len, scm);
+	unlock_kernel();
+	return retval;
+}
+
 /*
  *	Sleep until data has arrive. But check for races..
  */
@@ -1180,7 +1204,7 @@
 	}
 }
 
-static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+static int do_unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int size,
 			      int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -1257,8 +1281,18 @@
 	return err;
 }
 
+static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+			      int flags, struct scm_cookie *scm)
+{
+	int retval;
 
-static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+	lock_kernel();
+	retval = do_unix_dgram_recvmsg(sock, msg, size, flags, scm);
+	unlock_kernel();
+	return retval;
+}
+
+static int do_unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size,
 			       int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -1275,8 +1309,7 @@
 		return -EOPNOTSUPP;
 	if (flags&MSG_WAITALL)
 		target = size;
-		
-		
+
 	msg->msg_namelen = 0;
 
 	/* Lock the socket to prevent queue disordering
@@ -1390,6 +1423,17 @@
 
 	up(&sk->protinfo.af_unix.readsem);
 	return copied;
+}
+
+static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+			       int flags, struct scm_cookie *scm)
+{
+	int retval;
+
+	lock_kernel();
+	retval = do_unix_stream_recvmsg(sock, msg, size, flags, scm);
+	unlock_kernel();
+	return retval;
 }
 
 static int unix_shutdown(struct socket *sock, int mode)
diff -u --recursive --new-file v2.3.8/linux/net/unix/garbage.c linux/net/unix/garbage.c
--- v2.3.8/linux/net/unix/garbage.c	Mon Mar 22 10:06:09 1999
+++ linux/net/unix/garbage.c	Mon Jun 28 13:56:42 1999
@@ -199,7 +199,7 @@
 		 *	in flight we are in use.
 		 */
 		if(s->socket && s->socket->file &&
-		   s->socket->file->f_count > s->protinfo.af_unix.inflight)
+		   atomic_read(&s->socket->file->f_count) > s->protinfo.af_unix.inflight)
 			maybe_unmark_and_push(s);
 	}
 
diff -u --recursive --new-file v2.3.8/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
--- v2.3.8/linux/net/wanrouter/wanproc.c	Sun Nov 15 09:52:29 1998
+++ linux/net/wanrouter/wanproc.c	Sun Jun 27 10:10:41 1999
@@ -127,7 +127,7 @@
 	NULL,			/* readlink */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* truncate */
 	router_proc_perms
 };
@@ -167,7 +167,7 @@
 	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* get_block */
 	NULL,			/* truncate */
 	router_proc_perms
 };
