diff -u --recursive --new-file v1.1.24/linux/Makefile linux/Makefile
--- v1.1.24/linux/Makefile	Thu Jul  7 21:37:11 1994
+++ linux/Makefile	Thu Jul  7 14:59:35 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 24
+SUBLEVEL = 25
 
 all:	Version zImage
 
@@ -39,6 +39,12 @@
 ROOT_DEV = CURRENT
 
 #
+# INSTALL_PATH specifies where to place the updated kernel and system map
+# images.  Uncomment if you want to place them anywhere other than root.
+
+#INSTALL_PATH=/boot
+
+#
 # If you want to preset the SVGA mode, uncomment the next line and
 # set SVGA_MODE to whatever number you want.
 # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
@@ -188,10 +194,10 @@
 	dd bs=8192 if=zImage of=/dev/fd0
 
 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 [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
+	if [ -f $(INSTALL_PATH)/zSystem.map ]; then mv $(INSTALL_PATH)/zSystem.map $(INSTALL_PATH)/zSystem.old; fi
+	cat zImage > $(INSTALL_PATH)/vmlinuz
+	cp zSystem.map $(INSTALL_PATH)/
 	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 -u --recursive --new-file v1.1.24/linux/config.in linux/config.in
--- v1.1.24/linux/config.in	Mon Jun 27 16:46:57 1994
+++ linux/config.in	Thu Jul  7 19:11:44 1994
@@ -80,6 +80,8 @@
 #  bool ' SLIP debugging on' SL_DUMP y
 fi
 bool 'PPP (point-to-point) support' CONFIG_PPP n
+bool 'PLIP (parallel port) support' CONFIG_PLIP n
+bool 'SK_G16 support' CONFIG_SK_G16 n
 bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
 bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
 bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
@@ -104,15 +106,14 @@
 	bool 'DEPCA support' CONFIG_DEPCA n
 	if [ "$CONFIG_NET_ALPHA" = "y" ]; then
 		bool 'EtherExpress support' CONFIG_EEXPRESS n
+		bool 'AT1700 support' CONFIG_AT1700 n
 	fi
 	bool 'HP PCLAN support' CONFIG_HPLAN n
 	bool 'NE2000/NE1000 support' CONFIG_NE2000 n
 fi
-bool 'PLIP (parallel port) support' CONFIG_PLIP n
 bool 'EISA and on board controllers' CONFIG_NET_EISA n
 	if [ "$CONFIG_NET_ALPHA" = "y" ]; then
 		bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
-		bool 'AT1700 support' CONFIG_AT1700 n
 	fi
 	bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
 #bool 'NI52EE support' CONFIG_NI52 n
diff -u --recursive --new-file v1.1.24/linux/drivers/block/cdu31a.c linux/drivers/block/cdu31a.c
--- v1.1.24/linux/drivers/block/cdu31a.c	Tue Jun 21 14:16:19 1994
+++ linux/drivers/block/cdu31a.c	Thu Jul  7 18:22:08 1994
@@ -64,6 +64,58 @@
  *
  */
 
+/*
+ *
+ * Setting up the Sony CDU31A/CDU33A drive interface card.  If
+ * You have another card, you are on your own.
+ * 
+ *      +----------+-----------------+----------------------+
+ *      |  JP1     |  34 Pin Conn    |     		    |
+ *      |  JP2     +-----------------+     		    |
+ *      |  JP3     	        			    |
+ *      |  JP4     	        			    |
+ *      |			        		    +--+
+ *      |			                            |  +-+
+ *      |			        		    |  | |  External
+ *      |			        		    |  | |  Connector
+ *      |						    |  | |
+ *      |						    |  +-+
+ *      |						    +--+
+ *      |						    |
+ *      |					   +--------+
+ *      |					   |
+ *      +------------------------------------------+
+ * 
+ *    JP1 sets the Base Address, using the following settings:
+ * 
+ * 	Address		Pin 1		Pin 2
+ * 	-------		-----		-----
+ * 	0x320		Short		Short
+ * 	0x330		Short		Open
+ * 	0x340		Open		Short
+ * 	0x360		Open		Open
+ * 
+ *    JP2 and JP3 configure the DMA channel; they must be set the same.
+ * 
+ * 	DMA		Pin 1		Pin 2		Pin 3
+ * 	---		-----		-----		-----
+ * 	1		On		Off		On
+ * 	2		Off		On		Off
+ * 	3		Off		Off		On
+ * 
+ *    JP4 Configures the IRQ:
+ * 
+ * 	IRQ	Pin 1		Pin 2		Pin 3		Pin 4
+ * 	---	-----		-----		-----		-----
+ * 	3	Off		Off		On		Off
+ * 	4	Off		Off*		Off		On
+ * 	5	On		Off		Off		Off
+ * 	6	Off		On		Off		Off
+ * 
+ * 		* The documentation states to set this for interrupt
+ * 		  4, but I think that is a mistake.
+ */
+
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -110,6 +162,8 @@
    { 0x360,	-1,	0 },	/* Secondary standard Sony Interface */
    { 0x320,	-1,	0 },	/* Secondary standard Sony Interface */
    { 0x330,	-1,	0 },	/* Secondary standard Sony Interface */
+   { 0x634,	-1,	0 },	/* Sound FX SC400 */
+   { 0x654,	-1,	0 },	/* Sound FX SC400 */
    { 0 }
 };
 
@@ -201,6 +255,8 @@
 static int curr_control_reg = 0; /* Current value of the control register */
 
 
+#if 1 /* This will go away as soon as the isofs code is fixed
+         to use the fops struct. */
 /*
  * This routine returns 1 if the disk has been changed since the last
  * check or 0 if it hasn't.  Setting flag to 0 resets the changed flag.
@@ -226,6 +282,30 @@
 
    return retval;
 }
+#endif
+
+/*
+ * This routine returns 1 if the disk has been changed since the last
+ * check or 0 if it hasn't.  Setting flag to 0 resets the changed flag.
+ */
+static int
+scd_disk_change(dev_t full_dev)
+{
+   int retval, target;
+
+
+   target = MINOR(full_dev);
+
+   if (target > 0) {
+      printk("Sony CD-ROM request error: invalid device.\n");
+      return 0;
+   }
+
+   retval = sony_disc_changed;
+   sony_disc_changed = 0;
+
+   return retval;
+}
 
 static inline void
 enable_interrupts(void)
@@ -1823,7 +1903,10 @@
    NULL,                   /* mmap */
    scd_open,               /* open */
    scd_release,            /* release */
-   NULL                    /* fsync */
+   NULL,                   /* fsync */
+   NULL,		   /* fasync */
+   scd_disk_change,	   /* media_change */
+   NULL			   /* revalidate */
 };
 
 
diff -u --recursive --new-file v1.1.24/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.24/linux/drivers/block/floppy.c	Thu Jul  7 21:37:11 1994
+++ linux/drivers/block/floppy.c	Thu Jul  7 19:09:36 1994
@@ -74,6 +74,8 @@
 #define FLOPPY_DMA 2
 #define FDC_FIFO_UNTESTED           /* -bb */
 
+#define FDC_FIFO_BUG
+
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -287,8 +289,8 @@
 static void floppy_ready(void);
 static void recalibrate_floppy(void);
 
-static int floppy_grab_irq_and_dma(void);
-static void floppy_release_irq_and_dma(void);
+int floppy_grab_irq_and_dma(void);
+void floppy_release_irq_and_dma(void);
 
 /*
  * These are global variables, as that's the easiest way to give
@@ -506,6 +508,32 @@
 	printk("Unable to send byte to FDC\n");
 }
 
+#ifdef FDC_FIFO_BUG
+
+static void output_byte_force(char byte)
+{
+	int counter;
+	unsigned char status;
+
+	if (reset)
+		return;
+	for (counter = 0 ; counter < 10000 ; counter++) {
+		status = inb_p(FD_STATUS);
+		if ((status & (STATUS_READY | STATUS_DIR)) == STATUS_READY) {
+			outb(byte,FD_DATA);
+			return;
+		}
+		if ((status & (STATUS_READY | STATUS_BUSY)) == (STATUS_READY | STATUS_BUSY)) {
+			outb(byte,FD_DATA);
+			return;
+		}
+	}
+	current_track = NO_TRACK;
+	reset = 1;
+	printk("Unable to send byte to FDC\n");
+}
+#endif		/* FDC_FIFO_BUG */
+
 static int result(void)
 {
 	int i = 0, counter, status;
@@ -565,15 +593,27 @@
 		if (rate & 0x40) {
 			unsigned char r = rate & 0x03;
 			if (r == 0)
+#ifndef FDC_FIFO_BUG
 				output_byte(2);	/* perpendicular, 500 kbps */
+#else
+				output_byte_force(2);	/* perpendicular, 500 kbps */
+#endif
 			else if (r == 3)
+#ifndef FDC_FIFO_BUG
 				output_byte(3);	/* perpendicular, 1Mbps */
+#else
+				output_byte_force(3);	/* perpendicular, 1Mbps */
+#endif
 			else {
 				printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
 				reset = 1;
 			}
 		} else
+#ifndef FDC_FIFO_BUG
 			output_byte(0);		/* conventional mode */
+#else
+			output_byte_force(0);		/* conventional mode */
+#endif
 	} else {
 		if (rate & 0x40) {
 			printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n");
@@ -594,9 +634,17 @@
 	if (need_configure && (fdc_version == FDC_TYPE_82077)) {
 		/* Enhanced version with FIFO & vertical recording. */
 		output_byte(FD_CONFIGURE);
+#ifndef FDC_FIFO_BUG
 		output_byte(0);
+#else
+		output_byte_force(0);
+#endif
 		output_byte(0x1A);	/* FIFO on, polling off, 10 byte threshold */
+#ifndef FDC_FIFO_BUG
 		output_byte(0);		/* precompensation from track 0 upwards */
+#else
+		output_byte_force(0);		/* precompensation from track 0 upwards */
+#endif
 		need_configure = 0;
 		printk(DEVICE_NAME ": FIFO enabled\n");
 	}
@@ -1403,7 +1451,7 @@
 
 static int usage_count = 0;
 
-static int floppy_grab_irq_and_dma(void)
+int floppy_grab_irq_and_dma(void)
 {
 	if (usage_count++)
 		return 0;
@@ -1420,7 +1468,7 @@
 	return 0;
 }
 
-static void floppy_release_irq_and_dma(void)
+void floppy_release_irq_and_dma(void)
 {
 	if (--usage_count)
 		return;
diff -u --recursive --new-file v1.1.24/linux/drivers/block/mcd.c linux/drivers/block/mcd.c
--- v1.1.24/linux/drivers/block/mcd.c	Tue May 24 08:47:06 1994
+++ linux/drivers/block/mcd.c	Thu Jul  7 21:26:20 1994
@@ -30,6 +30,13 @@
 		   (Jon Tombs <jon@robots.ox.ac.uk>)
         0.3.3 Added more #defines and mcd_setup()
    		   (Jon Tombs <jon@gtex02.us.es>)
+
+	October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
+	Braunschweig, Germany: Total rework to speed up data read operation.
+	Also enabled definition of irq and address from bootstrap, using the
+	environment. linux/init/main.c must be patched to export the env.
+	November 93 added code for FX001 S,D (single & double speed).
+	February 94 added code for broken M 5/6 series of 16-bit single speed.
 */
 
 
@@ -41,6 +48,8 @@
 #include <linux/kernel.h>
 #include <linux/cdrom.h>
 #include <linux/ioport.h>
+#include <linux/string.h>
+#include <linux/delay.h>
 
 /* #define REALLY_SLOW_IO  */
 #include <asm/system.h>
@@ -57,8 +66,53 @@
 
 static int mcdPresent = 0;
 
-static char mcd_buf[2048];	/* buffer for block size conversion */
-static int   mcd_bn   = -1;
+#if 0
+#define TEST1 /* <int-..> */
+#define TEST2 /* do_mcd_req */
+#define TEST3 */ /* MCD_S_state */
+#define TEST4 /* QUICK_LOOP-counter */
+#define TEST5 */ /* port(1) state */
+#endif
+
+#if 1
+#define QUICK_LOOP_DELAY udelay(45)  /* use udelay */
+#define QUICK_LOOP_COUNT 20
+#else
+#define QUICK_LOOP_DELAY
+#define QUICK_LOOP_COUNT 140 /* better wait constant time */
+#endif
+/* #define DOUBLE_QUICK_ONLY */
+
+#define CURRENT_VALID \
+  (CURRENT && MAJOR(CURRENT -> dev) == MAJOR_NR && CURRENT -> cmd == READ \
+   && CURRENT -> sector != -1)
+#define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
+#define MCD_BUF_SIZ 16
+static volatile int mcd_transfer_is_active;
+static char mcd_buf[2048*MCD_BUF_SIZ];	/* buffer for block size conversion */
+static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
+static volatile int mcd_buf_in, mcd_buf_out = -1;
+static volatile int mcd_error;
+static int mcd_open_count;
+enum mcd_state_e {
+  MCD_S_IDLE,   /* 0 */
+  MCD_S_START,  /* 1 */
+  MCD_S_MODE, /* 2 */
+  MCD_S_READ,   /* 3 */
+  MCD_S_DATA,   /* 4 */
+  MCD_S_STOP,   /* 5 */
+  MCD_S_STOPPING /* 6 */
+};
+static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
+static int mcd_mode = -1;
+static int MCMD_DATA_READ= MCMD_PLAY_READ;
+#define READ_TIMEOUT 3000
+#define WORK_AROUND_MITSUMI_BUG_92
+#define WORK_AROUND_MITSUMI_BUG_93
+#ifdef WORK_AROUND_MITSUMI_BUG_93
+int mitsumi_bug_93_wait = 0;
+#endif /* WORK_AROUND_MITSUMI_BUG_93 */
+
 static short mcd_port = MCD_BASE_ADDR;
 static int   mcd_irq  = MCD_INTR_NR;
 
@@ -75,10 +129,8 @@
 static char mcdVersion;
 
 static void mcd_transfer(void);
-static void mcd_start(void);
-static void mcd_status(void);
-static void mcd_read_cmd(void);
-static void mcd_data(void);
+static void mcd_poll(void);
+static void mcd_invalidate_buffers(void);
 static void do_mcd_request(void);
 static void hsg2msf(long hsg, struct msf *msf);
 static void bin2bcd(unsigned char *p);
@@ -99,6 +151,10 @@
       mcd_port = ints[1];
    if (ints[0] > 1)      
       mcd_irq  = ints[2];
+#ifdef WORK_AROUND_MITSUMI_BUG_93
+   if (ints[0] > 2)
+      mitsumi_bug_93_wait = ints[3];
+#endif /* WORK_AROUND_MITSUMI_BUG_93 */
 }
 
  
@@ -507,16 +563,34 @@
 static void
 mcd_transfer(void)
 {
-	long offs;
-
-	while (CURRENT -> nr_sectors > 0 && mcd_bn == CURRENT -> sector / 4)
-	{
-		offs = (CURRENT -> sector & 3) * 512;
-		memcpy(CURRENT -> buffer, mcd_buf + offs, 512);
-		CURRENT -> nr_sectors--;
-		CURRENT -> sector++;
-		CURRENT -> buffer += 512;
-	}
+  if (CURRENT_VALID) {
+    while (CURRENT -> nr_sectors) {
+      int bn = CURRENT -> sector / 4;
+      int i;
+      for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
+	;
+      if (i < MCD_BUF_SIZ) {
+	int offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
+	int nr_sectors = 4 - (CURRENT -> sector & 3);
+	if (mcd_buf_out != i) {
+	  mcd_buf_out = i;
+	  if (mcd_buf_bn[i] != bn) {
+	    mcd_buf_out = -1;
+	    continue;
+	  }
+	}
+	if (nr_sectors > CURRENT -> nr_sectors)
+	  nr_sectors = CURRENT -> nr_sectors;
+	memcpy(CURRENT -> buffer, mcd_buf + offs, nr_sectors * 512);
+	CURRENT -> nr_sectors -= nr_sectors;
+	CURRENT -> sector += nr_sectors;
+	CURRENT -> buffer += nr_sectors * 512;
+      } else {
+	mcd_buf_out = -1;
+	break;
+      }
+    }
+  }
 }
 
 
@@ -531,220 +605,419 @@
 	int st;
 
 	st = inb(MCDPORT(1)) & 0xFF;
-	if (st != 0xFF)
+#ifdef TEST1
+		printk("<int1-%02X>", st);
+#endif
+	if (!(st & MFL_STATUS))
 	{
 		st = inb(MCDPORT(0)) & 0xFF;
-#if 0
-		printk("<int-%02X>", st);
+#ifdef TEST1
+		printk("<int0-%02X>", st);
 #endif
+		if ((st & 0xFF) != 0xFF)
+		  mcd_error = st ? st & 0xFF : -1;
 	}
 }
 
 
-/*
- * I/O request routine called from Linux kernel.
- */
-
 static void
 do_mcd_request(void)
 {
-	unsigned int block,dev;
-	unsigned int nsect;
+#ifdef TEST2
+  printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors);
+#endif
+  mcd_transfer_is_active = 1;
+  while (CURRENT_VALID) {
+    if (CURRENT->bh) {
+      if (!CURRENT->bh->b_lock)
+	panic(DEVICE_NAME ": block not locked");
+    }
+    mcd_transfer();
+    if (CURRENT -> nr_sectors == 0) {
+      end_request(1);
+    } else {
+      mcd_buf_out = -1;		/* Want to read a block not in buffer */
+      if (mcd_state == MCD_S_IDLE) {
+	if (!tocUpToDate) {
+	  if (updateToc() < 0) {
+	    while (CURRENT_VALID)
+	      end_request(0);
+	    break;
+	  }
+	}
+	mcd_state = MCD_S_START;
+	McdTries = 5;
+	SET_TIMER(mcd_poll, 1);
+      }
+      break;
+    }
+  }
+  mcd_transfer_is_active = 0;
+#ifdef TEST2
+  printk(" do_mcd_request ends\n");
+#endif
+}
 
-repeat:
-	if (!(CURRENT) || CURRENT->dev < 0) return;
-	INIT_REQUEST;
-	dev = MINOR(CURRENT->dev);
-	block = CURRENT->sector;
-	nsect = CURRENT->nr_sectors;
 
-	if (CURRENT == NULL || CURRENT -> sector == -1)
-		return;
 
-	if (CURRENT -> cmd != READ)
-	{
-		printk("mcd: bad cmd %d\n", CURRENT -> cmd);
-		end_request(0);
-		goto repeat;
+static void
+mcd_poll(void)
+{
+  int st;
+
+
+  if (mcd_error) {
+    if (mcd_error & 0xA5) {
+      printk("mcd: I/O error 0x%02x", mcd_error);
+      if (mcd_error & 0x80)
+	printk(" (Door open)");
+      if (mcd_error & 0x20)
+	printk(" (Disk changed)");
+      if (mcd_error & 0x04)
+	printk(" (Read error)");
+      printk("\n");
+      mcd_invalidate_buffers();
+#ifdef WARN_IF_READ_FAILURE
+      if (McdTries == 5)
+	printk("mcd: read of block %d failed\n", mcd_next_bn);
+#endif
+      if (!McdTries--) {
+	printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
+	if (mcd_transfer_is_active) {
+	  McdTries = 0;
+	  goto ret;
 	}
+	if (CURRENT_VALID)
+	  end_request(0);
+	McdTries = 5;
+      }
+    }
+    mcd_error = 0;
+    mcd_state = MCD_S_STOP;
+  }
 
-	mcd_transfer();
 
-	/* if we satisfied the request from the buffer, we're done. */
 
-	if (CURRENT -> nr_sectors == 0)
-	{
-		end_request(1);
-		goto repeat;
-	}
+ immediatly:
+  switch (mcd_state) {
 
-	McdTries = MCD_RETRY_ATTEMPTS;
-	mcd_start();
-}
 
 
-/*
- * Start the I/O for the cdrom. Handle retry count.
- */
+  case MCD_S_IDLE:
+#ifdef TEST3
+    printk("MCD_S_IDLE\n");
+#endif
+    return;
 
-static void
-mcd_start()
-{
-	if (McdTries == 0)
-	{
-		printk("mcd: read failed after %d tries\n", MCD_RETRY_ATTEMPTS);
-		end_request(0);
-		SET_TIMER(do_mcd_request, 1);	/* wait a bit, try again */
-		return;
-	}
 
-	McdTries--;
-	outb(0x40, MCDPORT(0));		/* get status */
-	McdTimeout = MCD_STATUS_DELAY;
-	SET_TIMER(mcd_status, 1);
-}
 
+  case MCD_S_START:
+#ifdef TEST3
+    printk("MCD_S_START\n");
+#endif
 
-/*
- * Called from the timer to check the results of the get-status cmd.
- * On success, send the set-mode command.
- */
+    outb(MCMD_GET_STATUS, MCDPORT(0));
+    mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
+    McdTimeout = 3000;
+    break;
 
-static void
-mcd_status()
-{
-	int st;
 
-	McdTimeout--;
-	st = mcdStatus();
-	if (st == -1)
-	{
-		if (McdTimeout == 0)
-		{
-			printk("mcd: status timed out\n");
-			SET_TIMER(mcd_start, 1);	/* wait a bit, try again */
-			return;
-		}
 
-		SET_TIMER(mcd_status, 1);
-		return;
-	}
+  case MCD_S_MODE:
+#ifdef TEST3
+    printk("MCD_S_MODE\n");
+#endif
 
-	if (st & MST_DSK_CHG)
-	{
-		mcdDiskChanged = 1;
-	}
-	
-	if ((st & MST_READY) == 0)
-	{
-		printk("mcd: disk removed\n");
-		mcdDiskChanged = 1;		
-		end_request(0);
-		do_mcd_request();
-		return;
-	}
+    if ((st = mcdStatus()) != -1) {
 
-	outb(0x50, MCDPORT(0));	/* set mode */
-	outb(0x01, MCDPORT(0));	/* mode = cooked data */
-	McdTimeout = 100;
-	SET_TIMER(mcd_read_cmd, 1);
-}
+      if (st & MST_DSK_CHG) {
+	mcdDiskChanged = 1;
+	tocUpToDate = 0;
+	mcd_invalidate_buffers();
+      }
+
+    set_mode_immediatly:
+
+      if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
+	mcdDiskChanged = 1;
+	tocUpToDate = 0;
+	if (mcd_transfer_is_active) {
+	  mcd_state = MCD_S_START;
+	  goto immediatly;
+	}
+	printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
+	mcd_state = MCD_S_IDLE;
+	while (CURRENT_VALID)
+	  end_request(0);
+	return;
+      }
+
+      outb(MCMD_SET_MODE, MCDPORT(0));
+      outb(1, MCDPORT(0));
+      mcd_mode = 1;
+      mcd_state = MCD_S_READ;
+      McdTimeout = 3000;
+
+    }
+    break;
 
 
-/*
- * Check the result of the set-mode command.  On success, send the
- * read-data command.
- */
 
-static void
-mcd_read_cmd()
-{
-	int st;
-	long block;
-	struct mcd_Play_msf mcdcmd;
+  case MCD_S_READ:
+#ifdef TEST3
+    printk("MCD_S_READ\n");
+#endif
 
-	McdTimeout--;
-	st = mcdStatus();
+    if ((st = mcdStatus()) != -1) {
 
-	if (st & MST_DSK_CHG)
-	{
-		mcdDiskChanged = 1;
-	}
-	
-	if (st == -1)
-	{
-		if (McdTimeout == 0)
-		{
-			printk("mcd: set mode timed out\n");
-			SET_TIMER(mcd_start, 1);	/* wait a bit, try again */
-			return;
-		}
+      if (st & MST_DSK_CHG) {
+	mcdDiskChanged = 1;
+	tocUpToDate = 0;
+	mcd_invalidate_buffers();
+      }
+
+    read_immediatly:
+
+      if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
+	mcdDiskChanged = 1;
+	tocUpToDate = 0;
+	if (mcd_transfer_is_active) {
+	  mcd_state = MCD_S_START;
+	  goto immediatly;
+	}
+	printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
+	mcd_state = MCD_S_IDLE;
+	while (CURRENT_VALID)
+	  end_request(0);
+	return;
+      }
+
+      if (CURRENT_VALID) {
+	struct mcd_Play_msf msf;
+	mcd_next_bn = CURRENT -> sector / 4;
+	hsg2msf(mcd_next_bn, &msf.start);
+	msf.end.min = ~0;
+	msf.end.sec = ~0;
+	msf.end.frame = ~0;
+	sendMcdCmd(MCMD_DATA_READ, &msf);
+	mcd_state = MCD_S_DATA;
+	McdTimeout = READ_TIMEOUT;
+      } else {
+	mcd_state = MCD_S_STOP;
+	goto immediatly;
+      }
+
+    }
+    break;
+
+
+  case MCD_S_DATA:
+#ifdef TEST3
+    printk("MCD_S_DATA\n");
+#endif
 
-		SET_TIMER(mcd_read_cmd, 1);
-		return;
-	}
+    st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
+  data_immediatly:
+#ifdef TEST5
+    printk("Status %02x\n",st);
+#endif
+    switch (st) {
 
-	mcd_bn = -1;			/* purge our buffer */
-	block = CURRENT -> sector / 4;
-	hsg2msf(block, &mcdcmd.start);	/* cvt to msf format */
-
-	mcdcmd.end.min = 0;
-	mcdcmd.end.sec = 0;
-	mcdcmd.end.frame = 1;
-
-	sendMcdCmd(MCMD_PLAY_READ, &mcdcmd);	/* read command */
-	McdTimeout = 200;
-	SET_TIMER(mcd_data, 1);
-}
+    case MFL_DATA:
+#ifdef WARN_IF_READ_FAILURE
+      if (McdTries == 5)
+	printk("mcd: read of block %d failed\n", mcd_next_bn);
+#endif
+      if (!McdTries--) {
+	printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
+	if (mcd_transfer_is_active) {
+	  McdTries = 0;
+	  break;
+	}
+	if (CURRENT_VALID)
+	  end_request(0);
+	McdTries = 5;
+      }
+      mcd_state = MCD_S_START;
+      McdTimeout = READ_TIMEOUT;
+      goto immediatly;
+
+    case MFL_STATUSorDATA:
+      break;
+
+    default:
+      McdTries = 5;
+      if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {
+	mcd_state = MCD_S_STOP;
+	goto immediatly;
+      }
+      mcd_buf_bn[mcd_buf_in] = -1;
+      READ_DATA(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in, 2048);
+      mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
+      if (mcd_buf_out == -1)
+	mcd_buf_out = mcd_buf_in;
+      mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
+      if (!mcd_transfer_is_active) {
+	while (CURRENT_VALID) {
+	  mcd_transfer();
+	  if (CURRENT -> nr_sectors == 0)
+	    end_request(1);
+	  else
+	    break;
+	}
+      }
+
+      if (CURRENT_VALID
+	  && (CURRENT -> sector / 4 < mcd_next_bn || 
+	      CURRENT -> sector / 4 > mcd_next_bn + 16)) {
+	mcd_state = MCD_S_STOP;
+	goto immediatly;
+      }
+      McdTimeout = READ_TIMEOUT;
+#ifdef DOUBLE_QUICK_ONLY
+      if (MCMD_DATA_READ != MCMD_PLAY_READ)
+#endif
+      {
+	int count= QUICK_LOOP_COUNT;
+	while (count--) {
+          QUICK_LOOP_DELAY;
+	  if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
+#   ifdef TEST4
+/*	    printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */
+	    printk(" %d ",QUICK_LOOP_COUNT-count);
+#   endif
+	    goto data_immediatly;
+	  }
+	}
+#   ifdef TEST4
+/*      printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */
+	printk("ended ");
+#   endif
+      }
+      break;
+    }
+    break;
 
 
-/*
- * Check the completion of the read-data command.  On success, read
- * the 2048 bytes of data from the disk into our buffer.
- */
 
-static void
-mcd_data()
-{
-	int i;
+  case MCD_S_STOP:
+#ifdef TEST3
+    printk("MCD_S_STOP\n");
+#endif
 
-	McdTimeout--;
-	cli();
-	i =inb(MCDPORT(1)) & (MFL_STATUS | MFL_DATA);
-	if (i == MFL_DATA)
-	{
-		printk("mcd: read failed\n");
-#ifdef MCD_DEBUG
-		printk("got 0xB %02X\n", inb(MCDPORT(0)) & 0xFF);
+#ifdef WORK_AROUND_MITSUMI_BUG_93
+    if (!mitsumi_bug_93_wait)
+      goto do_not_work_around_mitsumi_bug_93_1;
+
+    McdTimeout = mitsumi_bug_93_wait;
+    mcd_state = 9+3+1;
+    break;
+
+  case 9+3+1:
+    if (McdTimeout)
+      break;
+
+  do_not_work_around_mitsumi_bug_93_1:
+#endif /* WORK_AROUND_MITSUMI_BUG_93 */
+
+    outb(MCMD_STOP, MCDPORT(0));
+
+#ifdef WORK_AROUND_MITSUMI_BUG_92
+    if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
+      int i = 4096;
+      do {
+	inb(MCDPORT(0));
+      } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
+      outb(MCMD_STOP, MCDPORT(0));
+      if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
+	i = 4096;
+	do {
+	  inb(MCDPORT(0));
+	} while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
+	outb(MCMD_STOP, MCDPORT(0));
+      }
+    }
+#endif /* WORK_AROUND_MITSUMI_BUG_92 */
+
+    mcd_state = MCD_S_STOPPING;
+    McdTimeout = 1000;
+    break;
+
+  case MCD_S_STOPPING:
+#ifdef TEST3
+    printk("MCD_S_STOPPING\n");
 #endif
-		SET_TIMER(mcd_start, 1);
-		sti();
-		return;
-	}
-	
-	if (i == (MFL_STATUS | MFL_DATA))
-	{
-		if (McdTimeout == 0)
-		{
-			printk("mcd: data timeout, retrying\n");
-			SET_TIMER(mcd_start, 1);
-		}
-		
-		else
-			SET_TIMER(mcd_data, 1);
-		
-		sti();
-		return;
-	}
+
+    if ((st = mcdStatus()) == -1 && McdTimeout)
+      break;
+
+    if ((st != -1) && (st & MST_DSK_CHG)) {
+      mcdDiskChanged = 1;
+      tocUpToDate = 0;
+      mcd_invalidate_buffers();
+    }
+
+#ifdef WORK_AROUND_MITSUMI_BUG_93
+    if (!mitsumi_bug_93_wait)
+      goto do_not_work_around_mitsumi_bug_93_2;
+
+    McdTimeout = mitsumi_bug_93_wait;
+    mcd_state = 9+3+2;
+    break;
+
+  case 9+3+2:
+    if (McdTimeout)
+      break;
+
+    st = -1;
+
+  do_not_work_around_mitsumi_bug_93_2:
+#endif /* WORK_AROUND_MITSUMI_BUG_93 */
+
+#ifdef TEST3
+    printk("CURRENT_VALID %d mcd_mode %d\n",
+	   CURRENT_VALID, mcd_mode);
+#endif
+
+    if (CURRENT_VALID) {
+      if (st != -1) {
+	if (mcd_mode == 1)
+	  goto read_immediatly;
+	else
+	  goto set_mode_immediatly;
+      } else {
+	mcd_state = MCD_S_START;
+	McdTimeout = 1;
+      }
+    } else {
+      mcd_state = MCD_S_IDLE;
+      return;
+    }
+    break;
+
+  default:
+    printk("mcd: invalid state %d\n", mcd_state);
+    return;
+  }
+
+ ret:
+  if (!McdTimeout--) {
+    printk("mcd: timeout in state %d\n", mcd_state);
+    mcd_state = MCD_S_STOP;
+  }
+
+  SET_TIMER(mcd_poll, 1);
+}
+
 
-	CLEAR_TIMER;
-	READ_DATA(MCDPORT(0), &mcd_buf[0], 2048);
-	sti();
-
-	mcd_bn = CURRENT -> sector / 4;
-	mcd_transfer();
-	end_request(1);
-	SET_TIMER(do_mcd_request, 1);
+
+static void
+mcd_invalidate_buffers(void)
+{
+  int i;
+  for (i = 0; i < MCD_BUF_SIZ; ++i)
+    mcd_buf_bn[i] = -1;
+  mcd_buf_out = -1;
 }
 
 
@@ -760,6 +1033,10 @@
 	if (mcdPresent == 0)
 		return -ENXIO;			/* no hardware */
 
+	if (!mcd_open_count && mcd_state == MCD_S_IDLE) {
+
+	mcd_invalidate_buffers();
+
 	st = statusCmd();			/* check drive status */
 	if (st == -1)
 		return -EIO;			/* drive doesn't respond */
@@ -773,6 +1050,9 @@
 	if (updateToc() < 0)
 		return -EIO;
 
+	}
+	++mcd_open_count;
+
 	return 0;
 }
 
@@ -784,9 +1064,11 @@
 static void
 mcd_release(struct inode * inode, struct file * file)
 {
-	mcd_bn = -1;
+  if (!--mcd_open_count) {
+	mcd_invalidate_buffers();
 	sync_dev(inode->i_rdev);
 	invalidate_buffers(inode -> i_rdev);
+  }
 }
 
 
@@ -799,7 +1081,8 @@
 	mcd_ioctl,		/* ioctl */
 	NULL,			/* mmap */
 	mcd_open,		/* open */
-	mcd_release		/* release */
+	mcd_release,		/* release */
+	NULL			/* fsync */
 };
 
 
@@ -825,15 +1108,22 @@
 	int count;
 	unsigned char result[3];
 
