/*
 ****************************************************************************
 * Copyright (c) 1999-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 File:  asynrsp.c
 *
 * Author      : Sandy Haapala	  
 *
 * Purpose     :
 *
 *
 *----------------------------------------------------------------------
 */

#include "digiasyn.h"
#include "asynwrite.h"

VOID
PortOnSdxbSync(
	IN	PASYN_PORT_EXT			pPortExt,
	IN	USHORT					SyncSeq
)
{
	DigiDump(DIGISDXBRSP | DIGIFLOW, ("ASYN!PortOnSdxbSync: Port=%d SyncSeqNum=0x%x State=0x%x\n",
	         pPortExt->iSdxbPort, SyncSeq, pPortExt->State ));

	switch ( pPortExt->State )                 
	{
		case OpenInProgressState:
			AsynOpenOnSdxbSync( pPortExt, SyncSeq );
			break;
		case OpenState:
			AsynIoctlOnSdxbSync( pPortExt, SyncSeq );
			break;
		case CloseWaitTxDrainState:
      case CloseOnFinalSyncState:
			AsynCloseOnSdxbSync( pPortExt, SyncSeq );
			break;                  
	}
}


VOID
PortOnSdxbMstat(
	IN PASYN_PORT_EXT			pPortExt,
	IN UCHAR						ModemStat
)
{
	UCHAR		LastMstat;
	PASYN_SDXB		pSdxbExt = &pPortExt->SdxbValues;

	DigiDump(DIGISDXBRSP | DIGIFLOW, ("ASYN!OnModemStatus: Port=%d Mstat=0x%x\n",
	               pPortExt->iSdxbPort, ModemStat ));

	DigiAcquireSpinLock( &pSdxbExt->Lock );
	               
	LastMstat = pSdxbExt->Mstat;
	pPortExt->SdxbValues.Mstat = ModemStat;
	DigiReleaseSpinLock( &pSdxbExt->Lock );                     

	// TODO: Trace change in modem signals
   
	// Check for wait events
	if ( pPortExt->Wait.Mask & ( SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_RING ))
	{
		// Get the changed signals that we need for wait events
		UCHAR ChangedMstat = ( LastMstat ^ ModemStat ) & (SDXB_CTS | SDXB_DSR | SDXB_DCD | SDXB_RI) ;

		if ( ChangedMstat )
		{
			ULONG	EventReason = 0;

			if ( ChangedMstat & SDXB_CTS ) EventReason |= SERIAL_EV_CTS;
			if ( ChangedMstat & SDXB_DSR ) EventReason |= SERIAL_EV_DSR;
			if ( ChangedMstat & SDXB_DCD ) EventReason |= SERIAL_EV_RLSD;
			if ( ChangedMstat & SDXB_RI  ) EventReason |= SERIAL_EV_RING;

			if ( EventReason )
				AsynSatisfyWait( pPortExt, EventReason, FALSE );
		}
	}
}


