diff -u --recursive --new-file v1.1.60/linux/CREDITS linux/CREDITS
--- v1.1.60/linux/CREDITS	Wed Nov  2 12:03:44 1994
+++ linux/CREDITS	Tue Nov  1 19:50:44 1994
@@ -64,7 +64,7 @@
 S: The Netherlands
 
 N: Hennus Bergman
-E: hennus@sky.nl.mugnet.org [My uucp-fed Linux box at home]
+E: hennus@sky.ow.org [My uucp-fed Linux box at home]
 D: Author and maintainer of the QIC-02 tape driver
 S: The Netherlands
 
diff -u --recursive --new-file v1.1.60/linux/Makefile linux/Makefile
--- v1.1.60/linux/Makefile	Wed Nov  2 12:03:44 1994
+++ linux/Makefile	Tue Nov  1 19:50:44 1994
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 60
+SUBLEVEL = 61
 
 ARCH = i386
 
diff -u --recursive --new-file v1.1.60/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd
--- v1.1.60/linux/drivers/block/README.sbpcd	Tue Aug 30 08:16:13 1994
+++ linux/drivers/block/README.sbpcd	Wed Nov  2 11:51:13 1994
@@ -1,4 +1,4 @@
-This README belongs to release 2.6 or newer of the SoundBlaster Pro
+This README belongs to release 2.7 or newer of the SoundBlaster Pro
 (Matsushita, Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux.
 
 The driver is able to drive the whole family of "traditional" IDE-style (that
@@ -6,6 +6,14 @@
 Kotobuki, Panasonic drives, sometimes labelled as "CreativeLabs". The
 well-known drives are CR-521, CR-522, CR-523, CR-562, CR-563.
 
+There exists an "IBM External ISA CD-ROM Drive" which in fact is a CR-562
+with a special controller board. This drive is supported (the interface is
+of the "LaserMate" type), and it is possibly the best buy today (cheaper than
+an internal drive, and you can use it as an internal, too - f.e. plug it into
+a soundcard). If you own such a drive, please mail me the DOS driver (gzipped
+and uuencoded) and the specifications (exact name, address range etc.) I still
+have to confirm my opinion. ;-)
+
 This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives.
 The matter that some other brand's drives work with newer sound card
 interfaces does NOT make the drives compatible. :-)
@@ -49,8 +57,8 @@
 
 To use more than 4 drives (now that the single-speed CR-521's are as cheap as
 50$), you need a second interface card and you have to "duplicate" the driver.
-Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE
-accordingly.
+Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE (at top
+of sbpcd2.c) accordingly.
 
 The driver supports reading of data from the CD and playing of audio tracks.
 The audio part should run with WorkMan, xcdplayer, with the "non-X11" products
@@ -72,9 +80,10 @@
 The software interface possibly may change a bit the day the SCSI driver
 supports it too.
 
-MultiSession is supported, "ManySession" (not recommended, see below)
-alternatively.
-Photo CDs work, too (even with my "old" CR-521).
+With the CR-562 and CR-563 drives, MultiSession is supported, "ManySession"
+(not recommended, see below) alternatively.
+Photo CDs work, too (the "old" drives like CR-521 can access only the first
+session of a photoCD).
 At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's package to convert
 photo CD image files.
 
@@ -188,6 +197,57 @@
 distribution) which MUST get handled with a block_size of 1024. Generally,
 one can say all the CDs which hold files of the name YMTRANS.TBL are defective;
 do not use block=2048 with those.
+
+At the beginning of sbpcd.c, you will find some "#define"s (f.e. EJECT and
+JUKEBOX). With that, you can configure the driver for some special things.
+The following program disables the auto-eject feature during runtime:
+
+/*=================== begin program ========================================*/
+/*
+ * set the "eject" switch (enable/disable auto-ejecting)
+ *
+ * (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
+ *          may be used & enhanced freely
+ *
+ * Disables or enables the auto-eject feature at run time.
+ * Works only if a CD is in the drive (just like the feature itself ;-) 
+ * Useful for a "quiet" shutdown or for weird audio player programs.
+ */
+#define EJECT 0 /* 0: disable, 1: enable auto-ejecting */
+
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+
+static char arg=EJECT;
+static int drive;
+static int err;
+
+main(int argc, char *argv[])
+{
+/*
+ * open /dev/cdrom
+ */
+  drive=open("/dev/cdrom", 0);
+  if (drive<0)
+    {
+      fprintf(stderr, "can't open drive /dev/cdrom.\n");
+      exit (-1);
+    }
+/*
+ * set EJECT_SW
+ */
+  err=ioctl(drive, CDROMEJECT_SW, arg);
+  if (err!=0)
+    {
+      fprintf(stderr, "can't set EJECT_SW (error %d).\n", err);
+      exit (-1);
+    }
+  else
+    fprintf(stdout, "EJECT_SW set to %d\n", arg);
+}
+/*===================== end program ========================================*/
+
 
 
 Auto-probing at boot time:
diff -u --recursive --new-file v1.1.60/linux/drivers/block/cdu31a.c linux/drivers/block/cdu31a.c
--- v1.1.60/linux/drivers/block/cdu31a.c	Wed Nov  2 12:03:45 1994
+++ linux/drivers/block/cdu31a.c	Tue Nov  1 19:50:44 1994
@@ -2856,8 +2856,8 @@
       {
 	 if (request_irq(irq_used, cdu31a_interrupt, SA_INTERRUPT, "cdu31a"))
 	 {
-	    irq_used = 0;
 	    printk("Unable to grab IRQ%d for the CDU31A driver\n", irq_used);
+	    irq_used = 0;
 	 }
       }
       
diff -u --recursive --new-file v1.1.60/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.1.60/linux/drivers/block/floppy.c	Sun Oct 23 13:04:29 1994
+++ linux/drivers/block/floppy.c	Wed Nov  2 13:19:42 1994
@@ -348,6 +348,7 @@
 struct floppy_struct user_params[N_DRIVE];
 
 static int floppy_sizes[256];
+static int floppy_blocksizes[256] = { 0, };
 
 /*
  * The driver is trying to determine the correct media format
@@ -2848,7 +2849,7 @@
 	if (floppy_grab_irq_and_dma())
 		return -EBUSY;
 
-	if(filp->f_flags & O_EXCL)
+	if (filp->f_flags & O_EXCL)
 		UDRS->fd_ref = -1;
 	else
 		UDRS->fd_ref++;
@@ -2956,7 +2957,10 @@
 			UDRS->generation++;
 			if(!current_type[drive] && !TYPE(dev)){
 				/* auto-sensing */
-				if (!(bh = getblk(dev,0,1024))){
+				int size = floppy_blocksizes[MINOR(dev)];
+				if (!size)
+					size = 1024;
+				if (!(bh = getblk(dev,0,size))){
 					redo_fd_request();
 					return 1;
 				}
@@ -3062,6 +3066,7 @@
 			floppy_sizes[i] = MAX_DISK_SIZE;
 
 	blk_size[MAJOR_NR] = floppy_sizes;
+	blksize_size[MAJOR_NR] = floppy_blocksizes;
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 	timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
 	timer_active &= ~(1 << FLOPPY_TIMER);
diff -u --recursive --new-file v1.1.60/linux/drivers/block/mcd.c linux/drivers/block/mcd.c
--- v1.1.60/linux/drivers/block/mcd.c	Wed Aug 10 20:06:59 1994
+++ linux/drivers/block/mcd.c	Tue Nov  1 19:50:44 1994
@@ -1182,7 +1182,6 @@
 
 	mcd_invalidate_buffers();
 	mcdPresent = 1;
-	printk("\n");
 	return mem_start;
 }
 
diff -u --recursive --new-file v1.1.60/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.1.60/linux/drivers/block/sbpcd.c	Tue Aug 30 08:16:13 1994
+++ linux/drivers/block/sbpcd.c	Wed Nov  2 11:51:13 1994
@@ -5,7 +5,7 @@
  *            and for "no-sound" interfaces like Lasermate and the
  *            Panasonic CI-101P.
  *
- *  NOTE:     This is release 2.6.
+ *  NOTE:     This is release 2.7.
  *            It works with my SbPro & drive CR-521 V2.11 from 2/92
  *            and with the new CR-562-B V0.75 on a "naked" Panasonic
  *            CI-101P interface. And vice versa. 
@@ -128,6 +128,10 @@
  *
  *  2.6  Nothing new.  
  *       
+ *  2.7  Added CDROMEJECT_SW ioctl to set the "EJECT" behavior on the fly:
+ *       0 disables, 1 enables auto-ejecting. Useful to keep the tray in
+ *       during shutdown.
+ *       
  *  TODO
  *
  *     disk change detection
@@ -203,7 +207,7 @@
 
 #include "blk.h"
 
-#define VERSION "2.6 Eberhard Moenkeberg <emoenke@gwdg.de>"
+#define VERSION "2.7 Eberhard Moenkeberg <emoenke@gwdg.de>"
 
 #define SBPCD_DEBUG
 
@@ -303,6 +307,9 @@
   0x320, 2, /* SPEA Media FX */
   0x340, 2, /* SPEA Media FX */
   0x350, 2, /* SPEA Media FX */
+/* due to incomplete address decoding of the SbPro card, these must be last */
+  0x630, 0, /* "sound card #9" (default) */
+  0x650, 0, /* "sound card #9" */
 #if 0
 /* some "hazardous" locations (ethernet cards) */
   0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
@@ -310,9 +317,6 @@
   0x370, 0, /* Lasermate, CI-101P */
   0x290, 1, /* Soundblaster 16 */
   0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
-/* excluded due to incomplete address decoding of the SbPro card */
-  0x630, 0, /* "sound card #9" (default) */
-  0x650, 0, /* "sound card #9" */
 #endif
 };
 
@@ -390,6 +394,7 @@
 #else
 static int sbpcd_debug =  (1<<DBG_INF) |
                           (1<<DBG_TOC) |
+                          (1<<DBG_MUL) |
                           (1<<DBG_UPC);
 #endif
 #endif
@@ -481,6 +486,7 @@
 
   char drive_model[4];
   char firmware_version[4];
+  char f_eject; /* auto-eject flag: 0 or 1 */
   u_char *sbp_buf; /* Pointer to internal data buffer,
                            space allocated during sbpcd_init() */
   int sbp_first_frame;  /* First frame in buffer */
@@ -2390,7 +2396,7 @@
 /*==========================================================================*/
 /*==========================================================================*/
 /*
- * ioctl support, adopted from scsi/sr_ioctl.c and mcd.c
+ * ioctl support
  */
 static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
 		       u_long arg)
@@ -2583,6 +2589,12 @@
       DriveStruct[d].audio_state=0;
       return (0);
       
+    case CDROMEJECT_SW:
+      DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMEJECT_SW entered.\n"));
+      if (!new_drive) return (0);
+      DriveStruct[d].f_eject=arg;
+      return (0);
+      
     case CDROMVOLCTRL:   /* Volume control */
       DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMVOLCTRL entered.\n"));
       st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl));
@@ -2918,7 +2930,9 @@
     }
 
   DPRINTF((DBG_BSZ,"SBPCD: read sector %d (%d sectors)\n", block, nsect));
+#if 0
   DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4));
+#endif
 
   sbp_transfer();
   /* if we satisfied the request from the buffer, we're done. */
@@ -3007,7 +3021,7 @@
 	  DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
 		         blk2msf(DriveStruct[d].lba_multi+16),
                          blk2msf(block)));
-	  block=DriveStruct[d].lba_multi+16;
+	  block=DriveStruct[d].lba_multi+block;
 	}
 #endif MANY_SESSION
     }
@@ -3323,9 +3337,7 @@
 	  do
 	    i=yy_LockDoor(0);
 	  while (i!=0);
-#if EJECT
-	  if (new_drive) yy_SpinDown();
-#endif
+	  if (DriveStruct[d].f_eject) yy_SpinDown();
 	}
     }
 }
@@ -3550,6 +3562,12 @@
       DriveStruct[d].sbp_current = 0;       /* Frame being currently read */
       DriveStruct[d].CD_changed=1;
       DriveStruct[d].frame_size=CD_FRAMESIZE;
+#if EJECT
+      if (new_drive) DriveStruct[d].f_eject=1;
+      else DriveStruct[d].f_eject=0;
+#else
+      DriveStruct[d].f_eject=0;
+#endif
 
       xx_ReadStatus();
       i=ResponseStatus();  /* returns orig. status or p_busy_new */
diff -u --recursive --new-file v1.1.60/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v1.1.60/linux/drivers/char/tpqic02.c	Tue Aug 23 09:48:50 1994
+++ linux/drivers/char/tpqic02.c	Tue Nov  1 19:50:44 1994
@@ -1,10 +1,9 @@
-/* $Id: tpqic02.c,v 0.4.1.4 1994/07/21 02:15:45 root Exp root $
+/* $Id: tpqic02.c,v 0.4.1.5 1994/10/29 02:46:13 root Exp root $
  *
- * Driver for tape drive support for Linux-i386 1.1.30
+ * Driver for tape drive support for Linux-i386 1.1.58
  *
  * Copyright (c) 1992, 1993, 1994 by H. H. Bergman. All rights reserved.
- * Current e-mail address: hennus@sky.nl.mugnet.org [This is a UUCP link.]
- * Secondary e-mail address: csg279@wing.rug.nl [IP connected, but flaky]
+ * Current e-mail address: hennus@sky.ow.org [This is a UUCP link.]
  * [If you are unable to reach me directly, try the TAPE mailing list
  * channel on linux-activists@niksula.hut.fi using "X-Mn-Key: TAPE" as
  * the first line in your message.]
@@ -35,6 +34,9 @@
  * You are not allowed to change this line nor the text above.
  *
  * $Log: tpqic02.c,v $
+ * Revision 0.4.1.5  1994/10/29  02:46:13  root
+ * Minor cleanups.
+ *
  * Revision 0.4.1.4  1994/07/21  02:15:45  root
  * ifdef'd DDI. Exception masks.
  *
@@ -191,10 +193,8 @@
  * Also, be careful to avoid IO conflicts with other devices!
  */
 
-#include <linux/config.h>
+#include <linux/autoconf.h>
 
-/* skip this driver if not required for this configuration */
-#if CONFIG_QIC02_TAPE
 
 /*
 #define TDEBUG
@@ -233,8 +233,8 @@
  */
 
 #ifdef CONFIG_QIC02_DYNCONF
-/* This may hold the dynamic configuration info for the interface
- * card+drive info in future versions.
+/* This holds the dynamic configuration info for the interface
+ * card+drive info if runtime configuration has been selected.
  */
 struct mtconfiginfo qic02_tape_dynconf = { 0, };	/* user settable */
 struct qic02_ccb qic02_tape_ccb = { 0, };		/* private stuff */
@@ -256,8 +256,8 @@
 
 static volatile struct tpstatus tperror;	/* last drive status */
 
-static char rcs_revision[] = "$Revision: 0.4.1.4 $";
-static char rcs_date[] = "$Date: 1994/07/21 02:15:45 $";
+static char rcs_revision[] = "$Revision: 0.4.1.5 $";
+static char rcs_date[] = "$Date: 1994/10/29 02:46:13 $";
 
 /* Flag bits for status and outstanding requests.
  * (Could all be put in one bit-field-struct.)
@@ -285,7 +285,7 @@
 static volatile unsigned dma_mode = 0;		/* !=0 also means DMA in use */
 static 		flag need_rewind = YES;
 
-static dev_t current_tape_dev = QIC02_TAPE_MAJOR << 8;
+static dev_t current_tape_dev = MKDEV(QIC02_TAPE_MAJOR, 0);
 static int extra_blocks_left = BLOCKS_BEYOND_EW;
 
 
@@ -570,7 +570,9 @@
 #endif
 
 
-/* perform appropriate action for certain exceptions */
+/* Perform appropriate action for certain exceptions.
+ * should return a value to indicate stop/continue (in case of bad blocks)
+ */
 static void handle_exception(int exnr, int exbits)
 {
 	if (exnr==EXC_NCART) {
@@ -1358,9 +1360,7 @@
 			return do_qic_cmd(QCMD_REWIND, TIM_R);
 
 		case MTOFFL:
-			tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline"); /*---*/
-			/******* What exactly are we supposed to do, to take it offline????
-			 *****/
+			tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline");
 			/* Doing a drive select will clear (unlock) the current drive.
 			 * But that requires support for multiple drives and locking.
 			 */
@@ -1927,8 +1927,9 @@
 	}
 
 	if (TP_DIAGS(current_tape_dev))
+		/* can't print a ``long long'' (for filp->f_pos), so chop it */
 		printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
-			MINOR(dev), buf, count, filp->f_pos, flags);
+			MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
 
 	if (count % TAPE_BLKSIZE) {	/* Only allow mod 512 bytes at a time. */
 		tpqputs(TPQD_BLKSZ, "Wrong block size");
@@ -2100,8 +2101,9 @@
 	}
 
 	if (TP_DIAGS(current_tape_dev))
+		/* can't print a ``long long'' (for filp->f_pos), so chop it */
 		printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
-			MINOR(dev), buf, count, filp->f_pos, flags);
+			MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
 
 	if (count % TAPE_BLKSIZE) {	/* only allow mod 512 bytes at a time */
 		tpqputs(TPQD_BLKSZ, "Wrong block size");
@@ -2587,7 +2589,7 @@
 		if (!suser())
 			return -EPERM;
 		verify_area(VERIFY_READ, (int *) ioarg, sizeof(int));
-		c = get_fs_long((int *) ioarg);
+		c = get_user_long((int *) ioarg);
 		if (c==0) {
 			QIC02_TAPE_DEBUG = 0;
 			return 0;
@@ -2619,7 +2621,7 @@
 		stp = (char *) &qic02_tape_dynconf;
 		argp = (char *) ioarg;
 		for (i=0; i<sizeof(qic02_tape_dynconf); i++) 
-			put_fs_byte(*stp++, argp++);
+			put_user_byte(*stp++, argp++);
 		return 0;
 
 	} else if (c == (MTIOCSETCONFIG & IOCCMD_MASK)) {
@@ -2646,7 +2648,7 @@
 		stp = (char *) &qic02_tape_dynconf;
 		argp = (char *) ioarg;
 		for (i=0; i<sizeof(qic02_tape_dynconf); i++)
-			*stp++ = get_fs_byte(argp++);
+			*stp++ = get_user_byte(argp++);
 		if (status_zombie==NO)
 			qic02_release_resources();	/* and go zombie */
 		if (update_ifc_masks(qic02_tape_dynconf.ifc_type))
@@ -2678,7 +2680,7 @@
 		stp = (char *) &operation;
 		argp = (char *) ioarg;
 		for (i=0; i<sizeof(operation); i++)
-			*stp++ = get_fs_byte(argp++);
+			*stp++ = get_user_byte(argp++);
 
 		/* ---note: mt_count is signed, negative seeks must be
 		 * ---	    translated to seeks in opposite direction!
@@ -2740,7 +2742,7 @@
 		stp = (char *) &ioctl_status;
 		argp = (char *) ioarg;
 		for (i=0; i<sizeof(ioctl_status); i++) 
-			put_fs_byte(*stp++, argp++);
+			put_user_byte(*stp++, argp++);
 		return 0;
 
 
@@ -2773,7 +2775,7 @@
 		stp = (char *) &ioctl_tell;
 		argp = (char *) ioarg;
 		for (i=0; i<sizeof(ioctl_tell); i++) 
-			put_fs_byte(*stp++, argp++);
+			put_user_byte(*stp++, argp++);
 		return 0;
 
 	} else
@@ -2793,7 +2795,10 @@
 	NULL,				/* mmap not allowed */
 	qic02_tape_open,		/* open */
 	qic02_tape_release,		/* release */
-	NULL				/* fsync */
+	NULL,				/* fsync */
+	NULL,				/* fasync */
+	NULL,				/* check_media_change */
+	NULL				/* revalidate */
 };
 
 /* align `a' at `size' bytes. `size' must be a power of 2 */
@@ -2870,7 +2875,6 @@
 
 
 
-/* init() is called from chr_dev_init() in drivers/char/mem.c */
 long qic02_tape_init(long kmem_start)
 	/* Shouldn't this be a caddr_t ? */
 {
@@ -2969,5 +2973,3 @@
 	return kmem_start;
 } /* qic02_tape_init */
 
-
-#endif /* CONFIG_QIC02_TAPE */
diff -u --recursive --new-file v1.1.60/linux/drivers/net/CONFIG linux/drivers/net/CONFIG
--- v1.1.60/linux/drivers/net/CONFIG	Wed Aug 10 19:26:00 1994
+++ linux/drivers/net/CONFIG	Wed Nov  2 11:38:35 1994
@@ -34,9 +34,10 @@
 #	  DE620_IO	The DE620 I/O-port address (0x378 == default)
 #	  DE620_IRQ	The DE620 IRQ number to use (IRQ7 == default)
 #	  DE620_DEBUG	Enable or disable DE600 debugging (default off)
-#  DEPCA		The DIGITAL series of AT Ethernet Cards (DE100, DE200)
-#	  DEPCA_IRQ	Set the desired IRQ (=0, for autoprobe)
-#	  DEPCA_DEBUG	Set the desired debug level
+#  DEPCA		The DIGITAL series of LANCE based Ethernet Cards
+#			(DEPCA, DE100, DE200/1/2, DE210, DE422 (EISA))
+#  EWRK3		The DIGITAL series of AT Ethernet Cards (DE203/4/5)
+#       EWRK3_DEBUG	Set the desired debug level
 #
 
 # The following options exist, but cannot be set in this file.
@@ -57,4 +58,5 @@
 NE_OPTS		=
 HP_OPTS		=
 PLIP_OPTS	=
-DEPCA_OPTS	= -DDEPCA_IRQ=0 -DDEPCA_DEBUG=1
+DEPCA_OPTS	= -DDEPCA_DEBUG=1
+EWRK3_OPTS	= -DEWRK3_DEBUG=1
diff -u --recursive --new-file v1.1.60/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.1.60/linux/drivers/net/Makefile	Tue Oct 11 09:17:04 1994
+++ linux/drivers/net/Makefile	Wed Nov  2 11:59:32 1994
@@ -142,6 +142,11 @@
 depca.o: depca.c CONFIG
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
 endif
+ifdef CONFIG_EWRK3
+NETDRV_OBJS := $(NETDRV_OBJS) ewrk3.o
+ewrk3.o: ewrk3.c CONFIG
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(EWRK3_OPTS) -c $<
+endif
 ifdef CONFIG_ATP
 NETDRV_OBJS := $(NETDRV_OBJS) atp.o
 endif
diff -u --recursive --new-file v1.1.60/linux/drivers/net/README.ewrk3 linux/drivers/net/README.ewrk3
--- v1.1.60/linux/drivers/net/README.ewrk3	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/README.ewrk3	Wed Nov  2 11:38:34 1994
@@ -0,0 +1,43 @@
+The EtherWORKS 3  driver in this distribution is  designed to  work with all
+kernels   >  1.1.33   (approx)  and  includes  tools   in  the  'ewrk3tools'
+subdirectory   to  allow  set   up of   the   card,  similar  to  the  MSDOS
+'NICSETUP.EXE' tools provided on  the DOS drivers  disk (type 'make' in that
+subdirectory to make the tools).
+
+The supported cards  are  DE203, DE204 and  DE205.  All other cards are  NOT
+supported - refer  to the depca files for   running the LANCE based  network
+cards from Digital.
+
+The ability to load  this driver as a  loadable module has been included and
+used extensively  during the driver  development (to save those  long reboot
+sequences). To utilise this ability, you have to do 8 things:
+
+    0) have a copy of the loadable modules code installed on your system.
+    1) copy ewrk3.c from the  /linux/drivers/net directory to your favourite
+    temporary directory.
+    2) edit the  source code near  line 1750 to reflect  the I/O address and
+    IRQ you're using.
+    3) compile  ewrk3.c, but include -DMODULE in  the command line to ensure
+    that the correct bits are compiled (see end of source code).
+    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
+    kernel with the ewrk3 configuration turned off and reboot.
+    5) insmod ewrk3.o
+    6) run the net startup bits for your new eth?? interface manually 
+    (usually /etc/rc.inet[12] at boot time). 
+    7) enjoy!
+
+    Note that autoprobing is not allowed in loadable modules - the system is
+    already up and running and you're messing with interrupts.
+
+    To unload a module, turn off the associated interface 
+    'ifconfig eth?? down' then 'rmmod ewrk3'.
+
+The performance we've  achieved so far  has been measured through the 'ttcp'
+tool   at 975kB/s.  This  measures  the  total  tcp  stack performance which
+includes the   card,  so don't  expect   to get   much nearer  the  1.25MB/s
+theoretical ethernet rate.
+
+
+Enjoy!
+
+Dave
diff -u --recursive --new-file v1.1.60/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.1.60/linux/drivers/net/Space.c	Fri Aug 19 08:53:24 1994
+++ linux/drivers/net/Space.c	Wed Nov  2 11:38:34 1994
@@ -49,6 +49,7 @@
 extern int at1500_probe(struct device *);
 extern int at1700_probe(struct device *);
 extern int depca_probe(struct device *);
