diff -u --recursive --new-file v1.1.20/linux/Makefile linux/Makefile
--- v1.1.20/linux/Makefile	Tue Jun 21 14:16:19 1994
+++ linux/Makefile	Tue Jun 21 14:10:14 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 20
+SUBLEVEL = 21
 
 all:	Version zImage
 
diff -u --recursive --new-file v1.1.20/linux/config.in linux/config.in
--- v1.1.20/linux/config.in	Tue Jun 21 14:16:19 1994
+++ linux/config.in	Tue Jun 21 13:23:51 1994
@@ -102,6 +102,7 @@
 #bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
 #bool 'Cabletron E21xx support (not recommended)' CONFIG_E2100 n
 bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
+bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
 bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
 fi
 fi
diff -u --recursive --new-file v1.1.20/linux/drivers/block/hd.c linux/drivers/block/hd.c
--- v1.1.20/linux/drivers/block/hd.c	Tue Apr 19 10:52:42 1994
+++ linux/drivers/block/hd.c	Mon Jun 20 10:24:55 1994
@@ -655,6 +655,8 @@
 			hd_info[drive].ctl = *(8+BIOS);
 			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
 			hd_info[drive].sect = *(14+BIOS);
+			if (hd_info[drive].cyl && NR_HD == drive)
+				NR_HD++;
 			BIOS += 16;
 		}
 
diff -u --recursive --new-file v1.1.20/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v1.1.20/linux/drivers/char/n_tty.c	Tue May 31 12:48:16 1994
+++ linux/drivers/char/n_tty.c	Tue Jun 21 13:31:19 1994
@@ -956,7 +956,8 @@
 {
 	switch (sel_type) {
 		case SEL_IN:
-			if (input_available_p(tty, MIN_CHAR(tty)))
+			if (input_available_p(tty, TIME_CHAR(tty) ? 0 :
+					      MIN_CHAR(tty)))
 				return 1;
 			/* fall through */
 		case SEL_EX:
diff -u --recursive --new-file v1.1.20/linux/drivers/char/pty.c linux/drivers/char/pty.c
--- v1.1.20/linux/drivers/char/pty.c	Fri Jun 17 15:20:04 1994
+++ linux/drivers/char/pty.c	Tue Jun 21 13:31:19 1994
@@ -133,7 +133,7 @@
 {
 	struct tty_struct *to = tty->link;
 
-	if (!to)
+	if (!to || !to->ldisc.chars_in_buffer)
 		return 0;
 
 	return to->ldisc.chars_in_buffer(to);
diff -u --recursive --new-file v1.1.20/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.1.20/linux/drivers/char/serial.c	Fri Jun 17 15:20:05 1994
+++ linux/drivers/char/serial.c	Tue Jun 21 13:31:19 1994
@@ -871,8 +871,13 @@
 	 * here.
 	 */
 	if (serial_inp(info, UART_LSR) == 0xff) {
-		restore_flags(flags);
-		return -ENODEV;
+			restore_flags(flags);
+		if (suser()) {
+			if (info->tty)
+				set_bit(TTY_IO_ERROR, &info->tty->flags);
+			return 0;
+		} else
+			return -ENODEV;
 	}
 	
 	/*
@@ -892,7 +897,13 @@
 		retval = irqaction(info->irq,&sa);
 		if (retval) {
 			restore_flags(flags);
-			return retval;
+			if (suser()) {
+				if (info->tty)
+					set_bit(TTY_IO_ERROR,
+						&info->tty->flags);
+				return 0;
+			} else
+				return retval;
 		}
 	}
 
@@ -1410,10 +1421,13 @@
 	}
 
 	/* Make sure address is not already in use */
-	for (i = 0 ; i < NR_PORTS; i++)
-		if ((info != &rs_table[i]) &&
-		    (rs_table[i].port == new_serial.port) && rs_table[i].type)
-			return -EADDRINUSE;
+	if (new_serial.type) {
+		for (i = 0 ; i < NR_PORTS; i++)
+			if ((info != &rs_table[i]) &&
+			    (rs_table[i].port == new_serial.port) &&
+			    rs_table[i].type)
+				return -EADDRINUSE;
+	}
 
 	if ((change_port || change_irq) && (info->count > 1))
 		return -EBUSY;
diff -u --recursive --new-file v1.1.20/linux/drivers/net/CONFIG linux/drivers/net/CONFIG
--- v1.1.20/linux/drivers/net/CONFIG	Tue May 24 00:34:50 1994
+++ linux/drivers/net/CONFIG	Tue Jun 21 13:23:51 1994
@@ -30,6 +30,10 @@
 #	  DE600_IO	The DE600 I/O-port address (0x378 == default)
 #	  DE600_IRQ	The DE600 IRQ number to use (IRQ7 == default)
 #	  DE600_DEBUG	Enable or disable DE600 debugging (default off)
+#  DE620		The D-Link DE-600 Portable Ethernet Adaptor.
+#	  DE620_IO	The DE620 I/O-port address (0x378 == default)
+#	  DE620_IRQ	The DE620 IRQ number to use (IRQ7 == default)
+#	  DE620_DEBUG	Enable or disable DE600 debugging (default off)
 #  DEPCA		The DIGITAL series of AT Ethernet Cards (DE100, DE200)
 #	  DEPCA_IRQ	Set the desired IRQ (=0, for autoprobe)
 #	  DEPCA_DEBUG	Set the desired debug level
diff -u --recursive --new-file v1.1.20/linux/drivers/net/MODULES linux/drivers/net/MODULES
--- v1.1.20/linux/drivers/net/MODULES	Tue May 31 12:48:17 1994
+++ linux/drivers/net/MODULES	Tue Jun 21 13:23:51 1994
@@ -1,6 +1,7 @@
 MODULES = \
 	3c509.o \
 	de600.o \
+	de620.o \
 	3c501.o \
 	plip.o
 
diff -u --recursive --new-file v1.1.20/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.1.20/linux/drivers/net/Makefile	Tue Jun 21 14:16:20 1994
+++ linux/drivers/net/Makefile	Tue Jun 21 13:23:51 1994
@@ -91,6 +91,15 @@
 ifdef CONFIG_DE600
 NETDRV_OBJS := $(NETDRV_OBJS) net.a(de600.o)
 endif
+de600.o: de600.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE600_OPTS) -c $<
+	
+ifdef CONFIG_DE620
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(de620.o)
+endif
+de620.o: de620.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DE620_OPTS) -c $<
+	
 ifdef CONFIG_AT1500
 NETDRV_OBJS := $(NETDRV_OBJS) net.a(lance.o)
 endif
diff -u --recursive --new-file v1.1.20/linux/drivers/net/README.DLINK linux/drivers/net/README.DLINK
--- v1.1.20/linux/drivers/net/README.DLINK	Wed Dec  1 14:44:15 1993
+++ linux/drivers/net/README.DLINK	Tue Jun 21 13:23:52 1994
@@ -1,177 +1,205 @@
-This is version 0.32
+Released 1994-06-13
 
-          CONTENTS:
 
-            1. Introduction.
-            2. License.
-            3. Files in this release.
-            4. Installation.
-            5. Problems and tuning.
-            6. Acknowledgments.
+	CONTENTS:
 
+	1. Introduction.
+	2. License.
+	3. Files in this release.
+	4. Installation.
+	5. Problems and tuning.
+	6. Using the drivers with earlier releases.
+	7. Acknowledgments.
+
+
+	1. INTRODUCTION.
+
+	This is a set of Ethernet drivers for the D-Link DE-600/DE-620
+	pocket adapters, for the parallel port on a Linux based machine.
+	Some adapter "clones" will also work.  Xircom is _not_ a clone...
+	These drivers _can_ be used as loadable modules,
+	and were developed for use on Linux v1.1.13 and above.
+	For use on Linux v1.0.X, or earlier releases, see below.
+
+	I have used these drivers for NFS, ftp, telnet and X-clients on
+	remote machines. Transmissions with ftp seems to work as
+	good as can be expected (i.e. > 80k bytes/sec) from a
+	parallel port...:-)  Receive speeds will be about 60-80% of this.
+	Depending on your machine, somewhat higher speeds can be achieved.
+
+	All comments/fixes to Bjorn Ekwall (bj0rn@blox.se).
+
+
+	2. LICENSE.
+
+	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, 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.
+
+
+	3. FILES IN THIS RELEASE.
+
+	README.DLINK  This file.
+	de600.c       The Source (,may it be with You :-) for the DE-600
+	de620.c       ditto for the DE-620
+	de620.h       Macros for de620.c
+
+	If you are upgrading from the d-link tar release, there will
+	also be a "dlink-patches" file that will patch Linux v1.1.18:
+		linux/drivers/net/Makefile
+		linux/drivers/net/CONFIG
+		linux/drivers/net/MODULES
+		linux/drivers/net/Space.c
+		linux/config.in
+	Apply the patch by:
+	"cd /usr/src; patch -p0 < linux/drivers/net/dlink-patches"
+	The old source, "linux/drivers/net/d_link.c", can be removed.
+
+
+	4. INSTALLATION.
+
+	o Get the latest net binaries, according to current net.wisdom.
+
+	o Read the NET-2 and Ethernet HOWTO's and modify your setup.
+
+	o If your parallel port has a strange address or irq,
+	  modify "linux/drivers/net/CONFIG" accordingly, or adjust
+	  the parameters in the "tuning" section in the sources.
+
+	If you are going to use the drivers a loadable modules, do _not_
+	enable them while doing "make config", but instead make sure that
+	the drivers are included in "linux/drivers/net/MODULES".
+
+	If you are _not_ going to use the driver(s) as loadable modules,
+	but instead have them included in the kernel, remember to enable
+	the drivers while doing "make config".
+
+	o To include networking and DE600/DE620 support in your kernel:
+	  # cd /linux
+	  (as modules:)
+	  #  make config (answer yes on CONFIG_NET and CONFIG_INET)
+	  (else included in the kernel:)
+	  #  make config (answer yes on CONFIG _NET, _INET and _DE600 or _DE620)
+	  # make clean
+	  # make depend
+	  # make zImage (or whatever magic you usually do)
+
+	o I use lilo to boot multiple kernels, so that I at least
+	  can have one working kernel :-). If you do too, append
+	  these lines to /etc/lilo/config:
+
+		image = /linux/zImage
+		label = newlinux
+		root = /dev/hda2 (or whatever YOU have...)
+
+	  # /etc/lilo/install
+
+	o Do "sync" and reboot the new kernel with a D-Link
+	  DE-600/DE-620 pocket adapter connected.
+
+	o The adapter can be configured with ifconfig eth?
+	  where the actual number is decided by the kernel
+	  when the drivers are initialized.
+
+
+	5. "PROBLEMS" AND TUNING,
+
+	o If you see error messages from the driver, and if the traffic
+	  stops on the adapter, try to do "ifconfig" and "route" once
+	  more, just as in "rc.inet1".  This should take care of most
+	  problems, including effects from power loss, or adapters that
+	  aren't connected to the printer port in some way or another.
+	  You can somewhat change the behaviour by enabling/disabling
+	  the macro  SHUTDOWN_WHEN_LOST  in the "tuning" section.
+	  For the DE-600 there is another macro, CHECK_LOST_DE600,
+	  that you might want to read about in the "tuning" section.
+
+	o Some machines have trouble handling the parallel port and
+	  the adapter at high speed. If you experience problems:
+
+	  DE-600:
+	  - The adapter is not recognized at boot, i.e. an Ethernet
+	    adress of 00:80:c8:... is not shown, try to add another
+	      "; SLOW_DOWN_IO"
+	    at DE600_SLOW_DOWN in the "tuning" section. As a last resort,
+	    uncomment: "#define REALLY_SLOW_IO" (see <asm/io.h> for hints).
+
+	  - You experience "timeout" messages: first try to add another
+	      "; SLOW_DOWN_IO"
+	    at DE600_SLOW_DOWN in the "tuning" section, _then_ try to
+	    increase the value (original value: 5) at
+	    "if (tickssofar < 5)" near line 422.
+
+	  DE-620:
+	  - Your parallel port might be "sluggish".  To cater for
+	    this, there are the macros LOWSPEED and READ_DELAY/WRITE_DELAY
+	    in the "tuning" section. Your first step should be to enable
+	    LOWSPEED, and after that you can "tune" the XXX_DELAY values.
+
+	o If the adapter _is_ recognized at boot but you get messages
+	  about "Network Unreachable", then the problem is probably
+	  _not_ with the driver.  Check your net configuration instead
+	  (ifconfig and route) in "rc.inet1".
+
+	o There is some rudimentary support for debugging, look at
+	  the source. Use "-DDE600_DEBUG=3" or "-DDE620_DEBUG=3"
+	  when compiling, or include it in "linux/drivers/net/CONFIG".
+	  IF YOU HAVE PROBLEMS YOU CAN'T SOLVE: PLEASE COMPILE THE DRIVER
+	  WITH DEBUGGING ENABLED, AND SEND ME THE RESULTING OUTPUT!
+
+
+	6. USING THE DRIVERS WITH EARLIER RELEASES.
+
+	The later v1.1.X releases of the Linux kernel include some
+	changes in the networking layer (a.k.a. NET3). This affects
+	these drivers in a few places.  The hints that follow are
+	_not_ tested by me, since I don't have the diskspace to keep
+	all releases on-line.
+	Known needed changes to date:
+	- release patchfile: some patches will fail, but they should
+	  be easy to apply "by hand", since they are trivial.
+	  (Space.c: d_link_init() is now called de600_probe())
+	- de600.c: change  "mark_bh(NET_BH)" to  "mark_bh(INET_BH)".
+	- de620.c: (maybe) change the code around "netif_rx(skb);" to be
+		   similar to the code around "dev_rint(...)" in de600.c
+
+
+	7. ACKNOWLEDGMENTS.
+
+	These drivers wouldn't have been done without the base
+	(and support) from Ross Biro <bir7@leland.stanford.edu>,
+	and D-Link Systems Inc.  The driver relies upon GPL-ed
+	source from D-Link Systems Inc. and from Russel Nelson at
+	Crynwr Software <nelson@crynwr.com>.
+
+	Additional input also from:
+	Donald Becker <becker@super.org>, Alan Cox <A.Cox@swansea.ac.uk>
+	and Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
+
+	DE-600 alpha release primary victim^H^H^H^H^H^Htester:
+	- Erik Proper <erikp@cs.kun.nl>.
+	Good input also from several users, most notably
+	- Mark Burton <markb@ordern.demon.co.uk>.
+
+	DE-620 alpha release victims^H^H^H^H^H^H^Htesters:
+	- J. Joshua Kopper <kopper@rtsg.mot.com>
+	- Olav Kvittem <Olav.Kvittem@uninett.no>
+	- Germano Caronni <caronni@nessie.cs.id.ethz.ch>
+	- Jeremy Fitzhardinge <jeremy@suite.sw.oz.au>
 
