/*++
 * 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/hwutils.c 7     10/22/97 11:56a Darinh $
 *
 * Revision History:
 * $Log: /Components/Windows/NT/Sync/Build/Mp570/hwutils.c $
 * 
 * 7     10/22/97 11:56a Darinh
 * Changes to make multiple board installations work better.
 * 
 * 6     9/08/97 3:44p Darinh
 * A variety of changes, including Data General fixes are included.
 * 
 * 5     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.
 * 
 * 4     6/19/97 4:51p Darinh
 * Fixed an error that occurs after installing NT DDK 4.0.
 * 
 * 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 "io.h"
#include "hwutils.h"
#include "hw570.h"
#include "debug.h"
#include "digilog.h"


VOID
fnInitCommonScaRegs (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will setup initial values that aren't line/port dependent.
	The following are the settings (SCA chip registers):
		- LPR   - Low Power Register
		- PABR0 - Physical Addr Boundary Register 0
		- PABR1 - Physical Addr Boundary Register 1
		- WCRL  - Wait Control Register Region 0
		- WCRM  - Wait Control Register Region 1
		- WCRH  - Wait Control Register Region 2

Parameters:

	pDeviceExt
		Address of the Device Extension

Return Value:

	None.

NOTE:	All 4 ports have addresses to common registers.  Only 1 port should
		initialize these registers.
--*/
{
	DigiDump (DIGIFLOW, ("Entering fnInitCommonScaRegs()\n"));

	// Drive SCA out of "halt mode"
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComLpr, 0);

	// Include all possible card memory in first region
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComPabr0, 0x00);

	// This is a don't care
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComPabr1, 0x00);

	// No Wait states in low region
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComWcrl, 0);

	// No Wait states in middle region
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComWcrm, 0);

	// No Wait states in high region
	WRT_REG_UCHAR (&pDeviceExt->pSca->ComWcrh, 0);

	DigiDump (DIGIINIT,
		("Init Common Registers\n"
		"Lpr   = %02x\n"
		"Pabr0 = %02x\n"
		"Pabr1 = %02x\n"
		"Wcrl  = %02x\n"
		"Wcrm  = %02x\n"
		"Wcrh	 = %02x\n",
		READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pSca->ComLpr),
		READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pSca->ComPabr0),
		READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pSca->ComPabr1),
		READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pSca->ComWcrl),
		READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pSca->ComWcrm),
		READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pSca->ComWcrh)));


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