+extern int ewrk3_probe(struct device *);
 extern int el1_probe(struct device *);
 extern int el16_probe(struct device *);
 extern int elplus_probe(struct device *);
@@ -107,6 +108,9 @@
 #endif
 #ifdef CONFIG_DEPCA		/* DEC DEPCA */
 	&& depca_probe(dev)
+#endif
+#ifdef CONFIG_EWRK3             /* DEC EtherWORKS 3 */
+        && ewrk3_probe(dev)
 #endif
 #ifdef CONFIG_EL1		/* 3c501 */
 	&& el1_probe(dev)
diff -u --recursive --new-file v1.1.60/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- v1.1.60/linux/drivers/net/ewrk3.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/ewrk3.c	Wed Nov  2 11:38:34 1994
@@ -0,0 +1,1835 @@
+/*  ewrk3.c: A DIGITAL EtherWORKS 3 ethernet driver for linux.
+
+    Written 1994 by David C. Davies.
+
+    Copyright 1994 Digital Equipment Corporation.
+
+    This software may be used and distributed according to the terms of
+    the GNU Public License, incorporated herein by reference.
+
+    This driver is written for the Digital Equipment Corporation series
+    of EtherWORKS ethernet cards:
+
+	DE203 Turbo (BNC)
+	DE204 Turbo (TP)
+	DE205 Turbo (TP BNC)
+
+    The driver has been tested on a relatively busy  network using the DE205
+    card and benchmarked with 'ttcp': it transferred 16M  of data at 975kB/s
+    (7.8Mb/s) to a DECstation 5000/200.
+
+    The author may    be  reached as davies@wanton.lkg.dec.com  or   Digital
+    Equipment Corporation, 550 King Street, Littleton MA 01460.
+
+    =========================================================================
+    This driver has been written  substantially  from scratch, although  its
+    inheritance of style and stack interface from 'depca.c' and in turn from
+    Donald Becker's 'lance.c' should be obvious.
+
+    The  DE203/4/5 boards  all  use a new proprietary   chip in place of the
+    LANCE chip used in prior cards  (DEPCA, DE100, DE200/1/2, DE210, DE422).
+    Use the depca.c driver in the standard distribution  for the LANCE based
+    cards from DIGITAL; this driver will not work with them.
+
+    The DE203/4/5 cards have 2  main modes: shared memory  and I/O only. I/O
+    only makes  all the card accesses through  I/O transactions and  no high
+    (shared)  memory is used. This  mode provides a >48% performance penalty
+    and  is deprecated in this  driver,  although allowed to provide initial
+    setup when hardstrapped.
+
+    The shared memory mode comes in 3 flavours: 2kB, 32kB and 64kB. There is
+    no point in using any mode other than the 2kB  mode - their performances
+    are virtually identical, although the driver has  been tested in the 2kB
+    and 32kB modes. I would suggest you uncomment the line:
+
+                             FORCE_2K_MODE;
+
+    to allow the driver to configure the card as a  2kB card at your current
+    base  address, thus leaving more  room to clutter  your  system box with
+    other memory hungry boards.
+
+    Upto 21 ISA and 7 EISA cards can be supported under this driver, limited
+    primarily by the  available  IRQ   lines.   I have   checked   different
+    configurations  of multiple depca  cards and  ewrk3 cards  and  have not
+    found a problem yet (provided you have at least depca.c v0.38) ...
+
+    The board IRQ setting   must be at  an unused  IRQ which is  auto-probed
+    using  Donald  Becker's autoprobe  routines.   All  these cards   are at
+    {5,10,11,15}.
+
+    No 16MB memory  limitation should exist with this  driver as DMA is  not
+    used and the common memory area is in low memory on the network card (my
+    current system has 20MB and I've not had problems yet).
+
+    The ability to load  this driver as a  loadable module has been included
+    and used  extensively during the  driver development (to save those long
+    reboot sequences). To utilise this ability, you have to do 8 things:
+
+    0) have a copy of the loadable modules code installed on your system.
+    1) copy ewrk3.c from the  /linux/drivers/net directory to your favourite
+    temporary directory.
+    2) edit the  source code near  line 1340 to reflect  the I/O address and
+    IRQ you're using.
+    3) compile  ewrk3.c, but include -DMODULE in  the command line to ensure
+    that the correct bits are compiled (see end of source code).
+    4) if you are wanting to add a new  card, goto 5. Otherwise, recompile a
+    kernel with the ewrk3 configuration turned off and reboot.
+    5) insmod ewrk3.o
+    6) run the net startup bits for your new eth?? interface manually 
+    (usually /etc/rc.inet[12] at boot time). 
+    7) enjoy!
+
+    Note that autoprobing is not allowed in loadable modules - the system is
+    already up and running and you're messing with interrupts.
+
+    To unload a module, turn off the associated interface 
+    'ifconfig eth?? down' then 'rmmod ewrk3'.
+
+    Promiscuous   mode has been  turned  off  in this driver,   but  all the
+    multicast  address bits  have been   turned on. This  improved the  send
+    performance on a busy network by about 13%.
+
+    Ioctl's have now been provided (primarily because  I wanted to grab some
+    packet size statistics). They  are patterned after 'plipconfig.c' from a
+    suggestion by Alan Cox.  Using these  ioctls, you can enable promiscuous
+    mode, add/delete multicast  addresses, change the hardware address,  get
+    packet size distribution statistics and muck around with the control and
+    status register. I'll add others if and when the need arises.
+
+    TO DO:
+    ------
+
+
+    Revision History
+    ----------------
+
+    Version   Date        Description
+  
+      0.1     26-aug-94   Initial writing. ALPHA code release.
+      0.11    31-aug-94   Fixed: 2k mode memory base calc., 
+                                 LeMAC version calc.,
+				 IRQ vector assignments during autoprobe.
+      0.12    31-aug-94   Tested working on LeMAC2 (DE20[345]-AC) card.
+                          Fixed up MCA hash table algorithm.
+      0.20     4-sep-94   Added IOCTL functionality.
+      0.21    14-sep-94   Added I/O mode.
+      0.21axp 15-sep-94   Special version for ALPHA AXP Linux V1.0
+      0.22    16-sep-94   Added more IOCTLs & tidied up.
+      0.23    21-sep-94   Added transmit cut through
+      0.24    31-oct-94   Added uid checks in some ioctls
+      0.30     1-nov-94   BETA code release
+
+    =========================================================================
+*/
+
+static char *version = "ewrk3.c:v0.30 11/1/94 davies@wanton.lkg.dec.com\n";
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/segment.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/unistd.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include "/linux/tools/version.h"
+#endif /* MODULE */
+
+#include "ewrk3.h"
+
+#ifdef EWRK3_DEBUG
+static int ewrk3_debug = EWRK3_DEBUG;
+#else
+static int ewrk3_debug = 1;
+#endif
+
+#ifndef PROBE_LENGTH
+#define PROBE_LENGTH    32
+#endif
+
+#ifndef PROBE_SEQUENCE
+#define PROBE_SEQUENCE "FF0055AAFF0055AA"
+#endif
+
+#ifndef EWRK3_SIGNATURE
+#define EWRK3_SIGNATURE {"DE203","DE204","DE205",""}
+#define EWRK3_NAME_LENGTH 8
+#endif
+
+#ifndef EWRK3_RAM_BASE_ADDRESSES
+#define EWRK3_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0x00000}
+#endif
+
+/*
+** Sets up the search areas for the autoprobe. You can disable an area
+** by writing a zero into the corresponding bit position in EWRK3_IO_SEARCH.
+** The LSb -> I/O 0x100. Each bit increments the I/O location searched by 0x20.
+** Bit 24 -> I/O 0x400.
+**
+** By default, probes at locations:
+**             0x1e0   (may conflict with hard disk)
+**             0x320   (may conflict with hard disk)
+**             0x3e0   (may conflict with floppy disk)
+**
+** are disabled.
+*/
+
+#define EWRK3_IO_BASE 0x100             /* Start address for probe search */
+#define EWRK3_IOP_INC 0x20              /* I/O address increment */
+#define EWRK3_IO_SEARCH 0x007dff7f      /* probe search mask */
+static long mem_chkd = EWRK3_IO_SEARCH; /* holds which I/O addrs should be */
+				        /* checked, for multi-EWRK3 case */
+
+#ifndef MAX_NUM_EWRK3S
+#define MAX_NUM_EWRK3S 21
+#endif
+
+#ifndef EWRK3_EISA_IO_PORTS 
+#define EWRK3_EISA_IO_PORTS 0x0c00      /* I/O port base address, slot 0 */
+#endif
+
+#ifndef MAX_EISA_SLOTS
+#define MAX_EISA_SLOTS 8
+#define EISA_SLOT_INC 0x1000
+#endif
+
+#ifndef CRC_POLYNOMIAL
+#define CRC_POLYNOMIAL 0x04c11db7       /* Ethernet CRC polynomial */
+#endif /* CRC_POLYNOMIAL */
+
+/*
+** EtherWORKS 3 shared memory window sizes
+*/
+#define IO_ONLY         0x00
+#define SHMEM_2K        0x800
+#define SHMEM_32K       0x8000
+#define SHMEM_64K       0x10000
+
+/*
+** EtherWORKS 3 IRQ ENABLE/DISABLE
+*/
+static unsigned char irq_mask = TNEM|TXDM|RNEM|RXDM;
+
+#define ENABLE_IRQs \
+  icr |= irq_mask;\
+  outb(icr, EWRK3_ICR)                      /* Enable the IRQs */
+
+#define DISABLE_IRQs \
+  icr = inb(EWRK3_ICR);\
+  icr &= ~irq_mask;\
+  outb(icr, EWRK3_ICR)                      /* Disable the IRQs */
+
+/*
+** EtherWORKS 3 START/STOP
+*/
+#define START_EWRK3 \
+  csr = inb(EWRK3_CSR);\
+  csr &= ~(TXD|RXD);\
+  outb(csr, EWRK3_CSR)                      /* Enable the TX and/or RX */
+
+#define STOP_EWRK3 \
+  csr = (TXD|RXD);\
+  outb(csr, EWRK3_CSR)                      /* Disable the TX and/or RX */
+
+/*
+** The EtherWORKS 3 private structure
+*/
+#define EWRK3_PKT_STAT_SZ 16
+#define EWRK3_PKT_BIN_SZ  128           /* Should be >=100 unless you
+                                           increase EWRK3_PKT_STAT_SZ */
+
+struct ewrk3_private {
+    long shmem_base;                    /* Shared memory start address */
+    long shmem_length;                  /* Shared memory window length */
+    struct enet_statistics stats;       /* Public stats */
+    struct {
+      unsigned long bins[EWRK3_PKT_STAT_SZ]; /* Private stats counters */
+      unsigned long unicast;
+      unsigned long multicast;
+      unsigned long broadcast;
+      unsigned long excessive_collisions;
+      unsigned long tx_underruns;
+      unsigned long excessive_underruns;
+    } pktStats;
+    short mPage;                        /* Maximum 2kB Page number */
+    unsigned char lemac;                /* Chip rev. level */
+    unsigned char hard_strapped;        /* Don't allow a full open */
+    unsigned char lock;                 /* Lock the page register */
+    unsigned char txc;                  /* Transmit cut through */
+};
+
+/*
+** Force the EtherWORKS 3 card to be in 2kB MODE
+*/
+#define FORCE_2K_MODE \
+  shmem_length = SHMEM_2K;\
+  outb(((mem_start - 0x80000) >> 11), EWRK3_MBR)
+
+/*
+** Public Functions
+*/
+static int ewrk3_open(struct device *dev);
+static int ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev);
+static void ewrk3_interrupt(int reg_ptr);
+static int ewrk3_close(struct device *dev);
+static struct enet_statistics *ewrk3_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+static int ewrk3_ioctl(struct device *dev, struct ifreq *rq);
+
+/*
+** Private functions
+*/
+static int  ewrk3_hw_init(struct device *dev, short iobase);
+static void ewrk3_init(struct device *dev);
+static int  ewrk3_rx(struct device *dev);
+static int  ewrk3_tx(struct device *dev);
+
+static void EthwrkSignature(char * name, char *eeprom_image);
+static int  DevicePresent(short iobase);
+static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table);
+
+static int  Read_EEPROM(short iobase, unsigned char eaddr);
+static int  Write_EEPROM(short data, short iobase, unsigned char eaddr);
+static unsigned char aprom_crc (struct device *dev, unsigned char *eeprom_image, char chipType);
+
+#ifndef MODULE
+static struct device *isa_probe(struct device *dev);
+static struct device *eisa_probe(struct device *dev);
+static struct device *alloc_device(struct device *dev, int iobase);
+
+static int num_ewrk3s = 0, num_eth = 0, autoprobed = 0;
+static unsigned char irq[] = {5,0,10,3,11,9,15,12};
+
+#else
+int  init_module(void);
+void cleanup_module(void);
+
+#endif /* MODULE */
+
+/*
+** Miscellaneous defines...
+*/
+#define INIT_EWRK3 {\
+    int i;\
+    outb(EEPROM_INIT, EWRK3_IOPR);\
+    for (i=0;i<5000;i++) inb(EWRK3_CSR);\
+		   }
+
+
+
+
+int ewrk3_probe(struct device *dev)
+{
+  int base_addr = dev->base_addr;
+  int status = -ENODEV;
+#ifndef MODULE
+  struct device *eth0;
+#endif
+
+  if (base_addr > 0x0ff) {	      /* Check a single specified location. */
+    if (((mem_chkd >> ((base_addr - EWRK3_IO_BASE)/ EWRK3_IOP_INC))&0x01)==0) {
+      if (DevicePresent(base_addr) == 0) { /* Is EWRK3 really here? */
+	status = ewrk3_hw_init(dev, base_addr);
+      } else {
+	printk("ewrk3_probe(): No device found\n");
+      }
+    } else {
+      status = ewrk3_hw_init(dev, base_addr); /* Yes there is h/w */
+    }
+  } else if (base_addr > 0) {         /* Don't probe at all. */
+    status = -ENXIO;
+
+#ifdef MODULE
+  } else {
+    printk("Autoprobing is not supported when loading a module based driver.\n");
+    status = -EIO;
+#else
+  } else if (!autoprobed) {           /* First probe for the EWRK3 test */
+                                      /* pattern in ROM */
+    eth0=isa_probe(dev);
+    eth0=eisa_probe(eth0);
+    if (dev->priv) status=0;
+    autoprobed = 1;
+  } else {
+    status = -ENXIO;
+#endif /* MODULE */
+    
+  }
+
+  if (status) dev->base_addr = base_addr;
+
+  return status;
+}
+
+static int
+ewrk3_hw_init(struct device *dev, short iobase)
+{
+  struct ewrk3_private *lp;
+  int i, status=0;
+  unsigned long mem_start, shmem_length;
+  char name[EWRK3_NAME_LENGTH + 1];
+  unsigned char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
+  unsigned char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
+
+  /*
+  ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
+  ** This also disables the EISA_ENABLE bit in the EISA Control Register.
+  */
+  if (iobase > 0x400) eisa_cr = inb(EISA_CR);
+  INIT_EWRK3;
+
+  nicsr = inb(EWRK3_CSR);
+
+  /*
+  ** Disable & mask all board interrupts
+  */
+  DISABLE_IRQs;
+
+  if (nicsr == TXD|RXD) {
+
+    /*
+    ** Check that the EEPROM is alive and well and not living on Pluto...
+    */
+    for (chksum=0, i=0; i<EEPROM_MAX; i+=2) {
+      union {
+	short val;
+	char c[2];
+      } tmp;
+
+      tmp.val = (short)Read_EEPROM(iobase, (i>>1));
+      eeprom_image[i] = tmp.c[0];
+      eeprom_image[i+1] = tmp.c[1];
+
+      chksum += eeprom_image[i] + eeprom_image[i+1];
+    }
+
+    if (chksum != 0) {                             /* Bad EEPROM Data! */
+      printk("%s: Device has a bad on-board EEPROM.\n", dev->name);
+      status = -ENXIO;
+    } else {
+      /* 
+      ** Now find out what kind of EWRK3 we have.
+      */
+      EthwrkSignature(name, eeprom_image);
+
+      if (*name != '\0') {                         /* found a EWRK3 device */
+	dev->base_addr = iobase;
+      
+	if (iobase > 0x400) {
+	  outb(eisa_cr, EISA_CR);                  /* Rewrite the EISA CR */
+	}
+
+	lemac = eeprom_image[EEPROM_CHIPVER];
+	cmr = inb(EWRK3_CMR);
+
+	if (((lemac == LeMAC) && ((cmr & NO_EEPROM) != NO_EEPROM)) ||
+	    ((lemac == LeMAC2) && !(cmr & HS))) {
+	  printk("%s: %s at %#3x", dev->name, name, iobase);
+	  hard_strapped = 1;
+	} else if ((iobase&0x0fff)==EWRK3_EISA_IO_PORTS) {
+	                                           /* EISA slot address */
+	  printk("%s: %s at %#3x (EISA slot %d)", 
+	                         dev->name, name, iobase, ((iobase>>12)&0x0f));
+	} else {                                   /* ISA port address */
+	  printk("%s: %s at %#3x", dev->name, name, iobase);
+	}
+	
+	if (!status) {
+	  printk(", h/w address ");
+	  if (lemac == LeMAC2) {
+	    for (i = 0;i < ETH_ALEN - 1;i++) { /* get the ethernet address */
+	      printk("%2.2x:", dev->dev_addr[i] = 
+		                              eeprom_image[EEPROM_PADDR0 + i]);
+	      outb(eeprom_image[EEPROM_PADDR0 + i], EWRK3_PAR0 + i);
+	    }
+	    printk("%2.2x,\n",dev->dev_addr[i] = eeprom_image[EEPROM_PADDR0 + i]);
+	    outb(eeprom_image[EEPROM_PADDR0 + i], EWRK3_PAR0 + i);
+	  } else {
+	    DevicePresent(iobase);          /* needed after the EWRK3_INIT */
+	    for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
+	      printk("%2.2x:", dev->dev_addr[i] = inb(EWRK3_APROM));
+	      outb(dev->dev_addr[i], EWRK3_PAR0 + i);
+	    }
+	    printk("%2.2x,\n", dev->dev_addr[i] = inb(EWRK3_APROM));
+	    outb(dev->dev_addr[i], EWRK3_PAR0 + i);
+	  }
+
+	  if (aprom_crc(dev, eeprom_image, lemac)) {
+	    printk("      which has an EEPROM CRC error.\n");
+	    status = -ENXIO;
+	  } else {
+	    if (lemac == LeMAC2) {            /* Special LeMAC2 CMR things */
+	      cmr &= ~(RA | WB | LINK | POLARITY | _0WS);         
+	      if (eeprom_image[EEPROM_MISC0] & READ_AHEAD)    cmr |= RA;
+	      if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND)  cmr |= WB;
+	      if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL)  cmr |= POLARITY;
+	      if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) cmr |= LINK;
+	      if (eeprom_image[EEPROM_MISC0] & _0WS_ENA)      cmr |= _0WS;
+	    }
+	    if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM)      cmr |= DRAM;
+	    outb(cmr, EWRK3_CMR);
+
+	    cr = inb(EWRK3_CR);               /* Set up the Control Register */
+	    cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD;
+	    if (cr & SETUP_APD) cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS;
+	    cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS;
+	    cr |= eeprom_image[EEPROM_MISC0] & ENA_16;
+	    outb(cr, EWRK3_CR);
+
+	    /* 
+	    ** Determine the base address and window length for the EWRK3
+	    ** RAM from the memory base register.
+	    */
+	    mem_start = inb(EWRK3_MBR);
+	    shmem_length = 0;
+	    if (mem_start != 0) {
+	      if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) {
+		mem_start *= SHMEM_64K;
+		shmem_length = SHMEM_64K;
+	      } else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) {
+		mem_start *= SHMEM_32K;
+		shmem_length = SHMEM_32K;
+	      } else if ((mem_start >= 0x40) && (mem_start <= 0xff)) {
+		mem_start = mem_start * SHMEM_2K + 0x80000;
+		shmem_length = SHMEM_2K;
+	      } else {
+		status = -ENXIO;
+	      }
+	    }
+	  
+	    /*
+	    ** See the top of this source code for comments about
+	    ** uncommenting this line.
+	    */
+/*	    FORCE_2K_MODE;*/
+
+	    if (!status) {
+	      if (hard_strapped) {
+		printk("      is hard strapped.\n");
+	      } else if (mem_start) {
+		printk("      has a %dk RAM window", (int)(shmem_length >> 10));
+		printk(" at 0x%.5lx", mem_start);
+	      } else {
+		printk("      is in I/O only mode");
+	      }
+	    
+	      /* private area & initialise */
+	      dev->priv = (void *) kmalloc(sizeof(struct ewrk3_private), 
+					                           GFP_KERNEL);
+	      lp = (struct ewrk3_private *)dev->priv;
+	      memset(dev->priv, 0, sizeof(struct ewrk3_private));
+	      lp->shmem_base = mem_start;
+	      lp->shmem_length = shmem_length;
+	      lp->lemac = lemac;
+	      lp->hard_strapped = hard_strapped;
+
+	      lp->mPage = 64;
+	      if (cmr & DRAM) lp->mPage <<= 1 ;     /* 2 DRAMS on module */ 
+
+	      if (!hard_strapped) {
+		/*
+		** Enable EWRK3 board interrupts for autoprobing
+		*/
+		icr |= IE;	                   /* Enable interrupts */
+		outb(icr, EWRK3_ICR);
+	    
+		/* The DMA channel may be passed in on this parameter. */
+		dev->dma = 0;
+	
+		/* To auto-IRQ we enable the initialization-done and DMA err,
+		   interrupts. For now we will always get a DMA error. */
+		if (dev->irq < 2) {
+#ifndef MODULE
+		  unsigned char irqnum;
+	      
+		  autoirq_setup(0);
+
+		  /* 
+		  ** Trigger a TNE interrupt.
+		  */
+		  icr |=TNEM;
+		  outb(1,EWRK3_TDQ);          /* Write to the TX done queue */
+		  outb(icr, EWRK3_ICR);       /* Unmask the TXD interrupt */
+	      
+		  irqnum = irq[((icr & IRQ_SEL) >> 4)];
+	      
+		  dev->irq = autoirq_report(1);
+		  if ((dev->irq) && (irqnum == dev->irq)) {
+		    printk(" and uses IRQ%d.\n", dev->irq);
+		  } else {
+		    if (!dev->irq) {
+		      printk(" and failed to detect IRQ line.\n");
+		    } else if ((irqnum == 1) && (lemac == LeMAC2)) {
+		      printk(" and an illegal IRQ line detected.\n");
+		    } else {
+		      printk(", but incorrect IRQ line detected.\n");
+		    }
+		    status = -ENXIO;
+		  }
+		
+		  DISABLE_IRQs;                 /* Mask all interrupts */
+
+#endif /* MODULE */
+		} else {
+		  printk(" and requires IRQ%d.\n", dev->irq);
+		}
+	      }
+	    } else {
+	      status = -ENXIO;
+	    }
+	  }
+	}
+      } else {
+	status = -ENXIO;
+      }
+    }
+
+    if (!status) {
+      if (ewrk3_debug > 0) {
+	printk(version);
+      }
+      
+      /* The EWRK3-specific entries in the device structure. */
+      dev->open = &ewrk3_open;
+      dev->hard_start_xmit = &ewrk3_queue_pkt;
+      dev->stop = &ewrk3_close;
+      dev->get_stats = &ewrk3_get_stats;
+#ifdef HAVE_MULTICAST
+      dev->set_multicast_list = &set_multicast_list;
+#endif
+      dev->do_ioctl = &ewrk3_ioctl;
+
+      dev->mem_start = 0;
+	
+      /* Fill in the generic field of the device structure. */
+      ether_setup(dev);
+    }
+  } else {
+    status = -ENXIO;
+  }
+
+  return status;
+}
+
+
+static int
+ewrk3_open(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int i, iobase = dev->base_addr;
+  int status = 0;
+  unsigned char icr, csr;
+
+  /*
+  ** Stop the TX and RX...
+  */
+  STOP_EWRK3;
+
+  if (!lp->hard_strapped) {
+    if (request_irq(dev->irq, &ewrk3_interrupt, 0, "ewrk3")) {
+      printk("ewrk3_open(): Requested IRQ%d is busy\n",dev->irq);
+      status = -EAGAIN;
+    } else {
+
+      irq2dev_map[dev->irq] = dev;
+
+      /* 
+      ** Re-initialize the EWRK3... 
+      */
+      ewrk3_init(dev);
+
+      if (ewrk3_debug > 1){
+	printk("%s: ewrk3 open with irq %d\n",dev->name,dev->irq);
+	printk("\tphysical address: ");
+	for (i=0;i<6;i++){
+	  printk("%2.2x:",(short)dev->dev_addr[i]);
+	}
+	printk("\n");
+	printk("\tchecked memory: 0x%08lx\n",mem_chkd);
+	if (lp->shmem_length == 0) {
+	  printk("\tno shared memory, I/O only mode\n");
+	} else {
+	  printk("\tstart of shared memory: 0x%08lx\n",lp->shmem_base);
+	  printk("\twindow length: 0x%04lx\n",lp->shmem_length);
+	}
+	printk("\t# of DRAMS: %d\n",((inb(EWRK3_CMR) & 0x02) ? 2 : 1));
+	printk("\tcsr:  0x%02x\n", inb(EWRK3_CSR));
+	printk("\tcr:   0x%02x\n", inb(EWRK3_CR));
+	printk("\ticr:  0x%02x\n", inb(EWRK3_ICR));
+	printk("\tcmr:  0x%02x\n", inb(EWRK3_CMR));
+	printk("\tfmqc: 0x%02x\n", inb(EWRK3_FMQC));
+      }
+
+      dev->tbusy = 0;                         
+      dev->start = 1;
+      dev->interrupt = UNMASK_INTERRUPTS;
+
+      /*
+      ** Unmask EWRK3 board interrupts
+      */
+      icr = inb(EWRK3_ICR);
+      ENABLE_IRQs;
+
+    }
+  } else {
+    dev->start = 0;
+    dev->tbusy = 1;
+    printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name);
+    printk("      Run the 'ewrk3setup' utility or remove the hard straps.\n");
+  }
+
+#ifdef MODULE
+    MOD_INC_USE_COUNT;
+#endif       
+
+
+  return status;
+}
+
+/*
+** Initialize the EtherWORKS 3 operating conditions
+*/
+static void
+ewrk3_init(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  char csr, page;
+  short iobase = dev->base_addr;
+  
+  /* 
+  ** Enable all multicasts 
+  */
+  set_multicast_list(dev, HASH_TABLE_LEN, NULL);
+
+  /*
+  ** Clean out any remaining entries in all the queues here
+  */
+  while (inb(EWRK3_TQ));
+  while (inb(EWRK3_TDQ));
+  while (inb(EWRK3_RQ));
+  while (inb(EWRK3_FMQ));
+
+  /*
+  ** Write a clean free memory queue
+  */
+  for (page=1;page<lp->mPage;page++) {      /* Write the free page numbers */
+    outb(page, EWRK3_FMQ);                  /* to the Free Memory Queue */
+  }
+
+  lp->lock = 0;                             /* Ensure there are no locks */
+
+  START_EWRK3;                              /* Enable the TX and/or RX */
+}
+
+/* 
+** Writes a socket buffer to the free page queue
+*/
+static int
+ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  int status = 0;
+  unsigned char icr, csr;
+
+  /* Transmitter timeout, serious problems. */
+  if (dev->tbusy || lp->lock) {
+    int tickssofar = jiffies - dev->trans_start;
+    if (tickssofar < 10) {
+      status = -1;
+    } else if (!lp->hard_strapped) {
+      printk("%s: transmit timed/locked out, status %04x, resetting.\n",
+	                                           dev->name, inb(EWRK3_CSR));
+	
+      /*
+      ** Mask all board interrupts
+      */
+      DISABLE_IRQs;
+
+      /*
+      ** Stop the TX and RX...
+      */
+      STOP_EWRK3;
+
+      ewrk3_init(dev);
+
+      /*
+      ** Unmask EWRK3 board interrupts
+      */
+      ENABLE_IRQs;
+
+      dev->tbusy=0;
+      dev->trans_start = jiffies;
+    }
+  } else if (skb == NULL) {
+    dev_tint(dev);
+  } else if (skb->len > 0) {
+
+    /* 
+    ** Block a timer-based transmit from overlapping.  This could better be
+    ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well. 
+    */
+    if (set_bit(0, (void*)&dev->tbusy) != 0)
+      printk("%s: Transmitter access conflict.\n", dev->name);
+
+    DISABLE_IRQs;                      /* So that the page # remains correct */
+    
+    /* 
+    ** Get a free page from the FMQ when resources are available
+    */
+    if (inb(EWRK3_FMQC) > 0) {
+      unsigned char *buf;
+      unsigned char page;
+
+      if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
+	buf = NULL;
+
+	/*
+	** Set up shared memory window and pointer into the window
+	*/
+	while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+	if (lp->shmem_length == IO_ONLY) {
+	  outb(page, EWRK3_IOPR);
+	} else if (lp->shmem_length == SHMEM_2K) {
+	  buf = (char *) lp->shmem_base;
+	  outb(page, EWRK3_MPR);
+	} else if (lp->shmem_length == SHMEM_32K) {
+	  buf = (char *)((((short)page << 11) & 0x7800) + lp->shmem_base);
+	  outb((page >> 4), EWRK3_MPR);
+	} else if (lp->shmem_length == SHMEM_64K) {
+	  buf = (char *)((((short)page << 11) & 0xf800) + lp->shmem_base);
+	  outb((page >> 5), EWRK3_MPR);
+	} else {
+	  status = -1;
+	  printk("%s: Oops - your private data area is hosed!\n",dev->name);
+	}
+
+	if (!status) {
+
+          /* 
+	  ** Set up the buffer control structures and copy the data from
+	  ** the socket buffer to the shared memory .
+	  */
+
+	  if (lp->shmem_length == IO_ONLY) {
+	    int i;
+	    unsigned char *p = skb->data;
+	    
+	    outb((char)(QMODE | PAD | IFC), EWRK3_DATA);
+	    outb((char)(skb->len & 0xff), EWRK3_DATA);
+	    outb((char)((skb->len >> 8) & 0xff), EWRK3_DATA);
+	    outb((char)0x04, EWRK3_DATA);
+	    for (i=0; i<skb->len; i++) {
+	      outb(*p++, EWRK3_DATA);
+	    }
+	    outb(page, EWRK3_TQ);                     /* Start sending pkt */
+	  } else {
+	    *buf++ = (char)(QMODE | PAD | IFC);       /* control byte */
+	    *buf++ = (char)(skb->len & 0xff);         /* length (16 bit xfer)*/
+	    if (lp->txc) {
+	      *buf++ = (char)(((skb->len >> 8) & 0xff) | XCT);
+	      *buf++ = 0x04;                          /* index byte */
+	      *(buf + skb->len) = 0x00;               /* Write the XCT flag */
+	      memcpy(buf, skb->data, PRELOAD);        /* Write PRELOAD bytes */
+	      outb(page, EWRK3_TQ);                   /* Start sending pkt */
+	      memcpy(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
+	      *(buf + skb->len) = 0xff;               /* Write the XCT flag */
+	    } else {
+	      *buf++ = (char)((skb->len >> 8) & 0xff);
+	      *buf++ = 0x04;                          /* index byte */
+	      memcpy(buf, skb->data, skb->len);       /* Write data bytes */
+	      outb(page, EWRK3_TQ);                   /* Start sending pkt */
+	    }
+	  }
+
+	  dev->trans_start = jiffies;
+
+	  dev_kfree_skb (skb, FREE_WRITE);
+
+        } else {              /* return unused page to the free memory queue */
+	  outb(page, EWRK3_FMQ);
+	}
+	lp->lock = 0;         /* unlock the page register */
+      } else {
+	printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
+	                                                 (unsigned char) page);
+      }
+    } else {
+      printk("ewrk3_queue_pkt(): No free resources...\n");
+      printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n",inb(EWRK3_CSR),inb(EWRK3_ICR),inb(EWRK3_FMQC));
+    }
+    
+    /* Check for free resources: clear 'tbusy' if there are some */
+    if (inb(EWRK3_FMQC) > 0) {
+      dev->tbusy = 0;
+    }
+
+    ENABLE_IRQs;
+  }
+
+  return status;
+}
+
+/*
+** The EWRK3 interrupt handler. 
+*/
+static void
+ewrk3_interrupt(int reg_ptr)
+{
+    int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+    struct device *dev = (struct device *)(irq2dev_map[irq]);
+    struct ewrk3_private *lp;
+    int iobase;
+    unsigned char icr, cr, csr;
+
+    if (dev == NULL) {
+	printk ("ewrk3_interrupt(): irq %d for unknown device.\n", irq);
+    } else {
+      lp = (struct ewrk3_private *)dev->priv;
+      iobase = dev->base_addr;
+
+      if (dev->interrupt)
+	printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+      dev->interrupt = MASK_INTERRUPTS;
+
+      /* get the interrupt information */
+      csr = inb(EWRK3_CSR);
+
+      /* 
+      ** Mask the EWRK3 board interrupts and turn on the LED 
+      */
+      DISABLE_IRQs;
+
+      cr = inb(EWRK3_CR);
+      cr |= LED;
+      outb(cr, EWRK3_CR);
+
+      if (csr & RNE)		  /* Rx interrupt (packet[s] arrived) */
+	ewrk3_rx(dev);
+
+      if (csr & TNE) 	          /* Tx interrupt (packet sent) */
+        ewrk3_tx(dev);
+
+      /*
+      ** Now deal with the TX/RX disable flags. These are set when there
+      ** are no more resources. If resources free up then enable these
+      ** interrupts, otherwise mask them - failure to do this will result
+      ** in the system hanging in an interrupt loop.
+      */
+      if (inb(EWRK3_FMQC)) {      /* any resources available? */
+	irq_mask |= TXDM|RXDM;    /* enable the interrupt source */
+	csr &= ~(TXD|RXD);        /* ensure restart of a stalled TX or RX */
+	outb(csr, EWRK3_CSR);
+	dev->tbusy = 0;           /* clear TX busy flag */
+	mark_bh(NET_BH);
+      } else {
+	irq_mask &= ~(TXDM|RXDM); /* disable the interrupt source */
+      }
+
+      /* Unmask the EWRK3 board interrupts and turn off the LED */
+      cr &= ~LED;
+      outb(cr, EWRK3_CR);
+
+      dev->interrupt = UNMASK_INTERRUPTS;
+
+      ENABLE_IRQs;
+    }
+
+    return;
+}
+
+static int
+ewrk3_rx(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int i, iobase = dev->base_addr;
+  unsigned char page, tmpPage = 0, tmpLock = 0, *buf;
+  int status = 0;
+
+  while (inb(EWRK3_RQC) && !status) {        /* Whilst there's incoming data */
+    if ((page = inb(EWRK3_RQ)) < lp->mPage) {/* Get next entry's buffer page */
+      buf = NULL;
+
+      /*
+      ** Preempt any process using the current page register. Check for
+      ** an existing lock to reduce time taken in I/O transactions.
+      */
+      if ((tmpLock = set_bit(0, (void *)&lp->lock)) == 1) {   /* Assert lock */
+	if (lp->shmem_length == IO_ONLY) {              /* Get existing page */
+	  tmpPage = inb(EWRK3_IOPR);
+	} else {
+	  tmpPage = inb(EWRK3_MPR);
+	}
+      }
+
+      /*
+      ** Set up shared memory window and pointer into the window
+      */
+      if (lp->shmem_length == IO_ONLY) {
+	outb(page, EWRK3_IOPR);
+      } else if (lp->shmem_length == SHMEM_2K) {
+	buf = (char *) lp->shmem_base;
+	outb(page, EWRK3_MPR);
+      } else if (lp->shmem_length == SHMEM_32K) {
+	buf = (char *)((((short)page << 11) & 0x7800) + lp->shmem_base);
+	outb((page >> 4), EWRK3_MPR);
+      } else if (lp->shmem_length == SHMEM_64K) {
+	buf = (char *)((((short)page << 11) & 0xf800) + lp->shmem_base);
+	outb((page >> 5), EWRK3_MPR);
+      } else {
+	status = -1;
+	printk("%s: Oops - your private data area is hosed!\n",dev->name);
+      }
+
+      if (!status) {
+	char rx_status;
+	int pkt_len;
+
+	if (lp->shmem_length == IO_ONLY) {
+	  rx_status = inb(EWRK3_DATA);
+	  pkt_len = inb(EWRK3_DATA);
+	  pkt_len |= ((unsigned short)inb(EWRK3_DATA) << 8);
+	} else {
+	  rx_status = (char)(*buf++);
+	  pkt_len = (short)(*buf+((*(buf+1))<<8));
+	  buf+=3;
+	}
+
+	if (!(rx_status & ROK)) {	    /* There was an error. */
+	  lp->stats.rx_errors++;            /* Update the error stats. */
+	  if (rx_status & DBE) lp->stats.rx_frame_errors++;
+	  if (rx_status & CRC) lp->stats.rx_crc_errors++;
+	  if (rx_status & PLL) lp->stats.rx_fifo_errors++;
+	} else {
+	  struct sk_buff *skb;
+
+          if ((skb = alloc_skb(pkt_len, GFP_ATOMIC)) != NULL) {
+	    skb->len = pkt_len;
+	    skb->dev = dev;
+
+	    if (lp->shmem_length == IO_ONLY) {
+	      unsigned char *p = skb->data;
+
+	      *p = inb(EWRK3_DATA);         /* dummy read */
+	      for (i=0; i<skb->len; i++) {
+		*p++ = inb(EWRK3_DATA);
+	      }
+	    } else {
+	      memcpy(skb->data, buf, pkt_len);
+	    }
+
+	    /* 
+	    ** Notify the upper protocol layers that there is another 
+	    ** packet to handle
+	    */
+	    netif_rx(skb);
+
+	    /*
+	    ** Update stats
+	    */
+	    lp->stats.rx_packets++;
+	    for (i=1; i<EWRK3_PKT_STAT_SZ-1; i++) {
+	      if (pkt_len < i*EWRK3_PKT_BIN_SZ) {
+		lp->pktStats.bins[i]++;
+		i = EWRK3_PKT_STAT_SZ;
+	      }
+	    }
+	    buf = skb->data;                  /* Look at the dest addr */
+	    if (buf[0] & 0x01) {              /* Multicast/Broadcast */
+	      if ((*(long *)&buf[0] == -1) && (*(short *)&buf[4] == -1)) {
+		lp->pktStats.broadcast++;
+	      } else {
+		lp->pktStats.multicast++;
+	      }
+	    } else if ((*(long *)&buf[0] == *(long *)&dev->dev_addr[0]) &&
+		       (*(short *)&buf[4] == *(short *)&dev->dev_addr[4])) {
+	      lp->pktStats.unicast++;
+	    }
+
+	    lp->pktStats.bins[0]++;           /* Duplicates stats.rx_packets */
+	    if (lp->pktStats.bins[0] == 0) {  /* Reset counters */
+	      memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+	    }
+	  } else {
+	    printk("%s: Insufficient memory; nuking packet.\n", dev->name);
+	    lp->stats.rx_dropped++;	      /* Really, deferred. */
+	    break;
+	  }
+        }
+      }
+      /*
+      ** Return the received buffer to the free memory queue
+      */
+      outb(page, EWRK3_FMQ);
+
+      if (tmpLock) {                          /* If a lock was preempted */
+	if (lp->shmem_length == IO_ONLY) {    /* Replace old page */
+	  outb(tmpPage, EWRK3_IOPR);
+	} else {
+	  outb(tmpPage, EWRK3_MPR);
+	}
+      }
+      lp->lock = 0;                           /* Unlock the page register */
+    } else {
+      printk("ewrk3_rx(): Illegal page number, page %d\n",page);
+      printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n",inb(EWRK3_CSR),inb(EWRK3_ICR),inb(EWRK3_FMQC));
+    }
+  }
+  return status;
+}
+
+/*
+** Buffer sent - check for TX buffer errors.
+*/
+static int
+ewrk3_tx(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  unsigned char tx_status;
+
+  while ((tx_status = inb(EWRK3_TDQ)) > 0) {  /* Whilst there's old buffers */
+    if (tx_status & VSTS) {                   /* The status is valid */
+      if (tx_status & MAC_TXE) {
+	lp->stats.tx_errors++;
+	if (tx_status & MAC_NCL)    lp->stats.tx_carrier_errors++;
+	if (tx_status & MAC_LCL)    lp->stats.tx_window_errors++;
+	if (tx_status & MAC_CTU) {
+	  if ((tx_status & MAC_COLL) ^ MAC_XUR) {
+	    lp->pktStats.tx_underruns++;
+	  } else {
+	    lp->pktStats.excessive_underruns++;
+	  }
+	} else 	if (tx_status & MAC_COLL) {
+	  if ((tx_status & MAC_COLL) ^ MAC_XCOLL) {
+	    lp->stats.collisions++;
+	  } else {
+	    lp->pktStats.excessive_collisions++;
+	  }
+	}
+      } else {
+	lp->stats.tx_packets++;
+      }
+    }
+  }
+
+  return 0;
+}
+
+static int
+ewrk3_close(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  unsigned char icr, csr;
+
+  dev->start = 0;
+  dev->tbusy = 1;
+
+  if (ewrk3_debug > 1) {
+    printk("%s: Shutting down ethercard, status was %2.2x.\n",
+	   dev->name, inb(EWRK3_CSR));
+  }
+
+  /* 
+  ** We stop the EWRK3 here... mask interrupts and stop TX & RX
+  */
+  DISABLE_IRQs;
+
+  STOP_EWRK3;
+
+  /*
+  ** Clean out the TX and RX queues here (note that one entry
+  ** may get added to either the TXD or RX queues if the the TX or RX
+  ** just starts processing a packet before the STOP_EWRK3 command
+  ** is received. This will be flushed in the ewrk3_open() call).
+  */
+  while (inb(EWRK3_TQ));
+  while (inb(EWRK3_TDQ));
+  while (inb(EWRK3_RQ));
+
+  if (!lp->hard_strapped) {
+    free_irq(dev->irq);
+    
+    irq2dev_map[dev->irq] = 0;
+  }
+
+#ifdef MODULE
+  MOD_DEC_USE_COUNT;
+#endif    
+
+  return 0;
+}
+
+static struct enet_statistics *
+ewrk3_get_stats(struct device *dev)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+
+  /* Null body since there is no framing error counter */
+    
+  return &lp->stats;
+}
+
+/*
+** Set or clear the multicast filter for this adaptor.
+** num_addrs == -1	Promiscuous mode, receive all packets
+** num_addrs == 0	Normal mode, clear multicast list
+** num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+** 			best-effort filtering.
+*/
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  char *multicast_table;
+  unsigned char csr;
+
+  csr = inb(EWRK3_CSR);
+
+  if (lp->shmem_length == IO_ONLY) {
+    multicast_table = (char *) PAGE0_HTE;
+  } else {
+    multicast_table = (char *)(lp->shmem_base + PAGE0_HTE);
+  }
+
+  if (num_addrs >= 0) {
+    SetMulticastFilter(dev, num_addrs, (char *)addrs, multicast_table);
+    csr &= ~PME;
+    csr |= MCE;
+    outb(csr, EWRK3_CSR);
+  } else {                             /* set promiscuous mode */
+    csr |= PME;
+    csr &= ~MCE;
+    outb(csr, EWRK3_CSR);
+  }
+}
+
+/*
+** Calculate the hash code and update the logical address filter
+** from a list of ethernet multicast addresses.
+** Derived from a 'C' program in the AMD data book:
+** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", 
+** Pub #17781, Rev. A, May 1993
+**
+*/
+static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  int iobase = dev->base_addr;
+  char j, ctrl, bit, octet;
+  short *p = (short *) multicast_table;
+  unsigned short hashcode;
+  int i;
+  long int crc, poly = (long int) CRC_POLYNOMIAL;
+
+  while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+
+  if (lp->shmem_length == IO_ONLY) {
+    outb(0, EWRK3_IOPR);
+    outw((short)((long)multicast_table), EWRK3_PIR1);
+  } else {
+    outb(0, EWRK3_MPR);
+  }
+
+  if (num_addrs == HASH_TABLE_LEN) {
+    for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
+      if (lp->shmem_length == IO_ONLY) {
+	outb(0xff, EWRK3_DATA);
+      } else {                /* memset didn't work here */
+	*p++ = 0xffff;
+	i++;
+      }
+    }
+  } else if (num_addrs == 0) {
+    if (lp->shmem_length == IO_ONLY) {
+      for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
+	outb(0x00, EWRK3_DATA);
+      } 
+    } else {
+      memset(multicast_table, 0, (HASH_TABLE_LEN >> 3));
+    }
+  } else {
+    for (i=0;i<num_addrs;i++) {              /* for each address in the list */
+      if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* multicast address? */ 
+	crc = (long int) 0xffffffff;         /* init CRC for each address */
+	for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
+	  for(j=0;j<8;j++) {                 /* process each address bit */
+	    bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
+	    ctrl = ((crc < 0) ? 1 : 0);      /* shift the control bit */
+	    crc <<= 1;                       /* shift the CRC */
+	    if (bit ^ ctrl) {                /* (bit) XOR (control bit) */
+	      crc ^= poly;                   /* (CRC) XOR (polynomial) */
+	    }
+	  }
+	}
+	hashcode = (crc & 0x01);             /* hashcode is 9 LSb of CRC ... */
+	for (j=0;j<8;j++) {                  /* ... in reverse order. */
+	  hashcode <<= 1;
+	  crc >>= 1;
+	  hashcode |= (crc & 0x01);
+	}                                      
+	octet = hashcode >> 3;               /* bit[3-8] -> octet in filter */
+	                                     /* bit[0-2] -> bit in octet */
+	if (lp->shmem_length == IO_ONLY) {
+	  unsigned char tmp;
+
+	  outw((short)((long)multicast_table) + octet, EWRK3_PIR1);
+	  tmp = inb(EWRK3_DATA);
+	  tmp |= (1 << (hashcode & 0x07));
+	  outw((short)((long)multicast_table) + octet, EWRK3_PIR1);
+	  outb(tmp, EWRK3_DATA); 
+	} else {
+	  multicast_table[octet] |= (1 << (hashcode & 0x07));
+	}
+      }
+    }
+  }
+
+  lp->lock = 0;                              /* Unlock the page register */
+
+  return;
+}
+
+#ifndef MODULE
+/*
+** ISA bus I/O device probe
+*/
+static struct device *isa_probe(struct device *dev)
+{
+  int i, iobase, status;
+  unsigned long int tmp = mem_chkd;
+
+  for (status = -ENODEV, iobase = EWRK3_IO_BASE,i = 0; 
+       i < 24;
+       iobase += EWRK3_IOP_INC, i++) {
+    if (tmp & 0x01) {
+      if (DevicePresent(iobase) == 0) {
+/*
+** Device found. Mark its (I/O) location for future reference. Only 24
+** EtherWORKS devices can exist between 0x100 and 0x3e0.
+*/
+	if (num_ewrk3s > 0) {        /* only gets here in autoprobe */
+	  dev = alloc_device(dev, iobase);
+	} else {
+	  if ((status = ewrk3_hw_init(dev, iobase)) == 0) {
+	    num_ewrk3s++;
+	  }
+	}
+	num_eth++;
+      } else {
+	mem_chkd &= ~(0x01 << ((iobase - EWRK3_IO_BASE)/EWRK3_IOP_INC));
+      }
+    }
+    tmp >>= 1;
+  }
+
+  return dev;
+}
+
+/*
+** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
+** the motherboard.
+*/
+static struct device *eisa_probe(struct device *dev)
+{
+  int i, iobase = EWRK3_EISA_IO_PORTS;
+  int status;
+
+  iobase+=EISA_SLOT_INC;            /* get the first slot address */
+  for (status = -ENODEV, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
+
+    if (DevicePresent(iobase) == 0) {
+/*
+** Device found. Mark its slot location for future reference. Only 7
+** EtherWORKS devices can exist in EISA space....
+*/
+      mem_chkd |= (0x01 << (i + 24));
+      if (num_ewrk3s > 0) {        /* only gets here in autoprobe */
+	dev = alloc_device(dev, iobase);
+      } else {
+	if ((status = ewrk3_hw_init(dev, iobase)) == 0) {
+	  num_ewrk3s++;
+	}
+      }
+      num_eth++;
+    }
+  }
+  return dev;
+}
+
+/*
+** Allocate the device by pointing to the next available space in the
+** device structure. Should one not be available, it is created.
+*/
+static struct device *alloc_device(struct device *dev, int iobase)
+{
+  /*
+  ** Check the device structures for an end of list or unused device
+  */
+  while (dev->next != NULL) {
+    if (dev->next->base_addr == 0xffe0) break;
+    dev = dev->next;         /* walk through eth device list */
+    num_eth++;               /* increment eth device number */
+  }
+
+  /*
+  ** If no more device structures, malloc one up. If memory could
+  ** not be allocated, print an error message.
+  */
+  if (dev->next == NULL) {
+    dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+					 GFP_KERNEL);
+    if (dev->next == NULL) {
+      printk("eth%d: Device not initialised, insufficient memory\n",
+	     num_eth);
+    }
+  }
+  
+  /*
+  ** If the memory was allocated, point to the new memory area
+  ** and initialize it (name, I/O address, next device (NULL) and
+  ** initialisation probe routine).
+  */
+  if ((dev->next != NULL) &&
+      (num_eth > 0) && (num_eth < 9999)) {
+    dev = dev->next;                    /* point to the new device */
+    dev->name = (char *)(dev + sizeof(struct device));
+    sprintf(dev->name,"eth%d", num_eth);/* New device name */
+    dev->base_addr = iobase;            /* assign the io address */
+    dev->next = NULL;                   /* mark the end of list */
+    dev->init = &ewrk3_probe;           /* initialisation routine */
+    num_ewrk3s++;
+  }
+
+  return dev;
+}
+#endif    /* MODULE */
+
+/*
+** Read the EWRK3 EEPROM using this routine
+*/
+static int Read_EEPROM(short iobase, unsigned char eaddr)
+{
+  int i;
+
+  outb((eaddr & 0x3f), EWRK3_PIR1);     /* set up 6 bits of address info */
+  outb(EEPROM_RD, EWRK3_IOPR);          /* issue read command */
+  for (i=0;i<5000;i++) inb(EWRK3_CSR);  /* wait 1msec */
+
+  return inw(EWRK3_EPROM1);             /* 16 bits data return */
+}
+
+/*
+** Write the EWRK3 EEPROM using this routine
+*/
+static int Write_EEPROM(short data, short iobase, unsigned char eaddr)
+{
+  int i;
+
+  outb(EEPROM_WR_EN, EWRK3_IOPR);       /* issue write enable command */
+  for (i=0;i<5000;i++) inb(EWRK3_CSR);  /* wait 1msec */
+  outw(data, EWRK3_EPROM1);             /* write data to register */
+  outb((eaddr & 0x3f), EWRK3_PIR1);     /* set up 6 bits of address info */
+  outb(EEPROM_WR, EWRK3_IOPR);          /* issue write command */
+  for (i=0;i<75000;i++) inb(EWRK3_CSR); /* wait 15msec */
+  outb(EEPROM_WR_DIS, EWRK3_IOPR);      /* issue write disable command */
+  for (i=0;i<5000;i++) inb(EWRK3_CSR);  /* wait 1msec */
+
+  return 0;
+}
+
+/*
+** Look for a particular board name in the on-board EEPROM.
+*/
+static void EthwrkSignature(char *name, char *eeprom_image)
+{
+  unsigned long i,j,k;
+  char signatures[][EWRK3_NAME_LENGTH] = EWRK3_SIGNATURE;
+
+  strcpy(name, "");
+  for (i=0;*signatures[i] != '\0' && *name == '\0';i++) {
+    for (j=EEPROM_PNAME7,k=0;j<=EEPROM_PNAME0 && k<strlen(signatures[i]);j++) {
+      if (signatures[i][k] == eeprom_image[j]) {          /* track signature */
+	k++;
+      } else {                         /* lost signature; begin search again */
+	k=0;
+      }
+    }
+    if (k == strlen(signatures[i])) {
+      for (k=0; k<EWRK3_NAME_LENGTH; k++) {
+	name[k] = eeprom_image[EEPROM_PNAME7 + k];
+	name[EWRK3_NAME_LENGTH] = '\0';
+      }
+    }
+  }
+
+  return;                                   /* return the device name string */
+}
+
+/*
+** Look for a special sequence in the Ethernet station address PROM that
+** is common across all EWRK3 products.
+*/
+
+static int DevicePresent(short iobase)
+{
+  static short fp=1,sigLength=0;
+  static char devSig[] = PROBE_SEQUENCE;
+  char data;
+  int i, j, status = 0;
+  static char asc2hex(char value);
+
+/* 
+** Convert the ascii signature to a hex equivalent & pack in place 
+*/
+  if (fp) {                               /* only do this once!... */
+    for (i=0,j=0;devSig[i] != '\0' && !status;i+=2,j++) {
+      if ((devSig[i]=asc2hex(devSig[i]))>=0) {
+	devSig[i]<<=4;
+	if((devSig[i+1]=asc2hex(devSig[i+1]))>=0){
+	  devSig[j]=devSig[i]+devSig[i+1];
+	} else {
+	  status= -1;
+	}
+      } else {
+	status= -1;
+      }
+    }
+    sigLength=j;
+    fp = 0;
+  }
+
+/* 
+** Search the Ethernet address ROM for the signature. Since the ROM address
+** counter can start at an arbitrary point, the search must include the entire
+** probe sequence length plus the (length_of_the_signature - 1).
+** Stop the search IMMEDIATELY after the signature is found so that the
+** PROM address counter is correctly positioned at the start of the
+** ethernet address for later read out.
+*/
+  if (!status) {
+    for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
+      data = inb(EWRK3_APROM);
+      if (devSig[j] == data) {    /* track signature */
+	j++;
+      } else {                    /* lost signature; begin search again */
+	j=0;
+      }
+    }
+
+    if (j!=sigLength) {
+      status = -ENODEV;           /* search failed */
+    }
+  }
+
+  return status;
+}
+
+static unsigned char aprom_crc(struct device *dev, unsigned char *eeprom_image, char chipType)
+{
+  long k;
+  unsigned short j,chksum;
+  unsigned char crc, lfsr, sd, status = 0;
+  int iobase = dev->base_addr;
+
+  if (chipType == LeMAC2) {
+    for (crc=0x6a, j=0; j<ETH_ALEN; j++) {
+      for (sd=inb(EWRK3_PAR0+j), k=0; k<8; k++, sd >>= 1) {
+	lfsr = ((((crc & 0x02) >> 1) ^ (crc & 0x01)) ^ (sd & 0x01)) << 7;
+	crc = (crc >> 1) + lfsr;
+      }
+    }
+    if (crc != eeprom_image[EEPROM_PA_CRC]) status = -1;
+  } else {
+    for (k=0,j=0;j<3;j++) {
+      k <<= 1 ;
+      if (k > 0xffff) k-=0xffff;
+      k += inw(EWRK3_PAR0 + (j<<1));
+      if (k > 0xffff) k-=0xffff;
+    }
+    if (k == 0xffff) k=0;
+    chksum = inb(EWRK3_APROM);
+    chksum |= (inb(EWRK3_APROM)<<8);
+    if (k != chksum) status = -1;
+  }
+
+  return status;
+}
+
+/*
+** Perform IOCTL call functions here. Some are privileged operations and the
+** effective uid is checked in those cases.
+*/
+static int ewrk3_ioctl(struct device *dev, struct ifreq *rq)
+{
+  struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
+  struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_data;
+  int i, j, iobase = dev->base_addr, status = 0;
+  unsigned char csr;
+  union {
+    unsigned char addr[HASH_TABLE_LEN * ETH_ALEN];
+    unsigned short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+  } tmp;
+
+  switch(ioc->cmd) {
+  case EWRK3_GET_HWADDR:             /* Get the hardware address */
+    for (i=0; i<ETH_ALEN; i++) {
+      tmp.addr[i] = dev->dev_addr[i];
+    }
+    ioc->len = ETH_ALEN;
+    memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+
+    break;
+  case EWRK3_SET_HWADDR:             /* Set the hardware address */
+    if (suser()) {
+      csr = inb(EWRK3_CSR);
+      csr |= (TXD|RXD);
+      outb(csr, EWRK3_CSR);                  /* Disable the TX and RX */
+
+      memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
+      for (i=0; i<ETH_ALEN; i++) {
+	dev->dev_addr[i] = tmp.addr[i];
+	outb(tmp.addr[i], EWRK3_PAR0 + i);
+      }
+
+      csr &= ~(TXD|RXD);                       /* Enable the TX and RX */
+      outb(csr, EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_SET_PROM:               /* Set Promiscuous Mode */
+    if (suser()) {
+      csr = inb(EWRK3_CSR);
+      csr |= PME;
+      csr &= ~MCE;
+      outb(csr, EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_CLR_PROM:               /* Clear Promiscuous Mode */
+    if (suser()) {
+      csr = inb(EWRK3_CSR);
+      csr &= ~PME;
+      outb(csr, EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_SAY_BOO:                /* Say "Boo!" to the kernel log file */
+    printk("%s: Boo!\n", dev->name);
+
+    break;
+  case EWRK3_GET_MCA:                /* Get the multicast address table */
+    while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
+    if (lp->shmem_length == IO_ONLY) {
+      outb(0, EWRK3_IOPR);
+      outw(PAGE0_HTE, EWRK3_PIR1);
+      for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
+	tmp.addr[i] = inb(EWRK3_DATA);
+      }
+    } else {
+      outb(0, EWRK3_MPR);
+      memcpy(tmp.addr, (char *)(lp->shmem_base + PAGE0_HTE), (HASH_TABLE_LEN >> 3));
+    }
+    ioc->len = (HASH_TABLE_LEN >> 3);
+    memcpy_tofs(ioc->data, tmp.addr, ioc->len); 
+    lp->lock = 0;                               /* Unlock the page register */
+
+    break;
+  case EWRK3_SET_MCA:                /* Set a multicast address */
+    if (suser()) {
+      if (ioc->len != HASH_TABLE_LEN) {         /* MCA changes */
+	memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+      }
+      set_multicast_list(dev, ioc->len, tmp.addr);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_CLR_MCA:                /* Clear all multicast addresses */
+    if (suser()) {
+      set_multicast_list(dev, 0, NULL);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_MCA_EN:                 /* Enable multicast addressing */
+    if (suser()) {
+      csr = inb(EWRK3_CSR);
+      csr |= MCE;
+      csr &= ~PME;
+      outb(csr, EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_GET_STATS:              /* Get the driver statistics */
+    cli();
+    memcpy_tofs(ioc->data, &lp->pktStats, sizeof(lp->pktStats)); 
+    ioc->len = EWRK3_PKT_STAT_SZ;
+    sti();
+
+    break;
+  case EWRK3_CLR_STATS:              /* Zero out the driver statistics */
+    if (suser()) {
+      cli();
+      memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+      sti();
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_GET_CSR:                /* Get the CSR Register contents */
+    tmp.addr[0] = inb(EWRK3_CSR);
+    memcpy_tofs(ioc->data, tmp.addr, 1);
+
+    break;
+  case EWRK3_SET_CSR:                /* Set the CSR Register contents */
+    if (suser()) {
+      memcpy_fromfs(tmp.addr, ioc->data, 1);
+      outb(tmp.addr[0], EWRK3_CSR);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_GET_EEPROM:             /* Get the EEPROM contents */
+    if (suser()) {
+      for (i=0; i<(EEPROM_MAX>>1); i++) {
+	tmp.val[i] = (short)Read_EEPROM(iobase, i);
+      }
+      i = EEPROM_MAX;
+      tmp.addr[i++] = inb(EWRK3_CMR);            /* Config/Management Reg. */
+      for (j=0;j<ETH_ALEN;j++) {
+	tmp.addr[i++] = inb(EWRK3_PAR0 + j);
+      }
+      ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
+      memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_SET_EEPROM:             /* Set the EEPROM contents */
+    if (suser()) {
+      memcpy_fromfs(tmp.addr, ioc->data, EEPROM_MAX);
+      for (i=0; i<(EEPROM_MAX>>1); i++) {
+	Write_EEPROM(tmp.val[i], iobase, i);
+      }
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_GET_CMR:                /* Get the CMR Register contents */
+    tmp.addr[0] = inb(EWRK3_CMR);
+    memcpy_tofs(ioc->data, tmp.addr, 1);
+
+    break;
+  case EWRK3_SET_TX_CUT_THRU:        /* Set TX cut through mode */
+    if (suser()) {
+      lp->txc = 1;
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  case EWRK3_CLR_TX_CUT_THRU:        /* Clear TX cut through mode */
+    if (suser()) {
+      lp->txc = 0;
+    } else {
+      status = -EPERM;
+    }
+
+    break;
+  default:
+    status = -EOPNOTSUPP;
+  }
+
+  return status;
+}
+
+static char asc2hex(char value)
+{
+  value -= 0x30;                  /* normalise to 0..9 range */
+  if (value >= 0) {
+    if (value > 9) {              /* but may not be 10..15 */
+      value &= 0x1f;              /* make A..F & a..f be the same */
+      value -= 0x07;              /* normalise to 10..15 range */
+      if ((value < 0x0a) || (value > 0x0f)) { /* if outside range then... */
+	value = -1;               /* ...signal error */
+      }
+    }
+  } else {                        /* outside 0..9 range... */
+    value = -1;                   /* ...signal error */
+  }
+  return value;                   /* return hex char or error */
+}
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device thisEthwrk = {
+  "        ", /* device name inserted by /linux/drivers/net/net_init.c */
+  0, 0, 0, 0,
+  0x300, 5,  /* I/O address, IRQ <--- EDIT THIS LINE FOR YOUR CONFIGURATION */
+  0, 0, 0, NULL, ewrk3_probe };
+	
+int
+init_module(void)
+{
+  if (register_netdev(&thisEthwrk) != 0)
+    return -EIO;
+  return 0;
+}
+
+void
+cleanup_module(void)
+{
+  if (MOD_IN_USE) {
+    printk("%s: device busy, remove delayed\n",thisEthwrk.name);
+  } else {
+    unregister_netdev(&thisEthwrk);
+  }
+}
+#endif /* MODULE */
+
+
+/*
+ * Local variables:
+ *  kernel-compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c ewrk3.c"
+ *
+ *  module-compile-command: "gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c ewrk3.c"
+ * End:
+ */
+
+
+
diff -u --recursive --new-file v1.1.60/linux/drivers/net/ewrk3.h linux/drivers/net/ewrk3.h
--- v1.1.60/linux/drivers/net/ewrk3.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/ewrk3.h	Wed Nov  2 11:38:34 1994
@@ -0,0 +1,319 @@
+/*
+    Written 1994 by David C. Davies.
+
+    Copyright 1994 Digital Equipment Corporation.
+
+    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 davies@wanton.lkg.dec.com  or   Digital
+    Equipment Corporation, 550 King Street, Littleton MA 01460.
+
+    =========================================================================
+*/
+
+/*
+** I/O Address Register Map
+*/
+#define EWRK3_CSR    iobase+0x00   /* Control and Status Register */
+#define EWRK3_CR     iobase+0x01   /* Control Register */
+#define EWRK3_ICR    iobase+0x02   /* Interrupt Control Register */
+#define EWRK3_TSR    iobase+0x03   /* Transmit Status Register */
+#define EWRK3_RSVD1  iobase+0x04   /* RESERVED */
+#define EWRK3_RSVD2  iobase+0x05   /* RESERVED */
+#define EWRK3_FMQ    iobase+0x06   /* Free Memory Queue */
+#define EWRK3_FMQC   iobase+0x07   /* Free Memory Queue Counter */
+#define EWRK3_RQ     iobase+0x08   /* Receive Queue */
+#define EWRK3_RQC    iobase+0x09   /* Receive Queue Counter */
+#define EWRK3_TQ     iobase+0x0a   /* Transmit Queue */
+#define EWRK3_TQC    iobase+0x0b   /* Transmit Queue Counter */
+#define EWRK3_TDQ    iobase+0x0c   /* Transmit Done Queue */
+#define EWRK3_TDQC   iobase+0x0d   /* Transmit Done Queue Counter */
+#define EWRK3_PIR1   iobase+0x0e   /* Page Index Register 1 */
+#define EWRK3_PIR2   iobase+0x0f   /* Page Index Register 2 */
+#define EWRK3_DATA   iobase+0x10   /* Data Register */
+#define EWRK3_IOPR   iobase+0x11   /* I/O Page Register */
+#define EWRK3_IOBR   iobase+0x12   /* I/O Base Register */
+#define EWRK3_MPR    iobase+0x13   /* Memory Page Register */
+#define EWRK3_MBR    iobase+0x14   /* Memory Base Register */
+#define EWRK3_APROM  iobase+0x15   /* Address PROM */
+#define EWRK3_EPROM1 iobase+0x16   /* EEPROM Data Register 1 */
+#define EWRK3_EPROM2 iobase+0x17   /* EEPROM Data Register 2 */
+#define EWRK3_PAR0   iobase+0x18   /* Physical Address Register 0 */
+#define EWRK3_PAR1   iobase+0x19   /* Physical Address Register 1 */
+#define EWRK3_PAR2   iobase+0x1a   /* Physical Address Register 2 */
+#define EWRK3_PAR3   iobase+0x1b   /* Physical Address Register 3 */
+#define EWRK3_PAR4   iobase+0x1c   /* Physical Address Register 4 */
+#define EWRK3_PAR5   iobase+0x1d   /* Physical Address Register 5 */
+#define EWRK3_CMR    iobase+0x1e   /* Configuration/Management Register */
+
+/*
+** Control Page Map
+*/
+#define PAGE0_FMQ     0x000         /* Free Memory Queue */
+#define PAGE0_RQ      0x080         /* Receive Queue */
+#define PAGE0_TQ      0x100         /* Transmit Queue */
+#define PAGE0_TDQ     0x180         /* Transmit Done Queue */
+#define PAGE0_HTE     0x200         /* Hash Table Entries */
+#define PAGE0_RSVD    0x240         /* RESERVED */
+#define PAGE0_USRD    0x600         /* User Data */
+
+/*
+** Control and Status Register bit definitions (EWRK3_CSR)
+*/
+#define RA		0x80	    /* Runt Accept */
+#define PME		0x40	    /* Promiscuous Mode Enable */
+#define MCE		0x20	    /* Multicast Enable */ 
+#define TNE		0x08	    /* TX Done Queue Not Empty */
+#define RNE		0x04	    /* RX Queue Not Empty */
+#define TXD		0x02	    /* TX Disable */
+#define RXD		0x01	    /* RX Disable */
+
+/*
+** Control Register bit definitions (EWRK3_CR)
+*/
+#define APD		0x80	/* Auto Port Disable */
+#define PSEL		0x40	/* Port Select (0->TP port) */
+#define LBCK		0x20	/* LoopBaCK enable */
+#define FDUP		0x10	/* Full DUPlex enable */
+#define FBUS		0x08	/* Fast BUS enable (ISA clk > 8.33MHz) */
+#define EN_16		0x04	/* ENable 16 bit memory accesses */
+#define LED		0x02	/* LED (1-> turn on) */
+
+/*
+** Interrupt Control Register bit definitions (EWRK3_ICR)
+*/
+#define IE		0x80	/* Interrupt Enable */
+#define IS		0x60	/* Interrupt Selected */
+#define TNEM		0x08	/* TNE Mask (0->mask) */
+#define RNEM		0x04	/* RNE Mask (0->mask) */
+#define TXDM		0x02	/* TXD Mask (0->mask) */
+#define RXDM		0x01	/* RXD Mask (0->mask) */
+
+/*
+** Transmit Status Register bit definitions (EWRK3_TSR)
+*/
+#define NCL		0x80	/* No Carrier Loopback */
+#define ID		0x40	/* Initially Deferred */
+#define LCL		0x20	/* Late CoLlision */
+#define ECL		0x10	/* Excessive CoLlisions */
+#define RCNTR		0x0f	/* Retries CouNTeR */
+
+/*
+** I/O Page Register bit definitions (EWRK3_IOPR)
+*/
+#define EEPROM_INIT	0xc0	/* EEPROM INIT command */
+#define EEPROM_WR_EN	0xc8	/* EEPROM WRITE ENABLE command */
+#define EEPROM_WR	0xd0	/* EEPROM WRITE command */
+#define EEPROM_WR_DIS	0xd8	/* EEPROM WRITE DISABLE command */
+#define EEPROM_RD	0xe0	/* EEPROM READ command */
+
+/*
+** I/O Base Register bit definitions (EWRK3_IOBR)
+*/
+#define EISA		0x20	/* Enable EISA ID and Control Registers */
+#define IOB		0x1f	/* Compare bits for I/O Base Address */
+
+/*
+** I/O Congiguration/Management Register bit definitions (EWRK3_CMR)
+*/
+#define RA              0x80    /* Read Ahead */
+#define WB              0x40    /* Write Behind */
+#define LINK		0x20	/* 0->TP */
+#define POLARITY	0x10	/* Informational */
+#define NO_EEPROM	0x0c	/* NO_EEPROM<1:0> pin status */
+#define HS	        0x08	/* Hard Strapped pin status (LeMAC2) */
+#define PNP             0x04    /* Plug 'n Play */
+#define DRAM		0x02	/* 0-> 1DRAM, 1-> 2 DRAM on board */
+#define _0WS            0x01    /* Zero Wait State */
+
+/* 
+** MAC Receive Status Register bit definitions
+*/
+
+#define ROK     	0x80 	/* Receive OK summary */
+#define IAM     	0x10 	/* Individual Address Match */
+#define MCM     	0x08 	/* MultiCast Match */
+#define DBE     	0x04 	/* Dribble Bit Error */
+#define CRC     	0x02 	/* CRC error */
+#define PLL     	0x01 	/* Phase Lock Lost */
+
+/* 
+** MAC Transmit Control Register bit definitions
+*/
+
+#define SQEE    	0x40 	/* SQE Enable - look for heartbeat  */
+#define SED     	0x20 	/* Stop when Error Detected */
+#define QMODE     	0x10 	/* Q_MODE */
+#define LAB             0x08 	/* Less Aggressive Backoff */
+#define PAD     	0x04 	/* PAD Runt Packets */
+#define IFC     	0x02 	/* Insert Frame Check */
+#define ISA     	0x01 	/* Insert Source Address */
+
+/* 
+** MAC Transmit Status Register bit definitions
+*/
+
+#define VSTS    	0x80 	/* Valid STatuS */
+#define MAC_CTU     	0x40 	/* Cut Through Used */
+#define MAC_SQE     	0x20 	/* Signal Quality Error */
+#define MAC_NCL     	0x10 	/* No Carrier Loopback */
+#define MAC_LCL         0x08 	/* Late Collision */
+#define MAC_ID      	0x04 	/* Initially Deferred */
+#define MAC_COLL     	0x03 	/* COLLision status */
+#define MAC_XCOLL       0x03    /* Excessive Collisions */
+#define MAC_MCOLL       0x02    /* Multiple Collisions */
+#define MAC_OCOLL       0x01    /* One Collision */
+#define MAC_NOCOLL      0x00    /* No Collisions */
+#define MAC_XUR         0x03    /* Excessive Underruns */
+#define MAC_TXE         0x7f    /* TX Errors */
+
+/* 
+** EISA Configuration Register bit definitions 
+*/
+
+#define EISA_ID0      iobase + 0x0c80  /* EISA ID Register 0 */ 
+#define EISA_ID1      iobase + 0x0c81  /* EISA ID Register 1 */ 
+#define EISA_ID2      iobase + 0x0c82  /* EISA ID Register 2 */ 
+#define EISA_ID3      iobase + 0x0c83  /* EISA ID Register 3 */ 
+#define EISA_CR       iobase + 0x0c84  /* EISA Control Register */
+
+/*
+** EEPROM BYTES
+*/
+#define EEPROM_MEMB     0x00
+#define EEPROM_IOB      0x01
+#define EEPROM_EISA_ID0 0x02
+#define EEPROM_EISA_ID1 0x03
+#define EEPROM_EISA_ID2 0x04
+#define EEPROM_EISA_ID3 0x05
+#define EEPROM_MISC0    0x06
+#define EEPROM_MISC1    0x07
+#define EEPROM_PNAME7   0x08
+#define EEPROM_PNAME6   0x09
+#define EEPROM_PNAME5   0x0a
+#define EEPROM_PNAME4   0x0b
+#define EEPROM_PNAME3   0x0c
+#define EEPROM_PNAME2   0x0d
+#define EEPROM_PNAME1   0x0e
+#define EEPROM_PNAME0   0x0f
+#define EEPROM_SWFLAGS  0x10
+#define EEPROM_HWCAT    0x11
+#define EEPROM_NETMAN2  0x12
+#define EEPROM_REVLVL   0x13
+#define EEPROM_NETMAN0  0x14
+#define EEPROM_NETMAN1  0x15
+#define EEPROM_CHIPVER  0x16
+#define EEPROM_SETUP    0x17
+#define EEPROM_PADDR0   0x18
+#define EEPROM_PADDR1   0x19
+#define EEPROM_PADDR2   0x1a
+#define EEPROM_PADDR3   0x1b
+#define EEPROM_PADDR4   0x1c
+#define EEPROM_PADDR5   0x1d
+#define EEPROM_PA_CRC   0x1e
+#define EEPROM_CHKSUM   0x1f
+
+/*
+** EEPROM bytes for checksumming
+*/
+#define EEPROM_MAX      32             /* bytes */
+
+/*
+** EEPROM MISCELLANEOUS FLAGS
+*/
+#define RBE_SHADOW	0x0100	/* Remote Boot Enable Shadow */ 
+#define READ_AHEAD      0x0080  /* Read Ahead feature */
+#define IRQ_SEL2        0x0070  /* IRQ line selection (LeMAC2) */
+#define IRQ_SEL         0x0060  /* IRQ line selection */
+#define FAST_BUS        0x0008  /* ISA Bus speeds > 8.33MHz */
+#define ENA_16          0x0004  /* Enables 16 bit memory transfers */
+#define WRITE_BEHIND    0x0002  /* Write Behind feature */
+#define _0WS_ENA        0x0001  /* Zero Wait State Enable */
+
+/*
+** EEPROM NETWORK MANAGEMENT FLAGS
+*/
+#define NETMAN_POL      0x04    /* Polarity defeat */
+#define NETMAN_LINK     0x02    /* Link defeat */
+#define NETMAN_CCE      0x01    /* Custom Counters Enable */
+
+/*
+** EEPROM SW FLAGS
+*/
+#define SW_SQE		0x10	/* Signal Quality Error */ 
+#define SW_LAB		0x08	/* Less Aggressive Backoff */
+#define SW_INIT		0x04	/* Initialized */
+#define SW_TIMEOUT     	0x02	/* 0:2.5 mins, 1: 30 secs */
+#define SW_REMOTE      	0x01    /* Remote Boot Enable -> 1 */
+
+/*
+** EEPROM SETUP FLAGS
+*/
+#define SETUP_APD	0x80	/* AutoPort Disable */
+#define SETUP_PS	0x40	/* Port Select */
+#define SETUP_MP	0x20	/* MultiPort */
+#define SETUP_1TP	0x10	/* 1 port, TP */
+#define SETUP_1COAX	0x00	/* 1 port, Coax */
+#define SETUP_DRAM	0x02	/* Number of DRAMS on board */
+
+/*
+** EEPROM MANAGEMENT FLAGS
+*/
+#define MGMT_CCE	0x01	/* Custom Counters Enable */
+
+/*
+** EEPROM VERSIONS
+*/
+#define LeMAC           0x11
+#define LeMAC2          0x12
+
+/*
+** Miscellaneous
+*/
+
+#define EEPROM_WAIT_TIME 1000    /* Number of microseconds */
+#define EISA_EN         0x0001   /* Enable EISA bus buffers */
+
+#define HASH_TABLE_LEN   512     /* Bits */
+
+#define XCT 0x80                 /* Transmit Cut Through */
+#define PRELOAD 16               /* 4 long words */
+
+#define MASK_INTERRUPTS   1
+#define UNMASK_INTERRUPTS 0
+
+/*
+** Include the IOCTL stuff
+*/
+#include <linux/sockios.h>
+
+#define	EWRK3IOCTL	SIOCDEVPRIVATE
+
+struct ewrk3_ioctl {
+	unsigned short cmd;                /* Command to run */
+	unsigned short len;                /* Length of the data buffer */
+	unsigned char  *data;              /* Pointer to the data buffer */
+};
+
+/* 
+** Recognised commands for the driver 
+*/
+#define EWRK3_GET_HWADDR	0x01 /* Get the hardware address */
+#define EWRK3_SET_HWADDR	0x02 /* Get the hardware address */
+#define EWRK3_SET_PROM  	0x03 /* Set Promiscuous Mode */
+#define EWRK3_CLR_PROM  	0x04 /* Clear Promiscuous Mode */
+#define EWRK3_SAY_BOO	        0x05 /* Say "Boo!" to the kernel log file */
+#define EWRK3_GET_MCA   	0x06 /* Get a multicast address */
+#define EWRK3_SET_MCA   	0x07 /* Set a multicast address */
+#define EWRK3_CLR_MCA    	0x08 /* Clear a multicast address */
+#define EWRK3_MCA_EN    	0x09 /* Enable a multicast address group */
+#define EWRK3_GET_STATS  	0x0a /* Get the driver statistics */
+#define EWRK3_CLR_STATS 	0x0b /* Zero out the driver statistics */
+#define EWRK3_GET_CSR   	0x0c /* Get the CSR Register contents */
+#define EWRK3_SET_CSR   	0x0d /* Set the CSR Register contents */
+#define EWRK3_GET_EEPROM   	0x0e /* Get the EEPROM contents */
+#define EWRK3_SET_EEPROM	0x0f /* Set the EEPROM contents */
+#define EWRK3_GET_CMR   	0x10 /* Get the CMR Register contents */
+#define EWRK3_CLR_TX_CUT_THRU  	0x11 /* Clear the TX cut through mode */
+#define EWRK3_SET_TX_CUT_THRU	0x12 /* Set the TX cut through mode */
diff -u --recursive --new-file v1.1.60/linux/fs/block_dev.c linux/fs/block_dev.c
--- v1.1.60/linux/fs/block_dev.c	Sun Sep 18 05:26:48 1994
+++ linux/fs/block_dev.c	Wed Nov  2 13:47:52 1994
@@ -24,7 +24,7 @@
 	loff_t offset;
 	int chars;
 	int written = 0;
-	int cluster_list[4];
+	int cluster_list[8];
 	struct buffer_head * bhlist[NBUF];
 	int blocks_per_cluster;
 	unsigned int size;
@@ -159,7 +159,7 @@
 	int blocksize_bits, i;
 	unsigned int blocks, rblocks, left;
 	int bhrequest, uptodate;
-	int cluster_list[4];
+	int cluster_list[8];
 	int blocks_per_cluster;
 	struct buffer_head ** bhb, ** bhe;
 	struct buffer_head * buflist[NBUF];
diff -u --recursive --new-file v1.1.60/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v1.1.60/linux/fs/minix/inode.c	Mon Apr 18 11:38:18 1994
+++ linux/fs/minix/inode.c	Wed Nov  2 12:47:08 1994
@@ -122,6 +122,7 @@
 	if (32 != sizeof (struct minix_inode))
 		panic("bad i-node size");
 	lock_super(s);
+	set_blocksize(dev, BLOCK_SIZE);
 	if (!(bh = bread(dev,1,BLOCK_SIZE))) {
 		s->s_dev=0;
 		unlock_super(s);
diff -u --recursive --new-file v1.1.60/linux/fs/msdos/fat.c linux/fs/msdos/fat.c
--- v1.1.60/linux/fs/msdos/fat.c	Sat Apr 30 13:02:26 1994
+++ linux/fs/msdos/fat.c	Wed Nov  2 11:43:48 1994
@@ -20,7 +20,6 @@
 {
 	struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
 	unsigned char *p_first,*p_last;
-	void *data,*data2,*c_data,*c_data2;
 	int first,last,next,copy;
 
 	if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0;
@@ -30,17 +29,15 @@
 		last = first+1;
 	}
 	if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
-	    SECTOR_BITS),&data))) {
+	    SECTOR_BITS)))) {
 		printk("bread in fat_access failed\n");
 		return 0;
 	}
-	if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) {
+	if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS))
 		bh2 = bh;
-		data2 = data;
-	}
 	else {
 		if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
-		    >> SECTOR_BITS),&data2))) {
+		    >> SECTOR_BITS)))) {
 			brelse(bh);
 			printk("bread in fat_access failed\n");
 			return 0;
@@ -48,13 +45,13 @@
 	}
 	if (MSDOS_SB(sb)->fat_bits == 16) {
 		p_first = p_last = NULL; /* GCC needs that stuff */
-		next = CF_LE_W(((unsigned short *) data)[(first &
+		next = CF_LE_W(((unsigned short *) bh->b_data)[(first &
 		    (SECTOR_SIZE-1)) >> 1]);
 		if (next >= 0xfff7) next = -1;
 	}
 	else {
-		p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)];
-		p_last = &((unsigned char *) data2)[(first+1) &
+		p_first = &((unsigned char *) bh->b_data)[first & (SECTOR_SIZE-1)];
+		p_last = &((unsigned char *) bh2->b_data)[(first+1) &
 		    (SECTOR_SIZE-1)];
 		if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
 		else next = (*p_first+(*p_last << 8)) & 0xfff;
@@ -62,7 +59,7 @@
 	}
 	if (new_value != -1) {
 		if (MSDOS_SB(sb)->fat_bits == 16)
-			((unsigned short *) data)[(first & (SECTOR_SIZE-1)) >>
+			((unsigned short *) bh->b_data)[(first & (SECTOR_SIZE-1)) >>
 			    1] = CT_LE_W(new_value);
 		else {
 			if (nr & 1) {
@@ -79,25 +76,25 @@
 		for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
 			if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->
 			    fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->
-			    fat_length*copy,&c_data))) break;
-			memcpy(c_data,data,SECTOR_SIZE);
+			    fat_length*copy))) break;
+			memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE);
 			mark_buffer_dirty(c_bh, 1);
