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

   dxbv2.c

Abstract:

   This module encapsulates all DXB rev2 specifics, both commands and responses.

Author:

   Michael Zarns

--*/

#include "digidxb.h"

#define V2_ALIGN_HDR		TRUE
#define V2_ALIGN_CTRL	TRUE
#define V2_ALIGN_DATA	TRUE

#define V2_WRAP_HDR		TRUE
#define V2_WRAP_CTRL		TRUE
#define V2_WRAP_DATA		TRUE

#define V2_PAD_HDR		(V2_ALIGN_CTRL)
#define V2_PAD_CTRL		(V2_ALIGN_DATA)
#define V2_PAD_DATA		(V2_ALIGN_HDR)

// Credit limit.  nCredits can never exceed this value.  In dxbv2, no real limit.
#define V2_CREDIT_MAX			MAXULONG

// Fixed cost per packet.  Overhead added to each packet to prevent flooding with too 
// many short packets.  This value affects receive packets only!  Transmit FCost is set
// by the fep.
#define V2_CREDIT_FCOST			0x00

// Count of credits assumed at open.  DxbV2 assumes none and requires explicit credit
// awards before data may be sent either direction.
#define V2_CREDIT_OPEN			0

// Count of credits to be automatically sent immediately after open.  See also V2_CREDIT_OPEN.
#define V2_CREDIT_OPEN_AWARD	0x4000

/*
STATIC NTSTATUS
dxbV2Open(
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 Channel,
	IN DS_OPEN const         *pOpen )
/*++

Description:

	This routine builds a dxb Open command message and uses dxbQueueWriteCommand to 
	send it down.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which to place the request.

	pOpen
		The client supplied Open request.

Return Value:

	STATUS_SUCCESS if successful.

--*/
/*{
	DXB_MSG_OPEN Msg = { 0 };
	STRING Name;
	VOID  **ppUserData;
	USHORT cbUserData;

	RtlInitString( &Name, pOpen->DeviceName );

	if ( pOpen->pProviderData != NULL )
	{
		ppUserData  = pOpen->pProviderData;
		cbUserData = (USHORT)pOpen->cbUserData;
	}
	else
	{
		ppUserData  = NULL;
		cbUserData = 0;
	}

	Msg.type       = DXB_TYPE_OPEN;
	Msg.channel    = (UCHAR)Channel;
	Msg.fixed_cost = pOpen->FixedCost != 0 ? (UCHAR)pOpen->FixedCost : V2_CREDIT_FCOST;
	Msg.ctrl_len   = Name.MaximumLength;
	Msg.data_len   = cbUserData;

	DigiDump( DIGIV2,  ( "DXB!V2Open: pExt 0x%p, Channel 0x%x, Device %s, Minor 0x%p, FCost 0x%x\n",
	          pExt, Channel, Name.Buffer, ppUserData == NULL ? NULL : *ppUserData, Msg.fixed_cost ) );

	return ( dxbQueueWriteCommand( pExt, &Msg, sizeof Msg, 
	                               Name.Buffer, Name.MaximumLength, 
	                               ppUserData, cbUserData,
	                               V2_WRAP_HDR, V2_ALIGN_DATA ) );
}
*/
// Start old (working?) version
STATIC NTSTATUS
dxbV2Open(
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 Channel,
	IN DS_OPEN const         *pOpen )