+	if (mcd_port <= 0 || mcd_irq <= 0) {
+	  printk("skip mcd_init\n");
+	  return mem_start;
+	}
+
+	printk("mcd=0x%x,%d: ", mcd_port, mcd_irq);
+
 	if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
 	{
-		printk("mcd: Unable to get major %d for Mitsumi CD-ROM\n",
+		printk("Unable to get major %d for Mitsumi CD-ROM\n",
 		       MAJOR_NR);
 		return mem_start;
 	}
 
         if (check_region(mcd_port, 4)) {
-	  printk("mcd: Init failed, I/O port (%X) already in use\n",
+	  printk("Init failed, I/O port (%X) already in use\n",
 		 mcd_port);
 	  return mem_start;
 	}
@@ -844,16 +1134,16 @@
 	/* check for card */
 
 	outb(0, MCDPORT(1));			/* send reset */
-	for (count = 0; count < 1000000; count++)
+	for (count = 0; count < 2000000; count++)
 		(void) inb(MCDPORT(1));		/* delay a bit */
 
 	outb(0x40, MCDPORT(0));			/* send get-stat cmd */
-	for (count = 0; count < 1000000; count++)
+	for (count = 0; count < 2000000; count++)
 		if (!(inb(MCDPORT(1)) & MFL_STATUS))
 			break;
 
-	if (count >= 1000000) {
-		printk("mcd: Init failed. No mcd device at 0x%x irq %d\n",
+	if (count >= 2000000) {
+		printk("Init failed. No mcd device at 0x%x irq %d\n",
 		     mcd_port, mcd_irq);
 		return mem_start;
 	}
@@ -862,7 +1152,7 @@
 	outb(MCMD_GET_VERSION,MCDPORT(0));
 	for(count=0;count<3;count++)
 		if(getValue(result+count)) {
-			printk("mcd: mitsumi get version failed at 0x%d\n",
+			printk("mitsumi get version failed at 0x%d\n",
 			       mcd_port);
 			return mem_start;
 		}	
@@ -870,9 +1160,10 @@
 	if (result[0] == result[1] && result[1] == result[2])
 		return mem_start;
 
-	printk("mcd: Mitsumi version : %02X %c %x\n",
+	printk("Mitsumi status, type and version : %02X %c %x\n",
 	       result[0],result[1],result[2]);
 
+	if (result[1] == 'D') MCMD_DATA_READ= 0xC1;
 
 	mcdVersion=result[2];
 
@@ -883,13 +1174,24 @@
 
 	if (irqaction(mcd_irq,  &mcd_sigaction))
 	{
-		printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
+		printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
 		return mem_start;
 	}
 	snarf_region(mcd_port, 4);
+
+	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
+	outb(0x02,MCDPORT(0));
+	outb(0x00,MCDPORT(0));
+	getValue(result);
+
+	outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
+	outb(0x10,MCDPORT(0));
+	outb(0x04,MCDPORT(0));
+	getValue(result);
+
+	mcd_invalidate_buffers();
 	mcdPresent = 1;
-	printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n",
-	       mcd_port, mcd_irq);
+	printk("\n");
 	return mem_start;
 }
 
@@ -1189,6 +1491,7 @@
 	{
 		outb(MCMD_SET_MODE, MCDPORT(0));
 		outb(0x05, MCDPORT(0));			/* mode: toc */
+		mcd_mode = 0x05;
 		if (getMcdStatus(MCD_STATUS_DELAY) != -1)
 			break;
 	}
@@ -1219,6 +1522,7 @@
 	{
                 outb(MCMD_SET_MODE, MCDPORT(0));
                 outb(0x01, MCDPORT(0));
+		mcd_mode = 1;
                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
                         break;
 	}
diff -u --recursive --new-file v1.1.24/linux/drivers/block/ramdisk.c linux/drivers/block/ramdisk.c
--- v1.1.24/linux/drivers/block/ramdisk.c	Tue Apr 19 10:52:42 1994
+++ linux/drivers/block/ramdisk.c	Thu Jul  7 19:09:36 1994
@@ -94,12 +94,7 @@
 	return(length);
 }
 
-/*
- * If the root device is the RAM disk, try to load it.
- * In order to do this, the root device is originally set to the
- * floppy, and we later change it to be RAM disk.
- */
-void rd_load(void)
+static void do_load(void)
 {
 	struct buffer_head *bh;
 	struct minix_super_block s;
@@ -108,14 +103,6 @@
 	int		nblocks;
 	char		*cp;
 
-	/* If no RAM disk specified, give up early. */
-	if (!rd_length) return;
-	printk("RAMDISK: %d bytes, starting at 0x%x\n",
-					rd_length, (int) rd_start);
-
-	/* If we are doing a diskette boot, we might have to pre-load it. */
-	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return;
-
 	/*
 	 * Check for a super block on the diskette.
 	 * The old-style boot/root diskettes had their RAM image
@@ -175,4 +162,33 @@
 		ROOT_DEV = ((MEM_MAJOR << 8) | RAMDISK_MINOR);
 		return;
 	}
+}
+
+int floppy_grab_irq_and_dma(void);
+void floppy_release_irq_and_dma(void);
+
+/*
+ * If the root device is the RAM disk, try to load it.
+ * In order to do this, the root device is originally set to the
+ * floppy, and we later change it to be RAM disk.
+ */
+void rd_load(void)
+{
+	/* If no RAM disk specified, give up early. */
+	if (!rd_length)
+		return;
+	printk("RAMDISK: %d bytes, starting at 0x%x\n",
+			rd_length, (int) rd_start);
+
+	/* If we are doing a diskette boot, we might have to pre-load it. */
+	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR)
+		return;
+
+/* ugly, ugly */
+	if (floppy_grab_irq_and_dma()) {
+		printk("Unable to gram floppy IRQ/DMA for loading ramdisk image\n");
+		return;
+	}
+	do_load();
+	floppy_release_irq_and_dma();
 }
diff -u --recursive --new-file v1.1.24/linux/drivers/net/3c505.c linux/drivers/net/3c505.c
--- v1.1.24/linux/drivers/net/3c505.c	Mon Jun 27 16:46:58 1994
+++ linux/drivers/net/3c505.c	Thu Jul  7 18:28:21 1994
@@ -2,16 +2,20 @@
  * Linux ethernet device driver for the 3Com Etherlink Plus (3C505)
  * 	By Craig Southeren
  *
- * 3c505.c	This module implements an interface to the 3Com
+ * elplus.c	This module implements an interface to the 3Com
  *		Etherlink Plus (3c505) ethernet card. Linux device 
  *		driver interface reverse engineered from the Linux 3C509
  *		device drivers. Vital 3C505 information gleaned from
  *		the Crynwr packet driver
  *
- * Version:	@(#)3c505.c	0.1	23/09/93
+ * Version:	@(#)elplus.c	0.5	11-Jun-94
  *
  * Authors:	Linux 3c505 device driver by:
  *			Craig Southeren, <geoffw@extro.ucc.su.oz.au>
+ *              Final debugging by:
+ *			Andrew Tridgell, <tridge@nimbus.anu.edu.au>
+ *		Auto irq, auto detect, cleanup and v1.1.4+ kernel mods by:
+ *			Juha Laiho, <jlaiho@ichaos.nullnet.fi>
  *              Linux 3C509 driver by:
  *             		Donald Becker, <becker@super.org>
  *		Crynwr packet driver by
@@ -22,10 +26,36 @@
  *			   modified by Warren Van Houten and krus@diku.dk.
  *              3C505 technical information provided by
  *                      Terry Murphy, of 3Com Network Adapter Division
- *		Special thanks to Juha Laiho, <jlaiho@ichaos.nullnet.fi>
  *                     
  */
 
+
+/*********************************************************
+ *
+ *  set ELP_KERNEL_TYPE to the following values depending upon
+ *  the kernel type:
+ *       0   = 0.99pl14 or earlier
+ *       1   = 0.99pl15 through 1.1.3
+ *       2   = 1.1.4 through 1.1.11
+ *       3   = 1.1.12 through 1.1.19
+ *       4   = 1.1.20
+ *
+ *********************************************************/
+
+#define	ELP_KERNEL_TYPE	4
+
+/*********************************************************
+ *
+ *  set ELP_NEED_HARD_RESET to 1, if having problems with
+ *  "warm resets" from DOS. Bootup will then take some more
+ *  time, as the adapter will perform self-test upon hard
+ *  reset. This misbehaviour is reported to happen at least
+ *  after use of Windows real-mode NDIS drivers.
+ *
+ *********************************************************/
+
+#define ELP_NEED_HARD_RESET 0
+
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -34,23 +64,80 @@
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <asm/bitops.h>
 #include <asm/io.h>
-#ifndef port_read
-#include "iow.h"
-#endif
 
+#if (ELP_KERNEL_TYPE < 2)
+#include "dev.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+#else
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#endif
+
+#ifndef port_read
+#include "iow.h"
+#endif
 
 #include "3c505.h"
 
-#ifdef ELP_DEBUG
-static int elp_debug = ELP_DEBUG;
+#define ELPLUS_DEBUG 0
+
+/*********************************************************
+ *
+ *  define debug messages here as common strings to reduce space
+ *
+ *********************************************************/
+
+static char * filename = __FILE__;
+
+static char * null_msg = "*** NULL at %s(%d) ***\n";
+#define CHECK_NULL(p) if (!p) printk(null_msg, filename, __LINE__)
+
+static char * timeout_msg = "*** timeout at %s(%d) ***\n";
+#define TIMEOUT_MSG()     printk(timeout_msg, filename,__LINE__)
+
+static char * invalid_pcb_msg = "*** invalid pcb length %d at %s(%d) ***\n";
+
+static char * search_msg = "%s: Looking for 3c505 adapter at address 0x%x...";
+
+static char * stilllooking_msg = "still looking...";
+
+static char * found_msg = "found.\n";
+
+static char * notfound_msg = "not found (reason = %d)\n";
+
+static char * couldnot_msg = "%s: 3c505 not found\n";
+
+/*********************************************************
+ *
+ *  various other debug stuff
+ *
+ *********************************************************/
+
+#ifdef ELPLUS_DEBUG
+static int elp_debug = ELPLUS_DEBUG;
 #else
 static int elp_debug = 0;
 #endif
 
+#if (ELP_KERNEL_TYPE < 2)
+extern void	skb_check(struct sk_buff *skb,int, char *);
+#ifndef IS_SKB
+#define IS_SKB(skb)	skb_check((skb),__LINE__,filename)
+#endif
+#else
+#ifndef IS_SKB
+#define IS_SKB(skb)	skb_check((skb),0,__LINE__,filename)
+#endif
+#endif
+
+
 /*
  *  0 = no messages
  *  1 = messages when high level commands performed
@@ -58,9 +145,7 @@
  *  3 = messages when interrupts received
  */
 
-#define	ELP_VERSION	"0.1.0"
-
-extern struct device *irq2dev_map[16];
+#define	ELPLUS_VERSION	"0.4.0"
 
 /*****************************************************************
  *
@@ -68,8 +153,27 @@
  *
  *****************************************************************/
 
-#define	INB(port)	inb((unsigned short)port) 
-#define	OUTB(val,port)	outb((unsigned char)val,(unsigned short)port);
+/*
+ *  kernels before pl15 used an unobvious method for accessing
+ *  the skb data area
+ */
+#if (ELP_KERNEL_TYPE < 1)
+#define	SKB_DATA	(skb+1)
+#else
+#define	SKB_DATA	(skb->data) 
+#endif
+
+/*
+ *  not all kernels before 1.1.4 had an alloc_skb function (apparently!!)
+ */
+#if (ELP_KERNEL_TYPE < 2)
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#endif
+#endif
+
+#define	INB(port)	inb((unsigned short)(port)) 
+#define	OUTB(val,port)	outb((unsigned char)(val),(unsigned short)(port));
 
 #ifndef	TRUE
 #define	TRUE	1
@@ -82,16 +186,19 @@
 
 /*****************************************************************
  *
+ * List of I/O-addresses we try to auto-sense
+ * Last element MUST BE 0!
+ *****************************************************************/
+
+const int addr_list[]={0x300,0x280,0x310,0}; 
+
+/*****************************************************************
+ *
  * PCB structure
  *
  *****************************************************************/
 
-typedef struct {
-  unsigned char   command;		/* PCB command code */
-  unsigned char   length;		/* PCB data length */
-  unsigned char   data[MAX_PCB_DATA];	/* PCB data */
-} pcb_struct;
-
+#include "3c505dta.h"
 
 /*****************************************************************
  *
@@ -101,7 +208,8 @@
 
 typedef struct {
   int        io_addr;	     /* base I/O address */
-  short      got_configure;  /* set to TRUE when configure response received */
+  char *     name;           /* used for debug output */
+  short      got[NUM_TRANSMIT_CMDS];  /* flags for command completion */
   pcb_struct tx_pcb;         /* PCB for foreground sending */
   pcb_struct rx_pcb;         /* PCB for foreground receiving */
   pcb_struct itx_pcb;        /* PCB for background sending */
@@ -127,10 +235,13 @@
 static int get_status (elp_device * adapter)
 
 {
+  int timeout = jiffies + TIMEOUT;  
   register int stat1;
   do {
     stat1 = INB(adapter->io_addr+PORT_STATUS);
-  } while (stat1 != INB(adapter->io_addr+PORT_STATUS));
+  } while (stat1 != INB(adapter->io_addr+PORT_STATUS) && jiffies < timeout);
+  if (jiffies >= timeout)
+    TIMEOUT_MSG();
   return stat1;
 }
 
@@ -153,8 +264,8 @@
   while(((INB(adapter->io_addr+PORT_STATUS)&STATUS_HCRE)==0) &&
          (jiffies <= timeout))
     ;
-  if (jiffies > timeout) {
-    printk("elp0: timeout waiting for HCRE\n");
+  if (jiffies >= timeout) {
+    TIMEOUT_MSG();
     return FALSE;
   }
   return TRUE;
@@ -183,6 +294,12 @@
   int retry = 0;
   int timeout;
 
+  CHECK_NULL(pcb);
+  CHECK_NULL(adapter);
+
+  if (pcb->length > MAX_PCB_DATA)
+    printk(invalid_pcb_msg, pcb->length, filename, __LINE__);
+
   while (1) {
 
     cont = 1;
@@ -195,7 +312,6 @@
     SET_HSF(0); 
     OUTB(pcb->command, (adapter->io_addr)+PORT_COMMAND);
     cont = WAIT_HCRE(5);
-   /* SET_HSF(0);  */
 
     if (cont) {
       OUTB(pcb->length, (adapter->io_addr)+PORT_COMMAND);
@@ -203,7 +319,7 @@
     }
 
     for (i = 0; cont && (i < pcb->length); i++) {
-      OUTB(pcb->data[i], (adapter->io_addr)+PORT_COMMAND);
+      OUTB(pcb->data.raw[i], (adapter->io_addr)+PORT_COMMAND);
       cont = WAIT_HCRE(2);
     }
 
@@ -220,12 +336,16 @@
             (i == ASF_PCB_NAK))
           break;
       }
+
+      if (jiffies >= timeout)
+        TIMEOUT_MSG();
+
       if (i == ASF_PCB_ACK) {
         SET_HSF(0); 
         return TRUE;
-      } else if (i = ASF_PCB_NAK) {
+      } else if (i == ASF_PCB_NAK) {
         SET_HSF(0);
-        printk("elp0: PCB send was NAKed\n");
+        printk("%s: PCB send was NAKed\n", adapter->name);
         {
           int to = jiffies + 5;
           while (jiffies < to)
@@ -234,11 +354,13 @@
       }
     }
 
-    if (elp_debug >= 6)
-      printk("elp0: NAK/timeout on send PCB\n");
+    if (elp_debug >= 2)
+      printk("%s: NAK/timeout on send PCB\n", adapter->name);
     if ((retry++ & 7) == 0) 
-      printk("elp0: retry #%i on send PCB\n", retry);
+      printk("%s: retry #%i on send PCB\n", adapter->name, retry);
   }
+
+  return FALSE;
 }
 
 /*****************************************************************
@@ -260,38 +382,60 @@
   int i;
   int total_length;
   int stat;
+  int timeout;
+
+  CHECK_NULL(pcb);
+  CHECK_NULL(adapter);
 
   /* get the command code */
-  while (((stat = GET_STATUS())&STATUS_ACRF) == 0)
+  timeout = jiffies + TIMEOUT;
+  while (((stat = GET_STATUS())&STATUS_ACRF) == 0 && jiffies < timeout)
     ;
+  if (jiffies >= timeout)
+    TIMEOUT_MSG();
+
   SET_HSF(0); 
   pcb->command = INB(adapter->io_addr+PORT_COMMAND);
   if ((stat & ASF_PCB_MASK) != ASF_PCB_END) {
 
     /* read the data length */
-    while (((stat = GET_STATUS())&STATUS_ACRF) == 0)
+    timeout = jiffies + TIMEOUT;
+    while (((stat = GET_STATUS())&STATUS_ACRF) == 0 && jiffies < timeout)
       ;
+    if (jiffies >= timeout)
+      TIMEOUT_MSG();
     pcb->length = INB(adapter->io_addr+PORT_COMMAND);
+
+    if (pcb->length > MAX_PCB_DATA)
+      printk(invalid_pcb_msg, pcb->length, filename,__LINE__);
+
     if ((stat & ASF_PCB_MASK) != ASF_PCB_END) {
 
       /* read the data */
       i = 0;
+      timeout = jiffies + TIMEOUT;
       do {
-        while (((stat = GET_STATUS())&STATUS_ACRF) == 0)
+        while (((stat = GET_STATUS())&STATUS_ACRF) == 0 && jiffies < timeout)
           ;
-        pcb->data[i++] = INB(adapter->io_addr+PORT_COMMAND);
-      } while ((stat & ASF_PCB_MASK) != ASF_PCB_END);
-
+        pcb->data.raw[i++] = INB(adapter->io_addr+PORT_COMMAND);
+	if (i > MAX_PCB_DATA)
+	  printk(invalid_pcb_msg, i, filename, __LINE__);
+      } while ((stat & ASF_PCB_MASK) != ASF_PCB_END && jiffies < timeout);
+
+      if (jiffies >= timeout)
+        TIMEOUT_MSG();
+      
       /* woops, the last "data" byte was really the length! */
-      total_length = pcb->data[--i];
+      total_length = pcb->data.raw[--i];
 
       /* safety check total length vs data length */
       if (total_length != (pcb->length + 2)) {
-        if (elp_debug >= 6)
-          printk("elp0: mangled PCB received\n");
+        if (elp_debug >= 2)
+          printk("%s: mangled PCB received\n", adapter->name);
         SET_HSF(HSF_PCB_NAK);
         return FALSE;
       }
+
       SET_HSF(HSF_PCB_ACK);
       return TRUE;
     }
@@ -301,11 +445,15 @@
   return FALSE;
 }
 
+#if ELP_NEED_HARD_RESET
+
 static void adapter_hard_reset(elp_device * adapter)
 
 {
   int timeout;
 
+  CHECK_NULL(adapter);
+
   /*
    * take FLSH and ATTN high
    */
@@ -336,11 +484,14 @@
       break;
 }
 
-static void adapter_reset(elp_device * adapter)
+#endif /* ELP_NEED_HARD_RESET */
 
+static void adapter_reset(elp_device * adapter)
 {
   int timeout;
 
+  CHECK_NULL(adapter);
+
   cli();
   OUTB(CONTROL_ATTN|INB(adapter->io_addr+PORT_CONTROL), adapter->io_addr+PORT_CONTROL);
   sti();
@@ -350,10 +501,11 @@
    */
   for (timeout = jiffies + 20; jiffies <= timeout; )
     ;
-  
+
   cli();
   OUTB(INB(adapter->io_addr+PORT_CONTROL)&~(CONTROL_ATTN), adapter->io_addr+PORT_CONTROL);
   sti();
+
 }
 
 /******************************************************
@@ -366,14 +518,16 @@
 static int start_receive(elp_device * adapter, pcb_struct * tx_pcb)
 
 {
-  if (elp_debug > 3)
-    printk("elp0: restarting receiver\n");
+  CHECK_NULL(adapter);
+  CHECK_NULL(tx_pcb);
+
+  if (elp_debug >= 3)
+    printk("%s: restarting receiver\n", adapter->name);
   tx_pcb->command = CMD_RECEIVE_PACKET;
-  tx_pcb->length  = 8;
-  tx_pcb->data[4] = 1600 & 0xff;
-  tx_pcb->data[5] = 1600 >> 8;
-  tx_pcb->data[6] = 0;		/* set timeout to zero */
-  tx_pcb->data[7] = 0;
+  tx_pcb->length = sizeof(struct Rcv_pkt);
+  tx_pcb->data.rcv_pkt.buf_seg = tx_pcb->data.rcv_pkt.buf_ofs = 0; /* Unused */
+  tx_pcb->data.rcv_pkt.buf_len = 1600;
+  tx_pcb->data.rcv_pkt.timeout = 0;	/* set timeout to zero */
   return send_pcb(adapter, tx_pcb); 
 }
 
@@ -394,13 +548,33 @@
   register int i;
   unsigned short * ptr;
   short d;
+  int timeout;
+  int rlen;
+  struct sk_buff *skb;
 
   /*
    * allocate a buffer to put the packet into.
+   * (for kernels prior to 1.1.4 only)
    */
-  struct sk_buff *skb;
-  skb = alloc_skb(len+3, GFP_ATOMIC);
+#if (ELP_KERNEL_TYPE < 2)
+  int sksize = sizeof(struct sk_buff) + len + 4;
+#endif
+
+  CHECK_NULL(dev);
+  CHECK_NULL(adapter);
+
+  if (len <= 0 || ((len & ~1) != len))
+    if (elp_debug >= 3)
+      printk("*** bad packet len %d at %s(%d)\n",len,filename,__LINE__);
 
+  rlen = (len+1) & ~1;
+
+#if (ELP_KERNEL_TYPE < 2)
+  skb = alloc_skb(sksize, GFP_ATOMIC);
+#else
+  skb = alloc_skb(rlen, GFP_ATOMIC);
+#endif
+
   /*
    * make sure the data register is going the right way
    */
@@ -410,23 +584,52 @@
    * if buffer could not be allocated, swallow it
    */
   if (skb == NULL) {
-    for (i = 0; i < (len/2); i++) {
-      while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0)
+    for (i = 0; i < (rlen/2); i++) {
+      timeout = jiffies + TIMEOUT;
+      while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0 && 
+	     jiffies < timeout)
         ;
+      if (jiffies >= timeout)
+        TIMEOUT_MSG();
+
       d = inw(adapter->io_addr+PORT_DATA);
     }
     adapter->stats.rx_dropped++;
 
   } else {
+    skb->lock     = 0;
+    skb->len = rlen;
+    skb->dev = dev;
 
+/*
+ * for kernels before 1.1.4, the driver allocated the buffer
+ */
+#if (ELP_KERNEL_TYPE < 2)
+    skb->mem_len = sksize;
+    skb->mem_addr = skb;
+#endif
+
     /*
      * now read the data from the adapter
      */
-    ptr = (unsigned short *)(skb->data);
-    for (i = 0; i < (len/2); i++) { 
-      while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0) {
-        ;
-      }
+    ptr = (unsigned short *)SKB_DATA;
+    for (i = 0; i < (rlen/2); i++) { 
+      timeout = jiffies + TIMEOUT;
+      while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0 && 
+	     jiffies < timeout) 
+	;
+      if (jiffies >= timeout)
+	{
+	  printk("*** timeout at %s(%d) reading word %d of %d ***\n",
+                        filename,__LINE__, i, rlen/2);	
+#if (ELP_KERNEL_TYPE < 2)
+	  kfree_s(skb, sksize);
+#else
+	  kfree_s(skb, rlen);
+#endif
+	  return;
+	}
+
       *ptr = inw(adapter->io_addr+PORT_DATA); 
       ptr++; 
     }
@@ -436,10 +639,21 @@
      * protocol chain. If it returns 0, we can assume the packet was
      * swallowed up. If not, then we are responsible for freeing memory
      */
-    if (dev_rint((unsigned char *)skb, len, IN_SKBUFF, dev) != 0) {
+
+    IS_SKB(skb);
+
+/*
+ * for kernels before 1.1.4, the driver allocated the buffer, so it had
+ * to free it
+ */
+#if (ELP_KERNEL_TYPE < 2)
+    if (dev_rint((unsigned char *)skb, rlen, IN_SKBUFF, dev) != 0) {
       printk("%s: receive buffers full.\n", dev->name);
-      kfree_skb(skb, FREE_READ);
+      kfree_s(skb, sksize);
     }
+#else
+    netif_rx(skb);
+#endif
   }
 
   OUTB(INB(adapter->io_addr+PORT_CONTROL)&(~CONTROL_DIR), adapter->io_addr+PORT_CONTROL); 
@@ -460,27 +674,34 @@
   int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
   struct device *dev;
   elp_device * adapter;
+  int timeout;
 
   if (irq < 0 || irq > 15) {
-    printk ("elp0: illegal IRQ number found in interrupt routine (%i)\n", irq);
+    printk ("elp_interrupt(): illegal IRQ number found in interrupt routine (%i)\n", irq);
     return;
   }
 
-  if (irq != 0xc) {
-    printk ("elp0: warning - interrupt routine has incorrect IRQ of %i\n", irq);
+/* FIXME: How do I do this kind of check without a fixed IRQ? */
+#if 0
+  if (irq != ELP_IRQ) {
+    printk ("elp_interrupt(): - interrupt routine has incorrect IRQ of %i\n", irq);
     return;
   }
+#endif
 
   dev = irq2dev_map[irq];
-  adapter = (elp_device *) dev->priv;
 
   if (dev == NULL) {
     printk ("elp_interrupt(): irq %d for unknown device.\n", irq);
     return;
   }
 
+  adapter = (elp_device *) dev->priv;
+
+  CHECK_NULL(adapter);
+
   if (dev->interrupt)
-    if (elp_debug >= 3)
+    if (elp_debug >= 2)
       printk("%s: Re-entering the interrupt handler.\n", dev->name);
   dev->interrupt = 1;
 
@@ -492,7 +713,9 @@
   /*
    * receive a PCB from the adapter
    */
-  while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0) {
+  timeout = jiffies + TIMEOUT;
+  while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0 &&
+	 jiffies < timeout) {
     
     if (receive_pcb(adapter, &adapter->irx_pcb)) {
 
@@ -502,18 +725,66 @@
          * 82586 configured correctly
          */
         case CMD_CONFIGURE_82586_RESPONSE:
-          adapter->got_configure = 1;
+          adapter->got[CMD_CONFIGURE_82586] = 1;
           if (elp_debug >= 3)
             printk("%s: interrupt - configure response received\n", dev->name);
           break;
 
+	/*
+	 * Adapter memory configuration
+	 */
+	case CMD_CONFIGURE_ADAPTER_RESPONSE:
+	  adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1;
+	  if (elp_debug >= 3)
+	    printk("%s: Adapter memory configuration %s.",dev->name,
+	           adapter->irx_pcb.data.failed?"failed":"succeeded");
+	  break;
+	
+	/*
+	 * Multicast list loading
+	 */
+	case CMD_LOAD_MULTICAST_RESPONSE:
+	  adapter->got[CMD_LOAD_MULTICAST_LIST] = 1;
+          if (elp_debug >= 3)
+	    printk("%s: Multicast address list loading %s.",dev->name,
+	           adapter->irx_pcb.data.failed?"failed":"succeeded");
+	  break;
+
+	/*
+	 * Station address setting
+	 */
+	case CMD_SET_ADDRESS_RESPONSE:
+	  adapter->got[CMD_SET_STATION_ADDRESS] = 1;
+          if (elp_debug >= 3)
+            printk("%s: Ethernet address setting %s.",dev->name,
+                   adapter->irx_pcb.data.failed?"failed":"succeeded");
+          break;
+
+
+        /*
+         * received board statistics
+         */
+        case CMD_NETWORK_STATISTICS_RESPONSE:
+          adapter->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
+          adapter->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
+          adapter->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
+          adapter->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
+          adapter->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
+          adapter->got[CMD_NETWORK_STATISTICS] = 1;
+          if (elp_debug >= 3)
+            printk("%s: interrupt - statistics response received\n", dev->name);
+          break;
+
         /*
          * received a packet
          */
         case CMD_RECEIVE_PACKET_COMPLETE:
-          len  = adapter->irx_pcb.data[6] + (adapter->irx_pcb.data[7] << 8);
-          dlen  = adapter->irx_pcb.data[4] + (adapter->irx_pcb.data[5] << 8);
-          if (adapter->irx_pcb.data[8] != 0) {
+          /* if the device isn't open, don't pass packets up the stack */
+          if (dev->start == 0)
+            break;
+          len = adapter->irx_pcb.data.rcv_resp.pkt_len;
+          dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
+          if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
             printk("%s: interrupt - packet not received correctly\n", dev->name);
           } else {
             if (elp_debug >= 3)
@@ -521,7 +792,6 @@
             receive_packet(dev, adapter, dlen);
             if (elp_debug >= 3)
               printk("%s: packet received\n", dev->name);
-            adapter->stats.rx_packets++;
           }
           if (dev->start && !start_receive(adapter, &adapter->itx_pcb)) 
             if (elp_debug >= 2)
@@ -537,13 +807,18 @@
         case CMD_TRANSMIT_PACKET_COMPLETE:
           if (elp_debug >= 3) 
             printk("%s: interrupt - packet sent\n", dev->name);
-          if (adapter->irx_pcb.data[4] != 0)
+          if (dev->start == 0)
+            break;
+          if (adapter->irx_pcb.data.xmit_resp.c_stat != 0)
             if (elp_debug >= 2)
-              printk("%s: interrupt - error sending packet %4.4x\n", dev->name, 
-                adapter->irx_pcb.data[4] + (adapter->irx_pcb.data[5] << 8));
+              printk("%s: interrupt - error sending packet %4.4x\n",
+                dev->name, adapter->irx_pcb.data.xmit_resp.c_stat);
           dev->tbusy = 0;
+#if (ELP_KERNEL_TYPE < 3)
           mark_bh(INET_BH);
-          adapter->stats.tx_packets++;
+#else
+          mark_bh(NET_BH);
+#endif
           break;
 
         /*
@@ -556,6 +831,8 @@
     } else 
       printk("%s: failed to read PCB on interrupt\n", dev->name);
   }
+  if (jiffies >= timeout)
+    TIMEOUT_MSG();
 
   /*
    * indicate no longer in interrupt routine
@@ -575,7 +852,9 @@
 {
   elp_device * adapter = (elp_device *) dev->priv;
 
-  if (elp_debug >= 1)
+  CHECK_NULL(dev);
+
+  if (elp_debug >= 3)  
     printk("%s: request to open device\n", dev->name);
 
   /*
@@ -587,6 +866,16 @@
   }
 
   /*
+   * disable interrupts on the board
+   */
+  OUTB(0x00, adapter->io_addr+PORT_CONTROL);
+
+  /*
+   * clear any pending interrupts
+   */
+  INB(adapter->io_addr+PORT_COMMAND);
+
+  /*
    * interrupt routine not entered
    */
   dev->interrupt = 0;
@@ -618,74 +907,60 @@
   dev->start = 1;
 
   /*
+   * configure adapter memory: we need 10 multicast addresses, default==0
+   */
+  if (elp_debug >= 3)
+    printk("%s: sending 3c505 memory configuration command\n", dev->name);
+  adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY;
+  adapter->tx_pcb.data.memconf.cmd_q = 10;
+  adapter->tx_pcb.data.memconf.rcv_q = 20;
+  adapter->tx_pcb.data.memconf.mcast = 10;
+  adapter->tx_pcb.data.memconf.frame = 20;
+  adapter->tx_pcb.data.memconf.rcv_b = 20;
+  adapter->tx_pcb.data.memconf.progs = 0;
+  adapter->tx_pcb.length = sizeof(struct Memconf);
+  adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0;
+  if (!send_pcb(adapter, &adapter->tx_pcb))
+    printk("%s: couldn't send memory configuration command\n", dev->name);
+  else {
+    int timeout = jiffies + TIMEOUT;
+    while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && jiffies < timeout)
+      ;
+    if (jiffies >= timeout)
+      TIMEOUT_MSG();
+  }
+
+
+  /*
    * configure adapter to receive broadcast messages and wait for response
    */
-  if (elp_debug >= 2)
+  if (elp_debug >= 3)
     printk("%s: sending 82586 configure command\n", dev->name);
   adapter->tx_pcb.command = CMD_CONFIGURE_82586;
-  adapter->tx_pcb.data[0] = 1;
-  adapter->tx_pcb.data[1] = 0;
+  adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
   adapter->tx_pcb.length  = 2;
-  adapter->got_configure  = 0;
+  adapter->got[CMD_CONFIGURE_82586] = 0;
   if (!send_pcb(adapter, &adapter->tx_pcb))
     printk("%s: couldn't send 82586 configure command\n", dev->name);
-  else
-    while (adapter->got_configure == 0)
+  else {
+    int timeout = jiffies + TIMEOUT;
+    while (adapter->got[CMD_CONFIGURE_82586] == 0 && jiffies < timeout)
       ;
+    if (jiffies >= timeout)
+      TIMEOUT_MSG();
+  }
 
   /*
-   * queue a receive command to start things rolling
+   * queue receive commands to provide buffering
    */
   if (!start_receive(adapter, &adapter->tx_pcb))
     printk("%s: start receive command failed \n", dev->name);
-  if (elp_debug >= 2)
+  if (elp_debug >= 3)
     printk("%s: start receive command sent\n", dev->name);
 
   return 0;			/* Always succeed */
 }
 
-/******************************************************
- *
- * close the board
- *
- ******************************************************/
-
-static int elp_close (struct device *dev)
-
-{
-  elp_device * adapter = (elp_device *) dev->priv;
-
-  if (elp_debug >= 1)
-    printk("%s: request to close device\n", dev->name);
-
-  /*
-   * disable interrupts on the board
-   */
-  OUTB(0x00, adapter->io_addr+PORT_CONTROL);
-
-  /*
-   *  flag transmitter as busy (i.e. not available)
-   */
-  dev->tbusy = 1;
-
-  /*
-   *  indicate device is closed
-   */
-  dev->start = 0;
-
-  /*
-   * release the IRQ
-   */
-  free_irq(dev->irq);
-
-  /*
-   * and we no longer have to map irq to dev either
-   */
-  irq2dev_map[dev->irq] = 0;
-
-  return 0;
-}
-
 
 /******************************************************
  *
@@ -703,14 +978,20 @@
    */
   unsigned int nlen = (((len < 60) ? 60 : len) + 1) & (~1);
 
+  CHECK_NULL(adapter);
+  CHECK_NULL(ptr);
+
+  if (nlen < len)
+    printk("Warning, bad length nlen=%d len=%d %s(%d)\n",nlen,len,filename,__LINE__);
+
   /*
    * send the adapter a transmit packet command. Ignore segment and offset
    * and make sure the length is even
    */
   adapter->tx_pcb.command = CMD_TRANSMIT_PACKET;
-  adapter->tx_pcb.length  = 6;
-  adapter->tx_pcb.data[4] = nlen & 0xff;
-  adapter->tx_pcb.data[5] = nlen >> 8;
+  adapter->tx_pcb.length = sizeof(struct Xmit_pkt);
+  adapter->tx_pcb.data.xmit_pkt.buf_ofs = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0; /* Unused */
+  adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen;
   if (!send_pcb(adapter, &adapter->tx_pcb)) 
     return FALSE;
 
@@ -725,8 +1006,15 @@
    * write data to the adapter
    */
   for (i = 0; i < (nlen/2);i++) {
-    while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0)
+    int timeout = jiffies + TIMEOUT;
+    while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0 && jiffies < timeout)
       ;
+    if (jiffies >= timeout) {
+      printk("*** timeout at %s(%d) writing word %d of %d ***\n",
+            filename,__LINE__, i, nlen/2);
+      return FALSE;
+    }
+
     outw(*(short *)ptr, adapter->io_addr+PORT_DATA);
     ptr +=2;
   }
@@ -746,8 +1034,10 @@
 {
   elp_device * adapter = (elp_device *) dev->priv;
 
+  CHECK_NULL(dev);
+
   /*
-   * not sure what this does, but the 3c609 driver does it, so...
+   * not sure what this does, but the 3c509 driver does it, so...
    */
   if (skb == NULL) {
     dev_tint(dev);
@@ -755,20 +1045,34 @@
   }
 
   /*
+   * Fill in the ethernet header 
+   * (for kernels prior to 1.1.4 only)
+   */
+#if (ELP_KERNEL_TYPE < 2)
+  IS_SKB(skb);
+  if (!skb->arp && dev->rebuild_header(SKB_DATA, dev)) {
+    skb->dev = dev;
+    IS_SKB(skb);
+    arp_queue (skb);
+    return 0;
+  }
+#endif
+
+  /*
    * if we ended up with a munged length, don't send it
    */
   if (skb->len <= 0)
     return 0;
 
-  if (elp_debug >= 1)
-    printk("%s: request to send packet of length %i\n", dev->name, skb->len);
+  if (elp_debug >= 3)
+    printk("%s: request to send packet of length %d\n", dev->name, (int)skb->len);
 
   /*
    * if the transmitter is still busy, we have a transmit timeout...
    */
   if (dev->tbusy) {
     int tickssofar = jiffies - dev->trans_start;
-    if (tickssofar < 500)
+    if (tickssofar < 200) /* was 500, AJT */
       return 1;
     printk("%s: transmit timed out, resetting adapter\n", dev->name);
     if ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0) 
@@ -779,15 +1083,15 @@
   }
 
   /*
-   * send the packet at (void *)(skb+1) for skb->len
+   * send the packet at skb->data for skb->len
    */
