ALPHA-pl15h
diff --git a/Makefile b/Makefile
index 9d113f5..8b40870 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 0.99
 PATCHLEVEL = 15
-ALPHA = g
+ALPHA = h
 
 all:	Version zImage
 
@@ -188,7 +188,9 @@
 
 zlilo: $(CONFIGURE) zImage
 	if [ -f /vmlinuz ]; then mv /vmlinuz /vmlinuz.old; fi
+	if [ -f /zSystem.map ]; then mv /zSystem.map /zSystem.old; fi
 	cat zImage > /vmlinuz
+	cp zSystem.map /
 	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
 tools/zSystem:	boot/head.o init/main.o tools/version.o linuxsubdirs
diff --git a/config.in b/config.in
index 61146ca..a844923 100644
--- a/config.in
+++ b/config.in
@@ -76,7 +76,7 @@
 bool 'AT1700 support' CONFIG_AT1700 n
 #bool 'Zenith Z-Note support' CONFIG_ZNET n
 #bool 'EtherExpress support' CONFIG_EEXPRESS n
-#bool 'DEPCA support' CONFIG_DEPCA n
+bool 'DEPCA support' CONFIG_DEPCA n
 #bool 'NI52** support' CONFIG_NI52 n
 #bool 'NI65** support' CONFIG_NI65 n
 #bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
diff --git a/drivers/char/console.c b/drivers/char/console.c
index cfd1e0c..4b43d69 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -382,12 +382,18 @@
 	__set_origin(__real_origin);
 }
 
-static inline void hide_cursor(int currcons)
+/*
+ * Put the cursor just beyond the end of the display adaptor memory.
+ */
+static inline void hide_cursor(void)
 {
+  /* This is inefficient, we could just put the cursor at 0xffff,
+     but perhaps the delays due to the inefficiency are useful for
+     some hardware... */
 	outb_p(14, video_port_reg);
-	outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val);
+	outb_p(0xff&((video_mem_term-video_mem_base)>>9), video_port_val);
 	outb_p(15, video_port_reg);
-	outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val);
+	outb_p(0xff&((video_mem_term-video_mem_base)>>1), video_port_val);
 }
 
 static inline void set_cursor(int currcons)
@@ -405,7 +411,7 @@
 		outb_p(15, video_port_reg);
 		outb_p(0xff&((pos-video_mem_base)>>1), video_port_val);
 	} else
-		hide_cursor(currcons);
+		hide_cursor();
 	restore_flags(flags);
 }
 
@@ -1546,7 +1552,7 @@
 		return;
 	timer_table[BLANK_TIMER].fn = unblank_screen;
 	get_scrmem(fg_console);
-	hide_cursor(fg_console);
+	hide_cursor();
 	console_blanked = 1;
 	memsetw((void *)video_mem_base, 0x0020, video_mem_term-video_mem_base );
 }
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 024568e..e2125af 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -122,12 +122,6 @@
     
     irq2dev_map[dev->irq] = dev;
     NS8390_init(dev, 1);
-    ei_local->tx1 = ei_local->tx2 = 0;
-    /* The old local flags... */
-    ei_local->txing = 0;
-    /* ... are now global. */
-    dev->tbusy = 0;
-    dev->interrupt = 0;
     dev->start = 1;
     ei_local->irqlock = 0;
     return 0;
@@ -684,6 +678,10 @@
     outb_p(ei_local->rx_start_page,	 e8390_base + EN1_CURPAG);
     outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
     sti();