/*++

Description:

	This routine builds a dxb Open command message and uses dxbQueueWriteCommand to 
	send it down.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which to place the request.

	pOpen
		The client supplied Open request.

Return Value:

	STATUS_SUCCESS if successful.

--*/
{
	DXB_MSG_OPEN Msg = { 0 };
	STRING Name;
	ULONG const *pUserData;
	USHORT cbUserData;

	RtlInitString( &Name, pOpen->DeviceName );

	if ( pOpen->pProviderData != NULL )
	{
		pUserData  = pOpen->pProviderData;
		cbUserData = (USHORT)pOpen->cbUserData;
	}
	else
	{
		pUserData  = NULL;
		cbUserData = 0;
	}

	Msg.type       = DXB_TYPE_OPEN;
	Msg.channel    = (UCHAR)Channel;
	Msg.fixed_cost = pOpen->FixedCost != 0 ? (UCHAR)pOpen->FixedCost : V2_CREDIT_FCOST;
	Msg.ctrl_len   = Name.MaximumLength;
	Msg.data_len   = cbUserData;

	SRAPRINT2( DIGIV2,  SRA_MED_LEVEL,
                   ( "DXB!V2Open: pExt 0x%x, Channel 0x%x, Device %s, Minor 0x%x, FCost 0x%x\n",
                     pExt, Channel, Name.Buffer, pUserData == NULL ? (ULONG)pUserData : *pUserData, Msg.fixed_cost ) );

	return ( dxbQueueWriteCommand( pExt, &Msg, sizeof Msg, 
	                               Name.Buffer, Name.MaximumLength, 
	                               (PVOID)pUserData, cbUserData,
	                               V2_WRAP_HDR, V2_ALIGN_DATA ) );
}
// End old (working?) version
STATIC NTSTATUS
dxbV2Close(
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 Channel,
	IN DS_CLOSE const        *pClose )
/*++

Description:

	This routine builds a dxb Close command message and uses dxbQueueWriteCommand to 
	send it down.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which to place the request.

	pClose
		The close request.  Not used.

Return Value:

	STATUS_SUCCESS if successful.

--*/
{
	DXB_MSG_CLOSE Msg = { 0 };
	UNREFERENCED_PARAMETER( pClose );
	Msg.type = DXB_TYPE_CLOSE;
	Msg.channel = (UCHAR)Channel;

	SRAPRINT2( DIGIV2,  SRA_MED_LEVEL,
                  ( "DXB!V2Close: pExt 0x%x, Channel 0x%x\n", pExt, Channel ) );

	return( dxbQueueWriteCommand( pExt, &Msg, sizeof Msg, NULL, 0, 
	                              NULL, 0, V2_WRAP_HDR, V2_ALIGN_DATA ) );
}


STATIC NTSTATUS
dxbV2Ioctl(
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 Channel,
	IN DS_IOCTL const        *pIoctl )
/*++

Description:

	This routine builds a dxb Ioctl command message and uses dxbQueueWriteCommand to 
	send it down.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which to place the request.

	pIoctl
		The client supplied Ioctl request.

Return Value:

	STATUS_SUCCESS if successful.

--*/
{
	DXB_MSG_IOCTL Msg = { 0 };

	ASSERT( pIoctl->Command <= MAXUSHORT );
	ASSERT( Channel <= MAXUCHAR );
	ASSERT( pIoctl->cbDataIn <= MAXUSHORT );

	Msg.type    = DXB_TYPE_IOCTL;
	Msg.command = (USHORT)pIoctl->Command;
	Msg.channel = (UCHAR)Channel;
	Msg.data_len  = (USHORT)pIoctl->cbDataIn;

	SRAPRINT2( DIGIV2,  SRA_MED_LEVEL,
                   ( "DXB!V2Ioctl: pExt 0x%x, Channel 0x%x\n", pExt, Channel ) );

	return( dxbQueueWriteCommand( pExt, &Msg, sizeof Msg, NULL, 0,
	                              pIoctl->pProviderDataIn, pIoctl->cbDataIn, 
	                              V2_WRAP_HDR, V2_ALIGN_DATA ) );
}


STATIC NTSTATUS
dxbV2PutMsg(
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 Channel,
	IN DS_PUTMSG const       *pPutMsg )
