diff -u --recursive --new-file v1.3.8/linux/CREDITS linux/CREDITS
--- v1.3.8/linux/CREDITS	Fri Jul  7 13:42:57 1995
+++ linux/CREDITS	Mon Jul 10 17:08:04 1995
@@ -164,6 +164,13 @@
 S: Bellevue, Washington 98007
 S: USA
 
+N: Hamish Coleman
+E: hamish@zot.apana.org.au
+D: SEEQ8005 network driver
+S: 98 Paxton Street
+S: East Malvern, Victoria, 3145
+S: Australia
+
 N: Alan Cox
 E: A.Cox@swansea.ac.uk
 E: iiitac@pyr.swan.ac.uk
@@ -235,7 +242,7 @@
 
 N: Paal-Kristian Engstad
 E: engstad@funcom.com
-D: Wrote smbfs (to mount WfW, NT and OS/2 network drives.)
+D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.)
 S: Oscars gt. 35
 S: N-0258 OSLO
 S: Norway
@@ -473,6 +480,13 @@
 S: Mr. v. Boemellaan 39
 S: NL-5237 KA 's-Hertogenbosch
 S: The Netherlands
+
+N: Volker Lendecke
+E: lendecke@namu01.gwdg.de
+D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.)
+S: Innersteweg 11
+S: 37081 Goettingen
+S: Germany
 
 N: Kevin Lentin
 E: kevinl@cs.monash.edu.au
diff -u --recursive --new-file v1.3.8/linux/Makefile linux/Makefile
--- v1.3.8/linux/Makefile	Fri Jul  7 13:42:57 1995
+++ linux/Makefile	Tue Jul 11 08:02:20 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 8
+SUBLEVEL = 9
 
 ARCH = i386
 
@@ -106,8 +106,6 @@
 
 include arch/$(ARCH)/Makefile
 
-.c.s:
-	$(CC) $(CFLAGS) -S -o $*.s $<
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
diff -u --recursive --new-file v1.3.8/linux/Rules.make linux/Rules.make
--- v1.3.8/linux/Rules.make	Thu Jan  1 02:00:00 1970
+++ linux/Rules.make	Tue Jul 11 08:02:20 1995
@@ -0,0 +1,21 @@
+#
+# This file contains rules which are shared between multiple Makefiles.
+#
+
+#
+# Common rules
+#
+.c.s:
+	$(CC) $(CFLAGS) -S $<
+
+#
+# A rule to do nothing
+#
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff -u --recursive --new-file v1.3.8/linux/arch/alpha/boot/Makefile linux/arch/alpha/boot/Makefile
--- v1.3.8/linux/arch/alpha/boot/Makefile	Wed Jan 18 22:52:36 1995
+++ linux/arch/alpha/boot/Makefile	Tue Jul 11 08:02:20 1995
@@ -8,8 +8,6 @@
 # Copyright (C) 1994 by Linus Torvalds
 #
 
-.c.s:
-	$(CC) $(CFLAGS) -S -o $*.s $<
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
diff -u --recursive --new-file v1.3.8/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v1.3.8/linux/arch/alpha/kernel/Makefile	Thu Jun  1 13:22:05 1995
+++ linux/arch/alpha/kernel/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
@@ -35,13 +33,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
-
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v1.3.8/linux/arch/alpha/kernel/entry.S	Tue Jun 27 14:11:30 1995
+++ linux/arch/alpha/kernel/entry.S	Tue Jul 11 08:14:54 1995
@@ -369,6 +369,8 @@
 	jsr $26,($27),alpha_fork
 	br $0,undo_switch_stack
 	ldq $0,0($30)
+	bis $31,2,$19	/* Make sure that the stored user register v0 has */
+	stq $19,0($30)	/* the syscall # for fork */
 	ret $31,($26),1
 .end	sys_fork
 
@@ -406,8 +408,16 @@
 	beq	$1,1f
 	ldq	$27,0($2)
 1:	jsr	$26,($27),do_entSys
+	ldq	$1,0($30)	/* We have to handle ptrace specially */
+	subq	$1,26,$1	/* since it returns a pointer value it will*/
+	bne	$1,3f		/* set up a3 and v0 in the return frame */
+	ldq	$1,72($30)
+	stq	$1,0($30)
+	stq	$0,72($30)
 	bis	$31,$31,$1
-	bge	$0,2f
+	br	$31,ret_from_sys_call
+3:	bis	$31,$31,$1
+	bge	$0,2f		/* the call succeeded */
 	bis	$31,$31,$26	/* tell "ret_from_sys_call" that we can restart */
 	ldq	$19,0($30)	/* .. with this syscall nr */
 	ldq	$20,72($30)	/* .. and this a3 */
diff -u --recursive --new-file v1.3.8/linux/arch/alpha/kernel/ptrace.c linux/arch/alpha/kernel/ptrace.c
--- v1.3.8/linux/arch/alpha/kernel/ptrace.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/alpha/kernel/ptrace.c	Tue Jul 11 08:13:58 1995
@@ -0,0 +1,647 @@
+/* ptrace.c */
+/* By Ross Biro 1/23/92 */
+/* edited by Linus Torvalds */
+/* mangled further by Bob Manson (manson@santafe.edu) */
+
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/debugreg.h>
+
+#include <asm/segment.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+/* This was determined via brute force. */
+#define MAGICNUM 496
+
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which flags the user has access to. */
+/* 1 = access 0 = no access */
+#define FLAG_MASK 0x00044dd5
+
+/* set's the trap flag. */
+#define TRAP_FLAG 0x100
+
+/*
+ * this is the number to subtract from the top of the stack. To find
+ * the local frame.
+ */
+
+/* A mapping between register number and its offset on the kernel stack.
+ * You also need to add MAGICNUM to get past the kernel stack frame
+ * to the actual saved user info.
+ * The first portion is the switch_stack, then comes the pt_regs.
+ * 320 is the size of the switch_stack area.
+ */
+
+static int map_reg_to_offset[] = {
+   320+0,320+8,320+16,320+24,320+32,320+40,320+48,320+56,320+64, /* 0-8 */
+   0,8,16,24,32,40,48, /* 9-15 */
+   320+184,320+192,320+200, /* 16-18 */
+   320+72,320+80,320+88,320+96,320+104,320+112,320+120, /* 19-25 */
+   320+128,320+136,320+144,320+176,320+160,-1, /* 26-31*/
+
+   /* fp registers below */
+   64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192,
+   200,208,216,224,232,240,248,256,264,272,280,288,296,304,312,
+
+   /* 64 = pc */
+   320+168
+};
+
+static int offset_of_register(int reg_num) {
+   if(reg_num<0 || reg_num>64) {
+      return -1;
+   }
+   return map_reg_to_offset[reg_num];
+}
+
+static void unset_singlestep(struct task_struct *child) {
+}
+
+static void set_singlestep(struct task_struct *child) {
+}
+
+/* change a pid into a task struct. */
+static inline struct task_struct * get_task(int pid)
+{
+	int i;
+
+	for (i = 1; i < NR_TASKS; i++) {
+		if (task[i] != NULL && (task[i]->pid == pid))
+			return task[i];
+	}
+	return NULL;
+}
+
+/*
+ * this routine will get a word off of the processes privileged stack. 
+ * the offset is how far from the base addr as stored in the TSS.  
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ * MAGICNUM is the amount to skip to get to the actual user regs. It
+ * was determined by brute force & asking BufElves.
+ */   
+static inline long get_stack_long(struct task_struct *task, unsigned long offset)
+{
+	unsigned char *stack;
+
+	stack = (unsigned char *)task->tss.ksp;
+	stack += offset+MAGICNUM;
+	return (*((long *)stack));
+}
+
+/*
+ * this routine will put a word on the processes privileged stack. 
+ * the offset is how far from the base addr as stored in the TSS.  
+ * this routine assumes that all the privileged stacks are in our
+ * data space.
+ */
+static inline int put_stack_long(struct task_struct *task, unsigned long offset,
+	unsigned long data)
+{
+	unsigned char * stack;
+
+	stack = (unsigned char *) task->tss.ksp;
+	stack += offset+MAGICNUM;
+	*(unsigned long *) stack = data;
+	return 0;
+}
+
+/*
+ * This routine gets a long from any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ */
+static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
+{
+	pgd_t * pgdir;
+	pmd_t * pgmiddle;
+	pte_t * pgtable;
+	unsigned long page;
+
+#ifdef DEBUG
+	printk("Getting long at 0x%lx\n",addr);
+#endif
+repeat:
+	pgdir = pgd_offset(vma->vm_task, addr);
+	if (pgd_none(*pgdir)) {
+		do_no_page(vma, addr, 0);
+		goto repeat;
+	}
+	if (pgd_bad(*pgdir)) {
+		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+		pgd_clear(pgdir);
+		return 0;
+	}
+	pgmiddle = pmd_offset(pgdir, addr);
+	if (pmd_none(*pgmiddle)) {
+		do_no_page(vma, addr, 0);
+		goto repeat;
+	}
+	if (pmd_bad(*pgmiddle)) {
+		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
+		pmd_clear(pgmiddle);
+		return 0;
+	}
+	pgtable = pte_offset(pgmiddle, addr);
+	if (!pte_present(*pgtable)) {
+		do_no_page(vma, addr, 0);
+		goto repeat;
+	}
+	page = pte_page(*pgtable);
+/* this is a hack for non-kernel-mapped video buffers and similar */
+	if (page >= high_memory)
+		return 0;
+	page += addr & ~PAGE_MASK;
+	return *(unsigned long *) page;
+}
+
+/*
+ * This routine puts a long into any process space by following the page
+ * tables. NOTE! You should check that the long isn't on a page boundary,
+ * and that it is in the task area before calling this: this routine does
+ * no checking.
+ *
+ * Now keeps R/W state of page so that a text page stays readonly
+ * even if a debugger scribbles breakpoints into it.  -M.U-
+ */
+static void put_long(struct vm_area_struct * vma, unsigned long addr,
+	unsigned long data)
+{
+	pgd_t *pgdir;
+	pmd_t *pgmiddle;
+	pte_t *pgtable;
+	unsigned long page;
+
+repeat:
+	pgdir = pgd_offset(vma->vm_task, addr);
+	if (!pgd_present(*pgdir)) {
+		do_no_page(vma, addr, 1);
+		goto repeat;
+	}
+	if (pgd_bad(*pgdir)) {
+		printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+		pgd_clear(pgdir);
+		return;
+	}
+	pgmiddle = pmd_offset(pgdir, addr);
+	if (pmd_none(*pgmiddle)) {
+		do_no_page(vma, addr, 1);
+		goto repeat;
+	}
+	if (pmd_bad(*pgmiddle)) {
+		printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
+		pmd_clear(pgmiddle);
+		return;
+	}
+	pgtable = pte_offset(pgmiddle, addr);
+	if (!pte_present(*pgtable)) {
+		do_no_page(vma, addr, 1);
+		goto repeat;
+	}
+	page = pte_page(*pgtable);
+	if (!pte_write(*pgtable)) {
+		do_wp_page(vma, addr, 1);
+		goto repeat;
+	}
+/* this is a hack for non-kernel-mapped video buffers and similar */
+	if (page < high_memory) {
+		page += addr & ~PAGE_MASK;
+		*(unsigned long *) page = data;
+	}
+/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
+/* this should also re-instate whatever read-only mode there was before */
+	*pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
+	invalidate();
+}
+
+static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
+{
+	struct vm_area_struct * vma;
+
+	addr &= PAGE_MASK;
+	vma = find_vma(tsk,addr);
+	if (!vma)
+		return NULL;
+	if (vma->vm_start <= addr)
+		return vma;
+	if (!(vma->vm_flags & VM_GROWSDOWN))
+		return NULL;
+	if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
+		return NULL;
+	vma->vm_offset -= vma->vm_start - addr;
+	vma->vm_start = addr;
+	return vma;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls get_long() to read a long.
+ */
+static int read_long(struct task_struct * tsk, unsigned long addr,
+	unsigned long * result)
+{
+	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+#ifdef DEBUG
+	printk("in read_long\n");
+#endif
+	if (!vma) {
+	        printk("Unable to find vma for addr 0x%lx\n",addr);
+		return -EIO;
+	}
+	if ((addr & ~PAGE_MASK) > (PAGE_SIZE-sizeof(long))) {
+		unsigned long low,high;
+		struct vm_area_struct * vma_high = vma;
+
+		if (addr + sizeof(long) >= vma->vm_end) {
+			vma_high = vma->vm_next;
+			if (!vma_high || vma_high->vm_start != vma->vm_end)
+				return -EIO;
+		}
+		low = get_long(vma, addr & ~(sizeof(long)-1));
+		high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
+		switch (addr & (sizeof(long)-1)) {
+			case 1:
+				low >>= 8;
+				low |= high << 56;
+				break;
+			case 2:
+				low >>= 16;
+				low |= high << 48;
+				break;
+			case 3:
+				low >>= 24;
+				low |= high << 40;
+				break;
+			case 4:
+				low >>= 32;
+				low |= high << 32;
+				break;
+			case 5:
+				low >>= 40;
+				low |= high << 24;
+				break;
+			case 6:
+				low >>= 48;
+				low |= high << 16;
+				break;
+			case 7:
+				low >>= 56;
+				low |= high << 8;
+				break;
+		}
+		*result = low;
+	} else {
+	        long l =get_long(vma, addr);
+
+#ifdef DEBUG
+		printk("value is 0x%lx\n",l);
+#endif
+		*result = l;
+	}
+	return 0;
+}
+
+/*
+ * This routine checks the page boundaries, and that the offset is
+ * within the task area. It then calls put_long() to write a long.
+ */
+static int write_long(struct task_struct * tsk, unsigned long addr,
+	unsigned long data)
+{
+	struct vm_area_struct * vma = find_extend_vma(tsk, addr);
+
+	if (!vma)
+		return -EIO;
+	if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
+		unsigned long low,high;
+		struct vm_area_struct * vma_high = vma;
+
+		if (addr + sizeof(long) >= vma->vm_end) {
+			vma_high = vma->vm_next;
+			if (!vma_high || vma_high->vm_start != vma->vm_end)
+				return -EIO;
+		}
+		low = get_long(vma, addr & ~(sizeof(long)-1));
+		high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
+		switch (addr & (sizeof(long)-1)) {
+			case 0: /* shouldn't happen, but safety first */
+				low = data;
+				break;
+			case 1:
+				low &= 0x00000000000000ffL;
+				low |= data << 8;
+				high &= ~0x000000000000ffL;
+				high |= data >> 56;
+				break;
+			case 2:
+				low &= 0x000000000000ffffL;
+				low |= data << 16;
+				high &= ~0x0000000000ffffL;
+				high |= data >> 48;
+				break;
+			case 3:
+				low &= 0x0000000000ffffffL;
+				low |= data << 24;
+				high &= ~0x00000000ffffffL;
+				high |= data >> 40;
+				break;
+		        case 4:
+				low &= 0x00000000ffffffffL;
+				low |= data << 32;
+				high &= ~0x000000ffffffffL;
+				high |= data >> 32;
+				break;
+
+			case 5:
+				low &= 0x000000ffffffffffL;
+				low |= data << 40;
+				high &= ~0x0000ffffffffffL;
+				high |= data >> 24;
+				break;
+			case 6:
+				low &= 0x0000ffffffffffffL;
+				low |= data << 48;
+				high &= ~0x00ffffffffffffL;
+				high |= data >> 16;
+				break;
+			case 7:
+				low &= 0x00ffffffffffffffL;
+				low |= data << 56;
+				high &= ~0xffffffffffffffL;
+				high |= data >> 8;
+				break;
+		}
+		put_long(vma, addr & ~(sizeof(long)-1),low);
+		put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
+	} else
+		put_long(vma, addr, data);
+	return 0;
+}
+
+/* Uh, this does ugly stuff. It stores the specified value in the a3
+ * register. entry.S will swap a3 and the returned value from
+ * sys_ptrace() before returning to the user.
+ */
+
+static inline void set_success(struct pt_regs *regs,long resval) {
+   regs->r19=resval;
+}
+
+/* This doesn't do diddly, actually--if the value returned from 
+ * sys_ptrace() is != 0, it sets things up properly.
+ */
+
+static inline void set_failure(struct pt_regs *regs,long errcode) {
+   regs->r19=0;
+}
+
+asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4, int a5, struct pt_regs regs)
+{
+	struct task_struct *child;
+	struct user * dummy;
+
+	dummy = NULL;
+
+#ifdef DEBUG
+	printk("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",request,pid,addr,data);
+#endif
+	set_success(&regs,0);
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+	   if (current->flags & PF_PTRACED) {
+	      set_failure(&regs,-EPERM);
+	      return -EPERM;
+	   }
+	   /* set the ptrace bit in the process flags. */
+	   current->flags |= PF_PTRACED;
+	   return 0;
+	}
+	if (pid == 1) {
+	   set_failure(&regs,-EPERM);
+	   return -EPERM;
+	}
+	if (!(child = get_task(pid))) {
+	   set_failure(&regs,-ESRCH);
+	   return -ESRCH;
+	}
+	if (request == PTRACE_ATTACH) {
+	   if (child == current) {
+	      set_failure(&regs,-EPERM);
+	      return -EPERM;
+	   }
+	   if ((!child->dumpable ||
+		(current->uid != child->euid) ||
+		(current->uid != child->uid) ||
+		(current->gid != child->egid) ||
+		(current->gid != child->gid)) && !suser()) {
+	      set_failure(&regs,-EPERM);
+	      return -EPERM;
+	   }
+	   /* the same process cannot be attached many times */
+	   if (child->flags & PF_PTRACED) {
+	      set_failure(&regs,-EPERM);
+	      return -EPERM;
+	   }
+	   child->flags |= PF_PTRACED;
+	   if (child->p_pptr != current) {
+	      REMOVE_LINKS(child);
+	      child->p_pptr = current;
+	      SET_LINKS(child);
+	   }
+	   send_sig(SIGSTOP, child, 1);
+	   return 0;
+	}
+	if (!(child->flags & PF_PTRACED)) {
+#ifdef DEBUG
+	   printk("child not traced\n");
+#endif
+	   set_failure(&regs,-ESRCH);
+	   return -ESRCH;
+	}
+	if (child->state != TASK_STOPPED) {
+#ifdef DEBUG
+	   printk("child process not stopped\n");
+#endif
+	   if (request != PTRACE_KILL) {
+	      set_failure(&regs,-ESRCH);
+	      return -ESRCH;
+	   }
+	}
+	if (child->p_pptr != current) {
+#ifdef DEBUG
+	   printk("child not parent of this process\n");
+#endif
+	   set_failure(&regs,-ESRCH);
+	   return -ESRCH;
+	}
+
+	switch (request) {
+	/* when I and D space are separate, these will need to be fixed. */
+		case PTRACE_PEEKTEXT: /* read word at location addr. */ 
+		case PTRACE_PEEKDATA: {
+			unsigned long tmp;
+			int res;
+
+#ifdef DEBUG
+			printk("doing request at addr 0x%lx\n",addr);
+#endif
+			res = read_long(child, addr, &tmp);
+			if (res < 0) {
+			   set_failure(&regs,res);
+			   return res;
+			}
+			else {
+			   set_success(&regs,tmp);
+			   return 0;
+			}
+		}
+
+	/* read the word at location addr in the USER area. */
+		case PTRACE_PEEKUSR: {
+		        /* We only allow access to registers. */
+			unsigned long tmp;
+
+			tmp = 0;  /* Default return condition */
+			if(addr==30) {
+			   /* stack pointer */
+			   tmp=child->tss.usp;
+			}
+			else {
+			   int reg=addr;
+			   addr = offset_of_register(addr);
+			   if(addr < 0) {
+			      set_failure(&regs,-EIO);
+			      return -EIO;
+			   }
+			   tmp = get_stack_long(child, addr);
+#ifdef DEBUG
+			   printk("%d = reg 0x%lx=tmp\n",reg,tmp);
+#endif
+			}
+			set_success(&regs,tmp);
+			return 0;
+		}
+
+      /* when I and D space are separate, this will have to be fixed. */
+		case PTRACE_POKETEXT: /* write the word at location addr. */
+		case PTRACE_POKEDATA: {
+			long res=write_long(child,addr,data);
+			if(res) {
+			   set_failure(&regs,res);
+			}
+			return res;
+		}
+
+		case PTRACE_POKEUSR: /* write the specified register */
+		{
+		   long res;
+		   addr= offset_of_register(addr);
+		   if(addr < 0) {
+		      set_failure(&regs,-EIO);
+		      return -EIO;
+		   }
+		   res=put_stack_long(child,addr,data);
+		   if(res) {
+		      set_failure(&regs,res);
+		   }
+		   return res;
+		}
+
+		case PTRACE_SYSCALL: /* continue and stop at next 
+					(return from) syscall */
+		case PTRACE_CONT: { /* restart after signal. */
+			if ((unsigned long) data > NSIG) {
+			   set_failure(&regs,-EIO);
+			   return -EIO;
+			}
+			if (request == PTRACE_SYSCALL)
+				child->flags |= PF_TRACESYS;
+			else
+				child->flags &= ~PF_TRACESYS;
+			child->exit_code = data;
+			child->state = TASK_RUNNING;
+			unset_singlestep(child);
+			set_success(&regs,data);
+			return 0;
+		}
+
+/*
+ * make the child exit.  Best I can do is send it a sigkill. 
+ * perhaps it should be put in the status that it wants to 
+ * exit.
+ */
+		case PTRACE_KILL: {
+			child->state = TASK_RUNNING;
+			child->exit_code = SIGKILL;
+			unset_singlestep(child);
+			return 0;
+		}
+
+		case PTRACE_SINGLESTEP: {  /* set the trap flag. */
+			if ((unsigned long) data > NSIG) {
+			   set_failure(&regs,-EIO);
+			   return -EIO;
+			}
+			child->flags &= ~PF_TRACESYS;
+			set_singlestep(child);
+			child->state = TASK_RUNNING;
+			child->exit_code = data;
+			/* give it a chance to run. */
+			return 0;
+		}
+
+		case PTRACE_DETACH: { /* detach a process that was attached. */
+			if ((unsigned long) data > NSIG) {
+			   set_failure(&regs,-EIO);
+			   return -EIO;
+			}
+			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+			child->state = TASK_RUNNING;
+			child->exit_code = data;
+			REMOVE_LINKS(child);
+			child->p_pptr = child->p_opptr;
+			SET_LINKS(child);
+			/* make sure the single step bit is not set. */
+			unset_singlestep(child);
+			return 0;
+		}
+
+		default:
+		{
+		   set_failure(&regs,-EIO);
+		   return -EIO;
+		}
+	}
+}
+
+asmlinkage void syscall_trace(void)
+{
+	if ((current->flags & (PF_PTRACED|PF_TRACESYS))
+			!= (PF_PTRACED|PF_TRACESYS))
+		return;
+	current->exit_code = SIGTRAP;
+	current->state = TASK_STOPPED;
+	notify_parent(current);
+	schedule();
+	/*
+	 * this isn't the same as continuing with a signal, but it will do
+	 * for normal use.  strace only continues with a signal if the
+	 * stopping signal is not SIGTRAP.  -brl
+	 */
+	if (current->exit_code)
+		current->signal |= (1 << (current->exit_code - 1));
+	current->exit_code = 0;
+}
diff -u --recursive --new-file v1.3.8/linux/arch/alpha/lib/Makefile linux/arch/alpha/lib/Makefile
--- v1.3.8/linux/arch/alpha/lib/Makefile	Fri Jun 16 22:02:54 1995
+++ linux/arch/alpha/lib/Makefile	Tue Jul 11 08:02:20 1995
@@ -2,8 +2,6 @@
 # Makefile for alpha-specific library files..
 #
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
@@ -30,10 +28,4 @@
 
 dep:
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/alpha/lib/checksum.c linux/arch/alpha/lib/checksum.c
--- v1.3.8/linux/arch/alpha/lib/checksum.c	Fri Jul  7 08:54:43 1995
+++ linux/arch/alpha/lib/checksum.c	Mon Jul 10 16:59:58 1995
@@ -24,7 +24,7 @@
 
 /*
  * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
+ * returns a 16-bit checksum, already complemented.
  */
 unsigned short int csum_tcpudp_magic(unsigned long saddr,
 				   unsigned long daddr,
@@ -32,7 +32,9 @@
 				   unsigned short proto,
 				   unsigned int sum)
 {
-	return ~from64to16(saddr + daddr + sum + (ntohs(len) << 16) + (proto << 8));
+	return ~from64to16(saddr + daddr + sum +
+		((unsigned long) ntohs(len) << 16) +
+		((unsigned long) proto << 8));
 }
 
 /*
@@ -83,6 +85,7 @@
 					carry = (w > result);
 				} while (count);
 				result += carry;
+				result = (result & 0xffffffff) + (result >> 32);
 			}
 			if (len & 4) {
 				result += *(unsigned int *) buff;
diff -u --recursive --new-file v1.3.8/linux/arch/alpha/mm/Makefile linux/arch/alpha/mm/Makefile
--- v1.3.8/linux/arch/alpha/mm/Makefile	Mon Jan 16 07:17:34 1995
+++ linux/arch/alpha/mm/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 OBJS	= init.o fault.o
 
@@ -24,9 +22,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- v1.3.8/linux/arch/i386/boot/compressed/Makefile	Thu Jun 29 19:02:39 1995
+++ linux/arch/i386/boot/compressed/Makefile	Tue Jul 11 08:02:20 1995
@@ -17,8 +17,6 @@
 INPUT_LEN=input_len
 endif
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
diff -u --recursive --new-file v1.3.8/linux/arch/i386/config.in linux/arch/i386/config.in
--- v1.3.8/linux/arch/i386/config.in	Fri Jul  7 13:42:57 1995
+++ linux/arch/i386/config.in	Mon Jul 10 17:08:04 1995
@@ -166,6 +166,7 @@
 	bool 'DEPCA support' CONFIG_DEPCA n
 	bool 'EtherWorks 3 support' CONFIG_EWRK3 n
 	if [ "$CONFIG_NET_ALPHA" = "y" ]; then
+		bool 'SEEQ8005 support' CONFIG_SEEQ8005 n
 		bool 'AT1700 support' CONFIG_AT1700 n
 		bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
 		bool 'EtherExpress support' CONFIG_EEXPRESS n
diff -u --recursive --new-file v1.3.8/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v1.3.8/linux/arch/i386/kernel/Makefile	Thu Jun 29 19:02:39 1995
+++ linux/arch/i386/kernel/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
@@ -38,13 +36,4 @@
 
 modules:
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
-
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v1.3.8/linux/arch/i386/lib/Makefile	Tue Jun 20 09:10:31 1995
+++ linux/arch/i386/lib/Makefile	Tue Jul 11 08:02:20 1995
@@ -2,8 +2,6 @@
 # Makefile for i386-specific library files..
 #
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
@@ -19,10 +17,4 @@
 
 modules:
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/i386/math-emu/Makefile linux/arch/i386/math-emu/Makefile
--- v1.3.8/linux/arch/i386/math-emu/Makefile	Fri Jun 30 16:22:25 1995
+++ linux/arch/i386/math-emu/Makefile	Tue Jul 11 08:02:20 1995
@@ -42,11 +42,4 @@
 
 modules:
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/i386/mm/Makefile linux/arch/i386/mm/Makefile
--- v1.3.8/linux/arch/i386/mm/Makefile	Mon Jan 16 07:17:35 1995
+++ linux/arch/i386/mm/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 OBJS	= init.o fault.o
 
@@ -24,9 +22,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/mips/kernel/Makefile linux/arch/mips/kernel/Makefile
--- v1.3.8/linux/arch/mips/kernel/Makefile	Wed Jan 25 08:54:22 1995
+++ linux/arch/mips/kernel/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) $(ASFLAGS) -o $*.o $<
 .c.o:
@@ -60,11 +58,4 @@
 
 modules:
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile
--- v1.3.8/linux/arch/mips/mm/Makefile	Wed Jan 25 08:54:22 1995
+++ linux/arch/mips/mm/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 OBJS	= fault.o init.o
 
@@ -24,9 +22,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile
--- v1.3.8/linux/arch/sparc/boot/Makefile	Tue Jun 27 14:11:30 1995
+++ linux/arch/sparc/boot/Makefile	Tue Jul 11 08:02:20 1995
@@ -5,8 +5,6 @@
 OBJS	=bare.o init_me.o ../kernel/promops.o ../lib/lib.a
 BOOTLINKFLAGS = -N -Ttext 0x200000 -e _first_adr_in_text
 
-.c.s:
-	$(CC) $(CFLAGS) -S -o $*.s $<
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
@@ -25,11 +23,4 @@
 	$(CPP) -M *.c > .depend
 	$(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v1.3.8/linux/arch/sparc/kernel/Makefile	Tue Jun 27 14:11:31 1995
+++ linux/arch/sparc/kernel/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
@@ -36,13 +34,4 @@
 	$(CPP) -M *.c > .depend
 	$(CPP) -M -D__ASSEMBLY__ -ansi *.S >>.depend
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
-
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile
--- v1.3.8/linux/arch/sparc/lib/Makefile	Sun Jan 22 23:02:41 1995
+++ linux/arch/sparc/lib/Makefile	Tue Jul 11 08:02:20 1995
@@ -4,8 +4,6 @@
 
 CFLAGS := $(CFLAGS) -ansi
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
@@ -40,9 +38,4 @@
 
 dep:
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile
--- v1.3.8/linux/arch/sparc/mm/Makefile	Tue Jun 27 14:11:32 1995
+++ linux/arch/sparc/mm/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 OBJS	= fault.o vac-flush.o init.o sun4c.o srmmu.o loadmmu.o
 
@@ -24,9 +22,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/arch/sparc/prom/Makefile linux/arch/sparc/prom/Makefile
--- v1.3.8/linux/arch/sparc/prom/Makefile	Tue Jun 27 14:11:32 1995
+++ linux/arch/sparc/prom/Makefile	Tue Jul 11 08:02:20 1995
@@ -23,11 +23,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/drivers/Makefile linux/drivers/Makefile
--- v1.3.8/linux/drivers/Makefile	Wed Jun  7 13:03:54 1995
+++ linux/drivers/Makefile	Tue Jul 11 08:02:20 1995
@@ -9,14 +9,13 @@
 
 .S.s:
 	$(CPP) -traditional $< -o $*.s
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 
 SUBDIRS	= block char net #streams
+ALL_SUBDIRS = block char net scsi #streams
 
 ifdef CONFIG_PCI
 SUBDIRS := $(SUBDIRS) pci
@@ -36,17 +35,9 @@
 	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
 
 modules: dummy
-	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i modules; done
+	set -e; for i in $(ALL_SUBDIRS); do $(MAKE) -C $$i modules; done
 
 dep:
-	set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+	set -e; for i in $(ALL_SUBDIRS); do $(MAKE) -C $$i dep; done
 
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v1.3.8/linux/drivers/block/Makefile	Fri Jul  7 08:54:44 1995
+++ linux/drivers/block/Makefile	Tue Jul 11 08:02:20 1995
@@ -9,8 +9,6 @@
 # parent makefile.
 #
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
@@ -147,11 +145,4 @@
 	echo $(BLOCK_MODULE_OBJS) > ../../modules/BLOCK_MODULES
 	(cd ../../modules;for i in $(BLOCK_MODULE_OBJS); do ln -sf ../drivers/block/$$i .; done)
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/drivers/block/README.aztcd linux/drivers/block/README.aztcd
--- v1.3.8/linux/drivers/block/README.aztcd	Wed Apr  5 12:59:50 1995
+++ linux/drivers/block/README.aztcd	Mon Jul 10 08:00:56 1995
@@ -1,7 +1,7 @@
                        Readme-File README.aztcd
    for Aztech CD-ROM CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110 
                           CD-ROM  Driver 
-                       Version 1.0 and newer
+                       Version 1.2 and newer
                    (for other drives see 6.-8.)
 
 NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE
@@ -10,20 +10,27 @@
       IT WILL DEFINITELY NOT WORK WITH CD-ROM DRIVES WITH *IDE*-INTERFACE,
       such as the Aztech CDA269-031SE !!! IF YOU'RE USING A CD-ROM DRIVE
       WITH IDE-INTERFACE, SOMETIMES ALSO CALLED ATAPI-COMPATIBLE, PLEASE 
-      USE THE ide-cd.c DRIVER, WRITTEN BY MARK LORD AND SCOTT SNYDER !!!
+      USE THE ide-cd.c DRIVER, WRITTEN BY MARK LORD AND SCOTT SNYDER !
+      THE STANDARD-KERNEL 1.2.x NOW ALSO SUPPORTS IDE-CDROM-DRIVES, SEE THE
+      HARDDISK (!) SECTION OF make config, WHEN COMPILING A NEW KERNEL!!!
 ----------------------------------------------------------------------------
 Contents of this file:
-                         1. NOTE
-                         2. INSTALLATION
-                         3. CONFIGURING YOUR KERNEL
-                         4. RECOMPILING YOUR KERNEL
-                         5. KNOWN PROBLEMS, FUTURE DEVELOPMENTS
-                         6. BUG REPORTS
-                         7. OTHER DRIVES
-                         8. IF YOU DON'T SUCCEED ... DEBUGGING  
-                         9. TECHNICAL HISTORY OF THE DRIVER
-                        10. ACKNOWLEDGMENTS
-                        11. PROGRAMMING ADD ONS: CDPLAY.C
+                         1.  NOTE
+                         2.  INSTALLATION
+                         3.  CONFIGURING YOUR KERNEL
+                         4.  RECOMPILING YOUR KERNEL
+                         4.1 AZTCD AS A RUN-TIME LOADABLE MODULE
+                         4.2 CDROM CONNECTED TO A SOUNDCARD
+                         5.  KNOWN PROBLEMS, FUTURE DEVELOPMENTS
+			 5.1 MULTISESSION SUPPORT
+			 5.2 STATUS RECOGNITION
+			 5.3 DOSEMU's CDROM SUPPORT
+                         6.  BUG REPORTS
+                         7.  OTHER DRIVES
+                         8.  IF YOU DON'T SUCCEED ... DEBUGGING  
+                         9.  TECHNICAL HISTORY OF THE DRIVER
+                        10.  ACKNOWLEDGMENTS
+                        11.  PROGRAMMING ADD ONS: CDPLAY.C
                         APPENDIX: Source code of cdplay.c
 ----------------------------------------------------------------------------
 
@@ -94,7 +101,7 @@
 - Edit aztcd.h to set the I/O-address to your I/O-Base address (AZT_BASE_ADDR), 
   the driver does not use interrupts or DMA, so if you are using an AZTECH
   CD268, an ORCHID CD-3110 or ORCHID/WEARNES CDD110 that's the only item you 
-  have to set up. 
+  have to set up. If you have a soundcard, read chapter 4.2.
   Users of other drives should read chapter OTHER DRIVES of this file.
   You also can configure that address by LILO boot parameter aztcd=... 
 - Build a new kernel, configure it for 'Aztech/Orchid/Okano/Wearnes support' 
@@ -126,8 +133,10 @@
 4.1 AZTCD AS A RUN-TIME LOADABLE MODULE
 If you do not need aztcd permanently, you can also load and remove the driver
 during runtime via insmod and rmmod. To build aztcd as a loadable module you 
-must *not* configure your kernel for AZTECH support. But you need to have
-the ISO9660-filesystem included! So rebuild your kernel, if necessary.
+must *not* configure your kernel for AZTECH support. Nevertheless, you may
+run into problems, if the version of your boot kernel is not the same than
+the source kernel version, from which you create the modules. So rebuild your 
+kernel, if necessary. 
 
 Now edit the base address of your AZTECH interface card in
 /usr/src/linux/include/linux/aztcd.h to the appropriate value. Then change
@@ -137,20 +146,42 @@
 After that you can run-time load the driver via
                     insmod /lib/modules/X.X.X/misc/aztcd.o
 and remove it via   rmmod  aztcd.
-If you have not configured the correct base address, you can also supply the
+If you did not set the correct base address in aztcd.h, you can also supply the
 base address when loading the driver via
                     insmod /lib/modules/X.X.X/misc/aztcd.o aztcd=<base address>
-In all commands 'X.X.X' is the current linux kernel version number. For details
-see file README.modules in /usr/src/linux.
-
+If you do not have the iso9660-filesystem in your boot kernel, you also have
+to load it before you can mount the CDROM:
+                    insmod /lib/modules/X.X.X/fs/isofs.o
+The mount procedure works as described in 4. above.
+(In all commands 'X.X.X' is the current linux kernel version number. For details
+see file README.modules in /usr/src/linux.)
+
+4.2 CDROM CONNECTED TO A SOUNDCARD
+Most soundcards do have a bus interface to the CDROM-drive. In many cases
+this soundcard needs to be configured, before the CDROM can be used. This
+configuration procedure consists of writing some kind of initialization
+data to the soundcard registers. The AZTECH-CDROM driver in the moment does
+only support one type of soundcard (SoundWave32). Users of other soundcards
+should try to boot DOS first and let their DOS drivers initialize the
+soundcard and CDROM, then warm boot (or use loadlin) their PC to start
+Linux.
+Support for the CDROM-interface of SoundWave32-soundcards is directly
+implemented in the AZTECH driver. Please edit /usr/src/linux/include/aztdc.h,
+uncomment line '#define AZT_SW32' and set the appropiate value for
+AZT_BASE_ADDR and AZT_SW32_BASE_ADDR. This support was tested with an Orchid
+CDS-3110 connected to a SoundWave32.
+If you want your soundcard to be supported, find out, how it needs to be
+configured and mail me (see 6.) the appropriate information. 
 
 5. KNOWN PROBLEMS, FUTURE DEVELOPMENTS
+5.1 MULTISESSION SUPPORT
 The driver does not support applications such as photo CD, multi session CD
 etc.. I do not plan to include the support for that in the driver, because I
 do not use such applications. If you are interested in that stuff and would
 like to extend the drivers capability on your own, please contact me, I'll
 support you as far as I can. 
 
+5.2 STATUS RECOGNITION
 The drive status recognition does not work correctly in all cases. Changing
 a disk or having the door open, when a drive is already mounted, is detected 
 by the Aztech driver itself, but nevertheless causes multiple read attempts
@@ -170,6 +201,16 @@
 and substitute STEN_LOW_WAIT by STEN_LOW. Busy waiting with STEN_LOW is more
 stable, but also causes CPU overhead.
 
+5.3 DOSEMU's CD-ROM SUPPORT
+With release 1.20 aztcd was modified to allow access to CD-ROMS when running
+under dosemu-0.60. aztcd-versions before 1.20 are most likely to crash
+Linux, when a CD-ROM is accessed under dosemu. This problem has partly been
+fixed, but still when accessing a directory for the first time the system
+might hang for some 30sec. So be patient, when using dosemu's CD-ROM support
+in combination with aztcd :-) ! Unfortunately up to now, I could not locate
+the root cause of that problem. It seems to be somewhere in the interaction
+of the kernel with dosemu's and aztcd's buffers. I appreciate any help on
+this subject !
 
 6. BUG REPORTS
 Please send detailed bug reports and bug fixes via EMail to
@@ -380,7 +421,7 @@
 also to all the guys on the Internet, who collected valuable technical 
 information about CDROMs. 
 
-Joe Nardone (nardone@clark.net) was a patient tester even for my first
+Joe Nardone (joe@access.digex.net) was a patient tester even for my first
 trial, which was more than slow, and made suggestions for code improvement.
 Especially the 'finite state machine' azt_poll() was rewritten by Joe to get
 clean C code and avoid the ugly 'gotos', which I copied from mcd.c.
@@ -390,6 +431,9 @@
 
 Joseph Piskor and Peter Nugent were the first users with the ORCHID CD3110
 and also were very patient with the problems which occurred.
+
+Reinhard Max delivered the information for the CDROM-interface of the
+SoundWave32 soundcards.
 
 Anybody, who is interested in these items should have a look at 'ftp.gwdg.de',
 directory 'pub/linux/cdrom' and at 'ftp.cdrom.com', directory 'pub/cdrom'.
diff -u --recursive --new-file v1.3.8/linux/drivers/block/README.ide linux/drivers/block/README.ide
--- v1.3.8/linux/drivers/block/README.ide	Fri Jun  2 13:46:26 1995
+++ linux/drivers/block/README.ide	Mon Jul 10 17:08:05 1995
@@ -1,4 +1,4 @@
-README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.2.x)
+README.ide -- Information regarding ide.c and ide-cd.c (IDE driver in 1.3.x)
 ================================================================================
 Supported by:  mlord@bnr.ca           -- disks, interfaces, probing
                snyder@fnald0.fnal.gov -- cdroms, ATAPI, audio
@@ -21,18 +21,16 @@
 	- support for interrupt unmasking during I/O (better than hd.c)
 	- improved handshaking and error detection/recovery
 	- can co-exist with hd.c to control only the secondary interface
-NEW!	- support for reliable operation of buggy CMD-640 interfaces
+	- support for reliable operation of buggy CMD-640 interfaces
 		- use kernel command line option:   hda=serialize
-NEW!	- experimental support for DTC-2278D interfaces
+	- experimental support for DTC-2278D interfaces
 		- use kernel command line option:  hda=dtc2278
-NEW!	- run-time selectable 32bit interface support (using hdparm-2.3)
+	- run-time selectable 32bit interface support (using hdparm-2.3)
 
-Under construction:
+NEW!	- support for DiskManager 6.0x "Dynamic Disk Overlay" (experimental)
+NEW!	- support for drives with a stuck WRERR_STAT bit
+NEW!	- support for removeable devices
 
-	- improved CMD support:  tech info is supposedly "in the mail"
-	- support for interface speed selection on jumperless interfaces
-	- improved detection of non-standard IDE ATAPI cdrom drives
-	- support for non-standard 3rd/4th drive interface on Promise cards
 
 ***
 
@@ -266,13 +264,10 @@
 problems with some software".   Ignore them for linux partitions.  The "some
 software" refers to DOS, the BIOS, and LILO, as described previously.
 
-Western Digital now ships a "DiskManager 6.03" diskette with all of their big
-hard drives.  Burn it!  That idiotic piece of garbage isn't even universally
-compatible with DOS, let alone other operating systems like Linux.  Eventually
-some kind person will kludge Linux to work with it, but at present the two
-are completely incompatible.  If you have this version of DiskManager on your
-hard disk already, it can be exterminated at the expense of all data on the
-drive (back it up elsewhere), by using the "DM" command from the diskette
-as follows:   DM /Y-
+Western Digital ships a "DiskManager 6.03" diskette with all of their big
+hard drives.  Use BIOS translation instead of this if possible, as it is a
+more generally compatible method of achieving the same results (DOS access
+to the entire disk).  However, if you must use DiskManager, it should now
+work with Linux 1.3.x in most cases.  Let me know if you still have trouble.
 
 mlord@bnr.ca
diff -u --recursive --new-file v1.3.8/linux/drivers/block/aztcd.c linux/drivers/block/aztcd.c
--- v1.3.8/linux/drivers/block/aztcd.c	Tue Jun 27 14:11:33 1995
+++ linux/drivers/block/aztcd.c	Mon Jul 10 08:00:56 1995
@@ -1,5 +1,5 @@
-#define AZT_VERSION "V1.0"
-/*      $Id: aztcd.c,v 1.0 1995/03/25 08:27:11 root Exp $
+#define AZT_VERSION "1.30"
+/*      $Id: aztcd.c,v 1.30 1995/07/04 08:28:06 root Exp $
 	linux/drivers/block/aztcd.c - AztechCD268 CDROM driver
 
 	Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
@@ -104,6 +104,18 @@
                 Added support for loadable MODULEs, so aztcd can now also be
                 loaded by insmod and removed by rmmod during run time
                 Werner Zimmermann, Mar. 24, 95
+        V1.10   Implemented soundcard configuration for Orchid CDS-3110 drives
+                connected to Soundwave32 cards. Release for LST 2.1.
+                (still experimental)
+                Werner Zimmermann, May 8, 95
+        V1.20   Implemented limited support for DOSEMU0.60's cdrom.c. Now it works, but
+                sometimes DOSEMU may hang for 30 seconds or so. A fully functional ver-
+                sion needs an update of Dosemu0.60's cdrom.c, which will come with the 
+                next revision of Dosemu.
+                Also Soundwave32 support no works.
+                Werner Zimmermann, May 22, 95
+	V1.30   Auto-eject feature. Inspired by Franc Racis (racis@psu.edu)
+	        Werner Zimmermann, July 4, 95
 	NOTE: 
 	Points marked with ??? are questionable !
 */
@@ -135,16 +147,30 @@
 #define MAJOR_NR AZTECH_CDROM_MAJOR 
 
 #include "blk.h"
-#ifndef MODULE
+
+#ifdef MODULE
+#else
 # define MOD_INC_USE_COUNT
 # define MOD_DEC_USE_COUNT
 #endif
 
 #include <linux/aztcd.h>
 
+#define SET_TIMER(func, jifs)   delay_timer.expires = jifs; \
+                                delay_timer.function = (void *) func; \
+                                add_timer(&delay_timer); 
+
+#define CLEAR_TIMER             del_timer(&delay_timer);
+
+#define RETURNM(message,value) {printk("aztcd: Warning: %s failed\n",message);\
+                                return value;}
+#define RETURN(message)        {printk("aztcd: Warning: %s failed\n",message);\
+                                return;}
+
 static int aztPresent = 0;
 
 #if 0
+#define AZT_TEST
 #define AZT_TEST1 /* <int-..> */
 #define AZT_TEST2 /* do_aztcd_request */
 #define AZT_TEST3 /* AZT_S_state */
@@ -197,6 +223,7 @@
 
 static char  azt_cont = 0;
 static char  azt_init_end = 0;
+static char  azt_auto_eject = AZT_AUTO_EJECT;
 
 static int AztTimeout, AztTries;
 static struct wait_queue *azt_waitq = NULL; 
@@ -210,7 +237,6 @@
 static char aztDiskChanged = 1;
 static char aztTocUpToDate = 0;
 
-
 static void azt_transfer(void);
 static void azt_poll(void);
 static void azt_invalidate_buffers(void);
@@ -234,6 +260,7 @@
 
 static unsigned char aztIndatum;
 static unsigned long aztTimeOutCount;
+static int aztCmd = 0;
 
 /* Macros for the drive hardware interface handshake, these macros use
    busy waiting */
@@ -270,7 +297,7 @@
   do { aztIndatum=inb(STATUS_PORT);
        aztTimeOutCount++;
        if (aztTimeOutCount>=AZT_TIMEOUT)
-	{ if (azt_init_end) printk("aztcd: Error Wait STEN_LOW\n");
+	{ if (azt_init_end) printk("aztcd: Error Wait STEN_LOW commands:%x\n",aztCmd);
 	  break;
 	}
      } while (aztIndatum&AFL_STATUS);
@@ -297,25 +324,25 @@
 void statusAzt(void)
 { AztTimeout = AZT_STATUS_DELAY;
   SET_TIMER(aztStatTimer, 1); 
-  sleep_on(&azt_waitq);    
-  if (AztTimeout <= 0) printk("aztcd: Error Wait STEN_LOW_WAIT\n");
+  sleep_on(&azt_waitq);
+  if (AztTimeout <= 0) printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n",aztCmd);
   return;
 }
 
 static void aztStatTimer(void)
-{       if (!(inb(STATUS_PORT) & AFL_STATUS))
-	{       wake_up(&azt_waitq);
-		return;
-	}
-	AztTimeout--;
-	if (AztTimeout <= 0)
-	{       wake_up(&azt_waitq);
-		return;
-	}
-	SET_TIMER(aztStatTimer, 1);
+{ if (!(inb(STATUS_PORT) & AFL_STATUS))
+     { wake_up(&azt_waitq);
+       return;
+     }
+  AztTimeout--;
+  if (AztTimeout <= 0)
+     { wake_up(&azt_waitq);
+       printk("aztcd: Error aztStatTimer: Timeout\n");
+       return;
+     }
+  SET_TIMER(aztStatTimer, 1);
 }
 
-
 void aztcd_setup(char *str, int *ints)
 {  if (ints[0] > 0)
       azt_port = ints[1];
@@ -363,6 +390,7 @@
 #ifdef AZT_DEBUG
    printk("aztcd: Executing command %x\n",cmd);
 #endif
+   aztCmd=cmd;
    outb(POLLED,MODE_PORT);
    do { if (inb(STATUS_PORT)&AFL_STATUS) break;
 	inb(DATA_PORT);    /* if status left from last command, read and */
@@ -386,7 +414,7 @@
      { printk("### Error 2 aztcd: aztSendCmd %x \n",cmd);
        azt_error=0xA5;
      }
-   return -1;
+   RETURNM("aztSendCmd",-1);
 }
 
 /*
@@ -423,7 +451,7 @@
      { printk("### Error 2 aztcd: sendAztCmd %x\n ",cmd);
        azt_error=0xA5;
      }
-   return -1;
+   RETURNM("sendAztCmd",-1);
 }
 
 
@@ -440,16 +468,17 @@
  */
 static int aztStatus(void)  
 {       int st;
-	int i;
+/*	int i;
 
-	i = inb(STATUS_PORT) & AFL_STATUS;   /* is STEN=0?    ???*/
+	i = inb(STATUS_PORT) & AFL_STATUS;    is STEN=0?    ???
 	if (!i)
-	{
-		st = inb(DATA_PORT) & 0xFF;
+*/      STEN_LOW;
+        if (aztTimeOutCount<AZT_TIMEOUT)	
+	{   	st = inb(DATA_PORT) & 0xFF;
 		return st;
 	}
 	else
-		return -1;
+		RETURNM("aztStatus",-1);
 }
 
 /*
@@ -458,7 +487,7 @@
 static int getAztStatus(void)
 {       int st;
 
-	if (aztSendCmd(ACMD_GET_STATUS)) return -1;
+	if (aztSendCmd(ACMD_GET_STATUS)) RETURNM("getAztStatus 1",-1);
 	STEN_LOW;
 	st = inb(DATA_PORT) & 0xFF;
 #ifdef AZT_DEBUG
@@ -487,22 +516,14 @@
  * Send a 'Play' command and get the status.  Use only from the top half.
  */
 static int aztPlay(struct azt_Play_msf *arg)
-{       if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0) return -1;
+{       if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0) RETURNM("aztPlay",-1);
 	return 0;
 }
 
 
 long azt_msf2hsg(struct msf *mp)
-{
-#ifdef AZT_DEBUG
-	if (mp->min  >=70) printk("aztcd: Error msf2hsg address Minutes\n");
-	if (mp->sec  >=60) printk("aztcd: Error msf2hsg address Seconds\n");
-	if (mp->frame>=75) printk("aztcd: Error msf2hsg address Frames\n");
-#endif
-	return azt_bcd2bin(mp -> frame)
-		+ azt_bcd2bin(mp -> sec) * 75
-		+ azt_bcd2bin(mp -> min) * 4500
-		- 150;
+{ return azt_bcd2bin(mp -> frame) + azt_bcd2bin(mp -> sec) * 75
+		                  + azt_bcd2bin(mp -> min) * 4500 - 150;
 }
 
 static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
@@ -517,12 +538,12 @@
         struct cdrom_volctrl volctrl;
 
 #ifdef AZT_DEBUG
-	printk("aztcd: starting aztcd_ioctl - Command:%x\n",cmd);
+	printk("aztcd: starting aztcd_ioctl - Command:%x   Time: %li\n",cmd, jiffies);
 #endif
-	if (!ip) return -EINVAL;
-	if (getAztStatus()<0) return -EIO;
+	if (!ip) RETURNM("aztcd_ioctl 1",-EINVAL);
+	if (getAztStatus()<0) RETURNM("aztcd_ioctl 2", -EIO);
 	if (!aztTocUpToDate)
-	{ if ((i=aztUpdateToc())<0) return i; /* error reading TOC */
+	{ if ((i=aztUpdateToc())<0) RETURNM("aztcd_ioctl 3", i); /* error reading TOC */
 	}
 
 	switch (cmd)
@@ -530,12 +551,12 @@
 	case CDROMSTART:     /* Spin up the drive. Don't know, what to do,
 	                        at least close the tray */
 #ifdef AZT_PRIVATE_IOCTLS 
-	        if (aztSendCmd(ACMD_CLOSE)) return -1;
+	        if (aztSendCmd(ACMD_CLOSE)) RETURNM("aztcd_ioctl 4",-1);
 	        STEN_LOW_WAIT;
 #endif
 		break;
 	case CDROMSTOP:      /* Spin down the drive */
-		if (aztSendCmd(ACMD_STOP)) return -1;
+		if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 5",-1);
 		STEN_LOW_WAIT;
 		/* should we do anything if it fails? */
 		aztAudioStatus = CDROM_AUDIO_NO_STATUS;
@@ -546,10 +567,11 @@
 		if (aztGetQChannelInfo(&qInfo) < 0)
 		{ /* didn't get q channel info */
 		  aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-		  return 0;
+		  RETURNM("aztcd_ioctl 7",0);
 		}
 		azt_Play.start = qInfo.diskTime;        /* remember restart point */
-		if (aztSendCmd(ACMD_PAUSE)) return -1;
+
+		if (aztSendCmd(ACMD_PAUSE)) RETURNM("aztcd_ioctl 8",-1);
 		STEN_LOW_WAIT;
 		aztAudioStatus = CDROM_AUDIO_PAUSED;
 		break;
@@ -590,7 +612,7 @@
 		break;
 	case CDROMPLAYMSF:   /* Play starting at the given MSF address. */
 /*              if (aztAudioStatus == CDROM_AUDIO_PLAY) 
-		{ if (aztSendCmd(ACMD_STOP)) return -1;
+		{ if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1);
 		  STEN_LOW;
 		  aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 		}
@@ -661,13 +683,28 @@
 		memcpy_tofs((void *) arg, &entry, sizeof entry);
 		break;
 	case CDROMSUBCHNL:   /* Get subchannel info */
-		st = verify_area(VERIFY_READ, (void *) arg, sizeof subchnl);
-		if (st) return st;
-		st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
-		if (st) return st;
-		memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
+		st = verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl));
+		if (st) { 
+#ifdef AZT_DEBUG
+		          printk("aztcd: exiting aztcd_ioctl - Error 1 - Command:%x\n",cmd);
+#endif
+		          return st;
+		        }  
+		st = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
+		if (st) { 
+#ifdef AZT_DEBUG
+		          printk("aztcd: exiting aztcd_ioctl - Error 2 - Command:%x\n",cmd);
+#endif
+		          return st;
+		        }  
+		memcpy_fromfs(&subchnl, (void *) arg, sizeof (struct cdrom_subchnl));
 		if (aztGetQChannelInfo(&qInfo) < 0)
-		  return -EIO;
+		if (st) { 
+#ifdef AZT_DEBUG
+		          printk("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",cmd);
+#endif
+     		  	  return -EIO;
+     		  	}  
 		subchnl.cdsc_audiostatus = aztAudioStatus;
 		subchnl.cdsc_adr = qInfo.ctrl_addr;
 		subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
@@ -677,17 +714,16 @@
 		{ subchnl.cdsc_absaddr.lba = azt_msf2hsg(&qInfo.diskTime);
 		  subchnl.cdsc_reladdr.lba = azt_msf2hsg(&qInfo.trackTime);
 		}
-		else if (subchnl.cdsc_format == CDROM_MSF)
-		{ subchnl.cdsc_absaddr.msf.minute = azt_bcd2bin(qInfo.diskTime.min);
+		else  /*default*/
+		{ subchnl.cdsc_format = CDROM_MSF;
+		  subchnl.cdsc_absaddr.msf.minute = azt_bcd2bin(qInfo.diskTime.min);
 		  subchnl.cdsc_absaddr.msf.second = azt_bcd2bin(qInfo.diskTime.sec);
-		  subchnl.cdsc_absaddr.msf.frame = azt_bcd2bin(qInfo.diskTime.frame);
+		  subchnl.cdsc_absaddr.msf.frame  = azt_bcd2bin(qInfo.diskTime.frame);
 		  subchnl.cdsc_reladdr.msf.minute = azt_bcd2bin(qInfo.trackTime.min);
 		  subchnl.cdsc_reladdr.msf.second = azt_bcd2bin(qInfo.trackTime.sec);
 		  subchnl.cdsc_reladdr.msf.frame  = azt_bcd2bin(qInfo.trackTime.frame);
 		}
-		else
-		  return -EINVAL;
-		memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
+		memcpy_tofs((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
 		break;
 	case CDROMVOLCTRL:   /* Volume control 
 	 * With my Aztech CD268-01A volume control does not work, I can only
@@ -709,12 +745,16 @@
                 aztUnlockDoor(); /* Assume user knows what they're doing */
 	       /* all drives can at least stop! */
 		if (aztAudioStatus == CDROM_AUDIO_PLAY) 
-		{ if (aztSendCmd(ACMD_STOP)) return -1;
+		{ if (aztSendCmd(ACMD_STOP)) RETURNM("azt_ioctl 10",-1);
 		  STEN_LOW_WAIT;
 		}
-		if (aztSendCmd(ACMD_EJECT)) return -1;
+		if (aztSendCmd(ACMD_EJECT)) RETURNM("azt_ioctl 11",-1);
+		STEN_LOW_WAIT; /*???*/
 		aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 		break;
+	case CDROMEJECT_SW:
+		azt_auto_eject = (char) arg;
+		break;	
 	case CDROMREADMODE1: /*read data in mode 1 (2048 Bytes)*/
 	case CDROMREADMODE2: /*read data in mode 2 (2336 Bytes)*/
 /*Take care, the following code is not compatible with other CD-ROM drivers,
@@ -759,7 +799,7 @@
 		return -EINVAL;
 	}
 #ifdef AZT_DEBUG
-	printk("aztcd: exiting aztcd_ioctl\n");
+        printk("aztcd: exiting aztcd_ioctl Command:%x  Time:%li\n",cmd,jiffies);
 #endif
 	return 0;
 }
@@ -772,7 +812,7 @@
 static void azt_transfer(void)
 { 
 #ifdef AZT_TEST
-  printk("aztcd: executing azt_transfer\n");
+  printk("aztcd: executing azt_transfer Time:%li\n",jiffies);
 #endif
   if (CURRENT_VALID) {
     while (CURRENT -> nr_sectors) {
@@ -808,7 +848,7 @@
 static void do_aztcd_request(void)
 {
 #ifdef AZT_TEST
-  printk(" do_aztcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors);
+  printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies);
 #endif
   azt_transfer_is_active = 1;
   while (CURRENT_VALID) {
@@ -840,7 +880,7 @@
 #ifdef AZT_TEST2
   printk("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n", \
 	  azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
-  printk(" do_aztcd_request ends\n");
+  printk(" do_aztcd_request ends  Time:%li\n",jiffies);
 #endif
 
 }
@@ -852,7 +892,7 @@
     int skip = 0;
 
     if (azt_error) {                             /* ???*/
-	if (aztSendCmd(ACMD_GET_ERROR)) return;
+	if (aztSendCmd(ACMD_GET_ERROR)) RETURN("azt_poll 1");
 	STEN_LOW;
 	azt_error=inb(DATA_PORT)&0xFF;
 	printk("aztcd: I/O error 0x%02x\n", azt_error);
@@ -897,8 +937,7 @@
 	    printk("AZT_S_START\n");
 	  }
 #endif
-
-	  if(aztSendCmd(ACMD_GET_STATUS)) return;  /*result will be checked by aztStatus() */
+	  if(aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 2");  /*result will be checked by aztStatus() */
 	  azt_state = azt_mode == 1 ? AZT_S_READ : AZT_S_MODE;
 	  AztTimeout = 3000;
 	  break;
@@ -936,11 +975,12 @@
 	    return;
 	  }
 					/*???*/
-	  if (aztSendCmd(ACMD_SET_MODE)) return;
-	  outb(0x01, DATA_PORT);            /*Mode 1*/
+/*	  if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3");
+	  outb(0x01, DATA_PORT);          
 	  PA_OK;
 	  STEN_LOW;
-	  if (aztSendCmd(ACMD_GET_STATUS)) return;
+*/        if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 4");
+	  STEN_LOW; /*???*/
 	  azt_mode = 1;
 	  azt_state = AZT_S_READ;
 	  AztTimeout = 3000;
@@ -1148,7 +1188,7 @@
 	    }
 	    azt_read_count--;
 	  }  
-	  if (aztSendCmd(ACMD_GET_STATUS)) return;
+	  if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 5");
 	  azt_state = AZT_S_STOPPING;
 	  AztTimeout = 1000;
 	  break;
@@ -1209,8 +1249,8 @@
    if (!AztTimeout--) 
     { printk("aztcd: timeout in state %d\n", azt_state);
       azt_state = AZT_S_STOP;
-      if (aztSendCmd(ACMD_STOP)) return; 
-      STEN_LOW_WAIT;    
+      if (aztSendCmd(ACMD_STOP)) RETURN("azt_poll 6"); 
+      STEN_LOW_WAIT;     
     };
 
   SET_TIMER(azt_poll, 1);
@@ -1289,6 +1329,8 @@
 	sync_dev(inode->i_rdev);             /*??? isn't it a read only dev?*/
 	invalidate_buffers(inode -> i_rdev);
 	aztUnlockDoor();
+        if (azt_auto_eject)
+           aztSendCmd(ACMD_EJECT);
         CLEAR_TIMER;
   }
   return;
@@ -1345,7 +1387,25 @@
 #endif	  
 	}
 
-	/* check for card */
+#ifdef AZT_SW32   /*CDROM connected to Soundwave32 card*/
+        if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500)
+           { printk("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n",
+		 AZT_SW32_BASE_ADDR,AZT_SW32_INIT,AZT_SW32_CONFIG_REG,AZT_SW32_ID_REG);
+#ifndef MODULE
+	         return (mem_start);
+#else
+                 return -EIO;
+#endif	  
+	   }
+        else                
+           { printk("aztcd: Soundwave32 card detected at %x  Version %x\n",
+	 	 AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG));
+	     outw(AZT_SW32_INIT,AZT_SW32_CONFIG_REG);
+	     for (count=0;count<10000;count++);          /*delay a bit*/    	 
+           }
+#endif	
+
+	/* check for presence of drive */
 	outb(POLLED,MODE_PORT);                 /*???*/
 	inb(CMD_PORT);
 	inb(CMD_PORT);
@@ -1515,13 +1575,12 @@
 	int st;
 
 #ifdef AZT_DEBUG
-	printk("aztcd: starting aztGetQChannelInfo\n");
+	printk("aztcd: starting aztGetQChannelInfo  Time:%li\n",jiffies);
 #endif
-	if ((st=getAztStatus())==-1) return -1;
-	if (aztSendCmd(ACMD_GET_Q_CHANNEL))          return -1;
-	STEN_LOW_WAIT;
-	if (aztGetValue(&notUsed) <0)                return -1; /*Nullbyte ein-*/
-							     /*lesen ???*/
+	if ((st=getAztStatus())==-1)        RETURNM("aztGetQChannelInfo 1",-1);
+	if (aztSendCmd(ACMD_GET_Q_CHANNEL)) RETURNM("aztGetQChannelInfo 2",-1);
+	/*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here*/
+	if (aztGetValue(&notUsed)) RETURNM("aztGetQChannelInfo 3",-1); /*??? Nullbyte einlesen*/
 	if ((st&AST_MODE_BITS)==AST_INITIAL)
 	 { qp->ctrl_addr=0;      /* when audio stop ACMD_GET_Q_CHANNEL returns */
 	   qp->track=0;          /* only one byte with Aztech drives */
@@ -1535,19 +1594,19 @@
 	   return 0;  
 	 }
 	else
-	 { if (aztGetValue(&qp -> ctrl_addr) < 0)       return -1;
-	   if (aztGetValue(&qp -> track) < 0)           return -1;
-	   if (aztGetValue(&qp -> pointIndex) < 0)      return -1;
-	   if (aztGetValue(&qp -> trackTime.min) < 0)   return -1;
-	   if (aztGetValue(&qp -> trackTime.sec) < 0)   return -1;
-	   if (aztGetValue(&qp -> trackTime.frame) < 0) return -1;
-	   if (aztGetValue(&notUsed) < 0)               return -1;
-	   if (aztGetValue(&qp -> diskTime.min) < 0)    return -1;
-	   if (aztGetValue(&qp -> diskTime.sec) < 0)    return -1;
-	   if (aztGetValue(&qp -> diskTime.frame) < 0)  return -1;
+	 { if (aztGetValue(&qp -> ctrl_addr) < 0)       RETURNM("aztGetQChannelInfo 4",-1);
+	   if (aztGetValue(&qp -> track) < 0)           RETURNM("aztGetQChannelInfo 4",-1);
+	   if (aztGetValue(&qp -> pointIndex) < 0)      RETURNM("aztGetQChannelInfo 4",-1);
+	   if (aztGetValue(&qp -> trackTime.min) < 0)   RETURNM("aztGetQChannelInfo 4",-1);
+	   if (aztGetValue(&qp -> trackTime.sec) < 0)   RETURNM("aztGetQChannelInfo 4",-1);
+	   if (aztGetValue(&qp -> trackTime.frame) < 0) RETURNM("aztGetQChannelInfo 4",-1);
+	   if (aztGetValue(&notUsed) < 0)               RETURNM("aztGetQChannelInfo 4",-1);
+	   if (aztGetValue(&qp -> diskTime.min) < 0)    RETURNM("aztGetQChannelInfo 4",-1);
+	   if (aztGetValue(&qp -> diskTime.sec) < 0)    RETURNM("aztGetQChannelInfo 4",-1);
+	   if (aztGetValue(&qp -> diskTime.frame) < 0)  RETURNM("aztGetQChannelInfo 4",-1);
 	 }
 #ifdef AZT_DEBUG
-	printk("aztcd: exiting aztGetQChannelInfo\n");
+	printk("aztcd: exiting aztGetQChannelInfo  Time:%li\n",jiffies);
 #endif
 	return 0;
 }
@@ -1558,7 +1617,7 @@
 static int aztUpdateToc()
 {
 #ifdef AZT_DEBUG
-	printk("aztcd: starting aztUpdateToc\n");
+	printk("aztcd: starting aztUpdateToc  Time:%li\n",jiffies);
 #endif  
 	if (aztTocUpToDate)
 		return 0;
@@ -1571,7 +1630,7 @@
 
 	aztTocUpToDate = 1;
 #ifdef AZT_DEBUG
-	printk("aztcd: exiting aztUpdateToc\n");
+	printk("aztcd: exiting aztUpdateToc  Time:%li\n",jiffies);
 #endif
 	return 0;
 }
@@ -1586,13 +1645,13 @@
   struct azt_Toc qInfo;
 
 #ifdef AZT_DEBUG
-  printk("aztcd: starting aztGetDiskInfo\n");
+  printk("aztcd: starting aztGetDiskInfo  Time:%li\n",jiffies);
 #endif
-  if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) return -1;
+  if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetDiskInfo 1",-1);
   STEN_LOW_WAIT;
   test=0;
   for (limit=300;limit>0;limit--)
-   {  if (aztGetQChannelInfo(&qInfo)<0) return -1;
+   {  if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetDiskInfo 2",-1);
       if (qInfo.pointIndex==0xA0)   /*Number of FirstTrack*/
 	{ DiskInfo.first=qInfo.diskTime.min;
 	  DiskInfo.first = azt_bcd2bin(DiskInfo.first);
@@ -1618,7 +1677,7 @@
       if (test==0x0F) break;
    }
 #ifdef AZT_DEBUG
-printk ("aztcd: exiting aztGetDiskInfo\n");
+printk ("aztcd: exiting aztGetDiskInfo  Time:%li\n",jiffies);
 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
 	DiskInfo.first,
 	DiskInfo.last,
@@ -1643,7 +1702,7 @@
 	struct azt_Toc qInfo;
 
 #ifdef AZT_DEBUG
-	printk("aztcd: starting aztGetToc\n");
+	printk("aztcd: starting aztGetToc  Time:%li\n",jiffies);
 #endif
 	for (i = 0; i < MAX_TRACKS; i++)
 		Toc[i].pointIndex = 0;
@@ -1651,12 +1710,12 @@
 	i = DiskInfo.last + 3;
 
 /* Is there a good reason to stop motor before TOC read?
-	if (aztSendCmd(ACMD_STOP)) return -1;
+	if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1);
 	STEN_LOW_WAIT;
 */
 
 	azt_mode = 0x05;
-	if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) return -1; /*???*/
+	if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetToc 2",-1); /*???*/
 	STEN_LOW_WAIT;
 
 	for (limit = 300; limit > 0; limit--)
@@ -1679,7 +1738,7 @@
 	Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
 
 #ifdef AZT_DEBUG
-printk("aztcd: exiting aztGetToc\n");
+printk("aztcd: exiting aztGetToc  Time:%li\n",jiffies);
 for (i = 1; i <= DiskInfo.last+1; i++)
 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
diff -u --recursive --new-file v1.3.8/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.3.8/linux/drivers/block/floppy.c	Tue Jun 27 14:11:33 1995
+++ linux/drivers/block/floppy.c	Mon Jul 10 07:17:43 1995
@@ -81,7 +81,7 @@
  * errors to allow safe writing by specialized programs.
  */
 
-/* 1994/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
+/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks
  * by defining bit 1 of the "stretch" parameter to mean put sectors on the
  * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's
  * drives are "upside-down").
diff -u --recursive --new-file v1.3.8/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v1.3.8/linux/drivers/block/genhd.c	Fri Jul  7 08:54:44 1995
+++ linux/drivers/block/genhd.c	Mon Jul 10 17:08:05 1995
@@ -10,6 +10,11 @@
  *  in the early extended-partition checks and added DM partitions
  */
 
+/*
+ *  Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca)
+ *  with hints from uwe@eas.iis.fhg.de (us3@irz.inf.tu-dresden.de).
+ */
+
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kernel.h>
@@ -105,21 +110,62 @@
 
 static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
 {
-	int i, minor = current_minor;
+	int i, minor = current_minor, found_dm6 = 0;
 	struct buffer_head *bh;
 	struct partition *p;
 	int mask = (1 << hd->minor_shift) - 1;
+	extern void ide_xlate_1024(dev_t);
 
+read_mbr:
 	if (!(bh = bread(dev,0,1024))) {
 		printk("unable to read partition table\n");
 		return -1;
 	}
-	if (*(unsigned short *) (bh->b_data+510) != 0xAA55) {
+	if (*(unsigned short *)  (0x1fe + bh->b_data) != 0xAA55) {
 		brelse(bh);
 		return 0;
 	}
+	p = (struct partition *) (0x1be + bh->b_data);
+
+	/*
+	 *  Check for Disk Manager v6.0x "Dynamic Disk Overlay" (DDO)
+	 */
+	if (p->sys_ind == DM6_PARTITION && !found_dm6++)
+	{
+		printk(" [DM6:DDO]");
+		/*
+		 * Everything is offset by one track (p->end_sector sectors),
+		 * and a translated geometry is used to reduce the number
+		 * of apparent cylinders to 1024 or less.
+		 *
+		 * For complete compatibility with linux fdisk, we do:
+		 *  1. tell the driver to offset *everything* by one track,
+		 *  2. reduce the apparent disk capacity by one track,
+		 *  3. adjust the geometry reported by HDIO_GETGEO (for fdisk),
+		 *	(does nothing if not an IDE drive, but that's okay).
+		 *  4. invalidate our in-memory copy of block zero,
+		 *  5. restart the partition table hunt from scratch.
+		 */
+		first_sector                    += p->end_sector;
+		hd->part[MINOR(dev)].start_sect += p->end_sector;
+		hd->part[MINOR(dev)].nr_sects   -= p->end_sector;
+		ide_xlate_1024(dev);	/* harmless if not an IDE drive */
+		bh->b_dirt = 0;		/* prevent re-use of this block */
+		bh->b_uptodate = 0;
+		bh->b_req = 0;
+		brelse(bh);
+		goto read_mbr;
+	}
+
+	/*
+	 *  Check for Disk Manager v6.0x DDO on a secondary drive (?)
+	 */
+	if (p->sys_ind == DM6_AUXPARTITION) {
+		printk(" [DM6]");
+		ide_xlate_1024(dev);	/* harmless if not an IDE drive */
+	}
+
 	current_minor += 4;  /* first "extra" minor (for extended partitions) */
-	p = (struct partition *) (0x1BE + bh->b_data);
 	for (i=1 ; i<=4 ; minor++,i++,p++) {
 		if (!p->nr_sects)
 			continue;
@@ -133,10 +179,10 @@
 		}
 	}
 	/*
-	 * check for Disk Manager partition table
+	 *  Check for old-style Disk Manager partition table
 	 */
 	if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
-		p = (struct partition *) (0x1BE + bh->b_data);
+		p = (struct partition *) (0x1be + bh->b_data);
 		for (i = 4 ; i < 16 ; i++, current_minor++) {
 			p--;
 			if ((current_minor & mask) >= mask-2)
diff -u --recursive --new-file v1.3.8/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.8/linux/drivers/block/ide.c	Tue Jun 27 14:11:33 1995
+++ linux/drivers/block/ide.c	Mon Jul 10 17:08:05 1995
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 3.16  May 30, 1995
+ *  linux/drivers/block/ide.c	Version 4.00  Jul 10, 1995
  *
  *  Copyright (C) 1994, 1995  Linus Torvalds & authors (see below)
  */
@@ -40,47 +40,10 @@
  *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
  *
  *  Version 1.0 ALPHA	initial code, primary i/f working okay
- *  Version 1.1 ALPHA	fixes for dual i/f
- *  Version 1.2 ALPHA	first serious attempt at sharing irqs
  *  Version 1.3 BETA	dual i/f on shared irq tested & working!
  *  Version 1.4 BETA	added auto probing for irq(s)
  *  Version 1.5 BETA	added ALPHA (untested) support for IDE cd-roms,
- *			fixed hd.c coexistence bug, other minor stuff
- *  Version 1.6 BETA	fix link error when cd-rom not configured
- *  Version 2.0 BETA	lots of minor fixes; remove annoying messages; ...
- *  Version 2.2 BETA	fixed reset_drives; major overhaul of autoprobing
- *  Version 2.3 BETA	set DEFAULT_UNMASK_INTR to 0 again; cosmetic changes
- *  Version 2.4 BETA	added debounce on reading of drive status reg,
- *			added config flags to remove unwanted features
- *  Version 2.5 BETA	fixed problem with leftover phantom IRQ after probe,
- *			allow "set_geometry" even when in LBA (as per spec(?)),
- *			assorted miscellaneous tweaks.
- *  Version 2.6 BETA	more config flag stuff, another probing tweak,
- *  (not released)	multmode now defaults to status quo from boot time,
- *			moved >16heads check to init time, rearranged reset code
- *			added HDIO_DRIVE_CMD, removed standby/xfermode stuff
- *			hopefully fixed ATAPI probing code, added hdx=cdrom
- *  Version 2.7 BETA	fixed invocation of cdrom_setup()
- *  Version 2.8 BETA	fixed compile error for DISK_RECOVERY_TIME>0
- *			fixed incorrect drive selection in DO_DRIVE_CMD (Bug!)
- *  Version 2.9 BETA	more work on ATAPI CDROM recognition
- *  (not released)	changed init order so partition checks go in sequence
- *  Version 3.0 BETA	included ide-cd.c update from Steve with Mitsumi fixes
- *			attempt to fix byte-swap problem with Mitsumi id_info
- *			ensure drives on second i/f get initialized on boot
- *			preliminary compile-time support for 32bit IDE i/f chips
- *			added check_region() and snarf_region() to probes
- *  Version 3.1 BETA	ensure drives on *both* i/f get initialized on boot
- *			fix byte-swap problem with Mitsumi id_info
- *			changed ide_timermask into ide_timerbit
- *			get rid of unexpected interrupts after probing
- *			don't wait for READY_STAT on cdrom drives
- *  Version 3.2 BETA	Ooops.. mistakenly left VLB_32BIT_IDE on by default
- *			new ide-cd.c from Scott
- *  Version 3.3 BETA	fix compiling with PROBE_FOR_IRQS==0
- *  (sent to Linus)	tweak in do_probe() to fix Delman's DRDY problem
- *  Version 3.4 BETA	removed "444" debug message
- *  (sent to Linus)
+ *  ...
  *  Version 3.5		correct the bios_cyl field if it's too small
  *  (linux 1.1.76)	 (to help fdisk with brain-dead BIOSs)
  *  Version 3.6		cosmetic corrections to comments and stuff
@@ -120,12 +83,23 @@
  *			add boot flag to enable "dtc2278" probe
  *			add probe to avoid EATA (SCSI) interfaces,
  *			 courtesy of neuffer@goofy.zdv.uni-mainz.de.
+ *  Version 4.00	tidy up verify_area() calls - heiko@colossus.escape.de
+ *			add flag to ignore WRERR_STAT for some drives
+ *			 courtesy of David.H.West@um.cc.umich.edu
+ *			assembly syntax tweak to VLB_SYNC
+ *			removeable drive support from scuba@cs.tu-berlin.de
+ *			add transparent support for DiskManager-6.0x "Dynamic
+ *			 Disk Overlay" (DDO), most of this in in genhd.c
+ *			eliminate "multiple mode turned off" message at boot
  *
  *  To do:
- *	- improved CMD support:  tech info is supposedly "in the mail"
+ *	- add support for alternative IDE port addresses
+ *	- refine the DiskManager-6.0x overlay support (special cases)
+ *	- improved CMD support:  tech info is in my hands for 640B chip
  *	- special 32-bit controller-type detection & support
  *	- figure out how to support oddball "intelligent" caching cards
  *	- reverse-engineer 3/4 drive support on fancy "Promise" cards
+ *	- find someone to work on IDE *tape drive* support
  */
 
 #include <linux/config.h>
@@ -262,7 +236,7 @@
 
 #if SUPPORT_VLB_32BIT
 #if SUPPORT_VLB_SYNC
-#define VLB_SYNC __asm__ __volatile__ ("pusha\n movl $0x01f2,%edx\n inb (%dx),%al\n inb (%dx),%al\n inb (%dx),%al\n popa\n")
+#define VLB_SYNC __asm__ __volatile__ ("pusha\n movl $0x01f2,%edx\n inb %dx,%al\n inb %dx,%al\n inb %dx,%al\n popa\n")
 #endif	/* SUPPORT_VLB_SYNC */
 #endif	/* SUPPORT_VLB_32BIT */
 
@@ -274,7 +248,7 @@
 #define GET_STAT(hwif)		IN_BYTE(HD_STATUS,hwif)
 #define OK_STAT(stat,good,bad)	(((stat)&((good)|(bad)))==(good))
 #define BAD_R_STAT		(BUSY_STAT   | ERR_STAT)
-#define BAD_W_STAT		(BUSY_STAT   | ERR_STAT | WRERR_STAT)
+#define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
 #define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
 #define DRIVE_READY		(READY_STAT  | SEEK_STAT)
 #define DATA_READY		(DRIVE_READY | DRQ_STAT)
@@ -333,15 +307,15 @@
 	byte     unmask;		/* pretty quick access to this also */
 	dev_type type		: 1;	/* disk or cdrom (or tape, floppy..) */
 	unsigned present	: 1;	/* drive is physically present */
-	unsigned dont_probe 	: 1;	/* from:  hdx=noprobe */
+	unsigned noprobe 	: 1;	/* from:  hdx=noprobe */
 	unsigned keep_settings  : 1;	/* restore settings after drive reset */
 	unsigned busy		: 1;	/* mutex for ide_open, revalidate_.. */
 	unsigned vlb_32bit	: 1;	/* use 32bit in/out for data */
 	unsigned vlb_sync	: 1;	/* needed for some 32bit chip sets */
-	unsigned reserved0	: 1;	/* unused */
+	unsigned be_quiet	: 1;	/* supress "multiple mode" msg at boot */
 	special_t special;		/* special action flags */
 	select_t  select;		/* basic drive/head select reg value */
-	byte mult_count, chipset, reserved2;
+	byte mult_count, chipset, bad_wstat;
 	byte usage, mult_req, wpcom, ctl;
 	byte head, sect, bios_head, bios_sect;
 	unsigned short cyl, bios_cyl;
@@ -782,7 +756,7 @@
 	int i;
 	struct request *rq = ide_cur_rq[DEV_HWIF];
 
-	if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,BAD_W_STAT)) {
+	if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,dev->bad_wstat)) {
 #ifdef DEBUG
 		printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n",
 			dev->name, rq->sector, (unsigned long) rq->buffer,
@@ -849,7 +823,7 @@
 	int i;
 	struct request *rq = &ide_write_rq[DEV_HWIF];
 
-	if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,BAD_W_STAT)) {
+	if (OK_STAT(stat=GET_STAT(DEV_HWIF),DRIVE_READY,dev->bad_wstat)) {
 		if (stat & DRQ_STAT) {
 			if (rq->nr_sectors) {
 				if (dev->mult_count)
@@ -896,13 +870,14 @@
 		dev->mult_req = dev->mult_count = 0;
 		dev->special.b.recalibrate = 1;
 		(void) dump_status(DEV_HWIF, "set_multmode", stat);
-	} else {
+	} else if (!dev->be_quiet) {
 		if ((dev->mult_count = dev->mult_req))
 			printk ("  %s: enabled %d-sector multiple mode\n",
 				dev->name, dev->mult_count);
 		else
 			printk ("  %s: multiple mode turned off\n", dev->name);
 	}
+	dev->be_quiet = 0;
 	DO_REQUEST;
 }
 
@@ -1078,7 +1053,7 @@
 	if (rq->cmd == WRITE) {
 		OUT_BYTE(dev->wpcom,HD_PRECOMP);	/* for ancient drives */
 		OUT_BYTE(dev->mult_count ? WIN_MULTWRITE : WIN_WRITE, HD_COMMAND);
-		WAIT_STAT(dev, DATA_READY, BAD_W_STAT, WAIT_DRQ, "DRQ", error);
+		WAIT_STAT(dev,DATA_READY,dev->bad_wstat,WAIT_DRQ,"DRQ",error);
 		if (!dev->unmask)
 			cli();
 		if (dev->mult_count) {
@@ -1383,6 +1358,8 @@
 		sleep_on(&dev->wqueue);
 	dev->usage++;
 	restore_flags(flags);
+	if (dev->id->config & (1<<7))	/* for removeable disks */
+		check_disk_change(inode->i_rdev);
 #ifdef CONFIG_BLK_DEV_IDECD
 	if (dev->type == cdrom)
 		return cdrom_open (inode, filp, dev);
@@ -1416,7 +1393,7 @@
  * usage == 1 (we need an open channel to use an ioctl :-), so this
  * is our limit.
  */
-static int revalidate_disk(int i_rdev)
+static int revalidate_disk(dev_t  i_rdev)
 {
 	unsigned int i, major, start, drive = DEVICE_NR(i_rdev);
 	ide_dev_t *dev;
@@ -1584,29 +1561,34 @@
 			memcpy_tofs((char *)arg, (char *)dev->id, sizeof(*dev->id));
 			return 0;
 
+			case HDIO_GET_NOWERR:
+			return write_fs_long(arg, dev->bad_wstat == BAD_R_STAT);
+
 		case HDIO_SET_KEEPSETTINGS:
 		case HDIO_SET_UNMASKINTR:
-			if (!suser()) return -EACCES;
-			if ((arg > 1) || (MINOR(inode->i_rdev) & PARTN_MASK))
-				return -EINVAL;
-			save_flags(flags);
-			cli();
-			if (cmd == HDIO_SET_KEEPSETTINGS)
-				dev->keep_settings = arg;
-			else
-				dev->unmask = arg;
-			restore_flags(flags);
-			return 0;
-
+		case HDIO_SET_NOWERR:
 		case HDIO_SET_CHIPSET:
 			if (!suser()) return -EACCES;
-			if ((arg > 3) || (MINOR(inode->i_rdev) & PARTN_MASK))
+			if ((arg > 1) || (MINOR(inode->i_rdev) & PARTN_MASK))
 				return -EINVAL;
 			save_flags(flags);
 			cli();
-			dev->chipset   = arg;
-			dev->vlb_sync  = (arg & 2) >> 1;
-			dev->vlb_32bit = (arg & 1);
+			switch (cmd) {
+				case HDIO_SET_KEEPSETTINGS:
+					dev->keep_settings = arg;
+					break;
+				case HDIO_SET_UNMASKINTR:
+					dev->unmask = arg;
+					break;
+				case HDIO_SET_NOWERR:
+					dev->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT;
+					break;
+				case HDIO_SET_CHIPSET:
+					dev->chipset   = arg;
+					dev->vlb_sync  = (arg & 2) >> 1;
+					dev->vlb_32bit = (arg & 1);
+					break;
+			}
 			restore_flags(flags);
 			return 0;
 
@@ -1625,14 +1607,12 @@
 			dev->mult_req = arg;
 			dev->special.b.set_multmode = 1;
 			restore_flags(flags);
-#ifdef IDE_DRIVE_CMD
+#ifndef IDE_DRIVE_CMD
+			return 0;
+#else
 			do_drive_cmd (inode->i_rdev, NULL);
 			return (dev->mult_count == arg) ? 0 : -EIO;
-#else
-			return 0;
-#endif	/* IDE_DRIVE_CMD */
 
-#ifdef IDE_DRIVE_CMD
 		case HDIO_DRIVE_CMD:
 		{
 			unsigned long args;
@@ -1640,11 +1620,13 @@
 			if (NULL == (long *) arg)
 				err = do_drive_cmd(inode->i_rdev,NULL);
 			else {
-				if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long))))
+				if (!(err = verify_area(VERIFY_READ,(long *)arg,sizeof(long))))
 				{
 					args = get_user((long *)arg);
-					err = do_drive_cmd(inode->i_rdev,(char *)&args);
-					put_user(args,(long *)arg);
+					if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long)))) {
+						err = do_drive_cmd(inode->i_rdev,(char *)&args);
+						put_user(args,(long *)arg);
+					}
 				}
 			}
 			return err;
@@ -1662,18 +1644,20 @@
 	}
 }
 
-#ifdef CONFIG_BLK_DEV_IDECD
 static int ide_check_media_change (dev_t full_dev)
 {
 	ide_dev_t *dev;
 
 	if ((dev = get_info_ptr(full_dev)) == NULL)
 		return -ENODEV;
-	if (dev->type != cdrom)
-		return 0;
-	return cdrom_check_media_change (dev);
-}
+#ifdef CONFIG_BLK_DEV_IDECD
+	if (dev->type == cdrom)
+		return cdrom_check_media_change (dev);
 #endif	/* CONFIG_BLK_DEV_IDECD */
+	if (dev->id->config & (1<<7))	/* for removeable disks */
+		return 1;	/* always assume it was changed */
+	return 0;
+}
 
 
 static void fixstring (byte *s, int bytecount, int byteswap)
@@ -1850,8 +1834,10 @@
 		dev->mult_req = INITIAL_MULT_COUNT;
 		if (dev->mult_req > id->max_multsect)
 			dev->mult_req = id->max_multsect;
-		if (dev->mult_req || ((id->multsect_valid & 1) && id->multsect))
+		if (dev->mult_req || ((id->multsect_valid & 1) && id->multsect)) {
 			dev->special.b.set_multmode = 1;
+			dev->be_quiet = 1;
+		}
 		printk(", MaxMult=%d", id->max_multsect);
 	}
 	printk("\n");
@@ -1998,7 +1984,7 @@
  *		1  device was found (note: dev->present might still be 0)
  */
 {
-	if (dev->dont_probe)			/* skip probing? */
+	if (dev->noprobe)			/* skip probing? */
 		return dev->present;
 	if (do_probe(dev, WIN_IDENTIFY) >= 2) {	/* if !(success || timed-out) */
 #ifdef CONFIG_BLK_DEV_IDECD
@@ -2106,7 +2092,7 @@
 		}
 #endif /* SUPPORT_DTC2278 */
 #if SUPPORT_SERIALIZE
-		if (!strcmp(str,"serialize") || !strcmp(str,"cmd")) {
+		if (!strcmp(str,"serialize")) {
 			printk("%s\n",str);
 			single_threaded = 1;	/* serialize all drive access */
 			return;
@@ -2114,7 +2100,12 @@
 #endif /* SUPPORT_SERIALIZE */
 		if (!strcmp(str,"noprobe")) {
 			printk("%s\n",str);
-			dev->dont_probe = 1;	/* don't probe for this drive */
+			dev->noprobe = 1;	/* don't probe for this drive */
+			return;
+		}
+		if (!strcmp(str,"nowerr")) {
+			printk("%s\n",str);
+			dev->bad_wstat = BAD_R_STAT; /* ignore WRERR_STAT */
 			return;
 		}
 #ifdef CONFIG_BLK_DEV_IDECD
@@ -2168,6 +2159,22 @@
 	ide_setup (str, ints);
 }
 
+
+void ide_xlate_1024 (dev_t full_dev)
+{
+	ide_dev_t *dev;
+
+	if ((dev = get_info_ptr(full_dev)) != NULL) {
+		dev->bios_cyl -= 1;		/* keeps fdisk sane */
+		while (dev->bios_cyl > 1024) {
+			if (dev->bios_head > 32)
+				return;
+			dev->bios_head *= 2;
+			dev->bios_cyl  /= 2;
+		}
+	}
+}
+
 #ifndef CONFIG_BLK_DEV_HD
 /*
  * We query CMOS about hard disks : it could be that we have a SCSI/ESDI/etc
@@ -2238,6 +2245,8 @@
 		dev->keep_settings		= 0;
 		ide_hd[hwif][drive<<PARTN_BITS].start_sect = 0;
 		dev->name = ide_devname[hwif][drive];
+		if (!dev->bad_wstat)
+			dev->bad_wstat = BAD_W_STAT;
 	}
 }
 
@@ -2319,11 +2328,9 @@
 	ide_open,		/* open */
 	ide_release,		/* release */
 	block_fsync		/* fsync */
-#ifdef CONFIG_BLK_DEV_IDECD
 	,NULL,			/* fasync */
 	ide_check_media_change,	/* check_media_change */
-	NULL			/* revalidate */
-#endif CONFIG_BLK_DEV_IDECD
+	revalidate_disk		/* revalidate */
 };
 
 
diff -u --recursive --new-file v1.3.8/linux/drivers/block/mcdx.c linux/drivers/block/mcdx.c
--- v1.3.8/linux/drivers/block/mcdx.c	Fri Jul  7 08:54:45 1995
+++ linux/drivers/block/mcdx.c	Mon Jul 10 17:08:04 1995
@@ -23,7 +23,7 @@
  *  Eberhard Moenkeberg (he gave me much support and the initial kick)
  *  Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
  *      improved the original driver)
- *  John Tombs, Bjorn Ekwall (module support)
+ *  Jon Tombs, Bjorn Ekwall (module support)
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
  *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
diff -u --recursive --new-file v1.3.8/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v1.3.8/linux/drivers/char/Makefile	Fri Jun 16 22:02:54 1995
+++ linux/drivers/char/Makefile	Tue Jul 11 08:02:20 1995
@@ -9,8 +9,6 @@
 # parent makes..
 #
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
@@ -108,17 +106,10 @@
 	$(CPP) -M -DMODULE $(MODULES:.o=.c) >> .depend
 endif
 
-dummy:
-
 conmakehash: conmakehash.c
 	$(HOSTCC) -o conmakehash conmakehash.c
 
 uni_hash_tbl.h: $(FONTMAPFILE) conmakehash
 	./conmakehash $(FONTMAPFILE) 641 283 6 > uni_hash_tbl.h
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v1.3.8/linux/drivers/net/Makefile	Thu Jun 29 19:02:41 1995
+++ linux/drivers/net/Makefile	Tue Jul 11 08:02:20 1995
@@ -24,6 +24,10 @@
 
 net_init.o: ../../include/linux/autoconf.h
 
+ifdef CONFIG_SEEQ8005
+NETDRV_OBJS := $(NETDRV_OBJS) seeq8005.o
+endif
+
 ifdef CONFIG_IBMTR
 NETDRV_OBJS := $(NETDRV_OBJS) ibmtr.o
 endif
@@ -304,8 +308,4 @@
 
 endif
 
-# include a dependency file if one exists
-
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v1.3.8/linux/drivers/net/Space.c	Thu Jun 29 19:02:41 1995
+++ linux/drivers/net/Space.c	Mon Jul 10 17:08:04 1995
@@ -66,6 +66,7 @@
 extern int ni52_probe(struct device *);
 extern int ni65_probe(struct device *);
 extern int SK_init(struct device *);
+extern int seeq8005_probe(struct device *);
 
 /* Detachable devices ("pocket adaptors") */
 extern int atp_init(struct device *);
@@ -81,6 +82,9 @@
 	return 1;		/* ENXIO */
 
     if (1
+#if defined(CONFIG_SEEQ8005)
+	&& seeq8005_probe(dev)
+#endif
 #if defined(CONFIG_HP100)
 	&& hp100_probe(dev)
 #endif	
diff -u --recursive --new-file v1.3.8/linux/drivers/net/auto_irq.c linux/drivers/net/auto_irq.c
--- v1.3.8/linux/drivers/net/auto_irq.c	Mon Jan 16 07:17:36 1995
+++ linux/drivers/net/auto_irq.c	Mon Jul 10 08:45:05 1995
@@ -41,14 +41,14 @@
 
 struct device *irq2dev_map[16] = {0, 0, /* ... zeroed */};
 
-int irqs_busy = 0x2147;		/* The set of fixed IRQs (keyboard, timer, etc) */
-int irqs_used = 0x0001;		/* The set of fixed IRQs sometimes enabled. */
-int irqs_reserved = 0x0000;	/* An advisory "reserved" table. */
-int irqs_shared = 0x0000;	/* IRQ lines "shared" among conforming cards.*/
+unsigned long irqs_busy = 0x2147;		/* The set of fixed IRQs (keyboard, timer, etc) */
+unsigned long irqs_used = 0x0001;		/* The set of fixed IRQs sometimes enabled. */
+unsigned long irqs_reserved = 0x0000;		/* An advisory "reserved" table. */
+unsigned long irqs_shared = 0x0000;		/* IRQ lines "shared" among conforming cards.*/
 
-static volatile int irq_number;	/* The latest irq number we actually found. */
-static volatile int irq_bitmap; /* The irqs we actually found. */
-static int irq_handled;		/* The irq lines we have a handler on. */
+static volatile unsigned long irq_bitmap;	/* The irqs we actually found. */
+static unsigned long irq_handled;		/* The irq lines we have a handler on. */
+static volatile int irq_number;			/* The latest irq number we actually found. */
 
 static void autoirq_probe(int irq, struct pt_regs * regs)
 {
diff -u --recursive --new-file v1.3.8/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v1.3.8/linux/drivers/net/lance.c	Fri Jul  7 13:42:57 1995
+++ linux/drivers/net/lance.c	Mon Jul 10 17:08:04 1995
@@ -188,12 +188,13 @@
 };
 
 struct lance_private {
-	char *name;
-	void *pad;
-	/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
+	/* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
+	   This is accomplished by allocating 7 extra bytes for the struct
+	   and adjusting the start of the struct to be 8-byte aligned.  */
 	struct lance_rx_head rx_ring[RX_RING_SIZE];
 	struct lance_tx_head tx_ring[TX_RING_SIZE];
 	struct lance_init_block		init_block;
+	char *name;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct sk_buff* tx_skbuff[TX_RING_SIZE];
 	long rx_buffs;				/* Address of Rx and Tx buffers. */
@@ -206,7 +207,6 @@
 	unsigned char chip_version;			/* See lance_chip_type. */
 	char tx_full;
 	char lock;
-	int pad0, pad1;				/* Used for 8-byte alignment */
 };
 
 #define LANCE_MUST_PAD          0x00000001
@@ -249,6 +249,10 @@
 /* Non-zero only if the current card is a PCI with BIOS-set IRQ. */
 static unsigned char pci_irq_line = 0;
 
+/* Non-zero if lance_probe1() needs to allocate low-memory bounce buffers.
+   Assume yes until we know the memory size. */
+static unsigned char lance_need_isa_bounce_buffers = 1;
+
 static int lance_open(struct device *dev);
 static void lance_init_ring(struct device *dev);
 static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
@@ -272,6 +276,9 @@
 {
 	int *port;
 
+	if (mem_end <= 16*1024*1024)
+		lance_need_isa_bounce_buffers = 0;
+
 #if defined(CONFIG_PCI)
     if (pcibios_present()) {
 	    int pci_index;
@@ -342,7 +349,7 @@
 	   This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com.
 	   */
 	if ( *((unsigned short *) 0x000f0102) == 0x5048)  {
-		short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360};
+		static const short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360};
 		int hp_port = ( *((unsigned char *) 0x000f00f1) & 1)  ? 0x499 : 0x99;
 		/* We can have boards other than the built-in!  Verify this is on-board. */
 		if ((inb(hp_port) & 0xc0) == 0x80
@@ -384,8 +391,12 @@
 		}
 	}
 
-	dev = init_etherdev(0, sizeof(struct lance_private)
-						+ PKT_BUF_SZ*(RX_RING_SIZE + TX_RING_SIZE),
+	dev = init_etherdev(0, 7
+						+ ((sizeof(struct lance_private) + 7) & ~7)
+						+ PKT_BUF_SZ*RX_RING_SIZE
+						+ (lance_need_isa_bounce_buffers
+						   ? PKT_BUF_SZ*TX_RING_SIZE
+						   : 0),
 						&mem_start);
 
 	chipname = chip_table[lance_version].name;
@@ -403,18 +414,10 @@
 	dev->priv = (void *)(((int)dev->priv + 7) & ~7);
 	lp = (struct lance_private *)dev->priv;
 	lp->name = chipname;
-	lp->rx_buffs = (long)dev->priv + sizeof(struct lance_private);
+	lp->rx_buffs = (long)lp + ((sizeof(struct lance_private) + 7) & ~7);
 	lp->tx_bounce_buffs = (char (*)[PKT_BUF_SZ])
 						   (lp->rx_buffs + PKT_BUF_SZ*RX_RING_SIZE);
 
-#ifndef final_version
-	/* This should never happen. */
-	if ((int)(lp->rx_ring) & 0x07) {
-		printk(" **ERROR** LANCE Rx and Tx rings not on even boundary.\n");
-		return mem_start;
-	}
-#endif
-
 	lp->chip_version = lance_version;
 
 	lp->init_block.mode = 0x0003;		/* Disable Rx and Tx. */
@@ -438,15 +441,15 @@
 		dev->dma = 4;			/* Native bus-master, no DMA channel needed. */
 		dev->irq = pci_irq_line;
 	} else if (hp_builtin) {
-		char dma_tbl[4] = {3, 5, 6, 0};
-		char irq_tbl[8] = {3, 4, 5, 9};
+		static const char dma_tbl[4] = {3, 5, 6, 0};
+		static const char irq_tbl[4] = {3, 4, 5, 9};
 		unsigned char port_val = inb(hp_builtin);
 		dev->dma = dma_tbl[(port_val >> 4) & 3];
 		dev->irq = irq_tbl[(port_val >> 2) & 3];
 		printk(" HP Vectra IRQ %d DMA %d.\n", dev->irq, dev->dma);
 	} else if (hpJ2405A) {
-		char dma_tbl[4] = {3, 5, 6, 7};
-		char irq_tbl[8] = {3, 4, 5, 9, 10, 11, 12, 15};
+		static const char dma_tbl[4] = {3, 5, 6, 7};
+		static const char irq_tbl[8] = {3, 4, 5, 9, 10, 11, 12, 15};
 		short reset_val = inw(ioaddr+LANCE_RESET);
 		dev->dma = dma_tbl[(reset_val >> 2) & 3];
 		dev->irq = irq_tbl[(reset_val >> 4) & 7];
@@ -503,10 +506,10 @@
 		} else
 			printk(", assigned DMA %d.\n", dev->dma);
 	} else {			/* OK, we have to auto-DMA. */
-		int dmas[] = { 5, 6, 7, 3 }, boguscnt;
-
 		for (i = 0; i < 4; i++) {
+			static const char dmas[] = { 5, 6, 7, 3 };
 			int dma = dmas[i];
+			int boguscnt;
 
 			/* Don't enable a permanently busy DMA channel, or the machine
 			   will hang. */
@@ -1000,7 +1003,8 @@
 			}
 			skb->dev = dev;
 			skb_reserve(skb,2);	/* 16 byte align */
-			eth_copy_and_sum(skb_put(skb,pkt_len),
+			skb_put(skb,pkt_len);	/* Make room */
+			eth_copy_and_sum(skb,
 				   (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff),
 				   pkt_len,0);
 			skb->protocol=eth_type_trans(skb,dev);
diff -u --recursive --new-file v1.3.8/linux/drivers/net/seeq8005.c linux/drivers/net/seeq8005.c
--- v1.3.8/linux/drivers/net/seeq8005.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/seeq8005.c	Mon Jul 10 17:16:41 1995
@@ -0,0 +1,762 @@
+/* seeq8005.c: A network driver for linux. */
+/*
+	Based on skeleton.c,
+	Written 1993-94 by Donald Becker.
+	See the skeleton.c file for further copyright information.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	The author may be reached as hamish@zot.apana.org.au
+
+	This file is a network device driver for the SEEQ 8005 chipset and
+	the Linux operating system.
+
+*/
+
+static char *version =
+	"seeq8005.c:v1.00 8/07/95 Hamish Coleman (hamish@zot.apana.org.au)\n";
+
+/* Always include 'config.h' first in case the user wants to turn on
+   or override something. */
+#include <linux/config.h>
+
+/*
+  Sources:
+  	SEEQ 8005 databook
+  	
+  Version history:
+  	1.00	Public release. cosmetic changes (no warnings now)
+  	0.68	Turning per- packet,interrupt debug messages off - testing for release.
+  	0.67	timing problems/bad buffer reads seem to be fixed now
+  	0.63	*!@$ protocol=eth_type_trans -- now packets flow
+  	0.56	Send working
+  	0.48	Receive working
+*/
+
+#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 "seeq8005.h"
+extern struct device *init_etherdev(struct device *dev, int sizeof_private,
+									unsigned long *mem_startp);
+
+/* First, a few definitions that the brave might change. */
+/* A zero-terminated list of I/O addresses to be probed. */
+static unsigned int seeq8005_portlist[] =
+   { 0x300, 0x320, 0x340, 0x360, 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;
+
+/* Information that need to be kept for each board. */
+struct net_local {
+	struct enet_statistics stats;
+	unsigned short receive_ptr;		/* What address in packet memory do we expect a recv_pkt_header? */
+	long open_time;				/* Useless example local info. */
+};
+
+/* The station (ethernet) address prefix, used for IDing the board. */
+#define SA_ADDR0 0x00
+#define SA_ADDR1 0x80
+#define SA_ADDR2 0x4b
+
+/* Index to functions, as function prototypes. */
+
+extern int seeq8005_probe(struct device *dev);
+
+static int seeq8005_probe1(struct device *dev, int ioaddr);
+static int seeq8005_open(struct device *dev);
+static int seeq8005_send_packet(struct sk_buff *skb, struct device *dev);
+static void seeq8005_interrupt(int irq, struct pt_regs *regs);
+static void seeq8005_rx(struct device *dev);
+static int seeq8005_close(struct device *dev);
+static struct enet_statistics *seeq8005_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+
+/* Example routines you must write ;->. */
+#define tx_done(dev)	(inw(SEEQ_STATUS) & SEEQSTAT_TX_ON)
+extern void hardware_send_packet(struct device *dev, char *buf, int length);
+extern void seeq8005_init(struct device *dev, int startp);
+inline void wait_for_buffer(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 seeq8005_drv =
+{"seeq8005", seeq8005_probe1, SEEQ8005_IO_EXTENT, seeq8005_portlist};
+#else
+int
+seeq8005_probe(struct device *dev)
+{
+	int i;
+	int base_addr = dev ? dev->base_addr : 0;
+
+	if (base_addr > 0x1ff)		/* Check a single specified location. */
+		return seeq8005_probe1(dev, base_addr);
+	else if (base_addr != 0)	/* Don't probe at all. */
+		return ENXIO;
+
+	for (i = 0; seeq8005_portlist[i]; i++) {
+		int ioaddr = seeq8005_portlist[i];
+		if (check_region(ioaddr, SEEQ8005_IO_EXTENT))
+			continue;
+		if (seeq8005_probe1(dev, ioaddr) == 0)
+			return 0;
+	}
+
+	return ENODEV;
+}
+#endif
+
+/* This is the real probe routine.  Linux has a history of friendly device
+   probes on the ISA bus.  A good device probes avoids doing writes, and
+   verifies that the correct device exists and functions.  */
+
+static int seeq8005_probe1(struct device *dev, int ioaddr)
+{
+	static unsigned version_printed = 0;
+	int i,j;
+	unsigned char SA_prom[32];
+	int old_cfg1;
+	int old_cfg2;
+	int old_stat;
+	int old_dmaar;
+	int old_rear;
+
+	if (net_debug>1)
+		printk("seeq8005: probing at 0x%x\n",ioaddr);
+
+	old_stat = inw(SEEQ_STATUS);					/* read status register */
+	if (old_stat == 0xffff)
+		return ENODEV;						/* assume that 0xffff == no device */
+	if ( (old_stat & 0x1800) != 0x1800 ) {				/* assume that unused bits are 1, as my manual says */
+		if (net_debug>1) {
+			printk("seeq8005: reserved stat bits != 0x1800\n");
+			printk("          == 0x%04x\n",old_stat);
+		}
+	 	return ENODEV;
+	}
+
+	old_rear = inw(SEEQ_REA);
+	if (old_rear == 0xffff) {
+		outw(0,SEEQ_REA);
+		if (inw(SEEQ_REA) == 0xffff) {				/* assume that 0xffff == no device */
+			return ENODEV;
+		}
+	} else if ((old_rear & 0xff00) != 0xff00) {			/* assume that unused bits are 1 */
+		if (net_debug>1) {
+			printk("seeq8005: unused rear bits != 0xff00\n");
+			printk("          == 0x%04x\n",old_rear);
+		}
+		return ENODEV;
+	}
+	
+	old_cfg2 = inw(SEEQ_CFG2);					/* read CFG2 register */
+	old_cfg1 = inw(SEEQ_CFG1);
+	old_dmaar = inw(SEEQ_DMAAR);
+	
+	if (net_debug>4) {
+		printk("seeq8005: stat = 0x%04x\n",old_stat);
+		printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
+		printk("seeq8005: cfg2 = 0x%04x\n",old_cfg2);
+		printk("seeq8005: raer = 0x%04x\n",old_rear);
+		printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
+	}
+	
+	outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);	/* setup for reading PROM */
+	outw( 0, SEEQ_DMAAR);						/* set starting PROM address */
+	outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1);				/* set buffer to look at PROM */
+	
+	
+	j=0;
+	for(i=0; i <32; i++) {
+		j+= SA_prom[i] = inw(SEEQ_BUFFER) & 0xff;
+	}
+
+#if 0
+	/* untested because I only have the one card */
+	if ( (j&0xff) != 0 ) {						/* checksum appears to be 8bit = 0 */
+		if (net_debug>1) {					/* check this before deciding that we have a card */
+			printk("seeq8005: prom sum error\n");
+		}
+		outw( old_stat, SEEQ_STATUS);
+		outw( old_dmaar, SEEQ_DMAAR);
+		outw( old_cfg1, SEEQ_CFG1);
+		return ENODEV;
+	}
+#endif
+
+	outw( SEEQCFG2_RESET, SEEQ_CFG2);				/* reset the card */
+	SLOW_DOWN_IO;							/* have to wait 4us after a reset - should be fixed */
+	SLOW_DOWN_IO;
+	SLOW_DOWN_IO;
+	SLOW_DOWN_IO;
+	outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+	
+	if (net_debug) {
+		printk("seeq8005: prom sum = 0x%08x\n",j);
+		for(j=0; j<32; j+=16) {
+			printk("seeq8005: prom %02x: ",j);
+			for(i=0;i<16;i++) {
+				printk("%02x ",SA_prom[j|i]);
+			}
+			printk(" ");
+			for(i=0;i<16;i++) {
+				if ((SA_prom[j|i]>31)&&(SA_prom[j|i]<127)) {
+					printk("%c", SA_prom[j|i]);
+				} else {
+					printk(" ");
+				}
+			}
+			printk("\n");
+		}
+	}
+
+#if 0	
+	/* 
+	 * testing the packet buffer memory doesnt work yet
+	 * but all other buffer accesses do 
+	 *			- fixing is not a priority
+	 */
+	if (net_debug>1) {					/* test packet buffer memory */
+		printk("seeq8005: testing packet buffer ... ");
+		outw( SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
+		outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+		outw( 0 , SEEQ_DMAAR);
+		for(i=0;i<32768;i++) {
+			outw(0x5a5a, SEEQ_BUFFER);
+		}
+		j=jiffies+HZ;
+		while ( ((inw(SEEQ_STATUS) & SEEQSTAT_FIFO_EMPTY) != SEEQSTAT_FIFO_EMPTY) && jiffies < j )
+			mb();
+		outw( 0 , SEEQ_DMAAR);
+		while ( ((inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && jiffies < j+HZ)
+			mb();
+		if ( (inw(SEEQ_STATUS) & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
+			outw( SEEQCMD_WINDOW_INT_ACK | (inw(SEEQ_STATUS)& SEEQCMD_INT_MASK), SEEQ_CMD);
+		outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+		j=0;
+		for(i=0;i<32768;i++) {
+			if (inw(SEEQ_BUFFER) != 0x5a5a)
+				j++;
+		}
+		if (j) {
+			printk("%i\n",j);
+		} else {
+			printk("ok.\n");
+		}
+	}
+#endif
+
+	/* Allocate a new 'dev' if needed. */
+	if (dev == NULL)
+		dev = init_etherdev(0, sizeof(struct net_local), 0);
+
+	if (net_debug  &&  version_printed++ == 0)
+		printk(version);
+
+	printk("%s: %s found at %#3x, ", dev->name, "seeq8005", ioaddr);
+
+	/* Fill in the 'dev' fields. */
+	dev->base_addr = ioaddr;
+
+	/* Retrieve and print the ethernet address. */
+	for (i = 0; i < 6; i++)
+		printk(" %2.2x", dev->dev_addr[i] = SA_prom[i+6]);
+
+	if (dev->irq == 0xff)
+		;			/* Do nothing: a user-level program will set it. */
+	else if (dev->irq < 2) {	/* "Auto-IRQ" */
+		autoirq_setup(0);
+		
+		outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
+
+		dev->irq = autoirq_report(0);
+		
+		if (net_debug >= 2)
+			printk(" autoirq is %d\n", dev->irq);
+	} else if (dev->irq == 2)
+	  /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
+	   * or don't know which one to set. 
+	   */
+	  dev->irq = 9;
+
+#if 0
+	{
+		 int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005");
+		 if (irqval) {
+			 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
+					 dev->irq, irqval);
+			 return EAGAIN;
+		 }
+	}
+#endif
+
+	/* Grab the region so we can find another board if autoIRQ fails. */
+	request_region(ioaddr, SEEQ8005_IO_EXTENT,"seeq8005");
+
+	/* Initialize the device structure. */
+	if (dev->priv == NULL)
+		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct net_local));
+
+	dev->open		= seeq8005_open;
+	dev->stop		= seeq8005_close;
+	dev->hard_start_xmit = seeq8005_send_packet;
+	dev->get_stats	= seeq8005_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	return 0;
+}
+
+
+/* Open/initialize the board.  This is called (in the current kernel)
+   sometime after booting when the 'ifconfig' program is run.
+
+   This routine should set everything up anew at each open, even
+   registers that "should" only need to be set once at boot, so that
+   there is non-reboot way to recover if something goes wrong.
+   */
+static int
+seeq8005_open(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	{
+		 int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005");
+		 if (irqval) {
+			 printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
+					 dev->irq, irqval);
+			 return EAGAIN;
+		 }
+	}
+	irq2dev_map[dev->irq] = dev;
+
+	/* Reset the hardware here.  Don't forget to set the station address. */
+	seeq8005_init(dev, 1);
+
+	lp->open_time = jiffies;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+	return 0;
+}
+
+static int
+seeq8005_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	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 < 5)
+			return 1;
+		printk("%s: transmit timed out, %s?\n", dev->name,
+			   tx_done(dev) ? "IRQ conflict" : "network cable problem");
+		/* Try to restart the adaptor. */
+		seeq8005_init(dev, 1);
+		dev->tbusy=0;
+		dev->trans_start = jiffies;
+	}
+
+	/* 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;
+
+		hardware_send_packet(dev, buf, length); 
+		dev->trans_start = jiffies;
+	}
+	dev_kfree_skb (skb, FREE_WRITE);
+
+	/* You might need to clean up and record Tx statistics here. */
+
+	return 0;
+}
+
+/* The typical workload of the driver:
+   Handle the network interface interrupts. */
+static void
+seeq8005_interrupt(int irq, struct pt_regs * regs)
+{
+	struct device *dev = (struct device *)(irq2dev_map[irq]);
+	struct net_local *lp;
+	int ioaddr, status, boguscount = 0;
+
+	if (dev == NULL) {
+		printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+	
+	if (dev->interrupt)
+		printk ("%s: Re-entering the interrupt handler.\n", dev->name);
+	dev->interrupt = 1;
+
+	ioaddr = dev->base_addr;
+	lp = (struct net_local *)dev->priv;
+
+	status = inw(SEEQ_STATUS);
+	do {
+		if (net_debug >2) {
+			printk("%s: int, status=0x%04x\n",dev->name,status);
+		}
+		
+		if (status & SEEQSTAT_WINDOW_INT) {
+			outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+			if (net_debug) {
+				printk("%s: window int!\n",dev->name);
+			}
+		}
+		if (status & SEEQSTAT_TX_INT) {
+			outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+			lp->stats.tx_packets++;
+			dev->tbusy = 0;
+			mark_bh(NET_BH);	/* Inform upper layers. */
+		}
+		if (status & SEEQSTAT_RX_INT) {
+			/* Got a packet(s). */
+			seeq8005_rx(dev);
+		}
+		status = inw(SEEQ_STATUS);
+	} while ( (++boguscount < 10) && (status & SEEQSTAT_ANY_INT)) ;
+
+	if(net_debug>2) {
+		printk("%s: eoi\n",dev->name);
+	}
+	dev->interrupt = 0;
+	return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+seeq8005_rx(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int boguscount = 10;
+	int pkt_hdr;
+	int ioaddr = dev->base_addr;
+
+	do {
+		int next_packet;
+		int pkt_len;
+		int i;
+		int status;
+
+		status = inw(SEEQ_STATUS);
+	  	outw( lp->receive_ptr, SEEQ_DMAAR);
+		outw(SEEQCMD_FIFO_READ | SEEQCMD_RX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+	  	wait_for_buffer(dev);
+	  	next_packet = ntohs(inw(SEEQ_BUFFER));
+	  	pkt_hdr = inw(SEEQ_BUFFER);
+	  	
+		if (net_debug>2) {
+			printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
+		}
+			
+		if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) {	/* Read all the frames? */
+			return;							/* Done for now */
+		}
+			
+		if ((pkt_hdr & SEEQPKTS_DONE)==0)
+			break;
+			
+		if (next_packet < lp->receive_ptr) {
+			pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
+		} else {
+			pkt_len = next_packet - lp->receive_ptr - 4;
+		}
+		
+		if (next_packet < ((DEFAULT_TEA+1)<<8)) {			/* is the next_packet address sane? */
+			printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
+			seeq8005_init(dev,1);
+			return;
+		}
+		
+		lp->receive_ptr = next_packet;
+		
+		if (net_debug>2) {
+			printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
+		}
+
+		if (pkt_hdr & SEEQPKTS_ANY_ERROR) {				/* There was an error. */
+			lp->stats.rx_errors++;
+			if (pkt_hdr & SEEQPKTS_SHORT) lp->stats.rx_frame_errors++;
+			if (pkt_hdr & SEEQPKTS_DRIB) lp->stats.rx_frame_errors++;
+			if (pkt_hdr & SEEQPKTS_OVERSIZE) lp->stats.rx_over_errors++;
+			if (pkt_hdr & SEEQPKTS_CRC_ERR) lp->stats.rx_crc_errors++;
+			/* skip over this packet */
+			outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+			outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
+		} else {
+			/* Malloc up new buffer. */
+			struct sk_buff *skb;
+			unsigned char *buf;
+
+			skb = dev_alloc_skb(pkt_len);
+			if (skb == NULL) {
+				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+				lp->stats.rx_dropped++;
+				break;
+			}
+			skb->dev = dev;
+			skb_reserve(skb, 2);	/* align data on 16 byte */
+			buf = skb_put(skb,pkt_len);
+			
+			insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
+			
+			if (net_debug>2) {
+				char * p = buf;
+				printk("%s: recv ",dev->name);
+				for(i=0;i<14;i++) {
+					printk("%02x ",*(p++)&0xff);
+				}
+				printk("\n");
+			}
+
+			skb->protocol=eth_type_trans(skb,dev);
+			netif_rx(skb);
+			lp->stats.rx_packets++;
+		}
+	} while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
+
+	/* If any worth-while packets have been received, netif_rx()
+	   has done a mark_bh(NET_BH) for us and will work on them
+	   when we get to the bottom-half routine. */
+	return;
+}
+
+/* The inverse routine to net_open(). */
+static int
+seeq8005_close(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+
+	lp->open_time = 0;
+
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	/* Flush the Tx and disable Rx here. */
+	outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+
+	free_irq(dev->irq);
+
+	irq2dev_map[dev->irq] = 0;
+
+	/* Update the statistics here. */
+
+	return 0;
+
+}
+
+/* Get the current statistics.	This may be called with the card open or
+   closed. */
+static struct enet_statistics *
+seeq8005_get_stats(struct device *dev)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+
+	return &lp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1	Promiscuous mode, receive all packets
+   num_addrs == 0	Normal mode, clear multicast list
+   num_addrs > 0	Multicast mode, receive normal and MC packets, and do
+			best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+/*
+ * I _could_ do upto 6 addresses here, but wont (yet?)
+ */
+
+#if 0
+	int ioaddr = dev->base_addr;
+/*
+ * hmm, not even sure if my matching works _anyway_ - seem to be receiving
+ * _everything_ . . .
+ */
+ 
+	if (num_addrs) {			/* Enable promiscuous mode */
+		outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL,  SEEQ_CFG1);
+	} else {				/* Disable promiscuous mode, use normal mode */
+		outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_BROAD, SEEQ_CFG1);
+	}
+#endif
+}
+
+void seeq8005_init(struct device *dev, int startp)
+{
+	struct net_local *lp = (struct net_local *)dev->priv;
+	int ioaddr = dev->base_addr;
+	int i;
+	
+	outw(SEEQCFG2_RESET, SEEQ_CFG2);	/* reset device */
+	SLOW_DOWN_IO;				/* have to wait 4us after a reset - should be fixed */
+	SLOW_DOWN_IO;
+	SLOW_DOWN_IO;
+	SLOW_DOWN_IO;
+	
+	outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+	outw( 0, SEEQ_DMAAR);			/* load start address into both low and high byte */
+/*	wait_for_buffer(dev); */		/* I think that you only need a wait for memory buffer */
+	outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
+	
+	for(i=0;i<6;i++) {			/* set Station address */
+		outb(dev->dev_addr[i], SEEQ_BUFFER);
+		SLOW_DOWN_IO;
+	}
+	
+	outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1);	/* set xmit end area pointer to 16K */
+	outb( DEFAULT_TEA, SEEQ_BUFFER);	/* this gives us 16K of send buffer and 48K of recv buffer */
+	
+	lp->receive_ptr = (DEFAULT_TEA+1)<<8;	/* so we can find our packet_header */
+	outw( lp->receive_ptr, SEEQ_RPR);	/* Receive Pointer Register is set to recv buffer memory */
+	
+	outw( 0x00ff, SEEQ_REA);		/* Receive Area End */
+
+	if (net_debug>4) {
+		printk("%s: SA0 = ",dev->name);
+
+		outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
+		outw( 0, SEEQ_DMAAR);
+		outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
+		
+		for(i=0;i<6;i++) {
+			printk("%02x ",inb(SEEQ_BUFFER));
+		}
+		printk("\n");
+	}
+	
+	outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
+	outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
+	outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
+
+	if (net_debug>4) {
+		int old_cfg1;
+		old_cfg1 = inw(SEEQ_CFG1);
+		printk("%s: stat = 0x%04x\n",dev->name,inw(SEEQ_STATUS));
+		printk("%s: cfg1 = 0x%04x\n",dev->name,old_cfg1);
+		printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
+		printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
+		printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
+		
+	}
+}	
+
+
+void hardware_send_packet(struct device * dev, char *buf, int length)
+{
+	int ioaddr = dev->base_addr;
+	int status = inw(SEEQ_STATUS);
+	int transmit_ptr = 0;
+	int tmp;
+
+	if (net_debug>4) {
+		printk("%s: send 0x%04x\n",dev->name,length);
+	}
+	
+	/* Set FIFO to writemode and set packet-buffer address */
+	outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+	outw( transmit_ptr, SEEQ_DMAAR);
+	
+	/* output SEEQ Packet header barfage */
+	outw( htons(length + 4), SEEQ_BUFFER);
+	outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
+	
+	/* blat the buffer */
+	outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
+	/* paranoia !! */
+	outw( 0, SEEQ_BUFFER);
+	outw( 0, SEEQ_BUFFER);
+	
+	/* set address of start of transmit chain */
+	outw( transmit_ptr, SEEQ_TPR);
+	
+	/* drain FIFO */
+	tmp = jiffies;
+	while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && (jiffies < tmp + HZ))
+		mb();
+	
+	/* doit ! */
+	outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+	
+}
+
+
+/*
+ * wait_for_buffer
+ *
+ * This routine waits for the SEEQ chip to assert that the FIFO is ready
+ * by checking for a window interrupt, and then clearing it
+ */
+inline void wait_for_buffer(struct device * dev)
+{
+	int ioaddr = dev->base_addr;
+	int tmp;
+	int status;
+	
+	tmp = jiffies + HZ;
+	while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && jiffies < tmp)
+		mb();
+		
+	if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
+		outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
+}
+	
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
+ *  version-control: t
+ *  kept-new-versions: 5
+ *  tab-width: 4
+ * End:
+ */
diff -u --recursive --new-file v1.3.8/linux/drivers/net/seeq8005.h linux/drivers/net/seeq8005.h
--- v1.3.8/linux/drivers/net/seeq8005.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/seeq8005.h	Mon Jul 10 17:08:04 1995
@@ -0,0 +1,156 @@
+/* 
+ * defines, etc for the seeq8005
+ */
+ 
+/*
+ * This file is distributed under GPL.
+ *
+ * This style and layout of this file is also copied
+ * from many of the other linux network device drivers.
+ */
+
+/* The number of low I/O ports used by the ethercard. */
+#define SEEQ8005_IO_EXTENT	16
+
+#define SEEQ_B		(ioaddr)
+
+#define	SEEQ_CMD	(SEEQ_B)		/* Write only */
+#define	SEEQ_STATUS	(SEEQ_B)		/* Read only */
+#define SEEQ_CFG1	(SEEQ_B + 2)
+#define SEEQ_CFG2	(SEEQ_B + 4)
+#define	SEEQ_REA	(SEEQ_B + 6)		/* Receive End Area Register */
+#define SEEQ_RPR	(SEEQ_B + 10)		/* Receive Pointer Register */
+#define	SEEQ_TPR	(SEEQ_B + 12)		/* Transmit Pointer Register */
+#define	SEEQ_DMAAR	(SEEQ_B + 14)		/* DMA Address Register */
+#define SEEQ_BUFFER	(SEEQ_B + 8)		/* Buffer Window Register */
+
+#define	DEFAULT_TEA	(0x3f)
+
+#define SEEQCMD_DMA_INT_EN	(0x0001)	/* DMA Interrupt Enable */
+#define SEEQCMD_RX_INT_EN	(0x0002)	/* Receive Interrupt Enable */
+#define SEEQCMD_TX_INT_EN	(0x0004)	/* Transmit Interrupt Enable */
+#define SEEQCMD_WINDOW_INT_EN	(0x0008)	/* What the hell is this for?? */
+#define SEEQCMD_INT_MASK	(0x000f)
+
+#define SEEQCMD_DMA_INT_ACK	(0x0010)	/* DMA ack */
+#define SEEQCMD_RX_INT_ACK	(0x0020)
+#define SEEQCMD_TX_INT_ACK	(0x0040)
+#define	SEEQCMD_WINDOW_INT_ACK	(0x0080)
+#define SEEQCMD_ACK_ALL		(0x00f0)
+
+#define SEEQCMD_SET_DMA_ON	(0x0100)	/* Enables DMA Request logic */
+#define SEEQCMD_SET_RX_ON	(0x0200)	/* Enables Packet RX */
+#define SEEQCMD_SET_TX_ON	(0x0400)	/* Starts TX run */
+#define SEEQCMD_SET_DMA_OFF	(0x0800)
+#define SEEQCMD_SET_RX_OFF	(0x1000)
+#define SEEQCMD_SET_TX_OFF	(0x2000)
+#define SEEQCMD_SET_ALL_OFF	(0x3800)	/* set all logic off */
+
+#define SEEQCMD_FIFO_READ	(0x4000)	/* Set FIFO to read mode (read from Buffer) */
+#define SEEQCMD_FIFO_WRITE	(0x8000)	/* Set FIFO to write mode */
+
+#define SEEQSTAT_DMA_INT_EN	(0x0001)	/* Status of interrupt enable */
+#define SEEQSTAT_RX_INT_EN	(0x0002)
+#define SEEQSTAT_TX_INT_EN	(0x0004)
+#define SEEQSTAT_WINDOW_INT_EN	(0x0008)
+
+#define	SEEQSTAT_DMA_INT	(0x0010)	/* Interrupt flagged */
+#define SEEQSTAT_RX_INT		(0x0020)
+#define SEEQSTAT_TX_INT		(0x0040)
+#define	SEEQSTAT_WINDOW_INT	(0x0080)
+#define SEEQSTAT_ANY_INT	(0x00f0)
+
+#define SEEQSTAT_DMA_ON		(0x0100)	/* DMA logic on */
+#define SEEQSTAT_RX_ON		(0x0200)	/* Packet RX on */
+#define SEEQSTAT_TX_ON		(0x0400)	/* TX running */
+
+#define SEEQSTAT_FIFO_FULL	(0x2000)
+#define SEEQSTAT_FIFO_EMPTY	(0x4000)
+#define SEEQSTAT_FIFO_DIR	(0x8000)	/* 1=read, 0=write */
+
+#define SEEQCFG1_BUFFER_MASK	(0x000f)	/* define what mapps into the BUFFER register */
+#define SEEQCFG1_BUFFER_MAC0	(0x0000)	/* MAC station addresses 0-5 */
+#define SEEQCFG1_BUFFER_MAC1	(0x0001)
+#define SEEQCFG1_BUFFER_MAC2	(0x0002)
+#define SEEQCFG1_BUFFER_MAC3	(0x0003)
+#define SEEQCFG1_BUFFER_MAC4	(0x0004)
+#define SEEQCFG1_BUFFER_MAC5	(0x0005)
+#define SEEQCFG1_BUFFER_PROM	(0x0006)	/* The Address/CFG PROM */
+#define SEEQCFG1_BUFFER_TEA	(0x0007)	/* Transmit end area */
+#define SEEQCFG1_BUFFER_BUFFER	(0x0008)	/* Packet buffer memory */
+#define SEEQCFG1_BUFFER_INT_VEC	(0x0009)	/* Interrupt Vector */
+
+#define SEEQCFG1_DMA_INTVL_MASK	(0x0030)
+#define SEEQCFG1_DMA_CONT	(0x0000)
+#define SEEQCFG1_DMA_800ns	(0x0010)
+#define SEEQCFG1_DMA_1600ns	(0x0020)
+#define SEEQCFG1_DMA_3200ns	(0x0030)
+
+#define SEEQCFG1_DMA_LEN_MASK	(0x00c0)
+#define SEEQCFG1_DMA_LEN1	(0x0000)
+#define SEEQCFG1_DMA_LEN2	(0x0040)
+#define SEEQCFG1_DMA_LEN4	(0x0080)
+#define SEEQCFG1_DMA_LEN8	(0x00c0)
+
+#define SEEQCFG1_MAC_MASK	(0x3f00)	/* Dis/enable bits for MAC addresses */
+#define SEEQCFG1_MAC0_EN	(0x0100)
+#define SEEQCFG1_MAC1_EN	(0x0200)
+#define SEEQCFG1_MAC2_EN	(0x0400)
+#define SEEQCFG1_MAC3_EN	(0x0800)
+#define	SEEQCFG1_MAC4_EN	(0x1000)
+#define SEEQCFG1_MAC5_EN	(0x2000)
+
+#define	SEEQCFG1_MATCH_MASK	(0xc000)	/* Packet matching logic cfg bits */
+#define SEEQCFG1_MATCH_SPECIFIC	(0x0000)	/* only matching MAC addresses */
+#define SEEQCFG1_MATCH_BROAD	(0x4000)	/* matching and broadcast addresses */
+#define SEEQCFG1_MATCH_MULTI	(0x8000)	/* matching, broadcast and multicast */
+#define SEEQCFG1_MATCH_ALL	(0xc000)	/* Promiscuous mode */
+
+#define SEEQCFG1_DEFAULT	(SEEQCFG1_BUFFER_BUFFER | SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD)
+
+#define SEEQCFG2_BYTE_SWAP	(0x0001)	/* 0=Intel byte-order */
+#define SEEQCFG2_AUTO_REA	(0x0002)	/* if set, Receive End Area will be updated when reading from Buffer */
+
+#define SEEQCFG2_CRC_ERR_EN	(0x0008)	/* enables receiving of packets with CRC errors */
+#define SEEQCFG2_DRIBBLE_EN	(0x0010)	/* enables receiving of non-aligned packets */
+#define SEEQCFG2_SHORT_EN	(0x0020)	/* enables receiving of short packets */
+
+#define	SEEQCFG2_SLOTSEL	(0x0040)	/* 0= standard IEEE802.3, 1= smaller,faster, non-standard */
+#define SEEQCFG2_NO_PREAM	(0x0080)	/* 1= user supplies Xmit preamble bytes */
+#define SEEQCFG2_ADDR_LEN	(0x0100)	/* 1= 2byte addresses */
+#define SEEQCFG2_REC_CRC	(0x0200)	/* 0= recieved packets will have CRC stripped from them */
+#define SEEQCFG2_XMIT_NO_CRC	(0x0400)	/* dont xmit CRC with each packet (user supplies it) */
+#define SEEQCFG2_LOOPBACK	(0x0800)
+#define SEEQCFG2_CTRLO		(0x1000)
+#define SEEQCFG2_RESET		(0x8000)	/* software Hard-reset bit */
+
+struct seeq_pkt_hdr {
+	unsigned short	next;			/* address of next packet header */
+	unsigned char	babble_int:1,		/* enable int on >1514 byte packet */
+			coll_int:1,		/* enable int on collision */
+			coll_16_int:1,		/* enable int on >15 collision */
+			xmit_int:1,		/* enable int on success (or xmit with <15 collision) */
+			unused:1,
+			data_follows:1,		/* if not set, process this as a header and pointer only */
+			chain_cont:1,		/* if set, more headers in chain 		only cmd bit valid in recv header */
+			xmit_recv:1;		/* if set, a xmit packet, else a recieve packet.*/
+	unsigned char	status;
+};
+
+#define SEEQPKTH_BAB_INT_EN	(0x01)		/* xmit only */
+#define SEEQPKTH_COL_INT_EN	(0x02)		/* xmit only */
+#define SEEQPKTH_COL16_INT_EN	(0x04)		/* xmit only */
+#define SEEQPKTH_XMIT_INT_EN	(0x08)		/* xmit only */
+#define SEEQPKTH_DATA_FOLLOWS	(0x20)		/* supposedly in xmit only */
+#define SEEQPKTH_CHAIN		(0x40)		/* more headers follow */
+#define SEEQPKTH_XMIT		(0x80)
+
+#define SEEQPKTS_BABBLE		(0x0100)	/* xmit only */
+#define SEEQPKTS_OVERSIZE	(0x0100)	/* recv only */
+#define SEEQPKTS_COLLISION	(0x0200)	/* xmit only */
+#define SEEQPKTS_CRC_ERR	(0x0200)	/* recv only */
+#define SEEQPKTS_COLL16		(0x0400)	/* xmit only */
+#define SEEQPKTS_DRIB		(0x0400)	/* recv only */
+#define SEEQPKTS_SHORT		(0x0800)	/* recv only */
+#define SEEQPKTS_DONE		(0x8000)
+#define SEEQPKTS_ANY_ERROR	(0x0f00)
diff -u --recursive --new-file v1.3.8/linux/drivers/pci/Makefile linux/drivers/pci/Makefile
--- v1.3.8/linux/drivers/pci/Makefile	Wed Jun  7 13:03:54 1995
+++ linux/drivers/pci/Makefile	Tue Jul 11 08:02:20 1995
@@ -9,8 +9,6 @@
 # parent makefile.
 #
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
@@ -30,11 +28,5 @@
 	$(CPP) -M $(SRCS) > .depend
 
 modules:
-dummy:
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v1.3.8/linux/drivers/pci/pci.c	Thu Jun 29 19:02:42 1995
+++ linux/drivers/pci/pci.c	Mon Jul 10 17:08:03 1995
@@ -74,6 +74,8 @@
 	DEVICE( INTEL,		INTEL_82430,	"82430ZX Aries"),
 	DEVICE( INTEL,		INTEL_82437,	"82437 Triton"),
 	DEVICE( INTEL,		INTEL_82371,	"82471 Triton"),
+	DEVICE( INTEL,		INTEL_82438,	"82438"),
+	DEVICE( INTEL,		INTEL_7116,	"SAA7116"),
 	DEVICE( SMC,		SMC_37C665,	"FDC 37C665"),
 	DEVICE( ATI,		ATI_M32,	"Mach 32"),
 	DEVICE( ATI,		ATI_M64,	"Mach 64"),
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v1.3.8/linux/drivers/scsi/Makefile	Fri Jul  7 08:54:48 1995
+++ linux/drivers/scsi/Makefile	Tue Jul 11 08:02:20 1995
@@ -6,8 +6,6 @@
 # unless it's something special (ie not a .c file).
 #
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
@@ -264,13 +262,10 @@
 	(cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done)
 
 dep:	$(SCSI_DEP)
-	$(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend
-	$(CPP) -M -DMODULE $(patsubst sd_mod.c,sd.c sd_ioctl.c, \
-			   $(patsubst sr_mod.c,sr.c sr_ioctl.c, $(SCSI_MODULE_OBJS:.o=.c))) >> .depend
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+	$(CPP) -M $(AHA152X) constants.c $(SCSI_OBJS:.o=.c) > .depend
+	$(CPP) -M -DMODULE $(patsubst scsi_mod.c,scsi.c hosts.c scsi_ioctl.c \
+					constants.c scsicam.c scsi_proc.c, \
+			   $(patsubst sd_mod.c,sd.c sd_ioctl.c, \
+			   $(patsubst sr_mod.c,sr.c sr_ioctl.c, $(SCSI_MODULE_OBJS:.o=.c)))) >> .depend
+
+include $(TOPDIR)/Rules.make
Binary files v1.3.8/linux/drivers/scsi/aic7770 and linux/drivers/scsi/aic7770 differ
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/eata_dma_proc.c linux/drivers/scsi/eata_dma_proc.c
--- v1.3.8/linux/drivers/scsi/eata_dma_proc.c	Thu Jun 29 19:02:49 1995
+++ linux/drivers/scsi/eata_dma_proc.c	Tue Jul 11 07:56:04 1995
@@ -23,12 +23,12 @@
     u8 *bp;
     
     lp = (u32 *)p;
-    sp = ((short *)lp) + 1;         /* Convert Header */
+    sp = ((short *)lp) + 1;	    /* Convert Header */
     h_sp = *sp = ntohs(*sp);
     lp++;
 
     do {
-	sp = (u16 *)lp;           /* Convert SubHeader */
+	sp = (u16 *)lp;		  /* Convert SubHeader */
     *sp = ntohs(*sp);
     bp = (u8 *) lp;
     y = *(bp + 3);
@@ -53,13 +53,17 @@
 
 /*
  * eata_proc_info
- * inout : decides on the direction of the dataflow and the meaning of the variables
+ * inout : decides on the direction of the dataflow and the meaning of the 
+ *         variables
  * buffer: If inout==FALSE data is beeing written to it else read from it
  * *start: If inout==FALSE start of the valid data in the buffer
- * offset: If inout==FALSE offset from the beginning of the imaginary file from which we start writing into the buffer
- * length: If inout==FALSE max number of bytes to be written into the buffer else number of bytes in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file 
+ *         from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer 
+ *         else number of bytes in the buffer
  */
-int eata_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+int eata_proc_info(char *buffer, char **start, off_t offset, int length, 
+                   int hostno, int inout)
 {
 
     Scsi_Device *scd;
@@ -89,7 +93,7 @@
 	if (HBA_ptr->host_no == hostno)
 	    break;
 	HBA_ptr = SD(HBA_ptr)->next;
-    }        
+    }	     
 
     if(inout == TRUE) /* Has data been writen to the file ? */ 
 	return(eata_set_info(buffer, length, HBA_ptr));
@@ -116,35 +120,6 @@
 		   "processed interrupts:%10ld\n", queue_counter, int_counter);
     len += size; pos = begin + len;
 
-    if(SD(HBA_ptr)->bustype == IS_EISA)
-	goto devices;
-    
-    scmd.cmnd[0] = LOG_SENSE;
-    scmd.cmnd[1] = 0;
-    scmd.cmnd[2] = 0x33 + (3<<6);
-    scmd.cmnd[3] = 0;
-    scmd.cmnd[4] = 0;
-    scmd.cmnd[5] = 0;
-    scmd.cmnd[6] = 0;
-    scmd.cmnd[7] = 0x00;
-    scmd.cmnd[8] = 0x66;
-    scmd.cmnd[9] = 0;
-    scmd.cmd_len = 10;
-    
-    scmd.host = HBA_ptr; 
-    scmd.target = HBA_ptr->this_id; 
-    scmd.lun = 0; 
-    scmd.channel = 0;
-    
-    scmd.use_sg = 0;
-    scmd.request_bufflen = 0x66;
-    scmd.request_buffer = buff + 0x144;
-    HBA_interpret = TRUE;
-    
-    eata_queue(&scmd, (void *) eata_scsi_done);
-    while (internal_command_finished == FALSE)
-	barrier();
-    
     size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
 		   HBA_ptr->host_no, SD(HBA_ptr)->name);
     len += size; 
@@ -156,164 +131,208 @@
     size = sprintf(buffer + len, "Hardware Configuration:\n");
     len += size; 
     pos = begin + len;
-    size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt,
-		   (cc->intt == TRUE)?"level":"edge");
-    len += size; 
-    pos = begin + len;
-    if (HBA_ptr->dma_channel == 0xff)
-	size = sprintf(buffer + len, "DMA: BUSMASTER\n");
-    else
-	size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel);
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "CPU: MC680%02d %dMHz\n", bt->cpu_type,
-		   bt->cpu_speed);
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "Host Bus: %s\n", 
-		   (SD(HBA_ptr)->bustype == IS_PCI)?"PCI ":
-		   (SD(HBA_ptr)->bustype == IS_EISA)?"EISA":"ISA ");
     
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "SCSI Bus:%s%s Speed: %sMB/sec. %s\n",
-		   (sb->wide == TRUE)?" WIDE":"", 
-		   (sb->dif == TRUE)?" DIFFERENTIAL":"",
-		   (sb->speed == 0)?"5":(sb->speed == 1)?"10":"20",
-		   (sb->ext == TRUE)?"With external cable detection":"");
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "SCSI channel expansion Module: %s installed\n",
-		   (bt->sx1 == TRUE)?"SX1 (one channel)":
-		   ((bt->sx2 == TRUE)?"SX2 (two channels)":"not"));
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "SmartRAID hardware: %spresent.\n",
-		   (cc->srs == TRUE)?"":"not ");
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "    Type: %s\n",
-		   ((cc->key == TRUE)?((bt->dmi == TRUE)?"integrated"
-				       :((bt->dm4 == TRUE)?"DM401X"
-				       :(bt->dm4k == TRUE)?"DM4000"
-				       :"-"))
-				       :"-"));
-    len += size; 
-    pos = begin + len;
-    
-    size = sprintf(buffer + len, "    Max array groups:              %d\n",
-		   (al->code == 0x0e)?al->max_groups:7);
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "    Max drives per RAID 0 array:   %d\n",
-		   (al->code == 0x0e)?al->raid0_drv:7);
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "    Max drives per RAID 3/5 array: %d\n",
-		   (al->code == 0x0e)?al->raid35_drv:7);
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "Cache Module: %sinstalled.\n",
-		   (cc->csh)?"":"not ");
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "    Type: %s\n",
-		   ((cc->csh == TRUE)?((bt->cmi == TRUE)?"integrated"
-				       :((bt->cm4 == TRUE)?"CM401X"
-				       :((bt->cm4k == TRUE)?"CM4000"
-				       :"-")))
-				       :"-"));
-    len += size; 
-    pos = begin + len;
-    for (x = 0; x <= 3; x++) {
-	size = sprintf(buffer + len, "    Bank%d: %dMB with%s ECC\n",x,
-		       mc->banksize[x] & 0x7f, 
-		       (mc->banksize[x] & 0x80)?"":"out");
-	len += size; 
-	pos = begin + len;      
-    }   
-    size = sprintf(buffer + len, "Timer Modification: %sinstalled\n",
-		   (cc->tmr == TRUE)?"":"not ");
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "NVRAM: %spresent\n",
-		   (cc->nvr == TRUE)?"":"not ");
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "SmartROM: %senabled\n",
-		   (bt->srom == TRUE)?"not ":"");
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer + len, "HBA indicates %salarm.\n",
-		   (bt->alrm == TRUE)?"":"no ");
-    len += size; 
-    pos = begin + len;
-    
-    if (pos < offset) {
-	len = 0;
-	begin = pos;
-    }
-    if (pos > offset + length)
-	goto stop_output; 
-    
-    scmd.cmnd[0] = LOG_SENSE;
-    scmd.cmnd[1] = 0;
-    scmd.cmnd[2] = 0x32 + (3<<6); 
-    scmd.cmnd[3] = 0;
-    scmd.cmnd[4] = 0;
-    scmd.cmnd[5] = 0;
-    scmd.cmnd[6] = 0;
-    scmd.cmnd[7] = 0x01;
-    scmd.cmnd[8] = 0x44;
-    scmd.cmnd[9] = 0;
-    scmd.cmd_len = 10;
-    scmd.host = HBA_ptr; 
-    scmd.target = HBA_ptr->this_id; 
-    scmd.lun = 0; 
-    scmd.channel = 0;
-    scmd.use_sg = 0;
-    scmd.request_bufflen = 0x144;
-    scmd.request_buffer = buff2;
-    HBA_interpret = TRUE;
-    
-    eata_queue(&scmd, (void *) eata_scsi_done);
-    while (internal_command_finished == FALSE)
-	barrier();
-    
-    swap_statistics(buff2);
-    rhcs = (hst_cmd_stat *)(buff2 + 0x2c); 
-    whcs = (hst_cmd_stat *)(buff2 + 0x8c);           
-    
-    for (x = 0; x <= 11; x++) {
-	SD(HBA_ptr)->reads[x] += rhcs->sizes[x];
-	SD(HBA_ptr)->writes[x] += whcs->sizes[x];
-	SD(HBA_ptr)->reads[12] += rhcs->sizes[x];
-	SD(HBA_ptr)->writes[12] += whcs->sizes[x];
-    }
-    size = sprintf(buffer + len, "Host Disk Command Statistics:\n"
-		   "         Reads:      Writes:\n");
-    len += size; 
-    pos = begin + len;
-    for (x = 0; x <= 10; x++) {
-	size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x,
-		       SD(HBA_ptr)->reads[x], 
-		       SD(HBA_ptr)->writes[x]);
+    if(SD(HBA_ptr)->bustype == IS_EISA) {
+	if (HBA_ptr->dma_channel == 0xff)
+	    size = sprintf(buffer + len, "DMA: BUSMASTER\n");
+	else
+	    size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel);
+	len += size; 
+	pos = begin + len;
+
+	size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "Host Bus: EISA\n"); 
+	len += size; 
+	pos = begin + len;
+    } else {
+
+	scmd.cmnd[0] = LOG_SENSE;
+	scmd.cmnd[1] = 0;
+	scmd.cmnd[2] = 0x33 + (3<<6);
+	scmd.cmnd[3] = 0;
+	scmd.cmnd[4] = 0;
+	scmd.cmnd[5] = 0;
+	scmd.cmnd[6] = 0;
+	scmd.cmnd[7] = 0x00;
+	scmd.cmnd[8] = 0x66;
+	scmd.cmnd[9] = 0;
+	scmd.cmd_len = 10;
+	
+	scmd.host = HBA_ptr; 
+	scmd.target = HBA_ptr->this_id; 
+	scmd.lun = 0; 
+	scmd.channel = 0;
+	
+	scmd.use_sg = 0;
+	scmd.request_bufflen = 0x66;
+	scmd.request_buffer = buff + 0x144;
+	HBA_interpret = TRUE;
+	
+	eata_queue(&scmd, (void *) eata_scsi_done);
+	while (internal_command_finished == FALSE)
+	    barrier();
+	
+	size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt,
+		       (cc->intt == TRUE)?"level":"edge");
+	len += size; 
+	pos = begin + len;
+	if (HBA_ptr->dma_channel == 0xff)
+	    size = sprintf(buffer + len, "DMA: BUSMASTER\n");
+	else
+	    size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel);
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "CPU: MC680%02d %dMHz\n", bt->cpu_type,
+		       bt->cpu_speed);
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "Host Bus: %s\n", 
+		       (SD(HBA_ptr)->bustype == IS_PCI)?"PCI ":
+		       (SD(HBA_ptr)->bustype == IS_EISA)?"EISA":"ISA ");
+	
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "SCSI Bus:%s%s Speed: %sMB/sec. %s\n",
+		       (sb->wide == TRUE)?" WIDE":"", 
+		       (sb->dif == TRUE)?" DIFFERENTIAL":"",
+		       (sb->speed == 0)?"5":(sb->speed == 1)?"10":"20",
+		       (sb->ext == TRUE)?"With external cable detection":"");
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "SCSI channel expansion Module: %s installed\n",
+		       (bt->sx1 == TRUE)?"SX1 (one channel)":
+		       ((bt->sx2 == TRUE)?"SX2 (two channels)":"not"));
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "SmartRAID hardware: %spresent.\n",
+		       (cc->srs == TRUE)?"":"not ");
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "	  Type: %s\n",
+		       ((cc->key == TRUE)?((bt->dmi == TRUE)?"integrated"
+					   :((bt->dm4 == TRUE)?"DM401X"
+					   :(bt->dm4k == TRUE)?"DM4000"
+					   :"-"))
+					   :"-"));
+	len += size; 
+	pos = begin + len;
+	
+	size = sprintf(buffer + len, "	  Max array groups:		 %d\n",
+		       (al->code == 0x0e)?al->max_groups:7);
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "	  Max drives per RAID 0 array:	 %d\n",
+		       (al->code == 0x0e)?al->raid0_drv:7);
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "	  Max drives per RAID 3/5 array: %d\n",
+		       (al->code == 0x0e)?al->raid35_drv:7);
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "Cache Module: %sinstalled.\n",
+		       (cc->csh)?"":"not ");
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "	  Type: %s\n",
+		       ((cc->csh == TRUE)?((bt->cmi == TRUE)?"integrated"
+					 :((bt->cm4 == TRUE)?"CM401X"
+					 :((bt->cm4k == TRUE)?"CM4000"
+					 :"-")))
+					 :"-"));
+	len += size; 
+	pos = begin + len;
+	for (x = 0; x <= 3; x++) {
+	    size = sprintf(buffer + len, "    Bank%d: %dMB with%s ECC\n",x,
+			   mc->banksize[x] & 0x7f, 
+			   (mc->banksize[x] & 0x80)?"":"out");
+	    len += size; 
+	    pos = begin + len;	    
+	}   
+	size = sprintf(buffer + len, "Timer Modification: %sinstalled\n",
+		       (cc->tmr == TRUE)?"":"not ");
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "NVRAM: %spresent\n",
+		       (cc->nvr == TRUE)?"":"not ");
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "SmartROM: %senabled\n",
+		       (bt->srom == TRUE)?"not ":"");
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer + len, "HBA indicates %salarm.\n",
+		       (bt->alrm == TRUE)?"":"no ");
+	len += size; 
+	pos = begin + len;
+	
+	if (pos < offset) {
+	    len = 0;
+	    begin = pos;
+	}
+	if (pos > offset + length)
+	    goto stop_output; 
+	
+	scmd.cmnd[0] = LOG_SENSE;
+	scmd.cmnd[1] = 0;
+	scmd.cmnd[2] = 0x32 + (3<<6); 
+	scmd.cmnd[3] = 0;
+	scmd.cmnd[4] = 0;
+	scmd.cmnd[5] = 0;
+	scmd.cmnd[6] = 0;
+	scmd.cmnd[7] = 0x01;
+	scmd.cmnd[8] = 0x44;
+	scmd.cmnd[9] = 0;
+	scmd.cmd_len = 10;
+	scmd.host = HBA_ptr; 
+	scmd.target = HBA_ptr->this_id; 
+	scmd.lun = 0; 
+	scmd.channel = 0;
+	scmd.use_sg = 0;
+	scmd.request_bufflen = 0x144;
+	scmd.request_buffer = buff2;
+	HBA_interpret = TRUE;
+	
+	eata_queue(&scmd, (void *) eata_scsi_done);
+	while (internal_command_finished == FALSE)
+	    barrier();
+	
+	swap_statistics(buff2);
+	rhcs = (hst_cmd_stat *)(buff2 + 0x2c); 
+	whcs = (hst_cmd_stat *)(buff2 + 0x8c);		 
+	
+	for (x = 0; x <= 11; x++) {
+	    SD(HBA_ptr)->reads[x] += rhcs->sizes[x];
+	    SD(HBA_ptr)->writes[x] += whcs->sizes[x];
+	    SD(HBA_ptr)->reads[12] += rhcs->sizes[x];
+	    SD(HBA_ptr)->writes[12] += whcs->sizes[x];
+	}
+	size = sprintf(buffer + len, "Host Disk Command Statistics:\n"
+		       "	 Reads:	     Writes:\n");
+	len += size; 
+	pos = begin + len;
+	for (x = 0; x <= 10; x++) {
+	    size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x,
+			   SD(HBA_ptr)->reads[x], 
+			   SD(HBA_ptr)->writes[x]);
+	    len += size; 
+	    pos = begin + len;
+	}
+	size = sprintf(buffer+len,">1024k:%12u %12u\n",
+		       SD(HBA_ptr)->reads[11], 
+		       SD(HBA_ptr)->writes[11]);
+	len += size; 
+	pos = begin + len;
+	size = sprintf(buffer+len,"Sum	 :%12u %12u\n",
+		       SD(HBA_ptr)->reads[12], 
+		       SD(HBA_ptr)->writes[12]);
 	len += size; 
 	pos = begin + len;
     }
-    size = sprintf(buffer+len,">1024k:%12u %12u\n",
-		   SD(HBA_ptr)->reads[11], 
-		   SD(HBA_ptr)->writes[11]);
-    len += size; 
-    pos = begin + len;
-    size = sprintf(buffer+len,"Sum   :%12u %12u\n",
-		   SD(HBA_ptr)->reads[12], 
-		   SD(HBA_ptr)->writes[12]);
-    len += size; 
-    pos = begin + len;
     
     if (pos < offset) {
 	len = 0;
@@ -322,7 +341,6 @@
     if (pos > offset + length)
 	goto stop_output;
 
- devices:    
     scd = scsi_devices;
     
     size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
@@ -358,8 +376,8 @@
 	    
 	    size += sprintf(buffer + len + size, "  Type:   %s ",
 			    scd->type < MAX_SCSI_DEVICE_CODE ? 
-			    scsi_dev_types[(int)scd->type] : "Unknown          " );
-	    size += sprintf(buffer + len + size, "               ANSI"
+			    scsi_dev_types[(int)scd->type] : "Unknown	       " );
+	    size += sprintf(buffer + len + size, "		 ANSI"
 			    " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
 	    if (scd->scsi_level == 2)
 		size += sprintf(buffer + len + size, " CCS\n");
@@ -381,9 +399,9 @@
  stop_output:
     DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
     *start=buffer+(offset-begin);   /* Start of wanted data */
-    len-=(offset-begin);            /* Start slop */
+    len-=(offset-begin);	    /* Start slop */
     if(len>length)
-	len = length;               /* Ending slop */
+	len = length;		    /* Ending slop */
     DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
     
     return (len);     
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v1.3.8/linux/drivers/scsi/scsi.c	Fri Jul  7 08:54:50 1995
+++ linux/drivers/scsi/scsi.c	Tue Jul 11 07:56:04 1995
@@ -51,7 +51,6 @@
 
 #undef USE_STATIC_SCSI_MEMORY
 
-
 /*
 static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.5 1993/09/24 12:45:18 drew Exp drew $";
 */
@@ -164,65 +163,94 @@
  * lock up. 
  */
 
-struct blist{
+#define BLIST_NOLUN     0x01
+#define BLIST_FORCELUN  0x02
+#define BLIST_BORKEN    0x04
+#define BLIST_KEY       0x08
+#define BLIST_SINGLELUN 0x10
+
+struct dev_info{
     char * vendor;
     char * model;
     char * revision; /* Latest revision known to be bad.  Not used yet */
+    unsigned flags;
 };
 
-static struct blist blacklist[] =
-{
-{"CHINON","CD-ROM CDS-431","H42"}, /* Locks up if polled for lun != 0 */
-{"CHINON","CD-ROM CDS-535","Q14"}, /* Locks up if polled for lun != 0 */
-{"DENON","DRD-25X","V"},           /* Locks up if probed for lun != 0 */
-{"HITACHI","DK312C","CM81"},       /* Responds to all lun - dtg */
-{"HITACHI","DK314C","CR21" },      /* responds to all lun */
-{"IMS", "CDD521/10","2.06"},       /* Locks-up when LUN>0 polled. */
-{"MAXTOR","XT-3280","PR02"},       /* Locks-up when LUN>0 polled. */
-{"MAXTOR","XT-4380S","B3C"},       /* Locks-up when LUN>0 polled. */
-{"MAXTOR","MXT-1240S","I1.2"},     /* Locks up when LUN>0 polled */
-{"MAXTOR","XT-4170S","B5A"},       /* Locks-up sometimes when LUN>0 polled. */
-{"MAXTOR","XT-8760S","B7B"},       /* guess what? */
-{"NEC","CD-ROM DRIVE:841","1.0"},  /* Locks-up when LUN>0 polled. */
-{"RODIME","RO3000S","2.33"},       /* Locks up if polled for lun != 0 */
-{"SEAGATE", "ST157N", "\004|j"},   /* causes failed REQUEST SENSE on lun 1 
-				    * for aha152x controller, which causes 
-				    * SCSI code to reset bus.*/
-{"SEAGATE", "ST296","921"},        /* Responds to all lun */
-{"SONY","CD-ROM CDU-541","4.3d"},
-{"SONY","CD-ROM CDU-55S","1.0i"},
-{"TANDBERG","TDC 3600","U07"},     /* Locks up if polled for lun != 0 */
-{"TEAC","CD-ROM","1.06"},          /* causes failed REQUEST SENSE on lun 1 
-				    * for seagate controller, which causes 
-				    * SCSI code to reset bus.*/
-{"TEXEL","CD-ROM","1.06"},         /* causes failed REQUEST SENSE on lun 1 
-				    * for seagate controller, which causes 
-				    * SCSI code to reset bus.*/
-{"QUANTUM","LPS525S","3110"},      /* Locks sometimes if polled for lun != 0 */
-{"QUANTUM","PD1225S","3110"},      /* Locks sometimes if polled for lun != 0 */
-{"MEDIAVIS","CDR-H93MV","1.31"},   /* Locks up if polled for lun != 0 */
-{"SANKYO", "CP525","6.64"},        /* causes failed REQ SENSE, extra reset */
-{"HP", "C1750A", "3226"},          /* scanjet iic */
-{"HP", "C1790A", ""},              /* scanjet iip */
-{"HP", "C2500A", ""},              /* scanjet iicx */
+/*
+ * This is what was previously known as the blacklist.  The concept
+ * has been expanded so that we can specify other 
+ * The blacklist is used to determine which devices cannot tolerate a
+ * lun probe because of buggy firmware.  Far too many for my liking,
+ * which is why the default is now for there to be no lun scan. 
+ */
+static struct dev_info device_list[] =
+{
+{"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
+{"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
+{"DENON","DRD-25X","V", BLIST_NOLUN},           /* Locks up if probed for lun != 0 */
+{"HITACHI","DK312C","CM81", BLIST_NOLUN},       /* Responds to all lun - dtg */
+{"HITACHI","DK314C","CR21" , BLIST_NOLUN},      /* responds to all lun */
+{"IMS", "CDD521/10","2.06", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
+{"MAXTOR","XT-3280","PR02", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
+{"MAXTOR","XT-4380S","B3C", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
+{"MAXTOR","MXT-1240S","I1.2", BLIST_NOLUN},     /* Locks up when LUN>0 polled */
+{"MAXTOR","XT-4170S","B5A", BLIST_NOLUN},       /* Locks-up sometimes when LUN>0 polled. */
+{"MAXTOR","XT-8760S","B7B", BLIST_NOLUN},       /* guess what? */
+{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
+{"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
+{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},   /* causes failed REQUEST SENSE on lun 1 
+                                                 * for aha152x controller, which causes 
+                                                 * SCSI code to reset bus.*/
+{"SEAGATE", "ST296","921", BLIST_NOLUN},        /* Responds to all lun */
+{"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN},
+{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},
+{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},
+{"TANDBERG","TDC 3600","U07", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
+{"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1 
+                                                 * for seagate controller, which causes 
+                                                 * SCSI code to reset bus.*/
+{"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1 
+                                                 * for seagate controller, which causes 
+                                                 * SCSI code to reset bus.*/
+{"QUANTUM","LPS525S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
+{"QUANTUM","PD1225S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
+{"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN},   /* Locks up if polled for lun != 0 */
+{"SANKYO", "CP525","6.64", BLIST_NOLUN},        /* causes failed REQ SENSE, extra reset */
+{"HP", "C1750A", "3226", BLIST_NOLUN},          /* scanjet iic */
+{"HP", "C1790A", "", BLIST_NOLUN},              /* scanjet iip */
+{"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx */
+
+/*
+ * Other types of devices that have special flags.
+ */
+{"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN},
+{"TEXEL","CD-ROM","1.06", BLIST_BORKEN},
+{"INSITE","Floptical   F*8I","*", BLIST_KEY},
+{"INSITE","I325VM","*", BLIST_KEY},
+{"PIONEER","CD-ROMDRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
+{"PIONEER","CD-ROMDRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
+/*
+ * Must be at end of list...
+ */
 {NULL, NULL, NULL}
 };
 
-static int blacklisted(unsigned char * response_data){
+static int get_device_flags(unsigned char * response_data){
     int i = 0;
     unsigned char * pnt;
     for(i=0; 1; i++){
-	if(blacklist[i].vendor == NULL) return 0;
+	if(device_list[i].vendor == NULL) return 0;
 	pnt = &response_data[8];
 	while(*pnt && *pnt == ' ') pnt++;
-	if(memcmp(blacklist[i].vendor, pnt,
-		  strlen(blacklist[i].vendor))) continue;
+	if(memcmp(device_list[i].vendor, pnt,
+		  strlen(device_list[i].vendor))) continue;
 	pnt = &response_data[16];
 	while(*pnt && *pnt == ' ') pnt++;
-	if(memcmp(blacklist[i].model, pnt,
-		  strlen(blacklist[i].model))) continue;
-	return 1;
+	if(memcmp(device_list[i].model, pnt,
+		  strlen(device_list[i].model))) continue;
+	return device_list[i].flags;
     }
+    return 0;
 }
 
 /*
@@ -323,7 +351,7 @@
 
 /*
  *  Detecting SCSI devices :
- *  We scan all present host adapter's busses,  from ID 0 to ID 6.
+ *  We scan all present host adapter's busses,  from ID 0 to ID (max_id).
  *  We use the INQUIRY command, determine device type, and pass the ID /
  *  lun address of all sequential devices to the tape driver, all random
  *  devices to the disk driver.
@@ -338,6 +366,8 @@
     unsigned char * scsi_result;
     Scsi_Device * SDpnt, *SDtail;
     struct Scsi_Device_Template * sdtpnt;
+    int                 bflags;
+    int                 max_dev_lun = 0;
     Scsi_Cmnd  *SCpnt;
     
     ++in_scan_scsis;
@@ -364,7 +394,7 @@
 	channel = hchannel;
 	dev = hid;
 	lun = hlun;
-	goto crude;
+	goto crude; /* Anyone remember good ol' BASIC ?  :-) */
     }
 
     for (channel = 0; channel <= shpnt->max_channel; channel++)
@@ -374,9 +404,14 @@
 		
 		/*
 		 * We need the for so our continue, etc. work fine.
+                 * We put this in a variable so that we can override
+                 * it during the scan if we detect a device *KNOWN*
+                 * to have multiple logical units.
 		 */
-		for (lun = 0; lun < (max_scsi_luns < shpnt->max_lun ? 
-				     max_scsi_luns : shpnt->max_lun); ++lun)
+                max_dev_lun = (max_scsi_luns < shpnt->max_lun ? 
+                               max_scsi_luns : shpnt->max_lun);
+
+		for (lun = 0; lun < max_dev_lun; ++lun)
 		{
 		crude:
 		    memset(SDpnt, 0, sizeof(Scsi_Device));
@@ -531,6 +566,7 @@
 			SDpnt->changed = 0;
 			SDpnt->access_count = 0;
 			SDpnt->busy = 0;
+                        SDpnt->has_cmdblocks = 0;
 			/*
 			 * Currently, all sequential devices are assumed to be
 			 * tapes, all random devices disk, with the appropriate
@@ -560,6 +596,7 @@
 #endif
 			}
 			
+                        SDpnt->single_lun = 0;
 			SDpnt->soft_reset =
 			    (scsi_result[7] & 1) && ((scsi_result[3] &7) == 2);
 			SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
@@ -599,6 +636,12 @@
 			     */
 
 			    SDpnt->disconnect = 0;
+
+                            /*
+                             * Get any flags for this device.
+                             */
+                            bflags = get_device_flags(scsi_result);
+
 			    
 			    /*
 			     * Some revisions of the Texel CD ROM drives have 
@@ -608,38 +651,16 @@
 			     * change it here if it turns out that it isn't
 			     * a TEXEL drive.
 			     */
-			    if((strncmp("SONY",(char *) &scsi_result[8], 4)!= 0
-				|| strncmp("CD-ROM CDU-8001",
-					   (char *) &scsi_result[16], 15) != 0)
-			       && (strncmp("TEXEL", 
-					   (char *) &scsi_result[8], 5) != 0 
-				   || strncmp("CD-ROM", 
-					      (char *) &scsi_result[16], 6) != 0
-				/*
-				 * XXX 1.06 has problems, some one should 
-				 * figure out the others too so ALL TEXEL 
-				 * drives don't suffer in performance, 
-				 * especially when I finish integrating my 
-				 * seagate patches which do multiple I_T_L 
-				 * nexuses.
-				 */
-				
-#ifdef notyet
-				|| (strncmp("1.06", 
-					    (char *) &scsi_result, 4) != 0)
-#endif
-				))
+                            if( (bflags & BLIST_BORKEN) == 0 )
+                            {
 				SDpnt->borken = 0;
+                            }
 			    
 			    
 			    /* These devices need this "key" to unlock the
 			     * devices so we can use it 
 			     */
-			    if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
-			       (memcmp("Floptical   F*8I", 
-				       &scsi_result[16], 16) == 0
-				|| memcmp("I325VM", 
-					  &scsi_result[16], 6) == 0)) {
+                            if( (bflags & BLIST_KEY) != 0 ) {
 				printk("Unlocked floptical drive.\n");
 				SDpnt->lockable = 0;
 				scsi_cmd[0] = MODE_SENSE;
@@ -680,7 +701,32 @@
 			    /* Some scsi devices cannot be polled for lun != 0
 			     * due to firmware bugs 
 			     */
-			    if(blacklisted(scsi_result)) break;
+			    if(bflags & BLIST_NOLUN) break;
+
+                            /*
+                             * If we want to only allow I/O to one of the luns
+                             * attached to this device at a time, then we set this
+                             * flag.
+                             */
+                            if(bflags & BLIST_SINGLELUN)
+                            {
+                                SDpnt->single_lun = 1;
+                            }
+
+                            /*
+                             * If this device is known to support multiple units, override
+                             * the other settings, and scan all of them.
+                             */
+                            if(bflags & BLIST_FORCELUN)
+                            {
+                                /*
+                                 * We probably want to make this a variable, but this
+                                 * will do for now.
+                                 */
+                                max_dev_lun = 8;
+                            }
+ 
+
 			    /* Old drives like the MAXTOR XT-3280 say vers=0 */
 			    if ((scsi_result[2] & 0x07) == 0)
 				break;
@@ -692,6 +738,10 @@
 			}
 		    }       /* if result == DID_OK ends */
 
+                    /*
+                     * This might screw us up with multi-lun devices, but the user can
+                     * scan for them too.
+                     */
 		    if(hardcoded == 1)
 			goto leave;
 		} /* for lun ends */
@@ -778,6 +828,7 @@
 {
     Scsi_Cmnd * SCpnt = NULL;
     int tablesize;
+    Scsi_Cmnd * found = NULL;
     struct buffer_head * bh, *bhp;
     
     if (!device)
@@ -787,11 +838,44 @@
 	panic("Invalid device in request_queueable");
     
     SCpnt =  device->host->host_queue;
-    while(SCpnt){
-	if(SCpnt->target == device->id && SCpnt->lun == device->lun 
-	   && SCpnt->channel == device->channel)
-	    if(SCpnt->request.dev < 0) break;
-	SCpnt = SCpnt->next;
+
+    /*
+     * Look for a free command block.  If we have been instructed not to queue
+     * multiple commands to multi-lun devices, then check to see what else is going on
+     * for this device first.
+     */
+      
+    SCpnt = device->host->host_queue;
+    if (!device->single_lun) {
+        while(SCpnt){
+            if(SCpnt->target == device->id &&
+               SCpnt->lun == device->lun) {
+                if(SCpnt->request.dev < 0) break;
+            }
+            SCpnt = SCpnt->next;
+        }
+    } else {
+        while(SCpnt){
+            if(SCpnt->target == device->id) {
+                if (SCpnt->lun == device->lun) {
+                    if(found == NULL 
+                       && SCpnt->request.dev < 0) 
+                    {
+                        found=SCpnt;
+                    }
+                } 
+                if(SCpnt->request.dev >= 0) {
+                    /*
+                     * I think that we should really limit things to one
+                     * outstanding command per device - this is what tends to trip
+                     * up buggy firmware.
+                     */
+                    return NULL;
+                }
+            }
+            SCpnt = SCpnt->next;
+        }
+        SCpnt = found;
     }
     
     if (!SCpnt) return NULL;
@@ -841,14 +925,14 @@
     SCpnt->transfersize = 0;
     SCpnt->underflow = 0;
     SCpnt->cmd_len = 0;
-#if 1
+
 /* Since not everyone seems to set the device info correctly
  * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
  */ 
     SCpnt->channel = device->channel;
     SCpnt->lun = device->lun;
     SCpnt->target = device->id;
-#endif
+
     return SCpnt;
 }
 
@@ -873,6 +957,7 @@
     struct Scsi_Host * host;
     Scsi_Cmnd * SCpnt = NULL;
     Scsi_Cmnd * SCwait = NULL;
+    Scsi_Cmnd * found = NULL;
     
     if (!device)
 	panic ("No device passed to allocate_device().\n");
@@ -887,15 +972,40 @@
     if (intr_count && SCSI_BLOCK(host)) return NULL;
     
     while (1==1){
-	SCpnt = host->host_queue;
-	while(SCpnt){
-	    if(SCpnt->target == device->id && SCpnt->lun == device->lun
-	       && SCpnt->channel == device->channel) {
-		SCwait = SCpnt;
-		if(SCpnt->request.dev < 0) break;
-	    }
-	    SCpnt = SCpnt->next;
-	}
+        SCpnt = device->host->host_queue;
+        if (!device->single_lun) {
+            while(SCpnt){
+                if(SCpnt->target == device->id &&
+                   SCpnt->lun == device->lun) {
+                    if(SCpnt->request.dev < 0) break;
+                }
+                SCpnt = SCpnt->next;
+            }
+        } else {
+            while(SCpnt){
+                if(SCpnt->target == device->id) {
+                    if (SCpnt->lun == device->lun) {
+                        if(found == NULL 
+                           && SCpnt->request.dev < 0) 
+                        {
+                            found=SCpnt;
+                        }
+                    } 
+                    if(SCpnt->request.dev >= 0) {
+                        /*
+                         * I think that we should really limit things to one
+                         * outstanding command per device - this is what tends to trip
+                         * up buggy firmware.
+                         */
+                        found = NULL;
+                        break;
+                    }
+                }
+                SCpnt = SCpnt->next;
+            }
+            SCpnt = found;
+        }
+
 	save_flags(flags);
 	cli();
 	/* See if this request has already been queued by an interrupt routine
@@ -964,15 +1074,16 @@
     SCpnt->old_use_sg  = 0;
     SCpnt->transfersize = 0;      /* No default transfer size */
     SCpnt->cmd_len = 0;
+
     SCpnt->underflow = 0;         /* Do not flag underflow conditions */
-#if 1
-/* Since not everyone seems to set the device info correctly
- * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
- */ 
+
+    /* Since not everyone seems to set the device info correctly
+     * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+     */ 
     SCpnt->channel = device->channel;
     SCpnt->lun = device->lun;
     SCpnt->target = device->id;
-#endif
+
     return SCpnt;
 }
 
@@ -2139,6 +2250,7 @@
 	SCpnt->prev = NULL;
 	host->host_queue = SCpnt;
     }
+    SDpnt->has_cmdblocks = 1;
 }
 
 /*
@@ -2196,6 +2308,7 @@
 	if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
     }
     
+
     if (scsi_devicelist)
 	dma_sectors = 16;  /* Base value we use */
     
@@ -2584,6 +2697,7 @@
 		scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
 		sdpnt->host->host_queue = SCpnt;
 		if (SCpnt) SCpnt->prev = NULL;
+                sdpnt->has_cmdblocks = 0;
 	    }
     
     /* Next free up the Scsi_Device structures for this host */
@@ -2672,7 +2786,6 @@
 static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
 {
     Scsi_Device * SDpnt;
-    int previous_attachment;
     
     if (tpnt->next) return 1;
     
@@ -2686,7 +2799,7 @@
     
     /*
      * If any of the devices would match this driver, then perform the
-     * init function.  +
+     * init function.
      */
     if(tpnt->init && tpnt->dev_noticed) (*tpnt->init)();
     
@@ -2695,13 +2808,12 @@
      */
     for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
     {
-	previous_attachment = SDpnt->attached;
 	if(tpnt->attach)  (*tpnt->attach)(SDpnt);
 	/*
 	 * If this driver attached to the device, and we no longer
 	 * have anything attached, release the scso command blocks.
 	 */
-	if(SDpnt->attached && previous_attachment == 0)
+	if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
 	    scsi_build_commandblocks(SDpnt);
     }
     
@@ -2750,6 +2862,7 @@
 		    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
 		}
 	    }
+            SDpnt->has_cmdblocks = 0;
 	}
     }
     /*
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v1.3.8/linux/drivers/scsi/scsi.h	Fri Jul  7 08:54:50 1995
+++ linux/drivers/scsi/scsi.h	Tue Jul 11 07:56:04 1995
@@ -302,6 +302,7 @@
     unsigned writeable:1;
     unsigned removable:1; 
     unsigned random:1;
+    unsigned has_cmdblocks:1;
     unsigned changed:1;             /* Data invalid due to media change */
     unsigned busy:1;                /* Used to prevent races */
     unsigned lockable:1;            /* Able to prevent media removal */
@@ -312,6 +313,8 @@
     unsigned disconnect:1;          /* can disconnect */
     unsigned soft_reset:1;          /* Uses soft reset option */
     unsigned sync:1;                /* Negotiate for sync transfers */
+    unsigned single_lun:1;          /* Indicates we should only allow I/O to
+                                       one of the luns for the device at a time. */
     unsigned char current_tag;      /* current tag */
     unsigned char sync_min_period;  /* Not less than this period */
     unsigned char sync_max_offset;  /* Not greater than this offset */
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v1.3.8/linux/drivers/scsi/scsi_debug.c	Fri Jul  7 08:54:50 1995
+++ linux/drivers/scsi/scsi_debug.c	Tue Jul 11 07:56:04 1995
@@ -122,6 +122,11 @@
 
 static char sense_buffer[128] = {0,};
 
+/*
+ * Semaphore used to simulate bus lockups.
+ */
+static int scsi_debug_lockup = 0;
+
 static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
     int i;
 #if 0
@@ -229,7 +234,7 @@
 	scsi_debug_errsts = 0;
 	break;
     case TEST_UNIT_READY:
-	printk("Test unit ready.\n");
+	printk("Test unit ready(%x %d)\n", buff, bufflen);
 	if (buff)
 	    memset(buff, 0, bufflen);
 	scsi_debug_errsts = 0;
@@ -288,6 +293,7 @@
 	    /* If this is block 0, then we want to read the partition table for this
 	     * device.  Let's make one up */
 	    if(block == 0 && target == 0) {
+                memset(buff, 0, bufflen);
 		*((unsigned short *) (buff+510)) = 0xAA55;
 		p = (struct partition* ) (buff + 0x1be);
 		npart = 0;
@@ -412,8 +418,12 @@
 	printk("scsi_debug_queuecommand: done cant be NULL\n");
     
 #ifdef IMMEDIATE
-    SCpnt->result = scsi_debug_errsts;
-    scsi_debug_intr_handle();  /* No timer - do this one right away */
+    if( !scsi_debug_lockup )
+    {
+        SCpnt->result = scsi_debug_errsts;
+        scsi_debug_intr_handle();  /* No timer - do this one right away */
+    }
+    restore_flags(flags);
 #else
     timeout[i] = jiffies+DISK_SPEED;
     
@@ -580,19 +590,20 @@
     unsigned long flags;
     
     void (*my_done)(Scsi_Cmnd *);
+    scsi_debug_lockup = 0;
     DEB(printk("scsi_debug_reset called\n"));
     for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
-      if (SCint[i] == NULL) continue;
-      SCint[i]->result = DID_ABORT << 16;
-      my_done = do_done[i];
-      my_done(SCint[i]);
-      save_flags(flags);
-      cli();
-      SCint[i] = NULL;
-      do_done[i] = NULL;
-      timeout[i] = 0;
-      restore_flags(flags);
-  };
+        if (SCint[i] == NULL) continue;
+        SCint[i]->result = DID_ABORT << 16;
+        my_done = do_done[i];
+        my_done(SCint[i]);
+        save_flags(flags);
+        cli();
+        SCint[i] = NULL;
+        do_done[i] = NULL;
+        timeout[i] = 0;
+        restore_flags(flags);
+    }
     return 0;
 }
 
@@ -602,7 +613,7 @@
     return buffer;
 }
 
-/* generic_proc_info
+/* scsi_debug_proc_info
  * Used if the driver currently has no own support for /proc/scsi
  */
 int scsi_debug_proc_info(char *buffer, char **start, off_t offset, 
@@ -611,7 +622,35 @@
     int len, pos, begin;
 
     if(inout == 1)
-	return(-ENOSYS);  /* This is a no-op */
+    {
+        /* First check for the Signature */
+        if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
+            buffer += 11;
+            length -= 11;
+            /*
+             * OK, we are getting some kind of command.  Figure out
+             * what we are supposed to do here.  Simulate bus lockups
+             * to test our reset capability.
+             */
+            if( length == 6 && strncmp(buffer, "lockup", length) == 0 )
+            {
+                scsi_debug_lockup = 1;
+                return length;
+            } 
+            
+            if( length == 6 && strncmp(buffer, "unlock", length) == 0 )
+            {
+                scsi_debug_lockup = 0;
+                return length;
+            } 
+            
+            printk("Unknown command:%s\n", buffer);
+        } else 
+            printk("Wrong Signature:%10s\n", (char *) ((ulong)buffer-11));
+
+        return -EINVAL;
+        
+    }
     
     begin = 0;
     pos = len = sprintf(buffer, 
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v1.3.8/linux/drivers/scsi/scsi_ioctl.c	Fri Jul  7 08:54:50 1995
+++ linux/drivers/scsi/scsi_ioctl.c	Tue Jul 11 07:56:04 1995
@@ -42,11 +42,14 @@
 
 static int ioctl_probe(struct Scsi_Host * host, void *buffer)
 {
-    int temp;
+    int temp, result;
     unsigned int len,slen;
     const char * string;
     
     if ((temp = host->hostt->present) && buffer) {
+        result = verify_area(VERIFY_READ, buffer, sizeof(long));
+        if (result) return result;
+
 	len = get_user ((unsigned int *) buffer);
 	if(host->hostt->info)
 	    string = host->hostt->info(host);
@@ -56,7 +59,9 @@
 	    slen = strlen(string);
 	    if (len > slen)
 		len = slen + 1;
-	    verify_area(VERIFY_WRITE, buffer, len);
+            result = verify_area(VERIFY_WRITE, buffer, len);
+            if (result) return result;
+
 	    memcpy_tofs (buffer, string, len);
 	}
     }
@@ -139,7 +144,7 @@
 		break;
 	    };
 	default: /* Fall through for non-removable media */
-	    printk("SCSI CD error: host %d id %d lun %d return code = %x\n",
+	    printk("SCSI error: host %d id %d lun %d return code = %x\n",
 		   dev->host->host_no,
 		   dev->id,
 		   dev->lun,
@@ -157,6 +162,11 @@
     return result;
 }
 
+/*
+ * This interface is depreciated - users should use the scsi generics
+ * interface instead, as this is a more flexible approach to performing
+ * generic SCSI commands on a device.
+ */
 static int ioctl_command(Scsi_Device *dev, void *buffer)
 {
     char * buf;
@@ -171,11 +181,35 @@
     if (!buffer)
 	return -EINVAL;
     
- 	inlen = get_user((unsigned int *) buffer);
- 	outlen = get_user( ((unsigned int *) buffer) + 1);
-  
-  	cmd_in = (char *) ( ((int *)buffer) + 2);
- 	opcode = get_user(cmd_in); 
+
+    /*
+     * Verify that we can read at least this much.
+     */
+    result = verify_area(VERIFY_READ, buffer, 2*sizeof(long) + 1);
+    if (result) return result;
+
+    /*
+     * The structure that we are passed should look like:
+     *
+     * struct sdata{
+     *	int inlen;
+     *	int outlen;
+     *	char cmd[];  # However many bytes are used for cmd.
+     *	char data[];
+     */
+    inlen = get_user((unsigned int *) buffer);
+    outlen = get_user( ((unsigned int *) buffer) + 1);
+    
+    /*
+     * We do not transfer more than MAX_BUF with this interface.
+     * If the user needs to transfer more data than this, they
+     * should use scsi_generics instead.
+     */
+    if( inlen > MAX_BUF ) inlen = MAX_BUF;
+    if( outlen > MAX_BUF ) outlen = MAX_BUF;
+
+    cmd_in = (char *) ( ((int *)buffer) + 2);
+    opcode = get_user(cmd_in); 
     
     needed = buf_needed = (inlen > outlen ? inlen : outlen);
     if(buf_needed){
@@ -187,9 +221,27 @@
     } else
 	buf = NULL;
     
-    memcpy_fromfs ((void *) cmd,  cmd_in,  cmdlen = COMMAND_SIZE (opcode));
-    memcpy_fromfs ((void *) buf,  (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);
+    /*
+     * Obtain the command from the user's address space.
+     */
+    cmdlen = COMMAND_SIZE(opcode);
+
+    result = verify_area(VERIFY_READ, cmd_in, 
+                         cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen);
+    if (result) return result;
+
+    memcpy_fromfs ((void *) cmd,  cmd_in,  cmdlen);
     
+    /*
+     * Obtain the data to be sent to the device (if any).
+     */
+    memcpy_fromfs ((void *) buf,  
+                   (void *) (cmd_in + cmdlen), 
+                   inlen);
+    
+    /*
+     * Set the lun field to the correct value.
+     */
     cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
     
 #ifndef DEBUG_NO_CMD
@@ -205,22 +257,25 @@
 	down(&sem);
 	/* Hmm.. Have to ask about this one */
 	while (SCpnt->request.dev != 0xfffe) schedule();
-    };
+    }
     
     
-    /* If there was an error condition, pass the info back to the user. */
+    /* 
+     * If there was an error condition, pass the info back to the user. 
+     */
     if(SCpnt->result) {
-	result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer));
-	if (result)
-	    return result;
-	memcpy_tofs((void *) cmd_in,  SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
+        result = verify_area(VERIFY_WRITE, 
+                             cmd_in, 
+                             sizeof(SCpnt->sense_buffer));
+        if (result) return result;
+        memcpy_tofs((void *) cmd_in,  
+                    SCpnt->sense_buffer, 
+                    sizeof(SCpnt->sense_buffer));
     } else {
-	
-	result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF  : outlen);
-	if (result)
-	    return result;
-	memcpy_tofs ((void *) cmd_in,  buf,  (outlen > MAX_BUF) ? MAX_BUF  : outlen);
-    };
+        result = verify_area(VERIFY_WRITE, cmd_in, outlen);
+        if (result) return result;
+        memcpy_tofs ((void *) cmd_in,  buf,  outlen);
+    }
     result = SCpnt->result;
     SCpnt->request.dev = -1;  /* Mark as not busy */
     if (buf) scsi_free(buf, buf_needed);
@@ -255,6 +310,7 @@
  */
 int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
 {
+    int result;
     char scsi_cmd[12];
     
     /* No idea how this happens.... */
@@ -262,7 +318,9 @@
     
     switch (cmd) {
     case SCSI_IOCTL_GET_IDLUN:
-	verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long));
+        if (result) return result;
+
 	put_user(dev->id + (dev->lun << 8) + (dev->host->host_no << 16) +
 		    /* This has been added to support 
 		     * multichannel HBAs, it might cause 
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c
--- v1.3.8/linux/drivers/scsi/scsi_proc.c	Fri Jul  7 08:54:50 1995
+++ linux/drivers/scsi/scsi_proc.c	Tue Jul 11 07:56:04 1995
@@ -7,7 +7,7 @@
  * information directly to the lowlevel driver.
  *
  * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de 
- * Version: 0.99.5   last change: 95/06/28
+ * Version: 0.99.6   last change: 95/07/04
  * 
  * generic command parser provided by: 
  * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
@@ -86,8 +86,7 @@
     begin = 0;
     pos = len = sprintf(buffer, 
 			"The driver does not yet support the proc-fs\n");
-    if(pos < offset)
-    {
+    if(pos < offset) {
 	len = 0;
 	begin = pos;
     }
@@ -110,27 +109,23 @@
     struct Scsi_Host *hpnt = scsi_hostlist;
 
     if(func != 2) {    
-	if(ino == PROC_SCSI_SCSI) {
+	if(ino == PROC_SCSI_SCSI) {            
             /*
-             * If there are no hosts, tell the user to go away.
+             * This is for the scsi core, rather than any specific
+             * lowlevel driver.
              */
-            if( hpnt == NULL ) {
-                return (-ENOSYS);
-            }
-
-	    retval = scsi_proc_info(buffer, start, offset, length, 
-				  hpnt->host_no, func);
-            return(retval);
+            return(scsi_proc_info(buffer, start, offset, length, 0, func));
         }
 
 	while(hpnt) {
-	    if (ino == (hpnt->host_no + PROC_SCSI_FILE)) 
+	    if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
                 if(hpnt->hostt->proc_info == NULL)
                     return generic_proc_info(buffer, start, offset, length, 
                                              hpnt->host_no, func);
                 else
-                    return(hpnt->hostt->proc_info(buffer, start, offset, length, 
-                                                  hpnt->host_no, func));
+                    return(hpnt->hostt->proc_info(buffer, start, offset, 
+                                                  length, hpnt->host_no, func));
+            }
 	    hpnt = hpnt->next;
 	}
 	return(-EBADF);
@@ -154,8 +149,13 @@
 {
     Scsi_Host_Template *tpnt = scsi_hosts;
     struct Scsi_Host *hpnt;
-    static char names[PROC_SCSI_LAST - PROC_SCSI_FILE][3];
     uint x, y;
+
+    /* namespace for 16 HBAs with host_no 0-999 
+     * I don't think we'll need more. Having more than 2 
+     * HBAs in one system is already highly unusual 
+     */
+    static char names[PROC_SCSI_LAST - PROC_SCSI_FILE][4];
     
     x = y = 0;
 
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v1.3.8/linux/drivers/scsi/sd.c	Fri Jul  7 08:54:51 1995
+++ linux/drivers/scsi/sd.c	Tue Jul 11 07:56:04 1995
@@ -58,8 +58,8 @@
  *  Time out in seconds for disks and Magneto-opticals (which are slower).
  */
 
-#define SD_TIMEOUT 700
-#define SD_MOD_TIMEOUT 750
+#define SD_TIMEOUT (7 * HZ)
+#define SD_MOD_TIMEOUT (8 * HZ)
 
 #define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \
 				SC->device->type != TYPE_MOD)
@@ -904,7 +904,8 @@
     
     /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is 
      * considered a fatal error, and many devices report such an error 
-     * just after a scsi bus reset. */
+     * just after a scsi bus reset. 
+     */
     
     SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1);
     buffer = (unsigned char *) scsi_malloc(512);
@@ -1177,7 +1178,7 @@
 static void sd_finish()
 {
     int i;
-    
+
     blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
     
     sd_gendisk.next = gendisk_head;
@@ -1201,11 +1202,10 @@
      * a two block (4 sector) read ahead. 
      */
     if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize)
-	read_ahead[MAJOR_NR] = 120;
-    /* 64 sector read-ahead */
+	read_ahead[MAJOR_NR] = 120;  /* 120 sector read-ahead */
     else
 	read_ahead[MAJOR_NR] = 4;  /* 4 sector read-ahead */
-    
+
     return;
 }
 
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v1.3.8/linux/drivers/scsi/sg.c	Fri Jul  7 08:54:51 1995
+++ linux/drivers/scsi/sg.c	Tue Jul 11 07:56:04 1995
@@ -70,12 +70,16 @@
 static int sg_ioctl(struct inode * inode,struct file * file,
 		    unsigned int cmd_in, unsigned long arg)
 {
+    int result;
     int dev = MINOR(inode->i_rdev);
     if ((dev<0) || (dev>=sg_template.dev_max))
 	return -ENXIO;
     switch(cmd_in)
     {
     case SG_SET_TIMEOUT:
+        result = verify_area(VERIFY_READ, arg, sizeof(long));
+        if (result) return result;
+
 	scsi_generics[dev].timeout=get_user((int *) arg);
 	return 0;
     case SG_GET_TIMEOUT:
@@ -93,6 +97,11 @@
 	return -ENXIO;
     if (O_RDWR!=(flags & O_ACCMODE))
 	return -EACCES;
+
+  /*
+   * If we want exclusive access, then wait until the device is not
+   * busy, and then set the flag to prevent anyone else from using it.
+   */
     if (flags & O_EXCL)
     {
 	while(scsi_generics[dev].users)
@@ -106,6 +115,10 @@
 	scsi_generics[dev].exclude=1;
     }
     else
+        /*
+         * Wait until nobody has an exclusive open on
+         * this device.
+         */
 	while(scsi_generics[dev].exclude)
 	{
 	    if (flags & O_NONBLOCK)
@@ -114,7 +127,15 @@
 	    if (current->signal & ~current->blocked)
 		return -ERESTARTSYS;
 	}
-    if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
+
+    /*
+     * OK, we should have grabbed the device.  Mark the thing so
+     * that other processes know that we have it, and initialize the
+     * state variables to known values.
+     */
+    if (!scsi_generics[dev].users 
+        && scsi_generics[dev].pending
+        && scsi_generics[dev].complete)
     {
 	if (scsi_generics[dev].buff != NULL)
 	    sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
@@ -174,6 +195,11 @@
     scsi_free(buff,size);
 }
 
+/*
+ * Read back the results of a previous command.  We use the pending and
+ * complete semaphores to tell us whether the buffer is available for us
+ * and whether the command is actually done.
+ */
 static int sg_read(struct inode *inode,struct file *filp,char *buf,int count)
 {
     int dev=MINOR(inode->i_rdev);
@@ -181,6 +207,10 @@
     struct scsi_generic *device=&scsi_generics[dev];
     if ((i=verify_area(VERIFY_WRITE,buf,count)))
 	return i;
+
+    /*
+     * Wait until the command is actually done.
+     */
     while(!device->pending || !device->complete)
     {
 	if (filp->f_flags & O_NONBLOCK)
@@ -189,6 +219,10 @@
 	if (current->signal & ~current->blocked)
 	    return -ERESTARTSYS;
     }
+
+    /*
+     * Now copy the result back to the user buffer.
+     */
     device->header.pack_len=device->header.reply_len;
     device->header.result=0;
     if (count>=sizeof(struct sg_header))
@@ -203,6 +237,11 @@
     }
     else
 	count=0;
+    
+    /*
+     * Clean up, and release the device so that we can send another
+     * command.
+     */
     sg_free(device->buff,device->buff_len);
     device->buff = NULL;
     device->pending=0;
@@ -210,6 +249,11 @@
     return count;
 }
 
+/*
+ * This function is called by the interrupt handler when we
+ * actually have a command that is complete.  Change the
+ * flags to indicate that we have a result.
+ */
 static void sg_command_done(Scsi_Cmnd * SCpnt)
 {
     int dev=SCpnt->request.dev;
@@ -220,6 +264,11 @@
 	SCpnt->request.dev=-1;
 	return;
     }
+
+    /*
+     * See if the command completed normally, or whether something went
+     * wrong.
+     */
     memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
     if (SCpnt->sense_buffer[0])
     {
@@ -227,29 +276,44 @@
     }
     else
 	device->header.result=SCpnt->result;
+
+    /*
+     * Now wake up the process that is waiting for the
+     * result.
+     */
     device->complete=1;
     SCpnt->request.dev=-1;
     wake_up(&scsi_generics[dev].read_wait);
 }
 
+#define SG_SEND 0
+#define SG_REC  1
+
 static int sg_write(struct inode *inode,struct file *filp,char *buf,int count)
 {
-    int dev=MINOR(inode->i_rdev);
-    Scsi_Cmnd *SCpnt;
-    int bsize,size,amt,i;
-    unsigned char opcode;
-    unsigned char cmnd[MAX_COMMAND_SIZE];
-    struct scsi_generic *device=&scsi_generics[dev];
+    int			  bsize,size,amt,i;
+    unsigned char	  cmnd[MAX_COMMAND_SIZE];
+    int			  dev=MINOR(inode->i_rdev);
+    struct scsi_generic   * device=&scsi_generics[dev];
+    int			  direction;
+    unsigned char	  opcode;
+    Scsi_Cmnd		* SCpnt;
+    int			  sgcnt;
     
     if ((i=verify_area(VERIFY_READ,buf,count)))
 	return i;
     /*
-     * The minimum scsi command length is 6 bytes.  If we get anything less than this,
-     * it is clearly bogus.
+     * The minimum scsi command length is 6 bytes.  If we get anything
+     * less than this, it is clearly bogus.  
      */
     if (count<(sizeof(struct sg_header) + 6))
 	return -EIO;
-    /* make sure we can fit */
+
+    /*
+     * If we still have a result pending from a previous command,
+     * wait until the result has been read by the user before sending
+     * another command.
+     */
     while(device->pending)
     {
 	if (filp->f_flags & O_NONBLOCK)
@@ -261,27 +325,61 @@
 	if (current->signal & ~current->blocked)
 	    return -ERESTARTSYS;
     }
+
+    /*
+     * Mark the device flags for the new state.
+     */
     device->pending=1;
     device->complete=0;
     memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
-    /* fix input size */
+
+    /*
+     * fix input size, and see if we are sending data.
+     */
     device->header.pack_len=count;
     buf+=sizeof(struct sg_header);
-    bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len;
+    if( device->header.pack_len > device->header.reply_len )
+    {
+        bsize = device->header.pack_len;
+        direction = SG_SEND;
+    } else {
+        bsize = device->header.reply_len;
+        direction = SG_REC;
+    }
+    
+    /*
+     * Don't include the command header itself in the size.
+     */
     bsize-=sizeof(struct sg_header);
+
+    /*
+     * Allocate a buffer that is large enough to hold the data
+     * that has been requested.  Round up to an even number of sectors,
+     * since scsi_malloc allocates in chunks of 512 bytes.
+     */
     amt=bsize;
     if (!bsize)
 	bsize++;
     bsize=(bsize+511) & ~511;
+
+    /*
+     * If we cannot allocate the buffer, report an error.
+     */
     if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
     {
 	device->pending=0;
 	wake_up(&device->write_wait);
 	return -ENOMEM;
     }
+
 #ifdef DEBUG
     printk("allocating device\n");
 #endif
+
+    /*
+     * Grab a device pointer for the device we want to talk to.  If we
+     * don't want to block, just return with the appropriate message.
+     */
     if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
     {
 	device->pending=0;
@@ -293,39 +391,72 @@
 #ifdef DEBUG
     printk("device allocated\n");
 #endif    
-    /* now issue command */
+
+    /*
+     * Now we need to grab the command itself from the user's buffer.
+     */
     SCpnt->request.dev=dev;
     SCpnt->sense_buffer[0]=0;
     opcode = get_user(buf);
     size=COMMAND_SIZE(opcode);
     if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
     SCpnt->cmd_len = size;
-    amt-=device->header.pack_len>device->header.reply_len ? size : 0;
+
+    /*
+     * If we are writing data, subtract off the size
+     * of the command itself, to get the amount of actual data
+     * that we need to send to the device.
+     */
+    if( direction == SG_SEND )
+        amt -= size;
+    
     /*
      * Verify that the user has actually passed enough bytes for this command.
      */
-    if (count<(sizeof(struct sg_header) + size))
+    if( count < (sizeof(struct sg_header) + size) )
     {
 	device->pending=0;
-	wake_up(&device->write_wait);
-	sg_free(device->buff,device->buff_len);
+        wake_up( &device->write_wait );
+        sg_free( device->buff, device->buff_len );
 	device->buff = NULL;
 	return -EIO;
     }
     
+    /*
+     * Now copy the SCSI command from the user's address space.
+     */
     memcpy_fromfs(cmnd,buf,size);
     buf+=size;
-    memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
-    cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5);
+
+    /*
+     * If we are writing data, copy the data we are writing.  The pack_len
+     * field also includes the length of the header and the command,
+     * so we need to subtract these off.
+     */
+    if( direction == SG_SEND )  memcpy_fromfs(device->buff,buf, amt);
+    
+    /*
+     * Set the LUN field in the command structure.
+     */
+    cmnd[1]= (cmnd[1] & 0x1f) | (device->device->lun<<5);
+
 #ifdef DEBUG
     printk("do cmd\n");
 #endif
+
+    /*
+     * Now pass the actual command down to the low-level driver.  We
+     * do not do any more here - when the interrupt arrives, we will
+     * then do the post-processing.
+     */
     scsi_do_cmd (SCpnt,(void *) cmnd,
 		 (void *) device->buff,amt,
 		 sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
+
 #ifdef DEBUG
     printk("done cmd\n");
 #endif               
+
     return count;
 }
 
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v1.3.8/linux/drivers/scsi/sr.c	Fri Jul  7 08:54:51 1995
+++ linux/drivers/scsi/sr.c	Tue Jul 11 07:56:04 1995
@@ -13,6 +13,10 @@
  *
  *	    Modified by Eric Youngdale eric@aib.com to support loadable
  *	    low-level scsi drivers.
+ *
+ *	 Modified by Thomas Quinot thomas@melchior.frmug.fr.net to
+ *	 provide auto-eject.
+ *
  */
 
 #ifdef MODULE
@@ -39,7 +43,7 @@
 #include "constants.h"
 
 #define MAX_RETRIES 3
-#define SR_TIMEOUT 15000
+#define SR_TIMEOUT (150 * HZ)
 
 static void sr_init(void);
 static void sr_finish(void);
@@ -69,9 +73,13 @@
 {
 	sync_dev(inode->i_rdev);
 	if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count)
-	sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+        {
+            sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+	    if (scsi_CDs[MINOR(inode->i_rdev)].auto_eject)
+                sr_ioctl(inode, NULL, CDROMEJECT, 0);
+        }
 	if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
-	(*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
+            (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
 	if(sr_template.usage_count) (*sr_template.usage_count)--;
 }
 
@@ -302,6 +310,11 @@
  *
  *   kraxel@cs.tu-berlin.de (Gerd Knorr)
  */
+/*
+ * 19950704 operator@melchior.frmug.fr.net (Thomas Quinot)
+ *
+ *   - SONY:	Same as Nec.
+ */
 
 static void sr_photocd(struct inode *inode)
 {
@@ -481,7 +494,7 @@
             printk ("sr_photocd: multisession CD detected. start: %lu\n",sector);
 #endif
         break;
-        
+                
     case SCSI_MAN_NEC_OLDCDR:
     case SCSI_MAN_UNKNOWN:
     default:
@@ -1057,6 +1070,7 @@
 	scsi_CDs[i].use = 1;
 	scsi_CDs[i].ten = 1;
 	scsi_CDs[i].remap = 1;
+	scsi_CDs[i].auto_eject = 0; /* Default is not to eject upon unmount. */
 	sr_sizes[i] = scsi_CDs[i].capacity;
     }
     
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- v1.3.8/linux/drivers/scsi/sr.h	Mon Feb 20 08:49:05 1995
+++ linux/drivers/scsi/sr.h	Tue Jul 11 07:56:04 1995
@@ -32,6 +32,7 @@
 	unsigned 	ten:1;			/* support ten byte commands		*/
 	unsigned 	remap:1;		/* support remapping			*/
 	unsigned 	use:1;			/* is this device still supportable	*/
+	unsigned	auto_eject:1;		/* auto-eject medium on last release.	*/
 	} Scsi_CD;
 	
 extern Scsi_CD * scsi_CDs;
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c
--- v1.3.8/linux/drivers/scsi/sr_ioctl.c	Fri Jul  7 08:54:51 1995
+++ linux/drivers/scsi/sr_ioctl.c	Tue Jul 11 07:56:04 1995
@@ -139,6 +139,10 @@
     case CDROMPLAYMSF:
     {
 	struct cdrom_msf msf;
+
+        err = verify_area (VERIFY_READ, (void *) arg, sizeof (msf));
+        if (err) return err;
+
 	memcpy_fromfs(&msf, (void *) arg, sizeof(msf));
 	
 	sr_cmd[0] = SCMD_PLAYAUDIO_MSF;
@@ -159,6 +163,10 @@
     case CDROMPLAYTRKIND:
     {
 	struct cdrom_ti ti;
+
+        err = verify_area (VERIFY_READ, (void *) arg, sizeof (ti));
+        if (err) return err;
+
 	memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
 	
 	sr_cmd[0] = SCMD_PLAYAUDIO_TI;
@@ -213,7 +221,9 @@
 	struct cdrom_tocentry tocentry;
 	char * buffer;
 	
-	verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
+        err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
+        if (err) return err;
+
 	memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry));
 	
 	sr_cmd[0] = SCMD_READ_TOC;
@@ -267,7 +277,10 @@
 	return result;
 	
     case CDROMEJECT:
-	if (scsi_CDs[target].device -> access_count != 1)
+        /*
+         * Allow 0 for access count for auto-eject feature.
+         */
+	if (scsi_CDs[target].device -> access_count > 1)
 	    return -EBUSY;
 	
 	sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
@@ -281,12 +294,18 @@
 	
 	return result;
 	
+    case CDROMEJECT_SW:
+        scsi_CDs[target].auto_eject = !!arg;
+        return 0;
+
     case CDROMVOLCTRL:
     {
 	char * buffer, * mask;
 	struct cdrom_volctrl volctrl;
 	
-	verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
+        err = verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
+        if (err) return err;
+
 	memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl));
 	
 	/* First we get the current params so we can just twiddle the volume */
diff -u --recursive --new-file v1.3.8/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v1.3.8/linux/drivers/scsi/st.c	Fri Jul  7 08:54:51 1995
+++ linux/drivers/scsi/st.c	Tue Jul 11 07:56:04 1995
@@ -83,8 +83,8 @@
 #define MAX_READY_RETRIES 5
 #define NO_TAPE  NOT_READY
 
-#define ST_TIMEOUT 90000
-#define ST_LONG_TIMEOUT 200000
+#define ST_TIMEOUT (900 * HZ)
+#define ST_LONG_TIMEOUT (2000 * HZ)
 
 static int st_nbr_buffers;
 static ST_buffer **st_buffers;
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/.blurb linux/drivers/sound/.blurb
--- v1.3.8/linux/drivers/sound/.blurb	Tue May 30 13:20:32 1995
+++ linux/drivers/sound/.blurb	Fri Jul  7 22:52:28 1995
@@ -1,7 +1,8 @@
-
-	*********************************************************
-	* IF YOU HAVE ANY PROBLEMS WITH THE SOUND DRIVER,	*
-	* PLEASE READ THE SOUND-HOWTO. IT'S AVAILABLE FROM YOUR	*
-	* NEAREST LINUX FTP SITE AND CONTAINS ANSWER TO YOUR	*
-	* PROBLEM.						*
-	*********************************************************
+*********************************************************
+* IF YOU HAVE ANY PROBLEMS WITH THE SOUND DRIVER,       *
+* PLEASE READ THE SOUND-HOWTO. IT'S AVAILABLE FROM YOUR *
+* NEAREST LINUX FTP SITE AND CONTAINS ANSWER TO YOUR    *
+* PROBLEM.                                              *
+* Readme.cards (this directory) contains some card	*
+* specific instructions.				*
+*********************************************************
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/.version linux/drivers/sound/.version
--- v1.3.8/linux/drivers/sound/.version	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/.version	Mon Jul 10 01:42:01 1995
@@ -0,0 +1 @@
+3.0
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/CHANGELOG linux/drivers/sound/CHANGELOG
--- v1.3.8/linux/drivers/sound/CHANGELOG	Mon Mar  6 11:22:09 1995
+++ linux/drivers/sound/CHANGELOG	Mon Jul 10 01:10:38 1995
@@ -1,10 +1,39 @@
-Changelog for version 2.90
-------------------------------------
+Changelog for version 3.0
+-------------------------
 
-This is an intermediate release (v3.0 prototype with some experimental
-features disabled). See experimental.txt for more info.
+Since 3.0-beta2
+- Minor fixes.
+- Added Readme.cards
+
+Since 3.0-beta1
+- Minor fixes to the modules support.
+- Eliminated call to sb_free_irq() in ad1848.c
+- Rewritten MAD16&Mozart support (not tested with MAD16 Pro).
+- Fix to DMA initialization of PSS cards.
+- Some fixes to ad1848/cs42xx mixer support (GUS MAX, MSS, etc.)
+- Fixed some bugs in the PSS driver which caused I/O errors with
+  the MSS mode (/dev/dsp).
+
+Since 3.0-950506
+- Recording with GUS MAX fixed. It works when the driver is configured
+  to use two DMA channels with GUS MAX (16 bit ones recommended).
+
+Since 3.0-94xxxx
+- Too many changes
+
+Since 3.0-940818
+- Fixes for Linux 1.1.4x.
+- Disables Disney Sound System with SG NX Pro 16 (less noise).
+
+Since 2.90-2
+- Fixes to soundcard.h
+- Non blocking mode to /dev/sequencer
+- Experimental detection code for Ensoniq Soundscape.
 
-Since pre-3.0-949712
+Since 2.90
+- Minor and major bug fixes
+
+Since pre-3.0-940712
 - GUS MAX support
 - Partially working MSS/WSS support (could work with some cards).
 - Hardware u-Law and A-Law support with AD1848/CS4248 and CS4231 codecs
@@ -91,7 +120,7 @@
 
 Since 2.1
 - Preliminary support for SB16. 
-  - The SB16 mixer is supported in its native mode.
+  - The SB16 mixer is supported in it's native mode.
   - Digitized voice capability up to 44.1 kHz/8 bit/mono
     (16 bit and stereo support coming in the next release).
 - Fixed some bugs in the digitized voice driver for PAS16.
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v1.3.8/linux/drivers/sound/Makefile	Fri Jan 13 17:25:07 1995
+++ linux/drivers/sound/Makefile	Tue Jul 11 08:02:20 1995
@@ -5,11 +5,10 @@
 #
 #
 
-VERSION		= 2.90-2
+VERSION		= `cat .version`
 TARGET_OS	= linux
+USRINCDIR	= /usr/include
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
@@ -20,15 +19,11 @@
 	 pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \
 	 gus_midi.o gus_vol.o patmgr.o sb_mixer.o sb16_dsp.o sb_midi.o \
 	 sb16_midi.o sound_switch.o midi_synth.o uart6850.o sound_timer.o \
-	 sys_timer.o ics2101.o ad1848.o pss.o
+	 sys_timer.o ics2101.o ad1848.o pss.o sscape.o trix.o aedsp16.o \
+	 mad16.o
 
 all:	local.h sound.a
 
-/usr/include/sys/soundcard.h:
-	@echo "WARNING! Your /usr/include/sys/soundcard.h not found."
-	@echo "Please make a new /usr/include/sys/soundcard.h containing"
-	@echo "just a line #include <linux/soundcard.h>"
-
 sound.a: $(OBJS) 
 	-rm -f sound.a
 	$(AR) rcs sound.a $(OBJS)
@@ -36,7 +31,7 @@
 
 clean:
 	rm -f core core.* *.o *.a tmp_make *~ x z *%
-	rm -f configure sound_stub.c
+	rm -f configure
 	for i in *.c;do rm -f `basename $$i .c`.s;done
 
 indent:
@@ -44,38 +39,36 @@
 
 local.h:
 	$(MAKE) clean
+	$(MAKE) setup-$(TARGET_OS)
 	$(MAKE) config
 	$(MAKE) dep
 
-config: configure /usr/include/sys/soundcard.h
-	@echo Compiling Sound Driver v $(VERSION) for Linux
+config: configure
+	@$(MAKE) setup-$(TARGET_OS)
 	@./configure > local.h
-	@echo \#define SOUND_VERSION_STRING \"$(VERSION)\" >> local.h
 	@echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h
 	@echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h
 	@echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h
-	@if [ -x /bin/dnsdomainname ]; then \
-           echo \#define SOUND_CONFIG_DOMAIN \"`dnsdomainname`\"; \
-         else \
-           echo \#define SOUND_CONFIG_DOMAIN \"`domainname`\"; \
-         fi >> local.h
+	@echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h
 
 clrconf:
-	rm -f local.h .depend
+	rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h
 
-configure: configure.c /usr/include/sys/soundcard.h
+configure: configure.c
 	$(HOSTCC) -o configure configure.c
 	@cat .blurb
 
 dep:
-	$(MAKE) /usr/include/sys/soundcard.h
 	$(CPP) -M *.c > .depend
 
-modules:
+setup-linux:
+	@echo Compiling Sound Driver v $(VERSION) for Linux
+
+sound.o: $(OBJS) 
+	-rm -f sound.o
+	$(LD) -r -o sound.o $(OBJS)
+
+modules: sound.o
+	(cd ../../modules; ln -fs ../drivers/sound/sound.o .)
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme linux/drivers/sound/Readme
--- v1.3.8/linux/drivers/sound/Readme	Thu Feb  9 18:29:53 1995
+++ linux/drivers/sound/Readme	Mon Jul 10 19:13:24 1995
@@ -1,28 +1,81 @@
-VoxWare v2.90 release notes
---------------------------
+Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux ftp 
+sites). It contains much more information than this file.
 
+*****************************************************************
+* NEW! VoxWare home page is http://personal.eunet.fi/pp/voxware *
+* The file Readme.cards contains card specific instructions     *
+* about configuring various cards.				*
+*****************************************************************
 
-		This version includes some hidden features which
-		are described in the file experimental.txt
-		Some of these features are not enabled by default. Look at
-		experimental.txt for more info.
-
-		I just decided to release this version with some
-		incompletely implemented features disabled since
-		there are some new features required by a popular 
-		application. In addition there is also support
-		for the GUS MAX and the 16 bit sampling option of GUS.
-
-		The MSS/WSS support works now. At least with SG NX Pro 16.
-
-********* IMPORTANT *****************************************
-Linux 1.0 or later is required to by this driver version.
-
-Don't distribute binaries which use /dev/sequencer and are
-compiled with the soundcard.h of this version. They will
-not work with version 2.x of the driver.
-*************************************************************
+VoxWare v3.0 release notes
+--------------------------
 
+This version is the final v3.0. All features I have planned to
+include in v3.0 are there but some of them are completely untested
+(see experimental.txt).
+
+NOTE!	This Linux only distribution doesn't contain files required
+	for other operating systems than Linux. They are distributed
+	in file VoxWare-3.0.tar.gz which is available from
+	sunsite.unc.edu:pub/Linux/kernel/sound (or pub/Linux/Incoming).
+
+	Also some utilities for SoundScape, PSS and AudioTriX cards
+	have been removed. They are available in VoxWare-3.0.tar.gz and
+	in snd-util-3.0.tar.gz (when I have time to release it).
+
+*** GUS MAX enhancements *****************************************************
+Recording with GUS MAX works now. The configuration program asks
+two DMA channels for GUS MAX. You have to use two different 16 bit
+DMA numbers (5, 6 or 7) if you want to record (8 bit DMA channels
+may or may not work). It's still possible to use just one DMA channel
+with GUS MAX but recording doesn't work in this case (a hardware limitation).
+Even the driver has capability to use two DMA channels, simultaneous recording
+and playback is not possible with GUS MAX (will not be before v4.0 
+of the driver). However it's now possible to play using /dev/dsp and /dev/dsp1
+at the same time (or /dev/dsp and /dev/sequencer as well).
+Recording using /dev/dsp1 will not work if GUS MAX is configured to use two
+DMA channels.
+******************************************************************************
+
+There are some additional device files (since v2.90-2 andv3.0-proto-94mmdd 
+versions).
+You will need to create additional device files using the script at the
+end of ./linux/Readme. Also recompile all mixer programs since there are
+some new channels that are not enabled in mixers compiled with older
+soundcard.h.
+
+There are some programming information (little bit old) in the
+Hacker's Guide 
+(ftp://nic.funet.fi/pub/OS/Linux/ALPHA/sound/snd-sdk-doc-0.1.ps.gz).
+Believe me: The file is really there. The directory is just hidden and
+you have to cd into it before the file is visible.
+
+I have got many patches from various persons during last year. Some of
+them are still on my mailbox and they should be included in versions
+after v3.0 (I will not add aditional features before v3.0 is ready).
+
+   ====================================================
+-  THIS VERSION ____REQUIRES____ Linux 1.2.0 OR LATER.
+   ====================================================
+
+-  THIS VERSION MAY NOT WORK WITH Linux VERSIONS RELEASED
+   AFTER end of July 1995. If this version doesn't compile with
+   your kernel version, please use the sound driver version
+   included in your kernel.
+-  Ensoniq SoundScape support is included in this version but it's
+   somehow incomplete. MIDI recording may not work and you have to
+   use /dev/dsp1 and /dev/audio1 (/dev/dsp and /dev/audio don't work).
+   I recommend you recreate the device files used by the driver by
+   running the script at the end of linux/Readme. Then just
+   rm /dev/dsp;ln -s /dev/dsp1 /dev/dsp (and the same with /dev/audio).
+   You will also need the latest version of the soundscape.co[01] file.
+   The old sndscape.cod will ___NOT___ work (it propably just hangs your
+   system completely). The latest code file is available from ftp.ensoniq.com
+   as part of the DOS/Windows driver distribution. See sndscape/ssinit.c
+   for more info.
+-  This is Linux only version. It should work in other operating systems
+   (SCO, UW, FreeBSD and NetBSD) too but may require some fixes before
+   it compiles.
 
 You will need the snd-util-2.5.tar.gz and snd-data-0.1.tar.Z
 packages to use this driver. They should be in the same
@@ -32,55 +85,187 @@
 If you are looking for the installation instructions, please
 look at linux/Readme.
 
+Supported soundcards
+--------------------
+
+Gravis Ultrasound (GUS)
+GUS MAX
+GUS with the 16 bit sampling daughtercard
+PAS16
+Windows Sound System compatible soundcards
+ECHO-PSS (cards based on the PSS architecture by Analog Devices.
+	Including Orchid SW32, Cardinal DSP16 among others).
+		(NOTE! WSS mode may not work (DMA channel setup problem)).
+MediaTriX AudioTriX Pro (OPL4 and the optional effect daughtercard
+	require special initialization. There is a program (setfx) in
+	the audiotrix directory which does it).
+Ensoniq SoundScape (works but needs some improvements)
+MV Jazz16 based soundcards (ProSonic, 3D etc).
+SoundMan Wave (recording may not work, mixer support is limited)
+Mozart (OAK OTI-601 interface chip) based soundcards.
+MAD16 (an interface chip by OPTi) based soundcards (TB Tropez ???).
+(NOTE! The MAD16 looks similar to the Mozart chip. It could be a good
+idea to configure MAD16 cards as Mozart ones. The MAD16 driver doesn't set
+up MPU401 which the Mozart one does.
+
+In addition all Sound Blaster models and clones (up to AWE32) work if
+you want to use them.
+
+The Emu synthesizer chip of AWE32 is not and will not be supported. The same is
+true with the ASP chip also. Creative Technology will not release detailed
+information about them so it's not possible to support them.
+
+If you want to get support for AWE32 or ASP, please contact Creative Labs.
+Ask _politely_ if they are going to support Linux. Maybe they change
+their policy if there is enough demand.
+
+===========================================================================
+If your card is compatible with SB, MPU401 or Windows Sound System, it
+may work with the driver even if it's not listed in the above list. In this
+case it may require initialization using DOS. Just start DOS and cold
+boot to Linux (etc.) by hitting ctrl-alt-del. 
+===========================================================================
+
 Compatibility with the earlier versions
 ---------------------------------------
 
-This version is backward compatible with the version 2.X. All programs
-compiled with sys/soundcard.h of v2.X should work without problems.
-PROGRAMS COMPILED WITH THE sys/soundcard.h OF THIS VERSION WILL NOT
-WORK WITH v2.X DRIVER. BE CAREFUL WHEN DISTRIBUTING BINARIES COMPILED 
-FOR THIS VERSION.
+There have been some changes in soundcard.h after v2.5 of the driver
+(v2.90 is compatible with this one). Binaries compiled with this version
+of soundcard.h will not work with v2.0 and earlier.
 
 Contributors
 ------------
 
 This driver contains code by several contributors. In addition several other
-persons have given useful suggestions. The following is a list of major
+persons have given usefull suggestions. The following is a list of major
 contributors. (I could have forgotten some names.)
 
 	Craig Metz	1/2 of the PAS16 Mixer and PCM support
 	Rob Hooft	Volume computation algorithm for the FM synth.
 	Mika Liljeberg	uLaw encoding and decoding routines
+	Andy Fingerhut	New ulaw conversion tables (ulaw.h)
+	Jeff Tranter	Linux SOUND HOWTO document
 	Greg Lee	Volume computation algorithm for the GUS and
 			lot's of valuable suggestions.
 	Andy Warner	ISC port
-	Jim Lowe	FreeBSD port
+	Jim Lowe,
+	Amancio Hasty Jr	FreeBSD/NetBSD port
 	Anders Baekgaard 	Bughunting and valuable suggestions.
 	Joerg Schubert	SB16 DSP support.
 	Andrew Robinson Improvements to the GUS driver
 	Megens SA	MIDI recording for SB and SB Pro.
-	Mikael Nordqvist  Linear volume support for GUS.
-	Mikael Nordqvist  	Linear volume support for GUS.
+	Mikael Nordqvist  Linear volume support for GUS and
+			  nonblocking /dev/sequencer.
 	Ian Hartas		SVR4.2 port
 	Markus Aroharju	and
 	Risto Kankkunen		Major contributions to the mixer support
 				of GUS v3.7.
 	Hunyue Yau	Mixer support for SG NX Pro.
 	Marc Hoffman	PSS support.
+	Rainer Vranken	Initialization for Jazz16 (ProSonic, MV3D, SM Wave).
+	Peter Trattler	Loadable module support for Linux.
+	JRA Gibson	16 bit mode for Jazz16
+	Davor Jadrijevic MAD16 support
+	Gregor Hoffleit	Mozart support
+	Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support
+
+There are propably many other names missing. If you have sent me some
+patches and your name is not in the above list, please inform me.
+
+Sponsors etc.
+-------------
+
+The following companies have greatly helped development of this driver 
+in form of a free copy of their product:
+
+Novell Inc,		UnixWare personal edition + SDK
+Ensoniq Corp,		a SoundScape card and extensive amount of assistance
+MediaTriX Peripherals Inc, a AudioTriX Pro card + SDK
+
+In addition the following companies have provided me sufficial amount
+of technical information at least some of their products (free or $$$):
+
+Advanced Gravis Computer Technology Ltd.
+Media Vision Inc.
+Analog Devices Inc.
+Logitech Inc.
+Aztech Labs Inc.
+Crystal Semiconductor Corporation,
+Integrated Circuit Systems Inc.
+OAK Technology
+OPTi
+Ad Lib Inc. ($$)
+Music Quest Inc. ($$)
+Creative Labs ($$$)
+
+If you have some problems
+=========================
+
+Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?).
+
+It's likely that you have some problems when trying to use the sound driver
+first time. Soundcards don't have standard configuration so there are no
+good default configuration to use. Please try to use same I/O, DMA and IRQ
+values for the soundcard than with DOS.
+
+If you get an error message when trying to use the driver, please look
+at /var/adm/messages for more verbose error message.
+
+
+In general the easiest way to diagnoze problems is to do "cat /dev/sndstat".
+
+If you get an error message, there are some problems with the driver setup:
+
+	- "No such file or directory" tells that the device files for
+	the sound driver are missing. Use the script at the end of
+	linux/drivers/sound/Readme.linux to create them.
+
+	- "No such device" telss that the sound driver is not in the kernel.
+	You have to reconfigure and recompile the kernel to have the sound
+	driver. Compiling the driver doesn't help alone. You have to boot
+	with the newly compiled one before the driver becomes active.
+	The Linux-HOWTO should help in this step.
+
+The following errors are likely with /dev/dsp and /dev/audio.
+
+	- "No such device or address". This error message should not happen
+	with /dev/sndstat but it's possible with the other sound devices.
+	This error indicates that there are no suitable hardware for the
+	device file or the sound driver has been compiled without support for
+	this particular device. For example /dev/audio and /dev/dsp will not
+	work if "digitized voice support" was not enabled during "make config".
+	
+	- "Device or resource busy". Propably the IRQ (or DMA) channel 
+	required by the soundcard is in use by some other device/driver.
+
+	- "I/O error". Almost certainly (99%) it's an IRQ or DMA conflict.
+	Look at the kernel messages in /var/adm/notice for more info.
+
+	- "Invalid argument". The application is calling ioctl()
+	with impossible parameters. Check that the application is
+	for sound driver version 2.X or later.
+
+In general the printout of of /dev/sndstat should tell what is the problem.
+It's possible that there are bugs in the sound driver but 99% of the problems
+reported to me are caused by somehow incorrect setup during "make config".
+
+Hannu
 
 Regards,
 
 Hannu Savolainen
 hannu@voxware.pp.fi
+(or Hannu.Savolainen@cctap.carel.fi in case the above bounces)
 
 Snail mail:	Hannu Savolainen
 		Hiekkalaiturintie 3 A 8
 		00980 Helsinki
 		Finland
-FAX:		+358 0 341 6272 (answers if I have my machine (mgetty) on).
 
-NOTE!	I probably don't answer to Snail mail or FAX messages. Sending answer
+NOTE!	I propably don't answer to Snail mail or FAX messages. Sending answer
 	to each of them is simply too expensive and time consuming. However I
-	try to reply every email message I get (within a week). If you don't
+	try to reply every email message I get (within a week). If you don't 
 	get response, please check how your address is written in the message
 	header. I can't answer if I don't have a valid reply address.
+
+VoxWare home page is http://personal.eunet.fi/pp/voxware
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.aedsp16 linux/drivers/sound/Readme.aedsp16
--- v1.3.8/linux/drivers/sound/Readme.aedsp16	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/Readme.aedsp16	Fri Apr 28 03:54:01 1995
@@ -0,0 +1,6 @@
+Informations about Audio Excel DSP 16 can be found in the source
+file aedsp16.c
+Please, read the head of the source before using it. It contain useful
+informations.
+
+    Riccardo
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v1.3.8/linux/drivers/sound/Readme.cards	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/Readme.cards	Mon Jul 10 00:59:31 1995
@@ -0,0 +1,770 @@
+Configuring VoxWare 3.0 (for Linux) with some most common soundcards
+====================================================================
+
+NOTE! This document may contain some error. Please inform me
+      if you find any mistakes.
+
+Read this before trying to configure the driver
+-----------------------------------------------
+
+There are currently many cards that work with VoxWare. 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
+support in VoxWare. Detailed instructions for configuring these cards
+will be given later in this document.
+
+Pro Audio Spectrum 16 (PAS16) and compatibles:
+	Pro Audio Spectrum 16
+	Pro Audio Studio 16
+	Logitech Sound Man 16
+	NOTE! The original Pro Audio Spectrum as well as the PAS+ are not
+	      and will not be supported by VoxWare.
+
+Media Vision Jazz16 based cards
+	Pro Sonic 16
+	Logitech SoundMan Wave
+	(Other Jazz based cards should work but I don't have any reports
+	about them).
+
+Sound Blasters
+	SB 1.0 to 2.0
+	SB Pro
+	SB 16
+	NOTE!	The ASP chip and the EMU synth of the AWE32 is not supported 
+		since their manufacturer doesn't release information about
+		the card. However both the AB16ASP and the AWE32 work with
+		VoxWare just like a SB16. Also see the comment about some
+		unsupported cards at the end of this file.
+	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
+		be a proprietary one like MV Jazz16.
+
+Gravis Ultrasound (GUS)
+	GUS
+	GUS + the 16 bit option
+	GUS MAX
+	(GUS ACE ????????????)
+
+MPU-401	and compatibles
+	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
+	in VoxWare have their own MPU401 driver. Enabling the standard one
+	will cause a conflict with these cards. So look 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
+	(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,
+	MediaTriX AudioTriX Pro and TB Tropez. 
+
+	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 to VoxWare. Note also that most MSS compatible cards
+	require special boot time initialization which may not be present
+	in VoxWare. Also some MSS compatible cards have native support in
+	VoxWare. 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.
+
+6850 UART MIDI
+	This UART chip is used in the MIDI interface of some (rare)
+	soundcards. It's supported by VoxWare in case you need it.
+
+Yamaha FM synthesizers (OPL2, OPL3 and OPL4)
+	Most soundcards have a FM synthesizer chip. The OPL2 is a 2
+	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. VoxWare supports
+	just the OPL3 mode directly. Most cards having a OPL4 (like
+	SM Wave and AudioTriX Pro) support the OPL4 mode using MPU401
+	emulation. Writing a native OPL4 support to VoxWare is difficult
+	since Yamaha doesn't give information about their sample ROM chip.
+
+	Enable the generic OPL2/OPL3 FM synthesizer support if your
+	card has a FM chip made by Yamaha. Don't enable it if your card
+	has a software (TRS) based FM emulator.
+
+PSS based cards (AD1848 + ADSP-2115 + Echo ESC614 ASIC)
+	Analog Devices and Echo Speech have together defined a soundcard
+	architecture based on the above chips. The DSP chip is used
+	for emulation of SB Pro, FM and General MIDI/MT32.
+
+	There are several cards based on this architecture. The most known
+	ones are Orchid SW32 and Cardinal DSP16. 
+
+	VoxWare supports downloading DSP algorithms to these cards.
+
+MediaTriX AudioTriX Pro
+	The ATP card is built around a CS4231 codec and a OPL4 synthesizer
+	chips. The OPL4 mode is supported by a microcontroller running a
+	General MIDI emulator. There is also SB 1.5 playback mode.
+
+Ensoniq SoundScape and compatibles
+	Ensoniq has designed a soundcard architecture based on the
+	OTTO synthesizer chip used in their professional MIDI synthesizers.
+	Several companies (including Ensoniq, Reveal and Spea) are selling
+	cards based on this architecture.
+
+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
+	chips is to connect other audio components to the PC bus. The
+	interface chip performs address decoding for the other chips.
+
+Audio Excell DSP16 
+	Support for this card is made by Riccardo Faccetti
+	(riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info.
+
+What if your card was not listed above?
+---------------------------------------
+
+The first thing to do is to look at the major IC chips on the card.
+Many of the latest soundcards are based on some standard chips. If you
+are lucky, all of them could be supported by VoxWare. The most common ones
+are the OPTi MAD16, Mozart, SoundScape (Ensoniq) and the PSS architectures
+listed above. Also look at the end of this file for list of unsupported
+cards and the ones which could be supported later.
+
+The last resort is to send _exact_ name and model information of the card
+to me together with a list of the major IC chips (manufactured, model) to 
+me. I could then try to check if your card looks like something familiar.
+
+There are much more cards in the word than listed above. The first thing to
+do with these cards is to check if they emulate some other card/interface
+such as SB, MSS and/or MPU401. In this case there is a chance to get the
+card to work by booting DOS before starting Linux (boot DOS, hit ctrl-alt-del
+and boot Linux without hard resetting the machine). In this method the
+DOS based driver initializes the hardware to use a known I/O, IRQ and DMA
+settings. If VoxWare is configured to use the same settings, everything should 
+work OK.
+
+
+Configuring VoxWare (with Linux)
+================================
+
+VoxWare sound driver is currently a part of Linux kernel distribution. The 
+driver files are located in directory /usr/src/linux/drivers/sound. 
+
+****************************************************************************
+*	VoxWare MUST BE CONFIGURED AND COMPILED WITH THE KERNEL. TRYING    *
+*	TO COMPILE IT ALONE WILL _NOT_ WORK.				   *
+*									   *
+*	ALWAYS USE THE SOUND DRIVER VERSION WHICH IS DISTRIBUTED WITH	   *
+*	THE KERNEL SOURCE PACKAGE YOU ARE USING. SOME ALPHA AND BETA TEST  *
+*	VERSIONS CAN BE INSTALLED FROM A SEPARATELY DISTRIBUTED PACKAGE	   *
+*	BUT CHECK THAT THE PACKAGE IS NOT MUCH OLDER (OR NEWER) THAN THE   *
+*	KERNEL YOU ARE USING. IT'S POSSIBLE THAT THE KERNEL/DRIVER 	   *
+*	INTERFACE CHANGES BETWEEN KERNEL RELEASES WHICH MAY CAUSE SOME	   *
+*	INCOMPATIBILITY PROBLEMS.					   *
+*									   *
+*	IN CASE YOU INSTALL A SEPARATELY DISTRIBUTED SOUND DRIVER VERSION, *
+*	BE SURE TO REMOVE OR RENAME THE OLD SOUND DRIVER DIRECTORY BEFORE  *
+*	INSTALLING THE NEW ONE. LEAVING OLD FILES TO THE SOUND DRIVER	   *
+*	DIRECTORY _WILL_ CAUSE PROBLEMS WHEN THE DRIVER IS USED OR	   *
+*	COMPILED.							   *
+****************************************************************************
+
+To configure the driver, run "make config" in the kernel source directory
+(/usr/src/linux). Answer y to the question about Sound card support (after
+questions about mouse, CD-ROM, ftape, etc. supports). Sound config options
+will then be asked after some additional questions.
+
+After configuring the kernel and sound driver, run "make dep" and compile
+the kernel following instructions in the kernel README.
+
+The sound driver configuration dialog
+-------------------------------------
+
+All config information of the sound driver is written to file 
+linux/drivers/sound/local.h. You may save the old version is this file and
+use it again in case you want to use the same config later. In this case
+just answer n to each question made by the sound config program and put
+the original local.h back before running "make dep".
+Don't do this if the version number of the sound driver has changed. In this
+case you have to enter the configuration information again.
+
+If you already have the sound driver installed, consult printout of
+"cat /dev/sndstat" when configuring the driver again. It gives the I/O,
+IRQ and DMA settings you have used earlier.
+
+
+The sound config program (linux/drivers/sound/configure) starts by making
+some yes/no questions. Be careful when answering to these questions since
+answering y to a question may prevent some later ones from being asked. For
+example don't answer y to the first question (PAS16) if you don't really
+have a PAS16. Don't enable more cards than you really need since they
+just consume memory. Also some drivers (like MPU401) may conflict with your
+SCSI controller and prevent kernel from booting. If you card was in the list
+of supported cards (above), please look at the card specific config 
+instructions (later in this file) before starting to configure. Some cards
+must be configured in way which is not obvious.
+
+So here is the beginning of the config dialog. Answer 'y' or 'n' to these
+questions. The default answer is shown so that (y/n) means 'y' by default and
+(n/y) means 'n'. To use the default value, just hit ENTER. But be careful
+since using the default _doesn't_ guarantee anything.
+
+Note also that all questions may not be asked. The configuration program
+may disable some questions dependig on the earlier choices. It may also
+select some options automaticly as well.
+
+  "ProAudioSpectrum 16 support",
+	- Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_,
+	  ProAudio Studio 16 or Logitech SoundMan 16 (be sure that
+	  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.
+  "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
+	  SM Games). If your card was in the list of supported cards (above),
+	  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.
+  "Generic OPL2/OPL3 FM synthesizer support",
+	- Answer 'y' if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4).
+	  Answering 'y' is usually a safe and recommended choice. However some
+	  cards may have software (TSR) FM emulation. Enabling FM support
+	  with these cards may cause trouble. However I don't currently know
+	  such cards.
+  "Gravis Ultrasound support",
+	- Answer 'y' if you have GUS or GUS MAX. Answer 'n' if you don't
+	  have GUS since the GUS driver consumes much memory.
+	  Currently I don't have experiences with the GUS ACE so I don't
+	  know what to answer with it.
+  "MPU-401 support (NOT for SB16)",
+	- Be careful with this question. The MPU401 interface is supported
+	  by almost any soundcard today. However some natively supported cards
+	  have their own driver for MPU401. Enabling the MPU401 option with
+	  these cards wil cause a conflict. Also enabling MPU401 on a system
+	  that doesn't really have a MPU401 could cause some trouble. If your
+	  card was in the list of supported cards (above), please look at
+	  the card specific instructions later in this file.
+	  It's safe to answer 'y' if you have a true MPU401 MIDI interface
+	  card.
+  "6850 UART Midi support",
+	- It's safe to answer 'n' to this question in all cases. The 6850
+	  UART interface is so rarely used.
+  "PSS (ECHO-ADI2111) support",
+	- Answer 'y' only if you have Orchid SW32, Cardinal DSP16 or some
+	  other card based on the PSS chipset (AD1848 codec + ADSP-2115
+	  DSP chip + Echo ESC614 ASIC CHIP).
+  "16 bit sampling option of GUS (_NOT_ GUS MAX)",
+	- Answer 'y' if you have installed the 16 bit sampling daughtercard
+	  to your GUS. Answer 'n' if you have GUS MAX. Enabling this option
+	  disables GUS MAX support.
+  "GUS MAX support",
+	- Answer 'y' only if you have a GUS MAX.
+  "Microsoft Sound System support",
+	- Again think carefully before answering 'y' to this question. It's
+	  safe to answer 'y' in case you have the original Windows Sound 
+	  System card made by Microsoft or Aztech SG 16 Pro (or NX16 Pro).
+	  Also you may answer 'y' in case your card was not listed earlier
+	  in this file. For cards having native support in VoxWare, consult
+	  the card specific instructions later in this file. Some drivers
+	  have their own MSS support and enabling this option wil cause a
+	  conflict.
+  "Ensoniq Soundscape support",
+	- Answer 'y' if you have a soundcard based on the Ensoniq SoundScape
+	  chipset. Suach cards are being manufactured at least by Ensoniq,
+	  Spea and Reveal (note that Reveal makes other cards also).
+  "MediaTriX AudioTriX Pro support",
+	- Answer 'y' if you have the AudioTriX Pro.
+  "Support for MAD16 and/or Mozart based cards",
+	- Answer y if your card has a Mozart (OAK OTI-601) or MAD16
+	  (OPTi 82C928 or 82C929) audio interface chip. These chips are
+	  currently quite common so it's possible that many no-name cards
+	  have one of them. In addition the MAD16 chip is used in some
+	  cards made by known manufacturers such as Turtle Beach (Tropez),
+	  Reveal (some models) and Diamond (latest ones).
+  "SoundBlaster Pro support",
+	- Enable this option if your card is SB Pro or SB16. Enable it
+	  also with any SB Pro clones. Answering 'n' saves some amount of
+	  memory but 'y' is the safe alterative.
+  "SoundBlaster 16 support",
+	- Enable if you have a SB16 (including the AWE32).
+  "Audio Excel DSP 16 initialization support",
+	- Don't know much about this card. Look at aedsp16.c for more info.
+
+Then the configuration program asks some y/n questions about the higher
+level services. It's recommended to answer 'y' to each of these questions.
+Answer 'n' only if you know you will not need the option.
+
+  "/dev/dsp and /dev/audio supports (usually required)",
+	- Answering 'n' disables /dev/dsp and /dev/audio. Answer 'y'.
+  "MIDI interface support",
+	- Answering 'n' disables /dev/midi## devices and access to any
+	  MIDI ports using /dev/sequencer and /dev/music. This option
+	  also affects any MPU401 and/or General MIDI compatible devices.
+  "FM synthesizer (YM3812/OPL-3) support",
+	- Answer 'y' here.
+  "/dev/sequencer support",
+	- Answering 'n' disables /dev/sequencer and /dev/music.
+
+Entering the I/O, IRQ and DMA config parameters
+-----------------------------------------------
+
+After the above questions the configuration program prompts for the
+card specific configuration information. Usually just a set of
+I/O address, IRQ and DMA numbers are asked. With some cards the program
+asks for some files to be used during initialization of the card. For example
+many cards have a DSP chip or microprocessor which must be initialized by
+downloading a program (microcode) file to the card. In some cases this file
+is written to a .h file by the config program and then included to the driver
+during compile.
+
+Instructions for answering these questions are given in the next section.
+
+
+Card specific information
+=========================
+
+This section gives additional instructions about configuring some cards.
+Please refer manual of your card for valid I/O, IRQ and DMA numbers. Using
+the same settings with DOS/Windows and VoxWare is recommended. Using
+different values could cause some problems when switching between
+different operating systems.
+
+SoundBlasters (the original ones by Creative)
+---------------------------------------------
+
+It's possible to configure these cards to use different I/O, IRQ and
+DMA settings. Since the available settings have changed between various
+models, you have to consult manual of your card for the proper ones. It's
+a good idea to use the same values than with DOS/Windows. With SB and SB Pro
+it's the only choice. SB16 has software selectable IRQ and DMA channels but
+using different values with DOS and Linux is likely to cause troubles. The
+DOS driver is not able to reset the card properly after warm boot from Linux
+if Linux has used different IRQ or DMA values.
+
+The original (steam) Sound Blaster (versions 1.x and 2.x) use always
+DMA1. There is no way to change it.
+
+The SB16 needs two DMA channels. A 8 bit one (1 or 3) is required for
+8 bit operation and a 16 bit one (5, 6 or 7) for the 16 bit mode. In theory
+it's possible to use just one (8 bit) DMA channel by answering the 8 bit
+one when the configuration program asks for the 16 bit one. This may work
+in some systems but is likely to cause terrible noise on some other systems.
+
+NOTE!	Don't enable the SM Games option (asked by the configuration program)
+	if you are not 101% sure that your card is a Logitech Soundman Games
+	(not a SM Wave or SM16).
+
+SB Clones
+---------
+
+First of all: There are no SB16 clones. There are SB Pro clones with a
+16 bit mode which is not SB16 compatible. The most likely alternative is that
+the 16 bit mode means MSS/WSS.
+
+There are just few fully 100% hardware SB or SB Pro compatible cards.
+I know just Thunderboard and SM Games. Other cards require some kind of
+hardware initialization before they become SB compatible. Check if your card
+was listed in the beginning of this file. In this case you should follow
+instructions for your card later in this file.
+
+For other not fully SB clones yoy may try initialization using DOS in
+the following way:
+
+	- Boot DOS so that the card specific driver gets run.
+	- Hit ctrl-alt-del (or use loadlin) to boot Linux. Don't
+	  switch off power or press the reset button.
+	- If you use the same I/O, IRQ and DMA settings in Linux, the
+	  card should work.
+
+If your card is both SB and MSS compatible, I recommend using the MSS mode.
+Most cards of this kind are not able to work in the SB and the MSS mode 
+simultaneously. Using the MSS mode provides 16 bit recording and playback.
+
+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.
+
+With PAS16 you can use two audio devices at the same time. /dev/dsp (and
+/dev/audio) is connected to the 8/16 bit native codec and the /dev/dsp1 (and
+/dev/audio1) is connected to the SB emulation (8 bit mono only).
+
+Gravis Ultrasound
+-----------------
+
+There are many different revisions of the Ultrasound card (GUS). The
+earliest ones (pre 3.7) don't have a hardware mixer. With these cards
+the driver uses a software emulation for synth and pcm playbacks. It's
+also possible to switch some of the inputs (line in, mic) off by setting
+mixer volume of the channel level below 10%. For recording you have
+to select the channel as a recording source and to use volume above 10%.
+
+GUS 3.7 has a hardware mixer.
+
+GUS MAX and the 16 bit sampling daughtercard have a CS4231 codec chip which 
+also contains a mixer.
+
+Configuring GUS is simple. Just enable the GUS support and GUS MAX or
+the 16 bit daughtercard if you have them. Note that enabling the daughter
+card disables GUS MAX.
+
+With just the standard GUS enabled the configuration program prompts
+for the I/O, IRQ and DMA numbers for the card. Use the same values than
+with DOS.
+
+With the daughter card option enabled you will be prompted for the I/O,
+IRQ and DMA numbers for the daughter card. You have to use different I/O
+and DMA values than for the standard GUS. The daughter card permits
+simultaneous recording and playback. Use /dev/dsp (the daughtercard) for
+recording and /dev/dsp1 (GUS GF1) for playback.
+
+GUS MAX uses the same I/O address and IRQ settings than the original GUS
+(GUS MAX = GUS + a CS4231 codec). In addition an extra DMA channel may be used.
+Using two DMA channels permits simultaneous playback using two devices but
+simultaneous recording and playback is not possible (not before v4.0).
+Also using two DMA channels is required if you want to record in 16 bit modes.
+To enable the second DMA channels, give a valid DMA channel when the config
+program asks for the GUS MAX DMA (entering 0 disables the second DMA).
+Using 16 bit DMA channels (5,6 or 7) is recommended. The drawback of
+using two DMA channels with GUS MAX is that recording from /dev/dsp1
+(the 8 bit codec) is disabled.
+
+It's not guaranteed that recording using GUS MAX works (in 3.0-beta2).
+
+MPU401 and Windows Sound System
+-------------------------------
+
+Again. Don't enable these options in case your card is listed
+somewhere else in this file.
+
+Configuring these cards is obvious (or it should be). With MSS
+you should propably enable the OPL3 synth also since
+most MSS compatible cards have it. However check that this is true
+before enabling OPL3.
+
+VoxWare supports more than one MPU401 compatible cards at the same time
+but the config program asks config info for just the first of them.
+Adding the second or third MPU interfaces must be done manually by
+editing sound/local.h (after running the config program). Add defines for
+MPU2_BASE & MPU2_IRQ (and MPU3_BASE & MPU3_IRQ) to the file.
+
+PSS
+---
+
+Even the PSS cards are compatible with SB, MSS and MPU401, you must not
+enable these options when configuring the driver. The configuration
+program handles these options itself. (You may use the SB, MPU and MSS options
+together with PSS if you have another card on the system).
+
+The PSS driver enables MSS and MPU401 modes of the card. SB is not enabled 
+since it doesn't work concurrently with MSS. The driver loads also a
+DSP algorithm which is used to for the general MIDI emulation. The
+algorithm file (.ld) is read by the config program and written to a
+file included when the pss.c is compiled. For this reason the config
+program asks if you want to download the file. Use the genmidi.ld file
+distributed with the DOS/Windows drivers of the card (don't use the mt32.ld).
+With some cards the file is called 'synth.ld'. You must have access to
+the file when configuring the driver. The easiest way is to mount the DOS
+partition containing the file with Linux. 
+
+It's possible to load your own DSP algorithms and run them with the card.
+Look at the directory sound/pss_test for more info (in the VoxWare-3.0.tar.gz)
+package.
+
+AudioTriX Pro
+-------------
+
+You have to enable the OPL3 and SB (not SB Pro or SB16) drivers in addition
+to the native AudioTriX driver. You don't need to enable MSS or MPU drivers.
+
+Configuring ATP is little bit tricky since it uses so many I/O, IRQ and
+DMA numbers. Using the same values than with DOS/Win is a good idea. Don't
+attemp to use the same IRQ or DMA channels twice.
+
+The SB mode of ATP is implemented so the the ATP driver just enables SB
+in the proper address. The SB driver handles the rest. Yoy have to configure
+both the SB driver and the SB mode of ATP to use the same IRQ, DMA and I/O
+settings.
+
+Also the ATP has a microcontroller for the General MIDI emulation (OPL4).
+For this reason the driver asks for the name of a file containing the
+microcode (TRXPRO.HEX). This file is usually located in the directory
+where the DOS drivers were installed. You must have access to this file
+when configuring the driver.
+
+IMPORTANT!!!!!!!!!!!
+
+The OPL4/OPL3 chip and the (optional) effects daughtercard require 
+initialization after boot. Since information about the effect processor
+is not public, the initialization must be done by running a special program
+after boot. The setfx program is distributed in Linux binary form (only)
+in directory sound/audiotrix (of VoxWare-3.0.tar.gz package).
+It's calls ioperm() so it must be run as root.
+
+Another way to initialize the effects processor (and OPL4) is to boot DOS
+before running Linux.
+
+Ensoniq SoundScape
+------------------
+
+The SoundScape driver handles initialization of MSS and MPU supports
+itself so you don't need to enable other drivers than SoundScape
+(enable also the /dev/dsp, /dev/sequencer and MIDI supports).
+
+SoundScape driver uses the MSS compatible codec of the card. It's important
+to note that /dev/dsp0 (/dev/dsp is linked to /dev/dsp0 by default)
+doesn't work with SoundScape (yet). The 'ssinit' program needs /dev/dsp0 so
+that's the reason why it's there. It's possible that 'primary' pcm channel
+becomes supported later. Currently the card's firmware doesn't contain
+support for it.
+
+With 3.0 of VoxWare you have to change your system to use /dev/dsp1 by default
+so execute: cd /dev;rm dsp;ln -s dsp1 dsp after you have installed VoxWare
+3.0 (first time).
+
+The configuration program asks two DMA channels and two interrupts. One IRQ
+and one DMA is used by the MSS codec. The second IRQ is required for the
+MPU401 mode (you have to use different IRQs for both purposes).
+The second DMA channel is required for initialization of the microcontroller.
+
+The SoundScape card has a Motorola microcontroller which must initialized
+_after_ boot (the driver doesn't initialize it during boot).
+The initialization is done by running the 'ssinit' program which is
+distributed in directory sound/sndscape. You have to edit two
+defines in the ssinit.c and then compile the program. You may run ssinit 
+manually (after each boot) or add it to /etc/rc.d/rc.local.
+
+The ssinit program needs the microcode file that comes with the DOS/Windows
+driver of the card. You will need to use version 1.30.00 or later
+of the microcode file (sndscape.co0 or sndscape.co1 depending on
+your card model). THE OLD sndscape.cod WILL NOT WORK. IT WILL HANG YOUR
+MACHINE. The only way to get the new microcode file is to download
+and install the DOS/Windows driver from ftp://ftp.ensoniq.com/pub.
+
+Then you have to select the proper microcode file to use: soundscape.co0
+is the right one for most cards and sndscape.co1 is for few (older) cards
+made by Reveal and/or Spea. The driver has capability to detect the card
+version during boot. Look at the boot log messages in /var/adm/messages
+and locate the sound driver initialization message for the SoundScape
+card. If the driver displays string <Ensoniq Soundscape (old)>, you have
+an old card and you will need to use sndscape.co1. For other cards use
+soundscape.co0.
+
+Check /var/adm/messages after running ssinit. The driver prints
+the board version after downloading the microcode file. That version
+number must match the number in the name of the microcode file (extension).
+
+Running ssinit with a wrong version of the sndscape.co? file is not
+dangerous as long as you don't try to use a file called sndscape.cod.
+If you have initialized the card using a wrong microcode file (sounds
+are terrible), just modify ssinit.c to use another microcode file and try
+again. It's possible to use an earlier version of sndscape.co[01] but it
+may sound wierd.
+
+Btw, The driver may complain something about "sscapeintr()" after
+running ssinit. You should just ignore these messages.
+
+MAD16 (Pro) and Mozart
+----------------------
+
+You need to enable just the MAD16 /Mozart support when configuring
+the driver. Don't enable SB, MPU401 or MSS. However you will need the
+/dev/audio, /dev/sequencer and MIDI supports.
+
+Mozart and OPTi 82C928 (the original MAD16) chips don't support
+MPU401 mode so enter just 0 when the configuration program asks the
+MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) has MPU401 mode.
+
+TB Tropez is based on the 82C929 chip. However it has two MIDI ports.
+The one connected to the MAD16 chip is the second one (there is a second
+MIDI connector/pins somewhere??). If you have not connected the second MIDI
+port, just disable the MIDI port of MAD16. The 'Maui' compatible synth of
+Tropez is jumper configurable and not connected to the MAD16 chip.
+
+There are some other OPTi chips which may be used in soundcards such as
+82C930 and MAC32. These chips are not supported by VoxWare yet. Please
+contact me if you have a soundcard which uses these chips.
+
+MV Jazz (ProSonic)
+------------------
+
+The Jazz16 driver is just a hack made to the SB Pro driver. However it works
+fairly well. You have to enable SB, SB Pro (_not_ SB16) and MPU401 supports
+when configuring the driver. The configuration program asks later if you
+want support for MV Jazz16 based cards (after asking SB base address). Answer
+'y' here and the driver asks the second (16 bit) DMA channel.
+
+The Jazz16 driver uses the MPU401 driver in a way which will cause
+problems if you have another MPU401 compatible card. In this case you must
+give address of the Jazz16 based MPU401 interface when the config
+program prompts for the MPU401 information. Then look at the MPU401
+spesific section for instructions about configuring more than one MPU401 cards.
+
+Logitech Soundman Wave
+----------------------
+
+Read the above MV Jazz spesific instructions first.
+
+The Logitech SoundMan Wave (don't confuse with the SM16 or SM Games) is
+a MV Jazz based card which has an additional OPL4 based wave table
+synthesizer. The OPL4 chip is handled by an on board microcontroller
+which must be initialized during boot. The config program asks if
+you have a SM Wave immediately after asking the second DMA channel of jazz16.
+If you answer 'y', the config program will ask name of the file containing
+code to be loaded to the microcontroller. The file is usually called
+MIDI0001.BIN and it's located in the DOS/Windows driver directory. The file
+may also be called as TSUNAMI.BIN or something else (older cards?).
+
+The OPL4 synth will be riunaccessible without loading the microcontroller code.
+
+NOTE!	Don't answer 'y' when the driver asks about SM Games support
+	(the next question after the MIDI0001.BIN name). However
+	aneswering 'y' is not dangerous. 
+
+Sound Galaxies
+--------------
+
+There are many different Sound Galaxy cards made by Aztech. The 8 bit
+ones are fully SB or SB Pro compatible and there should be no problems
+with them. 
+
+The older 16 bit cards (SG Pro16, SG NX Pro16, Nova and Lyra) have
+an EEPROM chip for storing the configuration data. There is a microcontroller
+which initializes the card to match the EEPROM settigs when the machine
+is powered on. These cards actually behave just like they have jumpers
+for all of the settings. Configure VoxWare for MSS, MPU, SB/SB Pro  and OPL3 
+supports with these cards. 
+
+The config program asks if you want support for the mixer of
+SG NX Pro. Answer 'y' to these questions if you have one of the above 8 or
+16 bit Aztech cards.
+
+There are some new Sound Galaxies in the market. I have no experience with
+them so read the card's manual carefully.
+
+
+Reveal cards
+------------
+
+There are several different cards made/marketed by Reveal. Some of them
+are compatible with SoundScape and some use the MAD16 chip. You may have
+to look at the card and try to identify origin of the card.
+
+Diamond
+-------
+
+The oldest (Sierra Aria based) soundcards made by Diamond are not supported
+(they may work if the card is initialized using DOS). The recent (LX?)
+models are based on the MAD16 chip which is supported by VoxWare.
+
+Audio Excel DSP16
+-----------------
+
+See aedsp16.c.
+
+Others?
+-------
+
+Since there are so many different soundcards, it's likely that I have 
+forgotten to mention many of them. Please inform me if you know yet another
+card which works with Linux, please inform me (or is anybody else
+willing to maintain a database of supported cards (just like in XF86)?).
+
+Cards not supported yet
+=======================
+
+First of all. There is an easy way to make most soundcards to work
+with Linux. Just use the DOS based driver to initialize the card
+to a _known_ state. Then ctrl-alt-del to Linux. If Linux is configured
+to use the sama I/O, IRQ and DMA numbers than DOS, the card could work.
+
+Don't get fooled with SB compatibility. Most cards are compatible with
+SB but that may require a TSR which is not possible with Linux. If
+the card is compatible with MSS, it's a better choise. Some cards
+don't work in the SB and MSS modes at the same time.
+
+There are some cards which will be supported by VoxWare sooner or later
+(currently at least cards based on the ESS chipset). Such cards are
+so common that there is some idea in writing the driver. Check the
+VoxWare home page (http://personal.eunet.fi/pp/voxware) for latest
+information.
+
+Then there are cards which are no longer manufactured and/or which
+are relatively rarely used (such as the 8 bit ProAudioSpectrum
+models). It's extremely unlikely that such cards never get supported.
+Adding support for a new card requires much work and increases time
+required in maintaining the driver (some changes need to be done
+to all low level drivers and be tested too, maybe with multiple
+operating systems). For this reason I have made a desicion to not support
+obsolete cards. It's possible that someone else makes a separately 
+distributed driver (diffs) for the card. Version v4.0 will be much more
+modular so making separately distributed drivers will be easier with it.
+(The bad news is that v4.0 will not be available before late -96).
+
+Writing a driver for a new card is not possible if there are no 
+programming information available about the card. If you don't
+find your new card from this file, look from the home page 
+(http://personal.eunet.fi/pp/voxware). Then please contact
+manufacturer of the card and ask if they have (or are willing to)
+released technical details of the card. Do this before contacting me. I
+can only answer 'no' if there are no programming information available.
+
+Some companies don't give low level technical information about their
+products to public or at least their require signing a NDA.
+
+I have also made decicion to not accept code based on reverse engineering
+to VoxWare. There are three main reasons: First I don't want to break
+relationships to sound card manufacturers. The second reason is that
+maintaining and supporting a driver withoun any specs will be a pain. The
+third reason is that why shoud we help such companies in selling their
+products to Linux users when they don't want to sell to Linux users
+at all?
+
+Unfortunately many of the leading soundcard manufacturers are not willing
+to co-operate with Linux/Unix community. For example: Creative Technology 
+doesn't give information about the ASP chip and the Emu synth chip of AWE32
+and SB32. Turtle Beach don't give information about any of their
+products. MediaVision requires NDA before they are willing to
+give information about the Jazz16 chip (fortunately Logitech gave
+the info about SM Wave).
+
+So at least the above three companies are out until they are willing to 
+release documentation about their products (the situation is the
+same with many DOS based freeware/shareware games and utilities). If
+you want to use Linux/Unix with their cards, please don't try to push
+me. It's a better idea to contact the manufacturer and explain that
+you want to use your card with Linux/Unix. You could also try to sell
+your card to somebody else and then buy a card that is supported by VoxWare.
+
+However it's possible that things change and a driver gets written
+for some of the banned cards. Please, don't send me messages asking if
+there is any plans to write a driver for the cards mentioned above. I 
+will put any news to the VoxWare www home page (see below).
+
+There are some common audio chipsets that are supported yet. For example
+the ESS chips and Sierra Aria. It's likely that these architectures
+get some support in future but I can't make any promises. Just look
+at the home page for latest info.
+
+Information about unsupported soundcards and chipsets is welcome as well
+as free copies of soundcards, SDKs and operating systems.
+
+If you have any corrections and/or comments, please contact me.
+
+Hannu Savolainen
+hannu@voxware.pp.fi
+VoxWare www home page: http://personal.eunet.fi/pp/voxware
+
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.linux linux/drivers/sound/Readme.linux
--- v1.3.8/linux/drivers/sound/Readme.linux	Fri Aug 19 08:54:07 1994
+++ linux/drivers/sound/Readme.linux	Mon Jul 10 01:02:10 1995
@@ -1,11 +1,18 @@
 Installation
 ------------
 
+IMPORTANT!	Read this if you are installing a separately
+		distributed version of this driver.
+		Check that your kernel version works with this
+		release of the driver (see Readme). Also verify
+		that your current kernel version doesn't have more
+		recent sound driver version than this one.
+
 - Since you are reading this, you have already installed the files so
   let's skip this step. To be serious, the sound driver belongs
   to linux/drivers/sound. 
 
-- To build the device files you need to run the enclosed shell script 
+- To build the device files you need to run the enclosed shell scrip 
   (see below).
 
 - If you are installing a separately distributed version, copy the
@@ -23,6 +30,20 @@
 Boot time configuration (using lilo)
 ------------------------------------
 
+NOTE!	This information is little bit obsolete since it doesn't cover
+ 	some cards recently added to the driver.
+
+-------------------------------------------------------------------
+NOTE2!	This method to configure the sound driver is not normally
+	required. All configuration information is entered when the
+	kernel/driver is compiled. This method just gives a way
+	to override some configuration parameters during boot.
+
+	So THE METHOD PRESENTED IN THIS CHAPTER IS NORMALLY COMPLETELY
+	USELESS. DON'T USE IT UNLESS YOU HAVE A VERY SPECIAL REASON TO
+	DO THAT.
+-------------------------------------------------------------------
+
 This version of the sound driver has capability to accept the configuration
 parameters from the boot loader (for example lilo). By default the 
 driver is booted using the parameters given before compiling the driver
@@ -52,7 +73,7 @@
 					6=SB16 (16 bit DMA number)
 					7=SB16 Midi (MPU-401 emulation)
 			(There are some new ones also but they are currently
-			not documented).
+			not documented. The card numbers are in soundcard.h).
 
 These are the configuration templates for various soundcards:
 
@@ -68,7 +89,7 @@
 
 		sound=0x2220Id,0x138800	  (remember to set the IRQ and DMA)
 	or if you have SB16 or SB16ASP, you have to use the following:
-	        (use the same IRQ (the I columns) in all three places. The
+	        (use the same IRQ (the I colums) in all three places. The
 	         the D is the 16 bit DMA channel (5 to 7) and the d is 
 	         the 8 bit one (1 or 3). The X is the 2nd digit of the
 	         midi IO address (3 or 0)).
@@ -134,7 +155,7 @@
 
 	cat /dev/sndstat 
 
-and look at the output. It should display some useful info about the
+and look at the output. It should display some usefull info about the
 driver configuration. If there is no /dev/sndstat 
 (/dev/sndstat: No such file or directory), ensure that you have executed the
 soundinstall script (at the end of this file). The message: 
@@ -147,7 +168,7 @@
 
 - /dev/???????: No such device.
 You have not booted with a kernel containing the driver or the I/O address
-configuration doesn't match your hardware. 
+configuration doesn't match your hardaware. 
 
 - The module player (str) plays just a second and then stops completely.
 You have incorrect IRQ settings (usual with SB cards).
@@ -159,7 +180,7 @@
 UltraSound card. (If you already have GUS, you should use gmod and not the
 str). If the DSP_BUFFSIZE in the sound/local.h is less than (nr_channels*
 speed_in_Hz * (bits/8))/2, it could explain the pausing problem. Also check
-that the turbo switch is on and don't run applications like weather forecasting
+that the turbo swich is on and don't run applications like weather forecasting
 on background. Sometimes (very rarely) an IRQ conflict can cause similar
 problems with SB cards.
 If you want to play modules on a 386sx while recompiling the world, buy a GUS.
@@ -171,7 +192,7 @@
 ----------------- cut here ------------------------------
 #!/bin/sh
 #
-#	soundinstall		
+#	soudinstall		
 #
 #
 # Create the devices
@@ -205,51 +226,66 @@
 fi
 mknod -m 666 /dev/patmgr1 c 14 33
 
-###	#	Sequencer2	(14, 8)
-###	#
-###	if [ -e /dev/sequencer2 ]; then
-###		rm -f /dev/sequencer2
-###	fi
-###	mknod -m 666 /dev/sequencer2 c 14 8
+	#	music	(14, 8)
+	#
+	if [ -e /dev/music ]; then
+		rm -f /dev/music
+	fi
+
+	mknod -m 666 /dev/music c 14 8
+	if [ -e /dev/sequencer2 ]; then
+		rm -f /dev/sequencer2
+	fi
+	ln -s /dev/music /dev/sequencer2
 
 #	Midi devices
 #
 if [ -e /dev/midi ]; then
 	rm -f /dev/midi		# Old name. Don't use it
 fi
-###	if [ -e /dev/midi00 ]; then
-###		rm -f /dev/midi00
-###	fi
-###	mknod -m 666 /dev/midi00 c 14 2
-###	
-###	if [ -e /dev/midi01 ]; then
-###		rm -f /dev/midi01
-###	fi
-###	mknod -m 666 /dev/midi01 c 14 18
-###	
-###	if [ -e /dev/midi02 ]; then
-###		rm -f /dev/midi02
-###	fi
-###	mknod -m 666 /dev/midi02 c 14 34
-###	
-###	if [ -e /dev/midi03 ]; then
-###		rm -f /dev/midi03
-###	fi
-###	mknod -m 666 /dev/midi03 c 14 50
+	if [ -e /dev/midi00 ]; then
+		rm -f /dev/midi00
+	fi
+	mknod -m 666 /dev/midi00 c 14 2
+	
+	if [ -e /dev/midi01 ]; then
+		rm -f /dev/midi01
+	fi
+	mknod -m 666 /dev/midi01 c 14 18
+	
+	if [ -e /dev/midi02 ]; then
+		rm -f /dev/midi02
+	fi
+	mknod -m 666 /dev/midi02 c 14 34
+	
+	if [ -e /dev/midi03 ]; then
+		rm -f /dev/midi03
+	fi
+	mknod -m 666 /dev/midi03 c 14 50
 #
 #	DSP		(14, 3)
 #
 if [ -e /dev/dsp ]; then
 	rm -f /dev/dsp
 fi
-mknod -m 666 /dev/dsp c 14 3
+if [ -e /dev/dsp0 ]; then
+	rm -f /dev/dsp0
+fi
+mknod -m 666 /dev/dsp0 c 14 3
+ln -s /dev/dsp0 /dev/dsp
+
 #
 #	SPARC compatible /dev/audio	(14, 4)	
 #
 if [ -e /dev/audio ]; then
 	rm -f /dev/audio
 fi
-mknod -m 666 /dev/audio c 14 4
+if [ -e /dev/audio0 ]; then
+	rm -f /dev/audio0
+fi
+mknod -m 666 /dev/audio0 c 14 4
+ln -s /dev/audio0 /dev/audio
+
 #
 #	DSP1		(14, 19) /dev/dsp for the second soundcard.
 #				Also the SB emulation part of the
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.modules linux/drivers/sound/Readme.modules
--- v1.3.8/linux/drivers/sound/Readme.modules	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/Readme.modules	Wed Jan  2 02:30:41 1980
@@ -0,0 +1,87 @@
+			Linux sound-driver module
+			(c) Peter Trattler
+			License: GPL (Gnu Public License)
+
+
+Idea:
+
+I've modified the sources for the sound driver to allow simply insert and
+remove the sound driver from the kernel by calling (only available for Linux)
+
+	insmod /usr/src/linux/modules/sound.o
+
+and
+
+	rmmod sound
+
+This may be useful if you are doing one of the following things:
+
+1) Debugging the sound driver
+2) Creating a new device within the sound-driver
+3) You do not the sound driver all the time (as it wastes quite a lot of
+memory for its buffers)
+
+
+Compilation:
+
+Go to /usr/src/linux and make the following steps:
+
+a) configure the sound driver: To do that call "make config" and enable the
+sound-driver -- you will be asked different questions about your
+sound-hardware (remember not to use a too big DMA-Buffer size; you
+should use 16kB, if you have 16Bit devices, otherwise you can use 32kB)
+
+b) disable the sound driver in the kernel: call make config again but answer
+'N' to "Sound card support"
+
+c) run "make modules"; the sound-driver sound.o should end up in
+/usr/src/linux/modules
+
+
+If memory is tight:
+
+I've allocated at about 70kB for the sound-drivers internal tables. If this
+is too much, 'insmod sound.o' will generate the following warning
+...
+use 'insmod memsize=xxxx'
+...
+You can only use this command, if you have (I think) at least
+modules-1.1.87 or up. You can also switch debugging on by running the command
+
+insmod sound.o debugmem=1
+
+
+Files I changed:
+
+I've only changed the files soundcard.c(most changes) and some changes within
+the Makefile, sound_config.h and the Makefile in /usr/src/linux/drivers
+
+
+Bugs:
+
+a) As the kmalloc (..., GFP_DMA) caused some unexpected errors (I don't know if
+it is my fault), I created some code, which is (by default) enabled by
+
+#define KMALLOC_DMA_BROKEN 1 (within soundcard.c).
+
+It trys to allocate a large enough region, so that the complete dma-buffer
+can be occupied in this space. If it does not fit within this region it
+doubles the size of it. But this can cause problems, if the sound-buffer is
+too big (as kmalloc can only handle regions at up to circa 100kB).
+
+So take care to use for 8Bit devices a sound-DMA-buffer of 32kB (maximum)
+and for 16Bit devices a maximum of 16kB. Otherwise the allocation scheme
+might fail.
+
+b) Buffers allocated by the different sound devices via calls to kmalloc are
+not freed, if the sound driver is removed again (these buffers tend to be
+quite small -- so it does not harm a lot)
+
+c) If there is not enough (kernel-) memory available, the installation of
+the sound-driver fails. (This happens quite often, if you did not install the
+driver right after booting -- [PS: I've only got 5MB of Ram, so this might
+be the source for this problem])
+
+
+Author:
+	Peter Trattler (peter@sbox.tu-graz.ac.at)
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/Readme.v30 linux/drivers/sound/Readme.v30
--- v1.3.8/linux/drivers/sound/Readme.v30	Mon Mar  6 11:22:09 1995
+++ linux/drivers/sound/Readme.v30	Mon Jul 10 01:00:58 1995
@@ -1,38 +1,24 @@
 VoxWare v3.0
 ------------
 
-This is a PROTOTYPE of the VoxWare v3.0 to be released late 94.
-
-All features of v2.5 should work as earlier. There could be some
+All features of v2.90-2 should work as earlier. There could be some
 omissions but they are unintentional. I started this version thread
 after v2.3 so all features implemented before it are there.
 
-Even this is a prototype, there should not be any fatal bugs. The
-prototype just means that I don't have implemented all features
-completely. Mainly in the /dev/sequencer2 driver.
-For example recording from /dev/sequencer2 won't work
-with other cards than a full features MPU-401 or clones. As well the
-way how the MIDI controllers are handled will change.
-
-IMPORTANT!!!!!!!!!!!!!!!!!
-
-Don't distribute any binaries compiled with the soundcard.h of this version. 
-They will not work together with older drivers.
-
 New features
 ============
 
 There are now two new device interfaces. The /dev/midi## is a raw
 tty like interface to MIDI ports. There is a device file for each MIDI
 port on your system. They are named (/dev/midi00 to /dev/midiNN).
-The second addition is the /dev/sequencer2 which is higher level interface 
+The second addition is the /dev/music which is higher level interface 
 than the old /dev/sequencer. It's intended for writing device independent
 applications like sequencers.
 
 /dev/midi##
 -----------
 
-This interface should be useful for applications like MIDI sysex librarians.
+This interface should be usefull for applications like MIDI sysex librarians.
 There are (currently) no timing features so making music could be impossible.
 
 There are as many /dev/midi## devices as there are MIDI ports in the system. 
@@ -67,7 +53,7 @@
 If this ioctl is called with mode=1, the interface is put to the intelligent
 (coprocessor) mode. NOTE! The MIDI port will be reset when this ioctl is called.
 It could have some strange effects if not called immediately after open. This
-call returns EINVAL if the midi port doesn't support the MPU-401 intelligent
+vall returns EINVAL if the midi port doesn't support the MPU-401 intelligent
 mode.
 
 ioctl(fd, SNDCTL_MIDI_MPUCMD, &cmdstruct) is valid only if the MIDI port
@@ -95,15 +81,15 @@
 	data		Buffer for the command arguments and returned
 			data.
 
-Be extremely careful with the nr_args and nr_returns fields. They
+Be extremely carefull with the nr_args and nr_returns fields. They
 must match the command. An incorrect value will put the card and
 the driver out of sync. Refer to the MPU-401/MQX-32M documentation for further
-details.
+datails.
 
 
 
-/dev/sequencer2 (if you find a better name, please let me know).
----------------
+/dev/music (/dev/sequencer2)
+----------------------------
 
 This device file works much like the /dev/sequencer which has been present
 since the beginning. The main differences are the following:
@@ -113,7 +99,7 @@
 /dev/sequencer. Both kind of devices are accessed using the SEQ_START_NOTE()
 like macros. The voice number parameters of the API macros have been redefined
 to denote MIDI channels. This means that the driver allocates voices for
-the channels automatically (this is a responsibility/right of an application
+the channels automaticly (this is a responsibility/right of an application
 with /dev/sequencer). The result is that a SEQ_START_NOTE() macro has
 similar effects for a synth channel than on a MIDI port. This kind of
 solution provides better device independence than the /dev/sequencer. The
@@ -130,15 +116,15 @@
 
 - The new interface is used much like the ordinary /dev/sequencer. The
 event format is new so you have to use the API macros defined in the 
-sys/soundcard.h. The interface will probably change before the final 3.0
+sys/soundcard.h. The interface is will propably change before the final 3.0
 release but using the API macros should ensure compatibility in source level.
 The new event format is not recognized by version 2.X so don't try to 
 distribute binaries compiled with soundcard.h of v3.X.
 
-- The basic API usage is similar to the current one. There are some new
+- The basic API useage is similar to the current one. There are some new
 macros but the older ones should work as earlier. The most important
 incompatibility is that the /dev/sequencer2 driver allocates voices itself.
-The other one is that the application must send SEQ_START_TIMER() as its
+The other one is that the application must send SEQ_START_TIMER() as it's
 first event. Otherwise the timer is not started and the application waits
 infinitely.
 
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v1.3.8/linux/drivers/sound/ad1848.c	Mon Mar  6 11:22:09 1995
+++ linux/drivers/sound/ad1848.c	Mon Jul 10 01:45:02 1995
@@ -7,7 +7,7 @@
  * The CS4231 which is used in the GUS MAX and some other cards is
  * upwards compatible with AD1848 and this driver is able to drive it.
  *
- * Copyright by Hannu Savolainen 1994
+ * Copyright by Hannu Savolainen 1994, 1995
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -29,6 +29,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
+ * Modified:
+ *  Riccardo Facchetti  24 Mar 1995
+ *  - Added the Audio Excel DSP 16 initialization routine.
  */
 
 #define DEB(x)
@@ -37,6 +40,8 @@
 
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AD1848)
 
+#include "ad1848_mixer.h"
+
 #define IMODE_NONE		0
 #define IMODE_OUTPUT		1
 #define IMODE_INPUT		2
@@ -44,25 +49,33 @@
 #define IMODE_MIDI		4
 
 typedef struct
-{
-  int             base;
-  int             irq;
-  int             dma_capture, dma_playback;
-  unsigned char   MCE_bit;
-
-  int             speed;
-  unsigned char   speed_bits;
-  int             channels;
-  int             audio_format;
-  unsigned char   format_bits;
-
-  int             xfer_count;
-  int             irq_mode;
-  int             intr_active;
-  int             opened;
-  char           *chip_name;
-  int             mode;
-}
+  {
+    int             base;
+    int             irq;
+    int             dma_capture, dma_playback;
+    int             dual_dma;	/* 1, when two DMA channels allocated */
+    unsigned char   MCE_bit;
+    unsigned char   saved_regs[16];
+
+    int             speed;
+    unsigned char   speed_bits;
+    int             channels;
+    int             audio_format;
+    unsigned char   format_bits;
+
+    int             xfer_count;
+    int             irq_mode;
+    int             intr_active;
+    int             opened;
+    char           *chip_name;
+    int             mode;
+
+    /* Mixer parameters */
+    int             recmask;
+    int             supported_devices;
+    int             supported_rec_devices;
+    unsigned short  levels[32];
+  }
 
 ad1848_info;
 
@@ -71,7 +84,10 @@
 {-1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1};
 
-static int      ad_format_mask[3 /*devc->mode*/ ] =
+static char     mixer2codec[MAX_MIXER_DEV] =
+{0};
+
+static int      ad_format_mask[3 /*devc->mode */ ] =
 {
   0,
   AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
@@ -93,12 +109,17 @@
 static int      ad1848_prepare_for_IO (int dev, int bsize, int bcount);
 static void     ad1848_reset (int dev);
 static void     ad1848_halt (int dev);
+void            ad1848_interrupt (INT_HANDLER_PARMS (irq, dummy));
 
 static int
 ad_read (ad1848_info * devc, int reg)
 {
   unsigned long   flags;
   int             x;
+  int             timeout = 900000;
+
+  while (timeout > 0 && INB (devc->base) == 0x80)	/*Are we initializing */
+    timeout--;
 
   DISABLE_INTR (flags);
   OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
@@ -113,6 +134,10 @@
 ad_write (ad1848_info * devc, int reg, int data)
 {
   unsigned long   flags;
+  int             timeout = 90000;
+
+  while (timeout > 0 && INB (devc->base) == 0x80)	/*Are we initializing */
+    timeout--;
 
   DISABLE_INTR (flags);
   OUTB ((unsigned char) (reg & 0xff) | devc->MCE_bit, io_Index_Addr (devc));
@@ -122,50 +147,331 @@
 }
 
 static void
-ad_set_MCE (ad1848_info * devc, int state)
-{
-  unsigned long   flags;
-
-  DISABLE_INTR (flags);
-  if (state)
-    devc->MCE_bit = 0x40;
-  else
-    devc->MCE_bit = 0x00;
-  OUTB (devc->MCE_bit, io_Index_Addr (devc));
-  RESTORE_INTR (flags);
-}
-
-static void
 wait_for_calibration (ad1848_info * devc)
 {
   int             timeout = 0;
 
   /*
- * Wait until the auto calibration process has finished.
- *
- * 1)	Wait until the chip becomes ready (reads don't return 0x80).
- * 2)	Wait until the ACI bit of I11 gets on and then off.
- */
+     * Wait until the auto calibration process has finished.
+     *
+     * 1)       Wait until the chip becomes ready (reads don't return 0x80).
+     * 2)       Wait until the ACI bit of I11 gets on and then off.
+   */
 
   timeout = 100000;
-  while (timeout > 0 && INB (devc->base) == 0x80)
+  while (timeout > 0 && INB (devc->base) & 0x80)
     timeout--;
-  if (INB (devc->base) == 0x80)
+  if (INB (devc->base) & 0x80)
     printk ("ad1848: Auto calibration timed out(1).\n");
 
-  timeout = 100000;
+  timeout = 100;
   while (timeout > 0 && !(ad_read (devc, 11) & 0x20))
     timeout--;
   if (!(ad_read (devc, 11) & 0x20))
-    printk ("ad1848: Auto calibration timed out(2).\n");
+    return;
 
-  timeout = 100000;
+  timeout = 20000;
   while (timeout > 0 && ad_read (devc, 11) & 0x20)
     timeout--;
   if (ad_read (devc, 11) & 0x20)
     printk ("ad1848: Auto calibration timed out(3).\n");
 }
 
+static void
+ad_mute (ad1848_info * devc)
+{
+  int             i;
+  unsigned char   prev;
+
+  /*
+     * 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
+ad_enter_MCE (ad1848_info * devc)
+{
+  unsigned long   flags;
+  int             timeout = 1000;
+  unsigned short  prev;
+
+  while (timeout > 0 && INB (devc->base) == 0x80)	/*Are we initializing */
+    timeout--;
+
+  DISABLE_INTR (flags);
+
+  devc->MCE_bit = 0x40;
+  prev = INB (io_Index_Addr (devc));
+  if (prev & 0x40)
+    {
+      RESTORE_INTR (flags);
+      return;
+    }
+
+  OUTB (devc->MCE_bit, io_Index_Addr (devc));
+  RESTORE_INTR (flags);
+}
+
+static void
+ad_leave_MCE (ad1848_info * devc)
+{
+  unsigned long   flags;
+  unsigned char   prev;
+  int             timeout = 1000;
+
+  while (timeout > 0 && INB (devc->base) == 0x80)	/*Are we initializing */
+    timeout--;
+
+  DISABLE_INTR (flags);
+
+  devc->MCE_bit = 0x00;
+  prev = INB (io_Index_Addr (devc));
+  OUTB (0x00, io_Index_Addr (devc));	/* Clear the MCE bit */
+
+  if (prev & 0x40 == 0)		/* Not in MCE mode */
+    {
+      RESTORE_INTR (flags);
+      return;
+    }
+
+  OUTB (0x00, io_Index_Addr (devc));	/* Clear the MCE bit */
+  wait_for_calibration (devc);
+  RESTORE_INTR (flags);
+}
+
+
+static int
+ad1848_set_recmask (ad1848_info * devc, int mask)
+{
+  unsigned char   recdev;
+  int             i, n;
+
+  mask &= devc->supported_rec_devices;
+
+  n = 0;
+  for (i = 0; i < 32; i++)	/* Count selected device bits */
+    if (mask & (1 << i))
+      n++;
+
+  if (n == 0)
+    mask = SOUND_MASK_MIC;
+  else if (n != 1)		/* Too many devices selected */
+    {
+      mask &= ~devc->recmask;	/* Filter out active settings */
+
+      n = 0;
+      for (i = 0; i < 32; i++)	/* Count selected device bits */
+	if (mask & (1 << i))
+	  n++;
+
+      if (n != 1)
+	mask = SOUND_MASK_MIC;
+    }
+
+  switch (mask)
+    {
+    case SOUND_MASK_MIC:
+      recdev = 2;
+      break;
+
+    case SOUND_MASK_LINE:
+    case SOUND_MASK_LINE3:
+      recdev = 0;
+      break;
+
+    case SOUND_MASK_CD:
+    case SOUND_MASK_LINE1:
+      recdev = 1;
+      break;
+
+    default:
+      mask = SOUND_MASK_MIC;
+      recdev = 2;
+    }
+
+  recdev <<= 6;
+  ad_write (devc, 0, (ad_read (devc, 0) & 0x3f) | recdev);
+  ad_write (devc, 1, (ad_read (devc, 1) & 0x3f) | recdev);
+
+  devc->recmask = mask;
+  return mask;
+}
+
+static void
+change_bits (unsigned char *regval, int dev, int chn, int newval)
+{
+  unsigned char   mask;
+  int             shift;
+
+  if (mix_devices[dev][chn].polarity == 1)	/* Reverse */
+    newval = 100 - newval;
+
+  mask = (1 << mix_devices[dev][chn].nbits) - 1;
+  shift = mix_devices[dev][chn].bitpos;
+  newval = (int) ((newval * mask) + 50) / 100;	/* Scale it */
+
+  *regval &= ~(mask << shift);	/* Clear bits */
+  *regval |= (newval & mask) << shift;	/* Set new value */
+}
+
+static int
+ad1848_mixer_get (ad1848_info * devc, int dev)
+{
+  if (!((1 << dev) & devc->supported_devices))
+    return RET_ERROR (EINVAL);
+
+  return devc->levels[dev];
+}
+
+static int
+ad1848_mixer_set (ad1848_info * devc, int dev, int value)
+{
+  int             left = value & 0x000000ff;
+  int             right = (value & 0x0000ff00) >> 8;
+
+  int             regoffs;
+  unsigned char   val;
+
+  if (left > 100)
+    left = 100;
+  if (right > 100)
+    right = 100;
+
+  if (dev > 31)
+    return RET_ERROR (EINVAL);
+
+  if (!(devc->supported_devices & (1 << dev)))
+    return RET_ERROR (EINVAL);
+
+  if (mix_devices[dev][LEFT_CHN].nbits == 0)
+    return RET_ERROR (EINVAL);
+
+  /*
+     * Set the left channel
+   */
+
+  regoffs = mix_devices[dev][LEFT_CHN].regno;
+  val = ad_read (devc, regoffs);
+  change_bits (&val, dev, LEFT_CHN, left);
+  devc->levels[dev] = left | (left << 8);
+  ad_write (devc, regoffs, val);
+  devc->saved_regs[regoffs] = val;
+
+  /*
+     * Set the left right
+   */
+
+  if (mix_devices[dev][RIGHT_CHN].nbits == 0)
+    return left | (left << 8);	/* Was just a mono channel */
+
+  regoffs = mix_devices[dev][RIGHT_CHN].regno;
+  val = ad_read (devc, regoffs);
+  change_bits (&val, dev, RIGHT_CHN, right);
+  ad_write (devc, regoffs, val);
+  devc->saved_regs[regoffs] = val;
+
+  devc->levels[dev] = left | (right << 8);
+  return left | (right << 8);
+}
+
+static void
+ad1848_mixer_reset (ad1848_info * devc)
+{
+  int             i;
+
+  devc->recmask = 0;
+  if (devc->mode == 2)
+    devc->supported_devices = MODE2_MIXER_DEVICES;
+  else
+    devc->supported_devices = MODE1_MIXER_DEVICES;
+
+  devc->supported_rec_devices = MODE1_REC_DEVICES;
+
+  for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+    ad1848_mixer_set (devc, i, devc->levels[i] = default_mixer_levels[i]);
+  ad1848_set_recmask (devc, SOUND_MASK_MIC);
+}
+
+static int
+ad1848_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
+{
+  ad1848_info    *devc;
+
+  int             codec_dev = mixer2codec[dev];
+
+  if (!codec_dev)
+    return RET_ERROR (ENXIO);
+
+  codec_dev--;
+
+  devc = (ad1848_info *) audio_devs[codec_dev]->devc;
+
+  if (((cmd >> 8) & 0xff) == 'M')
+    {
+      if (cmd & IOC_IN)
+	switch (cmd & 0xff)
+	  {
+	  case SOUND_MIXER_RECSRC:
+	    return IOCTL_OUT (arg, ad1848_set_recmask (devc, IOCTL_IN (arg)));
+	    break;
+
+	  default:
+	    return IOCTL_OUT (arg, ad1848_mixer_set (devc, cmd & 0xff, IOCTL_IN (arg)));
+	  }
+      else
+	switch (cmd & 0xff)	/*
+				 * Return parameters
+				 */
+	  {
+
+	  case SOUND_MIXER_RECSRC:
+	    return IOCTL_OUT (arg, devc->recmask);
+	    break;
+
+	  case SOUND_MIXER_DEVMASK:
+	    return IOCTL_OUT (arg, devc->supported_devices);
+	    break;
+
+	  case SOUND_MIXER_STEREODEVS:
+	    return IOCTL_OUT (arg, devc->supported_devices &
+			      ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));
+	    break;
+
+	  case SOUND_MIXER_RECMASK:
+	    return IOCTL_OUT (arg, devc->supported_rec_devices);
+	    break;
+
+	  case SOUND_MIXER_CAPS:
+	    return IOCTL_OUT (arg, SOUND_CAP_EXCL_INPUT);
+	    break;
+
+	  default:
+	    return IOCTL_OUT (arg, ad1848_mixer_get (devc, cmd & 0xff));
+	  }
+    }
+  else
+    return RET_ERROR (EINVAL);
+}
+
 static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] =
 {
   {
@@ -186,6 +492,12 @@
     NULL
   }};
 
+static struct mixer_operations ad1848_mixer_operations =
+{
+  "AD1848/CS4248/CS4231",
+  ad1848_mixer_ioctl
+};
+
 static int
 ad1848_open (int dev, int mode)
 {
@@ -209,23 +521,55 @@
     }
 
   if (devc->irq)		/* Not managed by another driver */
-    if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt)) < 0)
+    if ((err = snd_set_irq_handler (devc->irq, ad1848_interrupt,
+				    audio_devs[dev]->name)) < 0)
       {
 	printk ("ad1848: IRQ in use\n");
 	RESTORE_INTR (flags);
 	return err;
       }
 
+/*
+ * Allocate DMA
+ */
+
+  if (mode & OPEN_WRITE)
+    audio_devs[dev]->dmachan = devc->dma_playback;
+  else
+    audio_devs[dev]->dmachan = devc->dma_capture;
+
   if (DMAbuf_open_dma (dev) < 0)
     {
       RESTORE_INTR (flags);
+      if (devc->irq)		/* Don't leave IRQ reserved */
+	snd_release_irq (devc->irq);
+
       printk ("ad1848: DMA in use\n");
       return RET_ERROR (EBUSY);
     }
 
+  devc->dual_dma = 0;
+
+  if (devc->dma_capture != devc->dma_playback && mode == OPEN_READWRITE)
+    {
+      devc->dual_dma = 1;
+
+      if (ALLOC_DMA_CHN (devc->dma_capture, "Sound System (capture)"))
+	{
+	  if (devc->irq)	/* Don't leave IRQ reserved */
+	    snd_release_irq (devc->irq);
+	  DMAbuf_close_dma (dev);
+	  return RET_ERROR (EBUSY);
+	}
+    }
+
   devc->intr_active = 0;
   devc->opened = 1;
   RESTORE_INTR (flags);
+/*
+ * Mute output until the playback really starts. This decreases clicking.
+ */
+  ad_mute (devc);
 
   return 0;
 }
@@ -245,8 +589,18 @@
     snd_release_irq (devc->irq);
   ad1848_reset (dev);
   DMAbuf_close_dma (dev);
+
+  if (devc->dual_dma)		/* Release the second DMA channel */
+    {
+      if (audio_devs[dev]->dmachan == devc->dma_playback)
+	RELEASE_DMA_CHN (devc->dma_capture);
+      else
+	RELEASE_DMA_CHN (devc->dma_playback);
+    }
+
   devc->opened = 0;
 
+  ad_unmute (devc);
   RESTORE_INTR (flags);
 }
 
@@ -254,18 +608,18 @@
 set_speed (ad1848_info * devc, int arg)
 {
   /*
- * The sampling speed is encoded in the least significant nibble of I8. The
- * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other
- * three bits select the divisor (indirectly):
- *
- * The available speeds are in the following table. Keep the speeds in
- * the increasing order.
- */
+     * The sampling speed is encoded in the least significant nible of I8. The
+     * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other
+     * three bits select the divisor (indirectly):
+     *
+     * The available speeds are in the following table. Keep the speeds in
+     * the increasing order.
+   */
   typedef struct
-    {
-      int             speed;
-      unsigned char   bits;
-    }
+  {
+    int             speed;
+    unsigned char   bits;
+  }
   speed_struct;
 
   static speed_struct speed_table[] =
@@ -296,7 +650,7 @@
   if (arg > speed_table[n - 1].speed)
     selected = n - 1;
 
-  for (i = 1 /*really*/ ; selected == -1 && i < n; i++)
+  for (i = 1 /*really */ ; selected == -1 && i < n; i++)
     if (speed_table[i].speed == arg)
       selected = i;
     else if (speed_table[i].speed > arg)
@@ -338,11 +692,11 @@
 {
 
   static struct format_tbl
-    {
-      int             format;
-      unsigned char   bits;
-    }
-  format2bits     [] =
+  {
+    int             format;
+    unsigned char   bits;
+  }
+  format2bits[] =
   {
     {
       0, 0
@@ -460,6 +814,8 @@
 
   cnt = count;
 
+  audio_devs[dev]->dmachan = devc->dma_playback;
+
   if (devc->audio_format == AFMT_IMA_ADPCM)
     {
       cnt /= 4;
@@ -487,31 +843,43 @@
 
   if (dma_restart)
     {
-      ad1848_halt (dev);
+      /* ad1848_halt (dev); */
       DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE);
     }
 
-  ad_set_MCE (devc, 1);
+  ad_enter_MCE (devc);
 
   ad_write (devc, 15, (unsigned char) (cnt & 0xff));
   ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
 
-
-  ad_write (devc, 9, 0x0d);	/*
+  if (devc->dma_playback == devc->dma_capture)
+    {
+      ad_write (devc, 9, 0x0d);	/*
 				 * Playback enable, single DMA channel mode,
 				 * auto calibration on.
 				 */
+    }
+  else
+    {
+      ad_write (devc, 9, 0x09);	/*
+				 * Playback enable, dual DMA channel mode.
+				 * auto calibration on.
+				 */
+    }
 
-  ad_set_MCE (devc, 0);		/*
+  ad_leave_MCE (devc);		/*
 				 * Starts the calibration process and
 				 * enters playback mode after it.
 				 */
-  wait_for_calibration (devc);
+  ad_unmute (devc);
 
   devc->xfer_count = cnt;
   devc->irq_mode = IMODE_OUTPUT;
   devc->intr_active = 1;
+  INB (io_Status (devc));
+  OUTB (0, io_Status (devc));	/* Clear pending interrupts */
   RESTORE_INTR (flags);
+
 }
 
 static void
@@ -520,7 +888,7 @@
   unsigned long   flags, cnt;
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
-  /* int             count_reg = (devc->mode == 1) ? 14 : 30; */
+  audio_devs[dev]->dmachan = devc->dma_capture;
 
   cnt = count;
   if (devc->audio_format == AFMT_IMA_ADPCM)
@@ -550,38 +918,45 @@
 
   if (dma_restart)
     {
-      ad1848_halt (dev);
+      /* ad1848_halt (dev); */
       DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ);
     }
 
-  ad_set_MCE (devc, 1);
-#if 0
-  ad_write (devc, count_reg + 1, (unsigned char) (cnt & 0xff));
-  ad_write (devc, count_reg, (unsigned char) ((cnt >> 8) & 0xff));
-#else
-  ad_write (devc, 15, (unsigned char) (cnt & 0xff));
-  ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
-  if (devc->mode == 2)
+  ad_enter_MCE (devc);
+
+  if (devc->dma_playback == devc->dma_capture)	/* Single DMA channel mode */
     {
-      ad_write (devc, 31, (unsigned char) (cnt & 0xff));
-      ad_write (devc, 32, (unsigned char) ((cnt >> 8) & 0xff));
-    }
-#endif
+      ad_write (devc, 15, (unsigned char) (cnt & 0xff));
+      ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff));
 
-  ad_write (devc, 9, 0x0e);	/*
+      ad_write (devc, 9, 0x0e);	/*
 				 * Capture enable, single DMA channel mode,
 				 * auto calibration on.
 				 */
+    }
+  else
+    /* Dual DMA channel mode */
+    {
+      ad_write (devc, 31, (unsigned char) (cnt & 0xff));
+      ad_write (devc, 30, (unsigned char) ((cnt >> 8) & 0xff));
 
-  ad_set_MCE (devc, 0);		/*
+      ad_write (devc, 9, 0x0a);	/*
+				 * Capture enable, dual DMA channel mode,
+				 * auto calibration on.
+				 */
+    }
+
+  ad_leave_MCE (devc);		/*
 				 * Starts the calibration process and
 				 * enters playback mode after it.
 				 */
-  wait_for_calibration (devc);
+  ad_unmute (devc);
 
   devc->xfer_count = cnt;
   devc->irq_mode = IMODE_INPUT;
   devc->intr_active = 1;
+  INB (io_Status (devc));
+  OUTB (0, io_Status (devc));	/* Clear interrupt status */
   RESTORE_INTR (flags);
 }
 
@@ -594,7 +969,7 @@
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
   DISABLE_INTR (flags);
-  ad_set_MCE (devc, 1);		/* Enables changes to the format select reg */
+  ad_enter_MCE (devc);		/* Enables changes to the format select reg */
   fs = devc->speed_bits | (devc->format_bits << 5);
 
   if (devc->channels > 1)
@@ -602,41 +977,32 @@
 
   ad_write (devc, 8, fs);
   /*
-   * Write to I8 starts resynchronization. Wait until it completes.
+   * Write to I8 starts resyncronization. Wait until it completes.
    */
   timeout = 10000;
   while (timeout > 0 && INB (devc->base) == 0x80)
     timeout--;
 
-  ad_set_MCE (devc, 0);		/*
-				 * Starts the calibration process and
-				 * enters playback mode after it.
-				 */
-  wait_for_calibration (devc);
-  RESTORE_INTR (flags);
-
   /*
- * If mode == 2 (CS4231), set I28 also. It's the capture format register.
- */
+     * If mode == 2 (CS4231), set I28 also. It's the capture format register.
+   */
   if (devc->mode == 2)
     {
-      ad_set_MCE (devc, 1);
       ad_write (devc, 28, fs);
 
       /*
-   * Write to I28 starts resynchronization. Wait until it completes.
-   */
+         * Write to I28 starts resyncronization. Wait until it completes.
+       */
       timeout = 10000;
       while (timeout > 0 && INB (devc->base) == 0x80)
 	timeout--;
 
-      ad_set_MCE (devc, 0);	/*
-				 * Starts the calibration process and
-				 * enters playback mode after it.
-				 */
-      wait_for_calibration (devc);
-      RESTORE_INTR (flags);
     }
+
+  ad_leave_MCE (devc);		/*
+				 * Starts the calibration process.
+				 */
+  RESTORE_INTR (flags);
   devc->xfer_count = 0;
   return 0;
 }
@@ -652,23 +1018,44 @@
 {
   ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
 
-  ad_write (devc, 9, 0);	/* Clear the PEN and CEN bits (among others) */
+  ad_mute (devc);
+  ad_write (devc, 9, ad_read (devc, 9) & ~0x03);	/* Stop DMA */
+  OUTB (0, io_Status (devc));	/* Clear interrupt status */
+
+  ad_enter_MCE (devc);
+  OUTB (0, io_Status (devc));	/* Clear interrupt status */
+  ad_write (devc, 15, 0);	/* Clear DMA counter */
+  ad_write (devc, 14, 0);	/* Clear DMA counter */
+
+  if (devc->mode == 2)
+    {
+      ad_write (devc, 30, 0);	/* Clear DMA counter */
+      ad_write (devc, 31, 0);	/* Clear DMA counter */
+    }
+
+  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 */
+  ad_leave_MCE (devc);
+
+  DMAbuf_reset_dma (dev);
 }
 
 int
 ad1848_detect (int io_base)
 {
 
-#define DDB(x)	x
-
   unsigned char   tmp;
   int             i;
   ad1848_info    *devc = &dev_info[nr_ad1848_devs];
   unsigned char   tmp1 = 0xff, tmp2 = 0xff;
 
   if (nr_ad1848_devs >= MAX_AUDIO_DEV)
-    return 0;
+    {
+      DDB (printk ("ad1848 detect error - step 0\n"));
+      return 0;
+    }
 
   devc->base = io_base;
   devc->MCE_bit = 0x40;
@@ -680,33 +1067,33 @@
   devc->mode = 1;		/* MODE1 = original AD1848 */
 
   /*
- * Check that the I/O address is in use.
- *
- * The bit 0x80 of the base I/O port is known to be 0 after the
- * chip has performed its power on initialization. Just assume
- * this has happened before the OS is starting.
- *
- * If the I/O address is unused, it typically returns 0xff.
- */
+     * Check that the I/O address is in use.
+     *
+     * The bit 0x80 of the base I/O port is known to be 0 after the
+     * chip has performed it's power on initialization. Just assume
+     * this has happened before the OS is starting.
+     *
+     * If the I/O address is unused, it typically returns 0xff.
+   */
 
   if ((INB (devc->base) & 0x80) != 0x00)	/* Not a AD1884 */
     {
-      DDB (printk ("ad_detect_A\n"));
+      DDB (printk ("ad1848 detect error - step A\n"));
       return 0;
     }
 
   /*
- * Test if it's possible to change contents of the indirect registers.
- * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only
- * so try to avoid using it.
-*/
+     * Test if it's possible to change contents of the indirect registers.
+     * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only
+     * so try to avoid using it.
+   */
 
   ad_write (devc, 0, 0xaa);
   ad_write (devc, 1, 0x45);	/* 0x55 with bit 0x10 clear */
 
   if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45)
     {
-      DDB (printk ("ad_detect_B (%x/%x)\n", tmp1, tmp2));
+      DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2));
       return 0;
     }
 
@@ -715,63 +1102,63 @@
 
   if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa)
     {
-      DDB (printk ("ad_detect_C (%x/%x)\n", tmp1, tmp2));
+      DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2));
       return 0;
     }
 
   /*
- * The indirect register I12 has some read only bits. Lets
- * try to change them.
- */
+     * The indirect register I12 has some read only bits. Lets
+     * try to change them.
+   */
 
   tmp = ad_read (devc, 12);
   ad_write (devc, 12, (~tmp) & 0x0f);
 
   if ((tmp & 0x0f) != ((tmp1 = ad_read (devc, 12)) & 0x0f))
     {
-      DDB (printk ("ad_detect_D (%x)\n", tmp1));
+      DDB (printk ("ad1848 detect error - step D (%x)\n", tmp1));
       return 0;
     }
 
   /*
- * NOTE! Last 4 bits of the reg I12 tell the chip revision.
- *	 0x01=RevB and 0x0A=RevC.
- */
+     * NOTE! Last 4 bits of the reg I12 tell the chip revision.
+     *   0x01=RevB and 0x0A=RevC.
+   */
 
   /*
- * The original AD1848/CS4248 has just 15 indirect registers. This means
- * that I0 and I16 should return the same value (etc.).
- * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails
- * with CS4231.
- */
+     * The original AD1848/CS4248 has just 15 indirect registers. This means
+     * that I0 and I16 should return the same value (etc.).
+     * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails
+     * with CS4231.
+   */
 
   ad_write (devc, 12, 0);	/* Mode2=disabled */
 
   for (i = 0; i < 16; i++)
     if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16)))
       {
-	DDB (printk ("ad_detect_F(%d/%x/%x)\n", i, tmp1, tmp2));
+	DDB (printk ("ad1848 detect error - step F(%d/%x/%x)\n", i, tmp1, tmp2));
 	return 0;
       }
 
   /*
- * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
- * The bit 0x80 is always 1 in CS4248 and CS4231.
- */
+     * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40).
+     * The bit 0x80 is always 1 in CS4248 and CS4231.
+   */
 
   ad_write (devc, 12, 0x40);	/* Set mode2, clear 0x80 */
 
   tmp1 = ad_read (devc, 12);
   if (tmp1 & 0x80)
-    devc->chip_name = "CS4248";
+    devc->chip_name = "CS4248";	/* Our best knowledge just now */
 
   if ((tmp1 & 0xc0) == (0x80 | 0x40))
     {
       /*
-	 *	CS4231 detected - is it?
-	 *
-	 *	Verify that setting I0 doesn't change I16.
-	 */
+         *      CS4231 detected - is it?
+         *
+         *      Verify that setting I0 doesn't change I16.
+       */
       ad_write (devc, 16, 0);	/* Set I16 to known value */
 
       ad_write (devc, 0, 0x45);
@@ -781,16 +1168,32 @@
 	  ad_write (devc, 0, 0xaa);
 	  if ((tmp1 = ad_read (devc, 16)) == 0xaa)	/* Rotten bits? */
 	    {
-	      DDB (printk ("ad_detect_H(%x)\n", tmp1));
+	      DDB (printk ("ad1848 detect error - step H(%x)\n", tmp1));
 	      return 0;
 	    }
 
 	  /*
-	 *	It's a CS4231 - So what!
-	 *	(Mode2 will be supported later)
-	 */
-	  devc->chip_name = "CS4231";
-	  devc->mode = 2;
+	     * Verify that some bits of I25 are read only.
+	   */
+
+	  tmp1 = ad_read (devc, 25);	/* Original bits */
+	  ad_write (devc, 25, ~tmp1);	/* Invert all bits */
+	  if ((ad_read (devc, 25) & 0xe7) == (tmp1 & 0xe7))
+	    {
+	      /*
+	         *      It's a CS4231
+	       */
+	      devc->chip_name = "CS4231";
+
+
+#ifdef MOZART_PORT
+	      if (devc->base != MOZART_PORT + 4)
+#endif
+		devc->mode = 2;
+
+
+	    }
+	  ad_write (devc, 25, tmp1);	/* Restore bits */
 	}
     }
 
@@ -801,18 +1204,22 @@
 ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture)
 {
   /*
- * NOTE! If irq < 0, there is another driver which has allocated the IRQ
- *	 so that this driver doesn't need to allocate/deallocate it.
- *	 The actually used IRQ is ABS(irq).
- */
+     * NOTE! If irq < 0, there is another driver which has allocated the IRQ
+     *   so that this driver doesn't need to allocate/deallocate it.
+     *   The actually used IRQ is ABS(irq).
+   */
 
   /*
- * Initial values for the indirect registers of CS4248/AD1848.
- */
+     * Initial values for the indirect registers of CS4248/AD1848.
+   */
   static int      init_values[] =
   {
-    0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
-    0x00, 0x08, 0x02, 0x00, 0xca, 0x00, 0x00, 0x00
+    0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x80, 0x80,
+    0x00, 0x08, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00,
+
+  /* Positions 16 to 31 just for CS4231 */
+    0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
   };
   int             i, my_dev;
   ad1848_info    *devc = &dev_info[nr_ad1848_devs];
@@ -821,8 +1228,13 @@
     return;
 
   devc->irq = (irq > 0) ? irq : 0;
-  devc->dma_capture = dma_playback;
-  devc->dma_playback = dma_capture;
+  devc->dma_playback = dma_playback;
+
+  if (devc->mode == 2)
+    devc->dma_capture = dma_capture;
+  else
+    devc->dma_capture = dma_playback;	/* Use just single DMA */
+
   devc->opened = 0;
 
   if (nr_ad1848_devs != 0)
@@ -835,15 +1247,26 @@
   for (i = 0; i < 16; i++)
     ad_write (devc, i, init_values[i]);
 
+  ad_mute (devc);		/* Initialize some variables */
+  ad_unmute (devc);		/* Leave it unmuted now */
+
+  if (devc->mode == 2)
+    {
+      ad_write (devc, 12, ad_read (devc, 12) | 0x40);	/* Mode2 = enabled */
+      for (i = 16; i < 32; i++)
+	ad_write (devc, i, init_values[i]);
+    }
+
   OUTB (0, io_Status (devc));	/* Clear pending interrupts */
 
-#ifndef SCO
-  sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
-	   "%s (%s)", name, devc->chip_name);
-#endif
+  if (name[0] != 0)
+    sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
+	     "%s (%s)", name, devc->chip_name);
+  else
+    sprintf (ad1848_pcm_operations[nr_ad1848_devs].name,
+	     "Generic audio codec (%s)", devc->chip_name);
 
-  if (irq > 0)
-    printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
+  printk (" <%s>", ad1848_pcm_operations[nr_ad1848_devs].name);
 
   if (num_audiodevs < MAX_AUDIO_DEV)
     {
@@ -859,13 +1282,28 @@
       audio_devs[my_dev]->devc = devc;
       audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode];
       nr_ad1848_devs++;
+
+      /*
+         * Toggle the MCE bit. It completes the initialization phase.
+       */
+
+      ad_enter_MCE (devc);	/* In case the bit was off */
+      ad_leave_MCE (devc);
+
+      if (num_mixers < MAX_MIXER_DEV)
+	{
+	  mixer2codec[num_mixers] = my_dev + 1;
+	  audio_devs[my_dev]->mixer_dev = num_mixers;
+	  mixer_devs[num_mixers++] = &ad1848_mixer_operations;
+	  ad1848_mixer_reset (devc);
+	}
     }
   else
     printk ("AD1848: Too many PCM devices available\n");
 }
 
 void
-ad1848_interrupt (int irq, struct pt_regs * regs)
+ad1848_interrupt (INT_HANDLER_PARMS (irq, dummy))
 {
   unsigned char   status;
   ad1848_info    *devc;
@@ -880,6 +1318,9 @@
   devc = (ad1848_info *) audio_devs[dev]->devc;
   status = INB (io_Status (devc));
 
+  if (status == 0x80)
+    printk ("ad1848_interrupt: Why?\n");
+
   if (status & 0x01)
     {
       if (devc->opened && devc->irq_mode == IMODE_OUTPUT)
@@ -892,25 +1333,72 @@
     }
 
   OUTB (0, io_Status (devc));	/* Clear interrupt status */
+
+  status = INB (io_Status (devc));
+  if (status == 0x80 || status & 0x01)
+    {
+      printk ("ad1848: Problems when clearing interrupt, status=%x\n", status);
+      OUTB (0, io_Status (devc));	/* Try again */
+    }
 }
 
-#endif
 /*
  * Some extra code for the MS Sound System
  */
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MSS)
 
 int
 probe_ms_sound (struct address_info *hw_config)
 {
-  if ((INB (hw_config->io_base + 3) & 0x04) == 0)
-    return 0;			/* WSS ID test failed */
+#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MSS)
+  /*
+     * Initialize Audio Excel DSP 16 to MSS: before any operation
+     * we must enable MSS I/O ports.
+   */
+
+  InitAEDSP16_MSS (hw_config);
+#endif
+
+  /*
+     * Check if the IO port returns valid signature. The original MS Sound
+     * system returns 0x04 while some cards (AudioTriX Pro for example)
+     * return 0x00.
+   */
+
+  if ((INB (hw_config->io_base + 3) & 0x3f) != 0x04 &&
+      (INB (hw_config->io_base + 3) & 0x3f) != 0x00)
+    {
+      DDB (printk ("No MSS signature detected on port 0x%x (0x%x)\n",
+		   hw_config->io_base, INB (hw_config->io_base + 3)));
+      return 0;
+    }
 
   if (hw_config->irq > 11)
-    return 0;
+    {
+      printk ("MSS: Bad IRQ %d\n", hw_config->irq);
+      return 0;
+    }
 
   if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
-	return 0;
+    {
+      printk ("MSS: Bad DMA %d\n", hw_config->dma);
+      return 0;
+    }
+
+  /*
+     * Check that DMA0 is not in use with a 8 bit board.
+   */
+
+  if (hw_config->dma == 0 && INB (hw_config->io_base + 3) & 0x80)
+    {
+      printk ("MSS: Can't use DMA0 with a 8 bit card/slot\n");
+      return 0;
+    }
+
+  if (hw_config->irq > 7 && hw_config->irq != 9 && INB (hw_config->io_base + 3) & 0x80)
+    {
+      printk ("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
+      return 0;
+    }
 
   return ad1848_detect (hw_config->io_base + 4);
 }
@@ -918,11 +1406,16 @@
 long
 attach_ms_sound (long mem_start, struct address_info *hw_config)
 {
-  static unsigned char interrupt_bits[12] =
-  {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
+  static char     interrupt_bits[12] =
+  {
+    -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20
+  };
   char            bits;
 
-  static unsigned char dma_bits[4] = {1, 2, 0, 3};
+  static char     dma_bits[4] =
+  {
+    1, 2, 0, 3
+  };
 
   int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
 
@@ -930,16 +1423,16 @@
     return mem_start;
 
   /*
- * Set the IRQ and DMA addresses.
- */
+     * Set the IRQ and DMA addresses.
+   */
 
   bits = interrupt_bits[hw_config->irq];
   if (bits == -1)
     return mem_start;
 
-  OUTB (bits | 0x40, config_port);	/* Verify IRQ (I guess) */
+  OUTB (bits | 0x40, config_port);
   if ((INB (version_port) & 0x40) == 0)
-    printk ("[IRQ?]");
+    printk ("[IRQ Conflict?]");
 
   OUTB (bits | dma_bits[hw_config->dma], config_port);	/* Write IRQ+DMA setup */
 
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h
--- v1.3.8/linux/drivers/sound/ad1848_mixer.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/ad1848_mixer.h	Mon Jun 12 12:48:59 1995
@@ -0,0 +1,130 @@
+/*
+ * sound/ad1848_mixer.h
+ * 
+ * Definitions for the mixer of AD1848 and compatible codecs.
+ * 
+ * Copyright by Hannu Savolainen 1994
+ * 
+ * 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.
+ */
+/*
+ * The AD1848 codec has generic input lines called Line, Aux1 and Aux2.
+ * Soundcard manufacturers have connected actual inputs (CD, synth, line,
+ * etc) to these inputs in different order. Therefore it's difficult
+ * to assign mixer channels to to these inputs correctly. The following
+ * contains two alternative mappings. The first one is for GUS MAX and
+ * the second is just a generic one (line1, line2 and line3).
+ * (Actually this is not a mapping but rather some kind of interleaving
+ * solution).
+ */
+#ifdef GUSMAX_MIXER
+#define MODE1_REC_DEVICES		(SOUND_MASK_LINE | SOUND_MASK_MIC | \
+					 SOUND_MASK_CD)
+
+#define MODE1_MIXER_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_MIC | \
+					 SOUND_MASK_CD | \
+					 SOUND_MASK_IGAIN | \
+					 SOUND_MASK_PCM|SOUND_MASK_IMIX)
+
+#define MODE2_MIXER_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
+					 SOUND_MASK_CD | SOUND_MASK_SPEAKER | \
+					 SOUND_MASK_IGAIN | \
+					 SOUND_MASK_PCM | SOUND_MASK_IMIX)
+#else	/* Generic mapping */
+#define MODE1_REC_DEVICES		(SOUND_MASK_LINE3 | SOUND_MASK_MIC | \
+					 SOUND_MASK_LINE1)
+
+#define MODE1_MIXER_DEVICES		(SOUND_MASK_LINE1 | SOUND_MASK_MIC | \
+					 SOUND_MASK_LINE2 | \
+					 SOUND_MASK_IGAIN | \
+					 SOUND_MASK_PCM | SOUND_MASK_IMIX)
+
+#define MODE2_MIXER_DEVICES		(SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_MIC | \
+					 SOUND_MASK_LINE3 | SOUND_MASK_SPEAKER | \
+					 SOUND_MASK_IGAIN | \
+					 SOUND_MASK_PCM | SOUND_MASK_IMIX)
+#endif
+
+struct mixer_def {
+	unsigned int regno: 7;
+	unsigned int polarity:1;	/* 0=normal, 1=reversed */
+	unsigned int bitpos:4;
+	unsigned int nbits:4;
+};
+
+
+typedef struct mixer_def mixer_ent;
+
+/*
+ * Most of the mixer entries work in backwards. Setting the polarity field
+ * makes them to work correctly.
+ *
+ * The channel numbering used by individual soundcards is not fixed. Some
+ * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs.
+ * The current version doesn't try to compensate this.
+ */
+
+#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r)	\
+	{{reg_l, pola_l, pos_r, len_l}, {reg_r, pola_r, pos_r, len_r}}
+
+mixer_ent mix_devices[32][2] = {	/* As used in GUS MAX */
+MIX_ENT(SOUND_MIXER_VOLUME,	 0, 0, 0, 0,	 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_BASS,	 0, 0, 0, 0,	 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,	 0, 0, 0, 0,	 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,	 4, 1, 0, 5,	 5, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_PCM,	 6, 1, 0, 6,	 7, 1, 0, 6),
+MIX_ENT(SOUND_MIXER_SPEAKER,	26, 1, 0, 4,	 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,	18, 1, 0, 5,	19, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_MIC,	 0, 0, 5, 1,	 1, 0, 5, 1),
+MIX_ENT(SOUND_MIXER_CD,	 	 2, 1, 0, 5,	 3, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_IMIX,	13, 1, 2, 6,	 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,	 0, 0, 0, 0,	 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,	 0, 0, 0, 0,	 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_IGAIN,	 0, 0, 0, 4,	 1, 0, 0, 4),
+MIX_ENT(SOUND_MIXER_OGAIN,	 0, 0, 0, 0,	 0, 0, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE1, 	 2, 1, 0, 5,	 3, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_LINE2,	 4, 1, 0, 5,	 5, 1, 0, 5),
+MIX_ENT(SOUND_MIXER_LINE3,	18, 1, 0, 5,	19, 1, 0, 5)
+};
+
+static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] =
+{
+  0x5a5a,			/* Master Volume */
+  0x3232,			/* Bass */
+  0x3232,			/* Treble */
+  0x4b4b,			/* FM */
+  0x6464,			/* PCM */
+  0x4b4b,			/* PC Speaker */
+  0x4b4b,			/* Ext Line */
+  0x1010,			/* Mic */
+  0x4b4b,			/* CD */
+  0x0000,			/* Recording monitor */
+  0x4b4b,			/* SB PCM */
+  0x4b4b,			/* Recording level */
+  0x4b4b,			/* Input gain */
+  0x4b4b,			/* Output gain */
+  0x4b4b,			/* Line1 */
+  0x4b4b,			/* Line2 */
+  0x4b4b			/* Line3 */
+};
+
+#define LEFT_CHN	0
+#define RIGHT_CHN	1
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/aedsp16.c linux/drivers/sound/aedsp16.c
--- v1.3.8/linux/drivers/sound/aedsp16.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/aedsp16.c	Mon Jul 10 01:45:03 1995
@@ -0,0 +1,867 @@
+/*
+   sound/aedsp16.c
+
+   Audio Excel DSP 16 software configuration routines
+
+   Copyright (C) 1995  Riccardo Facchetti (riccardo@cdc8g5.cdc.polimi.it)
+
+   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.
+ */
+/*
+ * Include the main voxware header file. It include all the os/voxware/etc
+ * headers needed by this source.
+ */
+#include "sound_config.h"
+/*
+ * all but ioport.h :)
+ */
+#include <linux/ioport.h>
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_AEDSP16)
+/*
+
+   READ THIS
+
+   This module is intended for Audio Excel DSP 16 Sound Card.
+
+   Audio Excel DSP 16 is an SB pro II, Microsoft Sound System
+   and MPU-401 compatible card.
+   It is software-only configurable (no jumpers to hard-set irq/dma/mpu-irq),
+   so before this module, the only way to configure the DSP under linux was
+   boot the MS-BAU loading the sound.sys device driver (this driver soft-
+   configure the sound board hardware by massaging someone of its registers),
+   and then ctrl-alt-del to boot linux with the DSP configured by the DOG
+   driver.
+
+   This module works configuring your Audio Excel DSP 16's
+   irq, dma and mpu-401-irq. The voxware probe routines rely on the
+   fact that if the hardware is there, they can detect it. The problem
+   with AEDSP16 is that no hardware can be found by the probe routines
+   if the sound card is not well configured. Sometimes the kernel probe
+   routines can find an SBPRO even when the card is not configured (this
+   is the standard setup of the card), but the SBPRO emulation don't work
+   well if the card is not properly initialized. For this reason
+
+   InitAEDSP16_...()
+
+   routines are called before the voxware probe routines try to detect the
+   hardware.
+
+   NOTE (READ THE NOTE TOO, IT CONTAIN USEFUL INFORMATIONS)
+
+   The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS;
+   the voxware sound driver can be configured for SBPRO and MSS cards
+   at the same time, but the aedsp16 can't be two cards!!
+   When we configure it, we have to choose the SBPRO or the MSS emulation
+   for AEDSP16. We also can install a *REAL* card of the other type
+   (see [1], not tested but I can't see any reason for it to fail).
+
+   NOTE: If someone can test the combination AEDSP16+MSS or AEDSP16+SBPRO
+   please let me know if it works.
+
+   The MPU-401 support can be compiled in together with one of the other
+   two operating modes.
+
+   The board configuration calls, are in the probe_...() routines because
+   we have to configure the board before probing it for a particular
+   hardware. After card configuration, we can probe the hardware.
+
+   NOTE: This is something like plug-and-play: we have only to plug
+   the AEDSP16 board in the socket, and then configure and compile
+   a kernel that uses the AEDSP16 software configuration capability.
+   No jumper setting is needed!
+
+   For example, if you want AEDSP16 to be an SBPro, on irq 10, dma 3
+   you have just to make config the voxware package, configuring
+   the SBPro sound card with that parameters, then when configure
+   asks if you have an AEDSP16, answer yes. That's it.
+   Compile the kernel and run it.
+
+   NOTE: This means that you can choose irq and dma, but not the
+   I/O addresses. To change I/O addresses you have to set them
+   with jumpers.
+
+   NOTE: InitAEDSP16_...() routines get as parameter the hw_config,
+   the hardware configuration of the - to be configured - board.
+   The InitAEDSP16() routine, configure the board following our
+   wishes, that are in the hw_config structure.
+
+   You can change the irq/dma/mirq settings WITHOUT THE NEED to open
+   your computer and massage the jumpers (there are no irq/dma/mirq
+   jumpers to be configured anyway, only I/O port ones have to be
+   configured with jumpers)
+
+   For some ununderstandable reason, the card default of irq 7, dma 1,
+   don't work for me. Seems to be an IRQ or DMA conflict. Under heavy
+   HDD work, the kernel start to erupt out a lot of messages like:
+
+   'Sound: DMA timed out - IRQ/DRQ config error?'
+
+   For what I can say, I have NOT any conflict at irq 7 (under linux I'm
+   using the lp polling driver), and dma line 1 is unused as stated by
+   /proc/dma. I can suppose this is a bug of AEDSP16. I know my hardware so
+   I'm pretty sure I have not any conflict, but may be I'm wrong. Who knows!
+   Anyway a setting of irq 10, dma 3 works really fine.
+
+   NOTE: if someone can use AEDSP16 with irq 7, dma 1, please let me know
+   the emulation mode, all the installed hardware and the hardware
+   configuration (irq and dma settings of all the hardware).
+
+   This init module should work with SBPRO+MSS, when one of the two is
+   the AEDSP16 emulation and the other the real card. (see [1])
+   For example:
+
+   AEDSP16 (0x220) in SBPRO emu (0x220) + real MSS + other
+   AEDSP16 (0x220) in MSS emu + real SBPRO (0x240) + other
+
+   MPU401 should work. (see [1])
+
+   [1] Not tested by me for lack of hardware.
+
+   TODO, WISHES AND TECH
+
+   May be there's lot of redundant delays, but for now I want to leave it
+   this way.
+
+   Should be interesting eventually write down a new ioctl for the
+   aedsp16, to let the suser() change the irq/dma/mirq on the fly.
+   The thing is not trivial.
+   In the real world, there's no need to have such an ioctl because
+   when we configure the kernel for compile, we can choose the config
+   parameters. If we change our mind, we can easily re-config the kernel
+   and re-compile.
+   Why let the suser() change the config parameters on the fly ?
+   If anyone have a reasonable answer to this question, I will write down
+   the code to do it.
+
+   More integration with voxware, using voxware low level routines to
+   read-write dsp is not possible because you may want to have MSS
+   support and in that case we can not rely on the functions included
+   in sb_dsp.c to control 0x2yy I/O ports. I will continue to use my
+   own I/O functions.
+
+   - About I/O ports allocation -
+
+   The request_region should be done at device probe in every sound card
+   module. This module is not the best site for requesting regions.
+   When the request_region code will be added to the main modules such as
+   sb, adlib, gus, ad1848, etc, the requesting code in this module should
+   go away.
+
+   I think the request regions should be done this way:
+
+   if (check_region(...))
+   return ERR; // I/O region alredy reserved
+   device_probe(...);
+   device_attach(...);
+   request_region(...); // reserve only when we are sure all is okay
+
+   Request the 2x0h region in any case if we are using this card.
+
+   NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region
+   (see code) does not mean necessarly that we are emulating sbpro.
+   It mean that the region is the sbpro I/O ports region. We use this
+   region to access the control registers of the card, and if emulating
+   sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro
+   registers are not used, in no way, to emulate an sbpro: they are
+   used only for configuration pourposes.
+
+   Someone pointed out that should be possible use both the SBPRO and MSS
+   modes because the sound card have all the two chipsets, supposing that
+   the card is really two cards. I have tried something to have the two
+   modes work together, but, for some reason unknown to me, without success.
+
+   I think all the soft-config only cards have an init sequence similar to
+   this. If you have a card that is not an aedsp16, you can try to start
+   with this module changing it (mainly in the CMD? I think) to fit your
+   needs.
+
+   Started Fri Mar 17 16:13:18 MET 1995
+
+   v0.1 (ALPHA, was an user-level program called AudioExcelDSP16.c)
+   - Initial code.
+   v0.2 (ALPHA)
+   - Cleanups.
+   - Integrated with Linux voxware v 2.90-2 kernel sound driver.
+   - SoundBlaster Pro mode configuration.
+   - Microsoft Sound System mode configuration.
+   - MPU-401 mode configuration.
+   v0.3 (ALPHA)
+   - Cleanups.
+   - Rearranged the code to let InitAEDSP16 be more general.
+   - Erased the REALLY_SLOW_IO. We don't need it. Erased the linux/io.h
+   inclusion too. We rely on os.h
+   - Used the INB and OUTB #defined in os.h instead of inb and outb.
+   - Corrected the code for GetCardName (DSP Copyright) to get a variable
+   len string (we are not sure about the len of Copyright string).
+   This works with any SB and compatible.
+   - Added the code to request_region at device init (should go in
+   the main body of voxware).
+   v0.4 (BETA)
+   - Better configure.c patch for aedsp16 configuration (better
+   logic of inclusion of AEDSP16 support)
+   - Modified the conditional compilation to better support more than
+   one sound card of the emulated type (read the NOTES above)
+   - Moved the sb init routine from the attach to the very first
+   probe in sb_card.c
+   - Rearrangemens and cleanups
+   - Wiped out some unnecessary code and variables: this is kernel
+   code so it is better save some TEXT and DATA
+   - Fixed the request_region code. We must allocate the aedsp16 (sbpro)
+   I/O ports in any case because they are used to access the DSP
+   configuration registers and we can not allow anyone to get them.
+   v0.5
+   - cleanups on comments
+   - prep for diffs against v3.0-proto-950402
+   v0.6
+   - removed the request_region()s when compiling the MODULE sound.o
+   because we are not allowed (by the actual voxware structure) to
+   release_region()
+
+ */
+
+
+#define VERSION "0.6"		/* Version of Audio Excel DSP 16 driver */
+
+#undef AEDSP16_DEBUG		/* Define this to enable debug code     */
+/* Actually no debug code is activated  */
+
+/*
+ * Hardware related defaults
+ */
+#define IRQ  7			/* 5 7(default) 9 10 11                 */
+#define MIRQ 0			/* 5 7 9 10 0(default), 0 means disable */
+#define DMA  1			/* 0 1(default) 3                       */
+
+/*
+ * Commands of AEDSP16's DSP (SBPRO+special).
+ * For now they are CMDn, in the future they may change.
+ */
+#define CMD1 0xe3		/* Get DSP Copyright                    */
+#define CMD2 0xe1		/* Get DSP Version                      */
+#define CMD3 0x88		/*                                      */
+#define CMD4 0x5c		/*                                      */
+#define CMD5 0x50		/* Set M&I&DRQ mask (the real config)   */
+#define CMD6 0x8c		/* Enable Microsoft Sound System mode   */
+
+/*
+ * Offsets of AEDSP16 DSP I/O ports. The offest is added to portbase
+ * to have the actual I/O port.
+ * Register permissions are:
+ * (wo) == Write Only
+ * (ro) == Read  Only
+ * (w-) == Write
+ * (r-) == Read
+ */
+#define DSP_RESET    0x06	/* offset of DSP RESET             (wo) */
+#define DSP_READ     0x0a	/* offset of DSP READ              (ro) */
+#define DSP_WRITE    0x0c	/* offset of DSP WRITE             (w-) */
+#define DSP_COMMAND  0x0c	/* offset of DSP COMMAND           (w-) */
+#define DSP_STATUS   0x0c	/* offset of DSP STATUS            (r-) */
+#define DSP_DATAVAIL 0x0e	/* offset of DSP DATA AVAILABLE    (ro) */
+
+
+#define RETRY           10	/* Various retry values on I/O opera-   */
+#define STATUSRETRY   1000	/* tions. Sometimes we have to          */
+#define HARDRETRY   500000	/* wait for previous cmd to complete    */
+
+/*
+ * Size of character arrays that store name and version of sound card
+ */
+#define CARDNAMELEN 15		/* Size of the card's name in chars     */
+#define CARDVERLEN  2		/* Size of the card's version in chars  */
+
+/*
+ * Bit mapped flags for calling InitAEDSP16(), and saving the current
+ * emulation mode.
+ */
+#define INIT_NONE   (0   )
+#define INIT_SBPRO  (1<<0)
+#define INIT_MSS    (1<<1)
+#define INIT_MPU401 (1<<2)
+#define RESET_DSP16 (1<<3)
+
+/* Base HW Port for Audio Card          */
+static int      portbase = AEDSP16_BASE;
+static int      irq = IRQ;	/* irq for DSP I/O                      */
+static int      mirq = MIRQ;	/* irq for MPU-401 I/O                  */
+static int      dma = DMA;	/* dma for DSP I/O                      */
+
+/* Init status of the card              */
+static int      ae_init = INIT_NONE;	/* (bitmapped variable)                 */
+static int      oredparams = 0;	/* Will contain or'ed values of params  */
+static int      gc = 0;		/* generic counter (utility counter)    */
+struct orVals
+  {				/* Contain the values to be or'ed       */
+    int             val;	/* irq|mirq|dma                         */
+    int             or;		/* oredparams |= TheStruct.or           */
+  };
+
+/*
+ * Magic values that the DSP will eat when configuring irq/mirq/dma
+ */
+/* DSP IRQ conversion array             */
+static struct orVals orIRQ[] =
+{
+  {0x05, 0x28},
+  {0x07, 0x08},
+  {0x09, 0x10},
+  {0x0a, 0x18},
+  {0x0b, 0x20},
+  {0x00, 0x00}
+};
+
+/* MPU-401 IRQ conversion array         */
+static struct orVals orMIRQ[] =
+{
+  {0x05, 0x04},
+  {0x07, 0x44},
+  {0x09, 0x84},
+  {0x0a, 0xc4},
+  {0x00, 0x00}
+};
+
+/* DMA Channels conversion array        */
+static struct orVals orDMA[] =
+{
+  {0x00, 0x01},
+  {0x01, 0x02},
+  {0x03, 0x03},
+  {0x00, 0x00}
+};
+
+/*
+ * Buffers to store audio card informations
+ */
+static char     AudioExcelName[CARDNAMELEN + 1];
+static char     AudioExcelVersion[CARDVERLEN + 1];
+
+static void
+tenmillisec (void)
+{
+
+  for (gc = 0; gc < 1000; gc++)
+    tenmicrosec ();
+}
+
+static int
+WaitForDataAvail (int port)
+{
+  int             loop = STATUSRETRY;
+  unsigned char   ret = 0;
+
+  do
+    {
+      ret = INB (port + DSP_DATAVAIL);
+      /*
+         * Wait for data available (bit 7 of ret == 1)
+       */
+    }
+  while (!(ret & 0x80) && loop--);
+
+  if (ret & 0x80)
+    return 0;
+
+  return -1;
+}
+
+static int
+ReadData (int port)
+{
+  if (WaitForDataAvail (port))
+    return -1;
+  return INB (port + DSP_READ);
+}
+
+static int
+CheckDSPOkay (int port)
+{
+  return ((ReadData (port) == 0xaa) ? 0 : -1);
+}
+
+static int
+ResetBoard (int port)
+{
+  /*
+     * Reset DSP
+   */
+  OUTB (1, (port + DSP_RESET));
+  tenmicrosec ();
+  OUTB (0, (port + DSP_RESET));
+  tenmicrosec ();
+  tenmicrosec ();
+  return CheckDSPOkay (port);
+}
+
+static int
+WriteDSPCommand (int port, int cmd)
+{
+  unsigned char   ret;
+  int             loop = HARDRETRY;
+
+  do
+    {
+      ret = INB (port + DSP_STATUS);
+      /*
+         * DSP ready to receive data if bit 7 of ret == 0
+       */
+      if (!(ret & 0x80))
+	{
+	  OUTB (cmd, port + DSP_COMMAND);
+	  return 0;
+	}
+    }
+  while (loop--);
+
+  printk ("[aedsp16] DSP Command (0x%x) timeout.\n", cmd);
+  return -1;
+}
+
+int
+InitMSS (int port)
+{
+
+  tenmillisec ();
+
+  if (WriteDSPCommand (port, CMD6))
+    {
+      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD6);
+      return -1;
+    }
+
+  tenmillisec ();
+
+  return 0;
+}
+
+static int
+SetUpBoard (int port)
+{
+  int             loop = RETRY;
+
+  do
+    {
+      if (WriteDSPCommand (portbase, CMD3))
+	{
+	  printk ("[aedsp16] CMD 0x%x: failed!\n", CMD3);
+	  return -1;
+	}
+
+      tenmillisec ();
+
+    }
+  while (WaitForDataAvail (port) && loop--);
+
+#if defined(THIS_SHOULD_GO_AWAY)
+  if (CheckDSPOkay (port))
+    {
+      printk ("[aedsp16]     CheckDSPOkay: failed\n");
+      return -1;
+    }
+#else
+  if (ReadData (port) == -1)
+    {
+      printk ("[aedsp16] ReadData after CMD 0x%x: failed\n", CMD3);
+      return -1;
+    }
+#endif
+
+  if (WriteDSPCommand (portbase, CMD4))
+    {
+      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD4);
+      return -1;
+    }
+
+  if (WriteDSPCommand (portbase, CMD5))
+    {
+      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD5);
+      return -1;
+    }
+
+  if (WriteDSPCommand (portbase, oredparams))
+    {
+      printk ("[aedsp16] Initialization of (M)IRQ and DMA: failed!\n");
+      return -1;
+    }
+  return 0;
+}
+
+static int
+GetCardVersion (int port)
+{
+  int             len = 0;
+  int             ret;
+  int             ver[3];
+
+  do
+    {
+      if ((ret = ReadData (port)) == -1)
+	return -1;
+      /*
+         * We alredy know how many int are stored (2), so we know when the
+         * string is finished.
+       */
+      ver[len++] = ret;
+    }
+  while (len < CARDVERLEN);
+  sprintf (AudioExcelVersion, "%d.%d", ver[0], ver[1]);
+  return 0;
+}
+
+static int
+GetCardName (int port)
+{
+  int             len = 0;
+  int             ret;
+
+  do
+    {
+      if ((ret = ReadData (port)) == -1)
+	/*
+	   * If no more data availabe, return to the caller, no error if len>0.
+	   * We have no other way to know when the string is finished.
+	 */
+	return (len ? 0 : -1);
+
+      AudioExcelName[len++] = ret;
+
+    }
+  while (len < CARDNAMELEN);
+  return 0;
+}
+
+static void
+InitializeHardParams (void)
+{
+
+  memset (AudioExcelName, 0, CARDNAMELEN + 1);
+  memset (AudioExcelVersion, 0, CARDVERLEN + 1);
+
+  for (gc = 0; orIRQ[gc].or; gc++)
+    if (orIRQ[gc].val == irq)
+      oredparams |= orIRQ[gc].or;
+
+  for (gc = 0; orMIRQ[gc].or; gc++)
+    if (orMIRQ[gc].or == mirq)
+      oredparams |= orMIRQ[gc].or;
+
+  for (gc = 0; orDMA[gc].or; gc++)
+    if (orDMA[gc].val == dma)
+      oredparams |= orDMA[gc].or;
+}
+
+static int
+InitAEDSP16 (int which)
+{
+  static char    *InitName = NULL;
+
+  InitializeHardParams ();
+
+  if (ResetBoard (portbase))
+    {
+      printk ("[aedsp16] ResetBoard: failed!\n");
+      return -1;
+    }
+
+#if defined(THIS_SHOULD_GO_AWAY)
+  if (CheckDSPOkay (portbase))
+    {
+      printk ("[aedsp16] CheckDSPOkay: failed!\n");
+      return -1;
+    }
+#endif
+
+  if (WriteDSPCommand (portbase, CMD1))
+    {
+      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD1);
+      return -1;
+    }
+
+  if (GetCardName (portbase))
+    {
+      printk ("[aedsp16] GetCardName: failed!\n");
+      return -1;
+    }
+
+  /*
+     * My AEDSP16 card return SC-6000 in AudioExcelName, so
+     * if we have something different, we have to be warned.
+   */
+  if (strcmp ("SC-6000", AudioExcelName))
+    printk ("[aedsp16] Warning: non SC-6000 audio card!\n");
+
+  if (WriteDSPCommand (portbase, CMD2))
+    {
+      printk ("[aedsp16] CMD 0x%x: failed!\n", CMD2);
+      return -1;
+    }
+
+  if (GetCardVersion (portbase))
+    {
+      printk ("[aedsp16] GetCardVersion: failed!\n");
+      return -1;
+    }
+
+  if (SetUpBoard (portbase))
+    {
+      printk ("[aedsp16] SetUpBoard: failed!\n");
+      return -1;
+    }
+
+  if (which == INIT_MSS)
+    {
+      if (InitMSS (portbase))
+	{
+	  printk ("[aedsp16] Can't initialize Microsoft Sound System mode.\n");
+	  return -1;
+	}
+    }
+
+  /*
+     * If we are resetting, do not print any message because we may be
+     * in playing and we do not want lost too much time.
+   */
+  if (!(which & RESET_DSP16))
+    {
+      if (which & INIT_MPU401)
+	InitName = "MPU401";
+      else if (which & INIT_SBPRO)
+	InitName = "SBPro";
+      else if (which & INIT_MSS)
+	InitName = "MSS";
+      else
+	InitName = "None";
+
+      printk ("Audio Excel DSP 16 init v%s (%s %s) [%s]\n",
+	      VERSION, AudioExcelName,
+	      AudioExcelVersion, InitName);
+    }
+
+  tenmillisec ();
+
+  return 0;
+}
+
+#if defined(AEDSP16_SBPRO)
+
+int
+InitAEDSP16_SBPRO (struct address_info *hw_config)
+{
+  /*
+     * If the card is alredy init'ed MSS, we can not init it to SBPRO too
+     * because the board can not emulate simultaneously MSS and SBPRO.
+   */
+  if (ae_init & INIT_MSS)
+    return -1;
+  if (ae_init & INIT_SBPRO)
+    return 0;
+
+  /*
+     * For now we will leave this
+     * code included only when INCLUDE_AEDSP16 is configured in, but it should
+     * be better include it every time.
+   */
+  if (!(ae_init & INIT_MPU401))
+    {
+      if (check_region (hw_config->io_base, 0x0f))
+	{
+	  printk ("AEDSP16/SBPRO I/O port region is alredy in use.\n");
+	  return -1;
+	}
+    }
+
+  /*
+     * Set up the internal hardware parameters, to let the driver reach
+     * the Sound Card.
+   */
+  portbase = hw_config->io_base;
+  irq = hw_config->irq;
+  dma = hw_config->dma;
+  if (InitAEDSP16 (INIT_SBPRO))
+    return -1;
+
+#if !defined(MODULE)
+  /*
+     * If we are compiling sound.o (MODULAR version) we can not
+     * request any region because there is not a uninit routine that
+     * can allow me to release the requested region.
+   */
+  if (!(ae_init & INIT_MPU401))
+    request_region (hw_config->io_base, 0x0f, "aedsp16 (sbpro)");
+#endif
+
+  ae_init |= INIT_SBPRO;
+  return 0;
+}
+
+#endif /* AEDSP16_SBPRO */
+
+#if defined(AEDSP16_MSS)
+
+int
+InitAEDSP16_MSS (struct address_info *hw_config)
+{
+  /*
+     * If the card is alredy init'ed SBPRO, we can not init it to MSS too
+     * because the board can not emulate simultaneously MSS and SBPRO.
+   */
+  if (ae_init & INIT_SBPRO)
+    return -1;
+  if (ae_init & INIT_MSS)
+    return 0;
+
+  /*
+     * For now we will leave this
+     * code included only when INCLUDE_AEDSP16 is configured in, but it should
+     * be better include it every time.
+   */
+  if (check_region (hw_config->io_base, 0x08))
+    {
+      printk ("MSS I/O port region is alredy in use.\n");
+      return -1;
+    }
+
+  /*
+     * We must allocate the AEDSP16 region too because these are the I/O ports
+     * to access card's control registers.
+   */
+  if (!(ae_init & INIT_MPU401))
+    {
+      if (check_region (AEDSP16_BASE, 0x0f))
+	{
+	  printk ("AEDSP16 I/O port region is alredy in use.\n");
+	  return -1;
+	}
+    }
+
+
+  /*
+     * If we are configuring the card for MSS, the portbase for card
+     * configuration is the default one (0x220 unless you have changed the
+     * factory default with board switches), so no need to modify the
+     * portbase variable.
+     * The default is AEDSP16_BASE, that is the right value.
+   */
+  irq = hw_config->irq;
+  dma = hw_config->dma;
+  if (InitAEDSP16 (INIT_MSS))
+    return -1;
+
+#if !defined(MODULE)
+  /*
+     * If we are compiling sound.o (MODULAR version) we can not
+     * request any region because there is not a uninit routine that
+     * can allow me to release the requested region. So when unloading
+     * and then reloading it, we are going to have some nice Oops!
+   */
+  request_region (hw_config->io_base, 0x08, "aedsp16 (mss)");
+#endif
+
+  if (!(ae_init & INIT_MPU401))
+    request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
+
+  ae_init |= INIT_MSS;
+  return 0;
+}
+
+#endif /* AEDSP16_MSS */
+
+#if defined(AEDSP16_MPU401)
+
+int
+InitAEDSP16_MPU401 (struct address_info *hw_config)
+{
+  if (ae_init & INIT_MPU401)
+    return 0;
+
+  /*
+     * For now we will leave this
+     * code included only when INCLUDE_AEDSP16 is configured in, but it should
+     * be better include it every time.
+   */
+  if (check_region (hw_config->io_base, 0x02))
+    {
+      printk ("SB I/O port region is alredy in use.\n");
+      return -1;
+    }
+
+  /*
+     * We must allocate the AEDSP16 region too because these are the I/O ports
+     * to access card's control registers.
+   */
+  if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
+    {
+      if (check_region (AEDSP16_BASE, 0x0f))
+	{
+	  printk ("AEDSP16 I/O port region is alredy in use.\n");
+	  return -1;
+	}
+    }
+
+  /*
+     * If mpu401, the irq and dma are not important, do not touch it
+     * because we may use the default if sbpro is not yet configured,
+     * we may use the sbpro ones if configured, and nothing wrong
+     * should happen.
+     *
+     * The mirq default is 0, but once set it to non-0 value, we should
+     * not touch it anymore (unless I write an ioctl to do it, of course).
+   */
+  mirq = hw_config->irq;
+  if (InitAEDSP16 (INIT_MPU401))
+    return -1;
+
+#if !defined(MODULE)
+  /*
+     * If we are compiling sound.o (MODULAR version) we can not
+     * request any region because there is not a uninit routine that
+     * can allow me to release the requested region.
+   */
+  request_region (hw_config->io_base, 0x02, "aedsp16 (mpu401)");
+#endif
+
+  if (!(ae_init & (INIT_MSS | INIT_SBPRO)))
+    request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)");
+
+  ae_init |= INIT_MPU401;
+  return 0;
+}
+
+#endif /* AEDSP16_MPU401 */
+
+#if 0				/* Leave it out for now. We are not using this portion of code. */
+
+/*
+ * Entry point for a reset function.
+ * May be I will write the infamous ioctl :)
+ */
+int
+ResetAEDSP16 (void)
+{
+#if defined(AEDSP16_DEBUG)
+  printk ("[aedsp16] ResetAEDSP16 called.\n");
+#endif
+  return InitAEDSP16 (RESET_DSP16);
+}
+
+#endif /* 0 */
+
+#endif /* !EXCLUDE_AEDSP16 */
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/audio.c linux/drivers/sound/audio.c
--- v1.3.8/linux/drivers/sound/audio.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/audio.c	Mon Jul 10 01:45:04 1995
@@ -33,11 +33,13 @@
 #ifndef EXCLUDE_AUDIO
 
 #include "ulaw.h"
+#include "coproc.h"
 
 #define ON		1
 #define OFF		0
 
 static int      wr_buff_no[MAX_AUDIO_DEV];	/*
+
 						 * != -1, if there is
 						 * a incomplete output
 						 * block in the queue.
@@ -45,6 +47,7 @@
 static int      wr_buff_size[MAX_AUDIO_DEV], wr_buff_ptr[MAX_AUDIO_DEV];
 
 static int      audio_mode[MAX_AUDIO_DEV];
+static int      dev_nblock[MAX_AUDIO_DEV];	/* 1 if in noblocking mode */
 
 #define		AM_NONE		0
 #define		AM_WRITE	1
@@ -98,6 +101,16 @@
   if ((ret = DMAbuf_open (dev, mode)) < 0)
     return ret;
 
+  if (audio_devs[dev]->coproc)
+    if ((ret = audio_devs[dev]->coproc->
+	 open (audio_devs[dev]->coproc->devc, COPR_PCM)) < 0)
+      {
+	audio_release (dev, file);
+	printk ("Sound: Can't access coprocessor device\n");
+
+	return ret;
+      }
+
   local_conversion[dev] = 0;
 
   if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, bits, 1) != bits)
@@ -115,6 +128,8 @@
 
   wr_buff_no[dev] = -1;
   audio_mode[dev] = AM_NONE;
+  wr_buff_size[dev] = wr_buff_ptr[dev] = 0;
+  dev_nblock[dev] = 0;
 
   return ret;
 }
@@ -134,6 +149,8 @@
       wr_buff_no[dev] = -1;
     }
 
+  if (audio_devs[dev]->coproc)
+    audio_devs[dev]->coproc->close (audio_devs[dev]->coproc->devc, COPR_PCM);
   DMAbuf_release (dev, mode);
 }
 
@@ -155,9 +172,9 @@
 	   "1:\tlodsb\n\t"
 	   "xlatb\n\t"
 	   "stosb\n\t"
-	   "loop 1b\n\t":
-	   :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
-	   :"bx", "cx", "di", "si", "ax");
+"loop 1b\n\t":
+:	   "b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff)
+:	   "bx", "cx", "di", "si", "ax");
 }
 
 #endif
@@ -203,8 +220,13 @@
 				 * There is no incomplete buffers
 				 */
 	{
-	  if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0)
+	  if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev],
+						     &wr_buff_size[dev],
+						     dev_nblock[dev])) < 0)
 	    {
+	      /* Handle nonblocking mode */
+	      if (dev_nblock[dev] && wr_buff_no[dev] == RET_ERROR (EAGAIN))
+		return p;	/* No more space. Return # of accepted bytes */
 	      return wr_buff_no[dev];
 	    }
 	  wr_buff_ptr[dev] = 0;
@@ -284,8 +306,16 @@
 
   while (c)
     {
-      if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0)
-	return buff_no;
+      if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l,
+					 dev_nblock[dev])) < 0)
+	{
+	  /* Nonblocking mode handling. Return current # of bytes */
+
+	  if (dev_nblock[dev] && buff_no == RET_ERROR (EAGAIN))
+	    return p;
+
+	  return buff_no;
+	}
 
       if (l > c)
 	l = c;
@@ -324,56 +354,149 @@
 
   dev = dev >> 4;
 
-  switch (cmd)
+  if (((cmd >> 8) & 0xff) == 'C')
     {
-    case SNDCTL_DSP_SYNC:
-      if (wr_buff_no[dev] >= 0)
+      if (audio_devs[dev]->coproc)	/* Coprocessor ioctl */
+	return audio_devs[dev]->coproc->ioctl (audio_devs[dev]->coproc->devc, cmd, arg, 0);
+      else
+	printk ("/dev/dsp%d: No coprocessor for this device\n", dev);
+
+      return RET_ERROR (EREMOTEIO);
+    }
+  else
+    switch (cmd)
+      {
+      case SNDCTL_DSP_SYNC:
+	if (wr_buff_no[dev] >= 0)
+	  {
+	    DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+	    wr_buff_no[dev] = -1;
+	  }
+	return DMAbuf_ioctl (dev, cmd, arg, 0);
+	break;
+
+      case SNDCTL_DSP_POST:
+	if (wr_buff_no[dev] >= 0)
+	  {
+	    DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+
+	    wr_buff_no[dev] = -1;
+	  }
+	return 0;
+	break;
+
+      case SNDCTL_DSP_RESET:
+	wr_buff_no[dev] = -1;
+	return DMAbuf_ioctl (dev, cmd, arg, 0);
+	break;
+
+      case SNDCTL_DSP_GETFMTS:
+	return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
+	break;
+
+      case SNDCTL_DSP_SETFMT:
+	return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
+
+      case SNDCTL_DSP_GETISPACE:
+	if (audio_mode[dev] == AM_WRITE)
+	  return RET_ERROR (EBUSY);
+
 	{
-	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+	  audio_buf_info  info;
 
-	  wr_buff_no[dev] = -1;
+	  int             err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1);
+
+	  if (err < 0)
+	    return err;
+
+	  if (wr_buff_no[dev] != -1)
+	    info.bytes += wr_buff_ptr[dev];
+
+	  IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info));
+	  return 0;
 	}
-      return DMAbuf_ioctl (dev, cmd, arg, 0);
-      break;
 
-    case SNDCTL_DSP_POST:
-      if (wr_buff_no[dev] >= 0)
+      case SNDCTL_DSP_GETOSPACE:
+	if (audio_mode[dev] == AM_READ)
+	  return RET_ERROR (EBUSY);
+
 	{
-	  DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]);
+	  audio_buf_info  info;
 
-	  wr_buff_no[dev] = -1;
-	}
-      return 0;
-      break;
+	  int             err = DMAbuf_ioctl (dev, cmd, (unsigned long) &info, 1);
 
-    case SNDCTL_DSP_RESET:
-      wr_buff_no[dev] = -1;
-      return DMAbuf_ioctl (dev, cmd, arg, 0);
-      break;
+	  if (err < 0)
+	    return err;
 
-    case SNDCTL_DSP_GETFMTS:
-      return IOCTL_OUT (arg, audio_devs[dev]->format_mask);
-      break;
+	  if (wr_buff_no[dev] != -1)
+	    info.bytes += wr_buff_size[dev] - wr_buff_ptr[dev];
 
-    case SNDCTL_DSP_SETFMT:
-      return IOCTL_OUT (arg, set_format (dev, IOCTL_IN (arg)));
+	  IOCTL_TO_USER ((char *) arg, 0, (char *) &info, sizeof (info));
+	  return 0;
+	}
 
-    default:
-      return DMAbuf_ioctl (dev, cmd, arg, 0);
-      break;
-    }
+      case SNDCTL_DSP_NONBLOCK:
+	dev_nblock[dev] = 1;
+	return 0;
+	break;
+
+      default:
+	return DMAbuf_ioctl (dev, cmd, arg, 0);
+      }
 }
 
 long
 audio_init (long mem_start)
 {
   /*
- * NOTE! This routine could be called several times during boot.
- */
+     * NOTE! This routine could be called several times during boot.
+   */
   return mem_start;
 }
 
-#else
+#ifdef ALLOW_SELECT
+int
+audio_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+{
+  int             l;
+  char           *dmabuf;
+
+  dev = dev >> 4;
+
+  switch (sel_type)
+    {
+    case SEL_IN:
+      if (audio_mode[dev] != AM_READ)	/* Wrong direction */
+	return 0;
+
+      if (DMAbuf_getrdbuffer (dev, &dmabuf, &l,
+			      1 /* Don't block */ ) >= 0)
+	return 1;		/* We have data */
+
+      return DMAbuf_select (dev, file, sel_type, wait);
+      break;
+
+    case SEL_OUT:
+      if (audio_mode[dev] != AM_WRITE)	/* Wrong direction */
+	return 0;
+
+      if (wr_buff_no[dev] != -1)
+	return 1;		/* There is space in the current buffer */
+
+      return DMAbuf_select (dev, file, sel_type, wait);
+      break;
+
+    case SEL_EX:
+      return 0;
+    }
+
+  return 0;
+}
+
+#endif /* ALLOW_SELECT */
+
+#else /* EXCLUDE_AUDIO */
 /*
  * Stub versions
  */
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/configure.c linux/drivers/sound/configure.c
--- v1.3.8/linux/drivers/sound/configure.c	Wed Jan 18 09:38:59 1995
+++ linux/drivers/sound/configure.c	Mon Jul 10 01:45:05 1995
@@ -1,3 +1,4 @@
+#define DISABLED_OPTIONS 	0
 /*
  * sound/configure.c  - Configuration program for the Linux Sound Driver
  *
@@ -45,26 +46,36 @@
 #define OPT_GUS16	7
 #define OPT_GUSMAX	8
 #define OPT_MSS		9
-
-#define OPT_HIGHLEVEL   10	/* This must be same than the next one */
-#define OPT_SBPRO	10
-#define OPT_SB16	11
-#define OPT_AUDIO	12
-#define OPT_MIDI_AUTO	13
-#define OPT_MIDI	14
-#define OPT_YM3812_AUTO	15
-#define OPT_YM3812	16
-#define OPT_SEQUENCER	17
-#define OPT_LAST	17	/* Must be the same than the defined OPT */
+#define OPT_SSCAPE	10
+#define OPT_TRIX	11
+#define OPT_MAD16	12
+
+#define OPT_HIGHLEVEL   13	/* This must be same than the next one */
+#define OPT_SBPRO	13
+#define OPT_SB16	14
+#define OPT_AEDSP16     15
+#define OPT_AUDIO	16
+#define OPT_MIDI_AUTO	17
+#define OPT_MIDI	18
+#define OPT_YM3812_AUTO	19
+#define OPT_YM3812	20
+#define OPT_SEQUENCER	21
+#define OPT_LAST	21	/* Last defined OPT number */
 
 #define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)| \
-		  B(OPT_MPU401)|B(OPT_PSS)|B(OPT_GUS16)|B(OPT_GUSMAX)|B(OPT_MSS))
+		  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))
+#define AUDIO_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS) | \
+		B (OPT_MSS) | B (OPT_GUS16) | B (OPT_GUSMAX) | B (OPT_TRIX) | \
+		B (OPT_SSCAPE)| B(OPT_MAD16))
+#define MIDI_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \
+		    B (OPT_GUS) | B (OPT_TRIX) | B (OPT_SSCAPE)|B(OPT_MAD16))
 /*
  * Options that have been disabled for some reason (incompletely implemented
  * and/or tested). Don't remove from this list before looking at file
  * experimental.txt for further info.
  */
-#define DISABLED_OPTIONS (B(OPT_PSS))
 
 typedef struct
   {
@@ -109,14 +120,18 @@
   {B (OPT_GUS), 0, "GUS16", 1, 0, 0},
   {B (OPT_GUS), B (OPT_GUS16), "GUSMAX", 1, 0, 0},
   {0, 0, "MSS", 1, 0, 0},
+  {0, 0, "SSCAPE", 1, 0, 0},
+  {0, 0, "TRIX", 1, 0, 0},
+  {0, 0, "MAD16", 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_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS) | B (OPT_MSS), 0, "AUDIO", 1, 0, 1},
+  {B (OPT_SBPRO) | B (OPT_MSS) | B (OPT_MPU401), 0, "AEDSP16", 1, 0, 0},
+  {AUDIO_CARDS, 0, "AUDIO", 1, 0, 1},
   {B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI, 0},
-  {B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1},
+  {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_YM3812_AUTO), "YM3812", 1, 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},
   {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1}
 };
 
@@ -124,7 +139,7 @@
 {
   "ProAudioSpectrum 16 support",
   "SoundBlaster support",
-  "AdLib support",
+  "Generic OPL2/OPL3 FM synthesizer support",
   "Gravis Ultrasound support",
   "MPU-401 support (NOT for SB16)",
   "6850 UART Midi support",
@@ -132,24 +147,32 @@
   "16 bit sampling option of GUS (_NOT_ GUS MAX)",
   "GUS MAX support",
   "Microsoft Sound System support",
+  "Ensoniq Soundscape support",
+  "MediaTriX AudioTriX Pro support",
+  "Support for MAD16 and/or Mozart based cards",
 
   "SoundBlaster Pro support",
   "SoundBlaster 16 support",
-  "/dev/dsp and /dev/audio support (_recommended_)",
+  "Audio Excel DSP 16 initialization support",
+  "/dev/dsp and /dev/audio supports (usually required)",
   "This should not be asked",
   "MIDI interface support",
   "This should not be asked",
   "FM synthesizer (YM3812/OPL-3) support",
   "/dev/sequencer support",
-  "Should I die"
+  "Is the sky really falling"
 };
 
 unsigned long   selected_options = 0;
 int             sb_dma = 0;
 
+#include "hex2hex.h"
+int             bin2hex (char *path, char *target, char *varname);
+
 int
 can_select_option (int nr)
 {
+#if 0
   switch (nr)
     {
     case 0:
@@ -175,6 +198,7 @@
 
 
     }
+#endif
 
   if (hw_table[nr].conditions)
     if (!(hw_table[nr].conditions & selected_options))
@@ -262,15 +286,19 @@
   printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n\n");
 
   fprintf (stderr, "\nConfiguring the sound support\n\n");
-
+#if 0
+  /*
+     * The full driver appeared to be impossible to compile and boot.
+     * There are too much supported cards now.
+   */
   fprintf (stderr, "Do you want to include full version of the sound driver (n/y) ? ");
 
   if (think_positively (0))
     {
       /*
- * Select all but some most dangerous cards. These cards are difficult to
- * detect reliably or conflict with some other cards (SCSI, Mitsumi)
- */
+         * Select all but some most dangerous cards. These cards are difficult to
+         * detect reliably or conflict with some other cards (SCSI, Mitsumi)
+       */
       selected_options = 0xffffffff &
 	~(B (OPT_MPU401) | B (OPT_UART6850) | B (OPT_PSS)) &
 	~DISABLED_OPTIONS;
@@ -279,7 +307,9 @@
       full_driver = 1;
     }
   else
+#endif
     {
+#if 0
       fprintf (stderr, "Do you want to DISABLE the Sound Driver (n/y) ?");
       if (think_positively (0))
 	{
@@ -287,6 +317,7 @@
 	  printf ("#undef KERNEL_SOUNDCARD\n");
 	  exit (0);
 	}
+#endif
       /*
        * Partial driver
        */
@@ -324,14 +355,119 @@
 
   if (selected_options & B (OPT_SBPRO))
     {
-      fprintf(stderr, "Do you want support for the mixer of SG NX Pro ? ");
+      fprintf (stderr, "Do you want support for the mixer of SG NX Pro ? ");
+      if (think_positively (0))
+	printf ("#define __SGNXPRO__\n");
+    }
+
+  if (selected_options & B (OPT_SB))
+    {
+      fprintf (stderr, "Do you want support for the MV Jazz16 (ProSonic etc.) ? ");
+      if (think_positively (0))
+	{
+	  printf ("#define JAZZ16\n");
+	  do
+	    {
+	      fprintf (stderr, "\tValid 16 bit DMA channels for ProSonic/Jazz 16 are\n");
+	      fprintf (stderr, "\t1, 3, 5 (default), 7\n");
+	      fprintf (stderr, "\tEnter 16bit DMA channel for Prosonic : ");
+	      num = ask_value ("%d", 5);
+	    }
+	  while (num != 1 && num != 3 && num != 5 && num != 7);
+	  fprintf (stderr, "ProSonic 16 bit DMA set to %d\n", num);
+	  printf ("#define JAZZ_DMA16 %d\n", num);
+
+	  fprintf (stderr, "Do you have SoundMan Wave (n/y) ? ");
+
+	  if (think_positively (0))
+	    {
+	      printf ("#define SM_WAVE\n");
+
+	    midi0001_again:
+	      fprintf
+		(stderr,
+		 "Logitech SoundMan Wave has a microcontroller which must be initialized\n"
+		 "before MIDI emulation works. This is possible only if the microcode\n"
+		 "file is compiled into the driver.\n"
+		 "Do you have access to the MIDI0001.BIN file (y/n) ? ");
+	      if (think_positively (1))
+		{
+		  char            path[512];
+
+		  fprintf (stderr,
+			   "Enter full name of the MIDI0001.BIN file (pwd is sound): ");
+		  scanf ("%s", path);
+		  fprintf (stderr, "including microcode file %s\n", path);
+
+		  if (!bin2hex (path, "smw-midi0001.h", "smw_ucode"))
+		    {
+		      fprintf (stderr, "couldn't open %s file\n",
+			       path);
+		      fprintf (stderr, "try again with correct path? ");
+		      if (think_positively (1))
+			goto midi0001_again;
+		    }
+		  else
+		    printf ("#define SMW_MIDI0001_INCLUDED\n");
+		}
+	    }
+	}
+    }
+
+  if (selected_options & B (OPT_SBPRO))
+    {
+      fprintf (stderr, "\n\nThe Logitech SoundMan Games supports 44 kHz in stereo\n"
+	       "while the standard SB Pro supports just 22 kHz/stereo\n"
+	       "You have an option to enable the SM Games mode.\n"
+	       "However do enable it only if you are _sure_ that your\n"
+	       "card is a SM Games. Enabling this feature with a\n"
+	       "plain old SB Pro _will_ cause troubles with stereo mode.\n"
+	       "\n"
+	       "DANGER! Read the above once again before answering 'y'\n"
+	       "Answer 'n' in case you are unsure what to do!\n");
+      fprintf (stderr, "Do you have a Logitech SoundMan Games (n/y) ? ");
       if (think_positively (0))
-	 printf("#define __SGNXPRO__\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))
+	{
+	  fprintf (stderr, "Do you want support for the Audio Excel SoundBlaster pro mode ? ");
+	  if (think_positively (1))
+	    {
+	      printf ("#define AEDSP16_SBPRO\n");
+	      sel1 = 1;
+	    }
+	}
+
+      if ((selected_options & B (OPT_MSS)) && (sel1 == 0))
+	{
+	  fprintf (stderr, "Do you want support for the Audio Excel Microsoft Sound System mode? ");
+	  if (think_positively (1))
+	    {
+	      printf ("#define AEDSP16_MSS\n");
+	      sel1 = 1;
+	    }
+	}
+
+      if (sel1 == 0)
+	{
+	  printf ("#undef CONFIGURE_SOUNDCARD\n");
+	  printf ("#undef KERNEL_SOUNDCARD\n");
+	  fprintf (stderr, "ERROR!!!!!\nYou loose: you must select at least one mode when using Audio Excel!\n");
+	  exit (-1);
+	}
+      if (selected_options & B (OPT_MPU401))
+	printf ("#define AEDSP16_MPU401\n");
+    }
+
   if (selected_options & B (OPT_PSS))
     {
     genld_again:
@@ -339,8 +475,8 @@
 	(stderr,
        "if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n"
 	 "then you must include the LD in the kernel.\n"
-	 "(do you wish to include a LD) ? ");
-      if (think_positively (0))
+	 "Do you wish to include a LD (y/n) ? ");
+      if (think_positively (1))
 	{
 	  char            path[512];
 
@@ -348,57 +484,55 @@
 		   "Enter the path to your LD file (pwd is sound): ");
 	  scanf ("%s", path);
 	  fprintf (stderr, "including LD file %s\n", path);
-	  selected_options |= B (OPT_SB) | B (OPT_MPU401) | B (OPT_ADLIB);
 
-	  /* Gen LD header */
-	  {
-	    int             fd;
-	    int             count;
-	    char            c;
-	    int             i = 0;
-
-	    if ((fd = open (path, 0)) > 0)
-	      {
-		FILE           *sf = fopen ("synth-ld.h", "w");
-
-		fprintf (sf, "/* automatically generated by configure */\n");
-		fprintf (sf, "unsigned char pss_synth[] = {\n");
-		while (1)
-		  {
-		    count = read (fd, &c, 1);
-		    if (count == 0)
-		      break;
-		    if (i != 0 && (i % 10) == 0)
-		      fprintf (sf, "\n");
-		    fprintf (sf, "0x%02x,", c & 0xFFL);
-		    i++;
-		  }
-		fprintf (sf, "};\n"
-			 "#define pss_synthLen %d\n", i);
-		fclose (sf);
-		close (fd);
-	      }
-	    else
-	      {
-		fprintf (stderr, "couldn't open %s as the ld file\n",
-			 path);
-		fprintf (stderr, "try again with correct path? ");
-		if (think_positively (1))
-		  goto genld_again;
-	      }
-	  }
+	  if (!bin2hex (path, "synth-ld.h", "pss_synth"))
+	    {
+	      fprintf (stderr, "couldn't open %s as the ld file\n",
+		       path);
+	      fprintf (stderr, "try again with correct path? ");
+	      if (think_positively (1))
+		goto genld_again;
+	    }
 	}
       else
 	{
 	  FILE           *sf = fopen ("synth-ld.h", "w");
 
-	  fprintf (sf, "/* automatically generated by configure */\n");
+	  fprintf (sf, "/* automaticaly generated by configure */\n");
 	  fprintf (sf, "unsigned char pss_synth[1];\n"
 		   "#define pss_synthLen 0\n");
 	  fclose (sf);
 	}
     }
 
+  if (selected_options & B (OPT_TRIX))
+    {
+    hex2hex_again:
+      fprintf (stderr, "MediaTriX audioTriX Pro has a onboard microcontroller\n"
+	       "which needs to be initialized by downloading\n"
+	       "the code from file TRXPRO.HEX in the DOS driver\n"
+	       "directory. If you don't have the TRXPRO.HEX handy\n"
+	       "you may skip this step. However SB and MPU-401\n"
+	       "modes of AudioTriX Pro will not work without\n"
+	       "this file!\n"
+	       "\n"
+	       "Do you want to include TRXPRO.HEX in your kernel (y/n) ? ");
+
+      if (think_positively (1))
+	{
+	  char            path[512];
+
+	  fprintf (stderr,
+		 "Enter the path to your TRXPRO.HEX file (pwd is sound): ");
+	  scanf ("%s", path);
+	  fprintf (stderr, "including HEX file %s\n", path);
+
+	  if (!hex2hex (path, "trix_boot.h", "static unsigned char trix_boot"))
+	    goto hex2hex_again;
+	  printf ("#define INCLUDE_TRIX_BOOT\n");
+	}
+    }
+
   if (!(selected_options & ANY_DEVS))
     {
       printf ("#undef CONFIGURE_SOUNDCARD\n");
@@ -423,6 +557,20 @@
   printf ("\n");
 
 #if defined(linux)
+  if (selected_options & B (OPT_AEDSP16))
+    {
+      fprintf (stderr, "\nI/O base for Audio Excel DSP 16 ?\n"
+	       "Warning:\n"
+	       "If you are using Audio Excel SoundBlaster emulation,\n"
+	"you must use the same I/O base for Audio Excel and SoundBlaster.\n"
+	       "The factory default is 220 (other possible value is 240)\n"
+	       "Enter the Audio Excel DSP 16 I/O base: ");
+
+      num = ask_value ("%x", 0x220);
+      fprintf (stderr, "Audio Excel DSP 16 I/O base set to %03x\n", num);
+      printf ("#define AEDSP16_BASE 0x%03x\n", num);
+    }
+
   if ((selected_options & B (OPT_SB)) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
     {
       fprintf (stderr, "\nI/O base for SB?\n"
@@ -450,7 +598,7 @@
 
       printf ("#define SBC_IRQ %d\n", num);
 
-      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_PSS)))
+      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS)))
 	{
 	  fprintf (stderr, "\nDMA channel for SoundBlaster?\n"
 		   "For SB 1.0, 1.5 and 2.0 this MUST be 1\n"
@@ -502,6 +650,7 @@
 
   if (selected_options & B (OPT_PAS))
     {
+
       if (selected_options & (B (OPT_AUDIO) | B (OPT_MIDI)))
 	{
 	  fprintf (stderr, "\nIRQ number for ProAudioSpectrum?\n"
@@ -541,6 +690,17 @@
 	  fprintf (stderr, "\nProAudioSpectrum DMA set to %d\n", num);
 	  printf ("#define PAS_DMA %d\n", num);
 	}
+      fprintf (stderr, "\nEnable Joystick port on ProAudioSpectrum (n/y) ? ");
+      if (think_positively (0))
+	printf ("#define PAS_JOYSTICK_ENABLE\n");
+
+      fprintf (stderr, "PAS16 could be noisy with some mother boards\n"
+	       "There is a command line switch (was it :T?)\n"
+	       "in the DOS driver for PAS16 which solves this.\n"
+	       "Don't enable this feature unless you have problems!\n"
+	       "Do you have to use this switch with DOS (y/n) ?");
+      if (think_positively (0))
+	printf ("#define BROKEN_BUS_CLOCK\n");
     }
 
   if (selected_options & B (OPT_GUS))
@@ -602,6 +762,65 @@
 	}
       fprintf (stderr, "\nGravis UltraSound DMA set to %d\n", num);
       printf ("#define GUS_DMA %d\n", num);
+
+      if (selected_options & B (OPT_GUSMAX))
+	{
+	  fprintf (stderr, "\nSecond DMA channel for GUS MAX (optional)?\n"
+		   "The default value is 7 (0 disables)\n"
+		   "Enter the value: ");
+
+	  num = ask_value ("%d", 7);
+	  if (num > 0)
+	    {
+	      if (num > 7)
+		{
+		  fprintf (stderr, "*** Illegal input! ***\n");
+		  num = 7;
+		}
+
+	      fprintf (stderr, "\nGUSMAX DMA set to %d\n", num);
+	      printf ("#define GUSMAX_DMA %d\n", num);
+	    }
+	}
+
+      if (selected_options & B (OPT_GUS16))
+	{
+	  fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n"
+		   "The factory default is 530\n"
+		   "Other possible values are  604, E80 or F40\n"
+		   "Enter the GUS16 I/O base: ");
+
+	  num = ask_value ("%x", 0x530);
+	  fprintf (stderr, "GUS16 I/O base set to %03x\n", num);
+	  printf ("#define GUS16_BASE 0x%03x\n", num);
+
+	  fprintf (stderr, "\nIRQ number for GUS16?\n"
+		   "Valid numbers are: 3, 4, 5, 7, or 9(=2).\n"
+		   "The default value is 7.\n"
+		   "Enter the value: ");
+
+	  num = ask_value ("%d", 7);
+	  if (num == 6 || num < 3 || num > 15)
+	    {
+	      fprintf (stderr, "*** Illegal input! ***\n");
+	      num = 7;
+	    }
+	  fprintf (stderr, "GUS16 IRQ set to %d\n", num);
+	  printf ("#define GUS16_IRQ %d\n", num);
+
+	  fprintf (stderr, "\nDMA number for GUS16?\n"
+		   "The default value is 3\n"
+		   "Enter the value: ");
+
+	  num = ask_value ("%d", 3);
+	  if (num < 0 || num > 3)
+	    {
+	      fprintf (stderr, "*** Illegal input! ***\n");
+	      num = 3;
+	    }
+	  fprintf (stderr, "\nGUS16 DMA set to %d\n", num);
+	  printf ("#define GUS16_DMA %d\n", num);
+	}
     }
 
   if (selected_options & B (OPT_MPU401))
@@ -620,9 +839,7 @@
 	       "Enter the value: ");
 
       num = ask_value ("%d", 9);
-      if (num == 6 || num < 3 || num > 15)	/*
-						 * Used for floppy
-						 */
+      if (num == 6 || num < 3 || num > 15)
 	{
 
 	  fprintf (stderr, "*** Illegal input! ***\n");
@@ -635,15 +852,15 @@
   if (selected_options & B (OPT_UART6850))
     {
       fprintf (stderr, "\nI/O base for 6850 UART Midi?\n"
-	       "Be careful. No defaults.\n"
+	       "Be carefull. No defaults.\n"
 	       "Enter the 6850 UART I/O base: ");
 
       num = ask_value ("%x", 0);
       if (num == 0)
 	{
 	  /*
- * Invalid value entered
- */
+	     * Invalid value entered
+	   */
 	  printf ("#define EXCLUDE_UART6850\n");
 	}
       else
@@ -657,9 +874,7 @@
 		   "Enter the value: ");
 
 	  num = ask_value ("%d", 5);
-	  if (num == 6 || num < 3 || num > 15)	/*
-						 * Used for floppy
-						 */
+	  if (num == 6 || num < 3 || num > 15)
 	    {
 
 	      fprintf (stderr, "*** Illegal input! ***\n");
@@ -673,7 +888,7 @@
   if (selected_options & B (OPT_PSS))
     {
       fprintf (stderr, "\nI/O base for PSS?\n"
-	       "The factory default is 220\n"
+	       "The factory default is 220 (240 also possible)\n"
 	       "Enter the PSS I/O base: ");
 
       num = ask_value ("%x", 0x220);
@@ -686,7 +901,7 @@
 	       "Enter the value: ");
 
       num = ask_value ("%d", 10);
-      if (num == 6 || num < 3 || num > 15)	/* Used for floppy */
+      if (num == 6 || num < 3 || num > 15)
 	{
 	  fprintf (stderr, "*** Illegal input! ***\n");
 	  num = 7;
@@ -695,6 +910,44 @@
       printf ("#define PSS_IRQ %d\n", num);
 
       fprintf (stderr, "\nDMA number for ECHO-PSS?\n"
+	       "The default value is 5\n"
+	       "Valid values are 5, 6 and 7\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 5);
+      if (num < 5 || num > 7)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 5;
+	}
+      fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num);
+      printf ("#define PSS_DMA %d\n", num);
+
+      fprintf (stderr, "\nMSS (MS Sound System) I/O base for the PSS card?\n"
+	       "The factory default is 530\n"
+	       "Other possible values are  604, E80 or F40\n"
+	       "Enter the MSS I/O base: ");
+
+      num = ask_value ("%x", 0x530);
+      fprintf (stderr, "PSS/MSS I/O base set to %03x\n", num);
+      printf ("#define PSS_MSS_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for the MSS mode of PSS ?\n"
+	       "Valid numbers are: 7, 9(=2), 10 and 11.\n"
+	       "The default value is 11.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 11);
+      if (num == 6 || num < 3 || num > 15)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 11;
+	}
+      fprintf (stderr, "PSS/MSS IRQ set to %d\n", num);
+      printf ("#define PSS_MSS_IRQ %d\n", num);
+
+      fprintf (stderr, "\nMSS DMA number for PSS?\n"
+	       "Valid values are 0, 1 and 3.\n"
 	       "The default value is 3\n"
 	       "Enter the value: ");
 
@@ -704,8 +957,31 @@
 	  fprintf (stderr, "*** Illegal input! ***\n");
 	  num = 3;
 	}
-      fprintf (stderr, "\nECHO-PSS DMA set to %d\n", num);
-      printf ("#define PSS_DMA %d\n", num);
+      fprintf (stderr, "\nPSS/MSS DMA set to %d\n", num);
+      printf ("#define PSS_MSS_DMA %d\n", num);
+
+      fprintf (stderr, "\nMIDI I/O base for PSS?\n"
+	       "The factory default is 330\n"
+	       "Enter the PSS MIDI I/O base: ");
+
+      num = ask_value ("%x", 0x330);
+      fprintf (stderr, "PSS/MIDI I/O base set to %03x\n", num);
+      printf ("#define PSS_MPU_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for PSS MIDI?\n"
+	       "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
+	       "The default value is 9.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 9);
+      if (num == 6 || num < 3 || num > 15)
+	{
+
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 5;
+	}
+      fprintf (stderr, "PSS MIDI IRQ set to %d\n", num);
+      printf ("#define PSS_MPU_IRQ %d\n", num);
     }
 
   if (selected_options & B (OPT_MSS))
@@ -725,7 +1001,7 @@
 	       "Enter the value: ");
 
       num = ask_value ("%d", 10);
-      if (num == 6 || num < 3 || num > 15)	/* Used for floppy */
+      if (num == 6 || num < 3 || num > 15)
 	{
 	  fprintf (stderr, "*** Illegal input! ***\n");
 	  num = 7;
@@ -734,7 +1010,7 @@
       printf ("#define MSS_IRQ %d\n", num);
 
       fprintf (stderr, "\nDMA number for MSS?\n"
-	       "Valid values are 1 and 3 (sometimes 0)"
+	       "Valid values are 0, 1 and 3.\n"
 	       "The default value is 3\n"
 	       "Enter the value: ");
 
@@ -748,61 +1024,275 @@
       printf ("#define MSS_DMA %d\n", num);
     }
 
-  if (selected_options & B (OPT_GUS16))
+  if (selected_options & B (OPT_SSCAPE))
     {
-      fprintf (stderr, "\nI/O base for GUS16 (GUS 16 bit sampling option)?\n"
+      int             reveal_spea;
+
+      fprintf (stderr, "\n(MIDI) I/O base for Ensoniq Soundscape?\n"
+	       "The factory default is 330\n"
+	       "Other possible values are 320, 340 or 350\n"
+	       "Enter the Soundscape I/O base: ");
+
+      num = ask_value ("%x", 0x330);
+      fprintf (stderr, "Soundscape I/O base set to %03x\n", num);
+      printf ("#define SSCAPE_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "Is your SoundScape card made/marketed by Reveal or Spea? ");
+      reveal_spea = think_positively (0);
+      if (reveal_spea)
+	printf ("#define REVEAL_SPEA\n");
+
+      fprintf (stderr, "\nIRQ number for Soundscape?\n");
+
+      if (reveal_spea)
+	fprintf (stderr, "Check valid interrupts from the manual of your card.\n");
+      else
+	fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 10.\n");
+
+      fprintf (stderr, "The default value is 9.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 9);
+      if (num == 6 || num < 3 || num > 15)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 9;
+	}
+      fprintf (stderr, "Soundscape IRQ set to %d\n", num);
+      printf ("#define SSCAPE_IRQ %d\n", num);
+
+      fprintf (stderr, "\nDMA number for Soundscape?\n"
+	       "Valid values are 1 and 3 (sometimes 0)"
+	       "The default value is 3\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 3);
+      if (num == 4 || num < 0 || num > 7)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 3;
+	}
+      fprintf (stderr, "\nSoundscape DMA set to %d\n", num);
+      printf ("#define SSCAPE_DMA %d\n", num);
+
+      fprintf (stderr, "\nMSS (MS Sound System) I/O base for the SSCAPE card?\n"
+	       "The factory default is 534\n"
+	       "Other possible values are  608, E84 or F44\n"
+	       "Enter the MSS I/O base: ");
+
+      num = ask_value ("%x", 0x534);
+      fprintf (stderr, "SSCAPE/MSS I/O base set to %03x\n", num);
+      printf ("#define SSCAPE_MSS_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for the MSS mode of SSCAPE ?\n");
+      if (reveal_spea)
+	fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 15.\n");
+      else
+	fprintf (stderr, "Valid numbers are: 5, 7, 9(=2) and 10.\n");
+      fprintf (stderr, "The default value is 5.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 5);
+      if (num == 6 || num < 3 || num > 15)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 10;
+	}
+      fprintf (stderr, "SSCAPE/MSS IRQ set to %d\n", num);
+      printf ("#define SSCAPE_MSS_IRQ %d\n", num);
+
+      fprintf (stderr, "\nMSS DMA number for SSCAPE?\n"
+	       "Valid values are 0, 1 and 3.\n"
+	       "The default value is 3\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 3);
+      if (num == 4 || num < 0 || num > 7)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 3;
+	}
+      fprintf (stderr, "\nSSCAPE/MSS DMA set to %d\n", num);
+      printf ("#define SSCAPE_MSS_DMA %d\n", num);
+    }
+  if (selected_options & B (OPT_TRIX))
+    {
+
+      fprintf (stderr, "\nWindows Sound System I/O base for the AudioTriX card?\n"
 	       "The factory default is 530\n"
 	       "Other possible values are  604, E80 or F40\n"
-	       "Enter the GUS16 I/O base: ");
+	       "Enter the MSS I/O base: ");
 
       num = ask_value ("%x", 0x530);
-      fprintf (stderr, "GUS16 I/O base set to %03x\n", num);
-      printf ("#define GUS16_BASE 0x%03x\n", num);
+      fprintf (stderr, "AudioTriX MSS I/O base set to %03x\n", num);
+      printf ("#define TRIX_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for the WSS mode of AudioTriX ?\n"
+	       "Valid numbers are: 5, 7, 9(=2), 10 and 11.\n"
+	       "The default value is 11.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 11);
+      if (num != 5 && num != 7 && num != 9 && num != 10 && num != 11)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 11;
+	}
+      fprintf (stderr, " AudioTriX WSS IRQ set to %d\n", num);
+      printf ("#define TRIX_IRQ %d\n", num);
 
-      fprintf (stderr, "\nIRQ number for GUS16?\n"
-	       "Valid numbers are: 3, 4, 5, 7, or 9(=2).\n"
+      fprintf (stderr, "\nWSS DMA number for AudioTriX?\n"
+	       "Valid values are 0, 1 and 3.\n"
+	       "The default value is 3\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 3);
+      if (num != 0 && num != 1 && num != 3)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 3;
+	}
+      fprintf (stderr, "\nAudioTriX/WSS DMA set to %d\n", num);
+      printf ("#define TRIX_DMA %d\n", num);
+
+      fprintf (stderr, "\nSoundBlaster I/O address for the AudioTriX card?\n"
+	       "The factory default is 220\n"
+	  "Other possible values are 200, 210, 230, 240, 250, 260 and 270\n"
+	       "Enter the MSS I/O base: ");
+
+      num = ask_value ("%x", 0x220);
+      fprintf (stderr, "AudioTriX SB I/O base set to %03x\n", num);
+      printf ("#define TRIX_SB_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for the SB mode of AudioTriX ?\n"
+	       "Valid numbers are: 3, 4, 5 and 7.\n"
 	       "The default value is 7.\n"
 	       "Enter the value: ");
 
       num = ask_value ("%d", 7);
-      if (num == 6 || num < 3 || num > 15)	/* Used for floppy */
+      if (num != 3 && num != 4 && num != 5 && num != 7)
 	{
 	  fprintf (stderr, "*** Illegal input! ***\n");
 	  num = 7;
 	}
-      fprintf (stderr, "GUS16 IRQ set to %d\n", num);
-      printf ("#define GUS16_IRQ %d\n", num);
+      fprintf (stderr, " AudioTriX SB IRQ set to %d\n", num);
+      printf ("#define TRIX_SB_IRQ %d\n", num);
+
+      fprintf (stderr, "\nSB DMA number for AudioTriX?\n"
+	       "Valid values are 1 and 3.\n"
+	       "The default value is 1\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 1);
+      if (num != 1 && num != 3)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 1;
+	}
+      fprintf (stderr, "\nAudioTriX/SB DMA set to %d\n", num);
+      printf ("#define TRIX_SB_DMA %d\n", num);
+
+      fprintf (stderr, "\nMIDI (MPU-401) I/O address for the AudioTriX card?\n"
+	       "The factory default is 330\n"
+	       "Other possible values are 330, 370, 3B0 and 3F0\n"
+	       "Enter the MPU I/O base: ");
+
+      num = ask_value ("%x", 0x330);
+      fprintf (stderr, "AudioTriX MIDI I/O base set to %03x\n", num);
+      printf ("#define TRIX_MPU_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nMIDI IRQ number for the AudioTriX ?\n"
+	       "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n"
+	       "The default value is 5.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 5);
+      if (num != 3 && num != 4 && num != 5 && num != 7 && num != 9)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 5;
+	}
+      fprintf (stderr, " AudioTriX MIDI IRQ set to %d\n", num);
+      printf ("#define TRIX_MPU_IRQ %d\n", num);
+    }
+
+  if (selected_options & B (OPT_MAD16))
+    {
+      fprintf (stderr, "\n*** Options for the MAD16 and Mozart based cards ***\n\n");
+
+      fprintf (stderr, "\nWindows Sound System I/O base for the MAD16/Mozart card?\n"
+	       "The factory default is 530\n"
+	       "Other possible values are  604, E80 or F40\n"
+	       "(Check which ones are supported by your card!!!!!!)\n"
+	       "Enter the MSS I/O base: ");
+
+      num = ask_value ("%x", 0x530);
+      fprintf (stderr, "MAD16 MSS I/O base set to %03x\n", num);
+      printf ("#define MAD16_BASE 0x%03x\n", num);
+
+      fprintf (stderr, "\nIRQ number for the WSS mode of MAD16/Mozart ?\n"
+	       "Valid numbers are: 7, 9(=2), 10 and 11.\n"
+	       "The default value is 11.\n"
+	       "Enter the value: ");
+
+      num = ask_value ("%d", 11);
+      if (num != 7 && num != 9 && num != 10 && num != 11)
+	{
+	  fprintf (stderr, "*** Illegal input! ***\n");
+	  num = 11;
+	}
+      fprintf (stderr, " MAD16 WSS IRQ set to %d\n", num);
+      printf ("#define MAD16_IRQ %d\n", num);
 
-      fprintf (stderr, "\nDMA number for GUS16?\n"
+      fprintf (stderr, "\nWSS DMA number for MAD16/Mozart?\n"
+	       "Valid values are 0, 1 and 3.\n"
 	       "The default value is 3\n"
 	       "Enter the value: ");
 
       num = ask_value ("%d", 3);
-      if (num < 0 || num > 3)
+      if (num != 0 && num != 1 && num != 3)
 	{
 	  fprintf (stderr, "*** Illegal input! ***\n");
 	  num = 3;
 	}
-      fprintf (stderr, "\nGUS16 DMA set to %d\n", num);
-      printf ("#define GUS16_DMA %d\n", num);
+      fprintf (stderr, "\nMAD16/WSS DMA set to %d\n", num);
+      printf ("#define MAD16_DMA %d\n", num);
+
+      fprintf (stderr, "\nMIDI (MPU-401) I/O address for the MAD16 card?\n"
+	       "(MPU401 is not supported by Mozart and 82C928)\n"
+	       "(This is the second MIDI port in TB Tropez)\n"
+	       "The factory default is 330 (use 0 to disable)\n"
+	       "Other possible values are 330, 320, 310 and 300\n"
+	       "Enter the MPU I/O base: ");
+
+      num = ask_value ("%x", 0x330);
+      if (num == 0)
+	fprintf (stderr, "MAD16/Mozart MIDI port disabled\n");
+      else
+	{
+	  fprintf (stderr, "MAD16 MIDI I/O base set to %03x\n", num);
+	  printf ("#define MAD16_MPU_BASE 0x%03x\n", num);
+
+	  fprintf (stderr, "\nMIDI IRQ number for the MAD16 ?\n"
+		   "Valid numbers are: 5, 7, 9(=2) and 10.\n"
+		   "The default value is 5.\n"
+		   "Enter the value: ");
+
+	  num = ask_value ("%d", 5);
+	  if (num != 3 && num != 4 && num != 5 && num != 7 && num != 9)
+	    {
+	      fprintf (stderr, "*** Illegal input! ***\n");
+	      num = 5;
+	    }
+	  fprintf (stderr, " MAD16 MIDI IRQ set to %d\n", num);
+	  printf ("#define MAD16_MPU_IRQ %d\n", num);
+	}
     }
 #endif
 
   if (selected_options & B (OPT_AUDIO))
     {
-      def_size = 16384;
-
-      if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B (OPT_SB16)))
-	def_size = 32768;
-
-#ifndef __386BSD__
-      if ((selected_options & (B (OPT_PAS) | B (OPT_PAS) | B (OPT_GUS16) | B (OPT_GUSMAX) |
-			       B (OPT_MSS) | B (OPT_PSS))) &&
-	  !full_driver)
-	def_size = 65536;	/*
-				 * PAS16 or SB16
-				 */
-#endif
+      def_size = 65536;
 
       fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n"
 	       "%d is recommended value for this configuration.\n"
@@ -827,4 +1317,38 @@
 #endif
 
   exit (0);
+}
+
+int
+bin2hex (char *path, char *target, char *varname)
+{
+  int             fd;
+  int             count;
+  char            c;
+  int             i = 0;
+
+  if ((fd = open (path, 0)) > 0)
+    {
+      FILE           *sf = fopen (target, "w");
+
+      fprintf (sf, "/* automaticaly generated by configure */\n");
+      fprintf (sf, "static unsigned char %s[] = {\n", varname);
+      while (1)
+	{
+	  count = read (fd, &c, 1);
+	  if (count == 0)
+	    break;
+	  if (i != 0 && (i % 10) == 0)
+	    fprintf (sf, "\n");
+	  fprintf (sf, "0x%02x,", c & 0xFFL);
+	  i++;
+	}
+      fprintf (sf, "};\n"
+	       "#define %sLen %d\n", varname, i);
+      fclose (sf);
+      close (fd);
+      return 1;
+    }
+
+  return 0;
 }
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/coproc.h linux/drivers/sound/coproc.h
--- v1.3.8/linux/drivers/sound/coproc.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/coproc.h	Fri Mar  3 12:03:07 1995
@@ -0,0 +1,12 @@
+/*
+ * Definitions for various on board processors on the soundcards. For
+ * example DSP processors.
+ */
+
+/*
+ * Coprocessor access types 
+ */
+#define COPR_CUSTOM		0x0001	/* Custom applications */
+#define COPR_MIDI		0x0002	/* MIDI (MPU-401) emulation */
+#define COPR_PCM		0x0004	/* Digitized voice applications */
+#define COPR_SYNTH		0x0008	/* Music synthesis */
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/dev_table.c linux/drivers/sound/dev_table.c
--- v1.3.8/linux/drivers/sound/dev_table.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/dev_table.c	Mon Jul 10 01:45:05 1995
@@ -52,6 +52,8 @@
   int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
   int             drv;
 
+  printk ("Sound initialization started\n");
+
   for (i = 0; i < (n - 1); i++)
     if (snd_installed_cards[i].enabled)
       if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
@@ -77,74 +79,75 @@
 	snd_installed_cards[i].enabled = 0;	/*
 						 * Mark as not detected
 						 */
+  printk ("Sound initialization complete\n");
   return mem_start;
 }
 
 int
 sndtable_probe (int unit, struct address_info *hw_config)
-  {
-    int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+{
+  int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
-    if (!unit)
-      return TRUE;
+  if (!unit)
+    return TRUE;
+
+  for (i = 0; i < (n - 1); i++)
+    if (snd_installed_cards[i].enabled)
+      if (snd_installed_cards[i].card_type == unit)
+	{
+	  int             drv;
 
-    for (i = 0; i < (n - 1); i++)
-      if (snd_installed_cards[i].enabled)
-	if (snd_installed_cards[i].card_type == unit)
-	  {
-	    int             drv;
-
-	    snd_installed_cards[i].config.io_base = hw_config->io_base;
-	    snd_installed_cards[i].config.irq = hw_config->irq;
-	    snd_installed_cards[i].config.dma = hw_config->dma;
-	    if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
-	      snd_installed_cards[i].enabled = 0;	/*
+	  snd_installed_cards[i].config.io_base = hw_config->io_base;
+	  snd_installed_cards[i].config.irq = hw_config->irq;
+	  snd_installed_cards[i].config.dma = hw_config->dma;
+	  if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
+	    snd_installed_cards[i].enabled = 0;		/*
 							 * Mark as not
 							 * detected
 							 */
-	    else if (sound_drivers[drv].probe (hw_config))
-	      return 1;
-	    snd_installed_cards[i].enabled = 0;	/*
+	  else if (sound_drivers[drv].probe (hw_config))
+	    return 1;
+	  snd_installed_cards[i].enabled = 0;	/*
 						 * Mark as not detected
 						 */
-	    return 0;
-	  }
+	  return 0;
+	}
 
-    return FALSE;
-  }
+  return FALSE;
+}
 
 int
 sndtable_init_card (int unit, struct address_info *hw_config)
-  {
-    int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
+{
+  int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
-    if (!unit)
+  if (!unit)
+    {
+      if (sndtable_init (0) != 0)
+	panic ("snd: Invalid memory allocation\n");
+      return TRUE;
+    }
+
+  for (i = 0; i < (n - 1); i++)
+    if (snd_installed_cards[i].card_type == unit)
       {
-	if (sndtable_init (0) != 0)
-	  panic ("snd: Invalid memory allocation\n");
-	return TRUE;
-      }
+	int             drv;
 
-    for (i = 0; i < (n - 1); i++)
-      if (snd_installed_cards[i].card_type == unit)
-	{
-	  int             drv;
+	snd_installed_cards[i].config.io_base = hw_config->io_base;
+	snd_installed_cards[i].config.irq = hw_config->irq;
+	snd_installed_cards[i].config.dma = hw_config->dma;
 
-	  snd_installed_cards[i].config.io_base = hw_config->io_base;
-	  snd_installed_cards[i].config.irq = hw_config->irq;
-	  snd_installed_cards[i].config.dma = hw_config->dma;
-
-	  if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
-	    snd_installed_cards[i].enabled = 0;	/*
+	if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) == -1)
+	  snd_installed_cards[i].enabled = 0;	/*
 						 * Mark as not detected
 						 */
-	  else if (sound_drivers[drv].attach (0, hw_config) != 0)
-	    panic ("snd#: Invalid memory allocation\n");
-	  return TRUE;
-	}
+	else if (sound_drivers[drv].attach (0, hw_config) != 0)
+	  panic ("snd#: Invalid memory allocation\n");
+	return TRUE;
+      }
 
-    return FALSE;
-  }
+  return FALSE;
+}
 
 int
 sndtable_get_cardcount (void)
@@ -159,8 +162,8 @@
   int             i, n = sizeof (snd_installed_cards) / sizeof (struct card_info);
 
   /*
- * First disable all drivers
- */
+     * First disable all drivers
+   */
 
   for (i = 0; i < n; i++)
     snd_installed_cards[i].enabled = 0;
@@ -168,8 +171,8 @@
   if (ints[0] == 0 || ints[1] == 0)
     return;
   /*
- * Then enable them one by time
- */
+     * Then enable them one by time
+   */
 
   for (i = 1; i <= ints[0]; i++)
     {
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h
--- v1.3.8/linux/drivers/sound/dev_table.h	Wed Jul 20 15:00:29 1994
+++ linux/drivers/sound/dev_table.h	Wed Jul  5 22:34:45 1995
@@ -107,6 +107,20 @@
 	int	 underrun_count;
 };
 
+/*
+ * Structure for use with various microcontrollers and DSP processors 
+ * in the recent soundcards.
+ */
+typedef struct coproc_operations {
+		char name[32];
+		int (*open) (void *devc, int sub_device);
+		void (*close) (void *devc, int sub_device);
+		int (*ioctl) (void *devc, unsigned int cmd, unsigned int arg, int local);
+		void (*reset) (void *devc);
+
+		void *devc;		/* Driver specific info */
+	} coproc_operations;
+
 struct audio_operations {
         char name[32];
 	int flags;
@@ -133,9 +147,12 @@
 	long buffsize;
 	int dmachan;
 	struct dma_buffparms *dmap;
+	struct coproc_operations *coproc;
+	int mixer_dev;
 };
 
 struct mixer_operations {
+	char name[32];
 	int (*ioctl) (int dev, unsigned int cmd, unsigned int arg);
 };
 
@@ -162,14 +179,29 @@
 	int (*pmgr_interface) (int dev, struct patmgr_info *info);
 	void (*bender) (int dev, int chn, int value);
 	int (*alloc_voice) (int dev, int chn, int note, struct voice_alloc_info *alloc);
+	void (*setup_voice) (int dev, int voice, int chn);
 
  	struct voice_alloc_info alloc;
  	struct channel_info chn_info[16];
 };
 
+struct midi_input_info { /* MIDI input scanner variables */
+#define MI_MAX	10
+    		int             m_busy;
+    		unsigned char   m_buf[MI_MAX];
+		unsigned char	m_prev_status;	/* For running status */
+    		int             m_ptr;
+#define MST_INIT			0
+#define MST_DATA			1
+#define MST_SYSEX			2
+    		int             m_state;
+    		int             m_left;
+	};
+
 struct midi_operations {
 	struct midi_info info;
 	struct synth_operations *converter;
+	struct midi_input_info in_info;
 	int (*open) (int dev, int mode,
 		void (*inputintr)(int dev, unsigned char data),
 		void (*outputintr)(int dev)
@@ -183,6 +215,7 @@
 	int (*command) (int dev, unsigned char *data);
 	int (*buffer_status) (int dev);
 	int (*prefix_cmd) (int dev, unsigned char status);
+	struct coproc_operations *coproc;
 };
 
 struct sound_timer_operations {
@@ -221,6 +254,16 @@
 	struct driver_info sound_drivers[] = {
 #ifndef EXCLUDE_PSS
 	  {SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss},
+#	ifdef PSS_MPU_BASE
+	  {SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu},
+#	endif
+#	ifdef PSS_MSS_BASE
+	  {SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss},
+#	endif
+#endif
+#ifndef EXCLUDE_MAD16
+		{SNDCARD_MAD16,	"MAD16/Mozart (MSS)",		attach_mad16, probe_mad16},
+		{SNDCARD_MAD16_MPU,	"MAD16/Mozart (MPU)",		attach_mad16_mpu, probe_mad16_mpu},
 #endif
 #ifndef EXCLUDE_YM3812
 		{SNDCARD_ADLIB,	"OPL-2/OPL-3 FM",		attach_adlib_card, probe_adlib},
@@ -254,9 +297,19 @@
 #ifndef EXCLUDE_GUS
 		{SNDCARD_GUS,	"Gravis Ultrasound",	attach_gus_card, probe_gus},
 #endif
+#ifndef EXCLUDE_SSCAPE
+		{SNDCARD_SSCAPE, "Ensoniq Soundscape",	attach_sscape, probe_sscape},
+		{SNDCARD_SSCAPE_MSS,	"MS Sound System (SoundScape)",	attach_ss_ms_sound, probe_ss_ms_sound},
+#endif
+#ifndef EXCLUDE_TRIX
+		{SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro",	attach_trix_wss, probe_trix_wss},
+		{SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)",	attach_trix_sb, probe_trix_sb},
+		{SNDCARD_TRXPRO_MPU, "AudioTriX MIDI",	attach_trix_mpu, probe_trix_mpu},
+#endif
 		{0,			"*?*",			NULL, NULL}
 	};
 
+#ifdef linux
 /*
  *	List of devices actually configured in the system.
  *
@@ -266,16 +319,33 @@
 	struct card_info snd_installed_cards[] = {
 #ifndef EXCLUDE_PSS
 	     {SNDCARD_PSS, {PSS_BASE, PSS_IRQ, PSS_DMA}, SND_DEFAULT_ENABLE},
+#	ifdef PSS_MPU_BASE
+	     {SNDCARD_PSS_MPU, {PSS_MPU_BASE, PSS_MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
+#	endif
+#	ifdef PSS_MSS_BASE
+	     {SNDCARD_PSS_MSS, {PSS_MSS_BASE, PSS_MSS_IRQ, PSS_MSS_DMA}, SND_DEFAULT_ENABLE},
+#	endif
 #endif
-#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
-		{SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
-#ifdef MPU2_BASE
-		{SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
-#endif
-#ifdef MPU3_BASE
-		{SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#ifndef EXCLUDE_TRIX
+	     {SNDCARD_TRXPRO, {TRIX_BASE, TRIX_IRQ, TRIX_DMA}, SND_DEFAULT_ENABLE},
+#	ifdef TRIX_SB_BASE
+	     {SNDCARD_TRXPRO_SB, {TRIX_SB_BASE, TRIX_SB_IRQ, TRIX_SB_DMA}, SND_DEFAULT_ENABLE},
+#	endif
+#	ifdef TRIX_MPU_BASE
+	     {SNDCARD_TRXPRO_MPU, {TRIX_MPU_BASE, TRIX_MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
+#	endif
 #endif
+#ifndef EXCLUDE_SSCAPE
+	     {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA}, SND_DEFAULT_ENABLE},
+	     {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA}, SND_DEFAULT_ENABLE},
+#endif
+#ifndef EXCLUDE_MAD16
+	     {SNDCARD_MAD16, {MAD16_BASE, MAD16_IRQ, MAD16_DMA}, SND_DEFAULT_ENABLE},
+#	ifdef MAD16_MPU_BASE
+	     {SNDCARD_MAD16_MPU, {MAD16_MPU_BASE, MAD16_MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
+#	endif
 #endif
+
 #ifndef EXCLUDE_MSS
 		{SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE},
 #	ifdef MSS2_BASE
@@ -283,18 +353,31 @@
 #	endif
 #endif
 
-#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
-		{SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE},
-#endif
-
 #ifndef EXCLUDE_PAS
 		{SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA}, SND_DEFAULT_ENABLE},
 #endif
 
 #ifndef EXCLUDE_SB
+#	ifndef SBC_DMA
+#		define SBC_DMA		1
+#	endif
 		{SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA}, SND_DEFAULT_ENABLE},
 #endif
 
+#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
+		{SNDCARD_MPU401, {MPU_BASE, MPU_IRQ, 0}, SND_DEFAULT_ENABLE},
+#ifdef MPU2_BASE
+		{SNDCARD_MPU401, {MPU2_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
+#ifdef MPU3_BASE
+		{SNDCARD_MPU401, {MPU3_BASE, MPU2_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
+#endif
+
+#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
+		{SNDCARD_UART6850, {U6850_BASE, U6850_IRQ, 0}, SND_DEFAULT_ENABLE},
+#endif
+
 #if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16)
 #ifndef EXCLUDE_AUDIO
 		{SNDCARD_SB16, {SBC_BASE, SBC_IRQ, SB16_DMA}, SND_DEFAULT_ENABLE},
@@ -317,11 +400,15 @@
 		{0, {0}, 0}
 	};
 
-	int num_sound_drivers =
-	    sizeof(sound_drivers) / sizeof (struct driver_info);
 	int num_sound_cards =
 	    sizeof(snd_installed_cards) / sizeof (struct card_info);
 
+#else
+	int num_sound_cards = 0;
+#endif	/* linux */
+
+	int num_sound_drivers =
+	    sizeof(sound_drivers) / sizeof (struct driver_info);
 
 #else
 	extern struct audio_operations * audio_devs[MAX_AUDIO_DEV]; int num_audiodevs;
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v1.3.8/linux/drivers/sound/dmabuf.c	Mon Mar  6 11:22:09 1995
+++ linux/drivers/sound/dmabuf.c	Mon Jul 10 01:45:06 1995
@@ -3,7 +3,7 @@
  *
  * The DMA buffer manager for digitized voice applications
  *
- * Copyright by Hannu Savolainen 1993, 1994
+ * Copyright by Hannu Savolainen 1993, 1994, 1995
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -38,11 +38,13 @@
 DEFINE_WAIT_QUEUES (dev_sleeper[MAX_AUDIO_DEV], dev_sleep_flag[MAX_AUDIO_DEV]);
 
 static struct dma_buffparms dmaps[MAX_AUDIO_DEV] =
-{{0}};		/*
-		 * Primitive way to allocate
-		 * such a large array.
-		 * Needs dynamic run-time allocation.
-		 */
+{
+  {0}};				/*
+
+				   * Primitive way to allocate
+				   * such a large array.
+				   * Needs dynamic run-time alloction.
+				 */
 
 static void
 reorganize_buffers (int dev)
@@ -78,10 +80,10 @@
       sz = sr * nc * sz;
 
       /*
-   * Compute a buffer size for time not exceeding 1 second.
-   * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
-   * of sound (using the current speed, sample size and #channels).
-   */
+         * Compute a buffer size for time not exeeding 1 second.
+         * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds
+         * of sound (using the current speed, sample size and #channels).
+       */
 
       bsz = dsp_dev->buffsize;
       while (bsz > sz)
@@ -106,9 +108,9 @@
   else
     {
       /*
- * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or
- * the buffer size computation has already been done.
- */
+         * The process has specified the buffer sice with SNDCTL_DSP_SETFRAGMENT or
+         * the buffer sice computation has already been done.
+       */
       if (dmap->fragment_size > audio_devs[dev]->buffsize)
 	dmap->fragment_size = audio_devs[dev]->buffsize;
       bsz = dmap->fragment_size;
@@ -157,7 +159,6 @@
   dmap->flags = DMA_BUSY;	/* Other flags off */
   dmap->qlen = dmap->qhead = dmap->qtail = 0;
 
-  dmap->qlen = dmap->qtail = dmap->qhead = 0;
   dmap->dma_mode = DMODE_NONE;
 }
 
@@ -250,7 +251,7 @@
 
       /*
        * Some devices such as GUS have huge amount of on board RAM for the
-       * audio data. We have to wait util the device has finished playing.
+       * audio data. We have to wait until the device has finished playing.
        */
 
       DISABLE_INTR (flags);
@@ -295,7 +296,7 @@
 }
 
 int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
 {
   unsigned long   flags;
   int             err = EIO;
@@ -342,6 +343,12 @@
 	  dmap->flags |= DMA_ACTIVE | DMA_STARTED;
 	}
 
+      if (dontblock)
+	{
+	  RESTORE_INTR (flags);
+	  return RET_ERROR (EAGAIN);
+	}
+
       /* Wait for the next block */
 
       DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ);
@@ -425,7 +432,7 @@
 	  }
 
 	if (dmap->subdivision != 0 ||
-	    dmap->fragment_size)/* Too late to change */
+	    dmap->fragment_size)	/* Loo late to change */
 	  return RET_ERROR (EINVAL);
 
 	if (fact > MAX_REALTIME_FACTOR)
@@ -448,7 +455,7 @@
 	  return RET_ERROR (EIO);
 
 	if (dmap->subdivision != 0 ||
-	    dmap->fragment_size)/* Too late to change */
+	    dmap->fragment_size)	/* Loo late to change */
 	  return RET_ERROR (EINVAL);
 
 	bytes = fact & 0xffff;
@@ -478,11 +485,24 @@
       }
       break;
 
+    case SNDCTL_DSP_GETISPACE:
+    case SNDCTL_DSP_GETOSPACE:
+      if (!local)
+	return RET_ERROR (EINVAL);
+
+      {
+	audio_buf_info *info = (audio_buf_info *) arg;
+
+	info->fragments = dmap->qlen;
+	info->fragsize = dmap->fragment_size;
+	info->bytes = dmap->qlen * dmap->fragment_size;
+      }
+      return 0;
+
     default:
       return audio_devs[dev]->ioctl (dev, cmd, arg, local);
     }
 
-  return RET_ERROR (EIO);
 }
 
 static int
@@ -491,13 +511,13 @@
   int             len, max, tmp;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
-  if (dmap->qlen == dmap->nbufs)/* No space at all */
+  if (dmap->qlen == dmap->nbufs)	/* No space at all */
     return 0;
 
   /*
-  * Verify that there are no more pending buffers than the limit
-  * defined by the process.
-  */
+     * Verify that there are no more pending buffers than the limit
+     * defined by the process.
+   */
 
   max = dmap->max_fragments;
   len = dmap->qlen;
@@ -507,8 +527,8 @@
       tmp = audio_devs[dev]->local_qlen (dev);
       if (tmp & len)
 	tmp--;			/*
-			 * This buffer has been counted twice
-			 */
+				   * This buffer has been counted twice
+				 */
       len += tmp;
     }
 
@@ -518,7 +538,7 @@
 }
 
 int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
 {
   unsigned long   flags;
   int             abort, err = EIO;
@@ -551,6 +571,9 @@
     }
 
 
+  if (dontblock)
+    return RET_ERROR (EAGAIN);
+
   DISABLE_INTR (flags);
 
   abort = 0;
@@ -669,13 +692,24 @@
 #ifndef DMAMODE_AUTO
       printk ("sound: Invalid DMA mode for device %d\n", dev);
 #endif
+#if defined(SVR42)
+
+      /*
+         ** send full count to snd_dma_prog, it will take care of subtracting
+         ** one if it is required.
+       */
+      snd_dma_prog (chan, dmap->raw_buf_phys[0], dmap->bytes_in_use,
+		    dma_mode, TRUE);
+
+#else /* !SVR42 */
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode)
 #ifdef DMAMODE_AUTO
 		 | DMAMODE_AUTO
 #endif
 		 ,
-		 dmap->raw_buf_phys[0], dmap->bytes_in_use);
+		 dmap->raw_buf_phys[0], dmap->bytes_in_use - 1);
       dma_enable (chan);
+#endif /*  ! SVR42 */
 #else
 #error This routine is not valid for this OS.
 #endif
@@ -703,9 +737,15 @@
 #else
 
 #if defined(GENERIC_SYSV)
+#if defined(SVR42)
+
+      snd_dma_prog (chan, physaddr, count, dma_mode, FALSE);
+
+#else /* ! SVR42 */
       dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode),
 		 physaddr, count);
       dma_enable (chan);
+#endif /* SVR42 */
 #else
 #error This routine is not valid for this OS.
 #endif /* GENERIC_SYSV */
@@ -722,9 +762,13 @@
 {
   int             dev;
 
+#if defined(SVR42)
+  snd_dma_init ();
+#endif /* SVR42 */
+
   /*
- * NOTE! This routine could be called several times.
- */
+     * NOTE! This routine could be called several times.
+   */
 
   for (dev = 0; dev < num_audiodevs; dev++)
     audio_devs[dev]->dmap = &dmaps[dev];
@@ -735,18 +779,22 @@
 DMAbuf_outputintr (int dev, int event_type)
 {
   /*
- * Event types:
- *	0 = DMA transfer done. Device still has more data in the local
- *	    buffer.
- *	1 = DMA transfer done. Device doesn't have local buffer or it's
- *	    empty now.
- *	2 = No DMA transfer but the device has now more space in its local
- *	    buffer.
- */
+     * Event types:
+     *  0 = DMA transfer done. Device still has more data in the local
+     *      buffer.
+     *  1 = DMA transfer done. Device doesn't have local buffer or it's
+     *      empty now.
+     *  2 = No DMA transfer but the device has now more space in it's local
+     *      buffer.
+   */
 
   unsigned long   flags;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
+#if defined(SVR42)
+  snd_dma_intr (audio_devs[dev]->dmachan);
+#endif /* SVR42 */
+
   if (event_type != 2)
     {
       if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs)
@@ -793,6 +841,10 @@
   unsigned long   flags;
   struct dma_buffparms *dmap = audio_devs[dev]->dmap;
 
+#if defined(SVR42)
+  snd_dma_intr (audio_devs[dev]->dmachan);
+#endif /* SVR42 */
+
   if (dmap->qlen == (dmap->nbufs - 1))
     {
       printk ("Sound: Recording overrun\n");
@@ -832,7 +884,7 @@
   unsigned long   flags;
   int             chan = audio_devs[dev]->dmachan;
 
-  if (ALLOC_DMA_CHN (chan,"audio"))
+  if (ALLOC_DMA_CHN (chan, audio_devs[dev]->name))
     {
       printk ("Unable to grab DMA%d for the audio driver\n", chan);
       return RET_ERROR (EBUSY);
@@ -853,24 +905,72 @@
 {
   int             chan = audio_devs[dev]->dmachan;
 
-  DMAbuf_reset_dma (chan);
+  DMAbuf_reset_dma (dev);
   RELEASE_DMA_CHN (chan);
 }
 
 void
-DMAbuf_reset_dma (int chan)
+DMAbuf_reset_dma (int dev)
 {
+#if 0
+  int             chan = audio_devs[dev]->dmachan;
+
+  disable_dma (chan);
+#endif
 }
 
-/*
- * The sound_mem_init() is called by mem_init() immediately after mem_map is
- * initialized and before free_page_list is created.
- *
- * This routine allocates DMA buffers at the end of available physical memory (
- * <16M) and marks pages reserved at mem_map.
- */
+#ifdef ALLOW_SELECT
+int
+DMAbuf_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
+{
+  struct dma_buffparms *dmap = audio_devs[dev]->dmap;
+  unsigned long   flags;
 
-#else
+  switch (sel_type)
+    {
+    case SEL_IN:
+      if (dmap->dma_mode != DMODE_INPUT)
+	return 0;
+
+      if (!dmap->qlen)
+	{
+	  DISABLE_INTR (flags);
+	  dev_sleep_flag[dev].mode = WK_SLEEP;
+	  select_wait (&dev_sleeper[dev], wait);
+	  RESTORE_INTR (flags);
+	  return 0;
+	}
+      return 1;
+      break;
+
+    case SEL_OUT:
+      if (dmap->dma_mode == DMODE_INPUT)
+	return 0;
+
+      if (dmap->dma_mode == DMODE_NONE)
+	return 1;
+
+      if (!space_in_queue (dev))
+	{
+	  DISABLE_INTR (flags);
+	  dev_sleep_flag[dev].mode = WK_SLEEP;
+	  select_wait (&dev_sleeper[dev], wait);
+	  RESTORE_INTR (flags);
+	  return 0;
+	}
+      return 1;
+      break;
+
+    case SEL_EX:
+      return 0;
+    }
+
+  return 0;
+}
+
+#endif /* ALLOW_SELECT */
+
+#else /* EXCLUDE_AUDIO */
 /*
  * Stub versions if audio services not included
  */
@@ -888,13 +988,13 @@
 }
 
 int
-DMAbuf_getwrbuffer (int dev, char **buf, int *size)
+DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock)
 {
   return RET_ERROR (EIO);
 }
 
 int
-DMAbuf_getrdbuffer (int dev, char **buf, int *len)
+DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock)
 {
   return RET_ERROR (EIO);
 }
@@ -930,19 +1030,19 @@
 }
 
 int
-DMAbuf_open_dma (int chan)
+DMAbuf_open_dma (int dev)
 {
   return RET_ERROR (ENXIO);
 }
 
 void
-DMAbuf_close_dma (int chan)
+DMAbuf_close_dma (int dev)
 {
   return;
 }
 
 void
-DMAbuf_reset_dma (int chan)
+DMAbuf_reset_dma (int dev)
 {
   return;
 }
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/experimental.txt linux/drivers/sound/experimental.txt
--- v1.3.8/linux/drivers/sound/experimental.txt	Mon Mar  6 11:22:09 1995
+++ linux/drivers/sound/experimental.txt	Sun Apr  2 13:55:09 1995
@@ -1,12 +1,10 @@
-This version contains some features which is are NOT enabled by default. 
+This version contains some features which is may NOT be enabled by default. 
 I'm trying to release an official/reliable version soon so that the
 Linux version of Doom (and other games) becomes possible. For that reason
 I have disabled some features which are not reliable enough to be
 released for wide public. If you are interested to try them, please
 read this file carefully.
 
-There are currently following goodies which I have disabled:
-
 1) ECHO PSS (Personal Sound System support)
 
 This version contains support for soundcards based on the AD20msp614
@@ -21,38 +19,20 @@
 You have also to enable the MSS support since I have not integrated
 the AD1848 driver with the PSS one yet.
 
-2) WSS/MSS (Microsoft Sound System) support
-
-The MSS standard is based on the AD1848 codec by Analog Devices.
-Since I don't know how the software configuration of the MSS works
-so it's not supported yet. This driver should work if your card
-has jumpers for the I/O base, IRQ and DMA or there is a way to configure
-them using DOS. You could try this if you have a soundcard with
-AD1848 codec. I have tried to use this with Aztech SG NX Pro 16 without
-success. 
-If you are interested, remove the B(OPT_MSS) from the DISABLED_OPTIONS
-(see above).
-
-3) /dev/sequencer2
+2) /dev/music (/dev/sequencer2)
 
-This version has a new device file called /dev/sequence2. I have not
+This version has a new device file called /dev/music. I have not
 implemented all parts of it but it's there. It's only interesting if
 you are writing a sequencer program yourself. Enable by creating
-the device file /dev/sequencer (minor 8).
+the device file /dev/music. Use the script at the end of linux/Readme
 
-4) /dev/midi##
+3) /dev/midi##
 
 These are tty like raw devices for MIDI ports. Since there is a minor
 incompatibility between different versions of Linux, I have disabled
 this feature by default. You just need to create the device files yourself.
-IMPORTANT!	If you get warning at line 64 of midibuf.c,
-		don't try to use /dev/midi## files. Otherwise your
-		system halts. You may also try to fix the
-		DEFINE_TIMER() macro in os.h (just remove the 2nd NULL).
-		This could happen with some earlier versions of Linux
-		(before 1.1.0???).
 
-5) Support for hardware based u-Law/A-Law and ADPCM formats.
+4) Support for hardware based u-Law/A-Law and ADPCM formats.
 
 The AD1848 (and compatibles) are able to do compression and
 decompression by hardware. This version has experimental support
@@ -95,7 +75,7 @@
 
 
 	2a) If the fragment gets played before the application writes a new
-	one, the device will be stopped and restarted which causes a click.
+	one, the device will be stoppen and restarted which causes a click.
 	When the process calls write next time, it will be processes as 
 	in step 1.
 
@@ -121,13 +101,13 @@
 	the process blocks for at most the time required to play a
 	buffer fragment.
 
-This method synchronizes the process and the audio device together 
-automatically. The process will block at most the 'fragment_time'. Usually 
+This method syncronizes the process and the audio device together 
+automaticly. The process will block at most the 'fragment_time'. Usually 
 less, depending on how much it needs time to do other things. The maximum
 delay between writing a byte and the time when it finally plays is
 at most 3 times the 'fragment_time'. 
 
-The delay depends on how much time the program needs to do its 
+The delay depends on how much time the program needs to do it's 
 computations for the next sample (updating screen etc). If it's about
 80% of the 'fragment_time' the game will run almost without delays. If it 
 uses more time, there is a risk that the audio buffer gets empty.
@@ -142,7 +122,7 @@
 ioctl(NDCTL_DSP_SPEED); /* And #channels & #bits if required */
 
 /*
- * Query the actual fragment size since the driver may refuse
+ * Query the actual fragment sice since the driver may refuse
  * the requested one (unlikely but possible?)
  */
 
@@ -157,4 +137,29 @@
 I have tested this with a modified version of str.c. The algorithm works 
 as long as the playing program gets enough time to run. Hitting ENTER on 
 another virtual console causes a pause/click (with 2 frags of 64 bytes).
+
+NOTE! It's important to know that this call may be called just once and
+it must be done immediately after open(). The fragment size will remain
+in effect until the device is closed.
 ------------------- cut here ---------------------
+
+6)	Detection and initialization code for Ensoniq Soundscape
+
+This version is able to initialize SoundScape (almost). However
+PCM recording and playback don't work. Also MIDI playback sounds wierd
+since the driver is not able to set volume controls properly.
+The soundscape support is disabled. You need to enable it by editing
+beginning of configure.c. Also read comments in sndscape/README.
+
+7)	select() support for /dev/audio and /dev/dsp. (/dev/midi## and
+	/dev/sequencer had it already in v2.90).
+
+There is now select() support in the audio/dsp driver (for Linux only).
+However I have not tried this feature yet. 
+There are also some new ioctl() calls (please look at soundcard.h).
+
+8)	MIDI recording in /dev/music (/dev/sequencer2)
+
+MIDI recording was earlier implemented only with full MPU-401 devices.
+This version has it also for dumb MIDI ports. However I have not tested it
+yet.
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c
--- v1.3.8/linux/drivers/sound/gus_card.c	Fri Jan 20 10:23:41 1995
+++ linux/drivers/sound/gus_card.c	Mon Jul 10 01:45:06 1995
@@ -33,7 +33,7 @@
 
 #include "gus_hw.h"
 
-void            gusintr (int, struct pt_regs * regs);
+void            gusintr (INT_HANDLER_PARMS (irq, dummy));
 
 int             gus_base, gus_irq, gus_dma;
 extern int      gus_wave_volume;
@@ -45,7 +45,7 @@
 {
   int             io_addr;
 
-  snd_set_irq_handler (hw_config->irq, gusintr);
+  snd_set_irq_handler (hw_config->irq, gusintr, "Gravis Ultrasound");
 
   if (gus_wave_detect (hw_config->io_base))	/*
 						 * Try first the default
@@ -118,7 +118,7 @@
 }
 
 void
-gusintr (int irq, struct pt_regs * regs)
+gusintr (INT_HANDLER_PARMS (irq, dummy))
 {
   unsigned char   src;
 
@@ -128,7 +128,7 @@
 
 #ifndef EXCLUDE_GUSMAX
   if (have_gus_max)
-    ad1848_interrupt (irq, regs);
+    ad1848_interrupt (INT_HANDLER_CALL (irq));
 #endif
 
   while (1)
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/gus_midi.c linux/drivers/sound/gus_midi.c
--- v1.3.8/linux/drivers/sound/gus_midi.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/gus_midi.c	Mon Jul 10 01:45:06 1995
@@ -231,6 +231,7 @@
 {
   {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
   &std_midi_synth,
+  {0},
   gus_midi_open,
   gus_midi_close,
   gus_midi_ioctl,
@@ -296,10 +297,12 @@
 	}
     }
 
+#if 0
   if (stat & MIDI_FRAME_ERR)
-    printk ("Midi framing error\n");
+    printk ("GUS: Midi framing error\n");
   if (stat & MIDI_OVERRUN && input_opened)
     printk ("GUS: Midi input overrun\n");
+#endif
 
   RESTORE_INTR (flags);
 }
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c
--- v1.3.8/linux/drivers/sound/gus_wave.c	Tue Jan 17 07:49:57 1995
+++ linux/drivers/sound/gus_wave.c	Mon Jul 10 19:25:31 1995
@@ -33,7 +33,7 @@
 
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
 
-#define MAX_SAMPLE	128
+#define MAX_SAMPLE	150
 #define MAX_PATCH	256
 
 struct voice_info
@@ -76,14 +76,18 @@
 
 extern int      gus_base;
 extern int      gus_irq, gus_dma;
+static int      gusmax_dma = -1;
+static int      dual_dma_mode = 0;
 static long     gus_mem_size = 0;
 static long     free_mem_ptr = 0;
 static int      gus_busy = 0;
+static int      gus_no_dma = 0;
 static int      nr_voices = 0;
 static int      gus_devnum = 0;
 static int      volume_base, volume_scale, volume_method;
 static int      gus_recmask = SOUND_MASK_MIC;
 static int      recording_active = 0;
+static int      only_read_access = 0;
 
 int             gus_wave_volume = 60;
 int             gus_pcm_volume = 80;
@@ -474,10 +478,12 @@
   DISABLE_INTR (flags);
   gus_select_voice (voice);
   gus_voice_volume (0);
+  gus_voice_off ();
   gus_write_addr (0x0a, 0, 0);	/* Set current position to 0 */
   gus_write8 (0x00, 0x03);	/* Voice off */
   gus_write8 (0x0d, 0x03);	/* Ramping off */
   voice_alloc->map[voice] = 0;
+  voice_alloc->alloc_times[voice] = 0;
   RESTORE_INTR (flags);
 
 }
@@ -672,7 +678,7 @@
   unsigned char   dma_image, irq_image, tmp;
 
   static unsigned char gus_irq_map[16] =
-  {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7};
+  {0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7};
 
   static unsigned char gus_dma_map[8] =
   {0, 1, 0, 2, 0, 3, 4, 5};
@@ -716,7 +722,7 @@
 
   OUTB (0x05, gus_base + 0x0f);
 
-  mix_image |= 0x02;		/* Disable line out */
+  mix_image |= 0x02;		/* Disable line out (for a moment) */
   OUTB (mix_image, u_Mixer);
 
   OUTB (0x00, u_IRQDMAControl);
@@ -740,11 +746,35 @@
   irq_image |= tmp;
   irq_image |= 0x40;		/* Combine IRQ1 (GF1) and IRQ2 (Midi) */
 
-  dma_image = 0x40;		/* Combine DMA1 (DRAM) and IRQ2 (ADC) */
-  tmp = gus_dma_map[gus_dma];
-  if (!tmp)
-    printk ("Warning! GUS DMA not selected\n");
-  dma_image |= tmp;
+  dual_dma_mode = 1;
+  if (!have_gus_max || gusmax_dma == gus_dma || gusmax_dma == -1)
+    {
+      dual_dma_mode = 0;
+      dma_image = 0x40;		/* Combine DMA1 (DRAM) and IRQ2 (ADC) */
+
+      tmp = gus_dma_map[gus_dma];
+      if (!tmp)
+	printk ("Warning! GUS DMA not selected\n");
+
+      dma_image |= tmp;
+    }
+  else
+    /* Setup dual DMA channel mode for GUS MAX */
+    {
+      dma_image = gus_dma_map[gus_dma];
+      if (!dma_image)
+	printk ("Warning! GUS DMA not selected\n");
+
+      tmp = gus_dma_map[gusmax_dma] << 3;
+      if (!tmp)
+	{
+	  printk ("Warning! Invalid GUS MAX DMA\n");
+	  tmp = 0x40;		/* Combine DMA channels */
+	  dual_dma_mode = 0;
+	}
+
+      dma_image |= tmp;
+    }
 
   /*
    * For some reason the IRQ and DMA addresses must be written twice
@@ -781,7 +811,7 @@
 
   gus_select_voice (0);		/* This disables writes to IRQ/DMA reg */
 
-  gusintr (0,NULL);		/* Serve pending interrupts */
+  gusintr (INT_HANDLER_CALL (0));	/* Serve pending interrupts */
   RESTORE_INTR (flags);
 }
 
@@ -888,7 +918,7 @@
   if (sample_no < 0)
     {
       printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice);
-      return RET_ERROR (EINVAL);/* Patch not defined */
+      return RET_ERROR (EINVAL);	/* Patch not defined */
     }
 
   if (sample_ptrs[sample_no] == -1)	/* Sample not loaded */
@@ -909,7 +939,7 @@
   unsigned long   flags;
 
   DISABLE_INTR (flags);
-  voice_alloc->map[voice] = 0xffff;
+  /* voice_alloc->map[voice] = 0xffff; */
   if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
     {
       voices[voice].kill_pending = 1;
@@ -921,17 +951,17 @@
       gus_voice_fade (voice);
     }
 
+  RESTORE_INTR (flags);
   return 0;
 }
 
 static void
 guswave_aftertouch (int dev, int voice, int pressure)
 {
+#if 0
   short           lo_limit, hi_limit;
   unsigned long   flags;
 
-  return;			/* Procedure currently disabled */
-
   if (voice < 0 || voice > 31)
     return;
 
@@ -964,6 +994,7 @@
   gus_ramp_rate (3, 8);
   gus_rampon (0x58);		/* Bidirectional, dow, loop */
   RESTORE_INTR (flags);
+#endif /* 0 */
 }
 
 static void
@@ -1020,8 +1051,8 @@
 
   DISABLE_INTR (flags);
   /*
- * CAUTION! Interrupts disabled. Enable them before returning
- */
+     * CAUTION! Interrupts disabled. Enable them before returning
+   */
 
   gus_select_voice (voice);
 
@@ -1230,8 +1261,8 @@
 	  note_freq <= samples[samplep].high_note)
 	sample = samplep;
       else
-	samplep = samples[samplep].key;	/*
-						 * Follow link
+	samplep = samples[samplep].key;		/*
+						   * Follow link
 						 */
     }
   if (sample == -1)
@@ -1336,9 +1367,9 @@
 	}
 
       gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start,
-		      is16bits);/* Loop start location */
+		      is16bits);	/* Loop start location */
       gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end,
-		      is16bits);/* Loop end location */
+		      is16bits);	/* Loop end location */
     }
   else
     {
@@ -1346,9 +1377,9 @@
       voices[voice].loop_irq_mode = LMODE_FINISH;	/* Ramp down at the end */
       voices[voice].loop_irq_parm = 1;
       gus_write_addr (0x02, sample_ptrs[sample],
-		      is16bits);/* Loop start location */
+		      is16bits);	/* Loop start location */
       gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1,
-		      is16bits);/* Loop end location */
+		      is16bits);	/* Loop end location */
     }
   gus_voice_freq (freq);
   gus_voice_balance (pan);
@@ -1378,7 +1409,6 @@
 	voices[voice].volume_pending = volume;
       else
 	{
-	  RESTORE_INTR (flags);
 	  ret_val = guswave_start_note2 (dev, voice, note_num, volume);
 	}
     }
@@ -1387,7 +1417,7 @@
       gus_select_voice (voice);
       mode = gus_read8 (0x00);
       if (mode & 0x20)
-	gus_write8 (0x00, mode & 0xdf);	/* No interrupt! */
+	gus_write8 (0x00, mode & 0xdf);		/* No interrupt! */
 
       voices[voice].offset_pending = 0;
       voices[voice].kill_pending = 0;
@@ -1396,11 +1426,12 @@
 
       if (voices[voice].sample_pending >= 0)
 	{
-	  RESTORE_INTR (flags);
+	  RESTORE_INTR (flags);	/* Run temporarily with interrupts enabled */
 	  guswave_set_instr (voices[voice].dev_pending, voice,
 			     voices[voice].sample_pending);
 	  voices[voice].sample_pending = -1;
 	  DISABLE_INTR (flags);
+	  gus_select_voice (voice);	/* Reselect the voice (just to be sure) */
 	}
 
       if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065))
@@ -1416,11 +1447,11 @@
 
 	  gus_rampoff ();
 	  gus_ramp_range (2000, 4065);
-	  gus_ramp_rate (0, 63);/* Fastest possible rate */
+	  gus_ramp_rate (0, 63);	/* Fastest possible rate */
 	  gus_rampon (0x20 | 0x40);	/* Ramp down, once, irq */
-	  RESTORE_INTR (flags);
 	}
     }
+  RESTORE_INTR (flags);
   return ret_val;
 }
 
@@ -1445,9 +1476,12 @@
     return RET_ERROR (EBUSY);
 
   gus_initialize ();
+  voice_alloc->timestamp = 0;
 
   if ((err = DMAbuf_open_dma (gus_devnum)) < 0)
-    return err;
+    gus_no_dma = 1;		/* Upload samples using PIO */
+  else
+    gus_no_dma = 0;
 
   RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag);
   gus_busy = 1;
@@ -1465,7 +1499,8 @@
   active_device = 0;
   gus_reset ();
 
-  DMAbuf_close_dma (gus_devnum);
+  if (!gus_no_dma)
+    DMAbuf_close_dma (gus_devnum);
 }
 
 static int
@@ -1478,7 +1513,7 @@
 
   unsigned long   blk_size, blk_end, left, src_offs, target;
 
-  sizeof_patch = (long) &patch.data[0] - (long) &patch;	/* Header size */
+  sizeof_patch = (long) &patch.data[0] - (long) &patch;		/* Header size */
 
   if (format != GUS_PATCH)
     {
@@ -1618,85 +1653,85 @@
 	  blk_size = blk_end - target;
 	}
 
-#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA)
-      /*
-       * For some reason the DMA is not possible. We have to use PIO.
-       */
-      {
-	long            i;
-	unsigned char   data;
+      if (gus_no_dma)
+	{
+	  /*
+	   * For some reason the DMA is not possible. We have to use PIO.
+	   */
+	  long            i;
+	  unsigned char   data;
 
-	for (i = 0; i < blk_size; i++)
-	  {
-	    GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
-	    if (patch.mode & WAVE_UNSIGNED)
+	  for (i = 0; i < blk_size; i++)
+	    {
+	      GET_BYTE_FROM_USER (data, addr, sizeof_patch + i);
+	      if (patch.mode & WAVE_UNSIGNED)
 
-	      if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
-		data ^= 0x80;	/* Convert to signed */
-	    gus_poke (target + i, data);
-	  }
-      }
-#else /* GUS_NO_DMA */
-      {
-	unsigned long   address, hold_address;
-	unsigned char   dma_command;
-	unsigned long   flags;
+		if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
+		  data ^= 0x80;	/* Convert to signed */
+	      gus_poke (target + i, data);
+	    }
+	}
+      else
+	{
+	  unsigned long   address, hold_address;
+	  unsigned char   dma_command;
+	  unsigned long   flags;
 
-	/*
-	 * OK, move now. First in and then out.
-	 */
+	  /*
+	   * OK, move now. First in and then out.
+	   */
 
-	COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0],
-			addr, sizeof_patch + src_offs,
-			blk_size);
-
-	DISABLE_INTR (flags);	/******** INTERRUPTS DISABLED NOW ********/
-	gus_write8 (0x41, 0);	/* Disable GF1 DMA */
-	DMAbuf_start_dma (gus_devnum,
-			  audio_devs[gus_devnum]->dmap->raw_buf_phys[0],
-			  blk_size, DMA_MODE_WRITE);
+	  COPY_FROM_USER (audio_devs[gus_devnum]->dmap->raw_buf[0],
+			  addr, sizeof_patch + src_offs,
+			  blk_size);
 
-	/*
-	 * Set the DRAM address for the wave data
-	 */
+	  DISABLE_INTR (flags);
+/******** INTERRUPTS DISABLED NOW ********/
+	  gus_write8 (0x41, 0);	/* Disable GF1 DMA */
+	  DMAbuf_start_dma (gus_devnum,
+			    audio_devs[gus_devnum]->dmap->raw_buf_phys[0],
+			    blk_size, DMA_MODE_WRITE);
 
-	address = target;
+	  /*
+	   * Set the DRAM address for the wave data
+	   */
 
-	if (audio_devs[gus_devnum]->dmachan > 3)
-	  {
-	    hold_address = address;
-	    address = address >> 1;
-	    address &= 0x0001ffffL;
-	    address |= (hold_address & 0x000c0000L);
-	  }
+	  address = target;
 
-	gus_write16 (0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
+	  if (audio_devs[gus_devnum]->dmachan > 3)
+	    {
+	      hold_address = address;
+	      address = address >> 1;
+	      address &= 0x0001ffffL;
+	      address |= (hold_address & 0x000c0000L);
+	    }
 
-	/*
-	 * Start the DMA transfer
-	 */
+	  gus_write16 (0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
 
-	dma_command = 0x21;	/* IRQ enable, DMA start */
-	if (patch.mode & WAVE_UNSIGNED)
-	  dma_command |= 0x80;	/* Invert MSB */
-	if (patch.mode & WAVE_16_BITS)
-	  dma_command |= 0x40;	/* 16 bit _DATA_ */
-	if (audio_devs[gus_devnum]->dmachan > 3)
-	  dma_command |= 0x04;	/* 16 bit DMA _channel_ */
+	  /*
+	   * Start the DMA transfer
+	   */
 
-	gus_write8 (0x41, dma_command);	/* Lets bo luteet (=bugs) */
+	  dma_command = 0x21;	/* IRQ enable, DMA start */
+	  if (patch.mode & WAVE_UNSIGNED)
+	    dma_command |= 0x80;	/* Invert MSB */
+	  if (patch.mode & WAVE_16_BITS)
+	    dma_command |= 0x40;	/* 16 bit _DATA_ */
+	  if (audio_devs[gus_devnum]->dmachan > 3)
+	    dma_command |= 0x04;	/* 16 bit DMA _channel_ */
 
-	/*
-	 * Sleep here until the DRAM DMA done interrupt is served
-	 */
-	active_device = GUS_DEV_WAVE;
+	  gus_write8 (0x41, dma_command);	/* Lets bo luteet (=bugs) */
 
-	DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ);
-	if (TIMED_OUT (dram_sleeper, dram_sleep_flag))
-	  printk ("GUS: DMA Transfer timed out\n");
-	RESTORE_INTR (flags);
-      }
-#endif /* GUS_NO_DMA */
+	  /*
+	   * Sleep here until the DRAM DMA done interrupt is served
+	   */
+	  active_device = GUS_DEV_WAVE;
+
+	  DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ);
+	  if (TIMED_OUT (dram_sleeper, dram_sleep_flag))
+	    printk ("GUS: DMA Transfer timed out\n");
+	  RESTORE_INTR (flags);
+	}
 
       /*
        * Now the next part
@@ -1867,13 +1902,25 @@
 static int
 gus_sampling_set_speed (int speed)
 {
+
   if (speed <= 0)
-    return gus_sampling_speed;
+    speed = gus_sampling_speed;
+
+  if (speed < 4000)
+    speed = 4000;
 
   if (speed > 44100)
     speed = 44100;
 
   gus_sampling_speed = speed;
+
+  if (only_read_access)
+    {
+      /* Compute nearest valid recording speed  and return it */
+
+      speed = (9878400 / (gus_sampling_speed + 2)) / 16;
+      speed = (9878400 / (speed * 16)) - 2;
+    }
   return speed;
 }
 
@@ -1957,8 +2004,6 @@
       return IOCTL_OUT (arg, RET_ERROR (EINVAL));
       break;
 
-    default:
-      return RET_ERROR (EINVAL);
     }
   return RET_ERROR (EINVAL);
 }
@@ -1966,15 +2011,21 @@
 static void
 gus_sampling_reset (int dev)
 {
+  if (recording_active)
+    {
+      gus_write8 (0x49, 0x00);	/* Halt recording */
+      set_input_volumes ();
+    }
 }
 
 static int
 gus_sampling_open (int dev, int mode)
 {
-#ifdef GUS_NO_DMA
-  printk ("GUS: DMA mode not enabled. Device not supported\n");
-  return RET_ERROR (ENXIO);
-#endif
+  if (mode & OPEN_READ && dual_dma_mode)
+    {
+      printk ("GUS: The 8 bit input device is disabled. Use GUS MAX\n");
+      return RET_ERROR (ENOTTY);
+    }
 
   if (gus_busy)
     return RET_ERROR (EBUSY);
@@ -1996,6 +2047,7 @@
       recording_active = 1;
       set_input_volumes ();
     }
+  only_read_access = !(mode & OPEN_WRITE);
 
   return 0;
 }
@@ -2009,7 +2061,10 @@
   active_device = 0;
 
   if (recording_active)
-    set_input_volumes ();
+    {
+      gus_write8 (0x49, 0x00);	/* Halt recording */
+      set_input_volumes ();
+    }
 
   recording_active = 0;
 }
@@ -2020,16 +2075,16 @@
   unsigned long   flags;
   int             voice;
 
-  DISABLE_INTR (flags);
   if (pcm_active && pcm_opened)
     for (voice = 0; voice < gus_sampling_channels; voice++)
       {
+	DISABLE_INTR (flags);
 	gus_select_voice (voice);
 	gus_rampoff ();
 	gus_voice_volume (1530 + (25 * gus_pcm_volume));
 	gus_ramp_range (65, 1530 + (25 * gus_pcm_volume));
+	RESTORE_INTR (flags);
       }
-  RESTORE_INTR (flags);
 }
 
 static void
@@ -2071,7 +2126,7 @@
       if (this_one == (pcm_nblk - 1))	/* Last fragment of the DRAM buffer */
 	{
 	  mode[chn] |= 0x08;	/* Enable loop */
-	  ramp_mode[chn] = 0x03;/* Disable rollover bit */
+	  ramp_mode[chn] = 0x03;	/* Disable rollover bit */
 	}
       else
 	{
@@ -2108,12 +2163,12 @@
 	  gus_write_addr (0x02, chn * pcm_banksize, is16bits);	/* Loop start */
 
 	  if (chn != 0)
-	    gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk),
+	    gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
 			    is16bits);	/* Loop end location */
 	}
 
       if (chn == 0)
-	gus_write_addr (0x04, dram_loc + pcm_datasize[this_one],
+	gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1,
 			is16bits);	/* Loop end location */
       else
 	mode[chn] |= 0x08;	/* Enable looping */
@@ -2126,7 +2181,7 @@
 	  if (chn == 0)
 	    {
 	      mode[chn] &= ~0x08;	/* Disable looping */
-	      mode[chn] |= 0x20;/* Enable IRQ at the end */
+	      mode[chn] |= 0x20;	/* Enable IRQ at the end */
 	      voices[0].loop_irq_mode = LMODE_PCM_STOP;
 	      ramp_mode[chn] = 0x03;	/* No rollover bit */
 	    }
@@ -2231,9 +2286,9 @@
   else
     {
       /*
-	 * Left channel data. The right channel
-	 * is transferred after DMA interrupt
-	 */
+         * Left channel data. The right channel
+         * is transferred after DMA interrupt
+       */
       active_device = GUS_DEV_PCM_CONTINUE;
     }
 
@@ -2360,8 +2415,8 @@
     }
   else
     {
-      int             in_left = useroffs;
-      int             in_right = useroffs + 1;
+      int             in_left = useroffs / 2;
+      int             in_right = useroffs / 2 + 1;
       short          *out_left, *out_right;
       int             i;
 
@@ -2401,6 +2456,23 @@
 };
 
 static void
+guswave_setup_voice (int dev, int voice, int chn)
+{
+  struct channel_info *info =
+  &synth_devs[dev]->chn_info[chn];
+
+  guswave_set_instr (dev, voice, info->pgm_num);
+
+  voices[voice].expression_vol =
+    info->controllers[CTL_EXPRESSION];	/* Just msb */
+  voices[voice].main_vol =
+    (info->controllers[CTL_MAIN_VOLUME] * 100) / 128;
+  voices[voice].panning =
+    (info->controllers[CTL_PAN] * 2) - 128;
+  voices[voice].bender = info->bender_value;
+}
+
+static void
 guswave_bender (int dev, int voice, int value)
 {
   int             freq;
@@ -2524,7 +2596,7 @@
 	if (offs < 0 || offs >= samples[sample].len)
 	  return RET_ERROR (EINVAL);	/* Invalid offset */
 
-	n = samples[sample].len - offs;	/* Num of bytes left */
+	n = samples[sample].len - offs;		/* Num of bytes left */
 
 	if (l > n)
 	  l = n;
@@ -2538,7 +2610,7 @@
 					 */
 
 	offs += sample_ptrs[sample];	/*
-					 * Begin offset + offset to DRAM
+					 * Begin offsess + offset to DRAM
 					 */
 
 	for (n = 0; n < l; n++)
@@ -2567,8 +2639,8 @@
 					 * Invalid offset
 					 */
 
-	n = samples[sample].len - offs;	/*
-						 * Nr of bytes left
+	n = samples[sample].len - offs;		/*
+						   * Nr of bytes left
 						 */
 
 	if (l > n)
@@ -2583,7 +2655,7 @@
 					 */
 
 	offs += sample_ptrs[sample];	/*
-					 * Begin offset + offset to DRAM
+					 * Begin offsess + offset to DRAM
 					 */
 
 	for (n = 0; n < l; n++)
@@ -2603,12 +2675,12 @@
 static int
 guswave_alloc (int dev, int chn, int note, struct voice_alloc_info *alloc)
 {
-  int             i, p;
+  int             i, p, best = -1, best_time = 0x7fffffff;
 
   p = alloc->ptr;
   /*
- * First look for a completely stopped voice
- */
+     * First look for a completely stopped voice
+   */
 
   for (i = 0; i < alloc->max_voice; i++)
     {
@@ -2617,12 +2689,17 @@
 	  alloc->ptr = p;
 	  return p;
 	}
+      if (alloc->alloc_times[p] < best_time)
+	{
+	  best = p;
+	  best_time = alloc->alloc_times[p];
+	}
       p = (p + 1) % alloc->max_voice;
     }
 
   /*
- * Then look for a releasing voice
- */
+     * Then look for a releasing voice
+   */
 
   for (i = 0; i < alloc->max_voice; i++)
     {
@@ -2633,7 +2710,9 @@
 	}
       p = (p + 1) % alloc->max_voice;
     }
-  printk ("GUS: Out of free voices\n");
+
+  if (best >= 0)
+    p = best;
 
   alloc->ptr = p;
   return p;
@@ -2660,7 +2739,8 @@
   guswave_volume_method,
   guswave_patchmgr,
   guswave_bender,
-  guswave_alloc
+  guswave_alloc,
+  guswave_setup_voice
 };
 
 static void
@@ -2669,13 +2749,16 @@
   unsigned long   flags;
   unsigned char   mask = 0xff & ~0x06;	/* Just line out enabled */
 
+  if (have_gus_max)		/* Don't disturb GUS MAX */
+    return;
+
   DISABLE_INTR (flags);
 
   /*
- *    Enable channels having vol > 10%
- *      Note! bit 0x01 means line in DISABLED while 0x04 means
- *            mic in ENABLED.
- */
+   *    Enable channels having vol > 10%
+   *      Note! bit 0x01 means the line in DISABLED while 0x04 means
+   *            the mic in ENABLED.
+   */
   if (gus_line_vol > 10)
     mask &= ~0x01;
   if (gus_mic_vol > 10)
@@ -2684,8 +2767,8 @@
   if (recording_active)
     {
       /*
- *    Disable channel, if not selected for recording
- */
+       *    Disable channel, if not selected for recording
+       */
       if (!(gus_recmask & SOUND_MASK_LINE))
 	mask |= 0x01;
       if (!(gus_recmask & SOUND_MASK_MIC))
@@ -2829,6 +2912,7 @@
 
 static struct mixer_operations gus_mixer_operations =
 {
+  "Gravis Ultrasound",
   gus_default_mixer_ioctl
 };
 
@@ -2841,6 +2925,16 @@
 					 */
     mixer_devs[num_mixers++] = &gus_mixer_operations;
 
+  if (have_gus_max)
+    {
+/*
+ *  Enable all mixer channels on the GF1 side. Otherwise recording will
+ *  not be possible using GUS MAX.
+ */
+      mix_image &= ~0x07;
+      mix_image |= 0x04;	/* All channels enabled */
+      OUTB (mix_image, u_Mixer);
+    }
   return mem_start;
 }
 
@@ -2853,11 +2947,33 @@
   int             gus_type = 0x24;	/* 2.4 */
   int             mixer_type = 0;
 
+  if (irq < 0 || irq > 15)
+    {
+      printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
+      return mem_start;
+    }
+
+  if (dma < 0 || dma > 7)
+    {
+      printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
+      return mem_start;
+    }
+
+  gus_irq = irq;
+  gus_dma = dma;
+#ifdef GUSMAX_DMA
+  if (gusmax_dma == -1)		/* Not already set */
+    gusmax_dma = GUSMAX_DMA;
+#else
+  if (gusmax_dma == -1)
+    gusmax_dma = dma;
+#endif
+
   /*
- * Try to identify the GUS model.
- *
- *	Versions < 3.6 don't have the digital ASIC. Try to probe it first.
- */
+     * Try to identify the GUS model.
+     *
+     *  Versions < 3.6 don't have the digital ASIC. Try to probe it first.
+   */
 
   DISABLE_INTR (flags);
   OUTB (0x20, gus_base + 0x0f);
@@ -2867,9 +2983,9 @@
   if (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.
-	 */
+         * It has the digital ASIC so the card is at least v3.4.
+         * Next try to detect the true model.
+       */
 
       val = INB (u_MixSelect);
 
@@ -2878,9 +2994,7 @@
          * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
          * 10 and above is GUS MAX which has the CS4231 codec/mixer.
          *
-         * Sorry. No GUS max support yet but it should be available
-	 * soon after the SDK for GUS MAX is available.
-	 */
+       */
 
       if (val == 255 || val < 5)
 	{
@@ -2902,8 +3016,11 @@
 	  {
 	    unsigned char   max_config = 0x40;	/* Codec enable */
 
-	    if (dma > 3)
-	      max_config |= 0x30;	/* 16 bit playback and capture DMAs */
+	    if (gus_dma > 3)
+	      max_config |= 0x10;	/* 16 bit capture DMA */
+
+	    if (gusmax_dma > 3)
+	      max_config |= 0x20;	/* 16 bit playback DMA */
 
 	    max_config |= (gus_base >> 4) & 0x0f;	/* Extract the X from 2X0 */
 
@@ -2917,45 +3034,28 @@
 	      have_gus_max = 1;
 	      ad1848_init ("GUS MAX", gus_base + 0x10c,
 			   -irq,
-			   dma,
-			   dma);
+			   gusmax_dma,	/* Playback DMA */
+			   gus_dma);	/* Capture DMA */
 	    }
 	  else
 	    printk ("[Where's the CS4231?]");
+#else
+	  printk ("\n\n\nGUS MAX support was not compiled in!!!\n\n\n\n");
 #endif
 	}
     }
   else
     {
       /*
-	 * ASIC not detected so the card must be 2.2 or 2.4.
-	 * There could still be the 16-bit/mixer daughter card.
-	 * It has the same codec/mixer than MAX.
-	 * At this time there is no support for it but it will appear soon.
-	 */
+         * ASIC not detected so the card must be 2.2 or 2.4.
+         * There could still be the 16-bit/mixer daughter card.
+       */
     }
 
 
   printk (" <Gravis UltraSound %s (%dk)>", model_num, (int) gus_mem_size / 1024);
 
-#ifndef SCO
   sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024);
-#endif
-
-  if (irq < 0 || irq > 15)
-    {
-      printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq);
-      return mem_start;
-    }
-
-  if (dma < 0 || dma > 7)
-    {
-      printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma);
-      return mem_start;
-    }
-
-  gus_irq = irq;
-  gus_dma = dma;
 
   if (num_synths >= MAX_SYNTH_DEV)
     printk ("GUS Error: Too many synthesizers\n");
@@ -2983,8 +3083,8 @@
     printk ("GUS: Too many PCM devices available\n");
 
   /*
- *  Mixer dependent initialization.
- */
+     *  Mixer dependent initialization.
+   */
 
   switch (mixer_type)
     {
@@ -2998,8 +3098,6 @@
     default:
       return gus_default_mixer_init (mem_start);
     }
-
-  return mem_start;
 }
 
 static void
@@ -3018,6 +3116,9 @@
 				 */
   gus_write8 (0x00, tmp);
 
+  if (tmp & 0x03)		/* Voice stopped */
+    voice_alloc->map[voice] = 0;
+
   mode = voices[voice].loop_irq_mode;
   voices[voice].loop_irq_mode = 0;
   parm = voices[voice].loop_irq_parm;
@@ -3029,9 +3130,9 @@
 				 * Final loop finished, shoot volume down
 				 */
 
-      if ((int) (gus_read16 (0x09) >> 4) < 100)	/*
-						 * Get current volume
-						 */
+      if ((int) (gus_read16 (0x09) >> 4) < 100)		/*
+							 * Get current volume
+							 */
 	{
 	  gus_voice_off ();
 	  gus_rampoff ();
@@ -3056,21 +3157,25 @@
 
 	pcm_qlen--;
 	pcm_head = (pcm_head + 1) % pcm_nblk;
-	if (pcm_qlen)
+	if (pcm_qlen && pcm_active)
 	  {
 	    play_next_pcm_block ();
 	  }
 	else
 	  {			/* Underrun. Just stop the voice */
+	    gus_select_voice (0);	/* Left channel */
+	    gus_voice_off ();
+	    gus_rampoff ();
+	    gus_select_voice (1);	/* Right channel */
 	    gus_voice_off ();
 	    gus_rampoff ();
 	    pcm_active = 0;
 	  }
 
-/*
- * If the queue was full before this interrupt, the DMA transfer was
- * suspended. Let it continue now.
- */
+	/*
+	   * If the queue was full before this interrupt, the DMA transfer was
+	   * suspended. Let it continue now.
+	 */
 	if (dma_active)
 	  {
 	    if (pcm_qlen == 0)
@@ -3173,9 +3278,9 @@
 				 * Wave IRQ pending
 				 */
 	if (!(wave_ignore & voice_bit) && (int) voice < nr_voices)	/*
-								 * Not done
-								 * yet
-								 */
+									   * Not done
+									   * yet
+									 */
 	  {
 	    wave_ignore |= voice_bit;
 	    do_loop_irq (voice);
@@ -3185,9 +3290,9 @@
 				 * Volume IRQ pending
 				 */
 	if (!(volume_ignore & voice_bit) && (int) voice < nr_voices)	/*
-								 * Not done
-								 * yet
-								 */
+									   * Not done
+									   * yet
+									 */
 	  {
 	    volume_ignore |= voice_bit;
 	    do_volume_irq (voice);
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/hex2hex.h linux/drivers/sound/hex2hex.h
--- v1.3.8/linux/drivers/sound/hex2hex.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/hex2hex.h	Wed Mar 29 13:30:30 1995
@@ -0,0 +1,97 @@
+/*
+ * This file is a part of configure.c
+ *
+ * hex2hex reads an input file in Intel HEX format and produces
+ * an (unsigned char) array which contains the bytes and writes it to the
+ * output file using C syntax
+ */
+
+#define MAX_SIZE (256*1024)
+#define ABANDON(why) { \
+		fprintf(stderr, "%s: " why "\n", source); \
+		fclose(inf);fclose(outf);return 0; \
+		}
+
+int hex2hex(char *source, char *target, char *varline)
+{
+	FILE *inf, *outf;
+
+	int i,l, c;
+	unsigned char buf[MAX_SIZE];
+
+	if ((inf=fopen(source, "r"))==NULL)
+	{
+		perror(source);
+		return 0;
+	}
+
+	if ((outf=fopen(target, "w"))==NULL)
+	{
+		perror(target);
+		fclose(inf);
+		return 0;
+	}
+
+	l=0;
+
+	while ((c=getc(inf))!=EOF)
+	{
+		if (c == ':')	/* Sync with beginning of line */
+		{
+			int n, check;
+			unsigned char sum;
+			int addr;
+			int linetype;
+
+			if (fscanf(inf, "%02x", &n) != 1)
+			   ABANDON("File format error");
+			sum = n;
+
+			if (fscanf(inf, "%04x", &addr) != 1)
+			   ABANDON("File format error");
+			sum += addr/256;
+			sum += addr%256;
+
+			if (fscanf(inf, "%02x", &linetype) != 1)
+			   ABANDON("File format error");
+			sum += linetype;
+
+			if (linetype != 0)
+			   continue;
+
+			for (i=0;i<n;i++)
+			{
+				if (fscanf(inf, "%02x", &c) != 1)
+			   	   ABANDON("File format error");
+				if (addr >= MAX_SIZE)
+				   ABANDON("File too large");
+				buf[addr++] = c;
+				if (addr > l)
+				   l = addr;
+				sum += c;
+			}
+
+			if (fscanf(inf, "%02x", &check) != 1)
+			   ABANDON("File format error");
+
+			sum = ~sum + 1;
+			if (check != sum)
+			   ABANDON("Line checksum error");
+		}
+	}
+
+	fprintf(outf, "/*\n *\t Computer generated file. Do not edit.\n */\n");
+	fprintf(outf, "%s[] = {\n", varline);
+
+	for (i=0;i<l;i++)
+	{
+		if (i) fprintf(outf, ",");
+		if (i && !(i % 16)) fprintf(outf, "\n");
+		fprintf(outf, "0x%02x", buf[i]);
+	}
+
+	fprintf(outf, "\n};\n\n");
+	fclose(inf);
+	fclose(outf);
+	return 1;
+}
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/ics2101.c linux/drivers/sound/ics2101.c
--- v1.3.8/linux/drivers/sound/ics2101.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/ics2101.c	Mon Jul 10 01:45:08 1995
@@ -30,7 +30,7 @@
 #include "sound_config.h"
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS)
 
-#include <linux/ultrasound.h>
+#include "ultrasound.h"
 #include "gus_hw.h"
 
 #define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
@@ -49,10 +49,10 @@
 {
 #if 1
   /*
- *	Experimental volume scaling by Risto Kankkunen.
- *	This should give smoother volume response than just
- *	a plain multiplication.
- */
+     *  Experimental volume scaling by Risto Kankkunen.
+     *  This should give smoother volume response than just
+     *  a plain multiplication.
+   */
   int             e;
 
   if (vol < 0)
@@ -224,6 +224,7 @@
 
 static struct mixer_operations ics2101_mixer_operations =
 {
+  "ICS2101 Multimedia Mixer",
   ics2101_mixer_ioctl
 };
 
@@ -237,9 +238,9 @@
       mixer_devs[num_mixers++] = &ics2101_mixer_operations;
 
       /*
- * Some GUS v3.7 cards had some channels flipped. Disable
- * the flipping feature if the model id is other than 5.
- */
+         * Some GUS v3.7 cards had some channels flipped. Disable
+         * the flipping feature if the model id is other than 5.
+       */
 
       if (INB (u_MixSelect) != 5)
 	{
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v1.3.8/linux/drivers/sound/mad16.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/mad16.c	Mon Jul 10 01:45:09 1995
@@ -0,0 +1,403 @@
+/*
+ * sound/mad16.c
+ *
+ * Initialization code for OPTi MAD16 compatible audio chips. Including
+ *
+ *      OPTi 82C928     MAD16           (replaced by C929)
+ *      OAK OTI-601D    Mozart
+ *      OPTi 82C929     MAD16 Pro
+ *
+ * These audio interface chips don't prduce sound themselves. They just
+ * connect some other components (OPL-[234] and a WSS compatible codec)
+ * to the PC bus and perform I/O, DMA and IRQ address decoding. There is
+ * also a UART for the MPU-401 mode (not 82C928/Mozart).
+ * The Mozart chip appears to be compatible with the 82C928 (can anybody
+ * confirm this?).
+ *
+ * NOTE! If you want to set CD-ROM address and/or joystick enable, define
+ *       MAD16_CONF in local.h as combination of the following bits:
+ *
+ *      0x01    - joystick disabled
+ *
+ *      CD-ROM type selection (select just one):
+ *      0x02    - Sony 31A
+ *      0x04    - Mitsumi
+ *      0x06    - Panasonic
+ *      0x08    - Secondary IDE
+ *      0x0a    - Primary IDE
+ *      
+ *      For example Mitsumi with joystick disabled = 0x04|0x01 = 0x05
+ *      
+ *      This defaults to CD I/O 0x340, no IRQ and DMA3 
+ *      (DMA5 with Mitsumi or IDE). If you like to change these, define
+ *      MAD16_CDSEL with the following bits:
+ *
+ *      CD-ROM port: 0x00=340, 0x40=330, 0x80=360 or 0xc0=320
+ *      OPL4 select: 0x20=OPL4, 0x00=OPL3
+ *      CD-ROM irq: 0x00=disabled, 0x04=IRQ5, 0x08=IRQ7, 0x0a=IRQ3, 0x10=IRQ9,
+ *                  0x14=IRQ10 and 0x18=IRQ11.
+ *
+ *      CD-ROM DMA (Sony or Panasonic): 0x00=DMA3, 0x01=DMA2, 0x02=DMA1 or 0x03=disabled
+ *   or
+ *      CD-ROM DMA (Mitsumi or IDE):    0x00=DMA5, 0x01=DMA6, 0x02=DMA7 or 0x03=disabled
+ *
+ * Copyright by Hannu Savolainen 1995
+ *
+ * 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.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MAD16)
+
+static int      already_initialized = 0;
+
+#define C928	1
+#define MOZART	2
+#define C929	3
+
+/*
+ *    Registers
+ *
+ *      The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations).
+ *      All ports are inactive by default. They can be activated by
+ *      writing 0xE2 or 0xE3 to the password register. The password is valid
+ *      only until the next I/O read or write.
+ */
+
+#define MC1_PORT	0xf8d
+#define MC2_PORT	0xf8e
+#define MC3_PORT	0xf8f
+#define PASSWD_REG	0xf8f
+#define MC4_PORT	0xf90
+#define MC5_PORT	0xf91
+#define MC6_PORT	0xf92
+#define MC7_PORT	0xf93
+
+static int      board_type = C928;
+
+#ifndef DDB
+#define DDB(x)
+#endif
+
+static unsigned char
+mad_read (int port)
+{
+  unsigned long   flags;
+  unsigned char   tmp;
+
+  DISABLE_INTR (flags);
+
+  switch (board_type)		/* Output password */
+    {
+    case C928:
+    case MOZART:
+      OUTB (0xE2, PASSWD_REG);
+      break;
+
+    case C929:
+      OUTB (0xE3, PASSWD_REG);
+      break;
+    }
+
+  tmp = INB (port);
+  RESTORE_INTR (flags);
+
+  return tmp;
+}
+
+static void
+mad_write (int port, int value)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+
+  switch (board_type)		/* Output password */
+    {
+    case C928:
+    case MOZART:
+      OUTB (0xE2, PASSWD_REG);
+      break;
+
+    case C929:
+      OUTB (0xE3, PASSWD_REG);
+      break;
+    }
+
+  OUTB ((unsigned char) (value & 0xff), port);
+  RESTORE_INTR (flags);
+}
+
+static int
+detect_mad16 (void)
+{
+  unsigned char   tmp, tmp2;
+
+/*
+ * Check that reading a register doesn't return bus float (0xff)
+ * when the card is accessed using password. This may fail in case
+ * the card is in low power mode. Normally at least the power saving mode
+ * bit should be 0.
+ */
+  if ((tmp = mad_read (MC1_PORT)) == 0xff)
+    {
+      DDB (printk ("MC1_PORT returned 0xff\n"));
+      return 0;
+    }
+/*
+ * Now check that the gate is closed on first I/O after writing
+ * the password. (This is how a MAD16 compatible card works).
+ */
+
+  if ((tmp2 = INB (MC1_PORT)) == tmp)	/* It didn't close */
+    {
+      DDB (printk ("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
+      return 0;
+    }
+
+  mad_write (MC1_PORT, tmp ^ 0x80);	/* Togge a bit */
+
+  if ((tmp2 = mad_read (MC1_PORT)) != (tmp ^ 0x80))	/* Compare the bit */
+    {
+      mad_write (MC1_PORT, tmp);	/* Restore */
+      DDB (printk ("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
+      return 0;
+    }
+
+  mad_write (MC1_PORT, tmp);	/* Restore */
+  return 1;			/* Bingo */
+
+}
+
+int
+probe_mad16 (struct address_info *hw_config)
+{
+  int             i;
+  static int      valid_ports[] =
+  {0x530, 0xe80, 0xf40, 0x604};
+  unsigned char   tmp;
+
+  if (already_initialized)
+    return 0;
+
+/*
+ *    Check that all ports return 0xff (bus float) when no password
+ *      is written to the password register.
+ */
+
+  DDB (printk ("--- Detecting MAD16 / Mozart ---\n"));
+
+#if 0
+  for (i = 0xf8d; i <= 0xf93; i++)
+    if (INB (i) != 0xff)
+      {
+	DDB (printk ("port 0x%03x != 0xff (0x%02x)\n", i, INB (i)));
+	return 0;
+      }
+#endif
+
+/*
+ *    Then try to detect with the old password
+ */
+  board_type = C928;
+
+  DDB (printk ("Detect using password = 0xE2\n"));
+
+  if (!detect_mad16 ())		/* No luck. Try different model */
+    {
+      board_type = C929;
+
+      DDB (printk ("Detect using password = 0xE3\n"));
+
+      if (!detect_mad16 ())
+	return 0;
+
+      printk ("mad16.c: A 82C929 detected???\n");
+    }
+  else
+    printk ("mad16.c: A 82C928 or Mozart detected???\n");
+
+  for (i = 0xf8d; i <= 0xf93; i++)
+    DDB (printk ("port %03x = %03x\n", i, mad_read (i)));
+
+/*
+ * Set the WSS address
+ */
+
+  tmp = 0x80;			/* Enable WSS, Disable SB */
+
+  for (i = 0; i < 5; i++)
+    {
+      if (i > 3)		/* Not a valid port */
+	{
+	  printk ("MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
+	  return 0;
+	}
+
+      if (valid_ports[i] == hw_config->io_base)
+	{
+	  tmp |= i << 4;	/* WSS port select bits */
+	  break;
+	}
+    }
+
+/*
+ * Set optional CD-ROM and joystick settings.
+ */
+
+#ifdef MAD16_CONF
+  tmp |= ((MAD16_CONF) & 0x0f);	/* CD-ROM and joystick bits */
+#endif
+  mad_write (MC1_PORT, tmp);
+
+#if defined(MAD16_CONF) && defined(MAD16_CDSEL)
+  tmp = MAD16_CDSEL;
+#else
+  tmp = 0x03;
+#endif
+
+#ifdef MAD16_OPL4
+  tmp |= 0x20;			/* Enable OPL4 access */
+#endif
+
+  mad_write (MC2_PORT, tmp);
+  mad_write (MC3_PORT, 0xf0);	/* Disable SB */
+
+  if (board_type == C929)
+    {
+      mad_write (MC4_PORT, 0xa2);
+      mad_write (MC5_PORT, 0x95);	/* AD184x mode (0x9f for CS42xx) */
+      mad_write (MC6_PORT, 0x03);	/* Disable MPU401 */
+    }
+  else
+    {
+      mad_write (MC4_PORT, 0x02);
+      mad_write (MC5_PORT, 0x10);	/* AD184x mode (0x12 for CS42xx) */
+    }
+
+  for (i = 0xf8d; i <= 0xf93; i++)
+    DDB (printk ("port %03x after init = %03x\n", i, mad_read (i)));
+
+  return probe_ms_sound (hw_config);
+}
+
+long
+attach_mad16 (long mem_start, struct address_info *hw_config)
+{
+
+  already_initialized = 1;
+
+  return attach_ms_sound (mem_start, hw_config);
+}
+
+long
+attach_mad16_mpu (long mem_start, struct address_info *hw_config)
+{
+
+#ifdef EXCLUDE_MIDI
+  return mem_start;
+#else
+  if (!already_initialized)
+    return mem_start;
+
+  return attach_mpu401 (mem_start, hw_config);
+#endif
+}
+
+int
+probe_mad16_mpu (struct address_info *hw_config)
+{
+#ifdef EXCLUDE_MIDI
+  return 0;
+#else
+  static int      mpu_attached = 0;
+  static int      valid_ports[] =
+  {0x330, 0x320, 0x310, 0x300};
+  static short    valid_irqs[] =
+  {9, 10, 5, 7};
+  unsigned char   tmp;
+
+  int             i;		/* A variable with secret power */
+
+  if (!already_initialized)	/* The MSS port must be initialized first */
+    return 0;
+
+  if (mpu_attached)		/* Don't let them call this twice */
+    return 0;
+  mpu_attached = 1;
+
+  if (board_type < C929)	/* Early chip. No MPU support */
+    {
+      printk ("Mozart and OPTi 82C928 based cards don't support MPU401. Sorry\n");
+      return 0;
+    }
+
+  tmp = 0x80;			/* MPU-401 enable */
+
+/*
+ * Set the MPU base bits
+ */
+
+  for (i = 0; i < 5; i++)
+    {
+      if (i > 3)		/* Out of array bounds */
+	{
+	  printk ("MAD16 / Mozart: Invalid MIDI port 0x%x\n", hw_config->io_base);
+	  return 0;
+	}
+
+      if (valid_ports[i] == hw_config->io_base)
+	{
+	  tmp |= i << 5;
+	  break;
+	}
+    }
+
+/*
+ * Set the MPU IRQ bits
+ */
+
+  for (i = 0; i < 5; i++)
+    {
+      if (i > 3)		/* Out of array bounds */
+	{
+	  printk ("MAD16 / Mozart: Invalid MIDI IRQ %d\n", hw_config->irq);
+	  return 0;
+	}
+
+      if (valid_irqs[i] == hw_config->irq)
+	{
+	  tmp |= i << 3;
+	  break;
+	}
+
+      tmp |= 0x03;		/* ???????? */
+      mad_write (MC6_PORT, tmp);	/* Write MPU401 config */
+    }
+
+  return probe_mpu401 (hw_config);
+#endif
+}
+
+/* That's all folks */
+#endif
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/midi_ctrl.h linux/drivers/sound/midi_ctrl.h
--- v1.3.8/linux/drivers/sound/midi_ctrl.h	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/midi_ctrl.h	Fri Mar  3 12:03:07 1995
@@ -1,9 +1,9 @@
 static unsigned char ctrl_def_values[128] =
 {
-	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*   0 to   7 */
-	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*   8 to  15 */
-	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  16 to  23 */
-	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  24 to  31 */
+	0x40,0x40,0x40,0x40,  0x40,0x40,0x40,0x40,	/*   0 to   7 */
+	0x40,0x40,0x40,0x40,  0x40,0x40,0x40,0x40,	/*   8 to  15 */
+	0x40,0x40,0x40,0x40,  0x40,0x40,0x40,0x40,	/*  16 to  23 */
+	0x40,0x40,0x40,0x40,  0x40,0x40,0x40,0x40,	/*  24 to  31 */
 
 	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  32 to  39 */
 	0x00,0x00,0x00,0x00,  0x00,0x00,0x00,0x00,	/*  40 to  47 */
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c
--- v1.3.8/linux/drivers/sound/midi_synth.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/midi_synth.c	Mon Jul 10 01:45:09 1995
@@ -27,6 +27,9 @@
  *
  */
 
+#define USE_SEQ_MACROS
+#define USE_SIMPLE_MACROS
+
 #include "sound_config.h"
 
 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MIDI)
@@ -40,6 +43,61 @@
 static int      midi2synth[MAX_MIDI_DEV];
 static unsigned char prev_out_status[MAX_MIDI_DEV];
 
+#define STORE(cmd) \
+{ \
+  int len; \
+  unsigned char obuf[8]; \
+  cmd; \
+  seq_input_event(obuf, len); \
+}
+#define _seqbuf obuf
+#define _seqbufptr 0
+#define _SEQ_ADVBUF(x) len=x
+
+void
+do_midi_msg (int synthno, unsigned char *msg, int mlen)
+{
+  switch (msg[0] & 0xf0)
+    {
+    case 0x90:
+      if (msg[2] != 0)
+	{
+	  STORE (SEQ_START_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2]));
+	  break;
+	}
+      msg[2] = 64;
+
+    case 0x80:
+      STORE (SEQ_STOP_NOTE (synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xA0:
+      STORE (SEQ_KEY_PRESSURE (synthno, msg[0] & 0x0f, msg[1], msg[2]));
+      break;
+
+    case 0xB0:
+      STORE (SEQ_CONTROL (synthno, msg[0] & 0x0f,
+			  msg[1], msg[2]));
+      break;
+
+    case 0xC0:
+      STORE (SEQ_SET_PATCH (synthno, msg[0] & 0x0f, msg[1]));
+      break;
+
+    case 0xD0:
+      STORE (SEQ_CHN_PRESSURE (synthno, msg[0] & 0x0f, msg[1]));
+      break;
+
+    case 0xE0:
+      STORE (SEQ_BENDER (synthno, msg[0] & 0x0f,
+			 (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7)));
+      break;
+
+    default:
+      /* printk ("MPU: Unknown midi channel message %02x\n", msg[0]); */
+    }
+}
+
 static void
 midi_outc (int midi_dev, int data)
 {
@@ -69,25 +127,118 @@
 static int
 prefix_cmd (int midi_dev, unsigned char status)
 {
-  if (midi_devs[midi_dev]->prefix_cmd == NULL)
+  if ((char *) midi_devs[midi_dev]->prefix_cmd == NULL)
     return 1;
 
   return midi_devs[midi_dev]->prefix_cmd (midi_dev, status);
 }
 
 static void
-midi_synth_input (int dev, unsigned char data)
+midi_synth_input (int orig_dev, unsigned char data)
 {
-  int             orig_dev;
+  int             dev;
+  struct midi_input_info *inc;
+
+  static unsigned char len_tab[] =	/* # of data bytes following a status
+					 */
+  {
+    2,				/* 8x */
+    2,				/* 9x */
+    2,				/* Ax */
+    2,				/* Bx */
+    1,				/* Cx */
+    1,				/* Dx */
+    2,				/* Ex */
+    0				/* Fx */
+  };
 
-  if (dev < 0 || dev > num_synths)
+  if (orig_dev < 0 || orig_dev > num_midis)
     return;
 
   if (data == 0xfe)		/* Ignore active sensing */
     return;
 
-  orig_dev = midi2synth[dev];
+  dev = midi2synth[orig_dev];
+  inc = &midi_devs[orig_dev]->in_info;
 
+  switch (inc->m_state)
+    {
+    case MST_INIT:
+      if (data & 0x80)		/* MIDI status byte */
+	{
+	  if ((data & 0xf0) == 0xf0)	/* Common message */
+	    {
+	      switch (data)
+		{
+		case 0xf0:	/* Sysex */
+		  inc->m_state = MST_SYSEX;
+		  break;	/* Sysex */
+
+		case 0xf1:	/* MTC quarter frame */
+		case 0xf3:	/* Song select */
+		  inc->m_state = MST_DATA;
+		  inc->m_ptr = 1;
+		  inc->m_left = 1;
+		  inc->m_buf[0] = data;
+		  break;
+
+		case 0xf2:	/* Song position pointer */
+		  inc->m_state = MST_DATA;
+		  inc->m_ptr = 1;
+		  inc->m_left = 2;
+		  inc->m_buf[0] = data;
+		  break;
+
+		default:
+		  inc->m_buf[0] = data;
+		  inc->m_ptr = 1;
+		  do_midi_msg (dev, inc->m_buf, inc->m_ptr);
+		  inc->m_ptr = 0;
+		  inc->m_left = 0;
+		}
+	    }
+	  else
+	    {
+	      inc->m_state = MST_DATA;
+	      inc->m_ptr = 1;
+	      inc->m_left = len_tab[(data >> 4) - 8];
+	      inc->m_buf[0] = inc->m_prev_status = data;
+	    }
+	}
+      else if (inc->m_prev_status & 0x80)	/* Ignore if no previous status (yet) */
+	{			/* Data byte (use running status) */
+	  inc->m_state = MST_DATA;
+	  inc->m_ptr = 2;
+	  inc->m_left = len_tab[(data >> 4) - 8] - 1;
+	  inc->m_buf[0] = inc->m_prev_status;
+	  inc->m_buf[1] = data;
+	}
+      break;			/* MST_INIT */
+
+    case MST_DATA:
+      inc->m_buf[inc->m_ptr++] = data;
+      if (--inc->m_left <= 0)
+	{
+	  inc->m_state = MST_INIT;
+	  do_midi_msg (dev, inc->m_buf, inc->m_ptr);
+	  inc->m_ptr = 0;
+	}
+      break;			/* MST_DATA */
+
+    case MST_SYSEX:
+      if (data == 0xf7)		/* Sysex end */
+	{
+	  inc->m_state = MST_INIT;
+	  inc->m_left = 0;
+	  inc->m_ptr = 0;
+	}
+      break;			/* MST_SYSEX */
+
+    default:
+      printk ("MIDI%d: Unexpected state %d (%02x)\n", orig_dev, inc->m_state,
+	      (int) data);
+      inc->m_state = MST_INIT;
+    }
 }
 
 static void
@@ -155,9 +306,9 @@
       if (msg == 0x90)		/*
 				 * Running status = Note on
 				 */
-	midi_outc (orig_dev, 0);/*
-					 * Note on with velocity 0 == note
-					 * off
+	midi_outc (orig_dev, 0);	/*
+					   * Note on with velocity 0 == note
+					   * off
 					 */
       else
 	midi_outc (orig_dev, velocity);
@@ -261,6 +412,8 @@
 {
   int             orig_dev = synth_devs[dev]->midi_dev;
   int             err;
+  unsigned long   flags;
+  struct midi_input_info *inc;
 
   if (orig_dev < 0 || orig_dev > num_midis)
     return RET_ERROR (ENXIO);
@@ -272,6 +425,16 @@
 				  midi_synth_input, midi_synth_output)) < 0)
     return err;
 
+  inc = &midi_devs[orig_dev]->in_info;
+
+  DISABLE_INTR (flags);
+  inc->m_busy = 0;
+  inc->m_state = MST_INIT;
+  inc->m_ptr = 0;
+  inc->m_left = 0;
+  inc->m_prev_status = 0x00;
+  RESTORE_INTR (flags);
+
   return 1;
 }
 
@@ -281,8 +444,8 @@
   int             orig_dev = synth_devs[dev]->midi_dev;
 
   /*
- * Shut up the synths by sending just single active sensing message.
- */
+     * Shut up the synths by sending just single active sensing message.
+   */
   midi_devs[orig_dev]->putc (orig_dev, 0xfe);
 
   midi_devs[orig_dev]->close (orig_dev);
@@ -303,6 +466,7 @@
   int             i;
   unsigned long   left, src_offs, eox_seen = 0;
   int             first_byte = 1;
+  int             hdr_size = (unsigned long) &sysex.data[0] - (unsigned long) &sysex;
 
   if (!prefix_cmd (orig_dev, 0xf0))
     return 0;
@@ -313,20 +477,20 @@
       return RET_ERROR (EINVAL);
     }
 
-  if (count < sizeof (struct sysex_info))
+  if (count < hdr_size)
     {
       printk ("MIDI Error: Patch header too short\n");
       return RET_ERROR (EINVAL);
     }
 
-  count -= sizeof (struct sysex_info);
+  count -= hdr_size;
 
   /*
    * Copy the header from user space but ignore the first bytes which have
    * been transferred already.
    */
 
-  COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, sizeof (struct sysex_info) - offs);
+  COPY_FROM_USER (&((char *) &sysex)[offs], addr, offs, hdr_size - offs);
 
   if (count < sysex.len)
     {
@@ -344,21 +508,20 @@
     {
       unsigned char   data;
 
-      GET_BYTE_FROM_USER (data, addr, sizeof (struct sysex_info) + i);
+      GET_BYTE_FROM_USER (data, addr, hdr_size + i);
 
-      if (first_byte && data != 0xf0)
-	midi_outc (orig_dev, 0xf0);	/* Sysex start */
+      eox_seen = (i > 0 && data & 0x80);	/* End of sysex */
 
-      eox_seen = (data == 0xf7);/*
-					 * Last byte was end of sysex
-					 */
+      if (eox_seen && data != 0xf7)
+	data = 0xf7;
 
       if (i == 0)
 	{
-	  if (data != 0xf0)	/*
-				 * Sysex start
-				 */
-	    return RET_ERROR (EINVAL);
+	  if (data != 0xf0)
+	    {
+	      printk ("Error: Sysex start missing\n");
+	      return RET_ERROR (EINVAL);
+	    }
 	}
 
       while (!midi_devs[orig_dev]->putc (orig_dev, (unsigned char) (data & 0xff)) &&
@@ -406,6 +569,7 @@
     }
   else if (!prefix_cmd (orig_dev, pressure))
     return;
+
   midi_outc (orig_dev, pressure);
 }
 
@@ -458,7 +622,8 @@
   prev_chn = prev_out_status[orig_dev] & 0x0f;
 
   if (msg != 0xd0 || prev_chn != channel)	/*
-						 * * Test for running status  */
+						 * Test for running status
+						 */
     {
       if (!prefix_cmd (orig_dev, 0xe0 | (channel & 0x0f)))
 	return;
@@ -469,6 +634,11 @@
 
   midi_outc (orig_dev, value & 0x7f);
   midi_outc (orig_dev, (value >> 7) & 0x7f);
+}
+
+void
+midi_synth_setup_voice (int dev, int voice, int channel)
+{
 }
 
 #endif
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/midi_synth.h linux/drivers/sound/midi_synth.h
--- v1.3.8/linux/drivers/sound/midi_synth.h	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/midi_synth.h	Fri Mar  3 12:03:07 1995
@@ -14,6 +14,8 @@
 void midi_synth_controller (int dev, int channel, int ctrl_num, int value);
 int midi_synth_patchmgr (int dev, struct patmgr_info *rec);
 void midi_synth_bender (int dev, int chn, int value);
+void midi_synth_setup_voice (int dev, int voice, int chn);
+void do_midi_msg (int synthno, unsigned char *msg, int mlen);
 
 
 #ifndef _MIDI_SYNTH_C_
@@ -40,6 +42,8 @@
   midi_synth_panning,
   NULL,
   midi_synth_patchmgr,
-  midi_synth_bender
+  midi_synth_bender,
+  NULL,	/* alloc_voice */
+  midi_synth_setup_voice
 };
 #endif
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c
--- v1.3.8/linux/drivers/sound/midibuf.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/midibuf.c	Mon Jul 10 01:45:10 1995
@@ -184,8 +184,8 @@
     }
 
   /*
- *    Interrupts disabled. Be careful
- */
+     *    Interrupts disabled. Be careful
+   */
 
   DISABLE_INTR (flags);
   if ((err = midi_devs[dev]->open (dev, mode,
@@ -245,14 +245,14 @@
   DISABLE_INTR (flags);
 
   /*
- * Wait until the queue is empty
- */
+     * Wait until the queue is empty
+   */
 
   if (mode != OPEN_READ)
     {
-      midi_devs[dev]->putc (dev, 0xfe);	/*
-						 * Active sensing to shut the
-						 * devices
+      midi_devs[dev]->putc (dev, 0xfe);		/*
+						   * Active sensing to shut the
+						   * devices
 						 */
 
       while (!PROCESS_ABORTING (midi_sleeper[dev], midi_sleep_flag[dev]) &&
@@ -379,22 +379,32 @@
 
   dev = dev >> 4;
 
-  switch (cmd)
+  if (((cmd >> 8) & 0xff) == 'C')
     {
-
-    case SNDCTL_MIDI_PRETIME:
-      val = IOCTL_IN (arg);
-      if (val < 0)
-	val = 0;
-
-      val = (HZ * val) / 10;
-      parms[dev].prech_timeout = val;
-      return IOCTL_OUT (arg, val);
-      break;
-
-    default:
-      return midi_devs[dev]->ioctl (dev, cmd, arg);
-    }
+      if (midi_devs[dev]->coproc)	/* Coprocessor ioctl */
+	return midi_devs[dev]->coproc->ioctl (midi_devs[dev]->coproc->devc, cmd, arg, 0);
+      else
+	printk ("/dev/midi%d: No coprocessor for this device\n", dev);
+
+      return RET_ERROR (EREMOTEIO);
+    }
+  else
+    switch (cmd)
+      {
+
+      case SNDCTL_MIDI_PRETIME:
+	val = IOCTL_IN (arg);
+	if (val < 0)
+	  val = 0;
+
+	val = (HZ * val) / 10;
+	parms[dev].prech_timeout = val;
+	return IOCTL_OUT (arg, val);
+	break;
+
+      default:
+	return midi_devs[dev]->ioctl (dev, cmd, arg);
+      }
 }
 
 #ifdef ALLOW_SELECT
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/mpu401.c linux/drivers/sound/mpu401.c
--- v1.3.8/linux/drivers/sound/mpu401.c	Mon Mar  6 11:22:09 1995
+++ linux/drivers/sound/mpu401.c	Mon Jul 10 01:45:12 1995
@@ -25,6 +25,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
+ * Modified:
+ *  Riccardo Facchetti  24 Mar 1995
+ *  - Added the Audio Excel DSP 16 initialization routine.
  */
 
 #define USE_SEQ_MACROS
@@ -34,7 +37,8 @@
 
 #ifdef CONFIGURE_SOUNDCARD
 
-#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI)
+#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+#include "coproc.h"
 
 static int      init_sequence[20];	/* NOTE! pos 0 = len, start pos 1. */
 static int      timer_mode = TMR_INTERNAL, timer_caps = TMR_INTERNAL;
@@ -75,7 +79,7 @@
     int             m_left;
     unsigned char   last_status;
     void            (*inputintr) (int dev, unsigned char data);
-    unsigned short  controls[32];
+    int             shared_irq;
   };
 
 #define	DATAPORT(base)   (base)
@@ -101,7 +105,9 @@
   {0}};
 
 static int      n_mpu_devs = 0;
-static int      irq2dev[16];
+static int      irq2dev[16] =
+{-1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1};
 
 static int      reset_mpu401 (struct mpu_config *devc);
 static void     set_uart_mode (int dev, struct mpu_config *devc, int arg);
@@ -128,7 +134,7 @@
 #define ST_SONGSEL		103	/* Song select */
 #define ST_SONGPOS		104	/* Song position pointer */
 
-static unsigned char len_tab[] =/* # of data bytes following a status
+static unsigned char len_tab[] =	/* # of data bytes following a status
 					 */
 {
   2,				/* 8x */
@@ -142,7 +148,6 @@
 };
 
 #define STORE(cmd) \
-if (devc->opened & OPEN_READ) \
 { \
   int len; \
   unsigned char obuf[8]; \
@@ -153,73 +158,10 @@
 #define _seqbufptr 0
 #define _SEQ_ADVBUF(x) len=x
 
-static void
-do_midi_msg (struct mpu_config *devc, unsigned char *msg, int mlen)
-{
-  switch (msg[0] & 0xf0)
-    {
-    case 0x90:
-      if (msg[2] != 0)
-	{
-	  STORE (SEQ_START_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
-	  break;
-	}
-      msg[2] = 64;
-
-    case 0x80:
-      STORE (SEQ_STOP_NOTE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
-      break;
-
-    case 0xA0:
-      STORE (SEQ_KEY_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
-      break;
-
-    case 0xB0:
-      /*
- * Fix the controller value (combine MSB and LSB)
- */
-      if (msg[1] < 64)
-	{
-	  int             ctrl = msg[1];
-
-	  if (ctrl < 32)
-	    {
-	      devc->controls[ctrl] = (msg[2] & 0x7f) << 7;
-	    }
-	  else
-	    {
-	      ctrl -= 32;
-	      devc->controls[ctrl] =
-		(devc->controls[ctrl] & ~0x7f) | (msg[2] & 0x7f);
-	    }
-	  STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f,
-			      msg[1], devc->controls[ctrl]));
-	}
-      else
-	STORE (SEQ_CONTROL (devc->synthno, msg[0] & 0x0f, msg[1], msg[2]));
-      break;
-
-    case 0xC0:
-      STORE (SEQ_SET_PATCH (devc->synthno, msg[0] & 0x0f, msg[1]));
-      break;
-
-    case 0xD0:
-      STORE (SEQ_CHN_PRESSURE (devc->synthno, msg[0] & 0x0f, msg[1]));
-      break;
-
-    case 0xE0:
-      STORE (SEQ_BENDER (devc->synthno, msg[0] & 0x0f,
-			 (msg[1] % 0x7f) | ((msg[2] & 0x7f) << 7)));
-      break;
-
-    default:
-      printk ("MPU: Unknown midi channel message %02x\n", msg[0]);
-    }
-}
-
 static int
 mpu_input_scanner (struct mpu_config *devc, unsigned char midic)
 {
+
   switch (devc->m_state)
     {
     case ST_INIT:
@@ -277,6 +219,7 @@
 	int             msg = (midic & 0xf0) >> 4;
 
 	devc->m_state = ST_DATABYTE;
+
 	if (msg < 8)		/* Data byte */
 	  {
 	    /* printk("midi msg (running status) "); */
@@ -291,7 +234,7 @@
 	    if (devc->m_left <= 0)
 	      {
 		devc->m_state = ST_INIT;
-		do_midi_msg (devc, devc->m_buf, devc->m_ptr);
+		do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr);
 		devc->m_ptr = 0;
 	      }
 	  }
@@ -320,7 +263,7 @@
 	else
 	  {
 	    devc->last_status = midic;
-	    /* printk("midi msg "); */
+	    /* printk ("midi msg "); */
 	    msg -= 8;
 	    devc->m_left = len_tab[msg];
 
@@ -330,7 +273,7 @@
 	    if (devc->m_left <= 0)
 	      {
 		devc->m_state = ST_INIT;
-		do_midi_msg (devc, devc->m_buf, devc->m_ptr);
+		do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr);
 		devc->m_ptr = 0;
 	      }
 	  }
@@ -363,8 +306,8 @@
 	  devc->m_state = ST_INIT;
 
 	  /*
- *    Real time messages
- */
+	     *    Real time messages
+	   */
 	case 0xf8:
 	  /* midi clock */
 	  devc->m_state = ST_INIT;
@@ -436,7 +379,7 @@
       if ((--devc->m_left) <= 0)
 	{
 	  devc->m_state = ST_INIT;
-	  do_midi_msg (devc, devc->m_buf, devc->m_ptr);
+	  do_midi_msg (devc->synthno, devc->m_buf, devc->m_ptr);
 	  devc->m_ptr = 0;
 	}
       break;
@@ -454,16 +397,19 @@
 {
   unsigned long   flags;
   int             busy;
+  int             n;
 
   DISABLE_INTR (flags);
   busy = devc->m_busy;
   devc->m_busy = 1;
   RESTORE_INTR (flags);
 
-  if (busy)
+  if (busy)			/* Already inside the scanner */
     return;
 
-  while (input_avail (devc->base))
+  n = 50;
+
+  while (input_avail (devc->base) && n-- > 0)
     {
       unsigned char   c = read_data (devc->base);
 
@@ -479,7 +425,7 @@
 }
 
 void
-mpuintr (int irq, struct pt_regs * regs)
+mpuintr (INT_HANDLER_PARMS (irq, dummy))
 {
   struct mpu_config *devc;
   int             dev;
@@ -497,15 +443,20 @@
   dev = irq2dev[irq];
   if (dev == -1)
     {
-      printk ("MPU-401: Interrupt #%d?\n", irq);
+      /* printk ("MPU-401: Interrupt #%d?\n", irq); */
       return;
     }
 
   devc = &dev_conf[dev];
 
-  if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
-    if (input_avail (devc->base))
+  if (input_avail (devc->base))
+    if (devc->base != 0 && (devc->opened & OPEN_READ || devc->mode == MODE_SYNTH))
       mpu401_input_loop (devc);
+    else
+      {
+	/* Dummy read (just to acknowledge the interrupt) */
+	read_data (devc->base);
+      }
 
 }
 
@@ -529,9 +480,40 @@
       return RET_ERROR (EBUSY);
     }
 
+  /*
+     *  Verify that the device is really running.
+     *  Some devices (such as Ensoniq SoundScape don't
+     *  work before the on board processor (OBP) is initialized
+     *  by downloadin it's microcode.
+   */
+
+  if (!devc->initialized)
+    {
+      if (mpu401_status (devc->base) == 0xff)	/* Bus float */
+	{
+	  printk ("MPU-401: Device not initialized properly\n");
+	  return RET_ERROR (EIO);
+	}
+      reset_mpu401 (devc);
+    }
+
   irq2dev[devc->irq] = dev;
-  if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0))
-    return err;
+  if (devc->shared_irq == 0)
+    if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[dev]->info.name) < 0))
+      {
+	return err;
+      }
+
+  if (midi_devs[dev]->coproc)
+    if ((err = midi_devs[dev]->coproc->
+	 open (midi_devs[dev]->coproc->devc, COPR_MIDI)) < 0)
+      {
+	if (devc->shared_irq == 0)
+	  snd_release_irq (devc->irq);
+	printk ("MPU-401: Can't access coprocessor device\n");
+
+	return err;
+      }
 
   set_uart_mode (dev, devc, 1);
   devc->mode = MODE_MIDI;
@@ -558,9 +540,12 @@
 				 */
   devc->mode = 0;
 
-  snd_release_irq (devc->irq);
+  if (devc->shared_irq == 0)
+    snd_release_irq (devc->irq);
   devc->inputintr = NULL;
-  irq2dev[devc->irq] = -1;
+
+  if (midi_devs[dev]->coproc)
+    midi_devs[dev]->coproc->close (midi_devs[dev]->coproc->devc, COPR_MIDI);
   devc->opened = 0;
 }
 
@@ -580,16 +565,16 @@
    */
 
   if (input_avail (devc->base))
-    mpu401_input_loop (devc);
+    {
+      mpu401_input_loop (devc);
+    }
 #endif
   /*
    * Sometimes it takes about 13000 loops before the output becomes ready
    * (After reset). Normally it takes just about 10 loops.
    */
 
-  for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--);	/*
-										 * Wait
-										 */
+  for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--);
 
   DISABLE_INTR (flags);
   if (!output_ready (devc->base))
@@ -633,34 +618,42 @@
    * (After reset). Normally it takes just about 10 loops.
    */
 
-  for (timeout = 500000; timeout > 0 && !output_ready (devc->base); timeout--);
+  timeout = 30000;
+retry:
+  if (timeout-- <= 0)
+    {
+      printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
+      return RET_ERROR (EIO);
+    }
 
   DISABLE_INTR (flags);
+
   if (!output_ready (devc->base))
     {
-      printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd);
       RESTORE_INTR (flags);
-      return RET_ERROR (EIO);
+      goto retry;
     }
 
   write_command (devc->base, cmd->cmd);
   ok = 0;
-  for (timeout = 500000; timeout > 0 && !ok; timeout--)
+  for (timeout = 50000; timeout > 0 && !ok; timeout--)
     if (input_avail (devc->base))
-      if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK)
-	ok = 1;
+      {
+	if (mpu_input_scanner (devc, read_data (devc->base)) == MPU_ACK)
+	  ok = 1;
+      }
 
   if (!ok)
     {
       RESTORE_INTR (flags);
-      printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd);
+      /*       printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */
       return RET_ERROR (EIO);
     }
 
   if (cmd->nr_args)
     for (i = 0; i < cmd->nr_args; i++)
       {
-	for (timeout = 30000; timeout > 0 && !output_ready (devc->base); timeout--);
+	for (timeout = 3000; timeout > 0 && !output_ready (devc->base); timeout--);
 
 	if (!mpu401_out (dev, cmd->data[i]))
 	  {
@@ -687,7 +680,7 @@
 	if (!ok)
 	  {
 	    RESTORE_INTR (flags);
-	    printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd);
+	    /* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */
 	    return RET_ERROR (EIO);
 	  }
       }
@@ -857,31 +850,64 @@
   midi_dev = synth_devs[dev]->midi_dev;
 
   if (midi_dev < 0 || midi_dev > num_midis)
-    return RET_ERROR (ENXIO);
+    {
+      return RET_ERROR (ENXIO);
+    }
 
   devc = &dev_conf[midi_dev];
 
+  /*
+     *  Verify that the device is really running.
+     *  Some devices (such as Ensoniq SoundScape don't
+     *  work before the on board processor (OBP) is initialized
+     *  by downloadin it's microcode.
+   */
+
+  if (!devc->initialized)
+    {
+      if (mpu401_status (devc->base) == 0xff)	/* Bus float */
+	{
+	  printk ("MPU-401: Device not initialized properly\n");
+	  return RET_ERROR (EIO);
+	}
+      reset_mpu401 (devc);
+    }
+
   if (devc->opened)
     {
       printk ("MPU-401: Midi busy\n");
       return RET_ERROR (EBUSY);
     }
 
-  devc->opened = mode;
   devc->mode = MODE_SYNTH;
   devc->synthno = dev;
 
   devc->inputintr = NULL;
   irq2dev[devc->irq] = midi_dev;
-  if ((err = snd_set_irq_handler (devc->irq, mpuintr) < 0))
-    return err;
+  if (devc->shared_irq == 0)
+    if ((err = snd_set_irq_handler (devc->irq, mpuintr, midi_devs[midi_dev]->info.name) < 0))
+      {
+	return err;
+      }
+
+  if (midi_devs[midi_dev]->coproc)
+    if ((err = midi_devs[midi_dev]->coproc->
+	 open (midi_devs[midi_dev]->coproc->devc, COPR_MIDI)) < 0)
+      {
+	if (devc->shared_irq == 0)
+	  snd_release_irq (devc->irq);
+	printk ("MPU-401: Can't access coprocessor device\n");
 
+	return err;
+      }
+
+  devc->opened = mode;
   reset_mpu401 (devc);
 
   if (mode & OPEN_READ)
     {
-      exec_cmd (midi_dev, 0x34, 0);	/* Return timing bytes in stop mode */
       exec_cmd (midi_dev, 0x8B, 0);	/* Enable data in stop mode */
+      exec_cmd (midi_dev, 0x34, 0);	/* Return timing bytes in stop mode */
     }
 
   return 0;
@@ -899,11 +925,14 @@
   exec_cmd (midi_dev, 0x15, 0);	/* Stop recording, playback and MIDI */
   exec_cmd (midi_dev, 0x8a, 0);	/* Disable data in stopped mode */
 
+  if (devc->shared_irq == 0)
+    snd_release_irq (devc->irq);
+  devc->inputintr = NULL;
+
+  if (midi_devs[midi_dev]->coproc)
+    midi_devs[midi_dev]->coproc->close (midi_devs[midi_dev]->coproc->devc, COPR_MIDI);
   devc->opened = 0;
   devc->mode = 0;
-  snd_release_irq (devc->irq);
-  devc->inputintr = NULL;
-  irq2dev[devc->irq] = -1;
 }
 
 #define MIDI_SYNTH_NAME	"MPU-401 UART Midi"
@@ -930,7 +959,9 @@
   midi_synth_panning,
   NULL,
   midi_synth_patchmgr,
-  midi_synth_bender
+  midi_synth_bender,
+  NULL,				/* alloc */
+  midi_synth_setup_voice
 };
 
 static struct synth_operations mpu401_synth_operations[MAX_MIDI_DEV];
@@ -939,6 +970,7 @@
 {
   {"MPU-401 Midi", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
   NULL,
+  {0},
   mpu401_open,
   mpu401_close,
   mpu401_ioctl,
@@ -962,25 +994,28 @@
 
   if ((tmp = exec_cmd (num_midis, 0xAC, 0)) < 0)
     return;
+
+  if ((tmp & 0xf0) > 0x20)	/* Why it's larger than 2.x ??? */
+    return;
+
   devc->version = tmp;
 
   if ((tmp = exec_cmd (num_midis, 0xAD, 0)) < 0)
-    return;
+    {
+      devc->version = 0;
+      return;
+    }
   devc->revision = tmp;
 }
 
 long
 attach_mpu401 (long mem_start, struct address_info *hw_config)
 {
-  int             i;
   unsigned long   flags;
   char            revision_char;
 
   struct mpu_config *devc;
 
-  for (i = 0; i < 16; i++)
-    irq2dev[i] = -1;
-
   if (num_midis >= MAX_MIDI_DEV)
     {
       printk ("MPU-401: Too many midi devices detected\n");
@@ -1000,18 +1035,20 @@
   devc->timer_flag = 0;
   devc->m_busy = 0;
   devc->m_state = ST_INIT;
+  devc->shared_irq = hw_config->always_detect;
 
-  for (i = 0; i < 32; i++)
-    devc->controls[i] = 0x2000;
-
-  if (!reset_mpu401 (devc))
-    return mem_start;
+  if (!hw_config->always_detect)
+    {
+      /* Verify the hardware again */
+      if (!reset_mpu401 (devc))
+	return mem_start;
 
-  DISABLE_INTR (flags);
-  mpu401_chk_version (devc);
-  if (devc->version == 0)
-    mpu401_chk_version (devc);
-  RESTORE_INTR (flags);
+      DISABLE_INTR (flags);
+      mpu401_chk_version (devc);
+      if (devc->version == 0)
+	mpu401_chk_version (devc);
+      RESTORE_INTR (flags);
+    }
 
   if (devc->version == 0)
     {
@@ -1051,13 +1088,11 @@
       printk (" <MQX-%d%c MIDI Interface>",
 	      ports,
 	      revision_char);
-#ifndef SCO
       sprintf (mpu_synth_info[num_midis].name,
 	       "MQX-%d%c MIDI Interface #%d",
 	       ports,
 	       revision_char,
 	       n_mpu_devs);
-#endif
     }
   else
     {
@@ -1072,20 +1107,16 @@
 	      (devc->version & 0xf0) >> 4,
 	      devc->version & 0x0f,
 	      revision_char);
-#ifndef SCO
       sprintf (mpu_synth_info[num_midis].name,
 	       "MPU-401 %d.%d%c Midi interface #%d",
 	       (devc->version & 0xf0) >> 4,
 	       devc->version & 0x0f,
 	       revision_char,
 	       n_mpu_devs);
-#endif
     }
 
-#ifndef SCO
   strcpy (mpu401_midi_operations[num_midis].info.name,
 	  mpu_synth_info[num_midis].name);
-#endif
 
   mpu401_synth_operations[num_midis].midi_dev = devc->devno = num_midis;
   mpu401_synth_operations[devc->devno].info =
@@ -1094,6 +1125,7 @@
   if (devc->capabilities & MPU_CAP_INTLG)	/* Has timer */
     mpu_timer_init (num_midis);
 
+  irq2dev[devc->irq] = num_midis;
   midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno];
   return mem_start;
 }
@@ -1154,10 +1186,14 @@
 {
 
   if (!arg && devc->version == 0)
-    return;
+    {
+      return;
+    }
 
   if ((devc->uart_mode == 0) == (arg == 0))
-    return;			/* Already set */
+    {
+      return;			/* Already set */
+    }
 
   reset_mpu401 (devc);		/* This exits the uart mode */
 
@@ -1184,6 +1220,19 @@
   tmp_devc.irq = hw_config->irq;
   tmp_devc.initialized = 0;
 
+#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_MPU401)
+  /*
+     * Initialize Audio Excel DSP 16 to MPU-401, before any operation.
+   */
+  InitAEDSP16_MPU401 (hw_config);
+#endif
+
+  if (hw_config->always_detect)
+    return 1;
+
+  if (INB (hw_config->io_base + 1) == 0xff)
+    return 0;			/* Just bus float? */
+
   ok = reset_mpu401 (&tmp_devc);
 
   return ok;
@@ -1207,11 +1256,11 @@
 clocks2ticks (unsigned long clocks)
 {
   /*
- * The MPU-401 supports just a limited set of possible timebase values.
- * Since the applications require more choices, the driver has to
- * program the HW to do its best and to convert between the HW and
- * actual timebases.
- */
+     * The MPU-401 supports just a limited set of possible timebase values.
+     * Since the applications require more choices, the driver has to
+     * program the HW to do it's best and to convert between the HW and
+     * actual timebases.
+   */
 
   return ((clocks * curr_timebase) + (hw_timebase / 2)) / hw_timebase;
 }
@@ -1269,8 +1318,8 @@
     {
       if (timer_mode & (TMR_MODE_MIDI | TMR_MODE_CLS))
 	{
-	  exec_cmd (midi_dev, 0x82, 0);	/* Use MIDI sync */
-	  exec_cmd (midi_dev, 0x91, 0);	/* Enable ext MIDI ctrl */
+	  exec_cmd (midi_dev, 0x82, 0);		/* Use MIDI sync */
+	  exec_cmd (midi_dev, 0x91, 0);		/* Enable ext MIDI ctrl */
 	}
       else if (timer_mode & TMR_MODE_FSK)
 	exec_cmd (midi_dev, 0x81, 0);	/* Use FSK sync */
@@ -1481,8 +1530,6 @@
       break;
 
     case SNDCTL_TMR_START:
-      if (tmr_running)
-	return 0;
       start_timer (midi_dev);
       return 0;
       break;
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/opl3.c linux/drivers/sound/opl3.c
--- v1.3.8/linux/drivers/sound/opl3.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/opl3.c	Mon Jul 10 01:45:13 1995
@@ -46,6 +46,7 @@
 				   * * OP4 * * begin here   */
 
 static int      opl3_enabled = 0;
+static int      opl4_enabled = 0;
 static int      left_address = 0x388, right_address = 0x388, both_address = 0;
 
 static int      nr_voices = 9;
@@ -189,7 +190,7 @@
    * Note2! The chip is initialized if detected.
    */
 
-  unsigned char   stat1, stat2;
+  unsigned char   stat1, stat2, signature;
   int             i;
 
   if (already_initialized)
@@ -202,22 +203,13 @@
   if (opl3_enabled)
     ioaddr = left_address;
 
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);	/*
-										 * Reset
-										 * timers
-										 * 1
-										 * and
-										 * 2
-										 */
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);	/*
-								 * Reset the
-								 * IRQ of FM
-								 * * chicp
-								 */
+  /* Reset timers 1 and 2 */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
 
-  stat1 = INB (ioaddr);		/*
-				 * Read status register
-				 */
+  /* Reset the IRQ of the FM chip */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
+
+  signature = stat1 = INB (ioaddr);	/* Status register */
 
   if ((stat1 & 0xE0) != 0x00)
     {
@@ -226,23 +218,19 @@
 				 */
     }
 
-  opl3_command (ioaddr, TIMER1_REGISTER, 0xff);	/*
-							 * Set timer 1 to
-							 * 0xff
-							 */
+  opl3_command (ioaddr, TIMER1_REGISTER, 0xff);		/* Set timer1 to 0xff */
+
   opl3_command (ioaddr, TIMER_CONTROL_REGISTER,
 		TIMER2_MASK | TIMER1_START);	/*
 						 * Unmask and start timer 1
 						 */
 
   /*
-   * Now we have to delay at least 80 msec
+   * Now we have to delay at least 80 usec
    */
 
   for (i = 0; i < 50; i++)
-    tenmicrosec ();		/*
-				 * To be sure
-				 */
+    tenmicrosec ();
 
   stat2 = INB (ioaddr);		/*
 				 * Read status after timers have expired
@@ -252,18 +240,10 @@
    * Stop the timers
    */
 
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);	/*
-										 * Reset
-										 * timers
-										 * 1
-										 * and
-										 * 2
-										 */
-  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);	/*
-								 * Reset the
-								 * IRQ of FM
-								 * * chicp
-								 */
+  /* Reset timers 1 and 2 */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK);
+  /* Reset the IRQ of the FM chip */
+  opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET);
 
   if ((stat2 & 0xE0) != 0xc0)
     {
@@ -273,9 +253,41 @@
     }
 
   /*
-   * There is a FM chicp in this address. Now set some default values.
+   * There is a FM chicp in this address. Detect the type (OPL2 to OPL4)
    */
 
+  if (signature == 0x06)	/* OPL2 */
+    {
+      opl3_enabled = 0;
+    }
+  else if (signature == 0x00)	/* OPL3 or OPL4 */
+    {
+      unsigned char   tmp;
+
+      if (!opl3_enabled)	/* Was not already enabled */
+	{
+	  left_address = ioaddr;
+	  right_address = ioaddr + 2;
+	  opl3_enabled = 1;
+	}
+
+      /*
+       * Detect availability of OPL4 (_experimental_). Works propably
+       * only after a cold boot. In addition the OPL4 port
+       * of the chip may not be connected to the PC bus at all.
+       */
+
+      opl3_command (right_address, OPL3_MODE_REGISTER, 0x00);
+      opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE | OPL4_ENABLE);
+
+      if ((tmp = INB (ioaddr)) == 0x02)		/* Have a OPL4 */
+	{
+	  opl4_enabled = 1;
+	}
+      opl3_command (right_address, OPL3_MODE_REGISTER, 0);
+
+    }
+
   for (i = 0; i < 9; i++)
     opl3_command (ioaddr, KEYON_BLOCK + i, 0);	/*
 						 * Note off
@@ -374,14 +386,14 @@
  -11, -11, -10, -10, -10, -9, -9, -8,	/*
 					 * 24 -  31
 					 */
- -8, -8, -7, -7, -7, -6, -6, -6,/*
-					 * 32 -  39
+ -8, -8, -7, -7, -7, -6, -6, -6,	/*
+					   * 32 -  39
 					 */
- -5, -5, -5, -5, -4, -4, -4, -4,/*
-					 * 40 -  47
+ -5, -5, -5, -5, -4, -4, -4, -4,	/*
+					   * 40 -  47
 					 */
- -3, -3, -3, -3, -2, -2, -2, -2,/*
-					 * 48 -  55
+ -3, -3, -3, -3, -2, -2, -2, -2,	/*
+					   * 48 -  55
 					 */
  -2, -1, -1, -1, -1, 0, 0, 0,	/*
 				 * 56 -  63
@@ -473,13 +485,13 @@
 	  calc_vol (&vol2, volume);
 	}
 
-      opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);	/*
-									 * Modulator
-									 * volume
+      opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);		/*
+									   * Modulator
+									   * volume
 									 */
-      opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2);	/*
-									 * Carrier
-									 * volume
+      opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2);		/*
+									   * Carrier
+									   * volume
 									 */
     }
   else
@@ -526,7 +538,7 @@
 
 	default:		/*
 				 * Why ??
-	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  	  				 */ ;
+				 */ ;
 	}
 
       opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1);
@@ -858,12 +870,23 @@
 static int
 opl3_open (int dev, int mode)
 {
+  int             i;
+
   if (!opl3_ok)
     return RET_ERROR (ENXIO);
   if (opl3_busy)
     return RET_ERROR (EBUSY);
   opl3_busy = 1;
 
+  voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
+  voice_alloc->timestamp = 0;
+
+  for (i = 0; i < 18; i++)
+    {
+      voice_alloc->map[i] = 0;
+      voice_alloc->alloc_times[i] = 0;
+    }
+
   connection_mask = 0x00;	/*
 				 * Just 2 OP voices
 				 */
@@ -877,6 +900,7 @@
 {
   opl3_busy = 0;
   voice_alloc->max_voice = nr_voices = opl3_enabled ? 18 : 9;
+
   fm_info.nr_drums = 0;
   fm_info.perc_mode = 0;
 
@@ -1076,7 +1100,7 @@
 static int
 opl3_alloc_voice (int dev, int chn, int note, struct voice_alloc_info *alloc)
 {
-  int             i, p, avail_voices;
+  int             i, p, best, first, avail_voices, best_time = 0x7fffffff;
   struct sbi_instrument *instr;
   int             is4op;
   int             instr_no;
@@ -1097,21 +1121,22 @@
 
   if (is4op)
     {
-      p = 0;
+      first = p = 0;
       avail_voices = 6;
     }
   else
     {
       if (nr_voices == 12)	/* 4 OP mode. Use the '2 OP only' voices first */
-	p = 6;
+	first = p = 6;
       else
-	p = 0;
+	first = p = 0;
       avail_voices = nr_voices;
     }
 
   /*
- *    Now try to find a free voice
- */
+     *    Now try to find a free voice
+   */
+  best = first;
 
   for (i = 0; i < avail_voices; i++)
     {
@@ -1119,15 +1144,36 @@
 	{
 	  return p;
 	}
-      p = (p + 1) % nr_voices;
+      if (alloc->alloc_times[p] < best_time)	/* Find oldest playing note */
+	{
+	  best_time = alloc->alloc_times[p];
+	  best = p;
+	}
+      p = (p + 1) % avail_voices;
     }
 
   /*
- *    Insert some kind of priority mechanism here.
- */
+     *    Insert some kind of priority mechanism here.
+   */
+
+  if (best < 0)
+    best = 0;
+  if (best > nr_voices)
+    best -= nr_voices;
 
-  printk ("OPL3: Out of free voices\n");
-  return 0;			/* All voices in use. Select the first one. */
+  return best;			/* All voices in use. Select the first one. */
+}
+
+static void
+opl3_setup_voice (int dev, int voice, int chn)
+{
+  struct channel_info *info =
+  &synth_devs[dev]->chn_info[chn];
+
+  opl3_set_instr (dev, voice,
+		  info->pgm_num);
+
+  voices[voice].bender = info->bender_value;
 }
 
 static struct synth_operations opl3_operations =
@@ -1151,7 +1197,8 @@
   opl3_volume_method,
   opl3_patchmgr,
   opl3_bender,
-  opl3_alloc_voice
+  opl3_alloc_voice,
+  opl3_setup_voice
 };
 
 long
@@ -1175,14 +1222,16 @@
   opl3_ok = 1;
   if (opl3_enabled)
     {
-      printk (" <Yamaha OPL-3 FM>");
+      if (opl4_enabled)
+	printk (" <Yamaha OPL4/OPL3 FM>");
+      else
+	printk (" <Yamaha OPL-3 FM>");
+
       fm_model = 2;
       voice_alloc->max_voice = nr_voices = 18;
       fm_info.nr_drums = 0;
       fm_info.capabilities |= SYNTH_CAP_OPL3;
-#ifndef SCO
       strcpy (fm_info.name, "Yamaha OPL-3");
-#endif
 
       for (i = 0; i < 18; i++)
 	if (physical_voices[i].ioaddr == USE_LEFT)
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/opl3.h linux/drivers/sound/opl3.h
--- v1.3.8/linux/drivers/sound/opl3.h	Fri Aug 19 08:54:09 1994
+++ linux/drivers/sound/opl3.h	Sat Mar 11 20:04:49 1995
@@ -35,7 +35,7 @@
  *
  *	The percussive mode is implemented in the left side only.
  *
- *	With the above exceptions the both sides can be operated independently.
+ *	With the above exeptions the both sides can be operated independently.
  *	
  *	A 4 OP voice can be created by setting the corresponding
  *	bit at offset 4 of the right side.
@@ -80,6 +80,7 @@
 
 #define OPL3_MODE_REGISTER			0x05	/* Right side */
 #define   OPL3_ENABLE			0x01
+#define   OPL4_ENABLE			0x02
 
 #define KBD_SPLIT_REGISTER			0x08	/* Left side */
 #define   COMPOSITE_SINE_WAVE_MODE	0x80		/* Don't use with OPL-3? */
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v1.3.8/linux/drivers/sound/os.h	Tue Aug 23 09:48:52 1994
+++ linux/drivers/sound/os.h	Mon Jul 10 19:22:42 1995
@@ -28,6 +28,12 @@
 
 #define ALLOW_SELECT
 
+#ifdef MODULE
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
 #include <linux/param.h>
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -45,7 +51,8 @@
 #include <linux/wait.h>
 #include <linux/malloc.h>
 #include <linux/string.h>
-#include <linux/soundcard.h>
+
+#include "linux/soundcard.h"
 
 typedef char snd_rw_buf;
 
@@ -93,7 +100,7 @@
 #define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP)
 #define WAKE_UP(q, f)			{f.mode = WK_WAKEUP;wake_up(&q);}
 
-#define ALLOC_DMA_CHN(chn,deviceID)	request_dma(chn,deviceID)
+#define ALLOC_DMA_CHN(chn,deviceID)	request_dma(chn, deviceID)
 #define RELEASE_DMA_CHN(chn)		free_dma(chn)
 
 #define GET_TIME()			jiffies
@@ -102,7 +109,7 @@
 
 /* DISABLE_INTR is used to disable interrupts.
    These macros store the current flags to the (unsigned long) variable given
-   as a parameter. RESTORE_INTR returns the interrupt enable bit to state
+   as a parameter. RESTORE_INTR returns the interrupt ebable bit to state
    before DISABLE_INTR or ENABLE_INTR */
 
 #define DISABLE_INTR(flags)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
@@ -152,10 +159,28 @@
   add_timer (&name);}
 
 #define INB	inb
+#define INW	inw
 #define OUTB	outb
+#define OUTW	outw
 
 /*
  * SND_SA_INTERRUPT is required. Otherwise the IRQ number is not passed 
  * the handler.
  */
 #define SND_SA_INTERRUPT
+
+/*
+ * The macro DECLARE_FILE() adds an entry to struct fileinfo referencing the
+ * connected filestructure.
+ * This entry must be initialized in sound_open() in soundcard.c
+ *
+ * ISSET_FILE_FLAG() allows checking of flags like O_NONBLOCK on files
+ *
+ */
+
+#define DECLARE_FILE()                   struct file *filp
+#define ISSET_FILE_FLAG(fileinfo, flag)  (fileinfo->filp->f_flags & (flag) ? \
+					  1 : 0)
+#define INT_HANDLER_PROTO() void(*hndlr)(int, struct pt_regs *)
+#define INT_HANDLER_PARMS(irq, parms) int irq, struct pt_regs *parms
+#define INT_HANDLER_CALL(irq) irq, NULL
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas.h linux/drivers/sound/pas.h
--- v1.3.8/linux/drivers/sound/pas.h	Fri Aug 19 08:54:09 1994
+++ linux/drivers/sound/pas.h	Fri Mar  3 12:03:07 1995
@@ -42,6 +42,8 @@
 #define WAIT_STATE			0xBF88		/* R W	Control		Four-bit bus wait-state count (~140ns ea.)	*/
 #define BOARD_REV_ID			0x2789		/* R	Control		Extended Board Revision ID			*/
 
+#define CHIP_REV			0xFF88		/* R	0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */
+
 #define SYSTEM_CONFIGURATION_1		0x8388		/* R W	Control								*/
 	#define S_C_1_PCS_ENABLE	0x01		/* R W  PC speaker	1=enable, 0=disable PC speaker emulation	*/
 	#define S_C_1_PCM_CLOCK_SELECT	0x02		/* R W  PCM		1=14.31818Mhz/12, 0=28.224Mhz master clock	*/ 
@@ -59,6 +61,7 @@
 
 #define IO_CONFIGURATION_1		0xF388		/* R W	Control								*/
 	#define I_C_1_BOOT_RESET_ENABLE	0x80		/* R W  Control		1=reset board on warm boot, 0=don't		*/
+	#define I_C_1_JOYSTICK_ENABLE	0x40		/* R W  Control		1=enable joystick port, 0=don't		        */
 #define IO_CONFIGURATION_2		0xF389		/* R W  Control								*/
 	#define	I_C_2_PCM_DMA_DISABLED	0x00		/* R W  PCM		PCM DMA disabled				*/
 #define IO_CONFIGURATION_3		0xF38A		/* R W	Control								*/
@@ -80,7 +83,7 @@
 
 #define OPERATION_MODE_1		0xEF8B		/* R	Control								*/
 	#define	O_M_1_CDROM_TYPE	0x03		/* R	CD-ROM		3=SCSI, 2=Sony, 0=no CD-ROM interface		*/
-	#define O_M_1_FM_TYPE		0x04		/* R	FM		1=stereo, 0=mono FM chip			*/
+	#define O_M_1_FM_TYPE		0x04		/* R	FM		1=sterero, 0=mono FM chip			*/
 	#define O_M_1_PCM_TYPE 		0x08		/* R	PCM		1=16-bit Codec, 0=8-bit DAC			*/
 #define OPERATION_MODE_2		0xFF8B		/* R	Control								*/
 	#define O_M_2_PCS_ENABLED	0x02		/* R	PC speaker	PC speaker emulation 1=enabled, 0=disabled	*/
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v1.3.8/linux/drivers/sound/pas2_card.c	Tue Jan 17 07:49:57 1995
+++ linux/drivers/sound/pas2_card.c	Mon Jul 10 01:45:14 1995
@@ -44,7 +44,7 @@
 static int      pas_intr_mask = 0;
 static int      pas_irq = 0;
 
-static char     pas_model;
+char            pas_model;
 static char    *pas_model_names[] =
 {"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"};
 
@@ -79,13 +79,13 @@
 /******************* Begin of the Interrupt Handler ********************/
 
 void
-pasintr (int unused, struct pt_regs * regs)
+pasintr (INT_HANDLER_PARMS (irq, dummy))
 {
   int             status;
 
   status = pas_read (INTERRUPT_STATUS);
-  pas_write (status, INTERRUPT_STATUS);	/*
-						 * Clear interrupt
+  pas_write (status, INTERRUPT_STATUS);		/*
+						   * Clear interrupt
 						 */
 
   if (status & I_S_PCM_SAMPLE_BUFFER_IRQ)
@@ -117,7 +117,7 @@
 
   if (!pas_intr_mask)
     {
-      if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0)
+      if ((err = snd_set_irq_handler (pas_irq, pasintr, "PAS16")) < 0)
 	return err;
     }
   pas_intr_mask |= mask;
@@ -182,9 +182,13 @@
   pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET	/*
 										 * |
 										 * S_M_OPL3_DUAL_MONO
-	     	     	     	     	     	     	     	     	     	     	     	     	     	     	     	     										 */ , SERIAL_MIXER);
+										 */ , SERIAL_MIXER);
 
-  pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1);
+  pas_write (I_C_1_BOOT_RESET_ENABLE
+#ifdef PAS_JOYSTICK_ENABLE
+	     | I_C_1_JOYSTICK_ENABLE
+#endif
+	     ,IO_CONFIGURATION_1);
 
   if (pas_irq < 0 || pas_irq > 15)
     {
@@ -219,9 +223,9 @@
     }
 
   /*
- * This fixes the timing problems of the PAS due to the Symphony chipset
- * as per Media Vision.  Only define this if your PAS doesn't work correctly.
- */
+     * This fixes the timing problems of the PAS due to the Symphony chipset
+     * as per Media Vision.  Only define this if your PAS doesn't work correctly.
+   */
 #ifdef SYMPHONY_PAS
   OUTB (0x05, 0xa8);
   OUTB (0x60, 0xa9);
@@ -253,8 +257,8 @@
   else
     pas_write (0, PRESCALE_DIVIDER);
 
-  pas_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
-  pas_write (5, PARALLEL_MIXER);
+  mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
+  mix_write (5, PARALLEL_MIXER);
 
 #if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB)
 
@@ -295,6 +299,8 @@
 	pas_write (irq_dma, EMULATION_CONFIGURATION);
       }
   }
+#else
+  pas_write (0x00, COMPATIBILITY_ENABLE);
 #endif
 
   if (!ok)
@@ -348,7 +354,7 @@
 				 */
     return 0;
 
-  pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f];
+  pas_model = pas_read (CHIP_REV);
 
   return pas_model;
 }
@@ -361,7 +367,7 @@
   if (detect_pas_hw (hw_config))
     {
 
-      if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]))
+      if (pas_model = pas_read (CHIP_REV))
 	{
 	  printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
 	}
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas2_midi.c linux/drivers/sound/pas2_midi.c
--- v1.3.8/linux/drivers/sound/pas2_midi.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/pas2_midi.c	Mon Jul 10 01:45:14 1995
@@ -83,8 +83,8 @@
 
   if (mode == OPEN_READ || mode == OPEN_READWRITE)
     {
-      ctrl |= M_C_ENA_INPUT_IRQ;/*
-					 * Enable input
+      ctrl |= M_C_ENA_INPUT_IRQ;	/*
+					   * Enable input
 					 */
       input_opened = 1;
     }
@@ -134,9 +134,9 @@
 
   fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f;
 
-  if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13))	/*
-									 * Fifo
-									 * full
+  if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13))		/*
+									   * Fifo
+									   * full
 									 */
     {
       return 0;			/*
@@ -239,6 +239,7 @@
 {
   {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
   &std_midi_synth,
+  {0},
   pas_midi_open,
   pas_midi_close,
   pas_midi_ioctl,
@@ -319,8 +320,10 @@
       RESTORE_INTR (flags);
     }
 
+#if 0
   if (stat & M_S_FRAMING_ERROR)
     printk ("MIDI framing error\n");
+#endif
 
   if (stat & M_S_OUTPUT_OVERRUN)
     {
@@ -328,8 +331,8 @@
       ofifo_bytes = 100;
     }
 
-  pas_write (stat, MIDI_STATUS);/*
-					 * Acknowledge interrupts
+  pas_write (stat, MIDI_STATUS);	/*
+					   * Acknowledge interrupts
 					 */
 }
 
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas2_mixer.c linux/drivers/sound/pas2_mixer.c
--- v1.3.8/linux/drivers/sound/pas2_mixer.c	Fri Aug 19 08:54:09 1994
+++ linux/drivers/sound/pas2_mixer.c	Mon Jul 10 01:45:14 1995
@@ -35,18 +35,12 @@
 
 #include "pas.h"
 
-#define TRACE(what)		/*
-				   * * * (what)   */
+#define TRACE(what)		/* (what) */
 
 extern int      translat_code;
+extern char     pas_model;
 
-static int      rec_devices = (SOUND_MASK_MIC);	/*
-
-
-							 * *  * * Default *
-							 * recording * source
-							 *
-							 * *  */
+static int      rec_devices = (SOUND_MASK_MIC);		/* Default recording source */
 static int      mode_control = 0;
 
 #define POSSIBLE_RECORDING_DEVICES	(SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
@@ -59,60 +53,47 @@
 
 static unsigned short levels[SOUND_MIXER_NRDEVICES] =
 {
-  0x3232,			/*
-				 * Master Volume
-				 */
-  0x3232,			/*
-				 * Bass
-				 */
-  0x3232,			/*
-				 * Treble
-				 */
-  0x5050,			/*
-				 * FM
-				 */
-  0x4b4b,			/*
-				 * PCM
-				 */
-  0x3232,			/*
-				 * PC Speaker
-				 */
-  0x4b4b,			/*
-				 * Ext Line
-				 */
-  0x4b4b,			/*
-				 * Mic
-				 */
-  0x4b4b,			/*
-				 * CD
-				 */
-  0x6464,			/*
-				 * Recording monitor
-				 */
-  0x4b4b,			/*
-				 * SB PCM
-				 */
-  0x6464};			/*
+  0x3232,			/* Master Volume */
+  0x3232,			/* Bass */
+  0x3232,			/* Treble */
+  0x5050,			/* FM */
+  0x4b4b,			/* PCM */
+  0x3232,			/* PC Speaker */
+  0x4b4b,			/* Ext Line */
+  0x4b4b,			/* Mic */
+  0x4b4b,			/* CD */
+  0x6464,			/* Recording monitor */
+  0x4b4b,			/* SB PCM */
+  0x6464			/* Recording level */
+};
 
+void
+mix_write (unsigned char data, int ioaddr)
+{
+  /*
+   * The Revision D cards have a problem with their MVA508 interface. The
+   * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
+   * MSBs out of the output byte and to do a 16-bit out to the mixer port -
+   * 1. We need to do this because it isn't timing problem but chip access
+   * sequence problem.
+   */
 
-				 * *  * * Recording level   */
+  if (pas_model == PAS_16D)
+    {
+      OUTW (data | (data << 8), (ioaddr ^ translat_code) - 1);
+      OUTB (0x80, 0);
+    }
+  else
+    pas_write (data, ioaddr);
+}
 
 static int
 mixer_output (int right_vol, int left_vol, int div, int bits,
-	      int mixer		/*
-				 * Input or output mixer
-     	      	      	      	      	      				 */ )
+	      int mixer)	/* Input or output mixer */
 {
   int             left = left_vol * div / 100;
   int             right = right_vol * div / 100;
 
-  /*
-   * The Revision D cards have a problem with their MVA508 interface. The
-   * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and
-   * MSBs out of the output byte and to do a 16-bit out to the mixer port -
-   * 1. We don't need to do this because the call to pas_write more than
-   * compensates for the timing problems.
-   */
 
   if (bits & P_M_MV508_MIXER)
     {				/*
@@ -126,16 +107,16 @@
     {				/*
 				 * Bass and treble are mono devices
 				 */
-      pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
-      pas_write (left, PARALLEL_MIXER);
+      mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
+      mix_write (left, PARALLEL_MIXER);
       right_vol = left_vol;
     }
   else
     {
-      pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
-      pas_write (left, PARALLEL_MIXER);
-      pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
-      pas_write (right, PARALLEL_MIXER);
+      mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
+      mix_write (left, PARALLEL_MIXER);
+      mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
+      mix_write (right, PARALLEL_MIXER);
     }
 
   return (left_vol | (right_vol << 8));
@@ -144,8 +125,8 @@
 void
 set_mode (int new_mode)
 {
-  pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
-  pas_write (new_mode, PARALLEL_MIXER);
+  mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
+  mix_write (new_mode, PARALLEL_MIXER);
 
   mode_control = new_mode;
 }
@@ -168,9 +149,7 @@
 
   switch (whichDev)
     {
-    case SOUND_MIXER_VOLUME:	/*
-				 * Master volume (0-63)
-				 */
+    case SOUND_MIXER_VOLUME:	/* Master volume (0-63) */
       levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
       break;
 
@@ -178,62 +157,39 @@
        * Note! Bass and Treble are mono devices. Will use just the left
        * channel.
        */
-    case SOUND_MIXER_BASS:	/*
-				 * Bass (0-12)
-				 */
+    case SOUND_MIXER_BASS:	/* Bass (0-12) */
       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
       break;
-    case SOUND_MIXER_TREBLE:	/*
-				 * Treble (0-12)
-				 */
+    case SOUND_MIXER_TREBLE:	/* Treble (0-12) */
       levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
       break;
 
-    case SOUND_MIXER_SYNTH:	/*
-				 * Internal synthesizer (0-31)
-				 */
+    case SOUND_MIXER_SYNTH:	/* Internal synthesizer (0-31) */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
       break;
-    case SOUND_MIXER_PCM:	/*
-				 * PAS PCM (0-31)
-				 */
+    case SOUND_MIXER_PCM:	/* PAS PCM (0-31) */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
       break;
-    case SOUND_MIXER_ALTPCM:	/*
-				 * SB PCM (0-31)
-				 */
+    case SOUND_MIXER_ALTPCM:	/* SB PCM (0-31) */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
       break;
-    case SOUND_MIXER_SPEAKER:	/*
-				 * PC speaker (0-31)
-				 */
+    case SOUND_MIXER_SPEAKER:	/* PC speaker (0-31) */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
       break;
-    case SOUND_MIXER_LINE:	/*
-				 * External line (0-31)
-				 */
+    case SOUND_MIXER_LINE:	/* External line (0-31) */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
       break;
-    case SOUND_MIXER_CD:	/*
-				 * CD (0-31)
-				 */
+    case SOUND_MIXER_CD:	/* CD (0-31) */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
       break;
-    case SOUND_MIXER_MIC:	/*
-				 * External microphone (0-31)
-				 */
+    case SOUND_MIXER_MIC:	/* External microphone (0-31) */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
       break;
-    case SOUND_MIXER_IMIX:	/*
-				 * Recording monitor (0-31) (Only available *
-				 * on the Output Mixer)
-				 */
+    case SOUND_MIXER_IMIX:	/* Recording monitor (0-31) (Output mixer only) */
       levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
 				       P_M_MV508_OUTPUTMIX);
       break;
-    case SOUND_MIXER_RECLEV:	/*
-				 * Recording level (0-15)
-				 */
+    case SOUND_MIXER_RECLEV:	/* Recording level (0-15) */
       levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
       break;
 
@@ -261,9 +217,7 @@
       if (level)
 	mode_control |= P_M_MV508_LOUDNESS;
       set_mode (mode_control);
-      return !!level;		/*
-				 * 0 or 1
-				 */
+      return !!level;		/* 0 or 1 */
       break;
 
     case SOUND_MIXER_RECSRC:
@@ -313,7 +267,7 @@
 	return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
       else
 	{			/*
-				 * Read parameters
+				   * Read parameters
 				 */
 
 	  switch (cmd & 0xff)
@@ -336,15 +290,11 @@
 	      break;
 
 	    case SOUND_MIXER_CAPS:
-	      return IOCTL_OUT (arg, 0);	/*
-						 * No special capabilities
-						 */
+	      return IOCTL_OUT (arg, 0);	/* No special capabilities */
 	      break;
 
 	    case SOUND_MIXER_MUTE:
-	      return IOCTL_OUT (arg, 0);	/*
-						 * No mute yet
-						 */
+	      return IOCTL_OUT (arg, 0);	/* No mute yet */
 	      break;
 
 	    case SOUND_MIXER_ENHANCE:
@@ -369,6 +319,7 @@
 
 static struct mixer_operations pas_mixer_operations =
 {
+  "Pro Audio Spectrum 16",
   pas_mixer_ioctl
 };
 
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pas2_pcm.c linux/drivers/sound/pas2_pcm.c
--- v1.3.8/linux/drivers/sound/pas2_pcm.c	Fri Aug 19 08:54:09 1994
+++ linux/drivers/sound/pas2_pcm.c	Mon Jul 10 01:45:15 1995
@@ -79,13 +79,13 @@
   tmp = pas_read (FILTER_FREQUENCY);
 
   /*
- * Set anti-aliasing filters according to sample rate. You really *NEED*
- * to enable this feature for all normal recording unless you want to
- * experiment with aliasing effects.
- * These filters apply to the selected "recording" source.
- * I (pfw) don't know the encoding of these 5 bits. The values shown
- * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
-*/
+     * Set anti-aliasing filters according to sample rate. You reall *NEED*
+     * to enable this feature for all normal recording unless you want to
+     * experiment with aliasing effects.
+     * These filters apply to the selected "recording" source.
+     * I (pfw) don't know the encoding of these 5 bits. The values shown
+     * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
+   */
 #if !defined NO_AUTO_FILTER_SET
   tmp &= 0xe0;
   if (pcm_speed >= 2 * 17897)
@@ -128,8 +128,8 @@
       pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL);
 
       pcm_channels = arg;
-      pcm_set_speed (pcm_speed);/*
-					 * The speed must be reinitialized
+      pcm_set_speed (pcm_speed);	/*
+					   * The speed must be reinitialized
 					 */
     }
 
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/patmgr.c linux/drivers/sound/patmgr.c
--- v1.3.8/linux/drivers/sound/patmgr.c	Fri Aug 19 08:54:09 1994
+++ linux/drivers/sound/patmgr.c	Mon Jul 10 01:45:15 1995
@@ -1,7 +1,7 @@
 /*
  * sound/patmgr.c
  *
- * The patch manager interface for the /dev/sequencer
+ * The patch maneger interface for the /dev/sequencer
  *
  * Copyright by Hannu Savolainen 1993
  *
@@ -234,8 +234,12 @@
     printk ("  PATMGR: Server %d mbox full. Why?\n", dev);
   else
     {
-      mbox[dev] =
-	(struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info));
+      if ((mbox[dev] =
+	   (struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info))) == NULL)
+	{
+	  printk ("pmgr: Couldn't allocate memory for a message\n");
+	  return 0;
+	}
 
       mbox[dev]->key = PM_K_EVENT;
       mbox[dev]->command = event;
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/pss.c linux/drivers/sound/pss.c
--- v1.3.8/linux/drivers/sound/pss.c	Mon Mar  6 11:22:09 1995
+++ linux/drivers/sound/pss.c	Mon Jul 10 01:45:16 1995
@@ -1,664 +1,250 @@
-/* Marc.Hoffman@analog.com
+/*
+ * sound/pss.c
+ *
+ * The low level driver for the Personal Sound System (ECHO ESC614).
+ *
+ * Copyright by Hannu Savolainen 1993
+ *
+ * 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.
+ *
+ */
 
-   This is a pss driver.
-
-   it is based on Greg.Yukna@analog.com @file{host} for DOG
-
-   Unfortunately I can't distribute the ld file needed to
-   make the pss card to emulate the SB stuff.
-
-   I have provided a simple interface to the PSS unlike the
-   DOG version.  to download a new algorithm just cat it to
-   /dev/pss 14,9.
-
-   You really need to rebuild this with the synth.ld file
-
-   get the <synth>.ld from your dos directory maybe
-   voyetra\dsp001.ld
-
-   ld2inc < synth.ld > synth-ld.h
-   (make config does the same).
-
-   rebuild
-
-   Okay if you blow things away no problem just
-
-   main(){ioctl(open("/dev/pss"),SNDCTL_PSS_RESET)};
-
-   and everything will be okay.
-
-   At first I was going to worry about applications that were using
-   the sound stuff and disallow the use of /dev/pss.  But for
-   now I figured it doesn't matter.
-
-   And if you change algos all the other applications running die off
-   due to DMA problems.  Yeah just pull the plug and watch em die.
-
-   If the registers get hosed
-   main(){ioctl(open("/dev/pss"),SNDCTL_PSS_SETUP_REGISTERS)};
-
-   Probably everything else can be done via mmap
-
-   Oh if you want to develop code for the ADSP-21xx or Program the
-   1848 just send me mail and I will hook you up.
-
-               marc.hoffman@analog.com
-
-   */
 #include "sound_config.h"
 
-#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS)
-
-#ifndef PSS_MSS_BASE
-#define PSS_MSS_BASE 0
-#endif
-
-#ifndef PSS_MPU_BASE
-#define PSS_MPU_BASE 0
-#endif
-
-#ifndef PSS_MPU_IRQ
-#define PSS_MPU_IRQ 0
-#endif
-
-#undef DEB
-#define DEB(x) x
-
-#include "pss.h"
-
-static int      pss_ok = 0;
-static int      sb_ok = 0;
-
-static int      pss_base;
-static int      pss_irq;
-static int      pss_dma;
-
-static int      gamePort = 0;
-
-static int      sbInt;
-static int      cdPol;
-static int      cdAddr = 0;	/* 0x340;	*/
-static int      cdInt = 10;
-
-/* Define these by hand in local.h */
-static int      wssAddr = PSS_MSS_BASE;
-static int      midiAddr = PSS_MPU_BASE;
-static int      midiInt = PSS_MPU_IRQ;
-
-static int      SoundPortAddress;
-static int      SoundPortData;
-static int      speaker = 1;
+#if defined (CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PSS) && !defined(EXCLUDE_AUDIO)
 
+/*
+ * PSS registers.
+ */
+#define REG(x)	(devc->base+x)
+#define	PSS_DATA	0
+#define	PSS_STATUS	2
+#define PSS_CONTROL	2
+#define	PSS_ID		4
+#define	PSS_IRQACK	4
+#define	PSS_PIO		0x1a
+
+/*
+ * Config registers
+ */
+#define CONF_PSS	0x10
+#define CONF_WSS	0x12
+#define CONF_SB		0x13
+#define CONF_CDROM	0x16
+#define CONF_MIDI	0x18
+
+/*
+ * Status bits.
+ */
+#define PSS_FLAG3     0x0800
+#define PSS_FLAG2     0x0400
+#define PSS_FLAG1     0x1000
+#define PSS_FLAG0     0x0800
+#define PSS_WRITE_EMPTY  0x8000
+#define PSS_READ_FULL    0x4000
 
-static struct pss_speaker default_speaker =
-{0, 0, 0, PSS_STEREO};
-
-DEFINE_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
-
+#include "coproc.h"
 #include "synth-ld.h"
 
-static int      pss_download_boot (unsigned char *block, int size);
-static int      pss_reset_dsp (void);
+typedef struct pss_config
+  {
+    int             base;
+    int             irq;
+    int             dma;
+  }
 
-static inline void
-pss_outpw (unsigned short port, unsigned short value)
-{
-  __asm__         __volatile__ ("outw %w0, %w1"
-				:	/* no outputs */
-				:"a"            (value), "d" (port));
-}
+pss_config;
 
-static inline unsigned int
-pss_inpw (unsigned short port)
-{
-  unsigned int    _v;
-  __asm__         __volatile__ ("inw %w1,%w0"
-				:"=a"           (_v):"d" (port), "0" (0));
+static pss_config pss_data;
+static pss_config *devc = &pss_data;
 
-  return _v;
-}
+static int      pss_initialized = 0;
+static int      nonstandard_microcode = 0;
 
-static void
-PSS_write (int data)
+int
+probe_pss (struct address_info *hw_config)
 {
-  int             i, limit;
+  unsigned short  id;
+  int             irq, dma;
 
-  limit = GET_TIME () + 10;	/* The timeout is 0.1 seconds */
-  /*
-   * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes
-   * called while interrupts are disabled. This means that the timer is
-   * disabled also. However the timeout situation is a abnormal condition.
-   * Normally the DSP should be ready to accept commands after just couple of
-   * loops.
-   */
-
-  for (i = 0; i < 5000000 && GET_TIME () < limit; i++)
-    {
-      if (pss_inpw (pss_base + PSS_STATUS) & PSS_WRITE_EMPTY)
-	{
-	  pss_outpw (pss_base + PSS_DATA, data);
-	  return;
-	}
-    }
-  printk ("PSS: DSP Command (%04x) Timeout.\n", data);
-  printk ("IRQ conflict???\n");
-}
-
-
-static void
-pss_setaddr (int addr, int configAddr)
-{
-  int             val;
+  devc->base = hw_config->io_base;
+  irq = devc->irq = hw_config->irq;
+  dma = devc->dma = hw_config->dma;
 
-  val = pss_inpw (configAddr);
-  val &= ADDR_MASK;
-  val |= (addr << 4);
-  pss_outpw (configAddr, val);
-}
-
-/*_____ pss_checkint
-         This function tests an interrupt number to see if
-	 it is available. It takes the interrupt button
-	 as its argument and returns TRUE if the interrupt
-	 is ok.
-*/
-static int
-pss_checkint (int intNum)
-{
-  int             val;
-  int             ret;
-  int             i;
-
-  /*_____ Set the interrupt bits */
-  switch (intNum)
-    {
-    case 3:
-      val = pss_inpw (pss_base + PSS_CONFIG);
-      val &= INT_MASK;
-      val |= INT_3_BITS;
-      pss_outpw (pss_base + PSS_CONFIG, val);
-      break;
-    case 5:
-      val = pss_inpw (pss_base + PSS_CONFIG);
-      val &= INT_MASK;
-      val |= INT_5_BITS;
-      pss_outpw (pss_base + PSS_CONFIG, val);
-      break;
-    case 7:
-      val = pss_inpw (pss_base + PSS_CONFIG);
-      val &= INT_MASK;
-      val |= INT_7_BITS;
-      pss_outpw (pss_base + PSS_CONFIG, val);
-      break;
-    case 9:
-      val = pss_inpw (pss_base + PSS_CONFIG);
-      val &= INT_MASK;
-      val |= INT_9_BITS;
-      pss_outpw (pss_base + PSS_CONFIG, val);
-      break;
-    case 10:
-      val = pss_inpw (pss_base + PSS_CONFIG);
-      val &= INT_MASK;
-      val |= INT_10_BITS;
-      pss_outpw (pss_base + PSS_CONFIG, val);
-      break;
-    case 11:
-      val = pss_inpw (pss_base + PSS_CONFIG);
-      val &= INT_MASK;
-      val |= INT_11_BITS;
-      pss_outpw (pss_base + PSS_CONFIG, val);
-      break;
-    case 12:
-      val = pss_inpw (pss_base + PSS_CONFIG);
-      val &= INT_MASK;
-      val |= INT_12_BITS;
-      pss_outpw (pss_base + PSS_CONFIG, val);
-      break;
-    default:
-      printk ("unknown interrupt selected. %d\n", intNum);
+  if (devc->base != 0x220 && devc->base != 0x240)
+    if (devc->base != 0x230 && devc->base != 0x250)	/* Some cards use these */
       return 0;
-    }
-
-  /*_____ Set the interrupt test bit */
-  val = pss_inpw (pss_base + PSS_CONFIG);
-  val |= INT_TEST_BIT;
-  pss_outpw (pss_base + PSS_CONFIG, val);
 
-  /*_____ Check if the interrupt is in use */
-  /*_____ Do it a few times in case there is a delay */
-  ret = 0;
-  for (i = 0; i < 5; i++)
-    {
-      val = pss_inpw (pss_base + PSS_CONFIG);
-      if (val & INT_TEST_PASS)
-	{
-	  ret = 1;
-	  break;
-	}
-    }
-  /*_____ Clear the Test bit and the interrupt bits */
-  val = pss_inpw (pss_base + PSS_CONFIG);
-  val &= INT_TEST_BIT_MASK;
-  val &= INT_MASK;
-  pss_outpw (pss_base + PSS_CONFIG, val);
-  return (ret);
-}
+  if (irq != 3 && irq != 5 && irq != 7 && irq != 9 &&
+      irq != 10 && irq != 11 && irq != 12)
+    return 0;
 
-/*____ pss_setint
-        This function sets the correct bits in the
-	configuration register to
-	enable the chosen interrupt.
-*/
-static void
-pss_setint (int intNum, int configAddress)
-{
-  int             val;
+  if (dma != 5 && dma != 6 && dma != 7)
+    return 0;
 
-  switch (intNum)
+  id = INW (REG (PSS_ID));
+  if ((id >> 8) != 'E')
     {
-    case 0:
-      val = pss_inpw (configAddress);
-      val &= INT_MASK;
-      pss_outpw (configAddress, val);
-      break;
-    case 3:
-      val = pss_inpw (configAddress);
-      val &= INT_MASK;
-      val |= INT_3_BITS;
-      pss_outpw (configAddress, val);
-      break;
-    case 5:
-      val = pss_inpw (configAddress);
-      val &= INT_MASK;
-      val |= INT_5_BITS;
-      pss_outpw (configAddress, val);
-      break;
-    case 7:
-      val = pss_inpw (configAddress);
-      val &= INT_MASK;
-      val |= INT_7_BITS;
-      pss_outpw (configAddress, val);
-      break;
-    case 9:
-      val = pss_inpw (configAddress);
-      val &= INT_MASK;
-      val |= INT_9_BITS;
-      pss_outpw (configAddress, val);
-      break;
-    case 10:
-      val = pss_inpw (configAddress);
-      val &= INT_MASK;
-      val |= INT_10_BITS;
-      pss_outpw (configAddress, val);
-      break;
-    case 11:
-      val = pss_inpw (configAddress);
-      val &= INT_MASK;
-      val |= INT_11_BITS;
-      pss_outpw (configAddress, val);
-      break;
-    case 12:
-      val = pss_inpw (configAddress);
-      val &= INT_MASK;
-      val |= INT_12_BITS;
-      pss_outpw (configAddress, val);
-      break;
-    default:
-      printk ("pss_setint unknown int\n");
+      printk ("No PSS signature detected at 0x%x (0x%x)\n", devc->base, id);
+      return 0;
     }
-}
 
-
-/*____ pss_setsbint
-        This function sets the correct bits in the
-	SoundBlaster configuration PSS register to
-	enable the chosen interrupt.
-	It takes a interrupt button as its argument.
-*/
-static void
-pss_setsbint (int intNum)
-{
-  int             val;
-  int             sbConfigAddress;
-
-  sbConfigAddress = pss_base + SB_CONFIG;
-  switch (intNum)
-    {
-    case 3:
-      val = pss_inpw (sbConfigAddress);
-      val &= INT_MASK;
-      val |= INT_3_BITS;
-      pss_outpw (sbConfigAddress, val);
-      break;
-    case 5:
-      val = pss_inpw (sbConfigAddress);
-      val &= INT_MASK;
-      val |= INT_5_BITS;
-      pss_outpw (sbConfigAddress, val);
-      break;
-    case 7:
-      val = pss_inpw (sbConfigAddress);
-      val &= INT_MASK;
-      val |= INT_7_BITS;
-      pss_outpw (sbConfigAddress, val);
-      break;
-    default:
-      printk ("pss_setsbint: unknown_int\n");
-    }
+  return 1;
 }
 
-/*____ pss_setsbdma
-        This function sets the correct bits in the
-	SoundBlaster configuration PSS register to
-	enable the chosen DMA channel.
-	It takes a DMA button as its argument.
-*/
-static void
-pss_setsbdma (int dmaNum)
+static int
+set_irq (pss_config * devc, int dev, int irq)
 {
-  int             val;
-  int             sbConfigAddress;
+  static unsigned short irq_bits[16] =
+  {
+    0x0000, 0x0000, 0x0000, 0x0008,
+    0x0000, 0x0010, 0x0000, 0x0018,
+    0x0000, 0x0020, 0x0028, 0x0030,
+    0x0038, 0x0000, 0x0000, 0x0000
+  };
 
-  sbConfigAddress = pss_base + SB_CONFIG;
+  unsigned short  tmp, bits;
 
-  switch (dmaNum)
-    {
-    case 1:
-      val = pss_inpw (sbConfigAddress);
-      val &= DMA_MASK;
-      val |= DMA_1_BITS;
-      pss_outpw (sbConfigAddress, val);
-      break;
-    default:
-      printk ("Personal Sound System ERROR! pss_setsbdma: unknown_dma\n");
-    }
-}
-
-/*____ pss_setwssdma
-        This function sets the correct bits in the
-	WSS configuration PSS register to
-	enable the chosen DMA channel.
-	It takes a DMA button as its argument.
-*/
-static void
-pss_setwssdma (int dmaNum)
-{
-  int             val;
-  int             wssConfigAddress;
+  if (irq < 1 || irq > 15)
+    return 0;
 
-  wssConfigAddress = pss_base + PSS_WSS_CONFIG;
+  tmp = INW (REG (dev)) & ~0x38;	/* Load confreg, mask IRQ bits out */
 
-  switch (dmaNum)
+  if ((bits = irq_bits[irq]) == 0)
     {
-    case 0:
-      val = pss_inpw (wssConfigAddress);
-      val &= DMA_MASK;
-      val |= DMA_0_BITS;
-      pss_outpw (wssConfigAddress, val);
-      break;
-    case 1:
-      val = pss_inpw (wssConfigAddress);
-      val &= DMA_MASK;
-      val |= DMA_1_BITS;
-      pss_outpw (wssConfigAddress, val);
-      break;
-    case 3:
-      val = pss_inpw (wssConfigAddress);
-      val &= DMA_MASK;
-      val |= DMA_3_BITS;
-      pss_outpw (wssConfigAddress, val);
-      break;
-    default:
-      printk ("Personal Sound System ERROR! pss_setwssdma: unknown_dma\n");
+      printk ("PSS: Invalid IRQ %d\n", irq);
+      return 0;
     }
-}
 
-
-/*_____ SetSpeakerOut
-         This function sets the Volume, Bass, Treble and Mode of
-	 the speaker out channel.
-	 */
-void
-pss_setspeaker (struct pss_speaker *spk)
-{
-  PSS_write (SET_MASTER_COMMAND);
-  if (spk->volume > PHILLIPS_VOL_MAX)
-    spk->volume = PHILLIPS_VOL_MAX;
-  if (spk->volume < PHILLIPS_VOL_MIN)
-    spk->volume = PHILLIPS_VOL_MIN;
-
-  PSS_write (MASTER_VOLUME_LEFT
-	     | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
-  PSS_write (SET_MASTER_COMMAND);
-  PSS_write (MASTER_VOLUME_RIGHT
-	     | (PHILLIPS_VOL_CONSTANT + spk->volume / PHILLIPS_VOL_STEP));
-
-  if (spk->bass > PHILLIPS_BASS_MAX)
-    spk->bass = PHILLIPS_BASS_MAX;
-  if (spk->bass < PHILLIPS_BASS_MIN)
-    spk->bass = PHILLIPS_BASS_MIN;
-  PSS_write (SET_MASTER_COMMAND);
-  PSS_write (MASTER_BASS
-	     | (PHILLIPS_BASS_CONSTANT + spk->bass / PHILLIPS_BASS_STEP));
-
-  if (spk->treb > PHILLIPS_TREBLE_MAX)
-    spk->treb = PHILLIPS_TREBLE_MAX;
-  if (spk->treb < PHILLIPS_TREBLE_MIN)
-    spk->treb = PHILLIPS_TREBLE_MIN;
-  PSS_write (SET_MASTER_COMMAND);
-  PSS_write (MASTER_TREBLE
-	   | (PHILLIPS_TREBLE_CONSTANT + spk->treb / PHILLIPS_TREBLE_STEP));
-
-  PSS_write (SET_MASTER_COMMAND);
-  PSS_write (MASTER_SWITCH | spk->mode);
+  OUTW (tmp | bits, REG (dev));
+  return 1;
 }
 
-static void
-pss_init1848 (void)
+static int
+set_io_base (pss_config * devc, int dev, int base)
 {
-  /*_____ Wait for 1848 to init */
-  while (INB (SoundPortAddress) & SP_IN_INIT);
+  unsigned short  tmp = INW (REG (dev)) & 0x003f;
+  unsigned short  bits = (base & 0x0ffc) << 4;
 
-  /*_____ Wait for 1848 to autocal */
-  OUTB (SoundPortAddress, SP_TEST_AND_INIT);
-  while (INB (SoundPortData) & AUTO_CAL_IN_PROG);
+  OUTW (bits | tmp, REG (dev));
+
+  return 1;
 }
 
 static int
-pss_configure_registers_to_look_like_sb (void)
+set_dma (pss_config * devc, int dev, int dma)
 {
-  pss_setaddr (wssAddr, pss_base + PSS_WSS_CONFIG);
-
-  SoundPortAddress = wssAddr + 4;
-  SoundPortData = wssAddr + 5;
-
-  DEB (printk ("Turning Game Port %s.\n",
-	       gamePort ? "On" : "Off"));
-
-  /*_____ Turn on the Game port */
-  if (gamePort)
-    pss_outpw (pss_base + PSS_STATUS,
-	       pss_inpw (pss_base + PSS_STATUS) | GAME_BIT);
-  else
-    pss_outpw (pss_base + PSS_STATUS,
-	       pss_inpw (pss_base + PSS_STATUS) & GAME_BIT_MASK);
+  static unsigned short dma_bits[8] =
+  {
+    0x0001, 0x0002, 0x0000, 0x0003,
+    0x0000, 0x0005, 0x0006, 0x0007
+  };
 
+  unsigned short  tmp, bits;
 
-  DEB (printk ("PSS attaching base %x irq %d dma %d\n",
-	       pss_base, pss_irq, pss_dma));
-
-  /* Check if sb is enabled if it is check the interrupt */
-  pss_outpw (pss_base + SB_CONFIG, 0);
-
-  if (pss_irq != 0)
-    {
-      DEB (printk ("PSS Emulating Sound Blaster ADDR %04x\n", pss_base));
-      DEB (printk ("PSS SBC: attaching base %x irq %d dma %d\n",
-		   SBC_BASE, SBC_IRQ, SBC_DMA));
-
-      if (pss_checkint (SBC_IRQ) == 0)
-	{
-	  printk ("PSS! attach: int_error\n");
-	  return 0;
-	}
-
-      pss_setsbint (SBC_IRQ);
-      pss_setsbdma (SBC_DMA);
-      sb_ok = 1;
-    }
-  else
-    {
-      sb_ok = 0;
-      printk ("PSS: sound blaster error init\n");
-    }
+  if (dma < 0 || dma > 7)
+    return 0;
 
-  /* Check if cd is enabled if it is check the interrupt */
-  pss_outpw (pss_base + CD_CONFIG, 0);
+  tmp = INW (REG (dev)) & ~0x07;	/* Load confreg, mask DMA bits out */
 
-  if (cdAddr != 0)
+  if ((bits = dma_bits[dma]) == 0)
     {
-      DEB (printk ("PSS:CD drive %x irq: %d", cdAddr, cdInt));
-      if (cdInt != 0)
-	{
-	  if (pss_checkint (cdInt) == 0)
-	    {
-	      printk ("Can't allocate cdInt %d\n", cdInt);
-	    }
-	  else
-	    {
-	      int             val;
-
-	      printk ("CD poll ");
-	      pss_setaddr (cdAddr, pss_base + CD_CONFIG);
-	      pss_setint (cdInt, pss_base + CD_CONFIG);
-
-	      /* set the correct bit in the
-		 configuration register to
-		 set the irq polarity for the CD-Rom.
-		 NOTE: This bit is in the address config
-		 field, It must be configured after setting
-		 the CD-ROM ADDRESS!!! */
-	      val = pss_inpw (pss_base + CD_CONFIG);
-	      pss_outpw (pss_base + CD_CONFIG, 0);
-	      val &= CD_POL_MASK;
-	      if (cdPol)
-		val |= CD_POL_BIT;
-	      pss_outpw (pss_base + CD_CONFIG, val);
-	    }
-	}
+      printk ("PSS: Invalid DMA %d\n", dma);
+      return 0;
     }
 
-  /* Check if midi is enabled if it is check the interrupt */
-  pss_outpw (pss_base + MIDI_CONFIG, 0);
-  if (midiAddr != 0)
-    {
-      printk ("midi init %x %d\n", midiAddr, midiInt);
-      if (pss_checkint (midiInt) == 0)
-	{
-	  printk ("midi init int error %x %d\n", midiAddr, midiInt);
-	}
-      else
-	{
-	  pss_setaddr (midiAddr, pss_base + MIDI_CONFIG);
-	  pss_setint (midiInt, pss_base + MIDI_CONFIG);
-	}
-    }
+  OUTW (tmp | bits, REG (dev));
   return 1;
 }
 
-long
-attach_pss (long mem_start, struct address_info *hw_config)
+static int
+pss_reset_dsp (pss_config * devc)
 {
-  if (pss_ok)
-    {
-      if (hw_config)
-	{
-	  printk (" <PSS-ESC614>");
-	}
-
-      return mem_start;
-    }
+  unsigned long   i, limit = GET_TIME () + 10;
 
-  pss_ok = 1;
+  OUTW (0x2000, REG (PSS_CONTROL));
 
-  if (pss_configure_registers_to_look_like_sb () == 0)
-    return mem_start;
+  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+    INW (REG (PSS_CONTROL));
 
-  if (sb_ok)
-    if (pss_synthLen
-	&& pss_download_boot (pss_synth, pss_synthLen))
-      {
-	if (speaker)
-	  pss_setspeaker (&default_speaker);
-	pss_ok = 1;
-      }
-    else
-      pss_reset_dsp ();
+  OUTW (0x0000, REG (PSS_CONTROL));
 
-  return mem_start;
+  return 1;
 }
 
-int
-probe_pss (struct address_info *hw_config)
+static int
+pss_put_dspword (pss_config * devc, unsigned short word)
 {
-  pss_base = hw_config->io_base;
-  pss_irq = hw_config->irq;
-  pss_dma = hw_config->dma;
+  int             i, val;
 
-  if ((pss_inpw (pss_base + 4) & 0xff00) == 0x4500)
+  for (i = 0; i < 327680; i++)
     {
-      attach_pss (0, hw_config);
-      return 1;
+      val = INW (REG (PSS_STATUS));
+      if (val & PSS_WRITE_EMPTY)
+	{
+	  OUTW (word, REG (PSS_DATA));
+	  return 1;
+	}
     }
-  printk (" fail base %x irq %d dma %d\n", pss_base, pss_irq, pss_dma);
   return 0;
 }
 
-
 static int
-pss_reattach (void)
+pss_get_dspword (pss_config * devc, unsigned short *word)
 {
-  pss_ok = 0;
-  attach_pss (0, 0);
-  return 1;
-}
+  int             i, val;
 
-static int
-pss_reset_dsp ()
-{
-  unsigned long   i, limit = GET_TIME () + 10;
-
-  pss_outpw (pss_base + PSS_CONTROL, 0x2000);
-
-  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
-    pss_inpw (pss_base + PSS_CONTROL);
-
-  pss_outpw (pss_base + PSS_CONTROL, 0x0000);
+  for (i = 0; i < 327680; i++)
+    {
+      val = INW (REG (PSS_STATUS));
+      if (val & PSS_READ_FULL)
+	{
+	  *word = INW (REG (PSS_DATA));
+	  return 1;
+	}
+    }
 
-  return 1;
+  return 0;
 }
 
-
 static int
-pss_download_boot (unsigned char *block, int size)
+pss_download_boot (pss_config * devc, unsigned char *block, int size, int flags)
 {
   int             i, limit, val, count;
 
-  printk ("PSS: downloading boot code synth.ld... ");
-
-  /*_____ Warn DSP software that a boot is coming */
-  pss_outpw (pss_base + PSS_DATA, 0x00fe);
+  if (flags & CPF_FIRST)
+    {
+/*_____ Warn DSP software that a boot is coming */
+      OUTW (0x00fe, REG (PSS_DATA));
 
-  limit = GET_TIME () + 10;
+      limit = GET_TIME () + 10;
 
-  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
-    if (pss_inpw (pss_base + PSS_DATA) == 0x5500)
-      break;
+      for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+	if (INW (REG (PSS_DATA)) == 0x5500)
+	  break;
 
-  pss_outpw (pss_base + PSS_DATA, *block++);
+      OUTW (*block++, REG (PSS_DATA));
 
-  pss_reset_dsp ();
-  printk ("start ");
+      pss_reset_dsp (devc);
+    }
 
   count = 1;
   while (1)
@@ -667,15 +253,15 @@
 
       for (j = 0; j < 327670; j++)
 	{
-	  /*_____ Wait for BG to appear */
-	  if (pss_inpw (pss_base + PSS_STATUS) & PSS_FLAG3)
+/*_____ Wait for BG to appear */
+	  if (INW (REG (PSS_STATUS)) & PSS_FLAG3)
 	    break;
 	}
 
       if (j == 327670)
 	{
 	  /* It's ok we timed out when the file was empty */
-	  if (count >= size)
+	  if (count >= size && flags & CPF_LAST)
 	    break;
 	  else
 	    {
@@ -684,241 +270,460 @@
 	      return 0;
 	    }
 	}
-      /*_____ Send the next byte */
-      pss_outpw (pss_base + PSS_DATA, *block++);
+/*_____ Send the next byte */
+      OUTW (*block++, REG (PSS_DATA));
       count++;
     }
 
-  /*_____ Why */
-  pss_outpw (pss_base + PSS_DATA, 0);
+  if (flags & CPF_LAST)
+    {
+/*_____ Why */
+      OUTW (0, REG (PSS_DATA));
 
-  limit = GET_TIME () + 10;
-  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
-    val = pss_inpw (pss_base + PSS_STATUS);
+      limit = GET_TIME () + 10;
+      for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+	val = INW (REG (PSS_STATUS));
 
-  printk ("downloaded\n");
+      limit = GET_TIME () + 10;
+      for (i = 0; i < 32768 && GET_TIME () < limit; i++)
+	{
+	  val = INW (REG (PSS_STATUS));
+	  if (val & 0x4000)
+	    break;
+	}
 
-  limit = GET_TIME () + 10;
-  for (i = 0; i < 32768 && GET_TIME () < limit; i++)
-    {
-      val = pss_inpw (pss_base + PSS_STATUS);
-      if (val & 0x4000)
-	break;
-    }
+      /* now read the version */
+      for (i = 0; i < 32000; i++)
+	{
+	  val = INW (REG (PSS_STATUS));
+	  if (val & PSS_READ_FULL)
+	    break;
+	}
+      if (i == 32000)
+	return 0;
 
-  /* now read the version */
-  for (i = 0; i < 32000; i++)
-    {
-      val = pss_inpw (pss_base + PSS_STATUS_REG);
-      if (val & PSS_READ_FULL)
-	break;
+      val = INW (REG (PSS_DATA));
+      /* printk("<PSS: microcode version %d.%d loaded>", val/16, val % 16); */
     }
-  if (i == 32000)
-    return 0;
-
-  val = pss_inpw (pss_base + PSS_DATA_REG);
 
   return 1;
 }
 
+long
+attach_pss (long mem_start, struct address_info *hw_config)
+{
+  unsigned short  id;
 
-/* The following is a simple device driver for the pss.
-   All I really care about is communication to and from the pss.
+  devc->base = hw_config->io_base;
+  devc->irq = hw_config->irq;
+  devc->dma = hw_config->dma;
 
-   The ability to reinitialize the <synth.ld>  This will be
-   default when release is chosen.
+  if (!probe_pss (hw_config))
+    return mem_start;
 
-   SNDCTL_PSS_DOWNLOAD:
+  id = INW (REG (PSS_ID)) & 0x00ff;
 
-   Okay we need to creat new minor numbers for the
-   DOWNLOAD functionality.
-
-   14,0x19 -- /dev/pssld where a read operation would output the
-                         current ld to user space
-                         where a write operation would effectively
-			 download a new ld.
-
-   14,0x09 -- /dev/psecho  would open up a communication path to the
-                         esc614 asic.  Given the ability to send
-			 messages to the asic and receive messages too.
-
-			 All messages would get read and written in the
-			 same manner.  It would be up to the application
-			 and the ld to maintain a relationship
-			 of what the messages mean.
-			
-			 for this device we need to implement select. */
-#define CODE_BUFFER_LEN (64*1024)
-static char    *code_buffer;
-static int      code_length;
+  /*
+     * Disable all emulations. Will be enabled later (if required).
+   */
+  OUTW (0x0000, REG (CONF_PSS));
+  OUTW (0x0000, REG (CONF_WSS));
+  OUTW (0x0000, REG (CONF_SB));
+  OUTW (0x0000, REG (CONF_MIDI));
+  OUTW (0x0000, REG (CONF_CDROM));
 
-static int      lock_pss = 0;
+  if (!set_irq (devc, CONF_PSS, devc->irq))
+    {
+      printk ("PSS: IRQ error\n");
+      return mem_start;
+    }
+
+  if (!set_dma (devc, CONF_PSS, devc->dma))
+    {
+      printk ("PSS: DRQ error\n");
+      return mem_start;
+    }
+
+  pss_initialized = 1;
+  printk (" <ECHO-PSS  Rev. %d>", id);
+
+  return mem_start;
+}
 
 int
-pss_open (int dev, struct fileinfo *file)
+probe_pss_mpu (struct address_info *hw_config)
 {
-  int             mode;
+  int             timeout;
+
+  if (!pss_initialized)
+    return 0;
 
-  DEB (printk ("pss_open\n"));
+  if (!set_io_base (devc, CONF_MIDI, hw_config->io_base))
+    {
+      printk ("PSS: MIDI base error.\n");
+      return 0;
+    }
 
-  if (pss_ok == 0)
-    return RET_ERROR (EIO);
+  if (!set_irq (devc, CONF_MIDI, hw_config->irq))
+    {
+      printk ("PSS: MIDI IRQ error.\n");
+      return 0;
+    }
 
-  if (lock_pss)
-    return 0;
+  if (!pss_synthLen)
+    {
+      printk ("PSS: Can't enable MPU. MIDI synth microcode not available.\n");
+      return 0;
+    }
+
+  if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
+    {
+      printk ("PSS: Unable to load MIDI synth microcode to DSP.\n");
+      return 0;
+    }
 
-  lock_pss = 1;
+/*
+ * Finally wait until the DSP algorithm has initialized itself and
+ * deactivates receive interrupt.
+ */
 
-  dev = dev >> 4;
-  mode = file->mode & O_ACCMODE;
-  if (mode == O_WRONLY)
+  for (timeout = 900000; timeout > 0; timeout--)
     {
-      printk ("pss-open for WRONLY\n");
-      code_length = 0;
+      if ((INB (hw_config->io_base + 1) & 0x80) == 0)	/* Input data avail */
+	INB (hw_config->io_base);	/* Discard it */
+      else
+	break;			/* No more input */
     }
 
-  RESET_WAIT_QUEUE (pss_sleeper, pss_sleep_flag);
-  return 1;
+#ifdef EXCLUDE_MIDI
+  return 0
+#else
+  return probe_mpu401 (hw_config);
+#endif
 }
 
-void
-pss_release (int dev, struct fileinfo *file)
+static int
+pss_coproc_open (void *dev_info, int sub_device)
 {
-  int             mode;
+  switch (sub_device)
+    {
+    case COPR_MIDI:
 
-  DEB (printk ("pss_release\n"));
-  if (pss_ok == 0)
-    return RET_ERROR (EIO);
-
-  dev = dev >> 4;
-  mode = file->mode & O_ACCMODE;
-  if (mode == O_WRONLY && code_length > 0)
-    {
-#ifdef linux
-      /* This just allows interrupts while the conversion is running */
-      __asm__ ("sti");
-#endif
-      if (!pss_download_boot (code_buffer, code_length))
+      if (pss_synthLen == 0)
 	{
-	  pss_reattach ();
+	  printk ("PSS: MIDI synth microcode not available.\n");
+	  return RET_ERROR (EIO);
 	}
+
+      if (nonstandard_microcode)
+	if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
+	  {
+	    printk ("PSS: Unable to load MIDI synth microcode to DSP.\n");
+	    return RET_ERROR (EIO);
+	  }
+      nonstandard_microcode = 0;
+      break;
+
+    default:;
     }
-  lock_pss = 0;
+  return 0;
 }
 
-int
-pss_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+static void
+pss_coproc_close (void *dev_info, int sub_device)
 {
-  int             c, p;
-
-  DEB (printk ("pss_read\n"));
-  if (pss_ok == 0)
-    return RET_ERROR (EIO);
-
-  dev = dev >> 4;
-  p = 0;
-  c = count;
+  return;
+}
 
-  return count - c;
+static void
+pss_coproc_reset (void *dev_info)
+{
+  if (pss_synthLen)
+    if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST))
+      {
+	printk ("PSS: Unable to load MIDI synth microcode to DSP.\n");
+      }
+  nonstandard_microcode = 0;
 }
 
-int
-pss_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count)
+static int
+download_boot_block (void *dev_info, copr_buffer * buf)
 {
-  DEB (printk ("pss_write\n"));
-  if (pss_ok == 0)
-    return RET_ERROR (EIO);
-  dev = dev >> 4;
+  if (buf->len <= 0 || buf->len > sizeof (buf->data))
+    return RET_ERROR (EINVAL);
 
-  if (count)			/* Flush output */
+  if (!pss_download_boot (devc, buf->data, buf->len, buf->flags))
     {
-      COPY_FROM_USER (&code_buffer[code_length], buf, 0, count);
-      code_length += count;
+      printk ("PSS: Unable to load microcode block to DSP.\n");
+      return RET_ERROR (EIO);
     }
-  return count;
-}
+  nonstandard_microcode = 1;	/* The MIDI microcode has been overwritten */
 
+  return 0;
+}
 
-int
-pss_ioctl (int dev, struct fileinfo *file,
-	   unsigned int cmd, unsigned int arg)
+static int
+pss_coproc_ioctl (void *dev_info, unsigned int cmd, unsigned int arg, int local)
 {
-  DEB (printk ("pss_ioctl dev=%d cmd=%x\n", dev, cmd));
-  if (pss_ok == 0)
-    return RET_ERROR (EIO);
-
-  dev = dev >> 4;
+  /* printk("PSS coproc ioctl %x %x %d\n", cmd, arg, local); */
 
   switch (cmd)
     {
-    case SNDCTL_PSS_RESET:
-      pss_reattach ();
-      return 1;
-
-    case SNDCTL_PSS_SETUP_REGISTERS:
-      pss_configure_registers_to_look_like_sb ();
-      return 1;
+    case SNDCTL_COPR_RESET:
+      pss_coproc_reset (dev_info);
+      return 0;
+      break;
+
+    case SNDCTL_COPR_LOAD:
+      {
+	copr_buffer    *buf;
+	int             err;
+
+	buf = (copr_buffer *) KERNEL_MALLOC (sizeof (copr_buffer));
+	IOCTL_FROM_USER ((char *) buf, (char *) arg, 0, sizeof (*buf));
+	err = download_boot_block (dev_info, buf);
+	KERNEL_FREE (buf);
+	return err;
+      }
+      break;
+
+    case SNDCTL_COPR_RDATA:
+      {
+	copr_debug_buf  buf;
+	unsigned long   flags;
+	unsigned short  tmp;
+
+	IOCTL_FROM_USER ((char *) &buf, (char *) arg, 0, sizeof (buf));
+
+	DISABLE_INTR (flags);
+	if (!pss_put_dspword (devc, 0x00d0))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	if (!pss_get_dspword (devc, &tmp))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	buf.parm1 = tmp;
+	RESTORE_INTR (flags);
+
+	IOCTL_TO_USER ((char *) arg, 0, &buf, sizeof (buf));
+	return 0;
+      }
+      break;
+
+    case SNDCTL_COPR_WDATA:
+      {
+	copr_debug_buf  buf;
+	unsigned long   flags;
+	unsigned short  tmp;
+
+	IOCTL_FROM_USER ((char *) &buf, (char *) arg, 0, sizeof (buf));
+
+	DISABLE_INTR (flags);
+	if (!pss_put_dspword (devc, 0x00d1))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	tmp = (unsigned int) buf.parm2 & 0xffff;
+	if (!pss_put_dspword (devc, tmp))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
 
-    case SNDCTL_PSS_SPEAKER:
+	RESTORE_INTR (flags);
+	return 0;
+      }
+      break;
+
+    case SNDCTL_COPR_WCODE:
       {
-	struct pss_speaker params;
-	COPY_FROM_USER (&params, (char *) arg, 0, sizeof (struct pss_speaker));
+	copr_debug_buf  buf;
+	unsigned long   flags;
+	unsigned short  tmp;
+
+	IOCTL_FROM_USER ((char *) &buf, (char *) arg, 0, sizeof (buf));
+
+	DISABLE_INTR (flags);
+	if (!pss_put_dspword (devc, 0x00d3))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff;
+	if (!pss_put_dspword (devc, tmp))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	tmp = (unsigned int) buf.parm2 & 0x00ff;
+	if (!pss_put_dspword (devc, tmp))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
 
-	pss_setspeaker (&params);
+	RESTORE_INTR (flags);
 	return 0;
       }
+      break;
+
+    case SNDCTL_COPR_RCODE:
+      {
+	copr_debug_buf  buf;
+	unsigned long   flags;
+	unsigned short  tmp;
+
+	IOCTL_FROM_USER ((char *) &buf, (char *) arg, 0, sizeof (buf));
+
+	DISABLE_INTR (flags);
+	if (!pss_put_dspword (devc, 0x00d2))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff)))
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	if (!pss_get_dspword (devc, &tmp))	/* Read msb */
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	buf.parm1 = tmp << 8;
+
+	if (!pss_get_dspword (devc, &tmp))	/* Read lsb */
+	  {
+	    RESTORE_INTR (flags);
+	    return RET_ERROR (EIO);
+	  }
+
+	buf.parm1 |= tmp & 0x00ff;
+
+	RESTORE_INTR (flags);
+
+	IOCTL_TO_USER ((char *) arg, 0, &buf, sizeof (buf));
+	return 0;
+      }
+      break;
+
     default:
-      return RET_ERROR (EIO);
+      return RET_ERROR (EINVAL);
     }
+
+  return RET_ERROR (EINVAL);
 }
 
-/* This is going to be used to implement
-   waiting on messages sent from the DSP and to the
-   DSP when communication is used via the pss directly.
+static coproc_operations pss_coproc_operations =
+{
+  "ADSP-2115",
+  pss_coproc_open,
+  pss_coproc_close,
+  pss_coproc_ioctl,
+  pss_coproc_reset,
+  &pss_data
+};
 
-   We need to find out if the pss can generate a different
-   interrupt other than the one it has been setup for.
+long
+attach_pss_mpu (long mem_start, struct address_info *hw_config)
+{
+  int             prev_devs;
+  long            ret;
 
-   This way we can carry on a conversation with the pss
-   on a separate channel.  This would be useful for debugging. */
+#ifndef EXCLUDE_MIDI
+  prev_devs = num_midis;
+  ret = attach_mpu401 (mem_start, hw_config);
 
-pss_select (int dev, struct fileinfo * file, int sel_type, select_table * wait)
+  if (num_midis == (prev_devs + 1))	/* The MPU driver installed itself */
+    midi_devs[prev_devs]->coproc = &pss_coproc_operations;
+#endif
+  return ret;
+}
+
+int
+probe_pss_mss (struct address_info *hw_config)
 {
-  return 0;
-  if (pss_ok == 0)
-    return RET_ERROR (EIO);
+  int             timeout;
 
-  dev = dev >> 4;
+  if (!pss_initialized)
+    return 0;
 
-  switch (sel_type)
+  if (!set_io_base (devc, CONF_WSS, hw_config->io_base))
     {
-    case SEL_IN:
-      select_wait (&pss_sleeper, wait);
+      printk ("PSS: WSS base error.\n");
       return 0;
-      break;
+    }
 
-    case SEL_OUT:
-      select_wait (&pss_sleeper, wait);
+  if (!set_irq (devc, CONF_WSS, hw_config->irq))
+    {
+      printk ("PSS: WSS IRQ error.\n");
       return 0;
-      break;
+    }
 
-    case SEL_EX:
+  if (!set_dma (devc, CONF_WSS, hw_config->dma))
+    {
+      printk ("PSS: WSS DRQ error\n");
       return 0;
     }
 
-  return 0;
+  /*
+     * For some reason the card returns 0xff in the WSS status register
+     * immediately after boot. Propably MIDI+SB emulation algorithm
+     * downloaded to the ADSP2115 spends some time initializing the card.
+     * Let's try to wait until it finishes this task.
+   */
+  for (timeout = 0;
+       timeout < 100000 && (INB (hw_config->io_base + 3) & 0x3f) != 0x04;
+       timeout++);
+
+  return probe_ms_sound (hw_config);
 }
 
 long
-pss_init (long mem_start)
+attach_pss_mss (long mem_start, struct address_info *hw_config)
 {
-  DEB (printk ("pss_init\n"));
-  if (pss_ok)
-    {
-      code_buffer = mem_start;
-      mem_start += CODE_BUFFER_LEN;
-    }
-  return mem_start;
+  int             prev_devs;
+  long            ret;
+
+  prev_devs = num_audiodevs;
+  ret = attach_ms_sound (mem_start, hw_config);
+
+  if (num_audiodevs == (prev_devs + 1))		/* The MSS driver installed itself */
+    audio_devs[prev_devs]->coproc = &pss_coproc_operations;
+
+  return ret;
 }
 
 #endif
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb16_dsp.c linux/drivers/sound/sb16_dsp.c
--- v1.3.8/linux/drivers/sound/sb16_dsp.c	Tue Aug 23 09:48:52 1994
+++ linux/drivers/sound/sb16_dsp.c	Mon Jul 10 01:45:17 1995
@@ -42,11 +42,11 @@
 
 extern int      sbc_base;
 
-static int      sb16_dsp_ok = 0;/*
+static int      sb16_dsp_ok = 0;	/*
 
 
-					 * *  * * Set to 1 after successful *
-					 * * initialization   */
+					   * *  * * Set to 1 after successful *
+					   * * initialization   */
 static int      dsp_16bit = 0;
 static int      dsp_stereo = 0;
 static int      dsp_current_speed = 8000;	/*
@@ -228,7 +228,7 @@
 
   sb_reset_dsp ();
 
-  if (ALLOC_DMA_CHN (dma8,"sb16 8bit"))
+  if (ALLOC_DMA_CHN (dma8, "SB16 (8bit)"))
     {
       printk ("SB16: Unable to grab DMA%d\n", dma8);
       sb_free_irq ();
@@ -236,7 +236,7 @@
     }
 
   if (dma16 != dma8)
-    if (ALLOC_DMA_CHN (dma16,"sb16 16bit"))
+    if (ALLOC_DMA_CHN (dma16, "SB16 (16bit)"))
       {
 	printk ("SB16: Unable to grab DMA%d\n", dma16);
 	sb_free_irq ();
@@ -436,6 +436,7 @@
       sb_dsp_command01 (0xda);
       sb_dsp_command01 (0xd0);
     }
+  DMAbuf_reset_dma (dev);
 }
 
 static void
@@ -472,9 +473,7 @@
   if (sbc_major < 4)
     return mem_start;		/* Not a SB16 */
 
-#ifndef SCO
   sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
-#endif
 
   printk (" <%s>", sb16_dsp_operations.name);
 
@@ -532,8 +531,8 @@
   DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, hw_config->dma));
 
   /*
- * dsp_showmessage(0xe3,99);
- */
+     * dsp_showmessage(0xe3,99);
+   */
   sb16_dsp_ok = 1;
   return 1;
 }
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb16_midi.c linux/drivers/sound/sb16_midi.c
--- v1.3.8/linux/drivers/sound/sb16_midi.c	Thu Oct 13 13:50:51 1994
+++ linux/drivers/sound/sb16_midi.c	Mon Jul 10 01:45:17 1995
@@ -180,6 +180,7 @@
 {
   {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI},
   &std_midi_synth,
+  {0},
   sb16midi_open,
   sb16midi_close,
   sb16midi_ioctl,
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v1.3.8/linux/drivers/sound/sb_card.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/sb_card.c	Mon Jul 10 01:45:17 1995
@@ -25,6 +25,9 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
+ * Modified:
+ *  Riccardo Facchetti  24 Mar 1995
+ *  - Added the Audio Excel DSP 16 initialization routine.
  */
 
 #include "sound_config.h"
@@ -46,6 +49,12 @@
 int
 probe_sb (struct address_info *hw_config)
 {
+#if !defined(EXCLUDE_AEDSP16) && defined(AEDSP16_SBPRO)
+  /*
+     * Initialize Audio Excel DSP 16 to SBPRO.
+   */
+  InitAEDSP16_SBPRO (hw_config);
+#endif
   return sb_dsp_detect (hw_config);
 }
 
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c
--- v1.3.8/linux/drivers/sound/sb_dsp.c	Wed Jan 18 09:38:50 1995
+++ linux/drivers/sound/sb_dsp.c	Mon Jul 10 01:45:18 1995
@@ -26,9 +26,11 @@
  * SUCH DAMAGE.
  *
  * Modified:
- *	Hunyue Yau	Jan 6 1994
- *	Added code to support Sound Galaxy NX Pro
+ *      Hunyue Yau      Jan 6 1994
+ *      Added code to support Sound Galaxy NX Pro
  *
+ *      JRA Gibson      April 1995
+ *      Code added for MV ProSonic/Jazz 16 in 16 bit mode
  */
 
 #include "sound_config.h"
@@ -42,6 +44,8 @@
 int             sbc_base = 0;
 static int      sbc_irq = 0;
 static int      open_mode = 0;	/* Read, write or both */
+int             Jazz16_detected = 0;
+int             sb_no_recording = 0;
 
 /*
  * The DSP channel can be used either for input or output. Variable
@@ -83,6 +87,21 @@
 						 * IMODE_NONE   */
 static volatile int irq_ok = 0;
 
+#ifdef JAZZ16
+/* 16 bit support
+ */
+
+static int      dsp_16bit = 0;
+static int      dma8 = 1;
+static int      dma16 = 5;
+
+static int      dsp_set_bits (int arg);
+static int      initialize_ProSonic16 (void);
+
+/* end of 16 bit support
+ */
+#endif
+
 int             sb_duplex_midi = 0;
 static int      my_dev = 0;
 
@@ -104,8 +123,8 @@
   int             i;
   unsigned long   limit;
 
-  limit = GET_TIME () + HZ / 10;/*
-					   * The timeout is 0.1 seconds
+  limit = GET_TIME () + HZ / 10;	/*
+					   * The timeout is 0.1 secods
 					 */
 
   /*
@@ -131,27 +150,22 @@
 }
 
 void
-sbintr (int unit, struct pt_regs *regs)
+sbintr (INT_HANDLER_PARMS (irq, dummy))
 {
   int             status;
 
 #ifndef EXCLUDE_SBPRO
   if (sb16)
     {
-      unsigned char   src = sb_getmixer (IRQ_STAT);	/*
-
-
-							 * *  * * Interrupt
-							 * source * *
-							 * register   */
+      unsigned char   src = sb_getmixer (IRQ_STAT);	/* Interrupt source register */
 
 #ifndef EXCLUDE_SB16
       if (src & 3)
-	sb16_dsp_interrupt (unit);
+	sb16_dsp_interrupt (irq);
 
 #ifndef EXCLUDE_MIDI
       if (src & 4)
-	sb16midiintr (unit);	/*
+	sb16midiintr (irq);	/*
 				 * SB MPU401 interrupt
 				 */
 #endif
@@ -160,13 +174,13 @@
 
       if (!(src & 1))
 	return;			/*
-				 * Not a DSP interrupt
+				 * Not a DSP interupt
 				 */
     }
 #endif
 
-  status = INB (DSP_DATA_AVAIL);/*
-					 * Clear interrupt
+  status = INB (DSP_DATA_AVAIL);	/*
+					   * Clear interrupt
 					 */
 
   if (sb_intr_active)
@@ -192,7 +206,7 @@
 
       case IMODE_MIDI:
 #ifndef EXCLUDE_MIDI
-	sb_midi_interrupt (unit);
+	sb_midi_interrupt (irq);
 #endif
 	break;
 
@@ -209,7 +223,7 @@
   int             ok;
 
   if (!sb_irq_usecount)
-    if ((ok = snd_set_irq_handler (sbc_irq, sbintr)) < 0)
+    if ((ok = snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster")) < 0)
       return ok;
 
   sb_irq_usecount++;
@@ -282,16 +296,16 @@
     speed = 4000;
 
   /*
- * Older SB models don't support higher speeds than 22050.
- */
+     * Older SB models don't support higher speeds than 22050.
+   */
 
   if (sbc_major < 2 ||
       (sbc_major == 2 && sbc_minor == 0))
     max_speed = 22050;
 
   /*
- * SB models earlier than SB Pro have low limit for the input speed.
- */
+     * SB models earlier than SB Pro have low limit for the input speed.
+   */
   if (open_mode != OPEN_WRITE)	/* Recording is possible */
     if (sbc_major < 3)		/* Limited input speed with these cards */
       if (sbc_major == 2 && sbc_minor > 0)
@@ -304,11 +318,14 @@
 				 * Invalid speed
 				 */
 
-  if (dsp_stereo && speed > 22050)
-    speed = 22050;
+  /* Logitech SoundMan Games and Jazz16 cards can support 44.1kHz stereo */
+#if !defined (SM_GAMES)
   /*
    * Max. stereo speed is 22050
    */
+  if (dsp_stereo && speed > 22050 && Jazz16_detected == 0)
+    speed = 22050;
+#endif
 
   if ((speed > 22050) && sb_midi_busy)
     {
@@ -349,7 +366,7 @@
       tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
 
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x40))/*
+      if (sb_dsp_command (0x40))	/*
 					 * Set time constant
 					 */
 	sb_dsp_command (tconst);
@@ -409,14 +426,14 @@
   if (sb_dsp_highspeed)
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x48))/*
-					 * High speed size
+      if (sb_dsp_command (0x48))	/*
+					   * High speed size
 					 */
 	{
 	  sb_dsp_command ((unsigned char) (count & 0xff));
 	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
-	  sb_dsp_command (0x91);/*
-					 * High speed 8 bit DAC
+	  sb_dsp_command (0x91);	/*
+					   * High speed 8 bit DAC
 					 */
 	}
       else
@@ -426,8 +443,8 @@
   else
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x14))/*
-					 * 8-bit DAC (DMA)
+      if (sb_dsp_command (0x14))	/*
+					   * 8-bit DAC (DMA)
 					 */
 	{
 	  sb_dsp_command ((unsigned char) (count & 0xff));
@@ -463,14 +480,14 @@
   if (sb_dsp_highspeed)
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x48))/*
-					 * High speed size
+      if (sb_dsp_command (0x48))	/*
+					   * High speed size
 					 */
 	{
 	  sb_dsp_command ((unsigned char) (count & 0xff));
 	  sb_dsp_command ((unsigned char) ((count >> 8) & 0xff));
-	  sb_dsp_command (0x99);/*
-					 * High speed 8 bit ADC
+	  sb_dsp_command (0x99);	/*
+					   * High speed 8 bit ADC
 					 */
 	}
       else
@@ -480,8 +497,8 @@
   else
     {
       DISABLE_INTR (flags);
-      if (sb_dsp_command (0x24))/*
-					 * 8-bit ADC (DMA)
+      if (sb_dsp_command (0x24))	/*
+					   * 8-bit ADC (DMA)
 					 */
 	{
 	  sb_dsp_command ((unsigned char) (count & 0xff));
@@ -511,11 +528,23 @@
 				 * SB Pro
 				 */
     {
+#ifdef JAZZ16
+      /* Select correct dma channel
+         * for 16/8 bit acccess
+       */
+      audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
+      if (dsp_stereo)
+	sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
+      else
+	sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
+#else
+      /* 8 bit only cards use this
+       */
       if (dsp_stereo)
 	sb_dsp_command (0xa8);
       else
 	sb_dsp_command (0xa0);
-
+#endif
       dsp_speed (dsp_current_speed);	/*
 					 * Speed must be recalculated if
 					 * #channels * changes
@@ -535,7 +564,19 @@
 				 * SB Pro
 				 */
     {
+#ifdef JAZZ16
+      /* 16 bit specific instructions
+       */
+      audio_devs[my_dev]->dmachan = dsp_16bit ? dma16 : dma8;
+      if (Jazz16_detected != 2)	/* SM Wave */
+	sb_mixer_set_stereo (dsp_stereo);
+      if (dsp_stereo)
+	sb_dsp_command (dsp_16bit ? 0xac : 0xa8);
+      else
+	sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0);
+#else
       sb_mixer_set_stereo (dsp_stereo);
+#endif
       dsp_speed (dsp_current_speed);	/*
 					 * Speed must be recalculated if
 					 * #channels * changes
@@ -597,6 +638,12 @@
       return RET_ERROR (ENXIO);
     }
 
+  if (sb_no_recording && mode & OPEN_READ)
+    {
+      printk ("SB Error: Recording not supported by this device\n");
+      return RET_ERROR (ENOTTY);
+    }
+
   if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI))
     {
       printk ("SB: PCM not possible during MIDI input\n");
@@ -616,12 +663,32 @@
   if (retval)
     return retval;
 
+  /* Allocate 8 bit dma
+   */
+#ifdef JAZZ16
+  audio_devs[my_dev]->dmachan = dma8;
+#endif
+
   if (DMAbuf_open_dma (dev) < 0)
     {
       sb_free_irq ();
       printk ("SB: DMA Busy\n");
       return RET_ERROR (EBUSY);
     }
+#ifdef JAZZ16
+  /* Allocate 16 bit dma
+   */
+  if (Jazz16_detected != 0)
+    if (dma16 != dma8)
+      {
+	if (ALLOC_DMA_CHN (dma16, "Jazz16 16 bit"))
+	  {
+	    sb_free_irq ();
+	    DMAbuf_close_dma (dev);
+	    return RET_ERROR (EBUSY);
+	  }
+      }
+#endif
 
   sb_irq_mode = IMODE_NONE;
 
@@ -634,6 +701,19 @@
 static void
 sb_dsp_close (int dev)
 {
+#ifdef JAZZ16
+  /* Release 16 bit dma channel
+   */
+  if (Jazz16_detected)
+    {
+      if (audio_devs[my_dev]->dmachan == dma8)
+	RELEASE_DMA_CHN (dma16);
+      else
+	RELEASE_DMA_CHN (dma8);
+
+    }
+#endif
+
   DMAbuf_close_dma (dev);
   sb_free_irq ();
   dsp_cleanup ();
@@ -643,6 +723,32 @@
   open_mode = 0;
 }
 
+#ifdef JAZZ16
+/* Function dsp_set_bits() only required for 16 bit cards
+ */
+static int
+dsp_set_bits (int arg)
+{
+  if (arg)
+    if (Jazz16_detected == 0)
+      dsp_16bit = 0;
+    else
+      switch (arg)
+	{
+	case 8:
+	  dsp_16bit = 0;
+	  break;
+	case 16:
+	  dsp_16bit = 1;
+	  break;
+	default:
+	  dsp_16bit = 0;
+	}
+  return dsp_16bit ? 16 : 8;
+}
+
+#endif /* ifdef JAZZ16 */
+
 static int
 sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
 {
@@ -678,14 +784,31 @@
       return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg)));
       break;
 
+#ifdef JAZZ16
+      /* Word size specific cases here.
+         * SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS
+       */
+    case SNDCTL_DSP_SETFMT:
+      if (local)
+	return dsp_set_bits (arg);
+      return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg)));
+      break;
+
+    case SOUND_PCM_READ_BITS:
+      if (local)
+	return dsp_16bit ? 16 : 8;
+      return IOCTL_OUT (arg, dsp_16bit ? 16 : 8);
+      break;
+#else
     case SOUND_PCM_WRITE_BITS:
     case SOUND_PCM_READ_BITS:
       if (local)
 	return 8;
-      return IOCTL_OUT (arg, 8);/*
-					 * Only 8 bits/sample supported
+      return IOCTL_OUT (arg, 8);	/*
+					   * Only 8 bits/sample supported
 					 */
       break;
+#endif /* ifdef JAZZ16  */
 
     case SOUND_PCM_WRITE_FILTER:
     case SOUND_PCM_READ_FILTER:
@@ -715,6 +838,232 @@
 
 #endif
 
+
+#ifdef JAZZ16
+
+/*
+ * Initialization of a Media Vision ProSonic 16 Soundcard.
+ * The function initializes a ProSonic 16 like PROS.EXE does for DOS. It sets
+ * the base address, the DMA-channels, interrupts and enables the joystickport.
+ *
+ * Also used by Jazz 16 (same card, different name)
+ *
+ * written 1994 by Rainer Vranken
+ * E-Mail: rvranken@polaris.informatik.uni-essen.de
+ */
+
+
+#ifndef MPU_BASE		/* take default values if not specified */
+#define MPU_BASE 0x330
+#endif
+#ifndef MPU_IRQ
+#define MPU_IRQ 9
+#endif
+
+unsigned int
+get_sb_byte (void)
+{
+  int             i;
+
+  for (i = 1000; i; i--)
+    if (INB (DSP_DATA_AVAIL) & 0x80)
+      {
+	return INB (DSP_READ);
+      }
+
+  return 0xffff;
+}
+
+#ifdef SM_WAVE
+/*
+ * Logitech Soundman Wave detection and initialization by Hannu Savolainen.
+ *
+ * There is a microcontroller (8031) in the SM Wave card for MIDI emulation.
+ * it's located at address MPU_BASE+4.  MPU_BASE+7 is a SM Wave specific
+ * control register for MC reset, SCSI, OPL4 and DSP (future expansion)
+ * address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16
+ * based soundcard.
+ */
+
+static void
+smw_putmem (int base, int addr, unsigned char val)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+
+  OUTB (addr & 0xff, base + 1);	/* Low address bits */
+  OUTB (addr >> 8, base + 2);	/* High address bits */
+  OUTB (val, base);		/* Data */
+
+  RESTORE_INTR (flags);
+}
+
+static unsigned char
+smw_getmem (int base, int addr)
+{
+  unsigned long   flags;
+  unsigned char   val;
+
+  DISABLE_INTR (flags);
+
+  OUTB (addr & 0xff, base + 1);	/* Low address bits */
+  OUTB (addr >> 8, base + 2);	/* High address bits */
+  val = INB (base);		/* Data */
+
+  RESTORE_INTR (flags);
+  return val;
+}
+
+static int
+initialize_smw (void)
+{
+#ifdef SMW_MIDI0001_INCLUDED
+#include "smw-midi0001.h"
+#else
+  unsigned char   smw_ucode[1];
+  int             smw_ucodeLen = 0;
+
+#endif
+
+  int             mp_base = MPU_BASE + 4;	/* Microcontroller base */
+  int             i;
+  unsigned char   control;
+
+  /*
+     *  Reset the microcontroller so that the RAM can be accessed
+   */
+
+  control = INB (MPU_BASE + 7);
+  OUTB (control | 3, MPU_BASE + 7);	/* Set last two bits to 1 (?) */
+  OUTB ((control & 0xfe) | 2, MPU_BASE + 7);	/* xxxxxxx0 resets the mc */
+
+  for (i = 0; i < 300; i++)	/* Wait at least 1ms */
+    tenmicrosec ();
+
+  OUTB (control & 0xfc, MPU_BASE + 7);	/* xxxxxx00 enables RAM */
+
+  /*
+     *  Detect microcontroller by probing the 8k RAM area
+   */
+  smw_putmem (mp_base, 0, 0x00);
+  smw_putmem (mp_base, 1, 0xff);
+  tenmicrosec ();
+
+  if (smw_getmem (mp_base, 0) != 0x00 || smw_getmem (mp_base, 1) != 0xff)
+    {
+      printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n",
+	      smw_getmem (mp_base, 0), smw_getmem (mp_base, 1));
+      return 0;			/* No RAM */
+    }
+
+  /*
+     *  There is RAM so assume it's really a SM Wave
+   */
+
+#ifdef SMW_MIDI0001_INCLUDED
+  if (smw_ucodeLen != 8192)
+    {
+      printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n");
+      return 1;
+    }
+#endif
+
+  /*
+     *  Download microcode
+   */
+
+  for (i = 0; i < 8192; i++)
+    smw_putmem (mp_base, i, smw_ucode[i]);
+
+  /*
+     *  Verify microcode
+   */
+
+  for (i = 0; i < 8192; i++)
+    if (smw_getmem (mp_base, i) != smw_ucode[i])
+      {
+	printk ("SM Wave: Microcode verification failed\n");
+	return 0;
+      }
+
+  control = 0;
+#ifdef SMW_SCSI_IRQ
+  /*
+     * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt
+     * is disabled by default.
+     *
+     * Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10.
+   */
+  {
+    static unsigned char scsi_irq_bits[] =
+    {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0};
+
+    control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6;
+  }
+#endif
+
+#ifdef SMW_OPL4_ENABLE
+  /*
+     *  Make the OPL4 chip visible on the PC bus at 0x380.
+     *
+     *  There is no need to enable this feature since VoxWare
+     *  doesn't support OPL4 yet. Also there is no RAM in SM Wave so
+     *  enabling OPL4 is pretty useless.
+   */
+  control |= 0x10;		/* Uses IRQ12 if bit 0x20 == 0 */
+  /* control |= 0x20;      Uncomment this if you want to use IRQ7 */
+#endif
+
+  OUTB (control | 0x03, MPU_BASE + 7);	/* xxxxxx11 restarts */
+  return 1;
+}
+
+#endif
+
+static int
+initialize_ProSonic16 (void)
+{
+  int             x;
+  static unsigned char int_translat[16] =
+  {0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, dma_translat[8] =
+  {0, 1, 0, 2, 0, 3, 0, 4};
+
+  OUTB (0xAF, 0x201);		/* ProSonic/Jazz16 wakeup */
+  for (x = 0; x < 1000; ++x)	/* wait 10 milliseconds */
+    tenmicrosec ();
+  OUTB (0x50, 0x201);
+  OUTB ((sbc_base & 0x70) | ((MPU_BASE & 0x30) >> 4), 0x201);
+
+  if (sb_reset_dsp ())
+    {				/* OK. We have at least a SB */
+
+      /* Check the version number of ProSonic (I guess) */
+
+      if (!sb_dsp_command (0xFA))
+	return 1;
+      if (get_sb_byte () != 0x12)
+	return 1;
+
+      if (sb_dsp_command (0xFB) &&	/* set DMA-channels and Interrupts */
+	  sb_dsp_command ((dma_translat[JAZZ_DMA16] << 4) | dma_translat[SBC_DMA]) &&
+      sb_dsp_command ((int_translat[MPU_IRQ] << 4) | int_translat[sbc_irq]))
+	{
+	  Jazz16_detected = 1;
+#ifdef SM_WAVE
+	  if (initialize_smw ())
+	    Jazz16_detected = 2;
+#endif
+	  sb_dsp_disable_midi ();
+	}
+
+      return 1;			/* There was at least a SB */
+    }
+  return 0;			/* No SB or ProSonic16 detected */
+}
+
+#endif /* ifdef JAZZ16  */
+
 int
 sb_dsp_detect (struct address_info *hw_config)
 {
@@ -725,9 +1074,16 @@
     return 0;			/*
 				 * Already initialized
 				 */
+#ifdef JAZZ16
+  dma8 = hw_config->dma;
+  dma16 = JAZZ_DMA16;
 
+  if (!initialize_ProSonic16 ())
+    return 0;
+#else
   if (!sb_reset_dsp ())
     return 0;
+#endif
 
   return 1;			/*
 				 * Detected
@@ -792,6 +1148,9 @@
 #ifndef EXCLUDE_SBPRO
   if (sbc_major >= 3)
     mixer_type = sb_mixer_init (sbc_major);
+#else
+  if (sbc_major >= 3)
+    printk ("\n\n\n\nNOTE! SB Pro support is required with your soundcard!\n\n\n");
 #endif
 
 #ifndef EXCLUDE_YM3812
@@ -801,31 +1160,42 @@
     enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH);
 #endif
 
+#ifndef EXCLUDE_AUDIO
   if (sbc_major >= 3)
     {
-#if !defined(SCO) && !defined(EXCLUDE_AUDIO)
-#  ifdef __SGNXPRO__
+      if (Jazz16_detected)
+	{
+	  if (Jazz16_detected == 2)
+	    sprintf (sb_dsp_operations.name, "SoundMan Wave %d.%d", sbc_major, sbc_minor);
+	  else
+	    sprintf (sb_dsp_operations.name, "MV Jazz16 %d.%d", sbc_major, sbc_minor);
+	  sb_dsp_operations.format_mask |= AFMT_S16_LE;		/* Hurrah, 16 bits          */
+	}
+      else
+#ifdef __SGNXPRO__
       if (mixer_type == 2)
 	{
 	  sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
 	}
       else
-#  endif
+#endif
+
+      if (sbc_major == 4)
+	{
+	  sprintf (sb_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
+	}
+      else
 	{
 	  sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
 	}
-#endif
     }
   else
     {
-#ifndef SCO
       sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor);
-#endif
     }
 
   printk (" <%s>", sb_dsp_operations.name);
 
-#ifndef EXCLUDE_AUDIO
 #if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO)
   if (!sb16)			/*
 				 * There is a better driver for SB16
@@ -840,6 +1210,8 @@
       }
     else
       printk ("SB: Too many DSP devices available\n");
+#else
+  printk (" <SoundBlaster (configured without audio support)>");
 #endif
 
 #ifndef EXCLUDE_MIDI
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_midi.c linux/drivers/sound/sb_midi.c
--- v1.3.8/linux/drivers/sound/sb_midi.c	Fri Aug 19 08:54:09 1994
+++ linux/drivers/sound/sb_midi.c	Mon Jul 10 01:45:18 1995
@@ -42,7 +42,7 @@
  * future version of this driver.
  */
 
-extern int      sb_dsp_ok;	/* Set to 1 after successful initialization */
+extern int      sb_dsp_ok;	/* Set to 1 atfer successful initialization */
 extern int      sbc_base;
 
 extern int      sb_midi_mode;
@@ -217,6 +217,7 @@
 {
   {"SoundBlaster", 0, 0, SNDCARD_SB},
   &std_midi_synth,
+  {0},
   sb_midi_open,
   sb_midi_close,
   sb_midi_ioctl,
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v1.3.8/linux/drivers/sound/sb_mixer.c	Wed Jul 20 15:00:55 1994
+++ linux/drivers/sound/sb_mixer.c	Mon Jul 10 01:45:19 1995
@@ -27,8 +27,8 @@
  * SUCH DAMAGE.
  *
  * Modified:
- *	Hunyue Yau	Jan 6 1994
- *	Added code to support the Sound Galaxy NX Pro mixer.
+ *      Hunyue Yau      Jan 6 1994
+ *      Added code to support the Sound Galaxy NX Pro mixer.
  *
  */
 
@@ -42,6 +42,7 @@
 #undef SB_TEST_IRQ
 
 extern int      sbc_base;
+extern int      Jazz16_detected;
 
 static int      mixer_initialized = 0;
 
@@ -97,9 +98,9 @@
 
 /*
  * Returns:
- *	0	No mixer detected.
- *	1	Only a plain Sound Blaster Pro style mixer detected.
- *	2	The Sound Galaxy NX Pro mixer detected.
+ *      0       No mixer detected.
+ *      1       Only a plain Sound Blaster Pro style mixer detected.
+ *      2       The Sound Galaxy NX Pro mixer detected.
  */
 static int
 detect_mixer (void)
@@ -109,6 +110,7 @@
 
 #endif
   int             retcode = 1;
+  extern int      sbc_major;
 
   /*
    * Detect the mixer by changing parameters of two volume channels. If the
@@ -127,8 +129,8 @@
 
 #ifdef __SGNXPRO__
   /* Attempt to detect the SG NX Pro by check for valid bass/treble
- * registers.
- */
+     * registers.
+   */
   oldbass = sb_getmixer (BASS_LVL);
   oldtreble = sb_getmixer (TREBLE_LVL);
 
@@ -147,6 +149,21 @@
    */
   sb_setmixer (BASS_LVL, oldbass);
   sb_setmixer (TREBLE_LVL, oldtreble);
+
+  /*
+     * If the SB version is 3.X (SB Pro), assume we have a SG NX Pro 16.
+     * In this case it's good idea to disable the Disney Sound Source
+     * compatibility mode. It's useless and just causes noise every time the
+     * LPT-port is accessed.
+     *
+     * Also place the card into WSS mode.
+   */
+  if (sbc_major == 3)
+    {
+      OUTB (0x01, sbc_base + 0x1c);
+      OUTB (0x00, sbc_base + 0x1a);
+    }
+
 #endif
   return retcode;
 }
@@ -181,6 +198,100 @@
   return levels[dev];
 }
 
+#ifdef JAZZ16
+static char     smw_mix_regs[] =	/* Left mixer registers */
+{
+  0x0b,				/* SOUND_MIXER_VOLUME */
+  0x0d,				/* SOUND_MIXER_BASS */
+  0x0d,				/* SOUND_MIXER_TREBLE */
+  0x05,				/* SOUND_MIXER_SYNTH */
+  0x09,				/* SOUND_MIXER_PCM */
+  0x00,				/* SOUND_MIXER_SPEAKER */
+  0x03,				/* SOUND_MIXER_LINE */
+  0x01,				/* SOUND_MIXER_MIC */
+  0x07,				/* SOUND_MIXER_CD */
+  0x00,				/* SOUND_MIXER_IMIX */
+  0x00,				/* SOUND_MIXER_ALTPCM */
+  0x00,				/* SOUND_MIXER_RECLEV */
+  0x00,				/* SOUND_MIXER_IGAIN */
+  0x00,				/* SOUND_MIXER_OGAIN */
+  0x00,				/* SOUND_MIXER_LINE1 */
+  0x00,				/* SOUND_MIXER_LINE2 */
+  0x00				/* SOUND_MIXER_LINE3 */
+};
+
+static void
+smw_mixer_init (void)
+{
+  int             i;
+
+  sb_setmixer (0x00, 0x18);	/* Mute unused (Telephone) line */
+  sb_setmixer (0x10, 0x38);	/* Config register 2 */
+
+  supported_devices = 0;
+  for (i = 0; i < sizeof (smw_mix_regs); i++)
+    if (smw_mix_regs[i] != 0)
+      supported_devices |= (1 << i);
+
+  supported_rec_devices = supported_devices &
+    ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM |
+      SOUND_MASK_VOLUME);
+}
+
+static int
+smw_mixer_set (int dev, int value)
+{
+  int             left = value & 0x000000ff;
+  int             right = (value & 0x0000ff00) >> 8;
+  int             reg, val;
+
+  if (left > 100)
+    left = 100;
+  if (right > 100)
+    right = 100;
+
+  if (dev > 31)
+    return RET_ERROR (EINVAL);
+
+  if (!(supported_devices & (1 << dev)))	/* Not supported */
+    return RET_ERROR (EINVAL);
+
+  switch (dev)
+    {
+    case SOUND_MIXER_VOLUME:
+      sb_setmixer (0x0b, 96 - (96 * left / 100));	/* 96=mute, 0=max */
+      sb_setmixer (0x0c, 96 - (96 * right / 100));
+      break;
+
+    case SOUND_MIXER_BASS:
+    case SOUND_MIXER_TREBLE:
+      levels[dev] = left | (right << 8);
+
+      /* Set left bass and treble values */
+      val = ((levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / 100) << 4;
+      val |= ((levels[SOUND_MIXER_BASS] & 0xff) * 16 / 100) & 0x0f;
+      sb_setmixer (0x0d, val);
+
+      /* Set right bass and treble values */
+      val = (((levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / 100) << 4;
+      val |= (((levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / 100) & 0x0f;
+      sb_setmixer (0x0e, val);
+      break;
+
+    default:
+      reg = smw_mix_regs[dev];
+      if (reg == 0)
+	return RET_ERROR (EINVAL);
+      sb_setmixer (reg, (24 - (24 * left / 100)) | 0x20);	/* 24=mute, 0=max */
+      sb_setmixer (reg + 1, (24 - (24 * right / 100)) | 0x40);
+    }
+
+  levels[dev] = left | (right << 8);
+  return left | (right << 8);
+}
+
+#endif
+
 static int
 sb_mixer_set (int dev, int value)
 {
@@ -190,6 +301,11 @@
   int             regoffs;
   unsigned char   val;
 
+#ifdef JAZZ16
+  if (Jazz16_detected == 2)
+    return smw_mixer_set (dev, value);
+#endif
+
   if (left > 100)
     left = 100;
   if (right > 100)
@@ -233,6 +349,7 @@
     }
 
   change_bits (&val, dev, RIGHT_CHN, right);
+
   sb_setmixer (regoffs, val);
 
   levels[dev] = left | (right << 8);
@@ -337,6 +454,7 @@
 	    break;
 
 	  default:
+
 	    return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
 	  }
       else
@@ -354,8 +472,11 @@
 	    break;
 
 	  case SOUND_MIXER_STEREODEVS:
-	    return IOCTL_OUT (arg, supported_devices &
-			      ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
+	    if (Jazz16_detected)
+	      return IOCTL_OUT (arg, supported_devices);
+	    else
+	      return IOCTL_OUT (arg, supported_devices &
+				~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER));
 	    break;
 
 	  case SOUND_MIXER_RECMASK:
@@ -376,6 +497,7 @@
 
 static struct mixer_operations sb_mixer_operations =
 {
+  "SoundBlaster",
   sb_mixer_ioctl
 };
 
@@ -414,6 +536,18 @@
     {
     case 3:
       mixer_caps = SOUND_CAP_EXCL_INPUT;
+
+#ifdef JAZZ16
+      if (Jazz16_detected == 2)	/* SM Wave */
+	{
+	  supported_devices = 0;
+	  supported_rec_devices = 0;
+	  iomap = &sbpro_mix;
+	  smw_mixer_init ();
+	  mixer_type = 1;
+	}
+      else
+#endif
 #ifdef __SGNXPRO__
       if (mixer_type == 2)	/* A SGNXPRO was detected */
 	{
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h
--- v1.3.8/linux/drivers/sound/sb_mixer.h	Wed Jul 20 15:00:55 1994
+++ linux/drivers/sound/sb_mixer.h	Thu Apr 27 22:21:53 1995
@@ -51,7 +51,8 @@
 					 SOUND_MASK_CD)
 
 #define SB16_MIXER_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
-					 SOUND_MASK_CD | SOUND_MASK_RECLEV | \
+					 SOUND_MASK_CD | \
+					 SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
 					 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
 
 /*
@@ -144,7 +145,9 @@
 MIX_ENT(SOUND_MIXER_CD,		0x28, 7, 4, 0x28, 3, 4),
 MIX_ENT(SOUND_MIXER_IMIX,	0x00, 0, 0, 0x00, 0, 0),
 MIX_ENT(SOUND_MIXER_ALTPCM,	0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV,	0x00, 0, 0, 0x00, 0, 0)
+MIX_ENT(SOUND_MIXER_RECLEV,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_IGAIN,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_OGAIN,	0x00, 0, 0, 0x00, 0, 0)
 };
 #endif
 
@@ -160,23 +163,51 @@
 MIX_ENT(SOUND_MIXER_CD,		0x36, 7, 5, 0x37, 7, 5),
 MIX_ENT(SOUND_MIXER_IMIX,	0x00, 0, 0, 0x00, 0, 0),
 MIX_ENT(SOUND_MIXER_ALTPCM,	0x00, 0, 0, 0x00, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV,	0x3f, 7, 2, 0x40, 7, 2)
+MIX_ENT(SOUND_MIXER_RECLEV,	0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */
+MIX_ENT(SOUND_MIXER_IGAIN,	0x3f, 7, 2, 0x40, 7, 2),
+MIX_ENT(SOUND_MIXER_OGAIN,	0x41, 7, 2, 0x42, 7, 2)
 };
 
+#ifdef SM_GAMES       /* Master volume is lower and PCM & FM volumes
+			     higher than with SB Pro. This improves the
+			     sound quality */
+
+static unsigned short levels[SOUND_MIXER_NRDEVICES] =
+{
+  0x2020,			/* Master Volume */
+  0x4b4b,			/* Bass */
+  0x4b4b,			/* Treble */
+  0x6464,			/* FM */
+  0x6464,			/* PCM */
+  0x4b4b,			/* PC Speaker */
+  0x4b4b,			/* Ext Line */
+  0x0000,			/* Mic */
+  0x4b4b,			/* CD */
+  0x4b4b,			/* Recording monitor */
+  0x4b4b,			/* SB PCM */
+  0x4b4b,			/* Recording level */
+  0x4b4b,			/* Input gain */
+  0x4b4b};			/* Output gain */
+
+#else  /* If the user selected just plain SB Pro */
+
 static unsigned short levels[SOUND_MIXER_NRDEVICES] =
 {
   0x5a5a,			/* Master Volume */
-  0x3232,			/* Bass */
-  0x3232,			/* Treble */
+  0x4b4b,			/* Bass */
+  0x4b4b,			/* Treble */
   0x4b4b,			/* FM */
   0x4b4b,			/* PCM */
   0x4b4b,			/* PC Speaker */
   0x4b4b,			/* Ext Line */
-  0x0000,			/* Mic */
+  0x1010,			/* Mic */
   0x4b4b,			/* CD */
   0x4b4b,			/* Recording monitor */
   0x4b4b,			/* SB PCM */
-  0x4b4b};			/* Recording level */
+  0x4b4b,			/* Recording level */
+  0x4b4b,			/* Input gain */
+  0x4b4b};			/* Output gain */
+#endif /* SM_GAMES */
 
 static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
 {
@@ -191,7 +222,9 @@
 	0x04,	/* SOUND_MIXER_CD	*/
 	0x00,	/* SOUND_MIXER_IMIX	*/
 	0x00,	/* SOUND_MIXER_ALTPCM	*/
-	0x00	/* SOUND_MIXER_RECLEV	*/
+	0x00,	/* SOUND_MIXER_RECLEV	*/
+	0x00,	/* SOUND_MIXER_IGAIN	*/
+	0x00	/* SOUND_MIXER_OGAIN	*/
 };
 
 static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
@@ -207,7 +240,9 @@
 	0x02,	/* SOUND_MIXER_CD	*/
 	0x00,	/* SOUND_MIXER_IMIX	*/
 	0x00,	/* SOUND_MIXER_ALTPCM	*/
-	0x00	/* SOUND_MIXER_RECLEV	*/
+	0x00,	/* SOUND_MIXER_RECLEV	*/
+	0x00,	/* SOUND_MIXER_IGAIN	*/
+	0x00	/* SOUND_MIXER_OGAIN	*/
 };
 
 /*
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v1.3.8/linux/drivers/sound/sequencer.c	Fri Aug 19 08:54:10 1994
+++ linux/drivers/sound/sequencer.c	Mon Jul 10 01:45:20 1995
@@ -29,6 +29,7 @@
 
 #define SEQUENCER_C
 #include "sound_config.h"
+#include "midi_ctrl.h"
 
 #ifdef CONFIGURE_SOUNDCARD
 
@@ -49,7 +50,7 @@
 /*
  * The seq_mode gives the operating mode of the sequencer:
  *      1 = level1 (the default)
- *      2 = level2 (extended capabilities)
+ *      2 = level2 (extended capabilites)
  */
 
 #define SEQ_1	1
@@ -83,7 +84,7 @@
 static int      pre_event_timeout;
 static unsigned synth_open_mask;
 
-static int      seq_queue (unsigned char *note);
+static int      seq_queue (unsigned char *note, char nonblock);
 static void     seq_startplay (void);
 static int      seq_sync (void);
 static void     seq_reset (void);
@@ -113,6 +114,12 @@
   DISABLE_INTR (flags);
   if (!iqlen)
     {
+      if (ISSET_FILE_FLAG (file, O_NONBLOCK))
+	{
+	  RESTORE_INTR (flags);
+	  return RET_ERROR (EAGAIN);
+	}
+
       DO_SLEEP (midi_sleeper, midi_sleep_flag, pre_event_timeout);
 
       if (!iqlen)
@@ -151,8 +158,8 @@
   unsigned long   flags;
 
   /*
- * Verify that the len is valid for the current mode.
- */
+     * Verify that the len is valid for the current mode.
+   */
 
   if (len != 4 && len != 8)
     return;
@@ -331,12 +338,17 @@
 
 	}
 
-      if (!seq_queue (event))
+      if (!seq_queue (event, ISSET_FILE_FLAG (file, O_NONBLOCK)))
 	{
+	  int             processed = count - c;
 
 	  if (!seq_playing)
 	    seq_startplay ();
-	  return count - c;
+
+	  if (!processed && ISSET_FILE_FLAG (file, O_NONBLOCK))
+	    return RET_ERROR (EAGAIN);
+	  else
+	    return processed;
 	}
 
       p += ev_size;
@@ -346,11 +358,13 @@
   if (!seq_playing)
     seq_startplay ();
 
-  return count;
+  return count;			/* This will "eat" chunks shorter than 4 bytes (if written
+				   * alone) Should we really do that ?
+				 */
 }
 
 static int
-seq_queue (unsigned char *note)
+seq_queue (unsigned char *note, char nonblock)
 {
 
   /*
@@ -363,7 +377,7 @@
 				 * Give chance to drain the queue
 				 */
 
-  if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+  if (!nonblock && qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
     {
       /*
        * Sleep until there is enough space on the queue
@@ -372,10 +386,11 @@
     }
 
   if (qlen >= SEQ_MAX_QUEUE)
-    return 0;			/*
+    {
+      return 0;			/*
 				 * To be sure
 				 */
-
+    }
   memcpy (&queue[qtail * EV_SZ], note, EV_SZ);
 
   qtail = (qtail + 1) % SEQ_MAX_QUEUE;
@@ -462,6 +477,8 @@
   voice = synth_devs[dev]->alloc_voice (dev, chn, note,
 					&synth_devs[dev]->alloc);
   synth_devs[dev]->alloc.map[voice] = key;
+  synth_devs[dev]->alloc.alloc_times[voice] =
+    synth_devs[dev]->alloc.timestamp++;
   return voice;
 }
 
@@ -485,33 +502,47 @@
   if (seq_mode == SEQ_2)
     {
       if (synth_devs[dev]->alloc_voice)
-        voice = find_voice (dev, chn, note);
+	voice = find_voice (dev, chn, note);
 
       if (cmd == MIDI_NOTEON && parm == 0)
-        {
-          cmd = MIDI_NOTEOFF;
-          parm = 64;
-        }
+	{
+	  cmd = MIDI_NOTEOFF;
+	  parm = 64;
+	}
     }
 
   switch (cmd)
     {
     case MIDI_NOTEON:
-      if (note > 127 && note != 255)
+      if (note > 127 && note != 255)	/* Not a seq2 feature */
 	return;
 
       if (voice == -1 && seq_mode == SEQ_2 && synth_devs[dev]->alloc_voice)
-	{
+	{			/* Internal synthesizer (FM, GUS, etc) */
 	  voice = alloc_voice (dev, chn, note);
 	}
 
       if (voice == -1)
 	voice = chn;
 
+      if (seq_mode == SEQ_2 && dev < num_synths)
+	{
+	  /*
+	     * The MIDI channel 10 is a percussive channel. Use the note
+	     * number to select the proper patch (128 to 255) to play.
+	   */
+
+	  if (chn == 9)
+	    {
+	      synth_devs[dev]->set_instr (dev, voice, 128 + note);
+	      note = 60;	/* Middle C */
+
+	    }
+	}
+
       if (seq_mode == SEQ_2)
 	{
-	  synth_devs[dev]->set_instr (dev, voice,
-				    synth_devs[dev]->chn_info[chn].pgm_num);
+	  synth_devs[dev]->setup_voice (dev, voice, chn);
 	}
 
       synth_devs[dev]->start_note (dev, voice, note, parm);
@@ -524,7 +555,9 @@
       break;
 
     case MIDI_KEY_PRESSURE:
-      /* To be implemented */
+      if (voice == -1)
+	voice = chn;
+      synth_devs[dev]->aftertouch (dev, voice, parm);
       break;
 
     default:;
@@ -555,33 +588,27 @@
       if (seq_mode == SEQ_2)
 	{
 	  synth_devs[dev]->chn_info[chn].pgm_num = p1;
+	  if (dev >= num_synths)
+	    synth_devs[dev]->set_instr (dev, chn, p1);
 	}
       else
 	synth_devs[dev]->set_instr (dev, chn, p1);
+
       break;
 
     case MIDI_CTL_CHANGE:
-      if (p1 == CTRL_MAIN_VOLUME)
-	{
-	  w14 = (unsigned short) (((int) w14 * 16383) / 100);
-	  p1 = CTL_MAIN_VOLUME;
-	}
-      if (p1 == CTRL_EXPRESSION)
-	{
-	  w14 *= 128;
-	  p1 = CTL_EXPRESSION;
-	}
 
       if (seq_mode == SEQ_2)
 	{
 	  if (chn > 15 || p1 > 127)
 	    break;
 
-	  synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0xff;
+	  synth_devs[dev]->chn_info[chn].controllers[p1] = w14 & 0x7f;
 
 	  if (dev < num_synths)
 	    {
-	      int             val = w14 & 0xff;
+	      int             val = w14 & 0x7f;
+	      int             i, key;
 
 	      if (p1 < 64)	/* Combine MSB and LSB */
 		{
@@ -591,20 +618,42 @@
 		       chn_info[chn].controllers[p1 | 32] & 0x7f);
 		  p1 &= ~32;
 		}
-	      else
-		val = synth_devs[dev]->chn_info[chn].controllers[p1];
 
-	      synth_devs[dev]->controller (dev, chn, p1, val);
+	      /* Handle all playing notes on this channel */
+
+	      key = (chn << 8);
+
+	      for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++)
+		if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key)
+		  synth_devs[dev]->controller (dev, i, p1, val);
 	    }
 	  else
 	    synth_devs[dev]->controller (dev, chn, p1, w14);
 	}
-      else
+      else			/* Mode 1 */
 	synth_devs[dev]->controller (dev, chn, p1, w14);
       break;
 
     case MIDI_PITCH_BEND:
-      synth_devs[dev]->bender (dev, chn, w14);
+      if (seq_mode == SEQ_2)
+	{
+	  synth_devs[dev]->chn_info[chn].bender_value = w14;
+
+	  if (dev < num_synths)
+	    {			/* Handle all playing notes on this channel */
+	      int             i, key;
+
+	      key = (chn << 8);
+
+	      for (i = 0; i < synth_devs[dev]->alloc.max_voice; i++)
+		if ((synth_devs[dev]->alloc.map[i] & 0xff00) == key)
+		  synth_devs[dev]->bender (dev, i, w14);
+	    }
+	  else
+	    synth_devs[dev]->bender (dev, chn, w14);
+	}
+      else			/* MODE 1 */
+	synth_devs[dev]->bender (dev, chn, w14);
       break;
 
     default:;
@@ -644,9 +693,9 @@
       parm += prev_event_time;
 
       /*
- * NOTE!  No break here. Execution of TMR_WAIT_REL continues in the
- * next case (TMR_WAIT_ABS)
- */
+         * NOTE!  No break here. Execution of TMR_WAIT_REL continues in the
+         * next case (TMR_WAIT_ABS)
+       */
 
     case TMR_WAIT_ABS:
       if (parm > 0)
@@ -714,151 +763,170 @@
   printk ("seq_local_event() called. WHY????????\n");
 }
 
-static void
-seq_startplay (void)
+static int
+play_event (unsigned char *q)
 {
-  int             this_one;
+  /*
+     * NOTE! This routine returns
+     *   0 = normal event played.
+     *   1 = Timer armed. Suspend playback until timer callback.
+     *   2 = MIDI output buffer full. Restore queue and suspend until timer
+   */
   unsigned long  *delay;
-  unsigned char  *q;
 
-  while (qlen > 0)
+  switch (q[0])
     {
+    case SEQ_NOTEOFF:
+      if (synth_open_mask & (1 << 0))
+	if (synth_devs[0])
+	  synth_devs[0]->kill_note (0, q[1], 255, q[3]);
+      break;
 
-      seq_playing = 1;
-
-      qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
-      qlen--;
-
-      q = &queue[this_one * EV_SZ];
-
-      switch (q[0])
-	{
-	case SEQ_NOTEOFF:
-	  if (synth_open_mask & (1 << 0))
-	    if (synth_devs[0])
-	      synth_devs[0]->kill_note (0, q[1], 255, q[3]);
-	  break;
-
-	case SEQ_NOTEON:
-	  if (q[4] < 128 || q[4] == 255)
-	    if (synth_open_mask & (1 << 0))
-	      if (synth_devs[0])
-		synth_devs[0]->start_note (0, q[1], q[2], q[3]);
-	  break;
+    case SEQ_NOTEON:
+      if (q[4] < 128 || q[4] == 255)
+	if (synth_open_mask & (1 << 0))
+	  if (synth_devs[0])
+	    synth_devs[0]->start_note (0, q[1], q[2], q[3]);
+      break;
 
-	case SEQ_WAIT:
-	  delay = (unsigned long *) q;	/*
+    case SEQ_WAIT:
+      delay = (unsigned long *) q;	/*
 					 * Bytes 1 to 3 are containing the *
 					 * delay in GET_TIME()
 					 */
-	  *delay = (*delay >> 8) & 0xffffff;
+      *delay = (*delay >> 8) & 0xffffff;
 
-	  if (*delay > 0)
-	    {
-	      long            time;
+      if (*delay > 0)
+	{
+	  long            time;
 
-	      seq_playing = 1;
-	      time = *delay;
-	      prev_event_time = time;
+	  seq_playing = 1;
+	  time = *delay;
+	  prev_event_time = time;
 
-	      request_sound_timer (time);
+	  request_sound_timer (time);
 
-	      if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
-		{
-		  unsigned long   flags;
+	  if ((SEQ_MAX_QUEUE - qlen) >= output_treshold)
+	    {
+	      unsigned long   flags;
 
-		  DISABLE_INTR (flags);
-		  if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
-		    {
-		      WAKE_UP (seq_sleeper, seq_sleep_flag);
-		    }
-		  RESTORE_INTR (flags);
+	      DISABLE_INTR (flags);
+	      if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
+		{
+		  WAKE_UP (seq_sleeper, seq_sleep_flag);
 		}
-	      /*
- * The timer is now active and will reinvoke this function
- * after the timer expires. Return to the caller now.
- */
-	      return;
+	      RESTORE_INTR (flags);
 	    }
-	  break;
+	  /*
+	     * The timer is now active and will reinvoke this function
+	     * after the timer expires. Return to the caller now.
+	   */
+	  return 1;
+	}
+      break;
+
+    case SEQ_PGMCHANGE:
+      if (synth_open_mask & (1 << 0))
+	if (synth_devs[0])
+	  synth_devs[0]->set_instr (0, q[1], q[2]);
+      break;
 
-	case SEQ_PGMCHANGE:
-	  if (synth_open_mask & (1 << 0))
-	    if (synth_devs[0])
-	      synth_devs[0]->set_instr (0, q[1], q[2]);
-	  break;
-
-	case SEQ_SYNCTIMER:	/*
-				 * Reset timer
-				 */
-	  seq_time = GET_TIME ();
-	  prev_input_time = 0;
-	  prev_event_time = 0;
-	  break;
+    case SEQ_SYNCTIMER:	/*
+				   * Reset timer
+				 */
+      seq_time = GET_TIME ();
+      prev_input_time = 0;
+      prev_event_time = 0;
+      break;
 
-	case SEQ_MIDIPUTC:	/*
+    case SEQ_MIDIPUTC:		/*
 				 * Put a midi character
 				 */
-	  if (midi_opened[q[2]])
-	    {
-	      int             dev;
+      if (midi_opened[q[2]])
+	{
+	  int             dev;
 
-	      dev = q[2];
+	  dev = q[2];
 
-	      if (!midi_devs[dev]->putc (dev, q[1]))
-		{
-		  /*
-		   * Output FIFO is full. Wait one timer cycle and try again.
-		   */
-
-		  qlen++;
-		  qhead = this_one;	/*
-					 * Restore queue
-					 */
-		  seq_playing = 1;
-		  request_sound_timer (-1);
-		  return;
-		}
-	      else
-		midi_written[dev] = 1;
+	  if (!midi_devs[dev]->putc (dev, q[1]))
+	    {
+	      /*
+	         * Output FIFO is full. Wait one timer cycle and try again.
+	       */
+
+	      seq_playing = 1;
+	      request_sound_timer (-1);
+	      return 2;
 	    }
-	  break;
+	  else
+	    midi_written[dev] = 1;
+	}
+      break;
 
-	case SEQ_ECHO:
-	  seq_copy_to_input (q, 4);	/*
-					   * Echo back to the process
-					 */
-	  break;
+    case SEQ_ECHO:
+      seq_copy_to_input (q, 4);	/*
+				   * Echo back to the process
+				 */
+      break;
 
-	case SEQ_PRIVATE:
-	  if ((int) q[1] < max_synthdev)
-	    synth_devs[q[1]]->hw_control (q[1], q);
-	  break;
-
-	case SEQ_EXTENDED:
-	  extended_event (q);
-	  break;
-
-	case EV_CHN_VOICE:
-	  seq_chn_voice_event (q);
-	  break;
-
-	case EV_CHN_COMMON:
-	  seq_chn_common_event (q);
-	  break;
+    case SEQ_PRIVATE:
+      if ((int) q[1] < max_synthdev)
+	synth_devs[q[1]]->hw_control (q[1], q);
+      break;
 
-	case EV_TIMING:
-	  if (seq_timing_event (q) == TIMER_ARMED)
-	    {
-	      return;
-	    }
-	  break;
+    case SEQ_EXTENDED:
+      extended_event (q);
+      break;
 
-	case EV_SEQ_LOCAL:
-	  seq_local_event (q);
-	  break;
+    case EV_CHN_VOICE:
+      seq_chn_voice_event (q);
+      break;
+
+    case EV_CHN_COMMON:
+      seq_chn_common_event (q);
+      break;
 
-	default:;
+    case EV_TIMING:
+      if (seq_timing_event (q) == TIMER_ARMED)
+	{
+	  return 1;
+	}
+      break;
+
+    case EV_SEQ_LOCAL:
+      seq_local_event (q);
+      break;
+
+    default:;
+    }
+
+  return 0;
+}
+
+static void
+seq_startplay (void)
+{
+  unsigned long   flags;
+  int             this_one, action;
+
+  while (qlen > 0)
+    {
+
+      DISABLE_INTR (flags);
+      qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE;
+      qlen--;
+      RESTORE_INTR (flags);
+
+      seq_playing = 1;
+
+      if ((action = play_event (&queue[this_one * EV_SZ])))
+	{			/* Suspend playback. Next timer routine invokes this routine again */
+	  if (action == 2)
+	    {
+	      qlen++;
+	      qhead = this_one;
+	    }
+	  return;
 	}
 
     }
@@ -876,13 +944,11 @@
 	}
       RESTORE_INTR (flags);
     }
-
 }
 
 static void
 reset_controllers (int dev, unsigned char *controller, int update_dev)
 {
-#include "midi_ctrl.h"
 
   int             i;
 
@@ -914,6 +980,7 @@
 	  reset_controllers (dev,
 			     synth_devs[dev]->chn_info[chn].controllers,
 			     0);
+	  synth_devs[dev]->chn_info[chn].bender_value = (1 << 7);	/* Neutral */
 	}
     }
 
@@ -998,7 +1065,6 @@
 
   if (level == 2)
     {
-      printk ("Using timer #%d\n", tmr_no);
       if (tmr == NULL)
 	{
 	  printk ("sequencer: No timer for level 2\n");
@@ -1035,7 +1101,7 @@
       {
 	printk ("Sequencer: Warning! Cannot open synth device #%d (%d)\n", i, tmp);
 	if (synth_devs[i]->midi_dev)
-	  printk ("(Maps to midi dev #%d\n", synth_devs[i]->midi_dev);
+	  printk ("(Maps to MIDI dev #%d)\n", synth_devs[i]->midi_dev);
       }
     else
       {
@@ -1091,7 +1157,7 @@
 
   n = 1;
 
-  while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n)
+  while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && n)
     {
       n = 0;
 
@@ -1132,10 +1198,10 @@
     }
 
   /*
-   * * Wait until the queue is empty
+   * * Wait until the queue is empty (if we don't have nonblock)
    */
 
-  if (mode != OPEN_READ)
+  if (mode != OPEN_READ && !ISSET_FILE_FLAG (file, O_NONBLOCK))
     while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen)
       {
 	seq_sync ();
@@ -1180,16 +1246,17 @@
 static int
 seq_sync (void)
 {
+  unsigned long   flags;
+
   if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag))
     seq_startplay ();
 
-  if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))	/*
-								 * Queue not
-								 * empty
-								 */
+  DISABLE_INTR (flags);
+  if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
     {
       DO_SLEEP (seq_sleeper, seq_sleep_flag, 0);
     }
+  RESTORE_INTR (flags);
 
   return qlen;
 }
@@ -1202,26 +1269,23 @@
    */
 
   int             n;
+  unsigned long   flags;
 
   /*
    * This routine sends one byte to the Midi channel.
-   */
-  /*
    * If the output Fifo is full, it waits until there
-   */
-  /*
    * is space in the queue
    */
 
-  n = 300;			/*
-				 * Timeout in jiffies
-				 */
+  n = 3 * HZ;			/* Timeout */
 
+  DISABLE_INTR (flags);
   while (n && !midi_devs[dev]->putc (dev, data))
     {
       DO_SLEEP (seq_sleeper, seq_sleep_flag, 4);
       n--;
     }
+  RESTORE_INTR (flags);
 }
 
 static void
@@ -1232,8 +1296,8 @@
    */
 
   int             i;
-
   int             chn;
+  unsigned long   flags;
 
   sound_stop_timer ();
   seq_time = GET_TIME ();
@@ -1250,13 +1314,20 @@
 
   if (seq_mode == SEQ_2)
     {
-      for (i = 0; i < max_synthdev; i++)
-	if (synth_open_mask & (1 << i))
-	  if (synth_devs[i])
-	    for (chn = 0; chn < 16; chn++)
-	      synth_devs[i]->controller (i, chn, 0xfe, 0);	/* All notes off */
+
+      for (chn = 0; chn < 16; chn++)
+	for (i = 0; i < max_synthdev; i++)
+	  if (synth_open_mask & (1 << i))
+	    if (synth_devs[i])
+	      {
+		synth_devs[i]->controller (i, chn, 123, 0);	/* All notes off */
+		synth_devs[i]->controller (i, chn, 121, 0);	/* Reset all ctl */
+		synth_devs[i]->bender (i, chn, 1 << 13);	/* Bender off */
+	      }
+
     }
   else
+    /* seq_mode == SEQ_1 */
     {
       for (i = 0; i < max_mididev; i++)
 	if (midi_written[i])	/*
@@ -1264,25 +1335,18 @@
 				 */
 	  {
 	    /*
- *    Sending just a ACTIVE SENSING message should be enough to stop all
- *      playing notes. Since there are devices not recognizing the
- *      active sensing, we have to send some all notes off messages also.
- */
+	       *      Sending just a ACTIVE SENSING message should be enough to stop all
+	       *      playing notes. Since there are devices not recognizing the
+	       *      active sensing, we have to send some all notes off messages also.
+	     */
 	    midi_outc (i, 0xfe);
 
 	    for (chn = 0; chn < 16; chn++)
 	      {
 		midi_outc (i,
-			   (unsigned char) (0xb0 + (chn & 0xff)));	/*
-								 * Channel
-								 * msg
-								 */
-		midi_outc (i, 0x7b);	/*
-					 * All notes off
-					 */
-		midi_outc (i, 0);	/*
-				 * Dummy parameter
-				 */
+			   (unsigned char) (0xb0 + (chn & 0x0f)));	/* control change */
+		midi_outc (i, 0x7b);	/* All notes off */
+		midi_outc (i, 0);	/* Dummy parameter */
 	      }
 
 	    midi_devs[i]->close (i);
@@ -1294,8 +1358,13 @@
 
   seq_playing = 0;
 
+  DISABLE_INTR (flags);
   if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag))
-    printk ("Sequencer Warning: Unexpected sleeping process\n");
+    {
+      /*      printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */
+      WAKE_UP (seq_sleeper, seq_sleep_flag);
+    }
+  RESTORE_INTR (flags);
 
 }
 
@@ -1303,22 +1372,22 @@
 seq_panic (void)
 {
   /*
- * This routine is called by the application in case the user
- * wants to reset the system to the default state.
- */
+     * This routine is called by the application in case the user
+     * wants to reset the system to the default state.
+   */
 
   seq_reset ();
 
   /*
- * Since some of the devices don't recognize the active sensing and
- * all notes off messages, we have to shut all notes manually.
- *
- *      TO BE IMPLEMENTED LATER
- */
+     * Since some of the devices don't recognize the active sensing and
+     * all notes off messages, we have to shut all notes manually.
+     *
+     *      TO BE IMPLEMENTED LATER
+   */
 
   /*
- * Also return the controllers to their default states
- */
+     * Also return the controllers to their default states
+   */
 }
 
 int
@@ -1523,6 +1592,21 @@
       }
       break;
 
+    case SNDCTL_SEQ_OUTOFBAND:
+      {
+	struct seq_event_rec event;
+	unsigned long   flags;
+
+	IOCTL_FROM_USER ((char *) &event, (char *) arg, 0, sizeof (event));
+
+	DISABLE_INTR (flags);
+	play_event (event.arr);
+	RESTORE_INTR (flags);
+
+	return 0;
+      }
+      break;
+
     case SNDCTL_MIDI_INFO:
       {
 	struct midi_info inf;
@@ -1544,7 +1628,11 @@
 	struct patmgr_info *inf;
 	int             dev, err;
 
-	inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf));
+	if ((inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf))) == NULL)
+	  {
+	    printk ("patmgr: Can't allocate memory for a message\n");
+	    return RET_ERROR (EIO);
+	  }
 
 	IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf));
 	dev = inf->device;
@@ -1578,7 +1666,11 @@
 	struct patmgr_info *inf;
 	int             dev, err;
 
-	inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf));
+	if ((inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf))) == NULL)
+	  {
+	    printk ("patmgr: Can't allocate memory for a message\n");
+	    return RET_ERROR (EIO);
+	  }
 
 	IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf));
 	dev = inf->device;
@@ -1607,7 +1699,7 @@
       }
       break;
 
-    case SNDCTL_SEQ_TRESHOLD:
+    case SNDCTL_SEQ_THRESHOLD:
       {
 	int             tmp = IOCTL_IN (arg);
 
@@ -1669,26 +1761,30 @@
   switch (sel_type)
     {
     case SEL_IN:
+      DISABLE_INTR (flags);
       if (!iqlen)
 	{
-	  DISABLE_INTR (flags);
 	  midi_sleep_flag.mode = WK_SLEEP;
 	  select_wait (&midi_sleeper, wait);
 	  RESTORE_INTR (flags);
 	  return 0;
 	}
+      midi_sleep_flag.mode &= ~WK_SLEEP;
+      RESTORE_INTR (flags);
       return 1;
       break;
 
     case SEL_OUT:
+      DISABLE_INTR (flags);
       if (qlen >= SEQ_MAX_QUEUE)
 	{
-	  DISABLE_INTR (flags);
 	  seq_sleep_flag.mode = WK_SLEEP;
 	  select_wait (&seq_sleeper, wait);
 	  RESTORE_INTR (flags);
 	  return 0;
 	}
+      seq_sleep_flag.mode &= ~WK_SLEEP;
+      RESTORE_INTR (flags);
       return 1;
       break;
 
@@ -1852,11 +1948,14 @@
   return mem_start;
 }
 
+#ifdef ALLOW_SELECT
 int
 sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait)
 {
   return RET_ERROR (EIO);
 }
+
+#endif
 
 #endif
 
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h
--- v1.3.8/linux/drivers/sound/sound_calls.h	Fri Jan 20 10:24:13 1995
+++ linux/drivers/sound/sound_calls.h	Mon Jun 12 15:47:27 1995
@@ -4,18 +4,21 @@
 
 int DMAbuf_open(int dev, int mode);
 int DMAbuf_release(int dev, int mode);
-int DMAbuf_getwrbuffer(int dev, char **buf, int *size);
-int DMAbuf_getrdbuffer(int dev, char **buf, int *len);
+int DMAbuf_getwrbuffer(int dev, char **buf, int *size, int dontblock);
+int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock);
 int DMAbuf_rmchars(int dev, int buff_no, int c);
 int DMAbuf_start_output(int dev, int buff_no, int l);
 int DMAbuf_ioctl(int dev, unsigned int cmd, unsigned int arg, int local);
 long DMAbuf_init(long mem_start);
 int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
-int DMAbuf_open_dma (int chan);
-void DMAbuf_close_dma (int chan);
-void DMAbuf_reset_dma (int chan);
+int DMAbuf_open_dma (int dev);
+void DMAbuf_close_dma (int dev);
+void DMAbuf_reset_dma (int dev);
 void DMAbuf_inputintr(int dev);
 void DMAbuf_outputintr(int dev, int underflow_flag);
+#ifdef ALLOW_SELECT
+int DMAbuf_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+#endif
 
 /*
  *	System calls for /dev/dsp and /dev/audio
@@ -30,6 +33,10 @@
 int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
 long audio_init (long mem_start);
 
+#ifdef ALLOW_SELECT
+int audio_select(int dev, struct fileinfo *file, int sel_type, select_table * wait);
+#endif
+
 /*
  *	System calls for the /dev/sequencer
  */
@@ -86,21 +93,13 @@
  *	Misc calls from various sources
  */
 
-/* 	From pro_midi.c 	*/
-
-long pro_midi_attach(long mem_start);
-int  pro_midi_open(int dev, int mode);
-void pro_midi_close(int dev);
-int pro_midi_write(int dev, snd_rw_buf *uio);
-int pro_midi_read(int dev, snd_rw_buf *uio);
-
 /*	From soundcard.c	*/
 long soundcard_init(long mem_start);
 void tenmicrosec(void);
 void request_sound_timer (int count);
 void sound_stop_timer(void);
 int snd_ioctl_return(int *addr, int value);
-int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, struct pt_regs *));
+int snd_set_irq_handler (int interrupt_level, INT_HANDLER_PROTO(), char *name);
 void snd_release_irq(int vect);
 void sound_dma_malloc(int dev);
 void sound_dma_free(int dev);
@@ -123,7 +122,7 @@
 int sb_reset_dsp (void);
 
 /*	From sb16_dsp.c	*/
-void sb16_dsp_interrupt (int unused);
+void sb16_dsp_interrupt (int irq);
 long sb16_dsp_init(long mem_start, struct address_info *hw_config);
 int sb16_dsp_detect(struct address_info *hw_config);
 
@@ -177,7 +176,7 @@
 long attach_gus_card(long mem_start, struct address_info * hw_config);
 int probe_gus(struct address_info *hw_config);
 int gus_set_midi_irq(int num);
-void gusintr(int, struct pt_regs * regs);
+void gusintr(INT_HANDLER_PARMS(irq, dummy));
 long attach_gus_db16(long mem_start, struct address_info * hw_config);
 int probe_gus_db16(struct address_info *hw_config);
 
@@ -198,6 +197,7 @@
 /*	From mpu401.c */
 long attach_mpu401(long mem_start, struct address_info * hw_config);
 int probe_mpu401(struct address_info *hw_config);
+void mpuintr(INT_HANDLER_PARMS(irq, dummy));
 
 /*	From uart6850.c */
 long attach_uart6850(long mem_start, struct address_info * hw_config);
@@ -225,13 +225,23 @@
 /*	From ad1848.c */
 void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture);
 int ad1848_detect (int io_base);
-void     ad1848_interrupt (int dev, struct pt_regs *regs);
+void     ad1848_interrupt (INT_HANDLER_PARMS(irq, dummy));
 long attach_ms_sound(long mem_start, struct address_info * hw_config);
 int probe_ms_sound(struct address_info *hw_config);
 
 /* 	From pss.c */
 int probe_pss (struct address_info *hw_config);
 long attach_pss (long mem_start, struct address_info *hw_config);
+int probe_pss_mpu (struct address_info *hw_config);
+long attach_pss_mpu (long mem_start, struct address_info *hw_config);
+int probe_pss_mss (struct address_info *hw_config);
+long attach_pss_mss (long mem_start, struct address_info *hw_config);
+
+/* 	From sscape.c */
+int probe_sscape (struct address_info *hw_config);
+long attach_sscape (long mem_start, struct address_info *hw_config);
+int probe_ss_ms_sound (struct address_info *hw_config);
+long attach_ss_ms_sound(long mem_start, struct address_info * hw_config);
 
 int pss_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
 int pss_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count);
@@ -241,3 +251,25 @@
 	   unsigned int cmd, unsigned int arg);
 int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig);
 long pss_init(long mem_start);
+
+/* From aedsp16.c */
+int InitAEDSP16_SBPRO(struct address_info *hw_config);
+int InitAEDSP16_MSS(struct address_info *hw_config);
+int InitAEDSP16_MPU401(struct address_info *hw_config);
+
+/*	From midi_synth.c	*/
+void do_midi_msg (int synthno, unsigned char *msg, int mlen);
+
+/*	From trix.c	*/
+long attach_trix_wss (long mem_start, struct address_info *hw_config);
+int probe_trix_wss (struct address_info *hw_config);
+long attach_trix_sb (long mem_start, struct address_info *hw_config);
+int probe_trix_sb (struct address_info *hw_config);
+long attach_trix_mpu (long mem_start, struct address_info *hw_config);
+int probe_trix_mpu (struct address_info *hw_config);
+
+/*	From mad16.c	*/
+long attach_mad16 (long mem_start, struct address_info *hw_config);
+int probe_mad16 (struct address_info *hw_config);
+long attach_mad16_mpu (long mem_start, struct address_info *hw_config);
+int probe_mad16_mpu (struct address_info *hw_config);
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h
--- v1.3.8/linux/drivers/sound/sound_config.h	Fri Aug 19 08:54:10 1994
+++ linux/drivers/sound/sound_config.h	Wed Jul  5 22:37:12 1995
@@ -29,6 +29,13 @@
  */
 
 #include "local.h"
+#include "os.h"
+#include "soundvers.h"
+
+#if !defined(PSS_MPU_BASE) && defined(EXCLUDE_SSCAPE) && \
+			      defined(EXCLUDE_TRIX) && !defined(MAD16_MPU_BASE)
+#define EXCLUDE_MPU_EMU
+#endif
 
 #if defined(ISC) || defined(SCO) || defined(SVR42)
 #define GENERIC_SYSV
@@ -38,10 +45,16 @@
  * Disable the AD1848 driver if there are no other drivers requiring it.
  */
 
-#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX)
+#if defined(EXCLUDE_GUS16) && defined(EXCLUDE_MSS) && \
+    defined(EXCLUDE_PSS) && defined(EXCLUDE_GUSMAX) && \
+    defined(EXCLUDE_SSCAPE) && defined(EXCLUDE_TRIX) && defined(EXCLUDE_MAD16)
 #define EXCLUDE_AD1848
 #endif
 
+#ifdef PSS_MSS_BASE
+#undef EXCLUDE_AD1848
+#endif
+
 #undef CONFIGURE_SOUNDCARD
 #undef DYNAMIC_BUFFER
 
@@ -63,80 +76,6 @@
 
 #ifdef CONFIGURE_SOUNDCARD
 
-/* ****** IO-address, DMA and IRQ settings ****
-
-If your card has nonstandard I/O address or IRQ number, change defines
-   for the following settings in your kernel Makefile */
-
-#ifndef SBC_BASE
-#define SBC_BASE	0x220	/* 0x220 is the factory default. */
-#endif
-
-#ifndef SBC_IRQ
-#define SBC_IRQ		7	/* IQR7 is the factory default.	 */
-#endif
-
-#ifndef SBC_DMA
-#define SBC_DMA		1
-#endif
-
-#ifndef SB16_DMA
-#define SB16_DMA	6
-#endif
-
-#ifndef SB16MIDI_BASE
-#define SB16MIDI_BASE	0x300
-#endif
-
-#ifndef PAS_BASE
-#define PAS_BASE	0x388
-#endif
-
-#ifndef PAS_IRQ
-#define PAS_IRQ		5
-#endif
-
-#ifndef PAS_DMA
-#define PAS_DMA		3
-#endif
-
-#ifndef GUS_BASE
-#define GUS_BASE	0x220
-#endif
-
-#ifndef GUS_IRQ
-#define GUS_IRQ		15
-#endif
-
-#ifndef GUS_MIDI_IRQ
-#define GUS_MIDI_IRQ	GUS_IRQ
-#endif
-
-#ifndef GUS_DMA
-#define GUS_DMA		6
-#endif
-
-#ifndef MPU_BASE
-#define MPU_BASE	0x330
-#endif
-
-#ifndef MPU_IRQ
-#define MPU_IRQ		6
-#endif
-
-/* Echo Personal Sound System */
-#ifndef PSS_BASE
-#define PSS_BASE        0x220   /* 0x240 or */
-#endif
-
-#ifndef PSS_IRQ
-#define PSS_IRQ         7
-#endif
-
-#ifndef PSS_DMA
-#define PSS_DMA         1
-#endif
-
 #ifndef MAX_REALTIME_FACTOR
 #define MAX_REALTIME_FACTOR	4
 #endif
@@ -190,7 +129,7 @@
 #define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
 #define SND_DEV_STATUS	6	/* /dev/sndstat */
 /* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
+#define SND_DEV_SEQ2	8	/* /dev/sequecer, level 2 interface */
 #define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
 #define SND_DEV_PSS	SND_DEV_SNDPROC
 
@@ -200,19 +139,21 @@
 #define OFF		0
 
 #define MAX_AUDIO_DEV	5
-#define MAX_MIXER_DEV	2
+#define MAX_MIXER_DEV	5
 #define MAX_SYNTH_DEV	3
 #define MAX_MIDI_DEV	6
 #define MAX_TIMER_DEV	3
 
 struct fileinfo {
-       	  int mode;	/* Open mode */
+       	  int mode;	      /* Open mode */
+	  DECLARE_FILE();     /* Reference to file-flags. OS-dependent. */
        };
 
 struct address_info {
 	int io_base;
 	int irq;
 	int dma;
+	int always_detect;	/* 1=Trust me, it's there */
 };
 
 #define SYNTH_MAX_VOICES	32
@@ -222,10 +163,13 @@
 		int used_voices;
 		int ptr;		/* For device specific use */
 		unsigned short map[SYNTH_MAX_VOICES]; /* (ch << 8) | (note+1) */
+		int timestamp;
+		int alloc_times[SYNTH_MAX_VOICES];
 	};
 
 struct channel_info {
 		int pgm_num;
+		int bender_value;
 		unsigned char controllers[128];
 	};
 
@@ -242,17 +186,18 @@
 #define OPEN_WRITE	2
 #define OPEN_READWRITE	3
 
-#include "os.h"
 #include "sound_calls.h"
 #include "dev_table.h"
 
 #ifndef DEB
 #define DEB(x)
+#endif
+
+#ifndef DDB
+#define DDB(x)
+#endif
 
 #define TIMER_ARMED	121234
 #define TIMER_NOT_ARMED	1
-
-#define FUTURE_VERSION
-#endif
 
 #endif
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c
--- v1.3.8/linux/drivers/sound/sound_switch.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/sound_switch.c	Mon Jul 10 01:45:21 1995
@@ -115,7 +115,7 @@
 
   status_ptr = 0;
 
-  put_status ("Sound Driver:" SOUND_VERSION_STRING
+  put_status ("VoxWare Sound Driver:" SOUND_VERSION_STRING
 	      " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@"
 	      SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")"
 	      "\n");
@@ -184,7 +184,11 @@
 	return;
     }
 
-  if (!put_status ("\nPCM devices:\n"))
+#ifdef EXCLUDE_AUDIO
+  if (!put_status ("\nAudio devices: NOT ENABLED IN CONFIG\n"))
+    return;
+#else
+  if (!put_status ("\nAudio devices:\n"))
     return;
 
   for (i = 0; i < num_audiodevs; i++)
@@ -198,7 +202,12 @@
       if (!put_status ("\n"))
 	return;
     }
+#endif
 
+#ifdef EXCLUDE_SEQUENCER
+  if (!put_status ("\nSynth devices: NOT ENABLED IN CONFIG\n"))
+    return;
+#else
   if (!put_status ("\nSynth devices:\n"))
     return;
 
@@ -213,7 +222,12 @@
       if (!put_status ("\n"))
 	return;
     }
+#endif
 
+#ifdef EXCLUDE_MIDI
+  if (!put_status ("\nMidi devices: NOT ENABLED IN CONFIG\n"))
+    return;
+#else
   if (!put_status ("\nMidi devices:\n"))
     return;
 
@@ -228,8 +242,9 @@
       if (!put_status ("\n"))
 	return;
     }
+#endif
 
-  if (!put_status ("\nMIDI Timers:\n"))
+  if (!put_status ("\nTimers:\n"))
     return;
 
   for (i = 0; i < num_sound_timers; i++)
@@ -244,12 +259,20 @@
 	return;
     }
 
-  if (!put_status ("\n"))
-    return;
-  if (!put_status_int (num_mixers, 10))
-    return;
-  if (!put_status (" mixer(s) installed\n"))
+  if (!put_status ("\nMixers:\n"))
     return;
+
+  for (i = 0; i < num_mixers; i++)
+    {
+      if (!put_status_int (i, 10))
+	return;
+      if (!put_status (": "))
+	return;
+      if (!put_status (mixer_devs[i]->name))
+	return;
+      if (!put_status ("\n"))
+	return;
+    }
 }
 
 static int
@@ -301,11 +324,6 @@
       return MIDIbuf_read (dev, file, buf, count);
 #endif
 
-#ifndef EXCLUDE_PSS
-    case SND_DEV_PSS:
-      return pss_read (dev, file, buf, count);
-#endif
-
     default:
       printk ("Sound: Undefined minor device %d\n", dev);
     }
@@ -338,11 +356,6 @@
       return MIDIbuf_write (dev, file, buf, count);
 #endif
 
-#ifndef EXCLUDE_PSS
-    case SND_DEV_PSS:
-      return pss_write (dev, file, buf, count);
-#endif
-
     default:
       return RET_ERROR (EPERM);
     }
@@ -392,13 +405,6 @@
       break;
 #endif
 
-#ifndef EXCLUDE_PSS
-    case SND_DEV_PSS:
-      if ((retval = pss_open (dev, file)) < 0)
-	return retval;
-      break;
-#endif
-
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -446,12 +452,6 @@
       break;
 #endif
 
-#ifndef EXCLUDE_PSS
-    case SND_DEV_PSS:
-      pss_release (dev, file);
-      break;
-#endif
-
     case SND_DEV_DSP:
     case SND_DEV_DSP16:
     case SND_DEV_AUDIO:
@@ -472,11 +472,27 @@
 {
   DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
 
-  if ((dev & 0x0f) != SND_DEV_CTL && num_mixers > 0)
-    if ((cmd >> 8) & 0xff == 'M')	/*
-					 * Mixer ioctl
-					 */
-      return mixer_devs[0]->ioctl (0, cmd, arg);
+  if ((cmd >> 8) & 0xff == 'M' && num_mixers > 0)	/* Mixer ioctl */
+    if ((dev & 0x0f) != SND_DEV_CTL)
+      {
+	int             dtype = dev & 0x0f;
+	int             mixdev;
+
+	switch (dtype)
+	  {
+	  case SND_DEV_DSP:
+	  case SND_DEV_DSP16:
+	  case SND_DEV_AUDIO:
+	    mixdev = audio_devs[dev >> 4]->mixer_dev;
+	    if (mixdev < 0 || mixdev >= num_mixers)
+	      return RET_ERROR (ENXIO);
+	    return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg);
+	    break;
+
+	  default:
+	    return mixer_devs[0]->ioctl (0, cmd, arg);
+	  }
+      }
 
   switch (dev & 0x0f)
     {
@@ -508,12 +524,6 @@
 #ifndef EXCLUDE_MIDI
     case SND_DEV_MIDIN:
       return MIDIbuf_ioctl (dev, file, cmd, arg);
-      break;
-#endif
-
-#ifndef EXCLUDE_PSS
-    case SND_DEV_PSS:
-      return pss_ioctl (dev, file, cmd, arg);
       break;
 #endif
 
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sound_timer.c linux/drivers/sound/sound_timer.c
--- v1.3.8/linux/drivers/sound/sound_timer.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/sound_timer.c	Mon Jul 10 01:45:21 1995
@@ -87,8 +87,8 @@
 tmr2ticks (int tmr_value)
 {
   /*
- *    Convert timer ticks to MIDI ticks
- */
+     *    Convert timer ticks to MIDI ticks
+   */
 
   unsigned long   tmp;
   unsigned long   scale;
@@ -110,8 +110,8 @@
   usecs_per_tick = (60 * 1000000) / (curr_tempo * curr_timebase);
 
   /*
- * Don't kill the system by setting too high timer rate
- */
+     * Don't kill the system by setting too high timer rate
+   */
   if (usecs_per_tick < 2000)
     usecs_per_tick = 2000;
 
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v1.3.8/linux/drivers/sound/soundcard.c	Mon Jan 23 23:04:09 1995
+++ linux/drivers/sound/soundcard.c	Mon Jul 10 01:45:22 1995
@@ -26,13 +26,15 @@
  * SUCH DAMAGE.
  *
  */
+/*
+ * Created modular version by Peter Trattler (peter@sbox.tu-graz.ac.at)
+ */
 
 #include "sound_config.h"
 
 #ifdef CONFIGURE_SOUNDCARD
 
 #include <linux/major.h>
-#include <linux/mm.h>
 
 static int      soundcards_installed = 0;	/* Number of installed
 
@@ -44,15 +46,9 @@
 int
 snd_ioctl_return (int *addr, int value)
 {
-  int error;
-
   if (value < 0)
     return value;
 
-  error = verify_area(VERIFY_WRITE, addr, sizeof(int));
-  if (error)
-    return error;
-
   PUT_WORD_TO_USER (addr, 0, value);
   return 0;
 }
@@ -73,6 +69,11 @@
 {
   int             dev;
 
+#ifdef MODULE
+  int             err;
+
+#endif
+
   dev = inode->i_rdev;
   dev = MINOR (dev);
 
@@ -88,7 +89,8 @@
 static int
 sound_open (struct inode *inode, struct file *file)
 {
-  int             dev;
+  int             dev, retval;
+  struct fileinfo tmp_file;
 
   dev = inode->i_rdev;
   dev = MINOR (dev);
@@ -99,16 +101,25 @@
       return RET_ERROR (ENXIO);
     }
 
-  files[dev].mode = 0;
+  tmp_file.mode = 0;
+  tmp_file.filp = file;
 
   if ((file->f_flags & O_ACCMODE) == O_RDWR)
-    files[dev].mode = OPEN_READWRITE;
+    tmp_file.mode = OPEN_READWRITE;
   if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-    files[dev].mode = OPEN_READ;
+    tmp_file.mode = OPEN_READ;
   if ((file->f_flags & O_ACCMODE) == O_WRONLY)
-    files[dev].mode = OPEN_WRITE;
+    tmp_file.mode = OPEN_WRITE;
 
-  return sound_open_sw (dev, &files[dev]);
+  if ((retval = sound_open_sw (dev, &tmp_file)) < 0)
+    return retval;
+
+#ifdef MODULE
+  MOD_INC_USE_COUNT;
+#endif
+
+  memcpy ((char *) &files[dev], (char *) &tmp_file, sizeof (tmp_file));
+  return retval;
 }
 
 static void
@@ -120,6 +131,9 @@
   dev = MINOR (dev);
 
   sound_release_sw (dev, &files[dev]);
+#ifdef MODULE
+  MOD_DEC_USE_COUNT;
+#endif
 }
 
 static int
@@ -131,6 +145,29 @@
   dev = inode->i_rdev;
   dev = MINOR (dev);
 
+  if (cmd & IOC_INOUT)
+    {
+      /*
+         * Have to validate the address given by the process.
+       */
+      int             len, err;
+
+      len = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+
+      if (cmd & IOC_IN)
+	{
+	  if ((err = verify_area (VERIFY_READ, (void *) arg, len)) < 0)
+	    return err;
+	}
+
+      if (cmd & IOC_OUT)
+	{
+	  if ((err = verify_area (VERIFY_WRITE, (void *) arg, len)) < 0)
+	    return err;
+	}
+
+    }
+
   return sound_ioctl_sw (dev, &files[dev], cmd, arg);
 }
 
@@ -148,6 +185,7 @@
     {
 #ifndef EXCLUDE_SEQUENCER
     case SND_DEV_SEQ:
+    case SND_DEV_SEQ2:
       return sequencer_select (dev, &files[dev], sel_type, wait);
       break;
 #endif
@@ -158,6 +196,14 @@
       break;
 #endif
 
+#ifndef EXCLUDE_AUDIO
+    case SND_DEV_DSP:
+    case SND_DEV_DSP16:
+    case SND_DEV_AUDIO:
+      return audio_select (dev, &files[dev], sel_type, wait);
+      break;
+#endif
+
     default:
       return 0;
     }
@@ -181,7 +227,9 @@
 long
 soundcard_init (long mem_start)
 {
+#ifndef MODULE
   register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
+#endif
 
   soundcard_configured = 1;
 
@@ -212,6 +260,89 @@
   return mem_start;
 }
 
+#ifdef MODULE
+static unsigned long irqs = 0;
+void            snd_release_irq (int);
+static int      module_sound_mem_init (void);
+static void     module_sound_mem_release (void);
+
+static void
+free_all_irqs (void)
+{
+  int             i;
+
+  for (i = 0; i < 31; i++)
+    if (irqs & (1ul << i))
+      snd_release_irq (i);
+  irqs = 0;
+}
+
+char            kernel_version[] = UTS_RELEASE;
+
+static long     memory_pool = 0;
+static int      memsize = 70 * 1024;
+static int      debugmem = 0;	/* switched off by default */
+
+int
+init_module (void)
+{
+  long            lastbyte;
+  int             err;
+
+  printk ("sound: made modular by Peter Trattler (peter@sbox.tu-graz.ac.at)\n");
+  err = register_chrdev (SOUND_MAJOR, "sound", &sound_fops);
+  if (err)
+    {
+      printk ("sound: driver already loaded/included in kernel\n");
+      return err;
+    }
+  memory_pool = (long) kmalloc (memsize, GFP_KERNEL);
+  if (memory_pool == 0l)
+    {
+      unregister_chrdev (SOUND_MAJOR, "sound");
+      return -ENOMEM;
+    }
+  lastbyte = soundcard_init (memory_pool);
+  if (lastbyte > memory_pool + memsize)
+    {
+      printk ("sound: Not enough memory; use : 'insmod sound.o memsize=%ld'\n",
+	      lastbyte - memory_pool);
+      kfree ((void *) memory_pool);
+      unregister_chrdev (SOUND_MAJOR, "sound");
+      free_all_irqs ();
+      return -ENOMEM;
+    }
+  err = module_sound_mem_init ();
+  if (err)
+    {
+      module_sound_mem_release ();
+      kfree ((void *) memory_pool);
+      unregister_chrdev (SOUND_MAJOR, "sound");
+      free_all_irqs ();
+      return err;
+    }
+  if (lastbyte < memory_pool + memsize)
+    printk ("sound: (Suggestion) too much memory; use : 'insmod sound.o memsize=%ld'\n",
+	    lastbyte - memory_pool);
+  return 0;
+}
+
+void
+cleanup_module (void)
+{
+  if (MOD_IN_USE)
+    printk ("sound: module busy -- remove delayed\n");
+  else
+    {
+      kfree ((void *) memory_pool);
+      unregister_chrdev (SOUND_MAJOR, "sound");
+      free_all_irqs ();
+      module_sound_mem_release ();
+    }
+}
+
+#endif
+
 void
 tenmicrosec (void)
 {
@@ -222,22 +353,19 @@
 }
 
 int
-snd_set_irq_handler (int interrupt_level, void (*hndlr) (int, struct pt_regs *))
+snd_set_irq_handler (int interrupt_level, INT_HANDLER_PROTO (), char *name)
 {
   int             retcode;
 
-  retcode = request_irq(interrupt_level, hndlr,
-#ifdef SND_SA_INTERRUPT
-	SA_INTERRUPT,
-#else
-	0,
-#endif
-	"sound");
-
+  retcode = request_irq (interrupt_level, hndlr, SA_INTERRUPT, name);
   if (retcode < 0)
     {
       printk ("Sound: IRQ%d already in use\n", interrupt_level);
     }
+#ifdef MODULE
+  else
+    irqs |= (1ul << interrupt_level);
+#endif
 
   return retcode;
 }
@@ -245,6 +373,9 @@
 void
 snd_release_irq (int vect)
 {
+#ifdef MODULE
+  irqs &= ~(1ul << vect);
+#endif
   free_irq (vect);
 }
 
@@ -286,6 +417,152 @@
     return 0;
 }
 
+#ifdef MODULE
+
+#ifdef KMALLOC_DMA_BROKEN
+#define KMALLOC_MEM_REGIONS 20
+
+static char    *dma_list[KMALLOC_MEM_REGIONS];
+static int      dma_last = 0;
+inline void
+add_to_dma_list (char *adr)
+{
+  dma_list[dma_last++] = adr;
+}
+
+#endif
+
+static int
+module_sound_mem_init (void)
+{
+  int             dev, ret = 0;
+  unsigned long   dma_pagesize;
+  char           *start_addr, *end_addr;
+  struct dma_buffparms *dmap;
+
+  for (dev = 0; dev < num_audiodevs; dev++)
+    if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0)
+      {
+	dmap = audio_devs[dev]->dmap;
+	if (audio_devs[dev]->flags & DMA_AUTOMODE)
+	  audio_devs[dev]->buffcount = 1;
+
+	if (audio_devs[dev]->dmachan > 3)
+	  dma_pagesize = 131072;	/* 16bit dma: 128k */
+	else
+	  dma_pagesize = 65536;	/* 8bit dma: 64k */
+	if (debugmem)
+	  printk ("sound: dma-page-size %lu\n", dma_pagesize);
+	/* More sanity checks */
+
+	if (audio_devs[dev]->buffsize > dma_pagesize)
+	  audio_devs[dev]->buffsize = dma_pagesize;
+	audio_devs[dev]->buffsize &= 0xfffff000;	/* Truncate to n*4k */
+	if (audio_devs[dev]->buffsize < 4096)
+	  audio_devs[dev]->buffsize = 4096;
+	if (debugmem)
+	  printk ("sound: buffsize %lu\n", audio_devs[dev]->buffsize);
+	/* Now allocate the buffers */
+	for (dmap->raw_count = 0; dmap->raw_count < audio_devs[dev]->buffcount;
+	     dmap->raw_count++)
+	  {
+#ifdef KMALLOC_DMA_BROKEN
+	    start_addr = kmalloc (audio_devs[dev]->buffsize, GFP_KERNEL);
+	    if (start_addr)
+	      {
+		if (debugmem)
+		  printk ("sound: trying 0x%lx for DMA\n", (long) start_addr);
+		if (valid_dma_page ((unsigned long) start_addr,
+				    audio_devs[dev]->buffsize,
+				    dma_pagesize))
+		  add_to_dma_list (start_addr);
+		else
+		  {
+		    kfree (start_addr);
+		    start_addr = kmalloc (audio_devs[dev]->buffsize * 2,
+					  GFP_KERNEL);	/* what a waste :-( */
+		    if (start_addr)
+		      {
+			if (debugmem)
+			  printk ("sound: failed; trying 0x%lx aligned to",
+				  (long) start_addr);
+			add_to_dma_list (start_addr);
+			/* now align it to the next dma-page boundary */
+			start_addr = (char *) (((long) start_addr
+						+ dma_pagesize - 1)
+					       & ~(dma_pagesize - 1));
+			if (debugmem)
+			  printk (" 0x%lx\n", (long) start_addr);
+		      }
+		  }
+	      }
+#else
+	    start_addr = kmalloc (audio_devs[dev]->buffsize,
+				  GFP_DMA | GFP_KERNEL);
+#endif
+	    if (start_addr == NULL)
+	      ret = -ENOMEM;	/* Can't stop the loop in this case, because
+				   * ...->raw_buf [...] must be initilized
+				   * to valid values (at least to NULL)
+				 */
+	    else
+	      {
+		/* make some checks */
+		end_addr = start_addr + audio_devs[dev]->buffsize - 1;
+		if (debugmem)
+		  printk ("sound: start 0x%lx, end 0x%lx\n",
+			  (long) start_addr, (long) end_addr);
+		/* now check if it fits into the same dma-pagesize */
+		if (((long) start_addr & ~(dma_pagesize - 1))
+		    != ((long) end_addr & ~(dma_pagesize - 1))
+		    || end_addr >= (char *) (16 * 1024 * 1024))
+		  {
+		    printk (
+			     "sound: kmalloc returned invalid address 0x%lx for %ld Bytes DMA-buffer\n",
+			     (long) start_addr,
+			     audio_devs[dev]->buffsize);
+		    ret = -EFAULT;
+		  }
+	      }
+	    dmap->raw_buf[dmap->raw_count] = start_addr;
+	    dmap->raw_buf_phys[dmap->raw_count] = (unsigned long) start_addr;
+	  }
+      }
+  return ret;
+}
+
+static void
+module_sound_mem_release (void)
+{
+#ifdef KMALLOC_DMA_BROKEN
+  int             i;
+
+  for (i = 0; i < dma_last; i++)
+    {
+      if (debugmem)
+	printk ("sound: freeing 0x%lx\n", (long) dma_list[i]);
+      kfree (dma_list[i]);
+    }
+#else
+  int             dev, i;
+
+  for (dev = 0; dev < num_audiodevs; dev++)
+    if (audio_devs[dev]->buffcount > 0 && audio_devs[dev]->dmachan >= 0)
+      {
+	for (i = 0; i < audio_devs[dev]->buffcount; i++)
+	  if (audio_devs[dev]->dmap->raw_buf[i])
+	    {
+	      if (debugmem)
+		printk ("sound: freeing 0x%lx\n",
+			(long) (audio_devs[dev]->dmap->raw_buf[i]));
+	      kfree (audio_devs[dev]->dmap->raw_buf[i]);
+	    }
+      }
+#endif
+}
+
+#else /* !MODULE */
+
 void
 sound_mem_init (void)
 {
@@ -309,7 +586,7 @@
 	  audio_devs[dev]->buffcount = 1;
 
 	if (audio_devs[dev]->dmachan > 3 && audio_devs[dev]->buffsize > 65536)
-	  dma_pagesize = 131072;/* 128k */
+	  dma_pagesize = 131072;	/* 128k */
 	else
 	  dma_pagesize = 65536;
 
@@ -347,6 +624,8 @@
       }				/* for dev */
 }
 
+#endif /* !MODULE */
+
 #endif
 
 #else
@@ -365,5 +644,14 @@
 {
   /* Dummy version */
 }
+
+#ifdef MODULE
+static int
+module_sound_mem_init (void)
+{
+  return 0;			/* no error */
+}
+
+#endif
 
 #endif
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h
--- v1.3.8/linux/drivers/sound/soundvers.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/soundvers.h	Mon Jul 10 01:45:00 1995
@@ -0,0 +1 @@
+#define SOUND_VERSION_STRING "3.0-950710"
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c
--- v1.3.8/linux/drivers/sound/sscape.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/sscape.c	Mon Jul 10 01:45:23 1995
@@ -0,0 +1,1134 @@
+/*
+ * sound/sscape.c
+ *
+ * Low level driver for Ensoniq Soundscape
+ *
+ * Copyright by Hannu Savolainen 1994
+ *
+ * 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.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SSCAPE)
+
+#include "coproc.h"
+
+/*
+ *    I/O ports
+ */
+#define MIDI_DATA        0
+#define MIDI_CTRL        1
+#define HOST_CTRL        2
+#define TX_READY		0x02
+#define RX_READY		0x01
+#define HOST_DATA        3
+#define ODIE_ADDR        4
+#define ODIE_DATA        5
+
+/*
+ *    Indirect registers
+ */
+#define GA_INTSTAT_REG   0
+#define GA_INTENA_REG    1
+#define GA_DMAA_REG      2
+#define GA_DMAB_REG      3
+#define GA_INTCFG_REG    4
+#define GA_DMACFG_REG    5
+#define GA_CDCFG_REG     6
+#define GA_SMCFGA_REG    7
+#define GA_SMCFGB_REG    8
+#define GA_HMCTL_REG     9
+
+/*
+ * DMA channel identifiers (A and B)
+ */
+#define SSCAPE_DMA_A 		0
+#define SSCAPE_DMA_B		1
+
+#define PORT(name)	(devc->base+name)
+
+/*
+ * Host commands recognized by the OBP microcode
+ */
+#define CMD_GEN_HOST_ACK        0x80
+#define CMD_GEN_MPU_ACK         0x81
+#define CMD_GET_BOARD_TYPE      0x82
+#define CMD_SET_CONTROL         0x88
+#define CMD_GET_CONTROL         0x89
+#define CMD_SET_MT32            0x96
+#define CMD_GET_MT32            0x97
+#define CMD_SET_EXTMIDI         0x9b
+#define CMD_GET_EXTMIDI         0x9c
+
+#define CMD_ACK			0x80
+
+typedef struct sscape_info
+  {
+    int             base, irq, dma;
+    int             ok;		/* Properly detected */
+    int             dma_allocated;
+    int             my_audiodev;
+    int             opened;
+  }
+
+sscape_info;
+static struct sscape_info dev_info =
+{0};
+static struct sscape_info *devc = &dev_info;
+
+DEFINE_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag);
+
+/* Some older cards have assigned interrupt bits differently than new ones */
+static char     valid_interrupts_old[] =
+{9, 7, 5, 15};
+
+static char     valid_interrupts_new[] =
+{9, 5, 7, 10};
+
+static char    *valid_interrupts = valid_interrupts_new;
+
+#ifdef REVEAL_SPEA
+static char     old_hardware = 1;
+
+#else
+static char     old_hardware = 0;
+
+#endif
+
+static unsigned char
+sscape_read (struct sscape_info *devc, int reg)
+{
+  unsigned long   flags;
+  unsigned char   val;
+
+  DISABLE_INTR (flags);
+  OUTB (reg, PORT (ODIE_ADDR));
+  val = INB (PORT (ODIE_DATA));
+  RESTORE_INTR (flags);
+  return val;
+}
+
+static void
+sscape_write (struct sscape_info *devc, int reg, int data)
+{
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  OUTB (reg, PORT (ODIE_ADDR));
+  OUTB (data, PORT (ODIE_DATA));
+  RESTORE_INTR (flags);
+}
+
+static void
+host_open (struct sscape_info *devc)
+{
+  OUTB (0x00, PORT (HOST_CTRL));	/* Put the board to the host mode */
+}
+
+static void
+host_close (struct sscape_info *devc)
+{
+  OUTB (0x03, PORT (HOST_CTRL));	/* Put the board to the MIDI mode */
+}
+
+static int
+host_write (struct sscape_info *devc, unsigned char *data, int count)
+{
+  unsigned long   flags;
+  int             i, timeout;
+
+  DISABLE_INTR (flags);
+
+  /*
+     * Send the command and data bytes
+   */
+
+  for (i = 0; i < count; i++)
+    {
+      for (timeout = 10000; timeout > 0; timeout--)
+	if (INB (PORT (HOST_CTRL)) & TX_READY)
+	  break;
+
+      if (timeout <= 0)
+	{
+	  RESTORE_INTR (flags);
+	  return 0;
+	}
+
+      OUTB (data[i], PORT (HOST_DATA));
+    }
+
+
+  RESTORE_INTR (flags);
+
+  return 1;
+}
+
+static int
+host_read (struct sscape_info *devc)
+{
+  unsigned long   flags;
+  int             timeout;
+  unsigned char   data;
+
+  DISABLE_INTR (flags);
+
+  /*
+     * Read a byte
+   */
+
+  for (timeout = 10000; timeout > 0; timeout--)
+    if (INB (PORT (HOST_CTRL)) & RX_READY)
+      break;
+
+  if (timeout <= 0)
+    {
+      RESTORE_INTR (flags);
+      return -1;
+    }
+
+  data = INB (PORT (HOST_DATA));
+
+  RESTORE_INTR (flags);
+
+  return data;
+}
+
+static int
+host_command1 (struct sscape_info *devc, int cmd)
+{
+  unsigned char   buf[10];
+
+  buf[0] = (unsigned char) (cmd & 0xff);
+
+  return host_write (devc, buf, 1);
+}
+
+static int
+host_command2 (struct sscape_info *devc, int cmd, int parm1)
+{
+  unsigned char   buf[10];
+
+  buf[0] = (unsigned char) (cmd & 0xff);
+  buf[1] = (unsigned char) (parm1 & 0xff);
+
+  return host_write (devc, buf, 2);
+}
+
+static int
+host_command3 (struct sscape_info *devc, int cmd, int parm1, int parm2)
+{
+  unsigned char   buf[10];
+
+  buf[0] = (unsigned char) (cmd & 0xff);
+  buf[1] = (unsigned char) (parm1 & 0xff);
+  buf[2] = (unsigned char) (parm2 & 0xff);
+
+  return host_write (devc, buf, 3);
+}
+
+static void
+set_mt32 (struct sscape_info *devc, int value)
+{
+  host_open (devc);
+  host_command2 (devc, CMD_SET_MT32,
+		 value ? 1 : 0);
+  if (host_read (devc) != CMD_ACK)
+    {
+      printk ("SNDSCAPE: Setting MT32 mode failed\n");
+    }
+  host_close (devc);
+}
+
+static int
+get_board_type (struct sscape_info *devc)
+{
+  int             tmp;
+
+  host_open (devc);
+  if (!host_command1 (devc, CMD_GET_BOARD_TYPE))
+    tmp = -1;
+  else
+    tmp = host_read (devc);
+  host_close (devc);
+  return tmp;
+}
+
+void
+sscapeintr (INT_HANDLER_PARMS (irq, dummy))
+{
+  unsigned char   bits, tmp;
+  static int      debug = 0;
+
+  printk ("sscapeintr(0x%02x)\n", (bits = sscape_read (devc, GA_INTSTAT_REG)));
+  if (SOMEONE_WAITING (sscape_sleeper, sscape_sleep_flag))
+    {
+      WAKE_UP (sscape_sleeper, sscape_sleep_flag);
+    }
+
+  if (bits & 0x02)		/* Host interface interrupt */
+    {
+      printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc));
+    }
+
+#if (!defined(EXCLUDE_MPU401) || !defined(EXCLUDE_MPU_EMU)) && !defined(EXCLUDE_MIDI)
+  if (bits & 0x01)
+    {
+      mpuintr (INT_HANDLER_CALL (irq));
+      if (debug++ > 10)		/* Temporary debugging hack */
+	{
+	  sscape_write (devc, GA_INTENA_REG, 0x00);	/* Disable all interrupts */
+	}
+    }
+#endif
+
+  /*
+     * Acknowledge interrupts (toggle the interrupt bits)
+   */
+
+  tmp = sscape_read (devc, GA_INTENA_REG);
+  sscape_write (devc, GA_INTENA_REG, (~bits & 0x0e) | (tmp & 0xf1));
+
+}
+
+static void
+sscape_enable_intr (struct sscape_info *devc, unsigned intr_bits)
+{
+  unsigned char   temp, orig;
+
+  temp = orig = sscape_read (devc, GA_INTENA_REG);
+  temp |= intr_bits;
+  temp |= 0x80;			/* Master IRQ enable */
+
+  if (temp == orig)
+    return;			/* No change */
+
+  sscape_write (devc, GA_INTENA_REG, temp);
+}
+
+static void
+sscape_disable_intr (struct sscape_info *devc, unsigned intr_bits)
+{
+  unsigned char   temp, orig;
+
+  temp = orig = sscape_read (devc, GA_INTENA_REG);
+  temp &= ~intr_bits;
+  if ((temp & ~0x80) == 0x00)
+    temp = 0x00;		/* Master IRQ disable */
+  if (temp == orig)
+    return;			/* No change */
+
+  sscape_write (devc, GA_INTENA_REG, temp);
+}
+
+static void
+do_dma (struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode)
+{
+  unsigned char   temp;
+
+  if (dma_chan != SSCAPE_DMA_A)
+    {
+      printk ("SSCAPE: Tried to use DMA channel  != A. Why?\n");
+      return;
+    }
+
+  DMAbuf_start_dma (devc->my_audiodev,
+		    buf,
+		    blk_size, mode);
+
+  temp = devc->dma << 4;	/* Setup DMA channel select bits */
+  if (devc->dma <= 3)
+    temp |= 0x80;		/* 8 bit DMA channel */
+
+  temp |= 1;			/* Trigger DMA */
+  sscape_write (devc, GA_DMAA_REG, temp);
+  temp &= 0xfe;			/* Clear DMA trigger */
+  sscape_write (devc, GA_DMAA_REG, temp);
+}
+
+static int
+verify_mpu (struct sscape_info *devc)
+{
+  /*
+     * The SoundScape board could be in three modes (MPU, 8250 and host).
+     * If the card is not in the MPU mode, enabling the MPU driver will
+     * cause infinite loop (the driver believes that there is always some
+     * received data in the buffer.
+     *
+     * Detect this by looking if there are more than 10 received MIDI bytes
+     * (0x00) in the buffer.
+   */
+
+  int             i;
+
+  for (i = 0; i < 10; i++)
+    {
+      if (INB (devc->base + HOST_CTRL) & 0x80)
+	return 1;
+
+      if (INB (devc->base) != 0x00)
+	return 1;
+    }
+
+  printk ("SoundScape: The device is not in the MPU-401 mode\n");
+  return 0;
+}
+
+static int
+sscape_coproc_open (void *dev_info, int sub_device)
+{
+  if (sub_device == COPR_MIDI)
+    {
+      set_mt32 (devc, 0);
+      if (!verify_mpu (devc))
+	return RET_ERROR (EIO);
+    }
+
+  return 0;
+}
+
+static void
+sscape_coproc_close (void *dev_info, int sub_device)
+{
+  struct sscape_info *devc = dev_info;
+  unsigned long   flags;
+
+  DISABLE_INTR (flags);
+  if (devc->dma_allocated)
+    {
+      sscape_write (devc, GA_DMAA_REG, 0x20);	/* DMA channel disabled */
+#ifndef EXCLUDE_NATIVE_PCM
+      DMAbuf_close_dma (devc->my_audiodev);
+#endif
+      devc->dma_allocated = 0;
+    }
+  RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag);
+  RESTORE_INTR (flags);
+
+  return;
+}
+
+static void
+sscape_coproc_reset (void *dev_info)
+{
+}
+
+static int
+sscape_download_boot (struct sscape_info *devc, unsigned char *block, int size, int flag)
+{
+  unsigned long   flags;
+  unsigned char   temp;
+  int             done, timeout;
+
+  if (flag & CPF_FIRST)
+    {
+      /*
+         * First block. Have to allocate DMA and to reset the board
+         * before continuing.
+       */
+
+      DISABLE_INTR (flags);
+      if (devc->dma_allocated == 0)
+	{
+#ifndef EXCLUDE_NATIVE_PCM
+	  if (DMAbuf_open_dma (devc->my_audiodev) < 0)
+	    {
+	      RESTORE_INTR (flags);
+	      return 0;
+	    }
+#endif
+
+	  devc->dma_allocated = 1;
+	}
+      RESTORE_INTR (flags);
+
+      sscape_write (devc, GA_HMCTL_REG,
+		    (temp = sscape_read (devc, GA_HMCTL_REG)) & 0x3f);	/*Reset */
+
+      for (timeout = 10000; timeout > 0; timeout--)
+	sscape_read (devc, GA_HMCTL_REG);	/* Delay */
+
+      /* Take board out of reset */
+      sscape_write (devc, GA_HMCTL_REG,
+		    (temp = sscape_read (devc, GA_HMCTL_REG)) | 0x80);
+    }
+
+  /*
+     * Transfer one code block using DMA
+   */
+  memcpy (audio_devs[devc->my_audiodev]->dmap->raw_buf[0], block, size);
+
+  DISABLE_INTR (flags);
+/******** INTERRUPTS DISABLED NOW ********/
+  do_dma (devc, SSCAPE_DMA_A,
+	  audio_devs[devc->my_audiodev]->dmap->raw_buf_phys[0],
+	  size, DMA_MODE_WRITE);
+
+  /*
+   * Wait until transfer completes.
+   */
+  RESET_WAIT_QUEUE (sscape_sleeper, sscape_sleep_flag);
+  done = 0;
+  timeout = 100;
+  while (!done && timeout-- > 0)
+    {
+      int             resid;
+
+      DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1);
+      clear_dma_ff (devc->dma);
+      if ((resid = get_dma_residue (devc->dma)) == 0)
+	done = 1;
+    }
+
+  RESTORE_INTR (flags);
+  if (!done)
+    return 0;
+
+  if (flag & CPF_LAST)
+    {
+      /*
+         * Take the board out of reset
+       */
+      OUTB (0x00, PORT (HOST_CTRL));
+      OUTB (0x00, PORT (MIDI_CTRL));
+
+      temp = sscape_read (devc, GA_HMCTL_REG);
+      temp |= 0x40;
+      sscape_write (devc, GA_HMCTL_REG, temp);	/* Kickstart the board */
+
+      /*
+         * Wait until the ODB wakes up
+       */
+
+      DISABLE_INTR (flags);
+      done = 0;
+      timeout = 5 * HZ;
+      while (!done && timeout-- > 0)
+	{
+	  DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1);
+	  if (INB (PORT (HOST_DATA)) == 0xff)	/* OBP startup acknowledge */
+	    done = 1;
+	}
+      RESTORE_INTR (flags);
+      if (!done)
+	{
+	  printk ("SoundScape: The OBP didn't respond after code download\n");
+	  return 0;
+	}
+
+      DISABLE_INTR (flags);
+      done = 0;
+      timeout = 5 * HZ;
+      while (!done && timeout-- > 0)
+	{
+	  DO_SLEEP (sscape_sleeper, sscape_sleep_flag, 1);
+	  if (INB (PORT (HOST_DATA)) == 0xfe)	/* Host startup acknowledge */
+	    done = 1;
+	}
+      RESTORE_INTR (flags);
+      if (!done)
+	{
+	  printk ("SoundScape: OBP Initialization failed.\n");
+	  return 0;
+	}
+
+      printk ("SoundScape board of type %d initialized OK\n",
+	      get_board_type (devc));
+
+#ifdef SSCAPE_DEBUG3
+      /*
+         * Temporary debugging aid. Print contents of the registers after
+         * downloading the code.
+       */
+      {
+	int             i;
+
+	for (i = 0; i < 13; i++)
+	  printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i));
+      }
+#endif
+
+    }
+
+  return 1;
+}
+
+static int
+download_boot_block (void *dev_info, copr_buffer * buf)
+{
+  if (buf->len <= 0 || buf->len > sizeof (buf->data))
+    return RET_ERROR (EINVAL);
+
+  if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags))
+    {
+      printk ("SSCAPE: Unable to load microcode block to the OBP.\n");
+      return RET_ERROR (EIO);
+    }
+
+  return 0;
+}
+
+static int
+sscape_coproc_ioctl (void *dev_info, unsigned int cmd, unsigned int arg, int local)
+{
+
+  switch (cmd)
+    {
+    case SNDCTL_COPR_RESET:
+      sscape_coproc_reset (dev_info);
+      return 0;
+      break;
+
+    case SNDCTL_COPR_LOAD:
+      {
+	copr_buffer    *buf;
+	int             err;
+
+	buf = (copr_buffer *) KERNEL_MALLOC (sizeof (copr_buffer));
+	IOCTL_FROM_USER ((char *) buf, (char *) arg, 0, sizeof (*buf));
+	err = download_boot_block (dev_info, buf);
+	KERNEL_FREE (buf);
+	return err;
+      }
+      break;
+
+    default:
+      return RET_ERROR (EINVAL);
+    }
+
+  return RET_ERROR (EINVAL);
+}
+
+static coproc_operations sscape_coproc_operations =
+{
+  "SoundScape M68K",
+  sscape_coproc_open,
+  sscape_coproc_close,
+  sscape_coproc_ioctl,
+  sscape_coproc_reset,
+  &dev_info
+};
+
+static int
+sscape_audio_open (int dev, int mode)
+{
+  unsigned long   flags;
+  sscape_info    *devc = (sscape_info *) audio_devs[dev]->devc;
+
+  DISABLE_INTR (flags);
+  if (devc->opened)
+    {
+      RESTORE_INTR (flags);
+      return RET_ERROR (EBUSY);
+    }
+
+  if (devc->dma_allocated == 0)
+    {
+      int             err;
+
+      if ((err = DMAbuf_open_dma (devc->my_audiodev)) < 0)
+	{
+	  RESTORE_INTR (flags);
+	  return err;
+	}
+
+      devc->dma_allocated = 1;
+    }
+
+  devc->opened = 1;
+  RESTORE_INTR (flags);
+#ifdef SSCAPE_DEBUG4
+  /*
+     * Temporary debugging aid. Print contents of the registers
+     * when the device is opened.
+   */
+  {
+    int             i;
+
+    for (i = 0; i < 13; i++)
+      printk ("I%d = %02x\n", i, sscape_read (devc, i));
+  }
+#endif
+
+  return 0;
+}
+
+static void
+sscape_audio_close (int dev)
+{
+  unsigned long   flags;
+  sscape_info    *devc = (sscape_info *) audio_devs[dev]->devc;
+
+  DEB (printk ("sscape_audio_close(void)\n"));
+
+  DISABLE_INTR (flags);
+
+  if (devc->dma_allocated)
+    {
+      sscape_write (devc, GA_DMAA_REG, 0x20);	/* DMA channel disabled */
+      DMAbuf_close_dma (dev);
+      devc->dma_allocated = 0;
+    }
+  devc->opened = 0;
+
+  RESTORE_INTR (flags);
+}
+
+static int
+set_speed (sscape_info * devc, int arg)
+{
+  return 8000;
+}
+
+static int
+set_channels (sscape_info * devc, int arg)
+{
+  return 1;
+}
+
+static int
+set_format (sscape_info * devc, int arg)
+{
+  return AFMT_U8;
+}
+
+static int
+sscape_audio_ioctl (int dev, unsigned int cmd, unsigned int arg, int local)
+{
+  sscape_info    *devc = (sscape_info *) audio_devs[dev]->devc;
+
+  switch (cmd)
+    {
+    case SOUND_PCM_WRITE_RATE:
+      if (local)
+	return set_speed (devc, arg);
+      return IOCTL_OUT (arg, set_speed (devc, IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_RATE:
+      if (local)
+	return 8000;
+      return IOCTL_OUT (arg, 8000);
+
+    case SNDCTL_DSP_STEREO:
+      if (local)
+	return set_channels (devc, arg + 1) - 1;
+      return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg) + 1) - 1);
+
+    case SOUND_PCM_WRITE_CHANNELS:
+      if (local)
+	return set_channels (devc, arg);
+      return IOCTL_OUT (arg, set_channels (devc, IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_CHANNELS:
+      if (local)
+	return 1;
+      return IOCTL_OUT (arg, 1);
+
+    case SNDCTL_DSP_SAMPLESIZE:
+      if (local)
+	return set_format (devc, arg);
+      return IOCTL_OUT (arg, set_format (devc, IOCTL_IN (arg)));
+
+    case SOUND_PCM_READ_BITS:
+      if (local)
+	return 8;
+      return IOCTL_OUT (arg, 8);
+
+    default:;
+    }
+  return RET_ERROR (EINVAL);
+}
+
+static void
+sscape_audio_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+}
+
+static void
+sscape_audio_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart)
+{
+}
+
+static int
+sscape_audio_prepare_for_input (int dev, int bsize, int bcount)
+{
+  return 0;
+}
+
+static int
+sscape_audio_prepare_for_output (int dev, int bsize, int bcount)
+{
+  return 0;
+}
+
+static void
+sscape_audio_halt (int dev)
+{
+}
+
+static void
+sscape_audio_reset (int dev)
+{
+  sscape_audio_halt (dev);
+}
+
+static struct audio_operations sscape_audio_operations =
+{
+  "Not functional",
+  0,
+  AFMT_U8 | AFMT_S16_LE,
+  NULL,
+  sscape_audio_open,
+  sscape_audio_close,
+  sscape_audio_output_block,
+  sscape_audio_start_input,
+  sscape_audio_ioctl,
+  sscape_audio_prepare_for_input,
+  sscape_audio_prepare_for_output,
+  sscape_audio_reset,
+  sscape_audio_halt,
+  NULL,
+  NULL
+};
+
+long
+attach_sscape (long mem_start, struct address_info *hw_config)
+{
+  int             my_dev;
+
+#ifndef SSCAPE_REGS
+  /*
+     * Config register values for Spea/V7 Media FX and Ensoniq S-2000.
+     * These values are card
+     * dependent. If you have another SoundScape based card, you have to
+     * find the correct values. Do the following:
+     *  - Compile this driver with SSCAPE_DEBUG1 defined.
+     *  - Shut down and power off your machine.
+     *  - Boot with DOS so that the SSINIT.EXE program is run.
+     *  - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed
+     *    when detecting the SoundScape.
+     *  - Modify the following list to use the values printed during boot.
+     *    Undefine the SSCAPE_DEBUG1
+   */
+#define SSCAPE_REGS { \
+/* I0 */	0x00, \
+		0xf0, /* Note! Ignored. Set always to 0xf0 */ \
+		0x20, /* Note! Ignored. Set always to 0x20 */ \
+		0x20, /* Note! Ignored. Set always to 0x20 */ \
+		0xf5, /* Ignored */ \
+		0x10, \
+		0x00, \
+		0x2e, /* I7 MEM config A. Likely to vary between models */ \
+		0x00, /* I8 MEM config B. Likely to vary between models */ \
+/* I9 */	0x40 /* Ignored */ \
+	}
+#endif
+
+  unsigned long   flags;
+  static unsigned char regs[10] = SSCAPE_REGS;
+
+  int             i, irq_bits = 0xff;
+
+  if (!probe_sscape (hw_config))
+    return mem_start;
+
+  if (old_hardware)
+    {
+      valid_interrupts = valid_interrupts_old;
+      printk (" <Ensoniq Soundscape (old)>");
+    }
+  else
+    printk (" <Ensoniq Soundscape>");
+
+  for (i = 0; i < sizeof (valid_interrupts); i++)
+    if (hw_config->irq == valid_interrupts[i])
+      {
+	irq_bits = i;
+	break;
+      }
+
+  if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff))
+    {
+      printk ("Invalid IRQ%d\n", hw_config->irq);
+      return mem_start;
+    }
+
+  DISABLE_INTR (flags);
+
+  for (i = 1; i < 10; i++)
+    switch (i)
+      {
+      case 1:			/* Host interrupt enable */
+	sscape_write (devc, i, 0xf0);	/* All interrupts enabled */
+	break;
+
+      case 2:			/* DMA A status/trigger register */
+      case 3:			/* DMA B status/trigger register */
+	sscape_write (devc, i, 0x20);	/* DMA channel disabled */
+	break;
+
+      case 4:			/* Host interrupt config reg */
+	sscape_write (devc, i, 0xf0 | (irq_bits << 2) | irq_bits);
+	break;
+
+      case 5:			/* Don't destroy CD-ROM DMA config bits (0xc0) */
+	sscape_write (devc, i, (regs[i] & 0x3f) |
+		      (sscape_read (devc, i) & 0xc0));
+	break;
+
+      case 6:			/* CD-ROM config. Don't touch. */
+	break;
+
+      case 9:			/* Master control reg. Don't modify CR-ROM bits. Disable SB emul */
+	sscape_write (devc, i,
+		      (sscape_read (devc, i) & 0xf0) | 0x00);
+	break;
+
+      default:
+	sscape_write (devc, i, regs[i]);
+      }
+
+  RESTORE_INTR (flags);
+
+#ifdef SSCAPE_DEBUG2
+  /*
+     * Temporary debugging aid. Print contents of the registers after
+     * changing them.
+   */
+  {
+    int             i;
+
+    for (i = 0; i < 13; i++)
+      printk ("I%d = %02x (new value)\n", i, sscape_read (devc, i));
+  }
+#endif
+
+#if !defined(EXCLUDE_MIDI) && !defined(EXCLUDE_MPU_EMU)
+  hw_config->always_detect = 1;
+  if (probe_mpu401 (hw_config))
+    {
+      int             prev_devs;
+
+      prev_devs = num_midis;
+      mem_start = attach_mpu401 (mem_start, hw_config);
+
+      if (num_midis == (prev_devs + 1))		/* The MPU driver installed itself */
+	midi_devs[prev_devs]->coproc = &sscape_coproc_operations;
+    }
+#endif
+
+#ifndef EXCLUDE_NATIVE_PCM
+  /* Not supported yet */
+
+#ifndef EXCLUDE_AUDIO
+  if (num_audiodevs < MAX_AUDIO_DEV)
+    {
+      audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations;
+      audio_devs[my_dev]->dmachan = hw_config->dma;
+      audio_devs[my_dev]->buffcount = 1;
+      audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
+      audio_devs[my_dev]->devc = devc;
+      devc->my_audiodev = my_dev;
+      devc->opened = 0;
+      audio_devs[my_dev]->coproc = &sscape_coproc_operations;
+      if (snd_set_irq_handler (hw_config->irq, sscapeintr, "SoundScape") < 0)
+	printk ("Error: Can't allocate IRQ for SoundScape\n");
+
+      sscape_write (devc, GA_INTENA_REG, 0x80);		/* Master IRQ enable */
+    }
+  else
+    printk ("SoundScape: More than enough audio devices detected\n");
+#endif
+#endif
+  devc->ok = 1;
+  return mem_start;
+}
+
+int
+probe_sscape (struct address_info *hw_config)
+{
+  unsigned char   save;
+
+  devc->base = hw_config->io_base;
+  devc->irq = hw_config->irq;
+  devc->dma = hw_config->dma;
+
+  /*
+     * First check that the address register of "ODIE" is
+     * there and that it has exactly 4 writeable bits.
+     * First 4 bits
+   */
+  if ((save = INB (PORT (ODIE_ADDR))) & 0xf0)
+    return 0;
+
+  OUTB (0x00, PORT (ODIE_ADDR));
+  if (INB (PORT (ODIE_ADDR)) != 0x00)
+    return 0;
+
+  OUTB (0xff, PORT (ODIE_ADDR));
+  if (INB (PORT (ODIE_ADDR)) != 0x0f)
+    return 0;
+
+  OUTB (save, PORT (ODIE_ADDR));
+
+  /*
+     * Now verify that some indirect registers return zero on some bits.
+     * This may break the driver with some future revisions of "ODIE" but...
+   */
+
+  if (sscape_read (devc, 0) & 0x0c)
+    return 0;
+
+  if (sscape_read (devc, 1) & 0x0f)
+    return 0;
+
+  if (sscape_read (devc, 5) & 0x0f)
+    return 0;
+
+#ifdef SSCAPE_DEBUG1
+  /*
+     * Temporary debugging aid. Print contents of the registers before
+     * changing them.
+   */
+  {
+    int             i;
+
+    for (i = 0; i < 13; i++)
+      printk ("I%d = %02x (old value)\n", i, sscape_read (devc, i));
+  }
+#endif
+
+  if (old_hardware)		/* Check that it's really an old Spea/Reveal card. */
+    {
+      int             tmp, status = 0;
+      int             cc;
+
+      if (!((tmp = sscape_read (devc, GA_HMCTL_REG)) & 0xc0))
+	{
+	  sscape_write (devc, GA_HMCTL_REG, tmp | 0x80);
+	  for (cc = 0; cc < 200000; ++cc)
+	    INB (devc->base + ODIE_ADDR);
+	}
+      else
+	old_hardware = 0;
+    }
+
+
+  return 1;
+}
+
+int
+probe_ss_ms_sound (struct address_info *hw_config)
+{
+  int             i, irq_bits = 0xff;
+
+  if (devc->ok == 0)
+    {
+      printk ("SoundScape: Invalid initialization order.\n");
+      return 0;
+    }
+
+  for (i = 0; i < sizeof (valid_interrupts); i++)
+    if (hw_config->irq == valid_interrupts[i])
+      {
+	irq_bits = i;
+	break;
+      }
+  if (hw_config->irq > 15 || irq_bits == 0xff)
+    {
+      printk ("SoundScape: Invalid MSS IRQ%d\n", hw_config->irq);
+      return 0;
+    }
+
+  return ad1848_detect (hw_config->io_base);
+}
+
+long
+attach_ss_ms_sound (long mem_start, struct address_info *hw_config)
+{
+  /*
+     * This routine configures the SoundScape card for use with the
+     * Win Sound System driver. The AD1848 codec interface uses the CD-ROM
+     * config registers of the "ODIE".
+   */
+
+  int             i, irq_bits = 0xff;
+
+#ifdef EXCLUDE_NATIVE_PCM
+  int             prev_devs = num_audiodevs;
+
+#endif
+
+  /*
+     * Setup the DMA polarity.
+   */
+  sscape_write (devc, GA_DMACFG_REG, 0x50);
+
+  /*
+     * Take the gate-arry off of the DMA channel.
+   */
+  sscape_write (devc, GA_DMAB_REG, 0x20);
+
+  /*
+     * Init the AD1848 (CD-ROM) config reg.
+   */
+
+  for (i = 0; i < sizeof (valid_interrupts); i++)
+    if (hw_config->irq == valid_interrupts[i])
+      {
+	irq_bits = i;
+	break;
+      }
+
+  sscape_write (devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) |
+		(irq_bits << 1));
+
+  if (hw_config->irq == devc->irq)
+    printk ("SoundScape: Warning! The WSS mode can't share IRQ with MIDI\n");
+
+  ad1848_init ("SoundScape", hw_config->io_base,
+	       hw_config->irq,
+	       hw_config->dma,
+	       hw_config->dma);
+
+#ifdef EXCLUDE_NATIVE_PCM
+  if (num_audiodevs == (prev_devs + 1))		/* The AD1848 driver installed itself */
+    audio_devs[prev_devs]->coproc = &sscape_coproc_operations;
+#endif
+#ifdef SSCAPE_DEBUG5
+  /*
+     * Temporary debugging aid. Print contents of the registers
+     * after the AD1848 device has been initialized.
+   */
+  {
+    int             i;
+
+    for (i = 0; i < 13; i++)
+      printk ("I%d = %02x\n", i, sscape_read (devc, i));
+  }
+#endif
+
+  return mem_start;
+}
+
+#endif
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c
--- v1.3.8/linux/drivers/sound/sys_timer.c	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/sys_timer.c	Mon Jul 10 01:45:23 1995
@@ -51,17 +51,23 @@
 tmr2ticks (int tmr_value)
 {
   /*
- *    Convert system timer ticks (HZ) to MIDI ticks
- */
+     *    Convert system timer ticks (HZ) to MIDI ticks
+   */
 
   unsigned long   tmp;
   unsigned long   scale;
 
-  tmp = (tmr_value * 1000) / HZ;/* Convert to msecs */
+  tmp = (tmr_value * 1000) / HZ;	/* Convert to msecs */
 
-  scale = (60 * 1000) / (curr_tempo * curr_timebase);	/* msecs per MIDI tick */
+  if (curr_tempo == 0 || curr_timebase == 0)	/* Error? */
+    scale = 1;
+  else
+    scale = (60 * 1000) / (curr_tempo * curr_timebase);		/* msecs per MIDI tick */
 
-  return (tmp + (scale / 2)) / scale;
+  if (scale == 0)		/* Error? */
+    scale = 1;
+
+  return (tmp + (scale >> 1)) / scale;
 }
 
 static void
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v1.3.8/linux/drivers/sound/trix.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sound/trix.c	Mon Jul 10 01:45:23 1995
@@ -0,0 +1,331 @@
+/*
+ * sound/trix.c
+ *
+ * Low level driver for the MediaTriX AudioTriX Pro
+ * (MT-0002-PC Control Chip)
+ *
+ * Copyright by Hannu Savolainen 1995
+ *
+ * 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.
+ *
+ */
+
+#include "sound_config.h"
+
+#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_TRIX)
+
+#ifdef INCLUDE_TRIX_BOOT
+#include "trix_boot.h"
+#endif
+
+static int      kilroy_was_here = 0;	/* Don't detect twice */
+static int      sb_initialized = 0;
+static int      mpu_initialized = 0;
+
+static unsigned char
+trix_read (int addr)
+{
+  OUTB ((unsigned char) addr, 0x390);	/* MT-0002-PC ASIC address */
+  return INB (0x391);		/* MT-0002-PC ASIC data */
+}
+
+static void
+trix_write (int addr, int data)
+{
+  OUTB ((unsigned char) addr, 0x390);	/* MT-0002-PC ASIC address */
+  OUTB ((unsigned char) data, 0x391);	/* MT-0002-PC ASIC data */
+}
+
+static void
+download_boot (int base)
+{
+#ifdef INCLUDE_TRIX_BOOT
+  int             i = 0, n = sizeof (trix_boot);
+
+  trix_write (0xf8, 0x00);	/* ??????? */
+  OUTB (0x01, base + 6);	/* Clear the internal data pointer */
+  OUTB (0x00, base + 6);	/* Restart */
+
+  /*
+     *  Write the boot code to the RAM upload/download register.
+     *  Each write increments the internal data pointer.
+   */
+  OUTB (0x01, base + 6);	/* Clear the internal data pointer */
+  OUTB (0x1A, 0x390);		/* Select RAM download/upload port */
+
+  for (i = 0; i < n; i++)
+    OUTB (trix_boot[i], 0x391);
+  for (i = n; i < 10016; i++)	/* Clear up to first 16 bytes of data RAM */
+    OUTB (0x00, 0x391);
+  OUTB (0x00, base + 6);	/* Reset */
+  OUTB (0x50, 0x390);		/* ?????? */
+#endif
+}
+
+static int
+trix_set_wss_port (struct address_info *hw_config)
+{
+  unsigned char   addr_bits;
+
+  if (kilroy_was_here)		/* Already initialized */
+    return 0;
+
+  kilroy_was_here = 1;
+
+  if (trix_read (0x15) != 0x71)	/* No asic signature */
+    return 0;
+
+  /*
+     * Disable separate wave playback and recording DMA channels since
+     * the driver doesn't support duplex mode yet.
+   */
+
+  trix_write (0x13, trix_read (0x13) & ~0x80);
+  trix_write (0x14, trix_read (0x14) & ~0x80);
+
+  /*
+     * Configure the ASIC to place the codec to the proper I/O location
+   */
+
+  switch (hw_config->io_base)
+    {
+    case 0x530:
+      addr_bits = 0;
+      break;
+    case 0x604:
+      addr_bits = 1;
+      break;
+    case 0xE80:
+      addr_bits = 2;
+      break;
+    case 0xF40:
+      addr_bits = 3;
+      break;
+    default:
+      return 0;
+    }
+
+  trix_write (0x19, (trix_read (0x19) & 0x03) | addr_bits);
+  return 1;
+}
+
+/*
+ *    Probe and attach routines for the Windows Sound System mode of
+ *      AudioTriX Pro
+ */
+
+int
+probe_trix_wss (struct address_info *hw_config)
+{
+  /*
+     * Check if the IO port returns valid signature. The original MS Sound
+     * system returns 0x04 while some cards (AudioTriX Pro for example)
+     * return 0x00.
+   */
+  if (!trix_set_wss_port (hw_config))
+    return 0;
+
+  if ((INB (hw_config->io_base + 3) & 0x3f) != 0x00)
+    {
+      DDB (printk ("No MSS signature detected on port 0x%x\n", hw_config->io_base));
+      return 0;
+    }
+
+  if (hw_config->irq > 11)
+    {
+      printk ("AudioTriX: Bad WSS IRQ %d\n", hw_config->irq);
+      return 0;
+    }
+
+  if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
+    {
+      printk ("AudioTriX: Bad WSS DMA %d\n", hw_config->dma);
+      return 0;
+    }
+
+  /*
+     * Check that DMA0 is not in use with a 8 bit board.
+   */
+
+  if (hw_config->dma == 0 && INB (hw_config->io_base + 3) & 0x80)
+    {
+      printk ("AudioTriX: Can't use DMA0 with a 8 bit card\n");
+      return 0;
+    }
+
+  if (hw_config->irq > 7 && hw_config->irq != 9 && INB (hw_config->io_base + 3) & 0x80)
+    {
+      printk ("AudioTriX: Can't use IRQ%d with a 8 bit card\n", hw_config->irq);
+      return 0;
+    }
+
+  return ad1848_detect (hw_config->io_base + 4);
+}
+
+long
+attach_trix_wss (long mem_start, struct address_info *hw_config)
+{
+  static unsigned char interrupt_bits[12] =
+  {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
+  char            bits;
+
+  static unsigned char dma_bits[4] =
+  {1, 2, 0, 3};
+
+  int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
+
+  if (!kilroy_was_here)
+    return mem_start;
+
+  /*
+     * Set the IRQ and DMA addresses.
+   */
+
+  bits = interrupt_bits[hw_config->irq];
+  if (bits == -1)
+    return mem_start;
+
+  OUTB (bits | 0x40, config_port);
+  if ((INB (version_port) & 0x40) == 0)
+    printk ("[IRQ Conflict?]");
+
+  OUTB (bits | dma_bits[hw_config->dma], config_port);	/* Write IRQ+DMA setup */
+
+  ad1848_init ("AudioTriX Pro", hw_config->io_base + 4,
+	       hw_config->irq,
+	       hw_config->dma,
+	       hw_config->dma);
+  return mem_start;
+}
+
+int
+probe_trix_sb (struct address_info *hw_config)
+{
+
+  int             tmp;
+  unsigned char   conf;
+  static char     irq_translate[] =
+  {-1, -1, -1, 0, 1, 2, -1, 3};
+
+#ifndef INCLUDE_TRIX_BOOT
+  return 0;			/* No boot code -> no fun */
+#endif
+  if (!kilroy_was_here)
+    return 0;			/* AudioTriX Pro has not been detected earlier */
+
+  if (sb_initialized)
+    return 0;
+
+  if (hw_config->io_base & 0xffffff8f != 0x200)
+    return 0;
+
+  tmp = hw_config->irq;
+  if (tmp > 7)
+    return 0;
+  if (irq_translate[tmp] == -1)
+    return 0;
+
+  tmp = hw_config->dma;
+  if (tmp != 1 && tmp != 3)
+    return 0;
+
+  conf = 0x84;			/* DMA and IRQ enable */
+  conf |= hw_config->io_base & 0x70;	/* I/O address bits */
+  conf |= irq_translate[hw_config->irq];
+  if (hw_config->dma == 3)
+    conf |= 0x08;
+  trix_write (0x1b, conf);
+
+  download_boot (hw_config->io_base);
+  sb_initialized = 1;
+
+  return 1;
+}
+
+long
+attach_trix_sb (long mem_start, struct address_info *hw_config)
+{
+#ifndef EXCLUDE_SB
+  extern int      sb_no_recording;
+
+  sb_dsp_disable_midi ();
+  sb_no_recording = 1;
+#endif
+  printk (" <AudioTriX (SB)>");
+  return mem_start;
+}
+
+long
+attach_trix_mpu (long mem_start, struct address_info *hw_config)
+{
+  return attach_mpu401 (mem_start, hw_config);
+}
+
+int
+probe_trix_mpu (struct address_info *hw_config)
+{
+  unsigned char   conf;
+  static char     irq_bits[] =
+  {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5};
+
+  if (!kilroy_was_here)
+    return 0;			/* AudioTriX Pro has not been detected earlier */
+
+  if (!sb_initialized)
+    return 0;
+
+  if (mpu_initialized)
+    return 0;
+
+  if (hw_config->irq > 9)
+    return 0;
+
+  if (irq_bits[hw_config->irq] == -1)
+    return 0;
+
+  switch (hw_config->io_base)
+    {
+    case 0x330:
+      conf = 0x00;
+      break;
+    case 0x370:
+      conf = 0x04;
+      break;
+    case 0x3b0:
+      conf = 0x08;
+      break;
+    case 0x3f0:
+      conf = 0x0c;
+      break;
+    default:
+      return 0;			/* Invalid port */
+    }
+
+  conf |= irq_bits[hw_config->irq] << 4;
+
+  trix_write (0x19, (trix_read (0x19) & 0x83) | conf);
+
+  mpu_initialized = 1;
+
+  return probe_mpu401 (hw_config);
+}
+
+#endif
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/uart6850.c linux/drivers/sound/uart6850.c
--- v1.3.8/linux/drivers/sound/uart6850.c	Tue Jan 17 07:49:57 1995
+++ linux/drivers/sound/uart6850.c	Mon Jul 10 01:45:24 1995
@@ -93,9 +93,8 @@
 }
 
 void
-m6850intr (int unit, struct pt_regs * regs)
+m6850intr (INTR_HANDLER_PARMS (irq, dummy))
 {
-  printk ("M");
   if (input_avail ())
     uart6850_input_loop ();
 }
@@ -243,6 +242,7 @@
 {
   {"6850 UART", 0, 0, SNDCARD_UART6850},
   &std_midi_synth,
+  {0},
   uart6850_open,
   uart6850_close,
   uart6850_ioctl,
@@ -309,7 +309,7 @@
   uart6850_base = hw_config->io_base;
   uart6850_irq = hw_config->irq;
 
-  if (snd_set_irq_handler (uart6850_irq, m6850intr) < 0)
+  if (snd_set_irq_handler (uart6850_irq, m6850intr, "MIDI6850") < 0)
     return 0;
 
   ok = reset_uart6850 ();
diff -u --recursive --new-file v1.3.8/linux/drivers/sound/ulaw.h linux/drivers/sound/ulaw.h
--- v1.3.8/linux/drivers/sound/ulaw.h	Mon Jul 18 09:50:55 1994
+++ linux/drivers/sound/ulaw.h	Sun Jun 25 17:09:37 1995
@@ -1,69 +1,74 @@
+
+/*
+ * This is a new ulaw.h made by Andy Fingerhut <jaf@dworkin.wustl.edu>
+ */
+
 static unsigned char ulaw_dsp[] = {
-     0,    0,    0,    0,    0,    0,    0,    0, 
-     0,    0,    0,    0,    0,    0,    0,    0, 
-     0,    0,    0,    0,    0,    0,    0,    0, 
-     0,    0,    0,    0,    0,    0,    0,    2, 
-     5,    9,   13,   17,   21,   25,   29,   33, 
-    37,   41,   45,   49,   53,   57,   61,   65, 
-    68,   70,   72,   74,   76,   78,   80,   82, 
-    84,   86,   88,   90,   92,   94,   96,   98, 
-   100,  101,  102,  103,  104,  105,  106,  107, 
-   108,  109,  110,  111,  112,  113,  114,  115, 
-   115,  116,  116,  117,  117,  118,  118,  119, 
-   119,  120,  120,  121,  121,  122,  122,  123, 
-   123,  123,  124,  124,  124,  124,  125,  125, 
-   125,  125,  126,  126,  126,  126,  127,  127, 
-   127,  127,  127,  127,  128,  128,  128,  128, 
-   128,  128,  128,  128,  128,  128,  128,  128, 
-   255,  255,  255,  255,  255,  255,  255,  255, 
-   255,  255,  255,  255,  255,  255,  255,  255, 
-   255,  255,  255,  255,  255,  255,  255,  255, 
-   255,  255,  255,  255,  255,  255,  255,  255, 
-   252,  248,  244,  240,  236,  232,  228,  224, 
-   220,  216,  212,  208,  204,  200,  196,  192, 
-   189,  187,  185,  183,  181,  179,  177,  175, 
-   173,  171,  169,  167,  165,  163,  161,  159, 
-   157,  156,  155,  154,  153,  152,  151,  150, 
-   149,  148,  147,  146,  145,  144,  143,  142, 
-   142,  141,  141,  140,  140,  139,  139,  138, 
-   138,  137,  137,  136,  136,  135,  135,  134, 
-   134,  134,  133,  133,  133,  133,  132,  132, 
-   132,  132,  131,  131,  131,  131,  130,  130, 
-   130,  130,  130,  130,  129,  129,  129,  129, 
-   129,  129,  129,  129,  128,  128,  128,  128, 
+    2,    6,   10,   14,   18,   22,   26,   30,
+   34,   38,   42,   46,   50,   54,   58,   62,
+   65,   67,   69,   71,   73,   75,   77,   79,
+   81,   83,   85,   87,   89,   91,   93,   95,
+   97,   98,   99,  100,  101,  102,  103,  104,
+  105,  106,  107,  108,  109,  110,  111,  112,
+  112,  113,  113,  114,  114,  115,  115,  116,
+  116,  117,  117,  118,  118,  119,  119,  120,
+  120,  120,  121,  121,  121,  121,  122,  122,
+  122,  122,  123,  123,  123,  123,  124,  124,
+  124,  124,  124,  124,  125,  125,  125,  125,
+  125,  125,  125,  125,  126,  126,  126,  126,
+  126,  126,  126,  126,  126,  126,  126,  126,
+  127,  127,  127,  127,  127,  127,  127,  127,
+  127,  127,  127,  127,  127,  127,  127,  127,
+  127,  127,  127,  127,  127,  127,  127,  128,
+  253,  249,  245,  241,  237,  233,  229,  225,
+  221,  217,  213,  209,  205,  201,  197,  193,
+  190,  188,  186,  184,  182,  180,  178,  176,
+  174,  172,  170,  168,  166,  164,  162,  160,
+  158,  157,  156,  155,  154,  153,  152,  151,
+  150,  149,  148,  147,  146,  145,  144,  143,
+  143,  142,  142,  141,  141,  140,  140,  139,
+  139,  138,  138,  137,  137,  136,  136,  135,
+  135,  135,  134,  134,  134,  134,  133,  133,
+  133,  133,  132,  132,  132,  132,  131,  131,
+  131,  131,  131,  131,  130,  130,  130,  130,
+  130,  130,  130,  130,  129,  129,  129,  129,
+  129,  129,  129,  129,  129,  129,  129,  129,
+  128,  128,  128,  128,  128,  128,  128,  128,
+  128,  128,  128,  128,  128,  128,  128,  128,
+  128,  128,  128,  128,  128,  128,  128,  128
 };
 
 static unsigned char dsp_ulaw[] = {
-    31,   31,   31,   32,   32,   32,   32,   33, 
-    33,   33,   33,   34,   34,   34,   34,   35, 
-    35,   35,   35,   36,   36,   36,   36,   37, 
-    37,   37,   37,   38,   38,   38,   38,   39, 
-    39,   39,   39,   40,   40,   40,   40,   41, 
-    41,   41,   41,   42,   42,   42,   42,   43, 
-    43,   43,   43,   44,   44,   44,   44,   45, 
-    45,   45,   45,   46,   46,   46,   46,   47, 
-    47,   47,   47,   48,   48,   49,   49,   50, 
-    50,   51,   51,   52,   52,   53,   53,   54, 
-    54,   55,   55,   56,   56,   57,   57,   58, 
-    58,   59,   59,   60,   60,   61,   61,   62, 
-    62,   63,   63,   64,   65,   66,   67,   68, 
-    69,   70,   71,   72,   73,   74,   75,   76, 
-    77,   78,   79,   81,   83,   85,   87,   89, 
-    91,   93,   95,   99,  103,  107,  111,  119, 
-   255,  247,  239,  235,  231,  227,  223,  221, 
-   219,  217,  215,  213,  211,  209,  207,  206, 
-   205,  204,  203,  202,  201,  200,  199,  198, 
-   197,  196,  195,  194,  193,  192,  191,  191, 
-   190,  190,  189,  189,  188,  188,  187,  187, 
-   186,  186,  185,  185,  184,  184,  183,  183, 
-   182,  182,  181,  181,  180,  180,  179,  179, 
-   178,  178,  177,  177,  176,  176,  175,  175, 
-   175,  175,  174,  174,  174,  174,  173,  173, 
-   173,  173,  172,  172,  172,  172,  171,  171, 
-   171,  171,  170,  170,  170,  170,  169,  169, 
-   169,  169,  168,  168,  168,  168,  167,  167, 
-   167,  167,  166,  166,  166,  166,  165,  165, 
-   165,  165,  164,  164,  164,  164,  163,  163, 
-   163,  163,  162,  162,  162,  162,  161,  161, 
-   161,  161,  160,  160,  160,  160,  159,  159, 
+    0,    0,    0,    0,    0,    1,    1,    1,
+    1,    2,    2,    2,    2,    3,    3,    3,
+    3,    4,    4,    4,    4,    5,    5,    5,
+    5,    6,    6,    6,    6,    7,    7,    7,
+    7,    8,    8,    8,    8,    9,    9,    9,
+    9,   10,   10,   10,   10,   11,   11,   11,
+   11,   12,   12,   12,   12,   13,   13,   13,
+   13,   14,   14,   14,   14,   15,   15,   15,
+   15,   16,   16,   17,   17,   18,   18,   19,
+   19,   20,   20,   21,   21,   22,   22,   23,
+   23,   24,   24,   25,   25,   26,   26,   27,
+   27,   28,   28,   29,   29,   30,   30,   31,
+   31,   32,   33,   34,   35,   36,   37,   38,
+   39,   40,   41,   42,   43,   44,   45,   46,
+   47,   48,   50,   52,   54,   56,   58,   60,
+   62,   65,   69,   73,   77,   83,   91,  103,
+  255,  231,  219,  211,  205,  201,  197,  193,
+  190,  188,  186,  184,  182,  180,  178,  176,
+  175,  174,  173,  172,  171,  170,  169,  168,
+  167,  166,  165,  164,  163,  162,  161,  160,
+  159,  159,  158,  158,  157,  157,  156,  156,
+  155,  155,  154,  154,  153,  153,  152,  152,
+  151,  151,  150,  150,  149,  149,  148,  148,
+  147,  147,  146,  146,  145,  145,  144,  144,
+  143,  143,  143,  143,  142,  142,  142,  142,
+  141,  141,  141,  141,  140,  140,  140,  140,
+  139,  139,  139,  139,  138,  138,  138,  138,
+  137,  137,  137,  137,  136,  136,  136,  136,
+  135,  135,  135,  135,  134,  134,  134,  134,
+  133,  133,  133,  133,  132,  132,  132,  132,
+  131,  131,  131,  131,  130,  130,  130,  130,
+  129,  129,  129,  129,  128,  128,  128,  128
 };
diff -u --recursive --new-file v1.3.8/linux/fs/Makefile linux/fs/Makefile
--- v1.3.8/linux/fs/Makefile	Fri Jul  7 08:54:51 1995
+++ linux/fs/Makefile	Tue Jul 11 08:29:44 1995
@@ -79,8 +79,6 @@
 MODULE_OBJS := $(MODULE_OBJS) binfmt_elf.o
 endif
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -114,11 +112,4 @@
 	set -e; for i in $(MODULE_FS_SUBDIRS); do \
 	  test ! -d $$i || $(MAKE) -C $$i CFLAGS="$(CFLAGS) -DMODULE" dep; done
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v1.3.8/linux/fs/binfmt_elf.c	Fri Jul  7 13:42:58 1995
+++ linux/fs/binfmt_elf.c	Tue Jul 11 07:56:04 1995
@@ -50,6 +50,7 @@
 
 static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
 static int load_elf_library(int fd);
+extern int aout_core_dump(long signr, struct pt_regs * regs);
 static int elf_core_dump(long signr, struct pt_regs * regs);
 extern int dump_fpu (elf_fpregset_t *);
 
diff -u --recursive --new-file v1.3.8/linux/fs/ext/Makefile linux/fs/ext/Makefile
--- v1.3.8/linux/fs/ext/Makefile	Wed Dec  1 14:44:15 1993
+++ linux/fs/ext/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -23,9 +21,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/ext2/CHANGES linux/fs/ext2/CHANGES
--- v1.3.8/linux/fs/ext2/CHANGES	Wed Apr  5 12:59:50 1995
+++ linux/fs/ext2/CHANGES	Mon Jul 10 17:08:03 1995
@@ -1,3 +1,10 @@
+Changes from version 0.5a to version 0.5b
+=========================================
+	- More consistency checks on directories.
+	- The ext2.diff patch from Tom May <ftom@netcom.com> has been
+	  integrated.  This patch replaces expensive "/" and "%" with
+	  cheap ">>" and "&" where possible.
+
 Changes from version 0.5 to version 0.5a
 ========================================
 	- Zero the partial block following the end of the file when a file
diff -u --recursive --new-file v1.3.8/linux/fs/ext2/Makefile linux/fs/ext2/Makefile
--- v1.3.8/linux/fs/ext2/Makefile	Fri Jul 29 14:35:03 1994
+++ linux/fs/ext2/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -23,9 +21,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v1.3.8/linux/fs/ext2/dir.c	Mon Jun 12 12:07:43 1995
+++ linux/fs/ext2/dir.c	Mon Jul 10 17:08:03 1995
@@ -88,10 +88,10 @@
 		error_msg = "inode out of bounds";
 
 	if (error_msg != NULL)
-		ext2_error (dir->i_sb, function, "bad directory entry: %s\n"
+		ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - "
 			    "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
-			    error_msg, offset, (unsigned long) de->inode, de->rec_len,
-			    de->name_len);
+			    dir->i_ino, error_msg, offset, (unsigned long) de->inode,
+			    de->rec_len, de->name_len);
 	return error_msg == NULL ? 1 : 0;
 }
 
@@ -118,6 +118,9 @@
 		blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
 		bh = ext2_bread (inode, blk, 0, &err);
 		if (!bh) {
+			ext2_error (sb, "ext2_readdir",
+				    "directory #%lu contains a hole at offset %lu",
+				    inode->i_ino, (unsigned long)filp->f_pos);
 			filp->f_pos += sb->s_blocksize - offset;
 			continue;
 		}
diff -u --recursive --new-file v1.3.8/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v1.3.8/linux/fs/ext2/file.c	Tue Jun 27 14:11:39 1995
+++ linux/fs/ext2/file.c	Mon Jul 10 17:08:03 1995
@@ -114,6 +114,7 @@
 	read = 0;
 	block = offset >> EXT2_BLOCK_SIZE_BITS(sb);
 	offset &= (sb->s_blocksize - 1);
+	chars = sb->s_blocksize - offset;
 	size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
 	blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb);
 	bhb = bhe = buflist;
@@ -188,12 +189,10 @@
 					break;
 				}
 			}
-			if (left < sb->s_blocksize - offset)
-				chars = left;
-			else
-				chars = sb->s_blocksize - offset;
-			filp->f_pos += chars;
 			left -= chars;
+			if (left < 0)
+				chars += left;
+			filp->f_pos += chars;
 			read += chars;
 			if (*bhe) {
 				memcpy_tofs (buf, offset + (*bhe)->b_data,
@@ -205,6 +204,7 @@
 					put_user (0, buf++);
 			}
 			offset = 0;
+			chars = sb->s_blocksize;
 			if (++bhe == &buflist[NBUF])
 				bhe = buflist;
 		} while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock));
@@ -234,9 +234,10 @@
 	const loff_t two_gb = 2147483647;
 	loff_t pos;
 	off_t pos2;
+	long block;
+	int offset;
 	int written, c;
 	struct buffer_head * bh, *bufferlist[NBUF];
-	char * p;
 	struct super_block * sb;
 	int err;
 	int i,buffercount,write_error;
@@ -272,22 +273,25 @@
 	 */
 	if (filp->f_flags & O_SYNC)
 		inode->u.ext2_i.i_osync++;
+	block = pos2 >> EXT2_BLOCK_SIZE_BITS(sb);
+	offset = pos2 & (sb->s_blocksize - 1);
+	c = sb->s_blocksize - offset;
 	written = 0;
-	while (written < count) {
+	while (count > 0) {
 		if (pos > two_gb) {
 			if (!written)
 				written = -EFBIG;
 			break;
 		}
-		bh = ext2_getblk (inode, pos2 / sb->s_blocksize, 1, &err);
+		bh = ext2_getblk (inode, block, 1, &err);
 		if (!bh) {
 			if (!written)
 				written = err;
 			break;
 		}
-		c = sb->s_blocksize - (pos2 % sb->s_blocksize);
-		if (c > count-written)
-			c = count - written;
+		count -= c;
+		if (count < 0)
+			c += count;
 		if (c != sb->s_blocksize && !bh->b_uptodate) {
 			ll_rw_block (READ, 1, &bh);
 			wait_on_buffer (bh);
@@ -298,11 +302,10 @@
 				break;
 			}
 		}
-		p = (pos2 % sb->s_blocksize) + bh->b_data;
 		pos2 += c;
 		pos += c;
 		written += c;
-		memcpy_fromfs (p, buf, c);
+		memcpy_fromfs (bh->b_data + offset, buf, c);
 		buf += c;
 		bh->b_uptodate = 1;
 		mark_buffer_dirty(bh, 0);
@@ -322,6 +325,9 @@
 		}
 		if(write_error)
 			break;
+		block++;
+		offset = 0;
+		c = sb->s_blocksize;
 	}
 	if ( buffercount ){
 		ll_rw_block(WRITE, buffercount, bufferlist);
diff -u --recursive --new-file v1.3.8/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v1.3.8/linux/fs/ext2/inode.c	Wed Mar 22 10:33:59 1995
+++ linux/fs/ext2/inode.c	Mon Jul 10 17:08:03 1995
@@ -129,14 +129,15 @@
 {
 	int i;
 	int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
 
 	if (block < 0) {
 		ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
 		return 0;
 	}
 	if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
-		     addr_per_block * addr_per_block +
-		     addr_per_block * addr_per_block * addr_per_block) {
+		(1 << (addr_per_block_bits * 2)) +
+		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
 		ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
 		return 0;
 	}
@@ -151,29 +152,29 @@
 					  inode->i_sb->s_blocksize), block);
 	}
 	block -= addr_per_block;
-	if (block < addr_per_block * addr_per_block) {
+	if (block < (1 << (addr_per_block_bits * 2))) {
 		i = inode_bmap (inode, EXT2_DIND_BLOCK);
 		if (!i)
 			return 0;
 		i = block_bmap (bread (inode->i_dev, i,
 				       inode->i_sb->s_blocksize),
-				block / addr_per_block);
+				block >> addr_per_block_bits);
 		if (!i)
 			return 0;
 		return block_bmap (bread (inode->i_dev, i,
 					  inode->i_sb->s_blocksize),
 				   block & (addr_per_block - 1));
 	}
-	block -= addr_per_block * addr_per_block;
+	block -= (1 << (addr_per_block_bits * 2));
 	i = inode_bmap (inode, EXT2_TIND_BLOCK);
 	if (!i)
 		return 0;
 	i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
-			block / (addr_per_block * addr_per_block));
+			block >> (addr_per_block_bits * 2));
 	if (!i)
 		return 0;
 	i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
-			(block / addr_per_block) & (addr_per_block - 1));
+			(block >> addr_per_block_bits) & (addr_per_block - 1));
 	if (!i)
 		return 0;
 	return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
@@ -335,10 +336,11 @@
 
 	if(!bh) return 0;
 
-	if(nr % (PAGE_SIZE / inode->i_sb->s_blocksize) != 0) goto out;
+	if((nr & ((PAGE_SIZE >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)) - 1)) != 0)
+		goto out;
 	if(nr + 3 > EXT2_ADDR_PER_BLOCK(inode->i_sb)) goto out;
 
-	for(i=0; i< (PAGE_SIZE / inode->i_sb->s_blocksize); i++) {
+	for(i=0; i< (PAGE_SIZE >> EXT2_BLOCK_SIZE_BITS(inode->i_sb)); i++) {
 	  p = (u32 *) bh->b_data + nr + i;
 	  
 	  /* All blocks in cluster must already be allocated */
@@ -363,15 +365,16 @@
 	struct buffer_head * bh;
 	unsigned long b;
 	unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
 
 	*err = -EIO;
 	if (block < 0) {
 		ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
 		return NULL;
 	}
-	if (block > EXT2_NDIR_BLOCKS + addr_per_block  +
-		    addr_per_block * addr_per_block +
-		    addr_per_block * addr_per_block * addr_per_block) {
+	if (block > EXT2_NDIR_BLOCKS + addr_per_block +
+		(1 << (addr_per_block_bits * 2)) +
+		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
 		ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
 		return NULL;
 	}
@@ -401,18 +404,18 @@
 				     inode->i_sb->s_blocksize, b, err);
 	}
 	block -= addr_per_block;
-	if (block < addr_per_block * addr_per_block) {
+	if (block < (1 << (addr_per_block_bits * 2))) {
 		bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err);
-		bh = block_getblk (inode, bh, block / addr_per_block, create,
-				   inode->i_sb->s_blocksize, b, err);
+		bh = block_getblk (inode, bh, block >> addr_per_block_bits,
+				   create, inode->i_sb->s_blocksize, b, err);
 		return block_getblk (inode, bh, block & (addr_per_block - 1),
 				     create, inode->i_sb->s_blocksize, b, err);
 	}
-	block -= addr_per_block * addr_per_block;
+	block -= (1 << (addr_per_block_bits * 2));
 	bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err);
-	bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block),
+	bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2),
 			   create, inode->i_sb->s_blocksize, b, err);
-	bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1),
+	bh = block_getblk (inode, bh, (block >> addr_per_block_bits) & (addr_per_block - 1),
 			   create, inode->i_sb->s_blocksize, b, err);
 	return block_getblk (inode, bh, block & (addr_per_block - 1), create,
 			     inode->i_sb->s_blocksize, b, err);
@@ -424,6 +427,7 @@
 	int err, create;
 	unsigned long b;
 	unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+	int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
 
 	create = 0;
 	err = -EIO;
@@ -431,9 +435,9 @@
 		ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
 		return 0;
 	}
-	if (block > EXT2_NDIR_BLOCKS + addr_per_block  +
-		    addr_per_block * addr_per_block +
-		    addr_per_block * addr_per_block * addr_per_block) {
+	if (block > EXT2_NDIR_BLOCKS + addr_per_block +
+		(1 << (addr_per_block_bits * 2)) +
+		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
 		ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
 		return 0;
 	}
@@ -450,18 +454,18 @@
 					 inode->i_sb->s_blocksize);
 	}
 	block -= addr_per_block;
-	if (block < addr_per_block * addr_per_block) {
+	if (block < (1 << (addr_per_block_bits * 2))) {
 		bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, &err);
-		bh = block_getblk (inode, bh, block / addr_per_block, create,
-				   inode->i_sb->s_blocksize, b, &err);
+		bh = block_getblk (inode, bh, block >> addr_per_block_bits,
+				   create, inode->i_sb->s_blocksize, b, &err);
 		return block_getcluster (inode, bh, block & (addr_per_block - 1),
 				     inode->i_sb->s_blocksize);
 	}
-	block -= addr_per_block * addr_per_block;
+	block -= (1 << (addr_per_block_bits * 2));
 	bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, &err);
-	bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block),
+	bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2),
 			   create, inode->i_sb->s_blocksize, b, &err);
-	bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1),
+	bh = block_getblk (inode, bh, (block >> addr_per_block_bits) & (addr_per_block - 1),
 			   create, inode->i_sb->s_blocksize, b, &err);
 	return block_getcluster (inode, bh, block & (addr_per_block - 1),
 				 inode->i_sb->s_blocksize);
@@ -505,8 +509,8 @@
 	if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count)
 		ext2_panic (inode->i_sb, "ext2_read_inode",
 			    "group >= groups count");
-	group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb);
-	desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb);
+	group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb);
+	desc = block_group & (EXT2_DESC_PER_BLOCK(inode->i_sb) - 1);
 	bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];
 	if (!bh)
 		ext2_panic (inode->i_sb, "ext2_read_inode",
@@ -514,13 +518,13 @@
 	gdp = (struct ext2_group_desc *) bh->b_data;
 	block = gdp[desc].bg_inode_table +
 		(((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb))
-		 / EXT2_INODES_PER_BLOCK(inode->i_sb));
+		 >> EXT2_INODES_PER_BLOCK_BITS(inode->i_sb));
 	if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
 		ext2_panic (inode->i_sb, "ext2_read_inode",
 			    "unable to read i-node block - "
 			    "inode=%lu, block=%lu", inode->i_ino, block);
 	raw_inode = ((struct ext2_inode *) bh->b_data) +
-		(inode->i_ino - 1) % EXT2_INODES_PER_BLOCK(inode->i_sb);
+		((inode->i_ino - 1) & (EXT2_INODES_PER_BLOCK(inode->i_sb) - 1));
 	inode->i_mode = raw_inode->i_mode;
 	inode->i_uid = raw_inode->i_uid;
 	inode->i_gid = raw_inode->i_gid;
@@ -596,8 +600,8 @@
 	if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count)
 		ext2_panic (inode->i_sb, "ext2_write_inode",
 			    "group >= groups count");
-	group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb);
-	desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb);
+	group_desc = block_group >> EXT2_DESC_PER_BLOCK_BITS(inode->i_sb);
+	desc = block_group & (EXT2_DESC_PER_BLOCK(inode->i_sb) - 1);
 	bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc];
 	if (!bh)
 		ext2_panic (inode->i_sb, "ext2_write_inode",
@@ -605,7 +609,7 @@
 	gdp = (struct ext2_group_desc *) bh->b_data;
 	block = gdp[desc].bg_inode_table +
 		(((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb))
-		 / EXT2_INODES_PER_BLOCK(inode->i_sb));
+		 >> EXT2_INODES_PER_BLOCK_BITS(inode->i_sb));
 	if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize)))
 		ext2_panic (inode->i_sb, "ext2_write_inode",
 			    "unable to read i-node block - "
diff -u --recursive --new-file v1.3.8/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v1.3.8/linux/fs/ext2/namei.c	Fri Jul  7 13:42:58 1995
+++ linux/fs/ext2/namei.c	Mon Jul 10 17:08:04 1995
@@ -101,9 +101,7 @@
 			bh_read[toread++] = bh;
 	}
 
-	block = 0;
-	offset = 0;
-	while (offset < dir->i_size) {
+	for (block = 0, offset = 0; offset < dir->i_size; block++) {
 		struct buffer_head * bh;
 		struct ext2_dir_entry * de;
 		char * dlimit;
@@ -113,9 +111,13 @@
 			toread = 0;
 		}
 		bh = bh_use[block % NAMEI_RA_SIZE];
-		if (!bh)
-			ext2_panic (sb, "ext2_find_entry",
-				    "buffer head pointer is NULL");
+		if (!bh) {
+			ext2_error (sb, "ext2_find_entry",
+				    "directory #%lu contains a hole at offset %lu",
+				    dir->i_ino, offset);
+			offset += sb->s_blocksize;
+			continue;
+		}
 		wait_on_buffer (bh);
 		if (!bh->b_uptodate) {
 			/*
@@ -149,7 +151,7 @@
 			bh = NULL;
 		else
 			bh = ext2_getblk (dir, block + NAMEI_RA_SIZE, 0, &err);
-		bh_use[block++ % NAMEI_RA_SIZE] = bh;
+		bh_use[block % NAMEI_RA_SIZE] = bh;
 		if (bh && !bh->b_uptodate)
 			bh_read[toread++] = bh;
 	}
@@ -558,7 +560,8 @@
 	if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) ||
 	    !(bh = ext2_bread (inode, 0, 0, &err))) {
 	    	ext2_warning (inode->i_sb, "empty_dir",
-			      "bad directory (dir %lu)", inode->i_ino);
+			      "bad directory (dir #%lu) - no data block",
+			      inode->i_ino);
 		return 1;
 	}
 	de = (struct ext2_dir_entry *) bh->b_data;
@@ -566,7 +569,8 @@
 	if (de->inode != inode->i_ino || !de1->inode || 
 	    strcmp (".", de->name) || strcmp ("..", de1->name)) {
 	    	ext2_warning (inode->i_sb, "empty_dir",
-			      "bad directory (dir %lu)", inode->i_ino);
+			      "bad directory (dir #%lu) - no `.' or `..'",
+			      inode->i_ino);
 		return 1;
 	}
 	offset = de->rec_len + de1->rec_len;
@@ -576,6 +580,9 @@
 			brelse (bh);
 			bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err);
 			if (!bh) {
+				ext2_error (sb, "empty_dir",
+					    "directory #%lu contains a hole at offset %lu",
+					    inode->i_ino, offset);
 				offset += sb->s_blocksize;
 				continue;
 			}
diff -u --recursive --new-file v1.3.8/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v1.3.8/linux/fs/ext2/super.c	Mon Jun 12 16:49:40 1995
+++ linux/fs/ext2/super.c	Mon Jul 10 17:08:04 1995
@@ -15,6 +15,7 @@
 
 #include <stdarg.h>
 
+#include <asm/bitops.h>
 #include <asm/segment.h>
 #include <asm/system.h>
 
@@ -388,6 +389,8 @@
 	return 1;
 }
 
+#define log2(n) ffz(~(n))
+
 struct super_block * ext2_read_super (struct super_block * sb, void * data,
 				      int silent)
 {
@@ -439,8 +442,8 @@
 				MAJOR(dev), MINOR(dev));
 		return NULL;
 	}
-	sb->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size;
-	sb->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(sb);
+	sb->s_blocksize_bits = sb->u.ext2_sb.s_es->s_log_block_size + 10;
+	sb->s_blocksize = 1 << sb->s_blocksize_bits;
 	if (sb->s_blocksize != BLOCK_SIZE && 
 	    (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 ||  
 	     sb->s_blocksize == 4096)) {
@@ -480,7 +483,6 @@
 	sb->u.ext2_sb.s_desc_per_block = sb->s_blocksize /
 					 sizeof (struct ext2_group_desc);
 	sb->u.ext2_sb.s_sbh = bh;
-	sb->u.ext2_sb.s_es = es;
 	if (resuid != EXT2_DEF_RESUID)
 		sb->u.ext2_sb.s_resuid = resuid;
 	else
@@ -492,6 +494,12 @@
 	sb->u.ext2_sb.s_mount_state = es->s_state;
 	sb->u.ext2_sb.s_rename_lock = 0;
 	sb->u.ext2_sb.s_rename_wait = NULL;
+	sb->u.ext2_sb.s_addr_per_block_bits =
+		log2 (EXT2_ADDR_PER_BLOCK(sb));
+	sb->u.ext2_sb.s_inodes_per_block_bits =
+		log2 (EXT2_INODES_PER_BLOCK(sb));
+	sb->u.ext2_sb.s_desc_per_block_bits =
+		log2 (EXT2_DESC_PER_BLOCK(sb));
 #ifdef EXT2FS_PRE_02B_COMPAT
 	if (sb->s_magic == EXT2_PRE_02B_MAGIC) {
 		if (es->s_blocks_count > 262144) {
diff -u --recursive --new-file v1.3.8/linux/fs/ext2/truncate.c linux/fs/ext2/truncate.c
--- v1.3.8/linux/fs/ext2/truncate.c	Wed Apr  5 12:59:50 1995
+++ linux/fs/ext2/truncate.c	Mon Jul 10 17:08:04 1995
@@ -354,9 +354,10 @@
 	 * zeroed in case it ever becomes accessible again because of
 	 * subsequent file growth.
 	 */
-	offset = inode->i_size % inode->i_sb->s_blocksize;
+	offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
 	if (offset) {
-		bh = ext2_bread (inode, inode->i_size / inode->i_sb->s_blocksize,
+		bh = ext2_bread (inode,
+				 inode->i_size >> EXT2_BLOCK_SIZE_BITS(inode->i_sb),
 				 0, &err);
 		if (bh) {
 			memset (bh->b_data + offset, 0,
diff -u --recursive --new-file v1.3.8/linux/fs/hpfs/Makefile linux/fs/hpfs/Makefile
--- v1.3.8/linux/fs/hpfs/Makefile	Sun Feb  5 14:44:32 1995
+++ linux/fs/hpfs/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -22,9 +20,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/isofs/Makefile linux/fs/isofs/Makefile
--- v1.3.8/linux/fs/isofs/Makefile	Tue Jan 10 17:02:17 1995
+++ linux/fs/isofs/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -25,9 +23,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v1.3.8/linux/fs/isofs/inode.c	Mon Jun 12 16:49:40 1995
+++ linux/fs/isofs/inode.c	Tue Jul 11 07:56:04 1995
@@ -2,6 +2,7 @@
  *  linux/fs/isofs/inode.c
  * 
  *  (C) 1992, 1993, 1994  Eric Youngdale Modified for ISO9660 filesystem.
+ *      1995  Mark Dobie - patch to allow VideoCD and PhotoCD mounting.
  *
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
@@ -425,6 +426,7 @@
 	void *cpnt = NULL;
 	int high_sierra;
 	int block;
+	int volume_seq_no ;
 	int i;
 
 	block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
@@ -563,16 +565,23 @@
 	
 	inode->i_op = NULL;
 
-	/* A volume number of 0 is nonsense.  Disable checking if we see
-	   this */
+	/* get the volume sequence numner */
+	volume_seq_no = isonum_723 (raw_inode->volume_sequence_number) ;
+
+	/* 
+	 * Disable checking if we see any volume number other than 0 or 1.
+	 * We could use the cruft option, but that has multiple purposes, one
+	 * of which is limiting the file size to 16Mb.  Thus we silently allow
+	 * volume numbers of 0 to go through without complaining.
+	 */
 	if (inode->i_sb->u.isofs_sb.s_cruft == 'n' && 
-	    isonum_723 (raw_inode->volume_sequence_number) == 0) {
+	    (volume_seq_no != 0) && (volume_seq_no != 1)) {
 	  printk("Warning: defective cdrom.  Enabling \"cruft\" mount option.\n");
 	  inode->i_sb->u.isofs_sb.s_cruft = 'y';
 	}
 
 	if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && 
-	    isonum_723 (raw_inode->volume_sequence_number) != 1) {
+	    (volume_seq_no != 0) && (volume_seq_no != 1)) {
 		printk("Multi volume CD somehow got mounted.\n");
 	} else {
 	  if (S_ISREG(inode->i_mode))
diff -u --recursive --new-file v1.3.8/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v1.3.8/linux/fs/isofs/namei.c	Wed Feb 22 08:15:14 1995
+++ linux/fs/isofs/namei.c	Tue Jul 11 07:56:04 1995
@@ -178,8 +178,18 @@
 		      dlen--;
 		  }
 		}
-		match = isofs_match(namelen,name,dpnt,dlen);
-		if (cpnt) {
+		/*
+		 * Skip hidden or associated files unless unhide is set 
+		 */
+		match = 0;
+		if(   !(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
+		   || dir->i_sb->u.isofs_sb.s_unhide == 'y' )
+		{
+			match = isofs_match(namelen,name,dpnt,dlen);
+		}
+
+		if (cpnt)
+		{
 			kfree(cpnt);
 			cpnt = NULL;
 		}
diff -u --recursive --new-file v1.3.8/linux/fs/minix/Makefile linux/fs/minix/Makefile
--- v1.3.8/linux/fs/minix/Makefile	Mon Jan  9 09:23:00 1995
+++ linux/fs/minix/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -25,9 +23,4 @@
 
 modules: minix.o
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/msdos/Makefile linux/fs/msdos/Makefile
--- v1.3.8/linux/fs/msdos/Makefile	Tue Jan 10 17:02:18 1995
+++ linux/fs/msdos/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -25,9 +23,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/msdos/mmap.c linux/fs/msdos/mmap.c
--- v1.3.8/linux/fs/msdos/mmap.c	Mon Jan 23 10:38:29 1995
+++ linux/fs/msdos/mmap.c	Mon Jul 10 17:08:04 1995
@@ -2,7 +2,7 @@
  *	fs/msdos/mmap.c
  *
  *	Written by Jacques Gelinas (jacques@solucorp.qc.ca)
- *	Inspired by fs/nfs/mmap.c (Jaon Tombs 15 Aug 1993)
+ *	Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993)
  *
  *	msdos mmap handling
  */
diff -u --recursive --new-file v1.3.8/linux/fs/nfs/Makefile linux/fs/nfs/Makefile
--- v1.3.8/linux/fs/nfs/Makefile	Mon Jan  9 09:23:36 1995
+++ linux/fs/nfs/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -25,9 +23,4 @@
 
 modules: nfs.o
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/nfs/mmap.c linux/fs/nfs/mmap.c
--- v1.3.8/linux/fs/nfs/mmap.c	Mon Jan 23 10:38:29 1995
+++ linux/fs/nfs/mmap.c	Mon Jul 10 17:10:41 1995
@@ -73,9 +73,10 @@
 #endif
 
 	tmp = page + PAGE_SIZE;
-	while (clear--) {
-		*(char *)--tmp = 0;
+	if (clear > 0){
+		memset ((char*)(tmp-clear),0,clear);
 	}
+
 	return page;
 }
 
diff -u --recursive --new-file v1.3.8/linux/fs/proc/Makefile linux/fs/proc/Makefile
--- v1.3.8/linux/fs/proc/Makefile	Thu Jun 29 19:02:54 1995
+++ linux/fs/proc/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -22,9 +20,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/proc/scsi.c linux/fs/proc/scsi.c
--- v1.3.8/linux/fs/proc/scsi.c	Fri Jul  7 08:54:52 1995
+++ linux/fs/proc/scsi.c	Tue Jul 11 07:56:04 1995
@@ -8,12 +8,13 @@
  *
  *  /proc/scsi directory handling functions
  *
- *  last change: 95/06/13    
+ *  last change: 95/07/04    
  *
  *  Initial version: March '95
- *  95/15/05 Added subdirectories for each driver and show every
+ *  95/05/15 Added subdirectories for each driver and show every
  *	     registered HBA as a single file. 
- *  95/30/05 Added rudimentary write support for parameter passing
+ *  95/05/30 Added rudimentary write support for parameter passing
+ *  95/07/04 Fixed bugs in directory handling
  *
  *  TODO: Improve support to write to the driver files
  *	  Optimize directory handling 
@@ -96,13 +97,17 @@
 
     (uint) *num = flag = index = 0;    
     
-    if(dispatch_scsi_info_ptr)
-    {
+    if(dispatch_scsi_info_ptr) {
 	if (inode == PROC_SCSI) { 
 	    dir = scsi_dir;
             while(dir[(uint)*num].low_ino)
                 (*num)++;
         } else {
+            /* Here we do not simply count the entries. Since the array
+             * contains the directories of all drivers, we need to return
+             * a pointer to the beginning of the directory information
+             * and its length.
+             */
 	    dir = scsi_hba_dir;
             while(dir[index].low_ino || dir[index].low_ino <= PROC_SCSI_LAST) {
                 if(dir[index].low_ino == inode)
@@ -140,8 +145,7 @@
 	iput(dir);
 	return(-ENOENT);
     }
-    if (dispatch_scsi_info_ptr != NULL)
-    {
+    if (dispatch_scsi_info_ptr != NULL) {
 	if (dir->i_ino <= PROC_SCSI_SCSI)
 	    de = scsi_dir;
 	else {
@@ -170,7 +174,7 @@
     struct proc_dir_entry * de;
     uint index, num;
  
-    index = num = 0;
+    num = 0;
 
     if (!inode || !S_ISDIR(inode->i_mode))
 	return(-EBADF);
@@ -221,7 +225,6 @@
 static int proc_readscsi(struct inode * inode, struct file * file,
 			 char * buf, int count)
 {
-    uint ino;
     int length;
     int bytes = count;
     int copied = 0;
@@ -235,18 +238,14 @@
 				   * end of the file */
     if (!(page = (char *) __get_free_page(GFP_KERNEL)))
 	return(-ENOMEM);
-    ino = inode->i_ino;
     
-    
-    while(bytes > 0 || count == -1)
-    {
-	
+    while(bytes > 0 || count == -1) {	
 	thistime = bytes;
 	if(bytes > PROC_BLOCK_SIZE || count == -1)
 	    thistime = PROC_BLOCK_SIZE;
 	
 	if(dispatch_scsi_info_ptr)
-	    length = dispatch_scsi_info_ptr(ino, page, &start, 
+	    length = dispatch_scsi_info_ptr(inode->i_ino, page, &start, 
 					    file->f_pos, thistime, 0);
 	else
 	    length = get_not_present_info(page, &start, file->f_pos, thistime);
diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/Makefile linux/fs/smbfs/Makefile
--- v1.3.8/linux/fs/smbfs/Makefile	Fri Jul  7 08:54:52 1995
+++ linux/fs/smbfs/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -25,9 +23,4 @@
 
 modules: smbfs.o
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v1.3.8/linux/fs/smbfs/dir.c	Fri Jul  7 08:54:52 1995
+++ linux/fs/smbfs/dir.c	Mon Jul 10 08:28:00 1995
@@ -554,11 +554,10 @@
         }
 }
         
-int
+void
 smb_init_root(struct smb_server *server)
 {
         struct smb_inode_info *root = &(server->root);
-        int result;
 
         root->finfo.path = server->m.root_path;
         root->finfo.len  = strlen(root->finfo.path);
@@ -568,6 +567,14 @@
         root->nused = 1;
         root->dir   = NULL;
         root->next = root->prev = root;
+        return;
+}
+
+int
+smb_stat_root(struct smb_server *server)
+{
+        struct smb_inode_info *root = &(server->root);
+        int result;
 
         if (root->finfo.len == 0) {
                 result = smb_proc_getattr(server, "\\", 1, &(root->finfo));
@@ -776,6 +783,8 @@
 
         entry.attr  = 0;
         entry.ctime = CURRENT_TIME;
+        entry.atime = CURRENT_TIME;
+        entry.mtime = CURRENT_TIME;
         entry.size  = 0;
 
         error = smb_proc_create(SMB_SERVER(dir), path, len, &entry);
diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v1.3.8/linux/fs/smbfs/file.c	Fri Jul  7 08:54:52 1995
+++ linux/fs/smbfs/file.c	Mon Jul 10 08:28:00 1995
@@ -119,6 +119,9 @@
 
         file->f_pos = pos;
 
+	if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;
+	inode->i_dirt = 1;
+
         DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->path);
 
         return already_read;
@@ -177,6 +180,9 @@
 			break;
 		}
 	}
+
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_dirt = 1;
 
 	file->f_pos = pos;
 
diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v1.3.8/linux/fs/smbfs/inode.c	Fri Jul  7 08:54:52 1995
+++ linux/fs/smbfs/inode.c	Mon Jul 10 08:28:00 1995
@@ -250,6 +250,8 @@
 	server->m.dir_mode  = (server->m.dir_mode &
                              (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
 
+        smb_init_root(server);
+
         /*
          * Make the connection to the server
          */
@@ -278,19 +280,19 @@
                 goto fail;
 	}
 
+	if ((error = smb_stat_root(server)) < 0) {
+		sb->s_dev = 0;
+		printk("smb_read_super: could not get root dir attributes\n");
+                smb_kfree_s(server->packet, server->max_xmit);
+                goto fail;
+	}
+
 	DPRINTK("smb_read_super : %u %u %u %u\n",
                 SMB_SBP(sb)->s_attr.total,
                 SMB_SBP(sb)->s_attr.blocksize,
                 SMB_SBP(sb)->s_attr.allocblocks,
                 SMB_SBP(sb)->s_attr.free);
 
-        if (smb_init_root(server) != 0) {
-                sb->s_dev = 0;
-                printk("smb_read_super: invalid root directory\n");
-                smb_kfree_s(server->packet, server->max_xmit);
-                goto fail;
-        }
-
         DPRINTK("smb_read_super: SMB_SBP(sb) = %x\n", (int)SMB_SBP(sb));
 
 	if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) {
@@ -406,7 +408,7 @@
 
 #ifdef MODULE
 
-static char kernel_version[] = UTS_RELEASE;
+char kernel_version[] = UTS_RELEASE;
 
 /* looks ugly, taken from gcc-info */
 static void *shut_up_gcc = (&shut_up_gcc, kernel_version);
diff -u --recursive --new-file v1.3.8/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v1.3.8/linux/fs/smbfs/sock.c	Fri Jul  7 08:54:52 1995
+++ linux/fs/smbfs/sock.c	Sat Jul  8 09:21:45 1995
@@ -22,7 +22,7 @@
 #include <linux/net.h>
 #include <linux/mm.h>
 #include <linux/netdevice.h>
-#include "/usr/src/linux/include/net/ip.h"
+#include <net/ip.h>
 
 #include <linux/smb.h>
 #include <linux/smbno.h>
diff -u --recursive --new-file v1.3.8/linux/fs/sysv/Makefile linux/fs/sysv/Makefile
--- v1.3.8/linux/fs/sysv/Makefile	Tue Jan 10 17:02:18 1995
+++ linux/fs/sysv/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -26,9 +24,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/umsdos/Makefile linux/fs/umsdos/Makefile
--- v1.3.8/linux/fs/umsdos/Makefile	Tue Jan 10 17:02:18 1995
+++ linux/fs/umsdos/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -35,9 +33,4 @@
 doc:
 	nadoc -i -p umsdos.doc - /tmp/umsdos.mpg
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/fs/xiafs/Makefile linux/fs/xiafs/Makefile
--- v1.3.8/linux/fs/xiafs/Makefile	Tue Jan 10 17:02:18 1995
+++ linux/fs/xiafs/Makefile	Tue Jul 11 08:02:20 1995
@@ -7,8 +7,6 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .s.o:
@@ -26,9 +24,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/include/asm-alpha/socket.h linux/include/asm-alpha/socket.h
--- v1.3.8/linux/include/asm-alpha/socket.h	Fri Jul  7 13:42:58 1995
+++ linux/include/asm-alpha/socket.h	Mon Jul 10 16:59:58 1995
@@ -1,6 +1,19 @@
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
 
+#include <linux/types.h>
+#include <asm/ioctl.h>
+
+/* Socket-level I/O control calls. */
+#define FIOGETOWN	_IOR('f', 123, int)
+#define FIOSETOWN 	_IOW('f', 124, int)
+
+#define SIOCATMARK	_IOR('s', 7, int)
+#define SIOCSPGRP	_IOW('s', 8, pid_t)
+#define SIOCGPGRP	_IOR('s', 9, pid_t)
+
+#define SIOCGSTAMP	0x8906			/* Get stamp - linux-specific */
+
 /* For setsockoptions(2) */
 /*
  * Note: we only bother about making the SOL_SOCKET options
diff -u --recursive --new-file v1.3.8/linux/include/asm-i386/socket.h linux/include/asm-i386/socket.h
--- v1.3.8/linux/include/asm-i386/socket.h	Fri Jul  7 13:42:58 1995
+++ linux/include/asm-i386/socket.h	Mon Jul 10 16:59:58 1995
@@ -1,6 +1,14 @@
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
 
+/* Socket-level I/O control calls. */
+#define FIOSETOWN 	0x8901
+#define SIOCSPGRP	0x8902
+#define FIOGETOWN	0x8903
+#define SIOCGPGRP	0x8904
+#define SIOCATMARK	0x8905
+#define SIOCGSTAMP	0x8906		/* Get stamp */
+
 /* For setsockoptions(2) */
 #define SOL_SOCKET	1
 
diff -u --recursive --new-file v1.3.8/linux/include/linux/aztcd.h linux/include/linux/aztcd.h
--- v1.3.8/linux/include/linux/aztcd.h	Sun Mar 26 11:56:23 1995
+++ linux/include/linux/aztcd.h	Mon Jul 10 08:00:56 1995
@@ -1,4 +1,4 @@
-/* $Id: aztcd.h,v 1.0 1995/03/25 08:27:19 root Exp $
+/* $Id: aztcd.h,v 1.30 1995/07/04 08:28:17 root Exp $
  * Definitions for a AztechCD268 CD-ROM interface
  *	Copyright (C) 1994, 1995  Werner Zimmermann
  *
@@ -22,12 +22,29 @@
  *		October 1994 Email: zimmerma@rz.fht-esslingen.de
  */
 
-/* *** change this to set the I/O port address */
+/* *** change this to set the I/O port address of your CD-ROM drive*/
 #define AZT_BASE_ADDR		0x320
 
-/* Comment this out to prevent tray from locking */
+/* Uncomment this, if your CDROM is connected to a Soundwave32-soundcard
+   and configure AZT_BASE_ADDR and AZT_SW32_BASE_ADDR */
+/*#define AZT_SW32 1
+*/
+
+#ifdef AZT_SW32 
+#define AZT_SW32_BASE_ADDR       0x220  /*I/O port base adress of your soundcard*/
+#endif
+
+/* Set this to 1, if you want your tray to be locked, set to 0 to prevent tray 
+   from locking */
 #define AZT_ALLOW_TRAY_LOCK	1
 
+/*Set this to 1 to allow auto-eject when unmounting a disk, set to 0, if you 
+  don't want the auto-eject feature*/
+#define AZT_AUTO_EJECT          0
+
+/*---------------------------------------------------------------------------*/
+/*------------nothing to be configured below this line-----------------------*/
+
 /* use incompatible ioctls for reading in raw and cooked mode */
 #define AZT_PRIVATE_IOCTLS
 
@@ -45,6 +62,11 @@
 #define DATA_PORT		azt_port
 #define STATUS_PORT		azt_port+1
 #define MODE_PORT		azt_port+2
+#ifdef  AZT_SW32                
+ #define AZT_SW32_INIT           (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16))
+ #define AZT_SW32_CONFIG_REG     AZT_SW32_BASE_ADDR+0x16  /*Soundwave32 Config. Register*/
+ #define AZT_SW32_ID_REG         AZT_SW32_BASE_ADDR+0x04  /*Soundwave32 ID Version Register*/
+#endif
 
 /* status bits */
 #define AST_CMD_CHECK		0x80		/* command error */
@@ -83,13 +105,6 @@
 #define ACMD_SET_VOLUME		0x93		/* set audio level */
 #define ACMD_GET_VERSION	0xA0		/* get firmware version */
 #define ACMD_SET_MODE		0xA1		/* set drive mode */
-
-#define SET_TIMER(func, jifs) \
-        delay_timer.expires = jifs; \
-        delay_timer.function = (void *) func; \
-        add_timer(&delay_timer);
-
-#define CLEAR_TIMER             del_timer(&delay_timer)
 
 #define MAX_TRACKS		104
 
diff -u --recursive --new-file v1.3.8/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v1.3.8/linux/include/linux/cdrom.h	Fri Jul  7 08:54:53 1995
+++ linux/include/linux/cdrom.h	Tue Jul 11 07:56:04 1995
@@ -404,7 +404,7 @@
 #define	CDROMREADAUDIO		0x530e		/* (struct cdrom_read_audio)	*/
 /*
  * preliminary extension for enable (1) / disable (0) auto-ejecting
- * currently used by sbpcd.c
+ * currently used by sbpcd.c and sr.c
  * (still may change if other drivers will use it, too):
  */
 #define	CDROMEJECT_SW		0x530f		/* arg: 0 or 1 */
diff -u --recursive --new-file v1.3.8/linux/include/linux/etherdevice.h linux/include/linux/etherdevice.h
--- v1.3.8/linux/include/linux/etherdevice.h	Fri Jun 30 16:22:30 1995
+++ linux/include/linux/etherdevice.h	Mon Jul 10 17:08:05 1995
@@ -34,6 +34,8 @@
 extern int		eth_rebuild_header(void *buff, struct device *dev,
 			unsigned long dst, struct sk_buff *skb);
 extern unsigned short	eth_type_trans(struct sk_buff *skb, struct device *dev);
+extern void		eth_copy_and_sum(struct sk_buff *dest,
+				unsigned char *src, int length, int base);
 
 #endif
 
diff -u --recursive --new-file v1.3.8/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v1.3.8/linux/include/linux/ext2_fs.h	Mon Jun 12 16:49:41 1995
+++ linux/include/linux/ext2_fs.h	Mon Jul 10 17:08:04 1995
@@ -50,8 +50,8 @@
 /*
  * The second extended file system version
  */
-#define EXT2FS_DATE		"95/03/19"
-#define EXT2FS_VERSION		"0.5a"
+#define EXT2FS_DATE		"95/07/02"
+#define EXT2FS_VERSION		"0.5b"
 
 /*
  * Debug code
@@ -102,11 +102,15 @@
 #define EXT2_ACLE_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
 #define	EXT2_ADDR_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (__u32))
 #ifdef __KERNEL__
-# define EXT2_BLOCK_SIZE_BITS(s)	((s)->u.ext2_sb.s_es->s_log_block_size + 10)
+# define EXT2_BLOCK_SIZE_BITS(s)	((s)->s_blocksize_bits)
 #else
 # define EXT2_BLOCK_SIZE_BITS(s)	((s)->s_log_block_size + 10)
 #endif
 #define	EXT2_INODES_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode))
+#ifdef __KERNEL__
+#define	EXT2_ADDR_PER_BLOCK_BITS(s)	((s)->u.ext2_sb.s_addr_per_block_bits)
+#define	EXT2_INODES_PER_BLOCK_BITS(s)	((s)->u.ext2_sb.s_inodes_per_block_bits)
+#endif
 
 /*
  * Macro-instructions used to manage fragments
@@ -175,6 +179,7 @@
 # define EXT2_BLOCKS_PER_GROUP(s)	((s)->u.ext2_sb.s_blocks_per_group)
 # define EXT2_DESC_PER_BLOCK(s)		((s)->u.ext2_sb.s_desc_per_block)
 # define EXT2_INODES_PER_GROUP(s)	((s)->u.ext2_sb.s_inodes_per_group)
+# define EXT2_DESC_PER_BLOCK_BITS(s)	((s)->u.ext2_sb.s_desc_per_block_bits)
 #else
 # define EXT2_BLOCKS_PER_GROUP(s)	((s)->s_blocks_per_group)
 # define EXT2_DESC_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
diff -u --recursive --new-file v1.3.8/linux/include/linux/ext2_fs_sb.h linux/include/linux/ext2_fs_sb.h
--- v1.3.8/linux/include/linux/ext2_fs_sb.h	Wed Mar 22 10:33:59 1995
+++ linux/include/linux/ext2_fs_sb.h	Mon Jul 10 17:08:04 1995
@@ -53,6 +53,10 @@
 	unsigned short s_resuid;
 	unsigned short s_resgid;
 	unsigned short s_mount_state;
+	unsigned short s_pad;
+	int s_addr_per_block_bits;
+	int s_inodes_per_block_bits;
+	int s_desc_per_block_bits;
 };
 
 #endif	/* _LINUX_EXT2_FS_SB */
diff -u --recursive --new-file v1.3.8/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v1.3.8/linux/include/linux/genhd.h	Fri Jul  7 08:54:53 1995
+++ linux/include/linux/genhd.h	Mon Jul 10 17:08:05 1995
@@ -16,6 +16,9 @@
 #endif
 	
 #define EXTENDED_PARTITION 5
+
+#define DM6_PARTITION		0x54	/* has DDO: use xlated geom & offset */
+#define DM6_AUXPARTITION	0x51	/* no DDO:  use xlated geom */
 	
 struct partition {
 	unsigned char boot_ind;		/* 0x80 - active */
diff -u --recursive --new-file v1.3.8/linux/include/linux/hdreg.h linux/include/linux/hdreg.h
--- v1.3.8/linux/include/linux/hdreg.h	Thu Jun  1 11:23:04 1995
+++ linux/include/linux/hdreg.h	Mon Jul 10 17:08:05 1995
@@ -79,6 +79,7 @@
 #define HDIO_GET_IDENTITY 	0x307	/* get IDE identification info */
 #define HDIO_GET_KEEPSETTINGS 	0x308	/* get keep-settings-on-reset flag */
 #define HDIO_GET_CHIPSET	0x309	/* get current interface type setting */
+#define HDIO_GET_NOWERR	0x30a	/* get ignore-write-error flag */
 #define HDIO_DRIVE_CMD		0x31f	/* execute a special drive command */
 
 /* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x32n/0x33n */
@@ -86,6 +87,7 @@
 #define HDIO_SET_UNMASKINTR	0x322	/* permit other irqs during I/O */
 #define HDIO_SET_KEEPSETTINGS	0x323	/* keep ioctl settings on reset */
 #define HDIO_SET_CHIPSET	0x324	/* optimise driver for interface type */
+#define HDIO_SET_NOWERR	0x325	/* set ignore-write-error flag */
 
 /* structure returned by HDIO_GET_IDENTITY, as per ANSI ATA2 rev.2f spec */
 struct hd_driveid {
diff -u --recursive --new-file v1.3.8/linux/include/linux/mcdx.h linux/include/linux/mcdx.h
--- v1.3.8/linux/include/linux/mcdx.h	Fri Jul  7 08:54:54 1995
+++ linux/include/linux/mcdx.h	Mon Jul 10 17:08:04 1995
@@ -23,7 +23,7 @@
  *  Eberhard Moenkeberg (he gave me much support and the initial kick)
  *  Bernd Huebner, Ruediger Helsch (Unifix-Software Gmbh, they
  *      improved the original driver)
- *  John Tombs, Bjorn Ekwall (module support)
+ *  Jon Tombs, Bjorn Ekwall (module support)
  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  *  Gerd Knorr (he lent me his PhotoCD)
  *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
diff -u --recursive --new-file v1.3.8/linux/include/linux/pci.h linux/include/linux/pci.h
--- v1.3.8/linux/include/linux/pci.h	Thu Jun 29 19:02:55 1995
+++ linux/include/linux/pci.h	Mon Jul 10 17:08:03 1995
@@ -218,6 +218,8 @@
 #define PCI_DEVICE_ID_INTEL_82430	0x0486
 #define PCI_DEVICE_ID_INTEL_82437	0x122d
 #define PCI_DEVICE_ID_INTEL_82371	0x122e
+#define PCI_DEVICE_ID_INTEL_82438	0x1230
+#define PCI_DEVICE_ID_INTEL_7116	0x1223
 
 #define PCI_VENDOR_ID_SMC		0x1042
 #define PCI_DEVICE_ID_SMC_37C665	0x1000
diff -u --recursive --new-file v1.3.8/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h
--- v1.3.8/linux/include/linux/smb_fs.h	Fri Jul  7 08:54:54 1995
+++ linux/include/linux/smb_fs.h	Mon Jul 10 08:28:01 1995
@@ -104,7 +104,8 @@
 extern struct inode_operations smb_dir_inode_operations;
 void smb_free_inode_info(struct smb_inode_info *i);
 void smb_free_all_inodes(struct smb_server *server);
-int  smb_init_root(struct smb_server *server);
+void smb_init_root(struct smb_server *server);
+int  smb_stat_root(struct smb_server *server);
 void smb_init_dir_cache(void);
 void smb_invalid_dir_cache(unsigned long ino);
 void smb_invalidate_all_inodes(struct smb_server *server);
diff -u --recursive --new-file v1.3.8/linux/include/linux/sockios.h linux/include/linux/sockios.h
--- v1.3.8/linux/include/linux/sockios.h	Tue Jan 24 15:27:55 1995
+++ linux/include/linux/sockios.h	Mon Jul 10 16:59:58 1995
@@ -18,16 +18,6 @@
 #ifndef _LINUX_SOCKIOS_H
 #define _LINUX_SOCKIOS_H
 
-/* This section will go away soon! */
-
-/* Socket-level I/O control calls. */
-#define FIOSETOWN 	0x8901
-#define SIOCSPGRP	0x8902
-#define FIOGETOWN	0x8903
-#define SIOCGPGRP	0x8904
-#define SIOCATMARK	0x8905
-#define SIOCGSTAMP	0x8906		/* Get stamp */
-
 /* Routing table calls. */
 #define SIOCADDRT	0x890B		/* add routing table entry	*/
 #define SIOCDELRT	0x890C		/* delete routing table entry	*/
diff -u --recursive --new-file v1.3.8/linux/include/linux/soundcard.h linux/include/linux/soundcard.h
--- v1.3.8/linux/include/linux/soundcard.h	Mon Mar  6 11:22:08 1995
+++ linux/include/linux/soundcard.h	Tue Jun 27 14:36:53 1995
@@ -35,12 +35,21 @@
   * Regards,
   * Hannu Savolainen
   * hannu@voxware.pp.fi
+  *
+  **********************************************************************
+  * PS.	The Hacker's Guide to VoxWare available from 
+  *     nic.funet.fi:pub/OS/Linux/ALPHA/sound. The file is
+  *	snd-sdk-doc-0.1.ps.gz (gzipped postscript). It contains
+  *	some useful information about programming with VoxWare.
+  *	(NOTE! The pub/OS/Linux/ALPHA/ directories are hidden. You have
+  *	to cd inside them before the files are accessible.)
+  **********************************************************************
   */
 
-#define SOUND_VERSION	300
+#define SOUND_VERSION	301
 #define VOXWARE
 
-#include <linux/ioctl.h>
+#include <sys/ioctl.h>
 
 /*
  *	Supported card ID numbers (Should be somewhere else?)
@@ -58,6 +67,14 @@
 #define SNDCARD_MSS		10
 #define SNDCARD_PSS     	11
 #define SNDCARD_SSCAPE		12
+#define SNDCARD_PSS_MPU     	13
+#define SNDCARD_PSS_MSS     	14
+#define SNDCARD_SSCAPE_MSS	15
+#define SNDCARD_TRXPRO		16
+#define SNDCARD_TRXPRO_SB	17
+#define SNDCARD_TRXPRO_MPU	18
+#define SNDCARD_MAD16		19
+#define SNDCARD_MAD16_MPU	20
 
 /***********************************
  * IOCTL Commands for /dev/sequencer
@@ -99,11 +116,16 @@
 #define SNDCTL_SEQ_NRSYNTHS		_IOR ('Q',10, int)
 #define SNDCTL_SEQ_NRMIDIS		_IOR ('Q',11, int)
 #define SNDCTL_MIDI_INFO		_IOWR('Q',12, struct midi_info)
-#define SNDCTL_SEQ_TRESHOLD		_IOW ('Q',13, int)
+#define SNDCTL_SEQ_THRESHOLD		_IOW ('Q',13, int)
 #define SNDCTL_SYNTH_MEMAVL		_IOWR('Q',14, int)	/* in=dev#, out=memsize */
 #define SNDCTL_FM_4OP_ENABLE		_IOW ('Q',15, int)	/* in=dev# */
 #define SNDCTL_PMGR_ACCESS		_IOWR('Q',16, struct patmgr_info)
 #define SNDCTL_SEQ_PANIC		_IO  ('Q',17)
+#define SNDCTL_SEQ_OUTOFBAND		_IOW ('Q',18, struct seq_event_rec)
+
+	struct seq_event_rec {
+			unsigned char arr[8];
+		};
 
 #define SNDCTL_TMR_TIMEBASE		_IOWR('T', 1, int)
 #define SNDCTL_TMR_START		_IO  ('T', 2)
@@ -124,7 +146,7 @@
  *	Sample loading mechanism for internal synthesizers (/dev/sequencer)
  *	The following patch_info structure has been designed to support
  *	Gravis UltraSound. It tries to be universal format for uploading
- *	sample based patches but is probably too limited.
+ *	sample based patches but is propably too limited.
  */
 
 struct patch_info {
@@ -211,6 +233,7 @@
 struct sysex_info {
 		short key;		/* Use GUS_PATCH here */
 #define SYSEX_PATCH	0x05fd
+#define MAUI_PATCH	0x06fd		/* For future use */
 		short device_no;	/* Synthesizer number */
 		long len;	/* Size of the sysex data in bytes */
 		unsigned char data[1];	/* Sysex data starts here */
@@ -343,14 +366,8 @@
  * controllers.
  * In the MIDI 1.0 these controllers are sent using
  * two messages. Controller numbers 0 to 31 are used
- * to send the LSB and the controller numbers 32 to 63
- * are for the LSB.
- *
- * This driver uses just the numbers 0 to 31 to store both
- * the LSB and MSB. The controller value is a unsigned short
- * and its valid range is between 0 and 16383 (0x0000 to 0x3fff).
- * The driver sends the controller value using two messages when
- * necessary.
+ * to send the MSB and the controller numbers 32 to 63
+ * are for the LSB. Note that just 7 bits are used in MIDI bytes.
  */
 
 #define	   CTL_BANK_SELECT		0x00
@@ -557,6 +574,22 @@
 #	define AFMT_S8			0x00000040
 #	define AFMT_U16_LE		0x00000080	/* Little endian U16 */
 #	define AFMT_U16_BE		0x00000100	/* Big endian U16 */
+#	define AFMT_MPEG		0x00000200	/* MPEG (2) audio */
+
+/*
+ * Buffer status queries.
+ */
+typedef struct audio_buf_info {
+			int fragments;	/* # of available fragments (partially usend ones not counted) */
+			int fragsize;	/* Size of a fragment in bytes */
+
+			int bytes;	/* Available space in bytes (includes partially used fragments) */
+			/* Note! 'bytes' could be more than fragments*fragsize */
+		} audio_buf_info;
+
+#define SNDCTL_DSP_GETOSPACE		_IOR ('P',12, audio_buf_info)
+#define SNDCTL_DSP_GETISPACE		_IOR ('P',13, audio_buf_info)
+#define SNDCTL_DSP_NONBLOCK		_IO  ('P',14)
 
 #define SOUND_PCM_READ_RATE		_IOR ('P', 2, int)
 #define SOUND_PCM_READ_CHANNELS		_IOR ('P', 6, int)
@@ -573,21 +606,50 @@
 #define SOUND_PCM_SETFRAGMENT		SNDCTL_DSP_SETFRAGMENT
 #define SOUND_PCM_GETFMTS		SNDCTL_DSP_GETFMTS
 #define SOUND_PCM_SETFMT		SNDCTL_DSP_SETFMT
-
-/*********************************************
- * IOCTL /dev/pss (experimental PSS API by marc.hoffman@analog.com.
- *		likely to change in near future.
- */
-#define SNDCTL_PSS_RESET             _IO  ('C',  0)
-#define SNDCTL_PSS_SETUP_REGISTERS   _IO  ('C',  1)
-#define SNDCTL_PSS_SPEAKER           _IOW ('C',  2, struct pss_speaker)
-
-struct pss_speaker {
-  int volume;
-  int bass;
-  int treb;
-  int mode;
-};
+#define SOUND_PCM_GETOSPACE		SNDCTL_DSP_GETOSPACE
+#define SOUND_PCM_GETISPACE		SNDCTL_DSP_GETISPACE
+#define SOUND_PCM_NONBLOCK		SNDCTL_DSP_NONBLOCK
+
+/*
+ * ioctl calls to be used in communication with coprocessors and
+ * DSP chips.
+ */
+
+typedef struct copr_buffer {
+		int command;	/* Set to 0 if not used */
+		int flags;
+#define CPF_NONE		0x0000
+#define CPF_FIRST		0x0001	/* First block */
+#define CPF_LAST		0x0002	/* Last block */
+		int len;
+		int offs;	/* If required by the device (0 if not used) */
+
+		unsigned char data[4000]; /* NOTE! 4000 is not 4k */
+	} copr_buffer;
+
+typedef struct copr_debug_buf {
+		int command;	/* Used internally. Set to 0 */
+		int parm1;
+		int parm2;
+		int flags;	
+		int len;	/* Length of data in bytes */
+	} copr_debug_buf;
+
+typedef struct copr_msg {
+		int len;
+		unsigned char data[4000];
+	} copr_msg;
+
+#define SNDCTL_COPR_RESET             _IO  ('C',  0)
+#define SNDCTL_COPR_LOAD	      _IOWR('C',  1, copr_buffer)
+#define SNDCTL_COPR_RDATA	      _IOWR('C',  2, copr_debug_buf)
+#define SNDCTL_COPR_RCODE	      _IOWR('C',  3, copr_debug_buf)
+#define SNDCTL_COPR_WDATA	      _IOW ('C',  4, copr_debug_buf)
+#define SNDCTL_COPR_WCODE	      _IOW ('C',  5, copr_debug_buf)
+#define SNDCTL_COPR_RUN		      _IOWR('C',  6, copr_debug_buf)
+#define SNDCTL_COPR_HALT	      _IOWR('C',  7, copr_debug_buf)
+#define SNDCTL_COPR_SENDMSG	      _IOW ('C',  8, copr_msg)
+#define SNDCTL_COPR_RCVMSG	      _IOR ('C',  9, copr_msg)
 
 /*********************************************
  * IOCTL commands for /dev/mixer
@@ -602,7 +664,7 @@
  * the devices supported by the particular mixer.
  */
 
-#define SOUND_MIXER_NRDEVICES	12
+#define SOUND_MIXER_NRDEVICES	17
 #define SOUND_MIXER_VOLUME	0
 #define SOUND_MIXER_BASS	1
 #define SOUND_MIXER_TREBLE	2
@@ -615,6 +677,17 @@
 #define SOUND_MIXER_IMIX	9	/*  Recording monitor  */
 #define SOUND_MIXER_ALTPCM	10
 #define SOUND_MIXER_RECLEV	11	/* Recording level */
+#define SOUND_MIXER_IGAIN	12	/* Input gain */
+#define SOUND_MIXER_OGAIN	13	/* Output gain */
+/* 
+ * The AD1848 codec and compatibles have three line level inputs
+ * (line, aux1 and aux2). Since each card manufacturer have assigned
+ * different meanings to these inputs, it's inpractical to assign
+ * specific meanings (line, cd, synth etc.) to them.
+ */
+#define SOUND_MIXER_LINE1	14	/* Input source 1  (aux1) */
+#define SOUND_MIXER_LINE2	15	/* Input source 2  (aux2) */
+#define SOUND_MIXER_LINE3	16	/* Input source 3  (line) */
 
 /* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */
 /* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */
@@ -627,10 +700,12 @@
 /* Note!	Number 31 cannot be used since the sign bit is reserved */
 
 #define SOUND_DEVICE_LABELS	{"Vol  ", "Bass ", "Trebl", "Synth", "Pcm  ", "Spkr ", "Line ", \
-				 "Mic  ", "CD   ", "Mix  ", "Pcm2 ", "rec"}
+				 "Mic  ", "CD   ", "Mix  ", "Pcm2 ", "Rec  ", "IGain", "OGain", \
+				 "Line1", "Line2", "Line3"}
 
 #define SOUND_DEVICE_NAMES	{"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
-				 "mic", "cd", "mix", "pcm2", "rec"}
+				 "mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
+				 "line1", "line2", "line3"}
 
 /*	Device bitmask identifiers	*/
 
@@ -655,6 +730,11 @@
 #define SOUND_MASK_IMIX		(1 << SOUND_MIXER_IMIX)
 #define SOUND_MASK_ALTPCM	(1 << SOUND_MIXER_ALTPCM)
 #define SOUND_MASK_RECLEV	(1 << SOUND_MIXER_RECLEV)
+#define SOUND_MASK_IGAIN	(1 << SOUND_MIXER_IGAIN)
+#define SOUND_MASK_OGAIN	(1 << SOUND_MIXER_OGAIN)
+#define SOUND_MASK_LINE1	(1 << SOUND_MIXER_LINE1)
+#define SOUND_MASK_LINE2	(1 << SOUND_MIXER_LINE2)
+#define SOUND_MASK_LINE3	(1 << SOUND_MIXER_LINE3)
 
 #define SOUND_MASK_MUTE		(1 << SOUND_MIXER_MUTE)
 #define SOUND_MASK_ENHANCE	(1 << SOUND_MIXER_ENHANCE)
@@ -673,6 +753,11 @@
 #define SOUND_MIXER_READ_IMIX		MIXER_READ(SOUND_MIXER_IMIX)
 #define SOUND_MIXER_READ_ALTPCM		MIXER_READ(SOUND_MIXER_ALTPCM)
 #define SOUND_MIXER_READ_RECLEV		MIXER_READ(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_READ_IGAIN		MIXER_READ(SOUND_MIXER_IGAIN)
+#define SOUND_MIXER_READ_OGAIN		MIXER_READ(SOUND_MIXER_OGAIN)
+#define SOUND_MIXER_READ_LINE1		MIXER_READ(SOUND_MIXER_LINE1)
+#define SOUND_MIXER_READ_LINE2		MIXER_READ(SOUND_MIXER_LINE2)
+#define SOUND_MIXER_READ_LINE3		MIXER_READ(SOUND_MIXER_LINE3)
 #define SOUND_MIXER_READ_MUTE		MIXER_READ(SOUND_MIXER_MUTE)
 #define SOUND_MIXER_READ_ENHANCE	MIXER_READ(SOUND_MIXER_ENHANCE)
 #define SOUND_MIXER_READ_LOUD		MIXER_READ(SOUND_MIXER_LOUD)
@@ -696,6 +781,11 @@
 #define SOUND_MIXER_WRITE_IMIX		MIXER_WRITE(SOUND_MIXER_IMIX)
 #define SOUND_MIXER_WRITE_ALTPCM	MIXER_WRITE(SOUND_MIXER_ALTPCM)
 #define SOUND_MIXER_WRITE_RECLEV	MIXER_WRITE(SOUND_MIXER_RECLEV)
+#define SOUND_MIXER_WRITE_IGAIN		MIXER_WRITE(SOUND_MIXER_IGAIN)
+#define SOUND_MIXER_WRITE_OGAIN		MIXER_WRITE(SOUND_MIXER_OGAIN)
+#define SOUND_MIXER_WRITE_LINE1		MIXER_WRITE(SOUND_MIXER_LINE1)
+#define SOUND_MIXER_WRITE_LINE2		MIXER_WRITE(SOUND_MIXER_LINE2)
+#define SOUND_MIXER_WRITE_LINE3		MIXER_WRITE(SOUND_MIXER_LINE3)
 #define SOUND_MIXER_WRITE_MUTE		MIXER_WRITE(SOUND_MIXER_MUTE)
 #define SOUND_MIXER_WRITE_ENHANCE	MIXER_WRITE(SOUND_MIXER_ENHANCE)
 #define SOUND_MIXER_WRITE_LOUD		MIXER_WRITE(SOUND_MIXER_LOUD)
@@ -922,7 +1012,7 @@
 #endif
 
 /*
- * Timing and synchronization macros
+ * Timing and syncronization macros
  */
 
 #define _TIMER_EVENT(ev, parm)		{_SEQ_NEEDBUF(8);\
diff -u --recursive --new-file v1.3.8/linux/include/linux/ultrasound.h linux/include/linux/ultrasound.h
--- v1.3.8/linux/include/linux/ultrasound.h	Wed Aug 10 19:26:44 1994
+++ linux/include/linux/ultrasound.h	Fri Mar  3 12:03:07 1995
@@ -52,7 +52,7 @@
  *		_GUS_VOICEOFF	- Stops voice (no parameters)
  *		_GUS_VOICEFADE	- Stops the voice smoothly.
  *		_GUS_VOICEMODE	- Alters the voice mode, don't start or stop voice (P1=voice mode)
- *		_GUS_VOICEBALA	- Sets voice balance (P1, 0=left, 7=middle and 15=right, default 7)
+ *		_GUS_VOICEBALA	- Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7)
  *		_GUS_VOICEFREQ	- Sets voice (sample) playback frequency (P1=Hz)
  *		_GUS_VOICEVOL	- Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
  *		_GUS_VOICEVOL2	- Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off)
diff -u --recursive --new-file v1.3.8/linux/ipc/Makefile linux/ipc/Makefile
--- v1.3.8/linux/ipc/Makefile	Wed Jan  4 21:16:06 1995
+++ linux/ipc/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 OBJS	=  util.o 
 SRCS	=  util.c
@@ -29,11 +27,5 @@
 	$(CPP) -M $(SRCS) > .depend
 
 modules:
-dummy:
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/ipc/msg.c linux/ipc/msg.c
--- v1.3.8/linux/ipc/msg.c	Tue Jun 27 14:11:47 1995
+++ linux/ipc/msg.c	Tue Jul 11 07:49:01 1995
@@ -105,7 +105,7 @@
 	msq->msg_stime = CURRENT_TIME;
 	if (msq->rwait)
 		wake_up (&msq->rwait);
-	return msgsz;
+	return 0;
 }
 
 asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, 
diff -u --recursive --new-file v1.3.8/linux/kernel/Makefile linux/kernel/Makefile
--- v1.3.8/linux/kernel/Makefile	Fri Jul  7 08:54:56 1995
+++ linux/kernel/Makefile	Tue Jul 11 08:02:20 1995
@@ -9,8 +9,6 @@
 
 .S.s:
 	$(CPP) -traditional $< -o $*.s
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
@@ -36,13 +34,6 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-dummy:
 modules:
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/kernel/exec_domain.c linux/kernel/exec_domain.c
--- v1.3.8/linux/kernel/exec_domain.c	Mon Jan 23 23:04:10 1995
+++ linux/kernel/exec_domain.c	Tue Jul 11 07:56:04 1995
@@ -28,6 +28,27 @@
 
 static asmlinkage void no_lcall7(struct pt_regs * regs)
 {
+
+  /*
+   * This may have been a static linked SVr4 binary, so we would have the
+   * personality set incorrectly.  Check to see whether SVr4 is available,
+   * and use it, otherwise give the user a SEGV.
+   */
+	if (current->exec_domain && current->exec_domain->use_count)
+		(*current->exec_domain->use_count)--;
+
+	current->personality = PER_SVR4;
+	current->exec_domain = lookup_exec_domain(current->personality);
+
+	if (current->exec_domain && current->exec_domain->use_count)
+		(*current->exec_domain->use_count)++;
+
+	if (current->exec_domain && current->exec_domain->handler
+	&& current->exec_domain->handler != no_lcall7) {
+		current->exec_domain->handler(regs);
+		return;
+	}
+
 	send_sig(SIGSEGV, current, 1);
 }
 
diff -u --recursive --new-file v1.3.8/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v1.3.8/linux/kernel/ksyms.c	Fri Jul  7 13:42:58 1995
+++ linux/kernel/ksyms.c	Tue Jul 11 07:56:04 1995
@@ -68,6 +68,8 @@
   
 extern void *sys_call_table;
 
+extern int aout_core_dump(long signr, struct pt_regs * regs);
+
 #ifdef CONFIG_FTAPE
 extern char * ftape_big_buffer;
 #endif
diff -u --recursive --new-file v1.3.8/linux/kernel/signal.c linux/kernel/signal.c
--- v1.3.8/linux/kernel/signal.c	Fri Jun 30 16:22:30 1995
+++ linux/kernel/signal.c	Mon Jul 10 07:43:21 1995
@@ -147,12 +147,10 @@
 		if (err)
 			return err;
 		memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));
+		new_sa.sa_mask |= _S(signum);
 		if (new_sa.sa_flags & SA_NOMASK)
-			new_sa.sa_mask = 0;
-		else {
-			new_sa.sa_mask |= _S(signum);
-			new_sa.sa_mask &= _BLOCKABLE;
-		}
+			new_sa.sa_mask &= ~_S(signum);
+		new_sa.sa_mask &= _BLOCKABLE;
 		if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
 			err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
 			if (err)
diff -u --recursive --new-file v1.3.8/linux/lib/Makefile linux/lib/Makefile
--- v1.3.8/linux/lib/Makefile	Mon Jan 16 07:17:38 1995
+++ linux/lib/Makefile	Tue Jul 11 08:02:20 1995
@@ -6,8 +6,6 @@
 # unless it's something special (ie not a .c file).
 #
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 .s.o:
 	$(AS) -c -o $*.o $<
 .c.o:
@@ -24,10 +22,4 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/mm/Makefile linux/mm/Makefile
--- v1.3.8/linux/mm/Makefile	Wed Jan 11 21:21:06 1995
+++ linux/mm/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 OBJS	= memory.o swap.o mmap.o filemap.o mprotect.o kmalloc.o vmalloc.o
 
@@ -24,9 +22,5 @@
 dep:
 	$(CPP) -M *.c > .depend
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/802/Makefile linux/net/802/Makefile
--- v1.3.8/linux/net/802/Makefile	Tue Jun  6 12:59:13 1995
+++ linux/net/802/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 
 OBJS	:= p8023.o
@@ -47,9 +45,5 @@
 tar:
 		tar -cvf /dev/f1 .
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/Makefile linux/net/Makefile
--- v1.3.8/linux/net/Makefile	Thu Jun 29 19:02:55 1995
+++ linux/net/Makefile	Tue Jul 11 08:02:20 1995
@@ -15,8 +15,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 OBJS	=  socket.o protocols.o
 
@@ -35,12 +33,4 @@
 
 modules:
 
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/appletalk/Makefile linux/net/appletalk/Makefile
--- v1.3.8/linux/net/appletalk/Makefile	Tue Jun  6 12:59:13 1995
+++ linux/net/appletalk/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 
 OBJS	:= aarp.o ddp.o
@@ -27,9 +25,5 @@
 tar:
 		tar -cvf /dev/f1 .
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/ax25/Makefile linux/net/ax25/Makefile
--- v1.3.8/linux/net/ax25/Makefile	Tue Jun  6 12:59:13 1995
+++ linux/net/ax25/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 
 OBJS	:= af_ax25.o
@@ -32,9 +30,5 @@
 tar:
 		tar -cvf /dev/f1 .
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/core/Makefile linux/net/core/Makefile
--- v1.3.8/linux/net/core/Makefile	Tue Jun  6 12:59:13 1995
+++ linux/net/core/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 
 OBJS	:= sock.o dev.o dev_mcast.o skbuff.o datagram.o
@@ -35,9 +33,5 @@
 tar:
 		tar -cvf /dev/f1 .
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/ethernet/Makefile linux/net/ethernet/Makefile
--- v1.3.8/linux/net/ethernet/Makefile	Tue Jun  6 12:59:13 1995
+++ linux/net/ethernet/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 
 OBJS	:= eth.o 
@@ -49,9 +47,5 @@
 tar:
 		tar -cvf /dev/f1 .
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/ethernet/eth.c linux/net/ethernet/eth.c
--- v1.3.8/linux/net/ethernet/eth.c	Fri Jul  7 08:54:57 1995
+++ linux/net/ethernet/eth.c	Mon Jul 10 17:08:04 1995
@@ -233,9 +233,12 @@
  *	Copy from an ethernet device memory space to an sk_buff while checksumming if IP
  */
  
-void eth_copy_and_sum(struct sk_buff *dest,unsigned char *src, int length, int base)
+void eth_copy_and_sum(struct sk_buff *dest, unsigned char *src, int length, int base)
 {
-	struct ethhdr *eth=(struct ethhdr *)dest->data;
+	struct ethhdr *eth;
+
+	IS_SKB(dest);
+	eth=(struct ethhdr *)dest->data;
 	memcpy(dest->data,src,34);	/* ethernet is always >= 60 */
 	length-=34;
 	if(eth->h_proto!=htons(ETH_P_IP))
diff -u --recursive --new-file v1.3.8/linux/net/ipv4/Makefile linux/net/ipv4/Makefile
--- v1.3.8/linux/net/ipv4/Makefile	Fri Jun 16 22:02:56 1995
+++ linux/net/ipv4/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,9 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
-
 
 OBJS	:= utils.o route.o proc.o timer.o protocol.o packet.o \
 		   arp.o ip.o raw.o icmp.o tcp.o udp.o devinet.o af_inet.o \
@@ -43,9 +40,5 @@
 tar:
 		tar -cvf /dev/f1 .
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/ipv4/ip.c linux/net/ipv4/ip.c
--- v1.3.8/linux/net/ipv4/ip.c	Fri Jul  7 13:42:58 1995
+++ linux/net/ipv4/ip.c	Mon Jul 10 17:08:03 1995
@@ -81,6 +81,7 @@
  *		Alan Cox	:	Set saddr on raw output frames as per BSD.
  *		Alan Cox	:	Stopped broadcast source route explosions.
  *		Alan Cox	:	Can disable source routing
+ *		Takeshi Sone    :	Masquerading didn't work.
  *
  *  
  *
@@ -1023,11 +1024,21 @@
 	 */
 
 	
-	if(!(is_frag&4) && (fw_res=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0))!=1)
+	if(!(is_frag&4))
 	{
-		if(fw_res==-1)
+		fw_res=ip_fw_chk(skb->h.iph, dev, ip_fw_fwd_chain, ip_fw_fwd_policy, 0);
+		switch (fw_res) {
+		case 1:
+#ifdef CONFIG_IP_MASQUERADE
+		case 2:
+#endif
+			break;
+		case -1:
 			icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
-		return;
+			/* fall thru */
+		default:
+			return;
+		}
 	}
 #endif
 	/*
diff -u --recursive --new-file v1.3.8/linux/net/ipx/Makefile linux/net/ipx/Makefile
--- v1.3.8/linux/net/ipx/Makefile	Tue Jun  6 12:59:13 1995
+++ linux/net/ipx/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 
 OBJS	:= af_ipx.o
@@ -27,9 +25,5 @@
 tar:
 		tar -cvf /dev/f1 .
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/netrom/Makefile linux/net/netrom/Makefile
--- v1.3.8/linux/net/netrom/Makefile	Tue Jun  6 12:59:13 1995
+++ linux/net/netrom/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 
 OBJS	:= af_netrom.o
@@ -32,9 +30,5 @@
 tar:
 		tar -cvf /dev/f1 .
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v1.3.8/linux/net/unix/Makefile linux/net/unix/Makefile
--- v1.3.8/linux/net/unix/Makefile	Wed Aug 10 21:35:00 1994
+++ linux/net/unix/Makefile	Tue Jul 11 08:02:20 1995
@@ -11,8 +11,6 @@
 	$(CC) $(CFLAGS) -c $<
 .s.o:
 	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
 
 OBJS	= sock.o proc.o
 
@@ -25,9 +23,5 @@
 tar:
 	tar -cvf /dev/f1 .
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+
+include $(TOPDIR)/Rules.make
