
/*****************************************************************************
* 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 File:  open.c
 *
 *  Purpose:
 *
 *      Open and Close dispatch routines for DgSna driver.
 *
 *
 *----------------------------------------------------------------------
 */

#include <ntddk.h>

// Streams Headers													  
#include "types.h"
#include "wan_proto.h"
#include "wan_control.h" 

#include "dsmp.h"
#include "dgsna.h"
#include "ioctls.h"
#include "dsapi.h"
#include "dsioctl.h"
#include "digilib.h"

extern VOID DgSnaReadComplete(HANDLE , HANDLE , PVOID,
				ULONG ,PVOID , ULONG , NTSTATUS );

/*
 *----------------------------------------------------------------------
 * Function:  DgSnaOpen.
 *
 * Purpose:
 *
 *    The IRP_MJ_CREATE dispatch routine for DigiDgSna driver.  Attempt to open
 *    a stream for the selected COM port and initialize the port settings.
 *
 *
 *
 *
 *----------------------------------------------------------------------
 */

						 
												  
																			
NTSTATUS
DgSnaOpen(
    IN PDEVICE_OBJECT   pDevice,       // device
    IN PIRP             pIrp           // Associated work order
)
{

	PPORT_EXT   pPortExt = NULL;        // Port specific information.
	KIRQL       openIrql;               // Save prior irq level.
	LIST_ENTRY  *p;                     // LIST_ENTRY intermediate value.
	ULONG       errorCode;
	HANDLE		hStream = NULL;
	ULONG 		snid;
	NTSTATUS    status = STATUS_UNSUCCESSFUL;

	DigiDump(DIGIOPENCLOSE,("DgSnaOpen: dev %x irp %x\n",pDevice,pIrp));

	pPortExt = pDevice->DeviceExtension;
	pPortExt->configured = 0;

	status = DgSnaFindAndInitTheLinkService(&pPortExt->snadeviceName,pPortExt);

	if( status != STATUS_SUCCESS )
	{
		DigiDump(DIGIOPENCLOSE,("DgSnaOpen:  DgSnaFindAndInitTheLinkService failed status = %x\n",pIrp,status));
		pPortExt->dsAdapterHandle = 0;
		goto OpenExit;
	}

	KeAcquireSpinLock(&pPortExt->ownership, &openIrql);
	if (pPortExt->state != IdleState)
	{
		DigiDump(DIGIOPENCLOSE,("DgSnaOpen: not ready, dev %x irp %x\n",pDevice,pIrp));
		KeReleaseSpinLock(&pPortExt->ownership,openIrql);
		goto OpenExit;
	}
	else
	{
		// Set Pending Open State
		pPortExt->state = OpeningState;
	}
	KeReleaseSpinLock(&pPortExt->ownership,openIrql);

	pPortExt->openIrp = pIrp;


	pPortExt->dsAdapterHandle	= NULL;
	pPortExt->dsPortHandle		= NULL;

	DigiDump(DIGIOPENCLOSE,("DgSnaOpen: Going in for DsOpenDevice, dev %x irp %x\n",pDevice,pIrp));

	status = DsOpenDevice( &pPortExt->adapterName,
						   &pPortExt->dsAdapterHandle );


	if( status != STATUS_SUCCESS )
	{
		DigiDump(DIGIOPENCLOSE,("DgSnaOpen:  DsOpenDevice failed, dev %x irp %x status %x\n",pDevice,pIrp,status));
		pPortExt->dsAdapterHandle = 0;
		goto OpenExit;
	}

	status = DsOpen( pPortExt->dsAdapterHandle,
                     pPortExt->deviceName,
                     (HANDLE)pPortExt,
                     pPortExt,
                     sizeof (pPortExt),
                     &pPortExt->dsPortHandle,
                     &errorCode);

	if (status != STATUS_SUCCESS)
	{
		DigiDump(DIGIOPENCLOSE,("DgSnaOpen:  DsOpen failed, dev %x irp %x status %x\n",pDevice,pIrp,status));
		goto OpenExit;
	}


	// Send WAN_SID
	snid	= pPortExt->snid;
	hStream = pPortExt->dsPortHandle;

	{
		struct wan_sid sid	= {0};
		sid.wan_type		= WAN_SID;
		sid.wan_snid		= snid;

		DigiDump(DIGIOPENCLOSE,("DgSnaOpen:Send WAN_SID, dev %x irp %x\n",pDevice,pIrp));

		status = DsPutMsg( hStream,
						   &sid,
						   sizeof (sid),
						   NULL,
						   0,
						   DS_PRIORITY_LOW );

		ASSERT( NT_SUCCESS( status ) );
		if (status != STATUS_SUCCESS){
			DigiDump(DIGIOPENCLOSE,("DgSnaOpen:Send WAN_SID failed, dev %x irp %x status %x\n",pDevice,pIrp,status));
			goto OpenExit;
		}
		
	}	

	// clear the Interface Record
	
	RtlZeroMemory (&pPortExt->IR, sizeof (IR));
	pPortExt->IR.TransmitBufferSpace = DGSNA_MAX_WRITE_ENTRIES * DGSNA_MAX_PACKET_SIZE;

OpenExit:
	if (status != STATUS_SUCCESS){
		if (pPortExt->dsPortHandle)
			DsClose( pPortExt->dsPortHandle);
		if (pPortExt->dsAdapterHandle)
			DsCloseDevice( pPortExt->dsAdapterHandle);
		pPortExt->state = IdleState;
	}
	else
	{
		pPortExt->state = OpenState;
	}

	pIrp->IoStatus.Status = status;
	IoCompleteRequest(pIrp,0);

	DigiDump(DIGIOPENCLOSE,("DgSnaOpen:Open Exit, dev %x irp %x status %x\n",pDevice,pIrp,status));

	return(status);
}
															  

										  
/*
 *----------------------------------------------------------------------
 * Function:  DgSnaClose.
 *
 * Purpose:
 *
 *    The IRP_MJ_CLOSE dispatch routine for DigiDgSna driver.  Attempt to close
 *    a stream for the selected  port.
 *
 *
 * 
 *----------------------------------------------------------------------
 */
