/*++

*******************************************************************************
* Copyright (c) 1994-95 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 copyright work  Digi   International *
* Inc.    Except   as   permitted   by  federal  law,  17 USC 117, copying is *
* strictly prohibited.                                                        *
*                                                                             *
* Digi  International  Inc.  CONFIDENTIAL  -   (Digi    International    Inc. *
* Confidential  when   combined   with   the   aggregated  modules  for  this *
* product) OBJECT CODE ONLY SOURCE MATERIALS                                  *
*                                                                             *
* (C) COPYRIGHT Digi International Inc. 1994-95                               *
*                                                                             *
* All Rights Reserved                                                         *
*                                                                             *
* US   Government   Users   Restricted   Rights   -   Use,   duplication   or *
* disclosure  restricted by GSA ADP Schedule Contract with Digi International *
* Inc.                                                                        *
*                                                                             *
*******************************************************************************

Module Name:

   digilan.c

Abstract:

   This is the main file for the Digi Frame Relay driver.  This driver conforms 
   to the NDIS 3.0 miniport interface.

Author:

   Michael Zarns

--*/
#include "digilan.h"
#include "DsApi.h"


#if NT5_BUILD
// Don't use MEMPRINT in 5.0 yet, due to MS bugs in registering Shutdown handler to 
// stop our memprint thread!
#else
#define LAN_USE_MEMPRINT
#endif

extern WCHAR gDigilanVersion[];

ULONG DigiDontLoadDriver = FALSE;


VOID
DigiLanHalt( 
	IN NDIS_HANDLE MiniportAdapterContext )
/*++

Description:

	MiniportHalt should stop the netcard and free all its resources before returning 
	from this function.  DigiLanHalt closes the link to SXB for this VC (really, it's
	called a PLL, or Permanent Logical Link) on the Frame Relay Circuit - which 
	effectively stops the "netcard".  
	
	Keep in mind that each Frame Relay PLL is mapped to a unique NDIS netcard.  There 
	are multiple PLL's on the Frame Relay circuit, and we're only stopping one of 
	them, so we're not actually stopping the physical card.

Parameters:

	NDIS_HANDLE MiniportAdapterContext
		The handle returned from DigiLanInitialize; actually it's a pointer to a
		LogpAdapter structure.

Return Value:

	None

--*/
{
    NDIS_STATUS Status;
    PDIGILAN_LOGICAL_ADAPTER pAdapter;
    LARGE_INTEGER Timeout;

    DigiDump( DIGIINIT, ("Enter DigiLanHalt\n") );

    pAdapter = (PDIGILAN_LOGICAL_ADAPTER) MiniportAdapterContext;

    DigiDump( DIGIINIT, ("*** DigiLanHalt - Spoof = %d\n",pAdapter->bSpoof) );

    // Stratus NDIS bugfix, flag that we are stopping, and wait until our NDIS work item
    // isn't pending.
    // XXX Should be surrounded by #ifdef STRATUS_DEVICE
    NdisAcquireSpinLock(&pAdapter->Lock);
    pAdapter->HaltReceived = TRUE;
    NdisReleaseSpinLock(&pAdapter->Lock);

    // Stop frame relay update process if running and wait for work
    // items to drain
    FrStopUpdate( pAdapter );	

    // Now do the same for X.25
    X25StopAttach( pAdapter );

    if (pAdapter->bSpoof == FALSE)
    {

        DigiDump( DIGIINIT, ("*** DigiLanHalt - Close Device = %x\n",pAdapter->hDevice) );

        if (pAdapter->hStream) {
            ASSERT(DlwBuffersAllocated(pAdapter,pAdapter->hStream) == FALSE);
            DsClose(pAdapter->hStream);
            pAdapter->hStream = NULL;
        }
        Status = DsCloseDevice( pAdapter->hDevice );

        if ( NDIS_STATUS_SUCCESS != Status )
            DigiDump( DIGIERRORS, 
                      ("*** DigiLanHalt: DsCloseDevice returned 0x%x!\n;", Status ) );

        NdisAcquireSpinLock( &DigiLanDriverObject.AdapterListLock  );
        RemoveEntryList( &pAdapter->ListEntry );
        NdisReleaseSpinLock( &DigiLanDriverObject.AdapterListLock  );

        // Free DigiRegQuery* strings using digi free routines
        if ( pAdapter->UDeviceName.Buffer )
            DigiRegFreeString( &pAdapter->UDeviceName);

        if ( pAdapter->UName.Buffer )
            DigiRegFreeString( &pAdapter->UName);

    }
    else
    {
        DigiDump( DIGIERRORS, ("*** DigiLanHalt: not halted because of Spoof\n") );
    }

    // Free multicast address list:
    if ( pAdapter->Multicast.AddressList != 0 )
    {
        DigiFreeMem( pAdapter->Multicast.AddressList );
    }

    // SDB: Stop and clean queue:
    DigiAdapterContextQueueDeInit( pAdapter );

    DigiFreeMem( pAdapter );

    DigiDump( DIGIINIT, ("Leave DigiLanHalt\n") );
}