-          1. INTRODUCTION.
 
-          This is an Ethernet driver for the D-Link DE-600 Ethernet pocket
-          adapter for the parallel port, used with Linux on a laptop.
-          Some improvements over the 0.2X releases include:
-            o  driver code trying to send packets end to end,
-            o  a more solid interrupt handler,
-            o  a fix that modifies the tcp protocol so that
-               the DE-600 won't choke as easily on receives.
+	Happy hacking!
 
-          This is a beta release, i.e. it ought to work! (:-)
-
-          I have used this driver for NFS, ftp, telnet and X-clients on
-          remote machines. Transmissions with ftp seems to work as
-          good as can be expected (i.e. > 80k bytes/sec) from a
-          parallel port...:-)
-          The speed limit is now in the upper protocols,
-          at least for a 386SX-25 :-)
-
-          All comments/fixes to Bjorn Ekwall (bj0rn@blox.se).
-
-          (No, I have _not_ included any support for the DE-620 yet
-          since I have _no_ official documentation on how to program
-          that beast. There are some code modifications in place
-          already in case I get some _real_ info..., c'mon D-Link!)
-
-
-          2. LICENSE.
-
-          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, 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.
-
-
-          3. FILES IN THIS RELEASE.
-
-          README.DLINK  This file.
-          d_link.c      The Source (,may it be with You :-).
-
-
-          4. INSTALLATION.
-
-           o Get the latest net binaries (those referring to /conf/net).
-
-           o Read the NET-2 and Ethernet HOWTO's and modify your setup.
-
-           o To include networking and the DE600 in your kernel, do:
-               # cd /linux
-               # make config       (answer yes on net and DE600)
-               # make clean
-               # make depend
-               # make zImage (or whatever magic you usually do)
-
-           o I use lilo to boot multiple kernels, so that I at least
-             can have one working kernel :-). If you do too, append
-             these lines to /etc/lilo/config:
-
-                  image = /usr/src/linux/zImage
-                       label = newlinux
-                       root = /dev/hda2 (or whatever YOU have...)
-
-               # /etc/lilo/install
-
-           o Do "sync" and reboot the new kernel with a D-Link pocket
-             adapter connected.
-
-          Now, watch for any fireworks (try to ignore (or live with)
-          the smoke... :-) or:
-
-               do
-                    read NET-FAQ and all info in /conf/net
-                    if fix in code needed...
-			 vi /linux/net/inet/d_link.c
-			 cd /linux
-                         make zImage
-			 /etc/lilo/install
-                         sync
-                         reboot
-                    endif
-                    try it...
-               until satisfied
-
-
-          5. "PROBLEMS" AND TUNING,
-
-           o Some machines have trouble handling the parallel port and
-             the adapter at high speed. If you experience problems:
-
-             - The adapter is not recognized at boot, i.e. an Ethernet
-               adress of 00:80:c8:... is not shown, try to add another
-                 "; SLOW_DOWN_IO"
-               at D_LINK_SLOW_DOWN near line 43. As a last resort, uncomment:
-                 "#define REALLY_SLOW_IO"
-               near line 48 (see <asm/io.h> for hints).
-
-             - You experience "timeout" messages: first try to add
-               another "; SLOW_DOWN_IO" at D_LINK_SLOW_DOWN near line 22,
-               _then_ try to increase the value (original value: 5)
-               at "if (tickssofar < 5)" near line 424.
-
-             - The adapter _is_ recognized at boot but you get
-               messages about "Network Unreachable": The problem
-               is probably _not_ with the d_link driver.
-               Check your net configuration instead (ifconfig and route)
-               in "rc.inet1".
-             
-           o There might be some temporary "slowdowns" when communicating
-             with other systems when receiving through the TCP layer.
-             A "fix" for this is made lastly in the source, in the function
-             "d_link_rspace()" that is used to modify TCP if there is
-             a DE-600 in use (see comments around lines 320 and 730).
-
-             The aim of this fix is to reduce the possibility of more
-             than two packets arriving adressed to the adapter within
-             the timespan it takes to copy one packet from the adapter.
-
-             Transfers with ftp with a packetsize of >= 1k will be taken
-             care of with this "fix", but telnet with many small packets
-             might run into problems sometimes. The "slowdown" will usually
-             take care of itself, especially if there are some larger packets
-             arriving now and then...
-
-             There is some room for "tuning" by changing (decreasing) the
-             values for "D_LINK_MAX_WINDOW" and "D_LINK_MIN_WINDOW"
-             defined near the end of the file (around line 726).
-             UDP (i.e. NFS) does not suffer from the same problem.
-
-           o The code inside d_link_interrupt() is somewhat of a
-             (educated) guesswork since my only source of information
-             is the asm-source (:-), though I have tried to improve on it.
-
-           o There is some rudimentary support for debugging, see
-	     the source. Use "-DD_LINK_DEBUG=3" when compiling.
-
-
-          6. ACKNOWLEDGMENTS.
-
-          This driver wouldn't have been done without the base
-          (and support) from Ross Biro (bir7@leland.stanford.edu).
-          The driver also relies upon GPL-ed source from D-Link Inc.
-          and from Russel Nelson at Crynwr Software (nelson@crynwr.com).
-          Additional input also from Donald Becker (becker@super.org).
-          Alpha release primary victim^H^H^H^H^H^Htester:
-          Erik Proper (erikp@cs.kun.nl).
-          Good input also from several users, most notably Mark Burton
-          <markb@ordern.demon.co.uk>.
-          Lastly, Fred van Kempen deserves all thanks for keeping up
-          the good work which will give us all a _great_ net package!
-
-
-          Happy hacking!
-
-          Bjorn Ekwall == bj0rn@blox.se
+	Bjorn Ekwall == bj0rn@blox.se
diff -u --recursive --new-file v1.1.20/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.1.20/linux/drivers/net/Space.c	Thu Jun  9 18:56:11 1994
+++ linux/drivers/net/Space.c	Tue Jun 21 13:23:52 1994
@@ -57,6 +57,7 @@
 /* Detachable devices ("pocket adaptors" and special PCMCIA drivers). */
 extern int atp_init(struct device *);
 extern int de600_probe(struct device *);
+extern int de620_probe(struct device *);
 
 static int
 ethif_probe(struct device *dev)
@@ -115,8 +116,11 @@
 #ifdef CONFIG_E2100		/* Cabletron E21xx series. */
 	&& e2100_probe(dev)
 #endif
-#ifdef CONFIG_DE600
+#ifdef CONFIG_DE600		/* D-Link DE-600 adapter */
 	&& de600_probe(dev)