+    dev->tbusy = 0;
+    dev->interrupt = 0;
+    ei_local->tx1 = ei_local->tx2 = 0;
+    ei_local->txing = 0;
     if (startp) {
 		outb_p(0xff,  e8390_base + EN0_ISR);
 		outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
diff --git a/drivers/net/CONFIG b/drivers/net/CONFIG
index cb9bbed..2231fa7 100644
--- a/drivers/net/CONFIG
+++ b/drivers/net/CONFIG
@@ -30,6 +30,9 @@
 #	  D_LINK_IO	The D-Link I/O address (0x378 == typical)
 #	  D_LINK_IRQ	The D-Link IRQ number to use (IRQ7 == typical)
 #	  D_LINK_DEBUG	Enable or disable D-Link debugging
+#  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
 #
 
 # The following options exist, but cannot be set in this file.
@@ -50,6 +53,7 @@
 NE_OPTS		=
 HP_OPTS		=
 PLIP_OPTS	=
+DEPCA_OPTS	= -DDEPCA_IRQ=0 -DDEPCA_DEBUG=1
 
 # The following are the only parameters that must be set in this file.
 DL_OPTS		= -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 51c1c8d..de6fc06 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -105,6 +105,8 @@
 endif
 ifdef CONFIG_DEPCA
 NETDRV_OBJS := $(NETDRV_OBJS) net.a(depca.o)
+depca.o: depca.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
 endif
 ifdef CONFIG_ATP
 NETDRV_OBJS := $(NETDRV_OBJS) net.a(atp.o)
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
new file mode 100644
index 0000000..50efe69
--- /dev/null
+++ b/drivers/net/depca.c
@@ -0,0 +1,1364 @@
+/*  depca.c: A DIGITAL DEPCA ethernet driver for linux.
+
+    Written 1994 by David C. Davies.
+
+    Copyright 1994 David C. Davies and United States Government as
+    represented by the Director, National Security Agency.  This software
+    may be used and distributed according to the terms of the GNU Public
+    License, incorporated herein by reference.
+
+    This driver is written for the Digital Equipment Corporation series
+    of DEPCA ethernet cards:
+
+    	DE100 DEPCA
+	DE200 DEPCA Turbo
+	DE202 DEPCA Turbo (TP BNC)
+	DE210 DEPCA
+
+    The driver has been tested on DE100 and DE20x cards in a relatively busy 
+    network.
+
+    The author may be reached as davies@wanton.enet.dec.com or
+    Digital Equipment Corporation, 146 Main Street, Maynard MA 01754.
+
+    =========================================================================
+    The driver was based on the 'lance.c' driver from Donald Becker which is
+    included with the standard driver distribution for linux. Modifications
+    were made to most routines and the hardware recognition routines were
+    written from scratch. Primary references used were:
+
+    1) Lance.c code in /linux/drivers/net/
+    2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
+       AMD, 1992 [(800) 222-9323].
+    3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
+       AMD, Pub. #17881, May 1993.
+    4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
+       AMD, Pub. #16907, May 1992
+    5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
+       Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
+    6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
+       Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
+    7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
+       Digital Equipment Corporation, 1989
+    8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
+       Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
+    
+    Peter Bauer's depca.c (V0.5) was referred to when debugging this driver.
+    The hash filter code was  derived from Reference  3 and has been  tested
+    only to the extent that the Table  A-1, page A-7,  was confirmed to fill
+    the   filter bit   positions  correctly.  Hash   filtering  is  not  yet
+    implemented in the current driver set.
+
+    The  DE200 series boards have   on-board 64kB RAM  for  use as a  shared
+    memory network buffer. Only  the DE100 cards  make  use of a  2kB buffer
+    mode  which has not  been implemented in  this driver (only the 32kB and
+    64kB modes are supported).
+
+    At the  most only 2 DEPCA  cards can be supported  because there is only
+    provision for two I/O base addresses on the cards (0x300 and 0x200). The
+    base  address is  'autoprobed' by  looking  for  the self  test PROM and
+    detecting the  card name.  The shared memory  base address is decoded by
+    'autoprobing' the Ethernet PROM address information. The second DEPCA is
+    detected and information placed  in the base_addr  variable of the  next
+    device  structure   (which is created    if  necessary),  thus  enabling
+    ethif_probe initialization for the device.
+
+    ************************************************************************
+
+    NOTE: If you are using two  DEPCAs, it is important  that you assign the
+    base memory addresses  correctly.  The driver  autoprobes I/O 0x300 then
+    0x200.  The base memory  address for the  first device must be less than
+    that of the second so that the auto probe will  correctly assign the I/O
+    and  memory addresses on  the same card.  I can't  think of  a way to do
+    this unambiguously at the moment, since there is nothing on the cards to
+    tie I/O and memory information together.
+
+    I   am unable to test    2 DEPCAs together for   now,   so this code  is
+    unchecked. All reports, good or bad, are welcome.
+
+    ************************************************************************
+
+    The board IRQ  setting must be  at  an unused  IRQ  which is auto-probed
+    using   Donald Becker's   autoprobe   routines. DE100   board IRQs   are
+    {2,3,4,5,7}, whereas  the DE200 is at  {5,9,10,11,15}. Note that IRQ2 is
+    really IRQ9 in machines with 16 IRQ lines.
+
+    No 16MB memory  limitation should exist with this  driver as DMA is  not
+    used and the common memory area is in low memory on the network card (my
+    current system has 20MB and I've not had problems yet).
+
+    The DE203,  DE204  and DE205 cards  may  also work  with this driver  (I
+    haven't tested  them so I don't  know). If you have  one of these cards,
+    place the name in the DEPCA_SIGNATURE string  around line 160, recompile
+    the kernel and reboot. Check if the card  is recognised and works - mail
+    me if so, so that I can add it into the list of supported cards!
+
+    TO DO:
+    ------
+
+    1. Implement the 2k buffer mode - does anyone need it??
+
+    Revision History
+    ----------------
+
+    Version   Date        Description
+  
+      0.1   25-jan-94     Initial writing
+      0.2   27-jan-94     Added LANCE TX buffer chaining
+      0.3    1-feb-94     Added multiple DEPCA support
+      0.31   4-feb-94     Added DE202 recognition
+      0.32  19-feb-94     Tidy up. Improve multi-DEPCA support.
+
+    =========================================================================
+*/
+
+static char *version = "depca.c:v0.32 2/19/94 davies@wanton.enet.dec.com\n";
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "dev.h"
+#include "iow.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+#include "depca.h"
+
+extern int vsprintf(char *buf, const char *fmt, ...);
+
+#ifdef DEPCA_DEBUG
+int depca_debug = DEPCA_DEBUG;
+#else
+int depca_debug = 1;
+#endif
+
+#ifndef DEPCA_IRQ
+/*#define DEPCA_IRQ	{5,9,10,11,15,0}*/
+#define DEPCA_IRQ	5
+#endif
+
+#ifndef PROBE_LENGTH
+#define PROBE_LENGTH    32
+#endif
+
+#ifndef PROBE_SEQUENCE
+#define PROBE_SEQUENCE "FF0055AAFF0055AA"
+#endif
+
+#ifndef DEPCA_SIGNATURE
+#define DEPCA_SIGNATURE {"DEPCA","DE100","DE200","DE202","DE210",""}
+#define DEPCA_NAME_LENGTH 8
+#endif
+
+#ifndef DEPCA_RAM_BASE_ADDRESSES
+#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
+#endif
+static short mem_chkd = 0;               /* holds which base addrs have been */
+					 /* checked, for multi-DEPCA case */
+
+#ifndef DEPCA_IO_PORTS
+#define DEPCA_IO_PORTS {0x300, 0x200, 0}
+#endif
+
+#ifndef DEPCA_TOTAL_SIZE
+#define DEPCA_TOTAL_SIZE 0x10
+#endif
+
+#ifndef MAX_NUM_DEPCAS
+#define MAX_NUM_DEPCAS 2
+#endif
+
+/*
+** Set the number of Tx and Rx buffers. 
+*/
+#ifndef DEPCA_BUFFER_LOG_SZ
+#define RING_SIZE	16              /* 16 buffers */
+#else
+#define RING_SIZE	(1 << (DEPCA_BUFFERS_LOG_SZ))
+#endif  /* DEPCA_BUFFER_LOG_SZ */
+
+#define PKT_BUF_SZ	1544            /* Buffer size for each Tx/Rx buffer */
+#define PKT_SZ   	1514            /* Maximum ethernet packet length */
+#define DAT_SZ   	1500            /* Maximum ethernet data length */
+#define PKT_HDR_LEN     14              /* Addresses and data length info */
+
+#ifdef HAVE_MULTICAST
+#ifndef CRC_POLYNOMIAL
+#define CRC_POLYNOMIAL 0x04c11db7       /* Ethernet CRC polynomial */
+#endif /* CRC_POLYNOMIAL */
+#endif /* HAVE_MULTICAST */
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(buff, size) kfree_s(buff,size)
+#endif  /* HAVE_ALLOC_SKB */
+
+/*
+** The DEPCA Rx and Tx ring descriptors. 
+*/
+struct depca_rx_head {
+    long base;
+    short buf_length;		/* This length is negative 2's complement! */
+    short msg_length;		/* This length is "normal". */
+};
+
+struct depca_tx_head {
+    long base;
+    short length;		/* This length is negative 2's complement! */
+    short misc;                 /* Errors and TDR info */
+};
+
+struct depca_ring_info {
+};
+
+/*
+** The Lance initialization block, described in databook, in common memory.
+*/
+struct depca_init {
+    unsigned short mode;	/* Mode register */
+    unsigned char phys_addr[ETH_ALEN];	/* Physical ethernet address */
+    unsigned short filter[4];	/* Multicast filter. */
+    unsigned long rx_ring;     	/* Rx ring base pointer & ring length */
+    unsigned long tx_ring;	/* Tx ring base pointer & ring length */
+};
+
+struct depca_private {
+    char devname[8];            /* Not used */
+    struct depca_rx_head *rx_ring; /* Pointer to start of RX descriptor ring */
+    struct depca_tx_head *tx_ring; /* Pointer to start of TX descriptor ring */
+    struct depca_init	init_block;/* Initialization block */
+    long dma_buffs;		/* Start address of Rx and Tx buffers. */
+    int	cur_rx, cur_tx;		/* The next free ring entry */
+    int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+    int dma;
+    struct enet_statistics stats;
+    char old_depca;
+    short ringSize;             /* ring size based on available memory */
+    short rmask;                /* modulus mask based on ring size */
+    long rlen;                  /* log2(ringSize) for the descriptors */
+};
+
+/*
+** Public Functions
+*/
+static int depca_open(struct device *dev);
+static int depca_start_xmit(struct sk_buff *skb, struct device *dev);
+static void depca_interrupt(int reg_ptr);
+static int depca_close(struct device *dev);
+static struct enet_statistics *depca_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+/*
+** Private functions
+*/
+static int depca_probe1(struct device *dev, short ioaddr);
+static void depca_init_ring(struct device *dev);
+static int depca_rx(struct device *dev);
+static int depca_tx(struct device *dev);
+
+static void LoadCSRs(struct device *dev);
+static int InitRestartDepca(struct device *dev);
+static char *DepcaSignature(unsigned long mem_addr);
+static int DevicePresent(short ioaddr);
+#ifdef HAVE_MULTICAST
+static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table);
+#endif
+
+static int num_depcas = 0, num_eth = 0;;
+
+/*
+** Miscellaneous defines...
+*/
+#define STOP_DEPCA \
+    outw(CSR0, DEPCA_ADDR);\
+    outw(STOP, DEPCA_DATA)
+
+
+
+int depca_probe(struct device *dev)
+{
+    int *port, ports[] = DEPCA_IO_PORTS;
+    int base_addr = dev->base_addr;
+    int status;
+    struct device *eth0 = (struct device *) NULL;
+
+    if (base_addr > 0x1ff) {	      /* Check a single specified location. */
+		status = depca_probe1(dev, base_addr);
+    } else if (base_addr > 0) {	      /* Don't probe at all. */
+		status = -ENXIO;
+    } else {                          /* First probe for the DEPCA test */
+                                      /* pattern in ROM */
+
+      for (status = -ENODEV, port = &ports[0]; 
+	                    *port && (num_depcas < MAX_NUM_DEPCAS); port++) {
+	int ioaddr = *port;
+
+#ifdef HAVE_PORTRESERVE
+	if (check_region(ioaddr, DEPCA_TOTAL_SIZE))
+	    continue;
+#endif
+	if (DevicePresent(DEPCA_PROM) == 0) {
+	  if (num_depcas > 0) {        /* only gets here in autoprobe */
+
+	    /*
+	    ** Check the device structures for an end of list or unused device
+	    */
+	    while (dev->next != (struct device *)NULL) {
+	      if (dev->next->base_addr == 0xffe0) break;
+	      dev = dev->next;         /* walk through eth device list */
+	      num_eth++;               /* increment eth device number */
+	    }
+
+	    /*
+	    ** If no more device structures, malloc one up. If memory could
+	    ** not be allocated, print an error message.
+	    ** 
+	    */
+	    if (dev->next == (struct device *)NULL) {
+	      dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+                                                                  GFP_KERNEL);
+	    } else {
+	      printk("eth%d: Device not initialised, insufficient memory\n",
+		                                                      num_eth);
+	    }
+
+	    /*
+	    ** If the memory was allocated, point to the new memory area
+	    ** and initialize it (name, I/O address, next device (NULL) and
+	    ** initialisation probe routine).
+	    */
+	    if ((dev->next != (struct device *)NULL) &&
+		(num_eth > 0) && (num_eth < 9999)) {
+	      dev = dev->next;         /* point to the new device */
+	      dev->name = (char *)(dev + sizeof(struct device));
+	      vsprintf(dev->name,"eth%d", num_eth); /* New device name */
+	      dev->base_addr = ioaddr; /* assign the io address */
+	      dev->next = (struct device *)NULL; /* mark the end of list */
+	      dev->init = &depca_probe;/* initialisation routine */
+	    }
+	  } else {
+	    eth0 = dev;                /* remember the first device */
+	    status = depca_probe1(dev, ioaddr);
+	  }
+	  num_depcas++;
+	  num_eth++;
+	}
+      }
+      if (eth0) dev = eth0;             /* restore the first device */
+    }
+
+    if (status) dev->base_addr = base_addr;
+
+    return status;			/* ENODEV would be more accurate. */
+}
+
+static int
+depca_probe1(struct device *dev, short ioaddr)
+{
+    struct depca_private *lp;
+    int i,j, status=0;
+    unsigned long mem_start, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
+    char *name=(char *)NULL;
+    int nicsr, offset;
+
+
+    /*
+    ** Stop the DEPCA. Enable the DBR ROM. Disable interrupts and remote boot
+    */
+    STOP_DEPCA;
+
+    nicsr = inw(DEPCA_NICSR);
+    nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
+    outw(nicsr, DEPCA_NICSR);
+
+    if (inw(DEPCA_DATA) == STOP) {
+
+    /* Now find out what kind of DEPCA we have. The DE100 uses a different
+    ** addressing scheme for some registers compared to the DE2xx series.
+    ** Note that a base address location is marked as checked if no DEPCA is
+    ** there or one is found (when the search is immediately terminated). This
+    ** shortens the search time a little for multiple DEPCAs.
+    */
+
+      for (j = 0, i = 0; mem_base[i] && (j == 0);) {
+	if (((mem_chkd >> i) & 0x01) == 0) { /* has the memory been checked? */
+	  name = DepcaSignature(mem_base[i]);/* check for a DEPCA here */
+	  mem_chkd |= (0x01 << i);           /* mark location checked */
+	  if (*name != (char)NULL) {         /* one found? */
+	    j = 1;                           /* set exit flag */
+	  } else {
+	    i++;                             /* increment search index */
+	  }
+	}
+      }
+
+      if (*name != (char)NULL) {          /* found a DEPCA device */
+	mem_start = mem_base[i];
+	dev->base_addr = ioaddr;
+
+	printk("%s: DEPCA at %#3x is a %s, ", dev->name, ioaddr, name);
+
+      /* There is a 32 byte station address PROM at DEPCA_PROM address.
+	 The first six bytes are the station address. They can be read
+	 directly since the signature search set up the ROM address 
+	 counter correctly just before this function.
+
+	 For the DE100 we have to be careful about which port is used to
+	 read the ROM info.
+      */
+
+	if (strstr(name,"DE100")!=(char *)NULL) {
+	  j = 1;
+	} else {
+	  j = 0;
+	}
+
+	printk("ethernet address ");
+	for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */
+	  printk("%2.2x:", dev->dev_addr[i] = inb(DEPCA_PROM + j));
+	}
+	printk("%2.2x", dev->dev_addr[i] = inb(DEPCA_PROM + j));
+
+	for (;i<32;i++) {                /* leave ROM counter in known state */
+	  j=inb(DEPCA_PROM);
+	}
+
+#ifdef HAVE_PORTRESERVE
+	snarf_region(ioaddr, DEPCA_TOTAL_SIZE);
+#endif
+
+	/* 
+	 ** Determine the base address for the DEPCA RAM from the NI-CSR
+	 ** and make up a DEPCA-specific-data structure. 
+        */
+
+	if (nicsr & BUF) {
+	  offset = 0x8000;              /* 32kbyte RAM */
+	  nicsr &= ~BS;                 /* DEPCA RAM in top 32k */
+	  printk(",\n      with 32kB RAM");
+	} else {
+	  offset = 0x0000;              /* 64kbyte RAM */
+	  printk(",\n      with 64kB RAM");
+	}
+
+	mem_start += offset;
+	printk(" starting at 0x%.5lx", mem_start);
+
+	/*
+	 ** Enable the shadow RAM.
+	*/
+	nicsr |= SHE;
+	outw(nicsr, DEPCA_NICSR);
+ 
+	/*
+	** Calculate the ring size based on the available RAM
+	** found above. Allocate an equal number of buffers, each
+	** of size PKT_BUF_SZ (1544 bytes) to the Tx and Rx. Make sure
+	** that this ring size is <= RING_SIZE. The ring size must be
+	** a power of 2.
+	*/
+
+	j = ((0x10000 - offset) / PKT_BUF_SZ) >> 1;
+	for (i=0;j>1;i++) {
+	  j >>= 1;
+	}
+
+	/* Hold the ring size information here before the depca
+	** private structure is allocated. Need this for the memory
+	** space calculations.
+	*/
+	j = 1 << i;
+
+	/*
+	** Set up memory information in the device structure.
+	** Align the descriptor rings on an 8 byte (quadword) boundary.
+	**
+	**     depca_private area
+	**     rx ring descriptors
+	**     tx ring descriptors
+	**     rx buffers
+	**     tx buffers
+	**
+	*/
+
+	/* private area & initialise */
+	dev->priv = (void *)((mem_start + 0x07) & ~0x07);      
+	lp = (struct depca_private *)dev->priv;
+	memset(dev->priv, 0, sizeof(struct depca_private));
+
+	/* Tx & Rx descriptors (aligned to a quadword boundary) */
+	mem_start = ((((unsigned long)dev->priv + 
+		        sizeof(struct depca_private)) +
+			(unsigned long)0x07) & (unsigned long)~0x07);
+	lp->rx_ring = (struct depca_rx_head *)mem_start;
+
+	mem_start += (sizeof(struct depca_rx_head) * j);
+	lp->tx_ring = (struct depca_tx_head *)mem_start;
+
+	mem_start += (sizeof(struct depca_tx_head) * j);
+	lp->dma_buffs = mem_start & 0x00ffffff;
+
+	mem_start += (PKT_BUF_SZ * j);
+	/* (mem_start now points to the start of the Tx buffers) */
+
+	/* Initialise the data structures */
+	memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j);
+	memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j);
+
+	/* This should never happen. */
+	if ((int)(lp->rx_ring) & 0x07) {
+	  printk("\n **ERROR** DEPCA Rx and Tx descriptor rings not on a quadword boundary.\n");
+	  return -ENXIO;
+	}
+
+	/*
+	** Finish initialising the ring information.
+	*/
+	lp->ringSize = j;
+	if (lp->ringSize > RING_SIZE) lp->ringSize = RING_SIZE;
+	lp->rmask = lp->ringSize - 1;
+
+	/*
+	** calculate the real RLEN size for the descriptors. It is
+	** log2(ringSize).
+	*/
+	for (i=0, j = lp->ringSize; j>1; i++) {
+	  j >>= 1;
+	}
+	lp->rlen = (unsigned long)(i << 29);
+
+	/*
+	** load the initialisation block
+	*/
+	depca_init_ring(dev);
+
+	/*
+	** Initialise the control and status registers
+	*/
+	LoadCSRs(dev);
+
+	/*
+	** Enable DEPCA board interrupts for autoprobing
+	*/
+	nicsr = ((nicsr & ~IM)|IEN);
+	outw(nicsr, DEPCA_NICSR);
+
+	/* The DMA channel may be passed in on this parameter. */
+	dev->dma = 0;
+	
+	/* To auto-IRQ we enable the initialization-done and DMA err,
+	 interrupts. For now we will always get a DMA error. */
+	if (dev->irq < 2) {
+	  autoirq_setup(0);
+
+	  /* Trigger an initialization just for the interrupt. */
+	  outw(INEA | INIT, DEPCA_DATA);
+	  
+	  dev->irq = autoirq_report(1);
+	  if (dev->irq) {
+	    printk(" and probed IRQ%d.\n", dev->irq);
+	  } else {
+	    printk(". Failed to detect IRQ line.\n");
+	    status = -EAGAIN;
+	  }
+	} else {
+	  printk(". Assigned IRQ%d.\n", dev->irq);
+	}
+      } else {
+	status = -ENXIO;
+      }
+      if (!status) {
+	if (depca_debug > 0) {
+	  printk(version);
+	}
+
+	/* The DEPCA-specific entries in the device structure. */
+	dev->open = &depca_open;
+	dev->hard_start_xmit = &depca_start_xmit;
+	dev->stop = &depca_close;
+	dev->get_stats = &depca_get_stats;
+#ifdef HAVE_MULTICAST
+	dev->set_multicast_list = &set_multicast_list;
+#endif
+
+	dev->mem_start = 0;
+	
+	/* Fill in the generic field of the device structure. */
+	for (i = 0; i < DEV_NUMBUFFS; i++) {
+	  dev->buffs[i] = NULL;
+	}
+
+	dev->hard_header     = eth_header;
+	dev->add_arp	     = eth_add_arp;
+	dev->queue_xmit	     = dev_queue_xmit;
+	dev->rebuild_header  = eth_rebuild_header;
+	dev->type_trans	     = eth_type_trans;
+	
+	dev->type	     = ARPHRD_ETHER;
+	dev->hard_header_len = ETH_HLEN;
+	dev->mtu	     = 1500; /* eth_mtu */
+	dev->addr_len	     = ETH_ALEN;
+
+	for (i = 0; i < dev->addr_len; i++) {
+	  dev->broadcast[i]=0xff;
+	}
+	
+	/* New-style flags. */
+	dev->flags	     = IFF_BROADCAST;
+	dev->family	     = AF_INET;
+	dev->pa_addr	     = 0;
+	dev->pa_brdaddr	     = 0;
+	dev->pa_mask	     = 0;
+	dev->pa_alen	     = sizeof(unsigned long);
+      }
+    } else {
+      status = -ENXIO;
+    }
+
+    return status;
+}
+
+
+static int
+depca_open(struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+    int i,nicsr,ioaddr = dev->base_addr;
+
+    if (request_irq(dev->irq, &depca_interrupt)) {
+        printk("depca_open(): Requested IRQ%d is busy\n",dev->irq);
+	return -EAGAIN;
+    }
+
+    irq2dev_map[dev->irq] = dev;
+
+    /*
+    ** Stop the DEPCA & get the board status information.  
+    */
+    STOP_DEPCA;
+    nicsr = inw(DEPCA_NICSR);
+
+    /* 
+    ** Re-initialize the DEPCA... 
+    */
+    depca_init_ring(dev);                 /* initialize the descriptor rings */
+    LoadCSRs(dev);
+
+    if (depca_debug > 1){
+      printk("%s: depca open with irq %d\n",dev->name,dev->irq);
+      printk("Descriptor head addresses:\n");
+      printk("\t0x%8.8lx  0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
+      printk("Descriptor addresses:\n");
+      for (i=0;i<lp->ringSize;i++){
+	printk("\t0x%8.8lx  0x%8.8lx\n",(long)&lp->rx_ring[i].base,
+	                                (long)&lp->tx_ring[i].base);
+      }
+      printk("Buffer addresses:\n");
+      for (i=0;i<lp->ringSize;i++){
+	printk("\t0x%8.8lx  0x%8.8lx\n",(long)lp->rx_ring[i].base,
+                                        (long)lp->tx_ring[i].base);
+      }
+      printk("Initialisation block at 0x%8.8lx\n",(long)&lp->init_block);
+      printk("\tmode: 0x%4.4x\n",lp->init_block.mode);
+      printk("\tphysical address: ");
+      for (i=0;i<6;i++){
+	printk("%2.2x:",(short)lp->init_block.phys_addr[i]);
+      }
+      printk("\n\tlogical address filter: 0x");
+      for (i=0;i<4;i++){
+	printk("%2.2x",(short)lp->init_block.filter[i]);
+      }
+      printk("\n\trx_ring at: 0x%8.8lx\n",(long)lp->init_block.rx_ring);
+      printk("\ttx_ring at: 0x%8.8lx\n",(long)lp->init_block.tx_ring);
+      printk("dma_buffs: 0x%8.8lx\n",(long)lp->dma_buffs);
+      printk("Ring size: %d\nMask: 0x%2.2x\nLog2(ringSize): 0x%8.8lx\n", 
+                                         (short)lp->ringSize, 
+                                          (char)lp->rmask,
+                                          (long)lp->rlen);
+      outw(CSR2,DEPCA_ADDR);
+      printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA));
+      outw(CSR1,DEPCA_ADDR);
+      printk("%4.4x\n",inw(DEPCA_DATA));
+      outw(CSR3,DEPCA_ADDR);
+      printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA));
+    }
+
+    /*
+    ** Enable DEPCA board interrupts
+    */
+    nicsr = ((nicsr & ~IM & ~LED)|SHE|IEN);
+    outw(nicsr, DEPCA_NICSR);
+    outw(CSR0,DEPCA_ADDR);
+
+    dev->tbusy = 0;                         
+    dev->interrupt = 0;
+    dev->start = 1;
+
+    InitRestartDepca(dev);                /* ignore the return status */
+
+    if (depca_debug > 1){
+      printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
+      printk("nicsr: 0x%4.4x\n",inw(DEPCA_NICSR));
+    }
+
+    return 0;			          /* Always succeed */
+}
+
+/* Initialize the lance Rx and Tx descriptor rings. */
+static void
+depca_init_ring(struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+    unsigned long i;
+
+    lp->init_block.mode = DTX | DRX;	     /* Disable Rx and Tx. */
+    lp->cur_rx = lp->cur_tx = 0;
+    lp->dirty_rx = lp->dirty_tx = 0;
+
+    /* Initialize the base addresses and length of each buffer in the ring */
+    for (i = 0; i < lp->ringSize; i++) {
+	lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | R_OWN;
+	lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
+	lp->tx_ring[i].base = (lp->dma_buffs + (i+lp->ringSize) * PKT_BUF_SZ) &
+	                                           (unsigned long)(0x00ffffff);
+    }
+
+    /* Set up the initialization block */
+    for (i = 0; i < ETH_ALEN; i++) {
+      lp->init_block.phys_addr[i] = dev->dev_addr[i];
+    }
+    for (i = 0; i < 4; i++) {
+      lp->init_block.filter[i] = 0x0000;
+    }
+    lp->init_block.rx_ring = (unsigned long)lp->rx_ring | lp->rlen;
+    lp->init_block.tx_ring = (unsigned long)lp->tx_ring | lp->rlen;
+
+    lp->init_block.mode = 0x0000;            /* Enable the Tx and Rx */ 
+}
+
+/* 
+** Writes a socket buffer to TX descriptor ring and starts transmission 
+*/
+static int
+depca_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+    int ioaddr = dev->base_addr;
+    int status = 0;
+
+    /* Transmitter timeout, serious problems. */
+    if (dev->tbusy) {
+      int tickssofar = jiffies - dev->trans_start;
+      if (tickssofar < 5) {
+	status = -1;
+      } else {
+	STOP_DEPCA;
+	printk("%s: transmit timed out, status %4.4x, resetting.\n",
+	       dev->name, inw(DEPCA_DATA));
+	
+	depca_init_ring(dev);
+	LoadCSRs(dev);
+	InitRestartDepca(dev);
+	dev->tbusy=0;
+	dev->trans_start = jiffies;
+      }
+      return status;
+    }
+
+    if (skb == NULL) {
+	dev_tint(dev);
+	return 0;
+    }
+
+    /* Fill in the ethernet header. */
+    if (!skb->arp  &&  dev->rebuild_header(skb+1, dev)) {
+	skb->dev = dev;
+	arp_queue (skb);
+	return 0;
+    }
+    skb->arp=1;
+
+    if (skb->len <= 0) {
+      return 0;
+    }
+
+    if (depca_debug > 3) {
+	outw(CSR0, DEPCA_ADDR);
+	printk("%s: depca_start_xmit() called, csr0 %4.4x.\n", dev->name,
+	       inw(DEPCA_DATA));
+    }
+
+    /* Block a timer-based transmit from overlapping.  This could better be
+       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+    if (set_bit(0, (void*)&dev->tbusy) != 0)
+	printk("%s: Transmitter access conflict.\n", dev->name);
+
+    /*
+    ** The TX buffer, skb, has to be copied into the local network RAM
+    ** for the LANCE to access it. The skb may be at > 16MB for large 
+    ** (memory) systems.
+    */
+    {				/* Fill in a Tx ring entry */
+      unsigned char *buf;
+      int entry = lp->cur_tx++;
+      int len;
+      long skbL = skb->len;
+      char *p = (char *)(skb + 1);
+
+      entry &= lp->rmask;  		    /* Ring around buffer number. */
+      buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+
+      /* Wait for a full ring to free up */
+      while (lp->tx_ring[entry].base < 0);
+
+      /* 
+      ** Caution: the write order is important here... don't set up the
+      ** ownership rights until all the other information is in place.
+      */
+      len = ((skbL > PKT_SZ) ? PKT_SZ : skbL); /* skb too long */
+      if (len < ETH_ZLEN) len = ETH_ZLEN;      /* len too short */
+      skbL -= len;
+      lp->tx_ring[entry].length = -len;
+
+      /* Clears various error flags */
+      lp->tx_ring[entry].misc = 0x0000;
+
+      /* copy the data from the socket buffer to the net memory */
+      memcpy((unsigned char *)(buf), (unsigned char *)(skb + 1), len);
+
+      /* Hand over buffer ownership to the LANCE */
+      if (skbL <= 0) lp->tx_ring[entry].base |= (T_ENP);
+      lp->tx_ring[entry].base |= (T_OWN|T_STP);
+
+      /* Trigger an immediate send demand. */
+      outw(CSR0, DEPCA_ADDR);
+      outw(INEA | TDMD, DEPCA_DATA);
+
+      dev->trans_start = jiffies;
+
+      for (p += len; skbL > 0; p += len) {
+
+	/* Get new buffer pointer */
+	entry = lp->cur_tx++;
+	entry &= lp->rmask;  		    /* Ring around buffer number. */
+	buf = (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+
+	/* Wait for a full ring to free up */
+	while (lp->tx_ring[entry].base < 0);
+	dev->tbusy=0;
+
+	/* Copy ethernet header to the new buffer */
+	memcpy((unsigned char *)buf, (unsigned char *)(skb + 1), PKT_HDR_LEN);
+
+	/* Determine length of data buffer */
+	len = ((skbL > DAT_SZ) ? DAT_SZ : skbL); /* skbL too long */
+	if (len < ETH_ZLEN) len = ETH_ZLEN;      /* len too short */
+	skbL -= len;
+	lp->tx_ring[entry].length = -len;
+
+	/* Clears various error flags */
+	lp->tx_ring[entry].misc = 0x0000;
+
+	/* copy the data from the socket buffer to the net memory */
+	memcpy((unsigned char *)(buf + PKT_HDR_LEN), (unsigned char *)p, len);
+
+	/* Hand over buffer ownership to the LANCE */
+	if (skbL <= 0) lp->tx_ring[entry].base |= T_ENP;
+	lp->tx_ring[entry].base |= T_OWN;
+      }
+
+      if (depca_debug > 4) {
+	unsigned char *pkt =
+	  (unsigned char *)(lp->tx_ring[entry].base & 0x00ffffff);
+
+	printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n",
+	       dev->name, entry, (unsigned long) &lp->tx_ring[entry],
+	       lp->tx_ring[entry].base, -lp->tx_ring[entry].length);
+	printk("%s:  Tx %2.2x %2.2x %2.2x ... %2.2x  %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x  %2.2x %2.2x.\n",
+	       dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6],
+	       pkt[7], pkt[8], pkt[11], pkt[12], pkt[13],
+	       pkt[14], pkt[15]);
+      }
+      
+      /* Check if the TX ring is full or not - 'tbusy' cleared if not full. */
+      if (lp->tx_ring[(entry+1) & lp->rmask].base >= 0) {
+	dev->tbusy=0;
+      }
+
+      if (skb->free) {
+	kfree_skb (skb, FREE_WRITE);
+      }
+    }
+
+    return 0;
+}
+
+/*
+** The DEPCA interrupt handler. 
+*/
+static void
+depca_interrupt(int reg_ptr)
+{
+    int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+    struct device *dev = (struct device *)(irq2dev_map[irq]);
+    struct depca_private *lp;
+    int csr0, ioaddr, nicsr;
+
+    if (dev == NULL) {
+	printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+	return;
+    } else {
+      lp = (struct depca_private *)dev->priv;
+      ioaddr = dev->base_addr;
+    }
+
+    if (dev->interrupt)
+	printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+    dev->interrupt = MASK_INTERRUPTS;
+
+    /* mask the DEPCA board interrupts and turn on the LED */
+    nicsr = inw(DEPCA_NICSR);
+    nicsr |= (IM|LED);
+    outw(nicsr, DEPCA_NICSR);
+
+    outw(CSR0, DEPCA_ADDR);
+    csr0 = inw(DEPCA_DATA);
+
+    /* Acknowledge all of the current interrupt sources ASAP. */
+    outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA);
+
+    if (depca_debug > 5)
+	printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
+	       dev->name, csr0, inw(DEPCA_DATA));
+
+    if (csr0 & RINT)		/* Rx interrupt (packet arrived) */
+	depca_rx(dev);
+
+    if (csr0 & TINT) 	        /* Tx interrupt (packet sent) */
+        depca_tx(dev);
+
+    /* Clear the interrupts we've handled. */
+    outw(CSR0, DEPCA_ADDR);
+    outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA);
+
+    if (depca_debug > 4) {
+      printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
+	     dev->name, inw(DEPCA_ADDR),
+	     inw(DEPCA_DATA));
+    }
+
+    /* Unmask the DEPCA board interrupts and turn off the LED */
+    nicsr = (nicsr & ~IM & ~LED);
+    outw(nicsr, DEPCA_NICSR);
+
+    dev->interrupt = UNMASK_INTERRUPTS;
+    return;
+}
+
+static int
+depca_rx(struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+    int entry = lp->cur_rx & lp->rmask;
+
+    /* If we own the next entry, it's a new packet. Send it up. */
+    for (; lp->rx_ring[entry].base >= 0; entry = (++lp->cur_rx) & lp->rmask) {
+	int status = lp->rx_ring[entry].base >> 16 ;
+
+	if (status & R_ERR) {	       /* There was an error. */
+	    lp->stats.rx_errors++;     /* Update the error stats. */
+	    if (status & R_FRAM) lp->stats.rx_frame_errors++;
+	    if (status & R_OFLO) lp->stats.rx_over_errors++;
+	    if (status & R_CRC)  lp->stats.rx_crc_errors++;
+	    if (status & R_BUFF) lp->stats.rx_fifo_errors++;
+	} else {	  /* Malloc up new buffer, compatible  with net-2e. */
+	    short pkt_len = lp->rx_ring[entry].msg_length;
+	    int sksize = sizeof(struct sk_buff) + pkt_len;
+	    struct sk_buff *skb;
+
+	    skb = alloc_skb(sksize, GFP_ATOMIC);
+	    if (skb == NULL) {
+		printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+		lp->stats.rx_dropped++;	/* Really, deferred. */
+		break;
+	    }
+	    skb->mem_len = sksize;
+	    skb->mem_addr = skb;
+	    skb->len = pkt_len;
+	    skb->dev = dev;
+	    memcpy((unsigned char *)(skb + 1),
+		   (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff),
+		   pkt_len);
+	    /* 
+	    ** Notify the upper protocol layers that there is another 
+	    ** packet to handle
+	    */
+#ifdef HAVE_NETIF_RX
+	    netif_rx(skb);
+#else
+	    skb->lock = 0;
+	    if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+		kfree_skbmem(skb, sksize);
+		lp->stats.rx_dropped++;
+		break;
+	    }
+#endif
+	    lp->stats.rx_packets++;
+	}
+
+	/* turn over ownership of the current entry back to the LANCE */
+	lp->rx_ring[entry].base |= R_OWN;
+    }
+
+    /* 
+    ** We should check that at least two ring entries are free.  If not,
+    ** we should free one and mark stats->rx_dropped++. 
+    */
+
+    return 0;
+}
+
+/*
+** Buffer sent - check for buffer errors.
+*/
+static int
+depca_tx(struct device *dev)
+{
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  int dirty_tx = lp->dirty_tx & lp->rmask;
+
+  if (depca_debug > 5)
+    printk("%s: Cleaning tx ring, dirty %d clean %d.\n",
+	   dev->name, dirty_tx, (lp->cur_tx & lp->rmask));
+  
+  /* 
+  ** While the dirty entry is not the current one AND 
+  ** the LANCE doesn't own it... 
+  */
+  for (; dirty_tx!=(lp->cur_tx & lp->rmask) && lp->tx_ring[dirty_tx].base>0;
+                                       dirty_tx = ++lp->dirty_tx & lp->rmask) {
+    unsigned long *tmdp = (unsigned long *)(&lp->tx_ring[dirty_tx]);
+    int status = lp->tx_ring[dirty_tx].base >> 16;
+
+    if (status < 0) {                          /* Packet not yet sent! */
+      printk("interrupt for packet not yet sent!\n");
+      break;
+    }
+    if (status & T_ERR) { /* There was an major error, log it. */
+      int err_status = lp->tx_ring[dirty_tx].misc;
+
+      lp->stats.tx_errors++;
+      if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+      if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+      if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
+      if (err_status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
+      /* We should re-init() after the FIFO error. */
+    } else if (status & (T_MORE | T_ONE)) {
+      lp->stats.collisions++;
+    } else {
+      lp->stats.tx_packets++;
+    }
+
+    if (depca_debug > 5)
+      printk("%s: Tx done entry %d, %4.4lx %4.4lx %4.4lx %4.4lx.\n",
+	     dev->name, dirty_tx,
+	     tmdp[0], tmdp[1], tmdp[2], tmdp[3]);
+  }
+  /*mark_bh(INET_BH);*/
+  return 0;
+}
+
+static int
+depca_close(struct device *dev)
+{
+    int ioaddr = dev->base_addr;
+
+    dev->start = 0;
+    dev->tbusy = 1;
+
+    outw(CSR0, DEPCA_ADDR);
+
+    if (depca_debug > 1) {
+      printk("%s: Shutting down ethercard, status was %2.2x.\n",
+	     dev->name, inw(DEPCA_DATA));
+    }
+
+    /* 
+    ** We stop the DEPCA here -- it occasionally polls
+    ** memory if we don't. 
+    */
+    outw(STOP, DEPCA_DATA);
+
+    free_irq(dev->irq);
+
+    irq2dev_map[dev->irq] = 0;
+
+    return 0;
+}
+
+static void LoadCSRs(struct device *dev)
+{
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  int ioaddr = dev->base_addr;
+
+  outw(CSR1, DEPCA_ADDR);                /* initialisation block address LSW */
+  outw((unsigned short)(unsigned long)&lp->init_block, DEPCA_DATA);
+  outw(CSR2, DEPCA_ADDR);                /* initialisation block address MSW */
+  outw((unsigned short)((unsigned long)&lp->init_block >> 16), DEPCA_DATA);
+  outw(CSR3, DEPCA_ADDR);                /* ALE control */
+  outw(ACON, DEPCA_DATA);
+  outw(CSR0, DEPCA_ADDR);                /* point back to CSR0 */
+}
+
+static int InitRestartDepca(struct device *dev)
+{
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  int ioaddr = dev->base_addr;
+  int i, status=0;
+
+  outw(CSR0, DEPCA_ADDR);                /* point back to CSR0 */
+  outw(INIT, DEPCA_DATA);                /* initialize DEPCA */
+
+  /* wait for lance to complete initialisation */
+  for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++); 
+
+  if (i!=100) {
+    /* clear IDON by writing a "1", enable interrupts and start lance */
+    outw(IDON | INEA | STRT, DEPCA_DATA);
+    if (depca_debug > 2) {
+      printk("%s: DEPCA open after %d ticks, init block %#lx csr0 %4.4x.\n",
+	     dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
+    }
+  } else {
+    status = -1;
+    printk("%s: DEPCA unopened after %d ticks, init block %#lx csr0 %4.4x.\n",
+	   dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
+  }
+
+  return status;
+}
+
+static struct enet_statistics *
+depca_get_stats(struct device *dev)
+{
+    struct depca_private *lp = (struct depca_private *)dev->priv;
+
+    /* Null body since there is no framing error counter */
+
+    return &lp->stats;
+}
+
+#ifdef HAVE_MULTICAST
+/*
+** Set or clear the multicast filter for this adaptor.
+** num_addrs == -1	Promiscuous mode, receive all packets
+** num_addrs == 0	Normal mode, clear multicast list
+** num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+** 			best-effort filtering.
+*/
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+  short ioaddr = dev->base_addr;
+  struct depca_private *lp = (struct depca_private *)dev->priv;
+  
+  /* We take the simple way out and always enable promiscuous mode. */
+  STOP_DEPCA;                       /* Temporarily stop the depca.  */
+
+  lp->init_block.mode = PROM;       /* Set promiscuous mode */
+  if (num_addrs >= 0) {
+    short multicast_table[4];
+    int i;
+
+    SetMulticastFilter(num_addrs, (char *)addrs, (char *)multicast_table);
+
+    /* We don't use the multicast table, but rely on upper-layer filtering. */
+    memset(multicast_table, (num_addrs==0) ? 0 : -1, sizeof(multicast_table));
+
+    for (i = 0; i < 4; i++) {
+      lp->init_block.filter[i] = multicast_table[i];
+    }
+    lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */
+  } else {
+    lp->init_block.mode |= PROM;    /* Set promiscuous mode */
+  }
+
+  outw(CSR0, DEPCA_ADDR);
+  outw(IDON|INEA|STRT, DEPCA_DATA); /* Resume normal operation. */
+}
+
+/*
+** Calculate the hash code and update the logical address filter
+** from a list of ethernet multicast addresses.
+** Derived from a 'C' program in the AMD data book:
+** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", 
+** Pub #17781, Rev. A, May 1993
+*/
+static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table)
+{
+  char j, ctrl, bit, octet, hashcode;
+  short int i;
+  long int CRC, poly = (long int) CRC_POLYNOMIAL;
+
+  for (i=0;i<num_addrs;i++) {                /* for each address in the list */
+    if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* is multicast address? */ 
+      CRC = (long int) 0xffffffff;           /* init CRC for each address */
+      for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
+	for(j=0;j<8;j++) {                   /* process each address bit */
+	  bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
+	  ctrl = ((CRC < 0) ? 1 : 0);        /* shift the control bit */
+	  CRC <<= 1;                         /* shift the CRC */
+	  if (bit ^ ctrl) {                  /* (bit) XOR (control bit) */
+	    CRC ^= poly;                     /* (CRC) XOR (polynomial) */
+	  }
+	}
+      }
+      hashcode = (CRC & 0x00000001);         /* hashcode is 6 LSb of CRC ... */
+      for (j=0;j<5;j++) {                    /* ... in reverse order. */
+	hashcode <<= 1;
+	CRC >>= 1;
+	hashcode |= (CRC & 0x00000001);
+      }                                      
+      octet = hashcode >> 3;                  /* bit[3-5] -> octet in filter */
+                                              /* bit[0-2] -> bit in octet */
+      multicast_table[octet] |= (1 << (hashcode & 0x07));
+    }
+  }
+  return;
+}
+
+#endif  /* HAVE_MULTICAST */
+
+/*
+** Look for a particular board name in the on-board Remote Diagnostics
+** and Boot (RDB) ROM. This will also give us a clue to the network RAM
+** base address.
+*/
+static char *DepcaSignature(unsigned long mem_addr)
+{
+  unsigned long i,j,k;
+  static char signatures[][DEPCA_NAME_LENGTH] = DEPCA_SIGNATURE;
+  static char thisName[DEPCA_NAME_LENGTH];
+  char tmpstr[17];
+
+  for (i=0;i<16;i++) {                  /* copy the first 16 bytes of ROM to */
+    tmpstr[i] = *(unsigned char *)(mem_addr+0xc000+i); /* a temporary string */
+  }
+  tmpstr[i]=(char)NULL;
+
+  strcpy(thisName,"");
+  for (i=0;*signatures[i]!=(char)NULL && *thisName==(char)NULL;i++) {
+    for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) {
+      if (signatures[i][k] == tmpstr[j]) {              /* track signature */
+	k++;
+      } else {                     /* lost signature; begin search again */
+	k=0;
+      }
+    }
+    if (k == strlen(signatures[i])) {
+      strcpy(thisName,signatures[i]);
+    }
+  }
+
+  return thisName;                    /* return the device name string */
+}
+
+/*
+** Look for a special sequence in the Ethernet station address PROM that
+** is common across all DEPCA products.
+*/
+
+static int DevicePresent(short ioaddr)
+{
+  static short fp=1,sigLength=0;
+  static char devSig[] = PROBE_SEQUENCE;
+  char data;
+  int i, j, status = 0;
+  static char asc2hex(char value);
+
+/* 
+** Convert the ascii signature to a hex equivalent & pack in place 
+*/
+  if (fp) {                               /* only do this once!... */
+    for (i=0,j=0;devSig[i]!=(char)NULL && !status;i+=2,j++) {
+      if ((devSig[i]=asc2hex(devSig[i]))>=0) {
+	devSig[i]<<=4;
+	if((devSig[i+1]=asc2hex(devSig[i+1]))>=0){
+	  devSig[j]=devSig[i]+devSig[i+1];
+	} else {
+	  status= -1;
+	}
+      } else {
+	status= -1;
+      }
+    }
+    sigLength=j;
+    fp = 0;
+  }
+
+/* 
+** Search the Ethernet address ROM for the signature. Since the ROM address
+** counter can start at an arbitrary point, the search must include the entire
+** probe sequence length plus the length of the (signature - 1).
+** Stop the search IMMEDIATELY after the signature is found so that the
+** PROM address counter is correctly positioned at the start of the
+** ethernet address for later read out.
+*/
+  if (!status) {
+    for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
+      data = inb(ioaddr);
+      if (devSig[j] == data) {    /* track signature */
+	j++;
+      } else {                    /* lost signature; begin search again */
+	j=0;
+      }
+    }
+
+    if (j!=sigLength) {
+      status = -ENODEV;           /* search failed */
+    }
+  }
+
+  return status;
+}
+
+static char asc2hex(char value)
+{
+  value -= 0x30;                  /* normalise to 0..9 range */
+  if (value >= 0) {
+    if (value > 9) {              /* but may not be 10..15 */
+      value &= 0x1f;              /* make A..F & a..f be the same */
+      value -= 0x07;              /* normalise to 10..15 range */
+      if ((value < 0x0a) || (value > 0x0f)) { /* if outside range then... */
+	value = -1;               /* ...signal error */
+      }
+    }
+  } else {                        /* outside 0..9 range... */
+    value = -1;                   /* ...signal error */
+  }
+  return value;                   /* return hex char or error */
+}
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c depca.c"
+ * End:
+ */
+
+
+
diff --git a/drivers/net/depca.h b/drivers/net/depca.h
new file mode 100644
index 0000000..4f5d719
--- /dev/null
+++ b/drivers/net/depca.h
@@ -0,0 +1,128 @@
+/*
+    Written 1994 by David C. Davies.
+
+    Copyright 1994 David C. Davies. This software may be used and distributed
+    according to the terms of the GNU Public License, incorporated herein by
+    reference.
+*/
+
+/*
+** I/O addresses. Note that the 2k buffer option is not supported in
+** this driver.
+*/
+#define DEPCA_NICSR ioaddr+0x00   /* Network interface CSR */
+#define DEPCA_RBI   ioaddr+0x02   /* RAM buffer index (2k buffer mode) */
+#define DEPCA_DATA  ioaddr+0x04   /* LANCE registers' data port */
+#define DEPCA_ADDR  ioaddr+0x06   /* LANCE registers' address port */
+#define DEPCA_PROM  ioaddr+0x0c   /* Ethernet address ROM data port */
+#define DEPCA_RBSA  ioaddr+0x0e   /* RAM buffer starting address (2k buff.) */
+
+/*
+** These are LANCE registers addressable through DEPCA_ADDR 
+*/
+#define CSR0       0
+#define CSR1       1
+#define CSR2       2
+#define CSR3       3
+
+/* 
+** NETWORK INTERFACE CSR (NI_CSR) bit definitions 
+*/
+ 
+#define TO       	0x0100	/* Time Out for remote boot */
+#define SHE      	0x0080  /* SHadow memory Enable */
+#define BS       	0x0040  /* Bank Select */
+#define BUF      	0x0020	/* BUFfer size (1->32k, 0->64k) */
+#define RBE      	0x0010	/* Remote Boot Enable (1->net boot) */
+#define AAC      	0x0008  /* for DEPCA family compatability */
+#define IM       	0x0004	/* Interrupt Mask (1->mask) */
+#define IEN      	0x0002	/* Interrupt tristate ENable (1->enable) */
+#define LED      	0x0001	/* LED control */
+
+/* 
+** Control and Status Register 0 (CSR0) bit definitions 
+*/
+
+#define ERR     	0x8000 	/* Error summary */
+#define BABL    	0x4000 	/* Babble transmitter timeout error  */
+#define CERR    	0x2000 	/* Collision Error */
+#define MISS    	0x1000 	/* Missed packet */
+#define MERR    	0x0800 	/* Memory Error */
+#define RINT    	0x0400 	/* Receiver Interrupt */
+#define TINT    	0x0200 	/* Transmit Interrupt */
+#define IDON    	0x0100 	/* Initialization Done */
+#define INTR    	0x0080 	/* Interrupt Flag */
+#define INEA    	0x0040 	/* Interrupt Enable */
+#define RXON    	0x0020 	/* Receiver on */
+#define TXON    	0x0010 	/* Transmitter on */
+#define TDMD    	0x0008 	/* Transmit Demand */
+#define STOP    	0x0004 	/* Stop */
+#define STRT    	0x0002 	/* Start */
+#define INIT    	0x0001 	/* Initialize */
+
+/*
+** CONTROL AND STATUS REGISTER 3 (CSR3)
+*/
+
+#define BSWP    	0x0004	/* Byte SWaP */
+#define ACON    	0x0002	/* ALE control */
+#define BCON    	0x0001	/* Byte CONtrol */
+
+/*
+** Initialization Block Mode Register 
+*/
+
+#define PROM       	0x8000 	/* Promiscuous Mode */
+#define EMBA       	0x0080	/* Enable Modified Back-off Algorithm */
+#define INTL       	0x0040 	/* Internal Loopback */
+#define DRTY       	0x0020 	/* Disable Retry */
+#define COLL       	0x0010 	/* Force Collision */
+#define DTCR       	0x0008 	/* Disable Transmit CRC */
+#define LOOP       	0x0004 	/* Loopback */
+#define DTX        	0x0002 	/* Disable the Transmitter */
+#define DRX        	0x0001 	/* Disable the Receiver */
+
+/*
+** Receive Message Descriptor 1 (RMD1) bit definitions. 
+*/
+
+#define R_OWN       0x80000000 	/* Owner bit 0 = host, 1 = lance */
+#define R_ERR     	0x4000 	/* Error Summary */
+#define R_FRAM    	0x2000 	/* Framing Error */
+#define R_OFLO    	0x1000 	/* Overflow Error */
+#define R_CRC     	0x0800 	/* CRC Error */
+#define R_BUFF    	0x0400 	/* Buffer Error */
+#define R_STP     	0x0200 	/* Start of Packet */
+#define R_ENP     	0x0100 	/* End of Packet */
+
+/*
+** Transmit Message Descriptor 1 (TMD1) bit definitions. 
+*/
+
+#define T_OWN       0x80000000 	/* Owner bit 0 = host, 1 = lance */
+#define T_ERR     	0x4000 	/* Error Summary */
+#define T_ADD_FCS 	0x2000 	/* More the 1 retry needed to Xmit */
+#define T_MORE    	0x1000	/* >1 retry to transmit packet */
+#define T_ONE     	0x0800 	/* 1 try needed to transmit the packet */
+#define T_DEF     	0x0400 	/* Deferred */
+#define T_STP       0x02000000 	/* Start of Packet */
+#define T_ENP       0x01000000	/* End of Packet */
+
+/*
+** Transmit Message Descriptor 3 (TMD3) bit definitions.
+*/
+
+#define TMD3_BUFF    0x8000	/* BUFFer error */
+#define TMD3_UFLO    0x4000	/* UnderFLOw error */
+#define TMD3_RES     0x2000	/* REServed */
+#define TMD3_LCOL    0x1000	/* Late COLlision */
+#define TMD3_LCAR    0x0800	/* Loss of CARrier */
+#define TMD3_RTRY    0x0400	/* ReTRY error */
+
+/*
+** Miscellaneous
+*/
+
+#define MASK_INTERRUPTS   1
+#define UNMASK_INTERRUPTS 0
+
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index e6c3dbe..a8d8689 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -605,6 +605,7 @@
 	struct buffer_head * bh;
 	struct ext2_super_block * es;
 	unsigned long desc_count, bitmap_count, x;