-			if (data != data2 || bh != bh2) {
+			if (bh != bh2) {
 				if (!(c_bh2 = msdos_sread(sb->s_dev,
 				    MSDOS_SB(sb)->fat_start+(first >>
 				    SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy
-				    +1,&c_data2))) {
+				    +1))) {
 					brelse(c_bh);
 					break;
 				}
-				memcpy(c_data2,data2,SECTOR_SIZE);
+				memcpy(c_bh2->b_data,bh2->b_data,SECTOR_SIZE);
 				brelse(c_bh2);
 			}
 			brelse(c_bh);
 		}
 	}
 	brelse(bh);
-	if (data != data2) brelse(bh2);
+	if (bh != bh2) brelse(bh2);
 	return next;
 }
 
diff -u --recursive --new-file v1.1.60/linux/fs/msdos/file.c linux/fs/msdos/file.c
--- v1.1.60/linux/fs/msdos/file.c	Wed Nov  2 12:03:46 1994
+++ linux/fs/msdos/file.c	Wed Nov  2 11:43:48 1994
@@ -30,7 +30,7 @@
 	NULL,			/* readdir - bad */
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
-	generic_mmap,	/* mmap */
+	generic_mmap,		/* mmap */
 	NULL,			/* no special open is needed */
 	NULL,			/* release */
 	file_fsync		/* fsync */
