From: Frank T Lofaro <fl0p+@andrew.cmu.edu>
Subject: ALPHA PATCH (for 0.98.6 kernel) for floppy disk enhancements/bug fixes.
Originator: mdw@db.TC.Cornell.EDU
Keywords: 0.98.6, patch, kernel, floppy, disk, enhancements, fixes, 82077
Organization: Cornell Theory Center
Date: Sat, 12 Dec 1992 22:25:55 GMT

	This patch is against linux 0.98 patchlevel 6. (It *should* work with
other versions that are reasonably close). This enables and fixes the
enhanced mode support for 82077 type floppy disk controllers, and also
configures the floppy controller right after bootup, which might help
with possible initialization problems (the floppy.c file states
something about being unable to format floppies right after bootup. I
haven't had that problem myself though, so I can not say any more about
that.)
	Anyway, this patch is mostly for those that have an enhanced floppy
disk controller (the kernel reports FDC version 0x90 at bootup), and
those that want to get as much performance out of their system as
possible. But it shouldn't cause trouble for others, and might actually
be helpful. (plus if it breaks anything for anyone, it would be good to
know that.) I have tested all this code myself, and it seems to work for
me. You may or may not need the #define FDC_FIFO_HACK. (I don't know why
my machine needs it, or whether it is normal, or whether the hack is the
best way to solve the problem, but without it, my kernel gets stuck in
an infinite try to send byte, reset controller loop). You can also try
changing the FDC_RATE_CONTROL #define to 0x00 if this patch doesn't work
for you, or to 0x43 if you want to up the speed (but it might not work
at that setting, sync before using the floppy, since the kernel might
get stuck).
	Sorry I can not provide more info, but my only docs are the kernel
sources. I am posting this just to comp.os.linux.announce (to the
moderator), until it is approved, in which case I'll then post it to
comp.os.linux. I have to do it this way, since crossposting is a bit
weird here, i.e. crossposting to both a moderated and unmoderated group
doesn't work like expected, it seems. I know this is suboptimal, but if
I try to crosspost, it will go to comp.os.linux even before being
approved my the comp.os.linux.announce moderators. Sigh. That's what we
get for having a *very* custom news setup here. 	Anyway, here is the
patch , to be applied to the root of your kernel source directory.
(usually /usr/src/linux).

*** kernel/blk_drv/floppy.c.orig	Sun Nov 29 22:41:34 1992
--- kernel/blk_drv/floppy.c	Sat Dec 12 03:01:47 1992
***************
*** 53,65 ****
   * modelled after the freeware MS/DOS program fdformat/88 V1.8 by 
   * Christoph H. Hochst\"atter.
   * I have fixed the shift values to the ones I always use. Maybe a new
   * ioctl() should be created to be able to modify them.
!  * There is a bug in the driver that makes it impossible to format a
   * floppy as the first thing after bootup.
   */
  
  #define REALLY_SLOW_IO
  #define FLOPPY_IRQ 6
  #define FLOPPY_DMA 2
  
  #include <linux/sched.h>
--- 53,73 ----
   * modelled after the freeware MS/DOS program fdformat/88 V1.8 by 
   * Christoph H. Hochst\"atter.
   * I have fixed the shift values to the ones I always use. Maybe a new
   * ioctl() should be created to be able to modify them.
!  * There might be a bug in the driver that makes it impossible to format a
   * floppy as the first thing after bootup.
   */
  
  #define REALLY_SLOW_IO
+ #define FDC_FIFO_EXPERIMENTAL
+ #define FDC_RATE_CONTROL 0x40 /* bit 6: 1=perpendicular mode enabled, 
+                                  0=disabled. 0x00 is conventional mode, 
+                                  0x40 is perpendicular 500 kbps, 
+                                  0x43 is perpendicular 1 Mpbs. */
+ #define FDC_FIFO_HACK /* This might not be needed for everyone, but without 
+                          it on some machines it can not send bytes to
the FDC 
+                          if using enhanced modes. */
  #define FLOPPY_IRQ 6
  #define FLOPPY_DMA 2
  
  #include <linux/sched.h>
