diff -u --recursive --new-file v1.1.93/linux/Makefile linux/Makefile
--- v1.1.93/linux/Makefile	Mon Feb 20 21:34:53 1995
+++ linux/Makefile	Mon Feb 20 21:33:03 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 93
+SUBLEVEL = 94
 
 ARCH = i386
 
diff -u --recursive --new-file v1.1.93/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v1.1.93/linux/arch/alpha/kernel/entry.S	Wed Feb  1 09:23:04 1995
+++ linux/arch/alpha/kernel/entry.S	Wed Feb 22 12:27:52 1995
@@ -145,6 +145,18 @@
 	rti
 .end entUna
 
+.align 5
+.globl	entSys
+.ent	entSys
+entSys:
+	SAVE_ALL
+	bis	$30,$30,$19
+	lda	$27,do_entSys
+	jsr	$26,($27),do_entSys
+	RESTORE_ALL
+	rti
+.end entSys
+
 	.align 5
 	.globl sys_call_table
 sys_call_table:
diff -u --recursive --new-file v1.1.93/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v1.1.93/linux/arch/alpha/kernel/process.c	Wed Feb 15 10:36:37 1995
+++ linux/arch/alpha/kernel/process.c	Wed Feb 22 12:27:52 1995
@@ -60,19 +60,19 @@
 }
 
 /*
- * This needs lots of work still..
+ * This needs some work still..
  */
-unsigned long copy_thread(int nr, unsigned long clone_flags, struct task_struct * p, struct pt_regs * regs)
+void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+	struct task_struct * p, struct pt_regs * regs)
 {
 	struct pt_regs * childregs;
 
-	p->tss.usp = rdusp();
+	p->tss.usp = usp;
 	childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
 	*childregs = *regs;
 	p->tss.ksp = (unsigned long) childregs;
 /*	p->tss.pc = XXXX; */
-	halt();
-	return clone_flags;
+	panic("copy_thread not implemented");
 }
 
 /*
@@ -84,9 +84,51 @@
 
 /*
  * sys_execve() executes a new program.
+ *
+ * This works due to the alpha calling sequence: the first 6 args
+ * are gotten from registers, while the rest is on the stack, so
+ * we get a0-a5 for free, and then magically find "struct pt_regs"
+ * on the stack for us..
+ *
+ * Don't do this at home.
  */
-asmlinkage int sys_execve(struct pt_regs regs)
+asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
+	unsigned long a3, unsigned long a4, unsigned long a5,
+	struct pt_regs regs)
 {
-	halt();
-	return 0;
+	int error;
+	char * filename;
+
+	error = getname((char *) a0, &filename);
+	if (error)
+		return error;
+	error = do_execve(filename, (char **) a1, (char **) a2, &regs);
+	putname(filename);
+	return error;
+}
+
+/*
+ * sys_fork() does the obvious thing, but not the obvious way.
+ * See sys_execve() above.
+ */
+asmlinkage int sys_fork(unsigned long a0, unsigned long a1, unsigned long a2,
+	unsigned long a3, unsigned long a4, unsigned long a5,
+	struct pt_regs regs)
+{
+	return do_fork(COPYVM | SIGCHLD, rdusp(), &regs);
+}
+
+asmlinkage int sys_clone(unsigned long a0, unsigned long a1, unsigned long a2,
+	unsigned long a3, unsigned long a4, unsigned long a5,
+	struct pt_regs regs)
+{
+	unsigned long clone_flags = a0;
+	unsigned long newsp;
+
+	newsp = rdusp();
+	if (newsp == a1 || !a1)
+		clone_flags |= COPYVM;
+	else
+		newsp = a1;	
+	return do_fork(clone_flags, newsp, &regs);
 }
diff -u --recursive --new-file v1.1.93/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v1.1.93/linux/arch/alpha/kernel/traps.c	Mon Jan 30 08:53:05 1995
+++ linux/arch/alpha/kernel/traps.c	Wed Feb 22 12:27:52 1995
@@ -38,10 +38,28 @@
 	die_if_kernel("Unaligned", regs, 0);
 }
 
+/*
+ * DEC means people to use the "retsys" instruction for return from
+ * a system call, but they are clearly misguided about this. We use
+ * "rti" in all cases, and fill in the stack with the return values.
+ * That should make signal handling etc much cleaner.
+ *
+ * Even more horribly, DEC doesn't allow system calls from kernel mode.
+ * "Security" features letting the user do something the kernel can't
+ * are a thinko. DEC palcode is strange. The PAL-code designers probably
+ * got terminally tainted by VMS at some point.
+ */
+asmlinkage void do_entSys(unsigned long sysnr, unsigned long arg1, unsigned long arg2, struct pt_regs *regs)
+{
+	printk("System call %ld(%ld,%ld)\n", sysnr, arg1, arg2);
+	die_if_kernel("Syscall", regs, 0);
+}
+
 extern asmlinkage void entMM(void);
 extern asmlinkage void entIF(void);
 extern asmlinkage void entArith(void);
 extern asmlinkage void entUna(void);
+extern asmlinkage void entSys(void);
 
 void trap_init(void)
 {
@@ -59,4 +77,5 @@
 	wrent(entMM, 2);
 	wrent(entIF, 3);
 	wrent(entUna, 4);
+	wrent(entSys, 5);
 }
diff -u --recursive --new-file v1.1.93/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v1.1.93/linux/arch/i386/kernel/process.c	Wed Feb 15 10:36:37 1995
+++ linux/arch/i386/kernel/process.c	Wed Feb 22 12:27:52 1995
@@ -150,9 +150,8 @@
 		current->debugreg[i] = 0;
 }
 
-#define IS_CLONE (regs->orig_eax == __NR_clone)
-
-unsigned long copy_thread(int nr, unsigned long clone_flags, struct task_struct * p, struct pt_regs * regs)
+void copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
+	struct task_struct * p, struct pt_regs * regs)
 {
 	int i;
 	struct pt_regs * childregs;
@@ -171,15 +170,9 @@
 	p->tss.eip = (unsigned long) ret_from_sys_call;
 	*childregs = *regs;
 	childregs->eax = 0;
+	childregs->esp = esp;
 	p->tss.back_link = 0;
 	p->tss.eflags = regs->eflags & 0xffffcfff;	/* iopl is always 0 for a new process */
-	if (IS_CLONE) {
-		if (regs->ebx)
-			childregs->esp = regs->ebx;
-		clone_flags = regs->ecx;
-		if (childregs->esp == regs->esp)
-			clone_flags |= COPYVM;
-	}
 	p->tss.ldt = _LDT(nr);
 	if (p->ldt) {
 		p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
@@ -196,7 +189,6 @@
 		p->tss.io_bitmap[i] = ~0;
 	if (last_task_used_math == current)
 		__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
-	return clone_flags;
 }
 
 /*
@@ -236,6 +228,25 @@
 		   convert it into standard 387 format first.. */
 		dump->u_fpvalid = 0;
 	}
+}
+
+asmlinkage int sys_fork(struct pt_regs regs)
+{
+	return do_fork(COPYVM | SIGCHLD, regs.esp, &regs);
+}
+
+asmlinkage int sys_clone(struct pt_regs regs)
+{
+	unsigned long clone_flags;
+	unsigned long newsp;
+
+	newsp = regs.ebx;
+	clone_flags = regs.ecx;
+	if (!newsp)
+		newsp = regs.esp;
+	if (newsp == regs.esp)
+		clone_flags |= COPYVM;
+	return do_fork(clone_flags, newsp, &regs);
 }
 
 /*
diff -u --recursive --new-file v1.1.93/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c
--- v1.1.93/linux/arch/i386/kernel/ptrace.c	Wed Feb  1 09:23:04 1995
+++ linux/arch/i386/kernel/ptrace.c	Mon Feb 20 21:29:53 1995
@@ -1,3 +1,4 @@
+#define THREE_LEVEL
 /* ptrace.c */
 /* By Ross Biro 1/23/92 */
 /* edited by Linus Torvalds */
@@ -86,11 +87,12 @@
 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;
 
 repeat:
-	pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr);
+	pgdir = pgd_offset(vma->vm_task, addr);
 	if (pgd_none(*pgdir)) {
 		do_no_page(vma, addr, 0);
 		goto repeat;
@@ -100,7 +102,17 @@
 		pgd_clear(pgdir);
 		return 0;
 	}
-	pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+	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;
@@ -126,11 +138,12 @@
 	unsigned long data)
 {
 	pgd_t *pgdir;
+	pmd_t *pgmiddle;
 	pte_t *pgtable;
 	unsigned long page;
 
 repeat:
-	pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr);
+	pgdir = pgd_offset(vma->vm_task, addr);
 	if (!pgd_present(*pgdir)) {
 		do_no_page(vma, addr, 1);
 		goto repeat;
@@ -140,7 +153,17 @@
 		pgd_clear(pgdir);
 		return;
 	}
-	pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+	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;
+	}
+	pgtable = pte_offset(pgmiddle, addr);
 	if (!pte_present(*pgtable)) {
 		do_no_page(vma, addr, 1);
 		goto repeat;
diff -u --recursive --new-file v1.1.93/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v1.1.93/linux/arch/sparc/mm/fault.c	Sun Feb  5 19:31:51 1995
+++ linux/arch/sparc/mm/fault.c	Wed Feb 22 08:47:40 1995
@@ -14,11 +14,6 @@
 extern unsigned long pg0[1024];		/* page table for 0-4MB for everybody */
 extern void die_if_kernel(char *,struct pt_regs *,long);
 
-/* Sparc stuff... I know this is a ugly place to put the PROM vector, don't
- * remind me.
- */
-extern unsigned int trapbase[];
-extern unsigned int end[], etext[], msgbuf[];
 struct linux_romvec *romvec;
 
 /* foo */
diff -u --recursive --new-file v1.1.93/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v1.1.93/linux/arch/sparc/mm/init.c	Mon Feb 20 21:34:54 1995
+++ linux/arch/sparc/mm/init.c	Wed Feb 22 08:47:40 1995
@@ -160,7 +160,7 @@
 	 * self-modifying code.
 	 */
 
-	a= (unsigned long) etext;
+	a= (unsigned long) &etext;
 	mask=~(PTE_NC|PTE_W);    /* make cacheable + not writable */
 
 	printk("changing kernel text perms...\n");
@@ -173,7 +173,7 @@
 
 	for(i=0; i<8; i++)
 	  {
-	    b=PAGE_ALIGN((unsigned long) trapbase);
+	    b=PAGE_ALIGN((unsigned long) &trapbase);
 
 	    switch_to_context(i);
 
diff -u --recursive --new-file v1.1.93/linux/drivers/block/sonycd535.c linux/drivers/block/sonycd535.c
--- v1.1.93/linux/drivers/block/sonycd535.c	Fri Feb 17 11:20:12 1995
+++ linux/drivers/block/sonycd535.c	Wed Feb 22 08:46:46 1995
@@ -4,7 +4,7 @@
  * This is a modified version of the CDU-31A device driver (see below).
  * Changes were made using documentation for the CDU-531 (which Sony
  * assures me is very similar to the 535) and partial disassembly of the
- * DOS driver.  I used Minyard's driver and replaced the the CDU-31A 
+ * DOS driver.  I used Minyard's driver and replaced the the CDU-31A
  * commands with the CDU-531 commands.  This was complicated by a different
  * interface protocol with the drive.  The driver is still polled.
  *
@@ -23,18 +23,23 @@
  *
  * Things to do:
  *  - handle errors and status better, put everything into a single word
- *  - use interrupts, DMA
+ *  - use interrupts (code mostly there, but a big hole still missing)
+ *  - handle multi-session CDs?
+ *  - use DMA?
  *
  *  Known Bugs:
  *  -
  *
+ *   Ken Pizzini (ken@halcyon.com)
+ *
+ * Original by:
  *   Ron Jeppesen (ronj.an@site007.saic.com)
  *
  *
  *------------------------------------------------------------------------
  * Sony CDROM interface device driver.
  *
- * Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to ronj above)
+ * Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to Ken above)
  *
  * Colossians 3:17
  *
@@ -99,6 +104,9 @@
 # include <linux/module.h>
 # include <linux/malloc.h>
 # include <linux/version.h>
+# ifndef CONFIG_MODVERSIONS
+	char kernel_version[]= UTS_RELEASE;
+# endif
 #endif
 
 #include <linux/errno.h>
@@ -137,9 +145,11 @@
  * proper address.
  */
 #ifndef CDU535_ADDRESS
-# define CDU535_ADDRESS	(0x340)
+# define CDU535_ADDRESS			0x340
+#endif
+#ifndef CDU535_INTERRUPT
+# define CDU535_INTERRUPT		0
 #endif
-
 #ifndef CDU535_HANDLE
 # define CDU535_HANDLE			"cdu535"
 #endif
@@ -171,7 +181,9 @@
  *  if LOCK_DOORS is defined then the eject button is disabled while
  * the device is open.
  */
-#define LOCK_DOORS
+#ifndef NO_LOCK_DOORS
+# define LOCK_DOORS
+#endif
 
 static int read_subcode(void);
 static void sony_get_toc(void);
@@ -179,11 +191,14 @@
 static inline unsigned int int_to_bcd(unsigned int val);
 static unsigned int bcd_to_int(unsigned int bcd);
 static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2],
-					   Byte * response, int nResponse, int ignoreStatusBit7);
+					   Byte * response, int n_response, int ignoreStatusBit7);
 
 /* The base I/O address of the Sony Interface.  This is a variable (not a
    #define) so it can be easily changed via some future ioctl() */
-static unsigned short sony_cd_base_io = CDU535_ADDRESS;
+#ifndef MODULE
+static
+#endif
+unsigned short sony535_cd_base_io = CDU535_ADDRESS;
 
 /*
  * The following are I/O addresses of the various registers for the drive.  The
@@ -217,10 +232,10 @@
 static struct s535_sony_subcode *last_sony_subcode;		/* Points to the last
 														   subcode address read */
 #ifndef MODULE
-static unsigned char *sony_buffer;	/* Points to the read-ahead buffer */
+static Byte *sony_buffer;		/* Points to the read-ahead buffer */
 #else
-static unsigned char **sony_buffer;		/* Points to the pointers
-										   to the sector buffers */
+static Byte **sony_buffer;		/* Points to the pointers
+								   to the sector buffers */
 #endif
 static int sony_inuse = 0;		/* is the drive in use? Only one
 								   open at a time allowed */
@@ -240,8 +255,17 @@
  *   I just kept the CDU-31A driver behavior rather than using the PAUSE
  * command on the CDU-535.
  */
-static unsigned char cur_pos_msf[3] = {0, 0, 0};
-static unsigned char final_pos_msf[3] = {0, 0, 0};
+static Byte cur_pos_msf[3] = {0, 0, 0};
+static Byte final_pos_msf[3] = {0, 0, 0};
+
+/* What IRQ is the drive using?  0 if none. */
+#ifndef MODULE
+static
+#endif
+int sony535_irq_used = CDU535_INTERRUPT;
+
+/* The interrupt handler will wake this queue up when it gets an interrupt. */
+static struct wait_queue *cdu535_irq_wait = NULL;
 
 
 /*
@@ -251,10 +275,10 @@
 static int
 cdu535_check_media_change(dev_t full_dev)
 {
-	int     retval;
+	int retval;
 
 	if (MINOR(full_dev) != 0) {
-		printk("Sony CD-ROM request error: invalid device.\n");
+		printk(CDU535_MESSAGE_NAME " request error: invalid device.\n");
 		return 0;
 	}
 
@@ -264,18 +288,64 @@
 	return retval;
 }
 
+static inline void
+enable_interrupts(void)
+{
+#ifdef USE_IRQ
+	/* this code snarfed from cdu31a.c; it will not
+	 * directly work for the cdu535 as written...
+	 */
+	curr_control_reg |= ( SONY_ATTN_INT_EN_BIT
+						| SONY_RES_RDY_INT_EN_BIT
+						| SONY_DATA_RDY_INT_EN_BIT);
+	outb(curr_control_reg, sony_cd_control_reg);
+#endif
+}
+
+static inline void
+disable_interrupts(void)
+{
+#ifdef USE_IRQ
+	/* this code snarfed from cdu31a.c; it will not
+	 * directly work for the cdu535 as written...
+	 */
+	curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT
+						| SONY_RES_RDY_INT_EN_BIT
+						| SONY_DATA_RDY_INT_EN_BIT);
+	outb(curr_control_reg, sony_cd_control_reg);
+#endif
+}
+
+static void
+cdu535_interrupt(int irq, struct pt_regs *regs)
+{
+	disable_interrupts();
+	if (cdu535_irq_wait != NULL)
+		wake_up(&cdu535_irq_wait);
+	else
+		printk(CDU535_MESSAGE_NAME
+				": Got an interrupt but nothing was waiting\n");
+}
+
 
 /*
  * Wait a little while (used for polling the drive).  If in initialization,
- * setting a timeout doesn't work, so just loop for a while  (we trust
- * that the sony_sleep() call is protected by a test for proper jiffies count).
+ * setting a timeout doesn't work, so just loop for a while.  (We trust
+ * that the sony_sleep() call is protected by a test for proper jiffies count.)
  */
 static inline void
 sony_sleep(void)
 {
-	current->state = TASK_INTERRUPTIBLE;
-	current->timeout = jiffies;
-	schedule();
+	if (sony535_irq_used <= 0) {	/* poll */
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies;
+		schedule();
+	} else {	/* Interrupt driven */
+		cli();
+		enable_interrupts();
+		interruptible_sleep_on(&cdu535_irq_wait);
+		sti();
+	}
 }
 
 /*------------------start of SONY CDU535 very specific ---------------------*/