-  if (!send_packet(adapter, (unsigned char *)(skb->data), skb->len)) {
+  if (!send_packet(adapter, (unsigned char *)SKB_DATA, skb->len)) {
     printk("%s: send packet PCB failed\n", dev->name);
     return 1;
   }
 
-  if (elp_debug >= 2)
-    printk("%s: packet of length %i sent\n", dev->name, skb->len);
+  if (elp_debug >= 3)
+    printk("%s: packet of length %d sent\n", dev->name, (int)skb->len);
 
 
   /*
@@ -803,7 +1107,15 @@
   /*
    * if we have been asked to free the buffer, do so
    */
+#if (ELP_KERNEL_TYPE < 4)
+  if (skb->free)
+    {
+      IS_SKB(skb);
+      kfree_skb(skb, FREE_WRITE);
+    }
+#else
   dev_kfree_skb(skb, FREE_WRITE);
+#endif
 
   return 0;
 }
@@ -817,30 +1129,174 @@
 static struct enet_statistics * elp_get_stats(struct device *dev)
 
 {
-  if (elp_debug >= 1)
+  elp_device *adapter = (elp_device *) dev->priv;
+
+  if (elp_debug >= 3)
     printk("%s: request for stats\n", dev->name);
 
-  elp_device * adapter = (elp_device *) dev->priv;
+  /* If the device is closed, just return the latest stats we have,
+     - we cannot ask from the adapter without interrupts */
+  if (!dev->start)
+    return &adapter->stats;
+
+  /* send a get statistics command to the board */
+  adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
+  adapter->tx_pcb.length  = 0;
+  adapter->got[CMD_NETWORK_STATISTICS] = 0;
+  if (!send_pcb(adapter, &adapter->tx_pcb))
+    printk("%s: couldn't send get statistics command\n", dev->name);
+  else
+    {
+      int timeout = jiffies + TIMEOUT;
+      while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && jiffies < timeout)
+	;
+      if (jiffies >= timeout) {
+        TIMEOUT_MSG();
+        return &adapter->stats;
+      }
+    }
+
+  /* statistics are now up to date */
   return &adapter->stats;
 }
 
 /******************************************************
  *
- * initialise Etherlink Pus board
+ * close the board
  *
  ******************************************************/
 
-static void elp_init(struct device *dev)
+static int elp_close (struct device *dev)
+
+{
+  elp_device * adapter = (elp_device *) dev->priv;
+
+  CHECK_NULL(dev);
+  CHECK_NULL(adapter);
+
+  if (elp_debug >= 3)
+    printk("%s: request to close device\n", dev->name);
+
+  /* Someone may request the device statistic information even when
+   * the interface is closed. The following will update the statistics
+   * structure in the driver, so we'll be able to give current statistics.
+   */
+  (void) elp_get_stats(dev);
+
+  /*
+   * disable interrupts on the board
+   */
+  OUTB(0x00, adapter->io_addr+PORT_CONTROL);
+
+  /*
+   *  flag transmitter as busy (i.e. not available)
+   */
+  dev->tbusy = 1;
+
+  /*
+   *  indicate device is closed
+   */
+  dev->start = 0;
+
+  /*
+   * release the IRQ
+   */
+  free_irq(dev->irq);
+
+  /*
+   * and we no longer have to map irq to dev either
+   */
+  irq2dev_map[dev->irq] = 0;
+
+  return 0;
+}
+
+
+/************************************************************
+ *
+ * Set multicast list
+ * num_addrs==0: clear mc_list
+ * num_addrs==-1: set promiscuous mode
+ * num_addrs>0: set mc_list
+ *
+ ************************************************************/
 
