diff options
Diffstat (limited to 'private/ntos/nthals/halppc/ppc/pxsiosup.c')
-rw-r--r-- | private/ntos/nthals/halppc/ppc/pxsiosup.c | 2218 |
1 files changed, 2218 insertions, 0 deletions
diff --git a/private/ntos/nthals/halppc/ppc/pxsiosup.c b/private/ntos/nthals/halppc/ppc/pxsiosup.c new file mode 100644 index 000000000..64c20c2e6 --- /dev/null +++ b/private/ntos/nthals/halppc/ppc/pxsiosup.c @@ -0,0 +1,2218 @@ +/*++ + +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. + +Copyright (c) 1996 International Business Machines Corporation + +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 "eisa.h" +#include "pxsiosup.h" +#include <pxmemctl.h> +#include "bugcodes.h" + +extern UCHAR VectorToIrqlTable[]; + +#define SioId 0x04848086 + +PVOID HalpPciIsaBridgeConfigBase; + +extern PADAPTER_OBJECT MasterAdapterObject; +extern ULONG HalpPciMaxSlots; +extern ULONG HalpPhase0GetPciDataByOffset(); +extern ULONG HalpPhase0SetPciDataByOffset(); + +// +// Define the context structure for use by the interrupt routine. +// + + +typedef BOOLEAN (*PSECONDARY_DISPATCH)( + PVOID InterruptRoutine, + PVOID ServiceContext, + PVOID TrapFrame + ); + +// +// Declare the interupt 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 interupt structure for machine checks +// + +KINTERRUPT HalpMachineCheckInterrupt; + +// +// Declare the interupt structure for the clock interrupt +// + +KINTERRUPT HalpDecrementerInterrupt; + + +// +// 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 resiters and level\edge control +// registers. +// + +#define ISA_CONTROL ((PEISA_CONTROL) HalpIoControlBase) +extern UCHAR HalpSioInterrupt1Mask; +extern UCHAR HalpSioInterrupt2Mask; +extern USHORT Halp8259MaskTable[]; + +UCHAR HalpSioInterrupt1Mask = 0xff; +UCHAR HalpSioInterrupt2Mask = 0xff; +UCHAR HalpSioInterrupt1Level; +UCHAR HalpSioInterrupt2Level; + +#if defined(SOFT_HDD_LAMP) + +// +// On PowerPC machines the HDD lamp is software driven. We +// turn it on any time we take an interrupt from a Mass Storage +// Controller (assuming it isn't already on) and turn it off the 2nd +// clock tick after we turn it on if we have not received +// any more MSC interrupts since the first clock tick. +// + +HDD_LAMP_STATUS HalpHddLamp; + +ULONG HalpMassStorageControllerVectors; + +#endif + +#ifdef POWER_MANAGEMENT +// +// Define save area for DMA channel extended mode. +// + +DMA_EXTENDED_MODE Dma1ExtendedMode[4]; +DMA_EXTENDED_MODE Dma2ExtendedMode[4]; + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGELK, HalpInitInterruptController) +#pragma alloc_text(PAGELK, HalpInitDmaController) +#endif // ALLOC_PRAGMA + +#endif // POWER_MANAGEMENT + + +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: + + +--*/ + +{ + ULONG Vector; + + // + // Mask all 8259 interrupts (except the cascade interrupt) + // + + for (Vector=0;Vector<16;Vector++) { + if (Vector == 2) + continue; + HalpDisableSioInterrupt(Vector + DEVICE_VECTORS); + } + + // + // 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. It also initializes the + SIO interrupt controller. + +Arguments: + + None. + +Return Value: + + If the second level interrupt dispatcher is connected, then a value of + TRUE is returned. Otherwise, a value of FALSE is returned. + +--*/ + +{ + + UCHAR DataByte; + KIRQL oldIrql; + + + // + // Initialize the 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 initalized. + // + + KeRaiseIrql(CLOCK2_LEVEL, &oldIrql); + + + + // + // Initialize any planar registers + // + + HalpInitPlanar(); + + // + // Initialize the PCI/ISA bridge chip + // + + HalpInitPciIsaBridge(); + + + + // + // 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 intitialization control word sets the iterrupt 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 thrid initialization control word set the controls for slave mode. + // The master ICW3 uses bit position and the slave ICW3 uses a numberic. + // + + DataByte = 1 << SLAVE_IRQL_LEVEL; + + WRITE_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 + ); + + + // + // Disable all of the interrupts except the slave. + // + + HalpSioInterrupt1Mask = (UCHAR) ~(1 << SLAVE_IRQL_LEVEL); + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, + HalpSioInterrupt1Mask + ); + + HalpSioInterrupt2Mask = 0xFF; + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, + HalpSioInterrupt2Mask + ); + + // + // Initialize the edge/level register masks to 0 which is the default + // edge sensitive value. + // + + HalpSioInterrupt1Level = 0; + HalpSioInterrupt2Level = 0; + + // + // 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 +HalpInitPciIsaBridge ( + VOID + ) + + +{ + + UCHAR DataByte; + BOOLEAN Found; + ULONG SlotNumber; + ULONG ChipId; + ULONG BufferLength; + + + Found = FALSE; + SlotNumber = 0; + + while (!Found && SlotNumber < HalpPciMaxSlots) { + + BufferLength = HalpPhase0GetPciDataByOffset(0, + SlotNumber, + &ChipId, + 0, + sizeof(ChipId)); + if (ChipId == SioId) + Found = TRUE; + else + SlotNumber++; + + + } + + // + // Make sure that we found a valid chip id + // + + if (!Found) + return FALSE; + + // + // Define macros for reading and writing to the SIO config space + // + +#define READ_SIO_CONFIG_UCHAR(offset,byte) \ + ( \ + HalpPhase0GetPciDataByOffset( \ + 0, \ + SlotNumber, \ + &byte, \ + FIELD_OFFSET(SIO_CONFIG,offset), \ + 1 \ + ) \ + ) + +#define WRITE_SIO_CONFIG_UCHAR(offset,byte) \ + ( \ + HalpPhase0SetPciDataByOffset( \ + 0, \ + SlotNumber, \ + &byte, \ + FIELD_OFFSET(SIO_CONFIG,offset), \ + 1 \ + ) \ + ) + + + + // + // Enable ISA Master line buffering + // + + + + READ_SIO_CONFIG_UCHAR(PciControl,DataByte); + + DataByte |= ENABLE_PCI_POSTED_WRITE_BUFFER + | ENABLE_ISA_MASTER_LINE_BUFFER + | EANBLE_DMA_LINE_BUFFER; + + WRITE_SIO_CONFIG_UCHAR(PciControl, DataByte ); + + // + // Disable Gauranteed Access Time Mode + // + + READ_SIO_CONFIG_UCHAR(PciArbiterControl,DataByte); + + DataByte &= ~ENABLE_GAT; + + WRITE_SIO_CONFIG_UCHAR(PciArbiterControl, DataByte); + + + + + // + // Initialize SuperIO chip + // + + if (!HalpInitSuperIo()) + + return FALSE; + + + // + // Utility Bus A chip select + // + + READ_SIO_CONFIG_UCHAR(UtilityBusEnableA,DataByte); + + DataByte |= ENABLE_RTC | ENABLE_KEYBOARD & ~ENABLE_IDE_DECODE; + + WRITE_SIO_CONFIG_UCHAR(UtilityBusEnableA, DataByte); + + // + // Utility Bus B chip select + // + + READ_SIO_CONFIG_UCHAR(UtilityBusEnableB,DataByte); + + DataByte |= ENABLE_RAM_DECODE | ENABLE_PORT92 | DISABLE_PARALLEL_PORT + | DISABLE_SERIAL_PORTA | DISABLE_SERIAL_PORTB; + + WRITE_SIO_CONFIG_UCHAR(UtilityBusEnableB, DataByte); + + 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, than 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 in 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; + PUCHAR PIC_Address; + UCHAR PIC_Mask; + + + // + // Read the interrupt vector. + // + + interruptVector = READ_REGISTER_UCHAR(HalpInterruptBase); + + // + // 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 + HalpSpuriousInterruptCount++; +#endif + return(0); + + } + } + +#if defined(SOFT_HDD_LAMP) + + if ( HalpMassStorageControllerVectors & (1 << interruptVector) ) { + // + // On any Mass Storage Controller interrupt, light the HDD lamp. + // The system timer routines will turn it off again in a little + // while. + // + + if ( !HalpHddLamp.Count ) { + *(PUCHAR)((PUCHAR)HalpIoControlBase + HDD_LAMP_PORT) = 1; + } + HalpHddLamp.Count = SOFT_HDD_TICK_COUNT; + } + +#endif + + // + // raise irql + // + + Irql = VectorToIrqlTable[interruptVector]; + + OldIrql = PCR->CurrentIrql; + PCR->CurrentIrql = Irql; + + HalpEnableInterrupts(); + + // + // 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. We disable + // interrupts first so we won't get multiple interrupts at this level + // without popping the stack. + // + + HalpDisableInterrupts(); + + // + // 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 leave external interrupts disabled. + // Return to caller with interrupts disabled. + // + + PCR->CurrentIrql = OldIrql; + + // + // Partial lazy irql - if hardware irql mask isn't what is should be + // set it and the interrupt controllers mask. + // + + if (HALPCR->HardPriority != PCR->CurrentIrql) { + + HALPCR->HardPriority = OldIrql; + + PIC_Mask = HalpSioInterrupt1Mask | (Halp8259MaskTable[OldIrql] & 0x00FF); + PIC_Address = &(ISA_CONTROL->Interrupt1ControlPort1); + WRITE_REGISTER_UCHAR(PIC_Address, PIC_Mask); + + // + // Get contoller 2 interrupt mask + // + + PIC_Mask = HalpSioInterrupt2Mask | (Halp8259MaskTable[OldIrql] >> 8 ); + PIC_Address = &(ISA_CONTROL->Interrupt2ControlPort1); + WRITE_REGISTER_UCHAR(PIC_Address, PIC_Mask); + } + + 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. + +--*/ + +{ + + // + // Calculate the SIO interrupt vector. + // + + Vector -= DEVICE_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpSioInterrupt2Mask |= (UCHAR) 1 << Vector; + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, + HalpSioInterrupt2Mask + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpSioInterrupt1Mask |= (ULONG) 1 << Vector; + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, + HalpSioInterrupt1Mask + ); + + } + +} + +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. + +--*/ + +{ + + // + // Calculate the SIO interrupt vector. + // + + Vector -= DEVICE_VECTORS; + + // + // Determine if this vector is for interrupt controller 1 or 2. + // + + if (Vector & 0x08) { + + // + // The interrupt is in controller 2. + // + + Vector &= 0x7; + + HalpSioInterrupt2Mask &= (UCHAR) ~(1 << Vector); + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, + HalpSioInterrupt2Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpSioInterrupt2Level |= (UCHAR) (1 << Vector); + + } else { + + HalpSioInterrupt2Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2EdgeLevel, + HalpSioInterrupt2Level + ); + + } else { + + // + // The interrupt is in controller 1. + // + + Vector &= 0x7; + + HalpSioInterrupt1Mask &= (UCHAR) ~(1 << Vector); + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, + HalpSioInterrupt1Mask + ); + + // + // Set the level/edge control register. + // + + if (InterruptMode == LevelSensitive) { + + HalpSioInterrupt1Level |= (UCHAR) (1 << Vector); + + } else { + + HalpSioInterrupt1Level &= (UCHAR) ~(1 << Vector); + + } + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1EdgeLevel, + HalpSioInterrupt1Level + ); + } + +} + +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; +#ifdef POWER_MANAGEMENT + PDMA_EXTENDED_MODE pointerExtendedMode; +#endif // POWER_MANAGEMENT + + // + // 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 speicified 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 signicantly 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; + +#ifdef POWER_MANAGEMENT + pointerExtendedMode = Dma1ExtendedMode; +#endif // POWER_MANAGEMENT + + } 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; + +#ifdef POWER_MANAGEMENT + pointerExtendedMode = Dma2ExtendedMode; +#endif // POWER_MANAGEMENT + + } + + + adapterObject->Width16Bits = FALSE; + + + // + // 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; + + // + // 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)); + +#ifdef POWER_MANAGEMENT + *(pointerExtendedMode + channelNumber) = extendedMode; +#endif // POWER_MANAGEMENT + + // + // 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); +} + +ULONG +HalReadDmaCounter( + IN PADAPTER_OBJECT AdapterObject + ) +/*++ + +Routine Description: + + This function reads the DMA counter and returns the number of bytes left + to be transfered. + +Arguments: + + AdapterObject - Supplies a pointer to the adapter object to be read. + +Return Value: + + Returns the number of bytes still be be transfered. + +--*/ + +{ + ULONG count; + ULONG high; + + + // + // 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"); + } + +} + +#ifdef POWER_MANAGEMENT + +VOID +HalpInitInterruptController ( + VOID + ) + +/*++ + +Routine Description: + + This routine re-initializes the SIO interrupt controller. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + UCHAR DataByte; + + // + // Disable all of the interrupts + // + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, + 0xFF + ); + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, + 0xFF + ); + + // + // 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 intitialization control word sets the iterrupt 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 thrid initialization control word set the controls for slave mode. + // The master ICW3 uses bit position and the slave ICW3 uses a numberic. + // + + DataByte = 1 << SLAVE_IRQL_LEVEL; + + WRITE_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 + ); + + // + // Re-enable the interrupts + // + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt1ControlPort1, + HalpSioInterrupt1Mask + ); + + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Interrupt2ControlPort1, + HalpSioInterrupt2Mask + ); + + return; +} + + +VOID +HalpInitDmaController ( + VOID + ) + +/*++ + +Routine Description: + + This routine re-initializes the SIO DMA controller. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + UCHAR DataByte; + ULONG channelNumber; + + // + // 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 + ); + + // + // Initialize the extended mode port. + // + + for(channelNumber = 0; channelNumber < 4; channelNumber++) + { + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Dma1ExtendedModePort, + *((PUCHAR) (Dma1ExtendedMode + channelNumber)) + ); + } /* endfor */ + + for(channelNumber = 1; channelNumber < 4; channelNumber++) + { + WRITE_REGISTER_UCHAR( + &((PEISA_CONTROL) HalpIoControlBase)->Dma2ExtendedModePort, + *((PUCHAR) (Dma2ExtendedMode + channelNumber)) + ); + } /* endfor */ + + return; +} +#endif // POWER_MANAGEMENT |