@@ -293,23 +363,24 @@
 }
 
 /***************************************************************************
- * int read_result_reg( unsigned char *data_ptr )
+ * int read_result_reg( Byte *data_ptr )
  *
  *  Read a result byte from the Sony CDU controller, store in location pointed
  * to by data_ptr.  Return zero on success, TIME_OUT if we did not receive
  * data.
  ***************************************************************************/
 static int
-read_result_reg(unsigned char *data_ptr)
+read_result_reg(Byte *data_ptr)
 {
-	int     retry_count;
-	int     read_status;
+	int retry_count;
+	int read_status;
 
 	retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
 	while (jiffies < retry_count) {
 		if (((read_status = inb(read_status_reg)) & SONY535_RESULT_NOT_READY_BIT) == 0) {
 #if DEBUG > 1
-			printk("read_result_reg(): readStatReg = 0x%x\n", read_status);
+			printk(CDU535_MESSAGE_NAME
+					": read_result_reg(): readStatReg = 0x%x\n", read_status);
 #endif
 			*data_ptr = inb(result_reg);
 			return 0;
@@ -317,14 +388,14 @@
 			sony_sleep();
 		}
 	}
-	printk(" Sony CDROM read_result_reg: TIME OUT!\n");
+	printk(CDU535_MESSAGE_NAME " read_result_reg: TIME OUT!\n");
 	return TIME_OUT;
 }
 
 /****************************************************************************
  * int read_exec_status( Byte status[2] )
  *
- *  Read the execution status of the last command and put into status. 
+ *  Read the execution status of the last command and put into status.
  * Handles reading second status word if available.  Returns 0 on success,
  * TIME_OUT on failure.
  ****************************************************************************/
@@ -339,10 +410,8 @@
 			return TIME_OUT;
 	}
 #if DEBUG > 1
-	printk("read_exec_status: read 0x%x\n", status[0]);
-	if (status[0] & 0x80)
-		printk(" and 0x%x\n", status[1]);
-	printk("\n");
+	printk(CDU535_MESSAGE_NAME ": read_exec_status: read 0x%x 0x%x\n",
+			status[0], status[1]);
 #endif
 	return 0;
 }
@@ -357,9 +426,9 @@
 static int
 check_drive_status(void)
 {
-	Byte    status, e_status[2];
-	int     CDD, ATN;
-	unsigned char cmd;
+	Byte status, e_status[2];
+	int  CDD, ATN;
+	Byte cmd;
 
 	select_unit(0);
 	if (sony_audio_status == CDROM_AUDIO_PLAY) {	/* check status */
@@ -387,7 +456,7 @@
 		return TIME_OUT;
 
 #if DEBUG > 1
-	printk("--check_drive_status() got 0x%x\n", status);
+	printk(CDU535_MESSAGE_NAME ": check_drive_status() got 0x%x\n", status);
 #endif
 
 	if (status == 0)
@@ -401,17 +470,17 @@
 		break;					/* go on to CDD stuff */
 	case SONY535_ATN_BUSY:
 		if (initialized)
-			printk("Sony CDROM error, drive busy\n");
+			printk(CDU535_MESSAGE_NAME " error: drive busy\n");
 		return CD_BUSY;
 	case SONY535_ATN_EJECT_IN_PROGRESS:
-		printk("Sony CDROM error, eject in progress\n");
+		printk(CDU535_MESSAGE_NAME " error: eject in progress\n");
 		sony_audio_status = CDROM_AUDIO_INVALID;
 		return CD_BUSY;
 	case SONY535_ATN_RESET_OCCURRED:
 	case SONY535_ATN_DISC_CHANGED:
 	case SONY535_ATN_RESET_AND_DISC_CHANGED:
 #if DEBUG > 0
-		printk("Sony CDROM, reset occurred or disc changed\n");
+		printk(CDU535_MESSAGE_NAME " notice: reset occurred or disc changed\n");
 #endif
 		sony_disc_changed = 1;
 		sony_toc_read = 0;
@@ -425,16 +494,17 @@
 		}
 		return 0;
 	default:
-		printk("Sony CDROM error, drive busy (ATN=0x%x)\n", ATN);
+		printk(CDU535_MESSAGE_NAME " error: drive busy (ATN=0x%x)\n", ATN);
 		return CD_BUSY;
 	}
-	switch (CDD) {				/* the 531 docs are not helpful in decoding this */
-	case 0x0:					/* just use the values from the DOS driver */
+	switch (CDD) {			/* the 531 docs are not helpful in decoding this */
+	case 0x0:				/* just use the values from the DOS driver */
 	case 0x2:
 	case 0xa:
-		break;					/* no error */
+		break;				/* no error */
 	case 0xc:
-		printk("check_drive_status(): CDD = 0xc! Not properly handled!\n");
+		printk(CDU535_MESSAGE_NAME
+				": check_drive_status(): CDD = 0xc! Not properly handled!\n");
 		return CD_BUSY;		/* ? */
 	default:
 		return CD_BUSY;
@@ -443,14 +513,14 @@
 }	/* check_drive_status() */
 
 /*****************************************************************************
- * int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2], 
+ * int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2],
  *                Byte *response, int n_response, int ignore_status_bit7 )
  *
  *  Generic routine for executing commands.  The command and its parameters
  *  should be placed in the cmd[] array, number of bytes in the command is
  *  stored in nCmd.  The response from the command will be stored in the
  *  response array.  The number of bytes you expect back (excluding status)
- *  should be passed in nResponse.  Finally, some
+ *  should be passed in n_response.  Finally, some
  *  commands set bit 7 of the return status even when there is no second
  *  status byte, on these commands set ignoreStatusBit7 TRUE.
  *    If the command was sent and data received back, then we return 0,
@@ -462,7 +532,7 @@
 do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2],
 			Byte * response, int n_response, int ignore_status_bit7)
 {
-	int     i;
+	int i;
 
 	/* write out the command */
 	for (i = 0; i < n_cmd; i++)
@@ -471,7 +541,7 @@
 	/* read back the status */
 	if (read_result_reg(status) != 0)
 		return TIME_OUT;
-	if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) {	
+	if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) {
 		/* get second status byte */
 		if (read_result_reg(status + 1) != 0)
 			return TIME_OUT;
@@ -479,7 +549,8 @@
 		status[1] = 0;
 	}
 #if DEBUG > 2
-	printk("do_sony_cmd %x: %x %x\n", *cmd, status[0], status[1]);
+	printk(CDU535_MESSAGE_NAME ": do_sony_cmd %x: %x %x\n",
+			*cmd, status[0], status[1]);
 #endif
 
 	/* do not know about when I should read set of data and when not to */
@@ -502,7 +573,8 @@
 static int
 set_drive_mode(int mode, Byte status[2])
 {
-	Byte    cmd_buff[2], ret_buff[1];
+	Byte cmd_buff[2];
+	Byte ret_buff[1];
 
 	cmd_buff[0] = SONY535_SET_DRIVE_MODE;
 	cmd_buff[1] = mode;
@@ -510,7 +582,7 @@
 }
 
 /***************************************************************************
- * int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2], 
+ * int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2],
  *                             Byte *data_buff, int buff_size )
  *
  *  Read n_blocks of data from the CDROM starting at position params[0:2],
@@ -527,19 +599,19 @@
 					   Byte * data_buff, int buf_size)
 #else
 seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2],
-					   unsigned char **buff, int buf_size)
+					   Byte **buff, int buf_size)
 #endif
 {
-	int     i;
 	const int block_size = 2048;
-	Byte    cmd_buff[7];
-	int     read_status;
-	int     retry_count;
-#ifdef MODULE
-	Byte   *data_buff;
-	int     sector_count = 0;
+	Byte cmd_buff[7];
+	int  i;
+	int  read_status;
+	int  retry_count;
+#ifndef MODULE
+	Byte *start_pos = data_buff;
 #else
-	Byte   *start_pos = data_buff;
+	Byte *data_buff;
+	int  sector_count = 0;
 #endif
 
 	if (buf_size < ((long)block_size) * n_blocks)
@@ -598,11 +670,11 @@
 static int
 request_toc_data(Byte status[2], struct s535_sony_toc *toc)
 {
-	int     to_status;
-	int     i, j, n_tracks, track_no;
-	Byte    cmd_no = 0xb2;
-	Byte    track_address_buffer[5];
-	int     first_track_num, last_track_num;
+	int  to_status;
+	int  i, j, n_tracks, track_no;
+	int  first_track_num, last_track_num;
+	Byte cmd_no = 0xb2;
+	Byte track_address_buffer[5];
 
 	/* read the fixed portion of the table of contents */
 	if ((to_status = do_sony_cmd(&cmd_no, 1, status, (Byte *) toc, 15, 1)) != 0)
@@ -636,19 +708,19 @@
 static int
 spin_up_drive(Byte status[2])
 {
-	Byte    cmd_buff[1];
+	Byte cmd;
 
 	/* first see if the drive is already spinning */
-	cmd_buff[0] = SONY535_REQUEST_DRIVE_STATUS_1;
-	if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0)
+	cmd = SONY535_REQUEST_DRIVE_STATUS_1;
+	if (do_sony_cmd(&cmd, 1, status, NULL, 0, 0) != 0)
 		return TIME_OUT;
 	if ((status[0] & SONY535_STATUS1_NOT_SPINNING) == 0)
-		return 0;				/* its already spinning */
+		return 0;	/* its already spinning */
 
-	/* else, give the spin-up command */
-	cmd_buff[0] = SONY535_SPIN_UP;
-	return do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
-}	/* spin_up_drive() */
+	/* otherwise, give the spin-up command */
+	cmd = SONY535_SPIN_UP;
+	return do_sony_cmd(&cmd, 1, status, NULL, 0, 0);
+}
 
 /*--------------------end of SONY CDU535 very specific ---------------------*/
 
@@ -656,8 +728,7 @@
 static inline unsigned int
 int_to_bcd(unsigned int val)
 {
-	int     retval;
-
+	int retval;
 
 	retval = (val / 10) << 4;
 	retval = retval | val % 10;
@@ -678,7 +749,7 @@
  * a block device) to an MSF format.
  */
 static void
-log_to_msf(unsigned int log, unsigned char *msf)
+log_to_msf(unsigned int log, Byte *msf)
 {
 	log = log + LOG_START_OFFSET;
 	msf[0] = int_to_bcd(log / 4500);
@@ -692,7 +763,7 @@
  * Convert an MSF format to a logical sector.
  */
 static unsigned int
-msf_to_log(unsigned char *msf)
+msf_to_log(Byte *msf)
 {
 	unsigned int log;
 
@@ -711,8 +782,7 @@
  * the drive would want to see a number-of-sector value.
  */
 static void
-size_to_buf(unsigned int size,
-			unsigned char *buf)
+size_to_buf(unsigned int size, Byte *buf)
 {
 	buf[0] = size / 65536;
 	size = size % 65536;
@@ -731,14 +801,15 @@
 static void
 do_cdu535_request(void)
 {
-	int     block;
 	unsigned int dev;
-	int     nsect;
-	unsigned char params[10];
-	int     copyoff;
-	int     spin_up_retry;
 	unsigned int read_size;
-	unsigned char status[2], cmd[2];
+	int  block;
+	int  nsect;
+	int  copyoff;
+	int  spin_up_retry;
+	Byte params[10];
+	Byte status[2];
+	Byte cmd[2];
 
 
 	if (!sony_inuse) {
@@ -798,33 +869,37 @@
 					size_to_buf(read_size, &params[3]);
 
 					/*
-					 * Read the data.  If the drive was not spinning, spin it up and try
-					 * once more.  I know, the goto is ugly, but I am too lazy to fix it.
+					 * Read the data.  If the drive was not spinning,
+					 * spin it up and try once more.
 					 */
 					spin_up_retry = 0;
-				  try_read_again:
+					for (;;) {
 #if DEBUG > 1
-					if (check_drive_status() != 0) {	/* drive not ready */
-						sony_first_block = -1;
-						sony_last_block = -1;
-						end_request(0);
-						return;
-					}
+						if (check_drive_status() != 0) {
+							/* drive not ready */
+							sony_first_block = -1;
+							sony_last_block = -1;
+							end_request(0);
+							return;
+						}
 #endif
-					if (seek_and_read_N_blocks(params, read_size, status, sony_buffer,
-											   (read_size * 2048)) < 0) {
-						if ((status[0] & SONY535_STATUS1_NOT_SPINNING) && (!spin_up_retry)) {
-							printk(" Sony535 Debug -- calling spin up when reading data!\n");
-							cmd[0] = SONY535_SPIN_UP;
-							do_sony_cmd(cmd, 1, status, NULL, 0, 0);
-							spin_up_retry = 1;
-							goto try_read_again;
+						if (0 <= seek_and_read_N_blocks(params, read_size,
+									status, sony_buffer, (read_size * 2048)))
+							break;
+						if (!(status[0] & SONY535_STATUS1_NOT_SPINNING) ||
+															spin_up_retry) {
+							printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n",
+									status[0]);
+							sony_first_block = -1;
+							sony_last_block = -1;
+							end_request(0);
+							return;
 						}
-						printk("Sony CDROM Read error: 0x%.2x\n", status[0]);
-						sony_first_block = -1;
-						sony_last_block = -1;
-						end_request(0);
-						return;
+						printk(CDU535_MESSAGE_NAME
+							" debug: calling spin up when reading data!\n");
+						cmd[0] = SONY535_SPIN_UP;
+						do_sony_cmd(cmd, 1, status, NULL, 0, 0);
+						spin_up_retry = 1;
 					}
 				}
 				/*
@@ -866,7 +941,7 @@
 static void
 sony_get_toc(void)
 {
-	unsigned char status[2];
+	Byte status[2];
 	if (!sony_toc_read) {
 		/* do not call check_drive_status() from here since it can call this routine */
 		if (request_toc_data(status, sony_toc) < 0)
@@ -884,8 +959,8 @@
 static int
 find_track(int track)
 {
-	int     i;
-	int     num_tracks;
+	int i;
+	int num_tracks;
 
 
 	num_tracks = bcd_to_int(sony_toc->last_track_num) -
@@ -905,16 +980,17 @@
 static int
 read_subcode(void)
 {
-	Byte    cmd = SONY535_REQUEST_SUB_Q_DATA, status[2];
-	int     dsc_status;
+	Byte cmd = SONY535_REQUEST_SUB_Q_DATA;
+	Byte status[2];
+	int  dsc_status;
 
 	if (check_drive_status() != 0)
 		return -EIO;
 
 	if ((dsc_status = do_sony_cmd(&cmd, 1, status, (Byte *) last_sony_subcode,
-							   sizeof (struct s535_sony_subcode), 1)) != 0) {
-		printk("Sony CDROM error 0x%.2x, %d (read_subcode)\n", status[0],
-			   dsc_status);
+							   sizeof(struct s535_sony_subcode), 1)) != 0) {
+		printk(CDU535_MESSAGE_NAME " error 0x%.2x, %d (read_subcode)\n",
+				status[0], dsc_status);
 		return -EIO;
 	}
 	return 0;
@@ -942,9 +1018,9 @@
 	if (!sony_toc_read) {
 		return -EIO;
 	}
-	verify_area(VERIFY_WRITE /* and read */ , (char *)arg, sizeof (schi));
+	verify_area(VERIFY_WRITE /* and read */ , (char *)arg, sizeof schi);
 
-	memcpy_fromfs(&schi, (char *)arg, sizeof (schi));
+	memcpy_fromfs(&schi, (char *)arg, sizeof schi);
 
 	switch (sony_audio_status) {
 	case CDROM_AUDIO_PLAY:
@@ -959,7 +1035,7 @@
 
 	case CDROM_AUDIO_NO_STATUS:
 		schi.cdsc_audiostatus = sony_audio_status;
-		memcpy_tofs((char *)arg, &schi, sizeof (schi));
+		memcpy_tofs((char *)arg, &schi, sizeof schi);
 		return 0;
 		break;
 
@@ -986,7 +1062,7 @@
 		schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf);
 		schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf);
 	}
-	memcpy_tofs((char *)arg, &schi, sizeof (schi));
+	memcpy_tofs((char *)arg, &schi, sizeof schi);
 	return 0;
 }
 
@@ -1001,9 +1077,9 @@
 		  unsigned long arg)
 {
 	unsigned int dev;
-	unsigned char status[2];
-	unsigned char cmd_buff[10], params[10];
-	int     i, dsc_status;
+	Byte status[2];
+	Byte cmd_buff[10], params[10];
+	int  i, dsc_status;
 
 
 	if (!inode) {
@@ -1019,7 +1095,8 @@
 	switch (cmd) {
 	case CDROMSTART:			/* Spin up the drive */
 		if (spin_up_drive(status) < 0) {
-			printk("Sony CDROM error 0x%.2x (CDROMSTART)\n", status[0]);
+			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTART)\n",
+					status[0]);
 			return -EIO;
 		}
 		return 0;
@@ -1038,7 +1115,8 @@
 		dsc_status = do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
 		if (((dsc_status < 0) && (dsc_status != BAD_STATUS)) ||
 			((status[0] & ~(SONY535_STATUS1_NOT_SPINNING)) != 0)) {
-			printk("Sony CDROM error 0x%.2x (CDROMSTOP)\n", status[0]);
+			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTOP)\n",
+					status[0]);
 			return -EIO;
 		}
 		return 0;
