diff -u --recursive --new-file v1.3.13/linux/Makefile linux/Makefile
--- v1.3.13/linux/Makefile	Thu Jul 27 10:13:16 1995
+++ linux/Makefile	Thu Jul 27 10:32:17 1995
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 13
+SUBLEVEL = 14
 
 ARCH = i386
 
diff -u --recursive --new-file v1.3.13/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v1.3.13/linux/drivers/block/Makefile	Tue Jul 11 10:02:48 1995
+++ linux/drivers/block/Makefile	Mon Jul 31 11:27:10 1995
@@ -30,9 +30,18 @@
 BLOCK_MODULE_OBJS := $(MODULES) floppy.o
 endif
 
+ifdef CONFIG_AZTCD
+OBJS := $(OBJS) aztcd.o
+SRCS := $(SRCS) aztcd.c
+else
+BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) aztcd.o
+endif #CONFIG_AZTCD
+
 ifdef CONFIG_CDU31A
 OBJS := $(OBJS) cdu31a.o
 SRCS := $(SRCS) cdu31a.c
+else
+BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) cdu31a.o
 endif #CONFIG_CDU31A
 
 ifdef CONFIG_MCD
@@ -70,13 +79,6 @@
 OBJS := $(OBJS) sbpcd4.o
 SRCS := $(SRCS) sbpcd4.c
 endif #CONFIG_SBPCD4
-
-ifdef CONFIG_AZTCD
-OBJS := $(OBJS) aztcd.o
-SRCS := $(SRCS) aztcd.c
-else
-BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) aztcd.o
-endif #CONFIG_AZTCD
 
 ifdef CONFIG_CDU535
 OBJS := $(OBJS) sonycd535.o
diff -u --recursive --new-file v1.3.13/linux/drivers/block/README.aztcd linux/drivers/block/README.aztcd
--- v1.3.13/linux/drivers/block/README.aztcd	Tue Jul 25 18:21:20 1995
+++ linux/drivers/block/README.aztcd	Mon Jul 31 11:27:10 1995
@@ -1,7 +1,8 @@
+$Id: README.aztcd,v 1.50 1995/07/29 20:33:35 root Exp root $
                        Readme-File README.aztcd
    for Aztech CD-ROM CDA268-01A, ORCHID CD-3110, OKANO/WEARNES CDD110 
                           CD-ROM  Driver 
-                       Version 1.4 and newer
+                       Version 1.5 and newer
                    (for other drives see 6.-8.)
 
 NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE
@@ -487,7 +488,7 @@
 Werner Zimmermann
 Fachhochschule fuer Technik Esslingen
 (EMail: zimmerma@rz.fht-esslingen.de)
-Mar 24, 1995
+July 26, 1995
 
 ---------------------------------------------------------------------------
 APPENDIX: Source code of cdplay.c
@@ -496,7 +497,7 @@
 
    Copyright 1994, 1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
 
-This program originally was written to test the audio functions of the
+This programm originally was written to test the audio functions of the
 AZTECH.CDROM-driver, but it should work with every CD-ROM drive. Before 
 using it, you should set a symlink from /dev/cdrom to your real CDROM
 device.
@@ -510,6 +511,7 @@
           V0.5  W.Zimmermann: clean 'scanf' commands without compiler warnings
                               Jan. 6, 1995
           V0.6  W.Zimmermann: volume control (still experimental). Jan. 24, 1995
+          V0.7  W.Zimmermann: read raw modified. July 26, 95
 */
 
 #include <stdio.h>
@@ -522,7 +524,7 @@
 #include <linux/aztcd.h>
 
 void help(void)
-{ printf("Available Commands:  STOP         s      EJECT        e       QUIT         q\n");
+{ printf("Available Commands:  STOP         s      EJECT/CLOSE  e       QUIT         q\n");
   printf("                     PLAY TRACK   t      PAUSE        p       RESUME       r\n");
   printf("                     NEXT TRACK   n      REPEAT LAST  l       HELP         h\n");
   printf("                     SUB CHANNEL  c      TRACK INFO   i       PLAY AT      a\n");
@@ -539,11 +541,11 @@
   struct cdrom_tocentry entry;
   struct cdrom_msf      msf;
   union  { struct cdrom_msf msf;
-           unsigned char buf[2336];
+           unsigned char buf[CD_FRAMESIZE_RAW];
          } azt;
   struct cdrom_volctrl  volctrl;
 
-  printf("\nMini-Audio CD-Player V0.6   (C) 1994,1995  W.Zimmermann\n");
+  printf("\nMini-Audio CD-Player V0.7   (C) 1994,1995  W.Zimmermann\n");
   handle=open("/dev/cdrom",O_RDWR);
   ioctl(handle,CDROMRESUME);
   
@@ -559,7 +561,7 @@
           switch (command)
             { case 'e':   cmd=CDROMEJECT;
                           ioctl(handle,cmd);
-                          break;
+                          break;  
               case 'p':   if (!ini)
                              { printf("Command not allowed - play track first\n");
                              }
@@ -578,10 +580,8 @@
                           break;
               case 's':   cmd=CDROMPAUSE;
                           if (ioctl(handle,cmd)) printf("Drive error or already stopped\n");
-                          ini=0;
                           cmd=CDROMSTOP;
                           if (ioctl(handle,cmd)) printf("Drive error\n");
-                          ini=0;
                           break;
               case 't':   cmd=CDROMREADTOCHDR;
                           if (ioctl(handle,cmd,&tocHdr)) printf("Drive Error\n");
@@ -675,7 +675,7 @@
                             }
                           break;
               case 'a':   cmd=CDROMPLAYMSF;
-                          printf("Address (min:sec:frame)  ");
+                          printf("Adress (min:sec:frame)  ");
                           scanf("%d:%d:%d",&arg1,&arg2,&arg3);
                           msf.cdmsf_min0  =arg1;
                           msf.cdmsf_sec0  =arg2;
@@ -686,12 +686,12 @@
                           msf.cdmsf_sec1=00;
                           msf.cdmsf_frame1=00;
                           if (ioctl(handle,cmd,&msf)) 
-                           { printf("Drive error or invalid address\n");
+                           { printf("Drive error or invalid adress\n");
                            }
                           break;
 #ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/
-              case 'd':   cmd=CDROMREADMODE1;
-                          printf("Address (min:sec:frame)  ");
+              case 'd':   cmd=CDROMREADCOOKED;
+                          printf("Adress (min:sec:frame)  ");
                           scanf("%d:%d:%d",&arg1,&arg2,&arg3);
                           azt.msf.cdmsf_min0  =arg1;
                           azt.msf.cdmsf_sec0  =arg2;
@@ -699,7 +699,7 @@
                           if (azt.msf.cdmsf_sec0  > 59) azt.msf.cdmsf_sec0  =59;
                           if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74;
                           if (ioctl(handle,cmd,&azt.msf)) 
-                           { printf("Drive error, invalid address or unsupported command\n");
+                           { printf("Drive error, invalid adress or unsupported command\n");
                            }
                           k=0;
                           getchar();
@@ -723,8 +723,8 @@
                               }
                            } 
                           break;
-              case 'w':   cmd=CDROMREADMODE2;
-                          printf("Address (min:sec:frame)  ");
+              case 'w':   cmd=CDROMREADRAW;
+                          printf("Adress (min:sec:frame)  ");
                           scanf("%d:%d:%d",&arg1,&arg2,&arg3);
                           azt.msf.cdmsf_min0  =arg1;
                           azt.msf.cdmsf_sec0  =arg2;
@@ -732,10 +732,10 @@
                           if (azt.msf.cdmsf_sec0  > 59) azt.msf.cdmsf_sec0  =59;
                           if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74;
                           if (ioctl(handle,cmd,&azt)) 
-                           { printf("Drive error, invalid address or unsupported command\n");
+                           { printf("Drive error, invalid adress or unsupported command\n");
                            }
                           k=0;
-                          for (i=0;i<146;i++)
+                          for (i=0;i<147;i++)
                            { printf("%4d:",i*16);
                              for (j=0;j<16;j++)
                                { printf("%2x ",azt.buf[i*16+j]);
@@ -779,4 +779,3 @@
     }
   return 0;
 }
-
diff -u --recursive --new-file v1.3.13/linux/drivers/block/README.ide linux/drivers/block/README.ide
--- v1.3.13/linux/drivers/block/README.ide	Tue Jul 11 10:02:48 1995
+++ linux/drivers/block/README.ide	Mon Jul 31 14:30:14 1995
@@ -27,10 +27,11 @@
 		- use kernel command line option:  hda=dtc2278
 	- run-time selectable 32bit interface support (using hdparm-2.3)
 
-NEW!	- support for DiskManager 6.0x "Dynamic Disk Overlay" (experimental)
 NEW!	- support for drives with a stuck WRERR_STAT bit
 NEW!	- support for removeable devices
 
+NEW!	- transparent support for DiskManager 6.0x and "Dynamic Disk Overlay"
+		- works with Linux fdisk, LILO, loadlin, bootln, etc..
 
 ***
 
@@ -267,7 +268,7 @@
 Western Digital ships a "DiskManager 6.03" diskette with all of their big
 hard drives.  Use BIOS translation instead of this if possible, as it is a
 more generally compatible method of achieving the same results (DOS access
-to the entire disk).  However, if you must use DiskManager, it should now
-work with Linux 1.3.x in most cases.  Let me know if you still have trouble.
+to the entire disk).  However, if you must use DiskManager, it now works
+with Linux 1.3.x in most cases.  Let me know if you still have trouble.
 
 mlord@bnr.ca
diff -u --recursive --new-file v1.3.13/linux/drivers/block/aztcd.c linux/drivers/block/aztcd.c
--- v1.3.13/linux/drivers/block/aztcd.c	Tue Jul 25 18:21:21 1995
+++ linux/drivers/block/aztcd.c	Mon Jul 31 11:27:10 1995
@@ -1,5 +1,5 @@
-#define AZT_VERSION "1.40"
-/*      $Id: aztcd.c,v 1.40 1995/07/15 20:35:15 root Exp root $
+#define AZT_VERSION "1.50"
+/*      $Id: aztcd.c,v 1.50 1995/07/28 16:43:59 root Exp root $
 	linux/drivers/block/aztcd.c - AztechCD268 CDROM driver
 
 	Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
@@ -120,6 +120,10 @@
 	        by Heiko Schlittermann. Not tested, as I do not have a multi-
 	        session CD. If you can test it, please contact me.
 	        Werner Zimmermann, July 15, 95
+        V1.50   Implementation of ioctl CDROMRESET, continued multisession, began
+                XA, but still untested. Heavy modifications to drive status de-
+                tection.
+                Werner Zimmermann, July 25, 95
 	NOTE: 
 	Points marked with ??? are questionable !
 */
@@ -160,8 +164,8 @@
 
 #include <linux/aztcd.h>
 
-#define SET_TIMER(func, jifs)   delay_timer.expires = jifs; \
-                                delay_timer.function = (void *) func; \
+#define SET_TIMER(func, jifs)   delay_timer.expires = jiffies + (jifs); \
+                                delay_timer.function = (void *) (func); \
                                 add_timer(&delay_timer); 
 
 #define CLEAR_TIMER             del_timer(&delay_timer);
@@ -189,20 +193,21 @@
 
 #define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA)
 #define AZT_BUF_SIZ 16
+#define CD_XA_HEAD_SUBHEAD CD_XA_HEAD+8
 
 static volatile int azt_transfer_is_active=0;
 
-static char azt_buf[2048*AZT_BUF_SIZ];  /*buffer for block size conversion*/
+static char azt_buf[CD_FRAMESIZE_RAW*AZT_BUF_SIZ];/*buffer for block size conversion*/
 #if AZT_PRIVATE_IOCTLS
-static char buf[2336];                  /*separate buffer for the ioctls*/
+static char buf[CD_FRAMESIZE_RAW];              /*separate buffer for the ioctls*/
 #endif
 
 static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn;
 static volatile int azt_buf_in, azt_buf_out = -1;
 static volatile int azt_error=0;
 static int azt_open_count=0;
-enum azt_state_e {
-  AZT_S_IDLE,    /* 0 */
+enum azt_state_e 
+{ AZT_S_IDLE,    /* 0 */
   AZT_S_START,   /* 1 */
   AZT_S_MODE,    /* 2 */
   AZT_S_READ,    /* 3 */
@@ -215,9 +220,14 @@
 static volatile enum azt_state_e azt_state_old = AZT_S_STOP;  
 static volatile int azt_st_old = 0;
 #endif
+enum azt_read_modes 
+{ AZT_MODE_0,     /*read mode for audio disks, not supported by Aztech firmware*/
+  AZT_MODE_1,     /*read mode for normal CD-ROMs*/
+  AZT_MODE_2      /*read mode for XA CD-ROMs*/
+};
+static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1;
 
 static int azt_mode = -1;
-static int ACMD_DATA_READ= ACMD_PLAY_READ;
 static volatile int azt_read_count = 1;
 
 #define READ_TIMEOUT 3000
@@ -458,6 +468,39 @@
    RETURNM("sendAztCmd",-1);
 }
 
+/* Send a Set Disk Type command
+   does not seem to work with Aztech drives, behavior is completely indepen-
+   dent on which mode is set ???
+*/
+static int aztSetDiskType(int type)
+{  unsigned char data;
+   int retry;
+
+#ifdef AZT_DEBUG
+   printk("aztcd: set disk type command: type= %i\n",type);
+#endif
+   for (retry=0;retry<AZT_RETRY_ATTEMPTS;retry++)
+     { aztSendCmd(ACMD_SET_DISK_TYPE);
+       outb(type,CMD_PORT);
+       STEN_LOW;
+       data=inb(DATA_PORT);
+       if (data==AFL_PA_OK)     /*PA_OK ?*/
+	 { azt_read_mode=type;
+	   return 0;            
+	 }  
+       if (data==AFL_PA_ERR)
+	 { STEN_LOW;
+	   data=inb(DATA_PORT);
+	   printk("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n",type,data);
+	 }
+     }
+   if (retry>=AZT_RETRY_ATTEMPTS)
+     { printk("### Error 2 aztcd: aztSetDiskType %x\n ",type);
+       azt_error=0xA5;
+     }
+   RETURNM("aztSetDiskType",-1);
+}
+
 
 /* 
  * Checking if the media has been changed not yet implemented
@@ -503,15 +546,14 @@
 	 }
 
 	if (((st&AST_MODE_BITS)!=AST_BUSY) && (aztAudioStatus == CDROM_AUDIO_PLAY))
-		/* XXX might be an error? look at q-channel? */
-		aztAudioStatus = CDROM_AUDIO_COMPLETED;
+	   /* XXX might be an error? look at q-channel? */
+	   aztAudioStatus = CDROM_AUDIO_COMPLETED;
 
-	if (st & AST_DSK_CHG)
-	{
-		aztDiskChanged = 1;
-		aztTocUpToDate = 0;
-		aztAudioStatus = CDROM_AUDIO_NO_STATUS;
-	}
+	if ((st & AST_DSK_CHG)||(st & AST_NOT_READY))
+	 { aztDiskChanged = 1;
+	   aztTocUpToDate = 0;
+	   aztAudioStatus = CDROM_AUDIO_NO_STATUS;
+	 }
 	return st;
 }
 
@@ -543,10 +585,11 @@
 
 #ifdef AZT_DEBUG
 	printk("aztcd: starting aztcd_ioctl - Command:%x   Time: %li\n",cmd, jiffies);
+        printk("aztcd Status %x\n", getAztStatus());
 #endif
 	if (!ip) RETURNM("aztcd_ioctl 1",-EINVAL);
 	if (getAztStatus()<0) RETURNM("aztcd_ioctl 2", -EIO);
-	if (!aztTocUpToDate)
+	if ((!aztTocUpToDate)||(aztDiskChanged))
 	{ if ((i=aztUpdateToc())<0) RETURNM("aztcd_ioctl 3", i); /* error reading TOC */
 	}
 
@@ -607,12 +650,7 @@
 		       ms.addr.lba = azt_msf2hsg(&DiskInfo.lastTrack);
 		  else
 		       return -EINVAL;
-		  if (DiskInfo.type == CD_XA) 
-		     { ms.xa_flag = 0x01;   	/*XA-Disk*/
-		     }
-		  else
-		     { ms.xa_flag = 0x00;   
-		     }
+		  ms.xa_flag = DiskInfo.xa;
  		  st = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct cdrom_multisession));
 		  if (st) return st;
 	  	  memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
@@ -704,7 +742,7 @@
 		st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
 		if (st) return st;
 		memcpy_fromfs(&entry, (void *) arg, sizeof entry);
-		if (!aztTocUpToDate) aztGetDiskInfo();
+		if ((!aztTocUpToDate)||aztDiskChanged) aztUpdateToc();
 		if (entry.cdte_track == CDROM_LEADOUT)
 		  tocPtr = &Toc[DiskInfo.last + 1];   /* ??? */
 		else if (entry.cdte_track > DiskInfo.last
@@ -800,13 +838,20 @@
 	case CDROMEJECT_SW:
 		azt_auto_eject = (char) arg;
 		break;	
-	case CDROMREADMODE1: /*read data in mode 1 (2048 Bytes)*/
-	case CDROMREADMODE2: /*read data in mode 2 (2336 Bytes)*/
+        case CDROMRESET:
+        	outb(ACMD_SOFT_RESET,CMD_PORT);   /*send reset*/
+	        STEN_LOW;
+	        if (inb(DATA_PORT)!=AFL_OP_OK)    /*OP_OK?*/
+	          { printk("aztcd: AZTECH CD-ROM drive does not respond\n");
+                  }
+                break;
 /*Take care, the following code is not compatible with other CD-ROM drivers,
   use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h,
   if you do not want to use it!
 */                  
 #if AZT_PRIVATE_IOCTLS 
+	case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes)*/
+	case CDROMREADRAW:    /*read data in mode 2 (2336 Bytes)*/
 		{ st = verify_area(VERIFY_READ,  (void *) arg, sizeof msf);
 		  if (st) return st;
 		  st = verify_area(VERIFY_WRITE, (void *) arg, sizeof buf);
@@ -825,21 +870,28 @@
 		  azt_Play.end.min = msf.cdmsf_min1;
 		  azt_Play.end.sec = msf.cdmsf_sec1;
 		  azt_Play.end.frame = msf.cdmsf_frame1;
-		  if (cmd==CDROMREADMODE1)
-		  { sendAztCmd(ACMD_DATA_READ, &azt_Play);
+		  if (cmd==CDROMREADCOOKED)
+		  { sendAztCmd(ACMD_PLAY_READ, &azt_Play);
 		    DTEN_LOW;
-		    insb(DATA_PORT,buf,2048);
-		    memcpy_tofs((void *) arg, &buf, 2048);
+		    insb(DATA_PORT,buf,CD_FRAMESIZE);
+		    memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE);
 		  }
-		  else /*CDROMREADMODE2*/
-		  { sendAztCmd(ACMD_DATA_READ_RAW, &azt_Play);
+		  else /*CDROMREADRAW*/
+		  { sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play);
 		    DTEN_LOW;
-		    insb(DATA_PORT,buf,2336);
-		    memcpy_tofs((void *) arg, &buf, 2336);
+		    insb(DATA_PORT,buf,CD_FRAMESIZE_RAW);
+		    memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE_RAW);
 		  }
 		 } 
-#endif  /*end of incompatible code*/               
-		break;
+                break;
+#endif /*end of incompatible code*/       
+        case CDROMREADMODE0: /*set read data in mode 0, does not work with my drive*/
+                printk ("aztcd Status %x\n", getAztStatus());
+                return aztSetDiskType(AZT_MODE_0);
+	case CDROMREADMODE1: /*set read data in mode 1*/
+                return aztSetDiskType(AZT_MODE_1);
+	case CDROMREADMODE2: /*set read data in mode 2*/
+                return aztSetDiskType(AZT_MODE_2);	    
 	default:
 		return -EINVAL;
 	}
@@ -895,6 +947,11 @@
 #ifdef AZT_TEST
   printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies);
 #endif
