diff -u --recursive --new-file v1.3.73/linux/CREDITS linux/CREDITS
--- v1.3.73/linux/CREDITS	Wed Mar 13 10:09:07 1996
+++ linux/CREDITS	Thu Mar 14 12:57:45 1996
@@ -394,6 +394,13 @@
 E: philipg@onsett.com
 D: Kernel / timekeeping stuff
 
+N: Grant Guenther
+E: grant@torque.net
+D: Iomega PPA / ZIP driver
+S: 906-1001 Bay St.
+S: Toronto, Ontario, M5S 3A6 
+S: Canada
+
 N: Miquel van Smoorenburg
 E: miquels@cistron.nl
 D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff.
diff -u --recursive --new-file v1.3.73/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v1.3.73/linux/Documentation/Configure.help	Wed Mar 13 10:09:08 1996
+++ linux/Documentation/Configure.help	Thu Mar 14 12:57:45 1996
@@ -815,9 +815,9 @@
 PC/TCP compatibility mode
 CONFIG_INET_PCTCP
   If you have been having difficulties telneting to your Linux machine
-  from a DOS system that uses (broken) PC/TCP networking software, try
-  enabling this option.  Everyone else says N. As of later 1.3.x kernels
-  nobody should need this option. Please report if it solves problems.
+  from a DOS system that uses (broken) PC/TCP networking software (all
+  versions up to OnNet 2.0), try enabling this option.  Everyone else
+  says N.
 
 Reverse ARP
 CONFIG_INET_RARP
@@ -1054,16 +1054,16 @@
 SCSI generic support
 CONFIG_CHR_DEV_SG
   If you want to use SCSI scanners, synthesizers or CD-writers or just
-  about anything having "SCSI" in its name, say Y here. Those won't be
-  supported by the kernel directly, so you need some additional
-  software which knows how to talk to these things using the SCSI
-  protocol. Chances are that you'll have to write that software
-  yourself, so have a look at the SCSI-HOWTO and at the
-  SCSI-Programming-HOWTO, both available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile this
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt and Documentation/scsi.txt.
+  about anything having "SCSI" in its name other than disks, CDROMs or
+  tapes, say Y here. Those won't be supported by the kernel directly,
+  so you need some additional software which knows how to talk to
+  these things using the SCSI protocol. Chances are that you'll have
+  to write that software yourself, so have a look at the SCSI-HOWTO
+  and at the SCSI-Programming-HOWTO, both available via ftp (user:
+  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to
+  compile this as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read Documentation/modules.txt and Documentation/scsi.txt.
 
 Probe all LUNs on each SCSI device
 CONFIG_SCSI_MULTI_LUN
@@ -1341,6 +1341,18 @@
   available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO, is for you.
 
+IOMEGA Parallel Port ZIP drive SCSI support
+CONFIG_SCSI_PPA
+  This driver supports the parallel port version of IOMEGA's ZIP
+  drive (a 100Mb removable media device).  For more infomation 
+  about this driver and how to use it you should read the file
+  drivers/scsi/README.ppa.  You should also read the SCSI-HOWTO,
+  which is available via anonymous ftp from sunsite.unc.edu in
+  the directory /pub/Linux/docs/HOWTO.  This driver is also available
+  as a module which can be inserted in and removed from the
+  running kernel whenever you want. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 Network device support?
 CONFIG_NETDEVICES
   You can say N here in case you don't intend to connect to any other
@@ -1583,9 +1595,10 @@
 
 SMC 9194 Support
 CONFIG_SMC9194
-  This has support for the SMC9xxx based Ethernet cards.  Choose this option
-  if you have a DELL laptop with the docking station, or another SMC9192/9194
-  based chipset.  Say Y if you want it compiled into the kernel, and read  
+  This is support for the SMC9xxx based Ethernet cards.  Choose this
+  option if you have a DELL laptop with the docking station, or
+  another SMC9192/9194 based chipset.  Say Y if you want it compiled
+  into the kernel, and read the the file drivers/net/README.smc9 and
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  This driver is also
   available as a module ( = code which can be inserted in and removed
@@ -1682,9 +1695,9 @@
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If your card is not working
-  you may need to use the DOS setup disk to disable Plug & Play mode, and
-  to select the default media type.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If your card is not
+  working you may need to use the DOS setup disk to disable Plug &
+  Play mode, and to select the default media type.
 
 3c590 series (592/595/597) "Vortex" support
 CONFIG_VORTEX
@@ -2006,7 +2019,9 @@
 
 DE425, DE434, DE435 support
 CONFIG_DE4X5
-  If you have a network (ethernet) card of this type, say Y and read
+  This is support for the DIGITAL series of PCI/EISA ethernet
+  cards. These include the DE425, DE434, DE435, DE450 and DE500
+  models. If you have a network card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  More specific information is
   contained in drivers/net/README.de4x5. This driver is also available
@@ -2383,7 +2398,8 @@
   partitions. It does not support Windows'95 compressed filesystems.
   You cannot use the VFAT filesystem for your root partition; use
   UMSDOS instead. This option enlarges your kernel by about 10 kB and
-  it only works if you enabled the "fat fs support" above. 
+  it only works if you enabled the "fat fs support" above. Please read
+  the file Documentation/filesystems/vfat.txt for details.
   If unsure, say N. If you want to compile this as a module ( = code 
   which can be inserted in and removed from the running kernel whenever 
   you want), say M here and read Documentation/modules.txt.
@@ -2699,7 +2715,9 @@
   (and their companion controller) is also supported. If you have a
   special controller (such as the CMS FC-10, FC-20, Iomega Mach-II, or
   Ditto Dash), you must configure it by editing the file
-  drivers/char/ftape/Makefile.  This driver is also available as a
+  drivers/char/ftape/Makefile. If you want to use such a tape drive on
+  a PCI-bus based system, please read the file
+  drivers/char/ftape/README.PCI. This driver is also available as a
   runtime loadable module ( = code which can be inserted in and
   removed from the running kernel whenever you want). If you want to
   compile it as a module, say M here and read
@@ -2962,3 +2980,5 @@
 # LocalWords:  NOWAYOUT behaviour dialin isdn callback BTX Teles ICN EDSS Cisco
 # LocalWords:  ipppd syncppp RFC MPP VJ downloaded icn NICCY Creatix shmem ufr
 # LocalWords:  ibp md ARCnet ether encap NDIS arcether ODI Amigas AmiTCP NetBSD
+# LocalWords:  initrd tue util DES funet des OnNet BIOSP smc Travan Iomega CMS
+# LocalWords:  FC
diff -u --recursive --new-file v1.3.73/linux/Makefile linux/Makefile
--- v1.3.73/linux/Makefile	Wed Mar 13 10:09:09 1996
+++ linux/Makefile	Wed Mar 13 10:05:09 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 73
+SUBLEVEL = 74
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.73/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v1.3.73/linux/arch/i386/mm/init.c	Wed Mar 13 10:09:12 1996
+++ linux/arch/i386/mm/init.c	Wed Mar 13 18:57:00 1996
@@ -236,6 +236,8 @@
 		start_mem += PAGE_SIZE;
 	}
 	for (tmp = 0 ; tmp < high_memory ; tmp += PAGE_SIZE) {
+		if (tmp >= 16*1024*1024)
+			mem_map[MAP_NR(tmp)].dma = 0;
 		if (mem_map[MAP_NR(tmp)].reserved) {
 			if (tmp >= 0xA0000 && tmp < 0x100000)
 				reservedpages++;
diff -u --recursive --new-file v1.3.73/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v1.3.73/linux/arch/sparc/mm/srmmu.c	Tue Mar  5 10:10:51 1996
+++ linux/arch/sparc/mm/srmmu.c	Thu Mar 14 09:20:05 1996
@@ -902,7 +902,7 @@
 {
 	unsigned long pages;
 
-	pages = __get_free_pages(GFP_KERNEL, 1, ~0UL);
+	pages = __get_free_pages(GFP_KERNEL, 1, 0);
 	if(!pages)
 		return 0;
 	memset((void *) pages, 0, (PAGE_SIZE << 1));
diff -u --recursive --new-file v1.3.73/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.3.73/linux/drivers/block/floppy.c	Wed Mar 13 10:09:13 1996
+++ linux/drivers/block/floppy.c	Wed Mar 13 10:41:12 1996
@@ -171,28 +171,23 @@
 /* Dma Memory related stuff */
 
 /* Pure 2^n version of get_order */
-static inline int __get_order (int size)
+static inline int __get_order(unsigned long size)
 {
 	int order;
 
-#ifdef  _ASM_IO_H2
-	__asm__ __volatile__("bsr %1,%0"
-			     : "=r" (order)
-			     : "r" (size / PAGE_SIZE));
-#else
-	for (order = 0; order < NR_MEM_LISTS; ++order)
-		if (size <= (PAGE_SIZE << order))
-			return order;
-#endif
-	return NR_MEM_LISTS;
+	size >>= (PAGE_SHIFT-1);
+	order = -1;
+	do {
+		size >>= 1;
+		order++;
+	} while (size);
+	return order;
 }
 
 static unsigned long dma_mem_alloc(int size)
 {
 	int order = __get_order(size);
 
-	if (order >= NR_MEM_LISTS)
-		return(0);
 	return __get_dma_pages(GFP_KERNEL,order);
 }
 
diff -u --recursive --new-file v1.3.73/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.73/linux/drivers/block/ide.c	Wed Mar 13 10:09:14 1996
+++ linux/drivers/block/ide.c	Wed Mar 13 19:30:15 1996
@@ -524,7 +524,7 @@
  */
 static void init_gendisk (ide_hwif_t *hwif)
 {
-	struct gendisk *gd, **gdp;
+	struct gendisk *gd;
 	unsigned int unit, units, minors;
 	int *bs;
 
@@ -556,9 +556,8 @@
 	gd->init	= ide_geninit;		/* initialization function */
 	gd->real_devices= hwif;			/* ptr to internal data */
 
-	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) ;
-	gd->next = NULL;			/* link to tail of list */
-	hwif->gd = *gdp = gd;
+	gd->next = gendisk_head;		/* link new major into list */
+	hwif->gd = gendisk_head = gd;
 }
 
 static void do_reset1 (ide_drive_t *, int);		/* needed below */
@@ -2900,11 +2899,11 @@
 		}
 	}
 	/*
-	 * Check for serialization with ide1.
-	 * This code depends on us having already taken care of ide1.
+	 * Check for serialization with ide0.
+	 * This code depends on us having already taken care of ide0.
 	 */
-	if (hwif->serialized && hwif->index == 0 && ide_hwifs[1].present)
-		hwgroup = ide_hwifs[1].hwgroup;
+	if (hwif->index == 1 && ide_hwifs[0].serialized && ide_hwifs[0].present)
+		hwgroup = ide_hwifs[0].hwgroup;
 	/*
 	 * If this is the first interface in a group,
 	 * then we need to create the hwgroup structure
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/Makefile linux/drivers/char/ftape/Makefile
--- v1.3.73/linux/drivers/char/ftape/Makefile	Sun Mar 10 09:49:47 1996
+++ linux/drivers/char/ftape/Makefile	Thu Mar 14 11:51:40 1996
@@ -54,7 +54,7 @@
 # This enables some (most?) 2Mbps controllers:
 #FDC_OPT         = -DFDC_BASE=0x3E0 -DFDC_IRQ=6 -DFDC_DMA=2
 
-EXTRA_CFLAGS := $(FTAPE_OPT) $(FDC_OPT) -D__NO_VERSION__
+EXTRA_CFLAGS := $(FTAPE_OPT) $(FDC_OPT)
 
 O_TARGET := ftape.o
 O_OBJS   = kernel-interface.o tracing.o fdc-io.o fdc-isr.o \
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/RELEASE-NOTES linux/drivers/char/ftape/RELEASE-NOTES
--- v1.3.73/linux/drivers/char/ftape/RELEASE-NOTES	Sun Mar 10 09:49:47 1996
+++ linux/drivers/char/ftape/RELEASE-NOTES	Thu Mar 14 11:51:40 1996
@@ -1,3 +1,11 @@
+===== Release notes for ftape-2.07a, 14/03/96 =====
+
+Bugfixes by Marcin Dalecki <dalecki@namu03.gwdg.de>:
+- In the last release it just compiled against 1.3.70;
+  now the params to request_irq() and free_irq are() are fixed, so it also 
+  works in 1.3.73 :-)
+- Support for modules is now correct for newer kernels.
+
 ===== Release notes for ftape-2.07, 04/03/96 =====
 
 
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/calibr.c linux/drivers/char/ftape/calibr.c
--- v1.3.73/linux/drivers/char/ftape/calibr.c	Sun Mar 10 09:49:47 1996
+++ linux/drivers/char/ftape/calibr.c	Thu Mar 14 11:51:41 1996
@@ -20,7 +20,6 @@
  *      functions.
  */
 
-#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/ftape.h>
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/ecc.c linux/drivers/char/ftape/ecc.c
--- v1.3.73/linux/drivers/char/ftape/ecc.c	Sun Mar 10 09:49:47 1996
+++ linux/drivers/char/ftape/ecc.c	Thu Mar 14 11:51:41 1996
@@ -32,7 +32,6 @@
  *      for the QIC-40/80 floppy-tape driver for Linux.
  */
 
-#include <linux/module.h>
 #include <linux/ftape.h>
 #include <stdio.h>
 #include <sys/errno.h>
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/fc-10.c linux/drivers/char/ftape/fc-10.c
--- v1.3.73/linux/drivers/char/ftape/fc-10.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/fc-10.c	Thu Mar 14 11:51:41 1996
@@ -41,7 +41,6 @@
  *      This file contains code for the CMS FC-10/FC-20 card.
  */
 
-#include <linux/module.h>
 #include <linux/ftape.h>
 #include <asm/io.h>
 
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/fdc-io.c linux/drivers/char/ftape/fdc-io.c
--- v1.3.73/linux/drivers/char/ftape/fdc-io.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/fdc-io.c	Thu Mar 14 11:55:09 1996
@@ -21,7 +21,6 @@
  *      for the QIC-40/80 tape streamer device driver.
  */
 
-#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
@@ -69,6 +68,8 @@
 static byte fdc_drv_spec[4];	/* drive specification bytes for i82078 */
 static int perpend_mode;	/* true if fdc is in perpendicular mode */
 
+static char ftape_id[] = "ftape"; /* used by request irq and free irq */
+
 void fdc_catch_stray_interrupts(unsigned count)
 {
 	unsigned long flags;
@@ -1179,7 +1180,6 @@
 {
 	TRACE_FUN(8, "fdc_grab_irq_and_dma");
 	int result = 0;
-	static char ftape_id[] = "ftape";
 
 	if (fdc.hook == &do_ftape) {
 		/*  Get fast interrupt handler.
@@ -1193,7 +1193,7 @@
 			result = request_dma(fdc.dma, ftape_id);
 			if (result) {
 				TRACEx1(-1, "Unable to grab DMA%d for ftape driver", fdc.dma);
-				free_irq(fdc.irq, NULL);
+				free_irq(fdc.irq, ftape_id);
 				result = -EIO;
 			} else {
 				enable_irq(fdc.irq);
@@ -1224,7 +1224,7 @@
 		disable_dma(fdc.dma);	/* just in case... */
 		free_dma(fdc.dma);
 		disable_irq(fdc.irq);
-		free_irq(fdc.irq, NULL);
+		free_irq(fdc.irq, ftape_id);
 	}
 #ifdef FDC_DMA
 	if (result == 0 && FDC_DMA == 2) {
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/fdc-isr.c linux/drivers/char/ftape/fdc-isr.c
--- v1.3.73/linux/drivers/char/ftape/fdc-isr.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/fdc-isr.c	Thu Mar 14 11:53:44 1996
@@ -26,7 +26,6 @@
  *      code for the QIC-40/80 tape streamer device driver.
  */
 
-#include <linux/module.h>
 #include <linux/ftape.h>
 #include <asm/io.h>
 #include <asm/dma.h>
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/ftape-bsm.c linux/drivers/char/ftape/ftape-bsm.c
--- v1.3.73/linux/drivers/char/ftape/ftape-bsm.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/ftape-bsm.c	Thu Mar 14 11:53:44 1996
@@ -27,7 +27,6 @@
  *      QIC-40, QIC-80, QIC-3010 and QIC-3020 maps are implemented.
  */
 
-#include <linux/module.h>
 #include <linux/ftape.h>
 #include <linux/string.h>
 
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/ftape-ctl.c linux/drivers/char/ftape/ftape-ctl.c
--- v1.3.73/linux/drivers/char/ftape/ftape-ctl.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/ftape-ctl.c	Thu Mar 14 11:53:44 1996
@@ -20,7 +20,6 @@
  *      for the QIC-40/80 floppy-tape driver for Linux.
  */
 
-#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/ftape.h>
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/ftape-eof.c linux/drivers/char/ftape/ftape-eof.c
--- v1.3.73/linux/drivers/char/ftape/ftape-eof.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/ftape-eof.c	Thu Mar 14 11:53:44 1996
@@ -27,7 +27,6 @@
  *      for the QIC-40/80 floppy-tape driver for Linux.
  */
 
-#include <linux/module.h>
 #include <linux/ftape.h>
 #include <linux/string.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/ftape-io.c linux/drivers/char/ftape/ftape-io.c
--- v1.3.73/linux/drivers/char/ftape/ftape-io.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/ftape-io.c	Thu Mar 14 11:53:45 1996
@@ -26,7 +26,6 @@
  *      for the QIC-40/80 floppy-tape driver for Linux.
  */
 
-#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/ftape-read.c linux/drivers/char/ftape/ftape-read.c
--- v1.3.73/linux/drivers/char/ftape/ftape-read.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/ftape-read.c	Thu Mar 14 11:53:45 1996
@@ -26,7 +26,6 @@
  *      for the QIC-117 floppy-tape driver for Linux.
  */
 
-#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/ftape-rw.c linux/drivers/char/ftape/ftape-rw.c
--- v1.3.73/linux/drivers/char/ftape/ftape-rw.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/ftape-rw.c	Thu Mar 14 11:53:45 1996
@@ -26,7 +26,6 @@
  *      write routines for the QIC-117 floppy-tape driver for Linux.
  */
 
-#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/ftape.h>
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/ftape-write.c linux/drivers/char/ftape/ftape-write.c
--- v1.3.73/linux/drivers/char/ftape/ftape-write.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/ftape-write.c	Thu Mar 14 11:53:45 1996
@@ -29,7 +29,6 @@
  *      for the QIC-117 floppy-tape driver for Linux.
  */
 
-#include <linux/module.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/kernel-interface.c linux/drivers/char/ftape/kernel-interface.c
--- v1.3.73/linux/drivers/char/ftape/kernel-interface.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/kernel-interface.c	Thu Mar 14 11:53:45 1996
@@ -53,10 +53,6 @@
 byte *tape_buffer[NR_BUFFERS] =
 {NULL};
 
-#ifdef MODULE
-char kernel_version[] = UTS_RELEASE;
-#endif
-
 /*      Local vars.
  */
 static int busy_flag = 0;
diff -u --recursive --new-file v1.3.73/linux/drivers/char/ftape/tracing.c linux/drivers/char/ftape/tracing.c
--- v1.3.73/linux/drivers/char/ftape/tracing.c	Sun Mar 10 09:49:48 1996
+++ linux/drivers/char/ftape/tracing.c	Thu Mar 14 11:53:45 1996
@@ -21,7 +21,6 @@
  *      for the QIC-117 floppy-tape driver for Linux.
  */
 
-#include <linux/module.h>
 #include <linux/ftape.h>
 
 #include "tracing.h"
diff -u --recursive --new-file v1.3.73/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v1.3.73/linux/drivers/char/lp.c	Sat Mar  2 10:43:25 1996
+++ linux/drivers/char/lp.c	Thu Mar 14 12:57:45 1996
@@ -7,6 +7,7 @@
  * Copyright (C) 1994 by Alan Cox (Modularised it)
  * LPCAREFUL, LPABORT, LPGETSTATUS added by Chris Metcalf, metcalf@lcs.mit.edu
  * Statistics and support for slow printers by Rob Janssen, rob@knoware.nl
+ * "lp=" command line parameters added by Grant Guenther, grant@torque.net
  */
 
 #include <linux/module.h>
@@ -538,6 +539,10 @@
 	unsigned int testvalue;
 
 	base = LP_B(offset);
+	if (base == 0) 
+		return -1;		/* de-configured by command line */
+	if (LP_IRQ(offset) > 15) 
+		return -1;		/* bogus interrupt value */
 	size = (base == 0x3bc)? 3 : 8;
 	if (check_region(base, size) < 0)
 		return -1;
@@ -557,6 +562,33 @@
 		return 1;
 	} else
 		return 0;
+}
+
+/* Command line parameters:
+
+   When the lp driver is built in to the kernel, you may use the
+   LILO/LOADLIN command line to set the port addresses and interrupts
+   that the driver will use.
+
+   Syntax:	lp=port0[,irq0[,port1[,irq1[,port2[,irq2]]]]]
+
+   For example:   lp=0x378,0   or   lp=0x278,5,0x378,7
+
+   Note that if this feature is used, you must specify *all* the ports
+   you want considered, there are no defaults.  You can disable a
+   built-in driver with lp=0 .
+
+*/
+
+void	lp_setup(char *str, int *ints)
+
+{	
+        LP_B(0)   = ((ints[0] > 0) ? ints[1] : 0 );
+        LP_IRQ(0) = ((ints[0] > 1) ? ints[2] : 0 );
+        LP_B(1)   = ((ints[0] > 2) ? ints[3] : 0 );
+        LP_IRQ(1) = ((ints[0] > 3) ? ints[4] : 0 );
+        LP_B(2)   = ((ints[0] > 4) ? ints[5] : 0 );
+        LP_IRQ(2) = ((ints[0] > 5) ? ints[6] : 0 );
 }
 
 #ifdef MODULE
diff -u --recursive --new-file v1.3.73/linux/drivers/isdn/teles/buffers.c linux/drivers/isdn/teles/buffers.c
--- v1.3.73/linux/drivers/isdn/teles/buffers.c	Wed Feb 28 11:50:03 1996
+++ linux/drivers/isdn/teles/buffers.c	Thu Mar 14 09:19:48 1996
@@ -39,7 +39,7 @@
 	printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
 #endif
 
-	ptr = (struct Pages *) __get_free_pages(priority,bp->pageorder,~0);
+	ptr = (struct Pages *) __get_free_pages(priority,bp->pageorder,0);
 	if (!ptr) {
 		printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
 		return (-1);
diff -u --recursive --new-file v1.3.73/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v1.3.73/linux/drivers/net/Config.in	Sun Mar 10 09:49:49 1996
+++ linux/drivers/net/Config.in	Wed Mar 13 08:38:53 1996
@@ -41,6 +41,7 @@
   if [ "$CONFIG_NET_ALPHA" = "y" ]; then
     bool 'SEEQ8005 support' CONFIG_SEEQ8005
     tristate 'AT1700 support' CONFIG_AT1700
+    tristate 'FMV-181/182 support' CONFIG_FMV18X
     tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
     tristate 'EtherExpress support' CONFIG_EEXPRESS
     tristate 'NI5210 support' CONFIG_NI52
diff -u --recursive --new-file v1.3.73/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.73/linux/drivers/net/Makefile	Wed Mar 13 10:09:16 1996
+++ linux/drivers/net/Makefile	Wed Mar 13 08:38:53 1996
@@ -223,6 +223,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_FMV18X),y)
+L_OBJS += fmv18x.o
+else
+  ifeq ($(CONFIG_FMV18X),m)
+  M_OBJS += fmv18x.o
+  endif
+endif
+
 ifeq ($(CONFIG_EL1),y)
 L_OBJS += 3c501.o
 else
diff -u --recursive --new-file v1.3.73/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.3.73/linux/drivers/net/Space.c	Wed Mar 13 10:09:16 1996
+++ linux/drivers/net/Space.c	Wed Mar 13 08:38:53 1996
@@ -51,6 +51,7 @@
 extern int el3_probe(struct device *);
 extern int at1500_probe(struct device *);
 extern int at1700_probe(struct device *);
+extern int fmv18x_probe(struct device *);
 extern int eth16i_probe(struct device *);
 extern int depca_probe(struct device *);
 extern int apricot_probe(struct device *);
@@ -126,6 +127,9 @@
 #endif
 #ifdef CONFIG_AT1700
 	&& at1700_probe(dev)
+#endif
+#ifdef CONFIG_FMV18X		/* Fujitsu FMV-181/182 */
+	&& fmv18x_probe(dev)
 #endif
 #ifdef CONFIG_ETH16I
 	&& eth16i_probe(dev)	/* ICL EtherTeam 16i/32 */
diff -u --recursive --new-file v1.3.73/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v1.3.73/linux/drivers/net/eexpress.c	Wed Mar 13 10:09:17 1996
+++ linux/drivers/net/eexpress.c	Thu Mar 14 09:50:46 1996
@@ -1224,8 +1224,8 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, express_probe 
 };
 
