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

#include "digilib.h"

// NT5_BUILD users must use the DLL interface.
#if NT5_BUILD		// Defined in digilib.h

#include <ntddk.h>
#include "def570.h"
#include "def64570.h"
#include "board.h"
#include "proto.h"
#include "mp_api.h"
#include "mpisr.h"
#include "hw570.h"
#include "hwutils.h"
#include "io.h"
#include "dsmp.h"
#include "hwsca.h"
#include "debug.h"
#include "digilog.h"
#include "dxbreg.h"



// The DLL interface is for users who wish to gain access to the board through
// function calls, and not via a device interface.  The NT5 version of DigiSOH
// is the first user of this interface.  This module is only include in an
// NT5_BUILD.

NTSTATUS 
Sync570DllStartAdapter ( 
		IN	PDRIVER_OBJECT					pDriverObject,
		IN	PDEVICE_OBJECT					pDeviceObject,
		IN  PUNICODE_STRING					pAdapterName,
		IN	PDIGI_RESOURCE_LIST				pResources,
		IN	ULONG							dwLineCount,
		OUT	PDSMP_DLL_ADAPTER_HANDLE		phAdapter
	)
/*++

Routine Description:

	Initializes each controller/adapter configured in the registry.

Purpose:

	This routine is called by DLL users to obtain a handle to the adapter
	interface.  Only one user can own an adapter.  If another user attempts
	to use the resources of an adapter the start adapter will fail.

	The DLL interface is currently used by NT5.  To start the adapter:

		1.	Allocate a controller extension for the adapter.
		2.	Call DigiInitializeAdapter() to set resource information.
		3.	Create a device object and corresponding device extension for
			each line on the controller.

Arguments:

	pResources - Requested Resource usage.

	RegistryPath - Pointer to this drivers registry path, which contains
		configuration information.

Return Value:

	STATUS_SUCCESS - No errors found initializing the controllers.

--*/
{
	PCONTROLLER_EXT		pControllerExt = NULL;
	NTSTATUS			Status = STATUS_UNSUCCESSFUL;
	int					LineNumber;
	LINKCHAR			LinkChars = {DEFAULT_MAX_MAXDATA, 56000, 0, 0, 
									 LO_NRZI | LO_HDLC | LO_RSTAT, 0};

	DigiDump (DIGIINIT, ("Entering Sync570StartAdapter Adapter name %S\n",pAdapterName->Buffer));

	pGlobalDriverObject	= pDriverObject;

	//  Create storage for the Controller Extension.  This pointer to the controller
	//  extension is the interface adapter handle.
	pControllerExt = DigiAllocMem (NonPagedPool, sizeof *pControllerExt);
	if (pControllerExt == NULL)
	{
		DigiDump (DIGIERRORS, ("*** DigiAllocMem for the Controller Extension failed!\n"));
		Status = STATUS_INSUFFICIENT_RESOURCES;

		DigiLogError (pDriverObject,
			MP570_CREATE_CONTROLLER_FAILED,
			19,
			NULL, 0,
			NULL, 0,
			NULL, 0);

		goto Exit;
	}

	DigiDump (DIGIINIT, ("  pControllerExt = 0x%x\n", pControllerExt));

	// Zero out the Controller Extension
	RtlZeroMemory (pControllerExt, sizeof *pControllerExt);

	// Setup the adapter name information for Error Logging
	pControllerExt->Name.Buffer = (PVOID) &pControllerExt->NameBuffer;
	pControllerExt->Name.MaximumLength = sizeof (pControllerExt->NameBuffer);
	RtlCopyUnicodeString (&pControllerExt->Name, pAdapterName);

	// Set bus specific resources in the controller extension and initialize the adapter
	Status = DigiInitializeAdapter (pDriverObject,pResources,pControllerExt);

	if (!NT_SUCCESS (Status))
	{
		DigiDump (DIGIERRORS, ("*** DigiInitializeAdapter failed, Status = %08x\n",Status));
		DigiFreeMem (pControllerExt);
		return Status;
	}

   //  Initialize the board level spinlock
   KeInitializeSpinLock (&pControllerExt->MemoryLock);

   //  Setup some known offsets
	if (PCIBus == pControllerExt->BusType)
	{
		pControllerExt->pDigiDcdIntReg =
			pControllerExt->VirtualIO + REG570PCI_DCD_INT_STATUS;
	}
	else
	{
		pControllerExt->pDigiDcdIntReg =
			pControllerExt->VirtualIO + REG570_DCD_INT_STATUS;
		pControllerExt->pDigiMemScaReg =
			pControllerExt->VirtualIO + REG570_MEM_SCA;
	}

	//  Reset the SCA chip(s)
	fnResetScas (pControllerExt);

	//  Get the interface information for this card (needs to be called
	//  after fnResetScas()).
	GetInterfaceId (pControllerExt);

	Status = fnZeroCardMemory (pControllerExt);

	if (!NT_SUCCESS (Status))
	{
		DigiDump (DIGIERRORS, ("*** fnZeroCardMemory failed, Status = %08x\n",Status));
		return Status;
	}

	pControllerExt->AdapterLines = dwLineCount;

	// Allocate a device Extension for each line.  This is not a true device extension,
	// for the DLL interface, since device object don't exist.  It is called a Device
	// Extension so the rest of the code works.  The rest of the code is shared by all
	// three interfaces supported by this driver.
	for (LineNumber = 0; LineNumber < pControllerExt->AdapterLines; LineNumber++)
	{

		PDEVICE_EXT	pDeviceExt;

		pDeviceExt = DigiAllocMem (NonPagedPool, sizeof *pDeviceExt);
		if (pDeviceExt == NULL)
		{
			DigiDump (DIGIERRORS, ("*** DigiAllocMem for the Device Extension failed!\n"));
			Status = STATUS_INSUFFICIENT_RESOURCES;

			DigiLogError (pDriverObject,
				MP570_CREATE_DEVICE_FAILED,
				20,
				NULL, 0,
				NULL, 0,
				NULL, 0);

			goto Exit;
		}

		DigiDump (DIGIINIT, ("  pDeviceExt = 0x%x\n", pDeviceExt));

		// Zero out the Device Extension
		RtlZeroMemory (pDeviceExt, sizeof *pDeviceExt);

		//  Save a pointer to the device object in the controller extension
		pControllerExt->pDeviceObject[LineNumber] = pDeviceObject;

		//  Save a pointer to the device object's extension
		pControllerExt->pDeviceExt[LineNumber] = pDeviceExt;

		// Init Device extension

		pDeviceExt->Name.Buffer = (PVOID) &pDeviceExt->NameBuffer;
		pDeviceExt->Name.MaximumLength = sizeof (pDeviceExt->NameBuffer);
		RtlCopyUnicodeString (&pDeviceExt->Name, pAdapterName);

		//  Setup the DPC routine associated with the ISR
		IoInitializeDpcRequest (pDeviceObject, fnDPCRoutine);

		//  Save a pointer to this line's parent controller object
		pDeviceExt->pControllerExt = pControllerExt;

		pDeviceExt->PortNumber = (CHAR) LineNumber;

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

		//  Point to the SCA registers
		if (PCIBus == pControllerExt->BusType)
		{
			//  Ports 1 & 2
			if ((LineNumber == 0) || (LineNumber == 1))
			{
				pDeviceExt->pSca = (PSCA_REGS) pControllerExt->VirtualSca;
			}
			//  Ports 3 & 4
			else
			{
				pDeviceExt->pSca = (PSCA_REGS) (pControllerExt->VirtualSca + 0x400);
			}
		}
		else
		{
			//  ISA card
			pDeviceExt->pSca = (PSCA_REGS) pControllerExt->VirtualSca;
		}

		//  Setup register offsets
		fnSetupPortRelatedRegisters (pDeviceExt);

		//
		//  Use the defaults set above as the default
		//
		fnSetLinkConfig (pDeviceExt, &LinkChars);

		//  Setup DMA Descriptor Chains for Rx and Tx channels
		fnSetupDmaChain (pDeviceExt);

		//  Initialize the common registers in the SCA (only once)
		if (LineNumber == 0)
		{
			fnInitCommonScaRegs (pDeviceExt);
//			fnPrintScaRegisters (pDeviceExt);
		}

		//  Setup Timeout values based on line speed
		fnSetupTimerValues (pDeviceExt);

		//  Setup SCA interrupt vector that uses a modified vector
		fnSetupScaIMVR (pDeviceExt);

	}

	// Connect to the Interrupt
	if (PCIBus == pControllerExt->BusType)
	{
		Status = PciConnectToInterrupt (pControllerExt);
	}
	else
	{
		Status = IsaConnectToInterrupt (pControllerExt);
	}

Exit:

	*phAdapter = (DSMP_DLL_ADAPTER_HANDLE) pControllerExt;

	DigiDump (DIGIINIT, ("Exiting Sync570StartAdapter, Status =%08x()\n",Status));

	return (Status);

}	// end Sync570StartAdapter


