/*++
*******************************************************************************
* Copyright (c) 1990-98 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:

   isdnv2.c

Abstract:

   Version 2 of Spider Isdn Api.  Used by Dense family ISDN adapters.

Author:

   Michael Zarns

--*/

#include "digiisdn.h"
#pragma hdrstop
#include "..\..\firmware\dense\inc\isdn_proto.h"

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

Description:

	Generic completion routine for PutMsgs with no data portion.  Does nothing.

--*/
{
	ASSERT( pOwner != NULL );
	ASSERT( Context == NULL );
	ASSERT( pControl != NULL );
	ASSERT( cbControl != 0 );
	ASSERT( pData == NULL );
	ASSERT( cbData == 0 );

	if ( NT_ERROR( IoStatus ) )
	{
		DigiDump( DIGIWARN, ( "DXB:V2PutComplete pOwner 0x%x, pIoStatus 0x%x!\n", 
		          pOwner, IoStatus ) );
	}
}


STATIC NTSTATUS
V2Connect(
	PVOID   pOwner,
	HANDLE  hStream,
	ULONG   Snid,
	ULONG   MaxFrameSize,
	ULONG   ConnType,
	PSTRING pCalledID )
/*++

Description:

	Sends an XN_CONNECT request out.  Used when dialing.

--*/
{
	NTSTATUS Status;
	xn_call_t Connect = { 0 };
	Connect.command        = XN_CONNECT;
	Connect.snid           = Snid;
	Connect.chan_type      = B_CH;
	Connect.max_frame_size = MaxFrameSize;

	switch ( ConnType )
	{
		case ISDN_CONN_TOLLSAVER:
			Connect.cip = CIP_TOLLSAVER;
			break;

		case ISDN_CONN_D56:
			Connect.cip = CIP_RA56K;
			break;

		case ISDN_CONN_D64:
			Connect.cip = CIP_UDI;
			break;
			
		default:
			DigiDump( DIGIWARN, ( "Isdn!V2Connect: Warning - overriding invalid ConnType 0x%x!\n", ConnType ) );
			Connect.cip = CIP_UDI;
			break;
	}

	// Destination Address
	{
		STRING Dest = { 0 };
		Dest.Buffer = Connect.dest_address.number;
		Dest.MaximumLength = sizeof Connect.dest_address.number;

		ASSERT( Dest.MaximumLength >= pCalledID->Length );
		RtlCopyString( &Dest, pCalledID );
		Connect.dest_address.number_len = Dest.Length;
	}

	DigiDump( DIGIV2, ( "Isdn!V2Connect: pOwner 0x%x, Snid 0x%x, RemoteAddr %s\n", pOwner, Snid, pCalledID->Buffer ) );
	Status = DsPutMsgEx( hStream, &Connect, sizeof Connect, NULL, 0, NULL, DS_PRIORITY_LOW, V2PutComplete );

	return Status;
}


STATIC NTSTATUS
V2Connack(
	PVOID  pOwner,
	HANDLE hStream,
	ULONG  ChanIndex,
	ULONG  Channel )
/*++

Description:

	Sends an XN_CONNACK request to the board.  Used to accept an incoming call.

--*/
{
	xn_cccc_t Connack = { 0 };

	Connack.command    = XN_CONNACK;
	Connack.channel    = Channel;
	Connack.chan_index = ChanIndex;

	DigiDump( DIGIV2, ( "Isdn!V2Connack: pOwner 0x%x, ChanIndex 0x%x, Channel 0x%x\n", pOwner, ChanIndex, Channel ) );
	return DsPutMsgEx( hStream, &Connack, sizeof Connack, NULL, 0, NULL, DS_PRIORITY_LOW, V2PutComplete );
}


STATIC NTSTATUS
V2Disconn(
	PVOID  pOwner,
	HANDLE hStream,
	ULONG  ChanIndex,
	ULONG  Channel )