-int irq[MAX_EEXP_CARDS] = {0, };
-int io[MAX_EEXP_CARDS] = {0, };
+int irq[EEXP_MAX_CARDS] = {0, };
+int io[EEXP_MAX_CARDS] = {0, };
 
 /* Ideally the user would give us io=, irq= for every card.  If any parameters
  * are specified, we verify and then use them.  If no parameters are given, we
@@ -1261,7 +1261,7 @@
 	for (this_dev = 0; this_dev < EEXP_MAX_CARDS; this_dev++) {
 		struct device *dev = &dev_eexp[this_dev];
 		if (dev->priv != NULL) {
-			kfree_s(dev->priv. sizeof(struct net_local));
+			kfree(dev->priv);
 			dev->priv = NULL;
 			release_region(dev->base_addr, EEXP_IO_EXTENT);
 			unregister_netdev(dev);
diff -u --recursive --new-file v1.3.73/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- v1.3.73/linux/drivers/net/fmv18x.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/fmv18x.c	Wed Mar 13 08:38:54 1996
@@ -0,0 +1,664 @@
+/* fmv18x.c: A network device driver for  the Fujitsu FMV-181/182.
+
+	Original: at1700.c (1993-94 by Donald Becker).
+		Copyright 1993 United States Government as represented by the
+		Director, National Security Agency.
+		The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+		Center of Excellence in Space Data and Information Sciences
+		   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	Modified by Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)
+		Copyright 1994 Fujitsu Laboratories Ltd.
+	Special thanks to:
+		Masayoshi UTAKA (utaka@ace.yk.fujitsu.co.jp)
+			for testing this driver.
+		H. NEGISHI (agy, negishi@sun45.psd.cs.fujitsu.co.jp)
+			for sugestion of some program modification.
+		Masahiro SEKIGUCHI <seki@sysrap.cs.fujitsu.co.jp>
+			for sugestion of some program modification.
+		Kazutoshi MORIOKA (morioka@aurora.oaks.cs.fujitsu.co.jp)
+			for testing this driver.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	This is a device driver for the Fujitsu FMV-181/182, which is a
+	straight-forward Fujitsu MB86965 implementation.
+
+  Sources:
+    at1700.c
+    The Fujitsu MB86965 datasheet.
+    The Fujitsu FMV-181/182 user's guide
+*/
+
+static const char *version =
+	"fmv18x.c:v1.3.71e 03/04/96  Yutaka TAMIYA (tamy@flab.fujitsu.co.jp)\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+static int fmv18x_probe_list[] =
+{0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0};
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 1
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+typedef unsigned char uchar;
+
+/* Information that need to be kept for each board. */
+struct net_local {
+	struct enet_statistics stats;
+	long open_time;				/* Useless example local info. */
+	uint tx_started:1;			/* Number of packet on the Tx queue. */
+	uchar tx_queue;				/* Number of packet on the Tx queue. */
+	ushort tx_queue_len;		/* Current length of the Tx queue. */
+};
+
+
+/* Offsets from the base address. */
+#define STATUS			0
+#define TX_STATUS		0
+#define RX_STATUS		1
+#define TX_INTR			2		/* Bit-mapped interrupt enable registers. */
+#define RX_INTR			3
+#define TX_MODE			4
+#define RX_MODE			5
+#define CONFIG_0		6		/* Misc. configuration settings. */
+#define CONFIG_1		7
+/* Run-time register bank 2 definitions. */
+#define DATAPORT		8		/* Word-wide DMA or programmed-I/O dataport. */
+#define TX_START		10
+#define COL16CNTL		11
+#define MODE13			13
+/* Fujitsu FMV-18x Card Configuration */
+#define	FJ_STATUS0		0x10
+#define	FJ_STATUS1		0x11
+#define	FJ_CONFIG0		0x12
+#define	FJ_CONFIG1		0x13
+#define	FJ_MACADDR		0x14	/* 0x14 - 0x19 */
+#define	FJ_BUFCNTL		0x1A
+#define	FJ_BUFDATA		0x1C
+#define FMV18X_IO_EXTENT	32
+
+/* Index to functions, as function prototypes. */
+
+extern int fmv18x_probe(struct device *dev);
+
+static int fmv18x_probe1(struct device *dev, short ioaddr);
+static int net_open(struct device *dev);
+static int	net_send_packet(struct sk_buff *skb, struct device *dev);
+static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void net_rx(struct device *dev);
+static int net_close(struct device *dev);
+static struct enet_statistics *net_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev);
+
+
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+   If dev->base_addr == 0, probe all likely locations.
+   If dev->base_addr == 1, always return failure.
+   If dev->base_addr == 2, allocate space for the device and return success
+   (detachable devices only).
+   */
+#ifdef HAVE_DEVLIST
+/* Support for a alternate probe manager, which will eliminate the
+   boilerplate below. */
+struct netdev_entry fmv18x_drv =
+{"fmv18x", fmv18x_probe1, FMV18X_IO_EXTENT, fmv18x_probe_list};
+#else
+int
+fmv18x_probe(struct device *dev)
+{
+	int i;
+	int base_addr = dev ? dev->base_addr : 0;
+
+	if (base_addr > 0x1ff)		/* Check a single specified location. */
+		return fmv18x_probe1(dev, base_addr);
+	else if (base_addr != 0)	/* Don't probe at all. */
+		return ENXIO;
+
+	for (i = 0; fmv18x_probe_list[i]; i++) {
+		int ioaddr = fmv18x_probe_list[i];
+ 		if (check_region(ioaddr, FMV18X_IO_EXTENT))
+			continue;
+		if (fmv18x_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
+
+	return ENODEV;
+}
+#endif
+
+/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
+   "signature", the default bit pattern after a reset.  This *doesn't* work --
+   there is no way to reset the bus interface without a complete power-cycle!
+
+   It turns out that ATI came to the same conclusion I did: the only thing
+   that can be done is checking a few bits and then diving right into MAC
+   address check. */
+
+int fmv18x_probe1(struct device *dev, short ioaddr)
+{
+	char irqmap[4] = {3, 7, 10, 15};
+	unsigned int i, irq;
+
+	/* Resetting the chip doesn't reset the ISA interface, so don't bother.
+	   That means we have to be careful with the register values we probe for.
+	   */
+
+	/* Check I/O address configuration and Fujitsu vendor code */
+	if (fmv18x_probe_list[inb(ioaddr + FJ_CONFIG0) & 0x07] != ioaddr
+ 	||  inb(ioaddr+FJ_MACADDR  ) != 0x00
+	||  inb(ioaddr+FJ_MACADDR+1) != 0x00
+	||  inb(ioaddr+FJ_MACADDR+2) != 0x0e)
+		return -ENODEV;
+
+	irq = irqmap[(inb(ioaddr + FJ_CONFIG0)>>6) & 0x03];
+
+	/* Snarf the interrupt vector now. */
+	if (request_irq(irq, &net_interrupt, 0, "fmv18x", NULL)) {
+		printk ("FMV-18x found at %#3x, but it's unusable due to a conflict on"
+				"IRQ %d.\n", ioaddr, irq);
+		return EAGAIN;
+	}
+
+	/* Allocate a new 'dev' if needed. */
+	if (dev == NULL)
+		dev = init_etherdev(0, sizeof(struct net_local));
+
+	/* Grab the region so that we can find another board if the IRQ request
+	   fails. */
+ 	request_region(ioaddr, FMV18X_IO_EXTENT, "fmv18x");
+
+	printk("%s: FMV-18x found at %#3x, IRQ %d, address ", dev->name,
+		   ioaddr, irq);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	irq2dev_map[irq] = dev;
+
+	for(i = 0; i < 6; i++) {
+		unsigned char val = inb(ioaddr + FJ_MACADDR + i);
+		printk("%02x", val);
+		dev->dev_addr[i] = val;
+	}
+
+	/* "FJ_STATUS0" 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
+	   rather than 150 ohm shielded twisted pair compensation.
+	   0x0000 == auto-sense the interface
+	   0x0800 == use TP interface
+	   0x1800 == use coax interface
+	   */
+	{
+		const char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2/5"};
+		ushort setup_value = inb(ioaddr + FJ_STATUS0);
+
+		switch( setup_value & 0x07 ){
+		case 0x01 /* 10base5 */:
+		case 0x02 /* 10base2 */: dev->if_port = 0x18; break;
+		case 0x04 /* 10baseT */: dev->if_port = 0x08; break;
+		default /* auto-sense*/: dev->if_port = 0x00; break;
+		}
+		printk(" %s interface.\n", porttype[(dev->if_port>>3) & 3]);
+	}
+
+	/* Initialize LAN Controller and LAN Card */
+	outb(0xda, ioaddr + CONFIG_0);	 /* Initialize LAN Controller */
+	outb(0x00, ioaddr + CONFIG_1);	 /* Stand by mode */
+	outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */
+	outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure (TAMIYA) */
+
+	/* wait for a while */
+	udelay(200);
+
+	/* Set the station address in bank zero. */
+	outb(0x00, ioaddr + CONFIG_1);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + 8 + i);
+
+	/* Switch to bank 1 and set the multicast table to accept none. */
+	outb(0x04, ioaddr + CONFIG_1);
+	for (i = 0; i < 8; i++)
+		outb(0x00, ioaddr + 8 + i);
+
+	/* Switch to bank 2 and lock our I/O address. */
+	outb(0x08, ioaddr + CONFIG_1);
+	outb(dev->if_port, ioaddr + MODE13);
+
+	if (net_debug)
+		printk(version);
+
+	/* Initialize the device structure. */
+	dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	if (dev->priv == NULL)
+		return -ENOMEM;
+	memset(dev->priv, 0, sizeof(struct net_local));
+
+	dev->open		= net_open;
+	dev->stop		= net_close;
+	dev->hard_start_xmit = net_send_packet;
+	dev->get_stats	= net_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+
+	/* Fill in the fields of 'dev' with ethernet-generic values. */
+	   
+	ether_setup(dev);
+	return 0;
+}
+
+
+static int net_open(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	/* Set the configuration register 0 to 32K 100ns. byte-wide memory,
+	   16 bit bus access, and two 4K Tx, enable the Rx and Tx. */
+	outb(0x5a, ioaddr + CONFIG_0);
+
+	/* Powerup and switch to register bank 2 for the run-time registers. */
+	outb(0xe8, ioaddr + CONFIG_1);
+
+	lp->tx_started = 0;
+	lp->tx_queue = 0;
+	lp->tx_queue_len = 0;
+
+	/* Clear Tx and Rx Status */
+	outb(0xff, ioaddr + TX_STATUS);
+	outb(0xff, ioaddr + RX_STATUS);
+	lp->open_time = jiffies;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	/* Enable the IRQ of the LAN Card */
+	outb(0x80, ioaddr + FJ_CONFIG1);
+
+	/* Enable both Tx and Rx interrupts */
+	outw(0x8182, ioaddr+TX_INTR);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int
+net_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	if (dev->tbusy) {
+		/* If we get here, some higher level has decided we are broken.
+		   There should really be a "kick me" function call instead. */
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 10)
+			return 1;
+		printk("%s: transmit timed out with status %04x, %s?\n", dev->name,
+			   htons(inw(ioaddr + TX_STATUS)),
+			   inb(ioaddr + TX_STATUS) & 0x80
+			   ? "IRQ conflict" : "network cable problem");
+		printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",
+			   dev->name, htons(inw(ioaddr + 0)),
+			   htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
+			   htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
+			   htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
+			   htons(inw(ioaddr +14)));
+		printk("eth card: %04x %04x\n",
+			htons(inw(ioaddr+FJ_STATUS0)),
+			htons(inw(ioaddr+FJ_CONFIG0)));
+		lp->stats.tx_errors++;
+		/* ToDo: We should try to restart the adaptor... */
+		cli();
+
+		/* Initialize LAN Controller and LAN Card */
+		outb(0xda, ioaddr + CONFIG_0);   /* Initialize LAN Controller */
+		outb(0x00, ioaddr + CONFIG_1);   /* Stand by mode */
+		outb(0x00, ioaddr + FJ_CONFIG1); /* Disable IRQ of LAN Card */
+		outb(0x00, ioaddr + FJ_BUFCNTL); /* Reset ? I'm not sure */
+		net_open(dev);
+
+		sti();
+	}
+
+	/* If some higher layer thinks we've missed an tx-done interrupt
+	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+	   itself. */
+	if (skb == NULL) {
+		dev_tint(dev);
+		return 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);
+	else {
+		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		unsigned char *buf = skb->data;
+
+		if (length > ETH_FRAME_LEN) {
+			if (net_debug)
+				printk("%s: Attempting to send a large packet (%d bytes).\n",
+					dev->name, length);
+			return 1;
+		}
+
+		if (net_debug > 4)
+			printk("%s: Transmitting a packet of length %lu.\n", dev->name,
+				   (unsigned long)skb->len);
+
+		/* Disable both interrupts. */
+		outw(0x0000, ioaddr + TX_INTR);
+		
+		outw(length, ioaddr + DATAPORT);
+		outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+
+		lp->tx_queue++;
+		lp->tx_queue_len += length + 2;
+
+		if (lp->tx_started == 0) {
+			/* If the Tx is idle, always trigger a transmit. */
+			outb(0x80 | lp->tx_queue, ioaddr + TX_START);
+			lp->tx_queue = 0;
+			lp->tx_queue_len = 0;
+			dev->trans_start = jiffies;
+			lp->tx_started = 1;
+			dev->tbusy = 0;
+		} else if (lp->tx_queue_len < 4096 - 1502)
+			/* Yes, there is room for one more packet. */
+			dev->tbusy = 0;
+
+		/* Re-enable interrupts */
+		outw(0x8182, ioaddr + TX_INTR);
+	}
+	dev_kfree_skb (skb, FREE_WRITE);
+
+	return 0;
+}
+
+/* The typical workload of the driver:
+   Handle the network interface interrupts. */
+static void
+net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct net_local *lp;
+	int ioaddr, status;
+
+	if (dev == NULL) {
+		printk ("fmv18x_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+	dev->interrupt = 1;
+
+	ioaddr = dev->base_addr;
+	lp = (struct net_local *)dev->priv;
+
+	/* Avoid multiple interrupts. */
+	outw(0x0000, ioaddr + TX_INTR);
+
+        status = inw(ioaddr + TX_STATUS);
+	outw(status, ioaddr + TX_STATUS);
+
+	if (net_debug > 4)
+		printk("%s: Interrupt with status %04x.\n", dev->name, status);
+	if (status & 0xff00
+		||  (inb(ioaddr + RX_MODE) & 0x40) == 0) {			/* Got a packet(s). */
+		net_rx(dev);
+	}
+	if (status & 0x00ff) {
+		if (status & 0x80) {
+			lp->stats.tx_packets++;
+			if (lp->tx_queue) {
+				outb(0x80 | lp->tx_queue, ioaddr + TX_START);
+				lp->tx_queue = 0;
+				lp->tx_queue_len = 0;
+				dev->trans_start = jiffies;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);	/* Inform upper layers. */
+			} else {
+				lp->tx_started = 0;
+				dev->tbusy = 0;
+				mark_bh(NET_BH);	/* Inform upper layers. */
+			}
+		}
+		if (status & 0x02 ) {
+			if (net_debug > 4)
+				printk("%s: 16 Collision occur during Txing.\n", dev->name);
+			/* Retry to send the packet */
+			outb(0x02, ioaddr + COL16CNTL);
+		}
+	}
+
+	dev->interrupt = 0;
+	outw(0x8182, ioaddr + TX_INTR);
+	return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+net_rx(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int boguscount = 10;	/* 5 -> 10: by agy 19940922 */
+
+	while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {
+		/* Clear PKT_RDY bit: by agy 19940922 */
+		/* outb(0x80, ioaddr + RX_STATUS); */
+		ushort status = inw(ioaddr + DATAPORT);
+
+		if (net_debug > 4)
+			printk("%s: Rxing packet mode %02x status %04x.\n",
+				   dev->name, inb(ioaddr + RX_MODE), status);
+#ifndef final_version
+		if (status == 0) {
+			outb(0x05, ioaddr + 14);
+			break;
+		}
+#endif
+
+		if ((status & 0xF0) != 0x20) {	/* There was an error. */
+			lp->stats.rx_errors++;
+			if (status & 0x08) lp->stats.rx_length_errors++;
+			if (status & 0x04) lp->stats.rx_frame_errors++;
+			if (status & 0x02) lp->stats.rx_crc_errors++;
+			if (status & 0x01) lp->stats.rx_over_errors++;
+		} else {
+			ushort pkt_len = inw(ioaddr + DATAPORT);
+			/* Malloc up new buffer. */
+			struct sk_buff *skb;
+
+			if (pkt_len > 1550) {
+				printk("%s: The FMV-18x claimed a very large packet, size %d.\n",
+					   dev->name, pkt_len);
+				outb(0x05, ioaddr + 14);
+				lp->stats.rx_errors++;
+				break;
+			}
+			skb = dev_alloc_skb(pkt_len+3);
+			if (skb == NULL) {
+				printk("%s: Memory squeeze, dropping packet (len %d).\n",
+					   dev->name, pkt_len);
+				outb(0x05, ioaddr + 14);
+				lp->stats.rx_dropped++;
+				break;
+			}
+			skb->dev = dev;
+			skb_reserve(skb,2);
+
+			insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);
+
+			if (net_debug > 5) {
+				int i;
+				printk("%s: Rxed packet of length %d: ", dev->name, pkt_len);
+				for (i = 0; i < 14; i++)
+					printk(" %02x", skb->data[i]);
+				printk(".\n");
+			}
+
+			skb->protocol=eth_type_trans(skb, dev);
+			netif_rx(skb);
+			lp->stats.rx_packets++;
+		}
+		if (--boguscount <= 0)
+			break;
+	}
+
+	/* If any worth-while packets have been received, dev_rint()
+	   has done a mark_bh(NET_BH) for us and will work on them
+	   when we get to the bottom-half routine. */
+	{
+		int i;
+		for (i = 0; i < 20; i++) {
+			if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)
+				break;
+			(void)inw(ioaddr + DATAPORT);				/* dummy status read */
+			outb(0x05, ioaddr + 14);
+		}
+
+		if (net_debug > 5 && i > 0)
+			printk("%s: Exint Rx packet with mode %02x after %d ticks.\n", 
+				   dev->name, inb(ioaddr + RX_MODE), i);
+	}
+
+	return;
+}
+
+/* The inverse routine to net_open(). */
+static int net_close(struct device *dev)
+{
+	int ioaddr = dev->base_addr;
+
+	((struct net_local *)dev->priv)->open_time = 0;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	/* Set configuration register 0 to disable Tx and Rx. */
+	outb(0xda, ioaddr + CONFIG_0);
+
+	/* Update the statistics -- ToDo. */
+
+	/* Power-down the chip.  Green, green, green! */
+	outb(0x00, ioaddr + CONFIG_1);
+
+	MOD_DEC_USE_COUNT;
+
+	/* Set the ethernet adaptor disable IRQ */
+	outb(0x00, ioaddr + FJ_CONFIG1);
+
+	return 0;
+}
+
+/* Get the current statistics.	This may be called with the card open or
+   closed. */
+static struct enet_statistics *
+net_get_stats(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	cli();
+	/* ToDo: Update the statistics from the device registers. */
+	sti();
+
+	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)
+{
+	short ioaddr = dev->base_addr;
+	if (dev->mc_count || dev->flags&(IFF_PROMISC|IFF_ALLMULTI)) 
+	{
+		/*
+		 *	We must make the kernel realise we had to move
+		 *	into promisc mode or we start all out war on
+		 *	the cable. - AC
+		 */
+		dev->flags|=IFF_PROMISC;		
+	
+		outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
+	} 
+	else
+		outb(2, ioaddr + RX_MODE);	/* Disable promiscuous, use normal mode */
+}
+
+#ifdef MODULE
+static char devicename[9] = { 0, };
+static struct device dev_fmv18x = {
+	devicename, /* device name is inserted by linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	0, 0,
+	0, 0, 0, NULL, fmv18x_probe };
+
+static int io = 0x220;
+static int irq = 0;
+
+int init_module(void)
+{
+	if (io == 0)
+		printk("fmv18x: You should not use auto-probing with insmod!\n");
+	dev_fmv18x.base_addr = io;
+	dev_fmv18x.irq       = irq;
+	if (register_netdev(&dev_fmv18x) != 0) {
+		printk("fmv18x: register_netdev() returned non-zero.\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+	unregister_netdev(&dev_fmv18x);
+	kfree(dev_fmv18x.priv);
+	dev_fmv18x.priv = NULL;
+
+	/* If we don't do this, we can't re-insmod it later. */
+	free_irq(dev_fmv18x.irq, NULL);
+	irq2dev_map[dev_fmv18x.irq] = NULL;
+	release_region(dev_fmv18x.base_addr, FMV18X_IO_EXTENT);
+}
+#endif /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c fmv18x.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 4
+ *  c-indent-level: 4
+ * End:
+ */
diff -u --recursive --new-file v1.3.73/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v1.3.73/linux/drivers/scsi/Config.in	Wed Mar 13 10:09:18 1996
+++ linux/drivers/scsi/Config.in	Thu Mar 14 12:57:45 1996
@@ -45,6 +45,7 @@
 dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
 dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
 dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI
+dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI
 bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
 endmenu
diff -u --recursive --new-file v1.3.73/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.3.73/linux/drivers/scsi/Makefile	Wed Feb  7 15:11:27 1996
+++ linux/drivers/scsi/Makefile	Thu Mar 14 12:57:45 1996
@@ -84,6 +84,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_PPA),y)
+L_OBJS += ppa.o
+else
+  ifeq ($(CONFIG_SCSI_PPA),m)
+  M_OBJS += ppa.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_QLOGIC),y)
 L_OBJS += qlogic.o
 else
diff -u --recursive --new-file v1.3.73/linux/drivers/scsi/README.ppa linux/drivers/scsi/README.ppa
--- v1.3.73/linux/drivers/scsi/README.ppa	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/README.ppa	Thu Mar 14 12:57:45 1996
@@ -0,0 +1,123 @@
+README.ppa (c) 1996   Grant R. Guenther,  grant@torque.net
+
+
+         The IOMEGA PPA3 parallel port SCSI Host Bus Adapter
+
+                     as embedded in the ZIP drive
+
+
+This README documents the Linux support for the parallel port version of
+IOMEGA's ZIP100.  The ZIP100 is an inexpensive and popular, but relatively 
+low performance, removable medium disk device.  The drive is also available
+as a regular SCSI device, but the driver documented here is for the
+parallel port version.  IOMEGA implemented the parallel port version by
+integrating (or emulating ?) their PPA3 parallel to SCSI converter into
+the ZIP drive.
+
+I have implemented a low-level driver, ppa.c,  for this parallel port 
+host bus adapter, thereby supporting the parallel port ZIP drive as a 
+regular SCSI device under Linux.
+
+It is possible that this driver will also work with the original PPA3
+device (to access a CDrom, for instance). But, the PPA3 is hard to find 
+and costs as much as the ZIP drive itself, so no-one has actually tried
+this, to the best of my knowledge.
+
+The driver was developed without the benefit of any technical specifications 
+for the interface.  Instead, a modified version of DOSemu was used to 
+monitor the protocol used by the DOS driver, 'guest.exe', for this adapter.
+I have no idea how my programming model relates to IOMEGA's design.
+(One technical consequence of this method:  I have never observed a
+SCSI message byte in the protocol transactions between guest.exe and
+the ZIP drive, so I do not know how they are delivered.  My working 
+hypothesis is that we don't have to worry about them if we don't
+send linked commands to the drive.)
+
+I'd like to thank Byron Jeff (byron@cc.gatech.edu) for publishing his
+observation that the 'guest' driver loads under DOSemu.  His remark was
+the stimulus that began this project.
+
+The ppa driver can detect and adapt to 4- and 8-bit parallel ports, but 
+there is currently no support for EPP or ECP ports, as I have been unable 
+to make the DOS drivers work in these modes on my test rig.
+
+The driver may be built in to the kernel, or loaded as a module.  It
+may be configured on the command line in both cases, although the syntax
+is different.  It may also be configured by editing the source file.
+
+Built-in drivers accept parameters using this LILO/LOADLIN command line
+syntax (omitted parameters retain their default values):
+
+        ppa=base[,speed_high[,speed_low[,call_sched[,nybble]]]]
+
+For example:    ppa=0x378,0,3
+
+If a driver is loaded as a module the parameters may be set on the
+insmod command line, but each one must be specified by name:
+
+For example:    insmod ppa.o ppa_base=0x378 ppa_nybble=1
+
+(Notice the ppa_ prefix on each of the parameters in the insmod form.)
+
+Here are the parameters and their functions:
+
+Variable        Default    Description
+
+ppa_base        0x378   The base address of PPA's parallel port.
+ppa_speed_high  1       Microsecond i/o delay used in data transfers
+ppa_speed_low   6       Microsecond delay used in other operations
+ppa_call_sched  1       1 to give up CPU during busy waits
+ppa_nybble      0       1 to force the driver to use 4-bit mode.
+
+A word about the timing parameters:  the ppa_speed_low parameter controls 
+the widths of a large number of pulses that are sent over the parallel bus, 
+the narrower the pulses, the faster things go, but the greater the risk of 
+distortion by noise damping circuits in the parallel ports.  The 
+ppa_speed_high parameter controls the same delays, but during the data 
+transfer phase only.   In this phase, there is a lot of handshaking going 
+on and the pulse shaping should not be so much of an issue, but if you 
+see data corruption, you can increase this parameter as well.
+
+You might also want to reduce the timing values to attempt to increase
+the transfer rates on your system.  Please be careful to watch for
+SCSI timeout errors in your log files.  If you are getting timeouts, you
+have set these parameters too low.  The default values appear to be
+safe on most machines.
+
+The ppa_call_sched parameter controls the 'friendliness' of this driver
+to the rest of your system.  When it is set to zero, the driver waits for
+events on the drive by continuously reading a port until the 0x80 bit is
+asserted.  Since it is in a tight loop inside the kernel, the rest of the
+system becomes very sluggish.  If you set ppa_call_sched to one, then
+ppa will call the scheduler in such circumstances, voluntarily giving up the
+CPU to other processes.   This appears to reduce the ZIP drive's 
+responsiveness, however.
+
+If you have both the lp and ppa drivers in your kernel, you must ensure
+that they access different parallel ports.  By default, the lp driver is
+initialised early in the booting process, and it claims all parallel
+ports that it can find.  You may control this behaviour with a LILO or
+LOADLIN command line argument of the form:
+
+        lp=base0[,irq0[,base1[,irq1[,base2[,irq2]]]]]
+
+For example:    lp=0x278,7
+
+If you use this method, only the ports named will be adopted by the lp
+driver.  You can disable them all with lp=0 .
+
+So, if you have a printer on 0x3bc and a ZIP drive on 0x278 you would
+give the following options on your boot command:
+
+        lp=0x3bc ppa=0x278
+
+In this case lp would use the polling driver, since an interrupt was not 
+specified.
+
+For information about using the ZIP drive, please read the generic
+instructions in the SCSI-HOWTO and the man pages for the normal disk
+management tools,  fdisk, mkfs, mount, umount, etc.  There is a mini-HOWTO
+circulating concerning the use of the normal SCSI version of the ZIP
+drive, most of its comments will apply to disks connected through the
+ppa driver as well.
+
diff -u --recursive --new-file v1.3.73/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v1.3.73/linux/drivers/scsi/hosts.c	Fri Jan 26 01:37:06 1996
+++ linux/drivers/scsi/hosts.c	Thu Mar 14 12:57:46 1996
@@ -129,6 +129,10 @@
 #include "AM53C974.h"
 #endif
 
+#ifdef CONFIG_SCSI_PPA
+#include "ppa.h"
+#endif
+
 #ifdef CONFIG_SCSI_DEBUG
 #include "scsi_debug.h"
 #endif
@@ -232,6 +236,9 @@
 #endif
 #ifdef CONFIG_SCSI_AM53C974
     AM53C974,
+#endif
+#ifdef CONFIG_SCSI_PPA
+    PPA,
 #endif
 #ifdef CONFIG_SCSI_DEBUG
     SCSI_DEBUG,