/*++

Description:

	This routine builds a dxb PutMsg command message and uses dxbQueueWriteCommand to 
	send it down.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which to place the request.

	pPutMsg
		The client supplied PutMsg request.

Return Value:

	STATUS_SUCCESS if successful.

--*/
{
	DXB_MSG_DATA  DataMsg = { 0 };
	DXB_MSG_CDATA CDataMsg = { 0 };
	PVOID pMsg;
	ULONG cbMsg;
	NTSTATUS Status;
	
	ASSERT( pPutMsg->pControl != NULL && pPutMsg->cbControl != 0 ||
	        pPutMsg->pControl == NULL && pPutMsg->cbControl == 0 )

	if ( pPutMsg->cbControl == 0 )
	{
		// M_DATA
		DataMsg.type     = DXB_TYPE_DATA;
		DataMsg.channel  = (UCHAR)Channel;
		DataMsg.data_len = (USHORT)pPutMsg->cbData;
		pMsg  = &DataMsg;
		cbMsg = sizeof DataMsg;
	}
	else
	{
		// M_PROTO and M_PCPROTO
		CDataMsg.type     = DXB_TYPE_CDATA;
		CDataMsg.channel  = (UCHAR)Channel;
		CDataMsg.priority = pPutMsg->Priority == DS_PRIORITY_HIGH ? 1 : 0;
		CDataMsg.ctrl_len = (USHORT)pPutMsg->cbControl;
		CDataMsg.data_len = (USHORT)pPutMsg->cbData;
		pMsg  = &CDataMsg;
		cbMsg = sizeof CDataMsg;
	}

	SRAPRINT2( DIGIV2,  SRA_MED_LEVEL,
                   ( "DXB!V2PutMsg: pExt 0x%x, Channel 0x%x, type %s, cbCtrl 0x%x, cbData 0x%x\n", 
                     pExt, Channel, ((DXB_MSG_GENERIC*)pMsg)->type == DXB_TYPE_CDATA ? "DXB_TYPE_CDATA" : "DXB_TYPE_DATA",
                     pPutMsg->cbControl, pPutMsg->cbData ) );

	Status = dxbQueueWriteCommand( pExt, pMsg, cbMsg,
	                               pPutMsg->pProviderControl, pPutMsg->cbControl, 
	                               pPutMsg->pProviderData, pPutMsg->cbData, 
	                               V2_WRAP_HDR, V2_ALIGN_DATA );

	return Status;
}


STATIC NTSTATUS
dxbV2Link(
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 Channel,
	IN DS_LINK const         *pLink )
/*++

Description:

	This routine builds a dxb Link command message and uses dxbQueueWriteCommand to 
	send it down.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which to place the request.

	pLink
		The client supplied Link request.

Return Value:

	STATUS_SUCCESS if successful.

--*/
{
	DXB_MSG_LINK Msg = { 0 };

	Msg.type = DXB_TYPE_LINK;
	Msg.channel = (UCHAR)Channel;
	Msg.other_channel = (USHORT)pLink->hStreamLower;

	SRAPRINT2( DIGIV2,  SRA_MED_LEVEL,
                   ( "DXB!V2Link: pExt 0x%x, Channel 0x%x, Lower 0x%x\n", 
                     pExt, Channel, Msg.other_channel ) );

	return( dxbQueueWriteCommand( pExt, &Msg, sizeof Msg, NULL, 0,
	                              NULL, 0, V2_WRAP_HDR, V2_ALIGN_DATA ) );
}


STATIC NTSTATUS
dxbV2CreditAward(
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 Channel,
	IN USHORT                nCredits )
/*++

Description:

	This routine builds a dxb credit award command message and uses 
	dxbQueueWriteCommand to send it down.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which to place the request.

	nCredits
		The number of credits to award.  Typically, the total outstanding for this stream.

Return Value:

	STATUS_SUCCESS if successful.

--*/
{
	DXB_MSG_CREDIT Msg = { 0 };

	Msg.type         = DXB_TYPE_CREDIT;
	Msg.channel      = (UCHAR)Channel;
	Msg.credit_award = nCredits;

	SRAPRINT2(DIGIV2, SRA_MED_LEVEL, 
                  ( "DXB!V2CreditAward: pExt 0x%x, Channel 0x%x, nCredits 0x%x\n", 
                    pExt, Channel, nCredits ) );
        
	return( dxbQueueWriteCommand( pExt, &Msg, sizeof Msg, NULL, 0, NULL, 0, 
	                              V2_WRAP_HDR, V2_ALIGN_DATA ) );
}

typedef struct DXB_RESPONSE
{
	USHORT ReturnValue;
	USHORT ErrorCode;
} DXB_RESPONSE;


