[comp.os.minix] PS/2 MCA test changes..

ackerman@kira.uvm.edu (Steve Ackerman) (05/24/89)

	Here is some code that needs testing on PS/2's.  Dr. Tanenbaum
sent it to me a few months ago, and Al Crew and I tested it.  It appeared
to work on PS/2's model 50's and 60's, but not on 70's and 80's.  

	The main problem with PS/2 MCA models is interrupt handling.
On the PS/2 interrupts are level triggered, and the line remains on
until the device is recognized.  As long as the line is high, the 8259A
will cause the CPU to jump to an interrupt handler routine.  What
happens is the disk interrupts the CPU when done with an operation;
the interrupt handler is called, and it re--enables the 8259A, and then
attempts to send a message to the Floppy Driver.  However, the line is
still high.  This causes another interrupt to be declared, thus
invoking the device driver's interrupt handler, which re--enables the
8259A, and then attempts to send a message to the Floppy Disk Driver,
and it loops forever.

	The solution to this problem is to have the 8259A ignore the
device interrupt until the device driver is certain that the interrupt
line is off.  For the Floppy disk, the interrupt is turned off by simply
reading from the controller, so after this is done (in floppy.c), it's
safe to allow the 8259A to catch interrupts from the floppy disk
controller.  

	Dr. Tanenbaum added the reenable() function in proc.c.   This
will reenable an interrupt level given the appropriate bit (0x40 for
the floppy).  When a floppy interrupt occurs, it's caught by disk_int
in mpx88.s.  At this point, disk_int turns off the interrupt level,
calls interrupt(), etc, etc..

	Anyways, there's the problem.  I set aside some time to work on
this last week, and this is what I came up with: 

     1)  I believe that there is a timing difference between the
         PS/2 Models 50's & 60's and the 70's & 80's due to the
         386 chip.  Meaning, that by the time the 8259A is told to
         accept a disk interrupt, the floppy controller has lowered
	 the line.  However, since the 70's & 80's are faster, the
         floppy controller doesn't have enough time to lower the line
         before the 8259A accepts the disk interrupt, and you get into
         the loop that was stated before.

     2)  Not being a hardware guru (as yet, still learning ;-) ), the
         only evidence I have to support (1) is the fact that by
         moving the reenable() call down a line or two, the code works
         (on my model 80 at least).

So, could someone please take this code and try it out on other PS/2s (ie.
50, 60 70, 55, or whatever new models are coming out..)?  The diffs
are (I think) in relation to 1.3d, and the floppy.c contains Al Crew's
changes for 1.44 MB. 

For a hard disk driver, I've been using bios_wini.c since at first try,
the other two drivers didn't work.  That problem, however, may be as 
simple as the patches to floppy.c (i.e., shutting of the line and then
turning it back on at a later date) or as difficult as rewriting the entire
driver.  Haven't taken a look at this yet, maybe tonight.  MINIX seems to
work best with pc_at TRUE and ps FALSE on my machine, and I think the code
is correct for setting the flags in main.c.   Hopefully, this patch should
run both on a PC and a PS/2, but haven't tried it yet on a PC.  I
haven't had time to install Bruce's protected mode code yet, so don't know
if these changes will work in it.  Hopefully, I'll look at it sometime soon.

I appreciate any input you can give me!  Thanks in advance.

Steve