NDIS_STATUS
DigiLanReset(
	IN NDIS_HANDLE MiniportAdapterContext, 
	OUT PBOOLEAN AddressingReset )
/*++

Description:

	MiniportReset should issue a hardware reset to the netcard. The miniport driver 
	should also resets its software state.

	Since our "netcards" aren't real physical netcards, they're logical channels on 
	the Frame Relay circuit, we won't do anything.

Parameters:

	NDIS_HANDLE MiniportAdapterContext
		The handle returned from DigiLanInitialize.

	PBOOLEAN AddressingReset
		Set to TRUE if the NDIS wrapper needs to call MiniportSetInformation to 
		restore addressing information to the current values.


Return Value:

	NDIS_STATUS_NOT_RESETTABLE

--*/
{
	DigiDump( DIGIFLOW, ("Enter DigiLanReset\n") );
	DigiDump( DIGIFLOW, ("Leave DigiLanReset\n") );

	// SDB:
	DigiDump( DIGIERRORS, ("*** Fake Reset\n") );

	return( NDIS_STATUS_NOT_RESETTABLE );
}


VOID
DriverUnload(
	PDRIVER_OBJECT pDriverObject )
/*++

Description:

	Last chance to cleanup before driver is unloaded.  Everything alloc'd, created,
	or started in DriverEntry or otherwise should be freed, destroyed or stopped.

Parameters:

	pDriverObject
		The driver object for this driver.

Return Value:

	None

--*/
{
	DigiDump( DIGIINIT,  ( "DigiLan!DriverUnload\n" ) );
#ifdef LAN_USE_MEMPRINT
	MemPrintQuit();
#endif
	DigiDisplayMemoryLeaks();
}


NDIS_STATUS
DriverEntry(
	IN PDRIVER_OBJECT DriverObject, 
	IN PUNICODE_STRING RegistryPath );

NDIS_STATUS
DriverEntry(
	IN PDRIVER_OBJECT DriverObject, 
	IN PUNICODE_STRING pRegistryPath )