@@ -1047,7 +1125,8 @@
 	case CDROMPAUSE:			/* Pause the drive */
 		cmd_buff[0] = SONY535_HOLD;		/* CDU-31 driver uses AUDIO_STOP, not pause */
 		if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) {
-			printk("Sony CDROM error 0x%.2x (CDROMPAUSE)\n", status[0]);
+			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPAUSE)\n",
+					status[0]);
 			return -EIO;
 		}
 		/* Get the current position and save it for resuming */
@@ -1082,7 +1161,8 @@
 		cmd_buff[9] = final_pos_msf[2];
 		if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
 			(do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
-			printk("Sony CDROM error 0x%.2x (CDROMRESUME)\n", status[0]);
+			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMRESUME)\n",
+					status[0]);
 			return -EIO;
 		}
 		sony_audio_status = CDROM_AUDIO_PLAY;
@@ -1108,7 +1188,8 @@
 		/* cmd_buff[7-9] are filled in for loop above */
 		if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
 			(do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
-			printk("Sony CDROM error 0x%.2x (CDROMPLAYMSF)\n", status[0]);
+			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYMSF)\n",
+					status[0]);
 			return -EIO;
 		}
 		/* Save the final position for pauses and resumes */
@@ -1128,10 +1209,10 @@
 			if (!sony_toc_read)
 				return -EIO;
 			hdr = (struct cdrom_tochdr *)arg;
-			verify_area(VERIFY_WRITE, hdr, sizeof (*hdr));
+			verify_area(VERIFY_WRITE, hdr, sizeof *hdr);
 			loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num);
 			loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num);
-			memcpy_tofs(hdr, &loc_hdr, sizeof (*hdr));
+			memcpy_tofs(hdr, &loc_hdr, sizeof *hdr);
 		}
 		return 0;
 		break;
@@ -1140,17 +1221,17 @@
 		{
 			struct cdrom_tocentry *entry;
 			struct cdrom_tocentry loc_entry;
-			int     track_idx;
-			unsigned char *msf_val = NULL;
+			int  track_idx;
+			Byte *msf_val = NULL;
 
 			sony_get_toc();
 			if (!sony_toc_read) {
 				return -EIO;
 			}
 			entry = (struct cdrom_tocentry *)arg;
-			verify_area(VERIFY_WRITE /* and read */ , entry, sizeof (*entry));
+			verify_area(VERIFY_WRITE /* and read */ , entry, sizeof *entry);
 
-			memcpy_fromfs(&loc_entry, entry, sizeof (loc_entry));
+			memcpy_fromfs(&loc_entry, entry, sizeof loc_entry);
 
 			/* Lead out is handled separately since it is special. */
 			if (loc_entry.cdte_track == CDROM_LEADOUT) {
@@ -1174,7 +1255,7 @@
 				loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1));
 				loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2));
 			}
-			memcpy_tofs(entry, &loc_entry, sizeof (*entry));
+			memcpy_tofs(entry, &loc_entry, sizeof *entry);
 		}
 		return 0;
 		break;
@@ -1182,14 +1263,14 @@
 	case CDROMPLAYTRKIND:		/* Play a track.  This currently ignores index. */
 		{
 			struct cdrom_ti ti;
-			int     track_idx;
+			int track_idx;
 
 			sony_get_toc();
 			if (!sony_toc_read)
 				return -EIO;
-			verify_area(VERIFY_READ, (char *)arg, sizeof (ti));
+			verify_area(VERIFY_READ, (char *)arg, sizeof ti);
 
-			memcpy_fromfs(&ti, (char *)arg, sizeof (ti));
+			memcpy_fromfs(&ti, (char *)arg, sizeof ti);
 			if ((ti.cdti_trk0 < sony_toc->first_track_num)
 				|| (sony_toc->last_track_num < ti.cdti_trk0)
 				|| (ti.cdti_trk1 < ti.cdti_trk0)) {
@@ -1234,9 +1315,11 @@
 			cmd_buff[9] = params[6];
 			if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
 				(do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
-				printk("Params: %x %x %x %x %x %x %x\n", params[0], params[1],
-					   params[2], params[3], params[4], params[5], params[6]);
-				printk("Sony CDROM error 0x%.2x (CDROMPLAYTRKIND)\n", status[0]);
+				printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYTRKIND)\n",
+						status[0]);
+				printk("... Params: %x %x %x %x %x %x %x\n",
+						params[0], params[1], params[2],
+						params[3], params[4], params[5], params[6]);
 				return -EIO;
 			}
 			/* Save the final position for pauses and resumes */
@@ -1254,14 +1337,15 @@
 		{
 			struct cdrom_volctrl volctrl;
 
-			verify_area(VERIFY_READ, (char *)arg, sizeof (volctrl));
+			verify_area(VERIFY_READ, (char *)arg, sizeof volctrl);
 
-			memcpy_fromfs(&volctrl, (char *)arg, sizeof (volctrl));
+			memcpy_fromfs(&volctrl, (char *)arg, sizeof volctrl);
 			cmd_buff[0] = SONY535_SET_VOLUME;
 			cmd_buff[1] = volctrl.channel0;
 			cmd_buff[2] = volctrl.channel1;
 			if (do_sony_cmd(cmd_buff, 3, status, NULL, 0, 0) != 0) {
-				printk("Sony CDROM error 0x%.2x (CDROMVOLCTRL)\n", status[0]);
+				printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMVOLCTRL)\n",
+						status[0]);
 				return -EIO;
 			}
 		}
@@ -1276,7 +1360,8 @@
 		sony_audio_status = CDROM_AUDIO_INVALID;
 		cmd_buff[0] = SONY535_EJECT_CADDY;
 		if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) {
-			printk("Sony CDROM error 0x%.2x (CDROMEJECT)\n", status[0]);
+			printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMEJECT)\n",
+					status[0]);
 			return -EIO;
 		}
 		return 0;