+static void elp_set_mc_list(struct device *dev, int num_addrs, void *addrs)
 {
+  elp_device *adapter = (elp_device *) dev->priv;
   int i;
+
+  if (elp_debug >= 3)
+    printk("%s: request to set multicast list\n", dev->name);
+
+  if (num_addrs != -1) {
+    /* send a "load multicast list" command to the board, max 10 addrs/cmd */
+    /* if num_addrs==0 the list will be cleared */
+    adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST;
+    adapter->tx_pcb.length  = 6*num_addrs;
+    for (i=0;i<num_addrs;i++)
+      memcpy(adapter->tx_pcb.data.multicast[i], addrs+6*i,6);
+    adapter->got[CMD_LOAD_MULTICAST_LIST] = 0;
+    if (!send_pcb(adapter, &adapter->tx_pcb))
+      printk("%s: couldn't send set_multicast command\n", dev->name);
+    else {
+      int timeout = jiffies + TIMEOUT;
+      while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && jiffies < timeout)
+        ;
+      if (jiffies >= timeout) {
+        TIMEOUT_MSG();
+      }
+    }
+    if (num_addrs)
+      adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI;
+    else /* num_addrs == 0 */
+      adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD;
+  } else /* num_addrs == -1 */
+    adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_ALL;
+  /*
+   * configure adapter to receive messages (as specified above)
+   * and wait for response
+   */
+  if (elp_debug >= 3)
+    printk("%s: sending 82586 configure command\n", dev->name);
+  adapter->tx_pcb.command = CMD_CONFIGURE_82586;
+  adapter->tx_pcb.length  = 2;
+  adapter->got[CMD_CONFIGURE_82586]  = 0;
+  if (!send_pcb(adapter, &adapter->tx_pcb))
+    printk("%s: couldn't send 82586 configure command\n", dev->name);
+  else {
+    int timeout = jiffies + TIMEOUT;
+    while (adapter->got[CMD_CONFIGURE_82586] == 0 && jiffies < timeout)
+      ;
+    if (jiffies >= timeout)
+      TIMEOUT_MSG();
+  }
+}
+
+/******************************************************
+ *
+ * initialise Etherlink Plus board
+ *
+ ******************************************************/
+
+static void elp_init(struct device *dev)
+
+{
   elp_device * adapter;
 
+  CHECK_NULL(dev);
+
   /*
    * NULL out buffer pointers
+   * (kernels prior to 1.1.4 only)
    */
-  for (i = 0; i < DEV_NUMBUFFS; i++)
-    dev->buffs[i] = NULL;
+#if (ELP_KERNEL_TYPE < 2)
+  {
+    int i;
+    for (i = 0; i < DEV_NUMBUFFS; i++)
+      dev->buffs[i] = NULL;
+  }
+#endif
 
   /*
    * set ptrs to various functions
@@ -849,31 +1305,43 @@
   dev->stop             = elp_close;		/* local */
   dev->get_stats	= elp_get_stats;	/* local */
   dev->hard_start_xmit  = elp_start_xmit;       /* local */
+  dev->set_multicast_list = elp_set_mc_list;	/* local */
 
+#if (ELP_KERNEL_TYPE < 2)
   dev->hard_header	= eth_header;		/* eth.c */
   dev->add_arp	        = eth_add_arp;		/* eth.c */
   dev->rebuild_header	= eth_rebuild_header;	/* eth.c */
   dev->type_trans	= eth_type_trans;	/* eth.c */
-
   dev->queue_xmit	= dev_queue_xmit;	/* dev.c */
+#else
+  /* Setup the generic properties */
+  ether_setup(dev);
+#endif
 
   /*
    * setup ptr to adapter specific information
    */
   adapter = (elp_device *)(dev->priv = kmalloc(sizeof(elp_device), GFP_KERNEL));
+  CHECK_NULL(adapter);
   adapter->io_addr = dev->base_addr;
+  adapter->name    = dev->name;
   memset(&(adapter->stats), 0, sizeof(struct enet_statistics));
 
 
   /*
    * Ethernet information
+   * (for kernels prior to 1.1.4 only)
    */
+#if (ELP_KERNEL_TYPE < 2)
   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;
+  {
+    int i;
+    for (i = 0; i < dev->addr_len; i++) 
+      dev->broadcast[i] = 0xff;
+  }
 
   /*
    * New-style flags. 
@@ -884,41 +1352,139 @@
   dev->pa_brdaddr	= 0;
   dev->pa_mask	        = 0;
   dev->pa_alen        	= sizeof(unsigned long);
+#endif
 
   /*
    * memory information
    */
   dev->mem_start = dev->mem_end = dev->rmem_end = dev->mem_start = 0;
+
+#if ELP_NEED_HARD_RESET
+  adapter_hard_reset(adapter);
+#else
+  adapter_reset(adapter);
+#endif
+}
+
+/************************************************************
+ *
+ * A couple of tests to see if there's 3C505 or not
+ * Called only by elp_autodetect
+ ************************************************************/
+
+static int elp_sense(int addr)
+{
+  int timeout;
+  byte orig_HCR=INB(addr+PORT_CONTROL),
+       orig_HSR=INB(addr+PORT_STATUS);
+  
+  if (((orig_HCR==0xff) && (orig_HSR==0xff)) ||
+       ( (orig_HCR & CONTROL_DIR) != (orig_HSR & STATUS_DIR) ) )
+    return 1;                /* It can't be 3c505 if HCR.DIR != HSR.DIR */
+
+  /* Wait for a while; the adapter may still be booting up */
+  if (elp_debug > 0)
+    printk(stilllooking_msg);
+  for (timeout = jiffies + (100 * 15); jiffies <= timeout; ) 
+    if ((INB(addr+PORT_STATUS) & ASF_PCB_MASK) != ASF_PCB_END)
+      break;
+
+  if (orig_HCR & CONTROL_DIR) {
+    /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
+    OUTB(orig_HCR & ~CONTROL_DIR,addr+PORT_CONTROL);
+    timeout = jiffies+30;
+    while (jiffies < timeout)
+      ;
+    if (INB(addr+PORT_STATUS) & STATUS_DIR) {
+      OUTB(orig_HCR,addr+PORT_CONTROL);
+      return 2;
+    }
+  } else {
+    /* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
+    OUTB(orig_HCR | CONTROL_DIR,addr+PORT_CONTROL);
+    timeout = jiffies+300;
+    while (jiffies < timeout)
+      ;
+    if (!(INB(addr+PORT_STATUS) & STATUS_DIR)) {
+      OUTB(orig_HCR,addr+PORT_CONTROL);
+      return 3;
+    }
+  }
+  return 0;	/* It certainly looks like a 3c505. */
 }
 
+/*************************************************************
+ *
+ * Search through addr_list[] and try to find a 3C505
+ * Called only by eplus_probe
+ *************************************************************/
+
+static int elp_autodetect(struct device * dev)
+{
+  int idx=0, addr;
+
+  /* if base address set, then only check that address
+     otherwise, run through the table */
+  if ( (addr=dev->base_addr) ) { /* dev->base_addr == 0 ==> plain autodetect */
+    if (elp_debug > 0)
+      printk(search_msg, dev->name, addr);
+    if (elp_sense(addr) == 0)
+    {
+      if (elp_debug > 0)
+        printk(found_msg);
+      return addr;
+    } else if (elp_debug > 0)
+      printk(notfound_msg);
+  } else while ( (addr=addr_list[idx++]) ) {
+    if (elp_debug > 0)
+      printk(search_msg, dev->name, addr);
+    if (elp_sense(addr) == 0) {
+      if (elp_debug > 0)
+        printk(found_msg);
+      return addr;
+    } else if (elp_debug > 0)
+      printk(notfound_msg);
+  }
+
+  /* could not find an adapter */
+  if (elp_debug == 0)
+    printk(couldnot_msg, dev->name);
+  return 0; /* Because of this, the layer above will return -ENODEV */
+}
 
 /******************************************************
  *
  * probe for an Etherlink Plus board at the specified address
- * by attempting to get the ethernet address. 
  *
  ******************************************************/
 
-int elp_probe(struct device *dev)
+int elplus_probe(struct device *dev)
 
 {
   elp_device adapter;
   int            i;
 
+  CHECK_NULL(dev);
+
   /*
    *  setup adapter structure
    */
-  adapter.io_addr = dev->base_addr;
 
-  printk ("%s: probing for 3c505...", dev->name);
+  adapter.io_addr = dev->base_addr = elp_autodetect(dev);
+  if ( !adapter.io_addr )
+    return -ENODEV;
 
   /*
-   * get the adapter's undivided attention (if it's there!)
+   *  As we enter here from bootup, the adapter should have IRQs enabled,
+   *  but we can as well enable them anyway.
    */
-  adapter_hard_reset(&adapter); 
+  OUTB(INB(dev->base_addr+PORT_CONTROL) | CONTROL_CMDE,
+       dev->base_addr+PORT_CONTROL);
+  autoirq_setup(0);
 
   /*
    * use ethernet address command to probe for board in polled mode
+   * (this also makes us the IRQ that we need for automatic detection)
    */
   adapter.tx_pcb.command = CMD_STATION_ADDRESS;
   adapter.tx_pcb.length  = 0;
@@ -926,16 +1492,59 @@
       !receive_pcb(&adapter, &adapter.rx_pcb) ||
       (adapter.rx_pcb.command != CMD_ADDRESS_RESPONSE) ||
       (adapter.rx_pcb.length != 6)) {
-    printk("not found\n");
+    printk("%s: not responding to first PCB\n", dev->name);
     return -ENODEV;
   }
-
+  if (dev->irq) { /* Is there a preset IRQ? */
+     if (dev->irq != autoirq_report(0)) {
+        printk("%s: Detected IRQ doesn't match user-defined one.\n",dev->name);
+	return -ENODEV;
+     }
+     /* if dev->irq == autoirq_report(0), all is well */
+  } else /* No preset IRQ; just use what we can detect */
+     dev->irq=autoirq_report(0);
+  switch (dev->irq) { /* Legal, sane? */
+    case 0: printk("%s: No IRQ reported by autoirq_report().\n",dev->name);
+            printk("%s: Check the jumpers of your 3c505 board.\n",dev->name);
+	    return -ENODEV;
+    case 1:
+    case 6:
+    case 8:
+    case 13: 
+            printk("%s: Impossible IRQ %d reported by autoirq_report().\n",
+	           dev->name,
+		   dev->irq);
+	    return -ENODEV;
+  }
+  /*
+   *  Now we have the IRQ number so we can disable the interrupts from
+   *  the board until the board is opened.
+   */
+  OUTB(INB(dev->base_addr+PORT_CONTROL) & ~CONTROL_CMDE,
+       dev->base_addr+PORT_CONTROL);
+  
+  /*
+   * copy ethernet address into structure
+   */
   for (i = 0; i < 6; i++) 
-    dev->dev_addr[i] = adapter.rx_pcb.data[i];
+    dev->dev_addr[i] = adapter.rx_pcb.data.eth_addr[i];
 
-  printk("found at port 0x%x, address = %s\n", dev->base_addr, eth_print(dev->dev_addr));
+  /*
+   * print remainder of startup message
+   */
+#if (ELP_KERNEL_TYPE < 2)
+  printk("%s: 3c505 card found at I/O 0x%x using IRQ%d has address %s\n",
+         dev->name, dev->base_addr, dev->irq, eth_print(dev->dev_addr));
+#else
+  printk("%s: 3c505 card found at I/O 0x%x using IRQ%d has address %02x:%02x:%02x:%02x:%02x:%02x\n",
+         dev->name, dev->base_addr, dev->irq,
+         dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+         dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+#endif
   
+  /*
+   * initialise the device
+   */
   elp_init(dev);
   return 0;
 }
-
diff -u --recursive --new-file v1.1.24/linux/drivers/net/3c505.h linux/drivers/net/3c505.h
--- v1.1.24/linux/drivers/net/3c505.h	Mon Jun 27 16:46:59 1994
+++ linux/drivers/net/3c505.h	Thu Jul  7 18:28:28 1994
@@ -72,7 +72,7 @@
  *
  *****************************************************************/
 
-#define	TIMEOUT	10000
+#define	TIMEOUT	300
 
 /*****************************************************************
  *
@@ -101,6 +101,7 @@
   CMD_SELF_TEST			= 0x0f,
   CMD_SET_STATION_ADDRESS	= 0x10,
   CMD_ADAPTER_INFO		= 0x11,
+  NUM_TRANSMIT_CMDS,
 
   /*
    * adapter PCB commands
diff -u --recursive --new-file v1.1.24/linux/drivers/net/3c505dta.h linux/drivers/net/3c505dta.h
--- v1.1.24/linux/drivers/net/3c505dta.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/3c505dta.h	Thu Jul  7 18:28:28 1994
@@ -0,0 +1,119 @@
+/* This header file defines some data structures used by the 3c505 driver */
+
+/* Data units */
+typedef unsigned char         byte;
+typedef unsigned short int    word;
+typedef unsigned long int     dword;
+
+
+/* Data structures */
+struct Memconf {
+	word	cmd_q,
+		rcv_q,
+		mcast,
+		frame,
+		rcv_b,
+		progs;
+};
+
+struct Rcv_pkt {
+	word	buf_ofs,
+		buf_seg,
+		buf_len,
+		timeout;
+};
+
+struct Xmit_pkt {
+	word	buf_ofs,
+		buf_seg,
+		pkt_len;
+};
+
+struct Rcv_resp {
+	word	buf_ofs,
+		buf_seg,
+		buf_len,
+		pkt_len,
+		timeout,
+		status;
+	dword	timetag;
+};
+
+struct Xmit_resp {
+	word	buf_ofs,
+		buf_seg,
+		c_stat,
+		status;
+};
+
+
+struct Netstat {
+	dword	tot_recv,
+		tot_xmit;
+	word	err_CRC,
+		err_align,
+		err_res,
+		err_ovrrun;
+};
+
+
+struct Selftest {
+	word	error;
+	union {
+		word ROM_cksum;
+		struct {
+			word ofs, seg;
+		} RAM;
+		word i82586;
+	} failure;
+};
+
+struct Info {
+	byte	minor_vers,
+		major_vers;
+	word	ROM_cksum,
+		RAM_sz,
+		free_ofs,
+		free_seg;
+};
+
+struct Memdump {
+       word size,
+            off,
+            seg;
+};
+
+/*
+Primary Command Block. The most important data structure. All communication
+between the host and the adapter is done with these. (Except for the ethernet
+data, which has different packaging.)
+*/
+typedef struct {
+	byte	command;
+	byte	length;
+	union	{
+		struct Memconf		memconf;
+		word			configure;
+		struct Rcv_pkt		rcv_pkt;
+		struct Xmit_pkt		xmit_pkt;
+		byte			multicast[10][6];
+		byte			eth_addr[6];
+		byte			failed;
+		struct Rcv_resp		rcv_resp;
+		struct Xmit_resp	xmit_resp;
+		struct Netstat		netstat;
+		struct Selftest		selftest;
+		struct Info		info;
+		struct Memdump    	memdump;
+		byte			raw[62];
+	} data;
+} pcb_struct;
+
+/* These defines for 'configure' */
+#define RECV_STATION	0x00
+#define RECV_BROAD	0x01
+#define RECV_MULTI	0x02
+#define RECV_ALL	0x04
+#define NO_LOOPBACK	0x00
+#define INT_LOOPBACK	0x08
+#define EXT_LOOPBACK	0x10
diff -u --recursive --new-file v1.1.24/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.1.24/linux/drivers/net/Makefile	Wed Jun 22 14:57:08 1994
+++ linux/drivers/net/Makefile	Thu Jul  7 18:05:15 1994
@@ -20,6 +20,10 @@
 
 net_init.o: ../../include/linux/autoconf.h
 
+ifdef CONFIG_SK_G16
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(sk_g16.o)
+endif
+
 ifdef CONFIG_WD80x3
 NETDRV_OBJS := $(NETDRV_OBJS) net.a(wd.o)
 CONFIG_8390 = CONFIG_8390
@@ -46,6 +50,11 @@
 CONFIG_8390 = CONFIG_8390
 hp.o:	hp.c CONFIG
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $<
+endif
+
+ifdef CONFIG_HPLAN_PLUS
+NETDRV_OBJS := $(NETDRV_OBJS) net.a(hp-plus.o)
+CONFIG_8390 = CONFIG_8390
 endif
 
 ifdef CONFIG_ULTRA
diff -u --recursive --new-file v1.1.24/linux/drivers/net/README.3c505 linux/drivers/net/README.3c505
--- v1.1.24/linux/drivers/net/README.3c505	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/README.3c505	Thu Jul  7 18:28:28 1994
@@ -0,0 +1,35 @@
+The address and IRQ used by the 3c505 driver can be configured at boot
+time by typing 'ether=eth0,15,0x300' (replace IRQ and base address with
+ones that tell how your adapter is jumpered).
+
+If no base address is given at the boot time, the driver will look for
+a 3c505 adapter at addresses 0x300, 0x280 and 0x310 in this order,
+possibly messing up any other hardware residing in these addresses.
+If a base address is given, it will be verified.
+
+There's two #defines one may need to change in the 3c505 driver:
+ELP_KERNEL_TYPE
+ this exists just to adapt the driver with pretty wide range of kernels.
+ See 3c505.c for exact information.
+
+ELP_NEED_HARD_RESET
+ some DOS drivers seem to get the adapter to some irrecoverable state
+ if the machine is "warm booted" from DOS to Linux. If you experience
+ problems when warm booting, but "cold boot" works, #defining this
+ to 1 may help.
+
+
+Known problems:
+ when 'ifconfig up' is run for the first time after bootup, the driver
+ complains:
+elp_interrupt(): irq 15 for unknown device.
+                     ^^
+ There should be the IRQ the ELPlus adapter is using. IF the IRQ doesn't
+ match, something is seriously wrong.
+
+Authors:
+ The driver is mainly written by Craig Southeren, email c/o
+ <geoffw@extro.ucc.su.OZ.AU>.
+ Parts of the driver (adapting the driver to 1.1.4+ kernels,
+ IRQ/address detection, minor changes) and this (lousy) 'readme'
+ by Juha Laiho <jlaiho@ichaos.nullnet.fi>.
diff -u --recursive --new-file v1.1.24/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.1.24/linux/drivers/net/Space.c	Wed Jun 22 14:57:08 1994
+++ linux/drivers/net/Space.c	Thu Jul  7 18:05:15 1994
@@ -42,6 +42,7 @@
 extern int el2_probe(struct device *dev);
 extern int ne_probe(struct device *dev);
 extern int hp_probe(struct device *dev);
+extern int hp_plus_probe(struct device *dev);
 extern int znet_probe(struct device *);
 extern int express_probe(struct device *);
 extern int el3_probe(struct device *);
@@ -53,6 +54,7 @@
 extern int elplus_probe(struct device *);
 extern int ac3200_probe(struct device *);
 extern int e2100_probe(struct device *);
+extern int SK_init(struct device *dev);
 
 /* Detachable devices ("pocket adaptors" and special PCMCIA drivers). */
 extern int atp_init(struct device *);
@@ -83,6 +85,9 @@
 #if defined(CONFIG_HPLAN) || defined(HPLAN)
 	&& hp_probe(dev)
 #endif
+#if defined(CONFIG_HPLAN_PLUS)
+	&& hp_plus_probe(dev)
+#endif
 #ifdef CONFIG_AT1500
 	&& at1500_probe(dev)
 #endif
@@ -121,6 +126,9 @@
 #endif
 #ifdef CONFIG_DE620		/* D-Link DE-620 adapter */
 	&& de620_probe(dev)
+#endif
+#if defined(CONFIG_SK_G16)
+	&& SK_init(dev)
 #endif
 	&& 1 ) {
 	return 1;	/* -ENODEV or -EAGAIN would be more accurate. */
diff -u --recursive --new-file v1.1.24/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c
--- v1.1.24/linux/drivers/net/ac3200.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/ac3200.c	Thu Jul  7 18:05:43 1994
@@ -0,0 +1,275 @@
+/* ac3200.c: A driver for the Ansel Communications EISA ethernet adaptor. */
+/*
+	Written 1993, 1994 by Donald Becker.
+	Copyright 1993 United States Government as represented by the Director,
+	National Security Agency.  This software may only be used and distributed
+	according to the terms of the GNU Public License as modified by SRC,
+	incorporated herein by reference.
+
+	The author may be reached as becker@cesdis.gsfc.nasa.gov, or
+    C/O Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN
+	Adapter.  The programming information is from the users manual, as related
+	by glee@ardnassak.math.clemson.edu.
+  */
+
+static char *version =
+	"ac3200.c:v1.01 7/1/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include "8390.h"
+
+/* Offsets from the base address. */
+#define AC_NIC_BASE		0x00
+#define AC_SA_PROM		0x16			/* The station address PROM. */
+#define  AC_ADDR0		 0x00			/* Prefix station address values. */
+#define  AC_ADDR1		 0x40			/* !!!!These are just guesses!!!! */
+#define  AC_ADDR2		 0x90
+#define AC_ID_PORT		0xC80
+#define AC_EISA_ID		 0x0110d305
+#define AC_RESET_PORT	0xC84
+#define  AC_RESET		 0x00
+#define  AC_ENABLE		 0x01
+#define AC_CONFIG		0xC90	/* The configuration port. */
+
+/* Decoding of the configuration register. */
+static unsigned char config2irqmap[8] = {15, 12, 11, 10, 9, 7, 5, 3};
+static int addrmap[8] =
+{0xFF0000, 0xFE0000, 0xFD0000, 0xFFF0000, 0xFFE0000, 0xFFC0000,  0xD0000, 0 };
+static char *port_name[4] = { "10baseT", "invalid", "AUI", "10base2"};
+
+#define config2irq(configval)	config2irqmap[((configval) >> 3) & 7]
+#define config2mem(configval)	addrmap[(configval) & 7]
+#define config2name(configval)	port_name[((configval) >> 6) & 3]
+
+/* First and last 8390 pages. */
+#define AC_START_PG		0x00	/* First page of 8390 TX buffer */
+#define AC_STOP_PG		0x80	/* Last page +1 of the 8390 RX ring */
+
+int ac3200_probe(struct device *dev);
+static int ac_probe1(int ioaddr, struct device *dev);
+
+static int ac_open(struct device *dev);
+static void ac_reset_8390(struct device *dev);
+static int ac_block_input(struct device *dev, int count,
+						  char *buf, int ring_offset);
+static void ac_block_output(struct device *dev, const int count,
+							const unsigned char *buf, const int start_page);
+static int ac_close_card(struct device *dev);
+
+
+/*	Probe for the AC3200.
+
+	The AC3200 can be identified by either the EISA configuration registers,
+	or the unique value in the station address PROM.
+	*/
+
+int ac3200_probe(struct device *dev)
+{
+	unsigned short ioaddr = dev->base_addr;
+
+	if (ioaddr > 0x1ff)		/* Check a single specified location. */
+		return ac_probe1(ioaddr, dev);
+	else if (ioaddr > 0)		/* Don't probe at all. */
+		return ENXIO;
+
+	/* If you have a pre-pl15 machine you should delete this line. */
+	if ( ! EISA_bus)
+		return ENXIO;
+
+	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000)
+		if (ac_probe1(ioaddr, dev) == 0)
+			return 0;
+
+	return ENODEV;
+}
+
+static int ac_probe1(int ioaddr, struct device *dev)
+{
+	int i;
+
+#ifndef final_version
+	printk("AC3200 ethercard probe at %#3x:", ioaddr);
+
+	for(i = 0; i < 6; i++)
+		printk(" %02x", inb(ioaddr + AC_SA_PROM + i));
+#endif
+
+	/* !!!!The values of AC_ADDRn (see above) should be corrected when we
+	   find out the correct station address prefix!!!! */
+	if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
+		|| inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1
+		|| inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) {
+#ifndef final_version
+		printk(" not found (invalid prefix).\n");
+#endif
+		return ENODEV;
+	}
+
+	/* The correct probe method is to check the EISA ID. */
+	for (i = 0; i < 4; i++)
+		if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID) {
+			printk("EISA ID mismatch, %8x vs %8x.\n",
+				   inl(ioaddr + AC_EISA_ID), AC_EISA_ID); 
+			return ENODEV;
+		}
+
+	for(i = 0; i < ETHER_ADDR_LEN; i++)
+		dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
+
+#ifndef final_version
+	printk("\nAC3200 ethercard configuration register is %#02x,"
+		   " EISA ID %02x %02x %02x %02x.\n", inb(ioaddr + AC_CONFIG),
+		   inb(ioaddr + AC_ID_PORT + 0), inb(ioaddr + AC_ID_PORT + 1),
+		   inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
+#endif
+
+	/* Assign and snarf the interrupt now. */
+	if (dev->irq == 0)
+		dev->irq = config2irq(inb(ioaddr + AC_CONFIG));
+	else if (dev->irq == 2)
+		dev->irq = 9;
+
+	if (irqaction (dev->irq, &ei_sigaction)) {
+		printk (" unable to get IRQ %d.\n", dev->irq);
+		return 0;
+	}
+
+	dev->base_addr = ioaddr;
+
+#ifdef notyet
+	if (dev->mem_start)	{		/* Override the value from the board. */
+		for (i = 0; i < 7; i++)
+			if (addrmap[i] == dev->mem_start)
+				break;
+		if (i >= 7)
+			i = 0;
+		outb((inb(ioaddr + AC_CONFIG) & ~7) | i, ioaddr + AC_CONFIG);
+	}
+#endif
+
+	dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
+	dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
+	dev->rmem_start = dev->mem_start + TX_PAGES*256;
+	dev->mem_end = dev->rmem_end = dev->mem_start
+		+ (AC_STOP_PG - AC_START_PG)*256;
+
+	ethdev_init(dev);
+
+	ei_status.name = "AC3200";
+	ei_status.tx_start_page = AC_START_PG;
+	ei_status.rx_start_page = AC_START_PG + TX_PAGES;
+	ei_status.stop_page = AC_STOP_PG;
+	ei_status.word16 = 1;
+
+	printk("\n%s: AC3200 at %#x, IRQ %d, %s port, shared memory %#lx-%#lx.\n",
+		   dev->name, ioaddr, dev->irq, port_name[dev->if_port],
+		   dev->mem_start, dev->mem_end-1);
+
+	if (ei_debug > 0)
+		printk(version);
+
+	ei_status.reset_8390 = &ac_reset_8390;
+	ei_status.block_input = &ac_block_input;
+	ei_status.block_output = &ac_block_output;
+
+	dev->open = &ac_open;
+	dev->stop = &ac_close_card;
+	NS8390_init(dev, 0);
+	return 0;
+}
+
+static int ac_open(struct device *dev)
+{
+#ifdef notyet
+	/* Someday we may enable the IRQ and shared memory here. */
+	int ioaddr = dev->base_addr;
+
+	if (irqaction(dev->irq, &ei_sigaction))
+		return -EAGAIN;
+#endif
+
+	return ei_open(dev);
+}
+
+static void ac_reset_8390(struct device *dev)
+{
+	ushort ioaddr = dev->base_addr;
+
+	outb(AC_RESET, ioaddr + AC_RESET_PORT);
+	if (ei_debug > 1) printk("resetting AC3200, t=%ld...", jiffies);
+
+	ei_status.txing = 0;
+	outb(AC_ENABLE, ioaddr + AC_RESET_PORT);
+	if (ei_debug > 1) printk("reset done\n");
+
+	return;
+}
+
+/*  Block input and output are easy on shared memory ethercards, the only
+	complication is when the ring buffer wraps. */
+
+static int ac_block_input(struct device *dev, int count, char *buf,
+						  int ring_offset)
+{
+	long xfer_start = dev->mem_start + ring_offset - (AC_START_PG<<8);
+
+	if (xfer_start + count > dev->rmem_end) {
+		/* We must wrap the input move. */
+		int semi_count = dev->rmem_end - xfer_start;
+		memcpy(buf, (char*)xfer_start, semi_count);
+		count -= semi_count;
+		memcpy(buf + semi_count, (char *)dev->rmem_start, count);
+		return dev->rmem_start + count;
+	}
+	memcpy(buf, (char*)xfer_start, count);
+
+	return ring_offset + count;
+}
+
+static void ac_block_output(struct device *dev, int count,
+							const unsigned char *buf, int start_page)
+{
+	long shmem = dev->mem_start + ((start_page - AC_START_PG)<<8);
+
+	memcpy((unsigned char *)shmem, buf, count);
+}
+
+static int ac_close_card(struct device *dev)
+{
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (ei_debug > 1)
+		printk("%s: Shutting down ethercard.\n", dev->name);
+
+#ifdef notyet
+	/* We should someday disable shared memory and interrupts. */
+	outb(0x00, ioaddr + 6);	/* Disable interrupts. */
+	free_irq(dev->irq);
+	irq2dev_map[dev->irq] = 0;
+#endif
+
+	NS8390_init(dev, 0);
+
+	return 0;
+}
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c ac3200.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 4
+ * End:
+ */
Only in v1.1.24/linux/drivers/net: ac32000.c
diff -u --recursive --new-file v1.1.24/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c
--- v1.1.24/linux/drivers/net/hp-plus.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/hp-plus.c	Thu Jul  7 18:03:36 1994
@@ -0,0 +1,366 @@
+/* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */
+/*
+	Written 1994 by Donald Becker.
+
+	This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
+	These cards are sold under several model numbers, usually 2724*.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+
+	Center of Excellence in Space Data and Information Sciences
+		Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	As is often the case, a great deal of credit is owed to Russ Nelson.
+	The Crynwr packet driver was my primary source of HP-specific
+	programming information.
+*/
+
+static char *version =
+"hp-plus.c:v0.04 6/16/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+
+#include <linux/config.h>
+#include <linux/string.h>		/* Important -- this inlines word moves. */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#ifdef start_bh_atomic			/* This checks for kernels >= 1.1.0. */
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#else
+#include "dev.h"
+#endif
+
+#include "8390.h"
+
+/*
+   The HP EtherTwist chip implementation is a fairly routine DP8390
+   implementation.  It allows both shared memory and programmed-I/O buffer
+   access, using a custom interface for both.  The programed-I/O mode is
+   entirely implemented in the HP EtherTwist chip, bypassing the problem
+   ridden built-in 8390 facilities used on NE2000 designs.  The shared
+   memory mode is likewise special, with an offset register used to make
+   packets appear at the shared memory base.  Both modes use a base and bounds
+   page register to hide the Rx ring buffer wrap -- a packet that spans the
+   end of physical buffer memory appears continuous to the driver. (c.f. the
+   3c503 and Cabletron E2100)
+
+   A special note: the internal buffer of the board is only 8 bits wide.
+   This lays several nasty traps for the unaware:
+   - the 8390 must be programmed for byte-wide operations
+   - all I/O and memory operations must work on whole words (the access
+     latches are serially preloaded and have no byte-swapping ability).
+
+   This board is laid out in I/O space much like the earlier HP boards:
+   the first 16 locations are for the board registers, and the second 16 are
+   for the 8390.  The board is easy to identify, with both a dedicated 16 bit
+   ID register and a constant 0x530* value in the upper bits of the paging
+   register.
+*/
+
+#define HPP_PROBE_LIST {0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0}
+
+#define HP_IO_EXTENT	32
+
+#define HP_ID			0x00	/* ID register, always 0x4850. */
+#define HP_PAGING		0x02	/* Registers visible @ 8-f, see PageName. */ 
+#define HPP_OPTION		0x04	/* Bitmapped options, see HP_Option.	*/
+#define HPP_OUT_ADDR	0x08	/* I/O output location in Perf_Page.	*/
+#define HPP_IN_ADDR		0x0A	/* I/O input location in Perf_Page.		*/
+#define HP_DATAPORT		0x0c	/* I/O data transfer in Perf_Page.		*/
+#define NIC_OFFSET		0x10	/* Offset to the 8390 registers.		*/
+
+#define HP_START_PG		0x00	/* First page of TX buffer */
+#define HP_STOP_PG		0x80	/* Last page +1 of RX ring */
+
+/* The register set selected in HP_PAGING. */
+enum PageName {
+	Perf_Page = 0,				/* Normal operation. */
+	MAC_Page = 1,				/* The ethernet address (+checksum). */
+	HW_Page = 2,				/* EEPROM-loaded hardware parameters. */
+	LAN_Page = 4,				/* Transceiver selection, testing, etc. */
+	ID_Page = 6 }; 
+
+/* The bit definitions for the HPP_OPTION register. */
+enum HP_Option {
+	NICReset = 1, ChipReset = 2, 	/* Active low, really UNreset. */
+	EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20,
+	MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, };
+
+int hpplus_probe(struct device *dev);
+int hpp_probe1(struct device *dev, int ioaddr);
+
+static void hpp_reset_8390(struct device *dev);
+static int hpp_open(struct device *dev);
+static int hpp_close(struct device *dev);
+static int hpp_mem_block_input(struct device *dev, int count,
+						  char *buf, int ring_offset);
+static void hpp_mem_block_output(struct device *dev, int count,
+							const unsigned char *buf, const start_page);
+static int hpp_io_block_input(struct device *dev, int count,
+						  char *buf, int ring_offset);
+static void hpp_io_block_output(struct device *dev, int count,
+							const unsigned char *buf, const start_page);
+
+
+/*	Probe a list of addresses for an HP LAN+ adaptor.
+	This routine is almost boilerplate. */
+
+int hp_plus_probe(struct device *dev)
+{
+	int *port, ports[] = HPP_PROBE_LIST;
+	short ioaddr = dev->base_addr;
+
+	if (ioaddr > 0x1ff)			/* Check a single specified location. */
+		return hpp_probe1(dev, ioaddr);
+	else if (ioaddr > 0)				/* Don't probe at all. */
+		return ENXIO;
+
+	for (port = &ports[0]; *port; port++) {
+		if (check_region(*port, HP_IO_EXTENT))
+			continue;
+		if (hpp_probe1(dev, *port) == 0) {
+			return 0;
+		}
+	}
+	return ENODEV;
+}
+
+/* Do the interesting part of the probe at a single address. */
+int hpp_probe1(struct device *dev, int ioaddr)
+{
+	int i;
+	unsigned char checksum = 0;
+	char *name = "HP-PC-LAN+";
+	unsigned char *station_addr = dev->dev_addr;
+	int mem_start;
+
+	/* Check for the HP+ signature, 50 48 0x 53. */
+	if (inw(ioaddr + HP_ID) != 0x4850
+		|| (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300)
+		return ENODEV;
+
+	/* OK, we think that we have it.  Get and checksum the physical address. */
+	printk("%s: %s at %#3x,", dev->name, name, ioaddr);
+
+	/* Retrieve and checksum the station address. */
+	outw(MAC_Page, ioaddr + HP_PAGING);
+
+	for(i = 0; i < ETHER_ADDR_LEN; i++) {
+		unsigned char inval = inb(ioaddr + 8 + i);
+		station_addr[i] = inval;
+		checksum += inval;
+		printk(" %2.2x", inval);
+	}
+	checksum += inb(ioaddr + 14);
+
+	if (checksum != 0xff) {
+		printk(" bad checksum %2.2x.\n", checksum);
+		return ENODEV;
+	} else {
+		/* Point at the Software Configuration Flags. */
+		outw(ID_Page, ioaddr + HP_PAGING);
+		printk(" ID %4.4x", inw(ioaddr + 12));
+	}
+
+	/* Grab the region so we can find another board if something fails. */
+	snarf_region(ioaddr, HP_IO_EXTENT);
+
+	/* Read the IRQ line. */
+	outw(HW_Page, ioaddr + HP_PAGING);
+	{
+		int irq = inb(ioaddr + 13) & 0x0f;
+		int option = inw(ioaddr + HPP_OPTION);
+
+		dev->irq = irq;
+		if (option & MemEnable) {
+			mem_start = inw(ioaddr + 9) << 8;
+			printk(", IRQ %d, memory address %#x.\n", irq, mem_start);
+		} else {
+			mem_start = 0;
+			printk(", IRQ %d, programmed-I/O mode.\n", irq);
+		}
+	}
+
+	printk( "%s%s", KERN_INFO, version);
+
+	/* Set the wrap registers for string I/O reads.   */
+	outw((HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
+
+	/* Set the base address to point to the NIC, not the "real" base! */
+	dev->base_addr = ioaddr + NIC_OFFSET;
+
+	ethdev_init(dev);
+
+    dev->open = &hpp_open;
+    dev->stop = &hpp_close;
+
+	ei_status.name = name;
+	ei_status.word16 = 0;		/* Agggghhhhh! Debug time: 2 days! */
+	ei_status.tx_start_page = HP_START_PG;
+	ei_status.rx_start_page = HP_START_PG + TX_2X_PAGES;
+	ei_status.stop_page = HP_STOP_PG;
+
+	ei_status.reset_8390 = &hpp_reset_8390;
+	ei_status.block_input = &hpp_io_block_input;
+	ei_status.block_output = &hpp_io_block_output;
+
+	/* Check if the memory_enable flag is set in the option register. */
+	if (mem_start) {
+		ei_status.block_input = &hpp_mem_block_input;
+		ei_status.block_output = &hpp_mem_block_output;
+		dev->mem_start = mem_start;
+		dev->rmem_start = dev->mem_start + TX_2X_PAGES*256;
+		dev->mem_end = dev->rmem_end
+			= dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
+	}
+
+	outw(Perf_Page, ioaddr + HP_PAGING);
+	NS8390_init(dev, 0);
+	/* Leave the 8390 and HP chip reset. */
+	outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
+
+	return 0;
+}
+
+static int
+hpp_open(struct device *dev)
+{
+	int ioaddr = dev->base_addr - NIC_OFFSET;
+	int option_reg;
+
+	if (request_irq(dev->irq, &ei_interrupt)) {
+	    return -EAGAIN;
+	}
+
+	/* Reset the 8390 and HP chip. */
+	option_reg = inw(ioaddr + HPP_OPTION);
+	outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
+	SLOW_DOWN_IO; SLOW_DOWN_IO;
+	/* Unreset the board and enable interrupts. */
+	outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
+
+	/* Set the wrap registers for programmed-I/O operation.   */
+	outw(HW_Page, ioaddr + HP_PAGING);
+	outw((HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
+
+	/* Select the operational page. */
+	outw(Perf_Page, ioaddr + HP_PAGING);
+
+    return ei_open(dev);
+}
+
+static int
+hpp_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr - NIC_OFFSET;
+	int option_reg = inw(ioaddr + HPP_OPTION);
+
+    free_irq(dev->irq);
+    irq2dev_map[dev->irq] = NULL;
+    NS8390_init(dev, 0);
+	outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
+		 ioaddr + HPP_OPTION);
+
+    return 0;
+}
+
+static void
+hpp_reset_8390(struct device *dev)
+{
+	int ioaddr = dev->base_addr - NIC_OFFSET;
+	int option_reg = inw(ioaddr + HPP_OPTION);
+
+	if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
+
+	outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
+	/* Pause a few cycles for the hardware reset to take place. */
+	SLOW_DOWN_IO;
+	SLOW_DOWN_IO;
+	ei_status.txing = 0;
+	outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
+
+	SLOW_DOWN_IO; SLOW_DOWN_IO;
+
+
+	if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
+		printk("%s: hp_reset_8390() did not complete.\n", dev->name);
+
+	if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
+	return;
+}
+
+/* Block input and output, similar to the Crynwr packet driver.
+   Note that transfer with the EtherTwist+ must be on word boundaries. */
+
+static int
+hpp_io_block_input(struct device *dev, int count, char *buf, int ring_offset)
+{
+	int ioaddr = dev->base_addr - NIC_OFFSET;
+
+	outw(ring_offset, ioaddr + HPP_IN_ADDR);
+	insw(ioaddr + HP_DATAPORT, buf, count>>1);
+	if (count & 0x01)
+        buf[count-1] = inw(ioaddr + HP_DATAPORT);
+	return ring_offset + count;
+}
+
+static int
+hpp_mem_block_input(struct device *dev, int count, char *buf, int ring_offset)
+{
+	int ioaddr = dev->base_addr - NIC_OFFSET;
+	int option_reg = inw(ioaddr + HPP_OPTION);
+
+	outw(ring_offset, ioaddr + HPP_IN_ADDR);
+
+	outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
+	/* Caution: this relies on 8390.c rounding up allocations! */
+	memcpy(buf, (char*)dev->mem_start,  (count + 3) & ~3);
+	outw(option_reg, ioaddr + HPP_OPTION);
+
+	return ring_offset + count;
+}
+
+/* A special note: we *must* always transfer >=16 bit words.
+   It's always safe to round up, so we do. */
+static void
+hpp_io_block_output(struct device *dev, int count,
+					const unsigned char *buf, const start_page)
+{
+	int ioaddr = dev->base_addr - NIC_OFFSET;
+	outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
+	outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
+	return;
+}
+
+static void
+hpp_mem_block_output(struct device *dev, int count,
+				const unsigned char *buf, const start_page)
+{
+	int ioaddr = dev->base_addr - NIC_OFFSET;
+	int option_reg = inw(ioaddr + HPP_OPTION);
+
+	outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
+	outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
+	memcpy((char *)dev->mem_start, buf, (count + 3) & ~3);
+	outw(option_reg, ioaddr + HPP_OPTION);
+
+	return;
+}
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp-plus.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * tab-width: 4
+ * c-indent-level: 4
+ * End:
+ */
diff -u --recursive --new-file v1.1.24/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c
--- v1.1.24/linux/drivers/net/sk_g16.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sk_g16.c	Thu Jul  7 17:56:36 1994
@@ -0,0 +1,2119 @@
+/*-
+ * Copyright (C) 1994 by PJD Weichmann & SWS Bern, Switzerland
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ *
+ * Module         : sk_g16.c
+ *
+ * Version        : $Revision: 1.1 $
+ *
+ * Author         : Patrick J.D. Weichmann
+ *
+ * Date Created   : 94/05/26
+ * Last Updated   : $Date: 1994/06/30 16:25:15 $
+ *
+ * Description    : Schneider & Koch G16 Ethernet Device Driver for
+ *                  Linux Kernel >= 1.1.22
+ * Update History :
+ *
+-*/
+
+static char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $";
+
+/*
+ * The Schneider & Koch (SK) G16 Network device driver is based
+ * on the 'ni6510' driver from Michael Hipp which can be found at
+ * ftp://sunsite.unc.edu/pub/Linux/system/Network/drivers/nidrivers.tar.gz
+ * 
+ * Sources: 1) ni6510.c by M. Hipp
+ *          2) depca.c  by D.C. Davies
+ *          3) skeleton.c by D. Becker
+ *          4) Am7990 Local Area Network Controller for Ethernet (LANCE),
+ *             AMD, Pub. #05698, June 1989
+ *
+ * Many Thanks for helping me to get things working to: 
+ *                 
+ *                 A. Cox (A.Cox@swansea.ac.uk)
+ *                 M. Hipp (mhipp@student.uni-tuebingen.de)
+ *                 R. Bolz (Schneider & Koch, Germany)
+ *
+ * See README.sk_g16 for details about limitations and bugs for the
+ * current version.
+ *
+ * To Do: 
+ *        - Support of SK_G8 and other SK Network Cards.
+ *        - Autoset memory mapped RAM. Check for free memory and then
+ *          configure RAM correctly. 
+ *        - SK_close should really set card in to initial state.
+ *        - Test if IRQ 3 is not switched off. Use autoirq() functionality.
+ *          (as in /drivers/net/skeleton.c)
+ *        - Implement Multicast addressing. At minimum something like
+ *          in depca.c. 
+ *        - Redo the statistics part.
+ *        - Try to find out if the board is in 8 Bit or 16 Bit slot.
+ *          If in 8 Bit mode don't use IRQ 11.
+ *        - (Try to make it slightly faster.) 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/string.h> 
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/bitops.h> 
+#include <errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sk_g16.h"
+
+/* 
+ * Schneider & Koch Card Definitions 
+ * =================================
+ */  
+
+#define SK_NAME   "SK_G16"
+
+/*
+ * SK_G16 Configuration
+ * --------------------
+ */ 
+
+/* 
+ * Abbreviations
+ * -------------
+ *  
+ * RAM - used for the 16KB shared memory 
+ * Boot_ROM, ROM - are used for referencing the BootEPROM
+ *
+ * SK_BOOT_ROM and SK_ADDR are symbolic constants used to configure
+ * the behaviour of the driver and the SK_G16.
+ *
+ * ! See sk_g16.install on how to install and configure the driver !   
+ *
+ * SK_BOOT_ROM defines if the Boot_ROM should be switched off or not.
+ *
+ * SK_ADDR defines the address where the RAM will be mapped into the real
+ *         host memory.
+ *         valid addresses are from 0xa0000 to 0xfc000 in 16Kbyte steps.
+ */  
+ 
+#define SK_BOOT_ROM     1              /* 1=BootROM on 0=off */
+
+#define SK_ADDR         0xcc000
+
+/* 
+ * In POS3 are bits A14-A19 of the address bus. These bits can be set
+ * to choose the RAM address. Thats why we only can choose the RAM address
+ * in 16KB steps.
+ */
+
+#define POS_ADDR       (rom_addr>>14)  /* Do not change this line */
+
+/* 
+ * SK_G16 I/O PORT's + IRQ's + Boot_ROM locations
+ * ----------------------------------------------
+ */
+
+/* 
+ * As nearly every card has also SK_G16 a specified I/O Port region and
+ * only a few possible IRQ's.
+ * In the Installation Guide from Schneider & Koch is listed a possible
+ * Interrupt IRQ2. IRQ2 is always IRQ9 in boards with two cascaded interrupt
+ * controllers. So we use in SK_IRQS IRQ9.
+ */
+
+/* Don't touch any of the following #defines. */
+
+#define SK_IO_PORTS     { 0x100, 0x180, 0x208, 0x220, 0x288, 0x320, 0x328, 0x390, 0 }
+
+#define SK_IRQS         { 3, 5, 9, 11, 0 }
+
+#define SK_BOOT_ROM_LOCATIONS { 0xc0000, 0xc4000, 0xc8000, 0xcc000, 0xd0000, 0xd4000, 0xd8000, 0xdc000, 0 }
+
+#define SK_BOOT_ROM_ID  { 0x55, 0xaa, 0x10, 0x50, 0x06, 0x33 }
+
+/* 
+ * SK_G16 POS REGISTERS 
+ * --------------------
+ */
+
+/*
+ * SK_G16 has a Programmable Option Select (POS) Register.
+ * The POS is composed of 8 separate registers (POS0-7) which 
+ * are I/O mapped on an address set by the W1 switch.                    
+ *
+ */
+
+#define SK_POS_SIZE 8           /* 8 I/O Ports are used by SK_G16 */
+
+#define SK_POS0     ioaddr      /* Card-ID Low (R) */
+#define SK_POS1     ioaddr+1    /* Card-ID High (R) */
+#define SK_POS2     ioaddr+2    /* Card-Enable, Boot-ROM Disable (RW) */
+#define SK_POS3     ioaddr+3    /* Base address of RAM */
+#define SK_POS4     ioaddr+4    /* IRQ */
+
+/* POS5 - POS7 are unused */
+
+/* 
+ * SK_G16 MAC PREFIX 
+ * -----------------
+ */
+
+/* 
+ * Scheider & Koch manufactorer code (00:00:a5).
+ * This must be checked, that we are sure it is a SK card.
+ */
+
+#define SK_MAC0         0x00
+#define SK_MAC1         0x00
+#define SK_MAC2         0x5a
+
+/* 
+ * SK_G16 ID 
+ * ---------
+ */ 
+
+/* 
+ * If POS0,POS1 contain the following ID, then we know
+ * at which I/O Port Address we are. 
+ */
+
+#define SK_IDLOW  0xfd 
+#define SK_IDHIGH 0x6a
+
+
+/* 
+ * LANCE POS Bit definitions 
+ * -------------------------
+ */
+
+#define SK_ROM_RAM_ON  (POS2_CARD)
+#define SK_ROM_RAM_OFF (POS2_EPROM)
+#define SK_ROM_ON      (inb(SK_POS2) & POS2_CARD)
+#define SK_ROM_OFF     (inb(SK_POS2) | POS2_EPROM)
+#define SK_RAM_ON      (inb(SK_POS2) | POS2_CARD)
+#define SK_RAM_OFF     (inb(SK_POS2) & POS2_EPROM) 
+
+#define POS2_CARD  0x0001              /* 1 = SK_G16 on      0 = off */
+#define POS2_EPROM 0x0002              /* 1 = Boot EPROM off 0 = on */ 
+
+/* 
+ * SK_G16 Memory mapped Registers
+ * ------------------------------
+ *
+ */ 
+
+#define SK_IOREG        (board->ioreg) /* LANCE data registers.     */ 
+#define SK_PORT         (board->port)  /* Control, Status register  */
+#define SK_IOCOM        (board->iocom) /* I/O Command               */
+
+/* 
+ * SK_G16 Status/Control Register bits
+ * -----------------------------------
+ *
+ * (C) Controlreg (S) Statusreg 
+ */
+
+/* 
+ * Register transfer: 0 = no transfer
+ *                    1 = transfering data between LANCE and I/O reg 
+ */
+#define SK_IORUN        0x20   
+
+/* 
+ * LANCE interrupt: 0 = LANCE interrupt occured	
+ *                  1 = no LANCE interrupt occured
+ */
+#define SK_IRQ          0x10   
+			
+#define SK_RESET        0x08   /* Reset SK_CARD: 0 = RESET 1 = normal */
+#define SK_RW           0x02   /* 0 = write to 1 = read from */
+#define SK_ADR          0x01   /* 0 = REG DataPort 1 = RAP Reg addr port */
+
+  
+#define SK_RREG         SK_RW  /* Transferdirection to read from lance */
+#define SK_WREG         0      /* Transferdirection to write to lance */
+#define SK_RAP          SK_ADR /* Destination Register RAP */
+#define SK_RDATA        0      /* Destination Register REG DataPort */
+
+/* 
+ * SK_G16 I/O Command 
+ * ------------------
+ */
+
+/* 
+ * Any bitcombination sets the internal I/O bit (transfer will start) 
+ * when written to I/O Command
+ */
+
+#define SK_DOIO         0x80   /* Do Transfer */ 
+ 
+/* 
+ * LANCE RAP (Register Adress Port). 
+ * ---------------------------------
+ */
+
+/*   
+ * The LANCE internal registers are selected through the RAP. 
+ * The Registers are:
+ *
+ * CSR0 - Status and Control flags 
+ * CSR1 - Low order bits of initialize block (bits 15:00)
+ * CSR2 - High order bits of initialize block (bits 07:00, 15:08 are reserved)
+ * CSR3 - Allows redifinition of the Bus Master Interface.
+ *        This register must be set to 0x0002, which means BSWAP = 0,
+ *        ACON = 1, BCON = 0;
+ *
+ */
+ 
+#define CSR0            0x00   
+#define CSR1            0x01  
+#define CSR2            0x02 
+#define CSR3            0x03
+
+/* 
+ * General Definitions 
+ * ===================
+ */
+
+/* 
+ * Set the number of Tx and Rx buffers, using Log_2(# buffers).
+ * We have 16KB RAM which can be accessed by the LANCE. In the 
+ * memory are not only the buffers but also the ring descriptors and
+ * the initialize block. 
+ * Don't change anything unless you really know what you do.
+ */
+
+#define LC_LOG_TX_BUFFERS 1               /* (2 == 2^^1) 2 Transmit buffers */
+#define LC_LOG_RX_BUFFERS 3               /* (8 == 2^^3) 8 Receive buffers */
+
+/* Descriptor ring sizes */
+
+#define TMDNUM (1 << (LC_LOG_TX_BUFFERS)) /* 2 Transmit descriptor rings */
+#define RMDNUM (1 << (LC_LOG_RX_BUFFERS)) /* 8 Receive Buffers */
+
+/* Define Mask for setting RMD, TMD length in the LANCE init_block */
+
+#define TMDNUMMASK (LC_LOG_TX_BUFFERS << 29)
+#define RMDNUMMASK (LC_LOG_RX_BUFFERS << 29)
+
+/*
+ * Data Buffer size is set to maximum packet length.
+ */
+
+#define PKT_BUF_SZ              1518 
+
+/* 
+ * The number of low I/O ports used by the ethercard. 
+ */
+
+#define ETHERCARD_TOTAL_SIZE    SK_POS_SIZE
+
+/* 
+ * Portreserve is there to mark the Card I/O Port region as used. 
+ * Check_region is to check if the region at ioaddr with the size "size" 
+ * is free or not.
+ * Snarf_region allocates the I/O Port region.
+ */
+
+#ifndef HAVE_PORTRESERVE
+
+#define check_region(ioaddr, size)              0
+#define snarf_region(ioaddr, size);             do ; while (0)
+
+#endif
+
+/* 
+ * SK_DEBUG
+ *
+ * Here you can choose what level of debugging wanted.
+ *
+ * If SK_DEBUG and SK_DEBUG2 are undefined, then only the
+ *  necessary messages will be printed.
+ *
+ * If SK_DEBUG is defined, there will be many debugging prints
+ *  which can help to find some mistakes in configuration or even
+ *  in the driver code.
+ *
+ * If SK_DEBUG2 is defined, many many messages will be printed 
+ *  which normally you don't need. I used this to check the interrupt
+ *  routine. 
+ *
+ * (If you define only SK_DEBUG2 then only the messages for 
+ *  checking interrupts will be printed!)
+ *
+ * Normal way of live is: 
+ *
+ * For the whole thing get going let both symbolic constants
+ * undefined. If you face any problems and you know whats going
+ * on (you know something about the card and you can interpret some
+ * hex LANCE register output) then define SK_DEBUG
+ * 
+ */
+
+#undef  SK_DEBUG	/* debugging */
+#undef  SK_DEBUG2	/* debugging with more verbose report */
+
+#ifdef SK_DEBUG
+#define PRINTK(x) printk x
+#else
+#define PRINTK(x) /**/
+#endif
+
+#ifdef SK_DEBUG2
+#define PRINTK2(x) printk x
+#else
+#define PRINTK2(x) /**/
+#endif
+
+/* 
+ * SK_G16 RAM
+ *
+ * The components are memory mapped and can be set in a region from
+ * 0x00000 through 0xfc000 in 16KB steps. 
+ *
+ * The Network components are: dual ported RAM, Prom, I/O Reg, Status-,
+ * Controlregister and I/O Command.
+ *
+ * dual ported RAM: This is the only memory region which the LANCE chip
+ *      has access to. From the Lance it is addressed from 0x0000 to
+ *      0x3fbf. The host accesses it normaly.
+ *
+ * PROM: The PROM obtains the ETHERNET-MAC-Address. It is realised as a
+ *       8-Bit PROM, this means only the 16 even addresses are used of the
+ *       32 Byte Address region. Access to a odd address results in invalid
+ *       data.
+ * 
+ * LANCE I/O Reg: The I/O Reg is build of 4 single Registers, Low-Byte Write,
+ *       Hi-Byte Write, Low-Byte Read, Hi-Byte Read.
+ *       Transfer from or to the LANCE is always in 16Bit so Low and High
+ *       registers are always relevant.
+ *
+ *       The Data from the Readregister is not the data in the Writeregister!!
+ *       
+ * Port: Status- and Controlregister. 
+ *       Two different registers which share the same address, Status is 
+ *       read-only, Control is write-only.
+ *    
+ * I/O Command: 
+ *       Any bitcombination written in here starts the transmission between
+ *       Host and LANCE.
+ */
+
+typedef struct
+{
+	unsigned char  ram[0x3fc0];   /* 16KB dual ported ram */
+	unsigned char  rom[0x0020];   /* 32Byte PROM containing 6Byte MAC */
+	unsigned char  res1[0x0010];  /* reserved */
+	unsigned volatile short ioreg;/* LANCE I/O Register */
+	unsigned volatile char  port; /* Statusregister and Controlregister */
+	unsigned char  iocom;         /* I/O Command Register */
+} SK_RAM;
+
+/* struct  */
+
+/* 
+ * This is the structure for the dual ported ram. We
+ * have exactly 16 320 Bytes. In here there must be:
+ *
+ *     - Initialize Block   (starting at a word boundary)
+ *     - Receive and Transmit Descriptor Rings (quadword boundary)
+ *     - Data Buffers (arbitrary boundary)
+ *
+ * This is because LANCE has on SK_G16 only access to the dual ported
+ * RAM and nowhere else.
+ */
+
+struct SK_ram
+{
+    struct init_block ib;
+    struct tmd tmde[TMDNUM];
+    struct rmd rmde[RMDNUM];
+    char tmdbuf[TMDNUM][PKT_BUF_SZ];
+    char rmdbuf[RMDNUM][PKT_BUF_SZ];
+};
+
+/* 
+ * Structure where all necessary information is for ring buffer 
+ * management and statistics.
+ */
+
+struct priv
+{
+    struct SK_ram *ram;  /* dual ported ram structure */
+    struct rmd *rmdhead; /* start of receive ring descriptors */
+    struct tmd *tmdhead; /* start of transmit ring descriptors */
+    int        rmdnum;   /* actual used ring descriptor */
+    int        tmdnum;   /* actual transmit descriptor for transmitting data */
+    int        tmdlast;  /* last sent descriptor used for error handling, etc */
+    void       *rmdbufs[RMDNUM]; /* pointer to the receive buffers */
+    void       *tmdbufs[TMDNUM]; /* pointer to the transmit buffers */
+    struct enet_statistics stats; /* Device driver statistics */
+};
+
+/* global variable declaration */
+
+/* IRQ map used to reserve a IRQ (see SK_open()) */
+
+extern void *irq2dev_map[16]; 
+
+/* static variables */
+
+static SK_RAM *board;  /* pointer to our memory mapped board components */
+
+/* Macros */
+
+
+/* Function Prototypes */
+
+/*
+ * Device Driver functions
+ * -----------------------
+ * See for short explanation of each function its definitions header.
+ */
+
+int          SK_init(struct device *dev);
+static int   SK_probe(struct device *dev, short ioaddr);
+
+static int   SK_open(struct device *dev);
+static int   SK_send_packet(struct sk_buff *skb, struct device *dev);
+static void  SK_interrupt(int reg_ptr);
+static void  SK_rxintr(struct device *dev);
+static void  SK_txintr(struct device *dev);
+static int   SK_close(struct device *dev);
+
+static struct enet_statistics *SK_get_stats(struct device *dev);
+
+unsigned int SK_rom_addr(void);
+
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+/*
+ * LANCE Functions
+ * ---------------
+ */
+
+static int SK_lance_init(struct device *dev, unsigned short mode);
+void   SK_reset_board(void);
+void   SK_set_RAP(int reg_number);
+int    SK_read_reg(int reg_number);
+int    SK_rread_reg(void);
+void   SK_write_reg(int reg_number, int value);
+
+/* 
+ * Debuging functions
+ * ------------------
+ */
+
+void SK_print_pos(struct device *dev, char *text);
+void SK_print_dev(struct device *dev, char *text);
+void SK_print_ram(struct device *dev);
+
+
+/*-
+ * Function       : SK_init
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/26
+ *
+ * Description    : Check for a SK_G16 network adaptor and initialize it.
+ *                  This function gets called by dev_init which initializes
+ *                  all Network devices.
+ *
+ * Parameters     : I : struct device *dev - structure preconfigured 
+ *                                           from Space.c
+ * Return Value   : 0 = Driver Found and initialized 
+ * Errors         : ENODEV - no device found
+ *                  ENXIO  - not probed
+ * Globals        : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+/* 
+ * Check for a network adaptor of this type, and return '0' if one exists.
+ * If dev->base_addr == 0, probe all likely locations.
+ * If dev->base_addr == 1, always return failure.
+ * If dev->base_addr == 2, alloate space for the device and return success
+ *                         (detachable devices only).
+ */
+
+int SK_init(struct device *dev)
+{
+	int ioaddr         = 0;            /* I/O port address used for POS regs */
+	int *port, ports[] = SK_IO_PORTS;  /* SK_G16 supported ports */
+
+	/* get preconfigured base_addr from dev which is done in Space.c */
+	int base_addr = dev->base_addr; 
+
+        PRINTK(("%s: %s", SK_NAME, rcsid));
+        rcsid = NULL;                 /* We do not want to use this further */
+
+	if (base_addr > 0x0ff)        /* Check a single specified address */
+	{
+	    /* Check if on specified address is a SK_G16 */
+
+	    if ( (inb(SK_POS0) == SK_IDLOW) ||
+		 (inb(SK_POS1) == SK_IDHIGH) )  
+	    {
+		return SK_probe(dev, base_addr);  
+	    }
+
+	    return ENODEV;            /* Sorry, but on specified address NO SK_G16 */
+	}
+	else if (base_addr > 0)       /* Don't probe at all */
+	{
+		return ENXIO;
+	}
+
+	/* Autoprobe base_addr */
+
+	for (port = &ports[0]; *port; port++) 
+	{
+	    ioaddr = *port;           /* we need ioaddr for accessing POS regs */
+
+	    /* Check if I/O Port region is used by another board */
+
+	    if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE))
+	    {
+		continue;             /* Try next Port address */
+	    }
+
+	    /* Check if at ioaddr is a SK_G16 */
+
+	    if ( !(inb(SK_POS0) == SK_IDLOW) ||
+		 !(inb(SK_POS1) == SK_IDHIGH) )
+	    {
+		continue;             /* Try next Port address */
+	    }
+
+	    dev->base_addr = ioaddr;  /* Set I/O Port Address */
+
+	    if (SK_probe(dev, ioaddr) == 0)  
+	    {
+		return 0; /* Card found and initialized */
+	    }
+	}
+
+	dev->base_addr = base_addr;   /* Write back original base_addr */
+
+	return ENODEV;                /* Failed to find or init driver */
+
+} /* End of SK_init */
+
+
+/*-
+ * Function       : SK_probe
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/26
+ *
+ * Description    : This function is called by SK_init and 
+ *                  does the main part of initialization.
+ *                  
+ * Parameters     : I : struct device *dev - SK_G16 device structure
+ *                  I : short ioaddr       - I/O Port address where POS is.
+ * Return Value   : 0 = Initilization done             
+ * Errors         : ENODEV - No SK_G16 found
+ *                  -1     - Configuration problem
+ * Globals        : irq2dev_map - Which device uses which IRQ
+ *                : board       - pointer to SK_RAM
+ * Update History :
+ *     YY/MM/DD  uid  Description
+ *     94/06/30  pwe  SK_ADDR now checked and at the correct place
+-*/
+
+int SK_probe(struct device *dev, short ioaddr)
+{
+    int i,j;                /* Counters */
+    int sk_addr_flag = 0;   /* SK ADDR correct? 1 - no, 0 - yes */
+    unsigned int rom_addr;  /* used to store RAM address used for POS_ADDR */
+
+    struct priv *p;         /* SK_G16 private structure */
+
+    if (SK_ADDR & 0x3fff || SK_ADDR < 0xa0000)
+    {
+      
+       sk_addr_flag = 1;
+
+       /* 
+        * Now here we could use a routine which searches for a free
+        * place in the ram and set SK_ADDR if found. TODO. 
+        */
+    }
+
+    if (SK_BOOT_ROM)            /* Shall we keep Boot_ROM on ? */
+    {
+        PRINTK(("## %s: SK_BOOT_ROM is set.\n", SK_NAME));
+
+        rom_addr = SK_rom_addr();
+
+	if (rom_addr == 0)      /* No Boot_ROM found */
+	{
+            if (sk_addr_flag)   /* No or Invalid SK_ADDR is defined */ 
+            {
+                printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n",
+                       dev->name, SK_ADDR);
+                return -1;
+            }
+
+	    rom_addr = SK_ADDR; /* assign predefined address */
+
+	    PRINTK(("## %s: NO Bootrom found \n", SK_NAME));
+
+	    outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off */
+	    outb(POS_ADDR, SK_POS3);       /* Set RAM address */
+	    outb(SK_RAM_ON, SK_POS2);      /* enable RAM */
+	}
+	else if (rom_addr == SK_ADDR) 
+	{
+            printk("%s: RAM + ROM are set to the same address %#08x\n"
+                   "   Check configuration. Now switching off Boot_ROM\n",
+                   SK_NAME, rom_addr);
+
+	    outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off*/
+	    outb(POS_ADDR, SK_POS3);       /* Set RAM address */
+	    outb(SK_RAM_ON, SK_POS2);      /* enable RAM */
+	}
+	else
+	{
+            PRINTK(("## %s: Found ROM at %#08x\n", SK_NAME, rom_addr));
+	    PRINTK(("## %s: Keeping Boot_ROM on\n", SK_NAME));
+
+            if (sk_addr_flag)       /* No or Invalid SK_ADDR is defined */ 
+            {
+                printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n",
+                       dev->name, SK_ADDR);
+                return -1;
+            }
+
+	    rom_addr = SK_ADDR;
+
+	    outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off */ 
+	    outb(POS_ADDR, SK_POS3);       /* Set RAM address */
+	    outb(SK_ROM_RAM_ON, SK_POS2);  /* RAM on, BOOT_ROM on */
+	}
+    }
+    else /* Don't keep Boot_ROM */
+    {
+        PRINTK(("## %s: SK_BOOT_ROM is not set.\n", SK_NAME));
+
+        if (sk_addr_flag)           /* No or Invalid SK_ADDR is defined */ 
+        {
+            printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n",
+                   dev->name, SK_ADDR);
+            return -1;
+        }
+
+	rom_addr = SK_rom_addr();          /* Try to find a Boot_ROM */
+
+	/* IF we find a Boot_ROM disable it */
+
+	outb(SK_ROM_RAM_OFF, SK_POS2);     /* Boot_ROM + RAM off */  
+
+        /* We found a Boot_ROM and its gone. Set RAM address on
+         * Boot_ROM address. 
+         */ 
+
+	if (rom_addr) 
+	{
+            printk("%s: We found Boot_ROM at %#08x. Now setting RAM on"
+                   "that address\n", SK_NAME, rom_addr);
+
+	    outb(POS_ADDR, SK_POS3);       /* Set RAM on Boot_ROM address */
+	}
+	else /* We did not find a Boot_ROM, use predefined SK_ADDR for ram */
+	{
+            if (sk_addr_flag)       /* No or Invalid SK_ADDR is defined */ 
+            {
+                printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n",
+                       dev->name, SK_ADDR);
+                return -1;
+            }
+
+	    rom_addr = SK_ADDR;
+
+	    outb(POS_ADDR, SK_POS3);       /* Set RAM address */ 
+	}
+	outb(SK_RAM_ON, SK_POS2);          /* enable RAM */
+    }
+
+#ifdef SK_DEBUG
+    SK_print_pos(dev, "POS registers after ROM, RAM config");
+#endif
+
+    board = (SK_RAM *) rom_addr; 
+
+    /* Read in station address */
+    for (i = 0, j = 0; i < ETH_ALEN; i++, j+=2)
+    {
+	dev->dev_addr[i] = board->rom[j];          
+    }
+
+    /* Check for manufactorer code */
+    if (!(dev->dev_addr[0] == SK_MAC0 &&
+	  dev->dev_addr[1] == SK_MAC1 &&
+	  dev->dev_addr[2] == SK_MAC2) )
+    {
+        PRINTK(("## %s: We did not find SK_G16 at RAM location.\n",
+                SK_NAME)); 
+	return ENODEV;                     /* NO SK_G16 found */
+    }
+
+    printk("%s: %s found at %#3x, HW addr: %#04x:%02x:%02x:%02x:%02x:%02x\n",
+	    dev->name,
+	    "Schneider & Koch Netcard",
+	    (unsigned int) dev->base_addr,
+	    dev->dev_addr[0],
+	    dev->dev_addr[1],
+	    dev->dev_addr[2],
+	    dev->dev_addr[3],
+	    dev->dev_addr[4],
+	    dev->dev_addr[5]);
+
+    /* Grap the I/O Port region */
+    snarf_region(ioaddr, ETHERCARD_TOTAL_SIZE);
+
+    /* Initialize device structure */
+
+    /* Allocate memory for private structure */
+    p = dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL);
+    memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */
+
+    /* Assign our Device Driver functions */
+
+    dev->open                   = &SK_open;
+    dev->stop                   = &SK_close;
+    dev->hard_start_xmit        = &SK_send_packet;
+    dev->get_stats              = &SK_get_stats;
+
+#ifdef HAVE_MULTICAST
+    dev->set_multicast_list     = &set_multicast_list;
+#endif
+
+
+    /* Set the generic fields of the device structure */
+
+    ether_setup(dev);
+
+    /* Initialize private structure */
+
+    p->ram = (struct SK_ram *) rom_addr; /* Set dual ported RAM addr */
+    p->tmdhead = &(p->ram)->tmde[0];     /* Set TMD head */
+    p->rmdhead = &(p->ram)->rmde[0];     /* Set RMD head */
+
+    /* Initialize buffer pointers */
+
+    for (i = 0; i < TMDNUM; i++)
+    {
+	p->tmdbufs[i] = &(p->ram)->tmdbuf[i];
+    }
+
+    for (i = 0; i < RMDNUM; i++)
+    {
+	p->rmdbufs[i] = &(p->ram)->rmdbuf[i]; 
+    }
+
+#ifdef SK_DEBUG
+    SK_print_pos(dev, "End of SK_probe");
+    SK_print_ram(dev);
+#endif 
+
+    return 0;                            /* Initialization done */
+
+} /* End of SK_probe() */
+
+
+/*- 
+ * Function       : SK_open
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/26
+ *
+ * Description    : This function is called sometimes after booting 
+ *                  when ifconfig programm is run.
+ *
+ *                  This function requests an IRQ, sets the correct
+ *                  IRQ in the card. Then calls SK_lance_init() to 
+ *                  init and start the LANCE chip. Then if everthing is 
+ *                  ok returns with 0 (OK), which means SK_G16 is now
+ *                  opened and operational.
+ *
+ *                  (Called by dev_open() /net/inet/dev.c)
+ *
+ * Parameters     : I : struct device *dev - SK_G16 device structure
+ * Return Value   : 0 - Device opened
+ * Errors         : -EAGAIN - Open failed
+ * Globals        : irq2dev_map - which device uses which irq
+ * Side Effects   : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+static int SK_open(struct device *dev)
+{
+    int i = 0;
+    int irqval = 0;
+    int ioaddr = dev->base_addr;
+
+    int irqtab[] = SK_IRQS; 
+
+    struct priv *p = (struct priv *)dev->priv;
+
+    PRINTK(("## %s: At beginning of SK_open(). CSR0: %#06x\n", 
+           SK_NAME, SK_read_reg(CSR0)));
+
+    if (dev->irq == 0) /* Autoirq */
+    {
+	i = 0;
+
+	/* 
+         * Check if one IRQ out of SK_IRQS is free and install 
+	 * interrupt handler.
+	 * Most done by request_irq(). 
+	 * irqval: 0       - interrupt handler installed for IRQ irqtab[i]
+	 *         -EBUSY  - interrupt busy 
+         *         -EINVAL - irq > 15 or handler = NULL
+	 */
+
+	do
+	{
+	  irqval = request_irq(irqtab[i], &SK_interrupt);
+	  i++;
+	} while (irqval && irqtab[i]);
+
+	if (irqval) /* We tried every possible IRQ but no success */
+	{
+	    printk("%s: unable to get an IRQ\n", dev->name);
+	    return -EAGAIN;
+	}
+
+	dev->irq = irqtab[--i]; 
+	
+	outb(i<<2, SK_POS4);           /* Set Card on probed IRQ */
+
+    }
+    else if (dev->irq == 2) /* IRQ2 is always IRQ9 */
+    {
+	if (request_irq(9, &SK_interrupt))
+	{
+	    printk("%s: unable to get IRQ 9\n", dev->name);
+	    return -EAGAIN;
+	} 
+	dev->irq = 9;
+	
+        /* 
+         * Now we set card on IRQ2.
+         * This can be confusing, but remember that IRQ2 on the network
+         * card is in reality IRQ9
+         */
+	outb(0x08, SK_POS4);           /* set card to IRQ2 */
+
+    }
+    else  /* Check IRQ as defined in Space.c */
+    {
+	int i = 0;
+
+	/* check if IRQ free and valid. Then install Interrupt handler */
+
+	if (request_irq(dev->irq, &SK_interrupt))
+	{
+	    printk("%s: unable to get selected IRQ\n", dev->name);
+	    return -EAGAIN;
+	}
+
+	switch(dev->irq)
+	{
+	    case 3: i = 0;
+		    break;
+	    case 5: i = 1;
+		    break;
+	    case 2: i = 2;
+		    break;
+	    case 11:i = 3;
+		    break;
+	    default: 
+		printk("%s: Preselected IRQ %d is invalid for %s boards",
+		       dev->name,
+		       dev->irq,
+                       SK_NAME);
+		return -EAGAIN;
+	}      
+  
+	outb(i<<2, SK_POS4);           /* Set IRQ on card */
+    }
+
+    irq2dev_map[dev->irq] = dev;       /* Set IRQ as used by us */
+    
+    printk("%s: Schneider & Koch G16 at %#3x, IRQ %d, shared mem at %#08x\n",
+	    dev->name, (unsigned int)dev->base_addr, 
+	    (int) dev->irq, (unsigned int) p->ram);
+
+    if (!(i = SK_lance_init(dev, 0)))  /* LANCE init OK? */
+    {
+
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+#ifdef SK_DEBUG
+
+        /* 
+         * This debug block tries to stop LANCE,
+         * reinit LANCE with transmitter and receiver disabled,
+         * then stop again and reinit with NORMAL_MODE
+         */
+
+        printk("## %s: After lance init. CSR0: %#06x\n", 
+               SK_NAME, SK_read_reg(CSR0));
+        SK_write_reg(CSR0, CSR0_STOP);
+        printk("## %s: LANCE stopped. CSR0: %#06x\n", 
+               SK_NAME, SK_read_reg(CSR0));
+        SK_lance_init(dev, MODE_DTX | MODE_DRX);
+        printk("## %s: Reinit with DTX + DRX off. CSR0: %#06x\n", 
+               SK_NAME, SK_read_reg(CSR0));
+        SK_write_reg(CSR0, CSR0_STOP);
+        printk("## %s: LANCE stopped. CSR0: %#06x\n", 
+               SK_NAME, SK_read_reg(CSR0));
+        SK_lance_init(dev, MODE_NORMAL);
+        printk("## %s: LANCE back to normal mode. CSR0: %#06x\n", 
+               SK_NAME, SK_read_reg(CSR0));
+        SK_print_pos(dev, "POS regs before returning OK");
+
+#endif /* SK_DEBUG */
+       
+	return 0;              /* SK_open() is successful */
+    }
+    else /* LANCE init failed */
+    {
+
+	PRINTK(("## %s: LANCE init failed: CSR0: %#06x\n", 
+               SK_NAME, SK_read_reg(CSR0)));
+
+	dev->start = 0;        /* Device not ready */
+	return -EAGAIN;
+    }
+
+} /* End of SK_open() */
+
+
+/*-
+ * Function       : SK_lance_init
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/26
+ *
+ * Description    : Reset LANCE chip, fill RMD, TMD structures with
+ *                  start values and Start LANCE.
+ *
+ * Parameters     : I : struct device *dev - SK_G16 device structure
+ *                  I : int mode - put LANCE into "mode" see data-sheet for
+ *                                 more info.
+ * Return Value   : 0  - Init done
+ * Errors         : -1 - Init failed
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+static int SK_lance_init(struct device *dev, unsigned short mode)
+{
+    int i;
+    struct priv *p = (struct priv *) dev->priv; 
+    struct tmd  *tmdp;
+    struct rmd  *rmdp;
+
+    PRINTK(("## %s: At beginning of LANCE init. CSR0: %#06x\n", 
+           SK_NAME, SK_read_reg(CSR0)));
+
+    /* Reset LANCE */
+    SK_reset_board();
+
+    /* Initialize TMD's with start values */
+    p->tmdnum = 0;                   /* First descriptor for transmitting */ 
+    p->tmdlast = 0;                  /* First descriptor for reading stats */
+
+    for (i = 0; i < TMDNUM; i++)     /* Init all TMD's */
+    {
+	tmdp = p->tmdhead + i; 
+   
+	tmdp->u.buffer = (unsigned long) p->tmdbufs[i]; /* assign buffer */
+	
+	/* Mark TMD as start and end of packet */
+	tmdp->u.s.status = TX_STP | TX_ENP;
+    }
+
+
+    /* Initialize RMD's with start values */
+
+    p->rmdnum = 0;                   /* First RMD which will be used */
+ 
+    for (i = 0; i < RMDNUM; i++)     /* Init all RMD's */
+    {
+	rmdp = p->rmdhead + i;
+
+	
+	rmdp->u.buffer = (unsigned long) p->rmdbufs[i]; /* assign buffer */
+	
+	/* 
+         * LANCE must be owner at beginning so that he can fill in 
+	 * receiving packets, set status and release RMD 
+	 */
+
+	rmdp->u.s.status = RX_OWN;  
+
+	rmdp->blen = -PKT_BUF_SZ;    /* Buffer Size in a two's comliment */
+
+	rmdp->mlen = 0;              /* init message length */       
+	
+    }
+
+    /* Fill LANCE Initialize Block */
+
+    (p->ram)->ib.mode = mode;        /* Set operation mode */
+
+    for (i = 0; i < ETH_ALEN; i++)   /* Set physical address */
+    {
+	(p->ram)->ib.paddr[i] = dev->dev_addr[i]; 
+    }
+
+    for (i = 0; i < 8; i++)          /* Set multicast, logical adress */
+    {
+	(p->ram)->ib.laddr[i] = 0;   /* We do not use logical addressing */
+    } 
+
+    /* Set ring descriptor pointers and set number of descriptors */
+
+    (p->ram)->ib.rdrp = (int)  p->rmdhead | RMDNUMMASK;
+    (p->ram)->ib.tdrp = (int)  p->tmdhead | TMDNUMMASK;
+
+    /* Prepare LANCE Controll and Status Registers */
+
+    cli();
+
+    SK_write_reg(CSR3, CSR3_ACON);   /* Ale Control !!!THIS MUST BE SET!!!! */
+ 
+    /* 
+     * LANCE addresses the RAM from 0x0000 to 0x3fbf and has no access to
+     * PC Memory locations.
+     *
+     * In structure SK_ram is defined that the first thing in ram
+     * is the initalization block. So his address is for LANCE always
+     * 0x0000
+     *
+     * CSR1 contains low order bits 15:0 of initialization block address
+     * CSR2 is built of: 
+     *    7:0  High order bits 23:16 of initialization block address
+     *   15:8  reserved, must be 0
+     */
+    
+    /* Set initialization block address (must be on word boundary) */
+    SK_write_reg(CSR1, 0);          /* Set low order bits 15:0 */
+    SK_write_reg(CSR2, 0);          /* Set high order bits 23:16 */ 
+    
+
+    PRINTK(("## %s: After setting CSR1-3. CSR0: %#06x\n", 
+           SK_NAME, SK_read_reg(CSR0)));
+
+    /* Initialize LANCE */
+
+    /* 
+     * INIT = Initialize, when set, cuases the LANCE to begin the
+     * initialization procedure and access the Init Block.
+     */
+
+    SK_write_reg(CSR0, CSR0_INIT); 
+
+    sti();
+
+    /* Wait until LANCE finished initialization */
+    
+    SK_set_RAP(CSR0);              /* Register Address Pointer to CSR0 */
+
+    for (i = 0; (i < 100) && !(SK_rread_reg() & CSR0_IDON); i++) 
+	; /* Wait until init done or go ahead if problems (i>=100) */
+
+    if (i >= 100) /* Something is wrong ! */
+    {
+	printk("%s: can't init am7990, status: %04x "
+	       "init_block: %#08x\n", 
+		dev->name, (int) SK_read_reg(CSR0), 
+		(unsigned int) &(p->ram)->ib);
+
+#ifdef SK_DEBUG
+	SK_print_pos(dev, "LANCE INIT failed");
+	SK_print_dev(dev,"Device Structure:");
+#endif
+
+	return -1;                 /* LANCE init failed */
+    }
+
+    PRINTK(("## %s: init done after %d ticks\n", SK_NAME, i));
+
+    /* Clear Initialize done, enable Interrupts, start LANCE */
+
+    SK_write_reg(CSR0, CSR0_IDON | CSR0_INEA | CSR0_STRT);
+
+    PRINTK(("## %s: LANCE started. CSR0: %#06x\n", SK_NAME, 
+            SK_read_reg(CSR0)));
+
+    return 0;                      /* LANCE is up and running */
+
+} /* End of SK_lance_init() */
+
+
+
+/*-
+ * Function       : SK_send_packet
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/27
+ *
+ * Description    : Writes an socket buffer into a transmit descriptor
+ *                  and starts transmission.
+ *
+ * Parameters     : I : struct sk_buff *skb - packet to transfer
+ *                  I : struct device *dev  - SK_G16 device structure
+ * Return Value   : 0 - OK
+ *                  1 - Could not transmit (dev_queue_xmit will queue it)
+ *                      and try to sent it later
+ * Globals        : None
+ * Side Effects   : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+static int SK_send_packet(struct sk_buff *skb, struct device *dev)
+{
+    struct priv *p = (struct priv *) dev->priv;
+    struct tmd *tmdp;
+
+    if (dev->tbusy)
+    {
+	/* if Transmitter more than 150ms busy -> time_out */
+
+	int tickssofar = jiffies - dev->trans_start;
+	if (tickssofar < 15)
+	{
+	    return 1;                    /* We have to try transmit later */
+	}
+
+	printk("%s: xmitter timed out, try to restart!\n", dev->name);
+
+	SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */
+
+	dev->tbusy = 0;                  /* Clear Transmitter flag */
+
+	dev->trans_start = jiffies;      /* Mark Start of transmission */
+
+    }
+
+    /* 
+     * If some upper Layer thinks we missed a transmit done interrupt
+     * we are passed NULL.
+     * (dev_queue_xmit net/inet/dev.c 
+     */
+
+    if (skb == NULL)
+    {
+        /* 
+         * Dequeue packets from transmit queue and send them.
+         */
+	dev_tint(dev); 
+                    
+	return 0;
+    }
+    
+    PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n", 
+	    SK_NAME, SK_read_reg(CSR0)));
+
+
+    /* 
+     * Block a timer-based transmit from overlapping. 
+     * This means check if we are already in. 
+     */
+
+    if (set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */ 
+    {
+	printk("%s: Transmitter access conflict.\n", dev->name);
+    }
+    else
+    {
+	/* Evaluate Packet length */
+	short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; 
+       
+	tmdp = p->tmdhead + p->tmdnum; /* Which descriptor for transmitting */
+
+	/* Fill in Transmit Message Descriptor */
+
+	/* Copy data into dual ported ram */
+
+	memcpy((char *) (tmdp->u.buffer & 0x00ffffff), (char *)skb->data,
+	       skb->len);
+
+	tmdp->blen = -len;            /* set length to transmit */
+
+	/* 
+	 * Packet start and end is always set because we use the maximum
+	 * packet length as buffer length.
+	 * Relinquish ownership to LANCE
+	 */
+
+	tmdp->u.s.status = TX_OWN | TX_STP | TX_ENP;
+	
+	/* Start Demand Transmission */
+	SK_write_reg(CSR0, CSR0_TDMD | CSR0_INEA);
+
+	dev->trans_start = jiffies;   /* Mark start of transmission */
+
+	/* Set pointer to next transmit buffer */
+	p->tmdnum++; 
+	p->tmdnum &= TMDNUM-1; 
+
+	/* Do we own the next transmit buffer ? */
+	if (! ((p->tmdhead + p->tmdnum)->u.s.status & TX_OWN) )
+	{
+	   /* 
+	    * We own next buffer and are ready to transmit, so
+	    * clear busy flag
+	    */
+	   dev->tbusy = 0;
+	}
+    }
+    dev_kfree_skb(skb, FREE_WRITE);
+    return 0;  
+} /* End of SK_send_packet */
+
+
+/*-
+ * Function       : SK_interrupt
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/27
+ *
+ * Description    : SK_G16 interrupt handler which checks for LANCE
+ *                  Errors, handles transmit and receive interrupts
+ *
+ * Parameters     : I : int reg_ptr -
+ * Return Value   : None
+ * Errors         : None
+ * Globals        : None
+ * Side Effects   : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+static void SK_interrupt(int reg_ptr)
+{
+    int irq = - (((struct pt_regs *)reg_ptr)->orig_eax+2);
+    int csr0;
+    struct device *dev = (struct device *) irq2dev_map[irq];
+    struct priv *p = (struct priv *) dev->priv;
+
+
+    PRINTK2(("## %s: SK_interrupt(). status: %#06x\n", 
+            SK_NAME, SK_read_reg(CSR0)));
+
+    if (dev == NULL)
+    {
+	printk("SK_interrupt(): IRQ %d for unknown device.\n", irq);
+    }
+    
+
+    if (dev->interrupt)
+    {
+	printk("%s: Re-entering the interrupt handler.\n", dev->name);
+    }
+
+    csr0 = SK_read_reg(CSR0);      /* store register for checking */
+
+    dev->interrupt = 1;            /* We are handling an interrupt */
+
+    /* 
+     * Acknowledge all of the current interrupt sources, disable      
+     * Interrupts (INEA = 0) 
+     */
+
+    SK_write_reg(CSR0, csr0 & CSR0_CLRALL); 
+
+    if (csr0 & CSR0_ERR) /* LANCE Error */
+    {
+	printk("%s: error: %04x\n", dev->name, csr0);
+      
+        if (csr0 & CSR0_MISS)      /* No place to store packet ? */
+        { 
+            p->stats.rx_dropped++;
+        }
+    }
+
+    if (csr0 & CSR0_RINT)          /* Receive Interrupt (packet arrived) */ 
+    {
+	SK_rxintr(dev); 
+    }
+
+    if (csr0 & CSR0_TINT)          /* Transmit interrupt (packet sent) */
+    {
+	SK_txintr(dev);
+    }
+
+    SK_write_reg(CSR0, CSR0_INEA); /* Enable Interrupts */
+
+    dev->interrupt = 0;            /* We are out */
+} /* End of SK_interrupt() */ 
+
+
+/*-
+ * Function       : SK_txintr
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/27
+ *
+ * Description    : After sending a packet we check status, update
+ *                  statistics and relinquish ownership of transmit 
+ *                  descriptor ring.
+ *
+ * Parameters     : I : struct device *dev - SK_G16 device structure
+ * Return Value   : None
+ * Errors         : None
+ * Globals        : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+static void SK_txintr(struct device *dev)
+{
+    int tmdstat;
+    struct tmd *tmdp;
+    struct priv *p = (struct priv *) dev->priv;
+
+
+    PRINTK2(("## %s: SK_txintr() status: %#06x\n", 
+            SK_NAME, SK_read_reg(CSR0)));
+
+    tmdp = p->tmdhead + p->tmdlast;     /* Which buffer we sent at last ? */
+
+    /* Set next buffer */
+    p->tmdlast++;
+    p->tmdlast &= TMDNUM-1;
+
+    tmdstat = tmdp->u.s.status & 0xff00; /* filter out status bits 15:08 */
+
+    /* 
+     * We check status of transmitted packet.
+     * see LANCE data-sheet for error explanation
+     */
+    if (tmdstat & TX_ERR) /* Error occured */
+    {
+	printk("%s: TX error: %04x %04x\n", dev->name, (int) tmdstat,
+		(int) tmdp->status2);
+
+	if (tmdp->status2 & TX_TDR)    /* TDR problems? */
+	{
+	    printk("%s: tdr-problems \n", dev->name);
+	}
+
+	if (tmdp->status2 & TX_RTRY)   /* Failed in 16 attempts to transmit ? */
+            p->stats.tx_aborted_errors++;   
+        if (tmdp->status2 & TX_LCOL)   /* Late collision ? */
+            p->stats.tx_window_errors++; 
+	if (tmdp->status2 & TX_LCAR)   /* Loss of Carrier ? */  
+            p->stats.tx_carrier_errors++;
+        if (tmdp->status2 & TX_UFLO)   /* Underflow error ? */
+        {
+            p->stats.tx_fifo_errors++;
+
+            /* 
+             * If UFLO error occurs it will turn tranmitter of.
+             * So we must reinit LANCE
+             */
+
+            SK_lance_init(dev, MODE_NORMAL);
+        }
+	
+	p->stats.tx_errors++;
+
+	tmdp->status2 = 0;             /* Clear error flags */
+    }
+    else if (tmdstat & TX_MORE)        /* Collisions occured ? */
+    {
+        /* 
+         * Here I have a problem.
+         * I only know that there must be one or up to 15 collisions.
+         * Thats why TX_MORE is set, because after 16 attempts TX_RTRY
+         * will be set which means couldn't send packet aborted transfer.
+         *
+         * First I did not have this in but then I thought at minimum
+         * we see that something was not ok.
+         * If anyone knows something better than this to handle this
+         * please report it. (see Email addresses in the README file)
+         */ 
+
+        p->stats.collisions++; 
+    }
+    else   /* Packet sent without any problems */
+    {
+        p->stats.tx_packets++; 
+    }
+
+    /* 
+     * We mark transmitter not busy anymore, because now we have a free
+     * transmit descriptor which can be filled by SK_send_packet and
+     * afterwards sent by the LANCE
+     */
+
+    dev->tbusy = 0; 
+
+    /* 
+     * mark_bh(NET_BH);
+     * This will cause net_bh() to run after this interrupt handler.
+     *
+     * The function which do handle slow IRQ parts is do_bottom_half()
+     * which runs at normal kernel priority, that means all interrupt are
+     * enabled. (see kernel/irq.c)
+     *  
+     * net_bh does something like this:
+     *  - check if already in net_bh
+     *  - try to transmit something from the send queue
+     *  - if something is in the receive queue send it up to higher 
+     *    levels if it is a known protocol
+     *  - try to transmit something from the send queue
+     */
+
+    mark_bh(NET_BH); 
+
+} /* End of SK_txintr() */
+
+
+/*-
+ * Function       : SK_rxintr
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/27
+ *
+ * Description    : Buffer sent, check for errors, relinquish ownership
+ *                  of the receive message descriptor. 
+ *
+ * Parameters     : I : SK_G16 device structure
+ * Return Value   : None
+ * Globals        : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+static void SK_rxintr(struct device *dev)
+{
+
+    struct rmd *rmdp;
+    int rmdstat;
+    struct priv *p = (struct priv *) dev->priv;
+
+    PRINTK2(("## %s: SK_rxintr(). CSR0: %#06x\n", 
+            SK_NAME, SK_read_reg(CSR0)));
+
+    rmdp = p->rmdhead + p->rmdnum;
+
+    /* As long as we own the next entry, check status and send
+     * it up to higher layer 
+     */
+
+    while (!( (rmdstat = rmdp->u.s.status) & RX_OWN))
+    {
+	/* 
+         * Start and end of packet must be set, because we use 
+	 * the ethernet maximum packet length (1518) as buffer size.
+	 * 
+	 * Because our buffers are at maximum OFLO and BUFF errors are
+	 * not to be concerned (see Data sheet)
+	 */
+
+	if (rmdstat & (RX_STP | RX_ENP) != (RX_STP | RX_ENP))
+	{
+	    /* Start of a frame > 1518 Bytes ? */
+
+	    if (rmdstat & RX_STP) 
+	    {
+		p->stats.rx_errors++;        /* bad packet received */
+		p->stats.rx_length_errors++; /* packet to long */
+
+		printk("%s: packet too long\n", dev->name);
+	    }
+	    
+	    /* 
+             * All other packets will be ignored until a new frame with
+	     * start (RX_STP) set follows.
+	     * 
+	     * What we do is just give descriptor free for new incoming
+	     * packets. 
+	     */
+
+	    rmdp->u.s.status = RX_OWN;      /* Relinquish ownership to LANCE */ 
+
+	}
+	else if (rmdstat & RX_ERR)          /* Receive Error ? */
+	{
+	    printk("%s: RX error: %04x\n", dev->name, (int) rmdstat);
+	    
+	    p->stats.rx_errors++;
+
+	    if (rmdstat & RX_FRAM) p->stats.rx_frame_errors++;
+	    if (rmdstat & RX_CRC)  p->stats.rx_crc_errors++;
+
+	    rmdp->u.s.status = RX_OWN;      /* Relinquish ownership to LANCE */
+
+	}
+	else /* We have a packet which can be queued for the upper layers */
+	{
+
+	    int len = (rmdp->mlen & 0x0fff);  /* extract message length from receive buffer */
+	    struct sk_buff *skb;
+
+	    skb = alloc_skb(len, GFP_ATOMIC); /* allocate socket buffer */ 
+
+	    if (skb == NULL)                /* Could not get mem ? */
+	    {
+    
+		/* 
+                 * Couldn't allocate sk_buffer so we give descriptor back
+		 * to Lance, update statistics and go ahead.
+		 */
+
+		rmdp->u.s.status = RX_OWN;  /* Reliquish ownershipt to LANCE */
+		printk("%s: Couldn't allocate sk_buff, deferring packet.\n",
+		       dev->name);
+		p->stats.rx_dropped++;
+
+		break;                      /* Jump out */
+	    }
+	    
+	    /* Prepare sk_buff to queue for upper layers */
+
+            skb->len = len;
+	    skb->dev = dev;
+	    
+	    /* 
+             * Copy data out of our receive descriptor into sk_buff.
+	     *
+	     * (rmdp->u.buffer & 0x00ffffff) -> get address of buffer and 
+	     * ignore status fields) 
+	     */
+
+	    memcpy(skb->data, (unsigned char *) (rmdp->u.buffer & 0x00ffffff),
+		   len);
+
+
+	    /* 
+             * Notify the upper protocol layers that there is another packet
+	     * to handle
+	     *
+	     * netif_rx() always succeeds. see /net/inet/dev.c for more.
+	     */
+
+	    netif_rx(skb);                 /* queue packet and mark it for processing */
+	   
+	    /* 
+             * Packet is queued and marked for processing so we
+	     * free our descriptor and update statistics 
+	     */
+
+	    rmdp->u.s.status = RX_OWN;
+	    p->stats.rx_packets++;
+
+
+	    p->rmdnum++;
+	    p->rmdnum %= RMDNUM;
+
+	    rmdp = p->rmdhead + p->rmdnum;
+	}
+    }
+} /* End of SK_rxintr() */
+
+
+/*-
+ * Function       : SK_close
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/26
+ *
+ * Description    : close gets called from dev_close() and should
+ *                  deinstall the card (free_irq, mem etc).
+ *
+ * Parameters     : I : struct device *dev - our device structure
+ * Return Value   : 0 - closed device driver
+ * Errors         : None
+ * Globals        : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+/* I have tried to set BOOT_ROM on and RAM off but then, after a 'ifconfig
+ * down' the system stops. So I don't shut set card to init state.
+ */
+
+static int SK_close(struct device *dev)
+{
+
+    PRINTK(("## %s: SK_close(). CSR0: %#06x\n", 
+           SK_NAME, SK_read_reg(CSR0)));
+
+    dev->tbusy = 1;                /* Transmitter busy */
+    dev->start = 0;                /* Card down */
+
+    printk("%s: Shuting %s down CSR0 %#06x\n", dev->name, SK_NAME, 
+           (int) SK_read_reg(CSR0));
+
+    SK_write_reg(CSR0, CSR0_STOP); /* STOP the LANCE */
+
+    free_irq(dev->irq);            /* Free IRQ */
+    irq2dev_map[dev->irq] = 0;     /* Mark IRQ as unused */
+
+    return 0; /* always succed */
+    
+} /* End of SK_close() */
+
+
+/*-
+ * Function       : SK_get_stats
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/26
+ *
+ * Description    : Return current status structure to upper layers.
+ *                  It is called by sprintf_stats (dev.c).
+ *
+ * Parameters     : I : struct device *dev   - our device structure
+ * Return Value   : struct enet_statistics * - our current statistics
+ * Errors         : None
+ * Side Effects   : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+static struct enet_statistics *SK_get_stats(struct device *dev)
+{
+
+    struct priv *p = (struct priv *) dev->priv;
+
+    PRINTK(("## %s: SK_get_stats(). CSR0: %#06x\n", 
+           SK_NAME, SK_read_reg(CSR0)));
+
+    return &p->stats;             /* Return Device status */
+
+} /* End of SK_get_stats() */
+
+#ifdef HAVE_MULTICAST
+
+/*-
+ * Function       : set_multicast_list
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/26
+ *
+ * Description    : This function gets called when a programm performs
+ *                  a SIOCSIFFLAGS call. Ifconfig does this if you call
+ *                  'ifconfig [-]allmultie' which enables or disables the
+ *                  Promiscous mode.
+ *                  Promiscous mode is when the Network card accepts all
+ *                  packets, not only the packets which match our MAC 
+ *                  Address. It is useful for writing a network monitor,
+ *                  but it is also a security problem. You have to remeber
+ *                  that all information on the net is not encrypted.
+ *
+ * Parameters     : I : struct device *dev - SK_G16 device Structure
+ *                  I : int num_addrs      - explanation further down
+ *                  I : void *addrs        - 
+ * Return Value   : None
+ * Errors         : None
+ * Globals        : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+
+/* Set or clear the multicast filter for SK_G16.
+ *
+ * num_addrs == -1      Promiscous mode, receive all packets
+ * num_addrs == 0       Normal mode, clear multicast list
+ * num_addrs > 0        Multicast mode, receive normal and MC packets
+ */
+
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+
+    if (num_addrs == -1)
+    {
+	/* Reinitialize LANCE with MODE_PROM set */
+	SK_lance_init(dev, MODE_PROM);
+    }
+    else if (num_addrs == 0)
+    {
+	/* Reinitialize LANCE without MODE_PROM */
+	SK_lance_init(dev, MODE_NORMAL);
+    }
+    else
+    {
+	/* Multicast with logical address filter on */
+	
+	/* Not implemented yet. */
+    }
+} /* End of set_multicast_list() */
+
+#endif     
+
+
+
+/*-
+ * Function       : SK_rom_addr
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/06/01
+ *
+ * Description    : Try to find a Boot_ROM at all possible locations
+ *
+ * Parameters     : None
+ * Return Value   : Address where Boot_ROM is
+ * Errors         : 0 - Did not find Boot_ROM
+ * Globals        : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+unsigned int SK_rom_addr(void)
+{
+    int i,j;
+    int rom_found = 0;
+    unsigned int rom_location[] = SK_BOOT_ROM_LOCATIONS;
+    unsigned char rom_id[] = SK_BOOT_ROM_ID;
+    unsigned char *test_byte;
+
+    /* Autodetect Boot_ROM */
+    PRINTK(("## %s: Autodetection of Boot_ROM\n", SK_NAME));
+
+    for (i = 0; (rom_location[i] != 0) && (rom_found == 0); i++)
+    {
+	
+	PRINTK(("##   Trying ROM location %#08x", rom_location[i]));
+	
+	rom_found = 1; 
+	for (j = 0; j < 6; j++)
+	{
+	    test_byte = (unsigned char *) (rom_location[i]+j);
+	    PRINTK((" %02x ", *test_byte));
+
+	    if(!(*test_byte == rom_id[j]))
+	    {
+		rom_found = 0;
+	    } 
+	}
+	PRINTK(("\n"));
+    }
+
+    if (rom_found == 1)
+    {
+	PRINTK(("## %s: Boot_ROM found at %#08x\n", 
+               SK_NAME, rom_location[(i-1)]));
+
+	return (rom_location[--i]);
+    }
+    else
+    {
+	PRINTK(("%s: No Boot_ROM found\n", SK_NAME));
+	return 0;
+    }
+} /* End of SK_rom_addr() */
+
+
+
+/* LANCE access functions 
+ *
+ * ! CSR1-3 can only be accessed when in CSR0 the STOP bit is set !
+ */
+
+
+/*-
+ * Function       : SK_reset_board
+ *
+ * Author         : Patrick J.D. Weichmann
+ *
+ * Date Created   : 94/05/25
+ *
+ * Description    : This function resets SK_G16 and all components, but
+ *                  POS registers are not changed
+ *
+ * Parameters     : None
+ * Return Value   : None
+ * Errors         : None
+ * Globals        : SK_RAM *board - SK_RAM structure pointer
+ *
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+void SK_reset_board(void)
+{
+    int i;
+
+    SK_PORT = 0x00;           /* Reset aktiv */
+    for (i = 0; i < 10 ; i++) /* Delay min 5ms */
+	;
+    SK_PORT = SK_RESET;       /* Set back to normal operation */
+
+} /* End of SK_reset_board() */
+
+
+/*-
+ * Function       : SK_set_RAP
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/25
+ *
+ * Description    : Set LANCE Register Address Port to register
+ *                  for later data trasfer.
+ *
+ * Parameters     : I : reg_number - which CSR to read/write from/to
+ * Return Value   : None
+ * Errors         : None
+ * Globals        : SK_RAM *board - SK_RAM structure pointer
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+void SK_set_RAP(int reg_number)
+{
+    SK_IOREG = reg_number;
+    SK_PORT  = SK_RESET | SK_RAP | SK_WREG;
+    SK_IOCOM = SK_DOIO;
+
+    while (SK_PORT & SK_IORUN) 
+	;
+} /* End of SK_set_RAP() */
+
+
+/*-
+ * Function       : SK_read_reg
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/25
+ *
+ * Description    : Set RAP and read data from a LANCE CSR register
+ *
+ * Parameters     : I : reg_number - which CSR to read from
+ * Return Value   : Register contents
+ * Errors         : None
+ * Globals        : SK_RAM *board - SK_RAM structure pointer
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+int SK_read_reg(int reg_number)
+{
+    SK_set_RAP(reg_number);
+
+    SK_PORT  = SK_RESET | SK_RDATA | SK_RREG;
+    SK_IOCOM = SK_DOIO;
+
+    while (SK_PORT & SK_IORUN)
+	;
+    return (SK_IOREG);
+
+} /* End of SK_read_reg() */
+
+
+/*-
+ * Function       : SK_rread_reg
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/28
+ *
+ * Description    : Read data from preseted register.
+ *                  This function requires that you know which
+ *                  Register is actually set. Be aware that CSR1-3
+ *                  can only be accessed when in CSR0 STOP is set.
+ *
+ * Return Value   : Register contents
+ * Errors         : None
+ * Globals        : SK_RAM *board - SK_RAM structure pointer
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+int SK_rread_reg(void)
+{
+    SK_PORT  = SK_RESET | SK_RDATA | SK_RREG;
+
+    SK_IOCOM = SK_DOIO;
+
+    while (SK_PORT & SK_IORUN)
+	;
+    return (SK_IOREG);
+
+} /* End of SK_rread_reg() */
+
+
+/*-
+ * Function       : SK_write_reg
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/25
+ *
+ * Description    : This function sets the RAP then fills in the
+ *                  LANCE I/O Reg and starts Transfer to LANCE.
+ *                  It waits until transfer has ended which is max. 7 ms
+ *                  and then it returns.
+ *
+ * Parameters     : I : reg_number - which CSR to write to
+ *                  I : value      - what value to fill into register 
+ * Return Value   : None
+ * Errors         : None
+ * Globals        : SK_RAM *board - SK_RAM structure pointer
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+void SK_write_reg(int reg_number, int value)
+{
+    SK_set_RAP(reg_number);
+
+    SK_IOREG = value;
+    SK_PORT  = SK_RESET | SK_RDATA | SK_WREG;
+    SK_IOCOM = SK_DOIO;
+
+    while (SK_PORT & SK_IORUN)
+	;
+} /* End of SK_write_reg */
+
+
+
+/* 
+ * Debugging functions
+ * -------------------
+ */
+
+/*-
+ * Function       : SK_print_pos
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/25
+ *
+ * Description    : This function prints out the 4 POS (Programmable
+ *                  Option Select) Registers. Used mainly to debug operation.
+ *
+ * Parameters     : I : struct device *dev - SK_G16 device structure
+ *                  I : char * - Text which will be printed as title
+ * Return Value   : None
+ * Errors         : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+void SK_print_pos(struct device *dev, char *text)
+{
+    int ioaddr = dev->base_addr;
+
+    unsigned char pos0 = inb(SK_POS0),
+		  pos1 = inb(SK_POS1),
+		  pos2 = inb(SK_POS2),
+		  pos3 = inb(SK_POS3),
+		  pos4 = inb(SK_POS4);
+
+
+    printk("## %s: %s.\n"
+           "##   pos0=%#4x pos1=%#4x pos2=%#04x pos3=%#08x pos4=%#04x\n",
+           SK_NAME, text, pos0, pos1, pos2, (pos3<<14), pos4);
+
+} /* End of SK_print_pos() */
+
+
+
+/*-
+ * Function       : SK_print_dev
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/05/25
+ *
+ * Description    : This function simply prints out the important fields
+ *                  of the device structure.
+ *
+ * Parameters     : I : struct device *dev  - SK_G16 device structure
+ *                  I : char *text - Title for printing
+ * Return Value   : None
+ * Errors         : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+void SK_print_dev(struct device *dev, char *text)
+{
+    if (dev == NULL)
+    {
+	printk("## %s: Device Structure. %s\n", SK_NAME, text);
+	printk("## DEVICE == NULL\n");
+    }
+    else
+    {
+	printk("## %s: Device Structure. %s\n", SK_NAME, text);
+	printk("## Device Name: %s Base Address: %#06x IRQ: %d\n", 
+               dev->name, dev->base_addr, dev->irq);
+	       
+	printk("##   FLAGS: start: %d tbusy: %d int: %d\n", 
+               dev->start, dev->tbusy, dev->interrupt);
+
+	printk("## next device: %#08x init function: %#08x\n", 
+              (int) dev->next, (int) dev->init);
+    }
+
+} /* End of SK_print_dev() */
+
+
+
+/*-
+ * Function       : SK_print_ram
+ * Author         : Patrick J.D. Weichmann
+ * Date Created   : 94/06/02
+ *
+ * Description    : This function is used to check how are things set up
+ *                  in the 16KB RAM. Also the pointers to the receive and 
+ *                  transmit descriptor rings and rx und tx buffers locations.
+ *                  It contains a minor bug in printing, but has no effect to the values
+ *                  only newlines are not correct.
+ *
+ * Parameters     : I : struct device *dev - SK_G16 device structure
+ * Return Value   : None
+ * Errors         : None
+ * Globals        : None
+ * Update History :
+ *     YY/MM/DD  uid  Description
+-*/
+
+void SK_print_ram(struct device *dev)
+{
+
+    int i;    
+    struct priv *p = (struct priv *) dev->priv;
+
+    printk("## %s: RAM Details.\n"
+           "##   RAM at %#08x tmdhead: %#08x rmdhead: %#08x initblock: %#08x\n",
+           SK_NAME, 
+           (unsigned int) p->ram,
+           (unsigned int) p->tmdhead, 
+           (unsigned int) p->rmdhead, 
+           (unsigned int) &(p->ram)->ib);
+           
+    printk("##   ");
+
+    for(i = 0; i < TMDNUM; i++)
+    {
+           if (!(i % 3)) /* Every third line do a newline */
+           {
+               printk("\n##   ");
+           }
+        printk("tmdbufs%d: %#08x ", (i+1), (int) p->tmdbufs[i]);
+    }
+    printk("##   ");
+
+    for(i = 0; i < RMDNUM; i++)
+    {
+         if (!(i % 3)) /* Every third line do a newline */
+           {
+               printk("\n##   ");
+           }
+        printk("rmdbufs%d: %#08x ", (i+1), (int) p->rmdbufs[i]);
+    } 
+    printk("\n");
+
+} /* End of SK_print_ram() */
+
diff -u --recursive --new-file v1.1.24/linux/drivers/net/sk_g16.h linux/drivers/net/sk_g16.h
--- v1.1.24/linux/drivers/net/sk_g16.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sk_g16.h	Thu Jul  7 17:56:36 1994
@@ -0,0 +1,165 @@
+/*-
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License, incorporated herein by reference.
+ *
+ * Module         : sk_g16.h
+ * Version        : $Revision$  
+ *
+ * Author         : M.Hipp (mhipp@student.uni-tuebingen.de)
+ * changes by     : Patrick J.D. Weichmann
+ *
+ * Date Created   : 94/05/25
+ *
+ * Description    : In here are all necessary definitions of  
+ *                  the am7990 (LANCE) chip used for writing a
+ *                  network device driver which uses this chip 
+ *
+ * $Log$
+-*/
+
+#ifndef SK_G16_H
+
+#define SK_G16_H
+
+
+/*
+ * 	Control and Status Register 0 (CSR0) bit definitions
+ *
+ * (R=Readable) (W=Writeable) (S=Set on write) (C-Clear on write)
+ *
+ */
+
+#define CSR0_ERR	0x8000	/* Error summary (R) */
+#define CSR0_BABL	0x4000	/* Babble transmitter timeout error (RC) */
+#define CSR0_CERR	0x2000	/* Collision Error (RC) */
+#define CSR0_MISS	0x1000	/* Missed packet (RC) */
+#define CSR0_MERR	0x0800	/* Memory Error  (RC) */ 
+#define CSR0_RINT	0x0400	/* Reciever Interrupt (RC) */
+#define CSR0_TINT       0x0200	/* Transmit Interrupt (RC) */ 
+#define CSR0_IDON	0x0100	/* Initialization Done (RC) */
+#define CSR0_INTR	0x0080	/* Interrupt Flag (R) */
+#define CSR0_INEA	0x0040	/* Interrupt Enable (RW) */
+#define CSR0_RXON	0x0020	/* Receiver on (R) */
+#define CSR0_TXON	0x0010  /* Transmitter on (R) */
+#define CSR0_TDMD	0x0008	/* Transmit Demand (RS) */
+#define CSR0_STOP	0x0004 	/* Stop (RS) */
+#define CSR0_STRT	0x0002	/* Start (RS) */
+#define CSR0_INIT	0x0001	/* Initialize (RS) */
+
+#define CSR0_CLRALL     0x7f00  /* mask for all clearable bits */
+
+/*
+ *    Control and Status Register 3 (CSR3) bit definitions
+ *
+ */
+
+#define CSR3_BSWAP	0x0004	/* Byte Swap (RW) */
+#define CSR3_ACON	0x0002  /* ALE Control (RW) */
+#define CSR3_BCON	0x0001	/* Byte Control (RW) */
+
+/*
+ *	Initialization Block Mode operation Bit Definitions.
+ */
+
+#define MODE_PROM	0x8000	/* Promiscuous Mode */
+#define MODE_INTL	0x0040  /* Internal Loopback */
+#define MODE_DRTY	0x0020  /* Disable Retry */ 
+#define MODE_COLL	0x0010	/* Force Collision */
+#define MODE_DTCR	0x0008	/* Disable Transmit CRC) */
+#define MODE_LOOP	0x0004	/* Loopback */
+#define MODE_DTX	0x0002	/* Disable the Transmitter */ 
+#define MODE_DRX	0x0001  /* Disable the Reciever */
+
+#define MODE_NORMAL 	0x0000  /* Normal operation mode */
+
+/*
+ * 	Receive message descriptor status bit definitions.
+ */
+
+#define RX_OWN		0x80	/* Owner bit 0 = host, 1 = lance */
+#define RX_ERR		0x40	/* Error Summary */
+#define RX_FRAM		0x20	/* Framing Error */
+#define RX_OFLO		0x10	/* Overflow Error */
+#define RX_CRC		0x08	/* CRC Error */ 
+#define RX_BUFF		0x04	/* Buffer Error */
+#define RX_STP		0x02	/* Start of Packet */
+#define RX_ENP		0x01	/* End of Packet */
+
+
+/*
+ *	Transmit message descriptor status bit definitions.
+ */
+
+#define TX_OWN		0x80	/* Owner bit 0 = host, 1 = lance */
+#define TX_ERR		0x40    /* Error Summary */
+#define TX_MORE		0x10	/* More the 1 retry needed to Xmit */
+#define TX_ONE		0x08	/* One retry needed to Xmit */
+#define TX_DEF		0x04	/* Deferred */
+#define TX_STP 		0x02	/* Start of Packet */
+#define TX_ENP		0x01	/* End of Packet */
+
+/*
+ *      Transmit status (2) (valid if TX_ERR == 1)
+ */
+
+#define TX_BUFF 	0x8000  /* Buffering error (no ENP) */
+#define TX_UFLO 	0x4000  /* Underflow (late memory) */
+#define TX_LCOL 	0x1000  /* Late collision */
+#define TX_LCAR 	0x0400  /* Loss of Carrier */
+#define TX_RTRY 	0x0200  /* Failed after 16 retransmissions  */
+#define TX_TDR          0x003f  /* Time-domain-reflectometer-value */
+
+
+/* 
+ * Structures used for Communication with the LANCE 
+ */
+
+/* LANCE Initialize Block */
+
+struct init_block 
+{
+  unsigned short mode;     /* Mode Register */
+  unsigned char  paddr[6]; /* Physical Address (MAC) */
+  unsigned char  laddr[8]; /* Logical Filter Address (not used) */
+  unsigned int   rdrp;     /* Receive Descriptor Ring pointer */
+  unsigned int   tdrp;     /* Transmit Descriptor Ring pointer */
+};
+
+
+/* Receive Message Descriptor Entry */
+
+struct rmd 
+{ 
+  union
+  {
+    unsigned long buffer;     /* Address of buffer */
+    struct 
+    {
+      unsigned char unused[3]; 
+      unsigned volatile char status;   /* Status Bits */
+    } s;
+  } u;
+  volatile short blen;        /* Buffer Length (two's complement) */
+  unsigned short mlen;        /* Message Byte Count */
+};
+
+
+/* Transmit Message Descriptor Entry */
+
+struct tmd   
+{
+  union 
+  {
+    unsigned long  buffer;    /* Address of buffer */
+    struct 
+    {
+      unsigned char unused[3];
+      unsigned volatile char status;   /* Status Bits */
+    } s;
+  } u;
+  unsigned short blen;             /* Buffer Length (two's complement) */
+  unsigned volatile short status2; /* Error Status Bits */
+};
+
+#endif /* End of SK_G16_H */
diff -u --recursive --new-file v1.1.24/linux/drivers/net/slhc.c linux/drivers/net/slhc.c
--- v1.1.24/linux/drivers/net/slhc.c	Tue May 24 00:34:52 1994
+++ linux/drivers/net/slhc.c	Thu Jul  7 18:28:48 1994
@@ -36,6 +36,8 @@
  *			allow zero or one slots
  *			separate routines
  *			status display