/*++

Description:

	Sends an XN_DISCONN request to the board.  Used to drop or reject a call currently 
	in progress.

--*/
{
	xn_cccc_t Disconn = { 0 };

	Disconn.command    = XN_DISCONN;
	Disconn.channel    = Channel;
	Disconn.chan_index = ChanIndex;

	DigiDump( DIGIV2, ( "Isdn!V2Disconn: pOwner 0x%x, ChanIndex 0x%x, Channel 0x%x\n", pOwner, ChanIndex, Channel ) );
	return DsPutMsgEx( hStream, &Disconn, sizeof Disconn, NULL, 0, NULL, DS_PRIORITY_LOW, V2PutComplete );
}


STATIC NTSTATUS
V2Connend(
	PVOID  pOwner,
	HANDLE hStream,
	ULONG  ChanIndex,
	ULONG  Channel )
/*++

Description:

	Sends an XN_CONNEND request to the board.  Used to reject an incoming call 
	that has not yet been accepted.

--*/
{
	xn_cccc_t Connend = { 0 };

	Connend.command    = XN_CONNEND;
	Connend.channel    = Channel;
	Connend.chan_index = ChanIndex;

	DigiDump( DIGIV2, ( "Isdn!V2Connend: pOwner 0x%x, ChanIndex 0x%x, Channel 0x%x\n", pOwner, ChanIndex, Channel ) );
	return DsPutMsgEx( hStream, &Connend, sizeof Connend, NULL, 0, NULL, DS_PRIORITY_LOW, V2PutComplete );
}


STATIC NTSTATUS
V2Listen(
	PVOID  pOwner,
	HANDLE hStream,
	ULONG  Snid )
/*++

Description:

	Sends an XN_LISTEN request to the board.  Required to accept incoming calls.

--*/
{
	xn_lstn_t Listen = { 0 };

	Listen.command = XN_LISTEN;
	Listen.snid    = Snid;

	DigiDump( DIGIV2, ( "Isdn!V2Listen: pOwner 0x%x, Snid 0x%x\n", pOwner, Snid ) );
	return DsPutMsgEx( hStream, &Listen, sizeof Listen, NULL, 0, NULL, DS_PRIORITY_LOW, V2PutComplete );
}


STATIC VOID
V2Interpreter(
	IN PVOID                pOwner, 
	IN PISDN_EVENT_HANDLERS pDispatchTable,
	IN PVOID                pControl, 
	IN ULONG                cbControl, 
	IN PVOID                pData, 
	IN ULONG                cbData )