diff -u --recursive --new-file v1.3.73/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v1.3.73/linux/drivers/scsi/ppa.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/ppa.c	Thu Mar 14 12:57:46 1996
@@ -0,0 +1,479 @@
+/*      ppa.c   --  low level driver for the IOMEGA PPA3 
+                    parallel port SCSI host adapter.
+
+        (The PPA3 is the embedded controller in the ZIP drive.)
+
+        (c) 1995,1996 Grant R. Guenther, grant@torque.net,
+                      under the terms of the GNU Public License.
+
+        THIS IS BETA SOFTWARE - PLEASE TAKE ALL NECESSARY PRECAUTIONS
+
+*/
+
+/*      This driver was developed without the benefit of any technical
+        specifications for the interface.  Instead, a modified version of
+        DOSemu was used to monitor the protocol used by the DOS driver
+        for this adapter.  I have no idea how my programming model relates
+        to IOMEGA's design.
+
+        IOMEGA's driver does not generate linked commands.  I've never
+        observed a SCSI message byte in the protocol transactions, so
+        I am assuming that as long as linked commands are not used
+        we won't see any.  
+
+        So far, this driver has been tested with the embedded PPA3 in the
+        ZIP drive, only.   It can detect and adapt to 4- and 8-bit parallel
+        ports, but there is currently no support for EPP or ECP ports, as
+        I have been unable to make the DOS drivers work in these modes on
+        my test rig.
+
+        For more information, see the file drivers/scsi/README.ppa.
+
+*/
+
+#define   PPA_VERSION   "0.20"
+
+/* Change these variables here or with insmod or with a LILO or LOADLIN
+   command line argument
+*/
+
+static int      ppa_base       = 0x378;  /* parallel port address    */
+static int      ppa_speed_high = 1;      /* port delay in data phase */
+static int      ppa_speed_low  = 6;      /* port delay otherwise     */
+static int      ppa_call_sched = 1;      /* give up the CPU ?        */
+static int      ppa_nybble     = 0;      /* don't force nybble mode  */
+
+
+#define   PPA_CAN_QUEUE         1       /* use "queueing" interface */
+#define   PPA_SELECT_TMO        5000    /* how long to wait for target ? */
+#define   PPA_SPIN_TMO          5000000 /* ppa_wait loop limiter */
+#define   PPA_SECTOR_SIZE       512     /* for a performance hack only */
+
+#include  <unistd.h>
+#include  <linux/module.h>
+#include  <linux/kernel.h>
+#include  <linux/ioport.h>
+#include  <linux/delay.h>
+#include  <linux/blk.h>
+#include  <linux/proc_fs.h>
+#include  <linux/stat.h>
+#include  <asm/io.h>
+#include  "sd.h"
+#include  "hosts.h"
+#include  "ppa.h"
+
+struct proc_dir_entry proc_scsi_ppa = 
+                { PROC_SCSI_PPA, 3, "ppa", S_IFDIR|S_IRUGO|S_IXUGO, 2 };
+
+static int              ppa_abort_flag = 0;
+static int              ppa_error_code = DID_OK;
+static char             ppa_info_string[132];
+static Scsi_Cmnd        *ppa_current = 0;
+static void             (*ppa_done) (Scsi_Cmnd *);
+static int              ppa_busy = 0;
+static int              ppa_port_delay;
+
+
+void    out_p( short port, char byte)
+
+{       outb(byte,ppa_base+port);
+        udelay(ppa_port_delay);
+}
+
+char    in_p( short port)
+
+{       return inb(ppa_base+port);
+        udelay(ppa_port_delay);
+}
+
+void    ppa_d_pulse( char b )
+
+{       out_p(0,b);
+        out_p(2,0xc); out_p(2,0xe); out_p(2,0xc); out_p(2,0x4); out_p(2,0xc);
+}
+
+void    ppa_disconnect( void )
+
+{       ppa_d_pulse(0);
+        ppa_d_pulse(0x3c);
+        ppa_d_pulse(0x20);
+        ppa_d_pulse(0xf);
+}
+
+void    ppa_c_pulse( char b )
+
+{       out_p(0,b);
+        out_p(2,0x4); out_p(2,0x6); out_p(2,0x4); out_p(2,0xc);
+}
+
+void    ppa_connect( void )
+
+{       ppa_c_pulse(0);
+        ppa_c_pulse(0x3c);
+        ppa_c_pulse(0x20);
+        ppa_c_pulse(0x8f);
+}
+
+void    ppa_do_reset( void )
+
+{       out_p(2,0);             /* This is really just a guess */
+        udelay(100);
+}
+
+char    ppa_select( int  initiator, int target )
+
+{       char    r;
+        int     k;
+
+        r = in_p(1);
+        out_p(0,(1<<target)); out_p(2,0xe); out_p(2,0xc);
+        out_p(0,(1<<initiator)); out_p(2,0x8);
+
+        k = 0;
+        while ( !(r = (in_p(1) & 0xf0)) && (k++ < PPA_SELECT_TMO)) barrier();
+        return r;
+}
+
+char    ppa_wait( void ) 
+
+/*      Wait for the high bit to be set.
+
+        In principle, this could be tied to an interrupt, but the adapter
+        doesn't appear to be designed to support interrupts.  We spin on
+        the 0x80 ready bit.  If ppa_call_sched is 1, we call the scheduler 
+        to allow other processes to run while we are waiting, just like
+        the lp driver does in polling mode.  The performance hit is
+        significant, so this behaviour is configurable.
+
+*/
+
+{       int     k;
+        char    r;
+
+        ppa_error_code = DID_OK;
+        k = 0;
+        while (!((r = in_p(1)) & 0x80) 
+                && (k++ < PPA_SPIN_TMO) && !ppa_abort_flag  )
+                        if (need_resched && ppa_call_sched) schedule();
+        if (ppa_abort_flag) {
+                if (ppa_abort_flag == 1) ppa_error_code = DID_ABORT;
+                else {  ppa_do_reset();
+                        ppa_error_code = DID_RESET;
+                }
+                ppa_disconnect();
+                return 0;
+        }
+        if (k >= PPA_SPIN_TMO) { 
+                ppa_error_code = DID_TIME_OUT;
+                ppa_disconnect();
+                return 0;               /* command timed out */
+        }
+        return (r & 0xf0);
+}
+
+int     ppa_init( void )
+
+/* This is based on a trace of what the Iomega DOS 'guest' driver does.
+   I've tried several different kinds of parallel ports with guest and
+   coded this to react in the same ways that it does.
+
+   The return value from this function is just a hint about where the
+   handshaking failed.
+
+*/
+
+{       char    r, s;
+
+        out_p(0,0xaa); 
+        if (in_p(0) != (char) 0xaa) return 1; 
+        ppa_disconnect();
+        ppa_connect();
+        out_p(2,0x6); 
+        if ((in_p(1) & 0xf0) != 0xf0) return 2; 
+        out_p(2,0x4);
+        if ((in_p(1) & 0xf0) != 0x80) return 3; 
+        ppa_disconnect();
+        s = in_p(2);
+        out_p(2,0xec);
+        out_p(0,0x55); 
+        r = in_p(0);    
+        if (r != (char) 0xff) { 
+                ppa_nybble = 1;
+                if (r != (char) 0x55) return 4; 
+                out_p(0,0xaa); if (in_p(0) != (char) 0xaa) return 5; 
+        }
+        out_p(2,s);
+        ppa_connect();
+        out_p(0,0x40); out_p(2,0x8); out_p(2,0xc);
+        ppa_disconnect();
+
+        return 0;
+}
+
+int     ppa_start( Scsi_Cmnd * cmd )
+
+{       int     k;
+
+        ppa_error_code = DID_OK;
+        ppa_abort_flag = 0;
+
+        if (cmd->target == PPA_INITIATOR) {
+                ppa_error_code = DID_BAD_TARGET;
+                return 0;
+        }
+        ppa_connect();
+        if (!ppa_select(PPA_INITIATOR,cmd->target)) {
+                ppa_disconnect();
+                ppa_error_code = DID_NO_CONNECT;
+                return 0;
+        }
+        out_p(2,0xc);
+
+        for (k=0; k < cmd->cmd_len; k++) {        /* send the command */
+                if (!ppa_wait()) return 0;
+                out_p(0,cmd->cmnd[k]);
+                out_p(2,0xe);
+                out_p(2,0xc);
+        }
+
+#ifdef PPA_DEBUG
+        printk("PPA: command out: ");
+        for (k=0; k < cmd->cmd_len; k++)
+                printk("%3x",(cmd->cmnd[k]) & 0xff );
+        printk("\n");
+#endif
+
+        return 1;
+}
+
+int     ppa_completion( Scsi_Cmnd * cmd )
+
+/* The bulk flag enables some optimisations in the data transfer loops,
+   it should be true for any command that transfers data in integral
+   numbers of sectors.
+
+   The driver appears to remain stable if we speed up the parallel port
+   i/o in this function, but not elsewhere.
+*/
+
+{       char    r, l, h, v;
+        int     dir, cnt, blen, fast, bulk;
+        char    *buffer;
+
+#ifdef PPA_DEBUG
+        int     k;
+#endif
+
+        if (!(r = ppa_wait())) return 0;
+        v = cmd->cmnd[0];
+        bulk = ((v==READ_6)||(v==READ_10)||(v==WRITE_6)||(v==WRITE_10));
+        buffer = cmd->request_buffer;
+        blen = cmd->request_bufflen;
+        cnt = 0;  dir = 0;
+        if (r == (char) 0xc0) dir = 1;  /* d0 = read c0 = write f0 = status */
+
+        ppa_port_delay = ppa_speed_high;
+
+        while (r != (char) 0xf0) {
+                if (((r & 0xc0) != 0xc0 ) || (cnt >= blen)) {
+                        ppa_disconnect();
+                        ppa_error_code = DID_ERROR;
+                        return 0;
+                }
+                fast = bulk && ((blen - cnt) >= PPA_SECTOR_SIZE);
+                if (dir) do {
+                        out_p(0,buffer[cnt++]);
+                        out_p(2,0xe); out_p(2,0xc);
+                        if (!fast) break;
+                } while (cnt % PPA_SECTOR_SIZE);
+                else {  
+                        if (ppa_nybble) do {
+                                out_p(2,0x4); h = in_p(1); 
+                                out_p(2,0x6); l = in_p(1);
+                                v = ((l >> 4) & 0x0f) + (h & 0xf0);
+                                buffer[cnt++] = v;
+                                if (!fast) break;
+                        } while (cnt % PPA_SECTOR_SIZE);
+                        else do {
+                                out_p(2,0x25); v = in_p(0); out_p(2,0x27);
+                                buffer[cnt++] = v;
+                                if (!fast) break;
+                        } while (cnt % PPA_SECTOR_SIZE);
+                        if (!ppa_nybble) {
+                                out_p(2,0x5); out_p(2,0x4);
+                        }
+                        out_p(2,0xc);
+                }
+                if (!(r = ppa_wait())) return 0;
+        }
+
+        ppa_port_delay = ppa_speed_low;
+
+        out_p(2,0x4);            /* now read status byte */
+        h = in_p(1);
+        out_p(2,0x6);
+        l = in_p(1);
+        out_p(2,0xc);
+        r = ((l >> 4) & 0x0f) + (h & 0xf0);
+
+        out_p(2,0xe); out_p(2,0xc);
+        ppa_disconnect();
+
+#ifdef PPA_DEBUG
+        printk("PPA: status: %x, data[%d]: ",r & STATUS_MASK,cnt);
+        if (cnt > 12) cnt = 12;
+        for (k=0; k < cnt; k++)
+           printk("%3x",buffer[k] & 0xff );
+        printk("\n");   
+#endif
+
+        return (r & STATUS_MASK);
+}
+
+int     ppa_command( Scsi_Cmnd * cmd )
+
+{       int     s;
+
+        s = 0;
+        if (ppa_start(cmd))
+           if (ppa_wait()) 
+               s = ppa_completion(cmd);
+        return s + (ppa_error_code << 16);
+}
+
+int     ppa_queuecommand( Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+
+/* This is not really a queued interface at all, but apparently there may
+   be some bugs in the mid-level support for the non-queued interface.
+   This function is re-entrant, but only to one level.
+*/
+
+{       int     s;
+
+        ppa_current = cmd; ppa_done = done;
+        if (ppa_busy) return 0;
+        ppa_busy = 1;
+        while (ppa_current) {
+                cmd = ppa_current;  done = ppa_done;
+                s = 0;
+                if (ppa_start(cmd))
+                    if (ppa_wait())
+                        s = ppa_completion(cmd);
+                cmd->result = s + (ppa_error_code << 16);
+                ppa_current = 0;
+                done(cmd);              /* can reenter this function */
+        }
+        ppa_busy = 0;
+        return 0;
+}
+
+int     ppa_detect( Scsi_Host_Template * host )
+
+{       struct  Scsi_Host       *hreg;
+        int     rs;
+
+        /* can we have the ports ? */
+
+        if (check_region(ppa_base,3)) {
+                printk("PPA: ports at 0x%3x are not available\n",ppa_base);
+                return 0;
+        }
+
+        /* attempt to initialise the controller */
+
+        ppa_port_delay = ppa_speed_low;
+
+        rs = ppa_init();
+        if (rs) {
+            printk("PPA: unable to initialise controller at 0x%x, error %d\n",
+                   ppa_base,rs);
+            return 0;
+        }
+
+        /* now the glue ... */
+
+        host->proc_dir = &proc_scsi_ppa;
+
+        request_region(ppa_base,3,"ppa");
+
+        host->can_queue = PPA_CAN_QUEUE;
+
+        hreg = scsi_register(host,0);
+        hreg->io_port = ppa_base;
+        hreg->n_io_port = 3;
+        hreg->dma_channel = -1;
+
+        sprintf(ppa_info_string,
+                "PPA driver version %s using %d-bit mode on port 0x%x.",
+                PPA_VERSION,8-ppa_nybble*4,ppa_base);
+        host->name = ppa_info_string;
+
+        return 1;       /* 1 host detected */
+}
+
+int     ppa_biosparam( Disk * disk, kdev_t dev, int ip[])
+
+/*  Apparently the the disk->capacity attribute is off by 1 sector 
+    for all disk drives.  We add the one here, but it should really
+    be done in sd.c.  Even if it gets fixed there, this will still
+    work.
+*/
+
+{       ip[0] = 0x40;
+        ip[1] = 0x20;
+        ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
+        if (ip[2] > 1024) {
+                ip[0] = 0xff;
+                ip[1] = 0x3f;
+                ip[2] = (disk->capacity +1) / (ip[0] * ip[1]);
+                if (ip[2] > 1023)
+                        ip[2] = 1023;
+        }
+        return 0;
+}
+
+int     ppa_abort( Scsi_Cmnd * cmd )
+
+{       ppa_abort_flag = 1;
+        return SCSI_ABORT_SNOOZE;
+}
+
+int     ppa_reset( Scsi_Cmnd * cmd )
+
+{       ppa_abort_flag = 2;
+        return SCSI_RESET_PUNT;
+}
+
+const char      *ppa_info( struct Scsi_Host * host )
+
+{       return ppa_info_string;
+}
+
+#ifndef MODULE
+
+/* Command line parameters (for built-in driver):
+
+   Syntax:  ppa=base[,speed_high[,speed_low[,call_sched[,nybble]]]]
+
+   For example:  ppa=0x378   or   ppa=0x378,0,3
+
+*/
+
+void    ppa_setup(char *str, int *ints)
+
+{       if (ints[0] > 0) ppa_base = ints[1];
+        if (ints[0] > 1) ppa_speed_high = ints[2];
+        if (ints[0] > 2) ppa_speed_low = ints[3];
+        if (ints[0] > 3) ppa_call_sched = ints[4];
+        if (ints[0] > 4) ppa_nybble = ints[5];
+}
+
+#else
+
+Scsi_Host_Template      driver_template = PPA;
+
+#include  "scsi_module.c"
+
+#endif
+
+/* end of ppa.c */
diff -u --recursive --new-file v1.3.73/linux/drivers/scsi/ppa.h linux/drivers/scsi/ppa.h
--- v1.3.73/linux/drivers/scsi/ppa.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/ppa.h	Thu Mar 14 12:57:46 1996
@@ -0,0 +1,44 @@
+#ifndef _PPA_H
+#define _PPA_H
+
+/*  Driver for the PPA3 parallel port SCSI HBA embedded in 
+    the Iomega ZIP drive
+
+	(c) 1996	Grant R. Guenther  grant@torque.net
+*/
+
+#define	PPA_INITIATOR	7
+
+int ppa_detect(Scsi_Host_Template * );
+const char * ppa_info(struct Scsi_Host *);
+int ppa_command(Scsi_Cmnd *);
+int ppa_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+int ppa_abort(Scsi_Cmnd *);
+int ppa_reset(Scsi_Cmnd *);
+int ppa_biosparam(Disk *, kdev_t, int[]);
+
+#define PPA {			\
+	0,			\
+	0,			\
+	0,			\
+	0,		        \
+	0,			\
+	ppa_detect,		\
+	0,			\
+	ppa_info,		\
+	ppa_command, 		\
+	ppa_queuecommand,	\
+	ppa_abort,		\
+	ppa_reset,		\
+	0,			\
+	ppa_biosparam,		\
+	0,			\
+	PPA_INITIATOR,		\
+	SG_NONE,		\
+	1,			\
+	0,			\
+	0,			\
+	DISABLE_CLUSTERING	\
+}
+
+#endif /* _PPA_H */
diff -u --recursive --new-file v1.3.73/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.3.73/linux/drivers/scsi/st.c	Sun Feb 11 15:32:45 1996
+++ linux/drivers/scsi/st.c	Wed Mar 13 08:38:54 1996
@@ -2143,7 +2143,7 @@
 {
   if(SDp->type != TYPE_TAPE) return 0;
 
-  printk(KERN_NOTICE "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", 
+  printk("Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n", 
 	 st_template.dev_noticed++,
 	 SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); 
   
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/.blurb linux/drivers/sound/.blurb
--- v1.3.73/linux/drivers/sound/.blurb	Wed Feb 28 11:50:06 1996
+++ linux/drivers/sound/.blurb	Wed Mar 13 09:12:25 1996
@@ -1,6 +1,8 @@
 *********************************************************
 * Readme.cards (this directory) contains some card	*
 * specific instructions.				*
+* See http://personal.eunet.fi/pp/voxware for most up   *
+* to date info.                                         *
 *							*
 * DON'T USE PROGRAMS FROM SND_UTIL PACKAGE EARLIER THAN *
 * snd-util-3.5 WITH THIS SOUND DRIVER VERSION.          *
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/.version linux/drivers/sound/.version
--- v1.3.73/linux/drivers/sound/.version	Tue Mar  5 10:11:01 1996
+++ linux/drivers/sound/.version	Wed Mar 13 09:12:25 1996
@@ -1,2 +1,2 @@
-3.5-beta10
-0x030505
+3.5
+0x030500
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG
--- v1.3.73/linux/drivers/sound/CHANGELOG	Tue Mar  5 10:11:01 1996
+++ linux/drivers/sound/CHANGELOG	Wed Mar 13 09:12:25 1996
@@ -1,7 +1,13 @@
-Changelog for version 3.5-beta10
---------------------------------
+Changelog for version 3.5
+-------------------------
 
-Since 3.5-beta8
+Since 3.5
+- Improved handling of playback underrunt situations.
+
+Since 3.5-beta10
+- Bug fixing
+
+Since 3.5-beta9
 - Fixed for compatibility with Linux 1.3.70 and later.
 - Changed boot time passing of 16 bit DMA channel number to SB driver.
 
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v1.3.73/linux/drivers/sound/Makefile	Tue Mar  5 10:11:02 1996
+++ linux/drivers/sound/Makefile	Wed Mar 13 10:26:29 1996
@@ -70,7 +70,7 @@
 
 clean:
 	rm -f core core.* *.o *.a tmp_make *~ x y z *%
-	rm -f configure sound_stub.c objects/*.o 
+	rm -f configure sound_stub.c objects/*.o
 
 indent:
 	for n in *.c;do echo indent $$n;indent $$n;done
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v1.3.73/linux/drivers/sound/Readme	Tue Mar  5 10:11:03 1996
+++ linux/drivers/sound/Readme	Wed Mar 13 09:12:22 1996
@@ -1,4 +1,4 @@
-Version 3.5-beta10 release notes
+Version 3.5-beta11 release notes
 --------------------------------
 
 Most up to date information about this driver is available from 
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v1.3.73/linux/drivers/sound/Readme.cards	Tue Mar  5 10:11:03 1996
+++ linux/drivers/sound/Readme.cards	Wed Mar 13 09:12:24 1996
@@ -43,8 +43,8 @@
 -----------------------------------------------
 
 There are currently many cards that work with this driver. Some of the cards
-have native support while the others work since they emulate some other
-cards (usually SB, MSS/WSS and/or MPU401). The following cards have native
+have native support while others work since they emulate some other
+card (usually SB, MSS/WSS and/or MPU401). The following cards have native
 support in the driver. Detailed instructions for configuring these cards
 will be given later in this document.
 
@@ -65,16 +65,17 @@
 	SB 1.0 to 2.0
 	SB Pro
 	SB 16
-	NOTE!	The ASP chip and the EMU synth of the AWE32 is not supported 
+	NOTE!	The ASP chip and the EMU synth of AWE32 are not supported 
 		since their manufacturer doesn't release information about
-		the card. However both the AB16ASP and the AWE32 work with
+		the card. However, both SB16ASP and AWE32 work with
 		the driver just like a SB16. Also see the comment about some
 		unsupported cards at the end of this file.
+		(The OPL3 FM chip of SB32/AWE works but you cannot hear it).
 	SB16 compatible cards by other manufacturers than Creative.
 		You have been fooled since there are no SB16 compatible
-		cards in the market (July95). It's likely that your card
-		is compatible just with SB Pro but there is also a non SB
-		compatible 16 bit mode. Usually it's MSS/WSS but could also
+		cards on the market (Feb 96). It's likely that your card
+		is compatible just with SB Pro but there is also a non-SB-
+		compatible 16 bit mode. Usually it's MSS/WSS but it could also
 		be a proprietary one like MV Jazz16 or ESS ES688.
 
 Gravis Ultrasound (GUS)
@@ -88,26 +89,26 @@
 	The driver works both with the full (intelligent mode) MPU-401
 	cards (such as MPU IPC-T and MQX-32M) and with the UART only
 	dumb MIDI ports. MPU-401 is currently the most common MIDI
-	interface. Most soundcards are compatible with it. However
-	don't enable MPU401 mode blindly. Many cards having native support
+	interface. Most soundcards are compatible with it. However,
+	don't enable MPU401 mode blindly. Many cards with native support
 	in the driver have their own MPU401 driver. Enabling the standard one
-	will cause a conflict with these cards. So look if your card is
+	will cause a conflict with these cards. So check if your card is
 	in the list of supported cards before enabling MPU401.
 
 Windows Sound System (MSS/WSS)
-	Even Microsoft has discontinued their own Sound System card, they
-	managed to make a standard. MSS compatible cards are based on a 
-	codec chip which is easily available from at least two manufacturers
+	Even when Microsoft has discontinued their own Sound System card 
+	they managed to make it a standard. MSS compatible cards are based on 
+	a codec chip which is easily available from at least two manufacturers
 	(AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor).
 	Currently most soundcards are based on one of the MSS compatible codec
-	chip. The CS4231 is used in the high quality cards such as GUS MAX,
+	chips. The CS4231 is used in the high quality cards such as GUS MAX,
 	MediaTriX AudioTriX Pro and TB Tropez (GUS MAX is not MSS compatible). 
 
 	Having a AD1848, CS4248 or CS4231 codec chip on the card is a good
 	sign. Even if the card is not MSS compatible, it could be easy to write
 	support for it. Note also that most MSS compatible cards
 	require special boot time initialization which may not be present
-	in in the driver. Also some MSS compatible cards have native support.
+	in the driver. Also, some MSS compatible cards have native support.
 	Enabling the MSS support with these cards is likely to
 	cause a conflict. So check if your card is listed in this file before
 	enabling the MSS support.
@@ -121,9 +122,9 @@
 	operator chip used in the original AdLib card. Currently it's used
 	only in the cheapest (8 bit mono) cards. The OPL3 is a 4 operator 
 	FM chip which provides better sound quality and/or more available 
-	voices than the OPL2. The OPL4 is a new chip which has a OPL3 and
-	a wave table synthesizer packed on the same chip. The driver supports
-	just the OPL3 mode directly. Most cards having a OPL4 (like
+	voices than the OPL2. The OPL4 is a new chip that has an OPL3 and
+	a wave table synthesizer packed onto the same chip. The driver supports
+	just the OPL3 mode directly. Most cards with an OPL4 (like
 	SM Wave and AudioTriX Pro) support the OPL4 mode using MPU401
 	emulation. Writing a native OPL4 support is difficult
 	since Yamaha doesn't give information about their sample ROM chip.
@@ -143,7 +144,7 @@
 	The driver supports downloading DSP algorithms to these cards.
 
 MediaTriX AudioTriX Pro
-	The ATP card is built around a CS4231 codec and a OPL4 synthesizer
+	The ATP card is built around a CS4231 codec and an OPL4 synthesizer
 	chips. The OPL4 mode is supported by a microcontroller running a
 	General MIDI emulator. There is also a SB 1.5 compatible playback mode.
 
@@ -158,28 +159,30 @@
 MAD16 and Mozart based cards
 	The Mozart (OAK OTI-601) and MAD16 Pro (OPTi 82C929) interface
 	chips are used in many different soundcards, including some
-	cards by Reveal and Turtle Beach (Tropez). Purpose of these
+	cards by Reveal and Turtle Beach (Tropez). The purpose of these
 	chips is to connect other audio components to the PC bus. The
 	interface chip performs address decoding for the other chips.
+	NOTE! Tropez Plus is not MAD16 but CS4232 based.
 
 Audio Excell DSP16 
-	Support for this card is made by Riccardo Faccetti
+	Support for this card was written by Riccardo Faccetti
 	(riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info.
+	(This driver is not functional in version 3.5 of this driver).
 	
-Crystal CS4232 based cards such as AcerMagic S23 and many PC motherboards
-	(Compaq, HP, Intel, ...).
+Crystal CS4232 based cards such as AcerMagic S23, TB Tropez _Plus_ and 
+	many PC motherboards (Compaq, HP, Intel, ...)
 	CS4232 is a PnP multimedia chip which contains a CS3231A codec,
 	SB and MPU401 emulations. There is support for OPL3 too.
 	This is a temporary driver which uses the chip in non PnP mode
 	(The final driver should be included in version 3.6 of the driver).
-	Unfortunately the MPU401 mode doesn't work. The chip may also stop
-	working after it has been used few times (only cold boot resets it).
+	Unfortunately the MPU401 mode doesn't work (I don't know how to
+	initialize it). 
 
 Turtle Beach Maui and Tropez
 	This driver version supports sample, patch and program loading commands
 	described in the Maui/Tropez User's manual. There is no initialization
-	code for Maui so it must be initialized using DOS. Audio side of Tropez
-	is based on the MAD16 chip (see above).
+	code for Maui so it must be initialized with DOS. The audio side of
+	the Tropez is based on the MAD16 chip (see above).
 
 Jumpers and software configuration
 ----------------------------------
@@ -310,6 +313,10 @@
 	  you read the above list correctly). Don't answer 'y' if you
 	  have some other card made by Media Vision or Logitech since they
 	  are not PAS16 compatible.
+	  NOTE! Since 3.5-beta10 you need to enable SB support (next question)
+	  if you want to use the SB emulation of PAS16. It's also possible to
+   	  the emulation if you want to use a true SB card together with PAS16
+	  (there is another question about this that is asked later).
   "SoundBlaster support",
 	- Answer 'y' if you have an original SB card made by Creative Labs
 	  or a full 100% hardware compatible clone (like Thunderboard or
@@ -317,6 +324,7 @@
 	  please look at the card specific instructions later in this file
 	  before answering this question. For an unknown card you may answer 
 	  'y' if the card claims to be SB compatible.
+	 Enable this option also with PAS16 (changed since v3.5-beta9).
 
 	 Don't enable SB if you have a MAD16 or Mozart compatible card.
 
@@ -477,11 +485,15 @@
 ProAudioSpectrum 16 and compatibles
 -----------------------------------
 
-There are nothing special with these cards. Just don't enable any
-other cards in case you don't have them also. The PAS16 has
-a SB mode so the driver config program will prompt for the SB settings
-do. Use I/O 0x220 and DMA1 for the SB mode. Ensure that you assign different
-IRQ numbers for the SB and PAS16 modes.
+PAS16 has a SB emulation chip which can be used together with the native
+(16 bit) mode of the card. To enable this emulation you should configure 
+the driver to have SB support too (this has been changed since version
+3.5-beta9 of this driver).
+
+With current driver versions it's also possible to use PAS16 together with 
+another SB compatible card. In this case you should configure SB support
+for the other card and to disable the SB emulation of PAS16 (there is a
+separate questions about this).
 
 With PAS16 you can use two audio device files at the same time. /dev/dsp (and
 /dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
@@ -773,11 +785,15 @@
 There are some new Sound Galaxies in the market. I have no experience with
 them so read the card's manual carefully.
 
-ESS ES1688 'AudioDrive' based cards
------------------------------------
+ESS ES1688 and ES688 'AudioDrive' based cards
+---------------------------------------------
 
 Configure these cards just like SB Pro. Enable the 'SB MPU401 MIDI port'
-if you want to use MIDI features of the card.
+if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode
+so you don't need to enable it (the driver uses normal SB MIDI automaticly
+with ES688).
+
+NOTE! ESS cards are not compatible with MSS/WSS.
 
 Reveal cards
 ------------
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux
--- v1.3.73/linux/drivers/sound/Readme.linux	Tue Mar  5 10:11:03 1996
+++ linux/drivers/sound/Readme.linux	Wed Mar 13 09:12:22 1996
@@ -165,6 +165,23 @@
 ln -s /dev/dsp0 /dev/dsp
 
 #
+#	DSPW		(14, 5)
+#
+if [ -e /dev/dspW ]; then
+	rm -f /dev/dspW
+fi
+if [ -e /dev/dspW0 ]; then
+	rm -f /dev/dspW0
+fi
+mknod -m 666 /dev/dspW0 c 14 5
+ln -s /dev/dspW0 /dev/dspW
+
+if [ -e /dev/dspW1 ]; then
+	rm -f /dev/dspW1
+fi
+mknod -m 666 /dev/dspW1 c 14 37
+
+#
 #	SPARC compatible /dev/audio	(14, 4)	
 #
 if [ -e /dev/audio ]; then
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v1.3.73/linux/drivers/sound/ad1848.c	Tue Mar  5 10:11:03 1996
+++ linux/drivers/sound/ad1848.c	Wed Mar 13 09:12:29 1996
@@ -192,7 +192,7 @@
   if (!(ad_read (devc, 11) & 0x20))
     return;
 
-  timeout = 40000;
+  timeout = 80000;
   while (timeout > 0 && ad_read (devc, 11) & 0x20)
     timeout--;
   if (ad_read (devc, 11) & 0x20)
@@ -202,11 +202,33 @@
 static void
 ad_mute (ad1848_info * devc)
 {
+  int             i;
+  unsigned char   prev;
+
+  if (devc->mode != MD_1848)
+    return;
+  /*
+     * Save old register settings and mute output channels
+   */
+  for (i = 6; i < 8; i++)
+    {
+      prev = devc->saved_regs[i] = ad_read (devc, i);
+      ad_write (devc, i, prev | 0x80);
+    }
 }
 
 static void
 ad_unmute (ad1848_info * devc)
 {
+  int             i;
+
+  /*
+     * Restore back old volume registers (unmute)
+   */
+  for (i = 6; i < 8; i++)
+    {
+      ad_write (devc, i, devc->saved_regs[i] & ~0x80);
+    }
 }
 
 static void
@@ -928,7 +950,7 @@
 ad1848_prepare_for_IO (int dev, int bsize, int bcount)
 {
   int             timeout;
-  unsigned char   fs, old_fs;
+  unsigned char   fs, old_fs, tmp = 0;
   unsigned long   flags;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
@@ -952,15 +974,22 @@
 
   old_fs = ad_read (devc, 8);
 
-  if (fs == old_fs)		/* No change */
-    {
-      restore_flags (flags);
-      devc->xfer_count = 0;
-      return 0;
-    }
+  if (devc->mode != MD_4232)
+    if (fs == old_fs)		/* No change */
+      {
+	restore_flags (flags);
+	devc->xfer_count = 0;
+	return 0;
+      }
 
   ad_enter_MCE (devc);		/* Enables changes to the format select reg */
 
+  if (devc->mode == MD_4232)
+    {
+      tmp = ad_read (devc, 16);
+      ad_write (devc, 16, tmp | 0x30);
+    }
+
   ad_write (devc, 8, fs);
   /*
    * Write to I8 starts resyncronization. Wait until it completes.
@@ -985,6 +1014,9 @@
 
     }
 
+  if (devc->mode == MD_4232)
+    ad_write (devc, 16, tmp & ~0x30);
+
   ad_leave_MCE (devc);		/*
 				 * Starts the calibration process.
 				 */
@@ -1011,38 +1043,14 @@
 ad1848_halt (int dev)
 {
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
-  unsigned long   flags;
-  int             timeout;
-
-
-  save_flags (flags);
-  cli ();
-
-  ad_mute (devc);
-  ad_enter_MCE (devc);
-  ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */
-  ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */
 
-  ad_write (devc, 15, 4);	/* Clear DMA counter */
-  ad_write (devc, 14, 0);	/* Clear DMA counter */
+  unsigned char   bits = ad_read (devc, 9);
 
-  if (devc->mode != MD_1848)
-    {
-      ad_write (devc, 30, 4);	/* Clear DMA counter */
-      ad_write (devc, 31, 0);	/* Clear DMA counter */
-    }
+  if (bits & 0x01)
+    ad1848_halt_output (dev);
 
-  for (timeout = 0; timeout < 10000 && !(inb (io_Status (devc)) & 0x80);
-       timeout++);		/* Wait for interrupt */
-
-  ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */
-  outb (0, io_Status (devc));	/* Clear interrupt status */
-  outb (0, io_Status (devc));	/* Clear interrupt status */
-  devc->irq_mode = 0;
-  ad_leave_MCE (devc);
-
-  /* DMAbuf_reset_dma (dev); */
-  restore_flags (flags);
+  if (bits & 0x02)
+    ad1848_halt_input (dev);
 }
 
 static void
@@ -1051,16 +1059,26 @@
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
   unsigned long   flags;
 
-  if (devc->mode == MD_1848)
-    {
-      ad1848_halt (dev);
-      return;
-    }
-
   save_flags (flags);
   cli ();
 
   ad_mute (devc);
+
+  if (devc->mode == MD_4232)	/* Use applied black magic */
+    {
+      int             tmout;
+
+      disable_dma (audio_devs[dev]->dmachan1);
+
+      for (tmout = 0; tmout < 100000; tmout++)
+	if (ad_read (devc, 11) & 0x10)
+	  break;
+      ad_write (devc, 9, ad_read (devc, 9) & ~0x01);	/* Stop playback */
+
+      enable_dma (audio_devs[dev]->dmachan1);
+      restore_flags (flags);
+      return;
+    }
   ad_write (devc, 9, ad_read (devc, 9) & ~0x02);	/* Stop capture */
 
 
@@ -1078,16 +1096,25 @@
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
   unsigned long   flags;
 
-  if (devc->mode == MD_1848)
-    {
-      ad1848_halt (dev);
-      return;
-    }
-
   save_flags (flags);
   cli ();
 
   ad_mute (devc);
+  if (devc->mode == MD_4232)	/* Use applied black magic */
+    {
+      int             tmout;
+
+      disable_dma (audio_devs[dev]->dmachan1);
+
+      for (tmout = 0; tmout < 100000; tmout++)
+	if (ad_read (devc, 11) & 0x10)
+	  break;
+      ad_write (devc, 9, ad_read (devc, 9) & ~0x01);	/* Stop playback */
+
+      enable_dma (audio_devs[dev]->dmachan1);
+      restore_flags (flags);
+      return;
+    }
   ad_write (devc, 9, ad_read (devc, 9) & ~0x01);	/* Stop playback */
 
 
@@ -1503,7 +1530,7 @@
       nr_ad1848_devs++;
 
 #ifdef CONFIG_SEQUENCER
-      if (devc->mode != MD_1848 && devc->irq_ok)
+      if (devc->mode != MD_1848 && devc->mode != MD_1845 && devc->irq_ok)
 	ad1848_tmr_install (my_dev);
 #endif
 
@@ -1592,7 +1619,7 @@
 
       if (irq > 15)
 	{
-	  printk ("ad1848.c: Bogus interrupt %d\n", irq);
+	  /* printk ("ad1848.c: Bogus interrupt %d\n", irq); */
 	  return;
 	}
 
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v1.3.73/linux/drivers/sound/configure.c	Tue Mar  5 10:11:04 1996
+++ linux/drivers/sound/configure.c	Thu Mar 14 17:06:09 1996
@@ -1,38 +1,13 @@
 /*
  *	 PnP soundcard support is not included in this version.
  *
- *       AEDSP16 will not work without significant changes.
- *
- *       SB Pro and SB16 drivers are always enabled together with SB.
+ *	 AEDSP16 will not work without significant changes.
  */
-#define DISABLED_OPTIONS 	(B(OPT_PNP)|B(OPT_AEDSP16)|B(OPT_SBPRO)|B(OPT_SB16))
+#define DISABLED_OPTIONS 	(B(OPT_PNP)|B(OPT_AEDSP16)|B(OPT_UNUSED1)|B(OPT_UNUSED2))
 /*
  * sound/configure.c  - Configuration program for the Linux Sound Driver
  */
-/*
- * Copyright by Hannu Savolainen 1993-1996
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer. 2.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
+#define COPYING2
 
 #include <stdio.h>
 #include <unistd.h>
@@ -66,20 +41,19 @@
 #define OPT_PNP		15
 
 #define OPT_HIGHLEVEL   16	/* This must be same than the next one */
-#define OPT_SBPRO	16
-#define OPT_SB16	17
+#define OPT_UNUSED1	16
+#define OPT_UNUSED2	17
 #define OPT_AEDSP16     18
 #define OPT_AUDIO	19
 #define OPT_MIDI_AUTO	20
 #define OPT_MIDI	21
 #define OPT_YM3812_AUTO	22
 #define OPT_YM3812	23
-#define OPT_SEQUENCER	24
-#define OPT_LAST	24	/* Last defined OPT number */
+#define OPT_LAST	23	/* Last defined OPT number */
 
 #define DUMMY_OPTS (B(OPT_MIDI_AUTO)|B(OPT_YM3812_AUTO))
 
-#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \
+#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_GUS)| \
 		  B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)| \
 		  B(OPT_MSS)|B(OPT_SSCAPE)|B(OPT_UART6850)|B(OPT_TRIX)| \
 		  B(OPT_MAD16)|B(OPT_CS4232)|B(OPT_MAUI))