+  if (DiskInfo.audio) 
+    { printk("aztcd: Error, tried to mount an Audio CD\n");
+      end_request(0);
+      return;
+    }
   azt_transfer_is_active = 1;
   while (CURRENT_VALID) {
     if (CURRENT->bh) {
@@ -907,7 +964,7 @@
     } else {
       azt_buf_out = -1;         /* Want to read a block not in buffer */
       if (azt_state == AZT_S_IDLE) {
-	if (!aztTocUpToDate) {
+	if ((!aztTocUpToDate)||aztDiskChanged) {
 	  if (aztUpdateToc() < 0) {
 	    while (CURRENT_VALID)
 	      end_request(0);
@@ -927,7 +984,6 @@
 	  azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
   printk(" do_aztcd_request ends  Time:%li\n",jiffies);
 #endif
-
 }
 
 static void azt_poll(void)
@@ -944,10 +1000,10 @@
 	azt_invalidate_buffers();
 #ifdef WARN_IF_READ_FAILURE
 	if (AztTries == 5)
-	  printk("aztcd: read of block %d failed - maybe audio disk?\n", azt_next_bn);
+	  printk("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n", azt_next_bn);
 #endif
 	if (!AztTries--) {
-	  printk("aztcd: read of block %d failed, maybe audio disk? Giving up\n", azt_next_bn);
+	  printk("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n", azt_next_bn);
 	  if (azt_transfer_is_active) {
 	    AztTries = 0;
 	    loop_ctl = 0;
@@ -996,10 +1052,12 @@
 #endif
 	  if (!skip) {
 	    if ((st = aztStatus()) != -1) {
-	      if (st & AST_DSK_CHG) {
+	      if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
 		aztDiskChanged = 1;
 		aztTocUpToDate = 0;
 		azt_invalidate_buffers();
+		end_request(0);
+		printk("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n");
 	      }
 	    } else break;
 	  }
@@ -1008,6 +1066,8 @@
 	  if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) {
 	    aztDiskChanged = 1;
 	    aztTocUpToDate = 0;
+            printk("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n");
+            end_request(0);
 	    printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n");
 	    if (azt_transfer_is_active) {
 	      azt_state = AZT_S_START;
@@ -1042,10 +1102,12 @@
 #endif
 	  if (!skip) {
 	      if ((st = aztStatus()) != -1) {
-		if (st & AST_DSK_CHG) {
+		if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
 		aztDiskChanged = 1;
 		aztTocUpToDate = 0;
 		azt_invalidate_buffers();
+		printk("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n");
+                end_request(0);               
 		}
 	      } else break;
 	  } 
@@ -1081,7 +1143,12 @@
 	    printk("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n", \
 		    azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
 #endif 
-	    sendAztCmd(ACMD_DATA_READ, &msf);
+            if (azt_read_mode==AZT_MODE_2)
+               { sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode*/
+               }
+            else
+               { sendAztCmd(ACMD_PLAY_READ, &msf);     /*others in cooked mode*/
+               }
 	    azt_state = AZT_S_DATA;
 	    AztTimeout = READ_TIMEOUT;
 	  } else {
@@ -1112,12 +1179,8 @@
 		printk("---AFL_DATA st:%x\n",st);
 	      }
 #endif
-#ifdef WARN_IF_READ_FAILURE
-	      if (AztTries == 5)
-		printk("aztcd: read of block %d failed - maybe audio disk?\n", azt_next_bn);
-#endif
 	      if (!AztTries--) {
-		printk("aztcd: read of block %d failed, maybe audio disk ? Giving up\n", azt_next_bn);
+		printk("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n", azt_next_bn);
 		if (azt_transfer_is_active) {
 		  AztTries = 0;
 		  break;
@@ -1175,7 +1238,20 @@
 		    end_request(1);  /*should we have here (1) or (0)? */
 		  }
 		 else
-		  { insb(DATA_PORT, azt_buf + 2048 * azt_buf_in, 2048);
+		  { if (azt_read_mode==AZT_MODE_2)
+		       { if (DiskInfo.xa) /*With XA disks skip head and tail*/
+		            { unsigned char tmp_buf[CD_XA_TAIL];
+		              insb(DATA_PORT, tmp_buf , CD_XA_HEAD_SUBHEAD);
+		              insb(DATA_PORT, azt_buf + CD_FRAMESIZE * azt_buf_in, CD_FRAMESIZE);
+		              insb(DATA_PORT, tmp_buf , CD_XA_TAIL);
+                            }
+                         else   
+		            { insb(DATA_PORT, azt_buf + CD_FRAMESIZE_RAW * azt_buf_in, CD_FRAMESIZE_RAW);
+		            }
+		       }
+		    else
+		       { insb(DATA_PORT, azt_buf + CD_FRAMESIZE * azt_buf_in, CD_FRAMESIZE);
+                       }
 		    azt_read_count--;
 #ifdef AZT_TEST3
 		    printk("AZT_S_DATA; ---I've read data- read_count: %d\n",azt_read_count);
@@ -1227,9 +1303,10 @@
 	  while (azt_read_count!=0) {
 	    int i;
 	    if ( !(inb(STATUS_PORT) & AFL_DATA) ) {
-	      for (i=0; i<2048; i++) {
-		inb(DATA_PORT);
-	      }
+	      if (azt_read_mode==AZT_MODE_2)
+	         for (i=0; i<CD_FRAMESIZE_RAW; i++) inb(DATA_PORT);
+	      else   
+	         for (i=0; i<CD_FRAMESIZE; i++) inb(DATA_PORT);
 	    }
 	    azt_read_count--;
 	  }  
@@ -1249,10 +1326,12 @@
 	  if ((st = aztStatus()) == -1 && AztTimeout)
 	    break;
 
-	  if ((st != -1) && (st & AST_DSK_CHG)) {
+	  if ((st != -1) && ((st & AST_DSK_CHG)||(st & AST_NOT_READY))) {
 	    aztDiskChanged = 1;
 	    aztTocUpToDate = 0;
 	    azt_invalidate_buffers();
+	    printk("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n");
+	    end_request(0);
 	  }
 
 
@@ -1324,34 +1403,46 @@
 	if (aztPresent == 0)
 		return -ENXIO;                  /* no hardware */
 
-	if (!azt_open_count && azt_state == AZT_S_IDLE) {
+	if (!azt_open_count && azt_state == AZT_S_IDLE) 
+	  { azt_invalidate_buffers();
 
-	azt_invalidate_buffers();
-
-	st = getAztStatus();                       /* check drive status */
-	if (st == -1)
-		return -EIO;                    /* drive doesn't respond */
-
-        if (st&AST_DOOR_OPEN)
-          {
-            /* close door, then get the status again. */
-            aztCloseDoor();     
-            st = getAztStatus();
-          }        
-
-	if ((st&AST_DOOR_OPEN)||(st&AST_NOT_READY)) /* no disk in drive or door open*/
-	{       /* Door should be closed, probably no disk in drive */
-		printk("aztcd: no disk in drive or door open\n");
-		return -EIO;
-	}
-
-	if (aztUpdateToc() < 0)
-		return -EIO;
+	    st = getAztStatus();                    /* check drive status */
+	    if (st == -1) return -EIO;              /* drive doesn't respond */
 
-	}
+            if (st & AST_DOOR_OPEN)
+               { /* close door, then get the status again. */
+	         printk("aztcd: Door Open?\n");
+                 aztCloseDoor();     
+                 st = getAztStatus();
+               }        
+
+	    if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) /*no disk in drive or changed*/
+	       { printk("aztcd: No Disk in Drive or Disk Changed?\n");
+/*	         return -EIO;
+*/	       }
+
+	    if (aztUpdateToc() < 0)	return -EIO;
+
+/*          Detect XA disks. XA disks will be read in raw mode, others not
+	      --> must set read command to read raw       --> to be done ???
+*/          if (aztSetDiskType(DiskInfo.xa ? AZT_MODE_2 : AZT_MODE_1)) return -EIO;
+            if (DiskInfo.xa) printk("aztcd: XA support not yet tested - please mail 'zimmerma@rz.fht-esslingen.de'\n");
+
+            /* audio detection was already done in aztGetToc */
+	    if (DiskInfo.audio) 
+	       { printk(("aztcd: Audio-CD found\n"));
+	       } 
+	    else 
+	       { printk("aztcd: %s%s CD-ROM found\n",
+	  	         DiskInfo.xa    ? "XA " : "",
+			 DiskInfo.multi ? "Multi Session" : "Single Session");
+	       }
+	  }
 	++azt_open_count;
         MOD_INC_USE_COUNT;
 	aztLockDoor();
+
+
 #ifdef AZT_DEBUG
 	printk("aztcd: exiting aztcd_open\n");
 #endif
@@ -1418,9 +1509,9 @@
           return -EIO;
 #endif	  
 	}
-	printk("Aztech CD-ROM Init: Aztech, Orchid, Okano, Wearnes CD-ROM Driver\n");
-	printk("Aztech CD-ROM Init: (C) 1994,1995 Werner Zimmermann\n");
-	printk("Aztech CD-ROM Init: DriverVersion=%s  BaseAddress=0x%x \n",AZT_VERSION,azt_port);
+	printk("aztcd: Aztech, Orchid, Okano, Wearnes CD-ROM Driver\n");
+	printk("aztcd: (C) 1994,1995 Werner Zimmermann\n");
+	printk("aztcd: DriverVersion=%s  BaseAddress=0x%x \n",AZT_VERSION,azt_port);
 
 	if (check_region(azt_port, 4)) {
 	  printk("aztcd: conflict, I/O port (%X) already used\n",
@@ -1508,25 +1599,25 @@
 	 }
 	if (count>30) max_count=30;  /*print max.30 chars of the version string*/
 	else          max_count=count;
-	printk("Aztech CD-ROM Init: FirmwareVersion=");
+	printk("aztcd: FirmwareVersion=");
 	for (count=1;count<max_count;count++) printk("%c",result[count]);
 	printk("<<<\n");
 
 	if ((result[1]=='A')&&(result[2]=='Z')&&(result[3]=='T'))
-	 { printk("Aztech CD-ROM Init: AZTECH drive detected\n"); /*AZTECH*/    
+	 { printk("aztcd: AZTECH drive detected\n"); /*AZTECH*/    
 	 }
 	else if ((result[2]=='C')&&(result[3]=='D')&&(result[4]=='D'))
-	 { printk("Aztech CD-ROM Init: ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES*/
+	 { printk("aztcd: ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES*/
 	 }
 	else                                               /*OTHERS or none*/
-	 { printk("Aztech CD-ROM Init: : unknown drive or firmware version detected\n");
+	 { printk("aztcd: : unknown drive or firmware version detected\n");
 	   printk("                      azt may not run stable, if you want to try anyhow,\n");
 	   printk("                      boot with: aztcd=base_address,0x79\n");
 	   if ((azt_cont!=0x79))     
-	     { printk("Aztech CD-ROM Init: FirmwareVersion=");
+	     { printk("aztcd: FirmwareVersion=");
 	       for (count=1;count<5;count++) printk("%c",result[count]);
 	       printk("\n");
-	       printk("Aztech CD-ROM Init: Aborted\n");
+	       printk("aztcd: Aborted\n");
 #ifndef MODULE
 	       return (mem_start);
 #else
@@ -1552,7 +1643,7 @@
 	azt_invalidate_buffers();
 	aztPresent = 1;
 	aztCloseDoor();
-	printk("Aztech CD-ROM Init: End\n");
+	printk("aztcd: End Init\n");
 #ifndef MODULE
 	return (mem_start);
 #else
@@ -1781,18 +1872,24 @@
 
 	Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
 
-        DiskInfo.lastTrack.sec=2;
-        DiskInfo.type = 0; 
-        for (i=0;i<=DiskInfo.last;i++) /*Unterscheidung zw. Audio- und Datendisk???*/
-          { if ((Toc[i].ctrl_addr)==0x01)      
-                DiskInfo.type=DiskInfo.type|CD_AUDIO; 
-            if ((Toc[i].ctrl_addr)==0x41)
-                DiskInfo.type=DiskInfo.type|CD_DATA;     
-          }
+/*support for XA and multisession CDs not yet working  ???*/
+        DiskInfo.multi = 0;     /*how to get this info ???*/
+        if (!DiskInfo.multi) DiskInfo.lastTrack.sec=2;
+        i = getAztStatus();
+  	DiskInfo.xa    = i & AST_MODE; /* I doubt this will work ??? */
         DiskInfo.lastTrack.min  =Toc[DiskInfo.last].diskTime.min;
 	DiskInfo.lastTrack.sec  =Toc[DiskInfo.last].diskTime.sec;
         DiskInfo.lastTrack.frame=Toc[DiskInfo.last].diskTime.frame;
 
+        /*try to detect audio disks; with my Aztech drive there is no audio
+          status bit, so I use the copy protection bit of the first track. If
+          this track is copy protected (copy bit = 0), I assume, it's an audio 
+          disk. ???*/
+        if (!(Toc[DiskInfo.first].ctrl_addr & 0x40)) 
+           DiskInfo.audio=1;
+        else 
+           DiskInfo.audio=0;
+
 #ifdef AZT_DEBUG
 printk("aztcd: exiting aztGetToc  Time:%li\n",jiffies);
 for (i = 1; i <= DiskInfo.last+1; i++)
@@ -1805,7 +1902,7 @@
 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
-printk("\nDisk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x last %02x:%02x.%02x type %02x\n",
+printk("\nDisk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x last %02x:%02x.%02x type %02x %02x\n",
 	DiskInfo.first,
 	DiskInfo.last,
 	DiskInfo.diskLength.min,
@@ -1817,7 +1914,8 @@
 	DiskInfo.lastTrack.min,
 	DiskInfo.lastTrack.sec,
 	DiskInfo.lastTrack.frame,
-        DiskInfo.type);
+        DiskInfo.xa,
+        DiskInfo.audio);
 #endif
 
 	return limit > 0 ? 0 : -1;
diff -u --recursive --new-file v1.3.13/linux/drivers/block/cdu31a.c linux/drivers/block/cdu31a.c
--- v1.3.13/linux/drivers/block/cdu31a.c	Tue Jul 25 18:21:21 1995
+++ linux/drivers/block/cdu31a.c	Mon Jul 31 10:34:08 1995
@@ -160,6 +160,17 @@
  *                4, but I think that is a mistake.
  */
 
+#include <linux/major.h>
+#include <linux/config.h>
+
+#ifdef MODULE
+# include <linux/module.h>
+# include <linux/version.h>
+# ifndef CONFIG_MODVERSIONS
+    char kernel_version[]= UTS_RELEASE;
+# endif
+#endif
+
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -237,7 +248,7 @@
 
 /* The base I/O address of the Sony Interface.  This is a variable (not a
    #define) so it can be easily changed via some future ioctl() */
-static unsigned short sony_cd_base_io = 0;
+static unsigned short cdu31a_port = 0;
 
 /*
  * The following are I/O addresses of the various registers for the drive.  The
@@ -267,15 +278,15 @@
 static int sony_pas_init = 0;		   /* Initialize the Pro-Audio
 					      Spectrum card? */
 
-static struct s_sony_session_toc *sony_toc; /* Points to the
+static struct s_sony_session_toc sony_toc;  /* Holds the
 					       table of
 					       contents. */
 
 static int sony_toc_read = 0;		   /* Has the TOC been read for
 					      the drive? */
 
-static struct s_sony_subcode * volatile last_sony_subcode; /* Points to the last
-                                                    subcode address read */
+static struct s_sony_subcode last_sony_subcode; /* Points to the last
+                                                   subcode address read */
 
 static volatile int sony_inuse = 0;  /* Is the drive in use?  Only one operation
 					at a time allowed */
@@ -305,7 +316,7 @@
 static unsigned volatile char final_pos_msf[3] = { 0, 0, 0 };
 
 /* What IRQ is the drive using?  0 if none. */
-static int irq_used = 0;
+static int cdu31a_irq = 0;
 
 /* The interrupt handler will wake this queue up when it gets an
    interrupts. */
@@ -321,7 +332,7 @@
 /* Variable for using the readahead buffer.  The readahead buffer
    is used for raw sector reads and for blocksizes that are smaller
    than 2048 bytes. */
-static char *readahead_buffer = NULL; /* Used for 1024 byte blocksize. */
+static char readahead_buffer[CD_FRAMESIZE_RAW];
 static int readahead_dataleft = 0;
 static int readahead_bad = 0;
 
@@ -330,6 +341,11 @@
    the drive from flashing for very long. */
 static struct timer_list cdu31a_abort_timer;
 
+/* Marks if the timeout has started an abort read.  This is used
+   on entry to the drive to tell the code to read out the status
+   from the abort read. */
+static int abort_read_started = 0;
+
 
 /*
  * This routine returns 1 if the disk has been changed since the last
@@ -387,7 +403,7 @@
 {
    unsigned long flags;
 
-   if (irq_used <= 0)
+   if (cdu31a_irq <= 0)
    {
       current->state = TASK_INTERRUPTIBLE;
       current->timeout = jiffies;
@@ -799,13 +815,14 @@
    {
       recursive_call = 1;
    }
-   restore_flags(flags);
 
    num_retries = 0;
 retry_cd_operation:
 
    while (handle_sony_cd_attention())
       ;
+
+   sti();
    
    retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
    while ((retry_count > jiffies) && (is_busy()))
@@ -851,6 +868,8 @@
       sony_inuse = 0;
       wake_up_interruptible(&sony_wait);
    }
+
+   restore_flags(flags);
 }
 
 
@@ -868,9 +887,26 @@
 {
    unsigned char atten_code;
    static int num_consecutive_attentions = 0;
+   volatile int val;
 
 
-   if (is_attention())
+   if (abort_read_started)
+   {
+      while (is_result_reg_not_empty())
+      {
+         val = read_result_register();
+      }
+      clear_data_ready();
+      clear_result_ready();
+      /* Clear out the data */
+      while (is_data_requested())
+      {
+         val = read_data_register();
+      }
+      abort_read_started = 0;
+      return(1);
+   }
+   else if (is_attention())
    {
       if (num_consecutive_attentions > CDU31A_MAX_CONSECUTIVE_ATTENTIONS)
       {
@@ -1018,9 +1054,9 @@
     * If the full read-ahead would go beyond the end of the media, trim
     * it back to read just till the end of the media.
     */
-   else if ((sector + nsect) >= sony_toc->lead_out_start_lba)
+   else if ((sector + nsect) >= sony_toc.lead_out_start_lba)
    {
-      read_size = sony_toc->lead_out_start_lba - sector;
+      read_size = sony_toc.lead_out_start_lba - sector;
    }
    /* Read the full readahead amount. */
    else
@@ -1106,7 +1142,22 @@
 static void
 handle_abort_timeout(unsigned long data)
 {
-   abort_read();
+   /* If it is in use, ignore it. */
+   if (!sony_inuse)
+   {
+      /* We can't use abort_read(), because it will sleep
+         or schedule in the timer interrupt.  Just start
+         the operation, finish it on the next access to
+         the drive. */
+      clear_result_ready();
+      clear_param_reg();
+      write_cmd(SONY_ABORT_CMD);
+
+      sony_blocks_left = 0;
+      readahead_dataleft = 0;
+      readahead_bad = 0;
+      abort_read_started = 1;
+   }
 }
 
 /* Actually get data and status from the drive. */
@@ -1411,12 +1462,13 @@
    }
    sony_inuse = 1;
    has_cd_task = current;
-   sti();
 
    /* Get drive status before doing anything. */
    while (handle_sony_cd_attention())
       ;
 
+   sti();
+
    /* If the timer is running, cancel it. */
    if (cdu31a_abort_timer.next != NULL)
    {
@@ -1478,7 +1530,7 @@
       if (block < 80)
       {
 	 /* Offset the request into the session. */
-	 block += (sony_toc->start_track_lba * 4);
+	 block += (sony_toc.start_track_lba * 4);
       }
 
       switch(CURRENT->cmd)
@@ -1489,20 +1541,20 @@
           * the media, return an error.
           */
 #if 0
-	 if ((block / 4) < sony_toc->start_track_lba)
+	 if ((block / 4) < sony_toc.start_track_lba)
 	 {
             printk("CDU31A: Request before beginning of media\n");
             end_request(0);
             goto cdu31a_request_startover;
 	 }
 #endif
-         if ((block / 4) >= sony_toc->lead_out_start_lba)
+         if ((block / 4) >= sony_toc.lead_out_start_lba)
          {
             printk("CDU31A: Request past end of media\n");
             end_request(0);
             goto cdu31a_request_startover;
          }
-         if (((block + nblock) / 4) >= sony_toc->lead_out_start_lba)
+         if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba)
          {
             printk("CDU31A: Request past end of media\n");
             end_request(0);
@@ -1599,7 +1651,7 @@
 #else
    /* Start a timer to time out after a while to disable
       the read. */
-   cdu31a_abort_timer.expires = 200; /* Wait 2 seconds */
+   cdu31a_abort_timer.expires = jiffies + 2*HZ; /* Wait 2 seconds */
    add_timer(&cdu31a_abort_timer);
 #endif
 
@@ -1694,9 +1746,9 @@
       do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD,
 		     parms,
 		     1, 
-		     (unsigned char *) sony_toc, 
+		     (unsigned char *) &sony_toc, 
 		     &res_size);
-      if ((res_size < 2) || ((sony_toc->exec_status[0] & 0xf0) == 0x20))
+      if ((res_size < 2) || ((sony_toc.exec_status[0] & 0xf0) == 0x20))
       {
 	 /* An error reading the TOC.  Return without sony_toc_read
 	    set. */
@@ -1707,57 +1759,57 @@
 
       /* For points that do not exist, move the data over them
 	 to the right location. */
-      if (sony_toc->pointb0 != 0xb0)
+      if (sony_toc.pointb0 != 0xb0)
       {
-	 mcovlp(((char *) sony_toc) + 27,
-		((char *) sony_toc) + 18,
+	 mcovlp(((char *) &sony_toc) + 27,
+		((char *) &sony_toc) + 18,
 		res_size - 18);
 	 res_size += 9;
       }
-      if (sony_toc->pointb1 != 0xb1)
+      if (sony_toc.pointb1 != 0xb1)
       {
-	 mcovlp(((char *) sony_toc) + 36,
-		((char *) sony_toc) + 27,
+	 mcovlp(((char *) &sony_toc) + 36,
+		((char *) &sony_toc) + 27,
 		res_size - 27);
 	 res_size += 9;
       }
-      if (sony_toc->pointb2 != 0xb2)
+      if (sony_toc.pointb2 != 0xb2)
       {
-	 mcovlp(((char *) sony_toc) + 45,
-		((char *) sony_toc) + 36,
+	 mcovlp(((char *) &sony_toc) + 45,
+		((char *) &sony_toc) + 36,
 		res_size - 36);
 	 res_size += 9;
       }
-      if (sony_toc->pointb3 != 0xb3)
+      if (sony_toc.pointb3 != 0xb3)
       {
-	 mcovlp(((char *) sony_toc) + 54,
-		((char *) sony_toc) + 45,
+	 mcovlp(((char *) &sony_toc) + 54,
+		((char *) &sony_toc) + 45,
 		res_size - 45);
 	 res_size += 9;
       }
-      if (sony_toc->pointb4 != 0xb4)
+      if (sony_toc.pointb4 != 0xb4)
       {
-	 mcovlp(((char *) sony_toc) + 63,
-		((char *) sony_toc) + 54,
+	 mcovlp(((char *) &sony_toc) + 63,
+		((char *) &sony_toc) + 54,
 		res_size - 54);
 	 res_size += 9;
       }
-      if (sony_toc->pointc0 != 0xc0)
+      if (sony_toc.pointc0 != 0xc0)
       {
-	 mcovlp(((char *) sony_toc) + 72,
-		((char *) sony_toc) + 63,
+	 mcovlp(((char *) &sony_toc) + 72,
+		((char *) &sony_toc) + 63,
 		res_size - 63);
 	 res_size += 9;
       }
 
-      sony_toc->start_track_lba = msf_to_log(sony_toc->tracks[0].track_start_msf);
-      sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf);
+      sony_toc.start_track_lba = msf_to_log(sony_toc.tracks[0].track_start_msf);
+      sony_toc.lead_out_start_lba = msf_to_log(sony_toc.lead_out_start_msf);
 
 #if DEBUG
    printk("Disk session %d, start track: %d, stop track: %d\n",
 	  session,
-	  sony_toc->start_track_lba,
-	  sony_toc->lead_out_start_lba);
+	  sony_toc.start_track_lba,
+	  sony_toc.lead_out_start_lba);
 #endif
    }
 #if DEBUG
@@ -1776,10 +1828,10 @@
    int num_tracks;
 
 
-   num_tracks = sony_toc->last_track_num - sony_toc->first_track_num + 1;
+   num_tracks = sony_toc.last_track_num - sony_toc.first_track_num + 1;
    for (i = 0; i < num_tracks; i++)
    {
-      if (sony_toc->tracks[i].track == track)
+      if (sony_toc.tracks[i].track == track)
       {
          return i;
       }
@@ -1801,12 +1853,12 @@
    do_sony_cd_cmd(SONY_REQ_SUBCODE_ADDRESS_CMD,
                   NULL,
                   0, 
-                  (unsigned char *) last_sony_subcode, 
+                  (unsigned char *) &last_sony_subcode, 
                   &res_size);
-   if ((res_size < 2) || ((last_sony_subcode->exec_status[0] & 0xf0) == 0x20))
+   if ((res_size < 2) || ((last_sony_subcode.exec_status[0] & 0xf0) == 0x20))
    {
       printk("Sony CDROM error 0x%2.2x (read_subcode)\n",
-             last_sony_subcode->exec_status[1]);
+             last_sony_subcode.exec_status[1]);
       return -EIO;
    }
 
@@ -1868,24 +1920,24 @@
    }
 
    schi.cdsc_audiostatus = sony_audio_status;
-   schi.cdsc_adr = last_sony_subcode->address;
-   schi.cdsc_ctrl = last_sony_subcode->control;
-   schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num);
-   schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num);
+   schi.cdsc_adr = last_sony_subcode.address;
+   schi.cdsc_ctrl = last_sony_subcode.control;
+   schi.cdsc_trk = bcd_to_int(last_sony_subcode.track_num);
+   schi.cdsc_ind = bcd_to_int(last_sony_subcode.index_num);
    if (schi.cdsc_format == CDROM_MSF)
    {
-      schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]);
-      schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]);
-      schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]);
-
-      schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]);
-      schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]);
-      schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]);
+      schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode.abs_msf[0]);
+      schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode.abs_msf[1]);
+      schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode.abs_msf[2]);
+
+      schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode.rel_msf[0]);
+      schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode.rel_msf[1]);
+      schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode.rel_msf[2]);
    }
    else if (schi.cdsc_format == CDROM_LBA)
    {
-      schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf);
-      schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf);
+      schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode.abs_msf);
+      schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode.rel_msf);
    }
    
    memcpy_tofs((char *) arg, &schi, sizeof(schi));
@@ -2217,12 +2269,13 @@
    return(retval);
 }
 
-/*
- * The big ugly ioctl handler.
- */
- 
-static int do_sony_cd_cmd_chk(char *name, unsigned char cmd, unsigned char *params, unsigned int num_params,
-		unsigned char *result_buffer, unsigned int *result_size)
+static int
+do_sony_cd_cmd_chk(char *name,
+                   unsigned char cmd,
+                   unsigned char *params,
+                   unsigned int num_params,
+		   unsigned char *result_buffer,
+                   unsigned int *result_size)
 {      
       do_sony_cd_cmd(cmd, params, num_params, result_buffer, result_size);
       if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20))
@@ -2233,6 +2286,9 @@
       return 0;
 }
  
+/*
+ * The big ugly ioctl handler.
+ */
 static int scd_ioctl(struct inode *inode,
           struct file  *file,
           unsigned int  cmd,
@@ -2274,9 +2330,9 @@
       {
          return -EIO;
       }
-      cur_pos_msf[0] = last_sony_subcode->abs_msf[0];
-      cur_pos_msf[1] = last_sony_subcode->abs_msf[1];
-      cur_pos_msf[2] = last_sony_subcode->abs_msf[2];
+      cur_pos_msf[0] = last_sony_subcode.abs_msf[0];
+      cur_pos_msf[1] = last_sony_subcode.abs_msf[1];
+      cur_pos_msf[2] = last_sony_subcode.abs_msf[2];
       sony_audio_status = CDROM_AUDIO_PAUSED;
       return 0;
       break;
@@ -2340,8 +2396,8 @@
          i=verify_area(VERIFY_WRITE, hdr, sizeof(*hdr));
          if(i<0)
          	return i;
-         loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num);
-         loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num);
+         loc_hdr.cdth_trk0 = bcd_to_int(sony_toc.first_track_num);
+         loc_hdr.cdth_trk1 = bcd_to_int(sony_toc.last_track_num);
          memcpy_tofs(hdr, &loc_hdr, sizeof(*hdr));
       }
       return 0;
@@ -2372,9 +2428,9 @@
          /* Lead out is handled separately since it is special. */
          if (loc_entry.cdte_track == CDROM_LEADOUT)
          {
-            loc_entry.cdte_adr = sony_toc->address2;
-            loc_entry.cdte_ctrl = sony_toc->control2;
-            msf_val = sony_toc->lead_out_start_msf;
+            loc_entry.cdte_adr = sony_toc.address2;
+            loc_entry.cdte_ctrl = sony_toc.control2;
+            msf_val = sony_toc.lead_out_start_msf;
          }
          else
          {
@@ -2384,9 +2440,9 @@
                return -EINVAL;
             }
             
-            loc_entry.cdte_adr = sony_toc->tracks[track_idx].address;
-            loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control;
-            msf_val = sony_toc->tracks[track_idx].track_start_msf;
+            loc_entry.cdte_adr = sony_toc.tracks[track_idx].address;
+            loc_entry.cdte_ctrl = sony_toc.tracks[track_idx].control;
+            msf_val = sony_toc.tracks[track_idx].track_start_msf;
          }
          
          /* Logical buffer address or MSF format requested? */
@@ -2421,8 +2477,8 @@
          	return i;
          
          memcpy_fromfs(&ti, (char *) arg, sizeof(ti));
