/*++
 * 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/hw570.c 5     10/22/97 11:56a Darinh $
 *
 * Revision History:
 * $Log: /Components/Windows/NT/Sync/Build/Mp570/hw570.c $
 * 
 * 5     10/22/97 11:56a Darinh
 * Changes to make multiple board installations work better.
 * 
 * 4     9/08/97 3:44p Darinh
 * A variety of changes, including Data General fixes are included.
 * 
 * 3     6/06/97 1:47p 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 "ioctls.h"
#include "hwsca.h"
#include "debug.h"
#include "snaioctl.h"


NTSTATUS
fnQueryAdapterExistence (
	IN PCONTROLLER_EXT	pControllerExt)
/*++

Description:

	This function will check for the existence of an ISA Sync/570 card
	at the specified I/O address (which is read from the registry).  It
	checks for the '570' signature.

Parameters:

	pControllerExt
		Address of the Controller extension.

Return Value:

	None

--*/
{
	PUCHAR	BaseIO = pControllerExt->VirtualIO;
	NTSTATUS	Status = STATUS_UNSUCCESSFUL;
	volatile UCHAR	RegVal = 0;


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

	if (('5' == IO_IN (BaseIO)) &&
		('7' == IO_IN (BaseIO + 1)) &&
		('0' == IO_IN (BaseIO + 2)))
	{
		RegVal = (*pControllerExt->pIO_IN) (BaseIO + REG570_HANDSHAKE);
		DigiDump (DIGIVERYLOUD, ("  Handshake signals: 0x%x\n", RegVal));
		Status = STATUS_SUCCESS;
	}

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

	return (Status);
}


VOID
fnResetScas (
	IN PCONTROLLER_EXT	pControllerExt)