@@ -94,6 +68,7 @@
 #define AD1848_DEVS (B(OPT_GUS16)|B(OPT_MSS)|B(OPT_PSS)|B(OPT_GUSMAX)|\
 		     B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_CS4232)|\
 		     B(OPT_PNP))
+#define SEQUENCER_DEVS (OPT_MIDI|OPT_YM3812|OPT_ADLIB|OPT_GUS|OPT_MAUI|MIDI_CARDS)
 /*
  * Options that have been disabled for some reason (incompletely implemented
  * and/or tested). Don't remove from this list before looking at file
@@ -150,15 +125,14 @@
   {0, 0, "MAUI", 1, 0, 0},
   {0, 0, "PNP", 1, 0, 0},
 
-  {B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1},
-  {B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1},
-  {B (OPT_SBPRO) | B (OPT_MSS) | B (OPT_MPU401), 0, "AEDSP16", 1, 0, 0},
+  {B (OPT_SB), B (OPT_PAS), "UNUSED1", 1, 0, 1},
+  {B (OPT_SB) | B (OPT_UNUSED1), B (OPT_PAS), "UNUSED2", 1, 0, 1},
+  {B (OPT_UNUSED1) | B (OPT_MSS) | B (OPT_MPU401), 0, "AEDSP16", 1, 0, 0},
   {AUDIO_CARDS, 0, "AUDIO", 1, 0, 1},
   {B (OPT_MPU401) | B (OPT_MAUI), 0, "MIDI_AUTO", 0, OPT_MIDI, 0},
   {MIDI_CARDS, 0, "MIDI", 1, 0, 1},
   {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0},
-  {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB) | B (OPT_MSS) | B (OPT_PSS), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1},
-  {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1}
+  {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB) | B (OPT_MSS) | B (OPT_PSS), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1}
 };
 
 char           *questions[] =
@@ -180,15 +154,14 @@
   "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers",
   "Support for PnP sound cards (_EXPERIMENTAL_)",
 
-  "SoundBlaster Pro support",
-  "SoundBlaster 16 support",
+  "*** Unused option 1 ***",
+  "*** Unused option 2 ***",
   "Audio Excel DSP 16 initialization support",
   "/dev/dsp and /dev/audio support",
   "This should not be asked",
   "MIDI interface support",
   "This should not be asked",
   "FM synthesizer (YM3812/OPL-3) support",
-  "/dev/sequencer support",
   "Is the sky really falling"
 };
 
@@ -248,7 +221,7 @@
   "them. In addition the MAD16 chip is used in some cards made by known\n"
   "manufacturers such as Turtle Beach (Tropez), Reveal (some models) and\n"
   "Diamond (latest ones).\n",
-
+  
   "Enable this if you have a card based on the Crystal CS4232 chip set.\n",
 
   "Enable this option if you have a Turtle Beach Wave Front, Maui,\n"
@@ -273,15 +246,12 @@
   "This enables the dev/midixx devices and access to any MIDI ports\n"
   "using /dev/sequencer and /dev/music. This option also affects any\n"
   "MPU401 and/or General MIDI compatible devices.\n",
-
+  
   "This should not be asked",
 
   "This enables the Yamaha FM synthesizer chip used on many sound\n"
   "cards.\n",
 
-  "This enables the /dev/sequencer and /dev/music devices used for\n"
-  "playing computer music.\n",
-
   "Is the sky really falling"
 };
 
@@ -301,6 +271,10 @@
   }
   ,
   {
+    "SEQUENCER", SEQUENCER_DEVS
+  }
+  ,
+  {
     NULL, 0
   }
 };
@@ -323,6 +297,21 @@
 int
 can_select_option (int nr)
 {
+#if 0
+  switch (nr)
+    {
+    case OPT_LAST_MUTUAL + 1:
+      fprintf (stderr, "\nThe following cards should work with any other cards.\n"
+	       "CAUTION! Don't enable MPU-401 if you don't have it.\n");
+      break;
+
+    case OPT_HIGHLEVEL:
+      fprintf (stderr, "\nSelect one or more of the following options\n");
+      break;
+
+
+    }
+#endif
 
   if (hw_table[nr].conditions)
     if (!(hw_table[nr].conditions & selected_options))
@@ -344,12 +333,12 @@
   char            answ[512];
   int             len;
 
-response:
-  fprintf (stderr, prompt);
+  response:
+  fprintf(stderr, prompt);
   if (def_answ)
-    fprintf (stderr, " [Y/n/?] ");
+    fprintf(stderr, " [Y/n/?] ");
   else
-    fprintf (stderr, " [N/y/?] ");
+    fprintf(stderr, " [N/y/?] ");
 
   if ((len = read (0, answ, sizeof (answ))) < 1)
     {
@@ -365,13 +354,12 @@
 				 */
     return def_answ;
 
-  if (answ[0] == '?')
-    {				/* display help message */
-      fprintf (stderr, "\n");
-      fprintf (stderr, help);
-      fprintf (stderr, "\n");
-      goto response;
-    }
+  if (answ[0] == '?') {		/* display help message */
+    fprintf(stderr, "\n");
+    fprintf(stderr, help);
+    fprintf(stderr, "\n");
+    goto response;
+  }
 
   answ[len - 1] = 0;
 
@@ -432,7 +420,7 @@
       for (i = 0; i < OPT_LAST; i++)
 	if (mask == B (i))
 	  {
-	    unsigned int    j;
+	    unsigned int             j;
 
 	    for (j = 0; j < strlen (choices); j++)
 	      if (choices[j] == '\'')
@@ -453,7 +441,7 @@
 	return;
 
       fprintf (stderr, "\n%s\n", question);
-      if (strcmp (choices, ""))
+      if (strcmp(choices, ""))
 	fprintf (stderr, "Possible values are: %s\n", choices);
 
       if (format == FMT_INT)
@@ -591,18 +579,18 @@
 	    continue;
 
 	  if (strcmp (tmp, "JAZZ_DMA16") == 0)	/* Rename it (hack) */
-	    {
-	      printf ("#define SB_DMA2 %s\n",
-		      &buf[18]);
-	      continue;
-	    }
+	  {
+		printf("#define SB_DMA2 %s\n",
+			&buf[18]);
+		continue;
+	  }
 
 	  if (strcmp (tmp, "SB16_DMA") == 0)	/* Rename it (hack) */
-	    {
-	      printf ("#define SB_DMA2 %s\n",
-		      &buf[16]);
-	      continue;
-	    }
+	  {
+		printf("#define SB_DMA2 %s\n",
+			&buf[16]);
+		continue;
+	  }
 
 	  tmp[8] = 0;		/* Truncate the string */
 	  if (strcmp (tmp, "EXCLUDE_") == 0)
@@ -690,11 +678,14 @@
   printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options);
   fprintf (stderr, "Old configuration copied.\n");
 
+#ifdef linux
   build_defines ();
+#endif
   old_config_used = 1;
   return 1;
 }
 
+#ifdef linux
 void
 build_defines (void)
 {
@@ -712,6 +703,10 @@
     if (!hw_table[i].alias)
       if (selected_options & B (i))
 	fprintf (optf, "CONFIG_%s=y\n", hw_table[i].macro);
+#if 0
+      else
+	fprintf (optf, "CONFIG_%s=n\n", hw_table[i].macro);
+#endif
 
 
   fprintf (optf, "\n");
@@ -722,16 +717,22 @@
     {
       if (selected_options & extra_options[i].mask)
 	fprintf (optf, "CONFIG_%s=y\n", extra_options[i].name);
+#if 0
+      else
+	fprintf (optf, "CONFIG_%s=n\n", extra_options[i].name);
+#endif
       i++;
     }
 
   fprintf (optf, "\n");
   fclose (optf);
 }
+#endif
 
 void
 ask_parameters (void)
 {
+#ifdef linux
   int             num;
 
   build_defines ();
@@ -764,7 +765,7 @@
 		  "0, 1 or 3");
 
   ask_int_choice (B (OPT_SB), "SB_DMA2",
-		"SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
+		  "SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)",
 		  FMT_INT,
 		  5,
 		  "5, 6 or 7");
@@ -796,17 +797,21 @@
   if (selected_options & B (OPT_PAS))
     {
       if (think_positively ("Enable Joystick port on ProAudioSpectrum", 0,
-	"Enable this option if you want to use the joystick port provided\n"
-			    "on the PAS sound card.\n"));
-
-      printf ("#define PAS_JOYSTICK_ENABLE\n");
+      "Enable this option if you want to use the joystick port provided\n"
+      "on the PAS sound card.\n"))
+         printf ("#define PAS_JOYSTICK_ENABLE\n");
 
       if (think_positively ("Enable PAS16 bus clock option", 0,
-       "The PAS16 can be noisy with some motherboards. There is a command\n"
-	"line switch (:T?) in the DOS driver for PAS16 which solves this.\n"
+      "The PAS16 can be noisy with some motherboards. There is a command\n"
+      "line switch (:T?) in the DOS driver for PAS16 which solves this.\n"
       "Don't enable this feature unless you have problems and have to use\n"
-			    "this switch with DOS\n"))
+      "this switch with DOS\n"))
 	printf ("#define BROKEN_BUS_CLOCK\n");
+
+      if (think_positively ("Disable SB mode of PAS16", 0,
+      "You should disable SB emulation of PAS16 if you want to use\n"
+      "Another SB compatible card in the same system\n"))
+         printf ("#define DISABLE_SB_EMULATION\n");
     }
 
   ask_int_choice (B (OPT_GUS), "GUS_BASE",
@@ -984,10 +989,10 @@
       int             reveal_spea;
 
       reveal_spea = think_positively (
-		  "Is your SoundScape card made/marketed by Reveal or Spea",
-				       0,
-		 "Enable if you have a SoundScape card with the Reveal or\n"
-				       "Spea name on it.\n");
+        "Is your SoundScape card made/marketed by Reveal or Spea",
+	0,
+	"Enable if you have a SoundScape card with the Reveal or\n"
+	"Spea name on it.\n");
       if (reveal_spea)
 	printf ("#define REVEAL_SPEA\n");
 
@@ -1118,6 +1123,7 @@
 		  FMT_INT,
 		  9,
 		  "5, 7, 9 or 10");
+#endif
   ask_int_choice (B (OPT_AUDIO), "DSP_BUFFSIZE",
 		  "Audio DMA buffer size",
 		  FMT_INT,
@@ -1137,11 +1143,18 @@
 	  printf ("bool '%s' CONFIG_%s\n", questions[i], hw_table[i].macro);
 	}
 
+/*
+ * Some "hardcoded" options
+ */
+  printf ("bool 'Support for SM Wave' CONFIG_SMWAVE\n");
+
   dump_only = 1;
   selected_options = 0;
   ask_parameters ();
 
+#if 1
   printf ("#\n$MAKE -C drivers/sound kernelconfig || exit 1\n");
+#endif
 }
 
 void
@@ -1245,12 +1258,11 @@
 
   if (access (oldconf, R_OK) == 0)
     {
-      char            str[255];
-
-      sprintf (str, "Old configuration exists in `%s'. Use it", oldconf);
+      char str[255];
+      sprintf(str, "Old configuration exists in `%s'. Use it", oldconf);
       if (think_positively (str, 1,
-      "Enable this option to load the previously saved configuration file\n"
-			    "for all of the sound driver parameters.\n"))
+"Enable this option to load the previously saved configuration file\n"
+"for all of the sound driver parameters.\n"))
 	if (use_old_config (oldconf))
 	  exit (0);
     }
@@ -1293,31 +1305,31 @@
 	}
   }
 
-  if (selected_options & B (OPT_SBPRO))
+  if (selected_options & B (OPT_SB))
     {
       if (think_positively (
-			     "Support for the SG NX Pro mixer", 0,
-       "Enable this if you want to support the additional mixer functions\n"
-			  "provided on Sound Galaxy NX Pro sound cards.\n"))
+        "Support for the SG NX Pro mixer", 0,
+        "Enable this if you want to support the additional mixer functions\n"
+        "provided on Sound Galaxy NX Pro sound cards.\n"))
 	printf ("#define __SGNXPRO__\n");
     }
 
   if (selected_options & B (OPT_SB))
     {
       if (think_positively ("Support for the MV Jazz16 (ProSonic etc.)", 0,
-	  "Enable this if you have an MV Jazz16 or ProSonic sound card.\n"))
+      "Enable this if you have an MV Jazz16 or ProSonic sound card.\n"))
 	{
 	  if (think_positively ("Do you have SoundMan Wave", 0,
-				"Enable this option of you have the Logitech SoundMan Wave sound card.\n"))
+ "Enable this option of you have the Logitech SoundMan Wave sound card.\n"))
 	    {
 	      printf ("#define SM_WAVE\n");
 
 	    midi0001_again:
 	      if (think_positively (
-			   "Do you have access to the MIDI0001.BIN file", 1,
-				     "The Logitech SoundMan Wave has a microcontroller which must be\n"
-				     "initialized before MIDI emulation works. This is possible only if the\n"
-			   "microcode file is compiled into the driver.\n"))
+"Do you have access to the MIDI0001.BIN file", 1,
+"The Logitech SoundMan Wave has a microcontroller which must be\n"
+"initialized before MIDI emulation works. This is possible only if the\n"
+"microcode file is compiled into the driver.\n"))
 		{
 		  char            path[512];
 
@@ -1331,8 +1343,8 @@
 		      fprintf (stderr, "Couldn't open file %s\n",
 			       path);
 		      if (think_positively ("Try again with correct path", 1,
-					    "The specified file could not be opened. Enter the correct path to the\n"
-					    "file.\n"))
+"The specified file could not be opened. Enter the correct path to the\n"
+"file.\n"))
 			goto midi0001_again;
 		    }
 		  else
@@ -1348,31 +1360,28 @@
   if (selected_options & B (OPT_SB))
     {
       if (think_positively ("Do you have a Logitech SoundMan Games", 0,
-	 "The Logitech SoundMan Games supports 44 kHz in stereo while the\n"
-      "standard SB Pro supports just 22 kHz stereo. You have the option of\n"
-			    "enabling SM Games mode.  However, enable it only if you are sure that\n"
-      "your card is an SM Games. Enabling this feature with a plain old SB\n"
-			    "Pro will cause troubles with stereo mode.\n\n"
-		  "DANGER! Read the above once again before answering 'y'\n"
-			    "Answer 'n' if you are unsure what to do!\n"))
+"The Logitech SoundMan Games supports 44 kHz in stereo while the\n"
+"standard SB Pro supports just 22 kHz stereo. You have the option of\n"
+"enabling SM Games mode.  However, enable it only if you are sure that\n"
+"your card is an SM Games. Enabling this feature with a plain old SB\n"
+"Pro will cause troubles with stereo mode.\n\n"
+"DANGER! Read the above once again before answering 'y'\n"
+"Answer 'n' if you are unsure what to do!\n"))
 	printf ("#define SM_GAMES\n");
     }
 
-  if (selected_options & B (OPT_SB16))
-    selected_options |= B (OPT_SBPRO);
-
   if (selected_options & B (OPT_AEDSP16))
     {
       int             sel1 = 0;
 
-      if (selected_options & B (OPT_SBPRO))
+      if (selected_options & B (OPT_SB))
 	{
 
 	  if (think_positively (
-	    "Do you want support for the Audio Excel SoundBlaster Pro mode",
-				 1,
-				 "Enable this option if you want the Audio Excel sound card to operate\n"
-				 "in SoundBlaster Pro mode.\n"))
+"Do you want support for the Audio Excel SoundBlaster Pro mode",
+1,
+"Enable this option if you want the Audio Excel sound card to operate\n"
+"in SoundBlaster Pro mode.\n"))
 	    {
 	      printf ("#define AEDSP16_SBPRO\n");
 	      sel1 = 1;
@@ -1381,12 +1390,12 @@
 
       if ((selected_options & B (OPT_MSS)) && (sel1 == 0))
 	{
-
+	  
 	  if (think_positively (
-				 "Do you want support for the Audio Excel Microsoft Sound System mode",
-				 1,
-				 "Enable this option if you want the Audio Excel sound card to operate\n"
-				 "in Microsoft Sound System mode.\n"))
+"Do you want support for the Audio Excel Microsoft Sound System mode",
+1,
+"Enable this option if you want the Audio Excel sound card to operate\n"
+"in Microsoft Sound System mode.\n"))
 	    {
 	      printf ("#define AEDSP16_MSS\n");
 	      sel1 = 1;
@@ -1407,8 +1416,8 @@
     {
     genld_again:
       if (think_positively ("Do you wish to include an LD file", 1,
-			    "If you want to emulate the SoundBlaster card and you have a DSPxxx.LD\n"
-		      "file then you must include the LD in the kernel.\n"))
+     "If you want to emulate the SoundBlaster card and you have a DSPxxx.LD\n"
+     "file then you must include the LD in the kernel.\n"))
 	{
 	  char            path[512];
 
@@ -1419,9 +1428,9 @@
 
 	  if (!bin2hex (path, "synth-ld.h", "pss_synth"))
 	    {
-	      fprintf (stderr, "couldn't open `%s' as the LD file\n", path);
+              fprintf (stderr, "couldn't open `%s' as the LD file\n", path);
 	      if (think_positively ("try again with correct path", 1,
-				    "The given LD file could not opened.\n"))
+                "The given LD file could not opened.\n"))
 		goto genld_again;
 	    }
 	  else
@@ -1446,12 +1455,12 @@
     hex2hex_again:
 
       if (think_positively ("Do you want to include TRXPRO.HEX in your kernel",
-			    1,
-	"The MediaTriX AudioTrix Pro has an onboard microcontroller which\n"
-			    "needs to be initialized by downloading the code from the file TRXPRO.HEX\n"
-			    "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n"
-			    "you may skip this step. However, the SB and MPU-401 modes of AudioTriX\n"
-			    "Pro will not work without this file!\n"))
+      1,
+"The MediaTriX AudioTrix Pro has an onboard microcontroller which\n"
+"needs to be initialized by downloading the code from the file TRXPRO.HEX\n"
+"in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n"
+"you may skip this step. However, the SB and MPU-401 modes of AudioTriX\n"
+"Pro will not work without this file!\n"))
 	{
 	  char            path[512];
 
@@ -1470,7 +1479,7 @@
   if (!(selected_options & ANY_DEVS))
     {
       printf ("invalid_configuration__run_make_config_again\n");
-      fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device    ***\n\n");
+      fprintf (stderr,"\n*** This combination is useless. Sound driver disabled!!! ***\n*** You need to enable support for at least one device    ***\n\n");
       exit (0);
     }
 
@@ -1507,13 +1516,12 @@
 
   if (!old_config_used)
     {
-      char            str[255];
-
-      sprintf (str, "Save copy of this configuration to `%s'", oldconf);
-      if (think_positively (str, 1,
-	"If you enable this option then the sound driver configuration is\n"
-      "saved to a file. If you later need to recompile the kernel you have\n"
-			  "the option of using the saved configuration.\n"))
+      char str[255];
+      sprintf(str, "Save copy of this configuration to `%s'", oldconf);
+      if (think_positively (str, 1, 
+"If you enable this option then the sound driver configuration is\n"
+"saved to a file. If you later need to recompile the kernel you have\n"
+"the option of using the saved configuration.\n"))
 	{
 	  char            cmd[200];
 
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v1.3.73/linux/drivers/sound/dev_table.h	Tue Mar  5 10:11:05 1996
+++ linux/drivers/sound/dev_table.h	Wed Mar 13 09:12:17 1996
@@ -334,6 +334,7 @@
 #endif
 #ifdef CONFIG_GUS
 		{"GUS", 0, SNDCARD_GUS,	"Gravis Ultrasound",	attach_gus_card, probe_gus, unload_gus},
+		{"GUSPNP", 1, SNDCARD_GUSPNP,	"GUS PnP",	attach_gus_card, probe_gus, unload_gus},
 #endif
 #ifdef CONFIG_SSCAPE
 		{"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq Soundscape",	attach_sscape, probe_sscape, unload_sscape},
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v1.3.73/linux/drivers/sound/dmabuf.c	Tue Mar  5 10:11:05 1996
+++ linux/drivers/sound/dmabuf.c	Wed Mar 13 09:12:37 1996
@@ -234,6 +234,7 @@
     dmap->dma_mode = DMODE_NONE;
   dmap->flags &= ~DMA_BUSY;
 
+  disable_dma (chan);
   sound_free_dmap (dev, dmap);
 }
 
@@ -1303,35 +1304,41 @@
 polish_buffers (struct dma_buffparms *dmap)
 {
   int             i;
+  int             p, l;
 
-  if (dmap->cfrag < 0)
+  i = dmap->qhead;
+
+  p = dmap->fragment_size * i;
+
+  if (i == dmap->cfrag)
     {
-      memset (dmap->raw_buf,
-	      dmap->neutral_byte,
-	      dmap->bytes_in_use);
-      return;
+      l = dmap->fragment_size - dmap->counts[i];
     }
+  else
+    l = dmap->fragment_size;
 
-  for (i = 0; i < dmap->nbufs; i++)
+  if (l)
     {
-      int             p, l;
-
-      p = dmap->fragment_size * i;
+      memset (dmap->raw_buf + p,
+	      dmap->neutral_byte,
+	      l);
+    }
+}
 
-      if (i == dmap->cfrag)
-	{
-	  l = dmap->fragment_size - dmap->counts[i];
-	}
-      else
-	l = dmap->fragment_size;
+static void
+force_restart (int dev, struct dma_buffparms *dmap)
+{
+  if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
+      audio_devs[dev]->halt_output)
+    audio_devs[dev]->halt_output (dev);
+  else
+    audio_devs[dev]->halt_xfer (dev);
 
-      if (l)
-	{
-	  memset (dmap->raw_buf + p,
-		  dmap->neutral_byte,
-		  l);
-	}
-    }
+  dmap->flags &= ~DMA_ACTIVE;
+  if (audio_devs[dev]->flags & DMA_AUTOMODE)
+    dmap->flags |= DMA_RESTART;
+  else
+    dmap->flags &= ~DMA_RESTART;
 }
 
 void
