/*++
*******************************************************************************
* 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 Name:

	asynsdxb.c

Abstract:

	Wrapper functions for the S/DXB firmware interface.

Author:

	Michael Zarns

--*/
#include "digiasyn.h"
#include "isdn_proto.h"
/*
// Callback routine for Data only messages
typedef void (*PASYN_RXENGINE_DATA_HANDLER) ( HANDLE Context, PVOID pData, ULONG cbData );

// Callback routine for Control+Data messages
typedef void (*PASYN_RXENGINE_CDATA_HANDLER)( HANDLE Context, PVOID pCtrl, ULONG cbCtrl, PVOID pData, ULONG cbData );
*/



STATIC VOID
SdxbPutMsgComplete(
	IN HANDLE   hOwner,
	IN HANDLE   Context,
	IN PVOID    pControl,
	IN ULONG    cbControl,
	IN PVOID    pData,
	IN ULONG    cbData,
	IN NTSTATUS IoStatus )
/*++

Description:

	Required completion routine for DsPutMsgEx api.  Normally a completion routine 
	would free data buffers, but with SDXB commands there are no data buffers so 
	there's nothing to free.

Parameters:

	hOwner, Context
		Ignored

	pControl, cbControl
		Control buffer and length

	pData, cbData
		Data buffer and length

	IoStatus
		Status returned from Dxb.  An error means this message was *not* passed down
		to firmware.

--*/
{
	// We don't expect a data block, but if there is one, somebody needs to free it.
	// That somebody should probably be me.
	//
	// Control buffers are owned by Dxb and are never freed.
	if ( pData && cbData )
		DigiFreeMem( pData );
	
	if ( NT_ERROR(IoStatus) )
	{
		DigiDump( DIGIWARN, ( "Asyn:SdxbPutMsgComplete: got IoStatus 0x%x!\n", IoStatus ) );
#if !NT5_BUILD
		// Verifier bugchecks in DigiDumpData
		if ( pControl && cbControl )
		{
			DigiDumpData( DIGIWARN, pControl, cbControl );
		}
#endif
	}
}


NTSTATUS
SdxbSync(
	IN HANDLE  hStream,
	IN USHORT  SequenceNumber,
	IN BOOLEAN Drain )
/*++

Description:

	Send a SYNC command down to S/DXB.

Parameters:

	hStream
		Handle to previously opened dxb stream on which to send the command.

	SequenceNumber
		Caller defined sequence number that should be unique and should be incremented
		for each sync request.  Firmware will ack with a sync response, but if multiple
		sync requests are sent down, the fep may only ack the last one sent.

	Drain
		If Drain is set, the request will be sent lo-priority with the DRAIN field set.
		This tells S/DXB to wait for all data to be transmitted before replying with a 
		sync response.

		If Drain is clear, the request is sent high-priority with the Drain field clear.
		In this case, S/DXB will send back a sync response once previous commands 
		have completed and does not wait for previously transmitted data to be sent on
		the wire.

Return Value:

	STATUS_SUCCESS indicates the request was sent down successfully, otherwise error.

--*/
{
	NTSTATUS Status = STATUS_SUCCESS;
	DS_PRIORITY Priority = Drain ? DS_PRIORITY_LOW : DS_PRIORITY_HIGH;
	struct sdxb_sync_command cmd = {0};
	cmd.ctype = SDXB_SYNC;
	cmd.flags = Drain ? SDXB_RESPPRI|DRAIN : SDXB_RESPPRI;
	cmd.sseq  = SequenceNumber;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, Priority, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbBufsize(
	IN HANDLE hStream )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_bufsize_command cmd = {0};
	cmd.ctype = SDXB_BUFSIZE;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbMstat(
	IN HANDLE  hStream,
	IN UCHAR   Mint,
	IN UCHAR   Mout,
	IN BOOLEAN ImmediateResponse )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_mstat_command cmd = {0};
	cmd.ctype = SDXB_MSTAT;
	cmd.flags = ImmediateResponse ? SDXB_IMMED | SDXB_RESPPRI : SDXB_RESPPRI;
	cmd.mint  = Mint;
	cmd.mout  = Mout;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbEvent(
	IN HANDLE hStream,
	IN USHORT Eint )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_event_command cmd = {0};
	cmd.ctype = SDXB_EVENT;
	cmd.flags = SDXB_RESPPRI;
	cmd.eint  = Eint;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbLerr(
	IN HANDLE hStream,
	IN USHORT Ltime )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_lerr_command cmd = {0};
	cmd.ctype = SDXB_LERR;
	cmd.ltime = Ltime;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbPcap(
	IN HANDLE hStream )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_pcap_command cmd = {0};
	cmd.ctype = SDXB_PCAP;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbParam(
	IN HANDLE hStream,
	IN struct sdxb_param_command * pParam )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_param_command cmd = *pParam;
	cmd.ctype = SDXB_PARAM;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbWmark(
	IN HANDLE hStream,
	IN ULONG  rlow,
	IN ULONG  rhigh )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_wmark_command cmd = {0};
	cmd.ctype = SDXB_WMARK;
	cmd.rlow  = rlow;
	cmd.rhigh = rhigh;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbSeq(
	IN HANDLE hStream,
	IN ULONG  rmax,
	IN ULONG  rtime,
	IN ULONG  tmax,
	IN ULONG  ttime,
	IN ULONG  icdtime )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_seq_command cmd = {0};
	cmd.ctype   = SDXB_SEQ;
	cmd.rmax    = rmax;
	cmd.rtime   = rtime;
	cmd.tmax    = tmax;
	cmd.ttime   = ttime;
	cmd.icdtime = icdtime;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbScimmed(
	IN HANDLE hStream,
	IN UCHAR  ImmediateChar )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_scimmed_command cmd = {0};
	cmd.ctype = SDXB_SCIMMED;
	cmd.sic   = ImmediateChar;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbBreak(
	IN HANDLE hStream,
	IN USHORT btime )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_break_command cmd = {0};
	cmd.ctype = SDXB_BREAK;
	cmd.btime = btime;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbFlush(
	IN HANDLE hStream,
	IN UCHAR  Flags )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_flush_command cmd = {0};
	cmd.ctype = SDXB_FLUSH;
	cmd.flags = Flags;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbPause(
	IN HANDLE hStream,
	IN UCHAR  pset,
	IN UCHAR  preset )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct sdxb_pause_command cmd = {0};
	cmd.ctype  = SDXB_PAUSE;
	cmd.pset   = pset;
	cmd.preset = preset;

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );
	return Status;
}