-         if (   (ti.cdti_trk0 < sony_toc->first_track_num)
-             || (ti.cdti_trk0 > sony_toc->last_track_num)
+         if (   (ti.cdti_trk0 < sony_toc.first_track_num)
+             || (ti.cdti_trk0 > sony_toc.last_track_num)
              || (ti.cdti_trk1 < ti.cdti_trk0))
          {
             return -EINVAL;
@@ -2433,17 +2489,17 @@
          {
             return -EINVAL;
          }
-         params[1] = sony_toc->tracks[track_idx].track_start_msf[0];
-         params[2] = sony_toc->tracks[track_idx].track_start_msf[1];
-         params[3] = sony_toc->tracks[track_idx].track_start_msf[2];
+         params[1] = sony_toc.tracks[track_idx].track_start_msf[0];
+         params[2] = sony_toc.tracks[track_idx].track_start_msf[1];
+         params[3] = sony_toc.tracks[track_idx].track_start_msf[2];
          
          /*
           * If we want to stop after the last track, use the lead-out
           * MSF to do that.
           */
-         if (ti.cdti_trk1 >= bcd_to_int(sony_toc->last_track_num))
+         if (ti.cdti_trk1 >= bcd_to_int(sony_toc.last_track_num))
          {
-            log_to_msf(msf_to_log(sony_toc->lead_out_start_msf)-1,
+            log_to_msf(msf_to_log(sony_toc.lead_out_start_msf)-1,
                        &(params[4]));
          }
          else
@@ -2453,7 +2509,7 @@
             {
                return -EINVAL;
             }
-            log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf)-1,
+            log_to_msf(msf_to_log(sony_toc.tracks[track_idx].track_start_msf)-1,
                        &(params[4]));
          }
          params[0] = 0x03;
@@ -2525,8 +2581,8 @@
 
          if (ra.addr_format == CDROM_LBA)
          {
-            if (   (ra.addr.lba >= sony_toc->lead_out_start_lba)
-                || (ra.addr.lba + ra.nframes >= sony_toc->lead_out_start_lba))
+            if (   (ra.addr.lba >= sony_toc.lead_out_start_lba)
+                || (ra.addr.lba + ra.nframes >= sony_toc.lead_out_start_lba))
             {
                return -EINVAL;
             }
@@ -2543,8 +2599,8 @@
             ra.addr.lba = (  (ra.addr.msf.minute * 4500)
                            + (ra.addr.msf.second * 75)
                            + ra.addr.msf.frame);
-            if (   (ra.addr.lba >= sony_toc->lead_out_start_lba)
-                || (ra.addr.lba + ra.nframes >= sony_toc->lead_out_start_lba))
+            if (   (ra.addr.lba >= sony_toc.lead_out_start_lba)
+                || (ra.addr.lba + ra.nframes >= sony_toc.lead_out_start_lba))
             {
                return -EINVAL;
             }
@@ -2638,7 +2694,7 @@
 
       /* For XA on the CDU31A only, we have to do special reads.
          The CDU33A handles XA automagically. */
-      if (   (sony_toc->disk_type == SONY_XA_DISK_TYPE)
+      if (   (sony_toc.disk_type == SONY_XA_DISK_TYPE)
           && (!is_double_speed))
       {
          params[0] = SONY_SD_DECODE_PARAM;
@@ -2743,17 +2799,17 @@
 
 
    /* Set the base address */
-   sony_cd_base_io = base_io;
+   cdu31a_port = base_io;
 
    /* Set up all the register locations */
-   sony_cd_cmd_reg = sony_cd_base_io + SONY_CMD_REG_OFFSET;
-   sony_cd_param_reg = sony_cd_base_io + SONY_PARAM_REG_OFFSET;
-   sony_cd_write_reg = sony_cd_base_io + SONY_WRITE_REG_OFFSET;
-   sony_cd_control_reg = sony_cd_base_io + SONY_CONTROL_REG_OFFSET;
-   sony_cd_status_reg = sony_cd_base_io + SONY_STATUS_REG_OFFSET;
-   sony_cd_result_reg = sony_cd_base_io + SONY_RESULT_REG_OFFSET;
-   sony_cd_read_reg = sony_cd_base_io + SONY_READ_REG_OFFSET;
-   sony_cd_fifost_reg = sony_cd_base_io + SONY_FIFOST_REG_OFFSET;
+   sony_cd_cmd_reg = cdu31a_port + SONY_CMD_REG_OFFSET;
+   sony_cd_param_reg = cdu31a_port + SONY_PARAM_REG_OFFSET;
+   sony_cd_write_reg = cdu31a_port + SONY_WRITE_REG_OFFSET;
+   sony_cd_control_reg = cdu31a_port + SONY_CONTROL_REG_OFFSET;
+   sony_cd_status_reg = cdu31a_port + SONY_STATUS_REG_OFFSET;
+   sony_cd_result_reg = cdu31a_port + SONY_RESULT_REG_OFFSET;
+   sony_cd_read_reg = cdu31a_port + SONY_READ_REG_OFFSET;
+   sony_cd_fifost_reg = cdu31a_port + SONY_FIFOST_REG_OFFSET;
 
    /*
     * Check to see if anything exists at the status register location.
@@ -2806,11 +2862,11 @@
 {
    if (ints[0] > 0)
    {
-      sony_cd_base_io = ints[1];
+      cdu31a_port = ints[1];
    }
    if (ints[0] > 1)
    {
-      irq_used = ints[2];
+      cdu31a_irq = ints[2];
    }
    if ((strings != NULL) && (*strings != '\0'))
    {
@@ -2830,8 +2886,13 @@
 /*
  * Initialize the driver.
  */
+#ifndef MODULE
 unsigned long
 cdu31a_init(unsigned long mem_start, unsigned long mem_end)
+#else
+int
+init_module(void)
+#endif
 {
    struct s_sony_drive_config drive_config;
    unsigned int res_size;
@@ -2856,15 +2917,15 @@
    drive_found = 0;
 
    /* Setting the base I/O address to 0xffff will disable it. */
-   if (sony_cd_base_io == 0xffff)
+   if (cdu31a_port == 0xffff)
    {
    }
-   else if (sony_cd_base_io != 0)
+   else if (cdu31a_port != 0)
    {
-      tmp_irq = irq_used; /* Need IRQ 0 because we can't sleep here. */
-      irq_used = 0;
+      tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */
+      cdu31a_irq = 0;
 
-      get_drive_configuration(sony_cd_base_io,
+      get_drive_configuration(cdu31a_port,
 			      drive_config.exec_status,
 			      &res_size);
       if ((res_size > 2) && ((drive_config.exec_status[0] & 0xf0) == 0x00))
@@ -2872,11 +2933,11 @@
 	 drive_found = 1;
       }
 
-      irq_used = tmp_irq;
+      cdu31a_irq = tmp_irq;
    }
    else
    {
-      irq_used = 0;
+      cdu31a_irq = 0;
       i = 0;
       while (   (cdu31a_addresses[i].base != 0)
 	     && (!drive_found))
@@ -2891,7 +2952,7 @@
 	 if ((res_size > 2) && ((drive_config.exec_status[0] & 0xf0) == 0x00))
 	 {
 	    drive_found = 1;
-	    irq_used = cdu31a_addresses[i].int_num;
+	    cdu31a_irq = cdu31a_addresses[i].int_num;
 	 }
 	 else
 	 {
@@ -2902,12 +2963,16 @@
 
    if (drive_found)
    {
-      request_region(sony_cd_base_io, 4,"cdu31a");
+      request_region(cdu31a_port, 4,"cdu31a");
       
       if (register_blkdev(MAJOR_NR,"cdu31a",&scd_fops))
       {
 	 printk("Unable to get major %d for CDU-31a\n", MAJOR_NR);
+#ifdef MODULE
+	 return -EIO;
+#else
 	 return mem_start;
+#endif
       }
 
       if (SONY_HWC_DOUBLE_SPEED(drive_config))
@@ -2915,35 +2980,19 @@
 	 is_double_speed = 1;
       }
 
-      /* A negative irq_used will attempt an autoirq. */
-      if (irq_used < 0)
-      {
-	 autoirq_setup(0);
-	 enable_interrupts();
-	 reset_drive();
-	 tmp_irq = autoirq_report(10);
-	 disable_interrupts();
-	 
-         irq_used = 0;
-	 set_drive_params();
-	 irq_used = tmp_irq;
-      }
-      else
-      {
-         tmp_irq = irq_used; /* Need IRQ 0 because we can't sleep here. */
-         irq_used = 0;
+      tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */
+      cdu31a_irq = 0;
 
-	 set_drive_params();
+      set_drive_params();
 
-         irq_used = tmp_irq;
-      }
+      cdu31a_irq = tmp_irq;
       
-      if (irq_used > 0)
+      if (cdu31a_irq > 0)
       {
-	 if (request_irq(irq_used, cdu31a_interrupt, SA_INTERRUPT, "cdu31a"))
+	 if (request_irq(cdu31a_irq, cdu31a_interrupt, SA_INTERRUPT, "cdu31a"))
 	 {
-	    printk("Unable to grab IRQ%d for the CDU31A driver\n", irq_used);
-	    irq_used = 0;
+	    printk("Unable to grab IRQ%d for the CDU31A driver\n", cdu31a_irq);
+	    cdu31a_irq = 0;
 	 }
       }
       
@@ -2977,9 +3026,9 @@
       {
 	 printk(", double speed");
       }
-      if (irq_used > 0)
+      if (cdu31a_irq > 0)
       {
-	 printk(", irq %d", irq_used);
+	 printk(", irq %d", cdu31a_irq);
       }
       printk("\n");
 
@@ -2989,13 +3038,6 @@
       /* use 'mount -o block=2048' */
       blksize_size[MAJOR_NR] = &cdu31a_block_size;
       
-      last_sony_subcode = (struct s_sony_subcode *) mem_start;
-      mem_start += sizeof(*last_sony_subcode);
-      readahead_buffer = (unsigned char *) mem_start;
-      mem_start += CD_FRAMESIZE_RAW;
-      sony_toc = (struct s_sony_session_toc *) mem_start;
-      mem_start += sizeof(struct s_sony_session_toc);
-
       cdu31a_abort_timer.next = NULL;
       cdu31a_abort_timer.prev = NULL;
       cdu31a_abort_timer.function = handle_abort_timeout;
@@ -3004,5 +3046,36 @@
 
    disk_changed = 1;
    
+#ifdef MODULE
+   if (drive_found)
+   {
+      return(0);
+   }
+   else
+   {
+      return -EIO;
+   }
+#else
    return mem_start;
+#endif
 }
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+   if (sony_usage != 0)
+   {
+      printk("cdu31a module in use - can't remove it.\n");
+      return;
+   }
+
+   if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL))    
+   {
+      printk("Can't unregister cdu31a\n");
+      return;
+   }
+   release_region(cdu31a_port,4);
+   printk("cdu31a module released.\n");
+}   
+#endif MODULE
diff -u --recursive --new-file v1.3.13/linux/drivers/block/cm206.c linux/drivers/block/cm206.c
--- v1.3.13/linux/drivers/block/cm206.c	Tue Jul 25 18:21:21 1995
+++ linux/drivers/block/cm206.c	Mon Jul 31 09:46:27 1995
@@ -302,7 +302,7 @@
 int sleep_or_timeout(struct wait_queue ** wait, int timeout)
 {
   cd->timer.data=(unsigned long) wait;
-  cd->timer.expires = timeout;
+  cd->timer.expires = jiffies + timeout;
   add_timer(&cd->timer);
   interruptible_sleep_on(wait);
   del_timer(&cd->timer);
diff -u --recursive --new-file v1.3.13/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v1.3.13/linux/drivers/block/floppy.c	Tue Jul 11 10:02:49 1995
+++ linux/drivers/block/floppy.c	Mon Jul 31 10:34:08 1995
@@ -599,10 +599,10 @@
 		drive = current_drive;
 	del_timer(&fd_timeout);
 	if (drive < 0 || drive > N_DRIVE) {
-		fd_timeout.expires = 2000;
+		fd_timeout.expires = jiffies + 20*HZ;
 		drive=0;
 	} else
-		fd_timeout.expires = UDP->timeout;
+		fd_timeout.expires = jiffies + UDP->timeout;
 	add_timer(&fd_timeout);
 	if (UDP->flags & FD_DEBUG){
 		DPRINT("reschedule timeout ");
@@ -671,7 +671,7 @@
 	if (UDP->flags & FD_BROKEN_DCL)
 		return UTESTF(FD_DISK_CHANGED);
 	if( (inb_p(FD_DIR) ^ UDP->flags) & 0x80){
-		USETF(FD_VERIFY); /* verify write protection */		
+		USETF(FD_VERIFY); /* verify write protection */
 		if(UDRS->maxblock){
 			/* mark it changed */
 			USETF(FD_DISK_CHANGED);
@@ -714,9 +714,9 @@
 		if(is_selected(olddor, unit) && !is_selected(newdor,unit)){
 			drive = REVDRIVE(fdc,unit);
 #ifdef DCL_DEBUG
-	if (UDP->flags & FD_DEBUG){
-		DPRINT("calling disk change from set_dor\n");
-	}
+			if (UDP->flags & FD_DEBUG){
+				DPRINT("calling disk change from set_dor\n");
+			}
 #endif
 			disk_change(drive);
 		}
@@ -858,7 +858,7 @@
 		delta = jiffies - UDRS->first_read_date + HZ -
 			UDP->spindown_offset;
 		delta = (( delta * UDP->rps) % HZ ) / UDP->rps;
-		motor_off_timer[drive].expires = UDP->spindown - delta;
+		motor_off_timer[drive].expires = jiffies + UDP->spindown - delta;
 	}
 	add_timer(motor_off_timer+drive);
 }
@@ -908,7 +908,7 @@
 	} else {		
 		del_timer(&fd_timer);
 		fd_timer.function = (timeout_fn) fd_watchdog;
-		fd_timer.expires = 10;
+		fd_timer.expires = jiffies + 10;
 		add_timer(&fd_timer);
 	}
 }
@@ -932,7 +932,7 @@
 	if ( jiffies < delay ){
 		del_timer(&fd_timer);
 		fd_timer.function = function;
-		fd_timer.expires = delay  - jiffies;
+		fd_timer.expires = delay;
 		add_timer(&fd_timer);
 		return 1;
 	}
@@ -1730,7 +1730,7 @@
 		printk("fd_timer.function=%p\n", fd_timer.function);
 	if(fd_timeout.prev){
 		printk("timer_table=%p\n",fd_timeout.function);
-		printk("expires=%ld\n",fd_timeout.expires);
+		printk("expires=%ld\n",fd_timeout.expires-jiffies);
 		printk("now=%ld\n",jiffies);
 	}
 	printk("cont=%p\n", cont);
@@ -2730,7 +2730,8 @@
 	generic_failure,
 	generic_done };
 
-static int poll_drive(int interruptible, int flag){
+static int poll_drive(int interruptible, int flag)
+{
 	int ret;
 	/* no auto-sense, just clear dcl */
 	raw_cmd.flags= flag;
@@ -3311,7 +3312,7 @@
 		return 0;
 	}
 
-	if (UTESTF(FD_DISK_CHANGED))
+	if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY))
 		return 1;
 
 	if(UDRS->last_checked + UDP->checkfreq < jiffies){
@@ -3319,8 +3320,9 @@
 		poll_drive(0,0);
 		process_fd_request();
 	}
-		
+
 	if(UTESTF(FD_DISK_CHANGED) ||
+	   UTESTF(FD_VERIFY) ||
 	   test_bit(drive, &fake_change) ||
 	   (!TYPE(dev) && !current_type[drive]))
 		return 1;
@@ -3338,9 +3340,12 @@
 	int drive=DRIVE(dev);
 	int cf;
 
-	if(UTESTF(FD_DISK_CHANGED) || test_bit(drive, &fake_change) || NO_GEOM){
+	if(UTESTF(FD_DISK_CHANGED) || 
+	   UTESTF(FD_VERIFY) ||
+	   test_bit(drive, &fake_change) || 
+	   NO_GEOM){
 		lock_fdc(drive,0);
-		cf = UTESTF(FD_DISK_CHANGED);
+		cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY);
 		if(! (cf || test_bit(drive, &fake_change) || NO_GEOM)){
 			process_fd_request(); /*already done by another thread*/
 			return 0;
@@ -3556,7 +3561,7 @@
 			return;
 		}
 	}
-	DPRINT1("unknown floppy option %s\n", str);
+	DPRINT1("unknown floppy option [%s]\n", str);
 	DPRINT("allowed options are:");
 	for(i=0; i< ARRAY_SIZE(config_params); i++)
 		printk(" %s",config_params[i].name);
@@ -3759,44 +3764,51 @@
 
 extern char *get_options(char *str, int *ints);
 
-#if 0
-/* assuming that insmod is compiled as a.out binary using a shared
-   C library ... */
-int ENVIRON = 0x60090b34;
-
-static void
-mod_setup(char *name,
-	  void (*setup)(char *, int *)) {
-	char **environ,*env,*ptr,c,i;
-	char line[100];
+static void mod_setup(char *pattern, void (*setup)(char *, int *))
+{
+	int i;
+	char c;
+	int j;
+	int match;
+	char buffer[100];
 	int ints[11];
+	int length = strlen(pattern)+1;
 
-	environ = (char **) get_fs_long( ENVIRON );
-	
-	while((env = (char *)get_fs_long(environ))){
-		for(i=0; i<strlen(name); i++)
-			if ( (char) get_fs_byte(env++) != name[i] )
+	match=0;
+	j=1;
+
+	for(i=current->mm->env_start; 
+	    i< current->mm->env_end; 
+	    i ++){
+		c= get_fs_byte(i);
+		if(match){
+			if(j==99)
+				c='\0';
+			buffer[j] = c;
+			if(!c || c == ' ' || c == '\t'){
+				if(j){
+					buffer[j] = '\0';
+					setup(get_options(buffer,ints),ints);
+				}
+				j=0;
+			} else
+				j++;
+			if(!c)
 				break;
-		if(i == strlen(name)){
-			ptr=line;
-			while(ptr < line+99){
-			        c = (char)get_fs_byte(env++);
-				if ( c== ' ' || !c ){
-					*ptr='\0';
-					if(ptr!=line)
-						setup(get_options(line,ints),
-						      ints);
-					ptr=line;
-					if (!c)
-						break;
-				} else
-					*ptr++ = c;
-			}
+			continue;
+		}
+		if( (!j && !c) ||
+		   ( j && c == pattern[j-1]))
+			j++;
+		else
+			j=0;
+		if(j==length){
+			match=1;
+			j=0;
 		}
-		environ++;
 	}
 }
-#endif
+
 
 #ifdef __cplusplus
 extern "C" {
@@ -3806,8 +3818,7 @@
 	int ret;
 	printk("inserting floppy driver for %s\n", kernel_version);
 
-	/*mod_setup("floppy=", floppy_setup);*/
-	/* Can't do that any more, insmod is now ELF */
+	mod_setup("floppy=", floppy_setup);
 
 	ret = floppy_init();
 	return 0;
diff -u --recursive --new-file v1.3.13/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v1.3.13/linux/drivers/block/genhd.c	Thu Jul 13 16:20:20 1995
+++ linux/drivers/block/genhd.c	Mon Jul 31 14:38:20 1995
@@ -12,13 +12,16 @@
 
 /*
  *  Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca)
- *  with hints from uwe@eas.iis.fhg.de (us3@irz.inf.tu-dresden.de).
+ *  with information provided by OnTrack.  This now works for linux fdisk
+ *  and LILO, as well as loadlin and bootln.  Note that disks other than
+ *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
  */
 
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
+#include <linux/config.h>
 
 struct gendisk *gendisk_head = NULL;
 
@@ -110,17 +113,14 @@
 
 static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector)
 {
-	int i, minor = current_minor, found_dm6 = 0;
+	int i, minor = current_minor, tested_for_dm6 = 0;
 	struct buffer_head *bh;
 	struct partition *p;
 	int mask = (1 << hd->minor_shift) - 1;
-#ifdef CONFIG_BLK_DEV_IDE
-	extern void ide_xlate_1024(dev_t);
-#endif
 
 read_mbr:
 	if (!(bh = bread(dev,0,1024))) {
-		printk("unable to read partition table\n");
+		printk(" unable to read partition table\n");
 		return -1;
 	}
 	if (*(unsigned short *)  (0x1fe + bh->b_data) != 0xAA55) {
@@ -129,47 +129,50 @@
 	}
 	p = (struct partition *) (0x1be + bh->b_data);
 
-	/*
-	 *  Check for Disk Manager v6.0x "Dynamic Disk Overlay" (DDO)
-	 */
-	if (p->sys_ind == DM6_PARTITION && !found_dm6++)
-	{
-		printk(" [DM6:DDO]");
-		/*
-		 * Everything is offset by one track (p->end_sector sectors),
-		 * and a translated geometry is used to reduce the number
-		 * of apparent cylinders to 1024 or less.
-		 *
-		 * For complete compatibility with linux fdisk, we do:
-		 *  1. tell the driver to offset *everything* by one track,
-		 *  2. reduce the apparent disk capacity by one track,
-		 *  3. adjust the geometry reported by HDIO_GETGEO (for fdisk),
-		 *	(does nothing if not an IDE drive, but that's okay).
-		 *  4. invalidate our in-memory copy of block zero,
-		 *  5. restart the partition table hunt from scratch.
-		 */
-		first_sector                    += p->end_sector;
-		hd->part[MINOR(dev)].start_sect += p->end_sector;
-		hd->part[MINOR(dev)].nr_sects   -= p->end_sector;
 #ifdef CONFIG_BLK_DEV_IDE
-		ide_xlate_1024(dev);	/* harmless if not an IDE drive */
-#endif
-		bh->b_dirt = 0;		/* prevent re-use of this block */
-		bh->b_uptodate = 0;
-		bh->b_req = 0;
-		brelse(bh);
-		goto read_mbr;
-	}
-
 	/*
-	 *  Check for Disk Manager v6.0x DDO on a secondary drive (?)
+	 *  Check for Disk Manager v6.0x with geometry translation
 	 */
-	if (p->sys_ind == DM6_AUXPARTITION) {
-		printk(" [DM6]");
-#ifdef CONFIG_BLK_DEV_IDE
-		ide_xlate_1024(dev);	/* harmless if not an IDE drive */
-#endif
+	if (!tested_for_dm6++) {	/* only check for DM6 *once* */
+		extern int ide_xlate_1024(dev_t, int, char *);
+		/* check for DM6 with Dynamic Drive Overlay (DDO) */
+		if (p->sys_ind == DM6_PARTITION) {
+			/*
+			 * Everything on the disk is offset by 63 sectors,
+			 * including a "new" MBR with its own partition table,
+			 * and the remainder of the disk must be accessed using
+			 * a translated geometry that reduces the number of 
+			 * apparent cylinders to less than 1024 if possible.
+			 *
+			 * ide_xlate_1024() will take care of the necessary
+			 * adjustments to fool fdisk/LILO and partition check.
+			 */
+			if (ide_xlate_1024(dev,1," [DM6:DDO]")) {
+				bh->b_dirt = 0;	/* force re-read of MBR block */
+				bh->b_uptodate = 0;
+				bh->b_req = 0;
+				brelse(bh);
+				goto read_mbr;	/* start over with new MBR */
+			}
+		} else {
+			/* look for DM6 signature in MBR, courtesy of OnTrack */
+			unsigned int sig = *(unsigned short *)(bh->b_data + 2);
+			if (sig <= 0x1ae
+			 && *(unsigned short *)(bh->b_data + sig) == 0x55AA
+			 && (1 & *(unsigned char *)(bh->b_data + sig + 2)) ) 
+			{
+				(void)ide_xlate_1024(dev,0," [DM6:MBR]");
+			} else {
+				/* look for DM6 AUX partition type in slot 1 */
+				if (p->sys_ind == DM6_AUX1PARTITION
+				 || p->sys_ind == DM6_AUX3PARTITION)
+				{
+					(void)ide_xlate_1024(dev,0," [DM6:AUX]");
+				}
+			}
+		}
 	}
+#endif	/* CONFIG_BLK_DEV_IDE */
 
 	current_minor += 4;  /* first "extra" minor (for extended partitions) */
 	for (i=1 ; i<=4 ; minor++,i++,p++) {
@@ -303,7 +306,7 @@
 	if (osf_partition(hd, dev, first_sector))
 		return;
 #endif
-	printk("unknown partition table\n");
+	printk(" unknown partition table\n");
 }
 
 /* This function is used to re-read partition tables for removable disks.
diff -u --recursive --new-file v1.3.13/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v1.3.13/linux/drivers/block/ide.c	Tue Jul 18 16:28:56 1995
+++ linux/drivers/block/ide.c	Mon Jul 31 14:30:15 1995
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 4.00  Jul 10, 1995
+ *  linux/drivers/block/ide.c	Version 4.11  Jul 29, 1995
  *
  *  Copyright (C) 1994, 1995  Linus Torvalds & authors (see below)
  */
@@ -91,6 +91,10 @@
  *			add transparent support for DiskManager-6.0x "Dynamic
  *			 Disk Overlay" (DDO), most of this in in genhd.c
  *			eliminate "multiple mode turned off" message at boot
+ *  Version 4.10	fix bug in ioctl for "hdparm -c3"
+ *			fix DM6:DDO support -- now works with LILO, fdisk, ...
+ *			don't treat some naughty WD drives as removeable
+ *  Version 4.11	updated DM6 support using info provided by OnTrack
  *
  *  To do:
  *	- add support for alternative IDE port addresses
@@ -278,6 +282,8 @@
  * For fast indexing, sizeof(ide_dev_t) = 32 = power_of_2;
  * Everything is carefully aligned on appropriate boundaries,
  *  and several fields are placed for optimal (gcc) access.
+ *
+ * Ugh.  Actually, we're two bytes over (34 bytes).. gotta fix this someday.
  */
 typedef enum {disk, cdrom} dev_type;
 
@@ -322,6 +328,7 @@
 	const char *name;
 	struct hd_driveid *id;
 	struct wait_queue *wqueue;
+	byte sect0, removeable;
 	} ide_dev_t;
 
 /*
@@ -1153,7 +1160,7 @@
 		end_request(0, HWIF);
 		goto repeat;
 	}
-	block += ide_hd[HWIF][minor].start_sect;
+	block += ide_hd[HWIF][minor].start_sect + dev->sect0;
 #if (DISK_RECOVERY_TIME > 0)
 	while ((read_timer() - ide_lastreq[HWIF]) < DISK_RECOVERY_TIME);
 #endif
@@ -1334,9 +1341,11 @@
 
 	if (drive < MAX_DRIVES) {
 		switch (MAJOR(i_rdev)) {
+#ifndef CONFIG_BLK_DEV_HD
 			case IDE0_MAJOR:	dev = &ide_dev[0][drive];
 						if (dev->present) return dev;
 						break;
+#endif /* CONFIG_BLK_DEV_HD */
 			case IDE1_MAJOR:	dev = &ide_dev[1][drive];
 						if (dev->present) return dev;
 						break;
@@ -1358,12 +1367,12 @@
 		sleep_on(&dev->wqueue);
 	dev->usage++;
 	restore_flags(flags);
-	if (dev->id && (dev->id->config & (1<<7)))	/* for removeable disks */
-		check_disk_change(inode->i_rdev);
 #ifdef CONFIG_BLK_DEV_IDECD
 	if (dev->type == cdrom)
 		return cdrom_open (inode, filp, dev);
 #endif	/* CONFIG_BLK_DEV_IDECD */
+	if (dev->removeable)	/* for disks */
+		check_disk_change(inode->i_rdev);
 	return 0;
 }
 
@@ -1567,9 +1576,12 @@
 		case HDIO_SET_KEEPSETTINGS:
 		case HDIO_SET_UNMASKINTR:
 		case HDIO_SET_NOWERR:
+			if (arg > 1)
+				return -EINVAL;
 		case HDIO_SET_CHIPSET:
-			if (!suser()) return -EACCES;
-			if ((arg > 1) || (MINOR(inode->i_rdev) & PARTN_MASK))
+			if (!suser())
+				return -EACCES;
+			if ((MINOR(inode->i_rdev) & PARTN_MASK))
 				return -EINVAL;
 			save_flags(flags);
 			cli();
@@ -1654,7 +1666,7 @@
 	if (dev->type == cdrom)
 		return cdrom_check_media_change (dev);
 #endif	/* CONFIG_BLK_DEV_IDECD */
-	if (dev->id && (dev->id->config & (1<<7))) /* for removeable disks */
+	if (dev->removeable) /* for disks */
 		return 1;	/* always assume it was changed */
 	return 0;
 }
@@ -1763,12 +1775,19 @@
 			printk(" UNKNOWN device\n");
 		dev->type = cdrom;	/* until we do it "correctly" above */
 		dev->present = 1;
+		dev->removeable = 1;
 #else
 		printk(unsupported);
 #endif	/* CONFIG_BLK_DEV_IDECD */
 		return;
 	}
 
+	/* check for removeable disks (eg. SYQUEST), ignore 'WD' drives */
+	if (id->config & (1<<7)) {	/* removeable disk ? */
+		if (id->model[0] != 'W' || id->model[1] != 'D')
+			dev->removeable = 1;
+	}
+
 	dev->type = disk;
 	/* Extract geometry if we did not already have one for the drive */
 	if (!dev->present) {
@@ -2159,20 +2178,36 @@
 	ide_setup (str, ints);
 }
 
-
-void ide_xlate_1024 (dev_t full_dev)
+int ide_xlate_1024 (dev_t full_dev, int need_offset, char *msg)
 {
 	ide_dev_t *dev;
+	byte head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0}, *heads = head_vals;
+	unsigned long capacity;
 
-	if ((dev = get_info_ptr(full_dev)) != NULL) {
-		dev->bios_cyl -= 1;		/* keeps fdisk sane */
-		while (dev->bios_cyl > 1024) {
-			if (dev->bios_head > 32)
-				return;
-			dev->bios_head *= 2;
-			dev->bios_cyl  /= 2;
-		}
+	if ((dev = get_info_ptr(full_dev)) == NULL && dev->id == NULL)
+		return 0;
+
+	dev->cyl  = dev->bios_cyl   = dev->id->cyls;
+	dev->head = dev->bios_head  = dev->id->heads;
+	dev->sect = dev->bios_sect  = dev->id->sectors; 
+	dev->special.b.set_geometry = 1;
+
+	capacity = dev->bios_cyl * dev->bios_head * dev->bios_sect / 63;
+	dev->bios_sect = 63;
+	do {
+		dev->bios_head = *heads;
+		dev->bios_cyl = capacity / dev->bios_head;
+	} while (dev->bios_cyl >= 1024 && *++heads);
+	if (need_offset) {
+		dev->sect0 = 63;
+		capacity -= 1;
+		dev->bios_cyl = capacity / dev->bios_head;
 	}
+	capacity = dev->bios_cyl * dev->bios_head * dev->bios_sect;
+	ide_capacity[DEV_HWIF][dev->select.b.drive] = capacity;
+	ide_hd[DEV_HWIF][MINOR(full_dev)].nr_sects  = capacity;
+	printk("%s [+%d,%d/%d/%d]", msg, dev->sect0, dev->bios_cyl, dev->bios_head, dev->bios_sect);
+	return 1;
 }
 
 #ifndef CONFIG_BLK_DEV_HD
@@ -2243,6 +2278,8 @@
 		dev->special.b.recalibrate	= 1;
 		dev->special.b.set_geometry	= 1;
 		dev->keep_settings		= 0;
+		dev->sect0			= 0;
+		dev->removeable			= 0;
 		ide_hd[hwif][drive<<PARTN_BITS].start_sect = 0;
 		dev->name = ide_devname[hwif][drive];
 		if (!dev->bad_wstat)
diff -u --recursive --new-file v1.3.13/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c
--- v1.3.13/linux/drivers/block/sbpcd.c	Fri Jul  7 08:54:45 1995
+++ linux/drivers/block/sbpcd.c	Mon Jul 31 09:46:27 1995
@@ -757,7 +757,7 @@
 	if (current == task[0]) 
 	{
 		del_timer(&delay_timer);
-		delay_timer.expires=time;
+		delay_timer.expires=jiffies+time;
 		timed_out_delay=0;
 		add_timer(&delay_timer);
 		while (!timed_out_delay) ;
@@ -2945,7 +2945,7 @@
 #if 1
 	del_timer(&delay_timer);
 #endif
-	delay_timer.expires=110;
+	delay_timer.expires=jiffies+110;
 	timed_out_delay=0;
 	add_timer(&delay_timer);
 	msg(DBG_TIM,"delay timer started (110).\n");
@@ -4579,7 +4579,7 @@
 		SBPCD_CLI;
 		
 		del_timer(&data_timer);
-		data_timer.expires=max_latency;
+		data_timer.expires=jiffies+max_latency;
 		timed_out_data=0;
 		add_timer(&data_timer);
 		while (!timed_out_data) 
diff -u --recursive --new-file v1.3.13/linux/drivers/block/sjcd.c linux/drivers/block/sjcd.c
--- v1.3.13/linux/drivers/block/sjcd.c	Tue Jul 18 16:28:57 1995
+++ linux/drivers/block/sjcd.c	Mon Jul 31 09:46:27 1995
@@ -191,8 +191,8 @@
  */
 static struct timer_list sjcd_delay_timer = { NULL, NULL, 0, 0, NULL };
 
-#define SJCD_SET_TIMER( func, jiffies )           \
-    ( sjcd_delay_timer.expires = jiffies,         \
+#define SJCD_SET_TIMER( func, tmout )           \
+    ( sjcd_delay_timer.expires = jiffies+tmout,         \
       sjcd_delay_timer.function = ( void * )func, \
       add_timer( &sjcd_delay_timer ) )
 
diff -u --recursive --new-file v1.3.13/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v1.3.13/linux/drivers/char/lp.c	Thu Jun 29 19:02:40 1995
+++ linux/drivers/char/lp.c	Mon Jul 31 10:20:02 1995
@@ -51,15 +51,6 @@
    (status & (LP_PBUSY|LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
       (LP_PBUSY|LP_PSELECD|LP_PERRORP) 
 
-/* Allow old versions of tunelp to continue to work */
-#define OLD_LPCHAR   0x0001
-#define OLD_LPTIME   0x0002
-#define OLD_LPABORT  0x0004
-#define OLD_LPSETIRQ 0x0005
-#define OLD_LPGETIRQ 0x0006
-#define OLD_LPWAIT   0x0008
-#define OLD_IOCTL_MAX 8
-
 /* 
  * All my debugging code assumes that you debug with only one printer at
  * a time. RWWH
@@ -406,19 +397,13 @@
 		return -ENODEV;
 	if ((LP_F(minor) & LP_EXIST) == 0)
 		return -ENODEV;
-	if (cmd <= OLD_IOCTL_MAX)
-		printk(KERN_NOTICE "lp%d: warning: obsolete ioctl %#x (perhaps you need a new tunelp)\n",
-		    minor, cmd);
 	switch ( cmd ) {
-		case OLD_LPTIME:
 		case LPTIME:
 			LP_TIME(minor) = arg;
 			break;
-		case OLD_LPCHAR:
 		case LPCHAR:
 			LP_CHAR(minor) = arg;
 			break;
-		case OLD_LPABORT:
 		case LPABORT:
 			if (arg)
 				LP_F(minor) |= LP_ABORT;
@@ -437,11 +422,9 @@
 			else
 				LP_F(minor) &= ~LP_CAREFUL;
 			break;
-		case OLD_LPWAIT:
 		case LPWAIT:
 			LP_WAIT(minor) = arg;
 			break;
-		case OLD_LPSETIRQ:
 		case LPSETIRQ: {
 			int oldirq;
 			int newirq = arg;
@@ -485,9 +468,6 @@
 			lp_reset(minor);
 			break;
 		}
-		case OLD_LPGETIRQ:
-			retval = LP_IRQ(minor);
-			break;
 		case LPGETIRQ:
 			retval = verify_area(VERIFY_WRITE, (void *) arg,
 			    sizeof(int));
diff -u --recursive --new-file v1.3.13/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v1.3.13/linux/drivers/char/psaux.c	Thu Jul 27 10:13:16 1995
+++ linux/drivers/char/psaux.c	Mon Jul 31 10:34:08 1995
@@ -12,13 +12,15 @@
  * Changed to prevent keyboard lockups on AST Power Exec.
  * 28Jul93  Brad Bosch - brad@lachman.com
  *
- * Modified by Johan Myreen (jempandora.pp.fi) 04Aug93
+ * Modified by Johan Myreen (jem@pandora.pp.fi) 04Aug93
  *   to include support for QuickPort mouse.
  *
  * Changed references to "QuickPort" with "82C710" since "QuickPort"
  * is not what this driver is all about -- QuickPort is just a
  * connector type, and this driver is for the mouse port on the Chips
  * & Technologies 82C710 interface chip. 15Nov93 jem@pandora.pp.fi
+ *
+ * Added support for SIGIO. 28Jul95 jem@pandora.pp.fi
  */
 
 /* Uncomment the following line if your mouse needs initialization. */
@@ -30,6 +32,7 @@
 #include <linux/fcntl.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
+#include <linux/malloc.h>
 
 #include <asm/io.h>
 #include <asm/segment.h>
@@ -95,6 +98,7 @@
 	unsigned long head;
 	unsigned long tail;
 	struct wait_queue *proc_list;
+	struct fasync_struct *fasync;
 	unsigned char buf[AUX_BUF_SIZE];
 };
 
@@ -104,6 +108,7 @@
 static int aux_present = 0;
 static int poll_aux_status(void);
 static int poll_aux_status_nosleep(void);
+static int fasync_aux(struct inode *inode, struct file *filp, int on);
 
 #ifdef CONFIG_82C710_MOUSE
 static int qp_present = 0;
@@ -122,9 +127,9 @@
 
 static void aux_write_dev(int val)
 {
-	poll_aux_status_nosleep();
+	poll_aux_status();
 	outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);	/* write magic cookie */
-	poll_aux_status_nosleep();
+	poll_aux_status();
 	outb_p(val,AUX_OUTPUT_PORT);		/* write data */
 }
 
@@ -137,7 +142,10 @@
 {
         int retries = 0;
 
-	aux_write_dev(val);		/* write the value to the device */
+	poll_aux_status_nosleep();
+	outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
+	poll_aux_status_nosleep();
+	outb_p(val,AUX_OUTPUT_PORT);
 	poll_aux_status_nosleep();
 
 	if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
@@ -199,6 +207,8 @@
 	}
 	queue->head = head;
 	aux_ready = 1;
+	if (queue->fasync)
+		kill_fasync(queue->fasync, SIGIO);
 	wake_up_interruptible(&queue->proc_list);
 }
 
@@ -220,6 +230,8 @@
 	}
 	queue->head = head;
 	aux_ready = 1;
+	if (queue->fasync)
+		kill_fasync(queue->fasync, SIGIO);
 	wake_up_interruptible(&queue->proc_list);
 }
 #endif
@@ -227,14 +239,12 @@
 
 static void release_aux(struct inode * inode, struct file * file)
 {
-#ifndef __alpha__
-	aux_write_dev(AUX_DISABLE_DEV);		/* disable aux device */
-#endif
 	aux_write_cmd(AUX_INTS_OFF);		/* disable controller ints */
 	poll_aux_status();
 	outb_p(AUX_DISABLE,AUX_COMMAND);      	/* Disable Aux device */
 	poll_aux_status();
 	free_irq(AUX_IRQ);
+	fasync_aux(inode, file, 0);
 	aux_busy = 0;
 }
 
@@ -250,10 +260,43 @@
 	if (!poll_qp_status())
 	        printk("Warning: Mouse device busy in release_qp()\n");
 	free_irq(QP_IRQ);
+	fasync_aux(inode, file, 0);
 	qp_busy = 0;
 }
 #endif
 