@@ -1393,7 +1400,14 @@
       if (event_type == 1 && dmap->qlen < 1)
 	{
 	  dmap->underrun_count++;
-	  /* Ignore underrun. Just move the tail pointer forward and go */
+
+	  if (dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)
+	    {
+	      dmap->qlen = 0;
+	      force_restart (dev, dmap);
+	    }
+	  else
+	    /* Ignore underrun. Just move the tail pointer forward and go */
 	  if (dmap->closing)
 	    {
 	      polish_buffers (dmap);
@@ -1482,7 +1496,7 @@
 
       if (audio_devs[dev]->flags & DMA_AUTOMODE)
 	{
-	  /* Force restart on next write */
+	  /* Force restart on next read */
 	  if ((audio_devs[dev]->flags & DMA_DUPLEX) &&
 	      audio_devs[dev]->halt_input)
 	    audio_devs[dev]->halt_input (dev);
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c
--- v1.3.73/linux/drivers/sound/gus_card.c	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/gus_card.c	Wed Mar 13 09:12:37 1996
@@ -41,6 +41,7 @@
 extern int      gus_wave_volume;
 extern int      gus_pcm_volume;
 extern int      have_gus_max;
+int             gus_pnp_flag = 0;
 
 int            *gus_osp;
 
@@ -115,6 +116,9 @@
 
   gus_osp = hw_config->osp;
 
+  if (hw_config->card_subtype == 1)
+    gus_pnp_flag = 1;
+
   irq = hw_config->irq;
 
   if (hw_config->card_subtype == 0)	/* GUS/MAX/ACE */
@@ -125,10 +129,12 @@
 	return 0;
       }
 
-  if (!check_region (hw_config->io_base, 16))
-    if (!check_region (hw_config->io_base + 0x100, 16))
-      if (gus_wave_detect (hw_config->io_base))
-	return 1;
+  if (check_region (hw_config->io_base, 16))
+    printk ("GUS: I/O range conflict (1)\n");
+  else if (check_region (hw_config->io_base + 0x100, 16))
+    printk ("GUS: I/O range conflict (2)\n");
+  else if (gus_wave_detect (hw_config->io_base))
+    return 1;
 
 #ifndef EXCLUDE_GUS_IODETECT
 
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v1.3.73/linux/drivers/sound/gus_wave.c	Tue Mar  5 10:11:05 1996
+++ linux/drivers/sound/gus_wave.c	Wed Mar 13 09:12:42 1996
@@ -80,6 +80,7 @@
 
 extern int      gus_base;
 extern int      gus_irq, gus_dma;
+extern int      gus_pnp_flag;
 static int      gus_dma2 = -1;
 static int      dual_dma_mode = 0;
 static long     gus_mem_size = 0;
@@ -2991,13 +2992,14 @@
 
   int             irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
 
-  if (irq < 0 || irq > 15)
-    {
-      printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
-      return mem_start;
-    }
+  if (!gus_pnp_flag)
+    if (irq < 0 || irq > 15)
+      {
+	printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
+	return mem_start;
+      }
 
-  if (dma < 0 || dma > 7)
+  if (dma < 0 || dma > 7 || dma == 4)
     {
       printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
       return mem_start;
@@ -3022,14 +3024,21 @@
   val = inb (gus_base + 0x0f);
   restore_flags (flags);
 
-  if (val != 0xff && (val & 0x06))	/* Should be 0x02?? */
+#ifndef GUSPNP_NO_AUTODETECT
+  gus_pnp_flag = (val == 1);
+#endif
+
+  if (gus_pnp_flag || (val != 0xff && (val & 0x06)))	/* Should be 0x02?? */
     {
       /*
          * It has the digital ASIC so the card is at least v3.4.
          * Next try to detect the true model.
        */
 
-      val = inb (u_MixSelect);
+      if (gus_pnp_flag)		/* Hack hack hack */
+	val = 10;
+      else
+	val = inb (u_MixSelect);
 
       /*
          * Value 255 means pre-3.7 which don't have mixer.
@@ -3103,7 +3112,11 @@
 
   if (hw_config->name)
     {
-      strncpy (gus_info.name, hw_config->name, sizeof (gus_info.name));
+      char            tmp[20];
+
+      strncpy (tmp, hw_config->name, 20);
+      tmp[19] = 0;
+      sprintf (gus_info.name, "%s (%dk)", tmp, (int) gus_mem_size / 1024);
       gus_info.name[sizeof (gus_info.name) - 1] = 0;
     }
   else
@@ -3420,7 +3433,8 @@
 	    if (pcm_qlen == 0)
 	      flag = 1;		/* Underrun */
 	    dma_active = 0;
-	    DMAbuf_outputintr (gus_devnum, flag);
+	    if (gus_busy)
+	      DMAbuf_outputintr (gus_devnum, flag);
 	  }
 	break;
 
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v1.3.73/linux/drivers/sound/os.h	Tue Mar  5 10:11:05 1996
+++ linux/drivers/sound/os.h	Wed Mar 13 09:12:22 1996
@@ -55,3 +55,4 @@
 
 #undef PSEUDO_DMA_AUTOINIT
 #define ALLOW_BUFFER_MAPPING
+
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v1.3.73/linux/drivers/sound/pas2_card.c	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/pas2_card.c	Wed Mar 13 09:12:51 1996
@@ -299,6 +299,8 @@
 
 	pas_write (irq_dma, EMULATION_CONFIGURATION);
       }
+    else
+      pas_write (0x00, COMPATIBILITY_ENABLE);
   }
 #else
   pas_write (0x00, COMPATIBILITY_ENABLE);
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v1.3.73/linux/drivers/sound/pss.c	Wed Feb 28 11:50:08 1996
+++ linux/drivers/sound/pss.c	Wed Mar 13 09:12:56 1996
@@ -518,6 +518,87 @@
       }
       break;
 
+    case SNDCTL_COPR_SENDMSG:
+      {
+	copr_msg       *buf;
+	unsigned long   flags;
+	unsigned short *data;
+	unsigned short  tmp;
+	int             i;
+
+	buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL);
+	if (buf == NULL)
+	  return -ENOSPC;
+
+	memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf));
+
+	data = (unsigned short *) (buf->data);
+
+	/* printk( "SNDCTL_COPR_SENDMSG: data = %d", data ); */
+
+	save_flags (flags);
+	cli ();
+
+	for (i = 0; i < buf->len; i++)
+	  {
+	    tmp = *data++;
+	    if (!pss_put_dspword (devc, tmp))
+	      {
+		restore_flags (flags);
+		buf->len = i;	/* feed back number of WORDs sent */
+		memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf));
+		kfree (buf);
+		return -EIO;
+	      }
+	  }
+
+	restore_flags (flags);
+	kfree (buf);
+
+	return 0;
+      }
+      break;
+
+
+    case SNDCTL_COPR_RCVMSG:
+      {
+	copr_msg       *buf;
+	unsigned long   flags;
+	unsigned short *data;
+	unsigned int    i;
+	int             err = 0;
+
+	buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL);
+	if (buf == NULL)
+	  return -ENOSPC;
+
+	memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf));
+
+	data = (unsigned short *) buf->data;
+
+	save_flags (flags);
+	cli ();
+
+	for (i = 0; i < buf->len; i++)
+	  {
+	    if (!pss_get_dspword (devc, data++))
+	      {
+		buf->len = i;	/* feed back number of WORDs read */
+		err = -EIO;
+		break;
+	      }
+	  }
+
+	restore_flags (flags);
+
+	memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf));
+	kfree (buf);
+
+	return err;
+      }
+      break;
+
+
     case SNDCTL_COPR_RDATA:
       {
 	copr_debug_buf  buf;
@@ -610,14 +691,14 @@
 	    return -EIO;
 	  }
 
-	tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff;
+	tmp = (unsigned int) buf.parm2 & 0x00ff;
 	if (!pss_put_dspword (devc, tmp))
 	  {
 	    restore_flags (flags);
 	    return -EIO;
 	  }
 
-	tmp = (unsigned int) buf.parm2 & 0x00ff;
+	tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff;
 	if (!pss_put_dspword (devc, tmp))
 	  {
 	    restore_flags (flags);
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c
--- v1.3.73/linux/drivers/sound/sb16_dsp.c	Tue Mar  5 10:11:05 1996
+++ linux/drivers/sound/sb16_dsp.c	Wed Mar 13 09:12:57 1996
@@ -246,6 +246,7 @@
   DEB (printk ("sb16_dsp_close()\n"));
   sb_dsp_command01 (0xd9);
   sb_dsp_command01 (0xd5);
+  sb_reset_dsp ();
 
   save_flags (flags);
   cli ();
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c
--- v1.3.73/linux/drivers/sound/sb16_midi.c	Tue Mar  5 10:11:05 1996
+++ linux/drivers/sound/sb16_midi.c	Wed Mar 13 09:12:57 1996
@@ -125,7 +125,6 @@
       return -EBUSY;
     }
 
-  reset_sb16midi ();
   while (input_avail ())
     sb16midi_read ();
 
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c
--- v1.3.73/linux/drivers/sound/sb_dsp.c	Tue Mar  5 10:11:05 1996
+++ linux/drivers/sound/sb_dsp.c	Wed Mar 13 09:12:59 1996
@@ -75,6 +75,7 @@
 int             sbc_major = 0, sbc_minor = 0;
 static int      dsp_stereo = 0;
 static int      dsp_current_speed = DSP_DEFAULT_SPEED;
+static int      dsp_requested_speed = DSP_DEFAULT_SPEED;
 static int      sb16 = 0;
 static int      irq_verified = 0;
 
@@ -334,6 +335,8 @@
   unsigned long   flags;
   int             max_speed = 44100;
 
+  dsp_requested_speed = speed;
+
   if (AudioDrive)
     return ess_speed (speed);
 
@@ -447,6 +450,7 @@
     }
 
   dsp_stereo = !!mode;
+  dsp_speed (dsp_requested_speed);
   return dsp_stereo;
 }
 
@@ -473,9 +477,6 @@
   unsigned long   flags;
   int             count = nr_bytes;
 
-  if (!sb_irq_mode)
-    dsp_speaker (ON);
-
   DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
 
   sb_irq_mode = 0;
@@ -564,9 +565,6 @@
    * Start a DMA input to the buffer pointed by dmaqtail
    */
 
-  if (!sb_irq_mode)
-    dsp_speaker (OFF);
-
   DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
   sb_irq_mode = 0;
 
@@ -665,6 +663,7 @@
 
   dsp_cleanup ();
   dsp_speaker (OFF);
+  dsp_speed (dsp_requested_speed);
 
   if (sbc_major == 3)		/*
 				 * SB Pro
@@ -722,7 +721,6 @@
 	  else
 	    sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
 
-	  dsp_speed (dsp_current_speed);
 	}			/* !AudioDrive */
     }
   trigger_bits = 0;
@@ -734,6 +732,7 @@
 {
   dsp_cleanup ();
   dsp_speaker (OFF);
+  dsp_speed (dsp_requested_speed);
 
   if (sbc_major == 3)		/* SB Pro (at least ) */
     {
@@ -827,6 +826,9 @@
       printk ("SB Error: SoundBlaster board not installed\n");
       return -ENXIO;
     }
+
+  if (!sb_midi_busy)
+    sb_reset_dsp ();
 
   if (sb_no_recording && mode & OPEN_READ)
     {
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h
--- v1.3.73/linux/drivers/sound/sound_config.h	Wed Feb 14 14:37:16 1996
+++ linux/drivers/sound/sound_config.h	Wed Mar 13 09:12:20 1996
@@ -27,8 +27,8 @@
  */
 
 
-#include "os.h"
 #include "local.h"
+#include "os.h"
 #include "soundvers.h"
 
 #if defined(ISC) || defined(SCO) || defined(SVR42)
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v1.3.73/linux/drivers/sound/soundcard.c	Sat Mar  2 10:43:42 1996
+++ linux/drivers/sound/soundcard.c	Thu Mar 14 09:19:25 1996
@@ -70,8 +70,8 @@
 {
   int             dev;
 
-  dev = inode_get_rdev (inode);
-  dev = MINOR (dev);
+  dev = MINOR (inode_get_rdev (inode));
+
   files[dev].flags = file_get_flags (file);
 
   return sound_read_sw (dev, &files[dev], buf, count);
@@ -82,8 +82,8 @@
 {
   int             dev;
 
-  dev = inode_get_rdev (inode);
-  dev = MINOR (dev);
+  dev = MINOR (inode_get_rdev (inode));
+
   files[dev].flags = file_get_flags (file);
 
   return sound_write_sw (dev, &files[dev], buf, count);
@@ -107,8 +107,7 @@
       return -EBUSY;
     }
 
-  dev = inode_get_rdev (inode);
-  dev = MINOR (dev);
+  dev = MINOR (inode_get_rdev (inode));
 
   if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
     {
@@ -142,8 +141,7 @@
 {
   int             dev;
 
-  dev = inode_get_rdev (inode);
-  dev = MINOR (dev);
+  dev = MINOR (inode_get_rdev (inode));
 
   files[dev].flags = file_get_flags (file);
 
@@ -159,8 +157,8 @@
 {
   int             dev, err;
 
-  dev = inode_get_rdev (inode);
-  dev = MINOR (dev);
+  dev = MINOR (inode_get_rdev (inode));
+
   files[dev].flags = file_get_flags (file);
 
   if (_IOC_DIR (cmd) != _IOC_NONE)
@@ -196,8 +194,8 @@
 {
   int             dev;
 
-  dev = inode_get_rdev (inode);
-  dev = MINOR (dev);
+  dev = MINOR (inode_get_rdev (inode));
+
   files[dev].flags = file_get_flags (file);
 
   DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
@@ -239,8 +237,8 @@
   unsigned long   size;
   struct dma_buffparms *dmap = NULL;
 
-  dev = inode_get_rdev (inode);
-  dev = MINOR (dev);
+  dev = MINOR (inode_get_rdev (inode));
+
   files[dev].flags = file_get_flags (file);
 
   dev_class = dev & 0x0f;
@@ -442,32 +440,27 @@
 void
 cleanup_module (void)
 {
-  if (MOD_IN_USE)
-    printk ("sound: module busy -- remove delayed\n");
-  else
-    {
-      int             i;
+  int             i;
 
-      if (chrdev_registered)
-	module_unregister_chrdev (sound_major, "sound");
+  if (chrdev_registered)
+    module_unregister_chrdev (sound_major, "sound");
 
 #ifdef CONFIG_SEQUENCER
-      sound_stop_timer ();
+  sound_stop_timer ();
 #endif
-      sound_unload_drivers ();
+  sound_unload_drivers ();
 
-      for (i = 0; i < sound_num_blocks; i++)
-	kfree (sound_mem_blocks[i]);
+  for (i = 0; i < sound_num_blocks; i++)
+    kfree (sound_mem_blocks[i]);
 
-      free_all_irqs ();		/* If something was left allocated by accident */
+  free_all_irqs ();		/* If something was left allocated by accident */
 
-      for (i = 0; i < 8; i++)
-	if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
-	  {
-	    printk ("Sound: Hmm, DMA%d was left allocated - fixed\n", i);
-	    sound_free_dma (i);
-	  }
-    }
+  for (i = 0; i < 8; i++)
+    if (dma_alloc_map[i] != DMA_MAP_UNAVAIL)
+      {
+	printk ("Sound: Hmm, DMA%d was left allocated - fixed\n", i);
+	sound_free_dma (i);
+      }
 }
 #endif
 
@@ -499,6 +492,9 @@
 void
 snd_release_irq (int vect)
 {
+  if (!(irqs & (1ul << vect)))
+    return;
+
   irqs &= ~(1ul << vect);
   free_irq (vect, NULL);
 }
@@ -651,7 +647,7 @@
 
       audio_devs[dev]->buffsize = PAGE_SIZE * (1 << sz);
 
-      if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL)
+      if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, 1)) == NULL)
 	audio_devs[dev]->buffsize /= 2;
     }
 
@@ -684,8 +680,6 @@
     }
   dmap->raw_buf = start_addr;
   dmap->raw_buf_phys = virt_to_bus (start_addr);
-
-  memset (dmap->raw_buf, 0x00, audio_devs[dev]->buffsize);
 
   for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++)
     {
diff -u --recursive --new-file v1.3.73/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h
--- v1.3.73/linux/drivers/sound/soundvers.h	Tue Mar  5 10:11:06 1996
+++ linux/drivers/sound/soundvers.h	Wed Mar 13 09:12:21 1996
@@ -1,2 +1,2 @@
-#define SOUND_VERSION_STRING "3.5-beta10-960301"
-#define SOUND_INTERNAL_VERSION 0x030505
+#define SOUND_VERSION_STRING "3.5-960313"
+#define SOUND_INTERNAL_VERSION 0x030500
diff -u --recursive --new-file v1.3.73/linux/fs/buffer.c linux/fs/buffer.c
--- v1.3.73/linux/fs/buffer.c	Wed Mar 13 10:09:19 1996
+++ linux/fs/buffer.c	Wed Mar 13 13:52:45 1996
@@ -49,7 +49,6 @@
 
 static int nr_hash = 0;  /* Size of hash table */
 static struct buffer_head ** hash_table;
-struct buffer_head ** buffer_pages;
 static struct buffer_head * lru_list[NR_LIST] = {NULL, };
 /* next_to_age is an array of pointers into the lru lists, used to
    cycle through the buffers aging their contents when deciding which
@@ -1327,7 +1326,7 @@
 			break;
 	}
 	free_list[isize] = bh;
-	buffer_pages[MAP_NR(page)] = bh;
+	mem_map[MAP_NR(page)].buffers = bh;
 	tmp->b_this_page = bh;
 	buffermem += PAGE_SIZE;
 	return 1;
@@ -1377,7 +1376,7 @@
 		put_unused_buffer_head(p);
 	} while (tmp != bh);
 	buffermem -= PAGE_SIZE;
-	buffer_pages[MAP_NR(page)] = NULL;
+	mem_map[MAP_NR(page)].buffers = NULL;
 	free_page(page);
 	return !mem_map[MAP_NR(page)].count;
 }
@@ -1728,7 +1727,7 @@
 			break;
 	}
 	buffermem += PAGE_SIZE;
-	buffer_pages[MAP_NR(page)] = bh;
+	mem_map[MAP_NR(page)].buffers = bh;
 	bh->b_this_page = tmp;
 	while (nblock-- > 0)
 		brelse(arr[nblock]);
@@ -1796,11 +1795,6 @@
 	hash_table = (struct buffer_head **) vmalloc(nr_hash * 
 						     sizeof(struct buffer_head *));
 
-
-	buffer_pages = (struct buffer_head **) vmalloc(MAP_NR(high_memory) * 
-						     sizeof(struct buffer_head *));
-	for (i = 0 ; i < MAP_NR(high_memory) ; i++)
-		buffer_pages[i] = NULL;
 
 	for (i = 0 ; i < nr_hash ; i++)
 		hash_table[i] = NULL;
diff -u --recursive --new-file v1.3.73/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v1.3.73/linux/include/asm-alpha/pgtable.h	Mon Jan  8 14:10:28 1996
+++ linux/include/asm-alpha/pgtable.h	Thu Mar 14 16:33:27 1996
@@ -238,29 +238,16 @@
 
 extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_VALID; }
-extern inline int pte_inuse(pte_t *ptep)	{ return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
 extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
-extern inline void pte_reuse(pte_t * ptep)
-{
-	if (!mem_map[MAP_NR(ptep)].reserved)
-		mem_map[MAP_NR(ptep)].count++;
-}
 
 extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
 extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE || pmd_page(pmd) > high_memory; }
 extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_VALID; }
-extern inline int pmd_inuse(pmd_t *pmdp)	{ return mem_map[MAP_NR(pmdp)].reserved || mem_map[MAP_NR(pmdp)].count != 1; }
 extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp)
-{
-	if (!mem_map[MAP_NR(pmdp)].reserved)
-		mem_map[MAP_NR(pmdp)].count++;
-}
 
 extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
 extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE || pgd_page(pgd) > high_memory; }
 extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_VALID; }
-extern inline int pgd_inuse(pgd_t *pgdp)	{ return mem_map[MAP_NR(pgdp)].reserved; }
 extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
 
 /*
@@ -328,11 +315,10 @@
 /*      
  * Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
- * if any, and marks the page tables reserved.
+ * if any.
  */
 extern inline void pte_free_kernel(pte_t * pte)
 {
-	mem_map[MAP_NR(pte)].reserved = 0;
 	free_page((unsigned long) pte);
 }
 
@@ -344,7 +330,6 @@
 		if (pmd_none(*pmd)) {
 			if (page) {
 				pmd_set(pmd, page);
-				mem_map[MAP_NR(page)].reserved = 1;
 				return page + address;
 			}
 			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
@@ -362,7 +347,6 @@
 
 extern inline void pmd_free_kernel(pmd_t * pmd)
 {
-	mem_map[MAP_NR(pmd)].reserved = 0;
 	free_page((unsigned long) pmd);
 }
 
@@ -374,7 +358,6 @@
 		if (pgd_none(*pgd)) {
 			if (page) {
 				pgd_set(pgd, page);
-				mem_map[MAP_NR(page)].reserved = 1;
 				return page + address;
 			}
 			pgd_set(pgd, BAD_PAGETABLE);
diff -u --recursive --new-file v1.3.73/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v1.3.73/linux/include/asm-i386/pgtable.h	Wed Feb  7 15:11:37 1996
+++ linux/include/asm-i386/pgtable.h	Thu Mar 14 16:33:04 1996
@@ -288,24 +288,12 @@
 
 extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
-extern inline int pte_inuse(pte_t *ptep)	{ return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
 extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
-extern inline void pte_reuse(pte_t * ptep)
-{
-	if (!mem_map[MAP_NR(ptep)].reserved)
-		mem_map[MAP_NR(ptep)].count++;
-}
 
 extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
 extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; }
 extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_PRESENT; }
-#ifdef USE_PENTIUM_MM
-extern inline int pmd_inuse(pmd_t *pmdp)	{ return (pmd_val(*pmdp) & _PAGE_4M) != 0; }
-#else
-extern inline int pmd_inuse(pmd_t *pmdp)	{ return 0; }
-#endif
 extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp)	{ }
 
 /*
  * The "pgd_xxx()" functions here are trivial for a folded two-level
@@ -315,7 +303,6 @@
 extern inline int pgd_none(pgd_t pgd)		{ return 0; }
 extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
 extern inline int pgd_present(pgd_t pgd)	{ return 1; }
-extern inline int pgd_inuse(pgd_t * pgdp)	{ return mem_map[MAP_NR(pgdp)].reserved; }
 extern inline void pgd_clear(pgd_t * pgdp)	{ }
 
 /*
@@ -376,11 +363,10 @@
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
- * if any, and marks the page tables reserved.
+ * if any.
  */
 extern inline void pte_free_kernel(pte_t * pte)
 {
-	mem_map[MAP_NR(pte)].reserved = 0;
 	free_page((unsigned long) pte);
 }
 
@@ -392,7 +378,6 @@
 		if (pmd_none(*pmd)) {
 			if (page) {
 				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
-				mem_map[MAP_NR(page)].reserved = 1;
 				return page + address;
 			}
 			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
diff -u --recursive --new-file v1.3.73/linux/include/asm-mips/dma.h linux/include/asm-mips/dma.h
--- v1.3.73/linux/include/asm-mips/dma.h	Sun Dec 17 11:43:23 1995
+++ linux/include/asm-mips/dma.h	Thu Mar 14 09:21:15 1996
@@ -279,7 +279,6 @@
 /*
  * DMA memory allocation - formerly in include/linux/mm.h
  */
-#define __get_dma_pages(priority, order) __get_free_pages((priority),(order), \
-                                             0x80000000 + MAX_DMA_ADDRESS)
+#define __get_dma_pages(priority, order) __get_free_pages((priority),(order), 1)
 
 #endif /* __ASM_MIPS_DMA_H */
diff -u --recursive --new-file v1.3.73/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.3.73/linux/include/linux/fs.h	Wed Mar 13 10:09:22 1996
+++ linux/include/linux/fs.h	Thu Mar 14 09:32:39 1996
@@ -491,7 +491,7 @@
 extern struct inode_operations chrdev_inode_operations;
 
 extern void init_fifo(struct inode * inode);
-struct inode_operations fifo_inode_operations;
+extern struct inode_operations fifo_inode_operations;
 
 extern struct file_operations connecting_fifo_fops;
 extern struct file_operations read_fifo_fops;
@@ -515,7 +515,6 @@
 extern void refill_freelist(int size);
 extern int try_to_free_buffer(struct buffer_head*, struct buffer_head**, int);
 
-extern struct buffer_head ** buffer_pages;
 extern int nr_buffers;
 extern int buffermem;
 extern int nr_buffer_heads;
diff -u --recursive --new-file v1.3.73/linux/include/linux/mm.h linux/include/linux/mm.h
--- v1.3.73/linux/include/linux/mm.h	Wed Feb 28 11:50:13 1996
+++ linux/include/linux/mm.h	Thu Mar 14 09:32:40 1996
@@ -123,7 +123,8 @@
 		 referenced:1,
 		 locked:1,
 		 free_after:1,
-		 unused:2,
+		 dma:1,
+		 unused:1,
 		 reserved:1;
 	struct wait_queue *wait;
 	struct page *next;
@@ -135,32 +136,19 @@
 
 	struct page *prev;
 	struct page *prev_hash;
+	struct buffer_head * buffers;
 } mem_map_t;
 
 extern mem_map_t * mem_map;
 
 /*
- * Free area management
- */
-
-#define NR_MEM_LISTS 6
-
-struct mem_list {
-	struct mem_list * next;
-	struct mem_list * prev;
-};
-
-extern struct mem_list free_area_list[NR_MEM_LISTS];
-extern unsigned int * free_area_map[NR_MEM_LISTS];
-
-/*
  * This is timing-critical - most of the time in getting a new page
  * goes to clearing the page. If you want a page without the clearing
  * overhead, just use __get_free_page() directly..
  */