+	unsigned long desc_blocks;
 	int bitmap_nr;
 	struct ext2_group_desc * gdp;
 	int i, j;
@@ -614,12 +615,24 @@
 	desc_count = 0;
 	bitmap_count = 0;
 	gdp = NULL;
+	desc_blocks = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
+		      EXT2_DESC_PER_BLOCK(sb);
 	for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
 		gdp = get_group_desc (sb, i, NULL);
 		desc_count += gdp->bg_free_blocks_count;
 		bitmap_nr = load_block_bitmap (sb, i);
 		bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
 
+		if (!test_bit (0, bh->b_data))
+			ext2_error (sb, "ext2_check_blocks_bitmap",
+				    "Superblock in group %d is marked free", i);
+
+		for (j = 0; j < desc_blocks; j++)
+			if (!test_bit (j + 1, bh->b_data))
+				ext2_error (sb, "ext2_check_blocks_bitmap",
+					    "Descriptor block #%d in group "
+					    "%d is marked free", j, i);
+
 		if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data))
 			ext2_error (sb, "ext2_check_blocks_bitmap",
 				    "Block bitmap for group %d is marked free",
@@ -632,9 +645,9 @@
 
 		for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++)
 			if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data))
-			ext2_error (sb, "ext2_check_blocks_bitmap",
-				    "Block #%d of the inode table in group %d "
-				    "is marked free", j, i);
+				ext2_error (sb, "ext2_check_blocks_bitmap",
+					    "Block #%d of the inode table in "
+					    "group %d is marked free", j, i);
 
 		x = ext2_count_free (bh, sb->s_blocksize);
 		if (gdp->bg_free_blocks_count != x)
diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c
index cc28496..b36598a 100644
--- a/fs/ext2/truncate.c
+++ b/fs/ext2/truncate.c
@@ -12,6 +12,11 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+/*
+ * Real random numbers for secure rm added 94/02/18
+ * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
+ */
+
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ext2_fs.h>
@@ -28,6 +33,10 @@
 		:"a" (value), "c" (size / 4), "D" ((long) (addr)) \
 		:"cx", "di")
 
+static int ext2_secrm_seed = 152;	/* Random generator base */
+
+#define RANDOM_INT (ext2_secrm_seed = ext2_secrm_seed * 69069l +1)
+
 /*
  * Truncate has the most races in the whole filesystem: coding it is
  * a pain in the a**. Especially as I don't do any locking...
@@ -80,7 +89,7 @@
 		inode->i_dirt = 1;
 		if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
 			clear_block (bh->b_data, inode->i_sb->s_blocksize,
-				     CURRENT_TIME);
+				     RANDOM_INT);
 			bh->b_dirt = 1;
 		}
 		brelse (bh);
@@ -156,7 +165,7 @@
 		ind_bh->b_dirt = 1;
 		if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) {
 			clear_block (bh->b_data, inode->i_sb->s_blocksize,
-				     CURRENT_TIME);
+				     RANDOM_INT);
 			bh->b_dirt = 1;
 		}
 		brelse (bh);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 932d26c..36f302d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -302,6 +302,8 @@
 extern struct task_struct *last_task_used_math;
 extern struct task_struct *current;
 extern unsigned long volatile jiffies;
+extern unsigned long itimer_ticks;
+extern unsigned long itimer_next;
 extern struct timeval xtime;
 extern int need_resched;
 
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 39d95e3..922029c 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -81,14 +81,23 @@
 		return k;
 	switch (which) {
 		case ITIMER_REAL:
+			if (j) {
+				j += 1+itimer_ticks;
+				if (j < itimer_next)
+					itimer_next = j;
+			}
 			current->it_real_value = j;
 			current->it_real_incr = i;
 			break;
 		case ITIMER_VIRTUAL:
+			if (j)
+				j++;
 			current->it_virt_value = j;
 			current->it_virt_incr = i;
 			break;
 		case ITIMER_PROF:
+			if (j)
+				j++;
 			current->it_prof_value = j;
 			current->it_prof_incr = i;
 			break;
diff --git a/kernel/sched.c b/kernel/sched.c
index a9f52ce..cbd4725 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -192,8 +192,8 @@
 
 #endif /* CONFIG_MATH_EMULATION */
 
