## Automatically generated incremental diff
## From:   linux-2.2.16-pre4
## To:     linux-2.2.16-pre5
## Robot:  $Id: make-incremental-diff,v 1.7 2001/12/04 05:19:54 hpa Exp $

diff -urN linux-2.2.16-pre4/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.16-pre4/Documentation/Configure.help	Mon Dec  3 22:03:47 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 22:03:53 2001
@@ -9305,14 +9305,6 @@
   backlight at all, or it might print a lot of errors to the console,
   especially if you are using gpm.
 
-Ignore multiple suspend/standby events
-CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
-  This option is necessary on the IBM Thinkpad 560, but should work on
-  all other laptops. When the APM BIOS returns multiple suspend or
-  standby events while one is already being processed they will be
-  ignored. Without this the Thinkpad 560 has troubles with the user
-  level daemon apmd, and with the PCMCIA package pcmcia-cs.
-
 Ignore multiple suspend/resume cycles
 CONFIG_APM_IGNORE_SUSPEND_BOUNCE
   This option is necessary on the Dell Inspiron 3200 and others, but
diff -urN linux-2.2.16-pre4/Makefile linux/Makefile
--- linux-2.2.16-pre4/Makefile	Mon Dec  3 22:03:47 2001
+++ linux/Makefile	Mon Dec  3 22:03:53 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 16
-EXTRAVERSION = pre4
+EXTRAVERSION = pre5
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.16-pre4/arch/alpha/config.in linux/arch/alpha/config.in
--- linux-2.2.16-pre4/arch/alpha/config.in	Wed May  3 17:16:30 2000
+++ linux/arch/alpha/config.in	Mon Dec  3 22:03:53 2001
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
 #
 mainmenu_name "Kernel configuration of Linux for Alpha machines"
 
diff -urN linux-2.2.16-pre4/arch/arm/config.in linux/arch/arm/config.in
--- linux-2.2.16-pre4/arch/arm/config.in	Thu Jan 14 10:29:28 1999
+++ linux/arch/arm/config.in	Mon Dec  3 22:03:53 2001
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
 #
 mainmenu_name "Linux Kernel Configuration"
 
diff -urN linux-2.2.16-pre4/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.2.16-pre4/arch/i386/config.in	Wed May  3 17:16:30 2000
+++ linux/arch/i386/config.in	Mon Dec  3 22:03:53 2001
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
 #
 mainmenu_name "Linux Kernel Configuration"
 
@@ -109,7 +109,6 @@
   bool '   Enable PM at boot time' CONFIG_APM_DO_ENABLE
   bool '   Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
   bool '   Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
-  bool '   Ignore multiple suspend' CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
   bool '   Ignore multiple suspend/resume cycles' CONFIG_APM_IGNORE_SUSPEND_BOUNCE
   bool '   RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
   bool '   Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
diff -urN linux-2.2.16-pre4/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- linux-2.2.16-pre4/arch/i386/kernel/apm.c	Wed May  3 17:16:30 2000
+++ linux/arch/i386/kernel/apm.c	Mon Dec  3 22:03:53 2001
@@ -126,6 +126,9 @@
  *         Register the /proc/apm entry even on SMP so that
  *         scripts that check for it before doing power off
  *         work (Jim Avera <jima@hal.com>).
+ *   1.13: Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS
+ *         is now the way life works). 
+ *         Fix thinko in suspend() (wrong return).
  *
  * APM 1.1 Reference:
  *
@@ -318,9 +321,7 @@
 #endif
 static int			suspends_pending = 0;
 static int			standbys_pending = 0;
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
 static int			waiting_for_resume = 0;
-#endif
 
 #ifdef CONFIG_APM_RTC_IS_GMT
 #	define	clock_cmos_diff	0
@@ -343,7 +344,7 @@
 
 static struct timer_list	apm_timer;
 
-static char			driver_version[] = "1.12";	/* no spaces */
+static char			driver_version[] = "1.13";	/* no spaces */
 
 static char *	apm_event_name[] = {
 	"system standby",
@@ -883,19 +884,19 @@
 static int suspend(void)
 {
 	int		err;
-	int		ret;
 	struct apm_user	*as;
 
 	get_time_diff();
 	err = apm_set_power_state(APM_STATE_SUSPEND);
 	reinit_timer();
 	set_time();
-	ret = (err == APM_SUCCESS) || (err == APM_NO_ERROR);
-	if (!ret)
+	if (err == APM_NO_ERROR)
+		err = APM_SUCCESS;
+	if (err != APM_SUCCESS)
 		apm_error("suspend", err);
 	for (as = user_list; as != NULL; as = as->next) {
 		as->suspend_wait = 0;
-		as->suspend_result = (ret ? 0 : -EIO);
+		as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO);
 	}
 	wake_up_interruptible(&apm_suspend_waitqueue);
 	return err;
@@ -975,14 +976,7 @@
 		switch (event) {
 		case APM_SYS_STANDBY:
 		case APM_USER_STANDBY:
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
-			if (waiting_for_resume)
-				break;
-#endif
 			if (send_event(event, APM_STANDBY_RESUME, NULL)) {
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
-				waiting_for_resume = 1;
-#endif
 				if (standbys_pending <= 0)
 					standby();
 			}
@@ -999,14 +993,18 @@
 			if (ignore_bounce)
 				break;
 #endif
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
+			/*
+			 * If we are already processing a SUSPEND,
+			 * then further SUSPEND events from the BIOS
+			 * will be ignored.  We also return here to
+			 * cope with the fact that the Thinkpads keep
+			 * sending a SUSPEND event until something else
+			 * happens!
+			 */
 			if (waiting_for_resume)
-				break;
-#endif
+				return;
 			if (send_event(event, APM_NORMAL_RESUME, NULL)) {
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
 				waiting_for_resume = 1;
-#endif
 				if (suspends_pending <= 0)
 					(void) suspend();
 			}
@@ -1015,9 +1013,7 @@
 		case APM_NORMAL_RESUME:
 		case APM_CRITICAL_RESUME:
 		case APM_STANDBY_RESUME:
-#ifdef CONFIG_APM_IGNORE_MULTIPLE_SUSPEND
 			waiting_for_resume = 0;
-#endif
 #ifdef CONFIG_APM_IGNORE_SUSPEND_BOUNCE
 			last_resume = jiffies;
 			ignore_bounce = 1;
@@ -1049,8 +1045,10 @@
 	int		err;
 
 	if ((standbys_pending > 0) || (suspends_pending > 0)) {
-		if ((apm_bios_info.version > 0x100) && (pending_count-- < 0)) {
+		if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
 			pending_count = 4;
+			if (debug)
+				printk(KERN_DEBUG "apm: setting state busy\n");
 			err = apm_set_power_state(APM_STATE_BUSY);
 			if (err)
 				apm_error("busy", err);
@@ -1066,7 +1064,7 @@
 static int check_apm_user(struct apm_user *as, const char *func)
 {
 	if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
-		printk(KERN_ERR "apm: %s passed bad filp", func);
+		printk(KERN_ERR "apm: %s passed bad filp\n", func);
 		return 1;
 	}
 	return 0;
@@ -1169,7 +1167,7 @@
 		} else if (!send_event(APM_USER_SUSPEND, APM_NORMAL_RESUME, as))
 			return -EAGAIN;
 		if (suspends_pending <= 0) {
-			if (!suspend())
+			if (suspend() != APM_SUCCESS)
 				return -EIO;
 		} else {
 			as->suspend_wait = 1;
@@ -1220,7 +1218,7 @@
 		     as1 = as1->next)
 			;
 		if (as1 == NULL)
-			printk(KERN_ERR "apm: filp not in user list");
+			printk(KERN_ERR "apm: filp not in user list\n");
 		else
 			as1->next = as->next;
 	}
@@ -1234,7 +1232,7 @@
 
 	as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL);
 	if (as == NULL) {
-		printk(KERN_ERR "apm: cannot allocate struct of size %d bytes",
+		printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
 		       sizeof(*as));
 		return -ENOMEM;
 	}
diff -urN linux-2.2.16-pre4/arch/m68k/config.in linux/arch/m68k/config.in
--- linux-2.2.16-pre4/arch/m68k/config.in	Tue May 11 09:57:14 1999
+++ linux/arch/m68k/config.in	Mon Dec  3 22:03:53 2001
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
 #
 mainmenu_name "Linux/68k Kernel Configuration"
 
diff -urN linux-2.2.16-pre4/arch/mips/config.in linux/arch/mips/config.in
--- linux-2.2.16-pre4/arch/mips/config.in	Mon Aug  9 12:04:38 1999
+++ linux/arch/mips/config.in	Mon Dec  3 22:03:53 2001
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
 #
 mainmenu_name "Linux Kernel Configuration"
 
diff -urN linux-2.2.16-pre4/arch/ppc/config.in linux/arch/ppc/config.in
--- linux-2.2.16-pre4/arch/ppc/config.in	Tue Jan  4 10:12:12 2000
+++ linux/arch/ppc/config.in	Mon Dec  3 22:03:53 2001
@@ -1,6 +1,6 @@
 # $Id: config.in,v 1.92.2.4 1999/09/10 01:23:40 paulus Exp $
 # For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
 #
 mainmenu_name "Linux/PowerPC Kernel Configuration"
 
diff -urN linux-2.2.16-pre4/arch/s390/config.in linux/arch/s390/config.in
--- linux-2.2.16-pre4/arch/s390/config.in	Mon Dec  3 22:03:47 2001
+++ linux/arch/s390/config.in	Mon Dec  3 22:03:53 2001
@@ -1,6 +1,6 @@
-
+#
 # For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
 #
 mainmenu_name "Linux Kernel Configuration"
 define_bool CONFIG_ARCH_S390 y
diff -urN linux-2.2.16-pre4/arch/s390/kernel/ptrace.c linux/arch/s390/kernel/ptrace.c
--- linux-2.2.16-pre4/arch/s390/kernel/ptrace.c	Wed May  3 17:16:31 2000
+++ linux/arch/s390/kernel/ptrace.c	Mon Dec  3 22:03:53 2001
@@ -474,6 +474,10 @@
 	}
 	ret = -ESRCH;
 	// printk("child=%lX child->flags=%lX",child,child->flags);
+	/* I added child!=current line so we can get the */
+	/* ieee_instruction_pointer from the user structure DJB */
+	if(child!=current)
+	{
 	if (!(child->flags & PF_PTRACED))
 		goto out;
 	if (child->state != TASK_STOPPED) 
@@ -483,7 +487,7 @@
 	}
 	if (child->p_pptr != current)
 		goto out;
-
+	}
 	switch (request) 
 	{
 		/* If I and D space are separate, these will need to be fixed. */
diff -urN linux-2.2.16-pre4/arch/s390/kernel/s390io.c linux/arch/s390/kernel/s390io.c
--- linux-2.2.16-pre4/arch/s390/kernel/s390io.c	Mon Dec  3 22:03:47 2001
+++ linux/arch/s390/kernel/s390io.c	Mon Dec  3 22:03:53 2001
@@ -437,8 +437,17 @@
       else
       {
 			ioinfo[irq]->schib.pmcw.ena = 1;
+
+			if ( irq == cons_dev )
+			{
+				ioinfo[irq]->schib.pmcw.isc = 7;
+			}
+			else	
+			{
 			ioinfo[irq]->schib.pmcw.isc = 3;
 
+			} /* endif */
+
          do
          {
 				ccode = msch( irq, &(ioinfo[irq]->schib) );
@@ -776,7 +785,7 @@
 	ioinfo[irq]->orb.fmt     = 1;
 
 	ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
-	ioinfo[irq]->orb.spnd =  (flag & DOIO_ALLOW_SUSPEND);
+	ioinfo[irq]->orb.spnd =  (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE);
 	ioinfo[irq]->orb.ssic =  (    (flag & DOIO_ALLOW_SUSPEND )
 	                          && (flag & DOIO_SUPPRESS_INTER) );
 
@@ -2092,7 +2101,7 @@
 	ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
 
 	//
-	// We must only accumulate the status if initiated by do_IO() or halt_IO()
+	// We must only accumulate the status if the device is busy already
 	//
 	if ( ioinfo[irq]->ui.flags.busy )
 				{
@@ -2130,9 +2139,11 @@
 	 * Save residual count and CCW information in case primary and
 	 *  secondary status are presented with different interrupts.
 			 */
-	if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl & SCSW_STCTL_PRIM_STATUS )
+	if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl
+	           & (   SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) )
 			{
 		ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count;
+		ioinfo[irq]->devstat.cpa    = ioinfo[irq]->devstat.ii.irb.scsw.cpa;
 
 #ifdef CONFIG_DEBUG_IO
       if ( irq != cons_dev )
@@ -2140,11 +2151,6 @@
                  "residual count from irb after tsch() %d\n",
                  irq, ioinfo[irq]->devstat.rescnt );
 #endif
-	} /* endif */
-
-	if ( ioinfo[irq]->devstat.ii.irb.scsw.cpa != 0 )
-	{
-		ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa;
 
 	} /* endif */
 
@@ -2305,7 +2311,7 @@
 				        sizeof( devstat_t) );
 
 				s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
-				s_ccw->cda      = (char *)virt_to_phys( ioinfo[irq]->devstat.ii.sense.data);
+				s_ccw->cda      = (char *)virt_to_phys( ioinfo[irq]->sense_data);
 				s_ccw->count    = SENSE_MAX_COUNT;
 				s_ccw->flags    = CCW_FLAG_SLI;
 
@@ -2373,7 +2379,7 @@
 		 * we allow for the device action handler if .
 		 *  - we received ending status
 		 *  - the action handler requested to see all interrupts
-		 *  - we received a PCI
+		 *  - we received an intermediate status
 		 *  - fast notification was requested (primary status)
 		 *  - unsollicited interrupts
 		 *
@@ -2382,7 +2388,7 @@
 		{
 			allow4handler =    ending_status
 			   || ( ioinfo[irq]->ui.flags.repall                                      )
-			   || ( ioinfo[irq]->devstat.ii.irb.scsw.cstat & SCHN_STAT_PCI            )
+			   || ( stctl & SCSW_STCTL_INTER_STATUS                                   )
 				|| ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) )
 				|| ( ioinfo[irq]->ui.flags.oper == 0                                   );
 
@@ -2421,7 +2427,7 @@
 				if ( sense_count >= 0 )
 				{
 					memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data,
-					        &(ioinfo[irq]->devstat.ii.sense.data),
+					        &(ioinfo[irq]->sense_data),
 					        sense_count);
 				}
 				else
@@ -2557,13 +2563,31 @@
 			{
 				ioinfo[irq]->ui.flags.w4final = 1;
 
+				/*
+				 * Eventually reset subchannel PCI status and
+				 *  set the PCI or SUSPENDED flag in the user
+				 *  device status block if appropriate.
+				 */
+				if ( ioinfo[irq]->devstat.cstat & SCHN_STAT_PCI )
+				{
+					((devstat_t *)(action->dev_id))->flag |= DEVSTAT_PCI;
+					ioinfo[irq]->devstat.cstat &= ~SCHN_STAT_PCI;
+				}
+				else if ( actl & SCSW_ACTL_SUSPENDED )
+				{
+					((devstat_t *)(action->dev_id))->flag |= DEVSTAT_SUSPENDED;
+
+				} /* endif */
+
 				if ( ioinfo[irq]->ui.flags.newreq )
 				{
 					action->handler( irq, ioinfo[irq]->u_intparm );
 				}
 				else
 				{
-					((io_handler_func1_t)action->handler)( irq, action->dev_id, &regs );
+					((io_handler_func1_t)action->handler)( irq,
+					                                       action->dev_id,
+					                                       &regs );
 
 				} /* endif */
 
@@ -4549,7 +4573,7 @@
 								        ioinfo[irq]->schib.pmcw.dev,
 								        irq);
 #endif
-								io_retry = 0;
+								io_retry = 1;
 		}
 #ifdef CONFIG_DEBUG_IO
 		else
