/*++ Copyright (c) 1990-1994 Microsoft Corporation Module Name: jxebsup.c Abstract: The module provides the EISA bus support for R98B systems. --*/ #include "halp.h" #include "eisa.h" #include "bugcodes.h" // // Define the context structure for use by the interrupt routine. // typedef BOOLEAN (*PSECONDARY_DISPATCH)( PKINTERRUPT Interrupt ); // // Define save area for EISA adapter objects. // PADAPTER_OBJECT HalpEisaAdapter[8]; // // Define save area for EISA interrupt mask resiters and level\edge control // registers. // UCHAR HalpEisaInterrupt1Mask; UCHAR HalpEisaInterrupt2Mask; UCHAR HalpEisaInterrupt1Level; UCHAR HalpEisaInterrupt2Level; PADAPTER_OBJECT HalpAllocateEisaAdapter( IN PDEVICE_DESCRIPTION DeviceDescriptor ) /*++ Routine Description: This function allocates an EISA adapter object according to the specification supplied in the device description. The necessary device descriptor information is saved. If there is no existing adapter object for this channel then a new one is allocated. The saved information in the adapter object is used to set the various DMA modes when the channel is allocated or a map transfer is done. Arguments: DeviceDescription - Supplies the description of the device which want to use the DMA adapter. Return Value: Returns a pointer to the newly created adapter object or NULL if one cannot be created. --*/ { PADAPTER_OBJECT adapterObject; PVOID adapterBaseVa; ULONG channelNumber; ULONG controllerNumber; DMA_EXTENDED_MODE extendedMode; UCHAR adapterMode; BOOLEAN useChannel; BOOLEAN eisaSystem; // // Determine if the the channel number is important. Master cards on // Eisa do not use a channel number. // if (DeviceDescriptor->InterfaceType == Eisa && DeviceDescriptor->Master) { useChannel = FALSE; } else { useChannel = TRUE; } // // Channel 4 cannot be used since it is used for chaining. Return null if // it is requested. // if ((DeviceDescriptor->DmaChannel == 4 || DeviceDescriptor->DmaChannel > 7) && useChannel) { return(NULL); } // // Set the channel number number. // channelNumber = DeviceDescriptor->DmaChannel & 0x03; // // Set the adapter base address to the Base address register and controller // number. // if (!(DeviceDescriptor->DmaChannel & 0x04)) { controllerNumber = 1; adapterBaseVa = (PVOID) &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort; } else { controllerNumber = 2; adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort; } // // Determine if a new adapter object is necessary. If so then allocate it. // if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) { adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel]; } else { // // Allocate an adapter object. // adapterObject = (PADAPTER_OBJECT) HalpAllocateAdapter( 0, adapterBaseVa, NULL ); if (adapterObject == NULL) { return(NULL); } if (useChannel) { HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject; } } // // If the channel is not used then indicate the this is an Eisa bus // master by setting the page port and mode to cascade even though // it is not used. // if (!useChannel) { adapterObject->PagePort = (PVOID) (~0x0); ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; return(adapterObject); } // // Setup the pointers to all the random registers. // adapterObject->ChannelNumber = (UCHAR)channelNumber; // S004 if (controllerNumber == 1) { switch ((UCHAR)channelNumber) { case 0: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel0; break; case 1: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel1; break; case 2: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel2; break; case 3: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel3; break; } // // Set the adapter number. // adapterObject->AdapterNumber = 1; // // Save the extended mode register address. // adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma1ExtendedModePort; } else { switch (channelNumber) { case 1: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel5; break; case 2: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel6; break; case 3: adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel7; break; } // // Set the adapter number. // adapterObject->AdapterNumber = 2; // // Save the extended mode register address. // adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort; } // // Initialzie the extended mode port. // *((PUCHAR) &extendedMode) = 0; extendedMode.ChannelNumber = (UCHAR)channelNumber; // S004 switch (DeviceDescriptor->DmaSpeed) { case Compatible: extendedMode.TimingMode = COMPATIBLITY_TIMING; break; case TypeA: extendedMode.TimingMode = TYPE_A_TIMING; break; case TypeB: extendedMode.TimingMode = TYPE_B_TIMING; break; case TypeC: extendedMode.TimingMode = BURST_TIMING; break; default: ObDereferenceObject( adapterObject ); return(NULL); } switch (DeviceDescriptor->DmaWidth) { case Width8Bits: extendedMode.TransferSize = BY_BYTE_8_BITS; break; case Width16Bits: extendedMode.TransferSize = BY_BYTE_16_BITS; break; case Width32Bits: extendedMode.TransferSize = BY_BYTE_32_BITS; break; default: ObDereferenceObject( adapterObject ); return(NULL); } WRITE_REGISTER_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode)); // // Initialize the adapter mode register value to the correct parameters, // and save them in the adapter object. // adapterMode = 0; ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber; if (DeviceDescriptor->Master) { ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE; // // Set the mode, and enable the request. // if (adapterObject->AdapterNumber == 1) { // // This request is for DMA controller 1 // PDMA1_CONTROL dmaControl; dmaControl = adapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); // // Unmask the DMA channel. // WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) ); } else { // // This request is for DMA controller 1 // PDMA2_CONTROL dmaControl; dmaControl = adapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); // // Unmask the DMA channel. // WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber) ); } } else if (DeviceDescriptor->DemandMode) { ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE; } else { ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE; } if (DeviceDescriptor->AutoInitialize) { ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1; } adapterObject->AdapterMode = adapterMode; return(adapterObject); } BOOLEAN HalpCreateEisaStructures ( VOID ) /*++ Routine Description: This routine initializes the structures necessary for EISA operations and connects the intermediate interrupt dispatcher. It also initializes the EISA 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; UCHAR charBuffer; // // Directly connect the EISA interrupt dispatcher to the level for // EISA bus interrupt. // // N.B. This vector is reserved for exclusive use by the HAL (see // interrupt initialization. // PCR->InterruptRoutine[EISA_DISPATCH_VECTOR] = (PKINTERRUPT_ROUTINE)HalpEisaDispatch; // // Raise the IRQL while the EISA interrupt controller is initalized. // KeRaiseIrql(EISA_LEVEL, &oldIrql); // // Initialize the EISA interrupt controller. There are two cascaded // interrupt controllers, each of which must initialized with 4 initialize // control words. // DataByte = 0; ((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1; ((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0, DataByte ); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0, DataByte ); // // The second intitialization control word sets the iterrupt vector to // 0-15. // DataByte = 0; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, DataByte ); DataByte = 0x08; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, DataByte ); // // The thrid initialization control word set the controls for slave mode. // The master ICW3 uses bit position and the slave ICW3 uses a numberic. // DataByte = 1 << SLAVE_IRQL_LEVEL; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, DataByte ); DataByte = SLAVE_IRQL_LEVEL; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, DataByte ); // // The fourth initialization control word is used to specify normal // end-of-interrupt mode and not special-fully-nested mode. // DataByte = 0; ((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, DataByte ); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, DataByte ); // // Disable all of the interrupts except the slave. // HalpEisaInterrupt1Mask = (UCHAR)~(1 << SLAVE_IRQL_LEVEL); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, HalpEisaInterrupt1Mask ); HalpEisaInterrupt2Mask = 0xFF; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, HalpEisaInterrupt2Mask ); // // Initialize the edge/level register masks to 0 which is the default // edge sensitive value. // HalpEisaInterrupt1Level = 0; HalpEisaInterrupt2Level = 0; // // Restore IRQL level. // KeLowerIrql(oldIrql); // // EISA Interrupt to PONCE Enable!!. // HalpInterruptFromPonce(EISA_DISPATCH_VECTOR ,1); //SNES // // 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) HalpEisaControlBase)->Dma1BasePort.AllMask, 0x0F ); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort.AllMask, 0x0E ); charBuffer = READ_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus ); // // IOCHK# NMI Disable and Clear // PERR# PCI System Board Error Disable // charBuffer = ((charBuffer & 0x03) | 0x0C); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus, charBuffer ); // // Disbale Bus Timeout,Fail Safe NMI adn Software NMI // charBuffer = READ_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl ); charBuffer = (charBuffer & 0x01); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, charBuffer ); return(TRUE); } VOID HalpDisableEisaInterrupt( IN ULONG Vector ) /*++ Routine Description: This function Disables the EISA bus specified EISA bus interrupt. Arguments: Vector - Supplies the vector of the ESIA interrupt that is Disabled. Return Value: None. --*/ { // // Calculate the EISA interrupt vector. // Vector -= EISA_VECTORS; // // Determine if this vector is for interrupt controller 1 or 2. // if (Vector & 0x08) { // // The interrupt is in controller 2. // Vector &= 0x7; HalpEisaInterrupt2Mask |= (UCHAR) 1 << Vector; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, HalpEisaInterrupt2Mask ); } else { // // The interrupt is in controller 1. // Vector &= 0x7; HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector; WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, HalpEisaInterrupt1Mask ); } } // // //extern KSPIN_LOCK HalpIoMapSpinLock; VOID HalpEisaMapTransfer( IN PADAPTER_OBJECT AdapterObject, IN ULONG Offset, IN ULONG Length, IN BOOLEAN WriteToDevice ) /*++ Routine Description: This function programs the EISA DMA controller for a transfer. Arguments: Adapter - Supplies the DMA adapter object to be programed. Offset - Supplies the logical address to use for the transfer. Length - Supplies the length of the transfer in bytes. WriteToDevice - Indicates the direction of the transfer. Return Value: None. --*/ { PUCHAR BytePtr; UCHAR adapterMode; KIRQL Irql; BytePtr = (PUCHAR) &Offset; // ASSERT(Offset >= 0x100000); // S009 // // grab the spinlock for the system DMA controller // Internal Floppy Device used ESC DMA and May be diffirent Onprocessor // with EISA Drivers OnProcessor. // So grab. KeAcquireSpinLock( &AdapterObject->MasterAdapter->SpinLock, &Irql ); adapterMode = AdapterObject->AdapterMode; // // Check to see if this request is for a master I/O card. // if (((PDMA_EISA_MODE) &adapterMode)->RequestMode == CASCADE_REQUEST_MODE) { // // Set the mode, Disable the request and return. // if (AdapterObject->AdapterNumber == 1) { // // This request is for DMA controller 1 // PDMA1_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); // // Unmask the DMA channel. // WRITE_REGISTER_UCHAR( &dmaControl->SingleMask, (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber) ); } else { // // This request is for DMA controller 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) ); } KeReleaseSpinLock (&AdapterObject->MasterAdapter->SpinLock, Irql); return; } // // Determine the mode based on the transfer direction. // ((PDMA_EISA_MODE) &adapterMode)->TransferType = WriteToDevice ? WRITE_TRANSFER : READ_TRANSFER; // // Determine the controller number based on the Adapter base va. // if (AdapterObject->AdapterNumber == 1) { // // This request is for DMA controller 1 // PDMA1_CONTROL dmaControl; dmaControl = AdapterObject->AdapterBaseVa; WRITE_REGISTER_UCHAR( &dmaControl->ClearBytePointer, 0 ); WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode ); WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseAddress, BytePtr[0] ); WRITE_REGISTER_UCHAR( &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber] .DmaBaseAddress, BytePtr[1] ); WRITE_REGISTER_UCHAR( ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) + (ULONG)AdapterObject->PagePort, BytePtr[2] ); // // Write the high page register with zero value. This enable a special mode // which allows ties the page register and base count into a single 24 bit // address register. // WRITE_REGISTER_UCHAR( ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) + (ULONG)AdapterObject->PagePort, 0 ); // // 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 1 // 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) HalpEisaControlBase)->DmaPageLowPort) + (ULONG)AdapterObject->PagePort, BytePtr[2] ); // // Write the high page register with zero value. This enable a special mode // which allows ties the page register and base count into a single 24 bit // address register. // WRITE_REGISTER_UCHAR( ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) + (ULONG)AdapterObject->PagePort, 0 ); // // 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 HalpEnableEisaInterrupt( IN ULONG Vector, IN KINTERRUPT_MODE InterruptMode ) /*++ Routine Description: This function enables the EISA bus specified EISA bus interrupt and sets the level/edge register to the requested value. Arguments: Vector - Supplies the vector of the EISA interrupt that is enabled. InterruptMode - Supplies the mode of the interrupt; LevelSensitive or Latched. Return Value: None. --*/ { // // Calculate the EISA interrupt vector. // Vector -= EISA_VECTORS; // // Determine if this vector is for interrupt controller 1 or 2. // if (Vector & 0x08) { // // The interrupt is in controller 2. // Vector &= 0x7; HalpEisaInterrupt2Mask &= (UCHAR) ~(1 << Vector); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1, HalpEisaInterrupt2Mask ); // // Set the level/edge control register. // if (InterruptMode == LevelSensitive) { HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector); } else { HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector); } WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel, HalpEisaInterrupt2Level ); } else { // // The interrupt is in controller 1. // Vector &= 0x7; HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector); WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1, HalpEisaInterrupt1Mask ); // // Set the level/edge control register. // if (InterruptMode == LevelSensitive) { HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector); } else { HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector); } WRITE_REGISTER_UCHAR( &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel, HalpEisaInterrupt1Level ); } } BOOLEAN HalpEisaDispatch( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext ) /*++ Routine Description: This routine is entered as the result of an interrupt being generated via the vector that is directly connected to EISA device interrupt. N.B. This interrupt is directly connected and therefore, no argument values are defined. Arguments: None. Return Value: Returns the value returned from the second level routine. --*/ { PULONG dispatchCode; USHORT interruptVector; PKINTERRUPT interruptObject; BOOLEAN returnValue; // // Read the interrupt vector. // interruptVector = (UCHAR)READ_REGISTER_ULONG( (PULONG)&PONCE_CNTL(0)->INTAC); // // If the vector is nonzero, then it is either an EISA interrupt // of an NMI interrupt. Otherwise, the interrupt is no longer // present. // if (interruptVector != 0) { // // If the interrupt vector is 0x8000 then the interrupt is an NMI. // Otherwise, dispatch the interrupt to the appropriate interrupt // handler. // // if (interruptVector != 0x8000) { //K001 Start if(interruptVector == 7|| interruptVector==15 ){ PVOID IsrPortAddr; UCHAR IsrValue; #define OCW3_READ_ISR 0x0B #define OCW3_READ_IRR 0x0A // // Master or Slave ? // IsrPortAddr = (interruptVector == 7) ? &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0: &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0; // SetUp to ISR Regsiter WRITE_REGISTER_UCHAR( IsrPortAddr, OCW3_READ_ISR ); // Read ISR Register IsrValue=READ_REGISTER_UCHAR( IsrPortAddr ); // Resume to IRR Register WRITE_REGISTER_UCHAR( IsrPortAddr, OCW3_READ_IRR); if(!IsrValue){ // This is a spurious interrupt!!. No Call Driver. goto NocallDriver; } } // K001 End // // Mask the upper bits off since the vector is only a byte and // dispatch to the secondary interrupt service routine. // interruptVector &= 0xff; dispatchCode = (PULONG)(PCR->InterruptRoutine[EISA_VECTORS + interruptVector]); interruptObject = CONTAINING_RECORD(dispatchCode, KINTERRUPT, DispatchCode); returnValue = ((PSECONDARY_DISPATCH)interruptObject->DispatchAddress)(interruptObject); NocallDriver: // // Dismiss the interrupt in the EISA 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) HalpEisaControlBase)->Interrupt2ControlPort0, NONSPECIFIC_END_OF_INTERRUPT); } WRITE_REGISTER_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0, NONSPECIFIC_END_OF_INTERRUPT); // } else { // returnValue = HalHandleNMI(NULL, NULL); // } } else { returnValue = FALSE; } return returnValue; } BOOLEAN HalHandleNMI( IN PKINTERRUPT Interrupt, IN PVOID ServiceContext ) /*++ Routine Description: This function is called when an EISA NMI occurs. It print the appropriate status information and bugchecks. Arguments: Interrupt - Supplies a pointer to the interrupt object ServiceContext - Bug number to call bugcheck with. Return Value: Returns TRUE. --*/ { KeBugCheck(NMI_HARDWARE_FAILURE); return(TRUE); }