/*++
*******************************************************************************
* Copyright (c) 1990-2000 Digi International Inc., All Rights Reserved			*
* 																										*
* This software contains proprietary and confidential information of Digi		*
* International Inc.  By accepting transfer of this copy, Recipient agrees		*
* to retain this software in confidence, to prevent disclosure to others, 		*
* and to make no use of this software other than that for which it was			*
* delivered.  This is an unpublished copyrighted work of Digi International	*
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly	*
* prohibited.																						*
* 																										*
* Restricted Rights Legend																		*
*																										*
* Use, duplication, or disclosure by the Government is subject to					*
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in			*
* Technical Data and Computer Software clause at DFARS 252.227-7031 or			*
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -				*
* Restricted Rights at 48 CFR 52.227-19, as applicable.								*
*																										*
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343				*
*																										*
*******************************************************************************

Module Name:

	dxbisr.c

Abstract:

	Interrupt service routines.

Author:

	Chris Walls-Manning

--*/

#include "digidxb.h"

BOOLEAN
dxbISR(
	IN PKINTERRUPT InterruptObject, 
	IN PVOID Context )
/*++

Routine Description:

	Generic interrupt service routine
	Schedules EventDpc to do the real work.
	Clears the interrupt on the adapter.

Arguments:

	InterruptObject
		PKINTERRUPT returned from IoConnectInterrupt().

	Context
		Pointer to DXB_DEVICE_EXTENSION used to enqueue EventDpc.

Return Value:

	TRUE if our adapter generated the interrupt and we've handled it, or
	FALSE otherwise.

--*/
{
	BOOLEAN fOurInterrupt = FALSE;
	PDXB_DEVICE_EXTENSION pExt = (PDXB_DEVICE_EXTENSION) Context;

	ASSERT( pExt != NULL );

	if ( pExt != NULL )
	{
		ASSERT( pExt->ClearInterrupt != NULL );

		if ( ( pExt->ClearInterrupt != NULL ) &&
				pExt->ClearInterrupt( pExt ) )
		{
			KeInsertQueueDpc( &pExt->EventDpc.Dpc, NULL, NULL );
			fOurInterrupt = TRUE;
		}
	}

	return fOurInterrupt;
}


NTSTATUS
dxbConnectInterrupt(
	IN PDXB_DEVICE_EXTENSION pExt )
/*++

Routine Description:

	Connect interrupt to service routine.

Arguments:

	pExt
		Extension of device to connect interrupt for.

Return Value:

	TRUE.

--*/
{

    // Failure # 8013 -- Low latency doesn't work in NT4.
    // The following calls to HalGetBusData and 
    // HalGetInterruptVector were removed btw. driver
    // Revs. J and L. I don't know why, but this breaks
    // interrupts. The code from Rev. J has been moved
    // back in to fix things.

#if !NT5_BUILD

	NTSTATUS Status = STATUS_UNSUCCESSFUL;

	ASSERT( MmIsAddressValid( pExt ) );

	if ( pExt != NULL )
	{
		PCI_COMMON_CONFIG PciConfig = { 0 };

		if ( HalGetBusData(
				PCIConfiguration,
				pExt->Hardware.BusNumber,
				pExt->Hardware.SlotNumber, 
				&PciConfig, sizeof PciConfig ) == sizeof PciConfig )
		{
			pExt->Hardware.Irq.Vector = HalGetInterruptVector(
				PCIBus,
				pExt->Hardware.BusNumber,
				PciConfig.u.type0.InterruptLine,
				PciConfig.u.type0.InterruptPin,
				&pExt->Hardware.Irq.Irql,
				&pExt->Hardware.Irq.Affinity );

			Status = IoConnectInterrupt(
				&pExt->Hardware.Irq.Interrupt,
				dxbISR, pExt, NULL,
				pExt->Hardware.Irq.Vector,
				pExt->Hardware.Irq.Irql,
				pExt->Hardware.Irq.Irql,
				pExt->Hardware.Irq.Mode,
				pExt->Hardware.Irq.fShared,
				pExt->Hardware.Irq.Affinity,
				FALSE );
		}
	}

	return Status;

#else

	return IoConnectInterrupt( &pExt->Hardware.Irq.Interrupt, dxbISR, pExt, NULL, 
	                           pExt->Hardware.Irq.Vector, pExt->Hardware.Irq.Irql, 
	                           pExt->Hardware.Irq.Irql, pExt->Hardware.Irq.Mode, 
	                           pExt->Hardware.Irq.fShared, pExt->Hardware.Irq.Affinity,
	                           FALSE );

#endif

}


VOID
dxbDisconnectInterrupt(
	IN PDXB_DEVICE_EXTENSION pExt )
{
	if ( (pExt != NULL) && (pExt->Hardware.Irq.Interrupt != NULL) )
	{
		IoDisconnectInterrupt( pExt->Hardware.Irq.Interrupt );
		KeRemoveQueueDpc( &pExt->EventDpc.Dpc );
		pExt->Hardware.Irq.Interrupt = NULL;
#if !NT5_BUILD
		pExt->Hardware.Irq.Vector = 0;
		pExt->Hardware.Irq.Irql = 0;
		pExt->Hardware.Irq.Affinity = 0;
#endif
	}
}