***************
*** 406,413 ****
--- 414,442 ----
  	reset = 1;
  	printk("Unable to send byte to FDC\n");
  }
  
+ #ifdef FDC_FIFO_HACK
+ static void output_byte_force(char byte)
+ {
+         int counter;
+         unsigned char status;
+ 
+         if (reset)
+                 return;
+         for(counter = 0 ; counter < 10000 ; counter++) {
+                 status = inb_p(FD_STATUS) & (STATUS_READY);
+                 if (status == STATUS_READY) {
+                         outb(byte,FD_DATA);
+                         return;
+                 }
+         }
+         current_track = NO_TRACK;
+         reset = 1;
+         printk("Unable to send byte to FDC\n");
+ }
+ #endif
+ 
  static int result(void)
  {
  	int i = 0, counter, status;
  
***************
*** 456,464 ****
  }	
  
  
  /* Set perpendicular mode as required, based on data rate, if supported.
!  * 82077 Untested! 1Mbps data rate only possible with 82077-1.
   * TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
   */
  static inline void perpendicular_mode(unsigned char rate)
  {
--- 485,493 ----
  }	
  
  
  /* Set perpendicular mode as required, based on data rate, if supported.
!  * 82077 Not well tested! 1Mbps data rate only possible with 82077-1.
   * TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
   */
  static inline void perpendicular_mode(unsigned char rate)
  {
***************
*** 465,482 ****
  	if (fdc_version == FDC_TYPE_82077) {
  		output_byte(FD_PERPENDICULAR);
  		if (rate & 0x40) {
  			unsigned char r = rate & 0x03;
! 			if (r == 0)
  				output_byte(2);	/* perpendicular, 500 kbps */
! 			else if (r == 3)
  				output_byte(3);	/* perpendicular, 1Mbps */
  			else {
  				printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
  				reset = 1;
  			}
! 		} else
  			output_byte(0);		/* conventional mode */
  	} else {
  		if (rate & 0x40) {
  			printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n");
  			reset = 1;
--- 494,534 ----
  	if (fdc_version == FDC_TYPE_82077) {
  		output_byte(FD_PERPENDICULAR);
  		if (rate & 0x40) {
  			unsigned char r = rate & 0x03;
! 			if (r == 0) {
! 			        if (need_configure) 
! 				        printk("floppy: perpendicular mode, 500 Kbps enabled.\n");
! #ifndef FDC_FIFO_HACK
  				output_byte(2);	/* perpendicular, 500 kbps */
! #else
! 				output_byte_force(2); /* perpendicular, 500 
!                                                          kbps */
! #endif
! 			      }
! 			else if (r == 3) {
! 			        if (need_configure)
! 			                printk("floppy: perpendicular mode, 1 Mbps enabled.\n");
! #ifndef FDC_FIFO_HACK
  				output_byte(3);	/* perpendicular, 1Mbps */
+ #else
+ 				output_byte_force(3); /* perpendicular, 
+                                                          1Mbps */
+ #endif
+ 			      }
  			else {
  				printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
  				reset = 1;
  			}
! 	} else {
! 		        if (need_configure)
! 		                printk("floppy: conventional mode for 82077 FDC
selected.\n");
! #ifndef FDC_FIFO_HACK
  			output_byte(0);		/* conventional mode */
+ #else
+ 			output_byte_force(0); /* conventional mode */
+ #endif
+ 		      }
  	} else {
  		if (rate & 0x40) {
  			printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n");
  			reset = 1;
***************
*** 485,506 ****
  } /* perpendicular_mode */
  
  
  /*
!  * This has only been tested for the case fdc_version == FDC_TYPE_STD.
   * In case you have a 82077 and want to test it, you'll have to compile
!  * with `FDC_FIFO_UNTESTED' defined. You may also want to add support for
   * recognizing drives with vertical recording support.
   */
  static void configure_fdc_mode(void)
  {
  	if (need_configure && (fdc_version == FDC_TYPE_82077)) {
  		/* Enhanced version with FIFO & vertical recording. */
  		output_byte(FD_CONFIGURE);
  		output_byte(0);
  		output_byte(0x1A);	/* FIFO on, polling off, 10 byte threshold */
  		output_byte(0);		/* precompensation from track 0 upwards */
! 		need_configure = 0;
  		printk(DEVICE_NAME ": FIFO enabled\n");
  	}
  	if (cur_spec1 != floppy->spec1) {
  		cur_spec1 = floppy->spec1;
--- 537,566 ----
  } /* perpendicular_mode */
  
  
  /*
!  * This has only been well tested for the case fdc_version == FDC_TYPE_STD.
   * In case you have a 82077 and want to test it, you'll have to compile
!  * with `FDC_FIFO_EXPERIMENTAL' defined. You may also want to add support for
   * recognizing drives with vertical recording support.
   */
  static void configure_fdc_mode(void)
  {
  	if (need_configure && (fdc_version == FDC_TYPE_82077)) {
  		/* Enhanced version with FIFO & vertical recording. */
  		output_byte(FD_CONFIGURE);
+ #ifndef FDC_FIFO_HACK
  		output_byte(0);
+ #else
+ 		output_byte_force(0);
+ #endif
  		output_byte(0x1A);	/* FIFO on, polling off, 10 byte threshold */
+ #ifndef FDC_FIFO_HACK
  		output_byte(0);		/* precompensation from track 0 upwards */
! #else
! 		output_byte_force(0);	/* precompensation from track 0 
!                                            upwards */
! #endif
  		printk(DEVICE_NAME ": FIFO enabled\n");
  	}
  	if (cur_spec1 != floppy->spec1) {
  		cur_spec1 = floppy->spec1;
***************
*** 509,518 ****
--- 569,582 ----
  		output_byte(6);			/* Head load time =6ms, DMA */
  	}
  	if (cur_rate != floppy->rate) {
  		/* use bit 6 of floppy->rate to indicate perpendicular mode */
+ #ifdef FDC_FIFO_EXPERIMENTAL
+ 	        floppy->rate=FDC_RATE_CONTROL;
+ #endif
  		perpendicular_mode(floppy->rate);
  		outb_p((cur_rate = (floppy->rate)) & ~0x40, FD_DCR);
+ 		need_configure = 0;
  	}
  } /* configure_fdc_mode */
  
  
***************
*** 1273,1283 ****
  		printk(DEVICE_NAME ": FDC failed to return version byte\n");
  		fdc_version = FDC_TYPE_STD;
  	} else
  		fdc_version = reply_buffer[0];
! 	if (fdc_version != FDC_TYPE_STD) 
  		printk(DEVICE_NAME ": FDC version 0x%x\n", fdc_version);
! #ifndef FDC_FIFO_UNTESTED
  	fdc_version = FDC_TYPE_STD;	/* force std fdc type; can't test other. */
  #endif
  
  	/* Not all FDCs seem to be able to handle the version command
--- 1337,1349 ----
  		printk(DEVICE_NAME ": FDC failed to return version byte\n");
  		fdc_version = FDC_TYPE_STD;
  	} else
  		fdc_version = reply_buffer[0];
! 	if (fdc_version == FDC_TYPE_82077)
! 	        printk(DEVICE_NAME ": FDC version 0x%x (82077 Enhanced
FDC)\n", fdc_version);
! 	if ((fdc_version != FDC_TYPE_STD) && (fdc_version != FDC_TYPE_82077)) 
  		printk(DEVICE_NAME ": FDC version 0x%x\n", fdc_version);
! #ifndef FDC_FIFO_EXPERIMENTAL
  	fdc_version = FDC_TYPE_STD;	/* force std fdc type; can't test other. */
  #endif
  
  	/* Not all FDCs seem to be able to handle the version command
***************
*** 1288,1292 ****
--- 1354,1360 ----
  	if (fdc_version == FDC_TYPE_STD) {
  		initial_reset_flag = 1;
  		reset_floppy();
  	}
+ 	configure_fdc_mode(); /* It is a good idea to take care of this now, 
+                                  82077 FDC or not. */
  }

--
Send submissions for comp.os.linux.announce to: linux-announce@tc.cornell.edu
Newsgroups: comp.os.linux.announce,comp.os.linux