NTSTATUS 
DigiInitializeAdapter (
	IN PDRIVER_OBJECT		pDriverObject,
	IN PDIGI_RESOURCE_LIST	pResources,
	IN PCONTROLLER_EXT		pControllerExt
	)
/*++

Routine Description:

	Read the parameters for each adapter configured in the registry.

Purpose:

	This routine is called at init time by DigiFindControllers().  It
	queries the adapter resource information needed from the registry, and
	saves that information in the appropriate Controller extension.  This
	routine is called once for each adapter in the system.

		1.	Save the Adapter resource settings in the Controller Extension.
		2.	Calls the appropriate adapter initialization routine,
			Setup<BusType>Adapter (i.e. SetupPciAdapter).
		3.  Update the Port Count.

Parameters:

	pDriverObject
		Address of the Driver object.

	pResources
		Allocated resources for this adapter.

	pControllerExt
		Address of the Controller extension

Return Value:

	STATUS_SUCCESS - Controller initialized successfully.

--*/
{

	NTSTATUS	Status = STATUS_SUCCESS;

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

	// Set the Common Bus Parameters.
	pControllerExt->BusType						= pResources->BusType;
	pControllerExt->BusNumber					= pResources->BusNumber;
	pControllerExt->PhysInterruptNumber.LowPart	= pResources->Irq.RawLevel; 
	pControllerExt->InterruptLevel				= (KIRQL)pResources->Irq.Level;
	pControllerExt->InterruptVector				= pResources->Irq.Vector;
	pControllerExt->ProcessorAffinity			= pResources->Irq.Affinity;

	// Set the Bus Specific Parameters in the Adapter.
	switch (pControllerExt->BusType)
	{
	case PCIBus:

		pControllerExt->PhysPlxRegisters.LowPart	= pResources->Io[0].BaseAddressTranslated.LowPart & 0xFFFFFFFC;
		pControllerExt->PhysWindowAddress.LowPart	= pResources->Io[2].BaseAddressTranslated.LowPart & 0xFFFFFFF0;

		Status = SetupPciAdapter (pDriverObject,pControllerExt);
		break;

	case Isa:
	case Eisa:

		pControllerExt->PhysIOPort.LowPart			= pResources->Io[0].BaseAddressTranslated.LowPart;
		pControllerExt->PhysWindowAddress.LowPart	= pResources->Io[1].BaseAddressTranslated.LowPart;

		//  Setup interrupt
		pControllerExt->InterruptMode				= pResources->Irq.Mode;
		pControllerExt->InterruptShareable			= FALSE;

		Status = SetupIsaAdapter (pDriverObject,pControllerExt);
		break;

	default:
		ASSERT (0 && "*** Unsupported BusType! ***\n");
		Status = STATUS_UNSUCCESSFUL;
		break;
	}

	DigiDump (DIGIFLOW, ("Exiting DigiInitializeAdapter (), Status = %08x\n",Status));

	return (Status);

} // end DigiInitializeAdapter


