368 lines
9.8 KiB
C
368 lines
9.8 KiB
C
/*****************************************************************************
|
||
*
|
||
* COPYRIGHT 1993 - COLORADO MEMORY SYSTEMS, INC.
|
||
* ALL RIGHTS RESERVED.
|
||
*
|
||
******************************************************************************
|
||
*
|
||
* FILE: \SE\DRIVER\DEVICE\JUMBO\SRC\0X1103A.C
|
||
*
|
||
* FUNCTION: cqd_ClearInterrupt
|
||
*
|
||
* PURPOSE:
|
||
*
|
||
* HISTORY:
|
||
* $Log: J:\se.vcs\driver\q117cd\src\0x1103a.c $
|
||
*
|
||
* Rev 1.5 09 Feb 1995 12:33:06 kurtgodw
|
||
* final m8 fixes
|
||
*
|
||
* Rev 1.4 23 Feb 1994 17:16:12 KEVINKES
|
||
* Removed an unreferenced local variable.
|
||
*
|
||
* Rev 1.3 23 Feb 1994 15:41:06 KEVINKES
|
||
* Modified to return a status and to correct problems with
|
||
* leaving the FDC in an unknown state.
|
||
*
|
||
* Rev 1.2 11 Nov 1993 15:20:46 KEVINKES
|
||
* Changed calls to cqd_inp and cqd_outp to kdi_ReadPort and kdi_WritePort.
|
||
* Modified the parameters to these calls. Changed FDC commands to be
|
||
* defines.
|
||
*
|
||
* Rev 1.1 08 Nov 1993 14:05:30 KEVINKES
|
||
* Removed all bit-field structures, removed all enumerated types, changed
|
||
* all defines to uppercase, and removed all signed data types wherever
|
||
* possible.
|
||
*
|
||
* Rev 1.0 18 Oct 1993 17:19:30 KEVINKES
|
||
* Initial Revision.
|
||
*
|
||
*****************************************************************************/
|
||
#define FCT_ID 0x1103a
|
||
#include "include\public\adi_api.h"
|
||
#include "include\public\frb_api.h"
|
||
#include "include\private\kdi_pub.h"
|
||
#include "include\private\cqd_pub.h"
|
||
#include "q117cd\include\cqd_defs.h"
|
||
#include "q117cd\include\cqd_strc.h"
|
||
#include "q117cd\include\cqd_hdr.h"
|
||
/*endinclude*/
|
||
|
||
dStatus cqd_ClearInterrupt
|
||
(
|
||
/* INPUT PARAMETERS: */
|
||
|
||
|
||
dVoidPtr context,
|
||
dBoolean expected_interrupt
|
||
|
||
/* UPDATE PARAMETERS: */
|
||
|
||
/* OUTPUT PARAMETERS: */
|
||
|
||
)
|
||
/* COMMENTS: *****************************************************************
|
||
*
|
||
* DEFINITIONS: *************************************************************/
|
||
{
|
||
|
||
/* DATA: ********************************************************************/
|
||
|
||
dStatus status=DONT_PANIC; /* dStatus or error condition.*/
|
||
dUDWord i;
|
||
CqdContextPtr cqd_context;
|
||
dUByte reset_byte;
|
||
|
||
/* CODE: ********************************************************************/
|
||
|
||
cqd_context = (CqdContextPtr)context;
|
||
|
||
if ( cqd_context->controller_data.command_has_result_phase ) {
|
||
|
||
//
|
||
// Result phase of previous command. (Note that we can't trust
|
||
// the CMD_BUSY bit in the status register to tell us whether
|
||
// there's result bytes or not; it's sometimes wrong).
|
||
// By reading the first result byte, we reset the interrupt.
|
||
// The other result bytes will be read by a thread.
|
||
//
|
||
|
||
if ( ( kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.msr )
|
||
& (MSR_RQM | MSR_DIO) ) == (MSR_RQM | MSR_DIO) ) {
|
||
|
||
cqd_context->controller_data.fifo_byte =
|
||
kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dr );
|
||
#if DBG
|
||
DBG_ADD_ENTRY(QIC117SHOWMCMDS, (CqdContextPtr)cqd_context, DBG_FIFO_FDC);
|
||
DBG_ADD_ENTRY(QIC117SHOWMCMDS, (CqdContextPtr)cqd_context, cqd_context->controller_data.fifo_byte);
|
||
#endif
|
||
|
||
|
||
} else {
|
||
|
||
status = kdi_Error(ERR_CONTROLLER_STATE_ERROR, FCT_ID, ERR_SEQ_1);
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Previous command doesn't have a result phase. To read how it
|
||
// completed, issue a sense interrupt command. Don't read
|
||
// the result bytes from the sense interrupt; that is the
|
||
// responsibility of the calling thread.
|
||
//
|
||
|
||
i = FDC_MSR_RETRIES;
|
||
|
||
do {
|
||
|
||
if ((kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.msr) &
|
||
(MSR_RQM | MSR_DIO)) == MSR_RQM) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
kdi_ShortTimer( kdi_wt12us );
|
||
|
||
} while (--i > 0);
|
||
|
||
if (i != 0) {
|
||
#if DBG
|
||
DBG_ADD_ENTRY(QIC117SHOWMCMDS, (CqdContextPtr)cqd_context, DBG_PGM_FDC);
|
||
DBG_ADD_ENTRY(QIC117SHOWMCMDS, (CqdContextPtr)cqd_context, FDC_CMD_SENSE_INT);
|
||
#endif
|
||
|
||
|
||
kdi_WritePort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dr,
|
||
FDC_CMD_SENSE_INT );
|
||
|
||
kdi_ShortTimer( kdi_wt12us );
|
||
|
||
//
|
||
// Wait for the controller to ACK the SenseInterrupt command, by
|
||
// showing busy. On very fast machines we can end up running
|
||
// driver's system-thread before the controller has had time to
|
||
// set the busy bit.
|
||
//
|
||
|
||
for (i = FDC_MSR_RETRIES; i; i--) {
|
||
|
||
if (kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.msr) & MSR_CB) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
kdi_ShortTimer( kdi_wt12us );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (i == 0) {
|
||
|
||
status = kdi_Error(ERR_CONTROLLER_STATE_ERROR, FCT_ID, ERR_SEQ_1);
|
||
|
||
}
|
||
|
||
|
||
/* Code no longer valid - Kurt G. - due to ISR sharing
|
||
if (!expected_interrupt && (status == DONT_PANIC)) {
|
||
|
||
//
|
||
// This is an unexpected interrupt, so nobody's going to
|
||
// read the result bytes. Read them now.
|
||
//
|
||
|
||
cqd_context->controller_data.fifo_byte =
|
||
kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dr );
|
||
|
||
cqd_context->controller_data.fifo_byte =
|
||
kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dr );
|
||
|
||
|
||
}
|
||
End of no longer functioning code */
|
||
|
||
|
||
}
|
||
|
||
/* Code no longer functioning - Kurt G. - Due to ISR sharing
|
||
if (status == DONT_PANIC) {
|
||
|
||
cqd_context->controller_data.isr_reentered = 0;
|
||
|
||
} else {
|
||
|
||
|
||
* Running the floppy (at least on R4000 boxes) we've seen
|
||
* examples where the device interrupts, yet it never says
|
||
* it *ISN'T* busy. If this ever happens on non-MCA x86 boxes
|
||
* it would be ok since we use latched interrupts. Even if
|
||
* the device isn't touched so that the line would be pulled
|
||
* down, on the latched machine, this ISR wouldn't be called
|
||
* again. The normal timeout code for a request would eventually
|
||
* reset the controller and retry the request.
|
||
*
|
||
* On the R4000 boxes and on MCA machines, the floppy is using
|
||
* level sensitive interrupts. Therefore if we don't do something
|
||
* to lower the interrupt line, we will be called over and over,
|
||
* *forever*. This makes it look as though the machine is hung.
|
||
* Unless we were lucky enough to be on a multiprocessor, the
|
||
* normal timeout code would NEVER get a chance to run because
|
||
* the timeout code runs at dispatch level, and we will never
|
||
* leave device level.
|
||
*
|
||
* What we will do is keep a counter that is incremented every
|
||
* time we reach this section of code. When the counter goes
|
||
* over the threshold we will do a hard reset of the device
|
||
* and reset the counter down to zero. The counter will be
|
||
* initialized when the device is first initialized. It will
|
||
* be set to zero in the other arm of this if, and it will be
|
||
* reset to zero by the normal timeout logic.
|
||
|
||
|
||
if (cqd_context->controller_data.isr_reentered > FDC_ISR_RESET_THRESHOLD) {
|
||
|
||
//
|
||
// Reset the controller. This could cause an interrupt
|
||
//
|
||
|
||
cqd_context->controller_data.isr_reentered = 0;
|
||
|
||
if (!cqd_context->configured) {
|
||
|
||
cqd_context->selected = dFALSE;
|
||
|
||
kdi_WritePort( cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dor,
|
||
alloff);
|
||
|
||
kdi_ShortTimer(kdi_wt10us);
|
||
|
||
kdi_WritePort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dor,
|
||
dselb);
|
||
|
||
} else {
|
||
|
||
if (cqd_context->selected == dTRUE) {
|
||
|
||
reset_byte =
|
||
cqd_context->device_cfg.select_byte;
|
||
|
||
} else {
|
||
|
||
reset_byte =
|
||
cqd_context->device_cfg.deselect_byte;
|
||
|
||
}
|
||
|
||
reset_byte &= 0xfb;
|
||
|
||
kdi_WritePort( cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dor,
|
||
reset_byte);
|
||
|
||
kdi_ShortTimer(kdi_wt10us);
|
||
reset_byte |= 0x0c;
|
||
kdi_WritePort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dor,
|
||
reset_byte);
|
||
|
||
}
|
||
|
||
|
||
kdi_ShortTimer(kdi_wt500us);
|
||
|
||
i = FDC_MSR_RETRIES;
|
||
|
||
do {
|
||
|
||
if ((kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.msr) &
|
||
(MSR_RQM | MSR_DIO)) == MSR_RQM) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
kdi_ShortTimer( kdi_wt12us );
|
||
|
||
} while (--i > 0);
|
||
|
||
if (i != 0) {
|
||
|
||
kdi_WritePort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dr,
|
||
FDC_CMD_SENSE_INT );
|
||
|
||
kdi_ShortTimer( kdi_wt12us );
|
||
|
||
// Wait for the controller to ACK the SenseInterrupt command, by
|
||
// showing busy. On very fast machines we can end up running
|
||
// driver's system-thread before the controller has had time to
|
||
// set the busy bit.
|
||
|
||
for (i = FDC_MSR_RETRIES; i; i--) {
|
||
|
||
if (kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.msr) & MSR_CB) {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
kdi_ShortTimer( kdi_wt12us );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
cqd_context->controller_data.fifo_byte =
|
||
kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dr );
|
||
|
||
cqd_context->controller_data.fifo_byte =
|
||
kdi_ReadPort(
|
||
cqd_context->kdi_context,
|
||
cqd_context->controller_data.fdc_addr.dr );
|
||
|
||
// Let the interrupt settle
|
||
|
||
kdi_ShortTimer( kdi_wt12us );
|
||
|
||
} else {
|
||
|
||
cqd_context->controller_data.isr_reentered++;
|
||
|
||
}
|
||
|
||
}
|
||
End of Non functioning code */
|
||
|
||
return status;
|
||
}
|