@@ -4579,7 +4603,7 @@
 #endif
 	}
 						else if (    ( pdevstat->flag & DEVSTAT_NOT_OPER )
-					             || ( irq_ret        != -ENODEV         ) )
+					             || ( irq_ret        == -ENODEV         ) )
 	{
 #ifdef CONFIG_DEBUG_IO
 							printk( "SenseID : path %02X for "
diff -urN linux-2.2.16-pre4/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c
--- linux-2.2.16-pre4/arch/s390/kernel/setup.c	Mon Dec  3 22:03:47 2001
+++ linux/arch/s390/kernel/setup.c	Mon Dec  3 22:03:53 2001
@@ -211,6 +211,13 @@
 #endif
         memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
 	memory_end = MEMORY_SIZE;
+        /*
+         * We need some free virtual space to be able to do vmalloc.
+         * On a machine with 2GB memory we make sure that we have at
+         * least 128 MB free space for vmalloc.
+         */
+        if (memory_end > 1920*1024*1024)
+                memory_end = 1920*1024*1024;
         init_task.mm->start_code = PAGE_OFFSET;
         init_task.mm->end_code = (unsigned long) &_etext;
         init_task.mm->end_data = (unsigned long) &_edata;
diff -urN linux-2.2.16-pre4/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c
--- linux-2.2.16-pre4/arch/s390/kernel/traps.c	Mon Dec  3 22:03:47 2001
+++ linux/arch/s390/kernel/traps.c	Mon Dec  3 22:03:53 2001
@@ -359,8 +359,23 @@
 	int do_sig = 0;
 
         lock_kernel();
-        if (regs->psw.mask & 0x00010000L) {
 		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	if(MACHINE_HAS_IEEE)
+	{
+		__asm__ volatile ("stfpc %0\n\t" 
+				  : "=m" (current->tss.fp_regs.fpc));
+		
+	}
+	/* Same code should work when we implement fpu emulation */
+	/* provided we call data exception from the fpu emulator */
+	if(current->tss.fp_regs.fpc&FPC_DXC_MASK)
+	{
+		current->tss.ieee_instruction_pointer=
+			(addr_t)ADDR_BITS_REMOVE((addr_t)location);
+		force_sig(SIGFPE, current);
+	}
+        else if ((regs->psw.mask & 0x00010000L)) 
+	{
 		get_user(*((__u16 *) opcode), location);
 		switch (opcode[0]) {
 		case 0x28: /* LDR Rx,Ry   */
@@ -411,7 +426,8 @@
 			do_sig = 1;
 			break;
                 }
-        } else
+        } 
+	else
 		do_sig = 1;
 	if (do_sig) {
                 if (check_for_fixup(regs) == 0) {
diff -urN linux-2.2.16-pre4/arch/sparc/config.in linux/arch/sparc/config.in
--- linux-2.2.16-pre4/arch/sparc/config.in	Mon Dec  3 22:03:47 2001
+++ linux/arch/sparc/config.in	Mon Dec  3 22:03:53 2001
@@ -1,6 +1,6 @@
 # $Id: config.in,v 1.68.2.1 1999/09/22 11:37:34 jj Exp $
 # For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
 #
 mainmenu_name "Linux/SPARC Kernel Configuration"
 
diff -urN linux-2.2.16-pre4/arch/sparc64/config.in linux/arch/sparc64/config.in
--- linux-2.2.16-pre4/arch/sparc64/config.in	Mon Dec  3 22:03:47 2001
+++ linux/arch/sparc64/config.in	Mon Dec  3 22:03:53 2001
@@ -1,6 +1,6 @@
 # $Id: config.in,v 1.67.2.5 1999/10/19 16:49:37 davem Exp $
 # For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
 #
 mainmenu_name "Linux/UltraSPARC Kernel Configuration"
 
diff -urN linux-2.2.16-pre4/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- linux-2.2.16-pre4/arch/sparc64/kernel/ioctl32.c	Mon Dec  3 22:03:47 2001
+++ linux/arch/sparc64/kernel/ioctl32.c	Mon Dec  3 22:03:53 2001
@@ -38,6 +38,7 @@
 #include <linux/videodev.h>
 #include <linux/netdevice.h>
 #include <linux/smb_fs.h>
+#include <linux/blkdev.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
diff -urN linux-2.2.16-pre4/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- linux-2.2.16-pre4/drivers/block/ide-probe.c	Wed May  3 17:16:33 2000
+++ linux/drivers/block/ide-probe.c	Mon Dec  3 22:03:53 2001
@@ -191,6 +191,10 @@
 	} else
 		hd_status = IDE_ALTSTATUS_REG;	/* use non-intrusive polling */
 
+	/* set features register for atapi identify command */
+	if((cmd == WIN_PIDENTIFY))
+	        OUT_BYTE(0,IDE_FEATURE_REG); /* disable dma & overlap mode */
+
 #if CONFIG_BLK_DEV_PDC4030
 	if (IS_PDC4030_DRIVE) {
 		extern int pdc4030_cmd(ide_drive_t *, byte);
diff -urN linux-2.2.16-pre4/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- linux-2.2.16-pre4/drivers/block/ll_rw_blk.c	Mon Dec  3 22:03:47 2001
+++ linux/drivers/block/ll_rw_blk.c	Mon Dec  3 22:03:53 2001
@@ -359,6 +359,7 @@
 	case BLKELVSET:
 		return blkelvset_ioctl(elevator, __arg);
 	}
+	return -EINVAL;
 }
 
 static inline int seek_to_not_starving_chunk(struct request ** req, int * lat)
diff -urN linux-2.2.16-pre4/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- linux-2.2.16-pre4/drivers/char/n_tty.c	Wed May  3 17:16:38 2000
+++ linux/drivers/char/n_tty.c	Mon Dec  3 22:03:54 2001
@@ -228,9 +228,9 @@
 		nr = space;
 	if (nr > sizeof(buf))
 	    nr = sizeof(buf);
-	nr -= copy_from_user(buf, inbuf, nr);
-	if (!nr)
-		return 0;
+
+	if (copy_from_user(buf, inbuf, nr))
+		return -EFAULT;
 	
 	for (i = 0, cp = buf; i < nr; i++, cp++) {
 		switch (*cp) {
diff -urN linux-2.2.16-pre4/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- linux-2.2.16-pre4/drivers/misc/parport_pc.c	Mon Dec  3 22:03:48 2001
+++ linux/drivers/misc/parport_pc.c	Mon Dec  3 22:03:54 2001
@@ -906,6 +906,8 @@
 		  { { 0, 1 }, } },
 		{ PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, 1,
 		  { { 2, -1 }, } },
+		{ PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_4008A, 1,
+		  { { 0, 1 }, } },
 		{ 0, }
 	};
 
diff -urN linux-2.2.16-pre4/drivers/net/3c59x.c linux/drivers/net/3c59x.c
--- linux-2.2.16-pre4/drivers/net/3c59x.c	Mon Dec  3 22:03:48 2001
+++ linux/drivers/net/3c59x.c	Mon Dec  3 22:03:54 2001
@@ -1394,8 +1394,10 @@
 		}
 		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
 		outw(DownUnstall, ioaddr + EL3_CMD);
-	} else
+	} else {
 		vp->stats.tx_dropped++;
+		clear_bit(0, (void *)&dev->tbusy);
+	}
 	
 	/* Issue Tx Enable */
 	outw(TxEnable, ioaddr + EL3_CMD);
diff -urN linux-2.2.16-pre4/drivers/net/eepro.c linux/drivers/net/eepro.c
--- linux-2.2.16-pre4/drivers/net/eepro.c	Mon Dec  3 22:03:48 2001
+++ linux/drivers/net/eepro.c	Mon Dec  3 22:03:54 2001
@@ -23,6 +23,8 @@
 	This is a compatibility hardware problem.
 
 	Versions:
+	0.12a	fixed bug that would make impossible have ee10 boards and
+		other previous supported boards. (aris, 05/19/2000)
 	0.12    added support to 82595FX etherexpress 10 based cards
                 (aris <aris@conectiva.com.br>), 04/26/2000)
 	0.11e   some tweaks about multiple cards support (PdP, jul/aug 1999)
@@ -95,7 +97,7 @@
 */
 
 static const char *version =
-	"eepro.c: v0.12 04/26/2000 aris@conectiva.com.br\n";
+	"eepro.c: v0.12a 04/26/2000 aris@conectiva.com.br\n";
 
 #include <linux/module.h>
 
@@ -142,11 +144,6 @@
 #include <linux/skbuff.h>
 
 
-/* need to remove these asap      */
-/* 2.1.xx compatibility macros... */
-/*                                */
-
-
 #include <linux/version.h>
 
 /* For linux 2.1.xx */
@@ -178,20 +175,10 @@
 /* First, a few definitions that the brave might change. */
 /* A zero-terminated list of I/O addresses to be probed. */
 static unsigned int eepro_portlist[] compat_init_data =
-#ifdef PnPWakeup
-   { 0x210, 0x300,
-#else
-   { 0x300, 0x210, 
-#endif
-   0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
+	{ 0x300, 0x210, 0x240, 0x280, 0x2C0, 0x200, 0x320, 0x340, 0x360, 0};
 /* note: 0x300 is default, the 595FX supports ALL IO Ports 
   from 0x000 to 0x3F0, some of which are reserved in PCs */
 
-/* To try the (not-really PnP Wakeup: */
-/*
-#define PnPWakeup
-*/
-
 /* use 0 for production, 1 for verification, >2 for debug */
 #ifndef NET_DEBUG
 #define NET_DEBUG 0
@@ -205,9 +192,7 @@
 #define	LAN595		0
 #define	LAN595TX	1
 #define	LAN595FX	2
-
-/* global to recall the read_eepro */
-static unsigned char etherexpress10 = 0;
+#define	LAN595FX_10ISA	3
 
 /* Information that need to be kept for each board. */
 struct eepro_local {
@@ -222,9 +207,7 @@
 	int version;	/* a flag to indicate if this is a TX or FX
 				   version of the 82595 chip. */
 	int stepping;
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 	spinlock_t lock; /* Serializing lock  */ 
-#endif
 };
 
 /* The station (ethernet) address prefix, used for IDing the board. */
@@ -326,7 +309,7 @@
 static struct enet_statistics *eepro_get_stats(struct device *dev);
 static void     set_multicast_list(struct device *dev);
 
-static int read_eeprom(int ioaddr, int location);
+static int read_eeprom(int ioaddr, int location, struct device *dev);
 static void hardware_send_packet(struct device *dev, void *buf, short length);
 static int	eepro_grab_irq(struct device *dev);
 
@@ -486,6 +469,59 @@
 #define EEDI 0x04
 #define EEDO 0x08
 
+/* do a full reset */
+#define eepro_reset(ioaddr) outb(RESET_CMD, ioaddr)
+
+/* do a nice reset */
+#define eepro_sel_reset(ioaddr) 	{ \
+					outb(SEL_RESET_CMD, ioaddr); \
+					SLOW_DOWN; \
+					SLOW_DOWN; \
+					}
+
+/* disable all interrupts */
+#define eepro_dis_int(ioaddr) outb(ALL_MASK, ioaddr + INT_MASK_REG)
+
+/* clear all interrupts */
+#define eepro_clear_int(ioaddr) outb(ALL_MASK, ioaddr + STATUS_REG)
+
+/* enable tx/rx */
+#define eepro_en_int(ioaddr) outb(ALL_MASK & ~(RX_MASK | TX_MASK), \
+							ioaddr + INT_MASK_REG)
+
+/* enable exec event interrupt */
+#define eepro_en_intexec(ioaddr) outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG)
+
+/* enable rx */
+#define eepro_en_rx(ioaddr) outb(RCV_ENABLE_CMD, ioaddr)
+
+/* disable rx */
+#define eepro_dis_rx(ioaddr) outb(RCV_DISABLE_CMD, ioaddr)
+
+/* switch bank */
+#define eepro_sw2bank0(ioaddr) outb(BANK0_SELECT, ioaddr)
+#define eepro_sw2bank1(ioaddr) outb(BANK1_SELECT, ioaddr)
+#define eepro_sw2bank2(ioaddr) outb(BANK2_SELECT, ioaddr)
+
+/* enable interrupt line */
+#define eepro_en_intline(ioaddr) outb(inb(ioaddr + REG1) | INT_ENABLE,\
+				ioaddr + REG1)
+
+/* disable interrupt line */
+#define eepro_dis_intline(ioaddr) outb(inb(ioaddr + REG1) & 0x7f, \
+				ioaddr + REG1);
+
+/* set diagnose flag */
+#define eepro_diag(ioaddr) outb(DIAGNOSE_CMD, ioaddr)
+
+/* ack for rx/tx int */
+#define eepro_ack_rxtx(ioaddr) outb (RX_INT | TX_INT, ioaddr + STATUS_REG)
+
+/* ack for rx int */
+#define eepro_ack_rx(ioaddr) outb (RX_INT, ioaddr + STATUS_REG)
+
+/* ack for tx int */
+#define eepro_ack_tx(ioaddr) outb (TX_INT, ioaddr + STATUS_REG)
 
 /* Check for a network adaptor of this type, and return '0' if one exists.
    If dev->base_addr == 0, probe all likely locations.
@@ -503,44 +539,12 @@
 {
 	int i;
 	int base_addr = dev ? dev->base_addr : 0;
-
-
-#ifdef PnPWakeup
-	/* XXXX for multiple cards should this only be run once? */
-	
-	/* Wakeup: */
-	#define WakeupPort 0x279
-	#define WakeupSeq    {0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,\
-	                      0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,\
-	                      0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,\
-	                      0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x43}
-
-	{
-		unsigned short int WS[32]=WakeupSeq;
-
-		if (check_region(WakeupPort, 2)==0) {
-
-			if (net_debug>5)
-				printk(KERN_DEBUG "Waking UP\n");
-
-			outb_p(0,WakeupPort);
-			outb_p(0,WakeupPort);
-			for (i=0; i<32; i++) {
-				outb_p(WS[i],WakeupPort);
-				if (net_debug>5) printk(KERN_DEBUG ": %#x ",WS[i]);
-			}
-		} else printk(KERN_WARNING "Checkregion Failed!\n");
-	}
-#endif
-
-
 	if (base_addr > 0x1ff)		/* Check a single specified location. */
 		return eepro_probe1(dev, base_addr);
 
 	else if (base_addr != 0)	/* Don't probe at all. */
 		return ENXIO;
 
-
 	for (i = 0; eepro_portlist[i]; i++) {
 		int ioaddr = eepro_portlist[i];
 
@@ -549,21 +553,21 @@
 		if (eepro_probe1(dev, ioaddr) == 0)
 			return 0;
 	}
-
+	
 	return ENODEV;
 }
 #endif
 