NTSTATUS 
Sync570DllStopAdapter ( 
		IN	DSMP_DLL_ADAPTER_HANDLE	hAdapter
	)
/*++

Routine Description:

	Unload the COntroller.

Arguments:

	phAdapter - Requested Resource usage.

Return Value:

	STATUS_SUCCESS - No errors found initializing the controllers.

--*/
{


	// The adapter handle is the Controller Extension.  Call the Unload Routine
	fnUnloadController((PCONTROLLER_EXT) hAdapter, (PDRIVER_OBJECT) NULL);

	return STATUS_SUCCESS;

}	// end Sync570StopAdapter

NTSTATUS 
Sync570DllOpenDevice ( 
		IN	DSMP_DLL_ADAPTER_HANDLE		hAdapter,
		IN	ULONG						ulLineNumber,
		OUT	PDSMP_DLL_DEVICE_HANDLE		phDevice
	)
/*++

Routine Description:

	Open a line on the Adapter.

Arguments:

	hAdapter		- the adapter structure.
	ulLineNumber	- the line number to be opened (0 based)
	pphDevice		- a pointer to return the device handle to the user

Return Value:

	Status 

--*/
{

	KIRQL			OldIrqL;
	NTSTATUS		Status			= STATUS_SUCCESS;
	PDEVICE_EXT		pDeviceExt		= NULL;
	PCONTROLLER_EXT	pControllerExt	= (PCONTROLLER_EXT) hAdapter;
				
	DigiDump (DIGIFLOW, ("Entering Sync570DllOpenDevice()  <Line: %d>\n",ulLineNumber));

	// Initilize the output parameter
	*phDevice = (DSMP_DLL_DEVICE_HANDLE) NULL;

	if (ulLineNumber >= (ULONG) pControllerExt->AdapterLines)
	{
		ASSERT(0);
		Status = STATUS_INVALID_PARAMETER;
	}
	else
	{

		pDeviceExt = pControllerExt->pDeviceExt[ulLineNumber];

		InterlockedIncrement (&pDeviceExt->DeviceOpens);
		if (pDeviceExt->DeviceOpens == 1)
		{
			RtlZeroMemory (&pDeviceExt->IR, sizeof (IR));
			pDeviceExt->IR.TransmitBufferSpace = (pDeviceExt->NumberOfDmaChains - 1) * DEFAULT_FRAME_SIZE;

			//  start the receiver
			KeAcquireSpinLock (&pControllerExt->MemoryLock, &OldIrqL);
			fnStartChannel (pDeviceExt);
			KeReleaseSpinLock (&pControllerExt->MemoryLock, OldIrqL);

			// Set the output parameter
			*phDevice = (DSMP_DLL_DEVICE_HANDLE) pDeviceExt;
		}
		else
		{
			Status = STATUS_UNSUCCESSFUL;
		}

	}
	
	DigiDump (DIGIFLOW, ("Exiting Sync570DllOpenDevice(): Status = %08x, Device = %08x\n",Status, pDeviceExt));

	return Status;

}