+#endif
+#ifdef CONFIG_DE620		/* D-Link DE-620 adapter */
+	&& de620_probe(dev)
 #endif
 	&& 1 ) {
 	return 1;	/* -ENODEV or -EAGAIN would be more accurate. */
diff -u --recursive --new-file v1.1.20/linux/drivers/net/apricot.c linux/drivers/net/apricot.c
--- v1.1.20/linux/drivers/net/apricot.c	Tue Jun 21 14:16:20 1994
+++ linux/drivers/net/apricot.c	Tue Jun 21 13:23:52 1994
@@ -636,11 +636,14 @@
     if (check_region(ioaddr, APRICOT_TOTAL_SIZE))
 	return mem_start;
 
-    /* very similar to the SMC card except that the checksum is 0x200 */
     for (i = 0; i < 8; i++)
 	checksum += inb(ioaddr + 8 + i);
 
-    if (checksum != 0x200) return mem_start;
+    /* checksum is a multiple of 0x100, got this wrong first time
+       some machines have 0x100, some 0x200. The DOS driver doesn't
+       even bother with the checksum */
+
+    if (checksum % 0x100) return mem_start;
 
     dev = init_etherdev(0, (sizeof (struct i596_private) + 0xf), &mem_start);
 
diff -u --recursive --new-file v1.1.20/linux/drivers/net/de600.c linux/drivers/net/de600.c
--- v1.1.20/linux/drivers/net/de600.c	Tue Jun 21 14:16:21 1994
+++ linux/drivers/net/de600.c	Tue Jun 21 13:23:52 1994
@@ -1,11 +1,11 @@
 static char *version =
-	"de600.c: $Revision: 1.35 $,  Bjorn Ekwall (bj0rn@blox.se)\n";
+	"de600.c: $Revision: 1.39 $,  Bjorn Ekwall (bj0rn@blox.se)\n";
 /*
  *	de600.c
  *
  *	Linux driver for the D-Link DE-600 Ethernet pocket adapter.
  *
- *	Portions (C) Copyright 1993 by Bjorn Ekwall
+ *	Portions (C) Copyright 1993, 1994 by Bjorn Ekwall
  *	The Author may be reached as bj0rn@blox.se
  *
  *	Based on adapter information gathered from DE600.ASM by D-Link Inc.,
@@ -50,9 +50,34 @@
 #define SLOW_IO_BY_JUMPING /* Looks "better" than dummy write to port 0x80 :-) */
 
 /*
- * For fix to TCP "slowdown", take a look at the "#define DE600_MAX_WINDOW"
- * near the end of the file...
+ * If you want to enable automatic continuous checking for the DE600,
+ * keep this #define enabled.
+ * It doesn't cost much per packet, so I think it is worth it!
+ * If you disagree, comment away the #define, and live with it...
+ *
+ */
+#define CHECK_LOST_DE600
+
+/*
+ * Enable this #define if you want the adapter to do a "ifconfig down" on
+ * itself when we have detected that something is possibly wrong with it.
+ * The default behaviour is to retry with "adapter_init()" until success.
+ * This should be used for debugging purposes only.
+ * (Depends on the CHECK_LOST_DE600 above)
+ *
+ */
+#define SHUTDOWN_WHEN_LOST
+
+/*
+ * See comment at "de600_rspace()"!
+ * This is an *ugly* hack, but for now it achieves its goal of
+ * faking a TCP flow-control that will not flood the poor DE600.
+ *
+ * Tricks TCP to announce a small max window (max 2 fast packets please :-)
+ *
+ * Comment away at your own risk!
  */
+#define FAKE_SMALL_MAX
 
 /* use 0 for production, 1 for verification, >2 for debug */
 #ifdef DE600_DEBUG
@@ -61,7 +86,7 @@
 #define DE600_DEBUG 0
 #define PRINTK(x) /**/
 #endif
-static unsigned int de600_debug = DE600_DEBUG;
+unsigned int de600_debug = DE600_DEBUG;
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -81,12 +106,16 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-#ifdef MODULE
 #include <linux/module.h>
 #include "../../tools/version.h"
+
+#ifdef FAKE_SMALL_MAX
+static unsigned long de600_rspace(struct sock *sk);
+#include "../../net/inet/sock.h"
 #endif
 
 #define netstats enet_statistics
+typedef unsigned char byte;
 
 /**************************************************
  *                                                *
@@ -206,14 +235,9 @@
 /*
  * Index to functions, as function prototypes.
  */
-#if 0
-/* For tricking tcp.c to announce a small max window (max 2 fast packets please :-) */
-static unsigned long	de600_rspace(struct sock *sk);
-#endif
-
 /* Routines used internally. (See "convenience macros") */
-static int		de600_read_status(struct device *dev);
-static unsigned	char	de600_read_byte(unsigned char type, struct device *dev);
+static byte	de600_read_status(struct device *dev);
+static byte	de600_read_byte(unsigned char type, struct device *dev);
 
 /* Put in the device structure. */
 static int	de600_open(struct device *dev);
@@ -229,7 +253,7 @@
 /* Initialization */
 static void	trigger_interrupt(struct device *dev);
 int		de600_probe(struct device *dev);
-static void	adapter_init(struct device *dev);
+static int	adapter_init(struct device *dev);
 
 /*
  * D-Link driver variables:
@@ -242,6 +266,7 @@
 static volatile int		tx_fifo_in = 0;
 static volatile int		tx_fifo_out = 0;
 static volatile int		free_tx_pages = TX_PAGES;
+static int			was_down = 0;
 
 /*
  * Convenience macros/functions for D-Link adapter
@@ -278,10 +303,10 @@
 
 #define tx_page_adr(a) (((a) + 1) * MEM_2K)
 
-static inline int
+static inline byte
 de600_read_status(struct device *dev)
 {
-	int	status;
+	byte status;
 
 	outb_p(STATUS, DATA_PORT);
 	status = inb(STATUS_PORT);
@@ -290,9 +315,9 @@
 	return status;
 }
 
-static inline unsigned char
+static inline byte
 de600_read_byte(unsigned char type, struct device *dev) { /* dev used by macros */
-	unsigned char	lo;
+	byte lo;
 
 	(void)outb_p((type), DATA_PORT);
 	lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
@@ -311,10 +336,6 @@
 static int
 de600_open(struct device *dev)
 {
-#if 0
-	extern struct proto tcp_prot;
-#endif
-
 	if (request_irq(DE600_IRQ, de600_interrupt)) {
 		printk ("%s: unable to get IRQ %d\n", dev->name, DE600_IRQ);
 		return 1;
@@ -324,21 +345,10 @@
 #ifdef MODULE
 	MOD_INC_USE_COUNT;
 #endif
-	adapter_init(dev);
-
-	/*
-	 * Yes, I know!
-	 * This is really not nice, but since a machine that uses DE-600
-	 * rarely uses any other TCP/IP connection device simultaneously,
-	 * this hack shouldn't really slow anything up.
-	 * (I don't know about slip though... but it won't break it)
-	 *
-	 * This fix is better than changing in tcp.h IMHO
-	 */
-#if 0	 
-	tcp_prot.rspace = de600_rspace; /* was: sock_rspace */
-#endif
-
+	dev->start = 1;
+	if (adapter_init(dev)) {
+		return 1;
+	}
 
 	return 0;
 }
@@ -356,15 +366,14 @@
 	de600_put_command(0);
 	select_prn();
 
-	free_irq(DE600_IRQ);
-	irq2dev_map[DE600_IRQ] = NULL;
-	dev->start = 0;
+	if (dev->start) {
+		free_irq(DE600_IRQ);
+		irq2dev_map[DE600_IRQ] = NULL;
+		dev->start = 0;
 #ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
-#if 0
-	tcp_prot.rspace = sock_rspace; /* see comment above! */
+		MOD_DEC_USE_COUNT;
 #endif
+	}
 	return 0;
 }
 
@@ -391,10 +400,10 @@
 static int
 de600_start_xmit(struct sk_buff *skb, struct device *dev)
 {
-	int		transmit_from;
-	int		len;
-	int		tickssofar;
-	unsigned char	*buffer = skb->data;
+	int	transmit_from;
+	int	len;
+	int	tickssofar;
+	byte	*buffer = skb->data;
 
 	/*
 	 * If some higher layer thinks we've missed a
@@ -420,7 +429,9 @@
 			"network cable problem"
 			);
 		/* Restart the adapter. */
-		adapter_init(dev);
+		if (adapter_init(dev)) {
+			return 1;
+		}
 	}
 
 	/* Start real output */
@@ -431,10 +442,21 @@
 
 	cli();
 	select_nic();
-
 	tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
 	tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */
 
+#ifdef CHECK_LOST_DE600
+	/* This costs about 40 instructions per packet... */
+	de600_setup_address(NODE_ADDRESS, RW_ADDR);
+	de600_read_byte(READ_DATA, dev);
+	if (was_down || (de600_read_byte(READ_DATA, dev) != 0xde)) {
+		if (adapter_init(dev)) {
+			sti();
+			return 1;
+		}
+	}
+#endif
+
 	de600_setup_address(transmit_from, RW_ADDR);
 	for ( ; len > 0; --len, ++buffer)
 		de600_put_byte(*buffer);
@@ -442,7 +464,7 @@
 	if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
 		dev->trans_start = jiffies;
 		dev->tbusy = 0;	/* allow more packets into adapter */
-		/* Send page and generate an interrupt */
+		/* Send page and generate a faked interrupt */
 		de600_setup_address(transmit_from, TX_ADDR);
 		de600_put_command(TX_ENABLE);
 	}
@@ -453,6 +475,13 @@
 	
 	sti(); /* interrupts back on */
 	
+#ifdef FAKE_SMALL_MAX
+	/* This will "patch" the socket TCP proto at an early moment */
+	if (skb->sk && (skb->sk->protocol == IPPROTO_TCP) &&
+		(skb->sk->prot->rspace != &de600_rspace))
+		skb->sk->prot->rspace = de600_rspace; /* Ugh! */
+#endif
+
 	dev_kfree_skb (skb, FREE_WRITE);
 
 	return 0;
@@ -467,7 +496,7 @@
 {
 	int		irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
 	struct device	*dev = irq2dev_map[irq];
-	unsigned char	irq_status;
+	byte		irq_status;
 	int		retrig = 0;
 	int		boguscount = 0;
 
@@ -482,7 +511,7 @@
 	irq_status = de600_read_status(dev);
 
 	do {
-		PRINTK(("de600_interrupt (%2.2X)\n", irq_status));
+		PRINTK(("de600_interrupt (%02X)\n", irq_status));
 
 		if (irq_status & RX_GOOD)
 			de600_rx_intr(dev);
@@ -496,7 +525,7 @@
 			retrig = 0;
 
 		irq_status = de600_read_status(dev);
-	} while ( (irq_status & RX_GOOD) || ((++boguscount < 10) && retrig) );
+	} while ( (irq_status & RX_GOOD) || ((++boguscount < 100) && retrig) );
 	/*
 	 * Yeah, it _looks_ like busy waiting, smells like busy waiting
 	 * and I know it's not PC, but please, it will only occur once
@@ -571,8 +600,12 @@
 	de600_put_command(RX_ENABLE);
 	sti();
 
-	if ((size < 32)  ||  (size > 1535))
+	if ((size < 32)  ||  (size > 1535)) {
 		printk("%s: Bogus packet size %d.\n", dev->name, size);
+		if (size > 10000)
+			adapter_init(dev);
+		return;
+	}
 
 	skb = alloc_skb(size, GFP_ATOMIC);
 	sti();
@@ -651,9 +684,9 @@
 		return ENODEV;
 	}
 
-	printk(", Ethernet Address: %2.2X", dev->dev_addr[0]);
+	printk(", Ethernet Address: %02X", dev->dev_addr[0]);
 	for (i = 1; i < ETH_ALEN; i++)
-		printk(":%2.2X",dev->dev_addr[i]);
+		printk(":%02X",dev->dev_addr[i]);
 	printk("\n");
 
 	/* Initialize the device structure. */
@@ -673,21 +706,49 @@
 	return 0;
 }
 
-static void
+static int
 adapter_init(struct device *dev)
 {
 	int	i;
+	long flags;
 
+	save_flags(flags);
 	cli();
-	dev->tbusy = 0;		/* Transmit busy...  */
-	dev->interrupt = 0;
-	dev->start = 1;
 
 	select_nic();
 	rx_page = 0; /* used by RESET */
 	de600_put_command(RESET);
 	de600_put_command(STOP_RESET);
+#ifdef CHECK_LOST_DE600
+	/* Check if it is still there... */
+	/* Get the some bytes of the adapter ethernet address from the ROM */
+	de600_setup_address(NODE_ADDRESS, RW_ADDR);
+	de600_read_byte(READ_DATA, dev);
+	if ((de600_read_byte(READ_DATA, dev) != 0xde) ||
+	    (de600_read_byte(READ_DATA, dev) != 0x15)) {
+	/* was: if (de600_read_status(dev) & 0xf0) { */
+		printk("Something has happened to the DE-600!  Please check it"
+#ifdef SHUTDOWN_WHEN_LOST
+			" and do a new ifconfig"
+#endif /* SHUTDOWN_WHEN_LOST */
+			"!\n");
+#ifdef SHUTDOWN_WHEN_LOST
+		/* Goodbye, cruel world... */
+		dev->flags &= ~IFF_UP;
+		de600_close(dev);
+#endif /* SHUTDOWN_WHEN_LOST */
+		was_down = 1;
+		dev->tbusy = 1;		/* Transmit busy...  */
+		return 1; /* failed */
+	}
+#endif /* CHECK_LOST_DE600 */
+	if (was_down) {
+		printk("Thanks, I feel much better now!\n");
+		was_down = 0;
+	}
 
+	dev->tbusy = 0;		/* Transmit busy...  */
+	dev->interrupt = 0;
 	tx_fifo_in = 0;
 	tx_fifo_out = 0;
 	free_tx_pages = TX_PAGES;
@@ -703,10 +764,12 @@
 	/* Enable receiver */
 	de600_put_command(RX_ENABLE);
 	select_prn();
-	sti();
+	restore_flags(flags);
+
+	return 0; /* OK */
 }
 
-#if 0
+#ifdef FAKE_SMALL_MAX
 /*
  *	The new router code (coming soon 8-) ) will fix this properly.
  */
@@ -714,16 +777,21 @@
 #define DE600_MAX_WINDOW 2048
 #define DE600_TCP_WINDOW_DIFF 1024
 /*
- * Copied from sock.c
+ * Copied from "net/inet/sock.c"
  *
  * Sets a lower max receive window in order to achieve <= 2
  * packets arriving at the adapter in fast succession.
- * (No way that a DE-600 can cope with an ethernet saturated with its packets :-)
+ * (No way that a DE-600 can keep up with a net saturated
+ *  with packets homing in on it :-( )
  *
  * Since there are only 2 receive buffers in the DE-600
  * and it takes some time to copy from the adapter,
  * this is absolutely necessary for any TCP performance whatsoever!
  *
+ * Note that the returned window info will never be smaller than
+ * DE600_MIN_WINDOW, i.e. 1024
+ * This differs from the standard function, that can return an
+ * arbitraily small window!
  */
 #define min(a,b)	((a)<(b)?(a):(b))
 static unsigned long
@@ -735,22 +803,23 @@
 /*
  * Hack! You might want to play with commenting away the following line,
  * if you know what you do!
- */
   	sk->max_unacked = DE600_MAX_WINDOW - DE600_TCP_WINDOW_DIFF;
+ */
 