-static void printEEPROMInfo(short ioaddr)
+static void printEEPROMInfo(short ioaddr, struct device *dev)
 {
 	unsigned short Word;
 	int i,j;
 
 	for (i=0, j=ee_Checksum; i<ee_SIZE; i++)
-		j+=read_eeprom(ioaddr,i);
+		j+=read_eeprom(ioaddr,i,dev);
 	printk("Checksum: %#x\n",j&0xffff);
 
-	Word=read_eeprom(ioaddr, 0);
+	Word=read_eeprom(ioaddr, 0, dev);
 	printk(KERN_DEBUG "Word0:\n");
 	printk(KERN_DEBUG " Plug 'n Pray: %d\n",GetBit(Word,ee_PnP));
 	printk(KERN_DEBUG " Buswidth: %d\n",(GetBit(Word,ee_BusWidth)+1)*8 );
@@ -571,7 +575,7 @@
 	printk(KERN_DEBUG " IO Address: %#x\n", (Word>>ee_IO0)<<4);
 
 	if (net_debug>4)  {
-		Word=read_eeprom(ioaddr, 1);
+		Word=read_eeprom(ioaddr, 1, dev);
 		printk(KERN_DEBUG "Word1:\n");
 		printk(KERN_DEBUG " INT: %d\n", Word & ee_IntMask);
 		printk(KERN_DEBUG " LI: %d\n", GetBit(Word,ee_LI));
@@ -582,7 +586,7 @@
 		printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
 	}
 
-	Word=read_eeprom(ioaddr, 5);
+	Word=read_eeprom(ioaddr, 5, dev);
 	printk(KERN_DEBUG "Word5:\n");
 	printk(KERN_DEBUG " BNC: %d\n",GetBit(Word,ee_BNC_TPE));
 	printk(KERN_DEBUG " NumConnectors: %d\n",GetBit(Word,ee_NumConn));
@@ -592,12 +596,12 @@
 	if (GetBit(Word,ee_PortAUI)) printk("AUI ");
 	printk("port(s) \n");
 
-	Word=read_eeprom(ioaddr, 6);
+	Word=read_eeprom(ioaddr, 6, dev);
 	printk(KERN_DEBUG "Word6:\n");
 	printk(KERN_DEBUG " Stepping: %d\n",Word & ee_StepMask);
 	printk(KERN_DEBUG " BoardID: %d\n",Word>>ee_BoardID);
 
-	Word=read_eeprom(ioaddr, 7);
+	Word=read_eeprom(ioaddr, 7, dev);
 	printk(KERN_DEBUG "Word7:\n");
 	printk(KERN_DEBUG " INT to IRQ:\n");
 
@@ -617,7 +621,8 @@
 {
 	unsigned short station_addr[6], id, counter;
 	int i,j, irqMask;
-	int eepro;
+	int eepro = 0;
+	struct eepro_local *lp;
 	const char *ifmap[] = {"AUI", "10Base2", "10BaseT"};
 	enum iftype { AUI=0, BNC=1, TPE=2 };
 
@@ -631,7 +636,6 @@
 		/* We seem to have the 82595 signature, let's
 		   play with its counter (last 2 bits of
 		   register 2 of bank 0) to be sure. */
-
 		counter = (id & R_ROBIN_BITS);	
 		if (((id=inb(ioaddr+ID_REG)) & R_ROBIN_BITS) == 
 			(counter + 0x40)) {
@@ -640,43 +644,47 @@
 			printk(KERN_DEBUG " id: %#x ",id);
 			printk(" io: %#x ",ioaddr);
 
+			/* Initialize the device structure */
+			dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
+			if (dev->priv == NULL)
+				return -ENOMEM;
+			memset(dev->priv, 0, sizeof(struct eepro_local));
+
+			lp = (struct eepro_local *)dev->priv;
+
 			/* Now, get the ethernet hardware address from
 			   the EEPROM */
 
-			station_addr[0] = read_eeprom(ioaddr, 2);
+			station_addr[0] = read_eeprom(ioaddr, 2, dev);
 
 			/* FIXME - find another way to know that we've found
 			 * a Etherexpress 10
 			 */
 			if (station_addr[0] == 0x0000 ||
 			    station_addr[0] == 0xffff) {
-				etherexpress10 = 1;
+				eepro = 3;
+				lp->eepro = LAN595FX_10ISA;
 				eeprom_reg = EEPROM_REG_10;
 				rcv_start = RCV_START_10;
 				xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_10;
 				xmt_upper_limit_reg = XMT_UPPER_LIMIT_REG_10;
 
-				station_addr[0] = read_eeprom(ioaddr, 2);
+				station_addr[0] = read_eeprom(ioaddr, 2, dev);
 			}
 			
-			station_addr[1] = read_eeprom(ioaddr, 3);
-			station_addr[2] = read_eeprom(ioaddr, 4);
+			station_addr[1] = read_eeprom(ioaddr, 3, dev);
+			station_addr[2] = read_eeprom(ioaddr, 4, dev);
 
-			/* Check the station address for the manufacturer's code */
-			if (net_debug>3)
-				printEEPROMInfo(ioaddr);
 
-			if (etherexpress10) {
-				eepro = 2;
+			if (eepro) {
 				printk("%s: Intel EtherExpress 10 ISA\n at %#x,",
 					dev->name, ioaddr);
-			} else if (read_eeprom(ioaddr,7)== ee_FX_INT2IRQ) {
+			} else if (read_eeprom(ioaddr,7,dev)== ee_FX_INT2IRQ) {
 						 /* int to IRQ Mask */
 				eepro = 2;
 				printk("%s: Intel EtherExpress Pro/10+ ISA\n at %#x,", 
 					dev->name, ioaddr);
-			} else
-			if (station_addr[2] == 0x00aa)  {
+			} else if (station_addr[2] == SA_ADDR1)  {
 				eepro = 1;
 				printk("%s: Intel EtherExpress Pro/10 ISA at %#x,",
 					dev->name, ioaddr);
@@ -694,7 +702,7 @@
 				dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i];
 				printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
 			}
-			
+
 			dev->mem_start = (RCV_LOWER_LIMIT << 8);
 
 			if ((dev->mem_end & 0x3f) < 3 ||	/* RX buffer must be more than 3K */
@@ -716,7 +724,7 @@
 								
 			/* ............... */
 
-			if (GetBit( read_eeprom(ioaddr, 5),ee_BNC_TPE))
+			if (GetBit( read_eeprom(ioaddr, 5, dev),ee_BNC_TPE))
 				dev->if_port = BNC;
 			else dev->if_port = TPE;
 
@@ -724,8 +732,8 @@
 
 
 			if ((dev->irq < 2) && (eepro!=0)) {
-				i = read_eeprom(ioaddr, 1);
-				irqMask = read_eeprom(ioaddr, 7);
+				i = read_eeprom(ioaddr, 1, dev);
+				irqMask = read_eeprom(ioaddr, 7, dev);
 				i &= 0x07; /* Mask off INT number */
 				
 				for (j=0; ((j<16) && (i>=0)); j++) {
@@ -737,7 +745,7 @@
 						i--; /* count bits set in irqMask */
 					}
 				}
-				if (dev -> irq<2) {
+				if (dev->irq < 2) {
 					printk(" Duh! illegal interrupt vector stored in EEPROM.\n");
 						return ENODEV;
 				} else 
@@ -753,7 +761,7 @@
 			else printk(", %s.\n", ifmap[dev->if_port]);
 			
 			if (net_debug > 3) {
-				i = read_eeprom(ioaddr, 5);
+				i = read_eeprom(ioaddr, 5, dev);
 				if (i & 0x2000) /* bit 13 of EEPROM word 5 */
 					printk(KERN_DEBUG "%s: Concurrent Processing is enabled but not used!\n",
 						dev->name);
@@ -765,15 +773,7 @@
 			/* Grab the region so we can find another board if autoIRQ fails. */
 			request_region(ioaddr, EEPRO_IO_EXTENT, dev->name);
 
-			/* Initialize the device structure */
-			dev->priv = kmalloc(sizeof(struct eepro_local), GFP_KERNEL);
-			if (dev->priv == NULL)
-				return -ENOMEM;
-			memset(dev->priv, 0, sizeof(struct eepro_local));
-
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 			spin_lock_init(&(((struct eepro_local *)dev->priv)->lock));
-#endif
 			dev->open               = eepro_open;
 			dev->stop               = eepro_close;
 			dev->hard_start_xmit    = eepro_send_packet;
@@ -785,7 +785,12 @@
 
 			ether_setup(dev);
 
-			outb(RESET_CMD, ioaddr); /* RESET the 82595 */
+			/* Check the station address for the manufacturer's code */
+			if (net_debug>3)
+				printEEPROMInfo(ioaddr, dev);
+
+			/* reset 82595 */
+			eepro_reset(ioaddr);
 
 			return 0;
 			}
@@ -811,55 +816,52 @@
 	int irqlist[] = { 3, 4, 5, 7, 9, 10, 11, 12 };
 	int *irqp = irqlist, temp_reg, ioaddr = dev->base_addr;
 	
-	outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
+	eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
 
 	/* Enable the interrupt line. */
-	temp_reg = inb(ioaddr + REG1);
-	outb(temp_reg | INT_ENABLE, ioaddr + REG1);
+	eepro_en_intline(ioaddr);
 	
-	outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */
+	eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
 
 	/* clear all interrupts */
-	outb(ALL_MASK, ioaddr + STATUS_REG);
+	eepro_clear_int(ioaddr);
 
 	/* Let EXEC event to interrupt */
-	outb(ALL_MASK & ~(EXEC_MASK), ioaddr + INT_MASK_REG);
+	eepro_en_intexec(ioaddr);
 
 	do {
-		outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
-
+		eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
 		temp_reg = inb(ioaddr + INT_NO_REG);
 		outb((temp_reg & 0xf8) | irqrmap[*irqp], ioaddr + INT_NO_REG);
 
-		outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+		eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
 
 		if (request_irq (*irqp, NULL, 0, "bogus", dev) != EBUSY) {
 			/* Twinkle the interrupt, and check if it's seen */
 			autoirq_setup(0);
 
-			outb(DIAGNOSE_CMD, ioaddr); /* RESET the 82595 */
+			eepro_diag(ioaddr); /* RESET the 82595 */
 				
 			if (*irqp == autoirq_report(2))  /* It's a good IRQ line */
 				break;
 
 			/* clear all interrupts */
-			outb(ALL_MASK, ioaddr + STATUS_REG); 
+			eepro_clear_int(ioaddr);
 		}
 	} while (*++irqp);
 
-	outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */
+	eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
 
 	/* Disable the physical interrupt line. */
-	temp_reg = inb(ioaddr + REG1);
-	outb(temp_reg & 0x7f, ioaddr + REG1); 
+	eepro_dis_intline(ioaddr);
 
-	outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+	eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
 
 	/* Mask all the interrupts. */
-	outb(ALL_MASK, ioaddr + INT_MASK_REG); 
+	eepro_dis_int(ioaddr);
 
 	/* clear all interrupts */
-	outb(ALL_MASK, ioaddr + STATUS_REG); 
+	eepro_clear_int(ioaddr);
 
 	return dev->irq;
 }
@@ -875,7 +877,12 @@
 	if (net_debug > 3)
 		printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name);
 
-	if ((irqMask=read_eeprom(ioaddr,7))== ee_FX_INT2IRQ) /* INT to IRQ Mask */
+	irqMask = read_eeprom(ioaddr,7,dev);
+
+	if (lp->eepro == LAN595FX_10ISA) {
+		if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 3;\n"); 
+	}
+	else if (irqMask == ee_FX_INT2IRQ) /* INT to IRQ Mask */
 		{
 			lp->eepro = 2; /* Yes, an Intel EtherExpress Pro/10+ */
 			if (net_debug > 3) printk(KERN_DEBUG "p->eepro = 2;\n"); 
@@ -913,18 +920,19 @@
 
 	/* Initialize the 82595. */
 
-	outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+	eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
 	temp_reg = inb(ioaddr + eeprom_reg);
 
 	lp->stepping = temp_reg >> 5;	/* Get the stepping number of the 595 */
-	
+	/* Get the stepping number of the 595 */
+
 	if (net_debug > 3)
 		printk(KERN_DEBUG "The stepping of the 82595 is %d\n", lp->stepping);
 
 	if (temp_reg & 0x10) /* Check the TurnOff Enable bit */
 		outb(temp_reg & 0xef, ioaddr + eeprom_reg);
-	for (i=0; i < 6; i++)
-		outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i); 
+	for (i=0; i < 6; i++) /* Fill the mac address */
+		outb(dev->dev_addr[i] , ioaddr + I_ADD_REG0 + i);
 			
 	temp_reg = inb(ioaddr + REG1);    /* Setup Transmit Chaining */
 	outb(temp_reg | XMT_Chain_Int | XMT_Chain_ErrStop /* and discard bad RCV frames */
@@ -937,17 +945,16 @@
 	outb(temp_reg & 0x3f, ioaddr + REG3); /* clear test mode */
 
 	/* Set the receiving mode */
-	outb(BANK1_SELECT, ioaddr); /* be CAREFUL, BANK 1 now */
+	eepro_sw2bank1(ioaddr); /* be CAREFUL, BANK 1 now */
 
 	/* Set the interrupt vector */	
 	temp_reg = inb(ioaddr + INT_NO_REG);
-	if (lp->eepro == 2)
+	if (lp->eepro == 2 || lp->eepro == LAN595FX_10ISA)
 		outb((temp_reg & 0xf8) | irqrmap2[dev->irq], ioaddr + INT_NO_REG);
 	else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG); 
 
-
 	temp_reg = inb(ioaddr + INT_NO_REG);
-	if (lp->eepro == 2)
+	if (lp->eepro == 2 || lp->eepro == LAN595FX_10ISA)
 		outb((temp_reg & 0xf0) | irqrmap2[dev->irq] | 0x08,ioaddr+INT_NO_REG);
 	else outb((temp_reg & 0xf8) | irqrmap[dev->irq], ioaddr + INT_NO_REG);
 
@@ -962,16 +969,15 @@
 	outb(XMT_UPPER_LIMIT, ioaddr + xmt_upper_limit_reg); 
 
 	/* Enable the interrupt line. */
-	temp_reg = inb(ioaddr + REG1);
-	outb(temp_reg | INT_ENABLE, ioaddr + REG1); 
+	eepro_en_intline(ioaddr);
 
-	outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+	eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
 
 	/* Let RX and TX events to interrupt */
-	outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+	eepro_en_int(ioaddr);
 
 	/* clear all interrupts */
-	outb(ALL_MASK, ioaddr + STATUS_REG); 
+	eepro_clear_int(ioaddr);
 
 	/* Initialize RCV */
 	outw((RCV_LOWER_LIMIT << 8), ioaddr + RCV_BAR); 
@@ -994,8 +1000,6 @@
 		lp->version = LAN595TX;
 		outb(old8, ioaddr + 8);
 		old9 = inb(ioaddr + 9);
-		/*outb(~old9, ioaddr + 9);
-		if (((temp_reg = inb(ioaddr + 9)) == ( (~old9)&0xff) )) {*/
 		
 		if (irqMask==ee_FX_INT2IRQ) {
 			enum iftype { AUI=0, BNC=1, TPE=2 };
@@ -1009,12 +1013,12 @@
 			if (dev->if_port != TPE) {	/* Hopefully, this will fix the
 							problem of using Pentiums and
 							pro/10 w/ BNC. */
-				outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+				eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
 				temp_reg = inb(ioaddr + REG13);
 				/* disable the full duplex mode since it is not
 				applicable with the 10Base2 cable. */
 				outb(temp_reg & ~(FDX | A_N_ENABLE), REG13);
-				outb(BANK0_SELECT, ioaddr); /* be CAREFUL, BANK 0 now */
+				eepro_sw2bank0(ioaddr); /* be CAREFUL, BANK 0 now */
 			}
 		}
 		else if (net_debug > 3) {
@@ -1023,11 +1027,7 @@
 		}
 	}
 	
-	outb(SEL_RESET_CMD, ioaddr);
-
-	/* We are supposed to wait for 2 us after a SEL_RESET */
-	SLOW_DOWN;
-	SLOW_DOWN;
+	eepro_sel_reset(ioaddr);
 
 	lp->tx_start = lp->tx_end = (XMT_LOWER_LIMIT << 8);
 	lp->tx_last = 0;
@@ -1039,7 +1039,8 @@
 	if (net_debug > 3)
 		printk(KERN_DEBUG "%s: exiting eepro_open routine.\n", dev->name);
 
-	outb(RCV_ENABLE_CMD, ioaddr);
+	/* enabling rx */
+	eepro_en_rx(ioaddr);
 
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -1050,23 +1051,22 @@
 	struct eepro_local *lp = (struct eepro_local *)dev->priv;
 	int ioaddr = dev->base_addr;
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 	unsigned long flags;
-#endif
-	
+
 	if (net_debug > 5)
 		printk(KERN_DEBUG  "%s: entering eepro_send_packet routine.\n", dev->name);
-	
+
 	if (dev->tbusy) {
 		/* If we get here, some higher level has decided we are broken.
 		   There should really be a "kick me" function call instead. */
 		int tickssofar = jiffies - dev->trans_start;
+
 		if (tickssofar < 40)
 			return 1;
-	
+		
 		/* let's disable interrupts so we can avoid confusion on SMP
 		 */
-		outb(ALL_MASK, ioaddr + INT_MASK_REG);
+		eepro_dis_int(ioaddr);
 		
 		/* if (net_debug > 1) */
 		printk(KERN_ERR "%s: transmit timed out, %s?\n", dev->name, 
@@ -1078,10 +1078,8 @@
 		lp->stats.tx_errors++;
 
 		/* Try to restart the adaptor. */
-		outb(SEL_RESET_CMD, ioaddr); 
 		/* We are supposed to wait for 2 us after a SEL_RESET */
-		SLOW_DOWN;
-		SLOW_DOWN;
+		eepro_sel_reset(ioaddr);
 
 		/* Do I also need to flush the transmit buffers here? YES? */
 		lp->tx_start = lp->tx_end = (XMT_LOWER_LIMIT << 8); 
@@ -1092,31 +1090,24 @@
 
 
 		/* re-enabling all interrupts */
-		outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
-		
-		outb(RCV_ENABLE_CMD, ioaddr);
-	}
+		eepro_en_int(ioaddr);
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
+		/* enable rx */
+		eepro_en_rx(ioaddr);
+	}
 	spin_lock_irqsave(&lp->lock, flags);
-#endif
 
 	/* Block a timer-based transmit from overlapping. */
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
 		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 		spin_unlock_irqrestore(&lp->lock, flags);
-#endif
 	} else {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 		unsigned char *buf = skb->data;
 		int discard = lp->stats.tx_dropped;
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 		lp->stats.tx_bytes+=skb->len;
-#endif
-
 		hardware_send_packet(dev, buf, length);
 
 		if (lp->stats.tx_dropped != discard)
@@ -1134,9 +1125,7 @@
 	if (net_debug > 5)
 		printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 	spin_unlock_irqrestore(&lp->lock, flags);
-#endif
 	
 	return 0;
 }
@@ -1158,20 +1147,17 @@
                 return;
         }
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
         spin_lock(&lp->lock);
-#endif
 
 	if (dev->interrupt) {
 		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 		spin_unlock(&lp->lock);
 		/* FIXME : with the lock, could this ever happen ? */
-#endif
 
 		return;
 	}
+
 	dev->interrupt = 1;
 
 	if (net_debug > 5)
@@ -1183,13 +1169,13 @@
 	{
 		switch (status & (RX_INT | TX_INT)) {
 			case (RX_INT | TX_INT):
-				outb (RX_INT | TX_INT, ioaddr + STATUS_REG);
+				eepro_ack_rxtx(ioaddr);
 				break;
 			case RX_INT:
-				outb (RX_INT, ioaddr + STATUS_REG);
+				eepro_ack_rx(ioaddr);
 				break;
 			case TX_INT:
-				outb (TX_INT, ioaddr + STATUS_REG);
+				eepro_ack_tx(ioaddr);
 				break;
 		}
 		if (status & RX_INT) {
@@ -1201,7 +1187,7 @@
 		}
 		if (status & TX_INT) {
 			if (net_debug > 4)
-				printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
+ 				printk(KERN_DEBUG "%s: packet transmit interrupt.\n", dev->name);
 
 			/* Process the status of transmitted packets */
 			eepro_transmit_interrupt(dev);
@@ -1213,9 +1199,8 @@
 	if (net_debug > 5)
 		printk(KERN_DEBUG "%s: exiting eepro_interrupt routine.\n", dev->name);
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 	spin_unlock(&lp->lock);
-#endif
+
 	return;
 }
 
@@ -1228,13 +1213,13 @@
 	dev->tbusy = 1;
 	dev->start = 0;
 
-	outb(BANK1_SELECT, ioaddr); /* Switch back to Bank 1 */
+	eepro_sw2bank1(ioaddr); /* Switch back to Bank 1 */
 
 	/* Disable the physical interrupt line. */
 	temp_reg = inb(ioaddr + REG1);
 	outb(temp_reg & 0x7f, ioaddr + REG1); 
 
-	outb(BANK0_SELECT, ioaddr); /* Switch back to Bank 0 */
+	eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
 
 	/* Flush the Tx and disable Rx. */
 	outb(STOP_RCV_CMD, ioaddr); 
@@ -1242,13 +1227,13 @@
 	lp->tx_last = 0;
 
 	/* Mask all the interrupts. */
-	outb(ALL_MASK, ioaddr + INT_MASK_REG); 
+	eepro_dis_int(ioaddr);
 
 	/* clear all interrupts */
-	outb(ALL_MASK, ioaddr + STATUS_REG); 
+	eepro_clear_int(ioaddr);
 
 	/* Reset the 82595 */
-	outb(RESET_CMD, ioaddr); 
+	eepro_reset(ioaddr);
 
 	/* release the interrupt */
 	free_irq(dev->irq, dev);
@@ -1259,10 +1244,6 @@
 
 	/* Update the statistics here. What statistics? */
 
-	/* We are supposed to wait for 200 us after a RESET */
-	SLOW_DOWN;
-	SLOW_DOWN; /* May not be enough? */
-
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -1297,23 +1278,23 @@
 		 */
 		dev->flags|=IFF_PROMISC;		
 
-		outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+		eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
 		mode = inb(ioaddr + REG2);
 		outb(mode | PRMSC_Mode, ioaddr + REG2);	
 		mode = inb(ioaddr + REG3);
 		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-		outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+		eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
 		printk("%s: promiscuous mode enabled.\n", dev->name);
 	}
 	
 	else if (dev->mc_count==0 ) 
 	{
-		outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+		eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
 		mode = inb(ioaddr + REG2);
 		outb(mode & 0xd6, ioaddr + REG2); /* Turn off Multi-IA and PRMSC_Mode bits */
 		mode = inb(ioaddr + REG3);
 		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-		outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+		eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
 	}
 	
 	else 
@@ -1324,14 +1305,14 @@
 		/* Disable RX and TX interrupts.  Necessary to avoid
 		   corruption of the HOST_ADDRESS_REG by interrupt
 		   service routines. */
-		outb(ALL_MASK, ioaddr + INT_MASK_REG);
+		eepro_dis_int(ioaddr);
 
-		outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */
+		eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
 		mode = inb(ioaddr + REG2);
 		outb(mode | Multi_IA, ioaddr + REG2);	
 		mode = inb(ioaddr + REG3);
 		outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
-		outb(BANK0_SELECT, ioaddr); /* Return to BANK 0 now */
+		eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
 		outw(lp->tx_end, ioaddr + HOST_ADDRESS_REG);
 		outw(MC_SETUP, ioaddr + IO_PORT);
 		outw(0, ioaddr + IO_PORT);
@@ -1395,10 +1376,11 @@
 		} while (++boguscount < 100);
 
 		/* Re-enable RX and TX interrupts */
-		outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+		eepro_en_int(ioaddr);
 	
 	}