NTSTATUS 
Sync570DllGetFrame ( 
		IN	DSMP_DLL_DEVICE_HANDLE		hDevice,
		IN	PDSMP_GETFRAME				pGetFrame
	)
/*++

Routine Description:

	Provide the interface routines to the Get Frame function.

Arguments:

	hDevice		- Pointer to a device on a particular adapeter.
	pPutFrame	- Frame to be received

Return Value:

	Status 

--*/
{
	KIRQL			OldIrqL;
	NTSTATUS		Status;
	PDEVICE_EXT		pDeviceExt		= (PDEVICE_EXT) hDevice;
	PCONTROLLER_EXT	pControllerExt	= pDeviceExt->pControllerExt;

   KeAcquireSpinLock (&pControllerExt->MemoryLock, &OldIrqL);
	Status = IoctlGetFrame (pDeviceExt, pGetFrame);
   KeReleaseSpinLock (&pControllerExt->MemoryLock, OldIrqL);

   return Status;
}


NTSTATUS 
Sync570DllPutFrame ( 
		IN	DSMP_DLL_DEVICE_HANDLE		hDevice,
		IN	PDSMP_PUTFRAME				pPutFrame
	)
/*++

Routine Description:

	Provide the interface routines to the Put Frame function.

Arguments:

	hDevice		- Pointer to a device on a particular adapeter.
	pPutFrame	- Frame to be sent

Return Value:

	Status 

--*/
{
	KIRQL			OldIrqL;
	NTSTATUS		Status;
	PDEVICE_EXT		pDeviceExt		= (PDEVICE_EXT) hDevice;
	PCONTROLLER_EXT	pControllerExt	= pDeviceExt->pControllerExt;

   KeAcquireSpinLock (&pControllerExt->MemoryLock, &OldIrqL);
	Status = IoctlPutFrame (pDeviceExt, pPutFrame);
   KeReleaseSpinLock (&pControllerExt->MemoryLock, OldIrqL);

   return Status;
}