-	if (sk->rmem_alloc >= SK_RMEM_MAX-2*DE600_MIN_WINDOW) return(0);
-	amt = min((SK_RMEM_MAX-sk->rmem_alloc)/2-DE600_MIN_WINDOW, DE600_MAX_WINDOW);
+	if (sk->rmem_alloc >= sk->rcvbuf-2*DE600_MIN_WINDOW) return(0);
+	amt = min((sk->rcvbuf-sk->rmem_alloc)/2/*-DE600_MIN_WINDOW*/, DE600_MAX_WINDOW);
 	if (amt < 0) return(0);
 	return(amt);
   }
   return(0);
 }
 #endif
-
+
 #ifdef MODULE
 char kernel_version[] = UTS_RELEASE;
+static char nullname[8];
 static struct device de600_dev = {
-	"        " /*"de600"*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de600_probe };
+	nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de600_probe };
 
 int
 init_module(void)
diff -u --recursive --new-file v1.1.20/linux/drivers/net/de620.c linux/drivers/net/de620.c
--- v1.1.20/linux/drivers/net/de620.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/de620.c	Tue Jun 21 13:23:53 1994
@@ -0,0 +1,986 @@
+/*
+ *	de620.c $Revision: 1.30 $ BETA
+ *
+ *
+ *	Linux driver for the D-Link DE-620 Ethernet pocket adapter.
+ *
+ *	Portions (C) Copyright 1993, 1994 by Bjorn Ekwall <bj0rn@blox.se>
+ *
+ *	Based on adapter information gathered from DOS packetdriver
+ *	sources from D-Link Inc:  (Special thanks to Henry Ngai of D-Link.)
+ *		Portions (C) Copyright D-Link SYSTEM Inc. 1991, 1992
+ *		Copyright, 1988, Russell Nelson, Crynwr Software
+ *
+ *	Adapted to the sample network driver core for linux,
+ *	written by: Donald Becker <becker@super.org>
+ *		(Now at <becker@cesdis.gsfc.nasa.gov>
+ *
+ *	Valuable assistance from:
+ *		J. Joshua Kopper <kopper@rtsg.mot.com>
+ *		Olav Kvittem <Olav.Kvittem@uninett.no>
+ *		Germano Caronni <caronni@nessie.cs.id.ethz.ch>
+ *		Jeremy Fitzhardinge <jeremy@suite.sw.oz.au>
+ *
+ *****************************************************************************/
+/*
+ *	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, 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. 
+ *
+ *****************************************************************************/
+static char *version =
+	"de620.c: $Revision: 1.30 $,  Bjorn Ekwall <bj0rn@blox.se>\n";
+
+/***********************************************************************
+ *
+ * "Tuning" section.
+ *
+ * Compile-time options: (see below for descriptions)
+ * -DDE620_IO=0x378	(lpt1)
+ * -DDE620_IRQ=7	(lpt1)
+ * -DDE602_DEBUG=...
+ * -DSHUTDOWN_WHEN_LOST
+ * -DCOUNT_LOOPS
+ * -DLOWSPEED
+ * -DREAD_DELAY
+ * -DWRITE_DELAY
+ */
+
+/*
+ * If the adapter has problems with high speeds, enable this #define
+ * otherwise full printerport speed will be attempted.
+ *
+ * You can tune the READ_DELAY/WRITE_DELAY below if you enable LOWSPEED
+ *
+#define LOWSPEED
+ */
+
+#ifndef READ_DELAY
+#define READ_DELAY 100	/* adapter internal read delay in 100ns units */
+#endif
+
+#ifndef WRITE_DELAY
+#define WRITE_DELAY 100	/* adapter internal write delay in 100ns units */
+#endif
+
+/*
+ * Enable this #define if you want the adapter to do a "ifconfig down" on
+ * itself when we have detected that something is possibly wrong with it.
+ * The default behaviour is to retry with "adapter_init()" until success.
+ * This should be used for debugging purposes only.
+ *
+#define SHUTDOWN_WHEN_LOST
+ */
+
+/*
+ * Enable debugging by "-DDE620_DEBUG=3" when compiling,
+ * OR in "./CONFIG"
+ * OR by enabling the following #define
+ *
+ * use 0 for production, 1 for verification, >2 for debug
+ *
+#define DE620_DEBUG 3
+ */
+
+#ifdef LOWSPEED
+/*
+ * Enable this #define if you want to see debugging output that show how long
+ * we have to wait before the DE-620 is ready for the next read/write/command.
+ *
+#define COUNT_LOOPS
+ */
+#endif
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <netinet/in.h>
+#include <linux/ptrace.h>
+#include <asm/system.h>
+#include <errno.h>
+
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/module.h>
+#include "../../tools/version.h"
+
+/* Constant definitions for the DE-620 registers, commands and bits */
+#include "de620.h"
+
+#define netstats enet_statistics
+typedef unsigned char byte;
+
+/*******************************************************
+ *                                                     *
+ * Definition of D-Link DE-620 Ethernet Pocket adapter *
+ * See also "de620.h"                                  *
+ *                                                     *
+ *******************************************************/
+#ifndef DE620_IO /* Compile-time configurable */
+#define DE620_IO 0x378
+#endif
+
+#ifndef DE620_IRQ /* Compile-time configurable */
+#define DE620_IRQ	7
+#endif
+
+#define DATA_PORT	(DE620_IO)
+#define STATUS_PORT	(DE620_IO + 1)
+#define COMMAND_PORT	(DE620_IO + 2)
+
+#define RUNT 60		/* Too small Ethernet packet */
+#define GIANT 1514	/* largest legal size packet, no fcs */
+
+#ifdef DE620_DEBUG /* Compile-time configurable */
+#define PRINTK(x) if (de620_debug >= 2) printk x
+#else
+#define DE620_DEBUG 0
+#define PRINTK(x) /**/
+#endif
+
+/***********************************************
+ *                                             *
+ * Index to functions, as function prototypes. *
+ *                                             *
+ ***********************************************/
+
+/*
+ * Routines used internally. (See also "convenience macros.. below")
+ */
+
+/* Put in the device structure. */
+static int	de620_open(struct device *);
+static int	de620_close(struct device *);
+static struct netstats *get_stats(struct device *);
+static void	de620_set_multicast_list(struct device *, int, void *);
+static int	de620_start_xmit(struct sk_buff *, struct device *);
+
+/* Dispatch from interrupts. */
+static void	de620_interrupt(int);
+static int	de620_rx_intr(struct device *);
+
+/* Initialization */
+static int	adapter_init(struct device *);
+int		de620_probe(struct device *);
+static int	read_eeprom(void);
+
+
+/*
+ * D-Link driver variables:
+ */
+#define SCR_DEF NIBBLEMODE |INTON | SLEEP | AUTOTX
+#define	TCR_DEF RXPB			/* not used: | TXSUCINT | T16INT */
+#define DE620_RX_START_PAGE 12		/* 12 pages (=3k) reserved for tx */
+#define DEF_NIC_CMD IRQEN | ICEN | DS1
+
+extern struct device *irq2dev_map[16];
+unsigned int de620_debug = DE620_DEBUG;
+
+static volatile byte	NIC_Cmd;
+static volatile byte	next_rx_page;
+static byte		first_rx_page;
+static byte		last_rx_page;
+static byte		EIPRegister;
+
+static struct nic {
+	byte	NodeID[6];
+	byte	RAM_Size;
+	byte	Model;
+	byte	Media;
+	byte	SCR;
+} nic_data;
+
+/**********************************************************
+ *                                                        *
+ * Convenience macros/functions for D-Link DE-620 adapter *
+ *                                                        *
+ **********************************************************/
+#define de620_tx_buffs() (inb(STATUS_PORT) & (TXBF0 | TXBF1))
+#define de620_flip_ds() NIC_Cmd ^= DS0 | DS1; outb(NIC_Cmd, COMMAND_PORT);
+
+/* Check for ready-status, and return a nibble (high 4 bits) for data input */
+#ifdef COUNT_LOOPS
+static int tot_cnt;
+#endif
+static inline byte
+de620_ready(void)
+{
+	byte value;
+	register short int cnt = 0;
+
+	while ((((value = inb(STATUS_PORT)) & READY) == 0) && (cnt <= 1000))
+		++cnt;
+
+#ifdef COUNT_LOOPS
+	tot_cnt += cnt;
+#endif
+	return value & 0xf0; /* nibble */
+}
+
+static inline void
+de620_send_command(byte cmd)
+{
+	de620_ready();
+	if (cmd == W_DUMMY)
+		outb(NIC_Cmd, COMMAND_PORT);
+
+	outb(cmd, DATA_PORT);
+
+	outb(NIC_Cmd ^ CS0, COMMAND_PORT);
+	de620_ready();
+	outb(NIC_Cmd, COMMAND_PORT);
+}
+
+static inline void
+de620_put_byte(byte value)
+{
+	/* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
+	de620_ready();
+	outb(value, DATA_PORT);
+	de620_flip_ds();
+}
+
+static inline byte
+de620_read_byte(void)
+{
+	byte value;
+
+	/* The de620_ready() makes 7 loops, on the average, on a DX2/66 */
+	value = de620_ready(); /* High nibble */
+	de620_flip_ds();
+	value |= de620_ready() >> 4; /* Low nibble */
+	return value;
+}
+
+static inline void
+de620_write_block(byte *buffer, int count)
+{
+#ifndef LOWSPEED
+	byte uflip = NIC_Cmd ^ (DS0 | DS1);
+	byte dflip = NIC_Cmd;
+#else /* LOWSPEED */
+#ifdef COUNT_LOOPS
+	int bytes = count;
+#endif /* COUNT_LOOPS */
+#endif /* LOWSPEED */
+
+#ifdef LOWSPEED
+#ifdef COUNT_LOOPS
+	tot_cnt = 0;
+#endif /* COUNT_LOOPS */
+	/* No further optimization useful, the limit is in the adapter. */
+	for ( ; count > 0; --count, ++buffer) {
+		de620_put_byte(*buffer);
+	}
+	de620_send_command(W_DUMMY);
+#ifdef COUNT_LOOPS
+	/* trial debug output: loops per byte in de620_ready() */
+	printk("WRITE(%d)\n", tot_cnt/((bytes?bytes:1)));
+#endif /* COUNT_LOOPS */
+#else /* not LOWSPEED */
+	for ( ; count > 0; count -=2) {
+		outb(*buffer++, DATA_PORT);
+		outb(uflip, COMMAND_PORT);
+		outb(*buffer++, DATA_PORT);
+		outb(dflip, COMMAND_PORT);
+	}
+	de620_send_command(W_DUMMY);
+#endif /* LOWSPEED */
+}
+
+static inline void
+de620_read_block(byte *data, int count)
+{
+#ifndef LOWSPEED
+	byte value;
+	byte uflip = NIC_Cmd ^ (DS0 | DS1);
+	byte dflip = NIC_Cmd;
+#else /* LOWSPEED */
+#ifdef COUNT_LOOPS
+	int bytes = count;
+
+	tot_cnt = 0;
+#endif /* COUNT_LOOPS */
+#endif /* LOWSPEED */
+
+#ifdef LOWSPEED
+	/* No further optimization useful, the limit is in the adapter. */
+	while (count-- > 0) {
+		*data++ = de620_read_byte();
+		de620_flip_ds();
+	}
+#ifdef COUNT_LOOPS
+	/* trial debug output: loops per byte in de620_ready() */
+	printk("READ(%d)\n", tot_cnt/(2*(bytes?bytes:1)));
+#endif /* COUNT_LOOPS */
+#else /* not LOWSPEED */
+	while (count-- > 0) {
+		value = inb(STATUS_PORT) & 0xf0; /* High nibble */
+		outb(uflip, COMMAND_PORT);
+		*data++ = value | inb(STATUS_PORT) >> 4; /* Low nibble */
+		outb(dflip , COMMAND_PORT);
+	}
+#endif /* LOWSPEED */
+}
+
+static inline void
+de620_set_delay(void)
+{
+	de620_ready();
+	outb(W_DFR, DATA_PORT);
+	outb(NIC_Cmd ^ CS0, COMMAND_PORT);
+
+	de620_ready();
+#ifdef LOWSPEED
+	outb(WRITE_DELAY, DATA_PORT);
+#else
+	outb(0, DATA_PORT);
+#endif
+	de620_flip_ds();
+
+	de620_ready();
+#ifdef LOWSPEED
+	outb(READ_DELAY, DATA_PORT);
+#else
+	outb(0, DATA_PORT);
+#endif
+	de620_flip_ds();
+}
+
+static inline void
+de620_set_register(byte reg, byte value)
+{
+	de620_ready();
+	outb(reg, DATA_PORT);
+	outb(NIC_Cmd ^ CS0, COMMAND_PORT);
+
+	de620_put_byte(value);
+}
+
+static inline byte
+de620_get_register(byte reg)
+{
+	byte value;
+
+	de620_send_command(reg);
+	value = de620_read_byte();
+	de620_send_command(W_DUMMY);
+
+	return value;
+}
+
+/*********************************************************************
+ *
+ * Open/initialize the board.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is a non-reboot way to recover if something goes wrong.
+ *
+ */
+static int
+de620_open(struct device *dev)
+{
+	if (request_irq(DE620_IRQ, de620_interrupt)) {
+		printk ("%s: unable to get IRQ %d\n", dev->name, DE620_IRQ);
+		return 1;
+	}
+	irq2dev_map[DE620_IRQ] = dev;
+
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+	if (adapter_init(dev)) {
+		return 1;
+	}
+	dev->start = 1;
+	return 0;
+}
+
+/************************************************
+ *
+ * The inverse routine to de620_open().
+ *
+ */
+static int
+de620_close(struct device *dev)
+{
+	/* disable recv */
+	de620_set_register(W_TCR, RXOFF);
+
+	free_irq(DE620_IRQ);
+	irq2dev_map[DE620_IRQ] = NULL;
+
+	dev->start = 0;
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return 0;
+}
+
+/*********************************************
+ *
+ * Return current statistics
+ *
+ */
+static struct netstats *
+get_stats(struct device *dev)
+{
+	return (struct netstats *)(dev->priv);
+}
+
+/*********************************************
+ *
+ * Set or clear the multicast filter for this adaptor.
+ * (no real multicast implemented for the DE-620, but she can be promiscuous...)
+ *
+ * num_addrs == -1	Promiscuous mode, receive all packets
+ * num_addrs == 0	Normal mode, clear multicast list
+ * num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+ *			best-effort filtering.
+ */
+static void
+de620_set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+	if (num_addrs) { /* Enable promiscuous mode */
+		de620_set_register(W_TCR, (TCR_DEF & ~RXPBM) | RXALL);
+	}
+	else { /* Disable promiscuous mode, use normal mode */
+		de620_set_register(W_TCR, TCR_DEF);
+	}
+}
+
+/*******************************************************
+ *
+ * Copy a buffer to the adapter transmit page memory.
+ * Start sending.
+ */
+static int
+de620_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	unsigned long flags;
+	int len;
+	int tickssofar;
+	byte *buffer = skb->data;
+	byte using_txbuf;
+
+	/*
+	 * If some higher layer thinks we've missed a
+	 * tx-done interrupt we are passed NULL.
+	 * Caution: dev_tint() handles the cli()/sti() itself.
+	 */
+
+	if (skb == NULL) {
+		dev_tint(dev);
+		return 0;
+	}
+
+	using_txbuf = de620_tx_buffs(); /* Peek at the adapter */
+	dev->tbusy = (using_txbuf == (TXBF0 | TXBF1)); /* Boolean! */
+
+	if (dev->tbusy) {	/* Do timeouts, to avoid hangs. */
+		tickssofar = jiffies - dev->trans_start;
+
+		if (tickssofar < 5)
+			return 1;
+
+		/* else */
+		printk("%s: transmit timed out (%d), %s?\n",
+			dev->name,
+			tickssofar,
+			"network cable problem"
+			);
+		/* Restart the adapter. */
+		if (adapter_init(dev)) /* maybe close it */
+			return 1;
+	}
+
+	if ((len = skb->len) < RUNT)
+		len = RUNT;
+	if (len & 1) /* send an even number of bytes */
+		++len;
+
+	/* Start real output */
+	save_flags(flags);
+	cli();
+
+	PRINTK(("de620_start_xmit: len=%d, bufs 0x%02x\n",
+		(int)skb->len, using_txbuf));
+
+	/* select a free tx buffer. if there is one... */
+	switch (using_txbuf) {
+	default: /* both are free: use TXBF0 */
+	case TXBF1: /* use TXBF0 */
+		de620_send_command(W_CR | RW0);
+		using_txbuf |= TXBF0;
+		break;
+
+	case TXBF0: /* use TXBF1 */
+		de620_send_command(W_CR | RW1);
+		using_txbuf |= TXBF1;
+		break;
+
+	case (TXBF0 | TXBF1): /* NONE!!! */
+		printk("de620: Ouch! No tx-buffer available!\n");
+		restore_flags(flags);
+		return 1;
+		break;
+	}
+	de620_write_block(buffer, len);
+
+	dev->trans_start = jiffies;
+	dev->tbusy = (using_txbuf == (TXBF0 | TXBF1)); /* Boolean! */
+
+	((struct netstats *)(dev->priv))->tx_packets++;
+	
+	restore_flags(flags); /* interrupts maybe back on */
+	
+	dev_kfree_skb (skb, FREE_WRITE);
+
+	return 0;
+}
+
+/*****************************************************
+ *
+ * Handle the network interface interrupts.
+ *
+ */
+static void
+de620_interrupt(int reg_ptr)
+{
+	int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+	struct device *dev = irq2dev_map[irq];
+	byte irq_status;
+	int bogus_count = 0;
+	int again = 0;
+
+	/* This might be deleted now, no crummy drivers present :-) Or..? */
+	if ((dev == NULL) || (DE620_IRQ != irq)) {
+		printk("%s: bogus interrupt %d\n", dev?dev->name:"DE620", irq);
+		return;
+	}
+
+	cli();
+	dev->interrupt = 1;
+
+	/* Read the status register (_not_ the status port) */
+	irq_status = de620_get_register(R_STS);
+
+	PRINTK(("de620_interrupt (%2.2X)\n", irq_status));
+
+	if (irq_status & RXGOOD) {
+		do {
+			again = de620_rx_intr(dev);
+			PRINTK(("again=%d\n", again));
+		}
+		while (again && (++bogus_count < 100));
+	}
+
+	dev->tbusy = (de620_tx_buffs() == (TXBF0 | TXBF1)); /* Boolean! */
+
+	dev->interrupt = 0;
+	sti();
+	return;
+}
+
+/**************************************
+ *
+ * Get a packet from the adapter
+ *
+ * Send it "upstairs"
+ *
+ */
+static int
+de620_rx_intr(struct device *dev)
+{
+	struct header_buf {
+		byte		status;
+		byte		Rx_NextPage;
+		unsigned short	Rx_ByteCount;
+	} header_buf;
+	struct sk_buff *skb;
+	int size;
+	byte *buffer;
+	byte pagelink;
+	byte curr_page;
+
+	PRINTK(("de620_rx_intr: next_rx_page = %d\n", next_rx_page));
+
+	/* Tell the adapter that we are going to read data, and from where */
+	de620_send_command(W_CR | RRN);
+	de620_set_register(W_RSA1, next_rx_page);
+	de620_set_register(W_RSA0, 0);
+
+	/* Deep breath, and away we goooooo */
+	de620_read_block((byte *)&header_buf, sizeof(struct header_buf));
+	PRINTK(("page status=0x%02x, nextpage=%d, packetsize=%d\n",
+	header_buf.status, header_buf.Rx_NextPage, header_buf.Rx_ByteCount));
+
+	/* Plausible page header? */
+	pagelink = header_buf.Rx_NextPage;
+	if ((pagelink < first_rx_page) || (last_rx_page < pagelink)) {
+		/* Ouch... Forget it! Skip all and start afresh... */
+		printk("%s: Ring overrun? Restoring...\n", dev->name);
+		/* You win some, you loose some. And sometimes plenty... */
+		adapter_init(dev);
+		((struct netstats *)(dev->priv))->rx_over_errors++;
+		return 0;
+	}
+
+	/* OK, this look good, so far. Let's see if it's consistent... */
+	/* Let's compute the start of the next packet, based on where we are */
+	pagelink = next_rx_page +
+		((header_buf.Rx_ByteCount + (4 - 1 + 0x100)) >> 8);
+
+	/* Are we going to wrap around the page counter? */
+	if (pagelink > last_rx_page)
+		pagelink -= (last_rx_page - first_rx_page + 1);
+
+	/* Is the _computed_ next page number equal to what the adapter says? */
+	if (pagelink != header_buf.Rx_NextPage) {
+		/* Naah, we'll skip this packet. Probably bogus data as well */
+		printk("%s: Page link out of sync! Restoring...\n", dev->name);
+		next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
+		de620_send_command(W_DUMMY);
+		de620_set_register(W_NPRF, next_rx_page);
+		((struct netstats *)(dev->priv))->rx_over_errors++;
+		return 0;
+	}
+	next_rx_page = pagelink;
+
+	size = header_buf.Rx_ByteCount - 4;
+	if ((size < RUNT) || (GIANT < size)) {
+		printk("%s: Illegal packet size: %d!\n", dev->name, size);
+	}
+	else { /* Good packet? */
+		skb = alloc_skb(size, GFP_ATOMIC);
+		if (skb == NULL) { /* Yeah, but no place to put it... */
+			printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+				dev->name, size);
+			((struct netstats *)(dev->priv))->rx_dropped++;
+		}
+		else { /* Yep! Go get it! */
+			skb->len = size; skb->dev = dev; skb->free = 1;
+			/* skb->data points to the start of sk_buff data area */
+			buffer = skb->data;
+			/* copy the packet into the buffer */
+			de620_read_block(buffer, size);
+			PRINTK(("Read %d bytes\n", size));
+			netif_rx(skb); /* deliver it "upstairs" */
+			/* count all receives */
+			((struct netstats *)(dev->priv))->rx_packets++;
+		}
+	}
+
+	/* Let's peek ahead to see if we have read the last current packet */
+	/* NOTE! We're _not_ checking the 'EMPTY'-flag! This seems better... */
+	curr_page = de620_get_register(R_CPR);
+	de620_set_register(W_NPRF, next_rx_page);
+	PRINTK(("next_rx_page=%d CPR=%d\n", next_rx_page, curr_page));
+
+	return (next_rx_page != curr_page); /* That was slightly tricky... */
+}
+
+/*********************************************
+ *
+ * Reset the adapter to a known state
+ *
+ */
+static int
+adapter_init(struct device *dev)
+{
+	int i;
+	static int was_down = 0;
+
+	if ((nic_data.Model == 3) || (nic_data.Model == 0)) { /* CT */
+		EIPRegister = NCTL0;
+		if (nic_data.Media != 1)
+			EIPRegister |= NIS0;	/* not BNC */
+	}
+	else if (nic_data.Model == 2) { /* UTP */
+		EIPRegister = NCTL0 | NIS0;
+	}
+
+	de620_send_command(W_CR | RNOP | CLEAR);
+	de620_send_command(W_CR | RNOP);
+
+	de620_set_register(W_SCR, SCR_DEF);
+	/* disable recv to wait init */
+	de620_set_register(W_TCR, RXOFF);
+
+	/* Set the node ID in the adapter */
+	for (i = 0; i < 6; ++i) { /* W_PARn = 0xaa + n */
+		de620_set_register(W_PAR0 + i, dev->dev_addr[i]);
+	}
+
+	de620_set_register(W_EIP, EIPRegister);
+
+	next_rx_page = first_rx_page = DE620_RX_START_PAGE;
+	if (nic_data.RAM_Size)
+		last_rx_page = nic_data.RAM_Size - 1;
+	else /* 64k RAM */
+		last_rx_page = 255;
+
+	de620_set_register(W_SPR, first_rx_page); /* Start Page Register */
+	de620_set_register(W_EPR, last_rx_page);  /* End Page Register */
+	de620_set_register(W_CPR, first_rx_page); /* Current Page Register */
+	de620_send_command(W_NPR | first_rx_page); /* Next Page Register */
+	de620_send_command(W_DUMMY);
+	de620_set_delay();
+
+	/* Final sanity check: Anybody out there? */
+	/* Let's hope some bits from the statusregister make a good check */
+#define CHECK_MASK (  0 | TXSUC |  T16  |  0  | RXCRC | RXSHORT |  0  |  0  )
+#define CHECK_OK   (  0 |   0   |  0    |  0  |   0   |   0     |  0  |  0  )
+        /* success:   X     0      0       X      0       0        X     X  */
+        /* ignore:   EEDI                RXGOOD                   COLS  LNKS*/
+
+	if (((i = de620_get_register(R_STS)) & CHECK_MASK) != CHECK_OK) {
+		printk("Something has happened to the DE-620!  Please check it"
+#ifdef SHUTDOWN_WHEN_LOST
+			" and do a new ifconfig"
+#endif
+			"! (%02x)\n", i);
+#ifdef SHUTDOWN_WHEN_LOST
+		/* Goodbye, cruel world... */
+		dev->flags &= ~IFF_UP;
+		de620_close(dev);
+#endif
+		was_down = 1;
+		return 1; /* failed */
+	}
+	if (was_down) {
+		printk("Thanks, I feel much better now!\n");
+		was_down = 0;
+	}
+
+	/* All OK, go ahead... */
+	de620_set_register(W_TCR, TCR_DEF);
+
+	return 0; /* all ok */
+}
+
+/******************************************************************************
+ *
+ * Only start-up code below
+ *
+ */
+/****************************************
+ *
+ * Check if there is a DE-620 connected
+ */
+int
+de620_probe(struct device *dev)
+{
+	static struct netstats de620_netstats;
+	int i;
+	byte checkbyte = 0xa5;
+
+	if (de620_debug)
+		printk(version);
+
+	printk("D-Link DE-620 pocket adapter");
+
+	/* Initially, configure basic nibble mode, so we can read the EEPROM */
+	NIC_Cmd = DEF_NIC_CMD;
+	de620_set_register(W_EIP, EIPRegister);
+
+	/* Anybody out there? */
+	de620_set_register(W_CPR, checkbyte);
+	checkbyte = de620_get_register(R_CPR);
+
+	if ((checkbyte != 0xa5) || (read_eeprom() != 0)) {
+		printk(" not identified in the printer port\n");
+		return ENODEV;
+	}
+
+	/* else, got it! */
+	printk(", Ethernet Address: %2.2X",
+		dev->dev_addr[0] = nic_data.NodeID[0]);
+	for (i = 1; i < ETH_ALEN; i++) {
+		printk(":%2.2X", dev->dev_addr[i] = nic_data.NodeID[i]);
+		dev->broadcast[i] = 0xff;
+	}
+
+	printk(" (%dk RAM,",
+		(nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
+
+	if (nic_data.Media == 1)
+		printk(" BNC)\n");
+	else
+		printk(" UTP)\n");
+
+	/* Initialize the device structure. */
+	/*dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);*/
+	dev->priv = &de620_netstats;
+
+	memset(dev->priv, 0, sizeof(struct netstats));
+	dev->get_stats = get_stats;
+	dev->open = de620_open;
+	dev->stop = de620_close;
+	dev->hard_start_xmit = &de620_start_xmit;
+	dev->set_multicast_list = &de620_set_multicast_list;
+	dev->base_addr = DE620_IO;
+	dev->irq = DE620_IRQ;
+
+	ether_setup(dev);
+	
+	/* dump eeprom */
+	if (de620_debug) {
+		printk("\nEEPROM contents:\n");
+		printk("RAM_Size = 0x%02X\n", nic_data.RAM_Size);
+		printk("NodeID = %02X:%02X:%02X:%02X:%02X:%02X\n",
+			nic_data.NodeID[0], nic_data.NodeID[1],
+			nic_data.NodeID[2], nic_data.NodeID[3],
+			nic_data.NodeID[4], nic_data.NodeID[5]);
+		printk("Model = %d\n", nic_data.Model);
+		printk("Media = %d\n", nic_data.Media);
+		printk("SCR = 0x%02x\n", nic_data.SCR);
+	}
+
+	return 0;
+}
+
+/**********************************
+ *
+ * Read info from on-board EEPROM
+ *
+ * Note: Bitwise serial I/O to/from the EEPROM vi the status _register_!
+ */
+#define sendit(data) de620_set_register(W_EIP, data | EIPRegister);
+
+static unsigned short
+ReadAWord(int from)
+{
+	unsigned short data;
+	int nbits;
+
+	/* cs   [__~~] SET SEND STATE */
+	/* di   [____]                */
+	/* sck  [_~~_]                */
+	sendit(0); sendit(1); sendit(5); sendit(4);
+
+	/* Send the 9-bit address from where we want to read the 16-bit word */
+	for (nbits = 9; nbits > 0; --nbits, from <<= 1) {
+		if (from & 0x0100) { /* bit set? */
+			/* cs    [~~~~] SEND 1 */
+			/* di    [~~~~]        */
+			/* sck   [_~~_]        */
+			sendit(6); sendit(7); sendit(7); sendit(6);
+		}
+		else {
+			/* cs    [~~~~] SEND 0 */
+			/* di    [____]        */
+			/* sck   [_~~_]        */
+			sendit(4); sendit(5); sendit(5); sendit(4);
+		}
+	}
+
+	/* Shift in the 16-bit word. The bits appear serially in EEDI (=0x80) */
+	for (data = 0, nbits = 16; nbits > 0; --nbits) {
+		/* cs    [~~~~] SEND 0 */
+		/* di    [____]        */
+		/* sck   [_~~_]        */
+		sendit(4); sendit(5); sendit(5); sendit(4);
+		data = (data << 1) | ((de620_get_register(R_STS) & EEDI) >> 7);
+	}
+	/* cs    [____] RESET SEND STATE */
+	/* di    [____]                  */
+	/* sck   [_~~_]                  */
+	sendit(0); sendit(1); sendit(1); sendit(0);
+
+	return data;
+}
+
+static int
+read_eeprom(void)
+{
+	unsigned short wrd;
+
+	/* D-Link Ethernet adresses are in the series  00:80:c8:7X:XX:XX:XX */
+	wrd = ReadAWord(0x1aa);	/* bytes 0 + 1 of NodeID */
+	if (wrd != htons(0x0080)) /* Valid D-Link ether sequence? */
+		return -1; /* Nope, not a DE-620 */
+	nic_data.NodeID[0] = wrd & 0xff;
+	nic_data.NodeID[1] = wrd >> 8;
+
+	wrd = ReadAWord(0x1ab);	/* bytes 2 + 3 of NodeID */
+	if ((wrd & 0xff) != 0xc8) /* Valid D-Link ether sequence? */
+		return -1; /* Nope, not a DE-620 */
+	nic_data.NodeID[2] = wrd & 0xff;
+	nic_data.NodeID[3] = wrd >> 8;
+
+	wrd = ReadAWord(0x1ac);	/* bytes 4 + 5 of NodeID */
+	nic_data.NodeID[4] = wrd & 0xff;
+	nic_data.NodeID[5] = wrd >> 8;
+
+	wrd = ReadAWord(0x1ad);	/* RAM size in pages (256 bytes). 0 = 64k */
+	nic_data.RAM_Size = (wrd >> 8);
+
+	wrd = ReadAWord(0x1ae);	/* hardware model (CT = 3) */
+	nic_data.Model = (wrd & 0xff);
+
+	wrd = ReadAWord(0x1af); /* media (indicates BNC/UTP) */
+	nic_data.Media = (wrd & 0xff);
+
+	wrd = ReadAWord(0x1a8); /* System Configuration Register */
+	nic_data.SCR = (wrd >> 8);
+
+	return 0; /* no errors */
+}
+
+/******************************************************************************
+ *
+ * Loadable module skeleton
+ *
+ */
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static char nullname[8];
+static struct device de620_dev = {
+	nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, de620_probe };
+
+int
+init_module(void)
+{
+	if (register_netdev(&de620_dev) != 0)
+		return -EIO;
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+	if (MOD_IN_USE)
+		printk("de620: device busy, remove delayed\n");
+	else
+		unregister_netdev(&de620_dev);
+}
+#endif /* MODULE */
+
+/*
+ * (add '-DMODULE' when compiling as loadable module)
+ *
+ * compile-command:
+ *	gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O2 \
+ *	 -fomit-frame-pointer -m486 \
+ *	-I/usr/src/linux/include -I../../net/inet -c de620.c
+ */
diff -u --recursive --new-file v1.1.20/linux/drivers/net/de620.h linux/drivers/net/de620.h
--- v1.1.20/linux/drivers/net/de620.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/de620.h	Tue Jun 21 13:23:53 1994
@@ -0,0 +1,117 @@
+/*********************************************************
+ *                                                       *
+ * Definition of D-Link DE-620 Ethernet Pocket adapter   *
+ *                                                       *
+ *********************************************************/
+
+/* DE-620's CMD port Command */
+#define CS0		0x08	/* 1->0 command strobe */
+#define ICEN		0x04	/* 0=enable DL3520 host interface */
+#define DS0		0x02	/* 1->0 data strobe 0 */
+#define DS1		0x01	/* 1->0 data strobe 1 */
+
+#define WDIR		0x20	/* general 0=read  1=write */
+#define RDIR		0x00	/*  (not 100% confirm ) */
+#define PS2WDIR		0x00	/* ps/2 mode 1=read, 0=write */
+#define PS2RDIR		0x20
+
+#define IRQEN		0x10	/* 1 = enable printer IRQ line */
+#define SELECTIN	0x08	/* 1 = select printer */
+#define INITP		0x04	/* 0 = initial printer */
+#define AUTOFEED	0x02	/* 1 = printer auto form feed */
+#define STROBE		0x01	/* 0->1 data strobe */
+
+#define RESET		0x08
+#define NIS0		0x20	/* 0 = BNC, 1 = UTP */
+#define NCTL0		0x10
+
+/* DE-620 DIC Command */
+#define W_DUMMY		0x00	/* DIC reserved command */
+#define W_CR		0x20	/* DIC write command register */
+#define W_NPR		0x40	/* DIC write Nect Page Register */
+#define W_TBR		0x60	/* DIC write Tx Byte Count 1 reg */
+#define W_RSA		0x80	/* DIC write Remote Start Addr 1 */
+
+/* DE-620's STAT port bits 7-4 */
+#define EMPTY		0x80	/* 1 = receive buffer empty */
+#define INTLEVEL	0x40	/* 1 = interrupt level is high */
+#define TXBF1		0x20	/* 1 = transmit buffer 1 is in use */
+#define TXBF0		0x10	/* 1 = transmit buffer 0 is in use */
+#define READY		0x08	/* 1 = h/w ready to accept cmd/data */
+
+/* IDC 1 Command */
+#define	W_RSA1		0xa0	/* write remote start address 1 */
+#define	W_RSA0		0xa1	/* write remote start address 0 */
+#define	W_NPRF		0xa2	/* write next page register NPR15-NPR8 */
+#define	W_DFR		0xa3	/* write delay factor register */
+#define	W_CPR		0xa4	/* write current page register */
+#define	W_SPR		0xa5	/* write start page register */
+#define	W_EPR		0xa6	/* write end page register */
+#define	W_SCR		0xa7	/* write system configuration register */
+#define	W_TCR		0xa8	/* write Transceiver Configuration reg */
+#define	W_EIP		0xa9	/* write EEPM Interface port */
+#define	W_PAR0		0xaa	/* write physical address registr 0 */
+#define	W_PAR1		0xab	/* write physical address registr 1 */
+#define	W_PAR2		0xac	/* write physical address registr 2 */
+#define	W_PAR3		0xad	/* write physical address registr 3 */
+#define	W_PAR4		0xae	/* write physical address registr 4 */
+#define	W_PAR5		0xaf	/* write physical address registr 5 */
+
+/* IDC 2 Command */
+#define	R_STS		0xc0	/* read status register */
+#define	R_CPR		0xc1	/* read current page register */
+#define	R_BPR		0xc2	/* read boundary page register */
+#define	R_TDR		0xc3	/* read time domain reflectometry reg */
+
+/* STATUS Register */
+#define EEDI		0x80	/* EEPM DO pin */
+#define TXSUC		0x40	/* tx success */
+#define T16		0x20	/* tx fail 16 times */
+#define TS1		0x40	/* 0=Tx success, 1=T16 */
+#define TS0		0x20	/* 0=Tx success, 1=T16 */
+#define RXGOOD		0x10	/* rx a good packet */
+#define RXCRC		0x08	/* rx a CRC error packet */
+#define RXSHORT		0x04	/* rx a short packet */
+#define COLS		0x02	/* coaxial collision status */
+#define LNKS		0x01	/* UTP link status */
+
+/* Command Register */
+#define CLEAR		0x10	/* reset part of hardware */
+#define NOPER		0x08	/* No Operation */
+#define RNOP		0x08
+#define RRA		0x06	/* After RR then auto-advance NPR & BPR(=NPR-1) */
+#define RRN		0x04	/* Normal Remote Read mode */
+#define RW1		0x02	/* Remote Write tx buffer 1  ( page 6 - 11 ) */
+#define RW0		0x00	/* Remote Write tx buffer 0  ( page 0 - 5 ) */
+#define TXEN		0x01	/* 0->1 tx enable */
+
+/* System Configuration Register */
+#define TESTON		0x80	/* test host data transfer reliability */
+#define SLEEP		0x40	/* sleep mode */
+#if 0
+#define FASTMODE	0x04	/* fast mode for intel 82360SL fast mode */
+#define BYTEMODE	0x02	/* byte mode */
+#else
+#define FASTMODE	0x20	/* fast mode for intel 82360SL fast mode */
+#define BYTEMODE	0x10	/* byte mode */
+#endif
+#define NIBBLEMODE	0x00	/* nibble mode */
+#define IRQINV		0x08	/* turn off IRQ line inverter */
+#define IRQNML		0x00	/* turn on IRQ line inverter */
+#define INTON		0x04
+#define AUTOFFSET	0x02	/* auto shift address to TPR+12 */
+#define AUTOTX		0x01	/* auto tx when leave RW mode */
+
+/* Tranceiver Configuration Register */
+#define JABBER		0x80	/* generate jabber condition */
+#define TXSUCINT	0x40	/* enable tx success interrupt */
+#define T16INT		0x20	/* enable T16 interrupt */
+#define RXERRPKT	0x10	/* accept CRC error or short packet */
+#define EXTERNALB2	0x0C	/* external loopback 2 */
+#define EXTERNALB1	0x08	/* external loopback 1 */
+#define INTERNALB	0x04	/* internal loopback */
+#define NMLOPERATE	0x00	/* normal operation */
+#define RXPBM		0x03	/* rx physical, broadcast, multicast */
+#define RXPB		0x02	/* rx physical, broadcast */
+#define RXALL		0x01	/* rx all packet */
+#define RXOFF		0x00	/* rx disable */
diff -u --recursive --new-file v1.1.20/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v1.1.20/linux/drivers/net/plip.c	Tue Jun 21 14:16:22 1994
+++ linux/drivers/net/plip.c	Tue Jun 21 13:23:52 1994
@@ -172,6 +172,7 @@
     struct plip_local rcv_data;
     unsigned long  trigger_us;
     unsigned long  nibble_us;
+    unsigned long  unit_us;
 };
 
 /* Routines used internally. */
@@ -948,10 +949,12 @@
 		case PLIP_GET_TIMEOUT:
 			pc->trigger=nl->trigger_us;
 			pc->nibble=nl->nibble_us;
+			pc->unit=nl->unit_us;
 			break;
 		case PLIP_SET_TIMEOUT:
 			nl->trigger_us=pc->trigger;
 			nl->nibble_us=pc->nibble;
+			nl->unit_us=pc->unit;
 			break;
 		default:
 			return -EOPNOTSUPP;
diff -u --recursive --new-file v1.1.20/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v1.1.20/linux/drivers/net/ppp.c	Tue Jun 21 14:16:22 1994
+++ linux/drivers/net/ppp.c	Tue Jun 21 13:23:52 1994
@@ -711,12 +711,14 @@
 		return;
 	}
 