-	outb(RCV_ENABLE_CMD, ioaddr);
+	/* enabling rx */
+	eepro_en_rx(ioaddr);
 }
 
 /* The horrible routine to read a word from the serial EEPROM. */
@@ -1409,11 +1391,12 @@
 #define EE_READ_CMD (6 << 6)
 
 int
-read_eeprom(int ioaddr, int location)
+read_eeprom(int ioaddr, int location, struct device *dev)
 {
 	int i;
 	unsigned short retval = 0;
 	short ee_addr = ioaddr + eeprom_reg;
+	struct eepro_local *lp = (struct eepro_local *)dev->priv;
 	int read_cmd = location | EE_READ_CMD;
 	short ctrl_val = EECS ;
 	
@@ -1421,12 +1404,12 @@
 	 *	  boards other than eepro10. I think that it won't let other
 	 *	  boards to fail. (aris)
 	 */
-	if (etherexpress10) {
-		outb(BANK1_SELECT, ioaddr);
+	if (lp->eepro == LAN595FX_10ISA) {
+		eepro_sw2bank1(ioaddr);
 		outb(0x00, ioaddr + STATUS_REG);
 	}
 		
-	outb(BANK2_SELECT, ioaddr);
+	eepro_sw2bank2(ioaddr);
 	outb(ctrl_val, ee_addr);
 	
 	/* Shift the read command bits out. */
@@ -1453,7 +1436,7 @@
 	eeprom_delay();
 	outb(ctrl_val, ee_addr);
 	eeprom_delay();
-	outb(BANK0_SELECT, ioaddr);
+	eepro_sw2bank0(ioaddr);
 	return retval;
 }
 
@@ -1462,21 +1445,22 @@
 {
 	struct eepro_local *lp = (struct eepro_local *)dev->priv;
 	short ioaddr = dev->base_addr;
+
 	unsigned status, tx_available, last, end, boguscount = 100;
 
 	if (net_debug > 5)
 		printk(KERN_DEBUG "%s: entering hardware_send_packet routine.\n", dev->name);
 
-	while (boguscount-- > 0) {
 
+	while (boguscount-- > 0) {
 		/* Disable RX and TX interrupts.  Necessary to avoid
 		corruption of the HOST_ADDRESS_REG by interrupt
 		service routines. */
-		outb(ALL_MASK, ioaddr + INT_MASK_REG);
+		eepro_dis_int(ioaddr);
 
 		if (dev->interrupt == 1) {
 			/* Enable RX and TX interrupts */
-			outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+			eepro_en_int(ioaddr);
 			continue;
 		}
 
@@ -1493,7 +1477,7 @@
 			eepro_transmit_interrupt(dev); /* Clean up the transmiting queue */
 
 			/* Enable RX and TX interrupts */
-			outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); 
+			eepro_en_int(ioaddr);
 			continue;
 		}
 
@@ -1537,7 +1521,6 @@
 		else {
 			/* update the next address and the chain bit in the 
 			last packet */
-			
 			if (lp->tx_end != last) {
 				outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG);
 				outw(last, ioaddr + IO_PORT); 
@@ -1546,7 +1529,6 @@
 			outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG);
 			status = inw(ioaddr + IO_PORT); 
 			outw(status | CHAIN_BIT, ioaddr + IO_PORT);
-
 			/* Continue the transmit command */
 			outb(RESUME_XMT_CMD, ioaddr);
 		}
@@ -1561,18 +1543,18 @@
 		/* now we are serializing tx. tbusy won't come back until
 		 * the tx interrupt
 		 */
-		if (etherexpress10)
+		if (lp->eepro == LAN595FX_10ISA)
 			dev->tbusy = 1;
 		
 		/* Enable RX and TX interrupts */
-		outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+		eepro_en_int(ioaddr);
 
 		if (net_debug > 5)
 			printk(KERN_DEBUG "%s: exiting hardware_send_packet routine.\n", dev->name);
 		return;
 	}
 
-	outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+	eepro_en_int(ioaddr);
 	dev->tbusy = 1;
 
 	if (net_debug > 5)
@@ -1584,15 +1566,16 @@
 {
 	struct eepro_local *lp = (struct eepro_local *)dev->priv;
 	short ioaddr = dev->base_addr;
+		
 	short boguscount = 20;
 	unsigned rcv_car = lp->rx_start;
 	unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size;
 
 	if (net_debug > 5)
 		printk(KERN_DEBUG "%s: entering eepro_rx routine.\n", dev->name);
-	
-	/* disabling all interrupts */
-	outb(ALL_MASK, ioaddr + STATUS_REG);
+
+	/* clear all interrupts */
+	eepro_clear_int(ioaddr);
 	
 	/* Set the read pointer to the start of the RCV */
 	outw(rcv_car, ioaddr + HOST_ADDRESS_REG);
@@ -1610,9 +1593,7 @@
 			/* Malloc up new buffer. */
 			struct sk_buff *skb;
 
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 			lp->stats.rx_bytes+=rcv_size;
-#endif
 			rcv_size &= 0x3fff;
 			skb = dev_alloc_skb(rcv_size+5);
 			if (skb == NULL) {
@@ -1675,7 +1656,8 @@
 	if (net_debug > 5)
 		printk(KERN_DEBUG "%s: exiting eepro_rx routine.\n", dev->name);
 
-	outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
+	/* enable tx/rx interrupts */
+	eepro_en_int(ioaddr);
 }
 
 static void
@@ -1685,7 +1667,7 @@
 	short ioaddr = dev->base_addr;
 	short boguscount = 20; 
 	unsigned xmt_status;
-	
+
 	/*
 	if (dev->tbusy == 0) {
 		printk("%s: transmit_interrupt called with tbusy = 0 ??\n",
@@ -1705,19 +1687,23 @@
 			continue;
 		}
 
+
 		xmt_status = inw(ioaddr+IO_PORT); 
 		lp->tx_start = inw(ioaddr+IO_PORT);
 
-		if (etherexpress10) {
+		if (lp->eepro == LAN595FX_10ISA) {
 			lp->tx_start = (XMT_LOWER_LIMIT << 8);
 			lp->tx_end = lp->tx_start;
 	
 			/* yeah, black magic :( */
-			outb(BANK0_SELECT, ioaddr);
-			outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG);
-		
-			outb(RCV_DISABLE_CMD, ioaddr);
-			outb(RCV_ENABLE_CMD, ioaddr);
+			eepro_sw2bank0(ioaddr);
+			eepro_en_int(ioaddr);
+
+			/* disabling rx */
+			eepro_dis_rx(ioaddr);
+			
+			/* enabling rx */
+			eepro_en_rx(ioaddr);
 		}
 
 		/* here the tbusy comes to 0 for normal and ee10 cards
@@ -1744,20 +1730,18 @@
 				printk(KERN_DEBUG "%s: XMT status = %#x\n",
 					dev->name, xmt_status);
 			}
-			
-			if (etherexpress10) {
+
+			if (lp->eepro == LAN595FX_10ISA) {			
 				/* Try to restart the adaptor. */
-				outb(SEL_RESET_CMD, ioaddr); 
-			
 				/* We are supposed to wait for 2 us after a SEL_RESET */
-				SLOW_DOWN;
-				SLOW_DOWN;
+				eepro_sel_reset(ioaddr);
 
 				/* first enable interrupts */
-				outb(BANK0_SELECT, ioaddr);
+				eepro_sw2bank0(ioaddr);
 				outb(ALL_MASK & ~(RX_INT | TX_INT), ioaddr + STATUS_REG);
 			
-				outb(RCV_ENABLE_CMD, ioaddr);
+				/* enabling rx */
+				eepro_en_rx(ioaddr);
 			}
 		}
 		
@@ -1786,15 +1770,12 @@
 static int autodetect;
 
 static int n_eepro = 0;
-/* For linux 2.1.xx */
-#if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 MODULE_AUTHOR("Pascal Dupuis <dupuis@lei.ucl.ac.be> for the 2.1 stuff (locking,...)");
 MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EEPRO) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i");
 MODULE_PARM(autodetect, "1-" __MODULE_STRING(1) "i");
-#endif 
 
 int 
 init_module(void)
@@ -1815,13 +1796,15 @@
 	for (i = 0; i < MAX_EEPRO; i++) {
 		struct device *d = &dev_eepro[n_eepro];
 		d->name		= devicename[n_eepro]; /* inserted by drivers/net/net_init.c */
-		d->mem_end	= mem[n_eepro];
+		d->mem_end	= mem[n_eepro];		
 		d->base_addr	= io[0];
 		d->irq		= irq[n_eepro];
 		d->init		= eepro_probe;
 
 		if (register_netdev(d) == 0)
 			n_eepro++;
+		else
+			break;
 	}
 	
 	return n_eepro ? 0 : -ENODEV;
diff -urN linux-2.2.16-pre4/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- linux-2.2.16-pre4/drivers/pci/oldproc.c	Mon Dec  3 22:03:48 2001
+++ linux/drivers/pci/oldproc.c	Mon Dec  3 22:03:54 2001
@@ -483,6 +483,7 @@
 	DEVICE( NVIDIA_SGS,	NVIDIA_SGS_RIVA128,	"Riva 128"),
 	DEVICE( CBOARDS,	CBOARDS_DAS1602_16,"DAS1602/16"),
 	DEVICE( MOTOROLA_OOPS,	MOTOROLA_FALCON,"Falcon"),
+	DEVICE( TIMEDIA,	TIMEDIA_4008A, "Noname 4008A"),
 	DEVICE( SYMPHONY,	SYMPHONY_101,	"82C101"),
 	DEVICE( TEKRAM,		TEKRAM_DC290,	"DC-290"),
 	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX"),
@@ -846,6 +847,7 @@
 	      case PCI_VENDOR_ID_PICTUREL:	return "Picture Elements";
 	      case PCI_VENDOR_ID_NVIDIA_SGS:	return "NVidia/SGS Thomson";
 	      case PCI_VENDOR_ID_CBOARDS:	return "ComputerBoards";
+	      case PCI_VENDOR_ID_TIMEDIA:	return "Timedia Technology";
 	      case PCI_VENDOR_ID_SYMPHONY:	return "Symphony";
 	      case PCI_VENDOR_ID_COMPUTONE:	return "Computone Corporation";
 	      case PCI_VENDOR_ID_TEKRAM:	return "Tekram";
diff -urN linux-2.2.16-pre4/drivers/s390/char/hwc_tty.c linux/drivers/s390/char/hwc_tty.c
--- linux-2.2.16-pre4/drivers/s390/char/hwc_tty.c	Mon Dec  3 22:03:48 2001
+++ linux/drivers/s390/char/hwc_tty.c	Mon Dec  3 22:03:54 2001
@@ -207,8 +207,6 @@
 {
 	struct tty_struct *tty = hwc_tty_data.tty;
 
-#if 0
-
 	if (tty != NULL) {
 
 		if (count == 2 && (
@@ -249,7 +247,7 @@
 		tty_flip_buffer_push (tty);
 		hwc_tty_wake_up ();
 	}
-#endif
+#if 0
 
 	if (tty != NULL) {
 
@@ -289,6 +287,7 @@
 		tty_flip_buffer_push(tty);
 		hwc_tty_wake_up ();
 	}
+#endif
 }
 
 void 
diff -urN linux-2.2.16-pre4/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c
--- linux-2.2.16-pre4/drivers/s390/net/ctc.c	Mon Dec  3 22:03:48 2001
+++ linux/drivers/s390/net/ctc.c	Mon Dec  3 22:03:54 2001
@@ -42,6 +42,9 @@
  *            IFCONFIG dev DOWN and IFCONFIG dev UP 
  *          - Possibility to switch the automatic selection off
  *          - Minor bug fixes 
+ *    0.52  Bug fixes 
+ *          - Subchannel check message enhanced 
+ *          - Read / Write retry routine check for CTC_STOP added  
  */
 #include <linux/version.h>
 #include <linux/init.h>
@@ -80,7 +83,7 @@
         #define KERN_WARNING KERN_EMERG
         #define KERN_DEBUG   KERN_EMERG
 #endif  
-//#undef DEBUG
+
 
 #define CCW_CMD_WRITE           0x01
 #define CCW_CMD_READ            0x02
@@ -914,10 +917,10 @@
 
         devstat_t *devstat = ((devstat_t *)initparm);
 
-        /* Bypass all 'unsolited interrupts' */
+        /* Bypass all 'unsolicited interrupts' */
         if (devstat->intparm == 0) {
 #ifdef DEBUG
-                printk(KERN_DEBUG "ctc: unsolited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
+                printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received c-%02x d-%02x f-%02x\n",
                     devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);
 #endif 
                 /* FIXME - find the related intparm!!! No IO outstanding!!!! */
@@ -935,8 +938,8 @@
 
         /* Check for good subchannel return code, otherwise error message */
         if (devstat->cstat) {
-                printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x\n", 
-                    dev->name, ctc->devno, devstat->cstat);
+                printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n", 
+                    dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag);
                 return;
         }
 
@@ -1245,6 +1248,8 @@
 #ifdef DEBUG
         printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state);
 #endif 
+        if (ctc->state == CTC_STOP)
+                return;
         s390irq_spin_lock_irqsave(ctc->irq, saveflags);
         ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
         parm = (__u32) ctc; 
@@ -1269,6 +1274,8 @@
 #ifdef DEBUG
         printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state);
 #endif 
+        if (ctc->state == CTC_STOP)
+                return;
         s390irq_spin_lock_irqsave(ctc->irq, saveflags);
         ctc->ccw[1].count = 0;
         ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
@@ -1414,6 +1421,7 @@
 static int ctc_release(net_device *dev)
 {   
         int                rc;
+        int                x; 
         int                i;
         int                j;
         __u8               flags = 0x00;
@@ -1429,6 +1437,7 @@
 	ctc_unprotect_busy_irqrestore(dev,flags);
         for (i = 0; i < 2;  i++) {
                 s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+                del_timer(&privptr->channel[READ].timer);  
                 privptr->channel[i].state = CTC_STOP;
                 parm = (__u32) &privptr->channel[i]; 
                 rc = halt_IO (privptr->channel[i].irq, parm, flags );
diff -urN linux-2.2.16-pre4/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- linux-2.2.16-pre4/drivers/scsi/sg.c	Tue Jan  4 10:12:21 2000
+++ linux/drivers/scsi/sg.c	Mon Dec  3 22:03:54 2001
@@ -7,7 +7,7 @@
  * Original driver (sg.c):
  *        Copyright (C) 1992 Lawrence Foard
  * 2.x extensions to driver:
- *        Copyright (C) 1998, 1999 Douglas Gilbert
+ *        Copyright (C) 1998 - 2000 Douglas Gilbert
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -16,8 +16,8 @@
  *
  *  Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
  */
- static char * sg_version_str = "Version: 2.1.36 (991218)";
- static int sg_version_num = 20136; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 2.1.37 (20000504)";
+ static int sg_version_num = 20137; /* 2 digits for each component */
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
@@ -100,7 +100,7 @@
 static void sg_detach(Scsi_Device *);
 
 
-struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff,
+struct Scsi_Device_Template sg_template = {NULL, "generic", "sg", NULL, 0xff,
                                            SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
                                            sg_detect, sg_init,
                                            sg_finish, sg_attach, sg_detach};
@@ -609,8 +609,29 @@
             return -EBUSY;
         result = get_user(val, (int *)arg);
         if (result) return result;
-        /* Don't do anything till scsi mod level visibility */
-        return 0;
+        if (SG_SCSI_RESET_NOTHING == val)
+            return 0;
+#ifdef SCSI_TRY_RESET_DEVICE
+        switch (val)
+        {
+        case SG_SCSI_RESET_DEVICE:
+            val = SCSI_TRY_RESET_DEVICE;
+            break;
+        case SG_SCSI_RESET_BUS:
+            val = SCSI_TRY_RESET_BUS;
+            break;
+        case SG_SCSI_RESET_HOST:
+            val = SCSI_TRY_RESET_HOST;
+            break;
+        default:
+            return -EINVAL;
+        }
+        if(! capable(CAP_SYS_ADMIN))  return -EACCES;
+        return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO;
+#else
+        SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n"));
+        result = -EINVAL;
+#endif
     case SCSI_IOCTL_SEND_COMMAND:
         /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
            user already has read/write access to the generic device and so
@@ -1124,6 +1145,8 @@
 
     SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n", 
                                max_buff_size)); 
+    if (max_buff_size <= 0)
+        return 0;
     if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) {
         sg_link_reserve(sfp, srp, max_buff_size);
         sg_write_xfer(req_schp, inp, num_write_xfer);
@@ -1351,6 +1374,8 @@
     Sg_scatter_hold * rsv_schp = &sfp->reserve;
 
     SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); 