VOID
fnSetupPortRelatedRegisters (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will setup initial values that is line/port dependent
	The following are the settings :
	. Digi Card registers
		- Memory and SCA chip enable
		- DTR signal enable
		- Transmit Clock Input/Output
		- SCA chips reset disable
		- DCD signal mask
		- SCA Interrupt Pending mask
		- Transmit Clock DTR Control Register
		- Interrupt Acknowledge Register
	. SCA chip registers
		- MSCI registers pointer
		- Timer registers pointer
		- DMAC registers pointer (Rx uses Chan 0 or 2, and Tx uses Chan 1 or 3)
		- Receive DMA Interrupts enable
		- Transmit DMA interrupts enable
		- Receive MSCI interrupts enable
		- Transmit MSCI interrupts enable
		- Timer interrupts enable
		- Receive Interrupt vector
		- Transmit Interrupt vector
		- Receive DMA Error Interrupt vector
		- Receive DMA Good Interrupt vector
		- Transmit DMA Error Interrupt vector
		- Transmit DMA Good Interrupt vector

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	PUCHAR		VirtualIO = pDeviceExt->pControllerExt->VirtualIO;


	DigiDump (DIGIFLOW, ("Entering fnSetupPortRelatedRegisters()  Port: %d\n",
		pDeviceExt->PortNumber));

	switch (pDeviceExt->PortNumber)
	{
	case FIRST_PORT:
		pDeviceExt->DigiMemScaE = MSCA_MEM_SCA0;
		pDeviceExt->DigiDtrTxE = TCD01_DTRTX0_ENABLE;
		if (PT_X21 == pDeviceExt->PortType)
			pDeviceExt->DigiTxClkInput = 0;
		else
			pDeviceExt->DigiTxClkInput = TCD01_TXCS0I;

		pDeviceExt->DigiRegTxClkDtrCtrl = TCD01_RES;
		pDeviceExt->DigiDcdMask = DIS_DCD0E;
		pDeviceExt->DigiIntPendMask = DIS_INT0P;
		if (PCIBus == pDeviceExt->pControllerExt->BusType)
		{
			pDeviceExt->DigiTxClkDtrCtrl = VirtualIO + REG570PCI_TXCLK_DTR01;
			pDeviceExt->DigiIntAckReg = VirtualIO + REG570PCI_INT_ACK01;
		}
		else
		{
			pDeviceExt->DigiTxClkDtrCtrl = VirtualIO + REG570_TXCLK_DTR01;
			pDeviceExt->DigiIntAckReg = VirtualIO + REG570_INT_ACK01;
		}

		pDeviceExt->pScaMsci = &pDeviceExt->pSca->MsciRegs[0];
		pDeviceExt->pScaTimer = &pDeviceExt->pSca->TimerRegs[0];
		pDeviceExt->pScaRxDmac = &pDeviceExt->pSca->DmacRegs[0];
		pDeviceExt->pScaTxDmac = &pDeviceExt->pSca->DmacRegs[1];

		pDeviceExt->ScaIntCtrlRxDmaIntE = INT_DMIAB0_ENABLE;
		pDeviceExt->ScaIntCtrlRxDmia0E = INT_DMIA0_ENABLE;
		pDeviceExt->ScaIntCtrlRxDmib0E = INT_DMIB0_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmaIntE = INT_DMIAB1_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmia1E = INT_DMIA1_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmib1E = INT_DMIB1_ENABLE;
		pDeviceExt->ScaIntCtrlRxIntE = INT_RXINT0_ENABLE;
		pDeviceExt->ScaIntCtrlTxIntE = INT_TXINT0_ENABLE;
		pDeviceExt->ScaIntCtrlTimerE = INT_T0IRQ_ENABLE;
		pDeviceExt->IntMsciDmacMask = INT_MSCI_CHANNEL0;
		break;

	case SECOND_PORT:
		pDeviceExt->DigiMemScaE = MSCA_MEM_SCA0;
		pDeviceExt->DigiDtrTxE = TCD01_DTRTX1_ENABLE;
		if (PT_X21 == pDeviceExt->PortType)
			pDeviceExt->DigiTxClkInput = 0;
		else
			pDeviceExt->DigiTxClkInput = TCD01_TXCS1I;
		pDeviceExt->DigiRegTxClkDtrCtrl = TCD01_RES;
		pDeviceExt->DigiDcdMask = DIS_DCD1E;
		pDeviceExt->DigiIntPendMask = DIS_INT0P;
		if (PCIBus == pDeviceExt->pControllerExt->BusType)
		{
			pDeviceExt->DigiTxClkDtrCtrl = VirtualIO + REG570PCI_TXCLK_DTR01;
			pDeviceExt->DigiIntAckReg = VirtualIO + REG570PCI_INT_ACK01;
		}
		else
		{
			pDeviceExt->DigiTxClkDtrCtrl = VirtualIO + REG570_TXCLK_DTR01;
			pDeviceExt->DigiIntAckReg = VirtualIO + REG570_INT_ACK01;
		}

		pDeviceExt->pScaMsci = &pDeviceExt->pSca->MsciRegs[1];
		pDeviceExt->pScaTimer = &pDeviceExt->pSca->TimerRegs[1];
		pDeviceExt->pScaRxDmac = &pDeviceExt->pSca->DmacRegs[2];
		pDeviceExt->pScaTxDmac = &pDeviceExt->pSca->DmacRegs[3];

		pDeviceExt->ScaIntCtrlRxDmaIntE = INT_DMIAB2_ENABLE;
		pDeviceExt->ScaIntCtrlRxDmia0E = INT_DMIA2_ENABLE;
		pDeviceExt->ScaIntCtrlRxDmib0E = INT_DMIB2_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmaIntE = INT_DMIAB3_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmia1E = INT_DMIA3_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmib1E = INT_DMIB3_ENABLE;
		pDeviceExt->ScaIntCtrlRxIntE = INT_RXINT1_ENABLE;
		pDeviceExt->ScaIntCtrlTxIntE = INT_TXINT1_ENABLE;
		pDeviceExt->ScaIntCtrlTimerE = INT_T1IRQ_ENABLE;
		pDeviceExt->IntMsciDmacMask = INT_MSCI_CHANNEL1;

		break;

	case THIRD_PORT:
		pDeviceExt->DigiMemScaE = MSCA_MEM_SCA1;
		pDeviceExt->DigiDtrTxE = TCD23_DTRTX2_ENABLE;
		if (PT_X21 == pDeviceExt->PortType)
			pDeviceExt->DigiTxClkInput = 0;
		else
			pDeviceExt->DigiTxClkInput = TCD23_TXCS2I;
		pDeviceExt->DigiRegTxClkDtrCtrl = 0;
		pDeviceExt->DigiDcdMask = DIS_DCD2E;
		pDeviceExt->DigiIntPendMask = DIS_INT1P;
		if (PCIBus == pDeviceExt->pControllerExt->BusType)
		{
			pDeviceExt->DigiTxClkDtrCtrl = VirtualIO + REG570PCI_TXCLK_DTR23;
			pDeviceExt->DigiIntAckReg = VirtualIO + REG570PCI_INT_ACK23;
		}
		else
		{
			pDeviceExt->DigiTxClkDtrCtrl = VirtualIO + REG570_TXCLK_DTR23;
			pDeviceExt->DigiIntAckReg = VirtualIO + REG570_INT_ACK23;
		}

		pDeviceExt->pScaMsci = &pDeviceExt->pSca->MsciRegs[0];
		pDeviceExt->pScaTimer = &pDeviceExt->pSca->TimerRegs[0];
		pDeviceExt->pScaRxDmac = &pDeviceExt->pSca->DmacRegs[0];
		pDeviceExt->pScaTxDmac = &pDeviceExt->pSca->DmacRegs[1];

		pDeviceExt->ScaIntCtrlRxDmaIntE = INT_DMIAB0_ENABLE;
		pDeviceExt->ScaIntCtrlRxDmia0E = INT_DMIA0_ENABLE;
		pDeviceExt->ScaIntCtrlRxDmib0E = INT_DMIB0_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmaIntE = INT_DMIAB1_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmia1E = INT_DMIA1_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmib1E = INT_DMIB1_ENABLE;
		pDeviceExt->ScaIntCtrlRxIntE = INT_RXINT0_ENABLE;
		pDeviceExt->ScaIntCtrlTxIntE = INT_TXINT0_ENABLE;
		pDeviceExt->ScaIntCtrlTimerE = INT_T0IRQ_ENABLE;
		pDeviceExt->IntMsciDmacMask = INT_MSCI_CHANNEL0;

		break;

	case FOURTH_PORT:
		pDeviceExt->DigiMemScaE = MSCA_MEM_SCA1;
		pDeviceExt->DigiDtrTxE = TCD23_DTRTX3_ENABLE;
		if (PT_X21 == pDeviceExt->PortType)
			pDeviceExt->DigiTxClkInput = 0;
		else
			pDeviceExt->DigiTxClkInput = TCD23_TXCS3I;
		pDeviceExt->DigiRegTxClkDtrCtrl = 0;
		pDeviceExt->DigiDcdMask = DIS_DCD3E;
		pDeviceExt->DigiIntPendMask = DIS_INT1P;
		if (PCIBus == pDeviceExt->pControllerExt->BusType)
		{
			pDeviceExt->DigiTxClkDtrCtrl = VirtualIO + REG570PCI_TXCLK_DTR23;
			pDeviceExt->DigiIntAckReg = VirtualIO + REG570PCI_INT_ACK23;
		}
		else
		{
			pDeviceExt->DigiTxClkDtrCtrl = VirtualIO + REG570_TXCLK_DTR23;
			pDeviceExt->DigiIntAckReg = VirtualIO + REG570_INT_ACK23;
		}

		pDeviceExt->pScaMsci = &pDeviceExt->pSca->MsciRegs[1];
		pDeviceExt->pScaTimer = &pDeviceExt->pSca->TimerRegs[1];
		pDeviceExt->pScaRxDmac = &pDeviceExt->pSca->DmacRegs[2];
		pDeviceExt->pScaTxDmac = &pDeviceExt->pSca->DmacRegs[3];

		pDeviceExt->ScaIntCtrlRxDmaIntE = INT_DMIAB2_ENABLE;
		pDeviceExt->ScaIntCtrlRxDmia0E = INT_DMIA2_ENABLE;
		pDeviceExt->ScaIntCtrlRxDmib0E = INT_DMIB2_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmaIntE = INT_DMIAB3_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmia1E = INT_DMIA3_ENABLE;
		pDeviceExt->ScaIntCtrlTxDmib1E = INT_DMIB3_ENABLE;
		pDeviceExt->ScaIntCtrlRxIntE = INT_RXINT1_ENABLE;
		pDeviceExt->ScaIntCtrlTxIntE = INT_TXINT1_ENABLE;
		pDeviceExt->ScaIntCtrlTimerE = INT_T1IRQ_ENABLE;
		pDeviceExt->IntMsciDmacMask = INT_MSCI_CHANNEL1;

		break;
	}

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


VOID
fnSetupAdapter (
	IN PCONTROLLER_EXT pControllerExt)
/*++

Description:

	This function will setup the adapter using the configured settings
	from the registry for memory address and IRQ.  It will also enable
	the adapter.

Parameters:

	pControllerExt
		Address of the Controller extension.

Return Value:

	None.

--*/
{
	UCHAR	RegisterValue = 0;
	UCHAR	Cma1415 = 0;
	UCHAR	AdapterIrqCode[] = {0x00,0x00,0x00,0x01,0x00,0x02,0x00,0x03,	 
								0x00,0x00,0x04,0x05,0x06,0x00,0x00,0x07};


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

	DigiDump (DIGIINIT, ("Using IRQ %d,  Memory Address: 0x%x\n",
		pControllerExt->PhysInterruptNumber.LowPart,
		pControllerExt->PhysWindowAddress.LowPart));

	// Setup the IRQ Level.
	RegisterValue = AdapterIrqCode[pControllerExt->PhysInterruptNumber.LowPart];
	RegisterValue <<= 1;

	// Setup the Memory Windows address.
	Cma1415 = (UCHAR) ((pControllerExt->PhysWindowAddress.LowPart >> 14) & 3);
	RegisterValue |= (Cma1415 << 4);

	// Enable the card
	pControllerExt->ioInterruptSelect = RegisterValue | IS_CEN;

	//  Save the desired card memory address (just have 0xD remaining)
	pControllerExt->ioMemorySelect =
		(UCHAR) (pControllerExt->PhysWindowAddress.LowPart >> 16);

	DigiDump (DIGIINIT, ("Writing 0x%x to the Memory Address Register\n",
		pControllerExt->ioMemorySelect));

	// Setup the Memory Select Register for window address
	(*pControllerExt->pIO_OUT) (pControllerExt->VirtualIO + REG570_MEM_SEL,
		pControllerExt->ioMemorySelect);

	DigiDump (DIGIINIT, ("Writing 0x%x to the Interrupt Select Register\n",
		pControllerExt->ioInterruptSelect));

	// Setup the Window Address, Interrupt level, and Enable the card
	(*pControllerExt->pIO_OUT) (pControllerExt->VirtualIO + REG570_INT_SEL,
		pControllerExt->ioInterruptSelect);

//	pControllerExt->AdapterFlag |= AF_ENABLE;

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


VOID
fnSetupTimerValues (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will setup two timer values. One of them is used
	to enable the Transmit Idle Interrupt and the other is used
	for dropping the RTS after the closing flag has been sent. This
	function is called for each Device Object during the
	initialization.

Parameters:

	pDeviceExt
		Address of the Device extension

Return Value:

	None.

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

	switch (pDeviceExt->Config.BaudRate)
	{
	case LS_2400BPS:
	case LS_4800BPS:
		pDeviceExt->TxIdleTimer = 20;
		pDeviceExt->DropRtsTimer = 140;
		break;

	case LS_9600BPS:
	case LS_19200BPS:
	case LS_38400BPS:
	case LS_56000BPS:
	case LS_64000BPS:
	default:
		pDeviceExt->TxIdleTimer = 20;
		pDeviceExt->DropRtsTimer = 30;
		break;
	}

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


NTSTATUS
fnZeroCardMemory (
	IN PCONTROLLER_EXT	pControllerExt)
/*++

Description:

	This function is called at init time to zero out device memory.

Parameters:

	pControllerExt
		Address of the Controller Extension

Return Value:

	None

--*/
{
	PULONG		pMemWindow;
	UCHAR		i;
	LONG		j;
	ULONG		tmp;

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

	DigiDump (DIGIINIT,
		("Clearing (%i) Adapter Memory Pages with WindowSize (0x%x)\n",
		pControllerExt->NumberOfWindows, pControllerExt->WindowSize));

//	fnPrint570IoRegisters (pControllerExt);


	for (i = 0; i < pControllerExt->NumberOfWindows; i++)
	{

		EnableControllerMemory (pControllerExt, i);

		pMemWindow = (PULONG) pControllerExt->VirtualWindow;

		// Zero out memory
		for (j = 0; j < pControllerExt->WindowSize/4; j++, pMemWindow++)
		{

			WRT_REG_ULONG (pMemWindow, 0);

			tmp = READ_REGISTER_ULONG (pMemWindow);

			if (tmp != 0)
			{
				DigiDump (DIGIERRORS,
					("*** Memory Error: Wrote 0x%08x, Read 0x%08x from 0x%08x\n",
					0, tmp, pMemWindow));

				DisableControllerMemory (pControllerExt);

				return (STATUS_UNSUCCESSFUL);
			}
		}
	}

	DisableControllerMemory (pControllerExt);

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

	return (STATUS_SUCCESS);
}


VOID
fnAllocateDmaResources (
	IN PDEVICE_EXT		pDeviceExt)
/*++

Description:

	This function will setup the Rx and Tx DMA descriptor chain and buffer
	addresses based on the amount of memory on the adapter, and the number
	of lines.  It will be called once per line.

Parameters:

	pDeviceExt
		Address of the Device Extension

Return Value:

	None.

--*/
{
	PCONTROLLER_EXT	pControllerExt = pDeviceExt->pControllerExt;
	ULONG			WorkingMemSize, TotalMemSize;
	USHORT			BuffersPerPort;
	LONG			DmaChainArraySize, SdlcBufferArraySize;


	DigiDump (DIGIFLOW, ("Entering fnAllocateDmaResources()  port: %d\n",
		pDeviceExt->PortNumber));

	TotalMemSize = pControllerExt->NumberOfWindows * pControllerExt->WindowSize;

	// Remove SCA Registers from 1st window
	WorkingMemSize = TotalMemSize - 256;

	// Always keep an even number of buffers. It makes bookkeeping easier
	BuffersPerPort = (USHORT) (WorkingMemSize / (sizeof (SDLC_BUFFER) +
		sizeof (DMA_CHAIN)) / (2 * pControllerExt->AdapterLines)) & ~1;

	DmaChainArraySize = 2 * BuffersPerPort * sizeof (DMA_CHAIN);
	SdlcBufferArraySize = 2 * BuffersPerPort * sizeof (SDLC_BUFFER);

	DigiDump (DIGIINIT,
		("DMA Chain Array Size: 0x%x  Sdlc Array Size: 0x%x  (of 0x%x)\n",
		DmaChainArraySize, SdlcBufferArraySize,
		pControllerExt->NumberOfWindows * pControllerExt->WindowSize));

	// Point to the beginning of the DMA chains array (past SCA registers)
	pDeviceExt->pRxRealDmaChainsArray = (PDMA_CHAIN) (0x100 +
		(DmaChainArraySize * pDeviceExt->PortNumber));

	// Point to the beginning of the SDLC buffer array (past the DMA chains)
	pDeviceExt->pRxRealSdlcBuffersArray = (PSDLC_BUFFER) (TotalMemSize -
		((pDeviceExt->pControllerExt->AdapterLines - pDeviceExt->PortNumber) *
		SdlcBufferArraySize));

	// Point to the middle of the DMA chains array for Tx chains
	pDeviceExt->pTxRealDmaChainsArray =
		&(pDeviceExt->pRxRealDmaChainsArray[BuffersPerPort]);

	// Point to the middle of the Sdlc buffer array for Tx buffers
	pDeviceExt->pTxRealSdlcBuffersArray =
		&(pDeviceExt->pRxRealSdlcBuffersArray[BuffersPerPort]);

	DigiDump (DIGIINIT, ("Rx - DMA: 0x%04x  Sdlc: 0x%04x\n"
		"Tx - DMA: 0x%04x  Sdlc: 0x%04x\n",
		pDeviceExt->pRxRealDmaChainsArray, pDeviceExt->pRxRealSdlcBuffersArray,
		pDeviceExt->pTxRealDmaChainsArray, pDeviceExt->pTxRealSdlcBuffersArray));

	pDeviceExt->NumberOfDmaChains = BuffersPerPort;
	pDeviceExt->IR.TransmitBufferSpace = (BuffersPerPort - 1) *
		DEFAULT_FRAME_SIZE;

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


VOID
fnSetupDmaChain (
	IN PDEVICE_EXT		pDeviceExt)
/*++

Description:

	This function will setup the Rx and Tx DMA descriptor chains based on
	the amount of memory on the adapter and the number of lines.  This 
	function will be called once for each Adapter.

Parameters:

	pDeviceExt
		Address of the Device Extension

Return Value:

	None.

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

	// Setup the Addresses of the DMA Resources
	fnAllocateDmaResources (pDeviceExt);

	// Setup RX DMA Descriptor Chains and Buffers
	fnSetupDmaDspChains (pDeviceExt, DMA_RX_DSP_CHAINS);
	pDeviceExt->pRxDmaDspCpb =
		(UCHAR) ((ULONG_PTR)pDeviceExt->pRxRealDmaChainsArray >> 16);
	fnInitializeRxDmaChains (pDeviceExt);

	// Setup TX DMA Descriptor Chains and Buffers
	fnSetupDmaDspChains (pDeviceExt, DMA_TX_DSP_CHAINS);
	pDeviceExt->pTxDmaDspCpb =
		(UCHAR) ((ULONG_PTR)pDeviceExt->pTxRealDmaChainsArray >> 16);
	fnInitializeTxDmaChains (pDeviceExt);

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


VOID
fnSetupDmaDspChains (
	IN PDEVICE_EXT	pDeviceExt,
	IN int			ChainType)
/*++

Description:

	This routine does the circular DMA chain setup.

Parameters:

	pDeviceExt
		Address of the Device Extension

Return Value:

	None.

--*/
{
	PDMA_CHAIN		pStartingDspChains;
	PSDLC_BUFFER	pStartingSdlcBuffers;
	DMA_CHAIN		TmpDmaDsp, TmpDmaDsp1;
	ULONG			pSdlcBuffer;
	int				i;


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

	RtlZeroMemory ((PVOID) &TmpDmaDsp, sizeof (DMA_CHAIN));

	//  For Receive DMA
	if (DMA_RX_DSP_CHAINS == ChainType)
	{
		pStartingDspChains = pDeviceExt->pRxRealDmaChainsArray;
		pStartingSdlcBuffers = pDeviceExt->pRxRealSdlcBuffersArray;
	}
	//  For Transmit DMA
	else
	{
		pStartingDspChains = pDeviceExt->pTxRealDmaChainsArray;
		pStartingSdlcBuffers = pDeviceExt->pTxRealSdlcBuffersArray;
	}

	// Chains the descriptors
	for (i = 0; i < pDeviceExt->NumberOfDmaChains; i++)
	{
		if ((i + 1) != pDeviceExt->NumberOfDmaChains)
			TmpDmaDsp.NextChain = (USHORT) &pStartingDspChains[i + 1];
		else
			TmpDmaDsp.NextChain = (USHORT) &pStartingDspChains[0];

		pSdlcBuffer = (ULONG)(ULONG_PTR) &pStartingSdlcBuffers[i];
		TmpDmaDsp.BufferAddress = (USHORT) pSdlcBuffer;
		TmpDmaDsp.BuffAddrExt = (UCHAR)(pSdlcBuffer >> 16);

		fnCopyToCardMemory (
			(PUCHAR) &TmpDmaDsp,
			(ULONG_PTR) &pStartingDspChains[i],
			(USHORT) DMA_CHAIN_SIZE,
			pDeviceExt);

		//
		//  Verify the DMA Chain descriptors
		//
		fnReadFromCardMemory (
			(ULONG_PTR) &pStartingDspChains[i],
			(PUCHAR) &TmpDmaDsp1,
			(USHORT) DMA_CHAIN_SIZE,
			pDeviceExt);

		if (TmpDmaDsp1.NextChain != TmpDmaDsp.NextChain)
			DigiDump (DIGIERRORS, ("1-Read/Write Error on Dma Descriptor at "
				"address %08x: Wrote %04x, Read%04x\n",
				&pStartingDspChains[i], TmpDmaDsp.NextChain,
				TmpDmaDsp1.NextChain));

		if (TmpDmaDsp1.BufferAddress != TmpDmaDsp.BufferAddress)
			DigiDump (DIGIERRORS, ("2-Read/Write Error on Dma Descriptor at "
				"address %08x: Wrote %04x Read%04x\n",
				&pStartingDspChains[i], TmpDmaDsp.BufferAddress,
				TmpDmaDsp1.BufferAddress));

		if (TmpDmaDsp1.BuffAddrExt != TmpDmaDsp.BuffAddrExt)
			DigiDump (DIGIERRORS, ("3-Read/Write Error on Dma Descriptor at "
				"address %08x: Wrote %02x Read%02x\n",
				&pStartingDspChains[i], TmpDmaDsp.BuffAddrExt,
				TmpDmaDsp1.BuffAddrExt));
	}

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


VOID
fnInitializeRxDmaChains (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function initializes the Receive DMA descriptor chains and
	indexes for the receive FIFO.

Parameters:

	pDeviceExt
		Address of the Device extension

Return Value:

	None.

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

	pDeviceExt->pRxDmaDspCda = &pDeviceExt->pRxRealDmaChainsArray[0];
	pDeviceExt->pRxDmaDspEda =
		&pDeviceExt->pRxRealDmaChainsArray[pDeviceExt->NumberOfDmaChains - 1];
	pDeviceExt->RxDspIn = 0;
	pDeviceExt->RxDspOut = 0;
	pDeviceExt->ReceivedFrames = 0;

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


VOID
fnInitializeTxDmaChains (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function initializes the Transmit DMA descriptor chains and
	indexes for the transmit FIFO.

Parameters:

	pDeviceExt
		Address of the Device extension

Return Value:

	None.

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

	pDeviceExt->pTxDmaDspCda = &pDeviceExt->pTxRealDmaChainsArray[0];
	pDeviceExt->pTxDmaDspEda = pDeviceExt->pTxDmaDspCda;
	pDeviceExt->TxDspIn = 0;
	pDeviceExt->TxDspOut = 0;
	pDeviceExt->NumberOfTxFrames = 0;

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


VOID
fnConvertRealAddrToWindowAddr (
	IN ULONG_PTR	RealAddress,
	IN PULONG		pWindowAddress,
	IN PUCHAR		pMemoryWindowNumber,
	IN ULONG		WindowSize)
/*++

Description:

	This function converts a physical address to a bank address.  The card
	memory can only be accessed in 16KB windows.  This function will move
	to the appropriate memory window.  This is designed to work for ISA,
	MCA, and PCI Sync/570i cards.

Parameters:

	pAdapter
		Address of the Adapter object.

	pEntry
		Address of the object to be inserted into the adapter context queue.

Return Value:

	None.

--*/
{
	*pMemoryWindowNumber = (UCHAR)(RealAddress / WindowSize);

	*pWindowAddress = (ULONG)(RealAddress % WindowSize);
}


VOID
fnCopyToCardMemory (
	IN PUCHAR		pSrc,
	IN ULONG_PTR	RealAddress,
	IN USHORT		Length,
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function copies a user block of memory to card memory.  It is smart
	enough to avoid crossing a 16KB boundary.

Parameters:

	pSrc
		User buffer

	RealAddress
		Card address (offset from the beginning of card memory)

	Length
		Length of the buffer to copy

	pDeviceExt
		Address of the Device extension

Return Value:

	None.

--*/
{
	ULONG		WindowSize = pDeviceExt->pControllerExt->WindowSize;
	UCHAR		MemoryWindowNum = (UCHAR)(RealAddress / WindowSize);
	ULONG		OffsetInMem = (ULONG)(RealAddress % WindowSize);
	ULONG		CopyLength1 = MIN (Length, (WindowSize - OffsetInMem));
	PUCHAR		pDest = pDeviceExt->pControllerExt->VirtualWindow + OffsetInMem;
	PUCHAR		pSrcBuffer = pSrc;
	USHORT		LocalLength = Length;
	PCONTROLLER_EXT	pControllerExt = pDeviceExt->pControllerExt;


	EnableMemory (pDeviceExt, MemoryWindowNum);

	//  Write the 1st part of the block to the card
	WRITE_ADAPTER_BUFFER (pDest, pSrcBuffer, CopyLength1);

	//  Did we copy the entire block?
	if (LocalLength - CopyLength1)
	{
		//
		//  Copy the portion that crossed the window boundary
		//
		MemoryWindowNum = (++MemoryWindowNum) % pControllerExt->NumberOfWindows;
		EnableMemory (pDeviceExt, MemoryWindowNum);

		//  Write the rest of the block to the card
		WRITE_ADAPTER_BUFFER (pControllerExt->VirtualWindow,
			pSrcBuffer + CopyLength1, LocalLength - CopyLength1);
	}

	DisableMemory (pDeviceExt);
}


VOID
fnReadFromCardMemory (
	IN ULONG_PTR	RealAddress,
	IN OUT PUCHAR	pDest,
	IN USHORT		Length,
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function copies the block of memory from card memory to the user
	buffer.

Parameters:

	RealAddress
		Card address (offset from the beginning of card memory)

	pDest
		User buffer

	Length
		Length of the buffer to copy

	pDeviceExt
		Address of the Device extension

Return Value:

	None.

--*/
{
	ULONG		WindowSize = pDeviceExt->pControllerExt->WindowSize;
	UCHAR		MemoryWindowNum = (UCHAR)(RealAddress / WindowSize);
	ULONG		OffsetInMem = (ULONG)(RealAddress % WindowSize);
	ULONG		ReadLength1 = MIN (Length, (WindowSize - OffsetInMem));
	PUCHAR		pSrc = pDeviceExt->pControllerExt->VirtualWindow + OffsetInMem;
	PUCHAR		pDestBuffer = pDest;
	USHORT		LocalLength = Length;
	PCONTROLLER_EXT	pControllerExt = pDeviceExt->pControllerExt;


	EnableMemory (pDeviceExt, MemoryWindowNum);

	// Read as much of the block as possible from the card
	READ_ADAPTER_BUFFER (pSrc, pDestBuffer, ReadLength1);

	if (LocalLength - ReadLength1)
	{
		MemoryWindowNum = (++MemoryWindowNum) % pControllerExt->NumberOfWindows;
		EnableMemory (pDeviceExt, MemoryWindowNum);

		// Read the rest of the block from the card
		READ_ADAPTER_BUFFER (pControllerExt->VirtualWindow,
			pDestBuffer + ReadLength1, LocalLength - ReadLength1);
	}

	DisableMemory (pDeviceExt);
}


VOID 
GetInterfaceId (
	IN PCONTROLLER_EXT	pControllerExt)
/*++

Description:

	This function determines the daughter card type on the 570 and 570i for PCI.

Parameters:

	pControllerExt
		Address of the Controller extension.

Return Value:

	None.

--*/
{
	UCHAR	InterfaceType ;


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


	InterfaceType = pControllerExt->iBusMemoryCommType;

	switch (InterfaceType & 0xE0)
	{
	case 0x00:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: RS-232 (0x%x)\n",
			IF_232));
		pControllerExt->InterfaceID = IF_232;
		break;

	case 0x20:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: V.35/RS-232 (0x%x)\n",
			IF_V35_232));
		pControllerExt->InterfaceID = IF_V35_232;
		break;

	case 0x40:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: EIA-530 (0x%x)\n",
			IF_530));
		pControllerExt->InterfaceID = IF_530;
		break;

	case 0x60:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: X.21 (0x%x)\n", IF_X21));
		pControllerExt->InterfaceID = IF_X21;
		break;

	case 0x80:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: Switched 56 (0x%x)\n",
			IF_SW56));
		pControllerExt->InterfaceID = IF_SW56;
		break;

	case 0xC0:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: EIA-530/X.21 (0x%x)\n",
			IF_530_X21));
		pControllerExt->InterfaceID = IF_530_X21;
		break;

	case 0xE0:
		//
		// if pci adapter, get interface id from daughter card
		//
		if (PCIBus == pControllerExt->BusType)
		{
			ReadInterfaceType (pControllerExt);
		}
		else
		{
			DigiDump (DIGIERRORS, ("*** Not PCI && Interface Type (0xE0)\n"));
		}
		break;

	default:
		DigiDump (DIGIERRORS, ("*** GetInterfaceId()  Unknown Interface Type (0x%x)\n",
			InterfaceType & 0xE0));

		DigiLogError (pGlobalDriverObject,
			MP570_UNKNOWN_INTERFACE_TYPE,
			1,
			NULL, 0,
			pControllerExt->Name.Buffer, pControllerExt->Name.Length + sizeof (WCHAR),
			NULL, 0);

	}

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


