From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/nthals/halsable/alpha/xiintsup.c | 912 ++++++++++++++++++++++++++ 1 file changed, 912 insertions(+) create mode 100644 private/ntos/nthals/halsable/alpha/xiintsup.c (limited to 'private/ntos/nthals/halsable/alpha/xiintsup.c') diff --git a/private/ntos/nthals/halsable/alpha/xiintsup.c b/private/ntos/nthals/halsable/alpha/xiintsup.c new file mode 100644 index 000000000..4c14ce127 --- /dev/null +++ b/private/ntos/nthals/halsable/alpha/xiintsup.c @@ -0,0 +1,912 @@ +/*++ + +Copyright (c) 1995 Digital Equipment Corporation + +Module Name: + + xiintsup.c + +Abstract: + + This module provides interrupt support for the Sable/Gamma/Lynx + External I/O module. + +Author: + + Dave Richarda 1-June-1995 + +Revision History: + +--*/ + +#ifdef XIO_PASS1 + +#include "halp.h" +#include "eisa.h" +#include "sableref.h" +#include "xiintsup.h" + +// +// External I/O 8259 Mask registers. +// + +UCHAR XioMasterInterruptMask; +UCHAR XioSlaveInterruptMask; + +// +// Define the context structure for use by interrupt service routines. +// + +typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)( + PKINTERRUPT InterruptObject + ); + +extern ULONG HalpProcessors; + + +ULONG +HalpGetXioInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) +{ + if( HalpXioPresent ){ + + switch( BusInterruptLevel ){ + + case XioPciSlot0AVector: + case XioPciSlot0BVector: + case XioPciSlot0CVector: + case XioPciSlot0DVector: + case XioPciSlot1AVector: + case XioPciSlot1BVector: + case XioPciSlot1CVector: + case XioPciSlot1DVector: + + *Irql = PCI_DEVICE_LEVEL; + + if( HalpProcessors > 1 ){ + *Affinity = HAL_CPU1_MASK; + } else { + *Affinity = HAL_CPU0_MASK; + } + + return( SABLE_VECTORS + BusInterruptLevel ); + + } + } + + // + // The caller specified a bus level not support by this platform. + // + + *Irql = 0; + *Affinity = 0; + return(0); +} + + +BOOLEAN +HalpInitializeXioInterrupts( + VOID + ) + +/*++ + +Routine Description: + + This routine does the following: + (1) initializes the Xio 8259 interrupt registers + (2) initializes structures necessary for EISA operations + (3) connects the intermediate interrupt dispatcher. + (4) 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; + + // + // Initialize the Xio interrupt controllers. The interrupt structure + // is one master interrupt controller with 1 cascaded slave controller. + // Proceed through each control word programming each of the controllers. + // + + // + // Write control word 1 for each of the controllers, indicate + // that initialization is in progress and the control word 4 will + // be used. + // + + DataByte = 0; + ((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1; +// ((PINITIALIZATION_COMMAND_1) &DataByte)->LevelTriggeredMode = 1; + DataByte |= 0x04; + ((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1; + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterControl, + DataByte + ); + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveControl, + DataByte + ); + + // + // Write control word 2 for each of the controllers, set the base + // interrupt vector for each controller. + // + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterMask, + XioMasterBaseVector + ); + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask, + XioSlaveBaseVector + ); + + // + // 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 << (XioSlaveCascadeVector & ~XioMasterBaseVector) ); + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterMask, + DataByte + ); + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask, + (XioSlaveCascadeVector & ~XioMasterBaseVector) + ); + + // + // 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; +#ifdef XIO_AEOI + ((PINITIALIZATION_COMMAND_4) &DataByte)->AutoEndOfInterruptMode = 1; +#endif + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterMask, + DataByte + ); + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask, + DataByte + ); + + // + // Disable all of the interrupts except the slave interrupts to the + // master controller. + // + + XioMasterInterruptMask = + (UCHAR)( ~(1 << (XioSlaveCascadeVector & ~XioMasterBaseVector)) ); + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterMask, + XioMasterInterruptMask + ); + + XioSlaveInterruptMask = 0xFF; + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask, + XioSlaveInterruptMask + ); + + return TRUE; + +} + +BOOLEAN +HalpXioDispatch( + VOID + ) + +/*++ + +Routine Description: + + This routine is entered as a result of an interrupt being generated + via the vector that is directly connected XIO device interrupt. + + This routine is responsible for determining the + source of the interrupt, performing the secondary dispatch and + acknowledging the interrupt in the 8259 controllers. + + 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. + +--*/ + +{ + UCHAR interruptVector; + BOOLEAN returnValue; + USHORT IdtIndex; + UCHAR InService; + PULONG DispatchCode; + PKINTERRUPT InterruptObject; + + // + // Acknowledge the Interrupt controller and receive the returned + // interrupt vector. + // + + interruptVector = READ_REGISTER_UCHAR( + &((PXIO_INTERRUPT_CSRS) + XIO_INTERRUPT_CSRS_QVA)->InterruptAcknowledge + ); + + // + // If we get a passive release, send a non-specific end of interrupt + // command and return TRUE, indicating that we processed the interrupt. + // + + switch( interruptVector ){ + + case XioMasterPassiveReleaseVector: + +#ifdef XIO_AEOI + + // + // If the passive release vector has not been enabled, then we can + // dismiss it now. + // + + if( XioMasterInterruptMask & 0x80 ){ + return TRUE; + } + +#else // XIO_AEOI + + // + // Read the "in-service" mask. + // + + WRITE_PORT_UCHAR( &((PSABLE_INTERRUPT_CSRS)SABLE_INTERRUPT_CSRS_QVA)->MasterControl, + 0x0B + ); + + InService = READ_PORT_UCHAR( + &((PSABLE_INTERRUPT_CSRS) SABLE_INTERRUPT_CSRS_QVA)->MasterControl + ); + + if( (InService & 0x80) == 0 ){ + + // + // Send end of interrupt to clear the passive release in the + // master controller. + // + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterControl, + NONSPECIFIC_END_OF_INTERRUPT + ); + + return TRUE; + + } + +#endif // XIO_AEOI + + break; + + case XioSlavePassiveReleaseVector: + +#ifdef XIO_AEOI + + // + // If the passive release vector has not been enabled, then we can + // dismiss it now. + // + + if( XioSlaveInterruptMask & 0x80 ){ + return TRUE; + } + +#else // XIO_AEOI + + // + // Read the "in-service" mask. + // + + WRITE_PORT_UCHAR( &((PSABLE_INTERRUPT_CSRS)SABLE_INTERRUPT_CSRS_QVA)->SlaveControl, + 0x0B + ); + + InService = READ_PORT_UCHAR( + &((PSABLE_INTERRUPT_CSRS) SABLE_INTERRUPT_CSRS_QVA)->SlaveControl + ); + + if( (InService & 0x80) == 0 ){ + + // + // Send end of interrupt to clear the passive release in the + // slave controller. + // + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveControl, + NONSPECIFIC_END_OF_INTERRUPT + ); + + return TRUE; + + } + +#endif // XIO_AEOI + + break; + + } + + // + // Dispatch to the secondary interrupt service routine. + // + + IdtIndex = interruptVector + SABLE_VECTORS; + DispatchCode = (PULONG)PCR->InterruptRoutine[IdtIndex]; + InterruptObject = CONTAINING_RECORD(DispatchCode, + KINTERRUPT, + DispatchCode); + + returnValue = ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(InterruptObject); + +#ifndef XIO_AEOI + + // + // Dismiss the interrupt in the 8259 interrupt controllers. + // If this is a cascaded interrupt then the interrupt must be dismissed in + // both controllers. + // + + if( (interruptVector & XioSlaveBaseVector) == XioSlaveBaseVector ){ + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveControl, + NONSPECIFIC_END_OF_INTERRUPT + ); + + } + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterControl, + NONSPECIFIC_END_OF_INTERRUPT + ); + +#endif // XIO_AEOI + + return(returnValue); + +} + + + +VOID +HalpDisableXioInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This function Disables the External IO specified interrupt. + +Arguments: + + Vector - Supplies the vector of the Xio interrupt that is Disabled. + +Return Value: + + None. + +--*/ + +{ + ULONG Interrupt; + + if( (Vector >= SABLE_VECTORS + XioMasterBaseVector) && + (Vector <= SABLE_VECTORS + XioSlavePassiveReleaseVector) ){ + + // + // Calculate the Xio relative interrupt vector. + // + + Vector -= SABLE_VECTORS; + + // + // Compute the interrupt within the interrupt controller. + // + + Interrupt = Vector & 0x7; + + // + // Enable the interrupt for the appropriate interrupt controller. + // + + if( (Vector & XioSlaveBaseVector) == XioSlaveBaseVector ){ + + XioSlaveInterruptMask |= (UCHAR) (1 << Interrupt); + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask, + XioSlaveInterruptMask + ); + + } + } +} + +BOOLEAN +HalpEnableXioInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This function enables the Xio specified interrupt in the + appropriate 8259 interrupt controllers. It also supports the + edge/level control for EISA bus interrupts. By default, all interrupts + are edge detected (and latched). + +Arguments: + + Vector - Supplies the vector of the Xio interrupt that is enabled. + + InterruptMode - Supplies the mode of the interrupt; LevelSensitive or + Latched (Edge). + +Return Value: + + None. + +--*/ + +{ + ULONG Interrupt; + + if( (Vector >= SABLE_VECTORS + XioMasterBaseVector) && + (Vector <= SABLE_VECTORS + XioSlavePassiveReleaseVector) ){ + + // + // Calculate the Xio relative interrupt vector. + // + + Vector -= SABLE_VECTORS; + + // + // Compute the interrupt within the interrupt controller. + // + + Interrupt = Vector & 0x7; + + // + // Enable the interrupt for the appropriate interrupt controller. + // + + if( (Vector & XioSlaveBaseVector) == XioSlaveBaseVector ){ + + XioSlaveInterruptMask &= (UCHAR) ~(1 << Interrupt); + + WRITE_PORT_UCHAR( + &((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask, + XioSlaveInterruptMask + ); + + return TRUE; + } + } + + return FALSE; +} + +#endif // XIO_PASS1 + +#ifdef XIO_PASS2 + +#include "halp.h" +#include "t2.h" +#include "icic.h" +#include "xiintsup.h" + +// +// Define the context structure for use by interrupt service routines. +// + +typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)( + PKINTERRUPT InterruptObject + ); + +extern ULONG HalpProcessors; + +// +// Cached copies of the corresponding ICIC register(s). +// + +ICIC_MASK_REGISTER XioIcIcMaskRegister; + + +ULONG +HalpGetXioInterruptVector( + IN PBUS_HANDLER BusHandler, + IN PBUS_HANDLER RootHandler, + IN ULONG BusInterruptLevel, + IN ULONG BusInterruptVector, + OUT PKIRQL Irql, + OUT PKAFFINITY Affinity + ) +{ + if( HalpXioPresent ){ + + switch( BusInterruptLevel ){ + + // + // Handle Vectors for PCI devices. + // + + case XioPciSlot0AVector: + case XioPciSlot0BVector: + case XioPciSlot0CVector: + case XioPciSlot0DVector: + case XioPciSlot1AVector: + case XioPciSlot1BVector: + case XioPciSlot1CVector: + case XioPciSlot1DVector: + case XioPciSlot2AVector: + case XioPciSlot2BVector: + case XioPciSlot2CVector: + case XioPciSlot2DVector: + case XioPciSlot3AVector: + case XioPciSlot3BVector: + case XioPciSlot3CVector: + case XioPciSlot3DVector: + case XioPciSlot4AVector: + case XioPciSlot4BVector: + case XioPciSlot4CVector: + case XioPciSlot4DVector: + case XioPciSlot5AVector: + case XioPciSlot5BVector: + case XioPciSlot5CVector: + case XioPciSlot5DVector: + case XioPciSlot6AVector: + case XioPciSlot6BVector: + case XioPciSlot6CVector: + case XioPciSlot6DVector: + case XioPciSlot7AVector: + case XioPciSlot7BVector: + case XioPciSlot7CVector: + case XioPciSlot7DVector: + + *Irql = DEVICE_LEVEL; + + if( HalpProcessors > 1 ){ + *Affinity = HAL_CPU1_MASK; + } else { + *Affinity = HAL_CPU0_MASK; + } + + return( BusInterruptLevel ); + + } + } + + *Irql = 0; + *Affinity = 0; + return 0; +} + + +BOOLEAN +HalpInitializeXioInterrupts( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the ICIC on the Standard I/O module. + +Arguments: + + None. + +Return Value: + + TRUE. + +--*/ + +{ + T2_ICE Ice; + ICIC_ELCR_REGISTER XioIcIcElcrRegister; + + // + // Initialize the interface between the T3/T4 and the ICIC. + // + + Ice.all = 0; + Ice.EisaFlushAddress = 0x542; + Ice.IcEnable = 1; + Ice.HalfSpeedEnable = 0; + + WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Ice, + Ice.all ); + + // + // Initialize the ICIC Mask Register. + // + + XioIcIcMaskRegister = (ULONGLONG)-1; + + WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcMaskRegister, + XioIcIcMaskRegister ); + + // + // Initialize the ICIC Edge/Level Control Register. + // + + XioIcIcElcrRegister = + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot4AVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot4BVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot4CVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot4DVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot5AVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot5BVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot5CVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot5DVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot6AVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot6BVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot6CVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot6DVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot7AVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot7BVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot7CVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot7DVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot7DVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot0AVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot0BVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot0CVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot0DVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot1AVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot1BVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot1CVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot1DVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot2AVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot2BVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot2CVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot2DVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot3AVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot3BVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot3CVector - XioBaseVector)) | + ((ICIC_ELCR_REGISTER)1 << (XioPciSlot3DVector - XioBaseVector)); + + WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcElcrRegister, + XioIcIcElcrRegister ); + + // + // Initialize the ICIC EISA Register. + // + + WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcEisaRegister, (ULONGLONG)0 ); + + // + // Initialize the ICIC Mode Register. + // + + WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcModeRegister, (ULONGLONG)0 ); + + return TRUE; +} + + +BOOLEAN +HalpXioDispatch( + VOID + ) + +/*++ + +Routine Description: + + This routine dispatches interrupts received by the External I/O + ICIC. + +Arguments: + + None. + +Return Value: + + A boolean value indicating whether the interrupt was handled by + the FLIH/SLIH. + +--*/ + +{ + T2_VAR Var; + PULONG DispatchCode; + PKINTERRUPT InterruptObject; + BOOLEAN ReturnValue; + + // + // Get the interrupt vector. + // + + Var.all = READ_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Var ); + + // + // If this is a passive release, ignore the interrupt. + // + + if( Var.PassiveRelease == 1 ){ + + return(TRUE); + + } + + // + // Dispatch to the secondary interrupt service routine. + // + + DispatchCode = (PULONG)PCR->InterruptRoutine[XioBaseVector + Var.Vector]; + InterruptObject = CONTAINING_RECORD(DispatchCode, + KINTERRUPT, + DispatchCode); + + ReturnValue = ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(InterruptObject); + + // + // Send an SEOI. + // + + WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Var, Var.Vector ); + + return(ReturnValue); +} + +VOID +HalpDisableXioInterrupt( + IN ULONG Vector + ) + +/*++ + +Routine Description: + + This routine disables interrupts associated with the External I/O + ICIC. + +Arguments: + + Vector - The vector of the interrupt to disable. + +Return Value: + + None. + +--*/ + +{ + ULONGLONG IrqMask; + + if( (Vector >= XioBaseVector) && + (Vector <= XioPciSlot3DVector) ){ + + // + // Compute the IRQ mask. + // + + IrqMask = (ICIC_MASK_REGISTER)1 << (Vector - XioBaseVector); + + // + // Mask the interrupt. + // + + XioIcIcMaskRegister |= IrqMask; + + // + // Update the ICIC Mask Register. + // + + WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcMaskRegister, + XioIcIcMaskRegister ); + + } +} + +BOOLEAN +HalpEnableXioInterrupt( + IN ULONG Vector, + IN KINTERRUPT_MODE InterruptMode + ) + +/*++ + +Routine Description: + + This routine enables interrupts associated with the External I/O + ICIC. + +Arguments: + + Vector - The vector of the interrupt to enable. + + InterruptMode - An indication of whether the interrupt should + be edge-triggered/level-sensitive. (Ignored) + +Return Value: + + None. + +--*/ + +{ + ULONGLONG IrqMask; + + if( (Vector >= XioBaseVector) && + (Vector <= XioPciSlot3DVector) ){ + + // + // Compute the IRQ mask. + // + + IrqMask = (ICIC_MASK_REGISTER)1 << (Vector - XioBaseVector); + + // + // Un-mask the interrupt. + // + + XioIcIcMaskRegister &= ~IrqMask; + + // + // Update the ICIC Mask Register. + // + + WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcMaskRegister, + XioIcIcMaskRegister ); + + return TRUE; + } + + return FALSE; +} + +#endif // XIO_PASS2 -- cgit v1.2.3