-static unsigned long itimer_ticks = 0;
-static unsigned long itimer_next = ~0;
+unsigned long itimer_ticks = 0;
+unsigned long itimer_next = ~0;
 static unsigned long lost_ticks = 0;
 
 /*
diff --git a/net/inet/dev.c b/net/inet/dev.c
index a620738..5d8c570 100644
--- a/net/inet/dev.c
+++ b/net/inet/dev.c
@@ -966,7 +966,6 @@
 {
   struct iflink iflink;
   struct ddi_device *dev;
-  int ret;
 
   switch(cmd) {
 	case IP_SET_DEV:
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index dc06c75..30c48e2 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -60,7 +60,9 @@
  *		Charles Hedrick :	TCP fixes
  *		Toomas Tamm	:	TCP window fixes
  *		Alan Cox	:	Small URG fix to rlogin ^C ack fight
- *		Linus		:	Rewrote URG handling completely
+ *		Charles Hedrick	:	Window fix
+ *		Linus		:	Rewrote tcp_read() and URG handling
+ *					completely
  *
  *
  * To Fix:
@@ -1293,175 +1295,111 @@
 
 
 /* This routine copies from a sock struct into the user buffer. */
-static int
-tcp_read(struct sock *sk, unsigned char *to,
-	 int len, int nonblock, unsigned flags)
+static int tcp_read(struct sock *sk, unsigned char *to,
+	int len, int nonblock, unsigned flags)
 {
-  int copied = 0; /* will be used to say how much has been copied. */
-  struct sk_buff *skb;
-  unsigned long peek_seq;
-  unsigned long offset;
-  unsigned long *seq;
-  int err;
+	struct wait_queue wait = { current, NULL };
+	int copied = 0;
+	unsigned long peek_seq;
+	unsigned long *seq;
+	unsigned long used;
+	int err;
 
-  if (len == 0)
-  	return 0;
+	if (len == 0)
+		return 0;
 
-  if (len < 0)
-	return -EINVAL;
+	if (len < 0)
+		return -EINVAL;
 
-  err=verify_area(VERIFY_WRITE,to,len);
-  if (err)
-  	return err;
+	err = verify_area(VERIFY_WRITE, to, len);
+	if (err)
+		return err;
 
-  /* This error should be checked. */
-  if (sk->state == TCP_LISTEN)
-	return -ENOTCONN;
+	/* This error should be checked. */
+	if (sk->state == TCP_LISTEN)
+		return -ENOTCONN;
 
-  /* Urgent data needs to be handled specially. */
-  if (flags & MSG_OOB) 
-  	return tcp_read_urg(sk, nonblock, to, len, flags);
+	/* Urgent data needs to be handled specially. */
+	if (flags & MSG_OOB)
+		return tcp_read_urg(sk, nonblock, to, len, flags);
 
-  /* So no-one else will use this socket. */
-  sk->inuse = 1;
-  skb=skb_peek(&sk->rqueue);
+	peek_seq = sk->copied_seq;
+	seq = &sk->copied_seq;
+	if (flags & MSG_PEEK)
+		seq = &peek_seq;
 
-  peek_seq = sk->copied_seq;
-  seq = &sk->copied_seq;
-  if (flags & MSG_PEEK)
-	seq = &peek_seq;
-
-  DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n",
-						sk, to, len, nonblock, flags));
-
-  while(len > 0) {
-	/* skb->used just checks to see if we've gone all the way around. */
+	add_wait_queue(sk->sleep, &wait);
+	sk->inuse = 1;
+	while (len > 0) {
+		struct sk_buff * skb;
+		unsigned long offset;
 	
-	/* While no data, or first data indicates some is missing, or data is used */
-	while(skb == NULL || skb->used || before(1+*seq, skb->h.th->seq)) {
-		DPRINTF((DBG_TCP, "skb = %X:\n", skb));
-		cleanup_rbuf(sk);
-		if (sk->err) 
-		{
-			int tmp;
+		/*
+		 * are we at urgent data? Stop if we have read anything.
+		 */
+		if (copied && sk->urg_data && sk->urg_seq == 1+*seq)
+			break;
 
-			release_sock(sk);
-			if (copied) 
-			{
-				DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
-									copied));
-				return(copied);
-			}
-			tmp = -sk->err;
+		current->state = TASK_INTERRUPTIBLE;
+
+		skb = sk->rqueue;
+		do {
+			if (!skb)
+				break;
+			if (before(1+*seq, skb->h.th->seq))
+				break;
+			offset = 1 + *seq - skb->h.th->seq;
+			if (skb->h.th->syn)
+				offset--;
+			if (offset < skb->len)
+				goto found_ok_skb;
+			if (!(flags & MSG_PEEK))
+				skb->used = 1;
+			skb = (struct sk_buff *)skb->next;
+		} while (skb != sk->rqueue);
+
+		if (copied)
+			break;
+
+		if (sk->err) {
+			copied = -sk->err;
 			sk->err = 0;
-			return(tmp);
+			break;
 		}
 
-		if (sk->state == TCP_CLOSE) 
-		{
-			release_sock(sk);
-			if (copied) {
-				DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
-								copied));
-				return(copied);
-			}
+		if (sk->state == TCP_CLOSE) {
 			if (!sk->done) {
 				sk->done = 1;
-				return(0);
+				break;
 			}
-			return(-ENOTCONN);
+			copied = -ENOTCONN;
+			break;
 		}
 
-		if (sk->shutdown & RCV_SHUTDOWN) 
-		{
-			release_sock(sk);
-			if (copied == 0) sk->done = 1;
-			DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
-			return(copied);
+		if (sk->shutdown & RCV_SHUTDOWN) {
+			sk->done = 1;
+			break;
 		}
 			
-		if (nonblock || copied) 
-		{
-			release_sock(sk);
-			if(sk->debug)
-				printk("read: EAGAIN\n");
-			if (copied) 
-			{
-				DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
-								copied));
-				return(copied);
-			}
-			return(-EAGAIN);
+		if (nonblock) {
+			copied = -EAGAIN;
+			break;
 		}
 
-		if ((flags & MSG_PEEK) && copied != 0) 
-		{
-			release_sock(sk);
-			DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
-			return(copied);
-		}
-		 
-		DPRINTF((DBG_TCP, "tcp_read about to sleep. state = %d\n",
-								sk->state));
+		cleanup_rbuf(sk);
 		release_sock(sk);
-
-		/*
-		 * Now we may have some data waiting or we could
-		 * have changed state.
-		 */
-		cli();
-		if (sk->shutdown & RCV_SHUTDOWN || sk->err != 0) {
-			sk->inuse = 1;
-			sti();
-			continue;
-		}
-
-		skb = skb_peek(&sk->rqueue);
-		if (skb == NULL || before(1+*seq, skb->h.th->seq)) {
-		        if(sk->debug)
-		        	printk("Read wait sleep\n");
-			interruptible_sleep_on(sk->sleep);
-			if(sk->debug)
-				printk("Read wait wakes\n");
-			if (current->signal & ~current->blocked) {
-				sti();
-				if (copied) {
-					DPRINTF((DBG_TCP, "tcp_read: returning %d\n",
-								copied));
-					return(copied);
-				}
-				return(-ERESTARTSYS);
-			}
-		}
+		schedule();
 		sk->inuse = 1;
-		sti();
-		DPRINTF((DBG_TCP, "tcp_read woke up. \n"));
 
+		if (current->signal & ~current->blocked) {
+			copied = -ERESTARTSYS;
+			break;
+		}
+		continue;
 
-		skb=skb_peek(&sk->rqueue);
-		/* That may have been null if we were beaten, if so we loop again */
-	}
-
-	/*
-	 * are we at urgent data? Stop if we have read anything.
-	 */
-	if (copied && sk->urg_data && sk->urg_seq == 1+*seq) {
-		release_sock(sk);
-		return copied;
-	}
-
-	/*
-	 * Copy anything from the current block that needs
-	 * to go into the user buffer.
-	 */
-	 offset = *seq - skb->h.th->seq + 1;
-  
-	 if (skb->h.th->syn) offset--;
-
-	 if (offset < skb->len) /* Some of the packet is useful */
-	 {
+	found_ok_skb:
 		/* Ok so how much can we use ? */
-		unsigned long used = skb->len - offset;
+		used = skb->len - offset;
 		if (len < used)
 			used = len;
 		/* do we have urgent data here? */
@@ -1469,50 +1407,38 @@
 			unsigned long urg_offset = sk->urg_seq - (1 + *seq);
 			if (urg_offset < used) {
 				if (!urg_offset) {
-					if (!(flags & MSG_PEEK))
-						sk->urg_data = 0;
 					if (!sk->urginline) {
 						++*seq;
 						offset++;
 						used--;
 					}
 				} else
-					used = offset;
+					used = urg_offset;
 			}
 		}
 		/* Copy it */
 		memcpy_tofs(to,((unsigned char *)skb->h.th) +
-			    skb->h.th->doff*4 + offset, used);
+			skb->h.th->doff*4 + offset, used);
 		copied += used;
 		len -= used;
 		to += used;
 		*seq += used;
