mirror of https://github.com/lianthony/NT4.0
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.
1761 lines
38 KiB
1761 lines
38 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Copyright (c) 1994 MOTOROLA, INC. All Rights Reserved. This file
|
|
contains copyrighted material. Use of this file is restricted
|
|
by the provisions of a Motorola Software License Agreement.
|
|
|
|
Module Name:
|
|
|
|
pxsiosup.c
|
|
|
|
Abstract:
|
|
|
|
The module provides the PCI ISA bridge support.
|
|
|
|
Author:
|
|
|
|
Jim Wooldridge ([email protected])
|
|
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
#include "halp.h"
|
|
#include "pxsystyp.h"
|
|
#include "eisa.h"
|
|
#include "pxsiosup.h"
|
|
#include "pxpcisup.h"
|
|
#include "pxmemctl.h"
|
|
#include "bugcodes.h"
|
|
|
|
|
|
#define SioId 0x04848086 // UMC 8886
|
|
|
|
PVOID HalpPciIsaBridgeConfigBase;
|
|
extern USHORT Halp8259MaskTable[];
|
|
extern PADAPTER_OBJECT MasterAdapterObject;
|
|
VOID HalpUpdate8259(KIRQL Irql);
|
|
|
|
|
|
|
|
//
|
|
// Define the context structure for use by the interrupt routine.
|
|
//
|
|
|
|
|
|
typedef BOOLEAN (*PSECONDARY_DISPATCH)(
|
|
PVOID InterruptRoutine,
|
|
PVOID ServiceContext,
|
|
PVOID TrapFrame
|
|
);
|
|
|
|
//
|
|
// Declare the interrupt structure for profile interrupt
|
|
//
|
|
|
|
KINTERRUPT HalpProfileInterrupt;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
//
|
|
// Declare the interrupt structure for machine checks
|
|
//
|
|
|
|
KINTERRUPT HalpMachineCheckInterrupt;
|
|
|
|
//
|
|
// Declare the interrupt structure for the clock interrupt
|
|
//
|
|
|
|
KINTERRUPT HalpDecrementerInterrupt;
|
|
|
|
//
|
|
// Map the interrupt controllers priority scheme to NT IRQL values.
|
|
// The SIO prioritizes IRQs as follows:
|
|
// IRQ0, IRQ1, IRQ8 ... IRQ15, IRQ3, IRQ4 ... IRQ7.
|
|
//
|
|
// NOTE: The following table must be coordinated with the entries
|
|
// in Halp8259MaskTable in PXIRQL.C
|
|
//
|
|
KIRQL VectorToIrql[16] = {
|
|
// IRQL Vector
|
|
// ---- ------
|
|
26, // 0
|
|
25, // 1
|
|
24, // 2
|
|
15, // 3
|
|
14, // 4
|
|
13, // 5
|
|
12, // 6
|
|
11, // 7
|
|
23, // 8
|
|
22, // 9
|
|
21, // 10
|
|
20, // 11
|
|
19, // 12
|
|
18, // 13
|
|
17, // 14
|
|
16 }; // 15
|
|
|
|
KIRQL HalpTranslateVectorToIrql(
|
|
IN ULONG Vector
|
|
)
|
|
{ // It is assumed that the caller has checked that Vector is valid (0..15)
|
|
return VectorToIrql[Vector];
|
|
}
|
|
|
|
//
|
|
// Add spurious and bogus interrupt counts
|
|
//
|
|
|
|
#if DBG
|
|
ULONG HalpSpuriousInterruptCount = 0;
|
|
ULONG HalpBogusInterruptCount = 0;
|
|
#endif
|
|
|
|
|
|
//
|
|
// Define Isa bus interrupt affinity.
|
|
//
|
|
|
|
KAFFINITY HalpIsaBusAffinity;
|
|
|
|
|
|
//
|
|
// The following function is called when a machine check occurs.
|
|
//
|
|
|
|
BOOLEAN
|
|
HalpHandleMachineCheck(
|
|
IN PKINTERRUPT Interrupt,
|
|
IN PVOID ServiceContext
|
|
);
|
|
|
|
//
|
|
// Define save area for ISA adapter objects.
|
|
//
|
|
|
|
PADAPTER_OBJECT HalpIsaAdapter[8];
|
|
|
|
//
|
|
// Define save area for ISA interrupt mask registers
|
|
// and level\edge control registers.
|
|
//
|
|
|
|
USHORT HalpSioInterruptLevel = 0x0000; // Default to edge-sensitive
|
|
|
|
|
|
|
|
BOOLEAN
|
|
HalpInitializeInterrupts (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called from phase 0 initialization, it initializes the
|
|
8259 interrupt controller ( currently it masks all 8259 interrupts).
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
{ UCHAR DataByte;
|
|
ULONG Vector;
|
|
|
|
|
|
//
|
|
// 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_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort0,
|
|
DataByte
|
|
);
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort0,
|
|
DataByte
|
|
);
|
|
|
|
//
|
|
// The second initialization control word sets the interrupt vector to
|
|
// 0-15.
|
|
//
|
|
|
|
DataByte = 0;
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1,
|
|
DataByte
|
|
);
|
|
|
|
DataByte = 0x08;
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->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(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1,
|
|
DataByte
|
|
);
|
|
|
|
DataByte = SLAVE_IRQL_LEVEL;
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->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(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1,
|
|
DataByte
|
|
);
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1,
|
|
DataByte
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// Mask all 8259 interrupts (except the Slave input)
|
|
//
|
|
|
|
for (Vector=0; Vector<= HIGHEST_8259_VECTOR; Vector++) {
|
|
HalpDisableSioInterrupt(Vector + DEVICE_VECTORS);
|
|
}
|
|
HalpEnableSioInterrupt(SLAVE_IRQL_LEVEL + DEVICE_VECTORS, Latched);
|
|
|
|
//
|
|
// Reserve the external interrupt vector for exclusive use by the HAL.
|
|
//
|
|
|
|
PCR->ReservedVectors |= (1 << EXTERNAL_INTERRUPT_VECTOR);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
HalpCreateSioStructures (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the structures necessary for SIO operations
|
|
and connects the intermediate interrupt dispatcher.
|
|
|
|
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 Machine Check interrupt handler
|
|
//
|
|
|
|
if (HalpEnableInterruptHandler(&HalpMachineCheckInterrupt,
|
|
HalpHandleMachineCheck,
|
|
NULL,
|
|
NULL,
|
|
MACHINE_CHECK_VECTOR,
|
|
MACHINE_CHECK_LEVEL,
|
|
MACHINE_CHECK_LEVEL,
|
|
Latched,
|
|
FALSE,
|
|
0,
|
|
FALSE,
|
|
InternalUsage,
|
|
MACHINE_CHECK_VECTOR
|
|
) == FALSE) {
|
|
KeBugCheck(HAL_INITIALIZATION_FAILED);
|
|
}
|
|
|
|
//
|
|
// Enable NMI IOCHK# and PCI SERR#
|
|
//
|
|
|
|
DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->NmiStatus);
|
|
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->NmiStatus,
|
|
DataByte & ~DISABLE_IOCHK_NMI & ~DISABLE_PCI_SERR_NMI);
|
|
|
|
//
|
|
// Clear the SIO NMI disable bit. This bit is the high order of the
|
|
// NMI enable register.
|
|
//
|
|
|
|
DataByte = 0;
|
|
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->NmiEnable,
|
|
DataByte
|
|
);
|
|
|
|
//
|
|
// Connect the external interrupt handler
|
|
//
|
|
|
|
PCR->InterruptRoutine[EXTERNAL_INTERRUPT_VECTOR] = (PKINTERRUPT_ROUTINE) HalpHandleExternalInterrupt;
|
|
|
|
//
|
|
// register the interrupt vector
|
|
//
|
|
|
|
HalpRegisterVector(InternalUsage,
|
|
EXTERNAL_INTERRUPT_VECTOR,
|
|
EXTERNAL_INTERRUPT_VECTOR,
|
|
HIGH_LEVEL);
|
|
|
|
|
|
|
|
|
|
// Connect directly to the decrementer handler. This is done
|
|
// directly rather than thru HalpEnableInterruptHandler due to
|
|
// special handling required because the handler calls KdPollBreakIn().
|
|
//
|
|
|
|
PCR->InterruptRoutine[DECREMENT_VECTOR] = (PKINTERRUPT_ROUTINE) HalpHandleDecrementerInterrupt;
|
|
|
|
|
|
//
|
|
// Initialize and connect the Timer 1 interrupt (IRQ0)
|
|
//
|
|
|
|
if (HalpEnableInterruptHandler( &HalpProfileInterrupt,
|
|
(PKSERVICE_ROUTINE) HalpHandleProfileInterrupt,
|
|
(PVOID) NULL,
|
|
(PKSPIN_LOCK)NULL,
|
|
PROFILE_VECTOR,
|
|
PROFILE_LEVEL,
|
|
PROFILE_LEVEL,
|
|
Latched,
|
|
TRUE,
|
|
0,
|
|
FALSE,
|
|
DeviceUsage,
|
|
PROFILE_VECTOR
|
|
) == FALSE) {
|
|
KeBugCheck(HAL_INITIALIZATION_FAILED);
|
|
}
|
|
|
|
|
|
//
|
|
// Disable Timer 1; only used by profiling
|
|
//
|
|
|
|
HalDisableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL);
|
|
|
|
//
|
|
// Set default profile rate
|
|
//
|
|
|
|
HalSetProfileInterval(5000);
|
|
|
|
//
|
|
// Raise the IRQL while the SIO interrupt controller is initialized.
|
|
//
|
|
|
|
KeRaiseIrql(CLOCK2_LEVEL, &oldIrql);
|
|
|
|
//
|
|
// Initialize any planar registers
|
|
//
|
|
|
|
HalpInitPlanar();
|
|
|
|
|
|
//
|
|
// Enable the clock interrupt
|
|
//
|
|
HalpUpdateDecrementer(1000); // Get those decrementer ticks going
|
|
|
|
|
|
//
|
|
// Set ISA bus interrupt affinity.
|
|
//
|
|
|
|
HalpIsaBusAffinity = PCR->SetMember;
|
|
|
|
|
|
//
|
|
// Restore IRQL level.
|
|
//
|
|
|
|
KeLowerIrql(oldIrql);
|
|
|
|
|
|
//
|
|
// DMA command - set assert level
|
|
//
|
|
|
|
DataByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Dma1BasePort.DmaStatus);
|
|
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Dma1BasePort.DmaStatus,
|
|
DataByte & ~DACK_ASSERT_HIGH & ~DREQ_ASSERT_LOW);
|
|
|
|
//
|
|
// 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(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Dma1BasePort.AllMask,
|
|
0x0F
|
|
);
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Dma2BasePort.AllMask,
|
|
0x0E
|
|
);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOLEAN
|
|
HalpMapIoControlSpace (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine maps the HAL SIO control space for a PowerPC system.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
If the initialization is successfully completed, then a value of TRUE
|
|
is returned. Otherwise, a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
|
|
PHYSICAL_ADDRESS physicalAddress;
|
|
|
|
//
|
|
// Map SIO control space.
|
|
//
|
|
|
|
physicalAddress.HighPart = 0;
|
|
physicalAddress.LowPart = IO_CONTROL_PHYSICAL_BASE;
|
|
HalpIoControlBase = MmMapIoSpace(physicalAddress,
|
|
PAGE_SIZE * 16,
|
|
FALSE);
|
|
|
|
|
|
if (HalpIoControlBase == NULL)
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
HalpHandleExternalInterrupt(
|
|
IN PKINTERRUPT Interrupt,
|
|
IN PVOID ServiceContext,
|
|
IN PVOID 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 SIO device interrupts. Its function is to call the second
|
|
level interrupt dispatch routine and acknowledge the interrupt at the SIO
|
|
controller.
|
|
|
|
N.B. This routine is entered and left with external interrupts disabled.
|
|
|
|
|
|
Arguments:
|
|
|
|
Interrupt - Supplies a pointer to the interrupt object.
|
|
|
|
ServiceContext - Supplies a pointer to the SIO interrupt acknowledge
|
|
register.
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Returns the value returned from the second level routine.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSECONDARY_DISPATCH SioHandler;
|
|
PKINTERRUPT SioInterrupt;
|
|
USHORT interruptVector;
|
|
BOOLEAN returnValue;
|
|
UCHAR OldIrql;
|
|
USHORT Isr;
|
|
UCHAR Irql;
|
|
|
|
|
|
//
|
|
// Read the interrupt vector.
|
|
//
|
|
|
|
interruptVector = READ_REGISTER_UCHAR(HalpInterruptBase);
|
|
|
|
//
|
|
// check for nmi interrupt before we raise irql since we would raise to a
|
|
// bogus level
|
|
//
|
|
|
|
if (interruptVector == 0xFF) {
|
|
|
|
HalpHandleMachineCheck(NULL, NULL);
|
|
}
|
|
|
|
//
|
|
// check for spurious interrupt
|
|
//
|
|
|
|
if (interruptVector == SPURIOUS_VECTOR) {
|
|
|
|
WRITE_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Interrupt1ControlPort0,
|
|
0x0B);
|
|
Isr = READ_REGISTER_UCHAR(&((PEISA_CONTROL)HalpIoControlBase)->Interrupt1ControlPort0);
|
|
if (!(Isr & 0x80)) {
|
|
|
|
//
|
|
// Spurious interrupt
|
|
//
|
|
|
|
#if DBG
|
|
//DbgPrint("A spurious interrupt occurred. \n");
|
|
HalpSpuriousInterruptCount++;
|
|
#endif
|
|
return(0);
|
|
|
|
}
|
|
}
|
|
|
|
if (interruptVector > HIGHEST_8259_VECTOR) {
|
|
#if DBG
|
|
DbgPrint("A bogus interrupt (0x%02x) occurred. \n", interruptVector);
|
|
HalpBogusInterruptCount++;
|
|
#endif
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// Translate vector to IRQL and raise IRQL
|
|
//
|
|
|
|
Irql = HalpTranslateVectorToIrql(interruptVector);
|
|
KeRaiseIrql( Irql, &OldIrql);
|
|
|
|
//
|
|
// Dispatch to the secondary interrupt service routine.
|
|
//
|
|
|
|
SioHandler = (PSECONDARY_DISPATCH)
|
|
PCR->InterruptRoutine[DEVICE_VECTORS + interruptVector];
|
|
SioInterrupt = CONTAINING_RECORD(SioHandler,
|
|
KINTERRUPT,
|
|
DispatchCode[0]);
|
|
|
|
returnValue = SioHandler(SioInterrupt,
|
|
SioInterrupt->ServiceContext,
|
|
TrapFrame
|
|
);
|
|
|
|
//
|
|
// Dismiss the interrupt in the SIO interrupt controllers.
|
|
//
|
|
|
|
//
|
|
// If this is a cascaded interrupt then the interrupt must be dismissed in
|
|
// both controllers.
|
|
//
|
|
|
|
if (interruptVector & 0x08) {
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort0,
|
|
NONSPECIFIC_END_OF_INTERRUPT
|
|
);
|
|
|
|
}
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort0,
|
|
NONSPECIFIC_END_OF_INTERRUPT
|
|
);
|
|
|
|
//
|
|
// Lower IRQL but disable external interrupts.
|
|
// Return to caller with interrupts disabled.
|
|
//
|
|
|
|
|
|
HalpResetIrqlAfterInterrupt(OldIrql);
|
|
|
|
return(returnValue);
|
|
|
|
}
|
|
|
|
VOID
|
|
HalpDisableSioInterrupt(
|
|
IN ULONG Vector
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function Disables the SIO interrupt.
|
|
|
|
Arguments:
|
|
|
|
Vector - Supplies the vector of the ESIA interrupt that is Disabled.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{ USHORT MaskBit, i;
|
|
|
|
//
|
|
// Calculate the SIO interrupt vector.
|
|
//
|
|
Vector -= DEVICE_VECTORS;
|
|
|
|
if (Vector <= HIGHEST_8259_VECTOR) {
|
|
//
|
|
// Generate 8259 mask
|
|
//
|
|
MaskBit = (USHORT) (1 << Vector);
|
|
|
|
//
|
|
// Set the mask bit in Halp8259MaskTable
|
|
//
|
|
for (i = 0; i <= 31; i++) {
|
|
Halp8259MaskTable[i] |= MaskBit;
|
|
}
|
|
|
|
// Write new mask values to 8259s
|
|
HalpUpdate8259(PCR->CurrentIrql);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HalpIsaMapTransfer(
|
|
IN PADAPTER_OBJECT AdapterObject,
|
|
IN ULONG Offset,
|
|
IN ULONG Length,
|
|
IN BOOLEAN WriteToDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function programs the SIO 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;
|
|
UCHAR dataByte;
|
|
KIRQL Irql;
|
|
|
|
|
|
ASSERT(Offset >= IO_CONTROL_PHYSICAL_BASE);
|
|
|
|
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 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)
|
|
);
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
//
|
|
// Determine the mode based on the transfer direction.
|
|
//
|
|
|
|
((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ?
|
|
WRITE_TRANSFER : READ_TRANSFER);
|
|
|
|
BytePtr = (PUCHAR) &Offset;
|
|
|
|
if (AdapterObject->Width16Bits) {
|
|
|
|
//
|
|
// If this is a 16 bit transfer then adjust the length and the address
|
|
// for the 16 bit DMA mode.
|
|
//
|
|
|
|
Length >>= 1;
|
|
|
|
//
|
|
// In 16 bit DMA mode the low 16 bits are shifted right one and the
|
|
// page register value is unchanged. So save the page register value
|
|
// and shift the logical address then restore the page value.
|
|
//
|
|
|
|
dataByte = BytePtr[2];
|
|
Offset >>= 1;
|
|
BytePtr[2] = dataByte;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// grab the spinlock for the system DMA controller
|
|
//
|
|
|
|
KeAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock, &Irql );
|
|
|
|
//
|
|
// Determine the controller number based on the Adapter number.
|
|
//
|
|
|
|
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 );
|
|
|
|
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) HalpIoControlBase)->DmaPageLowPort) +
|
|
(ULONG)AdapterObject->PagePort,
|
|
BytePtr[2]
|
|
);
|
|
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->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 );
|
|
|
|
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) HalpIoControlBase)->DmaPageLowPort) +
|
|
(ULONG)AdapterObject->PagePort,
|
|
BytePtr[2]
|
|
);
|
|
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
((PUCHAR) &((PEISA_CONTROL) HalpIoControlBase)->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)
|
|
);
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock (&AdapterObject->MasterAdapter->SpinLock, Irql);
|
|
|
|
}
|
|
|
|
VOID
|
|
HalpEnableSioInterrupt(
|
|
IN ULONG Vector,
|
|
IN KINTERRUPT_MODE InterruptMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables the SIO interrupt and sets
|
|
the level/edge register to the requested value.
|
|
|
|
Arguments:
|
|
|
|
Vector - Supplies the vector of the interrupt that is enabled.
|
|
|
|
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
|
|
Latched.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{ USHORT MaskBit, Irql, i;
|
|
|
|
//
|
|
// Calculate the SIO interrupt vector.
|
|
//
|
|
Vector -= DEVICE_VECTORS;
|
|
|
|
if (Vector <= HIGHEST_8259_VECTOR) {
|
|
//
|
|
// Generate 8259 mask
|
|
//
|
|
MaskBit = (USHORT) ~(1 << Vector);
|
|
|
|
|
|
//
|
|
// Force interrupts to be latched (edge-triggered) if Big Bend
|
|
//
|
|
if(HalpSystemType == MOTOROLA_BIG_BEND)
|
|
InterruptMode = Latched;
|
|
|
|
//
|
|
// Set the level/edge control register.
|
|
//
|
|
if (InterruptMode == LevelSensitive) {
|
|
HalpSioInterruptLevel |= ~MaskBit;
|
|
} else {
|
|
HalpSioInterruptLevel &= MaskBit;
|
|
}
|
|
|
|
if (Vector & 0x08) {
|
|
|
|
//
|
|
// The interrupt is in controller 2.
|
|
//
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt2EdgeLevel,
|
|
(UCHAR) (HalpSioInterruptLevel >> 8)
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// The interrupt is in controller 1.
|
|
//
|
|
|
|
WRITE_REGISTER_UCHAR(
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Interrupt1EdgeLevel,
|
|
(UCHAR) HalpSioInterruptLevel
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// Clear mask bit in Halp8259MaskTable
|
|
//
|
|
Irql = VectorToIrql[Vector];
|
|
for (i = 0; i < Irql; i++) {
|
|
Halp8259MaskTable[i] &= MaskBit;
|
|
}
|
|
|
|
// Write new mask values to 8259s
|
|
HalpUpdate8259(PCR->CurrentIrql);
|
|
}
|
|
}
|
|
|
|
PADAPTER_OBJECT
|
|
HalpAllocateIsaAdapter(
|
|
IN PDEVICE_DESCRIPTION DeviceDescriptor,
|
|
OUT PULONG NumberOfMapRegisters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocates an ISA 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.
|
|
|
|
NumberofMapRegisters - number of map registers required for the adapter
|
|
object created
|
|
|
|
|
|
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 numberOfMapRegisters;
|
|
ULONG controllerNumber;
|
|
DMA_EXTENDED_MODE extendedMode;
|
|
UCHAR adapterMode;
|
|
BOOLEAN useChannel;
|
|
ULONG maximumLength;
|
|
|
|
//
|
|
// Determine if the the channel number is important. Master cards
|
|
// do not use a channel number.
|
|
//
|
|
|
|
|
|
if ((DeviceDescriptor->Master) && (DeviceDescriptor->InterfaceType != Isa)) {
|
|
|
|
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);
|
|
}
|
|
|
|
//
|
|
// Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES
|
|
// macro works correctly.
|
|
//
|
|
|
|
maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff;
|
|
|
|
//
|
|
// Determine the number of map registers for this device.
|
|
//
|
|
|
|
if (DeviceDescriptor->ScatterGather &&
|
|
!(DeviceDescriptor->InterfaceType == Isa &&
|
|
DeviceDescriptor->Master)) {
|
|
|
|
|
|
//
|
|
// Scatter gather not supported in SIO
|
|
//
|
|
|
|
if (!DeviceDescriptor->Master)
|
|
|
|
//
|
|
// one map register will be required when the the SIO supports this
|
|
//
|
|
// numberOfMapRegisters = 1;
|
|
|
|
return NULL;
|
|
|
|
|
|
//
|
|
// Since the device support scatter/Gather then map registers are not
|
|
// required.
|
|
//
|
|
|
|
numberOfMapRegisters = 0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Determine the number of map registers required based on the maximum
|
|
// transfer length, up to a maximum number.
|
|
//
|
|
|
|
numberOfMapRegisters = BYTES_TO_PAGES(maximumLength)
|
|
+ 1;
|
|
numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ?
|
|
MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters;
|
|
|
|
//
|
|
// If the device is not a master then it only needs one map register
|
|
// and does scatter/Gather.
|
|
//
|
|
|
|
if (DeviceDescriptor->ScatterGather && !DeviceDescriptor->Master) {
|
|
|
|
numberOfMapRegisters = 1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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) HalpIoControlBase)->Dma1BasePort;
|
|
|
|
} else {
|
|
|
|
controllerNumber = 2;
|
|
adapterBaseVa = &((PEISA_CONTROL) HalpIoControlBase)->Dma2BasePort;
|
|
|
|
}
|
|
|
|
//
|
|
// Determine if a new adapter object is necessary. If so then allocate it.
|
|
//
|
|
|
|
if (useChannel && HalpIsaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
|
|
|
|
adapterObject = HalpIsaAdapter[DeviceDescriptor->DmaChannel];
|
|
|
|
if (adapterObject->NeedsMapRegisters) {
|
|
|
|
if (numberOfMapRegisters > adapterObject->MapRegistersPerChannel) {
|
|
|
|
adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Allocate an adapter object.
|
|
//
|
|
|
|
adapterObject = (PADAPTER_OBJECT) HalpAllocateAdapter(
|
|
numberOfMapRegisters,
|
|
adapterBaseVa,
|
|
NULL
|
|
);
|
|
|
|
if (adapterObject == NULL) {
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
if (useChannel) {
|
|
|
|
HalpIsaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the maximum number of map registers for this channel bus on
|
|
// the number requested and the type of device.
|
|
//
|
|
|
|
if (numberOfMapRegisters) {
|
|
|
|
//
|
|
// The specified number of registers are actually allowed to be
|
|
// allocated.
|
|
//
|
|
|
|
adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
|
|
|
|
//
|
|
// Increase the commitment for the map registers.
|
|
//
|
|
|
|
if (DeviceDescriptor->Master) {
|
|
|
|
//
|
|
// Master I/O devices use several sets of map registers double
|
|
// their commitment.
|
|
//
|
|
|
|
MasterAdapterObject->CommittedMapRegisters +=
|
|
numberOfMapRegisters * 2;
|
|
|
|
} else {
|
|
|
|
MasterAdapterObject->CommittedMapRegisters +=
|
|
numberOfMapRegisters;
|
|
|
|
}
|
|
|
|
//
|
|
// If the committed map registers is significantly greater than the
|
|
// number allocated then grow the map buffer.
|
|
//
|
|
|
|
if (MasterAdapterObject->CommittedMapRegisters >
|
|
MasterAdapterObject->NumberOfMapRegisters &&
|
|
MasterAdapterObject->CommittedMapRegisters -
|
|
MasterAdapterObject->NumberOfMapRegisters >
|
|
MAXIMUM_ISA_MAP_REGISTER ) {
|
|
|
|
HalpGrowMapBuffers(
|
|
MasterAdapterObject,
|
|
INCREMENT_MAP_BUFFER_SIZE
|
|
);
|
|
}
|
|
|
|
adapterObject->NeedsMapRegisters = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// No real map registers were allocated. If this is a master
|
|
// device, then the device can have as may registers as it wants.
|
|
//
|
|
|
|
adapterObject->NeedsMapRegisters = FALSE;
|
|
|
|
if (DeviceDescriptor->Master) {
|
|
|
|
adapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(
|
|
maximumLength
|
|
)
|
|
+ 1;
|
|
|
|
} else {
|
|
|
|
//
|
|
// The device only gets one register. It must call
|
|
// IoMapTransfer repeatedly to do a large transfer.
|
|
//
|
|
|
|
adapterObject->MapRegistersPerChannel = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
adapterObject->ScatterGather = DeviceDescriptor->ScatterGather;
|
|
|
|
if (DeviceDescriptor->Master) {
|
|
|
|
adapterObject->MasterDevice = TRUE;
|
|
|
|
} else {
|
|
|
|
adapterObject->MasterDevice = FALSE;
|
|
|
|
}
|
|
|
|
if (DeviceDescriptor->Master && (DeviceDescriptor->InterfaceType == Isa)) {
|
|
|
|
adapterObject->IsaBusMaster = TRUE;
|
|
|
|
} else {
|
|
|
|
adapterObject->IsaBusMaster = FALSE;
|
|
|
|
}
|
|
|
|
//
|
|
// If the channel number is not used then we are finished. The rest of
|
|
// the work deals with channels.
|
|
//
|
|
|
|
*NumberOfMapRegisters = adapterObject->MapRegistersPerChannel;
|
|
|
|
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 = (PUCHAR) &((PDMA_PAGE) 0)->Channel0;
|
|
break;
|
|
|
|
case 1:
|
|
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1;
|
|
break;
|
|
|
|
case 2:
|
|
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2;
|
|
break;
|
|
|
|
case 3:
|
|
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the adapter number.
|
|
//
|
|
|
|
adapterObject->AdapterNumber = 1;
|
|
|
|
//
|
|
// Save the extended mode register address.
|
|
//
|
|
|
|
adapterBaseVa =
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Dma1ExtendedModePort;
|
|
|
|
} else {
|
|
|
|
switch (channelNumber) {
|
|
case 1:
|
|
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5;
|
|
break;
|
|
|
|
case 2:
|
|
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6;
|
|
break;
|
|
|
|
case 3:
|
|
adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the adapter number.
|
|
//
|
|
|
|
adapterObject->AdapterNumber = 2;
|
|
|
|
//
|
|
// Save the extended mode register address.
|
|
//
|
|
adapterBaseVa =
|
|
&((PEISA_CONTROL) HalpIoControlBase)->Dma2ExtendedModePort;
|
|
|
|
}
|
|
|
|
|
|
adapterObject->Width16Bits = FALSE;
|
|
|
|
|
|
//
|
|
// Initialize 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;
|
|
|
|
//
|
|
// Note Width16bits should not be set here because there is no need
|
|
// to shift the address and the transfer count.
|
|
//
|
|
|
|
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 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)
|
|
);
|
|
|
|
}
|
|
|
|
} 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);
|
|
}
|
|
|
|
ULONG
|
|
HalReadDmaCounter(
|
|
IN PADAPTER_OBJECT AdapterObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function reads the DMA counter and returns the number of bytes left
|
|
to be transferred.
|
|
|
|
Arguments:
|
|
|
|
AdapterObject - Supplies a pointer to the adapter object to be read.
|
|
|
|
Return Value:
|
|
|
|
Returns the number of bytes still to be transferred.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG count=0;
|
|
ULONG high;
|
|
|
|
if (AdapterObject->PagePort) {
|
|
|
|
//
|
|
// Determine the controller number based on the Adapter number.
|
|
//
|
|
|
|
if (AdapterObject->AdapterNumber == 1) {
|
|
|
|
//
|
|
// This request is for DMA controller 1
|
|
//
|
|
|
|
PDMA1_CONTROL dmaControl;
|
|
|
|
dmaControl = AdapterObject->AdapterBaseVa;
|
|
|
|
//
|
|
// Initialize count to a value which will not match.
|
|
//
|
|
|
|
count = 0xFFFF00;
|
|
|
|
//
|
|
// Loop until the same high byte is read twice.
|
|
//
|
|
|
|
do {
|
|
|
|
high = count;
|
|
|
|
WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 );
|
|
|
|
//
|
|
// Read the current DMA count.
|
|
//
|
|
|
|
count = READ_REGISTER_UCHAR(
|
|
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
|
.DmaBaseCount
|
|
);
|
|
|
|
count |= READ_REGISTER_UCHAR(
|
|
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
|
.DmaBaseCount
|
|
) << 8;
|
|
|
|
} while ((count & 0xFFFF00) != (high & 0xFFFF00));
|
|
|
|
} else {
|
|
|
|
//
|
|
// This request is for DMA controller 2
|
|
//
|
|
|
|
PDMA2_CONTROL dmaControl;
|
|
|
|
dmaControl = AdapterObject->AdapterBaseVa;
|
|
|
|
//
|
|
// Initialize count to a value which will not match.
|
|
//
|
|
|
|
count = 0xFFFF00;
|
|
|
|
//
|
|
// Loop until the same high byte is read twice.
|
|
//
|
|
|
|
do {
|
|
|
|
high = count;
|
|
|
|
WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 );
|
|
|
|
//
|
|
// Read the current DMA count.
|
|
//
|
|
|
|
count = READ_REGISTER_UCHAR(
|
|
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
|
.DmaBaseCount
|
|
);
|
|
|
|
count |= READ_REGISTER_UCHAR(
|
|
&dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
|
|
.DmaBaseCount
|
|
) << 8;
|
|
|
|
} while ((count & 0xFFFF00) != (high & 0xFFFF00));
|
|
|
|
}
|
|
|
|
//
|
|
// The DMA counter has a bias of one and can only be 16 bit long.
|
|
//
|
|
|
|
count = (count + 1) & 0xFFFF;
|
|
|
|
}
|
|
|
|
return(count);
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpHandleIoError (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
|
|
UCHAR StatusByte;
|
|
|
|
|
|
//
|
|
// Read NMI status
|
|
//
|
|
|
|
StatusByte = READ_REGISTER_UCHAR(&((PEISA_CONTROL) HalpIoControlBase)->NmiStatus);
|
|
|
|
//
|
|
// Test for PCI bus error
|
|
//
|
|
|
|
if (StatusByte & 0x40) {
|
|
HalDisplayString ("NMI: IOCHK\n");
|
|
}
|
|
|
|
//
|
|
// Test for ISA IOCHK
|
|
//
|
|
|
|
if (StatusByte & 0x80) {
|
|
HalDisplayString ("NMI: PCI System Error\n");
|
|
}
|
|
|
|
}
|
|
|
|
|