/*++

Description:

	This is the primary initialization routine for the Digi Frame Relay 	driver.  
	It is simply responsible for initializing the wrapper and registering the 
	miniport driver.

Parameters:

	PDRIVER_OBJECT DriverObject
		Points to the driver object created by the I/O Manager when the driver was 
		loaded. Each driver's DriverEntry routine is called with a pointer to the 
		corresponding driver object.

	PUNICODE_STRING pRegistryPath
		Pointer to a Unicode string specifying a path to a driver-specific key in the 
		registry (i.e. \Registry\Machine\System\CurrentControlSet\Services\DigiLan).

Return Value:

	STATUS_SUCCESS or error.

--*/
{
	NDIS_STATUS Status;

	NDIS_MINIPORT_CHARACTERISTICS DigiLanChar;

	// Used by digilib routines to tag allocated memory blocks as being owned by 
	// DigiLan.  Used for debug purposes only.  "DLan" for DigiLan driver in 
	// reverse.  This shows up in memory dumps.
	DigiInitMem( 'naLD' );

#ifdef LAN_USE_MEMPRINT
	MemPrintInitialize( "\\SystemRoot\\digilan.log" );
#endif
	
	DigiDebugInitEx( pRegistryPath, 
                         DIGIINIT|DIGIERRORS|DIGIWARN, 
                         DEBUGMODE_CONSOLE,
                         "sradlan", gDigilanVersion );
	// SDB
	//DigiDebugInit( pRegistryPath, DIGIINIT|DIGIERRORS|DIGITX|DIGIRX|DIGIWARN, DEBUGMODE_CONSOLE );

#if DBG
	// Override debug settings
	DbgPrint( "\n"
	          "DigiLan!DriverEntry:\n"
	          "   gDebugMask         = 0x%08x\n"
	          "   gDebugMode         = 0x%08x\n"
	          "   DigiDontLoadDriver = 0x%08x\n",
	          &gDebugMask, &gDebugMode, &DigiDontLoadDriver );
#endif
	// Get debug settings from Registry
	{
		HANDLE hKey;
		Status = DigiRegOpenKey( &hKey, pRegistryPath->Buffer );
		if ( NT_SUCCESS( Status ) )
		{
			ULONG fBreak = 0;
			DigiRegQueryDword( hKey, L"DebugBreak", &fBreak, DigiRegFlagOptional, 0 );
			if ( fBreak )
				DbgBreakPoint();
			DigiRegCloseKey( hKey );
		}
	}	

	if( DigiDontLoadDriver )
	{
		Status = STATUS_CANCELLED;
		goto Exit;
	}

	// Initialize driver object
	NdisZeroMemory( &DigiLanDriverObject, sizeof( DIGILAN_DRIVER_OBJECT ) );
	DigiLanDriverObject.Type = DIGI_TYPE_DRIVER_OBJECT;
	DigiLanDriverObject.DriverObject = DriverObject;
	DigiLanDriverObject.bInSendComplete = FALSE;
	NdisAllocateSpinLock( &DigiLanDriverObject.InSendCompleteLock );
	NdisAllocateSpinLock( &DigiLanDriverObject.AdapterListLock );

	NdisMInitializeWrapper( &DigiLanDriverObject.WrapperHandle,
	                        DriverObject, pRegistryPath, NULL );

	InitializeListHead( &DigiLanDriverObject.AdapterList );

	NdisZeroMemory( &DigiLanChar, sizeof( DigiLanChar ) );
	DigiLanChar.MajorNdisVersion        = DIGILAN_MAJOR_VERSION;
	DigiLanChar.MinorNdisVersion        = DIGILAN_MINOR_VERSION;
	DigiLanChar.HaltHandler             = DigiLanHalt;
	DigiLanChar.InitializeHandler       = DigiLanInitialize;
	DigiLanChar.QueryInformationHandler = DigiLanQueryInformation;
	DigiLanChar.ResetHandler            = DigiLanReset;
	DigiLanChar.SendHandler             = DigiLanSend;
	DigiLanChar.SetInformationHandler   = DigiLanSetInformation;
	DigiLanChar.TransferDataHandler     = DigiLanTransferData;
   
#if NT5_BUILD
	// Additional entry points for NDIS V4.0, currently not handled
	DigiLanChar.ReturnPacketHandler     = NULL;
	DigiLanChar.SendPacketsHandler      = NULL;
	DigiLanChar.AllocateCompleteHandler = NULL;

	// Additional entry points for NDIS V5.0, currently not handled
	DigiLanChar.CoCreateVcHandler     = NULL;
	DigiLanChar.CoDeleteVcHandler     = NULL;
	DigiLanChar.CoActivateVcHandler   = NULL;
	DigiLanChar.CoDeactivateVcHandler = NULL;
	DigiLanChar.CoSendPacketsHandler  = NULL;
	DigiLanChar.CoRequestHandler      = NULL;
#endif

	Status = NdisMRegisterMiniport( DigiLanDriverObject.WrapperHandle,
	                                &DigiLanChar, sizeof DigiLanChar );

#if NT5_BUILD
	if ( NT_SUCCESS( Status ) )
	{
		NdisMRegisterUnloadHandler(DigiLanDriverObject.WrapperHandle,DriverUnload);
	}
#endif

Exit:
	if ( NT_ERROR( Status ) )
	{
#ifdef LAN_USE_MEMPRINT
		MemPrintQuit();
#endif
		DigiDisplayMemoryLeaks();
	}

	DigiDump( DIGIINIT, ( "DigiLan!DriverEntry: Leave, Status 0x%08x\n", Status ) );
	return( Status );
}