-	      
-		/*
-		 * Mark this data used if we are really reading it, and we
-		 * have used all the data.
-		 */
-		if (!(flags & MSG_PEEK) && (used + offset >= skb->len)) 
-		   	skb->used = 1;
-	} 
-	else 
-	{	/* already used this data, must be a retransmit */
-		if (!(flags & MSG_PEEK))
+		if (after(sk->copied_seq+1,sk->urg_seq))
+			sk->urg_data = 0;
+		if (!(flags & MSG_PEEK) && (used + offset >= skb->len))
 			skb->used = 1;
 	}
-	/* Move along a packet */
-	skb =(struct sk_buff *)skb->next;
-  }
-  /* Clean up data we have read: This will do ACK frames */
-  cleanup_rbuf(sk);
-  release_sock(sk);
-  DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
-  if (copied == 0 && nonblock) 
-  	return(-EAGAIN);
-  return(copied);
+	remove_wait_queue(sk->sleep, &wait);
+	current->state = TASK_RUNNING;
+
+	/* Clean up data we have read: This will do ACK frames */
+	cleanup_rbuf(sk);
+	release_sock(sk);
+	DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied));
+	return copied;
 }
 
-  
+ 
 /*
  * Send a FIN without closing the connection.
  * Not called at interrupt time.