+ *	- Jul 1994	Dmitry Gorodchanin
+ *			Fixes for memory leaks.
  *
  *
  *	This module is a difficult issue. Its clearly inet code but its also clearly
@@ -101,7 +103,10 @@
 		  (struct cstate *)kmalloc(rslots * sizeof(struct cstate),
 					   GFP_KERNEL);
 		if (! comp->rstate)
+		{
+			kfree((unsigned char *)comp);
 			return NULL;
+		}
 		memset(comp->rstate, 0, rslots * sizeof(struct cstate));
 		comp->rslot_limit = rslots - 1;
 	}
@@ -111,7 +116,11 @@
 		  (struct cstate *)kmalloc(tslots * sizeof(struct cstate),
 					   GFP_KERNEL);
 		if (! comp->tstate)
+		{
+			kfree((unsigned char *)comp->rstate);
+			kfree((unsigned char *)comp);
 			return NULL;
+		}
 		memset(comp->tstate, 0, rslots * sizeof(struct cstate));
 		comp->tslot_limit = tslots - 1;
 	}
diff -u --recursive --new-file v1.1.24/linux/drivers/net/slip.c linux/drivers/net/slip.c
--- v1.1.24/linux/drivers/net/slip.c	Wed Jun 22 14:57:10 1994
+++ linux/drivers/net/slip.c	Thu Jul  7 18:28:41 1994
@@ -23,6 +23,8 @@
  *		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)
