diff -u --recursive --new-file v2.4.4/linux/Documentation/DocBook/deviceiobook.tmpl linux/Documentation/DocBook/deviceiobook.tmpl
--- v2.4.4/linux/Documentation/DocBook/deviceiobook.tmpl	Fri Apr  6 10:42:55 2001
+++ linux/Documentation/DocBook/deviceiobook.tmpl	Tue May  1 14:20:25 2001
@@ -171,7 +171,7 @@
 	with 'isa_' and are <function>isa_readb</function>,
 	<function>isa_writeb</function>, <function>isa_readw</function>, 
 	<function>isa_writew</function>, <function>isa_readl</function>,
-	<function>isa_writel</function), <function>isa_memcpy_fromio</function>
+	<function>isa_writel</function>, <function>isa_memcpy_fromio</function>
 	and <function>isa_memcpy_toio</function>
       </para>
       <para>
diff -u --recursive --new-file v2.4.4/linux/Documentation/cris/README linux/Documentation/cris/README
--- v2.4.4/linux/Documentation/cris/README	Fri Apr  6 10:42:55 2001
+++ linux/Documentation/cris/README	Tue May  1 16:04:56 2001
@@ -1,13 +1,19 @@
 Linux 2.4 on the CRIS architecture
 ==================================
-$Id: README,v 1.6 2001/02/21 15:27:25 bjornw Exp $
+$Id: README,v 1.7 2001/04/19 12:38:32 bjornw Exp $
 
 This is a port of Linux 2.4 to Axis Communications ETRAX 100LX embedded 
 network CPU. For more information about CRIS and ETRAX please see further
 below.
 
-<to come: instructions on how to grab the right gcc, compiling and booting>
+In order to compile this you need a version of gcc with support for the
+ETRAX chip family. Please see this link for more information on how to 
+download the compiler and other tools useful when building and booting
+software for the ETRAX platform:
 
+http://developer.axis.com/doc/software/devboard_lx/install-howto.html
+
+<more specific information should come in this document later>
 
 What is CRIS ?
 --------------
@@ -97,7 +103,7 @@
 ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB
 eth0 initialized
 eth0: changed MAC to 00:40:8C:CD:00:00
-ETRAX 100LX serial-driver $Revision: 1.6 $, (c) 2000 Axis Communications AB
+ETRAX 100LX serial-driver $Revision: 1.7 $, (c) 2000 Axis Communications AB
 ttyS0 at 0xb0000060 is a builtin UART with DMA
 ttyS1 at 0xb0000068 is a builtin UART with DMA
 ttyS2 at 0xb0000070 is a builtin UART with DMA
@@ -127,7 +133,7 @@
 Hostname is bbox1
 Telnetd starting, using port 23.
   using /bin/sash as shell.
-sftpd[15]: sftpd $Revision: 1.6 $ starting up
+sftpd[15]: sftpd $Revision: 1.7 $ starting up
 
 
 
diff -u --recursive --new-file v2.4.4/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.4.4/linux/Documentation/devices.txt	Sat Dec 30 11:26:10 2000
+++ linux/Documentation/devices.txt	Tue May  1 16:04:56 2001
@@ -765,7 +765,7 @@
  36 char	Netlink support
 		  0 = /dev/route	Routing, device updates, kernel to user
 		  1 = /dev/skip		enSKIP security cache control
-		  3 = /dec/fwmonitor	Firewall packet copies
+		  3 = /dev/fwmonitor	Firewall packet copies
 		 16 = /dev/tap0		First Ethertap device
 		    ...
 		 31 = /dev/tap15	16th Ethertap device
@@ -2436,7 +2436,7 @@
 
 224 char	A2232 serial card
 		  0 = /dev/ttyY0		First A2232 port
-		  1 = /dev/cuy0			Second A2232 port
+		  1 = /dev/ttyY1		Second A2232 port
 		    ...
 
 225 char	A2232 serial card (alternate devices)
diff -u --recursive --new-file v2.4.4/linux/Documentation/scsi-generic.txt linux/Documentation/scsi-generic.txt
--- v2.4.4/linux/Documentation/scsi-generic.txt	Thu Apr 12 12:03:50 2001
+++ linux/Documentation/scsi-generic.txt	Tue May  1 16:04:56 2001
@@ -238,8 +238,8 @@
 open(const char * filename, int flags)
 --------------------------------------
 The filename should be an 'sg' device such as
-/dev/sg[a-z]
 /dev/sg[0,1,2,...]
+/dev/sg[a-z]             <<< now deprecated >>>
 or a symbolic link to one of these. [Devfs has its own sub-directory for
 sg devices with entries like: /dev/scsi/host1/bus2/target3/lun4/generic .]
 It seems as though SCSI devices are allocated to sg minor numbers in the
diff -u --recursive --new-file v2.4.4/linux/Documentation/sound/MAD16 linux/Documentation/sound/MAD16
--- v2.4.4/linux/Documentation/sound/MAD16	Mon Aug 23 10:23:23 1999
+++ linux/Documentation/sound/MAD16	Tue May  1 16:05:00 2001
@@ -1,3 +1,5 @@
+(This recipe has been edited to update the configuration symbols.)
+
 From: Shaw Carruthers <shaw@shawc.demon.co.uk>
 
 I have been using mad16 sound for some time now with no problems, current
@@ -14,9 +16,9 @@
 .config has:
 
 CONFIG_SOUND=m
-CONFIG_ADLIB=m
-CONFIG_MAD16=m
-CONFIG_YM3812=m
+CONFIG_SOUND_ADLIB=m
+CONFIG_SOUND_MAD16=m
+CONFIG_SOUND_YM3812=m
 
 modules.conf has:
 
diff -u --recursive --new-file v2.4.4/linux/Documentation/sound/Opti linux/Documentation/sound/Opti
--- v2.4.4/linux/Documentation/sound/Opti	Wed Mar  8 11:37:03 2000
+++ linux/Documentation/sound/Opti	Tue May  1 16:05:00 2001
@@ -29,21 +29,21 @@
 
 Sound card support should be enabled as a module (chose m).
 Answer 'm' for  these items:
-  Generic OPL2/OPL3 FM synthesizer support			(CONFIG_ADLIB)
-  Microsoft Sound System support				(CONFIG_MSS)
-  Support for OPTi MAD16 and/or Mozart based cards	 	(CONFIG_MAD16)
-  FM synthesizer (YM3812/OPL-3) support				(CONFIG_YM3812)
+  Generic OPL2/OPL3 FM synthesizer support		(CONFIG_SOUND_ADLIB)
+  Microsoft Sound System support			(CONFIG_SOUND_MSS)
+  Support for OPTi MAD16 and/or Mozart based cards	(CONFIG_SOUND_MAD16)
+  FM synthesizer (YM3812/OPL-3) support			(CONFIG_SOUND_YM3812)
 
 The configuration menu may ask for addresses, IRQ lines or DMA
 channels. If the card is used as a module the module loading
 options will override these values.
 
 For the OPTi 931 you can answer 'n' to:
-  Support MIDI in older MAD16 based cards (requires SB)		(CONFIG_MAD16_OLDCARD)
+  Support MIDI in older MAD16 based cards (requires SB)	(CONFIG_SOUND_MAD16_OLDCARD)
 If you do need MIDI support in a Mozart or C928 based card you
 need to answer 'm' to the above question. In that case you will
 also need to answer 'm' to:
-  '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SB)
+  '100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' (CONFIG_SOUND_SB)
 
 Go on and compile your kernel and modules. Install the modules. Run depmod -a.
 
diff -u --recursive --new-file v2.4.4/linux/MAINTAINERS linux/MAINTAINERS
--- v2.4.4/linux/MAINTAINERS	Wed Apr 25 14:35:25 2001
+++ linux/MAINTAINERS	Tue May  1 16:05:00 2001
@@ -161,7 +161,7 @@
 APPLETALK NETWORK LAYER
 P:	Jay Schulist
 M:	jschlst@turbolinux.com
-L:	linux-atalk@netspace.org
+L:	linux-atalk@lists.netspace.org
 S:	Maintained
 
 ARM MFM AND FLOPPY DRIVERS
@@ -280,13 +280,17 @@
 CONFIGURE, MENUCONFIG, XCONFIG
 P:	Michael Elizabeth Chastain
 M:	mec@shout.net
-L:	linux-kbuild@torque.net
-W:	http://www.kernel.org/pub/linux/kernel/projects/kbuild/
+L:	kbuild-devel@lists.sourceforge.net
+W:	http://kbuild.sourceforge.net
 S:	Maintained
 
 CONFIGURE.HELP
-P:	Axel Boldt
-M:	axel@uni-paderborn.de
+P:	Steven P. Cole
+M:	Steven P. Cole <elenstev@mesatop.com>
+P:	Eric S. Raymond
+M:	Eric S. Raymond <esr@thyrsus.com>
+L:	kbuild-devel@lists.sourceforge.net
+W:	http://kbuild.sourceforge.net
 S:	Maintained
 
 COSA/SRP SYNC SERIAL DRIVER
@@ -393,7 +397,7 @@
 
 DISK GEOMETRY AND PARTITION HANDLING
 P:     Andries Brouwer
-M:     aeb@veritas.com
+M:     aeb@cwi.nl
 W:     http://www.win.tue.nl/~aeb/linux/Large-Disk.html
 W:     http://www.win.tue.nl/~aeb/linux/zip/zip-1.html
 W:     http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
@@ -548,22 +552,6 @@
 W:	http://www.nt.tuwien.ac.at/~kkudielk/Linux/
 S:	Maintained
 
-KERNEL BUILD (Makefile, Rules.make, scripts/*)
-P:	Keith Owens
-M:	kaos@ocs.com.au
-P:	Michael Elizabeth Chastain
-M:	mec@shout.net
-L:	linux-kbuild@torque.net
-W:	http://www.kernel.org/pub/linux/kernel/projects/kbuild/
-S:	Maintained 
-
-LOGICAL VOLUME MANAGER
-P:     Heinz Mauelshagen
-M:     linux-LVM@EZ-Darmstadt.Telekom.de
-L:     linux-LVM@msede.com
-W:     http://linux.msede.com/lvm
-S:     Maintained 
-
 HIPPI
 P:	Jes Sorensen
 M:	jes@linuxcare.com
@@ -759,6 +747,15 @@
 L:	autofs@linux.kernel.org
 S:	Maintained
 
+KERNEL BUILD (Makefile, Rules.make, scripts/*)
+P:	Keith Owens
+M:	kaos@ocs.com.au
+P:	Michael Elizabeth Chastain
+M:	mec@shout.net
+L:	linux-kbuild@torque.net
+W:	http://www.kernel.org/pub/linux/kernel/projects/kbuild/
+S:	Maintained 
+
 KERNEL NFSD
 P:	Neil Brown
 M:	neilb@cse.unsw.edu.au
@@ -792,6 +789,13 @@
 W:	http://www.linuxppc.org/
 L:	linuxppc-dev@lists.linuxppc.org
 S:	Maintained
+
+LOGICAL VOLUME MANAGER
+P:     Heinz Mauelshagen
+M:     linux-LVM@EZ-Darmstadt.Telekom.de
+L:     linux-LVM@msede.com
+W:     http://linux.msede.com/lvm
+S:     Maintained 
 
 M68K
 P:	Jes Sorensen
diff -u --recursive --new-file v2.4.4/linux/Makefile linux/Makefile
--- v2.4.4/linux/Makefile	Fri Apr 27 18:17:19 2001
+++ linux/Makefile	Sat Apr 28 11:43:43 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 4
-EXTRAVERSION =
+SUBLEVEL = 5
+EXTRAVERSION =-pre1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file v2.4.4/linux/arch/cris/Makefile linux/arch/cris/Makefile
--- v2.4.4/linux/arch/cris/Makefile	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/Makefile	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.15 2001/02/16 17:50:04 larsv Exp $
+# $Id: Makefile,v 1.18 2001/04/17 13:58:38 orjanf Exp $
 # cris/Makefile
 #
 # This file is included by the global makefile so that you can add your own
@@ -25,8 +25,8 @@
 # regenerating stuff (even for incremental linking of subsystems!) is
 # even more nauseating.
 LD = if [ ! -e $(LD_SCRIPT).tmp -o $(LD_SCRIPT) -nt $(LD_SCRIPT).tmp ]; then \
-          sed -e s/@ETRAX_DRAM_VIRTUAL_BASE@/0x$(ETRAX_DRAM_VIRTUAL_BASE)/ \
-              -e s/@ETRAX_DRAM_SIZE_M@/$(ETRAX_DRAM_SIZE)/ \
+          sed -e s/@CONFIG_ETRAX_DRAM_VIRTUAL_BASE@/0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE)/ \
+              -e s/@CONFIG_ETRAX_DRAM_SIZE_M@/$(CONFIG_ETRAX_DRAM_SIZE)/ \
               < $(LD_SCRIPT) > $(LD_SCRIPT).tmp; \
      else true; \
      fi && $(CROSS_COMPILE)ld -mcriself
@@ -42,7 +42,7 @@
 
 CFLAGS := $(CFLAGS) -march=v10 -fno-strict-aliasing -pipe -D__linux__
 
-ifdef CONFIG_KGDB
+ifdef CONFIG_ETRAX_KGDB
 CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g
 CFLAGS += -fno-omit-frame-pointer
 endif
@@ -76,7 +76,7 @@
 
 cramfs:
 ## cramfs      - Creates a cramfs image
-	mkcramfs -b 8192 root cramfs.img
+	mkcramfs -b 8192 -m romfs_meta.txt root cramfs.img
 	cat vmlinux.bin cramfs.img >timage
 
 clinux: vmlinux.bin decompress.bin rescue.bin
diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/compressed/Makefile linux/arch/cris/boot/compressed/Makefile
--- v2.4.4/linux/arch/cris/boot/compressed/Makefile	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/boot/compressed/Makefile	Tue May  1 16:04:56 2001
@@ -24,7 +24,7 @@
 
 
 vmlinuz: piggy.img decompress.bin
-	cat decompress.bin piggy.img $(TOPDIR)/cramfs.img > vmlinuz
+	cat decompress.bin piggy.img > vmlinuz
 	rm -f piggy.img
 
 head.o: head.S
diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/compressed/head.S linux/arch/cris/boot/compressed/head.S
--- v2.4.4/linux/arch/cris/boot/compressed/head.S	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/boot/compressed/head.S	Tue May  1 16:04:56 2001
@@ -1,16 +1,19 @@
 /*
- *  arch/etrax100/boot/compressed/head.S
+ *  arch/cris/boot/compressed/head.S
  *
- *  Copyright (C) 1999 Axis Communications AB
+ *  Copyright (C) 1999, 2001 Axis Communications AB
  *
  *  Code that sets up the DRAM registers, calls the
  *  decompressor to unpack the piggybacked kernel, and jumps.
  *
  */
 
+#include <linux/config.h>
 #define ASSEMBLER_MACROS_ONLY
 #include <asm/sv_addr_ag.h>
 
+#define RAM_INIT_MAGIC 0x56902387
+	
 	;; Exported symbols
 	
 	.globl	_input_data
@@ -21,23 +24,28 @@
 	nop
 	di
 
-	;; We need to initialze DRAM registers before we start using the DRAM
-#include "../../lib/dram_init.S"
+;; We need to initialze DRAM registers before we start using the DRAM
 	
-dram_init_finished:
+	cmp.d	RAM_INIT_MAGIC, r8	; Already initialized?
+	beq	dram_init_finished
+	nop
+	
+#include "../../lib/dram_init.S"
 	
+dram_init_finished:	
+		
 	;; Initiate the PA and PB ports
 
-	move.b   DEF_R_PORT_PA_DATA, r0
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0
 	move.b   r0, [R_PORT_PA_DATA]
 
-	move.b   DEF_R_PORT_PA_DIR, r0
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0
 	move.b   r0, [R_PORT_PA_DIR]
 
-	move.b   DEF_R_PORT_PB_DATA, r0
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0
 	move.b   r0, [R_PORT_PB_DATA]
 
-	move.b   DEF_R_PORT_PB_DIR, r0
+	move.b   CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0
 	move.b   r0, [R_PORT_PB_DIR]
 
 	;; Setup the stack to a suitably high address.
@@ -70,6 +78,7 @@
 
 	move.d	r5, [_input_data] ; for the decompressor
 
+
 	;; Clear the decompressors BSS (between _edata and _end)
 	
 	moveq	0, r0
@@ -81,19 +90,22 @@
 	nop
 	
 	;; Do the decompression and save compressed size in _inptr
-	
+
 	jsr	_decompress_kernel
 	
-	;; Put start address of cramfs in r9 so the kernel can use it
+	;; Put start address of root partition in r9 so the kernel can use it
 	;; when mounting from flash
 
 	move.d	[_input_data], r9	; flash address of compressed kernel
 	add.d	[_inptr], r9		; size of compressed kernel
-
+	 
 	;; Enter the decompressed kernel
+	move.d	RAM_INIT_MAGIC, r8	; Tell kernel that DRAM is initialized
 	jump	0x40004000	; kernel is linked to this address
 	
 	.data
 
 _input_data:
 	.dword	0		; used by the decompressor
+
+#include "../../lib/hw_settings.S"
diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/compressed/misc.c linux/arch/cris/boot/compressed/misc.c
--- v2.4.4/linux/arch/cris/boot/compressed/misc.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/boot/compressed/misc.c	Tue May  1 16:04:56 2001
@@ -1,7 +1,7 @@
 /*
  * misc.c
  *
- * $Id: misc.c,v 1.3 2001/01/17 15:54:18 jonashg Exp $
+ * $Id: misc.c,v 1.6 2001/04/09 10:00:21 starvik Exp $
  * 
  * This is a collection of several routines from gzip-1.0.3 
  * adapted for Linux.
@@ -21,6 +21,7 @@
 #define KERNEL_LOAD_ADR 0x40004000
 
 #include <linux/config.h>
+
 #include <linux/types.h>
 #include <asm/svinto.h>
 
@@ -143,21 +144,21 @@
 static void
 puts(const char *s)
 {
-#ifndef CONFIG_DEBUG_PORT_NULL
+#ifndef CONFIG_ETRAX_DEBUG_PORT_NULL
 	while(*s) {
-#ifdef CONFIG_DEBUG_PORT0
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
 		while(!(*R_SERIAL0_STATUS & (1 << 5))) ;
 		*R_SERIAL0_TR_DATA = *s++;
 #endif
-#ifdef CONFIG_DEBUG_PORT1
+#ifdef CONFIG_ETRAX_DEBUG_PORT1
 		while(!(*R_SERIAL1_STATUS & (1 << 5))) ;
 		*R_SERIAL1_TR_DATA = *s++;
 #endif
-#ifdef CONFIG_DEBUG_PORT2
+#ifdef CONFIG_ETRAX_DEBUG_PORT2
 		while(!(*R_SERIAL2_STATUS & (1 << 5))) ;
 		*R_SERIAL2_TR_DATA = *s++;
 #endif
-#ifdef CONFIG_DEBUG_PORT3
+#ifdef CONFIG_ETRAX_DEBUG_PORT3
 		while(!(*R_SERIAL3_STATUS & (1 << 5))) ;
 		*R_SERIAL3_TR_DATA = *s++;
 #endif
@@ -227,33 +228,45 @@
 void
 decompress_kernel()
 {
+	char revision;
+	
 	/* input_data is set in head.S */
 	inbuf = input_data;
 
-#ifdef CONFIG_DEBUG_PORT0
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
 	*R_SERIAL0_XOFF = 0;
 	*R_SERIAL0_BAUD = 0x99;
 	*R_SERIAL0_TR_CTRL = 0x40;
 #endif
-#ifdef CONFIG_DEBUG_PORT1
+#ifdef CONFIG_ETRAX_DEBUG_PORT1
 	*R_SERIAL1_XOFF = 0;
 	*R_SERIAL1_BAUD = 0x99;
 	*R_SERIAL1_TR_CTRL = 0x40;
 #endif
-#ifdef CONFIG_DEBUG_PORT2
+#ifdef CONFIG_ETRAX_DEBUG_PORT2
+	*R_GEN_CONFIG = 0x08;
 	*R_SERIAL2_XOFF = 0;
 	*R_SERIAL2_BAUD = 0x99;
 	*R_SERIAL2_TR_CTRL = 0x40;
 #endif
-#ifdef CONFIG_DEBUG_PORT3
+#ifdef CONFIG_ETRAX_DEBUG_PORT3
+	*R_GEN_CONFIG = 0x100;
 	*R_SERIAL3_XOFF = 0;
 	*R_SERIAL3_BAUD = 0x99;
 	*R_SERIAL3_TR_CTRL = 0x40;
 #endif
-       
+
 	setup_normal_output_buffer();
 
 	makecrc();
+
+	__asm__ volatile ("move vr,%0" : "=rm" (revision));
+	if (revision < 10)
+	{
+		puts("You need an ETRAX 100LX to run linux 2.4\n");
+		while(1);
+	}
+
 	puts("Uncompressing Linux...\n");
 	gunzip();
 	puts("Done. Now booting the kernel.\n");
diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/rescue/head.S linux/arch/cris/boot/rescue/head.S
--- v2.4.4/linux/arch/cris/boot/rescue/head.S	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/boot/rescue/head.S	Tue May  1 16:04:56 2001
@@ -1,66 +1,67 @@
-	;; $Id: head.S,v 1.3 2001/02/14 16:57:25 larsv Exp $
-	;; 
-	;; Rescue code, made to reside at the beginning of the
-	;; flash-memory. when it starts, it checks a partition
-	;; table at the first sector after the rescue sector.
-	;; the partition table was generated by the product builder
-	;; script and contains offsets, lengths, types and checksums
-	;; for each partition that this code should check.
-	;;
-	;; If any of the checksums fail, we assume the flash is so
-	;; corrupt that we cant use it to boot into the ftp flash
-	;; loader, and instead we initialize the serial port to
-	;; receive a flash-loader and new flash image. we dont include
-	;; any flash code here, but just accept a certain amount of
-	;; bytes from the serial port and jump into it. the downloaded
-	;; code is put in the cache.
-	;;
-	;; The partitiontable is designed so that it is transparent to
-	;; code execution - it has a relative branch opcode in the
-	;; beginning that jumps over it. each entry contains extra
-	;; data so we can add stuff later.
-	;;
-	;; Partition table format:
-	;;
-	;;     Code transparency:
-	;; 
-	;;     2 bytes    [opcode 'nop']
-	;;     2 bytes    [opcode 'di']
-	;;     4 bytes    [opcode 'ba <offset>', 8-bit or 16-bit version]
-	;;     2 bytes    [opcode 'nop', delay slot]
-	;;
-	;;     Table validation (at +10):	
-	;; 
-	;;     2 bytes    [magic/version word for partitiontable - 0xef, 0xbe]
-	;;     2 bytes    [length of all entries plus the end marker]
-	;;     4 bytes    [checksum for the partitiontable itself]
-	;;
-	;;     Entries, each with the following format, last has offset -1:	
-	;;    
-	;;        4 bytes    [offset in bytes, from start of flash]
-	;;        4 bytes    [length in bytes of partition]
-	;;        4 bytes    [checksum, simple longword sum]
-	;;        2 bytes    [partition type]
-	;;        2 bytes    [flags, only bit 0 used, ro/rw = 1/0]
-	;;        16 bytes   [reserved for future use]
-	;;
-	;;     End marker
-	;;
-	;;        4 bytes    [-1]
-	;; 
-	;;	 10 bytes    [0, padding]
-	;; 
-	;; Bit 0 in flags signifies RW or RO. The rescue code only bothers
-	;; to check the checksum for RO partitions, since the others will
-	;; change its data without updating the checksums. A 1 in bit 0
-	;; means RO, 0 means RW. That way, it is possible to set a partition
-	;; in RO mode initially, and later mark it as RW, since you can always
-	;; write 0's to the flash.
-	;;
-	;; During the wait for serial input, the status LED will flash so the
-	;; user knows something went wrong.
-	;; 
-	;; Copyright (C) 1999 Axis Communications AB
+/* $Id: head.S,v 1.7 2001/04/18 12:05:07 bjornw Exp $
+ * 
+ * Rescue code, made to reside at the beginning of the
+ * flash-memory. when it starts, it checks a partition
+ * table at the first sector after the rescue sector.
+ * the partition table was generated by the product builder
+ * script and contains offsets, lengths, types and checksums
+ * for each partition that this code should check.
+ *
+ * If any of the checksums fail, we assume the flash is so
+ * corrupt that we cant use it to boot into the ftp flash
+ * loader, and instead we initialize the serial port to
+ * receive a flash-loader and new flash image. we dont include
+ * any flash code here, but just accept a certain amount of
+ * bytes from the serial port and jump into it. the downloaded
+ * code is put in the cache.
+ *
+ * The partitiontable is designed so that it is transparent to
+ * code execution - it has a relative branch opcode in the
+ * beginning that jumps over it. each entry contains extra
+ * data so we can add stuff later.
+ *
+ * Partition table format:
+ *
+ *     Code transparency:
+ * 
+ *     2 bytes    [opcode 'nop']
+ *     2 bytes    [opcode 'di']
+ *     4 bytes    [opcode 'ba <offset>', 8-bit or 16-bit version]
+ *     2 bytes    [opcode 'nop', delay slot]
+ *
+ *     Table validation (at +10):	
+ * 
+ *     2 bytes    [magic/version word for partitiontable - 0xef, 0xbe]
+ *     2 bytes    [length of all entries plus the end marker]
+ *     4 bytes    [checksum for the partitiontable itself]
+ *
+ *     Entries, each with the following format, last has offset -1:	
+ *    
+ *        4 bytes    [offset in bytes, from start of flash]
+ *        4 bytes    [length in bytes of partition]
+ *        4 bytes    [checksum, simple longword sum]
+ *        2 bytes    [partition type]
+ *        2 bytes    [flags, only bit 0 used, ro/rw = 1/0]
+ *        16 bytes   [reserved for future use]
+ *
+ *     End marker
+ *
+ *        4 bytes    [-1]
+ * 
+ *	 10 bytes    [0, padding]
+ * 
+ * Bit 0 in flags signifies RW or RO. The rescue code only bothers
+ * to check the checksum for RO partitions, since the others will
+ * change its data without updating the checksums. A 1 in bit 0
+ * means RO, 0 means RW. That way, it is possible to set a partition
+ * in RO mode initially, and later mark it as RW, since you can always
+ * write 0's to the flash.
+ *
+ * During the wait for serial input, the status LED will flash so the
+ * user knows something went wrong.
+ * 
+ * Copyright (C) 1999,2001 Axis Communications AB
+ */
 
 #include <linux/config.h>
 #define ASSEMBLER_MACROS_ONLY
@@ -69,7 +70,7 @@
 	;; The partitiontable is looked for at the first sector after the boot
 	;; sector. Sector size is 65536 bytes in all flashes we use.
 		
-#define PTABLE_START 0x10000
+#define PTABLE_START CONFIG_ETRAX_PTABLE_SECTOR
 #define PTABLE_MAGIC 0xbeef
 
 	;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0.
@@ -82,28 +83,28 @@
 #define CODE_START 0x40000000
 #define CODE_LENGTH 784
 
-#ifdef CONFIG_RESCUE_SER0
+#ifdef CONFIG_ETRAX_RESCUE_SER0
 #define SERXOFF R_SERIAL0_XOFF
 #define SERBAUD R_SERIAL0_BAUD
 #define SERRECC R_SERIAL0_REC_CTRL
 #define SERRDAT R_SERIAL0_REC_DATA
 #define SERSTAT R_SERIAL0_STATUS
 #endif
-#ifdef CONFIG_RESCUE_SER1
+#ifdef CONFIG_ETRAX_RESCUE_SER1
 #define SERXOFF R_SERIAL1_XOFF
 #define SERBAUD R_SERIAL1_BAUD
 #define SERRECC R_SERIAL1_REC_CTRL
 #define SERRDAT R_SERIAL1_REC_DATA
 #define SERSTAT R_SERIAL1_STATUS
 #endif
-#ifdef CONFIG_RESCUE_SER2
+#ifdef CONFIG_ETRAX_RESCUE_SER2
 #define SERXOFF R_SERIAL2_XOFF
 #define SERBAUD R_SERIAL2_BAUD
 #define SERRECC R_SERIAL2_REC_CTRL
 #define SERRDAT R_SERIAL2_REC_DATA
 #define SERSTAT R_SERIAL2_STATUS
 #endif	
-#ifdef CONFIG_RESCUE_SER3
+#ifdef CONFIG_ETRAX_RESCUE_SER3
 #define SERXOFF R_SERIAL3_XOFF
 #define SERBAUD R_SERIAL3_BAUD
 #define SERRECC R_SERIAL3_REC_CTRL
@@ -112,7 +113,8 @@
 #endif
 
 #define NOP_DI 0xf025050f
-	
+#define RAM_INIT_MAGIC 0x56902387
+		
 	.text
 	
 	;; This is the entry point of the rescue code
@@ -221,14 +223,14 @@
 	;; setup port PA and PB default initial directions and data
 	;; (so we can flash LEDs, and so that DTR and others are set)
 	
-	move.b	DEF_R_PORT_PA_DIR, r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0
 	move.b	r0, [R_PORT_PA_DIR]
-	move.b	DEF_R_PORT_PA_DATA, r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0
 	move.b	r0, [R_PORT_PA_DATA]
 	
-	move.b	DEF_R_PORT_PB_DIR, r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0
 	move.b	r0, [R_PORT_PB_DIR]
-	move.b	DEF_R_PORT_PB_DATA, r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0
 	move.b	r0, [R_PORT_PB_DATA]
 
 	;; setup the serial port at 115200 baud
@@ -250,10 +252,10 @@
 	addq	1, r1
 #ifndef CONFIG_ETRAX_NO_LEDS
 #ifdef CONFIG_ETRAX_PA_LEDS
-	move.b	DEF_R_PORT_PA_DATA, r2
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r2
 #endif
 #ifdef CONFIG_ETRAX_PB_LEDS
-	move.b	DEF_R_PORT_PB_DATA, r2
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r2
 #endif
 	move.d	(1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0
 	btstq	16, r1
@@ -293,7 +295,8 @@
 	nop
 
 	;; jump into downloaded code
-	
+
+	move.d	RAM_INIT_MAGIC, r8	; Tell next product that DRAM is initialized
 	jump	CODE_START
 
 flash_ok:
@@ -303,7 +306,8 @@
 	bne	1f
 	nop
 	move.d	PTABLE_START, r7; otherwise use the ptable start
-1:	
+1:
+	move.d	RAM_INIT_MAGIC, r8	; Tell next product that DRAM is initialized
 	jump	r7		; boot!
 
 
diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/rescue/kimagerescue.S linux/arch/cris/boot/rescue/kimagerescue.S
--- v2.4.4/linux/arch/cris/boot/rescue/kimagerescue.S	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/boot/rescue/kimagerescue.S	Tue May  1 16:04:56 2001
@@ -1,41 +1,42 @@
-	;; $Id: kimagerescue.S,v 1.2 2001/02/14 16:57:25 larsv Exp $
-	;; 
-	;; Rescue code to be prepended on a kimage and copied to the
-	;; rescue serial port.
-	;; This is called from the rescue code, it will copy received data to
-	;; 4000500 and after a timeout jump to it.
-	
+/* $Id: kimagerescue.S,v 1.4 2001/04/18 12:04:46 bjornw Exp $
+ * 
+ * Rescue code to be prepended on a kimage and copied to the
+ * rescue serial port.
+ * This is called from the rescue code, it will copy received data to
+ * 4004000 and after a timeout jump to it.
+ */
+
 #include <linux/config.h>
 #define ASSEMBLER_MACROS_ONLY
 #include <asm/sv_addr_ag.h>
 
-#define CODE_START 0x40000500
+#define CODE_START 0x40004000
 #define CODE_LENGTH 784
 #define TIMEOUT_VALUE 1000
 	
 		
-#ifdef CONFIG_RESCUE_SER0
+#ifdef CONFIG_ETRAX_RESCUE_SER0
 #define SERXOFF R_SERIAL0_XOFF
 #define SERBAUD R_SERIAL0_BAUD
 #define SERRECC R_SERIAL0_REC_CTRL
 #define SERRDAT R_SERIAL0_REC_DATA
 #define SERSTAT R_SERIAL0_STATUS
 #endif
-#ifdef CONFIG_RESCUE_SER1
+#ifdef CONFIG_ETRAX_RESCUE_SER1
 #define SERXOFF R_SERIAL1_XOFF
 #define SERBAUD R_SERIAL1_BAUD
 #define SERRECC R_SERIAL1_REC_CTRL
 #define SERRDAT R_SERIAL1_REC_DATA
 #define SERSTAT R_SERIAL1_STATUS
 #endif
-#ifdef CONFIG_RESCUE_SER2
+#ifdef CONFIG_ETRAX_RESCUE_SER2
 #define SERXOFF R_SERIAL2_XOFF
 #define SERBAUD R_SERIAL2_BAUD
 #define SERRECC R_SERIAL2_REC_CTRL
 #define SERRDAT R_SERIAL2_REC_DATA
 #define SERSTAT R_SERIAL2_STATUS
 #endif	
-#ifdef CONFIG_RESCUE_SER3
+#ifdef CONFIG_ETRAX_RESCUE_SER3
 #define SERXOFF R_SERIAL3_XOFF
 #define SERBAUD R_SERIAL3_BAUD
 #define SERRECC R_SERIAL3_REC_CTRL
@@ -55,14 +56,14 @@
 	;; setup port PA and PB default initial directions and data
 	;; (so we can flash LEDs, and so that DTR and others are set)
 	
-	move.b	DEF_R_PORT_PA_DIR, r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0
 	move.b	r0, [R_PORT_PA_DIR]
-	move.b	DEF_R_PORT_PA_DATA, r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0
 	move.b	r0, [R_PORT_PA_DATA]
 	
-	move.b	DEF_R_PORT_PB_DIR, r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0
 	move.b	r0, [R_PORT_PB_DIR]
-	move.b	DEF_R_PORT_PB_DATA, r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0
 	move.b	r0, [R_PORT_PB_DATA]
 	
 	;; We need to setup the bus registers before we start using the DRAM
@@ -99,10 +100,10 @@
 	nop
 #ifndef CONFIG_ETRAX_NO_LEDS
 #ifdef CONFIG_ETRAX_PA_LEDS
-	move.b	DEF_R_PORT_PA_DATA, r2
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r2
 #endif
 #ifdef CONFIG_ETRAX_PB_LEDS
-	move.b	DEF_R_PORT_PB_DATA, r2
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r2
 #endif
 	move.d	(1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), r0
 	btstq	16, r1
diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/rescue/testrescue.S linux/arch/cris/boot/rescue/testrescue.S
--- v2.4.4/linux/arch/cris/boot/rescue/testrescue.S	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/boot/rescue/testrescue.S	Tue May  1 16:04:56 2001
@@ -1,9 +1,10 @@
-	;; $Id: testrescue.S,v 1.1 2001/01/31 15:32:09 johana Exp $
-	;;
-	;; Simple testcode to download by the rescue block.
-	;; Just lits some LEDs to show it was downloaded correctly.
-	;; 
-	;; Copyright (C) 1999 Axis Communications AB
+/* $Id: testrescue.S,v 1.2 2001/04/18 12:05:07 bjornw Exp $
+ *
+ * Simple testcode to download by the rescue block.
+ * Just lits some LEDs to show it was downloaded correctly.
+ * 
+ * Copyright (C) 1999 Axis Communications AB
+ */
 
 #define ASSEMBLER_MACROS_ONLY
 #include <asm/sv_addr_ag.h>
diff -u --recursive --new-file v2.4.4/linux/arch/cris/boot/tools/build.c linux/arch/cris/boot/tools/build.c
--- v2.4.4/linux/arch/cris/boot/tools/build.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/boot/tools/build.c	Tue May  1 16:04:56 2001
@@ -31,6 +31,7 @@
 #include <unistd.h>	/* contains read/write */
 #include <fcntl.h>
 #include <linux/a.out.h>
+#include <linux/config.h>
 #include <errno.h>
 
 #define MINIX_HEADER 32
diff -u --recursive --new-file v2.4.4/linux/arch/cris/config.in linux/arch/cris/config.in
--- v2.4.4/linux/arch/cris/config.in	Tue Apr 17 17:19:24 2001
+++ linux/arch/cris/config.in	Tue May  1 16:04:56 2001
@@ -24,14 +24,10 @@
   tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 fi
 
-bool 'Use kernel gdb debugger' CONFIG_KGDB
+bool 'Use kernel gdb debugger' CONFIG_ETRAX_KGDB
 
 bool 'Enable Etrax100 watchdog' CONFIG_ETRAX_WATCHDOG
 
-bool 'Use serial console (on the debug port)' CONFIG_USE_SERIAL_CONSOLE
-
-bool 'Use in-kernel ifconfig/route setup' CONFIG_KERNEL_IFCONFIG
-
 endmenu
 
 mainmenu_option next_comment
@@ -46,20 +42,19 @@
 
 if [ "$CONFIG_ETRAX100LX" = "y" -o "$CONFIG_SVINTO_SIM" = "y" ]; then
 	define_bool CONFIG_CRIS_LOW_MAP y
-	define_hex  ETRAX_DRAM_VIRTUAL_BASE 60000000
+	define_hex  CONFIG_ETRAX_DRAM_VIRTUAL_BASE 60000000
 else
-	define_hex  ETRAX_DRAM_VIRTUAL_BASE c0000000
+	define_hex  CONFIG_ETRAX_DRAM_VIRTUAL_BASE c0000000
 fi
 
-int 'DRAM size (dec, in MB)' ETRAX_DRAM_SIZE 8
+int 'DRAM size (dec, in MB)' CONFIG_ETRAX_DRAM_SIZE 8
 
-int 'Max possible flash size (dec, in MB)' CONFIG_ETRAX_FLASH_LENGTH 2
 int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2
 
 choice 'Product LED port' \
 	"Port-PA-LEDs	CONFIG_ETRAX_PA_LEDS	\
 	 Port-PB-LEDs	CONFIG_ETRAX_PB_LEDS	\
-	 Mem-0x90000000-LEDs	CONFIG_ETRAX_90000000_LEDS  \
+	 Port-CSP0-LEDs	CONFIG_ETRAX_CSP0_LEDS  \
 	 None	CONFIG_ETRAX_NO_LEDS" Port-PA-LEDs
 
 if [ "$CONFIG_ETRAX_NO_LEDS" != "y" ]; then
@@ -71,38 +66,54 @@
   int '  Third red LED bit' CONFIG_ETRAX_LED3G 2
 fi
 
+if [ "$CONFIG_ETRAX_CSP0_LEDS" = "y" ]; then
+  int '  Fourth red LED bit' CONFIG_ETRAX_LED4R 2
+  int '  Fourth green LED bit' CONFIG_ETRAX_LED4G 2
+  int '  Fifth red LED bit' CONFIG_ETRAX_LED5R 2
+  int '  Fifth green LED bit' CONFIG_ETRAX_LED5G 2
+  int '  Sixth red LED bit' CONFIG_ETRAX_LED6R 2
+  int '  Sixth green LED bit' CONFIG_ETRAX_LED6G 2
+  int '  Seventh red LED bit' CONFIG_ETRAX_LED7R 2
+  int '  Seventh green LED bit' CONFIG_ETRAX_LED7G 2
+  int '  Eigth yellow LED bit' CONFIG_ETRAX_LED8Y 2
+  int '  Ninth yellow LED bit' CONFIG_ETRAX_LED9Y 2
+  int '  Tenth yellow LED bit' CONFIG_ETRAX_LED10Y 2
+  int '  Eleventh yellow LED bit' CONFIG_ETRAX_LED11Y 2
+  int '  Twelfth red LED bit' CONFIG_ETRAX_LED12R 2
+fi  
+
 choice 'Product debug-port' \
-	"Serial-0	CONFIG_DEBUG_PORT0	\
-	 Serial-1	CONFIG_DEBUG_PORT1	\
-	 Serial-2	CONFIG_DEBUG_PORT2	\
-	 Serial-3	CONFIG_DEBUG_PORT3	\
-	 disabled	CONFIG_DEBUG_PORT_NULL" Serial-0 
+	"Serial-0	CONFIG_ETRAX_DEBUG_PORT0	\
+	 Serial-1	CONFIG_ETRAX_DEBUG_PORT1	\
+	 Serial-2	CONFIG_ETRAX_DEBUG_PORT2	\
+	 Serial-3	CONFIG_ETRAX_DEBUG_PORT3	\
+	 disabled	CONFIG_ETRAX_DEBUG_PORT_NULL" Serial-0 
 
 choice 'Product rescue-port' \
-	"Serial-0	CONFIG_RESCUE_SER0	\
-	 Serial-1	CONFIG_RESCUE_SER1	\
-	 Serial-2	CONFIG_RESCUE_SER2	\
-	 Serial-3	CONFIG_RESCUE_SER3" Serial-0
-
-hex 'R_WAITSTATES' DEF_R_WAITSTATES 95a6
-hex 'R_BUS_CONFIG' DEF_R_BUS_CONFIG 104
-
-bool 'SDRAM support' CONFIG_SDRAM n
-if [ "$CONFIG_SDRAM" = "n" ]; then
-	hex 'R_DRAM_CONFIG' DEF_R_DRAM_CONFIG 1a200040
-	hex 'R_DRAM_TIMING' DEF_R_DRAM_TIMING 5611
+	"Serial-0	CONFIG_ETRAX_RESCUE_SER0	\
+	 Serial-1	CONFIG_ETRAX_RESCUE_SER1	\
+	 Serial-2	CONFIG_ETRAX_RESCUE_SER2	\
+	 Serial-3	CONFIG_ETRAX_RESCUE_SER3" Serial-0
+
+hex 'R_WAITSTATES' CONFIG_ETRAX_DEF_R_WAITSTATES 95a6
+hex 'R_BUS_CONFIG' CONFIG_ETRAX_DEF_R_BUS_CONFIG 104
+
+bool 'SDRAM support' CONFIG_ETRAX_SDRAM n
+if [ "$CONFIG_ETRAX_SDRAM" = "n" ]; then
+	hex 'R_DRAM_CONFIG' CONFIG_ETRAX_DEF_R_DRAM_CONFIG 1a200040
+	hex 'R_DRAM_TIMING' CONFIG_ETRAX_DEF_R_DRAM_TIMING 5611
 fi
 
-if [ "$CONFIG_SDRAM" = "y" ]; then
-	hex 'R_SDRAM_CONFIG' DEF_R_SDRAM_CONFIG d2fa7878
-	hex 'R_SDRAM_TIMING' DEF_R_SDRAM_TIMING 80004801
+if [ "$CONFIG_ETRAX_SDRAM" = "y" ]; then
+	hex 'R_SDRAM_CONFIG' CONFIG_ETRAX_DEF_R_SDRAM_CONFIG d2fa7878
+	hex 'R_SDRAM_TIMING' CONFIG_ETRAX_DEF_R_SDRAM_TIMING 80004801
 fi
 
-hex 'R_PORT_PA_DIR' DEF_R_PORT_PA_DIR 1c
-hex 'R_PORT_PA_DATA' DEF_R_PORT_PA_DATA 00
-hex 'R_PORT_PB_CONFIG' DEF_R_PORT_PB_CONFIG 00
-hex 'R_PORT_PB_DIR' DEF_R_PORT_PB_DIR 00
-hex 'R_PORT_PB_DATA' DEF_R_PORT_PB_DATA ff
+hex 'R_PORT_PA_DIR' CONFIG_ETRAX_DEF_R_PORT_PA_DIR 1c
+hex 'R_PORT_PA_DATA' CONFIG_ETRAX_DEF_R_PORT_PA_DATA 00
+hex 'R_PORT_PB_CONFIG' CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG 00
+hex 'R_PORT_PB_DIR' CONFIG_ETRAX_DEF_R_PORT_PB_DIR 00
+hex 'R_PORT_PB_DATA' CONFIG_ETRAX_DEF_R_PORT_PB_DATA ff
 
 endmenu
 
diff -u --recursive --new-file v2.4.4/linux/arch/cris/cris.ld linux/arch/cris/cris.ld
--- v2.4.4/linux/arch/cris/cris.ld	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/cris.ld	Tue May  1 16:04:56 2001
@@ -1,10 +1,16 @@
 /* ld script to make the Linux/CRIS kernel
  * Authors: Bjorn Wesen (bjornw@axis.com)
+ *
+ * It is VERY DANGEROUS to fiddle around with the symbols in this
+ * script. It is for example quite vital that all generated sections
+ * that are used are actually named here, otherwise the linker will
+ * put them at the end, where the init stuff is which is FREED after
+ * the kernel has booted. 
  */	
 
 SECTIONS
 {
-	. = @ETRAX_DRAM_VIRTUAL_BASE@;
+	. = @CONFIG_ETRAX_DRAM_VIRTUAL_BASE@;
 	_dram_start = .;
 	_ibr_start = .;
 	. = . + 0x4000; /* see head.S and pages reserved at the start */
@@ -75,5 +81,5 @@
 		*(.exitcall.exit)
         }
 
-	_dram_end = _dram_start + @ETRAX_DRAM_SIZE_M@*1024*1024;
+	_dram_end = _dram_start + @CONFIG_ETRAX_DRAM_SIZE_M@*1024*1024;
 }
diff -u --recursive --new-file v2.4.4/linux/arch/cris/defconfig linux/arch/cris/defconfig
--- v2.4.4/linux/arch/cris/defconfig	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/defconfig	Tue May  1 16:04:56 2001
@@ -15,10 +15,8 @@
 CONFIG_SYSVIPC=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_JAVA is not set
-# CONFIG_KGDB is not set
+# CONFIG_ETRAX_KGDB is not set
 # CONFIG_ETRAX_WATCHDOG is not set
-CONFIG_USE_SERIAL_CONSOLE=y
-# CONFIG_KERNEL_IFCONFIG is not set
 
 #
 # Hardware setup
@@ -27,8 +25,8 @@
 # CONFIG_ETRAX100LX_V2 is not set
 # CONFIG_SVINTO_SIM is not set
 CONFIG_CRIS_LOW_MAP=y
-ETRAX_DRAM_VIRTUAL_BASE=60000000
-ETRAX_DRAM_SIZE=8
+CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000
+CONFIG_ETRAX_DRAM_SIZE=8
 CONFIG_ETRAX_FLASH_LENGTH=2
 CONFIG_ETRAX_FLASH_BUSWIDTH=2
 CONFIG_ETRAX_PA_LEDS=y
@@ -39,24 +37,24 @@
 CONFIG_ETRAX_LED1R=2
 CONFIG_ETRAX_LED2G=2
 CONFIG_ETRAX_LED2R=2
-CONFIG_DEBUG_PORT0=y
-# CONFIG_DEBUG_PORT1 is not set
-# CONFIG_DEBUG_PORT2 is not set
-# CONFIG_DEBUG_PORT3 is not set
-CONFIG_RESCUE_SER0=y
-# CONFIG_RESCUE_SER1 is not set
-# CONFIG_RESCUE_SER2 is not set
-# CONFIG_RESCUE_SER3 is not set
-DEF_R_WAITSTATES=95a6
-DEF_R_BUS_CONFIG=104
-# CONFIG_SDRAM is not set
-DEF_R_DRAM_CONFIG=1a200040
-DEF_R_DRAM_TIMING=5611
-DEF_R_PORT_PA_DIR=1d
-DEF_R_PORT_PA_DATA=f0
-DEF_R_PORT_PB_CONFIG=00
-DEF_R_PORT_PB_DIR=1e
-DEF_R_PORT_PB_DATA=f3
+CONFIG_ETRAX_DEBUG_PORT0=y
+# CONFIG_ETRAX_DEBUG_PORT1 is not set
+# CONFIG_ETRAX_DEBUG_PORT2 is not set
+# CONFIG_ETRAX_DEBUG_PORT3 is not set
+CONFIG_ETRAX_RESCUE_SER0=y
+# CONFIG_ETRAX_RESCUE_SER1 is not set
+# CONFIG_ETRAX_RESCUE_SER2 is not set
+# CONFIG_ETRAX_RESCUE_SER3 is not set
+CONFIG_ETRAX_DEF_R_WAITSTATES=95a6
+CONFIG_ETRAX_DEF_R_BUS_CONFIG=104
+# CONFIG_ETRAX_SDRAM is not set
+CONFIG_ETRAX_DEF_R_DRAM_CONFIG=1a200040
+CONFIG_ETRAX_DEF_R_DRAM_TIMING=5611
+CONFIG_ETRAX_DEF_R_PORT_PA_DIR=1d
+CONFIG_ETRAX_DEF_R_PORT_PA_DATA=f0
+CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00
+CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e
+CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3
 
 #
 # Drivers for Etrax built-in interfaces
@@ -69,7 +67,7 @@
 # CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set
 # CONFIG_ETRAX_SERIAL_PORT2 is not set
 # CONFIG_ETRAX_SERIAL_PORT3 is not set
-# CONFIG_RS485 is not set
+# CONFIG_ETRAX_RS485 is not set
 # CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set
 # CONFIG_ETRAX_IDE is not set
 CONFIG_ETRAX_AXISFLASHMAP=y
@@ -84,15 +82,10 @@
 CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y
 CONFIG_ETRAX_GPIO=y
 CONFIG_ETRAX_PA_BUTTON_BITMASK=02
-CONFIG_PA_CHANGEABLE_DIR=00
-CONFIG_PA_CHANGEABLE_BITS=FF
-CONFIG_PB_CHANGEABLE_DIR=00
-CONFIG_PB_CHANGEABLE_BITS=FF
-# CONFIG_JULIETTE is not set
-# CONFIG_JULIETTE_VIDEO is not set
-# CONFIG_JULIETTE_CCD is not set
-# CONFIG_JULIETTE_SS1M is not set
-# CONFIG_JULIETTE_MEGCCD is not set
+CONFIG_ETRAX_PA_CHANGEABLE_DIR=00
+CONFIG_ETRAX_PA_CHANGEABLE_BITS=FF
+CONFIG_ETRAX_PB_CHANGEABLE_DIR=00
+CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF
 # CONFIG_ETRAX_USB_HOST is not set
 
 #
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/Config.in linux/arch/cris/drivers/Config.in
--- v2.4.4/linux/arch/cris/drivers/Config.in	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/Config.in	Tue May  1 16:04:56 2001
@@ -1,5 +1,5 @@
 mainmenu_option next_comment
-comment 'Drivers for Etrax built-in interfaces'
+comment 'Drivers for ETRAX 100LX built-in interfaces'
 
 bool 'Ethernet support' CONFIG_ETRAX_ETHERNET
 if [ "$CONFIG_ETRAX_ETHERNET" = "y" ]; then
@@ -46,13 +46,13 @@
     fi 
   fi
   bool '  Serial port 3 enabled' CONFIG_ETRAX_SERIAL_PORT3
-  bool '  RS-485 support' CONFIG_RS485
-  if [ "$CONFIG_RS485" = "y" ]; then
-    bool '    RS-485 mode on PA' CONFIG_RS485_ON_PA
-    if [ "$CONFIG_RS485_ON_PA" = "y" ]; then
-      int '      RS-485 mode on PA bit' CONFIG_RS485_ON_PA_BIT 3
+  bool '  RS-485 support' CONFIG_ETRAX_RS485
+  if [ "$CONFIG_ETRAX_RS485" = "y" ]; then
+    bool '    RS-485 mode on PA' CONFIG_ETRAX_RS485_ON_PA
+    if [ "$CONFIG_ETRAX_RS485_ON_PA" = "y" ]; then
+      int '      RS-485 mode on PA bit' CONFIG_ETRAX_RS485_ON_PA_BIT 3
     fi
-    bool '    Disable serial receiver' CONFIG_RS485_DISABLE_RECEIVER
+    bool '    Disable serial receiver' CONFIG_ETRAX_RS485_DISABLE_RECEIVER
   fi
 fi
 
@@ -60,14 +60,29 @@
 if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL" = "y" ]; then 
   bool '  Synchronous serial port 0 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0
   if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0" = "y" ]; then
-    bool '    Synchronous serial port 0 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA y
+    bool '    Synchronous serial port 0 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA
   fi
   bool '  Synchronous serial port 1 enabled' CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1
   if [ "$CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1" = "y" ]; then
-    bool '    Synchronous serial port 1 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA y
+    bool '    Synchronous serial port 1 uses DMA' CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA
   fi 
 fi
 
+bool 'Parallel port support' CONFIG_ETRAX_PARPORT
+if [ "$CONFIG_ETRAX_PARPORT" = "y" ]; then
+	bool '  Parallel port 0 enabled' CONFIG_ETRAX_PARALLEL_PORT0
+	bool '  Parallel port 1 enabled' CONFIG_ETRAX_PARALLEL_PORT1
+# here we define the CONFIG_'s necessary to enable parallel port support
+	define_tristate CONFIG_PARPORT y
+        define_bool CONFIG_PARPORT_1284 y
+        define_tristate CONFIG_PRINTER y
+else
+	define_tristate CONFIG_PARPORT n
+        define_bool CONFIG_PARPORT_1284 n
+        define_tristate CONFIG_PRINTER n
+fi
+
+
 bool 'ATA/IDE support' CONFIG_ETRAX_IDE
 
 if [ "$CONFIG_ETRAX_IDE" = "y" ]; then
@@ -89,7 +104,8 @@
 	choice 'IDE reset pin' \
   	"Port_PB_Bit_7  CONFIG_ETRAX_IDE_PB7_RESET\
    	 Port_G_Bit_27  CONFIG_ETRAX_IDE_G27_RESET\
-   	 Port_CSE1_Bit_16  CONFIG_ETRAX_IDE_CSE1_16_RESET" Port_PB_Bit_7 
+	 Port_CSE1_Bit_16  CONFIG_ETRAX_IDE_CSE1_16_RESET\
+	 Port_CSP0_Bit_08   CONFIG_ETRAX_IDE_CSP0_8_RESET"  Port_PB_Bit_7
 else
 	define_bool CONFIG_IDE n
 fi
@@ -97,6 +113,7 @@
 bool 'Axis flash-map support' CONFIG_ETRAX_AXISFLASHMAP
 
 if [ "$CONFIG_ETRAX_AXISFLASHMAP" = "y" ]; then
+        int  '  Byte-offset of partition table sector' CONFIG_ETRAX_PTABLE_SECTOR 65536
 # here we define the CONFIG_'s necessary to enable MTD support
 # for the flash
 	define_bool CONFIG_MTD y
@@ -118,16 +135,25 @@
 	bool 'I2C uses PB not PB-I2C' CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
 fi
 
+bool 'I2C EEPROM (non-volatile RAM) support' CONFIG_ETRAX_I2C_EEPROM
+if [ "$CONFIG_ETRAX_I2C_EEPROM" = "y" ]; then
+  choice '  EEPROM size' \
+    "Probed CONFIG_ETRAX_I2C_EEPROM_PROBE \
+     2kB    CONFIG_ETRAX_I2C_EEPROM_2KB   \
+     8kB    CONFIG_ETRAX_I2C_EEPROM_8KB   \
+     16kB   CONFIG_ETRAX_I2C_EEPROM_16KB" Probed
+fi
+
 bool 'GPIO support' CONFIG_ETRAX_GPIO
 if [ "$CONFIG_ETRAX_GPIO" = "y" ]; then
   hex  '  PA-buttons bitmask' CONFIG_ETRAX_PA_BUTTON_BITMASK 02
-  hex  '  PA user changeable dir mask' CONFIG_PA_CHANGEABLE_DIR 00
-  hex  '  PA user changeable bits mask' CONFIG_PA_CHANGEABLE_BITS FF
-  hex  '  PB user changeable dir mask' CONFIG_PB_CHANGEABLE_DIR 00
-  hex  '  PB user changeable bits mask' CONFIG_PB_CHANGEABLE_BITS FF
+  hex  '  PA user changeable dir mask' CONFIG_ETRAX_PA_CHANGEABLE_DIR 00
+  hex  '  PA user changeable bits mask' CONFIG_ETRAX_PA_CHANGEABLE_BITS FF
+  hex  '  PB user changeable dir mask' CONFIG_ETRAX_PB_CHANGEABLE_DIR 00
+  hex  '  PB user changeable bits mask' CONFIG_ETRAX_PB_CHANGEABLE_BITS FF
 fi
 
-bool 'Juliette support' CONFIG_JULIETTE n
+bool 'ARTPEC-1 support' CONFIG_JULIETTE
 
 if [ "$CONFIG_JULIETTE" = "y" ]; then
    source arch/cris/drivers/juliette/Config.in
@@ -136,8 +162,18 @@
 bool 'USB host' CONFIG_ETRAX_USB_HOST
 if [ "$CONFIG_ETRAX_USB_HOST" = "y" ]; then
 	define_bool CONFIG_USB y
-	bool '  USB port 1 enabled' CONFIG_ETRAX_USB_HOST_PORT1 n
-	bool '  USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2 n
+	bool '  USB port 1 enabled' CONFIG_ETRAX_USB_HOST_PORT1
+	bool '  USB port 2 enabled' CONFIG_ETRAX_USB_HOST_PORT2
+else
+	define_bool CONFIG_USB n
+fi
+
+bool 'DS1302 Real Time Clock support' CONFIG_ETRAX_DS1302
+if [ "$CONFIG_ETRAX_DS1302" = "y" ]; then
+  bool '  DS1302 RST on Generic Port' CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+  int '  DS1302 RST bit number' CONFIG_ETRAX_DS1302_RSTBIT 2
+  int '  DS1302 SCL bit number' CONFIG_ETRAX_DS1302_SCLBIT 1
+  int '  DS1302 SDA bit number' CONFIG_ETRAX_DS1302_SDABIT 0
 fi
 
 endmenu
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/Makefile linux/arch/cris/drivers/Makefile
--- v2.4.4/linux/arch/cris/drivers/Makefile	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/Makefile	Tue May  1 16:04:56 2001
@@ -12,10 +12,13 @@
 obj-$(CONFIG_ETRAX_IDE)                += ide.o
 obj-$(CONFIG_ETRAX_AXISFLASHMAP)       += axisflashmap.o
 obj-$(CONFIG_ETRAX_I2C) 	       += i2c.o
+obj-$(CONFIG_ETRAX_I2C_EEPROM)         += eeprom.o
 obj-$(CONFIG_ETRAX_GPIO) 	       += gpio.o
 obj-$(CONFIG_ETRAX_USB_HOST)           += usb-host.o
 obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
-obj-$(CONFIG_JULIETTE)                 += juliette/juliette.o
-subdir-$(CONFIG_JULIETTE)              += juliette
+obj-$(CONFIG_ETRAX_PARPORT)            += parport.o
+obj-$(CONFIG_ETRAX_DS1302)             += ds1302.o
+
+
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/axisflashmap.c linux/arch/cris/drivers/axisflashmap.c
--- v2.4.4/linux/arch/cris/drivers/axisflashmap.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/axisflashmap.c	Tue May  1 16:04:56 2001
@@ -11,6 +11,15 @@
  * partition split defined below.
  *
  * $Log: axisflashmap.c,v $
+ * Revision 1.7  2001/04/05 13:41:46  markusl
+ * Updated according to review remarks
+ *
+ * Revision 1.6  2001/03/07 09:21:21  bjornw
+ * No need to waste .data
+ *
+ * Revision 1.5  2001/03/06 16:27:01  jonashg
+ * Probe the entire flash area for flash devices.
+ *
  * Revision 1.4  2001/02/23 12:47:15  bjornw
  * Uncached flash in LOW_MAP moved from 0xe to 0x8
  *
@@ -50,19 +59,13 @@
 #endif
 
 /*
- * WINDOW_SIZE is the total size where the flash chips are mapped,
- * my guess is that this can be the total memory area even if there
- * are many flash chips inside the area or if they are not all mounted.
- * So possibly we can get rid of the CONFIG_ here and just write something
- * like 32 MB always.
- */
-
-#define WINDOW_SIZE  (CONFIG_ETRAX_FLASH_LENGTH * 1024 * 1024)
-
-/* Byte-offset where the partition-table is placed in the first chip
+ * WINDOW_SIZE is the total size where the flash chips may be mapped.
+ * MTD probes should find all devices there and it does not matter
+ * if there are unmapped gaps or aliases (mirrors of flash devices).
+ * The MTD probes will ignore them.
  */
 
-#define PTABLE_SECTOR 65536
+#define WINDOW_SIZE  (128 * 1024 * 1024)
 
 /* 
  * Map driver
@@ -70,8 +73,6 @@
  * Ok this is the scoop - we need to access the flash both with and without
  * the cache - without when doing all the fancy flash interfacing, and with
  * when we do actual copying because otherwise it will be slow like molasses.
- * I hope this works the way it's intended, so that there won't be any cases
- * of non-synchronicity because of the different access modes below...
  */
 
 static __u8 flash_read8(struct map_info *map, unsigned long ofs)
@@ -110,12 +111,6 @@
 	*(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d;
 }
 
-static void flash_copy_to(struct map_info *map, unsigned long to,
-			  const void *from, ssize_t len)
-{
-	memcpy((void *)(FLASH_CACHED_ADDR + to), from, len);
-}
-
 static struct map_info axis_map = {
 	name: "Axis flash",
 	size: WINDOW_SIZE,
@@ -127,7 +122,6 @@
 	write8: flash_write8,
 	write16: flash_write16,
 	write32: flash_write32,
-	copy_to: flash_copy_to
 };
 
 /* If no partition-table was found, we use this default-set.
@@ -139,18 +133,18 @@
 static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = {
 	{
 		name: "boot firmware",
-		size: PTABLE_SECTOR,
+		size: CONFIG_ETRAX_PTABLE_SECTOR,
 		offset: 0
 	},
 	{
 		name: "kernel",
 		size: 0x1a0000,
-		offset: PTABLE_SECTOR
+		offset: CONFIG_ETRAX_PTABLE_SECTOR
 	},
 	{
 		name: "filesystem",
 		size: 0x50000,
-		offset: (0x1a0000 + PTABLE_SECTOR)
+		offset: (0x1a0000 + CONFIG_ETRAX_PTABLE_SECTOR)
 	}
 };
 
@@ -214,11 +208,11 @@
 	printk(KERN_NOTICE "Axis flash mapping: %x at %x\n",
 	       WINDOW_SIZE, FLASH_CACHED_ADDR);
 
-	mymtd = do_cfi_probe(&axis_map);
+	mymtd = (struct mtd_info *)do_cfi_probe(&axis_map);
 
 #ifdef CONFIG_MTD_AMDSTD
 	if (!mymtd) {
-		mymtd = do_amd_flash_probe(&axis_map);
+		mymtd = (struct mtd_info *)do_amd_flash_probe(&axis_map);
 	}
 #endif
 
@@ -236,18 +230,15 @@
 	 */
 
 	ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
-		PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
+		CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
 	pidx++;  /* first partition is always set to the default */
 
 	if ((ptable_head->magic == PARTITION_TABLE_MAGIC)
-	    && (ptable_head->size
-		< (MAX_PARTITIONS
-		   * sizeof(struct partitiontable_entry) + 4))
-	    && (*(unsigned long*)
-		((void*)ptable_head
-		 + sizeof(*ptable_head)
-		 + ptable_head->size - 4)
-		==  PARTITIONTABLE_END_MARKER)) {
+	    && (ptable_head->size <
+		(MAX_PARTITIONS * sizeof(struct partitiontable_entry) + 4))
+	    && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) +
+				  ptable_head->size - 4)
+		== PARTITIONTABLE_END_MARKER)) {
 		/* Looks like a start, sane length and end of a
 		 * partition table, lets check csum etc.
 		 */
@@ -256,7 +247,7 @@
 			(struct partitiontable_entry *)
 			((unsigned long)ptable_head + sizeof(*ptable_head) +
 			 ptable_head->size);
-		unsigned long offset = PTABLE_SECTOR;
+		unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR;
 		unsigned char *p;
 		unsigned long csum = 0;
 		
@@ -293,16 +284,7 @@
 		       && ptable->offset != 0xffffffff
 		       && ptable < max_addr
 		       && pidx < MAX_PARTITIONS) {
-#if 0
-			/* wait with multi-chip support until we know
-			 * how mtd detects multiple chips
-			 */
-			if ((offset + ptable->offset) >= chips[0].size) {
-				partitions[pidx].start
-					= offset + chips[1].start
-					+ ptable->offset - chips[0].size;
-			}
-#endif
+
 			axis_partitions[pidx].offset = offset + ptable->offset;
 			axis_partitions[pidx].size = ptable->size;
 
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/ds1302.c linux/arch/cris/drivers/ds1302.c
--- v2.4.4/linux/arch/cris/drivers/ds1302.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/ds1302.c	Tue May  1 16:04:56 2001
@@ -0,0 +1,488 @@
+/*!***************************************************************************
+*!
+*! FILE NAME  : ds1302.c
+*!
+*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O
+*!
+*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status
+*!
+*! $Log: ds1302.c,v $
+*! Revision 1.3  2001/03/26 16:03:06  bjornw
+*! Needs linux/config.h
+*!
+*! Revision 1.2  2001/03/20 19:42:00  bjornw
+*! Use the ETRAX prefix on the DS1302 options
+*!
+*! Revision 1.1  2001/03/20 09:13:50  magnusmn
+*! Linux 2.4 port
+*!
+*! Revision 1.10  2000/07/05 15:38:23  bjornw
+*! Dont update kernel time when a RTC_SET_TIME is done
+*!
+*! Revision 1.9  2000/03/02 15:42:59  macce
+*! * Hack to make RTC work on all 2100/2400
+*!
+*! Revision 1.8  2000/02/23 16:59:18  torbjore
+*! added setup of R_GEN_CONFIG when RTC is connected to the generic port.
+*!
+*! Revision 1.7  2000/01/17 15:51:43  johana
+*! Added RTC_SET_CHARGE ioctl to enable trickle charger.
+*!
+*! Revision 1.6  1999/10/27 13:19:47  bjornw
+*! Added update_xtime_from_cmos which reads back the updated RTC into the kernel.
+*! /dev/rtc calls it now.
+*!
+*! Revision 1.5  1999/10/27 12:39:37  bjornw
+*! Disabled superuser check. Anyone can now set the time.
+*!
+*! Revision 1.4  1999/09/02 13:27:46  pkj
+*! Added shadow for R_PORT_PB_CONFIG.
+*! Renamed port_g_shadow to port_g_data_shadow.
+*!
+*! Revision 1.3  1999/09/02 08:28:06  pkj
+*! Made it possible to select either port PB or the generic port for the RST
+*! signal line to the DS1302 RTC.
+*! Also make sure the RST bit is configured as output on Port PB (if used).
+*!
+*! Revision 1.2  1999/09/01 14:47:20  bjornw
+*! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read
+*! and set the date. Register as major 121.
+*!
+*! Revision 1.1  1999/09/01 09:45:29  bjornw
+*! Implemented a DS1302 RTC driver.
+*!
+*!
+*! ---------------------------------------------------------------------------
+*!
+*! (C) Copyright 1999, 2000, 2001  Axis Communications AB, LUND, SWEDEN
+*!
+*! $Id: ds1302.c,v 1.3 2001/03/26 16:03:06 bjornw Exp $
+*!
+*!***************************************************************************/
+
+#include <linux/config.h>
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/svinto.h>
+#include <asm/io.h>
+#include <asm/rtc.h>
+
+#define RTC_MAJOR_NR 121 /* local major, change later */
+
+/* The DS1302 might be connected to different bits on different products. 
+ * It has three signals - SDA, SCL and RST. RST and SCL are always outputs,
+ * but SDA can have a selected direction.
+ * For now, only PORT_PB is hardcoded.
+ */
+
+/* The RST bit may be on either the Generic Port or Port PB */
+#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA,  port_g_data_shadow,  CONFIG_ETRAX_DS1302_RSTBIT, x)
+#define TK_RST_DIR(x)
+#else
+#define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x)
+#define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_RSTBIT, x)
+#endif
+
+
+#define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x)
+#define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x)
+
+#define TK_SDA_IN()   ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1)
+/* 1 is out, 0 is in */
+#define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_SDABIT, x)
+#define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR,  port_pb_dir_shadow,  CONFIG_ETRAX_DS1302_SCLBIT, x)
+
+
+/*
+ * The reason for tempudelay and not udelay is that loops_per_usec
+ * (used in udelay) is not set when functions here are called from time.c 
+ */
+
+static void tempudelay(int time) 
+{
+	int i;
+	for(i = 0; i < time * 10000; i++);	
+}
+
+
+/* send 8 bits */
+static void
+out_byte(int x) 
+{
+	int i;
+	TK_SDA_DIR(1);
+	for (i = 8; i--;) {
+		/* the chip latches incoming bits on the rising edge of SCL */
+		TK_SCL_OUT(0);
+		TK_SDA_OUT(x & 1);
+		tempudelay(1);
+		TK_SCL_OUT(1);
+		tempudelay(1);
+		x >>= 1;
+	}
+	TK_SDA_DIR(0);
+}
+
+static unsigned char
+in_byte(void) 
+{
+	unsigned char x = 0;
+	int i;
+
+	/* Read byte. Bits come LSB first, on the falling edge of SCL.
+	 * Assume SDA is in input direction already
+	 */
+	TK_SDA_DIR(0);
+
+	for (i = 8; i--;) {
+		TK_SCL_OUT(0);
+		tempudelay(1);
+		x >>= 1;
+		x |= (TK_SDA_IN() << 7);
+		TK_SCL_OUT(1);
+		tempudelay(1);
+	}
+
+	return x;
+}
+
+/* prepares for a transaction by de-activating RST (active-low) */
+
+static void
+start(void) 
+{
+	TK_SCL_OUT(0);
+	tempudelay(1);
+	TK_RST_OUT(0);
+	tempudelay(5);
+	TK_RST_OUT(1);	
+}
+
+/* ends a transaction by taking RST active again */
+
+static void
+stop(void) 
+{
+	tempudelay(2);
+	TK_RST_OUT(0);
+}
+
+/* enable writing */
+
+static void
+ds1302_wenable(void) 
+{
+	start(); 	
+	out_byte(0x8e); /* Write control register  */
+	out_byte(0x00); /* Disable write protect bit 7 = 0 */
+	stop();
+}
+
+/* disable writing */
+
+static void
+ds1302_wdisable(void) 
+{
+	start();
+	out_byte(0x8e); /* Write control register  */
+	out_byte(0x80); /* Disable write protect bit 7 = 0 */
+	stop();
+}
+
+/* probe for the chip by writing something to its RAM and try reading it back */
+
+static int
+ds1302_probe(void) 
+{
+	int retval, res; 
+
+	TK_RST_DIR(1);
+	TK_SCL_DIR(1);
+	TK_SDA_DIR(0);
+	
+	/* try to talk to timekeeper */
+
+	ds1302_wenable();  
+	start();
+	out_byte(0xc0); /* write RAM byte 0 */	
+	out_byte(0x42); /* write something magic */
+	start();
+	out_byte(0xc1); /* read RAM byte 0 */
+
+	if((res = in_byte()) == 0x42) {
+		char buf[100];
+		stop();
+		ds1302_wdisable();
+		printk("DS1302 RTC found.\n");
+                printk("SDA, SCL, RST on PB%i, PB%i, %s%i\n",
+                       CONFIG_ETRAX_DS1302_SDABIT,
+                       CONFIG_ETRAX_DS1302_SCLBIT,
+#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+                       "GENIO",
+#else
+                       "PB",
+#endif
+                       CONFIG_ETRAX_DS1302_RSTBIT
+                       );
+                get_rtc_status(buf);
+                printk(buf);
+		retval = 1;
+	} else {
+		stop();
+		printk("DS1302 RTC not found.\n");
+		retval = 0;
+	}
+
+	return retval;
+}
+
+
+/* read a byte from the selected register in the DS1302 */
+
+unsigned char
+ds1302_readreg(int reg) 
+{
+	unsigned char x;
+
+	start();
+	out_byte(0x81 | (reg << 1)); /* Read register */
+	x = in_byte();
+	stop();
+
+	return x;
+}
+
+/* write a byte to the selected register */
+
+void
+ds1302_writereg(int reg, unsigned char val) 
+{
+	ds1302_wenable();
+	start();
+	out_byte(0x80 | (reg << 1)); /* Write register */
+	out_byte(val);
+	stop();
+	ds1302_wdisable();
+}
+
+void
+get_rtc_time(struct rtc_time *rtc_tm) 
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+	rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+	rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+	rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+	rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+	rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+
+	restore_flags(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 <= 69)
+		rtc_tm->tm_year += 100;
+
+	rtc_tm->tm_mon--;
+}
+
+static unsigned char days_in_mo[] = 
+    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
+
+/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date) */
+
+static int
+rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg) 
+{
+        unsigned long flags;
+
+	switch(cmd) {
+		case RTC_RD_TIME:	/* Read the time/date from RTC	*/
+		{
+			struct rtc_time rtc_tm;
+						
+			get_rtc_time(&rtc_tm);						
+			if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
+				return -EFAULT;	
+			return 0;
+		}
+
+		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, save_freq_select;
+			unsigned int yrs;
+#if 0
+			if (!suser())
+				return -EACCES;
+#endif			
+			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) || (yrs > 2069))
+				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 >= 2000)
+				yrs -= 2000;	/* RTC (0, 1, ... 69) */
+			else
+				yrs -= 1900;	/* RTC (70, 71, ... 99) */
+
+			BIN_TO_BCD(sec);
+			BIN_TO_BCD(min);
+			BIN_TO_BCD(hrs);
+			BIN_TO_BCD(day);
+			BIN_TO_BCD(mon);
+			BIN_TO_BCD(yrs);
+
+			save_flags(flags);
+			cli();
+			CMOS_WRITE(yrs, RTC_YEAR);
+			CMOS_WRITE(mon, RTC_MONTH);
+			CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+			CMOS_WRITE(hrs, RTC_HOURS);
+			CMOS_WRITE(min, RTC_MINUTES);
+			CMOS_WRITE(sec, RTC_SECONDS);
+			restore_flags(flags);
+
+			/* notice that at this point, the RTC is updated but the kernel
+			 * is still running with the old time. you need to set that
+			 * separately with settimeofday or adjtimex.
+			 */
+			return 0;
+		}
+
+		case RTC_SET_CHARGE: /* Set the RTC TRICKLE CHARGE register */
+		{
+			int tcs_val;                        
+			unsigned char save_control, save_freq_select;
+#if 0
+			if (!suser())
+				return -EACCES;
+#endif
+			
+			if(copy_from_user(&tcs_val, (int*)arg, sizeof(int)))
+				return -EFAULT;
+
+			tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
+			ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
+			return 0;
+		}                
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+/*
+ *	Info exported via "/proc/rtc".
+ */
+
+int
+get_rtc_status(char *buf) 
+{
+	char *p;
+	struct rtc_time tm;
+
+	p = buf;
+
+	get_rtc_time(&tm);
+
+	/*
+	 * There is no way to tell if the luser has the RTC set for local
+	 * time or for Universal Standard Time (GMT). Probably local though.
+	 */
+
+	p += sprintf(p,
+		"rtc_time\t: %02d:%02d:%02d\n"
+		"rtc_date\t: %04d-%02d-%02d\n",
+		tm.tm_hour, tm.tm_min, tm.tm_sec,
+		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+
+	return  p - buf;
+}
+
+
+/*
+ *	The various file operations we support.
+ */
+
+static struct file_operations rtc_fops = {
+        owner:          THIS_MODULE,
+        ioctl:          rtc_ioctl,	
+}; 
+
+/* just probe for the RTC and register the device to handle the ioctl needed */
+
+int
+ds1302_init(void) 
+{ 
+  
+ /* Ugly hack to handle both 2100 and 2400 hardware.
+    Remove...
+ */
+	if(!ds1302_probe()) {
+#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
+    	/*
+     	* Make sure that R_GEN_CONFIG is 
+     	* setup correct.
+     	*/
+    		genconfig_shadow = ( (genconfig_shadow & ~IO_MASK(R_GEN_CONFIG, ata) ) | 
+                           ( IO_STATE( R_GEN_CONFIG, ata, select ) ) );    
+    		*R_GEN_CONFIG = genconfig_shadow;
+    		if(!ds1302_probe())
+      			return -1;
+#else
+    		return -1;
+#endif
+  	}
+  
+	if (register_chrdev(RTC_MAJOR_NR, "rtc", &rtc_fops)) {
+		printk("unable to get major %d for rtc\n", RTC_MAJOR_NR);
+		return -1;
+	}
+	return 0;
+}
+
+
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/eeprom.c linux/arch/cris/drivers/eeprom.c
--- v2.4.4/linux/arch/cris/drivers/eeprom.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/eeprom.c	Tue May  1 16:04:56 2001
@@ -0,0 +1,1161 @@
+/*!**************************************************************************
+*!
+*!  FILE NAME:      e100eeprom.c
+*!
+*!  DESCRIPTION:    Implements an interface for i2c compatible eeproms to run
+*!                  under linux.
+*!                  Supports 2k, 8k(?) and 16k
+*!                  Uses adaptive timing adjustents by Johan.Adolfsson@axis.com
+*!                  Probing results:
+*!                    8k or not is detected (the assumes 2k or 16k)
+*!                    2k or 16k detected using test reads and writes.
+*!
+*!  FUNCTIONS:
+*!
+*!  (Exported)
+*!              eeprom_init()
+*!
+*!  (Local)
+*!
+*!              eeprom_open()
+*!              eeprom_lseek()
+*!              eeprom_read()
+*!              eeprom_write()
+*!              eeprom_close()
+*!              eeprom_address()
+*!              eeprom_disable_write_protect()
+*!
+*!
+*!  $Id: eeprom.c,v 1.3 2001/03/19 16:04:46 markusl Exp $
+*!
+*!------------------------------------------------------------------------
+*!  HISTORY
+*!
+*!  DATE          NAME              CHANGES
+*!  ----          ----              -------
+*!  Aug  28 1999  Edgar Iglesias    Initial Version
+*!  Aug  31 1999  Edgar Iglesias    Allow simultaneous users.
+*!  Sep  03 1999  Edgar Iglesias    Updated probe.
+*!  Sep  03 1999  Edgar Iglesias    Added bail-out stuff if we get interrupted
+*!                                  in the spin-lock.
+*!
+*!  $Log: eeprom.c,v $
+*!  Revision 1.3  2001/03/19 16:04:46  markusl
+*!  Fixed init of fops struct
+*!
+*!  Revision 1.2  2001/03/19 10:35:07  markusl
+*!  2.4 port of eeprom driver
+*!
+*!  Revision 1.8  2000/05/18 10:42:25  edgar
+*!  Make sure to end write cycle on _every_ write
+*!
+*!  Revision 1.7  2000/01/17 17:41:01  johana
+*!  Adjusted probing and return -ENOSPC when writing outside EEPROM
+*!
+*!  Revision 1.6  2000/01/17 15:50:36  johana
+*!  Added adaptive timing adjustments and fixed autoprobing for 2k and 16k(?)
+*!  EEPROMs
+*!
+*!  Revision 1.5  1999/09/03 15:07:37  edgar
+*!  Added bail-out check to the spinlock
+*!
+*!  Revision 1.4  1999/09/03 12:11:17  bjornw
+*!  Proper atomicity (need to use spinlocks, not if's). users -> busy.
+*!
+*!
+*!        (c) 1999 Axis Communications AB, Lund, Sweden
+*!**************************************************************************/
+
+/********************** INCLUDE FILES SECTION ******************************/
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include "i2c.h"
+
+/********************** CONSTANT AND MACRO SECTION *************************/
+#define D(x) 
+
+/* If we should use adaptive timing or not: */
+//#define EEPROM_ADAPTIVE_TIMING      
+
+#define EEPROM_MAJOR_NR 122  /* use a LOCAL/EXPERIMENTAL major for now */
+#define EEPROM_MINOR_NR 0
+
+#define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */
+/*
+ *  this one defines how many times to try when eeprom fails.
+ */
+#define EEPROM_RETRIES 10
+
+#define EEPROM_2KB (2 * 1024)
+/*#define EEPROM_4KB (4 * 1024)*/ /* Exists but not used in Axis products */
+#define EEPROM_8KB (8 * 1024 - 1 ) /* Last byte has write protection bit */
+#define EEPROM_16KB (16 * 1024)
+
+#define i2c_delay(x) udelay(x)
+
+/********************** TYPE DEFINITION SECTION ****************************/
+
+/*
+ *  This structure describes the attached eeprom chip.
+ *  The values are probed for.
+ */
+
+struct eeprom_type
+{
+  unsigned long size;
+  unsigned long sequential_write_pagesize;
+  unsigned char select_cmd;
+  unsigned long usec_delay_writecycles; /* Min time between write cycles (up to 10ms for some models) */
+  unsigned long int usec_delay_step; /* For adaptive algorithm */
+  int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */
+  
+  /* this one is to keep the read/write operations atomic */
+  wait_queue_head_t wait_q;
+  int busy;
+  int retry_cnt_addr; /* Used to keep track of number of retries for
+                     adaptive timing adjustments */
+  int retry_cnt_read;
+
+  
+  
+};
+
+/********************** LOCAL FUNCTION DECLARATION SECTION *****************/
+
+static int  eeprom_open (struct inode * inode, struct file * file);
+static loff_t  eeprom_lseek(struct file * file, loff_t offset, int orig);
+static ssize_t  eeprom_read (struct file * file, char * buf, size_t count, loff_t *off);
+static ssize_t  eeprom_write(struct file * file, const char * buf, size_t count, loff_t *off);
+static int eeprom_close(struct inode * inode, struct file * file);
+
+static int  eeprom_address(unsigned long addr);
+static int  read_from_eeprom(char * buf, int count);
+static int eeprom_write_buf(unsigned long int addr,
+                            const char * buf, int count);
+static int eeprom_read_buf(unsigned long addr,
+                           char * buf, int count);
+
+static void eeprom_disable_write_protect(void);
+
+
+/********************** GLOBAL VARIABLE DECLARATION SECTION ****************/
+
+/********************** LOCAL VARIABLE DECLARATION SECTION *****************/
+
+/* chip description */
+static struct eeprom_type eeprom;
+
+/*
+ *  This is the exported file-operations structure
+ *  for this device.
+ */
+
+struct file_operations eeprom_fops =
+{
+  llseek:  eeprom_lseek,
+  read:    eeprom_read,
+  write:   eeprom_write,
+  open:    eeprom_open,
+  release: eeprom_close
+};
+
+/********************** FUNCTION DEFINITION SECTION ************************/
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_init
+*#                                                            
+*# PARAMETERS   : none
+*#                                                            
+*# RETURNS      : 0 if OK
+*#                                                            
+*# SIDE EFFECTS : 
+*#                                                            
+*# DESCRIPTION  : eeprom init call. Probes for different eeprom models.
+*#                                                            
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#                                                            
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Aug 28 1999  Edgar Iglesias  Initial version               
+*# Sep 03 1999  Edgar Iglesias  Updated probing. Added forced values.
+*#
+*#**************************************************************************/
+
+int __init eeprom_init(void)
+{
+  init_waitqueue_head(&eeprom.wait_q);
+  eeprom.busy = 0;
+
+#if CONFIG_ETRAX_I2C_EEPROM_PROBE
+#define EETEXT "Found"
+#else
+#define EETEXT "Assuming"
+#endif
+  if (register_chrdev(EEPROM_MAJOR_NR, "mem", &eeprom_fops))
+  {
+    printk("unable to get major %d for eeprom device\n", EEPROM_MAJOR_NR);
+    return -1;
+  }
+  
+  printk("EEPROM char device v0.3, (c) 2000 Axis Communications AB\n");
+
+  /*
+   *  Note: Most of this probing method was taken from the printserver (5470e)
+   *        codebase. It did not contain a way of finding the 16Kb chips
+   *        (M24128 or variants). The method used here might not work
+   *        for all models. If you encounter problems the easiest way
+   *        is probably to define your model within #ifdef's, and hard-
+   *        code it.
+   *
+   */
+
+  eeprom.size = 0;
+  eeprom.usec_delay_writecycles = 4000;/*MAX_WRITEDELAY_US / EEPROM_RETRIES;*/
+  eeprom.usec_delay_step = 128;
+  eeprom.adapt_state = 0;
+  
+#if CONFIG_ETRAX_I2C_EEPROM_PROBE
+  i2c_start();
+  i2c_outbyte(0x80);
+  if(!i2c_getack())
+  {
+    /* It's not 8k.. */
+    int success = 0;
+    unsigned char buf_2k_start[16];
+    
+    /* Im not sure this will work... :) */
+    /* assume 2Kb, if failure go for 16Kb */
+    /* Test with 16kB settings.. */
+    /* If it's a 2kB EEPROM and we address it outside it's range
+     * it will mirror the address space:
+     * 1. We read two locations (that are mirrored), 
+     *    if the content differs * it's a 16kB EEPROM.
+     * 2. if it doesn't differ - write diferent value to one of the locations,
+     *    check the other - if content still is the same it's a 2k EEPROM,
+     *    restore original data.
+     *    
+     */
+#define LOC1 8
+#define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */
+
+   /* 2k settings */  
+    i2c_stop();
+    eeprom.size = EEPROM_2KB;
+    eeprom.select_cmd = 0xA0;   
+    eeprom.sequential_write_pagesize = 16;
+    if( eeprom_read_buf( 0, buf_2k_start, 16 ) == 16 )
+    {
+      D(printk("2k start: '%16.16s'\n", buf_2k_start));
+    }
+    else
+    {
+      printk("Failed to read in 2k mode!\n");  
+    }
+    
+    /* 16k settings */
+    eeprom.size = EEPROM_16KB;
+    eeprom.select_cmd = 0xA0;   
+    eeprom.sequential_write_pagesize = 64;
+
+    {
+      unsigned char loc1[4], loc2[4], tmp[4];
+      if( eeprom_read_buf(LOC2, loc2, 4) == 4)
+      {
+        if( eeprom_read_buf(LOC1, loc1, 4) == 4)
+        {
+          D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", 
+                   LOC1, loc1, LOC2, loc2));
+#if 0
+          if (memcmp(loc1, loc2, 4) != 0 )
+          {
+            /* It's 16k */
+            printk("16k detected in step 1\n");
+            eeprom.size = EEPROM_16KB;     
+            success = 1;
+          }
+          else
+#endif
+          {
+            /* Do step 2 check */
+            /* Invert value */
+            loc1[0] = ~loc1[0];
+            if (eeprom_write_buf(LOC1, loc1, 1) == 1)
+            {
+              /* If 2k EEPROM this write will actually write 10 bytes
+               * from pos 0
+               */
+              D(printk("1 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", 
+                       LOC1, loc1, LOC2, loc2));
+              if( eeprom_read_buf(LOC1, tmp, 4) == 4)
+              {
+                D(printk("2 loc1: (%i) '%4.4s' tmp '%4.4s'\n", 
+                         LOC1, loc1, tmp));
+                if (memcmp(loc1, tmp, 4) != 0 )
+                {
+                  printk("read and write differs! Not 16kB\n");
+                  loc1[0] = ~loc1[0];
+                  
+                  if (eeprom_write_buf(LOC1, loc1, 1) == 1)
+                  {
+                    success = 1;
+                  }
+                  else
+                  {
+                    printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n");
+                    
+                  }
+                  i2c_stop();
+                  /* Go to 2k mode and write original data */
+                  eeprom.size = EEPROM_2KB;
+                  eeprom.select_cmd = 0xA0;   
+                  eeprom.sequential_write_pagesize = 16;
+                  if( eeprom_write_buf(0, buf_2k_start, 16) == 16)
+                  {
+                  }
+                  else
+                  {
+                    printk("Failed to write back 2k start!\n");
+                  }
+                  
+                  eeprom.size = EEPROM_2KB;
+                }
+              }
+                
+              if(!success)
+              {
+                if( eeprom_read_buf(LOC2, loc2, 1) == 1)
+                {
+                  D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", 
+                           LOC1, loc1, LOC2, loc2));
+                  if (memcmp(loc1, loc2, 4) == 0 )
+                  {
+                    /* Data the same, must be mirrored -> 2k */
+                    /* Restore data */
+                    printk("2k detected in step 2\n");
+                    loc1[0] = ~loc1[0];
+                    if (eeprom_write_buf(LOC1, loc1, 1) == 1)
+                    {
+                      success = 1;
+                    }
+                    else
+                    {
+                      printk("eeprom: Restore 2k failed during probe EEPROM might be corrupt!\n");
+                      
+                    }
+                    
+                    eeprom.size = EEPROM_2KB;     
+                  }
+                  else
+                  {
+                    printk("16k detected in step 2\n");
+                    loc1[0] = ~loc1[0];
+                    /* Data differs, assume 16k */
+                    /* Restore data */
+                    if (eeprom_write_buf(LOC1, loc1, 1) == 1)
+                    {
+                      success = 1;
+                    }
+                    else
+                    {
+                      printk("eeprom: Restore 16k failed during probe EEPROM might be corrupt!\n");
+                    }
+                    
+                    eeprom.size = EEPROM_16KB;
+                  }
+                }
+              }
+            }
+          } /* read LOC1 */
+        } /* address LOC1 */
+        if (!success)
+        {
+          printk("eeprom: Probing failed!, using 2KB!\n");
+          eeprom.size = EEPROM_2KB;               
+        }
+      } /* read */
+    }
+  }
+  else
+  {
+    i2c_outbyte(0x00);
+    if(!i2c_getack())
+    {
+      /* No 8k */
+      eeprom.size = EEPROM_2KB;
+    }
+    else
+    {
+      i2c_start();
+      i2c_outbyte(0x81);
+      if (!i2c_getack())
+      {
+        eeprom.size = EEPROM_2KB;
+      }
+      else
+      {
+        /* It's a 8kB */
+        i2c_inbyte();
+        eeprom.size = EEPROM_8KB;
+      }
+    }
+  }
+  i2c_stop();
+#elif defined(CONFIG_ETRAX_I2C_EEPROM_16KB)
+  eeprom.size = EEPROM_16KB;
+#elif defined(CONFIG_ETRAX_I2C_EEPROM_8KB)
+  eeprom.size = EEPROM_8KB;
+#elif defined(CONFIG_ETRAX_I2C_EEPROM_2KB)
+  eeprom.size = EEPROM_2KB;
+#endif
+
+  switch(eeprom.size)
+  {
+   case (EEPROM_2KB):
+     printk("e100eeprom: " EETEXT " i2c compatible 2Kb eeprom.\n");
+     eeprom.sequential_write_pagesize = 16;
+     eeprom.select_cmd = 0xA0;
+     break;
+   case (EEPROM_8KB):
+     printk("e100eeprom: " EETEXT " i2c compatible 8Kb eeprom.\n");
+     eeprom.sequential_write_pagesize = 16;
+     eeprom.select_cmd = 0x80;
+     break;
+   case (EEPROM_16KB):
+     printk("e100eeprom: " EETEXT " i2c compatible 16Kb eeprom.\n");
+     eeprom.sequential_write_pagesize = 64;
+     eeprom.select_cmd = 0xA0;     
+     break;
+   default:
+     eeprom.size = 0;
+     printk("e100eeprom: Did not find a supported eeprom\n");
+     break;
+  }
+
+  
+
+  eeprom_disable_write_protect();
+
+  return 0;
+}
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_open
+*#                                                            
+*# PARAMETERS   : inode    : Pointer to the inode
+*#                file     : Pointer to the file
+*#                                                            
+*# RETURNS      : 0 if OK
+*#                                                            
+*# SIDE EFFECTS : 
+*#                                                            
+*# DESCRIPTION  : Opens the device.
+*#                                                            
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#                                                            
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Aug 28 1999  Edgar Iglesias  Initial version               
+*# Sep 03 1999  Edgar Iglesias  Removed users check.
+*#
+*#**************************************************************************/
+
+static int eeprom_open(struct inode * inode, struct file * file)
+{
+
+  if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR)
+     return -ENXIO;
+  if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR)
+     return -ENXIO;
+
+  if( eeprom.size > 0 )
+  {
+    /* OK */
+    return 0;
+  }
+
+  /* No EEprom found */
+  return -EFAULT;
+}
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_lseek
+*#                                                            
+*# PARAMETERS   : file     : Pointer to the file
+*#                offset   : The offset (in bytes)
+*#                orig     : look at the note
+*#                                                            
+*# RETURNS      : 0 if OK
+*#                                                            
+*# SIDE EFFECTS : 
+*#                                                            
+*# DESCRIPTION  : Changes the current file position.
+*#                                                            
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#                                                            
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Aug 28 1999  Edgar Iglesias  Initial version
+*# Sep 03 1999  Edgar Iglesias  Return -EOVERFLOW when beyond eeprom size.
+*#
+*#**************************************************************************/
+
+static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig)
+{
+/*
+ *  orig 0: position from begning of eeprom
+ *  orig 1: relative from current position
+ *  orig 2: position from last eeprom address
+ */
+  
+  switch (orig)
+  {
+   case 0:
+     file->f_pos = offset;
+     break;
+   case 1:
+     file->f_pos += offset;
+     break;
+   case 2:
+     file->f_pos = eeprom.size - offset;
+     break;
+   default:
+     return -EINVAL;
+  }
+
+  /* truncate position */
+  if (file->f_pos < 0)
+  {
+    file->f_pos = 0;    
+    return(-EOVERFLOW);
+  }
+  
+  if (file->f_pos >= eeprom.size)
+  {
+    file->f_pos = eeprom.size - 1;
+    return(-EOVERFLOW);
+  }
+
+  return ( file->f_pos );
+}
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_read
+*#                                                            
+*# PARAMETERS   : inode    : Pointer to the inode
+*#                file     : Pointer to the file
+*#                buf      : Destination buffer
+*#                count    : max nr bytes to read
+*#                                                            
+*# RETURNS      : number of read bytes.
+*#                                                            
+*# SIDE EFFECTS : updates file->f_pos
+*#                                                            
+*# DESCRIPTION  : Reads data from eeprom.
+*#                                                            
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#                                                            
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Jan 17 2000  Johan Adolfsson Initial version
+*#
+*#**************************************************************************/
+static int eeprom_read_buf(unsigned long addr,
+                           char * buf, int count)
+{
+  struct file f;
+
+  f.f_pos = addr;
+  return eeprom_read(&f, buf, count, &addr);
+}
+
+
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_read
+*#                                                            
+*# PARAMETERS   : file     : Pointer to the file
+*#                buf      : Destination buffer
+*#                count    : max nr bytes to read
+*#                                                            
+*# RETURNS      : number of read bytes.
+*#                                                            
+*# SIDE EFFECTS : updates file->f_pos
+*#                                                            
+*# DESCRIPTION  : Reads data from eeprom.
+*#                                                            
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#                                                            
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Aug 28 1999  Edgar Iglesias  Initial version               
+*# Aug 31 1999  Edgar Iglesias  Made operation atomic with wait queues
+*# Sep 03 1999  Edgar Iglesias  Added bail-out stuff if we get interrupted
+*#                              in the spin-lock.
+*#
+*#**************************************************************************/
+
+static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off)
+{
+  int i, read=0;
+  unsigned long p = file->f_pos;
+
+  unsigned char page;
+
+  if(p >= eeprom.size)  /* Address i 0 - (size-1) */
+  {
+    return -EFAULT;
+  }
+  
+  while(eeprom.busy)
+  {
+    interruptible_sleep_on(&eeprom.wait_q);
+
+    /* bail out if we get interrupted */
+    if (signal_pending(current))
+      return -EINTR;
+    
+  }
+  eeprom.busy++;
+
+  page = (unsigned char) (p >> 8);
+  
+  if(!eeprom_address(p))
+  {
+    printk("eeprom: Read failed to address the eeprom: "
+           "0x%08X (%i) page: %i\n", p, p, page);
+    i2c_stop();
+    
+    /* don't forget to wake them up */
+    eeprom.busy--;
+    wake_up_interruptible(&eeprom.wait_q);  
+    return -EFAULT;
+  }
+
+  if( (p + count) > eeprom.size)
+  {
+    /* truncate count */
+    count = eeprom.size - p;
+  }
+
+  /* stop dummy write op and initiate the read op */
+  i2c_start();
+
+  /* special case for small eeproms */
+  if(eeprom.size < EEPROM_16KB)
+  {
+    i2c_outbyte( eeprom.select_cmd | 1 | (page << 1) );
+  }
+
+  /* go on with the actual read */
+  read = read_from_eeprom( buf, count);
+  
+  if(read > 0)
+  {
+    file->f_pos += read;
+  }
+
+  eeprom.busy--;
+  wake_up_interruptible(&eeprom.wait_q);
+  return read;
+}
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_write_buf
+*#                                                            
+*# PARAMETERS   : addr     : Address to write to
+*#                buf      : Data buffer to write from
+*#                count    : number bytes to write
+*#                                                            
+*# RETURNS      : number of bytes actualy written.
+*#                                                            
+*# SIDE EFFECTS : None
+*#             
+*# DESCRIPTION  : Writes data to eeprom.
+*#                                                            
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#                                                            
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Jan 17 2000  Johan Adolfsson Initial vesion
+*#
+*#**************************************************************************/
+static int eeprom_write_buf(unsigned long int addr,
+                            const char * buf, int count)
+{
+  struct file f;
+
+  f.f_pos = addr;
+  
+  return eeprom_write(&f, buf, count, &addr);
+}
+
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_write
+*#                                                            
+*# PARAMETERS   : file     : Pointer to the file
+*#                buf      : Data buffer to write from
+*#                count    : number bytes to write
+*#                                                            
+*# RETURNS      : number of bytes actualy written.
+*#                                                            
+*# SIDE EFFECTS : updates file->f_pos
+*#             
+*# DESCRIPTION  : Writes data to eeprom.
+*#                                                            
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#                                                            
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Aug 28 1999  Edgar Iglesias  Initial version               
+*# Aug 31 1999  Edgar Iglesias  Made operation atomic with wait queues
+*# Sep 03 1999  Edgar Iglesias  Moved the actual reading to read_from_eeprom
+*# Sep 03 1999  Edgar Iglesias  Added bail-out stuff if we get interrupted
+*#                              in the spin-lock.
+*# May 18 2000  Edgar Iglesias  Make sure to end write cycle after every write.
+*#
+*#**************************************************************************/
+
+static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
+                            loff_t *off)
+{
+  int i, written, restart=1;
+  unsigned long p;
+
+  while(eeprom.busy)
+  {
+    interruptible_sleep_on(&eeprom.wait_q);
+    /* bail out if we get interrupted */
+    if (signal_pending(current))
+      return -EINTR;
+  }
+  eeprom.busy++;
+  for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++)
+  {
+    restart = 0;
+    written = 0;
+    p = file->f_pos;
+   
+    
+    while( (written < count) && (p < eeprom.size))
+    {
+      /* address the eeprom */
+      if(!eeprom_address(p))
+      {
+        printk("eeprom: Write failed to address the eeprom: 0x%08X (%i) \n", 
+               p, p);
+        i2c_stop();
+        
+        /* don't forget to wake them up */
+        eeprom.busy--;
+        wake_up_interruptible(&eeprom.wait_q);
+        return -EFAULT;
+      }
+#ifdef EEPROM_ADAPTIVE_TIMING      
+      /* Adaptive algorithm to adjust timing */
+      if (eeprom.retry_cnt_addr > 0)
+      {
+        /* To Low now */
+        D(printk(">D=%i d=%i\n",
+               eeprom.usec_delay_writecycles, eeprom.usec_delay_step));
+
+        if (eeprom.usec_delay_step < 4)
+        {
+          eeprom.usec_delay_step++;
+          eeprom.usec_delay_writecycles += eeprom.usec_delay_step;
+        }
+        else
+        {
+
+          if (eeprom.adapt_state > 0)
+          {
+            /* To Low before */
+            eeprom.usec_delay_step *= 2;
+            if (eeprom.usec_delay_step > 2)
+            {
+              eeprom.usec_delay_step--;
+            }
+            eeprom.usec_delay_writecycles += eeprom.usec_delay_step;
+          }
+          else if (eeprom.adapt_state < 0)
+          {
+            /* To High before (toggle dir) */
+            eeprom.usec_delay_writecycles += eeprom.usec_delay_step;
+            if (eeprom.usec_delay_step > 1)
+            {
+              eeprom.usec_delay_step /= 2;
+              eeprom.usec_delay_step--;
+            }
+          }
+        }
+
+        eeprom.adapt_state = 1;
+      }
+      else
+      {
+        /* To High (or good) now */
+        D(printk("<D=%i d=%i\n",
+               eeprom.usec_delay_writecycles, eeprom.usec_delay_step));
+        
+        if (eeprom.adapt_state < 0)
+        {
+          /* To High before */
+          if (eeprom.usec_delay_step > 1)
+          {
+            if (eeprom.usec_delay_step > 0)
+            {
+              eeprom.usec_delay_step *= 2;
+              eeprom.usec_delay_step--;
+            }
+            
+            if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step)
+            {
+              eeprom.usec_delay_writecycles -= eeprom.usec_delay_step;
+            }
+          }
+        }
+        else if (eeprom.adapt_state > 0)
+        {
+          /* To Low before (toggle dir) */
+          if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step)
+          {
+            eeprom.usec_delay_writecycles -= eeprom.usec_delay_step;
+          }
+          if (eeprom.usec_delay_step > 1)
+          {
+            eeprom.usec_delay_step /= 2;
+            eeprom.usec_delay_step--;
+          }
+          
+          eeprom.adapt_state = -1;
+        }
+
+        if (eeprom.adapt_state > -100)
+        {
+          eeprom.adapt_state--;
+        }
+        else
+        {
+          /* Restart adaption */
+          D(printk("#Restart\n"));
+          eeprom.usec_delay_step++;
+        }
+      }
+#endif /* EEPROM_ADAPTIVE_TIMING */
+      /* write until we hit a page boundary or count */
+      do
+      {
+        i2c_outbyte(buf[written]);        
+        if(!i2c_getack())
+        {
+          restart=1;
+          printk("eeprom: write error, retrying. %d\n", i);
+          i2c_stop();
+          break;
+        }
+        written++;
+        p++;        
+      } while( written < count && ( p % eeprom.sequential_write_pagesize ));
+
+      /* end write cycle */
+      i2c_stop();
+      i2c_delay(eeprom.usec_delay_writecycles);
+    } /* while */
+  } /* for  */
+
+  eeprom.busy--;
+  wake_up_interruptible(&eeprom.wait_q);
+  if (written == 0 && file->f_pos >= eeprom.size){
+    return -ENOSPC;
+  }
+  file->f_pos += written;
+  return written;
+}
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_close
+*#                                                            
+*# PARAMETERS   : inode    : Pointer to the inode
+*#                file     : Pointer to the file
+*#
+*# RETURNS      : nothing
+*#
+*# SIDE EFFECTS :
+*#
+*# DESCRIPTION  : Closes the device.
+*#
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Aug 28 1999  Edgar Iglesias  Initial version               
+*# Sep 03 1999  Edgar Iglesias  Removed eeprom.users stuff.
+*#
+*#**************************************************************************/
+
+static int eeprom_close(struct inode * inode, struct file * file)
+{
+  /* do nothing for now */
+  return 0;
+}
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_address
+*#                                                            
+*# PARAMETERS   : addr     : Address to be given to eeprom
+*#
+*# RETURNS      : 1 if OK, 0 if failure.
+*#
+*# SIDE EFFECTS :
+*#
+*# DESCRIPTION  : Sets the current address of the eeprom.
+*#
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Aug 28 1999  Edgar Iglesias  Initial version               
+*# Sep 03 1999  Edgar Iglesias  Corrected typo.
+*#
+*#**************************************************************************/
+
+static int eeprom_address(unsigned long addr)
+{
+  int i, j;
+  unsigned char page, offset;
+
+  page   = (unsigned char) (addr >> 8);
+  offset = (unsigned char)  addr;
+
+  for(i = 0; i < EEPROM_RETRIES; i++)
+  {
+    /* start a dummy write for addressing */
+    i2c_start();
+
+    if(eeprom.size == EEPROM_16KB)
+    {
+      i2c_outbyte( eeprom.select_cmd ); 
+      i2c_getack();
+      i2c_outbyte(page); 
+    }
+    else
+    {
+      i2c_outbyte( eeprom.select_cmd | (page << 1) ); 
+    }
+    if(!i2c_getack())
+    {
+      /* retry */
+      i2c_stop();
+      /* Must have a delay here.. 500 works, >50, 100->works 5th time*/
+      i2c_delay(MAX_WRITEDELAY_US / EEPROM_RETRIES * i);
+      /* The chip needs up to 10 ms from write stop to next start */
+     
+    }
+    else
+    {
+      i2c_outbyte(offset);
+      
+      if(!i2c_getack())
+      {
+        /* retry */
+        i2c_stop();
+      }
+      else
+        break;
+    }
+  }    
+
+  
+  eeprom.retry_cnt_addr = i;
+  D(printk("%i\n", eeprom.retry_cnt_addr));
+  if(eeprom.retry_cnt_addr == EEPROM_RETRIES)
+  {
+    /* failed */
+    return 0;
+  }
+  return 1;
+}
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: read_from_eeprom
+*#                                                            
+*# PARAMETERS   : buf      : Destination buffer.
+*#                count    : Number of bytes to read.
+*#
+*# RETURNS      : number of read bytes or -EFAULT.
+*#
+*# SIDE EFFECTS :
+*#
+*# DESCRIPTION  : Reads from current adress.
+*#
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Sep 03 1999  Edgar Iglesias  Initial version               
+*#
+*#**************************************************************************/
+
+static int read_from_eeprom(char * buf, int count)
+{
+  int i, read=0;
+
+  for(i = 0; i < EEPROM_RETRIES; i++)
+  {    
+    if(eeprom.size == EEPROM_16KB)
+    {
+      i2c_outbyte( eeprom.select_cmd | 1 );
+    }
+
+    if(i2c_getack());
+    {
+      break;
+    }
+  }
+  
+  if(i == EEPROM_RETRIES)
+  {
+    printk("eeprom: failed to read from eeprom\n");
+    i2c_stop();
+    
+    return -EFAULT;
+  }
+
+  while( (read < count))
+  {    
+    buf[read++] = i2c_inbyte();      
+
+    /*
+     *  make sure we don't ack last byte or you will get very strange
+     *  results!
+     */
+    if(read < count)
+    {
+      i2c_sendack();
+    }
+  }
+
+  /* stop the operation */
+  i2c_stop();
+
+  return read;
+}
+
+/*#**************************************************************************
+*#                                                            
+*# FUNCTION NAME: eeprom_disable_write_protect
+*#                                                            
+*# PARAMETERS   : None
+*#
+*# RETURNS      : Nothing
+*#
+*# SIDE EFFECTS :
+*#
+*# DESCRIPTION  : Disables write protection if applicable
+*#
+*#---------------------------------------------------------------------------
+*# HISTORY                                                    
+*#
+*# DATE         NAME            CHANGES                       
+*# ----         ----            -------                       
+*# Jan 14 2000  Johan Adolfsson Initial version (from PS pareerom.c)
+*#
+*#**************************************************************************/
+#define DBP_SAVE(x)
+#define ax_printf printk
+static void eeprom_disable_write_protect(void)
+{
+  /* Disable write protect */
+  if (eeprom.size == EEPROM_8KB)
+  {
+    /* Step 1 Set WEL = 1 (write 00000010 to address 1FFFh */
+    i2c_start();
+    i2c_outbyte(0xbe);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false\n"));
+    }
+    i2c_outbyte(0xFF);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 2\n"));
+    }
+    i2c_outbyte(0x02);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 3\n"));
+    }
+    i2c_stop();
+
+    i2c_delay(1000);
+
+    /* Step 2 Set RWEL = 1 (write 00000110 to address 1FFFh */
+    i2c_start();
+    i2c_outbyte(0xbe);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 55\n"));
+    }
+    i2c_outbyte(0xFF);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 52\n"));
+    }
+    i2c_outbyte(0x06);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 53\n"));
+    }
+    i2c_stop();
+    
+    /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh*/
+    i2c_start();
+    i2c_outbyte(0xbe);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 56\n"));
+    }
+    i2c_outbyte(0xFF);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 57\n"));
+    }
+    i2c_outbyte(0x06);
+    if(!i2c_getack())
+    {
+      DBP_SAVE(ax_printf("Get ack returns false 58\n"));
+    }
+    i2c_stop();
+    
+    /* Write protect disabled */
+  }
+}
+
+module_init(eeprom_init);
+
+/********************** END OF FILE e100eeprom.c *****************************/
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/ethernet.c linux/arch/cris/drivers/ethernet.c
--- v2.4.4/linux/arch/cris/drivers/ethernet.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/ethernet.c	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-/* $Id: ethernet.c,v 1.8 2001/02/27 13:52:48 bjornw Exp $
+/* $Id: ethernet.c,v 1.12 2001/04/05 11:43:11 tobiasa Exp $
  *
  * e100net.c: A network driver for the ETRAX 100LX network controller.
  *
@@ -7,6 +7,21 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: ethernet.c,v $
+ * Revision 1.12  2001/04/05 11:43:11  tobiasa
+ * Check dev before panic.
+ *
+ * Revision 1.11  2001/04/04 11:21:05  markusl
+ * Updated according to review remarks
+ *
+ * Revision 1.10  2001/03/26 16:03:06  bjornw
+ * Needs linux/config.h
+ *
+ * Revision 1.9  2001/03/19 14:47:48  pkj
+ * * Make sure there is always a pause after the network LEDs are
+ *   changed so they will not look constantly lit during heavy traffic.
+ * * Always use HZ when setting times relative to jiffies.
+ * * Use LED_NETWORK_SET() when setting the network LEDs.
+ *
  * Revision 1.8  2001/02/27 13:52:48  bjornw
  * malloc.h -> slab.h
  *
@@ -40,10 +55,13 @@
  *
  */
 
+#include <linux/config.h>
+
 #include <linux/module.h>
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
@@ -52,11 +70,7 @@
 #include <linux/in.h>
 #include <linux/slab.h>
 #include <linux/string.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
 #include <linux/spinlock.h>
-#include <asm/io.h>
-#include <asm/dma.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 
@@ -65,11 +79,17 @@
 #include <linux/skbuff.h>
 
 #include <asm/svinto.h>     /* DMA and register descriptions */
+#include <asm/io.h>         /* LED_* I/O functions */
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
 
 //#define ETHDEBUG
-
 #define D(x)
 
+#define ETH_TX_DMA 0
+#define ETH_RX_DMA 1
+
 /*
  * The name of the card. Is used for messages and in the requests for
  * io regions, irqs and dma channels
@@ -126,12 +146,12 @@
 #define MDIO_PHYS_ADDR                      0x0
 
 /* Network flash constants */
-#define NET_FLASH_TIME                        2 /* 20 ms */
-#define NET_LINK_UP_CHECK_INTERVAL          200 /* 2 s   */
+#define NET_FLASH_TIME                  (HZ/50) /* 20 ms */
+#define NET_FLASH_PAUSE                (HZ/100) /* 10 ms */
+#define NET_LINK_UP_CHECK_INTERVAL       (2*HZ) /* 2 s   */
 
-/* RX_DESC_BUF_SIZE should be a multiple of four to avoid the buffer
- * alignment bug in Etrax 100 release 1
- */
+#define NO_NETWORK_ACTIVITY 0
+#define NETWORK_ACTIVITY    1
 
 #define RX_DESC_BUF_SIZE   256
 #define NBR_OF_RX_DESC     (RX_BUF_SIZE / \
@@ -146,8 +166,8 @@
 
 static unsigned char RxBuf[RX_BUF_SIZE];
 
-static etrax_dma_descr RxDescList[NBR_OF_RX_DESC];
-static etrax_dma_descr TxDesc;
+static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4)));
+static etrax_dma_descr TxDesc __attribute__ ((aligned(4)));
 
 static struct sk_buff *tx_skb;
 
@@ -155,8 +175,8 @@
 static struct timer_list speed_timer;
 static struct timer_list clear_led_timer;
 static int current_speed;
-static int led_clear_time;
-static int nolink;
+static int led_next_time;
+static int led_active;
 
 /* Index to functions, as function prototypes. */
 
@@ -184,6 +204,7 @@
 static void e100_reset_tranceiver(void);
 
 static void e100_clear_network_leds(unsigned long dummy);
+static void e100_set_network_leds(int active);
 
 #define tx_done(dev) (*R_DMA_CH0_CMD == 0)
 
@@ -201,7 +222,7 @@
 	int i;
 	int anOffset = 0;
 
-	printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000 Axis Communications AB\n");
+	printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2001 Axis Communications AB\n");
 
 	dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */
 
@@ -212,6 +233,8 @@
 	if (!dev) {
 		printk("dev == NULL. Should this happen?\n");
 		dev = init_etherdev(dev, sizeof(struct net_local));
+		if (!dev)
+			panic("init_etherdev failed\n");
 	}
 
 	/* setup generic handlers and stuff in the dev struct */
@@ -272,13 +295,12 @@
 
 	/* Initialize speed indicator stuff. */
 
-	nolink = 0;
 	current_speed = 10;
 	speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
 	speed_timer.function = e100_check_speed;
 	add_timer(&speed_timer);
 	clear_led_timer.function = e100_clear_network_leds;
-	clear_led_timer.expires = jiffies + 10;
+	clear_led_timer.expires = jiffies + HZ/10;
 	add_timer(&clear_led_timer);
 
 	return 0;
@@ -345,8 +367,17 @@
 
 	*R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable);
 
-	*R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */
-	*R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */
+	*R_IRQ_MASK0_CLR =
+		IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) |
+		IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) |
+		IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr);
+	
+	/* clear dma0 and 1 eop and descr irq masks */
+	*R_IRQ_MASK2_CLR =
+		IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
 
 	/* Reset and wait for the DMA channels */
 
@@ -383,17 +414,17 @@
 	 * and clean up on failure.
 	 */
 
-	if(request_dma(0, cardname)) {
+	if(request_dma(ETH_TX_DMA, cardname)) {
 		goto grace_exit;
 	}
 
-	if(request_dma(1, cardname)) {
+	if(request_dma(ETH_RX_DMA, cardname)) {
 	grace_exit:
 		/* this will cause some 'trying to free free irq' but what the heck... */
-		free_dma(0);
-		free_irq(NETWORK_DMARX_IRQ, NULL);
-		free_irq(NETWORK_DMATX_IRQ, NULL);
-		free_irq(NETWORK_STATUS_IRQ, NULL);
+		free_dma(ETH_TX_DMA);
+		free_irq(NETWORK_DMARX_IRQ, (void *)dev);
+		free_irq(NETWORK_DMATX_IRQ, (void *)dev);
+		free_irq(NETWORK_STATUS_IRQ, (void *)dev);
 		return -EAGAIN;
 	}
 
@@ -466,21 +497,19 @@
 e100_check_speed(unsigned long dummy)
 {
 	unsigned long data;
+	int old_speed = current_speed;
+
 	data = e100_get_mdio_reg(MDIO_BASE_STATUS_REG);
 	if (!(data & MDIO_LINK_UP_MASK)) {
-		nolink = 1;
-		LED_NETWORK_TX_SET(1); /* Make it red, link is down. */
+		current_speed = 0;
 	} else {
-		nolink = 0;
-		LED_NETWORK_TX_SET(0); /* Link is up again, clear red LED. */
 		data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG);
-		if (data & MDIO_SPEED) {
-			current_speed = 100;
-		} else {
-			current_speed = 10;
-		}
+		current_speed = (data & MDIO_SPEED ? 100 : 10);
 	}
 	
+	if (old_speed != current_speed)
+		e100_set_network_leds(NO_NETWORK_ACTIVITY);
+
 	/* Reinitialize the timer. */
 	speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
 	add_timer(&speed_timer);
@@ -534,23 +563,26 @@
 static void
 e100_send_mdio_bit(unsigned char bit)
 {
-	volatile int i;
-	*R_NETWORK_MGM_CTRL = 2 | bit&1;
-	for (i=40; i; i--);
-	*R_NETWORK_MGM_CTRL = 6 | bit&1;
-	for (i=40; i; i--);
+	*R_NETWORK_MGM_CTRL =
+		IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |
+		IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);
+	udelay(1);
+	*R_NETWORK_MGM_CTRL =
+		IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable) |
+		IO_MASK(R_NETWORK_MGM_CTRL, mdck) |
+		IO_FIELD(R_NETWORK_MGM_CTRL, mdio, bit);
+	udelay(1);
 }
 
 static unsigned char
 e100_receive_mdio_bit()
 {
 	unsigned char bit;
-	volatile int i;
 	*R_NETWORK_MGM_CTRL = 0;
-	bit = *R_NETWORK_STAT & 1;
-	for (i=40; i; i--);
-	*R_NETWORK_MGM_CTRL = 4;
-	for (i=40; i; i--);
+	bit = IO_EXTRACT(R_NETWORK_STAT, mdio, *R_NETWORK_STAT);
+	udelay(1);
+	*R_NETWORK_MGM_CTRL = IO_MASK(R_NETWORK_MGM_CTRL, mdck);
+	udelay(1);
 	return bit;
 }
 
@@ -566,7 +598,7 @@
 
 	cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2);
 
-	e100_send_mdio_cmd(cmd, 0);
+	e100_send_mdio_cmd(cmd, 1);
 	
 	data |= 0x8000;
 	
@@ -656,8 +688,8 @@
 {
 	struct net_device *dev = (struct net_device *)dev_id;
 	unsigned long irqbits = *R_IRQ_MASK2_RD;
-
-	if(irqbits & (1U << 3)) {
+ 
+	if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
 
 		/* acknowledge the eop interrupt */
 
@@ -671,10 +703,15 @@
 			 */
 			e100_rx(dev);
 			((struct net_local *)dev->priv)->stats.rx_packets++;
-			*R_DMA_CH1_CMD = 3; /* restart/continue on the channel, for safety */
-			*R_DMA_CH1_CLR_INTR = 3; /* clear dma channel 1 eop/descr irq bits */
-			/* now, we might have gotten another packet so we have to loop back
-			   and check if so */
+			/* restart/continue on the channel, for safety */
+			*R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart);
+			/* clear dma channel 1 eop/descr irq bits */
+			*R_DMA_CH1_CLR_INTR =
+				IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) |
+				IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do);
+			
+			/* now, we might have gotten another packet
+			   so we have to loop back and check if so */
 		}
 	}
 }
@@ -692,8 +729,9 @@
 	unsigned long irqbits = *R_IRQ_MASK2_RD;
 	struct net_local *np = (struct net_local *)dev->priv;
 
-	if(irqbits & 2) { /* check for a dma0_eop interrupt */
-
+	/* check for a dma0_eop interrupt */
+	if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { 
+		
 		/* This protects us from concurrent execution of
 		 * our dev->hard_start_xmit function above.
 		 */
@@ -727,12 +765,14 @@
 	struct net_local *np = (struct net_local *)dev->priv;
 	unsigned long irqbits = *R_IRQ_MASK0_RD;
 
-	if(irqbits & (1 << 19)) { /* check for overrun irq */
+	/* check for overrun irq */
+	if(irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) { 
 		update_rx_stats(&np->stats); /* this will ack the irq */
 		D(printk("ethernet receiver overrun!\n"));
 	}
-	if(irqbits & (1 << 17)) { /* check for excessive collision irq */
-		*R_NETWORK_TR_CTRL = 1 << 8; /* clear the interrupt */
+	/* check for excessive collision irq */
+	if(irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { 
+		*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
 		np->stats.tx_errors++;
 		D(printk("ethernet excessive collisions!\n"));
 	}
@@ -746,23 +786,19 @@
 	struct sk_buff *skb;
 	int length=0;
 	int i;
+	struct net_local *np = (struct net_local *)dev->priv;
 	struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc;
 	unsigned char *skb_data_ptr;
 
-	/* light the network rx packet depending on the current speed.
-	** But only if link has been detected.
-	*/
-	if (!nolink)
-		if (current_speed == 10) {
-			LED_NETWORK_TX_SET(1);
-			LED_NETWORK_RX_SET(1);
-		} else
-			LED_NETWORK_RX_SET(1);
-  
-	/* Set the earliest time we may clear the LED */
+	if (!led_active && jiffies > led_next_time) {
+		/* light the network leds depending on the current speed. */
+		e100_set_network_leds(NETWORK_ACTIVITY);
+
+		/* Set the earliest time we may clear the LED */
+		led_next_time = jiffies + NET_FLASH_TIME;
+		led_active = 1;
+	}
 
-	led_clear_time = jiffies + NET_FLASH_TIME;
-  
 	/* If the packet is broken down in many small packages then merge
 	 * count how much space we will need to alloc with skb_alloc() for
 	 * it to fit.
@@ -790,6 +826,7 @@
 
 	skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
 	if (!skb) {
+		np->stats.rx_errors++;
 		printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
 		       dev->name);
 		return;
@@ -798,7 +835,7 @@
 	skb_put(skb, length - ETHER_HEAD_LEN);        /* allocate room for the packet body */
 	skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */
 
-#if 0
+#ifdef ETHDEBUG
 	printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n",
 	       skb->head, skb->data, skb->tail, skb->end);
 	printk("copying packet to 0x%x.\n", skb_data_ptr);
@@ -849,9 +886,17 @@
 	*R_NETWORK_GEN_CONFIG =
 		IO_STATE(R_NETWORK_GEN_CONFIG, phy,    mii_clk) |
 		IO_STATE(R_NETWORK_GEN_CONFIG, enable, off);
-
-	*R_IRQ_MASK0_CLR = 0xe0000; /* clear excessive_col, over/underrun irq mask */
-	*R_IRQ_MASK2_CLR = 0xf; /* clear dma0 and 1 eop and descr irq masks */
+	
+	*R_IRQ_MASK0_CLR =
+		IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) |
+		IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) |
+		IO_STATE(R_IRQ_MASK0_CLR, excessive_col, clr);
+	
+	*R_IRQ_MASK2_CLR =
+		IO_STATE(R_IRQ_MASK2_CLR, dma0_descr, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma1_descr, clr) |
+		IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
 
 	/* Stop the receiver and the transmitter */
 
@@ -864,8 +909,8 @@
 	free_irq(NETWORK_DMATX_IRQ, (void *)dev);
 	free_irq(NETWORK_STATUS_IRQ, (void *)dev);
 
-	free_dma(0);
-	free_dma(1);
+	free_dma(ETH_TX_DMA);
+	free_dma(ETH_RX_DMA);
 
 	/* Update the statistics here. */
 
@@ -997,22 +1042,16 @@
 e100_hardware_send_packet(char *buf, int length)
 {
 	D(printk("e100 send pack, buf 0x%x len %d\n", buf, length));
-	/* light the network leds depending on the current speed.
-	** But only if link has been detected.
-	*/
-	if (!nolink) {
-		if (current_speed == 10) {
-			LED_NETWORK_TX_SET(1);
-			LED_NETWORK_RX_SET(1);
-		} else {
-			LED_NETWORK_RX_SET(1);
-		}
-	}
 
-	/* Set the earliest time we may clear the LED */
+	if (!led_active && jiffies > led_next_time) {
+		/* light the network leds depending on the current speed. */
+		e100_set_network_leds(NETWORK_ACTIVITY);
+
+		/* Set the earliest time we may clear the LED */
+		led_next_time = jiffies + NET_FLASH_TIME;
+		led_active = 1;
+	}
 
-	led_clear_time = jiffies + NET_FLASH_TIME;
-	
 	/* configure the tx dma descriptor */
 
 	TxDesc.sw_len = length;
@@ -1028,16 +1067,41 @@
 static void
 e100_clear_network_leds(unsigned long dummy)
 {
-	if (jiffies > led_clear_time) {
-		if (nolink)
-			LED_NETWORK_TX_SET(1);
-		else
-			LED_NETWORK_TX_SET(0);
-		LED_NETWORK_RX_SET(0); 
+        if (led_active && jiffies > led_next_time) {
+		e100_set_network_leds(NO_NETWORK_ACTIVITY);
+
+		/* Set the earliest time we may set the LED */
+		led_next_time = jiffies + NET_FLASH_PAUSE;
+		led_active = 0;
 	}
-	
-	clear_led_timer.expires = jiffies + 10;
+
+        clear_led_timer.expires = jiffies + HZ/10;
 	add_timer(&clear_led_timer);
+}
+
+static void
+e100_set_network_leds(int active)
+{
+#ifdef CONFIG_LED_OFF_DURING_ACTIVITY
+	int light_leds = (active == NO_NETWORK_ACTIVITY);
+#else
+	int light_leds = (active == NETWORK_ACTIVITY);
+#endif
+
+	if (!current_speed) {
+		/* Make LED red, link is down */
+		LED_NETWORK_SET(LED_RED);
+	}
+	else if (light_leds) {
+		if (current_speed == 10) {
+			LED_NETWORK_SET(LED_ORANGE);
+		} else {
+			LED_NETWORK_SET(LED_GREEN);
+		}
+	}
+	else {
+		LED_NETWORK_SET(LED_OFF);
+	}
 }
 
 static struct net_device dev_etrax_ethernet;  /* only got one */
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/parport.c linux/arch/cris/drivers/parport.c
--- v2.4.4/linux/arch/cris/drivers/parport.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/drivers/parport.c	Tue May  1 16:04:56 2001
@@ -0,0 +1,591 @@
+/* $Id: parport.c,v 1.4 2001/04/06 13:04:02 hugo Exp $
+ * 
+ * Elinux parallel port driver
+ * NOTE!
+ *   Since par0 shares DMA with ser2 and par 1 shares DMA with ser3
+ *   this should be handled if both are enabled at the same time.
+ *   THIS IS NOT HANDLED YET!
+ *
+ * Copyright (c) 2001 Axis Communications AB
+ * 
+ * Author: Fredrik Hugosson
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <asm/svinto.h>
+
+
+#undef DEBUG
+#ifdef DEBUG
+#define DPRINTK printk
+#else
+static inline int DPRINTK(void *nothing, ...) {return 0;}
+#endif
+
+/*
+ * Etrax100 DMAchannels:
+ * Par0 out : DMA2
+ * Par0 in  : DMA3
+ * Par1 out : DMA4
+ * Par1 in  : DMA5
+ * NOTE! par0 is hared with ser2 and par1 is shared with ser3 regarding
+ *       DMA and DMA irq
+ */
+
+//#define CONFIG_PAR0_INT 1
+//#define CONFIG_PAR1_INT 1
+
+#define SETF(var, reg, field, val) \
+	var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val)
+
+#define SETS(var, reg, field, val) \
+	var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val)
+
+struct etrax100par_struct {
+	/* parallell port control */
+	volatile u32 *reg_ctrl_data; /* R_PARx_CTRL_DATA */
+	const volatile u32 *reg_status_data; /* R_PARx_STATUS_DATA */
+	volatile u32 *reg_config; /* R_PARx_CONFIG */
+	volatile u32 *reg_delay; /* R_PARx_DELAY */
+	
+	/* DMA control */
+	int odma;
+	unsigned long dma_irq;  /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+
+	volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */
+	volatile u32 *ofirstadr;   /* adr to R_DMA_CHx_FIRST, output */
+	volatile char *ocmdadr;     /* adr to R_DMA_CHx_CMD, output */
+	
+	volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */
+	volatile u32 *ifirstadr;   /* adr to R_DMA_CHx_FIRST, input */
+	volatile char *icmdadr;     /* adr to R_DMA_CHx_CMD, input */
+	const volatile u8 *istatusadr;  /* adr to R_DMA_CHx_STATUS, input */
+	volatile u32 *ihwswadr;    /* adr to R_DMA_CHx_HWSW, input */
+
+	/* Non DMA interrupt stuff */
+	unsigned long int_irq; /* R_VECT_MASK_RD */
+	const volatile u32 *irq_mask_rd; /* R_IRQ_MASKX_RD */
+	volatile u32 *irq_mask_clr; /* R_IRQ_MASKX_RD */
+	const volatile u32 *irq_read; /* R_IRQ_READX */
+	volatile u32 *irq_mask_set; /* R_IRQ_MASKX_SET */
+	unsigned long irq_mask_tx;  /* bitmask in R_IRQ_ for tx (ready) int */
+	unsigned long irq_mask_rx;  /* bitmask in R_IRQ_ for rx (data) int */
+	unsigned long irq_mask_ecp_cmd;  /* mask in R_IRQ_ for ecp_cmd int */
+	unsigned long irq_mask_peri;  /* bitmask in R_IRQ_ for peri int */
+	int portnr;
+  
+	/* ----- end of fields initialised in port_table[] below ----- */
+
+	//  struct etrax_dma_descr tr_descr;
+	//  unsigned char tr_buf[LP_BUFFER_SIZE];
+	//  const unsigned char *tr_buf_curr; /* current char sent */
+	//  const unsigned char *tr_buf_last; /* last char in buf */
+  
+	//  int fifo_magic; /* fifo amount - bytes left in dma buffer */
+	//  unsigned char         fifo_didmagic; /* a fifo eop has been forced */
+	//  volatile int          tr_running; /* 1 if output is running */
+	
+	struct parport *port;
+  
+	/* Shadow registers */
+	volatile unsigned long reg_ctrl_data_shadow; /* for R_PARx_CTRL_DATA */
+	volatile unsigned long reg_config_shadow;    /* for R_PARx_CONFIG */
+	volatile unsigned long reg_delay_shadow;    /* for R_PARx_DELAY */
+};
+
+/* Always have the complete structs here, even if the port is not used!
+ *  (that way we can index this by the port number)
+ */
+static struct etrax100par_struct port_table[] = {
+	{ 
+		R_PAR0_CTRL_DATA,
+		R_PAR0_STATUS_DATA,
+		R_PAR0_CONFIG,
+		R_PAR0_DELAY,
+		/* DMA interrupt stuff */
+		2,
+		1U << 4, /* uses DMA 2 and 3 */
+		R_DMA_CH2_CLR_INTR,
+		R_DMA_CH2_FIRST,
+		R_DMA_CH2_CMD,
+		R_DMA_CH3_CLR_INTR,
+		R_DMA_CH3_FIRST,
+		R_DMA_CH3_CMD,
+		R_DMA_CH3_STATUS,
+		R_DMA_CH3_HWSW,
+		/* Non DMA interrupt stuff */
+		IO_BITNR(R_VECT_MASK_RD, par0),
+		R_IRQ_MASK0_RD,
+		R_IRQ_MASK0_CLR,
+		R_IRQ_READ0,
+		R_IRQ_MASK0_SET,
+		IO_FIELD(R_IRQ_MASK0_RD, par0_ready, 1U), /* tx (ready)*/
+		IO_FIELD(R_IRQ_MASK0_RD, par0_data, 1U), /* rx (data)*/
+		IO_FIELD(R_IRQ_MASK0_RD, par0_ecp_cmd, 1U), /* ecp_cmd */
+		IO_FIELD(R_IRQ_MASK0_RD, par0_peri, 1U), /* peri */
+		0
+	},
+	{
+		R_PAR1_CTRL_DATA,
+		R_PAR1_STATUS_DATA,
+		R_PAR1_CONFIG,
+		R_PAR1_DELAY,
+		/* DMA interrupt stuff */
+		4,
+		1U << 8, /* uses DMA 4 and 5 */
+		
+		R_DMA_CH4_CLR_INTR,
+		R_DMA_CH4_FIRST,
+		R_DMA_CH4_CMD,
+		R_DMA_CH5_CLR_INTR,
+		R_DMA_CH5_FIRST,
+		R_DMA_CH5_CMD,
+		R_DMA_CH5_STATUS,
+		R_DMA_CH5_HWSW,
+		/* Non DMA interrupt stuff */
+		IO_BITNR(R_VECT_MASK_RD, par1),
+		R_IRQ_MASK1_RD,
+		R_IRQ_MASK1_CLR,
+		R_IRQ_READ1,
+		R_IRQ_MASK1_SET,
+		IO_FIELD(R_IRQ_MASK1_RD, par1_ready, 1U), /* tx (ready)*/
+		IO_FIELD(R_IRQ_MASK1_RD, par1_data, 1U), /* rx (data)*/
+		IO_FIELD(R_IRQ_MASK1_RD, par1_ecp_cmd, 1U), /* ecp_cmd */
+		IO_FIELD(R_IRQ_MASK1_RD, par1_peri, 1U), /* peri */
+		1
+	}
+};
+
+
+#define NR_PORTS (sizeof(port_table)/sizeof(struct etrax100par_struct))
+
+static void
+parport_etrax_write_data(struct parport *p, unsigned char value)
+{
+	struct etrax100par_struct *info =
+		(struct etrax100par_struct *)p->private_data;
+
+	DPRINTK("* E100 PP %d: etrax_write_data %02X\n", p->portnum, value);
+	SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, data, value);
+	*info->reg_ctrl_data = info->reg_ctrl_data_shadow;
+}
+
+
+static unsigned char
+parport_etrax_read_data(struct parport *p)
+{
+	unsigned char ret;
+	struct etrax100par_struct *info =
+		(struct etrax100par_struct *)p->private_data;
+
+	ret = IO_EXTRACT(R_PAR0_STATUS_DATA, data, *info->reg_status_data);
+
+	DPRINTK("* E100 PP %d: etrax_read_data %02X\n", p->portnum, ret);
+	return ret;
+}
+
+
+static void
+parport_etrax_write_control(struct parport *p, unsigned char control)
+{
+	struct etrax100par_struct *info =
+		(struct etrax100par_struct *)p->private_data;
+
+	DPRINTK("* E100 PP %d: etrax_write_control %02x\n", p->portnum, control);
+  
+	SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, strb,
+	     (control & PARPORT_CONTROL_STROBE) > 0);
+	SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, autofd,
+	     (control & PARPORT_CONTROL_AUTOFD) > 0);
+	SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, init,
+	     (control & PARPORT_CONTROL_INIT) > 0);
+	SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, seli,
+	     (control & PARPORT_CONTROL_SELECT) > 0);
+
+	*info->reg_ctrl_data = info->reg_ctrl_data_shadow;
+}
+
+
+static unsigned char
+parport_etrax_read_control( struct parport *p)
+{
+	unsigned char ret = 0;
+	struct etrax100par_struct *info =
+		(struct etrax100par_struct *)p->private_data;
+
+	if (IO_EXTRACT(R_PAR0_CTRL_DATA, strb, info->reg_ctrl_data_shadow))
+		ret |= PARPORT_CONTROL_STROBE;
+	if (IO_EXTRACT(R_PAR0_CTRL_DATA, autofd, info->reg_ctrl_data_shadow))
+		ret |= PARPORT_CONTROL_AUTOFD;
+	if (IO_EXTRACT(R_PAR0_CTRL_DATA, init, info->reg_ctrl_data_shadow))
+		ret |= PARPORT_CONTROL_INIT;
+	if (IO_EXTRACT(R_PAR0_CTRL_DATA, seli, info->reg_ctrl_data_shadow))
+		ret |= PARPORT_CONTROL_SELECT;
+
+	DPRINTK("* E100 PP %d: etrax_read_control %02x\n", p->portnum, ret);
+	return ret;
+}
+
+
+static unsigned char
+parport_etrax_frob_control(struct parport *p, unsigned char mask,
+                           unsigned char val)
+{
+	unsigned char old;
+
+	DPRINTK("* E100 PP %d: frob_control mask %02x, value %02x\n",
+		p->portnum, mask, val);
+	old = parport_etrax_read_control(p);
+	parport_etrax_write_control(p, (old & ~mask) ^ val);
+	return old;
+}
+
+
+static unsigned char
+parport_etrax_read_status(struct parport *p)
+{
+	unsigned char ret = 0;
+	struct etrax100par_struct *info =
+		(struct etrax100par_struct *)p->private_data;
+
+	if (IO_EXTRACT(R_PAR0_STATUS_DATA, fault, *info->reg_status_data))
+		ret |= PARPORT_STATUS_ERROR;
+	if (IO_EXTRACT(R_PAR0_STATUS_DATA, sel, *info->reg_status_data))
+		ret |= PARPORT_STATUS_SELECT;
+	if (!IO_EXTRACT(R_PAR0_STATUS_DATA, perr, *info->reg_status_data))
+		ret |= PARPORT_STATUS_PAPEROUT;
+	if (IO_EXTRACT(R_PAR0_STATUS_DATA, ack, *info->reg_status_data))
+		ret |= PARPORT_STATUS_ACK;
+	if (!IO_EXTRACT(R_PAR0_STATUS_DATA, busy, *info->reg_status_data))
+		ret |= PARPORT_STATUS_BUSY;
+
+	DPRINTK("* E100 PP %d: status register %04x\n",
+		p->portnum, *info->reg_status_data);
+	DPRINTK("* E100 PP %d: read_status %02x\n", p->portnum, ret);
+	return ret;
+}
+
+
+static void
+parport_etrax_enable_irq(struct parport *p)
+{
+	struct etrax100par_struct *info =
+		(struct etrax100par_struct *)p->private_data;
+	*info->irq_mask_set = info->irq_mask_tx;
+	DPRINTK("* E100 PP %d: enable irq\n", p->portnum);
+}
+
+
+static void
+parport_etrax_disable_irq(struct parport *p)
+{
+	struct etrax100par_struct *info =
+		(struct etrax100par_struct *)p->private_data;
+	*info->irq_mask_clr = info->irq_mask_tx;
+	DPRINTK("* E100 PP %d: disable irq\n", p->portnum);
+}
+
+
+static void
+parport_etrax_data_forward(struct parport *p)
+{
+	struct etrax100par_struct *info =
+		(struct etrax100par_struct *)p->private_data;
+
+	DPRINTK("* E100 PP %d: forward mode\n", p->portnum);
+	SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, enable);
+	*info->reg_ctrl_data = info->reg_ctrl_data_shadow;
+}
+
+
+static void
+parport_etrax_data_reverse(struct parport *p)
+{
+	struct etrax100par_struct *info =
+		(struct etrax100par_struct *)p->private_data;
+
+	DPRINTK("* E100 PP %d: reverse mode\n", p->portnum);
+	SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, disable);
+	*info->reg_ctrl_data = info->reg_ctrl_data_shadow;
+}
+
+
+static void
+parport_etrax_init_state(struct pardevice *dev, struct parport_state *s)
+{
+	DPRINTK("* E100 PP: parport_etrax_init_state\n");
+}
+
+
+static void
+parport_etrax_save_state(struct parport *p, struct parport_state *s)
+{
+	DPRINTK("* E100 PP: parport_etrax_save_state\n");
+}
+
+
+static void
+parport_etrax_restore_state(struct parport *p, struct parport_state *s)
+{
+	DPRINTK("* E100 PP: parport_etrax_restore_state\n");
+}
+
+
+static void
+parport_etrax_inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+
+static void
+parport_etrax_dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+
+static struct
+parport_operations pp_etrax_ops = {
+	parport_etrax_write_data,
+	parport_etrax_read_data,
+
+	parport_etrax_write_control,
+	parport_etrax_read_control,
+	parport_etrax_frob_control,
+
+	parport_etrax_read_status,
+
+	parport_etrax_enable_irq,
+	parport_etrax_disable_irq,
+
+	parport_etrax_data_forward, 
+	parport_etrax_data_reverse, 
+
+	parport_etrax_init_state,
+	parport_etrax_save_state,
+	parport_etrax_restore_state,
+
+	parport_etrax_inc_use_count,
+	parport_etrax_dec_use_count,
+
+	parport_ieee1284_epp_write_data,
+	parport_ieee1284_epp_read_data,
+	parport_ieee1284_epp_write_addr,
+	parport_ieee1284_epp_read_addr,
+
+	parport_ieee1284_ecp_write_data,
+	parport_ieee1284_ecp_read_data,
+	parport_ieee1284_ecp_write_addr,
+
+	parport_ieee1284_write_compat,
+	parport_ieee1284_read_nibble,
+	parport_ieee1284_read_byte,
+};
+
+	
+static void 
+parport_etrax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct etrax100par_struct *info = (struct etrax100par_struct *)
+		((struct parport *)dev_id)->private_data;
+	DPRINTK("* E100 PP %d: Interrupt received\n",
+		((struct parport *)dev_id)->portnum);
+	*info->irq_mask_clr = info->irq_mask_tx;
+	parport_generic_irq(irq, (struct parport *)dev_id, regs);
+}
+
+/* ----------- Initialisation code --------------------------------- */
+
+static void 
+parport_etrax_show_parallel_version(void)
+{
+	printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n");
+}
+
+#ifdef CONFIG_ETRAX_PAR0_DMA
+#define PAR0_USE_DMA 1
+#else
+#define PAR0_USE_DMA 0
+#endif
+
+#ifdef CONFIG_ETRAX_PAR1_DMA
+#define PAR1_USE_DMA 1
+#else
+#define PAR1_USE_DMA 0
+#endif
+
+static void 
+parport_etrax_init_registers(void)
+{
+	struct etrax100par_struct *info;
+	int i;
+
+	/* The different times below will be (value*160 + 20) ns,    */
+	/* i.e. 20ns-4.98us. E.g. if setup is set to 00110 (0x6),    */
+	/* the setup time will be (6*160+20) = 980ns.                */
+
+	for (i = 0, info = port_table; i < 2; i++, info++) {
+#ifndef CONFIG_ETRAX_PARALLEL_PORT0
+		if (i == 0)
+			continue;
+#endif
+#ifndef CONFIG_ETRAX_PARALLEL_PORT1
+		if (i == 1)
+			continue;
+#endif
+		info->reg_config_shadow = 
+			IO_STATE(R_PAR0_CONFIG, iseli, inv)       |
+			IO_STATE(R_PAR0_CONFIG, iautofd, inv)     |
+			IO_STATE(R_PAR0_CONFIG, istrb, inv)       |
+			IO_STATE(R_PAR0_CONFIG, iinit, inv)       |
+			IO_STATE(R_PAR0_CONFIG, rle_in, disable)  |
+			IO_STATE(R_PAR0_CONFIG, rle_out, disable) |
+			IO_STATE(R_PAR0_CONFIG, enable, on)       |
+			IO_STATE(R_PAR0_CONFIG, force, off)       |
+			IO_STATE(R_PAR0_CONFIG, ign_ack, wait)    |
+			IO_STATE(R_PAR0_CONFIG, oe_ack, wait_oe)  |
+			IO_STATE(R_PAR0_CONFIG, mode, manual);
+
+		if ((i == 0 && PAR0_USE_DMA) || (i == 1 && PAR1_USE_DMA))
+			info->reg_config_shadow |=
+				IO_STATE(R_PAR0_CONFIG, dma, enable);
+		else
+			info->reg_config_shadow |=
+				IO_STATE(R_PAR0_CONFIG, dma, disable);
+
+		*info->reg_config = info->reg_config_shadow;
+
+		info->reg_ctrl_data_shadow = 
+			IO_STATE(R_PAR0_CTRL_DATA, peri_int, nop)    |
+			IO_STATE(R_PAR0_CTRL_DATA, oe, enable)       |
+			IO_STATE(R_PAR0_CTRL_DATA, seli, inactive)   |
+			IO_STATE(R_PAR0_CTRL_DATA, autofd, inactive) |
+			IO_STATE(R_PAR0_CTRL_DATA, strb, inactive)   |
+			IO_STATE(R_PAR0_CTRL_DATA, init, inactive)   |
+			IO_STATE(R_PAR0_CTRL_DATA, ecp_cmd, data)    |
+			IO_FIELD(R_PAR0_CTRL_DATA, data, 0);
+		*info->reg_ctrl_data = info->reg_ctrl_data_shadow;
+
+		/* Clear peri int without setting shadow */
+		*info->reg_ctrl_data = info->reg_ctrl_data_shadow |
+			IO_STATE(R_PAR0_CTRL_DATA, peri_int, ack);
+
+		info->reg_delay_shadow = 
+			IO_FIELD(R_PAR0_DELAY, setup, 5)  |
+			IO_FIELD(R_PAR0_DELAY, strobe, 5) |
+			IO_FIELD(R_PAR0_DELAY, hold, 5);
+		*info->reg_delay = info->reg_delay_shadow;
+	}
+
+#ifdef CONFIG_ETRAX_PARALLEL_PORT0
+#ifdef CONFIG_ETRAX_PAR0_DMA
+	RESET_DMA(2);
+	WAIT_DMA(2);
+#ifdef CONFIG_ETRAX_SERIAL_PORT2
+	printk(" Warning - DMA clash with ser2!\n");
+#endif /* SERIAL_PORT2 */
+#endif /* DMA */
+#endif /* PORT0 */
+
+#ifdef CONFIG_ETRAX_PARALLEL_PORT1
+#ifdef CONFIG_ETRAX_PAR1_DMA
+	RESET_DMA(4);
+	WAIT_DMA(4);
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
+	printk(" Warning - DMA clash with ser3!\n");
+#endif /* SERIAL_PORT3 */
+#endif /* DMA */
+#endif /* PORT1 */
+} 
+
+
+int __init
+parport_etrax_init(void)
+{
+	struct parport *p;
+	int port_exists = 0;
+	int i;
+	struct etrax100par_struct *info;
+        const char *names[] = { "parallel 0 tx+rx", "parallel 1 tx+rx" };
+
+	parport_etrax_show_parallel_version();
+	parport_etrax_init_registers();
+
+        for (i = 0, info = port_table; i < NR_PORTS; i++, info++) {
+#ifndef CONFIG_ETRAX_PARALLEL_PORT0
+		if (i == 0)
+			continue;
+#endif
+#ifndef CONFIG_ETRAX_PARALLEL_PORT1
+		if (i == 1)
+			continue;
+#endif
+                p = parport_register_port((unsigned long)0, info->int_irq,
+                                          PARPORT_DMA_NONE, &pp_etrax_ops);
+                if (!p)
+			continue;
+
+                info->port = p;
+                p->private_data = info;
+                /* Axis FIXME: Set mode flags. */
+                /* p->modes = PARPORT_MODE_TRISTATE | PARPORT_MODE_SAFEININT; */
+
+	        if(request_irq(info->int_irq, parport_etrax_interrupt,
+                               SA_SHIRQ, names[i], p)) {
+	        	parport_unregister_port (p);
+                        continue;
+                }
+
+                printk(KERN_INFO "%s: ETRAX 100LX port %d using irq\n",
+                       p->name, i);
+                parport_proc_register(p);
+                parport_announce_port(p);
+                port_exists = 1;
+        }
+
+	return port_exists;
+}
+
+void __exit
+parport_etrax_exit(void)
+{
+	int i;
+	struct etrax100par_struct *info;
+
+        for (i = 0, info = port_table; i < NR_PORTS; i++, info++) {
+#ifndef CONFIG_ETRAX_PARALLEL_PORT0
+		if (i == 0)
+			continue;
+#endif
+#ifndef CONFIG_ETRAX_PARALLEL_PORT1
+		if (i == 1)
+			continue;
+#endif
+		if (info->int_irq != PARPORT_IRQ_NONE)
+			free_irq(info->int_irq, info->port);
+		parport_proc_unregister(info->port);
+		parport_unregister_port(info->port);
+        }
+}
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/serial.c linux/arch/cris/drivers/serial.c
--- v2.4.4/linux/arch/cris/drivers/serial.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/serial.c	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-/* $Id: serial.c,v 1.10 2001/03/05 13:14:07 bjornw Exp $
+/* $Id: serial.c,v 1.12 2001/04/19 12:23:07 bjornw Exp $
  *
  * Serial port driver for the ETRAX 100LX chip
  *
@@ -7,6 +7,15 @@
  *      Many, many authors. Based once upon a time on serial.c for 16x50.
  *
  * $Log: serial.c,v $
+ * Revision 1.12  2001/04/19 12:23:07  bjornw
+ * CONFIG_RS485 -> CONFIG_ETRAX_RS485
+ *
+ * Revision 1.11  2001/04/05 14:29:48  markusl
+ * Updated according to review remarks i.e.
+ * -Use correct types in port structure to avoid compiler warnings
+ * -Try to use IO_* macros whenever possible
+ * -Open should never return -EBUSY
+ *
  * Revision 1.10  2001/03/05 13:14:07  bjornw
  * Another spelling fix
  *
@@ -190,7 +199,7 @@
  *
  */
 
-static char *serial_version = "$Revision: 1.10 $";
+static char *serial_version = "$Revision: 1.12 $";
 
 #include <linux/config.h>
 #include <linux/version.h>
@@ -299,6 +308,18 @@
 #define REG_BAUD 3
 #define REG_XOFF 4  /* this is a 32 bit register */
 
+/*
+ * General note regarding the use of IO_* macros in this file: 
+ *
+ * We will use the bits defined for DMA channel 6 when using various
+ * IO_* macros (e.g. IO_STATE, IO_MASK, IO_EXTRACT) and _assume_ they are
+ * the same for all channels (which of course they are).
+ *
+ * We will also use the bits defined for serial port 0 when writing commands
+ * to the different ports, as these bits too are the same for all ports.
+ */
+
+
 /* this is the data for the four serial ports in the etrax100 */
 /*  DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
 /* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
@@ -343,9 +364,9 @@
 
 
 /* RS-485 */
-#if defined(CONFIG_RS485)
-#if defined(CONFIG_RS485_ON_PA)
-static int rs485_pa_bit = CONFIG_RS485_ON_PA_BIT;
+#if defined(CONFIG_ETRAX_RS485)
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
+static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
 #endif
 #endif
   
@@ -421,8 +442,8 @@
   }
 };
 
-#if defined(CONFIG_RS485) && defined(CONFIG_RS485_ON_PA)
-unsigned char rs485_pa_port = CONFIG_RS485_ON_PA_BIT;
+#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA)
+unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT;
 #endif
 
 #define E100_RTS_MASK 0x20
@@ -668,7 +689,8 @@
 {
 #ifndef CONFIG_SVINTO_SIM
 	/* disable the receiver */
-	info->port[REG_REC_CTRL] = (info->rx_ctrl &= ~0x40);
+	info->port[REG_REC_CTRL] = info->rx_ctrl &=
+		~IO_MASK(R_SERIAL0_REC_CTRL, rec_enable);
 #endif
 }
 
@@ -677,7 +699,8 @@
 {
 #ifndef CONFIG_SVINTO_SIM
 	/* enable the receiver */
-	info->port[REG_REC_CTRL] = (info->rx_ctrl |= 0x40);
+	info->port[REG_REC_CTRL] = info->rx_ctrl |=
+		IO_MASK(R_SERIAL0_REC_CTRL, rec_enable);
 #endif
 }
 
@@ -747,14 +770,14 @@
 }
 #endif
 
-#if defined(CONFIG_RS485)
+#if defined(CONFIG_ETRAX_RS485)
 /* Enable RS-485 mode on selected port. This is UGLY. */
 static int
 e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r)
 {
 	struct e100_serial * info = (struct e100_serial *)tty->driver_data;
 
-#if defined(CONFIG_RS485_ON_PA)	
+#if defined(CONFIG_ETRAX_RS485_ON_PA)	
 	*R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
 #endif
 
@@ -766,7 +789,6 @@
 	return 0;
 }
 
-/* Enable RS-485 mode on selected port. This is UGLY. */
 static int
 e100_write_rs485(struct tty_struct *tty,struct rs485_write *r)
 {
@@ -782,7 +804,7 @@
 	 * the receiver before initiating a DMA transfer
 	 */
 	e100_rts(info, info->rs485.rts_on_send);
-#if defined(CONFIG_RS485_DISABLE_RECEIVER)
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
 	e100_disable_rx(info);
 	e100_disable_rxdma_irq(info);
 #endif
@@ -824,14 +846,16 @@
 	max_j = jiffies + (delay_ms * HZ)/1000 + 10;
 
 	while (jiffies < max_j ) {
-	  if (info->port[REG_STATUS] & 0x20) {
+	  if (info->port[REG_STATUS] &
+	      IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) {
 	    for( i=0 ; i<100; i++ ) {};
-	    if (info->port[REG_STATUS] & 0x20) {
+	    if (info->port[REG_STATUS] &
+		IO_STATE(R_SERIAL0_STATUS, tr_ready, ready)) {
 	      /* ~25 for loops per usec */
-	      stop_delay = 25 * (1000000 / info->baud);
+	      stop_delay = 1000000 / info->baud;
 	      if(cflags & CSTOPB) 
 		stop_delay *= 2;
-	      for( i=0 ; i<stop_delay; i++ ) {};
+	      udelay(stop_delay);
 	      break;
 	    }
 	  }
@@ -839,7 +863,7 @@
 
 	e100_rts(info, info->rs485.rts_after_sent);
 	
-#if defined(CONFIG_RS485_DISABLE_RECEIVER)
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
 	e100_enable_rx(info);
 	e100_enable_rxdma_irq(info);
 #endif
@@ -942,7 +966,9 @@
 	return;
 #endif
 	/* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */
-	*info->oclrintradr = 3;
+	*info->oclrintradr =
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
 
 #ifdef SERIAL_DEBUG_INTR
 	if(info->line == SERIAL_DEBUG_LINE)
@@ -987,19 +1013,20 @@
 		/* our job here is done, don't schedule any new DMA transfer */
 		info->tr_running = 0;
 
-#if defined(CONFIG_RS485)
+#if defined(CONFIG_ETRAX_RS485)
 		/* Check if we should toggle RTS now */
 		if (info->rs485.enabled)
 		{
 			/* Make sure fifo is empty */
 			int in_fifo = 0 ;
 			do{
-				in_fifo = (*info->ostatusadr) & 0x007F ;
+				in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail,
+						    *info->ostatusadr);
 			}  while (in_fifo > 0) ;
 			/* Any way to really check transmitter empty? (TEMT) */
 			/* Control RTS to set to RX mode */
 			e100_rts(info, info->rs485.rts_after_sent); 
-#if defined(CONFIG_RS485_DISABLE_RECEIVER)
+#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
 			e100_enable_rx(info);
 			e100_enable_rxdma_irq(info);
 #endif
@@ -1060,7 +1087,9 @@
 
 	/* acknowledge both a dma_descr and dma_eop irq in R_DMAx_CLRINTR */
 
-	*info->iclrintradr = 3;
+	*info->iclrintradr =
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
 
 	if(!tty) /* something wrong... */
 		return;
@@ -1088,7 +1117,9 @@
 		/* read the status register so we can detect errors */
 		rstat = info->port[REG_STATUS];
 
-		if(rstat & 0xe) {
+		if(rstat & (IO_MASK(R_SERIAL0_STATUS, overrun) |
+			    IO_MASK(R_SERIAL0_STATUS, par_err) |
+			    IO_MASK(R_SERIAL0_STATUS, framing_err))) {
 			/* if we got an error, we must reset it by reading the
 			 * data_in field
 			 */
@@ -1148,7 +1179,7 @@
 	descr->status = 0;
 
 	*info->ifirstadr = virt_to_phys(descr);
-	*info->icmdadr = 1; /* start */
+	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
 
 #ifdef SERIAL_HANDLE_EARLY_ERRORS
 	e100_enable_serial_data_irq(info);
@@ -1170,8 +1201,9 @@
 
 	/* reset the input dma channel to be sure it works */
 	
-	*info->icmdadr = 4;
-	while((*info->icmdadr & 7) == 4);
+	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+	while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+	      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
 
 	descr = &info->rec_descr;
 	
@@ -1186,7 +1218,8 @@
 	info->tty->flip.count = 0;
 
 	*info->ifirstadr = virt_to_phys(descr);
-	*info->icmdadr = 1; /* start */
+	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
+	
 }
 
 
@@ -1293,7 +1326,7 @@
 static struct timer_list flush_timer;
 
 static void 
-timed_flush_handler(void)
+timed_flush_handler(unsigned long ptr)
 {
 	struct e100_serial *info;
 	int i;
@@ -1381,7 +1414,7 @@
 				PROCSTAT(early_errors_cnt[info->line]++);
 
 				/* restart the DMA */
-				*info->icmdadr = 3;
+				*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
 			} 
 			else { /* it was a valid byte, now let the dma do the rest */
 #ifdef SERIAL_DEBUG_INTR
@@ -1472,7 +1505,7 @@
 	if (info->flags & ASYNC_INITIALIZED) {
 		free_page(page);
 		restore_flags(flags);
-		return -EBUSY;
+		return 0;
 	}
 	
 	if (info->xmit.buf)
@@ -1518,14 +1551,22 @@
 	 * Reset the DMA channels and make sure their interrupts are cleared
 	 */
 	
-	*info->icmdadr = 4; /* reset command */
-	*info->ocmdadr = 4; /* reset command */
-	
-	while((*info->icmdadr & 7) == 4); /* wait until reset cycle is complete */
-	while((*info->ocmdadr & 7) == 4);
-	
-	*info->iclrintradr = 3; /* make sure the irqs are cleared */
-	*info->oclrintradr = 3;
+	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+	*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+
+	/* wait until reset cycle is complete */
+	while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
+	      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+
+	while(IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
+	      IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
+	
+	*info->iclrintradr =
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
+	*info->oclrintradr =
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
+		IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
 	
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1597,8 +1638,8 @@
 
 	/* reset both dma channels */
 
-	*info->icmdadr = 4;
-	*info->ocmdadr = 4;
+	*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
+	*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
 
 #endif /* CONFIG_SVINTO_SIM */
 
@@ -1658,42 +1699,51 @@
 #ifndef CONFIG_SVINTO_SIM
 	info->port[REG_BAUD] = cflag_to_etrax_baud(cflag);
 	/* start with default settings and then fill in changes */
-	
-	info->rx_ctrl &= ~(0x07); /* 8 bit, no/even parity */
-	info->tx_ctrl &= ~(0x37); /* 8 bit, no/even parity, 1 stop bit, no cts */
+
+	/* 8 bit, no/even parity */
+	info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
+			   IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
+			   IO_MASK(R_SERIAL0_REC_CTRL, rec_par));
+
+	/* 8 bit, no/even parity, 1 stop bit, no cts */
+	info->tx_ctrl &= ~(IO_MASK(R_SERIAL0_TR_CTRL, tr_bitnr) |
+			   IO_MASK(R_SERIAL0_TR_CTRL, tr_par_en) |
+			   IO_MASK(R_SERIAL0_TR_CTRL, tr_par) |
+			   IO_MASK(R_SERIAL0_TR_CTRL, stop_bits) |
+			   IO_MASK(R_SERIAL0_TR_CTRL, auto_cts));
 	
 	if ((cflag & CSIZE) == CS7) {
 		/* set 7 bit mode */
-		info->tx_ctrl |= 0x01;
-		info->rx_ctrl |= 0x01;
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit);
+		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit);
 	}
 	
 	if (cflag & CSTOPB) {
 		/* set 2 stop bit mode */
-		info->tx_ctrl |= 0x10;
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, two_bits);
 	}	  
 	
 	if (cflag & PARENB) {
 		/* enable parity */
-		info->tx_ctrl |= 0x02;
-		info->rx_ctrl |= 0x02;
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable);
+		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable);
 	}
 	
 	if (cflag & PARODD) {
 		/* set odd parity */
-		info->tx_ctrl |= 0x04;
-		info->rx_ctrl |= 0x04;
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
+		info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
 	}
 	
 	if (cflag & CRTSCTS) {
 		/* enable automatic CTS handling */
-		info->tx_ctrl |= 0x20;
+		info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active);
 	}
 	
 	/* make sure the tx and rx are enabled */
 	
-	info->tx_ctrl |= 0x40;
-	info->rx_ctrl |= 0x40;
+	info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable);
+	info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
 
 	/* actually write the control regs to the hardware */
 	
@@ -2330,7 +2380,7 @@
 				return -EFAULT;
 			return 0;
 
-#if defined(CONFIG_RS485)
+#if defined(CONFIG_ETRAX_RS485)
 		case TIOCSERSETRS485:
 			error = verify_area(VERIFY_WRITE, (void *) arg,
 					sizeof(struct rs485_control));
@@ -2488,10 +2538,10 @@
 
 	/* port closed */
 
-#if defined(CONFIG_RS485)
+#if defined(CONFIG_ETRAX_RS485)
 	if (info->rs485.enabled) {
 		info->rs485.enabled = 0;
-#if defined(CONFIG_RS485_ON_PA)
+#if defined(CONFIG_ETRAX_RS485_ON_PA)
 		*R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
 #endif
 	}
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/serial.h linux/arch/cris/drivers/serial.h
--- v2.4.4/linux/arch/cris/drivers/serial.h	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/serial.h	Tue May  1 16:04:56 2001
@@ -25,26 +25,26 @@
 
 struct e100_serial {
 	int                   baud;
-	volatile unsigned char *	port; /* R_SERIALx_CTRL */
-	unsigned long	        irq;  /* bitnr in R_IRQ_MASK2 for dmaX_descr */
+	volatile u8 *port;             /* R_SERIALx_CTRL */
+	u32 irq;                       /* bitnr in R_IRQ_MASK2 for dmaX_descr */
 
-	volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */
-	volatile unsigned long *ofirstadr;   /* adr to R_DMA_CHx_FIRST, output */
-	volatile char *ocmdadr;     /* adr to R_DMA_CHx_CMD, output */
-	const volatile unsigned short *ostatusadr;  /* adr to R_DMA_CHx_STATUS, output */
-	volatile unsigned long  *ohwswadr;    /* adr to R_DMA_CHx_HWSW, output */
+	volatile u8 *oclrintradr;      /* adr to R_DMA_CHx_CLR_INTR, output */
+	volatile u32 *ofirstadr;       /* adr to R_DMA_CHx_FIRST, output */
+	volatile u8 *ocmdadr;          /* adr to R_DMA_CHx_CMD, output */
+	const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS, output */
+	volatile u32 *ohwswadr;        /* adr to R_DMA_CHx_HWSW, output */
 
-	volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */
-	volatile unsigned long *ifirstadr;   /* adr to R_DMA_CHx_FIRST, input */
-	volatile char *icmdadr;     /* adr to R_DMA_CHx_CMD, input */
-	const volatile unsigned short *istatusadr;  /* adr to R_DMA_CHx_STATUS, input */
-	volatile unsigned long  *ihwswadr;    /* adr to R_DMA_CHx_HWSW, input */
+	volatile u8 *iclrintradr;      /* adr to R_DMA_CHx_CLR_INTR, input */
+	volatile u32 *ifirstadr;       /* adr to R_DMA_CHx_FIRST, input */
+	volatile u8 *icmdadr;          /* adr to R_DMA_CHx_CMD, input */
+	const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */
+	volatile u32 *ihwswadr;        /* adr to R_DMA_CHx_HWSW, input */
 
 	int			flags; 		/* defined in tty.h */
 
-	unsigned char           rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
-	unsigned char           tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
-	unsigned char           iseteop; /* bit number for R_SET_EOP for the input dma */
+	u8           rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
+	u8           tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
+	u8           iseteop; /* bit number for R_SET_EOP for the input dma */
 /* end of fields defined in rs_table[] in .c-file */
 	unsigned char           fifo_didmagic; /* a fifo eop has been forced */
 
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/sync_serial.c linux/arch/cris/drivers/sync_serial.c
--- v2.4.4/linux/arch/cris/drivers/sync_serial.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/sync_serial.c	Tue May  1 16:04:56 2001
@@ -2,8 +2,9 @@
  * Simple synchronous serial port driver for ETRAX 100LX.
  *
  * Synchronous serial ports are used for continous streamed data like audio.
- * The deault setting for this driver is compatible with the STA 013 MP3 decoder
- * The driver can easily be tuned to fit other audio encoder/decoders and SPI
+ * The default setting for this driver is compatible with the STA 013 MP3
+ * decoder. The driver can easily be tuned to fit other audio encoder/decoders
+ * and SPI
  *
  * Copyright (c) 2001 Axis Communications AB
  * 
@@ -29,37 +30,43 @@
 #include <asm/sync_serial.h>
 
 /* The receiver is a bit tricky beacuse of the continous stream of data. */
-/*									 */
-/* Two DMA descriptors are linked together. Each DMA descriptor is	 */
-/* responsible for one half of a common buffer.				 */
-/*									 */
-/* ------------------------------					 */
-/* |   ----------   ----------	|					 */
-/* --> | Descr1 |-->| Descr2 |---					 */
-/*     ----------   ----------						 */
-/*	 |	       |						 */
-/*	 v	       v						 */
-/*	 -----------------------------					 */
-/*	 |	      BUFFER	     |					 */
-/*	 -----------------------------					 */
-/*	 |		|						 */
-/*	readp	      writep						 */
-/*									 */
+/*                                                                       */
+/* Two DMA descriptors are linked together. Each DMA descriptor is       */
+/* responsible for one half of a common buffer.                          */
+/*                                                                       */
+/* ------------------------------                                        */
+/* |   ----------   ----------	|                                        */
+/* --> | Descr1 |-->| Descr2 |---                                        */
+/*     ----------   ----------                                           */
+/*         |            |                                                */
+/*         v            v                                                */
+/*   -----------------------------                                       */
+/*   |        BUFFER             |                                       */
+/*   -----------------------------                                       */
+/*      |             |                                                  */
+/*    readp          writep                                              */
+/*                                                                       */
 /* If the application keeps up the pace readp will be right after writep.*/
-/* If the application can't keep the pace we have to throw away data.	 */ 
+/* If the application can't keep the pace we have to throw away data.    */ 
 /* The idea is that readp should be ready with the data pointed out by	 */
 /* Descr1 when the DMA has filled in Descr2. Otherwise we will discard	 */
 /* the rest of the data pointed out by Descr1 and set readp to the start */
-/* of Descr2								 */
+/* of Descr2                                                             */
 
 #define SYNC_SERIAL_MAJOR 125
 
-#define IN_BUFFER_SIZE 8192
+/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */
+/* words can be handled */
+
+#define IN_BUFFER_SIZE 12288
 #define OUT_BUFFER_SIZE 4096
 
+#define DEFAULT_FRAME_RATE 0
+#define DEFAULT_WORD_RATE 7
+
 #define DEBUG(x) 
 
-/* Define some macros to access Etrax 100 registers */
+/* Define some macros to access ETRAX 100 registers */
 #define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
 					  IO_FIELD(##reg##, field, val)
 #define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \
@@ -81,10 +88,8 @@
 	char data_avail_bit; /* In R_IRQ_MASK1_RD */
 	char transmitter_ready_bit; /* In R_IRQ_MASK1_RD */
 	char ready_irq_bit; /* In R_IRQ_MASK1_SET and R_IRQ_MASK1_CLR */
-	char input_dma_eop_bit;   /* In R_IRQ_MASK2_RD */
 	char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */
 	char output_dma_bit; /* In R_IRQ_MASK2_RD */
-	char eop_bit; /* In R_SET_EOP */
 
 	int enabled;  /* 1 if port is enabled */
 	int use_dma;  /* 1 if port uses dma */
@@ -125,7 +130,6 @@
 static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs);
 static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs);
 static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs);
-static void flush_handler(void);
 
 /* The ports */
 static struct sync_port ports[]=
@@ -133,40 +137,36 @@
 	{
 		R_SYNC_SERIAL1_STATUS,  /* status */
 		R_SYNC_SERIAL1_CTRL,    /* ctrl_data */
-		R_DMA_CH8_FIRST,	    /* output_dma_first */
-		R_DMA_CH8_CMD,	    /* output_dma_cmd */
-		R_DMA_CH8_CLR_INTR,	    /* output_dma_clr_irq */
-		R_DMA_CH9_FIRST,	    /* input_dma_first */
-		R_DMA_CH9_CMD,	    /* input_dma_cmd */
-		R_DMA_CH9_CLR_INTR,	    /* input_dma_clr_irq */
+		R_DMA_CH8_FIRST,        /* output_dma_first */
+		R_DMA_CH8_CMD,          /* output_dma_cmd */
+		R_DMA_CH8_CLR_INTR,     /* output_dma_clr_irq */
+		R_DMA_CH9_FIRST,        /* input_dma_first */
+		R_DMA_CH9_CMD,          /* input_dma_cmd */
+		R_DMA_CH9_CLR_INTR,     /* input_dma_clr_irq */
 		R_SYNC_SERIAL1_TR_DATA, /* data_out */
 		R_SYNC_SERIAL1_REC_DATA,/* data in */
 		IO_BITNR(R_IRQ_MASK1_RD, ser1_data),   /* data_avail_bit */
 		IO_BITNR(R_IRQ_MASK1_RD, ser1_ready),  /* transmitter_ready_bit */
 		IO_BITNR(R_IRQ_MASK1_SET, ser1_ready), /* ready_irq_bit */
-		IO_BITNR(R_IRQ_MASK2_RD, dma9_eop),	   /* input_dma_eop_bit */
 		IO_BITNR(R_IRQ_MASK2_RD, dma9_descr),  /* input_dma_descr_bit */
-		IO_BITNR(R_IRQ_MASK2_RD, dma8_eop),	   /* output_dma_bit */
-		IO_BITNR(R_SET_EOP, ch9_eop)	   /* eop_bit */
+		IO_BITNR(R_IRQ_MASK2_RD, dma8_eop),    /* output_dma_bit */
 	},
 	{
 		R_SYNC_SERIAL3_STATUS,  /* status */
 		R_SYNC_SERIAL3_CTRL,    /* ctrl_data */
-		R_DMA_CH4_FIRST,	    /* output_dma_first */
-		R_DMA_CH4_CMD,	    /* output_dma_cmd */
-		R_DMA_CH4_CLR_INTR,	    /* output_dma_clr_irq */
-		R_DMA_CH5_FIRST,	    /* input_dma_first */
-		R_DMA_CH5_CMD,	    /* input_dma_cmd */
-		R_DMA_CH5_CLR_INTR,	    /* input_dma_clr_irq */
+		R_DMA_CH4_FIRST,        /* output_dma_first */
+		R_DMA_CH4_CMD,          /* output_dma_cmd */
+		R_DMA_CH4_CLR_INTR,     /* output_dma_clr_irq */
+		R_DMA_CH5_FIRST,        /* input_dma_first */
+		R_DMA_CH5_CMD,          /* input_dma_cmd */
+		R_DMA_CH5_CLR_INTR,     /* input_dma_clr_irq */
 		R_SYNC_SERIAL3_TR_DATA, /* data_out */
 		R_SYNC_SERIAL3_REC_DATA,/* data in */
 		IO_BITNR(R_IRQ_MASK1_RD, ser3_data),   /* data_avail_bit */
 		IO_BITNR(R_IRQ_MASK1_RD, ser3_ready),  /* transmitter_ready_bit */
 		IO_BITNR(R_IRQ_MASK1_SET, ser3_ready), /* ready_irq_bit */
-		IO_BITNR(R_IRQ_MASK2_RD, dma5_eop),	   /* input_dma_eop_bit */
-		IO_BITNR(R_IRQ_MASK2_RD, dma5_descr),  /* input_dma_eop_bit */
-		IO_BITNR(R_IRQ_MASK2_RD, dma4_eop),	   /* output_dma_bit */
-		IO_BITNR(R_SET_EOP, ch5_eop)	   /* eop_bit */
+		IO_BITNR(R_IRQ_MASK2_RD, dma5_descr),  /* input_dma_descr_bit */
+		IO_BITNR(R_IRQ_MASK2_RD, dma4_eop),    /* output_dma_bit */
 	}
 };
 
@@ -174,9 +174,6 @@
 static unsigned sync_serial_prescale_shadow = 0;
 static unsigned gen_config_ii_shadow = 0;
 
-/* Timer used to flush data from the DMA */
-static struct timer_list flush_timer;
-
 #define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port))
 
 static struct file_operations sync_serial_fops = {
@@ -213,24 +210,25 @@
 #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)
 	ports[0].use_dma = 1;
 	initialize_port(0);
-	if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", NULL))
+	if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", &ports[0]))
 		 panic("Can't allocate sync serial port 1 IRQ");
-	if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", NULL))
+	if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", &ports[0]))
 		panic("Can't allocate sync serial port 1 IRQ");
 	RESET_DMA(8); WAIT_DMA(8);
 	RESET_DMA(9); WAIT_DMA(9);
-	*R_DMA_CH8_CLR_INTR = 3;  /* Clear IRQ */
-	*R_DMA_CH9_CLR_INTR = 3;  /* Clear IRQ */
+	*R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) |
+	  IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); 
+	*R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do) |
+	  IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) |
 	  IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) |
-          IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | 
           IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set);
 	start_dma_in(&ports[0]);
 #else
 	ports[0].use_dma = 0;
 	initialize_port(0);
-	if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL))
+	if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[0]))
 		panic("Can't allocate sync serial manual irq");
 	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set);	 
 #endif
@@ -243,18 +241,19 @@
 #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)
 	ports[1].use_dma = 1;
 	initialize_port(1);
-	if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", NULL))
+	if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", &ports[1]))
 		panic("Can't allocate sync serial port 1 IRQ");
-	if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", NULL))
+	if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", &ports[1]))
 		panic("Can't allocate sync serial port 1 IRQ");
 	RESET_DMA(4); WAIT_DMA(4);
 	RESET_DMA(5); WAIT_DMA(5);
-	*R_DMA_CH4_CLR_INTR = 3;  /* Clear IRQ */
-	*R_DMA_CH5_CLR_INTR = 3;  /* Clear IRQ */
+	*R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) |
+	  IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); 
+	*R_DMA_CH5_CLR_INTR = IO_STATE(R_DMA_CH5_CLR_INTR, clr_eop, do) |
+	  IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); 
 	*R_IRQ_MASK2_SET =
 	  IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) |
 	  IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) |
-	  IO_STATE(R_IRQ_MASK2_SET, dma5_eop, set) | 
 	  IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set);
 	start_dma_in(&ports[1]);
 #else
@@ -262,7 +261,7 @@
 	initialize_port(1);
 	if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */
 	{
-		if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", NULL))
+		if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[1]))
 			panic("Can't allocate sync serial manual irq");
 	}
 	*R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set);	 
@@ -278,22 +277,14 @@
 	  IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec) | 
 	  IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u3, external) | 
 	  IO_STATE(R_SYNC_SERIAL_PRESCALE, prescaler, div4) | 
-	  IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, 0) | 
-	  IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, 7) | 
+	  IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, DEFAULT_FRAME_RATE) | 
+	  IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, DEFAULT_WORD_RATE) | 
 	  IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal));
 
 	/* Select synchronous ports */
 	*R_GEN_CONFIG_II = gen_config_ii_shadow;
 
-	/*Initialize DMA flush timer if dma is used */
-	if (ports[0].use_dma || ports[1].use_dma) 
-	{
-		init_timer(&flush_timer);
-		flush_timer.function = flush_handler;
-		mod_timer(&flush_timer, jiffies + 10);
-	}
-
-	printk("Etrax100LX synchronous serial port driver\n");
+	printk("ETRAX 100LX synchronous serial port driver\n");
 	return 0;
 }
 
@@ -321,9 +312,9 @@
 	  IO_STATE(R_SYNC_SERIAL1_CTRL, f_syncsize, word)    |
 	  IO_STATE(R_SYNC_SERIAL1_CTRL, f_sync, on)	     |
 	  IO_STATE(R_SYNC_SERIAL1_CTRL, clk_mode, normal)    |
-	  IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, running)   |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, stopped)   |
 	  IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb)	     |
-	  IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, enable)   |
+	  IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, disable)  |
 	  IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit)  |
 	  IO_STATE(R_SYNC_SERIAL1_CTRL, buf_empty, lmt_8)    |
 	  IO_STATE(R_SYNC_SERIAL1_CTRL, buf_full, lmt_8)     |
@@ -365,27 +356,43 @@
 
 static int sync_serial_release(struct inode *inode, struct file *file)
 {
-	ports[MINOR(inode->i_rdev)].busy = 0;
+	int dev = MINOR(inode->i_rdev);
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	{
+		DEBUG(printk("Invalid minor %d\n", dev));
+		return -ENODEV;
+	}
+	ports[dev].busy = 0;
 	return 0;
 }
 
 static int sync_serial_ioctl(struct inode *inode, struct file *file,
 		  unsigned int cmd, unsigned long arg)
 {
+	int return_val = 0;
 	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
-	sync_port* port = &ports[dev];
+  sync_port* port;
+        
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	{
+		DEBUG(printk("Invalid minor %d\n", dev));
+		return -1;
+	}
+        port = &ports[dev];
 
 	/* Disable port while changing config */
 	if (dev)
 	{
 		RESET_DMA(4); WAIT_DMA(4);
-		*R_DMA_CH4_CLR_INTR = 3;  
+		*R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) |
+                  IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); 
 		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async);
 	}
 	else
 	{
 		RESET_DMA(8); WAIT_DMA(8);
-		*R_DMA_CH8_CLR_INTR = 3;  
+		*R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) |
+                  IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do);  
 		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async);
 	}
 	*R_GEN_CONFIG_II = gen_config_ii_shadow;
@@ -516,7 +523,7 @@
 			}
 			break;
 		default:
-			return -EINVAL;
+			return_val = -1;
 	}
 	/* Set config and enable port */
 	*port->ctrl_data = port->ctrl_data_shadow;
@@ -527,15 +534,23 @@
 		SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync);
 
 	*R_GEN_CONFIG_II = gen_config_ii_shadow;
-	return 0;
+	return return_val;
 }
 
 static ssize_t sync_serial_manual_write(struct file * file, const char * buf, 
                                         size_t count, loff_t *ppos)
 {
+	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
 	DECLARE_WAITQUEUE(wait, current);
-	sync_port* port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)];
+	sync_port* port;
 
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	{
+		DEBUG(printk("Invalid minor %d\n", dev));
+		return -ENODEV;
+	}
+
+	port = &ports[dev];
 	copy_from_user(port->out_buffer, buf, count);
 	port->outp = port->out_buffer;
 	port->out_count = count;
@@ -547,17 +562,36 @@
 	schedule();
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->out_wait_q, &wait);
+	if (signal_pending(current))
+	{
+		return -EINTR;
+	}
 	return count;
 }
 
 static ssize_t sync_serial_write(struct file * file, const char * buf, 
                                  size_t count, loff_t *ppos)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)];
+	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+	DECLARE_WAITQUEUE(wait, current);	
+	sync_port *port;
+
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	{
+		DEBUG(printk("Invalid minor %d\n", dev));
+		return -ENODEV;
+	}
+	port = &ports[dev];
 
 	DEBUG(printk("Write dev %d count %d\n", port->port_nbr, count));
 
+	count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count;
+
+	/* Make sure transmitter is running */
+	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable);
+	*port->ctrl_data = port->ctrl_data_shadow;
+
 	if (!port->use_dma)
 	{
 		return sync_serial_manual_write(file, buf, count, ppos); 
@@ -570,26 +604,47 @@
 	schedule();
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&port->out_wait_q, &wait);
+	if (signal_pending(current))
+	{
+		return -EINTR;
+	}
 	return count;
 }
 
 static ssize_t sync_serial_read(struct file * file, char * buf, 
 				size_t count, loff_t *ppos)
 {
+	int dev = MINOR(file->f_dentry->d_inode->i_rdev);
 	int avail;
-	sync_port *port = &ports[MINOR(file->f_dentry->d_inode->i_rdev)];
+	sync_port *port;
 	char* start; 
 	char* end;
 	unsigned long flags;	
 
-	DEBUG(printk("Read dev %d count\n"));
+	if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled)
+	{
+		DEBUG(printk("Invalid minor %d\n", dev));
+		return -ENODEV;
+	}
+	port = &ports[dev];
+
+	DEBUG(printk("Read dev %d count %d\n", dev, count));
+
+	/* Make sure receiver is running */
+	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running);
+	SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable);
+	*port->ctrl_data = port->ctrl_data_shadow;
 
 	/* Calculate number of available bytes */
 	while (port->readp == port->writep) /* No data */
 	{
 		if (file->f_flags & O_NONBLOCK)
 			return -EAGAIN;
-			interruptible_sleep_on(&port->in_wait_q);
+		interruptible_sleep_on(&port->in_wait_q);
+		if (signal_pending(current))
+		{
+			return -EINTR;
+		}
 	}
 	
 	/* Save pointers to avoid that they are modified by interrupt */
@@ -673,12 +728,12 @@
 		return;
 	}
 	port->in_descr1.hw_len = 0;
-	port->in_descr1.ctrl = d_eop | d_int;
+	port->in_descr1.ctrl = d_int;
 	port->in_descr1.status = 0;
 	port->in_descr1.next = virt_to_phys(&port->in_descr2);
 	port->in_descr2.hw_len = 0;
 	port->in_descr2.next = virt_to_phys(&port->in_descr1);
-	port->in_descr2.ctrl = d_eop | d_int;
+	port->in_descr2.ctrl = d_int;
 	port->in_descr2.status = 0;
 
 	/* Find out which descriptor to start */
@@ -766,22 +821,6 @@
 			start_dma_in(port);
 			wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */
 		}
-		else if (ireg & (1 << port->input_dma_eop_bit)) /* EOP interrupt */
-		{
-			/* EOP interrupt means that DMA has not reached end of descriptor */
-			*port->input_dma_clr_irq = 
-			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | 
-			  IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do);
-
-			/* Find out the current descriptor */
-			if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2)
-				port->writep += port->in_descr2.hw_len;
-			else
-				port->writep += port->in_descr1.hw_len;
-
-			start_dma_in(port);
-			wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */
-		}
 	}
 }
 
@@ -853,21 +892,6 @@
 			}
 		}
 	}
-}
-
-static void flush_handler(void)
-{
-	int i;
-	
-	for (i = 0; i < NUMBER_OF_PORTS; i++)
-	{
-		if (ports[i].enabled)
-		{
-			*R_SET_EOP = 1 << ports[i].eop_bit;  
-		}
-	}
-	/* restart flush timer */
-	mod_timer(&flush_timer, jiffies + 10);
 }
 
 module_init(etrax_sync_serial_init);
diff -u --recursive --new-file v2.4.4/linux/arch/cris/drivers/usb-host.c linux/arch/cris/drivers/usb-host.c
--- v2.4.4/linux/arch/cris/drivers/usb-host.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/drivers/usb-host.c	Tue May  1 16:04:56 2001
@@ -623,7 +623,7 @@
 
 				traffic_ep->nep = tmp_ep->nep;
 				tmp_ep->nep = virt_to_phys(traffic_ep);
-				dbg_intr("One ep successfully inserted");
+				dbg_intr("One ep sucessfully inserted");
 			}
 			i++;
 		}
@@ -1804,7 +1804,7 @@
 						r_usb_ept_data);
 			
 			if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) {
-				/* no_error means that this urb was successfully sent or that we have
+				/* no_error means that this urb was sucessfully sent or that we have
 				   some undefinde error*/
 				
 				if (IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3 ||
@@ -1888,9 +1888,9 @@
 						/*
 						  This means that the endpoint has no error, is disabled
 						  and had inserted traffic,
-						  i.e. transfer successfully completed
+						  i.e. transfer sucessfully completed
 						*/
-						dbg_ctrl("Last SB for CTRL %d sent successfully", epid);
+						dbg_ctrl("Last SB for CTRL %d sent sucessfully", epid);
 						handle_control_transfer_attn(epid, 0);
 					}
 				}
@@ -1905,9 +1905,9 @@
 						/*
 						  This means that the endpoint has no error, is disabled
 						  and had inserted traffic,
-						  i.e. transfer successfully completed
+						  i.e. transfer sucessfully completed
 						*/
-						dbg_bulk("Last SB for BULK %d sent successfully", epid);
+						dbg_bulk("Last SB for BULK %d sent sucessfully", epid);
 						handle_bulk_transfer_attn(epid, 0);
 					}
 				}
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile
--- v2.4.4/linux/arch/cris/kernel/Makefile	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/Makefile	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.3 2001/01/10 21:11:07 bjornw Exp $
+# $Id: Makefile,v 1.4 2001/04/17 13:58:39 orjanf Exp $
 #
 # Makefile for the linux kernel.
 #
@@ -18,7 +18,7 @@
            ptrace.o setup.o time.o sys_cris.o shadows.o \
 	   debugport.o semaphore.o
 
-obj-$(CONFIG_KGDB) += kgdb.o
+obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
 
 clean:
 
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/debugport.c linux/arch/cris/kernel/debugport.c
--- v2.4.4/linux/arch/cris/kernel/debugport.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/debugport.c	Tue May  1 16:04:56 2001
@@ -12,6 +12,12 @@
  *    init_etrax_debug()
  *
  * $Log: debugport.c,v $
+ * Revision 1.6  2001/04/17 13:58:39  orjanf
+ * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+ *
+ * Revision 1.5  2001/03/26 14:22:05  bjornw
+ * Namechange of some config options
+ *
  * Revision 1.4  2000/10/06 12:37:26  bjornw
  * Use physical addresses when talking to DMA
  *
@@ -29,7 +35,7 @@
 
 /* Which serial-port is our debug port ? */
 
-#if defined(CONFIG_DEBUG_PORT0) || defined(CONFIG_DEBUG_PORT_NULL)
+#if defined(CONFIG_ETRAX_DEBUG_PORT0) || defined(CONFIG_ETRAX_DEBUG_PORT_NULL)
 #define DEBUG_PORT_IDX 0
 #define DEBUG_OCMD R_DMA_CH6_CMD
 #define DEBUG_FIRST R_DMA_CH6_FIRST
@@ -43,7 +49,7 @@
 #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma6_descr, clr)
 #endif
 
-#ifdef CONFIG_DEBUG_PORT1
+#ifdef CONFIG_ETRAX_DEBUG_PORT1
 #define DEBUG_PORT_IDX 1
 #define DEBUG_OCMD R_DMA_CH8_CMD
 #define DEBUG_FIRST R_DMA_CH8_FIRST
@@ -57,7 +63,7 @@
 #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma8_descr, clr)
 #endif
 
-#ifdef CONFIG_DEBUG_PORT2
+#ifdef CONFIG_ETRAX_DEBUG_PORT2
 #define DEBUG_PORT_IDX 2
 #define DEBUG_OCMD R_DMA_CH2_CMD
 #define DEBUG_FIRST R_DMA_CH2_FIRST
@@ -71,7 +77,7 @@
 #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma2_descr, clr)
 #endif
 
-#ifdef CONFIG_DEBUG_PORT3
+#ifdef CONFIG_ETRAX_DEBUG_PORT3
 #define DEBUG_PORT_IDX 3
 #define DEBUG_OCMD R_DMA_CH4_CMD
 #define DEBUG_FIRST R_DMA_CH4_FIRST
@@ -97,7 +103,7 @@
 	unsigned long flags; 
 	int in_progress;
 	
-#ifdef CONFIG_DEBUG_PORT_NULL
+#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
         /* no debug printout at all */
         return;
 #endif
@@ -111,7 +117,7 @@
 	save_flags(flags);
 	cli();
 
-#ifdef CONFIG_KGDB
+#ifdef CONFIG_ETRAX_KGDB
 	/* kgdb needs to output debug info using the gdb protocol */
 	putDebugString(buf, len);
 	restore_flags(flags);
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S
--- v2.4.4/linux/arch/cris/kernel/entry.S	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/kernel/entry.S	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.15 2001/03/05 13:14:30 bjornw Exp $
+/* $Id: entry.S,v 1.22 2001/04/17 13:58:39 orjanf Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,40 @@
  *  Authors:	Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.22  2001/04/17 13:58:39  orjanf
+ *  * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+ *
+ *  Revision 1.21  2001/04/17 11:33:29  orjanf
+ *  Updated according to review:
+ *  * Included asm/sv_addr_ag.h to get macro for internal register.
+ *  * Corrected comment regarding system call argument passing.
+ *  * Removed comment about instruction being in a delay slot.
+ *  * Added comment about SYMBOL_NAME macro.
+ *
+ *  Revision 1.20  2001/04/12 08:51:07  hp
+ *  - Add entry for sys_fcntl64.  In fact copy last piece from i386 including ...
+ *  - .rept to fill table to safe state with sys_ni_syscall.
+ *
+ *  Revision 1.19  2001/04/04 09:43:32  orjanf
+ *  * Moved do_sigtrap from traps.c to entry.S.
+ *  * LTASK_PID need not be global anymore.
+ *
+ *  Revision 1.18  2001/03/26 09:25:02  markusl
+ *  Updated after review, should now handle USB interrupts correctly.
+ *
+ *  Revision 1.17  2001/03/21 16:12:55  bjornw
+ *  * Always make room for the cpu status record in the frame, in order to
+ *    use the same framelength and layout for both mmu busfaults and normal
+ *    irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore.
+ *  * Fixed bug with using addq for popping the stack in the epilogue - it
+ *    destroyed the flag register. Use instructions that don't affect the
+ *    flag register instead.
+ *  * Removed write to R_PORT_PA_DATA during spurious_interrupt
+ *
+ *  Revision 1.16  2001/03/20 19:43:02  bjornw
+ *  * Get rid of esp0 setting
+ *  * Give a 7th argument to a systemcall - the stackframe
+ *
  *  Revision 1.15  2001/03/05 13:14:30  bjornw
  *  Spelling fix
  *
@@ -80,7 +114,8 @@
 
 #include <linux/linkage.h>
 #include <linux/sys.h>
-			
+#include <asm/sv_addr_ag.h>
+	
 	;; functions exported from this file
 	
 	.globl _system_call
@@ -95,10 +130,11 @@
 	.globl _spurious_interrupt
 	.globl _hw_bp_trigs
 	.globl _mmu_bus_fault
-				
+	.globl _do_sigtrap
+	.globl _gdb_handle_breakpoint
+			
 	.globl _sys_call_table
 	
-	.globl LTASK_PID	
 	;; syscall error codes
 	
 LENOSYS = 38
@@ -115,11 +151,6 @@
 
 PT_TRACESYS_BIT	  = 1
 
-	;; Offset for esp0 into task_struct: current->thread.esp0.
-	;; FIXME: In need of padding somewhere, to get dword-alignment.
-
-THREAD_ESP0	  = 597
-	
 	;; some pt_regs offsets (from ptrace.h)
 	
 LORIG_R10	= 4
@@ -182,7 +213,7 @@
 	;; Since we can't have system calls inside interrupts, it should not matter
 	;; that we don't stack IRP.
 	;; 
-	;; In r1 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,r0
+	;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp
 	;;
 	;; This function looks on the _surface_ like spaghetti programming, but it's
 	;; really designed so that the fast-path does not force cache-loading of non-used
@@ -190,7 +221,7 @@
 
 _system_call:
 	;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call
-	push	brp		; this is normally push irp
+	move	brp,[sp=sp-16]	; instruction pointer and room for a fake SBFS frame
 	push	srp
 	push	dccr
 	push	mof
@@ -202,15 +233,11 @@
 	movs.w	-LENOSYS,r0
 	move.d	r0,[sp+LR10]	; put the default return value in r10 in the frame
 
-	;; Perform "current->thread.esp0 = sp".
-	;; This used to be a separate function; set_esp0(ssp).
-	movs.w -8192,r0		; THREAD_SIZE == 8192
-	and.d sp,r0
-
-	move.d sp,[r0+THREAD_ESP0]
-
 	;; check if this process is syscall-traced
 
+	movs.w	-8192,r0	; THREAD_SIZE == 8192
+	and.d	sp,r0
+	
 	move.d	[r0+LTASK_PTRACE],r0
 	btstq	PT_TRACESYS_BIT, r0
 	bmi	tracesys
@@ -222,6 +249,11 @@
 	bcc	_ret_from_sys_call
 	lslq	2,r9		;  multiply by 4, in the delay slot
 
+	;; as a bonus 7th parameter, we give the location on the stack
+	;; of the register structure itself. some syscalls need this.
+
+	push	sp
+	
 	;; the parameter carrying registers r10, r11, r12 and 13 are intact.
 	;; the fifth and sixth parameters (if any) was in mof and srp 
 	;; respectively, and we need to put them on the stack.
@@ -230,8 +262,8 @@
 	push	mof
 	
 	jsr	[r9+_sys_call_table]	; actually do the system call
-	addq	2*4,sp		; pop the mof and srp parameters
-	move.d	r10,[sp+LR10]	; save the return value
+	addq	3*4,sp			; pop the mof, srp and regs parameters
+	move.d	r10,[sp+LR10]		; save the return value
 
 	moveq	1,r9		; "parameter" to ret_from_sys_call to show it was a sys call
 	
@@ -274,31 +306,20 @@
 	pop	mof		; multiply overflow register 
 	pop	dccr		; condition codes
 	pop	srp		; subroutine return pointer
-	jmpu	[sp+]		; return by popping irp and jumping there
-	;; jmpu takes the U-flag into account to see if we return to
-	;; user-mode or kernel mode.
+	;; now we have a 4-word SBFS frame which we do not want to restore
+	;; using RBF since it was not stacked with SBFS. instead we would like to
+	;; just get the PC value to restart it with, and skip the rest of
+	;; the frame.
+	move	[sp=sp+16], p8	; pop the SBFS frame from the sp
+	jmpu	[sp-16]		; return through the irp field in the sbfs frame
 
 RBFexit:
-	cmpq	2, r10		; was it CRIS_FRAME_FIXUP ?
-	beq	2f
 	movem	[sp+],r13	; registers r0-r13, in delay slot
 	pop	mof		; multiply overflow register 
 	pop	dccr		; condition codes
 	pop	srp		; subroutine return pointer
 	rbf	[sp+]		; return by popping the CPU status
 
-2:	pop	mof		; multiply overflow register
-	pop	dccr		; condition codes
-	pop	srp		; subroutine return pointer
-	;; now we have a 4-word SBFS frame which we do not want to restore
-	;; using RBF since we have made a fixup. instead we would like to
-	;; just get the PC value to restart it with, and skip the rest of
-	;; the frame.
-	pop	irp		; fixup location will be here
-	reti			; return to IRP, taking U-flag into account
-	addq	12,sp		; Skip rest of SBFS frame.
-
-
 tracesys:
 	;; this first invocation of syscall_trace _requires_ that
 	;; LR10 in the frame contains -LENOSYS (as is set in the beginning
@@ -332,13 +353,19 @@
 	move	[sp+LMOF],      mof
 	move	[sp+LSRP],      srp
 
+	;; as a bonus 7th parameter, we give the location on the stack
+	;; of the register structure itself. some syscalls need this.
+
+	push	sp
+	
 	;; the fifth and sixth parameters needs to be put on the stack for
 	;; the system call to find them
 
 	push	srp
 	push	mof
+
 	jsr	r9		; actually call the system-call
-	addq	2*4,sp		; pop the r0 parameter
+	addq	3*4,sp		; pop the srp, mof and regs parameters
 
 1:	move.d	r10,[sp+LR10]	; save the return value
 
@@ -354,8 +381,7 @@
 	
 LTHREAD_KSP	= 0
 LTHREAD_USP	= 4
-LTHREAD_ESP0	= 8
-LTHREAD_DCCR	= 12
+LTHREAD_DCCR	= 8
 	
 	;; _resume performs the actual task-switching, by switching stack pointers
 	;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct
@@ -468,8 +494,6 @@
 _IRQ1_interrupt:
 _spurious_interrupt:	
 	di
-	move.b	4,r0
-	move.b	r0,[0xb0000030]
 basse2:	ba	basse2
 	nop
 
@@ -479,7 +503,7 @@
 	
 _multiple_interrupt:
 	;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
-	push	irp
+	move	irp,[sp=sp-16]	; instruction pointer and room for a fake SBFS frame
 	push	srp
 	push	dccr
 	push	mof
@@ -491,15 +515,15 @@
 	
 	move.d	_irq_shortcuts + 8,r1
 	moveq	2,r2		; first bit we care about is the timer0 irq
-	move.d	[0xb00000d8],r0	; read the irq bits that triggered the multiple irq
+	move.d	[R_VECT_MASK_RD],r0	; read the irq bits that triggered the multiple irq
 multloop:	
 	btst	r2,r0		; check for the irq given by bit r2
 	bmi	do_shortcut	; actually do the shortcut
 	nop
-	addq	1,r2		; next vector bit - remember this is in the delay slot!
+	addq	1,r2		; next vector bit
 	addq	4,r1		; next vector
-	cmpq	26,r2
-	bne	multloop	; process all irq's up to and including number 25
+	cmp.b	32,r2
+	bne	multloop	; process all irq's up to and including number 31
 	nop
 	
 	;; strange, we didn't get any set vector bits.. oh well, just return
@@ -513,6 +537,48 @@
 	nop
 	jump	[r1]		; jump to the irq handlers shortcut
 
+_do_sigtrap:
+	;; 
+	;; SIGTRAP the process that executed the break instruction.
+	;; Make a frame that Rexit in entry.S expects.
+	;;
+	move	brp,[sp=sp-16]		; Push BRP while faking a cpu status record.
+	push	srp			; Push subroutine return pointer.
+	push	dccr			; Push condition codes.
+	push	mof			; Push multiply overflow reg.
+	di				; Need to disable irq's at this point.
+	subq	14*4,sp			; Make room for r0-r13.
+	movem	r13,[sp]		; Push the r0-r13 registers.
+	push	r10			; Push orig_r10.
+	clear.d	[sp=sp-4]		; Frametype - this is a normal stackframe.
+
+	movs.w	-8192,r9		; THREAD_SIZE == 8192
+	and.d	sp,r9
+	move.d	[r9+LTASK_PID],r10	; current->pid as arg1.
+	moveq	5,r11			; SIGTRAP as arg2.
+	jsr	_sys_kill       
+	jump	_ret_from_intr		; Use the return routine for interrupts.
+
+_gdb_handle_breakpoint:	
+	push	dccr
+	push	r0
+#ifdef CONFIG_ETRAX_KGDB
+	move	dccr,r0			; U-flag not affected by previous insns. 
+	btstq	8,r0			; Test the U-flag.
+	bmi	_ugdb_handle_breakpoint	; Go to user mode debugging. 
+	nop				; Empty delay slot (cannot pop r0 here). 
+	pop	r0			; Restore r0.
+	ba	_kgdb_handle_breakpoint	; Go to kernel debugging. 
+	pop	dccr			; Restore dccr in delay slot.
+#endif
+	
+_ugdb_handle_breakpoint:	
+	move	brp,r0			; Use r0 temporarily for calculation.
+	subq	2,r0			; Set to address of previous instruction.
+	move	r0,brp
+	pop	r0			; Restore r0. 
+	ba	_do_sigtrap		; SIGTRAP the offending process. 
+	pop	dccr			; Restore dccr in delay slot.
 	
 	.data
 
@@ -521,8 +587,11 @@
 _hw_bp_trig_ptr:
 	.dword _hw_bp_trigs
 
-/* linux/linkage.h got it wrong for this compiler currently */
-	
+/* Because we compile this file with -traditional, we need to redefine
+   token-concatenation to the traditional trick, using an empty comment.
+   Normally (in other files, with ISO C as in gcc default) this is done
+   with the ## preprocessor operator.  */
+
 #undef SYMBOL_NAME
 #define SYMBOL_NAME(X) _/**/X
 		
@@ -748,6 +817,8 @@
 	.long SYMBOL_NAME(sys_mincore)
 	.long SYMBOL_NAME(sys_madvise)
 	.long SYMBOL_NAME(sys_getdents64)       /* 220 */
+	.long SYMBOL_NAME(sys_fcntl64)
+	.long SYMBOL_NAME(sys_ni_syscall)	/* reserved for TUX */
 
         /*
          * NOTE!! This doesn't have to be exact - we just have
@@ -756,9 +827,7 @@
          * been shrunk every time we add a new system call.
          */
 
-	;; TODO: this needs to actually generate sys_ni_syscall entires
-	;; since we now have removed the check for NULL entries in this
-	;; table in system_call!
-	
-	.space (NR_syscalls-220)*4
+	.rept NR_syscalls-221
+		.long SYMBOL_NAME(sys_ni_syscall)
+	.endr
 	
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S
--- v2.4.4/linux/arch/cris/kernel/head.S	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/kernel/head.S	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.20 2001/02/23 12:47:56 bjornw Exp $
+/* $Id: head.S,v 1.29 2001/04/18 12:51:59 orjanf Exp $
  * 
  * Head of the kernel - alter with care
  *
@@ -7,6 +7,40 @@
  * Authors:	Bjorn Wesen (bjornw@axis.com)
  * 
  * $Log: head.S,v $
+ * Revision 1.29  2001/04/18 12:51:59  orjanf
+ * * Reverted review change regarding the use of bcs/bcc.
+ * * Removed non-working LED-clearing code.
+ *
+ * Revision 1.28  2001/04/17 13:58:39  orjanf
+ * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+ *
+ * Revision 1.27  2001/04/17 11:42:35  orjanf
+ * Changed according to review:
+ * * Added comment explaining memory map bug.
+ * * Changed bcs and bcc to blo and bhs, respectively.
+ * * Removed mentioning of Stallone and Olga boards.
+ *
+ * Revision 1.26  2001/04/06 12:31:07  jonashg
+ * Check for cramfs in flash before RAM instead of RAM before flash.
+ *
+ * Revision 1.25  2001/04/04 06:23:53  starvik
+ * Initialize DRAM if not already initialized
+ *
+ * Revision 1.24  2001/04/03 11:12:00  starvik
+ * Removed dram init (done by rescue or etrax100boot
+ * Corrected include
+ *
+ * Revision 1.23  2001/04/03 09:53:03  starvik
+ * Include hw_settings.S
+ *
+ * Revision 1.22  2001/03/26 14:23:26  bjornw
+ * Namechange of some config options
+ *
+ * Revision 1.21  2001/03/08 12:14:41  bjornw
+ * * Config name for ETRAX IDE was renamed
+ * * Removed G27 auto-setting when JULIETTE is chosen (need to make this
+ *   a new config option later)
+ *
  * Revision 1.20  2001/02/23 12:47:56  bjornw
  * MMU regs during LOW_MAP updated to reflect a newer reality
  *
@@ -76,7 +110,8 @@
 #include <asm/sv_addr_ag.h>
 
 #define CRAMFS_MAGIC 0x28cd3d45
-	
+#define RAM_INIT_MAGIC 0x56902387
+		
 	;; exported symbols
 		
 	.globl	_etrax_irv
@@ -92,9 +127,9 @@
 	;; since etrax actually starts at address 2 when booting from flash, we
 	;; put a nop (2 bytes) here first so we dont accidentally skip the di
 	;;
-	;; NOTICE! The register r9 is used as a parameter carrying register from
-	;; the decompressor (if the kernel was compressed). It should not be
-	;; used in the code below until it is read.
+	;; NOTICE! The registers r8 and r9 are used as a parameter carrying
+	;; information from the decompressor (if the kernel was compressed). 
+	;; They should not be used in the code below until it is read.
 	
 	nop	
 	di
@@ -109,6 +144,7 @@
 	;;
 	;; Due to a bug in Etrax-100 LX version 1 we need to map the memory
 	;; slightly different. We also let the simulator get this mapping for now.
+	;; (The bug is that you can't remap bit 31.)
 
 #ifdef CONFIG_CRIS_LOW_MAP
 	move.d	0x0004b098, r0	; kseg mappings, temporary map of 0xc0->0x40
@@ -161,8 +197,14 @@
 	
 inflash:
 	;; We need to initialze DRAM registers before we start using the DRAM
-#include "../lib/dram_init.S"	
 
+	cmp.d	RAM_INIT_MAGIC, r8	; Already initialized?
+	beq	dram_init_finished
+	nop
+	
+#include "../lib/dram_init.S"
+
+dram_init_finished:		
 	;; Copy text+data to DRAM
 	;; This is fragile - the calculation of r4 as the image size depends
 	;; on that the labels below actually are the first and last positions
@@ -218,7 +260,39 @@
 	moveq	0, r0
 	move.d	r0, [_romfs_length] ; default if there is no cramfs
 	
-	;; First check if there is a cramfs (magic value)
+	;; The kernel could have been unpacked to DRAM by the loader, but
+	;; the cramfs image could still be in the Flash directly after the
+	;; compressed kernel image. The loader passes the address of the
+	;; byte succeeding the last compressed byte in the flash in the
+	;; register r9 when starting the kernel. Check if r9 points to a
+	;; decent cramfs image!
+	;; (Notice that if this is not booted from the loader, r9 will be
+	;;  garbage but we do sanity checks on it, the chance that it points
+	;;  to a cramfs magic is small.. )
+	
+	cmp.d	0x0ffffff8, r9
+	bcc	no_romfs_in_flash	; r9 points outside the flash area
+	nop
+	move.d	[r9], r0	; cramfs_super.magic
+	cmp.d	CRAMFS_MAGIC, r0
+	bne	no_romfs_in_flash
+	nop
+	move.d	[r9+4], r0	; cramfs_super.length
+	move.d	r0, [_romfs_length]
+#ifdef CONFIG_CRIS_LOW_MAP
+	add.d   0x50000000, r9	; add flash start in virtual memory (cached)
+#else
+	add.d   0xf0000000, r9	; add flash start in virtual memory (cached)
+#endif
+	move.d	r9, [_romfs_start]
+
+	moveq	1, r0
+	move.d	r0, [_romfs_in_flash]
+	
+	jump	start_it	; enter code, cached this time
+
+no_romfs_in_flash:
+	;; Check if there is a cramfs (magic value).
 	;; Notice that we check for cramfs magic value - which is
 	;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does
 	;; not need this mechanism anyway)
@@ -226,7 +300,7 @@
 	move.d	__vmlinux_end, r0 ; the image will be after the vmlinux end address
 	move.d	[r0], r1	; cramfs assumes same endian on host/target
 	cmp.d	CRAMFS_MAGIC, r1; magic value in cramfs superblock
-	bne	no_romfs_in_ram
+	bne	1f
 	nop
 
 	;; Ok. What is its size ? 
@@ -263,40 +337,6 @@
 	move.d	r0, [_romfs_in_flash]
 
 	jump	start_it	; better skip the additional cramfs check below
-			
-no_romfs_in_ram:
-
-	;; We have still one other possibility at this point - the kernel
-	;; could have been unpacked to DRAM by the loader, but the cramfs
-	;; image was still in the Flash directly after the compressed kernel
-	;; image. The loader passes the address of the byte succeeding the
-	;; last compressed byte in the flash in the register r9 when starting
-	;; the kernel. Check if r9 points to a decent cramfs image!
-	;; (Notice that if this is not booted from the loader, r9 will be
-	;;  garbage but we do sanity checks on it, the chance that it points
-	;;  to a cramfs magic is small.. )
-	
-	cmp.d	0x0ffffff8, r9
-	bcc	1f		; r9 points outside the flash area
-	nop
-	move.d	[r9], r0	; cramfs_super.magic
-	cmp.d	CRAMFS_MAGIC, r0
-	bne	1f
-	nop
-	move.d	[r9+4], r0	; cramfs_super.length
-	move.d	r0, [_romfs_length]
-#ifdef CONFIG_CRIS_LOW_MAP
-	add.d   0x50000000, r9	; add flash start in virtual memory (cached)
-#else
-	add.d   0xf0000000, r9	; add flash start in virtual memory (cached)
-#endif
-	move.d	r9, [_romfs_start]
-
-	moveq	1, r0
-	move.d	r0, [_romfs_in_flash]
-1:	
-	
-	jump	start_it	; enter code, cached this time
 	
 start_it:
 	;; the kernel stack is overlayed with the task structure for each
@@ -368,10 +408,10 @@
 	;; Etrax product HW genconfig setup
 
 	moveq	0,r0
-#if !defined(CONFIG_KGDB) && !defined(CONFIG_DMA_MEMCPY)
+#if !defined(CONFIG_ETRAX_KGDB) && !defined(CONFIG_DMA_MEMCPY)
 	or.d	0x140000,r0	; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
 #endif
-#if !defined(CONFIG_KGDB) || !defined(CONFIG_DEBUG_PORT1)	
+#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1)	
 	or.d	0xc00000,r0	; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
 #endif	
 #ifdef CONFIG_DMA_MEMCPY
@@ -389,7 +429,7 @@
 #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
 	or.w	0x80,r0	; parport 1 enabled using DMA 4/5
 #endif
-#ifdef CONFIG_BLK_DEV_ETRAXIDE
+#ifdef CONFIG_ETRAX_IDE
 	or.d	0x3c02,r0	; DMA channels 2 and 3 to ATA, ATA enabled
 #endif
 	
@@ -405,9 +445,6 @@
 	
 #ifdef CONFIG_JULIETTE
 	or.d	0x3c000,r0	; DMA channels 4 and 5 to EXTDMA0, for Juliette
-#ifndef CONFIG_BLK_DEV_ETRAXIDE
-	or.d	0x41,r0		; HACK for now! To make G27 connected for the RTC
-#endif
 #endif
 	move.d	r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG
 
@@ -447,20 +484,20 @@
 	;; setup port PA and PB default initial directions and data
 	;; including their shadow registers
 		
-	move.b	DEF_R_PORT_PA_DIR,r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DIR,r0
 	move.b	r0,[_port_pa_dir_shadow]
 	move.b	r0,[R_PORT_PA_DIR]
-	move.b	DEF_R_PORT_PA_DATA,r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PA_DATA,r0
 	move.b	r0,[_port_pa_data_shadow]
 	move.b	r0,[R_PORT_PA_DATA]
 	
-	move.b	DEF_R_PORT_PB_CONFIG,r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,r0
 	move.b	r0,[_port_pb_config_shadow]
 	move.b	r0,[R_PORT_PB_CONFIG]
-	move.b	DEF_R_PORT_PB_DIR,r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DIR,r0
 	move.b	r0,[_port_pb_dir_shadow]
 	move.b	r0,[R_PORT_PB_DIR]
-	move.b	DEF_R_PORT_PB_DATA,r0
+	move.b	CONFIG_ETRAX_DEF_R_PORT_PB_DATA,r0
 	move.b	r0,[_port_pb_data_shadow]
 	move.b	r0,[R_PORT_PB_DATA]
 	move.d  0, r0
@@ -499,12 +536,6 @@
 	move.b	0x40,r0			; tr enable
 	move.b	r0,[R_SERIAL1_TR_CTRL]
 
-#ifdef CONFIG_ETRAX_90000000_LEDS
-	;; clear LED's on Stallone and Olga boards
-	moveq	-1,r0
-	move.d	r0,[_port_90000000_shadow]
-	move.d	r0,[0x90000000]
-#endif
 	
 #ifdef CONFIG_ETRAX_SERIAL_PORT3	
 	;; setup the serial port 3 at 115200 baud for debug purposes
@@ -544,3 +575,5 @@
 #else	
 _swapper_pg_dir = 0xc0002000
 #endif
+	
+#include "../lib/hw_settings.S"
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c
--- v2.4.4/linux/arch/cris/kernel/irq.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/kernel/irq.c	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.11 2001/02/27 13:52:52 bjornw Exp $
+/* $Id: irq.c,v 1.14 2001/04/17 13:58:39 orjanf Exp $
  *
  *	linux/arch/cris/kernel/irq.c
  *
@@ -160,7 +160,7 @@
 BUILD_IRQ(23, 0x800000)
 BUILD_IRQ(24, 0x1000000)
 BUILD_IRQ(25, 0x2000000)
-/* IRQ 26-30 are resereved */	
+/* IRQ 26-30 are reserved */
 BUILD_IRQ(31, 0x80000000)
  
 /*
@@ -261,11 +261,11 @@
         irq_enter(cpu);
 	kstat.irqs[cpu][irq]++;
 
-	action = *(irq + irq_action);
+	action = irq_action[irq];
         if (action) {
                 if (!(action->flags & SA_INTERRUPT))
                         __sti();
-                action = *(irq + irq_action);
+                action = irq_action[irq];
                 do_random = 0;
                 do {
                         do_random |= action->flags;
@@ -396,7 +396,7 @@
 		save_flags(flags);
 		cli();
 		*p = action->next;
-		if (!irq[irq_action]) {
+		if (!irq_action[irq]) {
 			mask_irq(irq);
 			set_int_vector(irq, bad_interrupt[irq], 0);
 		}
@@ -419,8 +419,8 @@
 */
 
 void system_call(void);  /* from entry.S */
-void gdb_handle_breakpoint(void); /* from traps.c */
-void do_sigtrap(void); /* also from traps.c */
+void do_sigtrap(void); /* from entry.S */
+void gdb_handle_breakpoint(void); /* from entry.S */
 
 void init_IRQ(void)
 {
@@ -475,10 +475,10 @@
 
         /* setup a breakpoint handler for debugging used for both user and
            kernel mode debugging  (which is why it is not inside an ifdef
-           CONFIG_KGDB) */
+           CONFIG_ETRAX_KGDB) */
         set_break_vector(8, gdb_handle_breakpoint);
 
-#ifdef CONFIG_KGDB
+#ifdef CONFIG_ETRAX_KGDB
 	/* setup kgdb if its enabled, and break into the debugger */
 	kgdb_init();
 	breakpoint();
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/kgdb.c linux/arch/cris/kernel/kgdb.c
--- v2.4.4/linux/arch/cris/kernel/kgdb.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/kernel/kgdb.c	Tue May  1 16:04:56 2001
@@ -18,6 +18,9 @@
 *! Jul 21 1999  Bjorn Wesen     eLinux port
 *!
 *! $Log: kgdb.c,v $
+*! Revision 1.5  2001/04/17 13:58:39  orjanf
+*! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.
+*!
 *! Revision 1.4  2001/02/23 13:45:19  bjornw
 *! config.h check
 *!
@@ -49,7 +52,7 @@
 *!
 *!---------------------------------------------------------------------------
 *!
-*! $Id: kgdb.c,v 1.4 2001/02/23 13:45:19 bjornw Exp $
+*! $Id: kgdb.c,v 1.5 2001/04/17 13:58:39 orjanf Exp $
 *!
 *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN
 *!
@@ -60,8 +63,8 @@
  *  kgdb usage notes:
  *  -----------------
  *
- * If you select CONFIG_KGDB in the configuration, the kernel will be built
- * with different gcc flags: "-g" is added to get debug infos, and
+ * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be 
+ * built with different gcc flags: "-g" is added to get debug infos, and
  * "-fomit-frame-pointer" is omitted to make debugging easier. Since the
  * resulting kernel will be quite big (approx. > 7 MB), it will be stripped
  * before compresion. Such a kernel will behave just as usually, except if
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c
--- v2.4.4/linux/arch/cris/kernel/process.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/kernel/process.c	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.12 2001/02/27 13:52:52 bjornw Exp $
+/* $Id: process.c,v 1.13 2001/03/20 19:44:06 bjornw Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -7,6 +7,10 @@
  *
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
+ *  $Log: process.c,v $
+ *  Revision 1.13  2001/03/20 19:44:06  bjornw
+ *  Use the 7th syscall argument for regs instead of current_regs
+ *
  */
 
 /*
@@ -33,6 +37,8 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/processor.h>
+
 #include <linux/smp.h>
 
 //#define DEBUG
@@ -64,13 +70,6 @@
 
 static int hlt_counter=0;
 
-/* in a system call, set_esp0 is called to remember the stack frame, therefore
-   in the implementation of syscalls we can use that value to access the stack
-   frame and saved registers.
-*/
-
-#define currentregs ((struct pt_regs *)current->thread.esp0)
-
 void disable_hlt(void)
 {
 	hlt_counter++;
@@ -178,7 +177,7 @@
 	 * remember that the task_struct doubles as the kernel stack for the task
 	 */
 
-	childregs = ((struct pt_regs *) ((unsigned long)p + THREAD_SIZE)) - 1;
+	childregs = user_regs(p);
 
 	*childregs = *regs;  /* struct copy of pt_regs */
 
@@ -202,14 +201,11 @@
 
 	p->thread.ksp = (unsigned long) swstack;
 
-	/* esp0 keeps the pt_regs stacked structure pointer */
-
-	p->thread.esp0 = (unsigned long) childregs;
-
 #ifdef DEBUG
-	printk("kern_stack_page 0x%x, used stack %d, thread.usp 0x%x, usp 0x%x\n", 
-	       current->kernel_stack_page, usedstack, p->thread.usp, usp);
+	printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs);
+	show_registers(childregs);
 #endif
+
 	return 0;
 }
 
@@ -240,33 +236,53 @@
 #endif 
 }
 
-asmlinkage int sys_fork(void)
+/* 
+ * Be aware of the "magic" 7th argument in the four system-calls below.
+ * They need the latest stackframe, which is put as the 7th argument by
+ * entry.S. The previous arguments are dummies or actually used, but need
+ * to be defined to reach the 7th argument.
+ *
+ * N.B.: Another method to get the stackframe is to use current_regs(). But
+ * it returns the latest stack-frame stacked when going from _user mode_ and
+ * some of these (at least sys_clone) are called from kernel-mode sometimes
+ * (for example during kernel_thread, above) and thus cannot use it. Thus,
+ * to be sure not to get any surprises, we use the method for the other calls
+ * as well.
+ */
+
+asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp,
+			struct pt_regs *regs)
 {
-	return do_fork(SIGCHLD, rdusp(), currentregs, 0);
+	return do_fork(SIGCHLD, rdusp(), regs, 0);
 }
 
 /* if newusp is 0, we just grab the old usp */
 
-asmlinkage int sys_clone(unsigned long newusp, unsigned long flags)
+asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
+			 long r12, long r13, long mof, long srp,
+			 struct pt_regs *regs)
 {
 	if (!newusp)
 		newusp = rdusp();
-	return do_fork(flags, newusp, currentregs, 0);
+	return do_fork(flags, newusp, regs, 0);
 }
 
 /* vfork is a system call in i386 because of register-pressure - maybe
  * we can remove it and handle it in libc but we put it here until then.
  */
 
-asmlinkage int sys_vfork(void)
+asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp,
+			 struct pt_regs *regs)
 {
-        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), currentregs, 0);
+        return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0);
 }
 
 /*
  * sys_execve() executes a new program.
  */
-asmlinkage int sys_execve(const char *fname, char **argv, char **envp)
+asmlinkage int sys_execve(const char *fname, char **argv, char **envp,
+			  long r13, long mof, long srp, 
+			  struct pt_regs *regs)
 {
 	int error;
 	char *filename;
@@ -276,7 +292,7 @@
 
 	if (IS_ERR(filename))
 	        goto out;
-	error = do_execve(filename, argv, envp, currentregs);
+	error = do_execve(filename, argv, envp, regs);
 	putname(filename);
  out:
 	return error;
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/ptrace.c linux/arch/cris/kernel/ptrace.c
--- v2.4.4/linux/arch/cris/kernel/ptrace.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/ptrace.c	Tue May  1 16:04:56 2001
@@ -3,11 +3,18 @@
  *
  * Parts taken from the m68k port.
  * 
- * Copyright (c) 2000 Axis Communications AB
+ * Copyright (c) 2000, 2001 Axis Communications AB
  *
  * Authors:   Bjorn Wesen
  *
  * $Log: ptrace.c,v $
+ * Revision 1.5  2001/03/26 14:24:28  orjanf
+ * * Changed loop condition.
+ * * Added comment documenting non-standard ptrace behaviour.
+ *
+ * Revision 1.4  2001/03/20 19:44:41  bjornw
+ * Use the user_regs macro instead of thread.esp0
+ *
  * Revision 1.3  2000/12/18 23:45:25  bjornw
  * Linux/CRIS first version
  *
@@ -49,8 +56,8 @@
 
 	if (regno == PT_USP)
 		return task->thread.usp;
-	else if (regno <= PT_MAX)
-		return ((unsigned long *)(task->thread.esp0))[regno];
+	else if (regno < PT_MAX)
+		return ((unsigned long *)user_regs(task))[regno];
 	else
 		return 0;
 }
@@ -65,12 +72,20 @@
 
 	if (regno == PT_USP)
 		task->thread.usp = data;
-	else if (regno <= PT_MAX)
-		((unsigned long *)(task->thread.esp0))[regno] = data;
+	else if (regno < PT_MAX)
+		((unsigned long *)user_regs(task))[regno] = data;
 	else
 		return -1;
 	return 0;
 }
+
+/* Note that this implementation of ptrace behaves differently from vanilla
+ * ptrace.  Contrary to what the man page says, in the PTRACE_PEEKTEXT,
+ * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not
+ * ignored.  Instead, the data variable is expected to point at a location
+ * (in user space) where the result of the ptrace call is written (instead of
+ * being returned).
+ */
 
 asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c
--- v2.4.4/linux/arch/cris/kernel/setup.c	Fri Apr 27 14:10:31 2001
+++ linux/arch/cris/kernel/setup.c	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.11 2001/03/02 15:52:03 bjornw Exp $
+/* $Id: setup.c,v 1.14 2001/04/03 12:54:12 starvik Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -60,7 +60,7 @@
  * given by the macro __pa().
  *
  * In this DRAM, the kernel code and data is loaded, in the beginning.
- * It really starts at c00a0000 to make room for some special pages - 
+ * It really starts at c0004000 to make room for some special pages - 
  * the start address is text_start. The kernel data ends at _end. After
  * this the ROM filesystem is appended (if there is any).
  * 
@@ -77,11 +77,6 @@
 	unsigned long memory_start;
 	extern void console_print_etrax(const char *b);
 
-#if (defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH))
-	/* TODO: move this into flash_init I think */
-	flash_probe();
-#endif
-
  	/* register an initial console printing routine for printk's */
 
 	init_etrax_debug();
@@ -167,8 +162,9 @@
 
 	paging_init();
 
-	/* we dont use a command line yet, so just let it be an empty string */
-
+	/* we dont use a command line yet, so just let it be an empty string 
+	   to start with */
+        
 	*cmdline_p = command_line;
 	strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */
 
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/shadows.c linux/arch/cris/kernel/shadows.c
--- v2.4.4/linux/arch/cris/kernel/shadows.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/kernel/shadows.c	Tue May  1 16:04:56 2001
@@ -1,20 +1,36 @@
-/* $Id: shadows.c,v 1.1 2000/07/10 16:25:21 bjornw Exp $
+/* $Id: shadows.c,v 1.2 2001/03/15 14:25:16 bjornw Exp $
  * 
- * Various Etrax shadow registers. Defines for these are in include/asm-etrax100/io.h
+ * Various shadow registers. Defines for these are in include/asm-etrax100/io.h
  */
 
-#include <linux/config.h>
+/* Shadows for internal Etrax-registers */
+
+unsigned long genconfig_shadow;
+unsigned long port_g_data_shadow;
+unsigned char port_pa_dir_shadow;
+unsigned char port_pa_data_shadow;
+unsigned char port_pb_i2c_shadow;
+unsigned char port_pb_config_shadow;
+unsigned char port_pb_dir_shadow;
+unsigned char port_pb_data_shadow;
+unsigned long r_timer_ctrl_shadow;
+
+/* Shadows for external I/O port registers.
+ * These are only usable if there actually IS a latch connected
+ * to the corresponding external chip-select pin.
+ *
+ * A common usage is that CSP0 controls LED's and CSP4 video chips.
+ */
+
+unsigned long port_cse1_shadow;
+unsigned long port_csp0_shadow;
+unsigned long port_csp4_shadow;
+
+/* Corresponding addresses for the ports.
+ * These are initialized in arch/cris/mm/init.c using ioremap.
+ */
+
+volatile unsigned long *port_cse1_addr;
+volatile unsigned long *port_csp0_addr;
+volatile unsigned long *port_csp4_addr;
 
-unsigned long genconfig_shadow = 42;
-unsigned long port_g_data_shadow = 42;
-unsigned char port_pa_dir_shadow = 42;
-unsigned char port_pa_data_shadow = 42;
-unsigned char port_pb_i2c_shadow = 42;
-unsigned char port_pb_config_shadow = 42;
-unsigned char port_pb_dir_shadow = 42;
-unsigned char port_pb_data_shadow = 42;
-unsigned long r_timer_ctrl_shadow = 42;
-
-#ifdef CONFIG_ETRAX_90000000_LEDS
-unsigned long port_90000000_shadow = 42;
-#endif
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/signal.c linux/arch/cris/kernel/signal.c
--- v2.4.4/linux/arch/cris/kernel/signal.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/kernel/signal.c	Tue May  1 16:04:56 2001
@@ -36,6 +36,9 @@
 /* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */
 /* manipulate regs so that upon return, it will be re-executed */
 
+/* We rely on that pc points to the instruction after "break 13", so the
+ * library must never do strange things like putting it in a delay slot.
+ */
 #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2;
 
 int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs);
@@ -76,12 +79,14 @@
 }
 
 /*
- * Atomically swap in the new signal mask, and wait for a signal.
+ * Atomically swap in the new signal mask, and wait for a signal.  Define 
+ * dummy arguments to be able to reach the regs argument.  (Note that this
+ * arrangement relies on old_sigset_t occupying one register.)
  */
 int
-sys_sigsuspend(old_sigset_t mask)
+sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, 
+               long srp, struct pt_regs *regs)
 {
-	struct pt_regs * regs = (struct pt_regs *)current_regs();
 	sigset_t saveset;
 
 	mask &= _BLOCKABLE;
@@ -100,10 +105,13 @@
 	}
 }
 
+/* Define dummy arguments to be able to reach the regs argument.  (Note that
+ * this arrangement relies on size_t occupying one register.)
+ */
 int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
+sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, 
+                  long mof, long srp, struct pt_regs *regs)
 {
-	struct pt_regs * regs = (struct pt_regs *)current_regs();
 	sigset_t saveset, newset;
 
 	/* XXX: Don't preclude handling different sized sigset_t's.  */
@@ -225,9 +233,11 @@
 	return 1;
 }
 
-asmlinkage int sys_sigreturn(void)
+/* Define dummy arguments to be able to reach the regs argument.  */
+
+asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, 
+                             long srp, struct pt_regs *regs)
 {
-	struct pt_regs *regs = (struct pt_regs *)current_regs();
 	struct sigframe *frame = (struct sigframe *)rdusp();
 	sigset_t set;
 
@@ -265,9 +275,11 @@
 	return 0;
 }	
 
-asmlinkage int sys_rt_sigreturn(void)
+/* Define dummy arguments to be able to reach the regs argument.  */
+
+asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, 
+                                long mof, long srp, struct pt_regs *regs)
 {
-	struct pt_regs *regs = (struct pt_regs *)current_regs();
 	struct rt_sigframe *frame = (struct rt_sigframe *)rdusp();
 	sigset_t set;
 	stack_t st;
@@ -389,7 +401,6 @@
 		/* trampoline - the desired return ip is the retcode itself */
 		return_ip = (unsigned long)&frame->retcode;
 		/* This is movu.w __NR_sigreturn, r9; break 13; */
-		/* TODO: check byteorder */
 		err |= __put_user(0x9c5f,         (short *)(frame->retcode+0));
 		err |= __put_user(__NR_sigreturn, (short *)(frame->retcode+2));
 		err |= __put_user(0xe93d,         (short *)(frame->retcode+4));
@@ -535,7 +546,14 @@
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
+ *
+ * Also note that the regs structure given here as an argument, is the latest
+ * pushed pt_regs. It may or may not be the same as the first pushed registers
+ * when the initial usermode->kernelmode transition took place. Therefore
+ * we can use user_mode(regs) to see if we came directly from kernel or user
+ * mode below.
  */
+
 int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs)
 {
 	siginfo_t info;
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c
--- v2.4.4/linux/arch/cris/kernel/sys_cris.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/kernel/sys_cris.c	Tue May  1 16:04:56 2001
@@ -1,6 +1,6 @@
-/* $Id: sys_cris.c,v 1.4 2001/01/31 14:55:58 perf Exp $
+/* $Id: sys_cris.c,v 1.7 2001/04/17 11:52:15 orjanf Exp $
  *
- * linux/arch/cris/kernel/sys_etrax.c
+ * linux/arch/cris/kernel/sys_cris.c
  *
  * This file contains various random system calls that
  * have a non-standard calling sequence on some platforms.
@@ -177,20 +177,13 @@
 	case MSGCTL:
 		return sys_msgctl (first, second, (struct msqid_ds *) ptr);
 
-	case SHMAT:
-		switch (version) {
-		default: {
-			ulong raddr;
-			ret = sys_shmat (first, (char *) ptr, second, &raddr);
-			if (ret)
-				return ret;
-			return put_user (raddr, (ulong *) third);
-		}
-		case 1:	/* iBCS2 emulator entry point */
-			if (!segment_eq(get_fs(), get_ds()))
-				return -EINVAL;
-			return sys_shmat (first, (char *) ptr, second, (ulong *) third);
-		}
+	case SHMAT: {
+                ulong raddr;
+                ret = sys_shmat (first, (char *) ptr, second, &raddr);
+                if (ret)
+                        return ret;
+                return put_user (raddr, (ulong *) third);
+        }
 	case SHMDT: 
 		return sys_shmdt ((char *)ptr);
 	case SHMGET:
diff -u --recursive --new-file v2.4.4/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c
--- v2.4.4/linux/arch/cris/kernel/traps.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/kernel/traps.c	Tue May  1 16:04:56 2001
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.8 2001/02/23 13:45:20 bjornw Exp $
+/* $Id: traps.c,v 1.11 2001/04/04 09:43:31 orjanf Exp $
  *
  *  linux/arch/cris/traps.c
  *
@@ -9,7 +9,6 @@
  *  Copyright (C) 2000,2001 Axis Communications AB
  *
  *  Authors:   Bjorn Wesen
- *             Orjan Friberg
  *
  */
 
@@ -45,8 +44,10 @@
         int i;
 	extern char _stext, _etext;
 
-        // debugging aid: "show_stack(NULL);" prints the
-        // back trace for this cpu.
+        /*
+         * debugging aid: "show_stack(NULL);" prints the
+         * back trace for this cpu.
+         */
 
         if(sp == NULL)
                 sp = (unsigned long*)rdsp();
@@ -107,8 +108,8 @@
 {
 	unsigned long usp = rdusp();
 
-	printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx\n",
-	       regs->irp, regs->srp, regs->dccr, usp );
+	printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx MOF: %08lx\n",
+	       regs->irp, regs->srp, regs->dccr, usp, regs->mof );
 	printk(" r0: %08lx  r1: %08lx  r2: %08lx  r3: %08lx\n",
 	       regs->r0, regs->r1, regs->r2, regs->r3);
 	printk(" r4: %08lx  r5: %08lx  r6: %08lx  r7: %08lx\n",
@@ -120,7 +121,7 @@
 	printk("Process %s (pid: %d, stackpage=%08lx)\n",
 	       current->comm, current->pid, (unsigned long)current);
 
-	// TODO, fix in_kernel detection
+	/* TODO, fix in_kernel detection */
 
 #if 0
 	/*
@@ -168,65 +169,5 @@
 void __init 
 trap_init(void)
 {
-
+  /* Nothing needs to be done */
 }
-
-/* Use static variables instead of the stack for temporary storage.  */
-static int saved_r0 = 0;
-static int saved_dccr = 0;
-
-asm ("
-  .global _gdb_handle_breakpoint
-  .global _do_sigtrap
-_gdb_handle_breakpoint:
-;;
-;; This handles a break instruction for entering a debug session.
-;;
-  move     dccr,[_saved_dccr]       ; Save dccr.
-  move.d   r0,[_saved_r0]           ; Save r0. "
-#ifdef CONFIG_KGDB
-" 
-  move     ccr,r0                   
-  btstq    8,r0                     ; Test the U-flag.
-  bmi      _ugdb_handle_breakpoint  ; Go to user mode debugging.
-  nop                               ; Delay slot.
-  move.d   [_saved_r0],r0           ; Restore r0.
-  move     [_saved_dccr],dccr       ; Restore dccr.
-  ba       _kgdb_handle_breakpoint  ; Go to kernel debugging.
-  nop                               ; Delay slot. "
-#endif
-" 
-_ugdb_handle_breakpoint:
-;;
-;; Yes, we could do a 'push brp' here and let gdb adjust the pc once it
-;; starts talking to the target again, but this way we avoid a 'P' packet.
-;;
-  move     brp,r0               ; Use r0 temporarily for calculation.
-  subq     2,r0                 ; Set to address of previous instruction.
-  move     r0,brp               ; Restore new brp.
-  move.d   [_saved_r0],r0       ; Restore r0.
-  move     [_saved_dccr],dccr   ; Restore dccr.
-
-_do_sigtrap:
-;; 
-;; SIGTRAP the process that executed the break instruction.
-;; Make a frame that Rexit in entry.S expects.
-;;
-  push     brp                  ; Push breakpoint return pointer.
-  push     srp                  ; Push subroutine return pointer.
-  push     dccr                 ; Push condition codes.
-  push     mof                  ; Push multiply overflow reg.
-  di                            ; Need to disable irq's at this point.
-  subq     14*4,sp              ; Make room for r0-r13.
-  movem    r13,[sp]             ; Push the r0-r13 registers.
-  push     r10                  ; Push orig_r10.
-  clear.d  [sp=sp-4]            ; Frametype - this is a normal stackframe.
-
-  movs.w   -8192,r9             ; THREAD_SIZE == 8192
-  and.d    sp,r9
-  move.d   [r9+LTASK_PID],r10   ; current->pid as arg1.
-  moveq    5,r11                ; SIGTRAP as arg2.
-  jsr      _sys_kill       
-
-  jump     _ret_from_intr       ; Use the return routine for interrupts.
-");
diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/dram_init.S linux/arch/cris/lib/dram_init.S
--- v2.4.4/linux/arch/cris/lib/dram_init.S	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/lib/dram_init.S	Tue May  1 16:04:56 2001
@@ -1,63 +1,97 @@
-	;; $Id: dram_init.S,v 1.2 2001/02/08 15:20:00 starvik Exp $
-	;; 
-	;; DRAM/SDRAM initialization - alter with care
-	;; This file is intended to be included from other assembler files
-	;;
-	;; Copyright (C) 2000 Axis Communications AB
-	;;
-	;; Authors:  Mikael Starvik (starvik@axis.com)	
-	;;           Bjorn Wesen (bjornw@axis.com)
-	;; 
-	;; $Log: dram_init.S,v $
-	;; Revision 1.2  2001/02/08 15:20:00  starvik
-	;; Corrected SDRAM initialization
-	;; Should now be included as inline
-	;;
-	;; Revision 1.1  2001/01/29 13:08:02  starvik
-	;; Initial version
-	;; This file should be included from all assembler files that needs to
-	;; initialize DRAM/SDRAM.
-	;;
-	;;
-	;;
+/* $Id: dram_init.S,v 1.7 2001/04/18 12:05:39 bjornw Exp $
+ * 
+ * DRAM/SDRAM initialization - alter with care
+ * This file is intended to be included from other assembler files
+ *
+ * Note: This file may not modify r9 because r9 is used to carry
+ *       information from the decompresser to the kernel
+ *
+ * Copyright (C) 2000, 2001 Axis Communications AB
+ *
+ * Authors:  Mikael Starvik (starvik@axis.com)	
+ * 
+ * $Log: dram_init.S,v $
+ * Revision 1.7  2001/04/18 12:05:39  bjornw
+ * Fixed comments, and explicitely include config.h to be sure its there
+ *
+ * Revision 1.6  2001/04/10 06:20:16  starvik
+ * Delay should be 200us, not 200ns
+ *
+ * Revision 1.5  2001/04/09 06:01:13  starvik
+ * Added support for 100 MHz SDRAMs
+ *
+ * Revision 1.4  2001/03/26 14:24:01  bjornw
+ * Namechange of some config options
+ *
+ * Revision 1.3  2001/03/23 08:29:41  starvik
+ * Corrected calculation of mrs_data
+ *
+ * Revision 1.2  2001/02/08 15:20:00  starvik
+ * Corrected SDRAM initialization
+ * Should now be included as inline
+ *
+ * Revision 1.1  2001/01/29 13:08:02  starvik
+ * Initial version
+ * This file should be included from all assembler files that needs to
+ * initialize DRAM/SDRAM.
+ *
+ */
+
+/* Just to be certain the config file is included, we include it here
+ * explicitely instead of depending on it being included in the file that
+ * uses this code.
+ */
 
 #include <linux/config.h>
 
+
 #ifndef CONFIG_SVINTO_SIM	
-	move.d   DEF_R_WAITSTATES, r0
+	move.d   CONFIG_ETRAX_DEF_R_WAITSTATES, r0
 	move.d   r0, [R_WAITSTATES]
 
-	move.d   DEF_R_BUS_CONFIG, r0
+	move.d   CONFIG_ETRAX_DEF_R_BUS_CONFIG, r0
 	move.d   r0, [R_BUS_CONFIG]
 	
-#ifndef CONFIG_SDRAM
-	move.d   DEF_R_DRAM_CONFIG, r0
+#ifndef CONFIG_ETRAX_SDRAM
+	move.d   CONFIG_ETRAX_DEF_R_DRAM_CONFIG, r0
 	move.d   r0, [R_DRAM_CONFIG]
 
-	move.d   DEF_R_DRAM_TIMING, r0
+	move.d   CONFIG_ETRAX_DEF_R_DRAM_TIMING, r0
 	move.d   r0, [R_DRAM_TIMING]
 #else	
 	; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization
 	
 	; Bank configuration
-        move.d   DEF_R_SDRAM_CONFIG, r0
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, r0
 	move.d   r0, [R_SDRAM_CONFIG]
 
 	; Calculate value of mrs_data 
-	; cas_delay = 2 && bus_width = 32 => 0x40
-	; cas_delay = 3 && bus_width = 32 => 0x60
-	; cas_delay = 2 && bus_width = 16 => 0x20
-	; cas_delay = 3 && bus_width = 16 => 0x30
+	; CAS latency = 2 && bus_width = 32 => 0x40
+	; CAS latency = 3 && bus_width = 32 => 0x60
+	; CAS latency = 2 && bus_width = 16 => 0x20
+	; CAS latency = 3 && bus_width = 16 => 0x30
 	
-	move.d   0x40, r2       ; Assume 32 bits and cas_delay = 2
-	move.d   DEF_R_SDRAM_TIMING, r1
-	and.d    0x0c, r1	; Get cas delay
-	cmp.d    0x08, r1	; cas_delay = 2?
-        beq      bw_check
+	move.d   0x40, r2       ; Assume 32 bits and CAS latency = 2
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, r1
+	move.d   r1, r3
+ 	and.d    0x03, r1       ; Get CAS latency
+	and.d    0x1000, r3     ; 50 or 100 MHz?
+	beq      speed_50
+	nop
+speed_100:		
+	cmp.d    0x00, r1	; CAS latency = 2?
+	beq      bw_check
+	nop
+	or.d     0x20, r2	; CAS latency = 3 
+	ba       bw_check
+	nop
+speed_50:			
+	cmp.d    0x01, r1	; CAS latency = 2?
+	beq      bw_check
 	nop
-	or.d     0x20, r2       ; cas_delay = 3
+	or.d     0x20, r2       ; CAS latency = 3
 bw_check:
-	move.d   DEF_R_SDRAM_CONFIG, r1
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, r1
 	and.d    0x800000, r1	; DRAM width is bit 23
 	bne      set_timing
 	nop
@@ -65,14 +99,17 @@
 
 	; Set timing parameters. Starts master clock
 set_timing:
-	move.d   DEF_R_SDRAM_TIMING, r1
+	move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, r1
+	and.d    0x8000f9ff, r1 ; Make sure mrs data and command is 0 
 	or.d     0x80000000, r1	; Make sure sdram enable bit is set
+	move.d   r1, r5
+	or.d     0x0000c000, r1 ; ref = disable
 	lslq     16, r2		; mrs data starts at bit 16
 	or.d     r2, r1 
 	move.d   r1, [R_SDRAM_TIMING]	
 		
-	; Wait 200ns
-	move.d   10, r2
+	; Wait 200us
+	move.d   10000, r2
 sdram_loop:
 	bne      sdram_loop
 	subq     1, r2
@@ -83,10 +120,10 @@
 command_loop:
 	clear.d  r4
 	move.b   [r2+], r4
-	lslq     9, r4		; Command starts at bit 9
+	lslq     9, r4	; Command starts at bit 9
 	or.d     r1, r4
 	move.d   r4, [R_SDRAM_TIMING]
-	nop			; Wait five nop cycles between each command
+	nop		; Wait five nop cycles between each command
 	nop
 	nop
 	nop
@@ -94,6 +131,7 @@
 	cmp.d    r2, r3
 	bne      command_loop
 	nop
+	move.d   r5, [R_SDRAM_TIMING]
 	ba       sdram_commands_end
 	nop
 
diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/hw_settings.S linux/arch/cris/lib/hw_settings.S
--- v2.4.4/linux/arch/cris/lib/hw_settings.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/cris/lib/hw_settings.S	Tue May  1 16:04:56 2001
@@ -0,0 +1,61 @@
+	;; $Id: hw_settings.S,v 1.2 2001/04/03 11:11:09 starvik Exp $
+	;; 
+	;; This table is used by some tools to extract hardware parameters.
+	;; The table should be included in the kernel and the decompressor.
+	;; Don't forget to update the tools if you change this table.
+	;;
+	;; Copyright (C) 2001 Axis Communications AB
+	;;
+	;; Authors:  Mikael Starvik (starvik@axis.com)	
+
+	
+#define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \
+		(CONFIG_ETRAX_DEF_R_PORT_PA_DATA))
+#define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \
+		(CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \
+		(CONFIG_ETRAX_DEF_R_PORT_PB_DATA))
+	
+	.ascii "HW_PARAM_MAGIC" ; Magic number
+	.dword 0xc0004000	; Kernel start address
+
+	; Debug port
+#ifdef CONFIG_ETRAX_DEBUG_PORT0
+	.dword 0		
+#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
+	.dword 1
+#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
+	.dword 2
+#elif defined(CONFIG_ETRAX_DEBUG_PORT3)
+	.dword 3
+#else
+	.dword 4 ; No debug
+#endif			
+
+	; SDRAM or EDO DRAM?
+#ifdef CONFIG_ETRAX_SDRAM
+	.dword 1
+#else
+	.dword 0
+#endif
+
+	; Register values 
+	.dword R_WAITSTATES
+	.dword CONFIG_ETRAX_DEF_R_WAITSTATES
+	.dword R_BUS_CONFIG
+	.dword CONFIG_ETRAX_DEF_R_BUS_CONFIG
+#ifdef CONFIG_ETRAX_SDRAM
+	.dword R_SDRAM_CONFIG
+	.dword CONFIG_ETRAX_DEF_R_SDRAM_CONFIG
+	.dword R_SDRAM_TIMING
+	.dword CONFIG_ETRAX_DEF_R_SDRAM_TIMING
+#else
+	.dword R_DRAM_CONFIG
+	.dword CONFIG_ETRAX_DEF_R_DRAM_CONFIG
+	.dword R_DRAM_TIMING
+	.dword CONFIG_ETRAX_DEF_R_DRAM_TIMING
+#endif
+	.dword R_PORT_PA_SET
+	.dword PA_SET_VALUE 
+	.dword R_PORT_PB_SET
+	.dword PB_SET_VALUE
+	.dword 0 ; No more register values
diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/memset.c linux/arch/cris/lib/memset.c
--- v2.4.4/linux/arch/cris/lib/memset.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/lib/memset.c	Tue May  1 16:04:56 2001
@@ -27,6 +27,8 @@
 /*#                                                                         */
 /*#-------------------------------------------------------------------------*/
 
+#include <linux/types.h>
+
 /* No, there's no macro saying 12*4, since it is "hard" to get it into
    the asm in a good way.  Thus better to expose the problem everywhere.
    */
@@ -39,7 +41,7 @@
 
 void *memset(void *pdst,
              int c,
-             unsigned int plen)
+             size_t plen)
 {
   /* Ok.  Now we want the parameters put in special registers.
      Make sure the compiler is able to make something useful of this. */
@@ -54,7 +56,12 @@
 
   /* Ugh.  This is fragile at best.  Check with newer GCC releases, if
      they compile cascaded "x |= x << 8" sanely! */
-  __asm__("movu.b %0,r13\n\tlslq 8,r13\n\tmove.b %0,r13\n\tmove.d r13,%0\n\tlslq 16,r13\n\tor.d r13,%0"
+  __asm__("movu.b %0,r13\n\t"
+          "lslq 8,r13\n\t"
+	  "move.b %0,r13\n\t"
+	  "move.d r13,%0\n\t"
+	  "lslq 16,r13\n\t"
+	  "or.d r13,%0"
           : "=r" (lc) : "0" (lc) : "r13");
 
   {
diff -u --recursive --new-file v2.4.4/linux/arch/cris/lib/string.c linux/arch/cris/lib/string.c
--- v2.4.4/linux/arch/cris/lib/string.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/lib/string.c	Tue May  1 16:04:56 2001
@@ -31,9 +31,11 @@
 /*#                                                                         */
 /*#-------------------------------------------------------------------------*/
 
+#include <linux/types.h>
+
 void *memcpy(void *pdst,
              const void *psrc,
-             unsigned int pn)
+             size_t pn)
 {
   /* Ok.  Now we want the parameters put in special registers.
      Make sure the compiler is able to make something useful of this.
diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/extable.c linux/arch/cris/mm/extable.c
--- v2.4.4/linux/arch/cris/mm/extable.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/mm/extable.c	Tue May  1 16:04:56 2001
@@ -37,8 +37,7 @@
 
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
-	ret = search_one_table(_start___ex_table, _stop___ex_table-1, addr);
-	if (ret) return ret;
+	return search_one_table(_start___ex_table, _stop___ex_table-1, addr);
 #else
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c
--- v2.4.4/linux/arch/cris/mm/fault.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/mm/fault.c	Tue May  1 16:04:56 2001
@@ -1,11 +1,20 @@
 /*
  *  linux/arch/cris/mm/fault.c
  *
- *  Copyright (C) 2000  Axis Communications AB
+ *  Copyright (C) 2000, 2001  Axis Communications AB
  *
  *  Authors:  Bjorn Wesen 
  * 
  *  $Log: fault.c,v $
+ *  Revision 1.12  2001/04/04 10:51:14  bjornw
+ *  mmap_sem is grabbed for reading
+ *
+ *  Revision 1.11  2001/03/23 07:36:07  starvik
+ *  Corrected according to review remarks
+ *
+ *  Revision 1.10  2001/03/21 16:10:11  bjornw
+ *  CRIS_FRAME_FIXUP not needed anymore, use FRAME_NORMAL
+ *
  *  Revision 1.9  2001/03/05 13:22:20  bjornw
  *  Spell-fix and fix in vmalloc_fault handling
  *
@@ -70,12 +79,12 @@
 
 	address = cause & PAGE_MASK; /* get faulting address */
 	
-	page_id = IO_EXTRACT(R_MMU_CAUSE,  page_id,   cause);
+	D(page_id = IO_EXTRACT(R_MMU_CAUSE,  page_id,   cause));
+	D(acc     = IO_EXTRACT(R_MMU_CAUSE,  acc_excp,  cause));
+	D(inv     = IO_EXTRACT(R_MMU_CAUSE,  inv_excp,  cause));  
+	D(index  =  IO_EXTRACT(R_TLB_SELECT, index,     select));
 	miss    = IO_EXTRACT(R_MMU_CAUSE,  miss_excp, cause);
 	we      = IO_EXTRACT(R_MMU_CAUSE,  we_excp,   cause);
-	acc     = IO_EXTRACT(R_MMU_CAUSE,  acc_excp,  cause);
-	inv     = IO_EXTRACT(R_MMU_CAUSE,  inv_excp,  cause);  
-	index  =  IO_EXTRACT(R_TLB_SELECT, index,     select);
 	
 	D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, "
 		 "idx %d pid %d\n",
@@ -304,23 +313,32 @@
 	/* Are we prepared to handle this kernel fault?
 	 *
 	 * (The kernel has valid exception-points in the source 
-	 *  when it accesses user-memory. When it fails in one
+	 *  when it acesses user-memory. When it fails in one
 	 *  of those points, we find it in a table and do a jump
 	 *  to some fixup code that loads an appropriate error
 	 *  code)
 	 */
 
         if ((fixup = search_exception_table(regs->irp)) != 0) {
+		/* Adjust the instruction pointer in the stackframe */
+
                 regs->irp = fixup;
-		regs->frametype = CRIS_FRAME_FIXUP;
+
+		/* We do not want to return by restoring the CPU-state
+		 * anymore, so switch frame-types (see ptrace.h)
+		 */
+
+		regs->frametype = CRIS_FRAME_NORMAL;
+
 		D(printk("doing fixup to 0x%x\n", fixup));
                 return;
         }
 
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
+	/*
+	 * Oops. The kernel tried to access some bad page. We'll have to
+	 * terminate things with extreme prejudice.
+	 */
+
 	if ((unsigned long) (address) < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 	else
diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c
--- v2.4.4/linux/arch/cris/mm/init.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/mm/init.c	Tue May  1 16:04:56 2001
@@ -7,6 +7,22 @@
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: init.c,v $
+ *  Revision 1.23  2001/04/04 14:35:40  bjornw
+ *  * Removed get_pte_slow and friends (2.4.3 change)
+ *  * Removed bad_pmd handling (2.4.3 change)
+ *
+ *  Revision 1.22  2001/04/04 13:38:04  matsfg
+ *  Moved ioremap to a separate function instead
+ *
+ *  Revision 1.21  2001/03/27 09:28:33  bjornw
+ *  ioremap used too early - lets try it in mem_init instead
+ *
+ *  Revision 1.20  2001/03/23 07:39:21  starvik
+ *  Corrected according to review remarks
+ *
+ *  Revision 1.19  2001/03/15 14:25:17  bjornw
+ *  More general shadow registers and ioremaped addresses for external I/O
+ *
  *  Revision 1.18  2001/02/23 12:46:44  bjornw
  *  * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached
  *    flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O
@@ -68,6 +84,7 @@
 #include <asm/pgtable.h>
 #include <asm/dma.h>
 #include <asm/svinto.h>
+#include <asm/io.h>
 
 static unsigned long totalram_pages;
 
@@ -79,128 +96,13 @@
 extern void show_net_buffers(void);
 extern void tlb_init(void);
 
-/*
- * empty_bad_page is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * the main point is that when a page table error occurs, we want to get
- * out of the kernel safely before killing the process, so we need something
- * to feed the MMU with when the fault occurs even if we don't have any
- * real PTE's or page tables.
- *
- * empty_bad_page_table is the accompanying page-table: it is initialized
- * to point to empty_bad_page writable-shared entries.
- *
- * empty_zero_page is a special page that is used for zero-initialized
- * data and COW.
- */
 
-unsigned long empty_bad_page_table;
-unsigned long empty_bad_page;
 unsigned long empty_zero_page;
 
-pte_t * __bad_pagetable(void)
-{
-	/* somehow it is enough to just clear it and not fill it with
-	 * bad page PTE's...
-	 */
-	memset((void *)empty_bad_page_table, 0, PAGE_SIZE);
-
-	return (pte_t *) empty_bad_page_table;
-}
-
-pte_t __bad_page(void)
-{
-
-	/* clear the empty_bad_page page. this should perhaps be
-	 * a more simple inlined loop like it is on the other 
-	 * architectures.
-	 */
-
-	memset((void *)empty_bad_page, 0, PAGE_SIZE);
-
-	return pte_mkdirty(__mk_pte((void *)empty_bad_page, PAGE_SHARED));
-}
-
-static pte_t * get_bad_pte_table(void)
-{
-	pte_t *empty_bad_pte_table = (pte_t *)empty_bad_page_table;
-	pte_t v;
-	int i;
-
-	v = __bad_page();
-
-	for (i = 0; i < PAGE_SIZE/sizeof(pte_t); i++)
-		empty_bad_pte_table[i] = v;
-
-	return empty_bad_pte_table;
-}
-
-void __handle_bad_pmd(pmd_t *pmd)
-{
-	pmd_ERROR(*pmd);
-	pmd_set(pmd, get_bad_pte_table());
-}
-
-void __handle_bad_pmd_kernel(pmd_t *pmd)
-{
-	pmd_ERROR(*pmd);
-	pmd_set_kernel(pmd, get_bad_pte_table());
-}
-
-pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
-{
-        pte_t *pte;
-
-        pte = (pte_t *) __get_free_page(GFP_KERNEL);
-        if (pmd_none(*pmd)) {
-                if (pte) {
-                        clear_page(pte);
-			pmd_set_kernel(pmd, pte);
-                        return pte + offset;
-                }
-		pmd_set_kernel(pmd, get_bad_pte_table());
-                return NULL;
-        }
-        free_page((unsigned long)pte);
-        if (pmd_bad(*pmd)) {
-                __handle_bad_pmd_kernel(pmd);
-                return NULL;
-        }
-        return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
-{
-	pte_t *pte;
-
-        pte = (pte_t *) __get_free_page(GFP_KERNEL);
-        if (pmd_none(*pmd)) {
-                if (pte) {
-                        clear_page(pte);
-			pmd_set(pmd, pte);
-                        return pte + offset;
-                }
-		pmd_set(pmd, get_bad_pte_table());
-                return NULL;
-        }
-        free_page((unsigned long)pte);
-        if (pmd_bad(*pmd)) {
-                __handle_bad_pmd(pmd);
-                return NULL;
-        }
-        return (pte_t *) pmd_page(*pmd) + offset;
-}
-
-#ifndef CONFIG_NO_PGT_CACHE
-struct pgtable_cache_struct quicklists;
-
 /* trim the page-table cache if necessary */
 
-int do_check_pgt_cache(int low, int high)
+int 
+do_check_pgt_cache(int low, int high)
 {
         int freed = 0;
 
@@ -211,25 +113,20 @@
                                 freed++;
                         }
                         if(pmd_quicklist) {
-                                free_pmd_slow(get_pmd_fast());
+                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
                                 freed++;
                         }
                         if(pte_quicklist) {
-                                free_pte_slow(get_pte_fast());
-                                 freed++;
+                                pte_free_slow(pte_alloc_one_fast(NULL, 0));
+				freed++;
                         }
                 } while(pgtable_cache_size > low);
         }
         return freed;
 }
-#else
-int do_check_pgt_cache(int low, int high)
-{
-        return 0;
-}
-#endif
 
-void show_mem(void)
+void 
+show_mem(void)
 {
 	int i,free = 0,total = 0,cached = 0, reserved = 0, nonshared = 0;
 	int shared = 0;
@@ -287,15 +184,51 @@
 
 	/* see README.mm for details on the KSEG setup */
 
-#ifdef CONFIG_CRIS_LOW_MAP
+#ifndef CONFIG_CRIS_LOW_MAP
+	/* This code is for the corrected Etrax-100 LX version 2... */
 
+	*R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg  ) | /* cached flash */
+			IO_STATE(R_MMU_KSEG, seg_e, seg  ) | /* uncached flash */
+			IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */
+			IO_STATE(R_MMU_KSEG, seg_c, seg  ) | /* kernel area */
+			IO_STATE(R_MMU_KSEG, seg_b, seg  ) | /* kernel reg area */
+			IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */
+			IO_STATE(R_MMU_KSEG, seg_9, page ) |
+			IO_STATE(R_MMU_KSEG, seg_8, page ) |
+			IO_STATE(R_MMU_KSEG, seg_7, page ) |
+			IO_STATE(R_MMU_KSEG, seg_6, page ) |
+			IO_STATE(R_MMU_KSEG, seg_5, page ) |
+			IO_STATE(R_MMU_KSEG, seg_4, page ) |
+			IO_STATE(R_MMU_KSEG, seg_3, page ) |
+			IO_STATE(R_MMU_KSEG, seg_2, page ) |
+			IO_STATE(R_MMU_KSEG, seg_1, page ) |
+			IO_STATE(R_MMU_KSEG, seg_0, page ) );
+
+	*R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) );
+	
+	*R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) |
+			    IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) );
+#else
 	/* Etrax-100 LX version 1 has a bug so that we cannot map anything
 	 * across the 0x80000000 boundary, so we need to shrink the user-virtual
 	 * area to 0x50000000 instead of 0xb0000000 and map things slightly
 	 * different. The unused areas are marked as paged so that we can catch
 	 * freak kernel accesses there.
 	 *
-	 * The Juliette chip is mapped at 0xa so we pass that segment straight
+	 * The ARTPEC chip is mapped at 0xa so we pass that segment straight
 	 * through. We cannot vremap it because the vmalloc area is below 0x8
 	 * and Juliette needs an uncached area above 0x8.
 	 *
@@ -308,7 +241,7 @@
 			IO_STATE(R_MMU_KSEG, seg_d, page ) | 
 			IO_STATE(R_MMU_KSEG, seg_c, page ) |   
 			IO_STATE(R_MMU_KSEG, seg_b, seg  ) |  /* kernel reg area */
-			IO_STATE(R_MMU_KSEG, seg_a, seg  ) |  /* Juliette etc. */
+			IO_STATE(R_MMU_KSEG, seg_a, seg  ) |  /* ARTPEC etc. */
 			IO_STATE(R_MMU_KSEG, seg_9, seg  ) |  /* LED's on some boards */
 			IO_STATE(R_MMU_KSEG, seg_8, seg  ) |  /* CSE0/1, flash and I/O */
 			IO_STATE(R_MMU_KSEG, seg_7, page ) |  /* kernel vmalloc area */
@@ -337,44 +270,7 @@
 			    IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) |
 			    IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) |
 			    IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) );
-#else
-	/* This code is for the hopefully corrected Etrax-100 LX version 2... */
-
-	*R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg  ) | /* cached flash */
-			IO_STATE(R_MMU_KSEG, seg_e, seg  ) | /* uncached flash */
-			IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */
-			IO_STATE(R_MMU_KSEG, seg_c, seg  ) | /* kernel area */
-			IO_STATE(R_MMU_KSEG, seg_b, seg  ) | /* kernel reg area */
-			IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */
-			IO_STATE(R_MMU_KSEG, seg_9, page ) |
-			IO_STATE(R_MMU_KSEG, seg_8, page ) |
-			IO_STATE(R_MMU_KSEG, seg_7, page ) |
-			IO_STATE(R_MMU_KSEG, seg_6, page ) |
-			IO_STATE(R_MMU_KSEG, seg_5, page ) |
-			IO_STATE(R_MMU_KSEG, seg_4, page ) |
-			IO_STATE(R_MMU_KSEG, seg_3, page ) |
-			IO_STATE(R_MMU_KSEG, seg_2, page ) |
-			IO_STATE(R_MMU_KSEG, seg_1, page ) |
-			IO_STATE(R_MMU_KSEG, seg_0, page ) );
-
-	*R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) );
-	
-	*R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) |
-			    IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) );
-#endif	
+#endif
 
 	*R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) );
 	
@@ -393,8 +289,6 @@
 	 * to a couple of allocated pages
 	 */
 
-	empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
-	empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
 	empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
 	memset((void *)empty_zero_page, 0, PAGE_SIZE);
 
@@ -412,6 +306,7 @@
 	 */
 
 	free_area_init_node(0, 0, 0, zones_size, PAGE_OFFSET, 0);
+
 }
 
 extern unsigned long loops_per_jiffy; /* init/main.c */
@@ -462,7 +357,7 @@
 	       datasize >> 10,
 	       initsize >> 10
                );
-	
+
 	/* HACK alert - calculate a loops_per_usec for asm/delay.h here
 	 * since this is called just after calibrate_delay in init/main.c
 	 * but before places which use udelay. cannot be in time.c since
@@ -474,9 +369,52 @@
 	return;
 }
 
+/* Initialize remaps of some I/O-ports. This is designed to be callable
+ * multiple times from the drivers init-sections, because we don't know
+ * beforehand which driver will get initialized first.
+ */
+
+void 
+init_ioremap(void)
+{
+  
+	/* Give the external I/O-port addresses their values */
+
+        static int initialized = 0;
+  
+        if( !initialized ) {
+                initialized++;
+            
+#ifdef CONFIG_CRIS_LOW_MAP
+               /* Simply a linear map (see the KSEG map above in paging_init) */
+               port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | 
+                                                           MEM_NON_CACHEABLE);
+               port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START |
+                                                           MEM_NON_CACHEABLE);
+               port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START |
+                                                           MEM_NON_CACHEABLE);
+#else
+               /* Note that nothing blows up just because we do this remapping 
+                * it's ok even if the ports are not used or connected 
+                * to anything (or connected to a non-I/O thing) */        
+               port_cse1_addr = (volatile unsigned long *)
+                 ioremap((unsigned long)(MEM_CSE1_START | 
+                                         MEM_NON_CACHEABLE), 16);
+               port_csp0_addr = (volatile unsigned long *)
+                 ioremap((unsigned long)(MEM_CSP0_START |
+                                         MEM_NON_CACHEABLE), 16);
+               port_csp4_addr = (volatile unsigned long *)
+                 ioremap((unsigned long)(MEM_CSP4_START |
+                                         MEM_NON_CACHEABLE), 16);
+#endif	
+        }
+}
+
+
 /* free the pages occupied by initialization code */
 
-void free_initmem(void)
+void 
+free_initmem(void)
 {
 #if 0
 	/* currently this is a bad idea since the cramfs image is catted onto
@@ -497,7 +435,8 @@
 #endif
 }
 
-void si_meminfo(struct sysinfo *val)
+void 
+si_meminfo(struct sysinfo *val)
 {
 	int i;
 
diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/ioremap.c linux/arch/cris/mm/ioremap.c
--- v2.4.4/linux/arch/cris/mm/ioremap.c	Fri Apr  6 10:42:55 2001
+++ linux/arch/cris/mm/ioremap.c	Tue May  1 16:04:56 2001
@@ -51,7 +51,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		pte_t * pte = pte_alloc_kernel(pmd, address);
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
@@ -64,6 +64,7 @@
 static int remap_area_pages(unsigned long address, unsigned long phys_addr,
 				 unsigned long size, unsigned long flags)
 {
+	int error;
 	pgd_t * dir;
 	unsigned long end = address + size;
 
@@ -72,19 +73,23 @@
 	flush_cache_all();
 	if (address >= end)
 		BUG();
+	spin_lock(&init_mm.page_table_lock);
 	do {
 		pmd_t *pmd;
-		pmd = pmd_alloc_kernel(dir, address);
+		pmd = pmd_alloc(&init_mm, dir, address);
+		error = -ENOMEM;
 		if (!pmd)
-			return -ENOMEM;
+			break;
 		if (remap_area_pmd(pmd, address, end - address,
-					 phys_addr + address, flags))
-			return -ENOMEM;
+				   phys_addr + address, flags))
+			break;
+		error = 0;
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
 	} while (address && (address < end));
+	spin_unlock(&init_mm.page_table_lock);
 	flush_tlb_all();
-	return 0;
+	return error;
 }
 
 /*
diff -u --recursive --new-file v2.4.4/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c
--- v2.4.4/linux/arch/cris/mm/tlb.c	Thu Feb  8 16:32:44 2001
+++ linux/arch/cris/mm/tlb.c	Tue May  1 16:04:56 2001
@@ -288,7 +288,7 @@
 
 	/* clear the page_id map */
 
-	for(i = 0; i < 64; i++)
+	for(i = 0; i < NUM_PAGEID; i++)
 		page_id_map[i] = NULL;
 	
 	/* invalidate the entire TLB */
diff -u --recursive --new-file v2.4.4/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.4.4/linux/arch/i386/boot/setup.S	Wed Apr 11 18:50:25 2001
+++ linux/arch/i386/boot/setup.S	Tue May  1 16:04:56 2001
@@ -32,6 +32,16 @@
  *
  * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
  * <stiker@northlink.com>
+ *
+ * Fix to work around buggy BIOSes which dont use carry bit correctly
+ * and/or report extended memory in CX/DX for e801h memory size detection 
+ * call.  As a result the kernel got wrong figures.  The int15/e801h docs
+ * from Ralf Brown interrupt list seem to indicate AX/BX should be used
+ * anyway.  So to avoid breaking many machines (presumably there was a reason
+ * to orginally use CX/DX instead of AX/BX), we do a kludge to see
+ * if CX/DX have been changed in the e801 call and if so use AX/BX .
+ * Michael Miller, April 2001 <michaelm@mjmm.org>
+ *
  */
 
 #define __ASSEMBLY__
@@ -336,10 +346,24 @@
 # to write everything into the same place.)
 
 meme801:
+	stc					# fix to work around buggy
+	xorw	%cx,%cx				# BIOSes which dont clear/set
+	xorw	%dx,%dx				# carry on pass/error of
+						# e801h memory size call
+						# or merely pass cx,dx though
+						# without changing them.
 	movw	$0xe801, %ax
 	int	$0x15
 	jc	mem88
 
+	cmpw	$0x0, %cx			# Kludge to handle BIOSes
+	jne	e801usecxdx			# which report their extended
+	cmpw	$0x0, %dx			# memory in AX/BX rather than
+	jne	e801usecxdx			# CX/DX.  The spec I have read
+	movw	%ax, %cx			# seems to indicate AX/BX 
+	movw	%bx, %dx			# are more reasonable anyway...
+
+e801usecxdx:
 	andl	$0xffff, %edx			# clear sign extend
 	shll	$6, %edx			# and go from 64k to 1k chunks
 	movl	%edx, (0x1e0)			# store extended memory size
diff -u --recursive --new-file v2.4.4/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.4.4/linux/arch/i386/config.in	Fri Apr 20 18:26:15 2001
+++ linux/arch/i386/config.in	Mon Apr 30 16:59:06 2001
@@ -27,21 +27,21 @@
 mainmenu_option next_comment
 comment 'Processor type and features'
 choice 'Processor family' \
-	"386				CONFIG_M386 \
-	 486				CONFIG_M486 \
-	 586/K5/5x86/6x86/6x86MX	CONFIG_M586 \
-	 Pentium-Classic		CONFIG_M586TSC \
-	 Pentium-MMX			CONFIG_M586MMX \
-	 Pentium-Pro/Celeron/Pentium-II	CONFIG_M686 \
-	 Pentium-III			CONFIG_MPENTIUMIII \
-	 Pentium-4			CONFIG_MPENTIUM4 \
-	 K6/K6-II/K6-III		CONFIG_MK6 \
-	 Athlon/Duron/K7		CONFIG_MK7 \
-	 Crusoe				CONFIG_MCRUSOE \
-	 Winchip-C6			CONFIG_MWINCHIPC6 \
-	 Winchip-2			CONFIG_MWINCHIP2 \
-	 Winchip-2A/Winchip-3		CONFIG_MWINCHIP3D \
-	 CyrixIII/C3			CONFIG_MCYRIXIII" Pentium-Pro
+	"386					CONFIG_M386 \
+	 486					CONFIG_M486 \
+	 586/K5/5x86/6x86/6x86MX		CONFIG_M586 \
+	 Pentium-Classic			CONFIG_M586TSC \
+	 Pentium-MMX				CONFIG_M586MMX \
+	 Pentium-Pro/Celeron/Pentium-II		CONFIG_M686 \
+	 Pentium-III/Celeron(Coppermine)	CONFIG_MPENTIUMIII \
+	 Pentium-4				CONFIG_MPENTIUM4 \
+	 K6/K6-II/K6-III			CONFIG_MK6 \
+	 Athlon/Duron/K7			CONFIG_MK7 \
+	 Crusoe					CONFIG_MCRUSOE \
+	 Winchip-C6				CONFIG_MWINCHIPC6 \
+	 Winchip-2				CONFIG_MWINCHIP2 \
+	 Winchip-2A/Winchip-3			CONFIG_MWINCHIP3D \
+	 CyrixIII/C3				CONFIG_MCYRIXIII" Pentium-Pro
 #
 # Define implied options from the CPU selection here
 #
diff -u --recursive --new-file v2.4.4/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.4.4/linux/arch/i386/defconfig	Fri Apr 27 14:41:16 2001
+++ linux/arch/i386/defconfig	Mon Apr 30 17:55:05 2001
@@ -676,6 +676,7 @@
 CONFIG_USB_STORAGE=y
 # CONFIG_USB_STORAGE_DEBUG is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 
diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.4.4/linux/arch/i386/kernel/mtrr.c	Wed Apr 11 19:02:27 2001
+++ linux/arch/i386/kernel/mtrr.c	Tue May  1 16:04:56 2001
@@ -646,12 +646,32 @@
     unsigned long low;
 } centaur_mcr[8];
 
+static u8 centaur_mcr_reserved;
+static u8 centaur_mcr_type;		/* 0 for winchip, 1 for winchip2 */
+
+/*
+ *	Report boot time MCR setups 
+ */
+ 
+void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)
+{
+	centaur_mcr[mcr].low = lo;
+	centaur_mcr[mcr].high = hi;
+}
+
 static void centaur_get_mcr (unsigned int reg, unsigned long *base,
 			     unsigned long *size, mtrr_type *type)
 {
     *base = centaur_mcr[reg].high >> PAGE_SHIFT;
     *size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
     *type = MTRR_TYPE_WRCOMB;	/*  If it is there, it is write-combining  */
+    if(centaur_mcr_type==1 && ((centaur_mcr[reg].low&31)&2))
+    	*type = MTRR_TYPE_UNCACHABLE;
+    if(centaur_mcr_type==1 && (centaur_mcr[reg].low&31)==25)
+    	*type = MTRR_TYPE_WRBACK;
+    if(centaur_mcr_type==0 && (centaur_mcr[reg].low&31)==31)
+    	*type = MTRR_TYPE_WRBACK;
+    
 }   /*  End Function centaur_get_mcr  */
 
 static void (*get_mtrr) (unsigned int reg, unsigned long *base,
@@ -794,7 +814,15 @@
     else
     {
 	high = base << PAGE_SHIFT;
-	low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */
+	if(centaur_mcr_type == 0)
+		low = -size << PAGE_SHIFT | 0x1f; /* only support write-combining... */
+	else
+	{
+		if(type == MTRR_TYPE_UNCACHABLE)
+			low = -size << PAGE_SHIFT | 0x02;	/* NC */
+		else
+			low = -size << PAGE_SHIFT | 0x09;	/* WWO,WC */
+	}
     }
     centaur_mcr[reg].high = high;
     centaur_mcr[reg].low = low;
@@ -1104,6 +1132,28 @@
     return -ENOSPC;
 }   /*  End Function generic_get_free_region  */
 
+static int centaur_get_free_region (unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free MTRR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+    int i, max;
+    mtrr_type ltype;
+    unsigned long lbase, lsize;
+
+    max = get_num_var_ranges ();
+    for (i = 0; i < max; ++i)
+    {
+    	if(centaur_mcr_reserved & (1<<i))
+    		continue;
+	(*get_mtrr) (i, &lbase, &lsize, &ltype);
+	if (lsize == 0) return i;
+    }
+    return -ENOSPC;
+}   /*  End Function generic_get_free_region  */
+
 static int cyrix_get_free_region (unsigned long base, unsigned long size)
 /*  [SUMMARY] Get a free ARR.
     <base> The starting (base) address of the region.
@@ -1164,9 +1214,9 @@
  *
  *	The available types are
  *
- *	%MTRR_TYPE_UNCACHEABLE	-	No caching
+ *	%MTRR_TYPE_UNCACHABLE	-	No caching
  *
- *	%MTRR_TYPE_WRITEBACK	-	Write data back in bursts whenever
+ *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever
  *
  *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
  *
@@ -1229,9 +1279,13 @@
     case MTRR_IF_CENTAUR_MCR:
         if ( mtrr_if == MTRR_IF_CENTAUR_MCR )
 	{
-	    if (type != MTRR_TYPE_WRCOMB)
+	    /*
+	     *	FIXME: Winchip2 supports uncached
+	     */
+	    if (type != MTRR_TYPE_WRCOMB && (centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE))
 	    {
-		printk (KERN_WARNING "mtrr: only write-combining is supported\n");
+		printk (KERN_WARNING "mtrr: only write-combining%s supported\n",
+			centaur_mcr_type?" and uncacheable are":" is");
 		return -EINVAL;
 	    }
 	}
@@ -1348,9 +1402,9 @@
  *
  *	The available types are
  *
- *	%MTRR_TYPE_UNCACHEABLE	-	No caching
+ *	%MTRR_TYPE_UNCACHABLE	-	No caching
  *
- *	%MTRR_TYPE_WRITEBACK	-	Write data back in bursts whenever
+ *	%MTRR_TYPE_WRBACK	-	Write data back in bursts whenever
  *
  *	%MTRR_TYPE_WRCOMB	-	Write data back soon but allow bursts
  *
@@ -1947,23 +2001,64 @@
 {
     unsigned i;
     struct set_mtrr_context ctxt;
+    u32 lo, hi;
+    int wc2 = -1;
 
     set_mtrr_prepare (&ctxt);
     /* Unfortunately, MCR's are read-only, so there is no way to
      * find out what the bios might have done.
      */
-    /* Clear all MCR's.
+     
+    /*
+     *	Enable MCR key if we are using a winchip2
+     */
+     
+    if(boot_cpu_data.x86_model==4)
+    	wc2 = 0;
+    	
+    if(boot_cpu_data.x86_model==8 || boot_cpu_data.x86_model == 9)
+    {
+	    rdmsr(0x120, lo, hi);
+	    if(((lo>>17)&7)==1)		/* Type 1 Winchip2 MCR */
+	    {
+	    	lo&= ~0x1C0;		/* clear key */
+	    	lo|= 0x040;		/* set key to 1 */
+		wrmsr(0x120, lo, hi);	/* unlock MCR */
+		wc2 = 1;
+		centaur_mcr_type = 1;
+	    }
+    }    
+    /* Clear any unconfigured MCR's.
      * This way we are sure that the centaur_mcr array contains the actual
      * values. The disadvantage is that any BIOS tweaks are thus undone.
+     *
      */
     for (i = 0; i < 8; ++i)
     {
-        centaur_mcr[i].high = 0;
-	centaur_mcr[i].low = 0;
-	wrmsr (0x110 + i , 0, 0);
+    	if(centaur_mcr[i]. high == 0 && centaur_mcr[i].low == 0)
+    	{
+    		if(wc2 == 0 || ( wc2 == 1 && !(lo & (1<<(9+i)))))
+			wrmsr (0x110 + i , 0, 0);
+		else
+			/*
+			 *	If the BIOS set up an MCR we cannot see it
+			 *	but we don't wish to obliterate it
+			 */
+			centaur_mcr_reserved |= (1<<i);
+	}
+    }
+    /*  Throw the main write-combining switch... 
+        However if OOSTORE is enabled then people have already done far
+        cleverer things and we should behave. 
+     */
+
+    if(wc2 == 1)
+    {     
+	    lo |= 15;			/* Write combine enables */
+	    wrmsr(0x120, lo, hi);
     }
-    /*  Throw the main write-combining switch...  */
-    wrmsr (0x120, 0x01f0001f, 0);
+    else if(wc2 == 0)
+    	wrmsr(0x120, 0x01F0001F, 0);	/* Write only */
     set_mtrr_done (&ctxt);
 }   /*  End Function centaur_mcr_init  */
 
@@ -2036,6 +2131,7 @@
 	mtrr_if = MTRR_IF_CENTAUR_MCR;
 	get_mtrr = centaur_get_mcr;
 	set_mtrr_up = centaur_set_mcr_up;
+	get_free_region = centaur_get_free_region;
 	centaur_mcr_init();
 	size_or_mask  = 0xfff00000; /* 32 bits */
 	size_and_mask = 0;
diff -u --recursive --new-file v2.4.4/linux/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c
--- v2.4.4/linux/arch/i386/kernel/pci-irq.c	Fri Feb  9 11:29:44 2001
+++ linux/arch/i386/kernel/pci-irq.c	Tue May  1 16:04:56 2001
@@ -105,7 +105,7 @@
 		 *  known (ascending bus order) and therefore pci_scan_bus returns immediately.
 		 */
 		if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL))
-			printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i);
+			printk(KERN_INFO "PCI: Discovered primary peer bus %02x [IRQ]\n", i);
 	pcibios_last_bus = -1;
 }
 
@@ -295,10 +295,10 @@
 		case 0x61:
 		case 0x6a:
 		case 0x7e:
-			printk("SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
+			printk(KERN_INFO "SiS pirq: advanced IDE/ACPI/DAQ mapping not yet implemented\n");
 			return 0;
 		default:			
-			printk("SiS router pirq escape (%d)\n", pirq);
+			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
 			return 0;
 	}
 	return (x & 0x80) ? 0 : (x & 0x0f);
@@ -329,10 +329,10 @@
 		case 0x61:
 		case 0x6a:
 		case 0x7e:
-			printk("advanced SiS pirq mapping not yet implemented\n");
+			printk(KERN_INFO "advanced SiS pirq mapping not yet implemented\n");
 			return 0;
 		default:			
-			printk("SiS router pirq escape (%d)\n", pirq);
+			printk(KERN_INFO "SiS router pirq escape (%d)\n", pirq);
 			return 0;
 	}
 	pci_write_config_byte(router, reg, x);
@@ -351,7 +351,7 @@
 static int pirq_vlsi_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
 {
 	if (pirq > 8) {
-		printk("VLSI router pirq escape (%d)\n", pirq);
+		printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
 		return 0;
 	}
 	return read_config_nybble(router, 0x74, pirq-1);
@@ -360,7 +360,7 @@
 static int pirq_vlsi_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
 {
 	if (pirq > 8) {
-		printk("VLSI router pirq escape (%d)\n", pirq);
+		printk(KERN_INFO "VLSI router pirq escape (%d)\n", pirq);
 		return 0;
 	}
 	write_config_nybble(router, 0x74, pirq-1, irq);
@@ -439,7 +439,7 @@
 
 #ifdef CONFIG_PCI_BIOS
 	if (!rt->signature) {
-		printk("PCI: Using BIOS for IRQ routing\n");
+		printk(KERN_INFO "PCI: Using BIOS for IRQ routing\n");
 		pirq_router = &pirq_bios_router;
 		return;
 	}
@@ -464,7 +464,7 @@
 			pirq_router = r;
 		}
 	}
-	printk("PCI: Using IRQ router %s [%04x/%04x] at %s\n",
+	printk(KERN_INFO "PCI: Using IRQ router %s [%04x/%04x] at %s\n",
 		pirq_router->name,
 		pirq_router_dev->vendor,
 		pirq_router_dev->device,
@@ -568,7 +568,7 @@
 		} else
 			return 0;
 	}
-	printk("PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name);
+	printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name);
 
 	/* Update IRQ for all devices with the same pirq value */
 	pci_for_each_dev(dev2) {
@@ -582,13 +582,13 @@
 		if (info->irq[pin].link == pirq) {
 			/* We refuse to override the dev->irq information. Give a warning! */
 		    	if (dev2->irq && dev2->irq != irq) {
-		    		printk("IRQ routing conflict in pirq table for device %s\n", dev2->slot_name);
+		    		printk(KERN_INFO "IRQ routing conflict in pirq table for device %s\n", dev2->slot_name);
 		    		continue;
 		    	}
 			dev2->irq = irq;
 			pirq_penalty[irq]++;
 			if (dev != dev2)
-				printk("PCI: The same IRQ used for device %s\n", dev2->slot_name);
+				printk(KERN_INFO "PCI: The same IRQ used for device %s\n", dev2->slot_name);
 		}
 	}
 	return 1;
@@ -667,7 +667,7 @@
 				}
 #endif
 				if (irq >= 0) {
-					printk("PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
+					printk(KERN_INFO "PCI->APIC IRQ transform: (B%d,I%d,P%d) -> %d\n",
 						dev->bus->number, PCI_SLOT(dev->devfn), pin, irq);
 					dev->irq = irq;
 				}
diff -u --recursive --new-file v2.4.4/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.4.4/linux/arch/i386/mm/fault.c	Mon Mar 19 12:35:09 2001
+++ linux/arch/i386/mm/fault.c	Mon Apr 30 21:37:48 2001
@@ -322,12 +322,16 @@
 		/*
 		 * Synchronize this task's top level page-table
 		 * with the 'reference' page table.
+		 *
+		 * Do _not_ use "tsk" here. We might be inside
+		 * an interrupt in the middle of a task switch..
 		 */
 		int offset = __pgd_offset(address);
 		pgd_t *pgd, *pgd_k;
 		pmd_t *pmd, *pmd_k;
 
-		pgd = tsk->active_mm->pgd + offset;
+		asm("movl %%cr3,%0":"=r" (pgd));
+		pgd = offset + (pgd_t *)__va(pgd);
 		pgd_k = init_mm.pgd + offset;
 
 		if (!pgd_present(*pgd)) {
diff -u --recursive --new-file v2.4.4/linux/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c
--- v2.4.4/linux/drivers/acorn/block/mfmhd.c	Thu Oct 26 23:35:47 2000
+++ linux/drivers/acorn/block/mfmhd.c	Sat Apr 28 11:27:53 2001
@@ -1485,14 +1485,7 @@
 
 	for (i = maxp - 1; i >= 0; i--) {
 		int minor = start + i;
-		kdev_t devi = MKDEV(MAJOR_NR, minor);
-		struct super_block *sb = get_super(devi);
-
-		sync_dev (devi);
-		if (sb)
-			invalidate_inodes (sb);
-		invalidate_buffers (devi);
-
+		invalidate_device (MKDEV(MAJOR_NR, minor), 1);
 		mfm_gendisk.part[minor].start_sect = 0;
 		mfm_gendisk.part[minor].nr_sects = 0;
 	}
diff -u --recursive --new-file v2.4.4/linux/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- v2.4.4/linux/drivers/block/DAC960.c	Tue Feb 20 21:26:22 2001
+++ linux/drivers/block/DAC960.c	Sat Apr 28 11:27:53 2001
@@ -5134,16 +5134,12 @@
 						      PartitionNumber);
 	  int MinorNumber = DAC960_MinorNumber(LogicalDriveNumber,
 					       PartitionNumber);
-	  SuperBlock_T *SuperBlock = get_super(Device);
 	  if (Controller->GenericDiskInfo.part[MinorNumber].nr_sects == 0)
 	    continue;
 	  /*
 	    Flush all changes and invalidate buffered state.
 	  */
-	  sync_dev(Device);
-	  if (SuperBlock != NULL)
-	    invalidate_inodes(SuperBlock);
-	  invalidate_buffers(Device);
+	  invalidate_device(Device, 1);
 	  /*
 	    Clear existing partition sizes.
 	  */
diff -u --recursive --new-file v2.4.4/linux/drivers/block/acsi.c linux/drivers/block/acsi.c
--- v2.4.4/linux/drivers/block/acsi.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/block/acsi.c	Sat Apr 28 11:27:53 2001
@@ -1886,13 +1886,7 @@
 
 	for( i = max_p - 1; i >= 0 ; i-- ) {
 		if (gdev->part[start + i].nr_sects != 0) {
-			kdev_t devp = MKDEV(MAJOR_NR, start + i);
-			struct super_block *sb = get_super(devp);
-
-			fsync_dev(devp);
-			if (sb)
-				invalidate_inodes(sb);
-			invalidate_buffers(devp);
+			invalidate_device(MKDEV(MAJOR_NR, start + i), 1);
 			gdev->part[start + i].nr_sects = 0;
 		}
 		gdev->part[start+i].start_sect = 0;
diff -u --recursive --new-file v2.4.4/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v2.4.4/linux/drivers/block/amiflop.c	Sun Oct  1 20:35:15 2000
+++ linux/drivers/block/amiflop.c	Sat Apr 28 11:27:53 2001
@@ -1540,10 +1540,7 @@
 		break;
 	case FDFMTEND:
 		floppy_off(drive);
-		sb = get_super(inode->i_rdev);
-		if (sb)
-			invalidate_inodes(sb);
-		invalidate_buffers(inode->i_rdev);
+		invalidate_device(inode->i_rdev, 0);
 		break;
 	case FDGETPRM:
 		memset((void *)&getprm, 0, sizeof (getprm));
diff -u --recursive --new-file v2.4.4/linux/drivers/block/cciss.c linux/drivers/block/cciss.c
--- v2.4.4/linux/drivers/block/cciss.c	Fri Apr 13 20:26:07 2001
+++ linux/drivers/block/cciss.c	Tue May  1 16:05:00 2001
@@ -44,8 +44,8 @@
 #include <linux/genhd.h>
 
 #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq CISS Driver (v 2.4.2)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,2)
+#define DRIVER_NAME "Compaq CISS Driver (v 2.4.3)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,4,3)
 
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation");
@@ -125,10 +125,10 @@
 
         ctlr = h->ctlr;
         size = sprintf(buffer, "%s:  Compaq %s Controller\n"
-                "       Board ID: %08lx\n"
+                "       Board ID: 0x%08lx\n"
 		"       Firmware Version: %c%c%c%c\n"
-                "       Memory Address: %08lx\n"
-                "       IRQ: 0x%x\n"
+                "       Memory Address: 0x%08lx\n"
+                "       IRQ: %d\n"
                 "       Logical drives: %d\n"
                 "       Current Q depth: %d\n"
 		"       Current # commands on controller %d\n"
@@ -172,7 +172,7 @@
 static void __init cciss_procinit(int i)
 {
         if (proc_cciss == NULL) {
-                proc_cciss = proc_mkdir("driver/cciss", NULL);
+                proc_cciss = proc_mkdir("cciss", proc_root_driver);
                 if (!proc_cciss) 
 			return;
         }
@@ -691,13 +691,9 @@
         max_p = gdev->max_p;
         start = target << gdev->minor_shift;
 
-        for(i=max_p; i>=0; i--) {
+        for(i=max_p-1; i>=0; i--) {
                 int minor = start+i;
-                kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
-                struct super_block *sb = get_super(devi);
-                sync_dev(devi);
-                if (sb) invalidate_inodes(sb);
-                invalidate_buffers(devi);
+                invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
                 gdev->part[minor].start_sect = 0;
                 gdev->part[minor].nr_sects = 0;
 
@@ -1222,6 +1218,9 @@
 	struct request *creq;
 	u64bit temp64;
 
+    // Loop till the queue is empty if or it is plugged
+    while (1)
+    {
 	if (q->plugged || list_empty(queue_head)) {
                 start_io(h);
                 return;
@@ -1329,7 +1328,7 @@
 	h->Qdepth++;
 	if(h->Qdepth > h->maxQsinceinit)
 		h->maxQsinceinit = h->Qdepth; 
-	start_io(h);
+   }  // while loop
 }
 
 static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
@@ -1951,7 +1950,7 @@
 				}
 			}
 		}
-		remove_proc_entry("driver/cciss", &proc_root);
+		remove_proc_entry("cciss", proc_root_driver);
 		kfree(hba[i]->cmd_pool);
 		kfree(hba[i]->errinfo_pool);
                 kfree(hba[i]->cmd_pool_bits);
diff -u --recursive --new-file v2.4.4/linux/drivers/block/cciss_cmd.h linux/drivers/block/cciss_cmd.h
--- v2.4.4/linux/drivers/block/cciss_cmd.h	Fri Apr 13 20:26:07 2001
+++ linux/drivers/block/cciss_cmd.h	Tue May  1 16:05:00 2001
@@ -125,20 +125,20 @@
 //Command List Structure
 typedef union _SCSI3Addr_struct {
    struct {
+    BYTE Dev;
     BYTE Bus:6;
     BYTE Mode:2;        // b00
-    BYTE Dev;
   } PeripDev;
    struct {
+    BYTE DevLSB;
     BYTE DevMSB:6;
     BYTE Mode:2;        // b01
-    BYTE DevLSB;
   } LogDev;
    struct {
-    BYTE Targ:6;
-    BYTE Mode:2;        // b10
     BYTE Dev:5;
     BYTE Bus:3;
+    BYTE Targ:6;
+    BYTE Mode:2;        // b10
   } LogUnit;
 } SCSI3Addr_struct;
 
diff -u --recursive --new-file v2.4.4/linux/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- v2.4.4/linux/drivers/block/cpqarray.c	Tue Feb 13 14:13:43 2001
+++ linux/drivers/block/cpqarray.c	Tue May  1 16:05:00 2001
@@ -44,8 +44,8 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.2)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,2)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.3)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,3)
 
 /* Embedded module documentation macros - see modules.h */
 /* Original author Chris Frantz - Compaq Computer Corporation */
@@ -204,7 +204,7 @@
 static void __init ida_procinit(int i)
 {
 	if (proc_array == NULL) {
-		proc_array = proc_mkdir("driver/array", NULL);
+		proc_array = proc_mkdir("array", proc_root_driver);
 		if (!proc_array) return;
 	}
 
@@ -228,12 +228,12 @@
 
 	ctlr = h->ctlr;
 	size = sprintf(buffer, "%s:  Compaq %s Controller\n"
-		"       Board ID: %08lx\n"
+		"       Board ID: 0x%08lx\n"
 		"       Firmware Revision: %c%c%c%c\n"
-		"       Controller Sig: %08lx\n"
-		"       Memory Address: %08lx\n"
-		"       I/O Port: %04x\n"
-		"       IRQ: %x\n"
+		"       Controller Sig: 0x%08lx\n"
+		"       Memory Address: 0x%08lx\n"
+		"       I/O Port: 0x%04x\n"
+		"       IRQ: %d\n"
 		"       Logical drives: %d\n"
 		"       Physical drives: %d\n\n"
 		"       Current Q depth: %d\n"
@@ -314,7 +314,7 @@
 	int i;
 	struct gendisk *g;
 
-	remove_proc_entry("driver/array", NULL);
+	remove_proc_entry("array", proc_root_driver);
 
 	for(i=0; i<nr_ctlr; i++) {
 		hba[i]->access.set_intr_mask(hba[i], 0);
@@ -580,9 +580,11 @@
 		pdev = pci_find_device(ida_vendor_id[brdtype],
 				       ida_device_id[brdtype], NULL);
 		while (pdev) {
-			printk(KERN_DEBUG "cpqarray: Device %x has been found at %x %x\n",
+			printk(KERN_DEBUG "cpqarray: Device 0x%x has"
+				" been found at bus %d dev %d func %d\n",
 				ida_vendor_id[brdtype],
-				pdev->bus->number, pdev->devfn);
+				pdev->bus->number, PCI_SLOT(pdev->devfn),
+				PCI_FUNC(pdev->devfn));
 			if (nr_ctlr == 8) {
 				printk(KERN_WARNING "cpqarray: This driver"
 				" supports a maximum of 8 controllers.\n");
@@ -906,6 +908,9 @@
 	struct buffer_head *bh;
 	struct request *creq;
 
+// Loop till the queue is empty if or it is plugged 
+   while (1)
+{
 	if (q->plugged || list_empty(queue_head)) {
 		start_io(h);
 		return;
@@ -993,8 +998,7 @@
 	h->Qdepth++;
 	if (h->Qdepth > h->maxQsinceinit) 
 		h->maxQsinceinit = h->Qdepth;
-
-	start_io(h);
+   } // while loop
 }
 
 /* 
@@ -1574,13 +1578,9 @@
 	max_p = gdev->max_p;
 	start = target << gdev->minor_shift;
 
-	for(i=max_p; i>=0; i--) {
+	for(i=max_p-1; i>=0; i--) {
 		int minor = start+i;
-		kdev_t devi = MKDEV(MAJOR_NR + ctlr, minor);
-		struct super_block *sb = get_super(devi);
-		sync_dev(devi);
-		if (sb) invalidate_inodes(sb);
-		invalidate_buffers(devi);
+		invalidate_device(MKDEV(MAJOR_NR + ctlr, minor), 1);
 		gdev->part[minor].start_sect = 0;	
 		gdev->part[minor].nr_sects = 0;	
 
diff -u --recursive --new-file v2.4.4/linux/drivers/block/nbd.c linux/drivers/block/nbd.c
--- v2.4.4/linux/drivers/block/nbd.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/block/nbd.c	Tue May  1 14:20:25 2001
@@ -5,7 +5,8 @@
  * deadlocks sometimes - you can not swap over TCP in general.
  * 
  * Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
- * 
+ * Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
+ *
  * (part of code stolen from loop.c)
  *
  * 97-3-25 compiled 0-th version, not yet tested it 
@@ -20,6 +21,9 @@
  * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines <ankry@mif.pg.gda.pl>
  * 01-2-27 Fix to store proper blockcount for kernel (calculated using
  *   BLOCK_SIZE_BITS, not device blocksize) <aga@permonline.ru>
+ * 01-3-11 Make nbd work with new Linux block layer code. It now supports
+ *   plugging like all the other block devices. Also added in MSG_MORE to
+ *   reduce number of partial TCP segments sent. <steve@chygwyn.com>
  *
  * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
  * why not: would need verify_area and friends, would share yet another 
diff -u --recursive --new-file v2.4.4/linux/drivers/block/paride/pd.c linux/drivers/block/paride/pd.c
--- v2.4.4/linux/drivers/block/paride/pd.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/block/paride/pd.c	Sat Apr 28 11:27:53 2001
@@ -589,9 +589,6 @@
 
 {       int p, unit, minor;
         long flags;
-        kdev_t devp;
-
-	struct super_block *sb;
 
         unit = DEVICE_NR(dev);
         if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV;
@@ -607,13 +604,7 @@
 
         for (p=(PD_PARTNS-1);p>=0;p--) {
 		minor = p + unit*PD_PARTNS;
-                devp = MKDEV(MAJOR_NR, minor);
-                fsync_dev(devp);
-
-                sb = get_super(devp);
-                if (sb) invalidate_inodes(sb);
-
-                invalidate_buffers(devp);
+                invalidate_device(MKDEV(MAJOR_NR, minor), 1);
                 pd_hd[minor].start_sect = 0;
                 pd_hd[minor].nr_sects = 0;
         }
diff -u --recursive --new-file v2.4.4/linux/drivers/block/ps2esdi.c linux/drivers/block/ps2esdi.c
--- v2.4.4/linux/drivers/block/ps2esdi.c	Wed Apr 18 11:49:13 2001
+++ linux/drivers/block/ps2esdi.c	Tue May  1 16:05:00 2001
@@ -56,7 +56,7 @@
 #include <asm/uaccess.h>
 
 #define PS2ESDI_IRQ 14
-#define MAX_HD 1
+#define MAX_HD 2
 #define MAX_RETRIES 5
 #define MAX_16BIT 65536
 #define ESDI_TIMEOUT   0xf000
@@ -105,14 +105,14 @@
 
 static void ps2esdi_get_device_cfg(void);
 
-void ps2esdi_reset_timer(unsigned long unused);
+static void ps2esdi_reset_timer(unsigned long unused);
 
-u_int dma_arb_level;		/* DMA arbitration level */
+static u_int dma_arb_level;		/* DMA arbitration level */
 
 static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int);
 static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open);
 
-int no_int_yet;
+static int no_int_yet;
 static int access_count[MAX_HD];
 static char ps2esdi_valid[MAX_HD];
 static int ps2esdi_sizes[MAX_HD << 6];
@@ -123,26 +123,26 @@
 static struct timer_list esdi_timer = { function: ps2esdi_reset_timer };
 static int reset_status;
 static int ps2esdi_slot = -1;
-int tp720esdi = 0;		/* Is it Integrated ESDI of ThinkPad-720? */
-int intg_esdi = 0;              /* If integrated adapter */
+static int tp720esdi = 0;	/* Is it Integrated ESDI of ThinkPad-720? */
+static int intg_esdi = 0;       /* If integrated adapter */
 struct ps2esdi_i_struct {
 	unsigned int head, sect, cyl, wpcom, lzone, ctl;
 };
 
 #if 0
 #if 0				/* try both - I don't know which one is better... UB */
-struct ps2esdi_i_struct ps2esdi_info[] =
+static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
 {
 	{4, 48, 1553, 0, 0, 0},
 	{0, 0, 0, 0, 0, 0}};
 #else
-struct ps2esdi_i_struct ps2esdi_info[] =
+static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
 {
 	{64, 32, 161, 0, 0, 0},
 	{0, 0, 0, 0, 0, 0}};
 #endif
 #endif
-struct ps2esdi_i_struct ps2esdi_info[] =
+static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
 {
 	{0, 0, 0, 0, 0, 0},
 	{0, 0, 0, 0, 0, 0}};
@@ -191,9 +191,9 @@
 
 #ifdef MODULE
 
-int cyl[2] = {-1,-1};
-int head[2] = {-1, -1};
-int sect[2] = {-1, -1};
+static int cyl[MAX_HD] = {-1,-1};
+static int head[MAX_HD] = {-1, -1};
+static int sect[MAX_HD] = {-1, -1};
 
 MODULE_PARM(tp720esdi, "i");
 MODULE_PARM(cyl, "i");
@@ -203,7 +203,7 @@
 int init_module(void) {
 	int drive;
 
-	for(drive = 0; drive <= 1; drive++) {
+	for(drive = 0; drive < MAX_HD; drive++) {
 	        struct ps2_esdi_i_struct *info = &ps2esdi_info[drive];
 
         	if (cyl[drive] != -1) {
@@ -1145,15 +1145,9 @@
 	for (partition = ps2esdi_gendisk.max_p - 1;
 	     partition >= 0; partition--) {
 		int minor = (start | partition);
-		kdev_t devp = MKDEV(MAJOR_NR, minor);
-		struct super_block * sb = get_super(devp);
-		
-		sync_dev(devp);
-		if (sb)
-			invalidate_inodes(sb);
-		invalidate_buffers(devp);
-		ps2esdi_gendisk.part[start + partition].start_sect = 0;
-		ps2esdi_gendisk.part[start + partition].nr_sects = 0;
+		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
+		ps2esdi_gendisk.part[minor].start_sect = 0;
+		ps2esdi_gendisk.part[minor].nr_sects = 0;
 	}
 
 	grok_partitions(&ps2esdi_gendisk, target, 1<<6, 
@@ -1165,7 +1159,7 @@
 	return (0);
 }
 
-void ps2esdi_reset_timer(unsigned long unused)
+static void ps2esdi_reset_timer(unsigned long unused)
 {
 
 	int status;
diff -u --recursive --new-file v2.4.4/linux/drivers/block/smart1,2.h linux/drivers/block/smart1,2.h
--- v2.4.4/linux/drivers/block/smart1,2.h	Fri Jun 23 21:04:36 2000
+++ linux/drivers/block/smart1,2.h	Tue May  1 16:05:00 2001
@@ -45,7 +45,7 @@
 }
 
 /*  
- *  This card is the oposite of the other cards.  
+ *  This card is the opposite of the other cards.  
  *   0 turns interrupts on... 
  *   0x08 turns them off... 
  */
diff -u --recursive --new-file v2.4.4/linux/drivers/block/xd.c linux/drivers/block/xd.c
--- v2.4.4/linux/drivers/block/xd.c	Fri Feb 16 16:02:35 2001
+++ linux/drivers/block/xd.c	Sat Apr 28 11:27:53 2001
@@ -401,13 +401,7 @@
 
 	for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
 		int minor = (start | partition);
-		kdev_t devp = MKDEV(MAJOR_NR, minor);
-		struct super_block * sb = get_super(devp);
-		
-		sync_dev(devp);
-		if (sb)
-			invalidate_inodes(sb);
-		invalidate_buffers(devp);
+		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
 		xd_gendisk.part[minor].start_sect = 0;
 		xd_gendisk.part[minor].nr_sects = 0;
 	};
@@ -1163,16 +1157,6 @@
 	int partition,dev,start;
 
 	devfs_unregister_blkdev(MAJOR_NR, "xd");
-	for (dev = 0; dev < xd_drives; dev++) {
-		start = dev << xd_gendisk.minor_shift; 
-		for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
-			int minor = (start | partition);
-			kdev_t devp = MKDEV(MAJOR_NR, minor);
-			start = dev << xd_gendisk.minor_shift; 
-			sync_dev(devp);
-			invalidate_buffers(devp);
-		}
-	}
 	xd_done();
 	devfs_unregister (devfs_handle);
 	if (xd_drives) {
diff -u --recursive --new-file v2.4.4/linux/drivers/char/random.c linux/drivers/char/random.c
--- v2.4.4/linux/drivers/char/random.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/char/random.c	Tue May  1 16:05:00 2001
@@ -610,7 +610,7 @@
 static void batch_entropy_process(void *private_);
 
 /* note: the size must be a power of 2 */
-static int batch_entropy_init(int size, struct entropy_store *r)
+static int __init batch_entropy_init(int size, struct entropy_store *r)
 {
 	batch_entropy_pool = kmalloc(2*size*sizeof(__u32), GFP_KERNEL);
 	if (!batch_entropy_pool)
diff -u --recursive --new-file v2.4.4/linux/drivers/char/synclink.c linux/drivers/char/synclink.c
--- v2.4.4/linux/drivers/char/synclink.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/char/synclink.c	Tue May  1 16:05:00 2001
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * $Id: synclink.c,v 3.2 2000/11/06 22:34:38 paul Exp $
+ * $Id: synclink.c,v 3.8 2001/03/30 17:30:38 ez Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -107,8 +107,12 @@
 #endif
 
 #ifdef CONFIG_SYNCLINK_SYNCPPP
+#if LINUX_VERSION_CODE < VERSION(2,4,3) 
+#include "../net/wan/syncppp.h"
+#else
 #include <net/syncppp.h>
 #endif
+#endif
 
 #include <asm/segment.h>
 #define GET_USER(error,value,addr) error = get_user(value,addr)
@@ -176,6 +180,14 @@
 	int	cts_down;
 };
 
+/* transmit holding buffer definitions*/
+#define MAX_TX_HOLDING_BUFFERS 5
+struct tx_holding_buffer {
+	int	buffer_size;
+	unsigned char *	buffer;
+};
+
+
 /*
  * Device instance data structure
  */
@@ -241,11 +253,21 @@
 	DMABUFFERENTRY *rx_buffer_list;	/* list of receive buffer entries */
 	unsigned int current_rx_buffer;
 
+	int num_tx_dma_buffers;		/* number of tx dma frames required */
+ 	int tx_dma_buffers_used;
 	unsigned int tx_buffer_count;	/* count of total allocated Tx buffers */
 	DMABUFFERENTRY *tx_buffer_list;	/* list of transmit buffer entries */
+	int start_tx_dma_buffer;	/* tx dma buffer to start tx dma operation */
+	int current_tx_buffer;          /* next tx dma buffer to be loaded */
 	
 	unsigned char *intermediate_rxbuffer;
 
+	int num_tx_holding_buffers;	/* number of tx holding buffer allocated */
+	int get_tx_holding_index;  	/* next tx holding buffer for adapter to load */
+	int put_tx_holding_index;  	/* next tx holding buffer to store user request */
+	int tx_holding_count;		/* number of tx holding buffers waiting */
+	struct tx_holding_buffer tx_holding_buffers[MAX_TX_HOLDING_BUFFERS];
+
 	int rx_enabled;
 	int rx_overflow;
 
@@ -685,6 +707,8 @@
 #define usc_TCmd(a,b) usc_OutReg((a), TCSR, (u16)((a)->tcsr_value + (b)))
 #define usc_RCmd(a,b) usc_OutReg((a), RCSR, (b))
 
+#define usc_SetTransmitSyncChars(a,s0,s1) usc_OutReg((a), TSR, (u16)(((u16)s0<<8)|(u16)s1))
+
 void usc_process_rxoverrun_sync( struct mgsl_struct *info );
 void usc_start_receiver( struct mgsl_struct *info );
 void usc_stop_receiver( struct mgsl_struct *info );
@@ -775,7 +799,10 @@
  */
 void mgsl_free_rx_frame_buffers( struct mgsl_struct *info, unsigned int StartIndex, unsigned int EndIndex );
 int  mgsl_get_rx_frame( struct mgsl_struct *info );
+int  mgsl_get_raw_rx_frame( struct mgsl_struct *info );
 void mgsl_reset_rx_dma_buffers( struct mgsl_struct *info );
+void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info );
+int num_free_tx_dma_buffers(struct mgsl_struct *info);
 void mgsl_load_tx_dma_buffer( struct mgsl_struct *info, const char *Buffer, unsigned int BufferSize);
 void mgsl_load_pci_memory(char* TargetPtr, const char* SourcePtr, unsigned short count);
 
@@ -790,6 +817,10 @@
 void mgsl_free_buffer_list_memory(struct mgsl_struct *info);
 int mgsl_alloc_intermediate_rxbuffer_memory(struct mgsl_struct *info);
 void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info);
+int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info);
+void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info);
+int load_next_tx_holding_buffer(struct mgsl_struct *info);
+int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize);
 
 /*
  * Bottom half interrupt handlers
@@ -810,6 +841,7 @@
 void mgsl_isr_io_pin( struct mgsl_struct *info );
 void mgsl_isr_misc( struct mgsl_struct *info );
 void mgsl_isr_receive_dma( struct mgsl_struct *info );
+void mgsl_isr_transmit_dma( struct mgsl_struct *info );
 
 typedef void (*isr_dispatch_func)(struct mgsl_struct *);
 
@@ -874,6 +906,8 @@
 static int debug_level = 0;
 static int maxframe[MAX_TOTAL_DEVICES] = {0,};
 static int dosyncppp[MAX_TOTAL_DEVICES] = {0,};
+static int txdmabufs[MAX_TOTAL_DEVICES] = {0,};
+static int txholdbufs[MAX_TOTAL_DEVICES] = {0,};
 	
 MODULE_PARM(break_on_load,"i");
 MODULE_PARM(ttymajor,"i");
@@ -884,9 +918,11 @@
 MODULE_PARM(debug_level,"i");
 MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
+MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
+MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "3.2";
+static char *driver_version = "3.8";
 
 static int __init synclink_init_one (struct pci_dev *dev,
 				     const struct pci_device_id *ent);
@@ -1096,11 +1132,14 @@
 
 void mgsl_bh_receive(struct mgsl_struct *info)
 {
+	int (*get_rx_frame)(struct mgsl_struct *info) =
+		(info->params.mode == MGSL_MODE_HDLC ? mgsl_get_rx_frame : mgsl_get_raw_rx_frame);
+
 	if ( debug_level >= DEBUG_LEVEL_BH )
 		printk( "%s(%d):mgsl_bh_receive(%s)\n",
 			__FILE__,__LINE__,info->device_name);
 	
-	while( mgsl_get_rx_frame(info) );
+	while( (get_rx_frame)(info) );
 }
 
 void mgsl_bh_transmit(struct mgsl_struct *info)
@@ -1318,11 +1357,6 @@
 #endif
 			} else
 				info->input_signal_events.dcd_down++;
-#ifdef CONFIG_HARD_PPS
-			if ((info->flags & ASYNC_HARDPPS_CD) &&
-			    (status & MISCSTATUS_DCD_LATCHED))
-				hardpps();
-#endif
 		}
 		if (status & MISCSTATUS_CTS_LATCHED)
 		{
@@ -1609,6 +1643,58 @@
 
 }	/* end of mgsl_isr_receive_dma() */
 
+/* mgsl_isr_transmit_dma()
+ *
+ *	This function services a transmit DMA channel interrupt.
+ *
+ *	For this driver there is one source of transmit DMA interrupts
+ *	as identified in the Transmit DMA Mode Register (TDMR):
+ *
+ *     	BIT2  EOB       End of Buffer. This interrupt occurs when a
+ *     			transmit DMA buffer has been emptied.
+ *
+ *     	The driver maintains enough transmit DMA buffers to hold at least
+ *     	one max frame size transmit frame. When operating in a buffered
+ *     	transmit mode, there may be enough transmit DMA buffers to hold at
+ *     	least two or more max frame size frames. On an EOB condition,
+ *     	determine if there are any queued transmit buffers and copy into
+ *     	transmit DMA buffers if we have room.
+ *
+ * Arguments:		info		pointer to device instance data
+ * Return Value:	None
+ */
+void mgsl_isr_transmit_dma( struct mgsl_struct *info )
+{
+	u16 status;
+
+	/* clear interrupt pending and IUS bit for Tx DMA IRQ */
+	usc_OutDmaReg(info, CDIR, BIT8+BIT0 );
+
+	/* Read the transmit DMA status to identify interrupt type. */
+	/* This also clears the status bits. */
+
+	status = usc_InDmaReg( info, TDMR );
+
+	if ( debug_level >= DEBUG_LEVEL_ISR )
+		printk("%s(%d):mgsl_isr_transmit_dma(%s) status=%04X\n",
+			__FILE__,__LINE__,info->device_name,status);
+
+	if ( status & BIT2 ) {
+		--info->tx_dma_buffers_used;
+
+		/* if there are transmit frames queued,
+		 *  try to load the next one
+		 */
+		if ( load_next_tx_holding_buffer(info) ) {
+			/* if call returns non-zero value, we have
+			 * at least one free tx holding buffer
+			 */
+			info->pending_bh |= BH_TRANSMIT;
+		}
+	}
+
+}	/* end of mgsl_isr_transmit_dma() */
+
 /* mgsl_interrupt()
  * 
  * 	Interrupt service routine entry point.
@@ -1652,6 +1738,8 @@
 		/* Dispatch interrupt vector */
 		if ( UscVector )
 			(*UscIsrTable[UscVector])(info);
+		else if ( (DmaVector&(BIT10|BIT9)) == BIT10)
+			mgsl_isr_transmit_dma(info);
 		else
 			mgsl_isr_receive_dma(info);
 
@@ -1818,7 +1906,9 @@
 	usc_stop_transmitter(info);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 	
-	if (info->params.mode == MGSL_MODE_HDLC || info->netcount)
+	if (info->params.mode == MGSL_MODE_HDLC ||
+	    info->params.mode == MGSL_MODE_RAW ||
+	    info->netcount)
 		usc_set_sync_mode(info);
 	else
 		usc_set_async_mode(info);
@@ -1970,8 +2060,7 @@
 
 	spin_lock_irqsave(&info->irq_spinlock,flags);
 	
-	if ( (info->params.mode != MGSL_MODE_HDLC) || 
-	     !info->tx_active ) {
+	if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) {
 	
 		if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) {
 			info->xmit_buf[info->xmit_head++] = ch;
@@ -2015,8 +2104,8 @@
 	spin_lock_irqsave(&info->irq_spinlock,flags);
 	
 	if (!info->tx_active) {
-		if ( (info->params.mode == MGSL_MODE_HDLC) &&
-			info->xmit_cnt ) {
+		if ( (info->params.mode == MGSL_MODE_HDLC ||
+			info->params.mode == MGSL_MODE_RAW) && info->xmit_cnt ) {
 			/* operating in synchronous (frame oriented) mode */
 			/* copy data from circular xmit_buf to */
 			/* transmit DMA buffer. */
@@ -2060,11 +2149,51 @@
 	if (!tty || !info->xmit_buf || !tmp_buf)
 		goto cleanup;
 
-	if ( info->params.mode == MGSL_MODE_HDLC ) {
+	if ( info->params.mode == MGSL_MODE_HDLC ||
+			info->params.mode == MGSL_MODE_RAW ) {
+		/* operating in synchronous (frame oriented) mode */
 		/* operating in synchronous (frame oriented) mode */
-
 		if (info->tx_active) {
-			ret = 0; goto cleanup; 
+
+			if ( info->params.mode == MGSL_MODE_HDLC ) {
+				ret = 0;
+				goto cleanup;
+			}
+			/* transmitter is actively sending data -
+			 * if we have multiple transmit dma and
+			 * holding buffers, attempt to queue this
+			 * frame for transmission at a later time.
+			 */
+			if (info->tx_holding_count >= info->num_tx_holding_buffers ) {
+				/* no tx holding buffers available */
+				ret = 0;
+				goto cleanup;
+			}
+
+			/* queue transmit frame request */
+			ret = count;
+			if (from_user) {
+				down(&tmp_buf_sem);
+				COPY_FROM_USER(err,tmp_buf, buf, count);
+				if (err) {
+					if ( debug_level >= DEBUG_LEVEL_INFO )
+						printk( "%s(%d):mgsl_write(%s) sync user buf copy failed\n",
+							__FILE__,__LINE__,info->device_name);
+					ret = -EFAULT;
+				} else
+					save_tx_buffer_request(info,tmp_buf,count);
+				up(&tmp_buf_sem);
+			}
+			else
+				save_tx_buffer_request(info,buf,count);
+
+			/* if we have sufficient tx dma buffers,
+			 * load the next buffered tx request
+			 */
+			spin_lock_irqsave(&info->irq_spinlock,flags);
+			load_next_tx_holding_buffer(info);
+			spin_unlock_irqrestore(&info->irq_spinlock,flags);
+			goto cleanup;
 		}
 	
 		/* if operating in HDLC LoopMode and the adapter  */
@@ -2200,7 +2329,8 @@
 		printk("%s(%d):mgsl_write_room(%s)=%d\n",
 			 __FILE__,__LINE__, info->device_name,ret );
 			 
-	if ( info->params.mode == MGSL_MODE_HDLC ) {
+	if ( info->params.mode == MGSL_MODE_HDLC ||
+		info->params.mode == MGSL_MODE_RAW ) {
 		/* operating in synchronous (frame oriented) mode */
 		if ( info->tx_active )
 			return 0;
@@ -2234,10 +2364,11 @@
 		printk("%s(%d):mgsl_chars_in_buffer(%s)=%d\n",
 			 __FILE__,__LINE__, info->device_name,info->xmit_cnt );
 			 
-	if ( info->params.mode == MGSL_MODE_HDLC ) {
+	if ( info->params.mode == MGSL_MODE_HDLC ||
+		info->params.mode == MGSL_MODE_RAW ) {
 		/* operating in synchronous (frame oriented) mode */
 		if ( info->tx_active )
-			return info->tx_buffer_list[0].rcc;
+			return info->max_frame_size;
 		else
 			return 0;
 	}
@@ -2627,11 +2758,11 @@
  	unsigned long flags;
 	int s;
 	int rc=0;
-	u16 regval;
 	struct mgsl_icount cprev, cnow;
-	int events = 0;
+	int events;
 	int mask;
-	struct	_input_signal_events signal_events_prev, signal_events_now;
+	struct	_input_signal_events oldsigs, newsigs;
+	DECLARE_WAITQUEUE(wait, current);
 
 	COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
 	if (rc) {
@@ -2644,114 +2775,99 @@
 
 	spin_lock_irqsave(&info->irq_spinlock,flags);
 
+	/* return immediately if state matches requested events */
 	usc_get_serial_signals(info);
 	s = info->serial_signals;
+	events = mask &
+		( ((s & SerialSignal_DSR) ? MgslEvent_DsrActive:MgslEvent_DsrInactive) +
+ 		  ((s & SerialSignal_DCD) ? MgslEvent_DcdActive:MgslEvent_DcdInactive) +
+		  ((s & SerialSignal_CTS) ? MgslEvent_CtsActive:MgslEvent_CtsInactive) +
+		  ((s & SerialSignal_RI)  ? MgslEvent_RiActive :MgslEvent_RiInactive) );
+	if (events) {
+		spin_unlock_irqrestore(&info->irq_spinlock,flags);
+		goto exit;
+	}
 
-	/* note the counters on entry */
+	/* save current irq counts */
 	cprev = info->icount;
-	signal_events_prev = info->input_signal_events;
+	oldsigs = info->input_signal_events;
 	
-	if (mask & MgslEvent_ExitHuntMode) {
-		/* enable exit hunt mode IRQ */
-		regval = usc_InReg(info,RICR);
-		if (!(regval & RXSTATUS_EXITED_HUNT))
-			usc_OutReg(info, RICR, regval | RXSTATUS_EXITED_HUNT);
+	/* enable hunt and idle irqs if needed */
+	if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
+		u16 oldreg = usc_InReg(info,RICR);
+		u16 newreg = oldreg +
+			 (mask & MgslEvent_ExitHuntMode ? RXSTATUS_EXITED_HUNT:0) +
+			 (mask & MgslEvent_IdleReceived ? RXSTATUS_IDLE_RECEIVED:0);
+		if (oldreg != newreg)
+			usc_OutReg(info, RICR, newreg);
 	}
 	
-	if (mask & MgslEvent_IdleReceived) {
-		/* enable idle mode received IRQ */
-		regval = usc_InReg(info,RICR);
-		if (!(regval & RXSTATUS_IDLE_RECEIVED))
-			usc_OutReg(info, RICR, regval | RXSTATUS_IDLE_RECEIVED);
-	}
+	set_current_state(TASK_INTERRUPTIBLE);
+	add_wait_queue(&info->event_wait_q, &wait);
 	
 	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 	
-	/* Determine if any user requested events for input signals is currently TRUE */
-	
-	events |= (mask & ((s & SerialSignal_DSR) ?
-			MgslEvent_DsrActive:MgslEvent_DsrInactive));
-
-	events |= (mask & ((s & SerialSignal_DCD) ?
-			MgslEvent_DcdActive:MgslEvent_DcdInactive));
-		
-	events |= (mask & ((s & SerialSignal_CTS) ?
-			MgslEvent_CtsActive:MgslEvent_CtsInactive));
-		
-	events |= (mask & ((s & SerialSignal_RI) ?
-			MgslEvent_RiActive:MgslEvent_RiInactive));
-	
 
-	while(!events) {
-		/* sleep until event occurs */
-		interruptible_sleep_on(&info->event_wait_q);
-		
-		/* see if a signal woke us */
+	for(;;) {
+		schedule();
 		if (signal_pending(current)) {
 			rc = -ERESTARTSYS;
 			break;
 		}
 			
+		/* get current irq counts */
 		spin_lock_irqsave(&info->irq_spinlock,flags);
-
-		/* get icount and serial signal states */
 		cnow = info->icount;
-		signal_events_now = info->input_signal_events;
+		newsigs = info->input_signal_events;
+		set_current_state(TASK_INTERRUPTIBLE);
 		spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
-		if (signal_events_now.dsr_up != signal_events_prev.dsr_up && 
-				mask & MgslEvent_DsrActive )
-			events |= MgslEvent_DsrActive;
-		
-		if (signal_events_now.dsr_down != signal_events_prev.dsr_down && 
-				mask & MgslEvent_DsrInactive )
-			events |= MgslEvent_DsrInactive;
-
-		if (signal_events_now.dcd_up != signal_events_prev.dcd_up &&
-				mask & MgslEvent_DcdActive )
-			events |= MgslEvent_DcdActive;
-		
-		if (signal_events_now.dcd_down != signal_events_prev.dcd_down &&
-				mask & MgslEvent_DcdInactive )
-			events |= MgslEvent_DcdInactive;
-		
-		if (signal_events_now.cts_up != signal_events_prev.cts_up &&
-				mask & MgslEvent_CtsActive )
-			events |= MgslEvent_CtsActive;
-		
-		if (signal_events_now.cts_down != signal_events_prev.cts_down &&
-				mask & MgslEvent_CtsInactive )
-			events |= MgslEvent_CtsInactive;
-		
-		if (signal_events_now.ri_up != signal_events_prev.ri_up &&
-				mask & MgslEvent_RiActive )
-			events |= MgslEvent_RiActive;
-		
-		if (signal_events_now.ri_down != signal_events_prev.ri_down &&
-				mask & MgslEvent_RiInactive )
-			events |= MgslEvent_RiInactive;
-		
-		if (cnow.exithunt != cprev.exithunt)
-			events |= (mask & MgslEvent_ExitHuntMode);
+		/* if no change, wait aborted for some reason */
+		if (newsigs.dsr_up   == oldsigs.dsr_up   &&
+		    newsigs.dsr_down == oldsigs.dsr_down &&
+		    newsigs.dcd_up   == oldsigs.dcd_up   &&
+		    newsigs.dcd_down == oldsigs.dcd_down &&
+		    newsigs.cts_up   == oldsigs.cts_up   &&
+		    newsigs.cts_down == oldsigs.cts_down &&
+		    newsigs.ri_up    == oldsigs.ri_up    &&
+		    newsigs.ri_down  == oldsigs.ri_down  &&
+		    cnow.exithunt    == cprev.exithunt   &&
+		    cnow.rxidle      == cprev.rxidle) {
+			rc = -EIO;
+			break;
+		}
 
-		if (cnow.rxidle != cprev.rxidle)
-			events |= (mask & MgslEvent_IdleReceived);
+		events = mask &
+			( (newsigs.dsr_up   != oldsigs.dsr_up   ? MgslEvent_DsrActive:0)   +
+			(newsigs.dsr_down != oldsigs.dsr_down ? MgslEvent_DsrInactive:0) +
+			(newsigs.dcd_up   != oldsigs.dcd_up   ? MgslEvent_DcdActive:0)   +
+			(newsigs.dcd_down != oldsigs.dcd_down ? MgslEvent_DcdInactive:0) +
+			(newsigs.cts_up   != oldsigs.cts_up   ? MgslEvent_CtsActive:0)   +
+			(newsigs.cts_down != oldsigs.cts_down ? MgslEvent_CtsInactive:0) +
+			(newsigs.ri_up    != oldsigs.ri_up    ? MgslEvent_RiActive:0)    +
+			(newsigs.ri_down  != oldsigs.ri_down  ? MgslEvent_RiInactive:0)  +
+			(cnow.exithunt    != cprev.exithunt   ? MgslEvent_ExitHuntMode:0) +
+			  (cnow.rxidle      != cprev.rxidle     ? MgslEvent_IdleReceived:0) );
+		if (events)
+			break;
 		
 		cprev = cnow;
-		signal_events_prev = signal_events_now;
+		oldsigs = newsigs;
 	}
 	
+	remove_wait_queue(&info->event_wait_q, &wait);
+	set_current_state(TASK_RUNNING);
+
 	if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
 		spin_lock_irqsave(&info->irq_spinlock,flags);
 		if (!waitqueue_active(&info->event_wait_q)) {
 			/* disable enable exit hunt mode/idle rcvd IRQs */
-			regval = usc_InReg(info,RICR);
-			usc_OutReg(info, RICR, regval & 
+			usc_OutReg(info, RICR, usc_InReg(info,RICR) &
 				~(RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED));
 		}
 		spin_unlock_irqrestore(&info->irq_spinlock,flags);
 	}
-
+exit:
 	if ( rc == 0 )
 		PUT_USER(rc, events, mask_ptr);
 		
@@ -2759,6 +2875,56 @@
 	
 }	/* end of mgsl_wait_event() */
 
+static int modem_input_wait(struct mgsl_struct *info,int arg)
+{
+ 	unsigned long flags;
+	int rc;
+	struct mgsl_icount cprev, cnow;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* save current irq counts */
+	spin_lock_irqsave(&info->irq_spinlock,flags);
+	cprev = info->icount;
+	add_wait_queue(&info->status_event_wait_q, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+	for(;;) {
+		schedule();
+		if (signal_pending(current)) {
+			rc = -ERESTARTSYS;
+			break;
+		}
+
+		/* get new irq counts */
+		spin_lock_irqsave(&info->irq_spinlock,flags);
+		cnow = info->icount;
+		set_current_state(TASK_INTERRUPTIBLE);
+		spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+		/* if no change, wait aborted for some reason */
+		if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+		    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
+			rc = -EIO;
+			break;
+		}
+
+		/* check for change in caller specified modem input */
+		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)) {
+			rc = 0;
+			break;
+		}
+
+		cprev = cnow;
+	}
+	remove_wait_queue(&info->status_event_wait_q, &wait);
+	set_current_state(TASK_RUNNING);
+	return rc;
+}
+
 /* get_modem_info()
  * 
  * 	Read the state of the serial control and
@@ -2926,7 +3092,7 @@
 int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg)
 {
 	int error;
-	struct mgsl_icount cprev, cnow;	/* kernel counter temps */
+	struct mgsl_icount cnow;	/* kernel counter temps */
 	struct serial_icounter_struct *p_cuser;	/* user space */
 	unsigned long flags;
 	
@@ -2961,37 +3127,12 @@
 			while(MOD_IN_USE)
 				MOD_DEC_USE_COUNT;
 			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
+
+		/* Wait for modem input (DCD,RI,DSR,CTS) change
+		 * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS)
 		 */
 		case TIOCMIWAIT:
-			spin_lock_irqsave(&info->irq_spinlock,flags);
-			/* note the counters on entry */
-			cprev = info->icount;
-			spin_unlock_irqrestore(&info->irq_spinlock,flags);
-			while (1) {
-				interruptible_sleep_on(&info->status_event_wait_q);
-				/* see if a signal did it */
-				if (signal_pending(current))
-					return -ERESTARTSYS;
-				save_flags(flags); cli();
-				cnow = info->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 */
+			return modem_input_wait(info,(int)arg);
 
 		/* 
 		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
@@ -3243,7 +3384,8 @@
 	if (timeout)
 		char_time = MIN(char_time, timeout);
 		
-	if ( info->params.mode == MGSL_MODE_HDLC ) {
+	if ( info->params.mode == MGSL_MODE_HDLC ||
+		info->params.mode == MGSL_MODE_RAW ) {
 		while (info->tx_active) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(char_time);
@@ -3601,7 +3743,8 @@
 	if (info->serial_signals & SerialSignal_RI)
 		strcat(stat_buf, "|RI");
 
-	if (info->params.mode == MGSL_MODE_HDLC) {
+	if (info->params.mode == MGSL_MODE_HDLC ||
+	    info->params.mode == MGSL_MODE_RAW ) {
 		ret += sprintf(buf+ret, " HDLC txok:%d rxok:%d",
 			      info->icount.txok, info->icount.rxok);
 		if (info->icount.txunder)
@@ -3742,15 +3885,15 @@
 		 *
 		 * This leaves 62 4K pages.
 		 *
-		 * The next N pages are used for a transmit frame. We
-		 * reserve enough 4K page blocks to hold the configured
-		 * MaxFrameSize
+		 * The next N pages are used for transmit frame(s). We
+		 * reserve enough 4K page blocks to hold the required
+		 * number of transmit dma buffers (num_tx_dma_buffers),
+		 * each of MaxFrameSize size.
 		 *
 		 * Of the remaining pages (62-N), determine how many can
 		 * be used to receive full MaxFrameSize inbound frames
 		 */
-		
-		info->tx_buffer_count = BuffersPerFrame;
+		info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame;
 		info->rx_buffer_count = 62 - info->tx_buffer_count;
 	} else {
 		/* Calculate the number of PAGE_SIZE buffers needed for */
@@ -3763,7 +3906,7 @@
 		/* End of List condition if all receive buffers are used when */
 		/* using linked list DMA buffers. */
 
-		info->tx_buffer_count = BuffersPerFrame;
+		info->tx_buffer_count = info->num_tx_dma_buffers * BuffersPerFrame;
 		info->rx_buffer_count = (BuffersPerFrame * MAXRXFRAMES) + 6;
 		
 		/* 
@@ -3783,12 +3926,14 @@
 	if ( mgsl_alloc_buffer_list_memory( info ) < 0 ||
 		  mgsl_alloc_frame_memory(info, info->rx_buffer_list, info->rx_buffer_count) < 0 || 
 		  mgsl_alloc_frame_memory(info, info->tx_buffer_list, info->tx_buffer_count) < 0 || 
-		  mgsl_alloc_intermediate_rxbuffer_memory(info) < 0 ) {
+		  mgsl_alloc_intermediate_rxbuffer_memory(info) < 0  ||
+		  mgsl_alloc_intermediate_txbuffer_memory(info) < 0 ) {
 		printk("%s(%d):Can't allocate DMA buffer memory\n",__FILE__,__LINE__);
 		return -ENOMEM;
 	}
 	
 	mgsl_reset_rx_dma_buffers( info );
+  	mgsl_reset_tx_dma_buffers( info );
 
 	return 0;
 
@@ -4044,6 +4189,149 @@
 
 }	/* end of mgsl_free_intermediate_rxbuffer_memory() */
 
+/*
+ * mgsl_alloc_intermediate_txbuffer_memory()
+ *
+ * 	Allocate intermdiate transmit buffer(s) large enough to hold max_frame_size.
+ * 	This buffer is used to load transmit frames into the adapter's dma transfer
+ * 	buffers when there is sufficient space.
+ *
+ * Arguments:
+ *
+ *	info		pointer to device instance data
+ *
+ * Return Value:	0 if success, otherwise -ENOMEM
+ */
+int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info)
+{
+	int i;
+
+	if ( debug_level >= DEBUG_LEVEL_INFO )
+		printk("%s %s(%d)  allocating %d tx holding buffers\n",
+				info->device_name, __FILE__,__LINE__,info->num_tx_holding_buffers);
+
+	memset(info->tx_holding_buffers,0,sizeof(info->tx_holding_buffers));
+
+	for ( i=0; i<info->num_tx_holding_buffers; ++i) {
+		info->tx_holding_buffers[i].buffer =
+			kmalloc(info->max_frame_size, GFP_KERNEL);
+		if ( info->tx_holding_buffers[i].buffer == NULL )
+			return -ENOMEM;
+	}
+
+	return 0;
+
+}	/* end of mgsl_alloc_intermediate_txbuffer_memory() */
+
+/*
+ * mgsl_free_intermediate_txbuffer_memory()
+ *
+ *
+ * Arguments:
+ *
+ *	info		pointer to device instance data
+ *
+ * Return Value:	None
+ */
+void mgsl_free_intermediate_txbuffer_memory(struct mgsl_struct *info)
+{
+	int i;
+
+	for ( i=0; i<info->num_tx_holding_buffers; ++i ) {
+		if ( info->tx_holding_buffers[i].buffer ) {
+				kfree(info->tx_holding_buffers[i].buffer);
+				info->tx_holding_buffers[i].buffer=NULL;
+		}
+	}
+
+	info->get_tx_holding_index = 0;
+	info->put_tx_holding_index = 0;
+	info->tx_holding_count = 0;
+
+}	/* end of mgsl_free_intermediate_txbuffer_memory() */
+
+
+/*
+ * load_next_tx_holding_buffer()
+ *
+ * attempts to load the next buffered tx request into the
+ * tx dma buffers
+ *
+ * Arguments:
+ *
+ *	info		pointer to device instance data
+ *
+ * Return Value:	1 if next buffered tx request loaded
+ * 			into adapter's tx dma buffer,
+ * 			0 otherwise
+ */
+int load_next_tx_holding_buffer(struct mgsl_struct *info)
+{
+	int ret = 0;
+
+	if ( info->tx_holding_count ) {
+		/* determine if we have enough tx dma buffers
+		 * to accomodate the next tx frame
+		 */
+		struct tx_holding_buffer *ptx =
+			&info->tx_holding_buffers[info->get_tx_holding_index];
+		int num_free = num_free_tx_dma_buffers(info);
+		int num_needed = ptx->buffer_size / DMABUFFERSIZE;
+		if ( ptx->buffer_size % DMABUFFERSIZE )
+			++num_needed;
+
+		if (num_needed <= num_free) {
+			info->xmit_cnt = ptx->buffer_size;
+			mgsl_load_tx_dma_buffer(info,ptx->buffer,ptx->buffer_size);
+
+			--info->tx_holding_count;
+			if ( ++info->get_tx_holding_index >= info->num_tx_holding_buffers)
+				info->get_tx_holding_index=0;
+
+			/* restart transmit timer */
+			del_timer(&info->tx_timer);
+			info->tx_timer.expires = jiffies + jiffies_from_ms(5000);
+			add_timer(&info->tx_timer);
+
+			ret = 1;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * save_tx_buffer_request()
+ *
+ * attempt to store transmit frame request for later transmission
+ *
+ * Arguments:
+ *
+ *	info		pointer to device instance data
+ * 	Buffer		pointer to buffer containing frame to load
+ * 	BufferSize	size in bytes of frame in Buffer
+ *
+ * Return Value:	1 if able to store, 0 otherwise
+ */
+int save_tx_buffer_request(struct mgsl_struct *info,const char *Buffer, unsigned int BufferSize)
+{
+	struct tx_holding_buffer *ptx;
+
+	if ( info->tx_holding_count >= info->num_tx_holding_buffers ) {
+		return 0;	        /* all buffers in use */
+	}
+
+	ptx = &info->tx_holding_buffers[info->put_tx_holding_index];
+	ptx->buffer_size = BufferSize;
+	memcpy( ptx->buffer, Buffer, BufferSize);
+
+	++info->tx_holding_count;
+	if ( ++info->put_tx_holding_index >= info->num_tx_holding_buffers)
+		info->put_tx_holding_index=0;
+
+	return 1;
+}
+
 int mgsl_claim_resources(struct mgsl_struct *info)
 {
 	if (request_region(info->io_base,info->io_addr_size,"synclink") == NULL) {
@@ -4120,7 +4408,7 @@
 	return 0;
 errout:
 	mgsl_release_resources(info);
-	return ENODEV;
+	return -ENODEV;
 
 }	/* end of mgsl_claim_resources() */
 
@@ -4141,6 +4429,7 @@
 	}
 	mgsl_free_dma_buffers(info);
 	mgsl_free_intermediate_rxbuffer_memory(info);
+     	mgsl_free_intermediate_txbuffer_memory(info);
 	
 	if ( info->io_addr_requested ) {
 		release_region(info->io_base,info->io_addr_size);
@@ -4187,6 +4476,20 @@
 		if (maxframe[info->line])
 			info->max_frame_size = maxframe[info->line];
 		info->dosyncppp = dosyncppp[info->line];
+
+		if (txdmabufs[info->line]) {
+			info->num_tx_dma_buffers = txdmabufs[info->line];
+			if (info->num_tx_dma_buffers < 1)
+				info->num_tx_dma_buffers = 1;
+		}
+
+		if (txholdbufs[info->line]) {
+			info->num_tx_holding_buffers = txholdbufs[info->line];
+			if (info->num_tx_holding_buffers < 1)
+				info->num_tx_holding_buffers = 1;
+			else if (info->num_tx_holding_buffers > MAX_TX_HOLDING_BUFFERS)
+				info->num_tx_holding_buffers = MAX_TX_HOLDING_BUFFERS;
+		}
 	}
 
 	mgsl_device_count++;
@@ -4255,6 +4558,8 @@
 		spin_lock_init(&info->netlock);
 		memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS));
 		info->idle_mode = HDLC_TXIDLE_FLAGS;		
+		info->num_tx_dma_buffers = 1;
+		info->num_tx_holding_buffers = 0;
 	}
 	
 	return info;
@@ -4432,6 +4737,7 @@
 	unsigned long flags;
 	int rc;
 	struct mgsl_struct *info;
+	struct mgsl_struct *tmp;
 
 	printk("Unloading %s: version %s\n", driver_name, driver_version);
 	save_flags(flags);
@@ -4451,7 +4757,9 @@
 			mgsl_sppp_delete(info);
 #endif
 		mgsl_release_resources(info);
+		tmp = info;
 		info = info->next_device;
+		kfree(tmp);
 	}
 	
 	if (tmp_buf) {
@@ -4691,6 +4999,27 @@
 		 *
 		 * 0000 0110 0000 0110 = 0x0606
 		 */
+		if (info->params.mode == MGSL_MODE_RAW) {
+			RegValue = 0x0001;		/* Set Receive mode = external sync */
+
+			usc_OutReg( info, IOCR,		/* Set IOCR DCD is RxSync Detect Input */
+				(unsigned short)((usc_InReg(info, IOCR) & ~(BIT13|BIT12)) | BIT12));
+
+			/*
+			 * TxSubMode:
+			 * 	CMR <15>		0	Don't send CRC on Tx Underrun
+			 * 	CMR <14>		x	undefined
+			 * 	CMR <13>		0	Send preamble before openning sync
+			 * 	CMR <12>		0	Send 8-bit syncs, 1=send Syncs per TxLength
+			 *
+			 * TxMode:
+			 * 	CMR <11-8)	0100	MonoSync
+			 *
+			 * 	0x00 0100 xxxx xxxx  04xx
+			 */
+			RegValue |= 0x0400;
+		}
+		else {
 
 		RegValue = 0x0606;
 
@@ -4700,12 +5029,14 @@
 			RegValue |= BIT15;
 		else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC )
 			RegValue |= BIT15 + BIT14;
+		}
 
 		if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE )
 			RegValue |= BIT13;
 	}
 
-	if ( info->params.flags & HDLC_FLAG_SHARE_ZERO )
+	if ( info->params.mode == MGSL_MODE_HDLC &&
+		(info->params.flags & HDLC_FLAG_SHARE_ZERO) )
 		RegValue |= BIT12;
 
 	if ( info->params.addr_filter != 0xff )
@@ -4745,15 +5076,13 @@
 	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break;
 	}
 
-	if ( info->params.crc_type == HDLC_CRC_16_CCITT )
+	if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT )
 		RegValue |= BIT9;
-	else if ( info->params.crc_type == HDLC_CRC_32_CCITT )
+	else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT )
 		RegValue |= ( BIT12 | BIT10 | BIT9 );
 
 	usc_OutReg( info, RMR, RegValue );
 
-
- 
 	/* Set the Receive count Limit Register (RCLR) to 0xffff. */
 	/* When an opening flag of an SDLC frame is recognized the */
 	/* Receive Character count (RCC) is loaded with the value in */
@@ -4822,9 +5151,9 @@
 	case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: RegValue |= BIT15 + BIT14 + BIT13; break;
 	}
 
-	if ( info->params.crc_type == HDLC_CRC_16_CCITT )
+	if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_16_CCITT )
 		RegValue |= BIT9 + BIT8;
-	else if ( info->params.crc_type == HDLC_CRC_32_CCITT )
+	else if ( (info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_32_CCITT )
 		RegValue |= ( BIT12 | BIT10 | BIT9 | BIT8);
 
 	usc_OutReg( info, TMR, RegValue );
@@ -5495,7 +5824,8 @@
 	usc_OutReg( info, CCSR, (u16)(usc_InReg(info,CCSR) | BIT13) );
 	usc_RTCmd( info, RTCmd_PurgeRxFifo );
 
-	if ( info->params.mode == MGSL_MODE_HDLC ) {
+	if ( info->params.mode == MGSL_MODE_HDLC ||
+		info->params.mode == MGSL_MODE_RAW ) {
 		/* DMA mode Transfers */
 		/* Program the DMA controller. */
 		/* Enable the DMA controller end of buffer interrupt. */
@@ -5585,8 +5915,14 @@
 			/* Transmit DMA buffer is loaded, so program USC */
 			/* to send the frame contained in the buffers.	 */
 
+			FrameSize = info->tx_buffer_list[info->start_tx_dma_buffer].rcc;
 
-			FrameSize = info->tx_buffer_list[0].rcc;
+			/* if operating in Raw sync mode, reset the rcc component
+			 * of the tx dma buffer entry, otherwise, the serial controller
+			 * will send a closing sync char after this count.
+			 */
+	    		if ( info->params.mode == MGSL_MODE_RAW )
+				info->tx_buffer_list[info->start_tx_dma_buffer].rcc = 0;
 
 			/* Program the Transmit Character Length Register (TCLR) */
 			/* and clear FIFO (TCC is loaded with TCLR on FIFO clear) */
@@ -5595,7 +5931,7 @@
 			usc_RTCmd( info, RTCmd_PurgeTxFifo );
 
 			/* Program the address of the 1st DMA Buffer Entry in linked list */
-			phys_addr = info->tx_buffer_list[0].phys_entry;
+			phys_addr = info->tx_buffer_list[info->start_tx_dma_buffer].phys_entry;
 			usc_OutDmaReg( info, NTARL, (u16)phys_addr );
 			usc_OutDmaReg( info, NTARU, (u16)(phys_addr >> 16) );
 
@@ -5603,6 +5939,19 @@
 			usc_ClearIrqPendingBits( info, TRANSMIT_STATUS );
 			usc_EnableInterrupts( info, TRANSMIT_STATUS );
 
+			if ( info->params.mode == MGSL_MODE_RAW &&
+					info->num_tx_dma_buffers > 1 ) {
+			   /* When running external sync mode, attempt to 'stream' transmit  */
+			   /* by filling tx dma buffers as they become available. To do this */
+			   /* we need to enable Tx DMA EOB Status interrupts :               */
+			   /*                                                                */
+			   /* 1. Arm End of Buffer (EOB) Transmit DMA Interrupt (BIT2 of TDIAR) */
+			   /* 2. Enable Transmit DMA Interrupts (BIT0 of DICR) */
+
+			   usc_OutDmaReg( info, TDIAR, BIT2|BIT3 );
+			   usc_OutDmaReg( info, DICR, (u16)(usc_InDmaReg(info,DICR) | BIT0) );
+			}
+
 			/* Initialize Transmit DMA Channel */
 			usc_DmaCmd( info, DmaCmd_InitTxChannel );
 			
@@ -6026,6 +6375,9 @@
 void usc_loopback_frame( struct mgsl_struct *info )
 {
 	int i;
+	unsigned long oldmode = info->params.mode;
+
+	info->params.mode = MGSL_MODE_HDLC;
 	
 	usc_DisableMasterIrqBit( info );
 
@@ -6079,6 +6431,8 @@
 
 	usc_EnableMasterIrqBit(info);
 
+	info->params.mode = oldmode;
+
 }	/* end of usc_loopback_frame() */
 
 /* usc_set_sync_mode()	Programs the USC for SDLC communications.
@@ -6130,6 +6484,38 @@
 	info->tcsr_value += usc_idle_mode;
 	usc_OutReg(info, TCSR, info->tcsr_value);
 
+	/*
+	 * if SyncLink WAN adapter is running in external sync mode, the
+	 * transmitter has been set to Monosync in order to try to mimic
+	 * a true raw outbound bit stream. Monosync still sends an open/close
+	 * sync char at the start/end of a frame. Try to match those sync
+	 * patterns to the idle mode set here
+	 */
+	if ( info->params.mode == MGSL_MODE_RAW ) {
+		unsigned char syncpat = 0;
+		switch( info->idle_mode ) {
+		case HDLC_TXIDLE_FLAGS:
+			syncpat = 0x7e;
+			break;
+		case HDLC_TXIDLE_ALT_ZEROS_ONES:
+			syncpat = 0x55;
+			break;
+		case HDLC_TXIDLE_ZEROS:
+		case HDLC_TXIDLE_SPACE:
+			syncpat = 0x00;
+			break;
+		case HDLC_TXIDLE_ONES:
+		case HDLC_TXIDLE_MARK:
+			syncpat = 0xff;
+			break;
+		case HDLC_TXIDLE_ALT_MARK_SPACE:
+			syncpat = 0xaa;
+			break;
+		}
+
+		usc_SetTransmitSyncChars(info,syncpat,syncpat);
+	}
+
 }	/* end of usc_set_txidle() */
 
 /* usc_get_serial_signals()
@@ -6307,6 +6693,48 @@
  */
 
 /*
+ * mgsl_reset_tx_dma_buffers()
+ *
+ * 	Set the count for all transmit buffers to 0 to indicate the
+ * 	buffer is available for use and set the current buffer to the
+ * 	first buffer. This effectively makes all buffers free and
+ * 	discards any data in buffers.
+ *
+ * Arguments:		info	pointer to device instance data
+ * Return Value:	None
+ */
+void mgsl_reset_tx_dma_buffers( struct mgsl_struct *info )
+{
+	unsigned int i;
+
+	for ( i = 0; i < info->tx_buffer_count; i++ ) {
+		*((unsigned long *)&(info->tx_buffer_list[i].count)) = 0;
+	}
+
+	info->current_tx_buffer = 0;
+	info->start_tx_dma_buffer = 0;
+	info->tx_dma_buffers_used = 0;
+
+	info->get_tx_holding_index = 0;
+	info->put_tx_holding_index = 0;
+	info->tx_holding_count = 0;
+
+}	/* end of mgsl_reset_tx_dma_buffers() */
+
+/*
+ * num_free_tx_dma_buffers()
+ *
+ * 	returns the number of free tx dma buffers available
+ *
+ * Arguments:		info	pointer to device instance data
+ * Return Value:	number of free tx dma buffers
+ */
+int num_free_tx_dma_buffers(struct mgsl_struct *info)
+{
+	return info->tx_buffer_count - info->tx_dma_buffers_used;
+}
+
+/*
  * mgsl_reset_rx_dma_buffers()
  * 
  * 	Set the count for all receive buffers to DMABUFFERSIZE
@@ -6392,10 +6820,11 @@
 	unsigned int StartIndex, EndIndex;	/* index of 1st and last buffers of Rx frame */
 	unsigned short status;
 	DMABUFFERENTRY *pBufEntry;
-	unsigned int framesize;
+	unsigned int framesize = 0;
 	int ReturnCode = 0;
 	unsigned long flags;
 	struct tty_struct *tty = info->tty;
+	int return_frame = 0;
 	
 	/*
 	 * current_rx_buffer points to the 1st buffer of the next available
@@ -6451,14 +6880,20 @@
 			info->icount.rxabort++;
 		else if ( status & RXSTATUS_OVERRUN )
 			info->icount.rxover++;
-		else 
+		else {
 			info->icount.rxcrc++;
+			if ( info->params.crc_type & HDLC_CRC_RETURN_EX )
+				return_frame = 1;
+		}
 		framesize = 0;
 #ifdef CONFIG_SYNCLINK_SYNCPPP
 		info->netstats.rx_errors++;
 		info->netstats.rx_frame_errors++;
 #endif
-	} else {
+	} else
+		return_frame = 1;
+
+	if ( return_frame ) {
 		/* receive frame has no errors, get frame size.
 		 * The frame size is the starting value of the RCC (which was
 		 * set to 0xffff) minus the ending value of the RCC (decremented
@@ -6483,7 +6918,9 @@
 			MIN(framesize,DMABUFFERSIZE),0);	
 		
 	if (framesize) {
-		if (framesize > info->max_frame_size)
+		if ( ( (info->params.crc_type & HDLC_CRC_RETURN_EX) &&
+				((framesize+1) > info->max_frame_size) ) ||
+			(framesize > info->max_frame_size) )
 			info->icount.rxlong++;
 		else {
 			/* copy dma buffer(s) to contiguous intermediate buffer */
@@ -6491,6 +6928,7 @@
 			int index = StartIndex;
 			unsigned char *ptmp = info->intermediate_rxbuffer;
 
+			if ( !(status & RXSTATUS_CRC_ERROR))
 			info->icount.rxok++;
 			
 			while(copy_count) {
@@ -6509,6 +6947,18 @@
 					index = 0;
 			}
 
+			if ( info->params.crc_type & HDLC_CRC_RETURN_EX ) {
+				++framesize;
+				*ptmp = (status & RXSTATUS_CRC_ERROR ?
+						RX_CRC_ERROR :
+						RX_OK);
+
+				if ( debug_level >= DEBUG_LEVEL_DATA )
+					printk("%s(%d):mgsl_get_rx_frame(%s) rx frame status=%d\n",
+						__FILE__,__LINE__,info->device_name,
+						*ptmp);
+			}
+
 #ifdef CONFIG_SYNCLINK_SYNCPPP
 			if (info->netcount) {
 				/* pass frame to syncppp device */
@@ -6518,6 +6968,7 @@
 #endif
 			{
 				/* Call the line discipline receive callback directly. */
+				if ( tty && tty->ldisc.receive_buf )
 				tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize);
 			}
 		}
@@ -6547,6 +6998,180 @@
 
 }	/* end of mgsl_get_rx_frame() */
 
+/* mgsl_get_raw_rx_frame()
+ *
+ *     	This function attempts to return a received frame from the
+ *	receive DMA buffers when running in external loop mode. In this mode,
+ *	we will return at most one DMABUFFERSIZE frame to the application.
+ *	The USC receiver is triggering off of DCD going active to start a new
+ *	frame, and DCD going inactive to terminate the frame (similar to
+ *	processing a closing flag character).
+ *
+ *	In this routine, we will return DMABUFFERSIZE "chunks" at a time.
+ *	If DCD goes inactive, the last Rx DMA Buffer will have a non-zero
+ * 	status field and the RCC field will indicate the length of the
+ *	entire received frame. We take this RCC field and get the modulus
+ *	of RCC and DMABUFFERSIZE to determine if number of bytes in the
+ *	last Rx DMA buffer and return that last portion of the frame.
+ *
+ * Arguments:	 	info	pointer to device extension
+ * Return Value:	1 if frame returned, otherwise 0
+ */
+int mgsl_get_raw_rx_frame(struct mgsl_struct *info)
+{
+	unsigned int CurrentIndex, NextIndex;
+	unsigned short status;
+	DMABUFFERENTRY *pBufEntry;
+	unsigned int framesize = 0;
+	int ReturnCode = 0;
+	unsigned long flags;
+	struct tty_struct *tty = info->tty;
+
+	/*
+ 	 * current_rx_buffer points to the 1st buffer of the next available
+	 * receive frame. The status field is set by the 16C32 after
+	 * completing a receive frame. If the status field of this buffer
+	 * is zero, either the USC is still filling this buffer or this
+	 * is one of a series of buffers making up a received frame.
+	 *
+	 * If the count field of this buffer is zero, the USC is either
+	 * using this buffer or has used this buffer. Look at the count
+	 * field of the next buffer. If that next buffer's count is
+	 * non-zero, the USC is still actively using the current buffer.
+	 * Otherwise, if the next buffer's count field is zero, the
+	 * current buffer is complete and the USC is using the next
+	 * buffer.
+	 */
+	CurrentIndex = NextIndex = info->current_rx_buffer;
+	++NextIndex;
+	if ( NextIndex == info->rx_buffer_count )
+		NextIndex = 0;
+
+	if ( info->rx_buffer_list[CurrentIndex].status != 0 ||
+		(info->rx_buffer_list[CurrentIndex].count == 0 &&
+			info->rx_buffer_list[NextIndex].count == 0)) {
+		/*
+	 	 * Either the status field of this dma buffer is non-zero
+		 * (indicating the last buffer of a receive frame) or the next
+	 	 * buffer is marked as in use -- implying this buffer is complete
+		 * and an intermediate buffer for this received frame.
+	 	 */
+
+		status = info->rx_buffer_list[CurrentIndex].status;
+
+		if ( status & (RXSTATUS_SHORT_FRAME + RXSTATUS_OVERRUN +
+				RXSTATUS_CRC_ERROR + RXSTATUS_ABORT) ) {
+			if ( status & RXSTATUS_SHORT_FRAME )
+				info->icount.rxshort++;
+			else if ( status & RXSTATUS_ABORT )
+				info->icount.rxabort++;
+			else if ( status & RXSTATUS_OVERRUN )
+				info->icount.rxover++;
+			else
+				info->icount.rxcrc++;
+			framesize = 0;
+		} else {
+			/*
+			 * A receive frame is available, get frame size and status.
+			 *
+			 * The frame size is the starting value of the RCC (which was
+			 * set to 0xffff) minus the ending value of the RCC (decremented
+			 * once for each receive character) minus 2 or 4 for the 16-bit
+			 * or 32-bit CRC.
+			 *
+			 * If the status field is zero, this is an intermediate buffer.
+			 * It's size is 4K.
+			 *
+			 * If the DMA Buffer Entry's Status field is non-zero, the
+			 * receive operation completed normally (ie: DCD dropped). The
+			 * RCC field is valid and holds the received frame size.
+			 * It is possible that the RCC field will be zero on a DMA buffer
+			 * entry with a non-zero status. This can occur if the total
+			 * frame size (number of bytes between the time DCD goes active
+			 * to the time DCD goes inactive) exceeds 65535 bytes. In this
+			 * case the 16C32 has underrun on the RCC count and appears to
+			 * stop updating this counter to let us know the actual received
+			 * frame size. If this happens (non-zero status and zero RCC),
+			 * simply return the entire RxDMA Buffer
+			 */
+			if ( status ) {
+				/*
+				 * In the event that the final RxDMA Buffer is
+				 * terminated with a non-zero status and the RCC
+				 * field is zero, we interpret this as the RCC
+				 * having underflowed (received frame > 65535 bytes).
+				 *
+				 * Signal the event to the user by passing back
+				 * a status of RxStatus_CrcError returning the full
+				 * buffer and let the app figure out what data is
+				 * actually valid
+				 */
+				if ( info->rx_buffer_list[CurrentIndex].rcc )
+					framesize = RCLRVALUE - info->rx_buffer_list[CurrentIndex].rcc;
+				else
+					framesize = DMABUFFERSIZE;
+			}
+			else
+				framesize = DMABUFFERSIZE;
+		}
+
+		if ( framesize > DMABUFFERSIZE ) {
+			/*
+			 * if running in raw sync mode, ISR handler for
+			 * End Of Buffer events terminates all buffers at 4K.
+			 * If this frame size is said to be >4K, get the
+			 * actual number of bytes of the frame in this buffer.
+			 */
+			framesize = framesize % DMABUFFERSIZE;
+		}
+
+
+		if ( debug_level >= DEBUG_LEVEL_BH )
+			printk("%s(%d):mgsl_get_raw_rx_frame(%s) status=%04X size=%d\n",
+				__FILE__,__LINE__,info->device_name,status,framesize);
+
+		if ( debug_level >= DEBUG_LEVEL_DATA )
+			mgsl_trace_block(info,info->rx_buffer_list[CurrentIndex].virt_addr,
+				MIN(framesize,DMABUFFERSIZE),0);
+
+		if (framesize) {
+			/* copy dma buffer(s) to contiguous intermediate buffer */
+			/* NOTE: we never copy more than DMABUFFERSIZE bytes	*/
+
+			pBufEntry = &(info->rx_buffer_list[CurrentIndex]);
+			memcpy( info->intermediate_rxbuffer, pBufEntry->virt_addr, framesize);
+			info->icount.rxok++;
+
+			/* Call the line discipline receive callback directly. */
+			if ( tty && tty->ldisc.receive_buf )
+				tty->ldisc.receive_buf(tty, info->intermediate_rxbuffer, info->flag_buf, framesize);
+		}
+
+		/* Free the buffers used by this frame. */
+		mgsl_free_rx_frame_buffers( info, CurrentIndex, CurrentIndex );
+
+		ReturnCode = 1;
+	}
+
+
+	if ( info->rx_enabled && info->rx_overflow ) {
+		/* The receiver needs to restarted because of
+		 * a receive overflow (buffer or FIFO). If the
+		 * receive buffers are now empty, then restart receiver.
+		 */
+
+		if ( !info->rx_buffer_list[CurrentIndex].status &&
+			info->rx_buffer_list[CurrentIndex].count ) {
+			spin_lock_irqsave(&info->irq_spinlock,flags);
+			usc_start_receiver(info);
+			spin_unlock_irqrestore(&info->irq_spinlock,flags);
+		}
+	}
+
+	return ReturnCode;
+
+}	/* end of mgsl_get_raw_rx_frame() */
+
 /* mgsl_load_tx_dma_buffer()
  * 
  * 	Load the transmit DMA buffer with the specified data.
@@ -6576,12 +7201,19 @@
 	 	info->cmr_value |= BIT13;			  
 	}
 		
+	/* begin loading the frame in the next available tx dma
+	 * buffer, remember it's starting location for setting
+	 * up tx dma operation
+	 */
+	i = info->current_tx_buffer;
+	info->start_tx_dma_buffer = i;
+
 	/* Setup the status and RCC (Frame Size) fields of the 1st */
 	/* buffer entry in the transmit DMA buffer list. */
 
-	info->tx_buffer_list[0].status = info->cmr_value & 0xf000;
-	info->tx_buffer_list[0].rcc    = BufferSize;
-	info->tx_buffer_list[0].count  = BufferSize;
+	info->tx_buffer_list[i].status = info->cmr_value & 0xf000;
+	info->tx_buffer_list[i].rcc    = BufferSize;
+	info->tx_buffer_list[i].count  = BufferSize;
 
 	/* Copy frame data from 1st source buffer to the DMA buffers. */
 	/* The frame data may span multiple DMA buffers. */
@@ -6590,6 +7222,9 @@
 		/* Get a pointer to next DMA buffer entry. */
 		pBufEntry = &info->tx_buffer_list[i++];
 			
+		if ( i == info->tx_buffer_count )
+			i=0;
+
 		/* Calculate the number of bytes that can be copied from */
 		/* the source buffer to this DMA buffer. */
 		if ( BufferSize > DMABUFFERSIZE )
@@ -6609,8 +7244,13 @@
 		/* Advance source pointer and reduce remaining data count. */
 		Buffer += Copycount;
 		BufferSize -= Copycount;
+
+		++info->tx_dma_buffers_used;
 	}
 
+	/* remember next available tx dma buffer */
+	info->current_tx_buffer = i;
+
 }	/* end of mgsl_load_tx_dma_buffer() */
 
 /*
@@ -6741,7 +7381,7 @@
 	unsigned int i;
 	char *TmpPtr;
 	BOOLEAN rc = TRUE;
-	unsigned short status;
+	unsigned short status=0;
 	unsigned long EndTime;
 	unsigned long flags;
 	MGSL_PARAMS tmp_params;
@@ -6998,7 +7638,7 @@
 		status = info->rx_buffer_list[0].status;
 
 		if ( status & (BIT8 + BIT3 + BIT1) ) {
-			/* receive error has occurred */
+			/* receive error has occured */
 			rc = FALSE;
 		} else {
 			if ( memcmp( info->tx_buffer_list[0].virt_addr ,
@@ -7219,7 +7859,9 @@
 	if ( debug_level >= DEBUG_LEVEL_INFO )
 		printk( "%s(%d):mgsl_tx_timeout(%s)\n",
 			__FILE__,__LINE__,info->device_name);
-	if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) {
+	if(info->tx_active &&
+	   (info->params.mode == MGSL_MODE_HDLC ||
+	    info->params.mode == MGSL_MODE_RAW) ) {
 		info->icount.txtimeout++;
 	}
 	spin_lock_irqsave(&info->irq_spinlock,flags);
diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.4.4/linux/drivers/i2o/i2o_block.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/i2o/i2o_block.c	Tue May  1 16:12:51 2001
@@ -28,14 +28,16 @@
  *    		Support for larger I/Os through merge* functions 
  *       	(taken from DAC960 driver)
  *	Boji T Kannanthanam:
- *		Reduced the timeout during RAID 5 creation. 
- *		This is to prevent race condition when a RAID volume
- *		is created and immediately deleted.
+ *		Set the I2O Block devices to be detected in increasing 
+ *		order of TIDs during boot.
+ *		Search and set the I2O block device that we boot off from  as
+ *		the first device to be claimed (as /dev/i2o/hda)
+ *		Properly attach/detach I2O gendisk structure from the system
+ *		gendisk list. The I2O block devices now appear in 
+ * 		/proc/partitions.
  *
  *	To do:
  *		Serial number scanning to find duplicates for FC multipathing
- *		Remove the random timeout in the code needed for RAID 5
- *			volume creation.
  */
 
 #include <linux/major.h>
@@ -86,7 +88,8 @@
 #define I2OB_EVENT_MASK		(I2O_EVT_IND_BSA_VOLUME_LOAD |	\
 				 I2O_EVT_IND_BSA_VOLUME_UNLOAD | \
 				 I2O_EVT_IND_BSA_VOLUME_UNLOAD_REQ | \
-				 I2O_EVT_IND_BSA_CAPACITY_CHANGE)
+				 I2O_EVT_IND_BSA_CAPACITY_CHANGE | \
+				 I2O_EVT_IND_BSA_SCSI_SMART )
 
 
 /*
@@ -135,6 +138,8 @@
 	request_queue_t *req_queue;
 	int max_segments;
 	int done_flag;
+	int constipated;
+	int depth;
 };
 
 /*
@@ -164,7 +169,9 @@
 	struct i2ob_request *i2ob_qhead;
 	request_queue_t req_queue;
 };
-static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS] = {NULL};
+static struct i2ob_iop_queue *i2ob_queues[MAX_I2O_CONTROLLERS];
+static struct i2ob_request *i2ob_backlog[MAX_I2O_CONTROLLERS];
+static struct i2ob_request *i2ob_backlog_tail[MAX_I2O_CONTROLLERS];
 
 /*
  *	Each I2O disk is one of these.
@@ -179,10 +186,10 @@
  * Mutex and spin lock for event handling synchronization
  * evt_msg contains the last event.
  */
-DECLARE_MUTEX(i2ob_evt_sem);
+static DECLARE_MUTEX_LOCKED(i2ob_evt_sem);
+static DECLARE_MUTEX_LOCKED(i2ob_thread_dead);
 static spinlock_t i2ob_evt_lock = SPIN_LOCK_UNLOCKED;
-static unsigned int evt_msg[MSG_FRAME_SIZE>>2];
-DECLARE_WAIT_QUEUE_HEAD(i2ob_evt_wait);
+static u32 evt_msg[MSG_FRAME_SIZE>>2];
 
 static struct timer_list i2ob_timer;
 static int i2ob_timer_started = 0;
@@ -195,6 +202,7 @@
 static int i2ob_install_device(struct i2o_controller *, struct i2o_device *, int);
 static void i2ob_end_request(struct request *);
 static void i2ob_request(request_queue_t *);
+static int i2ob_backlog_request(struct i2o_controller *, struct i2ob_device *);
 static int i2ob_init_iop(unsigned int);
 static request_queue_t* i2ob_get_queue(kdev_t);
 static int i2ob_query_device(struct i2ob_device *, int, int, void*, int);
@@ -203,6 +211,7 @@
 
 static int evt_pid = 0;
 static int evt_running = 0;
+static int scan_unit = 0;
 
 /*
  * I2O OSM registration structure...keeps getting bigger and bigger :)
@@ -255,7 +264,12 @@
 	__raw_writel(i2ob_context|(unit<<8), msg+8);
 	__raw_writel(ireq->num, msg+12);
 	__raw_writel(req->nr_sectors << 9, msg+20);
-	
+
+	/* 
+	 * Mask out partitions from now on
+	 */
+	unit &= 0xF0;
+		
 	/* This can be optimised later - just want to be sure its right for
 	   starters */
 	offset = ((u64)(req->sector+base)) << 9;
@@ -266,8 +280,6 @@
 	if(req->cmd == READ)
 	{
 		__raw_writel(I2O_CMD_BLOCK_READ<<24|HOST_TID<<12|tid, msg+4);
-		/* We don't yet do cache/readahead and other magic */
-		__raw_writel(1<<16, msg+16);
 		while(bh!=NULL)
 		{
 			if(bh->b_data == last) {
@@ -293,16 +305,20 @@
 			count -= bh->b_size;
 			bh = bh->b_reqnext;
 		}
+		/*
+		 *	Heuristic for now since the block layer doesnt give
+		 *	us enough info. If its a big write assume sequential
+		 *	readahead on controller. If its small then don't read
+		 *	ahead but do use the controller cache.
+		 */
+		if(size >= 8192)
+			__raw_writel((8<<24)|(1<<16)|8, msg+16);
+		else
+			__raw_writel((8<<24)|(1<<16)|4, msg+16);
 	}
 	else if(req->cmd == WRITE)
 	{
 		__raw_writel(I2O_CMD_BLOCK_WRITE<<24|HOST_TID<<12|tid, msg+4);
-		/* 
-		 * Allow replies to come back once data is cached in the controller
-		 * This allows us to handle writes quickly thus giving more of the
-		 * queue to reads.
-		 */
-		__raw_writel(0x00000010, msg+16);
 		while(bh!=NULL)
 		{
 			if(bh->b_data == last) {
@@ -328,13 +344,32 @@
 			count -= bh->b_size;
 			bh = bh->b_reqnext;
 		}
+
+		if(c->battery)
+		{
+			
+			if(size>16384)
+				__raw_writel(4, msg+16);
+			else
+				/* 
+				 * Allow replies to come back once data is cached in the controller
+				 * This allows us to handle writes quickly thus giving more of the
+				 * queue to reads.
+				 */
+				__raw_writel(16, msg+16);
+		}
+		else
+		{
+			/* Large write, don't cache */
+			if(size>8192)
+				__raw_writel(4, msg+16);
+			else
+			/* write through */
+				__raw_writel(8, msg+16);
+		}
 	}
 	__raw_writel(I2O_MESSAGE_SIZE(mptr-msg)>>2 | SGL_OFFSET_8, msg);
 	
-	if(req->current_nr_sectors > i2ob_max_sectors[unit])
-		printk("Gathered sectors %ld.\n", 
-			req->current_nr_sectors);
-			
 	if(count != 0)
 	{
 		printk(KERN_ERR "Request count botched by %d.\n", count);
@@ -434,7 +469,32 @@
 	return 1;
 }
 
+static int i2ob_flush(struct i2o_controller *c, struct i2ob_device *d, int unit)
+{
+	unsigned long msg;
+	u32 m = i2ob_get(d);
+	
+	if(m == 0xFFFFFFFF)
+		return -1;
+		
+	msg = c->mem_offset + m;
 
+	/*
+	 *	Ask the controller to write the cache back. This sorts out
+	 *	the supertrak firmware flaw and also does roughly the right
+	 *	thing for other cases too.
+	 */
+	 	
+	__raw_writel(FIVE_WORD_MSG_SIZE|SGL_OFFSET_0, msg);
+	__raw_writel(I2O_CMD_BLOCK_CFLUSH<<24|HOST_TID<<12|d->tid, msg+4);
+	__raw_writel(i2ob_context|(unit<<8), msg+8);
+	__raw_writel(0, msg+12);
+	__raw_writel(60<<16, msg+16);
+	
+	i2o_post_message(c,m);
+	return 0;
+}
+			
 /*
  *	OSM reply handler. This gets all the message replies
  */
@@ -447,7 +507,7 @@
 	u32 *m = (u32 *)msg;
 	u8 unit = (m[2]>>8)&0xF0;	/* low 4 bits are partition */
 	struct i2ob_device *dev = &i2ob_dev[(unit&0xF0)];
-
+	
 	/*
 	 * FAILed message
 	 */
@@ -482,9 +542,20 @@
 	if(msg->function == I2O_CMD_UTIL_EVT_REGISTER)
 	{
 		spin_lock(&i2ob_evt_lock);
-		memcpy(&evt_msg, m, msg->size);
+		memcpy(evt_msg, msg, (m[0]>>16)<<2);
 		spin_unlock(&i2ob_evt_lock);
-		wake_up_interruptible(&i2ob_evt_wait);
+		up(&i2ob_evt_sem);
+		return;
+	}
+
+	if(msg->function == I2O_CMD_BLOCK_CFLUSH)
+	{
+		spin_lock_irqsave(&io_request_lock, flags);
+		dev->constipated=0;
+		DEBUG(("unconstipated\n"));
+		if(i2ob_backlog_request(c, dev)==0)
+			i2ob_request(dev->req_queue);
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return;
 	}
 
@@ -517,6 +588,7 @@
 
 	if(st!=0)
 	{
+		int err;
 		char *bsa_errors[] = 
 		{ 
 			"Success", 
@@ -535,12 +607,78 @@
 			"Volume has changed, waiting for acknowledgement"
 		};
 				
+		err = m[4]&0xFFFF;
+		
+		/*
+		 *	Device not ready means two things. One is that the
+		 *	the thing went offline (but not a removal media)
+		 *
+		 *	The second is that you have a SuperTrak 100 and the
+		 *	firmware got constipated. Unlike standard i2o card
+		 *	setups the supertrak returns an error rather than
+		 *	blocking for the timeout in these cases.
+		 */
+		 
+		
+		spin_lock_irqsave(&io_request_lock, flags);
+		if(err==4)
+		{
+			/*
+			 *	Time to uncork stuff
+			 */
+			
+			if(!dev->constipated)
+			{
+				dev->constipated = 1;
+				DEBUG(("constipated\n"));
+				/* Now pull the chain */
+				if(i2ob_flush(c, dev, unit)<0)
+				{
+					DEBUG(("i2ob: Unable to queue flush. Retrying I/O immediately.\n"));
+					dev->constipated=0;
+				}
+				DEBUG(("flushing\n"));
+			}
+			
+			/*
+			 *	Recycle the request
+			 */
+			 
+//			i2ob_unhook_request(ireq, c->unit);
+			
+			/*
+			 *	Place it on the recycle queue
+			 */
+			 
+			ireq->next = NULL;
+			if(i2ob_backlog_tail[c->unit]!=NULL)
+				i2ob_backlog_tail[c->unit]->next = ireq;
+			else
+				i2ob_backlog[c->unit] = ireq;			
+			i2ob_backlog_tail[c->unit] = ireq;
+			
+			atomic_dec(&i2ob_queues[c->unit]->queue_depth);
+
+			/*
+			 *	If the constipator flush failed we want to
+			 *	poke the queue again. 
+			 */
+			 
+			i2ob_request(dev->req_queue);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			
+			/*
+			 *	and out
+			 */
+			 
+			return;	
+		}
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		printk(KERN_ERR "\n/dev/%s error: %s", dev->i2odev->dev_name, 
 			bsa_errors[m[4]&0XFFFF]);
 		if(m[4]&0x00FF0000)
 			printk(" - DDM attempted %d retries", (m[4]>>16)&0x00FF );
-		printk("\n");
-
+		printk(".\n");
 		ireq->req->errors++;	
 	}
 	else
@@ -559,7 +697,9 @@
 	/*
 	 *	We may be able to do more I/O
 	 */
-	i2ob_request(dev->req_queue);
+
+	if(i2ob_backlog_request(c, dev)==0)
+		i2ob_request(dev->req_queue);
 
 	spin_unlock_irqrestore(&io_request_lock, flags);
 }
@@ -575,6 +715,14 @@
 	unsigned int flags;
 	int unit;
 	int i;
+	//The only event that has data is the SCSI_SMART event.
+	struct i2o_reply {
+		u32 header[4];
+		u32 evt_indicator;
+		u8 ASC;
+		u8 ASCQ;
+		u8 data[16];
+		} *evt_local;
 
 	lock_kernel();
 	daemonize();
@@ -585,15 +733,13 @@
 
 	while(1)
 	{
-#warning "RACE"
-		interruptible_sleep_on(&i2ob_evt_wait);
- 		if(signal_pending(current)) {
+		if(down_interruptible(&i2ob_evt_sem))
+		{
 			evt_running = 0;
-			return 0;
+			printk("exiting...");
+			break;
 		}
 
-		printk(KERN_INFO "Doing something in i2o_block event thread\n");
-		
 		/*
 		 * Keep another CPU/interrupt from overwriting the 
 		 * message while we're reading it
@@ -602,10 +748,12 @@
 		 * None of the BSA we care about events have EventData
 		 */
 		spin_lock_irqsave(&i2ob_evt_lock, flags);
-		unit = evt_msg[3];
-		evt = evt_msg[4];
+		evt_local = (struct i2o_reply *)evt_msg;
 		spin_unlock_irqrestore(&i2ob_evt_lock, flags);
 
+		unit = evt_local->header[3];
+		evt = evt_local->evt_indicator;
+
 		switch(evt)
 		{
 			/*
@@ -675,18 +823,43 @@
 				break;
 			}
 
+			/* 
+			 * We got a SCSI SMART event, we just log the relevant
+			 * information and let the user decide what they want
+			 * to do with the information.
+			 */
+			case I2O_EVT_IND_BSA_SCSI_SMART:
+			{
+				char buf[16];
+				printk(KERN_INFO "I2O Block: %s received a SCSI SMART Event\n",i2ob_dev[unit].i2odev->dev_name);
+				evt_local->data[16]='\0';
+				sprintf(buf,"%s",&evt_local->data[0]);
+				printk(KERN_INFO "      Disk Serial#:%s\n",buf);
+				printk(KERN_INFO "      ASC 0x%02x \n",evt_local->ASC);
+				printk(KERN_INFO "      ASCQ 0x%02x \n",evt_local->ASCQ);
+				break;
+			}
+		
+			/*
+			 *	Non event
+			 */
+			 
+			case 0:
+				break;
+				
 			/*
 			 * An event we didn't ask for.  Call the card manufacturer
 			 * and tell them to fix their firmware :)
 			 */
 			default:
-				printk(KERN_INFO "%s: Received event we didn't register for\n"
-					KERN_INFO "   Call I2O card manufacturer\n", 
-					i2ob_dev[unit].i2odev->dev_name);
+				printk(KERN_INFO "%s: Received event %d we didn't register for\n"
+					KERN_INFO "   Blame the I2O card manufacturer 8)\n", 
+					i2ob_dev[unit].i2odev->dev_name, evt);
 				break;
 		}
 	};
 
+	up_and_exit(&i2ob_thread_dead,0);
 	return 0;
 }
 
@@ -724,6 +897,34 @@
 	spin_unlock_irqrestore(&io_request_lock,flags);
 }
 
+static int i2ob_backlog_request(struct i2o_controller *c, struct i2ob_device *dev)
+{
+	u32 m;
+	struct i2ob_request *ireq;
+	
+	while((ireq=i2ob_backlog[c->unit])!=NULL)
+	{
+		int unit;
+
+		if(atomic_read(&i2ob_queues[c->unit]->queue_depth) > dev->depth/4)
+			break;
+
+		m = i2ob_get(dev);
+		if(m == 0xFFFFFFFF)
+			break;
+
+		i2ob_backlog[c->unit] = ireq->next;
+		if(i2ob_backlog[c->unit] == NULL)
+			i2ob_backlog_tail[c->unit] = NULL;
+			
+		unit = MINOR(ireq->req->rq_dev);
+		i2ob_send(m, dev, ireq, i2ob[unit].start_sect, unit);
+	}
+	if(i2ob_backlog[c->unit])
+		return 1;
+	return 0;
+}
+
 /*
  *	The I2O block driver is listed as one of those that pulls the
  *	front entry off the queue before processing it. This is important
@@ -731,6 +932,7 @@
  *	on us. We must unlink CURRENT in this routine before we return, if
  *	we use it.
  */
+
 static void i2ob_request(request_queue_t *q)
 {
 	struct request *req;
@@ -738,9 +940,8 @@
 	int unit;
 	struct i2ob_device *dev;
 	u32 m;
-
-	// printk(KERN_INFO "i2ob_request() called with queue %p\n", q);
-
+	
+	
 	while (!list_empty(&q->queue_head)) {
 		/*
 		 *	On an IRQ completion if there is an inactive
@@ -760,9 +961,16 @@
 		 *	generic IOP commit control. Certainly its not right 
 		 *	its global!  
 		 */
-		if(atomic_read(&i2ob_queues[dev->unit]->queue_depth)>=MAX_I2OB_DEPTH)
+		if(atomic_read(&i2ob_queues[dev->unit]->queue_depth) >= dev->depth)
 			break;
+		
+		/*
+		 *	Is the channel constipated ?
+		 */
 
+		if(i2ob_backlog[dev->unit]!=NULL)
+			break;
+			
 		/* Get a message */
 		m = i2ob_get(dev);
 
@@ -773,7 +981,7 @@
 			 */
 			if (!i2ob_timer_started)
 			{
-				printk(KERN_ERR "i2ob: starting timer\n");
+				DEBUG((KERN_ERR "i2ob: starting timer\n"));
 
 				/*
 				 * Set the timer_started flag to insure
@@ -795,6 +1003,7 @@
 				 */
 				 
 				add_timer(&i2ob_timer);
+				return;
 			}
 		}
 
@@ -804,7 +1013,7 @@
 		req->errors = 0;
 		blkdev_dequeue_request(req);	
 		req->sem = NULL;
-
+		
 		ireq = i2ob_queues[dev->unit]->i2ob_qhead;
 		i2ob_queues[dev->unit]->i2ob_qhead = ireq->next;
 		ireq->req = req;
@@ -892,13 +1101,7 @@
 	for( i = 15; i>=0 ; i--)
 	{
 		int m = minor+i;
-		kdev_t d = MKDEV(MAJOR_NR, m);
-		struct super_block *sb = get_super(d);
-		
-		sync_dev(d);
-		if(sb)
-			invalidate_inodes(sb);
-		invalidate_buffers(d);
+		invalidate_device(MKDEV(MAJOR_NR, m), 1);
 		i2ob_gendisk.part[m].start_sect = 0;
 		i2ob_gendisk.part[m].nr_sects = 0;
 	}
@@ -1009,7 +1212,8 @@
 		msg[2] = i2ob_context|0x40000000;
 		msg[3] = (u32)query_done;
 		msg[4] = 60<<16;
-		i2o_post_wait(dev->controller, msg, 20, 2);
+		DEBUG("Flushing...");
+		i2o_post_wait(dev->controller, msg, 20, 60);
 
 		/*
 		 *	Unlock the media
@@ -1019,14 +1223,18 @@
 		msg[2] = i2ob_context|0x40000000;
 		msg[3] = (u32)query_done;
 		msg[4] = -1;
+		DEBUG("Unlocking...");
 		i2o_post_wait(dev->controller, msg, 20, 2);
+		DEBUG("Unlocked.\n");
 	
 		/*
  		 * Now unclaim the device.
 		 */
+
 		if (i2o_release_device(dev->i2odev, &i2o_block_handler))
 			printk(KERN_ERR "i2ob_release: controller rejected unclaim.\n");
-
+		
+		DEBUG("Unclaim\n");
 	}
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -1055,12 +1263,14 @@
 	{ 
 		u32 msg[6];
 		
+		DEBUG("Claim ");
 		if(i2o_claim_device(dev->i2odev, &i2o_block_handler))
 		{
 			dev->refcnt--;
 			printk(KERN_INFO "I2O Block: Could not open device\n");
 			return -EBUSY;
 		}
+		DEBUG("Claimed ");
 		
 		/*
 		 *	Mount the media if needed. Note that we don't use
@@ -1072,6 +1282,7 @@
 		msg[1] = I2O_CMD_BLOCK_MMOUNT<<24|HOST_TID<<12|dev->tid;
 		msg[4] = -1;
 		msg[5] = 0;
+		DEBUG("Mount ");
 		i2o_post_wait(dev->controller, msg, 24, 2);
 
 		/*
@@ -1080,7 +1291,9 @@
 		msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
 		msg[1] = I2O_CMD_BLOCK_MLOCK<<24|HOST_TID<<12|dev->tid;
 		msg[4] = -1;
+		DEBUG("Lock ");
 		i2o_post_wait(dev->controller, msg, 20, 2);
+		DEBUG("Ready.\n");
 	}		
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -1132,7 +1345,8 @@
 	i2ob_query_device(dev, 0x0000, 5, &flags, 4);
 	i2ob_query_device(dev, 0x0000, 6, &status, 4);
 	i2ob_sizes[unit] = (int)(size>>10);
-	i2ob_hardsizes[unit] = blocksize;
+	for(i=unit; i <= unit+15 ; i++)
+		i2ob_hardsizes[i] = blocksize;
 	i2ob_gendisk.part[unit].nr_sects = size>>9;
 	i2ob[unit].nr_sects = (int)(size>>9);
 
@@ -1143,20 +1357,33 @@
 	/*
 	 * Max number of Scatter-Gather Elements
 	 */	
-	i2ob_dev[unit].max_segments = 
-		(d->controller->status_block->inbound_frame_size - 8)/2;
 
-	printk(KERN_INFO "Max Segments set to %d\n", 
-				i2ob_dev[unit].max_segments);
-	printk(KERN_INFO "Byte limit is %d.\n", limit);
-	
 	for(i=unit;i<=unit+15;i++)
 	{
-		i2ob_max_sectors[i]=MAX_SECTORS;
-		i2ob_dev[i].max_segments = 
-			(d->controller->status_block->inbound_frame_size - 8)/2;
+		if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.queue_buggy)
+		{
+			i2ob_max_sectors[i] = 32;
+			i2ob_dev[i].max_segments = 8;
+			i2ob_dev[i].depth = 4;
+		}
+		else if(d->controller->type == I2O_TYPE_PCI && d->controller->bus.pci.short_req)
+		{
+			i2ob_max_sectors[i] = 8;
+			i2ob_dev[i].max_segments = 8;
+		}
+		else
+		{
+			/* MAX_SECTORS was used but 255 is a dumb number for
+			   striped RAID */
+			i2ob_max_sectors[i]=256;
+			i2ob_dev[i].max_segments = (d->controller->status_block->inbound_frame_size - 8)/2;
+		}
 	}
 
+	printk(KERN_INFO "Max segments set to %d\n", 
+				i2ob_dev[unit].max_segments);
+	printk(KERN_INFO "Byte limit is %d.\n", limit);
+
 	i2ob_query_device(dev, 0x0000, 0, &type, 1);
 	
 	sprintf(d->dev_name, "%s%c", i2ob_gendisk.major_name, 'a' + (unit>>4));
@@ -1190,6 +1417,7 @@
 			printk(", %dMb cache", cachesize>>10);
 		else
 			printk(", %dKb cache", cachesize);
+		
 	}
 	printk(".\n");
 	printk(KERN_INFO "%s: Maximum sectors/read set to %d.\n", 
@@ -1277,53 +1505,94 @@
 /*
  * Probe the I2O subsytem for block class devices
  */
-static void i2ob_probe(void)
+static void i2ob_scan(int bios)
 {
 	int i;
-	int unit = 0;
 	int warned = 0;
+
+	struct i2o_device *d, *b=NULL;
+	struct i2o_controller *c;
+	struct i2ob_device *dev;
 		
 	for(i=0; i< MAX_I2O_CONTROLLERS; i++)
 	{
-		struct i2o_controller *c=i2o_find_controller(i);
-		struct i2o_device *d;
+		c=i2o_find_controller(i);
 	
 		if(c==NULL)
 			continue;
 
-		for(d=c->devices;d!=NULL;d=d->next)
-		{
+	/*
+	 *    The device list connected to the I2O Controller is doubly linked
+	 * Here we traverse the end of the list , and start claiming devices
+	 * from that end. This assures that within an I2O controller atleast
+	 * the newly created volumes get claimed after the older ones, thus
+	 * mapping to same major/minor (and hence device file name) after 
+	 * every reboot.
+	 * The exception being: 
+	 * 1. If there was a TID reuse.
+	 * 2. There was more than one I2O controller. 
+	 */
+
+	if(!bios)
+	{
+		for (d=c->devices;d!=NULL;d=d->next)
+		if(d->next == NULL)
+			b = d;
+	}
+	else
+		b = c->devices;
+
+	while(b != NULL)
+	{
+		d=b;
+		if(bios)
+			b = b->next;
+		else
+			b = b->prev;
+
 			if(d->lct_data.class_id!=I2O_CLASS_RANDOM_BLOCK_STORAGE)
 				continue;
 
 			if(d->lct_data.user_tid != 0xFFF)
 				continue;
 
+			if(bios)
+			{
+				if(d->lct_data.bios_info != 0x80)
+					continue;
+				printk(KERN_INFO "Claiming as Boot device: Controller %d, TID %d\n", c->unit, d->lct_data.tid);
+			}
+			else
+			{
+				if(d->lct_data.bios_info == 0x80)
+					continue; /*Already claimed on pass 1 */
+			}
+
 			if(i2o_claim_device(d, &i2o_block_handler))
 			{
 				printk(KERN_WARNING "i2o_block: Controller %d, TID %d\n", c->unit,
 					d->lct_data.tid);
-				printk(KERN_WARNING "\tDevice refused claim! Skipping installation\n");
+				printk(KERN_WARNING "\t%sevice refused claim! Skipping installation\n", bios?"Boot d":"D");
 				continue;
 			}
 
-			if(unit<MAX_I2OB<<4)
+			if(scan_unit<MAX_I2OB<<4)
 			{
  				/*
 				 * Get the device and fill in the
 				 * Tid and controller.
 				 */
-				struct i2ob_device *dev=&i2ob_dev[unit];
+				dev=&i2ob_dev[scan_unit];
 				dev->i2odev = d; 
 				dev->controller = c;
 				dev->unit = c->unit;
 				dev->tid = d->lct_data.tid;
 
-				if(i2ob_install_device(c,d,unit))
+				if(i2ob_install_device(c,d,scan_unit))
 					printk(KERN_WARNING "Could not install I2O block device\n");
 				else
 				{
-					unit+=16;
+					scan_unit+=16;
 					i2ob_dev_count++;
 
 					/* We want to know when device goes away */
@@ -1333,7 +1602,7 @@
 			else
 			{
 				if(!warned++)
-					printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", unit>>4);
+					printk(KERN_WARNING "i2o_block: too many device, registering only %d.\n", scan_unit>>4);
 			}
 			i2o_release_device(d, &i2o_block_handler);
 		}
@@ -1341,6 +1610,31 @@
 	}
 }
 
+static void i2ob_probe(void)
+{
+	/*
+	 *      Some overhead/redundancy involved here, while trying to
+	 *      claim the first boot volume encountered as /dev/i2o/hda
+	 *      everytime. All the i2o_controllers are searched and the
+	 *      first i2o block device marked as bootable is claimed
+	 *      If an I2O block device was booted off , the bios sets
+	 *      its bios_info field to 0x80, this what we search for.
+	 *      Assuming that the bootable volume is /dev/i2o/hda
+	 *      everytime will prevent any kernel panic while mounting
+	 *      root partition
+	 */
+
+	printk(KERN_INFO "i2o_block: Checking for Boot device...\n");
+	i2ob_scan(1);
+
+	/*
+	 *      Now the remainder.
+	 */
+	printk(KERN_INFO "i2o_block: Checking for I2O Block devices...\n");
+	i2ob_scan(0);
+}
+
+
 /*
  * New device notification handler.  Called whenever a new
  * I2O block storage device is added to the system.
@@ -1369,14 +1663,6 @@
 			break;
 	}
 
-	/*
-	 * Creating a RAID 5 volume takes a little while and the UTIL_CLAIM
-	 * will fail if we don't give the card enough time to do it's magic, 
-	 * so we just sleep for a little while and let it do it's thing
-	 */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(3*HZ);
-
 	if(i2o_claim_device(d, &i2o_block_handler))
 	{
 		printk(KERN_INFO 
@@ -1435,6 +1721,7 @@
 	if(unit >= MAX_I2OB<<4)
 	{
 		printk(KERN_ERR "i2ob_del_device called, but not in dev table!\n");
+		spin_unlock_irqrestore(&io_request_lock, flags);
 		return;
 	}
 
@@ -1492,8 +1779,6 @@
 	i2ob_media_change_flag[unit] = 1;
 
 	i2ob_dev_count--;	
-
-	return;
 }
 
 /*
@@ -1540,8 +1825,11 @@
 			msg[2] = i2ob_context|0x40000000;
 			msg[3] = (u32)query_done;
 			msg[4] = 60<<16;
-			i2o_post_wait(dev->controller, msg, 20, 2);
+			
+			DEBUG("Flushing...");
+			i2o_post_wait(dev->controller, msg, 20, 60);
 
+			DEBUG("Unlocking...");
 			/*
 			 *	Unlock the media
 			 */
@@ -1551,20 +1839,21 @@
 			msg[3] = (u32)query_done;
 			msg[4] = -1;
 			i2o_post_wait(dev->controller, msg, 20, 2);
+			
+			DEBUG("Unlocked.\n");
 		}
 	}	
 }
 
 static struct block_device_operations i2ob_fops =
 {
-   open:       i2ob_open,
-   release:    i2ob_release,
-   ioctl:         i2ob_ioctl,
-   check_media_change:  i2ob_media_change,
-   revalidate:    i2ob_revalidate,
+	open:			i2ob_open,
+	release:		i2ob_release,
+	ioctl:			i2ob_ioctl,
+	check_media_change:	i2ob_media_change,
+	revalidate:		i2ob_revalidate,
 };
 
-
 static struct gendisk i2ob_gendisk = 
 {
 	MAJOR_NR,
@@ -1573,9 +1862,10 @@
 	1<<4,
 	i2ob,
 	i2ob_sizes,
-	0,
+	MAX_I2OB,
+	NULL,
 	NULL,
-	NULL
+	&i2ob_fops,
 };
 
 
@@ -1593,7 +1883,7 @@
 	int i;
 
 	printk(KERN_INFO "I2O Block Storage OSM v0.9\n");
-	printk(KERN_INFO "   (c) Copyright 1999, 2000 Red Hat Software.\n");
+	printk(KERN_INFO "   (c) Copyright 1999-2001 Red Hat Software.\n");
 	
 	/*
 	 *	Register the block device interfaces
@@ -1629,6 +1919,7 @@
 		i2ob_dev[i].tid = 0;
 		i2ob_dev[i].head = NULL;
 		i2ob_dev[i].tail = NULL;
+		i2ob_dev[i].depth = MAX_I2OB_DEPTH;
 		i2ob_blksizes[i] = 1024;
 		i2ob_max_sectors[i] = 2;
 	}
@@ -1683,7 +1974,13 @@
 		register_disk(&i2ob_gendisk, MKDEV(MAJOR_NR,i<<4), 1<<4,
 			&i2ob_fops, 0);
 	i2ob_probe();
-	
+
+	/*
+	 *	Adding i2ob_gendisk into the gendisk list.
+	 */	
+	i2ob_gendisk.next = gendisk_head;
+	gendisk_head = &i2ob_gendisk;
+
 	return 0;
 }
 
@@ -1695,9 +1992,20 @@
 
 void cleanup_module(void)
 {
-	struct gendisk **gdp;
+	struct gendisk *gdp;
 	int i;
 	
+	if(evt_running) {
+		printk(KERN_INFO "Killing I2O block threads...");
+		i = kill_proc(evt_pid, SIGTERM, 1);
+		if(!i) {
+			printk("waiting...");
+		}
+		/* Be sure it died */
+		down(&i2ob_thread_dead);
+		printk("done.\n");
+	}
+
 	/*
 	 * Unregister for updates from any devices..otherwise we still
 	 * get them and the core jumps to random memory :O
@@ -1713,6 +2021,18 @@
 	}
 	
 	/*
+	 *	We may get further callbacks for ourself. The i2o_core
+	 *	code handles this case reasonably sanely. The problem here
+	 *	is we shouldn't get them .. but a couple of cards feel 
+	 *	obliged to tell us stuff we dont care about.
+	 *
+	 *	This isnt ideal at all but will do for now.
+	 */
+	 
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ);
+	
+	/*
 	 *	Flush the OSM
 	 */
 
@@ -1729,28 +2049,20 @@
 	 */
 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
 
-	if(evt_running) {
-		i = kill_proc(evt_pid, SIGTERM, 1);
-		if(!i) {
-			int count = 5 * 100;
-			while(evt_running && --count) {
-				current->state = TASK_INTERRUPTIBLE;
-				schedule_timeout(1);
-			}
-	
-			if(!count)
-				printk(KERN_ERR "Giving up on i2oblock thread...\n");	
-		}
-	}
-
-
 	/*
 	 *	Why isnt register/unregister gendisk in the kernel ???
 	 */
 
-	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
-		if (*gdp == &i2ob_gendisk)
-			break;
-
+	if (gendisk_head == &i2ob_gendisk) {
+		gendisk_head = i2ob_gendisk.next;
+		}
+	else {
+		for (gdp = gendisk_head; gdp; gdp = gdp->next)
+			if (gdp->next == &i2ob_gendisk)
+			{
+				gdp->next = i2ob_gendisk.next;
+				break;
+			}
+	}
 }
 #endif
diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_config.c linux/drivers/i2o/i2o_config.c
--- v2.4.4/linux/drivers/i2o/i2o_config.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/i2o/i2o_config.c	Tue May  1 16:10:37 2001
@@ -42,7 +42,6 @@
 
 static int i2o_cfg_context = -1;
 static void *page_buf;
-static void *i2o_buffer;
 static spinlock_t i2o_config_lock = SPIN_LOCK_UNLOCKED;
 struct wait_queue *i2o_wait_queue;
 
@@ -499,6 +498,7 @@
 	if(!res)
 	{
 		i2o_unlock_controller(c);
+		kfree(query);
 		return -ENOMEM;
 	}
 
@@ -517,16 +517,25 @@
 		msg[7] = 0xD4000000|(kcmd.qlen);
 		msg[8] = virt_to_bus(query);
 	}
-
-	token = i2o_post_wait(c, msg, 9*4, 10);
-	if(token)
+	/*
+	Wait for a considerable time till the Controller 
+	does its job before timing out. The controller might
+	take more time to process this request if there are
+	many devices connected to it.
+	*/
+	token = i2o_post_wait_mem(c, msg, 9*4, 400, query, res);
+	if(token < 0)
 	{
 		printk(KERN_DEBUG "token = %#10x\n", token);
 		i2o_unlock_controller(c);
-		kfree(res);
-		if(kcmd.qlen) kfree(query);
+		
+		if(token != -ETIMEDOUT)
+		{
+			kfree(res);
+			if(kcmd.qlen) kfree(query);
+		}
 
-		return -ETIMEDOUT;
+		return token;
 	}
 	i2o_unlock_controller(c);
 
@@ -595,17 +604,18 @@
 	msg[8]= virt_to_bus(buffer);
 
 //	printk("i2o_config: swdl frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
-	status = i2o_post_wait(c, msg, sizeof(msg), 60);
+	status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL);
 
 	i2o_unlock_controller(c);
-	kfree(buffer);
+	if(status != -ETIMEDOUT)
+		kfree(buffer);
 	
 	if (status != I2O_POST_WAIT_OK)
 	{
 		// it fails if you try and send frags out of order
 		// and for some yet unknown reasons too
 		printk(KERN_INFO "i2o_config: swdl failed, DetailedStatus = %d\n", status);
-		return -ETIMEDOUT;
+		return status;
 	}
 
 	return 0;
@@ -660,14 +670,15 @@
 	msg[8]= virt_to_bus(buffer);
 	
 //	printk("i2o_config: swul frag %d/%d (size %d)\n", curfrag, maxfrag, fragsize);
-	status = i2o_post_wait(c, msg, sizeof(msg), 60);
+	status = i2o_post_wait_mem(c, msg, sizeof(msg), 60, buffer, NULL);
 	i2o_unlock_controller(c);
 	
 	if (status != I2O_POST_WAIT_OK)
 	{
-		kfree(buffer);
+		if(status != -ETIMEDOUT)
+			kfree(buffer);
 		printk(KERN_INFO "i2o_config: swul failed, DetailedStatus = %d\n", status);
-		return -ETIMEDOUT;
+		return status;
 	}
 	
 	__copy_to_user(kxfer.buf, buffer, fragsize);
@@ -787,13 +798,6 @@
 	struct i2o_evt_get kget;
 	unsigned int flags;
 
-	// access_ok doesn't check for NULL?!?!
-	if(!arg)
-		return -EFAULT;
-	
-	if(!access_ok(VERIFY_WRITE, uget,  sizeof(struct i2o_evt_get)))
-		return -EFAULT;
-
 	for(p = open_files; p; p = p->next)
 		if(p->q_id == id)
 			break;
@@ -812,8 +816,8 @@
 	kget.lost = p->q_lost;
 	spin_unlock_irqrestore(&i2o_config_lock, flags);
 
-	__copy_to_user(uget, &kget, sizeof(struct i2o_evt_get));
-
+	if(copy_to_user(uget, &kget, sizeof(struct i2o_evt_get)))
+		return -EFAULT;
 	return 0;
 }
 
@@ -958,8 +962,6 @@
 		kfree(page_buf);
 	if(i2o_cfg_context != -1)
 		i2o_remove_handler(&cfg_handler);
-	if(i2o_buffer)
-		kfree(i2o_buffer);
 }
  
 EXPORT_NO_SYMBOLS;
diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.4.4/linux/drivers/i2o/i2o_core.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/i2o/i2o_core.c	Tue May  1 16:10:37 2001
@@ -1,5 +1,5 @@
-/* 
- * Core I2O structure managment 
+/*
+ * Core I2O structure management 
  * 
  * (C) Copyright 1999   Red Hat Software 
  *
@@ -49,7 +49,7 @@
 
 #include "i2o_lan.h"
 
-// #define DRIVERDEBUG
+//#define DRIVERDEBUG
 
 #ifdef DRIVERDEBUG
 #define dprintk(s, args...) printk(s, ## args)
@@ -147,10 +147,12 @@
  */ 
 struct i2o_post_wait_data
 {
-	int status;
-	u32 id;
-	wait_queue_head_t *wq;
-	struct i2o_post_wait_data *next;
+	int *status;		/* Pointer to status block on caller stack */
+	int *complete;		/* Pointer to completion flag on caller stack */
+	u32 id;			/* Unique identifier */
+	wait_queue_head_t *wq;	/* Wake up for caller (NULL for dead) */
+	struct i2o_post_wait_data *next;	/* Chain */
+	void *mem[2];		/* Memory blocks to recover on failure path */
 };
 static struct i2o_post_wait_data *post_wait_queue = NULL;
 static u32 post_wait_id = 0;	// Unique ID for each post_wait
@@ -169,10 +171,10 @@
 	I2O_CLASS_EXECUTIVE
 };
 
-
 /*
- * Used when queing a reply to be handled later
+ * Used when queueing a reply to be handled later
  */
+ 
 struct reply_info
 {
 	struct i2o_controller *iop;
@@ -199,10 +201,12 @@
 static spinlock_t i2o_evt_lock = SPIN_LOCK_UNLOCKED;
 
 /*
- * Semaphore used to syncrhonize event handling thread with 
+ * Semaphore used to synchronize event handling thread with 
  * interrupt handler.
  */
-DECLARE_MUTEX(evt_sem);
+ 
+static DECLARE_MUTEX(evt_sem);
+static DECLARE_MUTEX_LOCKED(evt_dead);
 DECLARE_WAIT_QUEUE_HEAD(evt_wait);
 
 static struct notifier_block i2o_reboot_notifier =
@@ -212,6 +216,12 @@
         0
 };
 
+/*
+ *	Config options
+ */
+
+static int verbose = 0;
+MODULE_PARM(verbose, "i");
 
 /*
  * I2O Core reply handler
@@ -252,7 +262,7 @@
 	if(msg[2]&0x80000000)	// Post wait message
 	{
 		if (msg[4] >> 24)
-			status = -(msg[4] & 0xFFFF);
+			status = (msg[4] & 0xFFFF);
 		else
 			status = I2O_POST_WAIT_OK;
 	
@@ -369,6 +379,9 @@
 	d->controller=c;
 	d->owner=NULL;
 	d->next=c->devices;
+	d->prev=NULL;
+	if (c->devices != NULL)
+		c->devices->prev=d;
 	c->devices=d;
 	*d->dev_name = 0;
 
@@ -696,7 +709,7 @@
 {
 	down(&i2o_configuration_lock);
 	if (d->owner) {
-		printk(KERN_INFO "Device claim called, but dev allready owned by %s!",
+		printk(KERN_INFO "Device claim called, but dev already owned by %s!",
 		       h->name);
 		up(&i2o_configuration_lock);
 		return -EBUSY;
@@ -721,37 +734,59 @@
  *	Drop a claim by an OSM on a given I2O device. The handler is cleared
  *	and 0 is returned on success.
  *
+ *	AC - some devices seem to want to refuse an unclaim until they have
+ *	finished internal processing. It makes sense since you don't want a
+ *	new device to go reconfiguring the entire system until you are done.
+ *	Thus we are prepared to wait briefly.
  */
 
 int i2o_release_device(struct i2o_device *d, struct i2o_handler *h)
 {
 	int err = 0;
+	int tries;
 
 	down(&i2o_configuration_lock);
 	if (d->owner != h) {
-		printk(KERN_INFO "Claim release called, but not owned by %s!",
+		printk(KERN_INFO "Claim release called, but not owned by %s!\n",
 		       h->name);
 		up(&i2o_configuration_lock);
 		return -ENOENT;
 	}	
 
-	d->owner = NULL;
-
-	if(i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, 
-			   I2O_CLAIM_PRIMARY))
+	for(tries=0;tries<10;tries++)
 	{
-		err = -ENXIO;
-		d->owner = h;
-	}
+		d->owner = NULL;
 
+		/*
+		 *	If the controller takes a nonblocking approach to
+		 *	releases we have to sleep/poll for a few times.
+		 */
+		 
+		if((err=i2o_issue_claim(I2O_CMD_UTIL_RELEASE, d->controller, d->lct_data.tid, I2O_CLAIM_PRIMARY)) )
+		{
+			err = -ENXIO;
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(HZ);
+		}
+		else
+		{
+			err=0;
+			break;
+		}
+	}
 	up(&i2o_configuration_lock);
 	return err;
 }
 
-/*
- * Called by OSMs to let the core know that they want to be
- * notified if the given device is deleted from the system.
+/**
+ * 	i2o_device_notify_on	-	Enable deletion notifiers
+ *	@d: device for notification
+ *	@h: handler to install
+ *
+ *	Called by OSMs to let the core know that they want to be
+ *	notified if the given device is deleted from the system.
  */
+
 int i2o_device_notify_on(struct i2o_device *d, struct i2o_handler *h)
 {
 	int i;
@@ -773,7 +808,11 @@
 	return 0;
 }
 
-/*
+/**
+ * 	i2o_device_notify_off	-	Remove deletion notifiers
+ *	@d: device for notification
+ *	@h: handler to remove
+ *
  * Called by OSMs to let the core know that they no longer
  * are interested in the fate of the given device.
  */
@@ -794,9 +833,18 @@
 	return -ENOENT;
 }
 
-/*
- * Event registration API
+/**
+ *	i2o_event_register	-	register interest in an event
+ * 	@c: Controller to register interest with
+ *	@tid: I2O task id
+ *	@init_context: initiator context to use with this notifier
+ *	@tr_context: transaction context to use with this notifier
+ *	@evt_mask: mask of events
+ *
+ *	Create and posts an event registration message to the task. No reply
+ *	is waited for, or expected. Errors in posting will be reported.
  */
+ 
 int i2o_event_register(struct i2o_controller *c, u32 tid, 
 		u32 init_context, u32 tr_context, u32 evt_mask)
 {
@@ -814,11 +862,13 @@
 }
 
 /*
- * Event ack API
+ * 	i2o_event_ack	-	acknowledge an event
+ *	@c: controller 
+ *	@msg: pointer to the UTIL_EVENT_REGISTER reply we received
  *
- * We just take a pointer to the original UTIL_EVENT_REGISTER reply
- * message and change the function code since that's what spec
- * describes an EventAck message looking like.
+ *	We just take a pointer to the original UTIL_EVENT_REGISTER reply
+ *	message and change the function code since that's what spec
+ *	describes an EventAck message looking like.
  */
  
 int i2o_event_ack(struct i2o_controller *c, u32 *msg)
@@ -850,12 +900,12 @@
 
 	while(1)
 	{
-		down_interruptible(&evt_sem);
-		if(signal_pending(current))
+		if(down_interruptible(&evt_sem))
 		{
 			dprintk(KERN_INFO "I2O event thread dead\n");
+			printk("exiting...");
 			evt_running = 0;
-			return 0;	
+			up_and_exit(&evt_dead, 0);
 		}
 
 		/* 
@@ -922,6 +972,10 @@
 					kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
 				int i;
 
+				if (d == NULL) {
+					printk(KERN_EMERG "i2oevtd: out of memory\n");
+					break;
+				}
 				memcpy(&d->lct_data, &msg[5], sizeof(i2o_lct_entry));
 	
 				d->next = NULL;
@@ -974,7 +1028,11 @@
 				printk(KERN_WARNING "%s: Warning notification received!"
 					"Check configuration for errors!\n", c->name);
 				break;
-	
+				
+			case I2O_EVT_IND_EVT_MASK_MODIFIED:
+				/* Well I guess that was us hey .. */
+				break;
+					
 			default:
 				printk(KERN_WARNING "%s: No handler for event (0x%08x)\n", c->name, msg[4]);
 				break;
@@ -1124,12 +1182,6 @@
 		m=(struct i2o_message *)bus_to_virt(mv);
 		msg=(u32*)m;
 
-		/*
-		 *	Temporary Debugging
-		 */
-		if(m->function==0x15)
-			printk(KERN_ERR "%s: UTFR!\n", c->name);
-
 		i=i2o_handlers[m->initiator_context&(MAX_I2O_MODULES-1)];
 		if(i && i->reply)
 			i->reply(i,c,m);
@@ -1219,9 +1271,9 @@
 
 
 /**
- *	i2o_wait_message
+ *	i2o_wait_message	-	obtain an i2o message from the IOP
  *	@c: controller
- *	@why: explanation
+ *	@why: explanation 
  *
  *	This function waits up to 5 seconds for a message slot to be
  *	available. If no message is available it prints an error message
@@ -1266,9 +1318,11 @@
 	char str[22];
 	int ret;
 	int unit = d->lct_data.tid;
-	
-	printk(KERN_INFO "Target ID %d.\n", unit);
 
+	if(verbose==0)
+		return;
+		
+	printk(KERN_INFO "Target ID %d.\n", unit);
 	if((ret=i2o_query_scalar(c, unit, 0xF100, 3, buf, 16))>=0)
 	{
 		buf[16]=0;
@@ -1279,13 +1333,11 @@
 		buf[16]=0;
 		printk(KERN_INFO "     Device: %s\n", buf);
 	}
-#if 0
 	if(i2o_query_scalar(c, unit, 0xF100, 5, buf, 16)>=0)
 	{
 		buf[16]=0;
 		printk(KERN_INFO "     Description: %s\n", buf);
 	}
-#endif	
 	if((ret=i2o_query_scalar(c, unit, 0xF100, 6, buf, 8))>=0)
 	{
 		buf[8]=0;
@@ -1581,7 +1633,7 @@
 
 
 /**
- *	i2o_reset_controller
+ *	i2o_reset_controller	-	reset an IOP
  *	@c: controller to reset
  *
  *	Reset the IOP into INIT state and wait until IOP gets into RESET state.
@@ -1601,7 +1653,10 @@
 	/* Quiesce all IOPs first */
 
 	for (iop = i2o_controller_chain; iop; iop = iop->next)
-		i2o_quiesce_controller(iop);
+	{
+		if(iop->type != I2O_TYPE_PCI || !iop->bus.pci.dpt)
+			i2o_quiesce_controller(iop);
+	}
 
 	m=i2o_wait_message(c, "AdapterReset");
 	if(m==0xFFFFFFFF)	
@@ -1628,19 +1683,19 @@
 
 	/* Wait for a reply */
 	time=jiffies;
-	while(status[0]==0)
+	while(*status==0)
 	{
 		if((jiffies-time)>=20*HZ)
 		{
 			printk(KERN_ERR "IOP reset timeout.\n");
-			kfree(status);
+			// Better to leak this for safety: kfree(status);
 			return -ETIMEDOUT;
 		}
 		schedule();
 		barrier();
 	}
 
-	if (status[0]==I2O_CMD_IN_PROGRESS)
+	if (*status==I2O_CMD_IN_PROGRESS)
 	{ 
 		/* 
 		 * Once the reset is sent, the IOP goes into the INIT state 
@@ -1799,7 +1854,7 @@
 	u32 msg[6];
 	int ret, size = sizeof(i2o_hrt);
 
-	/* Read first just the header to figure out the real size */
+	/* First read just the header to figure out the real size */
 
 	do  {
 		if (c->hrt == NULL) {
@@ -1816,7 +1871,18 @@
 		msg[4]= (0xD0000000 | size);	/* Simple transaction */
 		msg[5]= virt_to_bus(c->hrt);	/* Dump it here */
 
-		if ((ret = i2o_post_wait(c, msg, sizeof(msg), 20))) {
+		ret = i2o_post_wait_mem(c, msg, sizeof(msg), 20, c->hrt, NULL);
+		
+		if(ret == -ETIMEDOUT)
+		{
+			/* The HRT block we used is in limbo somewhere. When the iop wakes up
+			   we will recover it */
+			c->hrt = NULL;
+			return ret;
+		}
+		
+		if(ret<0)
+		{
 			printk(KERN_ERR "%s: Unable to get HRT (status=%#x)\n",
 				c->name, -ret);	
 			return ret;
@@ -1845,14 +1911,15 @@
 static int i2o_systab_send(struct i2o_controller *iop)
 {
 	u32 msg[12];
-	u32 privmem[2];
-	u32 privio[2];
 	int ret;
+	u32 *privbuf = kmalloc(16, GFP_KERNEL);
+	if(privbuf == NULL)
+		return -ENOMEM;
 
-	privmem[0] = iop->status_block->current_mem_base;
-	privmem[1] = iop->status_block->current_mem_size;
-	privio[0] = iop->status_block->current_io_base;
-	privio[1] = iop->status_block->current_io_size;
+	privbuf[0] = iop->status_block->current_mem_base;
+	privbuf[1] = iop->status_block->current_mem_size;
+	privbuf[2] = iop->status_block->current_io_base;
+	privbuf[3] = iop->status_block->current_io_size;
 
 	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
 	msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
@@ -1864,20 +1931,33 @@
  	 * Provide three SGL-elements:
  	 * System table (SysTab), Private memory space declaration and 
  	 * Private i/o space declaration  
+ 	 *
+ 	 * FIXME: provide these for controllers needing them
  	 */
 	msg[6] = 0x54000000 | sys_tbl_len;
 	msg[7] = virt_to_bus(sys_tbl);
 	msg[8] = 0x54000000 | 0;
-	msg[9] = virt_to_bus(privmem);
+	msg[9] = virt_to_bus(privbuf);
 	msg[10] = 0xD4000000 | 0;
-	msg[11] = virt_to_bus(privio);
+	msg[11] = virt_to_bus(privbuf+8);
 
-	if ((ret=i2o_post_wait(iop, msg, sizeof(msg), 120)))
-		printk(KERN_INFO "%s: Unable to set SysTab (status=%#x).\n", 
+	ret=i2o_post_wait_mem(iop, msg, sizeof(msg), 120, privbuf, NULL);
+	
+	if(ret==-ETIMEDOUT)
+	{
+		printk(KERN_ERR "%s: SysTab setup timed out.\n", iop->name);
+	}
+	else if(ret<0)
+	{
+		printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", 
 			iop->name, -ret);
+		kfree(privbuf);
+	}
 	else
+	{
 		dprintk(KERN_INFO "%s: SysTab set.\n", iop->name);
-
+		kfree(privbuf);
+	}
 	i2o_status_get(iop); // Entered READY state
 
 	return ret;	
@@ -2162,7 +2242,16 @@
 		msg[6] = 0xD0000000|size;
 		msg[7] = virt_to_bus(c->lct);
 
-		if ((ret=i2o_post_wait(c, msg, sizeof(msg), 120))) {
+		ret=i2o_post_wait_mem(c, msg, sizeof(msg), 120, c->lct, NULL);
+		
+		if(ret == -ETIMEDOUT)
+		{
+			c->lct = NULL;
+			return ret;
+		}
+		
+		if(ret<0)
+		{
 			printk(KERN_ERR "%s: LCT Get failed (status=%#x.\n", 
 				c->name, -ret);	
 			return ret;
@@ -2206,8 +2295,11 @@
 /*
  *	Bring a controller online into OPERATIONAL state. 
  */
+ 
 int i2o_online_controller(struct i2o_controller *iop)
 {
+	u32 v;
+	
 	if (i2o_systab_send(iop) < 0)
 		return -1;
 
@@ -2223,6 +2315,15 @@
 	if (i2o_lct_get(iop) < 0)
 		return -1;
 
+	/* Check battery status */
+	 
+	iop->battery = 0;
+	if(i2o_query_scalar(iop, ADAPTER_TID, 0x0000, 4, &v, 4)>=0)
+	{
+		if(v&16)
+			iop->battery = 1;
+	}
+
 	return 0;
 }
 
@@ -2346,83 +2447,134 @@
 	return 0;
 }
 
-/*
- * This core API allows an OSM to post a message and then be told whether
- * or not the system received a successful reply.  It is useful when
- * the OSM does not want to know the exact 3
+/**
+ * 	i2o_post_wait_mem	-	I2O query/reply with DMA buffers
+ *	@c: controller
+ *	@msg: message to send
+ *	@len: length of message
+ *	@timeout: time in seconds to wait
+ *	@mem1: attached memory buffer 1
+ *	@mem2: attached memory buffer 2
+ *
+ * 	This core API allows an OSM to post a message and then be told whether
+ *	or not the system received a successful reply. 
+ *
+ *	If the message times out then the value '-ETIMEDOUT' is returned. This
+ *	is a special case. In this situation the message may (should) complete
+ *	at an indefinite time in the future. When it completes it will use the
+ *	memory buffers attached to the request. If -ETIMEDOUT is returned then
+ *	the memory buffers must not be freed. Instead the event completion will
+ *	free them for you. In all other cases the buffers are your problem.
+ *
+ *	Pass NULL for unneeded buffers.
  */
-int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
+ 
+int i2o_post_wait_mem(struct i2o_controller *c, u32 *msg, int len, int timeout, void *mem1, void *mem2)
 {
 	DECLARE_WAIT_QUEUE_HEAD(wq_i2o_post);
-	int status = 0;
+	int complete = 0;
+	int status;
 	int flags = 0;
-	struct i2o_post_wait_data *p1, *p2;
 	struct i2o_post_wait_data *wait_data =
 		kmalloc(sizeof(struct i2o_post_wait_data), GFP_KERNEL);
 
 	if(!wait_data)
 		return -ENOMEM;
 
+	/*
+	 *	Create a new notification object
+	 */
+	wait_data->status = &status;
+	wait_data->complete = &complete;
+	wait_data->mem[0] = mem1;
+	wait_data->mem[1] = mem2;
 	/* 
-	 * The spin locking is needed to keep anyone from playing 
-	 * with the queue pointers and id while we do the same
+	 *	Queue the event with its unique id
 	 */
 	spin_lock_irqsave(&post_wait_lock, flags);
+
 	wait_data->next = post_wait_queue;
 	post_wait_queue = wait_data;
 	wait_data->id = (++post_wait_id) & 0x7fff;
-	spin_unlock_irqrestore(&post_wait_lock, flags);
-
 	wait_data->wq = &wq_i2o_post;
-	wait_data->status = -ETIMEDOUT;
 
+	spin_unlock_irqrestore(&post_wait_lock, flags);
+
+	/*
+	 *	Fill in the message id
+	 */
+	 
 	msg[2] = 0x80000000|(u32)core_context|((u32)wait_data->id<<16);
 	
+	/*
+	 *	Post the message to the controller. At some point later it 
+	 *	will return. If we time out before it returns then
+	 *	complete will be zero.  From the point post_this returns
+	 *	the wait_data may have been deleted.
+	 */
 	if ((status = i2o_post_this(c, msg, len))==0) {
-		interruptible_sleep_on_timeout(&wq_i2o_post, HZ * timeout);
-		status = wait_data->status;
+		sleep_on_timeout(&wq_i2o_post, HZ * timeout);
 	}  
-
-#ifdef DRIVERDEBUG
-	if(status == -ETIMEDOUT)
-		printk(KERN_INFO "%s: POST WAIT TIMEOUT\n",c->name);
-#endif
-
-	/* 
-	 * Remove the entry from the queue.
-	 * Since i2o_post_wait() may have been called again by
-	 * a different thread while we were waiting for this 
-	 * instance to complete, we're not guaranteed that 
-	 * this entry is at the head of the queue anymore, so 
-	 * we need to search for it, find it, and delete it.
-	 */
-	p2 = NULL;
+	else
+		return -EIO;
+		
+	if(signal_pending(current))
+		status = -EINTR;
+		
 	spin_lock_irqsave(&post_wait_lock, flags);
-	for(p1 = post_wait_queue; p1; p2 = p1, p1 = p1->next) {
-		if(p1 == wait_data) {
-			if(p2)
-				p2->next = p1->next;
-			else
-				post_wait_queue = p1->next;
-
-			break;
+	barrier();	/* Be sure we see complete as it is locked */
+	if(!complete)
+	{
+		/* 
+		 *	Mark the entry dead. We cannot remove it. This is important.
+		 *	When it does terminate (which it must do if the controller hasnt
+		 *	died..) then it will otherwise scribble on stuff.
+		 *	!complete lets us safely check if the entry is still
+		 *	allocated and thus we can write into it
+		 */
+		wait_data->wq = NULL;
+		status = -ETIMEDOUT;
+	}
+	else
+	{
+		/* Debugging check - remove me soon */
+		if(status == -ETIMEDOUT)
+		{
+			printk("TIMEDOUT BUG!\n");
+			status = -EIO;
 		}
 	}
+	/* And the wait_data is not leaked either! */	 
 	spin_unlock_irqrestore(&post_wait_lock, flags);
-	
-	kfree(wait_data);
-
 	return status;
 }
 
+/**
+ * 	i2o_post_wait		-	I2O query/reply
+ *	@c: controller
+ *	@msg: message to send
+ *	@len: length of message
+ *	@timeout: time in seconds to wait
+ *
+ * 	This core API allows an OSM to post a message and then be told whether
+ *	or not the system received a successful reply. 
+ */
+ 
+int i2o_post_wait(struct i2o_controller *c, u32 *msg, int len, int timeout)
+{
+	return i2o_post_wait_mem(c, msg, len, timeout, NULL, NULL);
+}
+
 /*
  * i2o_post_wait is completed and we want to wake up the 
  * sleeping proccess. Called by core's reply handler.
  */
+
 static void i2o_post_wait_complete(u32 context, int status)
 {
-	struct i2o_post_wait_data *p1 = NULL;
-
+	struct i2o_post_wait_data **p1, *q;
+	unsigned long flags;
+	
 	/* 
 	 * We need to search through the post_wait 
 	 * queue to see if the given message is still
@@ -2435,18 +2587,49 @@
 	 * Lock needed to keep anyone from moving queue pointers 
 	 * around while we're looking through them.
 	 */
-	spin_lock(&post_wait_lock);
-	for(p1 = post_wait_queue; p1; p1 = p1->next) {
-		if(p1->id == ((context >> 16) & 0x7fff)) {
-			p1->status = status;
-			wake_up_interruptible(p1->wq);
+
+	spin_lock_irqsave(&post_wait_lock, flags);
+
+	for(p1 = &post_wait_queue; *p1!=NULL; p1 = &((*p1)->next)) 
+	{
+		q = (*p1);
+		if(q->id == ((context >> 16) & 0x7fff)) {
+			/*
+			 *	Delete it 
+			 */
+			 
+			*p1 = q->next;
+			
+			/*
+			 *	Live or dead ?
+			 */
+			 
+			if(q->wq)
+			{
+				/* Live entry - wakeup and set status */
+				*q->status = status;
+				*q->complete = 1;
+				wake_up(q->wq);
+			}
+			else
+			{
+				/*
+				 *	Free resources. Caller is dead
+				 */
+				if(q->mem[0])
+					kfree(q->mem[0]);
+				if(q->mem[1])
+					kfree(q->mem[1]);
+				printk(KERN_WARNING "i2o_post_wait event completed after timeout.\n");
+			}
+			kfree(q);
 			spin_unlock(&post_wait_lock);
 			return;
 		}
 	}
 	spin_unlock(&post_wait_lock);
 
-	printk(KERN_DEBUG "i2o_post_wait reply after timeout!\n");
+	printk(KERN_DEBUG "i2o_post_wait: Bogus reply!\n");
 }
 
 /*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
@@ -2461,25 +2644,52 @@
                 void *oplist, int oplen, void *reslist, int reslen)
 {
 	u32 msg[9]; 
-	u8 *res = (u8 *)reslist;
 	u32 *res32 = (u32*)reslist;
 	u32 *restmp = (u32*)reslist;
 	int len = 0;
 	int i = 0;
 	int wait_status;
-
+	u32 *opmem, *resmem;
+	
+	/* Get DMAable memory */
+	opmem = kmalloc(oplen, GFP_KERNEL);
+	if(opmem == NULL)
+		return -ENOMEM;
+	memcpy(opmem, oplist, oplen);
+	
+	resmem = kmalloc(reslen, GFP_KERNEL);
+	if(resmem == NULL)
+	{
+		kfree(opmem);
+		return -ENOMEM;
+	}
+	
 	msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
 	msg[1] = cmd << 24 | HOST_TID << 12 | tid; 
 	msg[3] = 0;
 	msg[4] = 0;
 	msg[5] = 0x54000000 | oplen;	/* OperationList */
-	msg[6] = virt_to_bus(oplist);
+	msg[6] = virt_to_bus(opmem);
 	msg[7] = 0xD0000000 | reslen;	/* ResultList */
-	msg[8] = virt_to_bus(reslist);
+	msg[8] = virt_to_bus(resmem);
 
-	if((wait_status = i2o_post_wait(iop, msg, sizeof(msg), 10)))
-		return wait_status; 	/* -DetailedStatus */
+	wait_status = i2o_post_wait_mem(iop, msg, sizeof(msg), 10, opmem, resmem);
+	
+	/*
+	 *	This only looks like a memory leak - don't "fix" it.	
+	 */
+	if(wait_status == -ETIMEDOUT)
+		return wait_status;
 
+	/* Query failed */
+	if(wait_status != 0)
+	{
+		kfree(resmem);
+		kfree(opmem);
+		return wait_status;
+	}
+	
+	memcpy(reslist, resmem, reslen);
 	/*
 	 * Calculate number of bytes of Result LIST
 	 * We need to loop through each Result BLOCK and grab the length
@@ -2500,13 +2710,13 @@
 			 *	If this is the only request,than we return an error
 			 */
 			if((res32[0]&0x0000FFFF) == 1)
-				return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
+			{
+				return -((res32[1] >> 16) & 0xFF); /* -BlockStatus */
+			}
 		}
-
 		len += restmp[0] & 0x0000FFFF;	/* Length of res BLOCK */
 		restmp += restmp[0] & 0x0000FFFF;	/* Skip to next BLOCK */
 	}
-
 	return (len << 2);  /* bytes used by result list */
 }
 
@@ -2526,10 +2736,10 @@
 	size = i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, iop, tid, 
 		opblk, sizeof(opblk), resblk, sizeof(resblk));
 		
-	if (size < 0)
-		return size;	
-
 	memcpy(buf, resblk+8, buflen);  /* cut off header */
+	
+	if(size>buflen)
+		return buflen;
 	return size;
 }
 
@@ -2570,6 +2780,8 @@
 				opblk, 12+buflen, resblk, sizeof(resblk));
 
 	kfree(opblk);
+	if(size>buflen)
+		return buflen;
 	return size;
 }
 
@@ -2614,6 +2826,8 @@
 				opblk, 10+ibuflen, resblk, reslen);
 
 	kfree(opblk);
+	if(size>reslen)
+		return reslen;
 	return size;
 }
 
@@ -2662,6 +2876,8 @@
 				opblk, 10+buflen, resblk, sizeof(resblk));
 
 	kfree(opblk);
+	if(size>buflen)
+		return buflen;
 	return size;
 }
 
@@ -3113,8 +3329,6 @@
 }
 
 
-#ifdef MODULE
-
 EXPORT_SYMBOL(i2o_controller_chain);
 EXPORT_SYMBOL(i2o_num_controllers);
 EXPORT_SYMBOL(i2o_find_controller);
@@ -3131,6 +3345,7 @@
 
 EXPORT_SYMBOL(i2o_post_this);
 EXPORT_SYMBOL(i2o_post_wait);
+EXPORT_SYMBOL(i2o_post_wait_mem);
 
 EXPORT_SYMBOL(i2o_query_scalar);
 EXPORT_SYMBOL(i2o_set_scalar);
@@ -3147,6 +3362,8 @@
 
 EXPORT_SYMBOL(i2o_get_class_name);
 
+#ifdef MODULE
+
 MODULE_AUTHOR("Red Hat Software");
 MODULE_DESCRIPTION("I2O Core");
 
@@ -3206,17 +3423,13 @@
 	 * If this is shutdown time, the thread has already been killed
 	 */
 	if(evt_running) {
+		printk("Terminating i2o threads...");
 		stat = kill_proc(evt_pid, SIGTERM, 1);
 		if(!stat) {
-			int count = 10 * 100;
-			while(evt_running && count--) {
-				current->state = TASK_INTERRUPTIBLE;
-				schedule_timeout(1);
-			}
-	
-			if(!count)
-				printk(KERN_ERR "i2o: Event thread still running!\n");
+			printk("waiting...");
+			down(&evt_dead);
 		}
+		printk("done.\n");
 	}
 
 #ifdef CONFIG_I2O_PCI_MODULE
diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.4.4/linux/drivers/i2o/i2o_pci.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/i2o/i2o_pci.c	Tue May  1 16:11:29 2001
@@ -160,6 +160,10 @@
 
 	c->bus.pci.irq = -1;
 
+	c->bus.pci.queue_buggy = 0;
+	c->bus.pci.dpt = 0;
+	c->bus.pci.short_req = 0;
+
 	c->irq_mask = (volatile u32 *)(mem+0x34);
 	c->post_port = (volatile u32 *)(mem+0x40);
 	c->reply_port = (volatile u32 *)(mem+0x44);
@@ -175,6 +179,30 @@
 	
 	c->type = I2O_TYPE_PCI;
 
+	/*
+	 *	Cards that fall apart if you hit them with large I/O
+	 *	loads...
+	 */
+	 
+	if(dev->vendor == PCI_VENDOR_ID_NCR && dev->device == 0x0630)
+	{
+		c->bus.pci.short_req=1;
+		printk(KERN_INFO "I2O: Symbios FC920 workarounds activated.\n");
+	}
+	if(dev->subsystem_vendor == PCI_VENDOR_ID_PROMISE)
+	{
+		c->bus.pci.queue_buggy=1;
+		printk(KERN_INFO "I2O: Promise workarounds activated.\n");
+	}
+
+	/*
+	 *	Cards that go bananas if you quiesce them before you reset
+	 *	them
+	 */
+	 
+	if(dev->vendor == PCI_VENDOR_ID_DPT)
+		c->bus.pci.dpt=1;
+	
 	/* 
 	 * Enable Write Combining MTRR for IOP's memory region
 	 */
@@ -186,13 +214,12 @@
 * since the region contains the Messaging unit which shouldn't be cached.
 */
 	c->bus.pci.mtrr_reg1 = -1;
-	if(dev->vendor == PCI_VENDOR_ID_INTEL)
+	if(dev->vendor == PCI_VENDOR_ID_INTEL || dev->vendor == PCI_VENDOR_ID_DPT)
 	{
-	printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); 
-	c->bus.pci.mtrr_reg1 =
-		mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1);
-	if(c->bus.pci.mtrr_reg1< 0)
-		printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n");
+		printk(KERN_INFO "I2O: MTRR workaround for Intel i960 processor\n"); 
+		c->bus.pci.mtrr_reg1 =	mtrr_add(c->mem_phys, 65536, MTRR_TYPE_UNCACHABLE, 1);
+		if(c->bus.pci.mtrr_reg1< 0)
+			printk(KERN_INFO "i2o_pci: Error in setting MTRR_TYPE_UNCACHABLE\n");
 	}
 
 #endif
diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_proc.c linux/drivers/i2o/i2o_proc.c
--- v2.4.4/linux/drivers/i2o/i2o_proc.c	Fri Nov 17 16:51:47 2000
+++ linux/drivers/i2o/i2o_proc.c	Tue May  1 16:09:53 2001
@@ -2356,7 +2356,7 @@
 	len += sprintf(buf+len, "Packet orphan limit           : %d\n", work32[2]);
 
 	len += sprintf(buf+len, "Tx modes : 0x%08x\n", work32[3]);
-	len += sprintf(buf+len, "    [%s] HW CRC supression\n",
+	len += sprintf(buf+len, "    [%s] HW CRC suppression\n",
 			(work32[3]&0x00000004) ? "+" : "-");
 	len += sprintf(buf+len, "    [%s] HW IPv4 checksum\n",
 			(work32[3]&0x00000100) ? "+" : "-");
@@ -2368,7 +2368,7 @@
 			(work32[3]&0x00000800) ? "+" : "-");
 	len += sprintf(buf+len, "    [%s] HW ICMP checksum\n",
 			(work32[3]&0x00001000) ? "+" : "-");
-	len += sprintf(buf+len, "    [%s] Loopback supression enable\n",
+	len += sprintf(buf+len, "    [%s] Loopback suppression enable\n",
 			(work32[3]&0x00002000) ? "+" : "-");
 
 	len += sprintf(buf+len, "Rx modes : 0x%08x\n", work32[4]);
diff -u --recursive --new-file v2.4.4/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c
--- v2.4.4/linux/drivers/i2o/i2o_scsi.c	Mon Oct 30 14:44:29 2000
+++ linux/drivers/i2o/i2o_scsi.c	Tue May  1 16:09:53 2001
@@ -262,7 +262,7 @@
 	
 	if(st)
 	{
-		/* An error has occured */
+		/* An error has occurred */
 
 		dprintk((KERN_DEBUG "SCSI error %08X", m[4]));
 			
diff -u --recursive --new-file v2.4.4/linux/drivers/ide/hd.c linux/drivers/ide/hd.c
--- v2.4.4/linux/drivers/ide/hd.c	Fri Feb 16 16:02:36 2001
+++ linux/drivers/ide/hd.c	Sat Apr 28 11:27:53 2001
@@ -892,13 +892,7 @@
 
 	for (i=max_p - 1; i >=0 ; i--) {
 		int minor = start + i;
-		kdev_t devi = MKDEV(MAJOR_NR, minor);
-		struct super_block *sb = get_super(devi); 
-
-		sync_dev(devi);
-		if (sb)
-			invalidate_inodes(sb);
-		invalidate_buffers(devi);
+		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
 		gdev->part[minor].start_sect = 0;
 		gdev->part[minor].nr_sects = 0;
 	}
diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide-pci.c linux/drivers/ide/ide-pci.c
--- v2.4.4/linux/drivers/ide/ide-pci.c	Thu Apr 19 22:57:06 2001
+++ linux/drivers/ide/ide-pci.c	Tue May  1 16:05:00 2001
@@ -581,7 +581,7 @@
 		if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20265))
 		{
 			printk(KERN_INFO "ide: Found promise 20265 in RAID mode.\n");
-			if(dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
+			if(dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_INTEL &&
 				dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960)
 			{
 				printk(KERN_INFO "ide: Skipping Promise PDC20265 attached to I2O RAID controller.\n");
diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide-pnp.c linux/drivers/ide/ide-pnp.c
--- v2.4.4/linux/drivers/ide/ide-pnp.c	Wed May 24 18:38:26 2000
+++ linux/drivers/ide/ide-pnp.c	Tue May  1 16:06:23 2001
@@ -49,7 +49,7 @@
 
 /* ISA PnP device table entry */
 struct pnp_dev_t {
-	unsigned int vendor, device;
+	unsigned short card_vendor, card_device, vendor, device;
 	int (*init_fn)(struct pci_dev *dev, int enable);
 };
 
@@ -81,8 +81,9 @@
 
 /* Add your devices here :)) */
 struct pnp_dev_t idepnp_devices[] __initdata = {
-	/* Generic ESDI/IDE/ATA compatible hard disk controller
 */
-	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600),
+  	/* Generic ESDI/IDE/ATA compatible hard disk controller */
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0600),
 		pnpide_generic_init },
 	{	0 }
 };
diff -u --recursive --new-file v2.4.4/linux/drivers/ide/ide.c linux/drivers/ide/ide.c
--- v2.4.4/linux/drivers/ide/ide.c	Wed Apr 11 19:06:12 2001
+++ linux/drivers/ide/ide.c	Tue May  1 16:05:00 2001
@@ -179,6 +179,8 @@
 static int	ide_lock;
 #endif /* __mc68000__ || CONFIG_APUS */
 
+int noautodma = 0;
+
 /*
  * ide_modules keeps track of the available IDE chipset/probe/driver modules.
  */
@@ -1762,11 +1764,7 @@
 	for (p = 0; p < (1<<PARTN_BITS); ++p) {
 		if (drive->part[p].nr_sects > 0) {
 			kdev_t devp = MKDEV(major, minor+p);
-			struct super_block * sb = get_super(devp);
-			fsync_dev          (devp);
-			if (sb)
-				invalidate_inodes(sb);
-			invalidate_buffers (devp);
+			invalidate_device(devp, 1);
 			set_blocksize(devp, 1024);
 		}
 		drive->part[p].start_sect = 0;
@@ -1983,9 +1981,7 @@
 		for (p = 0; p < (1<<PARTN_BITS); ++p) {
 			if (drive->part[p].nr_sects > 0) {
 				kdev_t devp = MKDEV(hwif->major, minor+p);
-				struct super_block * sb = get_super(devp);
-				if (sb) invalidate_inodes(sb);
-				invalidate_buffers (devp);
+				invalidate_device(devp, 0);
 			}
 		}
 #ifdef CONFIG_PROC_FS
@@ -2893,6 +2889,12 @@
 		return 1;
 	}
 #endif /* CONFIG_BLK_DEV_IDEDOUBLER */
+
+	if (!strcmp(s, "ide=nodma")) {
+		printk("IDE: Prevented DMA\n");
+		noautodma = 1;
+		return 1;
+	}
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
 	if (!strcmp(s, "ide=reverse")) {
diff -u --recursive --new-file v2.4.4/linux/drivers/ide/opti621.c linux/drivers/ide/opti621.c
--- v2.4.4/linux/drivers/ide/opti621.c	Tue Nov  7 11:02:24 2000
+++ linux/drivers/ide/opti621.c	Tue May  1 16:05:00 2001
@@ -118,7 +118,7 @@
 /* Uncommnent for disable read prefetch.
  * There is some readprefetch capatibility in hdparm,
  * but when I type hdparm -P 1 /dev/hda, I got errors
- * and till reset drive is inacessible.
+ * and till reset drive is inaccessible.
  * This (hw) read prefetch is safe on my drive.
  */
 
diff -u --recursive --new-file v2.4.4/linux/drivers/ide/osb4.c linux/drivers/ide/osb4.c
--- v2.4.4/linux/drivers/ide/osb4.c	Sun Feb  4 10:05:30 2001
+++ linux/drivers/ide/osb4.c	Tue May  1 16:05:00 2001
@@ -402,10 +402,16 @@
 #ifdef DEBUG
 	printk("%s: reg64 == 0x%08x\n", name, reg64);
 #endif
-	reg64 &= ~0x0000A000;
-#ifdef CONFIG_SMP
-	reg64 |= 0x00008000;
-#endif
+
+//	reg64 &= ~0x0000A000;
+//#ifdef CONFIG_SMP
+//	reg64 |= 0x00008000;
+//#endif
+	/* Assume the APIC was set up properly by the BIOS for now . If it
+	   wasnt we need to do a fix up _way_ earlier. Bits 15,10,3 control
+	   APIC enable, routing and decode */
+	   
+	reg64 &= ~0x00002000;	
 	pci_write_config_dword(isa_dev, 0x64, reg64);
 
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
@@ -441,7 +447,8 @@
 #else /* CONFIG_BLK_DEV_IDEDMA */
 
 	if (hwif->dma_base) {
-		hwif->autodma = 1;
+		if (!noautodma)
+			hwif->autodma = 1;
 		hwif->dmaproc = &osb4_dmaproc;
 	} else {
 		hwif->autodma = 0;
diff -u --recursive --new-file v2.4.4/linux/drivers/ide/pdc202xx.c linux/drivers/ide/pdc202xx.c
--- v2.4.4/linux/drivers/ide/pdc202xx.c	Thu Apr 19 22:57:06 2001
+++ linux/drivers/ide/pdc202xx.c	Tue May  1 16:05:00 2001
@@ -101,13 +101,6 @@
 	return(pdc202xx_dma_verbose(drive_pci));
 }
 
-char *pdc202xx_interrupt_verbose (u8 sc1d)
-{
-	char *p = NULL;
-	p += sprintf(p,"0x%02x        ", sc1d);
-	return (char *)p;
-}
-
 static char * pdc202xx_info (char *buf, struct pci_dev *dev)
 {
 	char *p = buf;
@@ -862,7 +855,8 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA
 	if (hwif->dma_base) {
 		hwif->dmaproc = &pdc202xx_dmaproc;
-		hwif->autodma = 1;
+		if (!noautodma)
+			hwif->autodma = 1;
 	} else {
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
diff -u --recursive --new-file v2.4.4/linux/drivers/ide/rz1000.c linux/drivers/ide/rz1000.c
--- v2.4.4/linux/drivers/ide/rz1000.c	Thu Apr 13 22:54:26 2000
+++ linux/drivers/ide/rz1000.c	Tue May  1 16:05:00 2001
@@ -94,4 +94,4 @@
 		init_rz1000 (dev, "RZ1001");
 }
 
-#endif CONFIG_BLK_DEV_IDEPCI
+#endif /* CONFIG_BLK_DEV_IDEPCI */
diff -u --recursive --new-file v2.4.4/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c
--- v2.4.4/linux/drivers/macintosh/via-cuda.c	Sun Sep 17 09:48:05 2000
+++ linux/drivers/macintosh/via-cuda.c	Tue May  1 16:05:00 2001
@@ -170,7 +170,7 @@
     }
 
     /* Clear and enable interrupts, but only on PPC. On 68K it's done  */
-    /* for us by the the main VIA driver in arch/m68k/mac/via.c        */
+    /* for us by the main VIA driver in arch/m68k/mac/via.c        */
 
 #ifndef CONFIG_MAC
     via[IFR] = 0x7f; eieio();	/* clear interrupts by writing 1s */
diff -u --recursive --new-file v2.4.4/linux/drivers/media/video/tvaudio.c linux/drivers/media/video/tvaudio.c
--- v2.4.4/linux/drivers/media/video/tvaudio.c	Mon Feb 19 14:43:36 2001
+++ linux/drivers/media/video/tvaudio.c	Tue May  1 16:05:00 2001
@@ -124,7 +124,7 @@
 
 
 /* ---------------------------------------------------------------------- */
-/* i2c adresses                                                           */
+/* i2c addresses                                                           */
 
 static unsigned short normal_i2c[] = {
 	I2C_TDA8425   >> 1,
diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c
--- v2.4.4/linux/drivers/mtd/ftl.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/ftl.c	Sat Apr 28 11:27:54 2001
@@ -915,9 +915,6 @@
 
 static release_t ftl_close(struct inode *inode, struct file *file)
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-    struct super_block *sb = get_super(inode->i_rdev);
-#endif
     int minor = MINOR(inode->i_rdev);
     partition_t *part = myparts[minor >> 4];
     int i;
@@ -925,11 +922,7 @@
     DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
 
     /* Flush all writes */
-    fsync_dev(inode->i_rdev);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-    if (sb) invalidate_inodes(sb);
-#endif
-    invalidate_buffers(inode->i_rdev);
+    invalidate_device(inode->i_rdev, 1);
 
     /* Wait for any pending erase operations to complete */
     if (part->mtd->sync)
diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/mtdblock.c linux/drivers/mtd/mtdblock.c
--- v2.4.4/linux/drivers/mtd/mtdblock.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/mtdblock.c	Sat Apr 28 11:27:54 2001
@@ -355,19 +355,12 @@
 {
 	int dev;
 	struct mtdblk_dev *mtdblk;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	struct super_block * sb = get_super(inode->i_rdev);
-#endif
    	DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
 
 	if (inode == NULL)
 		release_return(-ENODEV);
    
-	fsync_dev(inode->i_rdev);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-	if (sb) invalidate_inodes(sb);
-#endif
-	invalidate_buffers(inode->i_rdev);
+	invalidate_device(inode->i_rdev, 1);
 
 	dev = MINOR(inode->i_rdev);
 	mtdblk = mtdblks[dev];
diff -u --recursive --new-file v2.4.4/linux/drivers/mtd/nftl.c linux/drivers/mtd/nftl.c
--- v2.4.4/linux/drivers/mtd/nftl.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/mtd/nftl.c	Sat Apr 28 11:27:54 2001
@@ -997,17 +997,13 @@
 
 static int nftl_release(struct inode *inode, struct file *fp)
 {
-	struct super_block *sb = get_super(inode->i_rdev);
 	struct NFTLrecord *thisNFTL;
 
 	thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
 
 	DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
 
-	fsync_dev(inode->i_rdev);
-	if (sb)
-		invalidate_inodes(sb);
-	invalidate_buffers(inode->i_rdev);
+	invalidate_device(inode->i_rdev, 1);
 
 	if (thisNFTL->mtd->sync)
 		thisNFTL->mtd->sync(thisNFTL->mtd);
diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/Config.in linux/drivers/net/irda/Config.in
--- v2.4.4/linux/drivers/net/irda/Config.in	Fri Jan 28 19:36:22 2000
+++ linux/drivers/net/irda/Config.in	Tue May  1 16:05:00 2001
@@ -5,14 +5,6 @@
 dep_tristate 'IrTTY (uses Linux serial driver)' CONFIG_IRTTY_SIR $CONFIG_IRDA
 dep_tristate 'IrPORT (IrDA serial driver)' CONFIG_IRPORT_SIR $CONFIG_IRDA
 
-comment 'FIR device drivers'
-dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR  $CONFIG_IRDA
-dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
-dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
-if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
-fi
-
 comment 'Dongle support' 
 bool 'Serial dongle support' CONFIG_DONGLE
 if [ "$CONFIG_DONGLE" != "n" ]; then
@@ -22,6 +14,15 @@
    dep_tristate '  Greenwich GIrBIL dongle' CONFIG_GIRBIL_DONGLE $CONFIG_IRDA
    dep_tristate '  Parallax LiteLink dongle' CONFIG_LITELINK_DONGLE $CONFIG_IRDA
    dep_tristate '  Old Belkin dongle' CONFIG_OLD_BELKIN_DONGLE $CONFIG_IRDA   
+fi
+
+comment 'FIR device drivers'
+dep_tristate 'IrDA USB dongles (Experimental)' CONFIG_USB_IRDA $CONFIG_IRDA $CONFIG_USB $CONFIG_EXPERIMENTAL
+dep_tristate 'NSC PC87108/PC87338' CONFIG_NSC_FIR  $CONFIG_IRDA
+dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
+dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
+if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
+dep_tristate 'SMC IrCC (Experimental)' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
 fi
 
 endmenu
diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/Makefile linux/drivers/net/irda/Makefile
--- v2.4.4/linux/drivers/net/irda/Makefile	Fri Dec 29 14:07:22 2000
+++ linux/drivers/net/irda/Makefile	Tue May  1 16:05:00 2001
@@ -12,6 +12,7 @@
 
 obj-$(CONFIG_IRTTY_SIR)		+= irtty.o
 obj-$(CONFIG_IRPORT_SIR)	+= 		irport.o
+obj-$(CONFIG_USB_IRDA)		+= irda-usb.o
 obj-$(CONFIG_NSC_FIR)		+= nsc-ircc.o
 obj-$(CONFIG_WINBOND_FIR)	+= w83977af_ir.o
 obj-$(CONFIG_TOSHIBA_FIR)	+= toshoboe.o
diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- v2.4.4/linux/drivers/net/irda/irda-usb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/irda/irda-usb.c	Tue May  1 16:05:00 2001
@@ -0,0 +1,1176 @@
+/*****************************************************************************
+ *
+ * Filename:      irda-usb.c
+ * Version:       0.9
+ * Description:   IrDA-USB Driver
+ * Status:        Experimental 
+ * Author:        Dag Brattli <dag@brattli.net>
+ *
+ *      Copyright (C) 2001, Dag Brattli <dag@brattli.net>
+ *      Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
+ *	Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
+ *          
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/malloc.h>
+#include <linux/rtnetlink.h>
+#include <linux/usb.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irlap.h>
+#include <net/irda/irda_device.h>
+#include <net/irda/wrapper.h>
+
+#include <net/irda/irda-usb.h>
+
+static u32 min_turn_times[]  = { 10000, 5000, 1000, 500, 100, 50, 10, 0 }; /* us */
+static int qos_mtt_bits = 0;
+
+static void irda_usb_dump_class_desc(struct irda_class_desc *desc);
+static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum);
+static void irda_usb_disconnect(struct usb_device *dev, void *ptr);
+static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
+static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
+static int irda_usb_open(struct irda_usb_cb *self);
+static int irda_usb_close(struct irda_usb_cb *self);
+static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb);
+static void write_bulk_callback(purb_t purb);
+static void irda_usb_receive(purb_t purb);
+static int irda_usb_net_init(struct net_device *dev);
+static int irda_usb_net_open(struct net_device *dev);
+static int irda_usb_net_close(struct net_device *dev);
+static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void irda_usb_net_timeout(struct net_device *dev);
+static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev);
+
+/* Master instance for each hardware found */
+#define NIRUSB 4		/* Max number of USB-IrDA dongles */
+static struct irda_usb_cb irda_instance[NIRUSB];
+
+/* These are the currently known IrDA USB dongles. Add new dongles here */
+static struct usb_device_id dongles[] = {
+	/* ACTiSYS Corp,  ACT-IR2000U FIR-USB Adapter */
+	{ USB_DEVICE(0x9c4, 0x011), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW },
+	/* KC Technology Inc.,  KC-180 USB IrDA Device */
+	{ USB_DEVICE(0x50f, 0x180), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW },
+	/* Extended Systems, Inc.,  XTNDAccess IrDA USB (ESI-9685) */
+	{ USB_DEVICE(0x8e9, 0x100), driver_info: IUC_SPEED_BUG | IUC_NO_WINDOW },
+	{ match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
+	  bInterfaceClass: USB_CLASS_APP_SPEC,
+	  bInterfaceSubClass: USB_CLASS_IRDA,
+	  driver_info: IUC_DEFAULT, },
+	{ }, /* The end */
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ * Note : it might be worth protecting this function by a global
+ * spinlock...
+ */
+static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
+			   const struct usb_device_id *id)
+{
+	struct irda_usb_cb *self = NULL;
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct irda_class_desc *irda_desc;
+	int capability = id->driver_info;
+	int ret;
+	int ep;
+	int i;
+
+	IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
+	
+	MESSAGE("IRDA-USB found at address %d\n", dev->devnum);
+
+	/* Try to cleanup all instance that have a pending disconnect
+	 * Instance will be in this state is the disconnect() occurs
+	 * before the net_close().
+	 * Jean II */
+	for (i = 0; i < NIRUSB; i++) {
+		struct irda_usb_cb *irda = &irda_instance[i];
+		if ((irda->usbdev != NULL) &&
+		    (irda->present == 0) &&
+		    (irda->netopen == 0)) {
+			IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n");
+			irda_usb_disconnect(irda->usbdev, (void *) irda);
+		}
+	}
+
+	/* Find an free instance to handle this new device... */
+	self = NULL;
+	for (i = 0; i < NIRUSB; i++) {
+		if(irda_instance[i].usbdev == NULL) {
+			self = &irda_instance[i];
+			break;
+		}
+	}
+	if (self == NULL) {
+		IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n",
+			   NIRUSB);
+		return NULL;
+	}
+
+	/* Reset the instance */
+	self->present = 0;
+	self->netopen = 0;
+
+       /* Is this really necessary? */
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+		err("set_configuration failed");
+		return NULL;
+	}
+	
+        /* Is this really necessary? */
+	ret = usb_set_interface(dev, ifnum, 0);
+	IRDA_DEBUG(0, "usb-irda: set interface result %d\n", ret);
+	switch (ret) {
+		case USB_ST_NOERROR:		/* 0 */
+			break;
+		case USB_ST_STALL:		/* -EPIPE = -32 */
+			usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
+			IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" );
+			break;
+		default:
+			IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret);
+			return NULL;
+			break;
+	}
+	
+	/* Find our endpoints */
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	endpoint = interface->endpoint;
+	ep = endpoint[0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	if ((endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+		self->bulk_in_ep = ep;
+	else {
+		self->bulk_out_ep = ep;
+		self->bulk_out_mtu = endpoint[0].wMaxPacketSize;
+	}
+
+	ep = endpoint[1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	if ((endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+		self->bulk_in_ep = ep;
+	else {
+		self->bulk_out_ep = ep;
+		self->bulk_out_mtu = endpoint[1].wMaxPacketSize;
+	}
+
+	if (self->bulk_out_ep == 0 || self->bulk_in_ep == 0 ||
+	    endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK ||
+	    endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK) 
+	{
+		ERROR(__FUNCTION__ "(), Bogus endpoints");
+		return NULL;
+	}
+
+	/* Find IrDA class descriptor */
+	irda_desc = irda_usb_find_class_desc(dev, ifnum);
+	if (irda_desc == NULL)
+		return NULL;
+	
+	self->irda_desc =  irda_desc;	
+	self->present = 1;
+	self->netopen = 0;
+	self->capability = capability;
+	self->usbdev = dev;
+	ret = irda_usb_open(self);
+	if (ret)
+		return NULL;
+
+	return self;
+}
+
+/*
+ * Function irda_usb_find_class_desc(dev, ifnum)
+ *
+ *    Returns instance of IrDA class descriptor, or NULL if not found
+ *
+ */
+static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	struct irda_class_desc *desc, *ptr;
+	int ret;
+		
+	desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
+	if (desc == NULL) 
+		return NULL;
+	memset(desc, 0, sizeof(struct irda_class_desc));
+	
+	ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc));
+	IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret);
+	if (ret) {
+		WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret);  
+	}
+
+	/* Check if we found it? */
+	if (desc->bDescriptorType == USB_DT_IRDA)
+		return desc;
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n");
+	
+	/* Check if the class descriptor is interleaved with standard descriptors */
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr);
+	if (ret) {
+		kfree(desc);
+		return NULL;
+	}
+	*desc = *ptr;
+#if 0
+	irda_usb_dump_class_desc(desc);
+#endif	
+	return desc;
+}
+
+/*
+ * Function usb_irda_dump_class_desc(desc)
+ *
+ *    Prints out the contents of the IrDA class descriptor
+ *
+ */
+static void irda_usb_dump_class_desc(struct irda_class_desc *desc)
+{
+	printk("bLength=%x\n", desc->bLength);
+	printk("bDescriptorType=%x\n", desc->bDescriptorType);
+	printk("bcdSpecRevision=%x\n", desc->bcdSpecRevision); 
+	printk("bmDataSize=%x\n", desc->bmDataSize);
+	printk("bmWindowSize=%x\n", desc->bmWindowSize);
+	printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);
+	printk("wBaudRate=%x\n", desc->wBaudRate);
+	printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs);
+	printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
+	printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList);
+}												
+	
+static void irda_usb_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct irda_usb_cb *self = (struct irda_usb_cb *) ptr;
+	int i;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	/* Oups ! We are not there any more */
+	self->present = 0;
+
+	/* Hum... Check if networking is still active */
+	if (self->netopen) {
+		/* Accept no more transmissions */
+		/*netif_device_detach(self->netdev);*/
+		netif_stop_queue(self->netdev);
+		/* Stop all the receive URBs */
+		for (i = 0; i < IU_MAX_RX_URBS; i++)
+			usb_unlink_urb(&(self->rx_urb[i]));
+		/* Cancel Tx and speed URB */
+		usb_unlink_urb(&(self->tx_urb));
+		usb_unlink_urb(&(self->speed_urb));
+
+		IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n");
+		/* better not do anything just yet, usb_irda_cleanup()
+		 * will do whats needed */
+		return;
+	}
+
+	/* Cleanup the device stuff */
+	irda_usb_close(self);
+	/* No longer attached to USB bus */
+	self->usbdev = NULL;
+	IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n");
+}
+
+static struct usb_driver irda_driver = {
+	name:		"irda-usb",
+	probe:		irda_usb_probe,
+	disconnect:	irda_usb_disconnect,
+	id_table:	dongles,
+};
+
+static void irda_usb_init_qos(struct irda_usb_cb *self)
+{
+	struct irda_class_desc *desc;
+
+	desc = self->irda_desc;
+	
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&self->qos);
+
+	self->qos.baud_rate.bits       = desc->wBaudRate;
+	self->qos.min_turn_time.bits   = desc->bmMinTurnaroundTime;
+	self->qos.additional_bofs.bits = desc->bmAdditionalBOFs;
+	self->qos.window_size.bits     = desc->bmWindowSize;
+	self->qos.data_size.bits       = desc->bmDataSize;
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits);
+
+	/* Don't always trust what the dongle tell us */
+	if (self->capability & IUC_SIR_ONLY)
+		self->qos.baud_rate.bits	&= 0xff;
+	if (self->capability & IUC_SMALL_PKT)
+		self->qos.data_size.bits	 = 0x07;
+	if (self->capability & IUC_NO_WINDOW)
+		self->qos.window_size.bits	 = 0x01;
+	if (self->capability & IUC_MAX_WINDOW)
+		self->qos.window_size.bits	 = 0x7f;
+	if (self->capability & IUC_MAX_XBOFS)
+		self->qos.additional_bofs.bits	 = 0x01;
+
+#if 1
+	/* Module parameter can override the rx window size */
+	if (qos_mtt_bits)
+		self->qos.min_turn_time.bits = qos_mtt_bits;
+#endif	    
+	/* 
+	 * Note : most of those values apply only for the receive path,
+	 * the transmit path will be set differently - Jean II 
+	 */
+	irda_qos_bits_to_value(&self->qos);
+
+	self->flags |= IFF_SIR;
+	if (self->qos.baud_rate.value > 115200)
+		self->flags |= IFF_MIR;
+	if (self->qos.baud_rate.value > 1152000)
+		self->flags |= IFF_FIR;
+	if (self->qos.baud_rate.value > 4000000)
+		self->flags |= IFF_VFIR;
+}
+
+static int irda_usb_open(struct irda_usb_cb *self)
+{
+	struct net_device *netdev;
+	int err;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	spin_lock_init(&self->lock);
+
+	irda_usb_init_qos(self);
+	
+	self->tx_list = hashbin_new(HB_GLOBAL);
+
+	/* Create a network device for us */
+	if (!(netdev = dev_alloc("irda%d", &err))) {
+		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		return -1;
+	}
+	self->netdev = netdev;
+ 	netdev->priv = (void *) self;
+
+	/* Override the network functions we need to use */
+	netdev->init            = irda_usb_net_init;
+	netdev->hard_start_xmit = irda_usb_hard_xmit;
+	netdev->tx_timeout	= irda_usb_net_timeout;
+	netdev->watchdog_timeo  = 110*HZ/1000;  /* 110 ms > USB timeout */
+	netdev->open            = irda_usb_net_open;
+	netdev->stop            = irda_usb_net_close;
+	netdev->get_stats	= irda_usb_net_get_stats;
+	netdev->do_ioctl        = irda_usb_net_ioctl;
+
+	rtnl_lock();
+	err = register_netdevice(netdev);
+	rtnl_unlock();
+	if (err) {
+		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		return -1;
+	}
+	MESSAGE("IrDA: Registered device %s\n", netdev->name);
+
+	return 0;
+}
+
+static int irda_usb_close(struct irda_usb_cb *self)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -1;);
+
+	/* Remove netdevice */
+	if (self->netdev) {
+		rtnl_lock();
+		unregister_netdevice(self->netdev);
+		self->netdev = NULL;
+		rtnl_unlock();
+	}
+	hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any);
+	
+	return 0;
+}
+
+/*
+ * Function irda_usb_build_header(self, skb, header)
+ *
+ *   Builds USB-IrDA outbound header
+ *
+ * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2
+ * that the setting of the link speed and xbof number in this outbound header
+ * should be applied *AFTER* the frame has been sent.
+ * Unfortunately, some devices are not compliant with that... It seems that
+ * reading the spec is far too difficult...
+ * Jean II
+ */
+static void irda_usb_build_header(struct irda_usb_cb *self, u8 *header,
+				  int force)
+{
+	/* Set the negotiated link speed */
+	if (self->new_speed != -1) {
+		/* Hum... Ugly hack :-(
+		 * Some device are not compliant with the spec and change
+		 * parameters *before* sending the frame. - Jean II
+		 */
+		if ((self->capability & IUC_SPEED_BUG) &&
+		    (!force) && (self->speed != -1)) 
+		{
+			/* No speed and xbofs change here
+			 * (we'll do it later in the write callback) */
+			IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n");
+			*header = 0;
+			return;
+		}
+
+		IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed);
+		self->speed = self->new_speed;
+		self->new_speed = -1;
+
+		switch (self->speed) {
+		case 2400:
+		        *header = SPEED_2400;
+			break;
+		default:
+		case 9600:
+			*header = SPEED_9600;
+			break;
+		case 19200:
+			*header = SPEED_19200;
+			break;
+		case 38400:
+			*header = SPEED_38400;
+			break;
+		case 57600:
+		        *header = SPEED_57600;
+			break;
+		case 115200:
+		        *header = SPEED_115200;
+			break;
+		case 576000:
+		        *header = SPEED_576000;
+			break;
+		case 1152000:
+		        *header = SPEED_1152000;
+			break;
+		case 4000000:
+		        *header = SPEED_4000000;
+			self->new_xbofs = 0;
+			break;
+		}
+	} else
+		/* No change */
+		*header = 0;
+	
+	/* Set the negotiated additional XBOFS */
+	if (self->new_xbofs != -1) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs);
+		self->xbofs = self->new_xbofs;
+		self->new_xbofs = -1;
+
+		switch (self->xbofs) {
+		case 48:
+			*header |= 0x10;
+			break;
+		case 28:
+		case 24: /* USB spec 1.0 says 24 */
+			*header |= 0x20;
+			break;
+		default:
+		case 12:
+			*header |= 0x30;
+			break;
+		case 5: /* Bug in IrLAP spec? (should be 6) */
+		case 6:
+			*header |= 0x40;
+			break;
+		case 3:
+			*header |= 0x50;
+			break;
+		case 2:
+			*header |= 0x60;
+			break;
+		case 1:
+			*header |= 0x70;
+			break;
+		case 0:
+			*header |= 0x80;
+			break;
+		}
+	}
+}
+
+static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
+{
+	struct sk_buff *skb;
+	unsigned long flags;
+	purb_t purb;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
+		   self->new_speed, self->new_xbofs);
+
+	purb = &self->speed_urb;
+	if (purb->status != USB_ST_NOERROR) {
+		WARNING(__FUNCTION__ "(), URB still in use!\n");
+		return;
+	}
+	spin_lock_irqsave(&self->lock, flags);
+
+	/* Allocate the fake frame */
+	skb = dev_alloc_skb(IRDA_USB_SPEED_MTU);
+	if (!skb)
+		return;
+	((struct irda_skb_cb *)skb->cb)->context = self;
+
+	/* Set the new speed and xbofs in this fake frame */
+	irda_usb_build_header(self, skb_put(skb, USB_IRDA_HEADER), 1);
+
+	/* Submit the 0 length IrDA frame to trigger new speed settings */
+        FILL_BULK_URB(purb, self->usbdev,
+		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
+                      skb->data, IRDA_USB_MAX_MTU,
+                      write_bulk_callback, skb);
+	purb->transfer_buffer_length = skb->len;
+	purb->transfer_flags |= USB_QUEUE_BULK;
+	purb->timeout = MSECS_TO_JIFFIES(100);
+
+	if ((ret = usb_submit_urb(purb))) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n");
+	}
+	spin_unlock_irqrestore(&self->lock, flags);
+}
+
+static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct irda_usb_cb *self = netdev->priv;
+	purb_t purb = &self->tx_urb;
+	unsigned long flags;
+	s32 speed;
+	s16 xbofs;
+	int mtt;
+
+	/* Check if the device is still there */
+	if ((!self) || (!self->present)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n");
+		return 1;	/* Failed */
+	}
+
+	netif_stop_queue(netdev);
+
+	/* Check if we need to change the number of xbofs */
+        xbofs = irda_get_next_xbofs(skb);
+        if ((xbofs != self->xbofs) && (xbofs != -1)) {
+		self->new_xbofs = xbofs;
+	}
+
+        /* Check if we need to change the speed */
+	speed = irda_get_next_speed(skb);
+	if ((speed != self->speed) && (speed != -1)) {
+		/* Set the desired speed */
+		self->new_speed = speed;
+
+		/* Check for empty frame */
+		if (!skb->len) {
+			/* IrLAP send us an empty frame to make us change the
+			 * speed. Changing speed with the USB adapter is in
+			 * fact sending an empty frame to the adapter, so we
+			 * could just let the present function do its job.
+			 * However, we would wait for min turn time,
+			 * do an extra memcpy and increment packet counters...
+			 * Jean II */
+			irda_usb_change_speed_xbofs(self);
+			netdev->trans_start = jiffies;
+			dev_kfree_skb(skb);
+			/* Will netif_wake_queue() in callback */
+			return 0;
+		}
+	}
+
+	if (purb->status != USB_ST_NOERROR) {
+		WARNING(__FUNCTION__ "(), URB still in use!\n");
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	/* Make room for IrDA-USB header */
+	if (skb_cow(skb, USB_IRDA_HEADER)) {
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
+	spin_lock_irqsave(&self->lock, flags);
+	
+	/* Change setting for next frame */
+	irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);
+
+	/* FIXME: Make macro out of this one */
+	((struct irda_skb_cb *)skb->cb)->context = self;
+
+        FILL_BULK_URB(purb, self->usbdev, 
+		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
+                      skb->data, IRDA_USB_MAX_MTU,
+                      write_bulk_callback, skb);
+	purb->transfer_buffer_length = skb->len;
+	purb->transfer_flags |= USB_QUEUE_BULK;
+	purb->timeout = MSECS_TO_JIFFIES(100);
+	
+	/* Generate min turn time */
+	mtt = irda_get_mtt(skb);
+	if (mtt) {
+		int diff;
+		get_fast_time(&self->now);
+		diff = self->now.tv_usec - self->stamp.tv_usec;
+		if (diff < 0)
+			diff += 1000000;
+
+                /* Check if the mtt is larger than the time we have
+		 * already used by all the protocol processing
+		 */
+		if (mtt > diff) {
+			mtt -= diff;
+			if (mtt > 1000) {
+				/* 
+				* FIXME: can we do better than this? Maybe call
+				* a function which sends a frame to a non 
+				* existing device, or change the speed to the 
+				* current one a number of times just to burn 
+				* time a better way.
+				*/															
+				mdelay(mtt/1000);
+				irda_usb_write_bulk(self, purb);
+				goto out;	
+			} else
+				udelay(mtt);
+		}
+	}	
+	irda_usb_write_bulk(self, purb);
+out:
+	spin_unlock_irqrestore(&self->lock, flags);
+	
+	return 0;
+}
+
+static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb)
+{
+	int len = purb->transfer_buffer_length; 
+	int res;
+	
+	if ((res = usb_submit_urb(purb))) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n");
+		self->stats.tx_errors++;
+		netif_start_queue(self->netdev);
+
+		return;
+	}
+	self->stats.tx_packets++;
+        self->stats.tx_bytes += len;
+	self->netdev->trans_start = jiffies;
+	
+	/* Send empty frame if size if a multiple of the USB max packet size */
+	ASSERT(self->bulk_out_mtu == 64, return;);
+	if ((len % self->bulk_out_mtu) == 0) {
+		/* Borrow speed urb */
+		purb = &self->speed_urb;
+		FILL_BULK_URB(purb, self->usbdev,
+			      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
+			      self, /* Anything not on the stack will do */
+			      IRDA_USB_MAX_MTU, NULL, NULL);
+		purb->transfer_buffer_length = 0;
+		purb->transfer_flags |= USB_QUEUE_BULK;
+		res = usb_submit_urb(purb);
+	}
+}
+
+/*
+ * Note : this function will be called with both tx_urb and speed_urb...
+ */
+static void write_bulk_callback(purb_t purb)
+{
+	struct sk_buff *skb = purb->context;
+	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
+	
+	/* We should always have a context */
+	if (self == NULL) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n");
+		return;
+	}
+
+	/* urb is now available */
+	purb->status = USB_ST_NOERROR;
+
+	dev_kfree_skb_any(skb);
+	purb->context = NULL;
+
+        /* Check for timeout and other USB nasties */
+        if (purb->status != USB_ST_NOERROR) {
+	        /* I get a lot of -ECONNABORTED = -103 here - Jean II */
+	        WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", 
+			purb->status, purb->transfer_flags);
+	        /* Don't do anything here, that might confuse the USB layer,
+	         * and we could go in recursion and blow the kernel stack...
+	         * Instead, we will wait for irda_usb_net_timeout(), the
+	         * network layer watchdog, to fix the situation.
+	         * Jean II */
+	        /* A reset of the dongle might be welcomed here - Jean II */
+	        return;
+	}
+													
+
+	/* URB is now available */
+	purb->status = USB_ST_NOERROR;
+
+	/* If the network is closed, stop everything */
+	if ((!self->netopen) || (!self->present)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n");
+		return;
+	}
+
+	/* If we need to change the speed or xbofs, do it now */
+	if ((self->new_speed != -1) || (self->new_xbofs != -1)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n");
+		irda_usb_change_speed_xbofs(self);
+	} else {
+		/* Otherwise, allow the stack to send more packets */
+		netif_wake_queue(self->netdev);
+	}
+}
+
+static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
+{
+	struct irda_skb_cb *cb;
+	int ret;
+
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+
+	/* Check that we have an urb */
+	if (!purb) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n");
+		return;
+	}
+
+	/* Allocate new skb if it has not been recycled */
+	if (!skb) {
+		skb = dev_alloc_skb(IRDA_USB_MAX_MTU + 1);
+		if (!skb) {
+			/* If this ever happen, we are in deep s***.
+			 * Basically, the Rx path will stop... */
+			IRDA_DEBUG(0, __FUNCTION__ "(), Failed to allocate Rx skb\n");
+			return;
+		}
+	} else  {
+		/* Reset recycled skb */
+		skb->data = skb->tail = skb->head;
+		skb->len = 0;
+	}
+	/* Make sure IP header get aligned (IrDA header is 5 bytes ) */
+	skb_reserve(skb, 1);
+
+	/* Save ourselves */
+	cb = (struct irda_skb_cb *) skb->cb;
+	cb->context = self;
+
+	/* Reinitialize URB */
+	FILL_BULK_URB(purb, self->usbdev, 
+		      usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), 
+		      skb->data, skb->truesize,
+                      irda_usb_receive, skb);
+	purb->transfer_flags |= USB_QUEUE_BULK;
+	purb->status = USB_ST_NOERROR;
+	purb->next = NULL; /* Make sure we don't auto resubmit */ 
+	
+	ret = usb_submit_urb(purb);
+	if (ret) {
+		/* If this ever happen, we are in deep s***.
+		 * Basically, the Rx path will stop... */
+		IRDA_DEBUG(0, __FUNCTION__ "(), Failed to submit Rx URB %d\n", ret);
+	}
+}
+
+/*
+ * Function irda_usb_receive(purb)
+ *
+ *     Called by the USB subsystem when a frame has been received
+ *
+ */
+static void irda_usb_receive(purb_t purb) 
+{
+	struct sk_buff *skb = (struct sk_buff *) purb->context;
+	struct irda_usb_cb *self; 
+	struct irda_skb_cb *cb;
+	struct sk_buff *new;
+	
+	/* Find ourselves */
+	cb = (struct irda_skb_cb *) skb->cb;
+	ASSERT(cb != NULL, return;);
+	self = (struct irda_usb_cb *) cb->context;
+	ASSERT(self != NULL, return;);
+
+	/* If the network is closed or the device gone, stop everything */
+	if ((!self->netopen) || (!self->present)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone!\n");
+		/* Don't re-submit the URB : will stall the Rx path */
+		return;
+	}
+	
+	/* Check the status */
+	if (purb->status != USB_ST_NOERROR) {
+		switch (purb->status) {
+		case USB_ST_CRC:		/* -EILSEQ */
+			self->stats.rx_errors++;
+			self->stats.rx_crc_errors++;	
+			break;
+		case -ECONNRESET:
+		        WARNING(__FUNCTION__ "(), Connection Reset !!!\n");
+			/* uhci_cleanup_unlink() is going to kill the Rx
+			 * URB just after we return. No problem, at this
+			 * point the URB will be idle ;-) - Jean II */
+			break;
+		default:
+			WARNING(__FUNCTION__ "(), RX status %d\n", purb->status);
+			break;
+		}
+		goto done;
+	}
+
+	/* Check for empty frames */
+	if (purb->actual_length <= USB_IRDA_HEADER) {
+		WARNING(__FUNCTION__ "(), empty frame!\n");
+		goto done;
+	}
+
+	/*  
+	 * Remember the time we received this frame, so we can
+	 * reduce the min turn time a bit since we will know
+	 * how much time we have used for protocol processing
+	 */
+        get_fast_time(&self->stamp);
+
+	/* Fix skb, and remove USB-IrDA header */
+	skb_put(skb, purb->actual_length);
+	skb_pull(skb, USB_IRDA_HEADER);
+
+	/* Don't waste a lot of memory on small IrDA frames */
+	if (skb->len < RX_COPY_THRESHOLD) {
+		new = dev_alloc_skb(skb->len+1);
+		if (!new) {
+			self->stats.rx_dropped++;
+			goto done;  
+		}
+
+		/* Make sure IP header get aligned (IrDA header is 5 bytes) */
+		skb_reserve(new, 1);
+		
+		/* Copy packet, so we can recycle the original */
+		memcpy(skb_put(new, skb->len), skb->data, skb->len);
+		/* We will cleanup the skb in irda_usb_submit */
+	} else {
+		/* Deliver the original skb */
+		new = skb;
+		skb = NULL;
+	}
+	
+	self->stats.rx_bytes += new->len;
+	self->stats.rx_packets++;
+
+	/* Ask the networking layer to queue the packet for the IrDA stack */
+        new->dev = self->netdev;
+        new->mac.raw  = new->data;
+        new->protocol = htons(ETH_P_IRDA);
+        netif_rx(new);
+done:
+	/* Recycle Rx URB (and possible the skb as well) */
+	irda_usb_submit(self, skb, self->rx_idle_urb);
+
+        /* Recycle Rx URB : Now, the idle URB is the present one */
+	self->rx_idle_urb = purb;
+	purb->context = NULL;
+	/* Prevent the USB layer playing games with our URBs */
+	purb->status = -ENOENT;
+}
+
+static int irda_usb_net_init(struct net_device *dev)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	
+	/* Set up to be a normal IrDA network device driver */
+	irda_device_setup(dev);
+
+	/* Insert overrides below this line! */
+
+	return 0;
+}
+
+/*
+ * Function irda_usb_net_open (dev)
+ *
+ *    Network device is taken up. Usually this is done by "ifconfig irda0 up" 
+ *   
+ * Note : don't mess with self->netopen - Jean II
+ */
+static int irda_usb_net_open(struct net_device *netdev)
+{
+	struct irda_usb_cb *self;
+	int i;
+	
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(netdev != NULL, return -1;);
+	self = (struct irda_usb_cb *) netdev->priv;
+	ASSERT(self != NULL, return -1;);
+
+	/* Can only open the device if it's there */
+	if(!self->present) {
+		WARNING(__FUNCTION__ "(), device not present!\n");
+		return -1;
+	}
+
+	/* Initialise default speed and xbofs value
+	 * (IrLAP will change that soon) */
+	self->speed = -1;
+	self->xbofs = -1;
+	self->new_speed = -1;
+	self->new_xbofs = -1;
+
+	/* To do *before* submitting Rx urbs and starting net Tx queue
+	 * Jean II */
+	self->netopen = 1;
+
+	/* 
+	 * Now that everything should be initialized properly,
+	 * Open new IrLAP layer instance to take care of us...
+	 * Note : will send immediately a speed change...
+	 */
+	self->irlap = irlap_open(netdev, &self->qos);
+	ASSERT(self->irlap != NULL, return -1;);
+
+	/* Allow IrLAP to send data to us */
+	netif_start_queue(netdev);
+
+	/* Now that we can pass data to IrLAP, allow the USB layer
+	 * to send us some data... */
+	for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++)
+		irda_usb_submit(self, NULL, &(self->rx_urb[i]));
+	/* Note : we submit all the Rx URB except for one - Jean II */
+	self->rx_idle_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]);
+	self->rx_idle_urb->context = NULL;
+
+	/* Ready to play !!! */
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * Function irda_usb_net_close (self)
+ *
+ *    Network device is taken down. Usually this is done by 
+ *    "ifconfig irda0 down" 
+ */
+static int irda_usb_net_close(struct net_device *netdev)
+{
+	struct irda_usb_cb *self;
+	int i;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(netdev != NULL, return -1;);
+	self = (struct irda_usb_cb *) netdev->priv;
+	ASSERT(self != NULL, return -1;);
+
+	/* Clear this flag *before* unlinking the urbs and *before*
+	 * stopping the network Tx queue - Jean II */
+	self->netopen = 0;
+
+	/* Stop network Tx queue */
+	netif_stop_queue(netdev);
+
+	/* Deallocate all the Rx path buffers (URBs and skb) */
+	for (i = 0; i < IU_MAX_RX_URBS; i++) {
+		purb_t purb = &(self->rx_urb[i]);
+		struct sk_buff *skb = (struct sk_buff *) purb->context;
+		/* Cancel the receive command */
+		usb_unlink_urb(purb);
+		/* The skb is ours, free it */
+		if (skb) {
+			dev_kfree_skb(skb);
+			purb->context = NULL;
+		}
+	}
+	/* Cancel Tx and speed URB */
+	usb_unlink_urb(&self->tx_urb);
+	usb_unlink_urb(&self->speed_urb);
+	
+	/* Stop and remove instance of IrLAP */
+	if (self->irlap)
+		irlap_close(self->irlap);
+	self->irlap = NULL;
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static void irda_usb_net_timeout(struct net_device *netdev)
+{
+	struct irda_usb_cb *self = netdev->priv;
+	int done = 0;	/* If we have made any progress */
+	purb_t purb;
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
+
+	if (!self || !self->present) {
+		WARNING(__FUNCTION__ "(), device not present!\n");
+		netif_stop_queue(netdev);
+		return;
+	}
+	WARNING("%s: Tx timed out\n", netdev->name);
+
+	/* Check Tx URB */
+	purb = &self->tx_urb;
+	switch (purb->status) {
+		case -ECONNABORTED:	/* Can't find proper USB_ST_* code */
+			purb->status = USB_ST_NOERROR;
+			netif_wake_queue(self->netdev);
+			done = 1;
+			break;
+		case USB_ST_URB_PENDING:	/* -EINPROGRESS == -115 */
+			usb_unlink_urb(purb);
+			done = 1;
+			break;
+		default:
+			break;
+	}
+	/* Check speed URB */
+	purb = &self->speed_urb;
+	switch (purb->status) {
+		case -ECONNABORTED:	/* Can't find proper USB_ST_* code */
+			purb->status = USB_ST_NOERROR;
+			netif_wake_queue(self->netdev);
+			done = 1;
+			break;
+		case USB_ST_URB_PENDING:	/* -EINPROGRESS */
+			usb_unlink_urb(purb);
+			done = 1;
+			break;
+		default:
+			break;
+	}
+	/* Maybe we need a reset */
+	/* if(done == 0) */
+}
+
+static int irda_usb_is_receiving(struct irda_usb_cb *self)
+{
+	return 0; /* For now */
+}
+
+static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct irda_usb_cb *self;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+	self = dev->priv;
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+
+	/* Check if the device is still there */
+	if (!self->present)
+		return -EFAULT;
+
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		/* Set the desired speed */
+		self->new_speed = irq->ifr_baudrate;
+		irda_usb_change_speed_xbofs(self);
+		/* Note : will spinlock in above function */
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = irda_usb_is_receiving(self);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	return ret;
+}
+
+static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev)
+{
+	struct irda_usb_cb *self = dev->priv;
+	return &self->stats;
+}
+
+int __init usb_irda_init(void)
+{
+	if (usb_register(&irda_driver) < 0)
+		return -1;
+
+	MESSAGE("USB IrDA support registered\n");
+	return 0;
+}
+module_init(usb_irda_init);
+
+void __exit usb_irda_cleanup(void)
+{
+	struct irda_usb_cb *irda = NULL;
+	int i;
+
+	/* Find zombie instances and kill them... */
+	for (i = 0; i < NIRUSB; i++) {
+		irda = &irda_instance[i];
+		/* If the Device is zombie */
+		if((irda->usbdev != NULL) && (irda->present == 0)) {
+			IRDA_DEBUG(0, __FUNCTION__ "(), disconnect zombie now !\n");
+			irda_usb_disconnect(irda->usbdev, (void *) irda);
+		}
+	}
+	/* Deregister the driver and remove all pending instances */
+	usb_deregister(&irda_driver);
+}
+module_exit(usb_irda_cleanup);
+
+MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
+MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net> and Jean Tourrilhes <jt@hpl.hp.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); 
+
+
+
diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- v2.4.4/linux/drivers/net/irda/nsc-ircc.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/irda/nsc-ircc.c	Tue May  1 16:05:00 2001
@@ -251,9 +251,14 @@
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
+	MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
+		info->cfg_base);
+
 	if ((nsc_ircc_setup(info)) == -1)
 		return -1;
 
+	MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
+
 	/* Allocate new instance of the driver */
 	self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL);
 	if (self == NULL) {
@@ -315,8 +320,8 @@
 	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
 					      GFP_KERNEL|GFP_DMA);
 	if (self->tx_buff.head == NULL) {
-		kfree(self);
 		kfree(self->rx_buff.head);
+		kfree(self);
 		return -ENOMEM;
 	}
 	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
@@ -699,8 +704,6 @@
 		ERROR("%s, Wrong chip version %02x\n", driver_name, version);
 		return -1;
 	}
-	MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, 
-		info->cfg_base);
 
 	/* Switch to advanced mode */
 	switch_bank(iobase, BANK2);
@@ -729,8 +732,6 @@
 	outb(0x0d, iobase+2); /* Set SIR pulse width to 1.6us */
 	outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */
 
-	MESSAGE("%s, driver loaded (Dag Brattli)\n", driver_name);
-
 	/* Enable receive interrupts */
 	switch_bank(iobase, BANK0);
 	outb(IER_RXHDL_IE, iobase+IER);
@@ -1858,7 +1859,7 @@
 	if (request_dma(self->io.dma, dev->name)) {
 		WARNING("%s, unable to allocate dma=%d\n", driver_name, 
 			self->io.dma);
-		free_irq(self->io.irq, self);
+		free_irq(self->io.irq, dev);
 		return -EAGAIN;
 	}
 	
@@ -2008,18 +2009,10 @@
 
 static void nsc_ircc_wakeup(struct nsc_ircc_cb *self)
 {
-	int iobase;
-
 	if (!self->io.suspended)
 		return;
 
-	iobase = self->io.fir_base;
-
-	/* Switch to advanced mode */
-	switch_bank(iobase, BANK2);
-	outb(ECR1_EXT_SL, iobase+ECR1);
-	switch_bank(iobase, BANK0);
-
+	nsc_ircc_setup(&self->io);
 	nsc_ircc_net_open(self->netdev);
 	
 	MESSAGE("%s, Waking up\n", driver_name);
diff -u --recursive --new-file v2.4.4/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- v2.4.4/linux/drivers/net/irda/toshoboe.c	Tue Feb 13 13:15:05 2001
+++ linux/drivers/net/irda/toshoboe.c	Tue May  1 16:05:00 2001
@@ -81,10 +81,18 @@
 
 #include <net/irda/toshoboe.h>
 
-static char *driver_name = "toshoboe";
+#define PCI_DEVICE_ID_FIR701b  0x0d01
 
-static struct toshoboe_cb *dev_self[NSELFS + 1] =
-{NULL, NULL, NULL, NULL, NULL};
+static struct pci_device_id toshoboe_pci_tbl[] __initdata = {
+	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_FIR701b, PCI_ANY_ID, PCI_ANY_ID, },
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, toshoboe_pci_tbl);
+
+static const char *driver_name = "toshoboe";
+
+static struct toshoboe_cb *dev_self[NSELFS + 1];
 
 static int max_baud = 4000000;
 
@@ -191,8 +199,8 @@
   outb_p (OBOE_NTR_VAL, OBOE_NTR);
   outb_p (0xf0, OBOE_REG_D);
   outb_p (0xff, OBOE_ISR);
-  outb_p (0x0f, OBOE_REG_1A);
-  outb_p (0xff, OBOE_REG_1B);
+  outb_p (0x0f, OBOE_REG_1B);
+  outb_p (0xff, OBOE_REG_1A);
 
 
   physaddr = virt_to_bus (self->taskfile);
@@ -608,18 +616,21 @@
 	/* Disable interrupts & save flags */
 	save_flags(flags);
 	cli();
-	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			goto out;
+		}
 		/* toshoboe_setbaud(self, irq->ifr_baudrate); */
                 /* Just change speed once - inserted by Paul Bristow */
 	        self->new_speed = irq->ifr_baudrate;
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
+		if (!capable(CAP_NET_ADMIN)) {
+			ret = -EPERM;
+			goto out;
+		}
 		irda_device_set_media_busy(self->netdev, TRUE);
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
@@ -628,9 +639,8 @@
 	default:
 		ret = -EOPNOTSUPP;
 	}
-	
+out:
 	restore_flags(flags);
-	
 	return ret;
 }
 
@@ -712,6 +722,9 @@
       return -ENOMEM;
     }
 
+  if ((err=pci_enable_device(pci_dev)))
+	  return err;
+
   self = kmalloc (sizeof (struct toshoboe_cb), GFP_KERNEL);
 
   if (self == NULL)
@@ -898,7 +911,7 @@
 /*FIXME: can't sleep here wait one second */
 
   while ((i--) && (self->txpending))
-    mdelay (100);
+    udelay (100);
 
   toshoboe_stopchip (self);
   toshoboe_disablebm (self);
@@ -978,6 +991,24 @@
 
     }
   while (pci_dev);
+
+  if (!found) do
+    {
+      pci_dev = pci_find_device (PCI_VENDOR_ID_TOSHIBA,
+                                 PCI_DEVICE_ID_FIR701b, pci_dev);
+      if (pci_dev)
+        {
+          printk (KERN_WARNING "ToshOboe: Found 701b chip at 0x%0lx irq %d\n",
+		  pci_dev->resource[0].start,
+                  pci_dev->irq);
+
+          if (!toshoboe_open (pci_dev))
+	      found++;
+        }
+
+    }
+  while (pci_dev);
+
 
 
   if (found)
diff -u --recursive --new-file v2.4.4/linux/drivers/parport/parport_mfc3.c linux/drivers/parport/parport_mfc3.c
--- v2.4.4/linux/drivers/parport/parport_mfc3.c	Mon Nov 27 17:11:26 2000
+++ linux/drivers/parport/parport_mfc3.c	Tue May  1 16:05:00 2001
@@ -91,7 +91,7 @@
 
 static unsigned char mfc3_read_data(struct parport *p)
 {
-	/* clears interupt bit. Triggers also /STROBE. */
+	/* clears interrupt bit. Triggers also /STROBE. */
 	return pia(p)->pprb;
 }
 
diff -u --recursive --new-file v2.4.4/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.4.4/linux/drivers/pci/pci.c	Thu Apr 19 08:38:48 2001
+++ linux/drivers/pci/pci.c	Tue May  1 16:05:00 2001
@@ -843,7 +843,7 @@
 		 * Ugh. We don't know enough about this bridge. Just assume
 		 * that it's entirely transparent.
 		 */
-		printk("Unknown bridge resource %d: assuming transparent\n", 0);
+		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0);
 		child->resource[0] = child->parent->resource[0];
 	}
 
@@ -859,7 +859,7 @@
 		res->name = child->name;
 	} else {
 		/* See comment above. Same thing */
-		printk("Unknown bridge resource %d: assuming transparent\n", 1);
+		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
 		child->resource[1] = child->parent->resource[1];
 	}
 
@@ -886,7 +886,7 @@
 		res->name = child->name;
 	} else {
 		/* See comments above */
-		printk("Unknown bridge resource %d: assuming transparent\n", 2);
+		printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
 		child->resource[2] = child->parent->resource[2];
 	}
 }
diff -u --recursive --new-file v2.4.4/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- v2.4.4/linux/drivers/pcmcia/i82365.c	Sat Mar  3 10:50:29 2001
+++ linux/drivers/pcmcia/i82365.c	Tue May  1 16:05:00 2001
@@ -257,23 +257,31 @@
 
 /*====================================================================*/
 
+static spinlock_t bus_lock = SPIN_LOCK_UNLOCKED;
+
 static u_char i365_get(u_short sock, u_short reg)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&bus_lock,flags);
     {
 	ioaddr_t port = socket[sock].ioaddr;
 	u_char val;
 	reg = I365_REG(socket[sock].psock, reg);
 	outb(reg, port); val = inb(port+1);
+	spin_unlock_irqrestore(&bus_lock,flags);
 	return val;
     }
 }
 
 static void i365_set(u_short sock, u_short reg, u_char data)
 {
+    unsigned long flags;
+    spin_lock_irqsave(&bus_lock,flags);
     {
 	ioaddr_t port = socket[sock].ioaddr;
 	u_char val = I365_REG(socket[sock].psock, reg);
 	outb(val, port); outb(data, port+1);
+	spin_unlock_irqrestore(&bus_lock,flags);
     }
 }
 
@@ -872,6 +880,13 @@
 		events = pending_events[i];
 		pending_events[i] = 0;
 		spin_unlock_irq(&pending_event_lock);
+		/* 
+		SS_DETECT events need a small delay here. The reason for this is that 
+		the "is there a card" electronics need time to see the card after the
+		"we have a card coming in" electronics have seen it. 
+		*/
+		if (events & SS_DETECT) 
+			mdelay(2);
 		if (socket[i].handler)
 			socket[i].handler(socket[i].info, events);
 	}
@@ -881,6 +896,8 @@
 	routine:	pcic_bh
 };
 
+static unsigned long last_detect_jiffies;
+
 static void pcic_interrupt(int irq, void *dev,
 				    struct pt_regs *regs)
 {
@@ -906,6 +923,20 @@
 		continue;
 	    }
 	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
+	    
+	    
+	    /* Several sockets will send multiple "new card detected"
+	       events in rapid succession. However, the rest of the pcmcia expects 
+	       only one such event. We just ignore these events by having a
+               timeout */
+
+	    if (events) {
+	    	if ((jiffies - last_detect_jiffies)<(HZ/20)) 
+	    		events = 0;
+	    	last_detect_jiffies = jiffies;
+	    	
+	    }
+	
 	    if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
 		events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
 	    else {
@@ -970,6 +1001,7 @@
     status = i365_get(sock, I365_STATUS);
     *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
 	? SS_DETECT : 0;
+	
     if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
 	*value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
     else {
@@ -1247,7 +1279,7 @@
     i = i365_get_pair(sock, base+I365_W_START);
     mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0;
     mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0;
-    mem->sys_start += ((u_long)(i & 0x0fff) << 12);
+    mem->sys_start = ((u_long)(i & 0x0fff) << 12);
     
     i = i365_get_pair(sock, base+I365_W_STOP);
     mem->speed  = (i & I365_MEM_WS0) ? 1 : 0;
diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v2.4.4/linux/drivers/scsi/aha1542.c	Tue Mar  6 19:44:37 2001
+++ linux/drivers/scsi/aha1542.c	Tue May  1 16:05:00 2001
@@ -254,7 +254,7 @@
 /* Only used at boot time, so we do not need to worry about latency as much
    here */
 
-static int aha1542_in(unsigned int base, unchar * cmdp, int len)
+static int __init aha1542_in(unsigned int base, unchar * cmdp, int len)
 {
 	unsigned long flags;
 
@@ -276,7 +276,7 @@
 /* Similar to aha1542_in, except that we wait a very short period of time.
    We use this if we know the board is alive and awake, but we are not sure
    if the board will respond to the command we are about to send or not */
-static int aha1542_in1(unsigned int base, unchar * cmdp, int len)
+static int __init aha1542_in1(unsigned int base, unchar * cmdp, int len)
 {
 	unsigned long flags;
 
@@ -886,7 +886,7 @@
 /* This function should only be called for 1542C boards - we can detect
    the special firmware settings and unlock the board */
 
-static int aha1542_mbenable(int base)
+static int __init aha1542_mbenable(int base)
 {
 	static unchar mbenable_cmd[3];
 	static unchar mbenable_result[2];
diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
--- v2.4.4/linux/drivers/scsi/ibmmca.c	Fri Mar  2 18:38:38 2001
+++ linux/drivers/scsi/ibmmca.c	Tue May  1 16:05:00 2001
@@ -50,7 +50,7 @@
 
 /* driver debugging - #undef all for normal operation */
 /* if defined: count interrupts and ignore this special one: */
-#undef	IM_DEBUG_TIMEOUT	50            
+#undef	IM_DEBUG_TIMEOUT	//50            
 #define TIMEOUT_PUN	0
 #define TIMEOUT_LUN	0
 /* verbose interrupt: */
diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/pci2220i.c linux/drivers/scsi/pci2220i.c
--- v2.4.4/linux/drivers/scsi/pci2220i.c	Fri Apr 27 13:59:19 2001
+++ linux/drivers/scsi/pci2220i.c	Mon Apr 30 17:13:07 2001
@@ -2657,7 +2657,7 @@
 		for ( z = 0;  z < BIGD_MAXDRIVES;  z++ )
 			DiskMirror[z].status = inb_p (padapter->regScratchPad + BIGD_RAID_0_STATUS + z);		
 
-		scsi_set_pci_info(pshost, pcidev);
+		scsi_set_pci_device(pshost, pcidev);
 		pshost->max_id = padapter->numberOfDrives;
 		padapter->failRegister = inb_p (padapter->regScratchPad + BIGD_ALARM_IMAGE);
 		for ( z = 0;  z < padapter->numberOfDrives;  z++ )
diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.4.4/linux/drivers/scsi/scsi.c	Wed Apr 25 16:18:54 2001
+++ linux/drivers/scsi/scsi.c	Mon Apr 30 16:31:18 2001
@@ -104,7 +104,7 @@
 const unsigned char scsi_command_size[8] =
 {
 	6, 10, 10, 12,
-	16, 12, 10, 10
+	12, 12, 10, 10
 };
 static unsigned long serial_number;
 static Scsi_Cmnd *scsi_bh_queue_head;
diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.4.4/linux/drivers/scsi/sd.c	Sat Feb  3 11:45:55 2001
+++ linux/drivers/scsi/sd.c	Sat Apr 28 11:28:08 2001
@@ -993,8 +993,7 @@
 		the_result = SRpnt->sr_result;
 
 		if (the_result) {
-			printk("%s: test WP failed, assume Write Protected\n", nbuff);
-			rscsi_disks[i].write_prot = 1;
+			printk("%s: test WP failed, assume Write Enabled\n", nbuff);
 		} else {
 			rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0);
 			printk("%s: Write Protect is %s\n", nbuff,
@@ -1261,12 +1260,7 @@
 
 	for (i = max_p - 1; i >= 0; i--) {
 		int index = start + i;
-		kdev_t devi = MKDEV_SD_PARTITION(index);
-		struct super_block *sb = get_super(devi);
-		sync_dev(devi);
-		if (sb)
-			invalidate_inodes(sb);
-		invalidate_buffers(devi);
+		invalidate_device(MKDEV_SD_PARTITION(index), 1);
 		sd_gendisks->part[index].start_sect = 0;
 		sd_gendisks->part[index].nr_sects = 0;
 		/*
@@ -1314,12 +1308,7 @@
 
 			for (j = max_p - 1; j >= 0; j--) {
 				int index = start + j;
-				kdev_t devi = MKDEV_SD_PARTITION(index);
-				struct super_block *sb = get_super(devi);
-				sync_dev(devi);
-				if (sb)
-					invalidate_inodes(sb);
-				invalidate_buffers(devi);
+				invalidate_device(MKDEV_SD_PARTITION(index), 1);
 				sd_gendisks->part[index].start_sect = 0;
 				sd_gendisks->part[index].nr_sects = 0;
 				sd_sizes[index] = 0;
diff -u --recursive --new-file v2.4.4/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.4.4/linux/drivers/scsi/sr.c	Mon Feb 19 10:25:17 2001
+++ linux/drivers/scsi/sr.c	Sat Apr 28 11:28:08 2001
@@ -496,13 +496,6 @@
 	return 0;
 }
 
-/*
- * do_sr_request() is the request handler function for the sr driver.
- * Its function in life is to take block device requests, and
- * translate them to SCSI commands.
- */
-
-
 static int sr_detect(Scsi_Device * SDp)
 {
 
@@ -869,16 +862,11 @@
 
 	for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++)
 		if (cpnt->device == SDp) {
-			kdev_t devi = MKDEV(MAJOR_NR, i);
-			struct super_block *sb = get_super(devi);
-
 			/*
 			 * Since the cdrom is read-only, no need to sync the device.
 			 * We should be kind to our buffer cache, however.
 			 */
-			if (sb)
-				invalidate_inodes(sb);
-			invalidate_buffers(devi);
+			invalidate_device(MKDEV(MAJOR_NR, i), 0);
 
 			/*
 			 * Reset things back to a sane state so that one can re-load a new
diff -u --recursive --new-file v2.4.4/linux/drivers/sound/cs4281/cs4281m.c linux/drivers/sound/cs4281/cs4281m.c
--- v2.4.4/linux/drivers/sound/cs4281/cs4281m.c	Wed Apr 18 11:49:11 2001
+++ linux/drivers/sound/cs4281/cs4281m.c	Tue May  1 16:05:00 2001
@@ -194,9 +194,6 @@
         }                                         \
 })
 
-#define list_for_each(pos, head) \
-        for (pos = (head)->next; pos != (head); pos = pos->next)
-
 //LIST_HEAD(cs4281_devs);
 struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs };
 
diff -u --recursive --new-file v2.4.4/linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- v2.4.4/linux/drivers/sound/i810_audio.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/sound/i810_audio.c	Tue May  1 16:05:00 2001
@@ -1520,7 +1520,9 @@
 			val = 16384;
 		if (val > 65536)
 			val = 65536;
-		dmabuf->ossfragsize = val/dmabuf->ossmaxfrags;
+		dmabuf->ossmaxfrags = val/dmabuf->ossfragsize;
+		if(dmabuf->ossmaxfrags<4)
+			dmabuf->ossfragsize = val/4;
 		dmabuf->ready = 0;
 #ifdef DEBUG
 		printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
diff -u --recursive --new-file v2.4.4/linux/drivers/sound/nm256_audio.c linux/drivers/sound/nm256_audio.c
--- v2.4.4/linux/drivers/sound/nm256_audio.c	Sat Nov 11 18:33:14 2000
+++ linux/drivers/sound/nm256_audio.c	Tue May  1 16:05:00 2001
@@ -15,6 +15,8 @@
  * Changes:
  * 11-10-2000	Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
  *		Added some __init
+ * 19-04-2001	Marcus Meissner <mm@caldera.de>
+ *		Ported to 2.4 PCI API.
  */
 
 #define __NO_VERSION__
@@ -49,8 +51,6 @@
 #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
 
-#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-
 /* List of cards.  */
 static struct nm256_info *nmcard_list;
 
@@ -1042,6 +1042,9 @@
     struct pm_dev *pmdev;
     int x;
 
+    if (pci_enable_device(pcidev))
+	    return 0;
+
     card = kmalloc (sizeof (struct nm256_info), GFP_KERNEL);
     if (card == NULL) {
 	printk (KERN_ERR "NM256: out of memory!\n");
@@ -1055,7 +1058,7 @@
 
     /* Init the memory port info.  */
     for (x = 0; x < 2; x++) {
-	card->port[x].physaddr = RSRCADDRESS (pcidev, x);
+	card->port[x].physaddr = pci_resource_start (pcidev, x);
 	card->port[x].ptr = NULL;
 	card->port[x].start_offset = 0;
 	card->port[x].end_offset = 0;
@@ -1201,6 +1204,8 @@
 	}
     }
 
+    pci_set_drvdata(pcidev,card);
+
     /* Insert the card in the list.  */
     card->next_card = nmcard_list;
     nmcard_list = card;
@@ -1251,37 +1256,38 @@
     return 0;
 }
 
-/*
- * 	This loop walks the PCI configuration database and finds where
- *	the sound cards are.
- */
- 
-int __init
-init_nm256(void)
+static int __devinit
+nm256_probe(struct pci_dev *pcidev,const struct pci_device_id *pciid)
 {
-    struct pci_dev *pcidev = NULL;
-    int count = 0;
-
-    if(! pci_present())
-	return -ENODEV;
-
-    while((pcidev = pci_find_device(PCI_VENDOR_ID_NEOMAGIC,
-				    PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO,
-				    pcidev)) != NULL) {
-	count += nm256_install(pcidev, REV_NM256AV, "256AV");
-    }
-
-    while((pcidev = pci_find_device(PCI_VENDOR_ID_NEOMAGIC,
-				    PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO,
-				    pcidev)) != NULL) {
-	count += nm256_install(pcidev, REV_NM256ZX, "256ZX");
+    if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO)
+	return nm256_install(pcidev, REV_NM256AV, "256AV");
+    if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO)
+	return nm256_install(pcidev, REV_NM256ZX, "256ZX");
+    return -1; /* should not come here ... */
+}
+
+static void __devinit
+nm256_remove(struct pci_dev *pcidev) {
+    struct nm256_info *xcard = pci_get_drvdata(pcidev);
+    struct nm256_info *card,*next_card = NULL;
+
+    for (card = nmcard_list; card != NULL; card = next_card) {
+	next_card = card->next_card;
+	if (card == xcard) {
+	    stopPlay (card);
+	    stopRecord (card);
+	    if (card->has_irq)
+		free_irq (card->irq, card);
+	    nm256_release_ports (card);
+	    sound_unload_mixerdev (card->mixer_oss_dev);
+	    sound_unload_audiodev (card->dev[0]);
+	    sound_unload_audiodev (card->dev[1]);
+	    kfree (card);
+	    break;
+	}
     }
-
-    if (count == 0)
-	return -ENODEV;
-
-    printk (KERN_INFO "Done installing NM256 audio driver.\n");
-    return 0;
+    if (nmcard_list == card)
+    	nmcard_list = next_card;
 }
 
 /*
@@ -1639,9 +1645,21 @@
     local_qlen:		nm256_audio_local_qlen,
 };
 
-EXPORT_SYMBOL(init_nm256);
+static struct pci_device_id nm256_pci_tbl[] __devinitdata = {
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO,
+	PCI_ANY_ID, PCI_ANY_ID, 0, 0},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO,
+	PCI_ANY_ID, PCI_ANY_ID, 0, 0},
+	{0,}
+};
+MODULE_DEVICE_TABLE(pci, nm256_pci_tbl);
 
-static int loaded = 0;
+struct pci_driver nm256_pci_driver = {
+	name:"nm256_audio",
+	id_table:nm256_pci_tbl,
+	probe:nm256_probe,
+	remove:nm256_remove,
+};
 
 MODULE_PARM (usecache, "i");
 MODULE_PARM (buffertop, "i");
@@ -1650,37 +1668,13 @@
 
 static int __init do_init_nm256(void)
 {
-    nmcard_list = NULL;
-    printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n");
-
-    if (init_nm256 () == 0) {
-	loaded = 1;
-	return 0;
-    }
-    else
-	return -ENODEV;
+    printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1p\n");
+    return pci_module_init(&nm256_pci_driver);
 }
 
 static void __exit cleanup_nm256 (void)
 {
-    if (loaded) {
-	struct nm256_info *card;
-	struct nm256_info *next_card;
-
-	for (card = nmcard_list; card != NULL; card = next_card) {
-	    stopPlay (card);
-	    stopRecord (card);
-	    if (card->has_irq)
-		free_irq (card->irq, card);
-	    nm256_release_ports (card);
-	    sound_unload_mixerdev (card->mixer_oss_dev);
-	    sound_unload_audiodev (card->dev[0]);
-	    sound_unload_audiodev (card->dev[1]);
-	    next_card = card->next_card;
-	    kfree (card);
-	}
-	nmcard_list = NULL;
-    }
+    pci_unregister_driver(&nm256_pci_driver);
     pm_unregister_all (&handle_pm_event);
 }
 
diff -u --recursive --new-file v2.4.4/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.4.4/linux/drivers/sound/sb_card.c	Sun Feb  4 10:05:29 2001
+++ linux/drivers/sound/sb_card.c	Tue May  1 16:05:00 2001
@@ -339,6 +339,11 @@
 		0,0,0,0,
 		0,1,1,-1},
 	{"Sound Blaster AWE 32",
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0047),
+		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+		0,0,0,0,
+		0,1,1,-1},
+	{"Sound Blaster AWE 32",
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0048), 
 		ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
 		0,0,0,0,
diff -u --recursive --new-file v2.4.4/linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- v2.4.4/linux/drivers/sound/trident.c	Fri Apr  6 10:51:19 2001
+++ linux/drivers/sound/trident.c	Tue May  1 16:05:00 2001
@@ -1967,9 +1967,9 @@
 
 	case SNDCTL_DSP_GETTRIGGER:
 		val = 0;
-		if (file->f_mode & FMODE_READ && dmabuf->enable)
+		if ((file->f_mode & FMODE_READ) && dmabuf->enable)
 			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && dmabuf->enable)
+		if ((file->f_mode & FMODE_WRITE) && dmabuf->enable)
 			val |= PCM_ENABLE_OUTPUT;
 		return put_user(val, (int *)arg);
 
@@ -3309,6 +3309,9 @@
 	struct trident_card *card;
 	u8 revision;
 
+	if (pci_enable_device(pci_dev))
+	    return -ENODEV;
+
 	if (pci_set_dma_mask(pci_dev, TRIDENT_DMA_MASK)) {
 		printk(KERN_ERR "trident: architecture does not support"
 		       " 30bit PCI busmaster DMA\n");
@@ -3322,9 +3325,6 @@
 		       iobase);
 		return -ENODEV;
 	}
-
-	if (pci_enable_device(pci_dev))
-	    return -ENODEV;
 
 	if ((card = kmalloc(sizeof(struct trident_card), GFP_KERNEL)) == NULL) {
 		printk(KERN_ERR "trident: out of memory\n");
diff -u --recursive --new-file v2.4.4/linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- v2.4.4/linux/drivers/sound/via82cxxx_audio.c	Fri Mar  2 11:02:15 2001
+++ linux/drivers/sound/via82cxxx_audio.c	Tue May  1 16:05:00 2001
@@ -3020,6 +3020,11 @@
 	if (printed_version++ == 0)
 		printk (KERN_INFO "Via 686a audio driver " VIA_VERSION "\n");
 
+	if (pci_enable_device (pdev)) {
+		rc = -EIO;
+		goto err_out_none;
+	}
+
 	if (!request_region (pci_resource_start (pdev, 0),
 	    		     pci_resource_len (pdev, 0),
 			     VIA_MODULE_NAME)) {
@@ -3028,10 +3033,6 @@
 		goto err_out;
 	}
 
-	if (pci_enable_device (pdev)) {
-		rc = -EIO;
-		goto err_out_none;
-	}
 
 	card = kmalloc (sizeof (*card), GFP_KERNEL);
 	if (!card) {
diff -u --recursive --new-file v2.4.4/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.4.4/linux/drivers/usb/Config.in	Mon Nov 27 18:10:35 2000
+++ linux/drivers/usb/Config.in	Sat Apr 28 11:28:08 2001
@@ -32,6 +32,7 @@
    if [ "$CONFIG_USB_STORAGE" != "n" ]; then
       bool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
       bool '    Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM
+      bool '    Microtech CompactFlash/SmartMedia reader' CONFIG_USB_STORAGE_DPCM
    fi
    dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
    dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
diff -u --recursive --new-file v2.4.4/linux/drivers/usb/storage/dpcm.c linux/drivers/usb/storage/dpcm.c
--- v2.4.4/linux/drivers/usb/storage/dpcm.c	Mon Aug 28 16:59:14 2000
+++ linux/drivers/usb/storage/dpcm.c	Sat Apr 28 11:28:08 2001
@@ -10,7 +10,7 @@
  *   (c) 2000 Brian Webb (webbb@earthlink.net)
  *
  * This device contains both a CompactFlash card reader, which
- * usest the Control/Bulk w/o Interrupt protocol and
+ * uses the Control/Bulk w/o Interrupt protocol and
  * a SmartMedia card reader that uses the same protocol
  * as the SDDR09.
  *
diff -u --recursive --new-file v2.4.4/linux/drivers/usb/storage/unusual_devs.h linux/drivers/usb/storage/unusual_devs.h
--- v2.4.4/linux/drivers/usb/storage/unusual_devs.h	Fri Apr 27 15:49:28 2001
+++ linux/drivers/usb/storage/unusual_devs.h	Tue May  1 18:24:01 2001
@@ -79,6 +79,12 @@
 		"CameraMate (DPCM_USB)",
  		US_SC_SCSI, US_PR_DPCM_USB, NULL,
 		US_FL_START_STOP ),
+
+UNUSUAL_DEV(  0x04e6, 0x0005, 0x0100, 0x0208,
+		"SCM Microsystems Inc",
+		"eUSB SmartMedia / CompactFlash Adapter",
+		US_SC_SCSI, US_PR_DPCM_USB, NULL,
+		US_FL_START_STOP ),
 #endif
 
 UNUSUAL_DEV(  0x04e6, 0x0006, 0x0100, 0x0200, 
diff -u --recursive --new-file v2.4.4/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.4.4/linux/drivers/usb/uhci.c	Wed Apr 25 14:10:49 2001
+++ linux/drivers/usb/uhci.c	Tue May  1 18:23:01 2001
@@ -644,21 +644,23 @@
 
 	urb->hcpriv = urbp;
 
-	if (urb->transfer_buffer_length) {
-		urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev,
-			urb->transfer_buffer, urb->transfer_buffer_length,
-			usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE :
-			PCI_DMA_TODEVICE);
-		if (!urbp->transfer_buffer_dma_handle)
-			return NULL;
-	}
+	if (urb->dev != uhci->rh.dev) {
+		if (urb->transfer_buffer_length) {
+			urbp->transfer_buffer_dma_handle = pci_map_single(uhci->dev,
+				urb->transfer_buffer, urb->transfer_buffer_length,
+				usb_pipein(urb->pipe) ? PCI_DMA_FROMDEVICE :
+				PCI_DMA_TODEVICE);
+			if (!urbp->transfer_buffer_dma_handle)
+				return NULL;
+		}
 
-	if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
-		urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
-			urb->setup_packet, sizeof(devrequest),
-			PCI_DMA_TODEVICE);
-		if (!urbp->setup_packet_dma_handle)
-			return NULL;
+		if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet) {
+			urbp->setup_packet_dma_handle = pci_map_single(uhci->dev,
+				urb->setup_packet, sizeof(devrequest),
+				PCI_DMA_TODEVICE);
+			if (!urbp->setup_packet_dma_handle)
+				return NULL;
+		}
 	}
 
 	return urbp;
@@ -722,11 +724,11 @@
 		uhci_free_td(uhci, td);
 	}
 
-	if (urb->setup_packet)
+	if (urbp->setup_packet_dma_handle)
 		pci_unmap_single(uhci->dev, urbp->setup_packet_dma_handle,
 			sizeof(devrequest), PCI_DMA_TODEVICE);
 
-	if (urb->transfer_buffer_length)
+	if (urbp->transfer_buffer_dma_handle)
 		pci_unmap_single(uhci->dev, urbp->transfer_buffer_dma_handle,
 			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
 			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
@@ -2247,12 +2249,12 @@
 	if (!killed)
 		urb->status = status;
 
-	if (urb->transfer_buffer_length)
+	if (urbp->transfer_buffer_dma_handle)
 		pci_dma_sync_single(uhci->dev, urbp->transfer_buffer_dma_handle,
 			urb->transfer_buffer_length, usb_pipein(urb->pipe) ?
 			PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
 
-	if (usb_pipetype(urb->pipe) == PIPE_CONTROL && urb->setup_packet)
+	if (urbp->setup_packet_dma_handle)
 		pci_dma_sync_single(uhci->dev, urbp->setup_packet_dma_handle,
 			sizeof(devrequest), PCI_DMA_TODEVICE);
 
diff -u --recursive --new-file v2.4.4/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.4.4/linux/drivers/usb/usb.c	Wed Apr 25 14:10:47 2001
+++ linux/drivers/usb/usb.c	Sat Apr 28 11:28:09 2001
@@ -569,7 +569,7 @@
  * The most specific match specifiers use device descriptor
  * data.  These are commonly used with product-specific matches;
  * the USB_DEVICE macro lets you provide vendor and product IDs,
- * and you can also matche against ranges of product revisions.
+ * and you can also match against ranges of product revisions.
  * These are widely used for devices with application or vendor
  * specific bDeviceClass values.
  *
diff -u --recursive --new-file v2.4.4/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.4.4/linux/fs/block_dev.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/block_dev.c	Mon Apr 30 19:54:03 2001
@@ -554,7 +554,6 @@
 {
 	int i;
 	const struct block_device_operations * bdops = NULL;
-	struct super_block * sb;
 
 	i = MAJOR(dev);
 	if (i < MAX_BLKDEV)
@@ -576,11 +575,8 @@
 	printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
 		bdevname(dev));
 
-	sb = get_super(dev);
-	if (sb && invalidate_inodes(sb))
+	if (invalidate_device(dev, 0))
 		printk("VFS: busy inodes on changed media.\n");
-
-	destroy_buffers(dev);
 
 	if (bdops->revalidate)
 		bdops->revalidate(dev);
diff -u --recursive --new-file v2.4.4/linux/fs/devfs/base.c linux/fs/devfs/base.c
--- v2.4.4/linux/fs/devfs/base.c	Tue Apr 17 15:04:10 2001
+++ linux/fs/devfs/base.c	Sat Apr 28 11:27:54 2001
@@ -2156,7 +2156,6 @@
     int tmp;
     kdev_t dev = MKDEV (de->u.fcb.u.device.major, de->u.fcb.u.device.minor);
     struct block_device_operations *bdops = de->u.fcb.ops;
-    struct super_block * sb;
     extern int warn_no_part;
 
     if ( !S_ISBLK (de->mode) ) return 0;
@@ -2165,10 +2164,8 @@
     if ( !bdops->check_media_change (dev) ) return 0;
     printk ( KERN_DEBUG "VFS: Disk change detected on device %s\n",
 	     kdevname (dev) );
-    sb = get_super (dev);
-    if ( sb && invalidate_inodes (sb) )
+    if (invalidate_device(dev, 0))
 	printk("VFS: busy inodes on changed media..\n");
-    invalidate_buffers (dev);
     /*  Ugly hack to disable messages about unable to read partition table  */
     tmp = warn_no_part;
     warn_no_part = 0;
diff -u --recursive --new-file v2.4.4/linux/fs/inode.c linux/fs/inode.c
--- v2.4.4/linux/fs/inode.c	Fri Apr 27 14:11:30 2001
+++ linux/fs/inode.c	Mon Apr 30 19:47:51 2001
@@ -591,6 +591,22 @@
 
 	return busy;
 }
+ 
+int invalidate_device(kdev_t dev, int do_sync)
+{
+	struct super_block *sb = get_super(dev);
+	int res;
+
+	if (do_sync)
+		fsync_dev(dev);
+
+	res = 0;
+	if (sb)
+		res = invalidate_inodes(sb);
+	invalidate_buffers(dev);
+	return res;
+}
+
 
 /*
  * This is called with the inode lock held. It searches
@@ -612,12 +628,13 @@
 {
 	LIST_HEAD(list);
 	struct list_head *entry, *freeable = &list;
-	int count = 0, synced = 0;
+	int count, synced = 0;
 	struct inode * inode;
 
 	spin_lock(&inode_lock);
 
 free_unused:
+	count = 0;
 	entry = inode_unused.prev;
 	while (entry != &inode_unused)
 	{
diff -u --recursive --new-file v2.4.4/linux/fs/isofs/util.c linux/fs/isofs/util.c
--- v2.4.4/linux/fs/isofs/util.c	Wed Nov 29 10:11:38 2000
+++ linux/fs/isofs/util.c	Tue May  1 18:21:01 2001
@@ -1,90 +1,10 @@
 /*
  *  linux/fs/isofs/util.c
- *
- *  The special functions in the file are numbered according to the section
- *  of the iso 9660 standard in which they are described.  isonum_733 will
- *  convert numbers according to section 7.3.3, etc.
- *
- *  isofs special functions.  This file was lifted in its entirety from
- *  the 386BSD iso9660 filesystem, by Pace Willisson <pace@blitz.com>.
  */
 
 #include <linux/time.h>
-
-int
-isonum_711 (char * p)
-{
-	return (*p & 0xff);
-}
-
-int
-isonum_712 (char * p)
-{
-	int val;
-	
-	val = *p;
-	if (val & 0x80)
-		val |= 0xffffff00;
-	return (val);
-}
-
-int
-isonum_721 (char * p)
-{
-	return ((p[0] & 0xff) | ((p[1] & 0xff) << 8));
-}
-
-int
-isonum_722 (char * p)
-{
-	return (((p[0] & 0xff) << 8) | (p[1] & 0xff));
-}
-
-int
-isonum_723 (char * p)
-{
-#if 0
-	if (p[0] != p[3] || p[1] != p[2]) {
-		fprintf (stderr, "invalid format 7.2.3 number\n");
-		exit (1);
-	}
-#endif
-	return (isonum_721 (p));
-}
-
-int
-isonum_731 (char * p)
-{
-	return ((p[0] & 0xff)
-		| ((p[1] & 0xff) << 8)
-		| ((p[2] & 0xff) << 16)
-		| ((p[3] & 0xff) << 24));
-}
-
-int
-isonum_732 (char * p)
-{
-	return (((p[0] & 0xff) << 24)
-		| ((p[1] & 0xff) << 16)
-		| ((p[2] & 0xff) << 8)
-		| (p[3] & 0xff));
-}
-
-int
-isonum_733 (char * p)
-{
-#if 0
-	int i;
-
-	for (i = 0; i < 4; i++) {
-		if (p[i] != p[7-i]) {
-			fprintf (stderr, "bad format 7.3.3 number\n");
-			exit (1);
-		}
-	}
-#endif
-	return (isonum_731 (p));
-}
+#include <linux/fs.h>
+#include <linux/iso_fs.h>
 
 /* 
  * We have to convert from a MM/DD/YY format to the Unix ctime format.
diff -u --recursive --new-file v2.4.4/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.4.4/linux/fs/nfsd/nfsfh.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/nfsd/nfsfh.c	Mon Apr 30 17:12:51 2001
@@ -156,6 +156,7 @@
 		result = list_entry(lp,struct dentry, d_alias);
 		if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
 			dget_locked(result);
+			result->d_vfs_flags |= DCACHE_REFERENCED;
 			spin_unlock(&dcache_lock);
 			iput(inode);
 			return result;
diff -u --recursive --new-file v2.4.4/linux/fs/super.c linux/fs/super.c
--- v2.4.4/linux/fs/super.c	Fri Apr 27 14:11:31 2001
+++ linux/fs/super.c	Sat Apr 28 11:30:08 2001
@@ -1288,12 +1288,18 @@
 }
 
 /*
- * Flags is a 32-bit value that allows up to 32 non-fs dependent flags to
+ * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to
  * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
  *
  * data is a (void *) that can point to any structure up to
  * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
  * information (or be NULL).
+ *
+ * Pre-0.97 versions of mount() didn't have a flags word.
+ * When the flags word was introduced its top half was required
+ * to have the magic value 0xC0ED, and this remained so until 2.4.0-test9.
+ * Therefore, if this magic number is present, it carries no information
+ * and must be discarded.
  */
 long do_mount(char * dev_name, char * dir_name, char *type_page,
 		  unsigned long flags, void *data_page)
@@ -1303,6 +1309,10 @@
 	struct vfsmount *mnt = NULL;
 	struct super_block *sb;
 	int retval = 0;
+
+	/* Discard magic */
+	if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+		flags &= ~MS_MGC_MSK;
 
 	/* Basic sanity checks */
 
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/axisflashmap.h linux/include/asm-cris/axisflashmap.h
--- v2.4.4/linux/include/asm-cris/axisflashmap.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/axisflashmap.h	Tue May  1 16:05:00 2001
@@ -15,7 +15,7 @@
  * tools/mkptable is used to generate the ptable. 
  */
 
-/* The partition table start with kod to "jump over" it: */
+/* The partition table starts with code to "jump over" it: */
 #define PARTITIONTABLE_CODE_START { \
  0x0f, 0x05, /* nop 0 */\
  0x25, 0xf0, /* di  2 */\
@@ -24,7 +24,7 @@
 /* The actual offset depend on the number of entries */
 #define PARTITIONTABLE_CODE_END { \
  0x00, 0x00, /* ba offset 6 */\
- 0x0f, 0x0f  /* nop 8 */}
+ 0x0f, 0x05  /* nop 8 */}
 
 #define PARTITION_TABLE_OFFSET 10
 #define PARTITION_TABLE_MAGIC 0xbeef /* Not a good magic */
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/elf.h linux/include/asm-cris/elf.h
--- v2.4.4/linux/include/asm-cris/elf.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/elf.h	Tue May  1 16:05:00 2001
@@ -36,7 +36,14 @@
 	   that have been loaded before the code runs.
 
 	   A value of 0 tells we have no such handler.  */
-#define ELF_PLAT_INIT(_r)	((_r)->r10 = 0)
+	
+	/* Explicitly set registers to 0 to increase determinism.  */
+#define ELF_PLAT_INIT(_r)	do { \
+	(_r)->r13 = 0; (_r)->r12 = 0; (_r)->r11 = 0; (_r)->r10 = 0; \
+	(_r)->r9 = 0;  (_r)->r8 = 0;  (_r)->r7 = 0;  (_r)->r6 = 0;  \
+	(_r)->r5 = 0;  (_r)->r4 = 0;  (_r)->r3 = 0;  (_r)->r2 = 0;  \
+	(_r)->r1 = 0;  (_r)->r0 = 0;  (_r)->mof = 0; (_r)->srp = 0; \
+} while (0)
 
 #undef USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE	8192
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/etraxgpio.h linux/include/asm-cris/etraxgpio.h
--- v2.4.4/linux/include/asm-cris/etraxgpio.h	Fri Apr  6 10:51:19 2001
+++ linux/include/asm-cris/etraxgpio.h	Tue May  1 16:05:00 2001
@@ -28,5 +28,7 @@
 #define IO_SETOUTPUT  0xA  /* Set direction 0=unchanged 1=output,
                               returns current dir */
 
+/* LED ioctl extended */
+#define IO_LED_SETBIT 0xB
+#define IO_LED_CLRBIT 0xC
 #endif
-
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/io.h linux/include/asm-cris/io.h
--- v2.4.4/linux/include/asm-cris/io.h	Fri Apr  6 10:51:19 2001
+++ linux/include/asm-cris/io.h	Tue May  1 16:05:00 2001
@@ -9,9 +9,9 @@
    use will be evident. */
 #ifdef CONFIG_SVINTO_SIM
   /* Let's use the ucsim interface since it lets us do write(2, ...) */
-#define SIMCOUT(s,len) asm ("moveq 4,r9\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\
+#define SIMCOUT(s,len) asm ("moveq 4,r1\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\
 \n\tpush irp\n\t.word 0xae3f\n\t.dword 0f\n\tjump -6809\n0:\n\tpop irp" \
-       : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory")
+       : : "rm" (s), "rm" (len) : "r1","r10","r11","r12","memory")
 #define TRACE_ON() __extension__ \
  ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \
 			       (255)); _Foofoo; })
@@ -36,7 +36,14 @@
 extern unsigned char port_pb_dir_shadow;
 extern unsigned char port_pb_data_shadow;
 extern unsigned long r_timer_ctrl_shadow;
-extern unsigned long port_90000000_shadow;
+
+extern unsigned long port_cse1_shadow;
+extern unsigned long port_csp0_shadow;
+extern unsigned long port_csp4_shadow;
+
+extern volatile unsigned long *port_cse1_addr;
+extern volatile unsigned long *port_csp0_addr;
+extern volatile unsigned long *port_csp4_addr;
 
 /* macro for setting regs through a shadow - 
  * r = register name (like R_PORT_PA_DATA)
@@ -45,74 +52,104 @@
  * v = value (0 or 1)
  */
 
-#define REG_SHADOW_SET(r,s,b,v) *r = s = (s & ~(1 << b)) | ((v) << b) 
+#define REG_SHADOW_SET(r,s,b,v) *r = s = (s & ~(1 << (b))) | ((v) << (b))
 
 /* The LED's on various Etrax-based products are set differently. */
 
 #if defined(CONFIG_ETRAX_NO_LEDS) || defined(CONFIG_SVINTO_SIM)
 #undef CONFIG_ETRAX_PA_LEDS
 #undef CONFIG_ETRAX_PB_LEDS
-#undef CONFIG_ETRAX_90000000_LEDS
-#define LED_NETWORK_RX_SET(x)
-#define LED_NETWORK_TX_SET(x)
-#define LED_ACTIVE_SET(x)
+#undef CONFIG_ETRAX_CSP0_LEDS
+#define LED_NETWORK_SET_G(x)
+#define LED_NETWORK_SET_R(x)
 #define LED_ACTIVE_SET_G(x)
 #define LED_ACTIVE_SET_R(x)
 #define LED_DISK_WRITE(x)
 #define LED_DISK_READ(x)
 #endif
 
+#if !defined(CONFIG_ETRAX_CSP0_LEDS)
+#define LED_BIT_SET(x)
+#define LED_BIT_CLR(x)
+#endif
+
+#define LED_OFF    0x00
+#define LED_GREEN  0x01
+#define LED_RED    0x02
+#define LED_ORANGE (LED_GREEN | LED_RED)
+
+#if CONFIG_ETRAX_LED1G == CONFIG_ETRAX_LED1R 
+#define LED_NETWORK_SET(x)                          \
+	do {                                        \
+		LED_NETWORK_SET_G((x) & LED_GREEN); \
+	} while (0)
+#else
+#define LED_NETWORK_SET(x)                          \
+	do {                                        \
+		LED_NETWORK_SET_G((x) & LED_GREEN); \
+		LED_NETWORK_SET_R((x) & LED_RED);   \
+	} while (0)
+#endif
+#if CONFIG_ETRAX_LED2G == CONFIG_ETRAX_LED2R 
+#define LED_ACTIVE_SET(x)                           \
+	do {                                        \
+		LED_ACTIVE_SET_G((x) & LED_GREEN);  \
+	} while (0)
+#else
+#define LED_ACTIVE_SET(x)                           \
+	do {                                        \
+		LED_ACTIVE_SET_G((x) & LED_GREEN);  \
+		LED_ACTIVE_SET_R((x) & LED_RED);    \
+	} while (0)
+#endif
+
 #ifdef CONFIG_ETRAX_PA_LEDS
-#define LED_NETWORK_RX_SET(x) \
-         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1G, !x)
-#define LED_NETWORK_TX_SET(x) \
-         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1R, !x)
-#define LED_ACTIVE_SET(x) \
-         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2G, !x)
+#define LED_NETWORK_SET_G(x) \
+         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1G, !(x))
+#define LED_NETWORK_SET_R(x) \
+         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1R, !(x))
 #define LED_ACTIVE_SET_G(x) \
-         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2G, !x)
+         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2G, !(x))
 #define LED_ACTIVE_SET_R(x) \
-         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !x)
+         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !x)
+         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x))
 #define LED_DISK_READ(x) \
-         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !x) 
+         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x)) 
 #endif
 
 #ifdef CONFIG_ETRAX_PB_LEDS
-#define LED_NETWORK_RX_SET(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1G, !x)
-#define LED_NETWORK_TX_SET(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1R, !x)
-#define LED_ACTIVE_SET(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2G, !x)
+#define LED_NETWORK_SET_G(x) \
+         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1G, !(x))
+#define LED_NETWORK_SET_R(x) \
+         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1R, !(x))
 #define LED_ACTIVE_SET_G(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2G, !x)
+         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2G, !(x))
 #define LED_ACTIVE_SET_R(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !x)
+         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !x)
+         REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x))
 #define LED_DISK_READ(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !x)     
+         REG_SHADOW_SET(R_PORT_PB_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x))     
 #endif
 
-#ifdef CONFIG_ETRAX_90000000_LEDS
-/* TODO: this won't work, need a vremap into kernel virtual memory of 90000000 */
-#define LED_PORT_90 (volatile unsigned long*)0x90000000
-#define LED_ACTIVE_SET(x) \
-         REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED2G, !x)
-#define LED_NETWORK_RX_SET(x) \
-         REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED1G, !x)
-#define LED_NETWORK_TX_SET(x) \
-         REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED1R, !x)
+#ifdef CONFIG_ETRAX_CSP0_LEDS
+#define LED_NETWORK_SET_G(x) \
+         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1G, !(x))
+#define LED_NETWORK_SET_R(x) \
+         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1R, !(x))
 #define LED_ACTIVE_SET_G(x) \
-         REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED2G, !x)
+         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2G, !(x))
 #define LED_ACTIVE_SET_R(x) \
-         REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED2R, !x)
+         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED3R, !x)
+         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x))
 #define LED_DISK_READ(x) \
-         REG_SHADOW_SET(LED_PORT_90, port_90000000_shadow, CONFIG_ETRAX_LED3G, !x)           
+         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x))
+#define LED_BIT_SET(x) \
+         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 1)
+#define LED_BIT_CLR(x) \
+          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 0)        
 #endif
 
 /*
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/irq.h linux/include/asm-cris/irq.h
--- v2.4.4/linux/include/asm-cris/irq.h	Fri Apr  6 10:51:19 2001
+++ linux/include/asm-cris/irq.h	Tue May  1 16:05:00 2001
@@ -45,7 +45,7 @@
 /* SAVE_ALL saves registers so they match pt_regs */
 
 #define SAVE_ALL \
-  "push irp\n\t"       /* push instruction pointer */ \
+  "move irp,[sp=sp-16]\n\t" /* push instruction pointer and fake SBFS struct */ \
   "push srp\n\t"       /* push subroutine return pointer */ \
   "push dccr\n\t"      /* push condition codes */ \
   "push mof\n\t"       /* push multiply overflow reg */ \
@@ -94,7 +94,9 @@
           "_bad_IRQ" #nr "_interrupt:\n\t" \
 	  "push r0\n\t" \
 	  BLOCK_IRQ(mask,nr) \
-	  "pop r0\n\t");
+	  "pop r0\n\t" \
+          "reti\n\t" \
+          "nop\n");
 
 
 #endif  /* _ASM_IRQ_H */
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/pgalloc.h linux/include/asm-cris/pgalloc.h
--- v2.4.4/linux/include/asm-cris/pgalloc.h	Mon Apr 23 15:28:07 2001
+++ linux/include/asm-cris/pgalloc.h	Tue May  1 16:05:00 2001
@@ -1,24 +1,25 @@
 #ifndef _CRIS_PGALLOC_H
 #define _CRIS_PGALLOC_H
 
-#include <linux/config.h>
 #include <asm/page.h>
 #include <linux/threads.h>
 
-/* bunch of protos */
+extern struct pgtable_cache_struct {
+        unsigned long *pgd_cache;
+        unsigned long *pte_cache;
+        unsigned long pgtable_cache_sz;
+} quicklists;
 
-extern pgd_t *get_pgd_slow(void);
-extern void free_pgd_slow(pgd_t *pgd);
-extern __inline__ void free_pmd_slow(pmd_t *pmd) { }
-extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
-extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted);
+#define pgd_quicklist           (quicklists.pgd_cache)
+#define pmd_quicklist           ((unsigned long *)0)
+#define pte_quicklist           (quicklists.pte_cache)
+#define pgtable_cache_size      (quicklists.pgtable_cache_sz)
 
-/* first the non-cached versions */
+#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte)
 
-extern __inline__ void free_pte_slow(pte_t *pte)
-{
-        free_page((unsigned long)pte);
-}
+/*
+ * Allocate and free page tables.
+ */
 
 extern __inline__ pgd_t *get_pgd_slow(void)
 {
@@ -37,27 +38,6 @@
         free_page((unsigned long)pgd);
 }
 
-/*
- * Now for the page table cache versions
- */
-
-#ifndef CONFIG_NO_PGT_CACHE
-
-#ifdef CONFIG_SMP
-#error Pgtable caches have to be per-CPU, so that no locking is needed.
-#endif  /* CONFIG_SMP */
-
-extern struct pgtable_cache_struct {
-        unsigned long *pgd_cache;
-        unsigned long *pte_cache;
-        unsigned long pgtable_cache_sz;
-} quicklists;
-
-#define pgd_quicklist           (quicklists.pgd_cache)
-#define pmd_quicklist           ((unsigned long *)0)
-#define pte_quicklist           (quicklists.pte_cache)
-#define pgtable_cache_size      (quicklists.pgtable_cache_sz)
-
 extern __inline__ pgd_t *get_pgd_fast(void)
 {
         unsigned long *ret;
@@ -78,16 +58,17 @@
         pgtable_cache_size++;
 }
 
-/* We don't use pmd cache, so this is a dummy routine */
-
-extern __inline__ pmd_t *get_pmd_fast(void)
+static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
-        return (pmd_t *)0;
-}
+        pte_t *pte;
 
-extern __inline__ void free_pmd_fast(pmd_t *pmd) { }
+        pte = (pte_t *) __get_free_page(GFP_KERNEL);
+        if (pte)
+                clear_page(pte);
+        return pte;
+}
 
-extern __inline__ pte_t *get_pte_fast(void)
+static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
 {
         unsigned long *ret;
 
@@ -99,99 +80,33 @@
         return (pte_t *)ret;
 }
 
-extern __inline__ void free_pte_fast(pte_t *pte)
+static __inline__ void pte_free_fast(pte_t *pte)
 {
         *(unsigned long *)pte = (unsigned long) pte_quicklist;
         pte_quicklist = (unsigned long *) pte;
         pgtable_cache_size++;
 }
 
-#else   /* CONFIG_NO_PGT_CACHE */
-
-#define pgd_quicklist           ((unsigned long *)0)
-#define pmd_quicklist           ((unsigned long *)0)
-#define pte_quicklist           ((unsigned long *)0)
-
-#define get_pgd_fast()          ((pgd_t *)0)
-#define get_pmd_fast()          ((pmd_t *)0)
-#define get_pte_fast()          ((pte_t *)0)
-
-#define free_pgd_fast(pgd)      free_pgd_slow(pgd)
-#define free_pmd_fast(pmd)      free_pmd_slow(pmd)
-#define free_pte_fast(pte)      free_pte_slow(pte)
-
-#endif  /* CONFIG_NO_PGT_CACHE */
-
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
-
-#define pte_free_kernel(pte)    free_pte_slow(pte)
-#define pte_free(pte)           free_pte_slow(pte)
-
-extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
+static __inline__ void pte_free_slow(pte_t *pte)
 {
-        if (!pmd)
-                BUG();
-        address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-        if (pmd_none(*pmd)) {
-                pte_t * page = (pte_t *) get_pte_fast();
-                if (!page)
-                        return get_pte_kernel_slow(pmd, address);
-		pmd_set_kernel(pmd, page);
-                return page + address;
-        }
-        if (pmd_bad(*pmd)) {
-                __handle_bad_pmd_kernel(pmd);
-                return NULL;
-        }
-        return (pte_t *) pmd_page(*pmd) + address;
+        free_page((unsigned long)pte);
 }
 
-extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
-{
-        address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-
-        if (pmd_none(*pmd))
-                goto getnew;
-        if (pmd_bad(*pmd))
-                goto fix;
-        return (pte_t *)pmd_page(*pmd) + address;
- getnew:
-	{
-		pte_t * page = (pte_t *) get_pte_fast();
-		if (!page)
-			return get_pte_slow(pmd, address);
-		pmd_set(pmd, page);
-		return page + address;
-	}
- fix:
-        __handle_bad_pmd(pmd);
-        return NULL;
-}
+#define pte_free(pte)      pte_free_slow(pte)
+#define pgd_free(pgd)      free_pgd_slow(pgd)
+#define pgd_alloc(mm)      get_pgd_fast()
 
 /*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
+ * We don't have any real pmd's, and this code never triggers because
+ * the pgd will always be present..
  */
 
-#define pmd_free(pmd)      free_pmd_slow(pmd)
-#define pmd_free_kernel    pmd_free
-#define pmd_alloc_kernel   pmd_alloc
-
-extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-        if (!pgd)
-                BUG();
-        return (pmd_t *) pgd;
-}
-
-/* pgd handling */
-
-#define pgd_free(pgd)      free_pgd_slow(pgd)
-#define pgd_alloc(mm)      get_pgd_fast()
+#define pmd_alloc_one_fast(mm, addr)    ({ BUG(); ((pmd_t *)1); })
+#define pmd_alloc_one(mm, addr)         ({ BUG(); ((pmd_t *)2); })
+#define pmd_free_slow(x)                do { } while (0)
+#define pmd_free_fast(x)                do { } while (0)
+#define pmd_free(x)                     do { } while (0)
+#define pgd_populate(mm, pmd, pte)      BUG()
 
 /* other stuff */
 
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/pgtable.h linux/include/asm-cris/pgtable.h
--- v2.4.4/linux/include/asm-cris/pgtable.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/pgtable.h	Tue May  1 16:05:00 2001
@@ -3,6 +3,12 @@
  * HISTORY:
  *
  * $Log: pgtable.h,v $
+ * Revision 1.11  2001/04/04 14:38:36  bjornw
+ * Removed bad_pagetable handling and the _kernel functions
+ *
+ * Revision 1.10  2001/03/23 07:46:42  starvik
+ * Corrected according to review remarks
+ *
  * Revision 1.9  2000/11/22 14:57:53  bjornw
  * * extern inline -> static inline
  * * include asm-generic/pgtable.h
@@ -97,7 +103,9 @@
  * the CRIS page table tree.
  */
 
-/* The cache doesn't need to be flushed when TLB entries change (I think!) */
+/* The cache doesn't need to be flushed when TLB entries change because 
+ * the cache is mapped to physical memory, not virtual memory
+ */
 #define flush_cache_all()			do { } while (0)
 #define flush_cache_mm(mm)			do { } while (0)
 #define flush_cache_range(mm, start, end)	do { } while (0)
@@ -244,27 +252,8 @@
 
 /* zero page used for uninitialized stuff */
 extern unsigned long empty_zero_page;
-
-/*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern pte_t __bad_page(void);
-extern pte_t * __bad_pagetable(void);
-
-#define BAD_PAGETABLE    __bad_pagetable()
-#define BAD_PAGE         __bad_page()
 #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
 
-/*
- * Handling allocation failures during page table setup.
- */
-extern void __handle_bad_pmd(pmd_t * pmd);
-extern void __handle_bad_pmd_kernel(pmd_t * pmd);
-
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR			(8*sizeof(unsigned long))
 
@@ -452,9 +441,6 @@
 
 static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
 { pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; }
-
-static inline void pmd_set_kernel(pmd_t * pmdp, pte_t * ptep)
-{ pmd_val(*pmdp) = _KERNPG_TABLE | (unsigned long) ptep; }
 
 /* to find an entry in a page-table-directory. */
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/processor.h linux/include/asm-cris/processor.h
--- v2.4.4/linux/include/asm-cris/processor.h	Fri Apr  6 10:51:19 2001
+++ linux/include/asm-cris/processor.h	Tue May  1 16:05:00 2001
@@ -18,7 +18,7 @@
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
  */
-#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+#define current_text_addr() ({void *pc; __asm__ ("move.d pc,%0" : "=rm" (pc)); pc; })
 
 /* CRIS has no problems with write protection */
 
@@ -40,6 +40,14 @@
  */
 #define TASK_UNMAPPED_BASE      (TASK_SIZE / 3)
 
+/* THREAD_SIZE is the size of the task_struct/kernel_stack combo.
+ * normally, the stack is found by doing something like p + THREAD_SIZE
+ * in CRIS, a page is 8192 bytes, which seems like a sane size
+ */
+
+#define THREAD_SIZE       PAGE_SIZE
+#define KERNEL_STACK_SIZE PAGE_SIZE
+
 /* CRIS thread_struct. this really has nothing to do with the processor itself, since
  * CRIS does not do any hardware task-switching, but it's here for legacy reasons.
  * The thread_struct here is used when task-switching using _resume defined in entry.S.
@@ -50,13 +58,24 @@
 struct thread_struct {
 	unsigned long ksp;     /* kernel stack pointer */
 	unsigned long usp;     /* user stack pointer */
-	unsigned long esp0;    /* points to start of saved stack frame, set in entry.S */  
 	unsigned long dccr;    /* saved flag register */
 };
 
-/* saved stack-frame upon syscall entry, points to registers */
+/*
+ * At user->kernel entry, the pt_regs struct is stacked on the top of the kernel-stack.
+ * This macro allows us to find those regs for a task.
+ * Notice that subsequent pt_regs stackings, like recursive interrupts occuring while
+ * we're in the kernel, won't affect this - only the first user->kernel transition
+ * registers are reached by this.
+ */
 
-#define current_regs() (current->thread.esp0)
+#define user_regs(task) (((struct pt_regs *)((unsigned long)(task) + THREAD_SIZE)) - 1)
+
+/*
+ * Dito but for the currently running task
+ */
+
+#define current_regs() user_regs(current)
 
 /* INIT_MMAP is the kernels map of memory, between KSEG_C and KSEG_D */
 
@@ -69,11 +88,7 @@
 #endif
 
 #define INIT_THREAD  { \
-   0, 0, 0, 0x20 }  /* ccr = int enable, nothing else */
-
-/* TODO: REMOVE */
-#define alloc_kernel_stack()    __get_free_page(GFP_KERNEL)
-#define free_kernel_stack(page) free_page((page))
+   0, 0, 0x20 }  /* ccr = int enable, nothing else */
 
 extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 
@@ -94,9 +109,10 @@
 #define KSTK_EIP(tsk)   \
     ({                  \
         unsigned long eip = 0;   \
-        if ((tsk)->thread.esp0 > PAGE_SIZE && \
-            VALID_PAGE(virt_to_page((tsk)->thread.esp0))) \
-              eip = ((struct pt_regs *) (tsk)->thread.esp0)->irp; \
+        unsigned long regs = (unsigned long)user_regs(tsk); \
+        if (regs > PAGE_SIZE && \
+            VALID_PAGE(virt_to_page(regs))) \
+              eip = ((struct pt_regs *)regs)->irp; \
         eip; })
 
 #define KSTK_ESP(tsk)   ((tsk) == current ? rdusp() : (tsk)->thread.usp)
@@ -111,11 +127,13 @@
 
 static inline void exit_thread(void)
 {
+        /* Nothing needs to be done.  */
 }
 
 /* Free all resources held by a thread. */
 static inline void release_thread(struct task_struct *dead_task)
 {
+        /* Nothing needs to be done.  */
 }
 
 /*
@@ -123,16 +141,8 @@
  */
 extern inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
-	return (unsigned long)((struct pt_regs *)t->esp0)->irp;
+	return (unsigned long)user_regs(t)->irp;
 }
-
-/* THREAD_SIZE is the size of the task_struct/kernel_stack combo.
- * normally, the stack is found by doing something like p + THREAD_SIZE
- * in CRIS, a page is 8192 bytes, which seems like a sane size
- */
-
-#define THREAD_SIZE     PAGE_SIZE
-#define KERNEL_STACK_SIZE PAGE_SIZE
 
 #define alloc_task_struct()  ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
 #define free_task_struct(p)  free_pages((unsigned long) (p), 1)
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/ptrace.h linux/include/asm-cris/ptrace.h
--- v2.4.4/linux/include/asm-cris/ptrace.h	Fri Apr  6 10:51:19 2001
+++ linux/include/asm-cris/ptrace.h	Tue May  1 16:05:00 2001
@@ -23,14 +23,16 @@
 #define PT_DCCR      17
 #define PT_SRP       18
 #define PT_IRP       19
-#define PT_USP       20    /* special case - USP is not in the pt_regs */
-#define PT_MAX       20
+#define PT_CSRINSTR  20    /* CPU Status record remnants - valid if frametype == busfault */
+#define PT_CSRADDR   21
+#define PT_CSRDATA   22
+#define PT_USP       23    /* special case - USP is not in the pt_regs */
+#define PT_MAX       23
 
 /* Frame types */
 
-#define CRIS_FRAME_NORMAL   0  /* normal frame like pt_regs struct */
-#define CRIS_FRAME_BUSFAULT 1  /* SBFS frame of 4 longwords on top, including irp */
-#define CRIS_FRAME_FIXUP    2  /* SBFS frame which should do a normal return, not RBF */
+#define CRIS_FRAME_NORMAL   0  /* normal frame without SBFS stacking */
+#define CRIS_FRAME_BUSFAULT 1  /* frame stacked using SBFS, need RBF return path */
 
 /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
 #define PTRACE_GETREGS            12
@@ -63,6 +65,9 @@
 	unsigned long dccr;
 	unsigned long srp;
 	unsigned long irp;
+	unsigned long csrinstr;
+	unsigned long csraddr;
+	unsigned long csrdata;
 };
 
 /* switch_stack is the extra stuff pushed onto the stack in _resume (entry.S) when
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/rtc.h linux/include/asm-cris/rtc.h
--- v2.4.4/linux/include/asm-cris/rtc.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/rtc.h	Tue May  1 16:05:00 2001
@@ -1,4 +1,4 @@
-/* $Id: rtc.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */
+/* $Id: rtc.h,v 1.3 2001/03/21 09:56:31 magnusmn Exp $ */
 
 #ifndef RTC_H
 #define RTC_H
@@ -14,8 +14,21 @@
 #define RTC_MONTH 4
 #define RTC_WEEKDAY 5
 #define RTC_YEAR 6
+#define RTC_CONTROL 7
 
-#ifdef CONFIG_DS1302
+/* Bits in CONTROL register */
+#define RTC_CONTROL_WRITEPROTECT 0x80
+#define RTC_TRICKLECHARGER 8
+/* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS */
+#define   RTC_TCR_PATTERN 0xA0 /* 1010xxxx */
+#define   RTC_TCR_1DIOD 0x04 /* xxxx01xx */
+#define   RTC_TCR_2DIOD 0x08 /* xxxx10xx */
+#define   RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */
+#define   RTC_TCR_2KOHM 0x01      /* xxxxxx01 2KOhm */
+#define   RTC_TCR_4KOHM 0x02      /* xxxxxx10 4kOhm */
+#define   RTC_TCR_8KOHM 0x03      /* xxxxxx11 8kOhm */
+
+#ifdef CONFIG_ETRAX_DS1302
 #define CMOS_READ(x) ds1302_readreg(x)
 #define CMOS_WRITE(val,reg) ds1302_writereg(reg,val)
 #define RTC_INIT() ds1302_init()
@@ -55,5 +68,8 @@
 
 #define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time) /* Read RTC time   */
 #define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
+#define RTC_SET_CHARGE  _IOW('p', 0x0b, int) /* Set CHARGE mode    */
 
 #endif
+
+
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/segment.h linux/include/asm-cris/segment.h
--- v2.4.4/linux/include/asm-cris/segment.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/segment.h	Tue May  1 16:05:00 2001
@@ -1,14 +1,6 @@
 #ifndef _ASM_SEGMENT_H
 #define _ASM_SEGMENT_H
 
-/* argh. really legacy. totally misnomed. */
-
-#define __KERNEL_CS	0x10
-#define __KERNEL_DS	0x18
-
-#define __USER_CS	0x23
-#define __USER_DS	0x2B
-
 typedef struct {
   unsigned long seg;
 } mm_segment_t;
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/semaphore-helper.h linux/include/asm-cris/semaphore-helper.h
--- v2.4.4/linux/include/asm-cris/semaphore-helper.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/semaphore-helper.h	Tue May  1 16:05:00 2001
@@ -1,4 +1,4 @@
-/* $Id: semaphore-helper.h,v 1.1 2000/07/13 16:52:42 bjornw Exp $
+/* $Id: semaphore-helper.h,v 1.3 2001/03/26 15:00:33 orjanf Exp $
  *
  * SMP- and interrupt-safe semaphores helper functions. Generic versions, no
  * optimizations whatsoever... 
@@ -10,6 +10,12 @@
 
 #include <asm/atomic.h>
 
+#define read(a) ((a)->counter)
+#define inc(a) (((a)->counter)++)
+#define dec(a) (((a)->counter)--)
+
+#define count_inc(a) ((*(a))++)
+
 /*
  * These two _must_ execute atomically wrt each other.
  */
@@ -17,12 +23,6 @@
 {
 	atomic_inc(&sem->waking);
 }
-
-#define read(a) ((a)->counter)
-#define inc(a) (((a)->counter)++)
-#define dec(a) (((a)->counter)--)
-
-#define count_inc(a) ((*(a))++)
 
 static inline int waking_non_zero(struct semaphore *sem)
 {
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/stat.h linux/include/asm-cris/stat.h
--- v2.4.4/linux/include/asm-cris/stat.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/stat.h	Tue May  1 16:05:00 2001
@@ -1,7 +1,8 @@
 #ifndef _CRIS_STAT_H
 #define _CRIS_STAT_H
 
-/* verbatim copy of i386 version */
+/* Keep this a verbatim copy of i386 version; tweak CRIS-specific bits in
+   the kernel if necessary.  */
 
 struct __old_kernel_stat {
 	unsigned short st_dev;
@@ -47,7 +48,9 @@
 	unsigned short	st_dev;
 	unsigned char	__pad0[10];
 
-	unsigned long	st_ino;
+#define STAT64_HAS_BROKEN_ST_INO	1
+	unsigned long	__st_ino;
+
 	unsigned int	st_mode;
 	unsigned int	st_nlink;
 
@@ -72,8 +75,7 @@
 	unsigned long	st_ctime;
 	unsigned long	__pad7;		/* will be high 32 bits of ctime someday */
 
-	unsigned long	__unused1;
-	unsigned long	__unused2;
+	unsigned long long	st_ino;
 };
 
 #endif
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/system.h linux/include/asm-cris/system.h
--- v2.4.4/linux/include/asm-cris/system.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/system.h	Tue May  1 16:05:00 2001
@@ -1,14 +1,11 @@
-/* $Id: system.h,v 1.3 2000/10/17 14:56:27 bjornw Exp $ */
+/* $Id: system.h,v 1.4 2001/03/20 19:46:00 bjornw Exp $ */
 
 #ifndef __ASM_CRIS_SYSTEM_H
 #define __ASM_CRIS_SYSTEM_H
 
-#include <asm/segment.h>
-
-/* I need a task-specific debug struct (and the define for #ifdef
-   RELOC_DEBUG) to kludge into task_struct. */
 #include <linux/config.h>
-#include <asm/eshlibld.h>
+
+#include <asm/segment.h>
 
 /* the switch_to macro calls resume, an asm function in entry.S which does the actual
  * task switching.
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/timex.h linux/include/asm-cris/timex.h
--- v2.4.4/linux/include/asm-cris/timex.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/timex.h	Tue May  1 16:05:00 2001
@@ -6,7 +6,7 @@
 #ifndef _ASM_CRIS_TIMEX_H
 #define _ASM_CRIS_TIMEX_H
 
-#define CLOCK_TICK_RATE 9600 /* Underlying frequency of the HZ timer */
+#define CLOCK_TICK_RATE 19200 /* Underlying frequency of the HZ timer */
 
 /*
  * We don't have a cycle-counter.. but we do not support SMP anyway where this is
diff -u --recursive --new-file v2.4.4/linux/include/asm-cris/unistd.h linux/include/asm-cris/unistd.h
--- v2.4.4/linux/include/asm-cris/unistd.h	Fri Apr  6 10:51:19 2001
+++ linux/include/asm-cris/unistd.h	Tue May  1 16:05:00 2001
@@ -57,7 +57,7 @@
 #define __NR_geteuid		 49
 #define __NR_getegid		 50
 #define __NR_acct		 51
-#define __NR_phys		 52
+#define __NR_umount2		 52
 #define __NR_lock		 53
 #define __NR_ioctl		 54
 #define __NR_fcntl		 55
diff -u --recursive --new-file v2.4.4/linux/include/asm-i386/mtrr.h linux/include/asm-i386/mtrr.h
--- v2.4.4/linux/include/asm-i386/mtrr.h	Fri Apr 27 15:48:21 2001
+++ linux/include/asm-i386/mtrr.h	Tue May  1 18:22:28 2001
@@ -88,6 +88,7 @@
 		     unsigned int type, char increment);
 extern int mtrr_del (int reg, unsigned long base, unsigned long size);
 extern int mtrr_del_page (int reg, unsigned long base, unsigned long size);
+extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi);
 #  else
 static __inline__ int mtrr_add (unsigned long base, unsigned long size,
 				unsigned int type, char increment)
@@ -109,6 +110,9 @@
 {
     return -ENODEV;
 }
+
+static __inline__ void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) {;}
+
 #  endif
 
 /*  The following functions are for initialisation: don't use them!  */
diff -u --recursive --new-file v2.4.4/linux/include/linux/cciss_ioctl.h linux/include/linux/cciss_ioctl.h
--- v2.4.4/linux/include/linux/cciss_ioctl.h	Mon Dec 11 12:50:40 2000
+++ linux/include/linux/cciss_ioctl.h	Tue May  1 16:05:00 2001
@@ -80,25 +80,28 @@
 
 #define CISS_MAX_LUN	16	
 
+#define LEVEL2LUN   1   // index into Target(x) structure, due to byte swapping
+#define LEVEL3LUN   0
+
 #pragma pack(1)
 
 //Command List Structure
 typedef union _SCSI3Addr_struct {
    struct {
+    BYTE Dev;
     BYTE Bus:6;
     BYTE Mode:2;        // b00
-    BYTE Dev;
   } PeripDev;
    struct {
+    BYTE DevLSB;
     BYTE DevMSB:6;
     BYTE Mode:2;        // b01
-    BYTE DevLSB;
   } LogDev;
    struct {
-    BYTE Targ:6;
-    BYTE Mode:2;        // b10
     BYTE Dev:5;
     BYTE Bus:3;
+    BYTE Targ:6;
+    BYTE Mode:2;        // b10
   } LogUnit;
 } SCSI3Addr_struct;
 
diff -u --recursive --new-file v2.4.4/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.4.4/linux/include/linux/fs.h	Fri Apr 27 15:48:28 2001
+++ linux/include/linux/fs.h	Tue May  1 18:22:29 2001
@@ -121,6 +121,12 @@
 #define MS_RMT_MASK	(MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|\
 			MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME)
 
+/*
+ * Old magic mount flag and mask
+ */
+#define MS_MGC_VAL 0xC0ED0000
+#define MS_MGC_MSK 0xffff0000
+
 /* Inode flags - they have nothing to superblock flags now */
 
 #define S_SYNC		1	/* Writes are synced at once */
@@ -1086,6 +1092,7 @@
 extern void balance_dirty(kdev_t);
 extern int check_disk_change(kdev_t);
 extern int invalidate_inodes(struct super_block *);
+extern int invalidate_device(kdev_t, int);
 extern void invalidate_inode_pages(struct inode *);
 extern void invalidate_inode_buffers(struct inode *);
 #define invalidate_buffers(dev)	__invalidate_buffers((dev), 0)
diff -u --recursive --new-file v2.4.4/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.4.4/linux/include/linux/i2o.h	Mon Dec 11 13:20:00 2000
+++ linux/include/linux/i2o.h	Tue May  1 16:17:18 2001
@@ -69,6 +69,7 @@
 
 	struct i2o_controller *controller;	/* Controlling IOP */
 	struct i2o_device *next;	/* Chain */
+	struct i2o_device *prev;
 	char dev_name[8];		/* linux /dev name if available */
 };
 
@@ -78,6 +79,9 @@
 struct i2o_pci
 {
 	int irq;
+	int queue_buggy:1;	/* Don't send a lot of messages */
+	int short_req:1;	/* Use small block sizes	*/
+	int dpt:1;		/* Don't quiesce		*/
 #ifdef CONFIG_MTRR
 	int mtrr_reg0;
 	int mtrr_reg1;
@@ -120,6 +124,8 @@
 
 	u32 mem_offset;				/* MFA offset */
 	u32 mem_phys;				/* MFA physical */
+	
+	int battery:1;				/* Has a battery backup */
 
 	struct proc_dir_entry* proc_entry;	/* /proc dir */
 
@@ -295,6 +301,7 @@
 
 extern int i2o_post_this(struct i2o_controller *, u32 *, int);
 extern int i2o_post_wait(struct i2o_controller *, u32 *, int, int);
+extern int i2o_post_wait_mem(struct i2o_controller *, u32 *, int, int, void *, void *);
 
 extern int i2o_query_scalar(struct i2o_controller *, int, int, int, void *, int);
 extern int i2o_set_scalar(struct i2o_controller *, int, int, int, void *, int);
diff -u --recursive --new-file v2.4.4/linux/include/linux/ide.h linux/include/linux/ide.h
--- v2.4.4/linux/include/linux/ide.h	Fri Apr 27 15:48:56 2001
+++ linux/include/linux/ide.h	Tue May  1 18:23:37 2001
@@ -648,6 +648,7 @@
 extern	ide_module_t	*ide_modules;
 extern	ide_module_t	*ide_probe;
 #endif
+extern int noautodma;
 
 /*
  * We need blk.h, but we replace its end_request by our own version.
diff -u --recursive --new-file v2.4.4/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- v2.4.4/linux/include/linux/iso_fs.h	Fri Apr 27 15:48:20 2001
+++ linux/include/linux/iso_fs.h	Tue May  1 18:22:59 2001
@@ -165,14 +165,46 @@
 #define ISOFS_SUPER_MAGIC 0x9660
 
 #ifdef __KERNEL__
-extern int isonum_711(char *);
-extern int isonum_712(char *);
-extern int isonum_721(char *);
-extern int isonum_722(char *);
-extern int isonum_723(char *);
-extern int isonum_731(char *);
-extern int isonum_732(char *);
-extern int isonum_733(char *);
+/* Number conversion inlines, named after the section in ISO 9660
+   they correspond to. */
+
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
+
+static inline int isonum_711(char *p)
+{
+	return *(u8 *)p;
+}
+static inline int isonum_712(char *p)
+{
+	return *(s8 *)p;
+}
+static inline int isonum_721(char *p)
+{
+	return le16_to_cpu(get_unaligned((u16 *)p));
+}
+static inline int isonum_722(char *p)
+{
+	return be16_to_cpu(get_unaligned((u16 *)p));
+}
+static inline int isonum_723(char *p)
+{
+	/* Ignore bigendian datum due to broken mastering programs */
+	return le16_to_cpu(get_unaligned((u16 *)p));
+}
+static inline int isonum_731(char *p)
+{
+	return le32_to_cpu(get_unaligned((u32 *)p));
+}
+static inline int isonum_732(char *p)
+{
+	return be32_to_cpu(get_unaligned((u32 *)p));
+}
+static inline int isonum_733(char *p)
+{
+	/* Ignore bigendian datum due to broken mastering programs */
+	return le32_to_cpu(get_unaligned((u32 *)p));
+}
 extern int iso_date(char *, int);
 
 extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
diff -u --recursive --new-file v2.4.4/linux/include/linux/nbd.h linux/include/linux/nbd.h
--- v2.4.4/linux/include/linux/nbd.h	Wed Apr 11 19:02:30 2001
+++ linux/include/linux/nbd.h	Tue May  1 14:20:25 2001
@@ -2,6 +2,9 @@
  * 1999 Copyright (C) Pavel Machek, pavel@ucw.cz. This code is GPL.
  * 1999/11/04 Copyright (C) 1999 VMware, Inc. (Regis "HPReg" Duchesne)
  *            Made nbd_end_request() use the io_request_lock
+ * 2001 Copyright (C) Steven Whitehouse
+ *            New nbd_end_request() for compatibility with new linux block
+ *            layer code.
  */
 
 #ifndef LINUX_NBD_H
diff -u --recursive --new-file v2.4.4/linux/include/linux/serial_reg.h linux/include/linux/serial_reg.h
--- v2.4.4/linux/include/linux/serial_reg.h	Tue Mar  6 19:28:35 2001
+++ linux/include/linux/serial_reg.h	Tue May  1 16:05:00 2001
@@ -260,8 +260,8 @@
 #define UART_RSA_SRR_Rx_FIFO_NEMP (1 << 3) /* Rx FIFO is not empty (1) */
 #define UART_RSA_SRR_Rx_FIFO_NHFL (1 << 4) /* Rx FIFO is not half full (1) */
 #define UART_RSA_SRR_Rx_FIFO_NFUL (1 << 5) /* Rx FIFO is not full (1) */
-#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occured (1) */
-#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occured */
+#define UART_RSA_SRR_Rx_TOUT (1 << 6) /* Character reception timeout occurred (1) */
+#define UART_RSA_SRR_TIMER (1 << 7) /* Timer interrupt occurred */
 
 #define UART_RSA_FRR ((UART_RSA_BASE) + 2) /* OUT: FIFO Reset Register */
 
diff -u --recursive --new-file v2.4.4/linux/include/linux/synclink.h linux/include/linux/synclink.h
--- v2.4.4/linux/include/linux/synclink.h	Tue Mar  6 19:44:37 2001
+++ linux/include/linux/synclink.h	Tue May  1 16:05:00 2001
@@ -1,17 +1,17 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
- * $Id: synclink.h,v 3.2 2000/11/06 22:34:38 paul Exp $
+ * $Id: synclink.h,v 3.5 2001/03/26 17:04:36 ez Exp $
  *
  * Copyright (C) 1998-2000 by Microgate Corporation
  * 
  * Redistribution of this file is permitted under 
- * the terms of the GNU General Public License (GPL)
+ * the terms of the GNU Public License (GPL)
  */
 
 #ifndef _SYNCLINK_H_
 #define _SYNCLINK_H_
-#define SYNCLINK_H_VERSION 3.2
+#define SYNCLINK_H_VERSION 3.5
 
 #define BOOLEAN int
 #define TRUE 1
@@ -84,6 +84,11 @@
 #define HDLC_CRC_NONE			0
 #define HDLC_CRC_16_CCITT		1
 #define HDLC_CRC_32_CCITT		2
+#define HDLC_CRC_MASK			0x00ff
+#define HDLC_CRC_RETURN_EX		0x8000
+
+#define RX_OK				0
+#define RX_CRC_ERROR			1
 
 #define HDLC_TXIDLE_FLAGS		0
 #define HDLC_TXIDLE_ALT_ZEROS_ONES	1
@@ -117,6 +122,7 @@
 
 #define MGSL_MODE_ASYNC		1
 #define MGSL_MODE_HDLC		2
+#define MGSL_MODE_RAW		6
 
 #define MGSL_BUS_TYPE_ISA	1
 #define MGSL_BUS_TYPE_EISA	2
@@ -150,6 +156,8 @@
 
 #define MICROGATE_VENDOR_ID 0x13c0
 #define SYNCLINK_DEVICE_ID 0x0010
+#define MGSCC_DEVICE_ID 0x0020
+#define SYNCLINK_SCA_DEVICE_ID 0x0030
 #define MGSL_MAX_SERIAL_NUMBER 30
 
 /*
diff -u --recursive --new-file v2.4.4/linux/include/linux/timer.h linux/include/linux/timer.h
--- v2.4.4/linux/include/linux/timer.h	Fri Apr 27 15:48:20 2001
+++ linux/include/linux/timer.h	Tue May  1 18:22:28 2001
@@ -5,17 +5,13 @@
 #include <linux/list.h>
 
 /*
- * This is completely separate from the above, and is the
- * "new and improved" way of handling timers more dynamically.
- * Hopefully efficient and general enough for most things.
+ * In Linux 2.4, static timers have been removed from the kernel.
+ * Timers may be dynamically created and destroyed, and should be initialized
+ * by a call to init_timer() upon creation.
  *
- * The "hardcoded" timers above are still useful for well-
- * defined problems, but the timer-list is probably better
- * when you need multiple outstanding timers or similar.
- *
- * The "data" field is in case you want to use the same
- * timeout function for several timeouts. You can use this
- * to distinguish between the different invocations.
+ * The "data" field enables use of a common timeout function for several
+ * timeouts. You can use this field to distinguish between the different
+ * invocations.
  */
 struct timer_list {
 	struct list_head list;
diff -u --recursive --new-file v2.4.4/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.4.4/linux/include/linux/videodev.h	Thu Apr 12 12:20:31 2001
+++ linux/include/linux/videodev.h	Tue May  1 16:05:00 2001
@@ -374,6 +374,7 @@
 #define VID_HARDWARE_OV511	27	
 #define VID_HARDWARE_ZR356700	28	/* Zoran 36700 series */
 #define VID_HARDWARE_W9966	29
+#define VID_HARDWARE_SE401	30	/* SE401 USB webcams */
 
 
 /*
diff -u --recursive --new-file v2.4.4/linux/include/net/irda/irda-usb.h linux/include/net/irda/irda-usb.h
--- v2.4.4/linux/include/net/irda/irda-usb.h	Wed Dec 31 16:00:00 1969
+++ linux/include/net/irda/irda-usb.h	Tue May  1 16:05:00 2001
@@ -0,0 +1,120 @@
+/*****************************************************************************
+ *
+ * Filename:      irda-usb.h
+ * Version:       0.8
+ * Description:   IrDA-USB Driver
+ * Status:        Experimental 
+ * Author:        Dag Brattli <dag@brattli.net>
+ *
+ *      Copyright (C) 2001, Dag Brattli <dag@brattli.net>
+ *	Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
+ *          
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *****************************************************************************/
+
+#include <linux/time.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irlap.h>
+#include <net/irda/irda_device.h>
+
+#define RX_COPY_THRESHOLD 200
+#define IRDA_USB_MAX_MTU 2051
+#define IRDA_USB_SPEED_MTU 64		/* Weird, but work like this */
+
+/*
+ * Maximum number of URB on the Rx and Tx path, a number larger than 1
+ * is required for handling back-to-back (brickwalled) frames 
+ */
+#define IU_MAX_ACTIVE_RX_URBS 1
+#define IU_MAX_RX_URBS	(IU_MAX_ACTIVE_RX_URBS + 1) 
+#define IU_MAX_TX_URBS  1
+
+/* Inbound header */
+#define MEDIA_BUSY    0x80
+
+#define SPEED_2400    0x01
+#define SPEED_9600    0x02
+#define SPEED_19200   0x03
+#define SPEED_38400   0x04
+#define SPEED_57600   0x05
+#define SPEED_115200  0x06
+#define SPEED_576000  0x07
+#define SPEED_1152000 0x08
+#define SPEED_4000000 0x09
+
+/* device_info flags in struct usb_device_id */
+#define IUC_DEFAULT	0x00	/* Basic device compliant with 1.0 spec */
+#define IUC_SPEED_BUG	0x01	/* Device doesn't set speed after the frame */
+#define IUC_SIR_ONLY	0x02	/* Device doesn't behave at FIR speeds */
+#define IUC_SMALL_PKT	0x04	/* Device doesn't behave with big Rx packets */
+#define IUC_NO_WINDOW	0x08	/* Device doesn't behave with big Rx window */
+#define IUC_MAX_WINDOW	0x10	/* Device underestimate the Rx window */
+#define IUC_MAX_XBOFS	0x20	/* Device need more xbofs than advertised */
+
+#define USB_IRDA_HEADER   0x01
+#define USB_CLASS_IRDA    0x02 /* USB_CLASS_APP_SPEC subclass */ 
+#define USB_DT_IRDA       0x21
+
+struct irda_class_desc {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u16 bcdSpecRevision;
+	__u8  bmDataSize;
+	__u8  bmWindowSize;
+	__u8  bmMinTurnaroundTime;
+	__u16 wBaudRate;
+	__u8  bmAdditionalBOFs;
+	__u8  bIrdaRateSniff;
+	__u8  bMaxUnicastList;
+} __attribute__ ((packed));
+
+struct irda_usb_cb {
+	struct irda_class_desc *irda_desc;
+	struct usb_device *usbdev;	/* init: probe_irda */
+	unsigned int ifnum;		/* Interface number of the USB dev. */
+	int netopen;			/* Device is active for network */
+	int present;			/* Device is present on the bus */
+	__u32 capability;		/* Capability of the hardware */
+	__u8  bulk_in_ep, bulk_out_ep;	/* Endpoint assignments */
+	__u16 bulk_out_mtu;
+	
+	wait_queue_head_t wait_q;	/* for timeouts */
+
+	struct urb rx_urb[IU_MAX_RX_URBS];  /* URBs used to receive data frames */
+	struct urb *rx_idle_urb;         /* Pointer to idle URB in Rx path */
+	struct urb tx_urb;		/* URB used to send data frames */
+	struct urb speed_urb;		/* URB used to send speed commands */
+	
+	struct net_device *netdev;	/* Yes! we are some kind of netdev. */
+	struct net_device_stats stats;
+	struct irlap_cb   *irlap;	/* The link layer we are binded to */
+	struct qos_info qos;		 
+	hashbin_t *tx_list;		/* Queued transmit skb's */
+
+        struct timeval stamp;
+	struct timeval now;
+
+	spinlock_t lock;		/* For serializing operations */
+
+	__u16 xbofs;			/* Current xbofs setting */
+	__s16 new_xbofs;		/* xbofs we need to set */
+	__u32 speed;			/* Current speed */
+	__s32 new_speed;		/* speed we need to set */
+	__u32 flags;			/* Interface flags */
+};
+
+
diff -u --recursive --new-file v2.4.4/linux/include/net/irda/irda.h linux/include/net/irda/irda.h
--- v2.4.4/linux/include/net/irda/irda.h	Fri Apr 27 15:48:59 2001
+++ linux/include/net/irda/irda.h	Tue May  1 18:23:37 2001
@@ -71,7 +71,9 @@
         func }
 #else
 #define IRDA_DEBUG(n, args...)
-#define ASSERT(expr, func)
+#define ASSERT(expr, func) \
+if(!(expr)) do { \
+        func } while (0)
 #endif /* CONFIG_IRDA_DEBUG */
 
 #define WARNING(args...) printk(KERN_WARNING args)
diff -u --recursive --new-file v2.4.4/linux/init/main.c linux/init/main.c
--- v2.4.4/linux/init/main.c	Fri Apr 27 14:23:40 2001
+++ linux/init/main.c	Tue May  1 16:05:00 2001
@@ -718,6 +718,7 @@
 	do_initcalls();
 
 #ifdef CONFIG_IRDA
+	irda_proto_init();
 	irda_device_init(); /* Must be done after protocol initialization */
 #endif
 #ifdef CONFIG_PCMCIA
diff -u --recursive --new-file v2.4.4/linux/kernel/fork.c linux/kernel/fork.c
--- v2.4.4/linux/kernel/fork.c	Thu Apr 26 06:11:17 2001
+++ linux/kernel/fork.c	Mon Apr 30 22:23:29 2001
@@ -666,17 +666,15 @@
 	p->pdeath_signal = 0;
 
 	/*
-	 * Give the parent's dynamic priority entirely to the child.  The
-	 * total amount of dynamic priorities in the system doesn't change
-	 * (more scheduling fairness), but the child will run first, which
-	 * is especially useful in avoiding a lot of copy-on-write faults
-	 * if the child for a fork() just wants to do a few simple things
-	 * and then exec(). This is only important in the first timeslice.
-	 * In the long run, the scheduling behavior is unchanged.
+	 * "share" dynamic priority between parent and child, thus the
+	 * total amount of dynamic priorities in the system doesnt change,
+	 * more scheduling fairness. This is only important in the first
+	 * timeslice, on the long run the scheduling behaviour is unchanged.
 	 */
-	p->counter = current->counter;
-	current->counter = 0;
-	current->need_resched = 1;
+	p->counter = (current->counter + 1) >> 1;
+	current->counter >>= 1;
+	if (!current->counter)
+		current->need_resched = 1;
 
 	/*
 	 * Ok, add it to the run-queues and make it
diff -u --recursive --new-file v2.4.4/linux/kernel/kmod.c linux/kernel/kmod.c
--- v2.4.4/linux/kernel/kmod.c	Sat Dec 30 18:16:13 2000
+++ linux/kernel/kmod.c	Tue May  1 16:05:00 2001
@@ -157,19 +157,18 @@
 }
 
 /**
- *	request_module - try to load a kernel module
- *	@module_name: Name of module
+ * request_module - try to load a kernel module
+ * @module_name: Name of module
  *
- * 	Load a module using the user mode module loader. The function returns
- *	zero on success or a negative errno code on failure. Note that a
- * 	successful module load does not mean the module did not then unload
- *	and exit on an error of its own. Callers must check that the service
- *	they requested is now available not blindly invoke it.
+ * Load a module using the user mode module loader. The function returns
+ * zero on success or a negative errno code on failure. Note that a
+ * successful module load does not mean the module did not then unload
+ * and exit on an error of its own. Callers must check that the service
+ * they requested is now available not blindly invoke it.
  *
- *	If module auto-loading support is disabled then this function
- *	becomes a no-operation.
+ * If module auto-loading support is disabled then this function
+ * becomes a no-operation.
  */
- 
 int request_module(const char * module_name)
 {
 	pid_t pid;
diff -u --recursive --new-file v2.4.4/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.4.4/linux/kernel/ksyms.c	Fri Apr 27 14:23:25 2001
+++ linux/kernel/ksyms.c	Sat Apr 28 11:27:54 2001
@@ -174,6 +174,7 @@
 EXPORT_SYMBOL(check_disk_change);
 EXPORT_SYMBOL(__invalidate_buffers);
 EXPORT_SYMBOL(invalidate_inodes);
+EXPORT_SYMBOL(invalidate_device);
 EXPORT_SYMBOL(invalidate_inode_pages);
 EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
diff -u --recursive --new-file v2.4.4/linux/kernel/module.c linux/kernel/module.c
--- v2.4.4/linux/kernel/module.c	Fri Feb 16 16:02:37 2001
+++ linux/kernel/module.c	Tue May  1 16:05:00 2001
@@ -554,8 +554,8 @@
 	put_mod_name(name);
 
 	/* Initialize the module.  */
-	mod->flags |= MOD_INITIALIZING;
 	atomic_set(&mod->uc.usecount,1);
+	mod->flags |= MOD_INITIALIZING;
 	if (mod->init && (error = mod->init()) != 0) {
 		atomic_set(&mod->uc.usecount,0);
 		mod->flags &= ~MOD_INITIALIZING;
@@ -613,11 +613,6 @@
 	if (name_user) {
 		if ((error = get_mod_name(name_user, &name)) < 0)
 			goto out;
-		if (error == 0) {
-			error = -EINVAL;
-			put_mod_name(name);
-			goto out;
-		}
 		error = -ENOENT;
 		if ((mod = find_module(name)) == NULL) {
 			put_mod_name(name);
@@ -847,7 +842,6 @@
 		bufsize -= len;
 		space += len;
 	}
-
 	if (put_user(i, ret))
 		return -EFAULT;
 	else
@@ -876,8 +870,11 @@
 		info.addr = (unsigned long)mod;
 		info.size = mod->size;
 		info.flags = mod->flags;
+		
+		/* usecount is one too high here - report appropriately to
+		   compensate for locking */
 		info.usecount = (mod_member_present(mod, can_unload)
-				 && mod->can_unload ? -1 : atomic_read(&mod->uc.usecount));
+				 && mod->can_unload ? -1 : atomic_read(&mod->uc.usecount)-1);
 
 		if (copy_to_user(buf, &info, sizeof(struct module_info)))
 			return -EFAULT;
@@ -909,15 +906,17 @@
 			goto out;
 		}
 		err = -ENOENT;
-		if (namelen == 0)
-			mod = &kernel_module;
-		else if ((mod = find_module(name)) == NULL) {
+		if ((mod = find_module(name)) == NULL) {
 			put_mod_name(name);
 			goto out;
 		}
 		put_mod_name(name);
 	}
 
+	/* __MOD_ touches the flags. We must avoid that */
+	
+	atomic_inc(&mod->uc.usecount);
+		
 	switch (which)
 	{
 	case 0:
@@ -942,6 +941,8 @@
 		err = -EINVAL;
 		break;
 	}
+	atomic_dec(&mod->uc.usecount);
+	
 out:
 	unlock_kernel();
 	return err;
diff -u --recursive --new-file v2.4.4/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- v2.4.4/linux/net/decnet/af_decnet.c	Thu Apr 12 12:11:39 2001
+++ linux/net/decnet/af_decnet.c	Tue May  1 16:05:00 2001
@@ -1431,7 +1431,7 @@
 	struct	sock *sk = sock->sk;
 	struct dn_scp *scp = DN_SK(sk);
 	struct linkinfo_dn link;
-	int r_len;
+	unsigned int r_len;
 	void *r_data = NULL;
 	unsigned int val;
 
diff -u --recursive --new-file v2.4.4/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.4.4/linux/net/ipv4/tcp.c	Wed Apr 25 14:57:39 2001
+++ linux/net/ipv4/tcp.c	Tue May  1 14:20:25 2001
@@ -1185,7 +1185,7 @@
 	if (skb->len==0) {
 		if (tp->send_head == skb) {
 			tp->send_head = skb->prev;
-			if (tp->send_head == (struct sk_buff*)&sk->write_queue)
+			if (TCP_SKB_CB(skb)->seq == tp->snd_nxt)
 				tp->send_head = NULL;
 		}
 		__skb_unlink(skb, skb->list);
diff -u --recursive --new-file v2.4.4/linux/net/irda/af_irda.c linux/net/irda/af_irda.c
--- v2.4.4/linux/net/irda/af_irda.c	Thu Apr 12 12:11:39 2001
+++ linux/net/irda/af_irda.c	Tue May  1 16:05:00 2001
@@ -218,8 +218,7 @@
 		   self->max_data_size);
 
 	memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
-
-	skb_queue_tail(&sk->receive_queue, skb);
+	kfree_skb(skb);
 
 	/* We are now connected! */
 	sk->state = TCP_ESTABLISHED;
@@ -439,7 +438,7 @@
  * We were waiting for a node to be discovered, but nothing has come up
  * so far. Wake up the user and tell him that we failed...
  */
-static void irda_discovery_timeout(u_long	priv)
+static void irda_discovery_timeout(u_long priv)
 {
 	struct irda_sock *self;
 	
@@ -776,7 +775,6 @@
 	struct sock *sk = sock->sk;
 	struct sockaddr_irda *addr = (struct sockaddr_irda *) uaddr;
 	struct irda_sock *self;
-	__u16 hints = 0;
 	int err;
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
@@ -821,15 +819,6 @@
 				 self->stsap_sel, IAS_KERNEL_ATTR);
 	irias_insert_object(self->ias_obj);
 	
-#if 1 /* Will be removed in near future */
-
-	/* Fill in some default hint bits values */
-	if (strncmp(addr->sir_name, "OBEX", 4) == 0)
-		hints = irlmp_service_to_hint(S_OBEX);
-	
-	if (hints)
-		self->skey = irlmp_register_service(hints);
-#endif
 	return 0;
 }
 
@@ -1633,34 +1622,54 @@
 {
 	struct sock *sk = sock->sk;
 	unsigned int mask;
+	struct irda_sock *self;
 
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
+	self = sk->protinfo.irda;
 	poll_wait(file, sk->sleep, wait);
 	mask = 0;
 
-	/* exceptional events? */
+	/* Exceptional events? */
 	if (sk->err)
 		mask |= POLLERR;
 	if (sk->shutdown & RCV_SHUTDOWN)
 		mask |= POLLHUP;
 
-	/* readable? */
+	/* Readable? */
 	if (!skb_queue_empty(&sk->receive_queue)) {
 		IRDA_DEBUG(4, "Socket is readable\n");
 		mask |= POLLIN | POLLRDNORM;
 	}
+
 	/* Connection-based need to check for termination and startup */
-	if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE)
-		mask |= POLLHUP;
+	switch (sk->type) {
+	case SOCK_STREAM:
+		if (sk->state == TCP_CLOSE)
+			mask |= POLLHUP;
 
-	/*
-	 * we set writable also when the other side has shut down the
-	 * connection. This prevents stuck sockets.
-	 */
-	if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)
+		if (sk->state == TCP_ESTABLISHED) {
+			if ((self->tx_flow == FLOW_START) && 
+			    (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE))
+			{
+				mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+			}
+		}
+		break;
+	case SOCK_SEQPACKET:
+		if ((self->tx_flow == FLOW_START) && 
+		    (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE))
+		{	
 			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
-
+		}
+		break;
+	case SOCK_DGRAM:
+		if (sk->sndbuf - (int)atomic_read(&sk->wmem_alloc) >= SOCK_MIN_WRITE_SPACE)
+			mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+		break;
+	default:
+		break;
+	}		
 	return mask;
 }
 
@@ -2328,6 +2337,9 @@
 SOCKOPS_WRAP(irda_stream, PF_IRDA);
 SOCKOPS_WRAP(irda_seqpacket, PF_IRDA);
 SOCKOPS_WRAP(irda_dgram, PF_IRDA);
+#ifdef CONFIG_IRDA_ULTRA
+SOCKOPS_WRAP(irda_ultra, PF_IRDA);
+#endif /* CONFIG_IRDA_ULTRA */
 
 /*
  * Function irda_device_event (this, event, ptr)
@@ -2416,7 +2428,9 @@
 #endif
 	return 0;
 }
-module_init(irda_proto_init);
+#ifdef MODULE
+module_init(irda_proto_init);	/* If non-module, called from init/main.c */
+#endif
 
 /*
  * Function irda_proto_cleanup (void)
diff -u --recursive --new-file v2.4.4/linux/net/irda/irias_object.c linux/net/irda/irias_object.c
--- v2.4.4/linux/net/irda/irias_object.c	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/irias_object.c	Tue May  1 16:05:00 2001
@@ -34,7 +34,7 @@
 /*
  *  Used when a missing value needs to be returned
  */
-struct ias_value missing = { IAS_MISSING, 0, 0, 0};
+struct ias_value missing = { IAS_MISSING, 0, 0, 0, {0}};
 
 /*
  * Function strdup (str)
diff -u --recursive --new-file v2.4.4/linux/net/irda/irlap.c linux/net/irda/irlap.c
--- v2.4.4/linux/net/irda/irlap.c	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/irlap.c	Tue May  1 16:05:00 2001
@@ -860,13 +860,6 @@
 	/* Free sliding window buffered packets */
 	while ((skb = skb_dequeue(&self->wx_list)) != NULL)
 		dev_kfree_skb(skb);
-
-#ifdef CONFIG_IRDA_RECYCLE_RR
-	if (self->recycle_rr_skb) { 
- 		dev_kfree_skb(self->recycle_rr_skb);
- 		self->recycle_rr_skb = NULL;
- 	}
-#endif
 }
 
 /*
@@ -1076,7 +1069,7 @@
 
 	/* Set the negociated xbofs value */
 	self->next_bofs   = self->qos_tx.additional_bofs.value;
-	if(now)
+	if (now)
 		self->bofs_count = self->next_bofs;
 
 	/* Set the negociated link speed (may need the new xbofs value) */
@@ -1107,13 +1100,13 @@
 		 */
 		self->N1 = -1; /* Disable */
 	else
-		self->N1 = 3000 / self->qos_tx.max_turn_time.value;
+		self->N1 = 3000 / self->qos_rx.max_turn_time.value;
 	
 	IRDA_DEBUG(4, "Setting N1 = %d\n", self->N1);
 	
 	
 	self->N2 = self->qos_tx.link_disc_time.value * 1000 / 
-		self->qos_tx.max_turn_time.value;
+		self->qos_rx.max_turn_time.value;
 	IRDA_DEBUG(4, "Setting N2 = %d\n", self->N2);
 
 	/* 
diff -u --recursive --new-file v2.4.4/linux/net/irda/irlap_frame.c linux/net/irda/irlap_frame.c
--- v2.4.4/linux/net/irda/irlap_frame.c	Thu Feb  8 15:14:08 2001
+++ linux/net/irda/irlap_frame.c	Tue May  1 16:05:00 2001
@@ -742,12 +742,6 @@
 			return;
 		}
 		
-		/*
-		 *  make sure the skb->sk accounting of memory usage is sane
-		 */
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-		
 		/* 
 		 *  Insert frame in store, in case of retransmissions 
 		 */
@@ -788,12 +782,6 @@
 			return;
 		}
 		
-		/*
-		 *  make sure the skb->sk accounting of memory usage is sane
-		 */
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-		
 		/* 
 		 *  Insert frame in store, in case of retransmissions 
 		 */
@@ -863,9 +851,6 @@
 			return;
 		}		
 
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-		
 		/* Insert frame in store */
 		skb_queue_tail(&self->wx_list, skb_get(skb));
 		
@@ -917,9 +902,6 @@
 			return;
 		}		
 		
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-		
 		/* Insert frame in store */
 		skb_queue_tail(&self->wx_list, skb_get(skb));
 		
@@ -973,12 +955,6 @@
 		tx_skb->next = tx_skb->prev = NULL;
 		tx_skb->list = NULL;
 
-		/*
-		 *  make sure the skb->sk accounting of memory usage is sane
-		 */
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
-
 		/* Clear old Nr field + poll bit */
 		tx_skb->data[1] &= 0x0f;
 
@@ -1058,12 +1034,6 @@
 		/* Unlink tx_skb from list */
 		tx_skb->next = tx_skb->prev = NULL;
 		tx_skb->list = NULL;
-
-		/*
-		 *  make sure the skb->sk accounting of memory usage is sane
-		 */
-		if (skb->sk != NULL)
-			skb_set_owner_w(tx_skb, skb->sk);
 
 		/* Clear old Nr field + poll bit */
 		tx_skb->data[1] &= 0x0f;
diff -u --recursive --new-file v2.4.4/linux/net/irda/irlmp.c linux/net/irda/irlmp.c
--- v2.4.4/linux/net/irda/irlmp.c	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/irlmp.c	Tue May  1 16:05:00 2001
@@ -959,6 +959,7 @@
 {
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;);
+	ASSERT(skb->sk == NULL, /* Just a warning - NOP */;);
 	
 	/* Make room for MUX header */
 	ASSERT(skb_headroom(skb) >= LMP_HEADER, return -1;);
diff -u --recursive --new-file v2.4.4/linux/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c
--- v2.4.4/linux/net/irda/irlmp_event.c	Sat Nov 11 18:11:22 2000
+++ linux/net/irda/irlmp_event.c	Tue May  1 16:05:00 2001
@@ -472,8 +472,6 @@
 		irlmp_start_watchdog_timer(self, 5*HZ);
 		break;
 	case LM_CONNECT_INDICATION:
-		irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
-
 		if (self->conn_skb) {
 			WARNING(__FUNCTION__ 
 				"(), busy with another request!\n");
@@ -481,6 +479,8 @@
 		}
 		self->conn_skb = skb;
 
+		irlmp_next_lsap_state(self, LSAP_CONNECT_PEND);
+
 		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 		break;
 	default:
@@ -562,6 +562,15 @@
 	switch (event) {
 	case LM_CONNECT_REQUEST:
 		/* Keep state */
+		break;
+	case LM_CONNECT_INDICATION:
+		/* Will happen in some rare cases when the socket get stuck,
+		 * the other side retries the connect request.
+		 * We just unstuck the socket - Jean II */
+		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_INDICATION, "
+			   "LSAP stuck in CONNECT_PEND state...\n");
+		/* Keep state */
+		irlmp_do_lap_event(self->lap, LM_LAP_CONNECT_REQUEST, NULL);
 		break;
 	case LM_CONNECT_RESPONSE:
 		IRDA_DEBUG(0, __FUNCTION__ "(), LM_CONNECT_RESPONSE, "
diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet.h linux/net/irda/irnet/irnet.h
--- v2.4.4/linux/net/irda/irnet/irnet.h	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/irnet/irnet.h	Tue May  1 16:05:00 2001
@@ -5,7 +5,7 @@
  *
  * This file contains definitions and declarations global to the IrNET module,
  * all grouped in one place...
- * This file is a private header, so other modules don't want to know
+ * This file is a *private* header, so other modules don't want to know
  * what's in there...
  *
  * Note : as most part of the Linux kernel, this module is available
@@ -52,15 +52,13 @@
  *	o multipoint operation (limited by IrLAP specification)
  *	o information in /proc/net/irda/irnet
  *	o IrNET events on /dev/irnet (for user space daemon)
- *	o IrNET deamon (irnetd) to automatically handle incoming requests
+ *	o IrNET daemon (irnetd) to automatically handle incoming requests
  *	o Windows 2000 compatibility (tested, but need more work)
  * Currently missing :
  *	o Lot's of testing (that's your job)
  *	o Connection retries (may be too hard to do)
  *	o Check pppd persist mode
- *	o User space deamon (to automatically handle incoming requests)
- *	o A registered device number (coming, waiting from an answer) 
- *	o Final integration in Linux-IrDA (up to Dag) 
+ *	o User space daemon (to automatically handle incoming requests)
  *
  * The setup is not currently the most easy, but this should get much
  * better when everything will get integrated...
@@ -159,6 +157,17 @@
  *	o Add IRNET_NOANSWER_FROM event (mostly to help support)
  *	o Release flow control in disconnect_indication
  *	o Block packets while connecting (speed up connections)
+ *
+ * v5 - 11/01/01 - Jean II
+ *	o Init self->max_header_size, just in case...
+ *	o Set up ap->chan.hdrlen, to get zero copy on tx side working.
+ *	o avoid tx->ttp->flow->ppp->tx->... loop, by checking flow state
+ *		Thanks to Christian Gennerat for finding this bug !
+ *	---
+ *	o Declare the proper MTU/MRU that we can support
+ *		(but PPP doesn't read the MTU value :-()
+ *	o Declare hashbin HB_NOLOCK instead of HB_LOCAL to avoid
+ *		disabling and enabling irq twice
  */
 
 /***************************** INCLUDES *****************************/
@@ -375,7 +384,7 @@
   struct irda_device_info *discoveries;	/* Copy of the discovery log */
   int			disco_index;	/* Last read in the discovery log */
   int			disco_number;	/* Size of the discovery log */
-#endif INITIAL_DISCOVERY
+#endif /* INITIAL_DISCOVERY */
 
 } irnet_socket;
 
@@ -450,4 +459,4 @@
 /* Control channel stuff - allocated in irnet_irda.h */
 extern struct irnet_ctrl_channel	irnet_events;
 
-#endif IRNET_H
+#endif /* IRNET_H */
diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c
--- v2.4.4/linux/net/irda/irnet/irnet_irda.c	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/irnet/irnet_irda.c	Tue May  1 16:05:00 2001
@@ -380,9 +380,9 @@
   self->ckey = irlmp_register_client(0, NULL, NULL, NULL);
 #ifdef DISCOVERY_NOMASK
   self->mask = 0xffff;		/* For W2k compatibility */
-#else DISCOVERY_NOMASK
+#else /* DISCOVERY_NOMASK */
   self->mask = irlmp_service_to_hint(S_LAN);
-#endif DISCOVERY_NOMASK
+#endif /* DISCOVERY_NOMASK */
   self->tx_flow = FLOW_START;	/* Flow control from IrTTP */
 
   DEXIT(IRDA_SOCK_TRACE, "\n");
@@ -692,7 +692,7 @@
   /* If we want to receive "stream sockets" */
   if(max_sdu_size == 0)
     new->max_data_size = irttp_get_max_seg_size(new->tsap);
-#endif STREAM_COMPAT
+#endif /* STREAM_COMPAT */
 
   /* Clean up the original one to keep it in listen state */
   self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
@@ -708,7 +708,7 @@
    * Also, not doing it give IrDA a chance to finish the setup properly
    * before beeing swamped with packets... */
   ppp_output_wakeup(&new->chan);
-#endif CONNECT_INDIC_KICK
+#endif /* CONNECT_INDIC_KICK */
 
   /* Notify the control channel */
   irnet_post_event(new, IRNET_CONNECT_FROM, new->daddr, self->rname);
@@ -738,7 +738,7 @@
   /* Hum... Is it the right thing to do ? And do we need to send
    * a connect response before ? It looks ok without this... */
   irttp_disconnect_request(self->tsap, NULL, P_NORMAL);
-#endif FAIL_SEND_DISCONNECT
+#endif /* FAIL_SEND_DISCONNECT */
 
   /* Clean up the server to keep it in listen state */
   self->tsap->dtsap_sel = self->tsap->lsap->dlsap_sel = LSAP_ANY;
@@ -788,7 +788,7 @@
 #ifdef ADVERTISE_HINT
   /* Register with IrLMP as a service (advertise our hint bit) */
   irnet_server.skey = irlmp_register_service(hints);
-#endif ADVERTISE_HINT
+#endif /* ADVERTISE_HINT */
 
   /* Register with LM-IAS (so that people can connect to us) */
   irnet_server.ias_obj = irias_new_object(IRNET_SERVICE_NAME, jiffies);
@@ -823,7 +823,7 @@
 #ifdef ADVERTISE_HINT
   /* Unregister with IrLMP */
   irlmp_unregister_service(irnet_server.skey);
-#endif ADVERTISE_HINT
+#endif /* ADVERTISE_HINT */
 
   /* Unregister with LM-IAS */
   if(irnet_server.ias_obj)
@@ -995,7 +995,7 @@
 #ifdef STREAM_COMPAT
   if(max_sdu_size == 0)
     self->max_data_size = irttp_get_max_seg_size(self->tsap);
-#endif STREAM_COMPAT
+#endif /* STREAM_COMPAT */
 
   /* At this point, IrLMP has assigned our source address */
   self->saddr = irttp_get_saddr(self->tsap);
@@ -1012,10 +1012,10 @@
       DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");
       /* Try to pass it to PPP */
       irnet_data_indication(instance, sap, skb);
-#else PASS_CONNECT_PACKETS
+#else /* PASS_CONNECT_PACKETS */
       DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");
       kfree_skb(skb);	/* Note : will be optimised with other kfree... */
-#endif PASS_CONNECT_PACKETS
+#endif /* PASS_CONNECT_PACKETS */
     }
   else
     kfree_skb(skb);
@@ -1039,6 +1039,7 @@
 		      LOCAL_FLOW flow) 
 {
   irnet_socket *	self = (irnet_socket *) instance;
+  LOCAL_FLOW		oldflow = self->tx_flow;
 
   DENTER(IRDA_TCB_TRACE, "(self=0x%X, flow=%d)\n", (unsigned int) self, flow);
 
@@ -1050,7 +1051,11 @@
     {
     case FLOW_START:
       DEBUG(IRDA_CB_INFO, "IrTTP wants us to start again\n");
-      ppp_output_wakeup(&self->chan);
+      /* Check if we really need to wake up PPP */
+      if(oldflow == FLOW_STOP)
+	ppp_output_wakeup(&self->chan);
+      else
+	DEBUG(IRDA_CB_INFO, "But we were already transmitting !!!\n");
       break;
     case FLOW_STOP:
       DEBUG(IRDA_CB_INFO, "IrTTP wants us to slow down\n");
@@ -1157,10 +1162,10 @@
        * WARNING : This need more testing ! */
       irttp_close_tsap(new->tsap);
       /* Note : no return, fall through... */
-#else ALLOW_SIMULT_CONNECT
+#else /* ALLOW_SIMULT_CONNECT */
       irnet_disconnect_server(self, skb);
       return;
-#endif ALLOW_SIMULT_CONNECT
+#endif /* ALLOW_SIMULT_CONNECT */
     }
 
   /* So : at this point, we have a socket, and it is idle. Good ! */
@@ -1173,10 +1178,10 @@
       DEBUG(IRDA_CB_INFO, "Passing connect packet to PPP.\n");
       /* Try to pass it to PPP */
       irnet_data_indication(new, new->tsap, skb);
-#else PASS_CONNECT_PACKETS
+#else /* PASS_CONNECT_PACKETS */
       DERROR(IRDA_CB_ERROR, "Dropping non empty packet.\n");
       kfree_skb(skb);	/* Note : will be optimised with other kfree... */
-#endif PASS_CONNECT_PACKETS
+#endif /* PASS_CONNECT_PACKETS */
     }
   else
     kfree_skb(skb);
@@ -1312,7 +1317,7 @@
 
   DEXIT(IRDA_OCB_TRACE, "\n");
 }
-#endif DISCOVERY_EVENTS
+#endif /* DISCOVERY_EVENTS */
 
 
 /*********************** PROC ENTRY CALLBACKS ***********************/
@@ -1426,7 +1431,7 @@
   memset(&irnet_server, 0, sizeof(struct irnet_root));
 
   /* Setup start of irnet instance list */
-  irnet_server.list = hashbin_new(HB_LOCAL); 
+  irnet_server.list = hashbin_new(HB_NOLOCK); 
   DABORT(irnet_server.list == NULL, -ENOMEM,
 	 MODULE_ERROR, "Can't allocate hashbin!\n");
   /* Init spinlock for instance list */
@@ -1469,7 +1474,7 @@
 #ifdef CONFIG_PROC_FS
   /* Remove our /proc file */
   remove_proc_entry("irnet", proc_irda);
-#endif CONFIG_PROC_FS
+#endif /* CONFIG_PROC_FS */
 
   /* Remove our IrNET server from existence */
   irnet_destroy_server();
diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet_irda.h linux/net/irda/irnet/irnet_irda.h
--- v2.4.4/linux/net/irda/irnet/irnet_irda.h	Mon Dec 11 13:33:15 2000
+++ linux/net/irda/irnet/irnet_irda.h	Tue May  1 16:05:00 2001
@@ -13,8 +13,9 @@
 #define IRNET_IRDA_H
 
 /***************************** INCLUDES *****************************/
-
 #include <linux/config.h>
+/* Please add other headers in irnet.h */
+
 #include "irnet.h"		/* Module global include */
 
 /************************ CONSTANTS & MACROS ************************/
@@ -149,7 +150,7 @@
 			char **,
 			off_t,
 			int);
-#endif CONFIG_PROC_FS
+#endif /* CONFIG_PROC_FS */
 
 /**************************** VARIABLES ****************************/
 
@@ -164,6 +165,6 @@
 /* The /proc/net/irda directory, defined elsewhere... */
 #ifdef CONFIG_PROC_FS
 extern struct proc_dir_entry *proc_irda;
-#endif CONFIG_PROC_FS
+#endif /* CONFIG_PROC_FS */
 
-#endif IRNET_IRDA_H
+#endif /* IRNET_IRDA_H */
diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet_ppp.c linux/net/irda/irnet/irnet_ppp.c
--- v2.4.4/linux/net/irda/irnet/irnet_ppp.c	Fri Apr 20 11:54:24 2001
+++ linux/net/irda/irnet/irnet_ppp.c	Tue May  1 16:05:00 2001
@@ -186,7 +186,7 @@
 
   return done_event;
 }
-#endif INITIAL_DISCOVERY
+#endif /* INITIAL_DISCOVERY */
 
 /*------------------------------------------------------------------*/
 /*
@@ -221,7 +221,7 @@
       DEXIT(CTRL_TRACE, "\n");
       return(strlen(event));
     }
-#endif INITIAL_DISCOVERY
+#endif /* INITIAL_DISCOVERY */
 
   /* Put ourselves on the wait queue to be woken up */
   add_wait_queue(&irnet_events.rwait, &wait);
@@ -346,7 +346,7 @@
 #ifdef INITIAL_DISCOVERY
   if(ap->disco_number != -1)
     mask |= POLLIN | POLLRDNORM;
-#endif INITIAL_DISCOVERY
+#endif /* INITIAL_DISCOVERY */
 
   DEXIT(CTRL_TRACE, " - mask=0x%X\n", mask);
   return mask;
@@ -379,7 +379,7 @@
   /* This could (should?) be enforced by the permissions on /dev/irnet. */
   if(!capable(CAP_NET_ADMIN))
     return -EPERM;
-#endif SECURE_DEVIRNET
+#endif /* SECURE_DEVIRNET */
 
   /* Allocate a private structure for this IrNET instance */
   ap = kmalloc(sizeof(*ap), GFP_KERNEL);
@@ -394,8 +394,11 @@
   /* PPP channel setup */
   ap->ppp_open = 0;
   ap->chan.private = ap;
+  ap->chan.ops = &irnet_ppp_ops;
+  ap->chan.mtu = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN);
+  ap->chan.hdrlen = 2 + TTP_MAX_HEADER;		/* for A/C + Max IrDA hdr */
   /* PPP parameters */
-  ap->mru = PPP_MRU;
+  ap->mru = (2048 - TTP_MAX_HEADER - 2 - PPP_HDRLEN);
   ap->xaccm[0] = ~0U;
   ap->xaccm[3] = 0x60000000U;
   ap->raccm = ~0U;
@@ -554,7 +557,7 @@
 #ifdef SECURE_DEVIRNET
   if(!capable(CAP_NET_ADMIN))
     return -EPERM;
-#endif SECURE_DEVIRNET
+#endif /* SECURE_DEVIRNET */
 
   err = -EFAULT;
   switch(cmd)
@@ -566,10 +569,7 @@
       if((val == N_SYNC_PPP) || (val == N_PPP))
 	{
 	  DEBUG(FS_INFO, "Entering PPP discipline.\n");
-	  /* PPP channel setup */
-	  ap->chan.private = ap;
-	  ap->chan.ops = &irnet_ppp_ops;
-	  ap->chan.mtu = PPP_MRU;
+	  /* PPP channel setup (ap->chan in configued in dev_irnet_open())*/
 	  err = ppp_register_channel(&ap->chan);
 	  if(err == 0)
 	    {
@@ -672,7 +672,7 @@
        * we get rid of our own buffers */
 #ifdef FLUSH_TO_PPP
       ppp_output_wakeup(&ap->chan);
-#endif FLUSH_TO_PPP
+#endif /* FLUSH_TO_PPP */
       err = 0;
       break;
 
@@ -758,7 +758,7 @@
   /* prepend address/control fields if necessary */
   if(needaddr)
     {
-      skb_push(skb,2);
+      skb_push(skb, 2);
       skb->data[0] = PPP_ALLSTATIONS;
       skb->data[1] = PPP_UI;
     }
@@ -800,7 +800,7 @@
        * go through interruptible_sleep_on() in irnet_find_lsap_sel()
        * We need to find another way... */
       irda_irnet_connect(self);
-#endif CONNECT_IN_SEND
+#endif /* CONNECT_IN_SEND */
 
       DEBUG(PPP_INFO, "IrTTP not ready ! (%d-0x%X)\n",
 	    self->ttp_open, (unsigned int) self->tsap);
@@ -831,7 +831,7 @@
 	  /* Blocking packet, ppp_generic will retry later */
 	  return 0;
 	}
-#endif BLOCK_WHEN_CONNECT
+#endif /* BLOCK_WHEN_CONNECT */
 
       /* Dropping packet, pppd will retry later */
       dev_kfree_skb(skb);
diff -u --recursive --new-file v2.4.4/linux/net/irda/irnet/irnet_ppp.h linux/net/irda/irnet/irnet_ppp.h
--- v2.4.4/linux/net/irda/irnet/irnet_ppp.h	Mon Dec 11 13:33:14 2000
+++ linux/net/irda/irnet/irnet_ppp.h	Mon Apr 30 16:26:09 2001
@@ -27,8 +27,8 @@
  * Should be defined in <linux/if_ppp.h> */
 #ifndef PPPIOCSLINKNAME
 #define PPPIOCSLINKNAME	_IOW('t', 74, struct ppp_option_data)
-#endif PPPIOCSLINKNAME
-#endif LINKNAME_IOCTL
+#endif /* PPPIOCSLINKNAME */
+#endif /* LINKNAME_IOCTL */
 
 /* PPP hardcore stuff */
 
@@ -127,4 +127,4 @@
   ppp_irnet_ioctl
 };
 
-#endif IRNET_PPP_H
+#endif /* IRNET_PPP_H */
diff -u --recursive --new-file v2.4.4/linux/net/irda/irttp.c linux/net/irda/irttp.c
--- v2.4.4/linux/net/irda/irttp.c	Thu Feb  8 15:14:08 2001
+++ linux/net/irda/irttp.c	Tue May  1 16:05:00 2001
@@ -369,7 +369,7 @@
 	} else {
 		/*
 		 *  Fragment the frame, this function will also queue the
-		 *  fragments, we don't care about the fact the the transmit
+		 *  fragments, we don't care about the fact the transmit
 		 *  queue may be overfilled by all the segments for a little
 		 *  while
 		 */
@@ -454,6 +454,46 @@
 		 */
 		skb->data[0] |= (n & 0x7f);
 		
+		/* Detach from socket.
+		 * The current skb has a reference to the socket that sent
+		 * it (skb->sk). When we pass it to IrLMP, the skb will be
+		 * stored in in IrLAP (self->wx_list). When we are within
+		 * IrLAP, we loose the notion of socket, so we should not
+		 * have a reference to a socket. So, we drop it here.
+		 * 
+		 * Why does it matter ?
+		 * When the skb is freed (kfree_skb), if it is associated
+		 * with a socket, it release buffer space on the socket
+		 * (through sock_wfree() and sock_def_write_space()).
+		 * If the socket no longer exist, we may crash. Hard.
+		 * When we close a socket, we make sure that associated packets
+		 * in IrTTP are freed. However, we have no way to cancel
+		 * the packet that we have passed to IrLAP. So, if a packet
+		 * remains in IrLAP (retry on the link or else) after we
+		 * close the socket, we are dead !
+		 * Jean II */
+		if (skb->sk != NULL) {
+			struct sk_buff *tx_skb;
+
+			/* IrSOCK application, IrOBEX, ... */
+			IRDA_DEBUG(4, __FUNCTION__ "() : Detaching SKB from socket.\n");
+			/* Note : still looking for a more efficient way
+			 * to do that - Jean II */
+
+			/* Get another skb on the same buffer, but without
+			 * a reference to the socket (skb->sk = NULL) */
+			tx_skb = skb_clone(skb, GFP_ATOMIC);
+			if (tx_skb != NULL) {
+				/* Release the skb associated with the
+				 * socket, and use the new skb insted */
+				kfree_skb(skb);
+				skb = tx_skb;
+			}
+		} else {
+			/* IrCOMM over IrTTP, IrLAN, ... */
+			IRDA_DEBUG(4, __FUNCTION__ "() : Got SKB not attached to a socket.\n");
+		}
+
 		irlmp_data_request(self->lsap, skb);
 		self->stats.tx_packets++;
 
diff -u --recursive --new-file v2.4.4/linux/net/irda/qos.c linux/net/irda/qos.c
--- v2.4.4/linux/net/irda/qos.c	Thu Feb  8 15:14:08 2001
+++ linux/net/irda/qos.c	Mon Apr 30 16:26:09 2001
@@ -346,7 +346,7 @@
 			WARNING(__FUNCTION__ "(), nothing more we can do!\n");
 		}
 	}
-#endif CONFIG_IRDA_DYNAMIC_WINDOW
+#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
 }
 
 /*
diff -u --recursive --new-file v2.4.4/linux/net/irda/wrapper.c linux/net/irda/wrapper.c
--- v2.4.4/linux/net/irda/wrapper.c	Sat Nov 11 18:11:23 2000
+++ linux/net/irda/wrapper.c	Mon Apr 30 16:26:09 2001
@@ -130,7 +130,7 @@
 #ifdef __LITTLE_ENDIAN
 	n += stuff_byte(fcs.bytes[0], tx_buff+n);
 	n += stuff_byte(fcs.bytes[1], tx_buff+n);
-#else ifdef __BIG_ENDIAN
+#else /* ifdef __BIG_ENDIAN */
 	n += stuff_byte(fcs.bytes[1], tx_buff+n);
 	n += stuff_byte(fcs.bytes[0], tx_buff+n);
 #endif