STATIC ULONG  
dxbV2OnOpenEvent(
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 Channel,
	IN ULONG                 QOut,
	IN DXB_MSG_OPEN const    *pOpenAck )
/*++

Description:

	This routine is called to handle an OPEN_ACK event from the adapter.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which the event occurred.

	QOut
		Offset into Q at which to start reading control/data.

	pOpenAck
		The open response from the adapter

Return Value:

	New value for QOut.  Always == QOut.

--*/
{
	DXB_RESPONSE Response;
	ULONG QOffset;

	ASSERT( pOpenAck->ctrl_len == sizeof Response );
	QOffset = dxbEventQueueRead( pExt, QOut, &Response, sizeof Response, 
	                             V2_WRAP_CTRL, V2_PAD_CTRL );
	
	SRAPRINT2(DIGIV2, SRA_MED_LEVEL, 
                  ( "DXB!V2OpenEvent: pExt 0x%x, Channel 0x%x, FCost 0x%x\n", 
                    pExt, Channel, pOpenAck->fixed_cost ) );

	ASSERT( ( Response.ReturnValue == 0 ) == ( Response.ErrorCode == 0 ) );
	dxbStreamOnOpenComplete( pExt, Channel, Response.ReturnValue != 0 ? Response.ErrorCode : 0, pOpenAck->fixed_cost );
	return QOffset;
}


STATIC ULONG
dxbV2OnCloseEvent(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 Channel,
	IN ULONG                 QOut,
	IN DXB_MSG_CLOSE const   *pCloseAck )
/*++

Description:

	This routine is called to handle a CLOSE_ACK event from the adapter.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which the event occurred.

	QOut
		Offset into Q at which to start reading control/data.

	pCloseAck
		The response from the adapter

Return Value:

	None

--*/
{
	ASSERT( pCloseAck );

	SRAPRINT2(DIGIV2, SRA_MED_LEVEL, 
                  ( "DXB!V2CloseEvent: pExt 0x%x, Channel 0x%x\n", pExt, Channel ) );

	dxbStreamOnCloseComplete( pExt, Channel );
	return QOut;
}


STATIC ULONG
dxbV2OnDataEvent(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 Channel,
	IN ULONG                 QOut,
	IN DXB_MSG_DATA const    *pMsg )
/*++

Description:

	This routine is called to handle DATA messages from the adapter.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which the event occurred.

	QOut
		Offset into Q at which to start reading control/data.

	pMsg
		The header of the message from the adapter.

Return Value:

	QOffset.  New value for QOut.

--*/
{
	ASSERT( pMsg != NULL );

	SRAPRINT2(DIGIV2, SRA_MED_LEVEL, 
                  ( "DXB!V2DataEvent: pExt 0x%x, Channel 0x%x, cbData 0x%x\n", 
                    pExt, Channel, pMsg->data_len ) );
	return dxbStreamOnDataEvent( pExt, Channel, QOut, 0, pMsg->data_len, DS_PRIORITY_LOW );
}


STATIC ULONG
dxbV2OnCDataEvent(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 Channel,
	IN ULONG                 QOut,
	IN DXB_MSG_CDATA const   *pMsg )
/*++

Description:

	This routine is called to handle CONTROL_DATA messages from the adapter.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which the event occurred.

	QOut
		Offset into Q at which to start reading control/data.

	pMsg
		The header of the message from the adapter.

Return Value:

	QOffset.  New value for QOut.

--*/
{
	ASSERT( pMsg != NULL );

	SRAPRINT2(DIGIV2, SRA_MED_LEVEL, 
                  ( "DXB!V2CDataEvent: pExt 0x%x, Channel 0x%x, cbCtrl 0x%x, cbData 0x%x\n", 
                    pExt, Channel, pMsg->ctrl_len, pMsg->data_len ) );

	ASSERT( pMsg->ctrl_len != 0 || pMsg->data_len != 0 );
	return dxbStreamOnDataEvent( pExt, Channel, QOut, pMsg->ctrl_len, pMsg->data_len, 
	                             pMsg->priority == 0 ? DS_PRIORITY_LOW : DS_PRIORITY_HIGH );
}