-#define __get_free_page(priority) __get_free_pages((priority),0,~0UL)
-#define __get_dma_pages(priority, order) __get_free_pages((priority),(order),MAX_DMA_ADDRESS)
-extern unsigned long __get_free_pages(int priority, unsigned long gfporder, unsigned long max_addr);
+#define __get_free_page(priority) __get_free_pages((priority),0,0)
+#define __get_dma_pages(priority, order) __get_free_pages((priority),(order),1)
+extern unsigned long __get_free_pages(int priority, unsigned long gfporder, int dma);
 
 extern inline unsigned long get_free_page(int priority)
 {
@@ -222,7 +210,7 @@
 
 /* filemap.c */
 extern unsigned long page_unuse(unsigned long);
-extern int shrink_mmap(int, unsigned long);
+extern int shrink_mmap(int, int);
 extern void truncate_inode_pages(struct inode *, unsigned long);
 
 #define GFP_BUFFER	0x00
diff -u --recursive --new-file v1.3.73/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v1.3.73/linux/include/linux/proc_fs.h	Wed Feb 28 11:50:14 1996
+++ linux/include/linux/proc_fs.h	Thu Mar 14 12:57:46 1996
@@ -128,6 +128,7 @@
 	PROC_SCSI_AM53C974,
 	PROC_SCSI_SSC,
 	PROC_SCSI_NCR53C406A,
+	PROC_SCSI_PPA,
 	PROC_SCSI_SCSI_DEBUG,	
 	PROC_SCSI_NOT_PRESENT,
 	PROC_SCSI_FILE,                        /* I'm asuming here that we */
diff -u --recursive --new-file v1.3.73/linux/include/linux/soundcard.h linux/include/linux/soundcard.h
--- v1.3.73/linux/include/linux/soundcard.h	Wed Feb 28 11:50:14 1996
+++ linux/include/linux/soundcard.h	Wed Mar 13 09:12:21 1996
@@ -57,6 +57,7 @@
 #define SNDCARD_CS4232_MPU	22
 #define SNDCARD_MAUI		23
 #define SNDCARD_PSEUDO_MSS	24
+#define SNDCARD_GUSPNP		25
 
 /***********************************
  * IOCTL Commands for /dev/sequencer
@@ -614,12 +615,13 @@
 #define SNDCTL_DSP_GETOPTR		_IOR ('P',18, count_info)
 
 typedef struct buffmem_desc {
-		caddr_t buffer;
+		unsigned *buffer;
 		int size;
 	} buffmem_desc;
 #define SNDCTL_DSP_MAPINBUF		_IOR ('P', 19, buffmem_desc)
 #define SNDCTL_DSP_MAPOUTBUF		_IOR ('P', 20, buffmem_desc)
 #define SNDCTL_DSP_SETSYNCRO		_IO  ('P', 21)
+#define SNDCTL_DSP_SETDUPLEX		_IO  ('P', 22)
 
 #define SOUND_PCM_READ_RATE		_IOR ('P', 2, int)
 #define SOUND_PCM_READ_CHANNELS		_IOR ('P', 6, int)
diff -u --recursive --new-file v1.3.73/linux/include/linux/swap.h linux/include/linux/swap.h
--- v1.3.73/linux/include/linux/swap.h	Wed Feb 28 11:50:14 1996
+++ linux/include/linux/swap.h	Wed Mar 13 15:18:33 1996
@@ -43,10 +43,10 @@
 struct sysinfo;
 
 /* linux/ipc/shm.c */
-extern int shm_swap (int, unsigned long);
+extern int shm_swap (int, int);
 
 /* linux/mm/vmscan.c */
-extern int try_to_free_page(int, unsigned long, int);
+extern int try_to_free_page(int, int, int);
 
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, unsigned long, char *, int);
@@ -97,19 +97,19 @@
 extern unsigned long swap_cache_find_success;
 #endif
 
-extern inline unsigned long in_swap_cache(unsigned long addr)
+extern inline unsigned long in_swap_cache(unsigned long index)
 {
-	return swap_cache[MAP_NR(addr)]; 
+	return swap_cache[index]; 
 }
 
-extern inline long find_in_swap_cache (unsigned long addr)
+extern inline long find_in_swap_cache(unsigned long index)
 {
 	unsigned long entry;
 
 #ifdef SWAP_CACHE_INFO
 	swap_cache_find_total++;
 #endif
-	entry = xchg(swap_cache + MAP_NR(addr), 0);
+	entry = xchg(swap_cache + index, 0);
 #ifdef SWAP_CACHE_INFO
 	if (entry)
 		swap_cache_find_success++;
@@ -117,14 +117,14 @@
 	return entry;
 }
 
