484 lines
9.7 KiB
C
484 lines
9.7 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1990 Microsoft Corporation
|
|||
|
Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
pic8259.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
The module provides the interrupt support for the PCI SIO
|
|||
|
programmable interrupt controller.
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Eric Rehm (DEC) 4-Feburary-1994
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "halp.h"
|
|||
|
#include "eisa.h"
|
|||
|
|
|||
|
//
|
|||
|
// Import save area for SIO interrupt mask registers.
|
|||
|
//
|
|||
|
|
|||
|
UCHAR HalpSioInterrupt1Mask;
|
|||
|
UCHAR HalpSioInterrupt2Mask;
|
|||
|
UCHAR HalpSioInterrupt1Level;
|
|||
|
UCHAR HalpSioInterrupt2Level;
|
|||
|
|
|||
|
//
|
|||
|
// Define the context structure for use by interrupt service routines.
|
|||
|
//
|
|||
|
|
|||
|
typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)(
|
|||
|
PKINTERRUPT InterruptObject
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeSioInterrupts (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine initializes the standard dual 8259 programmable interrupt
|
|||
|
controller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR DataByte;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the SIO 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.
|
|||
|
//
|
|||
|
|
|||
|
HalpSioInterrupt1Mask = (UCHAR)(~(1 << SLAVE_IRQL_LEVEL));
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
|
|||
|
HalpSioInterrupt1Mask
|
|||
|
);
|
|||
|
|
|||
|
HalpSioInterrupt2Mask = 0xFF;
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
|
|||
|
HalpSioInterrupt2Mask
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the edge/level register masks to 0 which is the default
|
|||
|
// edge sensitive value.
|
|||
|
//
|
|||
|
|
|||
|
HalpSioInterrupt1Level = 0;
|
|||
|
HalpSioInterrupt2Level = 0;
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalpDisableSioInterrupt(
|
|||
|
IN ULONG Vector
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function Disables the SIO bus specified SIO bus interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Vector - Supplies the vector of the ESIA interrupt that is Disabled.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the SIO interrupt vector.
|
|||
|
//
|
|||
|
|
|||
|
Vector -= ISA_VECTORS;
|
|||
|
|
|||
|
//
|
|||
|
// Determine if this vector is for interrupt controller 1 or 2.
|
|||
|
//
|
|||
|
|
|||
|
if (Vector & 0x08) {
|
|||
|
|
|||
|
//
|
|||
|
// The interrupt is in controller 2.
|
|||
|
//
|
|||
|
|
|||
|
Vector &= 0x7;
|
|||
|
|
|||
|
HalpSioInterrupt2Mask |= (UCHAR) 1 << Vector;
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
|
|||
|
HalpSioInterrupt2Mask
|
|||
|
);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The interrupt is in controller 1.
|
|||
|
//
|
|||
|
|
|||
|
Vector &= 0x7;
|
|||
|
|
|||
|
//
|
|||
|
// never disable IRQL2, it is the slave interrupt
|
|||
|
//
|
|||
|
|
|||
|
if (Vector != SLAVE_IRQL_LEVEL) {
|
|||
|
HalpSioInterrupt1Mask |= (ULONG) 1 << Vector;
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
|
|||
|
HalpSioInterrupt1Mask
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalpEnableSioInterrupt(
|
|||
|
IN ULONG Vector,
|
|||
|
IN KINTERRUPT_MODE InterruptMode
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function enables the SIO bus specified SIO bus interrupt.
|
|||
|
Arguments:
|
|||
|
|
|||
|
Vector - Supplies the vector of the SIO interrupt that is enabled.
|
|||
|
|
|||
|
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
|
|||
|
Latched.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the SIO interrupt vector.
|
|||
|
//
|
|||
|
|
|||
|
Vector -= ISA_VECTORS;
|
|||
|
|
|||
|
//
|
|||
|
// Determine if this vector is for interrupt controller 1 or 2.
|
|||
|
//
|
|||
|
|
|||
|
if (Vector & 0x08) {
|
|||
|
|
|||
|
//
|
|||
|
// The interrupt is in controller 2.
|
|||
|
//
|
|||
|
|
|||
|
Vector &= 0x7;
|
|||
|
|
|||
|
HalpSioInterrupt2Mask &= (UCHAR) ~(1 << Vector);
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
|
|||
|
HalpSioInterrupt2Mask
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Set the level/edge control register.
|
|||
|
//
|
|||
|
|
|||
|
if (InterruptMode == LevelSensitive) {
|
|||
|
|
|||
|
HalpSioInterrupt2Level |= (UCHAR) (1 << Vector);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
HalpSioInterrupt2Level &= (UCHAR) ~(1 << Vector);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
|
|||
|
HalpSioInterrupt2Level
|
|||
|
);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The interrupt is in controller 1.
|
|||
|
//
|
|||
|
|
|||
|
Vector &= 0x7;
|
|||
|
|
|||
|
HalpSioInterrupt1Mask &= (UCHAR) ~(1 << Vector);
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
|
|||
|
HalpSioInterrupt1Mask
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Set the level/edge control register.
|
|||
|
//
|
|||
|
|
|||
|
if (InterruptMode == LevelSensitive) {
|
|||
|
|
|||
|
HalpSioInterrupt1Level |= (UCHAR) (1 << Vector);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
HalpSioInterrupt1Level &= (UCHAR) ~(1 << Vector);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
WRITE_PORT_UCHAR(
|
|||
|
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel,
|
|||
|
HalpSioInterrupt1Level
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalpSioDispatch(
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is entered as the result of an interrupt being generated
|
|||
|
via the vector that is directly connected to an interrupt object that
|
|||
|
describes the SIO device interrupts. Its function is to call the second
|
|||
|
level interrupt dispatch routine and acknowledge the interrupt at the SIO
|
|||
|
controller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns the value returned from the second level routine.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR ISAVector;
|
|||
|
PKPRCB Prcb;
|
|||
|
BOOLEAN returnValue;
|
|||
|
USHORT PCRInOffset;
|
|||
|
UCHAR Int1Isr;
|
|||
|
UCHAR Int2Isr;
|
|||
|
PULONG DispatchCode;
|
|||
|
PKINTERRUPT InterruptObject;
|
|||
|
|
|||
|
//
|
|||
|
// Acknowledge the Interrupt controller and receive the returned
|
|||
|
// interrupt vector.
|
|||
|
//
|
|||
|
|
|||
|
ISAVector = READ_PORT_UCHAR(HalpEisaIntAckBase);
|
|||
|
|
|||
|
|
|||
|
if ((ISAVector & 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 FALSE; // ecrfix - now returns a value
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Dispatch to the secondary interrupt service routine.
|
|||
|
//
|
|||
|
|
|||
|
PCRInOffset = ISAVector + ISA_VECTORS;
|
|||
|
DispatchCode = (PULONG)PCR->InterruptRoutine[PCRInOffset];
|
|||
|
InterruptObject = CONTAINING_RECORD(DispatchCode,
|
|||
|
KINTERRUPT,
|
|||
|
DispatchCode);
|
|||
|
|
|||
|
returnValue = ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(InterruptObject);
|
|||
|
|
|||
|
//
|
|||
|
// Dismiss the interrupt in the SIO interrupt controllers.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// If this is a cascaded interrupt then the interrupt must be dismissed in
|
|||
|
// both controlles.
|
|||
|
//
|
|||
|
|
|||
|
if (ISAVector & 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);
|
|||
|
}
|
|||
|
|
|||
|
|