NTSTATUS
SdxbIsdn(
	IN HANDLE hStream,
	IN PVOID  pBuf,
	IN ULONG  cbBuf )
{
	NTSTATUS Status = STATUS_SUCCESS;
	struct
	{
		dxb_uint8 ctype;
		union ISDN_primitives msg;
	} cmd;

	cmd.ctype  = SDXB_ISDN;
	if ( cbBuf > sizeof cmd.msg )
	{
		DigiDump( DIGIWARN, ( "Asyn!SdxbIsdn: Request too big, rejected.\n" ) );
		Status = STATUS_UNSUCCESSFUL;
		goto Exit;
	}
	RtlCopyMemory( &cmd.msg, pBuf, cbBuf );

	Status = DsPutMsgEx( hStream, &cmd, sizeof cmd, NULL, 0, NULL, DS_PRIORITY_HIGH, SdxbPutMsgComplete );

Exit:
	return Status;
}


VOID
SdxbMessageCracker(
	IN HANDLE hOwner, 
	IN PVOID  pControl,
	IN ULONG  cbControl )
/*++

Description:

	Called to crack SDXB messages received up from the fep.  Decode the message and
	call the appropriate port message handler.

Parameters:

	hOwner
		Handle passed transparently back up to port message handler.  This is the handle
		passed in the original DsOpen request for the stream on which this message was
		received.

	pControl
		Control buffer received from fep.  This buffer contains the SDXB message.

	cbControl
		Count of bytes in the control buffer.

Return Value:

	None

--*/
{
	// Put all the responses we know about in a union so we can easily use the buffer
	// correctly for each message.
	union SDXB_RESPONSES
	{
		dxb_uint8 ctype;
		struct sdxb_sync_response     sync;
		struct sdxb_bufsize_response  bufsize;
		struct sdxb_mstat_response    mstat;
		struct sdxb_event_response    event;
		struct sdxb_lerr_response     lerr;
		struct sdxb_pcap_response     pcap;
		struct sdxb_param_response    param;
		struct sdxb_seq_response      seq;
		struct sdxb_screcv_response   screcv;
		struct sdxb_frexcp_response   frexcp;
		struct sdxb_txprint_response  txprint;
		struct sdxb_proterr_response  proterr;
		struct sdxb_markidle_response markidle;
		struct
		{
			dxb_uint8             ctype;
			union ISDN_primitives msg;
		}                             isdn;
	};

	union SDXB_RESPONSES const * pResponse = pControl;
	if ( cbControl < sizeof pResponse->ctype )
	{
		DigiDump( DIGIWARN, ( "Asyn!SdxbCracker: Invalid buffer received, cb 0x%x\n", cbControl ) );
		return;
	}

	switch ( pResponse->ctype )
	{
		case SDXB_SYNC:
			ASSERT( cbControl == sizeof pResponse->sync );
			PortOnSdxbSync( hOwner, pResponse->sync.sseq );
			break;

		case SDXB_BUFSIZE:
			ASSERT( cbControl == sizeof pResponse->bufsize );
			PortOnSdxbBufsize( hOwner, pResponse->bufsize.insize, pResponse->bufsize.outsize );
			break;

		case SDXB_MSTAT:
			ASSERT( cbControl == sizeof pResponse->mstat );
			PortOnSdxbMstat( hOwner, pResponse->mstat.mstat );
			break;

		case SDXB_EVENT:
			ASSERT( cbControl == sizeof pResponse->event );
			PortOnSdxbEvent( hOwner, pResponse->event.estat );
			break;

		case SDXB_LERR:
			ASSERT( cbControl == sizeof pResponse->lerr );
			PortOnSdxbLerr( hOwner, (PVOID)&pResponse->lerr );
			break;

		case SDXB_PCAP:
			ASSERT( cbControl == sizeof pResponse->pcap );
			PortOnSdxbPcap( hOwner, (PVOID)&pResponse->pcap );
			break;

		case SDXB_PARAM:
			ASSERT( cbControl == sizeof pResponse->param );
			PortOnSdxbParam( hOwner, (PVOID)&pResponse->param );
			break;

		case SDXB_SEQ:
			ASSERT( cbControl == sizeof pResponse->seq );
			PortOnSdxbSeq( hOwner, pResponse->seq.rin, pResponse->seq.tout );
			break;

		case SDXB_SCRECV:
			ASSERT( cbControl == sizeof pResponse->screcv );
			PortOnSdxbScrecv( hOwner );
			break;

		case SDXB_FREXCP:
			ASSERT( cbControl == sizeof pResponse->frexcp );
			PortOnSdxbFrexcp( hOwner, pResponse->frexcp.flags );
			break;

		case SDXB_TXPRINT:
			ASSERT( cbControl == sizeof pResponse->txprint );
			PortOnSdxbTxprint( hOwner );
			break;

		case SDXB_MARKIDLE:
			ASSERT( cbControl == sizeof pResponse->markidle );
			PortOnSdxbMarkidle( hOwner );
			break;

		case SDXB_PROTERR:
			ASSERT( cbControl == sizeof pResponse->proterr );
			PortOnSdxbProterr( hOwner, pResponse->proterr.offset, (PVOID)&pResponse->proterr.badreq );
			break;

		case SDXB_ISDN:
			PortOnSdxbIsdn( hOwner, (PVOID)&pResponse->isdn.msg );
			break;

		default:
			DigiDump( DIGIWARN, ( "Asyn!SdxbCracker: Unknown message, 0x%x\n", pResponse->ctype ) );
			if ( cbControl )
			{
				DigiDumpData( DIGIWARN, (PVOID)pResponse, cbControl );
			}
			break;
	}	
}