+ *		A.N.Kuznetsov	:	dev_tint() recursion fix.
+ *	Dmitry Gorodchanin	:	SLIP memory leaks
  *
  *
  *	FIXME:	This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without
@@ -379,7 +381,7 @@
   actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count);
   if (actual == count) {
 	  sl_unlock(sl);
-	  dev_tint(sl->dev);
+	  mark_bh(NET_BH);
   } else {
 	  sl->xhead = sl->xbuff + count;
 	  sl->xtail = sl->xbuff + actual;
@@ -420,7 +422,7 @@
 		tty->flags &= ~TTY_DO_WRITE_WAKEUP;
 
 		sl_unlock(sl);
-		dev_tint(sl->dev);
+		mark_bh(NET_BH);
 	} else {
 		sl->xtail += answer;
 	}
@@ -566,7 +568,7 @@
 
   p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
   if (p == NULL) {
-	kfree_s((void *)sl->dev->mem_start,l+4);
+	kfree((unsigned char *)sl->dev->mem_start);
 	return(-ENOMEM);
   }
   sl->dev->rmem_start	= (unsigned long) p;
@@ -584,6 +586,7 @@
   p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
   if (p == NULL) {
   	kfree((unsigned char *)sl->dev->mem_start);
+  	kfree((unsigned char *)sl->dev->rmem_start);
 	return(-ENOMEM);
   }
   sl->cbuff		= p;
@@ -592,7 +595,7 @@
   if (sl->slcomp == NULL) {
   	kfree((unsigned char *)sl->dev->mem_start);
   	kfree((unsigned char *)sl->dev->rmem_start);
-  	kfree(sl->cbuff);
+  	kfree((unsigned char *)sl->cbuff);
 	return(-ENOMEM);
   }
 #endif
diff -u --recursive --new-file v1.1.24/linux/drivers/net/znet.c linux/drivers/net/znet.c
--- v1.1.24/linux/drivers/net/znet.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/znet.c	Thu Jul  7 18:03:34 1994
@@ -0,0 +1,767 @@
+/* znet.c: An Zenith Z-Note ethernet driver for linux. */
+
+static char *version = "znet.c:v1.01 7/1/94 becker@cesdis.gsfc.nasa.gov\n";
+
+/*
+	Written by Donald Becker.
+
+	The author may be reached as becker@cesdis.gsfc.nasa.gov.
+	This driver is based on the Linux skeleton driver.  The copyright of the
+	skeleton driver is held by the United States Government, as represented
+	by DIRNSA, and it is released under the GPL.
+
+	Thanks to Mike Hollick for alpha testing and suggestions.
+
+  References:
+	   The Crynwr packet driver.
+
+	  "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992
+	  Intel Microcommunications Databook, Vol. 1, 1990.
+    As usual with Intel, the documentation is incomplete and inaccurate.
+	I had to read the Crynwr packet driver to figure out how to actually
+	use the i82593, and guess at what register bits matched the loosely
+	related i82586.
+
+					Theory of Operation
+
+	The i82593 used in the Zenith Z-Note series operates using two(!) slave
+	DMA	channels, one interrupt, and one 8-bit I/O port.
+
+	While there	several ways to configure '593 DMA system, I chose the one
+	that seemed commesurate with the highest system performance in the face
+	of moderate interrupt latency: Both DMA channels are configued as
+	recirculating ring buffers, with one channel (#0) dedicated to Rx and
+	the other channel (#1) to Tx and configuration.  (Note that this is
+	different than the Crynwr driver, where the Tx DMA channel is initialized
+	before each operation.  That approach simplifies operation and Tx error
+	recovery, but requires additional I/O in normal operation and precludes
+	transmit buffer	chaining.)
+
+	Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE.  This provides
+	a reasonable ring size for Rx, while simplifying DMA buffer allocation --
+	DMA buffers must not cross a 128K boundary.  (In truth the size selection
+	was influenced by my lack of '593 documentation.  I thus was constrained
+	to use the Crynwr '593 initialization table, which sets the Rx ring size
+	to 8K.)
+
+	Despite my usual low opinion about Intel-designed parts, I must admit
+	that the bulk data handling of the i82593 is a good design for
+	an integrated system, like a laptop, where using two slave DMA channels
+	doesn't pose a problem.  I still take issue with using only a single I/O
+	port.  In the same controlled environment there are essentially no
+	limitations on I/O space, and using multiple locations would eliminate
+	the	need for multiple operations when looking at status registers,
+	setting the Rx ring boundary, or switching to promiscuous mode.
+
+	I also question Zenith's selection of the '593: one of the advertised
+	advantages of earlier Intel parts was that if you figured out the magic
+	initialization incantation you could use the same part on many different
+	network types.  Zenith's use of the "FriendlyNet" (sic) connector rather
+	than an	on-board transceiver leads me to believe that they were planning
+	to take advantage of this.  But, uhmmm, the '593 omits all but ethernet
+	functionality from the serial subsystem.
+ */
+
+#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/interrupt.h>
+#include <linux/ioport.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+
+#ifndef ZNET_DEBUG
+#define ZNET_DEBUG 3
+#endif
+static unsigned int znet_debug = ZNET_DEBUG;
+
+/* The DMA modes we need aren't in <dma.h>. */
+#define DMA_RX_MODE		0x14	/* Auto init, I/O to mem, ++, demand. */
+#define DMA_TX_MODE		0x18	/* Auto init, Mem to I/O, ++, demand. */
+#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17)
+#define DMA_BUF_SIZE 8192
+#define RX_BUF_SIZE 8192
+#define TX_BUF_SIZE 8192
+
+/* Commands to the i82593 channel 0. */
+#define CMD0_CHNL_0			0x00
+#define CMD0_CHNL_1			0x10		/* Switch to channel 1. */
+#define CMD0_NOP (CMD0_CHNL_0)
+#define CMD0_PORT_1	CMD0_CHNL_1
+#define CMD1_PORT_0	1
+#define CMD0_IA_SETUP		1
+#define CMD0_CONFIGURE		2
+#define CMD0_MULTICAST_LIST 3
+#define CMD0_TRANSMIT		4
+#define CMD0_DUMP			6
+#define CMD0_DIAGNOSE		7
+#define CMD0_Rx_ENABLE		8
+#define CMD0_Rx_DISABLE		10
+#define CMD0_Rx_STOP		11
+#define CMD0_RETRANSMIT		12
+#define CMD0_ABORT			13
+#define CMD0_RESET			14
+
+#define CMD0_ACK 0x80
+
+#define CMD0_STAT0 (0 << 5)
+#define CMD0_STAT1 (1 << 5)
+#define CMD0_STAT2 (2 << 5)
+#define CMD0_STAT3 (3 << 5)
+
+#define net_local znet_private
+struct znet_private {
+	int rx_dma, tx_dma;
+	struct enet_statistics stats;
+	/* The starting, current, and end pointers for the packet buffers. */
+	ushort *rx_start, *rx_cur, *rx_end;
+	ushort *tx_start, *tx_cur, *tx_end;
+	ushort tx_buf_len;			/* Tx buffer lenght, in words. */
+};
+
+/* Only one can be built-in;-> */
+static struct znet_private zn;
+static ushort dma_buffer1[DMA_BUF_SIZE/2];
+static ushort dma_buffer2[DMA_BUF_SIZE/2];
+static ushort dma_buffer3[DMA_BUF_SIZE/2 + 8];
+
+/* The configuration block.  What an undocumented nightmare.  The first
+   set of values are those suggested (without explaination) for ethernet
+   in the Intel 82586 databook.	 The rest appear to be completely undocumented,
+   except for cryptic notes in the Crynwr packet driver.  This driver uses
+   the Crynwr values verbatim. */
+
+static unsigned char i593_init[] = {
+  0xAA,					/* 0: 16-byte input & 80-byte output FIFO. */
+						/*	  threshhold, 96-byte FIFO, 82593 mode. */
+  0x88,					/* 1: Continuous w/interrupts, 128-clock DMA.*/
+  0x2E,					/* 2: 8-byte preamble, NO address insertion, */
+						/*	  6-byte Ethernet address, loopback off.*/
+  0x00,					/* 3: Default priorities & backoff methods. */
+  0x60,					/* 4: 96-bit interframe spacing. */
+  0x00,					/* 5: 512-bit slot time (low-order). */
+  0xF2,					/* 6: Slot time (high-order), 15 COLL retries. */
+  0x00,					/* 7: Promisc-off, broadcast-on, default CRC. */
+  0x00,					/* 8: Default carrier-sense, collision-detect. */
+  0x40,					/* 9: 64-byte minimum frame length. */
+  0x5F,					/* A: Type/length checks OFF, no CRC input,
+						   "jabber" termination, etc. */
+  0x00,					/* B: Full-duplex disabled. */
+  0x3F,					/* C: Default multicast addresses & backoff. */
+  0x07,					/* D: Default IFS retriggering. */
+  0x31,					/* E: Internal retransmit, drop "runt" packets,
+						   synchr. DRQ deassertion, 6 status bytes. */
+  0x22,					/* F: Receive ring-buffer size (8K), 
+						   receive-stop register enable. */
+};
+
+struct netidblk {
+	char magic[8];		/* The magic number (string) "NETIDBLK" */
+	unsigned char netid[8]; /* The physical station address */
+	char nettype, globalopt;
+	char vendor[8];		/* The machine vendor and product name. */
+	char product[8];
+	char irq1, irq2;		/* Interrupts, only one is currently used.	*/
+	char dma1, dma2;
+	short dma_mem_misc[8];		/* DMA buffer locations (unused in Linux). */
+	short iobase1, iosize1;
+	short iobase2, iosize2;		/* Second iobase unused. */
+	char driver_options;			/* Misc. bits */
+	char pad;
+};
+
+int znet_probe(struct device *dev);
+static int	znet_open(struct device *dev);
+static int	znet_send_packet(struct sk_buff *skb, struct device *dev);
+static void	znet_interrupt(int reg_ptr);
+static void	znet_rx(struct device *dev);
+static int	znet_close(struct device *dev);
+static struct enet_statistics *net_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+static void hardware_init(struct device *dev);
+static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
+
+#ifdef notdef
+static struct sigaction znet_sigaction = { &znet_interrupt, 0, 0, NULL, };
+#endif
+
+
+/* The Z-Note probe is pretty easy.  The NETIDBLK exists in the safe-to-probe
+   BIOS area.  We just scan for the signature, and pull the vital parameters
+   out of the structure. */
+
+int znet_probe(struct device *dev)
+{
+	int i;
+	struct netidblk *netinfo;
+	char *p;
+
+	/* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
+	for(p = (char *)0xf0000; p < (char *)0x100000; p++)
+		if (*p == 'N'  &&  strncmp(p, "NETIDBLK", 8) == 0)
+			break;
+
+	if (p >= (char *)0x100000) {
+		if (znet_debug > 1)
+			printk(KERN_INFO "No Z-Note ethernet adaptor found.\n");
+		return ENODEV;
+	}
+	netinfo = (struct netidblk *)p;
+	dev->base_addr = netinfo->iobase1;
+	dev->irq = netinfo->irq1;
+
+	printk(KERN_INFO "%s: ZNET at %#3x,", dev->name, dev->base_addr);
+
+	/* The station address is in the "netidblk" at 0x0f0000. */
+	for (i = 0; i < 6; i++)
+		printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]);
+
+	printk(", using IRQ %d DMA %d and %d.\n", dev->irq, netinfo->dma1,
+		netinfo->dma2);
+
+	if (znet_debug > 1) {
+		printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
+			   dev->name, netinfo->vendor,
+			   netinfo->irq1, netinfo->irq2,
+			   netinfo->dma1, netinfo->dma2);
+		printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n",
+			   dev->name, netinfo->iobase1, netinfo->iosize1,
+			   netinfo->iobase2, netinfo->iosize2, netinfo->nettype);
+	}
+
+	if (znet_debug > 0)
+		printk("%s%s", KERN_INFO, version);
+
+	dev->priv = (void *) &zn;
+	zn.rx_dma = netinfo->dma1;
+	zn.tx_dma = netinfo->dma2;
+
+	/* These should never fail.  You can't add devices to a sealed box! */
+	if (request_irq(dev->irq, &znet_interrupt)
+		|| request_dma(zn.rx_dma)
+		|| request_dma(zn.tx_dma)) {
+		printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
+		return EBUSY;
+	}
+	irq2dev_map[dev->irq] = dev;
+
+	/* Allocate buffer memory.	We can cross a 128K boundary, so we
+	   must be careful about the allocation.  It's easiest to waste 8K. */
+	if (dma_page_eq(dma_buffer1, &dma_buffer1[RX_BUF_SIZE/2-1]))
+	  zn.rx_start = dma_buffer1;
+	else 
+	  zn.rx_start = dma_buffer2;
+
+	if (dma_page_eq(dma_buffer3, &dma_buffer3[RX_BUF_SIZE/2-1]))
+	  zn.tx_start = dma_buffer3;
+	else
+	  zn.tx_start = dma_buffer2;
+	zn.rx_end = zn.rx_start + RX_BUF_SIZE/2;
+	zn.tx_buf_len = TX_BUF_SIZE/2;
+	zn.tx_end = zn.tx_start + zn.tx_buf_len;
+
+	/* The ZNET-specific entries in the device structure. */
+	dev->open = &znet_open;
+	dev->hard_start_xmit = &znet_send_packet;
+	dev->stop = &znet_close;
+	dev->get_stats	= net_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+
+	/* Fill in the 'dev' with ethernet-generic values. */
+	ether_setup(dev);
+
+	return 0;
+}
+
+
+static int znet_open(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+
+	if (znet_debug > 2)
+		printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name);
+
+	/* Turn on the 82501 SIA, using zenith-specific magic. */
+	outb(0x10, 0xe6);					/* Select LAN control register */
+	outb(inb(0xe7) | 0x84, 0xe7);		/* Turn on LAN power (bit 2). */
+	/* According to the Crynwr driver we should wait 50 msec. for the
+	   LAN clock to stabilize.  My experiments indicates that the '593 can
+	   be initialized immediately.  The delay is probably needed for the
+	   DC-to-DC converter to come up to full voltage, and for the oscillator
+	   to be spot-on at 20Mhz before transmitting.
+	   Until this proves to be a problem we rely on the higher layers for the
+	   delay and save allocating a timer entry. */
+
+	/* This follows the packet driver's lead, and checks for success. */
+	if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
+		printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
+			   dev->name);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	hardware_init(dev);
+	dev->start = 1;
+
+	return 0;
+}
+
+static int znet_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+
+	if (znet_debug > 4)
+		printk(KERN_DEBUG "%s: ZNet_send_packet(%d).\n", dev->name, dev->tbusy);
+
+	/* Transmitter timeout, likely just recovery after suspending the machine. */
+	if (dev->tbusy) {
+		ushort event, tx_status, rx_offset, state;
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 10)
+			return 1;
+		outb(CMD0_STAT0, ioaddr); event = inb(ioaddr);
+		outb(CMD0_STAT1, ioaddr); tx_status = inw(ioaddr);
+		outb(CMD0_STAT2, ioaddr); rx_offset = inw(ioaddr);
+		outb(CMD0_STAT3, ioaddr); state = inb(ioaddr);
+		printk(KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x,"
+			   " resetting.\n", dev->name, event, tx_status, rx_offset, state);
+		if (tx_status == 0x0400)
+		  printk(KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n",
+				 dev->name);
+		outb(CMD0_RESET, ioaddr);
+		hardware_init(dev);
+	}
+
+	if (skb == NULL) {
+		dev_tint(dev);
+		return 0;
+	}
+
+	/* Check that the part hasn't reset itself, probably from suspend. */
+	outb(CMD0_STAT0, ioaddr);
+	if (inw(ioaddr) == 0x0010
+		&& inw(ioaddr) == 0x0000
+		&& inw(ioaddr) == 0x0010)
+	  hardware_init(dev);
+
+	/* 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(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+	else {
+		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		unsigned char *buf = (void *)(skb+1);
+		ushort *tx_link = zn.tx_cur - 1;
+		ushort rnd_len = (length + 1)>>1;
+
+		{
+			short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
+			unsigned addr = inb(dma_port);
+			addr |= inb(dma_port) << 8;
+			addr <<= 1;
+			if (((int)zn.tx_cur & 0x1ffff) != addr)
+			  printk(KERN_WARNING "Address mismatch at Tx: %#x vs %#x.\n",
+					 (int)zn.tx_cur & 0xffff, addr);
+			zn.tx_cur = (ushort *)(((int)zn.tx_cur & 0xfe0000) | addr);
+		}
+
+		if (zn.tx_cur >= zn.tx_end)
+		  zn.tx_cur = zn.tx_start;
+		*zn.tx_cur++ = length;
+		if (zn.tx_cur + rnd_len + 1 > zn.tx_end) {
+			int semi_cnt = (zn.tx_end - zn.tx_cur)<<1; /* Cvrt to byte cnt. */
+			memcpy(zn.tx_cur, buf, semi_cnt);
+			rnd_len -= semi_cnt>>1;
+			memcpy(zn.tx_start, buf + semi_cnt, length - semi_cnt);
+			zn.tx_cur = zn.tx_start + rnd_len;
+		} else {
+			memcpy(zn.tx_cur, buf, skb->len);
+			zn.tx_cur += rnd_len;
+		}
+		*zn.tx_cur++ = 0;
+		cli(); {
+			*tx_link = CMD0_TRANSMIT + CMD0_CHNL_1;
+			/* Is this always safe to do? */
+			outb(CMD0_TRANSMIT + CMD0_CHNL_1,ioaddr);
+		} sti();
+
+		dev->trans_start = jiffies;
+		if (znet_debug > 4)
+		  printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
+	}
+	dev_kfree_skb(skb, FREE_WRITE); 
+	return 0;
+}
+
+/* The ZNET interrupt handler. */
+static void	znet_interrupt(int reg_ptr)
+{
+	int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+	struct device *dev = irq2dev_map[irq];
+	int ioaddr;
+	int boguscnt = 20;
+
+	if (dev == NULL) {
+		printk(KERN_WARNING "znet_interrupt(): IRQ %d for unknown device.\n", irq);
+		return;
+	}
+
+	dev->interrupt = 1;
+	ioaddr = dev->base_addr;
+
+	outb(CMD0_STAT0, ioaddr);
+	do {
+		ushort status = inb(ioaddr);
+		if (znet_debug > 5) {
+			ushort result, rx_ptr, running;
+			outb(CMD0_STAT1, ioaddr);
+			result = inw(ioaddr);
+			outb(CMD0_STAT2, ioaddr);
+			rx_ptr = inw(ioaddr);
+			outb(CMD0_STAT3, ioaddr);
+			running = inb(ioaddr);
+			printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",
+				 dev->name, status, result, rx_ptr, running, boguscnt);
+		}
+		if ((status & 0x80) == 0)
+			break;
+
+		if ((status & 0x0F) == 4) {	/* Transmit done. */
+			struct net_local *lp = (struct net_local *)dev->priv;
+			int tx_status;
+			outb(CMD0_STAT1, ioaddr);
+			tx_status = inw(ioaddr);
+			/* It's undocumented, but tx_status seems to match the i82586. */
+			if (tx_status & 0x2000) {
+				lp->stats.tx_packets++;
+				lp->stats.collisions += tx_status & 0xf;
+			} else {
+				if (tx_status & 0x0600)  lp->stats.tx_carrier_errors++;
+				if (tx_status & 0x0100)  lp->stats.tx_fifo_errors++;
+				if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++;
+				if (tx_status & 0x0020)  lp->stats.tx_aborted_errors++;
+				/* ...and the catch-all. */
+				if (tx_status | 0x0760 != 0x0760)
+				  lp->stats.tx_errors++;
+			}
+			dev->tbusy = 0;
+			mark_bh(NET_BH);	/* Inform upper layers. */
+		}
+
+		if ((status & 0x40)
+			|| (status & 0x0f) == 11) {
+			znet_rx(dev);
+		}
+		/* Clear the interrupts we've handled. */
+		outb(CMD0_ACK,ioaddr);
+	} while (boguscnt--);
+
+	dev->interrupt = 0;
+	return;
+}
+
+static void znet_rx(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int boguscount = 1;
+	short next_frame_end_offset = 0; 		/* Offset of next frame start. */
+	short *cur_frame_end;
+	short cur_frame_end_offset;
+
+	outb(CMD0_STAT2, ioaddr);
+	cur_frame_end_offset = inw(ioaddr);
+
+	if (cur_frame_end_offset == zn.rx_cur - zn.rx_start) {
+		printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",
+			   dev->name, cur_frame_end_offset);
+		return;
+	}
+
+	/* Use same method as the Crynwr driver: construct a forward list in
+	   the same area of the backwards links we now have.  This allows us to
+	   pass packets to the upper layers in the order they were received --
+	   important for fast-path sequential operations. */
+	 while (zn.rx_start + cur_frame_end_offset != zn.rx_cur
+			&& ++boguscount < 5) {
+		unsigned short hi_cnt, lo_cnt, hi_status, lo_status;
+		int count, status;
+
+		if (cur_frame_end_offset < 4) {
+			/* Oh no, we have a special case: the frame trailer wraps around
+			   the end of the ring buffer.  We've saved space at the end of
+			   the ring buffer for just this problem. */
+			memcpy(zn.rx_end, zn.rx_start, 8);
+			cur_frame_end_offset += (RX_BUF_SIZE/2);
+		}
+		cur_frame_end = zn.rx_start + cur_frame_end_offset - 4;
+
+		lo_status = *cur_frame_end++;
+		hi_status = *cur_frame_end++;
+		status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);
+		lo_cnt = *cur_frame_end++;
+		hi_cnt = *cur_frame_end++;
+		count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);
+
+		if (znet_debug > 5)
+		  printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"
+				 " count %#x status %04x.\n",
+				 cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,
+				 count, status);
+		cur_frame_end[-4] = status;
+		cur_frame_end[-3] = next_frame_end_offset;
+		cur_frame_end[-2] = count;
+		next_frame_end_offset = cur_frame_end_offset;
+		cur_frame_end_offset -= ((count + 1)>>1) + 3;
+		if (cur_frame_end_offset < 0)
+		  cur_frame_end_offset += RX_BUF_SIZE/2;
+	};
+
+	/* Now step  forward through the list. */
+	do {
+		ushort *this_rfp_ptr = zn.rx_start + next_frame_end_offset;
+		int status = this_rfp_ptr[-4];
+		int pkt_len = this_rfp_ptr[-2];
+	  
+		if (znet_debug > 5)
+		  printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
+				 " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
+				 this_rfp_ptr[-3]<<1);
+		/* Once again we must assume that the i82586 docs apply. */
+		if ( ! (status & 0x2000)) {				/* There was an error. */
+			lp->stats.rx_errors++;
+			if (status & 0x0800) lp->stats.rx_crc_errors++;
+			if (status & 0x0400) lp->stats.rx_frame_errors++;
+			if (status & 0x0200) lp->stats.rx_over_errors++; /* Wrong. */
+			if (status & 0x0100) lp->stats.rx_fifo_errors++;
+			if (status & 0x0080) lp->stats.rx_length_errors++;
+		} else if (pkt_len > 1536) {
+			lp->stats.rx_length_errors++;
+		} else {
+			/* Malloc up new buffer. */
+			int sksize = sizeof(struct sk_buff) + pkt_len;
+			struct sk_buff *skb;
+
+			skb = alloc_skb(sksize, GFP_ATOMIC);
+			if (skb == NULL) {
+				if (znet_debug)
+				  printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
+				lp->stats.rx_dropped++;
+				break;
+			}
+			skb->mem_len = sksize;
+			skb->mem_addr = skb;
+			skb->len = pkt_len;
+			skb->dev = dev;
+
+			if (&zn.rx_cur[(pkt_len+1)>>1] > zn.rx_end) {
+				int semi_cnt = (zn.rx_end - zn.rx_cur)<<1;
+				memcpy((unsigned char *) (skb + 1), zn.rx_cur, semi_cnt);
+				memcpy((unsigned char *) (skb + 1) + semi_cnt, zn.rx_start,
+					   pkt_len - semi_cnt);
+			} else {
+				memcpy((unsigned char *) (skb + 1), zn.rx_cur, pkt_len);
+				if (znet_debug > 6) {
+					unsigned int *packet = (unsigned int *) (skb + 1);
+					printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],
+						   packet[1], packet[2], packet[3]);
+				}
+		  }
+
+#ifdef HAVE_NETIF_RX
+			netif_rx(skb);
+#else
+			skb->lock = 0;
+			if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+				kfree_s(skb, sksize);
+				lp->stats.rx_dropped++;
+				break;
+			}
+#endif
+			lp->stats.rx_packets++;
+		}
+		zn.rx_cur = this_rfp_ptr;
+		if (zn.rx_cur >= zn.rx_end)
+			zn.rx_cur -= RX_BUF_SIZE/2;
+		update_stop_hit(ioaddr, (zn.rx_cur - zn.rx_start)<<1);
+		next_frame_end_offset = this_rfp_ptr[-3];
+		if (next_frame_end_offset == 0)		/* Read all the frames? */
+			break;			/* Done for now */
+		this_rfp_ptr = zn.rx_start + next_frame_end_offset;
+	} while (--boguscount);
+
+	/* If any worth-while packets have been received, dev_rint()
+	   has done a mark_bh(INET_BH) for us and will work on them
+	   when we get to the bottom-half routine. */
+	return;
+}
+
+/* The inverse routine to znet_open(). */
+static int znet_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	outb(CMD0_RESET, ioaddr);			/* CMD0_RESET */
+
+	disable_dma(zn.rx_dma);
+	disable_dma(zn.tx_dma);
+
+	free_irq(dev->irq);
+
+	if (znet_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
+	/* Turn off transceiver power. */
+	outb(0x10, 0xe6);					/* Select LAN control register */
+	outb(inb(0xe7) & ~0x84, 0xe7);		/* Turn on LAN power (bit 2). */
+
+	return 0;
+}
+
+/* Get the current statistics.	This may be called with the card open or
+   closed. */
+static struct enet_statistics *net_get_stats(struct device *dev)
+{
+		struct net_local *lp = (struct net_local *)dev->priv;
+
+		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.
+   As a side effect this routine must also initialize the device parameters.
+   This is taken advantage of in open().
+
+   N.B. that we change i593_init[] in place.  This (properly) makes the
+   mode change persistent, but must be changed if this code is moved to
+   a multiple adaptor environment.
+ */
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+	short ioaddr = dev->base_addr;
+
+	if (num_addrs < 0) {
+		/* Enable promiscuous mode */
+		i593_init[7] &= ~3;		i593_init[7] |= 1;
+		i593_init[13] &= ~8;	i593_init[13] |= 8;
+	} else if (num_addrs > 0) {
+		/* Enable accept-all-multicast mode */
+		i593_init[7] &= ~3;		i593_init[7] |= 0;
+		i593_init[13] &= ~8;	i593_init[13] |= 8;
+	} else {					/* Enable normal mode. */
+		i593_init[7] &= ~3;		i593_init[7] |= 0;
+		i593_init[13] &= ~8;	i593_init[13] |= 0;
+	}
+	*zn.tx_cur++ = sizeof(i593_init);
+	memcpy(zn.tx_cur, i593_init, sizeof(i593_init));
+	zn.tx_cur += sizeof(i593_init)/2;
+	outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);
+#ifdef not_tested
+	if (num_addrs > 0) {
+		int addrs_len = 6*num_addrs;
+		*zn.tx_cur++ = addrs_len;
+		memcpy(zn.tx_cur, addrs, addrs_len);
+		outb(CMD0_MULTICAST_LIST+CMD0_CHNL_1, ioaddr);
+		zn.tx_cur += addrs_len>>1;
+	}
+#endif
+}
+#endif
+
+void show_dma(void)
+{
+	short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;
+	unsigned addr = inb(dma_port);
+	addr |= inb(dma_port) << 8;
+	printk("Addr: %04x cnt:%3x...", addr<<1, get_dma_residue(zn.tx_dma));
+}
+
+/* Initialize the hardware.  We have to do this when the board is open()ed
+   or when we come out of suspend mode. */
+static void hardware_init(struct device *dev)
+{
+	short ioaddr = dev->base_addr;
+
+	zn.rx_cur = zn.rx_start;
+	zn.tx_cur = zn.tx_start;
+
+	/* Reset the chip, and start it up. */
+	outb(CMD0_RESET, ioaddr);
+
+	cli(); {							/* Protect against a DMA flip-flop */
+		disable_dma(zn.rx_dma); 		/* reset by an interrupting task. */
+		clear_dma_ff(zn.rx_dma);
+		set_dma_mode(zn.rx_dma, DMA_RX_MODE);
+		set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_start);
+		set_dma_count(zn.rx_dma, RX_BUF_SIZE);
+		enable_dma(zn.rx_dma);
+		/* Now set up the Tx channel. */
+		disable_dma(zn.tx_dma);
+		clear_dma_ff(zn.tx_dma);
+		set_dma_mode(zn.tx_dma, DMA_TX_MODE);
+		set_dma_addr(zn.tx_dma, (unsigned int) zn.tx_start);
+		set_dma_count(zn.tx_dma, zn.tx_buf_len<<1);
+		enable_dma(zn.tx_dma);
+	} sti();
+
+	if (znet_debug > 1)
+	  printk(KERN_DEBUG "%s: Initializing the i82593, tx buf %p... ", dev->name,
+			 zn.tx_start);
+	/* Do an empty configure command, just like the Crynwr driver.  This
+	   resets to chip to its default values. */
+	*zn.tx_cur++ = 0;
+	*zn.tx_cur++ = 0;
+	printk("stat:%02x ", inb(ioaddr)); show_dma();
+	outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);
+	*zn.tx_cur++ = sizeof(i593_init);
+	memcpy(zn.tx_cur, i593_init, sizeof(i593_init));
+	zn.tx_cur += sizeof(i593_init)/2;
+	printk("stat:%02x ", inb(ioaddr)); show_dma();
+	outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);
+	*zn.tx_cur++ = 6;
+	memcpy(zn.tx_cur, dev->dev_addr, 6);
+	zn.tx_cur += 3;
+	printk("stat:%02x ", inb(ioaddr)); show_dma();
+	outb(CMD0_IA_SETUP + CMD0_CHNL_1, ioaddr);
+	printk("stat:%02x ", inb(ioaddr)); show_dma();
+
+	update_stop_hit(ioaddr, 8192);
+	if (znet_debug > 1)  printk("enabling Rx.\n");
+	outb(CMD0_Rx_ENABLE+CMD0_CHNL_0, ioaddr);
+	dev->tbusy = 0;
+}
+
+static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset)
+{
+	outb(CMD0_PORT_1, ioaddr);
+	if (znet_debug > 5)
+	  printk(KERN_DEBUG "Updating stop hit with value %02x.\n",
+			 (rx_stop_offset >> 6) | 0x80);
+	outb((rx_stop_offset >> 6) | 0x80, ioaddr);
+	outb(CMD1_PORT_0, ioaddr);
+}
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c znet.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
Only in v1.1.24/linux/drivers/net: znote.c
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog
--- v1.1.24/linux/drivers/scsi/ChangeLog	Fri Jun 17 15:20:05 1994
+++ linux/drivers/scsi/ChangeLog	Thu Jul  7 18:45:08 1994
@@ -1,4 +1,45 @@
+Wed Jul  6 05:45:02 1994  Eric Youngdale  (eric@esp22)
+
+	* Linux 1.1.25 released.
+
+	* sd.c, sr.c: Use new check_media_change and revalidate
+	file_operations fields.
+
+	* st.c, st.h: Add changes from Kai Makisara, dated Jun 22.
+
+	* hosts.h: Change SG_ALL back to 0xff.  Apparently soft error
+	in /dev/brain resulted in having this bumped up.
+	Change first parameter in bios_param function to be Disk * instead
+	of index into rscsi_disks.
+
+	* sd_ioctl.c: Pass pointer to rscsi_disks element instead of index
+	to array.
+
+	* sd.h: Add struct name "scsi_disk" to typedef for Scsi_Disk.
+
+	* scsi.c: Remove redundant Maxtor XT8760S from blacklist.
+	In scsi_reset, add printk when DEBUG defined.
+
+	* All low level drivers: Modify definitions of bios_param in
+	appropriate way.
+
+Thu Jun 16 10:31:59 1994  Eric Youngdale  (eric@esp22)
+
+	* Linux 1.1.20 released.
+
+	* scsi_ioctl.c: Only pass down the actual number of characters
+	required to scsi_do_cmd, not the one rounded up to a even number
+	of sectors.
+
+	* ultrastor.c: Changes from Caleb Epstein for 24f cards.  Support
+	larger SG lists.
+
+	* ultrastor.c: Changes from me - use scsi_register to register
+	host.  Add some consistency checking, 
+
 Wed Jun  1 21:12:13 1994  Eric Youngdale  (eric@esp22)