NTSTATUS 
Sync570DllGetConfig ( 
		IN	DSMP_DLL_DEVICE_HANDLE		hDevice,
		IN	PDSMP_CONFIG				pConfig
	)
/*++

Routine Description:

	Provide the interface routines to the Get Config function.

Arguments:

	hDevice - Pointer to a device on a particular adapeter.
	pConfig - Config settings

Return Value:

	Status 

--*/
{

	PDEVICE_EXT	pDeviceExt	= (PDEVICE_EXT) hDevice;

	return IoctlGetConfig (pDeviceExt, pConfig);

}



NTSTATUS 
Sync570DllSetConfig ( 
		IN	DSMP_DLL_DEVICE_HANDLE		hDevice,
		IN	PDSMP_CONFIG				pConfig
	)
/*++

Routine Description:

	Provide the interface routines to the Set Config function.

Arguments:

	hDevice - Pointer to a device on a particular adapeter.
	pConfig - Config settings

Return Value:

	Status 

--*/
{
   KIRQL			OldIrqL;
	NTSTATUS		Status;
	PDEVICE_EXT		pDeviceExt		= (PDEVICE_EXT) hDevice;
	PCONTROLLER_EXT	pControllerExt	= pDeviceExt->pControllerExt;

   KeAcquireSpinLock (&pControllerExt->MemoryLock, &OldIrqL);
	Status = IoctlSetConfig (pDeviceExt, pConfig);
   KeReleaseSpinLock (&pControllerExt->MemoryLock, OldIrqL);

   return Status;
}



NTSTATUS 
Sync570DllGetModem ( 
		IN	DSMP_DLL_DEVICE_HANDLE		hDevice,
		IN	PDSMP_MODEM					pModem
	)
/*++

Routine Description:

	Provide the interface routines to the Get Modem function.

Arguments:

	hDevice - Pointer to a device on a particular adapeter.
	pModem  - Modem settings

Return Value:

	Status 

--*/
{
   KIRQL			OldIrqL;
	NTSTATUS		Status;
	PDEVICE_EXT		pDeviceExt		= (PDEVICE_EXT) hDevice;
	PCONTROLLER_EXT	pControllerExt	= pDeviceExt->pControllerExt;

   KeAcquireSpinLock (&pControllerExt->MemoryLock, &OldIrqL);
	Status = IoctlGetModem (pDeviceExt, pModem);
   KeReleaseSpinLock (&pControllerExt->MemoryLock, OldIrqL);

   return Status;
}



NTSTATUS 
Sync570DllSetModem ( 
		IN	DSMP_DLL_DEVICE_HANDLE		hDevice,
		IN	PDSMP_MODEM					pModem
	)