@@ -52,7 +52,7 @@
 	msdos_bmap,		/* bmap */
 	msdos_truncate,		/* truncate */
 	NULL,			/* permission */
-	NULL		/* smap */
+	NULL			/* smap */
 };
 
 /*
@@ -127,12 +127,11 @@
 			int sector;
 			if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
 				break;
-			if (!(bh = msdos_sread(inode->i_dev,sector,&data)))
+			if (!(bh = msdos_sread(inode->i_dev,sector)))
 				break;
 		}else{
 			bh = pre.bhlist[pre.nolist];
 			pre.bhlist[pre.nolist++] = NULL;
-			data = bh->b_data;
 			wait_on_buffer(bh);
 			if (!bh->b_uptodate){
 				/* read error  ? */
@@ -140,6 +139,7 @@
 				break;
 			}
 		}
+		data = bh->b_data;
 		offset = filp->f_pos & (SECTOR_SIZE-1);
 		filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
 		if (MSDOS_I(inode)->i_binary) {
@@ -183,7 +183,6 @@
 	int error,carry;
 	char *start,*to,ch;
 	struct buffer_head *bh;
-	void *data;
 	int binary_mode = MSDOS_I(inode)->i_binary;
 
 	if (!inode) {
@@ -211,25 +210,28 @@
 		}
 		offset = filp->f_pos & (SECTOR_SIZE-1);
 		size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
-		if (binary_mode && offset == 0 && size == SECTOR_SIZE){
+		if (binary_mode
+			&& offset == 0
+			&& (size == SECTOR_SIZE
+				|| filp->f_pos + size >= inode->i_size)){
 			/* No need to read the block first since we will */
 			/* completely overwrite it */
+			/* or at least write past the end of file */
 			if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){
 				error = -EIO;
 				break;
 			}
-			data = bh->b_data;
-		}else if (!(bh = msdos_sread(inode->i_dev,sector,&data))) {
+		}else if (!(bh = msdos_sread(inode->i_dev,sector))) {
 			error = -EIO;
 			break;
 		}
 		if (binary_mode) {
-			memcpy_fromfs(data+offset,buf,written = size);
+			memcpy_fromfs(bh->b_data+offset,buf,written = size);
 			buf += size;
 		}
 		else {
 			written = left = SECTOR_SIZE-offset;
-			to = (char *) data+(filp->f_pos & (SECTOR_SIZE-1));
+			to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
 			if (carry) {
 				*to++ = '\n';
 				left--;
diff -u --recursive --new-file v1.1.60/linux/fs/msdos/inode.c linux/fs/msdos/inode.c
--- v1.1.60/linux/fs/msdos/inode.c	Wed Nov  2 12:03:46 1994
+++ linux/fs/msdos/inode.c	Wed Nov  2 13:20:18 1994
@@ -172,20 +172,7 @@
 	}
 	cache_init();
 	lock_super(s);
-	if (MAJOR(s->s_dev) == FLOPPY_MAJOR){
-		/* Patch for floppy which lacks a table ??? */
-		static int tbdef[]={
-			1024,1024,1024,1024,1024,
-			1024,1024,1024,1024,1024,
-			1024,1024,1024,1024,1024,
-			1024,1024,1024,1024,1024,
-			1024,1024,1024,1024,1024,
-			1024,1024,1024,1024,1024,
-			1024,1024,1024,1024,1024,
-		};
-		blksize_size[FLOPPY_MAJOR] = tbdef;
-	}
-	set_blocksize (s->s_dev,SECTOR_SIZE);
+	set_blocksize(s->s_dev, SECTOR_SIZE);
 	bh = bread(s->s_dev, 0, SECTOR_SIZE);
 	unlock_super(s);
 	if (bh == NULL) {
diff -u --recursive --new-file v1.1.60/linux/fs/msdos/misc.c linux/fs/msdos/misc.c
--- v1.1.60/linux/fs/msdos/misc.c	Wed Nov  2 12:03:46 1994
+++ linux/fs/msdos/misc.c	Wed Nov  2 11:43:48 1994
@@ -256,7 +256,6 @@
     struct msdos_dir_entry **de)
 {
 	int sector,offset;
-	void *data;
 
 	while (1) {
 		offset = *pos;
@@ -270,12 +269,12 @@
 		if (*bh)
 			brelse(*bh);
 		PRINTK (("get_entry sector apres brelse\n"));
-		if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) {
+		if (!(*bh = msdos_sread(dir->i_dev,sector))) {
 			printk("Directory sread (sector %d) failed\n",sector);
 			continue;
 		}
 		PRINTK (("get_entry apres sread\n"));
-		*de = (struct msdos_dir_entry *) (data+(offset &
+		*de = (struct msdos_dir_entry *) ((*bh)->b_data+(offset &
 		    (SECTOR_SIZE-1)));
 		return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
 		    MSDOS_DIR_BITS);
@@ -344,7 +343,8 @@
 	struct inode *inode;
 	int entry,start,done;
 
-	if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
+	if (!(bh = msdos_sread(sb->s_dev,sector))) return -EIO;
+	data = (struct msdos_dir_entry *) bh->b_data;
 	for (entry = 0; entry < MSDOS_DPS; entry++) {
 		if (name) RSS_NAME
 		else {
diff -u --recursive --new-file v1.1.60/linux/fs/read_write.c linux/fs/read_write.c
--- v1.1.60/linux/fs/read_write.c	Sun Oct 23 19:20:36 1994
+++ linux/fs/read_write.c	Tue Nov  1 19:50:44 1994
@@ -33,7 +33,10 @@
 		return -EBADF;
 	error = -ENOTDIR;
 	if (file->f_op && file->f_op->readdir) {
-		error = verify_area(VERIFY_WRITE, dirent, sizeof (*dirent));
+		int size = count;
+		if (count == 1)
+			size = sizeof(*dirent);
+		error = verify_area(VERIFY_WRITE, dirent, size);
 		if (!error)
 			error = file->f_op->readdir(inode,file,dirent,count);
 	}
diff -u --recursive --new-file v1.1.60/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v1.1.60/linux/fs/umsdos/inode.c	Wed Nov  2 12:03:47 1994
+++ linux/fs/umsdos/inode.c	Wed Nov  2 11:16:02 1994
@@ -273,7 +273,13 @@
 	newattrs.ia_atime = inode->i_atime;
 	newattrs.ia_ctime = inode->i_ctime;
 	newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
+	/*
+		UMSDOS_notify_change is convenient to call here
+		to update the EMD entry associated with this inode.
+		But it has the side effect to re"dirt" the inode.
+	*/
 	UMSDOS_notify_change (inode, &newattrs);
+	inode->i_dirt = 0;
 }
 
 int UMSDOS_notify_change(struct inode *inode, struct iattr *attr)
@@ -319,6 +325,7 @@
 				struct file filp;
 				struct umsdos_dirent entry;
 				filp.f_pos = inode->u.umsdos_i.pos;
+				filp.f_reada = 0;
 				PRINTK (("pos = %d ",filp.f_pos));
 				/* Read only the start of the entry since we don't touch */
 				/* the name */
diff -u --recursive --new-file v1.1.60/linux/fs/xiafs/bitmap.c linux/fs/xiafs/bitmap.c
--- v1.1.60/linux/fs/xiafs/bitmap.c	Sat Oct 22 16:24:03 1994
+++ linux/fs/xiafs/bitmap.c	Tue Nov  1 19:50:45 1994
@@ -35,7 +35,6 @@
 
     int end, i, j, tmp;
     u_long *bmap;
-    char res;
 
     bmap=(u_long *)bh->b_data;
     end = end_bit >> 5;
diff -u --recursive --new-file v1.1.60/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v1.1.60/linux/include/linux/cdrom.h	Wed Aug 10 19:26:42 1994
+++ linux/include/linux/cdrom.h	Wed Nov  2 11:51:13 1994
@@ -377,10 +377,16 @@
                                                 /* read type-1 data 		*/
 /*
  * preliminary extension for transferring audio frames
- * currently used by sbpcd.c
+ * currently used by cdu31a.c and sbpcd.c
  * (still may change if other drivers will use it, too):
  */
 #define	CDROMREADAUDIO		0x530e		/* (struct cdrom_read_audio)	*/
+/*
+ * preliminary extension for enable (1) / disable (0) auto-ejecting
+ * currently used by sbpcd.c
+ * (still may change if other drivers will use it, too):
+ */
+#define	CDROMEJECT_SW		0x530f		/* arg: 0 or 1 */
 
 #endif  _LINUX_CDROM_H
 
diff -u --recursive --new-file v1.1.60/linux/include/linux/ipc.h linux/include/linux/ipc.h
--- v1.1.60/linux/include/linux/ipc.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/ipc.h	Tue Nov  1 19:50:45 1994
@@ -39,7 +39,7 @@
 #define IPC_NOID	((void *) -2)		/* being allocated/destroyed */
 
 /* 
- * These are used to wrap system calls. See ipc/util.c, libipc.c 
+ * These are used to wrap system calls. See ipc/util.c.
  */
 struct ipc_kludge {
     struct msgbuf *msgp;
diff -u --recursive --new-file v1.1.60/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v1.1.60/linux/include/linux/msdos_fs.h	Wed Nov  2 12:03:47 1994
+++ linux/include/linux/msdos_fs.h	Wed Nov  2 11:43:48 1994
@@ -110,13 +110,9 @@
 
 #ifdef __KERNEL__
 
-static inline struct buffer_head *msdos_sread(int dev,int sector,void **start)
+static inline struct buffer_head *msdos_sread(int dev,int sector)
 {
- 	struct buffer_head *bh = bread(dev,sector, 512);
-	if (bh != NULL){
-		*start = bh->b_data;	/* From the time of 1024 bytes block */
-	}
-	return bh;
+	return bread(dev,sector,SECTOR_SIZE);
 }
 
 
diff -u --recursive --new-file v1.1.60/linux/include/linux/msg.h linux/include/linux/msg.h
--- v1.1.60/linux/include/linux/msg.h	Sun Mar  6 16:10:53 1994
+++ linux/include/linux/msg.h	Tue Nov  1 19:50:45 1994
@@ -6,15 +6,6 @@
 #define MSG_NOERROR     010000  /* no error if message is too big */
 #define MSG_EXCEPT      020000  /* recv any msg except of specified type.*/
 
-
-/* one msg structure for each message */
-struct msg {
-    struct msg *msg_next;   /* next message on queue */
-    long  msg_type;          
-    char *msg_spot;         /* message text address */
-    short msg_ts;           /* message text size */
-};
-
 /* one msqid structure for each queue on the system */
 struct msqid_ds {
     struct ipc_perm msg_perm;
@@ -32,14 +23,13 @@
     ushort msg_lrpid;       /* last receive pid */
 };
 
-
 /* message buffer for msgsnd and msgrcv calls */
 struct msgbuf {
     long mtype;         /* type of message */
     char mtext[1];      /* message text */
 };
 
-
+/* buffer for msgctl calls IPC_INFO, MSG_INFO */
 struct msginfo {
     int msgpool;
     int msgmap; 
@@ -64,6 +54,14 @@
 #define MSGSEG (__MSGSEG <= 0xffff ? __MSGSEG : 0xffff)
 
 #ifdef __KERNEL__
+
+/* one msg structure for each message */
+struct msg {
+    struct msg *msg_next;   /* next message on queue */
+    long  msg_type;          
+    char *msg_spot;         /* message text address */
+    short msg_ts;           /* message text size */
+};
 
 /* ipcs ctl commands */
 #define MSG_STAT 11
diff -u --recursive --new-file v1.1.60/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.1.60/linux/include/linux/sched.h	Tue Oct 18 14:14:42 1994
+++ linux/include/linux/sched.h	Tue Nov  1 19:50:45 1994
@@ -290,7 +290,7 @@
 	struct tty_struct *tty; /* NULL if no tty */
 /* shm stuff */
 	struct shm_desc *shm;
-	struct sem_undo *semun;
+	struct sem_undo *semundo;
 /* ldt for this task - used by Wine.  If NULL, default_ldt is used */
 	struct desc_struct *ldt;
 /* tss for this task */
diff -u --recursive --new-file v1.1.60/linux/include/linux/sem.h linux/include/linux/sem.h
--- v1.1.60/linux/include/linux/sem.h	Wed Dec  1 14:44:15 1993
+++ linux/include/linux/sem.h	Tue Nov  1 19:50:45 1994
@@ -26,16 +26,7 @@
   ushort          sem_nsems;      /* no. of semaphores in array */
 };
 
-
-/* One semaphore structure for each semaphore in the system. */
-struct sem {
-  short   sempid;         /* pid of last operation */
-  ushort  semval;         /* current value */
-  ushort  semncnt;        /* num procs awaiting increase in semval */
-  ushort  semzcnt;        /* num procs awaiting semval = 0 */
-};
-
-/* semop system calls takes an array of these.*/
+/* semop system calls takes an array of these. */
 struct sembuf {
   ushort  sem_num;        /* semaphore index in array */
   short   sem_op;         /* semaphore operation */
@@ -44,12 +35,13 @@
 
 /* arg for semctl system calls. */
 union semun {
-  int val;               /* value for SETVAL */
-  struct semid_ds *buf;  /* buffer for IPC_STAT & IPC_SET */
-  ushort *array;         /* array for GETALL & SETALL */
+  int val;			/* value for SETVAL */
+  struct semid_ds *buf;		/* buffer for IPC_STAT & IPC_SET */
+  ushort *array;		/* array for GETALL & SETALL */
+  struct seminfo *__buf;	/* buffer for IPC_INFO */
+  void *__pad;
 };
 
-
 struct  seminfo {
     int semmap; 
     int semmni; 
@@ -77,6 +69,15 @@
 #define SEMUSZ  20		/* sizeof struct sem_undo */ 
 
 #ifdef __KERNEL__
+
+/* One semaphore structure for each semaphore in the system. */
+struct sem {
+  short   sempid;         /* pid of last operation */
+  ushort  semval;         /* current value */
+  ushort  semncnt;        /* num procs awaiting increase in semval */
+  ushort  semzcnt;        /* num procs awaiting semval = 0 */
+};
+
 /* ipcs ctl cmds */
 #define SEM_STAT 18	
 #define SEM_INFO 19
diff -u --recursive --new-file v1.1.60/linux/include/linux/shm.h linux/include/linux/shm.h
--- v1.1.60/linux/include/linux/shm.h	Tue Jan  4 13:08:23 1994
+++ linux/include/linux/shm.h	Tue Nov  1 19:50:45 1994
@@ -3,7 +3,7 @@
 #include <linux/ipc.h>
 
 struct shmid_ds {
-	struct	ipc_perm shm_perm;	/* operation perms */
+	struct ipc_perm shm_perm;	/* operation perms */
 	int	shm_segsz;		/* size of segment (bytes) */
 	time_t	shm_atime;		/* last attach time */
 	time_t	shm_dtime;		/* last detach time */
@@ -12,9 +12,9 @@
 	unsigned short	shm_lpid;	/* pid of last operator */
 	short	shm_nattch;		/* no. of current attaches */
 	/* the following are private */
-	unsigned short   shm_npages;  /* size of segment (pages) */
-	unsigned long   *shm_pages;   /* array of ptrs to frames -> SHMMAX */ 
-	struct shm_desc *attaches;    /* descriptors for attaches */
+	unsigned short   shm_npages;	/* size of segment (pages) */
+	unsigned long   *shm_pages;	/* array of ptrs to frames -> SHMMAX */ 
+	struct shm_desc *attaches;	/* descriptors for attaches */
 };
 
 /* mode for attach */
@@ -34,34 +34,35 @@
     int shmall;	
 };
 
+/* address range for shared memory attaches if no address passed to shmat() */
 #define SHM_RANGE_START	0x40000000
 #define SHM_RANGE_END	0x60000000
 
-				/* _SHM_ID_BITS is a variable you can adjust to */
-				/* tune the kernel.  It determines the value of */
-				/* SHMMNI, which specifies the maximum no. of */
-				/* shared segments (system wide).  SRB. */
-#define _SHM_ID_BITS	7		/* keep as low as possible */
-					/* a static array is declared */
-					/* using SHMMNI */
-
-#define __SHM_IDX_BITS	(BITS_PER_PTR-2-SHM_IDX_SHIFT)
-
-/* !!!!!!!?????
- * Why reserve the two (2) high bits of the signature (shm_sgn) field?
- * Since, as far as I can see, only the high bit is used (SHM_READ_ONLY).
- *						SRB.
- */
-
-#define _SHM_IDX_BITS	(__SHM_IDX_BITS+PAGE_SHIFT>=BITS_PER_PTR?\
- BITS_PER_PTR-PAGE_SHIFT-1:__SHM_IDX_BITS)	/* sanity check */
+/* format of page table entries that correspond to shared memory pages
+   currently out in swap space (see also mm/swap.c):
+   bit 0 (PAGE_PRESENT) is  = 0
+   bits 7..1 (SWP_TYPE) are = SHM_SWP_TYPE
+   bits 31..8 are used like this:
+   bits 14..8 (SHM_ID) the id of the shared memory segment
+   bits 29..15 (SHM_IDX) the index of the page within the shared memory segment
+                    (actually only bits 24..15 get used since SHMMAX is so low)
+   bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach
+*/
 
-/* not present page table entry format bit 0 is 0, low byte defined in mm.h */
 #define SHM_ID_SHIFT	8
+/* Keep _SHM_ID_BITS as low as possible since SHMMNI depends on it and
+   there is a static array of size SHMMNI. */
+#define _SHM_ID_BITS	7
 #define SHM_ID_MASK	((1<<_SHM_ID_BITS)-1)
+
 #define SHM_IDX_SHIFT	(SHM_ID_SHIFT+_SHM_ID_BITS)
+#define _SHM_IDX_BITS	15
 #define SHM_IDX_MASK	((1<<_SHM_IDX_BITS)-1)
-#define SHM_READ_ONLY	(1<<(BITS_PER_PTR-1))
+
+#define SHM_READ_ONLY	(1<<31)
+
+/* We must have SHM_ID_SHIFT + _SHM_ID_BITS + _SHM_IDX_BITS + 1 <= 32
+   and SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS). */
 
 #define SHMMAX 0x3fa000				/* max shared seg size (bytes) */
 #define SHMMIN 1	 /* really PAGE_SIZE */	/* min shared seg size (bytes) */
@@ -105,5 +106,4 @@
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_SHM_H_ */
-
 
diff -u --recursive --new-file v1.1.60/linux/ipc/msg.c linux/ipc/msg.c
--- v1.1.60/linux/ipc/msg.c	Wed Apr 27 08:05:16 1994
+++ linux/ipc/msg.c	Tue Nov  1 19:50:45 1994
@@ -29,7 +29,7 @@
 {
 	int id;
 	
-	for (id=0; id < MSGMNI; id++) 
+	for (id = 0; id < MSGMNI; id++) 
 		msgque[id] = (struct msqid_ds *) IPC_UNUSED;
 	msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
 	msg_lock = NULL;
@@ -53,14 +53,14 @@
 		return err;
 	if ((mtype = get_fs_long (&msgp->mtype)) < 1)
 		return -EINVAL;
-	id = msqid % MSGMNI;
+	id = (unsigned int) msqid % MSGMNI;
 	msq = msgque [id];
 	if (msq == IPC_UNUSED || msq == IPC_NOID)
 		return -EINVAL;
 	ipcp = &msq->msg_perm; 
 
  slept:
-	if (ipcp->seq != (msqid / MSGMNI)) 
+	if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) 
 		return -EIDRM;
 	if (ipcperms(ipcp, S_IWUGO)) 
 		return -EACCES;
@@ -83,7 +83,7 @@
 	memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); 
 	
 	if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
-		|| ipcp->seq != msqid / MSGMNI) {
+		|| msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
 		kfree(msgh);
 		return -EIDRM;
 	}
@@ -125,7 +125,7 @@
 	if (err)
 		return err;
 
-	id = msqid % MSGMNI;
+	id = (unsigned int) msqid % MSGMNI;
 	msq = msgque [id];
 	if (msq == IPC_NOID || msq == IPC_UNUSED)
 		return -EINVAL;
@@ -138,7 +138,7 @@
 	 *  msgtyp < 0 => get message with least type must be < abs(msgtype).  
 	 */
 	while (!nmsg) {
-		if(ipcp->seq != msqid / MSGMNI)
+		if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
 			return -EIDRM;
 		if (ipcperms (ipcp, S_IRUGO))
 			return -EACCES;
@@ -174,7 +174,7 @@
 			if (nmsg ==  msq->msg_first)
 				msq->msg_first = nmsg->msg_next;
 			else {
-				for (tmsg= msq->msg_first; tmsg; 
+				for (tmsg = msq->msg_first; tmsg; 
 				     tmsg = tmsg->msg_next)
 					if (tmsg->msg_next == nmsg) 
 						break;
@@ -213,7 +213,7 @@
 	int id;
 	struct msqid_ds *msq;
 	
-	for (id=0; id <= max_msqid; id++) {
+	for (id = 0; id <= max_msqid; id++) {
 		while ((msq = msgque[id]) == IPC_NOID) 
 			interruptible_sleep_on (&msg_lock);
 		if (msq == IPC_UNUSED)
@@ -230,7 +230,7 @@
 	struct msqid_ds *msq;
 	struct ipc_perm *ipcp;
 
-	for (id=0; id < MSGMNI; id++) 
+	for (id = 0; id < MSGMNI; id++) 
 		if (msgque[id] == IPC_UNUSED) {
 			msgque[id] = (struct msqid_ds *) IPC_NOID;
 			goto found;
@@ -250,7 +250,7 @@
 	ipcp->key = key;
 	ipcp->cuid = ipcp->uid = current->euid;
 	ipcp->gid = ipcp->cgid = current->egid;
-	ipcp->seq = msg_seq;
+	msq->msg_perm.seq = msg_seq;
 	msq->msg_first = msq->msg_last = NULL;
 	msq->rwait = msq->wwait = NULL;
 	msq->msg_cbytes = msq->msg_qnum = 0;
@@ -264,7 +264,7 @@
 	used_queues++;
 	if (msg_lock)
 		wake_up (&msg_lock);
-	return (int) msg_seq * MSGMNI + id;
+	return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
 }
 
 int sys_msgget (key_t key, int msgflg)
@@ -286,7 +286,7 @@
 		return -EIDRM;
 	if (ipcperms(&msq->msg_perm, msgflg))
 		return -EACCES;
-	return msq->msg_perm.seq * MSGMNI +id;
+	return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
 } 
 
 static void freeque (int id)
@@ -295,7 +295,7 @@
 	struct msg *msgp, *msgh;
 
 	msq->msg_perm.seq++;
-	msg_seq++;
+	msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI); /* increment, but avoid overflow */
 	msgbytes -= msq->msg_cbytes;
 	if (id == max_msqid)
 		while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
@@ -319,7 +319,8 @@
 int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
 {
 	int id, err;
-	struct msqid_ds *msq, tbuf;
+	struct msqid_ds *msq;
+	struct msqid_ds tbuf;
 	struct ipc_perm *ipcp;
 	
 	if (msqid < 0 || cmd < 0)
@@ -353,7 +354,7 @@
 	case MSG_STAT:
 		if (!buf)
 			return -EFAULT;
-		err = verify_area (VERIFY_WRITE, buf, sizeof (*msq));
+		err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
 		if (err)
 			return err;
 		if (msqid > max_msqid)
@@ -363,46 +364,62 @@
 			return -EINVAL;
 		if (ipcperms (&msq->msg_perm, S_IRUGO))
 			return -EACCES;
-		id = msqid + msq->msg_perm.seq * MSGMNI; 
-		memcpy_tofs (buf, msq, sizeof(*msq));
+		id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
+		tbuf.msg_perm   = msq->msg_perm;
+		tbuf.msg_stime  = msq->msg_stime;
+		tbuf.msg_rtime  = msq->msg_rtime;
+		tbuf.msg_ctime  = msq->msg_ctime;
+		tbuf.msg_cbytes = msq->msg_cbytes;
+		tbuf.msg_qnum   = msq->msg_qnum;
+		tbuf.msg_qbytes = msq->msg_qbytes;
+		tbuf.msg_lspid  = msq->msg_lspid;
+		tbuf.msg_lrpid  = msq->msg_lrpid;
+		memcpy_tofs (buf, &tbuf, sizeof(*buf));
 		return id;
 	case IPC_SET:
 		if (!buf)
 			return -EFAULT;
+		err = verify_area (VERIFY_READ, buf, sizeof (*buf));
+		if (err)
+			return err;
 		memcpy_fromfs (&tbuf, buf, sizeof (*buf));
 		break;
 	case IPC_STAT:
 		if (!buf)
 			return -EFAULT;
-		err = verify_area (VERIFY_WRITE, buf, sizeof(*msq));
+		err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
 		if (err)
 			return err;
 		break;
 	}
 
-	id = msqid % MSGMNI;
+	id = (unsigned int) msqid % MSGMNI;
 	msq = msgque [id];
 	if (msq == IPC_UNUSED || msq == IPC_NOID)
 		return -EINVAL;
-	ipcp = &msq->msg_perm;
-	if (ipcp->seq != msqid / MSGMNI)
+	if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
 		return -EIDRM;
+	ipcp = &msq->msg_perm;
 
 	switch (cmd) {
 	case IPC_STAT:
 		if (ipcperms (ipcp, S_IRUGO))
 			return -EACCES;
-		memcpy_tofs (buf, msq, sizeof (*msq));
+		tbuf.msg_perm   = msq->msg_perm;
+		tbuf.msg_stime  = msq->msg_stime;
+		tbuf.msg_rtime  = msq->msg_rtime;
+		tbuf.msg_ctime  = msq->msg_ctime;
+		tbuf.msg_cbytes = msq->msg_cbytes;
+		tbuf.msg_qnum   = msq->msg_qnum;
+		tbuf.msg_qbytes = msq->msg_qbytes;
+		tbuf.msg_lspid  = msq->msg_lspid;
+		tbuf.msg_lrpid  = msq->msg_lrpid;
+		memcpy_tofs (buf, &tbuf, sizeof (*buf));
 		return 0;
-		break;
-	case IPC_RMID: case IPC_SET:
+	case IPC_SET:
 		if (!suser() && current->euid != ipcp->cuid && 
 		    current->euid != ipcp->uid)
 			return -EPERM;
-		if (cmd == IPC_RMID) {
-			freeque (id); 
-			return 0;
-		}
 		if (tbuf.msg_qbytes > MSGMNB && !suser())
 			return -EPERM;
 		msq->msg_qbytes = tbuf.msg_qbytes;
@@ -411,10 +428,14 @@
 		ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 
 			(S_IRWXUGO & tbuf.msg_perm.mode);
 		msq->msg_ctime = CURRENT_TIME;
-		break;
+		return 0;
+	case IPC_RMID:
+		if (!suser() && current->euid != ipcp->cuid && 
+		    current->euid != ipcp->uid)
+			return -EPERM;
+		freeque (id); 
+		return 0;
 	default:
 		return -EINVAL;
-		break;
 	}
-	return 0;
 }
diff -u --recursive --new-file v1.1.60/linux/ipc/sem.c linux/ipc/sem.c
--- v1.1.60/linux/ipc/sem.c	Wed Apr 27 08:06:06 1994
+++ linux/ipc/sem.c	Tue Nov  1 19:50:45 1994
@@ -26,11 +26,11 @@
 
 void sem_init (void)
 {
-	int i=0;
+	int i;
 	
 	sem_lock = NULL;
 	used_sems = used_semids = max_semid = sem_seq = 0;
-	for (i=0; i < SEMMNI; i++)
+	for (i = 0; i < SEMMNI; i++)
 		semary[i] = (struct semid_ds *) IPC_UNUSED;
 	return;
 }
@@ -40,7 +40,7 @@
 	int id;
 	struct semid_ds *sma;
 	
-	for (id=0; id <= max_semid; id++) {
+	for (id = 0; id <= max_semid; id++) {
 		while ((sma = semary[id]) == IPC_NOID) 
 			interruptible_sleep_on (&sem_lock);
 		if (sma == IPC_UNUSED)
@@ -62,7 +62,7 @@
 		return -EINVAL;
 	if (used_sems + nsems > SEMMNS)
 		return -ENOSPC;
-	for (id=0; id < SEMMNI; id++) 
+	for (id = 0; id < SEMMNI; id++) 
 		if (semary[id] == IPC_UNUSED) {
 			semary[id] = (struct semid_ds *) IPC_NOID;
 			goto found;
@@ -86,7 +86,7 @@
 	ipcp->key = key;
 	ipcp->cuid = ipcp->uid = current->euid;
 	ipcp->gid = ipcp->cgid = current->egid;
-	ipcp->seq = sem_seq;
+	sma->sem_perm.seq = sem_seq;
 	sma->eventn = sma->eventz = NULL;
 	sma->sem_nsems = nsems;
 	sma->sem_ctime = CURRENT_TIME;
@@ -96,7 +96,7 @@
 	semary[id] = sma;
 	if (sem_lock)
 		wake_up (&sem_lock);
-	return (int) sem_seq * SEMMNI + id;
+	return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
 }
 
 int sys_semget (key_t key, int nsems, int semflg)
@@ -120,7 +120,7 @@
 		return -EINVAL;
 	if (ipcperms(&sma->sem_perm, semflg))
 		return -EACCES;
-	return sma->sem_perm.seq*SEMMNI + id;
+	return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
 } 
 
 static void freeary (int id)
@@ -129,13 +129,13 @@
 	struct sem_undo *un;
 
 	sma->sem_perm.seq++;
-	sem_seq++;
+	sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI); /* increment, but avoid overflow */
 	used_sems -= sma->sem_nsems;
 	if (id == max_semid)
 		while (max_semid && (semary[--max_semid] == IPC_UNUSED));
 	semary[id] = (struct semid_ds *) IPC_UNUSED;
 	used_semids--;
-	for (un=sma->undo; un; un=un->id_next)
+	for (un = sma->undo; un; un = un->id_next)
 	        un->semadj = 0;
 	while (sma->eventz || sma->eventn) {
 		if (sma->eventz)
@@ -148,16 +148,19 @@
 	return;
 }
 
-int sys_semctl (int semid, int semnum, int cmd, void *arg)
+int sys_semctl (int semid, int semnum, int cmd, union semun arg)
 {
+	struct semid_ds *buf = NULL;
+	struct semid_ds tbuf;
 	int i, id, val = 0;
-	struct semid_ds *sma, *buf = NULL, tbuf;
+	struct semid_ds *sma;
 	struct ipc_perm *ipcp;
 	struct sem *curr;
 	struct sem_undo *un;
-	ushort nsems, *array = NULL;
+	unsigned int nsems;
+	ushort *array = NULL;
 	ushort sem_io[SEMMSL];
-	
+
 	if (semid < 0 || semnum < 0 || cmd < 0)
 		return -EINVAL;
 
@@ -165,9 +168,7 @@
 	case IPC_INFO: 
 	case SEM_INFO: 
 	{
-		struct seminfo seminfo, *tmp;
-		if (!arg || ! (tmp = (struct seminfo *) get_fs_long((int *)arg)))
-			return -EFAULT;
+		struct seminfo seminfo, *tmp = arg.__buf;
 		seminfo.semmni = SEMMNI;
 		seminfo.semmns = SEMMNS;
 		seminfo.semmsl = SEMMSL;
@@ -182,7 +183,7 @@
 			seminfo.semusz = used_semids;
 			seminfo.semaem = used_sems;
 		}
-		i= verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
+		i = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
 		if (i)
 			return i;
 		memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo));
@@ -190,9 +191,8 @@
 	}
 
 	case SEM_STAT:
-		if (!arg || ! (buf = (struct semid_ds *) get_fs_long((int *) arg)))
-			return -EFAULT;
-		i = verify_area (VERIFY_WRITE, buf, sizeof (*sma));
+		buf = arg.buf;
+		i = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
 		if (i)
 			return i;
 		if (semid > max_semid)
@@ -202,18 +202,22 @@
 			return -EINVAL;
 		if (ipcperms (&sma->sem_perm, S_IRUGO))
 			return -EACCES;
-		id = semid + sma->sem_perm.seq * SEMMNI; 
-		memcpy_tofs (buf, sma, sizeof(*sma));
+		id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;
+		tbuf.sem_perm   = sma->sem_perm;
+		tbuf.sem_otime  = sma->sem_otime;
+		tbuf.sem_ctime  = sma->sem_ctime;
+		tbuf.sem_nsems  = sma->sem_nsems;
+		memcpy_tofs (buf, &tbuf, sizeof(*buf));
 		return id;
 	}
 
-	id = semid % SEMMNI;
+	id = (unsigned int) semid % SEMMNI;
 	sma = semary [id];
 	if (sma == IPC_UNUSED || sma == IPC_NOID)
 		return -EINVAL;
 	ipcp = &sma->sem_perm;
 	nsems = sma->sem_nsems;
-	if (ipcp->seq != semid / SEMMNI)
+	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
 		return -EIDRM;
 	if (semnum >= nsems)
 		return -EINVAL;
@@ -233,17 +237,15 @@
 		case GETNCNT: return curr->semncnt;
 		case GETZCNT: return curr->semzcnt;
 		case GETALL:
-			if (!arg || ! (array = (ushort *) get_fs_long((int *) arg)))
-				return -EFAULT;
-			i = verify_area (VERIFY_WRITE, array, nsems*sizeof(short));
+			array = arg.array;
+			i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
 			if (i)
 				return i;
 		}
 		break;
-	case SETVAL: 
-		if (!arg)
-			return -EFAULT;
-		if ((val = (int) get_fs_long ((int *) arg))  > SEMVMX || val < 0) 
+	case SETVAL:
+		val = arg.val;
+		if (val > SEMVMX || val < 0) 
 			return -ERANGE;
 		break;
 	case IPC_RMID:
@@ -254,40 +256,37 @@
 		}
 		return -EPERM;
 	case SETALL: /* arg is a pointer to an array of ushort */
-		if (!arg || ! (array = (ushort *) get_fs_long ((int *) arg)) )
-			return -EFAULT;
-		if ((i = verify_area (VERIFY_READ, array, sizeof tbuf)))
+		array = arg.array;
+		if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
 			return i;
 		memcpy_fromfs (sem_io, array, nsems*sizeof(ushort));
-		for (i=0; i< nsems; i++)
+		for (i = 0; i < nsems; i++)
 			if (sem_io[i] > SEMVMX)
 				return -ERANGE;
 		break;
 	case IPC_STAT:
-		if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) 
-			return -EFAULT;
-		if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*sma))))
+		buf = arg.buf;
+		if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
 			return i;
 		break;
 	case IPC_SET:
-		if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) 
-			return -EFAULT;
-		if ((i = verify_area (VERIFY_READ, buf, sizeof tbuf)))
+		buf = arg.buf;
+		if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf))))
 			return i;
-		memcpy_fromfs (&tbuf, buf, sizeof tbuf);
+		memcpy_fromfs (&tbuf, buf, sizeof (*buf));
 		break;
 	}
 	
 	if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
 		return -EIDRM;
-	if (ipcp->seq != semid / SEMMNI)
+	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
 		return -EIDRM;
 	
 	switch (cmd) {
 	case GETALL:
 		if (ipcperms (ipcp, S_IRUGO))
 			return -EACCES;
-		for (i=0; i< sma->sem_nsems; i++)
+		for (i = 0; i < sma->sem_nsems; i++)
 			sem_io[i] = sma->sem_base[i].semval;
 		memcpy_tofs (array, sem_io, nsems*sizeof(ushort));
 		break;
@@ -318,12 +317,16 @@
 	case IPC_STAT:
 		if (ipcperms (ipcp, S_IRUGO))
 			return -EACCES;
-		memcpy_tofs (buf, sma, sizeof (*sma));
+		tbuf.sem_perm   = sma->sem_perm;
+		tbuf.sem_otime  = sma->sem_otime;
+		tbuf.sem_ctime  = sma->sem_ctime;
+		tbuf.sem_nsems  = sma->sem_nsems;
+		memcpy_tofs (buf, &tbuf, sizeof(*buf));
 		break;
 	case SETALL:
 		if (ipcperms (ipcp, S_IWUGO))
 			return -EACCES;
-		for (i=0; i<nsems; i++) 
+		for (i = 0; i < nsems; i++) 
 			sma->sem_base[i].semval = sem_io[i];
 		for (un = sma->undo; un; un = un->id_next)
 			un->semadj = 0;
@@ -354,11 +357,13 @@
 		return -E2BIG;
 	if (!tsops) 
 		return -EFAULT;
+	if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops))))
+		return i;
 	memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops));  