-	if (!ppp->xtail || (ppp->flags & SC_XMIT_BUSY))
+	if (!ppp->xtail)
 		return;
 
 	cli();
-	if (ppp->flags & SC_XMIT_BUSY)
+	if (ppp->flags & SC_XMIT_BUSY) {
+		sti();
 		return;
+	}
 	ppp->flags |= SC_XMIT_BUSY;
 	sti();
 	
@@ -746,7 +748,7 @@
 
 /* stuff a single character into the receive buffer */
 
-inline void
+static inline void
 ppp_enqueue(struct ppp *ppp, unsigned char c)
 {
   unsigned long flags;
@@ -1966,8 +1968,7 @@
 
 static char hex[] = "0123456789ABCDEF";
 
-inline void ppp_print_hex (register char *out, char *in, int count);
-inline void ppp_print_hex (register char *out, char *in, int count)
+static inline void ppp_print_hex (register char *out, char *in, int count)
 {
   register unsigned char next_ch;
 
@@ -1981,8 +1982,7 @@
   }
 }
 
-inline void ppp_print_char (register char *out, char *in, int count);
-inline void ppp_print_char (register char *out, char *in, int count)
+static inline void ppp_print_char (register char *out, char *in, int count)
 {
   register unsigned char next_ch;
 
diff -u --recursive --new-file v1.1.20/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v1.1.20/linux/drivers/net/slip.c	Tue Jun 21 14:16:22 1994
+++ linux/drivers/net/slip.c	Tue Jun 21 13:31:25 1994
@@ -22,6 +22,7 @@
  *		Charles Hedrick :	CSLIP header length problem fix.
  *		Alan Cox	:	Corrected non-IP cases of the above.
  *		Alan Cox	:	Now uses hardware type as per FvK.
+ *		Alan Cox	:	Default to 192.168.0.0 (RFC 1597)
  *
  *
  *	FIXME:	This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without
@@ -400,12 +401,14 @@
 		return;
 	}
 