VOID
PortOnSdxbLerr
(
	IN PASYN_PORT_EXT			pPortExt,
	IN struct sdxb_lerr_response * pLineErr
)
{
	ULONG EventReason = 0;
	PASYN_SDXB			pSdxbExt = &pPortExt->SdxbValues;

	DigiDump(DIGISDXBRSP | DIGIFLOW, 
						("ASYN!OnLineError: RX Port=%d LINE_ERR orun=0x%x oflow=0x%x frame=0x%x parity=0x%x break=0x%x\n",
						pPortExt->iSdxbPort, pLineErr->norun, pLineErr->noflow, pLineErr->nframe, pLineErr->nparity, pLineErr->nbreak ));

	DigiAcquireSpinLock( &pSdxbExt->Lock );                  
	if ( pSdxbExt->Norun != pLineErr->norun )
	{
		pSdxbExt->CommErr |= SERIAL_ERROR_OVERRUN;
		EventReason |= SERIAL_EV_ERR;
		pSdxbExt->PerfStats.SerialOverrunErrorCount += ( pLineErr->norun - pSdxbExt->Norun );
		pSdxbExt->Norun = pLineErr->norun;
	}

	if ( pSdxbExt->Noflow != pLineErr->noflow )
	{
		pSdxbExt->CommErr |= SERIAL_ERROR_QUEUEOVERRUN;
		EventReason |= SERIAL_EV_ERR;
		pSdxbExt->PerfStats.BufferOverrunErrorCount += (pLineErr->noflow - pSdxbExt->Noflow );
		pSdxbExt->Norun = pLineErr->norun;
	}

	if ( pSdxbExt->Nframe != pLineErr->nframe )
	{
		pSdxbExt->CommErr |= SERIAL_ERROR_FRAMING;
		EventReason |= SERIAL_EV_ERR;
		pSdxbExt->PerfStats.FrameErrorCount += (pLineErr->nframe - pSdxbExt->Nframe );
		pSdxbExt->Nframe = pLineErr->nframe;
	}

	if ( pSdxbExt->Nparity != pLineErr->nparity )
	{
		pSdxbExt->CommErr |= SERIAL_ERROR_PARITY;
		EventReason |= SERIAL_EV_ERR;
		pSdxbExt->PerfStats.ParityErrorCount += (pLineErr->nparity - pSdxbExt->Nparity );
		pSdxbExt->Nparity = pLineErr->nparity;
	}

	if ( pSdxbExt->Nbreak != pLineErr->nbreak )
	{
		pSdxbExt->CommErr |= SERIAL_ERROR_BREAK;
		EventReason |= SERIAL_EV_BREAK;
		pSdxbExt->Nbreak = pLineErr->nbreak;
	}
	DigiReleaseSpinLock( &pSdxbExt->Lock );                     

	// Check if wait events can be completed   
	if ( EventReason )
		AsynSatisfyWait( pPortExt, EventReason, FALSE );
      

}


VOID
PortOnSdxbPcap
(
	IN	PASYN_PORT_EXT			pPortExt,
	IN struct sdxb_pcap_response * pcap 
)
{
	PASYN_SDXB pSdxbExt = &pPortExt->SdxbValues;                  
	DigiDump(DIGISDXBRSP | DIGIFLOW, 
						("ASYN!PortOnSdxbPcap: RX Port=%d Type=0x%x Capabilities=0x%x\n",	pPortExt->iSdxbPort,pcap->ptype,pcap->cvec ));
	pSdxbExt->PortType = pcap->ptype;
	pSdxbExt->PortCapabilities = pcap->cvec;
}   


VOID
PortOnSdxbParam
(
	IN PASYN_PORT_EXT			pPortExt,
	IN	PSDXB_PORT_PARAM_RSP pPortParam 
)
{
	DigiDump(DIGISDXBRSP | DIGIFLOW, 
						("ASYN!OnPortParameter: RX Port=%d Baud rate=%d cflag=x%x xflags=x%x\n",
						pPortExt->iSdxbPort, pPortParam->speed,pPortParam->cflags,pPortParam->xflags));

}   
                     

VOID 
PortOnSdxbSeq
(
	IN PASYN_PORT_EXT pPortExt, 
	IN ULONG rin, 
	IN ULONG tout 
)
{
	PASYN_WRITE		pWrite = &pPortExt->Write;
	PIRP			pIrp;
	PLIST_ENTRY		list;


	DigiDump(DIGISDXBRSP | DIGIFLOW, 
						("ASYN!PortOnSdxbSeq: RX Port=%d rin=x%x tout=x%x\n",	pPortExt->iSdxbPort,rin,tout ));

	DigiAcquireSpinLock( &pWrite->Lock );
	pWrite->Sequence.CurrentCountOut = tout;
	DigiReleaseSpinLock( &pWrite->Lock );

	if ( pWrite->Sequence.WaitForWrite )
		KeSetEvent( &pWrite->Sequence.ClearEvent, 0 , FALSE );  

	if ( pWrite->Sequence.WaitTillDone )
		AsynCompleteWaitingIrp( pPortExt );

	if ( pWrite->Sequence.WaitEmptyEvent )
	{
		if ( pWrite->Sequence.CurrentCountIn == pWrite->Sequence.CurrentCountOut )
		{
			KeSetEvent( &pWrite->Sequence.EmptyEvent, 0, FALSE );
			AsynSatisfyWait( pPortExt, SERIAL_EV_TXEMPTY, TRUE );
		}
	}

	DigiAcquireSpinLock( &pWrite->Lock );
	if ( !IsListEmpty(&pWrite->Sequence.FlushList) )
	{
		list = RemoveHeadList( &pWrite->Sequence.FlushList );
		pIrp = CONTAINING_RECORD( list, IRP, Tail.Overlay.ListEntry );

		if ( pIrp->IoStatus.Information <= tout ) // Because I keep the current buffer count in the information field
		{
			DigiReleaseSpinLock( &pWrite->Lock );
			IoSetCancelRoutine( pIrp, NULL );
			AsynIoCompleteRequest( pIrp, STATUS_SUCCESS, NULL );
		}
		else
		{
			InsertHeadList( &pWrite->Sequence.FlushList, &pIrp->Tail.Overlay.ListEntry );
			DigiReleaseSpinLock( &pWrite->Lock );
		}

	}
	else
		DigiReleaseSpinLock( &pWrite->Lock );

}

