/*++
 * Copyright (c) 1990-96 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
 *
 *
 * Last Update: $Date: 10/22/97 11:56a $
 *
 * $Header: /Components/Windows/NT/Sync/Build/Mp570/hwrxsca.c 6     10/22/97 11:56a Darinh $
 *
 * Revision History:
 * $Log: /Components/Windows/NT/Sync/Build/Mp570/hwrxsca.c $
 * 
 * 6     10/22/97 11:56a Darinh
 * Changes to make multiple board installations work better.
 * 
 * 5     9/08/97 3:44p Darinh
 * A variety of changes, including Data General fixes are included.
 * 
 * 4     7/15/97 1:05p Darinh
 * Added DigiLogError statements and message file, altered code to function
 * in DStreams environment and SNA environment with a conditional
 * compilation.
 * 
 * 3     6/06/97 1:48p Darinh
 * Everything seems functional, but more testing is required.
 * 
 * 2     4/08/97 4:55p Darinh
 * Changes made to correspond to the new DigiUtil library.  It
 * successfully transmits data!  I don't know about receiving data yet.
 * 
 * 1     4/02/97 10:08a Darinh
 * Initial checkin; ISA cards initialize, but do not pass data.
 * 
--*/
#include "digilib.h"

#include <ntddk.h>
#include "def570.h"
#include "def64570.h"
#include "board.h"
#include "ioctls.h"
#include "io.h"
#include "hwutils.h"
#include "hwsca.h"
#include "debug.h"



VOID
fnStartRxDma (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will start the Receive DMA channel.  The DMA is setup using
	chained-block multi-frame transfers.  The receive descriptors are setup
	at initialization time as a circular chain.

	The following are the setting of Receive DMA registers:
		. Reset DMA Status Register (DSR)
		. Issue a software abort to the DMA Command Register (DCR)
		. Set up the DMA Mode Register (DMR) for
			- Chained-block Transfer
			- Multi-frame
			- Enable Frame end interrupt counter (FCT)
		. Set up Current Descriptor Address Register (CDA), Chain
			Pointer Base (CPB), Error Descriptor Address Register (EDA),
			and Receive Buffer Length Register (BFL)
		. Enable the DMA

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DigiDump (DIGIFLOW, ("Entering fnStartRxDma()\n"));

	EnableScaMemMap (pDeviceExt);

	// Disable DMA
	WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dsr, 0x00);

	// Software abort
	WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dcr, DMAC_DCR_DMA_SW_ABORT);

	// Chained-block multi-frame transfer
	WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dmr, 0x16);

	WRT_REG_USHORT (&pDeviceExt->pScaRxDmac->Cda, pDeviceExt->pRxDmaDspCda);
	WRT_REG_USHORT (&pDeviceExt->pScaRxDmac->Eda, pDeviceExt->pRxDmaDspEda);
	WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Cpb, pDeviceExt->pRxDmaDspCpb);

	DigiDump (DIGIVERYLOUD, (
		"  Rx Local CDA   = %x\n"
		"  Rx Local EDA   = %x\n"
		"  Rx Local CPB   = %x\n"
		"  Rx SCA   CDA   = %x\n"
		"  Rx SCA   EDA   = %x\n"
		"  Rx SCA   CPB   = %x\n",
		(USHORT) pDeviceExt->pRxDmaDspCda,
		(USHORT) pDeviceExt->pRxDmaDspEda,
		(UCHAR) pDeviceExt->pRxDmaDspCpb,
		READ_REGISTER_USHORT ((PUSHORT) &pDeviceExt->pScaRxDmac->Cda),
		READ_REGISTER_USHORT ((PUSHORT) &pDeviceExt->pScaRxDmac->Eda),
		READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaRxDmac->Cpb)));

	// Receive buffer size
	WRT_REG_USHORT (&pDeviceExt->pScaRxDmac->Rbl, DEFAULT_FRAME_SIZE);

	//  Enable the DMA
	WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dsr, DMAC_DSR_DEE);

	pDeviceExt->IsRxTxEnable |= RXDMA_ENABLE;

	DisableMemory (pDeviceExt);

	DigiDump (DIGIFLOW, ("Exiting fnStartRxDma()\n"));
}


