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