VOID 
PortOnSdxbFrexcp
(
	IN PASYN_PORT_EXT pPortExt, 
	IN UCHAR flags 
)   
{
	DigiDump(DIGISDXBRSP | DIGIFLOW, 
						("ASYN!PortOnSdxbFrexcp: RX Port=%d flags=x%x\n",	pPortExt->iSdxbPort,flags ));
}

VOID 
PortOnSdxbTxprint
( 
	IN PASYN_PORT_EXT pPortExt
)
{
	DigiDump(DIGISDXBRSP | DIGIFLOW, 
						("ASYN!PortOnSdxbTxprint: RX Port=%d\n",	pPortExt->iSdxbPort ));
}

VOID 
PortOnSdxbMarkidle
( 
	IN PASYN_PORT_EXT pPortExt
)
{
	DigiDump(DIGISDXBRSP | DIGIFLOW, 
						("ASYN!PortOnSdxbMarkIdle: RX Port=%d\n",	pPortExt->iSdxbPort ));
}

VOID
PortOnSdxbProterr
( 
	IN PASYN_PORT_EXT pPortExt, 
	IN USHORT offset, 
	IN UCHAR  badreq[]
)
{
	DigiDump(DIGISDXBRSP | DIGIFLOW, 
						("ASYN!PortOnSdxbProterr: RX Port=%d\n",	pPortExt->iSdxbPort ));
}



VOID
PortOnSdxbEvent
(
	IN PASYN_PORT_EXT			pPortExt,
	IN USHORT					Estat
)
{
	DigiDump(DIGISDXBRSP | DIGIFLOW, 
						("ASYN!OnEvent: RX Port=%d Current event status=0x%x\n",
						pPortExt->iSdxbPort, Estat));

	pPortExt->SdxbValues.Estat = Estat;   	

}


VOID
PortOnSdxbScrecv
(
	IN PASYN_PORT_EXT			pPortExt
)
{
	DigiDump(DIGISDXBRSP | DIGIFLOW, ("ASYN!OnSpecialChar: RX Port=%d\n", 
									pPortExt->iSdxbPort ));

	// Special character will be in the next receive buffer...
	AsynSatisfyWait( pPortExt, SERIAL_EV_RXFLAG, FALSE );
}


VOID
PortOnSdxbBufsize
(
	IN PASYN_PORT_EXT			pPortExt,
	IN ULONG						Insize,
	IN ULONG						Outsize
)
{
	DigiDump(DIGISDXBRSP | DIGIFLOW, ("ASYN!SDXB: RX Port=%d BUF_SIZE In=0x%x Out=0x%x\n",
									pPortExt->iSdxbPort, Insize, Outsize));

	pPortExt->Write.cbMaxPutMsg = Outsize;      

	{
		PASYN_READ pReadExt = &pPortExt->Read;

		if ( pReadExt->cbMaxRxQ < Insize )
		{
			pReadExt->cbMaxRxQ = Insize;
			if ( pReadExt->fRxPaused && pReadExt->cbRxQ < pReadExt->cbMaxRxQ )
			{
				RxEngineUnpause( pPortExt->hRxEngine_LowPriority );
				pReadExt->fRxPaused = FALSE;
			}            
		}         
	}
}


VOID
PortOnSdxbIsdn
(
	IN PASYN_PORT_EXT			pPortExt,
	IN PVOID					 	msg
)
{
}