@@ -1296,7 +1381,7 @@
 cdu_open(struct inode *inode,
 		 struct file *filp)
 {
-	unsigned char status[2], cmd_buff[2];
+	Byte status[2], cmd_buff[2];
 
 
 	if (sony_inuse)
@@ -1307,7 +1392,8 @@
 	MOD_INC_USE_COUNT;
 
 	if (spin_up_drive(status) != 0) {
-		printk("Sony CDROM error 0x%.2x (cdu_open, spin up)\n", status[0]);
+		printk(CDU535_MESSAGE_NAME " error 0x%.2x (cdu_open, spin up)\n",
+				status[0]);
 		sony_inuse = 0;
 		MOD_DEC_USE_COUNT;
 		return -EIO;
@@ -1343,7 +1429,7 @@
 cdu_release(struct inode *inode,
 			struct file *filp)
 {
-	unsigned char status[2], cmd_no;
+	Byte status[2], cmd_no;
 
 	sony_inuse = 0;
 	MOD_DEC_USE_COUNT;
@@ -1392,28 +1478,44 @@
 unsigned long
 sony535_init(unsigned long mem_start, unsigned long mem_end)
 #else
-int 
+int
 init_module(void)
 #endif
 {
 	struct s535_sony_drive_config drive_config;
-	unsigned char cmd_buff[3], ret_buff[2];
-	unsigned char status[2];
-	int     retry_count;
+	Byte cmd_buff[3];
+	Byte ret_buff[2];
+	Byte status[2];
+	int  retry_count;
+	int  tmp_irq;
 #ifdef MODULE
-	int     i;
+	int  i;
 #endif
 
+	/* Setting the base I/O address to 0xffff will disable it. */
+	if (sony535_cd_base_io == 0xffff)
+		goto bail;
+
 	/* Set up all the register locations */
-	result_reg = sony_cd_base_io;
-	command_reg = sony_cd_base_io;
-	data_reg = sony_cd_base_io + 1;
-	read_status_reg = sony_cd_base_io + 2;
-	select_unit_reg = sony_cd_base_io + 3;
-
-	printk("sonycd535: probing base address %03X\n", sony_cd_base_io);
-	if (check_region(sony_cd_base_io,4)) {
-		printk("sonycd535: my base address is not free!\n");
+	result_reg = sony535_cd_base_io;
+	command_reg = sony535_cd_base_io;
+	data_reg = sony535_cd_base_io + 1;
+	read_status_reg = sony535_cd_base_io + 2;
+	select_unit_reg = sony535_cd_base_io + 3;
+
+#ifndef USE_IRQ
+	sony535_irq_used = 0;	/* polling only until this is ready... */
+#endif
+	/* we need to poll until things get initialized */
+	tmp_irq = sony535_irq_used;
+	sony535_irq_used = 0;
+
+#if DEBUG > 0
+	printk(CDU535_MESSAGE_NAME ": probing base address %03X\n",
+			sony535_cd_base_io);
+#endif
+	if (check_region(sony535_cd_base_io,4)) {
+		printk(CDU535_MESSAGE_NAME ": my base address is not free!\n");
 #ifndef MODULE
 		return mem_start;
 #else
@@ -1433,19 +1535,46 @@
 		select_unit(0);
 		if (inb(result_reg) != 0xff)
 			break;
-		sony_sleep();			/* about 1-2 ms on my machine */
+		sony_sleep();
 	}
 
 	if ((jiffies < retry_count) && (check_drive_status() != TIME_OUT)) {
 		/* CD-ROM drive responded --  get the drive configuration */
 		cmd_buff[0] = SONY535_INQUIRY;
-		if (do_sony_cmd(cmd_buff, 1, status, (Byte *) & drive_config, 28, 1) == 0) {
-			/* was able to get the configuration, set drive mode as rest of init */
+		if (do_sony_cmd(cmd_buff, 1, status,
+						(Byte *)&drive_config, 28, 1) == 0) {
+			/* was able to get the configuration,
+			 * set drive mode as rest of init
+			 */
 #if DEBUG > 0
 			/* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */
 			if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 )
-				printk("Inquiry command returned status = 0x%x\n", status[0]);
+				printk(CDU535_MESSAGE_NAME
+						"Inquiry command returned status = 0x%x\n", status[0]);
 #endif
+			/* now ready to use interrupts, if available */
+			sony535_irq_used = tmp_irq;
+#ifndef MODULE
+/* This code is not in MODULEs by default, since the autoirq stuff might
+ * not be in the module-accessable symbol table.
+ */
+			/* A negative sony535_irq_used will attempt an autoirq. */
+			if (sony535_irq_used < 0) {
+				autoirq_setup(0);
+				enable_interrupts();
+				outb(0, read_status_reg);	/* does a reset? */
+				sony535_irq_used = autoirq_report(10);
+				disable_interrupts();
+			}
+#endif
+			if (sony535_irq_used > 0) {
+			    if (request_irq(sony535_irq_used, cdu535_interrupt,
+								SA_INTERRUPT, CDU535_HANDLE)) {
+					printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME
+							" driver; polling instead.\n", sony535_irq_used);
+					sony535_irq_used = 0;
+				}
+			}
 			cmd_buff[0] = SONY535_SET_DRIVE_MODE;
 			cmd_buff[1] = 0x0;	/* default audio */
 			if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) == 0) {
@@ -1453,11 +1582,14 @@
 				sony_buffer_size = SONY535_BUFFER_SIZE;
 				sony_buffer_sectors = sony_buffer_size / 2048;
 
-				printk("Sony I/F CDROM : %8.8s %16.16s %4.4s",
+				printk(CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s",
 					   drive_config.vendor_id,
 					   drive_config.product_id,
 					   drive_config.product_rev_level);
-				printk("  using %d byte buffer\n", sony_buffer_size);
+				printk("  base address %03X, ", sony535_cd_base_io);
+				if (tmp_irq > 0)
+					printk("IRQ%d, ", tmp_irq);
+				printk("using %d byte buffer\n", sony_buffer_size);
 
 				if (register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
 					printk("Unable to get major %d for %s\n",
@@ -1473,21 +1605,21 @@
 
 #ifndef MODULE
 				sony_toc = (struct s535_sony_toc *)mem_start;
-				mem_start += sizeof (*sony_toc);
+				mem_start += sizeof *sony_toc;
 				last_sony_subcode = (struct s535_sony_subcode *)mem_start;
-				mem_start += sizeof (*last_sony_subcode);
-				sony_buffer = (unsigned char *)mem_start;
+				mem_start += sizeof *last_sony_subcode;
+				sony_buffer = (Byte *)mem_start;
 				mem_start += sony_buffer_size;
 
 #else /* MODULE */
 				sony_toc = (struct s535_sony_toc *)
-					kmalloc(sizeof (*sony_toc), GFP_KERNEL);
+					kmalloc(sizeof *sony_toc, GFP_KERNEL);
 				last_sony_subcode = (struct s535_sony_subcode *)
-					kmalloc(sizeof (*last_sony_subcode), GFP_KERNEL);
-				sony_buffer = (unsigned char **)
+					kmalloc(sizeof *last_sony_subcode, GFP_KERNEL);
+				sony_buffer = (Byte **)
 					kmalloc(4 * sony_buffer_sectors, GFP_KERNEL);
 				for (i = 0; i < sony_buffer_sectors; i++)
-					sony_buffer[i] = (unsigned char *)kmalloc(2048, GFP_KERNEL);
+					sony_buffer[i] = (Byte *)kmalloc(2048, GFP_KERNEL);
 #endif /* MODULE */
 				initialized = 1;
 			}
@@ -1500,8 +1632,9 @@
 		return -EIO;
 #endif
 	} else {
-		request_region(sony_cd_base_io, 4, CDU535_HANDLE);
+		request_region(sony535_cd_base_io, 4, CDU535_HANDLE);
 	}
+bail:
 #ifndef MODULE
 	return mem_start;
 #else
@@ -1511,7 +1644,7 @@
 
 #ifndef MODULE
 /*
- * accept "kernel command line" parameters 
+ * accept "kernel command line" parameters
  * (added by emoenke@gwdg.de)
  *
  * use: tell LILO:
@@ -1522,33 +1655,35 @@
 void
 sonycd535_setup(char *strings, int *ints)
 {
+	/* if IRQ change and default io base desired,
+	 * then call with io base of 0
+	 */
 	if (ints[0] > 0)
-		sony_cd_base_io = ints[1];
-#if 0	/* placeholder for future use */
+		if (ints[0] != 0)
+			sony535_cd_base_io = ints[1];
 	if (ints[0] > 1)
-		irq_used = ints[2];
-#endif
+		sony535_irq_used = ints[2];
 	if ((strings != NULL) && (*strings != '\0'))
-		printk("%s: Warning: Unknown interface type: %s\n",
-				strings, CDU535_MESSAGE_NAME);
+		printk(CDU535_MESSAGE_NAME
+				": Warning: Unknown interface type: %s\n", strings);
 }
 
 #else /* MODULE */
 
-void 
+void
 cleanup_module(void)
 {
 	int i;
 	if (MOD_IN_USE) {
-		printk("Sony 535 module in use, cannot remove\n");
+		printk(CDU535_HANDLE " module in use, cannot remove\n");
 		return;
 	}
-	release_region(sony_cd_base_io, 4);
-	kfree_s(sony_toc, sizeof (*sony_toc));
-	kfree_s(last_sony_subcode, sizeof (*last_sony_subcode));
+	release_region(sony535_cd_base_io, 4);
 	for (i = 0; i < sony_buffer_sectors; i++)
 		kfree_s(sony_buffer[i], 2048);
 	kfree_s(sony_buffer, 4 * sony_buffer_sectors);
+	kfree_s(last_sony_subcode, sizeof *last_sony_subcode);
+	kfree_s(sony_toc, sizeof *sony_toc);
 	if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL)
 		printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n");
 	else
diff -u --recursive --new-file v1.1.93/linux/drivers/char/ChangeLog linux/drivers/char/ChangeLog
--- v1.1.93/linux/drivers/char/ChangeLog	Thu Feb  9 10:18:50 1995
+++ linux/drivers/char/ChangeLog	Mon Feb 20 21:29:52 1995
@@ -1,3 +1,75 @@
+Sat Feb 18 12:13:51 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* tty_io.c (disassociate_ctty, tty_open, tty_ioctl): Clear
+		current->tty_old_pgrp field when a session leader
+		acquires a controlling tty, and after a session leader
+		has disassociated from a controlling tty.
+
+Fri Feb 17 09:34:09 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* serial.c (rs_interrupt_single, rs_interrupt, rs_interrupt_multi): 
+		Change the the number of passes made from 64 to be 256,
+		configurable with the #define RS_ISR_PASS_LIMIT.
+
+	* serial.c (rs_init, set_serial_info, get_serial_info, rs_close):
+		Remove support for closing_wait2.  Instead, set
+		tty->closing and rely on the line dispcline to prevent
+		echo wars.
+
+	* n_tty.c (n_tty_receive_char):  IEXTEN does not need to be
+		enabled in order for IXANY to be active.
+
+		If tty->closing is set, then only process XON and XOFF
+                characters.
+
+Sun Feb 12 23:57:48 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* serial.c (rs_timer): Change the interrupt poll time from 60
+		seconds to 10 seconds, configurable with the #define
+		RS_STROBE_TIME.
+
+	* serial.c (rs_interrupt_multi, startup, shutdown, rs_ioctl,
+		set_multiport_struct, get_multiport_struct): Add
+		provisions for a new type of interrutp service routine,
+		which better supports multiple serial ports on a single
+		IRQ.  
+
+Sun Feb  5 19:35:11 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* tty_ioctl.c (n_tty_ioctl, set_termios, tty_wait_until_sent): 
+	* serial.c (rs_ioctl, rs_close): 
+	* cyclades.c (cy_ioctl, cy_close): 
+	* n_tty.c (n_tty_close):  Rename wait_until_sent to
+		tty_wait_until_sent, so that it's a better name to export
+		in ksyms.c.
+
+Sat Feb  4 23:36:20 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* serial.c (rs_close): Added missing check for closing_wait2 being
+		ASYNC_CLOSING_WAIT_NONE.
+
+Thu Jan 26 09:02:49 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* serial.c (rs_init, set_serial_info, get_serial_info,
+		rs_close): Support close_wait in the serial driver.
+		This is helpful for slow devices (like serial
+		plotters) so that their outputs don't get flushed upon
+		device close.  This has to be configurable because
+		normally we don't want ports to be hung up for long
+		periods of time during a close when they are not
+		connected to a device, or the device is powered off.
+
+		The default is to wait 30 seconds; in the case of a
+		very slow device, the close_wait timeout should be
+		lengthed.  If it is set to 0, the kernel will wait
+		forever for all of the data to be transmitted.
+
+Thu Jan 17 01:17:20 1995  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* serial.c (startup, change_speed, rs_init): Add support to detect
+		the StarTech 16650 chip.  Treat it as a 16450 for now,
+		because of its FIFO bugs.
+
 Thu Jan  5 21:21:57 1995  <dhinds@allegro.stanford.edu>
 
 	* serial.c: (receive_char): Added counter to prevent infinite loop
diff -u --recursive --new-file v1.1.93/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- v1.1.93/linux/drivers/char/n_tty.c	Thu Feb  9 10:18:51 1995
+++ linux/drivers/char/n_tty.c	Mon Feb 20 21:29:52 1995
@@ -345,7 +345,7 @@
 		return;
 	}
 	
-	if (tty->stopped && I_IXON(tty) && I_IXANY(tty) && L_IEXTEN(tty)) {
+	if (tty->stopped && I_IXON(tty) && I_IXANY(tty)) {
 		start_tty(tty);
 		return;
 	}
@@ -355,6 +355,16 @@
 	if (I_IUCLC(tty) && L_IEXTEN(tty))
 		c=tolower(c);
 
+	if (tty->closing) {
+		if (I_IXON(tty)) {
+			if (c == START_CHAR(tty))
+				start_tty(tty);
+			else if (c == STOP_CHAR(tty))
+				stop_tty(tty);
+		}
+		return;
+	}
+
 	/*
 	 * If the previous character was LNEXT, or we know that this
 	 * character is not one of the characters that we'll have to
@@ -690,6 +700,7 @@
 	memset(tty->read_flags, 0, sizeof(tty->read_flags));
 	n_tty_set_termios(tty, 0);
 	tty->minimum_to_wake = 1;
+	tty->closing = 0;
 	return 0;
 }
 
diff -u --recursive --new-file v1.1.93/linux/drivers/char/selection.c linux/drivers/char/selection.c
--- v1.1.93/linux/drivers/char/selection.c	Fri Feb 17 11:20:12 1995
+++ linux/drivers/char/selection.c	Wed Feb 22 12:27:52 1995
@@ -3,10 +3,10 @@
  *
  * This module exports the functions:
  *
- *     'int set_selection(const int arg)'
+ *     'int set_selection(const unsigned long arg)'
  *     'void clear_selection(void)'
  *     'int paste_selection(struct tty_struct *tty)'
- *     'int sel_loadlut(const int arg)'
+ *     'int sel_loadlut(const unsigned long arg)'
  *
  * Now that /dev/vcs exists, most of this can disappear again.
  */
@@ -15,6 +15,9 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+
+#include <asm/segment.h>
+
 #include "vt_kern.h"
 #include "consolemap.h"
 #include "selection.h"
@@ -82,7 +85,7 @@
 }
 
 /* set inwordLut contents. Invoked by ioctl(). */
-int sel_loadlut(const int arg)
+int sel_loadlut(const unsigned long arg)
 {
 	int i = verify_area(VERIFY_READ, (char *) arg, 36);
 	if (i)
@@ -107,7 +110,7 @@
 }
 
 /* set the current selection. Invoked by ioctl(). */
-int set_selection(const int arg, struct tty_struct *tty)
+int set_selection(const unsigned long arg, struct tty_struct *tty)
 {
 	int sel_mode, new_sel_start, new_sel_end, spc;
 	char *bp, *obp;
diff -u --recursive --new-file v1.1.93/linux/drivers/char/selection.h linux/drivers/char/selection.h
--- v1.1.93/linux/drivers/char/selection.h	Fri Feb 17 11:20:13 1995
+++ linux/drivers/char/selection.h	Wed Feb 22 12:27:52 1995
@@ -6,9 +6,9 @@
 extern int sel_cons;
 
 extern void clear_selection(void);
-extern int set_selection(const int arg, struct tty_struct *tty);
+extern int set_selection(const unsigned long arg, struct tty_struct *tty);
 extern int paste_selection(struct tty_struct *tty);
-extern int sel_loadlut(const int arg);
+extern int sel_loadlut(const unsigned long arg);
 extern int mouse_reporting(void);
 extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
 
@@ -33,7 +33,9 @@
 
 /* how to access screen memory */
 #ifdef __alpha__
- 
+
+#include <asm/io.h> 
+
 static inline void scr_writew(unsigned short val, unsigned short * addr)
 {
 	if ((long) addr < 0)
diff -u --recursive --new-file v1.1.93/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v1.1.93/linux/drivers/char/serial.c	Thu Feb  9 10:18:51 1995
+++ linux/drivers/char/serial.c	Mon Feb 20 21:29:52 1995
@@ -67,12 +67,14 @@
 #define SERIAL_PARANOIA_CHECK
 #define CONFIG_SERIAL_NOPAUSE_IO
 #define SERIAL_DO_RESTART
-#define CONFIG_SERIAL_NEW_ISR
 
 #undef SERIAL_DEBUG_INTR
 #undef SERIAL_DEBUG_OPEN
 #undef SERIAL_DEBUG_FLOW
 
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
 #define _INLINE_ inline
   
 /*
@@ -81,6 +83,7 @@
  */
 
 static struct async_struct *IRQ_ports[16];
+static struct rs_multiport_struct rs_multiport[16];
 static int IRQ_timeout[16];
 static volatile int rs_irq_triggered;
 static volatile int rs_triggered;
@@ -420,9 +423,7 @@
 	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
 	    info->tty->hw_stopped) {
 		info->IER &= ~UART_IER_THRI;
-#ifdef CONFIG_SERIAL_NEW_ISR
 		serial_out(info, UART_IER, info->IER);
-#endif
 		return;
 	}
 	
@@ -445,9 +446,7 @@
 
 	if (info->xmit_cnt <= 0) {
 		info->IER &= ~UART_IER_THRI;
-#ifdef CONFIG_SERIAL_NEW_ISR
 		serial_out(info, UART_IER, info->IER);
-#endif
 	}
 }
 
@@ -480,9 +479,7 @@
 #endif
 				info->tty->hw_stopped = 0;
 				info->IER |= UART_IER_THRI;
-#ifdef CONFIG_SERIAL_NEW_ISR
 				serial_out(info, UART_IER, info->IER);
-#endif
 				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
 				return;
 			}
@@ -493,15 +490,12 @@
 #endif
 				info->tty->hw_stopped = 1;
 				info->IER &= ~UART_IER_THRI;
-#ifdef CONFIG_SERIAL_NEW_ISR
 				serial_out(info, UART_IER, info->IER);
-#endif
 			}
 		}
 	}
 }
 
-#ifdef CONFIG_SERIAL_NEW_ISR
 /*
  * This is the serial driver's generic interrupt routine
  */
@@ -511,6 +505,8 @@
 	struct async_struct * info;
 	int pass_counter = 0;
 	struct async_struct *end_mark = 0;
+	int first_multi = 0;
+	struct rs_multiport_struct *multi;
 
 #ifdef SERIAL_DEBUG_INTR
 	printk("rs_interrupt(%d)...", irq);
@@ -520,6 +516,10 @@
 	if (!info)
 		return;
 	
+	multi = &rs_multiport[irq];
+	if (multi->port_monitor)
+		first_multi = inb(multi->port_monitor);
+
 	do {
 		if (!info->tty ||
 		    (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
@@ -545,7 +545,7 @@
 		info = info->next_port;
 		if (!info) {
 			info = IRQ_ports[irq];
-			if (pass_counter++ > 64) {
+			if (pass_counter++ > RS_ISR_PASS_LIMIT) {
 #if 0
 				printk("rs loop break\n");
 #endif
@@ -554,6 +554,9 @@
 			continue;
 		}
 	} while (end_mark != info);
+	if (multi->port_monitor)
+		printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
+		       info->irq, first_multi, inb(multi->port_monitor));
 #ifdef SERIAL_DEBUG_INTR
 	printk("end.\n");
 #endif
@@ -566,7 +569,9 @@
 {
 	int status;
 	int pass_counter = 0;
+	int first_multi = 0;
 	struct async_struct * info;
+	struct rs_multiport_struct *multi;
 	
 #ifdef SERIAL_DEBUG_INTR
 	printk("rs_interrupt_single(%d)...", irq);
@@ -576,6 +581,10 @@
 	if (!info || !info->tty)
 		return;
 
+	multi = &rs_multiport[irq];
+	if (multi->port_monitor)
+		first_multi = inb(multi->port_monitor);
+
 	do {
 		status = serial_inp(info, UART_LSR) & info->read_status_mask;
 #ifdef SERIAL_DEBUG_INTR
@@ -586,7 +595,7 @@
 		check_modem_status(info);
 		if (status & UART_LSR_THRE)
 			transmit_chars(info, 0);
-		if (pass_counter++ > 64) {
+		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
 #if 0
 			printk("rs_single loop break.\n");
 #endif
@@ -594,102 +603,95 @@
 		}
 	} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
 	info->last_active = jiffies;
+	if (multi->port_monitor)
+		printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
+		       info->irq, first_multi, inb(multi->port_monitor));
 #ifdef SERIAL_DEBUG_INTR
 	printk("end.\n");
 #endif
 }
 
-#else /* CONFIG_SERIAL_NEW_ISR */
-
 /*
- * This is the serial driver's generic interrupt routine
+ * This is the serial driver's for multiport boards
  */
-static void rs_interrupt(int irq, struct pt_regs * regs)
+static void rs_interrupt_multi(int irq, struct pt_regs * regs)
 {
 	int status;
 	struct async_struct * info;
-	int done = 1, pass_counter = 0;
+	int pass_counter = 0;
+	int first_multi= 0;
+	struct rs_multiport_struct *multi;
 
-	
 #ifdef SERIAL_DEBUG_INTR
-	printk("rs_interrupt(%d)...", irq);
+	printk("rs_interrupt_multi(%d)...", irq);
 #endif
 	
 	info = IRQ_ports[irq];
 	if (!info)
 		return;
+	multi = &rs_multiport[irq];
+	if (!multi->port1) {
+		/* Should never happen */
+		printk("rs_interrupt_multi: NULL port1!\n");
+		return;
+	}
+	if (multi->port_monitor)
+		first_multi = inb(multi->port_monitor);
 	
 	while (1) {
-		if (!info->tty)
+		if (!info->tty ||
+		    (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
 			goto next;
 
-		serial_outp(info, UART_IER, 0);
+		info->last_active = jiffies;
+
 		status = serial_inp(info, UART_LSR) & info->read_status_mask;
-		if (status & UART_LSR_DR) {
+#ifdef SERIAL_DEBUG_INTR
+		printk("status = %x...", status);
+#endif
+		if (status & UART_LSR_DR)
 			receive_chars(info, &status);
-			done = 0;
-		}
 		check_modem_status(info);
 		if (status & UART_LSR_THRE)
-			transmit_chars(info, &done);
+			transmit_chars(info, 0);
 
 	next:
-		info = info->next_port;		
-		if (!info) {
-			info = IRQ_ports[irq];
-			if (done)
-				break;
-			done = 1;
-			if (pass_counter++ > 64) {
-#if 0
-				printk("rs loop break\n");
-#endif
-				break; 	/* Prevent infinite loops */
-			}
-		}
-	}
-
-	/*
-	 * Reset the IER registers; info is already set up from the
-	 * above while loop.
-	 */
-	do
-		serial_outp(info, UART_IER, info->IER);
-	while ((info = info->next_port) != NULL);
-}
-
-/*
- * This is the serial driver's interrupt routine for a single port
- */
-static void rs_interrupt_single(int irq, struct pt_regs * regs)
-{
-	int status;
-	struct async_struct * info;
+		info = info->next_port;
+		if (info)
+			continue;
 
-	
+		info = IRQ_ports[irq];
+		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+#if 1
+			printk("rs_multi loop break\n");
+#endif
+			break; 	/* Prevent infinite loops */
+		}
+		if (multi->port_monitor)
+			printk("rs port monitor irq %d: 0x%x, 0x%x\n",
+			       info->irq, first_multi,
+			       inb(multi->port_monitor));
+		if ((inb(multi->port1) & multi->mask1) != multi->match1)
+			continue;
+		if (!multi->port2)
+			break;
+		if ((inb(multi->port2) & multi->mask2) != multi->match2)
+			continue;
+		if (!multi->port3)
+			break;
+		if ((inb(multi->port3) & multi->mask3) != multi->match3)
+			continue;
+		if (!multi->port4)
+			break;
+		if ((inb(multi->port4) & multi->mask4) == multi->match4)
+			continue;
+		break;
+	} 
 #ifdef SERIAL_DEBUG_INTR
-	printk("rs_interrupt_single(%d)...", irq);
+	printk("end.\n");
 #endif
-	
-	info = IRQ_ports[irq];
-	if (!info || !info->tty)
-		return;
-
-	serial_outp(info, UART_IER, 0);
-	status = serial_inp(info, UART_LSR) & info->read_status_mask;
-	if (status & UART_LSR_DR)
-		receive_chars(info, &status);
-	check_modem_status(info);
-	if (status & UART_LSR_THRE)
-		transmit_chars(info, 0);
-
-	/*
-	 * Reset the IER register
-	 */
-	serial_outp(info, UART_IER, info->IER);
 }
 
-#endif /* CONFIG_SERIAL_NEW_ISR */
 
 /*
  * -------------------------------------------------------------------
@@ -747,7 +749,7 @@
 	struct async_struct *info;
 	unsigned int	i;
 
-	if ((jiffies - last_strobe) >= 60*HZ) {
+	if ((jiffies - last_strobe) >= RS_STROBE_TIME*HZ) {
 		for (i=1; i < 16; i++) {
 			info = IRQ_ports[i];
 			if (!info)
@@ -760,14 +762,17 @@
 					serial_out(info, UART_IER, info->IER);
 					info = info->next_port;
 				} while (info);
-				rs_interrupt(i, NULL);
+				if (rs_multiport[i].port1)
+					rs_interrupt_multi(i, NULL);
+				else
+					rs_interrupt(i, NULL);
 			} else
 				rs_interrupt_single(i, NULL);
 			sti();
 		}
 	}
 	last_strobe = jiffies;
-	timer_table[RS_TIMER].expires = jiffies + 60 * HZ;
+	timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME * HZ;
 	timer_active |= 1 << RS_TIMER;
 
 	if (IRQ_ports[0]) {
@@ -877,7 +882,11 @@
 	 * Clear the FIFO buffers and disable them
 	 * (they will be reenabled in change_speed())
 	 */
-	if (info->type == PORT_16550A) {
+	if (info->type == PORT_16650) {
+		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+					     UART_FCR_CLEAR_XMIT));
+		info->xmit_fifo_size = 1; /* disabled for now */
+	} else if (info->type == PORT_16550A) {
 		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
 					     UART_FCR_CLEAR_XMIT));
 		info->xmit_fifo_size = 16;