/*++

Routine Description:

	Provide the interface routines to the Set Modem function.

Arguments:

	hDevice - Pointer to a device on a particular adapeter.
	pModem  - Modem settings

Return Value:

	Status 

--*/
{
   KIRQL			OldIrqL;
	NTSTATUS		Status;
	PDEVICE_EXT		pDeviceExt		= (PDEVICE_EXT) hDevice;
	PCONTROLLER_EXT	pControllerExt	= pDeviceExt->pControllerExt;

   KeAcquireSpinLock (&pControllerExt->MemoryLock, &OldIrqL);
	Status = IoctlSetModem (pDeviceExt, pModem);
   KeReleaseSpinLock (&pControllerExt->MemoryLock, OldIrqL);

   return Status;
}


NTSTATUS 
Sync570DllGetStats ( 
		IN	DSMP_DLL_DEVICE_HANDLE		hDevice,
		IN	PDSMP_STATS					pStats
	)
/*++

Routine Description:

	Provide the interface routines to the Get Stats function.

Arguments:

	hDevice - Pointer to a device on a particular adapeter.
	pStats  - Stats settings

Return Value:

	Status 

--*/
{

	PDEVICE_EXT	pDeviceExt	= (PDEVICE_EXT) hDevice;

	return IoctlGetStats (pDeviceExt, pStats);

}


NTSTATUS 
Sync570DllZeroStats ( 
		IN	DSMP_DLL_DEVICE_HANDLE		hDevice
	)
/*++

Routine Description:

	Provide the interface routines to the Zero Stats function.

Arguments:

	hDevice - Pointer to a device on a particular adapeter.

Return Value:

	Status 

--*/
{

	PDEVICE_EXT	pDeviceExt	= (PDEVICE_EXT) hDevice;

	return IoctlZeroStats (pDeviceExt);

}


NTSTATUS 
Sync570DllCloseDevice ( 
		IN	DSMP_DLL_DEVICE_HANDLE	hDevice
	)
/*++

Routine Description:

	Close a previously opened device.


Arguments:

	hDevice - A device Extension.

Return Value:

	Status 

--*/
{

	KIRQL			OldIrqL;
	NTSTATUS		Status			= STATUS_SUCCESS;
	PDEVICE_EXT		pDeviceExt		= (PDEVICE_EXT) hDevice;
	PCONTROLLER_EXT	pControllerExt	= pDeviceExt->pControllerExt;
				
	DigiDump (DIGIFLOW, ("Entering Sync570DllCloseDevice()  <Device: %08x>\n",pDeviceExt));

	KeAcquireSpinLock (&pControllerExt->MemoryLock, &OldIrqL);
	// Drop DTR, RTS, CTS
	fnDropModemSignals (pDeviceExt);
	// Stop the Send/Receive channels on the board
	fnStopChannel (pDeviceExt);
	KeReleaseSpinLock (&pControllerExt->MemoryLock, OldIrqL);	

	// This device is no longer in use
	InterlockedDecrement (&pDeviceExt->DeviceOpens);

	DigiDump (DIGIFLOW, ("Exiting Sync570DllCloseDevice(): Status = %08x, Device = %08x\n",Status, pDeviceExt));

	return Status;

}

STATIC DSMP_DLL_INTERFACE_ROUTINES gDllInterface = {

						Sync570DllStartAdapter,
						Sync570DllOpenDevice,
						Sync570DllGetFrame,
						Sync570DllPutFrame,
						Sync570DllGetConfig,
						Sync570DllSetConfig,
						Sync570DllGetModem,
						Sync570DllSetModem,
						Sync570DllGetStats,
						Sync570DllZeroStats,
						Sync570DllCloseDevice,
						Sync570DllStopAdapter,

};

extern PDSMP_DLL_INTERFACE_ROUTINES 
Sync570DllInitialize (
	)
/*++

Routine Description:

	Provide the interface routines to the DLL.

Purpose:

	Pass back the interface routines to the user of the DLL interface.

Arguments:

	pphDllHandle - Pointer to a pointer to the Interface Structure.

Return Value:

	VOID 

--*/
{

	return &gDllInterface;

}


#endif // NT5_BUILD