VOID
fnStartRxMsci (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will start the MSCI receiver.  This will trigger the
	receiver to start receiving frames.  If the station address is
	specified, only those frames that match the address will be passed
	to the DMA's buffers.

	The following is the setting of the MSCI registers :
		. Issue Receive Enable to MSCI Command Register (CMD)

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DigiDump (DIGIFLOW, ("Entering fnStartRxMsci()\n"));

	EnableScaMemMap (pDeviceExt);

	WRT_REG_UCHAR ((PUCHAR) &pDeviceExt->pScaMsci->Rrc, 0x0C);
	WRT_REG_UCHAR (&pDeviceExt->pScaMsci->Cmd, CMD_RX_ENABLE);
	pDeviceExt->IsRxTxEnable |= RXMSCI_ENABLE;

	DisableMemory (pDeviceExt);

	DigiDump (DIGIFLOW, ("Exiting fnStartRxMsci()\n"));
}


VOID
fnStartReceiver (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function starts the receiver on the card.  The characteristics
	for the receiver are setup in SetLinkConfig().

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DigiDump (DIGIFLOW, ("Entering fnStartReceiver()\n"));

	fnStartRxDma (pDeviceExt);			// Setup and start the Receive DMA
	fnStartRxMsci (pDeviceExt);			// Start the MSCI receiver

	DigiDump (DIGIFLOW, ("Exiting fnStartReceiver()\n"));
}


VOID
fnEnableRxDmaInterrupts (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function enables the interrupts from the DMAC.  The sources for the
	interrupts are the following:
		. End of transfer (EOT)
		. End of frame (EOM)
		. Buffer Overflow (BOF)
		. Frame end interrupt counter overflow
	
Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	UCHAR   ScaHoldingCell;


	DigiDump (DIGIFLOW, ("Entering fnEnableRxDmaInterrupts()\n"));

	EnableScaMemMap (pDeviceExt);

	// Enable EOT, EOM, BOF, and COF interrupts
	WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dir, 0xF0);

	// Enable the Interrupt Controller's Master DMA interrupts
	ScaHoldingCell = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pSca->ComIer1);
	ScaHoldingCell |= pDeviceExt->ScaIntCtrlRxDmaIntE;
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComIer1, ScaHoldingCell);

	DisableMemory (pDeviceExt);

	DigiDump (DIGIFLOW, ("Exiting fnEnableRxDmaInterrupts()\n"));
}


VOID
fnEnableRxMsciInterrupts (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function enables the interrupts from the MSCI receiver.  The source
	of this interrupt is one of the following:
		. Change in DSR status.  (the 570 SCA does not support the DSR signal
			directly.  The DSR is wired to the DCD pin to cause an interrupt
			when the DSR signal changes.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	UCHAR   ScaHoldingCell;


	DigiDump (DIGIFLOW, ("Entering fnEnableRxMsciInterrupts()\n"));

	EnableScaMemMap (pDeviceExt);

	// Enable DSR interrupt.  The DSR is connected to DCD.
	ScaHoldingCell = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaMsci->Ie1);
	ScaHoldingCell |= MSCI_IE1_CDCDE;
	WRT_REG_UCHAR (&pDeviceExt->pScaMsci->Ie1, ScaHoldingCell);

	// Enable MSCI Master's RXINT interrupt
	ScaHoldingCell = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaMsci->Ie0);
	ScaHoldingCell |= MSCI_IE0_RXINTE;
	WRT_REG_UCHAR (&pDeviceExt->pScaMsci->Ie0, ScaHoldingCell);

	// Enable Interrupts Controller's Master Receive Interrupts
	ScaHoldingCell = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pSca->ComIer0);
	ScaHoldingCell |= pDeviceExt->ScaIntCtrlRxIntE;
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComIer0, ScaHoldingCell);

	DisableMemory (pDeviceExt);

	DigiDump (DIGIFLOW, ("Exiting fnEnableRxMsciInterrupts()\n"));
}