//
//  UIB and PCI specific functions
//

VOID 
ReadInterfaceType (
	IN PCONTROLLER_EXT	pControllerExt)
/*++

Description:

	This routine interprets the configuration bit-stream from the daughter
	card on the Sync/570i PCI card to determine the actual interface type.

Parameters:

	pControllerExt
		Address of the Controller extension.

Return Value:

	Port type code.

--*/
{
	register LONG	Config = 0, i;
	LONG			Temp = 0;
	PUCHAR			VirtualIO;
	UCHAR			ActualPorts = 0;


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


	VirtualIO = pControllerExt->VirtualIO + REG570PCI_PIM_CTRL;

	// Read the configuration bit-stream from a daughtercard on a Sync/570i PCI
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x00);	// init serial interface
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x01);	// strobe interface
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x04);	// set read mode

	for (i = 0; i < 16; i++)
	{
		Temp = (*pControllerExt->pIO_IN) (VirtualIO);
		Config |= (((Temp & 0x02) >> 1) << i);
		(*pControllerExt->pIO_OUT) (VirtualIO, 0x05);	// strobe interface in read mode
	}
	pControllerExt->ConfigStream = Config;

	DigiDump (DIGIVERYLOUD, ("  Config bit-stream value 0x%x\n", Config));

	// leave device in initialized state (also turns off LED's)

	(*pControllerExt->pIO_OUT) (VirtualIO, 0x00);	// init serial interface
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x01);	// strobe interface
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x14);	// Green LED on, Yellow LED Auto

	//  Compare the actual and configured number of lines for this adapter
	ActualPorts = (Config & 0x10) ? 2 : 4;
	if (ActualPorts != pControllerExt->AdapterLines)
	{
		DigiDump (DIGIERRORS, ("*** Actual Ports (%d)  Configured Ports (%d)\n",
			ActualPorts, pControllerExt->AdapterLines));

//
//  Port Count is not configured in SNA installations, the port count
//  is assumed from the PCI Device ID of the adapter, but does not
//  get determined until after this routine is called, therefore this
//  is not an error.
//
#if !NT5_BUILD
#if (!SNA_DRIVER)
		DigiLogError (pGlobalDriverObject,
			MP570_PORT_COUNT_WRONG,
			2,
			NULL, 0,
			pControllerExt->Name.Buffer, pControllerExt->Name.Length + sizeof (WCHAR),
			NULL, 0);
#endif // !SNA_DRIVER
#endif
	}

	switch (Config & 0x0F)
	{
	case 0x00:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: TTL Loopback (0x%x)\n",
			IF_TTL));
		pControllerExt->InterfaceID = IF_TTL;
		break;

	case 0x01:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: 4 Port RS-232 (0x%x)\n",
			IF_4P232));
		pControllerExt->InterfaceID = IF_4P232;
		break;

	case 0x02:
		DigiDump (DIGIVERYLOUD,
			("  Interface Type: 2 Port V.35/RS-232 combo (0x%x)\n",
			IF_2PDUAL));
		pControllerExt->InterfaceID = IF_2PDUAL;
		break;

	case 0x03:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: 4 Port V.35 (0x%x)\n",
			IF_4PV35));
		pControllerExt->InterfaceID = IF_4PV35;
		break;

	case 0x04:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: UIB (0x%x)\n", IF_UIB));
		pControllerExt->InterfaceID = IF_UIB;
		break;

	case 0x0F:
		DigiDump (DIGIVERYLOUD, ("  Interface Type: No interface card (0x%x)\n",
			IF_NONE));
		pControllerExt->InterfaceID = IF_NONE;
		break;
	}

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