-	if (!sl->xtail || (sl->flags & SLF_XMIT_BUSY))
+	if (!sl->xtail)
 		return;
 
 	cli();
-	if (sl->flags & SLF_XMIT_BUSY)
+	if (sl->flags & SLF_XMIT_BUSY) {
+		sti();
 		return;
+	}
 	sl->flags |= SLF_XMIT_BUSY;
 	sti();
 	
@@ -596,7 +599,7 @@
   dev->flags|=IFF_UP;
   /* Needed because address '0' is special */
   if(dev->pa_addr==0)
-  	dev->pa_addr=ntohl(0xC0000001);
+  	dev->pa_addr=ntohl(0xC0A80001);
   return(0);
 }
 
diff -u --recursive --new-file v1.1.20/linux/include/linux/if_plip.h linux/include/linux/if_plip.h
--- v1.1.20/linux/include/linux/if_plip.h	Tue Jun 21 14:16:24 1994
+++ linux/include/linux/if_plip.h	Tue Jun 21 13:23:51 1994
@@ -20,6 +20,7 @@
 	unsigned short pcmd;
 	unsigned long  nibble;
 	unsigned long  trigger;
+	unsigned long  unit;
 };
 
 #define PLIP_GET_TIMEOUT	0x1
Only in v1.1.20/linux/include/linux: mktime.h
diff -u --recursive --new-file v1.1.20/linux/include/linux/mtio.h linux/include/linux/mtio.h
--- v1.1.20/linux/include/linux/mtio.h	Mon May 23 12:14:25 1994
+++ linux/include/linux/mtio.h	Tue Jun 21 13:50:19 1994
@@ -90,10 +90,29 @@
 #define MT_ISSCSI1		0x71	/* Generic ANSI SCSI-1 tape unit */
 #define MT_ISSCSI2		0x72	/* Generic ANSI SCSI-2 tape unit */
 
