764 lines
17 KiB
C
764 lines
17 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
Copyright (c) 1992, 1993 Digital Equipment Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
eisasup.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
The module provides the EISA bus support for Alpha systems.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jeff Havens (jhavens) 19-Jun-1991
|
|||
|
Miche Baker-Harvey (miche) 13-May-1992
|
|||
|
Jeff McLeman (DEC) 1-Jun-1992
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
11-Mar-1993 Joe Mitchell (DEC)
|
|||
|
Added support for NMI interrupts: Added interrupt service routine
|
|||
|
HalHandleNMI. Added code to HalpCreateEisaStructures to initialize
|
|||
|
NMI interrupts.
|
|||
|
|
|||
|
22-Jul-1992 Jeff McLeman (mcleman)
|
|||
|
Removed eisa xfer routines, since this is done in JXHWSUP
|
|||
|
|
|||
|
02-Jul-92 Jeff McLeman (mcleman)
|
|||
|
Removed alphadma.h header file. This file was not needed since
|
|||
|
the DMA structure is described in the eisa header. Also add
|
|||
|
a note describing eisa references in this module.
|
|||
|
|
|||
|
13-May-92 Stole file jxebsup.c and converted for Alpha/Jensen
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "halp.h"
|
|||
|
#include "eisa.h"
|
|||
|
|
|||
|
//
|
|||
|
// Define the context structure for use by the interrupt routine.
|
|||
|
//
|
|||
|
|
|||
|
typedef BOOLEAN (*PSECONDARY_DISPATCH)(
|
|||
|
PVOID InterruptRoutine,
|
|||
|
PKTRAP_FRAME TrapFrame
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Declare the interupt structure and spinlock for the intermediate EISA
|
|||
|
// interrupt dispachter.
|
|||
|
//
|
|||
|
|
|||
|
KINTERRUPT HalpEisaInterrupt;
|
|||
|
|
|||
|
/* [jrm 3/8/93] Add support for NMI interrupts */
|
|||
|
|
|||
|
//
|
|||
|
// The following is the interrupt object used for DMA controller interrupts.
|
|||
|
// DMA controller interrupts occur when a memory parity error occurs or a
|
|||
|
// programming error occurs to the DMA controller.
|
|||
|
//
|
|||
|
|
|||
|
KINTERRUPT HalpEisaNmiInterrupt;
|
|||
|
|
|||
|
UCHAR EisaNMIMsg[] = "NMI: Eisa IOCHKERR board x\n";
|
|||
|
|
|||
|
//
|
|||
|
// The following function is called when an EISA NMI occurs.
|
|||
|
//
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalHandleNMI(
|
|||
|
IN PKINTERRUPT Interrupt,
|
|||
|
IN PVOID ServiceContext
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Define save area for EISA interrupt mask registers and level\edge control
|
|||
|
// registers.
|
|||
|
//
|
|||
|
|
|||
|
UCHAR HalpEisaInterrupt1Mask;
|
|||
|
UCHAR HalpEisaInterrupt2Mask;
|
|||
|
UCHAR HalpEisaInterrupt1Level;
|
|||
|
UCHAR HalpEisaInterrupt2Level;
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalpInitializeEisaInterrupts (
|
|||
|
//HalpCreateEisaStructures (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine initializes the structures necessary for EISA operations
|
|||
|
and connects the intermediate interrupt dispatcher. It also initializes the
|
|||
|
EISA interrupt controller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If the second level interrupt dispatcher is connected, then a value of
|
|||
|
TRUE is returned. Otherwise, a value of FALSE is returned.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
UCHAR DataByte;
|
|||
|
KIRQL oldIrql;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the EISA NMI interrupt.
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeInterrupt( &HalpEisaNmiInterrupt,
|
|||
|
HalHandleNMI,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
EISA_NMI_VECTOR,
|
|||
|
EISA_NMI_LEVEL,
|
|||
|
EISA_NMI_LEVEL,
|
|||
|
LevelSensitive,
|
|||
|
FALSE,
|
|||
|
0,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Don't fail if the interrupt cannot be connected.
|
|||
|
//
|
|||
|
|
|||
|
KeConnectInterrupt( &HalpEisaNmiInterrupt );
|
|||
|
|
|||
|
//
|
|||
|
// Clear the Eisa NMI disable bit. This bit is the high order of the
|
|||
|
// NMI enable register.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = 0;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Enable Software-Generated NMI interrupts by setting bit 1 of port 0x461.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = 0x02;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the EISA interrupt dispatcher for EISA I/O interrupts.
|
|||
|
//
|
|||
|
|
|||
|
KeInitializeInterrupt( &HalpEisaInterrupt,
|
|||
|
HalpEisaInterruptHandler,
|
|||
|
(PVOID) HalpEisaIntAckBase,
|
|||
|
(PKSPIN_LOCK)NULL,
|
|||
|
PIC_VECTOR,
|
|||
|
EISA_DEVICE_LEVEL,
|
|||
|
EISA_DEVICE_LEVEL,
|
|||
|
LevelSensitive,
|
|||
|
TRUE,
|
|||
|
0,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
if (!KeConnectInterrupt( &HalpEisaInterrupt )) {
|
|||
|
|
|||
|
return(FALSE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Raise the IRQL while the EISA interrupt controller is initalized.
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql(EISA_DEVICE_LEVEL, &oldIrql);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the EISA interrupt controller. There are two cascaded
|
|||
|
// interrupt controllers, each of which must initialized with 4 initialize
|
|||
|
// control words.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = 0;
|
|||
|
((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1;
|
|||
|
((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// The second intitialization control word sets the iterrupt vector to
|
|||
|
// 0-15.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = 0;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
DataByte = 0x08;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// The thrid initialization control word set the controls for slave mode.
|
|||
|
// The master ICW3 uses bit position and the slave ICW3 uses a numberic.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = 1 << SLAVE_IRQL_LEVEL;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
DataByte = SLAVE_IRQL_LEVEL;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// The fourth initialization control word is used to specify normal
|
|||
|
// end-of-interrupt mode and not special-fully-nested mode.
|
|||
|
//
|
|||
|
|
|||
|
DataByte = 0;
|
|||
|
((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
|
|||
|
DataByte
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Disable all of the interrupts except the slave.
|
|||
|
//
|
|||
|
|
|||
|
HalpEisaInterrupt1Mask = ~(1 << SLAVE_IRQL_LEVEL);
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
|
|||
|
HalpEisaInterrupt1Mask
|
|||
|
);
|
|||
|
|
|||
|
HalpEisaInterrupt2Mask = 0xFF;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
|
|||
|
HalpEisaInterrupt2Mask
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the edge/level register masks to 0 which is the default
|
|||
|
// edge sensitive value.
|
|||
|
//
|
|||
|
|
|||
|
HalpEisaInterrupt1Level = 0;
|
|||
|
HalpEisaInterrupt2Level = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Restore IRQL level.
|
|||
|
//
|
|||
|
|
|||
|
KeLowerIrql(oldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the DMA mode registers to a default value.
|
|||
|
// Disable all of the DMA channels except channel 4 which is the
|
|||
|
// cascade of channels 0-3.
|
|||
|
//
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask,
|
|||
|
0x0F
|
|||
|
);
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort.AllMask,
|
|||
|
0x0E
|
|||
|
);
|
|||
|
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalpEisaDispatch(
|
|||
|
IN PKINTERRUPT Interrupt,
|
|||
|
IN PVOID ServiceContext,
|
|||
|
IN PKTRAP_FRAME TrapFrame
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is entered as the result of an interrupt being generated
|
|||
|
via the vector that is connected to an interrupt object that describes
|
|||
|
the EISA device interrupts. Its function is to call the second
|
|||
|
level interrupt dispatch routine and acknowledge the interrupt at the EISA
|
|||
|
controller.
|
|||
|
|
|||
|
This service routine should be connected as follows:
|
|||
|
|
|||
|
KeInitializeInterrupt(&Interrupt, HalpEisaDispatch,
|
|||
|
EISA_VIRTUAL_BASE,
|
|||
|
(PKSPIN_LOCK)NULL, EISA_LEVEL, EISA_LEVEL, EISA_LEVEL,
|
|||
|
LevelSensitive, TRUE, 0, FALSE);
|
|||
|
KeConnectInterrupt(&Interrupt);
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Interrupt - Supplies a pointer to the interrupt object.
|
|||
|
|
|||
|
ServiceContext - Supplies a pointer to the EISA interrupt acknowledge
|
|||
|
register.
|
|||
|
|
|||
|
TrapFrame - Supplies a pointer to the trap frame for this interrupt.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the value returned from the second level routine.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR interruptVector;
|
|||
|
PKPRCB Prcb;
|
|||
|
BOOLEAN returnValue;
|
|||
|
USHORT PCRInOffset;
|
|||
|
UCHAR Int1Isr;
|
|||
|
UCHAR Int2Isr;
|
|||
|
|
|||
|
//
|
|||
|
// Acknowledge the Interrupt controller and receive the returned
|
|||
|
// interrupt vector.
|
|||
|
//
|
|||
|
|
|||
|
interruptVector = HalpAcknowledgeEisaInterrupt(ServiceContext);
|
|||
|
|
|||
|
|
|||
|
if ((interruptVector & 0x07) == 0x07) {
|
|||
|
|
|||
|
//
|
|||
|
// Check for a passive release by looking at the inservice register.
|
|||
|
// If there is a real IRQL7 interrupt, just go along normally. If there
|
|||
|
// is not, then it is a passive release. So just dismiss it.
|
|||
|
//
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
|
|||
|
0x0B
|
|||
|
);
|
|||
|
|
|||
|
Int1Isr = READ_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0);
|
|||
|
|
|||
|
//
|
|||
|
// do second controller
|
|||
|
//
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
|
|||
|
0x0B
|
|||
|
);
|
|||
|
|
|||
|
Int2Isr = READ_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0);
|
|||
|
|
|||
|
|
|||
|
if (!(Int2Isr & 0x80) && !(Int1Isr & 0x80)) {
|
|||
|
|
|||
|
//
|
|||
|
// Clear the master controller to clear situation
|
|||
|
//
|
|||
|
|
|||
|
if (!(Int2Isr & 0x80)) {
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
|
|||
|
NONSPECIFIC_END_OF_INTERRUPT
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Dispatch to the secondary interrupt service routine.
|
|||
|
//
|
|||
|
PCRInOffset = interruptVector + EISA_VECTORS;
|
|||
|
|
|||
|
|
|||
|
returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])(
|
|||
|
PCR->InterruptRoutine[PCRInOffset],
|
|||
|
TrapFrame
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Dismiss the interrupt in the EISA interrupt controllers.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// If this is a cascaded interrupt then the interrupt must be dismissed in
|
|||
|
// both controlles.
|
|||
|
//
|
|||
|
|
|||
|
if (interruptVector & 0x08) {
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
|
|||
|
NONSPECIFIC_END_OF_INTERRUPT
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
|
|||
|
NONSPECIFIC_END_OF_INTERRUPT
|
|||
|
);
|
|||
|
|
|||
|
return(returnValue);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalpDisableEisaInterrupt(
|
|||
|
IN ULONG Vector
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function Disables the EISA bus specified EISA bus interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Vector - Supplies the vector of the ESIA interrupt that is Disabled.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the EISA interrupt vector.
|
|||
|
//
|
|||
|
|
|||
|
Vector -= EISA_VECTORS;
|
|||
|
|
|||
|
//
|
|||
|
// Determine if this vector is for interrupt controller 1 or 2.
|
|||
|
//
|
|||
|
|
|||
|
if (Vector & 0x08) {
|
|||
|
|
|||
|
//
|
|||
|
// The interrupt is in controller 2.
|
|||
|
//
|
|||
|
|
|||
|
Vector &= 0x7;
|
|||
|
|
|||
|
HalpEisaInterrupt2Mask |= (UCHAR) 1 << Vector;
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
|
|||
|
HalpEisaInterrupt2Mask
|
|||
|
);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The interrupt is in controller 1.
|
|||
|
//
|
|||
|
|
|||
|
Vector &= 0x7;
|
|||
|
|
|||
|
//
|
|||
|
// never disable IRQL2, it is the slave interrupt
|
|||
|
//
|
|||
|
|
|||
|
if (Vector != SLAVE_IRQL_LEVEL) {
|
|||
|
HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector;
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
|
|||
|
HalpEisaInterrupt1Mask
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalpEnableEisaInterrupt(
|
|||
|
IN ULONG Vector,
|
|||
|
IN KINTERRUPT_MODE InterruptMode
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function enables the EISA bus specified EISA bus interrupt and sets
|
|||
|
the level/edge register to the requested value.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Vector - Supplies the vector of the ESIA interrupt that is enabled.
|
|||
|
|
|||
|
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
|
|||
|
Latched.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the EISA interrupt vector.
|
|||
|
//
|
|||
|
|
|||
|
Vector -= EISA_VECTORS;
|
|||
|
|
|||
|
//
|
|||
|
// Determine if this vector is for interrupt controller 1 or 2.
|
|||
|
//
|
|||
|
|
|||
|
if (Vector & 0x08) {
|
|||
|
|
|||
|
//
|
|||
|
// The interrupt is in controller 2.
|
|||
|
//
|
|||
|
|
|||
|
Vector &= 0x7;
|
|||
|
|
|||
|
HalpEisaInterrupt2Mask &= (UCHAR) ~(1 << Vector);
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
|
|||
|
HalpEisaInterrupt2Mask
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Set the level/edge control register.
|
|||
|
//
|
|||
|
|
|||
|
if (InterruptMode == LevelSensitive) {
|
|||
|
|
|||
|
HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
|
|||
|
HalpEisaInterrupt2Level
|
|||
|
);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The interrupt is in controller 1.
|
|||
|
//
|
|||
|
|
|||
|
Vector &= 0x7;
|
|||
|
|
|||
|
HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector);
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
|
|||
|
HalpEisaInterrupt1Mask
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Set the level/edge control register.
|
|||
|
//
|
|||
|
|
|||
|
if (InterruptMode == LevelSensitive) {
|
|||
|
|
|||
|
HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel,
|
|||
|
HalpEisaInterrupt1Level
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalHandleNMI(
|
|||
|
IN PKINTERRUPT Interrupt,
|
|||
|
IN PVOID ServiceContext
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called when an EISA NMI occurs. It print the appropriate
|
|||
|
status information and bugchecks.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Interrupt - Supplies a pointer to the interrupt object
|
|||
|
|
|||
|
ServiceContext - Bug number to call bugcheck with.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns TRUE.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR StatusByte;
|
|||
|
UCHAR EisaPort;
|
|||
|
ULONG port;
|
|||
|
ULONG AddressSpace = 1; // 1 = I/O address space
|
|||
|
BOOLEAN Status;
|
|||
|
PHYSICAL_ADDRESS BusAddress;
|
|||
|
PHYSICAL_ADDRESS TranslatedAddress;
|
|||
|
|
|||
|
StatusByte =
|
|||
|
READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus);
|
|||
|
|
|||
|
if (StatusByte & 0x80) {
|
|||
|
HalDisplayString ("NMI: Parity Check / Parity Error\n");
|
|||
|
}
|
|||
|
|
|||
|
if (StatusByte & 0x40) {
|
|||
|
HalDisplayString ("NMI: Channel Check / IOCHK\n");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This is an Eisa machine, check for extnded nmi information...
|
|||
|
//
|
|||
|
|
|||
|
StatusByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl);
|
|||
|
|
|||
|
if (StatusByte & 0x80) {
|
|||
|
HalDisplayString ("NMI: Fail-safe timer\n");
|
|||
|
}
|
|||
|
|
|||
|
if (StatusByte & 0x40) {
|
|||
|
HalDisplayString ("NMI: Bus Timeout\n");
|
|||
|
}
|
|||
|
|
|||
|
if (StatusByte & 0x20) {
|
|||
|
HalDisplayString ("NMI: Software NMI generated\n");
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Look for any Eisa expansion board. See if it asserted NMI.
|
|||
|
//
|
|||
|
|
|||
|
BusAddress.HighPart = 0;
|
|||
|
|
|||
|
for (EisaPort = 0; EisaPort <= 0xf; EisaPort++)
|
|||
|
{
|
|||
|
BusAddress.LowPart = (EisaPort << 12) + 0xC80;
|
|||
|
|
|||
|
Status = HalTranslateBusAddress(Eisa, // InterfaceType
|
|||
|
0, // BusNumber
|
|||
|
BusAddress,
|
|||
|
&AddressSpace, // 1=I/O address space
|
|||
|
&TranslatedAddress); // QVA
|
|||
|
if (Status == FALSE)
|
|||
|
{
|
|||
|
UCHAR pbuf[80];
|
|||
|
sprintf(pbuf,
|
|||
|
"Unable to translate bus address %x for EISA slot %d\n",
|
|||
|
BusAddress.LowPart, EisaPort);
|
|||
|
HalDisplayString(pbuf);
|
|||
|
KeBugCheck(NMI_HARDWARE_FAILURE);
|
|||
|
}
|
|||
|
|
|||
|
port = TranslatedAddress.LowPart;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR ((PUCHAR) port, 0xff);
|
|||
|
StatusByte = READ_PORT_UCHAR ((PUCHAR) port);
|
|||
|
|
|||
|
if ((StatusByte & 0x80) == 0) {
|
|||
|
//
|
|||
|
// Found valid Eisa board, Check to see if it's
|
|||
|
// if IOCHKERR is asserted.
|
|||
|
//
|
|||
|
|
|||
|
StatusByte = READ_PORT_UCHAR ((PUCHAR) port+4);
|
|||
|
if (StatusByte & 0x2) {
|
|||
|
EisaNMIMsg[25] = (EisaPort > 9 ? 'A'-10 : '0') + EisaPort;
|
|||
|
HalDisplayString (EisaNMIMsg);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
// Reset NMI interrupts (for debugging purposes only).
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x00);
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x02);
|
|||
|
#endif
|
|||
|
|
|||
|
KeBugCheck(NMI_HARDWARE_FAILURE);
|
|||
|
return(TRUE);
|
|||
|
}
|