VOID
fnEnableRxInterrupts (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function enables the interrupts from the DMA channel and the MSCI.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DigiDump (DIGIFLOW, ("Entering fnEnableRxInterrupts()\n"));

	if (!(pDeviceExt->IsRxTxEnable & RXMSCI_INTE))
	{
		fnEnableRxDmaInterrupts (pDeviceExt);
		pDeviceExt->IsRxTxEnable |= RXMSCI_INTE;
	}

	if (!(pDeviceExt->IsRxTxEnable & RXDMA_INTE))
	{
		fnEnableRxMsciInterrupts (pDeviceExt);
		pDeviceExt->IsRxTxEnable |= RXDMA_INTE;
	}

	DigiDump (DIGIFLOW, ("Exiting fnEnableRxInterrupts()\n"));
}


VOID
fnDisableRxDmaInterrupts (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function disables the interrupt from the DMA channel.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	UCHAR   ScaHoldingCell;


	DigiDump (DIGIFLOW, ("Entering fnDisableRxDmaInterrupts()\n"));

	EnableScaMemMap (pDeviceExt);

	// Disable EOT, EOM, BOF, and COF interrupts
	WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dir, 0);

	// Disable DMA interrupts
	ScaHoldingCell = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pSca->ComIer1);
	ScaHoldingCell &= ~pDeviceExt->ScaIntCtrlRxDmaIntE;
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComIer1, ScaHoldingCell);

	DisableMemory (pDeviceExt);

	DigiDump (DIGIFLOW, ("Exiting fnDisableRxDmaInterrupts()\n"));
}


VOID
fnDisableRxMsciInterrupts (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function disables the interrupt from the MSCI for receiving.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	UCHAR   ScaHoldingCell;


	DigiDump (DIGIFLOW, ("Entering fnDisableRxMsciInterrupts()\n"));

	EnableScaMemMap (pDeviceExt);

	// Disable DSR interrupt.
	ScaHoldingCell = READ_REGISTER_UCHAR ((PUCHAR) & pDeviceExt->pScaMsci->Ie1);
	ScaHoldingCell &= ~MSCI_IE1_CDCDE;
	WRT_REG_UCHAR (&pDeviceExt->pScaMsci->Ie1, ScaHoldingCell);

	// Disable MSCI Master's RXINT interrupt
	ScaHoldingCell = READ_REGISTER_UCHAR ((PUCHAR) & pDeviceExt->pScaMsci->Ie0);
	ScaHoldingCell &= ~MSCI_IE0_RXINTE;
	WRT_REG_UCHAR (&pDeviceExt->pScaMsci->Ie0, ScaHoldingCell);

	// Disable Interrupts Controller's Master Receive Interrupts
	ScaHoldingCell = READ_REGISTER_UCHAR ((PUCHAR) & pDeviceExt->pSca->ComIer1);
	ScaHoldingCell &= ~pDeviceExt->ScaIntCtrlRxIntE;
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComIer1, ScaHoldingCell);

	DisableMemory (pDeviceExt);

	DigiDump (DIGIFLOW, ("Exiting fnDisableRxMsciInterrupts()\n"));
}


VOID
fnDisableRxInterrupts (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function disables the interrupts from the DMA channel and the MSCI.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DigiDump (DIGIFLOW, ("Entering fnDisableRxInterrupts()\n"));

	if (pDeviceExt->IsRxTxEnable & RXMSCI_INTE)
	{
		fnDisableRxDmaInterrupts (pDeviceExt);
		pDeviceExt->IsRxTxEnable &= ~RXMSCI_INTE;
	}

	if (pDeviceExt->IsRxTxEnable & RXDMA_INTE)
	{
		fnDisableRxMsciInterrupts (pDeviceExt);
		pDeviceExt->IsRxTxEnable &= ~RXDMA_INTE;
	}

	DigiDump (DIGIFLOW, ("Exiting fnDisableRxInterrupts()\n"));
}