-	id = semid % SEMMNI;
+	id = (unsigned int) semid % SEMMNI;
 	if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
 		return -EINVAL;
-	for (i=0; i<nsops; i++) { 
+	for (i = 0; i < nsops; i++) { 
 		sop = &sops[i];
 		if (sop->sem_num > sma->sem_nsems)
 			return -EFBIG;
@@ -376,10 +381,10 @@
 	 * ensure every sop with undo gets an undo structure 
 	 */
 	if (undos) {
-		for (i=0; i<nsops; i++) {
+		for (i = 0; i < nsops; i++) {
 			if (!(sops[i].sem_flg & SEM_UNDO))
 				continue;
-			for (un = current->semun; un; un = un->proc_next) 
+			for (un = current->semundo; un; un = un->proc_next) 
 				if ((un->semid == semid) && 
 				    (un->sem_num == sops[i].sem_num))
 					break;
@@ -392,17 +397,17 @@
 			un->semid = semid;
 			un->semadj = 0;
 			un->sem_num = sops[i].sem_num;
-			un->proc_next = current->semun;
-			current->semun = un;
+			un->proc_next = current->semundo;
+			current->semundo = un;
 			un->id_next = sma->undo;
 			sma->undo = un;
 		}
 	}
 	
  slept:
-	if (sma->sem_perm.seq != semid / SEMMNI) 
+	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) 
 		return -EIDRM;
-	for (i=0; i<nsops; i++) {
+	for (i = 0; i < nsops; i++) {
 		sop = &sops[i];
 		curr = &sma->sem_base[sop->sem_num];
 		if (sop->sem_op + curr->semval > SEMVMX)
@@ -429,7 +434,7 @@
 		}
 	}
 	
-	for (i=0; i<nsops; i++) {
+	for (i = 0; i < nsops; i++) {
 		sop = &sops[i];
 		curr = &sma->sem_base[sop->sem_num];
 		curr->sempid = current->pid;
@@ -437,7 +442,7 @@
 			semzcnt++;
 		if (!(sop->sem_flg & SEM_UNDO))
 			continue;
-		for (un = current->semun; un; un = un->proc_next) 
+		for (un = current->semundo; un; un = un->proc_next) 
 			if ((un->semid == semid) && 
 			    (un->sem_num == sop->sem_num))
 				break;
@@ -466,11 +471,11 @@
 	struct semid_ds *sma;
 	struct sem *sem = NULL;
 	
-	for (up = &current->semun; (u = *up); *up = u->proc_next, kfree(u)) {
-		sma = semary[u->semid % SEMMNI];
+	for (up = &current->semundo; (u = *up); *up = u->proc_next, kfree(u)) {
+		sma = semary[(unsigned int) u->semid % SEMMNI];
 		if (sma == IPC_UNUSED || sma == IPC_NOID) 
 			continue;
-		if (sma->sem_perm.seq != u->semid / SEMMNI)
+		if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI)
 			continue;
 		for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
 			if (u == un) 
@@ -483,7 +488,7 @@
 		if (!un->semadj)
 			continue;
 		while (1) {
-			if (sma->sem_perm.seq != un->semid / SEMMNI)
+			if (sma->sem_perm.seq != (unsigned int) un->semid / SEMMNI)
 				break;
 			sem = &sma->sem_base[un->sem_num];
 			if (sem->semval + un->semadj >= 0) {
@@ -503,6 +508,6 @@
 			sem->semncnt--;
 		}
 	}
-	current->semun = NULL;
+	current->semundo = NULL;
 	return;
 }
diff -u --recursive --new-file v1.1.60/linux/ipc/shm.c linux/ipc/shm.c
--- v1.1.60/linux/ipc/shm.c	Tue Aug  9 09:33:00 1994
+++ linux/ipc/shm.c	Tue Nov  1 19:50:45 1994
@@ -1,31 +1,30 @@
 /*
  * linux/ipc/shm.c
- * Copyright (C) 1992, 1993 Krishna Balasubramanian 
+ * Copyright (C) 1992, 1993 Krishna Balasubramanian
  *         Many improvements/fixes by Bruno Haible.
- * assume user segments start at 0x0
  */
 
 #include <linux/errno.h>
 #include <asm/segment.h>
 #include <linux/sched.h>
-#include <linux/ipc.h> 
+#include <linux/ipc.h>
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/malloc.h>
 
-extern int ipcperms (struct ipc_perm *ipcp, short semflg);
-extern unsigned int get_swap_page(void);
+extern int ipcperms (struct ipc_perm *ipcp, short shmflg);
+extern unsigned int get_swap_page (void);
 static int findkey (key_t key);
 static int newseg (key_t key, int shmflg, int size);
 static int shm_map (struct shm_desc *shmd, int remap);
 static void killseg (int id);
-static unsigned long shm_swap_in(struct vm_area_struct *, unsigned long);
+static unsigned long shm_swap_in (struct vm_area_struct *, unsigned long);
 
-static int shm_tot = 0;  /* total number of shared memory pages */
+static int shm_tot = 0; /* total number of shared memory pages */
 static int shm_rss = 0; /* number of shared memory pages that are in memory */
 static int shm_swp = 0; /* number of shared memory pages that are in swap */
 static int max_shmid = 0; /* every used id is <= max_shmid */
-static struct wait_queue *shm_lock = NULL;
+static struct wait_queue *shm_lock = NULL; /* calling findkey() may need to wait */
 static struct shmid_ds *shm_segs[SHMMNI];
 
 static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */
@@ -38,31 +37,31 @@
 void shm_init (void)
 {
 	int id;
-    
-       	for (id = 0; id < SHMMNI; id++) 
+
+	for (id = 0; id < SHMMNI; id++)
 		shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
 	shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
 	shm_lock = NULL;
 	return;
 }
 
-static int findkey (key_t key)    
+static int findkey (key_t key)
 {
 	int id;
 	struct shmid_ds *shp;
-	
-	for (id=0; id <= max_shmid; id++) {
-		while ((shp = shm_segs[id]) == IPC_NOID) 
+
+	for (id = 0; id <= max_shmid; id++) {
+		while ((shp = shm_segs[id]) == IPC_NOID)
 			sleep_on (&shm_lock);
 		if (shp == IPC_UNUSED)
 			continue;
-		if (key == shp->shm_perm.key) 
+		if (key == shp->shm_perm.key)
 			return id;
 	}
 	return -1;
 }
 
-/* 
+/*
  * allocate new shmid_ds and pgtable. protected by shm_segs[id] = NOID.
  */
 static int newseg (key_t key, int shmflg, int size)
@@ -75,7 +74,7 @@
 		return -EINVAL;
 	if (shm_tot + numpages >= SHMALL)
 		return -ENOSPC;
-	for (id=0; id < SHMMNI; id++)
+	for (id = 0; id < SHMMNI; id++)
 		if (shm_segs[id] == IPC_UNUSED) {
 			shm_segs[id] = (struct shmid_ds *) IPC_NOID;
 			goto found;
@@ -100,7 +99,7 @@
 		return -ENOMEM;
 	}
 
-	for (i=0; i< numpages; shp->shm_pages[i++] = 0);
+	for (i = 0; i < numpages; shp->shm_pages[i++] = 0);
 	shm_tot += numpages;
 	shp->shm_perm.key = key;
 	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
@@ -121,23 +120,23 @@
 	used_segs++;
 	if (shm_lock)
 		wake_up (&shm_lock);
-	return id + (int)shm_seq*SHMMNI;
+	return (unsigned int) shp->shm_perm.seq * SHMMNI + id;
 }
 
 int sys_shmget (key_t key, int size, int shmflg)
 {
 	struct shmid_ds *shp;
 	int id = 0;
-	
+
 	if (size < 0 || size > SHMMAX)
 		return -EINVAL;
-	if (key == IPC_PRIVATE) 
+	if (key == IPC_PRIVATE)
 		return newseg(key, shmflg, size);
 	if ((id = findkey (key)) == -1) {
 		if (!(shmflg & IPC_CREAT))
 			return -ENOENT;
 		return newseg(key, shmflg, size);
-	} 
+	}
 	if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
 		return -EEXIST;
 	shp = shm_segs[id];
@@ -147,10 +146,10 @@
 		return -EINVAL;
 	if (ipcperms (&shp->shm_perm, shmflg))
 		return -EACCES;
-	return shp->shm_perm.seq*SHMMNI + id;
+	return (unsigned int) shp->shm_perm.seq * SHMMNI + id;
 }
 
-/* 
+/*
  * Only called after testing nattch and SHM_DEST.
  * Here pages, pgtable and shmid_ds are freed.
  */
@@ -166,20 +165,20 @@
 		return;
 	}
 	shp->shm_perm.seq++;     /* for shmat */
-	numpages = shp->shm_npages; 
-	shm_seq++;
+	shm_seq = (shm_seq+1) % ((unsigned)(1<<31)/SHMMNI); /* increment, but avoid overflow */
 	shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
 	used_segs--;
-	if (id == max_shmid) 
+	if (id == max_shmid)
 		while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED));
 	if (!shp->shm_pages) {
 		printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id);
 		return;
 	}