ULONG
AdcToInterface (
	IN LONG		ADC)
/*++

Description:

	This function translates the ADC value associated with an Active Interface
	cable into the interface type of the cable (i.e. the port type).

Parameters:

	ADC
		Config value read from the the Analog to Digital Converter.

Return Value:

	Port type value.

--*/
{
	int		i;
	//  The spec says these ranges should be larger for the device
	//  driver, but I don't know what they should be right now, so this
	//  may need to be changed later.
	AdcToInterface_t AdcToInterfaceTable[] = {
		{245, 255, PT_V35},
		{216, 233, PT_232_RI},
		{182, 198, PT_X21},
		{161, 175, PT_530},
		{10, 16, PT_LOOP},
		{0, 4, PT_NO_CABLE},
		{-1, 256, PT_UNKNOWN} };			// must be final entry!
	LONG	TableSize = sizeof(AdcToInterfaceTable)/sizeof(AdcToInterface_t);

	DigiDump (DIGIFLOW, ("<AdcToInterface> Entering\n"));

	for (i = 0; i < TableSize; i++)
	{
		if (ADC >= AdcToInterfaceTable[i].LowLimit
			&& ADC <= AdcToInterfaceTable[i].HighLimit)
		{
			DigiDump (DIGIFLOW, ("<AdcToInterface> Exiting (Port is 0x%x)\n",
				AdcToInterfaceTable[i].Interface));
			return (AdcToInterfaceTable[i].Interface);
		}
	}

	DigiDump (DIGIFLOW, ("<AdcToInterface> Exiting (*** PORT Unknown!!!)\n"));

	return (PT_UNKNOWN);
}