VOID
fnCheckDsrStatus (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function is called when there is a Receive interrupt.  The sources
	for this interrupt are listed below:
		. DSR change (also DCD change).

Parameters:

	pControllerExt
		Address of the Controller extension.

Return Value:

	None.

--*/
{
	volatile UCHAR	RegVal, Status = 0;
	volatile UCHAR	ScaHoldingCell = 0;


//	DigiDump (DIGIFLOW, ("Entering fnCheckDsrStatus()\n"));

	EnableScaMemMap (pDeviceExt);

	// Check the DSR signal changes
	RegVal = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaMsci->St1);
	if (RegVal & MSCI_ST1_CDCDM)
	{
		// The DSR signal has changed, clear the DCD changed bit
#if 1
		ScaHoldingCell = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaMsci->St1);
		ScaHoldingCell |= MSCI_ST1_CDCDM;
		WRT_REG_UCHAR (&pDeviceExt->pScaMsci->St1, ScaHoldingCell);
#else
		WRT_REG_UCHAR (&pDeviceExt->pScaMsci->St1, MSCI_ST1_CDCDM);
#endif // 0

		RegVal = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaMsci->St3);

		// Check DSR drop
		if (RegVal & MSCI_ST3_DCDM)
		{
			// DSR Drop
			++pDeviceExt->IR.StatisticsCounters[SC_DSRDROP];
			++pDeviceExt->IR.StatusEvents;
			Status = 1;
		}
	}

	// Check the DCD signal
	RegVal = (*pDeviceExt->pControllerExt->pIO_IN) (
		pDeviceExt->pControllerExt->pDigiDcdIntReg);
	if (!(RegVal & pDeviceExt->DigiDcdMask))
	{
		// DCD drop
		++pDeviceExt->IR.StatisticsCounters[SC_DCDDROP];
		++pDeviceExt->IR.StatusEvents;
		Status = 1;
	}

	DisableMemory (pDeviceExt);

	if (Status)
		pDeviceExt->SignalService = TRUE;	// need to signal link service

//	DigiDump (DIGIFLOW, ("Exiting fnCheckDsrStatus()\n"));
}


VOID
fnStopRxDma (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will stop the receive DMA channel.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DigiDump (DIGIFLOW, ("Entering fnStopRxDma()\n"));


	if (pDeviceExt->IsRxTxEnable & RXDMA_ENABLE)
	{
		EnableScaMemMap (pDeviceExt);

		// Disable all DMAC interrupts
		WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dir, 0);

		// Disable DMA channel
		WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dsr, 0);

		// Reset current status
		WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dcr, DCR_SOFTWARE_ABORT);

		pDeviceExt->IsRxTxEnable &= ~RXDMA_ENABLE;

		DisableMemory (pDeviceExt);
	}

	DigiDump (DIGIFLOW, ("Exiting fnStopRxDma()\n"));
}


VOID
fnStopRxMsci (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will stop the MSCI receiver.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DigiDump (DIGIFLOW, ("Entering fnStopRxMsci()\n"));

	if (pDeviceExt->IsRxTxEnable & RXMSCI_ENABLE)
	{
		EnableScaMemMap (pDeviceExt);

		// Reject current receive frame
		WRT_REG_UCHAR ((PUCHAR) & pDeviceExt->pScaMsci->Cmd, CMD_RX_MSG_REJECT);

		// Reset receiver
		WRT_REG_UCHAR ((PUCHAR) & pDeviceExt->pScaMsci->Cmd, CMD_RX_RESET);

		pDeviceExt->IsRxTxEnable &= ~RXMSCI_ENABLE;

		DisableMemory (pDeviceExt);
	}

	DigiDump (DIGIFLOW, ("Exiting fnStopRxMsci()\n"));
}


VOID
fnStopReceiver (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will stop the receiver.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DigiDump (DIGIFLOW, ("Entering fnStopReceiver()\n"));

	fnStopRxMsci (pDeviceExt);
	fnStopRxDma (pDeviceExt);

	DigiDump (DIGIFLOW, ("Exiting fnStopReceiver()\n"));
}