/*++

Description:

	This function will reset all the SCA chips on the current Sync/570 card.
	The reset bit must be held on 0 for at least 1000 nsec., and then set
	to 1.  We actually hold it in reset for 20 usec.

Parameters:

	pControllerExt
		Address of the Controller extension.

Return Value:

	None

--*/
{
	PUCHAR  pResetReg;


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

	if (PCIBus == pControllerExt->BusType)
		pResetReg = pControllerExt->VirtualIO + REG570PCI_TXCLK_DTR01;
	else
		pResetReg = pControllerExt->VirtualIO + REG570_TXCLK_DTR01;

	pControllerExt->oTxClkDtr01 &= ~TCD01_RES;
	(*pControllerExt->pIO_OUT) (pResetReg, pControllerExt->oTxClkDtr01);

	//  Wait for 20 usecs.
	IO_DELAY (20L);

	pControllerExt->oTxClkDtr01 |= TCD01_RES;
	(*pControllerExt->pIO_OUT) (pResetReg, pControllerExt->oTxClkDtr01);

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


NTSTATUS
fnSetLinkConfig (
	IN PDEVICE_EXT	pDeviceExt,
	IN PLINKCHAR	pLinkChars)
/*++

Description:

	This function is used to set up the Link Protocol parameters. The
	following are the setting for MSCI registers:                             
	. MSCI Mode Register 2 (MD2)
		- Transmission Code type (NRZI or NRZ)
		- Always Full Duplex
	. MSCI Control Register (CTL)
		- Constant or switch RTS
		- Underrun state control : Enter idle state after FCS and flag
			transmission
		- Idle state control : Transmit a mark
	. MSCI RX Clock Source Register (RXS)
		- Use the RXC line input as the Receive Clock
	. MSCI TX Clock Source Register (TXS)
		- Use the Receive Clock as the Transmit Clock

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	PCONTROLLER_EXT	pControllerExt = pDeviceExt->pControllerExt;
	UCHAR			ScaClkVal, ScaTmcVal;
	NTSTATUS		Status = STATUS_SUCCESS;


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

	//  Abort Receiver
	SnaIoctlAbortRx (pDeviceExt);

	//  Abort Transmitter
	SnaIoctlAbortTx (pDeviceExt);

	//  Get the Port Type for this DeviceObject
	GetPortType (pDeviceExt);

	pDeviceExt->ScaMd0 = MD0_PRTCL_HDLC | MD0_CRC_ENABLE | MD0_CRC_CCITT |
		MD0_CRC_INIT_1;

	//  Validate input settings
	if (pLinkChars->FrameSize < DEFAULT_MIN_MAXDATA)
	{
		Status = STATUS_INVALID_PARAMETER;
		pDeviceExt->Information = INFO_FRAME_BUF_TOO_SMALL;
	}
	else if (pLinkChars->FrameSize > DEFAULT_MAX_MAXDATA)
	{
		Status = STATUS_INVALID_PARAMETER;
		pDeviceExt->Information = INFO_FRAME_BUF_TOO_BIG;
	}
	else if (pLinkChars->LinkOptions & LO_CLOCK)
	{
		Status = STATUS_INVALID_PARAMETER;
		pDeviceExt->Information = INFO_NO_CLOCKS;
	}

	if (pLinkChars->LinkOptions & LO_NRZI)
	{
		pDeviceExt->ScaMd2 = MD2_NRZI | MD2_FULL_DUPLEX;
	}
	else
	{
		pDeviceExt->ScaMd2 = MD2_NRZ | MD2_FULL_DUPLEX;
	}

	if (pLinkChars->LinkOptions & LO_4WIRE)
	{
		//  Set RTS low
		pDeviceExt->ScaCtl = 0;		// Constant RTS

		// Send IDL character during Idle
		pDeviceExt->ScaCtl |= MSCI_CTL_IDLC_PATTERN;

	}
	else
	{
		//  Set RTS high
		pDeviceExt->ScaCtl = MSCI_CTL_RTS_HIGH;
	}

	// Enter idle state after FCS and flag transmission
	pDeviceExt->ScaCtl |= MSCI_CTL_UDRNC_ENABLE;

	pDeviceExt->ScaRxs = 0x0;   // Use the RXC input line as RX clock

	//  External Clocks
	if (!pDeviceExt->InternalClocking)
	{
		if (( PT_X21 == pDeviceExt->PortType) || ( PT_V35 == pDeviceExt->PortType))
			pDeviceExt->ScaTxs = 0x60;	// Use the RX Clock as the TX clock
		else
			pDeviceExt->ScaTxs = 0x0;

		pDeviceExt->ScaTmc = 0;

		if (PT_SW56 == pDeviceExt->PortType)
			pDeviceExt->DigiDtrTxE = TCD01_DTRTX0_ENABLE_56;
	}
	else
	{

		//
		//  Clock freq is 9.8304 MHz
		//
		//  f(BR) = f(CLK)/TMC /2**BR
		//
		//  Use the BRG as the TX clock 9600bps  : 0x43 with TMC of 130
		//  Use the BRG as the TX clock 19200bps : 0x42 with TMC of 130
		//  Use the BRG as the TX clock 32000bps : 0x41 with TMC of 156
		//  Use the BRG as the TX clock 64000bps : 0x40 with TMC of 156
		//
		if (pDeviceExt->Config.BaudRate < 
			(LS_2400BPS + ((LS_4800BPS - LS_2400BPS)/2)))
		{
			ScaClkVal = 0x45;
			ScaTmcVal = 128;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_4800BPS + ((LS_9600BPS - LS_4800BPS)/2)))
		{
			ScaClkVal = 0x44;
			ScaTmcVal = 128;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_9600BPS + ((LS_19200BPS - LS_9600BPS)/2)))
		{
			ScaClkVal = 0x43;
			ScaTmcVal = 128;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_19200BPS + ((LS_38400BPS - LS_19200BPS)/2)))
		{
			ScaClkVal = 0x42;
			ScaTmcVal = 128;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_38400BPS + ((LS_56000BPS - LS_38400BPS)/2)))
		{
			ScaClkVal = 0x41;
			ScaTmcVal = 128;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_56000BPS + ((LS_64000BPS - LS_56000BPS)/2)))
		{
			ScaClkVal = 0x43;
			ScaTmcVal = 22;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_64000BPS + ((LS_128000BPS - LS_64000BPS)/2)))
		{
			ScaClkVal = 0x43;
			ScaTmcVal = 19;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_128000BPS + ((LS_256000BPS - LS_128000BPS)/2)))
		{
			ScaClkVal = 0x41;
			ScaTmcVal = 38;
		} else if (pDeviceExt->Config.BaudRate < 
			(LS_256000BPS + ((LS_512000BPS - LS_256000BPS)/2)))
		{
			ScaClkVal = 0x41;
			ScaTmcVal = 19;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_512000BPS + ((LS_1024000BPS - LS_512000BPS)/2)))
		{
			ScaClkVal = 0x41;
			ScaTmcVal = 10;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_1024000BPS + ((LS_1536000BPS - LS_1024000BPS)/2)))
		{
			ScaClkVal = 0x41;
			ScaTmcVal = 5;
		} 
		else if (pDeviceExt->Config.BaudRate < 
			(LS_1536000BPS + ((LS_2048000BPS - LS_1536000BPS)/2)))
		{
			ScaClkVal = 0x41;
			ScaTmcVal = 3;
		} 
		else
		{
			// 2048000BPS is the defaults:
			ScaClkVal = 0x41;
			ScaTmcVal = 2;
		}

		DigiDump (DIGIVERYLOUD, ("Clk = 0x%02x, Tmc = 0x%04x\n",
			ScaClkVal, ScaTmcVal));

		// Use the PLL Baud Generator for the RX Clock
		pDeviceExt->ScaRxs = ScaClkVal;  
		
		// Use the RX Clock for the TX Clock
		pDeviceExt->ScaTxs = 0x60;

		// Set the Time Constant Value
		pDeviceExt->ScaTmc = ScaTmcVal;

	}

	//
	//  Save the config options for later
	//
	pDeviceExt->Config.MaxFrameSize = (USHORT)pLinkChars->FrameSize;
	pDeviceExt->StationAddress1 = pLinkChars->StationAddress1;
	pDeviceExt->StationAddress2 = pLinkChars->StationAddress2;
	pDeviceExt->LinkOptions = pLinkChars->LinkOptions;

	if ((pLinkChars->StationAddress1 == 0) &&
		(pLinkChars->StationAddress2 == 0))
	{
		pDeviceExt->ScaMd1 = 0;
	}
	else if ((pLinkChars->StationAddress2 == 0) ||
		(pLinkChars->StationAddress2 == 0xFF))
	{
		pDeviceExt->ScaMd1 = MD1_SINGLE_ADDR1;
	}

	//  Should we reset statistics?
	if (pLinkChars->LinkOptions & LO_RSTAT)
	{
		pDeviceExt->IR.StatusEvents = 0;
		RtlZeroMemory (pDeviceExt->IR.StatisticsCounters,
			sizeof (pDeviceExt->IR.StatisticsCounters));
	}

	// Setup SCA chip with these communication settings
	fnSetScaLinkConfig (pDeviceExt);

	// Set the Clocking
	switch (pDeviceExt->PortNumber)
	{
	case FIRST_PORT:
	case SECOND_PORT:
		//
		// If CLKS=External, we must make the
		// TXC direction value in the DTR-TX_CLK reg = INPUT
		//
		pDeviceExt->DigiRegTxClkDtrCtrl = pControllerExt->oTxClkDtr01;

		// Output the transmit clock (get from RXC)
		if (pDeviceExt->InternalClocking)
		{
			pDeviceExt->DigiRegTxClkDtrCtrl &= ~pDeviceExt->DigiTxClkInput;
		}
		else
		{
			pDeviceExt->DigiRegTxClkDtrCtrl |= pDeviceExt->DigiTxClkInput;
		}

		pControllerExt->oTxClkDtr01 = pDeviceExt->DigiRegTxClkDtrCtrl;
		(*pControllerExt->pIO_OUT) (pDeviceExt->DigiTxClkDtrCtrl,
			pDeviceExt->DigiRegTxClkDtrCtrl);

		break;

	case THIRD_PORT:
	case FOURTH_PORT:

		pDeviceExt->DigiRegTxClkDtrCtrl = pControllerExt->oTxClkDtr23;

		// Output the transmit clock (get from RXC)
		if (pDeviceExt->InternalClocking)
		{
			pDeviceExt->DigiRegTxClkDtrCtrl &= ~pDeviceExt->DigiTxClkInput;
		}
		else
		{
			pDeviceExt->DigiRegTxClkDtrCtrl |= pDeviceExt->DigiTxClkInput;
		}
		pControllerExt->oTxClkDtr23 = pDeviceExt->DigiRegTxClkDtrCtrl;
		(*pControllerExt->pIO_OUT) (pDeviceExt->DigiTxClkDtrCtrl,
			pDeviceExt->DigiRegTxClkDtrCtrl);

		break;
	}

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

	return (Status);
}


VOID
fnPrint570IoRegisters (
	IN PCONTROLLER_EXT	pControllerExt)
/*++

Description:

	This function is used to dump the contents of the IO registers of the '570.

Parameters:

	pAdapter
		Address of the Adapter object.

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

Return Value:

	None.

--*/
{
	PUCHAR  lp570IoReg = pControllerExt->VirtualIO;
	UCHAR   RegVal = 0;
	int     i;


	DigiDump (DIGIDATA, ("Entering fnPrint570IoRegisters()\n"));

	DigiDump (DIGIDATA, ("570 IO Register values are: "));

	for (i = 0; i < 14; i++, lp570IoReg++)
	{
		RegVal = (*pControllerExt->pIO_IN) (lp570IoReg);
		DigiDump (DIGIDATA, (" %02x\n", RegVal));
	}
	DigiDump (DIGIDATA, ("\n"));

	DigiDump (DIGIDATA, ("Exiting fnPrint570IoRegisters()\n"));
}


VOID
fnPrintScaRegisters (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will print the contents of the 256 SCA registers.

Parameters:

	pDeviceExt
		Address of the Device extension

Return Value:

	None.

--*/
{
// This is causing a blue-screen after 30 bytes


	PUCHAR  pSca = (PUCHAR) pDeviceExt->pSca;
	int     i, j;


	DigiDump (DIGIDATA, ("Entering fnPrintScaRegisters()\n"));

	// Enable the SCA in Card Memory Space
	EnableScaMemMap (pDeviceExt);

	DigiDump (DIGIDATA, ("SCA Register Dump\n"));
	for (i = 0; i < 16; i++)
	{
		for (j = 0; j < 16; j++)
		{
			DigiDump (DIGIDATA, ("%02x ", READ_REGISTER_UCHAR (pSca++)));
			if (j == 7)
				DigiDump (DIGIDATA, ("- "));
		}
		DigiDump (DIGIDATA, ("\n"));
	}

	// Disable the SCA in Card Memory Space
	DisableMemory (pDeviceExt);

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

}



VOID
fnPrintScaMsciRegisters (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This function will print the contents of the SCA MSCI registers.

Parameters:

	pDeviceExt
		Address of the Device extension

Return Value:

	None.

--*/
{

	// Enable the SCA in Card Memory Space
	EnableScaMemMap (pDeviceExt);

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

	DigiDump (DIGIDATA, ("SCA MSCI Register Dump\n"));

	DigiDump (DIGIDATA, ("Md0 = %02x\n",READ_REGISTER_UCHAR(&pDeviceExt->pScaMsci->Md0)));
	DigiDump (DIGIDATA, ("Md1 = %02x\n",READ_REGISTER_UCHAR(&pDeviceExt->pScaMsci->Md1)));
	DigiDump (DIGIDATA, ("Md2 = %02x\n",READ_REGISTER_UCHAR(&pDeviceExt->pScaMsci->Md2)));
	DigiDump (DIGIDATA, ("Ctl = %02x\n",READ_REGISTER_UCHAR(&pDeviceExt->pScaMsci->Ctl)));
	DigiDump (DIGIDATA, ("Rxs = %02x\n",READ_REGISTER_UCHAR(&pDeviceExt->pScaMsci->Rxs)));
	DigiDump (DIGIDATA, ("Txs = %02x\n",READ_REGISTER_UCHAR(&pDeviceExt->pScaMsci->Txs)));
	DigiDump (DIGIDATA, ("Tmc = %02x\n",READ_REGISTER_UCHAR(&pDeviceExt->pScaMsci->Tmc)));
	DigiDump (DIGIDATA, ("Cmd = %02x\n",READ_REGISTER_UCHAR(&pDeviceExt->pScaMsci->Cmd)));
	DigiDump (DIGIDATA, ("Idl = %02x\n",READ_REGISTER_UCHAR(&pDeviceExt->pScaMsci->Idl)));

	// Disable the SCA in Card Memory Space
	DisableMemory (pDeviceExt);

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

}


void
fnWriteDTR (
	IN PDEVICE_EXT	pDeviceExt,
	IN ULONG		NewPinSetting)
/*++

Description:

	This function control the raising of DTR depending on the port number.

Parameters:

	pDeviceExt
		Address of the Device extension.
		The New Pin Setting

Return Value:

	None.

--*/
{

	PCONTROLLER_EXT	pControllerExt = pDeviceExt->pControllerExt;

	// Get the Current Value of the Register.  This register is maintained
	// in software, since it is a write only register.
	switch (pDeviceExt->PortNumber)
	{
	case FIRST_PORT:
	case SECOND_PORT:
		pDeviceExt->DigiRegTxClkDtrCtrl = pControllerExt->oTxClkDtr01;
		break;

	case THIRD_PORT:
	case FOURTH_PORT:
		pDeviceExt->DigiRegTxClkDtrCtrl = pControllerExt->oTxClkDtr23;
		break;

	}

	// Raise or Lower DTR
	switch (NewPinSetting)
	{
	case LOWER:
		pDeviceExt->DigiRegTxClkDtrCtrl &= ~pDeviceExt->DigiDtrTxE;
		break;

	case RAISE:
		pDeviceExt->DigiRegTxClkDtrCtrl |= pDeviceExt->DigiDtrTxE;
		break;

	}


	// Now write out the New Value
	(*pControllerExt->pIO_OUT) (pDeviceExt->DigiTxClkDtrCtrl,
		pDeviceExt->DigiRegTxClkDtrCtrl);

	// Maintain the new value of the register
	switch (pDeviceExt->PortNumber)
	{

	case FIRST_PORT:
	case SECOND_PORT:
		pControllerExt->oTxClkDtr01 = pDeviceExt->DigiRegTxClkDtrCtrl;
		break;

	case THIRD_PORT:
	case FOURTH_PORT:
		pControllerExt->oTxClkDtr23 = pDeviceExt->DigiRegTxClkDtrCtrl;
		break;

	}

}


VOID
fnDropModemSignals (
	IN PDEVICE_EXT	pDeviceExt)
/*++

Description:

	This routine will be called at shutdown time for each of the
	pDeviceExt's present for the pController object.

Parameters:

	pDeviceExt
		Address of the Device extension.

Return Value:

	None.

--*/
{
	PCONTROLLER_EXT	pControllerExt = pDeviceExt->pControllerExt;
	volatile UCHAR	Ctl;
	UCHAR			DtrMask = 0;
	UCHAR			DtrCtrlReg = 0, OtherReg = 0;


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

	//
	//  Modify DTR
	//
	DtrMask = pDeviceExt->DigiDtrTxE & 0xC;

	DigiDump (DIGIVERYLOUD, ("DTR is %s\n",
		(pDeviceExt->DigiRegTxClkDtrCtrl & DtrMask) ? "ON" : "OFF"));

	DigiDump (DIGIVERYLOUD, ("Lowering DTR\n"));
	fnWriteDTR (pDeviceExt,LOWER);

	//
	//  Modify RTS
	//
	EnableScaMemMap (pDeviceExt);

	// Setup RTS signal
	Ctl = READ_REGISTER_UCHAR ((PUCHAR) &pDeviceExt->pScaMsci->Ctl);

	DigiDump (DIGIVERYLOUD, ("RTS is %s, ",
		(Ctl & MSCI_CTL_RTS_HIGH) ? "OFF" : "ON"));

	DigiDump (DIGIVERYLOUD, ("Lowering RTS\n"));
	Ctl |= MSCI_CTL_RTS_HIGH;
	WRT_REG_UCHAR (&pDeviceExt->pScaMsci->Ctl, Ctl);

	DisableMemory (pDeviceExt);


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