STATIC ULONG
dxbV2OnIoctlEvent(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 Channel,
	IN ULONG                 QOut,
	IN DXB_MSG_IOCTL const   *pMsg )
/*++

Description:

	This routine is called to handle Ioctl response events from the adapter.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which the event occurred.

	QOut
		Offset into Q at which to start reading ioctl response data.

	pMsg
		The header of the message from the adapter.

Return Value:

	QOffset.  New value for QOut.

--*/
{
	DXB_RESPONSE Response;
	ULONG QOffset;
	
	ASSERT( pMsg );
	ASSERT( pMsg->ctrl_len == sizeof Response );

	QOffset = dxbEventQueueRead( pExt, QOut, &Response, pMsg->ctrl_len, V2_WRAP_CTRL, V2_PAD_CTRL );

	SRAPRINT2(DIGIV2, SRA_MED_LEVEL, 
                  ( "DXB!V2IoctlEvent: pExt 0x%x, Channel 0x%x, cbCtrl 0x%x, cbData 0x%x\n", 
                    pExt, Channel, pMsg->ctrl_len, pMsg->data_len ) );

	ASSERT( Response.ErrorCode == 0 || Response.ReturnValue != 0 );

	return dxbStreamOnIoctlComplete( pExt, Channel, QOffset, Response.ReturnValue, 
	                                 Response.ErrorCode, pMsg->data_len );
}


STATIC ULONG
dxbV2OnCreditEvent(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 Channel,
	IN ULONG                 QOut,
	IN DXB_MSG_CREDIT const    *pMsg )
/*++

Description:

	This routine is called to handle Credit or "position report" events from the 
	adapter.  These are sent to give back credits we previously used while sending
	data via PutMsg requests.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which the event occurred.

	QOut
		Offset into Q at which to start reading ioctl response data.

	pMsg
		The header of the message from the adapter.

Return Value:

	None.

--*/
{
	ASSERT( pMsg );

	SRAPRINT2(DIGIV2, SRA_MED_LEVEL, 
                  ( "DXB!V2CreditEvent: pExt 0x%x, Channel 0x%x, nCredits 0x%x\n", 
                    pExt, Channel, pMsg->credit_award ) );

	dxbStreamOnCreditEvent( pExt, Channel, pMsg->credit_award );
	return QOut;
}


STATIC ULONG
dxbV2OnLinkEvent( 
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 Channel,
	IN ULONG                 QOut,
	IN DXB_MSG_LINK const    *pMsg )
/*++

Description:

	This routine is called to handle the OOB Ioctl ack END_LINK.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which the event occurred.

	QOut
		Offset into Q at which to start reading ioctl response data.

	pMsg
		The header of the message from the adapter.

Return Value:

	Normalized QOffset after reading End_Link data.

--*/
{
	DXB_RESPONSE Response;
	ULONG QOffset;
	QOffset = dxbEventQueueRead( pExt, QOut, &Response, pMsg->ctrl_len, V2_WRAP_CTRL, V2_PAD_CTRL );

	SRAPRINT2(DIGIV2, SRA_MED_LEVEL, 
                  ( "DXB!V2LinkEvent: pExt 0x%x, Channel 0x%x, Return 0x%x, Error 0x%x\n", 
                    pExt, Channel, Response.ReturnValue, Response.ErrorCode ) );

	dxbStreamOnLinkComplete( pExt, Channel, Response.ReturnValue, Response.ErrorCode );
	return QOffset;
}


STATIC ULONG
dxbV2OnFlushEvent( 
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 Channel,
	IN ULONG                 QOut,
	IN DXB_MSG_FLUSH const   *pMsg )
/*++

Description:

	This routine is called to handle the OOB Ioctl ack for Flush.

Parameters:

	pExt
		The device extension defines the adapter.

	Channel
		The dxb channel (or stream) on which the event occurred.

	QOut
		Offset into Q at which to start reading ioctl response data.

	pMsg
		The header of the message from the adapter.

Return Value:

	Normalized QOffset after reading data.

--*/
{
	// Ignore response
	return dxbEventQueueRead( pExt, QOut, NULL, sizeof (DXB_RESPONSE), V2_WRAP_DATA, V2_PAD_DATA );
}