VOID
fnCheckRxDmaError (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function is called when Receive DMA detected an error.  The
	following are possible reasons for the error:
		. Buffer overflow
		. Too many unprocessed, outstanding receive frames

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	volatile UCHAR	RegVal, RegFct;
	BOOLEAN			Reset = FALSE;


//	DigiDump (DIGIFLOW, ("Entering fnCheckRxDmaError()\n"));

	EnableScaMemMap (pDeviceExt);

	RegVal = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaRxDmac->Dsr);
	RegFct = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaRxDmac->Fct);

//	DigiDump (DIGIERRORS, (
//		"*** RX DMA DSR = %x\n"
//		"Rx Local CDA   = %x\n"
//		"Rx Local EDA   = %x\n"
//		"Rx SCA   CDA   = %x\n"
//		"Rx SCA   EDA   = %x\n"
//		"RxDspIn        = %x\n"
//		"RxDspOut       = %x\n"
//		"Rx FCT         = %x\n"
//		"RxFrames Cnt   = %x\n"
//		"Port           = %x\n",
//		RegVal,
//		(USHORT) pDeviceExt->pRxDmaDspCda,
//		(USHORT) pDeviceExt->pRxDmaDspEda,
//		READ_REGISTER_USHORT ((PUSHORT) &pDeviceExt->pScaRxDmac->Cda),
//		READ_REGISTER_USHORT ((PUSHORT) &pDeviceExt->pScaRxDmac->Eda),
//		pDeviceExt->RxDspIn,
//		pDeviceExt->RxDspOut,
//		RegFct,
//		pDeviceExt->ReceivedFrames,
//		pDeviceExt->PortNumber));

	if (RegVal & DMAC_DSR_BOFM)
	{
		// CDA == EDA and DMA is enabled
//		DigiDump (DIGIERRORS, ("*** RxDmaError:BOF (Buffer Overflow/Underflow)\n"));
		WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dsr, DMAC_DSR_CLEAR_BOF);
		++pDeviceExt->Stats.RxOverflow;
		Reset = TRUE;
	}

	if (RegVal & DMAC_DSR_COFM)
	{
		// FCT overrun
//		DigiDump (DIGIERRORS, ("*** RxDmaError:COF (Counter Overflow)\n"));

		// You must clear this bit to restart DMA after FCT Overflow
		WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dsr, DMAC_DSR_CLEAR_COF);
		WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dcr, DMAC_DCR_DMA_SW_ABORT);
		WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dcr, DMAC_DCR_CLEAR_FCT);
		Reset = TRUE;
	}

	if (Reset)
	{
		fnDisableRxInterrupts (pDeviceExt);
		fnStopReceiver (pDeviceExt);

		//  Reset receiver
		WRT_REG_UCHAR (&pDeviceExt->pScaMsci->Cmd, CMD_RX_RESET);
		fnInitializeRxDmaChains (pDeviceExt);

		// Start receiver
		fnStartReceiver (pDeviceExt);

		++pDeviceExt->IR.StatisticsCounters[SC_RXOVERRUN];
		++pDeviceExt->IR.StatusEvents;
		++pDeviceExt->Stats.RxOverrun;
		pDeviceExt->SignalService = TRUE;	// need to signal link service
		fnEnableRxInterrupts (pDeviceExt);
		pDeviceExt->ReceivedFrames = 0;
		pDeviceExt->IR.ReceivedFrames = 0;
	}

	DisableMemory (pDeviceExt);

//	DigiDump (DIGIFLOW, ("Exiting fnCheckRxDmaError()\n"));

}