NTSTATUS DgSnaClose(
    IN PDEVICE_OBJECT   pDevice,    // Comm port device
    IN PIRP             pIrp            // Associated work order
)
{

	PPORT_EXT   pPortExt = NULL;        // Port specific information.
	KIRQL		closeIrql;
	NTSTATUS	status = STATUS_SUCCESS;

	// Get the driver specific data structures.
	pIrp->IoStatus.Information = 0;
	pPortExt = pDevice->DeviceExtension;

	DigiDump(DIGIOPENCLOSE, ("DgSnaClose : dev %x irp %x port = %x\n",pDevice,pIrp,pPortExt) );

	// Set the Closing State so no more Get or Put Messages are sent
	KeAcquireSpinLock(&pPortExt->ownership, &closeIrql);
	pPortExt->state = ClosingState;

	// If the DPC is running we must delay the close till it is finished.
	if (pPortExt->dpcReadRequestIsRunning == TRUE)
	{

		DigiDump(DIGIOPENCLOSE,("DgSnaClose : The DPC is running Port = %x\n",pPortExt));

		// Reset the Close Event
		KeResetEvent(&pPortExt->evClose );

		KeReleaseSpinLock(&pPortExt->ownership,closeIrql);

		// Wait till the DPC is finished
		KeWaitForSingleObject( &pPortExt->evClose, Executive, KernelMode, FALSE, NULL );

	}
	else
	{
		KeReleaseSpinLock(&pPortExt->ownership,closeIrql);
	}

	DigiDump(DIGIOPENCLOSE,("DgSnaClose : Close The Port = %x\n",pPortExt));

	// Closing the Device will finish all the outstanding IRPs.
	if (pPortExt->dsPortHandle)
		DsClose(pPortExt->dsPortHandle);
	if ( pPortExt->dsAdapterHandle)
		DsCloseDevice(pPortExt->dsAdapterHandle);
	pPortExt->dsPortHandle = pPortExt->dsAdapterHandle = NULL;

	// Now all IOCTLs are complete.  We need to put the completed read buffers
	// back in the pool.
	while(!IsListEmpty(&pPortExt->completedReadBuffers)){

		LIST_ENTRY * p;

		p  = RemoveHeadList(&pPortExt->completedReadBuffers);
		InsertHeadList( &pPortExt->readBuffers,p);

	} 

	pPortExt->state = IdleState;
	pIrp->IoStatus.Status = status;

	IoCompleteRequest(pIrp,0);

	DigiDump(DIGIOPENCLOSE,("DigiSnaClose - Exit Status = %x Port = %x\n",status,pPortExt));

	return(status);
}

	
	
	