STATIC INLINE ULONG 
dxbV2ReadHeader(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 QOut,
	OUT DXB_MSG_GENERIC      *pHeader )
/*++

Description:

	This routine is used to read a single message header from the dxb adapter event 
	queue.  Message headers are always 4 or 8 bytes in length.  Process: Read 4 bytes, 
	then if needed, read another 4 bytes.

Parameters:

	pExt
		Device extension defining the adapter from which to read.

	QOut
		Offset into dxb event queue at which to start reading.
	
	pHeader
		Pointer to dxb message header structure which is filled in before returning.

Return Value:

	New value of QOut

--*/
{
	ULONG QOffset;
	ASSERT( QOut == dxbAlign32( QOut ) );
	QOffset = dxbEventQueueRead( pExt, QOut, pHeader, 4, FALSE, FALSE );

	switch ( pHeader->type )
	{
		case DXB_TYPE_OPEN:
		case DXB_TYPE_CDATA:
		case DXB_TYPE_LINK:
		case DXB_TYPE_IOCTL:
			QOffset = dxbEventQueueRead( pExt, QOffset, (PUCHAR)pHeader + 4, 4, V2_WRAP_HDR, V2_PAD_HDR );
			break;

		case DXB_TYPE_CLOSE:
		case DXB_TYPE_DATA:
		case DXB_TYPE_START:
		case DXB_TYPE_CREDIT:
			break;

		default:
			SRAPRINT( DIGIERROR|DIGIBREAK,  ( "DXB!dxbV2ReadHeader: "
			          "Invalid message found in event Q, type = 0x%x!\n", 
			          pHeader->type) );
			break;
	}
	return QOffset;
}


STATIC ULONG 
dxbV2ReadCData( 
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 QOut, 
	IN PVOID                 pCtrl,
	IN ULONG                 cbCtrl,
	IN PVOID                 pData,
	IN ULONG                 cbData )
{
	ULONG QOffset = QOut;

	if ( cbCtrl )
		QOffset = dxbEventQueueRead( pExt, QOffset, pCtrl, cbCtrl, V2_WRAP_CTRL, V2_PAD_CTRL );

	if ( cbData )
		QOffset = dxbEventQueueRead( pExt, QOffset, pData, cbData, V2_WRAP_DATA, V2_PAD_DATA );

	return QOffset;
}


STATIC ULONG
dxbV2EventProcessor(
	IN PDXB_DEVICE_EXTENSION pExt, 
	IN ULONG                 QStart )
/*++

Description:

	Grab a single message from the DXB event queue and process it.

Parameters:

	pExt
		Device extension for the adapter being serviced

	QOut
		QOut offset into the dxb event queue at which to start processing.

Return Value:

	New normalized QOut value.

--*/
{
	DXB_MSG_GENERIC Msg;
	ULONG QOut = QStart;

	QOut = dxbV2ReadHeader( pExt, QStart, &Msg );
	ASSERT( Msg.channel <= 255 );

	switch ( Msg.type )
	{
		case DXB_TYPE_OPEN:
			QOut = dxbV2OnOpenEvent( pExt, Msg.channel, QOut, (PVOID)&Msg );
			break;

		case DXB_TYPE_CLOSE:
			QOut = dxbV2OnCloseEvent( pExt, Msg.channel, QOut, (PVOID)&Msg );
			break;

		case DXB_TYPE_DATA:
			QOut = dxbV2OnDataEvent( pExt, Msg.channel, QOut, (PVOID)&Msg );
			break;

		case DXB_TYPE_CDATA:
			QOut = dxbV2OnCDataEvent( pExt, Msg.channel, QOut, (PVOID)&Msg );
			break;

		case DXB_TYPE_IOCTL:
			QOut = dxbV2OnIoctlEvent( pExt, Msg.channel, QOut, (PVOID)&Msg );
			break;

		case DXB_TYPE_CREDIT:
			QOut = dxbV2OnCreditEvent( pExt, Msg.channel, QOut, (PVOID)&Msg );
			break;

		case DXB_TYPE_LINK:
			QOut = dxbV2OnLinkEvent( pExt, Msg.channel, QOut, (PVOID)&Msg );
			break;

		case DXB_TYPE_FLUSH:
			QOut = dxbV2OnFlushEvent( pExt, Msg.channel, QOut, (PVOID)&Msg );
			break;

		case DXB_TYPE_START:
			QOut = 0;
			break;

		default:
			SRAPRINT( DIGIBREAK|DIGIERROR, 
			          ( "DXB!V2EventProcessor: unknown message in event Queue 0x%x!\n",
			          Msg.type) );
			break;
	}

	return QOut;
}