-	for (i=0; i< numpages ; i++) {
+	numpages = shp->shm_npages;
+	for (i = 0; i < numpages ; i++) {
 		if (!(page = shp->shm_pages[i]))
 			continue;
-		if (page & 1) {
+		if (page & PAGE_PRESENT) {
 			free_page (page & PAGE_MASK);
 			shm_rss--;
 		} else {
@@ -195,10 +194,11 @@
 
 int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
 {
-	struct shmid_ds *shp, tbuf;
+	struct shmid_ds tbuf;
+	struct shmid_ds *shp;
 	struct ipc_perm *ipcp;
 	int id, err;
-	
+
 	if (cmd < 0 || shmid < 0)
 		return -EINVAL;
 	if (cmd == IPC_SET) {
@@ -211,7 +211,7 @@
 	}
 
 	switch (cmd) { /* replace with proc interface ? */
-	case IPC_INFO: 
+	case IPC_INFO:
 	{
 		struct shminfo shminfo;
 		if (!buf)
@@ -227,15 +227,15 @@
 		memcpy_tofs (buf, &shminfo, sizeof(struct shminfo));
 		return max_shmid;
 	}
-	case SHM_INFO: 
-	{ 
+	case SHM_INFO:
+	{
 		struct shm_info shm_info;
 		if (!buf)
 			return -EFAULT;
 		err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info));
 		if (err)
 			return err;
-		shm_info.used_ids = used_segs; 
+		shm_info.used_ids = used_segs;
 		shm_info.shm_rss = shm_rss;
 		shm_info.shm_tot = shm_tot;
 		shm_info.shm_swp = shm_swp;
@@ -247,7 +247,7 @@
 	case SHM_STAT:
 		if (!buf)
 			return -EFAULT;
-		err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));
+		err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
 		if (err)
 			return err;
 		if (shmid > max_shmid)
@@ -257,18 +257,26 @@
 			return -EINVAL;
 		if (ipcperms (&shp->shm_perm, S_IRUGO))
 			return -EACCES;
-		id = shmid + shp->shm_perm.seq * SHMMNI; 
-		memcpy_tofs (buf, shp, sizeof(*shp));
+		id = (unsigned int) shp->shm_perm.seq * SHMMNI + shmid;
+		tbuf.shm_perm   = shp->shm_perm;
+		tbuf.shm_segsz  = shp->shm_segsz;
+		tbuf.shm_atime  = shp->shm_atime;
+		tbuf.shm_dtime  = shp->shm_dtime;
+		tbuf.shm_ctime  = shp->shm_ctime;
+		tbuf.shm_cpid   = shp->shm_cpid;
+		tbuf.shm_lpid   = shp->shm_lpid;
+		tbuf.shm_nattch = shp->shm_nattch;
+		memcpy_tofs (buf, &tbuf, sizeof(*buf));
 		return id;
 	}
-	
-	shp = shm_segs[id = shmid % SHMMNI];
+
+	shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
 	if (shp == IPC_UNUSED || shp == IPC_NOID)
 		return -EINVAL;
-	ipcp = &shp->shm_perm;
-	if (ipcp->seq != shmid / SHMMNI) 
+	if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
 		return -EIDRM;
-	
+	ipcp = &shp->shm_perm;
+
 	switch (cmd) {
 	case SHM_UNLOCK:
 		if (!suser())
@@ -292,10 +300,18 @@
 			return -EACCES;
 		if (!buf)
 			return -EFAULT;
-		err = verify_area (VERIFY_WRITE, buf, sizeof (*shp));
+		err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
 		if (err)
 			return err;
-		memcpy_tofs (buf, shp, sizeof(*shp));
+		tbuf.shm_perm   = shp->shm_perm;
+		tbuf.shm_segsz  = shp->shm_segsz;
+		tbuf.shm_atime  = shp->shm_atime;
+		tbuf.shm_dtime  = shp->shm_dtime;
+		tbuf.shm_ctime  = shp->shm_ctime;
+		tbuf.shm_cpid   = shp->shm_cpid;
+		tbuf.shm_lpid   = shp->shm_lpid;
+		tbuf.shm_nattch = shp->shm_nattch;
+		memcpy_tofs (buf, &tbuf, sizeof(*buf));
 		break;
 	case IPC_SET:
 		if (suser() || current->euid == shp->shm_perm.uid ||
@@ -312,7 +328,7 @@
 		if (suser() || current->euid == shp->shm_perm.uid ||
 		    current->euid == shp->shm_perm.cuid) {
 			shp->shm_perm.mode |= SHM_DEST;
-			if (shp->shm_nattch <= 0) 
+			if (shp->shm_nattch <= 0)
 				killseg (id);
 			break;
 		}
@@ -334,9 +350,9 @@
 	unsigned long *page_table;
 	unsigned long tmp, shm_sgn;
 	unsigned long page_dir = shmd->task->tss.cr3;
-	
+
 	/* check that the range is unmapped and has page_tables */
-	for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) { 
+	for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) {
 		page_table = PAGE_DIR_OFFSET(page_dir,tmp);
 		if (*page_table & PAGE_PRESENT) {
 			page_table = (ulong *) (PAGE_MASK & *page_table);
@@ -353,10 +369,10 @@
 				invalid++;
 			}
 			continue;
-		}  
+		}
 	      {
 		unsigned long new_pt;
-		if(!(new_pt = get_free_page(GFP_KERNEL)))	/* clearing needed?  SRB. */
+		if (!(new_pt = get_free_page(GFP_KERNEL)))
 			return -ENOMEM;
 		*page_table = new_pt | PAGE_TABLE;
 		tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE);
@@ -366,8 +382,8 @@
 
 	/* map page range */
 	shm_sgn = shmd->shm_sgn;
-	for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE, 
-	     shm_sgn += (1 << SHM_IDX_SHIFT)) { 
+	for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE,
+	     shm_sgn += (1 << SHM_IDX_SHIFT)) {
 		page_table = PAGE_DIR_OFFSET(page_dir,tmp);
 		page_table = (ulong *) (PAGE_MASK & *page_table);
 		page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
@@ -404,7 +420,7 @@
 	vma->vm_task = current;
 	vma->vm_start = addr;
 	vma->vm_end = addr + len;
-	vma->vm_flags = VM_SHM | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC;
+	vma->vm_flags = VM_SHM | VM_SHARED | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC;
 	if (readonly)
 		vma->vm_page_prot = PAGE_READONLY;
 	else {
@@ -420,10 +436,9 @@
 	return 0;
 }
 
-/* 
+/*
  * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
  * raddr is needed to return addresses above 2Gig.
- * Specific attaches are allowed over the executable....
  */
 int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
 {
@@ -432,17 +447,17 @@
 	int err;
 	unsigned int id;
 	unsigned long addr;
-	
+
 	if (shmid < 0)
 		return -EINVAL;
 
 	if (raddr) {
-		err = verify_area(VERIFY_WRITE, raddr, sizeof(long));
+		err = verify_area(VERIFY_WRITE, raddr, sizeof(ulong));
 		if (err)
 			return err;
 	}
 
-	shp = shm_segs[id = shmid % SHMMNI];
+	shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
 	if (shp == IPC_UNUSED || shp == IPC_NOID)
 		return -EINVAL;
 
@@ -450,7 +465,7 @@
 		if (shmflg & SHM_REMAP)
 			return -EINVAL;
 		/* set addr below  all current unspecified attaches */
-		addr = SHM_RANGE_END; 
+		addr = SHM_RANGE_END;
 		for (shmd = current->shm; shmd; shmd = shmd->task_next) {
 			if (shmd->start < SHM_RANGE_START)
 				continue;
@@ -459,7 +474,7 @@
 		}
 		addr = (addr - shp->shm_segsz) & PAGE_MASK;
 	} else if (addr & (SHMLBA-1)) {
-		if (shmflg & SHM_RND) 
+		if (shmflg & SHM_RND)
 			addr &= ~(SHMLBA-1);       /* round down */
 		else
 			return -EINVAL;
@@ -470,26 +485,26 @@
 		for (shmd = current->shm; shmd; shmd = shmd->task_next) {
 			if (addr >= shmd->start && addr < shmd->end)
 				return -EINVAL;
-			if (addr + shp->shm_segsz >= shmd->start && 
+			if (addr + shp->shm_segsz >= shmd->start &&
 			    addr + shp->shm_segsz < shmd->end)
 				return -EINVAL;
 		}
 
 	if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO))
 		return -EACCES;
-	if (shp->shm_perm.seq != shmid / SHMMNI) 
+	if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
 		return -EIDRM;
 
 	shmd = (struct shm_desc *) kmalloc (sizeof(*shmd), GFP_KERNEL);
 	if (!shmd)
 		return -ENOMEM;
-	if ((shp != shm_segs[id]) || (shp->shm_perm.seq != shmid / SHMMNI)) {
+	if ((shp != shm_segs[id]) || (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)) {
 		kfree(shmd);
 		return -EIDRM;
 	}
 	shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) |
 		(shmflg & SHM_RDONLY ? SHM_READ_ONLY : 0);
-       	shmd->start = addr;
+	shmd->start = addr;
 	shmd->end = addr + shp->shm_npages * PAGE_SIZE;
 	shmd->task = current;
 
@@ -506,7 +521,7 @@
 		kfree(shmd);
 		return err;
 	}
-		
+
 	shmd->task_next = current->shm;
 	current->shm = shmd;
 	shmd->seg_next = shp->attaches;
@@ -526,28 +541,28 @@
  */
 static void detach (struct shm_desc **shmdp)
 {
- 	struct shm_desc *shmd = *shmdp; 
-  	struct shmid_ds *shp;
-  	int id;
-	
+	struct shm_desc *shmd = *shmdp;
+	struct shmid_ds *shp;
+	int id;
+
 	id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK;
-  	shp = shm_segs[id];
- 	*shmdp = shmd->task_next;
- 	for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next)
+	shp = shm_segs[id];
+	*shmdp = shmd->task_next;
+	for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next)
 		if (*shmdp == shmd) {
-			*shmdp = shmd->seg_next; 
-			goto found; 
+			*shmdp = shmd->seg_next;
+			goto found;
 		}
- 	printk("detach: shm segment (id=%d) attach list inconsistent\n",id);
-	
+	printk("detach: shm segment (id=%d) attach list inconsistent\n",id);
+
  found:
 	do_munmap(shmd->start, shp->shm_segsz);
 	kfree(shmd);
-  	shp->shm_lpid = current->pid;
+	shp->shm_lpid = current->pid;
 	shp->shm_dtime = CURRENT_TIME;
 	if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
 		killseg (id); /* sleeps */
-  	return;
+	return;
 }
 
 /*
@@ -556,9 +571,9 @@
  */
 int sys_shmdt (char *shmaddr)
 {
-	struct shm_desc *shmd, **shmdp;	
-	
-	for (shmdp = &current->shm; (shmd = *shmdp); shmdp=&shmd->task_next) { 
+	struct shm_desc *shmd, **shmdp;
+
+	for (shmdp = &current->shm; (shmd = *shmdp); shmdp=&shmd->task_next) {
 		if (shmd->start == (ulong) shmaddr) {
 			detach (shmdp);
 			return 0;
@@ -567,17 +582,17 @@
 	return -EINVAL;
 }
 
-/* 
- * detach all attached segments. 
+/*
+ * detach all attached segments.
  */
 void shm_exit (void)
 {
- 	while (current->shm) 
+	while (current->shm)
 		detach(&current->shm);
-  	return;
+	return;
 }
 
-/* 
+/*
  * copy the parent shm descriptors and update nattch
  * parent is stuck in fork so an attach on each segment is assured.
  * copy_page_tables does the mapping.
@@ -588,17 +603,17 @@
 	struct shmid_ds *shp;
 	int id;
 
-	p2->semun = NULL;
+	p2->semundo = NULL;
 	p2->shm = NULL;
         if (!p1->shm)
 		return 0;
 	for (shmd = p1->shm; shmd; shmd = shmd->task_next) {
 		tmp = (struct shm_desc *) kmalloc(sizeof(*tmp), GFP_KERNEL);
 		if (!tmp) {
-			while (new_desc) { 
-				tmp = new_desc->task_next; 
+			while (new_desc) {
+				tmp = new_desc->task_next;
 				kfree(new_desc);
-				new_desc = tmp; 
+				new_desc = tmp;
 			}
 			free_page_tables (p2);
 			return -ENOMEM;
@@ -670,7 +685,7 @@
 		}
 		shm_rss++;
 		shp->shm_pages[idx] = page | (PAGE_SHARED | PAGE_DIRTY);
-	} else 
+	} else
 		--current->mm->maj_flt;  /* was incremented in do_no_page */
 
 done:
@@ -683,7 +698,7 @@
 }
 
 /*
- * Goes through counter = (shm_rss << prio) present shm pages. 
+ * Goes through counter = (shm_rss << prio) present shm pages.
  */
 static unsigned long swap_id = 0; /* currently being swapped */
 static unsigned long swap_idx = 0; /* next to swap */
@@ -704,7 +719,7 @@
  check_id:
 	shp = shm_segs[swap_id];
 	if (shp == IPC_UNUSED || shp == IPC_NOID || shp->shm_perm.mode & SHM_LOCKED ) {
-		swap_idx = 0; 
+		swap_idx = 0;
 		if (++swap_id > max_shmid)
 			swap_id = 0;
 		goto check_id;
@@ -712,8 +727,8 @@
 	id = swap_id;
 
  check_table:
-	idx = swap_idx++; 
-	if (idx  >= shp->shm_npages) { 
+	idx = swap_idx++;
+	if (idx >= shp->shm_npages) {
 		swap_idx = 0;
 		if (++swap_id > max_shmid)
 			swap_id = 0;
@@ -743,12 +758,12 @@
 			continue;
 		}
 		pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp);
-		if (!(*pte & 1)) { 
-			printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n", 
+		if (!(*pte & PAGE_PRESENT)) {
+			printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n",
 					id, shmd->start, idx);
 			*pte = 0;
 			continue;
-		} 
+		}
 		pte = (ulong *) (PAGE_MASK & *pte);
 		pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
 		tmp = *pte;
@@ -756,7 +771,7 @@
 			continue;
 		if (tmp & PAGE_ACCESSED) {
 			*pte &= ~PAGE_ACCESSED;
-			continue;  
+			continue;
 		}
 		tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT;
 		*pte = tmp;
@@ -765,7 +780,7 @@
 		invalid++;
 	}
 
-	if (mem_map[MAP_NR(page)] != 1) 
+	if (mem_map[MAP_NR(page)] != 1)
 		goto check_table;
 	page &= PAGE_MASK;
 	shp->shm_pages[idx] = swap_nr;
diff -u --recursive --new-file v1.1.60/linux/ipc/util.c linux/ipc/util.c
--- v1.1.60/linux/ipc/util.c	Fri Feb 18 16:20:22 1994
+++ linux/ipc/util.c	Tue Nov  1 19:50:45 1994
@@ -13,7 +13,7 @@
 #include <linux/stat.h>
 
 void ipc_init (void);
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr); 
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr);
 
 #ifdef CONFIG_SYSVIPC
 
