diff options
Diffstat (limited to 'private/ntos/nthals/haleagle/ppc/pxsiosup.c')
-rw-r--r-- | private/ntos/nthals/haleagle/ppc/pxsiosup.c | 1761 |
1 files changed, 1761 insertions, 0 deletions
diff --git a/private/ntos/nthals/haleagle/ppc/pxsiosup.c b/private/ntos/nthals/haleagle/ppc/pxsiosup.c new file mode 100644 index 000000000..1cd1c9789 --- /dev/null +++ b/private/ntos/nthals/haleagle/ppc/pxsiosup.c @@ -0,0 +1,1761 @@ +/*++ + +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 (jimw@vnet.ibm.com) + + +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"); + } + +} + + |