+static int fasync_aux(struct inode *inode, struct file *filp, int on)
+{
+	struct fasync_struct *fa, *prev;
+
+	for (fa = queue->fasync, prev = 0; fa; prev= fa, fa = fa->fa_next) {
+		if (fa->fa_file == filp)
+			break;
+	}
+
+	if (on) {
+		if (fa)
+		    return 0;
+		fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
+		if (!fa)
+			return -ENOMEM;
+		fa->magic = FASYNC_MAGIC;
+		fa->fa_file = filp;
+		fa->fa_next = queue->fasync;
+		queue->fasync = fa;
+	}
+	else {
+		if (!fa)
+			return 0;
+		if (prev)
+			prev->fa_next = fa->fa_next;
+		else
+			queue->fasync = fa->fa_next;
+		kfree_s(fa, sizeof(struct fasync_struct));
+	}
+	return 0;	
+}
+
 /*
  * Install interrupt handler.
  * Enable auxiliary device.
@@ -426,6 +469,8 @@
 	NULL,		/* mmap */
 	open_aux,
 	release_aux,
+	NULL,
+	fasync_aux
 };
 
 
@@ -470,7 +515,10 @@
 	        poll_aux_status_nosleep();
 #endif /* INITIALIZE_DEVICE */
         	outb_p(AUX_DISABLE,AUX_COMMAND);   /* Disable Aux device */
-	        aux_write_cmd(AUX_INTS_OFF);    /* disable controller ints */
+		poll_aux_status_nosleep();
+		outb_p(AUX_CMD_WRITE,AUX_COMMAND);
+		poll_aux_status_nosleep();             /* Disable interrupts */
+		outb_p(AUX_INTS_OFF, AUX_OUTPUT_PORT); /*  on the controller */
 	}
 	return kmem_start;
 }
diff -u --recursive --new-file v1.3.13/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v1.3.13/linux/drivers/char/vt.c	Thu Jun 29 19:02:41 1995
+++ linux/drivers/char/vt.c	Mon Jul 31 09:46:27 1995
@@ -169,7 +169,7 @@
 		outb((count >> 8) & 0xff, 0x42);
 
 		if (ticks) {
-			sound_timer.expires = ticks;
+			sound_timer.expires = jiffies+ticks;
 			add_timer(&sound_timer);
 		}
 	} else
diff -u --recursive --new-file v1.3.13/linux/drivers/net/atp.c linux/drivers/net/atp.c
--- v1.3.13/linux/drivers/net/atp.c	Fri Jun 30 16:22:26 1995
+++ linux/drivers/net/atp.c	Mon Jul 31 09:46:26 1995
@@ -248,7 +248,7 @@
 
 #ifdef TIMED_CHECKER
 	del_timer(&atp_timer);
-	atp_timer.expires = TIMED_CHECKER;
+	atp_timer.expires = jiffies + TIMED_CHECKER;
 	atp_timed_dev = dev;
 	add_timer(&atp_timer);
 #endif
@@ -585,7 +585,7 @@
 			write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);
 #ifdef TIMED_CHECKER
 		del_timer(&atp_timer);
-		atp_timer.expires = TIMED_CHECKER;
+		atp_timer.expires = jiffies + TIMED_CHECKER;
 		add_timer(&atp_timer);
 #endif
 	}
@@ -635,7 +635,7 @@
 #endif
 	}
   del_timer(&atp_timer);
-  atp_timer.expires = TIMED_CHECKER;
+  atp_timer.expires = jiffies + TIMED_CHECKER;
   add_timer(&atp_timer);
 }
 #endif
diff -u --recursive --new-file v1.3.13/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v1.3.13/linux/drivers/net/eql.c	Thu Jul 13 16:20:20 1995
+++ linux/drivers/net/eql.c	Mon Jul 31 09:46:27 1995
@@ -222,7 +222,7 @@
 
   init_timer (&eql->timer);
   eql->timer.data     = (unsigned long) dev->priv;
-  eql->timer.expires  = EQL_DEFAULT_RESCHED_IVAL;
+  eql->timer.expires  = jiffies+EQL_DEFAULT_RESCHED_IVAL;
   eql->timer.function = &eql_timer;
   eql->timer_on       = 0;
 
@@ -1160,7 +1160,7 @@
 
   if (eql->timer_on != 0) 
     {
-      eql->timer.expires = EQL_DEFAULT_RESCHED_IVAL;
+      eql->timer.expires = jiffies+EQL_DEFAULT_RESCHED_IVAL;
       add_timer (&eql->timer);
     }
 }
diff -u --recursive --new-file v1.3.13/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v1.3.13/linux/drivers/net/ibmtr.c	Fri Jun 30 16:22:28 1995
+++ linux/drivers/net/ibmtr.c	Mon Jul 31 09:46:27 1995
@@ -627,7 +627,7 @@
 						DPRINTK("open failed: ret_code = %02X, retrying\n",open_response->ret_code);
 					}
 					if(ti->open_status!=FAILURE) {
-						tr_timer.expires=TR_RETRY_INTERVAL;
+						tr_timer.expires=jiffies+TR_RETRY_INTERVAL;
 						tr_timer.data=(unsigned long)dev;
 						tr_timer.next=tr_timer.prev=NULL;
 						add_timer(&tr_timer);
@@ -642,7 +642,7 @@
 					struct dlc_open_sap *open_sap=(struct dlc_open_sap *)ti->srb;
 					if(open_sap->ret_code) {
 						DPRINTK("open_sap failed: ret_code = %02X,retrying\n",open_sap->ret_code);
-						tr_timer.expires=TR_RETRY_INTERVAL;
+						tr_timer.expires=jiffies+TR_RETRY_INTERVAL;
 						tr_timer.data=(unsigned long)dev;
 						tr_timer.next=tr_timer.prev=NULL;
 						add_timer(&tr_timer);
@@ -724,7 +724,7 @@
 					if(ring_status & (SIGNAL_LOSS + LOBE_FAULT)) {
 						DPRINTK("Signal loss/Lobe fault\n");
 						DPRINTK("We try to reopen the adapter.\n");	
-						tr_timer.expires=TR_RETRY_INTERVAL;
+						tr_timer.expires=jiffies+TR_RETRY_INTERVAL;
 						tr_timer.data=(unsigned long)dev;
 						tr_timer.next=tr_timer.prev=NULL;
 						add_timer(&tr_timer);
diff -u --recursive --new-file v1.3.13/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v1.3.13/linux/drivers/net/wavelan.c	Fri Jul  7 08:54:48 1995
+++ linux/drivers/net/wavelan.c	Mon Jul 31 09:46:27 1995
@@ -1824,7 +1824,7 @@
 		return;
 	}
 
-	lp->watchdog.expires = WATCHDOG_JIFFIES;
+	lp->watchdog.expires = jiffies+WATCHDOG_JIFFIES;
 	add_timer(&lp->watchdog);
 
 	if (jiffies - dev->trans_start < WATCHDOG_JIFFIES)
diff -u --recursive --new-file v1.3.13/linux/drivers/sound/Readme.cards linux/drivers/sound/Readme.cards
--- v1.3.13/linux/drivers/sound/Readme.cards	Tue Jul 11 10:02:51 1995
+++ linux/drivers/sound/Readme.cards	Mon Jul 31 10:20:02 1995
@@ -461,6 +461,13 @@
 editing sound/local.h (after running the config program). Add defines for
 MPU2_BASE & MPU2_IRQ (and MPU3_BASE & MPU3_IRQ) to the file.
 
+CAUTION!
+
+The default I/O base of Adaptec AHA-1542 SCSI controller is 0x330 which
+is also the default of the MPU401 driver. Don't configure the sound driver to
+use 0x330 as the MPU401 base if you have a AHA1542. The kernel will not boot
+if you make this mistake.
+
 PSS
 ---
 
@@ -598,6 +605,9 @@
 82C930 and MAC32. These chips are not supported by VoxWare yet. Please
 contact me if you have a soundcard which uses these chips.
 
+Some MAD16 based cards may cause feedback, whistle or terrible noise if the
+line3 mixer channel is turned too high.
+
 MV Jazz (ProSonic)
 ------------------
 
@@ -628,7 +638,8 @@
 MIDI0001.BIN and it's located in the DOS/Windows driver directory. The file
 may also be called as TSUNAMI.BIN or something else (older cards?).
 
-The OPL4 synth will be riunaccessible without loading the microcontroller code.
+The OPL4 synth will be inaccessible without loading the microcontroller code.
+Also remember to enable MPU401 support if you want to use the OPL4 mode.
 
 NOTE!	Don't answer 'y' when the driver asks about SM Games support
 	(the next question after the MIDI0001.BIN name). However
@@ -673,7 +684,23 @@
 Audio Excel DSP16
 -----------------
 
-See aedsp16.c.
+See comments in aedsp16.c.
+
+
+PCMCIA cards
+------------
+
+Sorry, can't help. Some cards may work and some don't.
+
+TI TM4000M notebooks
+--------------------
+
+These computers have a built in sound support based on the Jazz chipset.
+Look at the instructions for MV Jazz (above). It's also important to note
+that there is something wrong with the mouse port and sound at least on
+some TM models. Don't enable the "C&T 82C710 mouse port support" when
+configuring Linux. Having it enabled is likely to cause mysterious problems
+and kernel failures when sound is used.
 
 Others?
 -------
diff -u --recursive --new-file v1.3.13/linux/drivers/sound/ad1848_mixer.h linux/drivers/sound/ad1848_mixer.h
--- v1.3.13/linux/drivers/sound/ad1848_mixer.h	Tue Jul 11 10:02:52 1995
+++ linux/drivers/sound/ad1848_mixer.h	Mon Jul 31 10:20:02 1995
@@ -123,7 +123,7 @@
   0x4b4b,			/* Output gain */
   0x4b4b,			/* Line1 */
   0x4b4b,			/* Line2 */
-  0x4b4b			/* Line3 */
+  0x3232			/* Line3 (usually line in)*/
 };
 
 #define LEFT_CHN	0
diff -u --recursive --new-file v1.3.13/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v1.3.13/linux/drivers/sound/mad16.c	Tue Jul 11 10:02:53 1995
+++ linux/drivers/sound/mad16.c	Mon Jul 31 10:20:02 1995
@@ -232,10 +232,23 @@
       if (!detect_mad16 ())
 	return 0;
 
-      printk ("mad16.c: A 82C929 detected???\n");
+      printk ("mad16.c: 82C929 detected???\n");
     }
   else
-    printk ("mad16.c: A 82C928 or Mozart detected???\n");
+    {
+      unsigned char model;
+
+      if (((model=mad_read (MC3_PORT)) & 0x03) == 0x03)
+	{
+	  printk ("mad16.c: Mozart detected???\n");
+	  board_type = MOZART;
+	}
+      else
+	{
+	  printk ("mad16.c: 82C928 detected???\n");
+	  board_type = C928;
+	}
+    }
 
   for (i = 0xf8d; i <= 0xf93; i++)
     DDB (printk ("port %03x = %03x\n", i, mad_read (i)));
diff -u --recursive --new-file v1.3.13/linux/drivers/sound/os.h linux/drivers/sound/os.h
--- v1.3.13/linux/drivers/sound/os.h	Tue Jul 11 10:02:53 1995
+++ linux/drivers/sound/os.h	Mon Jul 31 09:46:27 1995
@@ -155,7 +155,7 @@
  */
 
 #define ACTIVATE_TIMER(name, proc, time) \
-  {name.expires = time; \
+  {name.expires = jiffies+(time); \
   add_timer (&name);}
 
 #define INB	inb
diff -u --recursive --new-file v1.3.13/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c
--- v1.3.13/linux/drivers/sound/pas2_card.c	Thu Jul 13 16:20:21 1995
+++ linux/drivers/sound/pas2_card.c	Mon Jul 31 10:20:02 1995
@@ -252,11 +252,14 @@
 								 * rate * of
 								 * 17.897 kHz
 								 */
-
+#if 1
+    pas_write (8, PRESCALE_DIVIDER);
+#else
   if (pas_model == PAS_16 || pas_model == PAS_16D)
     pas_write (8, PRESCALE_DIVIDER);
   else
     pas_write (0, PRESCALE_DIVIDER);
+#endif
 
   mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER);
   mix_write (5, PARALLEL_MIXER);
diff -u --recursive --new-file v1.3.13/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c
--- v1.3.13/linux/drivers/sound/sb_dsp.c	Tue Jul 11 10:02:54 1995
+++ linux/drivers/sound/sb_dsp.c	Mon Jul 31 10:20:02 1995
@@ -854,10 +854,10 @@
 
 
 #ifndef MPU_BASE		/* take default values if not specified */
-#define MPU_BASE 0x330
+#define MPU_BASE 0
 #endif
 #ifndef MPU_IRQ
-#define MPU_IRQ 9
+#define MPU_IRQ 0
 #endif
 
 unsigned int
diff -u --recursive --new-file v1.3.13/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c
--- v1.3.13/linux/drivers/sound/sequencer.c	Tue Jul 11 10:02:54 1995
+++ linux/drivers/sound/sequencer.c	Mon Jul 31 10:20:02 1995
@@ -1818,7 +1818,7 @@
     369998, 391998, 415306, 440000, 466162, 493880
   };
 
-#define BASE_OCTAVE	5
+#define BASE_OCTAVE	4
 
   octave = note_num / 12;
   note = note_num % 12;