VOID
fnCheckRxDmaGood (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function is called when a frame is received and no DMA error
	occurred.  The DMA might receive multiple frames before this
	routine can service it.  Thus, when this routine is called, it
	will service all outstanding received frames.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DMA_CHAIN		RxDmaDsp;
	USHORT			RxFrameLen;
	volatile USHORT	FirstDmaDspInd;
//	UCHAR			WindowNumber;
	volatile UCHAR	DmaStatus, DmacFctValue, RegVal;
	BOOLEAN			Done;


//	DigiDump (DIGIFLOW, ("Entering fnCheckRxDmaGood()\n"));

	EnableScaMemMap (pDeviceExt);

	// DMA interrupt status
	RegVal = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaRxDmac->Dsr);

	// Number of outstanding received frames
	DmacFctValue = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaRxDmac->Fct);

	DisableMemory (pDeviceExt);

	if (RegVal & DMAC_DSR_EOMM)
	{
		// End of frame interrupt
		do
		{
			// Process all the outstanding frames

			FirstDmaDspInd = pDeviceExt->RxDspIn;
			RxFrameLen = 0;

			// Clear the status bit. This will decrement the FCT count
			EnableScaMemMap (pDeviceExt);
			WRT_REG_UCHAR (&pDeviceExt->pScaRxDmac->Dsr, DMAC_DSR_CLEAR_EOM);
			DisableMemory (pDeviceExt);

			Done = FALSE;

			while (1)
			{
				fnReadFromCardMemory (
					(ULONG_PTR) &pDeviceExt->pRxRealDmaChainsArray[pDeviceExt->RxDspIn],
					(PUCHAR) &RxDmaDsp,
					(USHORT) DMA_CHAIN_SIZE,
					pDeviceExt);

				RxFrameLen += RxDmaDsp.DataLen;

				// The received frame might be stored on multiple buffers,
				// Only the last one will contain the receive status.
				if (RxDmaDsp.DmaStatus & DMAC_STATUS_MASK)
				{
					RxDmaDsp.FrameStatus = FS_GOOD_FRAME;
					DmaStatus = RxDmaDsp.DmaStatus;
					pDeviceExt->Stats.RxBytes += RxFrameLen;

					//  Commit the changes to card memory
					fnCopyToCardMemory (
						(PUCHAR) &RxDmaDsp,
						(ULONG_PTR) &pDeviceExt->pRxRealDmaChainsArray[pDeviceExt->RxDspIn],
						(USHORT) DMA_CHAIN_SIZE,
						pDeviceExt);

					UpdateInOutIndex (&pDeviceExt->RxDspIn, pDeviceExt);
					break;
				}
				else
				{
					RxDmaDsp.FrameStatus = FS_CONTINUE_FRAME;

					//  Commit the changes to card memory
					fnCopyToCardMemory (
						(PUCHAR) &RxDmaDsp,
						(ULONG_PTR) &pDeviceExt->pRxRealDmaChainsArray[pDeviceExt->RxDspIn],
						(USHORT) DMA_CHAIN_SIZE,
						pDeviceExt);

					UpdateInOutIndex (&pDeviceExt->RxDspIn, pDeviceExt);
				}
			}

			// Check receive status for error
			if (!fnCheckRxMsciError (pDeviceExt, RxFrameLen, DmaStatus))
			{
				// Receive error detected, need to update the descriptor
				++pDeviceExt->IR.ReceivedFrames;
				++pDeviceExt->ReceivedFrames;
				++pDeviceExt->Stats.RxFrames;
				pDeviceExt->SignalService = TRUE;	// signal link service

				while (!Done)
				{
					fnReadFromCardMemory (
						(ULONG_PTR) &pDeviceExt->pRxRealDmaChainsArray[pDeviceExt->RxDspOut],
						(PUCHAR) &RxDmaDsp,
						(USHORT) DMA_CHAIN_SIZE,
						pDeviceExt);

					if (FS_ERROR_FRAME == RxDmaDsp.FrameStatus)
					{
						UpdateInOutIndex (&pDeviceExt->RxDspOut, pDeviceExt);
					}
					else
					{
						Done = TRUE;
					}
				}

				fnAdjustRxDmacEdaDsp (pDeviceExt);	// Adjust descriptor
			}
			else
			{
				// Dma Error on frame
				fnUpdateDmaDspFrameErrorStatus (pDeviceExt, FirstDmaDspInd);
			}

		} while (--DmacFctValue);
	}

	if (RegVal & DMAC_DSR_EOTM)
	{
		EnableScaMemMap (pDeviceExt);

		//
		// End of transfer CDA == EDA
		// This condition should never occur. The driver will always update
		// the descriptor.
		//
//		DigiDump (DIGIERRORS, (
//			"*** RX EOT DSR = %x\n"
//			"Rx Local CDA   = %x\n"
//			"Rx Local EDA   = %x\n"
//			"Rx SCA   CDA   = %x\n"
//			"Rx SCA   EDA   = %x\n"
//			"RxDspIn        = %x\n"
//			"RxDspOut       = %x\n"
//			"Rx Frames      = %x\n"
//			"Port           = %x\n",
//			RegVal,
//			pDeviceExt->pRxDmaDspCda,
//			pDeviceExt->pRxDmaDspEda,
//			READ_REGISTER_USHORT ((PUSHORT) &pDeviceExt->pScaRxDmac->Cda),
//			READ_REGISTER_USHORT ((PUSHORT) &pDeviceExt->pScaRxDmac->Eda),
//			pDeviceExt->RxDspIn,
//			pDeviceExt->RxDspOut,
//			pDeviceExt->ReceivedFrames,
//			pDeviceExt->PortNumber));

		fnStopReceiver (pDeviceExt);
	}

	DisableMemory (pDeviceExt);