VOID
ReadUcType (
	IN PDEVICE_EXT		pDeviceExt)
/*++

Description:

	This function will fetch the embedded serial bit stream, this will be
	returned in the pDeviceExt->Adc variable.  This value is actually the
	internal ID resistor of the Universal cable for the specified port.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	register ULONG	Config = 0;
	register LONG	i;
	ULONG			ADC;
	PUCHAR			VirtualIO;
	PCONTROLLER_EXT	pControllerExt = pDeviceExt->pControllerExt;


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

	//  Is this right???  -DLH what are we really reading here???
	VirtualIO = pControllerExt->VirtualIO + REG570PCI_PIM_CTRL;

	//
	// read interface card serial id bit stream (up to bit 8)
	//
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x00);		// init serial interface
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x01);		// strobe interface
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x04);		// set read mode

	for (i = 0; i < 8; i++)
	{
		Config |= (((*pControllerExt->pIO_IN) (VirtualIO) & 0x02) >> 1) << i;
		(*pControllerExt->pIO_OUT) (VirtualIO, 0x05);	// strobe interface in read mode
	}

	DigiDump (DIGIVERYLOUD, ("  Config stream (bits 0-7): 0x%x\n", Config));

	//
	// read UC value
	//

#define YELLOW(n) ((UCHAR) ((n) != 0 ? 0x08 : 0x00))
#define GREEN(n)  ((UCHAR) ((n) != 0 ? 0x04 : 0x00))

#define C1		(*pControllerExt->pIO_OUT) (VirtualIO, YELLOW(1) | GREEN(1)), \
				(*pControllerExt->pIO_OUT) (VirtualIO, YELLOW(1) | GREEN(0))

#define C0		(*pControllerExt->pIO_OUT) (VirtualIO, YELLOW(0) | GREEN(1)), \
				(*pControllerExt->pIO_OUT) (VirtualIO, YELLOW(0) | GREEN(0))

	// Set Initial Conditions
	C1;
	C1;
	C1;

	// Select Port

	switch (pDeviceExt->PortNumber & 0x03)
	{
	case FIRST_PORT:
		C0;
		C0;
		break;

	case SECOND_PORT:
		C0;
		C1;
		break;

	case THIRD_PORT:
		C1;
		C0;
		break;

	case FOURTH_PORT:
		C1;
		C1;
		break;
	}

	C0;								// dummy C0 to turn around ADC

	//
	//  Read data bits
	//

	ADC = 0;

	for (i = 0; i < 8; i++)
	{
		(*pControllerExt->pIO_OUT) (VirtualIO, YELLOW (0) | GREEN (1));
		(*pControllerExt->pIO_OUT) (VirtualIO, YELLOW (0) | GREEN (0));
		ADC <<= 1;
		if ((*pControllerExt->pIO_IN) (VirtualIO) & 0x02)
			ADC |= 0x01;
	}

	DigiDump (DIGIINIT, ("  ADC is 0x%x\n", ADC));
	pDeviceExt->Adc = ADC;
	pDeviceExt->PortType = AdcToInterface (ADC);

	//
	//  Read interface card serial id bit stream (bits 8 - 15)
	//
	for (i = 0; i < 8; i++)
	{
		Config |= (((*pControllerExt->pIO_IN) (VirtualIO) & 0x02) >> 1) << i;
		(*pControllerExt->pIO_OUT) (VirtualIO, 0x05);	// strobe interface in read mode
	}

	DigiDump (DIGIINIT, ("  Config stream (bits 0-15): 0x%x\n", Config));


	// leave device in initialized state (also turns off LED's)

	(*pControllerExt->pIO_OUT) (VirtualIO, 0x00);	// init serial interface
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x01);	// strobe interface
	(*pControllerExt->pIO_OUT) (VirtualIO, 0x14);	// Green LED on, Yellow LED Auto

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


VOID
GetPortType (
	PDEVICE_EXT		pDeviceExt)
/*++

Description:

	This function will determine the Port Type for the passed in pDeviceExt.
	Some cables have different types of connectors for each port.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	PCONTROLLER_EXT		pControllerExt = pDeviceExt->pControllerExt;


	DigiDump (DIGIFLOW, ("<GetPortType> Entering\n"));

	pDeviceExt->PortType = PT_UNKNOWN;

	switch (pControllerExt->InterfaceID)
	{
	case IF_4P232:
	case IF_232:
		pDeviceExt->PortType = PT_232;
		break;

	case IF_V35_232:
		pDeviceExt->PortType = PT_V35_232;
		break;

	case IF_530:
		pDeviceExt->PortType = PT_530;
		break;

	case IF_X21:
		pDeviceExt->PortType = PT_X21;
		break;

	case IF_530_X21:
		if (FIRST_PORT == pDeviceExt->PortNumber)
			pDeviceExt->PortType = PT_530;
		else if (SECOND_PORT == pDeviceExt->PortNumber)
			pDeviceExt->PortType = PT_X21;
		break;

	case IF_SW56:
		pDeviceExt->PortType = PT_SW56;
		break;

	case IF_UIB:
		//  this routine saves the port type in pDeviceExt->PortType
		ReadUcType (pDeviceExt);
		break;
	}

	if (PT_UNKNOWN == pDeviceExt->PortType)
	{
		DigiDump (DIGIERRORS, ("*** Unknown Interface Type (0x%x)\n",
			pControllerExt->InterfaceID));

		DigiLogError (pGlobalDriverObject,
			MP570_UNKNOWN_INTERFACE,
			3,
			NULL, 0,
			pControllerExt->Name.Buffer, pControllerExt->Name.Length + sizeof (WCHAR),
			NULL, 0);
	}

	DigiDump (DIGIFLOW, ("<GetPortType> Exiting\n"));
}