STATIC ULONG
dxbV2GetCmdQOut(
	IN PDXB_DEVICE_EXTENSION pExt )
/*++

Description:

	Returns the current Dxb command queue QOut pointer.

Parameters:

	pExt
		Defines the adapter

Return Value:

	QOut

--*/
{
	return *pExt->DxbCmdQ.Descriptor.pQOut;
}


STATIC ULONG
dxbV2GetCmdQIn(
	IN PDXB_DEVICE_EXTENSION pExt )
/*++

Description:

	Returns the current Dxb command queue QIn pointer.

Parameters:

	pExt
		Defines the adapter

Return Value:

	QIn

--*/
{
	return *pExt->DxbCmdQ.Descriptor.pQIn;
}


STATIC VOID
dxbV2SetCmdQIn(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 QIn )
/*++

Description:

	Set the current Dxb command queue QIn pointer.

Parameters:

	pExt
		Defines the adapter

Return Value:

	None

--*/
{
	ASSERT( QIn == dxbAlign32( QIn ) );
	ASSERT( QIn < pExt->DxbCmdQ.cbTotal );
	*pExt->DxbCmdQ.Descriptor.pQIn = QIn;
}


STATIC ULONG
dxbV2GetEventQIn(
	IN PDXB_DEVICE_EXTENSION pExt )
/*++

Description:

	Returns the current Dxb event queue QIn pointer.

Parameters:

	pExt
		Defines the adapter

Return Value:

	QIn

--*/
{
	return *pExt->DxbEventQ.Descriptor.pQIn;
}


STATIC ULONG
dxbV2GetEventQOut(
	IN PDXB_DEVICE_EXTENSION pExt )
/*++

Description:

	Returns the current Dxb event queue QOut pointer.

Parameters:

	pExt
		Defines the adapter

Return Value:

	QOut

--*/
{
	return *pExt->DxbEventQ.Descriptor.pQOut;
}


STATIC VOID
dxbV2SetEventQOut(
	IN PDXB_DEVICE_EXTENSION pExt,
	IN ULONG                 QOut )
/*++

Description:

	Set the current Dxb event queue QOut pointer.

Parameters:

	pExt
		Defines the adapter

Return Value:

	None

--*/
{
	ASSERT( QOut == dxbAlign32( QOut ) );
	ASSERT( QOut < pExt->DxbEventQ.cbTotal );
	*pExt->DxbEventQ.Descriptor.pQOut = QOut;
}


DXB_CODEC DxbV2 = 
{
	dxbV2Open,
	dxbV2Close,
	dxbV2PutMsg,
	dxbV2Ioctl,
	dxbV2Link,
	dxbV2CreditAward,
	dxbV2EventProcessor,
	dxbV2ReadCData,
	dxbV2GetCmdQIn,
	dxbV2GetCmdQOut,
	dxbV2SetCmdQIn,
	dxbV2GetEventQIn,
	dxbV2GetEventQOut,
	dxbV2SetEventQOut
};


VOID 
dxbV2Init( 
	PDXB_DEVICE_EXTENSION pExt )
{
	pExt->Message = DxbV2;
	dxbCreditInit( &pExt->CreditDefault, 
	               V2_CREDIT_OPEN, V2_CREDIT_OPEN_AWARD, V2_CREDIT_MAX, V2_CREDIT_FCOST );
}