+/* QIC-40/QIC-80 ftape supported drives.
+ * 20bit vendor ID + 0x800000
+ */
+#define MT_ISFTAPE_UNKNOWN      0x800000
+#define MT_ISCMSDJ10_DJ20       0x800047
+#define MT_ISCMSDJ10_DJ20_NEW   0x8011c4
+#define MT_ISARCHIVE_5580I      0x800005
+#define MT_ISARCHIVE_XL9250I    0x80014a
+#define MT_ISARCHIVE_31250Q     0x800146
+#define MT_ISINSIGHT_80	        0x810005
+#define MT_ISCONNER_C250MQT     0x80014c
+#define MT_ISWANGTEK_2040F      0x8001c1
+#define MT_ISWANGTEK_2080F      0x8001c8
+#define MT_ISIOMEGA_250         0x808880
+#define MT_ISSUMMIT_SE150       0x800180
+#define MT_ISSUMMIT_SE250       0x800181
+#define MT_ISESCOM_IDTBU120E    0x800140
+
 struct mt_tape_info {
 	long t_type;		/* device type id (mt_type) */
 	char *t_name;		/* descriptive name */
 };
+
 #define MT_TAPE_INFO	{ \
 	{MT_ISUNKNOWN,		"Unknown type of tape device"}, \
 	{MT_ISQIC02,		"Generic QIC-02 tape streamer"}, \
@@ -108,6 +127,20 @@
 	{MT_ISEVEREX_FT40A,	"Everex FT40A, QIC-40"}, \
 	{MT_ISSCSI1,		"Generic SCSI-1 tape"}, \
 	{MT_ISSCSI2,		"Generic SCSI-2 tape"}, \
+	{MT_ISFTAPE_UNKNOWN,	"Unknown floppy interface tape drive"},\
+	{MT_ISCMSDJ10_DJ20,	"Colorado DJ-10/DJ-20"},\
+	{MT_ISCMSDJ10_DJ20_NEW, "Colorado DJ-10/DJ-20 (new)"},\
+	{MT_ISARCHIVE_5580I,	"Archive 5580i"},\
+        {MT_ISARCHIVE_XL9250I,  "Archive XL9250i [Conner/Escom]"},\
+	{MT_ISARCHIVE_31250Q,	"Escom/Archive 31250Q"},\
+        {MT_ISINSIGHT_80,	"Insight 80 Mb"},\
+        {MT_ISCONNER_C250MQT,   "Conner C250MQT"},\
+        {MT_ISWANGTEK_2040F,	"Wangtek 3040F"},\
+        {MT_ISWANGTEK_2080F,	"Wangtek 3080F"},\
+        {MT_ISIOMEGA_250,       "Iomega 250"},\
+        {MT_ISSUMMIT_SE150,	"Summit SE 150"},\
+        {MT_ISSUMMIT_SE250,	"Summit SE 250/Mountain FS8000"},\
+        {MT_ISESCOM_IDTBU120E,  "Identity IDTBU120E, Escom?"},\
 	{0, NULL} \
 }
 
diff -u --recursive --new-file v1.1.20/linux/include/linux/socket.h linux/include/linux/socket.h
--- v1.1.20/linux/include/linux/socket.h	Tue Jun 21 14:16:25 1994
+++ linux/include/linux/socket.h	Tue Jun 21 13:23:51 1994
@@ -36,6 +36,7 @@
 #define AF_MAX		8	/* For now.. */
 
 /* Protocol families, same as address families. */
+#define PF_UNSPEC	AF_UNSPEC
 #define PF_UNIX		AF_UNIX
 #define PF_INET		AF_INET
 #define PF_AX25		AF_AX25
diff -u --recursive --new-file v1.1.20/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.20/linux/kernel/ksyms.c	Tue Jun 21 14:16:26 1994
+++ linux/kernel/ksyms.c	Tue Jun 21 13:50:19 1994
@@ -10,7 +10,6 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
-#include <linux/binfmts.h>
 #include <linux/ptrace.h>
 #include <linux/sys.h>
 #include <linux/utsname.h>
@@ -30,6 +29,9 @@
 extern void (*do_floppy)(void);
 #endif
 
+extern int request_dma(unsigned int dmanr);
+extern void free_dma(unsigned int dmanr);
+
 extern int do_execve(char * filename, char ** argv, char ** envp,
 		struct pt_regs * regs);
 extern void flush_old_exec(struct linux_binprm * bprm);
@@ -104,11 +106,16 @@
 	X(unregister_exec_domain),
 
 	/* interrupt handling */
+	X(irqaction),
 	X(request_irq),
 	X(free_irq),
 	X(bh_active),
 	X(bh_mask),
 
+	/* dma handling */
+	X(request_dma),
+	X(free_dma),	
+	
 	/* process management */
 	X(wake_up),
 	X(wake_up_interruptible),
diff -u --recursive --new-file v1.1.20/linux/kernel/ldt.c linux/kernel/ldt.c
--- v1.1.20/linux/kernel/ldt.c	Tue Jun 21 14:16:26 1994
+++ linux/kernel/ldt.c	Tue Jun 21 14:10:04 1994
@@ -58,10 +58,8 @@
 		limit *= PAGE_SIZE;
 
 	limit += base;
-#ifdef	NOTDEF_KLUDGE
 	if (limit < base || limit >= 0xC0000000)
 		return -EINVAL;