diff -u --recursive --new-file v1.3.13/linux/drivers/sound/sound_switch.c linux/drivers/sound/sound_switch.c
--- v1.3.13/linux/drivers/sound/sound_switch.c	Tue Jul 11 10:02:54 1995
+++ linux/drivers/sound/sound_switch.c	Mon Jul 31 09:50:22 1995
@@ -58,8 +58,8 @@
 {
   int             l;
 
-  for (l = 0; l < 256, s[l]; l++);	/*
-					 * l=strlen(s);
+  for (l = 0; l < 256 && s[l]; l++);	/*
+					 * l=strnlen(s,256);
 					 */
 
   if (status_len + l >= 4000)
diff -u --recursive --new-file v1.3.13/linux/drivers/sound/soundvers.h linux/drivers/sound/soundvers.h
--- v1.3.13/linux/drivers/sound/soundvers.h	Tue Jul 11 10:02:54 1995
+++ linux/drivers/sound/soundvers.h	Mon Jul 31 10:20:02 1995
@@ -1 +1 @@
-#define SOUND_VERSION_STRING "3.0-950710"
+#define SOUND_VERSION_STRING "3.0-950728"
diff -u --recursive --new-file v1.3.13/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v1.3.13/linux/include/asm-i386/bitops.h	Tue Jun 27 14:11:44 1995
+++ linux/include/asm-i386/bitops.h	Mon Jul 31 12:04:06 1995
@@ -66,7 +66,7 @@
 /*
  * Find-bit routines..
  */
-extern inline int find_first_zero_bit(void * addr, unsigned size)
+extern __inline__ int find_first_zero_bit(void * addr, unsigned size)
 {
 	int res;
 
@@ -90,7 +90,7 @@
 	return res;
 }
 
-extern inline int find_next_zero_bit (void * addr, int size, int offset)
+extern __inline__ int find_next_zero_bit (void * addr, int size, int offset)
 {
 	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
 	int set = 0, bit = offset & 31, res;
@@ -122,7 +122,7 @@
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
-extern inline unsigned long ffz(unsigned long word)
+extern __inline__ unsigned long ffz(unsigned long word)
 {
 	__asm__("bsfl %1,%0"
 		:"=r" (word)
diff -u --recursive --new-file v1.3.13/linux/include/linux/ax25.h linux/include/linux/ax25.h
--- v1.3.13/linux/include/linux/ax25.h	Fri Jun 30 16:22:30 1995
+++ linux/include/linux/ax25.h	Thu Jul 27 19:36:17 1995
@@ -30,11 +30,13 @@
 #define AX25_T3		4
 #define AX25_T2		5
 #define	AX25_BACKOFF	6
+#define	AX25_EXTSEQ	7
 
 #define SIOCAX25GETUID		(SIOCPROTOPRIVATE)
 #define SIOCAX25ADDUID		(SIOCPROTOPRIVATE+1)
 #define SIOCAX25DELUID		(SIOCPROTOPRIVATE+2)
 #define SIOCAX25NOUID		(SIOCPROTOPRIVATE+3)
+#define	SIOCAX25DIGCTL		(SIOCPROTOPRIVATE+4)
 
 #define AX25_NOUID_DEFAULT	0
 #define AX25_NOUID_BLOCK	1
diff -u --recursive --new-file v1.3.13/linux/include/linux/aztcd.h linux/include/linux/aztcd.h
--- v1.3.13/linux/include/linux/aztcd.h	Tue Jul 25 18:21:23 1995
+++ linux/include/linux/aztcd.h	Mon Jul 31 11:27:10 1995
@@ -1,4 +1,4 @@
-/* $Id: aztcd.h,v 1.40 1995/07/15 20:35:01 root Exp root $
+/* $Id: aztcd.h,v 1.50 1995/07/29 20:31:32 root Exp $
  *
  * Definitions for a AztechCD268 CD-ROM interface
  *	Copyright (C) 1994, 1995  Werner Zimmermann
@@ -45,7 +45,7 @@
 
 /*Set this to 1, if you want multisession support. Be warned, this function has
 not been tested !!!*/
-#define AZT_MULTISESSION        0
+#define AZT_MULTISESSION        1
 
 /*Set this to 1, if you want to use incompatible ioctls for reading in raw and
   cooked mode */
@@ -76,10 +76,11 @@
 #endif
 
 /* status bits */
-#define AST_CMD_CHECK		0x80		/* command error */
-#define AST_DSK_CHG		0x20		/* disk removed or changed */
-#define AST_NOT_READY		0x02		/* no disk in the drive */
-#define AST_DOOR_OPEN		0x40		/* door is open */
+#define AST_CMD_CHECK		0x80		/* 1 = command error */
+#define AST_DOOR_OPEN		0x40		/* 1 = door is open */
+#define AST_NOT_READY		0x20		/* 1 = no disk in the drive */
+#define AST_DSK_CHG		0x02		/* 1 = disk removed or changed */
+#define AST_MODE                0x01            /* 0=MODE1, 1=MODE2 */
 #define AST_MODE_BITS		0x1C		/* Mode Bits */
 #define AST_INITIAL		0x0C		/* initial, only valid ... */
 #define AST_BUSY		0x04		/* now playing, only valid
@@ -97,7 +98,7 @@
 /* commands */
 #define ACMD_SOFT_RESET		0x10		/* reset drive */
 #define ACMD_PLAY_READ		0x20		/* read data track in cooked mode */
-#define ACMD_DATA_READ_RAW      0x21		/* reading in raw mode*/
+#define ACMD_PLAY_READ_RAW      0x21		/* reading in raw mode*/
 #define ACMD_SEEK_TO_LEADIN     0x31		/* seek to leadin track*/
 #define ACMD_GET_ERROR		0x40		/* get error code */
 #define ACMD_GET_STATUS		0x41		/* get status */
@@ -111,14 +112,10 @@
 #define ACMD_PLAY_AUDIO		0x90		/* play audio track */
 #define ACMD_SET_VOLUME		0x93		/* set audio level */
 #define ACMD_GET_VERSION	0xA0		/* get firmware version */
-#define ACMD_SET_MODE		0xA1		/* set drive mode */
+#define ACMD_SET_DISK_TYPE	0xA1		/* set disk data mode */
 
 #define MAX_TRACKS		104
 
-#define CD_DATA			0x01
-#define CD_AUDIO		0x02
-#define CD_XA                   (CD_DATA|CD_AUDIO)
-
 struct msf {
 	unsigned char	min;
 	unsigned char	sec;
@@ -137,7 +134,8 @@
 	struct msf	firstTrack;
         unsigned char   multi;
         struct msf      lastTrack;
-        unsigned char   type;
+        unsigned char   xa;
+        unsigned char   audio;
 };
 
 struct azt_Toc {
diff -u --recursive --new-file v1.3.13/linux/include/linux/cdrom.h linux/include/linux/cdrom.h
--- v1.3.13/linux/include/linux/cdrom.h	Tue Jul 11 10:02:59 1995
+++ linux/include/linux/cdrom.h	Mon Jul 31 11:27:10 1995
@@ -424,4 +424,8 @@
 #define	CDROMVOLREAD		0x5313 /* let the drive tell its volume setting */
 					/* (struct cdrom_volctrl) */
 
+#define CDROMREADMODE0          0x5314  /*read data in audio mode*/
+#define CDROMREADRAW            0x5315  /*read data in raw mode*/
+#define CDROMREADCOOKED         0x5316  /*read data in cooked mode*/
+
 #endif  _LINUX_CDROM_H
diff -u --recursive --new-file v1.3.13/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v1.3.13/linux/include/linux/genhd.h	Tue Jul 11 10:02:59 1995
+++ linux/include/linux/genhd.h	Mon Jul 31 14:30:15 1995
@@ -18,7 +18,8 @@
 #define EXTENDED_PARTITION 5
 
 #define DM6_PARTITION		0x54	/* has DDO: use xlated geom & offset */
-#define DM6_AUXPARTITION	0x51	/* no DDO:  use xlated geom */
+#define DM6_AUX1PARTITION	0x51	/* no DDO:  use xlated geom */
+#define DM6_AUX3PARTITION	0x53	/* no DDO:  use xlated geom */
 	
 struct partition {
 	unsigned char boot_ind;		/* 0x80 - active */
diff -u --recursive --new-file v1.3.13/linux/include/linux/netrom.h linux/include/linux/netrom.h
--- v1.3.13/linux/include/linux/netrom.h	Fri Jun 30 16:22:30 1995
+++ linux/include/linux/netrom.h	Thu Jul 27 19:36:17 1995
@@ -8,6 +8,7 @@
 #define	SIOCNRGETPARMS		(SIOCPROTOPRIVATE+0)
 #define	SIOCNRSETPARMS		(SIOCPROTOPRIVATE+1)
 #define	SIOCNRDECOBS		(SIOCPROTOPRIVATE+2)
+#define	SIOCNRRTCTL		(SIOCPROTOPRIVATE+3)
 
 struct nr_route_struct {
 #define	NETROM_NEIGH	0
diff -u --recursive --new-file v1.3.13/linux/include/linux/optcd.h linux/include/linux/optcd.h
--- v1.3.13/linux/include/linux/optcd.h	Fri Jul  7 08:54:54 1995
+++ linux/include/linux/optcd.h	Mon Jul 31 09:46:27 1995
@@ -135,8 +135,8 @@
 #define RESET_WAIT		1000
 
 #define SET_TIMER(func, jifs) \
-	delay_timer.expires = jifs; \
-	delay_timer.function = (void *) func; \
+	delay_timer.expires = jiffies+(jifs); \
+	delay_timer.function = (void *) (func); \
 	add_timer(&delay_timer);
 #define CLEAR_TIMER		del_timer(&delay_timer)
 
diff -u --recursive --new-file v1.3.13/linux/include/linux/soundcard.h linux/include/linux/soundcard.h
--- v1.3.13/linux/include/linux/soundcard.h	Tue Jul 11 10:02:59 1995
+++ linux/include/linux/soundcard.h	Mon Jul 31 10:01:13 1995
@@ -117,6 +117,7 @@
 #define SNDCTL_SEQ_NRMIDIS		_IOR ('Q',11, int)
 #define SNDCTL_MIDI_INFO		_IOWR('Q',12, struct midi_info)
 #define SNDCTL_SEQ_THRESHOLD		_IOW ('Q',13, int)
+#define SNDCTL_SEQ_TRESHOLD		SNDCTL_SEQ_THRESHOLD	/* there was once a typo */
 #define SNDCTL_SYNTH_MEMAVL		_IOWR('Q',14, int)	/* in=dev#, out=memsize */
 #define SNDCTL_FM_4OP_ENABLE		_IOW ('Q',15, int)	/* in=dev# */
 #define SNDCTL_PMGR_ACCESS		_IOWR('Q',16, struct patmgr_info)
diff -u --recursive --new-file v1.3.13/linux/include/net/ax25.h linux/include/net/ax25.h
--- v1.3.13/linux/include/net/ax25.h	Fri Jul  7 08:54:55 1995
+++ linux/include/net/ax25.h	Thu Jul 27 19:36:17 1995
@@ -19,12 +19,17 @@
 #define AX25_P_ARP	0xCD
 #define AX25_P_TEXT 	0xF0
 #define AX25_P_NETROM 	0xCF
+#define	AX25_P_SEGMENT	0x08
 
-#define LAPB_UI	0x03
-#define LAPB_C	0x80
-#define LAPB_E	0x01
+#define	SEG_REM		0x7F
+#define	SEG_FIRST	0x80
 
-#define SSID_SPARE	0x60		/* Unused bits (DAMA bit and spare must be 1) */
+#define LAPB_UI		0x03
+#define LAPB_C		0x80
+#define LAPB_E		0x01
+
+#define SSSID_SPARE	0x60	/* Unused bits in SSID for standard AX.25 */
+#define ESSID_SPARE	0x20	/* Unused bits in SSID for extended AX.25 */
 
 #define AX25_REPEATED	0x80
 
@@ -74,11 +79,13 @@
 #define	UA	0x63	/* Unnumbered acknowledge */
 #define	FRMR	0x87	/* Frame reject */
 #define	UI	0x03	/* Unnumbered information */
-#define	PF	0x10	/* Poll/final bit */
+#define	PF	0x10	/* Poll/final bit for standard AX.25 */
+#define	EPF	0x01	/* Poll/final bit for extended AX.25 */
 
 #define ILLEGAL	0x100	/* Impossible to be a real frame type */
 
-#define	MMASK	7	/* Mask for modulo-8 sequence numbers */
+#define	POLLOFF		0
+#define	POLLON		1
 
 /* AX25 L2 C-bit */
 
@@ -99,8 +106,8 @@
 #define DEFAULT_T3	(300 * PR_SLOWHZ)	/*  Idle supervision   - 300 seconds */
 #define DEFAULT_N2	10			/*  Number of retries */
 #define	DEFAULT_WINDOW	2			/*  Default window size	*/
-#define MODULUS 	8
-#define MAX_WINDOW_SIZE 7			/*  Maximum window allowable */
+#define MODULUS 	8			/*  Standard AX.25 modulus */
+#define	EMODULUS	128			/*  Extended AX.25 modulus */
 
 typedef struct ax25_uid_assoc {
 	struct ax25_uid_assoc *next;
@@ -119,15 +126,18 @@
 	struct ax25_cb		*next;
 	ax25_address		source_addr, dest_addr;
 	struct device		*device;
-	unsigned char		state;
+	unsigned char		state, modulus;
 	unsigned short		vs, vr, va;
 	unsigned char		condition, backoff;
 	unsigned char		n2, n2count;
 	unsigned short		t1, t2, t3, rtt;
 	unsigned short		t1timer, t2timer, t3timer;
+	unsigned short		fragno, fraglen;
 	ax25_digi		*digipeat;
 	struct sk_buff_head	write_queue;
+	struct sk_buff_head	reseq_queue;
 	struct sk_buff_head	ack_queue;
+	struct sk_buff_head	frag_queue;
 	unsigned char		window;
 	struct timer_list	timer;
 	struct sock		*sk;		/* Backlink to socket */
@@ -154,7 +164,7 @@
 extern int  ax25_process_rx_frame(ax25_cb *, struct sk_buff *, int);
 
 /* ax25_out.c */
-extern int  ax25_output(ax25_cb *, struct sk_buff *);
+extern void ax25_output(ax25_cb *, struct sk_buff *);
 extern void ax25_kick(ax25_cb *);
 extern void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int);
 extern void ax25_nr_error_recovery(ax25_cb *);
@@ -174,17 +184,17 @@
 extern char ax25_ip_mode_get(ax25_address *, struct device *);
 
 /* ax25_subr.c */
-extern void ax25_clear_tx_queue(ax25_cb *);
+extern void ax25_clear_queues(ax25_cb *);
 extern void ax25_frames_acked(ax25_cb *, unsigned short);
 extern int  ax25_validate_nr(ax25_cb *, unsigned short);
-extern int  ax25_decode(unsigned char *);
-extern void ax25_send_control(ax25_cb *, int, int);
+extern int  ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *);
+extern void ax25_send_control(ax25_cb *, int, int, int);
 extern unsigned short ax25_calculate_t1(ax25_cb *);
 extern void ax25_calculate_rtt(ax25_cb *);
 extern unsigned char *ax25_parse_addr(unsigned char *, int, ax25_address *,
 	ax25_address *, ax25_digi *, int *);
 extern int  build_ax25_addr(unsigned char *, ax25_address *, ax25_address *,
-	ax25_digi *, int);
+	ax25_digi *, int, int);
 extern int  size_ax25_addr(ax25_digi *);
 extern void ax25_digi_invert(ax25_digi *, ax25_digi *);
 extern void ax25_return_dm(struct device *, ax25_address *, ax25_address *, ax25_digi *);
diff -u --recursive --new-file v1.3.13/linux/include/net/netrom.h linux/include/net/netrom.h
--- v1.3.13/linux/include/net/netrom.h	Fri Jul  7 08:54:55 1995
+++ linux/include/net/netrom.h	Thu Jul 27 19:36:17 1995
@@ -45,6 +45,7 @@
 
 typedef struct {
 	ax25_address		user_addr, source_addr, dest_addr;
+	struct device		*device;
 	unsigned char		my_index,    my_id;
 	unsigned char		your_index,  your_id;
 	unsigned char		state, bpqext;
@@ -53,7 +54,10 @@
 	unsigned char		n2, n2count;
 	unsigned short		t1, t2, rtt;
 	unsigned short		t1timer, t2timer, t4timer;
-	struct sk_buff_head	ack_queue, reseq_queue;
+	unsigned short		fraglen;
+	struct sk_buff_head	ack_queue;
+	struct sk_buff_head	reseq_queue;
+	struct sk_buff_head	frag_queue;
 	struct sock		*sk;		/* Backlink to socket */
 } nr_cb;
 
@@ -99,7 +103,7 @@
 extern int  nr_process_rx_frame(struct sock *, struct sk_buff *);
 
 /* nr_out.c */
-extern int  nr_output(struct sock *, struct sk_buff *);
+extern void nr_output(struct sock *, struct sk_buff *);
 extern void nr_send_nak_frame(struct sock *);
 extern void nr_kick(struct sock *);
 extern void nr_transmit_buffer(struct sock *, struct sk_buff *);
@@ -119,7 +123,7 @@
 extern int  nr_neigh_get_info(char *, char **, off_t, int);
 
 /* nr_subr.c */
-extern void nr_clear_tx_queue(struct sock *);
+extern void nr_clear_queues(struct sock *);
 extern void nr_frames_acked(struct sock *, unsigned short);
 extern void nr_requeue_frames(struct sock *);
 extern int  nr_validate_nr(struct sock *, unsigned short);
diff -u --recursive --new-file v1.3.13/linux/kernel/itimer.c linux/kernel/itimer.c
--- v1.3.13/linux/kernel/itimer.c	Thu Jul 27 10:13:17 1995
+++ linux/kernel/itimer.c	Mon Jul 31 09:46:27 1995
@@ -38,7 +38,7 @@
 		interval = current->it_real_incr;
 		val = 0;
 		if (del_timer(&current->real_timer)) {
-			val = current->real_timer.expires;
+			val = current->real_timer.expires-jiffies;
 			add_timer(&current->real_timer);
 			if (val <= 0)
 				val = interval;
@@ -83,7 +83,7 @@
 
 	send_sig(SIGALRM, p, 1);
 	if (p->it_real_incr) {
-		p->real_timer.expires = p->it_real_incr;
+		p->real_timer.expires = jiffies+p->it_real_incr;
 		add_timer(&p->real_timer);
 	}
 }
@@ -101,7 +101,7 @@
 		case ITIMER_REAL:
 			del_timer(&current->real_timer);
 			if (j) {
-				current->real_timer.expires = j;
+				current->real_timer.expires = jiffies+j;
 				add_timer(&current->real_timer);
 			}
 			current->it_real_value = j;
diff -u --recursive --new-file v1.3.13/linux/kernel/sched.c linux/kernel/sched.c
--- v1.3.13/linux/kernel/sched.c	Thu Jul 27 10:13:17 1995
+++ linux/kernel/sched.c	Mon Jul 31 09:19:52 1995
@@ -183,7 +183,7 @@
 
 	if (intr_count) {
 		printk("Aiee: scheduling in interrupt\n");
-		intr_count = 0;
+		return;
 	}
 	run_task_queue(&tq_scheduler);
 
@@ -233,7 +233,7 @@
 		kstat.context_swtch++;
 		if (timeout) {
 			init_timer(&timer);
-			timer.expires = timeout - jiffies;
+			timer.expires = timeout;
 			timer.data = (unsigned long) current;
 			timer.function = process_timeout;
 			add_timer(&timer);
@@ -369,7 +369,6 @@
 	}
 #endif
 	p = &timer_head;
-	timer->expires += jiffies;
 	save_flags(flags);
 	cli();
 	do {
@@ -397,7 +396,6 @@
 			timer->prev->next = timer->next;
 			timer->next = timer->prev = NULL;
 			restore_flags(flags);
-			timer->expires -= jiffies;
 			return 1;
 		}
 	}
@@ -414,7 +412,6 @@
 		timer->prev->next = timer->next;
 		timer->next = timer->prev = NULL;
 		restore_flags(flags);
-		timer->expires -= jiffies;
 		return 1;
 	}
 	restore_flags(flags);
diff -u --recursive --new-file v1.3.13/linux/mm/filemap.c linux/mm/filemap.c
--- v1.3.13/linux/mm/filemap.c	Fri Jun 16 22:02:56 1995
+++ linux/mm/filemap.c	Mon Jul 31 14:44:46 1995
@@ -81,6 +81,7 @@
 		return;
 	}
 	inode = vma->vm_inode;
+	offset += vma->vm_offset;
 	multi_bmap(inode, offset, nr, inode->i_sb->s_blocksize_bits);
 	bwrite_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize);
 }
diff -u --recursive --new-file v1.3.13/linux/net/802/p8022.c linux/net/802/p8022.c
--- v1.3.13/linux/net/802/p8022.c	Fri Jul  7 08:54:56 1995
+++ linux/net/802/p8022.c	Thu Jul 27 19:34:36 1995
@@ -48,20 +48,13 @@
 		struct sk_buff *skb, unsigned char *dest_node)
 {
 	struct device	*dev = skb->dev;
-	unsigned long	len = skb->len;
-	unsigned long	hard_len = dev->hard_header_len;
 	unsigned char	*rawp;
 
-	dev->hard_header(skb, dev, len - hard_len,
-			dest_node, NULL, len - hard_len);
 	rawp = skb_push(skb,3);
-	*rawp = dl->type[0];
-	rawp++;
-	*rawp = dl->type[0];
-	rawp++;
+	*rawp++ = dl->type[0];
+	*rawp++ = dl->type[0];
 	*rawp = 0x03;	/* UI */
-	rawp++;
-	skb->h.raw = rawp;
+	dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
 }
 
 static struct packet_type p8022_packet_type = 
diff -u --recursive --new-file v1.3.13/linux/net/802/p8023.c linux/net/802/p8023.c
--- v1.3.13/linux/net/802/p8023.c	Fri Jun 30 16:22:30 1995
+++ linux/net/802/p8023.c	Thu Jul 27 19:34:36 1995
@@ -9,12 +9,8 @@
 		struct sk_buff *skb, unsigned char *dest_node)
 {
 	struct device	*dev = skb->dev;
-	unsigned long	len = skb->len;
-	unsigned long	hard_len = dev->hard_header_len;
-
-	dev->hard_header(skb, dev, len - hard_len,
-			dest_node, NULL, len - hard_len);
-	skb->h.raw = skb->data + hard_len;
+	
+	dev->hard_header(skb, dev, ETH_P_802_3, dest_node, NULL, skb->len);
 }
 
 struct datalink_proto *
diff -u --recursive --new-file v1.3.13/linux/net/802/psnap.c linux/net/802/psnap.c
--- v1.3.13/linux/net/802/psnap.c	Fri Jun 30 16:22:30 1995
+++ linux/net/802/psnap.c	Thu Jul 27 19:34:36 1995
@@ -74,11 +74,7 @@
  
 static void snap_datalink_header(struct datalink_proto *dl, struct sk_buff *skb, unsigned char *dest_node)
 {
-	unsigned char	*rawp;
-
-	rawp = skb_push(skb,5);
-	memcpy(rawp,dl->type,5);
-	skb->h.raw = rawp+5;
+	memcpy(skb_push(skb,5),dl->type,5);
 	snap_dl->datalink_header(snap_dl, skb, dest_node);
 }
 
diff -u --recursive --new-file v1.3.13/linux/net/802/tr.c linux/net/802/tr.c
--- v1.3.13/linux/net/802/tr.c	Tue Jul 25 18:21:24 1995
+++ linux/net/802/tr.c	Mon Jul 31 09:46:27 1995
@@ -236,7 +236,7 @@
 	restore_flags(flags);
 
 	del_timer(&rif_timer);
-	rif_timer.expires=RIF_CHECK_INTERVAL;
+	rif_timer.expires=jiffies+RIF_CHECK_INTERVAL;
 	add_timer(&rif_timer);
 
 }
diff -u --recursive --new-file v1.3.13/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- v1.3.13/linux/net/appletalk/aarp.c	Tue Jul 18 16:28:59 1995
+++ linux/net/appletalk/aarp.c	Mon Jul 31 09:46:26 1995
@@ -362,9 +362,9 @@
 	}
 	del_timer(&aarp_timer);
 	if(unresolved_count==0)
-		aarp_timer.expires=AARP_EXPIRY_TIME;
+		aarp_timer.expires=jiffies+AARP_EXPIRY_TIME;
 	else
-		aarp_timer.expires=AARP_TICK_TIME;
+		aarp_timer.expires=jiffies+AARP_TICK_TIME;
 	add_timer(&aarp_timer);
 }
 
@@ -523,7 +523,7 @@
 	if(unresolved_count==1)
 	{
 		del_timer(&aarp_timer);
-		aarp_timer.expires=AARP_TICK_TIME;
+		aarp_timer.expires=jiffies+AARP_TICK_TIME;
 		add_timer(&aarp_timer);
 	}
 	/*
@@ -667,7 +667,7 @@
 			if(unresolved_count==0)
 			{
 				del_timer(&aarp_timer);
-				aarp_timer.expires=AARP_EXPIRY_TIME;
+				aarp_timer.expires=jiffies+AARP_EXPIRY_TIME;
 				add_timer(&aarp_timer);
 			}
 			break;
@@ -718,7 +718,7 @@
 	init_timer(&aarp_timer);
 	aarp_timer.function=aarp_expire_timeout;
 	aarp_timer.data=0;
-	aarp_timer.expires=AARP_EXPIRY_TIME;
+	aarp_timer.expires=jiffies+AARP_EXPIRY_TIME;
 	add_timer(&aarp_timer);
 	register_netdevice_notifier(&aarp_notifier);
 }
diff -u --recursive --new-file v1.3.13/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v1.3.13/linux/net/appletalk/ddp.c	Fri Jul  7 13:42:58 1995
+++ linux/net/appletalk/ddp.c	Mon Jul 31 09:46:27 1995
@@ -199,7 +199,7 @@
 		 *	Someone is using our buffers still.. defer
 		 */
 		init_timer(&sk->timer);
-		sk->timer.expires=10*HZ;
+		sk->timer.expires=jiffies+10*HZ;
 		sk->timer.function=atalk_destroy_timer;
 		sk->timer.data = (unsigned long)sk;
 		add_timer(&sk->timer);
diff -u --recursive --new-file v1.3.13/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v1.3.13/linux/net/ax25/af_ax25.c	Fri Jul  7 08:54:56 1995
+++ linux/net/ax25/af_ax25.c	Mon Jul 31 09:46:26 1995
@@ -1,5 +1,5 @@
 /*
- *	AX.25 release 029
+ *	AX.25 release 030
  *
  *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *	releases, misbehave and/or generally screw up. It might even work. 
@@ -58,7 +58,9 @@
  *			Alan(GW4PTS)		Missed suser() on axassociate checks
  *	AX.25 030	Alan(GW4PTS)		Added variable length headers.
  *			Jonathan(G4KLX)		Added BPQ Ethernet interface.
- *			Steven(GW7RRM)
+ *			Steven(GW7RRM)		Added digi-peating control ioctl.
+ *						Added extended AX.25 support.
+ *						Added AX.25 frame segmentation.
  *
  *	To do:
  *		Support use as digipeater, including an on/off ioctl
@@ -98,6 +100,8 @@
 #include <net/ip.h>
 #include <net/arp.h>
 
+static int ax25_digi_on = 1;
+
 #define	CONFIG_AX25_XDIGI	/* Cross port (band) digi stuff */
 
 /**********************************************************************************************************************\
@@ -197,6 +201,7 @@
 	
 	for (s = ax25_list; s != NULL; s = s->next) {
 		if (s->device == dev) {
+			s->state  = AX25_STATE_0;
 			s->device = NULL;
 			if (s->sk != NULL) {
 				s->sk->state = TCP_CLOSE;
@@ -388,7 +393,7 @@
 	del_timer(&ax25->timer);
 	
 	ax25_remove_socket(ax25);
-	ax25_clear_tx_queue(ax25);	/* Flush the send queue */
+	ax25_clear_queues(ax25);	/* Flush the queues */
 	
 	if (ax25->sk != NULL) {
 		while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) {
@@ -410,7 +415,7 @@
 	if (ax25->sk != NULL) {
 		if (ax25->sk->wmem_alloc || ax25->sk->rmem_alloc) { /* Defer: outstanding buffers */
 			init_timer(&ax25->timer);
-			ax25->timer.expires  = 10 * HZ;
+			ax25->timer.expires  = jiffies + 10 * HZ;
 			ax25->timer.function = ax25_destroy_timer;
 			ax25->timer.data     = (unsigned long)ax25;
 			add_timer(&ax25->timer);
@@ -502,7 +507,9 @@
 		return NULL;
 
 	skb_queue_head_init(&ax25->write_queue);
+	skb_queue_head_init(&ax25->frag_queue);
 	skb_queue_head_init(&ax25->ack_queue);
+	skb_queue_head_init(&ax25->reseq_queue);
 
 	init_timer(&ax25->timer);
 
@@ -512,6 +519,9 @@
 	ax25->n2      = DEFAULT_N2;
 	ax25->t3      = DEFAULT_T3;
 
+	ax25->modulus   = MODULUS;
+	ax25->fragno    = 0;
+	ax25->fraglen   = 0;
 	ax25->backoff   = 1;
 	ax25->condition = 0x00;
 	ax25->t1timer   = 0;
@@ -656,8 +666,13 @@
 
 	switch (optname) {
 		case AX25_WINDOW:
-			if (opt < 1 || opt > 7)
-				return -EINVAL;
+			if (sk->ax25->modulus == MODULUS) {
+				if (opt < 1 || opt > 7)
+					return -EINVAL;
+			} else {
+				if (opt < 1 || opt > 63)
+					return -EINVAL;
+			}
 			sk->ax25->window = opt;
 			return 0;
 
@@ -689,6 +704,10 @@
 			sk->ax25->backoff = opt ? 1 : 0;
 			return 0;
 
+		case AX25_EXTSEQ:
+			sk->ax25->modulus = opt ? EMODULUS : MODULUS;
+			return 0;
+
 		default:
 			return -ENOPROTOOPT;
 	}
@@ -734,6 +753,10 @@
 			val = sk->ax25->backoff;
 			break;
 
+		case AX25_EXTSEQ:
+			val = (sk->ax25->modulus == EMODULUS);
+			return 0;
+
 		default:
 			return -ENOPROTOOPT;
 	}
@@ -907,6 +930,7 @@
 	sk->write_space  = def_callback1;
 	sk->error_report = def_callback1;
 
+	ax25->modulus = osk->ax25->modulus;
 	ax25->backoff = osk->ax25->backoff;
 	ax25->rtt     = osk->ax25->rtt;
 	ax25->t1      = osk->ax25->t1;
@@ -955,7 +979,7 @@
 				break;
 
 			case AX25_STATE_1:
-				ax25_send_control(sk->ax25, DISC | PF, C_COMMAND);
+				ax25_send_control(sk->ax25, DISC, POLLON, C_COMMAND);
 				sk->ax25->state = AX25_STATE_0;
 				sk->dead        = 1;
 				sk->state_change(sk);
@@ -963,7 +987,7 @@
 				break;
 
 			case AX25_STATE_2:
-				ax25_send_control(sk->ax25, DM | PF, C_RESPONSE);
+				ax25_send_control(sk->ax25, DM, POLLON, C_RESPONSE);
 				sk->ax25->state = AX25_STATE_0;
 				sk->dead        = 1;
 				sk->state_change(sk);
@@ -972,9 +996,9 @@
 
 			case AX25_STATE_3:
 			case AX25_STATE_4:
-				ax25_clear_tx_queue(sk->ax25);
+				ax25_clear_queues(sk->ax25);
 				sk->ax25->n2count = 0;
-				ax25_send_control(sk->ax25, DISC | PF, C_COMMAND);
+				ax25_send_control(sk->ax25, DISC, POLLON, C_COMMAND);
 				sk->ax25->t3timer = 0;
 				sk->ax25->t1timer = sk->ax25->t1 = ax25_calculate_t1(sk->ax25);
 				sk->ax25->state   = AX25_STATE_2;
@@ -1306,9 +1330,13 @@
 				dev = dev_scan;
 			}
 #endif
-			build_ax25_addr(skb->data, &src, &dest, &dp, type);
+			build_ax25_addr(skb->data, &src, &dest, &dp, type, MODULUS);
 			skb->arp = 1;
-			ax25_queue_xmit(skb, dev, SOPRI_NORMAL);			
+			if (ax25_digi_on) {
+				ax25_queue_xmit(skb, dev, SOPRI_NORMAL);
+			} else {
+				kfree_skb(skb, FREE_READ);
+			}
 		} else {
 			kfree_skb(skb, FREE_READ);
 		}