@@ -906,7 +915,10 @@
 			  !IRQ_ports[info->irq]->next_port)) {
 		if (IRQ_ports[info->irq]) {
 			free_irq(info->irq);
-			handler = rs_interrupt;
+			if (rs_multiport[info->irq].port1)
+				handler = rs_interrupt_multi;
+			else
+				handler = rs_interrupt;
 		} else 
 			handler = rs_interrupt_single;
 
@@ -1148,6 +1160,18 @@
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
 		else
 			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+	} else if (info->type == PORT_16650) {
+		/*
+		 * On the 16650, we disable the FIFOs altogether
+		 * because of a design bug in how the implement
+		 * things.  We could support it by completely changing
+		 * how we handle the interrupt driver, but not today....
+		 *
+		 * N.B.  Because there's no way to set a FIFO trigger
+		 * at 1 char, we'd probably disable at speed below
+		 * 2400 baud anyway...
+		 */
+		fcr = 0;
 	} else
 		fcr = 0;
 	
@@ -1404,6 +1428,7 @@
 	tmp.flags = info->flags;
 	tmp.baud_base = info->baud_base;
 	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
 	tmp.custom_divisor = info->custom_divisor;
 	tmp.hub6 = info->hub6;
 	memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
@@ -1471,6 +1496,7 @@
 	info->custom_divisor = new_serial.custom_divisor;
 	info->type = new_serial.type;
 	info->close_delay = new_serial.close_delay;
+	info->closing_wait = new_serial.closing_wait;
 
 	release_region(info->port,8);
 	if (change_port || change_irq) {
@@ -1676,6 +1702,101 @@
 	return wild_interrupts;
 }
 
+static int get_multiport_struct(struct async_struct * info,
+				struct serial_multiport_struct *retinfo)
+{
+	struct serial_multiport_struct ret;
+	struct rs_multiport_struct *multi;
+	
+	multi = &rs_multiport[info->irq];
+
+	ret.port_monitor = multi->port_monitor;
+	
+	ret.port1 = multi->port1;
+	ret.mask1 = multi->mask1;
+	ret.match1 = multi->match1;
+	
+	ret.port2 = multi->port2;
+	ret.mask2 = multi->mask2;
+	ret.match2 = multi->match2;
+	
+	ret.port3 = multi->port3;
+	ret.mask3 = multi->mask3;
+	ret.match3 = multi->match3;
+	
+	ret.port4 = multi->port4;
+	ret.mask4 = multi->mask4;
+	ret.match4 = multi->match4;
+
+	ret.irq = info->irq;
+
+	memcpy_tofs(retinfo,&ret,sizeof(*retinfo));
+	return 0;
+	
+}
+
+static int set_multiport_struct(struct async_struct * info,
+				struct serial_multiport_struct *in_multi)
+{
+	struct serial_multiport_struct new_multi;
+	struct rs_multiport_struct *multi;
+	int	was_multi, now_multi;
+	int	retval;
+	void (*handler)(int, struct pt_regs *);
+
+	if (!suser())
+		return -EPERM;
+	if (!in_multi)
+		return -EFAULT;
+	memcpy_fromfs(&new_multi, in_multi,
+		      sizeof(struct serial_multiport_struct));
+
+	if (new_multi.irq != info->irq || info->irq == 0 ||
+	    !IRQ_ports[info->irq])
+		return -EINVAL;
+
+	multi = &rs_multiport[info->irq];
+	was_multi = (multi->port1 != 0);
+	
+	multi->port_monitor = new_multi.port_monitor;
+	
+	multi->port1 = new_multi.port1;
+	multi->mask1 = new_multi.mask1;
+	multi->match1 = new_multi.match1;
+
+	multi->port2 = new_multi.port2;
+	multi->mask2 = new_multi.mask2;
+	multi->match2 = new_multi.match2;
+
+	multi->port3 = new_multi.port3;
+	multi->mask3 = new_multi.mask3;
+	multi->match3 = new_multi.match3;
+
+	multi->port4 = new_multi.port4;
+	multi->mask4 = new_multi.mask4;
+	multi->match4 = new_multi.match4;
+
+	now_multi = (multi->port1 != 0);
+	
+	if (IRQ_ports[info->irq]->next_port &&
+	    (was_multi != now_multi)) {
+		free_irq(info->irq);
+		if (now_multi)
+			handler = rs_interrupt_multi;
+		else
+			handler = rs_interrupt;
+
+		retval = request_irq(info->irq, handler, SA_INTERRUPT,
+				     "serial");
+		if (retval) {
+			printk("Couldn't reallocate serial interrupt "
+			       "driver!!\n");
+		}
+	}
+
+	return 0;
+}
+
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
@@ -1778,6 +1899,16 @@
 				    info, sizeof(struct async_struct));
 			return 0;
 			
+		case TIOCSERGETMULTI:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+				    sizeof(struct serial_multiport_struct));
+			if (error)
+				return error;
+			return get_multiport_struct(info,
+				       (struct serial_multiport_struct *) arg);
+		case TIOCSERSETMULTI:
+			return set_multiport_struct(info,
+				       (struct serial_multiport_struct *) arg);
 		default:
 			return -ENOIOCTLCMD;
 		}
@@ -1872,6 +2003,13 @@
 	if (info->flags & ASYNC_CALLOUT_ACTIVE)
 		info->callout_termios = *tty->termios;
 	/*
+	 * Now we wait for the trnasmit buffer to clear; and we notify 
+	 * the line discpline only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
 	 * At this point we stop accepting input.  To do this, we
 	 * disable the receive line status interrupts, and tell the
 	 * interrupt driver to stop checking the data ready bit in the
@@ -1881,7 +2019,6 @@
 	info->read_status_mask &= ~UART_LSR_DR;
 	if (info->flags & ASYNC_INITIALIZED) {
 		serial_out(info, UART_IER, info->IER);
-		tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
 		/*
 		 * Before we drop DTR, make sure the UART transmitter
 		 * has completely drained; this is especially
@@ -1901,6 +2038,7 @@
 		tty->driver.flush_buffer(tty);
 	if (tty->ldisc.flush_buffer)
 		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
 	info->event = 0;
 	info->tty = 0;
 	if (tty->ldisc.num != ldiscs[N_TTY].num) {
@@ -2155,7 +2293,7 @@
  */
 static void show_serial_version(void)
 {
-	printk("Serial driver version 4.00 with");
+	printk("Serial driver version 4.11 with");
 #ifdef CONFIG_HUB6
 	printk(" HUB-6");
 #define SERIAL_OPT
@@ -2329,6 +2467,10 @@
 	if (info->flags & ASYNC_AUTO_IRQ)
 		info->irq = do_auto_irq(info);
 		
+	scratch2 = serial_in(info, UART_LCR);
+	serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+	serial_outp(info, UART_EFR, 0);	/* EFR is the same as FCR */
+	serial_outp(info, UART_LCR, scratch2);
 	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 	scratch = serial_in(info, UART_IIR) >> 6;
 	info->xmit_fifo_size = 1;
@@ -2343,8 +2485,15 @@
 			info->type = PORT_16550;
 			break;
 		case 3:
-			info->type = PORT_16550A;
-			info->xmit_fifo_size = 16;
+			serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+			if (serial_in(info, UART_EFR) == 0) {
+				info->type = PORT_16650;
+				info->xmit_fifo_size = 32;
+			} else {
+				info->type = PORT_16550A;
+				info->xmit_fifo_size = 16;
+			}
+			serial_outp(info, UART_LCR, scratch2);
 			break;
 	}
 	if (info->type == PORT_16450) {
@@ -2398,6 +2547,7 @@
 	for (i = 0; i < 16; i++) {
 		IRQ_ports[i] = 0;
 		IRQ_timeout[i] = 0;
+		memset(&rs_multiport[i], 0, sizeof(struct rs_multiport_struct));
 	}
 	
 	show_serial_version();
@@ -2458,6 +2608,7 @@
 		info->type = PORT_UNKNOWN;
 		info->custom_divisor = 0;
 		info->close_delay = 50;
+		info->closing_wait = 3000;
 		info->x_char = 0;
 		info->event = 0;
 		info->count = 0;
@@ -2492,6 +2643,9 @@
 				break;
 			case PORT_16550A:
 				printk(" is a 16550A\n");
+				break;
+			case PORT_16650:
+				printk(" is a 16650\n");
 				break;
 			default:
 				printk("\n");
diff -u --recursive --new-file v1.1.93/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v1.1.93/linux/drivers/char/tty_io.c	Fri Feb 17 11:20:13 1995
+++ linux/drivers/char/tty_io.c	Mon Feb 20 21:29:52 1995
@@ -452,6 +452,7 @@
 		kill_pg(tty->pgrp, SIGCONT, priv);
 	}
 
+	current->tty_old_pgrp = 0;
 	tty->session = 0;
 	tty->pgrp = -1;
 
@@ -1165,6 +1166,7 @@
 	    !current->tty &&
 	    tty->session == 0) {
 		current->tty = tty;
+		current->tty_old_pgrp = 0;
 		tty->session = current->session;
 		tty->pgrp = current->pgrp;
 	}
@@ -1393,6 +1395,7 @@
 					return -EPERM;
 			}
 			current->tty = tty;
+			current->tty_old_pgrp = 0;
 			tty->session = current->session;
 			tty->pgrp = current->pgrp;
 			return 0;
diff -u --recursive --new-file v1.1.93/linux/drivers/net/README.wavelan linux/drivers/net/README.wavelan
--- v1.1.93/linux/drivers/net/README.wavelan	Sun Feb  5 19:31:52 1995
+++ linux/drivers/net/README.wavelan	Wed Feb 22 16:25:04 1995
@@ -1,13 +1,8 @@
 #if	defined(CONFIG_WAVELAN)
 
-Tue Jan 31 10:42:35 EST 1995
+Thu Feb 23 00:10:31 EST 1995
 