-#endif
 
 	if (!current->ldt) {
 		for (i=1 ; i<NR_TASKS ; i++) {
Only in v1.1.20/linux/kernel: mktime.c
diff -u --recursive --new-file v1.1.20/linux/kernel/module.c linux/kernel/module.c
--- v1.1.20/linux/kernel/module.c	Fri Feb 11 08:55:26 1994
+++ linux/kernel/module.c	Tue Jun 21 13:14:12 1994
@@ -120,6 +120,8 @@
 			return error;
 		if ((mp = find_module(name)) == NULL)
 			return -ENOENT;
+		if (GET_USE_COUNT(mp) != 0)
+			return -EBUSY;
 		if (mp->state == MOD_RUNNING)
 			(*mp->cleanup)();
 		mp->state = MOD_DELETED;
diff -u --recursive --new-file v1.1.20/linux/mm/memory.c linux/mm/memory.c
--- v1.1.20/linux/mm/memory.c	Tue Jun 21 14:16:27 1994
+++ linux/mm/memory.c	Sat Jun 18 12:17:21 1994
@@ -1057,7 +1057,9 @@
 	printk("%d reserved pages\n",reserved);
 	printk("%d pages shared\n",shared);
 	show_buffers();
+#ifdef CONFIG_NET
 	show_net_buffers();
+#endif
 }
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
diff -u --recursive --new-file v1.1.20/linux/net/inet/README linux/net/inet/README
--- v1.1.20/linux/net/inet/README	Tue Jun 21 14:16:27 1994
+++ linux/net/inet/README	Tue Jun 21 13:23:53 1994
@@ -1,7 +1,37 @@
-This is snapshot 015
+Changes for 1.1.21
 
-Changes for the 015 snapshot
+o	Small bug fix in the apricot xen-ii driver code (Mark Evans)
+o	DE600 changes + DE620 driver (Bj0rn Eckwall)
+o	WWW error return bug fixed (Everyone!)
+o	SLIP default address is now better
+o	Small changes to PLIP (Niibe)
+o	Added PF_UNSPEC	(Dominic Kubla)
+o	TCP fastpath for receive.
+o	Turbo charged tcp checksum routine (Arnt Gulbrandsen)
+o	PPP locking bug fixes (Florian La Roche)
 
+To Do
+
+o	Include the HP onboard lance fixes.
+o	Fix Unix domain sockets.
+o	Fix the _SLOW_ TCP window calculation junk in tcp_data/tcp_ack.
+o	Make the dev_add_proto() list hashed by protocol type.
+o	Remove the call to dev->header_type - load it into the skbuff.
+	instead to avoid the extra calls and cache misses.
+o	Include new sk_buff skb_push() code and move toward using it.
+o	Fix the PI driver so pi0a can be down when pi0b is up without getting
+	crashes. Also fix the stuff to allow piconfig to set the parameters.
+o	Make AX.25 set the packet type - certainly before it hits IP.
+o	sk_buff building at the top level - pure kernel interfaces to the
+	protocol layers
+o	Clean up NFS, merge NFS/TCP code.
+o	SIGIO
+o	IP forwarding use of options properly (needs new sk_buff code)
+o	Reroute TCP retransmits if needed (needs new sk_buffs)
+
+
+Changes for 1.1.20
+
 o	All read/write buffers are validated at the top level _only_
 o	All address structures are moved to and from user mode at the top
 	level. Thus you can now issue proto->bind(....) calls and related
@@ -45,29 +75,6 @@
 	8390 drivers.
 o	Potential ARP TCP-retransmit clear race fixed. Incredibly
 	unlikely to occur but no doubt it will 8(.
-
-To Do
-
-o	Fast path the tcp for packets in order with no flags set - we ought
-	to hit cable speed on slower machines if we fix that and the below.
-	(under test - define TCP_FASTPATH in tcp.c if you want to be brave
-	 and report any findings.)
-o	Include the HP onboard lance fixes.
-o	Fix Unix domain sockets.
-o	Fix the _SLOW_ TCP window calculation junk in tcp_data/tcp_ack.
-o	Make the dev_add_proto() list hashed by protocol type.
-o	Remove the call to dev->header_type - load it into the skbuff.
-	instead to avoid the extra calls and cache misses.
-o	Include new sk_buff skb_push() code and move toward using it.
-o	Fix the PI driver so pi0a can be down when pi0b is up without getting
-	crashes. Also fix the stuff to allow piconfig to set the parameters.
-o	Make AX.25 set the packet type - certainly before it hits IP.
-o	sk_buff building at the top level - pure kernel interfaces to the
-	protocol layers
-o	Clean up NFS, merge NFS/TCP code.
-o	SIGIO
-o	IP forwarding use of options properly (needs new sk_buff code)
-o	Reroute TCP retransmits if needed (needs new sk_buffs)
 
 
 Fixes added for 1.1.19
diff -u --recursive --new-file v1.1.20/linux/net/inet/af_inet.c linux/net/inet/af_inet.c
--- v1.1.20/linux/net/inet/af_inet.c	Tue Jun 21 14:16:27 1994
+++ linux/net/inet/af_inet.c	Tue Jun 21 13:21:58 1994
@@ -847,7 +847,7 @@
 	}
 
 	if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && (flags & O_NONBLOCK))
-		return -EINPROGRESS;	/* Connecting is currently in progress */
+		return -EALREADY;	/* Connecting is currently in progress */
   	
 	if (sock->state != SS_CONNECTING) 
 	{
@@ -1303,7 +1303,7 @@
 	int i;
 
 
-	printk("NET3 TCP/IP protcols stack v016\n");
+	printk("NET3 TCP/IP protocols stack v016\n");
 
 	/*
 	 *	Tell SOCKET that we are alive... 
diff -u --recursive --new-file v1.1.20/linux/net/inet/ip.c linux/net/inet/ip.c
--- v1.1.20/linux/net/inet/ip.c	Tue Jun 21 14:16:28 1994
+++ linux/net/inet/ip.c	Fri Jun 17 19:37:30 1994
@@ -1633,10 +1633,6 @@
   	struct iphdr *iph;
   	unsigned char *ptr;
 
-	/* All buffers without an owner socket get freed */
-  	if (sk == NULL) 
-  		free = 1;
-  	
   	/* Sanity check */
   	if (dev == NULL) 
   	{
@@ -1677,6 +1673,10 @@
 	else
 		free=1;
 		
+	/* All buffers without an owner socket get freed */
+  	if (sk == NULL) 
+  		free = 1;
+  	
   	skb->free = free;		
 
 	/*
diff -u --recursive --new-file v1.1.20/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.20/linux/net/inet/tcp.c	Tue Jun 21 14:16:31 1994
+++ linux/net/inet/tcp.c	Tue Jun 21 13:24:11 1994
@@ -16,6 +16,7 @@
  *		Linus Torvalds, <torvalds@cs.helsinki.fi>
  *		Alan Cox, <gw4pts@gw4pts.ampr.org>
  *		Matthew Dillon, <dillon@apollo.west.oic.com>
+ *		Arnt Gulbrandsen, <agulbra@no.unit.nvg>
  *
  * Fixes:	
  *		Alan Cox	:	Numerous verify_area() calls
@@ -74,6 +75,7 @@
  *		Matthew Dillon	:	Fixed another RST bug
  *		Alan Cox	:	Move to kernel side addressing changes.
  *		Alan Cox	:	Beginning work on TCP fastpathing (not yet usable)
+ *		Arnt Gulbrandsen:	Turbocharged tcp_check() routine.
  *
  *
  * To Fix:
@@ -85,10 +87,6 @@
  *			Fast path the code. Two things here - fix the window calculation
  *		so it doesn't iterate over the queue, also spot packets with no funny
  *		options arriving in order and process directly.
- *			Any assembler hacker who can speed up the checksum routines will
- *		be welcome as well as someone who feels like writing a single 'checksum udp
- *		and copy up to user mode for the first n bytes at the same time' routine.
- *		which should be quicker than the current sum then copy for the UDP layer.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -154,7 +152,7 @@
 #include <asm/segment.h>
 #include <linux/mm.h>
 
-#undef TCP_FASTPATH
+#define TCP_FASTPATH
 
 #define SEQ_TICK 3
 unsigned long seq_offset;
@@ -184,6 +182,8 @@
    of two things. Firstly we will bin packets even within the window
    in order to get the data we are waiting for into the memory limit.
    Secondly we bin common duplicate forms at receive time
+   
+   TODO: add sk->window_clamp to limit windows over the DE600 and AX.25
 
    Better heuristics welcome
 */
@@ -524,64 +524,79 @@
 	unsigned long sum;
    
 	if (saddr == 0) saddr = ip_my_addr();
-	
-	__asm__("\t addl %%ecx,%%ebx\n"
-		"\t adcl %%edx,%%ebx\n"
-		"\t adcl $0, %%ebx\n"
-		: "=b"(sum)
-		: "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256)
-		: "cx","bx","dx" );
-   
-	if (len > 3) 
-	{
-		__asm__("\tclc\n"
-			"1:\n"
-			"\t lodsl\n"
-			"\t adcl %%eax, %%ebx\n"
-			"\t loop 1b\n"
-			"\t adcl $0, %%ebx\n"
-			: "=b"(sum) , "=S"(th)
-			: "0"(sum), "c"(len/4) ,"1"(th)
-			: "ax", "cx", "bx", "si" );
-	}
-   
-	/* Convert from 32 bits to 16 bits. */
-	__asm__("\t movl %%ebx, %%ecx\n"
-		"\t shrl $16,%%ecx\n"
-		"\t addw %%cx, %%bx\n"
-		"\t adcw $0, %%bx\n"
-		: "=b"(sum)
-		: "0"(sum)
-		: "bx", "cx");
-   
-	/* Check for an extra word. */
 
-	if ((len & 2) != 0) 
-	{
-		__asm__("\t lodsw\n"
-			"\t addw %%ax,%%bx\n"
-			"\t adcw $0, %%bx\n"
-			: "=b"(sum), "=S"(th)
-			: "0"(sum) ,"1"(th)
-			: "si", "ax", "bx");
-  	}
-   
-   	/* Now check for the extra byte. */
-  	if ((len & 1) != 0) 
-  	{
-		__asm__("\t lodsb\n"
-			"\t movb $0,%%ah\n"
-			"\t addw %%ax,%%bx\n"
-			"\t adcw $0, %%bx\n"
-			: "=b"(sum)
-			: "0"(sum) ,"S"(th)
-			: "si", "ax", "bx");
-  	}
-   
+/*
+ * stupid, gcc complains when I use just one __asm__ block,
+ * something about too many reloads, but this is just two
+ * instructions longer than what I want
+ */
+	__asm__("
+	    addl %%ecx, %%ebx
+	    adcl %%edx, %%ebx
+	    adcl $0, %%ebx
+	    "
+	: "=b"(sum)
+	: "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256)
+	: "bx", "cx", "dx" );
+	__asm__("
+	    movl %%ecx, %%edx
+	    cld
+	    cmpl $32, %%ecx
+	    jb 2f
+	    shrl $5, %%ecx
+	    clc
+1:	    lodsl
+	    adcl %%eax, %%ebx
+	    lodsl
+	    adcl %%eax, %%ebx
+	    lodsl
+	    adcl %%eax, %%ebx
+	    lodsl
+	    adcl %%eax, %%ebx
+	    lodsl
+	    adcl %%eax, %%ebx
+	    lodsl
+	    adcl %%eax, %%ebx
+	    lodsl
+	    adcl %%eax, %%ebx
+	    lodsl
+	    adcl %%eax, %%ebx
+	    loop 1b
+	    adcl $0, %%ebx
+	    movl %%edx, %%ecx
+2:	    andl $28, %%ecx
+	    cmpl $4, %%ecx
+	    jb 4f
+	    shrl $2, %%ecx
+	    clc
+3:	    lodsl
+	    adcl %%eax, %%ebx
+	    loop 3b
+	    adcl $0, %%ebx
+4:	    movl $0, %%eax
+	    testw $2, %%dx
+	    je 5f
+	    lodsw
+	    addl %%eax, %%ebx
+	    movw $0, %%ax
+5:	    test $1, %%edx
+	    je 6f
+	    lodsb
+	    addl %%eax, %%ebx
+6:	    movl %%ebx, %%eax
+	    shrl $16, %%eax
+	    addw %%ax, %%bx
+	    adcw $0, %%bx
+	    "
+	: "=b"(sum)
+	: "0"(sum), "c"(len), "S"(th)
+	: "ax", "bx", "cx", "dx", "si" );
+
   	/* We only want the bottom 16 bits, but we never cleared the top 16. */
   
   	return((~sum) & 0xffff);
 }
+
 
 
 void tcp_send_check(struct tcphdr *th, unsigned long saddr, 