@@ -1398,12 +1426,12 @@
 		return 0;
 	}
 
-	if ((*skb->data & 0xEF) != SABM) {
+	if ((*skb->data & ~PF) != SABM && (*skb->data & ~PF) != SABME) {
 		/*
 		 *	Never reply to a DM. Also ignore any connects for
 		 *	addresses that are not our interfaces and not a socket.
 		 */
-		if ((*skb->data & 0xEF) != DM && mine)
+		if ((*skb->data & ~PF) != DM && mine)
 			ax25_return_dm(dev, &src, &dest, &dp);
 
 		kfree_skb(skb, FREE_READ);
@@ -1471,9 +1499,15 @@
 		ax25_digi_invert(&dp, ax25->digipeat);
 	}
 
+	if ((*skb->data & ~PF) == SABME) {
+		ax25->modulus = EMODULUS;
+	} else {
+		ax25->modulus = MODULUS;
+	}
+
 	ax25->device = dev;
 	
-	ax25_send_control(ax25, UA | PF, C_RESPONSE);
+	ax25_send_control(ax25, UA, POLLON, C_RESPONSE);
 
 	ax25->t3timer = ax25->t3;
 	ax25->state   = AX25_STATE_3;
@@ -1524,10 +1558,10 @@
 		return 0;
 	}
 
-	len = skb->data[14] + skb->data[15] * 256 - 5;
+	len = skb->data[0] + skb->data[1] * 256 - 5;
 
-	skb_pull(skb, AX25_BPQ_HEADER_LEN);	/* Remove the BPQ Header */
-	skb_trim(skb, len);			/* Set the length of the data */
+	skb_pull(skb, 2);	/* Remove the length bytes */
+	skb_trim(skb, len);	/* Set the length of the data */
 
 	return ax25_rcv(skb, dev, &port_call, ptype);
 }
@@ -1618,7 +1652,7 @@
 		printk("AX.25: sendto: building packet.\n");
 
 	/* Assume the worst case */
-	size = len + 2 + size_ax25_addr(dp) + AX25_BPQ_HEADER_LEN;
+	size = len + 3 + size_ax25_addr(dp) + AX25_BPQ_HEADER_LEN;
 
 	if ((skb = sock_alloc_send_skb(sk, size, 0, &err)) == NULL)
 		return err;
@@ -1662,7 +1696,7 @@
 		}
 
 		/* Build an AX.25 header */
-		asmptr += (lv = build_ax25_addr(asmptr, &sk->ax25->source_addr, &sax.sax25_call, dp, C_COMMAND));
+		asmptr += (lv = build_ax25_addr(asmptr, &sk->ax25->source_addr, &sax.sax25_call, dp, C_COMMAND, MODULUS));
 
 		if (sk->debug)
 			printk("Built header (%d bytes)\n",lv);
@@ -1716,7 +1750,7 @@
 	if (sk->type == SOCK_SEQPACKET) {
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
-		bias = 2;
+		bias = 1;
 	}
 
 	/* Now we can treat all alike */
@@ -1843,6 +1877,15 @@
 			ax25_uid_policy = amount;
 			return 0;
 
+		case SIOCAX25DIGCTL:
+			if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(int))) != 0)
+				return err;
+			if (!suser())
+				return -EPERM;
+			amount = get_fs_long((void *)arg);
+			ax25_digi_on = amount ? 1 : 0;
+			return 0;
+
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFDSTADDR:
@@ -1874,7 +1917,7 @@
   
 	cli();
 
-	len += sprintf(buffer, "dest_addr src_addr  dev  st vs vr va    t1     t2     t3     n2  rtt wnd Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "dest_addr src_addr  dev  st  vs  vr  va    t1     t2     t3     n2  rtt wnd Snd-Q Rcv-Q\n");
 
 	for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {
 		if ((dev = ax25->device) == NULL)
@@ -1884,7 +1927,7 @@
 
 		len += sprintf(buffer + len, "%-9s ",
 			ax2asc(&ax25->dest_addr));
-		len += sprintf(buffer + len, "%-9s %-4s %2d %2d %2d %2d %3d/%03d %2d/%02d %3d/%03d %2d/%02d %3d %3d",
+		len += sprintf(buffer + len, "%-9s %-4s %2d %3d %3d %3d %3d/%03d %2d/%02d %3d/%03d %2d/%02d %3d %3d",
 			ax2asc(&ax25->source_addr), devname,
 			ax25->state,
 			ax25->vs, ax25->vr, ax25->va,
@@ -2050,7 +2093,7 @@
 
   	buff[6] &= ~LAPB_C;
   	buff[6] &= ~LAPB_E;
-  	buff[6] |= SSID_SPARE;
+  	buff[6] |= SSSID_SPARE;
   	buff += AX25_ADDR_LEN;
 
   	if (saddr != NULL)
@@ -2060,7 +2103,7 @@
 
   	buff[6] &= ~LAPB_C;
   	buff[6] |= LAPB_E;
-  	buff[6] |= SSID_SPARE;
+  	buff[6] |= SSSID_SPARE;
   	buff   += AX25_ADDR_LEN;
 
   	*buff++ = LAPB_UI;	/* UI */
@@ -2105,11 +2148,11 @@
 
   	bp[7]  &= ~LAPB_C;
   	bp[7]  &= ~LAPB_E;
-  	bp[7]  |= SSID_SPARE;
+  	bp[7]  |= SSSID_SPARE;
 
   	bp[14] &= ~LAPB_C;
   	bp[14] |= LAPB_E;
-  	bp[14] |= SSID_SPARE;
+  	bp[14] |= SSSID_SPARE;
 
   	return 0;
 }	
diff -u --recursive --new-file v1.3.13/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c
--- v1.3.13/linux/net/ax25/ax25_in.c	Fri Jul  7 08:54:56 1995
+++ linux/net/ax25/ax25_in.c	Thu Jul 27 19:36:17 1995
@@ -1,5 +1,5 @@
 /*
- *	AX.25 release 029
+ *	AX.25 release 030
  *
  *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *	releases, misbehave and/or generally screw up. It might even work. 
@@ -24,6 +24,8 @@
  *					the sock structure.
  *	AX.25 029	Alan(GW4PTS)	Switched to KA9Q constant names.
  *			Jonathan(G4KLX)	Added IP mode registration.
+ *	AX.25 030	Jonathan(G4KLX)	Added AX.25 fragment reception.
+ *					Upgraded state machine for SABME.
  */
 
 #include <linux/config.h>
@@ -53,6 +55,65 @@
 #include <net/netrom.h>
 #endif
 
+static int ax25_rx_iframe(ax25_cb *, struct sk_buff *);
+
+/*
+ *	Given a fragment, queue it on the fragment queue and if the fragment
+ *	is complete, send it back to ax25_rx_iframe.
+ */
+static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb)
+{
+	struct sk_buff *skbn, *skbo;
+	
+	if (ax25->fragno != 0) {
+		if (!(*skb->data & SEG_FIRST)) {
+			if ((ax25->fragno - 1) == (*skb->data & SEG_REM)) {
+				ax25->fragno = *skb->data & SEG_REM;
+				skb_pull(skb, 1);
+				ax25->fraglen += skb->len;
+				skb_queue_tail(&ax25->frag_queue, skb);
+
+				if (ax25->fragno == 0) {
+					if ((skbn = alloc_skb(AX25_MAX_HEADER_LEN + ax25->fraglen, GFP_ATOMIC)) == NULL)
+						return 0;
+
+					skbn->free = 1;
+					skbn->arp  = 1;
+
+					if (ax25->sk != NULL) {
+						skbn->sk = ax25->sk;
+						ax25->sk->rmem_alloc += skbn->truesize;
+					}
+
+					skb_reserve(skbn, AX25_MAX_HEADER_LEN);
+
+					while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) {
+						memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+						kfree_skb(skbo, FREE_READ);
+					}
+
+					ax25->fraglen = 0;
+
+					if (ax25_rx_iframe(ax25, skbn) == 0)
+						kfree_skb(skbn, FREE_READ);
+				}
+				
+				return 1;
+			}
+		}
+	} else {
+		if (*skb->data & SEG_FIRST) {
+			ax25->fragno = *skb->data & SEG_REM;
+			skb_pull(skb, 1);
+			ax25->fraglen = skb->len;
+			skb_queue_tail(&ax25->frag_queue, skb);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
 /*
  *	This is where all valid I frames are sent to, to be dispatched to
  *	whichever protocol requires them.
@@ -63,18 +124,18 @@
 
 	skb->h.raw = skb->data;
 
-	switch (skb->data[1]) {
+	switch (*skb->data) {
 #ifdef CONFIG_NETROM
 		case AX25_P_NETROM:
-			skb_pull(skb, 2);
+			skb_pull(skb, 1);	/* Remove PID */
 			queued = nr_route_frame(skb, ax25);
 			break;
 #endif
 #ifdef CONFIG_INET
 		case AX25_P_IP:
+			skb_pull(skb, 1);	/* Remove PID */
+			skb->h.raw = skb->data;
 			ax25_ip_mode_set(&ax25->dest_addr, ax25->device, 'V');
-			skb->h.raw += 2;
-			skb_push(skb, skb->dev->hard_header_len);
 			ip_rcv(skb, skb->dev, NULL);	/* Wrong ptype */
 			queued = 1;
 			break;
@@ -88,7 +149,12 @@
 				}
 			}
 			break;
-					
+			
+		case AX25_P_SEGMENT:
+			skb_pull(skb, 1);	/* Remove PID */
+			queued = ax25_rx_fragment(ax25, skb);
+			break;
+
 		default:
 			break;
 	}
@@ -101,17 +167,21 @@
  *	The handling of the timer(s) is in file ax25_timer.c.
  *	Handling of state 0 and connection release is in ax25.c.
  */
-static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type)
+static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
 {
-	int pf = skb->data[0] & PF;
-
 	switch (frametype) {
 		case SABM:
-			ax25_send_control(ax25, UA | pf, C_RESPONSE);
+			ax25->modulus = MODULUS;
+			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			break;
+
+		case SABME:
+			ax25->modulus = EMODULUS;
+			ax25_send_control(ax25, UA, pf, C_RESPONSE);
 			break;
 
 		case DISC:
-			ax25_send_control(ax25, DM | pf, C_RESPONSE);
+			ax25_send_control(ax25, DM, pf, C_RESPONSE);
 			break;
 
 		case UA:
@@ -135,14 +205,18 @@
 
 		case DM:
 			if (pf) {
-				ax25_clear_tx_queue(ax25);
-				ax25->state = AX25_STATE_0;
-				if (ax25->sk != NULL) {
-					ax25->sk->state = TCP_CLOSE;
-					ax25->sk->err   = ECONNREFUSED;
-					if (!ax25->sk->dead)
-						ax25->sk->state_change(ax25->sk);
-					ax25->sk->dead  = 1;
+				if (ax25->modulus == MODULUS) {
+					ax25_clear_queues(ax25);
+					ax25->state = AX25_STATE_0;
+					if (ax25->sk != NULL) {
+						ax25->sk->state = TCP_CLOSE;
+						ax25->sk->err   = ECONNREFUSED;
+						if (!ax25->sk->dead)
+							ax25->sk->state_change(ax25->sk);
+						ax25->sk->dead  = 1;
+					}
+				} else {
+					ax25->modulus = MODULUS;
 				}
 			}
 			break;
@@ -159,17 +233,16 @@
  *	The handling of the timer(s) is in file ax25_timer.c
  *	Handling of state 0 and connection release is in ax25.c.
  */
-static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type)
+static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
 {
-	int pf = skb->data[0] & PF;
-
 	switch (frametype) {
 		case SABM:
-			ax25_send_control(ax25, DM | pf, C_RESPONSE);
+		case SABME:
+			ax25_send_control(ax25, DM, pf, C_RESPONSE);
 			break;
 
 		case DISC:
-			ax25_send_control(ax25, UA | pf, C_RESPONSE);
+			ax25_send_control(ax25, UA, pf, C_RESPONSE);
 			break;
 
 		case UA:
@@ -203,7 +276,7 @@
 		case RNR:
 		case RR:
 			if (pf)
-				ax25_send_control(ax25, DM | PF, C_RESPONSE);
+				ax25_send_control(ax25, DM, POLLON, C_RESPONSE);
 			break;
 				
 		default:
@@ -218,16 +291,25 @@
  *	The handling of the timer(s) is in file ax25_timer.c
  *	Handling of state 0 and connection release is in ax25.c.
  */
-static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type)
+static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
 {
-	unsigned short nr = (skb->data[0] >> 5) & 7;
-	unsigned short ns = (skb->data[0] >> 1) & 7;
-	int pf = skb->data[0] & PF;
 	int queued = 0;
 
 	switch (frametype) {
 		case SABM:
-			ax25_send_control(ax25, UA | pf, C_RESPONSE);
+			ax25->modulus   = MODULUS;
+			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25->condition = 0x00;
+			ax25->t1timer   = 0;
+			ax25->t3timer   = ax25->t3;
+			ax25->vs        = 0;
+			ax25->va        = 0;
+			ax25->vr        = 0;
+			break;
+
+		case SABME:
+			ax25->modulus   = EMODULUS;
+			ax25_send_control(ax25, UA, pf, C_RESPONSE);
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
@@ -237,8 +319,8 @@
 			break;
 
 		case DISC:
-			ax25_clear_tx_queue(ax25);
-			ax25_send_control(ax25, UA | pf, C_RESPONSE);
+			ax25_clear_queues(ax25);
+			ax25_send_control(ax25, UA, pf, C_RESPONSE);
 			ax25->t3timer = 0;
 			ax25->state   = AX25_STATE_0;
 			if (ax25->sk != NULL) {
@@ -256,7 +338,7 @@
 			break;
 
 		case DM:
-			ax25_clear_tx_queue(ax25);
+			ax25_clear_queues(ax25);
 			ax25->t3timer = 0;
 			ax25->state   = AX25_STATE_0;
 			if (ax25->sk) {
@@ -327,7 +409,7 @@
 					if (pf) ax25_enquiry_response(ax25);
 					break;
 				}
-				ax25->vr = (ax25->vr + 1) % MODULUS;
+				ax25->vr = (ax25->vr + 1) % ax25->modulus;
 				ax25->condition &= ~REJECT_CONDITION;
 				if (pf) {
 					ax25_enquiry_response(ax25);
@@ -342,7 +424,7 @@
 					if (pf) ax25_enquiry_response(ax25);
 				} else {
 					ax25->condition |= REJECT_CONDITION;
-					ax25_send_control(ax25, REJ | pf, C_RESPONSE);
+					ax25_send_control(ax25, REJ, pf, C_RESPONSE);
 					ax25->condition &= ~ACK_PENDING_CONDITION;
 				}
 			}
@@ -366,16 +448,27 @@
  *	The handling of the timer(s) is in file ax25_timer.c
  *	Handling of state 0 and connection release is in ax25.c.
  */
-static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type)
+static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int ns, int nr, int pf, int type)
 {
-	unsigned short nr = (skb->data[0] >> 5) & 7;
-	unsigned short ns = (skb->data[0] >> 1) & 7;
-	int pf = skb->data[0] & PF;
 	int queued = 0;
 
 	switch (frametype) {
 		case SABM:
-			ax25_send_control(ax25, UA | pf, C_RESPONSE);
+			ax25->modulus   = MODULUS;
+			ax25_send_control(ax25, UA, pf, C_RESPONSE);
+			ax25->condition = 0x00;
+			ax25->t1timer   = 0;
+			ax25->t3timer   = ax25->t3;
+			ax25->vs        = 0;
+			ax25->va        = 0;
+			ax25->vr        = 0;
+			ax25->state     = AX25_STATE_3;
+			ax25->n2count   = 0;
+			break;
+
+		case SABME:
+			ax25->modulus   = EMODULUS;
+			ax25_send_control(ax25, UA, pf, C_RESPONSE);
 			ax25->condition = 0x00;
 			ax25->t1timer   = 0;
 			ax25->t3timer   = ax25->t3;
@@ -387,8 +480,8 @@
 			break;
 
 		case DISC:
-			ax25_clear_tx_queue(ax25);
-			ax25_send_control(ax25, UA | pf, C_RESPONSE);
+			ax25_clear_queues(ax25);
+			ax25_send_control(ax25, UA, pf, C_RESPONSE);
 			ax25->t3timer = 0;
 			ax25->state   = AX25_STATE_0;
 			if (ax25->sk != NULL) {
@@ -406,7 +499,7 @@
 			break;
 
 		case DM:
-			ax25_clear_tx_queue(ax25);
+			ax25_clear_queues(ax25);
 			ax25->t3timer = 0;
 			ax25->state   = AX25_STATE_0;
 			if (ax25->sk != NULL) {
@@ -518,7 +611,7 @@
 					if (pf) ax25_enquiry_response(ax25);
 					break;
 				}
-				ax25->vr = (ax25->vr + 1) % MODULUS;
+				ax25->vr = (ax25->vr + 1) % ax25->modulus;
 				ax25->condition &= ~REJECT_CONDITION;
 				if (pf) {
 					ax25_enquiry_response(ax25);
@@ -533,7 +626,7 @@
 					if (pf) ax25_enquiry_response(ax25);
 				} else {
 					ax25->condition |= REJECT_CONDITION;
-					ax25_send_control(ax25, REJ | pf, C_RESPONSE);
+					ax25_send_control(ax25, REJ, pf, C_RESPONSE);
 					ax25->condition &= ~ACK_PENDING_CONDITION;
 				}
 			}
@@ -557,7 +650,7 @@
  */
 int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type)
 {
-	int queued = 0, frametype;
+	int queued = 0, frametype, ns, nr, pf;
 
 	if (ax25->state != AX25_STATE_1 && ax25->state != AX25_STATE_2 &&
 	    ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4) {
@@ -567,20 +660,20 @@
 
 	del_timer(&ax25->timer);
 
-	frametype = ax25_decode(skb->data);
+	frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
 
 	switch (ax25->state) {
 		case AX25_STATE_1:
-			queued = ax25_state1_machine(ax25, skb, frametype, type);
+			queued = ax25_state1_machine(ax25, skb, frametype, pf, type);
 			break;
 		case AX25_STATE_2:
-			queued = ax25_state2_machine(ax25, skb, frametype, type);
+			queued = ax25_state2_machine(ax25, skb, frametype, pf, type);
 			break;
 		case AX25_STATE_3:
-			queued = ax25_state3_machine(ax25, skb, frametype, type);
+			queued = ax25_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
 			break;
 		case AX25_STATE_4:
-			queued = ax25_state4_machine(ax25, skb, frametype, type);
+			queued = ax25_state4_machine(ax25, skb, frametype, ns, nr, pf, type);
 			break;
 	}
 
diff -u --recursive --new-file v1.3.13/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c
--- v1.3.13/linux/net/ax25/ax25_out.c	Fri Jul  7 08:54:56 1995
+++ linux/net/ax25/ax25_out.c	Thu Jul 27 19:36:17 1995
@@ -1,5 +1,5 @@
 /*
- *	AX.25 release 029
+ *	AX.25 release 030
  *
  *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *	releases, misbehave and/or generally screw up. It might even work. 
@@ -22,6 +22,8 @@
  *	AX.25 028a	Jonathan(G4KLX)	New state machine based on SDL diagrams.
  *	AX.25 029	Alan(GW4PTS)	Switched to KA9Q constant names.
  *			Jonathan(G4KLX)	Only poll when window is full.
+ *	AX.25 030	Jonathan(G4KLX)	Added fragmentation to ax25_output.
+ *					Added support for extended AX.25.
  */
 
 #include <linux/config.h>
@@ -47,14 +49,67 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 
-int ax25_output(ax25_cb *ax25, struct sk_buff *skb)
+/*
+ * All outgoing AX.25 I frames pass via this routine. Therefore this is
+ * where the fragmentation of frames takes place.
+ */
+void ax25_output(ax25_cb *ax25, struct sk_buff *skb)
 {
-	skb_queue_tail(&ax25->write_queue, skb);	/* Throw it on the queue */
+	struct sk_buff *skbn;
+	unsigned char *p;
+	int err, frontlen, mtu, len, fragno, first = 1;
+	
+	mtu = ax25->device->mtu;
+	
+	if (skb->len > mtu) {
+		mtu -= 2;		/* Allow for fragment control info */
+		
+		fragno = skb->len / mtu;
+		if (skb->len % mtu == 0) fragno--;
+
+		frontlen = skb_headroom(skb);	/* Address space + CTRL */
+
+		while (skb->len > 0) {
+			if (skb->sk != NULL) {
+				if ((skbn = sock_alloc_send_skb(skb->sk, mtu + 2 + frontlen, 0, &err)) == NULL)
+					return;
+			} else {
+				if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL)
+					return;
+			}
+
+			skbn->sk   = skb->sk;
+			skbn->free = 1;
+			skbn->arp  = 1;
+
+			skb_reserve(skbn, frontlen + 2);
+
+			len = (mtu > skb->len) ? skb->len : mtu;
+			
+			memcpy(skb_put(skbn, len), skb->data, len);
+			skb_pull(skb, len);
+
+			p = skb_push(skbn, 2);
+
+			*p++ = AX25_P_SEGMENT;
+
+			*p = fragno--;
+			if (first) {
+				*p |= SEG_FIRST;
+				first = 0;
+			}
+
+			skb_queue_tail(&ax25->write_queue, skbn); /* Throw it on the queue */
+		}
+		
+		skb->free = 1;
+		kfree_skb(skb, FREE_WRITE);
+	} else {
+		skb_queue_tail(&ax25->write_queue, skb);	  /* Throw it on the queue */
+	}
 
 	if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4)
 		ax25_kick(ax25);
-
-	return 0;
 }
 
 /* 
@@ -67,13 +122,22 @@
 
 	if (skb == NULL)
 		return;
-	
-	frame = skb_push(skb, 1);	/* KISS + header */
 
-	*frame = I;
-	*frame |= poll_bit;
-	*frame |= (ax25->vr << 5);
-	*frame |= (ax25->vs << 1);
+	if (ax25->modulus == MODULUS) {
+		frame = skb_push(skb, 1);
+
+		*frame = I;
+		*frame |= (poll_bit) ? PF : 0;
+		*frame |= (ax25->vr << 5);
+		*frame |= (ax25->vs << 1);
+	} else {
+		frame = skb_push(skb, 2);
+
+		frame[0] = I;
+		frame[0] |= (ax25->vs << 1);
+		frame[1] = (poll_bit) ? EPF : 0;
+		frame[1] |= (ax25->vr << 1);
+	}
 
 	ax25_transmit_buffer(ax25, skb, C_COMMAND);	
 }
@@ -87,7 +151,7 @@
 	del_timer(&ax25->timer);
 
 	start = (skb_peek(&ax25->ack_queue) == NULL) ? ax25->va : ax25->vs;
-	end   = (ax25->va + ax25->window) % MODULUS;
+	end   = (ax25->va + ax25->window) % ax25->modulus;
 
 	if (!(ax25->condition & PEER_RX_BUSY_CONDITION) &&
 	    start != end                                   &&
@@ -111,7 +175,7 @@
 				return;
 			}
 
-			next = (ax25->vs + 1) % MODULUS;
+			next = (ax25->vs + 1) % ax25->modulus;
 #ifdef notdef
 			last = (next == end) || skb_peek(&ax25->write_queue) == NULL;
 #else
@@ -120,7 +184,7 @@
 			/*
 			 * Transmit the frame copy.
 			 */
-			ax25_send_iframe(ax25, skbn, (last) ? PF : 0);
+			ax25_send_iframe(ax25, skbn, (last) ? POLLON : POLLOFF);
 
 			ax25->vs = next;
 
@@ -167,7 +231,7 @@
 	}
 
 	ptr = skb_push(skb, size_ax25_addr(ax25->digipeat));
-	build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type);
+	build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
 
 	skb->arp = 1;
 
@@ -189,8 +253,12 @@
 	ax25->condition = 0x00;
 	ax25->n2count   = 0;
 
-	ax25_send_control(ax25, SABM | PF, C_COMMAND);
-
+	if (ax25->modulus == MODULUS) {
+		ax25_send_control(ax25, SABM, POLLON, C_COMMAND);
+	} else {
+		ax25_send_control(ax25, SABME, POLLON, C_COMMAND);
+	}
+	
 	ax25->t3timer = 0;
 	ax25->t2timer = 0;
 	ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25);