+    /* round request up to next highest SG_SECTOR_SZ byte boundary */
+    size = (size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
     if (rsv_schp->use_sg > 0) {
         int k, num;
         int rem = size;
@@ -1431,12 +1456,12 @@
 static Sg_request * sg_add_request(Sg_fd * sfp)
 {
     int k;
-    Sg_request * resp = NULL;
-    Sg_request * rp;
+    Sg_request * resp = sfp->headrp;
+    Sg_request * rp = sfp->req_arr;
 
-    resp = sfp->headrp;
-    rp = sfp->req_arr;
     if (! resp) {
+        memset(rp, 0, sizeof(Sg_request));
+        rp->parentfp = sfp;
         resp = rp;
         sfp->headrp = resp;
     }
@@ -1444,12 +1469,15 @@
         if (0 == sfp->cmd_q)
             resp = NULL;   /* command queuing disallowed */
         else {
-            for (k = 0, rp; k < SG_MAX_QUEUE; ++k, ++rp) {
+            for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
                 if (! rp->parentfp)
                     break;
             }
             if (k < SG_MAX_QUEUE) {
-                while (resp->nextrp) resp = resp->nextrp;
+                memset(rp, 0, sizeof(Sg_request));
+                rp->parentfp = sfp;
+                while (resp->nextrp) 
+                    resp = resp->nextrp;
                 resp->nextrp = rp;
                 resp = rp;
             }
@@ -1458,11 +1486,7 @@
         }
     }
     if (resp) {
-        resp->parentfp = sfp;
         resp->nextrp = NULL;
-        resp->res_used = 0;
-        memset(&resp->data, 0, sizeof(Sg_scatter_hold));
-        memset(&resp->header, 0, sizeof(struct sg_header));
         resp->my_cmdp = NULL;
     }
     return resp;
@@ -1478,14 +1502,14 @@
         return 0;
     prev_rp = sfp->headrp;
     if (srp == prev_rp) {
-        prev_rp->parentfp = NULL;
         sfp->headrp = prev_rp->nextrp;
+        prev_rp->parentfp = NULL;
         return 1;
     }
     while ((rp = prev_rp->nextrp)) {
         if (srp == rp) {
-            rp->parentfp = NULL;
             prev_rp->nextrp = rp->nextrp;
+            rp->parentfp = NULL;
             return 1;
         }
         prev_rp = rp;
diff -urN linux-2.2.16-pre4/drivers/sound/Makefile linux/drivers/sound/Makefile
--- linux-2.2.16-pre4/drivers/sound/Makefile	Mon Dec  3 22:03:48 2001
+++ linux/drivers/sound/Makefile	Mon Dec  3 22:03:54 2001
@@ -53,7 +53,7 @@
 obj-$(CONFIG_SOUND_CS4232)	+= uart401.o
 obj-$(CONFIG_SOUND_GUS)		+= gus.o ad1848.o
 obj-$(CONFIG_SOUND_MAD16)	+= mad16.o ad1848.o sb.o uart401.o
-obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx.o sb.o uart401.o
+obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx.o sb.o uart401.o 
 obj-$(CONFIG_SOUND_MAUI)	+= maui.o mpu401.o
 obj-$(CONFIG_SOUND_MPU401)	+= mpu401.o
 obj-$(CONFIG_SOUND_MSNDCLAS)	+= msnd.o msnd_classic.o
@@ -90,7 +90,7 @@
 # Declare multi-part drivers.
 
 list-multi	:= sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \
-    soundcore.o wavefront.o nm256.o
+    soundcore.o wavefront.o nm256.o via82cxxx.o \
 
 sound-objs	:= 							\
     dev_table.o soundcard.o sound_syms.o		\
@@ -108,6 +108,7 @@
 vidc_mod-objs	:= vidc.o vidc_audio.o vidc_fill.o vidc_mixer.o vidc_synth.o
 wavefront-objs  := wavfront.o wf_midi.o yss225.o
 nm256-objs	:= nm256_audio.o ac97.o
+via82cxxx-objs := via82cxxx_audio.o ac97.o
 
 
 # Extract lists of the multi-part drivers.
@@ -195,6 +196,9 @@
 
 nm256.o: $(nm256-objs)
 	$(LD) -r -o $@ $(nm256-objs)
+
+via82cxxx.o: $(via82cxxx-objs)
+	$(LD) -r -o $@ $(via82cxxx-objs)
 
 # Firmware files that need translation
 #
diff -urN linux-2.2.16-pre4/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- linux-2.2.16-pre4/drivers/sound/cmpci.c	Wed May  3 17:16:45 2000
+++ linux/drivers/sound/cmpci.c	Mon Dec  3 22:03:54 2001
@@ -588,7 +588,7 @@
 
 /* --------------------------------------------------------------------- */
 
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
+#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
 #define DMABUF_MINORDER 1
 
 static void dealloc_dmabuf(struct dmabuf *db)
diff -urN linux-2.2.16-pre4/drivers/sound/via82cxxx.c linux/drivers/sound/via82cxxx.c
--- linux-2.2.16-pre4/drivers/sound/via82cxxx.c	Tue Oct 26 17:53:41 1999
+++ linux/drivers/sound/via82cxxx.c	Wed Dec 31 16:00:00 1969
@@ -1,266 +0,0 @@
-/*
- * Support for VIA 82Cxxx Audio Codecs
- * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
- *
- * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
- * See the "COPYING" file distributed with this software for more info.
- *
- ********************************************************************
- *
- * TODO:
- *
- *	- Integrate AC'97 support, when AC'97 interface released
- *
- */
- 
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "sound_config.h"
-#include "soundmodule.h"
-#include "sb.h"
-
-#ifndef SOUND_LOCK
-#define SOUND_LOCK do {} while (0)
-#define SOUND_LOCK_END do {} while (0)
-#endif
-
-#define MAX_CARDS	2
-
-#define PFX		"via82cxxx: "
-
-#define VIA_VERSION	"1.0.0"
-#define VIA_CARD_NAME	"VIA 82Cxxx Audio driver " VIA_VERSION
-
-#define VIA_FUNC_ENABLE		0x42
-#define VIA_PNP_CONTROL		0x43
-
-#define VIA_CR42_SB_ENABLE	0x01
-#define VIA_CR42_MIDI_ENABLE	0x02
-#define VIA_CR42_FM_ENABLE	0x04
-
-#define via_probe_midi probe_uart401
-#define via_attach_midi attach_uart401
-#define via_unload_midi unload_uart401
-
-static struct address_info	sb_data[MAX_CARDS];
-static struct address_info	opl3_data[MAX_CARDS];
-static unsigned			cards = 0;
-
-
-static void __init via_attach_sb(struct address_info *hw_config)
-{
-	if(!sb_dsp_init(hw_config))
-		hw_config->slots[0] = -1;
-}
-
-
-static int __init via_probe_sb(struct address_info *hw_config)
-{
-	if (check_region(hw_config->io_base, 16))
-	{
-		printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n",
-		       hw_config->io_base);
-		return 0;
-	}
-	return sb_dsp_detect(hw_config, 0, 0);
-}
-
-
-static void via_unload_sb(struct address_info *hw_config, int unload_mpu)
-{
-	if(hw_config->slots[0]!=-1)
-		sb_dsp_unload(hw_config, unload_mpu);
-}
-
-
-static int __init via82cxxx_install (struct pci_dev *pcidev)
-{
-	int sb_io_base = 0;
-	int sb_irq = 0;
-	int sb_dma = 0;
-	int midi_base = 0;
-	u8 tmp8;
-	
-	memset (&sb_data[cards], 0, sizeof (struct address_info));
-	memset (&opl3_data[cards], 0, sizeof (struct address_info));
-
-	sb_data[cards].name = opl3_data[cards].name = VIA_CARD_NAME;
-	opl3_data[cards].irq = -1;
-
-	/* turn on features, if not already */
-	pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
-	tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
-		VIA_CR42_FM_ENABLE;
-	pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
-
-	/* read legacy PNP info byte */
-	pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8);
-	pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8);
-	
-	switch ((tmp8 >> 6) & 0x03) {
-		case 0: sb_irq = 5; break;
-		case 1: sb_irq = 7; break;
-		case 2: sb_irq = 9; break;
-		case 3: sb_irq = 10; break;
-		default: /* do nothing */ break;
-	}
-	switch ((tmp8 >> 4) & 0x03) {
-		case 0: sb_dma = 0; break;
-		case 1: sb_dma = 1; break;
-		case 2: sb_dma = 2; break;
-		case 3: sb_dma = 3; break;
-		default: /* do nothing */ break;
-	}
-	switch ((tmp8 >> 2) & 0x03) {
-		case 0: midi_base = 0x300; break;
-		case 1: midi_base = 0x310; break;
-		case 2: midi_base = 0x320; break;
-		case 3: midi_base = 0x330; break;
-		default: /* do nothing */ break;
-	}
-	switch (tmp8 & 0x03) {
-		case 0: sb_io_base = 0x220; break;
-		case 1: sb_io_base = 0x240; break;
-		case 2: sb_io_base = 0x260; break;
-		case 3: sb_io_base = 0x280; break;
-		default: /* do nothing */ break;
-	}
-
-	udelay(100);
-	
-	printk(KERN_INFO PFX "legacy "
-	       "MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n",
-		midi_base, sb_io_base, sb_irq, sb_dma);
-		
-	sb_data[cards].card_subtype = MDL_SBPRO;
-	sb_data[cards].io_base = sb_io_base;
-	sb_data[cards].irq = sb_irq;
-	sb_data[cards].dma = sb_dma;
-	
-	opl3_data[cards].io_base = midi_base;
-	
-	/* register legacy SoundBlaster Pro */
-	if (!via_probe_sb (&sb_data[cards])) {
-		printk (KERN_ERR PFX
-			"SB probe @ 0x%X failed, aborting\n",
-			sb_io_base);
-		return -1;
-	}
-	via_attach_sb (&sb_data[cards]);
-
-	/* register legacy MIDI */
-	if (!via_probe_midi (&opl3_data[cards])) {
-		printk (KERN_ERR PFX
-			"MIDI probe @ 0x%X failed, aborting\n",
-			midi_base);
-		via_unload_sb (&sb_data[cards], 0);
-		return -1;
-	}
-	via_attach_midi (&opl3_data[cards]);
-
-	cards++;	
-	return 0;
-}
-
-
-/*
- * 	This loop walks the PCI configuration database and finds where
- *	the sound cards are.
- */
- 
-static int __init probe_via82cxxx (void)
-{
-	struct pci_dev *pcidev = NULL;
-
-	while ((pcidev = pci_find_device (PCI_VENDOR_ID_VIA,
-					  PCI_DEVICE_ID_VIA_82C686_5,
-					  pcidev)) != NULL) {
-
-		  if (via82cxxx_install (pcidev) != 0) {
-			  printk (KERN_ERR PFX "audio init failed\n");
-			  return -1;
-		  }
-
-		  if (cards == MAX_CARDS) {
-		  	  printk (KERN_DEBUG PFX "maximum number of cards reached\n");
-			  break;
-		  }
-	}
-
-	return 0;
-}
-
-
-/*
- *	This function is called when the user or kernel loads the 
- *	module into memory.
- */
-
-
-static int __init init_via82cxxx_module(void)
-{
-	if (!pci_present ()) {
-		printk (KERN_DEBUG PFX "PCI not present, exiting\n");
-		return -ENODEV;
-	}
-
-	if (probe_via82cxxx() != 0) {
-		printk(KERN_ERR PFX "probe failed, aborting\n");
-		/* XXX unload cards registered so far, if any */
-		return -ENODEV;
-	}
-
-	if (cards == 0) {
-		printk(KERN_DEBUG PFX "No chips found, aborting\n");
-		return -ENODEV;
-	}
-
-	printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n");
-	
-	/*
-	 *	Binds us to the sound subsystem	
-	 */
-	SOUND_LOCK;
-	return 0;
-}
-
-/*
- *	This is called when it is removed. It will only be removed 
- *	when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK
- *	macros hide the entire work for this.
- */
- 
-static void cleanup_via82cxxx_module(void)
-{
-	int i;
-	
-	for (i = 0; i < cards; i++)
-		via_unload_sb (&sb_data[i], 1);
-
-	/*
-	 *	Final clean up with the sound layer
-	 */
-	SOUND_LOCK_END;
-}
-
-#ifdef MODULE
-
-int init_module(void)
-{
-	return init_via82cxxx_module();
-}
-
-void cleanup_module(void)
-{
-	cleanup_via82cxxx_module();
-}
-
-#endif
diff -urN linux-2.2.16-pre4/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- linux-2.2.16-pre4/drivers/sound/via82cxxx_audio.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/via82cxxx_audio.c	Mon Dec  3 22:03:54 2001
@@ -0,0 +1,729 @@
+/*
+ * Support for VIA 82Cxxx Audio Codecs
+ * Copyright 1999,2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+ *
+ * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
+ * See the "COPYING" file distributed with this software for more info.
+ *
+ * Documentation for this driver available as
+ * linux/Documentation/sound/via82cxxx.txt.
+ *
+ * Since the mixer is called from the OSS glue the kernel lock is always held
+ * on our AC97 mixing
+ */
+ 
+
+#define VIA_VERSION	"1.1.2.1"
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+
+#include "sound_config.h"
+#include "soundmodule.h"
+#include "sb.h"
+#include "ac97.h"
+
+#ifndef SOUND_LOCK
+#define SOUND_LOCK do {} while (0)
+#define SOUND_LOCK_END do {} while (0)
+#endif
+
+#define VIA_DEBUG 0	/* define to 1 to enable debugging output and checks */
+#if VIA_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define VIA_NDEBUG 0	/* define to 1 to disable lightweight runtime checks */
+#if VIA_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+        if(!(expr)) {					\
+        printk( "Assertion failed! %s,%s,%s,line=%d\n",	\
+        #expr,__FILE__,__FUNCTION__,__LINE__);		\
+        }
+#endif
+
+#define arraysize(x)            (sizeof(x)/sizeof(*(x)))
+
+#define MAX_CARDS	2
+
+#define	LINE_SIZE	10
+
+#define VIA_CARD_NAME	"VIA 82Cxxx Audio driver " VIA_VERSION
+#define VIA_MODULE_NAME "via_audio"
+#define PFX		VIA_MODULE_NAME ": "
+
+#define VIA_COUNTER_LIMIT	100000
+
+/* 82C686 function 5 (audio codec) PCI configuration registers */
+#define VIA_FUNC_ENABLE		0x42
+#define VIA_PNP_CONTROL		0x43
+#define VIA_AC97_CTRL		0x80
+
+/* PCI configuration register bits and masks */
+#define VIA_CR40_AC97_READY	0x01
+#define VIA_CR40_AC97_LOW_POWER	0x02
+#define VIA_CR40_SECONDARY_READY 0x04
+
+#define VIA_CR41_ACLINK_ENABLE	0x80
+
+#define VIA_CR42_SB_ENABLE	0x01
+#define VIA_CR42_MIDI_ENABLE	0x02
+#define VIA_CR42_FM_ENABLE	0x04
+#define VIA_CR42_GAME_ENABLE	0x08
+
+#define VIA_CR44_SECOND_CODEC_SUPPORT	(1 << 6)
+#define VIA_CR44_AC_LINK_ACCESS		(1 << 7)
+
+#define VIA_CR80_FIRST_CODEC		0
+#define VIA_CR80_SECOND_CODEC		(1 << 30)
+#define VIA_CR80_FIRST_CODEC_VALID	(1 << 25)
+#define VIA_CR80_SECOND_CODEC_VALID	(1 << 27)
+#define VIA_CR80_BUSY			(1 << 24)
+#define VIA_CR80_READ_MODE		(1 << 23)
+#define VIA_CR80_WRITE_MODE		0
+#define VIA_CR80_REG_IDX(idx)		(((idx) & 0x7E) << 16)
+
+struct via_info {
+	struct address_info sb_data;
+	struct address_info opl3_data;
+	struct pci_dev *pdev;
+	struct ac97_hwint ac97;
+	int mixer_oss_dev;
+	int have_ac97;
+};
+static struct via_info		cards [MAX_CARDS];
+static unsigned			num_cards = 0;
+
+
+static const struct {
+	int revision;
+	const char *rev_name;
+} via_chip_revs[] __initdata = {
+	{ 0x10, "A" },
+	{ 0x11, "B" },
+	{ 0x12, "C" },
+	{ 0x13, "D" },
+	{ 0x14, "E" },
+	{ 0x20, "H" },
+};
+
+static inline void via_ac97_write32 (struct pci_dev *pdev, int port, u32 data)
+{
+
+	int iobase = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+	
+	outw ((u16)data,iobase+port);	
+	outw ((u16)(data>>16),iobase+port+2);	
+}
+
+static inline u32 via_ac97_read32 (struct pci_dev *pdev, int port)
+{
+	int iobase = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+
+	return
+		((u32)inw (iobase+port)) |
+		(((u32)inw (iobase+port+2)) << 16);
+}
+
+/****************************************************************
+ *
+ * Intel Audio Codec '97 interface
+ *
+ *
+ */
+ 
+static inline void via_ac97_wait_idle (struct pci_dev *pdev)
+{
+	u32 tmp;
+	int counter = VIA_COUNTER_LIMIT;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (pdev != NULL);
+	
+	do {
+		tmp = via_ac97_read32 (pdev,VIA_AC97_CTRL);
+	} while ((tmp & VIA_CR80_BUSY) && (counter-- > 0));
+
+	DPRINTK ("EXIT%s\n", counter > 0 ? "" : ", counter limit reached");
+}
+
+
+static int via_ac97_read_reg (struct ac97_hwint *dev, u8 reg)
+{
+	u32 data;
+	struct via_info *card;
+	struct pci_dev *pdev;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (dev != NULL);
+	assert (dev->driver_private != NULL);
+
+	card = (struct via_info *) dev->driver_private;
+	pdev = card->pdev;
+	assert (pdev != NULL);
+
+	via_ac97_wait_idle (pdev);
+	data =	VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID |
+		VIA_CR80_READ_MODE | VIA_CR80_REG_IDX(reg);
+	via_ac97_write32 (pdev,VIA_AC97_CTRL,data);
+	via_ac97_wait_idle (pdev);
+	data = via_ac97_read32 (pdev,VIA_AC97_CTRL);
+
+#if 0
+	if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
+		DPRINTK ("EXIT, first codec not valid, returning -1\n");
+		return -1;
+	}
+#endif
+
+	DPRINTK ("EXIT, returning %d\n", data & 0xFFFF);
+	return data & 0xFFFF;
+}
+
+
+static int via_ac97_write_reg (struct ac97_hwint *dev, u8 reg, u16 value)
+{
+	u32 data;
+	struct via_info *card;
+	struct pci_dev *pdev;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (dev != NULL);
+	assert (dev->driver_private != NULL);
+
+	card = (struct via_info *) dev->driver_private;
+	pdev = card->pdev;
+	assert (pdev != NULL);
+
+	via_ac97_wait_idle (pdev);
+	data =	VIA_CR80_FIRST_CODEC | VIA_CR80_FIRST_CODEC_VALID |
+		VIA_CR80_WRITE_MODE | VIA_CR80_REG_IDX(reg) | value;
+	via_ac97_write32 (pdev,VIA_AC97_CTRL,data);
+
+#if 0
+	if (! (data & VIA_CR80_FIRST_CODEC_VALID)) {
+		DPRINTK ("EXIT, first codec invalid, returning -1\n");
+		return -1;
+	}
+#endif
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static int via_ac97_reset (struct ac97_hwint *dev)
+{
+	struct via_info *card;
+	struct pci_dev *pdev;
+	
+	DPRINTK ("ENTER\n");
+
+	assert (dev != NULL);
+	assert (dev->driver_private != NULL);
+
+	card = (struct via_info *) dev->driver_private;
+	pdev = card->pdev;
+	assert (pdev != NULL);
+	
+	pci_write_config_word (pdev, PCI_COMMAND, PCI_COMMAND_IO);
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static struct via_info *via_ac97_find_card_for_mixer (int dev)
+{
+	int x;
+
+	DPRINTK ("ENTER\n");
+
+	for (x = 0; x < num_cards; x++)
+		if (cards[x].mixer_oss_dev == dev) {
+			DPRINTK ("EXIT, returning %p\n", cards + x);
+			return cards + x;
+		}
+
+	DPRINTK ("EXIT, returning 0\n");
+	return NULL;
+}
+
+
+static int
+via_ac97_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
+{
+	int rc;
+	struct via_info *card = via_ac97_find_card_for_mixer (dev);
+
+	DPRINTK ("ENTER\n");
+
+	if (card != NULL) {
+		rc = ac97_mixer_ioctl (&card->ac97, cmd, arg);
+		DPRINTK ("EXIT, returning %d\n", rc);
+		return rc;
+	}
+	
+	DPRINTK ("EXIT, returning -ENODEV\n");
+	return -ENODEV;
+
+}
+
+static struct mixer_operations via_ac97_mixer_operations =
+{
+	"VIA82Cxxx",
+	"via82cxxxAC97Mixer",
+	via_ac97_default_mixer_ioctl
+};
+
+static int __init via_attach_ac97 (struct via_info *card)
+{
+	int mixer;
+	struct ac97_hwint *mdev;
+
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+
+	mdev = &card->ac97;
+
+	memset (mdev, 0, sizeof (*mdev));
+	mdev->reset_device = via_ac97_reset;
+	mdev->read_reg = via_ac97_read_reg;
+	mdev->write_reg = via_ac97_write_reg;
+	mdev->driver_private = (void *) card;
+
+	if (ac97_init (mdev)) {
+		printk (KERN_ERR PFX "Unable to init AC97\n");
+		DPRINTK ("EXIT, returning -1\n");
+		return -1;
+	}
+	mixer = sound_alloc_mixerdev ();
+	if (mixer < 0 || num_mixers >= MAX_MIXER_DEV) {
+		printk (KERN_ERR PFX "Unable to alloc mixerdev\n");
+		DPRINTK ("EXIT, returning -1\n");
+		return -1;
+	}
+	mixer_devs[mixer] = &via_ac97_mixer_operations;
+	card->mixer_oss_dev = mixer;
+
+	/* Some reasonable default values.  */
+	ac97_set_mixer (mdev, SOUND_MIXER_VOLUME, (85 << 8) | 85);
+	ac97_set_mixer (mdev, SOUND_MIXER_SPEAKER, 100);
+	ac97_set_mixer (mdev, SOUND_MIXER_PCM, (65 << 8) | 65);
+	ac97_set_mixer (mdev, SOUND_MIXER_CD, (65 << 8) | 65);
+
+	printk (KERN_INFO PFX "Initialized AC97 mixer\n");
+	
+	card->have_ac97 = mixer;
+	
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+static void via_unload_ac97 (struct via_info *card)
+{
+	DPRINTK ("ENTER\n");
+
+	assert (card != NULL);
+
+	if (card->have_ac97 >= 0)
+		sound_unload_mixerdev (card->have_ac97);
+
+	DPRINTK ("EXIT\n");
+}
+
+#if 0
+#ifdef CONFIG_PROC_FS
+
+/****************************************************************
+ *
+ * /proc/driver/via82cxxx/info
+ *
+ *
+ */
+static int via_info_read_proc (char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+#define YN(val,bit) (((val) & (bit)) ? "yes" : "no")
+
+	int len = 0, i;
+	u8 r40, r41, r42, r44;
+	
+	DPRINTK ("ENTER\n");
+
+	len += sprintf (page+len, VIA_CARD_NAME "\n\n");
+	
+	for (i = 0; i < num_cards; i++) {
+		pci_read_config_byte (cards[i].pdev, 0x40, &r40);
+		pci_read_config_byte (cards[i].pdev, 0x42, &r41);
+		pci_read_config_byte (cards[i].pdev, 0x42, &r42);
+		pci_read_config_byte (cards[i].pdev, 0x44, &r44);
+	
+		len += sprintf (page+len,
+			"40  AC97 Codec Ready: %s\n"
+			"    AC97 Codec Low-power: %s\n"
+			"    Secondary Codec Ready: %s\n"
+
+			"41  AC-Link Interface Enable: %s\n"
+
+			"42  Game port enabled: %s\n"
+			"    SoundBlaster enabled: %s\n"
+			"    FM enabled: %s\n"
+			"    MIDI enabled: %s\n"
+			
+			"44  AC-Link Interface Access: %s\n"
+			"    Secondary Codec Support: %s\n"
+			
+			"\n",
+			
+			YN (r40, VIA_CR40_AC97_READY),
+			YN (r40, VIA_CR40_AC97_LOW_POWER),
+			YN (r40, VIA_CR40_SECONDARY_READY),
+
+			YN (r41, VIA_CR41_ACLINK_ENABLE),
+
+			YN (r42, VIA_CR42_GAME_ENABLE),
+			YN (r42, VIA_CR42_SB_ENABLE),
+			YN (r42, VIA_CR42_FM_ENABLE),
+			YN (r42, VIA_CR42_MIDI_ENABLE),
+
+			YN (r44, VIA_CR44_AC_LINK_ACCESS),
+			YN (r44, VIA_CR44_SECOND_CODEC_SUPPORT)
+			
+			);
+	}
+	
+	DPRINTK("EXIT, returning %d\n", len);
+	return len;
+
+#undef YN
+}
+
+
+/****************************************************************
+ *
+ * /proc/driver/via82cxxx
+ *
+ *
+ */
+
+static int __init via_init_proc (void)
+{
+	DPRINTK ("ENTER\n");
+
+
+	proc_mkdir ("driver/via_audio", 0);
+	create_proc_read_entry ("driver/via_audio/info", 0, 0, via_info_read_proc, NULL);
+	
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+
+
+static void __exit via_cleanup_proc (void)
+{
+	DPRINTK ("ENTER\n");
+	remove_proc_entry ("driver/via_audio/info", NULL);
+	remove_proc_entry ("driver/via_audio", NULL);
+	DPRINTK("EXIT\n");
+}
+
+
+#else
+#endif /* CONFIG_PROC_FS */
+
+#endif /* if 0 */
+
+static inline int via_init_proc (void) { return 0; }
+static inline void via_cleanup_proc (void) {}
+
+
+
+/****************************************************************
+ *
+ * Legacy SoundBlaster Pro, FM support via OSS
+ *
+ *
+ */
+
+static void via_attach_sb(struct address_info *hw_config)
+{
+	DPRINTK ("ENTER\n");
+
+	if(!sb_dsp_init(hw_config))
+		hw_config->slots[0] = -1;
+
+	DPRINTK("EXIT\n");
+}
+
+
+static int via_probe_sb(struct address_info *hw_config)
+{
+	DPRINTK ("ENTER\n");
+
+	if (check_region(hw_config->io_base, 16))
+	{
+		printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n",
+		       hw_config->io_base);
+		return 0;
+	}
+	DPRINTK("EXIT after sb_dsp_detect\n");
+	return sb_dsp_detect(hw_config, 0, 0);
+}
+
+
+static void via_unload_sb(struct address_info *hw_config)
+{
+	DPRINTK ("ENTER\n");
+
+	if(hw_config->slots[0] != -1)
+		sb_dsp_unload(hw_config, 1);
+
+	DPRINTK("EXIT\n");
+}
+
+
+static const struct {
+	int sb_irq,
+	    sb_dma,
+	    midi_base,
+	    sb_io_base;
+} via_pnp_data[] __initdata = {
+	{ 5, 0, 0x300, 0x220 },
+	{ 7, 1, 0x310, 0x240 },
+	{ 9, 2, 0x320, 0x260 },
+	{ 10,3, 0x330, 0x280 },
+};
+
+
+/****************************************************************
+ *
+ * Chip setup and kernel registration
+ *
+ *
+ */
+
+static int __init via82cxxx_install (struct pci_dev *pcidev)
+{
+	int sb_io_base;
+	int sb_irq;
+	int sb_dma;
+	int midi_base, rc;
+	u8 tmp8;
+	struct via_info *card = &cards[num_cards];
+	
+	DPRINTK ("ENTER\n");
+
+	card->pdev = pcidev;
+	card->have_ac97 = -1;
+	
+	/* turn off legacy features, if not already */
+	pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
+	tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
+		  VIA_CR42_FM_ENABLE);
+	pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
+
+	/* 
+	 * try to init AC97 mixer device
+	 */
+	rc = via_attach_ac97 (card);
+	if (rc) {
+		printk (KERN_WARNING PFX
+			"AC97 init failed, SB legacy mode only\n");
+	}
+	
+	/* turn on legacy features */
+	pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
+	tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
+		VIA_CR42_FM_ENABLE;
+	pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
+
+	/* read legacy PNP info byte */
+	pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8);
+	pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8);
+	
+	sb_irq = via_pnp_data[((tmp8 >> 6) & 0x03)].sb_irq;
+	sb_dma = via_pnp_data[((tmp8 >> 4) & 0x03)].sb_dma;
+	midi_base = via_pnp_data[((tmp8 >> 2) & 0x03)].midi_base;
+	sb_io_base = via_pnp_data[(tmp8 & 0x03)].sb_io_base;
+
+	udelay(100);
+	
+	printk(KERN_INFO PFX "legacy "
+	       "MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n",
+		midi_base, sb_io_base, sb_irq, sb_dma);
+		
+	card->sb_data.name = VIA_CARD_NAME;
+	card->sb_data.card_subtype = MDL_SBPRO;
+	card->sb_data.io_base = sb_io_base;
+	card->sb_data.irq = sb_irq;
+	card->sb_data.dma = sb_dma;
+	
+	/* register legacy SoundBlaster Pro */
+	if (!via_probe_sb (&card->sb_data)) {
+		printk (KERN_ERR PFX
+			"SB probe @ 0x%X failed, aborting\n",
+			sb_io_base);
+		DPRINTK ("EXIT, returning -1\n");
+		return -1;
+	}
+	via_attach_sb (&card->sb_data);
+
+	card->opl3_data.name = card->sb_data.name;
+	card->opl3_data.io_base = midi_base;
+	card->opl3_data.irq = -1;
+	
+	/* register legacy MIDI */
+	if (!probe_uart401 (&card->opl3_data)) {
+		printk (KERN_WARNING PFX
+			"MIDI probe @ 0x%X failed, continuing\n",
+			midi_base);
+		card->opl3_data.io_base = 0;
+	} else {
+		attach_uart401 (&card->opl3_data);
+	}
+
+	num_cards++;	
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+/*
+ * 	This loop walks the PCI configuration database and finds where
+ *	the sound cards are.
+ *
+ *	Note - only a single PCI scan occurs, eliminating possibility
+ *	of multiple audio chips
+ *
+ */
+ 
+static int __init probe_via82cxxx (void)
+{
+	struct pci_dev *pcidev = NULL;
+
+	DPRINTK ("ENTER\n");
+
+	pcidev = pci_find_device (PCI_VENDOR_ID_VIA,
+				  PCI_DEVICE_ID_VIA_82C686_5, NULL);
+
+	if (!pcidev || via82cxxx_install (pcidev) != 0) {
+		printk (KERN_ERR PFX "audio init failed\n");
+		DPRINTK ("EXIT, returning -1\n");
+		return -1;
+	}
+
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+
+/*
+ *	This function is called when the user or kernel loads the 
+ *	module into memory.
+ */
+
+
+static int init_via82cxxx_module(void)
+{
+	u8 tmp;
+	int i;
+	const char *rev = "unknown!";
+	
+	memset (cards, 0, sizeof (cards));
+	
+	DPRINTK ("ENTER\n");
+
+	if (!pci_present ()) {
+		printk (KERN_DEBUG PFX "PCI not present, exiting\n");
+		DPRINTK ("EXIT, returning -ENODEV\n");
+		return -ENODEV;
+	}
+
+	if (probe_via82cxxx() != 0) {
+		printk(KERN_ERR PFX "probe failed, aborting\n");
+		/* XXX unload cards registered so far, if any */
+		DPRINTK ("EXIT, returning -ENODEV\n");
+		return -ENODEV;
+	}
+
+	pci_read_config_byte (cards[0].pdev, PCI_REVISION_ID, &tmp);
+	for (i = 0; i < arraysize(via_chip_revs); i++)
+		if (via_chip_revs[i].revision == tmp) {
+			rev = via_chip_revs[i].rev_name;
+			break;
+		}
+	printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n");
+	printk (KERN_INFO PFX "Chip rev %s.  Features: SBPro compat%s%s\n",
+		rev,
+		cards[0].opl3_data.io_base == 0 ? "" : ", MPU-401 MIDI",
+		cards[0].have_ac97 == -1 ? "" : ", AC97 mixer");
+	
+	if (via_init_proc () != 0) {
+		printk (KERN_WARNING PFX
+			"Unable to init experimental /proc, ignoring\n");
+	}
+
+	/*
+	 *	Binds us to the sound subsystem	
+	 */
+	SOUND_LOCK;
+	DPRINTK ("EXIT, returning 0\n");
+	return 0;
+}
+
+int init_module(void) {
+	return init_via82cxxx_module();
+}
+
+/*
+ *	This is called when it is removed. It will only be removed 
+ *	when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK
+ *	macros hide the entire work for this.
+ */
+ 
+static void cleanup_via82cxxx_module(void)
+{
+	DPRINTK("ENTER\n");
+	
+	if (cards[0].opl3_data.io_base)
+		unload_uart401 (&cards[0].opl3_data);
+
+	via_unload_sb (&cards[0].sb_data);
+	
+	via_unload_ac97 (&cards[0]);
+
+	via_cleanup_proc ();
+	
+	/*
+	 *	Final clean up with the sound layer
+	 */
+	SOUND_LOCK_END;
+
+	DPRINTK("EXIT\n");
+}
+
+void cleanup_module(void) {
+	cleanup_via82cxxx_module();
+}
+
diff -urN linux-2.2.16-pre4/fs/exec.c linux/fs/exec.c
--- linux-2.2.16-pre4/fs/exec.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/exec.c	Mon Dec  3 22:03:54 2001
@@ -515,6 +515,8 @@
 	/* This is the point of no return */
 	release_old_signals(oldsig);
 
+	current->sas_ss_sp = current->sas_ss_size = 0;
+
 	if (current->euid == current->uid && current->egid == current->gid)
 		current->dumpable = 1;
 	name = bprm->filename;
diff -urN linux-2.2.16-pre4/fs/nls/nls_base.c linux/fs/nls/nls_base.c
--- linux-2.2.16-pre4/fs/nls/nls_base.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_base.c	Mon Dec  3 22:03:54 2001
@@ -15,6 +15,7 @@
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
+#include <linux/init.h>
 #include <asm/byteorder.h>
 
 static struct nls_table *tables = (struct nls_table *) NULL;
@@ -429,7 +430,7 @@
 EXPORT_SYMBOL(utf8_wctomb);
 EXPORT_SYMBOL(utf8_wcstombs);
 
-int init_nls(void)
+int __init init_nls(void)
 {
 #ifdef CONFIG_NLS_ISO8859_1
 	init_nls_iso8859_1();
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp437.c linux/fs/nls/nls_cp437.c
--- linux-2.2.16-pre4/fs/nls/nls_cp437.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp437.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -435,7 +436,7 @@
 	NULL
 };
 
-int init_nls_cp437(void)
+int __init init_nls_cp437(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp737.c linux/fs/nls/nls_cp737.c
--- linux-2.2.16-pre4/fs/nls/nls_cp737.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp737.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -364,7 +365,7 @@
 	NULL
 };
 
-int init_nls_cp737(void)
+int __init init_nls_cp737(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp775.c linux/fs/nls/nls_cp775.c
--- linux-2.2.16-pre4/fs/nls/nls_cp775.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp775.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -363,7 +364,7 @@
 	NULL
 };
 
-int init_nls_cp775(void)
+int __init init_nls_cp775(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp850.c linux/fs/nls/nls_cp850.c
--- linux-2.2.16-pre4/fs/nls/nls_cp850.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp850.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -327,7 +328,7 @@
 	NULL
 };
 
-int init_nls_cp850(void)
+int __init init_nls_cp850(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp852.c linux/fs/nls/nls_cp852.c
--- linux-2.2.16-pre4/fs/nls/nls_cp852.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp852.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -327,7 +328,7 @@
 	NULL
 };
 
-int init_nls_cp852(void)
+int __init init_nls_cp852(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp855.c linux/fs/nls/nls_cp855.c
--- linux-2.2.16-pre4/fs/nls/nls_cp855.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp855.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -327,7 +328,7 @@
 	NULL
 };
 
-int init_nls_cp855(void)
+int __init init_nls_cp855(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp857.c linux/fs/nls/nls_cp857.c
--- linux-2.2.16-pre4/fs/nls/nls_cp857.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp857.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -291,7 +292,7 @@
 	NULL
 };
 
-int init_nls_cp857(void)
+int __init init_nls_cp857(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp860.c linux/fs/nls/nls_cp860.c
--- linux-2.2.16-pre4/fs/nls/nls_cp860.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp860.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -399,7 +400,7 @@
 	NULL
 };
 
-int init_nls_cp860(void)
+int __init init_nls_cp860(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp861.c linux/fs/nls/nls_cp861.c
--- linux-2.2.16-pre4/fs/nls/nls_cp861.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp861.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -435,7 +436,7 @@
 	NULL
 };
 
-int init_nls_cp861(void)
+int __init init_nls_cp861(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp862.c linux/fs/nls/nls_cp862.c
--- linux-2.2.16-pre4/fs/nls/nls_cp862.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp862.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -471,7 +472,7 @@
 	NULL
 };
 
-int init_nls_cp862(void)
+int __init init_nls_cp862(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp863.c linux/fs/nls/nls_cp863.c
--- linux-2.2.16-pre4/fs/nls/nls_cp863.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp863.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -435,7 +436,7 @@
 	NULL
 };
 
-int init_nls_cp863(void)
+int __init init_nls_cp863(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp864.c linux/fs/nls/nls_cp864.c
--- linux-2.2.16-pre4/fs/nls/nls_cp864.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp864.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -426,7 +427,7 @@
 	NULL
 };
 
-int init_nls_cp864(void)
+int __init init_nls_cp864(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp865.c linux/fs/nls/nls_cp865.c
--- linux-2.2.16-pre4/fs/nls/nls_cp865.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp865.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -435,7 +436,7 @@
 	NULL
 };
 
-int init_nls_cp865(void)
+int __init init_nls_cp865(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp866.c linux/fs/nls/nls_cp866.c
--- linux-2.2.16-pre4/fs/nls/nls_cp866.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp866.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -363,7 +364,7 @@
 	NULL
 };
 
-int init_nls_cp866(void)
+int __init init_nls_cp866(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp869.c linux/fs/nls/nls_cp869.c
--- linux-2.2.16-pre4/fs/nls/nls_cp869.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp869.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -327,7 +328,7 @@
 	NULL
 };
 
-int init_nls_cp869(void)
+int __init init_nls_cp869(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp874.c linux/fs/nls/nls_cp874.c
--- linux-2.2.16-pre4/fs/nls/nls_cp874.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp874.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -291,7 +292,7 @@
 	NULL
 };
 
-int init_nls_cp874(void)
+int __init init_nls_cp874(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp932.c linux/fs/nls/nls_cp932.c
--- linux-2.2.16-pre4/fs/nls/nls_cp932.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp932.c	Mon Dec  3 22:03:54 2001
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode c2u_81[256] = {
 	{0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, /* 0x00-0x03 */
@@ -9809,7 +9810,7 @@
 	NULL
 };
 
-int init_nls_cp932(void)
+int __init init_nls_cp932(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp936.c linux/fs/nls/nls_cp936.c
--- linux-2.2.16-pre4/fs/nls/nls_cp936.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp936.c	Mon Dec  3 22:03:54 2001
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode c2u_81[256] = {
 	{0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, /* 0x00-0x03 */
@@ -15576,7 +15577,7 @@
 	NULL
 };
 
-int init_nls_cp936(void)
+int __init init_nls_cp936(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp949.c linux/fs/nls/nls_cp949.c
--- linux-2.2.16-pre4/fs/nls/nls_cp949.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp949.c	Mon Dec  3 22:03:54 2001
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode c2u_81[256] = {
 	{0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, /* 0x00-0x03 */
@@ -18364,7 +18365,7 @@
 	NULL
 };
 
-int init_nls_cp949(void)
+int __init init_nls_cp949(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_cp950.c linux/fs/nls/nls_cp950.c
--- linux-2.2.16-pre4/fs/nls/nls_cp950.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_cp950.c	Mon Dec  3 22:03:54 2001
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode c2u_A1[256] = {
 	{0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, {0x00, 0x3F}, /* 0x00-0x03 */
@@ -12584,7 +12585,7 @@
 	NULL
 };
 
-int init_nls_cp950(void)
+int __init init_nls_cp950(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-1.c linux/fs/nls/nls_iso8859-1.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-1.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-1.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -215,7 +216,7 @@
 	NULL
 };
 
-int init_nls_iso8859_1(void)
+int __init init_nls_iso8859_1(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-14.c linux/fs/nls/nls_iso8859-14.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-14.c	Wed Aug 25 17:29:49 1999
+++ linux/fs/nls/nls_iso8859-14.c	Mon Dec  3 22:03:54 2001
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -219,6 +220,30 @@
 	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,	NULL,
 };
 
+static void uni2char(unsigned char ch, unsigned char cl, unsigned char *out, int boundlen, int *outlen)
+{
+	unsigned char *uni2charset;
+
+	if (boundlen <= 0)
+		return;
+
+	uni2charset = page_uni2charset[ch];
+	if (uni2charset && uni2charset[cl])
+		out[0] = uni2charset[cl];
+	else
+		out[0] = '?';
+	*outlen = 1;
+	return;
+}
+
+static void char2uni(unsigned char *rawstring, int *offset, unsigned char *uni1, unsigned char *uni2)
+{
+	*uni1 = charset2uni[*rawstring].uni1;
+	*uni2 = charset2uni[*rawstring].uni2;
+	*offset = 1;
+	return;
+}
+
 static void inc_use_count(void)
 {
 	MOD_INC_USE_COUNT;
@@ -231,14 +256,14 @@
 
 static struct nls_table table = {
 	"iso8859-14",
-	page_uni2charset,
-	charset2uni,
+	uni2char,
+	char2uni,
 	inc_use_count,
 	dec_use_count,
 	NULL
 };
 
-int init_nls_iso8859_14(void)
+int __init init_nls_iso8859_14(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-15.c linux/fs/nls/nls_iso8859-15.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-15.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-15.c	Mon Dec  3 22:03:54 2001
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -255,7 +256,7 @@
 	NULL
 };
 
-int init_nls_iso8859_15(void)
+int __init init_nls_iso8859_15(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-2.c linux/fs/nls/nls_iso8859-2.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-2.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-2.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -287,7 +288,7 @@
 	NULL
 };
 
-int init_nls_iso8859_2(void)
+int __init init_nls_iso8859_2(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-3.c linux/fs/nls/nls_iso8859-3.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-3.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-3.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -287,7 +288,7 @@
 	NULL
 };
 
-int init_nls_iso8859_3(void)
+int __init init_nls_iso8859_3(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-4.c linux/fs/nls/nls_iso8859-4.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-4.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-4.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -287,7 +288,7 @@
 	NULL
 };
 
-int init_nls_iso8859_4(void)
+int __init init_nls_iso8859_4(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-5.c linux/fs/nls/nls_iso8859-5.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-5.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-5.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -291,7 +292,7 @@
 	NULL
 };
 
-int init_nls_iso8859_5(void)
+int __init init_nls_iso8859_5(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-6.c linux/fs/nls/nls_iso8859-6.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-6.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-6.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -251,7 +252,7 @@
 	NULL
 };
 
-int init_nls_iso8859_6(void)
+int __init init_nls_iso8859_6(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-7.c linux/fs/nls/nls_iso8859-7.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-7.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-7.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -327,7 +328,7 @@
 	NULL
 };
 
-int init_nls_iso8859_7(void)
+int __init init_nls_iso8859_7(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-8.c linux/fs/nls/nls_iso8859-8.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-8.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-8.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -291,7 +292,7 @@
 	NULL
 };
 
-int init_nls_iso8859_8(void)
+int __init init_nls_iso8859_8(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_iso8859-9.c linux/fs/nls/nls_iso8859-9.c
--- linux-2.2.16-pre4/fs/nls/nls_iso8859-9.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_iso8859-9.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -251,7 +252,7 @@
 	NULL
 };
 
-int init_nls_iso8859_9(void)
+int __init init_nls_iso8859_9(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/nls/nls_koi8-r.c linux/fs/nls/nls_koi8-r.c
--- linux-2.2.16-pre4/fs/nls/nls_koi8-r.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/nls/nls_koi8-r.c	Mon Dec  3 22:03:54 2001
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/nls.h>
+#include <linux/init.h>
 
 static struct nls_unicode charset2uni[256] = {
 	/* 0x00*/
@@ -363,7 +364,7 @@
 	NULL
 };
 
-int init_nls_koi8_r(void)
+int __init init_nls_koi8_r(void)
 {
 	return register_nls(&table);
 }
diff -urN linux-2.2.16-pre4/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.2.16-pre4/fs/proc/array.c	Mon Dec  3 22:03:48 2001
+++ linux/fs/proc/array.c	Mon Dec  3 22:03:54 2001
@@ -651,6 +651,26 @@
 			fp = rw->ins[6] + bias;
 		} while (++count < 16);
 	}
+#elif defined (__s390__)
+        {
+                unsigned long ksp, backchain, ip;
+                unsigned long stack_page;
+                int count = 0;
+
+                stack_page = (unsigned long)p;
+                ksp = p->tss.ksp;
+                if (!stack_page || ksp < stack_page || ksp >= 8188+stack_page)
+                        return 0;
+                backchain = (*(unsigned long *) ksp) & 0x7fffffff;
+                do {
+                        if (backchain < stack_page || backchain >= 8188+stack_page)
+                                return 0;
+                        ip = (*(unsigned long *) (backchain+56)) & 0x7fffffff;
+                        if (ip < first_sched || ip >= last_sched)
+                                return ip;
+                        backchain = (*(unsigned long *) backchain) & 0x7fffffff;
+                } while (count++ < 16);
+        }
 #endif
 
 	return 0;
diff -urN linux-2.2.16-pre4/include/asm-s390/irq.h linux/include/asm-s390/irq.h
--- linux-2.2.16-pre4/include/asm-s390/irq.h	Mon Dec  3 22:03:48 2001
+++ linux/include/asm-s390/irq.h	Mon Dec  3 22:03:54 2001
@@ -365,6 +365,8 @@
 #define DEVSTAT_DEVICE_GONE        0x00000040
 #define DEVSTAT_DEVICE_OWNED       0x00000080
 #define DEVSTAT_CLEAR_FUNCTION     0x00000100
+#define DEVSTAT_PCI                0x00000200
+#define DEVSTAT_SUSPENDED          0x00000400
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
diff -urN linux-2.2.16-pre4/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
--- linux-2.2.16-pre4/include/asm-s390/pgtable.h	Mon Dec  3 22:03:48 2001
+++ linux/include/asm-s390/pgtable.h	Mon Dec  3 22:03:54 2001
@@ -630,22 +630,27 @@
 extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
 {
         address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-        if (pmd_none(*pmd)) {
-                pte_t * page = (pte_t *) get_pte_fast();
 
-                if (!page)
-                        return get_pte_kernel_slow(pmd, address);
-                pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(page);
-                pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(page+1024);
-                pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(page+2048);
-                pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(page+3072);
-                return page + address;
-        }
-        if (pmd_bad(*pmd)) {
-                __bad_pte_kernel(pmd);
-                return NULL;
-        }
+        if (pmd_none(*pmd))
+                goto getnew;
+        if (pmd_bad(*pmd))
+                goto fix;
         return (pte_t *) pmd_page(*pmd) + address;
+getnew:
+{
+        unsigned long page = (unsigned long) get_pte_fast();
+
+        if (!page)
+                return get_pte_kernel_slow(pmd, address);
+        pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(page);
+        pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(page+1024);
+        pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(page+2048);
+        pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(page+3072);
+        return (pte_t *) page + address;
+}
+fix:
+        __bad_pte_kernel(pmd);
+        return NULL;
 }
 
 extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
diff -urN linux-2.2.16-pre4/include/asm-s390/ptrace.h linux/include/asm-s390/ptrace.h
--- linux-2.2.16-pre4/include/asm-s390/ptrace.h	Mon Dec  3 22:03:48 2001
+++ linux/include/asm-s390/ptrace.h	Mon Dec  3 22:03:54 2001
@@ -1,3 +1,4 @@
+
 /*
  *  include/asm-s390/ptrace.h
  *
@@ -133,6 +134,8 @@
  * this is the way intel does it
  */
 	per_struct per_info;
+	addr_t  ieee_instruction_pointer; 
+	/* Used to give failing instruction back to user for ieee exceptions */
 };
 
 typedef struct user_regs_struct user_regs_struct;
@@ -269,8 +272,9 @@
 	PT_CR_9=pt_off(per_info.control_regs.words.cr[0]),
 	PT_CR_10=pt_off(per_info.control_regs.words.cr[1]),
 	PT_CR_11=pt_off(per_info.control_regs.words.cr[2]),
-	PT_LASTOFF=PT_CR_11,
-	PT_ENDREGS=offsetof(user_regs_struct,per_info.lowcore.words.perc_atmid)
+	PT_IEEE_IP=pt_off(ieee_instruction_pointer),
+	PT_LASTOFF=PT_IEEE_IP,
+	PT_ENDREGS=sizeof(user_regs_struct)-1
 };
 
 #define PTRACE_AREA \
diff -urN linux-2.2.16-pre4/include/asm-s390/s390-regs-common.h linux/include/asm-s390/s390-regs-common.h
--- linux-2.2.16-pre4/include/asm-s390/s390-regs-common.h	Wed May  3 17:16:51 2000
+++ linux/include/asm-s390/s390-regs-common.h	Mon Dec  3 22:03:54 2001
@@ -69,6 +69,12 @@
 	freg_t  fprs[NUM_FPRS];              
 } s390_fp_regs;
 
+#define FPC_DXC_MASK            0x0000FF00
+#define FPC_EXCEPTION_MASK      0xF8000000
+#define FPC_FLAGS_MASK          0x00F80000
+#define FPC_RM_MASK             0x00000003
+
+
 /*
   gdb structures & the kernel have this much always in common
  */
diff -urN linux-2.2.16-pre4/include/asm-s390/s390io.h linux/include/asm-s390/s390io.h
--- linux-2.2.16-pre4/include/asm-s390/s390io.h	Mon Dec  3 22:03:48 2001
+++ linux/include/asm-s390/s390io.h	Mon Dec  3 22:03:54 2001
@@ -69,6 +69,7 @@
      devstat_t     devstat;       /* device status */
      ccw1_t       *qcpa;          /* queued channel program */
      ccw1_t        senseccw;      /* ccw for sense command */
+     __u8          sense_data[32];/* buffer for basic sense */
      unsigned int  stctl;         /* accumulated status control from irb */
      unsigned long qintparm;      /* queued interruption parameter  */
      unsigned long qflag;         /* queued flags */
diff -urN linux-2.2.16-pre4/include/linux/capability.h linux/include/linux/capability.h
--- linux-2.2.16-pre4/include/linux/capability.h	Tue Oct 26 17:53:42 1999
+++ linux/include/linux/capability.h	Mon Dec  3 22:03:54 2001
@@ -10,7 +10,6 @@
 #define _LINUX_CAPABILITY_H
 
 #include <linux/types.h>
-#include <linux/fs.h>
 
 /* User-level do most of the mapping between kernel and user
    capabilities based on the version tag given by the kernel. The
diff -urN linux-2.2.16-pre4/include/linux/nls.h linux/include/linux/nls.h
--- linux-2.2.16-pre4/include/linux/nls.h	Mon Dec  3 22:03:48 2001
+++ linux/include/linux/nls.h	Mon Dec  3 22:03:54 2001
@@ -36,6 +36,7 @@
 extern int init_nls_iso8859_7(void);
 extern int init_nls_iso8859_8(void);
 extern int init_nls_iso8859_9(void);
+extern int init_nls_iso8859_14(void);
 extern int init_nls_iso8859_15(void);
 extern int init_nls_cp437(void);
 extern int init_nls_cp737(void);
diff -urN linux-2.2.16-pre4/include/linux/pci.h linux/include/linux/pci.h
--- linux-2.2.16-pre4/include/linux/pci.h	Mon Dec  3 22:03:48 2001
+++ linux/include/linux/pci.h	Mon Dec  3 22:03:54 2001
@@ -1045,6 +1045,9 @@
 #define PCI_VENDOR_ID_AFAVLAB		0x14db
 #define PCI_DEVICE_ID_AFAVLAB_TK9902	0x2120
 
+#define PCI_VENDOR_ID_TIMEDIA		0x1409
+#define PCI_DEVICE_ID_TIMEDIA_4008A	0x7268
+
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
 
diff -urN linux-2.2.16-pre4/include/linux/timex.h linux/include/linux/timex.h
--- linux-2.2.16-pre4/include/linux/timex.h	Tue May 11 10:35:44 1999
+++ linux/include/linux/timex.h	Mon Dec  3 22:03:54 2001
@@ -136,6 +136,10 @@
  * Pick up the architecture specific timex specifications
  */
 #include <asm/timex.h>
+/*
+ * Pick up the definition of timeval
+ */
+#include <linux/time.h>
 
 /* LATCH is used in the interval timer and ftape setup. */
 #define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
diff -urN linux-2.2.16-pre4/include/scsi/sg.h linux/include/scsi/sg.h
--- linux-2.2.16-pre4/include/scsi/sg.h	Tue Jan  4 10:12:25 2000
+++ linux/include/scsi/sg.h	Mon Dec  3 22:03:54 2001
@@ -9,13 +9,15 @@
 Original driver (sg.h):
 *       Copyright (C) 1992 Lawrence Foard
 2.x extensions to driver:
-*       Copyright (C) 1998, 1999 Douglas Gilbert
+*       Copyright (C) 1998 - 2000 Douglas Gilbert
 
-
-    Version: 2.1.36 (991008)
+    Version: 2.1.37 (20000504)
     This version for 2.2.x series kernels
     D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
 
+    Changes since 2.1.36 (991008)
+        - fix 0 length scatter gather requests + alignment
+        - activate SG_SCSI_RESET ioctl() [to work needs mid level changes]
     Changes since 2.1.34 (990603)
         - skipped 2.1.35 (never fully released)
         - add queuing info into struct sg_scsi_id
@@ -35,19 +37,24 @@
         - clean up logging of pointers to use %p (for 64 bit architectures)
         - rework usage of get_user/copy_to_user family of kernel calls
         - "disown" scsi_command blocks before releasing them
-    Changes since 2.1.30 (990320)
-        - memory tweaks: change flags on kmalloc (GFP_KERNEL to GFP_ATOMIC)
-        -                increase max allowable mid-level pool usage
 
+Map of SG verions to the Linux kernels in which they appear:
+       ----------        ----------------------------------
+       original          all kernels < 2.2.6
+       2.1.31            2.2.6 and 2.2.7
+       2.1.32            2.2.8 and 2.2.9
+       2.1.34            2.2.10 to 2.2.13
+       2.1.36            2.2.14 and 2.2.15
+       2.1.37            2.2.16
+       3.0.13            optional version 3 sg driver for 2.2 series
+       3.1.13            2.3.99-pre5, version 3 sg driver for 2.3 series
 
     New features and changes:
-        - per file descriptor (fd) write-read sequencing and command queues.
-        - command queuing supported (SG_MAX_QUEUE is maximum per fd).
+        - per file descriptor (fd) write-read sequencing
+        - command queuing supported
         - scatter-gather supported (allowing potentially megabyte transfers).
-        - the SCSI target, host and driver status are returned
-          in unused fields of sg_header (maintaining its original size).
-        - asynchronous notification support added (SIGPOLL, SIGIO) for
-          read()s (write()s should never block).
+        - more SCSI status information returned
+        - asynchronous notification support added (SIGPOLL, SIGIO)
         - pack_id logic added so read() can wait for a specific pack_id. 
         - uses memory > ISA_DMA_THRESHOLD if adapter allows it (e.g. a
           pci scsi adapter).
@@ -68,61 +75,21 @@
           calling the ioctl of the same name is a more flexible and
           safer approach.
         - adds several ioctl calls, see ioctl section below.
- 
- Good documentation on the original "sg" device interface and usage can be
- found in the Linux HOWTO document: "SCSI Programming HOWTO" (version 0.5)
- by Heiko Eissfeldt; last updated 7 May 1996. Here is a quick summary of
- sg basics:
- An SG device is accessed by writing SCSI commands plus any associated 
- outgoing data to it; the resulting status codes and any incoming data
- are then obtained by a read call. The device can be opened O_NONBLOCK
- (non-blocking) and poll() used to monitor its progress. The device may be
- opened O_EXCL which excludes other "sg" users from this device (but not 
- "sd", "st" or "sr" users). The buffer given to the write() call is made
- up as follows:
-        - struct sg_header image (see below)
-        - scsi command (6, 10 or 12 bytes long)
-        - data to be written to the device (if any)
-
- The buffer received from the corresponding read() call contains:
-        - struct sg_header image (check results + sense_buffer)
-        - data read back from device (if any)
-
- The given SCSI command has its LUN field overwritten internally by the
- value associated with the device that has been opened.
-
- This device currently uses "indirect IO" in the sense that data is
- DMAed into kernel buffers from the hardware and afterwards is
- transferred into the user space (or vice versa if you are writing).
- Transfer speeds or up to 20 to 30MBytes/sec have been measured using
- indirect IO. For faster throughputs "direct IO" which cuts out the
- double handling of data is required. This will also need a new interface.
-
- Grabbing memory for those kernel buffers used in this driver for DMA may
- cause the dreaded ENOMEM error. This error seems to be more prevalent 
- under early 2.2.x kernels than under the 2.0.x kernel series. For a given 
- (large) transfer the memory obtained by this driver must be contiguous or
- scatter-gather must be used (if supported by the adapter). [Furthermore, 
- ISA SCSI adapters can only use memory below the 16MB level on a i386.]
-
- When a "sg" device is open()ed O_RDWR then this driver will attempt to
- reserve a buffer of SG_DEF_RESERVED_SIZE that will be used by subsequent
- write()s on this file descriptor as long as:
-    -  it is not already in use (eg when command queuing is in use)
-    -  the write() does not call for a buffer size larger than the
-       reserved size.
- In these cases the write() will attempt to find the memory it needs for
- DMA buffers dynamically and in the worst case will fail with ENOMEM.
- The amount of memory actually reserved depends on various dynamic factors
- and can be checked with the SG_GET_RESERVED_SIZE ioctl(). [In a very
- tight memory situation it may yield 0!] The size of the reserved buffer
- can be changed with the SG_SET_RESERVED_SIZE ioctl(). It should be
- followed with a call to the SG_GET_RESERVED_SIZE ioctl() to find out how
- much was actually reserved.
 
- More documentation plus test and utility programs can be found at 
- http://www.torque.net/sg
+ Documentation
+ =============
+ A web site for SG device drivers can be found at:
+        http://www.torque.net/sg  [alternatively check the MAINTAINERS file]
+ The main documents are still based on 2.x versions:
+        http://www.torque.net/sg/p/scsi-generic.txt
+        http://www.torque.net/sg/p/scsi-generic_long.txt
+ The first document can also be found in the kernel source tree, probably at:
+        /usr/src/linux/Documentation/scsi-generic.txt .
+ Documentation on the changes and additions in 3.x version of the sg driver
+ can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
+ Utility and test programs are also available at that web site.
 */
+ 
 
 #define SG_MAX_SENSE 16   /* too little, unlikely to change in 2.2.x */
 
@@ -213,9 +180,13 @@
 #define SG_NEXT_CMD_LEN 0x2283  /* override SCSI command length with given
                    number on the next write() on this file descriptor */
 
-/* Returns -EBUSY if occupied else takes as input: 0 -> do nothing,
-   1 -> device reset or  2 -> bus reset (not operational yet) */
+/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
 #define SG_SCSI_RESET 0x2284
+/* Associated values that can be given to SG_SCSI_RESET follow */
+#define         SG_SCSI_RESET_NOTHING   0
+#define         SG_SCSI_RESET_DEVICE    1
+#define         SG_SCSI_RESET_BUS       2
+#define         SG_SCSI_RESET_HOST      3
 
 
 #define SG_SCATTER_SZ (8 * 4096)  /* PAGE_SIZE not available to user */
diff -urN linux-2.2.16-pre4/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.2.16-pre4/kernel/ksyms.c	Wed May  3 17:16:53 2000
+++ linux/kernel/ksyms.c	Mon Dec  3 22:03:54 2001
@@ -405,9 +405,7 @@
 EXPORT_SYMBOL(add_mouse_randomness);
 EXPORT_SYMBOL(fasync_helper);
 
-#ifdef CONFIG_BLK_DEV_MD
-EXPORT_SYMBOL(disk_name);	/* for md.c */
-#endif
+EXPORT_SYMBOL(disk_name);	/* for md.c and others */
 
 /* binfmt_aout */
 EXPORT_SYMBOL(get_write_access);
diff -urN linux-2.2.16-pre4/p_sg2136_sg2137 linux/p_sg2136_sg2137
--- linux-2.2.16-pre4/p_sg2136_sg2137	Wed Dec 31 16:00:00 1969
+++ linux/p_sg2136_sg2137	Mon Dec  3 22:03:55 2001
@@ -0,0 +1,291 @@
+--- linux/include/scsi/sg.h	Thu Jan 13 20:40:36 2000
++++ linux/include/scsi/sg.h2137	Thu May  4 01:25:19 2000
+@@ -9,13 +9,15 @@
+ Original driver (sg.h):
+ *       Copyright (C) 1992 Lawrence Foard
+ 2.x extensions to driver:
+-*       Copyright (C) 1998, 1999 Douglas Gilbert
+-
++*       Copyright (C) 1998 - 2000 Douglas Gilbert
+ 
+-    Version: 2.1.36 (991008)
++    Version: 2.1.37 (20000504)
+     This version for 2.2.x series kernels
+     D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
+ 
++    Changes since 2.1.36 (991008)
++        - fix 0 length scatter gather requests + alignment
++        - activate SG_SCSI_RESET ioctl() [to work needs mid level changes]
+     Changes since 2.1.34 (990603)
+         - skipped 2.1.35 (never fully released)
+         - add queuing info into struct sg_scsi_id
+@@ -35,19 +37,24 @@
+         - clean up logging of pointers to use %p (for 64 bit architectures)
+         - rework usage of get_user/copy_to_user family of kernel calls
+         - "disown" scsi_command blocks before releasing them
+-    Changes since 2.1.30 (990320)
+-        - memory tweaks: change flags on kmalloc (GFP_KERNEL to GFP_ATOMIC)
+-        -                increase max allowable mid-level pool usage
+ 
++Map of SG verions to the Linux kernels in which they appear:
++       ----------        ----------------------------------
++       original          all kernels < 2.2.6
++       2.1.31            2.2.6 and 2.2.7
++       2.1.32            2.2.8 and 2.2.9
++       2.1.34            2.2.10 to 2.2.13
++       2.1.36            2.2.14 and 2.2.15
++       2.1.37            2.2.16
++       3.0.13            optional version 3 sg driver for 2.2 series
++       3.1.13            2.3.99-pre5, version 3 sg driver for 2.3 series
+ 
+     New features and changes:
+-        - per file descriptor (fd) write-read sequencing and command queues.
+-        - command queuing supported (SG_MAX_QUEUE is maximum per fd).
++        - per file descriptor (fd) write-read sequencing
++        - command queuing supported
+         - scatter-gather supported (allowing potentially megabyte transfers).
+-        - the SCSI target, host and driver status are returned
+-          in unused fields of sg_header (maintaining its original size).
+-        - asynchronous notification support added (SIGPOLL, SIGIO) for
+-          read()s (write()s should never block).
++        - more SCSI status information returned
++        - asynchronous notification support added (SIGPOLL, SIGIO)
+         - pack_id logic added so read() can wait for a specific pack_id. 
+         - uses memory > ISA_DMA_THRESHOLD if adapter allows it (e.g. a
+           pci scsi adapter).
+@@ -68,61 +75,21 @@
+           calling the ioctl of the same name is a more flexible and
+           safer approach.
+         - adds several ioctl calls, see ioctl section below.
+- 
+- Good documentation on the original "sg" device interface and usage can be
+- found in the Linux HOWTO document: "SCSI Programming HOWTO" (version 0.5)
+- by Heiko Eissfeldt; last updated 7 May 1996. Here is a quick summary of
+- sg basics:
+- An SG device is accessed by writing SCSI commands plus any associated 
+- outgoing data to it; the resulting status codes and any incoming data
+- are then obtained by a read call. The device can be opened O_NONBLOCK
+- (non-blocking) and poll() used to monitor its progress. The device may be
+- opened O_EXCL which excludes other "sg" users from this device (but not 
+- "sd", "st" or "sr" users). The buffer given to the write() call is made
+- up as follows:
+-        - struct sg_header image (see below)
+-        - scsi command (6, 10 or 12 bytes long)
+-        - data to be written to the device (if any)
+-
+- The buffer received from the corresponding read() call contains:
+-        - struct sg_header image (check results + sense_buffer)
+-        - data read back from device (if any)
+-
+- The given SCSI command has its LUN field overwritten internally by the
+- value associated with the device that has been opened.
+ 
+- This device currently uses "indirect IO" in the sense that data is
+- DMAed into kernel buffers from the hardware and afterwards is
+- transferred into the user space (or vice versa if you are writing).
+- Transfer speeds or up to 20 to 30MBytes/sec have been measured using
+- indirect IO. For faster throughputs "direct IO" which cuts out the
+- double handling of data is required. This will also need a new interface.
+-
+- Grabbing memory for those kernel buffers used in this driver for DMA may
+- cause the dreaded ENOMEM error. This error seems to be more prevalent 
+- under early 2.2.x kernels than under the 2.0.x kernel series. For a given 
+- (large) transfer the memory obtained by this driver must be contiguous or
+- scatter-gather must be used (if supported by the adapter). [Furthermore, 
+- ISA SCSI adapters can only use memory below the 16MB level on a i386.]
+-
+- When a "sg" device is open()ed O_RDWR then this driver will attempt to
+- reserve a buffer of SG_DEF_RESERVED_SIZE that will be used by subsequent
+- write()s on this file descriptor as long as:
+-    -  it is not already in use (eg when command queuing is in use)
+-    -  the write() does not call for a buffer size larger than the
+-       reserved size.
+- In these cases the write() will attempt to find the memory it needs for
+- DMA buffers dynamically and in the worst case will fail with ENOMEM.
+- The amount of memory actually reserved depends on various dynamic factors
+- and can be checked with the SG_GET_RESERVED_SIZE ioctl(). [In a very
+- tight memory situation it may yield 0!] The size of the reserved buffer
+- can be changed with the SG_SET_RESERVED_SIZE ioctl(). It should be
+- followed with a call to the SG_GET_RESERVED_SIZE ioctl() to find out how
+- much was actually reserved.
+-
+- More documentation plus test and utility programs can be found at 
+- http://www.torque.net/sg
++ Documentation
++ =============
++ A web site for SG device drivers can be found at:
++        http://www.torque.net/sg  [alternatively check the MAINTAINERS file]
++ The main documents are still based on 2.x versions:
++        http://www.torque.net/sg/p/scsi-generic.txt
++        http://www.torque.net/sg/p/scsi-generic_long.txt
++ The first document can also be found in the kernel source tree, probably at:
++        /usr/src/linux/Documentation/scsi-generic.txt .
++ Documentation on the changes and additions in 3.x version of the sg driver
++ can be found at: http://www.torque.net/sg/p/scsi-generic_v3.txt
++ Utility and test programs are also available at that web site.
+ */
++ 
+ 
+ #define SG_MAX_SENSE 16   /* too little, unlikely to change in 2.2.x */
+ 
+@@ -213,9 +180,13 @@
+ #define SG_NEXT_CMD_LEN 0x2283  /* override SCSI command length with given
+                    number on the next write() on this file descriptor */
+ 
+-/* Returns -EBUSY if occupied else takes as input: 0 -> do nothing,
+-   1 -> device reset or  2 -> bus reset (not operational yet) */
++/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
+ #define SG_SCSI_RESET 0x2284
++/* Associated values that can be given to SG_SCSI_RESET follow */
++#define         SG_SCSI_RESET_NOTHING   0
++#define         SG_SCSI_RESET_DEVICE    1
++#define         SG_SCSI_RESET_BUS       2
++#define         SG_SCSI_RESET_HOST      3
+ 
+ 
+ #define SG_SCATTER_SZ (8 * 4096)  /* PAGE_SIZE not available to user */
+--- linux/drivers/scsi/sg.c	Thu Jan 13 20:40:23 2000
++++ linux/drivers/scsi/sg.c2137	Thu May  4 01:24:01 2000
+@@ -7,7 +7,7 @@
+  * Original driver (sg.c):
+  *        Copyright (C) 1992 Lawrence Foard
+  * 2.x extensions to driver:
+- *        Copyright (C) 1998, 1999 Douglas Gilbert
++ *        Copyright (C) 1998 - 2000 Douglas Gilbert
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -16,8 +16,8 @@
+  *
+  *  Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
+  */
+- static char * sg_version_str = "Version: 2.1.36 (991218)";
+- static int sg_version_num = 20136; /* 2 digits for each component */
++ static char * sg_version_str = "Version: 2.1.37 (20000504)";
++ static int sg_version_num = 20137; /* 2 digits for each component */
+ /*
+  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
+  *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
+@@ -100,7 +100,7 @@
+ static void sg_detach(Scsi_Device *);
+ 
+ 
+-struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff,
++struct Scsi_Device_Template sg_template = {NULL, "generic", "sg", NULL, 0xff,
+                                            SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
+                                            sg_detect, sg_init,
+                                            sg_finish, sg_attach, sg_detach};
+@@ -609,8 +609,29 @@
+             return -EBUSY;
+         result = get_user(val, (int *)arg);
+         if (result) return result;
+-        /* Don't do anything till scsi mod level visibility */
+-        return 0;
++        if (SG_SCSI_RESET_NOTHING == val)
++            return 0;
++#ifdef SCSI_TRY_RESET_DEVICE
++        switch (val)
++        {
++        case SG_SCSI_RESET_DEVICE:
++            val = SCSI_TRY_RESET_DEVICE;
++            break;
++        case SG_SCSI_RESET_BUS:
++            val = SCSI_TRY_RESET_BUS;
++            break;
++        case SG_SCSI_RESET_HOST:
++            val = SCSI_TRY_RESET_HOST;
++            break;
++        default:
++            return -EINVAL;
++        }
++        if(! capable(CAP_SYS_ADMIN))  return -EACCES;
++        return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO;
++#else
++        SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n"));
++        result = -EINVAL;
++#endif
+     case SCSI_IOCTL_SEND_COMMAND:
+         /* Allow SCSI_IOCTL_SEND_COMMAND without checking suser() since the
+            user already has read/write access to the generic device and so
+@@ -1124,6 +1145,8 @@
+ 
+     SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n", 
+                                max_buff_size)); 
++    if (max_buff_size <= 0)
++        return 0;
+     if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) {
+         sg_link_reserve(sfp, srp, max_buff_size);
+         sg_write_xfer(req_schp, inp, num_write_xfer);
+@@ -1351,6 +1374,8 @@
+     Sg_scatter_hold * rsv_schp = &sfp->reserve;
+ 
+     SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); 
++    /* round request up to next highest SG_SECTOR_SZ byte boundary */
++    size = (size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
+     if (rsv_schp->use_sg > 0) {
+         int k, num;
+         int rem = size;
+@@ -1431,12 +1456,12 @@
+ static Sg_request * sg_add_request(Sg_fd * sfp)
+ {
+     int k;
+-    Sg_request * resp = NULL;
+-    Sg_request * rp;
++    Sg_request * resp = sfp->headrp;
++    Sg_request * rp = sfp->req_arr;
+ 
+-    resp = sfp->headrp;
+-    rp = sfp->req_arr;
+     if (! resp) {
++        memset(rp, 0, sizeof(Sg_request));
++        rp->parentfp = sfp;
+         resp = rp;
+         sfp->headrp = resp;
+     }
+@@ -1444,12 +1469,15 @@
+         if (0 == sfp->cmd_q)
+             resp = NULL;   /* command queuing disallowed */
+         else {
+-            for (k = 0, rp; k < SG_MAX_QUEUE; ++k, ++rp) {
++            for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
+                 if (! rp->parentfp)
+                     break;
+             }
+             if (k < SG_MAX_QUEUE) {
+-                while (resp->nextrp) resp = resp->nextrp;
++                memset(rp, 0, sizeof(Sg_request));
++                rp->parentfp = sfp;
++                while (resp->nextrp) 
++                    resp = resp->nextrp;
+                 resp->nextrp = rp;
+                 resp = rp;
+             }
+@@ -1458,11 +1486,7 @@
+         }
+     }
+     if (resp) {
+-        resp->parentfp = sfp;
+         resp->nextrp = NULL;
+-        resp->res_used = 0;
+-        memset(&resp->data, 0, sizeof(Sg_scatter_hold));
+-        memset(&resp->header, 0, sizeof(struct sg_header));
+         resp->my_cmdp = NULL;
+     }
+     return resp;
+@@ -1478,14 +1502,14 @@
+         return 0;
+     prev_rp = sfp->headrp;
+     if (srp == prev_rp) {
+-        prev_rp->parentfp = NULL;
+         sfp->headrp = prev_rp->nextrp;
++        prev_rp->parentfp = NULL;
+         return 1;
+     }
+     while ((rp = prev_rp->nextrp)) {
+         if (srp == rp) {
+-            rp->parentfp = NULL;
+             prev_rp->nextrp = rp->nextrp;
++            rp->parentfp = NULL;
+             return 1;
+         }
+         prev_rp = rp;