-extern inline int delete_from_swap_cache(unsigned long addr)
+extern inline int delete_from_swap_cache(unsigned long index)
 {
 	unsigned long entry;
 	
 #ifdef SWAP_CACHE_INFO
 	swap_cache_del_total++;
 #endif	
-	entry= xchg(swap_cache + MAP_NR(addr), 0);
+	entry = xchg(swap_cache + index, 0);
 	if (entry)  {
 #ifdef SWAP_CACHE_INFO
 		swap_cache_del_success++;
diff -u --recursive --new-file v1.3.73/linux/init/main.c linux/init/main.c
--- v1.3.73/linux/init/main.c	Wed Mar 13 10:09:23 1996
+++ linux/init/main.c	Thu Mar 14 12:57:46 1996
@@ -64,6 +64,7 @@
 extern void buff_setup(char *str, int *ints);
 extern void panic_setup(char *str, int *ints);
 extern void bmouse_setup(char *str, int *ints);
+extern void lp_setup(char *str, int *ints);
 extern void eth_setup(char *str, int *ints);
 extern void xd_setup(char *str, int *ints);
 extern void floppy_setup(char *str, int *ints);
@@ -82,6 +83,7 @@
 extern void BusLogic_Setup(char *str, int *ints);
 extern void fdomain_setup(char *str, int *ints);
 extern void NCR53c406a_setup(char *str, int *ints);
+extern void ppa_setup(char *str, int *ints);
 extern void scsi_luns_setup(char *str, int *ints);
 extern void sound_setup(char *str, int *ints);
 #ifdef CONFIG_CDU31A
@@ -227,6 +229,9 @@
 #ifdef CONFIG_INET
 	{ "ether=", eth_setup },
 #endif
+#ifdef CONFIG_PRINTER
+        { "lp=", lp_setup },
+#endif
 #ifdef CONFIG_SCSI
 	{ "max_scsi_luns=", scsi_luns_setup },
 #endif
@@ -276,6 +281,9 @@
 #endif
 #ifdef CONFIG_SCSI_FUTURE_DOMAIN
 	{ "fdomain=", fdomain_setup},
+#endif
+#ifdef CONFIG_SCSI_PPA
+        { "ppa=", ppa_setup },
 #endif
 #ifdef CONFIG_BLK_DEV_XD
 	{ "xd=", xd_setup },
diff -u --recursive --new-file v1.3.73/linux/ipc/shm.c linux/ipc/shm.c
--- v1.3.73/linux/ipc/shm.c	Wed Feb 28 11:50:15 1996
+++ linux/ipc/shm.c	Wed Mar 13 13:56:21 1996
@@ -674,7 +674,7 @@
 static unsigned long swap_id = 0; /* currently being swapped */
 static unsigned long swap_idx = 0; /* next to swap */
 
-int shm_swap (int prio, unsigned long limit)
+int shm_swap (int prio, int dma)
 {
 	pte_t page;
 	struct shmid_ds *shp;
@@ -711,7 +711,7 @@
 	pte_val(page) = shp->shm_pages[idx];
 	if (!pte_present(page))
 		goto check_table;
-	if (pte_page(page) >= limit)
+	if (dma && !mem_map[MAP_NR(pte_page(page))].dma)
 		goto check_table;
 	swap_attempts++;
 
diff -u --recursive --new-file v1.3.73/linux/kernel/sys.c linux/kernel/sys.c
--- v1.3.73/linux/kernel/sys.c	Wed Mar 13 10:09:24 1996
+++ linux/kernel/sys.c	Wed Mar 13 07:54:17 1996
@@ -290,7 +290,7 @@
 
    if (acct_active) {
       strncpy(ac.ac_comm, current->comm, ACCT_COMM);
-      ac.ac_comm[ACCT_COMM] = '\0';
+      ac.ac_comm[ACCT_COMM-1] = '\0';
       ac.ac_utime = current->utime;
       ac.ac_stime = current->stime;
       ac.ac_btime = CT_TO_SECS(current->start_time) + (xtime.tv_sec - (jiffies / HZ));
diff -u --recursive --new-file v1.3.73/linux/mm/filemap.c linux/mm/filemap.c
--- v1.3.73/linux/mm/filemap.c	Wed Feb 28 11:50:15 1996
+++ linux/mm/filemap.c	Wed Mar 13 13:53:24 1996
@@ -109,25 +109,23 @@
 	}
 }
 
-int shrink_mmap(int priority, unsigned long limit)
+int shrink_mmap(int priority, int dma)
 {
 	static int clock = 0;
 	struct page * page;
+	unsigned long limit = MAP_NR(high_memory);
 	struct buffer_head *tmp, *bh;
 
-	if (limit > high_memory)
-		limit = high_memory;
-	limit = MAP_NR(limit);
-	if (clock >= limit)
-		clock = 0;
 	priority = (limit<<2) >> priority;
 	page = mem_map + clock;
 	while (priority-- > 0) {
 		if (page->locked)
-		    goto next;
+			goto next;
+		if (dma && !page->dma)
+			goto next;
 		/* First of all, regenerate the page's referenced bit
                    from any buffers in the page */
-		bh = buffer_pages[MAP_NR(page_address(page))];
+		bh = page->buffers;
 		if (bh) {
 			tmp = bh;
 			do {
@@ -505,7 +503,7 @@
 	struct inode * inode;
 	struct buffer_head * bh;
 
-	bh = buffer_pages[MAP_NR(page)];
+	bh = mem_map[MAP_NR(page)].buffers;
 	if (bh) {
 		/* whee.. just mark the buffer heads dirty */
 		struct buffer_head * tmp = bh;
diff -u --recursive --new-file v1.3.73/linux/mm/kmalloc.c linux/mm/kmalloc.c
--- v1.3.73/linux/mm/kmalloc.c	Tue Mar  5 10:11:15 1996
+++ linux/mm/kmalloc.c	Thu Mar 14 08:13:53 1996
@@ -176,7 +176,7 @@
 void *kmalloc(size_t size, int priority)
 {
 	unsigned long flags;
-	unsigned long max_addr, type;
+	unsigned long type;
 	int order, i, sz;
 	struct block_header *p;
 	struct page_descriptor *page, **pg;
@@ -187,11 +187,9 @@
 		return (NULL);
 	}
 
-	max_addr = ~0UL;
 	type = MF_USED;
 	pg = &sizes[order].firstfree;
 	if (priority & GFP_DMA) {
-		max_addr = MAX_DMA_ADDRESS;
 		type = MF_DMA;
 		pg = &sizes[order].dmafree;
 	}
@@ -229,7 +227,7 @@
 	sz = BLOCKSIZE(order);
 
 	page = (struct page_descriptor *) __get_free_pages(priority,
-			sizes[order].gfporder, max_addr);
+			sizes[order].gfporder, priority & GFP_DMA);
 
 	if (!page) {
 		static unsigned long last = 0;
diff -u --recursive --new-file v1.3.73/linux/mm/memory.c linux/mm/memory.c
--- v1.3.73/linux/mm/memory.c	Wed Feb 28 11:50:15 1996
+++ linux/mm/memory.c	Thu Mar 14 16:23:36 1996
@@ -53,15 +53,6 @@
 unsigned long high_memory = 0;
 
 /*
- * The free_area_list arrays point to the queue heads of the free areas
- * of different sizes
- */
-int nr_swap_pages = 0;
-int nr_free_pages = 0;
-struct mem_list free_area_list[NR_MEM_LISTS];
-unsigned int * free_area_map[NR_MEM_LISTS];
-
-/*
  * We special-case the C-O-W ZERO_PAGE, because it's such
  * a common occurrence (no need to read the page to know
  * that it's zero - better for the cache and memory subsystem).
@@ -113,6 +104,7 @@
 
 static inline void free_one_pgd(pgd_t * dir)
 {
+	int j;
 	pmd_t * pmd;
 
 	if (pgd_none(*dir))
@@ -124,11 +116,8 @@
 	}
 	pmd = pmd_offset(dir, 0);
 	pgd_clear(dir);
-	if (!pmd_inuse(pmd)) {
-		int j;
-		for (j = 0; j < PTRS_PER_PMD ; j++)
-			free_one_pmd(pmd+j);
-	}
+	for (j = 0; j < PTRS_PER_PMD ; j++)
+		free_one_pmd(pmd+j);
 	pmd_free(pmd);
 }
 	
@@ -170,7 +159,7 @@
 	invalidate_mm(tsk->mm);
 	SET_PAGE_DIR(tsk, swapper_pg_dir);
 	tsk->mm->pgd = swapper_pg_dir;	/* or else... */
-	for (i = 0 ; i < PTRS_PER_PGD ; i++)
+	for (i = 0 ; i < USER_PTRS_PER_PGD ; i++)
 		free_one_pgd(page_dir + i);
 	pgd_free(page_dir);
 }
@@ -193,6 +182,7 @@
 static inline void copy_one_pte(pte_t * old_pte, pte_t * new_pte, int cow)
 {
 	pte_t pte = *old_pte;
+	unsigned long page_nr;
 
 	if (pte_none(pte))
 		return;
@@ -201,17 +191,18 @@
 		set_pte(new_pte, pte);
 		return;
 	}
-	if (pte_page(pte) > high_memory || mem_map[MAP_NR(pte_page(pte))].reserved) {
+	page_nr = MAP_NR(pte_page(pte));
+	if (page_nr >= MAP_NR(high_memory) || mem_map[page_nr].reserved) {
 		set_pte(new_pte, pte);
 		return;
 	}
 	if (cow)
 		pte = pte_wrprotect(pte);
-	if (delete_from_swap_cache(pte_page(pte)))
+	if (delete_from_swap_cache(page_nr))
 		pte = pte_mkdirty(pte);
 	set_pte(new_pte, pte_mkold(pte));
 	set_pte(old_pte, pte);
-	mem_map[MAP_NR(pte_page(pte))].count++;
+	mem_map[page_nr].count++;
 }
 
 static inline int copy_pte_range(pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long address, unsigned long size, int cow)
diff -u --recursive --new-file v1.3.73/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v1.3.73/linux/mm/page_alloc.c	Fri Jan 26 01:37:08 1996
+++ linux/mm/page_alloc.c	Wed Mar 13 18:55:52 1996
@@ -23,17 +23,47 @@
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
 
-static inline void add_mem_queue(struct mem_list * head, struct mem_list * entry)
+int nr_swap_pages = 0;
+int nr_free_pages = 0;
+
+/*
+ * Free area management
+ *
+ * The free_area_list arrays point to the queue heads of the free areas
+ * of different sizes
+ */
+
+#define NR_MEM_LISTS 6
+
+struct free_area_struct {
+	struct page list;
+	unsigned int *  map;
+};
+
+static struct free_area_struct free_area[NR_MEM_LISTS];
+
+static inline void init_mem_queue(struct page * head)
 {
+	head->next = head;
+	head->prev = head;
+}
+
+static inline void add_mem_queue(struct page * head, struct page * entry)
+{
+	struct page * next = head->next;
+
 	entry->prev = head;
-	(entry->next = head->next)->prev = entry;
+	entry->next = next;
+	next->prev = entry;
 	head->next = entry;
 }
 
-static inline void remove_mem_queue(struct mem_list * head, struct mem_list * entry)
+static inline void remove_mem_queue(struct page * head, struct page * entry)
 {
-	struct mem_list * next = entry->next;
-	(next->prev = entry->prev)->next = next;
+	struct page * next = entry->next;
+	struct page * prev = entry->prev;
+	next->prev = prev;
+	prev->next = next;
 }
 
 /*
@@ -55,30 +85,33 @@
 /*
  * Buddy system. Hairy. You really aren't expected to understand this
  */
-static inline void free_pages_ok(unsigned long addr, unsigned long order)
+static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
 {
-	unsigned long index = MAP_NR(addr) >> (1 + order);
-	unsigned long mask = PAGE_MASK << order;
+	unsigned long index = map_nr >> (1 + order);
+	unsigned long mask = (~0UL) << order;
+
+#define list(x) (mem_map+(x))
 
-	addr &= mask;
+	map_nr &= mask;
 	nr_free_pages += 1 << order;
 	while (order < NR_MEM_LISTS-1) {
-		if (!change_bit(index, free_area_map[order]))
+		if (!change_bit(index, free_area[order].map))
 			break;
-		remove_mem_queue(free_area_list+order, (struct mem_list *) (addr ^ (1+~mask)));
+		remove_mem_queue(&free_area[order].list, list(map_nr ^ (1+~mask)));
+		mask <<= 1;
 		order++;
 		index >>= 1;
-		mask <<= 1;
-		addr &= mask;
+		map_nr &= mask;
 	}
-	add_mem_queue(free_area_list+order, (struct mem_list *) addr);
+	add_mem_queue(&free_area[order].list, list(map_nr));
+#undef list
 }
 
-static inline void check_free_buffers(unsigned long addr)
+static inline void check_free_buffers(mem_map_t * map)
 {
 	struct buffer_head * bh;
 
-	bh = buffer_pages[MAP_NR(addr)];
+	bh = map->buffers;
 	if (bh) {
 		struct buffer_head *tmp = bh;
 		do {
@@ -92,21 +125,23 @@
 
 void free_pages(unsigned long addr, unsigned long order)
 {
-	if (MAP_NR(addr) < MAP_NR(high_memory)) {
-		unsigned long flag;
-		mem_map_t * map = mem_map + MAP_NR(addr);
+	unsigned long map_nr = MAP_NR(addr);
+
+	if (map_nr < MAP_NR(high_memory)) {
+		mem_map_t * map = mem_map + map_nr;
 		if (map->reserved)
 			return;
 		if (map->count) {
+			unsigned long flag;
 			save_flags(flag);
 			cli();
 			if (!--map->count) {
-				free_pages_ok(addr, order);
-				delete_from_swap_cache(addr);
+				free_pages_ok(map_nr, order);
+				delete_from_swap_cache(map_nr);
 			}
 			restore_flags(flag);
 			if (map->count == 1)
-				check_free_buffers(addr);
+				check_free_buffers(map);
 			return;
 		}
 		printk("Trying to free free memory (%08lx): memory probably corrupted\n",addr);
@@ -118,43 +153,44 @@
 /*
  * Some ugly macros to speed up __get_free_pages()..
  */
-#define RMQUEUE(order, limit) \
-do { struct mem_list * queue = free_area_list+order; \
+#define MARK_USED(index, order, area) \
+	change_bit((index) >> (1+(order)), (area)->map)
+#define CAN_DMA(x) ((x)->dma)
+#define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT))
+#define RMQUEUE(order, dma) \
+do { struct free_area_struct * area = free_area+order; \
      unsigned long new_order = order; \
-	do { struct mem_list *prev = queue, *ret; \
-		while (queue != (ret = prev->next)) { \
-			if ((unsigned long) ret < (limit)) { \
+	do { struct page *prev = &area->list, *ret; \
+		while (&area->list != (ret = prev->next)) { \
+			if (!dma || CAN_DMA(ret)) { \
+				unsigned long map_nr = ret - mem_map; \
 				(prev->next = ret->next)->prev = prev; \
-				mark_used((unsigned long) ret, new_order); \
+				MARK_USED(map_nr, new_order, area); \
 				nr_free_pages -= 1 << order; \
+				EXPAND(ret, map_nr, order, new_order, area); \
 				restore_flags(flags); \
-				EXPAND(ret, order, new_order); \
-				return (unsigned long) ret; \
+				return ADDRESS(map_nr); \
 			} \
 			prev = ret; \
 		} \
-		new_order++; queue++; \
+		new_order++; area++; \
 	} while (new_order < NR_MEM_LISTS); \
 } while (0)
 
-static inline int mark_used(unsigned long addr, unsigned long order)
-{
-	return change_bit(MAP_NR(addr) >> (1+order), free_area_map[order]);
-}
-
-#define EXPAND(addr,low,high) \
-do { unsigned long size = PAGE_SIZE << high; \
+#define EXPAND(map,index,low,high,area) \
+do { unsigned long size = 1 << high; \
 	while (high > low) { \
-		high--; size >>= 1; cli(); \
-		add_mem_queue(free_area_list+high, addr); \
-		mark_used((unsigned long) addr, high); \
-		restore_flags(flags); \
-		addr = (struct mem_list *) (size + (unsigned long) addr); \
-	} mem_map[MAP_NR((unsigned long) addr)].count = 1; \
-	mem_map[MAP_NR((unsigned long) addr)].age = PAGE_INITIAL_AGE; \
+		area--; high--; size >>= 1; \
+		add_mem_queue(&area->list, map); \
+		MARK_USED(index, high, area); \
+		index += size; \
+		map += size; \
+	} \
+	map->count = 1; \
+	map->age = PAGE_INITIAL_AGE; \
 } while (0)
 
-unsigned long __get_free_pages(int priority, unsigned long order, unsigned long limit)
+unsigned long __get_free_pages(int priority, unsigned long order, int dma)
 {
 	unsigned long flags;
 	int reserved_pages;
@@ -176,12 +212,12 @@
 repeat:
 	cli();
 	if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
-		RMQUEUE(order, limit);
+		RMQUEUE(order, dma);
 		restore_flags(flags);
 		return 0;
 	}
 	restore_flags(flags);
-	if (priority != GFP_BUFFER && try_to_free_page(priority, limit, 1))
+	if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1))
 		goto repeat;
 	return 0;
 }
@@ -200,9 +236,9 @@
 	save_flags(flags);
 	cli();
  	for (order=0 ; order < NR_MEM_LISTS; order++) {
-		struct mem_list * tmp;
+		struct page * tmp;
 		unsigned long nr = 0;
-		for (tmp = free_area_list[order].next ; tmp != free_area_list + order ; tmp = tmp->next) {
+		for (tmp = free_area[order].list.next ; tmp != &free_area[order].list ; tmp = tmp->next) {
 			nr ++;
 		}
 		total += nr * ((PAGE_SIZE>>10) << order);
@@ -246,18 +282,19 @@
 	memset(mem_map, 0, start_mem - (unsigned long) mem_map);
 	do {
 		--p;
+		p->dma = 1;
 		p->reserved = 1;
 	} while (p > mem_map);
 
 	for (i = 0 ; i < NR_MEM_LISTS ; i++) {
 		unsigned long bitmap_size;
-		free_area_list[i].prev = free_area_list[i].next = &free_area_list[i];
+		init_mem_queue(&free_area[i].list);
 		mask += mask;
 		end_mem = (end_mem + ~mask) & mask;
 		bitmap_size = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT + i);
 		bitmap_size = (bitmap_size + 7) >> 3;
 		bitmap_size = LONG_ALIGN(bitmap_size);
-		free_area_map[i] = (unsigned int *) start_mem;
+		free_area[i].map = (unsigned int *) start_mem;
 		memset((void *) start_mem, 0, bitmap_size);
 		start_mem += bitmap_size;
 	}
@@ -293,7 +330,7 @@
 	}
 	vma->vm_mm->rss++;
 	tsk->maj_flt++;
-	if (!write_access && add_to_swap_cache(page, entry)) {
+	if (!write_access && add_to_swap_cache(MAP_NR(page), entry)) {
 		set_pte(page_table, mk_pte(page, vma->vm_page_prot));
 		return;
 	}
diff -u --recursive --new-file v1.3.73/linux/mm/swap_state.c linux/mm/swap_state.c
--- v1.3.73/linux/mm/swap_state.c	Sun Jan 14 16:30:16 1996
+++ linux/mm/swap_state.c	Wed Mar 13 15:17:23 1996
@@ -49,7 +49,7 @@
 }
 #endif
 
-int add_to_swap_cache(unsigned long addr, unsigned long entry)
+int add_to_swap_cache(unsigned long index, unsigned long entry)
 {
 	struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
 
@@ -57,7 +57,7 @@
 	swap_cache_add_total++;
 #endif
 	if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
-		entry = xchg(swap_cache + MAP_NR(addr), entry);
+		entry = xchg(swap_cache + index, entry);
 		if (entry)  {
 			printk("swap_cache: replacing non-NULL entry\n");
 		}
diff -u --recursive --new-file v1.3.73/linux/mm/swapfile.c linux/mm/swapfile.c
--- v1.3.73/linux/mm/swapfile.c	Wed Feb  7 15:11:40 1996
+++ linux/mm/swapfile.c	Thu Mar 14 16:26:49 1996
@@ -168,14 +168,14 @@
 	if (pte_none(pte))
 		return 0;
 	if (pte_present(pte)) {
-		unsigned long page = pte_page(pte);
-		if (page >= high_memory)
+		unsigned long page_nr = MAP_NR(pte_page(pte));
+		if (page_nr >= MAP_NR(high_memory))
 			return 0;
-		if (!in_swap_cache(page))
+		if (!in_swap_cache(page_nr))
 			return 0;
-		if (SWP_TYPE(in_swap_cache(page)) != type)
+		if (SWP_TYPE(in_swap_cache(page_nr)) != type)
 			return 0;
-		delete_from_swap_cache(page);
+		delete_from_swap_cache(page_nr);
 		set_pte(dir, pte_mkdirty(pte));
 		return 0;
 	}
@@ -263,18 +263,18 @@
 	return 0;
 }
 
-static int unuse_process(struct task_struct * p, unsigned int type, unsigned long page)
+static int unuse_process(struct mm_struct * mm, unsigned int type, unsigned long page)
 {
 	struct vm_area_struct* vma;
 
 	/*
 	 * Go through process' page directory.
 	 */
-	if (!p->mm || pgd_inuse(p->mm->pgd))
+	if (!mm)
 		return 0;
-	vma = p->mm->mmap;
+	vma = mm->mmap;
 	while (vma) {
-		pgd_t * pgd = pgd_offset(p->mm, vma->vm_start);
+		pgd_t * pgd = pgd_offset(mm, vma->vm_start);
 		if (unuse_vma(vma, pgd, vma->vm_start, vma->vm_end, type, page))
 			return 1;
 		vma = vma->vm_next;
@@ -296,8 +296,9 @@
 		return -ENOMEM;
 	nr = 0;
 	while (nr < NR_TASKS) {
-		if (task[nr]) {
-			if (unuse_process(task[nr], type, page)) {
+		struct task_struct * p = task[nr];
+		if (p) {
+			if (unuse_process(p->mm, type, page)) {
 				page = get_free_page(GFP_KERNEL);
 				if (!page)
 					return -ENOMEM;
diff -u --recursive --new-file v1.3.73/linux/mm/vmscan.c linux/mm/vmscan.c
--- v1.3.73/linux/mm/vmscan.c	Wed Feb 28 11:50:15 1996
+++ linux/mm/vmscan.c	Wed Mar 13 15:15:22 1996
@@ -68,7 +68,7 @@
  * have died while we slept).
  */
 static inline int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
-	unsigned long address, pte_t * page_table, unsigned long limit, int wait)
+	unsigned long address, pte_t * page_table, int dma, int wait)
 {
 	pte_t pte;
 	unsigned long entry;
@@ -81,16 +81,15 @@
 	page = pte_page(pte);
 	if (MAP_NR(page) >= MAP_NR(high_memory))
 		return 0;
-	if (page >= limit)
-		return 0;
 
 	page_map = mem_map + MAP_NR(page);
-	if (page_map->reserved || page_map->locked)
+	if (page_map->reserved || page_map->locked ||
+	    (dma && !page_map->dma))
 		return 0;
 	/* Deal with page aging.  Pages age from being unused; they
 	 * rejuvinate on being accessed.  Only swap old pages (age==0
 	 * is oldest). */
-	if ((pte_dirty(pte) && delete_from_swap_cache(page)) 
+	if ((pte_dirty(pte) && delete_from_swap_cache(MAP_NR(page))) 
 	    || pte_young(pte))  {
 		set_pte(page_table, pte_mkold(pte));
 		touch_page(page_map);
@@ -119,7 +118,7 @@
 		free_page(page);
 		return 1;	/* we slept: the process may not exist any more */
 	}
-        if ((entry = find_in_swap_cache(page)))  {
+        if ((entry = find_in_swap_cache(MAP_NR(page))))  {
 		if (page_map->count != 1) {
 			set_pte(page_table, pte_mkdirty(pte));
 			printk("Aiee.. duplicated cached swap-cache entry\n");
@@ -154,7 +153,7 @@
  */
 
 static inline int swap_out_pmd(struct task_struct * tsk, struct vm_area_struct * vma,
-	pmd_t *dir, unsigned long address, unsigned long end, unsigned long limit, int wait)
+	pmd_t *dir, unsigned long address, unsigned long end, int dma, int wait)
 {
 	pte_t * pte;
 	unsigned long pmd_end;
@@ -176,7 +175,7 @@
 	do {
 		int result;
 		tsk->swap_address = address + PAGE_SIZE;
-		result = try_to_swap_out(tsk, vma, address, pte, limit, wait);
+		result = try_to_swap_out(tsk, vma, address, pte, dma, wait);
 		if (result)
 			return result;
 		address += PAGE_SIZE;
@@ -186,7 +185,7 @@
 }
 
 static inline int swap_out_pgd(struct task_struct * tsk, struct vm_area_struct * vma,
-	pgd_t *dir, unsigned long address, unsigned long end, unsigned long limit, int wait)
+	pgd_t *dir, unsigned long address, unsigned long end, int dma, int wait)
 {
 	pmd_t * pmd;
 	unsigned long pgd_end;
@@ -206,7 +205,7 @@
 		end = pgd_end;
 	
 	do {
-		int result = swap_out_pmd(tsk, vma, pmd, address, end, limit, wait);
+		int result = swap_out_pmd(tsk, vma, pmd, address, end, dma, wait);
 		if (result)
 			return result;
 		address = (address + PMD_SIZE) & PMD_MASK;
@@ -216,7 +215,7 @@
 }
 
 static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma,
-	pgd_t *pgdir, unsigned long start, unsigned long limit, int wait)
+	pgd_t *pgdir, unsigned long start, int dma, int wait)
 {
 	unsigned long end;
 
@@ -227,7 +226,7 @@
 
 	end = vma->vm_end;
 	while (start < end) {
-		int result = swap_out_pgd(tsk, vma, pgdir, start, end, limit, wait);
+		int result = swap_out_pgd(tsk, vma, pgdir, start, end, dma, wait);
 		if (result)
 			return result;
 		start = (start + PGDIR_SIZE) & PGDIR_MASK;
@@ -236,7 +235,7 @@
 	return 0;
 }
 
-static int swap_out_process(struct task_struct * p, unsigned long limit, int wait)
+static int swap_out_process(struct task_struct * p, int dma, int wait)
 {
 	unsigned long address;
 	struct vm_area_struct* vma;
@@ -257,7 +256,7 @@
 		address = vma->vm_start;
 
 	for (;;) {
-		int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, limit, wait);
+		int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, dma, wait);
 		if (result)
 			return result;
 		vma = vma->vm_next;
@@ -269,7 +268,7 @@
 	return 0;
 }
 
-static int swap_out(unsigned int priority, unsigned long limit, int wait)
+static int swap_out(unsigned int priority, int dma, int wait)
 {
 	static int swap_task;
 	int loop, counter;
@@ -308,7 +307,7 @@
 		}
 		if (!--p->swap_cnt)
 			swap_task++;
-		switch (swap_out_process(p, limit, wait)) {
+		switch (swap_out_process(p, dma, wait)) {
 			case 0:
 				if (p->swap_cnt)
 					swap_task++;
@@ -327,7 +326,7 @@
  * to be.  This works out OK, because we now do proper aging on page
  * contents. 
  */
-int try_to_free_page(int priority, unsigned long limit, int wait)
+int try_to_free_page(int priority, int dma, int wait)
 {
 	static int state = 0;
 	int i=6;
@@ -335,15 +334,15 @@
 	switch (state) {
 		do {
 		case 0:
-			if (shrink_mmap(i, limit))
+			if (shrink_mmap(i, dma))
 				return 1;
 			state = 1;
 		case 1:
-			if (shm_swap(i, limit))
+			if (shm_swap(i, dma))
 				return 1;
 			state = 2;
 		default:
-			if (swap_out(i, limit, wait))
+			if (swap_out(i, dma, wait))
 				return 1;
 			state = 0;
 		} while (i--);
@@ -400,7 +399,7 @@
 		swapstats.wakeups++;
 		/* Do the background pageout: */
 		for (i=0; i < kswapd_ctl.maxpages; i++)
-			try_to_free_page(GFP_KERNEL, ~0UL, 0);
+			try_to_free_page(GFP_KERNEL, 0, 0);
 	}
 }
 
diff -u --recursive --new-file v1.3.73/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v1.3.73/linux/net/unix/af_unix.c	Wed Mar 13 10:09:27 1996
+++ linux/net/unix/af_unix.c	Thu Mar 14 14:05:36 1996
@@ -170,6 +170,7 @@
 static void unix_destroy_socket(unix_socket *sk)
 {
 	struct sk_buff *skb;
+
 	unix_remove_socket(sk);
 	
 	while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
@@ -184,7 +185,7 @@
 		}
 		else
 		{
-/*			unix_kill_credentials(skb);	*//* Throw out any passed fd's */
+			/* passed fds are erased where?? */
 			kfree_skb(skb,FREE_WRITE);
 		}
 	}
@@ -782,7 +783,7 @@
  *	but how the old code did it - or like this...
  */
 
-int unix_files_free(void)
+static int unix_files_free(void)
 {
 	int i;
 	int n=0;
@@ -808,13 +809,16 @@
 static void unix_detach_fds(struct sk_buff *skb, struct cmsghdr *cmsg)
 {
 	int i;
+	/* count of space in parent for fds */
 	int cmnum;
 	struct file **fp;
 	struct file **ufp;
 	int *cmfptr=NULL;	/* =NULL To keep gcc happy */
+	/* number of fds actually passed */
 	int fdnum;
 	int ffree;
 	int ufn=0;
+
 	if(cmsg==NULL)
 		cmnum=0;
 	else
@@ -858,7 +862,9 @@
 	}
 	kfree(skb->h.filp);
 	skb->h.filp=NULL;
-	
+
+	/* no need to use destructor */
+	skb->destructor = NULL;
 }
 
 static void unix_destruct_fds(struct sk_buff *skb)
@@ -869,14 +875,16 @@
 /*
  *	Attach the file descriptor array to an sk_buff
  */
- 
 static void unix_attach_fds(int fpnum,struct file **fp,struct sk_buff *skb)
 {
+
 	skb->h.filp=kmalloc(sizeof(int)+fpnum*sizeof(struct file *), 
 							GFP_KERNEL);
+	/* number of descriptors starts block */
 	memcpy(skb->h.filp,&fpnum,sizeof(int));
+	/* actual  descriptors */
 	memcpy(skb->h.filp+sizeof(int),fp,fpnum*sizeof(struct file *));
-	skb->destructor=unix_destruct_fds;
+	skb->destructor = unix_destruct_fds;
 }
 
 /*
@@ -893,8 +901,10 @@
 	int limit=0;
 	int sent=0;
 	struct file *fp[UNIX_MAX_FD];
+	/* number of fds waiting to be passed, 0 means either
+	 * no fds to pass or they've already been passed 
+	 */
 	int fpnum=0;
-	int fp_attached=0;
 
 	if(sk->err)
 		return sock_error(sk);
@@ -935,18 +945,12 @@
 		   cm->cmsg_level!=SOL_SOCKET ||
 		   msg->msg_accrightslen!=cm->cmsg_len)
 		{
-#if 0
-			printk("Sendmsg: bad access rights\n");
-#endif
 			kfree(cm);
 		   	return -EINVAL;
 		}
 		fpnum=unix_fd_copy(sk,cm,fp);
 		kfree(cm);
 		if(fpnum<0) {
-#if 0
-			printk("Sendmsg error = %d\n", fpnum);
-#endif
 			return fpnum;
 		}
 	}
@@ -1001,14 +1005,14 @@
 		skb->sk=sk;
 		skb->free=1;
 		
-		if(fpnum && !fp_attached)
+		if(fpnum)
 		{
-			fp_attached=1;
 			unix_attach_fds(fpnum,fp,skb);
 			fpnum=0;
 		}
 		else
 			skb->h.filp=NULL;
+
 		memcpy_fromiovec(skb_put(skb,size),msg->msg_iov, size);
 
 		cli();
@@ -1090,7 +1094,6 @@
 
 	if(msg->msg_accrights) 
 	{
-		printk("recvmsg with accrights\n");
 		cm=unix_copyrights(msg->msg_accrights, 
 			msg->msg_accrightslen);
 		if(msg->msg_accrightslen<sizeof(struct cmsghdr)
diff -u --recursive --new-file v1.3.73/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v1.3.73/linux/scripts/Menuconfig	Sun Mar 10 09:49:57 1996
+++ linux/scripts/Menuconfig	Wed Mar 13 08:38:53 1996
@@ -843,11 +843,11 @@
 
 menu_instructions="\
 Arrow keys navigate the menu.  \
-Highlighted letters are hotkeys. \
-Select an item with <Space Bar> or <Enter>. \
+Highlighted letters are hotkeys.  \
+Select an item with <Space Bar> or <Enter>.  \
 When finished press <Esc><Esc> or <X>.  \
-(*) indicates an option will be compiled into the kernel.  \
-(M) indicates an option will be compiled as a module."
+A (*) marks an option to be compiled into the kernel.  \
+An (M) marks an option to be compiled as a module."
 
 radiolist_instructions="\
 Use the arrow keys to navigate this window or \
@@ -970,7 +970,7 @@
 EOM
 else
 	clear
-	echo -e "Your kernel configuration changes where NOT saved.\n"
+	echo -e "Your kernel configuration changes were NOT saved.\n"
 fi
 
 
diff -u --recursive --new-file v1.3.73/linux/scripts/header.tk linux/scripts/header.tk
--- v1.3.73/linux/scripts/header.tk	Wed Mar 13 10:09:27 1996
+++ linux/scripts/header.tk	Thu Mar 14 14:20:23 1996
@@ -381,7 +381,7 @@
 			/^$varname\[ 	\]*\$/ {
 				start=1;
 				printf(\"%s:\\n\\n\",\$0);
-				continue;
+				next;
 			}
 			!/^\[ 	\]/ {
 				start=0;
diff -u --recursive --new-file v1.3.73/linux/scripts/lxdialog/util.c linux/scripts/lxdialog/util.c
--- v1.3.73/linux/scripts/lxdialog/util.c	Wed Feb  7 15:11:46 1996
+++ linux/scripts/lxdialog/util.c	Wed Mar 13 08:38:53 1996
@@ -190,16 +190,16 @@
 
 /*
  * Print a string of text in a window, automatically wrap around to the
- * next line if the string is too long to fit on one line. Note that the
- * string may contain "\n" to represent a newline character or the real
- * newline '\n', but in that case, auto wrap around will be disabled.
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are replaced by spaces.  We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
  */
 void
 print_autowrap (WINDOW * win, const char *prompt, int width, int y, int x)
 {
-    int first = 1, cur_x, cur_y;
-    int i, prompt_len;
-    char tempstr[MAX_LEN + 1], *word /*,  *tempptr, *tempptr1*/;
+    int newl, cur_x, cur_y;
+    int i, prompt_len, room, wlen;
+    char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
 
     strcpy (tempstr, prompt);
 
@@ -212,24 +212,41 @@
 	if(tempstr[i] == '\n') tempstr[i] = ' ';
     }
 
-    if (strlen (tempstr) <= width - x * 2) {	/* If prompt is short */
-	wmove (win, y, (width - strlen (tempstr)) / 2);
+    if (prompt_len <= width - x * 2) {	/* If prompt is short */
+	wmove (win, y, (width - prompt_len) / 2);
 	waddstr (win, tempstr);
     } else {
 	cur_x = x;
 	cur_y = y;
-	/* Print prompt word by word, wrap around if necessary */
-	while ((word = strtok (first ? tempstr : NULL, " ")) != NULL) {
-	    if (first)		/* First iteration */
-		first = 0;
-	    if (cur_x + strlen (word) > width) {
-		cur_y++;	/* wrap to next line */
+	newl = 1;
+	word = tempstr;
+	while (word && *word) {
+	    sp = index(word, ' ');
+	    if (sp)
+	        *sp++ = 0;
+
+	    /* Wrap to next line if either the word does not fit,
+	       or it is the first word of a new sentence, and it is
+	       short, and the next word does not fit. */
+	    room = width - cur_x;
+	    wlen = strlen(word);
+	    if (wlen > room ||
+	       (newl && wlen < 4 && sp && wlen+1+strlen(sp) > room
+		     && (!(sp2 = index(sp, ' ')) || wlen+1+(sp2-sp) > room))) {
+		cur_y++;
 		cur_x = x;
 	    }
 	    wmove (win, cur_y, cur_x);
 	    waddstr (win, word);
 	    getyx (win, cur_y, cur_x);
 	    cur_x++;
+	    if (sp && *sp == ' ') {
+	        cur_x++;	/* double space */
+		while (*++sp == ' ');
+		newl = 1;
+	    } else
+	        newl = 0;
+	    word = sp;
 	}
     }
 }