-0. This document refers to Version 5 of the Linux WaveLAN device driver software.
-   It has been tested successfully under the 1.1.87 release of the Linux
-   kernel.  It is `beta-test' software, so caveat emptor.  Please report bugs
-   to me so that I can fix them quickly.
-
-1. At present the driver only autoprobes for a WaveLAN card at I/O address 0x390.
+1. At present the driver autoprobes for a WaveLAN card only at I/O address 0x390.
    The version of the card that I use (NCR) supports four I/O addresses (selectable
    via a pair of DIP switches).  If you want the driver to autoprobe a different
    subset of the four valid addresses then you will need to edit
@@ -28,20 +23,7 @@
 	append	="ether=0,0x390,0x4321,eth0"
 	..
 
-3. The files that comprise this software must be incorporated into the Linux
-   kernel source tree (usually rooted at /usr/src/linux).  Following that a
-   "make clean; make config; make dep; make zImage" should produce a Linux
-   kernel incorporating the WaveLAN driver, ready for installation.
-   The files:
-   	drivers/net/wavelan.[ch]
-   	drivers/net/i82586.h
-   are unique to this package and simply may be moved into place.  The
-   others are modified versions of pre-existing files and must
-   be incorporated more carefully.  However, the regions of modified code
-   within these files are small and are bracketed by the preprocessor
-   symbol CONFIG_WAVELAN, so incorporation should be straightforward.
-
-4. If you encounter any problems send me some email.
+3. If you encounter any problems send me some email.
 
 Good luck,
 Bruce Janson (bruce@cs.usyd.edu.au)
diff -u --recursive --new-file v1.1.93/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v1.1.93/linux/drivers/net/wavelan.c	Wed Feb  1 09:23:06 1995
+++ linux/drivers/net/wavelan.c	Wed Feb 22 16:25:04 1995
@@ -21,6 +21,7 @@
 #include	<linux/ioport.h>
 #include	<linux/in.h>
 #include	<linux/string.h>
+#include	<linux/delay.h>
 #include	<asm/system.h>
 #include	<asm/bitops.h>
 #include	<asm/io.h>
@@ -70,7 +71,7 @@
 
 extern int		wavelan_probe(device *);	/* See Space.c */
 
-static char		*version	= "wavelan.c:v5 31/1/95\n";
+static char		*version	= "wavelan.c:v6 22/2/95\n";
 
 /*
  * Entry point forward declarations.
@@ -104,14 +105,6 @@
 static net_local	*first_wavelan	= (net_local *)0;
 
 static
-void
-busy_loop(int i)
-{
-	while (i-- > 0)
-		;
-}
-
-static
 unsigned long
 wavelan_splhi(void)
 {
@@ -150,7 +143,7 @@
 {
 	hacr_write(ioaddr, hacr);
 	/* delay might only be needed sometimes */
-	busy_loop(1000);
+	udelay(1000);
 }
 
 /*
@@ -444,11 +437,13 @@
 
 	set_chan_attn(ioaddr, lp->hacr);
 
-	for (i = 1000000; i > 0; i--)
+	for (i = 1000; i > 0; i--)
 	{
 		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
 		if (scb_cs == 0)
 			break;
+
+		udelay(1000);
 	}
 
 	if (i <= 0)
@@ -477,11 +472,13 @@
 
 	set_chan_attn(ioaddr, lp->hacr);
 
-	for (i = 64000; i > 0; i--)
+	for (i = 64; i > 0; i--)
 	{
 		obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
 		if (cb.ac_status & AC_SFLD_C)
 			break;
+
+		udelay(1000);
 	}
 
 	if (i <= 0 || !(cb.ac_status & AC_SFLD_OK))
@@ -557,23 +554,27 @@
 
 	set_chan_attn(ioaddr, lp->hacr);
 
-	for (i = 1000000; i > 0; i--)
+	for (i = 1000; i > 0; i--)
 	{
 		obram_read(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
 
 		if (iscp.iscp_busy == (unsigned short)0)
 			break;
+
+		udelay(1000);
 	}
 
 	if (i <= 0)
 		printk("%s: wavelan_hardware_reset(): iscp_busy timeout.\n", dev->name);
 
-	for (i = 15000; i > 0; i--)
+	for (i = 15; i > 0; i--)
 	{
 		obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
 
 		if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA))
 			break;
+
+		udelay(1000);
 	}
 
 	if (i <= 0)
@@ -970,11 +971,13 @@
 
 	set_chan_attn(ioaddr, lp->hacr);
 
-	for (i = 1000000; i > 0; i--)
+	for (i = 1000; i > 0; i--)
 	{
 		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
 		if (scb_cs == 0)
 			break;
+
+		udelay(1000);
 	}
 
 	if (i <= 0)
@@ -1049,11 +1052,13 @@
 
 	set_chan_attn(ioaddr, lp->hacr);
 
-	for (i = 1000000; i > 0; i--)
+	for (i = 1000; i > 0; i--)
 	{
 		obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
 		if (scb_cs == 0)
 			break;
+
+		udelay(1000);
 	}
 
 	if (i <= 0)
@@ -1849,6 +1854,7 @@
 wavelan_set_multicast_list(device *dev, int num_addrs, void *addrs)
 {
 	net_local	*lp;
+	unsigned long	x;
 
 	lp = (net_local *)dev->priv;
 
@@ -1859,7 +1865,9 @@
 		 * Promiscuous mode: receive all packets.
 		 */
 		lp->promiscuous = 1;
+		x = wavelan_splhi();
 		(void)wavelan_hardware_reset(dev);
+		wavelan_splx(x);
 		break;
 
 	case 0:
@@ -1868,7 +1876,9 @@
 		 * clear multicast list.
 		 */
 		lp->promiscuous = 0;
+		x = wavelan_splhi();
 		(void)wavelan_hardware_reset(dev);
+		wavelan_splx(x);
 		break;
 
 	default:
@@ -2319,9 +2329,9 @@
  *	Allan Creighton (allanc@cs.usyd.edu.au),
  *	Matthew Geier (matthew@cs.usyd.edu.au),
  *	Remo di Giovanni (remo@cs.usyd.edu.au),
+ *	Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de),
  *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
  *	Tim Nicholson (tim@cs.usyd.edu.au),
- *	Jeff Noxon (jeff@oylpatch.sccsi.com),
  *	Ian Parkin (ian@cs.usyd.edu.au),
  *	John Rosenberg (johnr@cs.usyd.edu.au),
  *	George Rossi (george@phm.gov.au),
diff -u --recursive --new-file v1.1.93/linux/fs/buffer.c linux/fs/buffer.c
--- v1.1.93/linux/fs/buffer.c	Thu Jan 26 07:49:07 1995
+++ linux/fs/buffer.c	Mon Feb 20 16:10:32 1995
@@ -1363,7 +1363,7 @@
 		if(priority > 3 && nlist == BUF_SHARED) continue;
 		bh = lru_list[nlist];
 		if(!bh) continue;
-		i = nr_buffers_type[nlist] >> priority;
+		i = 2*nr_buffers_type[nlist] >> priority;
 		for ( ; i-- > 0 ; bh = bh->b_next_free) {
 			/* We may have stalled while waiting for I/O to complete. */
 			if(bh->b_list != nlist) goto repeat1;
diff -u --recursive --new-file v1.1.93/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v1.1.93/linux/fs/isofs/dir.c	Thu Jan 26 07:49:07 1995
+++ linux/fs/isofs/dir.c	Wed Feb 22 08:15:14 1995
@@ -183,14 +183,17 @@
 		   is no Rock Ridge NM field. */
 		
 		else {
-		  /* Do not report hidden or associated files */
-		        high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
-		        if (de->flags[-high_sierra] & 5) {
-			  if (cpnt) {
-			    kfree(cpnt);
-			    cpnt = NULL;
-			  };
-			  continue;
+			if (inode->i_sb->u.isofs_sb.s_unhide=='n')
+                        {
+		  		/* Do not report hidden or associated files */
+		        	high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
+		        	if (de->flags[-high_sierra] & 5) {
+				  if (cpnt) {
+				    kfree(cpnt);
+				    cpnt = NULL;
+				  };
+				  continue;
+				}
 			}
 			dlen = de->name_len[0];
 			dpnt = de->name;
diff -u --recursive --new-file v1.1.93/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v1.1.93/linux/fs/isofs/inode.c	Thu Feb  9 10:18:53 1995
+++ linux/fs/isofs/inode.c	Wed Feb 22 08:15:14 1995
@@ -63,6 +63,7 @@
   char map;
   char rock;
   char cruft;
+  char unhide;
   unsigned char conversion;
   unsigned int blocksize;
   mode_t mode;
@@ -77,6 +78,7 @@
 	popt->map = 'n';
 	popt->rock = 'y';
 	popt->cruft = 'n';
+	popt->unhide = 'n';
 	popt->conversion = 'a';
 	popt->blocksize = 1024;
 	popt->mode = S_IRUGO;
@@ -88,6 +90,10 @@
 		  popt->rock = 'n';
 		  continue;
 		};
+	        if (strncmp(this_char,"unhide",6) == 0) {
+		  popt->unhide = 'y';
+		  continue;
+		};
 	        if (strncmp(this_char,"cruft",5) == 0) {
 		  popt->cruft = 'y';
 		  continue;
@@ -214,6 +220,7 @@
 	printk("map = %c\n", opt.map);
 	printk("rock = %c\n", opt.rock);
 	printk("cruft = %c\n", opt.cruft);
+	printk("unhide = %c\n", opt.unhide);
 	printk("conversion = %c\n", opt.conversion);
 	printk("blocksize = %d\n", opt.blocksize);
 	printk("gid = %d\n", opt.gid);
@@ -353,6 +360,7 @@
 	s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 1 : 0);
 	s->u.isofs_sb.s_conversion = opt.conversion;
 	s->u.isofs_sb.s_cruft = opt.cruft;
+	s->u.isofs_sb.s_unhide = opt.unhide;
 	s->u.isofs_sb.s_uid = opt.uid;
 	s->u.isofs_sb.s_gid = opt.gid;
 	/*
diff -u --recursive --new-file v1.1.93/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v1.1.93/linux/fs/isofs/namei.c	Thu Jan 26 07:49:07 1995
+++ linux/fs/isofs/namei.c	Wed Feb 22 08:15:14 1995
@@ -73,7 +73,6 @@
 	unsigned int old_offset;
 	unsigned int backlink;
 	int dlen, rrflag, match;
-	int high_sierra = 0;
 	char * dpnt;
 	struct iso_directory_record * de;
 	char c;
@@ -155,16 +154,6 @@
 			backlink = 0;
 		}
     
-		/* Do not report hidden or associated files */
-		high_sierra = dir->i_sb->u.isofs_sb.s_high_sierra;
-		if (de->flags[-high_sierra] & 5) {
-		  if (cpnt) {
-		    kfree(cpnt);
-		    cpnt = NULL;
-		  };
-		  continue;
-		}
-		
 		dlen = de->name_len[0];
 		dpnt = de->name;
 		/* Now convert the filename in the buffer to lower case */
diff -u --recursive --new-file v1.1.93/linux/fs/locks.c linux/fs/locks.c
--- v1.1.93/linux/fs/locks.c	Fri Feb 17 11:20:16 1995
+++ linux/fs/locks.c	Wed Feb 22 09:43:10 1995
@@ -7,7 +7,7 @@
  *  Deadlock Detection added by Kelly Carmichael, kelly@[142.24.8.65]
  *  September 17, 1994.
  *
- * FIXME: one thing isn't handled yet:
+ *  FIXME: one thing isn't handled yet:
  *	- mandatory locks (requires lots of changes elsewhere)
  *
  *  Edited by Kai Petzke, wpp@marie.physik.tu-berlin.de
@@ -22,7 +22,11 @@
  *  process. Since locks still depend on the process id, locks are inherited
  *  after an exec() but not after a fork(). This agrees with POSIX, and both
  *  BSD and SVR4 practice.
- *  Andy Walker (andy@keo.kvaerner.no), February 14, 1994
+ *  Andy Walker (andy@keo.kvaerner.no), February 14, 1995
+ *
+ *  Scrapped free list which is redundant now that we allocate locks
+ *  dynamically with kmalloc()/kfree().
+ *  Andy Walker (andy@keo.kvaerner.no), February 21, 1995
  *
  */
 
@@ -45,16 +49,11 @@
 static int lock_it(struct file *filp, struct file_lock *caller);
 static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl);
 static void free_lock(struct file_lock **fl);
-static void free_list_garbage_collect(void);
 #ifdef DEADLOCK_DETECTION
 int locks_deadlocked(int my_pid,int blocked_pid);
 #endif
 
-#define FREE_LIST_GARBAGE_COLLECT 20
-
 static struct file_lock *file_lock_table = NULL;
-static struct file_lock *file_lock_free_list = NULL;
-static int free_list_cnt = 0;
 
 int fcntl_getlk(unsigned int fd, struct flock *l)
 {
@@ -155,7 +154,8 @@
 				if (current->signal & ~current->blocked)
 					return -ERESTARTSYS;
 #ifdef DEADLOCK_DETECTION
-				if (locks_deadlocked(file_lock.fl_owner->pid,fl->fl_owner->pid)) return -EDEADLOCK;
+				if (locks_deadlocked(file_lock.fl_owner->pid,fl->fl_owner->pid))
+					return -EDEADLOCK;
 #endif
 				interruptible_sleep_on(&fl->fl_wait);
 				if (current->signal & ~current->blocked)
@@ -192,9 +192,11 @@
 		dlock_wait = fl->fl_wait;
 		do {
 			if (dlock_wait->task != NULL) {
-				if (dlock_wait->task->pid == blocked_pid) return -EDEADLOCK;
+				if (dlock_wait->task->pid == blocked_pid)
+					return -EDEADLOCK;
 				ret_val = locks_deadlocked(dlock_wait->task->pid,blocked_pid);
-				if (ret_val) return -EDEADLOCK;
+				if (ret_val)
+					return -EDEADLOCK;
 			}
 			dlock_wait = dlock_wait->next;
 		} while (dlock_wait != fl->fl_wait);
@@ -445,40 +447,26 @@
 
 /*
  * File_lock() inserts a lock at the position pos of the linked list.
- *
- *  Modified to create a new node if no free entries available - Chad Page
- *
  */
 static struct file_lock *alloc_lock(struct file_lock **pos,
 				    struct file_lock *fl)
 {
 	struct file_lock *tmp;
 
-	tmp = file_lock_free_list;
-
-	if (tmp == NULL)
-	{
-		/* Okay, let's make a new file_lock structure... */
-		tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock), GFP_KERNEL);
-		tmp -> fl_owner = NULL;
-		tmp -> fl_next = file_lock_free_list;
-		tmp -> fl_nextlink = file_lock_table;
-		file_lock_table = tmp;
-	}
-	else
-	{
-		/* remove from free list */
-		file_lock_free_list = tmp->fl_next;
-		free_list_cnt--;
-	}
-
-	if (tmp->fl_owner != NULL)
-		panic("alloc_lock: broken free list\n");
+	/* Okay, let's make a new file_lock structure... */
+	tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock), GFP_KERNEL);
+	if (!tmp)
+		return tmp;
+	tmp->fl_nextlink = file_lock_table;
+	tmp->fl_prevlink = NULL;
+	if (file_lock_table != NULL)
+		file_lock_table->fl_prevlink = tmp;
+	file_lock_table = tmp;
 
 	tmp->fl_next = *pos;	/* insert into file's list */
 	*pos = tmp;
 
-	tmp->fl_owner = current;	/* FIXME: needed? */
+	tmp->fl_owner = current;
 	tmp->fl_wait = NULL;
 
 	tmp->fl_type = fl->fl_type;
@@ -490,7 +478,7 @@
 }
 
 /*
- * Add a lock to the free list ...
+ * Free up a lock...
  */
 
 static void free_lock(struct file_lock **fl_p)
@@ -498,24 +486,19 @@
 	struct file_lock *fl;
 
 	fl = *fl_p;
-	if (fl->fl_owner == NULL)	/* sanity check */
-		panic("free_lock: broken lock list\n");
-
 	*fl_p = (*fl_p)->fl_next;
 
-	fl->fl_next = file_lock_free_list;	/* add to free list */
-	file_lock_free_list = fl;
-	fl->fl_owner = NULL;			/* for sanity checks */
-
-	free_list_cnt++;
-	if (free_list_cnt == FREE_LIST_GARBAGE_COLLECT)
-		free_list_garbage_collect();
+	if (fl->fl_nextlink != NULL)
+		fl->fl_nextlink->fl_prevlink = fl->fl_prevlink;
+
+	if (fl->fl_prevlink != NULL)
+		fl->fl_prevlink->fl_nextlink = fl->fl_nextlink;
+	else
+		file_lock_table = fl->fl_nextlink;
 
 	wake_up(&fl->fl_wait);
-}
 
-static void free_list_garbage_collect(void)
-{
-	/* Do nothing for now */
+	kfree(fl);
+
 	return;
 }
diff -u --recursive --new-file v1.1.93/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v1.1.93/linux/fs/proc/mem.c	Wed Feb  1 09:23:06 1995
+++ linux/fs/proc/mem.c	Mon Feb 20 21:29:53 1995
@@ -1,3 +1,4 @@
+#define THREE_LEVEL
 /*
  *  linux/fs/proc/mem.c
  *
@@ -25,7 +26,8 @@
 
 static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
 {
-	pgd_t *pgdir;
+	pgd_t *page_dir;
+	pmd_t *page_middle;
 	pte_t pte;
 	char * page;
 	struct task_struct * tsk;
@@ -50,15 +52,23 @@
 	while (count > 0) {
 		if (current->signal & ~current->blocked)
 			break;
-		pgdir = PAGE_DIR_OFFSET(tsk,addr);
-		if (pgd_none(*pgdir))
+		page_dir = pgd_offset(tsk,addr);
+		if (pgd_none(*page_dir))
 			break;
-		if (pgd_bad(*pgdir)) {
-			printk("Bad page dir entry %08lx\n", pgd_val(*pgdir));
-			pgd_clear(pgdir);
+		if (pgd_bad(*page_dir)) {
+			printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
+			pgd_clear(page_dir);
 			break;
 		}
-		pte = *(pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+		page_middle = pmd_offset(page_dir,addr);
+		if (pmd_none(*page_middle))
+			break;
+		if (pmd_bad(*page_middle)) {
+			printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
+			pmd_clear(page_middle);
+			break;
+		}
+		pte = *pte_offset(page_middle,addr);
 		if (!pte_present(pte))
 			break;
 		page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
@@ -78,8 +88,9 @@
 
 static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
 {
-	pgd_t * pgdir;
-	pte_t * pte;
+	pgd_t *page_dir;
+	pmd_t *page_middle;
+	pte_t pte;
 	char * page;
 	struct task_struct * tsk;
 	unsigned long addr, pid;
@@ -103,15 +114,23 @@
 	while (count > 0) {
 		if (current->signal & ~current->blocked)
 			break;
-		pgdir = PAGE_DIR_OFFSET(tsk,addr);
-		if (pgd_none(*pgdir))
+		page_dir = pgd_offset(tsk,addr);
+		if (pgd_none(*page_dir))
 			break;
-		if (pgd_bad(*pgdir)) {
-			printk("Bad page dir entry %08lx\n", pgd_val(*pgdir));
-			pgd_clear(pgdir);
+		if (pgd_bad(*page_dir)) {
+			printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
+			pgd_clear(page_dir);
 			break;
 		}
-		pte = *(pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+		page_middle = pmd_offset(page_dir,addr);
+		if (pmd_none(*page_middle))
+			break;
+		if (pmd_bad(*page_middle)) {
+			printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
+			pmd_clear(page_middle);
+			break;
+		}
+		pte = *pte_offset(page_middle,addr);
 		if (!pte_present(pte))
 			break;
 		if (!pte_write(pte))
@@ -157,6 +176,7 @@
 {
 	struct task_struct *tsk;
 	pgd_t *src_dir, *dest_dir;
+	pmd_t *src_middle, *dest_middle;
 	pte_t *src_table, *dest_table;
 	unsigned long stmp, dtmp;
 	struct vm_area_struct *src_vma = NULL;
@@ -168,7 +188,6 @@
 	for (i = 1 ; i < NR_TASKS ; i++)
 		if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
 			tsk = task[i];
-			src_vma = task[i]->mm->mmap;
 			break;
 		}
 
@@ -180,6 +199,7 @@
 	 moment because working out the vm_area_struct & nattach stuff isn't
 	 worth it. */
 
+	src_vma = tsk->mm->mmap;
 	stmp = vma->vm_offset;
 	while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
 		while (src_vma && stmp > src_vma->vm_end)
@@ -187,15 +207,21 @@
 		if (!src_vma || (src_vma->vm_flags & VM_SHM))
 			return -EINVAL;
 
-		src_dir = PAGE_DIR_OFFSET(tsk, stmp);
+		src_dir = pgd_offset(tsk, stmp);
 		if (pgd_none(*src_dir))
 			return -EINVAL;
 		if (pgd_bad(*src_dir)) {
 			printk("Bad source page dir entry %08lx\n", pgd_val(*src_dir));
 			return -EINVAL;
 		}
-
-		src_table = (pte_t *)(pgd_page(*src_dir) + PAGE_PTR(stmp));
+		src_middle = pmd_offset(src_dir, stmp);
+		if (pmd_none(*src_middle))
+			return -EINVAL;
+		if (pmd_bad(*src_middle)) {
+			printk("Bad source page middle entry %08lx\n", pmd_val(*src_middle));
+			return -EINVAL;
+		}
+		src_table = pte_offset(src_middle, stmp);
 		if (pte_none(*src_table))
 			return -EINVAL;
 
@@ -208,7 +234,7 @@
 		stmp += PAGE_SIZE;
 	}
 
-	src_vma = task[i]->mm->mmap;
+	src_vma = tsk->mm->mmap;
 	stmp    = vma->vm_offset;
 	dtmp    = vma->vm_start;
 
@@ -216,28 +242,17 @@
 		while (src_vma && stmp > src_vma->vm_end)
 			src_vma = src_vma->vm_next;
 
-		src_dir = PAGE_DIR_OFFSET(tsk, stmp);
-		src_table = (pte_t *) (pgd_page(*src_dir) + PAGE_PTR(stmp));
-
-		dest_dir = PAGE_DIR_OFFSET(current, dtmp);
-
-		if (pgd_none(*dest_dir)) {
-			unsigned long page = get_free_page(GFP_KERNEL);
-			if (!page)
-				return -ENOMEM;
-			if (pgd_none(*dest_dir)) {
-				pgd_set(dest_dir, (pte_t *) page);
-			} else {
-				free_page(page);
-			}
-		}
-
-		if (pgd_bad(*dest_dir)) {
-			printk("Bad dest directory entry %08lx\n", pgd_val(*dest_dir));
-			return -EINVAL;
-		}
-
-		dest_table = (pte_t *) (pgd_page(*dest_dir) + PAGE_PTR(dtmp));
+		src_dir = pgd_offset(tsk, stmp);
+		src_middle = pmd_offset(src_dir, stmp);
+		src_table = pte_offset(src_middle, stmp);
+
+		dest_dir = pgd_offset(current, dtmp);
+		dest_middle = pmd_alloc(dest_dir, dtmp);
+		if (!dest_middle)
+			return -ENOMEM;
+		dest_table = pte_alloc(dest_middle, dtmp);
+		if (!dest_table)
+			return -ENOMEM;
 
 		if (!pte_present(*src_table))
 			do_no_page(src_vma, stmp, 1);
diff -u --recursive --new-file v1.1.93/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h
--- v1.1.93/linux/include/asm-alpha/byteorder.h	Wed Jan 11 21:14:29 1995
+++ linux/include/asm-alpha/byteorder.h	Tue Feb 21 09:05:02 1995
@@ -32,14 +32,11 @@
 		((x & 0xff000000U) >> 24));
 }
 
-extern __inline__ unsigned long int
-__constant_ntohl(unsigned long int x)
-{
-	return (((x & 0x000000ffU) << 24) |
-		((x & 0x0000ff00U) <<  8) |
-		((x & 0x00ff0000U) >>  8) |
-		((x & 0xff000000U) >> 24));
-}
+#define __constant_ntohl(x) \
+((unsigned int)((((unsigned int)(x) & 0x000000ffU) << 24) | \
+		(((unsigned int)(x) & 0x0000ff00U) <<  8) | \
+		(((unsigned int)(x) & 0x00ff0000U) >>  8) | \
+		(((unsigned int)(x) & 0xff000000U) >> 24)))
 
 extern __inline__ unsigned short int
 __ntohs(unsigned short int x)
@@ -48,12 +45,9 @@
 		((x & 0xff00) >> 8));
 }
 
-extern __inline__ unsigned short int
-__constant_ntohs(unsigned short int x)
-{
-	return (((x & 0x00ff) << 8) |
-		((x & 0xff00) >> 8));
-}
+#define __constant_ntohs(x) \
+((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
+		      (((unsigned short int)(x) & 0xff00) >> 8)))
 
 #define __htonl(x) __ntohl(x)
 #define __htons(x) __ntohs(x)
diff -u --recursive --new-file v1.1.93/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v1.1.93/linux/include/asm-alpha/pgtable.h	Wed Feb 15 10:36:39 1995
+++ linux/include/asm-alpha/pgtable.h	Wed Feb 22 12:27:52 1995
@@ -160,18 +160,33 @@
 extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_VALID; }
 extern inline int pte_inuse(pte_t *ptep)	{ return mem_map[MAP_NR(ptep)] > 1; }
 extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
+extern inline void pte_reuse(pte_t * ptep)
+{
+	if (!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
+		mem_map[MAP_NR(ptep)]++;
+}
 
 extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
 extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE || pmd_page(pmd) > high_memory; }
 extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_VALID; }
 extern inline int pmd_inuse(pmd_t *pmdp)	{ return mem_map[MAP_NR(pmdp)] > 1; }
 extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
+extern inline void pmd_reuse(pmd_t * pmdp)
+{
+	if (!(mem_map[MAP_NR(pmdp)] & MAP_PAGE_RESERVED))
+		mem_map[MAP_NR(pmdp)]++;
+}
 
 extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
 extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE || pgd_page(pgd) > high_memory; }
 extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_VALID; }
 extern inline int pgd_inuse(pgd_t *pgdp)	{ return mem_map[MAP_NR(pgdp)] > 1; }
 extern inline void pgd_clear(pgd_t * pgdp)	{ pgd_val(*pgdp) = 0; }
+extern inline void pgd_reuse(pgd_t * pgdp)
+{
+	if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
+		mem_map[MAP_NR(pgdp)]++;
+}
 
 /*
  * The following only work if pte_present() is true.
diff -u --recursive --new-file v1.1.93/linux/include/asm-i386/byteorder.h linux/include/asm-i386/byteorder.h
--- v1.1.93/linux/include/asm-i386/byteorder.h	Mon Jan  9 07:22:09 1995
+++ linux/include/asm-i386/byteorder.h	Tue Feb 21 09:02:02 1995
@@ -27,14 +27,11 @@
 	return x;
 }
 
-extern __inline__ unsigned long int
-__constant_ntohl(unsigned long int x)
-{
-	return (((x & 0x000000ffU) << 24) |
-		((x & 0x0000ff00U) <<  8) |
-		((x & 0x00ff0000U) >>  8) |
-		((x & 0xff000000U) >> 24));
-}
+#define __constant_ntohl(x) \
+	((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
+			     (((unsigned long int)(x) & 0x0000ff00U) <<  8) | \
+			     (((unsigned long int)(x) & 0x00ff0000U) >>  8) | \
+			     (((unsigned long int)(x) & 0xff000000U) >> 24)))
 
 extern __inline__ unsigned short int
 __ntohs(unsigned short int x)
@@ -45,12 +42,9 @@
 	return x;
 }
 
-extern __inline__ unsigned short int
-__constant_ntohs(unsigned short int x)
-{
-	return (((x & 0x00ff) << 8) |
-		((x & 0xff00) >> 8));
-}
+#define __constant_ntohs(x) \
+	((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
+			      (((unsigned short int)(x) & 0xff00) >> 8))) \
 
 #define __htonl(x) __ntohl(x)
 #define __htons(x) __ntohs(x)
diff -u --recursive --new-file v1.1.93/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v1.1.93/linux/include/asm-sparc/system.h	Mon Feb 20 21:34:56 1995
+++ linux/include/asm-sparc/system.h	Wed Feb 22 08:47:40 1995
@@ -1,6 +1,8 @@
 #ifndef __SPARC_SYSTEM_H
 #define __SPARC_SYSTEM_H
 
+#include <asm/segment.h>
+
 /*
  * System defines.. Note that this is included both from .c and .S
  * files, so it does only defines, not any C code.
diff -u --recursive --new-file v1.1.93/linux/include/asm-sparc/vac-ops.h linux/include/asm-sparc/vac-ops.h
--- v1.1.93/linux/include/asm-sparc/vac-ops.h	Thu Jan 26 07:49:15 1995
+++ linux/include/asm-sparc/vac-ops.h	Wed Feb 22 08:47:40 1995
@@ -7,8 +7,8 @@
    Copyright (C) 1994, David S. Miller (davem@caip.rutgers.edu)
 */
 
-extern unsigned int trapbase[];
-extern unsigned int end[], etext[], msgbuf[];
+extern unsigned long *trapbase;
+extern char end, etext, msgbuf;
 
 extern void flush_vac_context(void);
 extern void flush_vac_segment(unsigned int foo_segment);
diff -u --recursive --new-file v1.1.93/linux/include/linux/fs.h linux/include/linux/fs.h
--- v1.1.93/linux/include/linux/fs.h	Fri Feb 17 11:20:16 1995
+++ linux/include/linux/fs.h	Wed Feb 22 09:31:32 1995
@@ -266,8 +266,9 @@
 };
 
 struct file_lock {
-	struct file_lock *fl_next;	/* singly linked list */
-	struct file_lock *fl_nextlink;
+	struct file_lock *fl_next;	/* singly linked list for this inode (or the free list) */
+	struct file_lock *fl_nextlink;	/* doubly linked list of all locks */
+	struct file_lock *fl_prevlink;	/* used to simplify garbage collecting */
 	struct task_struct *fl_owner;	/* NULL if on free list, for sanity checks */
 	struct wait_queue *fl_wait;
 	char fl_type;
diff -u --recursive --new-file v1.1.93/linux/include/linux/iso_fs_sb.h linux/include/linux/iso_fs_sb.h
--- v1.1.93/linux/include/linux/iso_fs_sb.h	Mon Jan  9 07:22:10 1995
+++ linux/include/linux/iso_fs_sb.h	Wed Feb 22 08:15:14 1995
@@ -18,6 +18,7 @@
 			unsigned char s_cruft; /* Broken disks with high
 						  byte of length containing
 						  junk */
+			unsigned char s_unhide;
 			unsigned char s_nosuid;
 			unsigned char s_nodev;
 			mode_t s_mode;
diff -u --recursive --new-file v1.1.93/linux/include/linux/sched.h linux/include/linux/sched.h
--- v1.1.93/linux/include/linux/sched.h	Wed Feb 15 10:36:40 1995
+++ linux/include/linux/sched.h	Wed Feb 22 12:27:52 1995
@@ -268,11 +268,12 @@
 	unsigned long flags, const char *device);
 extern void free_irq(unsigned int irq);
 
-extern unsigned long copy_thread(int, unsigned long, struct task_struct *, struct pt_regs *);
+extern void copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
 extern void flush_thread(void);
 extern void exit_thread(void);
 
 extern int do_execve(char *, char **, char **, struct pt_regs *);
+extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
 asmlinkage int do_signal(unsigned long, struct pt_regs *);
 
 /*
diff -u --recursive --new-file v1.1.93/linux/include/linux/serial.h linux/include/linux/serial.h
--- v1.1.93/linux/include/linux/serial.h	Thu Feb  9 10:18:53 1995
+++ linux/include/linux/serial.h	Mon Feb 20 21:29:53 1995
@@ -22,10 +22,19 @@
 	unsigned short	close_delay;
 	char	reserved_char[2];
 	int	hub6;
-	int	reserved[5];
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	int	reserved[4];
 };
 
 /*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define ASYNC_CLOSING_WAIT_INF	0
+#define ASYNC_CLOSING_WAIT_NONE	65535
+
+/*
  * These are the supported serial types.
  */
 #define PORT_UNKNOWN	0
@@ -34,7 +43,8 @@
 #define PORT_16550	3
 #define PORT_16550A	4
 #define PORT_CIRRUS     5
-#define PORT_MAX	5
+#define PORT_16650	6
+#define PORT_MAX	6
 
 /*
  * Definitions for async_struct (and serial_struct) flags field
@@ -70,6 +80,23 @@
 #define ASYNC_CTS_FLOW		0x04000000 /* Do CTS flow control */
 #define ASYNC_CHECK_CD		0x02000000 /* i.e., CLOCAL */
 
+/*
+ * Multiport serial configuration structure --- external structure
+ */
+struct serial_multiport_struct {
+	int		irq;
+	int		port1;
+	unsigned char	mask1, match1;
+	int		port2;
+	unsigned char	mask2, match2;
+	int		port3;
+	unsigned char	mask3, match3;
+	int		port4;
+	unsigned char	mask4, match4;
+	int		port_monitor;
+	int	reserved[32];
+};
+
 #ifdef __KERNEL__
 /*
  * This is our internal structure for each serial port's state.
@@ -96,6 +123,8 @@
 	int			custom_divisor;
 	int			x_char;	/* xon/xoff character */
 	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
 	int			IER; 	/* Interrupt Enable Register */
 	int			MCR; 	/* Modem control register */
 	int			MCR_noint; /* MCR with interrupts off */
@@ -132,6 +161,21 @@
  */
 #define RS_EVENT_WRITE_WAKEUP	0
 #define RS_EVENT_HANGUP		1
+
+/*
+ * Multiport serial configuration structure --- internal structure
+ */
+struct rs_multiport_struct {
+	int		port1;
+	unsigned char	mask1, match1;
+	int		port2;
+	unsigned char	mask2, match2;
+	int		port3;
+	unsigned char	mask3, match3;
+	int		port4;
+	unsigned char	mask4, match4;
+	int		port_monitor;
+};
 
 /* Export to allow PCMCIA to use this - Dave Hinds */
 extern int register_serial(struct serial_struct *req);
diff -u --recursive --new-file v1.1.93/linux/include/linux/serial_reg.h linux/include/linux/serial_reg.h
--- v1.1.93/linux/include/linux/serial_reg.h	Thu Feb  9 10:18:53 1995
+++ linux/include/linux/serial_reg.h	Mon Feb 20 21:29:53 1995
@@ -21,6 +21,8 @@
 #define UART_IER	1	/* Out: Interrupt Enable Register */
 #define UART_IIR	2	/* In:  Interrupt ID Register */
 #define UART_FCR	2	/* Out: FIFO Control Register */
+#define UART_EFR	2	/* I/O: Extended Features Register */
+				/* (DLAB=1, 16C660 only) */
 #define UART_LCR	3	/* Out: Line Control Register */
 #define UART_MCR	4	/* Out: Modem Control Register */
 #define UART_LSR	5	/* In:  Line Status Register */
@@ -29,6 +31,7 @@
 
 /*
  * These are the definitions for the FIFO Control Register
+ * (16650 only)
  */
 #define UART_FCR_ENABLE_FIFO	0x01 /* Enable the FIFO */
 #define UART_FCR_CLEAR_RCVR	0x02 /* Clear the RCVR FIFO */
@@ -39,6 +42,15 @@
 #define UART_FCR_TRIGGER_4	0x40 /* Mask for trigger set at 4 */
 #define UART_FCR_TRIGGER_8	0x80 /* Mask for trigger set at 8 */
 #define UART_FCR_TRIGGER_14	0xC0 /* Mask for trigger set at 14 */
+/* 16650 redefinitions */
+#define UART_FCR6_R_TRIGGER_8	0x00 /* Mask for receive trigger set at 1 */
+#define UART_FCR6_R_TRIGGER_16	0x40 /* Mask for receive trigger set at 4 */
+#define UART_FCR6_R_TRIGGER_24  0x80 /* Mask for receive trigger set at 8 */
+#define UART_FCR6_R_TRIGGER_28	0xC0 /* Mask for receive trigger set at 14 */
+#define UART_FCR6_T_TRIGGER_16	0x00 /* Mask for transmit trigger set at 16 */
+#define UART_FCR6_T_TRIGGER_8	0x10 /* Mask for transmit trigger set at 8 */
+#define UART_FCR6_T_TRIGGER_24  0x20 /* Mask for transmit trigger set at 24 */
+#define UART_FCR6_T_TRIGGER_30	0x30 /* Mask for transmit trigger set at 30 */
 
 /*
  * These are the definitions for the Line Control Register
@@ -108,6 +120,18 @@
 #define UART_MSR_DDSR	0x02	/* Delta DSR */
 #define UART_MSR_DCTS	0x01	/* Delta CTS */
 #define UART_MSR_ANY_DELTA 0x0F	/* Any of the delta bits! */
+
+/*
+ * These are the definitions for the Extended Features Register
+ * (StarTech 16C660 only, when DLAB=1)
+ */
+#define UART_EFR_CTS	0x80	/* CTS flow control */
+#define UART_EFR_RTS	0x40	/* RTS flow control */
+#define UART_EFR_SCD	0x20	/* Special character detect */
+#define UART_EFR_ENI	0x10	/* Enhanced Interrupt */
+/*
+ * the low four bits control software flow control
+ */
 
 #endif /* _LINUX_SERIAL_REG_H */
 
diff -u --recursive --new-file v1.1.93/linux/include/linux/sys.h linux/include/linux/sys.h
--- v1.1.93/linux/include/linux/sys.h	Mon Apr 18 11:38:20 1994
+++ linux/include/linux/sys.h	Wed Feb 22 12:27:52 1995
@@ -7,11 +7,6 @@
 #define NR_syscalls 256
 
 /*
- * These are system calls with the same entry-point
- */
-#define _sys_clone _sys_fork
-
-/*
  * These are system calls that will be removed at some time
  * due to newer versions existing..
  * (please be careful - ibcs2 may need some of these).
diff -u --recursive --new-file v1.1.93/linux/include/linux/termios.h linux/include/linux/termios.h
--- v1.1.93/linux/include/linux/termios.h	Tue Nov 29 18:58:28 1994
+++ linux/include/linux/termios.h	Mon Feb 20 21:29:53 1995
@@ -54,6 +54,8 @@
 #define TIOCSLCKTRMIOS	0x5457
 #define TIOCSERGSTRUCT	0x5458 /* For debugging only */
 #define TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
@@ -193,6 +195,7 @@
 #define CBAUDEX 0010000
 #define  B57600  0010001
 #define  B115200 0010002
+#define  B230400 0010003
 #define CIBAUD	  002003600000	/* input baud rate (not used) */
 #define CRTSCTS	  020000000000		/* flow control */
 
diff -u --recursive --new-file v1.1.93/linux/include/linux/tty.h linux/include/linux/tty.h
--- v1.1.93/linux/include/linux/tty.h	Fri Feb 17 11:20:16 1995
+++ linux/include/linux/tty.h	Mon Feb 20 21:29:52 1995
@@ -222,6 +222,7 @@
 	 */
 	unsigned int column;
 	unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
+	unsigned char closing:1;
 	unsigned short minimum_to_wake;
 	unsigned overrun_time;
 	int num_overrun;
diff -u --recursive --new-file v1.1.93/linux/ipc/shm.c linux/ipc/shm.c
--- v1.1.93/linux/ipc/shm.c	Wed Feb  1 09:23:08 1995
+++ linux/ipc/shm.c	Mon Feb 20 21:32:18 1995
@@ -1,3 +1,4 @@
+#define THREE_LEVEL
 /*
  * linux/ipc/shm.c
  * Copyright (C) 1992, 1993 Krishna Balasubramanian
@@ -20,7 +21,7 @@
 extern unsigned int get_swap_page (void);
 static int findkey (key_t key);
 static int newseg (key_t key, int shmflg, int size);
-static int shm_map (struct vm_area_struct *shmd, int remap);
+static int shm_map (struct vm_area_struct *shmd);
 static void killseg (int id);
 static void shm_open (struct vm_area_struct *shmd);
 static void shm_close (struct vm_area_struct *shmd);
@@ -411,34 +412,16 @@
 }
 
 /*
- * check range is unmapped, ensure page tables exist
+ * ensure page tables exist
  * mark page table entries with shm_sgn.
- * if remap != 0 the range is remapped.
  */
-static int shm_map (struct vm_area_struct *shmd, int remap)
+static int shm_map (struct vm_area_struct *shmd)
 {
 	pgd_t *page_dir;
+	pmd_t *page_middle;
 	pte_t *page_table;
 	unsigned long tmp, shm_sgn;
-
-	/* check that the range is unmapped */
-	if (!remap)
-		for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE) {
-			page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
-			if (pgd_none(*page_dir))
-				continue;
-			if (pgd_bad(*page_dir)) {
-				printk("bad ipc page directory entry %08lx\n", pgd_val(*page_dir));
-				pgd_clear(page_dir);
-				continue;
-			}
-			page_table = (pte_t *) pgd_page(*page_dir);	
-			page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
-			if (!pte_none(*page_table)) {
-				/* printk("shmat() -> EINVAL because address 0x%lx is already mapped.\n",tmp); */
-				return -EINVAL;
-			}
-		}
+	int error;
 
 	/* clear old mappings */
 	do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
@@ -447,35 +430,17 @@
 	insert_vm_struct(current, shmd);
 	merge_segments(current, shmd->vm_start, shmd->vm_end);
 
-	/* check that the range has page_tables */
-	for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE) {
-		page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
-		if (!pgd_none(*page_dir)) {
-			page_table = (pte_t *) pgd_page(*page_dir);
-			page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
-			if (!pte_none(*page_table)) {
-				if (pte_present(*page_table)) {
-					--current->mm->rss;
-					free_page (pte_page(*page_table));
-				} else
-					swap_free(pte_val(*page_table));
-				pte_clear(page_table);
-			}
-		} else {
-			if (!(page_table = (pte_t *) get_free_page(GFP_KERNEL)))
-				return -ENOMEM;
-			pgd_set(page_dir, page_table);
-			tmp |= (PGDIR_SIZE - PAGE_SIZE);
-		}
-	}
-
 	/* map page range */
 	shm_sgn = shmd->vm_pte + ((shmd->vm_offset >> PAGE_SHIFT) << SHM_IDX_SHIFT);
 	for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE,
 	     shm_sgn += (1 << SHM_IDX_SHIFT)) {
-		page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
-		page_table = (pte_t *) pgd_page(*page_dir);
-		page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
+		page_dir = pgd_offset(shmd->vm_task,tmp);
+		page_middle = pmd_alloc(page_dir,tmp);
+		if (!page_middle)
+			break;
+		page_table = pte_alloc(page_middle,tmp);
+		if (!page_table)
+			break;
 		pte_val(*page_table) = shm_sgn;
 	}
 	invalidate();
@@ -553,7 +518,7 @@
 	shmd->vm_ops = &shm_vm_ops;
 
 	shp->shm_nattch++;            /* prevent destruction */
-	if ((err = shm_map (shmd, shmflg & SHM_REMAP))) {
+	if ((err = shm_map (shmd))) {
 		if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
 			killseg(id);
 		kfree(shmd);
@@ -749,6 +714,7 @@
 	  for (shmd = shp->attaches; ; ) {
 	    do {
 		pgd_t *page_dir;
+		pmd_t *page_middle;
 		pte_t *page_table, pte;
 		unsigned long tmp;
 
@@ -759,15 +725,21 @@
 		tmp = shmd->vm_start + (idx << PAGE_SHIFT) - shmd->vm_offset;
 		if (!(tmp >= shmd->vm_start && tmp < shmd->vm_end))
 			continue;
-		page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
+		page_dir = pgd_offset(shmd->vm_task,tmp);
 		if (pgd_none(*page_dir) || pgd_bad(*page_dir)) {
 			printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n",
 					id, shmd->vm_start, idx);
 			pgd_clear(page_dir);
 			continue;
 		}
-		page_table = (pte_t *) pgd_page(*page_dir);
-		page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
+		page_middle = pmd_offset(page_dir,tmp);
+		if (pmd_none(*page_middle) || pmd_bad(*page_middle)) {
+			printk("shm_swap: bad pgmid! id=%ld start=%lx idx=%ld\n",
+					id, shmd->vm_start, idx);
+			pmd_clear(page_middle);
+			continue;
+		}
+		page_table = pte_offset(page_middle,tmp);
 		pte = *page_table;
 		if (!pte_present(pte))
 			continue;
@@ -779,7 +751,8 @@
 			printk("shm_swap_out: page and pte mismatch\n");
 		pte_val(*page_table) = shmd->vm_pte | idx << SHM_IDX_SHIFT;
 		mem_map[MAP_NR(pte_page(pte))]--;
-		shmd->vm_task->mm->rss--;
+		if (shmd->vm_task->mm->rss > 0)
+			shmd->vm_task->mm->rss--;
 		invalid++;
 	    /* continue looping through circular list */
 	    } while (0);
diff -u --recursive --new-file v1.1.93/linux/kernel/fork.c linux/kernel/fork.c
--- v1.1.93/linux/kernel/fork.c	Mon Jan 30 06:41:59 1995
+++ linux/kernel/fork.c	Wed Feb 22 12:27:52 1995
@@ -163,12 +163,11 @@
  * information (task[nr]) and sets up the necessary registers. It
  * also copies the data segment in its entirety.
  */
-asmlinkage int sys_fork(struct pt_regs regs)
+int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
 {
 	int nr;
-	struct task_struct *p;
 	unsigned long new_stack;
-	unsigned long clone_flags = COPYVM | SIGCHLD;
+	struct task_struct *p;
 
 	if(!(p = (struct task_struct*)__get_free_page(GFP_KERNEL)))
 		goto bad_fork;
@@ -206,7 +205,7 @@
 	task[nr] = p;
 
 	/* copy all the process information */
-	clone_flags = copy_thread(nr, COPYVM | SIGCHLD, p, &regs);
+	copy_thread(nr, clone_flags, usp, p, regs);
 	if (copy_mm(clone_flags, p))
 		goto bad_fork_cleanup;
 	p->semundo = NULL;
diff -u --recursive --new-file v1.1.93/linux/kernel/sys.c linux/kernel/sys.c
--- v1.1.93/linux/kernel/sys.c	Mon Jan 30 06:41:59 1995
+++ linux/kernel/sys.c	Mon Feb 20 21:29:53 1995
@@ -517,6 +517,7 @@
 	current->leader = 1;
 	current->session = current->pgrp = current->pid;
 	current->tty = NULL;
+	current->tty_old_pgrp = 0;
 	return current->pgrp;
 }
 
diff -u --recursive --new-file v1.1.93/linux/mm/swap.c linux/mm/swap.c
--- v1.1.93/linux/mm/swap.c	Mon Feb 20 21:34:56 1995
+++ linux/mm/swap.c	Mon Feb 20 16:10:32 1995
@@ -506,11 +506,10 @@
 static int swap_out(unsigned int priority)
 {
 	static int swap_task;
-	int loop;
-	int counter = NR_TASKS * 2 >> priority;
+	int loop, counter;
 	struct task_struct *p;
 
-	counter = NR_TASKS * 2 >> priority;
+	counter = 2*NR_TASKS >> priority;
 	for(; counter >= 0; counter--, swap_task++) {
 		/*
 		 * Check that swap_task is suitable for swapping.  If not, look for
@@ -557,6 +556,15 @@
 	return 0;
 }
 
+/*
+ * we keep on shrinking one resource until it's considered "too hard",
+ * and then switch to the next one (priority being an indication on how
+ * hard we should try with the resource).
+ *
+ * This should automatically find the resource that can most easily be
+ * free'd, so hopefully we'll get reasonable behaviour even under very
+ * different circumstances.
+ */
 static int try_to_free_page(int priority)
 {
 	static int state = 0;
@@ -565,23 +573,19 @@
 	switch (state) {
 		do {
 		case 0:
-			if (priority != GFP_NOBUFFER && shrink_buffers(i)) {
-				state = 1;
+			if (priority != GFP_NOBUFFER && shrink_buffers(i))
 				return 1;
-			}
+			state = 1;
 		case 1:
-			if (shm_swap(i)) {
-				state = 2;
+			if (shm_swap(i))
 				return 1;
-			}
-		case 2:
-			if (swap_out(i)) {
-				state = 0;
+			state = 2;
+		default:
+			if (swap_out(i))
 				return 1;
-			}
+			state = 0;
 		} while(--i);
 	}
-	state = 2;
 	return 0;
 }
 
diff -u --recursive --new-file v1.1.93/linux/net/inet/af_inet.c linux/net/inet/af_inet.c
--- v1.1.93/linux/net/inet/af_inet.c	Mon Feb 20 21:34:56 1995
+++ linux/net/inet/af_inet.c	Tue Feb 21 16:12:05 1995
@@ -864,11 +864,13 @@
 	{
 /* should be below! */
 		if (sk2->num != snum) continue;
+#if 0
 		if (sk2->dead) 
 		{
 			destroy_sock(sk2);
 			goto outside_loop;
 		}
+#endif
 		if (!sk->reuse)
 		{
 			sti();
diff -u --recursive --new-file v1.1.93/linux/net/inet/tcp.c linux/net/inet/tcp.c
--- v1.1.93/linux/net/inet/tcp.c	Thu Feb  9 10:18:54 1995
+++ linux/net/inet/tcp.c	Tue Feb 21 17:00:05 1995
@@ -2769,9 +2769,9 @@
 	newsk->linger=0;
 	newsk->destroy = 0;
 	init_timer(&newsk->timer);
-	init_timer(&newsk->retransmit_timer);
 	newsk->timer.data = (unsigned long)newsk;
 	newsk->timer.function = &net_timer;
+	init_timer(&newsk->retransmit_timer);
 	newsk->retransmit_timer.data = (unsigned long)newsk;
 	newsk->retransmit_timer.function=&retransmit_timer;
 	newsk->dummy_th.source = skb->h.th->dest;
@@ -4393,7 +4393,9 @@
 
 	tcp_set_state(sk,TCP_SYN_SENT);
 	sk->rto = TCP_TIMEOUT_INIT;
-	init_timer(&sk->retransmit_timer);
+#if 0 /* we already did this */
+	init_timer(&sk->retransmit_timer); 
+#endif
 	sk->retransmit_timer.function=&retransmit_timer;
 	sk->retransmit_timer.data = (unsigned long)sk;
 	reset_xmit_timer(sk, TIME_WRITE, sk->rto);	/* Timer for repeating the SYN until an answer */