VOID	AsynOnHighPriorityCData
( 
	IN HANDLE Context, 
 	IN PVOID pControl, 
   IN ULONG cbControl, 
   IN PVOID pData, 
   IN ULONG cbData 
)
{
	if (cbControl)
	{
		SdxbMessageCracker( Context, pControl, cbControl );
	}

	if ( pData || cbData )
   {
		DigiDump( DIGIWARN, ( "AsynOnHighPrioriy CData: received data!\n" ) );
		if ( pData && cbData )
		{
			DigiDumpData( DIGIWARN, pData, cbData );
		}
      if ( pData )
	   	RxEngineFreeData( pData );
   }
   
}

VOID	AsynOnHighPriorityData
( 
	IN HANDLE Context, 
   IN PVOID pData, 
   IN ULONG cbData 
)
{
	if ( pData || cbData )
   {
		DigiDump( DIGIWARN, ( "AsynOnHighPrioriyData: received data!\n" ) );
		if ( pData && cbData )
		{
			DigiDumpData( DIGIWARN, pData, cbData );
		}
   }
   if ( pData )
	   RxEngineFreeData( pData );
}


VOID	AsynOnCData
( 
	IN HANDLE Context, 
 	IN PVOID pControl, 
   IN ULONG cbControl, 
   IN PVOID pData, 
   IN ULONG cbData 
)
{
	if (cbControl)
	{
		SdxbMessageCracker( Context, pControl, cbControl );
	}
   
	if (cbData)
	{
		AsynOnData( Context, pData, cbData );
	}
   else
	{
   	if ( pData )
	   	RxEngineFreeData( pData );
   }   	
}