@@ -199,9 +267,9 @@
 void ax25_transmit_enquiry(ax25_cb *ax25)
 {
 	if (ax25->condition & OWN_RX_BUSY_CONDITION)
-		ax25_send_control(ax25, RNR | PF, C_COMMAND);
+		ax25_send_control(ax25, RNR, POLLON, C_COMMAND);
 	else
-		ax25_send_control(ax25, RR | PF, C_COMMAND);
+		ax25_send_control(ax25, RR, POLLON, C_COMMAND);
 
 	ax25->condition &= ~ACK_PENDING_CONDITION;
 
@@ -211,9 +279,9 @@
 void ax25_enquiry_response(ax25_cb *ax25)
 {
 	if (ax25->condition & OWN_RX_BUSY_CONDITION)
-		ax25_send_control(ax25, RNR | PF, C_RESPONSE);
+		ax25_send_control(ax25, RNR, POLLON, C_RESPONSE);
 	else
-		ax25_send_control(ax25, RR | PF, C_RESPONSE);
+		ax25_send_control(ax25, RR, POLLON, C_RESPONSE);
 
 	ax25->condition &= ~ACK_PENDING_CONDITION;
 }
diff -u --recursive --new-file v1.3.13/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c
--- v1.3.13/linux/net/ax25/ax25_route.c	Fri Jul  7 08:54:56 1995
+++ linux/net/ax25/ax25_route.c	Thu Jul 27 19:36:17 1995
@@ -1,5 +1,5 @@
 /*
- *	AX.25 release 029
+ *	AX.25 release 030
  *
  *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *	releases, misbehave and/or generally screw up. It might even work. 
diff -u --recursive --new-file v1.3.13/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c
--- v1.3.13/linux/net/ax25/ax25_subr.c	Fri Jul  7 08:54:56 1995
+++ linux/net/ax25/ax25_subr.c	Thu Jul 27 19:36:17 1995
@@ -1,5 +1,5 @@
 /*
- *	AX.25 release 029
+ *	AX.25 release 030
  *
  *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *	releases, misbehave and/or generally screw up. It might even work. 
@@ -21,6 +21,8 @@
  *	History
  *	AX.25 029	Alan(GW4PTS)	Switched to KA9Q constant names. Removed
  *					old BSD code.
+ *	AX.25 030	Jonathan(G4KLX)	Added support for extended AX.25.
+ *					Added fragmentation support.
  */
 
 #include <linux/config.h>
@@ -49,9 +51,9 @@
 /* #define	NO_BACKOFF	*/
 
 /*
- * This routine purges the input queue of frames.
+ *	This routine purges all the queues of frames.
  */
-void ax25_clear_tx_queue(ax25_cb *ax25)
+void ax25_clear_queues(ax25_cb *ax25)
 {
 	struct sk_buff *skb;
 
@@ -64,6 +66,14 @@
 		skb->free = 1;
 		kfree_skb(skb, FREE_WRITE);
 	}
+
+	while ((skb = skb_dequeue(&ax25->reseq_queue)) != NULL) {
+		kfree_skb(skb, FREE_READ);
+	}
+
+	while ((skb = skb_dequeue(&ax25->frag_queue)) != NULL) {
+		kfree_skb(skb, FREE_READ);
+	}
 }
 
 /*
@@ -83,7 +93,7 @@
 		        skb = skb_dequeue(&ax25->ack_queue);
 			skb->free = 1;
 			kfree_skb(skb, FREE_WRITE);
-			ax25->va = (ax25->va + 1) % MODULUS;
+			ax25->va = (ax25->va + 1) % ax25->modulus;
 		}
 	}
 
@@ -111,7 +121,7 @@
 
 	while (vc != ax25->vs) {
 		if (nr == vc) return 1;
-		vc = (vc + 1) % MODULUS;
+		vc = (vc + 1) % ax25->modulus;
 	}
 	
 	if (nr == ax25->vs) return 1;
@@ -119,16 +129,51 @@
 	return 0;
 }
 
-int ax25_decode(unsigned char *frame)
+/*
+ *	This routine is the centralised routine for parsing the control
+ *	information for the different frame formats.
+ */
+int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
 {
+	unsigned char *frame;
 	int frametype = ILLEGAL;
 
-	if ((frame[0] & S) == 0)
-		frametype = I;		/* I frame - carries NR/NS/PF */
-	else if ((frame[0] & U) == 1) 	/* S frame - take out PF/NR */
-		frametype = frame[0] & 0x0F;
-	else if ((frame[0] & U) == 3) 	/* U frame - take out PF */
-		frametype = frame[0] & ~PF;
+	frame = skb->data;
+	*ns = *nr = *pf = 0;
+
+	if (ax25->modulus == MODULUS) {
+		if ((frame[0] & S) == 0) {
+			frametype = I;			/* I frame - carries NR/NS/PF */
+			*ns = (frame[0] >> 1) & 0x07;
+			*nr = (frame[0] >> 5) & 0x07;
+			*pf = frame[0] & PF;
+		} else if ((frame[0] & U) == 1) { 	/* S frame - take out PF/NR */
+			frametype = frame[0] & 0x0F;
+			*nr = (frame[0] >> 5) & 0x07;
+			*pf = frame[0] & PF;
+		} else if ((frame[0] & U) == 3) { 	/* U frame - take out PF */
+			frametype = frame[0] & ~PF;
+			*pf = frame[0] & PF;
+		}
+		skb_pull(skb, 1);
+	} else {
+		if ((frame[0] & S) == 0) {
+			frametype = I;			/* I frame - carries NR/NS/PF */
+			*ns = (frame[0] >> 1) & 0x7F;
+			*nr = (frame[1] >> 1) & 0x7F;
+			*pf = frame[1] & EPF;
+			skb_pull(skb, 2);
+		} else if ((frame[0] & U) == 1) { 	/* S frame - take out PF/NR */
+			frametype = frame[0] & 0x0F;
+			*nr = (frame[1] >> 1) & 0x7F;
+			*pf = frame[1] & EPF;
+			skb_pull(skb, 2);
+		} else if ((frame[0] & U) == 3) { 	/* U frame - take out PF */
+			frametype = frame[0] & ~PF;
+			*pf = frame[0] & PF;
+			skb_pull(skb, 1);
+		}
+	}
 
 	return frametype;
 }
@@ -138,7 +183,7 @@
  *	command or  response  for  the remote machine ( eg. RR, UA etc. ). 
  *	Only supervisory or unnumbered frames are processed.
  */
-void ax25_send_control(ax25_cb *ax25, int frametype, int type)
+void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type)
 {
 	struct sk_buff *skb;
 	unsigned char  *dptr;
@@ -147,7 +192,7 @@
 	if ((dev = ax25->device) == NULL)
 		return;	/* Route died */
 
-	if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat) + 1, GFP_ATOMIC)) == NULL)
+	if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL)
 		return;
 
 	skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat));
@@ -158,12 +203,24 @@
 	}
 
 	/* Assume a response - address structure for DTE */
-	dptr = skb_put(skb, 1);
-	
-	if ((frametype & U) == S)		/* S frames carry NR */
-		frametype |= (ax25->vr << 5);
-
-	*dptr = frametype;
+	if (ax25->modulus == MODULUS) {
+		dptr = skb_put(skb, 1);
+		*dptr = frametype;
+		*dptr |= (poll_bit) ? PF : 0;
+		if ((frametype & U) == S)		/* S frames carry NR */
+			*dptr |= (ax25->vr << 5);
+	} else {
+		if ((frametype & U) == U) {
+			dptr = skb_put(skb, 1);
+			*dptr = frametype;
+			*dptr |= (poll_bit) ? PF : 0;
+		} else {
+			dptr = skb_put(skb, 2);
+			dptr[0] = frametype;
+			dptr[1] = (ax25->vr << 1);
+			dptr[1] |= (poll_bit) ? EPF : 0;
+		}
+	}
 
 	skb->free = 1;
 
@@ -201,7 +258,7 @@
 	 */
 
 	dptr  = skb_push(skb, size_ax25_addr(digi));
-	dptr += build_ax25_addr(dptr, dest, src, &retdigi, C_RESPONSE);
+	dptr += build_ax25_addr(dptr, dest, src, &retdigi, C_RESPONSE, MODULUS);
 
 	skb->arp  = 1;
 	skb->free = 1;
@@ -217,10 +274,13 @@
 #ifndef NO_BACKOFF
 	int n, t = 2;
 
-	if (ax25->backoff)
+	if (ax25->backoff) {
 		for (n = 0; n < ax25->n2count; n++)
 			t *= 2;
 
+		if (t > 8) t = 8;
+	}
+
 	return t * ax25->rtt;
 #else
 	return 2 * ax25->rtt;
@@ -249,7 +309,6 @@
  *	Given an AX.25 address pull of to, from, digi list, command/response and the start of data
  *
  */
-
 unsigned char *ax25_parse_addr(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags)
 {
 	int d = 0;
@@ -302,28 +361,32 @@
 /*
  *	Assemble an AX.25 header from the bits
  */
-		
-int build_ax25_addr(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag)
+int build_ax25_addr(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus)
 {
 	int len = 0;
 	int ct  = 0;
 
 	memcpy(buf, dest, AX25_ADDR_LEN);
-	
-	if (flag != C_COMMAND && flag != C_RESPONSE)
-		printk("build_ax25_addr: Bogus flag %d\n!", flag);
 	buf[6] &= ~(LAPB_E | LAPB_C);
-	buf[6] |= SSID_SPARE;
+	buf[6] |= SSSID_SPARE;
 
 	if (flag == C_COMMAND) buf[6] |= LAPB_C;
 
 	buf += AX25_ADDR_LEN;
 	len += AX25_ADDR_LEN;
+
 	memcpy(buf, src, AX25_ADDR_LEN);
 	buf[6] &= ~(LAPB_E | LAPB_C);
-	buf[6] |= SSID_SPARE;
+	buf[6] &= ~SSSID_SPARE;
+
+	if (modulus == MODULUS) {
+		buf[6] |= SSSID_SPARE;
+	} else {
+		buf[6] |= ESSID_SPARE;
+	}
 
 	if (flag == C_RESPONSE) buf[6] |= LAPB_C;
+
 	/*
 	 *	Fast path the normal digiless path
 	 */
@@ -342,7 +405,7 @@
 		else
 			buf[6] &= ~AX25_REPEATED;
 		buf[6] &= ~LAPB_E;
-		buf[6] |= SSID_SPARE;
+		buf[6] |= SSSID_SPARE;
 
 		buf += AX25_ADDR_LEN;
 		len += AX25_ADDR_LEN;
@@ -365,7 +428,6 @@
 /* 
  *	Reverse Digipeat List. May not pass both parameters as same struct
  */	
-
 void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
 {
 	int ct = 0;
diff -u --recursive --new-file v1.3.13/linux/net/ax25/ax25_timer.c linux/net/ax25/ax25_timer.c
--- v1.3.13/linux/net/ax25/ax25_timer.c	Tue Jun  6 12:16:43 1995
+++ linux/net/ax25/ax25_timer.c	Mon Jul 31 09:46:26 1995
@@ -1,5 +1,5 @@
 /*
- *	AX.25 release 029
+ *	AX.25 release 030
  *
  *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
  *	releases, misbehave and/or generally screw up. It might even work. 
@@ -63,7 +63,7 @@
 	ax25->timer.data     = (unsigned long)ax25;
 	ax25->timer.function = &ax25_timer;
 
-	ax25->timer.expires = 10;
+	ax25->timer.expires = jiffies + 10;
 	add_timer(&ax25->timer);
 }
 
@@ -78,7 +78,7 @@
 
 	ax25->timer.data     = (unsigned long)ax25;
 	ax25->timer.function = &ax25_timer;
-	ax25->timer.expires  = 10;
+	ax25->timer.expires  = jiffies + 10;
 	add_timer(&ax25->timer);
 }
 
@@ -111,7 +111,7 @@
 			if (ax25->sk != NULL) {
 				if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & OWN_RX_BUSY_CONDITION)) {
 					ax25->condition &= ~OWN_RX_BUSY_CONDITION;
-					ax25_send_control(ax25, RR, C_RESPONSE);
+					ax25_send_control(ax25, RR, POLLOFF, C_RESPONSE);
 					ax25->condition &= ~ACK_PENDING_CONDITION;
 					break;
 				}
@@ -152,21 +152,30 @@
 	switch (ax25->state) {
 		case AX25_STATE_1: 
 			if (ax25->n2count == ax25->n2) {
+				if (ax25->modulus == MODULUS) {
 #ifdef CONFIG_NETROM
-				nr_link_failed(&ax25->dest_addr, ax25->device);
+					nr_link_failed(&ax25->dest_addr, ax25->device);
 #endif
-				ax25_clear_tx_queue(ax25);
-				ax25->state = AX25_STATE_0;
-				if (ax25->sk != NULL) {
-					ax25->sk->state = TCP_CLOSE;
-					ax25->sk->err   = ETIMEDOUT;
-					if (!ax25->sk->dead)
-						ax25->sk->state_change(ax25->sk);
-					ax25->sk->dead  = 1;
+					ax25_clear_queues(ax25);
+					ax25->state = AX25_STATE_0;
+					if (ax25->sk != NULL) {
+						ax25->sk->state = TCP_CLOSE;
+						ax25->sk->err   = ETIMEDOUT;
+						if (!ax25->sk->dead)
+							ax25->sk->state_change(ax25->sk);
+						ax25->sk->dead  = 1;
+					}
+				} else {
+					ax25->modulus = MODULUS;
+					ax25->n2count = 0;
 				}
 			} else {
 				ax25->n2count++;
-				ax25_send_control(ax25, SABM | PF, C_COMMAND);
+				if (ax25->modulus == MODULUS) {
+					ax25_send_control(ax25, SABM, POLLON, C_COMMAND);
+				} else {
+					ax25_send_control(ax25, SABME, POLLON, C_COMMAND);
+				}
 			}
 			break;
 
@@ -175,7 +184,7 @@
 #ifdef CONFIG_NETROM
 				nr_link_failed(&ax25->dest_addr, ax25->device);
 #endif
-				ax25_clear_tx_queue(ax25);
+				ax25_clear_queues(ax25);
 				ax25->state = AX25_STATE_0;
 				if (ax25->sk != NULL) {
 					ax25->sk->state = TCP_CLOSE;
@@ -186,7 +195,7 @@
 				}
 			} else {
 				ax25->n2count++;
-				ax25_send_control(ax25, DISC | PF, C_COMMAND);
+				ax25_send_control(ax25, DISC, POLLON, C_COMMAND);
 			}
 			break;
 
@@ -201,8 +210,8 @@
 #ifdef CONFIG_NETROM
 				nr_link_failed(&ax25->dest_addr, ax25->device);
 #endif
-				ax25_clear_tx_queue(ax25);
-				ax25_send_control(ax25, DM | PF, C_RESPONSE);
+				ax25_clear_queues(ax25);
+				ax25_send_control(ax25, DM, POLLON, C_RESPONSE);
 				ax25->state = AX25_STATE_0;
 				if (ax25->sk != NULL) {
 					ax25->sk->state = TCP_CLOSE;
diff -u --recursive --new-file v1.3.13/linux/net/ethernet/pe2.c linux/net/ethernet/pe2.c
--- v1.3.13/linux/net/ethernet/pe2.c	Fri Jun 30 16:22:31 1995
+++ linux/net/ethernet/pe2.c	Thu Jul 27 19:34:36 1995
@@ -9,12 +9,8 @@
 		struct sk_buff *skb, unsigned char *dest_node)
 {
 	struct device	*dev = skb->dev;
-	unsigned long	len = skb->len;
-	unsigned long	hard_len = dev->hard_header_len;
-
-	dev->hard_header(skb, dev, ETH_P_IPX,
-			dest_node, NULL, len - hard_len);
-	skb->h.raw = skb->data + hard_len;
+	
+	dev->hard_header(skb, dev, ETH_P_IPX, dest_node, NULL, skb->len);
 }
 
 struct datalink_proto *
diff -u --recursive --new-file v1.3.13/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v1.3.13/linux/net/ipv4/arp.c	Fri Jul  7 08:54:57 1995
+++ linux/net/ipv4/arp.c	Mon Jul 31 09:46:26 1995
@@ -232,7 +232,7 @@
 	 */
 
 	del_timer(&arp_timer);
-	arp_timer.expires = ARP_CHECK_INTERVAL;
+	arp_timer.expires = jiffies + ARP_CHECK_INTERVAL;
 	add_timer(&arp_timer);
 }
 
@@ -411,7 +411,7 @@
 
 		/* Set new timer. */
 		del_timer(&entry->timer);
-		entry->timer.expires = ARP_RES_TIME;
+		entry->timer.expires = jiffies + ARP_RES_TIME;
 		add_timer(&entry->timer);
 		restore_flags(flags);
 		arp_send(ARPOP_REQUEST, ETH_P_ARP, ip, dev, dev->pa_addr, 
@@ -962,7 +962,7 @@
 		init_timer(&entry->timer);
 		entry->timer.function = arp_expire_request;
 		entry->timer.data = (unsigned long)entry;
-		entry->timer.expires = ARP_RES_TIME;
+		entry->timer.expires = jiffies + ARP_RES_TIME;
 		arp_tables[hash] = entry;
 		add_timer(&entry->timer);
 		entry->retries = ARP_MAX_TRIES;
diff -u --recursive --new-file v1.3.13/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v1.3.13/linux/net/ipv4/igmp.c	Thu Jul 13 16:20:21 1995
+++ linux/net/ipv4/igmp.c	Mon Jul 31 09:46:27 1995
@@ -69,7 +69,7 @@
 	if(im->tm_running)
 		return;
 	tv=random()%(10*HZ);		/* Pick a number any number 8) */
-	im->timer.expires=tv;
+	im->timer.expires=jiffies+tv;
 	im->tm_running=1;
 	add_timer(&im->timer);
 }
diff -u --recursive --new-file v1.3.13/linux/net/ipv4/ip.c linux/net/ipv4/ip.c
--- v1.3.13/linux/net/ipv4/ip.c	Tue Jul 25 18:21:24 1995
+++ linux/net/ipv4/ip.c	Mon Jul 31 09:46:27 1995
@@ -523,7 +523,7 @@
 	qp->dev = dev;
 
 	/* Start a timer for this entry. */
-	qp->timer.expires = IP_FRAG_TIME;		/* about 30 seconds	*/
+	qp->timer.expires = jiffies + IP_FRAG_TIME;	/* about 30 seconds	*/
 	qp->timer.data = (unsigned long) qp;		/* pointer to queue	*/
 	qp->timer.function = ip_expire;			/* expire function	*/
 	add_timer(&qp->timer);
@@ -682,7 +682,7 @@
 	if (qp != NULL)
 	{
 		del_timer(&qp->timer);
-		qp->timer.expires = IP_FRAG_TIME;	/* about 30 seconds */
+		qp->timer.expires = jiffies + IP_FRAG_TIME;	/* about 30 seconds */
 		qp->timer.data = (unsigned long) qp;	/* pointer to queue */
 		qp->timer.function = ip_expire;		/* expire function */
 		add_timer(&qp->timer);
@@ -1974,7 +1974,7 @@
                                 len+=sprintf(buffer+len,
 					"\t\t\t%08lX %5d %d:%08lX\n",
                                         im->multiaddr, im->users,
-					im->tm_running, im->timer.expires);
+					im->tm_running, im->timer.expires-jiffies);
                                 pos=begin+len;
                                 if(pos<offset)
                                 {
diff -u --recursive --new-file v1.3.13/linux/net/ipv4/ip_fw.c linux/net/ipv4/ip_fw.c
--- v1.3.13/linux/net/ipv4/ip_fw.c	Tue Jul 25 18:21:24 1995
+++ linux/net/ipv4/ip_fw.c	Mon Jul 31 09:46:27 1995
@@ -579,7 +579,7 @@
 		ms->sport    = htons(port);	/* derived from PORT cmd */
 		ms->dst      = iph->daddr;
 		ms->dport    = htons(20);	/* ftp-data */
-		ms->timer.expires = MASQUERADE_EXPIRE_TCP_FIN;
+		ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
 		add_timer(&ms->timer);
 
 		/*
@@ -724,7 +724,7 @@
  	 
  	if (iph->protocol==IPPROTO_UDP) 
  	{
- 		ms->timer.expires = MASQUERADE_EXPIRE_UDP;
+ 		ms->timer.expires = jiffies+MASQUERADE_EXPIRE_UDP;
  		recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
  	}
  	else 
@@ -744,10 +744,10 @@
  		 */
  		if (ms->sawfin || th->fin) 
  		{
- 			ms->timer.expires = MASQUERADE_EXPIRE_TCP_FIN;
+ 			ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP_FIN;
  			ms->sawfin = 1;
  		}
- 		else ms->timer.expires = MASQUERADE_EXPIRE_TCP;
+ 		else ms->timer.expires = jiffies+MASQUERADE_EXPIRE_TCP;
  
  		tcp_send_check(th,iph->saddr,iph->daddr,size,skb->sk);
  	}
@@ -1482,13 +1482,13 @@
 	{
 		int timer_active = del_timer(&ms->timer);
 		if (!timer_active)
-			ms->timer.expires = 0;
+			ms->timer.expires = jiffies;
 		len+=sprintf(buffer+len,"%s %08lX:%04X %08lX:%04X %04X %08X %5d %lu\n",
 			strProt[ms->protocol==IPPROTO_TCP],
 			ntohl(ms->src),ntohs(ms->sport),
 			ntohl(ms->dst),ntohs(ms->dport),
 			ntohs(ms->mport),
-			ms->init_seq,ms->delta,ms->timer.expires);
+			ms->init_seq,ms->delta,ms->timer.expires-jiffies);
 		if (timer_active)
 			add_timer(&ms->timer);
 
diff -u --recursive --new-file v1.3.13/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v1.3.13/linux/net/ipv4/proc.c	Tue Jun  6 12:16:44 1995
+++ linux/net/ipv4/proc.c	Mon Jul 31 09:46:27 1995
@@ -111,7 +111,7 @@
 				i, src, srcp, dest, destp, sp->state, 
 				format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, 
 				format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
-				timer_active, timer_expires, (unsigned) sp->retransmits,
+				timer_active, timer_expires-jiffies, (unsigned) sp->retransmits,
 				sp->socket?SOCK_INODE(sp->socket)->i_uid:0,
 				timer_active?sp->timeout:0);
 			if (timer_active1) add_timer(&sp->retransmit_timer);
diff -u --recursive --new-file v1.3.13/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v1.3.13/linux/net/ipv4/tcp.c	Tue Jul 18 16:29:00 1995
+++ linux/net/ipv4/tcp.c	Mon Jul 31 09:46:27 1995
@@ -596,7 +596,7 @@
 		when=3;
 		printk("Error: Negative timer in xmit_timer\n");
 	}
-	sk->retransmit_timer.expires=when;
+	sk->retransmit_timer.expires=jiffies+when;
 	add_timer(&sk->retransmit_timer);
 }
 