//	DigiDump (DIGIFLOW, ("Exiting fnCheckRxDmaGood()\n"));
}


BOOLEAN
fnCheckRxMsciError (
	IN PDEVICE_EXT	pDeviceExt,
	IN USHORT		RxFrameLen,
	IN UCHAR		DmaStatus)
/*++

Description:

	This function will check the receive error status.  The following are 
	possible errors:
		. Short frame
		. Aborted frame
		. Residual frame
		. Receive overrun
		. CRC error
		. Long frame

	If there are any errors, need to notify the Link Service Driver

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	volatile BOOLEAN	Status = FALSE;


	DigiDump (DIGIFLOW, ("Entering fnCheckRxMsciError()\n"));

	if (DmaStatus & DMAC_STATUS_SHRTM)
	{
		// Short frame
		++pDeviceExt->IR.StatisticsCounters[SC_SHORTFRAME];
		++pDeviceExt->IR.StatusEvents;
		Status = TRUE;
		DigiDump (DIGIERRORS, ("*** Short frame received\n"));
	}

	if (DmaStatus & DMAC_STATUS_ABORTM)
	{
		// Received aborted frame
		++pDeviceExt->IR.StatisticsCounters[SC_RXABORT];
		++pDeviceExt->IR.StatusEvents;
		++pDeviceExt->Stats.RxAbort;
		Status = TRUE;
		DigiDump (DIGIERRORS, ("*** Aborted frame received\n"));
	}

	if (DmaStatus & DMAC_STATUS_RBITM)
	{	
		// Received residual frame
		++pDeviceExt->IR.StatisticsCounters[SC_SPARE];
		++pDeviceExt->IR.StatusEvents;
		Status = TRUE;
		DigiDump (DIGIERRORS, ("*** Residual frame received\n"));
	}

	if (DmaStatus & DMAC_STATUS_OVRRNM)
	{
		// Receive overrun
		++pDeviceExt->IR.StatisticsCounters[SC_RXOVERRUN];
		++pDeviceExt->IR.StatusEvents;
		++pDeviceExt->Stats.RxOverrun;
		Status = TRUE;
		DigiDump (DIGIERRORS, ("*** Receive Overrun\n"));
	}

	if (DmaStatus & DMAC_STATUS_CRCM)
	{
		// CRC error
		++pDeviceExt->IR.StatisticsCounters[SC_CRC_ERROR];
		++pDeviceExt->IR.StatusEvents;
		++pDeviceExt->Stats.RxCrc;
		Status = TRUE;
		DigiDump (DIGIERRORS, ("*** CRC Error\n"));
	}

	if (RxFrameLen > pDeviceExt->Config.MaxFrameSize)
	{
		// Large frame receive
		++pDeviceExt->IR.StatisticsCounters[SC_LONGFRAME];
		++pDeviceExt->IR.StatusEvents;
		Status = TRUE;
		DigiDump (DIGIERRORS, ("*** Large frame received\n"));
	}

	DigiDump (DIGIFLOW, ("Exiting fnCheckRxMsciError()\n"));

	return Status;
}


VOID
fnUpdateDmaDspFrameErrorStatus (
	IN PDEVICE_EXT	pDeviceExt,
	IN USHORT		FirstDmaDspInd)
/*++

Description:

	This function will update the FrameStatus because the received frame has
	an error.  It will update all the descriptor that stored the frame.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	DMA_CHAIN	RxDmaDsp;


	DigiDump (DIGIFLOW, ("Entering fnUpdateDmaDspFrameErrorStatus()\n"));

	do
	{
		fnReadFromCardMemory (
			(ULONG_PTR) &pDeviceExt->pRxRealDmaChainsArray[FirstDmaDspInd],
			(PUCHAR) &RxDmaDsp,
			(USHORT) DMA_CHAIN_SIZE,
			pDeviceExt);

		RxDmaDsp.FrameStatus = FS_ERROR_FRAME;

		fnCopyToCardMemory (
			(PUCHAR) &RxDmaDsp,
			(ULONG_PTR) &pDeviceExt->pRxRealDmaChainsArray[FirstDmaDspInd],
			(USHORT) DMA_CHAIN_SIZE,
			pDeviceExt);

		UpdateInOutIndex (&FirstDmaDspInd, pDeviceExt);

	// Only the last buffer contains the receive status
	} while (!(RxDmaDsp.DmaStatus & DMAC_STATUS_MASK));

	DigiDump (DIGIFLOW, ("Exiting fnUpdateDmaDspFrameErrorStatus()\n"));
}


VOID
fnAdjustRxDmacEdaDsp (
	IN PDEVICE_EXT pDeviceExt)
/*++

Description:

	This function will update the Receive DMA Error Descriptor Address (EDA)
	so that the receiver can receive more frames.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	PDMA_CHAIN	pDmaDsp;
	DMA_CHAIN	RxDmaDsp;
	USHORT		CurrentCda = 0;
	UCHAR		WindowNumber = 0;


	DigiDump (DIGIFLOW, ("Entering fnAdjustRxDmacEdaDsp()\n"));

	pDmaDsp = &pDeviceExt->pRxRealDmaChainsArray[pDeviceExt->RxDspOut];
	if (pDmaDsp != pDeviceExt->pRxDmaDspEda)
	{
		EnableScaMemMap (pDeviceExt);

		CurrentCda = READ_REGISTER_USHORT ((PUSHORT) &pDeviceExt->pScaRxDmac->Cda);

		if (CurrentCda != (USHORT) pDmaDsp)
		{
			pDeviceExt->pRxDmaDspEda = pDmaDsp;
			WRT_REG_USHORT (&pDeviceExt->pScaRxDmac->Eda, pDmaDsp);
		}

		DisableMemory (pDeviceExt);
	}

	DigiDump (DIGIFLOW, ("Exiting fnAdjustRxDmacEdaDsp()\n"));
}


USHORT
fnGetReceivedFrameLen (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will retrieve the size of the received frame from the
	receive queue.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	USHORT		RxFrameLen = 0;
	USHORT		RxDspOut = pDeviceExt->RxDspOut;
	UCHAR		Reg = 0;
	DMA_CHAIN	RxDmaDsp;


	DigiDump (DIGIFLOW, ("Entering fnGetReceivedFrameLen()\n"));

	do
	{
		fnReadFromCardMemory (
			(ULONG_PTR) &pDeviceExt->pRxRealDmaChainsArray[RxDspOut],
			(PUCHAR) &RxDmaDsp,
			(USHORT) DMA_CHAIN_SIZE,
			pDeviceExt);

		UpdateInOutIndex (&RxDspOut, pDeviceExt);

		if (FS_ERROR_FRAME != RxDmaDsp.FrameStatus)
			RxFrameLen += RxDmaDsp.DataLen;
		else
			pDeviceExt->RxDspOut = RxDspOut;

	} while (FS_CONTINUE_FRAME == RxDmaDsp.FrameStatus);


	DigiDump (DIGIDEBUGRX,
		("<fnGetReceivedFrameLen> Recv'd frame length is 0x%x\n", RxFrameLen));

	DigiDump (DIGIFLOW, ("Exiting fnGetReceivedFrameLen()\n"));

	return (RxFrameLen);
}