+
+	* Linux 1.1.19 released.
 
 	* scsi.h: Add new return code for reset() function:
 	SCSI_RESET_PUNT.
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/README.st linux/drivers/scsi/README.st
--- v1.1.24/linux/drivers/scsi/README.st	Mon May 23 12:14:22 1994
+++ linux/drivers/scsi/README.st	Thu Jul  7 18:45:05 1994
@@ -1,5 +1,5 @@
 This file contains brief information about the SCSI tape driver.
-Last modified: Thu May  5 00:13:24 1994 by root@kai.home
+Last modified: Wed Jun 22 23:38:47 1994 by root@kai.home
 
 BASICS
 
@@ -10,6 +10,9 @@
 (minor equals device number) and non-rewind devices (minor is 128 +
 device number) are implemented.
 
+By default the driver writes one filemark when the device is closed after
+writing. Two filemarks can be optionally written. In both cases end
+of data is signified by returning zero bytes for two consecutive reads.
 
 BUFFERING
 
@@ -78,12 +81,13 @@
 MTWEOF  Write count filemarks.
 MTREW   Rewind tape.
 MTOFFL  Set device off line (often rewind plus eject).
-MTNOP   Do nothing.
+MTNOP   Do nothing except flush the buffers.
 MTRETEN Retension tape.
 MTEOM   Space to end of recorded data.
 MTERASE Erase tape.
 MTSEEK	Seek to tape block count. Uses Tandberg-compatible seek (QFA)
-        for SCSI-1 drives and SCSI-2 seek for SCSI-2 drives.
+        for SCSI-1 drives and SCSI-2 seek for SCSI-2 drives. The file and
+	block numbers in the status are not valid after a seek.
 MTSETBLK Set the drive block size. Setting to zero sets the drive into
         variable block mode (if applicable).
 MTSETDENSITY Sets the drive density code to arg. See drive
@@ -99,8 +103,9 @@
            Sets the buffering options. The bits are the new states
            (enabled/disabled) of the write buffering (MT_ST_BUFFER_WRITES),
            asynchronous writes (MT_ST_ASYNC_WRITES), read ahead
-           (MT_ST_READ_AHEAD) and debugging (MT_ST_DEBUGGING;
-           (debugging must be compiled into the driver).
+           (MT_ST_READ_AHEAD), writing of two filemark (ST_TWO_FM), and
+	   debugging (MT_ST_DEBUGGING ; debugging must be compiled into the
+	   driver).
         MT_ST_WRITE_THRESHOLD
            Sets the write threshold for this device to kilobytes
            specified by the lowest bits.
@@ -120,6 +125,8 @@
         The current block size and the density code are stored in the field
         mt_dsreg (shifts for the subfields are MT_ST_BLKSIZE_SHIFT and
         MT_ST_DENSITY_SHIFT).
+	The write protect bit in mt_gstat is set if the tape is write
+	protected.
         The other fields are empty.
 
 
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- v1.1.24/linux/drivers/scsi/aha152x.c	Fri May 27 10:49:07 1994
+++ linux/drivers/scsi/aha152x.c	Thu Jul  7 18:45:06 1994
@@ -20,10 +20,19 @@
  * General Public License for more details.
  
  *
- * $Id: aha152x.c,v 1.0 1994/03/25 12:52:00 root Exp $
+ * $Id: aha152x.c,v 1.2 1994/07/03 12:56:36 root Exp $
  *
 
  * $Log: aha152x.c,v $
+ * Revision 1.2  1994/07/03  12:56:36  root
+ * - cleaned up debugging code
+ * - more tweaking on reset delays
+ * - updated abort/reset code (pretty untested...)
+ *
+ * Revision 1.1  1994/05/28  21:18:49  root
+ * - update for mid-level interface change (abort-reset)
+ * - delays after resets adjusted for some slow devices
+ *
  * Revision 1.0  1994/03/25  12:52:00  root
  * - Fixed "more data than expected" problem
  * - added new BIOS signatures
@@ -162,12 +171,11 @@
 
  **************************************************************************/
 
-#include "aha152x.h"
-
 #include <linux/sched.h>
 #include <asm/io.h>
 #include "../block/blk.h"
 #include "scsi.h"
+#include "sd.h" /* Reqd for biosparam definition */
 #include "hosts.h"
 #include "constants.h"
 #include <asm/system.h>
@@ -176,6 +184,8 @@
 #include <linux/wait.h>
 #include <linux/ioport.h>
 
+#include "aha152x.h"
+
 /* DEFINES */
 
 
@@ -500,10 +510,6 @@
   struct sigaction    sa;
   int                 interrupt_level;
   
-#if defined(DEBUG_RACE)
-  enter_driver("detect");
-#endif
-  
   if(setup_called)
     {
       printk("aha152x: processing commandline: ");
@@ -568,13 +574,8 @@
                      (int) signatures[j].sig_length);
 
       if(!ok)
-        {
-#if defined(DEBUG_RACE)
-          leave_driver("(1) detect");
-#endif
-          printk("failed\n");
-          return 0;
-        }
+        return 0;
+
       printk("aha152x: BIOS test: passed, ");
 #else
       printk("aha152x: ");
@@ -588,9 +589,6 @@
       if(i==PORT_COUNT)
         {
           printk("failed\n");
-#if defined(DEBUG_RACE)
-          leave_driver("(2) detect");
-#endif
           return 0;
         }
       else
@@ -662,9 +660,9 @@
 
   /* RESET OUT */
   SETBITS(SCSISEQ, SCSIRSTO );
-  do_pause(5);
+  do_pause(30);
   CLRBITS(SCSISEQ, SCSIRSTO );
-  do_pause(10);
+  do_pause(60);
 
   aha152x_reset(NULL);
 
@@ -677,10 +675,6 @@
   SETPORT(SIMODE0, 0);
   SETPORT(SIMODE1, 0);
 
-#if defined(DEBUG_RACE)
-  leave_driver("(3) detect");
-#endif
-
   SETBITS( DMACNTRL0, INTEN);
   return 1;
 }
@@ -765,6 +759,10 @@
     }
   sti();
 
+#if defined(DEBUG_RACE)
+  leave_driver("queue");
+#endif
+
   return 0;
 }
 
@@ -791,7 +789,9 @@
   printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt );
 #endif
 
+#if defined(DEBUG_ABORT)
   show_queues();
+#endif
 
   /* look for command in issue queue */
   for( ptr=issue_SC, prev=NULL;
@@ -814,12 +814,21 @@
       return SCSI_ABORT_SUCCESS;
     }
 
-  /* Fail abortion, if we're on the bus */
   if (current_SC)