@@ -749,7 +749,7 @@
 	if (sk->inuse || in_bh) 
 	{
 		/* Try again in 1 second */
-		sk->retransmit_timer.expires = HZ;
+		sk->retransmit_timer.expires = jiffies+HZ;
 		add_timer(&sk->retransmit_timer);
 		sti();
 		return;
@@ -1302,7 +1302,7 @@
 	/*
 	 *	Wait up to 1 second for the buffer to fill.
 	 */
-	sk->partial_timer.expires = HZ;
+	sk->partial_timer.expires = jiffies+HZ;
 	sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial;
 	sk->partial_timer.data = (unsigned long) sk;
 	add_timer(&sk->partial_timer);
@@ -1956,7 +1956,7 @@
 		{
 			/* Force it to send an ack soon. */
 			int was_active = del_timer(&sk->retransmit_timer);
-			if (!was_active || TCP_ACK_TIME < sk->timer.expires) 
+			if (!was_active || jiffies+TCP_ACK_TIME < sk->timer.expires) 
 			{
 				reset_xmit_timer(sk, TIME_WRITE, TCP_ACK_TIME);
 			} 
diff -u --recursive --new-file v1.3.13/linux/net/ipv4/timer.c linux/net/ipv4/timer.c
--- v1.3.13/linux/net/ipv4/timer.c	Tue Jun  6 12:16:44 1995
+++ linux/net/ipv4/timer.c	Mon Jul 31 09:46:27 1995
@@ -72,7 +72,7 @@
 	if ((int) len < 0)	/* prevent close to infinite timers. THEY _DO_ */
 		len = 3;	/* happen (negative values ?) - don't ask me why ! -FB */
 #endif
-	t->timer.expires = len;
+	t->timer.expires = jiffies+len;
 	add_timer (&t->timer);
 }
 
@@ -95,7 +95,7 @@
 	cli();
 	if (sk->inuse || in_bh) 
 	{
-		sk->timer.expires = 10;
+		sk->timer.expires = jiffies+10;
 		add_timer(&sk->timer);
 		sti();
 		return;
diff -u --recursive --new-file v1.3.13/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v1.3.13/linux/net/ipx/af_ipx.c	Fri Jul  7 13:42:58 1995
+++ linux/net/ipx/af_ipx.c	Thu Jul 27 19:34:36 1995
@@ -425,7 +425,7 @@
 ipxitf_adjust_skbuff(ipx_interface *intrfc, struct sk_buff *skb)
 {
 	struct sk_buff	*skb2;
-	int	in_offset = skb->h.raw - skb->data;
+	int	in_offset = skb->h.raw - skb->head;
 	int	out_offset = intrfc->if_ipx_offset;
 #if 0
 	char	*oldraw;
@@ -533,6 +533,12 @@
 		skb->sk->wmem_alloc += skb->truesize;
 	}
 
+#if 0
+	/* Now log the packet just before transmission */
+	dump_pkt("IPX snd:", (ipx_packet *)skb->h.raw);
+	dump_data("ETH hdr:", skb->data, skb->h.raw - skb->data);
+#endif
+
 	/* Send it out */
 	dev_queue_xmit(skb, dev, SOPRI_NORMAL);
 	return 0;
@@ -1588,20 +1594,31 @@
 /*
  * User to dump IPX packets (debugging)
  */
-void dump_data(char *str,unsigned char *d) {
+void dump_data(char *str,unsigned char *d, int len) {
   static char h2c[] = "0123456789ABCDEF";
   int l,i;
   char *p, b[64];
-  for (l=0;l<16;l++) {
+  for (l=0;len > 0 && l<16;l++) {
     p = b;
-    for (i=0; i < 8 ; i++) {
-      *(p++) = h2c[d[i] & 0x0f];
-      *(p++) = h2c[(d[i] >> 4) & 0x0f];
+    for (i=0; i < 8 ; i++, --len) {
+	  if (len > 0) {
+	      *(p++) = h2c[(d[i] >> 4) & 0x0f];
+	      *(p++) = h2c[d[i] & 0x0f];
+	  }
+	  else {
+	      *(p++) = ' ';
+	      *(p++) = ' ';
+	  }
       *(p++) = ' ';
     }
     *(p++) = '-';
     *(p++) = ' ';
-    for (i=0; i < 8 ; i++)  *(p++) = ' '<= d[i] && d[i]<'\177' ? d[i] : '.';
+	len += 8;
+    for (i=0; i < 8 ; i++, --len)
+		if (len > 0)
+			*(p++) = ' '<= d[i] && d[i]<'\177' ? d[i] : '.';
+		else
+			*(p++) = ' ';
     *p = '\000';
     d += i;
     printk("%s-%04X: %s\n",str,l*8,b);
@@ -1623,8 +1640,10 @@
 }
 
 void dump_pkt(char *str,ipx_packet *p) {
+  int len = ntohs(p->ipx_pktsize);
   dump_hdr(str,p);
-  dump_data(str,(unsigned char *)p);
+  if (len > 30)
+	  dump_data(str,(unsigned char *)p + 30, len - 30);
 }
 #endif
 
diff -u --recursive --new-file v1.3.13/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v1.3.13/linux/net/netrom/af_netrom.c	Fri Jul  7 08:54:57 1995
+++ linux/net/netrom/af_netrom.c	Mon Jul 31 09:46:26 1995
@@ -18,6 +18,7 @@
  *			Jonathan(G4KLX)	Complete bind re-think.
  *			Alan(GW4PTS)	Trivial tweaks into new format.
  *	NET/ROM	003	Jonathan(G4KLX)	Added G8BPQ extensions.
+ *					Added NET/ROM routing ioctl.
  *
  *	To do:
  *		Fix non-blocking connect failure.
@@ -96,6 +97,27 @@
 }
 
 /*
+ *	Kill all bound sockets on a dropped device.
+ */
+static void nr_kill_by_device(struct device *dev)
+{
+	struct sock *s;
+	
+	for (s = nr_list; s != NULL; s = s->next) {
+		if (s->nr->device == dev) {
+			s->nr->state  = NR_STATE_0;
+			s->nr->device = NULL;
+			s->state = TCP_CLOSE;
+			s->err   = ENETUNREACH;
+			s->state_change(s);
+			s->dead  = 1;
+		}
+	}
+
+	nr_rt_device_down(dev);
+}
+
+/*
  *	Handle device status changes.
  */
 static int nr_device_event(unsigned long event, void *ptr)
@@ -103,7 +125,7 @@
 	if (event != NETDEV_DOWN)
 		return NOTIFY_DONE;
 		
-	nr_rt_device_down(ptr);
+	nr_kill_by_device(ptr);
 	
 	return NOTIFY_DONE;
 }
@@ -223,7 +245,7 @@
 	del_timer(&sk->timer);
 	
 	nr_remove_socket(sk);
-	nr_clear_tx_queue(sk);	/* Flush the send queue */
+	nr_clear_queues(sk);		/* Flush the queues */
 	
 	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
 		if (skb->sk != sk) {			/* A pending connection */
@@ -237,7 +259,7 @@
 	
 	if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */
 		init_timer(&sk->timer);
-		sk->timer.expires  = 10 * HZ;
+		sk->timer.expires  = jiffies + 10 * HZ;
 		sk->timer.function = nr_destroy_timer;
 		sk->timer.data     = (unsigned long)sk;
 		add_timer(&sk->timer);
@@ -446,6 +468,7 @@
 
 	skb_queue_head_init(&nr->ack_queue);
 	skb_queue_head_init(&nr->reseq_queue);
+	skb_queue_head_init(&nr->frag_queue);
 
 	nr->my_index = 0;
 	nr->my_id    = 0;
@@ -471,7 +494,9 @@
 	nr->my_id      = 0;
 
 	nr->bpqext     = 1;
+	nr->fraglen    = 0;
 	nr->state      = NR_STATE_0;
+	nr->device     = NULL;
 
 	memset(&nr->source_addr, '\0', sizeof(ax25_address));
 	memset(&nr->user_addr,   '\0', sizeof(ax25_address));
@@ -514,7 +539,6 @@
 
 	init_timer(&sk->timer);
 
-	sk->rmem_alloc  = 0;
 	sk->dead        = 0;
 	sk->next        = NULL;
 	sk->priority    = osk->priority;
@@ -545,13 +569,16 @@
 
 	skb_queue_head_init(&nr->ack_queue);
 	skb_queue_head_init(&nr->reseq_queue);
+	skb_queue_head_init(&nr->frag_queue);
 
 	nr->rtt      = osk->nr->rtt;
 	nr->t1       = osk->nr->t1;
 	nr->t2       = osk->nr->t2;
 	nr->n2       = osk->nr->n2;
 
+	nr->device   = osk->nr->device;
 	nr->bpqext   = osk->nr->bpqext;
+	nr->fraglen  = 0;
 
 	nr->t1timer  = 0;
 	nr->t2timer  = 0;
@@ -606,7 +633,7 @@
 				break;			
 
 			case NR_STATE_3:
-				nr_clear_tx_queue(sk);
+				nr_clear_queues(sk);
 				sk->nr->n2count = 0;
 				nr_write_internal(sk, NR_DISCREQ);
 				sk->nr->t1timer = sk->nr->t1 = nr_calculate_t1(sk);
@@ -635,6 +662,7 @@
 {
 	struct sock *sk;
 	struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
+	struct device *dev;
 	ax25_address *user, *source;
 	
 	sk = (struct sock *)sock->data;
@@ -653,7 +681,7 @@
 	}
 #endif
 
-	if (nr_dev_get(&addr->fsa_ax25.sax25_call) == NULL) {
+	if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) {
 		if (sk->debug)
 			printk("NET/ROM: bind failed: invalid node callsign\n");
 		return -EADDRNOTAVAIL;
@@ -680,6 +708,7 @@
 		memcpy(&sk->nr->source_addr, source, sizeof(ax25_address));
 	}
 
+	sk->nr->device = dev;
 	nr_insert_socket(sk);
 
 	sk->zapped = 0;
@@ -999,6 +1028,9 @@
 
 	if (sk->zapped)
 		return -EADDRNOTAVAIL;
+
+	if (sk->nr->device == NULL)
+		return -ENETUNREACH;
 		
 	if (usax) {
 		if (addr_len < sizeof(sax))
@@ -1022,7 +1054,7 @@
 	if (sk->debug)
 		printk("NET/ROM: sendto: building packet.\n");
 
-	size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
+	size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 3 + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
 
 	if ((skb = sock_alloc_send_skb(sk, size, 0, &err)) == NULL)
 		return err;
@@ -1218,6 +1250,7 @@
 		case SIOCADDRT:
 		case SIOCDELRT:
 		case SIOCNRDECOBS:
+		case SIOCNRRTCTL:
 			if (!suser()) return -EPERM;
 			return nr_rt_ioctl(cmd, (void *)arg);
 
@@ -1254,22 +1287,29 @@
 int nr_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	struct sock *s;
+	struct device *dev;
+	char *devname;
 	int len = 0;
 	off_t pos = 0;
 	off_t begin = 0;
   
 	cli();
 
-	len += sprintf(buffer, "user_addr dest_node src_node    my  your  st vs vr va    t1     t2    n2  rtt wnd Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st vs vr va    t1     t2    n2  rtt wnd Snd-Q Rcv-Q\n");
 
 	for (s = nr_list; s != NULL; s = s->next) {
+		if ((dev = s->nr->device) == NULL)
+			devname = "???";
+		else
+			devname = dev->name;
+	
 		len += sprintf(buffer + len, "%-9s ",
 			ax2asc(&s->nr->user_addr));
 		len += sprintf(buffer + len, "%-9s ",
 			ax2asc(&s->nr->dest_addr));
-		len += sprintf(buffer + len, "%-9s %02X/%02X %02X/%02X %2d %2d %2d %2d %3d/%03d %2d/%02d %2d/%02d %3d %3d %5ld %5ld\n",
+		len += sprintf(buffer + len, "%-9s %-3s  %02X/%02X %02X/%02X %2d %2d %2d %2d %3d/%03d %2d/%02d %2d/%02d %3d %3d %5ld %5ld\n",
 			ax2asc(&s->nr->source_addr),
-			s->nr->my_index, s->nr->my_id,
+			devname, s->nr->my_index, s->nr->my_id,
 			s->nr->your_index, s->nr->your_id,
 			s->nr->state,
 			s->nr->vs, s->nr->vr, s->nr->va,
diff -u --recursive --new-file v1.3.13/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v1.3.13/linux/net/netrom/nr_dev.c	Fri Jul  7 08:54:57 1995
+++ linux/net/netrom/nr_dev.c	Thu Jul 27 19:36:17 1995
@@ -79,14 +79,14 @@
 	memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len);
 	buff[6] &= ~LAPB_C;
 	buff[6] &= ~LAPB_E;
-	buff[6] |= SSID_SPARE;
+	buff[6] |= SSSID_SPARE;
 	buff    += AX25_ADDR_LEN;
 
 	if (daddr != NULL)
 		memcpy(buff, daddr, dev->addr_len);
 	buff[6] &= ~LAPB_C;
 	buff[6] |= LAPB_E;
-	buff[6] |= SSID_SPARE;
+	buff[6] |= SSSID_SPARE;
 	buff    += AX25_ADDR_LEN;
 
 	*buff++ = nr_default.ttl;
@@ -119,12 +119,12 @@
 
 	bp[6] &= ~LAPB_C;
 	bp[6] &= ~LAPB_E;
-	bp[6] |= SSID_SPARE;
+	bp[6] |= SSSID_SPARE;
 	bp    += AX25_ADDR_LEN;
 	
 	bp[6] &= ~LAPB_C;
 	bp[6] |= LAPB_E;
-	bp[6] |= SSID_SPARE;
+	bp[6] |= SSSID_SPARE;
 
 	if (!nr_route_frame(skb, NULL)) {
 		skb->free = 1;
diff -u --recursive --new-file v1.3.13/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c
--- v1.3.13/linux/net/netrom/nr_in.c	Fri Jul  7 08:54:58 1995
+++ linux/net/netrom/nr_in.c	Thu Jul 27 19:36:17 1995
@@ -20,6 +20,7 @@
  *
  *	History
  *	NET/ROM 001	Jonathan(G4KLX)	Cloned from ax25_in.c
+ *	NET/ROM 003	Jonathan(G4KLX)	Added NET/ROM fragment reception.
  */
 
 #include <linux/config.h>
@@ -47,6 +48,40 @@
 #include <linux/interrupt.h>
 #include <net/netrom.h>
 
+static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+{
+	struct sk_buff *skbo, *skbn = skb;
+
+	if (more) {
+		sk->nr->fraglen += skb->len;
+		skb_queue_tail(&sk->nr->frag_queue, skb);
+		return 0;
+	}
+	
+	if (!more && sk->nr->fraglen > 0) {	/* End of fragment */
+		sk->nr->fraglen += skb->len;
+		skb_queue_tail(&sk->nr->frag_queue, skb);
+
+		if ((skbn = alloc_skb(sk->nr->fraglen, GFP_ATOMIC)) == NULL)
+			return 1;
+
+		skbn->free = 1;
+		skbn->arp  = 1;
+		skbn->sk   = sk;
+		sk->rmem_alloc += skb->truesize;
+			
+		while ((skbo = skb_dequeue(&sk->nr->frag_queue)) != NULL) {
+			memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+
+			kfree_skb(skbo, FREE_READ);
+		}
+
+		sk->nr->fraglen = 0;		
+	}
+
+	return sock_queue_rcv_skb(sk, skbn);
+}
+
 /*
  * State machine for state 1, Awaiting Connection State.
  * The handling of the timer(s) is in file nr_timer.c.
@@ -76,8 +111,8 @@
 				sk->state_change(sk);
 			break;
 
-		case NR_CONNACK + NR_CHOKE_FLAG:
-			nr_clear_tx_queue(sk);
+		case NR_CONNACK | NR_CHOKE_FLAG:
+			nr_clear_queues(sk);
 			sk->nr->state = NR_STATE_0;
 			sk->state     = TCP_CLOSE;
 			sk->err       = ECONNREFUSED;
@@ -153,7 +188,7 @@
 			break;
 
 		case NR_DISCREQ:
-			nr_clear_tx_queue(sk);
+			nr_clear_queues(sk);
 			nr_write_internal(sk, NR_DISCACK);
 			sk->nr->state = NR_STATE_0;
 			sk->state     = TCP_CLOSE;
@@ -164,7 +199,7 @@
 			break;
 
 		case NR_DISCACK:
-			nr_clear_tx_queue(sk);
+			nr_clear_queues(sk);
 			sk->nr->state = NR_STATE_0;
 			sk->state     = TCP_CLOSE;
 			sk->err       = ECONNRESET;
@@ -174,7 +209,7 @@
 			break;
 
 		case NR_INFOACK:
-		case NR_INFOACK + NR_CHOKE_FLAG:
+		case NR_INFOACK | NR_CHOKE_FLAG:
 			if (frametype & NR_CHOKE_FLAG) {
 				sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 				sk->nr->t4timer = nr_default.busy_delay;
@@ -194,8 +229,8 @@
 			}
 			break;
 			
-		case NR_INFOACK + NR_NAK_FLAG:
-		case NR_INFOACK + NR_NAK_FLAG + NR_CHOKE_FLAG:
+		case NR_INFOACK | NR_NAK_FLAG:
+		case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
 			if (frametype & NR_CHOKE_FLAG) {
 				sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 				sk->nr->t4timer = nr_default.busy_delay;
@@ -213,9 +248,9 @@
 			break;
 			
 		case NR_INFO:
-		case NR_INFO + NR_CHOKE_FLAG:
-		case NR_INFO + NR_MORE_FLAG:
-		case NR_INFO + NR_CHOKE_FLAG + NR_MORE_FLAG:
+		case NR_INFO | NR_CHOKE_FLAG:
+		case NR_INFO | NR_MORE_FLAG:
+		case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
 			if (frametype & NR_CHOKE_FLAG) {
 				sk->nr->condition |= PEER_RX_BUSY_CONDITION;
 				sk->nr->t4timer = nr_default.busy_delay;
@@ -243,7 +278,7 @@
 				while ((skbn = skb_dequeue(&sk->nr->reseq_queue)) != NULL) {
 					ns = skbn->data[2];
 					if (ns == sk->nr->vr) {
-						if (sock_queue_rcv_skb(sk, skbn) == 0) {
+						if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
 							sk->nr->vr = (sk->nr->vr + 1) % NR_MODULUS;
 						} else {
 							sk->nr->condition |= OWN_RX_BUSY_CONDITION;
diff -u --recursive --new-file v1.3.13/linux/net/netrom/nr_out.c linux/net/netrom/nr_out.c
--- v1.3.13/linux/net/netrom/nr_out.c	Fri Jul  7 08:54:58 1995
+++ linux/net/netrom/nr_out.c	Thu Jul 27 19:36:17 1995
@@ -14,6 +14,7 @@
  *
  *	History
  *	NET/ROM 001	Jonathan(G4KLX)	Cloned from ax25_out.c
+ *	NET/ROM 003	Jonathan(G4KLX)	Added NET/ROM fragmentation.
  */
 
 #include <linux/config.h>
@@ -40,19 +41,64 @@
 #include <linux/interrupt.h>
 #include <net/netrom.h>
 
-int nr_output(struct sock *sk, struct sk_buff *skb)
+/*
+ *	This is where all NET/ROM frames pass, except for IP-over-NET/ROM which
+ *	cannot be fragmented in this manner.
+ */
+void nr_output(struct sock *sk, struct sk_buff *skb)
 {
-	skb_queue_tail(&sk->write_queue, skb);	/* Throw it on the queue */
+	struct sk_buff *skbn;
+	unsigned char transport[NR_TRANSPORT_LEN];
+	int err, frontlen, len, mtu;
+
+	mtu = sk->nr->device->mtu;
+	
+	if (skb->len - NR_TRANSPORT_LEN > mtu) {
+		/* Save a copy of the Transport Header */
+		memcpy(transport, skb->data, NR_TRANSPORT_LEN);
+		skb_pull(skb, NR_TRANSPORT_LEN);
+
+		frontlen = skb_headroom(skb);
+
+		while (skb->len > 0) {
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + mtu, 0, &err)) == NULL)
+				return;
+
+			skbn->sk   = sk;
+			skbn->free = 1;
+			skbn->arp  = 1;
+
+			skb_reserve(skbn, frontlen);
+
+			len = (mtu > skb->len) ? skb->len : mtu;
+
+			/* Copy the user data */
+			memcpy(skb_put(skbn, len), skb->data, len);
+			skb_pull(skb, len);
+
+			/* Duplicate the Transport Header */
+			skb_push(skbn, NR_TRANSPORT_LEN);
+			memcpy(skbn->data, transport, NR_TRANSPORT_LEN);
+
+			if (skb->len > 0)
+				skbn->data[4] |= NR_MORE_FLAG;
+		
+			skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
+		}
+		
+		skb->free = 1;
+		kfree_skb(skb, FREE_WRITE);
+	} else {
+		skb_queue_tail(&sk->write_queue, skb);		/* Throw it on the queue */
+	}
 
 	if (sk->nr->state == NR_STATE_3)
 		nr_kick(sk);
-
-	return 0;
 }
 
 /* 
- *  This procedure is passed a buffer descriptor for an iframe. It builds
- *  the rest of the control part of the frame and then writes it out.
+ *	This procedure is passed a buffer descriptor for an iframe. It builds
+ *	the rest of the control part of the frame and then writes it out.
  */
 static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
 {
@@ -62,6 +108,9 @@
 	skb->data[2] = sk->nr->vs;
 	skb->data[3] = sk->nr->vr;
 
+	if (sk->nr->condition & OWN_RX_BUSY_CONDITION)
+		skb->data[4] |= NR_CHOKE_FLAG;
+
 	nr_transmit_buffer(sk, skb);	
 }
 
@@ -154,13 +203,13 @@
 	memcpy(dptr, &sk->nr->source_addr, sizeof(ax25_address));
 	dptr[6] &= ~LAPB_C;
 	dptr[6] &= ~LAPB_E;
-	dptr[6] |= SSID_SPARE;
+	dptr[6] |= SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
 
 	memcpy(dptr, &sk->nr->dest_addr,   sizeof(ax25_address));
 	dptr[6] &= ~LAPB_C;
 	dptr[6] |= LAPB_E;
-	dptr[6] |= SSID_SPARE;
+	dptr[6] |= SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
 
 	*dptr++ = nr_default.ttl;
@@ -207,10 +256,10 @@
 	int frametype = NR_INFOACK;
 	
 	if (sk->nr->condition & OWN_RX_BUSY_CONDITION) {
-		frametype += NR_CHOKE_FLAG;
+		frametype |= NR_CHOKE_FLAG;
 	} else {
 		if (skb_peek(&sk->nr->reseq_queue) != NULL) {
-			frametype += NR_NAK_FLAG;
+			frametype |= NR_NAK_FLAG;
 		}
 	}
 	
diff -u --recursive --new-file v1.3.13/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c
--- v1.3.13/linux/net/netrom/nr_route.c	Fri Jul  7 08:54:58 1995
+++ linux/net/netrom/nr_route.c	Thu Jul 27 19:36:17 1995
@@ -53,6 +53,7 @@
 #include <net/netrom.h>
 
 static int nr_neigh_no = 1;
+static int nr_route_on = 1;
 
 static struct nr_node  *nr_node_list  = NULL;
 static struct nr_neigh *nr_neigh_list = NULL;
@@ -564,6 +565,7 @@
 	struct nr_route_struct nr_route;
 	struct device *dev;
 	int err;
+	long opt = 0;
 
 	switch (cmd) {
 
@@ -606,6 +608,13 @@
 
 		case SIOCNRDECOBS:
 			return nr_dec_obs();
+			
+		case SIOCNRRTCTL:
+			if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0)
+				return err;
+			opt = get_fs_long((void *)arg);
+			nr_route_on = opt ? 1 : 0;
+			return 0;
 	}
 
 	return 0;
@@ -651,6 +660,9 @@
 
 	if ((dev = nr_dev_get(nr_dest)) != NULL)	/* Its for me */
 		return nr_rx_frame(skb, dev);
+
+	if (!nr_route_on && ax25 != NULL)
+		return 0;
 
 	/* Its Time-To-Live has expired */
 	if (--skb->data[14] == 0)
diff -u --recursive --new-file v1.3.13/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c
--- v1.3.13/linux/net/netrom/nr_subr.c	Fri Jul  7 08:54:58 1995
+++ linux/net/netrom/nr_subr.c	Thu Jul 27 19:36:17 1995
@@ -42,9 +42,9 @@
 #include <net/netrom.h>
 
 /*
- * This routine purges the input queue of frames.
+ *	This routine purges all of the queues of frames.
  */
-void nr_clear_tx_queue(struct sock *sk)
+void nr_clear_queues(struct sock *sk)
 {
 	struct sk_buff *skb;
 
@@ -61,7 +61,10 @@
 	}
 
 	while ((skb = skb_dequeue(&sk->nr->reseq_queue)) != NULL) {
-		skb->free = 1;
+		kfree_skb(skb, FREE_READ);
+	}
+
+	while ((skb = skb_dequeue(&sk->nr->frag_queue)) != NULL) {
 		kfree_skb(skb, FREE_READ);
 	}
 }
@@ -153,7 +156,7 @@
 	unsigned char  *dptr;
 	int len, timeout;
 
-	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
+	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 3 + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
 	
 	switch (frametype & 0x0F) {
 		case NR_CONNREQ:
@@ -194,12 +197,12 @@
 			memcpy(dptr, &sk->nr->user_addr, sizeof(ax25_address));
 			dptr[6] &= ~LAPB_C;
 			dptr[6] &= ~LAPB_E;
-			dptr[6] |= SSID_SPARE;
+			dptr[6] |= SSSID_SPARE;
 			dptr    += AX25_ADDR_LEN;
 			memcpy(dptr, &sk->nr->source_addr, sizeof(ax25_address));
 			dptr[6] &= ~LAPB_C;
 			dptr[6] &= ~LAPB_E;
-			dptr[6] |= SSID_SPARE;
+			dptr[6] |= SSSID_SPARE;
 			dptr    += AX25_ADDR_LEN;
 			*dptr++  = timeout % 256;
 			*dptr++  = timeout / 256;
@@ -248,7 +251,7 @@
 	unsigned char *dptr;
 	int len;
 
-	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1;
+	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 3 + NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1;
 
 	if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL)
 		return;
@@ -260,13 +263,13 @@
 	memcpy(dptr, skb->data + 7, AX25_ADDR_LEN);
 	dptr[6] &= ~LAPB_C;
 	dptr[6] &= ~LAPB_E;
-	dptr[6] |= SSID_SPARE;
+	dptr[6] |= SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
 	
 	memcpy(dptr, skb->data + 0, AX25_ADDR_LEN);
 	dptr[6] &= ~LAPB_C;
 	dptr[6] |= LAPB_E;
-	dptr[6] |= SSID_SPARE;
+	dptr[6] |= SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
 
 	*dptr++ = nr_default.ttl;
@@ -275,7 +278,7 @@
 	*dptr++ = skb->data[16];
 	*dptr++ = 0;
 	*dptr++ = 0;
-	*dptr++ = NR_CONNACK + NR_CHOKE_FLAG;
+	*dptr++ = NR_CONNACK | NR_CHOKE_FLAG;
 	*dptr++ = 0;
 
 	skbn->free = 1;
@@ -294,6 +297,8 @@
 	
 	for (t = 2, n = 0; n < sk->nr->n2count; n++)
 		t *= 2;
+
+	if (t > 8) t = 8;
 
 	return t * sk->nr->rtt;
 }
diff -u --recursive --new-file v1.3.13/linux/net/netrom/nr_timer.c linux/net/netrom/nr_timer.c
--- v1.3.13/linux/net/netrom/nr_timer.c	Fri Jun 30 16:22:34 1995
+++ linux/net/netrom/nr_timer.c	Mon Jul 31 09:46:27 1995
@@ -58,7 +58,7 @@
 	sk->timer.data     = (unsigned long)sk;
 	sk->timer.function = &nr_timer;
 
-	sk->timer.expires = 10;
+	sk->timer.expires = jiffies+10;
 	add_timer(&sk->timer);
 }
 
@@ -73,7 +73,7 @@
 
 	sk->timer.data     = (unsigned long)sk;
 	sk->timer.function = &nr_timer;
-	sk->timer.expires  = 10;
+	sk->timer.expires  = jiffies+10;
 	add_timer(&sk->timer);
 }
 
@@ -140,7 +140,7 @@
 	switch (sk->nr->state) {
 		case NR_STATE_1: 
 			if (sk->nr->n2count == sk->nr->n2) {
-				nr_clear_tx_queue(sk);
+				nr_clear_queues(sk);
 				sk->nr->state = NR_STATE_0;
 				sk->state     = TCP_CLOSE;
 				sk->err       = ETIMEDOUT;
@@ -155,7 +155,7 @@
 
 		case NR_STATE_2:
 			if (sk->nr->n2count == sk->nr->n2) {
-				nr_clear_tx_queue(sk);
+				nr_clear_queues(sk);
 				sk->nr->state = NR_STATE_0;
 				sk->state     = TCP_CLOSE;
 				sk->err       = ETIMEDOUT;
@@ -170,7 +170,7 @@
 
 		case NR_STATE_3:
 			if (sk->nr->n2count == sk->nr->n2) {
-				nr_clear_tx_queue(sk);
+				nr_clear_queues(sk);
 				sk->nr->state = NR_STATE_0;
 				sk->state     = TCP_CLOSE;
 				sk->err       = ETIMEDOUT;