@@ -21,16 +21,16 @@
 extern void sem_init (void), msg_init (void), shm_init (void);
 extern int sys_semget (key_t key, int nsems, int semflg);
 extern int sys_semop (int semid, struct sembuf *sops, unsigned nsops);
-extern int sys_semctl (int semid, int semnum, int cmd, void *arg);
+extern int sys_semctl (int semid, int semnum, int cmd, union semun arg);
 extern int sys_msgget (key_t key, int msgflg);
 extern int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
 extern int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
 		       int msgflg);
 extern int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
-extern int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
 extern int sys_shmget (key_t key, int size, int flag);
 extern int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr);
 extern int sys_shmdt (char *shmaddr);
+extern int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
 
 void ipc_init (void)
 {
@@ -71,8 +71,16 @@
 			return sys_semop (first, (struct sembuf *)ptr, second);
 		case SEMGET:
 			return sys_semget (first, second, third);
-		case SEMCTL:
-			return sys_semctl (first, second, third, ptr);
+		case SEMCTL: {
+			union semun fourth;
+			int err;
+			if (!ptr)
+				return -EINVAL;
+			if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
+				return err;
+			fourth.__pad = (void *) get_fs_long(ptr);
+			return sys_semctl (first, second, third, fourth);
+			}
 		default:
 			return -EINVAL;
 		}
@@ -82,10 +90,13 @@
 			return sys_msgsnd (first, (struct msgbuf *) ptr, 
 					   second, third);
 		case MSGRCV: {
-			struct ipc_kludge tmp; 
+			struct ipc_kludge tmp;
+			int err;
 			if (!ptr)
 				return -EINVAL;
-			memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, 
+			if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
+				return err;
+			memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
 				       sizeof (tmp));
 			return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
 					 	third);
@@ -93,14 +104,13 @@
 		case MSGGET:
 			return sys_msgget ((key_t) first, second);
 		case MSGCTL:
-			return sys_msgctl (first, second, 
-						(struct msqid_ds *) ptr);
+			return sys_msgctl (first, second, (struct msqid_ds *) ptr);
 		default:
 			return -EINVAL;
 		}
 	if (call <= SHMCTL) 
 		switch (call) {
-		case SHMAT: /* returning shmaddr > 2G will screw up */
+		case SHMAT:
 			return sys_shmat (first, (char *) ptr, second, 
 							(ulong *) third);
 		case SHMDT: 
@@ -108,8 +118,7 @@
 		case SHMGET:
 			return sys_shmget (first, second, third);
 		case SHMCTL:
-			return sys_shmctl (first, second, 
-						(struct shmid_ds *) ptr);
+			return sys_shmctl (first, second, (struct shmid_ds *) ptr);
 		default:
 			return -EINVAL;
 		}
diff -u --recursive --new-file v1.1.60/linux/kernel/exit.c linux/kernel/exit.c
--- v1.1.60/linux/kernel/exit.c	Tue Aug  9 09:34:45 1994
+++ linux/kernel/exit.c	Tue Nov  1 19:50:45 1994
@@ -411,7 +411,7 @@
 		intr_count = 0;
 	}
 fake_volatile:
-	if (current->semun)
+	if (current->semundo)
 		sem_exit();
 	if (current->shm)
 		shm_exit();
diff -u --recursive --new-file v1.1.60/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.1.60/linux/kernel/ksyms.c	Wed Nov  2 12:03:47 1994
+++ linux/kernel/ksyms.c	Tue Nov  1 19:50:45 1994
@@ -28,6 +28,7 @@
 #include <linux/tty.h>
 #include <linux/serial.h>
 #include <linux/locks.h>
+#include <linux/string.h>
 #ifdef CONFIG_INET
 #include <linux/net.h>
 #include <linux/netdevice.h>
@@ -46,7 +47,6 @@
 #endif
 
 extern int sys_tz;
-extern int ___strtok;
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
 
@@ -92,6 +92,13 @@
 	X(open_namei),
 	X(inode_setattr),
 	X(inode_change_ok),
+	X(generic_mmap),
+	X(set_blocksize),
+	X(getblk),
+	X(bread),
+	X(brelse),
+	X(ll_rw_block),
+	X(__wait_on_buffer),
 
 	/* device registration */
 	X(register_chrdev),
@@ -156,6 +163,7 @@
 	X(printk),
 	X(sprintf),
 	X(vsprintf),
+	X(simple_strtoul),
 	X(system_utsname),
 	X(sys_call_table),
 
@@ -206,26 +214,16 @@
 #endif
 	/* Added to make file system as module */
 	X(set_writetime),
-	X(getblk),
-	X(inode_setattr),
 	X(sys_tz),
-	X(inode_change_ok),
 	X(__wait_on_super),
 	X(file_fsync),
-	X(simple_strtoul),
-	X(generic_mmap),
-	X(set_blocksize),
 	X(clear_inode),
 	X(refile_buffer),
 	X(___strtok),
-	X(brelse),
-	X(bread),
 	X(init_fifo),
 	X(super_blocks),
 	X(chrdev_inode_operations),
 	X(blkdev_inode_operations),
-	X(ll_rw_block),
-	X(__wait_on_buffer),
 	X(read_ahead),
 	/********************************************************
 	 * Do not add anything below this line,
diff -u --recursive --new-file v1.1.60/linux/mm/memory.c linux/mm/memory.c
--- v1.1.60/linux/mm/memory.c	Sun Oct 23 12:33:58 1994
+++ linux/mm/memory.c	Tue Nov  1 19:50:45 1994
@@ -319,7 +319,7 @@
 		for (pc = pcnt; pc--; page_table++) {
 			if ((page = *page_table) != 0) {
 				*page_table = 0;
-				if (1 & page) {
+				if (PAGE_PRESENT & page) {
 					if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
 						if (current->mm->rss > 0)
 							--current->mm->rss;
diff -u --recursive --new-file v1.1.60/linux/net/inet/af_inet.c linux/net/inet/af_inet.c
--- v1.1.60/linux/net/inet/af_inet.c	Wed Nov  2 12:03:47 1994
+++ linux/net/inet/af_inet.c	Wed Nov  2 11:32:03 1994
@@ -624,7 +624,7 @@
 	sk->prot = prot;
 	sk->sleep = sock->wait;
 	sk->daddr = 0;
-	sk->saddr = ip_my_addr();
+	sk->saddr = 0 /* ip_my_addr() */;
 	sk->err = 0;
 	sk->next = NULL;
 	sk->pair = NULL;
@@ -749,6 +749,7 @@
 	/* This will destroy it. */
 	release_sock(sk);
 	sock->data = NULL;
+	sk->socket = NULL;
 	return(0);
 }
 
@@ -1261,6 +1262,10 @@
 /*
  * This routine must find a socket given a TCP or UDP header.
  * Everything is assumed to be in net order.
+ *
+ * We give priority to more closely bound ports: if some socket
+ * is bound to a particular foreign address, it will get the packet
+ * rather than somebody listening to any address..
  */
 
 struct sock *get_sock(struct proto *prot, unsigned short num,
@@ -1268,6 +1273,8 @@
 				unsigned short rnum, unsigned long laddr)
 {
 	struct sock *s;
+	struct sock *result = NULL;
+	int badness = -1;
 	unsigned short hnum;
 
 	hnum = ntohs(num);
@@ -1284,21 +1291,41 @@
 	for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
 			s != NULL; s = s->next) 
 	{
+		int score = 0;
+
 		if (s->num != hnum) 
 			continue;
+
 		if(s->dead && (s->state == TCP_CLOSE))
 			continue;
-		if(ip_addr_match(s->saddr,laddr) == 0)
-			continue;
-		if(prot == &udp_prot)
+		/* local address matches? */
+		if (s->saddr) {
+			if (s->saddr != laddr)
+				continue;
+			score++;
+		}
+		/* remote address matches? */
+		if (s->daddr) {
+			if (s->daddr != raddr)
+				continue;
+			score++;
+		}
+		/* remote port matches? */
+		if (s->dummy_th.dest) {
+			if (s->dummy_th.dest != rnum)
+				continue;
+			score++;
+		}
+		/* perfect match? */
+		if (score == 3)
 			return s;
-		if(ip_addr_match(s->daddr,raddr)==0)
-			continue;
-		if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) 
+		/* no, check if this is the best so far.. */
+		if (score <= badness)
 			continue;
-		return(s);
+		result = s;
+		badness = score;
   	}
-  	return(NULL);
+  	return result;
 }
 
 static struct proto_ops inet_proto_ops = {
diff -u --recursive --new-file v1.1.60/linux/net/inet/ip.c linux/net/inet/ip.c
--- v1.1.60/linux/net/inet/ip.c	Wed Oct 12 15:35:00 1994
+++ linux/net/inet/ip.c	Tue Nov  1 19:50:45 1994
@@ -200,13 +200,6 @@
 	int tmp;
 	unsigned long src;
 
-	/*
-	 *	If there is no 'from' address as yet, then make it our loopback
-	 */
-
-	if (saddr == 0)
-		saddr = ip_my_addr();
-
 	buff = skb->data;
 
 	/*
@@ -254,6 +247,12 @@
 
 		raddr = (rt == NULL) ? 0 : rt->rt_gateway;
 	}
+
+	/*
+	 *	No source addr so make it our addr
+	 */
+	if (saddr == 0)
+		saddr = src;
 
 	/*
 	 *	No gateway so aim at the real destination
diff -u --recursive --new-file v1.1.60/linux/net/inet/proc.c linux/net/inet/proc.c
--- v1.1.60/linux/net/inet/proc.c	Wed Jul 13 01:01:40 1994
+++ linux/net/inet/proc.c	Wed Nov  2 12:33:50 1994
@@ -95,7 +95,7 @@
 				format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, 
 				format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
 				timer_active, sp->timer.expires, (unsigned) sp->retransmits,
-				sp->dead?0:SOCK_INODE(sp->socket)->i_uid);
+				sp->socket?SOCK_INODE(sp->socket)->i_uid:0);
 			if (timer_active)
 				add_timer(&sp->timer);
 			/*
diff -u --recursive --new-file v1.1.60/linux/net/inet/route.c linux/net/inet/route.c
--- v1.1.60/linux/net/inet/route.c	Wed Nov  2 12:03:47 1994
+++ linux/net/inet/route.c	Tue Nov  1 19:50:45 1994
@@ -542,9 +542,9 @@
 		/*
 		 *	broadcast addresses can be special cases.. 
 		 */
-		 
-		if ((rt->rt_gateway == 0) &&
-		    (rt->rt_dev->flags & IFF_BROADCAST) &&
+		if (rt->rt_flags & RTF_GATEWAY)
+			continue;		 
+		if ((rt->rt_dev->flags & IFF_BROADCAST) &&
 		    (rt->rt_dev->pa_brdaddr == daddr))
 			break;
 	}
diff -u --recursive --new-file v1.1.60/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.60/linux/net/inet/tcp.c	Fri Oct 28 12:54:32 1994
+++ linux/net/inet/tcp.c	Tue Nov  1 19:50:46 1994
@@ -89,6 +89,10 @@
  *		Michael Pall	:	Undo the last fix in tcp_read_urg() (multi URG PUSH broke rlogin).
  *		Michael Pall	:	Fix the multi URG PUSH problem in tcp_readable(), select() after URG works now.
  *		Michael Pall	:	recv(...,MSG_OOB) never blocks in the BSD api.
+ *		Alan Cox	:	Changed the semantics of sk->socket to 
+ *					fix a race and a signal problem with
+ *					accept() and async I/O.
+ *		Alan Cox	:	Relaxed the rules on tcp_sendto().
  *
  *
  * To Fix:
@@ -1227,7 +1231,7 @@
 {
 	if (flags & ~(MSG_OOB|MSG_DONTROUTE))
 		return -EINVAL;
-	if (!tcp_connected(sk->state))
+	if (sk->state == TCP_CLOSE)
 		return -ENOTCONN;
 	if (addr_len < sizeof(*addr))
 		return -EINVAL;
@@ -2084,6 +2088,7 @@
 	newsk->dummy_th.res2 = 0;
 	newsk->acked_seq = skb->h.th->seq + 1;
 	newsk->copied_seq = skb->h.th->seq;
+	newsk->socket = NULL;
 
 	/*
 	 *	Grab the ttl and tos values and use them 