-    {
+    if( TESTLO(SSTAT1, BUSFREE) ) {
+       /* fail abortion, if current command is on the bus */
        sti();
        return SCSI_ABORT_BUSY;
     }
+    else
+    { 
+      /* target entered bus free before COMMAND COMPLETE, nothing to abort */
+      sti();
+      current_SC->result = DID_ERROR << 16;
+      current_SC->done(current_SC);
+      current_SC = (Scsi_Cmnd *) NULL;
+      return SCSI_ABORT_SUCCESS;
+    }
 
   /* look for command in disconnected queue */
   for( ptr=disconnected_SC, prev=NULL;
@@ -836,7 +845,7 @@
       if(prev)
         prev->host_scribble = ptr->host_scribble;
       else
-        issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
+        disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
 
       /* set command current and initiate selection,
          let the interrupt routine take care of the abortion */
@@ -903,11 +912,11 @@
 
 /*
  *  Reset registers, reset a hanging bus and
- *  kill active and disconnected commands
+ *  kill active and disconnected commands for target w/o soft reset
  */
 int aha152x_reset(Scsi_Cmnd * __unused)
 {
-  Scsi_Cmnd *ptr;
+  Scsi_Cmnd *ptr, *prev, *next;
 
   aha152x_reset_ports();
 
@@ -920,13 +929,11 @@
        printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
 #endif
 
+#if defined( DEBUG_RESET )
        show_queues();
-
-       /* FIXME - if the device implements soft resets, the command will still
-	  be running after the bus reset. In this case we should do nothing
-	  and let the command continue. -ERY */
+#endif
 
-       if(current_SC)
+       if(current_SC && !current_SC->device->soft_reset)
          {
            current_SC->host_scribble = NULL;
            current_SC->result = DID_RESET << 16;
@@ -934,22 +941,45 @@
            current_SC=NULL;
          }
 
-       while(disconnected_SC)
-         {
-           ptr = disconnected_SC;
-           disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
-           ptr->host_scribble = NULL;
-           ptr->result = DID_RESET << 16;
-           ptr->done(ptr);
-         }
+       cli();
+       prev=NULL; ptr=disconnected_SC;
+       while(ptr)
+	 {
+	   if(!ptr->device->soft_reset)
+	     {
+	       if(prev)
+		 prev->host_scribble = ptr->host_scribble;
+	       else
+		 disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
+
+	       next = (Scsi_Cmnd *) ptr->host_scribble;
+  
+	       ptr->host_scribble = NULL;
+	       ptr->result        = DID_RESET << 16;
+	       ptr->done(ptr);
+  
+	       ptr = next; 
+	     }
+	   else
+	     {
+	       prev=ptr;
+	       ptr = (Scsi_Cmnd *) ptr->host_scribble;
+	     }
+	 }
+       sti();
+
+#if defined( DEBUG_RESET )
+       printk("commands on targets w/ soft-resets:\n");
+       show_queues();
+#endif
 
        /* RESET OUT */
        SETPORT(SCSISEQ, SCSIRSTO);
-       do_pause(5);
+       do_pause(30);
        SETPORT(SCSISEQ, 0);
-       do_pause(10);
+       do_pause(60);
 
-       SETPORT(SIMODE0, 0 );
+       SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
        SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
 
        SETPORT( DMACNTRL0, INTEN );
@@ -961,8 +991,9 @@
 /*
  * Return the "logical geometry"
  */
-int aha152x_biosparam( int size, int dev, int *info_array )
+int aha152x_biosparam(Scsi_Disk * disk, int dev, int *info_array )
 {
+  int size = disk->capacity;
 #if defined(DEBUG_BIOSPARAM)
   printk("aha152x_biosparam: dev=%x, size=%d, ", dev, size);
 #endif
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h
--- v1.1.24/linux/drivers/scsi/aha152x.h	Fri May 27 10:49:07 1994
+++ linux/drivers/scsi/aha152x.h	Thu Jul  7 18:45:07 1994
@@ -2,7 +2,7 @@
 #define _AHA152X_H
 
 /*
- * $Id: aha152x.h,v 1.0 1994/03/25 12:52:00 root Exp $
+ * $Id: aha152x.h,v 1.2 1994/07/03 13:01:47 root Exp $
  */
 
 #include "../block/blk.h"
@@ -16,13 +16,13 @@
 int        aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int        aha152x_abort(Scsi_Cmnd *);
 int        aha152x_reset(Scsi_Cmnd *);
-int        aha152x_biosparam(int, int, int*);
+int        aha152x_biosparam(Disk *, int, int*);
 
 /* number of queueable commands
    (unless we support more than 1 cmd_per_lun this should do) */
 #define AHA152X_MAXQUEUE	7		
 
-#define AHA152X_REVID	"Adaptec 152x SCSI driver; $Revision: 1.0 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.2 $"
 
 /* Initial value of Scsi_Host entry */
 #define AHA152X       { /* name */		AHA152X_REVID, \
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c
--- v1.1.24/linux/drivers/scsi/aha1542.c	Fri Jun 17 15:20:06 1994
+++ linux/drivers/scsi/aha1542.c	Thu Jul  7 18:45:06 1994
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
-#include <linux/config.h>
 
 #include <linux/sched.h>
 #include <asm/dma.h>
@@ -1063,18 +1062,14 @@
     return SCSI_RESET_PUNT;
 }
 
-#ifdef CONFIG_BLK_DEV_SD
 #include "sd.h"
-#endif
 
-int aha1542_biosparam(int size, int dev, int * ip)
+int aha1542_biosparam(Scsi_Disk * disk, int dev, int * ip)
 {
   int translation_algorithm;
-#ifdef CONFIG_BLK_DEV_SD
-  Scsi_Device *disk;
+  int size = disk->capacity;
 
-  disk = rscsi_disks[MINOR(dev) >> 4].device;
-  translation_algorithm = HOSTDATA(disk->host)->bios_translation;
+  translation_algorithm = HOSTDATA(disk->device->host)->bios_translation;
   /* Should this be > 1024, or >= 1024?  Enquiring minds want to know. */
   if((size>>11) > 1024 && translation_algorithm == 2) {
     /* Please verify that this is the same as what DOS returns */
@@ -1087,6 +1082,5 @@
     ip[2] = size >> 11;
   };
 /*  if (ip[2] >= 1024) ip[2] = 1024; */
-#endif
   return 0;
 }
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha1542.h linux/drivers/scsi/aha1542.h
--- v1.1.24/linux/drivers/scsi/aha1542.h	Fri May 27 10:49:07 1994
+++ linux/drivers/scsi/aha1542.h	Thu Jul  7 18:45:08 1994
@@ -134,7 +134,7 @@
 int aha1542_abort(Scsi_Cmnd *);
 const char *aha1542_info(void);
 int aha1542_reset(Scsi_Cmnd *);
-int aha1542_biosparam(int, int, int*);
+int aha1542_biosparam(Disk *, int, int*);
 
 #define AHA1542_MAILBOXES 8
 #define AHA1542_SCATTER 16
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c
--- v1.1.24/linux/drivers/scsi/aha1740.c	Fri Jun 17 15:20:06 1994
+++ linux/drivers/scsi/aha1740.c	Thu Jul  7 18:45:06 1994
@@ -31,6 +31,7 @@
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
+#include "sd.h"
 
 #include "aha1740.h"
 
@@ -489,8 +490,9 @@
     return SCSI_RESET_PUNT;
 }
 
-int aha1740_biosparam(int size, int dev, int* ip)
+int aha1740_biosparam(Disk * disk, int dev, int* ip)
 {
+  int size = disk->capacity;
 DEB(printk("aha1740_biosparam\n"));
   ip[0] = 64;
   ip[1] = 32;
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha1740.h linux/drivers/scsi/aha1740.h
--- v1.1.24/linux/drivers/scsi/aha1740.h	Fri May 27 10:49:08 1994
+++ linux/drivers/scsi/aha1740.h	Thu Jul  7 18:45:08 1994
@@ -158,7 +158,7 @@
 int aha1740_abort(Scsi_Cmnd *);
 const char *aha1740_info(void);
 int aha1740_reset(Scsi_Cmnd *);
-int aha1740_biosparam(int, int, int*);
+int aha1740_biosparam(Disk *, int, int*);
 
 #define AHA1740_ECBS 32
 #define AHA1740_SCATTER 16
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c
--- v1.1.24/linux/drivers/scsi/buslogic.c	Fri Jun 17 15:20:06 1994
+++ linux/drivers/scsi/buslogic.c	Thu Jul  7 18:45:06 1994
@@ -59,7 +59,6 @@
  *    unfinished, questionable, or wrong.
  */
 
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -74,9 +73,7 @@
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
-#ifdef CONFIG_BLK_DEV_SD
 # include "sd.h"
-#endif
 #define BUSLOGIC_PRIVATE_H	/* Get the "private" stuff */
 #include "buslogic.h"
 
@@ -1181,17 +1178,17 @@
     return SCSI_RESET_PUNT;
 }
 
-int buslogic_biosparam(int size, int dev, int *ip)
+int buslogic_biosparam(Disk * disk, int dev, int *ip)
 {
-    /* ??? This is wrong if disk is configured for > 1G mapping.
-       Unfortunately, unlike UltraStor, I see know way of determining whether
-       > 1G mapping has been enabled. */
-#ifdef CONFIG_BLK_DEV_SD
-    int translation_algorithm;
-    Scsi_Device *disk;
+  int size = disk->capacity;
+  int translation_algorithm;
+
+  /* ??? This is wrong if disk is configured for > 1G mapping.
+     Unfortunately, unlike UltraStor, I see know way of determining whether
+     > 1G mapping has been enabled. */
 
-    disk = rscsi_disks[MINOR(dev) >> 4].device;
-    translation_algorithm = HOSTDATA(disk->host)->bios_translation;
+
+    translation_algorithm = HOSTDATA(disk->device->host)->bios_translation;
     /* ??? Should this be > 1024, or >= 1024?  Enquiring minds want to know. */
     if ((size >> 11) > 1024
 	&& translation_algorithm == BIOS_TRANSLATION_25563) {
@@ -1206,6 +1203,5 @@
     }
 /*    if (ip[2] > 1024)
       ip[2] = 1024; */
-#endif
     return 0;
 }
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/buslogic.h linux/drivers/scsi/buslogic.h
--- v1.1.24/linux/drivers/scsi/buslogic.h	Fri May 27 10:49:08 1994
+++ linux/drivers/scsi/buslogic.h	Thu Jul  7 18:45:08 1994
@@ -17,7 +17,7 @@
 int buslogic_abort(Scsi_Cmnd *);
 const char *buslogic_info(void);
 int buslogic_reset(Scsi_Cmnd *);
-int buslogic_biosparam(int, int, int *);
+int buslogic_biosparam(Disk *, int, int *);
 
 #define BUSLOGIC_CMDLUN 1	/* ??? */
 
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c
--- v1.1.24/linux/drivers/scsi/fdomain.c	Fri May 27 10:49:09 1994
+++ linux/drivers/scsi/fdomain.c	Thu Jul  7 18:45:07 1994
@@ -156,7 +156,6 @@
 
  **************************************************************************/
 
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <asm/io.h>
 #include "../block/blk.h"
@@ -1456,20 +1455,18 @@
    return SCSI_RESET_WAKEUP;
 }
 
-#ifdef CONFIG_BLK_DEV_SD
-
 #include "sd.h"
 #include "scsi_ioctl.h"
 
-int fdomain_16x0_biosparam( int size, int dev, int *info_array )
+int fdomain_16x0_biosparam(Scsi_Disk * disk, int dev, int *info_array )
 {
    int              drive;
+   int		    size = disk->capacity;
    unsigned char    buf[512 + sizeof( int ) * 2];
    int              *sizes    = (int *)buf;
    unsigned char    *data     = (unsigned char *)(sizes + 2);
    unsigned char    do_read[] = { READ_6, 0, 0, 0, 1, 0 };
    int              retcode;
-   Scsi_Device      *disk;
    struct drive_info {
       unsigned short cylinders;
       unsigned char  heads;
@@ -1509,7 +1506,6 @@
     */
 
    drive = MINOR(dev) / 16;
-   disk  = rscsi_disks[ drive ].device;
 
    if (bios_major == 2) {
       i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 );
@@ -1527,7 +1523,7 @@
       sizes[0] = 0;		/* zero bytes out */
       sizes[1] = 512;		/* one sector in */
       memcpy( data, do_read, sizeof( do_read ) );
-      retcode = kernel_scsi_ioctl( disk,
+      retcode = kernel_scsi_ioctl( disk->device,
 				   SCSI_IOCTL_SEND_COMMAND,
 				   (void *)buf );
       if (!retcode		                    /* SCSI command ok */
@@ -1588,5 +1584,3 @@
    
    return 0;
 }
-
-#endif /* CONFIG_BLK_DEV_SD */
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/fdomain.h linux/drivers/scsi/fdomain.h
--- v1.1.24/linux/drivers/scsi/fdomain.h	Fri May 27 10:49:09 1994
+++ linux/drivers/scsi/fdomain.h	Thu Jul  7 18:45:07 1994
@@ -32,11 +32,7 @@
 int        fdomain_16x0_reset( Scsi_Cmnd * ); 
 int        fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
 
-#ifdef CONFIG_BLK_DEV_SD
-int        fdomain_16x0_biosparam( int, int, int * );
-#else
-#define    fdomain_16x0_biosparam NULL
-#endif
+int        fdomain_16x0_biosparam(Disk *, int, int * );
 
 #define FDOMAIN_16X0 { "Future Domain TMC-16x0",          \
 			fdomain_16x0_detect,              \
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h
--- v1.1.24/linux/drivers/scsi/hosts.h	Fri May 27 10:49:09 1994
+++ linux/drivers/scsi/hosts.h	Thu Jul  7 18:45:05 1994
@@ -21,8 +21,10 @@
 */
 
 
+/* It is senseless to set SG_ALL any higher than this - the performance
+   does not get any better, and it wastes memory */
 #define SG_NONE 0
-#define SG_ALL 0x7fff
+#define SG_ALL 0xff
 
 #define DISABLE_CLUSTERING 0
 #define ENABLE_CLUSTERING 1
@@ -42,6 +44,8 @@
 	type of host adapter that is supported on the system.
 */
 
+typedef struct scsi_disk Disk;
+
 typedef struct     
 	{
 	/*
@@ -144,7 +148,7 @@
 		size, device number, list (heads, sectors, cylinders)
 	*/ 
 
-	int (* bios_param)(int, int, int []);
+	int (* bios_param)(Disk *, int, int []);
 	
 	/*
 		This determines if we will use a non-interrupt driven
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c
--- v1.1.24/linux/drivers/scsi/pas16.c	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/pas16.c	Thu Jul  7 18:45:06 1994
@@ -91,9 +91,9 @@
 #define AUTOPROBE_IRQ
 #include "NCR5380.h"
 #include "constants.h"
+#include "sd.h"
 
 
-
 int scsi_irq_translate[] =
 	{ 0,  0,  1,  2,  3,  4,  5,  6, 0,  0,  7,  8,  9,  0, 10, 11 };
 
@@ -374,7 +374,7 @@
 }
 
 /*
- * Function : int pas16_biosparam(int size, int dev, int *ip)
+ * Function : int pas16_biosparam(Disk *disk, int dev, int *ip)
  *
  * Purpose : Generates a BIOS / DOS compatable H-C-S mapping for 
  *	the specified device / size.
@@ -393,8 +393,9 @@
  * and matching the H_C_S coordinates to what DOS uses.
  */
 
-int pas16_biosparam(int size, int dev, int * ip)
+int pas16_biosparam(Disk * disk, int dev, int * ip)
 {
+  int size = disk->capacity;
   ip[0] = 64;
   ip[1] = 32;
   ip[2] = size >> 11;
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/pas16.h linux/drivers/scsi/pas16.h
--- v1.1.24/linux/drivers/scsi/pas16.h	Fri May 27 10:49:09 1994
+++ linux/drivers/scsi/pas16.h	Thu Jul  7 18:45:08 1994
@@ -115,7 +115,7 @@
 
 #ifndef ASM
 int pas16_abort(Scsi_Cmnd *);
-int pas16_biosparam(int, int, int*);
+int pas16_biosparam(Disk *, int, int*);
 int pas16_detect(int);
 const char *pas16_info(void);
 int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.1.24/linux/drivers/scsi/scsi.c	Mon Jun 27 16:47:01 1994
+++ linux/drivers/scsi/scsi.c	Thu Jul  7 18:45:06 1994
@@ -142,7 +142,6 @@
    {"MAXTOR","XT-4380S","B3C"},   /* Locks-up when LUN>0 polled. */
    {"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */
    {"MAXTOR","XT-4170S","B5A"},   /* Locks-up sometimes when LUN>0 polled. */
-   {"MAXTOR","XT-8760S","B6B"},   /* Locks-up when LUN > 0 is polled */
    {"MAXTOR","XT-8760S","B7B"},   /* guess what? */
    {"NEC","CD-ROM DRIVE:841","1.0"},  /* Locks-up when LUN>0 polled. */
    {"RODIME","RO3000S","2.33"},  /* Locks up if polled for lun != 0 */
@@ -1493,6 +1492,9 @@
 				host->host_busy--;
 				}
 
+#ifdef DEBUG
+			printk("scsi reset function returned %d\n", temp);
+#endif
 			switch(temp) {
 			case SCSI_RESET_SUCCESS:
 			  cli();
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v1.1.24/linux/drivers/scsi/scsi_debug.c	Fri May 27 10:49:10 1994
+++ linux/drivers/scsi/scsi_debug.c	Thu Jul  7 18:45:07 1994
@@ -22,6 +22,8 @@
 #include "scsi.h"
 #include "hosts.h"
 
+#include "sd.h"
+
 /* A few options that we want selected */
 
 /* Do not attempt to use a timer to simulate a real disk with latency */
@@ -541,7 +543,8 @@
     return 0;
 }
 
-int scsi_debug_biosparam(int size, int dev, int* info){
+int scsi_debug_biosparam(Disk * disk, int dev, int* info){
+  int size = disk->capacity;
   info[0] = 32;
   info[1] = 64;
   info[2] = (size + 2047) >> 11;
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h
--- v1.1.24/linux/drivers/scsi/scsi_debug.h	Fri May 27 10:49:10 1994
+++ linux/drivers/scsi/scsi_debug.h	Thu Jul  7 18:45:08 1994
@@ -6,7 +6,7 @@
 int scsi_debug_command(Scsi_Cmnd *);
 int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int scsi_debug_abort(Scsi_Cmnd *, int);
-int scsi_debug_biosparam(int, int, int[]);
+int scsi_debug_biosparam(Disk *, int, int[]);
 const char *scsi_debug_info(void);
 int scsi_debug_reset(Scsi_Cmnd *);
 
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.1.24/linux/drivers/scsi/sd.c	Fri May 27 10:49:11 1994
+++ linux/drivers/scsi/sd.c	Thu Jul  7 18:45:05 1994
@@ -54,6 +54,9 @@
 
 extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
+static int check_scsidisk_media_change(dev_t);
+static int fop_revalidate_scsidisk(dev_t);
+
 static sd_init_onedisk(int);
 
 static void requeue_sd_request (Scsi_Cmnd * SCpnt);
@@ -108,7 +111,10 @@
 	NULL,			/* mmap */
 	sd_open,		/* open code */
 	sd_release,		/* release */
-	block_fsync		/* fsync */
+	block_fsync,		/* fsync */
+	NULL,			/* fasync */
+	check_scsidisk_media_change,  /* Disk change */
+	fop_revalidate_scsidisk     /* revalidate */
 };
 
 static struct gendisk sd_gendisk = {
@@ -733,10 +739,11 @@
 		     MAX_RETRIES);
 }
 
-int check_scsidisk_media_change(int full_dev, int flag){
+static int check_scsidisk_media_change(dev_t full_dev){
         int retval;
 	int target;
 	struct inode inode;
+	int flag = 0;
 
 	target =  DEVICE_NR(MINOR(full_dev));
 
@@ -1089,5 +1096,9 @@
 
 	  DEVICE_BUSY = 0;
 	  return 0;
+}
+
+static int fop_revalidate_scsidisk(dev_t dev){
+  return revalidate_scsidisk(dev, 0);
 }
 
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/sd.h linux/drivers/scsi/sd.h
--- v1.1.24/linux/drivers/scsi/sd.h	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/sd.h	Thu Jul  7 18:45:07 1994
@@ -31,7 +31,7 @@
 
 extern struct hd_struct * sd;
 
-typedef struct {
+typedef struct scsi_disk {
 		unsigned capacity;		/* size in blocks */
 		unsigned sector_size;		/* size in bytes */
 		Scsi_Device  *device;		
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c
--- v1.1.24/linux/drivers/scsi/sd_ioctl.c	Tue Apr 19 10:52:49 1994
+++ linux/drivers/scsi/sd_ioctl.c	Thu Jul  7 18:45:08 1994
@@ -33,7 +33,7 @@
 			diskinfo[1] = 0;
 			diskinfo[2] = 0;
 			if(host->hostt->bios_param != NULL)
-			      host->hostt->bios_param(rscsi_disks[MINOR(dev) >> 4].capacity,
+			      host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4],
 							  dev,
 							  &diskinfo[0]);
 			put_fs_byte(diskinfo[0],
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c
--- v1.1.24/linux/drivers/scsi/seagate.c	Fri May 27 10:49:11 1994
+++ linux/drivers/scsi/seagate.c	Thu Jul  7 18:45:07 1994
@@ -1590,34 +1590,28 @@
 	return SCSI_RESET_PENDING;
 	}
 
-#ifdef CONFIG_BLK_DEV_SD
-
 #include <asm/segment.h>
 #include "sd.h"
 #include "scsi_ioctl.h"
 
-int seagate_st0x_biosparam(int size, int dev, int* ip) {
+int seagate_st0x_biosparam(Disk * disk, int dev, int* ip) {
   unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page;
   int *sizes, result, formatted_sectors, total_sectors;
   int cylinders, heads, sectors;
 
-  Scsi_Device *disk;
-
-  disk = rscsi_disks[MINOR(dev) >> 4].device;
-
 /*
  * Only SCSI-I CCS drives and later implement the necessary mode sense 
  * pages.  
  */
 
-  if (disk->scsi_level < 2) 
+  if (disk->device->scsi_level < 2) 
 	return -1;
 
   sizes = (int *) buf;
   data = (unsigned char *) (sizes + 2);
 
   cmd[0] = MODE_SENSE;
-  cmd[1] = (disk->lun << 5) & 0xe5;
+  cmd[1] = (disk->device->lun << 5) & 0xe5;
   cmd[2] = 0x04; /* Read page 4, rigid disk geometry page current values */
   cmd[3] = 0;
   cmd[4] = 255;
@@ -1633,7 +1627,7 @@
 
   memcpy (data, cmd, 6);
 
-  if (!(result = kernel_scsi_ioctl (disk, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) {
+  if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) {
 /*
  * The mode page lies beyond the MODE SENSE header, with length 4, and 
  * the BLOCK DESCRIPTOR, with length header[3].
@@ -1646,7 +1640,7 @@
     cmd[2] = 0x03; /* Read page 3, format page current values */
     memcpy (data, cmd, 6);
 
-    if (!(result = kernel_scsi_ioctl (disk, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) {
+    if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) {
       page = data + 4 + data[3];
       sectors = (page[10] << 8) | page[11];	
 
@@ -1701,7 +1695,5 @@
     
   return result;
 }
-#endif /* CONFIG_BLK_DEV_SD */
-
 #endif	/* defined(CONFIG_SCSI_SEGATE) */
 
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/seagate.h linux/drivers/scsi/seagate.h
--- v1.1.24/linux/drivers/scsi/seagate.h	Fri May 27 10:49:11 1994
+++ linux/drivers/scsi/seagate.h	Thu Jul  7 18:45:07 1994
@@ -24,11 +24,7 @@
 	#define NULL 0
 #endif
 
-#ifdef CONFIG_BLK_DEV_SD
-int seagate_st0x_biosparam(int, int, int*);
-#else
-#define seagate_st0x_biosparam NULL
-#endif
+int seagate_st0x_biosparam(Disk *, int, int*);
 
 #define SEAGATE_ST0X  {"Seagate ST-01/ST-02", seagate_st0x_detect, 	\
 			 seagate_st0x_info, seagate_st0x_command,  	\
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.1.24/linux/drivers/scsi/sr.c	Fri May 27 10:49:11 1994
+++ linux/drivers/scsi/sr.c	Thu Jul  7 18:45:05 1994
@@ -45,6 +45,7 @@
 extern int sr_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
 void requeue_sr_request (Scsi_Cmnd * SCpnt);
+static int check_cdrom_media_change(dev_t);
 
 static void sr_release(struct inode * inode, struct file * file)
 {
@@ -62,9 +63,12 @@
 	NULL,			/* select */
 	sr_ioctl,		/* ioctl */
 	NULL,			/* mmap */
-	sr_open,       		/* no special open code */
+	sr_open,       		/* special open code */
 	sr_release,		/* release */
-	NULL			/* fsync */
+	NULL,			/* fsync */
+	NULL,			/* fasync */
+	check_cdrom_media_change,  /* Disk change */
+	NULL			/* revalidate */
 };
 
 /*
@@ -77,9 +81,10 @@
  * an inode for that to work, and we do not always have one.
  */
 
-int check_cdrom_media_change(int full_dev, int flag){
+int check_cdrom_media_change(dev_t full_dev){
 	int retval, target;
 	struct inode inode;
+	int flag = 0;
 
 	target =  MINOR(full_dev);
 
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.1.24/linux/drivers/scsi/st.c	Mon May 23 12:14:23 1994
+++ linux/drivers/scsi/st.c	Thu Jul  7 18:45:05 1994
@@ -11,7 +11,7 @@
   Copyright 1992, 1993, 1994 Kai Makisara
 		 email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi
 
-  Last modified: Wed May  4 20:29:42 1994 by root@kai.home
+  Last modified: Wed Jun 22 23:37:10 1994 by root@kai.home
 */
 
 #include <linux/fs.h>
@@ -40,6 +40,8 @@
 
 /* #define ST_RECOVERED_WRITE_FATAL */
 
+#define ST_TWO_FM 0
+
 #define ST_BUFFER_WRITES 1
 
 #define ST_ASYNC_WRITES 1
@@ -71,7 +73,7 @@
 #define MAX_READY_RETRIES 5
 #define NO_TAPE  NOT_READY
 
-#define ST_TIMEOUT 9000
+#define ST_TIMEOUT 27000
 #define ST_LONG_TIMEOUT 200000
 
 static int st_nbr_buffers;
@@ -237,6 +239,11 @@
 
   if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
   SCpnt->request.dev = -1;
+  if ((STp->buffer)->last_result != 0) {
+    printk("st%d: Backing over filemark failed.\n", dev);
+    (STp->mt_status)->mt_fileno += 1;
+    (STp->mt_status)->mt_blkno = 0;
+  }
 
   return (STp->buffer)->last_result_fatal;
 }
@@ -551,7 +558,8 @@
 	     (STp->buffer)->buffer_blocks);
 #endif
 
-    if ((STp->buffer)->b_data[2] & 0x80) {
+    STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
+    if (STp->drv_write_prot) {
       STp->write_prot = 1;
 #ifdef DEBUG
       if (debugging)
@@ -594,7 +602,7 @@
 	SCpnt->sense_buffer[0] = 0;
 	memset(cmd, 0, 10);
 	cmd[0] = WRITE_FILEMARKS;
-	cmd[4] = 1;
+	cmd[4] = 1 + STp->two_fm;
 	SCpnt->request.dev = dev;
 	scsi_do_cmd( SCpnt,
 		    (void *) cmd, (void *) (STp->buffer)->b_data,
@@ -602,19 +610,23 @@
 
 	if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) );
 
-	if ((STp->buffer)->last_result_fatal != 0)
+	if ((STp->buffer)->last_result_fatal != 0) {
+	  SCpnt->request.dev = -1;  /* Mark as not busy */
 	  printk("st%d: Error on write filemark.\n", dev);
+	}
 	else {
+	  SCpnt->request.dev = -1;  /* Mark as not busy */
           (STp->mt_status)->mt_fileno++ ;
 	  STp->drv_block = 0;
+	  if (STp->two_fm)
+	    back_over_eof(dev);
 	}
 
-	SCpnt->request.dev = -1;  /* Mark as not busy */
       }
 
 #ifdef DEBUG
       if (debugging)
-	printk("st%d: Buffer flushed, EOF written\n", dev);
+	printk("st%d: Buffer flushed, %d EOF(s) written\n", dev, cmd[4]);
 #endif
     }
     else if (!rewind) {
@@ -670,6 +682,9 @@
       STp->rw = ST_WRITING;
     }
 
+    if (STp->moves_after_eof < 255)
+      STp->moves_after_eof++;
+
     if ((STp->buffer)->writing) {
       write_behind_check(dev);
       if ((STp->buffer)->last_result_fatal) {
@@ -896,6 +911,8 @@
 	return transfer;
       STp->rw = ST_READING;
     }
+    if (STp->moves_after_eof < 255)
+      STp->moves_after_eof++;
 
 #ifdef DEBUG
     if (debugging && STp->eof != ST_NOEOF)
@@ -1010,8 +1027,8 @@
 		    "st%d: EOF detected (%d bytes read, transferred %d bytes).\n",
 			 dev, (STp->buffer)->buffer_bytes, total);
 #endif
-	      } /* end of EOF, EOM, ILI test */
-	    }
+	      }
+	    } /* end of EOF, EOM, ILI test */
 	    else { /* nonzero sense key */
 #ifdef DEBUG
 	      if (debugging)
@@ -1021,16 +1038,25 @@
 	      STp->drv_block = (-1);
 	      if (total)
 		return total;
+	      else if (STp->moves_after_eof == 1 &&
+		       (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
+#ifdef DEBUG
+		if (debugging)
+		  printk("st%d: Zero returned for first BLANK CHECK after EOF.\n",
+			 dev);
+#endif
+		return 0; /* First BLANK_CHECK after EOF */
+	      }
 	      else
 		return -EIO;
 	    }
-	  }
+	  } /* End of extended sense test */
 	  else {
 	    transfer = (STp->buffer)->last_result_fatal;
 	    SCpnt->request.dev = -1;  /* Mark as not busy */
 	    return transfer;
 	  }
-	}
+	} /* End of error handling */
 	else /* Read successful */
 	  (STp->buffer)->buffer_bytes = bytes;
 
@@ -1066,6 +1092,8 @@
 	if (total == 0 && STp->eof == ST_FM) {
 	  STp->eof = 0;
 	  STp->drv_block = 0;
+	  if (STp->moves_after_eof > 1)
+	    STp->moves_after_eof = 0;
 	  (STp->mt_status)->mt_fileno++;
 	}
 	if (total == 0 && STp->eof == ST_EOM_OK)
@@ -1098,13 +1126,15 @@
     STp->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
     STp->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
     STp->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
+    STp->two_fm		  = (options & MT_ST_TWO_FM) != 0;
 #ifdef DEBUG
     debugging = (options & MT_ST_DEBUGGING) != 0;
     printk(
 "st%d: options: buffer writes: %d, async writes: %d, read ahead: %d\n",
 	   dev, STp->do_buffer_writes, STp->do_async_writes,
 	   STp->do_read_ahead);
-    printk("              debugging: %d\n", debugging);
+    printk("              two FMs: %d, debugging: %d\n", STp->two_fm,
+	   debugging);
 #endif
   }
   else if ((options & MT_ST_OPTIONS) == MT_ST_WRITE_THRESHOLD) {
@@ -1397,8 +1427,16 @@
    SCpnt->request.dev = -1;  /* Mark as not busy */
 
    if (!ioctl_result) {
-     STp->drv_block = blkno;
-     (STp->mt_status)->mt_fileno = fileno;
+     if (cmd_in != MTSEEK) {
+       STp->drv_block = blkno;
+       (STp->mt_status)->mt_fileno = fileno;
+     }
+     else
+       STp->drv_block = (STp->mt_status)->mt_fileno = (-1);
+     if (cmd_in == MTFSF)
+       STp->moves_after_eof = 0;
+     else
+       STp->moves_after_eof = 1;
      if (cmd_in == MTBSFM)
        ioctl_result = st_int_ioctl(inode, file, MTFSF, 1);
      else if (cmd_in == MTFSFM)
@@ -1419,10 +1457,10 @@
 	 (STp->buffer)->read_pointer = 0;
      }
      else if (cmd_in == MTSETDRVBUFFER)
-       STp->drv_buffer = arg;
+       STp->drv_buffer = (arg & 7);
      else if (cmd_in == MTSETDENSITY)
        STp->density = arg;
-     else if (cmd_in == MTEOM || cmd_in == MTWEOF) {
+     else if (cmd_in == MTEOM) {
        STp->eof = ST_EOM_OK;
        STp->eof_hit = 0;
      }
@@ -1498,7 +1536,7 @@
 
      memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop));
 
-     i = flush_buffer(inode, file, mtc.mt_op == MTSEEK ||
+     i = flush_buffer(inode, file, mtc.mt_op == MTNOP || mtc.mt_op == MTSEEK ||
 		      mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
 		      mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM);
      if (i < 0)
@@ -1530,6 +1568,9 @@
 	 (STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes +
 	   STp->block_size - 1) / STp->block_size;
      }
+     (STp->mt_status)->mt_gstat = 0;
+     if (STp->drv_write_prot)
+       (STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff);
 
      memcpy_tofs((char *)arg, (char *)(STp->mt_status),
 		 sizeof(struct mtget));
@@ -1677,8 +1718,10 @@
     STp->do_buffer_writes = ST_BUFFER_WRITES;
     STp->do_async_writes = ST_ASYNC_WRITES;
     STp->do_read_ahead = ST_READ_AHEAD;
+    STp->two_fm = ST_TWO_FM;
     STp->write_threshold = st_write_threshold;
     STp->drv_block = 0;
+    STp->moves_after_eof = 1;
     STp->mt_status = (struct mtget *) mem_start;
     mem_start += sizeof(struct mtget);
     /* Initialize status */
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v1.1.24/linux/drivers/scsi/st.h	Mon May 23 12:14:23 1994
+++ linux/drivers/scsi/st.h	Thu Jul  7 18:45:05 1994
@@ -25,16 +25,18 @@
   unsigned capacity;
   struct wait_queue * waiting;
   Scsi_Device* device;
-  unsigned dirty:1;
-  unsigned rw:2;
-  unsigned eof:2;
-  unsigned write_prot:1;
-  unsigned in_use:1;
-  unsigned eof_hit:1;
-  unsigned drv_buffer:3;
-  unsigned do_buffer_writes:1;
-  unsigned do_async_writes:1;
-  unsigned do_read_ahead:1;
+  unsigned char dirty;
+  unsigned char rw;
+  unsigned char eof;
+  unsigned char write_prot;
+  unsigned char drv_write_prot;
+  unsigned char in_use;
+  unsigned char eof_hit;
+  unsigned char drv_buffer;
+  unsigned char do_buffer_writes;
+  unsigned char do_async_writes;
+  unsigned char do_read_ahead;
+  unsigned char two_fm;
   unsigned char density;
   ST_buffer * buffer;
   int block_size;
@@ -43,6 +45,7 @@
   int write_threshold;
   int recover_count;
   int drv_block;	/* The block where the drive head is */
+  unsigned char moves_after_eof;
   struct mtget * mt_status;
   Scsi_Cmnd SCpnt;
 } Scsi_Tape;
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c
--- v1.1.24/linux/drivers/scsi/t128.c	Wed Dec  1 14:44:16 1993
+++ linux/drivers/scsi/t128.c	Thu Jul  7 18:45:07 1994
@@ -116,10 +116,10 @@
 #define AUTOPROBE_IRQ
 #include "NCR5380.h"
 #include "constants.h"
+#include "sd.h"
 
 
 
-
 static struct override {
     unsigned char *address;
     int irq;
@@ -273,7 +273,7 @@
 }
 
 /*
- * Function : int t128_biosparam(int size, int dev, int *ip)
+ * Function : int t128_biosparam(Disk * disk, int dev, int *ip)
  *
  * Purpose : Generates a BIOS / DOS compatable H-C-S mapping for 
  *	the specified device / size.
@@ -292,8 +292,9 @@
  * and matching the H_C_S coordinates to what DOS uses.
  */
 
-int t128_biosparam(int size, int dev, int * ip)
+int t128_biosparam(Disk * disk, int dev, int * ip)
 {
+  int size = disk->capacity;
   ip[0] = 64;
   ip[1] = 32;
   ip[2] = size >> 11;
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/t128.h linux/drivers/scsi/t128.h
--- v1.1.24/linux/drivers/scsi/t128.h	Fri May 27 10:49:11 1994
+++ linux/drivers/scsi/t128.h	Thu Jul  7 18:45:08 1994
@@ -92,7 +92,7 @@
 
 #ifndef ASM
 int t128_abort(Scsi_Cmnd *);
-int t128_biosparam(int, int, int*);
+int t128_biosparam(Disk *, int, int*);
 int t128_detect(int);
 const char *t128_info(void);
 int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c
--- v1.1.24/linux/drivers/scsi/ultrastor.c	Tue Jun 21 14:16:23 1994
+++ linux/drivers/scsi/ultrastor.c	Thu Jul  7 18:45:07 1994
@@ -140,6 +140,7 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "ultrastor.h"
+#include "sd.h"
 
 #define FALSE 0
 #define TRUE 1
@@ -996,8 +997,9 @@
 
 }
 
-int ultrastor_biosparam(int size, int dev, int * dkinfo)
+int ultrastor_biosparam(Disk * disk, int dev, int * dkinfo)
 {
+    int size = disk->capacity;
     unsigned int s = config.heads * config.sectors;
 
     dkinfo[0] = config.heads;
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/ultrastor.h linux/drivers/scsi/ultrastor.h
--- v1.1.24/linux/drivers/scsi/ultrastor.h	Tue Jun 21 14:16:23 1994
+++ linux/drivers/scsi/ultrastor.h	Thu Jul  7 18:45:08 1994
@@ -18,7 +18,7 @@
 int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 int ultrastor_abort(Scsi_Cmnd *);
 int ultrastor_reset(Scsi_Cmnd *);
-int ultrastor_biosparam(int, int, int *);
+int ultrastor_biosparam(Disk *, int, int *);
 
 #define ULTRASTOR_14F_MAX_SG 16
 #define ULTRASTOR_24F_MAX_SG 33
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c
--- v1.1.24/linux/drivers/scsi/wd7000.c	Fri Jun 17 15:20:07 1994
+++ linux/drivers/scsi/wd7000.c	Thu Jul  7 18:45:07 1994
@@ -115,6 +115,7 @@
 #include "../block/blk.h"
 #include "scsi.h"
 #include "hosts.h"
+#include "sd.h"
 
 #define ANY2SCSI_INLINE    /* undef this to use old macros */
 #undef DEBUG
@@ -1225,8 +1226,9 @@
  *  this way, so I think it will work OK.  Someone who is ambitious can
  *  borrow a newer or more complete version from another driver.
  */
-int wd7000_biosparam(int size, int dev, int* ip)
+int wd7000_biosparam(Disk * disk, int dev, int* ip)
 {
+  int size = disk->capacity;
   ip[0] = 64;
   ip[1] = 32;
   ip[2] = size >> 11;
diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/wd7000.h linux/drivers/scsi/wd7000.h
--- v1.1.24/linux/drivers/scsi/wd7000.h	Fri May 27 10:49:12 1994
+++ linux/drivers/scsi/wd7000.h	Thu Jul  7 18:45:08 1994
@@ -18,7 +18,7 @@
 int wd7000_abort(Scsi_Cmnd *);
 const char *wd7000_info(void);
 int wd7000_reset(Scsi_Cmnd *);
-int wd7000_biosparam(int, int, int*);
+int wd7000_biosparam(Disk *, int, int*);
 
 #ifndef NULL
 #define NULL 0L
diff -u --recursive --new-file v1.1.24/linux/fs/buffer.c linux/fs/buffer.c
--- v1.1.24/linux/fs/buffer.c	Thu Jul  7 21:37:12 1994
+++ linux/fs/buffer.c	Thu Jul  7 18:45:04 1994
@@ -479,7 +479,7 @@
 			
 			wait_on_buffer(bh);
 			if (bh->b_dev == dev && bh->b_size != size) {
-				bh->b_uptodate = bh->b_dirt = 
+				bh->b_uptodate = bh->b_dirt = bh->b_req =
 					 bh->b_flushtime = 0;
 			};
 			remove_from_hash_queue(bh);
diff -u --recursive --new-file v1.1.24/linux/fs/devices.c linux/fs/devices.c
--- v1.1.24/linux/fs/devices.c	Thu Jul  7 21:37:12 1994
+++ linux/fs/devices.c	Thu Jul  7 18:47:46 1994
@@ -15,22 +15,12 @@
 #include <linux/fcntl.h>
 #include <linux/errno.h>
 
+#include <linux/config.h>
+
 /*
  * Ugly. We'll fix this once all the drivers use the f_ops->check_media_change()
  * stuff instead..
  */
-#ifdef CONFIG_SCSI
-#ifdef CONFIG_BLK_DEV_SR
-extern int check_cdrom_media_change(int, int);
-#endif
-#ifdef CONFIG_BLK_DEV_SD
-extern int check_scsidisk_media_change(int, int);
-extern int revalidate_scsidisk(int, int);
-#endif
-#endif
-#ifdef CONFIG_CDU31A
-extern int check_cdu31a_media_change(int, int);
-#endif
 #ifdef CONFIG_MCD
 extern int check_mcd_media_change(int, int);
 #endif
@@ -142,57 +132,37 @@
  * People changing diskettes in the middle of an operation deserve
  * to loose :-)
  */
-void check_disk_change(dev_t dev)
+int check_disk_change(dev_t dev)
 {
 	int i;
 	struct file_operations * fops;
 
 	i = MAJOR(dev);
 	if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL)
-		return;
+		return 0;
 	if (fops->check_media_change != NULL) {
 		if (!fops->check_media_change(dev))
-			return;
+			return 0;
 	} 
 #if 1 /* this will go soon.. */
 	else switch(MAJOR(dev)){
-#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
-         case SCSI_DISK_MAJOR:
-		if (!check_scsidisk_media_change(dev, 0))
-			return;
-		break;
-#endif
-
-#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
-	 case SCSI_CDROM_MAJOR:
-		if (!check_cdrom_media_change(dev, 0))
-			return;
-		break;
-#endif
-
-#if defined(CONFIG_CDU31A)
-         case CDU31A_CDROM_MAJOR:
-		if (!check_cdu31a_media_change(dev, 0))
-			return;
-		break;
-#endif
 
 #if defined(CONFIG_MCD)
          case MITSUMI_CDROM_MAJOR:
 		if (!check_mcd_media_change(dev, 0))
-			return;
+			return 0;
 		break;
 #endif
 
 #if defined(CONFIG_SBPCD)
          case MATSUSHITA_CDROM_MAJOR:
 		if (!check_sbpcd_media_change(dev, 0))
-			return;
+			return 0;
 		break;
 #endif
 
          default:
-		return;
+		return 0;
 	}
 #endif	/* will go away */
 
@@ -206,13 +176,7 @@
 
 	if (fops->revalidate)
 		fops->revalidate(dev);
-
-#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI)
-/* This is trickier for a removable hardisk, because we have to invalidate
-   all of the partitions that lie on the disk. */
-	if (MAJOR(dev) == SCSI_DISK_MAJOR)
-		revalidate_scsidisk(dev, 0);
-#endif
+	return 1;
 }
 
 /*
diff -u --recursive --new-file v1.1.24/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v1.1.24/linux/fs/isofs/inode.c	Tue Jun 21 14:16:23 1994
+++ linux/fs/isofs/inode.c	Thu Jul  7 18:45:04 1994
@@ -305,35 +305,8 @@
 		printk("get root inode failed\n");
 		return NULL;
 	}
-#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI)
-	if (MAJOR(s->s_dev) == SCSI_CDROM_MAJOR) {
-		/* Check this one more time. */
-		if(check_cdrom_media_change(s->s_dev, 0))
-		  goto out;
-	}
-#endif
-#if defined(CONFIG_CDU31A)
-	if (MAJOR(s->s_dev) == CDU31A_CDROM_MAJOR) {
-		/* Check this one more time. */
-		if(check_cdu31a_media_change(s->s_dev, 0))
-		  goto out;
-	}
-#endif
-#if defined(CONFIG_MCD)
-	if (MAJOR(s->s_dev) == MITSUMI_CDROM_MAJOR) {
-		/* Check this one more time. */
-		if(check_mcd_media_change(s->s_dev, 0))
-		  goto out;
-	}
-#endif
-#if defined(CONFIG_SBPCD)
-	if (MAJOR(s->s_dev) == MATSUSHITA_CDROM_MAJOR) {
-		if (check_sbpcd_media_change(s->s_dev,0))
-		  goto out;
-	};
-#endif CONFIG_SBPCD
 
-	return s;
+	if(!check_disk_change(s->s_dev)) return s;
  out: /* Kick out for various error conditions */
 	brelse(bh);
 	s->s_dev = 0;
diff -u --recursive --new-file v1.1.24/linux/fs/locks.c linux/fs/locks.c
--- v1.1.24/linux/fs/locks.c	Sat May  7 14:54:07 1994
+++ linux/fs/locks.c	Thu Jul  7 15:08:56 1994
@@ -200,8 +200,6 @@
 
 	if (!filp->f_inode)	/* just in case */
 		return 0;
-	if (!S_ISREG(filp->f_inode->i_mode))
-		return 0;
 	if (l->l_type != F_UNLCK && l->l_type != F_RDLCK && l->l_type != F_WRLCK
 	 && l->l_type != F_SHLCK && l->l_type != F_EXLCK)
 		return 0;
@@ -378,7 +376,7 @@
 
 	if (! added) {
 		if (caller->fl_type == F_UNLCK)
-			return -EINVAL;
+			return 0;
 		if (! (caller = alloc_lock(before, caller, fd)))
 			return -ENOLCK;
 	}
diff -u --recursive --new-file v1.1.24/linux/fs/nfs/sock.c linux/fs/nfs/sock.c
--- v1.1.24/linux/fs/nfs/sock.c	Tue Mar  1 08:03:41 1994
+++ linux/fs/nfs/sock.c	Thu Jul  7 18:28:55 1994
@@ -4,6 +4,13 @@
  *  Copyright (C) 1992, 1993  Rick Sladkey
  *
  *  low-level nfs remote procedure call interface
+ *
+ * FIXES
+ *
+ * 2/7/94 James Bottomley and Jon Peatfield DAMTP, Cambridge University
+ *
+ * An xid mismatch no longer causes the request to be trashed.
+ *
  */
 
 #include <linux/config.h>
@@ -15,8 +22,14 @@
 #include <asm/segment.h>
 #include <linux/in.h>
 #include <linux/net.h>
+#include <linux/mm.h>
 
+/* JEJB/JSP 2/7/94
+ * this must match the value of NFS_SLACK_SPACE in linux/fs/nfs/proc.c 
+ * ***FIXME*** should probably put this in nfs_fs.h */
+#define NFS_SLACK_SPACE 1024
 
+
 extern struct socket *socki_lookup(struct inode *inode);
 
 #define _S(nr) (1<<((nr)-1))
@@ -51,6 +64,9 @@
 	int n;
 	int addrlen;
 	unsigned long old_mask;
+	/* JEJB/JSP 2/7/94
+	 * This is for a 4 byte recv of the xid only */
+	int recv_xid;
 
 	xid = start[0];
 	len = ((char *) end) - ((char *) start);
@@ -92,8 +108,14 @@
 		current->state = TASK_INTERRUPTIBLE;
 		if (!select(inode, file, SEL_IN, &wait_table)
 		    && !select(inode, file, SEL_IN, NULL)) {
-			if (timeout > max_timeout)
-				timeout = max_timeout;
+			if (timeout > max_timeout) {
+			  /* JEJB/JSP 2/7/94
+			   * This is useful to see if the system is
+			   * hanging */
+			  printk("NFS max timeout reached on %s\n",
+				 server_name);
+			  timeout = max_timeout;
+			}
 			current->timeout = jiffies + timeout;
 			schedule();
 			remove_wait_queue(entry.wait_address, &entry.wait);
@@ -116,8 +138,8 @@
 				timeout = init_timeout;
 				init_timeout <<= 1;
 				if (!major_timeout_seen) {
-					printk("NFS server %s not responding, "
-						"still trying\n", server_name);
+				  printk("NFS server %s not responding, "
+					 "still trying\n", server_name);
 				}
 				major_timeout_seen = 1;
 				continue;
@@ -129,8 +151,13 @@
 			remove_wait_queue(entry.wait_address, &entry.wait);
 		current->state = TASK_RUNNING;
 		addrlen = 0;
-		result = sock->ops->recvfrom(sock, (void *) start, PAGE_SIZE, 1, 0,
-			NULL, &addrlen);
+		/* JEJB/JSP 2/7/94
+		 * Get the xid from the next packet using a peek, so keep it
+		 * on the recv queue.  If it is wrong, it will be some reply
+		 * we don't now need, so discard it */
+		result = sock->ops->recvfrom(sock, (void *)&recv_xid,
+					     sizeof(recv_xid), 1, MSG_PEEK,
+					     NULL, &addrlen);
 		if (result < 0) {
 			if (result == -EAGAIN) {
 #if 0
@@ -150,15 +177,41 @@
 			}
 			break;
 		}
-		if (*start == xid) {
+		if (recv_xid == xid) {
 			if (major_timeout_seen)
 				printk("NFS server %s OK\n", server_name);
 			break;
 		}
+		/* JEJB/JSP 2/7/94
+		 * we have xid mismatch, so discard the packet and start
+		 * again.  What a hack! but I can't call recvfrom with
+		 * a null buffer yet. */
+		(void)sock->ops->recvfrom(sock, (void *)&recv_xid,
+					  sizeof(recv_xid), 1, 0, NULL,
+					  &addrlen);
 #if 0
 		printk("nfs_rpc_call: XID mismatch\n");
 #endif
 	}
+	/* JEJB/JSP 2/7/94
+	 *
+	 * we have the correct xid, so read into the correct place and
+	 * return it
+	 *
+	 * Here we need to know the size given to alloc, server->wsize for
+	 * writes or server->rsize for reads.  In practice these are the
+	 * same. 
+	 *
+	 * If they are not the same then a reply to a write request will be
+	 * a small acknowledgement, so even if wsize < rsize we should never
+	 * cause data to be written past the end of the buffer (unless some
+	 * brain damaged implementation sends out a large write acknowledge).
+	 *
+	 * FIXME:  I should really know how big a packet was alloc'd --
+	 *         should pass it to do_nfs_rpc. */
+	result=sock->ops->recvfrom(sock, (void *)start, 
+				  server->rsize + NFS_SLACK_SPACE, 1, 0, NULL,
+				  &addrlen);
 	current->blocked = old_mask;
 	set_fs(fs);
 	return result;
diff -u --recursive --new-file v1.1.24/linux/fs/open.c linux/fs/open.c
--- v1.1.24/linux/fs/open.c	Tue May 24 00:34:53 1994
+++ linux/fs/open.c	Thu Jul  7 15:08:57 1994
@@ -448,7 +448,7 @@
 		return 0;
 	}
 	inode = filp->f_inode;
-	if (inode && S_ISREG(inode->i_mode))
+	if (inode)
 		fcntl_remove_locks(current, filp, fd);
 	if (filp->f_count > 1) {
 		filp->f_count--;
diff -u --recursive --new-file v1.1.24/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.1.24/linux/include/linux/fs.h	Thu Jul  7 21:37:13 1994
+++ linux/include/linux/fs.h	Thu Jul  7 18:45:04 1994
@@ -413,7 +413,7 @@
 }
 
 
-extern void check_disk_change(dev_t dev);
+extern int check_disk_change(dev_t dev);
 extern void invalidate_inodes(dev_t dev);
 extern void invalidate_buffers(dev_t dev);
 extern void sync_inodes(dev_t dev);
diff -u --recursive --new-file v1.1.24/linux/include/linux/mcd.h linux/include/linux/mcd.h
--- v1.1.24/linux/include/linux/mcd.h	Thu Jul  7 21:37:13 1994
+++ linux/include/linux/mcd.h	Thu Jul  7 21:26:55 1994
@@ -28,7 +28,7 @@
 #define MCD_INTR_NR		10
 
 /* Increase this if you get lots of timeouts */
-#define MCD_STATUS_DELAY	100
+#define MCD_STATUS_DELAY	200
 
 /* number of times to retry a command before giving up */
 #define MCD_RETRY_ATTEMPTS      5
diff -u --recursive --new-file v1.1.24/linux/include/linux/mtio.h linux/include/linux/mtio.h
--- v1.1.24/linux/include/linux/mtio.h	Wed Jun 22 14:57:10 1994
+++ linux/include/linux/mtio.h	Thu Jul  7 18:45:05 1994
@@ -203,6 +203,7 @@
 #define MT_ST_ASYNC_WRITES	0x2
 #define MT_ST_READ_AHEAD	0x4
 #define MT_ST_DEBUGGING		0x8
+#define MT_ST_TWO_FM		0x10
 
 #endif /* _LINUX_MTIO_H */
 
diff -u --recursive --new-file v1.1.24/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.24/linux/kernel/ksyms.c	Tue Jun 28 22:30:28 1994
+++ linux/kernel/ksyms.c	Thu Jul  7 19:32:15 1994
@@ -17,6 +17,7 @@
 #include <linux/sys.h>
 #include <linux/utsname.h>
 #include <linux/interrupt.h>
+#include <linux/timer.h>
 #include <linux/binfmts.h>
 #include <linux/personality.h>
 #include <linux/module.h>
@@ -122,6 +123,8 @@
 	X(disable_irq),
 	X(bh_active),
 	X(bh_mask),
+	X(add_timer),
+	X(del_timer),
 
 	/* dma handling */
 	X(request_dma),
@@ -136,6 +139,7 @@
 	X(xtime),
 
 	/* misc */
+	X(panic),
 	X(printk),
 	X(sprintf),
 	X(vsprintf),
diff -u --recursive --new-file v1.1.24/linux/net/inet/af_inet.c linux/net/inet/af_inet.c
--- v1.1.24/linux/net/inet/af_inet.c	Mon Jun 27 16:47:02 1994
+++ linux/net/inet/af_inet.c	Thu Jul  7 18:29:06 1994
@@ -12,6 +12,10 @@
  *		Florian La Roche, <flla@stud.uni-sb.de>
  *		Alan Cox, <A.Cox@swansea.ac.uk>
  *
+ * Changes (see also sock.c)
+ *
+ *		A.N.Kuznetsov	:	Socket death error in accept().
+ *
  *		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
@@ -975,6 +979,7 @@
 	{
 		err = -sk2->err;
 		sk2->err=0;
+		sk2->dead=1;	/* ANK */
 		destroy_sock(sk2);
 		newsock->data = NULL;
 		return(err);
diff -u --recursive --new-file v1.1.24/linux/net/inet/icmp.c linux/net/inet/icmp.c
--- v1.1.24/linux/net/inet/icmp.c	Mon Jun 27 16:47:02 1994
+++ linux/net/inet/icmp.c	Thu Jul  7 18:31:00 1994
@@ -370,7 +370,7 @@
 	skb2->free = 1;
 
 	/* Build Layer 2-3 headers for message back to source */
-	offset = ip_build_header(skb2, daddr, saddr, &ndev,
+	offset = ip_build_header(skb2, daddr, dev->pa_addr, &ndev,
 	 	IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255);
 	if (offset < 0) 
 	{
@@ -586,12 +586,6 @@
 	
 	icmp_statistics.IcmpInMsgs++;
 	 
-	if (ip_chk_addr(daddr) == IS_BROADCAST) 
-	{
-		icmp_statistics.IcmpInErrors++;
-		kfree_skb(skb1, FREE_READ);
-		return(0);
-  	}
   	
   	/*
   	 *	Grab the packet as an icmp object
@@ -616,6 +610,13 @@
 	/*
 	 *	Parse the ICMP message 
 	 */
+
+	if (ip_chk_addr(daddr) == IS_BROADCAST && icmph->type != ICMP_ECHO) 
+	{
+		icmp_statistics.IcmpInErrors++;
+		kfree_skb(skb1, FREE_READ);
+		return(0);
+  	}
 
 	switch(icmph->type) 
 	{