------------------------------cut here------------------------------
echo x - floppy.c.cdif
sed '/^X/s///' > floppy.c.cdif << '/'
X*** floppy.c.orig	Mon May 22 13:47:57 1989
X--- floppy.c	Tue May 23 01:08:14 1989
X***************
X*** 16,21 ****
X--- 16,24 ----
X   *
X   *  Changes:
X   *	27 october 1986 by Jakob Schripsema: fdc_results fixed for 8 MHz
X+  *	28 Nov. 1986 by Peter Kay: better resetting for 386
X+  *	06 Jan. 1988 by Al Crew: allow 1.44 MB diskettes
X+  *	26 Jan. 1989 by Dr. Tanenbaum & Steve Ackerman: fix for PS/2 interrupts
X   */
X  
X  #include "../h/const.h"
X***************
X*** 39,44 ****
X--- 42,48 ----
X  #define DMA_M2         0x00C	/* DMA status port */
X  #define DMA_M1         0x00B	/* DMA status port */
X  #define DMA_INIT       0x00A	/* DMA init port */
X+ #define DMA_RESET_VAL  0x006    /* DMA Reset Value */
X  
X  /* Status registers returned as result of operation. */
X  #define ST0             0x00	/* status register 0 */
X***************
X*** 82,91 ****
X  
X  /* Parameters for the disk drive. */
X  #define SECTOR_SIZE      512	/* physical sector size in bytes */
X! #define HC_SIZE         2400	/* # sectors on a high-capacity (1.2M) disk */
X  #define NR_HEADS        0x02	/* two heads (i.e., two tracks/cylinder) */
X  #define DTL             0xFF	/* determines data length (sector size) */
X- #define SPEC1           0xDF	/* first parameter to SPECIFY */
X  #define SPEC2           0x02	/* second parameter to SPECIFY */
X  
X  #define MOTOR_OFF       3*HZ	/* how long to wait before stopping motor */
X--- 86,94 ----
X  
X  /* Parameters for the disk drive. */
X  #define SECTOR_SIZE      512	/* physical sector size in bytes */
X! #define HC_SIZE         2880	/* # sectors on largest legal disk (1.44 MB) */
X  #define NR_HEADS        0x02	/* two heads (i.e., two tracks/cylinder) */
X  #define DTL             0xFF	/* determines data length (sector size) */
X  #define SPEC2           0x02	/* second parameter to SPECIFY */
X  
X  #define MOTOR_OFF       3*HZ	/* how long to wait before stopping motor */
X***************
X*** 105,111 ****
X  #define NR_DRIVES          2	/* maximum number of drives */
X  #define DIVISOR          128	/* used for sector size encoding */
X  #define MAX_FDC_RETRY    100	/* max # times to try to output to FDC */
X! #define NT                 6	/* number of diskette/drive combinations */
X  
X  /* Variables. */
X  PRIVATE struct floppy {		/* main drive struct, one entry per drive */
X--- 108,118 ----
X  #define NR_DRIVES          2	/* maximum number of drives */
X  #define DIVISOR          128	/* used for sector size encoding */
X  #define MAX_FDC_RETRY    100	/* max # times to try to output to FDC */
X! #define NT                 7	/* number of diskette/drive combinations */
X! #define AUTOMATIC	0x3F	/* bit map allowing both 3.5 and 5.25 disks */
X! #define THREE_INCH	0x48	/* bit map allowing only 3.5 inch diskettes */
X! #define FIVE_INCH	0x37	/* bit map allowing only 5.25 inch diskettes */
X! #define FLOPPY_BIT      0x40	/* 8259A bit corresponding to floppy intr */
X  
X  /* Variables. */
X  PRIVATE struct floppy {		/* main drive struct, one entry per drive */
X***************
X*** 120,126 ****
X    vir_bytes fl_address;		/* user virtual address */
X    char fl_results[MAX_RESULTS];	/* the controller can give lots of output */
X    char fl_calibration;		/* CALIBRATED or UNCALIBRATED */
X!   char fl_density;		/* 0 = 360K/360K; 1 = 360K/1.2M; 2= 1.2M/1.2M*/
X  } floppy[NR_DRIVES];
X  
X  #define UNCALIBRATED       0	/* drive needs to be calibrated at next use */
X--- 127,133 ----
X    vir_bytes fl_address;		/* user virtual address */
X    char fl_results[MAX_RESULTS];	/* the controller can give lots of output */
X    char fl_calibration;		/* CALIBRATED or UNCALIBRATED */
X!   char fl_density;		/* 0 = 360K/360K; 1 = 360K/1.2M; etc. */
X  } floppy[NR_DRIVES];
X  
X  #define UNCALIBRATED       0	/* drive needs to be calibrated at next use */
X***************
X*** 132,144 ****
X  PRIVATE int need_reset;		/* set to 1 when controller must be reset */
X  PRIVATE int initialized;	/* set to 1 after first successful transfer */
X  PRIVATE int d;			/* diskette/drive combination */
X  
X  PRIVATE message mess;		/* message buffer for in and out */
X  
X  PRIVATE char len[] = {-1,0,1,-1,2,-1,-1,3,-1,-1,-1,-1,-1,-1,-1,4};
X! PRIVATE char interleave[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
X  
X! /* Six combinations of diskette/drive are supported:
X   * # Drive  diskette  Sectors  Tracks  Rotation Data-rate  Comment
X   * 0  360K    360K      9       40     300 RPM  250 kbps   Standard PC DSDD
X   * 1  1.2M    1.2M     15       80     360 RPM  500 kbps   AT disk in AT drive
X--- 139,152 ----
X  PRIVATE int need_reset;		/* set to 1 when controller must be reset */
X  PRIVATE int initialized;	/* set to 1 after first successful transfer */
X  PRIVATE int d;			/* diskette/drive combination */
X+ PRIVATE int current_spec1;	/* latest spec1 sent to the controller */
X  
X  PRIVATE message mess;		/* message buffer for in and out */
X  
X  PRIVATE char len[] = {-1,0,1,-1,2,-1,-1,3,-1,-1,-1,-1,-1,-1,-1,4};
X! PRIVATE char interleave[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18};
X  
X! /* Seven combinations of diskette/drive are supported:
X   * # Drive  diskette  Sectors  Tracks  Rotation Data-rate  Comment
X   * 0  360K    360K      9       40     300 RPM  250 kbps   Standard PC DSDD
X   * 1  1.2M    1.2M     15       80     360 RPM  500 kbps   AT disk in AT drive
X***************
X*** 146,165 ****
X   * 3  720K    720K      9       80     300 RPM  250 kbps   Toshiba, et al.
X   * 4  1.2M    360K      9       40     360 RPM  300 kbps   PC disk in AT drive
X   * 5  1.2M    720K      9       80     360 RPM  300 kbps   Toshiba in AT drive
X   */
X  PRIVATE int gap[NT] =
X! 	{0x2A, 0x1B, 0x2A, 0x2A, 0x23, 0x23}; /* gap size */
X  PRIVATE int rate[NT] = 
X! 	{0x02, 0x00, 0x02, 0x02, 0x01, 0x01}; /* 250,300,500 kbps*/
X  PRIVATE int nr_sectors[NT] = 
X! 	{9,    15,   9,    9,    9,    9};   /* sectors/track */
X  PRIVATE int nr_blocks[NT] = 
X! 	{720,  2400, 720,  1440, 720,  1440}; /* sectors/diskette*/
X  PRIVATE int steps_per_cyl[NT] = 
X! 	{1,    1,    2,    1,    2,    1};   /* 2 = dbl step */
X  PRIVATE int mtr_setup[NT] = 
X! 	{HZ/4,3*HZ/4,HZ/4,2*HZ/4,3*HZ/4,3*HZ/4};/* in ticks */
X  
X  /*===========================================================================*
X   *				floppy_task				     * 
X   *===========================================================================*/
X--- 154,201 ----
X   * 3  720K    720K      9       80     300 RPM  250 kbps   Toshiba, et al.
X   * 4  1.2M    360K      9       40     360 RPM  300 kbps   PC disk in AT drive
X   * 5  1.2M    720K      9       80     360 RPM  300 kbps   Toshiba in AT drive
X+  * 6  1.44M   1.44M    18       80     360 RPM  500 kbps   IBM PS/2, et al.
X+  *
X+  * In addition, 720K diskettes can be read in 1.44MB drives, but that does 
X+  * not need a different set of parameters.  This combination uses
X+  *
X+  * X  1.44M   720K	9	80     300 RPM  250 kbps   PS/2, et al.
X   */
X  PRIVATE int gap[NT] =
X! 	{0x2A, 0x1B, 0x2A, 0x2A, 0x23, 0x23, 0x1B}; /* gap size */
X  PRIVATE int rate[NT] = 
X! 	{0x02, 0x00, 0x02, 0x02, 0x01, 0x01, 0x00}; /* 2=250,1=300,0=500 kbps*/
X  PRIVATE int nr_sectors[NT] = 
X! 	{9,    15,   9,    9,    9,    9,    18};   /* sectors/track */
X  PRIVATE int nr_blocks[NT] = 
X! 	{720,  2400, 720,  1440, 720,  1440, 2880}; /* sectors/diskette*/
X  PRIVATE int steps_per_cyl[NT] = 
X! 	{1,    1,    2,    1,    2,    1,    1};   /* 2 = dbl step */
X  PRIVATE int mtr_setup[NT] = 
X! 	{HZ/4,3*HZ/4,HZ/4,2*HZ/4,3*HZ/4,3*HZ/4,HZ/4};/* in ticks */
X! PRIVATE char spec1[NT] =
X! 	{0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xAF}; /* step rate, etc. */
X  
X+ /* This driver hunts around for the proper density by simply trying them all
X+  * until it finds one that works.  By defining DEFAULT_CLASS, one can reduce 
X+  * the searching to only 5.25 inch or only 3.5 inch types.  The array
X+  * drive_class contains a bit map for each drive, telling which of the NT
X+  * combinations defined above should be tried.
X+  */
X+ PRIVATE char drive_class[NR_DRIVES] = {
X+ #ifndef DEFAULT_CLASS
X+ 	AUTOMATIC, AUTOMATIC		/* both drives can handle both types */
X+ #else
X+ #	if	(DEFAULT_CLASS==3)
X+ 		THREE_INCH, THREE_INCH	/* drive 0 = 3.5 inch, drive 1 also */
X+ #	endif
X+ 
X+ #	if	(DEFAULT_CLASS==5)
X+ 		FIVE_INCH, FIVE_INCH	/* drive 0 = 5.25 inch, drive 1 also */
X+ #	endif
X+ #endif
X+ };
X+ 
X  /*===========================================================================*
X   *				floppy_task				     * 
X   *===========================================================================*/
X***************
X*** 175,180 ****
X--- 211,217 ----
X    while (TRUE) {
X  	/* First wait for a request to read or write a disk block. */
X  	receive(ANY, &mess);	/* get a request to do some work */
X+         if (mess.m_source == -1) { port_out(INT_CTLMASK, 0x0); continue;}
X  	if (mess.m_source < 0)
X  		panic("disk task got message from ", mess.m_source);
X  	caller = mess.m_source;
X***************
X*** 217,222 ****
X--- 254,265 ----
X    block = m_ptr->POSITION/SECTOR_SIZE;
X    if (block >= HC_SIZE) return(EOF);	/* sector is beyond end of 1.2M disk */
X    d = fp->fl_density;		/* diskette/drive combination */
X+ 
X+   /* Check the bit map to see if this density is allowed.  If not, skip it. */
X+   while ((drive_class[drive] & (1 << d)) == 0) d = (d + 1) % NT;
X+ 
X+   /* Store the message parameters in the fp->fl array. */
X+   fp->fl_density=d;
X    fp->fl_cylinder = (int) (block / (NR_HEADS * nr_sectors[d]));
X    fp->fl_sector = (int) interleave[(int)(block % nr_sectors[d])];
X    fp->fl_head = (int) (block % (NR_HEADS*nr_sectors[d]) )/nr_sectors[d];
X***************
X*** 236,242 ****
X  	 */
X  	errors++;		/* increment count once per loop cycle */
X   	if (errors % (MAX_ERRORS/NT) == 0) {
X!  		d = (d + 1) % NT;	/* try next density */
X   		fp->fl_density = d;
X  		sectors = nr_sectors[d];
X  		fp->fl_cylinder = (int) (block / (NR_HEADS * sectors));
X--- 279,289 ----
X  	 */
X  	errors++;		/* increment count once per loop cycle */
X   	if (errors % (MAX_ERRORS/NT) == 0) {
X!                 d++;
X! 
X! 		/* Check bit map to skip illegal densities. */
X! 		while ((drive_class[drive] & (1 << d)) == 0) d = (d + 1) % NT;
X! 
X   		fp->fl_density = d;
X  		sectors = nr_sectors[d];
X  		fp->fl_cylinder = (int) (block / (NR_HEADS * sectors));
X***************
X*** 249,254 ****
X--- 296,311 ----
X  	/* First check to see if a reset is needed. */
X  	if (need_reset) reset();
X  
X+ 	/* Set the stepping rate */
X+ 	if (current_spec1 != spec1[d]) {
X+ 		fdc_out(FDC_SPECIFY);
X+ 		fdc_out(current_spec1=spec1[d]);
X+ 		fdc_out(SPEC2);
X+ 	}
X+ 
X+  	/* Set the data rate */
X+ 	if (pc_at) port_out(FDC_RATE, rate[d]);
X+ 
X  	/* Now set up the DMA chip. */
X  	dma_setup(fp);
X  
X***************
X*** 259,266 ****
X--- 316,325 ----
X  	r = seek(fp);
X  	if (r != OK) continue;	/* if error, try again */
X  
X+ 
X  	/* Perform the transfer. */
X  	r = transfer(fp);
X+ 
X  	if (r == OK) break;	/* if successful, exit loop */
X  	if (r == ERR_WR_PROTECT) break;	/* retries won't help */
X    }
X***************
X*** 286,292 ****
X   * 512-byte block starting at physical address 65520).
X   */
X  
X!   int mode, low_addr, high_addr, top_addr, low_ct, high_ct, top_end, s;
X    vir_bytes vir, ct;
X    phys_bytes user_phys;
X    extern phys_bytes umap();
X--- 345,351 ----
X   * 512-byte block starting at physical address 65520).
X   */
X  
X!   int mode, low_addr, high_addr, top_addr, low_ct, high_ct, top_end, s, valu;
X    vir_bytes vir, ct;
X    phys_bytes user_phys;
X    extern phys_bytes umap();
X***************
X*** 312,317 ****
X--- 371,378 ----
X  
X    /* Now set up the DMA registers. */
X    s = lock();
X+   port_out(DMA_INIT, DMA_RESET_VAL);        /* reset the dma controller */
X+ 
X    port_out(DMA_M2, mode);	/* set the DMA mode */
X    port_out(DMA_M1, mode);	/* set it again */
X    port_out(DMA_ADDR, low_addr);	/* output low-order 8 bits */
X***************
X*** 388,394 ****
X   * positioned on the correct cylinder.
X   */
X  
X!   int r, send_mess();
X  
X    /* Are we already on the correct cylinder? */
X    if (fp->fl_calibration == UNCALIBRATED)
X--- 449,455 ----
X   * positioned on the correct cylinder.
X   */
X  
X!   int r, s, send_mess();
X  
X    /* Are we already on the correct cylinder? */
X    if (fp->fl_calibration == UNCALIBRATED)
X***************
X*** 405,416 ****
X    /* Interrupt has been received.  Check drive status. */
X    fdc_out(FDC_SENSE);		/* probe FDC to make it return status */
X    r = fdc_results(fp);		/* get controller status bytes */
X    if ( (fp->fl_results[ST0] & ST0_BITS) != SEEK_ST0) r = ERR_SEEK;
X    if (fp->fl_results[ST1] != fp->fl_cylinder * steps_per_cyl[d]) r = ERR_SEEK;
X    if (r != OK) 
X  	if (recalibrate(fp) != OK) return(ERR_SEEK);
X    fp->fl_curcyl = (r == OK ? fp->fl_cylinder : -1);
X!   if (r == OK && ps) {		/* give head time to settle on PS/2 */
X  	clock_mess(2, send_mess);
X  	receive(CLOCK, &mess);
X    }
X--- 466,478 ----
X    /* Interrupt has been received.  Check drive status. */
X    fdc_out(FDC_SENSE);		/* probe FDC to make it return status */
X    r = fdc_results(fp);		/* get controller status bytes */
X+   reenable(FLOPPY_BIT);         /* reset 8259A Interrupt */
X    if ( (fp->fl_results[ST0] & ST0_BITS) != SEEK_ST0) r = ERR_SEEK;
X    if (fp->fl_results[ST1] != fp->fl_cylinder * steps_per_cyl[d]) r = ERR_SEEK;
X    if (r != OK) 
X  	if (recalibrate(fp) != OK) return(ERR_SEEK);
X    fp->fl_curcyl = (r == OK ? fp->fl_cylinder : -1);
X!   if (r == OK && ps && ((d == 6) || (d == 3))) {/* give head time to settle on PS/2 */
X  	clock_mess(2, send_mess);
X  	receive(CLOCK, &mess);
X    }
X***************
X*** 454,460 ****
X  
X    /* Get controller status and check for errors. */
X    r = fdc_results(fp);
X!   if (r != OK) return(r);
X    if ( (fp->fl_results[ST1] & BAD_SECTOR) || (fp->fl_results[ST2] & BAD_CYL) )
X  	fp->fl_calibration = UNCALIBRATED;
X    if (fp->fl_results[ST1] & WRITE_PROTECT) {
X--- 516,526 ----
X  
X    /* Get controller status and check for errors. */
X    r = fdc_results(fp);
X!   if (r != OK) {
X!         reenable(FLOPPY_BIT); 
X!         return(r);
X!   }
X!   reenable(FLOPPY_BIT);
X    if ( (fp->fl_results[ST1] & BAD_SECTOR) || (fp->fl_results[ST2] & BAD_CYL) )
X  	fp->fl_calibration = UNCALIBRATED;
X    if (fp->fl_results[ST1] & WRITE_PROTECT) {
X***************
X*** 476,488 ****
X  /*===========================================================================*
X   *				fdc_results				     * 
X   *===========================================================================*/
X! PRIVATE int fdc_results(fp)
X  register struct floppy *fp;	/* pointer to the drive struct */
X  {
X  /* Extract results from the controller after an operation. */
X  
X    int i, j, k, status, ready;
X  
X    /* Loop, extracting bytes from FDC until it says it has no more. */
X    for (i = 0; i < MAX_RESULTS; i++) {
X  	ready = FALSE;
X--- 542,556 ----
X  /*===========================================================================*
X   *				fdc_results				     * 
X   *===========================================================================*/
X! int fdc_results(fp)
X  register struct floppy *fp;	/* pointer to the drive struct */
X  {
X  /* Extract results from the controller after an operation. */
X  
X    int i, j, k, status, ready;
X+   message  junk_mess; 
X  
X+ 
X    /* Loop, extracting bytes from FDC until it says it has no more. */
X    for (i = 0; i < MAX_RESULTS; i++) {
X  	ready = FALSE;
X***************
X*** 494,499 ****
X--- 562,570 ----
X  			break;
X  		}
X  	}
X+ 
X+         for (k = 0; k < 32; k++) ;
X+ 
X  	if (ready == FALSE) return(ERR_STATUS);	/* time out */
X  
X  	if ((status & CTL_BUSY) == 0) return(OK);
X***************
X*** 511,517 ****
X  /*===========================================================================*
X   *				fdc_out					     * 
X   *===========================================================================*/
X! PRIVATE fdc_out(val)
X  int val;			/* write this byte to floppy disk controller */
X  {
X  /* Output a byte to the controller.  This is not entirely trivial, since you
X--- 582,588 ----
X  /*===========================================================================*
X   *				fdc_out					     * 
X   *===========================================================================*/
X! int fdc_out(val)
X  int val;			/* write this byte to floppy disk controller */
X  {
X  /* Output a byte to the controller.  This is not entirely trivial, since you
X***************
X*** 553,560 ****
X   * into sync with reality.
X   */
X  
X!   int r;
X    /* Issue the RECALIBRATE command and wait for the interrupt. */
X    start_motor(fp);		/* can't recalibrate with motor off */
X    fdc_out(FDC_RECALIBRATE);	/* tell drive to recalibrate itself */
X    fdc_out(fp->fl_drive);	/* specify drive */
X--- 624,632 ----
X   * into sync with reality.
X   */
X  
X!   int r, s;
X    /* Issue the RECALIBRATE command and wait for the interrupt. */
X+ 
X    start_motor(fp);		/* can't recalibrate with motor off */
X    fdc_out(FDC_RECALIBRATE);	/* tell drive to recalibrate itself */
X    fdc_out(fp->fl_drive);	/* specify drive */
X***************
X*** 565,570 ****
X--- 637,643 ----
X    fdc_out(FDC_SENSE);		/* issue SENSE command to see where we are */
X    r = fdc_results(fp);		/* get results of the SENSE command */
X    fp->fl_curcyl = -1;		/* force a SEEK next time */
X+   reenable(FLOPPY_BIT);
X    if (r != OK ||		/* controller would not respond */
X       (fp->fl_results[ST0]&ST0_BITS) != SEEK_ST0 || fp->fl_results[ST_PCN] !=0){
X  	/* Recalibration failed.  FDC must be reset. */
X***************
X*** 574,580 ****
X    } else {
X  	/* Recalibration succeeded. */
X  	fp->fl_calibration = CALIBRATED;
X! 	if (ps) {		/* give head time to settle on PS/2 */
X  		clock_mess(2, send_mess);
X  		receive(CLOCK, &mess);
X  	}
X--- 647,653 ----
X    } else {
X  	/* Recalibration succeeded. */
X  	fp->fl_calibration = CALIBRATED;
X! 	if (ps || ((d == 6) || (d == 3))) {/* give head time to settle on PS/2 */
X  		clock_mess(2, send_mess);
X  		receive(CLOCK, &mess);
X  	}
X***************
X*** 592,598 ****
X   * like the controller refusing to respond.
X   */
X  
X!   int i, r, status, old_state;
X    register struct floppy *fp;
X  
X    /* Disable interrupts and strobe reset bit low. */
X--- 665,671 ----
X   * like the controller refusing to respond.
X   */
X  
X!   int i, r, status, old_state, s;
X    register struct floppy *fp;
X  
X    /* Disable interrupts and strobe reset bit low. */
X***************
X*** 610,623 ****
X    fp->fl_results[0] = 0;	/* this byte will be checked shortly */
X    fdc_out(FDC_SENSE);		/* did it work? */
X    r = fdc_results(fp);		/* get results */
X    status = fp->fl_results[0] & BYTE;
X  
X    /* Tell FDC drive parameters. */
X    fdc_out(FDC_SPECIFY);		/* specify some timing parameters */
X!   fdc_out(SPEC1);		/* step-rate and head-unload-time */
X    fdc_out(SPEC2);		/* head-load-time and non-dma */
X- 
X-   for (i = 0; i < NR_DRIVES; i++) floppy[i].fl_calibration = UNCALIBRATED;
X  }
X  
X  
X--- 683,695 ----
X    fp->fl_results[0] = 0;	/* this byte will be checked shortly */
X    fdc_out(FDC_SENSE);		/* did it work? */
X    r = fdc_results(fp);		/* get results */
X+   reenable(FLOPPY_BIT);
X    status = fp->fl_results[0] & BYTE;
X  
X    /* Tell FDC drive parameters. */
X    fdc_out(FDC_SPECIFY);		/* specify some timing parameters */
X!   fdc_out(current_spec1=spec1[d]); /* step-rate and head-unload-time */
X    fdc_out(SPEC2);		/* head-load-time and non-dma */
X  }
X  
X  
X***************
X*** 647,649 ****
X--- 719,722 ----
X  
X    send(FLOPPY, &mess);
X  }
X+ 
/
echo x - main.c.cdif
sed '/^X/s///' > main.c.cdif << '/'
X*** main.c.orig	Mon May 22 13:47:58 1989
X--- main.c	Mon May 22 13:47:58 1989
X***************
X*** 27,34 ****
X  #define SIZES              8	/* sizes array has 8 entries */
X  #define CPU_TY1       0xFFFF	/* BIOS segment that tells CPU type */
X  #define CPU_TY2       0x000E	/* BIOS offset that tells CPU type */
X! #define PC_AT           0xFC	/* IBM code for PC-AT (in BIOS at 0xFFFFE) */
X! #define PS              0xFA	/* IBM code for PS/2  (in BIOS at 0xFFFFE) */
X  #define EM_VEC          0x15	/* vector for extended memory BIOS calls */
X  #define CMASK1          0x00	/* interrupt mask: ptr, dsk, keybd, clk, PIC */
X  #define CMASK2          0xBF	/* interrupt mask for secondary PIC */
X--- 27,36 ----
X  #define SIZES              8	/* sizes array has 8 entries */
X  #define CPU_TY1       0xFFFF	/* BIOS segment that tells CPU type */
X  #define CPU_TY2       0x000E	/* BIOS offset that tells CPU type */
X! #define CPU_TY3       0x000F	/* BIOS offset that give subtype */
X! #define PC_AT           0xFC	/* IBM code for PC-AT & PS/2 model 50, 60 */
X! #define PS30            0xFA	/* IBM code for PS/2 Model 30 */
X! #define PS80            0xF8	/* IBM code for PS/2 Model 80 */
X  #define EM_VEC          0x15	/* vector for extended memory BIOS calls */
X  #define CMASK1          0x00	/* interrupt mask: ptr, dsk, keybd, clk, PIC */
X  #define CMASK2          0xBF	/* interrupt mask for secondary PIC */
X***************
X*** 42,47 ****
X--- 44,50 ----
X  int (*int_vec[HIGH_INT])() = {int00, int01, int02, int03, int04, int05, int06,
X      int07, int08, int09, int10, int11, int12, int13, int14, int15};     
X  
X+ PUBLIC int vec_table[VECTOR_BYTES/2];
X  
X  /*===========================================================================*
X   *                                   main                                    * 
X***************
X*** 59,65 ****
X    int	stack_size;
X    int * ktsb;			/* kernel task stack base */
X    extern unsigned sizes[8];	/* table filled in by build */
X!   extern int port_65, ega, color, vec_table[], get_chrome();
X    extern int s_call(), disk_int(), tty_int(), clock_int(), disk_int();
X    extern int wini_int(), lpr_int(), trp(), rs232_int(), secondary_int();
X    extern phys_bytes umap();
X--- 62,68 ----
X    int	stack_size;
X    int * ktsb;			/* kernel task stack base */
X    extern unsigned sizes[8];	/* table filled in by build */
X!   extern int port_65, ega, color, get_chrome();
X    extern int s_call(), disk_int(), tty_int(), clock_int(), disk_int();
X    extern int wini_int(), lpr_int(), trp(), rs232_int(), secondary_int();
X    extern phys_bytes umap();
X***************
X*** 144,162 ****
X    /* Determine if display is color or monochrome and CPU type (from BIOS). */
X    color = get_chrome();		/* 0 = mono, 1 = color */
X    ega = get_ega();
X!   t = (int)get_byte(CPU_TY1, CPU_TY2) & 0xFF;	/* is this PC, XT, AT ... ? */
X!   if (t == PC_AT) pc_at = TRUE;
X!   else if (t == PS) ps = TRUE;
X  
X    /* Save the old interrupt vectors. */
X    phys_b = umap(proc_addr(HARDWARE), D, (vir_bytes) vec_table, VECTOR_BYTES);
X    phys_copy(0L, phys_b, (long) VECTOR_BYTES);	/* save all the vectors */
X-   if (ps) save_tty_vec();	/* save tty vector 0x71 for reboot() */
X  
X!   /* Set up the new interrupt vectors. */
X    for (t = 0; t < HIGH_INT; t++) set_vec(t, int_vec[t], base_click);
X!   for (t = HIGH_INT; t < 256; t++) set_vec(t, trp, base_click);
X  
X    set_vec(SYS_VECTOR, s_call, base_click);
X    set_vec(CLOCK_VECTOR, clock_int, base_click);
X    set_vec(KEYBOARD_VECTOR, tty_int, base_click);
X--- 147,168 ----
X    /* Determine if display is color or monochrome and CPU type (from BIOS). */
X    color = get_chrome();		/* 0 = mono, 1 = color */
X    ega = get_ega();
X!   t = (int) get_byte(CPU_TY1, CPU_TY2) & 0xFF;	/* is this PC, XT, AT ... ? */
X!   i = (int) get_byte(CPU_TY1, CPU_TY3) & 0xFF;	/*  i = subtype */
X!   if (t == PS30) ps = TRUE;
X!   if (t == PC_AT || t == PS80) {
X! 	pc_at = TRUE;
X!   }
X  
X    /* Save the old interrupt vectors. */
X    phys_b = umap(proc_addr(HARDWARE), D, (vir_bytes) vec_table, VECTOR_BYTES);
X    phys_copy(0L, phys_b, (long) VECTOR_BYTES);	/* save all the vectors */
X  
X!   /* Overwrite unused vectors.  The holes in this list are needed by the BIOS*/
X    for (t = 0; t < HIGH_INT; t++) set_vec(t, int_vec[t], base_click);
X!   for (t = 16; t < 256; t++) set_vec(t, trp, base_click);
X  
X+   /* Set up the new interrupt vectors. */
X    set_vec(SYS_VECTOR, s_call, base_click);
X    set_vec(CLOCK_VECTOR, clock_int, base_click);
X    set_vec(KEYBOARD_VECTOR, tty_int, base_click);
X***************
X*** 164,177 ****
X    set_vec(RS232_VECTOR, rs232_int, base_click);
X    set_vec(FLOPPY_VECTOR, disk_int, base_click);
X    set_vec(PRINTER_VECTOR, lpr_int, base_click);
X  #ifdef AM_KERNEL
X  #ifndef NONET
X    set_vec(ETHER_VECTOR, eth_int, base_click);	/* overwrites RS232 port 2 */
X  #endif
X  #endif
X    if (pc_at) {
X  	set_vec(AT_WINI_VECTOR, wini_int, base_click);
X! 	phys_copy(phys_b + 4L*EM_VEC, 4L*EM_VEC, 4L);	/* extended mem vec */
X    } else
X  	set_vec(XT_WINI_VECTOR, wini_int, base_click);
X  
X--- 170,186 ----
X    set_vec(RS232_VECTOR, rs232_int, base_click);
X    set_vec(FLOPPY_VECTOR, disk_int, base_click);
X    set_vec(PRINTER_VECTOR, lpr_int, base_click);
X+ 
X+ 
X  #ifdef AM_KERNEL
X  #ifndef NONET
X    set_vec(ETHER_VECTOR, eth_int, base_click);	/* overwrites RS232 port 2 */
X  #endif
X  #endif
X+ 
X    if (pc_at) {
X  	set_vec(AT_WINI_VECTOR, wini_int, base_click);
X! 	phys_copy(phys_b + 4L*EM_VEC, 4L*EM_VEC, 4L);
X    } else
X  	set_vec(XT_WINI_VECTOR, wini_int, base_click);
X  
X***************
X*** 261,267 ****
X  /*===========================================================================*
X   *                                   set_vec                                 * 
X   *===========================================================================*/
X! PRIVATE set_vec(vec_nr, addr, base_click)
X  int vec_nr;			/* which vector */
X  int (*addr)();			/* where to start */
X  phys_clicks base_click;		/* click where kernel sits in memory */
X--- 270,276 ----
X  /*===========================================================================*
X   *                                   set_vec                                 * 
X   *===========================================================================*/
X! PUBLIC set_vec(vec_nr, addr, base_click)
X  int vec_nr;			/* which vector */
X  int (*addr)();			/* where to start */
X  phys_clicks base_click;		/* click where kernel sits in memory */
X***************
X*** 295,297 ****
X--- 304,308 ----
X  PUBLIC eth_stp() {}			/* stop the ethernet upon reboot */
X  PUBLIC dp8390_int(){}			/* Ethernet interrupt */
X  #endif
X+ 
X+ 
/
echo x - mpx88.s.cdif
sed '/^X/s///' > mpx88.s.cdif << '/'
X*** mpx88.s.orig	Mon May 22 13:48:00 1989
X--- mpx88.s	Mon May 22 13:47:59 1989
X***************
X*** 30,35 ****
X--- 30,39 ----
X  DISKINT		=    1
X  CLOCK_TICK	=    2
X  
X+ INT_MASK	= 0x21		| I/O port for the 8259A mask register
X+ FLOP_BIT	= 0x40		| 8259A mask bit for floppy disk
X+ PRINT_BIT       = 0x80          | 8259A mask bit for parallel port
X+ 
X  | The following procedures are defined in this file and called from outside it.
X  .globl _tty_int, _rs232_int, _lpr_int, _clock_int, _disk_int, _wini_int
X  .globl _eth_int, _s_call, _trp, _restart, _secondary_int
X***************
X*** 128,133 ****
X--- 132,141 ----
X  |*===========================================================================*
X  _lpr_int:			| Interrupt routine for terminal input.
X  	call save		| save the machine state
X+         mov  dx,#INT_MASK       | point to 8259 control reg
X+         in                      | get value 
X+         or   ax,#PRINT_BIT      | mask off parallel port-shutting of interrupt
X+         out                     | send value back to 8259 chip
X  	call _pr_char		| process a line printer interrupt
X  	jmp _restart		| continue execution
X  
X***************
X*** 137,142 ****
X--- 145,154 ----
X  |*===========================================================================*
X  _disk_int:			| Interrupt routine for the floppy disk.
X  	call save		| save the machine state
X+ 	mov dx,#INT_MASK	| INT_MASK = 8259A mask register
X+ 	in			| ax = 8259A interrupt mask
X+ 	or ax,#FLOP_BIT		| disable floppy disk
X+ 	out			| reload 8259A interrupt mask
X  	mov _int_mess+2,*DISKINT| build message for disk task
X  	mov ax,#_int_mess	| prepare to call interrupt(FLOPPY, &intmess)
X  	push ax			| push second parameter
X***************
X*** 361,363 ****
X--- 373,377 ----
X  ttyomess: .asciz "RS232 interrupt"
X  .bss
X  begbss:
X+ 
X+ 
/
echo x - printer.c.cdif
sed '/^X/s///' > printer.c.cdif << '/'
X*** printer.c.orig	Mon May 22 13:48:01 1989
X--- printer.c	Mon May 22 13:48:01 1989
X***************
X*** 47,52 ****
X--- 47,53 ----
X  #define DELAY_LOOP      1000	/* delay when printer is busy */
X  #define MAX_REP         1000	/* controls max delay when busy */
X  #define STATUS_MASK	0xB0	/* mask to filter out status bits */ 
X+ #define PRINT_BIT	0x80	/* mask for 8259 chip */
X  
X  PRIVATE int port_base;		/* I/O port for printer: 0x 378 or 0x3BC */
X  PRIVATE int caller;		/* process to tell when printing done (FS) */
X***************
X*** 221,230 ****
X  {
X  /* Color display uses 0x378 for printer; mono display uses 0x3BC. */
X  
X!   int i;
X    extern int color;
X  
X!   port_base = (color ? PR_COLOR_BASE : PR_MONO_BASE);
X    pr_busy = FALSE;
X    port_out(port_base + 2, INIT_PRINTER);
X    for (i = 0; i < DELAY_COUNT; i++) ;	/* delay loop */
X--- 222,234 ----
X  {
X  /* Color display uses 0x378 for printer; mono display uses 0x3BC. */
X  
X!   int i = 0, testval = 0xAA;
X    extern int color;
X  
X!   /* See if PR_COLOR_BASE installed by writing to it and reading it back. */
X!   port_out(PR_COLOR_BASE, testval);	/* output random bit pattern */
X!   port_in(PR_COLOR_BASE, &i);		/* read it back */
X!   port_base = (i == testval ? PR_COLOR_BASE : PR_MONO_BASE);
X    pr_busy = FALSE;
X    port_out(port_base + 2, INIT_PRINTER);
X    for (i = 0; i < DELAY_COUNT; i++) ;	/* delay loop */
X***************
X*** 233,239 ****
X  
X  
X  /*===========================================================================*
X!  *				pr_char				     *
X   *===========================================================================*/
X  PUBLIC pr_char()
X  {
X--- 237,243 ----
X  
X  
X  /*===========================================================================*
X!  *				pr_char					     *
X   *===========================================================================*/
X  PUBLIC pr_char()
X  {
X***************
X*** 263,269 ****
X--- 267,275 ----
X  		pcount--;
X  		cum_count++;	/* count characters output */
X  		for (i = 0; i < DELAY_COUNT; i++) ;	/* delay loop */
X+                 reenable(PRINT_BIT);  /* reenable print interrupt */
X  	} else if ((value&STATUS_MASK) == BUSY_STATUS) {
X+                         reenable(PRINT_BIT);  /* reenable print interrupt */
X  		 	return;		/* printer is busy; wait for interrupt*/
X  	} else {
X  		 	break;		/* err: send message to printer task */
X***************
X*** 273,279 ****
X--- 279,288 ----
X  /* Count is 0 or an error occurred; send message to printer task. */
X    int_mess.m_type = TTY_O_DONE;
X    int_mess.REP_STATUS = (pcount == 0 ? OK : value);
X+   reenable(PRINT_BIT);  /* reenable print interrupt -- needed for MCA */
X    interrupt(PRINTER, &int_mess);
X  }
X+ 
X+ 
X  
X  
/
echo x - proc.c.cdif
sed '/^X/s///' > proc.c.cdif << '/'
X*** proc.c.orig	Mon May 22 13:48:03 1989
X--- proc.c	Mon May 22 13:48:02 1989
X***************
X*** 383,385 ****
X--- 383,407 ----
X    pick_proc();
X    restore(old_state);			/* restore interrupts to prev state */
X  }
X+ 
X+ 
X+ /*===========================================================================*
X+  *				reenable				     * 
X+  *===========================================================================*/
X+ PUBLIC reenable(bit)
X+ int bit;			/* singleton bit map to OR into 8259A mask */
X+ {
X+ /* This procedure is called to re-enable the 8259A by sending it an EOI code.
X+  * This is done shortly after an interrupt has been received.  At the time of
X+  * the interrupt, the 8259A mask register is changed to disable the interupt.
X+  * Here it is turned back on.  Note: 0 is enabled, 1 is disabled.
X+  */
X+ 
X+   int r;
X+ 
X+   port_in(INT_CTLMASK, &r);	/* get the current 8259A mask value */
X+   r = r & ~bit;			/* clear this bit to enable the interrupt */
X+   port_out(INT_CTLMASK, r);	/* install the new mask */
X+ }
X+ 
X+ 
/




	
--
============================================================================
Steven Ackerman, Systems Programmer      |  EMBA-CF University of Vermont    
uunet!uvm-gen!ackerman                   |  Burlington, Vermont 05401 
Internet: ackerman@uvm.edu               |  Telephone: (802) 879-0371