/*++

Description:

	Called by RxEngine to interpret and process a single incoming message from the card.

--*/
{
	union ISDN_primitives const * const pMsg = pControl;
	if ( pMsg != NULL )
	{
		// Control Messages
		switch ( pMsg->command )
		{
			case XN_LISTEN:
				DigiDump( DIGIV2, ( "Isdn!V2Interpreter: XN_LISTEN on pOwner 0x%x\n", pOwner ) );
				pDispatchTable->OnListen( pOwner );
				break;

			case XN_CONNECT:
				DigiDump( DIGIV2, ( "Isdn!V2Interpreter: XN_CONNECT on pOwner 0x%x\n", pOwner ) );
				{
					ISDN_CONN_TYPE ConnType;
#if 0
					switch ( pMsg->call.appid )
					{
						case APPID_64K_DIGITAL_CALL:	ConnType = ISDN_CONN_D64;			break;
						case APPID_56K_DIGITAL_CALL:	ConnType = ISDN_CONN_D56;			break;
						case APPID_TOLLSAVER_56K_CALL:	
						default:								ConnType = ISDN_CONN_TOLLSAVER;	break;
					}
#else
					switch ( pMsg->call.cip )
					{
						case CIP_RA56K:		ConnType = ISDN_CONN_D56;			break;
						case CIP_RDI:			ConnType = ISDN_CONN_D56;			break;
						case CIP_UDI:			ConnType = ISDN_CONN_D64;			break;
						case CIP_TOLLSAVER:	ConnType = ISDN_CONN_TOLLSAVER;	break;
						default:					
							DigiDump( DIGIWARN, ( "Isdn!V2Interpreter: XN_CONNECT with invalid cip 0x%x, defaulting to TollSaver!\n", pMsg->call.cip ) );
							ConnType = ISDN_CONN_TOLLSAVER;	
							break;
					}
#endif
					pDispatchTable->OnConnect( pOwner, pMsg->call.chan_index, pMsg->call.channel, ConnType );
				}
				break;

			case XN_CONNACK:
			{
		  		PISDN_CALL pCall = pOwner;
				pCall->ConnectedID.Length = ( unsigned short )pMsg->cccc.conn_address.number_len;
				pCall->ConnectedID.MaximumLength = ISDN_NUMBER_SIZE;
				ASSERT( sizeof pCall->ConnectedIDBuffer >= sizeof pMsg->cccc.conn_address.number );
			 	RtlCopyMemory( pCall->ConnectedIDBuffer, pMsg->cccc.conn_address.number, pCall->ConnectedID.Length );
				pCall->ConnectedID.Buffer = pCall->ConnectedIDBuffer;
				DigiDump( DIGIV2, ( "Isdn!V2Interpreter: XN_CONNACK on pOwner 0x%x\n", pOwner ) );
				pDispatchTable->OnConnack( pOwner, pMsg->cccc.chan_index, pMsg->cccc.channel );
				break;
			}
			case XN_CACTIVE:
				DigiDump( DIGIV2, ( "Isdn!V2Interpreter: XN_CACTIVE on pOwner 0x%x\n", pOwner ) );
				pDispatchTable->OnCActive( pOwner );
				break;

			case XN_DISCONN:
				DigiDump( DIGIV2, ( "Isdn!V2Interpreter: XN_DISCONN on pOwner 0x%x, cause 0x%x\n", pOwner, pMsg->cccc.cause ) );
				pDispatchTable->OnDisconn( pOwner, pMsg->cccc.chan_index, pMsg->cccc.channel );
				break;

			case XN_CONNEND:
				DigiDump( DIGIV2, ( "Isdn!V2Interpreter: XN_CONNEND on pOwner 0x%x, cause 0x%x\n", pOwner, pMsg->cccc.cause ) );
				pDispatchTable->OnConnend( pOwner, pMsg->cccc.chan_index, pMsg->cccc.channel );
				break;

			case XN_STS:
				DigiDump( DIGIV2|DIGIWARN, ( "Isdn!V2Interpreter: XN_STS on pOwner 0x%x\n", pOwner ) );
				break;

			case XN_DATA:
				DigiDump( DIGIV2|DIGIWARN, ( "Isdn!V2Interpreter: XN_DATA on pOwner 0x%x, error 0x%x\n", pOwner, pMsg->data.error ) );
				break;

			case XN_INFO:
				DigiDump( DIGIV2, ( "Isdn!V2Interpreter: XN_INFO on pOwner 0x%x\n", pOwner ) );
				break;

			case XN_BAD_MSG:
				DigiDump( DIGIV2|DIGIWARN, ( "Isdn!V2Interpreter: XN_BAD_MSG on pOwner 0x%x, reason 0x%x\n", pOwner, pMsg->badm.reason ) );
				DigiDump( DIGIWARN, ( "   command 0x%x\n"
				                      "   snid    0x%x\n"
				                      "   appid   0x%x\n"
				                      "   message 0x%x\n"
				                      "   reason  0x%x\n",
				                      pMsg->badm.command, pMsg->badm.snid, pMsg->badm.appid, pMsg->badm.message, pMsg->badm.reason ) );
				break;

			default:
				DigiDump( DIGIV2|DIGIERROR, ( "Isdn!V2Interpreter: Unknown msg 0x%x on pOwner 0x%x!\n", pMsg->command, pOwner ) );
				break;
		}
		RxEngineFreeData( pData );
	}
	else
	{
		// Data Messages
		DigiDump( DIGIV2, ( "Isdn!V2Interpreter: Rx Data, pOwner 0x%x, pData 0x%x, cbData 0x%x\n", pOwner, pData, cbData ) );
		pDispatchTable->OnData( pOwner, pData, cbData );
	}
}


ISDN_CODEC IsdnV2 = 
{
	V2Connect,
	V2Connack,
	V2Disconn,
	V2Connend,
	V2Listen,
	V2Interpreter,
	sizeof (union ISDN_primitives),
	"ISDN"
};


VOID
IsdnV2Init(
	PISDN_ADAPTER pAdapter )
/*++

Description:

	Initialize the adapter dispatch table to use V2 Spider Api.

--*/
{
	pAdapter->XnDispatch = IsdnV2;
}
