Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1387 lines
32 KiB

/*++
Copyright (c) 1990-1993 Microsoft Corporation
Module Name:
jxebsup.c
Abstract:
The module provides the EISA bus support for JAZZ systems.
--*/
#include "halp.h"
#include "eisa.h"
#include "bugcodes.h"
//
// external (defined in fxpcibus.c)
//
extern UCHAR HalpPCIPinToLineTable[];
extern UCHAR HalpPIRQTable[];
//
// Define the context structure for use by the interrupt routine.
//
typedef BOOLEAN (*PSECONDARY_DISPATCH)(
PVOID InterruptRoutine
);
//
// Declare the interupt structure and spinlock for the intermediate EISA
// interrupt dispachter.
//
KINTERRUPT HalpEisaInterrupt;
//
// 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 adapter objects.
//
PADAPTER_OBJECT HalpEisaAdapter[8];
//
// Define save area for EISA interrupt mask registers and level\edge control
// registers.
//
UCHAR HalpEisaInterrupt1Mask;
UCHAR HalpEisaInterrupt2Mask;
UCHAR HalpEisaInterrupt1Level;
UCHAR HalpEisaInterrupt2Level;
//
// Define EISA bus interrupt affinity.
//
#if defined(PROCESSOR_AFFINITY_PCR)
KAFFINITY HalpEisaBusAffinity;
#endif // PROCESSOR_AFFINITY_PCR
PADAPTER_OBJECT
HalpAllocateEisaAdapter(
IN PDEVICE_DESCRIPTION DeviceDescriptor
)
/*++
Routine Description:
This function allocates an EISA adapter object according to the
specification supplied in the device description. The necessary device
descriptor information is saved. If there is
no existing adapter object for this channel then a new one is allocated.
The saved information in the adapter object is used to set the various DMA
modes when the channel is allocated or a map transfer is done.
Arguments:
DeviceDescription - Supplies the description of the device which want to
use the DMA adapter.
Return Value:
Returns a pointer to the newly created adapter object or NULL if one
cannot be created.
--*/
{
PADAPTER_OBJECT adapterObject;
PVOID adapterBaseVa;
ULONG channelNumber;
ULONG controllerNumber;
DMA_EXTENDED_MODE extendedMode;
UCHAR adapterMode;
BOOLEAN useChannel;
//
// Determine if the the channel number is important. Master cards on
// Eisa do not use a channel number.
//
//
if (DeviceDescriptor->InterfaceType == Eisa && DeviceDescriptor->Master) {
useChannel = FALSE;
} else {
useChannel = TRUE;
}
//
// Channel 4 cannot be used since it is used for chaining. Return null if
// it is requested.
//
if ((DeviceDescriptor->DmaChannel == 4 ||
DeviceDescriptor->DmaChannel > 7) && useChannel) {
return(NULL);
}
//
// Set the channel number number.
//
channelNumber = DeviceDescriptor->DmaChannel & 0x03;
//
// Set the adapter base address to the Base address register and controller
// number.
//
if (!(DeviceDescriptor->DmaChannel & 0x04)) {
controllerNumber = 1;
adapterBaseVa = (PVOID) &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort;
} else {
controllerNumber = 2;
adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort;
}
//
// Determine if a new adapter object is necessary. If so then allocate it.
//
if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
} else {
//
// Allocate an adapter object.
//
adapterObject = (PADAPTER_OBJECT) HalpAllocateAdapter(
0,
adapterBaseVa,
NULL
);
if (adapterObject == NULL) {
return(NULL);
}
//
// We want to know the interface type
//
adapterObject->InterfaceType = DeviceDescriptor->InterfaceType;
if (useChannel) {
HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
}
}
//
// If the channel is not used then indicate the this is an Eisa bus
// master by setting the page port and mode to cascade even though
// it is not used.
//
if (!useChannel) {
adapterObject->PagePort = (PVOID) (~0x0);
((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE;
return(adapterObject);
}
//
// Setup the pointers to all the random registers.
//
adapterObject->ChannelNumber = (UCHAR)channelNumber;
if (controllerNumber == 1) {
switch ((UCHAR)channelNumber) {
case 0:
adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel0;
break;
case 1:
adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel1;
break;
case 2:
adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel2;
break;
case 3:
adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel3;
break;
}
//
// Set the adapter number.
//
adapterObject->AdapterNumber = 1;
//
// Save the extended mode register address.
//
adapterBaseVa =
&((PEISA_CONTROL) HalpEisaControlBase)->Dma1ExtendedModePort;
} else {
switch (channelNumber) {
case 1:
adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel5;
break;
case 2:
adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel6;
break;
case 3:
adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel7;
break;
}
//
// Set the adapter number.
//
adapterObject->AdapterNumber = 2;
//
// Save the extended mode register address.
//
adapterBaseVa =
&((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort;
}
//
// Initialzie the extended mode port.
//
*((PUCHAR) &extendedMode) = 0;
extendedMode.ChannelNumber = (UCHAR)channelNumber;
switch (DeviceDescriptor->DmaSpeed) {
case Compatible:
extendedMode.TimingMode = COMPATIBLITY_TIMING;
break;
case TypeA:
extendedMode.TimingMode = TYPE_A_TIMING;
break;
case TypeB:
extendedMode.TimingMode = TYPE_B_TIMING;
break;
case TypeC:
extendedMode.TimingMode = BURST_TIMING;
break;
default:
ObDereferenceObject( adapterObject );
return(NULL);
}
switch (DeviceDescriptor->DmaWidth) {
case Width8Bits:
extendedMode.TransferSize = BY_BYTE_8_BITS;
break;
case Width16Bits:
extendedMode.TransferSize = BY_BYTE_16_BITS;
break;
case Width32Bits:
extendedMode.TransferSize = BY_BYTE_32_BITS;
break;
default:
ObDereferenceObject( adapterObject );
return(NULL);
}
WRITE_REGISTER_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode));
//
// Initialize the adapter mode register value to the correct parameters,
// and save them in the adapter object.
//
adapterMode = 0;
((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber;
if (DeviceDescriptor->Master) {
((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE;
//
// Set the mode, and enable the request.
//
if (adapterObject->AdapterNumber == 1) {
//
// This request is for DMA controller 1
//
PDMA1_CONTROL dmaControl;
dmaControl = adapterObject->AdapterBaseVa;
WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
//
// Unmask the DMA channel.
//
WRITE_REGISTER_UCHAR(
&dmaControl->SingleMask,
(UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
);
} else {
//
// This request is for DMA controller 1
//
PDMA2_CONTROL dmaControl;
dmaControl = adapterObject->AdapterBaseVa;
WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
//
// Unmask the DMA channel.
//
WRITE_REGISTER_UCHAR(
&dmaControl->SingleMask,
(UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
);
}
} else if (DeviceDescriptor->DemandMode) {
((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE;
} else {
((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE;
}
if (DeviceDescriptor->AutoInitialize) {
((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1;
}
adapterObject->AdapterMode = adapterMode;
return(adapterObject);
}
/*++
Routine Description:
This function initializes IO interrupts on a Falcon system.
This function is only called during phase 0 initialization.
Arguments:
pointer to eisa control structure.
Return Value:
None
--*/
VOID
HalpInitializeEisaInterrupts (
IN PEISA_CONTROL controlBase
)
{
UCHAR DataByte;
ULONG i;
//
// Set EISA bus interrupt affinity.
//
#if defined(PROCESSOR_AFFINITY_PCR)
HalpEisaBusAffinity = PCR->SetMember;
#endif // PROCESSOR_AFFINITY_PCR)
//
// Let's read the PIRQ* registers to obtain the dynamic
// mapping for PCI interrupts as set by the firmware
// in the 82374/82375. We will save the PIRQ mappings
// in the HalpPCIPinToLineTable[] which is used during
// PCI bus probing and device configuration.
//
// Warning: Do not change the section of code related
// to PIRQ mappings unless you thoroughly
// understand the HalpPCIPinToLineTable[] and
// the HalpPciConfigSelectDecodeTable[]. These
// tables correspond directly to the PciConfigSelect
// register inside the PMP asic and the PIRQ
// lines which deliver the interrupts for each
// PCI device.
//
WRITE_REGISTER_UCHAR(&controlBase->Reserved1[0], ESC_CONFIG_ID);
WRITE_REGISTER_UCHAR(&controlBase->Reserved1[1], ESC_CONFIG_IDEN_BYTE);
WRITE_REGISTER_UCHAR(&controlBase->Reserved1[0], ESC_CONFIG_PIRQ0);
HalpPCIPinToLineTable[PCI_OBENET_DEVICE_NUMBER] = HalpPIRQTable[0] =
READ_REGISTER_UCHAR(&controlBase->Reserved1[1]);
WRITE_REGISTER_UCHAR(&controlBase->Reserved1[0], ESC_CONFIG_PIRQ1);
HalpPCIPinToLineTable[PCI_OBSCSI_DEVICE_NUMBER] = HalpPIRQTable[1] =
READ_REGISTER_UCHAR(&controlBase->Reserved1[1]);
WRITE_REGISTER_UCHAR(&controlBase->Reserved1[0], ESC_CONFIG_PIRQ3);
HalpPCIPinToLineTable[PCI_SLOT0_DEVICE_NUMBER] = HalpPIRQTable[2] =
READ_REGISTER_UCHAR(&controlBase->Reserved1[1]);
WRITE_REGISTER_UCHAR(&controlBase->Reserved1[0], ESC_CONFIG_PIRQ2);
HalpPCIPinToLineTable[PCI_SLOT1_DEVICE_NUMBER] = HalpPIRQTable[3] =
READ_REGISTER_UCHAR(&controlBase->Reserved1[1]);
//
// First lets mask off all interrupts to separate ourselves
// from the firmware to avoid spurious interrupts
//
HalpEisaInterrupt1Mask = (UCHAR)0xFF;
WRITE_REGISTER_UCHAR(&controlBase->Interrupt1ControlPort1, HalpEisaInterrupt1Mask);
HalpEisaInterrupt2Mask = (UCHAR)0xFF;
WRITE_REGISTER_UCHAR(&controlBase->Interrupt2ControlPort1, HalpEisaInterrupt2Mask);
//
// Set everything to edge before beginning the initialization
// sequence (per the 82374 errata)
//
WRITE_REGISTER_UCHAR(&controlBase->Interrupt1EdgeLevel, 0);
WRITE_REGISTER_UCHAR(&controlBase->Interrupt2EdgeLevel, 0);
//
// 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_REGISTER_UCHAR(&controlBase->Interrupt1ControlPort0, DataByte);
WRITE_REGISTER_UCHAR(&controlBase->Interrupt2ControlPort0, DataByte);
//
// The second intitialization control word sets the interrupt vector to
// 0-15.
//
DataByte = 0;
WRITE_REGISTER_UCHAR(&controlBase->Interrupt1ControlPort1, DataByte);
DataByte = 0x08;
WRITE_REGISTER_UCHAR(&controlBase->Interrupt2ControlPort1, DataByte);
//
// The third initialization control word set the controls for slave mode.
// The master ICW3 uses bit position and the slave ICW3 uses a numeric.
//
DataByte = 1 << SLAVE_IRQL_LEVEL;
WRITE_REGISTER_UCHAR(&controlBase->Interrupt1ControlPort1, DataByte);
DataByte = SLAVE_IRQL_LEVEL;
WRITE_REGISTER_UCHAR(&controlBase->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_REGISTER_UCHAR(&controlBase->Interrupt1ControlPort1, DataByte);
WRITE_REGISTER_UCHAR(&controlBase->Interrupt2ControlPort1, DataByte);
//
// Enable the slave interrupt which connects the two cascaded
// interrupt controllers together.
//
HalpEisaInterrupt1Mask = (UCHAR) ~(1 << SLAVE_IRQL_LEVEL);
WRITE_REGISTER_UCHAR(&controlBase->Interrupt1ControlPort1, HalpEisaInterrupt1Mask);
HalpEisaInterrupt2Mask = (UCHAR)0xFF;
WRITE_REGISTER_UCHAR(&controlBase->Interrupt2ControlPort1, HalpEisaInterrupt2Mask);
//
// Program the level versus edge sensitivity of the interrupts.
//
WRITE_REGISTER_UCHAR(&controlBase->Interrupt1EdgeLevel, HalpEisaInterrupt1Level);
WRITE_REGISTER_UCHAR(&controlBase->Interrupt2EdgeLevel, HalpEisaInterrupt2Level);
//
// Clear any specific interrupts
// left hanging around by the
// boot
for (i = 0; i < 8; i++) {
WRITE_REGISTER_UCHAR(&controlBase->Interrupt1ControlPort0, 0x20);
}
for (i = 0; i < 8; i++) {
WRITE_REGISTER_UCHAR(&controlBase->Interrupt2ControlPort0, 0x20);
}
//
// Initialize the DMA mode registers to a default value.
// Disable all of the DMA channels except channel 4 which is that
// cascade of channels 0-3.
//
WRITE_REGISTER_UCHAR(&controlBase->Dma1BasePort.AllMask, 0x0F);
WRITE_REGISTER_UCHAR(&controlBase->Dma2BasePort.AllMask, 0x0E);
//
// We're done
//
return;
}
/*++
Routine Description:
This function dispatches IO interrupts on a Falcon system.
It calls the device-specific interrupt handler (ISR).
Arguments:
None
Return Value:
None
--*/
VOID
HalpIoInterruptDispatch(
VOID
)
{
UCHAR interruptVector;
UCHAR inService;
PKPRCB Prcb;
BOOLEAN Status;
//
// Read IoIntAck register to determine the interrupt source
//
interruptVector = READ_REGISTER_UCHAR(HalpPmpIoIntAck);
//
// Determine if this is a bogus interrupt from the 8259
// by checking the corresponding InService bit. If it is
// real then we will deal with it normally; otherwise,
// we will just dismiss it straight away.
//
if (interruptVector == 0x07) {
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpEisaControlBase)->Interrupt1ControlPort0, 0x0B);
inService = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpEisaControlBase)->Interrupt1ControlPort0);
if (!(inService & 0x80)) {
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpEisaControlBase)->Interrupt1ControlPort0, NONSPECIFIC_END_OF_INTERRUPT);
}
}
//
// Get the PRCB.
//
Prcb = KeGetCurrentPrcb();
//
// Dispatch to the secondary interrupt service routine.
//
Status = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[EISA_VECTORS + interruptVector])(
PCR->InterruptRoutine[EISA_VECTORS + interruptVector]
);
//
// Dismiss the interrupt in the 8259 interrupt controller.
//
//
// If this is a cascaded interrupt then the interrupt must be dismissed in
// both controllers.
//
if (interruptVector & 0x08) {
WRITE_REGISTER_UCHAR(
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
NONSPECIFIC_END_OF_INTERRUPT
);
}
WRITE_REGISTER_UCHAR(
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
NONSPECIFIC_END_OF_INTERRUPT
);
}
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_REGISTER_UCHAR(
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
HalpEisaInterrupt2Mask
);
} else {
//
// The interrupt is in controller 1.
//
Vector &= 0x7;
HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector;
WRITE_REGISTER_UCHAR(
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
HalpEisaInterrupt1Mask
);
}
}
VOID
HalpEisaMapTransfer(
IN PADAPTER_OBJECT AdapterObject,
IN ULONG Offset,
IN ULONG Length,
IN BOOLEAN WriteToDevice
)
/*++
Routine Description:
This function programs the EISA DMA controller for a transfer.
Arguments:
Adapter - Supplies the DMA adapter object to be programed.
Offset - Supplies the logical address to use for the transfer.
Length - Supplies the length of the transfer in bytes.
WriteToDevice - Indicates the direction of the transfer.
Return Value:
None.
--*/
{
PUCHAR BytePtr;
UCHAR adapterMode;
KIRQL Irql;
BytePtr = (PUCHAR) &Offset;
ASSERT(Offset >= 0x100000);
//
// grab the spinlock for the system DMA controller
//
KeAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock, &Irql );
adapterMode = AdapterObject->AdapterMode;
//
// Check to see if this request is for a master I/O card.
//
if (((PDMA_EISA_MODE) &adapterMode)->RequestMode == CASCADE_REQUEST_MODE) {
//
// Set the mode, Disable the request and return.
//
if (AdapterObject->AdapterNumber == 1) {
//
// This request is for DMA controller 1
//
PDMA1_CONTROL dmaControl;
dmaControl = AdapterObject->AdapterBaseVa;
WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
//
// Unmask the DMA channel.
//
WRITE_REGISTER_UCHAR(
&dmaControl->SingleMask,
(UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
);
} else {
//
// This request is for DMA controller 2
//
PDMA2_CONTROL dmaControl;
dmaControl = AdapterObject->AdapterBaseVa;
WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
//
// Unmask the DMA channel.
//
WRITE_REGISTER_UCHAR(
&dmaControl->SingleMask,
(UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
);
}
//
// Release adapter spin lock
//
KeReleaseSpinLock (&AdapterObject->MasterAdapter->SpinLock, Irql);
return;
}
//
// Determine the mode based on the transfer direction.
//
((PDMA_EISA_MODE) &adapterMode)->TransferType = WriteToDevice ?
WRITE_TRANSFER : READ_TRANSFER;
//
// Determine the controller number based on the Adapter base va.
//
if (AdapterObject->AdapterNumber == 1) {
//
// This request is for DMA controller 1
//
PDMA1_CONTROL dmaControl;
dmaControl = AdapterObject->AdapterBaseVa;
WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 );
WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
//
// Devices which do not use auto-initialize
// CommonBuffer DMA can use the scatter/gather
// capabilities of the 82374 which we manage
// through map registers similar to how previous
// MIPS machines managed the IO TLB.
//
if (!AdapterObject->AutoInitialize) {
//
// 1. Setup Scatter/Gather Descriptor Table Pointer
// register according to which channel is being used.
// 2. Issue Scatter/Gather Start command.
//
switch (AdapterObject->ChannelNumber) {
case 0:
WRITE_REGISTER_ULONG( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[16], Offset);
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[0], SCATTER_GATHER_COMMAND);
break;
case 1:
WRITE_REGISTER_ULONG( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[20], Offset);
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[1], SCATTER_GATHER_COMMAND);
break;
case 2:
WRITE_REGISTER_ULONG( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[24], Offset);
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[2], SCATTER_GATHER_COMMAND);
break;
case 3:
WRITE_REGISTER_ULONG( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[28], Offset);
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[3], SCATTER_GATHER_COMMAND);
break;
}
} else {
WRITE_REGISTER_UCHAR(
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
.DmaBaseAddress,
BytePtr[0]
);
WRITE_REGISTER_UCHAR(
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
.DmaBaseAddress,
BytePtr[1]
);
WRITE_REGISTER_UCHAR(
((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
(ULONG)AdapterObject->PagePort,
BytePtr[2]
);
WRITE_REGISTER_UCHAR(
((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
(ULONG)AdapterObject->PagePort,
BytePtr[3]
);
//
// Notify DMA chip of the length to transfer.
//
WRITE_REGISTER_UCHAR(
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
.DmaBaseCount,
(UCHAR) ((Length - 1) & 0xff)
);
WRITE_REGISTER_UCHAR(
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
.DmaBaseCount,
(UCHAR) ((Length - 1) >> 8)
);
}
//
// Set the DMA chip to read or write mode; and unmask it.
//
WRITE_REGISTER_UCHAR(
&dmaControl->SingleMask,
(UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
);
} else {
//
// This request is for DMA controller 2
//
PDMA2_CONTROL dmaControl;
dmaControl = AdapterObject->AdapterBaseVa;
WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 );
WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
//
// Devices which do not use auto-initialize
// CommonBuffer DMA can use the scatter/gather
// capabilities of the 82374 which we manage
// through map registers.
//
if (!AdapterObject->AutoInitialize) {
//
// 1. Setup Scatter/Gather Descriptor Table Pointer
// register according to which channel is being used.
// 2. Issue Scatter/Gather Start command.
//
switch (AdapterObject->ChannelNumber) {
case 1:
WRITE_REGISTER_ULONG( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[36], Offset);
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[5], SCATTER_GATHER_COMMAND);
break;
case 2:
WRITE_REGISTER_ULONG( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[40], Offset);
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[6], SCATTER_GATHER_COMMAND);
break;
case 3:
WRITE_REGISTER_ULONG( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[44], Offset);
WRITE_REGISTER_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Reserved6[7], SCATTER_GATHER_COMMAND);
break;
}
} else {
WRITE_REGISTER_UCHAR(
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
.DmaBaseAddress,
BytePtr[0]
);
WRITE_REGISTER_UCHAR(
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
.DmaBaseAddress,
BytePtr[1]
);
WRITE_REGISTER_UCHAR(
((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
(ULONG)AdapterObject->PagePort,
BytePtr[2]
);
WRITE_REGISTER_UCHAR(
((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
(ULONG)AdapterObject->PagePort,
BytePtr[3]
);
//
// Notify DMA chip of the length to transfer.
//
WRITE_REGISTER_UCHAR(
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
.DmaBaseCount,
(UCHAR) ((Length - 1) & 0xff)
);
WRITE_REGISTER_UCHAR(
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
.DmaBaseCount,
(UCHAR) ((Length - 1) >> 8)
);
}
//
// Set the DMA chip to read or write mode; and unmask it.
//
WRITE_REGISTER_UCHAR(
&dmaControl->SingleMask,
(UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
);
}
//
// Release adapter spin lock
//
KeReleaseSpinLock (&AdapterObject->MasterAdapter->SpinLock, Irql);
}
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_REGISTER_UCHAR(
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
HalpEisaInterrupt2Mask
);
//
// Set the level/edge control register.
//
//
// According to the 82374, the following interrupts
// MUST be edge-triggered: 0, 1, 2, 8, 13.
//
if ( (InterruptMode == LevelSensitive) && (Vector != 0) && (Vector != 0x5) ) {
HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector);
} else {
HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector);
}
WRITE_REGISTER_UCHAR(
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
HalpEisaInterrupt2Level
);
} else {
//
// The interrupt is in controller 1.
//
Vector &= 0x7;
HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector);
WRITE_REGISTER_UCHAR(
&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
HalpEisaInterrupt1Mask
);
//
// Set the level/edge control register.
//
//
// According to the 82374, the following interrupts
// MUST be edge-triggered: 0, 1, 2, 8, 13.
//
// Warning: due to a firmware limitation (???) we must
// force the floppy interrupt (irq6) to be edge
// even though it will request level. There is no
// mechanism for communicating to a driver that
// its interrupt mode is different than requested.
// Hope this doesn't cause problems ...
//
if ( (InterruptMode == LevelSensitive) && (Vector >= 3) && (Vector != 6) ) {
HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector);
} else {
HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector);
}
WRITE_REGISTER_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;
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.
//
for (EisaPort = 0; EisaPort <= 0xf; EisaPort++) {
port = (EisaPort << 12) + 0xC80;
port += (ULONG) HalpEisaControlBase;
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);
}
}
}
KeBugCheck(NMI_HARDWARE_FAILURE);
return(TRUE);
}
NTSTATUS
HalpAdjustEisaResourceList (
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
)
{
SUPPORTED_RANGE InterruptRange;
RtlZeroMemory (&InterruptRange, sizeof InterruptRange);
InterruptRange.Base = 0;
InterruptRange.Limit = 15;
return HaliAdjustResourceListRange (
BusHandler->BusAddresses,
&InterruptRange,
pResourceList
);
}
VOID
HalpConfigureGpcsRegs(
IN PVOID ControlBase
)
{
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[0], ESC_CONFIG_ID);
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[1], ESC_CONFIG_IDEN_BYTE);
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[0], ESC_CONFIG_GPCSHA0);
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[1], (UCHAR)(PCI_CONFIG_SELECT_OFFSET >> 8));
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[0], ESC_CONFIG_GPCSLA0);
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[1], (UCHAR)(PCI_CONFIG_SELECT_OFFSET & 0xFF));
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[0], ESC_CONFIG_GPCSHA1);
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[1], (UCHAR)(EXTERNAL_PMP_CONTROL_OFFSET >> 8));
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[0], ESC_CONFIG_GPCSLA1);
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[1], (UCHAR)(EXTERNAL_PMP_CONTROL_OFFSET & 0xFF));
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[0], ESC_CONFIG_GPCSHA2);
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[1], (UCHAR)(EXTERNAL_PMP_CONTROL_OFFSET2 >> 8));
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[0], ESC_CONFIG_GPCSLA2);
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)ControlBase)->Reserved1[1], (UCHAR)(EXTERNAL_PMP_CONTROL_OFFSET2 & 0xFF));
}